|
34 | 34 | #include <drm/drm_atomic_helper.h>
|
35 | 35 | #include <drm/drm_crtc.h>
|
36 | 36 | #include <drm/drm_edid.h>
|
| 37 | +#include <drm/drm_hdcp.h> |
37 | 38 | #include <drm/drm_scdc_helper.h>
|
38 | 39 | #include "intel_drv.h"
|
39 | 40 | #include <drm/i915_drm.h>
|
@@ -876,6 +877,248 @@ void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable)
|
876 | 877 | adapter, enable);
|
877 | 878 | }
|
878 | 879 |
|
| 880 | +static int intel_hdmi_hdcp_read(struct intel_digital_port *intel_dig_port, |
| 881 | + unsigned int offset, void *buffer, size_t size) |
| 882 | +{ |
| 883 | + struct intel_hdmi *hdmi = &intel_dig_port->hdmi; |
| 884 | + struct drm_i915_private *dev_priv = |
| 885 | + intel_dig_port->base.base.dev->dev_private; |
| 886 | + struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv, |
| 887 | + hdmi->ddc_bus); |
| 888 | + int ret; |
| 889 | + u8 start = offset & 0xff; |
| 890 | + struct i2c_msg msgs[] = { |
| 891 | + { |
| 892 | + .addr = DRM_HDCP_DDC_ADDR, |
| 893 | + .flags = 0, |
| 894 | + .len = 1, |
| 895 | + .buf = &start, |
| 896 | + }, |
| 897 | + { |
| 898 | + .addr = DRM_HDCP_DDC_ADDR, |
| 899 | + .flags = I2C_M_RD, |
| 900 | + .len = size, |
| 901 | + .buf = buffer |
| 902 | + } |
| 903 | + }; |
| 904 | + ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs)); |
| 905 | + if (ret == ARRAY_SIZE(msgs)) |
| 906 | + return 0; |
| 907 | + return ret >= 0 ? -EIO : ret; |
| 908 | +} |
| 909 | + |
| 910 | +static int intel_hdmi_hdcp_write(struct intel_digital_port *intel_dig_port, |
| 911 | + unsigned int offset, void *buffer, size_t size) |
| 912 | +{ |
| 913 | + struct intel_hdmi *hdmi = &intel_dig_port->hdmi; |
| 914 | + struct drm_i915_private *dev_priv = |
| 915 | + intel_dig_port->base.base.dev->dev_private; |
| 916 | + struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv, |
| 917 | + hdmi->ddc_bus); |
| 918 | + int ret; |
| 919 | + u8 *write_buf; |
| 920 | + struct i2c_msg msg; |
| 921 | + |
| 922 | + write_buf = kzalloc(size + 1, GFP_KERNEL); |
| 923 | + if (!write_buf) |
| 924 | + return -ENOMEM; |
| 925 | + |
| 926 | + write_buf[0] = offset & 0xff; |
| 927 | + memcpy(&write_buf[1], buffer, size); |
| 928 | + |
| 929 | + msg.addr = DRM_HDCP_DDC_ADDR; |
| 930 | + msg.flags = 0, |
| 931 | + msg.len = size + 1, |
| 932 | + msg.buf = write_buf; |
| 933 | + |
| 934 | + ret = i2c_transfer(adapter, &msg, 1); |
| 935 | + if (ret == 1) |
| 936 | + return 0; |
| 937 | + return ret >= 0 ? -EIO : ret; |
| 938 | +} |
| 939 | + |
| 940 | +static |
| 941 | +int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port, |
| 942 | + u8 *an) |
| 943 | +{ |
| 944 | + struct intel_hdmi *hdmi = &intel_dig_port->hdmi; |
| 945 | + struct drm_i915_private *dev_priv = |
| 946 | + intel_dig_port->base.base.dev->dev_private; |
| 947 | + struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv, |
| 948 | + hdmi->ddc_bus); |
| 949 | + int ret; |
| 950 | + |
| 951 | + ret = intel_hdmi_hdcp_write(intel_dig_port, DRM_HDCP_DDC_AN, an, |
| 952 | + DRM_HDCP_AN_LEN); |
| 953 | + if (ret) { |
| 954 | + DRM_ERROR("Write An over DDC failed (%d)\n", ret); |
| 955 | + return ret; |
| 956 | + } |
| 957 | + |
| 958 | + ret = intel_gmbus_output_aksv(adapter); |
| 959 | + if (ret < 0) { |
| 960 | + DRM_ERROR("Failed to output aksv (%d)\n", ret); |
| 961 | + return ret; |
| 962 | + } |
| 963 | + return 0; |
| 964 | +} |
| 965 | + |
| 966 | +static int intel_hdmi_hdcp_read_bksv(struct intel_digital_port *intel_dig_port, |
| 967 | + u8 *bksv) |
| 968 | +{ |
| 969 | + int ret; |
| 970 | + ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BKSV, bksv, |
| 971 | + DRM_HDCP_KSV_LEN); |
| 972 | + if (ret) |
| 973 | + DRM_ERROR("Read Bksv over DDC failed (%d)\n", ret); |
| 974 | + return ret; |
| 975 | +} |
| 976 | + |
| 977 | +static |
| 978 | +int intel_hdmi_hdcp_read_bstatus(struct intel_digital_port *intel_dig_port, |
| 979 | + u8 *bstatus) |
| 980 | +{ |
| 981 | + int ret; |
| 982 | + ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BSTATUS, |
| 983 | + bstatus, DRM_HDCP_BSTATUS_LEN); |
| 984 | + if (ret) |
| 985 | + DRM_ERROR("Read bstatus over DDC failed (%d)\n", ret); |
| 986 | + return ret; |
| 987 | +} |
| 988 | + |
| 989 | +static |
| 990 | +int intel_hdmi_hdcp_repeater_present(struct intel_digital_port *intel_dig_port, |
| 991 | + bool *repeater_present) |
| 992 | +{ |
| 993 | + int ret; |
| 994 | + u8 val; |
| 995 | + |
| 996 | + ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BCAPS, &val, 1); |
| 997 | + if (ret) { |
| 998 | + DRM_ERROR("Read bcaps over DDC failed (%d)\n", ret); |
| 999 | + return ret; |
| 1000 | + } |
| 1001 | + *repeater_present = val & DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT; |
| 1002 | + return 0; |
| 1003 | +} |
| 1004 | + |
| 1005 | +static |
| 1006 | +int intel_hdmi_hdcp_read_ri_prime(struct intel_digital_port *intel_dig_port, |
| 1007 | + u8 *ri_prime) |
| 1008 | +{ |
| 1009 | + int ret; |
| 1010 | + ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_RI_PRIME, |
| 1011 | + ri_prime, DRM_HDCP_RI_LEN); |
| 1012 | + if (ret) |
| 1013 | + DRM_ERROR("Read Ri' over DDC failed (%d)\n", ret); |
| 1014 | + return ret; |
| 1015 | +} |
| 1016 | + |
| 1017 | +static |
| 1018 | +int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *intel_dig_port, |
| 1019 | + bool *ksv_ready) |
| 1020 | +{ |
| 1021 | + int ret; |
| 1022 | + u8 val; |
| 1023 | + |
| 1024 | + ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BCAPS, &val, 1); |
| 1025 | + if (ret) { |
| 1026 | + DRM_ERROR("Read bcaps over DDC failed (%d)\n", ret); |
| 1027 | + return ret; |
| 1028 | + } |
| 1029 | + *ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY; |
| 1030 | + return 0; |
| 1031 | +} |
| 1032 | + |
| 1033 | +static |
| 1034 | +int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *intel_dig_port, |
| 1035 | + int num_downstream, u8 *ksv_fifo) |
| 1036 | +{ |
| 1037 | + int ret; |
| 1038 | + ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_KSV_FIFO, |
| 1039 | + ksv_fifo, num_downstream * DRM_HDCP_KSV_LEN); |
| 1040 | + if (ret) { |
| 1041 | + DRM_ERROR("Read ksv fifo over DDC failed (%d)\n", ret); |
| 1042 | + return ret; |
| 1043 | + } |
| 1044 | + return 0; |
| 1045 | +} |
| 1046 | + |
| 1047 | +static |
| 1048 | +int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port *intel_dig_port, |
| 1049 | + int i, u32 *part) |
| 1050 | +{ |
| 1051 | + int ret; |
| 1052 | + |
| 1053 | + if (i >= DRM_HDCP_V_PRIME_NUM_PARTS) |
| 1054 | + return -EINVAL; |
| 1055 | + |
| 1056 | + ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_V_PRIME(i), |
| 1057 | + part, DRM_HDCP_V_PRIME_PART_LEN); |
| 1058 | + if (ret) |
| 1059 | + DRM_ERROR("Read V'[%d] over DDC failed (%d)\n", i, ret); |
| 1060 | + return ret; |
| 1061 | +} |
| 1062 | + |
| 1063 | +static |
| 1064 | +int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *intel_dig_port, |
| 1065 | + bool enable) |
| 1066 | +{ |
| 1067 | + int ret; |
| 1068 | + |
| 1069 | + if (!enable) |
| 1070 | + usleep_range(6, 60); /* Bspec says >= 6us */ |
| 1071 | + |
| 1072 | + ret = intel_ddi_toggle_hdcp_signalling(&intel_dig_port->base, enable); |
| 1073 | + if (ret) { |
| 1074 | + DRM_ERROR("%s HDCP signalling failed (%d)\n", |
| 1075 | + enable ? "Enable" : "Disable", ret); |
| 1076 | + return ret; |
| 1077 | + } |
| 1078 | + return 0; |
| 1079 | +} |
| 1080 | + |
| 1081 | +static |
| 1082 | +bool intel_hdmi_hdcp_check_link(struct intel_digital_port *intel_dig_port) |
| 1083 | +{ |
| 1084 | + struct drm_i915_private *dev_priv = |
| 1085 | + intel_dig_port->base.base.dev->dev_private; |
| 1086 | + enum port port = intel_dig_port->base.port; |
| 1087 | + int ret; |
| 1088 | + union { |
| 1089 | + u32 reg; |
| 1090 | + u8 shim[DRM_HDCP_RI_LEN]; |
| 1091 | + } ri; |
| 1092 | + |
| 1093 | + ret = intel_hdmi_hdcp_read_ri_prime(intel_dig_port, ri.shim); |
| 1094 | + if (ret) |
| 1095 | + return false; |
| 1096 | + |
| 1097 | + I915_WRITE(PORT_HDCP_RPRIME(port), ri.reg); |
| 1098 | + |
| 1099 | + /* Wait for Ri prime match */ |
| 1100 | + if (wait_for(I915_READ(PORT_HDCP_STATUS(port)) & |
| 1101 | + (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) { |
| 1102 | + DRM_ERROR("Ri' mismatch detected, link check failed (%x)\n", |
| 1103 | + I915_READ(PORT_HDCP_STATUS(port))); |
| 1104 | + return false; |
| 1105 | + } |
| 1106 | + return true; |
| 1107 | +} |
| 1108 | + |
| 1109 | +static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = { |
| 1110 | + .write_an_aksv = intel_hdmi_hdcp_write_an_aksv, |
| 1111 | + .read_bksv = intel_hdmi_hdcp_read_bksv, |
| 1112 | + .read_bstatus = intel_hdmi_hdcp_read_bstatus, |
| 1113 | + .repeater_present = intel_hdmi_hdcp_repeater_present, |
| 1114 | + .read_ri_prime = intel_hdmi_hdcp_read_ri_prime, |
| 1115 | + .read_ksv_ready = intel_hdmi_hdcp_read_ksv_ready, |
| 1116 | + .read_ksv_fifo = intel_hdmi_hdcp_read_ksv_fifo, |
| 1117 | + .read_v_prime_part = intel_hdmi_hdcp_read_v_prime_part, |
| 1118 | + .toggle_signalling = intel_hdmi_hdcp_toggle_signalling, |
| 1119 | + .check_link = intel_hdmi_hdcp_check_link, |
| 1120 | +}; |
| 1121 | + |
879 | 1122 | static void intel_hdmi_prepare(struct intel_encoder *encoder,
|
880 | 1123 | const struct intel_crtc_state *crtc_state)
|
881 | 1124 | {
|
@@ -2053,6 +2296,13 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
|
2053 | 2296 |
|
2054 | 2297 | intel_hdmi_add_properties(intel_hdmi, connector);
|
2055 | 2298 |
|
| 2299 | + if (INTEL_GEN(dev_priv) >= 9) { |
| 2300 | + int ret = intel_hdcp_init(intel_connector, |
| 2301 | + &intel_hdmi_hdcp_shim); |
| 2302 | + if (ret) |
| 2303 | + DRM_DEBUG_KMS("HDCP init failed, skipping.\n"); |
| 2304 | + } |
| 2305 | + |
2056 | 2306 | intel_connector_attach_encoder(intel_connector, intel_encoder);
|
2057 | 2307 | intel_hdmi->attached_connector = intel_connector;
|
2058 | 2308 |
|
|
0 commit comments