a10_hdmi.c revision 297514
1/*- 2 * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/sys/arm/allwinner/a10_hdmi.c 297514 2016-04-02 16:53:12Z jmcneill $ 27 */ 28 29/* 30 * Allwinner A10/A20 HDMI TX 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: head/sys/arm/allwinner/a10_hdmi.c 297514 2016-04-02 16:53:12Z jmcneill $"); 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/bus.h> 39#include <sys/rman.h> 40#include <sys/condvar.h> 41#include <sys/kernel.h> 42#include <sys/module.h> 43 44#include <machine/bus.h> 45 46#include <dev/ofw/ofw_bus.h> 47#include <dev/ofw/ofw_bus_subr.h> 48 49#include <dev/videomode/videomode.h> 50#include <dev/videomode/edidvar.h> 51 52#include <arm/allwinner/a10_clk.h> 53 54#include "hdmi_if.h" 55 56#define HDMI_CTRL 0x004 57#define CTRL_MODULE_EN (1 << 31) 58#define HDMI_INT_STATUS 0x008 59#define HDMI_HPD 0x00c 60#define HPD_DET (1 << 0) 61#define HDMI_VID_CTRL 0x010 62#define VID_CTRL_VIDEO_EN (1 << 31) 63#define VID_CTRL_HDMI_MODE (1 << 30) 64#define VID_CTRL_INTERLACE (1 << 4) 65#define VID_CTRL_REPEATER_2X (1 << 0) 66#define HDMI_VID_TIMING0 0x014 67#define VID_ACT_V(v) (((v) - 1) << 16) 68#define VID_ACT_H(h) (((h) - 1) << 0) 69#define HDMI_VID_TIMING1 0x018 70#define VID_VBP(vbp) (((vbp) - 1) << 16) 71#define VID_HBP(hbp) (((hbp) - 1) << 0) 72#define HDMI_VID_TIMING2 0x01c 73#define VID_VFP(vfp) (((vfp) - 1) << 16) 74#define VID_HFP(hfp) (((hfp) - 1) << 0) 75#define HDMI_VID_TIMING3 0x020 76#define VID_VSPW(vspw) (((vspw) - 1) << 16) 77#define VID_HSPW(hspw) (((hspw) - 1) << 0) 78#define HDMI_VID_TIMING4 0x024 79#define TX_CLOCK_NORMAL 0x03e00000 80#define VID_VSYNC_ACTSEL (1 << 1) 81#define VID_HSYNC_ACTSEL (1 << 0) 82#define HDMI_AUD_CTRL 0x040 83#define AUD_CTRL_EN (1 << 31) 84#define AUD_CTRL_RST (1 << 30) 85#define HDMI_ADMA_CTRL 0x044 86#define HDMI_ADMA_MODE (1 << 31) 87#define HDMI_ADMA_MODE_DDMA (0 << 31) 88#define HDMI_ADMA_MODE_NDMA (1 << 31) 89#define HDMI_AUD_FMT 0x048 90#define AUD_FMT_CH(n) ((n) - 1) 91#define HDMI_PCM_CTRL 0x04c 92#define HDMI_AUD_CTS 0x050 93#define HDMI_AUD_N 0x054 94#define HDMI_AUD_CH_STATUS0 0x058 95#define CH_STATUS0_FS_FREQ (0xf << 24) 96#define CH_STATUS0_FS_FREQ_48 (2 << 24) 97#define HDMI_AUD_CH_STATUS1 0x05c 98#define CH_STATUS1_WORD_LEN (0x7 << 1) 99#define CH_STATUS1_WORD_LEN_16 (1 << 1) 100#define HDMI_AUDIO_RESET_RETRY 1000 101#define HDMI_AUDIO_CHANNELS 2 102#define HDMI_AUDIO_CHANNELMAP 0x76543210 103#define HDMI_AUDIO_N 6144 /* 48 kHz */ 104#define HDMI_AUDIO_CTS(r, n) ((((r) * 10) * ((n) / 128)) / 480) 105#define HDMI_PADCTRL0 0x200 106#define PADCTRL0_BIASEN (1 << 31) 107#define PADCTRL0_LDOCEN (1 << 30) 108#define PADCTRL0_LDODEN (1 << 29) 109#define PADCTRL0_PWENC (1 << 28) 110#define PADCTRL0_PWEND (1 << 27) 111#define PADCTRL0_PWENG (1 << 26) 112#define PADCTRL0_CKEN (1 << 25) 113#define PADCTRL0_SEN (1 << 24) 114#define PADCTRL0_TXEN (1 << 23) 115#define HDMI_PADCTRL1 0x204 116#define PADCTRL1_AMP_OPT (1 << 23) 117#define PADCTRL1_AMPCK_OPT (1 << 22) 118#define PADCTRL1_DMP_OPT (1 << 21) 119#define PADCTRL1_EMP_OPT (1 << 20) 120#define PADCTRL1_EMPCK_OPT (1 << 19) 121#define PADCTRL1_PWSCK (1 << 18) 122#define PADCTRL1_PWSDT (1 << 17) 123#define PADCTRL1_REG_CSMPS (1 << 16) 124#define PADCTRL1_REG_DEN (1 << 15) 125#define PADCTRL1_REG_DENCK (1 << 14) 126#define PADCTRL1_REG_PLRCK (1 << 13) 127#define PADCTRL1_REG_EMP (0x7 << 10) 128#define PADCTRL1_REG_EMP_EN (0x2 << 10) 129#define PADCTRL1_REG_CD (0x3 << 8) 130#define PADCTRL1_REG_CKSS (0x3 << 6) 131#define PADCTRL1_REG_CKSS_1X (0x1 << 6) 132#define PADCTRL1_REG_CKSS_2X (0x0 << 6) 133#define PADCTRL1_REG_AMP (0x7 << 3) 134#define PADCTRL1_REG_AMP_EN (0x6 << 3) 135#define PADCTRL1_REG_PLR (0x7 << 0) 136#define HDMI_PLLCTRL0 0x208 137#define PLLCTRL0_PLL_EN (1 << 31) 138#define PLLCTRL0_BWS (1 << 30) 139#define PLLCTRL0_HV_IS_33 (1 << 29) 140#define PLLCTRL0_LDO1_EN (1 << 28) 141#define PLLCTRL0_LDO2_EN (1 << 27) 142#define PLLCTRL0_SDIV2 (1 << 25) 143#define PLLCTRL0_VCO_GAIN (0x1 << 22) 144#define PLLCTRL0_S (0x7 << 17) 145#define PLLCTRL0_CP_S (0xf << 12) 146#define PLLCTRL0_CS (0x7 << 8) 147#define PLLCTRL0_PREDIV(x) ((x) << 4) 148#define PLLCTRL0_VCO_S (0x8 << 0) 149#define HDMI_PLLDBG0 0x20c 150#define PLLDBG0_CKIN_SEL (1 << 21) 151#define PLLDBG0_CKIN_SEL_PLL3 (0 << 21) 152#define PLLDBG0_CKIN_SEL_PLL7 (1 << 21) 153#define HDMI_PKTCTRL0 0x2f0 154#define HDMI_PKTCTRL1 0x2f4 155#define PKTCTRL_PACKET(n,t) ((t) << ((n) << 2)) 156#define PKT_NULL 0 157#define PKT_GC 1 158#define PKT_AVI 2 159#define PKT_AI 3 160#define PKT_SPD 5 161#define PKT_END 15 162#define DDC_CTRL 0x500 163#define CTRL_DDC_EN (1 << 31) 164#define CTRL_DDC_ACMD_START (1 << 30) 165#define CTRL_DDC_FIFO_DIR (1 << 8) 166#define CTRL_DDC_FIFO_DIR_READ (0 << 8) 167#define CTRL_DDC_FIFO_DIR_WRITE (1 << 8) 168#define CTRL_DDC_SWRST (1 << 0) 169#define DDC_SLAVE_ADDR 0x504 170#define SLAVE_ADDR_SEG_SHIFT 24 171#define SLAVE_ADDR_EDDC_SHIFT 16 172#define SLAVE_ADDR_OFFSET_SHIFT 8 173#define SLAVE_ADDR_SHIFT 0 174#define DDC_INT_STATUS 0x50c 175#define INT_STATUS_XFER_DONE (1 << 0) 176#define DDC_FIFO_CTRL 0x510 177#define FIFO_CTRL_CLEAR (1 << 31) 178#define DDC_BYTE_COUNTER 0x51c 179#define DDC_COMMAND 0x520 180#define COMMAND_EOREAD (4 << 0) 181#define DDC_CLOCK 0x528 182#define DDC_CLOCK_M (1 << 3) 183#define DDC_CLOCK_N (5 << 0) 184#define DDC_FIFO 0x518 185#define SWRST_DELAY 1000 186#define DDC_DELAY 1000 187#define DDC_RETRY 1000 188#define DDC_BLKLEN 16 189#define DDC_ADDR 0x50 190#define EDDC_ADDR 0x60 191#define EDID_LENGTH 128 192#define HDMI_ENABLE_DELAY 50000 193#define DDC_READ_RETRY 4 194#define EXT_TAG 0x00 195#define CEA_TAG_ID 0x02 196#define CEA_DTD 0x03 197#define DTD_BASIC_AUDIO (1 << 6) 198#define CEA_REV 0x02 199#define CEA_DATA_OFF 0x03 200#define CEA_DATA_START 4 201#define BLOCK_TAG(x) (((x) >> 5) & 0x7) 202#define BLOCK_TAG_VSDB 3 203#define BLOCK_LEN(x) ((x) & 0x1f) 204#define HDMI_VSDB_MINLEN 5 205#define HDMI_OUI "\x03\x0c\x00" 206#define HDMI_OUI_LEN 3 207 208struct a10hdmi_softc { 209 struct resource *res; 210 211 struct intr_config_hook mode_hook; 212 213 uint8_t edid[EDID_LENGTH]; 214 215 int has_hdmi; 216 int has_audio; 217}; 218 219static struct resource_spec a10hdmi_spec[] = { 220 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 221 { -1, 0 } 222}; 223 224#define HDMI_READ(sc, reg) bus_read_4((sc)->res, (reg)) 225#define HDMI_WRITE(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) 226 227static void 228a10hdmi_init(struct a10hdmi_softc *sc) 229{ 230 /* Enable the HDMI module */ 231 HDMI_WRITE(sc, HDMI_CTRL, CTRL_MODULE_EN); 232 233 /* Configure PLL/DRV settings */ 234 HDMI_WRITE(sc, HDMI_PADCTRL0, PADCTRL0_BIASEN | PADCTRL0_LDOCEN | 235 PADCTRL0_LDODEN | PADCTRL0_PWENC | PADCTRL0_PWEND | 236 PADCTRL0_PWENG | PADCTRL0_CKEN | PADCTRL0_TXEN); 237 HDMI_WRITE(sc, HDMI_PADCTRL1, PADCTRL1_AMP_OPT | PADCTRL1_AMPCK_OPT | 238 PADCTRL1_EMP_OPT | PADCTRL1_EMPCK_OPT | PADCTRL1_REG_DEN | 239 PADCTRL1_REG_DENCK | PADCTRL1_REG_EMP_EN | PADCTRL1_REG_AMP_EN); 240 241 /* Select PLL3 as input clock */ 242 HDMI_WRITE(sc, HDMI_PLLDBG0, PLLDBG0_CKIN_SEL_PLL3); 243 244 DELAY(HDMI_ENABLE_DELAY); 245} 246 247static void 248a10hdmi_hpd(void *arg) 249{ 250 struct a10hdmi_softc *sc; 251 device_t dev; 252 uint32_t hpd; 253 254 dev = arg; 255 sc = device_get_softc(dev); 256 257 hpd = HDMI_READ(sc, HDMI_HPD); 258 if ((hpd & HPD_DET) == HPD_DET) 259 EVENTHANDLER_INVOKE(hdmi_event, dev, HDMI_EVENT_CONNECTED); 260 261 config_intrhook_disestablish(&sc->mode_hook); 262} 263 264static int 265a10hdmi_probe(device_t dev) 266{ 267 if (!ofw_bus_status_okay(dev)) 268 return (ENXIO); 269 270 if (!ofw_bus_is_compatible(dev, "allwinner,sun7i-a20-hdmi")) 271 return (ENXIO); 272 273 device_set_desc(dev, "Allwinner HDMI TX"); 274 return (BUS_PROBE_DEFAULT); 275} 276 277static int 278a10hdmi_attach(device_t dev) 279{ 280 struct a10hdmi_softc *sc; 281 int error; 282 283 sc = device_get_softc(dev); 284 285 if (bus_alloc_resources(dev, a10hdmi_spec, &sc->res)) { 286 device_printf(dev, "cannot allocate resources for device\n"); 287 return (ENXIO); 288 } 289 290 a10_clk_hdmi_activate(); 291 292 a10hdmi_init(sc); 293 294 sc->mode_hook.ich_func = a10hdmi_hpd; 295 sc->mode_hook.ich_arg = dev; 296 297 error = config_intrhook_establish(&sc->mode_hook); 298 if (error != 0) 299 return (error); 300 301 return (0); 302} 303 304static int 305a10hdmi_ddc_xfer(struct a10hdmi_softc *sc, uint16_t addr, uint8_t seg, 306 uint8_t off, int len) 307{ 308 uint32_t val; 309 int retry; 310 311 /* Set FIFO direction to read */ 312 val = HDMI_READ(sc, DDC_CTRL); 313 val &= ~CTRL_DDC_FIFO_DIR; 314 val |= CTRL_DDC_FIFO_DIR_READ; 315 HDMI_WRITE(sc, DDC_CTRL, val); 316 317 /* Setup DDC slave address */ 318 val = (addr << SLAVE_ADDR_SHIFT) | (seg << SLAVE_ADDR_SEG_SHIFT) | 319 (EDDC_ADDR << SLAVE_ADDR_EDDC_SHIFT) | 320 (off << SLAVE_ADDR_OFFSET_SHIFT); 321 HDMI_WRITE(sc, DDC_SLAVE_ADDR, val); 322 323 /* Clear FIFO */ 324 val = HDMI_READ(sc, DDC_FIFO_CTRL); 325 val |= FIFO_CTRL_CLEAR; 326 HDMI_WRITE(sc, DDC_FIFO_CTRL, val); 327 328 /* Set transfer length */ 329 HDMI_WRITE(sc, DDC_BYTE_COUNTER, len); 330 331 /* Set command to "Explicit Offset Address Read" */ 332 HDMI_WRITE(sc, DDC_COMMAND, COMMAND_EOREAD); 333 334 /* Start transfer */ 335 val = HDMI_READ(sc, DDC_CTRL); 336 val |= CTRL_DDC_ACMD_START; 337 HDMI_WRITE(sc, DDC_CTRL, val); 338 339 /* Wait for command to start */ 340 retry = DDC_RETRY; 341 while (--retry > 0) { 342 val = HDMI_READ(sc, DDC_CTRL); 343 if ((val & CTRL_DDC_ACMD_START) == 0) 344 break; 345 DELAY(DDC_DELAY); 346 } 347 if (retry == 0) 348 return (ETIMEDOUT); 349 350 /* Ensure that the transfer completed */ 351 val = HDMI_READ(sc, DDC_INT_STATUS); 352 if ((val & INT_STATUS_XFER_DONE) == 0) 353 return (EIO); 354 355 return (0); 356} 357 358static int 359a10hdmi_ddc_read(struct a10hdmi_softc *sc, int block, uint8_t *edid) 360{ 361 int resid, off, len, error; 362 uint8_t *pbuf; 363 364 pbuf = edid; 365 resid = EDID_LENGTH; 366 off = (block & 1) ? EDID_LENGTH : 0; 367 368 while (resid > 0) { 369 len = min(resid, DDC_BLKLEN); 370 error = a10hdmi_ddc_xfer(sc, DDC_ADDR, block >> 1, off, len); 371 if (error != 0) 372 return (error); 373 374 bus_read_multi_1(sc->res, DDC_FIFO, pbuf, len); 375 376 pbuf += len; 377 off += len; 378 resid -= len; 379 } 380 381 return (0); 382} 383 384static int 385a10hdmi_detect_hdmi_vsdb(uint8_t *edid) 386{ 387 int off, p, btag, blen; 388 389 if (edid[EXT_TAG] != CEA_TAG_ID) 390 return (0); 391 392 off = edid[CEA_DATA_OFF]; 393 394 /* CEA data block collection starts at byte 4 */ 395 if (off <= CEA_DATA_START) 396 return (0); 397 398 /* Parse the CEA data blocks */ 399 for (p = CEA_DATA_START; p < off;) { 400 btag = BLOCK_TAG(edid[p]); 401 blen = BLOCK_LEN(edid[p]); 402 403 /* Make sure the length is sane */ 404 if (p + blen + 1 > off) 405 break; 406 407 /* Look for a VSDB with the HDMI 24-bit IEEE registration ID */ 408 if (btag == BLOCK_TAG_VSDB && blen >= HDMI_VSDB_MINLEN && 409 memcmp(&edid[p + 1], HDMI_OUI, HDMI_OUI_LEN) == 0) 410 return (1); 411 412 /* Next data block */ 413 p += (1 + blen); 414 } 415 416 return (0); 417} 418 419static void 420a10hdmi_detect_hdmi(struct a10hdmi_softc *sc, int *phdmi, int *paudio) 421{ 422 struct edid_info ei; 423 uint8_t edid[EDID_LENGTH]; 424 int block; 425 426 *phdmi = *paudio = 0; 427 428 if (edid_parse(sc->edid, &ei) != 0) 429 return; 430 431 /* Scan through extension blocks, looking for a CEA-861 block. */ 432 for (block = 1; block <= ei.edid_ext_block_count; block++) { 433 if (a10hdmi_ddc_read(sc, block, edid) != 0) 434 return; 435 436 if (a10hdmi_detect_hdmi_vsdb(edid) != 0) { 437 *phdmi = 1; 438 *paudio = ((edid[CEA_DTD] & DTD_BASIC_AUDIO) != 0); 439 return; 440 } 441 } 442} 443 444static int 445a10hdmi_get_edid(device_t dev, uint8_t **edid, uint32_t *edid_len) 446{ 447 struct a10hdmi_softc *sc; 448 int error, retry; 449 450 sc = device_get_softc(dev); 451 retry = DDC_READ_RETRY; 452 453 while (--retry > 0) { 454 /* I2C software reset */ 455 HDMI_WRITE(sc, DDC_FIFO_CTRL, 0); 456 HDMI_WRITE(sc, DDC_CTRL, CTRL_DDC_EN | CTRL_DDC_SWRST); 457 DELAY(SWRST_DELAY); 458 if (HDMI_READ(sc, DDC_CTRL) & CTRL_DDC_SWRST) { 459 device_printf(dev, "DDC software reset failed\n"); 460 return (ENXIO); 461 } 462 463 /* Configure DDC clock */ 464 HDMI_WRITE(sc, DDC_CLOCK, DDC_CLOCK_M | DDC_CLOCK_N); 465 466 /* Read EDID block */ 467 error = a10hdmi_ddc_read(sc, 0, sc->edid); 468 if (error == 0) { 469 *edid = sc->edid; 470 *edid_len = sizeof(sc->edid); 471 break; 472 } 473 } 474 475 if (error == 0) 476 a10hdmi_detect_hdmi(sc, &sc->has_hdmi, &sc->has_audio); 477 else 478 sc->has_hdmi = sc->has_audio = 0; 479 480 return (error); 481} 482 483static void 484a10hdmi_set_audiomode(device_t dev, const struct videomode *mode) 485{ 486 struct a10hdmi_softc *sc; 487 uint32_t val; 488 int retry; 489 490 sc = device_get_softc(dev); 491 492 /* Disable and reset audio module and wait for reset bit to clear */ 493 HDMI_WRITE(sc, HDMI_AUD_CTRL, AUD_CTRL_RST); 494 for (retry = HDMI_AUDIO_RESET_RETRY; retry > 0; retry--) { 495 val = HDMI_READ(sc, HDMI_AUD_CTRL); 496 if ((val & AUD_CTRL_RST) == 0) 497 break; 498 } 499 if (retry == 0) { 500 device_printf(dev, "timeout waiting for audio module\n"); 501 return; 502 } 503 504 if (!sc->has_audio) 505 return; 506 507 /* DMA and FIFO control */ 508 HDMI_WRITE(sc, HDMI_ADMA_CTRL, HDMI_ADMA_MODE_DDMA); 509 510 /* Audio format control (LPCM, S16LE, stereo) */ 511 HDMI_WRITE(sc, HDMI_AUD_FMT, AUD_FMT_CH(HDMI_AUDIO_CHANNELS)); 512 513 /* Channel mappings */ 514 HDMI_WRITE(sc, HDMI_PCM_CTRL, HDMI_AUDIO_CHANNELMAP); 515 516 /* Clocks */ 517 HDMI_WRITE(sc, HDMI_AUD_CTS, 518 HDMI_AUDIO_CTS(mode->dot_clock, HDMI_AUDIO_N)); 519 HDMI_WRITE(sc, HDMI_AUD_N, HDMI_AUDIO_N); 520 521 /* Set sampling frequency to 48 kHz, word length to 16-bit */ 522 HDMI_WRITE(sc, HDMI_AUD_CH_STATUS0, CH_STATUS0_FS_FREQ_48); 523 HDMI_WRITE(sc, HDMI_AUD_CH_STATUS1, CH_STATUS1_WORD_LEN_16); 524 525 /* Enable */ 526 HDMI_WRITE(sc, HDMI_AUD_CTRL, AUD_CTRL_EN); 527} 528 529static int 530a10hdmi_set_videomode(device_t dev, const struct videomode *mode) 531{ 532 struct a10hdmi_softc *sc; 533 int error, clk_div, clk_dbl; 534 int dblscan, hfp, hspw, hbp, vfp, vspw, vbp; 535 uint32_t val; 536 537 sc = device_get_softc(dev); 538 dblscan = !!(mode->flags & VID_DBLSCAN); 539 hfp = mode->hsync_start - mode->hdisplay; 540 hspw = mode->hsync_end - mode->hsync_start; 541 hbp = mode->htotal - mode->hsync_start; 542 vfp = mode->vsync_start - mode->vdisplay; 543 vspw = mode->vsync_end - mode->vsync_start; 544 vbp = mode->vtotal - mode->vsync_start; 545 546 error = a10_clk_tcon_get_config(&clk_div, &clk_dbl); 547 if (error != 0) 548 return (error); 549 550 /* Clear interrupt status */ 551 HDMI_WRITE(sc, HDMI_INT_STATUS, HDMI_READ(sc, HDMI_INT_STATUS)); 552 553 /* Clock setup */ 554 val = HDMI_READ(sc, HDMI_PADCTRL1); 555 val &= ~PADCTRL1_REG_CKSS; 556 val |= (clk_dbl ? PADCTRL1_REG_CKSS_2X : PADCTRL1_REG_CKSS_1X); 557 HDMI_WRITE(sc, HDMI_PADCTRL1, val); 558 HDMI_WRITE(sc, HDMI_PLLCTRL0, PLLCTRL0_PLL_EN | PLLCTRL0_BWS | 559 PLLCTRL0_HV_IS_33 | PLLCTRL0_LDO1_EN | PLLCTRL0_LDO2_EN | 560 PLLCTRL0_SDIV2 | PLLCTRL0_VCO_GAIN | PLLCTRL0_S | 561 PLLCTRL0_CP_S | PLLCTRL0_CS | PLLCTRL0_PREDIV(clk_div) | 562 PLLCTRL0_VCO_S); 563 564 /* Setup display settings */ 565 if (bootverbose) 566 device_printf(dev, "HDMI: %s, Audio: %s\n", 567 sc->has_hdmi ? "yes" : "no", sc->has_audio ? "yes" : "no"); 568 val = 0; 569 if (sc->has_hdmi) 570 val |= VID_CTRL_HDMI_MODE; 571 if (mode->flags & VID_INTERLACE) 572 val |= VID_CTRL_INTERLACE; 573 if (mode->flags & VID_DBLSCAN) 574 val |= VID_CTRL_REPEATER_2X; 575 HDMI_WRITE(sc, HDMI_VID_CTRL, val); 576 577 /* Setup display timings */ 578 HDMI_WRITE(sc, HDMI_VID_TIMING0, 579 VID_ACT_V(mode->vdisplay) | VID_ACT_H(mode->hdisplay << dblscan)); 580 HDMI_WRITE(sc, HDMI_VID_TIMING1, 581 VID_VBP(vbp) | VID_HBP(hbp << dblscan)); 582 HDMI_WRITE(sc, HDMI_VID_TIMING2, 583 VID_VFP(vfp) | VID_HFP(hfp << dblscan)); 584 HDMI_WRITE(sc, HDMI_VID_TIMING3, 585 VID_VSPW(vspw) | VID_HSPW(hspw << dblscan)); 586 val = TX_CLOCK_NORMAL; 587 if (mode->flags & VID_PVSYNC) 588 val |= VID_VSYNC_ACTSEL; 589 if (mode->flags & VID_PHSYNC) 590 val |= VID_HSYNC_ACTSEL; 591 HDMI_WRITE(sc, HDMI_VID_TIMING4, val); 592 593 /* This is an ordered list of infoframe packets that the HDMI 594 * transmitter will send. Transmit packets in the following order: 595 * 1. General control packet 596 * 2. AVI infoframe 597 * 3. Audio infoframe 598 * There are 2 registers with 4 slots each. The list is terminated 599 * with the special PKT_END marker. 600 */ 601 HDMI_WRITE(sc, HDMI_PKTCTRL0, 602 PKTCTRL_PACKET(0, PKT_GC) | PKTCTRL_PACKET(1, PKT_AVI) | 603 PKTCTRL_PACKET(2, PKT_AI) | PKTCTRL_PACKET(3, PKT_END)); 604 HDMI_WRITE(sc, HDMI_PKTCTRL1, 0); 605 606 /* Setup audio */ 607 a10hdmi_set_audiomode(dev, mode); 608 609 return (0); 610} 611 612static int 613a10hdmi_enable(device_t dev, int onoff) 614{ 615 struct a10hdmi_softc *sc; 616 uint32_t val; 617 618 sc = device_get_softc(dev); 619 620 /* Enable or disable video output */ 621 val = HDMI_READ(sc, HDMI_VID_CTRL); 622 if (onoff) 623 val |= VID_CTRL_VIDEO_EN; 624 else 625 val &= ~VID_CTRL_VIDEO_EN; 626 HDMI_WRITE(sc, HDMI_VID_CTRL, val); 627 628 return (0); 629} 630 631static device_method_t a10hdmi_methods[] = { 632 /* Device interface */ 633 DEVMETHOD(device_probe, a10hdmi_probe), 634 DEVMETHOD(device_attach, a10hdmi_attach), 635 636 /* HDMI interface */ 637 DEVMETHOD(hdmi_get_edid, a10hdmi_get_edid), 638 DEVMETHOD(hdmi_set_videomode, a10hdmi_set_videomode), 639 DEVMETHOD(hdmi_enable, a10hdmi_enable), 640 641 DEVMETHOD_END 642}; 643 644static driver_t a10hdmi_driver = { 645 "a10hdmi", 646 a10hdmi_methods, 647 sizeof(struct a10hdmi_softc), 648}; 649 650static devclass_t a10hdmi_devclass; 651 652DRIVER_MODULE(a10hdmi, simplebus, a10hdmi_driver, a10hdmi_devclass, 0, 0); 653MODULE_VERSION(a10hdmi, 1); 654