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:
Dave Airlie 2020-09-23 09:11:00 +10:00
commit db29dc7d33
69 changed files with 2872 additions and 1657 deletions

View File

@ -67,7 +67,15 @@ ACPI_MODULE_NAME("acpi_lpss");
#define LPSS_CLK_DIVIDER BIT(2) #define LPSS_CLK_DIVIDER BIT(2)
#define LPSS_LTR BIT(3) #define LPSS_LTR BIT(3)
#define LPSS_SAVE_CTX BIT(4) #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; 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 = { 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, .prv_offset = 0x800,
.setup = bsw_pwm_setup, .setup = bsw_pwm_setup,
.resume_from_noirq = true,
}; };
static const struct lpss_device_desc byt_uart_dev_desc = { 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 * we have to deassert reset line to be sure that ->probe() will
* recognize the device. * 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); 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; return 0;
} }
@ -1030,7 +1044,7 @@ static int acpi_lpss_resume(struct device *dev)
acpi_lpss_d3_to_d0_delay(pdata); 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); acpi_lpss_restore_ctx(dev, pdata);
return 0; return 0;

View File

@ -363,6 +363,66 @@ int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux,
} }
EXPORT_SYMBOL(drm_dp_dpcd_read_link_status); 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 * drm_dp_send_real_edid_checksum() - send back real edid checksum value
* @aux: DisplayPort AUX channel * @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); ret = drm_dp_dpcd_read(aux, DP_DOWNSTREAM_PORT_0, downstream_ports, len);
if (ret < 0) if (ret < 0)
return ret; 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); EXPORT_SYMBOL(drm_dp_read_downstream_info);
/** /**
* drm_dp_downstream_max_clock() - extract branch device max * drm_dp_downstream_max_dotclock() - extract downstream facing port max dot clock
* pixel rate for legacy VGA
* converter or max TMDS clock
* rate for others
* @dpcd: DisplayPort configuration data * @dpcd: DisplayPort configuration data
* @port_cap: port capabilities * @port_cap: port capabilities
* *
* See also: * Returns: Downstream facing port max dot clock in kHz on success,
* drm_dp_read_downstream_info() * or 0 if max clock not defined
* drm_dp_downstream_max_bpc()
*
* Returns: Max 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], int drm_dp_downstream_max_dotclock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
const u8 port_cap[4]) const u8 port_cap[4])
{ {
int type = port_cap[0] & DP_DS_PORT_TYPE_MASK; if (!drm_dp_is_branch(dpcd))
bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
DP_DETAILED_CAP_INFO_AVAILABLE;
if (!detailed_cap_info)
return 0; 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: case DP_DS_PORT_TYPE_VGA:
return port_cap[1] * 8 * 1000; if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE) == 0)
case DP_DS_PORT_TYPE_DVI: return 0;
case DP_DS_PORT_TYPE_HDMI: 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: 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; return port_cap[1] * 2500;
default: default:
return 0; 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 * drm_dp_downstream_min_tmds_clock() - extract downstream facing port min TMDS clock
* bits per component
* @dpcd: DisplayPort configuration data * @dpcd: DisplayPort configuration data
* @port_cap: port capabilities * @port_cap: port capabilities
* @edid: EDID
* *
* See also: * Returns: HDMI/DVI downstream facing port min TMDS clock in kHz on success,
* drm_dp_read_downstream_info() * or 0 if max TMDS clock not defined
* drm_dp_downstream_max_clock() */
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 * 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], 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; if (!drm_dp_is_branch(dpcd))
bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
DP_DETAILED_CAP_INFO_AVAILABLE;
int bpc;
if (!detailed_cap_info)
return 0; return 0;
switch (type) { if (dpcd[DP_DPCD_REV] < 0x11) {
case DP_DS_PORT_TYPE_VGA: switch (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) {
case DP_DS_PORT_TYPE_DVI: case DP_DWN_STRM_PORT_TYPE_DP:
case DP_DS_PORT_TYPE_HDMI: return 0;
case DP_DS_PORT_TYPE_DP_DUALMODE: default:
bpc = port_cap[2] & DP_DS_MAX_BPC_MASK; 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: case DP_DS_8BPC:
return 8; return 8;
case DP_DS_10BPC: case DP_DS_10BPC:
@ -626,14 +798,130 @@ int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
return 12; return 12;
case DP_DS_16BPC: case DP_DS_16BPC:
return 16; return 16;
default:
return 8;
} }
fallthrough; break;
default: default:
return 0; return 8;
} }
} }
EXPORT_SYMBOL(drm_dp_downstream_max_bpc); 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 * drm_dp_downstream_id() - identify branch device
* @aux: DisplayPort AUX channel * @aux: DisplayPort AUX channel
@ -652,12 +940,15 @@ EXPORT_SYMBOL(drm_dp_downstream_id);
* @m: pointer for debugfs file * @m: pointer for debugfs file
* @dpcd: DisplayPort configuration data * @dpcd: DisplayPort configuration data
* @port_cap: port capabilities * @port_cap: port capabilities
* @edid: EDID
* @aux: DisplayPort AUX channel * @aux: DisplayPort AUX channel
* *
*/ */
void drm_dp_downstream_debug(struct seq_file *m, void drm_dp_downstream_debug(struct seq_file *m,
const u8 dpcd[DP_RECEIVER_CAP_SIZE], 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] & bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
DP_DETAILED_CAP_INFO_AVAILABLE; 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]); seq_printf(m, "\t\tSW: %d.%d\n", rev[0], rev[1]);
if (detailed_cap_info) { 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) { clk = drm_dp_downstream_max_tmds_clock(dpcd, port_cap, edid);
if (type == DP_DS_PORT_TYPE_VGA) if (clk > 0)
seq_printf(m, "\t\tMax dot clock: %d kHz\n", clk); seq_printf(m, "\t\tMax TMDS clock: %d kHz\n", clk);
else
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) if (bpc > 0)
seq_printf(m, "\t\tMax bpc: %d\n", bpc); seq_printf(m, "\t\tMax bpc: %d\n", bpc);

View File

@ -20,11 +20,13 @@
* OF THIS SOFTWARE. * OF THIS SOFTWARE.
*/ */
#include <linux/bitfield.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/random.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/iopoll.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); memcpy(&buf[idx], req->u.i2c_write.bytes, req->u.i2c_write.num_bytes);
idx += req->u.i2c_write.num_bytes; idx += req->u.i2c_write.num_bytes;
break; 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; raw->cur_len = idx;
} }
@ -551,6 +569,20 @@ drm_dp_decode_sideband_req(const struct drm_dp_sideband_msg_tx *raw,
return -ENOMEM; return -ENOMEM;
} }
break; 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; 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.num_bytes, req->u.i2c_write.num_bytes,
req->u.i2c_write.bytes); req->u.i2c_write.bytes);
break; 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: default:
P("???\n"); P("???\n");
break; break;
@ -936,6 +978,42 @@ static bool drm_dp_sideband_parse_power_updown_phy_ack(struct drm_dp_sideband_ms
return true; 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, static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw,
struct drm_dp_sideband_msg_reply_body *msg) 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); return drm_dp_sideband_parse_power_updown_phy_ack(raw, msg);
case DP_CLEAR_PAYLOAD_ID_TABLE: case DP_CLEAR_PAYLOAD_ID_TABLE:
return true; /* since there's nothing to parse */ 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: default:
DRM_ERROR("Got unknown reply 0x%02x (%s)\n", msg->req_type, DRM_ERROR("Got unknown reply 0x%02x (%s)\n", msg->req_type,
drm_dp_mst_req_type_str(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; 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, static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_vcpi *vcpi) 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); 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, static int drm_dp_create_payload_step1(struct drm_dp_mst_topology_mgr *mgr,
int id, int id,
struct drm_dp_payload *payload) struct drm_dp_payload *payload)

View File

@ -3738,6 +3738,34 @@ drm_add_cmdb_modes(struct drm_connector *connector, u8 svd)
bitmap_set(hdmi->y420_cmdb_modes, vic, 1); 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 static int
do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len) do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len)
{ {

View File

@ -234,6 +234,7 @@ i915-y += \
display/intel_ddi.o \ display/intel_ddi.o \
display/intel_dp.o \ display/intel_dp.o \
display/intel_dp_aux_backlight.o \ display/intel_dp_aux_backlight.o \
display/intel_dp_hdcp.o \
display/intel_dp_link_training.o \ display/intel_dp_link_training.o \
display/intel_dp_mst.o \ display/intel_dp_mst.o \
display/intel_dsi.o \ display/intel_dsi.o \

View File

@ -1646,6 +1646,7 @@ static const struct drm_encoder_funcs gen11_dsi_encoder_funcs = {
}; };
static const struct drm_connector_funcs gen11_dsi_connector_funcs = { static const struct drm_connector_funcs gen11_dsi_connector_funcs = {
.detect = intel_panel_detect,
.late_register = intel_connector_register, .late_register = intel_connector_register,
.early_unregister = intel_connector_unregister, .early_unregister = intel_connector_unregister,
.destroy = intel_connector_destroy, .destroy = intel_connector_destroy,

View File

@ -527,8 +527,6 @@ void intel_atomic_state_clear(struct drm_atomic_state *s)
intel_atomic_clear_global_state(state); intel_atomic_clear_global_state(state);
state->dpll_set = state->modeset = false; state->dpll_set = state->modeset = false;
state->global_state_changed = false;
state->active_pipes = 0;
} }
struct intel_crtc_state * 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); 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;
}

View File

@ -56,8 +56,4 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
struct intel_crtc *intel_crtc, struct intel_crtc *intel_crtc,
struct intel_crtc_state *crtc_state); 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__ */ #endif /* __INTEL_ATOMIC_H__ */

View File

@ -958,13 +958,8 @@ static int glk_force_audio_cdclk_commit(struct intel_atomic_state *state,
if (IS_ERR(cdclk_state)) if (IS_ERR(cdclk_state))
return PTR_ERR(cdclk_state); return PTR_ERR(cdclk_state);
cdclk_state->force_min_cdclk_changed = true;
cdclk_state->force_min_cdclk = enable ? 2 * 96000 : 0; 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); return drm_atomic_commit(&state->base);
} }

View File

@ -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_E] = { DVO_PORT_HDMIE, DVO_PORT_DPE, DVO_PORT_CRT },
[PORT_F] = { DVO_PORT_HDMIF, DVO_PORT_DPF, -1 }, [PORT_F] = { DVO_PORT_HDMIF, DVO_PORT_DPF, -1 },
[PORT_G] = { DVO_PORT_HDMIG, DVO_PORT_DPG, -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 * 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); 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, drm_dbg_kms(&dev_priv->drm,
"Skipping VBT init due to disabled display.\n"); "Skipping VBT init due to disabled display.\n");
return; return;
@ -2650,6 +2652,12 @@ enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *dev_priv,
case DP_AUX_G: case DP_AUX_G:
aux_ch = AUX_CH_G; aux_ch = AUX_CH_G;
break; break;
case DP_AUX_H:
aux_ch = AUX_CH_H;
break;
case DP_AUX_I:
aux_ch = AUX_CH_I;
break;
default: default:
MISSING_CASE(info->alternate_aux_channel); MISSING_CASE(info->alternate_aux_channel);
aux_ch = AUX_CH_A; aux_ch = AUX_CH_A;

View File

