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 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 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 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 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 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 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 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 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 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 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 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, ®); 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, ®, 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 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 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 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 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