mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 01:50:54 +07:00
Driver Changes:
- Reduce INTEL_DISPLAY_ENABLED to just removed outputs treating it as disconnected (Ville) - Introducing new AUX, DVO, and TC ports and refactoring code around hot plug interrupts for those. (Ville) - Centralize PLL_ENABLE register lookup (Anusha) - Improvements around DP downstream facing ports (DFP). (Ville) - Enable YCbCr 444->420 conversion for HDMI DFPs. Ville - Remove the old global state on Display's atomic modeset (Ville) - Nuke force_min_cdclk_changed (Ville) - Extend a TGL W/A to all SKUs and to RKL (Swathi) -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEbSBwaO7dZQkcLOKj+mJfZA7rE8oFAl9jzm4ACgkQ+mJfZA7r E8otXgf/V0gGTWSo/CUiBIDjW6jn9f/1pRmF2W0a0M8duLwlFMGVj/TGecgHRTNf ZHd66tqb7v2wxc+YouGYYZNcKyWwdH8nhTEjn8Zt3cIc2lweh3cWKIr0S+MiBQGo klaq+knIbr9gk3tJS4gvM0OQv0lPoXp6Gu8FsTAfmvkdt8L93OeNpmbA4TtSFbv5 sVm6e4LWI36TZuDO5VRDHTfLrQ7XkVte5sk2CzRRap+L77+RpBwD8p+QovRmNK4Q hTlfDHrLZR2XGpeTlqnqfzYq210hNyDspdhTENcnFrrxtB6pvd/CfOGRqEm/9MvX A37jLJfTtpeLRlQJDPt3KzOG581a+A== =gR/1 -----END PGP SIGNATURE----- Merge tag 'drm-intel-next-2020-09-17' of git://anongit.freedesktop.org/drm/drm-intel into drm-next Driver Changes: - Reduce INTEL_DISPLAY_ENABLED to just removed outputs treating it as disconnected (Ville) - Introducing new AUX, DVO, and TC ports and refactoring code around hot plug interrupts for those. (Ville) - Centralize PLL_ENABLE register lookup (Anusha) - Improvements around DP downstream facing ports (DFP). (Ville) - Enable YCbCr 444->420 conversion for HDMI DFPs. Ville - Remove the old global state on Display's atomic modeset (Ville) - Nuke force_min_cdclk_changed (Ville) - Extend a TGL W/A to all SKUs and to RKL (Swathi) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20200918173013.GA748558@intel.com
This commit is contained in:
commit
db29dc7d33
@ -67,7 +67,15 @@ ACPI_MODULE_NAME("acpi_lpss");
|
||||
#define LPSS_CLK_DIVIDER BIT(2)
|
||||
#define LPSS_LTR BIT(3)
|
||||
#define LPSS_SAVE_CTX BIT(4)
|
||||
#define LPSS_NO_D3_DELAY BIT(5)
|
||||
/*
|
||||
* For some devices the DSDT AML code for another device turns off the device
|
||||
* before our suspend handler runs, causing us to read/save all 1-s (0xffffffff)
|
||||
* as ctx register values.
|
||||
* Luckily these devices always use the same ctx register values, so we can
|
||||
* work around this by saving the ctx registers once on activation.
|
||||
*/
|
||||
#define LPSS_SAVE_CTX_ONCE BIT(5)
|
||||
#define LPSS_NO_D3_DELAY BIT(6)
|
||||
|
||||
struct lpss_private_data;
|
||||
|
||||
@ -254,9 +262,10 @@ static const struct lpss_device_desc byt_pwm_dev_desc = {
|
||||
};
|
||||
|
||||
static const struct lpss_device_desc bsw_pwm_dev_desc = {
|
||||
.flags = LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
|
||||
.flags = LPSS_SAVE_CTX_ONCE | LPSS_NO_D3_DELAY,
|
||||
.prv_offset = 0x800,
|
||||
.setup = bsw_pwm_setup,
|
||||
.resume_from_noirq = true,
|
||||
};
|
||||
|
||||
static const struct lpss_device_desc byt_uart_dev_desc = {
|
||||
@ -884,9 +893,14 @@ static int acpi_lpss_activate(struct device *dev)
|
||||
* we have to deassert reset line to be sure that ->probe() will
|
||||
* recognize the device.
|
||||
*/
|
||||
if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
|
||||
if (pdata->dev_desc->flags & (LPSS_SAVE_CTX | LPSS_SAVE_CTX_ONCE))
|
||||
lpss_deassert_reset(pdata);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (pdata->dev_desc->flags & LPSS_SAVE_CTX_ONCE)
|
||||
acpi_lpss_save_ctx(dev, pdata);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1030,7 +1044,7 @@ static int acpi_lpss_resume(struct device *dev)
|
||||
|
||||
acpi_lpss_d3_to_d0_delay(pdata);
|
||||
|
||||
if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
|
||||
if (pdata->dev_desc->flags & (LPSS_SAVE_CTX | LPSS_SAVE_CTX_ONCE))
|
||||
acpi_lpss_restore_ctx(dev, pdata);
|
||||
|
||||
return 0;
|
||||
|
@ -363,6 +363,66 @@ int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_dpcd_read_link_status);
|
||||
|
||||
static bool is_edid_digital_input_dp(const struct edid *edid)
|
||||
{
|
||||
return edid && edid->revision >= 4 &&
|
||||
edid->input & DRM_EDID_INPUT_DIGITAL &&
|
||||
(edid->input & DRM_EDID_DIGITAL_TYPE_MASK) == DRM_EDID_DIGITAL_TYPE_DP;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_is_type() - is the downstream facing port of certain type?
|
||||
* @dpcd: DisplayPort configuration data
|
||||
* @port_cap: port capabilities
|
||||
*
|
||||
* Caveat: Only works with DPCD 1.1+ port caps.
|
||||
*
|
||||
* Returns: whether the downstream facing port matches the type.
|
||||
*/
|
||||
bool drm_dp_downstream_is_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4], u8 type)
|
||||
{
|
||||
return drm_dp_is_branch(dpcd) &&
|
||||
dpcd[DP_DPCD_REV] >= 0x11 &&
|
||||
(port_cap[0] & DP_DS_PORT_TYPE_MASK) == type;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_downstream_is_type);
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_is_tmds() - is the downstream facing port TMDS?
|
||||
* @dpcd: DisplayPort configuration data
|
||||
* @port_cap: port capabilities
|
||||
* @edid: EDID
|
||||
*
|
||||
* Returns: whether the downstream facing port is TMDS (HDMI/DVI).
|
||||
*/
|
||||
bool drm_dp_downstream_is_tmds(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4],
|
||||
const struct edid *edid)
|
||||
{
|
||||
if (dpcd[DP_DPCD_REV] < 0x11) {
|
||||
switch (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) {
|
||||
case DP_DWN_STRM_PORT_TYPE_TMDS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) {
|
||||
case DP_DS_PORT_TYPE_DP_DUALMODE:
|
||||
if (is_edid_digital_input_dp(edid))
|
||||
return false;
|
||||
fallthrough;
|
||||
case DP_DS_PORT_TYPE_DVI:
|
||||
case DP_DS_PORT_TYPE_HDMI:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_downstream_is_tmds);
|
||||
|
||||
/**
|
||||
* drm_dp_send_real_edid_checksum() - send back real edid checksum value
|
||||
* @aux: DisplayPort AUX channel
|
||||
@ -545,79 +605,191 @@ int drm_dp_read_downstream_info(struct drm_dp_aux *aux,
|
||||
ret = drm_dp_dpcd_read(aux, DP_DOWNSTREAM_PORT_0, downstream_ports, len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret != len)
|
||||
return -EIO;
|
||||
|
||||
return ret == len ? 0 : -EIO;
|
||||
DRM_DEBUG_KMS("%s: DPCD DFP: %*ph\n",
|
||||
aux->name, len, downstream_ports);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_read_downstream_info);
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_max_clock() - extract branch device max
|
||||
* pixel rate for legacy VGA
|
||||
* converter or max TMDS clock
|
||||
* rate for others
|
||||
* drm_dp_downstream_max_dotclock() - extract downstream facing port max dot clock
|
||||
* @dpcd: DisplayPort configuration data
|
||||
* @port_cap: port capabilities
|
||||
*
|
||||
* See also:
|
||||
* drm_dp_read_downstream_info()
|
||||
* drm_dp_downstream_max_bpc()
|
||||
*
|
||||
* Returns: Max clock in kHz on success or 0 if max clock not defined
|
||||
* Returns: Downstream facing port max dot clock in kHz on success,
|
||||
* or 0 if max clock not defined
|
||||
*/
|
||||
int drm_dp_downstream_max_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4])
|
||||
int drm_dp_downstream_max_dotclock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4])
|
||||
{
|
||||
int type = port_cap[0] & DP_DS_PORT_TYPE_MASK;
|
||||
bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
|
||||
DP_DETAILED_CAP_INFO_AVAILABLE;
|
||||
|
||||
if (!detailed_cap_info)
|
||||
if (!drm_dp_is_branch(dpcd))
|
||||
return 0;
|
||||
|
||||
switch (type) {
|
||||
if (dpcd[DP_DPCD_REV] < 0x11)
|
||||
return 0;
|
||||
|
||||
switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) {
|
||||
case DP_DS_PORT_TYPE_VGA:
|
||||
return port_cap[1] * 8 * 1000;
|
||||
case DP_DS_PORT_TYPE_DVI:
|
||||
case DP_DS_PORT_TYPE_HDMI:
|
||||
if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0)
|
||||
return 0;
|
||||
return port_cap[1] * 8000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_downstream_max_dotclock);
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_max_tmds_clock() - extract downstream facing port max TMDS clock
|
||||
* @dpcd: DisplayPort configuration data
|
||||
* @port_cap: port capabilities
|
||||
* @edid: EDID
|
||||
*
|
||||
* Returns: HDMI/DVI downstream facing port max TMDS clock in kHz on success,
|
||||
* or 0 if max TMDS clock not defined
|
||||
*/
|
||||
int drm_dp_downstream_max_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4],
|
||||
const struct edid *edid)
|
||||
{
|
||||
if (!drm_dp_is_branch(dpcd))
|
||||
return 0;
|
||||
|
||||
if (dpcd[DP_DPCD_REV] < 0x11) {
|
||||
switch (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) {
|
||||
case DP_DWN_STRM_PORT_TYPE_TMDS:
|
||||
return 165000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) {
|
||||
case DP_DS_PORT_TYPE_DP_DUALMODE:
|
||||
if (is_edid_digital_input_dp(edid))
|
||||
return 0;
|
||||
/*
|
||||
* It's left up to the driver to check the
|
||||
* DP dual mode adapter's max TMDS clock.
|
||||
*
|
||||
* Unfortunatley it looks like branch devices
|
||||
* may not fordward that the DP dual mode i2c
|
||||
* access so we just usually get i2c nak :(
|
||||
*/
|
||||
fallthrough;
|
||||
case DP_DS_PORT_TYPE_HDMI:
|
||||
/*
|
||||
* We should perhaps assume 165 MHz when detailed cap
|
||||
* info is not available. But looks like many typical
|
||||
* branch devices fall into that category and so we'd
|
||||
* probably end up with users complaining that they can't
|
||||
* get high resolution modes with their favorite dongle.
|
||||
*
|
||||
* So let's limit to 300 MHz instead since DPCD 1.4
|
||||
* HDMI 2.0 DFPs are required to have the detailed cap
|
||||
* info. So it's more likely we're dealing with a HDMI 1.4
|
||||
* compatible* device here.
|
||||
*/
|
||||
if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0)
|
||||
return 300000;
|
||||
return port_cap[1] * 2500;
|
||||
case DP_DS_PORT_TYPE_DVI:
|
||||
if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0)
|
||||
return 165000;
|
||||
/* FIXME what to do about DVI dual link? */
|
||||
return port_cap[1] * 2500;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_downstream_max_clock);
|
||||
EXPORT_SYMBOL(drm_dp_downstream_max_tmds_clock);
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_max_bpc() - extract branch device max
|
||||
* bits per component
|
||||
* drm_dp_downstream_min_tmds_clock() - extract downstream facing port min TMDS clock
|
||||
* @dpcd: DisplayPort configuration data
|
||||
* @port_cap: port capabilities
|
||||
* @edid: EDID
|
||||
*
|
||||
* See also:
|
||||
* drm_dp_read_downstream_info()
|
||||
* drm_dp_downstream_max_clock()
|
||||
* Returns: HDMI/DVI downstream facing port min TMDS clock in kHz on success,
|
||||
* or 0 if max TMDS clock not defined
|
||||
*/
|
||||
int drm_dp_downstream_min_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4],
|
||||
const struct edid *edid)
|
||||
{
|
||||
if (!drm_dp_is_branch(dpcd))
|
||||
return 0;
|
||||
|
||||
if (dpcd[DP_DPCD_REV] < 0x11) {
|
||||
switch (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) {
|
||||
case DP_DWN_STRM_PORT_TYPE_TMDS:
|
||||
return 25000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) {
|
||||
case DP_DS_PORT_TYPE_DP_DUALMODE:
|
||||
if (is_edid_digital_input_dp(edid))
|
||||
return 0;
|
||||
fallthrough;
|
||||
case DP_DS_PORT_TYPE_DVI:
|
||||
case DP_DS_PORT_TYPE_HDMI:
|
||||
/*
|
||||
* Unclear whether the protocol converter could
|
||||
* utilize pixel replication. Assume it won't.
|
||||
*/
|
||||
return 25000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_downstream_min_tmds_clock);
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_max_bpc() - extract downstream facing port max
|
||||
* bits per component
|
||||
* @dpcd: DisplayPort configuration data
|
||||
* @port_cap: downstream facing port capabilities
|
||||
* @edid: EDID
|
||||
*
|
||||
* Returns: Max bpc on success or 0 if max bpc not defined
|
||||
*/
|
||||
int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4])
|
||||
const u8 port_cap[4],
|
||||
const struct edid *edid)
|
||||
{
|
||||
int type = port_cap[0] & DP_DS_PORT_TYPE_MASK;
|
||||
bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
|
||||
DP_DETAILED_CAP_INFO_AVAILABLE;
|
||||
int bpc;
|
||||
|
||||
if (!detailed_cap_info)
|
||||
if (!drm_dp_is_branch(dpcd))
|
||||
return 0;
|
||||
|
||||
switch (type) {
|
||||
case DP_DS_PORT_TYPE_VGA:
|
||||
case DP_DS_PORT_TYPE_DVI:
|
||||
case DP_DS_PORT_TYPE_HDMI:
|
||||
case DP_DS_PORT_TYPE_DP_DUALMODE:
|
||||
bpc = port_cap[2] & DP_DS_MAX_BPC_MASK;
|
||||
if (dpcd[DP_DPCD_REV] < 0x11) {
|
||||
switch (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) {
|
||||
case DP_DWN_STRM_PORT_TYPE_DP:
|
||||
return 0;
|
||||
default:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
switch (bpc) {
|
||||
switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) {
|
||||
case DP_DS_PORT_TYPE_DP:
|
||||
return 0;
|
||||
case DP_DS_PORT_TYPE_DP_DUALMODE:
|
||||
if (is_edid_digital_input_dp(edid))
|
||||
return 0;
|
||||
fallthrough;
|
||||
case DP_DS_PORT_TYPE_HDMI:
|
||||
case DP_DS_PORT_TYPE_DVI:
|
||||
case DP_DS_PORT_TYPE_VGA:
|
||||
if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0)
|
||||
return 8;
|
||||
|
||||
switch (port_cap[2] & DP_DS_MAX_BPC_MASK) {
|
||||
case DP_DS_8BPC:
|
||||
return 8;
|
||||
case DP_DS_10BPC:
|
||||
@ -626,14 +798,130 @@ int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
return 12;
|
||||
case DP_DS_16BPC:
|
||||
return 16;
|
||||
default:
|
||||
return 8;
|
||||
}
|
||||
fallthrough;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_downstream_max_bpc);
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_420_passthrough() - determine downstream facing port
|
||||
* YCbCr 4:2:0 pass-through capability
|
||||
* @dpcd: DisplayPort configuration data
|
||||
* @port_cap: downstream facing port capabilities
|
||||
*
|
||||
* Returns: whether the downstream facing port can pass through YCbCr 4:2:0
|
||||
*/
|
||||
bool drm_dp_downstream_420_passthrough(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4])
|
||||
{
|
||||
if (!drm_dp_is_branch(dpcd))
|
||||
return false;
|
||||
|
||||
if (dpcd[DP_DPCD_REV] < 0x13)
|
||||
return false;
|
||||
|
||||
switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) {
|
||||
case DP_DS_PORT_TYPE_DP:
|
||||
return true;
|
||||
case DP_DS_PORT_TYPE_HDMI:
|
||||
if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0)
|
||||
return false;
|
||||
|
||||
return port_cap[3] & DP_DS_HDMI_YCBCR420_PASS_THROUGH;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_downstream_420_passthrough);
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_444_to_420_conversion() - determine downstream facing port
|
||||
* YCbCr 4:4:4->4:2:0 conversion capability
|
||||
* @dpcd: DisplayPort configuration data
|
||||
* @port_cap: downstream facing port capabilities
|
||||
*
|
||||
* Returns: whether the downstream facing port can convert YCbCr 4:4:4 to 4:2:0
|
||||
*/
|
||||
bool drm_dp_downstream_444_to_420_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4])
|
||||
{
|
||||
if (!drm_dp_is_branch(dpcd))
|
||||
return false;
|
||||
|
||||
if (dpcd[DP_DPCD_REV] < 0x13)
|
||||
return false;
|
||||
|
||||
switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) {
|
||||
case DP_DS_PORT_TYPE_HDMI:
|
||||
if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0)
|
||||
return false;
|
||||
|
||||
return port_cap[3] & DP_DS_HDMI_YCBCR444_TO_420_CONV;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_downstream_444_to_420_conversion);
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_mode() - return a mode for downstream facing port
|
||||
* @dpcd: DisplayPort configuration data
|
||||
* @port_cap: port capabilities
|
||||
*
|
||||
* Provides a suitable mode for downstream facing ports without EDID.
|
||||
*
|
||||
* Returns: A new drm_display_mode on success or NULL on failure
|
||||
*/
|
||||
struct drm_display_mode *
|
||||
drm_dp_downstream_mode(struct drm_device *dev,
|
||||
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4])
|
||||
|
||||
{
|
||||
u8 vic;
|
||||
|
||||
if (!drm_dp_is_branch(dpcd))
|
||||
return NULL;
|
||||
|
||||
if (dpcd[DP_DPCD_REV] < 0x11)
|
||||
return NULL;
|
||||
|
||||
switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) {
|
||||
case DP_DS_PORT_TYPE_NON_EDID:
|
||||
switch (port_cap[0] & DP_DS_NON_EDID_MASK) {
|
||||
case DP_DS_NON_EDID_720x480i_60:
|
||||
vic = 6;
|
||||
break;
|
||||
case DP_DS_NON_EDID_720x480i_50:
|
||||
vic = 21;
|
||||
break;
|
||||
case DP_DS_NON_EDID_1920x1080i_60:
|
||||
vic = 5;
|
||||
break;
|
||||
case DP_DS_NON_EDID_1920x1080i_50:
|
||||
vic = 20;
|
||||
break;
|
||||
case DP_DS_NON_EDID_1280x720_60:
|
||||
vic = 4;
|
||||
break;
|
||||
case DP_DS_NON_EDID_1280x720_50:
|
||||
vic = 19;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
return drm_display_mode_from_cea_vic(dev, vic);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_downstream_mode);
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_id() - identify branch device
|
||||
* @aux: DisplayPort AUX channel
|
||||
@ -652,12 +940,15 @@ EXPORT_SYMBOL(drm_dp_downstream_id);
|
||||
* @m: pointer for debugfs file
|
||||
* @dpcd: DisplayPort configuration data
|
||||
* @port_cap: port capabilities
|
||||
* @edid: EDID
|
||||
* @aux: DisplayPort AUX channel
|
||||
*
|
||||
*/
|
||||
void drm_dp_downstream_debug(struct seq_file *m,
|
||||
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4], struct drm_dp_aux *aux)
|
||||
const u8 port_cap[4],
|
||||
const struct edid *edid,
|
||||
struct drm_dp_aux *aux)
|
||||
{
|
||||
bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
|
||||
DP_DETAILED_CAP_INFO_AVAILABLE;
|
||||
@ -715,16 +1006,19 @@ void drm_dp_downstream_debug(struct seq_file *m,
|
||||
seq_printf(m, "\t\tSW: %d.%d\n", rev[0], rev[1]);
|
||||
|
||||
if (detailed_cap_info) {
|
||||
clk = drm_dp_downstream_max_clock(dpcd, port_cap);
|
||||
clk = drm_dp_downstream_max_dotclock(dpcd, port_cap);
|
||||
if (clk > 0)
|
||||
seq_printf(m, "\t\tMax dot clock: %d kHz\n", clk);
|
||||
|
||||
if (clk > 0) {
|
||||
if (type == DP_DS_PORT_TYPE_VGA)
|
||||
seq_printf(m, "\t\tMax dot clock: %d kHz\n", clk);
|
||||
else
|
||||
seq_printf(m, "\t\tMax TMDS clock: %d kHz\n", clk);
|
||||
}
|
||||
clk = drm_dp_downstream_max_tmds_clock(dpcd, port_cap, edid);
|
||||
if (clk > 0)
|
||||
seq_printf(m, "\t\tMax TMDS clock: %d kHz\n", clk);
|
||||
|
||||
bpc = drm_dp_downstream_max_bpc(dpcd, port_cap);
|
||||
clk = drm_dp_downstream_min_tmds_clock(dpcd, port_cap, edid);
|
||||
if (clk > 0)
|
||||
seq_printf(m, "\t\tMin TMDS clock: %d kHz\n", clk);
|
||||
|
||||
bpc = drm_dp_downstream_max_bpc(dpcd, port_cap, edid);
|
||||
|
||||
if (bpc > 0)
|
||||
seq_printf(m, "\t\tMax bpc: %d\n", bpc);
|
||||
|
@ -20,11 +20,13 @@
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/iopoll.h>
|
||||
@ -423,6 +425,22 @@ drm_dp_encode_sideband_req(const struct drm_dp_sideband_msg_req_body *req,
|
||||
memcpy(&buf[idx], req->u.i2c_write.bytes, req->u.i2c_write.num_bytes);
|
||||
idx += req->u.i2c_write.num_bytes;
|
||||
break;
|
||||
case DP_QUERY_STREAM_ENC_STATUS: {
|
||||
const struct drm_dp_query_stream_enc_status *msg;
|
||||
|
||||
msg = &req->u.enc_status;
|
||||
buf[idx] = msg->stream_id;
|
||||
idx++;
|
||||
memcpy(&buf[idx], msg->client_id, sizeof(msg->client_id));
|
||||
idx += sizeof(msg->client_id);
|
||||
buf[idx] = 0;
|
||||
buf[idx] |= FIELD_PREP(GENMASK(1, 0), msg->stream_event);
|
||||
buf[idx] |= msg->valid_stream_event ? BIT(2) : 0;
|
||||
buf[idx] |= FIELD_PREP(GENMASK(4, 3), msg->stream_behavior);
|
||||
buf[idx] |= msg->valid_stream_behavior ? BIT(5) : 0;
|
||||
idx++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
raw->cur_len = idx;
|
||||
}
|
||||
@ -551,6 +569,20 @@ drm_dp_decode_sideband_req(const struct drm_dp_sideband_msg_tx *raw,
|
||||
return -ENOMEM;
|
||||
}
|
||||
break;
|
||||
case DP_QUERY_STREAM_ENC_STATUS:
|
||||
req->u.enc_status.stream_id = buf[idx++];
|
||||
for (i = 0; i < sizeof(req->u.enc_status.client_id); i++)
|
||||
req->u.enc_status.client_id[i] = buf[idx++];
|
||||
|
||||
req->u.enc_status.stream_event = FIELD_GET(GENMASK(1, 0),
|
||||
buf[idx]);
|
||||
req->u.enc_status.valid_stream_event = FIELD_GET(BIT(2),
|
||||
buf[idx]);
|
||||
req->u.enc_status.stream_behavior = FIELD_GET(GENMASK(4, 3),
|
||||
buf[idx]);
|
||||
req->u.enc_status.valid_stream_behavior = FIELD_GET(BIT(5),
|
||||
buf[idx]);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -629,6 +661,16 @@ drm_dp_dump_sideband_msg_req_body(const struct drm_dp_sideband_msg_req_body *req
|
||||
req->u.i2c_write.num_bytes, req->u.i2c_write.num_bytes,
|
||||
req->u.i2c_write.bytes);
|
||||
break;
|
||||
case DP_QUERY_STREAM_ENC_STATUS:
|
||||
P("stream_id=%u client_id=%*ph stream_event=%x "
|
||||
"valid_event=%d stream_behavior=%x valid_behavior=%d",
|
||||
req->u.enc_status.stream_id,
|
||||
(int)ARRAY_SIZE(req->u.enc_status.client_id),
|
||||
req->u.enc_status.client_id, req->u.enc_status.stream_event,
|
||||
req->u.enc_status.valid_stream_event,
|
||||
req->u.enc_status.stream_behavior,
|
||||
req->u.enc_status.valid_stream_behavior);
|
||||
break;
|
||||
default:
|
||||
P("???\n");
|
||||
break;
|
||||
@ -936,6 +978,42 @@ static bool drm_dp_sideband_parse_power_updown_phy_ack(struct drm_dp_sideband_ms
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
drm_dp_sideband_parse_query_stream_enc_status(
|
||||
struct drm_dp_sideband_msg_rx *raw,
|
||||
struct drm_dp_sideband_msg_reply_body *repmsg)
|
||||
{
|
||||
struct drm_dp_query_stream_enc_status_ack_reply *reply;
|
||||
|
||||
reply = &repmsg->u.enc_status;
|
||||
|
||||
reply->stream_id = raw->msg[3];
|
||||
|
||||
reply->reply_signed = raw->msg[2] & BIT(0);
|
||||
|
||||
/*
|
||||
* NOTE: It's my impression from reading the spec that the below parsing
|
||||
* is correct. However I noticed while testing with an HDCP 1.4 display
|
||||
* through an HDCP 2.2 hub that only bit 3 was set. In that case, I
|
||||
* would expect both bits to be set. So keep the parsing following the
|
||||
* spec, but beware reality might not match the spec (at least for some
|
||||
* configurations).
|
||||
*/
|
||||
reply->hdcp_1x_device_present = raw->msg[2] & BIT(4);
|
||||
reply->hdcp_2x_device_present = raw->msg[2] & BIT(3);
|
||||
|
||||
reply->query_capable_device_present = raw->msg[2] & BIT(5);
|
||||
reply->legacy_device_present = raw->msg[2] & BIT(6);
|
||||
reply->unauthorizable_device_present = raw->msg[2] & BIT(7);
|
||||
|
||||
reply->auth_completed = !!(raw->msg[1] & BIT(3));
|
||||
reply->encryption_enabled = !!(raw->msg[1] & BIT(4));
|
||||
reply->repeater_present = !!(raw->msg[1] & BIT(5));
|
||||
reply->state = (raw->msg[1] & GENMASK(7, 6)) >> 6;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw,
|
||||
struct drm_dp_sideband_msg_reply_body *msg)
|
||||
{
|
||||
@ -970,6 +1048,8 @@ static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw,
|
||||
return drm_dp_sideband_parse_power_updown_phy_ack(raw, msg);
|
||||
case DP_CLEAR_PAYLOAD_ID_TABLE:
|
||||
return true; /* since there's nothing to parse */
|
||||
case DP_QUERY_STREAM_ENC_STATUS:
|
||||
return drm_dp_sideband_parse_query_stream_enc_status(raw, msg);
|
||||
default:
|
||||
DRM_ERROR("Got unknown reply 0x%02x (%s)\n", msg->req_type,
|
||||
drm_dp_mst_req_type_str(msg->req_type));
|
||||
@ -1121,6 +1201,25 @@ static void build_power_updown_phy(struct drm_dp_sideband_msg_tx *msg,
|
||||
msg->path_msg = true;
|
||||
}
|
||||
|
||||
static int
|
||||
build_query_stream_enc_status(struct drm_dp_sideband_msg_tx *msg, u8 stream_id,
|
||||
u8 *q_id)
|
||||
{
|
||||
struct drm_dp_sideband_msg_req_body req;
|
||||
|
||||
req.req_type = DP_QUERY_STREAM_ENC_STATUS;
|
||||
req.u.enc_status.stream_id = stream_id;
|
||||
memcpy(req.u.enc_status.client_id, q_id,
|
||||
sizeof(req.u.enc_status.client_id));
|
||||
req.u.enc_status.stream_event = 0;
|
||||
req.u.enc_status.valid_stream_event = false;
|
||||
req.u.enc_status.stream_behavior = 0;
|
||||
req.u.enc_status.valid_stream_behavior = false;
|
||||
|
||||
drm_dp_encode_sideband_req(&req, msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr,
|
||||
struct drm_dp_vcpi *vcpi)
|
||||
{
|
||||
@ -3153,6 +3252,57 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_send_power_updown_phy);
|
||||
|
||||
int drm_dp_send_query_stream_enc_status(struct drm_dp_mst_topology_mgr *mgr,
|
||||
struct drm_dp_mst_port *port,
|
||||
struct drm_dp_query_stream_enc_status_ack_reply *status)
|
||||
{
|
||||
struct drm_dp_sideband_msg_tx *txmsg;
|
||||
u8 nonce[7];
|
||||
int len, ret;
|
||||
|
||||
txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
|
||||
if (!txmsg)
|
||||
return -ENOMEM;
|
||||
|
||||
port = drm_dp_mst_topology_get_port_validated(mgr, port);
|
||||
if (!port) {
|
||||
ret = -EINVAL;
|
||||
goto out_get_port;
|
||||
}
|
||||
|
||||
get_random_bytes(nonce, sizeof(nonce));
|
||||
|
||||
/*
|
||||
* "Source device targets the QUERY_STREAM_ENCRYPTION_STATUS message
|
||||
* transaction at the MST Branch device directly connected to the
|
||||
* Source"
|
||||
*/
|
||||
txmsg->dst = mgr->mst_primary;
|
||||
|
||||
len = build_query_stream_enc_status(txmsg, port->vcpi.vcpi, nonce);
|
||||
|
||||
drm_dp_queue_down_tx(mgr, txmsg);
|
||||
|
||||
ret = drm_dp_mst_wait_tx_reply(mgr->mst_primary, txmsg);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
} else if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) {
|
||||
drm_dbg_kms(mgr->dev, "query encryption status nak received\n");
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
memcpy(status, &txmsg->reply.u.enc_status, sizeof(*status));
|
||||
|
||||
out:
|
||||
drm_dp_mst_topology_put_port(port);
|
||||
out_get_port:
|
||||
kfree(txmsg);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_send_query_stream_enc_status);
|
||||
|
||||
static int drm_dp_create_payload_step1(struct drm_dp_mst_topology_mgr *mgr,
|
||||
int id,
|
||||
struct drm_dp_payload *payload)
|
||||
|
@ -3738,6 +3738,34 @@ drm_add_cmdb_modes(struct drm_connector *connector, u8 svd)
|
||||
bitmap_set(hdmi->y420_cmdb_modes, vic, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_display_mode_from_cea_vic() - return a mode for CEA VIC
|
||||
* @dev: DRM device
|
||||
* @vic: CEA VIC of the mode
|
||||
*
|
||||
* Creates a new mode matching the specified CEA VIC.
|
||||
*
|
||||
* Returns: A new drm_display_mode on success or NULL on failure
|
||||
*/
|
||||
struct drm_display_mode *
|
||||
drm_display_mode_from_cea_vic(struct drm_device *dev,
|
||||
u8 video_code)
|
||||
{
|
||||
const struct drm_display_mode *cea_mode;
|
||||
struct drm_display_mode *newmode;
|
||||
|
||||
cea_mode = cea_mode_for_vic(video_code);
|
||||
if (!cea_mode)
|
||||
return NULL;
|
||||
|
||||
newmode = drm_mode_duplicate(dev, cea_mode);
|
||||
if (!newmode)
|
||||
return NULL;
|
||||
|
||||
return newmode;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_display_mode_from_cea_vic);
|
||||
|
||||
static int
|
||||
do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len)
|
||||
{
|
||||
|
@ -234,6 +234,7 @@ i915-y += \
|
||||
display/intel_ddi.o \
|
||||
display/intel_dp.o \
|
||||
display/intel_dp_aux_backlight.o \
|
||||
display/intel_dp_hdcp.o \
|
||||
display/intel_dp_link_training.o \
|
||||
display/intel_dp_mst.o \
|
||||
display/intel_dsi.o \
|
||||
|
@ -1646,6 +1646,7 @@ static const struct drm_encoder_funcs gen11_dsi_encoder_funcs = {
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs gen11_dsi_connector_funcs = {
|
||||
.detect = intel_panel_detect,
|
||||
.late_register = intel_connector_register,
|
||||
.early_unregister = intel_connector_unregister,
|
||||
.destroy = intel_connector_destroy,
|
||||
|
@ -527,8 +527,6 @@ void intel_atomic_state_clear(struct drm_atomic_state *s)
|
||||
intel_atomic_clear_global_state(state);
|
||||
|
||||
state->dpll_set = state->modeset = false;
|
||||
state->global_state_changed = false;
|
||||
state->active_pipes = 0;
|
||||
}
|
||||
|
||||
struct intel_crtc_state *
|
||||
@ -542,40 +540,3 @@ intel_atomic_get_crtc_state(struct drm_atomic_state *state,
|
||||
|
||||
return to_intel_crtc_state(crtc_state);
|
||||
}
|
||||
|
||||
int _intel_atomic_lock_global_state(struct intel_atomic_state *state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||
struct intel_crtc *crtc;
|
||||
|
||||
state->global_state_changed = true;
|
||||
|
||||
for_each_intel_crtc(&dev_priv->drm, crtc) {
|
||||
int ret;
|
||||
|
||||
ret = drm_modeset_lock(&crtc->base.mutex,
|
||||
state->base.acquire_ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _intel_atomic_serialize_global_state(struct intel_atomic_state *state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||
struct intel_crtc *crtc;
|
||||
|
||||
state->global_state_changed = true;
|
||||
|
||||
for_each_intel_crtc(&dev_priv->drm, crtc) {
|
||||
struct intel_crtc_state *crtc_state;
|
||||
|
||||
crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
|
||||
if (IS_ERR(crtc_state))
|
||||
return PTR_ERR(crtc_state);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -56,8 +56,4 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
|
||||
struct intel_crtc *intel_crtc,
|
||||
struct intel_crtc_state *crtc_state);
|
||||
|
||||
int _intel_atomic_lock_global_state(struct intel_atomic_state *state);
|
||||
|
||||
int _intel_atomic_serialize_global_state(struct intel_atomic_state *state);
|
||||
|
||||
#endif /* __INTEL_ATOMIC_H__ */
|
||||
|
@ -958,13 +958,8 @@ static int glk_force_audio_cdclk_commit(struct intel_atomic_state *state,
|
||||
if (IS_ERR(cdclk_state))
|
||||
return PTR_ERR(cdclk_state);
|
||||
|
||||
cdclk_state->force_min_cdclk_changed = true;
|
||||
cdclk_state->force_min_cdclk = enable ? 2 * 96000 : 0;
|
||||
|
||||
ret = intel_atomic_lock_global_state(&cdclk_state->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return drm_atomic_commit(&state->base);
|
||||
}
|
||||
|
||||
|
@ -1656,6 +1656,8 @@ static enum port dvo_port_to_port(struct drm_i915_private *dev_priv,
|
||||
[PORT_E] = { DVO_PORT_HDMIE, DVO_PORT_DPE, DVO_PORT_CRT },
|
||||
[PORT_F] = { DVO_PORT_HDMIF, DVO_PORT_DPF, -1 },
|
||||
[PORT_G] = { DVO_PORT_HDMIG, DVO_PORT_DPG, -1 },
|
||||
[PORT_H] = { DVO_PORT_HDMIH, DVO_PORT_DPH, -1 },
|
||||
[PORT_I] = { DVO_PORT_HDMII, DVO_PORT_DPI, -1 },
|
||||
};
|
||||
/*
|
||||
* Bspec lists the ports as A, B, C, D - however internally in our
|
||||
@ -2133,7 +2135,7 @@ void intel_bios_init(struct drm_i915_private *dev_priv)
|
||||
|
||||
INIT_LIST_HEAD(&dev_priv->vbt.display_devices);
|
||||
|
||||
if (!HAS_DISPLAY(dev_priv) || !INTEL_DISPLAY_ENABLED(dev_priv)) {
|
||||
if (!HAS_DISPLAY(dev_priv)) {
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
"Skipping VBT init due to disabled display.\n");
|
||||
return;
|
||||
@ -2650,6 +2652,12 @@ enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *dev_priv,
|
||||
case DP_AUX_G:
|
||||
aux_ch = AUX_CH_G;
|
||||
break;
|
||||
case DP_AUX_H:
|
||||
aux_ch = AUX_CH_H;
|
||||
break;
|
||||
case DP_AUX_I:
|
||||
aux_ch = AUX_CH_I;
|
||||
break;
|
||||
default:
|
||||
MISSING_CASE(info->alternate_aux_channel);
|
||||
aux_ch = AUX_CH_A;
|
||||
|
@ -2426,7 +2426,6 @@ static struct intel_global_state *intel_cdclk_duplicate_state(struct intel_globa
|
||||
if (!cdclk_state)
|
||||
return NULL;
|
||||
|
||||
cdclk_state->force_min_cdclk_changed = false;
|
||||
cdclk_state->pipe = INVALID_PIPE;
|
||||
|
||||
return &cdclk_state->base;
|
||||
@ -2501,6 +2500,7 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state)
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (old_cdclk_state->active_pipes != new_cdclk_state->active_pipes ||
|
||||
old_cdclk_state->force_min_cdclk != new_cdclk_state->force_min_cdclk ||
|
||||
intel_cdclk_changed(&old_cdclk_state->logical,
|
||||
&new_cdclk_state->logical)) {
|
||||
ret = intel_atomic_lock_global_state(&new_cdclk_state->base);
|
||||
|
@ -49,7 +49,6 @@ struct intel_cdclk_state {
|
||||
|
||||
/* forced minimum cdclk for glk+ audio w/a */
|
||||
int force_min_cdclk;
|
||||
bool force_min_cdclk_changed;
|
||||
|
||||
/* bitmask of active pipes */
|
||||
u8 active_pipes;
|
||||
|
@ -833,6 +833,9 @@ intel_crt_detect(struct drm_connector *connector,
|
||||
connector->base.id, connector->name,
|
||||
force);
|
||||
|
||||
if (!INTEL_DISPLAY_ENABLED(dev_priv))
|
||||
return connector_status_disconnected;
|
||||
|
||||
if (dev_priv->params.load_detect_test) {
|
||||
wakeref = intel_display_power_get(dev_priv,
|
||||
intel_encoder->power_domain);
|
||||
|
@ -572,13 +572,13 @@ static const struct cnl_ddi_buf_trans ehl_combo_phy_ddi_translations_dp[] = {
|
||||
/* NT mV Trans mV db */
|
||||
{ 0xA, 0x33, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */
|
||||
{ 0xA, 0x47, 0x36, 0x00, 0x09 }, /* 350 500 3.1 */
|
||||
{ 0xC, 0x64, 0x30, 0x00, 0x0F }, /* 350 700 6.0 */
|
||||
{ 0x6, 0x7F, 0x2C, 0x00, 0x13 }, /* 350 900 8.2 */
|
||||
{ 0xC, 0x64, 0x34, 0x00, 0x0B }, /* 350 700 6.0 */
|
||||
{ 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 350 900 8.2 */
|
||||
{ 0xA, 0x46, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */
|
||||
{ 0xC, 0x64, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */
|
||||
{ 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */
|
||||
{ 0xC, 0x64, 0x38, 0x00, 0x07 }, /* 500 700 2.9 */
|
||||
{ 0x6, 0x7F, 0x32, 0x00, 0x0D }, /* 500 900 5.1 */
|
||||
{ 0xC, 0x61, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */
|
||||
{ 0x6, 0x7F, 0x37, 0x00, 0x08 }, /* 600 900 3.5 */
|
||||
{ 0x6, 0x7F, 0x38, 0x00, 0x07 }, /* 600 900 3.5 */
|
||||
{ 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */
|
||||
};
|
||||
|
||||
@ -1074,12 +1074,28 @@ static const struct cnl_ddi_buf_trans *
|
||||
ehl_get_combo_buf_trans(struct intel_encoder *encoder, int type, int rate,
|
||||
int *n_entries)
|
||||
{
|
||||
if (type != INTEL_OUTPUT_HDMI && type != INTEL_OUTPUT_EDP) {
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
|
||||
switch (type) {
|
||||
case INTEL_OUTPUT_HDMI:
|
||||
*n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
|
||||
return icl_combo_phy_ddi_translations_hdmi;
|
||||
case INTEL_OUTPUT_EDP:
|
||||
if (dev_priv->vbt.edp.low_vswing) {
|
||||
if (rate > 540000) {
|
||||
*n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3);
|
||||
return icl_combo_phy_ddi_translations_edp_hbr3;
|
||||
} else {
|
||||
*n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2);
|
||||
return icl_combo_phy_ddi_translations_edp_hbr2;
|
||||
}
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
/* All combo DP and eDP ports that do not support low_vswing */
|
||||
*n_entries = ARRAY_SIZE(ehl_combo_phy_ddi_translations_dp);
|
||||
return ehl_combo_phy_ddi_translations_dp;
|
||||
}
|
||||
|
||||
return icl_get_combo_buf_trans(encoder, type, rate, n_entries);
|
||||
}
|
||||
|
||||
static const struct cnl_ddi_buf_trans *
|
||||
@ -1088,30 +1104,44 @@ tgl_get_combo_buf_trans(struct intel_encoder *encoder, int type, int rate,
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
|
||||
if (type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.hobl) {
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
switch (type) {
|
||||
case INTEL_OUTPUT_HDMI:
|
||||
*n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi);
|
||||
return icl_combo_phy_ddi_translations_hdmi;
|
||||
case INTEL_OUTPUT_EDP:
|
||||
if (dev_priv->vbt.edp.hobl) {
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
|
||||
if (!intel_dp->hobl_failed && rate <= 540000) {
|
||||
/* Same table applies to TGL, RKL and DG1 */
|
||||
*n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_edp_hbr2_hobl);
|
||||
return tgl_combo_phy_ddi_translations_edp_hbr2_hobl;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_EDP) {
|
||||
return icl_get_combo_buf_trans(encoder, type, rate, n_entries);
|
||||
} else if (rate > 270000) {
|
||||
if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) {
|
||||
*n_entries = ARRAY_SIZE(tgl_uy_combo_phy_ddi_translations_dp_hbr2);
|
||||
return tgl_uy_combo_phy_ddi_translations_dp_hbr2;
|
||||
if (!intel_dp->hobl_failed && rate <= 540000) {
|
||||
/* Same table applies to TGL, RKL and DG1 */
|
||||
*n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_edp_hbr2_hobl);
|
||||
return tgl_combo_phy_ddi_translations_edp_hbr2_hobl;
|
||||
}
|
||||
}
|
||||
|
||||
*n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr2);
|
||||
return tgl_combo_phy_ddi_translations_dp_hbr2;
|
||||
}
|
||||
if (rate > 540000) {
|
||||
*n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3);
|
||||
return icl_combo_phy_ddi_translations_edp_hbr3;
|
||||
} else if (dev_priv->vbt.edp.low_vswing) {
|
||||
*n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2);
|
||||
return icl_combo_phy_ddi_translations_edp_hbr2;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
/* All combo DP and eDP ports that do not support low_vswing */
|
||||
if (rate > 270000) {
|
||||
if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) {
|
||||
*n_entries = ARRAY_SIZE(tgl_uy_combo_phy_ddi_translations_dp_hbr2);
|
||||
return tgl_uy_combo_phy_ddi_translations_dp_hbr2;
|
||||
}
|
||||
|
||||
*n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr);
|
||||
return tgl_combo_phy_ddi_translations_dp_hbr;
|
||||
*n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr2);
|
||||
return tgl_combo_phy_ddi_translations_dp_hbr2;
|
||||
}
|
||||
|
||||
*n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr);
|
||||
return tgl_combo_phy_ddi_translations_dp_hbr;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct tgl_dkl_phy_ddi_buf_trans *
|
||||
@ -1791,6 +1821,8 @@ void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state
|
||||
|
||||
ctl = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder));
|
||||
|
||||
drm_WARN_ON(crtc->base.dev, ctl & TRANS_DDI_HDCP_SIGNALLING);
|
||||
|
||||
ctl &= ~TRANS_DDI_FUNC_ENABLE;
|
||||
|
||||
if (IS_GEN_RANGE(dev_priv, 8, 10))
|
||||
@ -1818,12 +1850,12 @@ void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state
|
||||
}
|
||||
|
||||
int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
|
||||
enum transcoder cpu_transcoder,
|
||||
bool enable)
|
||||
{
|
||||
struct drm_device *dev = intel_encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
intel_wakeref_t wakeref;
|
||||
enum pipe pipe = 0;
|
||||
int ret = 0;
|
||||
u32 tmp;
|
||||
|
||||
@ -1832,19 +1864,12 @@ int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
|
||||
if (drm_WARN_ON(dev, !wakeref))
|
||||
return -ENXIO;
|
||||
|
||||
if (drm_WARN_ON(dev,
|
||||
!intel_encoder->get_hw_state(intel_encoder, &pipe))) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(pipe));
|
||||
tmp = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder));
|
||||
if (enable)
|
||||
tmp |= TRANS_DDI_HDCP_SIGNALLING;
|
||||
else
|
||||
tmp &= ~TRANS_DDI_HDCP_SIGNALLING;
|
||||
intel_de_write(dev_priv, TRANS_DDI_FUNC_CTL(pipe), tmp);
|
||||
out:
|
||||
intel_de_write(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder), tmp);
|
||||
intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
|
||||
return ret;
|
||||
}
|
||||
@ -3445,6 +3470,7 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
|
||||
intel_ddi_init_dp_buf_reg(encoder);
|
||||
if (!is_mst)
|
||||
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
|
||||
intel_dp_configure_protocol_converter(intel_dp);
|
||||
intel_dp_sink_set_decompression_state(intel_dp, crtc_state,
|
||||
true);
|
||||
intel_dp_sink_set_fec_ready(intel_dp, crtc_state);
|
||||
@ -3556,19 +3582,17 @@ static void intel_ddi_pre_enable(struct intel_atomic_state *state,
|
||||
intel_ddi_pre_enable_hdmi(state, encoder, crtc_state,
|
||||
conn_state);
|
||||
} else {
|
||||
struct intel_lspcon *lspcon =
|
||||
enc_to_intel_lspcon(encoder);
|
||||
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
|
||||
|
||||
intel_ddi_pre_enable_dp(state, encoder, crtc_state,
|
||||
conn_state);
|
||||
if (lspcon->active) {
|
||||
struct intel_digital_port *dig_port =
|
||||
enc_to_dig_port(encoder);
|
||||
|
||||
/* FIXME precompute everything properly */
|
||||
/* FIXME how do we turn infoframes off again? */
|
||||
if (dig_port->lspcon.active && dig_port->dp.has_hdmi_sink)
|
||||
dig_port->set_infoframes(encoder,
|
||||
crtc_state->has_infoframe,
|
||||
crtc_state, conn_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4012,18 +4036,19 @@ static void intel_ddi_update_pipe_dp(struct intel_atomic_state *state,
|
||||
|
||||
intel_psr_update(intel_dp, crtc_state, conn_state);
|
||||
intel_dp_set_infoframes(encoder, true, crtc_state, conn_state);
|
||||
intel_edp_drrs_enable(intel_dp, crtc_state);
|
||||
intel_edp_drrs_update(intel_dp, crtc_state);
|
||||
|
||||
intel_panel_update_backlight(state, encoder, crtc_state, conn_state);
|
||||
}
|
||||
|
||||
static void intel_ddi_update_pipe(struct intel_atomic_state *state,
|
||||
struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *crtc_state,
|
||||
const struct drm_connector_state *conn_state)
|
||||
void intel_ddi_update_pipe(struct intel_atomic_state *state,
|
||||
struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *crtc_state,
|
||||
const struct drm_connector_state *conn_state)
|
||||
{
|
||||
|
||||
if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
|
||||
if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) &&
|
||||
!intel_encoder_is_mst(encoder))
|
||||
intel_ddi_update_pipe_dp(state, encoder, crtc_state,
|
||||
conn_state);
|
||||
|
||||
@ -4949,6 +4974,57 @@ static bool hti_uses_phy(struct drm_i915_private *i915, enum phy phy)
|
||||
i915->hti_state & HDPORT_PHY_USED_HDMI(phy));
|
||||
}
|
||||
|
||||
static enum hpd_pin tgl_hpd_pin(struct drm_i915_private *dev_priv,
|
||||
enum port port)
|
||||
{
|
||||
if (port >= PORT_D)
|
||||
return HPD_PORT_TC1 + port - PORT_D;
|
||||
else
|
||||
return HPD_PORT_A + port - PORT_A;
|
||||
}
|
||||
|
||||
static enum hpd_pin rkl_hpd_pin(struct drm_i915_private *dev_priv,
|
||||
enum port port)
|
||||
{
|
||||
if (HAS_PCH_TGP(dev_priv))
|
||||
return tgl_hpd_pin(dev_priv, port);
|
||||
|
||||
if (port >= PORT_D)
|
||||
return HPD_PORT_C + port - PORT_D;
|
||||
else
|
||||
return HPD_PORT_A + port - PORT_A;
|
||||
}
|
||||
|
||||
static enum hpd_pin icl_hpd_pin(struct drm_i915_private *dev_priv,
|
||||
enum port port)
|
||||
{
|
||||
if (port >= PORT_C)
|
||||
return HPD_PORT_TC1 + port - PORT_C;
|
||||
else
|
||||
return HPD_PORT_A + port - PORT_A;
|
||||
}
|
||||
|
||||
static enum hpd_pin ehl_hpd_pin(struct drm_i915_private *dev_priv,
|
||||
enum port port)
|
||||
{
|
||||
if (port == PORT_D)
|
||||
return HPD_PORT_A;
|
||||
|
||||
if (HAS_PCH_MCC(dev_priv))
|
||||
return icl_hpd_pin(dev_priv, port);
|
||||
|
||||
return HPD_PORT_A + port - PORT_A;
|
||||
}
|
||||
|
||||
static enum hpd_pin cnl_hpd_pin(struct drm_i915_private *dev_priv,
|
||||
enum port port)
|
||||
{
|
||||
if (port == PORT_F)
|
||||
return HPD_PORT_E;
|
||||
|
||||
return HPD_PORT_A + port - PORT_A;
|
||||
}
|
||||
|
||||
void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
|
||||
{
|
||||
struct intel_digital_port *dig_port;
|
||||
@ -5001,6 +5077,9 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
|
||||
drm_encoder_init(&dev_priv->drm, &encoder->base, &intel_ddi_funcs,
|
||||
DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
|
||||
|
||||
mutex_init(&dig_port->hdcp_mutex);
|
||||
dig_port->num_hdcp_streams = 0;
|
||||
|
||||
encoder->hotplug = intel_ddi_hotplug;
|
||||
encoder->compute_output_type = intel_ddi_compute_output_type;
|
||||
encoder->compute_config = intel_ddi_compute_config;
|
||||
@ -5022,6 +5101,19 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
|
||||
encoder->cloneable = 0;
|
||||
encoder->pipe_mask = ~0;
|
||||
|
||||
if (IS_ROCKETLAKE(dev_priv))
|
||||
encoder->hpd_pin = rkl_hpd_pin(dev_priv, port);
|
||||
else if (INTEL_GEN(dev_priv) >= 12)
|
||||
encoder->hpd_pin = tgl_hpd_pin(dev_priv, port);
|
||||
else if (IS_ELKHARTLAKE(dev_priv))
|
||||
encoder->hpd_pin = ehl_hpd_pin(dev_priv, port);
|
||||
else if (IS_GEN(dev_priv, 11))
|
||||
encoder->hpd_pin = icl_hpd_pin(dev_priv, port);
|
||||
else if (IS_GEN(dev_priv, 10))
|
||||
encoder->hpd_pin = cnl_hpd_pin(dev_priv, port);
|
||||
else
|
||||
encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port);
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 11)
|
||||
dig_port->saved_port_bits =
|
||||
intel_de_read(dev_priv, DDI_BUF_CTL(port))
|
||||
|
@ -16,6 +16,7 @@ struct intel_crtc_state;
|
||||
struct intel_dp;
|
||||
struct intel_dpll_hw_state;
|
||||
struct intel_encoder;
|
||||
enum transcoder;
|
||||
|
||||
void intel_ddi_fdi_post_disable(struct intel_atomic_state *state,
|
||||
struct intel_encoder *intel_encoder,
|
||||
@ -43,6 +44,7 @@ void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv,
|
||||
u32 bxt_signal_levels(struct intel_dp *intel_dp);
|
||||
u32 ddi_signal_levels(struct intel_dp *intel_dp);
|
||||
int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
|
||||
enum transcoder cpu_transcoder,
|
||||
bool enable);
|
||||
void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder);
|
||||
|
||||
|
@ -67,6 +67,7 @@
|
||||
#include "intel_bw.h"
|
||||
#include "intel_cdclk.h"
|
||||
#include "intel_color.h"
|
||||
#include "intel_csr.h"
|
||||
#include "intel_display_types.h"
|
||||
#include "intel_dp_link_training.h"
|
||||
#include "intel_fbc.h"
|
||||
@ -7331,6 +7332,10 @@ enum intel_display_power_domain intel_port_to_power_domain(enum port port)
|
||||
return POWER_DOMAIN_PORT_DDI_F_LANES;
|
||||
case PORT_G:
|
||||
return POWER_DOMAIN_PORT_DDI_G_LANES;
|
||||
case PORT_H:
|
||||
return POWER_DOMAIN_PORT_DDI_H_LANES;
|
||||
case PORT_I:
|
||||
return POWER_DOMAIN_PORT_DDI_I_LANES;
|
||||
default:
|
||||
MISSING_CASE(port);
|
||||
return POWER_DOMAIN_PORT_OTHER;
|
||||
@ -7356,6 +7361,10 @@ intel_aux_power_domain(struct intel_digital_port *dig_port)
|
||||
return POWER_DOMAIN_AUX_F_TBT;
|
||||
case AUX_CH_G:
|
||||
return POWER_DOMAIN_AUX_G_TBT;
|
||||
case AUX_CH_H:
|
||||
return POWER_DOMAIN_AUX_H_TBT;
|
||||
case AUX_CH_I:
|
||||
return POWER_DOMAIN_AUX_I_TBT;
|
||||
default:
|
||||
MISSING_CASE(dig_port->aux_ch);
|
||||
return POWER_DOMAIN_AUX_C_TBT;
|
||||
@ -7387,6 +7396,10 @@ intel_legacy_aux_to_power_domain(enum aux_ch aux_ch)
|
||||
return POWER_DOMAIN_AUX_F;
|
||||
case AUX_CH_G:
|
||||
return POWER_DOMAIN_AUX_G;
|
||||
case AUX_CH_H:
|
||||
return POWER_DOMAIN_AUX_H;
|
||||
case AUX_CH_I:
|
||||
return POWER_DOMAIN_AUX_I;
|
||||
default:
|
||||
MISSING_CASE(aux_ch);
|
||||
return POWER_DOMAIN_AUX_A;
|
||||
@ -14636,16 +14649,8 @@ u8 intel_calc_active_pipes(struct intel_atomic_state *state,
|
||||
static int intel_modeset_checks(struct intel_atomic_state *state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||
int ret;
|
||||
|
||||
state->modeset = true;
|
||||
state->active_pipes = intel_calc_active_pipes(state, dev_priv->active_pipes);
|
||||
|
||||
if (state->active_pipes != dev_priv->active_pipes) {
|
||||
ret = _intel_atomic_lock_global_state(state);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (IS_HASWELL(dev_priv))
|
||||
return hsw_mode_set_planes_workaround(state);
|
||||
@ -14789,7 +14794,8 @@ static int intel_atomic_check_cdclk(struct intel_atomic_state *state,
|
||||
bool *need_cdclk_calc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||
struct intel_cdclk_state *new_cdclk_state;
|
||||
const struct intel_cdclk_state *old_cdclk_state;
|
||||
const struct intel_cdclk_state *new_cdclk_state;
|
||||
struct intel_plane_state *plane_state;
|
||||
struct intel_bw_state *new_bw_state;
|
||||
struct intel_plane *plane;
|
||||
@ -14808,9 +14814,11 @@ static int intel_atomic_check_cdclk(struct intel_atomic_state *state,
|
||||
return ret;
|
||||
}
|
||||
|
||||
old_cdclk_state = intel_atomic_get_old_cdclk_state(state);
|
||||
new_cdclk_state = intel_atomic_get_new_cdclk_state(state);
|
||||
|
||||
if (new_cdclk_state && new_cdclk_state->force_min_cdclk_changed)
|
||||
if (new_cdclk_state &&
|
||||
old_cdclk_state->force_min_cdclk != new_cdclk_state->force_min_cdclk)
|
||||
*need_cdclk_calc = true;
|
||||
|
||||
ret = dev_priv->display.bw_calc_min_cdclk(state);
|
||||
@ -15757,14 +15765,6 @@ static void intel_atomic_track_fbs(struct intel_atomic_state *state)
|
||||
plane->frontbuffer_bit);
|
||||
}
|
||||
|
||||
static void assert_global_state_locked(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_crtc *crtc;
|
||||
|
||||
for_each_intel_crtc(&dev_priv->drm, crtc)
|
||||
drm_modeset_lock_assert_held(&crtc->base.mutex);
|
||||
}
|
||||
|
||||
static int intel_atomic_commit(struct drm_device *dev,
|
||||
struct drm_atomic_state *_state,
|
||||
bool nonblock)
|
||||
@ -15840,12 +15840,6 @@ static int intel_atomic_commit(struct drm_device *dev,
|
||||
intel_shared_dpll_swap_state(state);
|
||||
intel_atomic_track_fbs(state);
|
||||
|
||||
if (state->global_state_changed) {
|
||||
assert_global_state_locked(dev_priv);
|
||||
|
||||
dev_priv->active_pipes = state->active_pipes;
|
||||
}
|
||||
|
||||
drm_atomic_state_get(&state->base);
|
||||
INIT_WORK(&state->base.commit_work, intel_atomic_commit_work);
|
||||
|
||||
@ -16892,7 +16886,7 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv)
|
||||
|
||||
intel_pps_init(dev_priv);
|
||||
|
||||
if (!HAS_DISPLAY(dev_priv) || !INTEL_DISPLAY_ENABLED(dev_priv))
|
||||
if (!HAS_DISPLAY(dev_priv))
|
||||
return;
|
||||
|
||||
if (IS_ROCKETLAKE(dev_priv)) {
|
||||
@ -17878,6 +17872,27 @@ int intel_modeset_init_noirq(struct drm_i915_private *i915)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (i915_inject_probe_failure(i915))
|
||||
return -ENODEV;
|
||||
|
||||
if (HAS_DISPLAY(i915)) {
|
||||
ret = drm_vblank_init(&i915->drm,
|
||||
INTEL_NUM_PIPES(i915));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
intel_bios_init(i915);
|
||||
|
||||
ret = intel_vga_register(i915);
|
||||
if (ret)
|
||||
goto cleanup_bios;
|
||||
|
||||
/* FIXME: completely on the wrong abstraction layer */
|
||||
intel_power_domains_init_hw(i915, false);
|
||||
|
||||
intel_csr_ucode_init(i915);
|
||||
|
||||
i915->modeset_wq = alloc_ordered_workqueue("i915_modeset", 0);
|
||||
i915->flip_wq = alloc_workqueue("i915_flip", WQ_HIGHPRI |
|
||||
WQ_UNBOUND, WQ_UNBOUND_MAX_ACTIVE);
|
||||
@ -17886,15 +17901,15 @@ int intel_modeset_init_noirq(struct drm_i915_private *i915)
|
||||
|
||||
ret = intel_cdclk_init(i915);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto cleanup_vga_client_pw_domain_csr;
|
||||
|
||||
ret = intel_dbuf_init(i915);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto cleanup_vga_client_pw_domain_csr;
|
||||
|
||||
ret = intel_bw_init(i915);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto cleanup_vga_client_pw_domain_csr;
|
||||
|
||||
init_llist_head(&i915->atomic_helper.free_list);
|
||||
INIT_WORK(&i915->atomic_helper.free_work,
|
||||
@ -17905,10 +17920,19 @@ int intel_modeset_init_noirq(struct drm_i915_private *i915)
|
||||
intel_fbc_init(i915);
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_vga_client_pw_domain_csr:
|
||||
intel_csr_ucode_fini(i915);
|
||||
intel_power_domains_driver_remove(i915);
|
||||
intel_vga_unregister(i915);
|
||||
cleanup_bios:
|
||||
intel_bios_driver_remove(i915);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* part #2: call after irq install */
|
||||
int intel_modeset_init(struct drm_i915_private *i915)
|
||||
/* part #2: call after irq install, but before gem init */
|
||||
int intel_modeset_init_nogem(struct drm_i915_private *i915)
|
||||
{
|
||||
struct drm_device *dev = &i915->drm;
|
||||
enum pipe pipe;
|
||||
@ -17925,7 +17949,7 @@ int intel_modeset_init(struct drm_i915_private *i915)
|
||||
INTEL_NUM_PIPES(i915),
|
||||
INTEL_NUM_PIPES(i915) > 1 ? "s" : "");
|
||||
|
||||
if (HAS_DISPLAY(i915) && INTEL_DISPLAY_ENABLED(i915)) {
|
||||
if (HAS_DISPLAY(i915)) {
|
||||
for_each_pipe(i915, pipe) {
|
||||
ret = intel_crtc_init(i915, pipe);
|
||||
if (ret) {
|
||||
@ -18007,6 +18031,30 @@ int intel_modeset_init(struct drm_i915_private *i915)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* part #3: call after gem init */
|
||||
int intel_modeset_init(struct drm_i915_private *i915)
|
||||
{
|
||||
int ret;
|
||||
|
||||
intel_overlay_setup(i915);
|
||||
|
||||
if (!HAS_DISPLAY(i915))
|
||||
return 0;
|
||||
|
||||
ret = intel_fbdev_init(&i915->drm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Only enable hotplug handling once the fbdev is fully set up. */
|
||||
intel_hpd_init(i915);
|
||||
|
||||
intel_init_ipc(i915);
|
||||
|
||||
intel_psr_set_force_mode_changed(i915->psr.dp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
|
||||
{
|
||||
struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
|
||||
@ -18891,6 +18939,18 @@ void intel_modeset_driver_remove_noirq(struct drm_i915_private *i915)
|
||||
intel_fbc_cleanup_cfb(i915);
|
||||
}
|
||||
|
||||
/* part #3: call after gem init */
|
||||
void intel_modeset_driver_remove_nogem(struct drm_i915_private *i915)
|
||||
{
|
||||
intel_csr_ucode_fini(i915);
|
||||
|
||||
intel_power_domains_driver_remove(i915);
|
||||
|
||||
intel_vga_unregister(i915);
|
||||
|
||||
intel_bios_driver_remove(i915);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
|
||||
|
||||
struct intel_display_error_state {
|
||||
@ -18951,7 +19011,7 @@ intel_display_capture_error_state(struct drm_i915_private *dev_priv)
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(transcoders) != ARRAY_SIZE(error->transcoder));
|
||||
|
||||
if (!HAS_DISPLAY(dev_priv) || !INTEL_DISPLAY_ENABLED(dev_priv))
|
||||
if (!HAS_DISPLAY(dev_priv))
|
||||
return NULL;
|
||||
|
||||
error = kzalloc(sizeof(*error), GFP_ATOMIC);
|
||||
|
@ -272,8 +272,6 @@ enum dpio_phy {
|
||||
DPIO_PHY2,
|
||||
};
|
||||
|
||||
#define I915_NUM_PHYS_VLV 2
|
||||
|
||||
enum aux_ch {
|
||||
AUX_CH_A,
|
||||
AUX_CH_B,
|
||||
@ -282,6 +280,8 @@ enum aux_ch {
|
||||
AUX_CH_E, /* ICL+ */
|
||||
AUX_CH_F,
|
||||
AUX_CH_G,
|
||||
AUX_CH_H,
|
||||
AUX_CH_I,
|
||||
};
|
||||
|
||||
#define aux_ch_name(a) ((a) + 'A')
|
||||
@ -629,9 +629,11 @@ intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info,
|
||||
/* modesetting */
|
||||
void intel_modeset_init_hw(struct drm_i915_private *i915);
|
||||
int intel_modeset_init_noirq(struct drm_i915_private *i915);
|
||||
int intel_modeset_init_nogem(struct drm_i915_private *i915);
|
||||
int intel_modeset_init(struct drm_i915_private *i915);
|
||||
void intel_modeset_driver_remove(struct drm_i915_private *i915);
|
||||
void intel_modeset_driver_remove_noirq(struct drm_i915_private *i915);
|
||||
void intel_modeset_driver_remove_nogem(struct drm_i915_private *i915);
|
||||
void intel_display_resume(struct drm_device *dev);
|
||||
void intel_init_pch_refclk(struct drm_i915_private *dev_priv);
|
||||
|
||||
|
@ -601,6 +601,11 @@ static void intel_hdcp_info(struct seq_file *m,
|
||||
{
|
||||
bool hdcp_cap, hdcp2_cap;
|
||||
|
||||
if (!intel_connector->hdcp.shim) {
|
||||
seq_puts(m, "No Connector Support");
|
||||
goto out;
|
||||
}
|
||||
|
||||
hdcp_cap = intel_hdcp_capable(intel_connector);
|
||||
hdcp2_cap = intel_hdcp2_capable(intel_connector);
|
||||
|
||||
@ -612,6 +617,7 @@ static void intel_hdcp_info(struct seq_file *m,
|
||||
if (!hdcp_cap && !hdcp2_cap)
|
||||
seq_puts(m, "None");
|
||||
|
||||
out:
|
||||
seq_puts(m, "\n");
|
||||
}
|
||||
|
||||
@ -620,6 +626,7 @@ static void intel_dp_info(struct seq_file *m,
|
||||
{
|
||||
struct intel_encoder *intel_encoder = intel_attached_encoder(intel_connector);
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(intel_encoder);
|
||||
const struct drm_property_blob *edid = intel_connector->base.edid_blob_ptr;
|
||||
|
||||
seq_printf(m, "\tDPCD rev: %x\n", intel_dp->dpcd[DP_DPCD_REV]);
|
||||
seq_printf(m, "\taudio support: %s\n", yesno(intel_dp->has_audio));
|
||||
@ -627,11 +634,7 @@ static void intel_dp_info(struct seq_file *m,
|
||||
intel_panel_info(m, &intel_connector->panel);
|
||||
|
||||
drm_dp_downstream_debug(m, intel_dp->dpcd, intel_dp->downstream_ports,
|
||||
&intel_dp->aux);
|
||||
if (intel_connector->hdcp.shim) {
|
||||
seq_puts(m, "\tHDCP version: ");
|
||||
intel_hdcp_info(m, intel_connector);
|
||||
}
|
||||
edid ? edid->data : NULL, &intel_dp->aux);
|
||||
}
|
||||
|
||||
static void intel_dp_mst_info(struct seq_file *m,
|
||||
@ -649,10 +652,6 @@ static void intel_hdmi_info(struct seq_file *m,
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(intel_encoder);
|
||||
|
||||
seq_printf(m, "\taudio support: %s\n", yesno(intel_hdmi->has_audio));
|
||||
if (intel_connector->hdcp.shim) {
|
||||
seq_puts(m, "\tHDCP version: ");
|
||||
intel_hdcp_info(m, intel_connector);
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_lvds_info(struct seq_file *m,
|
||||
@ -708,6 +707,9 @@ static void intel_connector_info(struct seq_file *m,
|
||||
break;
|
||||
}
|
||||
|
||||
seq_puts(m, "\tHDCP version: ");
|
||||
intel_hdcp_info(m, intel_connector);
|
||||
|
||||
seq_printf(m, "\tmodes:\n");
|
||||
list_for_each_entry(mode, &connector->modes, head)
|
||||
intel_seq_print_mode(m, 2, mode);
|
||||
@ -1069,10 +1071,18 @@ static void drrs_status_per_crtc(struct seq_file *m,
|
||||
|
||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||
drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
bool supported = false;
|
||||
|
||||
if (connector->state->crtc != &intel_crtc->base)
|
||||
continue;
|
||||
|
||||
seq_printf(m, "%s:\n", connector->name);
|
||||
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_eDP &&
|
||||
drrs->type == SEAMLESS_DRRS_SUPPORT)
|
||||
supported = true;
|
||||
|
||||
seq_printf(m, "\tDRRS Supported: %s\n", yesno(supported));
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
|
||||
@ -1083,7 +1093,7 @@ static void drrs_status_per_crtc(struct seq_file *m,
|
||||
|
||||
mutex_lock(&drrs->mutex);
|
||||
/* DRRS Supported */
|
||||
seq_puts(m, "\tDRRS Supported: Yes\n");
|
||||
seq_puts(m, "\tDRRS Enabled: Yes\n");
|
||||
|
||||
/* disable_drrs() will make drrs->dp NULL */
|
||||
if (!drrs->dp) {
|
||||
@ -1118,7 +1128,7 @@ static void drrs_status_per_crtc(struct seq_file *m,
|
||||
mutex_unlock(&drrs->mutex);
|
||||
} else {
|
||||
/* DRRS not supported. Print the VBT parameter*/
|
||||
seq_puts(m, "\tDRRS Supported : No");
|
||||
seq_puts(m, "\tDRRS Enabled : No");
|
||||
}
|
||||
seq_puts(m, "\n");
|
||||
}
|
||||
@ -2029,10 +2039,6 @@ static int i915_hdcp_sink_capability_show(struct seq_file *m, void *data)
|
||||
if (connector->status != connector_status_connected)
|
||||
return -ENODEV;
|
||||
|
||||
/* HDCP is supported by connector */
|
||||
if (!intel_connector->hdcp.shim)
|
||||
return -EINVAL;
|
||||
|
||||
seq_printf(m, "%s:%d HDCP version: ", connector->name,
|
||||
connector->base.id);
|
||||
intel_hdcp_info(m, intel_connector);
|
||||
|
@ -5263,7 +5263,7 @@ static void tgl_bw_buddy_init(struct drm_i915_private *dev_priv)
|
||||
unsigned long abox_mask = INTEL_INFO(dev_priv)->abox_mask;
|
||||
int config, i;
|
||||
|
||||
if (IS_TGL_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_B0))
|
||||
if (IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_B0))
|
||||
/* Wa_1409767108: tgl */
|
||||
table = wa_1409767108_buddy_page_masks;
|
||||
else
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include <linux/async.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/sched/clock.h>
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
@ -223,6 +224,7 @@ struct intel_panel {
|
||||
bool util_pin_active_low; /* bxt+ */
|
||||
u8 controller; /* bxt+ only */
|
||||
struct pwm_device *pwm;
|
||||
struct pwm_state pwm_state;
|
||||
|
||||
/* DPCD backlight */
|
||||
u8 pwmgen_bit_count;
|
||||
@ -314,10 +316,12 @@ struct intel_hdcp_shim {
|
||||
|
||||
/* Enables HDCP signalling on the port */
|
||||
int (*toggle_signalling)(struct intel_digital_port *dig_port,
|
||||
enum transcoder cpu_transcoder,
|
||||
bool enable);
|
||||
|
||||
/* Ensures the link is still protected */
|
||||
bool (*check_link)(struct intel_digital_port *dig_port);
|
||||
bool (*check_link)(struct intel_digital_port *dig_port,
|
||||
struct intel_connector *connector);
|
||||
|
||||
/* Detects panel's hdcp capability. This is optional for HDMI. */
|
||||
int (*hdcp_capable)(struct intel_digital_port *dig_port,
|
||||
@ -479,8 +483,6 @@ struct intel_atomic_state {
|
||||
|
||||
bool dpll_set, modeset;
|
||||
|
||||
u8 active_pipes;
|
||||
|
||||
struct intel_shared_dpll_state shared_dpll[I915_NUM_PLLS];
|
||||
|
||||
/*
|
||||
@ -491,11 +493,6 @@ struct intel_atomic_state {
|
||||
|
||||
bool rps_interactive;
|
||||
|
||||
/*
|
||||
* active_pipes
|
||||
*/
|
||||
bool global_state_changed;
|
||||
|
||||
struct i915_sw_fence commit_ready;
|
||||
|
||||
struct llist_node freed;
|
||||
@ -1275,6 +1272,7 @@ struct intel_dp {
|
||||
u8 sink_count;
|
||||
bool link_mst;
|
||||
bool link_trained;
|
||||
bool has_hdmi_sink;
|
||||
bool has_audio;
|
||||
bool reset_link_params;
|
||||
u8 dpcd[DP_RECEIVER_CAP_SIZE];
|
||||
@ -1376,6 +1374,14 @@ struct intel_dp {
|
||||
/* Displayport compliance testing */
|
||||
struct intel_dp_compliance compliance;
|
||||
|
||||
/* Downstream facing port caps */
|
||||
struct {
|
||||
int min_tmds_clock, max_tmds_clock;
|
||||
int max_dotclock;
|
||||
u8 max_bpc;
|
||||
bool ycbcr_444_to_420;
|
||||
} dfp;
|
||||
|
||||
/* Display stream compression testing */
|
||||
bool force_dsc_en;
|
||||
|
||||
@ -1415,6 +1421,11 @@ struct intel_digital_port {
|
||||
enum phy_fia tc_phy_fia;
|
||||
u8 tc_phy_fia_idx;
|
||||
|
||||
/* protects num_hdcp_streams reference count */
|
||||
struct mutex hdcp_mutex;
|
||||
/* the number of pipes using HDCP signalling out of this port */
|
||||
unsigned int num_hdcp_streams;
|
||||
|
||||
void (*write_infoframe)(struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *crtc_state,
|
||||
unsigned int type,
|
||||
@ -1525,6 +1536,18 @@ static inline bool intel_encoder_is_dig_port(struct intel_encoder *encoder)
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool intel_encoder_is_mst(struct intel_encoder *encoder)
|
||||
{
|
||||
return encoder->type == INTEL_OUTPUT_DP_MST;
|
||||
}
|
||||
|
||||
static inline struct intel_dp_mst_encoder *
|
||||
enc_to_mst(struct intel_encoder *encoder)
|
||||
{
|
||||
return container_of(&encoder->base, struct intel_dp_mst_encoder,
|
||||
base.base);
|
||||
}
|
||||
|
||||
static inline struct intel_digital_port *
|
||||
enc_to_dig_port(struct intel_encoder *encoder)
|
||||
{
|
||||
@ -1533,6 +1556,8 @@ enc_to_dig_port(struct intel_encoder *encoder)
|
||||
if (intel_encoder_is_dig_port(intel_encoder))
|
||||
return container_of(&encoder->base, struct intel_digital_port,
|
||||
base.base);
|
||||
else if (intel_encoder_is_mst(intel_encoder))
|
||||
return enc_to_mst(encoder)->primary;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
@ -1543,13 +1568,6 @@ intel_attached_dig_port(struct intel_connector *connector)
|
||||
return enc_to_dig_port(intel_attached_encoder(connector));
|
||||
}
|
||||
|
||||
static inline struct intel_dp_mst_encoder *
|
||||
enc_to_mst(struct intel_encoder *encoder)
|
||||
{
|
||||
return container_of(&encoder->base, struct intel_dp_mst_encoder,
|
||||
base.base);
|
||||
}
|
||||
|
||||
static inline struct intel_dp *enc_to_intel_dp(struct intel_encoder *encoder)
|
||||
{
|
||||
return &enc_to_dig_port(encoder)->dp;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -17,6 +17,7 @@ struct drm_encoder;
|
||||
struct drm_i915_private;
|
||||
struct drm_modeset_acquire_ctx;
|
||||
struct drm_dp_vsc_sdp;
|
||||
struct intel_atomic_state;
|
||||
struct intel_connector;
|
||||
struct intel_crtc_state;
|
||||
struct intel_digital_port;
|
||||
@ -50,6 +51,7 @@ int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
|
||||
int intel_dp_retrain_link(struct intel_encoder *encoder,
|
||||
struct drm_modeset_acquire_ctx *ctx);
|
||||
void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
|
||||
void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp);
|
||||
void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
|
||||
const struct intel_crtc_state *crtc_state,
|
||||
bool enable);
|
||||
@ -81,6 +83,8 @@ void intel_edp_drrs_enable(struct intel_dp *intel_dp,
|
||||
const struct intel_crtc_state *crtc_state);
|
||||
void intel_edp_drrs_disable(struct intel_dp *intel_dp,
|
||||
const struct intel_crtc_state *crtc_state);
|
||||
void intel_edp_drrs_update(struct intel_dp *intel_dp,
|
||||
const struct intel_crtc_state *crtc_state);
|
||||
void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
|
||||
unsigned int frontbuffer_bits);
|
||||
void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
|
||||
@ -127,4 +131,12 @@ static inline unsigned int intel_dp_unused_lane_mask(int lane_count)
|
||||
|
||||
u32 intel_dp_mode_to_fec_clock(u32 mode_clock);
|
||||
|
||||
void intel_ddi_update_pipe(struct intel_atomic_state *state,
|
||||
struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *crtc_state,
|
||||
const struct drm_connector_state *conn_state);
|
||||
|
||||
int intel_dp_init_hdcp(struct intel_digital_port *dig_port,
|
||||
struct intel_connector *intel_connector);
|
||||
|
||||
#endif /* __INTEL_DP_H__ */
|
||||
|
703
drivers/gpu/drm/i915/display/intel_dp_hdcp.c
Normal file
703
drivers/gpu/drm/i915/display/intel_dp_hdcp.c
Normal file
@ -0,0 +1,703 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright (C) 2020 Google, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Sean Paul <seanpaul@chromium.org>
|
||||
*/
|
||||
|
||||
#include <drm/drm_dp_helper.h>
|
||||
#include <drm/drm_dp_mst_helper.h>
|
||||
#include <drm/drm_hdcp.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "intel_display_types.h"
|
||||
#include "intel_ddi.h"
|
||||
#include "intel_dp.h"
|
||||
#include "intel_hdcp.h"
|
||||
|
||||
static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout)
|
||||
{
|
||||
long ret;
|
||||
|
||||
#define C (hdcp->cp_irq_count_cached != atomic_read(&hdcp->cp_irq_count))
|
||||
ret = wait_event_interruptible_timeout(hdcp->cp_irq_queue, C,
|
||||
msecs_to_jiffies(timeout));
|
||||
|
||||
if (!ret)
|
||||
DRM_DEBUG_KMS("Timedout at waiting for CP_IRQ\n");
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
|
||||
u8 *an)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
u8 aksv[DRM_HDCP_KSV_LEN] = {};
|
||||
ssize_t dpcd_ret;
|
||||
|
||||
/* Output An first, that's easy */
|
||||
dpcd_ret = drm_dp_dpcd_write(&dig_port->dp.aux, DP_AUX_HDCP_AN,
|
||||
an, DRM_HDCP_AN_LEN);
|
||||
if (dpcd_ret != DRM_HDCP_AN_LEN) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Failed to write An over DP/AUX (%zd)\n",
|
||||
dpcd_ret);
|
||||
return dpcd_ret >= 0 ? -EIO : dpcd_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since Aksv is Oh-So-Secret, we can't access it in software. So we
|
||||
* send an empty buffer of the correct length through the DP helpers. On
|
||||
* the other side, in the transfer hook, we'll generate a flag based on
|
||||
* the destination address which will tickle the hardware to output the
|
||||
* Aksv on our behalf after the header is sent.
|
||||
*/
|
||||
dpcd_ret = drm_dp_dpcd_write(&dig_port->dp.aux, DP_AUX_HDCP_AKSV,
|
||||
aksv, DRM_HDCP_KSV_LEN);
|
||||
if (dpcd_ret != DRM_HDCP_KSV_LEN) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Failed to write Aksv over DP/AUX (%zd)\n",
|
||||
dpcd_ret);
|
||||
return dpcd_ret >= 0 ? -EIO : dpcd_ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_dp_hdcp_read_bksv(struct intel_digital_port *dig_port,
|
||||
u8 *bksv)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
ssize_t ret;
|
||||
|
||||
ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BKSV, bksv,
|
||||
DRM_HDCP_KSV_LEN);
|
||||
if (ret != DRM_HDCP_KSV_LEN) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Read Bksv from DP/AUX failed (%zd)\n", ret);
|
||||
return ret >= 0 ? -EIO : ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *dig_port,
|
||||
u8 *bstatus)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
ssize_t ret;
|
||||
|
||||
/*
|
||||
* For some reason the HDMI and DP HDCP specs call this register
|
||||
* definition by different names. In the HDMI spec, it's called BSTATUS,
|
||||
* but in DP it's called BINFO.
|
||||
*/
|
||||
ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BINFO,
|
||||
bstatus, DRM_HDCP_BSTATUS_LEN);
|
||||
if (ret != DRM_HDCP_BSTATUS_LEN) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Read bstatus from DP/AUX failed (%zd)\n", ret);
|
||||
return ret >= 0 ? -EIO : ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp_read_bcaps(struct intel_digital_port *dig_port,
|
||||
u8 *bcaps)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
ssize_t ret;
|
||||
|
||||
ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BCAPS,
|
||||
bcaps, 1);
|
||||
if (ret != 1) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Read bcaps from DP/AUX failed (%zd)\n", ret);
|
||||
return ret >= 0 ? -EIO : ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp_repeater_present(struct intel_digital_port *dig_port,
|
||||
bool *repeater_present)
|
||||
{
|
||||
ssize_t ret;
|
||||
u8 bcaps;
|
||||
|
||||
ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*repeater_present = bcaps & DP_BCAPS_REPEATER_PRESENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
|
||||
u8 *ri_prime)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
ssize_t ret;
|
||||
|
||||
ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_RI_PRIME,
|
||||
ri_prime, DRM_HDCP_RI_LEN);
|
||||
if (ret != DRM_HDCP_RI_LEN) {
|
||||
drm_dbg_kms(&i915->drm, "Read Ri' from DP/AUX failed (%zd)\n",
|
||||
ret);
|
||||
return ret >= 0 ? -EIO : ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
|
||||
bool *ksv_ready)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
ssize_t ret;
|
||||
u8 bstatus;
|
||||
|
||||
ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
|
||||
&bstatus, 1);
|
||||
if (ret != 1) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Read bstatus from DP/AUX failed (%zd)\n", ret);
|
||||
return ret >= 0 ? -EIO : ret;
|
||||
}
|
||||
*ksv_ready = bstatus & DP_BSTATUS_READY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
|
||||
int num_downstream, u8 *ksv_fifo)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
ssize_t ret;
|
||||
int i;
|
||||
|
||||
/* KSV list is read via 15 byte window (3 entries @ 5 bytes each) */
|
||||
for (i = 0; i < num_downstream; i += 3) {
|
||||
size_t len = min(num_downstream - i, 3) * DRM_HDCP_KSV_LEN;
|
||||
ret = drm_dp_dpcd_read(&dig_port->dp.aux,
|
||||
DP_AUX_HDCP_KSV_FIFO,
|
||||
ksv_fifo + i * DRM_HDCP_KSV_LEN,
|
||||
len);
|
||||
if (ret != len) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Read ksv[%d] from DP/AUX failed (%zd)\n",
|
||||
i, ret);
|
||||
return ret >= 0 ? -EIO : ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp_read_v_prime_part(struct intel_digital_port *dig_port,
|
||||
int i, u32 *part)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
ssize_t ret;
|
||||
|
||||
if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
|
||||
return -EINVAL;
|
||||
|
||||
ret = drm_dp_dpcd_read(&dig_port->dp.aux,
|
||||
DP_AUX_HDCP_V_PRIME(i), part,
|
||||
DRM_HDCP_V_PRIME_PART_LEN);
|
||||
if (ret != DRM_HDCP_V_PRIME_PART_LEN) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
|
||||
return ret >= 0 ? -EIO : ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
|
||||
enum transcoder cpu_transcoder,
|
||||
bool enable)
|
||||
{
|
||||
/* Not used for single stream DisplayPort setups */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
bool intel_dp_hdcp_check_link(struct intel_digital_port *dig_port,
|
||||
struct intel_connector *connector)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
ssize_t ret;
|
||||
u8 bstatus;
|
||||
|
||||
ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
|
||||
&bstatus, 1);
|
||||
if (ret != 1) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Read bstatus from DP/AUX failed (%zd)\n", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
return !(bstatus & (DP_BSTATUS_LINK_FAILURE | DP_BSTATUS_REAUTH_REQ));
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp_capable(struct intel_digital_port *dig_port,
|
||||
bool *hdcp_capable)
|
||||
{
|
||||
ssize_t ret;
|
||||
u8 bcaps;
|
||||
|
||||
ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*hdcp_capable = bcaps & DP_BCAPS_HDCP_CAPABLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hdcp2_dp_errata_stream_type {
|
||||
u8 msg_id;
|
||||
u8 stream_type;
|
||||
} __packed;
|
||||
|
||||
struct hdcp2_dp_msg_data {
|
||||
u8 msg_id;
|
||||
u32 offset;
|
||||
bool msg_detectable;
|
||||
u32 timeout;
|
||||
u32 timeout2; /* Added for non_paired situation */
|
||||
};
|
||||
|
||||
static const struct hdcp2_dp_msg_data hdcp2_dp_msg_data[] = {
|
||||
{ HDCP_2_2_AKE_INIT, DP_HDCP_2_2_AKE_INIT_OFFSET, false, 0, 0 },
|
||||
{ HDCP_2_2_AKE_SEND_CERT, DP_HDCP_2_2_AKE_SEND_CERT_OFFSET,
|
||||
false, HDCP_2_2_CERT_TIMEOUT_MS, 0 },
|
||||
{ HDCP_2_2_AKE_NO_STORED_KM, DP_HDCP_2_2_AKE_NO_STORED_KM_OFFSET,
|
||||
false, 0, 0 },
|
||||
{ HDCP_2_2_AKE_STORED_KM, DP_HDCP_2_2_AKE_STORED_KM_OFFSET,
|
||||
false, 0, 0 },
|
||||
{ HDCP_2_2_AKE_SEND_HPRIME, DP_HDCP_2_2_AKE_SEND_HPRIME_OFFSET,
|
||||
true, HDCP_2_2_HPRIME_PAIRED_TIMEOUT_MS,
|
||||
HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT_MS },
|
||||
{ HDCP_2_2_AKE_SEND_PAIRING_INFO,
|
||||
DP_HDCP_2_2_AKE_SEND_PAIRING_INFO_OFFSET, true,
|
||||
HDCP_2_2_PAIRING_TIMEOUT_MS, 0 },
|
||||
{ HDCP_2_2_LC_INIT, DP_HDCP_2_2_LC_INIT_OFFSET, false, 0, 0 },
|
||||
{ HDCP_2_2_LC_SEND_LPRIME, DP_HDCP_2_2_LC_SEND_LPRIME_OFFSET,
|
||||
false, HDCP_2_2_DP_LPRIME_TIMEOUT_MS, 0 },
|
||||
{ HDCP_2_2_SKE_SEND_EKS, DP_HDCP_2_2_SKE_SEND_EKS_OFFSET, false,
|
||||
0, 0 },
|
||||
{ HDCP_2_2_REP_SEND_RECVID_LIST,
|
||||
DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET, true,
|
||||
HDCP_2_2_RECVID_LIST_TIMEOUT_MS, 0 },
|
||||
{ HDCP_2_2_REP_SEND_ACK, DP_HDCP_2_2_REP_SEND_ACK_OFFSET, false,
|
||||
0, 0 },
|
||||
{ HDCP_2_2_REP_STREAM_MANAGE,
|
||||
DP_HDCP_2_2_REP_STREAM_MANAGE_OFFSET, false,
|
||||
0, 0 },
|
||||
{ HDCP_2_2_REP_STREAM_READY, DP_HDCP_2_2_REP_STREAM_READY_OFFSET,
|
||||
false, HDCP_2_2_STREAM_READY_TIMEOUT_MS, 0 },
|
||||
/* local define to shovel this through the write_2_2 interface */
|
||||
#define HDCP_2_2_ERRATA_DP_STREAM_TYPE 50
|
||||
{ HDCP_2_2_ERRATA_DP_STREAM_TYPE,
|
||||
DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET, false,
|
||||
0, 0 },
|
||||
};
|
||||
|
||||
static int
|
||||
intel_dp_hdcp2_read_rx_status(struct intel_digital_port *dig_port,
|
||||
u8 *rx_status)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
ssize_t ret;
|
||||
|
||||
ret = drm_dp_dpcd_read(&dig_port->dp.aux,
|
||||
DP_HDCP_2_2_REG_RXSTATUS_OFFSET, rx_status,
|
||||
HDCP_2_2_DP_RXSTATUS_LEN);
|
||||
if (ret != HDCP_2_2_DP_RXSTATUS_LEN) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Read bstatus from DP/AUX failed (%zd)\n", ret);
|
||||
return ret >= 0 ? -EIO : ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int hdcp2_detect_msg_availability(struct intel_digital_port *dig_port,
|
||||
u8 msg_id, bool *msg_ready)
|
||||
{
|
||||
u8 rx_status;
|
||||
int ret;
|
||||
|
||||
*msg_ready = false;
|
||||
ret = intel_dp_hdcp2_read_rx_status(dig_port, &rx_status);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (msg_id) {
|
||||
case HDCP_2_2_AKE_SEND_HPRIME:
|
||||
if (HDCP_2_2_DP_RXSTATUS_H_PRIME(rx_status))
|
||||
*msg_ready = true;
|
||||
break;
|
||||
case HDCP_2_2_AKE_SEND_PAIRING_INFO:
|
||||
if (HDCP_2_2_DP_RXSTATUS_PAIRING(rx_status))
|
||||
*msg_ready = true;
|
||||
break;
|
||||
case HDCP_2_2_REP_SEND_RECVID_LIST:
|
||||
if (HDCP_2_2_DP_RXSTATUS_READY(rx_status))
|
||||
*msg_ready = true;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Unidentified msg_id: %d\n", msg_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
intel_dp_hdcp2_wait_for_msg(struct intel_digital_port *dig_port,
|
||||
const struct hdcp2_dp_msg_data *hdcp2_msg_data)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
struct intel_dp *dp = &dig_port->dp;
|
||||
struct intel_hdcp *hdcp = &dp->attached_connector->hdcp;
|
||||
u8 msg_id = hdcp2_msg_data->msg_id;
|
||||
int ret, timeout;
|
||||
bool msg_ready = false;
|
||||
|
||||
if (msg_id == HDCP_2_2_AKE_SEND_HPRIME && !hdcp->is_paired)
|
||||
timeout = hdcp2_msg_data->timeout2;
|
||||
else
|
||||
timeout = hdcp2_msg_data->timeout;
|
||||
|
||||
/*
|
||||
* There is no way to detect the CERT, LPRIME and STREAM_READY
|
||||
* availability. So Wait for timeout and read the msg.
|
||||
*/
|
||||
if (!hdcp2_msg_data->msg_detectable) {
|
||||
mdelay(timeout);
|
||||
ret = 0;
|
||||
} else {
|
||||
/*
|
||||
* As we want to check the msg availability at timeout, Ignoring
|
||||
* the timeout at wait for CP_IRQ.
|
||||
*/
|
||||
intel_dp_hdcp_wait_for_cp_irq(hdcp, timeout);
|
||||
ret = hdcp2_detect_msg_availability(dig_port,
|
||||
msg_id, &msg_ready);
|
||||
if (!msg_ready)
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"msg_id %d, ret %d, timeout(mSec): %d\n",
|
||||
hdcp2_msg_data->msg_id, ret, timeout);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct hdcp2_dp_msg_data *get_hdcp2_dp_msg_data(u8 msg_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hdcp2_dp_msg_data); i++)
|
||||
if (hdcp2_dp_msg_data[i].msg_id == msg_id)
|
||||
return &hdcp2_dp_msg_data[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port,
|
||||
void *buf, size_t size)
|
||||
{
|
||||
struct intel_dp *dp = &dig_port->dp;
|
||||
struct intel_hdcp *hdcp = &dp->attached_connector->hdcp;
|
||||
unsigned int offset;
|
||||
u8 *byte = buf;
|
||||
ssize_t ret, bytes_to_write, len;
|
||||
const struct hdcp2_dp_msg_data *hdcp2_msg_data;
|
||||
|
||||
hdcp2_msg_data = get_hdcp2_dp_msg_data(*byte);
|
||||
if (!hdcp2_msg_data)
|
||||
return -EINVAL;
|
||||
|
||||
offset = hdcp2_msg_data->offset;
|
||||
|
||||
/* No msg_id in DP HDCP2.2 msgs */
|
||||
bytes_to_write = size - 1;
|
||||
byte++;
|
||||
|
||||
hdcp->cp_irq_count_cached = atomic_read(&hdcp->cp_irq_count);
|
||||
|
||||
while (bytes_to_write) {
|
||||
len = bytes_to_write > DP_AUX_MAX_PAYLOAD_BYTES ?
|
||||
DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_write;
|
||||
|
||||
ret = drm_dp_dpcd_write(&dig_port->dp.aux,
|
||||
offset, (void *)byte, len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
bytes_to_write -= ret;
|
||||
byte += ret;
|
||||
offset += ret;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static
|
||||
ssize_t get_receiver_id_list_size(struct intel_digital_port *dig_port)
|
||||
{
|
||||
u8 rx_info[HDCP_2_2_RXINFO_LEN];
|
||||
u32 dev_cnt;
|
||||
ssize_t ret;
|
||||
|
||||
ret = drm_dp_dpcd_read(&dig_port->dp.aux,
|
||||
DP_HDCP_2_2_REG_RXINFO_OFFSET,
|
||||
(void *)rx_info, HDCP_2_2_RXINFO_LEN);
|
||||
if (ret != HDCP_2_2_RXINFO_LEN)
|
||||
return ret >= 0 ? -EIO : ret;
|
||||
|
||||
dev_cnt = (HDCP_2_2_DEV_COUNT_HI(rx_info[0]) << 4 |
|
||||
HDCP_2_2_DEV_COUNT_LO(rx_info[1]));
|
||||
|
||||
if (dev_cnt > HDCP_2_2_MAX_DEVICE_COUNT)
|
||||
dev_cnt = HDCP_2_2_MAX_DEVICE_COUNT;
|
||||
|
||||
ret = sizeof(struct hdcp2_rep_send_receiverid_list) -
|
||||
HDCP_2_2_RECEIVER_IDS_MAX_LEN +
|
||||
(dev_cnt * HDCP_2_2_RECEIVER_ID_LEN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port,
|
||||
u8 msg_id, void *buf, size_t size)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
unsigned int offset;
|
||||
u8 *byte = buf;
|
||||
ssize_t ret, bytes_to_recv, len;
|
||||
const struct hdcp2_dp_msg_data *hdcp2_msg_data;
|
||||
|
||||
hdcp2_msg_data = get_hdcp2_dp_msg_data(msg_id);
|
||||
if (!hdcp2_msg_data)
|
||||
return -EINVAL;
|
||||
offset = hdcp2_msg_data->offset;
|
||||
|
||||
ret = intel_dp_hdcp2_wait_for_msg(dig_port, hdcp2_msg_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (msg_id == HDCP_2_2_REP_SEND_RECVID_LIST) {
|
||||
ret = get_receiver_id_list_size(dig_port);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
size = ret;
|
||||
}
|
||||
bytes_to_recv = size - 1;
|
||||
|
||||
/* DP adaptation msgs has no msg_id */
|
||||
byte++;
|
||||
|
||||
while (bytes_to_recv) {
|
||||
len = bytes_to_recv > DP_AUX_MAX_PAYLOAD_BYTES ?
|
||||
DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_recv;
|
||||
|
||||
ret = drm_dp_dpcd_read(&dig_port->dp.aux, offset,
|
||||
(void *)byte, len);
|
||||
if (ret < 0) {
|
||||
drm_dbg_kms(&i915->drm, "msg_id %d, ret %zd\n",
|
||||
msg_id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bytes_to_recv -= ret;
|
||||
byte += ret;
|
||||
offset += ret;
|
||||
}
|
||||
byte = buf;
|
||||
*byte = msg_id;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp2_config_stream_type(struct intel_digital_port *dig_port,
|
||||
bool is_repeater, u8 content_type)
|
||||
{
|
||||
int ret;
|
||||
struct hdcp2_dp_errata_stream_type stream_type_msg;
|
||||
|
||||
if (is_repeater)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Errata for DP: As Stream type is used for encryption, Receiver
|
||||
* should be communicated with stream type for the decryption of the
|
||||
* content.
|
||||
* Repeater will be communicated with stream type as a part of it's
|
||||
* auth later in time.
|
||||
*/
|
||||
stream_type_msg.msg_id = HDCP_2_2_ERRATA_DP_STREAM_TYPE;
|
||||
stream_type_msg.stream_type = content_type;
|
||||
|
||||
ret = intel_dp_hdcp2_write_msg(dig_port, &stream_type_msg,
|
||||
sizeof(stream_type_msg));
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp2_check_link(struct intel_digital_port *dig_port)
|
||||
{
|
||||
u8 rx_status;
|
||||
int ret;
|
||||
|
||||
ret = intel_dp_hdcp2_read_rx_status(dig_port, &rx_status);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(rx_status))
|
||||
ret = HDCP_REAUTH_REQUEST;
|
||||
else if (HDCP_2_2_DP_RXSTATUS_LINK_FAILED(rx_status))
|
||||
ret = HDCP_LINK_INTEGRITY_FAILURE;
|
||||
else if (HDCP_2_2_DP_RXSTATUS_READY(rx_status))
|
||||
ret = HDCP_TOPOLOGY_CHANGE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port,
|
||||
bool *capable)
|
||||
{
|
||||
u8 rx_caps[3];
|
||||
int ret;
|
||||
|
||||
*capable = false;
|
||||
ret = drm_dp_dpcd_read(&dig_port->dp.aux,
|
||||
DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
|
||||
rx_caps, HDCP_2_2_RXCAPS_LEN);
|
||||
if (ret != HDCP_2_2_RXCAPS_LEN)
|
||||
return ret >= 0 ? -EIO : ret;
|
||||
|
||||
if (rx_caps[0] == HDCP_2_2_RX_CAPS_VERSION_VAL &&
|
||||
HDCP_2_2_DP_HDCP_CAPABLE(rx_caps[2]))
|
||||
*capable = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
|
||||
.write_an_aksv = intel_dp_hdcp_write_an_aksv,
|
||||
.read_bksv = intel_dp_hdcp_read_bksv,
|
||||
.read_bstatus = intel_dp_hdcp_read_bstatus,
|
||||
.repeater_present = intel_dp_hdcp_repeater_present,
|
||||
.read_ri_prime = intel_dp_hdcp_read_ri_prime,
|
||||
.read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
|
||||
.read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
|
||||
.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
|
||||
.toggle_signalling = intel_dp_hdcp_toggle_signalling,
|
||||
.check_link = intel_dp_hdcp_check_link,
|
||||
.hdcp_capable = intel_dp_hdcp_capable,
|
||||
.write_2_2_msg = intel_dp_hdcp2_write_msg,
|
||||
.read_2_2_msg = intel_dp_hdcp2_read_msg,
|
||||
.config_stream_type = intel_dp_hdcp2_config_stream_type,
|
||||
.check_2_2_link = intel_dp_hdcp2_check_link,
|
||||
.hdcp_2_2_capable = intel_dp_hdcp2_capable,
|
||||
.protocol = HDCP_PROTOCOL_DP,
|
||||
};
|
||||
|
||||
static int
|
||||
intel_dp_mst_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
|
||||
enum transcoder cpu_transcoder,
|
||||
bool enable)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
int ret;
|
||||
|
||||
if (!enable)
|
||||
usleep_range(6, 60); /* Bspec says >= 6us */
|
||||
|
||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base,
|
||||
cpu_transcoder, enable);
|
||||
if (ret)
|
||||
drm_dbg_kms(&i915->drm, "%s HDCP signalling failed (%d)\n",
|
||||
enable ? "Enable" : "Disable", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
bool intel_dp_mst_hdcp_check_link(struct intel_digital_port *dig_port,
|
||||
struct intel_connector *connector)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
struct intel_dp *intel_dp = &dig_port->dp;
|
||||
struct drm_dp_query_stream_enc_status_ack_reply reply;
|
||||
int ret;
|
||||
|
||||
if (!intel_dp_hdcp_check_link(dig_port, connector))
|
||||
return false;
|
||||
|
||||
ret = drm_dp_send_query_stream_enc_status(&intel_dp->mst_mgr,
|
||||
connector->port, &reply);
|
||||
if (ret) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[CONNECTOR:%d:%s] failed QSES ret=%d\n",
|
||||
connector->base.base.id, connector->base.name, ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
return reply.auth_completed && reply.encryption_enabled;
|
||||
}
|
||||
|
||||
static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
|
||||
.write_an_aksv = intel_dp_hdcp_write_an_aksv,
|
||||
.read_bksv = intel_dp_hdcp_read_bksv,
|
||||
.read_bstatus = intel_dp_hdcp_read_bstatus,
|
||||
.repeater_present = intel_dp_hdcp_repeater_present,
|
||||
.read_ri_prime = intel_dp_hdcp_read_ri_prime,
|
||||
.read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
|
||||
.read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
|
||||
.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
|
||||
.toggle_signalling = intel_dp_mst_hdcp_toggle_signalling,
|
||||
.check_link = intel_dp_mst_hdcp_check_link,
|
||||
.hdcp_capable = intel_dp_hdcp_capable,
|
||||
|
||||
.protocol = HDCP_PROTOCOL_DP,
|
||||
};
|
||||
|
||||
int intel_dp_init_hdcp(struct intel_digital_port *dig_port,
|
||||
struct intel_connector *intel_connector)
|
||||
{
|
||||
struct drm_device *dev = intel_connector->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_encoder *intel_encoder = &dig_port->base;
|
||||
enum port port = intel_encoder->port;
|
||||
struct intel_dp *intel_dp = &dig_port->dp;
|
||||
|
||||
if (!is_hdcp_supported(dev_priv, port))
|
||||
return 0;
|
||||
|
||||
if (intel_connector->mst_port)
|
||||
return intel_hdcp_init(intel_connector, port,
|
||||
&intel_dp_mst_hdcp_shim);
|
||||
else if (!intel_dp_is_edp(intel_dp))
|
||||
return intel_hdcp_init(intel_connector, port,
|
||||
&intel_dp_hdcp_shim);
|
||||
|
||||
return 0;
|
||||
}
|
@ -37,6 +37,7 @@
|
||||
#include "intel_dp.h"
|
||||
#include "intel_dp_mst.h"
|
||||
#include "intel_dpio_phy.h"
|
||||
#include "intel_hdcp.h"
|
||||
|
||||
static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *crtc_state,
|
||||
@ -352,6 +353,8 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state,
|
||||
drm_dbg_kms(&i915->drm, "active links %d\n",
|
||||
intel_dp->active_mst_links);
|
||||
|
||||
intel_hdcp_disable(intel_mst->connector);
|
||||
|
||||
drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, connector->port);
|
||||
|
||||
ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
|
||||
@ -556,6 +559,13 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
|
||||
|
||||
if (pipe_config->has_audio)
|
||||
intel_audio_codec_enable(encoder, pipe_config, conn_state);
|
||||
|
||||
/* Enable hdcp if it's desired */
|
||||
if (conn_state->content_protection ==
|
||||
DRM_MODE_CONTENT_PROTECTION_DESIRED)
|
||||
intel_hdcp_enable(to_intel_connector(conn_state->connector),
|
||||
pipe_config->cpu_transcoder,
|
||||
(u8)conn_state->hdcp_content_type);
|
||||
}
|
||||
|
||||
static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
|
||||
@ -709,9 +719,13 @@ static int
|
||||
intel_dp_mst_detect(struct drm_connector *connector,
|
||||
struct drm_modeset_acquire_ctx *ctx, bool force)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(connector->dev);
|
||||
struct intel_connector *intel_connector = to_intel_connector(connector);
|
||||
struct intel_dp *intel_dp = intel_connector->mst_port;
|
||||
|
||||
if (!INTEL_DISPLAY_ENABLED(i915))
|
||||
return connector_status_disconnected;
|
||||
|
||||
if (drm_connector_is_unregistered(connector))
|
||||
return connector_status_disconnected;
|
||||
|
||||
@ -799,6 +813,14 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
|
||||
intel_attach_force_audio_property(connector);
|
||||
intel_attach_broadcast_rgb_property(connector);
|
||||
|
||||
|
||||
/* TODO: Figure out how to make HDCP work on GEN12+ */
|
||||
if (INTEL_GEN(dev_priv) < 12) {
|
||||
ret = intel_dp_init_hdcp(dig_port, intel_connector);
|
||||
if (ret)
|
||||
DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Reuse the prop from the SST connector because we're
|
||||
* not allowed to create new props after device registration.
|
||||
@ -865,6 +887,7 @@ intel_dp_create_fake_mst_encoder(struct intel_digital_port *dig_port, enum pipe
|
||||
intel_encoder->compute_config_late = intel_dp_mst_compute_config_late;
|
||||
intel_encoder->disable = intel_mst_disable_dp;
|
||||
intel_encoder->post_disable = intel_mst_post_disable_dp;
|
||||
intel_encoder->update_pipe = intel_ddi_update_pipe;
|
||||
intel_encoder->pre_pll_enable = intel_mst_pre_pll_enable_dp;
|
||||
intel_encoder->pre_enable = intel_mst_pre_enable_dp;
|
||||
intel_encoder->enable = intel_mst_enable_dp;
|
||||
|
@ -147,6 +147,18 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv,
|
||||
pll->info->name, onoff(state), onoff(cur_state));
|
||||
}
|
||||
|
||||
static i915_reg_t
|
||||
intel_combo_pll_enable_reg(struct drm_i915_private *i915,
|
||||
struct intel_shared_dpll *pll)
|
||||
{
|
||||
|
||||
if (IS_ELKHARTLAKE(i915) && (pll->info->id == DPLL_ID_EHL_DPLL4))
|
||||
return MG_PLL_ENABLE(0);
|
||||
|
||||
return CNL_DPLL_ENABLE(pll->info->id);
|
||||
|
||||
|
||||
}
|
||||
/**
|
||||
* intel_prepare_shared_dpll - call a dpll's prepare hook
|
||||
* @crtc_state: CRTC, and its state, which has a shared dpll
|
||||
@ -3842,12 +3854,7 @@ static bool combo_pll_get_hw_state(struct drm_i915_private *dev_priv,
|
||||
struct intel_shared_dpll *pll,
|
||||
struct intel_dpll_hw_state *hw_state)
|
||||
{
|
||||
i915_reg_t enable_reg = CNL_DPLL_ENABLE(pll->info->id);
|
||||
|
||||
if (IS_ELKHARTLAKE(dev_priv) &&
|
||||
pll->info->id == DPLL_ID_EHL_DPLL4) {
|
||||
enable_reg = MG_PLL_ENABLE(0);
|
||||
}
|
||||
i915_reg_t enable_reg = intel_combo_pll_enable_reg(dev_priv, pll);
|
||||
|
||||
return icl_pll_get_hw_state(dev_priv, pll, hw_state, enable_reg);
|
||||
}
|
||||
@ -4045,11 +4052,10 @@ static void icl_pll_enable(struct drm_i915_private *dev_priv,
|
||||
static void combo_pll_enable(struct drm_i915_private *dev_priv,
|
||||
struct intel_shared_dpll *pll)
|
||||
{
|
||||
i915_reg_t enable_reg = CNL_DPLL_ENABLE(pll->info->id);
|
||||
i915_reg_t enable_reg = intel_combo_pll_enable_reg(dev_priv, pll);
|
||||
|
||||
if (IS_ELKHARTLAKE(dev_priv) &&
|
||||
pll->info->id == DPLL_ID_EHL_DPLL4) {
|
||||
enable_reg = MG_PLL_ENABLE(0);
|
||||
|
||||
/*
|
||||
* We need to disable DC states when this DPLL is enabled.
|
||||
@ -4157,19 +4163,14 @@ static void icl_pll_disable(struct drm_i915_private *dev_priv,
|
||||
static void combo_pll_disable(struct drm_i915_private *dev_priv,
|
||||
struct intel_shared_dpll *pll)
|
||||
{
|
||||
i915_reg_t enable_reg = CNL_DPLL_ENABLE(pll->info->id);
|
||||
|
||||
if (IS_ELKHARTLAKE(dev_priv) &&
|
||||
pll->info->id == DPLL_ID_EHL_DPLL4) {
|
||||
enable_reg = MG_PLL_ENABLE(0);
|
||||
icl_pll_disable(dev_priv, pll, enable_reg);
|
||||
|
||||
intel_display_power_put(dev_priv, POWER_DOMAIN_DPLL_DC_OFF,
|
||||
pll->wakeref);
|
||||
return;
|
||||
}
|
||||
i915_reg_t enable_reg = intel_combo_pll_enable_reg(dev_priv, pll);
|
||||
|
||||
icl_pll_disable(dev_priv, pll, enable_reg);
|
||||
|
||||
if (IS_ELKHARTLAKE(dev_priv) &&
|
||||
pll->info->id == DPLL_ID_EHL_DPLL4)
|
||||
intel_display_power_put(dev_priv, POWER_DOMAIN_DPLL_DC_OFF,
|
||||
pll->wakeref);
|
||||
}
|
||||
|
||||
static void tbt_pll_disable(struct drm_i915_private *dev_priv,
|
||||
|
@ -313,9 +313,15 @@ static void intel_dvo_pre_enable(struct intel_atomic_state *state,
|
||||
static enum drm_connector_status
|
||||
intel_dvo_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(connector->dev);
|
||||
struct intel_dvo *intel_dvo = intel_attached_dvo(to_intel_connector(connector));
|
||||
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
|
||||
connector->base.id, connector->name);
|
||||
|
||||
if (!INTEL_DISPLAY_ENABLED(i915))
|
||||
return connector_status_disconnected;
|
||||
|
||||
return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
|
||||
}
|
||||
|
||||
|
@ -451,8 +451,7 @@ int intel_fbdev_init(struct drm_device *dev)
|
||||
struct intel_fbdev *ifbdev;
|
||||
int ret;
|
||||
|
||||
if (drm_WARN_ON(dev, !HAS_DISPLAY(dev_priv) ||
|
||||
!INTEL_DISPLAY_ENABLED(dev_priv)))
|
||||
if (drm_WARN_ON(dev, !HAS_DISPLAY(dev_priv)))
|
||||
return -ENODEV;
|
||||
|
||||
ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
|
||||
|
@ -834,7 +834,7 @@ int intel_gmbus_setup(struct drm_i915_private *dev_priv)
|
||||
unsigned int pin;
|
||||
int ret;
|
||||
|
||||
if (!HAS_DISPLAY(dev_priv) || !INTEL_DISPLAY_ENABLED(dev_priv))
|
||||
if (!HAS_DISPLAY(dev_priv))
|
||||
return 0;
|
||||
|
||||
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
|
||||
|
@ -148,9 +148,8 @@ static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *dig_port,
|
||||
|
||||
static bool hdcp_key_loadable(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct i915_power_domains *power_domains = &dev_priv->power_domains;
|
||||
struct i915_power_well *power_well;
|
||||
enum i915_power_well_id id;
|
||||
intel_wakeref_t wakeref;
|
||||
bool enabled = false;
|
||||
|
||||
/*
|
||||
@ -162,17 +161,9 @@ static bool hdcp_key_loadable(struct drm_i915_private *dev_priv)
|
||||
else
|
||||
id = SKL_DISP_PW_1;
|
||||
|
||||
mutex_lock(&power_domains->lock);
|
||||
|
||||
/* PG1 (power well #1) needs to be enabled */
|
||||
for_each_power_well(dev_priv, power_well) {
|
||||
if (power_well->desc->id == id) {
|
||||
enabled = power_well->desc->ops->is_enabled(dev_priv,
|
||||
power_well);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&power_domains->lock);
|
||||
with_intel_runtime_pm(&dev_priv->runtime_pm, wakeref)
|
||||
enabled = intel_display_power_well_is_enabled(dev_priv, id);
|
||||
|
||||
/*
|
||||
* Another req for hdcp key loadability is enabled state of pll for
|
||||
@ -713,7 +704,7 @@ static int intel_hdcp_auth(struct intel_connector *connector)
|
||||
intel_de_write(dev_priv, HDCP_REP_CTL,
|
||||
intel_hdcp_get_repeater_ctl(dev_priv, cpu_transcoder, port));
|
||||
|
||||
ret = shim->toggle_signalling(dig_port, true);
|
||||
ret = shim->toggle_signalling(dig_port, cpu_transcoder, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -801,6 +792,19 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
|
||||
drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being disabled...\n",
|
||||
connector->base.name, connector->base.base.id);
|
||||
|
||||
/*
|
||||
* If there are other connectors on this port using HDCP, don't disable
|
||||
* it. Instead, toggle the HDCP signalling off on that particular
|
||||
* connector/pipe and exit.
|
||||
*/
|
||||
if (dig_port->num_hdcp_streams > 0) {
|
||||
ret = hdcp->shim->toggle_signalling(dig_port,
|
||||
cpu_transcoder, false);
|
||||
if (ret)
|
||||
DRM_ERROR("Failed to disable HDCP signalling\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
hdcp->hdcp_encrypted = false;
|
||||
intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder, port), 0);
|
||||
if (intel_de_wait_for_clear(dev_priv,
|
||||
@ -816,7 +820,7 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
|
||||
intel_de_write(dev_priv, HDCP_REP_CTL,
|
||||
intel_de_read(dev_priv, HDCP_REP_CTL) & ~repeater_ctl);
|
||||
|
||||
ret = hdcp->shim->toggle_signalling(dig_port, false);
|
||||
ret = hdcp->shim->toggle_signalling(dig_port, cpu_transcoder, false);
|
||||
if (ret) {
|
||||
drm_err(&dev_priv->drm, "Failed to disable HDCP signalling\n");
|
||||
return ret;
|
||||
@ -876,6 +880,34 @@ static struct intel_connector *intel_hdcp_to_connector(struct intel_hdcp *hdcp)
|
||||
return container_of(hdcp, struct intel_connector, hdcp);
|
||||
}
|
||||
|
||||
static void intel_hdcp_update_value(struct intel_connector *connector,
|
||||
u64 value, bool update_property)
|
||||
{
|
||||
struct drm_device *dev = connector->base.dev;
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
|
||||
drm_WARN_ON(connector->base.dev, !mutex_is_locked(&hdcp->mutex));
|
||||
|
||||
if (hdcp->value == value)
|
||||
return;
|
||||
|
||||
drm_WARN_ON(dev, !mutex_is_locked(&dig_port->hdcp_mutex));
|
||||
|
||||
if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
|
||||
if (!drm_WARN_ON(dev, dig_port->num_hdcp_streams == 0))
|
||||
dig_port->num_hdcp_streams--;
|
||||
} else if (value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
|
||||
dig_port->num_hdcp_streams++;
|
||||
}
|
||||
|
||||
hdcp->value = value;
|
||||
if (update_property) {
|
||||
drm_connector_get(&connector->base);
|
||||
schedule_work(&hdcp->prop_work);
|
||||
}
|
||||
}
|
||||
|
||||
/* Implements Part 3 of the HDCP authorization procedure */
|
||||
static int intel_hdcp_check_link(struct intel_connector *connector)
|
||||
{
|
||||
@ -887,6 +919,8 @@ static int intel_hdcp_check_link(struct intel_connector *connector)
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&hdcp->mutex);
|
||||
mutex_lock(&dig_port->hdcp_mutex);
|
||||
|
||||
cpu_transcoder = hdcp->cpu_transcoder;
|
||||
|
||||
/* Check_link valid only when HDCP1.4 is enabled */
|
||||
@ -903,15 +937,16 @@ static int intel_hdcp_check_link(struct intel_connector *connector)
|
||||
connector->base.name, connector->base.base.id,
|
||||
intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port)));
|
||||
ret = -ENXIO;
|
||||
hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
|
||||
schedule_work(&hdcp->prop_work);
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_DESIRED,
|
||||
true);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hdcp->shim->check_link(dig_port)) {
|
||||
if (hdcp->shim->check_link(dig_port, connector)) {
|
||||
if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
|
||||
hdcp->value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
|
||||
schedule_work(&hdcp->prop_work);
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_ENABLED, true);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
@ -923,20 +958,23 @@ static int intel_hdcp_check_link(struct intel_connector *connector)
|
||||
ret = _intel_hdcp_disable(connector);
|
||||
if (ret) {
|
||||
drm_err(&dev_priv->drm, "Failed to disable hdcp (%d)\n", ret);
|
||||
hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
|
||||
schedule_work(&hdcp->prop_work);
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_DESIRED,
|
||||
true);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = _intel_hdcp_enable(connector);
|
||||
if (ret) {
|
||||
drm_err(&dev_priv->drm, "Failed to enable hdcp (%d)\n", ret);
|
||||
hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
|
||||
schedule_work(&hdcp->prop_work);
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_DESIRED,
|
||||
true);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&dig_port->hdcp_mutex);
|
||||
mutex_unlock(&hdcp->mutex);
|
||||
return ret;
|
||||
}
|
||||
@ -962,6 +1000,8 @@ static void intel_hdcp_prop_work(struct work_struct *work)
|
||||
|
||||
mutex_unlock(&hdcp->mutex);
|
||||
drm_modeset_unlock(&dev_priv->drm.mode_config.connection_mutex);
|
||||
|
||||
drm_connector_put(&connector->base);
|
||||
}
|
||||
|
||||
bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port)
|
||||
@ -1600,7 +1640,8 @@ static int hdcp2_enable_encryption(struct intel_connector *connector)
|
||||
intel_de_read(dev_priv, HDCP2_STATUS(dev_priv, cpu_transcoder, port)) &
|
||||
LINK_ENCRYPTION_STATUS);
|
||||
if (hdcp->shim->toggle_signalling) {
|
||||
ret = hdcp->shim->toggle_signalling(dig_port, true);
|
||||
ret = hdcp->shim->toggle_signalling(dig_port, cpu_transcoder,
|
||||
true);
|
||||
if (ret) {
|
||||
drm_err(&dev_priv->drm,
|
||||
"Failed to enable HDCP signalling. %d\n",
|
||||
@ -1650,7 +1691,8 @@ static int hdcp2_disable_encryption(struct intel_connector *connector)
|
||||
drm_dbg_kms(&dev_priv->drm, "Disable Encryption Timedout");
|
||||
|
||||
if (hdcp->shim->toggle_signalling) {
|
||||
ret = hdcp->shim->toggle_signalling(dig_port, false);
|
||||
ret = hdcp->shim->toggle_signalling(dig_port, cpu_transcoder,
|
||||
false);
|
||||
if (ret) {
|
||||
drm_err(&dev_priv->drm,
|
||||
"Failed to disable HDCP signalling. %d\n",
|
||||
@ -1766,16 +1808,18 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
|
||||
"HDCP2.2 link stopped the encryption, %x\n",
|
||||
intel_de_read(dev_priv, HDCP2_STATUS(dev_priv, cpu_transcoder, port)));
|
||||
ret = -ENXIO;
|
||||
hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
|
||||
schedule_work(&hdcp->prop_work);
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_DESIRED,
|
||||
true);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = hdcp->shim->check_2_2_link(dig_port);
|
||||
if (ret == HDCP_LINK_PROTECTED) {
|
||||
if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
|
||||
hdcp->value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
|
||||
schedule_work(&hdcp->prop_work);
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_ENABLED,
|
||||
true);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
@ -1788,8 +1832,9 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
|
||||
"HDCP2.2 Downstream topology change\n");
|
||||
ret = hdcp2_authenticate_repeater_topology(connector);
|
||||
if (!ret) {
|
||||
hdcp->value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
|
||||
schedule_work(&hdcp->prop_work);
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_ENABLED,
|
||||
true);
|
||||
goto out;
|
||||
}
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
@ -1807,8 +1852,8 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
|
||||
drm_err(&dev_priv->drm,
|
||||
"[%s:%d] Failed to disable hdcp2.2 (%d)\n",
|
||||
connector->base.name, connector->base.base.id, ret);
|
||||
hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
|
||||
schedule_work(&hdcp->prop_work);
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_DESIRED, true);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1818,8 +1863,9 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
|
||||
"[%s:%d] Failed to enable hdcp2.2 (%d)\n",
|
||||
connector->base.name, connector->base.base.id,
|
||||
ret);
|
||||
hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
|
||||
schedule_work(&hdcp->prop_work);
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_DESIRED,
|
||||
true);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1835,6 +1881,9 @@ static void intel_hdcp_check_work(struct work_struct *work)
|
||||
check_work);
|
||||
struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
|
||||
|
||||
if (drm_connector_is_unregistered(&connector->base))
|
||||
return;
|
||||
|
||||
if (!intel_hdcp2_check_link(connector))
|
||||
schedule_delayed_work(&hdcp->check_work,
|
||||
DRM_HDCP2_CHECK_PERIOD_MS);
|
||||
@ -1896,6 +1945,7 @@ static enum mei_fw_tc intel_get_mei_fw_tc(enum transcoder cpu_transcoder)
|
||||
}
|
||||
|
||||
static int initialize_hdcp_port_data(struct intel_connector *connector,
|
||||
enum port port,
|
||||
const struct intel_hdcp_shim *shim)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||
@ -1903,8 +1953,7 @@ static int initialize_hdcp_port_data(struct intel_connector *connector,
|
||||
struct hdcp_port_data *data = &hdcp->port_data;
|
||||
|
||||
if (INTEL_GEN(dev_priv) < 12)
|
||||
data->fw_ddi =
|
||||
intel_get_mei_fw_ddi_index(intel_attached_encoder(connector)->port);
|
||||
data->fw_ddi = intel_get_mei_fw_ddi_index(port);
|
||||
else
|
||||
/*
|
||||
* As per ME FW API expectation, for GEN 12+, fw_ddi is filled
|
||||
@ -1974,14 +2023,14 @@ void intel_hdcp_component_init(struct drm_i915_private *dev_priv)
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_hdcp2_init(struct intel_connector *connector,
|
||||
static void intel_hdcp2_init(struct intel_connector *connector, enum port port,
|
||||
const struct intel_hdcp_shim *shim)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
int ret;
|
||||
|
||||
ret = initialize_hdcp_port_data(connector, shim);
|
||||
ret = initialize_hdcp_port_data(connector, port, shim);
|
||||
if (ret) {
|
||||
drm_dbg_kms(&i915->drm, "Mei hdcp data init failed\n");
|
||||
return;
|
||||
@ -1991,6 +2040,7 @@ static void intel_hdcp2_init(struct intel_connector *connector,
|
||||
}
|
||||
|
||||
int intel_hdcp_init(struct intel_connector *connector,
|
||||
enum port port,
|
||||
const struct intel_hdcp_shim *shim)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||
@ -2000,8 +2050,8 @@ int intel_hdcp_init(struct intel_connector *connector,
|
||||
if (!shim)
|
||||
return -EINVAL;
|
||||
|
||||
if (is_hdcp2_supported(dev_priv))
|
||||
intel_hdcp2_init(connector, shim);
|
||||
if (is_hdcp2_supported(dev_priv) && !connector->mst_port)
|
||||
intel_hdcp2_init(connector, port, shim);
|
||||
|
||||
ret =
|
||||
drm_connector_attach_content_protection_property(&connector->base,
|
||||
@ -2025,6 +2075,7 @@ int intel_hdcp_enable(struct intel_connector *connector,
|
||||
enum transcoder cpu_transcoder, u8 content_type)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
unsigned long check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
|
||||
int ret = -EINVAL;
|
||||
@ -2033,14 +2084,14 @@ int intel_hdcp_enable(struct intel_connector *connector,
|
||||
return -ENOENT;
|
||||
|
||||
mutex_lock(&hdcp->mutex);
|
||||
mutex_lock(&dig_port->hdcp_mutex);
|
||||
drm_WARN_ON(&dev_priv->drm,
|
||||
hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED);
|
||||
hdcp->content_type = content_type;
|
||||
hdcp->cpu_transcoder = cpu_transcoder;
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 12) {
|
||||
hdcp->cpu_transcoder = cpu_transcoder;
|
||||
if (INTEL_GEN(dev_priv) >= 12)
|
||||
hdcp->port_data.fw_tc = intel_get_mei_fw_tc(cpu_transcoder);
|
||||
}
|
||||
|
||||
/*
|
||||
* Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
|
||||
@ -2063,16 +2114,19 @@ int intel_hdcp_enable(struct intel_connector *connector,
|
||||
|
||||
if (!ret) {
|
||||
schedule_delayed_work(&hdcp->check_work, check_link_interval);
|
||||
hdcp->value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
|
||||
schedule_work(&hdcp->prop_work);
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_ENABLED,
|
||||
true);
|
||||
}
|
||||
|
||||
mutex_unlock(&dig_port->hdcp_mutex);
|
||||
mutex_unlock(&hdcp->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int intel_hdcp_disable(struct intel_connector *connector)
|
||||
{
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
int ret = 0;
|
||||
|
||||
@ -2080,15 +2134,20 @@ int intel_hdcp_disable(struct intel_connector *connector)
|
||||
return -ENOENT;
|
||||
|
||||
mutex_lock(&hdcp->mutex);
|
||||
mutex_lock(&dig_port->hdcp_mutex);
|
||||
|
||||
if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
|
||||
hdcp->value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
|
||||
if (hdcp->hdcp2_encrypted)
|
||||
ret = _intel_hdcp2_disable(connector);
|
||||
else if (hdcp->hdcp_encrypted)
|
||||
ret = _intel_hdcp_disable(connector);
|
||||
}
|
||||
if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
|
||||
goto out;
|
||||
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_UNDESIRED, false);
|
||||
if (hdcp->hdcp2_encrypted)
|
||||
ret = _intel_hdcp2_disable(connector);
|
||||
else if (hdcp->hdcp_encrypted)
|
||||
ret = _intel_hdcp_disable(connector);
|
||||
|
||||
out:
|
||||
mutex_unlock(&dig_port->hdcp_mutex);
|
||||
mutex_unlock(&hdcp->mutex);
|
||||
cancel_delayed_work_sync(&hdcp->check_work);
|
||||
return ret;
|
||||
@ -2102,11 +2161,15 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state,
|
||||
struct intel_connector *connector =
|
||||
to_intel_connector(conn_state->connector);
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
bool content_protection_type_changed =
|
||||
bool content_protection_type_changed, desired_and_not_enabled = false;
|
||||
|
||||
if (!connector->hdcp.shim)
|
||||
return;
|
||||
|
||||
content_protection_type_changed =
|
||||
(conn_state->hdcp_content_type != hdcp->content_type &&
|
||||
conn_state->content_protection !=
|
||||
DRM_MODE_CONTENT_PROTECTION_UNDESIRED);
|
||||
bool desired_and_not_enabled = false;
|
||||
|
||||
/*
|
||||
* During the HDCP encryption session if Type change is requested,
|
||||
@ -2159,12 +2222,39 @@ void intel_hdcp_component_fini(struct drm_i915_private *dev_priv)
|
||||
|
||||
void intel_hdcp_cleanup(struct intel_connector *connector)
|
||||
{
|
||||
if (!connector->hdcp.shim)
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
|
||||
if (!hdcp->shim)
|
||||
return;
|
||||
|
||||
mutex_lock(&connector->hdcp.mutex);
|
||||
kfree(connector->hdcp.port_data.streams);
|
||||
mutex_unlock(&connector->hdcp.mutex);
|
||||
/*
|
||||
* If the connector is registered, it's possible userspace could kick
|
||||
* off another HDCP enable, which would re-spawn the workers.
|
||||
*/
|
||||
drm_WARN_ON(connector->base.dev,
|
||||
connector->base.registration_state == DRM_CONNECTOR_REGISTERED);
|
||||
|
||||
/*
|
||||
* Now that the connector is not registered, check_work won't be run,
|
||||
* but cancel any outstanding instances of it
|
||||
*/
|
||||
cancel_delayed_work_sync(&hdcp->check_work);
|
||||
|
||||
/*
|
||||
* We don't cancel prop_work in the same way as check_work since it
|
||||
* requires connection_mutex which could be held while calling this
|
||||
* function. Instead, we rely on the connector references grabbed before
|
||||
* scheduling prop_work to ensure the connector is alive when prop_work
|
||||
* is run. So if we're in the destroy path (which is where this
|
||||
* function should be called), we're "guaranteed" that prop_work is not
|
||||
* active (tl;dr This Should Never Happen).
|
||||
*/
|
||||
drm_WARN_ON(connector->base.dev, work_pending(&hdcp->prop_work));
|
||||
|
||||
mutex_lock(&hdcp->mutex);
|
||||
kfree(hdcp->port_data.streams);
|
||||
hdcp->shim = NULL;
|
||||
mutex_unlock(&hdcp->mutex);
|
||||
}
|
||||
|
||||
void intel_hdcp_atomic_check(struct drm_connector *connector,
|
||||
|
@ -22,7 +22,7 @@ enum transcoder;
|
||||
void intel_hdcp_atomic_check(struct drm_connector *connector,
|
||||
struct drm_connector_state *old_state,
|
||||
struct drm_connector_state *new_state);
|
||||
int intel_hdcp_init(struct intel_connector *connector,
|
||||
int intel_hdcp_init(struct intel_connector *connector, enum port port,
|
||||
const struct intel_hdcp_shim *hdcp_shim);
|
||||
int intel_hdcp_enable(struct intel_connector *connector,
|
||||
enum transcoder cpu_transcoder, u8 content_type);
|
||||
|
@ -1477,7 +1477,8 @@ int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port *dig_port,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kbl_repositioning_enc_en_signal(struct intel_connector *connector)
|
||||
static int kbl_repositioning_enc_en_signal(struct intel_connector *connector,
|
||||
enum transcoder cpu_transcoder)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
@ -1494,13 +1495,15 @@ static int kbl_repositioning_enc_en_signal(struct intel_connector *connector)
|
||||
usleep_range(25, 50);
|
||||
}
|
||||
|
||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base, false);
|
||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base, cpu_transcoder,
|
||||
false);
|
||||
if (ret) {
|
||||
drm_err(&dev_priv->drm,
|
||||
"Disable HDCP signalling failed (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base, true);
|
||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base, cpu_transcoder,
|
||||
true);
|
||||
if (ret) {
|
||||
drm_err(&dev_priv->drm,
|
||||
"Enable HDCP signalling failed (%d)\n", ret);
|
||||
@ -1512,6 +1515,7 @@ static int kbl_repositioning_enc_en_signal(struct intel_connector *connector)
|
||||
|
||||
static
|
||||
int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
|
||||
enum transcoder cpu_transcoder,
|
||||
bool enable)
|
||||
{
|
||||
struct intel_hdmi *hdmi = &dig_port->hdmi;
|
||||
@ -1522,7 +1526,8 @@ int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
|
||||
if (!enable)
|
||||
usleep_range(6, 60); /* Bspec says >= 6us */
|
||||
|
||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base, enable);
|
||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base, cpu_transcoder,
|
||||
enable);
|
||||
if (ret) {
|
||||
drm_err(&dev_priv->drm, "%s HDCP signalling failed (%d)\n",
|
||||
enable ? "Enable" : "Disable", ret);
|
||||
@ -1534,17 +1539,17 @@ int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
|
||||
* opportunity and enc_en signalling in KABYLAKE.
|
||||
*/
|
||||
if (IS_KABYLAKE(dev_priv) && enable)
|
||||
return kbl_repositioning_enc_en_signal(connector);
|
||||
return kbl_repositioning_enc_en_signal(connector,
|
||||
cpu_transcoder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
bool intel_hdmi_hdcp_check_link_once(struct intel_digital_port *dig_port)
|
||||
bool intel_hdmi_hdcp_check_link_once(struct intel_digital_port *dig_port,
|
||||
struct intel_connector *connector)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
struct intel_connector *connector =
|
||||
dig_port->hdmi.attached_connector;
|
||||
enum port port = dig_port->base.port;
|
||||
enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
|
||||
int ret;
|
||||
@ -1572,13 +1577,14 @@ bool intel_hdmi_hdcp_check_link_once(struct intel_digital_port *dig_port)
|
||||
}
|
||||
|
||||
static
|
||||
bool intel_hdmi_hdcp_check_link(struct intel_digital_port *dig_port)
|
||||
bool intel_hdmi_hdcp_check_link(struct intel_digital_port *dig_port,
|
||||
struct intel_connector *connector)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
int retry;
|
||||
|
||||
for (retry = 0; retry < 3; retry++)
|
||||
if (intel_hdmi_hdcp_check_link_once(dig_port))
|
||||
if (intel_hdmi_hdcp_check_link_once(dig_port, connector))
|
||||
return true;
|
||||
|
||||
drm_err(&i915->drm, "Link check failed\n");
|
||||
@ -2271,35 +2277,18 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
|
||||
return intel_mode_valid_max_plane_size(dev_priv, mode);
|
||||
}
|
||||
|
||||
static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
|
||||
int bpc)
|
||||
bool intel_hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
|
||||
int bpc, bool has_hdmi_sink, bool ycbcr420_output)
|
||||
{
|
||||
struct drm_i915_private *dev_priv =
|
||||
to_i915(crtc_state->uapi.crtc->dev);
|
||||
struct drm_atomic_state *state = crtc_state->uapi.state;
|
||||
struct drm_connector_state *connector_state;
|
||||
struct drm_connector *connector;
|
||||
const struct drm_display_mode *adjusted_mode =
|
||||
&crtc_state->hw.adjusted_mode;
|
||||
int i;
|
||||
|
||||
if (HAS_GMCH(dev_priv))
|
||||
return false;
|
||||
|
||||
if (bpc == 10 && INTEL_GEN(dev_priv) < 11)
|
||||
return false;
|
||||
|
||||
if (crtc_state->pipe_bpp < bpc * 3)
|
||||
return false;
|
||||
|
||||
if (!crtc_state->has_hdmi_sink)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* HDMI deep color affects the clocks, so it's only possible
|
||||
* when not cloning with other encoder types.
|
||||
*/
|
||||
if (crtc_state->output_types != 1 << INTEL_OUTPUT_HDMI)
|
||||
if (!has_hdmi_sink)
|
||||
return false;
|
||||
|
||||
for_each_new_connector_in_state(state, connector, connector_state, i) {
|
||||
@ -2308,7 +2297,7 @@ static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
|
||||
if (connector_state->crtc != crtc_state->uapi.crtc)
|
||||
continue;
|
||||
|
||||
if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
|
||||
if (ycbcr420_output) {
|
||||
const struct drm_hdmi_info *hdmi = &info->hdmi;
|
||||
|
||||
if (bpc == 12 && !(hdmi->y420_dc_modes &
|
||||
@ -2327,6 +2316,30 @@ static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
|
||||
int bpc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv =
|
||||
to_i915(crtc_state->uapi.crtc->dev);
|
||||
const struct drm_display_mode *adjusted_mode =
|
||||
&crtc_state->hw.adjusted_mode;
|
||||
|
||||
if (HAS_GMCH(dev_priv))
|
||||
return false;
|
||||
|
||||
if (bpc == 10 && INTEL_GEN(dev_priv) < 11)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* HDMI deep color affects the clocks, so it's only possible
|
||||
* when not cloning with other encoder types.
|
||||
*/
|
||||
if (crtc_state->output_types != BIT(INTEL_OUTPUT_HDMI))
|
||||
return false;
|
||||
|
||||
/* Display Wa_1405510057:icl,ehl */
|
||||
if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 &&
|
||||
bpc == 10 && IS_GEN(dev_priv, 11) &&
|
||||
@ -2334,7 +2347,10 @@ static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
|
||||
adjusted_mode->crtc_hblank_start) % 8 == 2)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return intel_hdmi_deep_color_possible(crtc_state, bpc,
|
||||
crtc_state->has_hdmi_sink,
|
||||
crtc_state->output_format ==
|
||||
INTEL_OUTPUT_FORMAT_YCBCR420);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2459,6 +2475,23 @@ bool intel_hdmi_limited_color_range(const struct intel_crtc_state *crtc_state,
|
||||
}
|
||||
}
|
||||
|
||||
static bool intel_hdmi_has_audio(struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *crtc_state,
|
||||
const struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
const struct intel_digital_connector_state *intel_conn_state =
|
||||
to_intel_digital_connector_state(conn_state);
|
||||
|
||||
if (!crtc_state->has_hdmi_sink)
|
||||
return false;
|
||||
|
||||
if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
|
||||
return intel_hdmi->has_audio;
|
||||
else
|
||||
return intel_conn_state->force_audio == HDMI_AUDIO_ON;
|
||||
}
|
||||
|
||||
int intel_hdmi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
@ -2468,8 +2501,6 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
|
||||
struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
|
||||
struct drm_connector *connector = conn_state->connector;
|
||||
struct drm_scdc *scdc = &connector->display_info.hdmi.scdc;
|
||||
struct intel_digital_connector_state *intel_conn_state =
|
||||
to_intel_digital_connector_state(conn_state);
|
||||
int ret;
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
@ -2495,13 +2526,8 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
|
||||
if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv))
|
||||
pipe_config->has_pch_encoder = true;
|
||||
|
||||
if (pipe_config->has_hdmi_sink) {
|
||||
if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
|
||||
pipe_config->has_audio = intel_hdmi->has_audio;
|
||||
else
|
||||
pipe_config->has_audio =
|
||||
intel_conn_state->force_audio == HDMI_AUDIO_ON;
|
||||
}
|
||||
pipe_config->has_audio =
|
||||
intel_hdmi_has_audio(encoder, pipe_config, conn_state);
|
||||
|
||||
ret = intel_hdmi_compute_clock(encoder, pipe_config);
|
||||
if (ret)
|
||||
@ -2667,6 +2693,9 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
|
||||
drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n",
|
||||
connector->base.id, connector->name);
|
||||
|
||||
if (!INTEL_DISPLAY_ENABLED(dev_priv))
|
||||
return connector_status_disconnected;
|
||||
|
||||
wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 11 &&
|
||||
@ -3250,7 +3279,6 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
|
||||
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
|
||||
connector->ycbcr_420_allowed = true;
|
||||
|
||||
intel_encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port);
|
||||
intel_connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
|
||||
if (HAS_DDI(dev_priv))
|
||||
@ -3264,7 +3292,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
|
||||
intel_hdmi->attached_connector = intel_connector;
|
||||
|
||||
if (is_hdcp_supported(dev_priv, port)) {
|
||||
int ret = intel_hdcp_init(intel_connector,
|
||||
int ret = intel_hdcp_init(intel_connector, port,
|
||||
&intel_hdmi_hdcp_shim);
|
||||
if (ret)
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
@ -3335,6 +3363,8 @@ void intel_hdmi_init(struct drm_i915_private *dev_priv,
|
||||
|
||||
intel_encoder = &dig_port->base;
|
||||
|
||||
mutex_init(&dig_port->hdcp_mutex);
|
||||
|
||||
drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
|
||||
&intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
|
||||
"HDMI %c", port_name(port));
|
||||
@ -3382,6 +3412,7 @@ void intel_hdmi_init(struct drm_i915_private *dev_priv,
|
||||
intel_encoder->pipe_mask = ~0;
|
||||
}
|
||||
intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG;
|
||||
intel_encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port);
|
||||
/*
|
||||
* BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems
|
||||
* to work on real hardware. And since g4x can send infoframes to
|
||||
|
@ -48,5 +48,7 @@ void intel_read_infoframe(struct intel_encoder *encoder,
|
||||
union hdmi_infoframe *frame);
|
||||
bool intel_hdmi_limited_color_range(const struct intel_crtc_state *crtc_state,
|
||||
const struct drm_connector_state *conn_state);
|
||||
bool intel_hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state, int bpc,
|
||||
bool has_hdmi_sink, bool ycbcr420_output);
|
||||
|
||||
#endif /* __INTEL_HDMI_H__ */
|
||||
|
@ -81,33 +81,12 @@
|
||||
*
|
||||
* It is only valid and used by digital port encoder.
|
||||
*
|
||||
* Return pin that is associatade with @port and HDP_NONE if no pin is
|
||||
* hard associated with that @port.
|
||||
* Return pin that is associatade with @port.
|
||||
*/
|
||||
enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv,
|
||||
enum port port)
|
||||
{
|
||||
enum phy phy = intel_port_to_phy(dev_priv, port);
|
||||
|
||||
/*
|
||||
* RKL + TGP PCH is a special case; we effectively choose the hpd_pin
|
||||
* based on the DDI rather than the PHY (i.e., the last two outputs
|
||||
* shold be HPD_PORT_{D,E} rather than {C,D}. Note that this differs
|
||||
* from the behavior of both TGL+TGP and RKL+CMP.
|
||||
*/
|
||||
if (IS_ROCKETLAKE(dev_priv) && HAS_PCH_TGP(dev_priv))
|
||||
return HPD_PORT_A + port - PORT_A;
|
||||
|
||||
switch (phy) {
|
||||
case PHY_F:
|
||||
return IS_CNL_WITH_PORT_F(dev_priv) ? HPD_PORT_E : HPD_PORT_F;
|
||||
case PHY_A ... PHY_E:
|
||||
case PHY_G ... PHY_I:
|
||||
return HPD_PORT_A + phy - PHY_A;
|
||||
default:
|
||||
MISSING_CASE(phy);
|
||||
return HPD_NONE;
|
||||
}
|
||||
return HPD_PORT_A + port - PORT_A;
|
||||
}
|
||||
|
||||
#define HPD_STORM_DETECT_PERIOD 1000
|
||||
@ -503,7 +482,6 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
|
||||
* only the one of them (DP) will have ->hpd_pulse().
|
||||
*/
|
||||
for_each_intel_encoder(&dev_priv->drm, encoder) {
|
||||
bool has_hpd_pulse = intel_encoder_has_hpd_pulse(encoder);
|
||||
enum port port = encoder->port;
|
||||
bool long_hpd;
|
||||
|
||||
@ -511,7 +489,7 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
|
||||
if (!(BIT(pin) & pin_mask))
|
||||
continue;
|
||||
|
||||
if (!has_hpd_pulse)
|
||||
if (!intel_encoder_has_hpd_pulse(encoder))
|
||||
continue;
|
||||
|
||||
long_hpd = long_mask & BIT(pin);
|
||||
|
@ -456,12 +456,6 @@ static int intel_lvds_compute_config(struct intel_encoder *intel_encoder,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
intel_lvds_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
|
||||
*/
|
||||
@ -490,7 +484,7 @@ static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_lvds_connector_funcs = {
|
||||
.detect = intel_lvds_detect,
|
||||
.detect = intel_panel_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.atomic_get_property = intel_digital_connector_atomic_get_property,
|
||||
.atomic_set_property = intel_digital_connector_atomic_set_property,
|
||||
|
@ -40,8 +40,6 @@
|
||||
#include "intel_dsi_dcs_backlight.h"
|
||||
#include "intel_panel.h"
|
||||
|
||||
#define CRC_PMIC_PWM_PERIOD_NS 21333
|
||||
|
||||
void
|
||||
intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
@ -594,10 +592,10 @@ static u32 bxt_get_backlight(struct intel_connector *connector)
|
||||
static u32 pwm_get_backlight(struct intel_connector *connector)
|
||||
{
|
||||
struct intel_panel *panel = &connector->panel;
|
||||
int duty_ns;
|
||||
struct pwm_state state;
|
||||
|
||||
duty_ns = pwm_get_duty_cycle(panel->backlight.pwm);
|
||||
return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS);
|
||||
pwm_get_state(panel->backlight.pwm, &state);
|
||||
return pwm_get_relative_duty_cycle(&state, 100);
|
||||
}
|
||||
|
||||
static void lpt_set_backlight(const struct drm_connector_state *conn_state, u32 level)
|
||||
@ -671,9 +669,9 @@ static void bxt_set_backlight(const struct drm_connector_state *conn_state, u32
|
||||
static void pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level)
|
||||
{
|
||||
struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;
|
||||
int duty_ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100);
|
||||
|
||||
pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS);
|
||||
pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100);
|
||||
pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -842,10 +840,8 @@ static void pwm_disable_backlight(const struct drm_connector_state *old_conn_sta
|
||||
struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
|
||||
struct intel_panel *panel = &connector->panel;
|
||||
|
||||
/* Disable the backlight */
|
||||
intel_panel_actually_set_backlight(old_conn_state, 0);
|
||||
usleep_range(2000, 3000);
|
||||
pwm_disable(panel->backlight.pwm);
|
||||
panel->backlight.pwm_state.enabled = false;
|
||||
pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
|
||||
}
|
||||
|
||||
void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state)
|
||||
@ -1177,9 +1173,12 @@ static void pwm_enable_backlight(const struct intel_crtc_state *crtc_state,
|
||||
{
|
||||
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
||||
struct intel_panel *panel = &connector->panel;
|
||||
int level = panel->backlight.level;
|
||||
|
||||
pwm_enable(panel->backlight.pwm);
|
||||
intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
|
||||
level = intel_panel_compute_brightness(connector, level);
|
||||
pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100);
|
||||
panel->backlight.pwm_state.enabled = true;
|
||||
pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
|
||||
}
|
||||
|
||||
static void __intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state,
|
||||
@ -1543,18 +1542,9 @@ static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
|
||||
return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
|
||||
}
|
||||
|
||||
static u32 get_backlight_max_vbt(struct intel_connector *connector)
|
||||
static u16 get_vbt_pwm_freq(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||
struct intel_panel *panel = &connector->panel;
|
||||
u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz;
|
||||
u32 pwm;
|
||||
|
||||
if (!panel->backlight.hz_to_pwm) {
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
"backlight frequency conversion not supported\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pwm_freq_hz) {
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
@ -1567,6 +1557,22 @@ static u32 get_backlight_max_vbt(struct intel_connector *connector)
|
||||
pwm_freq_hz);
|
||||
}
|
||||
|
||||
return pwm_freq_hz;
|
||||
}
|
||||
|
||||
static u32 get_backlight_max_vbt(struct intel_connector *connector)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||
struct intel_panel *panel = &connector->panel;
|
||||
u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv);
|
||||
u32 pwm;
|
||||
|
||||
if (!panel->backlight.hz_to_pwm) {
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
"backlight frequency conversion not supported\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pwm = panel->backlight.hz_to_pwm(connector, pwm_freq_hz);
|
||||
if (!pwm) {
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
@ -1891,8 +1897,7 @@ static int pwm_setup_backlight(struct intel_connector *connector,
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_panel *panel = &connector->panel;
|
||||
const char *desc;
|
||||
u32 level, ns;
|
||||
int retval;
|
||||
u32 level;
|
||||
|
||||
/* Get the right PWM chip for DSI backlight according to VBT */
|
||||
if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) {
|
||||
@ -1910,31 +1915,29 @@ static int pwm_setup_backlight(struct intel_connector *connector,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: pwm_apply_args() should be removed when switching to
|
||||
* the atomic PWM API.
|
||||
*/
|
||||
pwm_apply_args(panel->backlight.pwm);
|
||||
|
||||
panel->backlight.min = 0; /* 0% */
|
||||
panel->backlight.max = 100; /* 100% */
|
||||
level = intel_panel_compute_brightness(connector, 100);
|
||||
ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100);
|
||||
panel->backlight.min = get_backlight_min_vbt(connector);
|
||||
|
||||
retval = pwm_config(panel->backlight.pwm, ns, CRC_PMIC_PWM_PERIOD_NS);
|
||||
if (retval < 0) {
|
||||
drm_err(&dev_priv->drm, "Failed to configure the pwm chip\n");
|
||||
pwm_put(panel->backlight.pwm);
|
||||
panel->backlight.pwm = NULL;
|
||||
return retval;
|
||||
if (pwm_is_enabled(panel->backlight.pwm)) {
|
||||
/* PWM is already enabled, use existing settings */
|
||||
pwm_get_state(panel->backlight.pwm, &panel->backlight.pwm_state);
|
||||
|
||||
level = pwm_get_relative_duty_cycle(&panel->backlight.pwm_state,
|
||||
100);
|
||||
level = intel_panel_compute_brightness(connector, level);
|
||||
panel->backlight.level = clamp(level, panel->backlight.min,
|
||||
panel->backlight.max);
|
||||
panel->backlight.enabled = true;
|
||||
|
||||
drm_dbg_kms(&dev_priv->drm, "PWM already enabled at freq %ld, VBT freq %d, level %d\n",
|
||||
NSEC_PER_SEC / (unsigned long)panel->backlight.pwm_state.period,
|
||||
get_vbt_pwm_freq(dev_priv), level);
|
||||
} else {
|
||||
/* Set period from VBT frequency, leave other settings at 0. */
|
||||
panel->backlight.pwm_state.period =
|
||||
NSEC_PER_SEC / get_vbt_pwm_freq(dev_priv);
|
||||
}
|
||||
|
||||
level = DIV_ROUND_UP_ULL(pwm_get_duty_cycle(panel->backlight.pwm) * 100,
|
||||
CRC_PMIC_PWM_PERIOD_NS);
|
||||
panel->backlight.level =
|
||||
intel_panel_compute_brightness(connector, level);
|
||||
panel->backlight.enabled = panel->backlight.level != 0;
|
||||
|
||||
drm_info(&dev_priv->drm, "Using %s PWM for LCD backlight control\n",
|
||||
desc);
|
||||
return 0;
|
||||
@ -2092,6 +2095,17 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel)
|
||||
}
|
||||
}
|
||||
|
||||
enum drm_connector_status
|
||||
intel_panel_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(connector->dev);
|
||||
|
||||
if (!INTEL_DISPLAY_ENABLED(i915))
|
||||
return connector_status_disconnected;
|
||||
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
int intel_panel_init(struct intel_panel *panel,
|
||||
struct drm_display_mode *fixed_mode,
|
||||
struct drm_display_mode *downclock_mode)
|
||||
|
@ -23,6 +23,8 @@ int intel_panel_init(struct intel_panel *panel,
|
||||
struct drm_display_mode *fixed_mode,
|
||||
struct drm_display_mode *downclock_mode);
|
||||
void intel_panel_fini(struct intel_panel *panel);
|
||||
enum drm_connector_status
|
||||
intel_panel_detect(struct drm_connector *connector, bool force);
|
||||
void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
int intel_pch_panel_fitting(struct intel_crtc_state *crtc_state,
|
||||
|
@ -555,7 +555,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp)
|
||||
|
||||
if (dev_priv->psr.psr2_sel_fetch_enabled) {
|
||||
/* WA 1408330847 */
|
||||
if (IS_TGL_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_A0) ||
|
||||
if (IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_A0) ||
|
||||
IS_RKL_REVID(dev_priv, RKL_REVID_A0, RKL_REVID_A0))
|
||||
intel_de_rmw(dev_priv, CHICKEN_PAR1_1,
|
||||
DIS_RAM_BYPASS_PSR2_MAN_TRACK,
|
||||
@ -1109,7 +1109,7 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp)
|
||||
|
||||
/* WA 1408330847 */
|
||||
if (dev_priv->psr.psr2_sel_fetch_enabled &&
|
||||
(IS_TGL_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_A0) ||
|
||||
(IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_A0) ||
|
||||
IS_RKL_REVID(dev_priv, RKL_REVID_A0, RKL_REVID_A0)))
|
||||
intel_de_rmw(dev_priv, CHICKEN_PAR1_1,
|
||||
DIS_RAM_BYPASS_PSR2_MAN_TRACK, 0);
|
||||
|
@ -2084,14 +2084,18 @@ intel_sdvo_connector_matches_edid(struct intel_sdvo_connector *sdvo,
|
||||
static enum drm_connector_status
|
||||
intel_sdvo_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
u16 response;
|
||||
struct drm_i915_private *i915 = to_i915(connector->dev);
|
||||
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector));
|
||||
struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
|
||||
enum drm_connector_status ret;
|
||||
u16 response;
|
||||
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
|
||||
connector->base.id, connector->name);
|
||||
|
||||
if (!INTEL_DISPLAY_ENABLED(i915))
|
||||
return connector_status_disconnected;
|
||||
|
||||
if (!intel_sdvo_get_value(intel_sdvo,
|
||||
SDVO_CMD_GET_ATTACHED_DISPLAYS,
|
||||
&response, 2))
|
||||
|
@ -1626,8 +1626,7 @@ static int g4x_sprite_min_cdclk(const struct intel_crtc_state *crtc_state,
|
||||
hscale = drm_rect_calc_hscale(&plane_state->uapi.src,
|
||||
&plane_state->uapi.dst,
|
||||
0, INT_MAX);
|
||||
if (hscale < 0x10000)
|
||||
return pixel_rate;
|
||||
hscale = max(hscale, 0x10000u);
|
||||
|
||||
/* Decimation steps at 2x,4x,8x,16x */
|
||||
decimate = ilog2(hscale >> 16);
|
||||
@ -1640,8 +1639,8 @@ static int g4x_sprite_min_cdclk(const struct intel_crtc_state *crtc_state,
|
||||
limit -= decimate;
|
||||
|
||||
/* -10% for RGB */
|
||||
if (fb->format->cpp[0] >= 4)
|
||||
limit--; /* -10% for RGB */
|
||||
if (!fb->format->is_yuv)
|
||||
limit--;
|
||||
|
||||
/*
|
||||
* We should also do -10% if sprite scaling is enabled
|
||||
@ -2845,7 +2844,7 @@ static bool gen12_plane_supports_mc_ccs(struct drm_i915_private *dev_priv,
|
||||
{
|
||||
/* Wa_14010477008:tgl[a0..c0],rkl[all] */
|
||||
if (IS_ROCKETLAKE(dev_priv) ||
|
||||
IS_TGL_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_C0))
|
||||
IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_C0))
|
||||
return false;
|
||||
|
||||
return plane_id < PLANE_SPRITE4;
|
||||
|
@ -1706,6 +1706,9 @@ intel_tv_detect(struct drm_connector *connector,
|
||||
drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] force=%d\n",
|
||||
connector->base.id, connector->name, force);
|
||||
|
||||
if (!INTEL_DISPLAY_ENABLED(i915))
|
||||
return connector_status_disconnected;
|
||||
|
||||
if (force) {
|
||||
struct intel_load_detect_pipe tmp;
|
||||
int ret;
|
||||
|
@ -293,8 +293,12 @@ struct bdb_general_features {
|
||||
#define DVO_PORT_HDMIE 12 /* 193 */
|
||||
#define DVO_PORT_DPF 13 /* N/A */
|
||||
#define DVO_PORT_HDMIF 14 /* N/A */
|
||||
#define DVO_PORT_DPG 15
|
||||
#define DVO_PORT_HDMIG 16
|
||||
#define DVO_PORT_DPG 15 /* 217 */
|
||||
#define DVO_PORT_HDMIG 16 /* 217 */
|
||||
#define DVO_PORT_DPH 17 /* 217 */
|
||||
#define DVO_PORT_HDMIH 18 /* 217 */
|
||||
#define DVO_PORT_DPI 19 /* 217 */
|
||||
#define DVO_PORT_HDMII 20 /* 217 */
|
||||
#define DVO_PORT_MIPIA 21 /* 171 */
|
||||
#define DVO_PORT_MIPIB 22 /* 171 */
|
||||
#define DVO_PORT_MIPIC 23 /* 171 */
|
||||
@ -330,6 +334,8 @@ enum vbt_gmbus_ddi {
|
||||
#define DP_AUX_E 0x50
|
||||
#define DP_AUX_F 0x60
|
||||
#define DP_AUX_G 0x70
|
||||
#define DP_AUX_H 0x80
|
||||
#define DP_AUX_I 0x90
|
||||
|
||||
#define VBT_DP_MAX_LINK_RATE_HBR3 0
|
||||
#define VBT_DP_MAX_LINK_RATE_HBR2 1
|
||||
|
@ -1585,6 +1585,7 @@ static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_dsi_connector_funcs = {
|
||||
.detect = intel_panel_detect,
|
||||
.late_register = intel_connector_register,
|
||||
.early_unregister = intel_connector_unregister,
|
||||
.destroy = intel_connector_destroy,
|
||||
|
@ -483,7 +483,7 @@ int bxt_dsi_pll_compute(struct intel_encoder *encoder,
|
||||
|
||||
if (dsi_ratio < dsi_ratio_min || dsi_ratio > dsi_ratio_max) {
|
||||
drm_err(&dev_priv->drm,
|
||||
"Cant get a suitable ratio from DSI PLL ratios\n");
|
||||
"Can't get a suitable ratio from DSI PLL ratios\n");
|
||||
return -ECHRNG;
|
||||
} else
|
||||
drm_dbg_kms(&dev_priv->drm, "DSI PLL calculation is Done!!\n");
|
||||
|
@ -70,6 +70,19 @@ const struct i915_rev_steppings kbl_revids[] = {
|
||||
[7] = { .gt_stepping = KBL_REVID_G0, .disp_stepping = KBL_REVID_C0 },
|
||||
};
|
||||
|
||||
const struct i915_rev_steppings tgl_uy_revids[] = {
|
||||
[0] = { .gt_stepping = TGL_REVID_A0, .disp_stepping = TGL_REVID_A0 },
|
||||
[1] = { .gt_stepping = TGL_REVID_B0, .disp_stepping = TGL_REVID_C0 },
|
||||
[2] = { .gt_stepping = TGL_REVID_B1, .disp_stepping = TGL_REVID_C0 },
|
||||
[3] = { .gt_stepping = TGL_REVID_C0, .disp_stepping = TGL_REVID_D0 },
|
||||
};
|
||||
|
||||
/* Same GT stepping between tgl_uy_revids and tgl_revids don't mean the same HW */
|
||||
const struct i915_rev_steppings tgl_revids[] = {
|
||||
[0] = { .gt_stepping = TGL_REVID_A0, .disp_stepping = TGL_REVID_B0 },
|
||||
[1] = { .gt_stepping = TGL_REVID_B0, .disp_stepping = TGL_REVID_D0 },
|
||||
};
|
||||
|
||||
static void wa_init_start(struct i915_wa_list *wal, const char *name, const char *engine_name)
|
||||
{
|
||||
wal->name = name;
|
||||
@ -1219,13 +1232,13 @@ tgl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal)
|
||||
gen12_gt_workarounds_init(i915, wal);
|
||||
|
||||
/* Wa_1409420604:tgl */
|
||||
if (IS_TGL_REVID(i915, TGL_REVID_A0, TGL_REVID_A0))
|
||||
if (IS_TGL_UY_GT_REVID(i915, TGL_REVID_A0, TGL_REVID_A0))
|
||||
wa_write_or(wal,
|
||||
SUBSLICE_UNIT_LEVEL_CLKGATE2,
|
||||
CPSSUNIT_CLKGATE_DIS);
|
||||
|
||||
/* Wa_1607087056:tgl also know as BUG:1409180338 */
|
||||
if (IS_TGL_REVID(i915, TGL_REVID_A0, TGL_REVID_A0))
|
||||
if (IS_TGL_UY_GT_REVID(i915, TGL_REVID_A0, TGL_REVID_A0))
|
||||
wa_write_or(wal,
|
||||
SLICE_UNIT_LEVEL_CLKGATE,
|
||||
L3_CLKGATE_DIS | L3_CR2X_CLKGATE_DIS);
|
||||
@ -1660,7 +1673,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
|
||||
{
|
||||
struct drm_i915_private *i915 = engine->i915;
|
||||
|
||||
if (IS_TGL_REVID(i915, TGL_REVID_A0, TGL_REVID_A0)) {
|
||||
if (IS_TGL_UY_GT_REVID(i915, TGL_REVID_A0, TGL_REVID_A0)) {
|
||||
/*
|
||||
* Wa_1607138336:tgl
|
||||
* Wa_1607063988:tgl
|
||||
@ -1700,7 +1713,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
|
||||
* Wa_1407928979:tgl A*
|
||||
* Wa_18011464164:tgl B0+
|
||||
* Wa_22010931296:tgl B0+
|
||||
* Wa_14010919138:rkl
|
||||
* Wa_14010919138:rkl,tgl
|
||||
*/
|
||||
wa_write_or(wal, GEN7_FF_THREAD_MODE,
|
||||
GEN12_FF_TESSELATION_DOP_GATE_DISABLE);
|
||||
@ -1716,15 +1729,23 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
|
||||
GEN6_RC_SLEEP_PSMI_CONTROL,
|
||||
GEN12_WAIT_FOR_EVENT_POWER_DOWN_DISABLE |
|
||||
GEN8_RC_SEMA_IDLE_MSG_DISABLE);
|
||||
}
|
||||
|
||||
if (IS_TIGERLAKE(i915)) {
|
||||
/* Wa_1606700617:tgl */
|
||||
/*
|
||||
* Wa_1606700617:tgl
|
||||
* Wa_22010271021:tgl,rkl
|
||||
*/
|
||||
wa_masked_en(wal,
|
||||
GEN9_CS_DEBUG_MODE1,
|
||||
FF_DOP_CLOCK_GATE_DISABLE);
|
||||
}
|
||||
|
||||
if (IS_GEN(i915, 12)) {
|
||||
/* Wa_1406941453:gen12 */
|
||||
wa_masked_en(wal,
|
||||
GEN10_SAMPLER_MODE,
|
||||
ENABLE_SMALLPL);
|
||||
}
|
||||
|
||||
if (IS_GEN(i915, 11)) {
|
||||
/* This is not an Wa. Enable for better image quality */
|
||||
wa_masked_en(wal,
|
||||
|
@ -936,7 +936,7 @@ static int cmd_reg_handler(struct parser_exec_state *s,
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!intel_gvt_mmio_is_cmd_access(gvt, offset)) {
|
||||
if (!intel_gvt_mmio_is_cmd_accessible(gvt, offset)) {
|
||||
gvt_vgpu_err("%s access to non-render register (%x)\n",
|
||||
cmd, offset);
|
||||
return -EBADRQC;
|
||||
@ -976,7 +976,7 @@ static int cmd_reg_handler(struct parser_exec_state *s,
|
||||
* inhibit context will restore with correct values
|
||||
*/
|
||||
if (IS_GEN(s->engine->i915, 9) &&
|
||||
intel_gvt_mmio_is_in_ctx(gvt, offset) &&
|
||||
intel_gvt_mmio_is_sr_in_ctx(gvt, offset) &&
|
||||
!strncmp(cmd, "lri", 3)) {
|
||||
intel_gvt_hypervisor_read_gpa(s->vgpu,
|
||||
s->workload->ring_context_gpa + 12, &ctx_sr_ctl, 4);
|
||||
@ -992,8 +992,6 @@ static int cmd_reg_handler(struct parser_exec_state *s,
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Update the global mask if this MMIO is a masked-MMIO */
|
||||
intel_gvt_mmio_set_cmd_accessed(gvt, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -256,11 +256,11 @@ struct intel_gvt_mmio {
|
||||
/* This reg has been accessed by a VM */
|
||||
#define F_ACCESSED (1 << 4)
|
||||
/* This reg has been accessed through GPU commands */
|
||||
#define F_CMD_ACCESSED (1 << 5)
|
||||
/* This reg could be accessed by unaligned address */
|
||||
#define F_UNALIGN (1 << 6)
|
||||
/* This reg is saved/restored in context */
|
||||
#define F_IN_CTX (1 << 7)
|
||||
/* This reg is in GVT's mmio save-restor list and in hardware
|
||||
* logical context image
|
||||
*/
|
||||
#define F_SR_IN_CTX (1 << 7)
|
||||
|
||||
struct gvt_mmio_block *mmio_block;
|
||||
unsigned int num_mmio_block;
|
||||
@ -597,15 +597,30 @@ static inline void intel_gvt_mmio_set_accessed(
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_mmio_is_cmd_accessed - mark a MMIO could be accessed by command
|
||||
* intel_gvt_mmio_is_cmd_accessible - if a MMIO could be accessed by command
|
||||
* @gvt: a GVT device
|
||||
* @offset: register offset
|
||||
*
|
||||
* Returns:
|
||||
* True if an MMIO is able to be accessed by GPU commands
|
||||
*/
|
||||
static inline bool intel_gvt_mmio_is_cmd_accessible(
|
||||
struct intel_gvt *gvt, unsigned int offset)
|
||||
{
|
||||
return gvt->mmio.mmio_attribute[offset >> 2] & F_CMD_ACCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_mmio_set_cmd_accessible -
|
||||
* mark a MMIO could be accessible by command
|
||||
* @gvt: a GVT device
|
||||
* @offset: register offset
|
||||
*
|
||||
*/
|
||||
static inline bool intel_gvt_mmio_is_cmd_access(
|
||||
static inline void intel_gvt_mmio_set_cmd_accessible(
|
||||
struct intel_gvt *gvt, unsigned int offset)
|
||||
{
|
||||
return gvt->mmio.mmio_attribute[offset >> 2] & F_CMD_ACCESS;
|
||||
gvt->mmio.mmio_attribute[offset >> 2] |= F_CMD_ACCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -620,18 +635,6 @@ static inline bool intel_gvt_mmio_is_unalign(
|
||||
return gvt->mmio.mmio_attribute[offset >> 2] & F_UNALIGN;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_mmio_set_cmd_accessed - mark a MMIO has been accessed by command
|
||||
* @gvt: a GVT device
|
||||
* @offset: register offset
|
||||
*
|
||||
*/
|
||||
static inline void intel_gvt_mmio_set_cmd_accessed(
|
||||
struct intel_gvt *gvt, unsigned int offset)
|
||||
{
|
||||
gvt->mmio.mmio_attribute[offset >> 2] |= F_CMD_ACCESSED;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_mmio_has_mode_mask - if a MMIO has a mode mask
|
||||
* @gvt: a GVT device
|
||||
@ -648,30 +651,33 @@ static inline bool intel_gvt_mmio_has_mode_mask(
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_mmio_is_in_ctx - check if a MMIO has in-ctx mask
|
||||
* intel_gvt_mmio_is_sr_in_ctx -
|
||||
* check if an MMIO has F_SR_IN_CTX mask
|
||||
* @gvt: a GVT device
|
||||
* @offset: register offset
|
||||
*
|
||||
* Returns:
|
||||
* True if a MMIO has a in-context mask, false if it isn't.
|
||||
* True if an MMIO has an F_SR_IN_CTX mask, false if it isn't.
|
||||
*
|
||||
*/
|
||||
static inline bool intel_gvt_mmio_is_in_ctx(
|
||||
static inline bool intel_gvt_mmio_is_sr_in_ctx(
|
||||
struct intel_gvt *gvt, unsigned int offset)
|
||||
{
|
||||
return gvt->mmio.mmio_attribute[offset >> 2] & F_IN_CTX;
|
||||
return gvt->mmio.mmio_attribute[offset >> 2] & F_SR_IN_CTX;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_mmio_set_in_ctx - mask a MMIO in logical context
|
||||
* intel_gvt_mmio_set_sr_in_ctx -
|
||||
* mask an MMIO in GVT's mmio save-restore list and also
|
||||
* in hardware logical context image
|
||||
* @gvt: a GVT device
|
||||
* @offset: register offset
|
||||
*
|
||||
*/
|
||||
static inline void intel_gvt_mmio_set_in_ctx(
|
||||
static inline void intel_gvt_mmio_set_sr_in_ctx(
|
||||
struct intel_gvt *gvt, unsigned int offset)
|
||||
{
|
||||
gvt->mmio.mmio_attribute[offset >> 2] |= F_IN_CTX;
|
||||
gvt->mmio.mmio_attribute[offset >> 2] |= F_SR_IN_CTX;
|
||||
}
|
||||
|
||||
void intel_gvt_debugfs_add_vgpu(struct intel_vgpu *vgpu);
|
||||
|
@ -1892,7 +1892,7 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
|
||||
struct drm_i915_private *dev_priv = gvt->gt->i915;
|
||||
int ret;
|
||||
|
||||
MMIO_RING_DFH(RING_IMR, D_ALL, F_CMD_ACCESS, NULL,
|
||||
MMIO_RING_DFH(RING_IMR, D_ALL, 0, NULL,
|
||||
intel_vgpu_reg_imr_handler);
|
||||
|
||||
MMIO_DFH(SDEIMR, D_ALL, 0, NULL, intel_vgpu_reg_imr_handler);
|
||||
@ -1900,7 +1900,8 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
|
||||
MMIO_DFH(SDEIIR, D_ALL, 0, NULL, intel_vgpu_reg_iir_handler);
|
||||
MMIO_D(SDEISR, D_ALL);
|
||||
|
||||
MMIO_RING_DFH(RING_HWSTAM, D_ALL, F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_RING_DFH(RING_HWSTAM, D_ALL, 0, NULL, NULL);
|
||||
|
||||
|
||||
MMIO_DH(GEN8_GAMW_ECO_DEV_RW_IA, D_BDW_PLUS, NULL,
|
||||
gamw_echo_dev_rw_ia_write);
|
||||
@ -1927,11 +1928,11 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
|
||||
MMIO_GM_RDR(_MMIO(0x12198), D_ALL, NULL, NULL);
|
||||
MMIO_D(GEN7_CXT_SIZE, D_ALL);
|
||||
|
||||
MMIO_RING_DFH(RING_TAIL, D_ALL, F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_RING_DFH(RING_HEAD, D_ALL, F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_RING_DFH(RING_CTL, D_ALL, F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_RING_DFH(RING_ACTHD, D_ALL, F_CMD_ACCESS, mmio_read_from_hw, NULL);
|
||||
MMIO_RING_GM_RDR(RING_START, D_ALL, NULL, NULL);
|
||||
MMIO_RING_DFH(RING_TAIL, D_ALL, 0, NULL, NULL);
|
||||
MMIO_RING_DFH(RING_HEAD, D_ALL, 0, NULL, NULL);
|
||||
MMIO_RING_DFH(RING_CTL, D_ALL, 0, NULL, NULL);
|
||||
MMIO_RING_DFH(RING_ACTHD, D_ALL, 0, mmio_read_from_hw, NULL);
|
||||
MMIO_RING_GM(RING_START, D_ALL, NULL, NULL);
|
||||
|
||||
/* RING MODE */
|
||||
#define RING_REG(base) _MMIO((base) + 0x29c)
|
||||
@ -2686,7 +2687,7 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
|
||||
MMIO_DFH(_MMIO(0x4094), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL);
|
||||
|
||||
MMIO_DFH(ARB_MODE, D_ALL, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_RING_GM_RDR(RING_BBADDR, D_ALL, NULL, NULL);
|
||||
MMIO_RING_GM(RING_BBADDR, D_ALL, NULL, NULL);
|
||||
MMIO_DFH(_MMIO(0x2220), D_ALL, F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_DFH(_MMIO(0x12220), D_ALL, F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_DFH(_MMIO(0x22220), D_ALL, F_CMD_ACCESS, NULL, NULL);
|
||||
@ -2771,7 +2772,7 @@ static int init_bdw_mmio_info(struct intel_gvt *gvt)
|
||||
MMIO_DH(GEN8_MASTER_IRQ, D_BDW_PLUS, NULL,
|
||||
intel_vgpu_reg_master_irq_handler);
|
||||
|
||||
MMIO_RING_DFH(RING_ACTHD_UDW, D_BDW_PLUS, F_CMD_ACCESS,
|
||||
MMIO_RING_DFH(RING_ACTHD_UDW, D_BDW_PLUS, 0,
|
||||
mmio_read_from_hw, NULL);
|
||||
|
||||
#define RING_REG(base) _MMIO((base) + 0xd0)
|
||||
@ -2785,7 +2786,7 @@ static int init_bdw_mmio_info(struct intel_gvt *gvt)
|
||||
#undef RING_REG
|
||||
|
||||
#define RING_REG(base) _MMIO((base) + 0x234)
|
||||
MMIO_RING_F(RING_REG, 8, F_RO | F_CMD_ACCESS, 0, ~0, D_BDW_PLUS,
|
||||
MMIO_RING_F(RING_REG, 8, F_RO, 0, ~0, D_BDW_PLUS,
|
||||
NULL, NULL);
|
||||
#undef RING_REG
|
||||
|
||||
@ -2820,7 +2821,7 @@ static int init_bdw_mmio_info(struct intel_gvt *gvt)
|
||||
MMIO_RING_F(RING_REG, 32, F_CMD_ACCESS, 0, 0, D_BDW_PLUS, NULL, NULL);
|
||||
#undef RING_REG
|
||||
|
||||
MMIO_RING_GM_RDR(RING_HWS_PGA, D_BDW_PLUS, NULL, hws_pga_write);
|
||||
MMIO_RING_GM(RING_HWS_PGA, D_BDW_PLUS, NULL, hws_pga_write);
|
||||
|
||||
MMIO_DFH(HDC_CHICKEN0, D_BDW_PLUS, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);
|
||||
|
||||
@ -2921,7 +2922,7 @@ static int init_skl_mmio_info(struct intel_gvt *gvt)
|
||||
MMIO_D(GEN9_MEDIA_PG_IDLE_HYSTERESIS, D_SKL_PLUS);
|
||||
MMIO_D(GEN9_RENDER_PG_IDLE_HYSTERESIS, D_SKL_PLUS);
|
||||
MMIO_DFH(GEN9_GAMT_ECO_REG_RW_IA, D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_DH(MMCD_MISC_CTRL, D_SKL_PLUS, NULL, NULL);
|
||||
MMIO_DFH(MMCD_MISC_CTRL, D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_DH(CHICKEN_PAR1_1, D_SKL_PLUS, NULL, NULL);
|
||||
MMIO_D(DC_STATE_EN, D_SKL_PLUS);
|
||||
MMIO_D(DC_STATE_DEBUG, D_SKL_PLUS);
|
||||
@ -3137,7 +3138,7 @@ static int init_skl_mmio_info(struct intel_gvt *gvt)
|
||||
MMIO_DFH(GEN9_WM_CHICKEN3, D_SKL_PLUS, F_MODE_MASK | F_CMD_ACCESS,
|
||||
NULL, NULL);
|
||||
|
||||
MMIO_D(GAMT_CHKN_BIT_REG, D_KBL | D_CFL);
|
||||
MMIO_DFH(GAMT_CHKN_BIT_REG, D_KBL | D_CFL, F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_D(GEN9_CTX_PREEMPT_REG, D_SKL_PLUS);
|
||||
|
||||
return 0;
|
||||
@ -3357,7 +3358,10 @@ void intel_gvt_clean_mmio_info(struct intel_gvt *gvt)
|
||||
gvt->mmio.mmio_attribute = NULL;
|
||||
}
|
||||
|
||||
/* Special MMIO blocks. */
|
||||
/* Special MMIO blocks. registers in MMIO block ranges should not be command
|
||||
* accessible (should have no F_CMD_ACCESS flag).
|
||||
* otherwise, need to update cmd_reg_handler in cmd_parser.c
|
||||
*/
|
||||
static struct gvt_mmio_block mmio_blocks[] = {
|
||||
{D_SKL_PLUS, _MMIO(CSR_MMIO_START_RANGE), 0x3000, NULL, NULL},
|
||||
{D_ALL, _MMIO(MCHBAR_MIRROR_BASE_SNB), 0x40000, NULL, NULL},
|
||||
|
@ -251,6 +251,9 @@ void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu, bool dmlr)
|
||||
/* set the bit 0:2(Core C-State ) to C0 */
|
||||
vgpu_vreg_t(vgpu, GEN6_GT_CORE_STATUS) = 0;
|
||||
|
||||
/* uc reset hw expect GS_MIA_IN_RESET */
|
||||
vgpu_vreg_t(vgpu, GUC_STATUS) |= GS_MIA_IN_RESET;
|
||||
|
||||
if (IS_BROXTON(vgpu->gvt->gt->i915)) {
|
||||
vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) &=
|
||||
~(BIT(0) | BIT(1));
|
||||
|
@ -595,7 +595,7 @@ void intel_gvt_init_engine_mmio_context(struct intel_gvt *gvt)
|
||||
i915_mmio_reg_valid(mmio->reg); mmio++) {
|
||||
if (mmio->in_context) {
|
||||
gvt->engine_mmio_list.ctx_mmio_count[mmio->id]++;
|
||||
intel_gvt_mmio_set_in_ctx(gvt, mmio->reg.reg);
|
||||
intel_gvt_mmio_set_sr_in_ctx(gvt, mmio->reg.reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,6 @@
|
||||
#include "display/intel_hotplug.h"
|
||||
#include "display/intel_overlay.h"
|
||||
#include "display/intel_pipe_crc.h"
|
||||
#include "display/intel_psr.h"
|
||||
#include "display/intel_sprite.h"
|
||||
#include "display/intel_vga.h"
|
||||
|
||||
@ -216,125 +215,6 @@ intel_teardown_mchbar(struct drm_i915_private *dev_priv)
|
||||
release_resource(&dev_priv->mch_res);
|
||||
}
|
||||
|
||||
/* part #1: call before irq install */
|
||||
static int i915_driver_modeset_probe_noirq(struct drm_i915_private *i915)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (i915_inject_probe_failure(i915))
|
||||
return -ENODEV;
|
||||
|
||||
if (HAS_DISPLAY(i915) && INTEL_DISPLAY_ENABLED(i915)) {
|
||||
ret = drm_vblank_init(&i915->drm,
|
||||
INTEL_NUM_PIPES(i915));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
intel_bios_init(i915);
|
||||
|
||||
ret = intel_vga_register(i915);
|
||||
if (ret)
|
||||
goto cleanup_bios;
|
||||
|
||||
intel_power_domains_init_hw(i915, false);
|
||||
|
||||
intel_csr_ucode_init(i915);
|
||||
|
||||
ret = intel_modeset_init_noirq(i915);
|
||||
if (ret)
|
||||
goto cleanup_vga_client_pw_domain_csr;
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_vga_client_pw_domain_csr:
|
||||
intel_csr_ucode_fini(i915);
|
||||
intel_power_domains_driver_remove(i915);
|
||||
intel_vga_unregister(i915);
|
||||
cleanup_bios:
|
||||
intel_bios_driver_remove(i915);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* part #2: call after irq install */
|
||||
static int i915_driver_modeset_probe(struct drm_i915_private *i915)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Important: The output setup functions called by modeset_init need
|
||||
* working irqs for e.g. gmbus and dp aux transfers. */
|
||||
ret = intel_modeset_init(i915);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = i915_gem_init(i915);
|
||||
if (ret)
|
||||
goto cleanup_modeset;
|
||||
|
||||
intel_overlay_setup(i915);
|
||||
|
||||
if (!HAS_DISPLAY(i915) || !INTEL_DISPLAY_ENABLED(i915))
|
||||
return 0;
|
||||
|
||||
ret = intel_fbdev_init(&i915->drm);
|
||||
if (ret)
|
||||
goto cleanup_gem;
|
||||
|
||||
/* Only enable hotplug handling once the fbdev is fully set up. */
|
||||
intel_hpd_init(i915);
|
||||
|
||||
intel_init_ipc(i915);
|
||||
|
||||
intel_psr_set_force_mode_changed(i915->psr.dp);
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_gem:
|
||||
i915_gem_suspend(i915);
|
||||
i915_gem_driver_remove(i915);
|
||||
i915_gem_driver_release(i915);
|
||||
cleanup_modeset:
|
||||
/* FIXME */
|
||||
intel_modeset_driver_remove(i915);
|
||||
intel_irq_uninstall(i915);
|
||||
intel_modeset_driver_remove_noirq(i915);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* part #1: call before irq uninstall */
|
||||
static void i915_driver_modeset_remove(struct drm_i915_private *i915)
|
||||
{
|
||||
intel_modeset_driver_remove(i915);
|
||||
}
|
||||
|
||||
/* part #2: call after irq uninstall */
|
||||
static void i915_driver_modeset_remove_noirq(struct drm_i915_private *i915)
|
||||
{
|
||||
intel_csr_ucode_fini(i915);
|
||||
|
||||
intel_power_domains_driver_remove(i915);
|
||||
|
||||
intel_vga_unregister(i915);
|
||||
|
||||
intel_bios_driver_remove(i915);
|
||||
}
|
||||
|
||||
static void intel_init_dpio(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
/*
|
||||
* IOSF_PORT_DPIO is used for VLV x2 PHY (DP/HDMI B and C),
|
||||
* CHV x1 PHY (DP/HDMI D)
|
||||
* IOSF_PORT_DPIO_2 is used for CHV x2 PHY (DP/HDMI B and C)
|
||||
*/
|
||||
if (IS_CHERRYVIEW(dev_priv)) {
|
||||
DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO_2;
|
||||
DPIO_PHY_IOSF_PORT(DPIO_PHY1) = IOSF_PORT_DPIO;
|
||||
} else if (IS_VALLEYVIEW(dev_priv)) {
|
||||
DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO;
|
||||
}
|
||||
}
|
||||
|
||||
static int i915_workqueues_init(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
/*
|
||||
@ -463,7 +343,6 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv)
|
||||
intel_detect_pch(dev_priv);
|
||||
|
||||
intel_pm_setup(dev_priv);
|
||||
intel_init_dpio(dev_priv);
|
||||
ret = intel_power_domains_init(dev_priv);
|
||||
if (ret < 0)
|
||||
goto err_gem;
|
||||
@ -798,7 +677,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
|
||||
drm_err(&dev_priv->drm,
|
||||
"Failed to register driver for userspace access!\n");
|
||||
|
||||
if (HAS_DISPLAY(dev_priv) && INTEL_DISPLAY_ENABLED(dev_priv)) {
|
||||
if (HAS_DISPLAY(dev_priv)) {
|
||||
/* Must be done after probing outputs */
|
||||
intel_opregion_register(dev_priv);
|
||||
acpi_video_register();
|
||||
@ -821,7 +700,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
|
||||
* We need to coordinate the hotplugs with the asynchronous fbdev
|
||||
* configuration, for which we use the fbdev->async_cookie.
|
||||
*/
|
||||
if (HAS_DISPLAY(dev_priv) && INTEL_DISPLAY_ENABLED(dev_priv))
|
||||
if (HAS_DISPLAY(dev_priv))
|
||||
drm_kms_helper_poll_init(dev);
|
||||
|
||||
intel_power_domains_enable(dev_priv);
|
||||
@ -988,7 +867,7 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
if (ret < 0)
|
||||
goto out_cleanup_mmio;
|
||||
|
||||
ret = i915_driver_modeset_probe_noirq(i915);
|
||||
ret = intel_modeset_init_noirq(i915);
|
||||
if (ret < 0)
|
||||
goto out_cleanup_hw;
|
||||
|
||||
@ -996,10 +875,18 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
if (ret)
|
||||
goto out_cleanup_modeset;
|
||||
|
||||
ret = i915_driver_modeset_probe(i915);
|
||||
if (ret < 0)
|
||||
ret = intel_modeset_init_nogem(i915);
|
||||
if (ret)
|
||||
goto out_cleanup_irq;
|
||||
|
||||
ret = i915_gem_init(i915);
|
||||
if (ret)
|
||||
goto out_cleanup_modeset2;
|
||||
|
||||
ret = intel_modeset_init(i915);
|
||||
if (ret)
|
||||
goto out_cleanup_gem;
|
||||
|
||||
i915_driver_register(i915);
|
||||
|
||||
enable_rpm_wakeref_asserts(&i915->runtime_pm);
|
||||
@ -1010,10 +897,20 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
return 0;
|
||||
|
||||
out_cleanup_gem:
|
||||
i915_gem_suspend(i915);
|
||||
i915_gem_driver_remove(i915);
|
||||
i915_gem_driver_release(i915);
|
||||
out_cleanup_modeset2:
|
||||
/* FIXME clean up the error path */
|
||||
intel_modeset_driver_remove(i915);
|
||||
intel_irq_uninstall(i915);
|
||||
intel_modeset_driver_remove_noirq(i915);
|
||||
goto out_cleanup_modeset;
|
||||
out_cleanup_irq:
|
||||
intel_irq_uninstall(i915);
|
||||
out_cleanup_modeset:
|
||||
i915_driver_modeset_remove_noirq(i915);
|
||||
intel_modeset_driver_remove_nogem(i915);
|
||||
out_cleanup_hw:
|
||||
i915_driver_hw_remove(i915);
|
||||
intel_memory_regions_driver_release(i915);
|
||||
@ -1045,7 +942,7 @@ void i915_driver_remove(struct drm_i915_private *i915)
|
||||
|
||||
intel_gvt_driver_remove(i915);
|
||||
|
||||
i915_driver_modeset_remove(i915);
|
||||
intel_modeset_driver_remove(i915);
|
||||
|
||||
intel_irq_uninstall(i915);
|
||||
|
||||
@ -1054,7 +951,7 @@ void i915_driver_remove(struct drm_i915_private *i915)
|
||||
i915_reset_error_state(i915);
|
||||
i915_gem_driver_remove(i915);
|
||||
|
||||
i915_driver_modeset_remove_noirq(i915);
|
||||
intel_modeset_driver_remove_nogem(i915);
|
||||
|
||||
i915_driver_hw_remove(i915);
|
||||
|
||||
|
@ -108,18 +108,11 @@
|
||||
|
||||
#define DRIVER_NAME "i915"
|
||||
#define DRIVER_DESC "Intel Graphics"
|
||||
#define DRIVER_DATE "20200824"
|
||||
#define DRIVER_TIMESTAMP 1598293597
|
||||
#define DRIVER_DATE "20200917"
|
||||
#define DRIVER_TIMESTAMP 1600375437
|
||||
|
||||
struct drm_i915_gem_object;
|
||||
|
||||
/*
|
||||
* The code assumes that the hpd_pins below have consecutive values and
|
||||
* starting with HPD_PORT_A, the HPD pin associated with any port can be
|
||||
* retrieved by adding the corresponding port (or phy) enum value to
|
||||
* HPD_PORT_A in most cases. For example:
|
||||
* HPD_PORT_C = HPD_PORT_A + PHY_C - PHY_A
|
||||
*/
|
||||
enum hpd_pin {
|
||||
HPD_NONE = 0,
|
||||
HPD_TV = HPD_NONE, /* TV is known to be unreliable */
|
||||
@ -131,10 +124,12 @@ enum hpd_pin {
|
||||
HPD_PORT_C,
|
||||
HPD_PORT_D,
|
||||
HPD_PORT_E,
|
||||
HPD_PORT_F,
|
||||
HPD_PORT_G,
|
||||
HPD_PORT_H,
|
||||
HPD_PORT_I,
|
||||
HPD_PORT_TC1,
|
||||
HPD_PORT_TC2,
|
||||
HPD_PORT_TC3,
|
||||
HPD_PORT_TC4,
|
||||
HPD_PORT_TC5,
|
||||
HPD_PORT_TC6,
|
||||
|
||||
HPD_NUM_PINS
|
||||
};
|
||||
@ -537,13 +532,9 @@ struct intel_gmbus {
|
||||
|
||||
struct i915_suspend_saved_registers {
|
||||
u32 saveDSPARB;
|
||||
u32 saveFBC_CONTROL;
|
||||
u32 saveCACHE_MODE_0;
|
||||
u32 saveMI_ARB_STATE;
|
||||
u32 saveSWF0[16];
|
||||
u32 saveSWF1[16];
|
||||
u32 saveSWF3[3];
|
||||
u32 savePCH_PORT_HOTPLUG;
|
||||
u16 saveGCDGMBUS;
|
||||
};
|
||||
|
||||
@ -1020,8 +1011,6 @@ struct drm_i915_private {
|
||||
*/
|
||||
u8 active_pipes;
|
||||
|
||||
int dpio_phy_iosf_port[I915_NUM_PHYS_VLV];
|
||||
|
||||
struct i915_wa_list gt_wa_list;
|
||||
|
||||
struct i915_frontbuffer_tracking fb_tracking;
|
||||
@ -1572,12 +1561,41 @@ extern const struct i915_rev_steppings kbl_revids[];
|
||||
#define IS_EHL_REVID(p, since, until) \
|
||||
(IS_ELKHARTLAKE(p) && IS_REVID(p, since, until))
|
||||
|
||||
#define TGL_REVID_A0 0x0
|
||||
#define TGL_REVID_B0 0x1
|
||||
#define TGL_REVID_C0 0x2
|
||||
enum {
|
||||
TGL_REVID_A0,
|
||||
TGL_REVID_B0,
|
||||
TGL_REVID_B1,
|
||||
TGL_REVID_C0,
|
||||
TGL_REVID_D0,
|
||||
};
|
||||
|
||||
#define IS_TGL_REVID(p, since, until) \
|
||||
(IS_TIGERLAKE(p) && IS_REVID(p, since, until))
|
||||
extern const struct i915_rev_steppings tgl_uy_revids[];
|
||||
extern const struct i915_rev_steppings tgl_revids[];
|
||||
|
||||
static inline const struct i915_rev_steppings *
|
||||
tgl_revids_get(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv))
|
||||
return tgl_uy_revids;
|
||||
else
|
||||
return tgl_revids;
|
||||
}
|
||||
|
||||
#define IS_TGL_DISP_REVID(p, since, until) \
|
||||
(IS_TIGERLAKE(p) && \
|
||||
tgl_revids_get(p)->disp_stepping >= (since) && \
|
||||
tgl_revids_get(p)->disp_stepping <= (until))
|
||||
|
||||
#define IS_TGL_UY_GT_REVID(p, since, until) \
|
||||
((IS_TGL_U(p) || IS_TGL_Y(p)) && \
|
||||
tgl_uy_revids->gt_stepping >= (since) && \
|
||||
tgl_uy_revids->gt_stepping <= (until))
|
||||
|
||||
#define IS_TGL_GT_REVID(p, since, until) \
|
||||
(IS_TIGERLAKE(p) && \
|
||||
!(IS_TGL_U(p) || IS_TGL_Y(p)) && \
|
||||
tgl_revids->gt_stepping >= (since) && \
|
||||
tgl_revids->gt_stepping <= (until))
|
||||
|
||||
#define RKL_REVID_A0 0x0
|
||||
#define RKL_REVID_B0 0x1
|
||||
|
@ -132,40 +132,24 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = {
|
||||
};
|
||||
|
||||
static const u32 hpd_gen11[HPD_NUM_PINS] = {
|
||||
[HPD_PORT_C] = GEN11_TC1_HOTPLUG | GEN11_TBT1_HOTPLUG,
|
||||
[HPD_PORT_D] = GEN11_TC2_HOTPLUG | GEN11_TBT2_HOTPLUG,
|
||||
[HPD_PORT_E] = GEN11_TC3_HOTPLUG | GEN11_TBT3_HOTPLUG,
|
||||
[HPD_PORT_F] = GEN11_TC4_HOTPLUG | GEN11_TBT4_HOTPLUG,
|
||||
};
|
||||
|
||||
static const u32 hpd_gen12[HPD_NUM_PINS] = {
|
||||
[HPD_PORT_D] = GEN11_TC1_HOTPLUG | GEN11_TBT1_HOTPLUG,
|
||||
[HPD_PORT_E] = GEN11_TC2_HOTPLUG | GEN11_TBT2_HOTPLUG,
|
||||
[HPD_PORT_F] = GEN11_TC3_HOTPLUG | GEN11_TBT3_HOTPLUG,
|
||||
[HPD_PORT_G] = GEN11_TC4_HOTPLUG | GEN11_TBT4_HOTPLUG,
|
||||
[HPD_PORT_H] = GEN12_TC5_HOTPLUG | GEN12_TBT5_HOTPLUG,
|
||||
[HPD_PORT_I] = GEN12_TC6_HOTPLUG | GEN12_TBT6_HOTPLUG,
|
||||
[HPD_PORT_TC1] = GEN11_TC_HOTPLUG(PORT_TC1) | GEN11_TBT_HOTPLUG(PORT_TC1),
|
||||
[HPD_PORT_TC2] = GEN11_TC_HOTPLUG(PORT_TC2) | GEN11_TBT_HOTPLUG(PORT_TC2),
|
||||
[HPD_PORT_TC3] = GEN11_TC_HOTPLUG(PORT_TC3) | GEN11_TBT_HOTPLUG(PORT_TC3),
|
||||
[HPD_PORT_TC4] = GEN11_TC_HOTPLUG(PORT_TC4) | GEN11_TBT_HOTPLUG(PORT_TC4),
|
||||
[HPD_PORT_TC5] = GEN11_TC_HOTPLUG(PORT_TC5) | GEN11_TBT_HOTPLUG(PORT_TC5),
|
||||
[HPD_PORT_TC6] = GEN11_TC_HOTPLUG(PORT_TC6) | GEN11_TBT_HOTPLUG(PORT_TC6),
|
||||
};
|
||||
|
||||
static const u32 hpd_icp[HPD_NUM_PINS] = {
|
||||
[HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(PORT_A),
|
||||
[HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(PORT_B),
|
||||
[HPD_PORT_C] = SDE_TC_HOTPLUG_ICP(PORT_TC1),
|
||||
[HPD_PORT_D] = SDE_TC_HOTPLUG_ICP(PORT_TC2),
|
||||
[HPD_PORT_E] = SDE_TC_HOTPLUG_ICP(PORT_TC3),
|
||||
[HPD_PORT_F] = SDE_TC_HOTPLUG_ICP(PORT_TC4),
|
||||
};
|
||||
|
||||
static const u32 hpd_tgp[HPD_NUM_PINS] = {
|
||||
[HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(PORT_A),
|
||||
[HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(PORT_B),
|
||||
[HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(PORT_C),
|
||||
[HPD_PORT_D] = SDE_TC_HOTPLUG_ICP(PORT_TC1),
|
||||
[HPD_PORT_E] = SDE_TC_HOTPLUG_ICP(PORT_TC2),
|
||||
[HPD_PORT_F] = SDE_TC_HOTPLUG_ICP(PORT_TC3),
|
||||
[HPD_PORT_G] = SDE_TC_HOTPLUG_ICP(PORT_TC4),
|
||||
[HPD_PORT_H] = SDE_TC_HOTPLUG_ICP(PORT_TC5),
|
||||
[HPD_PORT_I] = SDE_TC_HOTPLUG_ICP(PORT_TC6),
|
||||
[HPD_PORT_TC1] = SDE_TC_HOTPLUG_ICP(PORT_TC1),
|
||||
[HPD_PORT_TC2] = SDE_TC_HOTPLUG_ICP(PORT_TC2),
|
||||
[HPD_PORT_TC3] = SDE_TC_HOTPLUG_ICP(PORT_TC3),
|
||||
[HPD_PORT_TC4] = SDE_TC_HOTPLUG_ICP(PORT_TC4),
|
||||
[HPD_PORT_TC5] = SDE_TC_HOTPLUG_ICP(PORT_TC5),
|
||||
[HPD_PORT_TC6] = SDE_TC_HOTPLUG_ICP(PORT_TC6),
|
||||
};
|
||||
|
||||
static void intel_hpd_init_pins(struct drm_i915_private *dev_priv)
|
||||
@ -181,9 +165,7 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv)
|
||||
return;
|
||||
}
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 12)
|
||||
hpd->hpd = hpd_gen12;
|
||||
else if (INTEL_GEN(dev_priv) >= 11)
|
||||
if (INTEL_GEN(dev_priv) >= 11)
|
||||
hpd->hpd = hpd_gen11;
|
||||
else if (IS_GEN9_LP(dev_priv))
|
||||
hpd->hpd = hpd_bxt;
|
||||
@ -197,9 +179,8 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv)
|
||||
if (!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv))
|
||||
return;
|
||||
|
||||
if (HAS_PCH_TGP(dev_priv) || HAS_PCH_JSP(dev_priv))
|
||||
hpd->pch_hpd = hpd_tgp;
|
||||
else if (HAS_PCH_ICP(dev_priv) || HAS_PCH_MCC(dev_priv))
|
||||
if (HAS_PCH_TGP(dev_priv) || HAS_PCH_JSP(dev_priv) ||
|
||||
HAS_PCH_ICP(dev_priv) || HAS_PCH_MCC(dev_priv))
|
||||
hpd->pch_hpd = hpd_icp;
|
||||
else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_SPT(dev_priv))
|
||||
hpd->pch_hpd = hpd_spt;
|
||||
@ -1049,33 +1030,17 @@ static void ivb_parity_work(struct work_struct *work)
|
||||
static bool gen11_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
|
||||
{
|
||||
switch (pin) {
|
||||
case HPD_PORT_C:
|
||||
case HPD_PORT_TC1:
|
||||
return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC1);
|
||||
case HPD_PORT_D:
|
||||
case HPD_PORT_TC2:
|
||||
return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC2);
|
||||
case HPD_PORT_E:
|
||||
case HPD_PORT_TC3:
|
||||
return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC3);
|
||||
case HPD_PORT_F:
|
||||
case HPD_PORT_TC4:
|
||||
return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC4);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool gen12_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
|
||||
{
|
||||
switch (pin) {
|
||||
case HPD_PORT_D:
|
||||
return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC1);
|
||||
case HPD_PORT_E:
|
||||
return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC2);
|
||||
case HPD_PORT_F:
|
||||
return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC3);
|
||||
case HPD_PORT_G:
|
||||
return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC4);
|
||||
case HPD_PORT_H:
|
||||
case HPD_PORT_TC5:
|
||||
return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC5);
|
||||
case HPD_PORT_I:
|
||||
case HPD_PORT_TC6:
|
||||
return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC6);
|
||||
default:
|
||||
return false;
|
||||
@ -1113,33 +1078,17 @@ static bool icp_ddi_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
|
||||
static bool icp_tc_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
|
||||
{
|
||||
switch (pin) {
|
||||
case HPD_PORT_C:
|
||||
case HPD_PORT_TC1:
|
||||
return val & ICP_TC_HPD_LONG_DETECT(PORT_TC1);
|
||||
case HPD_PORT_D:
|
||||
case HPD_PORT_TC2:
|
||||
return val & ICP_TC_HPD_LONG_DETECT(PORT_TC2);
|
||||
case HPD_PORT_E:
|
||||
case HPD_PORT_TC3:
|
||||
return val & ICP_TC_HPD_LONG_DETECT(PORT_TC3);
|
||||
case HPD_PORT_F:
|
||||
case HPD_PORT_TC4:
|
||||
return val & ICP_TC_HPD_LONG_DETECT(PORT_TC4);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool tgp_tc_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
|
||||
{
|
||||
switch (pin) {
|
||||
case HPD_PORT_D:
|
||||
return val & ICP_TC_HPD_LONG_DETECT(PORT_TC1);
|
||||
case HPD_PORT_E:
|
||||
return val & ICP_TC_HPD_LONG_DETECT(PORT_TC2);
|
||||
case HPD_PORT_F:
|
||||
return val & ICP_TC_HPD_LONG_DETECT(PORT_TC3);
|
||||
case HPD_PORT_G:
|
||||
return val & ICP_TC_HPD_LONG_DETECT(PORT_TC4);
|
||||
case HPD_PORT_H:
|
||||
case HPD_PORT_TC5:
|
||||
return val & ICP_TC_HPD_LONG_DETECT(PORT_TC5);
|
||||
case HPD_PORT_I:
|
||||
case HPD_PORT_TC6:
|
||||
return val & ICP_TC_HPD_LONG_DETECT(PORT_TC6);
|
||||
default:
|
||||
return false;
|
||||
@ -1893,19 +1842,16 @@ static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
|
||||
{
|
||||
u32 ddi_hotplug_trigger, tc_hotplug_trigger;
|
||||
u32 pin_mask = 0, long_mask = 0;
|
||||
bool (*tc_port_hotplug_long_detect)(enum hpd_pin pin, u32 val);
|
||||
|
||||
if (HAS_PCH_TGP(dev_priv)) {
|
||||
ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_TGP;
|
||||
tc_hotplug_trigger = pch_iir & SDE_TC_MASK_TGP;
|
||||
tc_port_hotplug_long_detect = tgp_tc_port_hotplug_long_detect;
|
||||
} else if (HAS_PCH_JSP(dev_priv)) {
|
||||
ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_TGP;
|
||||
tc_hotplug_trigger = 0;
|
||||
} else if (HAS_PCH_MCC(dev_priv)) {
|
||||
ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP;
|
||||
tc_hotplug_trigger = pch_iir & SDE_TC_HOTPLUG_ICP(PORT_TC1);
|
||||
tc_port_hotplug_long_detect = icp_tc_port_hotplug_long_detect;
|
||||
} else {
|
||||
drm_WARN(&dev_priv->drm, !HAS_PCH_ICP(dev_priv),
|
||||
"Unrecognized PCH type 0x%x\n",
|
||||
@ -1913,7 +1859,6 @@ static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
|
||||
|
||||
ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP;
|
||||
tc_hotplug_trigger = pch_iir & SDE_TC_MASK_ICP;
|
||||
tc_port_hotplug_long_detect = icp_tc_port_hotplug_long_detect;
|
||||
}
|
||||
|
||||
if (ddi_hotplug_trigger) {
|
||||
@ -1937,7 +1882,7 @@ static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
|
||||
intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
|
||||
tc_hotplug_trigger, dig_hotplug_reg,
|
||||
dev_priv->hotplug.pch_hpd,
|
||||
tc_port_hotplug_long_detect);
|
||||
icp_tc_port_hotplug_long_detect);
|
||||
}
|
||||
|
||||
if (pin_mask)
|
||||
@ -2185,12 +2130,6 @@ static void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir)
|
||||
u32 pin_mask = 0, long_mask = 0;
|
||||
u32 trigger_tc = iir & GEN11_DE_TC_HOTPLUG_MASK;
|
||||
u32 trigger_tbt = iir & GEN11_DE_TBT_HOTPLUG_MASK;
|
||||
long_pulse_detect_func long_pulse_detect;
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 12)
|
||||
long_pulse_detect = gen12_port_hotplug_long_detect;
|
||||
else
|
||||
long_pulse_detect = gen11_port_hotplug_long_detect;
|
||||
|
||||
if (trigger_tc) {
|
||||
u32 dig_hotplug_reg;
|
||||
@ -2201,7 +2140,7 @@ static void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir)
|
||||
intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
|
||||
trigger_tc, dig_hotplug_reg,
|
||||
dev_priv->hotplug.hpd,
|
||||
long_pulse_detect);
|
||||
gen11_port_hotplug_long_detect);
|
||||
}
|
||||
|
||||
if (trigger_tbt) {
|
||||
@ -2213,7 +2152,7 @@ static void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir)
|
||||
intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
|
||||
trigger_tbt, dig_hotplug_reg,
|
||||
dev_priv->hotplug.hpd,
|
||||
long_pulse_detect);
|
||||
gen11_port_hotplug_long_detect);
|
||||
}
|
||||
|
||||
if (pin_mask)
|
||||
@ -3048,6 +2987,18 @@ static u32 intel_hpd_enabled_irqs(struct drm_i915_private *dev_priv,
|
||||
return enabled_irqs;
|
||||
}
|
||||
|
||||
static u32 intel_hpd_hotplug_irqs(struct drm_i915_private *dev_priv,
|
||||
const u32 hpd[HPD_NUM_PINS])
|
||||
{
|
||||
struct intel_encoder *encoder;
|
||||
u32 hotplug_irqs = 0;
|
||||
|
||||
for_each_intel_encoder(&dev_priv->drm, encoder)
|
||||
hotplug_irqs |= hpd[encoder->hpd_pin];
|
||||
|
||||
return hotplug_irqs;
|
||||
}
|
||||
|
||||
static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
u32 hotplug;
|
||||
@ -3077,50 +3028,50 @@ static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
u32 hotplug_irqs, enabled_irqs;
|
||||
|
||||
if (HAS_PCH_IBX(dev_priv))
|
||||
hotplug_irqs = SDE_HOTPLUG_MASK;
|
||||
else
|
||||
hotplug_irqs = SDE_HOTPLUG_MASK_CPT;
|
||||
|
||||
enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.pch_hpd);
|
||||
hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->hotplug.pch_hpd);
|
||||
|
||||
ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
|
||||
|
||||
ibx_hpd_detection_setup(dev_priv);
|
||||
}
|
||||
|
||||
static void icp_hpd_detection_setup(struct drm_i915_private *dev_priv,
|
||||
u32 ddi_hotplug_enable_mask,
|
||||
u32 tc_hotplug_enable_mask)
|
||||
static void icp_ddi_hpd_detection_setup(struct drm_i915_private *dev_priv,
|
||||
u32 enable_mask)
|
||||
{
|
||||
u32 hotplug;
|
||||
|
||||
hotplug = I915_READ(SHOTPLUG_CTL_DDI);
|
||||
hotplug |= ddi_hotplug_enable_mask;
|
||||
hotplug |= enable_mask;
|
||||
I915_WRITE(SHOTPLUG_CTL_DDI, hotplug);
|
||||
}
|
||||
|
||||
if (tc_hotplug_enable_mask) {
|
||||
hotplug = I915_READ(SHOTPLUG_CTL_TC);
|
||||
hotplug |= tc_hotplug_enable_mask;
|
||||
I915_WRITE(SHOTPLUG_CTL_TC, hotplug);
|
||||
}
|
||||
static void icp_tc_hpd_detection_setup(struct drm_i915_private *dev_priv,
|
||||
u32 enable_mask)
|
||||
{
|
||||
u32 hotplug;
|
||||
|
||||
hotplug = I915_READ(SHOTPLUG_CTL_TC);
|
||||
hotplug |= enable_mask;
|
||||
I915_WRITE(SHOTPLUG_CTL_TC, hotplug);
|
||||
}
|
||||
|
||||
static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv,
|
||||
u32 sde_ddi_mask, u32 sde_tc_mask,
|
||||
u32 ddi_enable_mask, u32 tc_enable_mask)
|
||||
{
|
||||
u32 hotplug_irqs, enabled_irqs;
|
||||
|
||||
hotplug_irqs = sde_ddi_mask | sde_tc_mask;
|
||||
enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.pch_hpd);
|
||||
hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->hotplug.pch_hpd);
|
||||
|
||||
if (INTEL_PCH_TYPE(dev_priv) <= PCH_TGP)
|
||||
I915_WRITE(SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ);
|
||||
|
||||
ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
|
||||
|
||||
icp_hpd_detection_setup(dev_priv, ddi_enable_mask, tc_enable_mask);
|
||||
icp_ddi_hpd_detection_setup(dev_priv, ddi_enable_mask);
|
||||
if (tc_enable_mask)
|
||||
icp_tc_hpd_detection_setup(dev_priv, tc_enable_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3130,7 +3081,6 @@ static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv,
|
||||
static void mcc_hpd_irq_setup(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
icp_hpd_irq_setup(dev_priv,
|
||||
SDE_DDI_MASK_ICP, SDE_TC_HOTPLUG_ICP(PORT_TC1),
|
||||
ICP_DDI_HPD_ENABLE_MASK, ICP_TC_HPD_ENABLE(PORT_TC1));
|
||||
}
|
||||
|
||||
@ -3142,7 +3092,6 @@ static void mcc_hpd_irq_setup(struct drm_i915_private *dev_priv)
|
||||
static void jsp_hpd_irq_setup(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
icp_hpd_irq_setup(dev_priv,
|
||||
SDE_DDI_MASK_TGP, 0,
|
||||
TGP_DDI_HPD_ENABLE_MASK, 0);
|
||||
}
|
||||
|
||||
@ -3154,14 +3103,18 @@ static void gen11_hpd_detection_setup(struct drm_i915_private *dev_priv)
|
||||
hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) |
|
||||
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) |
|
||||
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) |
|
||||
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4);
|
||||
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4) |
|
||||
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC5) |
|
||||
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC6);
|
||||
I915_WRITE(GEN11_TC_HOTPLUG_CTL, hotplug);
|
||||
|
||||
hotplug = I915_READ(GEN11_TBT_HOTPLUG_CTL);
|
||||
hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) |
|
||||
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) |
|
||||
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) |
|
||||
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4);
|
||||
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4) |
|
||||
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC5) |
|
||||
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC6);
|
||||
I915_WRITE(GEN11_TBT_HOTPLUG_CTL, hotplug);
|
||||
}
|
||||
|
||||
@ -3171,7 +3124,7 @@ static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv)
|
||||
u32 val;
|
||||
|
||||
enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.hpd);
|
||||
hotplug_irqs = GEN11_DE_TC_HOTPLUG_MASK | GEN11_DE_TBT_HOTPLUG_MASK;
|
||||
hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->hotplug.hpd);
|
||||
|
||||
val = I915_READ(GEN11_DE_HPD_IMR);
|
||||
val &= ~hotplug_irqs;
|
||||
@ -3182,10 +3135,10 @@ static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv)
|
||||
gen11_hpd_detection_setup(dev_priv);
|
||||
|
||||
if (INTEL_PCH_TYPE(dev_priv) >= PCH_TGP)
|
||||
icp_hpd_irq_setup(dev_priv, SDE_DDI_MASK_TGP, SDE_TC_MASK_TGP,
|
||||
icp_hpd_irq_setup(dev_priv,
|
||||
TGP_DDI_HPD_ENABLE_MASK, TGP_TC_HPD_ENABLE_MASK);
|
||||
else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
|
||||
icp_hpd_irq_setup(dev_priv, SDE_DDI_MASK_ICP, SDE_TC_MASK_ICP,
|
||||
icp_hpd_irq_setup(dev_priv,
|
||||
ICP_DDI_HPD_ENABLE_MASK, ICP_TC_HPD_ENABLE_MASK);
|
||||
}
|
||||
|
||||
@ -3221,8 +3174,8 @@ static void spt_hpd_irq_setup(struct drm_i915_private *dev_priv)
|
||||
if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP)
|
||||
I915_WRITE(SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ);
|
||||
|
||||
hotplug_irqs = SDE_HOTPLUG_MASK_SPT;
|
||||
enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.pch_hpd);
|
||||
hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->hotplug.pch_hpd);
|
||||
|
||||
ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
|
||||
|
||||
@ -3249,22 +3202,13 @@ static void ilk_hpd_irq_setup(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
u32 hotplug_irqs, enabled_irqs;
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 8) {
|
||||
hotplug_irqs = GEN8_PORT_DP_A_HOTPLUG;
|
||||
enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.hpd);
|
||||
enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.hpd);
|
||||
hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->hotplug.hpd);
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 8)
|
||||
bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
|
||||
} else if (INTEL_GEN(dev_priv) >= 7) {
|
||||
hotplug_irqs = DE_DP_A_HOTPLUG_IVB;
|
||||
enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.hpd);
|
||||
|
||||
else
|
||||
ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs);
|
||||
} else {
|
||||
hotplug_irqs = DE_DP_A_HOTPLUG;
|
||||
enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.hpd);
|
||||
|
||||
ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs);
|
||||
}
|
||||
|
||||
ilk_hpd_detection_setup(dev_priv);
|
||||
|
||||
@ -3313,7 +3257,7 @@ static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv)
|
||||
u32 hotplug_irqs, enabled_irqs;
|
||||
|
||||
enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.hpd);
|
||||
hotplug_irqs = BXT_DE_PORT_HOTPLUG_MASK;
|
||||
hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->hotplug.hpd);
|
||||
|
||||
bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
|
||||
|
||||
@ -3534,17 +3478,18 @@ static void icp_irq_postinstall(struct drm_i915_private *dev_priv)
|
||||
gen3_assert_iir_is_zero(&dev_priv->uncore, SDEIIR);
|
||||
I915_WRITE(SDEIMR, ~mask);
|
||||
|
||||
if (HAS_PCH_TGP(dev_priv))
|
||||
icp_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK,
|
||||
TGP_TC_HPD_ENABLE_MASK);
|
||||
else if (HAS_PCH_JSP(dev_priv))
|
||||
icp_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK, 0);
|
||||
else if (HAS_PCH_MCC(dev_priv))
|
||||
icp_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK,
|
||||
ICP_TC_HPD_ENABLE(PORT_TC1));
|
||||
else
|
||||
icp_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK,
|
||||
ICP_TC_HPD_ENABLE_MASK);
|
||||
if (HAS_PCH_TGP(dev_priv)) {
|
||||
icp_ddi_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK);
|
||||
icp_tc_hpd_detection_setup(dev_priv, TGP_TC_HPD_ENABLE_MASK);
|
||||
} else if (HAS_PCH_JSP(dev_priv)) {
|
||||
icp_ddi_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK);
|
||||
} else if (HAS_PCH_MCC(dev_priv)) {
|
||||
icp_ddi_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK);
|
||||
icp_tc_hpd_detection_setup(dev_priv, ICP_TC_HPD_ENABLE(PORT_TC1));
|
||||
} else {
|
||||
icp_ddi_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK);
|
||||
icp_tc_hpd_detection_setup(dev_priv, ICP_TC_HPD_ENABLE_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
static void gen11_irq_postinstall(struct drm_i915_private *dev_priv)
|
||||
|
@ -1382,7 +1382,6 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
|
||||
#define DPIO_CMNRST (1 << 0)
|
||||
|
||||
#define DPIO_PHY(pipe) ((pipe) >> 1)
|
||||
#define DPIO_PHY_IOSF_PORT(phy) (dev_priv->dpio_phy_iosf_port[phy])
|
||||
|
||||
/*
|
||||
* Per pipe/PLL DPIO regs
|
||||
@ -7760,32 +7759,20 @@ enum {
|
||||
#define GEN11_DE_HPD_IMR _MMIO(0x44474)
|
||||
#define GEN11_DE_HPD_IIR _MMIO(0x44478)
|
||||
#define GEN11_DE_HPD_IER _MMIO(0x4447c)
|
||||
#define GEN12_TC6_HOTPLUG (1 << 21)
|
||||
#define GEN12_TC5_HOTPLUG (1 << 20)
|
||||
#define GEN11_TC4_HOTPLUG (1 << 19)
|
||||
#define GEN11_TC3_HOTPLUG (1 << 18)
|
||||
#define GEN11_TC2_HOTPLUG (1 << 17)
|
||||
#define GEN11_TC1_HOTPLUG (1 << 16)
|
||||
#define GEN11_TC_HOTPLUG(tc_port) (1 << ((tc_port) + 16))
|
||||
#define GEN11_DE_TC_HOTPLUG_MASK (GEN12_TC6_HOTPLUG | \
|
||||
GEN12_TC5_HOTPLUG | \
|
||||
GEN11_TC4_HOTPLUG | \
|
||||
GEN11_TC3_HOTPLUG | \
|
||||
GEN11_TC2_HOTPLUG | \
|
||||
GEN11_TC1_HOTPLUG)
|
||||
#define GEN12_TBT6_HOTPLUG (1 << 5)
|
||||
#define GEN12_TBT5_HOTPLUG (1 << 4)
|
||||
#define GEN11_TBT4_HOTPLUG (1 << 3)
|
||||
#define GEN11_TBT3_HOTPLUG (1 << 2)
|
||||
#define GEN11_TBT2_HOTPLUG (1 << 1)
|
||||
#define GEN11_TBT1_HOTPLUG (1 << 0)
|
||||
#define GEN11_DE_TC_HOTPLUG_MASK (GEN11_TC_HOTPLUG(PORT_TC6) | \
|
||||
GEN11_TC_HOTPLUG(PORT_TC5) | \
|
||||
GEN11_TC_HOTPLUG(PORT_TC4) | \
|
||||
GEN11_TC_HOTPLUG(PORT_TC3) | \
|
||||
GEN11_TC_HOTPLUG(PORT_TC2) | \
|
||||
GEN11_TC_HOTPLUG(PORT_TC1))
|
||||
#define GEN11_TBT_HOTPLUG(tc_port) (1 << (tc_port))
|
||||
#define GEN11_DE_TBT_HOTPLUG_MASK (GEN12_TBT6_HOTPLUG | \
|
||||
GEN12_TBT5_HOTPLUG | \
|
||||
GEN11_TBT4_HOTPLUG | \
|
||||
GEN11_TBT3_HOTPLUG | \
|
||||
GEN11_TBT2_HOTPLUG | \
|
||||
GEN11_TBT1_HOTPLUG)
|
||||
#define GEN11_DE_TBT_HOTPLUG_MASK (GEN11_TBT_HOTPLUG(PORT_TC6) | \
|
||||
GEN11_TBT_HOTPLUG(PORT_TC5) | \
|
||||
GEN11_TBT_HOTPLUG(PORT_TC4) | \
|
||||
GEN11_TBT_HOTPLUG(PORT_TC3) | \
|
||||
GEN11_TBT_HOTPLUG(PORT_TC2) | \
|
||||
GEN11_TBT_HOTPLUG(PORT_TC1))
|
||||
|
||||
#define GEN11_TBT_HOTPLUG_CTL _MMIO(0x44030)
|
||||
#define GEN11_TC_HOTPLUG_CTL _MMIO(0x44038)
|
||||
@ -9315,6 +9302,7 @@ enum {
|
||||
#define GEN11_LSN_UNSLCVC_GAFS_HALF_SF_MAXALLOC (1 << 7)
|
||||
|
||||
#define GEN10_SAMPLER_MODE _MMIO(0xE18C)
|
||||
#define ENABLE_SMALLPL REG_BIT(15)
|
||||
#define GEN11_SAMPLER_ENABLE_HEADLESS_MSG REG_BIT(5)
|
||||
|
||||
/* IVYBRIDGE DPF */
|
||||
|
@ -34,17 +34,25 @@
|
||||
|
||||
static void i915_save_display(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
|
||||
/* Display arbitration control */
|
||||
if (INTEL_GEN(dev_priv) <= 4)
|
||||
dev_priv->regfile.saveDSPARB = I915_READ(DSPARB);
|
||||
|
||||
/* save FBC interval */
|
||||
if (HAS_FBC(dev_priv) && INTEL_GEN(dev_priv) <= 4 && !IS_G4X(dev_priv))
|
||||
dev_priv->regfile.saveFBC_CONTROL = I915_READ(FBC_CONTROL);
|
||||
if (IS_GEN(dev_priv, 4))
|
||||
pci_read_config_word(pdev, GCDGMBUS,
|
||||
&dev_priv->regfile.saveGCDGMBUS);
|
||||
}
|
||||
|
||||
static void i915_restore_display(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
|
||||
if (IS_GEN(dev_priv, 4))
|
||||
pci_write_config_word(pdev, GCDGMBUS,
|
||||
dev_priv->regfile.saveGCDGMBUS);
|
||||
|
||||
/* Display arbitration */
|
||||
if (INTEL_GEN(dev_priv) <= 4)
|
||||
I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB);
|
||||
@ -52,31 +60,17 @@ static void i915_restore_display(struct drm_i915_private *dev_priv)
|
||||
/* only restore FBC info on the platform that supports FBC*/
|
||||
intel_fbc_global_disable(dev_priv);
|
||||
|
||||
/* restore FBC interval */
|
||||
if (HAS_FBC(dev_priv) && INTEL_GEN(dev_priv) <= 4 && !IS_G4X(dev_priv))
|
||||
I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL);
|
||||
|
||||
intel_vga_redisable(dev_priv);
|
||||
|
||||
intel_gmbus_reset(dev_priv);
|
||||
}
|
||||
|
||||
int i915_save_state(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
int i;
|
||||
|
||||
i915_save_display(dev_priv);
|
||||
|
||||
if (IS_GEN(dev_priv, 4))
|
||||
pci_read_config_word(pdev, GCDGMBUS,
|
||||
&dev_priv->regfile.saveGCDGMBUS);
|
||||
|
||||
/* Cache mode state */
|
||||
if (INTEL_GEN(dev_priv) < 7)
|
||||
dev_priv->regfile.saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
|
||||
|
||||
/* Memory Arbitration state */
|
||||
dev_priv->regfile.saveMI_ARB_STATE = I915_READ(MI_ARB_STATE);
|
||||
|
||||
/* Scratch space */
|
||||
if (IS_GEN(dev_priv, 2) && IS_MOBILE(dev_priv)) {
|
||||
for (i = 0; i < 7; i++) {
|
||||
@ -102,22 +96,10 @@ int i915_save_state(struct drm_i915_private *dev_priv)
|
||||
|
||||
int i915_restore_state(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
int i;
|
||||
|
||||
if (IS_GEN(dev_priv, 4))
|
||||
pci_write_config_word(pdev, GCDGMBUS,
|
||||
dev_priv->regfile.saveGCDGMBUS);
|
||||
i915_restore_display(dev_priv);
|
||||
|
||||
/* Cache mode state */
|
||||
if (INTEL_GEN(dev_priv) < 7)
|
||||
I915_WRITE(CACHE_MODE_0, dev_priv->regfile.saveCACHE_MODE_0 |
|
||||
0xffff0000);
|
||||
|
||||
/* Memory arbitration state */
|
||||
I915_WRITE(MI_ARB_STATE, dev_priv->regfile.saveMI_ARB_STATE | 0xffff0000);
|
||||
|
||||
/* Scratch space */
|
||||
if (IS_GEN(dev_priv, 2) && IS_MOBILE(dev_priv)) {
|
||||
for (i = 0; i < 7; i++) {
|
||||
@ -138,7 +120,5 @@ int i915_restore_state(struct drm_i915_private *dev_priv)
|
||||
I915_WRITE(SWF3(i), dev_priv->regfile.saveSWF3[i]);
|
||||
}
|
||||
|
||||
intel_gmbus_reset(dev_priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -516,6 +516,14 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv)
|
||||
S32_MAX),
|
||||
USEC_PER_SEC));
|
||||
}
|
||||
|
||||
if (!HAS_DISPLAY(dev_priv)) {
|
||||
dev_priv->drm.driver_features &= ~(DRIVER_MODESET |
|
||||
DRIVER_ATOMIC);
|
||||
memset(&info->display, 0, sizeof(info->display));
|
||||
memset(runtime->num_sprites, 0, sizeof(runtime->num_sprites));
|
||||
memset(runtime->num_scalers, 0, sizeof(runtime->num_scalers));
|
||||
}
|
||||
}
|
||||
|
||||
void intel_driver_caps_print(const struct intel_driver_caps *caps,
|
||||
|
@ -7136,7 +7136,7 @@ static void tgl_init_clock_gating(struct drm_i915_private *dev_priv)
|
||||
I915_READ(POWERGATE_ENABLE) | vd_pg_enable);
|
||||
|
||||
/* Wa_1409825376:tgl (pre-prod)*/
|
||||
if (IS_TGL_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_A0))
|
||||
if (IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_B1))
|
||||
I915_WRITE(GEN9_CLKGATE_DIS_3, I915_READ(GEN9_CLKGATE_DIS_3) |
|
||||
TGL_VRH_GATING_DIS);
|
||||
|
||||
|
@ -231,9 +231,21 @@ void vlv_ccu_write(struct drm_i915_private *i915, u32 reg, u32 val)
|
||||
SB_CRWRDA_NP, reg, &val);
|
||||
}
|
||||
|
||||
static u32 vlv_dpio_phy_iosf_port(struct drm_i915_private *i915, enum dpio_phy phy)
|
||||
{
|
||||
/*
|
||||
* IOSF_PORT_DPIO: VLV x2 PHY (DP/HDMI B and C), CHV x1 PHY (DP/HDMI D)
|
||||
* IOSF_PORT_DPIO_2: CHV x2 PHY (DP/HDMI B and C)
|
||||
*/
|
||||
if (IS_CHERRYVIEW(i915))
|
||||
return phy == DPIO_PHY0 ? IOSF_PORT_DPIO_2 : IOSF_PORT_DPIO;
|
||||
else
|
||||
return IOSF_PORT_DPIO;
|
||||
}
|
||||
|
||||
u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg)
|
||||
{
|
||||
int port = i915->dpio_phy_iosf_port[DPIO_PHY(pipe)];
|
||||
u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe));
|
||||
u32 val = 0;
|
||||
|
||||
vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MRD_NP, reg, &val);
|
||||
@ -252,7 +264,7 @@ u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg)
|
||||
void vlv_dpio_write(struct drm_i915_private *i915,
|
||||
enum pipe pipe, int reg, u32 val)
|
||||
{
|
||||
int port = i915->dpio_phy_iosf_port[DPIO_PHY(pipe)];
|
||||
u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe));
|
||||
|
||||
vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MWR_NP, reg, &val);
|
||||
}
|
||||
|
@ -1993,13 +1993,14 @@ int __intel_wait_for_register_fw(struct intel_uncore *uncore,
|
||||
unsigned int slow_timeout_ms,
|
||||
u32 *out_value)
|
||||
{
|
||||
u32 reg_value;
|
||||
u32 reg_value = 0;
|
||||
#define done (((reg_value = intel_uncore_read_fw(uncore, reg)) & mask) == value)
|
||||
int ret;
|
||||
|
||||
/* Catch any overuse of this function */
|
||||
might_sleep_if(slow_timeout_ms);
|
||||
GEM_BUG_ON(fast_timeout_us > 20000);
|
||||
GEM_BUG_ON(!fast_timeout_us && !slow_timeout_ms);
|
||||
|
||||
ret = -ETIMEDOUT;
|
||||
if (fast_timeout_us && fast_timeout_us <= 20000)
|
||||
|
@ -118,11 +118,11 @@ static struct dev_pm_domain pm_domain = {
|
||||
|
||||
struct drm_i915_private *mock_gem_device(void)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_IOMMU_API) && defined(CONFIG_INTEL_IOMMU)
|
||||
static struct dev_iommu fake_iommu = { .priv = (void *)-1 };
|
||||
#endif
|
||||
struct drm_i915_private *i915;
|
||||
struct pci_dev *pdev;
|
||||
#if IS_ENABLED(CONFIG_IOMMU_API) && defined(CONFIG_INTEL_IOMMU)
|
||||
struct dev_iommu iommu;
|
||||
#endif
|
||||
int err;
|
||||
|
||||
pdev = kzalloc(sizeof(*pdev), GFP_KERNEL);
|
||||
@ -141,10 +141,8 @@ struct drm_i915_private *mock_gem_device(void)
|
||||
dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
|
||||
|
||||
#if IS_ENABLED(CONFIG_IOMMU_API) && defined(CONFIG_INTEL_IOMMU)
|
||||
/* HACK HACK HACK to disable iommu for the fake device; force identity mapping */
|
||||
memset(&iommu, 0, sizeof(iommu));
|
||||
iommu.priv = (void *)-1;
|
||||
pdev->dev.iommu = &iommu;
|
||||
/* HACK to disable iommu for the fake device; force identity mapping */
|
||||
pdev->dev.iommu = &fake_iommu;
|
||||
#endif
|
||||
|
||||
pci_set_drvdata(pdev, i915);
|
||||
|
@ -239,8 +239,8 @@ nv50_dp_mode_valid(struct drm_connector *connector,
|
||||
return MODE_NO_INTERLACE;
|
||||
|
||||
max_clock = outp->dp.link_nr * outp->dp.link_bw;
|
||||
ds_clock = drm_dp_downstream_max_clock(outp->dp.dpcd,
|
||||
outp->dp.downstream_ports);
|
||||
ds_clock = drm_dp_downstream_max_dotclock(outp->dp.dpcd,
|
||||
outp->dp.downstream_ports);
|
||||
if (ds_clock)
|
||||
max_clock = min(max_clock, ds_clock);
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
#define PREFIX_STR "[drm_dp_mst_helper]"
|
||||
|
||||
#include <linux/random.h>
|
||||
|
||||
#include <drm/drm_dp_mst_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
@ -237,6 +239,21 @@ int igt_dp_mst_sideband_msg_req_decode(void *unused)
|
||||
in.u.i2c_write.bytes = data;
|
||||
DO_TEST();
|
||||
|
||||
in.req_type = DP_QUERY_STREAM_ENC_STATUS;
|
||||
in.u.enc_status.stream_id = 1;
|
||||
DO_TEST();
|
||||
get_random_bytes(in.u.enc_status.client_id,
|
||||
sizeof(in.u.enc_status.client_id));
|
||||
DO_TEST();
|
||||
in.u.enc_status.stream_event = 3;
|
||||
DO_TEST();
|
||||
in.u.enc_status.valid_stream_event = 0;
|
||||
DO_TEST();
|
||||
in.u.enc_status.stream_behavior = 3;
|
||||
DO_TEST();
|
||||
in.u.enc_status.valid_stream_behavior = 1;
|
||||
DO_TEST();
|
||||
|
||||
#undef DO_TEST
|
||||
return 0;
|
||||
}
|
||||
|
@ -21,8 +21,8 @@
|
||||
|
||||
#define PWM_MAX_LEVEL 0xFF
|
||||
|
||||
#define PWM_BASE_CLK 6000000 /* 6 MHz */
|
||||
#define PWM_MAX_PERIOD_NS 21333 /* 46.875KHz */
|
||||
#define PWM_BASE_CLK_MHZ 6 /* 6 MHz */
|
||||
#define PWM_MAX_PERIOD_NS 5461334 /* 183 Hz */
|
||||
|
||||
/**
|
||||
* struct crystalcove_pwm - Crystal Cove PWM controller
|
||||
@ -39,59 +39,121 @@ static inline struct crystalcove_pwm *to_crc_pwm(struct pwm_chip *pc)
|
||||
return container_of(pc, struct crystalcove_pwm, chip);
|
||||
}
|
||||
|
||||
static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm)
|
||||
static int crc_pwm_calc_clk_div(int period_ns)
|
||||
{
|
||||
struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
|
||||
int clk_div;
|
||||
|
||||
regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
|
||||
clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_USEC);
|
||||
/* clk_div 1 - 128, maps to register values 0-127 */
|
||||
if (clk_div > 0)
|
||||
clk_div--;
|
||||
|
||||
return 0;
|
||||
return clk_div;
|
||||
}
|
||||
|
||||
static void crc_pwm_disable(struct pwm_chip *c, struct pwm_device *pwm)
|
||||
static int crc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
|
||||
|
||||
regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
|
||||
}
|
||||
|
||||
static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm,
|
||||
int duty_ns, int period_ns)
|
||||
{
|
||||
struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
|
||||
struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
|
||||
struct device *dev = crc_pwm->chip.dev;
|
||||
int level;
|
||||
int err;
|
||||
|
||||
if (period_ns > PWM_MAX_PERIOD_NS) {
|
||||
if (state->period > PWM_MAX_PERIOD_NS) {
|
||||
dev_err(dev, "un-supported period_ns\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pwm_get_period(pwm) != period_ns) {
|
||||
int clk_div;
|
||||
if (state->polarity != PWM_POLARITY_NORMAL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* changing the clk divisor, need to disable fisrt */
|
||||
crc_pwm_disable(c, pwm);
|
||||
clk_div = PWM_BASE_CLK * period_ns / NSEC_PER_SEC;
|
||||
|
||||
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
|
||||
clk_div | PWM_OUTPUT_ENABLE);
|
||||
|
||||
/* enable back */
|
||||
crc_pwm_enable(c, pwm);
|
||||
if (pwm_is_enabled(pwm) && !state->enabled) {
|
||||
err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
|
||||
if (err) {
|
||||
dev_err(dev, "Error writing BACKLIGHT_EN %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* change the pwm duty cycle */
|
||||
level = duty_ns * PWM_MAX_LEVEL / period_ns;
|
||||
regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level);
|
||||
if (pwm_get_duty_cycle(pwm) != state->duty_cycle ||
|
||||
pwm_get_period(pwm) != state->period) {
|
||||
u64 level = state->duty_cycle * PWM_MAX_LEVEL;
|
||||
|
||||
do_div(level, state->period);
|
||||
|
||||
err = regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level);
|
||||
if (err) {
|
||||
dev_err(dev, "Error writing PWM0_DUTY_CYCLE %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (pwm_is_enabled(pwm) && state->enabled &&
|
||||
pwm_get_period(pwm) != state->period) {
|
||||
/* changing the clk divisor, clear PWM_OUTPUT_ENABLE first */
|
||||
err = regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
|
||||
if (err) {
|
||||
dev_err(dev, "Error writing PWM0_CLK_DIV %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (pwm_get_period(pwm) != state->period ||
|
||||
pwm_is_enabled(pwm) != state->enabled) {
|
||||
int clk_div = crc_pwm_calc_clk_div(state->period);
|
||||
int pwm_output_enable = state->enabled ? PWM_OUTPUT_ENABLE : 0;
|
||||
|
||||
err = regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
|
||||
clk_div | pwm_output_enable);
|
||||
if (err) {
|
||||
dev_err(dev, "Error writing PWM0_CLK_DIV %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pwm_is_enabled(pwm) && state->enabled) {
|
||||
err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
|
||||
if (err) {
|
||||
dev_err(dev, "Error writing BACKLIGHT_EN %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
|
||||
struct device *dev = crc_pwm->chip.dev;
|
||||
unsigned int clk_div, clk_div_reg, duty_cycle_reg;
|
||||
int error;
|
||||
|
||||
error = regmap_read(crc_pwm->regmap, PWM0_CLK_DIV, &clk_div_reg);
|
||||
if (error) {
|
||||
dev_err(dev, "Error reading PWM0_CLK_DIV %d\n", error);
|
||||
return;
|
||||
}
|
||||
|
||||
error = regmap_read(crc_pwm->regmap, PWM0_DUTY_CYCLE, &duty_cycle_reg);
|
||||
if (error) {
|
||||
dev_err(dev, "Error reading PWM0_DUTY_CYCLE %d\n", error);
|
||||
return;
|
||||
}
|
||||
|
||||
clk_div = (clk_div_reg & ~PWM_OUTPUT_ENABLE) + 1;
|
||||
|
||||
state->period =
|
||||
DIV_ROUND_UP(clk_div * NSEC_PER_USEC * 256, PWM_BASE_CLK_MHZ);
|
||||
state->duty_cycle =
|
||||
DIV_ROUND_UP_ULL(duty_cycle_reg * state->period, PWM_MAX_LEVEL);
|
||||
state->polarity = PWM_POLARITY_NORMAL;
|
||||
state->enabled = !!(clk_div_reg & PWM_OUTPUT_ENABLE);
|
||||
}
|
||||
|
||||
static const struct pwm_ops crc_pwm_ops = {
|
||||
.config = crc_pwm_config,
|
||||
.enable = crc_pwm_enable,
|
||||
.disable = crc_pwm_disable,
|
||||
.apply = crc_pwm_apply,
|
||||
.get_state = crc_pwm_get_state,
|
||||
};
|
||||
|
||||
static int crystalcove_pwm_probe(struct platform_device *pdev)
|
||||
|
@ -89,7 +89,6 @@ static int pwm_lpss_prepare(struct device *dev)
|
||||
|
||||
static const struct dev_pm_ops pwm_lpss_platform_pm_ops = {
|
||||
.prepare = pwm_lpss_prepare,
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pwm_lpss_suspend, pwm_lpss_resume)
|
||||
};
|
||||
|
||||
static const struct acpi_device_id pwm_lpss_acpi_match[] = {
|
||||
|
@ -85,7 +85,7 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm,
|
||||
unsigned long long on_time_div;
|
||||
unsigned long c = lpwm->info->clk_rate, base_unit_range;
|
||||
unsigned long long base_unit, freq = NSEC_PER_SEC;
|
||||
u32 orig_ctrl, ctrl;
|
||||
u32 ctrl;
|
||||
|
||||
do_div(freq, period_ns);
|
||||
|
||||
@ -93,26 +93,25 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm,
|
||||
* The equation is:
|
||||
* base_unit = round(base_unit_range * freq / c)
|
||||
*/
|
||||
base_unit_range = BIT(lpwm->info->base_unit_bits) - 1;
|
||||
base_unit_range = BIT(lpwm->info->base_unit_bits);
|
||||
freq *= base_unit_range;
|
||||
|
||||
base_unit = DIV_ROUND_CLOSEST_ULL(freq, c);
|
||||
/* base_unit must not be 0 and we also want to avoid overflowing it */
|
||||
base_unit = clamp_val(base_unit, 1, base_unit_range - 1);
|
||||
|
||||
on_time_div = 255ULL * duty_ns;
|
||||
do_div(on_time_div, period_ns);
|
||||
on_time_div = 255ULL - on_time_div;
|
||||
|
||||
orig_ctrl = ctrl = pwm_lpss_read(pwm);
|
||||
ctrl = pwm_lpss_read(pwm);
|
||||
ctrl &= ~PWM_ON_TIME_DIV_MASK;
|
||||
ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
|
||||
base_unit &= base_unit_range;
|
||||
ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT);
|
||||
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
|
||||
ctrl |= on_time_div;
|
||||
|
||||
if (orig_ctrl != ctrl) {
|
||||
pwm_lpss_write(pwm, ctrl);
|
||||
pwm_lpss_write(pwm, ctrl | PWM_SW_UPDATE);
|
||||
}
|
||||
pwm_lpss_write(pwm, ctrl);
|
||||
pwm_lpss_write(pwm, ctrl | PWM_SW_UPDATE);
|
||||
}
|
||||
|
||||
static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond)
|
||||
@ -121,41 +120,47 @@ static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond)
|
||||
pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
|
||||
}
|
||||
|
||||
static int pwm_lpss_prepare_enable(struct pwm_lpss_chip *lpwm,
|
||||
struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pwm_lpss_is_updating(pwm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
|
||||
pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false);
|
||||
ret = pwm_lpss_wait_for_update(pwm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pwm_lpss_cond_enable(pwm, lpwm->info->bypass == true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct pwm_lpss_chip *lpwm = to_lpwm(chip);
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (state->enabled) {
|
||||
if (!pwm_is_enabled(pwm)) {
|
||||
pm_runtime_get_sync(chip->dev);
|
||||
ret = pwm_lpss_is_updating(pwm);
|
||||
if (ret) {
|
||||
pm_runtime_put(chip->dev);
|
||||
return ret;
|
||||
}
|
||||
pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
|
||||
pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false);
|
||||
ret = pwm_lpss_wait_for_update(pwm);
|
||||
if (ret) {
|
||||
pm_runtime_put(chip->dev);
|
||||
return ret;
|
||||
}
|
||||
pwm_lpss_cond_enable(pwm, lpwm->info->bypass == true);
|
||||
} else {
|
||||
ret = pwm_lpss_is_updating(pwm);
|
||||
ret = pwm_lpss_prepare_enable(lpwm, pwm, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
|
||||
return pwm_lpss_wait_for_update(pwm);
|
||||
pm_runtime_put(chip->dev);
|
||||
} else {
|
||||
ret = pwm_lpss_prepare_enable(lpwm, pwm, state);
|
||||
}
|
||||
} else if (pwm_is_enabled(pwm)) {
|
||||
pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
|
||||
pm_runtime_put(chip->dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -255,30 +260,6 @@ int pwm_lpss_remove(struct pwm_lpss_chip *lpwm)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwm_lpss_remove);
|
||||
|
||||
int pwm_lpss_suspend(struct device *dev)
|
||||
{
|
||||
struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < lpwm->info->npwm; i++)
|
||||
lpwm->saved_ctrl[i] = readl(lpwm->regs + i * PWM_SIZE + PWM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwm_lpss_suspend);
|
||||
|
||||
int pwm_lpss_resume(struct device *dev)
|
||||
{
|
||||
struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < lpwm->info->npwm; i++)
|
||||
writel(lpwm->saved_ctrl[i], lpwm->regs + i * PWM_SIZE + PWM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwm_lpss_resume);
|
||||
|
||||
MODULE_DESCRIPTION("PWM driver for Intel LPSS");
|
||||
MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -19,7 +19,6 @@ struct pwm_lpss_chip {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *regs;
|
||||
const struct pwm_lpss_boardinfo *info;
|
||||
u32 saved_ctrl[MAX_PWMS];
|
||||
};
|
||||
|
||||
struct pwm_lpss_boardinfo {
|
||||
@ -37,7 +36,5 @@ struct pwm_lpss_boardinfo {
|
||||
struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
|
||||
const struct pwm_lpss_boardinfo *info);
|
||||
int pwm_lpss_remove(struct pwm_lpss_chip *lpwm);
|
||||
int pwm_lpss_suspend(struct device *dev);
|
||||
int pwm_lpss_resume(struct device *dev);
|
||||
|
||||
#endif /* __PWM_LPSS_H */
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include <linux/types.h>
|
||||
#include <drm/drm_connector.h>
|
||||
|
||||
struct drm_device;
|
||||
|
||||
/*
|
||||
* Unless otherwise noted, all values are from the DP 1.1a spec. Note that
|
||||
* DP and DPCD versions are independent. Differences from 1.0 are not noted,
|
||||
@ -385,13 +387,30 @@
|
||||
# define DP_DS_PORT_TYPE_DP_DUALMODE 5
|
||||
# define DP_DS_PORT_TYPE_WIRELESS 6
|
||||
# define DP_DS_PORT_HPD (1 << 3)
|
||||
# define DP_DS_NON_EDID_MASK (0xf << 4)
|
||||
# define DP_DS_NON_EDID_720x480i_60 (1 << 4)
|
||||
# define DP_DS_NON_EDID_720x480i_50 (2 << 4)
|
||||
# define DP_DS_NON_EDID_1920x1080i_60 (3 << 4)
|
||||
# define DP_DS_NON_EDID_1920x1080i_50 (4 << 4)
|
||||
# define DP_DS_NON_EDID_1280x720_60 (5 << 4)
|
||||
# define DP_DS_NON_EDID_1280x720_50 (7 << 4)
|
||||
/* offset 1 for VGA is maximum megapixels per second / 8 */
|
||||
/* offset 2 */
|
||||
/* offset 1 for DVI/HDMI is maximum TMDS clock in Mbps / 2.5 */
|
||||
/* offset 2 for VGA/DVI/HDMI */
|
||||
# define DP_DS_MAX_BPC_MASK (3 << 0)
|
||||
# define DP_DS_8BPC 0
|
||||
# define DP_DS_10BPC 1
|
||||
# define DP_DS_12BPC 2
|
||||
# define DP_DS_16BPC 3
|
||||
/* offset 3 for DVI */
|
||||
# define DP_DS_DVI_DUAL_LINK (1 << 1)
|
||||
# define DP_DS_DVI_HIGH_COLOR_DEPTH (1 << 2)
|
||||
/* offset 3 for HDMI */
|
||||
# define DP_DS_HDMI_FRAME_SEQ_TO_FRAME_PACK (1 << 0)
|
||||
# define DP_DS_HDMI_YCBCR422_PASS_THROUGH (1 << 1)
|
||||
# define DP_DS_HDMI_YCBCR420_PASS_THROUGH (1 << 2)
|
||||
# define DP_DS_HDMI_YCBCR444_TO_422_CONV (1 << 3)
|
||||
# define DP_DS_HDMI_YCBCR444_TO_420_CONV (1 << 4)
|
||||
|
||||
#define DP_MAX_DOWNSTREAM_PORTS 0x10
|
||||
|
||||
@ -984,6 +1003,16 @@
|
||||
#define DP_CEC_TX_MESSAGE_BUFFER 0x3020
|
||||
#define DP_CEC_MESSAGE_BUFFER_LENGTH 0x10
|
||||
|
||||
#define DP_PROTOCOL_CONVERTER_CONTROL_0 0x3050 /* DP 1.3 */
|
||||
# define DP_HDMI_DVI_OUTPUT_CONFIG (1 << 0) /* DP 1.3 */
|
||||
#define DP_PROTOCOL_CONVERTER_CONTROL_1 0x3051 /* DP 1.3 */
|
||||
# define DP_CONVERSION_TO_YCBCR420_ENABLE (1 << 0) /* DP 1.3 */
|
||||
# define DP_HDMI_EDID_PROCESSING_DISABLE (1 << 1) /* DP 1.4 */
|
||||
# define DP_HDMI_AUTONOMOUS_SCRAMBLING_DISABLE (1 << 2) /* DP 1.4 */
|
||||
# define DP_HDMI_FORCE_SCRAMBLING (1 << 3) /* DP 1.4 */
|
||||
#define DP_PROTOCOL_CONVERTER_CONTROL_2 0x3052 /* DP 1.3 */
|
||||
# define DP_CONVERSION_TO_YCBCR422_ENABLE (1 << 0) /* DP 1.3 */
|
||||
|
||||
#define DP_AUX_HDCP_BKSV 0x68000
|
||||
#define DP_AUX_HDCP_RI_PRIME 0x68005
|
||||
#define DP_AUX_HDCP_AKSV 0x68007
|
||||
@ -1109,6 +1138,9 @@
|
||||
#define DP_POWER_DOWN_PHY 0x25
|
||||
#define DP_SINK_EVENT_NOTIFY 0x30
|
||||
#define DP_QUERY_STREAM_ENC_STATUS 0x38
|
||||
#define DP_QUERY_STREAM_ENC_STATUS_STATE_NO_EXIST 0
|
||||
#define DP_QUERY_STREAM_ENC_STATUS_STATE_INACTIVE 1
|
||||
#define DP_QUERY_STREAM_ENC_STATUS_STATE_ACTIVE 2
|
||||
|
||||
/* DP 1.2 MST sideband reply types */
|
||||
#define DP_SIDEBAND_REPLY_ACK 0x00
|
||||
@ -1619,13 +1651,35 @@ bool drm_dp_send_real_edid_checksum(struct drm_dp_aux *aux,
|
||||
int drm_dp_read_downstream_info(struct drm_dp_aux *aux,
|
||||
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]);
|
||||
int drm_dp_downstream_max_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4]);
|
||||
bool drm_dp_downstream_is_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4], u8 type);
|
||||
bool drm_dp_downstream_is_tmds(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4],
|
||||
const struct edid *edid);
|
||||
int drm_dp_downstream_max_dotclock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4]);
|
||||
int drm_dp_downstream_max_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4],
|
||||
const struct edid *edid);
|
||||
int drm_dp_downstream_min_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4],
|
||||
const struct edid *edid);
|
||||
int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4]);
|
||||
const u8 port_cap[4],
|
||||
const struct edid *edid);
|
||||
bool drm_dp_downstream_420_passthrough(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4]);
|
||||
bool drm_dp_downstream_444_to_420_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4]);
|
||||
struct drm_display_mode *drm_dp_downstream_mode(struct drm_device *dev,
|
||||
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4]);
|
||||
int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]);
|
||||
void drm_dp_downstream_debug(struct seq_file *m, const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4], struct drm_dp_aux *aux);
|
||||
void drm_dp_downstream_debug(struct seq_file *m,
|
||||
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4],
|
||||
const struct edid *edid,
|
||||
struct drm_dp_aux *aux);
|
||||
enum drm_mode_subconnector
|
||||
drm_dp_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4]);
|
||||
|
@ -313,6 +313,34 @@ struct drm_dp_remote_i2c_write_ack_reply {
|
||||
u8 port_number;
|
||||
};
|
||||
|
||||
struct drm_dp_query_stream_enc_status_ack_reply {
|
||||
/* Bit[23:16]- Stream Id */
|
||||
u8 stream_id;
|
||||
|
||||
/* Bit[15]- Signed */
|
||||
bool reply_signed;
|
||||
|
||||
/* Bit[10:8]- Stream Output Sink Type */
|
||||
bool unauthorizable_device_present;
|
||||
bool legacy_device_present;
|
||||
bool query_capable_device_present;
|
||||
|
||||
/* Bit[12:11]- Stream Output CP Type */
|
||||
bool hdcp_1x_device_present;
|
||||
bool hdcp_2x_device_present;
|
||||
|
||||
/* Bit[4]- Stream Authentication */
|
||||
bool auth_completed;
|
||||
|
||||
/* Bit[3]- Stream Encryption */
|
||||
bool encryption_enabled;
|
||||
|
||||
/* Bit[2]- Stream Repeater Function Present */
|
||||
bool repeater_present;
|
||||
|
||||
/* Bit[1:0]- Stream State */
|
||||
u8 state;
|
||||
};
|
||||
|
||||
#define DRM_DP_MAX_SDP_STREAMS 16
|
||||
struct drm_dp_allocate_payload {
|
||||
@ -374,6 +402,15 @@ struct drm_dp_remote_i2c_write {
|
||||
u8 *bytes;
|
||||
};
|
||||
|
||||
struct drm_dp_query_stream_enc_status {
|
||||
u8 stream_id;
|
||||
u8 client_id[7]; /* 56-bit nonce */
|
||||
u8 stream_event;
|
||||
bool valid_stream_event;
|
||||
u8 stream_behavior;
|
||||
u8 valid_stream_behavior;
|
||||
};
|
||||
|
||||
/* this covers ENUM_RESOURCES, POWER_DOWN_PHY, POWER_UP_PHY */
|
||||
struct drm_dp_port_number_req {
|
||||
u8 port_number;
|
||||
@ -422,6 +459,8 @@ struct drm_dp_sideband_msg_req_body {
|
||||
|
||||
struct drm_dp_remote_i2c_read i2c_read;
|
||||
struct drm_dp_remote_i2c_write i2c_write;
|
||||
|
||||
struct drm_dp_query_stream_enc_status enc_status;
|
||||
} u;
|
||||
};
|
||||
|
||||
@ -444,6 +483,8 @@ struct drm_dp_sideband_msg_reply_body {
|
||||
struct drm_dp_remote_i2c_read_ack_reply remote_i2c_read_ack;
|
||||
struct drm_dp_remote_i2c_read_nak_reply remote_i2c_read_nack;
|
||||
struct drm_dp_remote_i2c_write_ack_reply remote_i2c_write_ack;
|
||||
|
||||
struct drm_dp_query_stream_enc_status_ack_reply enc_status;
|
||||
} u;
|
||||
};
|
||||
|
||||
@ -807,6 +848,9 @@ drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state,
|
||||
struct drm_dp_mst_port *port);
|
||||
int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr,
|
||||
struct drm_dp_mst_port *port, bool power_up);
|
||||
int drm_dp_send_query_stream_enc_status(struct drm_dp_mst_topology_mgr *mgr,
|
||||
struct drm_dp_mst_port *port,
|
||||
struct drm_dp_query_stream_enc_status_ack_reply *status);
|
||||
int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state);
|
||||
|
||||
void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port);
|
||||
|
@ -517,4 +517,8 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name,
|
||||
struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
|
||||
int hsize, int vsize, int fresh,
|
||||
bool rb);
|
||||
struct drm_display_mode *
|
||||
drm_display_mode_from_cea_vic(struct drm_device *dev,
|
||||
u8 video_code);
|
||||
|
||||
#endif /* __DRM_EDID_H__ */
|
||||
|
@ -594,19 +594,25 @@
|
||||
INTEL_VGA_DEVICE(0x4E51, info)
|
||||
|
||||
/* TGL */
|
||||
#define INTEL_TGL_12_IDS(info) \
|
||||
#define INTEL_TGL_12_GT1_IDS(info) \
|
||||
INTEL_VGA_DEVICE(0x9A60, info), \
|
||||
INTEL_VGA_DEVICE(0x9A68, info), \
|
||||
INTEL_VGA_DEVICE(0x9A70, info)
|
||||
|
||||
#define INTEL_TGL_12_GT2_IDS(info) \
|
||||
INTEL_VGA_DEVICE(0x9A40, info), \
|
||||
INTEL_VGA_DEVICE(0x9A49, info), \
|
||||
INTEL_VGA_DEVICE(0x9A59, info), \
|
||||
INTEL_VGA_DEVICE(0x9A60, info), \
|
||||
INTEL_VGA_DEVICE(0x9A68, info), \
|
||||
INTEL_VGA_DEVICE(0x9A70, info), \
|
||||
INTEL_VGA_DEVICE(0x9A78, info), \
|
||||
INTEL_VGA_DEVICE(0x9AC0, info), \
|
||||
INTEL_VGA_DEVICE(0x9AC9, info), \
|
||||
INTEL_VGA_DEVICE(0x9AD9, info), \
|
||||
INTEL_VGA_DEVICE(0x9AF8, info)
|
||||
|
||||
#define INTEL_TGL_12_IDS(info) \
|
||||
INTEL_TGL_12_GT1_IDS(info), \
|
||||
INTEL_TGL_12_GT2_IDS(info)
|
||||
|
||||
/* RKL */
|
||||
#define INTEL_RKL_IDS(info) \
|
||||
INTEL_VGA_DEVICE(0x4C80, info), \
|
||||
|
Loading…
Reference in New Issue
Block a user