@ -2426,7 +2426,6 @@ static struct intel_global_state *intel_cdclk_duplicate_state(struct intel_globa
if (!cdclk_state) if (!cdclk_state)
return NULL; return NULL;
cdclk_state->force_min_cdclk_changed = false;
cdclk_state->pipe = INVALID_PIPE; cdclk_state->pipe = INVALID_PIPE;
return &cdclk_state->base; return &cdclk_state->base;
@ -2501,6 +2500,7 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state)
if (ret) if (ret)
return ret; return ret;
} else if (old_cdclk_state->active_pipes != new_cdclk_state->active_pipes || } 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, intel_cdclk_changed(&old_cdclk_state->logical,
&new_cdclk_state->logical)) { &new_cdclk_state->logical)) {
ret = intel_atomic_lock_global_state(&new_cdclk_state->base); ret = intel_atomic_lock_global_state(&new_cdclk_state->base);

View File

@ -49,7 +49,6 @@ struct intel_cdclk_state {
/* forced minimum cdclk for glk+ audio w/a */ /* forced minimum cdclk for glk+ audio w/a */
int force_min_cdclk; int force_min_cdclk;
bool force_min_cdclk_changed;
/* bitmask of active pipes */ /* bitmask of active pipes */
u8 active_pipes; u8 active_pipes;

View File

@ -833,6 +833,9 @@ intel_crt_detect(struct drm_connector *connector,
connector->base.id, connector->name, connector->base.id, connector->name,
force); force);
if (!INTEL_DISPLAY_ENABLED(dev_priv))
return connector_status_disconnected;
if (dev_priv->params.load_detect_test) { if (dev_priv->params.load_detect_test) {
wakeref = intel_display_power_get(dev_priv, wakeref = intel_display_power_get(dev_priv,
intel_encoder->power_domain); intel_encoder->power_domain);

View File

@ -572,13 +572,13 @@ static const struct cnl_ddi_buf_trans ehl_combo_phy_ddi_translations_dp[] = {
/* NT mV Trans mV db */ /* NT mV Trans mV db */
{ 0xA, 0x33, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ { 0xA, 0x33, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */
{ 0xA, 0x47, 0x36, 0x00, 0x09 }, /* 350 500 3.1 */ { 0xA, 0x47, 0x36, 0x00, 0x09 }, /* 350 500 3.1 */
{ 0xC, 0x64, 0x30, 0x00, 0x0F }, /* 350 700 6.0 */ { 0xC, 0x64, 0x34, 0x00, 0x0B }, /* 350 700 6.0 */
{ 0x6, 0x7F, 0x2C, 0x00, 0x13 }, /* 350 900 8.2 */ { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 350 900 8.2 */
{ 0xA, 0x46, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ { 0xA, 0x46, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */
{ 0xC, 0x64, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ { 0xC, 0x64, 0x38, 0x00, 0x07 }, /* 500 700 2.9 */
{ 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ { 0x6, 0x7F, 0x32, 0x00, 0x0D }, /* 500 900 5.1 */
{ 0xC, 0x61, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ { 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 */ { 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, ehl_get_combo_buf_trans(struct intel_encoder *encoder, int type, int rate,
int *n_entries) 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); *n_entries = ARRAY_SIZE(ehl_combo_phy_ddi_translations_dp);
return 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 * 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); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
if (type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.hobl) { switch (type) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); 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) { if (!intel_dp->hobl_failed && rate <= 540000) {
/* Same table applies to TGL, RKL and DG1 */ /* Same table applies to TGL, RKL and DG1 */
*n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_edp_hbr2_hobl); *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_edp_hbr2_hobl);
return 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;
} }
*n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr2); if (rate > 540000) {
return tgl_combo_phy_ddi_translations_dp_hbr2; *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); *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr2);
return tgl_combo_phy_ddi_translations_dp_hbr; 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 * 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)); 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; ctl &= ~TRANS_DDI_FUNC_ENABLE;
if (IS_GEN_RANGE(dev_priv, 8, 10)) 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, int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
enum transcoder cpu_transcoder,
bool enable) bool enable)
{ {
struct drm_device *dev = intel_encoder->base.dev; struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_private *dev_priv = to_i915(dev);
intel_wakeref_t wakeref; intel_wakeref_t wakeref;
enum pipe pipe = 0;
int ret = 0; int ret = 0;
u32 tmp; u32 tmp;
@ -1832,19 +1864,12 @@ int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
if (drm_WARN_ON(dev, !wakeref)) if (drm_WARN_ON(dev, !wakeref))
return -ENXIO; return -ENXIO;
if (drm_WARN_ON(dev, tmp = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder));
!intel_encoder->get_hw_state(intel_encoder, &pipe))) {
ret = -EIO;
goto out;
}
tmp = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(pipe));
if (enable) if (enable)
tmp |= TRANS_DDI_HDCP_SIGNALLING; tmp |= TRANS_DDI_HDCP_SIGNALLING;
else else
tmp &= ~TRANS_DDI_HDCP_SIGNALLING; tmp &= ~TRANS_DDI_HDCP_SIGNALLING;
intel_de_write(dev_priv, TRANS_DDI_FUNC_CTL(pipe), tmp); intel_de_write(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder), tmp);
out:
intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref); intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
return ret; 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); intel_ddi_init_dp_buf_reg(encoder);
if (!is_mst) if (!is_mst)
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); 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, intel_dp_sink_set_decompression_state(intel_dp, crtc_state,
true); true);
intel_dp_sink_set_fec_ready(intel_dp, crtc_state); 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, intel_ddi_pre_enable_hdmi(state, encoder, crtc_state,
conn_state); conn_state);
} else { } else {
struct intel_lspcon *lspcon = struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
enc_to_intel_lspcon(encoder);
intel_ddi_pre_enable_dp(state, encoder, crtc_state, intel_ddi_pre_enable_dp(state, encoder, crtc_state,
conn_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, dig_port->set_infoframes(encoder,
crtc_state->has_infoframe, crtc_state->has_infoframe,
crtc_state, conn_state); 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_psr_update(intel_dp, crtc_state, conn_state);
intel_dp_set_infoframes(encoder, true, 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); intel_panel_update_backlight(state, encoder, crtc_state, conn_state);
} }
static void intel_ddi_update_pipe(struct intel_atomic_state *state, void intel_ddi_update_pipe(struct intel_atomic_state *state,
struct intel_encoder *encoder, struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state, const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_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, intel_ddi_update_pipe_dp(state, encoder, crtc_state,
conn_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)); 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) void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
{ {
struct intel_digital_port *dig_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_encoder_init(&dev_priv->drm, &encoder->base, &intel_ddi_funcs,
DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port)); 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->hotplug = intel_ddi_hotplug;
encoder->compute_output_type = intel_ddi_compute_output_type; encoder->compute_output_type = intel_ddi_compute_output_type;
encoder->compute_config = intel_ddi_compute_config; 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->cloneable = 0;
encoder->pipe_mask = ~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) if (INTEL_GEN(dev_priv) >= 11)
dig_port->saved_port_bits = dig_port->saved_port_bits =
intel_de_read(dev_priv, DDI_BUF_CTL(port)) intel_de_read(dev_priv, DDI_BUF_CTL(port))

View File

@ -16,6 +16,7 @@ struct intel_crtc_state;
struct intel_dp; struct intel_dp;
struct intel_dpll_hw_state; struct intel_dpll_hw_state;
struct intel_encoder; struct intel_encoder;
enum transcoder;
void intel_ddi_fdi_post_disable(struct intel_atomic_state *state, void intel_ddi_fdi_post_disable(struct intel_atomic_state *state,
struct intel_encoder *intel_encoder, 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 bxt_signal_levels(struct intel_dp *intel_dp);
u32 ddi_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, int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
enum transcoder cpu_transcoder,
bool enable); bool enable);
void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder); void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder);

View File

@ -67,6 +67,7 @@
#include "intel_bw.h" #include "intel_bw.h"
#include "intel_cdclk.h" #include "intel_cdclk.h"
#include "intel_color.h" #include "intel_color.h"
#include "intel_csr.h"
#include "intel_display_types.h" #include "intel_display_types.h"
#include "intel_dp_link_training.h" #include "intel_dp_link_training.h"
#include "intel_fbc.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; return POWER_DOMAIN_PORT_DDI_F_LANES;
case PORT_G: case PORT_G:
return POWER_DOMAIN_PORT_DDI_G_LANES; 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: default:
MISSING_CASE(port); MISSING_CASE(port);
return POWER_DOMAIN_PORT_OTHER; 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; return POWER_DOMAIN_AUX_F_TBT;
case AUX_CH_G: case AUX_CH_G:
return POWER_DOMAIN_AUX_G_TBT; 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: default:
MISSING_CASE(dig_port->aux_ch); MISSING_CASE(dig_port->aux_ch);
return POWER_DOMAIN_AUX_C_TBT; 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; return POWER_DOMAIN_AUX_F;
case AUX_CH_G: case AUX_CH_G:
return POWER_DOMAIN_AUX_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: default:
MISSING_CASE(aux_ch); MISSING_CASE(aux_ch);
return POWER_DOMAIN_AUX_A; 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) static int intel_modeset_checks(struct intel_atomic_state *state)
{ {
struct drm_i915_private *dev_priv = to_i915(state->base.dev); struct drm_i915_private *dev_priv = to_i915(state->base.dev);
int ret;
state->modeset = true; 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)) if (IS_HASWELL(dev_priv))
return hsw_mode_set_planes_workaround(state); 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) bool *need_cdclk_calc)
{ {
struct drm_i915_private *dev_priv = to_i915(state->base.dev); 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_plane_state *plane_state;
struct intel_bw_state *new_bw_state; struct intel_bw_state *new_bw_state;
struct intel_plane *plane; struct intel_plane *plane;
@ -14808,9 +14814,11 @@ static int intel_atomic_check_cdclk(struct intel_atomic_state *state,
return ret; return ret;
} }
old_cdclk_state = intel_atomic_get_old_cdclk_state(state);
new_cdclk_state = intel_atomic_get_new_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; *need_cdclk_calc = true;
ret = dev_priv->display.bw_calc_min_cdclk(state); 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); 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, static int intel_atomic_commit(struct drm_device *dev,
struct drm_atomic_state *_state, struct drm_atomic_state *_state,
bool nonblock) bool nonblock)
@ -15840,12 +15840,6 @@ static int intel_atomic_commit(struct drm_device *dev,
intel_shared_dpll_swap_state(state); intel_shared_dpll_swap_state(state);
intel_atomic_track_fbs(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); drm_atomic_state_get(&state->base);
INIT_WORK(&state->base.commit_work, intel_atomic_commit_work); 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); intel_pps_init(dev_priv);
if (!HAS_DISPLAY(dev_priv) || !INTEL_DISPLAY_ENABLED(dev_priv)) if (!HAS_DISPLAY(dev_priv))
return; return;
if (IS_ROCKETLAKE(dev_priv)) { if (IS_ROCKETLAKE(dev_priv)) {
@ -17878,6 +17872,27 @@ int intel_modeset_init_noirq(struct drm_i915_private *i915)
{ {
int ret; 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->modeset_wq = alloc_ordered_workqueue("i915_modeset", 0);
i915->flip_wq = alloc_workqueue("i915_flip", WQ_HIGHPRI | i915->flip_wq = alloc_workqueue("i915_flip", WQ_HIGHPRI |
WQ_UNBOUND, WQ_UNBOUND_MAX_ACTIVE); 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); ret = intel_cdclk_init(i915);
if (ret) if (ret)
return ret; goto cleanup_vga_client_pw_domain_csr;
ret = intel_dbuf_init(i915); ret = intel_dbuf_init(i915);
if (ret) if (ret)
return ret; goto cleanup_vga_client_pw_domain_csr;
ret = intel_bw_init(i915); ret = intel_bw_init(i915);
if (ret) if (ret)
return ret; goto cleanup_vga_client_pw_domain_csr;
init_llist_head(&i915->atomic_helper.free_list); init_llist_head(&i915->atomic_helper.free_list);
INIT_WORK(&i915->atomic_helper.free_work, 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); intel_fbc_init(i915);
return 0; 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 */ /* part #2: call after irq install, but before gem init */
int intel_modeset_init(struct drm_i915_private *i915) int intel_modeset_init_nogem(struct drm_i915_private *i915)
{ {
struct drm_device *dev = &i915->drm; struct drm_device *dev = &i915->drm;
enum pipe pipe; enum pipe pipe;
@ -17925,7 +17949,7 @@ int intel_modeset_init(struct drm_i915_private *i915)
INTEL_NUM_PIPES(i915), INTEL_NUM_PIPES(i915),
INTEL_NUM_PIPES(i915) > 1 ? "s" : ""); INTEL_NUM_PIPES(i915) > 1 ? "s" : "");
if (HAS_DISPLAY(i915) && INTEL_DISPLAY_ENABLED(i915)) { if (HAS_DISPLAY(i915)) {
for_each_pipe(i915, pipe) { for_each_pipe(i915, pipe) {
ret = intel_crtc_init(i915, pipe); ret = intel_crtc_init(i915, pipe);
if (ret) { if (ret) {
@ -18007,6 +18031,30 @@ int intel_modeset_init(struct drm_i915_private *i915)
return 0; 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) 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); 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); 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) #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
struct intel_display_error_state { 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)); 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; return NULL;
error = kzalloc(sizeof(*error), GFP_ATOMIC); error = kzalloc(sizeof(*error), GFP_ATOMIC);

View File

@ -272,8 +272,6 @@ enum dpio_phy {
DPIO_PHY2, DPIO_PHY2,
}; };
#define I915_NUM_PHYS_VLV 2
enum aux_ch { enum aux_ch {
AUX_CH_A, AUX_CH_A,
AUX_CH_B, AUX_CH_B,
@ -282,6 +280,8 @@ enum aux_ch {
AUX_CH_E, /* ICL+ */ AUX_CH_E, /* ICL+ */
AUX_CH_F, AUX_CH_F,
AUX_CH_G, AUX_CH_G,
AUX_CH_H,
AUX_CH_I,
}; };
#define aux_ch_name(a) ((a) + 'A') #define aux_ch_name(a) ((a) + 'A')
@ -629,9 +629,11 @@ intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info,
/* modesetting */ /* modesetting */
void intel_modeset_init_hw(struct drm_i915_private *i915); void intel_modeset_init_hw(struct drm_i915_private *i915);
int intel_modeset_init_noirq(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); int intel_modeset_init(struct drm_i915_private *i915);
void intel_modeset_driver_remove(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_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_display_resume(struct drm_device *dev);
void intel_init_pch_refclk(struct drm_i915_private *dev_priv); void intel_init_pch_refclk(struct drm_i915_private *dev_priv);

View File

@ -601,6 +601,11 @@ static void intel_hdcp_info(struct seq_file *m,
{ {
bool hdcp_cap, hdcp2_cap; 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); hdcp_cap = intel_hdcp_capable(intel_connector);
hdcp2_cap = intel_hdcp2_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) if (!hdcp_cap && !hdcp2_cap)
seq_puts(m, "None"); seq_puts(m, "None");
out:
seq_puts(m, "\n"); 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_encoder *intel_encoder = intel_attached_encoder(intel_connector);
struct intel_dp *intel_dp = enc_to_intel_dp(intel_encoder); 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, "\tDPCD rev: %x\n", intel_dp->dpcd[DP_DPCD_REV]);
seq_printf(m, "\taudio support: %s\n", yesno(intel_dp->has_audio)); 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); intel_panel_info(m, &intel_connector->panel);
drm_dp_downstream_debug(m, intel_dp->dpcd, intel_dp->downstream_ports, drm_dp_downstream_debug(m, intel_dp->dpcd, intel_dp->downstream_ports,
&intel_dp->aux); edid ? edid->data : NULL, &intel_dp->aux);
if (intel_connector->hdcp.shim) {
seq_puts(m, "\tHDCP version: ");
intel_hdcp_info(m, intel_connector);
}
} }
static void intel_dp_mst_info(struct seq_file *m, 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); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(intel_encoder);
seq_printf(m, "\taudio support: %s\n", yesno(intel_hdmi->has_audio)); 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, static void intel_lvds_info(struct seq_file *m,
@ -708,6 +707,9 @@ static void intel_connector_info(struct seq_file *m,
break; break;
} }
seq_puts(m, "\tHDCP version: ");
intel_hdcp_info(m, intel_connector);
seq_printf(m, "\tmodes:\n"); seq_printf(m, "\tmodes:\n");
list_for_each_entry(mode, &connector->modes, head) list_for_each_entry(mode, &connector->modes, head)
intel_seq_print_mode(m, 2, mode); 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_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) { drm_for_each_connector_iter(connector, &conn_iter) {
bool supported = false;
if (connector->state->crtc != &intel_crtc->base) if (connector->state->crtc != &intel_crtc->base)
continue; continue;
seq_printf(m, "%s:\n", connector->name); 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); 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); mutex_lock(&drrs->mutex);
/* DRRS Supported */ /* DRRS Supported */
seq_puts(m, "\tDRRS Supported: Yes\n"); seq_puts(m, "\tDRRS Enabled: Yes\n");
/* disable_drrs() will make drrs->dp NULL */ /* disable_drrs() will make drrs->dp NULL */
if (!drrs->dp) { if (!drrs->dp) {
@ -1118,7 +1128,7 @@ static void drrs_status_per_crtc(struct seq_file *m,
mutex_unlock(&drrs->mutex); mutex_unlock(&drrs->mutex);
} else { } else {
/* DRRS not supported. Print the VBT parameter*/ /* DRRS not supported. Print the VBT parameter*/
seq_puts(m, "\tDRRS Supported : No"); seq_puts(m, "\tDRRS Enabled : No");
} }
seq_puts(m, "\n"); 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) if (connector->status != connector_status_connected)
return -ENODEV; return -ENODEV;
/* HDCP is supported by connector */
if (!intel_connector->hdcp.shim)
return -EINVAL;
seq_printf(m, "%s:%d HDCP version: ", connector->name, seq_printf(m, "%s:%d HDCP version: ", connector->name,
connector->base.id); connector->base.id);
intel_hdcp_info(m, intel_connector); intel_hdcp_info(m, intel_connector);

View File

@ -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; unsigned long abox_mask = INTEL_INFO(dev_priv)->abox_mask;
int config, i; 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 */ /* Wa_1409767108: tgl */
table = wa_1409767108_buddy_page_masks; table = wa_1409767108_buddy_page_masks;
else else

View File

@ -28,6 +28,7 @@
#include <linux/async.h> #include <linux/async.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/pwm.h>
#include <linux/sched/clock.h> #include <linux/sched/clock.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
@ -223,6 +224,7 @@ struct intel_panel {
bool util_pin_active_low; /* bxt+ */ bool util_pin_active_low; /* bxt+ */
u8 controller; /* bxt+ only */ u8 controller; /* bxt+ only */
struct pwm_device *pwm; struct pwm_device *pwm;
struct pwm_state pwm_state;
/* DPCD backlight */ /* DPCD backlight */
u8 pwmgen_bit_count; u8 pwmgen_bit_count;
@ -314,10 +316,12 @@ struct intel_hdcp_shim {
/* Enables HDCP signalling on the port */ /* Enables HDCP signalling on the port */
int (*toggle_signalling)(struct intel_digital_port *dig_port, int (*toggle_signalling)(struct intel_digital_port *dig_port,
enum transcoder cpu_transcoder,
bool enable); bool enable);
/* Ensures the link is still protected */ /* 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. */ /* Detects panel's hdcp capability. This is optional for HDMI. */
int (*hdcp_capable)(struct intel_digital_port *dig_port, int (*hdcp_capable)(struct intel_digital_port *dig_port,
@ -479,8 +483,6 @@ struct intel_atomic_state {
bool dpll_set, modeset; bool dpll_set, modeset;
u8 active_pipes;
struct intel_shared_dpll_state shared_dpll[I915_NUM_PLLS]; struct intel_shared_dpll_state shared_dpll[I915_NUM_PLLS];
/* /*
@ -491,11 +493,6 @@ struct intel_atomic_state {
bool rps_interactive; bool rps_interactive;
/*
* active_pipes
*/
bool global_state_changed;
struct i915_sw_fence commit_ready; struct i915_sw_fence commit_ready;
struct llist_node freed; struct llist_node freed;
@ -1275,6 +1272,7 @@ struct intel_dp {
u8 sink_count; u8 sink_count;
bool link_mst; bool link_mst;
bool link_trained; bool link_trained;
bool has_hdmi_sink;
bool has_audio; bool has_audio;
bool reset_link_params; bool reset_link_params;
u8 dpcd[DP_RECEIVER_CAP_SIZE]; u8 dpcd[DP_RECEIVER_CAP_SIZE];
@ -1376,6 +1374,14 @@ struct intel_dp {
/* Displayport compliance testing */ /* Displayport compliance testing */
struct intel_dp_compliance compliance; 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 */ /* Display stream compression testing */
bool force_dsc_en; bool force_dsc_en;
@ -1415,6 +1421,11 @@ struct intel_digital_port {
enum phy_fia tc_phy_fia; enum phy_fia tc_phy_fia;
u8 tc_phy_fia_idx; 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, void (*write_infoframe)(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state, const struct intel_crtc_state *crtc_state,
unsigned int type, 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 * static inline struct intel_digital_port *
enc_to_dig_port(struct intel_encoder *encoder) 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)) if (intel_encoder_is_dig_port(intel_encoder))
return container_of(&encoder->base, struct intel_digital_port, return container_of(&encoder->base, struct intel_digital_port,
base.base); base.base);
else if (intel_encoder_is_mst(intel_encoder))
return enc_to_mst(encoder)->primary;
else else
return NULL; return NULL;
} }
@ -1543,13 +1568,6 @@ intel_attached_dig_port(struct intel_connector *connector)
return enc_to_dig_port(intel_attached_encoder(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) static inline struct intel_dp *enc_to_intel_dp(struct intel_encoder *encoder)
{ {
return &enc_to_dig_port(encoder)->dp; return &enc_to_dig_port(encoder)->dp;

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,7 @@ struct drm_encoder;
struct drm_i915_private; struct drm_i915_private;
struct drm_modeset_acquire_ctx; struct drm_modeset_acquire_ctx;
struct drm_dp_vsc_sdp; struct drm_dp_vsc_sdp;
struct intel_atomic_state;
struct intel_connector; struct intel_connector;
struct intel_crtc_state; struct intel_crtc_state;
struct intel_digital_port; 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, int intel_dp_retrain_link(struct intel_encoder *encoder,
struct drm_modeset_acquire_ctx *ctx); struct drm_modeset_acquire_ctx *ctx);
void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode); 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, void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state, const struct intel_crtc_state *crtc_state,
bool enable); bool enable);
@ -81,6 +83,8 @@ void intel_edp_drrs_enable(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state); const struct intel_crtc_state *crtc_state);
void intel_edp_drrs_disable(struct intel_dp *intel_dp, void intel_edp_drrs_disable(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state); 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, void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits); unsigned int frontbuffer_bits);
void intel_edp_drrs_flush(struct drm_i915_private *dev_priv, 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); 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__ */ #endif /* __INTEL_DP_H__ */

View 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;
}

View File

@ -37,6 +37,7 @@
#include "intel_dp.h" #include "intel_dp.h"
#include "intel_dp_mst.h" #include "intel_dp_mst.h"
#include "intel_dpio_phy.h" #include "intel_dpio_phy.h"
#include "intel_hdcp.h"
static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state, 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", drm_dbg_kms(&i915->drm, "active links %d\n",
intel_dp->active_mst_links); intel_dp->active_mst_links);
intel_hdcp_disable(intel_mst->connector);
drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, connector->port); drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, connector->port);
ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr); 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) if (pipe_config->has_audio)
intel_audio_codec_enable(encoder, pipe_config, conn_state); 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, 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, intel_dp_mst_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx, bool force) 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_connector *intel_connector = to_intel_connector(connector);
struct intel_dp *intel_dp = intel_connector->mst_port; struct intel_dp *intel_dp = intel_connector->mst_port;
if (!INTEL_DISPLAY_ENABLED(i915))
return connector_status_disconnected;
if (drm_connector_is_unregistered(connector)) if (drm_connector_is_unregistered(connector))
return connector_status_disconnected; 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_force_audio_property(connector);
intel_attach_broadcast_rgb_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 * Reuse the prop from the SST connector because we're
* not allowed to create new props after device registration. * 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->compute_config_late = intel_dp_mst_compute_config_late;
intel_encoder->disable = intel_mst_disable_dp; intel_encoder->disable = intel_mst_disable_dp;
intel_encoder->post_disable = intel_mst_post_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_pll_enable = intel_mst_pre_pll_enable_dp;
intel_encoder->pre_enable = intel_mst_pre_enable_dp; intel_encoder->pre_enable = intel_mst_pre_enable_dp;
intel_encoder->enable = intel_mst_enable_dp; intel_encoder->enable = intel_mst_enable_dp;

