| .. | .. |
|---|
| 49 | 49 | #define DDC_SEGMENT_ADDR 0x30 |
|---|
| 50 | 50 | |
|---|
| 51 | 51 | #define HDMI_EDID_LEN 512 |
|---|
| 52 | +#define HDMI_EDID_BLOCK_LEN 128 |
|---|
| 52 | 53 | |
|---|
| 53 | 54 | /* DW-HDMI Controller >= 0x200a are at least compliant with SCDC version 1 */ |
|---|
| 54 | 55 | #define SCDC_MIN_SOURCE_VERSION 0x1 |
|---|
| .. | .. |
|---|
| 320 | 321 | struct drm_display_mode previous_mode; |
|---|
| 321 | 322 | |
|---|
| 322 | 323 | struct i2c_adapter *ddc; |
|---|
| 324 | + struct cec_adapter *cec_adap; |
|---|
| 323 | 325 | void __iomem *regs; |
|---|
| 324 | 326 | bool sink_is_hdmi; |
|---|
| 325 | 327 | bool sink_has_audio; |
|---|
| .. | .. |
|---|
| 358 | 360 | struct cec_notifier *cec_notifier; |
|---|
| 359 | 361 | |
|---|
| 360 | 362 | bool initialized; /* hdmi is enabled before bind */ |
|---|
| 363 | + bool logo_plug_out; /* hdmi is plug out when kernel logo */ |
|---|
| 361 | 364 | hdmi_codec_plugged_cb plugged_cb; |
|---|
| 362 | 365 | struct device *codec_dev; |
|---|
| 363 | 366 | enum drm_connector_status last_connector_result; |
|---|
| 364 | 367 | bool rgb_quant_range_selectable; |
|---|
| 368 | + bool update; |
|---|
| 369 | + bool hdr2sdr; /* from hdr to sdr */ |
|---|
| 365 | 370 | }; |
|---|
| 366 | 371 | |
|---|
| 367 | 372 | #define HDMI_IH_PHY_STAT0_RX_SENSE \ |
|---|
| .. | .. |
|---|
| 456 | 461 | change = drm_helper_hpd_irq_event(hdmi->bridge.dev); |
|---|
| 457 | 462 | |
|---|
| 458 | 463 | #ifdef CONFIG_CEC_NOTIFIER |
|---|
| 459 | | - if (change) |
|---|
| 464 | + if (change) { |
|---|
| 460 | 465 | cec_notifier_repo_cec_hpd(hdmi->cec_notifier, |
|---|
| 461 | 466 | hdmi->hpd_state, |
|---|
| 462 | 467 | ktime_get()); |
|---|
| 468 | + } |
|---|
| 463 | 469 | #endif |
|---|
| 464 | 470 | } |
|---|
| 465 | 471 | } |
|---|
| .. | .. |
|---|
| 568 | 574 | unsigned char *buf, unsigned int length) |
|---|
| 569 | 575 | { |
|---|
| 570 | 576 | struct dw_hdmi_i2c *i2c = hdmi->i2c; |
|---|
| 571 | | - int stat; |
|---|
| 577 | + int stat, retry, i; |
|---|
| 578 | + bool read_edid = false; |
|---|
| 572 | 579 | |
|---|
| 573 | 580 | if (!i2c->is_regaddr) { |
|---|
| 574 | 581 | dev_dbg(hdmi->dev, "set read register address to 0\n"); |
|---|
| .. | .. |
|---|
| 576 | 583 | i2c->is_regaddr = true; |
|---|
| 577 | 584 | } |
|---|
| 578 | 585 | |
|---|
| 579 | | - while (length--) { |
|---|
| 580 | | - reinit_completion(&i2c->cmp); |
|---|
| 586 | + /* edid reads are in 128 bytes. scdc reads are in 1 byte */ |
|---|
| 587 | + if (length == HDMI_EDID_BLOCK_LEN) |
|---|
| 588 | + read_edid = true; |
|---|
| 581 | 589 | |
|---|
| 582 | | - hdmi_writeb(hdmi, i2c->slave_reg++, HDMI_I2CM_ADDRESS); |
|---|
| 583 | | - if (i2c->is_segment) |
|---|
| 584 | | - hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ_EXT, |
|---|
| 585 | | - HDMI_I2CM_OPERATION); |
|---|
| 586 | | - else |
|---|
| 587 | | - hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ, |
|---|
| 588 | | - HDMI_I2CM_OPERATION); |
|---|
| 590 | + while (length > 0) { |
|---|
| 591 | + retry = 100; |
|---|
| 592 | + hdmi_writeb(hdmi, i2c->slave_reg, HDMI_I2CM_ADDRESS); |
|---|
| 589 | 593 | |
|---|
| 590 | | - stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); |
|---|
| 591 | | - if (!stat) |
|---|
| 592 | | - return -EAGAIN; |
|---|
| 594 | + if (read_edid) { |
|---|
| 595 | + i2c->slave_reg += 8; |
|---|
| 596 | + length -= 8; |
|---|
| 597 | + } else { |
|---|
| 598 | + i2c->slave_reg++; |
|---|
| 599 | + length--; |
|---|
| 600 | + } |
|---|
| 593 | 601 | |
|---|
| 594 | | - /* Check for error condition on the bus */ |
|---|
| 595 | | - if (i2c->stat & HDMI_IH_I2CM_STAT0_ERROR) |
|---|
| 602 | + while (retry > 0) { |
|---|
| 603 | + if (!(hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD)) { |
|---|
| 604 | + void *data = hdmi->plat_data->phy_data; |
|---|
| 605 | + |
|---|
| 606 | + dev_dbg(hdmi->dev, "hdmi disconnect, stop ddc read\n"); |
|---|
| 607 | + if (hdmi->plat_data->set_ddc_io) |
|---|
| 608 | + hdmi->plat_data->set_ddc_io(data, false); |
|---|
| 609 | + return -EPERM; |
|---|
| 610 | + } |
|---|
| 611 | + reinit_completion(&i2c->cmp); |
|---|
| 612 | + if (i2c->is_segment) { |
|---|
| 613 | + if (read_edid) |
|---|
| 614 | + hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ8_EXT, |
|---|
| 615 | + HDMI_I2CM_OPERATION); |
|---|
| 616 | + else |
|---|
| 617 | + hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ_EXT, |
|---|
| 618 | + HDMI_I2CM_OPERATION); |
|---|
| 619 | + } else { |
|---|
| 620 | + if (read_edid) |
|---|
| 621 | + hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ8, |
|---|
| 622 | + HDMI_I2CM_OPERATION); |
|---|
| 623 | + else |
|---|
| 624 | + hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ, |
|---|
| 625 | + HDMI_I2CM_OPERATION); |
|---|
| 626 | + } |
|---|
| 627 | + stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); |
|---|
| 628 | + if (!stat) { |
|---|
| 629 | + dev_dbg(hdmi->dev, "ddc read time out\n"); |
|---|
| 630 | + hdmi_writeb(hdmi, 0, HDMI_I2CM_SOFTRSTZ); |
|---|
| 631 | + hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_BUS_CLEAR, |
|---|
| 632 | + HDMI_I2CM_OPERATION); |
|---|
| 633 | + retry -= 10; |
|---|
| 634 | + continue; |
|---|
| 635 | + } |
|---|
| 636 | + /* Check for error condition on the bus */ |
|---|
| 637 | + if (i2c->stat & HDMI_IH_I2CM_STAT0_ERROR) { |
|---|
| 638 | + dev_dbg(hdmi->dev, "ddc read err\n"); |
|---|
| 639 | + hdmi_writeb(hdmi, 0, HDMI_I2CM_SOFTRSTZ); |
|---|
| 640 | + hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_BUS_CLEAR, |
|---|
| 641 | + HDMI_I2CM_OPERATION); |
|---|
| 642 | + retry--; |
|---|
| 643 | + usleep_range(10000, 11000); |
|---|
| 644 | + continue; |
|---|
| 645 | + } |
|---|
| 646 | + /* read success */ |
|---|
| 647 | + break; |
|---|
| 648 | + } |
|---|
| 649 | + if (retry <= 0) { |
|---|
| 650 | + dev_err(hdmi->dev, "ddc read failed\n"); |
|---|
| 596 | 651 | return -EIO; |
|---|
| 652 | + } |
|---|
| 597 | 653 | |
|---|
| 598 | | - *buf++ = hdmi_readb(hdmi, HDMI_I2CM_DATAI); |
|---|
| 654 | + if (read_edid) |
|---|
| 655 | + for (i = 0; i < 8; i++) |
|---|
| 656 | + *buf++ = hdmi_readb(hdmi, HDMI_I2CM_READ_BUFF0 + i); |
|---|
| 657 | + else |
|---|
| 658 | + *buf++ = hdmi_readb(hdmi, HDMI_I2CM_DATAI); |
|---|
| 599 | 659 | } |
|---|
| 660 | + |
|---|
| 600 | 661 | i2c->is_segment = false; |
|---|
| 601 | 662 | |
|---|
| 602 | 663 | return 0; |
|---|
| .. | .. |
|---|
| 606 | 667 | unsigned char *buf, unsigned int length) |
|---|
| 607 | 668 | { |
|---|
| 608 | 669 | struct dw_hdmi_i2c *i2c = hdmi->i2c; |
|---|
| 609 | | - int stat; |
|---|
| 670 | + int stat, retry; |
|---|
| 610 | 671 | |
|---|
| 611 | 672 | if (!i2c->is_regaddr) { |
|---|
| 612 | 673 | /* Use the first write byte as register address */ |
|---|
| .. | .. |
|---|
| 617 | 678 | } |
|---|
| 618 | 679 | |
|---|
| 619 | 680 | while (length--) { |
|---|
| 620 | | - reinit_completion(&i2c->cmp); |
|---|
| 681 | + retry = 100; |
|---|
| 621 | 682 | |
|---|
| 622 | 683 | hdmi_writeb(hdmi, *buf++, HDMI_I2CM_DATAO); |
|---|
| 623 | 684 | hdmi_writeb(hdmi, i2c->slave_reg++, HDMI_I2CM_ADDRESS); |
|---|
| 624 | | - hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_WRITE, |
|---|
| 625 | | - HDMI_I2CM_OPERATION); |
|---|
| 626 | 685 | |
|---|
| 627 | | - stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); |
|---|
| 628 | | - if (!stat) |
|---|
| 629 | | - return -EAGAIN; |
|---|
| 686 | + while (retry > 0) { |
|---|
| 687 | + if (!(hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD)) { |
|---|
| 688 | + void *data = hdmi->plat_data->phy_data; |
|---|
| 630 | 689 | |
|---|
| 631 | | - /* Check for error condition on the bus */ |
|---|
| 632 | | - if (i2c->stat & HDMI_IH_I2CM_STAT0_ERROR) |
|---|
| 690 | + dev_dbg(hdmi->dev, "hdmi disconnect, stop ddc write\n"); |
|---|
| 691 | + if (hdmi->plat_data->set_ddc_io) |
|---|
| 692 | + hdmi->plat_data->set_ddc_io(data, false); |
|---|
| 693 | + return -EPERM; |
|---|
| 694 | + } |
|---|
| 695 | + reinit_completion(&i2c->cmp); |
|---|
| 696 | + hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_WRITE, |
|---|
| 697 | + HDMI_I2CM_OPERATION); |
|---|
| 698 | + |
|---|
| 699 | + stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); |
|---|
| 700 | + if (!stat) { |
|---|
| 701 | + dev_dbg(hdmi->dev, "ddc write time out\n"); |
|---|
| 702 | + hdmi_writeb(hdmi, 0, HDMI_I2CM_SOFTRSTZ); |
|---|
| 703 | + hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_BUS_CLEAR, |
|---|
| 704 | + HDMI_I2CM_OPERATION); |
|---|
| 705 | + retry -= 10; |
|---|
| 706 | + continue; |
|---|
| 707 | + } |
|---|
| 708 | + |
|---|
| 709 | + /* Check for error condition on the bus */ |
|---|
| 710 | + if (i2c->stat & HDMI_IH_I2CM_STAT0_ERROR) { |
|---|
| 711 | + dev_dbg(hdmi->dev, "ddc write err\n"); |
|---|
| 712 | + hdmi_writeb(hdmi, 0, HDMI_I2CM_SOFTRSTZ); |
|---|
| 713 | + hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_BUS_CLEAR, |
|---|
| 714 | + HDMI_I2CM_OPERATION); |
|---|
| 715 | + retry--; |
|---|
| 716 | + usleep_range(10000, 11000); |
|---|
| 717 | + continue; |
|---|
| 718 | + } |
|---|
| 719 | + |
|---|
| 720 | + /* write success */ |
|---|
| 721 | + break; |
|---|
| 722 | + } |
|---|
| 723 | + |
|---|
| 724 | + if (retry <= 0) { |
|---|
| 725 | + dev_err(hdmi->dev, "ddc write failed\n"); |
|---|
| 633 | 726 | return -EIO; |
|---|
| 727 | + } |
|---|
| 634 | 728 | } |
|---|
| 635 | 729 | |
|---|
| 636 | 730 | return 0; |
|---|
| .. | .. |
|---|
| 642 | 736 | struct dw_hdmi *hdmi = i2c_get_adapdata(adap); |
|---|
| 643 | 737 | struct dw_hdmi_i2c *i2c = hdmi->i2c; |
|---|
| 644 | 738 | u8 addr = msgs[0].addr; |
|---|
| 739 | + void *data = hdmi->plat_data->phy_data; |
|---|
| 645 | 740 | int i, ret = 0; |
|---|
| 646 | 741 | |
|---|
| 647 | 742 | if (addr == DDC_CI_ADDR) |
|---|
| .. | .. |
|---|
| 665 | 760 | } |
|---|
| 666 | 761 | |
|---|
| 667 | 762 | mutex_lock(&i2c->lock); |
|---|
| 763 | + |
|---|
| 764 | + if (hdmi->plat_data->set_ddc_io) |
|---|
| 765 | + hdmi->plat_data->set_ddc_io(data, true); |
|---|
| 766 | + |
|---|
| 767 | + hdmi_writeb(hdmi, 0, HDMI_I2CM_SOFTRSTZ); |
|---|
| 768 | + udelay(100); |
|---|
| 668 | 769 | |
|---|
| 669 | 770 | /* Unmute DONE and ERROR interrupts */ |
|---|
| 670 | 771 | hdmi_writeb(hdmi, 0x00, HDMI_IH_MUTE_I2CM_STAT0); |
|---|
| .. | .. |
|---|
| 1378 | 1479 | HDMI_VP_CONF_PR_EN_MASK | |
|---|
| 1379 | 1480 | HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF); |
|---|
| 1380 | 1481 | |
|---|
| 1381 | | - if ((color_depth == 5 && hdmi->previous_mode.htotal % 4) || |
|---|
| 1382 | | - (color_depth == 6 && hdmi->previous_mode.htotal % 2)) |
|---|
| 1383 | | - hdmi_modb(hdmi, 0, HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, |
|---|
| 1384 | | - HDMI_VP_STUFF); |
|---|
| 1385 | | - else |
|---|
| 1386 | | - hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET, |
|---|
| 1387 | | - HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF); |
|---|
| 1388 | | - |
|---|
| 1482 | + hdmi_modb(hdmi, 0, HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF); |
|---|
| 1389 | 1483 | hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP); |
|---|
| 1390 | 1484 | |
|---|
| 1391 | 1485 | if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) { |
|---|
| .. | .. |
|---|
| 1943 | 2037 | HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; |
|---|
| 1944 | 2038 | break; |
|---|
| 1945 | 2039 | } |
|---|
| 2040 | + frame.ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_LIMITED; |
|---|
| 1946 | 2041 | } else { |
|---|
| 1947 | | - frame.colorimetry = HDMI_COLORIMETRY_NONE; |
|---|
| 1948 | | - frame.extended_colorimetry = |
|---|
| 1949 | | - HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; |
|---|
| 2042 | + if (hdmi->hdmi_data.enc_out_encoding == V4L2_YCBCR_ENC_BT2020) { |
|---|
| 2043 | + frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; |
|---|
| 2044 | + frame.extended_colorimetry = |
|---|
| 2045 | + HDMI_EXTENDED_COLORIMETRY_BT2020; |
|---|
| 2046 | + } else { |
|---|
| 2047 | + frame.colorimetry = HDMI_COLORIMETRY_NONE; |
|---|
| 2048 | + frame.extended_colorimetry = |
|---|
| 2049 | + HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; |
|---|
| 2050 | + } |
|---|
| 2051 | + |
|---|
| 2052 | + if (is_hdmi2 && frame.quantization_range == HDMI_QUANTIZATION_RANGE_FULL) |
|---|
| 2053 | + frame.ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_FULL; |
|---|
| 2054 | + else |
|---|
| 2055 | + frame.ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_LIMITED; |
|---|
| 1950 | 2056 | } |
|---|
| 1951 | 2057 | |
|---|
| 1952 | 2058 | frame.scan_mode = HDMI_SCAN_MODE_NONE; |
|---|
| .. | .. |
|---|
| 1986 | 2092 | hdmi_writeb(hdmi, val, HDMI_FC_AVICONF2); |
|---|
| 1987 | 2093 | |
|---|
| 1988 | 2094 | /* AVI data byte 4 differences: none */ |
|---|
| 1989 | | - val = frame.video_code & 0x7f; |
|---|
| 2095 | + if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format) || |
|---|
| 2096 | + hdmi->connector.display_info.hdmi.scdc.supported) |
|---|
| 2097 | + val = hdmi->vic; |
|---|
| 2098 | + else |
|---|
| 2099 | + val = frame.video_code & 0x7f; |
|---|
| 1990 | 2100 | hdmi_writeb(hdmi, val, HDMI_FC_AVIVID); |
|---|
| 1991 | 2101 | |
|---|
| 1992 | 2102 | /* AVI Data Byte 5- set up input and output pixel repetition */ |
|---|
| .. | .. |
|---|
| 2023 | 2133 | struct hdmi_vendor_infoframe frame; |
|---|
| 2024 | 2134 | u8 buffer[10]; |
|---|
| 2025 | 2135 | ssize_t err; |
|---|
| 2136 | + |
|---|
| 2137 | + /* if sink support hdmi2.0, don't send vsi */ |
|---|
| 2138 | + if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format) || |
|---|
| 2139 | + hdmi->connector.display_info.hdmi.scdc.supported) { |
|---|
| 2140 | + hdmi_mask_writeb(hdmi, 0, HDMI_FC_DATAUTO0, HDMI_FC_DATAUTO0_VSD_OFFSET, |
|---|
| 2141 | + HDMI_FC_DATAUTO0_VSD_MASK); |
|---|
| 2142 | + return; |
|---|
| 2143 | + } |
|---|
| 2026 | 2144 | |
|---|
| 2027 | 2145 | err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, |
|---|
| 2028 | 2146 | &hdmi->connector, |
|---|
| .. | .. |
|---|
| 2188 | 2306 | hdmi_writeb(hdmi, HDR_LSB(frame.max_fall), HDMI_FC_DRM_PB24); |
|---|
| 2189 | 2307 | hdmi_writeb(hdmi, HDR_MSB(frame.max_fall), HDMI_FC_DRM_PB25); |
|---|
| 2190 | 2308 | hdmi_writeb(hdmi, 1, HDMI_FC_DRM_UP); |
|---|
| 2309 | + /* |
|---|
| 2310 | + * avi and hdr infoframe cannot be sent at the same time |
|---|
| 2311 | + * for compatibility with Huawei TV |
|---|
| 2312 | + */ |
|---|
| 2313 | + msleep(300); |
|---|
| 2191 | 2314 | hdmi_modb(hdmi, HDMI_FC_PACKET_DRM_TX_EN, |
|---|
| 2192 | 2315 | HDMI_FC_PACKET_DRM_TX_EN_MASK, HDMI_FC_PACKET_TX_EN); |
|---|
| 2193 | 2316 | |
|---|
| .. | .. |
|---|
| 2215 | 2338 | vmode->mtmdsclock = hdmi_get_tmdsclock(hdmi, vmode->mpixelclock); |
|---|
| 2216 | 2339 | if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) |
|---|
| 2217 | 2340 | vmode->mtmdsclock /= 2; |
|---|
| 2341 | + |
|---|
| 2342 | + if (hdmi->update) |
|---|
| 2343 | + return; |
|---|
| 2218 | 2344 | |
|---|
| 2219 | 2345 | /* Set up HDMI_FC_INVIDCONF |
|---|
| 2220 | 2346 | * Some display equipments require that the interval |
|---|
| .. | .. |
|---|
| 2373 | 2499 | hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM); |
|---|
| 2374 | 2500 | |
|---|
| 2375 | 2501 | /* Enable pixel clock and tmds data path */ |
|---|
| 2376 | | - hdmi->mc_clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE | |
|---|
| 2377 | | - HDMI_MC_CLKDIS_CSCCLK_DISABLE | |
|---|
| 2378 | | - HDMI_MC_CLKDIS_AUDCLK_DISABLE | |
|---|
| 2379 | | - HDMI_MC_CLKDIS_PREPCLK_DISABLE | |
|---|
| 2380 | | - HDMI_MC_CLKDIS_TMDSCLK_DISABLE; |
|---|
| 2502 | + |
|---|
| 2503 | + if (!hdmi->update) |
|---|
| 2504 | + hdmi->mc_clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE | |
|---|
| 2505 | + HDMI_MC_CLKDIS_CSCCLK_DISABLE | |
|---|
| 2506 | + HDMI_MC_CLKDIS_AUDCLK_DISABLE | |
|---|
| 2507 | + HDMI_MC_CLKDIS_PREPCLK_DISABLE | |
|---|
| 2508 | + HDMI_MC_CLKDIS_TMDSCLK_DISABLE; |
|---|
| 2381 | 2509 | hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; |
|---|
| 2382 | 2510 | hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); |
|---|
| 2383 | 2511 | |
|---|
| .. | .. |
|---|
| 2455 | 2583 | HDMI_IH_MUTE_FC_STAT2); |
|---|
| 2456 | 2584 | } |
|---|
| 2457 | 2585 | |
|---|
| 2586 | +static void dw_hdmi_force_output_pattern(struct dw_hdmi *hdmi, struct drm_display_mode *mode) |
|---|
| 2587 | +{ |
|---|
| 2588 | + /* force output black */ |
|---|
| 2589 | + if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) { |
|---|
| 2590 | + enum hdmi_quantization_range rgb_quant_range = drm_default_rgb_quant_range(mode); |
|---|
| 2591 | + |
|---|
| 2592 | + if (hdmi->hdmi_data.quant_range == HDMI_QUANTIZATION_RANGE_FULL) { |
|---|
| 2593 | + hdmi_writeb(hdmi, 0x00, HDMI_FC_DBGTMDS2); /*R*/ |
|---|
| 2594 | + hdmi_writeb(hdmi, 0x00, HDMI_FC_DBGTMDS1); /*G*/ |
|---|
| 2595 | + hdmi_writeb(hdmi, 0x00, HDMI_FC_DBGTMDS0); /*B*/ |
|---|
| 2596 | + } else if (hdmi->hdmi_data.quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) { |
|---|
| 2597 | + hdmi_writeb(hdmi, 0x10, HDMI_FC_DBGTMDS2); /*R*/ |
|---|
| 2598 | + hdmi_writeb(hdmi, 0x10, HDMI_FC_DBGTMDS1); /*G*/ |
|---|
| 2599 | + hdmi_writeb(hdmi, 0x10, HDMI_FC_DBGTMDS0); /*B*/ |
|---|
| 2600 | + } else if (hdmi->hdmi_data.quant_range == HDMI_QUANTIZATION_RANGE_DEFAULT) { |
|---|
| 2601 | + if (rgb_quant_range == HDMI_QUANTIZATION_RANGE_FULL) { |
|---|
| 2602 | + hdmi_writeb(hdmi, 0x00, HDMI_FC_DBGTMDS2); /*R*/ |
|---|
| 2603 | + hdmi_writeb(hdmi, 0x00, HDMI_FC_DBGTMDS1); /*G*/ |
|---|
| 2604 | + hdmi_writeb(hdmi, 0x00, HDMI_FC_DBGTMDS0); /*B*/ |
|---|
| 2605 | + } else if (rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) { |
|---|
| 2606 | + hdmi_writeb(hdmi, 0x10, HDMI_FC_DBGTMDS2); /*R*/ |
|---|
| 2607 | + hdmi_writeb(hdmi, 0x10, HDMI_FC_DBGTMDS1); /*G*/ |
|---|
| 2608 | + hdmi_writeb(hdmi, 0x10, HDMI_FC_DBGTMDS0); /*B*/ |
|---|
| 2609 | + } |
|---|
| 2610 | + } |
|---|
| 2611 | + } else { |
|---|
| 2612 | + hdmi_writeb(hdmi, 0x80, HDMI_FC_DBGTMDS2); /*Cr*/ |
|---|
| 2613 | + hdmi_writeb(hdmi, 0x10, HDMI_FC_DBGTMDS1); /*Y*/ |
|---|
| 2614 | + hdmi_writeb(hdmi, 0x80, HDMI_FC_DBGTMDS0); /*Cb*/ |
|---|
| 2615 | + } |
|---|
| 2616 | +} |
|---|
| 2617 | + |
|---|
| 2458 | 2618 | static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) |
|---|
| 2459 | 2619 | { |
|---|
| 2460 | 2620 | int ret; |
|---|
| 2461 | 2621 | void *data = hdmi->plat_data->phy_data; |
|---|
| 2462 | | - bool need_delay = false; |
|---|
| 2463 | 2622 | |
|---|
| 2464 | 2623 | hdmi_disable_overflow_interrupts(hdmi); |
|---|
| 2465 | 2624 | |
|---|
| .. | .. |
|---|
| 2508 | 2667 | hdmi->hdmi_data.enc_out_bus_format = |
|---|
| 2509 | 2668 | MEDIA_BUS_FMT_RGB888_1X24; |
|---|
| 2510 | 2669 | |
|---|
| 2670 | + if (hdmi->plat_data->set_prev_bus_format) |
|---|
| 2671 | + hdmi->plat_data->set_prev_bus_format(data, hdmi->hdmi_data.enc_out_bus_format); |
|---|
| 2672 | + |
|---|
| 2511 | 2673 | /* TOFIX: Get input encoding from plat data or fallback to none */ |
|---|
| 2512 | 2674 | if (hdmi->plat_data->get_enc_in_encoding) |
|---|
| 2513 | 2675 | hdmi->hdmi_data.enc_in_encoding = |
|---|
| .. | .. |
|---|
| 2537 | 2699 | (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 1 : 0; |
|---|
| 2538 | 2700 | hdmi->hdmi_data.video_mode.mdataenablepolarity = true; |
|---|
| 2539 | 2701 | |
|---|
| 2702 | + dw_hdmi_force_output_pattern(hdmi, mode); |
|---|
| 2703 | + |
|---|
| 2540 | 2704 | /* HDMI Initialization Step B.1 */ |
|---|
| 2541 | 2705 | hdmi_av_composer(hdmi, mode); |
|---|
| 2542 | 2706 | |
|---|
| 2543 | | - /* HDMI Initializateion Step B.2 */ |
|---|
| 2544 | | - if (!hdmi->phy.enabled || |
|---|
| 2545 | | - hdmi->hdmi_data.video_mode.previous_pixelclock != |
|---|
| 2546 | | - hdmi->hdmi_data.video_mode.mpixelclock || |
|---|
| 2547 | | - hdmi->hdmi_data.video_mode.previous_tmdsclock != |
|---|
| 2548 | | - hdmi->hdmi_data.video_mode.mtmdsclock) { |
|---|
| 2549 | | - ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, |
|---|
| 2550 | | - &hdmi->previous_mode); |
|---|
| 2551 | | - if (ret) |
|---|
| 2552 | | - return ret; |
|---|
| 2553 | | - hdmi->phy.enabled = true; |
|---|
| 2554 | | - } else { |
|---|
| 2555 | | - need_delay = true; |
|---|
| 2556 | | - } |
|---|
| 2557 | 2707 | /* HDMI Initialization Step B.3 */ |
|---|
| 2558 | 2708 | dw_hdmi_enable_video_path(hdmi); |
|---|
| 2559 | 2709 | |
|---|
| .. | .. |
|---|
| 2582 | 2732 | hdmi_video_sample(hdmi); |
|---|
| 2583 | 2733 | hdmi_tx_hdcp_config(hdmi, mode); |
|---|
| 2584 | 2734 | |
|---|
| 2735 | + /* HDMI Enable phy output */ |
|---|
| 2736 | + if (!hdmi->phy.enabled || |
|---|
| 2737 | + hdmi->hdmi_data.video_mode.previous_pixelclock != |
|---|
| 2738 | + hdmi->hdmi_data.video_mode.mpixelclock || |
|---|
| 2739 | + hdmi->hdmi_data.video_mode.previous_tmdsclock != |
|---|
| 2740 | + hdmi->hdmi_data.video_mode.mtmdsclock) { |
|---|
| 2741 | + ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, |
|---|
| 2742 | + &hdmi->previous_mode); |
|---|
| 2743 | + if (ret) |
|---|
| 2744 | + return ret; |
|---|
| 2745 | + hdmi->phy.enabled = true; |
|---|
| 2746 | + } |
|---|
| 2747 | + |
|---|
| 2585 | 2748 | dw_hdmi_clear_overflow(hdmi); |
|---|
| 2586 | 2749 | |
|---|
| 2587 | | - /* XXX: Add delay to make csc work before unmute video. */ |
|---|
| 2588 | | - if (need_delay) |
|---|
| 2750 | + /* |
|---|
| 2751 | + * konka tv should switch pattern after set to yuv420 10bit or |
|---|
| 2752 | + * the TV might not recognize the signal. |
|---|
| 2753 | + */ |
|---|
| 2754 | + if (!hdmi->update) { |
|---|
| 2755 | + hdmi_writeb(hdmi, 1, HDMI_FC_DBGFORCE); |
|---|
| 2589 | 2756 | msleep(50); |
|---|
| 2757 | + hdmi_writeb(hdmi, 0, HDMI_FC_DBGFORCE); |
|---|
| 2758 | + } |
|---|
| 2759 | + |
|---|
| 2590 | 2760 | return 0; |
|---|
| 2591 | 2761 | } |
|---|
| 2592 | 2762 | |
|---|
| .. | .. |
|---|
| 2686 | 2856 | if (hdmi->initialized) { |
|---|
| 2687 | 2857 | hdmi->initialized = false; |
|---|
| 2688 | 2858 | hdmi->disabled = true; |
|---|
| 2859 | + hdmi->logo_plug_out = true; |
|---|
| 2689 | 2860 | } |
|---|
| 2690 | 2861 | if (hdmi->bridge_is_on) |
|---|
| 2691 | 2862 | dw_hdmi_poweroff(hdmi); |
|---|
| .. | .. |
|---|
| 2793 | 2964 | |
|---|
| 2794 | 2965 | edid = drm_get_edid(connector, hdmi->ddc); |
|---|
| 2795 | 2966 | if (edid) { |
|---|
| 2967 | + int vic = 0; |
|---|
| 2968 | + |
|---|
| 2796 | 2969 | dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", |
|---|
| 2797 | 2970 | edid->width_cm, edid->height_cm); |
|---|
| 2798 | 2971 | |
|---|
| .. | .. |
|---|
| 2802 | 2975 | drm_connector_update_edid_property(connector, edid); |
|---|
| 2803 | 2976 | cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); |
|---|
| 2804 | 2977 | ret = drm_add_edid_modes(connector, edid); |
|---|
| 2805 | | - dw_hdmi_update_hdr_property(connector); |
|---|
| 2978 | + |
|---|
| 2979 | + list_for_each_entry(mode, &connector->probed_modes, head) { |
|---|
| 2980 | + vic = drm_match_cea_mode(mode); |
|---|
| 2981 | + |
|---|
| 2982 | + if (mode->picture_aspect_ratio == HDMI_PICTURE_ASPECT_NONE) { |
|---|
| 2983 | + if (vic >= 93 && vic <= 95) |
|---|
| 2984 | + mode->picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9; |
|---|
| 2985 | + else if (vic == 98) |
|---|
| 2986 | + mode->picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135; |
|---|
| 2987 | + } |
|---|
| 2988 | + } |
|---|
| 2989 | + |
|---|
| 2806 | 2990 | kfree(edid); |
|---|
| 2807 | 2991 | } else { |
|---|
| 2808 | 2992 | hdmi->support_hdmi = true; |
|---|
| .. | .. |
|---|
| 2815 | 2999 | |
|---|
| 2816 | 3000 | mode = drm_mode_duplicate(connector->dev, ptr); |
|---|
| 2817 | 3001 | if (mode) { |
|---|
| 2818 | | - if (!i) { |
|---|
| 3002 | + if (!i) |
|---|
| 2819 | 3003 | mode->type = DRM_MODE_TYPE_PREFERRED; |
|---|
| 2820 | | - mode->picture_aspect_ratio = |
|---|
| 2821 | | - HDMI_PICTURE_ASPECT_NONE; |
|---|
| 2822 | | - } |
|---|
| 2823 | 3004 | drm_mode_probed_add(connector, mode); |
|---|
| 2824 | 3005 | ret++; |
|---|
| 2825 | 3006 | } |
|---|
| .. | .. |
|---|
| 2830 | 3011 | |
|---|
| 2831 | 3012 | dev_info(hdmi->dev, "failed to get edid\n"); |
|---|
| 2832 | 3013 | } |
|---|
| 3014 | + dw_hdmi_update_hdr_property(connector); |
|---|
| 2833 | 3015 | dw_hdmi_check_output_type_changed(hdmi); |
|---|
| 2834 | 3016 | |
|---|
| 2835 | 3017 | return ret; |
|---|
| .. | .. |
|---|
| 2892 | 3074 | return ret; |
|---|
| 2893 | 3075 | } |
|---|
| 2894 | 3076 | |
|---|
| 2895 | | -static bool hdr_metadata_equal(const struct drm_connector_state *old_state, |
|---|
| 3077 | +static bool hdr_metadata_equal(struct dw_hdmi *hdmi, const struct drm_connector_state *old_state, |
|---|
| 2896 | 3078 | const struct drm_connector_state *new_state) |
|---|
| 2897 | 3079 | { |
|---|
| 2898 | 3080 | struct drm_property_blob *old_blob = old_state->hdr_output_metadata; |
|---|
| 2899 | 3081 | struct drm_property_blob *new_blob = new_state->hdr_output_metadata; |
|---|
| 3082 | + int i, ret; |
|---|
| 3083 | + u8 *data; |
|---|
| 2900 | 3084 | |
|---|
| 2901 | | - if (!old_blob || !new_blob) |
|---|
| 2902 | | - return old_blob == new_blob; |
|---|
| 3085 | + hdmi->hdr2sdr = false; |
|---|
| 3086 | + |
|---|
| 3087 | + if (!old_blob && !new_blob) |
|---|
| 3088 | + return true; |
|---|
| 3089 | + |
|---|
| 3090 | + if (!old_blob) { |
|---|
| 3091 | + data = (u8 *)new_blob->data; |
|---|
| 3092 | + |
|---|
| 3093 | + for (i = 0; i < new_blob->length; i++) |
|---|
| 3094 | + if (data[i]) |
|---|
| 3095 | + return false; |
|---|
| 3096 | + |
|---|
| 3097 | + return true; |
|---|
| 3098 | + } |
|---|
| 3099 | + |
|---|
| 3100 | + if (!new_blob) { |
|---|
| 3101 | + data = (u8 *)old_blob->data; |
|---|
| 3102 | + |
|---|
| 3103 | + for (i = 0; i < old_blob->length; i++) |
|---|
| 3104 | + if (data[i]) |
|---|
| 3105 | + return false; |
|---|
| 3106 | + |
|---|
| 3107 | + return true; |
|---|
| 3108 | + } |
|---|
| 2903 | 3109 | |
|---|
| 2904 | 3110 | if (old_blob->length != new_blob->length) |
|---|
| 2905 | 3111 | return false; |
|---|
| 2906 | 3112 | |
|---|
| 2907 | | - return !memcmp(old_blob->data, new_blob->data, old_blob->length); |
|---|
| 3113 | + ret = !memcmp(old_blob->data, new_blob->data, old_blob->length); |
|---|
| 3114 | + |
|---|
| 3115 | + if (!ret && new_blob) { |
|---|
| 3116 | + data = (u8 *)new_blob->data; |
|---|
| 3117 | + |
|---|
| 3118 | + for (i = 0; i < new_blob->length; i++) |
|---|
| 3119 | + if (data[i]) |
|---|
| 3120 | + break; |
|---|
| 3121 | + |
|---|
| 3122 | + if (i == new_blob->length) |
|---|
| 3123 | + hdmi->hdr2sdr = true; |
|---|
| 3124 | + } |
|---|
| 3125 | + |
|---|
| 3126 | + return ret; |
|---|
| 3127 | +} |
|---|
| 3128 | + |
|---|
| 3129 | +static bool check_hdr_color_change(struct drm_connector_state *old_state, |
|---|
| 3130 | + struct drm_connector_state *new_state, |
|---|
| 3131 | + struct dw_hdmi *hdmi) |
|---|
| 3132 | +{ |
|---|
| 3133 | + void *data = hdmi->plat_data->phy_data; |
|---|
| 3134 | + |
|---|
| 3135 | + if (!hdr_metadata_equal(hdmi, old_state, new_state)) { |
|---|
| 3136 | + hdmi->plat_data->check_hdr_color_change(new_state, data); |
|---|
| 3137 | + return true; |
|---|
| 3138 | + } |
|---|
| 3139 | + |
|---|
| 3140 | + return false; |
|---|
| 3141 | +} |
|---|
| 3142 | + |
|---|
| 3143 | +static bool check_hdmi_format_change(struct drm_connector_state *old_state, |
|---|
| 3144 | + struct drm_connector_state *new_state, |
|---|
| 3145 | + struct drm_connector *connector, |
|---|
| 3146 | + struct dw_hdmi *hdmi) |
|---|
| 3147 | +{ |
|---|
| 3148 | + bool hdr_change, color_change; |
|---|
| 3149 | + |
|---|
| 3150 | + hdr_change = check_hdr_color_change(old_state, new_state, hdmi); |
|---|
| 3151 | + color_change = dw_hdmi_color_changed(connector); |
|---|
| 3152 | + |
|---|
| 3153 | + if (hdr_change || color_change) |
|---|
| 3154 | + return true; |
|---|
| 3155 | + |
|---|
| 3156 | + return false; |
|---|
| 2908 | 3157 | } |
|---|
| 2909 | 3158 | |
|---|
| 2910 | 3159 | static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, |
|---|
| .. | .. |
|---|
| 2925 | 3174 | if (!crtc) |
|---|
| 2926 | 3175 | return 0; |
|---|
| 2927 | 3176 | |
|---|
| 3177 | + crtc_state = drm_atomic_get_crtc_state(state, crtc); |
|---|
| 3178 | + if (IS_ERR(crtc_state)) |
|---|
| 3179 | + return PTR_ERR(crtc_state); |
|---|
| 3180 | + |
|---|
| 3181 | + mode = &crtc_state->mode; |
|---|
| 3182 | + |
|---|
| 2928 | 3183 | /* |
|---|
| 2929 | 3184 | * If HDMI is enabled in uboot, it's need to record |
|---|
| 2930 | 3185 | * drm_display_mode and set phy status to enabled. |
|---|
| 2931 | 3186 | */ |
|---|
| 2932 | 3187 | if (!vmode->mpixelclock) { |
|---|
| 2933 | | - crtc_state = drm_atomic_get_crtc_state(state, crtc); |
|---|
| 3188 | + u8 val; |
|---|
| 3189 | + |
|---|
| 2934 | 3190 | if (hdmi->plat_data->get_enc_in_encoding) |
|---|
| 2935 | 3191 | hdmi->hdmi_data.enc_in_encoding = |
|---|
| 2936 | 3192 | hdmi->plat_data->get_enc_in_encoding(data); |
|---|
| .. | .. |
|---|
| 2944 | 3200 | hdmi->hdmi_data.enc_out_bus_format = |
|---|
| 2945 | 3201 | hdmi->plat_data->get_output_bus_format(data); |
|---|
| 2946 | 3202 | |
|---|
| 2947 | | - mode = &crtc_state->mode; |
|---|
| 2948 | 3203 | memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode)); |
|---|
| 2949 | 3204 | vmode->mpixelclock = mode->crtc_clock * 1000; |
|---|
| 2950 | | - vmode->previous_pixelclock = mode->clock; |
|---|
| 2951 | | - vmode->previous_tmdsclock = mode->clock; |
|---|
| 3205 | + vmode->previous_pixelclock = mode->clock * 1000; |
|---|
| 3206 | + vmode->previous_tmdsclock = mode->clock * 1000; |
|---|
| 2952 | 3207 | vmode->mtmdsclock = hdmi_get_tmdsclock(hdmi, |
|---|
| 2953 | 3208 | vmode->mpixelclock); |
|---|
| 2954 | 3209 | if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) |
|---|
| 2955 | 3210 | vmode->mtmdsclock /= 2; |
|---|
| 3211 | + |
|---|
| 3212 | + dw_hdmi_force_output_pattern(hdmi, mode); |
|---|
| 3213 | + |
|---|
| 3214 | + hdmi_clk_regenerator_update_pixel_clock(hdmi); |
|---|
| 3215 | + hdmi_enable_audio_clk(hdmi, hdmi->audio_enable); |
|---|
| 3216 | + |
|---|
| 3217 | + drm_scdc_readb(hdmi->ddc, SCDC_TMDS_CONFIG, &val); |
|---|
| 3218 | + |
|---|
| 3219 | + /* if plug out before hdmi bind, reset hdmi */ |
|---|
| 3220 | + if (vmode->mtmdsclock >= 340000000 && !(val & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40)) |
|---|
| 3221 | + hdmi->logo_plug_out = true; |
|---|
| 2956 | 3222 | } |
|---|
| 2957 | 3223 | |
|---|
| 2958 | | - if (!hdr_metadata_equal(old_state, new_state) || |
|---|
| 2959 | | - dw_hdmi_color_changed(connector)) { |
|---|
| 2960 | | - crtc_state = drm_atomic_get_crtc_state(state, crtc); |
|---|
| 2961 | | - if (IS_ERR(crtc_state)) |
|---|
| 2962 | | - return PTR_ERR(crtc_state); |
|---|
| 3224 | + if (check_hdmi_format_change(old_state, new_state, connector, hdmi) || |
|---|
| 3225 | + hdmi->logo_plug_out) { |
|---|
| 3226 | + u32 mtmdsclk; |
|---|
| 2963 | 3227 | |
|---|
| 2964 | | - crtc_state->mode_changed = true; |
|---|
| 3228 | + if (hdmi->plat_data->update_color_format) |
|---|
| 3229 | + hdmi->plat_data->update_color_format(new_state, data); |
|---|
| 3230 | + if (hdmi->plat_data->get_enc_in_encoding) |
|---|
| 3231 | + hdmi->hdmi_data.enc_in_encoding = |
|---|
| 3232 | + hdmi->plat_data->get_enc_in_encoding(data); |
|---|
| 3233 | + if (hdmi->plat_data->get_enc_out_encoding) |
|---|
| 3234 | + hdmi->hdmi_data.enc_out_encoding = |
|---|
| 3235 | + hdmi->plat_data->get_enc_out_encoding(data); |
|---|
| 3236 | + if (hdmi->plat_data->get_input_bus_format) |
|---|
| 3237 | + hdmi->hdmi_data.enc_in_bus_format = |
|---|
| 3238 | + hdmi->plat_data->get_input_bus_format(data); |
|---|
| 3239 | + if (hdmi->plat_data->get_output_bus_format) |
|---|
| 3240 | + hdmi->hdmi_data.enc_out_bus_format = |
|---|
| 3241 | + hdmi->plat_data->get_output_bus_format(data); |
|---|
| 3242 | + |
|---|
| 3243 | + mtmdsclk = hdmi_get_tmdsclock(hdmi, mode->clock); |
|---|
| 3244 | + |
|---|
| 3245 | + if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) |
|---|
| 3246 | + mtmdsclk /= 2; |
|---|
| 3247 | + |
|---|
| 3248 | + if (!(hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD)) |
|---|
| 3249 | + return 0; |
|---|
| 3250 | + |
|---|
| 3251 | + if (hdmi->hdmi_data.video_mode.mpixelclock == (mode->clock * 1000) && |
|---|
| 3252 | + hdmi->hdmi_data.video_mode.mtmdsclock == (mtmdsclk * 1000) && |
|---|
| 3253 | + !hdmi->logo_plug_out && !hdmi->disabled) { |
|---|
| 3254 | + hdmi->update = true; |
|---|
| 3255 | + hdmi_writeb(hdmi, HDMI_FC_GCP_SET_AVMUTE, HDMI_FC_GCP); |
|---|
| 3256 | + mdelay(180); |
|---|
| 3257 | + handle_plugged_change(hdmi, false); |
|---|
| 3258 | + } else { |
|---|
| 3259 | + hdmi->update = false; |
|---|
| 3260 | + crtc_state->mode_changed = true; |
|---|
| 3261 | + hdmi->logo_plug_out = false; |
|---|
| 3262 | + } |
|---|
| 2965 | 3263 | } |
|---|
| 2966 | 3264 | |
|---|
| 2967 | 3265 | return 0; |
|---|
| 3266 | +} |
|---|
| 3267 | + |
|---|
| 3268 | +static void dw_hdmi_connector_atomic_commit(struct drm_connector *connector, |
|---|
| 3269 | + struct drm_connector_state *state) |
|---|
| 3270 | +{ |
|---|
| 3271 | + struct dw_hdmi *hdmi = |
|---|
| 3272 | + container_of(connector, struct dw_hdmi, connector); |
|---|
| 3273 | + |
|---|
| 3274 | + if (hdmi->update) { |
|---|
| 3275 | + dw_hdmi_setup(hdmi, &hdmi->previous_mode); |
|---|
| 3276 | + mdelay(50); |
|---|
| 3277 | + handle_plugged_change(hdmi, true); |
|---|
| 3278 | + hdmi_writeb(hdmi, HDMI_FC_GCP_CLEAR_AVMUTE, HDMI_FC_GCP); |
|---|
| 3279 | + hdmi->update = false; |
|---|
| 3280 | + } |
|---|
| 2968 | 3281 | } |
|---|
| 2969 | 3282 | |
|---|
| 2970 | 3283 | void dw_hdmi_set_quant_range(struct dw_hdmi *hdmi) |
|---|
| .. | .. |
|---|
| 3006 | 3319 | } |
|---|
| 3007 | 3320 | EXPORT_SYMBOL_GPL(dw_hdmi_get_output_type_cap); |
|---|
| 3008 | 3321 | |
|---|
| 3322 | +void dw_hdmi_set_hpd_wake(struct dw_hdmi *hdmi) |
|---|
| 3323 | +{ |
|---|
| 3324 | + if (!hdmi->cec) |
|---|
| 3325 | + return; |
|---|
| 3326 | + |
|---|
| 3327 | + dw_hdmi_hpd_wake_up(hdmi->cec); |
|---|
| 3328 | +} |
|---|
| 3329 | +EXPORT_SYMBOL_GPL(dw_hdmi_set_hpd_wake); |
|---|
| 3330 | + |
|---|
| 3009 | 3331 | static void dw_hdmi_connector_force(struct drm_connector *connector) |
|---|
| 3010 | 3332 | { |
|---|
| 3011 | 3333 | struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, |
|---|
| .. | .. |
|---|
| 3045 | 3367 | .get_modes = dw_hdmi_connector_get_modes, |
|---|
| 3046 | 3368 | .best_encoder = drm_atomic_helper_best_encoder, |
|---|
| 3047 | 3369 | .atomic_check = dw_hdmi_connector_atomic_check, |
|---|
| 3370 | + .atomic_commit = dw_hdmi_connector_atomic_commit, |
|---|
| 3048 | 3371 | }; |
|---|
| 3049 | 3372 | |
|---|
| 3050 | 3373 | static void dw_hdmi_attach_properties(struct dw_hdmi *hdmi) |
|---|
| .. | .. |
|---|
| 3172 | 3495 | if (hdmi->next_bridge) |
|---|
| 3173 | 3496 | return MODE_OK; |
|---|
| 3174 | 3497 | |
|---|
| 3498 | + if (!(hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD) && hdmi->hdr2sdr) |
|---|
| 3499 | + return MODE_OK; |
|---|
| 3500 | + |
|---|
| 3175 | 3501 | if (hdmi->plat_data->mode_valid) |
|---|
| 3176 | 3502 | mode_status = hdmi->plat_data->mode_valid(connector, mode); |
|---|
| 3177 | 3503 | |
|---|
| .. | .. |
|---|
| 3195 | 3521 | static void dw_hdmi_bridge_disable(struct drm_bridge *bridge) |
|---|
| 3196 | 3522 | { |
|---|
| 3197 | 3523 | struct dw_hdmi *hdmi = bridge->driver_private; |
|---|
| 3524 | + void *data = hdmi->plat_data->phy_data; |
|---|
| 3198 | 3525 | |
|---|
| 3199 | 3526 | mutex_lock(&hdmi->mutex); |
|---|
| 3200 | 3527 | hdmi->disabled = true; |
|---|
| 3528 | + handle_plugged_change(hdmi, false); |
|---|
| 3201 | 3529 | dw_hdmi_update_power(hdmi); |
|---|
| 3202 | 3530 | dw_hdmi_update_phy_mask(hdmi); |
|---|
| 3531 | + if (hdmi->plat_data->dclk_set) |
|---|
| 3532 | + hdmi->plat_data->dclk_set(hdmi->plat_data->phy_data, false, 0); |
|---|
| 3203 | 3533 | mutex_unlock(&hdmi->mutex); |
|---|
| 3534 | + |
|---|
| 3535 | + mutex_lock(&hdmi->i2c->lock); |
|---|
| 3536 | + if (hdmi->plat_data->set_ddc_io) |
|---|
| 3537 | + hdmi->plat_data->set_ddc_io(data, false); |
|---|
| 3538 | + mutex_unlock(&hdmi->i2c->lock); |
|---|
| 3204 | 3539 | } |
|---|
| 3205 | 3540 | |
|---|
| 3206 | 3541 | static void dw_hdmi_bridge_enable(struct drm_bridge *bridge) |
|---|
| .. | .. |
|---|
| 3209 | 3544 | |
|---|
| 3210 | 3545 | mutex_lock(&hdmi->mutex); |
|---|
| 3211 | 3546 | hdmi->disabled = false; |
|---|
| 3547 | + if (hdmi->plat_data->dclk_set) |
|---|
| 3548 | + hdmi->plat_data->dclk_set(hdmi->plat_data->phy_data, true, 0); |
|---|
| 3212 | 3549 | dw_hdmi_update_power(hdmi); |
|---|
| 3213 | 3550 | dw_hdmi_update_phy_mask(hdmi); |
|---|
| 3551 | + handle_plugged_change(hdmi, true); |
|---|
| 3214 | 3552 | mutex_unlock(&hdmi->mutex); |
|---|
| 3215 | 3553 | } |
|---|
| 3216 | 3554 | |
|---|
| .. | .. |
|---|
| 3456 | 3794 | static const struct dw_hdmi_cec_ops dw_hdmi_cec_ops = { |
|---|
| 3457 | 3795 | .write = hdmi_writeb, |
|---|
| 3458 | 3796 | .read = hdmi_readb, |
|---|
| 3797 | + .mod = hdmi_modb, |
|---|
| 3459 | 3798 | .enable = dw_hdmi_cec_enable, |
|---|
| 3460 | 3799 | .disable = dw_hdmi_cec_disable, |
|---|
| 3461 | 3800 | }; |
|---|
| .. | .. |
|---|
| 3464 | 3803 | .reg_bits = 32, |
|---|
| 3465 | 3804 | .val_bits = 8, |
|---|
| 3466 | 3805 | .reg_stride = 1, |
|---|
| 3467 | | - .max_register = HDMI_I2CM_FS_SCL_LCNT_0_ADDR, |
|---|
| 3806 | + .max_register = HDMI_I2CM_SCDC_UPDATE1, |
|---|
| 3468 | 3807 | }; |
|---|
| 3469 | 3808 | |
|---|
| 3470 | 3809 | static const struct regmap_config hdmi_regmap_32bit_config = { |
|---|
| 3471 | 3810 | .reg_bits = 32, |
|---|
| 3472 | 3811 | .val_bits = 32, |
|---|
| 3473 | 3812 | .reg_stride = 4, |
|---|
| 3474 | | - .max_register = HDMI_I2CM_FS_SCL_LCNT_0_ADDR << 2, |
|---|
| 3813 | + .max_register = HDMI_I2CM_SCDC_UPDATE1 << 2, |
|---|
| 3475 | 3814 | }; |
|---|
| 3476 | 3815 | |
|---|
| 3477 | 3816 | static int dw_hdmi_status_show(struct seq_file *s, void *v) |
|---|
| .. | .. |
|---|
| 3852 | 4191 | hdmi->connector.stereo_allowed = 1; |
|---|
| 3853 | 4192 | hdmi->plat_data = plat_data; |
|---|
| 3854 | 4193 | hdmi->dev = dev; |
|---|
| 4194 | + hdmi->audio_enable = true; |
|---|
| 3855 | 4195 | hdmi->sample_rate = 48000; |
|---|
| 3856 | 4196 | hdmi->disabled = true; |
|---|
| 3857 | 4197 | hdmi->rxsense = true; |
|---|
| .. | .. |
|---|
| 3983 | 4323 | if (ret) |
|---|
| 3984 | 4324 | goto err_iahb; |
|---|
| 3985 | 4325 | |
|---|
| 4326 | + hdmi->logo_plug_out = false; |
|---|
| 3986 | 4327 | hdmi->initialized = false; |
|---|
| 3987 | 4328 | ret = hdmi_readb(hdmi, HDMI_PHY_STAT0); |
|---|
| 3988 | 4329 | if (((ret & HDMI_PHY_TX_PHY_LOCK) && (ret & HDMI_PHY_HPD) && |
|---|
| .. | .. |
|---|
| 3992 | 4333 | hdmi->bridge_is_on = true; |
|---|
| 3993 | 4334 | hdmi->phy.enabled = true; |
|---|
| 3994 | 4335 | hdmi->initialized = true; |
|---|
| 4336 | + if (hdmi->plat_data->set_ddc_io) |
|---|
| 4337 | + hdmi->plat_data->set_ddc_io(hdmi->plat_data->phy_data, true); |
|---|
| 4338 | + if (hdmi->plat_data->dclk_set) |
|---|
| 4339 | + hdmi->plat_data->dclk_set(hdmi->plat_data->phy_data, true, 0); |
|---|
| 3995 | 4340 | } else if (ret & HDMI_PHY_TX_PHY_LOCK) { |
|---|
| 3996 | 4341 | hdmi->phy.ops->disable(hdmi, hdmi->phy.data); |
|---|
| 4342 | + if (hdmi->plat_data->set_ddc_io) |
|---|
| 4343 | + hdmi->plat_data->set_ddc_io(hdmi->plat_data->phy_data, false); |
|---|
| 3997 | 4344 | } |
|---|
| 3998 | 4345 | |
|---|
| 3999 | 4346 | init_hpd_work(hdmi); |
|---|
| .. | .. |
|---|
| 4007 | 4354 | |
|---|
| 4008 | 4355 | hdmi->irq = irq; |
|---|
| 4009 | 4356 | ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq, |
|---|
| 4010 | | - dw_hdmi_irq, IRQF_SHARED, |
|---|
| 4357 | + dw_hdmi_irq, IRQF_SHARED | IRQF_ONESHOT, |
|---|
| 4011 | 4358 | dev_name(dev), hdmi); |
|---|
| 4012 | 4359 | if (ret) |
|---|
| 4013 | 4360 | goto err_iahb; |
|---|
| .. | .. |
|---|
| 4126 | 4473 | cec.ops = &dw_hdmi_cec_ops; |
|---|
| 4127 | 4474 | cec.irq = irq; |
|---|
| 4128 | 4475 | |
|---|
| 4476 | + irq = platform_get_irq(pdev, 1); |
|---|
| 4477 | + if (irq < 0) |
|---|
| 4478 | + dev_dbg(hdmi->dev, "can't get cec wake up irq\n"); |
|---|
| 4479 | + |
|---|
| 4480 | + cec.wake_irq = irq; |
|---|
| 4481 | + |
|---|
| 4129 | 4482 | pdevinfo.name = "dw-hdmi-cec"; |
|---|
| 4130 | 4483 | pdevinfo.data = &cec; |
|---|
| 4131 | 4484 | pdevinfo.size_data = sizeof(cec); |
|---|
| .. | .. |
|---|
| 4136 | 4489 | |
|---|
| 4137 | 4490 | hdmi->extcon = devm_extcon_dev_allocate(hdmi->dev, dw_hdmi_cable); |
|---|
| 4138 | 4491 | if (IS_ERR(hdmi->extcon)) { |
|---|
| 4139 | | - dev_err(hdmi->dev, "allocate extcon failed\n"); |
|---|
| 4492 | + ret = PTR_ERR(hdmi->extcon); |
|---|
| 4493 | + dev_err(hdmi->dev, "allocate extcon failed: %d\n", ret); |
|---|
| 4140 | 4494 | goto err_iahb; |
|---|
| 4141 | 4495 | } |
|---|
| 4142 | 4496 | |
|---|