27
27
#include <drm/drm_atomic_helper.h>
28
28
#include <drm/drm_edid.h>
29
29
#include <drm/drm_encoder_slave.h>
30
+ #include <drm/drm_scdc_helper.h>
30
31
#include <drm/drm_probe_helper.h>
31
32
#include <drm/bridge/dw_hdmi.h>
32
33
43
44
44
45
#define HDMI_EDID_LEN 512
45
46
47
+ /* DW-HDMI Controller >= 0x200a are at least compliant with SCDC version 1 */
48
+ #define SCDC_MIN_SOURCE_VERSION 0x1
49
+
50
+ #define HDMI14_MAX_TMDSCLK 340000000
51
+
46
52
enum hdmi_datamap {
47
53
RGB444_8B = 0x01 ,
48
54
RGB444_10B = 0x03 ,
@@ -1015,6 +1021,33 @@ void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
1015
1021
}
1016
1022
EXPORT_SYMBOL_GPL (dw_hdmi_phy_i2c_write );
1017
1023
1024
+ /*
1025
+ * HDMI2.0 Specifies the following procedure for High TMDS Bit Rates:
1026
+ * - The Source shall suspend transmission of the TMDS clock and data
1027
+ * - The Source shall write to the TMDS_Bit_Clock_Ratio bit to change it
1028
+ * from a 0 to a 1 or from a 1 to a 0
1029
+ * - The Source shall allow a minimum of 1 ms and a maximum of 100 ms from
1030
+ * the time the TMDS_Bit_Clock_Ratio bit is written until resuming
1031
+ * transmission of TMDS clock and data
1032
+ *
1033
+ * To respect the 100ms maximum delay, the dw_hdmi_set_high_tmds_clock_ratio()
1034
+ * helper should called right before enabling the TMDS Clock and Data in
1035
+ * the PHY configuration callback.
1036
+ */
1037
+ void dw_hdmi_set_high_tmds_clock_ratio (struct dw_hdmi * hdmi )
1038
+ {
1039
+ unsigned long mtmdsclock = hdmi -> hdmi_data .video_mode .mpixelclock ;
1040
+
1041
+ /* Control for TMDS Bit Period/TMDS Clock-Period Ratio */
1042
+ if (hdmi -> connector .display_info .hdmi .scdc .supported ) {
1043
+ if (mtmdsclock > HDMI14_MAX_TMDSCLK )
1044
+ drm_scdc_set_high_tmds_clock_ratio (hdmi -> ddc , 1 );
1045
+ else
1046
+ drm_scdc_set_high_tmds_clock_ratio (hdmi -> ddc , 0 );
1047
+ }
1048
+ }
1049
+ EXPORT_SYMBOL_GPL (dw_hdmi_set_high_tmds_clock_ratio );
1050
+
1018
1051
static void dw_hdmi_phy_enable_powerdown (struct dw_hdmi * hdmi , bool enable )
1019
1052
{
1020
1053
hdmi_mask_writeb (hdmi , !enable , HDMI_PHY_CONF0 ,
@@ -1216,6 +1249,8 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
1216
1249
1217
1250
dw_hdmi_phy_power_off (hdmi );
1218
1251
1252
+ dw_hdmi_set_high_tmds_clock_ratio (hdmi );
1253
+
1219
1254
/* Leave low power consumption mode by asserting SVSRET. */
1220
1255
if (phy -> has_svsret )
1221
1256
dw_hdmi_phy_enable_svsret (hdmi , 1 );
@@ -1237,6 +1272,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
1237
1272
return ret ;
1238
1273
}
1239
1274
1275
+ /* Wait for resuming transmission of TMDS clock and data */
1276
+ if (mpixelclock > HDMI14_MAX_TMDSCLK )
1277
+ msleep (100 );
1278
+
1240
1279
return dw_hdmi_phy_power_on (hdmi );
1241
1280
}
1242
1281
@@ -1504,7 +1543,8 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi,
1504
1543
static void hdmi_av_composer (struct dw_hdmi * hdmi ,
1505
1544
const struct drm_display_mode * mode )
1506
1545
{
1507
- u8 inv_val ;
1546
+ u8 inv_val , bytes ;
1547
+ struct drm_hdmi_info * hdmi_info = & hdmi -> connector .display_info .hdmi ;
1508
1548
struct hdmi_vmode * vmode = & hdmi -> hdmi_data .video_mode ;
1509
1549
int hblank , vblank , h_de_hs , v_de_vs , hsync_len , vsync_len ;
1510
1550
unsigned int vdisplay ;
@@ -1514,7 +1554,9 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
1514
1554
dev_dbg (hdmi -> dev , "final pixclk = %d\n" , vmode -> mpixelclock );
1515
1555
1516
1556
/* Set up HDMI_FC_INVIDCONF */
1517
- inv_val = (hdmi -> hdmi_data .hdcp_enable ?
1557
+ inv_val = (hdmi -> hdmi_data .hdcp_enable ||
1558
+ vmode -> mpixelclock > HDMI14_MAX_TMDSCLK ||
1559
+ hdmi_info -> scdc .scrambling .low_rates ?
1518
1560
HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
1519
1561
HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE );
1520
1562
@@ -1563,6 +1605,45 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
1563
1605
vsync_len /= 2 ;
1564
1606
}
1565
1607
1608
+ /* Scrambling Control */
1609
+ if (hdmi_info -> scdc .supported ) {
1610
+ if (vmode -> mpixelclock > HDMI14_MAX_TMDSCLK ||
1611
+ hdmi_info -> scdc .scrambling .low_rates ) {
1612
+ /*
1613
+ * HDMI2.0 Specifies the following procedure:
1614
+ * After the Source Device has determined that
1615
+ * SCDC_Present is set (=1), the Source Device should
1616
+ * write the accurate Version of the Source Device
1617
+ * to the Source Version field in the SCDCS.
1618
+ * Source Devices compliant shall set the
1619
+ * Source Version = 1.
1620
+ */
1621
+ drm_scdc_readb (& hdmi -> i2c -> adap , SCDC_SINK_VERSION ,
1622
+ & bytes );
1623
+ drm_scdc_writeb (& hdmi -> i2c -> adap , SCDC_SOURCE_VERSION ,
1624
+ min_t (u8 , bytes , SCDC_MIN_SOURCE_VERSION ));
1625
+
1626
+ /* Enabled Scrambling in the Sink */
1627
+ drm_scdc_set_scrambling (& hdmi -> i2c -> adap , 1 );
1628
+
1629
+ /*
1630
+ * To activate the scrambler feature, you must ensure
1631
+ * that the quasi-static configuration bit
1632
+ * fc_invidconf.HDCP_keepout is set at configuration
1633
+ * time, before the required mc_swrstzreq.tmdsswrst_req
1634
+ * reset request is issued.
1635
+ */
1636
+ hdmi_writeb (hdmi , (u8 )~HDMI_MC_SWRSTZ_TMDSSWRST_REQ ,
1637
+ HDMI_MC_SWRSTZ );
1638
+ hdmi_writeb (hdmi , 1 , HDMI_FC_SCRAMBLER_CTRL );
1639
+ } else {
1640
+ hdmi_writeb (hdmi , 0 , HDMI_FC_SCRAMBLER_CTRL );
1641
+ hdmi_writeb (hdmi , (u8 )~HDMI_MC_SWRSTZ_TMDSSWRST_REQ ,
1642
+ HDMI_MC_SWRSTZ );
1643
+ drm_scdc_set_scrambling (& hdmi -> i2c -> adap , 0 );
1644
+ }
1645
+ }
1646
+
1566
1647
/* Set up horizontal active pixel width */
1567
1648
hdmi_writeb (hdmi , mode -> hdisplay >> 8 , HDMI_FC_INHACTV1 );
1568
1649
hdmi_writeb (hdmi , mode -> hdisplay , HDMI_FC_INHACTV0 );
0 commit comments