View File

@ -147,6 +147,18 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv,
pll->info->name, onoff(state), onoff(cur_state)); 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 * intel_prepare_shared_dpll - call a dpll's prepare hook
* @crtc_state: CRTC, and its state, which has a shared dpll * @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_shared_dpll *pll,
struct intel_dpll_hw_state *hw_state) struct intel_dpll_hw_state *hw_state)
{ {
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);
}
return icl_pll_get_hw_state(dev_priv, pll, hw_state, enable_reg); 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, static void combo_pll_enable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll) 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) && if (IS_ELKHARTLAKE(dev_priv) &&
pll->info->id == DPLL_ID_EHL_DPLL4) { pll->info->id == DPLL_ID_EHL_DPLL4) {
enable_reg = MG_PLL_ENABLE(0);
/* /*
* We need to disable DC states when this DPLL is enabled. * 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, static void combo_pll_disable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll) 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);
icl_pll_disable(dev_priv, pll, enable_reg);
intel_display_power_put(dev_priv, POWER_DOMAIN_DPLL_DC_OFF,
pll->wakeref);
return;
}
icl_pll_disable(dev_priv, pll, enable_reg); 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, static void tbt_pll_disable(struct drm_i915_private *dev_priv,

View File

@ -313,9 +313,15 @@ static void intel_dvo_pre_enable(struct intel_atomic_state *state,
static enum drm_connector_status static enum drm_connector_status
intel_dvo_detect(struct drm_connector *connector, bool force) 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)); struct intel_dvo *intel_dvo = intel_attached_dvo(to_intel_connector(connector));
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
connector->base.id, connector->name); connector->base.id, connector->name);
if (!INTEL_DISPLAY_ENABLED(i915))
return connector_status_disconnected;
return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev); return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
} }

View File

@ -451,8 +451,7 @@ int intel_fbdev_init(struct drm_device *dev)
struct intel_fbdev *ifbdev; struct intel_fbdev *ifbdev;
int ret; int ret;
if (drm_WARN_ON(dev, !HAS_DISPLAY(dev_priv) || if (drm_WARN_ON(dev, !HAS_DISPLAY(dev_priv)))
!INTEL_DISPLAY_ENABLED(dev_priv)))
return -ENODEV; return -ENODEV;
ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL); ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);

View File

@ -834,7 +834,7 @@ int intel_gmbus_setup(struct drm_i915_private *dev_priv)
unsigned int pin; unsigned int pin;
int ret; int ret;
if (!HAS_DISPLAY(dev_priv) || !INTEL_DISPLAY_ENABLED(dev_priv)) if (!HAS_DISPLAY(dev_priv))
return 0; return 0;
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))

View File

@ -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) 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; enum i915_power_well_id id;
intel_wakeref_t wakeref;
bool enabled = false; bool enabled = false;
/* /*
@ -162,17 +161,9 @@ static bool hdcp_key_loadable(struct drm_i915_private *dev_priv)
else else
id = SKL_DISP_PW_1; id = SKL_DISP_PW_1;
mutex_lock(&power_domains->lock);
/* PG1 (power well #1) needs to be enabled */ /* PG1 (power well #1) needs to be enabled */
for_each_power_well(dev_priv, power_well) { with_intel_runtime_pm(&dev_priv->runtime_pm, wakeref)
if (power_well->desc->id == id) { enabled = intel_display_power_well_is_enabled(dev_priv, id);
enabled = power_well->desc->ops->is_enabled(dev_priv,
power_well);
break;
}
}
mutex_unlock(&power_domains->lock);
/* /*
* Another req for hdcp key loadability is enabled state of pll for * 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_de_write(dev_priv, HDCP_REP_CTL,
intel_hdcp_get_repeater_ctl(dev_priv, cpu_transcoder, port)); 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) if (ret)
return 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", drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being disabled...\n",
connector->base.name, connector->base.base.id); 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; hdcp->hdcp_encrypted = false;
intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder, port), 0); intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder, port), 0);
if (intel_de_wait_for_clear(dev_priv, 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_write(dev_priv, HDCP_REP_CTL,
intel_de_read(dev_priv, HDCP_REP_CTL) & ~repeater_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) { if (ret) {
drm_err(&dev_priv->drm, "Failed to disable HDCP signalling\n"); drm_err(&dev_priv->drm, "Failed to disable HDCP signalling\n");
return ret; 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); 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 */ /* Implements Part 3 of the HDCP authorization procedure */
static int intel_hdcp_check_link(struct intel_connector *connector) 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; int ret = 0;
mutex_lock(&hdcp->mutex); mutex_lock(&hdcp->mutex);
mutex_lock(&dig_port->hdcp_mutex);
cpu_transcoder = hdcp->cpu_transcoder; cpu_transcoder = hdcp->cpu_transcoder;
/* Check_link valid only when HDCP1.4 is enabled */ /* 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, connector->base.name, connector->base.base.id,
intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port))); intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port)));
ret = -ENXIO; ret = -ENXIO;
hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED; intel_hdcp_update_value(connector,
schedule_work(&hdcp->prop_work); DRM_MODE_CONTENT_PROTECTION_DESIRED,
true);
goto out; 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) { if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
hdcp->value = DRM_MODE_CONTENT_PROTECTION_ENABLED; intel_hdcp_update_value(connector,
schedule_work(&hdcp->prop_work); DRM_MODE_CONTENT_PROTECTION_ENABLED, true);
} }
goto out; goto out;
} }
@ -923,20 +958,23 @@ static int intel_hdcp_check_link(struct intel_connector *connector)
ret = _intel_hdcp_disable(connector); ret = _intel_hdcp_disable(connector);
if (ret) { if (ret) {
drm_err(&dev_priv->drm, "Failed to disable hdcp (%d)\n", ret); drm_err(&dev_priv->drm, "Failed to disable hdcp (%d)\n", ret);
hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED; intel_hdcp_update_value(connector,
schedule_work(&hdcp->prop_work); DRM_MODE_CONTENT_PROTECTION_DESIRED,
true);
goto out; goto out;
} }
ret = _intel_hdcp_enable(connector); ret = _intel_hdcp_enable(connector);
if (ret) { if (ret) {
drm_err(&dev_priv->drm, "Failed to enable hdcp (%d)\n", ret); drm_err(&dev_priv->drm, "Failed to enable hdcp (%d)\n", ret);
hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED; intel_hdcp_update_value(connector,
schedule_work(&hdcp->prop_work); DRM_MODE_CONTENT_PROTECTION_DESIRED,
true);
goto out; goto out;
} }
out: out:
mutex_unlock(&dig_port->hdcp_mutex);
mutex_unlock(&hdcp->mutex); mutex_unlock(&hdcp->mutex);
return ret; return ret;
} }
@ -962,6 +1000,8 @@ static void intel_hdcp_prop_work(struct work_struct *work)
mutex_unlock(&hdcp->mutex); mutex_unlock(&hdcp->mutex);
drm_modeset_unlock(&dev_priv->drm.mode_config.connection_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) 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)) & intel_de_read(dev_priv, HDCP2_STATUS(dev_priv, cpu_transcoder, port)) &
LINK_ENCRYPTION_STATUS); LINK_ENCRYPTION_STATUS);
if (hdcp->shim->toggle_signalling) { 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) { if (ret) {
drm_err(&dev_priv->drm, drm_err(&dev_priv->drm,
"Failed to enable HDCP signalling. %d\n", "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"); drm_dbg_kms(&dev_priv->drm, "Disable Encryption Timedout");
if (hdcp->shim->toggle_signalling) { 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) { if (ret) {
drm_err(&dev_priv->drm, drm_err(&dev_priv->drm,
"Failed to disable HDCP signalling. %d\n", "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", "HDCP2.2 link stopped the encryption, %x\n",
intel_de_read(dev_priv, HDCP2_STATUS(dev_priv, cpu_transcoder, port))); intel_de_read(dev_priv, HDCP2_STATUS(dev_priv, cpu_transcoder, port)));
ret = -ENXIO; ret = -ENXIO;
hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED; intel_hdcp_update_value(connector,
schedule_work(&hdcp->prop_work); DRM_MODE_CONTENT_PROTECTION_DESIRED,
true);
goto out; goto out;
} }
ret = hdcp->shim->check_2_2_link(dig_port); ret = hdcp->shim->check_2_2_link(dig_port);
if (ret == HDCP_LINK_PROTECTED) { if (ret == HDCP_LINK_PROTECTED) {
if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
hdcp->value = DRM_MODE_CONTENT_PROTECTION_ENABLED; intel_hdcp_update_value(connector,
schedule_work(&hdcp->prop_work); DRM_MODE_CONTENT_PROTECTION_ENABLED,
true);
} }
goto out; goto out;
} }
@ -1788,8 +1832,9 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
"HDCP2.2 Downstream topology change\n"); "HDCP2.2 Downstream topology change\n");
ret = hdcp2_authenticate_repeater_topology(connector); ret = hdcp2_authenticate_repeater_topology(connector);
if (!ret) { if (!ret) {
hdcp->value = DRM_MODE_CONTENT_PROTECTION_ENABLED; intel_hdcp_update_value(connector,
schedule_work(&hdcp->prop_work); DRM_MODE_CONTENT_PROTECTION_ENABLED,
true);
goto out; goto out;
} }
drm_dbg_kms(&dev_priv->drm, 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, drm_err(&dev_priv->drm,
"[%s:%d] Failed to disable hdcp2.2 (%d)\n", "[%s:%d] Failed to disable hdcp2.2 (%d)\n",
connector->base.name, connector->base.base.id, ret); connector->base.name, connector->base.base.id, ret);
hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED; intel_hdcp_update_value(connector,
schedule_work(&hdcp->prop_work); DRM_MODE_CONTENT_PROTECTION_DESIRED, true);
goto out; 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", "[%s:%d] Failed to enable hdcp2.2 (%d)\n",
connector->base.name, connector->base.base.id, connector->base.name, connector->base.base.id,
ret); ret);
hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED; intel_hdcp_update_value(connector,
schedule_work(&hdcp->prop_work); DRM_MODE_CONTENT_PROTECTION_DESIRED,
true);
goto out; goto out;
} }
@ -1835,6 +1881,9 @@ static void intel_hdcp_check_work(struct work_struct *work)
check_work); check_work);
struct intel_connector *connector = intel_hdcp_to_connector(hdcp); struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
if (drm_connector_is_unregistered(&connector->base))
return;
if (!intel_hdcp2_check_link(connector)) if (!intel_hdcp2_check_link(connector))
schedule_delayed_work(&hdcp->check_work, schedule_delayed_work(&hdcp->check_work,
DRM_HDCP2_CHECK_PERIOD_MS); 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, static int initialize_hdcp_port_data(struct intel_connector *connector,
enum port port,
const struct intel_hdcp_shim *shim) const struct intel_hdcp_shim *shim)
{ {
struct drm_i915_private *dev_priv = to_i915(connector->base.dev); 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; struct hdcp_port_data *data = &hdcp->port_data;
if (INTEL_GEN(dev_priv) < 12) if (INTEL_GEN(dev_priv) < 12)
data->fw_ddi = data->fw_ddi = intel_get_mei_fw_ddi_index(port);
intel_get_mei_fw_ddi_index(intel_attached_encoder(connector)->port);
else else
/* /*
* As per ME FW API expectation, for GEN 12+, fw_ddi is filled * 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) const struct intel_hdcp_shim *shim)
{ {
struct drm_i915_private *i915 = to_i915(connector->base.dev); struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_hdcp *hdcp = &connector->hdcp; struct intel_hdcp *hdcp = &connector->hdcp;
int ret; int ret;
ret = initialize_hdcp_port_data(connector, shim); ret = initialize_hdcp_port_data(connector, port, shim);
if (ret) { if (ret) {
drm_dbg_kms(&i915->drm, "Mei hdcp data init failed\n"); drm_dbg_kms(&i915->drm, "Mei hdcp data init failed\n");
return; return;
@ -1991,6 +2040,7 @@ static void intel_hdcp2_init(struct intel_connector *connector,
} }
int intel_hdcp_init(struct intel_connector *connector, int intel_hdcp_init(struct intel_connector *connector,
enum port port,
const struct intel_hdcp_shim *shim) const struct intel_hdcp_shim *shim)
{ {
struct drm_i915_private *dev_priv = to_i915(connector->base.dev); 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) if (!shim)
return -EINVAL; return -EINVAL;
if (is_hdcp2_supported(dev_priv)) if (is_hdcp2_supported(dev_priv) && !connector->mst_port)
intel_hdcp2_init(connector, shim); intel_hdcp2_init(connector, port, shim);
ret = ret =
drm_connector_attach_content_protection_property(&connector->base, 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) enum transcoder cpu_transcoder, u8 content_type)
{ {
struct drm_i915_private *dev_priv = to_i915(connector->base.dev); 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; struct intel_hdcp *hdcp = &connector->hdcp;
unsigned long check_link_interval = DRM_HDCP_CHECK_PERIOD_MS; unsigned long check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
int ret = -EINVAL; int ret = -EINVAL;
@ -2033,14 +2084,14 @@ int intel_hdcp_enable(struct intel_connector *connector,
return -ENOENT; return -ENOENT;
mutex_lock(&hdcp->mutex); mutex_lock(&hdcp->mutex);
mutex_lock(&dig_port->hdcp_mutex);
drm_WARN_ON(&dev_priv->drm, drm_WARN_ON(&dev_priv->drm,
hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED); hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED);
hdcp->content_type = content_type; hdcp->content_type = content_type;
hdcp->cpu_transcoder = cpu_transcoder;
if (INTEL_GEN(dev_priv) >= 12) { if (INTEL_GEN(dev_priv) >= 12)
hdcp->cpu_transcoder = cpu_transcoder;
hdcp->port_data.fw_tc = intel_get_mei_fw_tc(cpu_transcoder); 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 * 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) { if (!ret) {
schedule_delayed_work(&hdcp->check_work, check_link_interval); schedule_delayed_work(&hdcp->check_work, check_link_interval);
hdcp->value = DRM_MODE_CONTENT_PROTECTION_ENABLED; intel_hdcp_update_value(connector,
schedule_work(&hdcp->prop_work); DRM_MODE_CONTENT_PROTECTION_ENABLED,
true);
} }
mutex_unlock(&dig_port->hdcp_mutex);
mutex_unlock(&hdcp->mutex); mutex_unlock(&hdcp->mutex);
return ret; return ret;
} }
int intel_hdcp_disable(struct intel_connector *connector) 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; struct intel_hdcp *hdcp = &connector->hdcp;
int ret = 0; int ret = 0;
@ -2080,15 +2134,20 @@ int intel_hdcp_disable(struct intel_connector *connector)
return -ENOENT; return -ENOENT;
mutex_lock(&hdcp->mutex); mutex_lock(&hdcp->mutex);
mutex_lock(&dig_port->hdcp_mutex);
if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
hdcp->value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; goto out;
if (hdcp->hdcp2_encrypted)
ret = _intel_hdcp2_disable(connector);
else if (hdcp->hdcp_encrypted)
ret = _intel_hdcp_disable(connector);
}
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); mutex_unlock(&hdcp->mutex);
cancel_delayed_work_sync(&hdcp->check_work); cancel_delayed_work_sync(&hdcp->check_work);
return ret; return ret;
@ -2102,11 +2161,15 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state,
struct intel_connector *connector = struct intel_connector *connector =
to_intel_connector(conn_state->connector); to_intel_connector(conn_state->connector);
struct intel_hdcp *hdcp = &connector->hdcp; 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->hdcp_content_type != hdcp->content_type &&
conn_state->content_protection != conn_state->content_protection !=
DRM_MODE_CONTENT_PROTECTION_UNDESIRED); DRM_MODE_CONTENT_PROTECTION_UNDESIRED);
bool desired_and_not_enabled = false;
/* /*
* During the HDCP encryption session if Type change is requested, * 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) void intel_hdcp_cleanup(struct intel_connector *connector)
{ {
if (!connector->hdcp.shim) struct intel_hdcp *hdcp = &connector->hdcp;
if (!hdcp->shim)
return; return;
mutex_lock(&connector->hdcp.mutex); /*
kfree(connector->hdcp.port_data.streams); * If the connector is registered, it's possible userspace could kick
mutex_unlock(&connector->hdcp.mutex); * 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, void intel_hdcp_atomic_check(struct drm_connector *connector,

View File

@ -22,7 +22,7 @@ enum transcoder;
void intel_hdcp_atomic_check(struct drm_connector *connector, void intel_hdcp_atomic_check(struct drm_connector *connector,
struct drm_connector_state *old_state, struct drm_connector_state *old_state,
struct drm_connector_state *new_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); const struct intel_hdcp_shim *hdcp_shim);
int intel_hdcp_enable(struct intel_connector *connector, int intel_hdcp_enable(struct intel_connector *connector,
enum transcoder cpu_transcoder, u8 content_type); enum transcoder cpu_transcoder, u8 content_type);

View File

@ -1477,7 +1477,8 @@ int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port *dig_port,
return ret; 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 drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_digital_port *dig_port = intel_attached_dig_port(connector); 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); 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) { if (ret) {
drm_err(&dev_priv->drm, drm_err(&dev_priv->drm,
"Disable HDCP signalling failed (%d)\n", ret); "Disable HDCP signalling failed (%d)\n", ret);
return 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) { if (ret) {
drm_err(&dev_priv->drm, drm_err(&dev_priv->drm,
"Enable HDCP signalling failed (%d)\n", ret); "Enable HDCP signalling failed (%d)\n", ret);
@ -1512,6 +1515,7 @@ static int kbl_repositioning_enc_en_signal(struct intel_connector *connector)
static static
int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *dig_port, int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
enum transcoder cpu_transcoder,
bool enable) bool enable)
{ {
struct intel_hdmi *hdmi = &dig_port->hdmi; 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) if (!enable)
usleep_range(6, 60); /* Bspec says >= 6us */ 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) { if (ret) {
drm_err(&dev_priv->drm, "%s HDCP signalling failed (%d)\n", drm_err(&dev_priv->drm, "%s HDCP signalling failed (%d)\n",
enable ? "Enable" : "Disable", ret); 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. * opportunity and enc_en signalling in KABYLAKE.
*/ */
if (IS_KABYLAKE(dev_priv) && enable) if (IS_KABYLAKE(dev_priv) && enable)
return kbl_repositioning_enc_en_signal(connector); return kbl_repositioning_enc_en_signal(connector,
cpu_transcoder);
return 0; return 0;
} }
static 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 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 port port = dig_port->base.port;
enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder; enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
int ret; int ret;
@ -1572,13 +1577,14 @@ bool intel_hdmi_hdcp_check_link_once(struct intel_digital_port *dig_port)
} }
static 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); struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
int retry; int retry;
for (retry = 0; retry < 3; 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; return true;
drm_err(&i915->drm, "Link check failed\n"); 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); return intel_mode_valid_max_plane_size(dev_priv, mode);
} }
static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state, bool intel_hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state,
int bpc) 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_atomic_state *state = crtc_state->uapi.state;
struct drm_connector_state *connector_state; struct drm_connector_state *connector_state;
struct drm_connector *connector; struct drm_connector *connector;
const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode;
int i; 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) if (crtc_state->pipe_bpp < bpc * 3)
return false; return false;
if (!crtc_state->has_hdmi_sink) if (!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)
return false; return false;
for_each_new_connector_in_state(state, connector, connector_state, i) { 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) if (connector_state->crtc != crtc_state->uapi.crtc)
continue; continue;
if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) { if (ycbcr420_output) {
const struct drm_hdmi_info *hdmi = &info->hdmi; const struct drm_hdmi_info *hdmi = &info->hdmi;
if (bpc == 12 && !(hdmi->y420_dc_modes & 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 */ /* Display Wa_1405510057:icl,ehl */
if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 && if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 &&
bpc == 10 && IS_GEN(dev_priv, 11) && 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) adjusted_mode->crtc_hblank_start) % 8 == 2)
return false; 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 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, int intel_hdmi_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config, struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state) 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_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
struct drm_connector *connector = conn_state->connector; struct drm_connector *connector = conn_state->connector;
struct drm_scdc *scdc = &connector->display_info.hdmi.scdc; 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; int ret;
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) 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)) if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv))
pipe_config->has_pch_encoder = true; pipe_config->has_pch_encoder = true;
if (pipe_config->has_hdmi_sink) { pipe_config->has_audio =
if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO) intel_hdmi_has_audio(encoder, pipe_config, conn_state);
pipe_config->has_audio = intel_hdmi->has_audio;
else
pipe_config->has_audio =
intel_conn_state->force_audio == HDMI_AUDIO_ON;
}
ret = intel_hdmi_compute_clock(encoder, pipe_config); ret = intel_hdmi_compute_clock(encoder, pipe_config);
if (ret) 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", drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n",
connector->base.id, connector->name); 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); wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
if (INTEL_GEN(dev_priv) >= 11 && 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)) if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
connector->ycbcr_420_allowed = true; connector->ycbcr_420_allowed = true;
intel_encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port);
intel_connector->polled = DRM_CONNECTOR_POLL_HPD; intel_connector->polled = DRM_CONNECTOR_POLL_HPD;
if (HAS_DDI(dev_priv)) 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; intel_hdmi->attached_connector = intel_connector;
if (is_hdcp_supported(dev_priv, port)) { 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); &intel_hdmi_hdcp_shim);
if (ret) if (ret)
drm_dbg_kms(&dev_priv->drm, 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; intel_encoder = &dig_port->base;
mutex_init(&dig_port->hdcp_mutex);
drm_encoder_init(&dev_priv->drm, &intel_encoder->base, drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
&intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS, &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
"HDMI %c", port_name(port)); "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->pipe_mask = ~0;
} }
intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG; 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 * BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems
* to work on real hardware. And since g4x can send infoframes to * to work on real hardware. And since g4x can send infoframes to

