xref: /openbsd/sys/arch/armv7/omap/nxphdmi.c (revision 9fdf0c62)
1 /* $OpenBSD: nxphdmi.c,v 1.8 2021/10/24 17:52:27 mpi Exp $ */
2 /*
3  * Copyright (c) 2016 Ian Sutton <ians@openbsd.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 /*
29  * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@freebsd.org>
30  * All rights reserved.
31  *
32  * Redistribution and use in source and binary forms, with or without
33  * modification, are permitted provided that the following conditions
34  * are met:
35  * 1. Redistributions of source code must retain the above copyright
36  *    notice, this list of conditions and the following disclaimer.
37  * 2. Redistributions in binary form must reproduce the above copyright
38  *    notice, this list of conditions and the following disclaimer in the
39  *    documentation and/or other materials provided with the distribution.
40  *
41  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  */
53 
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/device.h>
57 #include <sys/errno.h>
58 
59 #include <dev/i2c/i2cvar.h>
60 #include <dev/videomode/videomode.h>
61 
62 #include <dev/ofw/ofw_pinctrl.h>
63 
64 #include <arch/armv7/omap/nxphdmivar.h>
65 
66 /* TDA19988 registers */
67 #define	MKREG(page, addr)	(((page) << 8) | (addr))
68 
69 #define	REGPAGE(reg)		(((reg) >> 8) & 0xff)
70 #define	REGADDR(reg)		((reg) & 0xff)
71 
72 #define	TDA_VERSION		MKREG(0x00, 0x00)
73 #define	TDA_MAIN_CNTRL0		MKREG(0x00, 0x01)
74 #define		MAIN_CNTRL0_SR		(1 << 0)
75 #define	TDA_VERSION_MSB		MKREG(0x00, 0x02)
76 #define	TDA_SOFTRESET		MKREG(0x00, 0x0a)
77 #define		SOFTRESET_I2C		(1 << 1)
78 #define		SOFTRESET_AUDIO		(1 << 0)
79 #define	TDA_DDC_CTRL		MKREG(0x00, 0x0b)
80 #define		DDC_ENABLE		0
81 #define	TDA_CCLK		MKREG(0x00, 0x0c)
82 #define		CCLK_ENABLE		1
83 #define	TDA_INT_FLAGS_2		MKREG(0x00, 0x11)
84 #define		INT_FLAGS_2_EDID_BLK_RD	(1 << 1)
85 
86 #define	TDA_VIP_CNTRL_0		MKREG(0x00, 0x20)
87 #define	TDA_VIP_CNTRL_1		MKREG(0x00, 0x21)
88 #define	TDA_VIP_CNTRL_2		MKREG(0x00, 0x22)
89 #define	TDA_VIP_CNTRL_3		MKREG(0x00, 0x23)
90 #define		VIP_CNTRL_3_SYNC_HS	(2 << 4)
91 #define		VIP_CNTRL_3_V_TGL	(1 << 2)
92 #define		VIP_CNTRL_3_H_TGL	(1 << 1)
93 
94 #define	TDA_VIP_CNTRL_4		MKREG(0x00, 0x24)
95 #define		VIP_CNTRL_4_BLANKIT_NDE		(0 << 2)
96 #define		VIP_CNTRL_4_BLANKIT_HS_VS	(1 << 2)
97 #define		VIP_CNTRL_4_BLANKIT_NHS_VS	(2 << 2)
98 #define		VIP_CNTRL_4_BLANKIT_HE_VE	(3 << 2)
99 #define		VIP_CNTRL_4_BLC_NONE		(0 << 0)
100 #define		VIP_CNTRL_4_BLC_RGB444		(1 << 0)
101 #define		VIP_CNTRL_4_BLC_YUV444		(2 << 0)
102 #define		VIP_CNTRL_4_BLC_YUV422		(3 << 0)
103 #define	TDA_VIP_CNTRL_5		MKREG(0x00, 0x25)
104 #define		VIP_CNTRL_5_SP_CNT(n)	(((n) & 3) << 1)
105 #define	TDA_MUX_VP_VIP_OUT	MKREG(0x00, 0x27)
106 #define	TDA_MAT_CONTRL		MKREG(0x00, 0x80)
107 #define		MAT_CONTRL_MAT_BP	(1 << 2)
108 #define	TDA_VIDFORMAT		MKREG(0x00, 0xa0)
109 #define	TDA_REFPIX_MSB		MKREG(0x00, 0xa1)
110 #define	TDA_REFPIX_LSB		MKREG(0x00, 0xa2)
111 #define	TDA_REFLINE_MSB		MKREG(0x00, 0xa3)
112 #define	TDA_REFLINE_LSB		MKREG(0x00, 0xa4)
113 #define	TDA_NPIX_MSB		MKREG(0x00, 0xa5)
114 #define	TDA_NPIX_LSB		MKREG(0x00, 0xa6)
115 #define	TDA_NLINE_MSB		MKREG(0x00, 0xa7)
116 #define	TDA_NLINE_LSB		MKREG(0x00, 0xa8)
117 #define	TDA_VS_LINE_STRT_1_MSB	MKREG(0x00, 0xa9)
118 #define	TDA_VS_LINE_STRT_1_LSB	MKREG(0x00, 0xaa)
119 #define	TDA_VS_PIX_STRT_1_MSB	MKREG(0x00, 0xab)
120 #define	TDA_VS_PIX_STRT_1_LSB	MKREG(0x00, 0xac)
121 #define	TDA_VS_LINE_END_1_MSB	MKREG(0x00, 0xad)
122 #define	TDA_VS_LINE_END_1_LSB	MKREG(0x00, 0xae)
123 #define	TDA_VS_PIX_END_1_MSB	MKREG(0x00, 0xaf)
124 #define	TDA_VS_PIX_END_1_LSB	MKREG(0x00, 0xb0)
125 #define	TDA_VS_LINE_STRT_2_MSB	MKREG(0x00, 0xb1)
126 #define	TDA_VS_LINE_STRT_2_LSB	MKREG(0x00, 0xb2)
127 #define	TDA_VS_PIX_STRT_2_MSB	MKREG(0x00, 0xb3)
128 #define	TDA_VS_PIX_STRT_2_LSB	MKREG(0x00, 0xb4)
129 #define	TDA_VS_LINE_END_2_MSB	MKREG(0x00, 0xb5)
130 #define	TDA_VS_LINE_END_2_LSB	MKREG(0x00, 0xb6)
131 #define	TDA_VS_PIX_END_2_MSB	MKREG(0x00, 0xb7)
132 #define	TDA_VS_PIX_END_2_LSB	MKREG(0x00, 0xb8)
133 #define	TDA_HS_PIX_START_MSB	MKREG(0x00, 0xb9)
134 #define	TDA_HS_PIX_START_LSB	MKREG(0x00, 0xba)
135 #define	TDA_HS_PIX_STOP_MSB	MKREG(0x00, 0xbb)
136 #define	TDA_HS_PIX_STOP_LSB	MKREG(0x00, 0xbc)
137 #define	TDA_VWIN_START_1_MSB	MKREG(0x00, 0xbd)
138 #define	TDA_VWIN_START_1_LSB	MKREG(0x00, 0xbe)
139 #define	TDA_VWIN_END_1_MSB	MKREG(0x00, 0xbf)
140 #define	TDA_VWIN_END_1_LSB	MKREG(0x00, 0xc0)
141 #define	TDA_VWIN_START_2_MSB	MKREG(0x00, 0xc1)
142 #define	TDA_VWIN_START_2_LSB	MKREG(0x00, 0xc2)
143 #define	TDA_VWIN_END_2_MSB	MKREG(0x00, 0xc3)
144 #define	TDA_VWIN_END_2_LSB	MKREG(0x00, 0xc4)
145 #define	TDA_DE_START_MSB	MKREG(0x00, 0xc5)
146 #define	TDA_DE_START_LSB	MKREG(0x00, 0xc6)
147 #define	TDA_DE_STOP_MSB		MKREG(0x00, 0xc7)
148 #define	TDA_DE_STOP_LSB		MKREG(0x00, 0xc8)
149 
150 #define	TDA_TBG_CNTRL_0		MKREG(0x00, 0xca)
151 #define		TBG_CNTRL_0_SYNC_ONCE	(1 << 7)
152 #define		TBG_CNTRL_0_SYNC_MTHD	(1 << 6)
153 
154 #define	TDA_TBG_CNTRL_1		MKREG(0x00, 0xcb)
155 #define		TBG_CNTRL_1_DWIN_DIS	(1 << 6)
156 #define		TBG_CNTRL_1_TGL_EN	(1 << 2)
157 #define		TBG_CNTRL_1_V_TGL	(1 << 1)
158 #define		TBG_CNTRL_1_H_TGL	(1 << 0)
159 
160 #define	TDA_HVF_CNTRL_0		MKREG(0x00, 0xe4)
161 #define		HVF_CNTRL_0_PREFIL_NONE		(0 << 2)
162 #define		HVF_CNTRL_0_INTPOL_BYPASS	(0 << 0)
163 #define	TDA_HVF_CNTRL_1		MKREG(0x00, 0xe5)
164 #define		HVF_CNTRL_1_VQR(x)	(((x) & 3) << 2)
165 #define		HVF_CNTRL_1_VQR_FULL	HVF_CNTRL_1_VQR(0)
166 #define	TDA_ENABLE_SPACE	MKREG(0x00, 0xd6)
167 #define	TDA_RPT_CNTRL		MKREG(0x00, 0xf0)
168 
169 #define	TDA_PLL_SERIAL_1	MKREG(0x02, 0x00)
170 #define		PLL_SERIAL_1_SRL_MAN_IP	(1 << 6)
171 #define	TDA_PLL_SERIAL_2	MKREG(0x02, 0x01)
172 #define		PLL_SERIAL_2_SRL_PR(x)		(((x) & 0xf) << 4)
173 #define		PLL_SERIAL_2_SRL_NOSC(x)	(((x) & 0x3) << 0)
174 #define	TDA_PLL_SERIAL_3	MKREG(0x02, 0x02)
175 #define		PLL_SERIAL_3_SRL_PXIN_SEL	(1 << 4)
176 #define		PLL_SERIAL_3_SRL_DE		(1 << 2)
177 #define		PLL_SERIAL_3_SRL_CCIR		(1 << 0)
178 #define	TDA_SERIALIZER		MKREG(0x02, 0x03)
179 #define	TDA_BUFFER_OUT		MKREG(0x02, 0x04)
180 #define	TDA_PLL_SCG1		MKREG(0x02, 0x05)
181 #define	TDA_PLL_SCG2		MKREG(0x02, 0x06)
182 #define	TDA_PLL_SCGN1		MKREG(0x02, 0x07)
183 #define	TDA_PLL_SCGN2		MKREG(0x02, 0x08)
184 #define	TDA_PLL_SCGR1		MKREG(0x02, 0x09)
185 #define	TDA_PLL_SCGR2		MKREG(0x02, 0x0a)
186 
187 #define	TDA_SEL_CLK		MKREG(0x02, 0x11)
188 #define		SEL_CLK_ENA_SC_CLK	(1 << 3)
189 #define		SEL_CLK_SEL_VRF_CLK(x)	(((x) & 3) << 1)
190 #define		SEL_CLK_SEL_CLK1	(1 << 0)
191 #define	TDA_ANA_GENERAL		MKREG(0x02, 0x12)
192 
193 #define	TDA_EDID_DATA0		MKREG(0x09, 0x00)
194 #define	TDA_EDID_CTRL		MKREG(0x09, 0xfa)
195 #define	TDA_DDC_ADDR		MKREG(0x09, 0xfb)
196 #define	TDA_DDC_OFFS		MKREG(0x09, 0xfc)
197 #define	TDA_DDC_SEGM_ADDR	MKREG(0x09, 0xfd)
198 #define	TDA_DDC_SEGM		MKREG(0x09, 0xfe)
199 
200 #define	TDA_IF_VSP		MKREG(0x10, 0x20)
201 #define	TDA_IF_AVI		MKREG(0x10, 0x40)
202 #define	TDA_IF_SPD		MKREG(0x10, 0x60)
203 #define	TDA_IF_AUD		MKREG(0x10, 0x80)
204 #define	TDA_IF_MPS		MKREG(0x10, 0xa0)
205 
206 #define	TDA_ENC_CNTRL		MKREG(0x11, 0x0d)
207 #define		ENC_CNTRL_DVI_MODE	(0 << 2)
208 #define		ENC_CNTRL_HDMI_MODE	(1 << 2)
209 #define	TDA_DIP_IF_FLAGS	MKREG(0x11, 0x0f)
210 #define		DIP_IF_FLAGS_IF5	(1 << 5)
211 #define		DIP_IF_FLAGS_IF4	(1 << 4)
212 #define		DIP_IF_FLAGS_IF3	(1 << 3)
213 #define		DIP_IF_FLAGS_IF2	(1 << 2) /*  AVI IF on page 10h */
214 #define		DIP_IF_FLAGS_IF1	(1 << 1)
215 
216 #define	TDA_TX3			MKREG(0x12, 0x9a)
217 #define	TDA_TX4			MKREG(0x12, 0x9b)
218 #define		TX4_PD_RAM		(1 << 1)
219 #define	TDA_HDCP_TX33		MKREG(0x12, 0xb8)
220 #define		HDCP_TX33_HDMI		(1 << 1)
221 
222 #define	TDA_CURPAGE_ADDR	0xff
223 
224 #define	TDA_CEC_ENAMODS		0xff
225 #define		ENAMODS_RXSENS		(1 << 2)
226 #define		ENAMODS_HDMI		(1 << 1)
227 #define	TDA_CEC_FRO_IM_CLK_CTRL	0xfb
228 #define		CEC_FRO_IM_CLK_CTRL_GHOST_DIS	(1 << 7)
229 #define		CEC_FRO_IM_CLK_CTRL_IMCLK_SEL	(1 << 1)
230 
231 /* EDID reading */
232 #define	EDID_LENGTH		0x80
233 #define	MAX_READ_ATTEMPTS	100
234 
235 /* EDID fields */
236 #define	EDID_MODES0		35
237 #define	EDID_MODES1		36
238 #define	EDID_TIMING_START	38
239 #define	EDID_TIMING_END		54
240 #define	EDID_TIMING_X(v)	(((v) + 31) * 8)
241 #define	EDID_FREQ(v)		(((v) & 0x3f) + 60)
242 #define	EDID_RATIO(v)		(((v) >> 6) & 0x3)
243 #define	EDID_RATIO_10x16	0
244 #define	EDID_RATIO_3x4		1
245 #define	EDID_RATIO_4x5		2
246 #define	EDID_RATIO_9x16		3
247 
248 /* NXP TDA19988 slave addrs. */
249 #define	TDA_HDMI		0x70
250 #define	TDA_CEC			0x34
251 
252 /* debug/etc macros */
253 #define DEVNAME(s)		((s)->sc_dev.dv_xname)
254 #ifdef NXPTDA_DEBUG
255 int nxphdmi_debug = 1;
256 #define DPRINTF(n,s)	do { if ((n) <= nxphdmi_debug) printf s; } while (0)
257 #else
258 #define DPRINTF(n,s)	do {} while (0)
259 #endif
260 
261 struct nxphdmi_softc {
262 	struct device	sc_dev;
263 	i2c_tag_t	sc_tag;
264 	i2c_addr_t	sc_addr;
265 
266 	uint8_t		sc_curpage;
267 	uint8_t		sc_edid[EDID_LENGTH];
268 };
269 
270 int	nxphdmi_match(struct device *, void *, void *);
271 void	nxphdmi_attach(struct device *, struct device *, void *);
272 
273 int	nxphdmi_cec_read(struct nxphdmi_softc *, uint8_t, uint8_t *);
274 int	nxphdmi_cec_write(struct nxphdmi_softc *, uint8_t, uint8_t);
275 int	nxphdmi_read(struct nxphdmi_softc *, uint16_t, uint8_t *);
276 int	nxphdmi_write(struct nxphdmi_softc *, uint16_t, uint8_t);
277 int	nxphdmi_write2(struct nxphdmi_softc *, uint16_t, uint16_t);
278 int	nxphdmi_set(struct nxphdmi_softc *, uint16_t, uint8_t);
279 int	nxphdmi_clear(struct nxphdmi_softc *, uint16_t, uint8_t);
280 int	nxphdmi_set_page(struct nxphdmi_softc *, uint8_t);
281 int	nxphdmi_read_edid(struct nxphdmi_softc *);
282 int	nxphdmi_reset(struct nxphdmi_softc *);
283 int	nxphdmi_init_encoder(struct nxphdmi_softc *, struct videomode *);
284 
285 int	nxphdmi_get_edid(uint8_t *, int);
286 int	nxphdmi_set_videomode(struct videomode *);
287 
288 const struct cfattach nxphdmi_ca = {
289 	sizeof(struct nxphdmi_softc), nxphdmi_match, nxphdmi_attach
290 };
291 
292 struct cfdriver nxphdmi_cd = {
293 	NULL, "nxphdmi", DV_DULL
294 };
295 
296 int
nxphdmi_match(struct device * parent,void * match,void * aux)297 nxphdmi_match(struct device *parent, void *match, void *aux)
298 {
299 	struct i2c_attach_args *ia = aux;
300 
301 	if (strcmp(ia->ia_name, "nxp,tda998x") == 0)
302 		return 1;
303 
304 	return 0;
305 }
306 
307 void
nxphdmi_attach(struct device * parent,struct device * self,void * aux)308 nxphdmi_attach(struct device *parent, struct device *self, void *aux)
309 {
310 	struct nxphdmi_softc *sc = (struct nxphdmi_softc *)self;
311 	struct i2c_attach_args *ia = aux;
312 	uint8_t data = 0;
313 	uint16_t version = 0;
314 	int res = 0, node = *(int *)(ia->ia_cookie);
315 
316 	sc->sc_tag = ia->ia_tag;
317 	sc->sc_addr = ia->ia_addr;
318 	sc->sc_curpage = 0xff;
319 
320 	if (!node) {
321 		printf(": not configured\n");
322 		return;
323 	} else if ((pinctrl_byname(node, "default") == -1)) {
324 		printf(": not configured\n");
325 		return;
326 	}
327 
328 	iic_acquire_bus(sc->sc_tag, 0);
329 
330 	DPRINTF(3,("\n"));
331 
332 	/* enable HDMI core */
333 	nxphdmi_cec_write(sc, TDA_CEC_ENAMODS, ENAMODS_RXSENS | ENAMODS_HDMI);
334 	delay(1000);
335 
336 	if (!(nxphdmi_reset(sc)))
337 		DPRINTF(3,("%s: software reset OK\n", DEVNAME(sc)));
338 	else
339 		DPRINTF(3,("%s: software reset failed!\n", DEVNAME(sc)));
340 
341 	/*  PLL registers common configuration */
342 	nxphdmi_write(sc, TDA_PLL_SERIAL_1, 0x00);
343 	nxphdmi_write(sc, TDA_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(1));
344 	nxphdmi_write(sc, TDA_PLL_SERIAL_3, 0x00);
345 	nxphdmi_write(sc, TDA_SERIALIZER, 0x00);
346 	nxphdmi_write(sc, TDA_BUFFER_OUT, 0x00);
347 	nxphdmi_write(sc, TDA_PLL_SCG1, 0x00);
348 	nxphdmi_write(sc, TDA_SEL_CLK, SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
349 	nxphdmi_write(sc, TDA_PLL_SCGN1, 0xfa);
350 	nxphdmi_write(sc, TDA_PLL_SCGN2, 0x00);
351 	nxphdmi_write(sc, TDA_PLL_SCGR1, 0x5b);
352 	nxphdmi_write(sc, TDA_PLL_SCGR2, 0x00);
353 	nxphdmi_write(sc, TDA_PLL_SCG2, 0x10);
354 
355 	/*  Write the default value MUX register */
356 	nxphdmi_write(sc, TDA_MUX_VP_VIP_OUT, 0x24);
357 
358 	res |= nxphdmi_read(sc, TDA_VERSION, &data);
359 	version |= data;
360 	res |= nxphdmi_read(sc, TDA_VERSION_MSB, &data);
361 	version |= (data << 8);
362 	version &= ~0x30;
363 
364 	if (!res) {
365 		DPRINTF(3,("%s: ", DEVNAME(sc)));
366 		printf(": rev 0x%04x\n", version);
367 	} else {
368 		DPRINTF(3,("%s: ", DEVNAME(sc)));
369 		printf(": failed to enable HDMI core, exiting...\n");
370 		iic_release_bus(sc->sc_tag, 0);
371 		return;
372 	}
373 
374 	nxphdmi_write(sc, TDA_DDC_CTRL, DDC_ENABLE);
375 	nxphdmi_write(sc, TDA_TX3, 39);
376 
377 	nxphdmi_cec_write(sc, TDA_CEC_FRO_IM_CLK_CTRL,
378 	    CEC_FRO_IM_CLK_CTRL_GHOST_DIS | CEC_FRO_IM_CLK_CTRL_IMCLK_SEL);
379 
380 	if (nxphdmi_read_edid(sc)) {
381 		DPRINTF(3,("%s: failed to read EDID bits, exiting!\n",
382 		    DEVNAME(sc)));
383 		return;
384 	}
385 
386 	/*  Default values for RGB 4:4:4 mapping */
387 	nxphdmi_write(sc, TDA_VIP_CNTRL_0, 0x23);
388 	nxphdmi_write(sc, TDA_VIP_CNTRL_1, 0x01);
389 	nxphdmi_write(sc, TDA_VIP_CNTRL_2, 0x45);
390 
391 	iic_release_bus(sc->sc_tag, 0);
392 }
393 
394 int
nxphdmi_cec_read(struct nxphdmi_softc * sc,uint8_t addr,uint8_t * buf)395 nxphdmi_cec_read(struct nxphdmi_softc *sc, uint8_t addr, uint8_t *buf)
396 {
397 	int ret = 0;
398 
399 	if ((ret |= iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, TDA_CEC,
400 	    &addr, 1, NULL, 0, 0))) {
401 		DPRINTF(3,("%s: (CEC) failed to read addr 0x%02x, errno %d\n",
402 		    DEVNAME(sc), addr, ret));
403 		return ret;
404 	}
405 
406 	DPRINTF(3,("%s: (CEC) read 0x%02x from 0x%02x\n", DEVNAME(sc), *buf,
407 	    addr));
408 
409 	return ret;
410 }
411 
412 int
nxphdmi_cec_write(struct nxphdmi_softc * sc,uint8_t addr,uint8_t val)413 nxphdmi_cec_write(struct nxphdmi_softc *sc, uint8_t addr, uint8_t val)
414 {
415 	int ret = 0;
416 	uint8_t sendbuf[] = { addr, val };
417 
418 	if ((ret |= iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, TDA_CEC,
419 	    &sendbuf, 2, NULL, 0, 0))) {
420 		DPRINTF(3,(
421 		    "%s: (CEC) failed to write 0x%02x to 0x%02x, errno %d\n",
422 		    DEVNAME(sc), val, addr, ret));
423 		return ret;
424 	}
425 
426 	DPRINTF(3,("%s: (CEC) wrote 0x%02x to 0x%02x\n", DEVNAME(sc), val,
427 	    addr));
428 
429 	return ret;
430 }
431 
432 int
nxphdmi_read(struct nxphdmi_softc * sc,uint16_t reg,uint8_t * buf)433 nxphdmi_read(struct nxphdmi_softc *sc, uint16_t reg, uint8_t *buf)
434 {
435 	int ret = 0;
436 
437 	nxphdmi_set_page(sc, REGPAGE(reg));
438 
439 	if ((ret = iic_smbus_read_byte(sc->sc_tag, TDA_HDMI, REGADDR(reg),
440 	    buf, 0))) {
441 		DPRINTF(3,(
442 		    "%s: failed to read addr 0x%02x on page 0x%02x, errno %d\n",
443 		    DEVNAME(sc), REGADDR(reg), REGPAGE(reg), ret));
444 		return ret;
445 	}
446 
447 	DPRINTF(3,("%s: read  0x%02x from 0x%02x on page 0x%02x\n",
448 	    DEVNAME(sc), *buf, REGADDR(reg), REGPAGE(reg)));
449 
450 	return ret;
451 }
452 
453 int
nxphdmi_write(struct nxphdmi_softc * sc,uint16_t reg,uint8_t val)454 nxphdmi_write(struct nxphdmi_softc *sc, uint16_t reg, uint8_t val)
455 {
456 	int ret = 0;
457 	uint8_t sendbuf[] = { REGADDR(reg), val };
458 
459 	nxphdmi_set_page(sc, REGPAGE(reg));
460 
461 	if ((ret = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, TDA_HDMI,
462 	    &sendbuf, 2, NULL, 0, 0))) {
463 	    DPRINTF(3,(
464 		"%s: failed to write 0x%02x to 0x%02x on page 0x%02x, errno %d\n",
465 		DEVNAME(sc), val, REGADDR(reg), REGPAGE(reg), ret));
466 		return ret;
467 	}
468 
469 	DPRINTF(3,("%s: wrote 0x%02x  to  0x%02x on page 0x%02x\n",
470 	    DEVNAME(sc), val, REGADDR(reg), REGPAGE(reg)));
471 
472 	return ret;
473 }
474 
475 int
nxphdmi_write2(struct nxphdmi_softc * sc,uint16_t reg,uint16_t val)476 nxphdmi_write2(struct nxphdmi_softc *sc, uint16_t reg, uint16_t val)
477 {
478 	int ret = 0;
479 	uint8_t sendbuf[] = { REGADDR(reg), val >> 8, val & 0xff };
480 
481 	nxphdmi_set_page(sc, REGPAGE(reg));
482 
483 	if ((ret = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, TDA_HDMI,
484 	    &sendbuf, 3, NULL, 0, 0))) {
485 		DPRINTF(3,(
486 		"%s: failed to write 0x%04x to 0x%02x on page 0x%02x, errno %d\n",
487 		DEVNAME(sc), val, REGADDR(reg), REGPAGE(reg), ret));
488 		return ret;
489 	}
490 
491 	DPRINTF(3,("%s: wrote 0x%04x  to  0x%02x on page 0x%02x\n",
492 	    DEVNAME(sc), val, REGADDR(reg), REGPAGE(reg)));
493 
494 	return ret;
495 
496 }
497 
498 int
nxphdmi_set(struct nxphdmi_softc * sc,uint16_t reg,uint8_t bits)499 nxphdmi_set(struct nxphdmi_softc *sc, uint16_t reg, uint8_t bits)
500 {
501 	int ret = 0;
502 	uint8_t buf;
503 
504 	ret |= nxphdmi_read(sc, reg, &buf);
505 	buf |= bits;
506 	ret |= nxphdmi_write(sc, reg, buf);
507 
508 	return ret;
509 }
510 
511 int
nxphdmi_clear(struct nxphdmi_softc * sc,uint16_t reg,uint8_t bits)512 nxphdmi_clear(struct nxphdmi_softc *sc, uint16_t reg, uint8_t bits)
513 {
514 	int ret = 0;
515 	uint8_t buf;
516 
517 	ret |= nxphdmi_read(sc, reg, &buf);
518 	buf &= ~bits;
519 	ret |= nxphdmi_write(sc, reg, buf);
520 
521 	return ret;
522 }
523 
524 int
nxphdmi_set_page(struct nxphdmi_softc * sc,uint8_t page)525 nxphdmi_set_page(struct nxphdmi_softc *sc, uint8_t page)
526 {
527 	int ret = 0;
528 	uint8_t sendbuf[] = { TDA_CURPAGE_ADDR, page };
529 
530 	if (sc->sc_curpage == page)
531 		return ret;
532 
533 	if ((ret = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, TDA_HDMI,
534 	    &sendbuf, sizeof(sendbuf), NULL, 0, 0))) {
535 		DPRINTF(3,("%s: failed to set memory page 0x%02x, errno %d\n",
536 		    DEVNAME(sc),
537 		page, ret));
538 		return ret;
539 	}
540 
541 	sc->sc_curpage = page;
542 	DPRINTF(3,("%s: set page to 0x%02x\n", DEVNAME(sc), page));
543 
544 	return ret;
545 }
546 
547 int
nxphdmi_read_edid(struct nxphdmi_softc * sc)548 nxphdmi_read_edid(struct nxphdmi_softc *sc)
549 {
550 	int i = 0, ret = 0;
551 	uint8_t reg;
552 
553 	nxphdmi_set(sc, TDA_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
554 
555 	/*  Block 0 */
556 	nxphdmi_write(sc, TDA_DDC_ADDR, 0xa0);
557 	nxphdmi_write(sc, TDA_DDC_OFFS, 0x00);
558 	nxphdmi_write(sc, TDA_DDC_SEGM_ADDR, 0x60);
559 	nxphdmi_write(sc, TDA_DDC_SEGM, 0x00);
560 
561 	nxphdmi_write(sc, TDA_EDID_CTRL, 1);
562 	nxphdmi_write(sc, TDA_EDID_CTRL, 0);
563 
564 	for (; i < MAX_READ_ATTEMPTS; i++) {
565 		nxphdmi_read(sc, TDA_INT_FLAGS_2, &reg);
566 		if (reg & INT_FLAGS_2_EDID_BLK_RD) {
567 			DPRINTF(3,("%s: EDID-ready IRQ fired\n", DEVNAME(sc)));
568 			break;
569 		}
570 	}
571 
572 	if (i == MAX_READ_ATTEMPTS) {
573 		printf("%s: no display detected\n", DEVNAME(sc));
574 		ret = ENXIO;
575 		return ret;
576 	}
577 
578 	nxphdmi_set_page(sc, 0x09);
579 
580 	reg = 0x00;
581 	DPRINTF(1,("%s: ------------- EDID -------------", DEVNAME(sc)));
582 	for (i = 0; i < EDID_LENGTH; i++) {
583 		iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, TDA_HDMI, &reg, 1,
584 		    &sc->sc_edid[i], 1, 0);
585 		if (!(i % 16))
586 			DPRINTF(1,("\n%s: ", DEVNAME(sc)));
587 		DPRINTF(1,("%02x", sc->sc_edid[i]));
588 		reg++;
589 	}
590 	DPRINTF(1,("\n%s: --------------------------------\n", DEVNAME(sc)));
591 
592 	nxphdmi_clear(sc, TDA_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
593 	nxphdmi_set(sc, TDA_TX4, TX4_PD_RAM);
594 
595 	return ret;
596 }
597 
598 int
nxphdmi_reset(struct nxphdmi_softc * sc)599 nxphdmi_reset(struct nxphdmi_softc *sc)
600 {
601 	int ret = 0;
602 
603 	/* reset core */
604 	ret |= nxphdmi_set(sc, TDA_SOFTRESET, 3);
605 	delay(100);
606 	ret |= nxphdmi_clear(sc, TDA_SOFTRESET, 3);
607 	delay(100);
608 
609 	/* reset transmitter */
610 	ret |= nxphdmi_set(sc, TDA_MAIN_CNTRL0, MAIN_CNTRL0_SR);
611 	ret |= nxphdmi_clear(sc, TDA_MAIN_CNTRL0, MAIN_CNTRL0_SR);
612 
613 	return ret;
614 }
615 
616 int
nxphdmi_init_encoder(struct nxphdmi_softc * sc,struct videomode * mode)617 nxphdmi_init_encoder(struct nxphdmi_softc *sc, struct videomode *mode)
618 {
619 	int ret = 0;
620 
621 	uint16_t ref_pix, ref_line, n_pix, n_line;
622 	uint16_t hs_pix_start, hs_pix_stop;
623 	uint16_t vs1_pix_start, vs1_pix_stop;
624 	uint16_t vs1_line_start, vs1_line_end;
625 	uint16_t vs2_pix_start, vs2_pix_stop;
626 	uint16_t vs2_line_start, vs2_line_end;
627 	uint16_t vwin1_line_start, vwin1_line_end;
628 	uint16_t vwin2_line_start, vwin2_line_end;
629 	uint16_t de_start, de_stop;
630 	uint8_t reg, div;
631 
632 	n_pix = mode->htotal;
633 	n_line = mode->vtotal;
634 
635 	hs_pix_stop = mode->hsync_end - mode->hdisplay;
636 	hs_pix_start = mode->hsync_start - mode->hdisplay;
637 
638 	de_stop = mode->htotal;
639 	de_start = mode->htotal - mode->hdisplay;
640 	ref_pix = hs_pix_start + 3;
641 
642 	if (mode->flags & VID_HSKEW)
643 		ref_pix += mode->hsync_end - mode->hsync_start;
644 
645 	if ((mode->flags & VID_INTERLACE) == 0) {
646 		ref_line = 1 + mode->vsync_start - mode->vdisplay;
647 		vwin1_line_start = mode->vtotal - mode->vdisplay - 1;
648 		vwin1_line_end = vwin1_line_start + mode->vdisplay;
649 
650 		vs1_pix_start = vs1_pix_stop = hs_pix_start;
651 		vs1_line_start = mode->vsync_start - mode->vdisplay;
652 		vs1_line_end = vs1_line_start +
653 		    mode->vsync_end - mode->vsync_start;
654 
655 		vwin2_line_start = vwin2_line_end = 0;
656 		vs2_pix_start = vs2_pix_stop = 0;
657 		vs2_line_start = vs2_line_end = 0;
658 	} else {
659 		ref_line = 1 + (mode->vsync_start - mode->vdisplay)/2;
660 		vwin1_line_start = (mode->vtotal - mode->vdisplay)/2;
661 		vwin1_line_end = vwin1_line_start + mode->vdisplay/2;
662 
663 		vs1_pix_start = vs1_pix_stop = hs_pix_start;
664 		vs1_line_start = (mode->vsync_start - mode->vdisplay)/2;
665 		vs1_line_end = vs1_line_start +
666 		    (mode->vsync_end - mode->vsync_start)/2;
667 
668 		vwin2_line_start = vwin1_line_start + mode->vtotal/2;
669 		vwin2_line_end = vwin2_line_start + mode->vdisplay/2;
670 
671 		vs2_pix_start = vs2_pix_stop = hs_pix_start + mode->htotal/2;
672 		vs2_line_start = vs1_line_start + mode->vtotal/2 ;
673 		vs2_line_end = vs2_line_start +
674 		    (mode->vsync_end - mode->vsync_start)/2;
675 	}
676 
677 	div = 148500 / mode->dot_clock;
678 	if (div != 0) {
679 		div--;
680 		if (div > 3)
681 			div = 3;
682 	}
683 
684 	/*  set HDMI HDCP mode off */
685 	nxphdmi_set(sc, TDA_TBG_CNTRL_1, TBG_CNTRL_1_DWIN_DIS);
686 	nxphdmi_clear(sc, TDA_HDCP_TX33, HDCP_TX33_HDMI);
687 	nxphdmi_write(sc, TDA_ENC_CNTRL, ENC_CNTRL_DVI_MODE);
688 
689 	/*  no pre-filter or interpolator */
690 	nxphdmi_write(sc, TDA_HVF_CNTRL_0,
691 	    HVF_CNTRL_0_INTPOL_BYPASS | HVF_CNTRL_0_PREFIL_NONE);
692 	nxphdmi_write(sc, TDA_VIP_CNTRL_5, VIP_CNTRL_5_SP_CNT(0));
693 	nxphdmi_write(sc, TDA_VIP_CNTRL_4,
694 	    VIP_CNTRL_4_BLANKIT_NDE | VIP_CNTRL_4_BLC_NONE);
695 
696 	nxphdmi_clear(sc, TDA_PLL_SERIAL_3, PLL_SERIAL_3_SRL_CCIR);
697 	nxphdmi_clear(sc, TDA_PLL_SERIAL_1, PLL_SERIAL_1_SRL_MAN_IP);
698 	nxphdmi_clear(sc, TDA_PLL_SERIAL_3, PLL_SERIAL_3_SRL_DE);
699 	nxphdmi_write(sc, TDA_SERIALIZER, 0);
700 	nxphdmi_write(sc, TDA_HVF_CNTRL_1, HVF_CNTRL_1_VQR_FULL);
701 
702 	nxphdmi_write(sc, TDA_RPT_CNTRL, 0);
703 	nxphdmi_write(sc, TDA_SEL_CLK, SEL_CLK_SEL_VRF_CLK(0) |
704 			SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
705 
706 	nxphdmi_write(sc, TDA_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) |
707 			PLL_SERIAL_2_SRL_PR(0));
708 
709 	nxphdmi_set(sc, TDA_MAT_CONTRL, MAT_CONTRL_MAT_BP);
710 
711 	nxphdmi_write(sc, TDA_ANA_GENERAL, 0x09);
712 
713 	nxphdmi_clear(sc, TDA_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_MTHD);
714 
715 	/*
716 	 * Sync on rising HSYNC/VSYNC
717 	 */
718 	reg = VIP_CNTRL_3_SYNC_HS;
719 	if (mode->flags & VID_NHSYNC)
720 		reg |= VIP_CNTRL_3_H_TGL;
721 	if (mode->flags & VID_NVSYNC)
722 		reg |= VIP_CNTRL_3_V_TGL;
723 	nxphdmi_write(sc, TDA_VIP_CNTRL_3, reg);
724 
725 	reg = TBG_CNTRL_1_TGL_EN;
726 	if (mode->flags & VID_NHSYNC)
727 		reg |= TBG_CNTRL_1_H_TGL;
728 	if (mode->flags & VID_NVSYNC)
729 		reg |= TBG_CNTRL_1_V_TGL;
730 	nxphdmi_write(sc, TDA_TBG_CNTRL_1, reg);
731 
732 	/*  Program timing */
733 	nxphdmi_write(sc, TDA_VIDFORMAT, 0x00);
734 
735 	nxphdmi_write2(sc, TDA_REFPIX_MSB, ref_pix);
736 	nxphdmi_write2(sc, TDA_REFLINE_MSB, ref_line);
737 	nxphdmi_write2(sc, TDA_NPIX_MSB, n_pix);
738 	nxphdmi_write2(sc, TDA_NLINE_MSB, n_line);
739 
740 	nxphdmi_write2(sc, TDA_VS_LINE_STRT_1_MSB, vs1_line_start);
741 	nxphdmi_write2(sc, TDA_VS_PIX_STRT_1_MSB, vs1_pix_start);
742 	nxphdmi_write2(sc, TDA_VS_LINE_END_1_MSB, vs1_line_end);
743 	nxphdmi_write2(sc, TDA_VS_PIX_END_1_MSB, vs1_pix_stop);
744 	nxphdmi_write2(sc, TDA_VS_LINE_STRT_2_MSB, vs2_line_start);
745 	nxphdmi_write2(sc, TDA_VS_PIX_STRT_2_MSB, vs2_pix_start);
746 	nxphdmi_write2(sc, TDA_VS_LINE_END_2_MSB, vs2_line_end);
747 	nxphdmi_write2(sc, TDA_VS_PIX_END_2_MSB, vs2_pix_stop);
748 	nxphdmi_write2(sc, TDA_HS_PIX_START_MSB, hs_pix_start);
749 	nxphdmi_write2(sc, TDA_HS_PIX_STOP_MSB, hs_pix_stop);
750 	nxphdmi_write2(sc, TDA_VWIN_START_1_MSB, vwin1_line_start);
751 	nxphdmi_write2(sc, TDA_VWIN_END_1_MSB, vwin1_line_end);
752 	nxphdmi_write2(sc, TDA_VWIN_START_2_MSB, vwin2_line_start);
753 	nxphdmi_write2(sc, TDA_VWIN_END_2_MSB, vwin2_line_end);
754 	nxphdmi_write2(sc, TDA_DE_START_MSB, de_start);
755 	nxphdmi_write2(sc, TDA_DE_STOP_MSB, de_stop);
756 
757 	nxphdmi_write(sc, TDA_ENABLE_SPACE, 0x00);
758 
759 	/*  must be last register set */
760 	nxphdmi_clear(sc, TDA_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_ONCE);
761 
762 	return ret;
763 }
764 
765 int
nxphdmi_get_edid(uint8_t * buf,int buflen)766 nxphdmi_get_edid(uint8_t *buf, int buflen)
767 {
768 	int ret = 0, i;
769 	struct nxphdmi_softc *sc = nxphdmi_cd.cd_devs[0];
770 
771 	if (buflen < EDID_LENGTH)
772 		return -1;
773 
774 	for (i = 0; i < EDID_LENGTH; i++)
775 		buf[i] = sc->sc_edid[i];
776 
777 	return ret;
778 }
779 
780 int
nxphdmi_set_videomode(struct videomode * mode)781 nxphdmi_set_videomode(struct videomode *mode)
782 {
783 	int ret = 0;
784 	struct nxphdmi_softc *sc = nxphdmi_cd.cd_devs[0];
785 
786 	ret = nxphdmi_init_encoder(sc, mode);
787 
788 	return ret;
789 }
790