View File

@ -48,5 +48,7 @@ void intel_read_infoframe(struct intel_encoder *encoder,
union hdmi_infoframe *frame); union hdmi_infoframe *frame);
bool intel_hdmi_limited_color_range(const struct intel_crtc_state *crtc_state, bool intel_hdmi_limited_color_range(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_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__ */ #endif /* __INTEL_HDMI_H__ */

View File

@ -81,33 +81,12 @@
* *
* It is only valid and used by digital port encoder. * It is only valid and used by digital port encoder.
* *
* Return pin that is associatade with @port and HDP_NONE if no pin is * Return pin that is associatade with @port.
* hard associated with that @port.
*/ */
enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv, enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv,
enum port port) enum port port)
{ {
enum phy phy = intel_port_to_phy(dev_priv, port); return HPD_PORT_A + port - PORT_A;
/*
* 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;
}
} }
#define HPD_STORM_DETECT_PERIOD 1000 #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(). * only the one of them (DP) will have ->hpd_pulse().
*/ */
for_each_intel_encoder(&dev_priv->drm, encoder) { for_each_intel_encoder(&dev_priv->drm, encoder) {
bool has_hpd_pulse = intel_encoder_has_hpd_pulse(encoder);
enum port port = encoder->port; enum port port = encoder->port;
bool long_hpd; bool long_hpd;
@ -511,7 +489,7 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
if (!(BIT(pin) & pin_mask)) if (!(BIT(pin) & pin_mask))
continue; continue;
if (!has_hpd_pulse) if (!intel_encoder_has_hpd_pulse(encoder))
continue; continue;
long_hpd = long_mask & BIT(pin); long_hpd = long_mask & BIT(pin);

View File

@ -456,12 +456,6 @@ static int intel_lvds_compute_config(struct intel_encoder *intel_encoder,
return 0; 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. * 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 = { 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, .fill_modes = drm_helper_probe_single_connector_modes,
.atomic_get_property = intel_digital_connector_atomic_get_property, .atomic_get_property = intel_digital_connector_atomic_get_property,
.atomic_set_property = intel_digital_connector_atomic_set_property, .atomic_set_property = intel_digital_connector_atomic_set_property,

View File

@ -40,8 +40,6 @@
#include "intel_dsi_dcs_backlight.h" #include "intel_dsi_dcs_backlight.h"
#include "intel_panel.h" #include "intel_panel.h"
#define CRC_PMIC_PWM_PERIOD_NS 21333
void void
intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode, intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_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) static u32 pwm_get_backlight(struct intel_connector *connector)
{ {
struct intel_panel *panel = &connector->panel; struct intel_panel *panel = &connector->panel;
int duty_ns; struct pwm_state state;
duty_ns = pwm_get_duty_cycle(panel->backlight.pwm); pwm_get_state(panel->backlight.pwm, &state);
return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS); return pwm_get_relative_duty_cycle(&state, 100);
} }
static void lpt_set_backlight(const struct drm_connector_state *conn_state, u32 level) 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) 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; 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 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_connector *connector = to_intel_connector(old_conn_state->connector);
struct intel_panel *panel = &connector->panel; struct intel_panel *panel = &connector->panel;
/* Disable the backlight */ panel->backlight.pwm_state.enabled = false;
intel_panel_actually_set_backlight(old_conn_state, 0); pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
usleep_range(2000, 3000);
pwm_disable(panel->backlight.pwm);
} }
void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_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_connector *connector = to_intel_connector(conn_state->connector);
struct intel_panel *panel = &connector->panel; struct intel_panel *panel = &connector->panel;
int level = panel->backlight.level;
pwm_enable(panel->backlight.pwm); level = intel_panel_compute_brightness(connector, level);
intel_panel_actually_set_backlight(conn_state, panel->backlight.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, 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); 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; 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) { if (pwm_freq_hz) {
drm_dbg_kms(&dev_priv->drm, drm_dbg_kms(&dev_priv->drm,
@ -1567,6 +1557,22 @@ static u32 get_backlight_max_vbt(struct intel_connector *connector)
pwm_freq_hz); 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); pwm = panel->backlight.hz_to_pwm(connector, pwm_freq_hz);
if (!pwm) { if (!pwm) {
drm_dbg_kms(&dev_priv->drm, 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 drm_i915_private *dev_priv = to_i915(dev);
struct intel_panel *panel = &connector->panel; struct intel_panel *panel = &connector->panel;
const char *desc; const char *desc;
u32 level, ns; u32 level;
int retval;
/* Get the right PWM chip for DSI backlight according to VBT */ /* Get the right PWM chip for DSI backlight according to VBT */
if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) { 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; 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% */ panel->backlight.max = 100; /* 100% */
level = intel_panel_compute_brightness(connector, 100); panel->backlight.min = get_backlight_min_vbt(connector);
ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100);
retval = pwm_config(panel->backlight.pwm, ns, CRC_PMIC_PWM_PERIOD_NS); if (pwm_is_enabled(panel->backlight.pwm)) {
if (retval < 0) { /* PWM is already enabled, use existing settings */
drm_err(&dev_priv->drm, "Failed to configure the pwm chip\n"); pwm_get_state(panel->backlight.pwm, &panel->backlight.pwm_state);
pwm_put(panel->backlight.pwm);
panel->backlight.pwm = NULL; level = pwm_get_relative_duty_cycle(&panel->backlight.pwm_state,
return retval; 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", drm_info(&dev_priv->drm, "Using %s PWM for LCD backlight control\n",
desc); desc);
return 0; 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, int intel_panel_init(struct intel_panel *panel,
struct drm_display_mode *fixed_mode, struct drm_display_mode *fixed_mode,
struct drm_display_mode *downclock_mode) struct drm_display_mode *downclock_mode)

View File

@ -23,6 +23,8 @@ int intel_panel_init(struct intel_panel *panel,
struct drm_display_mode *fixed_mode, struct drm_display_mode *fixed_mode,
struct drm_display_mode *downclock_mode); struct drm_display_mode *downclock_mode);
void intel_panel_fini(struct intel_panel *panel); 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, void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_mode); struct drm_display_mode *adjusted_mode);
int intel_pch_panel_fitting(struct intel_crtc_state *crtc_state, int intel_pch_panel_fitting(struct intel_crtc_state *crtc_state,

View File

@ -555,7 +555,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp)
if (dev_priv->psr.psr2_sel_fetch_enabled) { if (dev_priv->psr.psr2_sel_fetch_enabled) {
/* WA 1408330847 */ /* 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)) IS_RKL_REVID(dev_priv, RKL_REVID_A0, RKL_REVID_A0))
intel_de_rmw(dev_priv, CHICKEN_PAR1_1, intel_de_rmw(dev_priv, CHICKEN_PAR1_1,
DIS_RAM_BYPASS_PSR2_MAN_TRACK, DIS_RAM_BYPASS_PSR2_MAN_TRACK,
@ -1109,7 +1109,7 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp)
/* WA 1408330847 */ /* WA 1408330847 */
if (dev_priv->psr.psr2_sel_fetch_enabled && 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))) IS_RKL_REVID(dev_priv, RKL_REVID_A0, RKL_REVID_A0)))
intel_de_rmw(dev_priv, CHICKEN_PAR1_1, intel_de_rmw(dev_priv, CHICKEN_PAR1_1,
DIS_RAM_BYPASS_PSR2_MAN_TRACK, 0); DIS_RAM_BYPASS_PSR2_MAN_TRACK, 0);

View File

@ -2084,14 +2084,18 @@ intel_sdvo_connector_matches_edid(struct intel_sdvo_connector *sdvo,
static enum drm_connector_status static enum drm_connector_status
intel_sdvo_detect(struct drm_connector *connector, bool force) 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 *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector));
struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
enum drm_connector_status ret; enum drm_connector_status ret;
u16 response;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
connector->base.id, connector->name); connector->base.id, connector->name);
if (!INTEL_DISPLAY_ENABLED(i915))
return connector_status_disconnected;
if (!intel_sdvo_get_value(intel_sdvo, if (!intel_sdvo_get_value(intel_sdvo,
SDVO_CMD_GET_ATTACHED_DISPLAYS, SDVO_CMD_GET_ATTACHED_DISPLAYS,
&response, 2)) &response, 2))

View File

@ -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, hscale = drm_rect_calc_hscale(&plane_state->uapi.src,
&plane_state->uapi.dst, &plane_state->uapi.dst,
0, INT_MAX); 0, INT_MAX);
if (hscale < 0x10000) hscale = max(hscale, 0x10000u);
return pixel_rate;
/* Decimation steps at 2x,4x,8x,16x */ /* Decimation steps at 2x,4x,8x,16x */
decimate = ilog2(hscale >> 16); decimate = ilog2(hscale >> 16);
@ -1640,8 +1639,8 @@ static int g4x_sprite_min_cdclk(const struct intel_crtc_state *crtc_state,
limit -= decimate; limit -= decimate;
/* -10% for RGB */ /* -10% for RGB */
if (fb->format->cpp[0] >= 4) if (!fb->format->is_yuv)
limit--; /* -10% for RGB */ limit--;
/* /*
* We should also do -10% if sprite scaling is enabled * 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] */ /* Wa_14010477008:tgl[a0..c0],rkl[all] */
if (IS_ROCKETLAKE(dev_priv) || 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 false;
return plane_id < PLANE_SPRITE4; return plane_id < PLANE_SPRITE4;

View File

@ -1706,6 +1706,9 @@ intel_tv_detect(struct drm_connector *connector,
drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] force=%d\n", drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] force=%d\n",
connector->base.id, connector->name, force); connector->base.id, connector->name, force);
if (!INTEL_DISPLAY_ENABLED(i915))
return connector_status_disconnected;
if (force) { if (force) {
struct intel_load_detect_pipe tmp; struct intel_load_detect_pipe tmp;
int ret; int ret;

View File

@ -293,8 +293,12 @@ struct bdb_general_features {
#define DVO_PORT_HDMIE 12 /* 193 */ #define DVO_PORT_HDMIE 12 /* 193 */
#define DVO_PORT_DPF 13 /* N/A */ #define DVO_PORT_DPF 13 /* N/A */
#define DVO_PORT_HDMIF 14 /* N/A */ #define DVO_PORT_HDMIF 14 /* N/A */
#define DVO_PORT_DPG 15 #define DVO_PORT_DPG 15 /* 217 */
#define DVO_PORT_HDMIG 16 #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_MIPIA 21 /* 171 */
#define DVO_PORT_MIPIB 22 /* 171 */ #define DVO_PORT_MIPIB 22 /* 171 */
#define DVO_PORT_MIPIC 23 /* 171 */ #define DVO_PORT_MIPIC 23 /* 171 */
@ -330,6 +334,8 @@ enum vbt_gmbus_ddi {
#define DP_AUX_E 0x50 #define DP_AUX_E 0x50
#define DP_AUX_F 0x60 #define DP_AUX_F 0x60
#define DP_AUX_G 0x70 #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_HBR3 0
#define VBT_DP_MAX_LINK_RATE_HBR2 1 #define VBT_DP_MAX_LINK_RATE_HBR2 1

View File

@ -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 = { static const struct drm_connector_funcs intel_dsi_connector_funcs = {
.detect = intel_panel_detect,
.late_register = intel_connector_register, .late_register = intel_connector_register,
.early_unregister = intel_connector_unregister, .early_unregister = intel_connector_unregister,
.destroy = intel_connector_destroy, .destroy = intel_connector_destroy,

View File

@ -483,7 +483,7 @@ int bxt_dsi_pll_compute(struct intel_encoder *encoder,
if (dsi_ratio < dsi_ratio_min || dsi_ratio > dsi_ratio_max) { if (dsi_ratio < dsi_ratio_min || dsi_ratio > dsi_ratio_max) {
drm_err(&dev_priv->drm, 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; return -ECHRNG;
} else } else
drm_dbg_kms(&dev_priv->drm, "DSI PLL calculation is Done!!\n"); drm_dbg_kms(&dev_priv->drm, "DSI PLL calculation is Done!!\n");

View File

@ -70,6 +70,19 @@ const struct i915_rev_steppings kbl_revids[] = {
[7] = { .gt_stepping = KBL_REVID_G0, .disp_stepping = KBL_REVID_C0 }, [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) static void wa_init_start(struct i915_wa_list *wal, const char *name, const char *engine_name)
{ {
wal->name = 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); gen12_gt_workarounds_init(i915, wal);
/* Wa_1409420604:tgl */ /* 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, wa_write_or(wal,
SUBSLICE_UNIT_LEVEL_CLKGATE2, SUBSLICE_UNIT_LEVEL_CLKGATE2,
CPSSUNIT_CLKGATE_DIS); CPSSUNIT_CLKGATE_DIS);
/* Wa_1607087056:tgl also know as BUG:1409180338 */ /* 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, wa_write_or(wal,
SLICE_UNIT_LEVEL_CLKGATE, SLICE_UNIT_LEVEL_CLKGATE,
L3_CLKGATE_DIS | L3_CR2X_CLKGATE_DIS); 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; 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_1607138336:tgl
* Wa_1607063988: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_1407928979:tgl A*
* Wa_18011464164:tgl B0+ * Wa_18011464164:tgl B0+
* Wa_22010931296:tgl B0+ * Wa_22010931296:tgl B0+
* Wa_14010919138:rkl * Wa_14010919138:rkl,tgl
*/ */
wa_write_or(wal, GEN7_FF_THREAD_MODE, wa_write_or(wal, GEN7_FF_THREAD_MODE,
GEN12_FF_TESSELATION_DOP_GATE_DISABLE); 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, GEN6_RC_SLEEP_PSMI_CONTROL,
GEN12_WAIT_FOR_EVENT_POWER_DOWN_DISABLE | GEN12_WAIT_FOR_EVENT_POWER_DOWN_DISABLE |
GEN8_RC_SEMA_IDLE_MSG_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, wa_masked_en(wal,
GEN9_CS_DEBUG_MODE1, GEN9_CS_DEBUG_MODE1,
FF_DOP_CLOCK_GATE_DISABLE); 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)) { if (IS_GEN(i915, 11)) {
/* This is not an Wa. Enable for better image quality */ /* This is not an Wa. Enable for better image quality */
wa_masked_en(wal, wa_masked_en(wal,

View File

@ -936,7 +936,7 @@ static int cmd_reg_handler(struct parser_exec_state *s,
return -EFAULT; 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", gvt_vgpu_err("%s access to non-render register (%x)\n",
cmd, offset); cmd, offset);
return -EBADRQC; return -EBADRQC;
@ -976,7 +976,7 @@ static int cmd_reg_handler(struct parser_exec_state *s,
* inhibit context will restore with correct values * inhibit context will restore with correct values
*/ */
if (IS_GEN(s->engine->i915, 9) && 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)) { !strncmp(cmd, "lri", 3)) {
intel_gvt_hypervisor_read_gpa(s->vgpu, intel_gvt_hypervisor_read_gpa(s->vgpu,
s->workload->ring_context_gpa + 12, &ctx_sr_ctl, 4); 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; return 0;
} }

View File

@ -256,11 +256,11 @@ struct intel_gvt_mmio {
/* This reg has been accessed by a VM */ /* This reg has been accessed by a VM */
#define F_ACCESSED (1 << 4) #define F_ACCESSED (1 << 4)
/* This reg has been accessed through GPU commands */ /* 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) #define F_UNALIGN (1 << 6)
/* This reg is saved/restored in context */ /* This reg is in GVT's mmio save-restor list and in hardware
#define F_IN_CTX (1 << 7) * logical context image
*/
#define F_SR_IN_CTX (1 << 7)
struct gvt_mmio_block *mmio_block; struct gvt_mmio_block *mmio_block;
unsigned int num_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 * @gvt: a GVT device
* @offset: register offset * @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) 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; 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 * intel_gvt_mmio_has_mode_mask - if a MMIO has a mode mask
* @gvt: a GVT device * @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 * @gvt: a GVT device
* @offset: register offset * @offset: register offset
* *
* Returns: * 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) 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 * @gvt: a GVT device
* @offset: register offset * @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) 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); void intel_gvt_debugfs_add_vgpu(struct intel_vgpu *vgpu);

View File

@ -1892,7 +1892,7 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
struct drm_i915_private *dev_priv = gvt->gt->i915; struct drm_i915_private *dev_priv = gvt->gt->i915;
int ret; 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); intel_vgpu_reg_imr_handler);
MMIO_DFH(SDEIMR, 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_DFH(SDEIIR, D_ALL, 0, NULL, intel_vgpu_reg_iir_handler);
MMIO_D(SDEISR, D_ALL); 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, MMIO_DH(GEN8_GAMW_ECO_DEV_RW_IA, D_BDW_PLUS, NULL,
gamw_echo_dev_rw_ia_write); 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_GM_RDR(_MMIO(0x12198), D_ALL, NULL, NULL);
MMIO_D(GEN7_CXT_SIZE, D_ALL); MMIO_D(GEN7_CXT_SIZE, D_ALL);
MMIO_RING_DFH(RING_TAIL, D_ALL, F_CMD_ACCESS, NULL, NULL); MMIO_RING_DFH(RING_TAIL, D_ALL, 0, NULL, NULL);
MMIO_RING_DFH(RING_HEAD, D_ALL, F_CMD_ACCESS, NULL, NULL); MMIO_RING_DFH(RING_HEAD, D_ALL, 0, NULL, NULL);
MMIO_RING_DFH(RING_CTL, D_ALL, F_CMD_ACCESS, NULL, NULL); MMIO_RING_DFH(RING_CTL, D_ALL, 0, NULL, NULL);
MMIO_RING_DFH(RING_ACTHD, D_ALL, F_CMD_ACCESS, mmio_read_from_hw, NULL); MMIO_RING_DFH(RING_ACTHD, D_ALL, 0, mmio_read_from_hw, NULL);
MMIO_RING_GM_RDR(RING_START, D_ALL, NULL, NULL); MMIO_RING_GM(RING_START, D_ALL, NULL, NULL);
/* RING MODE */ /* RING MODE */
#define RING_REG(base) _MMIO((base) + 0x29c) #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(_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_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(0x2220), D_ALL, F_CMD_ACCESS, NULL, NULL);
MMIO_DFH(_MMIO(0x12220), 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); 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, MMIO_DH(GEN8_MASTER_IRQ, D_BDW_PLUS, NULL,
intel_vgpu_reg_master_irq_handler); 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); mmio_read_from_hw, NULL);
#define RING_REG(base) _MMIO((base) + 0xd0) #define RING_REG(base) _MMIO((base) + 0xd0)
@ -2785,7 +2786,7 @@ static int init_bdw_mmio_info(struct intel_gvt *gvt)
#undef RING_REG #undef RING_REG
#define RING_REG(base) _MMIO((base) + 0x234) #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); NULL, NULL);
#undef RING_REG #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); MMIO_RING_F(RING_REG, 32, F_CMD_ACCESS, 0, 0, D_BDW_PLUS, NULL, NULL);
#undef RING_REG #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); 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_MEDIA_PG_IDLE_HYSTERESIS, D_SKL_PLUS);
MMIO_D(GEN9_RENDER_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_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_DH(CHICKEN_PAR1_1, D_SKL_PLUS, NULL, NULL);
MMIO_D(DC_STATE_EN, D_SKL_PLUS); MMIO_D(DC_STATE_EN, D_SKL_PLUS);
MMIO_D(DC_STATE_DEBUG, 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, MMIO_DFH(GEN9_WM_CHICKEN3, D_SKL_PLUS, F_MODE_MASK | F_CMD_ACCESS,
NULL, NULL); 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); MMIO_D(GEN9_CTX_PREEMPT_REG, D_SKL_PLUS);
return 0; return 0;
@ -3357,7 +3358,10 @@ void intel_gvt_clean_mmio_info(struct intel_gvt *gvt)
gvt->mmio.mmio_attribute = NULL; 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[] = { static struct gvt_mmio_block mmio_blocks[] = {
{D_SKL_PLUS, _MMIO(CSR_MMIO_START_RANGE), 0x3000, NULL, NULL}, {D_SKL_PLUS, _MMIO(CSR_MMIO_START_RANGE), 0x3000, NULL, NULL},
{D_ALL, _MMIO(MCHBAR_MIRROR_BASE_SNB), 0x40000, NULL, NULL}, {D_ALL, _MMIO(MCHBAR_MIRROR_BASE_SNB), 0x40000, NULL, NULL},

View File

@ -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 */ /* set the bit 0:2(Core C-State ) to C0 */
vgpu_vreg_t(vgpu, GEN6_GT_CORE_STATUS) = 0; 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)) { if (IS_BROXTON(vgpu->gvt->gt->i915)) {
vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) &= vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) &=
~(BIT(0) | BIT(1)); ~(BIT(0) | BIT(1));

View File

@ -595,7 +595,7 @@ void intel_gvt_init_engine_mmio_context(struct intel_gvt *gvt)
i915_mmio_reg_valid(mmio->reg); mmio++) { i915_mmio_reg_valid(mmio->reg); mmio++) {
if (mmio->in_context) { if (mmio->in_context) {
gvt->engine_mmio_list.ctx_mmio_count[mmio->id]++; 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);
} }
} }
} }

View File

@ -58,7 +58,6 @@
#include "display/intel_hotplug.h" #include "display/intel_hotplug.h"
#include "display/intel_overlay.h" #include "display/intel_overlay.h"
#include "display/intel_pipe_crc.h" #include "display/intel_pipe_crc.h"
#include "display/intel_psr.h"
#include "display/intel_sprite.h" #include "display/intel_sprite.h"
#include "display/intel_vga.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); 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) 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_detect_pch(dev_priv);
intel_pm_setup(dev_priv); intel_pm_setup(dev_priv);
intel_init_dpio(dev_priv);
ret = intel_power_domains_init(dev_priv); ret = intel_power_domains_init(dev_priv);
if (ret < 0) if (ret < 0)
goto err_gem; goto err_gem;
@ -798,7 +677,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
drm_err(&dev_priv->drm, drm_err(&dev_priv->drm,
"Failed to register driver for userspace access!\n"); "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 */ /* Must be done after probing outputs */
intel_opregion_register(dev_priv); intel_opregion_register(dev_priv);
acpi_video_register(); 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 * We need to coordinate the hotplugs with the asynchronous fbdev
* configuration, for which we use the fbdev->async_cookie. * 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); drm_kms_helper_poll_init(dev);
intel_power_domains_enable(dev_priv); 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) if (ret < 0)
goto out_cleanup_mmio; goto out_cleanup_mmio;
ret = i915_driver_modeset_probe_noirq(i915); ret = intel_modeset_init_noirq(i915);
if (ret < 0) if (ret < 0)
goto out_cleanup_hw; goto out_cleanup_hw;
@ -996,10 +875,18 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret) if (ret)
goto out_cleanup_modeset; goto out_cleanup_modeset;
ret = i915_driver_modeset_probe(i915); ret = intel_modeset_init_nogem(i915);
if (ret < 0) if (ret)
goto out_cleanup_irq; 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); i915_driver_register(i915);
enable_rpm_wakeref_asserts(&i915->runtime_pm); 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; 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: out_cleanup_irq:
intel_irq_uninstall(i915); intel_irq_uninstall(i915);
out_cleanup_modeset: out_cleanup_modeset:
i915_driver_modeset_remove_noirq(i915); intel_modeset_driver_remove_nogem(i915);
out_cleanup_hw: out_cleanup_hw:
i915_driver_hw_remove(i915); i915_driver_hw_remove(i915);
intel_memory_regions_driver_release(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); intel_gvt_driver_remove(i915);
i915_driver_modeset_remove(i915); intel_modeset_driver_remove(i915);
intel_irq_uninstall(i915); intel_irq_uninstall(i915);
@ -1054,7 +951,7 @@ void i915_driver_remove(struct drm_i915_private *i915)
i915_reset_error_state(i915); i915_reset_error_state(i915);
i915_gem_driver_remove(i915); i915_gem_driver_remove(i915);
i915_driver_modeset_remove_noirq(i915); intel_modeset_driver_remove_nogem(i915);
i915_driver_hw_remove(i915); i915_driver_hw_remove(i915);

View File

@ -108,18 +108,11 @@
#define DRIVER_NAME "i915" #define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics" #define DRIVER_DESC "Intel Graphics"
#define DRIVER_DATE "20200824" #define DRIVER_DATE "20200917"
#define DRIVER_TIMESTAMP 1598293597 #define DRIVER_TIMESTAMP 1600375437
struct drm_i915_gem_object; 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 { enum hpd_pin {
HPD_NONE = 0, HPD_NONE = 0,
HPD_TV = HPD_NONE, /* TV is known to be unreliable */ HPD_TV = HPD_NONE, /* TV is known to be unreliable */
@ -131,10 +124,12 @@ enum hpd_pin {
HPD_PORT_C, HPD_PORT_C,
HPD_PORT_D, HPD_PORT_D,
HPD_PORT_E, HPD_PORT_E,
HPD_PORT_F, HPD_PORT_TC1,
HPD_PORT_G, HPD_PORT_TC2,
HPD_PORT_H, HPD_PORT_TC3,
HPD_PORT_I, HPD_PORT_TC4,
HPD_PORT_TC5,
HPD_PORT_TC6,
HPD_NUM_PINS HPD_NUM_PINS
}; };
@ -537,13 +532,9 @@ struct intel_gmbus {
struct i915_suspend_saved_registers { struct i915_suspend_saved_registers {
u32 saveDSPARB; u32 saveDSPARB;
u32 saveFBC_CONTROL;
u32 saveCACHE_MODE_0;
u32 saveMI_ARB_STATE;
u32 saveSWF0[16]; u32 saveSWF0[16];
u32 saveSWF1[16]; u32 saveSWF1[16];
u32 saveSWF3[3]; u32 saveSWF3[3];
u32 savePCH_PORT_HOTPLUG;
u16 saveGCDGMBUS; u16 saveGCDGMBUS;
}; };
@ -1020,8 +1011,6 @@ struct drm_i915_private {
*/ */
u8 active_pipes; u8 active_pipes;
int dpio_phy_iosf_port[I915_NUM_PHYS_VLV];
struct i915_wa_list gt_wa_list; struct i915_wa_list gt_wa_list;
struct i915_frontbuffer_tracking fb_tracking; 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) \ #define IS_EHL_REVID(p, since, until) \
(IS_ELKHARTLAKE(p) && IS_REVID(p, since, until)) (IS_ELKHARTLAKE(p) && IS_REVID(p, since, until))
#define TGL_REVID_A0 0x0 enum {
#define TGL_REVID_B0 0x1 TGL_REVID_A0,
#define TGL_REVID_C0 0x2 TGL_REVID_B0,
TGL_REVID_B1,
TGL_REVID_C0,
TGL_REVID_D0,
};
#define IS_TGL_REVID(p, since, until) \ extern const struct i915_rev_steppings tgl_uy_revids[];
(IS_TIGERLAKE(p) && IS_REVID(p, since, until)) 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_A0 0x0
#define RKL_REVID_B0 0x1 #define RKL_REVID_B0 0x1

View File

@ -132,40 +132,24 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = {
}; };
static const u32 hpd_gen11[HPD_NUM_PINS] = { static const u32 hpd_gen11[HPD_NUM_PINS] = {
[HPD_PORT_C] = GEN11_TC1_HOTPLUG | GEN11_TBT1_HOTPLUG, [HPD_PORT_TC1] = GEN11_TC_HOTPLUG(PORT_TC1) | GEN11_TBT_HOTPLUG(PORT_TC1),
[HPD_PORT_D] = GEN11_TC2_HOTPLUG | GEN11_TBT2_HOTPLUG, [HPD_PORT_TC2] = GEN11_TC_HOTPLUG(PORT_TC2) | GEN11_TBT_HOTPLUG(PORT_TC2),
[HPD_PORT_E] = GEN11_TC3_HOTPLUG | GEN11_TBT3_HOTPLUG, [HPD_PORT_TC3] = GEN11_TC_HOTPLUG(PORT_TC3) | GEN11_TBT_HOTPLUG(PORT_TC3),
[HPD_PORT_F] = GEN11_TC4_HOTPLUG | GEN11_TBT4_HOTPLUG, [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_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,
}; };
static const u32 hpd_icp[HPD_NUM_PINS] = { 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_A] = SDE_DDI_HOTPLUG_ICP(PORT_A),
[HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(PORT_B), [HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(PORT_B),
[HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(PORT_C), [HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(PORT_C),
[HPD_PORT_D] = SDE_TC_HOTPLUG_ICP(PORT_TC1), [HPD_PORT_TC1] = SDE_TC_HOTPLUG_ICP(PORT_TC1),
[HPD_PORT_E] = SDE_TC_HOTPLUG_ICP(PORT_TC2), [HPD_PORT_TC2] = SDE_TC_HOTPLUG_ICP(PORT_TC2),
[HPD_PORT_F] = SDE_TC_HOTPLUG_ICP(PORT_TC3), [HPD_PORT_TC3] = SDE_TC_HOTPLUG_ICP(PORT_TC3),
[HPD_PORT_G] = SDE_TC_HOTPLUG_ICP(PORT_TC4), [HPD_PORT_TC4] = SDE_TC_HOTPLUG_ICP(PORT_TC4),
[HPD_PORT_H] = SDE_TC_HOTPLUG_ICP(PORT_TC5), [HPD_PORT_TC5] = SDE_TC_HOTPLUG_ICP(PORT_TC5),
[HPD_PORT_I] = SDE_TC_HOTPLUG_ICP(PORT_TC6), [HPD_PORT_TC6] = SDE_TC_HOTPLUG_ICP(PORT_TC6),
}; };
static void intel_hpd_init_pins(struct drm_i915_private *dev_priv) 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; return;
} }
if (INTEL_GEN(dev_priv) >= 12) if (INTEL_GEN(dev_priv) >= 11)
hpd->hpd = hpd_gen12;
else if (INTEL_GEN(dev_priv) >= 11)
hpd->hpd = hpd_gen11; hpd->hpd = hpd_gen11;
else if (IS_GEN9_LP(dev_priv)) else if (IS_GEN9_LP(dev_priv))
hpd->hpd = hpd_bxt; 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)) if (!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv))
return; return;
if (HAS_PCH_TGP(dev_priv) || HAS_PCH_JSP(dev_priv)) if (HAS_PCH_TGP(dev_priv) || HAS_PCH_JSP(dev_priv) ||
hpd->pch_hpd = hpd_tgp; HAS_PCH_ICP(dev_priv) || HAS_PCH_MCC(dev_priv))
else if (HAS_PCH_ICP(dev_priv) || HAS_PCH_MCC(dev_priv))
hpd->pch_hpd = hpd_icp; hpd->pch_hpd = hpd_icp;
else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_SPT(dev_priv)) else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_SPT(dev_priv))
hpd->pch_hpd = hpd_spt; 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) static bool gen11_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
{ {
switch (pin) { switch (pin) {
case HPD_PORT_C: case HPD_PORT_TC1:
return val & GEN11_HOTPLUG_CTL_LONG_DETECT(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); 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); 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); return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC4);
default: case HPD_PORT_TC5:
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:
return val & GEN11_HOTPLUG_CTL_LONG_DETECT(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); return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC6);
default: default:
return false; 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) static bool icp_tc_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
{ {
switch (pin) { switch (pin) {
case HPD_PORT_C: case HPD_PORT_TC1:
return val & ICP_TC_HPD_LONG_DETECT(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); 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); 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); return val & ICP_TC_HPD_LONG_DETECT(PORT_TC4);
default: case HPD_PORT_TC5:
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:
return val & ICP_TC_HPD_LONG_DETECT(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); return val & ICP_TC_HPD_LONG_DETECT(PORT_TC6);
default: default:
return false; 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 ddi_hotplug_trigger, tc_hotplug_trigger;
u32 pin_mask = 0, long_mask = 0; 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)) { if (HAS_PCH_TGP(dev_priv)) {
ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_TGP; ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_TGP;
tc_hotplug_trigger = pch_iir & SDE_TC_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)) { } else if (HAS_PCH_JSP(dev_priv)) {
ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_TGP; ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_TGP;
tc_hotplug_trigger = 0; tc_hotplug_trigger = 0;
} else if (HAS_PCH_MCC(dev_priv)) { } else if (HAS_PCH_MCC(dev_priv)) {
ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP; ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP;
tc_hotplug_trigger = pch_iir & SDE_TC_HOTPLUG_ICP(PORT_TC1); tc_hotplug_trigger = pch_iir & SDE_TC_HOTPLUG_ICP(PORT_TC1);
tc_port_hotplug_long_detect = icp_tc_port_hotplug_long_detect;
} else { } else {
drm_WARN(&dev_priv->drm, !HAS_PCH_ICP(dev_priv), drm_WARN(&dev_priv->drm, !HAS_PCH_ICP(dev_priv),
"Unrecognized PCH type 0x%x\n", "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; ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP;
tc_hotplug_trigger = pch_iir & SDE_TC_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) { 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, intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
tc_hotplug_trigger, dig_hotplug_reg, tc_hotplug_trigger, dig_hotplug_reg,
dev_priv->hotplug.pch_hpd, dev_priv->hotplug.pch_hpd,
tc_port_hotplug_long_detect); icp_tc_port_hotplug_long_detect);
} }
if (pin_mask) 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 pin_mask = 0, long_mask = 0;
u32 trigger_tc = iir & GEN11_DE_TC_HOTPLUG_MASK; u32 trigger_tc = iir & GEN11_DE_TC_HOTPLUG_MASK;
u32 trigger_tbt = iir & GEN11_DE_TBT_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) { if (trigger_tc) {
u32 dig_hotplug_reg; 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, intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
trigger_tc, dig_hotplug_reg, trigger_tc, dig_hotplug_reg,
dev_priv->hotplug.hpd, dev_priv->hotplug.hpd,
long_pulse_detect); gen11_port_hotplug_long_detect);
} }
if (trigger_tbt) { 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, intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
trigger_tbt, dig_hotplug_reg, trigger_tbt, dig_hotplug_reg,
dev_priv->hotplug.hpd, dev_priv->hotplug.hpd,
long_pulse_detect); gen11_port_hotplug_long_detect);
} }
if (pin_mask) if (pin_mask)
@ -3048,6 +2987,18 @@ static u32 intel_hpd_enabled_irqs(struct drm_i915_private *dev_priv,
return enabled_irqs; 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) static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv)
{ {
u32 hotplug; u32 hotplug;
@ -3077,50 +3028,50 @@ static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv)
{ {
u32 hotplug_irqs, enabled_irqs; 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); 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_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
ibx_hpd_detection_setup(dev_priv); ibx_hpd_detection_setup(dev_priv);
} }
static void icp_hpd_detection_setup(struct drm_i915_private *dev_priv, static void icp_ddi_hpd_detection_setup(struct drm_i915_private *dev_priv,
u32 ddi_hotplug_enable_mask, u32 enable_mask)
u32 tc_hotplug_enable_mask)
{ {
u32 hotplug; u32 hotplug;
hotplug = I915_READ(SHOTPLUG_CTL_DDI); hotplug = I915_READ(SHOTPLUG_CTL_DDI);
hotplug |= ddi_hotplug_enable_mask; hotplug |= enable_mask;
I915_WRITE(SHOTPLUG_CTL_DDI, hotplug); I915_WRITE(SHOTPLUG_CTL_DDI, hotplug);
}
if (tc_hotplug_enable_mask) { static void icp_tc_hpd_detection_setup(struct drm_i915_private *dev_priv,
hotplug = I915_READ(SHOTPLUG_CTL_TC); u32 enable_mask)
hotplug |= tc_hotplug_enable_mask; {
I915_WRITE(SHOTPLUG_CTL_TC, hotplug); 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, 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 ddi_enable_mask, u32 tc_enable_mask)
{ {
u32 hotplug_irqs, enabled_irqs; 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); 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) if (INTEL_PCH_TYPE(dev_priv) <= PCH_TGP)
I915_WRITE(SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ); I915_WRITE(SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ);
ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs); 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) static void mcc_hpd_irq_setup(struct drm_i915_private *dev_priv)
{ {
icp_hpd_irq_setup(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)); 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) static void jsp_hpd_irq_setup(struct drm_i915_private *dev_priv)
{ {
icp_hpd_irq_setup(dev_priv, icp_hpd_irq_setup(dev_priv,
SDE_DDI_MASK_TGP, 0,
TGP_DDI_HPD_ENABLE_MASK, 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) | hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) |
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) | GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) |
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) | 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); I915_WRITE(GEN11_TC_HOTPLUG_CTL, hotplug);
hotplug = I915_READ(GEN11_TBT_HOTPLUG_CTL); hotplug = I915_READ(GEN11_TBT_HOTPLUG_CTL);
hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) | hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) |
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) | GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) |
GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) | 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); 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; u32 val;
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 = 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 = I915_READ(GEN11_DE_HPD_IMR);
val &= ~hotplug_irqs; 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); gen11_hpd_detection_setup(dev_priv);
if (INTEL_PCH_TYPE(dev_priv) >= PCH_TGP) 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); TGP_DDI_HPD_ENABLE_MASK, TGP_TC_HPD_ENABLE_MASK);
else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) 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); 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) if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP)
I915_WRITE(SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ); 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); 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_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; u32 hotplug_irqs, enabled_irqs;
if (INTEL_GEN(dev_priv) >= 8) { enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.hpd);
hotplug_irqs = GEN8_PORT_DP_A_HOTPLUG; hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->hotplug.hpd);
enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.hpd);
if (INTEL_GEN(dev_priv) >= 8)
bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs); bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
} else if (INTEL_GEN(dev_priv) >= 7) { else
hotplug_irqs = DE_DP_A_HOTPLUG_IVB;
enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.hpd);
ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs); 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); 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; u32 hotplug_irqs, enabled_irqs;
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 = 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); 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); gen3_assert_iir_is_zero(&dev_priv->uncore, SDEIIR);
I915_WRITE(SDEIMR, ~mask); I915_WRITE(SDEIMR, ~mask);
if (HAS_PCH_TGP(dev_priv)) if (HAS_PCH_TGP(dev_priv)) {
icp_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK, icp_ddi_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK);
TGP_TC_HPD_ENABLE_MASK); icp_tc_hpd_detection_setup(dev_priv, TGP_TC_HPD_ENABLE_MASK);
else if (HAS_PCH_JSP(dev_priv)) } else if (HAS_PCH_JSP(dev_priv)) {
icp_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK, 0); icp_ddi_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK);
else if (HAS_PCH_MCC(dev_priv)) } else if (HAS_PCH_MCC(dev_priv)) {
icp_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK, icp_ddi_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK);
ICP_TC_HPD_ENABLE(PORT_TC1)); icp_tc_hpd_detection_setup(dev_priv, ICP_TC_HPD_ENABLE(PORT_TC1));
else } else {
icp_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK, icp_ddi_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK);
ICP_TC_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) static void gen11_irq_postinstall(struct drm_i915_private *dev_priv)

View File

@ -1382,7 +1382,6 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
#define DPIO_CMNRST (1 << 0) #define DPIO_CMNRST (1 << 0)
#define DPIO_PHY(pipe) ((pipe) >> 1) #define DPIO_PHY(pipe) ((pipe) >> 1)
#define DPIO_PHY_IOSF_PORT(phy) (dev_priv->dpio_phy_iosf_port[phy])
/* /*
* Per pipe/PLL DPIO regs * Per pipe/PLL DPIO regs
@ -7760,32 +7759,20 @@ enum {
#define GEN11_DE_HPD_IMR _MMIO(0x44474) #define GEN11_DE_HPD_IMR _MMIO(0x44474)
#define GEN11_DE_HPD_IIR _MMIO(0x44478) #define GEN11_DE_HPD_IIR _MMIO(0x44478)
#define GEN11_DE_HPD_IER _MMIO(0x4447c) #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_TC_HOTPLUG(tc_port) (1 << ((tc_port) + 16))
#define GEN11_DE_TC_HOTPLUG_MASK (GEN12_TC6_HOTPLUG | \ #define GEN11_DE_TC_HOTPLUG_MASK (GEN11_TC_HOTPLUG(PORT_TC6) | \
GEN12_TC5_HOTPLUG | \ GEN11_TC_HOTPLUG(PORT_TC5) | \
GEN11_TC4_HOTPLUG | \ GEN11_TC_HOTPLUG(PORT_TC4) | \
GEN11_TC3_HOTPLUG | \ GEN11_TC_HOTPLUG(PORT_TC3) | \
GEN11_TC2_HOTPLUG | \ GEN11_TC_HOTPLUG(PORT_TC2) | \
GEN11_TC1_HOTPLUG) GEN11_TC_HOTPLUG(PORT_TC1))
#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_TBT_HOTPLUG(tc_port) (1 << (tc_port)) #define GEN11_TBT_HOTPLUG(tc_port) (1 << (tc_port))
#define GEN11_DE_TBT_HOTPLUG_MASK (GEN12_TBT6_HOTPLUG | \ #define GEN11_DE_TBT_HOTPLUG_MASK (GEN11_TBT_HOTPLUG(PORT_TC6) | \
GEN12_TBT5_HOTPLUG | \ GEN11_TBT_HOTPLUG(PORT_TC5) | \
GEN11_TBT4_HOTPLUG | \ GEN11_TBT_HOTPLUG(PORT_TC4) | \
GEN11_TBT3_HOTPLUG | \ GEN11_TBT_HOTPLUG(PORT_TC3) | \
GEN11_TBT2_HOTPLUG | \ GEN11_TBT_HOTPLUG(PORT_TC2) | \
GEN11_TBT1_HOTPLUG) GEN11_TBT_HOTPLUG(PORT_TC1))
#define GEN11_TBT_HOTPLUG_CTL _MMIO(0x44030) #define GEN11_TBT_HOTPLUG_CTL _MMIO(0x44030)
#define GEN11_TC_HOTPLUG_CTL _MMIO(0x44038) #define GEN11_TC_HOTPLUG_CTL _MMIO(0x44038)
@ -9315,6 +9302,7 @@ enum {
#define GEN11_LSN_UNSLCVC_GAFS_HALF_SF_MAXALLOC (1 << 7) #define GEN11_LSN_UNSLCVC_GAFS_HALF_SF_MAXALLOC (1 << 7)
#define GEN10_SAMPLER_MODE _MMIO(0xE18C) #define GEN10_SAMPLER_MODE _MMIO(0xE18C)
#define ENABLE_SMALLPL REG_BIT(15)
#define GEN11_SAMPLER_ENABLE_HEADLESS_MSG REG_BIT(5) #define GEN11_SAMPLER_ENABLE_HEADLESS_MSG REG_BIT(5)
/* IVYBRIDGE DPF */ /* IVYBRIDGE DPF */

View File

@ -34,17 +34,25 @@
static void i915_save_display(struct drm_i915_private *dev_priv) static void i915_save_display(struct drm_i915_private *dev_priv)
{ {
struct pci_dev *pdev = dev_priv->drm.pdev;
/* Display arbitration control */ /* Display arbitration control */
if (INTEL_GEN(dev_priv) <= 4) if (INTEL_GEN(dev_priv) <= 4)
dev_priv->regfile.saveDSPARB = I915_READ(DSPARB); dev_priv->regfile.saveDSPARB = I915_READ(DSPARB);
/* save FBC interval */ if (IS_GEN(dev_priv, 4))
if (HAS_FBC(dev_priv) && INTEL_GEN(dev_priv) <= 4 && !IS_G4X(dev_priv)) pci_read_config_word(pdev, GCDGMBUS,
dev_priv->regfile.saveFBC_CONTROL = I915_READ(FBC_CONTROL); &dev_priv->regfile.saveGCDGMBUS);
} }
static void i915_restore_display(struct drm_i915_private *dev_priv) 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 */ /* Display arbitration */
if (INTEL_GEN(dev_priv) <= 4) if (INTEL_GEN(dev_priv) <= 4)
I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB); 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*/ /* only restore FBC info on the platform that supports FBC*/
intel_fbc_global_disable(dev_priv); 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_vga_redisable(dev_priv);
intel_gmbus_reset(dev_priv);
} }
int i915_save_state(struct drm_i915_private *dev_priv) int i915_save_state(struct drm_i915_private *dev_priv)
{ {
struct pci_dev *pdev = dev_priv->drm.pdev;
int i; int i;
i915_save_display(dev_priv); 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 */ /* Scratch space */
if (IS_GEN(dev_priv, 2) && IS_MOBILE(dev_priv)) { if (IS_GEN(dev_priv, 2) && IS_MOBILE(dev_priv)) {
for (i = 0; i < 7; i++) { 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) int i915_restore_state(struct drm_i915_private *dev_priv)
{ {
struct pci_dev *pdev = dev_priv->drm.pdev;
int i; int i;
if (IS_GEN(dev_priv, 4))
pci_write_config_word(pdev, GCDGMBUS,
dev_priv->regfile.saveGCDGMBUS);
i915_restore_display(dev_priv); 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 */ /* Scratch space */
if (IS_GEN(dev_priv, 2) && IS_MOBILE(dev_priv)) { if (IS_GEN(dev_priv, 2) && IS_MOBILE(dev_priv)) {
for (i = 0; i < 7; i++) { 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]); I915_WRITE(SWF3(i), dev_priv->regfile.saveSWF3[i]);
} }
intel_gmbus_reset(dev_priv);
return 0; return 0;
} }

View File

@ -516,6 +516,14 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv)
S32_MAX), S32_MAX),
USEC_PER_SEC)); 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, void intel_driver_caps_print(const struct intel_driver_caps *caps,

View File

@ -7136,7 +7136,7 @@ static void tgl_init_clock_gating(struct drm_i915_private *dev_priv)
I915_READ(POWERGATE_ENABLE) | vd_pg_enable); I915_READ(POWERGATE_ENABLE) | vd_pg_enable);
/* Wa_1409825376:tgl (pre-prod)*/ /* 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) | I915_WRITE(GEN9_CLKGATE_DIS_3, I915_READ(GEN9_CLKGATE_DIS_3) |
TGL_VRH_GATING_DIS); TGL_VRH_GATING_DIS);

View File

@ -231,9 +231,21 @@ void vlv_ccu_write(struct drm_i915_private *i915, u32 reg, u32 val)
SB_CRWRDA_NP, reg, &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) 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; u32 val = 0;
vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MRD_NP, reg, &val); 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, void vlv_dpio_write(struct drm_i915_private *i915,
enum pipe pipe, int reg, u32 val) 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); vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MWR_NP, reg, &val);
} }

View File

@ -1993,13 +1993,14 @@ int __intel_wait_for_register_fw(struct intel_uncore *uncore,
unsigned int slow_timeout_ms, unsigned int slow_timeout_ms,
u32 *out_value) u32 *out_value)
{ {
u32 reg_value; u32 reg_value = 0;
#define done (((reg_value = intel_uncore_read_fw(uncore, reg)) & mask) == value) #define done (((reg_value = intel_uncore_read_fw(uncore, reg)) & mask) == value)
int ret; int ret;
/* Catch any overuse of this function */ /* Catch any overuse of this function */
might_sleep_if(slow_timeout_ms); might_sleep_if(slow_timeout_ms);
GEM_BUG_ON(fast_timeout_us > 20000); GEM_BUG_ON(fast_timeout_us > 20000);
GEM_BUG_ON(!fast_timeout_us && !slow_timeout_ms);
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
if (fast_timeout_us && fast_timeout_us <= 20000) if (fast_timeout_us && fast_timeout_us <= 20000)

View File

@ -118,11 +118,11 @@ static struct dev_pm_domain pm_domain = {
struct drm_i915_private *mock_gem_device(void) 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 drm_i915_private *i915;
struct pci_dev *pdev; struct pci_dev *pdev;
#if IS_ENABLED(CONFIG_IOMMU_API) && defined(CONFIG_INTEL_IOMMU)
struct dev_iommu iommu;
#endif
int err; int err;
pdev = kzalloc(sizeof(*pdev), GFP_KERNEL); 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)); dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
#if IS_ENABLED(CONFIG_IOMMU_API) && defined(CONFIG_INTEL_IOMMU) #if IS_ENABLED(CONFIG_IOMMU_API) && defined(CONFIG_INTEL_IOMMU)
/* HACK HACK HACK to disable iommu for the fake device; force identity mapping */ /* HACK to disable iommu for the fake device; force identity mapping */
memset(&iommu, 0, sizeof(iommu)); pdev->dev.iommu = &fake_iommu;
iommu.priv = (void *)-1;
pdev->dev.iommu = &iommu;
#endif #endif
pci_set_drvdata(pdev, i915); pci_set_drvdata(pdev, i915);

View File

@ -239,8 +239,8 @@ nv50_dp_mode_valid(struct drm_connector *connector,
return MODE_NO_INTERLACE; return MODE_NO_INTERLACE;
max_clock = outp->dp.link_nr * outp->dp.link_bw; max_clock = outp->dp.link_nr * outp->dp.link_bw;
ds_clock = drm_dp_downstream_max_clock(outp->dp.dpcd, ds_clock = drm_dp_downstream_max_dotclock(outp->dp.dpcd,
outp->dp.downstream_ports); outp->dp.downstream_ports);
if (ds_clock) if (ds_clock)
max_clock = min(max_clock, ds_clock); max_clock = min(max_clock, ds_clock);

View File

@ -5,6 +5,8 @@
#define PREFIX_STR "[drm_dp_mst_helper]" #define PREFIX_STR "[drm_dp_mst_helper]"
#include <linux/random.h>
#include <drm/drm_dp_mst_helper.h> #include <drm/drm_dp_mst_helper.h>
#include <drm/drm_print.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; in.u.i2c_write.bytes = data;
DO_TEST(); 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 #undef DO_TEST
return 0; return 0;
} }

View File

@ -21,8 +21,8 @@
#define PWM_MAX_LEVEL 0xFF #define PWM_MAX_LEVEL 0xFF
#define PWM_BASE_CLK 6000000 /* 6 MHz */ #define PWM_BASE_CLK_MHZ 6 /* 6 MHz */
#define PWM_MAX_PERIOD_NS 21333 /* 46.875KHz */ #define PWM_MAX_PERIOD_NS 5461334 /* 183 Hz */
/** /**
* struct crystalcove_pwm - Crystal Cove PWM controller * 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); 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); struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
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 device *dev = crc_pwm->chip.dev; 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"); dev_err(dev, "un-supported period_ns\n");
return -EINVAL; return -EINVAL;
} }
if (pwm_get_period(pwm) != period_ns) { if (state->polarity != PWM_POLARITY_NORMAL)
int clk_div; return -EOPNOTSUPP;
/* changing the clk divisor, need to disable fisrt */ if (pwm_is_enabled(pwm) && !state->enabled) {
crc_pwm_disable(c, pwm); err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
clk_div = PWM_BASE_CLK * period_ns / NSEC_PER_SEC; if (err) {
dev_err(dev, "Error writing BACKLIGHT_EN %d\n", err);
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, return err;
clk_div | PWM_OUTPUT_ENABLE); }
/* enable back */
crc_pwm_enable(c, pwm);
} }
/* change the pwm duty cycle */ if (pwm_get_duty_cycle(pwm) != state->duty_cycle ||
level = duty_ns * PWM_MAX_LEVEL / period_ns; pwm_get_period(pwm) != state->period) {
regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level); 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; 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 = { static const struct pwm_ops crc_pwm_ops = {
.config = crc_pwm_config, .apply = crc_pwm_apply,
.enable = crc_pwm_enable, .get_state = crc_pwm_get_state,
.disable = crc_pwm_disable,
}; };
static int crystalcove_pwm_probe(struct platform_device *pdev) static int crystalcove_pwm_probe(struct platform_device *pdev)

View File

@ -89,7 +89,6 @@ static int pwm_lpss_prepare(struct device *dev)
static const struct dev_pm_ops pwm_lpss_platform_pm_ops = { static const struct dev_pm_ops pwm_lpss_platform_pm_ops = {
.prepare = pwm_lpss_prepare, .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[] = { static const struct acpi_device_id pwm_lpss_acpi_match[] = {

View File

@ -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 long on_time_div;
unsigned long c = lpwm->info->clk_rate, base_unit_range; unsigned long c = lpwm->info->clk_rate, base_unit_range;
unsigned long long base_unit, freq = NSEC_PER_SEC; unsigned long long base_unit, freq = NSEC_PER_SEC;
u32 orig_ctrl, ctrl; u32 ctrl;
do_div(freq, period_ns); 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: * The equation is:
* base_unit = round(base_unit_range * freq / c) * 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; freq *= base_unit_range;
base_unit = DIV_ROUND_CLOSEST_ULL(freq, c); 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; on_time_div = 255ULL * duty_ns;
do_div(on_time_div, period_ns); do_div(on_time_div, period_ns);
on_time_div = 255ULL - on_time_div; 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 &= ~PWM_ON_TIME_DIV_MASK;
ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT); ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT);
base_unit &= base_unit_range;
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT; ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div; ctrl |= on_time_div;
if (orig_ctrl != ctrl) { pwm_lpss_write(pwm, ctrl);
pwm_lpss_write(pwm, ctrl); pwm_lpss_write(pwm, ctrl | PWM_SW_UPDATE);
pwm_lpss_write(pwm, ctrl | PWM_SW_UPDATE);
}
} }
static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond) 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); 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, static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state) const struct pwm_state *state)
{ {
struct pwm_lpss_chip *lpwm = to_lpwm(chip); struct pwm_lpss_chip *lpwm = to_lpwm(chip);
int ret; int ret = 0;
if (state->enabled) { if (state->enabled) {
if (!pwm_is_enabled(pwm)) { if (!pwm_is_enabled(pwm)) {
pm_runtime_get_sync(chip->dev); pm_runtime_get_sync(chip->dev);
ret = pwm_lpss_is_updating(pwm); ret = pwm_lpss_prepare_enable(lpwm, pwm, state);
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);
if (ret) if (ret)
return ret; pm_runtime_put(chip->dev);
pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); } else {
return pwm_lpss_wait_for_update(pwm); ret = pwm_lpss_prepare_enable(lpwm, pwm, state);
} }
} else if (pwm_is_enabled(pwm)) { } else if (pwm_is_enabled(pwm)) {
pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE); pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
pm_runtime_put(chip->dev); pm_runtime_put(chip->dev);
} }
return 0; return ret;
} }
static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm, 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); 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_DESCRIPTION("PWM driver for Intel LPSS");
MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");

View File

@ -19,7 +19,6 @@ struct pwm_lpss_chip {
struct pwm_chip chip; struct pwm_chip chip;
void __iomem *regs; void __iomem *regs;
const struct pwm_lpss_boardinfo *info; const struct pwm_lpss_boardinfo *info;
u32 saved_ctrl[MAX_PWMS];
}; };
struct pwm_lpss_boardinfo { 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, struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
const struct pwm_lpss_boardinfo *info); const struct pwm_lpss_boardinfo *info);
int pwm_lpss_remove(struct pwm_lpss_chip *lpwm); 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 */ #endif /* __PWM_LPSS_H */

View File

@ -28,6 +28,8 @@
#include <linux/types.h> #include <linux/types.h>
#include <drm/drm_connector.h> #include <drm/drm_connector.h>
struct drm_device;
/* /*
* Unless otherwise noted, all values are from the DP 1.1a spec. Note that * 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, * 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_DP_DUALMODE 5
# define DP_DS_PORT_TYPE_WIRELESS 6 # define DP_DS_PORT_TYPE_WIRELESS 6
# define DP_DS_PORT_HPD (1 << 3) # 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 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_MAX_BPC_MASK (3 << 0)
# define DP_DS_8BPC 0 # define DP_DS_8BPC 0
# define DP_DS_10BPC 1 # define DP_DS_10BPC 1
# define DP_DS_12BPC 2 # define DP_DS_12BPC 2
# define DP_DS_16BPC 3 # 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 #define DP_MAX_DOWNSTREAM_PORTS 0x10
@ -984,6 +1003,16 @@
#define DP_CEC_TX_MESSAGE_BUFFER 0x3020 #define DP_CEC_TX_MESSAGE_BUFFER 0x3020
#define DP_CEC_MESSAGE_BUFFER_LENGTH 0x10 #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_BKSV 0x68000
#define DP_AUX_HDCP_RI_PRIME 0x68005 #define DP_AUX_HDCP_RI_PRIME 0x68005
#define DP_AUX_HDCP_AKSV 0x68007 #define DP_AUX_HDCP_AKSV 0x68007
@ -1109,6 +1138,9 @@
#define DP_POWER_DOWN_PHY 0x25 #define DP_POWER_DOWN_PHY 0x25
#define DP_SINK_EVENT_NOTIFY 0x30 #define DP_SINK_EVENT_NOTIFY 0x30
#define DP_QUERY_STREAM_ENC_STATUS 0x38 #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 */ /* DP 1.2 MST sideband reply types */
#define DP_SIDEBAND_REPLY_ACK 0x00 #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, int drm_dp_read_downstream_info(struct drm_dp_aux *aux,
const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 dpcd[DP_RECEIVER_CAP_SIZE],
u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]); u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]);
int drm_dp_downstream_max_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], bool drm_dp_downstream_is_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
const u8 port_cap[4]); 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], 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]); 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], void drm_dp_downstream_debug(struct seq_file *m,
const u8 port_cap[4], struct drm_dp_aux *aux); 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 enum drm_mode_subconnector
drm_dp_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE], drm_dp_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
const u8 port_cap[4]); const u8 port_cap[4]);

View File

@ -313,6 +313,34 @@ struct drm_dp_remote_i2c_write_ack_reply {
u8 port_number; 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 #define DRM_DP_MAX_SDP_STREAMS 16
struct drm_dp_allocate_payload { struct drm_dp_allocate_payload {
@ -374,6 +402,15 @@ struct drm_dp_remote_i2c_write {
u8 *bytes; 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 */ /* this covers ENUM_RESOURCES, POWER_DOWN_PHY, POWER_UP_PHY */
struct drm_dp_port_number_req { struct drm_dp_port_number_req {
u8 port_number; 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_read i2c_read;
struct drm_dp_remote_i2c_write i2c_write; struct drm_dp_remote_i2c_write i2c_write;
struct drm_dp_query_stream_enc_status enc_status;
} u; } 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_ack_reply remote_i2c_read_ack;
struct drm_dp_remote_i2c_read_nak_reply remote_i2c_read_nack; 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_remote_i2c_write_ack_reply remote_i2c_write_ack;
struct drm_dp_query_stream_enc_status_ack_reply enc_status;
} u; } u;
}; };
@ -807,6 +848,9 @@ drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state,
struct drm_dp_mst_port *port); struct drm_dp_mst_port *port);
int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_port *port, bool power_up); 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); 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); void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port);

View File

@ -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, struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
int hsize, int vsize, int fresh, int hsize, int vsize, int fresh,
bool rb); bool rb);
struct drm_display_mode *
drm_display_mode_from_cea_vic(struct drm_device *dev,
u8 video_code);
#endif /* __DRM_EDID_H__ */ #endif /* __DRM_EDID_H__ */

View File

@ -594,19 +594,25 @@
INTEL_VGA_DEVICE(0x4E51, info) INTEL_VGA_DEVICE(0x4E51, info)
/* TGL */ /* 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(0x9A40, info), \
INTEL_VGA_DEVICE(0x9A49, info), \ INTEL_VGA_DEVICE(0x9A49, info), \
INTEL_VGA_DEVICE(0x9A59, 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(0x9A78, info), \
INTEL_VGA_DEVICE(0x9AC0, info), \ INTEL_VGA_DEVICE(0x9AC0, info), \
INTEL_VGA_DEVICE(0x9AC9, info), \ INTEL_VGA_DEVICE(0x9AC9, info), \
INTEL_VGA_DEVICE(0x9AD9, info), \ INTEL_VGA_DEVICE(0x9AD9, info), \
INTEL_VGA_DEVICE(0x9AF8, 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 */ /* RKL */
#define INTEL_RKL_IDS(info) \ #define INTEL_RKL_IDS(info) \
INTEL_VGA_DEVICE(0x4C80, info), \ INTEL_VGA_DEVICE(0x4C80, info), \