mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 14:24:11 +08:00
Merge tag 'drm-intel-next-2024-02-27-1' of git://anongit.freedesktop.org/drm/drm-intel into drm-next
drm/i915 feature pull #2 for v6.9: Features and functionality: - DP tunneling and bandwidth allocation support (Imre) - Add more ADL-N PCI IDs (Gustavo) - Enable fastboot also on older platforms (Ville) - Bigjoiner force enable debugfs option for testing (Stan) Refactoring and cleanups: - Remove unused structs and struct members (Jiri Slaby) - Use per-device debug logging (Ville) - State check improvements (Ville) - Hardcoded cd2x divider cleanups (Ville) - CDCLK documentation updates (Ville, Rodrigo) Fixes: - HDCP MST Type1 fixes (Suraj) - Fix MTL C20 PHY PLL values (Ravi) - More hardware access prevention during init (Imre) - Always enable decompression with tile4 on Xe2 (Juha-Pekka) - Improve LNL package C residency (Suraj) drm core changes: - DP tunneling and bandwidth allocation helpers (Imre) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/87sf1devbj.fsf@intel.com
This commit is contained in:
commit
ca7a1d0d18
@ -17,6 +17,27 @@ config DRM_DISPLAY_DP_HELPER
|
||||
help
|
||||
DRM display helpers for DisplayPort.
|
||||
|
||||
config DRM_DISPLAY_DP_TUNNEL
|
||||
bool
|
||||
select DRM_DISPLAY_DP_HELPER
|
||||
help
|
||||
Enable support for DisplayPort tunnels. This allows drivers to use
|
||||
DP tunnel features like the Bandwidth Allocation mode to maximize the
|
||||
BW utilization for display streams on Thunderbolt links.
|
||||
|
||||
config DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE
|
||||
bool "Enable debugging the DP tunnel state"
|
||||
depends on REF_TRACKER
|
||||
depends on DRM_DISPLAY_DP_TUNNEL
|
||||
depends on DEBUG_KERNEL
|
||||
depends on EXPERT
|
||||
help
|
||||
Enables debugging the DP tunnel manager's state, including the
|
||||
consistency of all managed tunnels' reference counting and the state of
|
||||
streams contained in tunnels.
|
||||
|
||||
If in doubt, say "N".
|
||||
|
||||
config DRM_DISPLAY_HDCP_HELPER
|
||||
bool
|
||||
depends on DRM_DISPLAY_HELPER
|
||||
|
@ -8,6 +8,8 @@ drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_HELPER) += \
|
||||
drm_dp_helper.o \
|
||||
drm_dp_mst_topology.o \
|
||||
drm_dsc_helper.o
|
||||
drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_TUNNEL) += \
|
||||
drm_dp_tunnel.o
|
||||
drm_display_helper-$(CONFIG_DRM_DISPLAY_HDCP_HELPER) += drm_hdcp_helper.o
|
||||
drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += \
|
||||
drm_hdmi_helper.o \
|
||||
|
@ -4055,3 +4055,33 @@ int drm_dp_bw_channel_coding_efficiency(bool is_uhbr)
|
||||
return 800000;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_bw_channel_coding_efficiency);
|
||||
|
||||
/**
|
||||
* drm_dp_max_dprx_data_rate - Get the max data bandwidth of a DPRX sink
|
||||
* @max_link_rate: max DPRX link rate in 10kbps units
|
||||
* @max_lanes: max DPRX lane count
|
||||
*
|
||||
* Given a link rate and lanes, get the data bandwidth.
|
||||
*
|
||||
* Data bandwidth is the actual payload rate, which depends on the data
|
||||
* bandwidth efficiency and the link rate.
|
||||
*
|
||||
* Note that protocol layers above the DPRX link level considered here can
|
||||
* further limit the maximum data rate. Such layers are the MST topology (with
|
||||
* limits on the link between the source and first branch device as well as on
|
||||
* the whole MST path until the DPRX link) and (Thunderbolt) DP tunnels -
|
||||
* which in turn can encapsulate an MST link with its own limit - with each
|
||||
* SST or MST encapsulated tunnel sharing the BW of a tunnel group.
|
||||
*
|
||||
* Returns the maximum data rate in kBps units.
|
||||
*/
|
||||
int drm_dp_max_dprx_data_rate(int max_link_rate, int max_lanes)
|
||||
{
|
||||
int ch_coding_efficiency =
|
||||
drm_dp_bw_channel_coding_efficiency(drm_dp_is_uhbr_rate(max_link_rate));
|
||||
|
||||
return DIV_ROUND_DOWN_ULL(mul_u32_u32(max_link_rate * 10 * max_lanes,
|
||||
ch_coding_efficiency),
|
||||
1000000 * 8);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_max_dprx_data_rate);
|
||||
|
1949
drivers/gpu/drm/display/drm_dp_tunnel.c
Normal file
1949
drivers/gpu/drm/display/drm_dp_tunnel.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -155,6 +155,20 @@ config DRM_I915_PXP
|
||||
protected session and manage the status of the alive software session,
|
||||
as well as its life cycle.
|
||||
|
||||
config DRM_I915_DP_TUNNEL
|
||||
bool "Enable DP tunnel support"
|
||||
depends on DRM_I915
|
||||
depends on USB4
|
||||
select DRM_DISPLAY_DP_TUNNEL
|
||||
default y
|
||||
help
|
||||
Choose this option to detect DP tunnels and enable the Bandwidth
|
||||
Allocation mode for such tunnels. This allows using the maximum
|
||||
resolution allowed by the link BW on all displays sharing the
|
||||
link BW, for instance on a Thunderbolt link.
|
||||
|
||||
If in doubt, say "Y".
|
||||
|
||||
menu "drm/i915 Debugging"
|
||||
depends on DRM_I915
|
||||
depends on EXPERT
|
||||
|
@ -28,6 +28,7 @@ config DRM_I915_DEBUG
|
||||
select STACKDEPOT
|
||||
select STACKTRACE
|
||||
select DRM_DP_AUX_CHARDEV
|
||||
select DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE if DRM_I915_DP_TUNNEL
|
||||
select X86_MSR # used by igt/pm_rpm
|
||||
select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks)
|
||||
select DRM_DEBUG_MM if DRM=y
|
||||
|
@ -369,6 +369,9 @@ i915-y += \
|
||||
display/vlv_dsi.o \
|
||||
display/vlv_dsi_pll.o
|
||||
|
||||
i915-$(CONFIG_DRM_I915_DP_TUNNEL) += \
|
||||
display/intel_dp_tunnel.o
|
||||
|
||||
i915-y += \
|
||||
i915_perf.o
|
||||
|
||||
|
@ -205,7 +205,7 @@ static bool ch7017_init(struct intel_dvo_device *dvo,
|
||||
const char *str;
|
||||
u8 val;
|
||||
|
||||
priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL);
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return false;
|
||||
|
||||
|
@ -216,7 +216,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
|
||||
u8 vendor, device;
|
||||
char *name, *devid;
|
||||
|
||||
ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
|
||||
ch7xxx = kzalloc(sizeof(*ch7xxx), GFP_KERNEL);
|
||||
if (ch7xxx == NULL)
|
||||
return false;
|
||||
|
||||
|
@ -267,7 +267,7 @@ static bool ivch_init(struct intel_dvo_device *dvo,
|
||||
u16 temp;
|
||||
int i;
|
||||
|
||||
priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL);
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return false;
|
||||
|
||||
|
@ -476,7 +476,7 @@ static bool ns2501_init(struct intel_dvo_device *dvo,
|
||||
struct ns2501_priv *ns;
|
||||
unsigned char ch;
|
||||
|
||||
ns = kzalloc(sizeof(struct ns2501_priv), GFP_KERNEL);
|
||||
ns = kzalloc(sizeof(*ns), GFP_KERNEL);
|
||||
if (ns == NULL)
|
||||
return false;
|
||||
|
||||
@ -551,7 +551,7 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo,
|
||||
const struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
const struct ns2501_configuration *conf;
|
||||
struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
|
||||
struct ns2501_priv *ns = dvo->dev_priv;
|
||||
int mode_idx, i;
|
||||
|
||||
DRM_DEBUG_KMS
|
||||
@ -655,7 +655,7 @@ static bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
|
||||
/* set the NS2501 power state */
|
||||
static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
|
||||
{
|
||||
struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
|
||||
struct ns2501_priv *ns = dvo->dev_priv;
|
||||
|
||||
DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable);
|
||||
|
||||
|
@ -141,7 +141,7 @@ static bool sil164_init(struct intel_dvo_device *dvo,
|
||||
struct sil164_priv *sil;
|
||||
unsigned char ch;
|
||||
|
||||
sil = kzalloc(sizeof(struct sil164_priv), GFP_KERNEL);
|
||||
sil = kzalloc(sizeof(*sil), GFP_KERNEL);
|
||||
if (sil == NULL)
|
||||
return false;
|
||||
|
||||
|
@ -173,7 +173,7 @@ static bool tfp410_init(struct intel_dvo_device *dvo,
|
||||
struct tfp410_priv *tfp;
|
||||
int id;
|
||||
|
||||
tfp = kzalloc(sizeof(struct tfp410_priv), GFP_KERNEL);
|
||||
tfp = kzalloc(sizeof(*tfp), GFP_KERNEL);
|
||||
if (tfp == NULL)
|
||||
return false;
|
||||
|
||||
|
@ -70,26 +70,25 @@ static const struct cxsr_latency cxsr_latency_table[] = {
|
||||
{0, 1, 400, 800, 6042, 36042, 6584, 36584}, /* DDR3-800 SC */
|
||||
};
|
||||
|
||||
static const struct cxsr_latency *intel_get_cxsr_latency(bool is_desktop,
|
||||
bool is_ddr3,
|
||||
int fsb,
|
||||
int mem)
|
||||
static const struct cxsr_latency *intel_get_cxsr_latency(struct drm_i915_private *i915)
|
||||
{
|
||||
const struct cxsr_latency *latency;
|
||||
int i;
|
||||
|
||||
if (fsb == 0 || mem == 0)
|
||||
if (i915->fsb_freq == 0 || i915->mem_freq == 0)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) {
|
||||
latency = &cxsr_latency_table[i];
|
||||
const struct cxsr_latency *latency = &cxsr_latency_table[i];
|
||||
bool is_desktop = !IS_MOBILE(i915);
|
||||
|
||||
if (is_desktop == latency->is_desktop &&
|
||||
is_ddr3 == latency->is_ddr3 &&
|
||||
fsb == latency->fsb_freq && mem == latency->mem_freq)
|
||||
i915->is_ddr3 == latency->is_ddr3 &&
|
||||
i915->fsb_freq == latency->fsb_freq &&
|
||||
i915->mem_freq == latency->mem_freq)
|
||||
return latency;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
|
||||
drm_dbg_kms(&i915->drm, "Unknown FSB/MEM found, disable CxSR\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -525,6 +524,7 @@ static unsigned int intel_wm_method2(unsigned int pixel_rate,
|
||||
|
||||
/**
|
||||
* intel_calculate_wm - calculate watermark level
|
||||
* @i915: the device
|
||||
* @pixel_rate: pixel clock
|
||||
* @wm: chip FIFO params
|
||||
* @fifo_size: size of the FIFO buffer
|
||||
@ -542,7 +542,8 @@ static unsigned int intel_wm_method2(unsigned int pixel_rate,
|
||||
* past the watermark point. If the FIFO drains completely, a FIFO underrun
|
||||
* will occur, and a display engine hang could result.
|
||||
*/
|
||||
static unsigned int intel_calculate_wm(int pixel_rate,
|
||||
static unsigned int intel_calculate_wm(struct drm_i915_private *i915,
|
||||
int pixel_rate,
|
||||
const struct intel_watermark_params *wm,
|
||||
int fifo_size, int cpp,
|
||||
unsigned int latency_ns)
|
||||
@ -559,10 +560,10 @@ static unsigned int intel_calculate_wm(int pixel_rate,
|
||||
latency_ns / 100);
|
||||
entries = DIV_ROUND_UP(entries, wm->cacheline_size) +
|
||||
wm->guard_size;
|
||||
DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries);
|
||||
drm_dbg_kms(&i915->drm, "FIFO entries required for mode: %d\n", entries);
|
||||
|
||||
wm_size = fifo_size - entries;
|
||||
DRM_DEBUG_KMS("FIFO watermark level: %d\n", wm_size);
|
||||
drm_dbg_kms(&i915->drm, "FIFO watermark level: %d\n", wm_size);
|
||||
|
||||
/* Don't promote wm_size to unsigned... */
|
||||
if (wm_size > wm->max_wm)
|
||||
@ -634,10 +635,7 @@ static void pnv_update_wm(struct drm_i915_private *dev_priv)
|
||||
u32 reg;
|
||||
unsigned int wm;
|
||||
|
||||
latency = intel_get_cxsr_latency(!IS_MOBILE(dev_priv),
|
||||
dev_priv->is_ddr3,
|
||||
dev_priv->fsb_freq,
|
||||
dev_priv->mem_freq);
|
||||
latency = intel_get_cxsr_latency(dev_priv);
|
||||
if (!latency) {
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
"Unknown FSB/MEM found, disable CxSR\n");
|
||||
@ -653,7 +651,8 @@ static void pnv_update_wm(struct drm_i915_private *dev_priv)
|
||||
int cpp = fb->format->cpp[0];
|
||||
|
||||
/* Display SR */
|
||||
wm = intel_calculate_wm(pixel_rate, &pnv_display_wm,
|
||||
wm = intel_calculate_wm(dev_priv, pixel_rate,
|
||||
&pnv_display_wm,
|
||||
pnv_display_wm.fifo_size,
|
||||
cpp, latency->display_sr);
|
||||
reg = intel_uncore_read(&dev_priv->uncore, DSPFW1);
|
||||
@ -663,20 +662,23 @@ static void pnv_update_wm(struct drm_i915_private *dev_priv)
|
||||
drm_dbg_kms(&dev_priv->drm, "DSPFW1 register is %x\n", reg);
|
||||
|
||||
/* cursor SR */
|
||||
wm = intel_calculate_wm(pixel_rate, &pnv_cursor_wm,
|
||||
wm = intel_calculate_wm(dev_priv, pixel_rate,
|
||||
&pnv_cursor_wm,
|
||||
pnv_display_wm.fifo_size,
|
||||
4, latency->cursor_sr);
|
||||
intel_uncore_rmw(&dev_priv->uncore, DSPFW3, DSPFW_CURSOR_SR_MASK,
|
||||
FW_WM(wm, CURSOR_SR));
|
||||
|
||||
/* Display HPLL off SR */
|
||||
wm = intel_calculate_wm(pixel_rate, &pnv_display_hplloff_wm,
|
||||
wm = intel_calculate_wm(dev_priv, pixel_rate,
|
||||
&pnv_display_hplloff_wm,
|
||||
pnv_display_hplloff_wm.fifo_size,
|
||||
cpp, latency->display_hpll_disable);
|
||||
intel_uncore_rmw(&dev_priv->uncore, DSPFW3, DSPFW_HPLL_SR_MASK, FW_WM(wm, HPLL_SR));
|
||||
|
||||
/* cursor HPLL off SR */
|
||||
wm = intel_calculate_wm(pixel_rate, &pnv_cursor_hplloff_wm,
|
||||
wm = intel_calculate_wm(dev_priv, pixel_rate,
|
||||
&pnv_cursor_hplloff_wm,
|
||||
pnv_display_hplloff_wm.fifo_size,
|
||||
4, latency->cursor_hpll_disable);
|
||||
reg = intel_uncore_read(&dev_priv->uncore, DSPFW3);
|
||||
@ -2124,7 +2126,7 @@ static void i9xx_update_wm(struct drm_i915_private *dev_priv)
|
||||
else
|
||||
cpp = fb->format->cpp[0];
|
||||
|
||||
planea_wm = intel_calculate_wm(crtc->config->pixel_rate,
|
||||
planea_wm = intel_calculate_wm(dev_priv, crtc->config->pixel_rate,
|
||||
wm_info, fifo_size, cpp,
|
||||
pessimal_latency_ns);
|
||||
} else {
|
||||
@ -2151,7 +2153,7 @@ static void i9xx_update_wm(struct drm_i915_private *dev_priv)
|
||||
else
|
||||
cpp = fb->format->cpp[0];
|
||||
|
||||
planeb_wm = intel_calculate_wm(crtc->config->pixel_rate,
|
||||
planeb_wm = intel_calculate_wm(dev_priv, crtc->config->pixel_rate,
|
||||
wm_info, fifo_size, cpp,
|
||||
pessimal_latency_ns);
|
||||
} else {
|
||||
@ -2245,7 +2247,7 @@ static void i845_update_wm(struct drm_i915_private *dev_priv)
|
||||
if (crtc == NULL)
|
||||
return;
|
||||
|
||||
planea_wm = intel_calculate_wm(crtc->config->pixel_rate,
|
||||
planea_wm = intel_calculate_wm(dev_priv, crtc->config->pixel_rate,
|
||||
&i845_wm_info,
|
||||
i845_get_fifo_size(dev_priv, PLANE_A),
|
||||
4, pessimal_latency_ns);
|
||||
@ -2531,7 +2533,8 @@ static void ilk_compute_wm_reg_maximums(const struct drm_i915_private *dev_priv,
|
||||
max->fbc = ilk_fbc_wm_reg_max(dev_priv);
|
||||
}
|
||||
|
||||
static bool ilk_validate_wm_level(int level,
|
||||
static bool ilk_validate_wm_level(struct drm_i915_private *i915,
|
||||
int level,
|
||||
const struct ilk_wm_maximums *max,
|
||||
struct intel_wm_level *result)
|
||||
{
|
||||
@ -2554,14 +2557,17 @@ static bool ilk_validate_wm_level(int level,
|
||||
*/
|
||||
if (level == 0 && !result->enable) {
|
||||
if (result->pri_val > max->pri)
|
||||
DRM_DEBUG_KMS("Primary WM%d too large %u (max %u)\n",
|
||||
level, result->pri_val, max->pri);
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Primary WM%d too large %u (max %u)\n",
|
||||
level, result->pri_val, max->pri);
|
||||
if (result->spr_val > max->spr)
|
||||
DRM_DEBUG_KMS("Sprite WM%d too large %u (max %u)\n",
|
||||
level, result->spr_val, max->spr);
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Sprite WM%d too large %u (max %u)\n",
|
||||
level, result->spr_val, max->spr);
|
||||
if (result->cur_val > max->cur)
|
||||
DRM_DEBUG_KMS("Cursor WM%d too large %u (max %u)\n",
|
||||
level, result->cur_val, max->cur);
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Cursor WM%d too large %u (max %u)\n",
|
||||
level, result->cur_val, max->cur);
|
||||
|
||||
result->pri_val = min_t(u32, result->pri_val, max->pri);
|
||||
result->spr_val = min_t(u32, result->spr_val, max->spr);
|
||||
@ -2761,7 +2767,7 @@ static void ilk_setup_wm_latency(struct drm_i915_private *dev_priv)
|
||||
}
|
||||
}
|
||||
|
||||
static bool ilk_validate_pipe_wm(const struct drm_i915_private *dev_priv,
|
||||
static bool ilk_validate_pipe_wm(struct drm_i915_private *dev_priv,
|
||||
struct intel_pipe_wm *pipe_wm)
|
||||
{
|
||||
/* LP0 watermark maximums depend on this pipe alone */
|
||||
@ -2776,7 +2782,7 @@ static bool ilk_validate_pipe_wm(const struct drm_i915_private *dev_priv,
|
||||
ilk_compute_wm_maximums(dev_priv, 0, &config, INTEL_DDB_PART_1_2, &max);
|
||||
|
||||
/* At least LP0 must be valid */
|
||||
if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0])) {
|
||||
if (!ilk_validate_wm_level(dev_priv, 0, &max, &pipe_wm->wm[0])) {
|
||||
drm_dbg_kms(&dev_priv->drm, "LP0 watermark invalid\n");
|
||||
return false;
|
||||
}
|
||||
@ -2845,7 +2851,7 @@ static int ilk_compute_pipe_wm(struct intel_atomic_state *state,
|
||||
* register maximums since such watermarks are
|
||||
* always invalid.
|
||||
*/
|
||||
if (!ilk_validate_wm_level(level, &max, wm)) {
|
||||
if (!ilk_validate_wm_level(dev_priv, level, &max, wm)) {
|
||||
memset(wm, 0, sizeof(*wm));
|
||||
break;
|
||||
}
|
||||
@ -2976,7 +2982,7 @@ static void ilk_wm_merge(struct drm_i915_private *dev_priv,
|
||||
|
||||
if (level > last_enabled_level)
|
||||
wm->enable = false;
|
||||
else if (!ilk_validate_wm_level(level, max, wm))
|
||||
else if (!ilk_validate_wm_level(dev_priv, level, max, wm))
|
||||
/* make sure all following levels get disabled */
|
||||
last_enabled_level = level - 1;
|
||||
|
||||
@ -4016,10 +4022,7 @@ void i9xx_wm_init(struct drm_i915_private *dev_priv)
|
||||
g4x_setup_wm_latency(dev_priv);
|
||||
dev_priv->display.funcs.wm = &g4x_wm_funcs;
|
||||
} else if (IS_PINEVIEW(dev_priv)) {
|
||||
if (!intel_get_cxsr_latency(!IS_MOBILE(dev_priv),
|
||||
dev_priv->is_ddr3,
|
||||
dev_priv->fsb_freq,
|
||||
dev_priv->mem_freq)) {
|
||||
if (!intel_get_cxsr_latency(dev_priv)) {
|
||||
drm_info(&dev_priv->drm,
|
||||
"failed to find known CxSR latency "
|
||||
"(found ddr%s fsb freq %d, mem freq %d), "
|
||||
|
@ -29,6 +29,7 @@
|
||||
* See intel_atomic_plane.c for the plane-specific atomic functionality.
|
||||
*/
|
||||
|
||||
#include <drm/display/drm_dp_tunnel.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
@ -38,6 +39,7 @@
|
||||
#include "intel_atomic.h"
|
||||
#include "intel_cdclk.h"
|
||||
#include "intel_display_types.h"
|
||||
#include "intel_dp_tunnel.h"
|
||||
#include "intel_global_state.h"
|
||||
#include "intel_hdcp.h"
|
||||
#include "intel_psr.h"
|
||||
@ -258,6 +260,10 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc)
|
||||
if (crtc_state->post_csc_lut)
|
||||
drm_property_blob_get(crtc_state->post_csc_lut);
|
||||
|
||||
if (crtc_state->dp_tunnel_ref.tunnel)
|
||||
drm_dp_tunnel_ref_get(crtc_state->dp_tunnel_ref.tunnel,
|
||||
&crtc_state->dp_tunnel_ref);
|
||||
|
||||
crtc_state->update_pipe = false;
|
||||
crtc_state->update_m_n = false;
|
||||
crtc_state->update_lrr = false;
|
||||
@ -309,6 +315,8 @@ intel_crtc_destroy_state(struct drm_crtc *crtc,
|
||||
|
||||
__drm_atomic_helper_crtc_destroy_state(&crtc_state->uapi);
|
||||
intel_crtc_free_hw_state(crtc_state);
|
||||
if (crtc_state->dp_tunnel_ref.tunnel)
|
||||
drm_dp_tunnel_ref_put(&crtc_state->dp_tunnel_ref);
|
||||
kfree(crtc_state);
|
||||
}
|
||||
|
||||
@ -344,6 +352,8 @@ void intel_atomic_state_clear(struct drm_atomic_state *s)
|
||||
/* state->internal not reset on purpose */
|
||||
|
||||
state->dpll_set = state->modeset = false;
|
||||
|
||||
intel_dp_tunnel_atomic_cleanup_inherited_state(state);
|
||||
}
|
||||
|
||||
struct intel_crtc_state *
|
||||
|
@ -1759,7 +1759,8 @@ parse_mipi_config(struct drm_i915_private *i915,
|
||||
|
||||
/* Find the sequence block and size for the given panel. */
|
||||
static const u8 *
|
||||
find_panel_sequence_block(const struct bdb_mipi_sequence *sequence,
|
||||
find_panel_sequence_block(struct drm_i915_private *i915,
|
||||
const struct bdb_mipi_sequence *sequence,
|
||||
u16 panel_id, u32 *seq_size)
|
||||
{
|
||||
u32 total = get_blocksize(sequence);
|
||||
@ -1776,7 +1777,7 @@ find_panel_sequence_block(const struct bdb_mipi_sequence *sequence,
|
||||
|
||||
for (i = 0; i < MAX_MIPI_CONFIGURATIONS && index < total; i++) {
|
||||
if (index + header_size > total) {
|
||||
DRM_ERROR("Invalid sequence block (header)\n");
|
||||
drm_err(&i915->drm, "Invalid sequence block (header)\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1789,7 +1790,7 @@ find_panel_sequence_block(const struct bdb_mipi_sequence *sequence,
|
||||
index += header_size;
|
||||
|
||||
if (index + current_size > total) {
|
||||
DRM_ERROR("Invalid sequence block\n");
|
||||
drm_err(&i915->drm, "Invalid sequence block\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1801,12 +1802,13 @@ find_panel_sequence_block(const struct bdb_mipi_sequence *sequence,
|
||||
index += current_size;
|
||||
}
|
||||
|
||||
DRM_ERROR("Sequence block detected but no valid configuration\n");
|
||||
drm_err(&i915->drm, "Sequence block detected but no valid configuration\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int goto_next_sequence(const u8 *data, int index, int total)
|
||||
static int goto_next_sequence(struct drm_i915_private *i915,
|
||||
const u8 *data, int index, int total)
|
||||
{
|
||||
u16 len;
|
||||
|
||||
@ -1836,7 +1838,7 @@ static int goto_next_sequence(const u8 *data, int index, int total)
|
||||
len = *(data + index + 6) + 7;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Unknown operation byte\n");
|
||||
drm_err(&i915->drm, "Unknown operation byte\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -1844,7 +1846,8 @@ static int goto_next_sequence(const u8 *data, int index, int total)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int goto_next_sequence_v3(const u8 *data, int index, int total)
|
||||
static int goto_next_sequence_v3(struct drm_i915_private *i915,
|
||||
const u8 *data, int index, int total)
|
||||
{
|
||||
int seq_end;
|
||||
u16 len;
|
||||
@ -1855,7 +1858,7 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total)
|
||||
* checking on the structure.
|
||||
*/
|
||||
if (total < 5) {
|
||||
DRM_ERROR("Too small sequence size\n");
|
||||
drm_err(&i915->drm, "Too small sequence size\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1872,7 +1875,7 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total)
|
||||
|
||||
seq_end = index + size_of_sequence;
|
||||
if (seq_end > total) {
|
||||
DRM_ERROR("Invalid sequence size\n");
|
||||
drm_err(&i915->drm, "Invalid sequence size\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1882,7 +1885,7 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total)
|
||||
|
||||
if (operation_byte == MIPI_SEQ_ELEM_END) {
|
||||
if (index != seq_end) {
|
||||
DRM_ERROR("Invalid element structure\n");
|
||||
drm_err(&i915->drm, "Invalid element structure\n");
|
||||
return 0;
|
||||
}
|
||||
return index;
|
||||
@ -1904,8 +1907,8 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total)
|
||||
case MIPI_SEQ_ELEM_PMIC:
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Unknown operation byte %u\n",
|
||||
operation_byte);
|
||||
drm_err(&i915->drm, "Unknown operation byte %u\n",
|
||||
operation_byte);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2030,7 +2033,7 @@ parse_mipi_sequence(struct drm_i915_private *i915,
|
||||
drm_dbg(&i915->drm, "Found MIPI sequence block v%u\n",
|
||||
sequence->version);
|
||||
|
||||
seq_data = find_panel_sequence_block(sequence, panel_type, &seq_size);
|
||||
seq_data = find_panel_sequence_block(i915, sequence, panel_type, &seq_size);
|
||||
if (!seq_data)
|
||||
return;
|
||||
|
||||
@ -2058,9 +2061,9 @@ parse_mipi_sequence(struct drm_i915_private *i915,
|
||||
panel->vbt.dsi.sequence[seq_id] = data + index;
|
||||
|
||||
if (sequence->version >= 3)
|
||||
index = goto_next_sequence_v3(data, index, seq_size);
|
||||
index = goto_next_sequence_v3(i915, data, index, seq_size);
|
||||
else
|
||||
index = goto_next_sequence(data, index, seq_size);
|
||||
index = goto_next_sequence(i915, data, index, seq_size);
|
||||
if (!index) {
|
||||
drm_err(&i915->drm, "Invalid sequence %u\n",
|
||||
seq_id);
|
||||
@ -2135,12 +2138,13 @@ parse_compression_parameters(struct drm_i915_private *i915)
|
||||
}
|
||||
}
|
||||
|
||||
static u8 translate_iboost(u8 val)
|
||||
static u8 translate_iboost(struct drm_i915_private *i915, u8 val)
|
||||
{
|
||||
static const u8 mapping[] = { 1, 3, 7 }; /* See VBT spec */
|
||||
|
||||
if (val >= ARRAY_SIZE(mapping)) {
|
||||
DRM_DEBUG_KMS("Unsupported I_boost value found in VBT (%d), display may not work properly\n", val);
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Unsupported I_boost value found in VBT (%d), display may not work properly\n", val);
|
||||
return 0;
|
||||
}
|
||||
return mapping[val];
|
||||
@ -2897,12 +2901,14 @@ static const struct bdb_header *get_bdb_header(const struct vbt_header *vbt)
|
||||
|
||||
/**
|
||||
* intel_bios_is_valid_vbt - does the given buffer contain a valid VBT
|
||||
* @i915: the device
|
||||
* @buf: pointer to a buffer to validate
|
||||
* @size: size of the buffer
|
||||
*
|
||||
* Returns true on valid VBT.
|
||||
*/
|
||||
bool intel_bios_is_valid_vbt(const void *buf, size_t size)
|
||||
bool intel_bios_is_valid_vbt(struct drm_i915_private *i915,
|
||||
const void *buf, size_t size)
|
||||
{
|
||||
const struct vbt_header *vbt = buf;
|
||||
const struct bdb_header *bdb;
|
||||
@ -2911,17 +2917,17 @@ bool intel_bios_is_valid_vbt(const void *buf, size_t size)
|
||||
return false;
|
||||
|
||||
if (sizeof(struct vbt_header) > size) {
|
||||
DRM_DEBUG_DRIVER("VBT header incomplete\n");
|
||||
drm_dbg_kms(&i915->drm, "VBT header incomplete\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(vbt->signature, "$VBT", 4)) {
|
||||
DRM_DEBUG_DRIVER("VBT invalid signature\n");
|
||||
drm_dbg_kms(&i915->drm, "VBT invalid signature\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vbt->vbt_size > size) {
|
||||
DRM_DEBUG_DRIVER("VBT incomplete (vbt_size overflows)\n");
|
||||
drm_dbg_kms(&i915->drm, "VBT incomplete (vbt_size overflows)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2931,13 +2937,13 @@ bool intel_bios_is_valid_vbt(const void *buf, size_t size)
|
||||
vbt->bdb_offset,
|
||||
sizeof(struct bdb_header),
|
||||
size)) {
|
||||
DRM_DEBUG_DRIVER("BDB header incomplete\n");
|
||||
drm_dbg_kms(&i915->drm, "BDB header incomplete\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bdb = get_bdb_header(vbt);
|
||||
if (range_overflows_t(size_t, vbt->bdb_offset, bdb->bdb_size, size)) {
|
||||
DRM_DEBUG_DRIVER("BDB incomplete\n");
|
||||
drm_dbg_kms(&i915->drm, "BDB incomplete\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2989,7 +2995,7 @@ static struct vbt_header *spi_oprom_get_vbt(struct drm_i915_private *i915)
|
||||
for (count = 0; count < vbt_size; count += 4)
|
||||
*(vbt + store++) = intel_spi_read(&i915->uncore, found + count);
|
||||
|
||||
if (!intel_bios_is_valid_vbt(vbt, vbt_size))
|
||||
if (!intel_bios_is_valid_vbt(i915, vbt, vbt_size))
|
||||
goto err_free_vbt;
|
||||
|
||||
drm_dbg_kms(&i915->drm, "Found valid VBT in SPI flash\n");
|
||||
@ -3046,7 +3052,7 @@ static struct vbt_header *oprom_get_vbt(struct drm_i915_private *i915)
|
||||
|
||||
memcpy_fromio(vbt, p, vbt_size);
|
||||
|
||||
if (!intel_bios_is_valid_vbt(vbt, vbt_size))
|
||||
if (!intel_bios_is_valid_vbt(i915, vbt, vbt_size))
|
||||
goto err_free_vbt;
|
||||
|
||||
pci_unmap_rom(pdev, oprom);
|
||||
@ -3398,6 +3404,7 @@ static void fill_dsc(struct intel_crtc_state *crtc_state,
|
||||
struct dsc_compression_parameters_entry *dsc,
|
||||
int dsc_max_bpc)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
|
||||
struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
|
||||
int bpc = 8;
|
||||
|
||||
@ -3411,8 +3418,8 @@ static void fill_dsc(struct intel_crtc_state *crtc_state,
|
||||
else if (dsc->support_8bpc && dsc_max_bpc >= 8)
|
||||
bpc = 8;
|
||||
else
|
||||
DRM_DEBUG_KMS("VBT: Unsupported BPC %d for DCS\n",
|
||||
dsc_max_bpc);
|
||||
drm_dbg_kms(&i915->drm, "VBT: Unsupported BPC %d for DCS\n",
|
||||
dsc_max_bpc);
|
||||
|
||||
crtc_state->pipe_bpp = bpc * 3;
|
||||
|
||||
@ -3432,16 +3439,16 @@ static void fill_dsc(struct intel_crtc_state *crtc_state,
|
||||
} else {
|
||||
/* FIXME */
|
||||
if (!(dsc->slices_per_line & BIT(0)))
|
||||
DRM_DEBUG_KMS("VBT: Unsupported DSC slice count for DSI\n");
|
||||
drm_dbg_kms(&i915->drm, "VBT: Unsupported DSC slice count for DSI\n");
|
||||
|
||||
crtc_state->dsc.slice_count = 1;
|
||||
}
|
||||
|
||||
if (crtc_state->hw.adjusted_mode.crtc_hdisplay %
|
||||
crtc_state->dsc.slice_count != 0)
|
||||
DRM_DEBUG_KMS("VBT: DSC hdisplay %d not divisible by slice count %d\n",
|
||||
crtc_state->hw.adjusted_mode.crtc_hdisplay,
|
||||
crtc_state->dsc.slice_count);
|
||||
drm_dbg_kms(&i915->drm, "VBT: DSC hdisplay %d not divisible by slice count %d\n",
|
||||
crtc_state->hw.adjusted_mode.crtc_hdisplay,
|
||||
crtc_state->dsc.slice_count);
|
||||
|
||||
/*
|
||||
* The VBT rc_buffer_block_size and rc_buffer_size definitions
|
||||
@ -3597,7 +3604,7 @@ int intel_bios_dp_boost_level(const struct intel_bios_encoder_data *devdata)
|
||||
if (!devdata || devdata->i915->display.vbt.version < 196 || !devdata->child.iboost)
|
||||
return 0;
|
||||
|
||||
return translate_iboost(devdata->child.dp_iboost_level);
|
||||
return translate_iboost(devdata->i915, devdata->child.dp_iboost_level);
|
||||
}
|
||||
|
||||
int intel_bios_hdmi_boost_level(const struct intel_bios_encoder_data *devdata)
|
||||
@ -3605,7 +3612,7 @@ int intel_bios_hdmi_boost_level(const struct intel_bios_encoder_data *devdata)
|
||||
if (!devdata || devdata->i915->display.vbt.version < 196 || !devdata->child.iboost)
|
||||
return 0;
|
||||
|
||||
return translate_iboost(devdata->child.hdmi_iboost_level);
|
||||
return translate_iboost(devdata->i915, devdata->child.hdmi_iboost_level);
|
||||
}
|
||||
|
||||
int intel_bios_hdmi_ddc_pin(const struct intel_bios_encoder_data *devdata)
|
||||
|
@ -242,7 +242,8 @@ void intel_bios_init_panel_late(struct drm_i915_private *dev_priv,
|
||||
const struct drm_edid *drm_edid);
|
||||
void intel_bios_fini_panel(struct intel_panel *panel);
|
||||
void intel_bios_driver_remove(struct drm_i915_private *dev_priv);
|
||||
bool intel_bios_is_valid_vbt(const void *buf, size_t size);
|
||||
bool intel_bios_is_valid_vbt(struct drm_i915_private *i915,
|
||||
const void *buf, size_t size);
|
||||
bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv);
|
||||
bool intel_bios_is_lvds_present(struct drm_i915_private *dev_priv, u8 *i2c_pin);
|
||||
bool intel_bios_is_port_present(struct drm_i915_private *dev_priv, enum port port);
|
||||
|
@ -63,6 +63,16 @@
|
||||
* DMC will not change the active CDCLK frequency however, so that part
|
||||
* will still be performed by the driver directly.
|
||||
*
|
||||
* Several methods exist to change the CDCLK frequency, which ones are
|
||||
* supported depends on the platform:
|
||||
*
|
||||
* - Full PLL disable + re-enable with new VCO frequency. Pipes must be inactive.
|
||||
* - CD2X divider update. Single pipe can be active as the divider update
|
||||
* can be synchronized with the pipe's start of vblank.
|
||||
* - Crawl the PLL smoothly to the new VCO frequency. Pipes can be active.
|
||||
* - Squash waveform update. Pipes can be active.
|
||||
* - Crawl and squash can also be done back to back. Pipes can be active.
|
||||
*
|
||||
* RAWCLK is a fixed frequency clock, often used by various auxiliary
|
||||
* blocks such as AUX CH or backlight PWM. Hence the only thing we
|
||||
* really need to know about RAWCLK is its frequency so that various
|
||||
@ -1406,6 +1416,20 @@ static const struct intel_cdclk_vals lnl_cdclk_table[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static const int cdclk_squash_len = 16;
|
||||
|
||||
static int cdclk_squash_divider(u16 waveform)
|
||||
{
|
||||
return hweight16(waveform ?: 0xffff);
|
||||
}
|
||||
|
||||
static int cdclk_divider(int cdclk, int vco, u16 waveform)
|
||||
{
|
||||
/* 2 * cd2x divider */
|
||||
return DIV_ROUND_CLOSEST(vco * cdclk_squash_divider(waveform),
|
||||
cdclk * cdclk_squash_len);
|
||||
}
|
||||
|
||||
static int bxt_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk)
|
||||
{
|
||||
const struct intel_cdclk_vals *table = dev_priv->display.cdclk.table;
|
||||
@ -1744,10 +1768,10 @@ static u32 bxt_cdclk_cd2x_pipe(struct drm_i915_private *dev_priv, enum pipe pipe
|
||||
}
|
||||
|
||||
static u32 bxt_cdclk_cd2x_div_sel(struct drm_i915_private *dev_priv,
|
||||
int cdclk, int vco)
|
||||
int cdclk, int vco, u16 waveform)
|
||||
{
|
||||
/* cdclk = vco / 2 / div{1,1.5,2,4} */
|
||||
switch (DIV_ROUND_CLOSEST(vco, cdclk)) {
|
||||
switch (cdclk_divider(cdclk, vco, waveform)) {
|
||||
default:
|
||||
drm_WARN_ON(&dev_priv->drm,
|
||||
cdclk != dev_priv->display.cdclk.hw.bypass);
|
||||
@ -1764,7 +1788,7 @@ static u32 bxt_cdclk_cd2x_div_sel(struct drm_i915_private *dev_priv,
|
||||
}
|
||||
}
|
||||
|
||||
static u32 cdclk_squash_waveform(struct drm_i915_private *dev_priv,
|
||||
static u16 cdclk_squash_waveform(struct drm_i915_private *dev_priv,
|
||||
int cdclk)
|
||||
{
|
||||
const struct intel_cdclk_vals *table = dev_priv->display.cdclk.table;
|
||||
@ -1826,20 +1850,13 @@ static bool cdclk_pll_is_unknown(unsigned int vco)
|
||||
return vco == ~0;
|
||||
}
|
||||
|
||||
static const int cdclk_squash_len = 16;
|
||||
|
||||
static int cdclk_squash_divider(u16 waveform)
|
||||
{
|
||||
return hweight16(waveform ?: 0xffff);
|
||||
}
|
||||
|
||||
static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i915,
|
||||
const struct intel_cdclk_config *old_cdclk_config,
|
||||
const struct intel_cdclk_config *new_cdclk_config,
|
||||
struct intel_cdclk_config *mid_cdclk_config)
|
||||
{
|
||||
u16 old_waveform, new_waveform, mid_waveform;
|
||||
int div = 2;
|
||||
int old_div, new_div, mid_div;
|
||||
|
||||
/* Return if PLL is in an unknown state, force a complete disable and re-enable. */
|
||||
if (cdclk_pll_is_unknown(old_cdclk_config->vco))
|
||||
@ -1858,6 +1875,18 @@ static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i91
|
||||
old_waveform == new_waveform)
|
||||
return false;
|
||||
|
||||
old_div = cdclk_divider(old_cdclk_config->cdclk,
|
||||
old_cdclk_config->vco, old_waveform);
|
||||
new_div = cdclk_divider(new_cdclk_config->cdclk,
|
||||
new_cdclk_config->vco, new_waveform);
|
||||
|
||||
/*
|
||||
* Should not happen currently. We might need more midpoint
|
||||
* transitions if we need to also change the cd2x divider.
|
||||
*/
|
||||
if (drm_WARN_ON(&i915->drm, old_div != new_div))
|
||||
return false;
|
||||
|
||||
*mid_cdclk_config = *new_cdclk_config;
|
||||
|
||||
/*
|
||||
@ -1870,15 +1899,17 @@ static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i91
|
||||
|
||||
if (cdclk_squash_divider(new_waveform) > cdclk_squash_divider(old_waveform)) {
|
||||
mid_cdclk_config->vco = old_cdclk_config->vco;
|
||||
mid_div = old_div;
|
||||
mid_waveform = new_waveform;
|
||||
} else {
|
||||
mid_cdclk_config->vco = new_cdclk_config->vco;
|
||||
mid_div = new_div;
|
||||
mid_waveform = old_waveform;
|
||||
}
|
||||
|
||||
mid_cdclk_config->cdclk = DIV_ROUND_CLOSEST(cdclk_squash_divider(mid_waveform) *
|
||||
mid_cdclk_config->vco,
|
||||
cdclk_squash_len * div);
|
||||
cdclk_squash_len * mid_div);
|
||||
|
||||
/* make sure the mid clock came out sane */
|
||||
|
||||
@ -1906,16 +1937,12 @@ static u32 bxt_cdclk_ctl(struct drm_i915_private *i915,
|
||||
{
|
||||
int cdclk = cdclk_config->cdclk;
|
||||
int vco = cdclk_config->vco;
|
||||
int unsquashed_cdclk;
|
||||
u16 waveform;
|
||||
u32 val;
|
||||
|
||||
waveform = cdclk_squash_waveform(i915, cdclk);
|
||||
|
||||
unsquashed_cdclk = DIV_ROUND_CLOSEST(cdclk * cdclk_squash_len,
|
||||
cdclk_squash_divider(waveform));
|
||||
|
||||
val = bxt_cdclk_cd2x_div_sel(i915, unsquashed_cdclk, vco) |
|
||||
val = bxt_cdclk_cd2x_div_sel(i915, cdclk, vco, waveform) |
|
||||
bxt_cdclk_cd2x_pipe(i915, pipe);
|
||||
|
||||
/*
|
||||
|
@ -2111,7 +2111,8 @@ static u32 intel_degamma_lut_size(const struct intel_crtc_state *crtc_state)
|
||||
return DISPLAY_INFO(i915)->color.degamma_lut_size;
|
||||
}
|
||||
|
||||
static int check_lut_size(const struct drm_property_blob *lut, int expected)
|
||||
static int check_lut_size(struct drm_i915_private *i915,
|
||||
const struct drm_property_blob *lut, int expected)
|
||||
{
|
||||
int len;
|
||||
|
||||
@ -2120,8 +2121,8 @@ static int check_lut_size(const struct drm_property_blob *lut, int expected)
|
||||
|
||||
len = drm_color_lut_size(lut);
|
||||
if (len != expected) {
|
||||
DRM_DEBUG_KMS("Invalid LUT size; got %d, expected %d\n",
|
||||
len, expected);
|
||||
drm_dbg_kms(&i915->drm, "Invalid LUT size; got %d, expected %d\n",
|
||||
len, expected);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -2146,8 +2147,8 @@ static int _check_luts(const struct intel_crtc_state *crtc_state,
|
||||
degamma_length = intel_degamma_lut_size(crtc_state);
|
||||
gamma_length = intel_gamma_lut_size(crtc_state);
|
||||
|
||||
if (check_lut_size(degamma_lut, degamma_length) ||
|
||||
check_lut_size(gamma_lut, gamma_length))
|
||||
if (check_lut_size(i915, degamma_lut, degamma_length) ||
|
||||
check_lut_size(i915, gamma_lut, gamma_length))
|
||||
return -EINVAL;
|
||||
|
||||
if (drm_color_lut_check(degamma_lut, degamma_tests) ||
|
||||
|
@ -933,6 +933,9 @@ static int intel_crt_get_modes(struct drm_connector *connector)
|
||||
struct i2c_adapter *ddc;
|
||||
int ret;
|
||||
|
||||
if (!intel_display_driver_check_access(dev_priv))
|
||||
return drm_edid_connector_add_modes(connector);
|
||||
|
||||
wakeref = intel_display_power_get(dev_priv,
|
||||
intel_encoder->power_domain);
|
||||
|
||||
|
@ -848,10 +848,10 @@ static const struct intel_c20pll_state mtl_c20_dp_hbr3 = {
|
||||
static const struct intel_c20pll_state mtl_c20_dp_uhbr10 = {
|
||||
.clock = 1000000, /* 10 Gbps */
|
||||
.tx = { 0xbe21, /* tx cfg0 */
|
||||
0x4800, /* tx cfg1 */
|
||||
0xe800, /* tx cfg1 */
|
||||
0x0000, /* tx cfg2 */
|
||||
},
|
||||
.cmn = {0x0500, /* cmn cfg0*/
|
||||
.cmn = {0x0700, /* cmn cfg0*/
|
||||
0x0005, /* cmn cfg1 */
|
||||
0x0000, /* cmn cfg2 */
|
||||
0x0000, /* cmn cfg3 */
|
||||
@ -1641,7 +1641,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_594 = {
|
||||
static const struct intel_c20pll_state mtl_c20_hdmi_300 = {
|
||||
.clock = 3000000,
|
||||
.tx = { 0xbe98, /* tx cfg0 */
|
||||
0x9800, /* tx cfg1 */
|
||||
0x8800, /* tx cfg1 */
|
||||
0x0000, /* tx cfg2 */
|
||||
},
|
||||
.cmn = { 0x0500, /* cmn cfg0*/
|
||||
@ -1649,8 +1649,8 @@ static const struct intel_c20pll_state mtl_c20_hdmi_300 = {
|
||||
0x0000, /* cmn cfg2 */
|
||||
0x0000, /* cmn cfg3 */
|
||||
},
|
||||
.mpllb = { 0x209c, /* mpllb cfg0 */
|
||||
0x7d10, /* mpllb cfg1 */
|
||||
.mpllb = { 0x309c, /* mpllb cfg0 */
|
||||
0x2110, /* mpllb cfg1 */
|
||||
0xca06, /* mpllb cfg2 */
|
||||
0xbe40, /* mpllb cfg3 */
|
||||
0x0000, /* mpllb cfg4 */
|
||||
@ -1666,7 +1666,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_300 = {
|
||||
static const struct intel_c20pll_state mtl_c20_hdmi_600 = {
|
||||
.clock = 6000000,
|
||||
.tx = { 0xbe98, /* tx cfg0 */
|
||||
0x9800, /* tx cfg1 */
|
||||
0x8800, /* tx cfg1 */
|
||||
0x0000, /* tx cfg2 */
|
||||
},
|
||||
.cmn = { 0x0500, /* cmn cfg0*/
|
||||
@ -1674,8 +1674,8 @@ static const struct intel_c20pll_state mtl_c20_hdmi_600 = {
|
||||
0x0000, /* cmn cfg2 */
|
||||
0x0000, /* cmn cfg3 */
|
||||
},
|
||||
.mpllb = { 0x009c, /* mpllb cfg0 */
|
||||
0x7d08, /* mpllb cfg1 */
|
||||
.mpllb = { 0x109c, /* mpllb cfg0 */
|
||||
0x2108, /* mpllb cfg1 */
|
||||
0xca06, /* mpllb cfg2 */
|
||||
0xbe40, /* mpllb cfg3 */
|
||||
0x0000, /* mpllb cfg4 */
|
||||
@ -1691,7 +1691,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_600 = {
|
||||
static const struct intel_c20pll_state mtl_c20_hdmi_800 = {
|
||||
.clock = 8000000,
|
||||
.tx = { 0xbe98, /* tx cfg0 */
|
||||
0x9800, /* tx cfg1 */
|
||||
0x8800, /* tx cfg1 */
|
||||
0x0000, /* tx cfg2 */
|
||||
},
|
||||
.cmn = { 0x0500, /* cmn cfg0*/
|
||||
@ -1699,8 +1699,8 @@ static const struct intel_c20pll_state mtl_c20_hdmi_800 = {
|
||||
0x0000, /* cmn cfg2 */
|
||||
0x0000, /* cmn cfg3 */
|
||||
},
|
||||
.mpllb = { 0x00d0, /* mpllb cfg0 */
|
||||
0x7d08, /* mpllb cfg1 */
|
||||
.mpllb = { 0x10d0, /* mpllb cfg0 */
|
||||
0x2108, /* mpllb cfg1 */
|
||||
0x4a06, /* mpllb cfg2 */
|
||||
0xbe40, /* mpllb cfg3 */
|
||||
0x0000, /* mpllb cfg4 */
|
||||
@ -1716,7 +1716,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_800 = {
|
||||
static const struct intel_c20pll_state mtl_c20_hdmi_1000 = {
|
||||
.clock = 10000000,
|
||||
.tx = { 0xbe98, /* tx cfg0 */
|
||||
0x9800, /* tx cfg1 */
|
||||
0x8800, /* tx cfg1 */
|
||||
0x0000, /* tx cfg2 */
|
||||
},
|
||||
.cmn = { 0x0500, /* cmn cfg0*/
|
||||
@ -1725,7 +1725,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_1000 = {
|
||||
0x0000, /* cmn cfg3 */
|
||||
},
|
||||
.mpllb = { 0x1104, /* mpllb cfg0 */
|
||||
0x7d08, /* mpllb cfg1 */
|
||||
0x2108, /* mpllb cfg1 */
|
||||
0x0a06, /* mpllb cfg2 */
|
||||
0xbe40, /* mpllb cfg3 */
|
||||
0x0000, /* mpllb cfg4 */
|
||||
@ -1741,7 +1741,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_1000 = {
|
||||
static const struct intel_c20pll_state mtl_c20_hdmi_1200 = {
|
||||
.clock = 12000000,
|
||||
.tx = { 0xbe98, /* tx cfg0 */
|
||||
0x9800, /* tx cfg1 */
|
||||
0x8800, /* tx cfg1 */
|
||||
0x0000, /* tx cfg2 */
|
||||
},
|
||||
.cmn = { 0x0500, /* cmn cfg0*/
|
||||
@ -1749,8 +1749,8 @@ static const struct intel_c20pll_state mtl_c20_hdmi_1200 = {
|
||||
0x0000, /* cmn cfg2 */
|
||||
0x0000, /* cmn cfg3 */
|
||||
},
|
||||
.mpllb = { 0x0138, /* mpllb cfg0 */
|
||||
0x7d08, /* mpllb cfg1 */
|
||||
.mpllb = { 0x1138, /* mpllb cfg0 */
|
||||
0x2108, /* mpllb cfg1 */
|
||||
0x5486, /* mpllb cfg2 */
|
||||
0xfe40, /* mpllb cfg3 */
|
||||
0x0000, /* mpllb cfg4 */
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include "intel_dp_aux.h"
|
||||
#include "intel_dp_link_training.h"
|
||||
#include "intel_dp_mst.h"
|
||||
#include "intel_dp_tunnel.h"
|
||||
#include "intel_dpio_phy.h"
|
||||
#include "intel_dsi.h"
|
||||
#include "intel_fdi.h"
|
||||
@ -4150,7 +4151,7 @@ static void intel_ddi_sync_state(struct intel_encoder *encoder,
|
||||
intel_tc_port_sanitize_mode(enc_to_dig_port(encoder),
|
||||
crtc_state);
|
||||
|
||||
if (crtc_state && intel_crtc_has_dp_encoder(crtc_state))
|
||||
if (intel_encoder_is_dp(encoder))
|
||||
intel_dp_sync_state(encoder, crtc_state);
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <linux/string_helpers.h>
|
||||
|
||||
#include <drm/display/drm_dp_helper.h>
|
||||
#include <drm/display/drm_dp_tunnel.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_atomic_uapi.h>
|
||||
@ -73,6 +74,7 @@
|
||||
#include "intel_dp.h"
|
||||
#include "intel_dp_link_training.h"
|
||||
#include "intel_dp_mst.h"
|
||||
#include "intel_dp_tunnel.h"
|
||||
#include "intel_dpll.h"
|
||||
#include "intel_dpll_mgr.h"
|
||||
#include "intel_dpt.h"
|
||||
@ -2478,7 +2480,7 @@ intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes,
|
||||
u32 link_symbol_clock = intel_dp_link_symbol_clock(link_clock);
|
||||
u32 data_m = intel_dp_effective_data_rate(pixel_clock, bits_per_pixel_x16,
|
||||
bw_overhead);
|
||||
u32 data_n = intel_dp_max_data_rate(link_clock, nlanes);
|
||||
u32 data_n = drm_dp_max_dprx_data_rate(link_clock, nlanes);
|
||||
|
||||
/*
|
||||
* Windows/BIOS uses fixed M/N values always. Follow suit.
|
||||
@ -4490,6 +4492,8 @@ copy_bigjoiner_crtc_state_modeset(struct intel_atomic_state *state,
|
||||
saved_state->crc_enabled = slave_crtc_state->crc_enabled;
|
||||
|
||||
intel_crtc_free_hw_state(slave_crtc_state);
|
||||
if (slave_crtc_state->dp_tunnel_ref.tunnel)
|
||||
drm_dp_tunnel_ref_put(&slave_crtc_state->dp_tunnel_ref);
|
||||
memcpy(slave_crtc_state, saved_state, sizeof(*slave_crtc_state));
|
||||
kfree(saved_state);
|
||||
|
||||
@ -4505,6 +4509,10 @@ copy_bigjoiner_crtc_state_modeset(struct intel_atomic_state *state,
|
||||
&master_crtc_state->hw.adjusted_mode);
|
||||
slave_crtc_state->hw.scaling_filter = master_crtc_state->hw.scaling_filter;
|
||||
|
||||
if (master_crtc_state->dp_tunnel_ref.tunnel)
|
||||
drm_dp_tunnel_ref_get(master_crtc_state->dp_tunnel_ref.tunnel,
|
||||
&slave_crtc_state->dp_tunnel_ref);
|
||||
|
||||
copy_bigjoiner_crtc_state_nomodeset(state, slave_crtc);
|
||||
|
||||
slave_crtc_state->uapi.mode_changed = master_crtc_state->uapi.mode_changed;
|
||||
@ -4533,6 +4541,8 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state,
|
||||
/* free the old crtc_state->hw members */
|
||||
intel_crtc_free_hw_state(crtc_state);
|
||||
|
||||
intel_dp_tunnel_atomic_clear_stream_bw(state, crtc_state);
|
||||
|
||||
/* FIXME: before the switch to atomic started, a new pipe_config was
|
||||
* kzalloc'd. Code that depends on any field being zero should be
|
||||
* fixed, so that the crtc_state can be safely duplicated. For now,
|
||||
@ -4851,10 +4861,12 @@ memcmp_diff_len(const u8 *a, const u8 *b, size_t len)
|
||||
}
|
||||
|
||||
static void
|
||||
pipe_config_buffer_mismatch(struct drm_i915_private *dev_priv,
|
||||
bool fastset, const char *name,
|
||||
pipe_config_buffer_mismatch(bool fastset, const struct intel_crtc *crtc,
|
||||
const char *name,
|
||||
const u8 *a, const u8 *b, size_t len)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||
|
||||
if (fastset) {
|
||||
if (!drm_debug_enabled(DRM_UT_KMS))
|
||||
return;
|
||||
@ -4863,7 +4875,8 @@ pipe_config_buffer_mismatch(struct drm_i915_private *dev_priv,
|
||||
len = memcmp_diff_len(a, b, len);
|
||||
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
"fastset requirement not met in %s buffer\n", name);
|
||||
"[CRTC:%d:%s] fastset requirement not met in %s buffer\n",
|
||||
crtc->base.base.id, crtc->base.name, name);
|
||||
print_hex_dump(KERN_DEBUG, "expected: ", DUMP_PREFIX_NONE,
|
||||
16, 0, a, len, false);
|
||||
print_hex_dump(KERN_DEBUG, "found: ", DUMP_PREFIX_NONE,
|
||||
@ -4872,7 +4885,8 @@ pipe_config_buffer_mismatch(struct drm_i915_private *dev_priv,
|
||||
/* only dump up to the last difference */
|
||||
len = memcmp_diff_len(a, b, len);
|
||||
|
||||
drm_err(&dev_priv->drm, "mismatch in %s buffer\n", name);
|
||||
drm_err(&dev_priv->drm, "[CRTC:%d:%s] mismatch in %s buffer\n",
|
||||
crtc->base.base.id, crtc->base.name, name);
|
||||
print_hex_dump(KERN_ERR, "expected: ", DUMP_PREFIX_NONE,
|
||||
16, 0, a, len, false);
|
||||
print_hex_dump(KERN_ERR, "found: ", DUMP_PREFIX_NONE,
|
||||
@ -4903,18 +4917,34 @@ pipe_config_mismatch(bool fastset, const struct intel_crtc *crtc,
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static bool fastboot_enabled(struct drm_i915_private *dev_priv)
|
||||
static void
|
||||
pipe_config_pll_mismatch(bool fastset,
|
||||
const struct intel_crtc *crtc,
|
||||
const char *name,
|
||||
const struct intel_dpll_hw_state *a,
|
||||
const struct intel_dpll_hw_state *b)
|
||||
{
|
||||
/* Enable fastboot by default on Skylake and newer */
|
||||
if (DISPLAY_VER(dev_priv) >= 9)
|
||||
return true;
|
||||
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
|
||||
|
||||
/* Enable fastboot by default on VLV and CHV */
|
||||
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
|
||||
return true;
|
||||
if (fastset) {
|
||||
if (!drm_debug_enabled(DRM_UT_KMS))
|
||||
return;
|
||||
|
||||
/* Disabled by default on all others */
|
||||
return false;
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[CRTC:%d:%s] fastset requirement not met in %s\n",
|
||||
crtc->base.base.id, crtc->base.name, name);
|
||||
drm_dbg_kms(&i915->drm, "expected:\n");
|
||||
intel_dpll_dump_hw_state(i915, a);
|
||||
drm_dbg_kms(&i915->drm, "found:\n");
|
||||
intel_dpll_dump_hw_state(i915, b);
|
||||
} else {
|
||||
drm_err(&i915->drm, "[CRTC:%d:%s] mismatch in %s buffer\n",
|
||||
crtc->base.base.id, crtc->base.name, name);
|
||||
drm_err(&i915->drm, "expected:\n");
|
||||
intel_dpll_dump_hw_state(i915, a);
|
||||
drm_err(&i915->drm, "found:\n");
|
||||
intel_dpll_dump_hw_state(i915, b);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@ -4925,14 +4955,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
|
||||
struct drm_i915_private *dev_priv = to_i915(current_config->uapi.crtc->dev);
|
||||
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
|
||||
bool ret = true;
|
||||
bool fixup_inherited = fastset &&
|
||||
current_config->inherited && !pipe_config->inherited;
|
||||
|
||||
if (fixup_inherited && !fastboot_enabled(dev_priv)) {
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
"initial modeset and fastboot not set\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
#define PIPE_CONF_CHECK_X(name) do { \
|
||||
if (current_config->name != pipe_config->name) { \
|
||||
@ -5012,7 +5034,17 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PIPE_CONF_CHECK_TIMINGS(name) do { \
|
||||
#define PIPE_CONF_CHECK_PLL(name) do { \
|
||||
if (!intel_dpll_compare_hw_state(dev_priv, ¤t_config->name, \
|
||||
&pipe_config->name)) { \
|
||||
pipe_config_pll_mismatch(fastset, crtc, __stringify(name), \
|
||||
¤t_config->name, \
|
||||
&pipe_config->name); \
|
||||
ret = false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PIPE_CONF_CHECK_TIMINGS(name) do { \
|
||||
PIPE_CONF_CHECK_I(name.crtc_hdisplay); \
|
||||
PIPE_CONF_CHECK_I(name.crtc_htotal); \
|
||||
PIPE_CONF_CHECK_I(name.crtc_hblank_start); \
|
||||
@ -5071,7 +5103,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
|
||||
BUILD_BUG_ON(sizeof(current_config->name) != (len)); \
|
||||
BUILD_BUG_ON(sizeof(pipe_config->name) != (len)); \
|
||||
if (!intel_compare_buffer(current_config->name, pipe_config->name, (len))) { \
|
||||
pipe_config_buffer_mismatch(dev_priv, fastset, __stringify(name), \
|
||||
pipe_config_buffer_mismatch(fastset, crtc, __stringify(name), \
|
||||
current_config->name, \
|
||||
pipe_config->name, \
|
||||
(len)); \
|
||||
@ -5215,42 +5247,12 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
|
||||
|
||||
PIPE_CONF_CHECK_BOOL(double_wide);
|
||||
|
||||
if (dev_priv->display.dpll.mgr) {
|
||||
if (dev_priv->display.dpll.mgr)
|
||||
PIPE_CONF_CHECK_P(shared_dpll);
|
||||
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.dpll);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.wrpll);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.spll);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr0);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.div0);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.ebb0);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.ebb4);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.pll0);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.pll1);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.pll2);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.pll3);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.pll6);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.pll8);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.pll9);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.pll10);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.pcsdw12);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.mg_refclkin_ctl);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_coreclkctl1);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_hsclkctl);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div0);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div1);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_lf);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_frac_lock);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_ssc);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_bias);
|
||||
PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_tdc_coldst_bias);
|
||||
}
|
||||
/* FIXME convert everything over the dpll_mgr */
|
||||
if (dev_priv->display.dpll.mgr || HAS_GMCH(dev_priv))
|
||||
PIPE_CONF_CHECK_PLL(dpll_hw_state);
|
||||
|
||||
PIPE_CONF_CHECK_X(dsi_pll.ctrl);
|
||||
PIPE_CONF_CHECK_X(dsi_pll.div);
|
||||
@ -5373,6 +5375,10 @@ static int intel_modeset_pipe(struct intel_atomic_state *state,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = intel_dp_tunnel_atomic_add_state_for_crtc(state, crtc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = intel_dp_mst_add_topology_state_for_crtc(state, crtc);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -6260,12 +6266,11 @@ static int intel_atomic_check_config(struct intel_atomic_state *state,
|
||||
|
||||
static int intel_atomic_check_config_and_link(struct intel_atomic_state *state)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(state->base.dev);
|
||||
struct intel_link_bw_limits new_limits;
|
||||
struct intel_link_bw_limits old_limits;
|
||||
int ret;
|
||||
|
||||
intel_link_bw_init_limits(i915, &new_limits);
|
||||
intel_link_bw_init_limits(state, &new_limits);
|
||||
old_limits = new_limits;
|
||||
|
||||
while (true) {
|
||||
@ -7118,6 +7123,8 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
|
||||
|
||||
intel_commit_modeset_disables(state);
|
||||
|
||||
intel_dp_tunnel_atomic_alloc_bw(state);
|
||||
|
||||
/* FIXME: Eventually get rid of our crtc->config pointer */
|
||||
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i)
|
||||
crtc->config = new_crtc_state;
|
||||
@ -8094,8 +8101,9 @@ void intel_hpd_poll_fini(struct drm_i915_private *i915)
|
||||
/* Kill all the work that may have been queued by hpd. */
|
||||
drm_connector_list_iter_begin(&i915->drm, &conn_iter);
|
||||
for_each_intel_connector_iter(connector, &conn_iter) {
|
||||
if (connector->modeset_retry_work.func)
|
||||
cancel_work_sync(&connector->modeset_retry_work);
|
||||
if (connector->modeset_retry_work.func &&
|
||||
cancel_work_sync(&connector->modeset_retry_work))
|
||||
drm_connector_put(&connector->base);
|
||||
if (connector->hdcp.shim) {
|
||||
cancel_delayed_work_sync(&connector->hdcp.check_work);
|
||||
cancel_work_sync(&connector->hdcp.prop_work);
|
||||
|
@ -524,6 +524,7 @@ struct intel_display {
|
||||
} wq;
|
||||
|
||||
/* Grouping using named structs. Keep sorted. */
|
||||
struct drm_dp_tunnel_mgr *dp_tunnel_mgr;
|
||||
struct intel_audio audio;
|
||||
struct intel_dpll dpll;
|
||||
struct intel_fbc *fbc[I915_MAX_FBCS];
|
||||
|
@ -188,7 +188,8 @@ static void intel_panel_info(struct seq_file *m,
|
||||
}
|
||||
|
||||
static void intel_hdcp_info(struct seq_file *m,
|
||||
struct intel_connector *intel_connector)
|
||||
struct intel_connector *intel_connector,
|
||||
bool remote_req)
|
||||
{
|
||||
bool hdcp_cap, hdcp2_cap;
|
||||
|
||||
@ -197,8 +198,14 @@ static void intel_hdcp_info(struct seq_file *m,
|
||||
goto out;
|
||||
}
|
||||
|
||||
hdcp_cap = intel_hdcp_capable(intel_connector);
|
||||
hdcp2_cap = intel_hdcp2_capable(intel_connector);
|
||||
if (remote_req) {
|
||||
intel_hdcp_get_remote_capability(intel_connector,
|
||||
&hdcp_cap,
|
||||
&hdcp2_cap);
|
||||
} else {
|
||||
hdcp_cap = intel_hdcp_get_capability(intel_connector);
|
||||
hdcp2_cap = intel_hdcp2_get_capability(intel_connector);
|
||||
}
|
||||
|
||||
if (hdcp_cap)
|
||||
seq_puts(m, "HDCP1.4 ");
|
||||
@ -285,7 +292,11 @@ static void intel_connector_info(struct seq_file *m,
|
||||
}
|
||||
|
||||
seq_puts(m, "\tHDCP version: ");
|
||||
intel_hdcp_info(m, intel_connector);
|
||||
if (intel_encoder_is_mst(encoder)) {
|
||||
intel_hdcp_info(m, intel_connector, true);
|
||||
seq_puts(m, "\tMST Hub HDCP version: ");
|
||||
}
|
||||
intel_hdcp_info(m, intel_connector, false);
|
||||
|
||||
seq_printf(m, "\tmax bpc: %u\n", connector->display_info.bpc);
|
||||
|
||||
@ -1131,7 +1142,7 @@ static int i915_hdcp_sink_capability_show(struct seq_file *m, void *data)
|
||||
|
||||
seq_printf(m, "%s:%d HDCP version: ", connector->base.name,
|
||||
connector->base.base.id);
|
||||
intel_hdcp_info(m, connector);
|
||||
intel_hdcp_info(m, connector, false);
|
||||
|
||||
out:
|
||||
drm_modeset_unlock(&i915->drm.mode_config.connection_mutex);
|
||||
@ -1391,6 +1402,20 @@ out: drm_modeset_unlock(&i915->drm.mode_config.connection_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int i915_bigjoiner_enable_show(struct seq_file *m, void *data)
|
||||
{
|
||||
struct intel_connector *connector = m->private;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
crtc = connector->base.state->crtc;
|
||||
if (connector->base.status != connector_status_connected || !crtc)
|
||||
return -ENODEV;
|
||||
|
||||
seq_printf(m, "Bigjoiner enable: %d\n", connector->force_bigjoiner_enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t i915_dsc_output_format_write(struct file *file,
|
||||
const char __user *ubuf,
|
||||
size_t len, loff_t *offp)
|
||||
@ -1412,6 +1437,30 @@ static ssize_t i915_dsc_output_format_write(struct file *file,
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t i915_bigjoiner_enable_write(struct file *file,
|
||||
const char __user *ubuf,
|
||||
size_t len, loff_t *offp)
|
||||
{
|
||||
struct seq_file *m = file->private_data;
|
||||
struct intel_connector *connector = m->private;
|
||||
struct drm_crtc *crtc;
|
||||
bool bigjoiner_en = 0;
|
||||
int ret;
|
||||
|
||||
crtc = connector->base.state->crtc;
|
||||
if (connector->base.status != connector_status_connected || !crtc)
|
||||
return -ENODEV;
|
||||
|
||||
ret = kstrtobool_from_user(ubuf, len, &bigjoiner_en);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
connector->force_bigjoiner_enable = bigjoiner_en;
|
||||
*offp += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int i915_dsc_output_format_open(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
@ -1505,6 +1554,8 @@ static const struct file_operations i915_dsc_fractional_bpp_fops = {
|
||||
.write = i915_dsc_fractional_bpp_write
|
||||
};
|
||||
|
||||
DEFINE_SHOW_STORE_ATTRIBUTE(i915_bigjoiner_enable);
|
||||
|
||||
/*
|
||||
* Returns the Current CRTC's bpc.
|
||||
* Example usage: cat /sys/kernel/debug/dri/0/crtc-0/i915_current_bpc
|
||||
@ -1586,6 +1637,13 @@ void intel_connector_debugfs_add(struct intel_connector *connector)
|
||||
connector, &i915_dsc_fractional_bpp_fops);
|
||||
}
|
||||
|
||||
if (DISPLAY_VER(i915) >= 11 &&
|
||||
(connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
|
||||
connector_type == DRM_MODE_CONNECTOR_eDP)) {
|
||||
debugfs_create_file("i915_bigjoiner_force_enable", 0644, root,
|
||||
connector, &i915_bigjoiner_enable_fops);
|
||||
}
|
||||
|
||||
if (connector_type == DRM_MODE_CONNECTOR_DSI ||
|
||||
connector_type == DRM_MODE_CONNECTOR_eDP ||
|
||||
connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "intel_dkl_phy.h"
|
||||
#include "intel_dmc.h"
|
||||
#include "intel_dp.h"
|
||||
#include "intel_dp_tunnel.h"
|
||||
#include "intel_dpll.h"
|
||||
#include "intel_dpll_mgr.h"
|
||||
#include "intel_fb.h"
|
||||
@ -434,10 +435,8 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915)
|
||||
|
||||
for_each_pipe(i915, pipe) {
|
||||
ret = intel_crtc_init(i915, pipe);
|
||||
if (ret) {
|
||||
intel_mode_config_cleanup(i915);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto err_mode_config;
|
||||
}
|
||||
|
||||
intel_plane_possible_crtcs_init(i915);
|
||||
@ -457,6 +456,10 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915)
|
||||
intel_vga_disable(i915);
|
||||
intel_setup_outputs(i915);
|
||||
|
||||
ret = intel_dp_tunnel_mgr_init(i915);
|
||||
if (ret)
|
||||
goto err_hdcp;
|
||||
|
||||
intel_display_driver_disable_user_access(i915);
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
@ -475,6 +478,13 @@ int intel_display_driver_probe_nogem(struct drm_i915_private *i915)
|
||||
ilk_wm_sanitize(i915);
|
||||
|
||||
return 0;
|
||||
|
||||
err_hdcp:
|
||||
intel_hdcp_component_fini(i915);
|
||||
err_mode_config:
|
||||
intel_mode_config_cleanup(i915);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* part #3: call after gem init */
|
||||
@ -599,6 +609,8 @@ void intel_display_driver_remove_noirq(struct drm_i915_private *i915)
|
||||
|
||||
intel_mode_config_cleanup(i915);
|
||||
|
||||
intel_dp_tunnel_mgr_cleanup(i915);
|
||||
|
||||
intel_overlay_cleanup(i915);
|
||||
|
||||
intel_gmbus_teardown(i915);
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#include <drm/display/drm_dp_dual_mode_helper.h>
|
||||
#include <drm/display/drm_dp_mst_helper.h>
|
||||
#include <drm/display/drm_dp_tunnel.h>
|
||||
#include <drm/display/drm_dsc.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
@ -327,7 +328,6 @@ struct intel_vbt_panel_data {
|
||||
struct edp_power_seq pps;
|
||||
u8 drrs_msa_timing_delay;
|
||||
bool low_vswing;
|
||||
bool initialized;
|
||||
bool hobl;
|
||||
} edp;
|
||||
|
||||
@ -499,15 +499,15 @@ struct intel_hdcp_shim {
|
||||
struct intel_connector *connector);
|
||||
|
||||
/* Detects panel's hdcp capability. This is optional for HDMI. */
|
||||
int (*hdcp_capable)(struct intel_digital_port *dig_port,
|
||||
bool *hdcp_capable);
|
||||
int (*hdcp_get_capability)(struct intel_digital_port *dig_port,
|
||||
bool *hdcp_capable);
|
||||
|
||||
/* HDCP adaptation(DP/HDMI) required on the port */
|
||||
enum hdcp_wired_protocol protocol;
|
||||
|
||||
/* Detects whether sink is HDCP2.2 capable */
|
||||
int (*hdcp_2_2_capable)(struct intel_connector *connector,
|
||||
bool *capable);
|
||||
int (*hdcp_2_2_get_capability)(struct intel_connector *connector,
|
||||
bool *capable);
|
||||
|
||||
/* Write HDCP2.2 messages */
|
||||
int (*write_2_2_msg)(struct intel_connector *connector,
|
||||
@ -532,6 +532,10 @@ struct intel_hdcp_shim {
|
||||
/* HDCP2.2 Link Integrity Check */
|
||||
int (*check_2_2_link)(struct intel_digital_port *dig_port,
|
||||
struct intel_connector *connector);
|
||||
|
||||
/* HDCP remote sink cap */
|
||||
int (*get_remote_hdcp_capability)(struct intel_connector *connector,
|
||||
bool *hdcp_capable, bool *hdcp2_capable);
|
||||
};
|
||||
|
||||
struct intel_hdcp {
|
||||
@ -626,6 +630,8 @@ struct intel_connector {
|
||||
|
||||
struct intel_dp *mst_port;
|
||||
|
||||
bool force_bigjoiner_enable;
|
||||
|
||||
struct {
|
||||
struct drm_dp_aux *dsc_decompression_aux;
|
||||
u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE];
|
||||
@ -677,6 +683,8 @@ struct intel_atomic_state {
|
||||
|
||||
struct intel_shared_dpll_state shared_dpll[I915_NUM_PLLS];
|
||||
|
||||
struct intel_dp_tunnel_inherited_state *inherited_dp_tunnels;
|
||||
|
||||
/*
|
||||
* Current watermarks can't be trusted during hardware readout, so
|
||||
* don't bother calculating intermediate watermarks.
|
||||
@ -1374,6 +1382,9 @@ struct intel_crtc_state {
|
||||
struct drm_dsc_config config;
|
||||
} dsc;
|
||||
|
||||
/* DP tunnel used for BW allocation. */
|
||||
struct drm_dp_tunnel_ref dp_tunnel_ref;
|
||||
|
||||
/* HSW+ linetime watermarks */
|
||||
u16 linetime;
|
||||
u16 ips_linetime;
|
||||
@ -1784,6 +1795,9 @@ struct intel_dp {
|
||||
/* connector directly attached - won't be use for modeset in mst world */
|
||||
struct intel_connector *attached_connector;
|
||||
|
||||
struct drm_dp_tunnel *tunnel;
|
||||
bool tunnel_suspended:1;
|
||||
|
||||
/* mst connector list */
|
||||
struct intel_dp_mst_encoder *mst_encoders[I915_MAX_PIPES];
|
||||
struct drm_dp_mst_topology_mgr mst_mgr;
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include <drm/display/drm_dp_helper.h>
|
||||
#include <drm/display/drm_dp_tunnel.h>
|
||||
#include <drm/display/drm_dsc_helper.h>
|
||||
#include <drm/display/drm_hdmi_helper.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
@ -63,6 +64,7 @@
|
||||
#include "intel_dp_hdcp.h"
|
||||
#include "intel_dp_link_training.h"
|
||||
#include "intel_dp_mst.h"
|
||||
#include "intel_dp_tunnel.h"
|
||||
#include "intel_dpio_phy.h"
|
||||
#include "intel_dpll.h"
|
||||
#include "intel_fifo_underrun.h"
|
||||
@ -152,6 +154,22 @@ int intel_dp_link_symbol_clock(int rate)
|
||||
return DIV_ROUND_CLOSEST(rate * 10, intel_dp_link_symbol_size(rate));
|
||||
}
|
||||
|
||||
static int max_dprx_rate(struct intel_dp *intel_dp)
|
||||
{
|
||||
if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
|
||||
return drm_dp_tunnel_max_dprx_rate(intel_dp->tunnel);
|
||||
|
||||
return drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
|
||||
}
|
||||
|
||||
static int max_dprx_lane_count(struct intel_dp *intel_dp)
|
||||
{
|
||||
if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
|
||||
return drm_dp_tunnel_max_dprx_lane_count(intel_dp->tunnel);
|
||||
|
||||
return drm_dp_max_lane_count(intel_dp->dpcd);
|
||||
}
|
||||
|
||||
static void intel_dp_set_default_sink_rates(struct intel_dp *intel_dp)
|
||||
{
|
||||
intel_dp->sink_rates[0] = 162000;
|
||||
@ -180,7 +198,7 @@ static void intel_dp_set_dpcd_sink_rates(struct intel_dp *intel_dp)
|
||||
/*
|
||||
* Sink rates for 8b/10b.
|
||||
*/
|
||||
max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
|
||||
max_rate = max_dprx_rate(intel_dp);
|
||||
max_lttpr_rate = drm_dp_lttpr_max_link_rate(intel_dp->lttpr_common_caps);
|
||||
if (max_lttpr_rate)
|
||||
max_rate = min(max_rate, max_lttpr_rate);
|
||||
@ -259,7 +277,7 @@ static void intel_dp_set_max_sink_lane_count(struct intel_dp *intel_dp)
|
||||
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
|
||||
struct intel_encoder *encoder = &intel_dig_port->base;
|
||||
|
||||
intel_dp->max_sink_lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
|
||||
intel_dp->max_sink_lane_count = max_dprx_lane_count(intel_dp);
|
||||
|
||||
switch (intel_dp->max_sink_lane_count) {
|
||||
case 1:
|
||||
@ -309,7 +327,7 @@ static int intel_dp_common_rate(struct intel_dp *intel_dp, int index)
|
||||
}
|
||||
|
||||
/* Theoretical max between source and sink */
|
||||
static int intel_dp_max_common_rate(struct intel_dp *intel_dp)
|
||||
int intel_dp_max_common_rate(struct intel_dp *intel_dp)
|
||||
{
|
||||
return intel_dp_common_rate(intel_dp, intel_dp->num_common_rates - 1);
|
||||
}
|
||||
@ -326,7 +344,7 @@ static int intel_dp_max_source_lane_count(struct intel_digital_port *dig_port)
|
||||
}
|
||||
|
||||
/* Theoretical max between source and sink */
|
||||
static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
|
||||
int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||
int source_max = intel_dp_max_source_lane_count(dig_port);
|
||||
@ -383,50 +401,27 @@ int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16,
|
||||
1000000 * 16 * 8);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a link rate and lanes, get the data bandwidth.
|
||||
/**
|
||||
* intel_dp_max_link_data_rate: Calculate the maximum rate for the given link params
|
||||
* @intel_dp: Intel DP object
|
||||
* @max_dprx_rate: Maximum data rate of the DPRX
|
||||
* @max_dprx_lanes: Maximum lane count of the DPRX
|
||||
*
|
||||
* Data bandwidth is the actual payload rate, which depends on the data
|
||||
* bandwidth efficiency and the link rate.
|
||||
* Calculate the maximum data rate for the provided link parameters taking into
|
||||
* account any BW limitations by a DP tunnel attached to @intel_dp.
|
||||
*
|
||||
* For 8b/10b channel encoding, SST and non-FEC, the data bandwidth efficiency
|
||||
* is 80%. For example, for a 1.62 Gbps link, 1.62*10^9 bps * 0.80 * (1/8) =
|
||||
* 162000 kBps. With 8-bit symbols, we have 162000 kHz symbol clock. Just by
|
||||
* coincidence, the port clock in kHz matches the data bandwidth in kBps, and
|
||||
* they equal the link bit rate in Gbps multiplied by 100000. (Note that this no
|
||||
* longer holds for data bandwidth as soon as FEC or MST is taken into account!)
|
||||
*
|
||||
* For 128b/132b channel encoding, the data bandwidth efficiency is 96.71%. For
|
||||
* example, for a 10 Gbps link, 10*10^9 bps * 0.9671 * (1/8) = 1208875
|
||||
* kBps. With 32-bit symbols, we have 312500 kHz symbol clock. The value 1000000
|
||||
* does not match the symbol clock, the port clock (not even if you think in
|
||||
* terms of a byte clock), nor the data bandwidth. It only matches the link bit
|
||||
* rate in units of 10000 bps.
|
||||
* Returns the maximum data rate in kBps units.
|
||||
*/
|
||||
int
|
||||
intel_dp_max_data_rate(int max_link_rate, int max_lanes)
|
||||
int intel_dp_max_link_data_rate(struct intel_dp *intel_dp,
|
||||
int max_dprx_rate, int max_dprx_lanes)
|
||||
{
|
||||
int ch_coding_efficiency =
|
||||
drm_dp_bw_channel_coding_efficiency(drm_dp_is_uhbr_rate(max_link_rate));
|
||||
int max_link_rate_kbps = max_link_rate * 10;
|
||||
int max_rate = drm_dp_max_dprx_data_rate(max_dprx_rate, max_dprx_lanes);
|
||||
|
||||
/*
|
||||
* UHBR rates always use 128b/132b channel encoding, and have
|
||||
* 97.71% data bandwidth efficiency. Consider max_link_rate the
|
||||
* link bit rate in units of 10000 bps.
|
||||
*/
|
||||
/*
|
||||
* Lower than UHBR rates always use 8b/10b channel encoding, and have
|
||||
* 80% data bandwidth efficiency for SST non-FEC. However, this turns
|
||||
* out to be a nop by coincidence:
|
||||
*
|
||||
* int max_link_rate_kbps = max_link_rate * 10;
|
||||
* max_link_rate_kbps = DIV_ROUND_DOWN_ULL(max_link_rate_kbps * 8, 10);
|
||||
* max_link_rate = max_link_rate_kbps / 8;
|
||||
*/
|
||||
return DIV_ROUND_DOWN_ULL(mul_u32_u32(max_link_rate_kbps * max_lanes,
|
||||
ch_coding_efficiency),
|
||||
1000000 * 8);
|
||||
if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
|
||||
max_rate = min(max_rate,
|
||||
drm_dp_tunnel_available_bw(intel_dp->tunnel));
|
||||
|
||||
return max_rate;
|
||||
}
|
||||
|
||||
bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp)
|
||||
@ -658,7 +653,7 @@ static bool intel_dp_can_link_train_fallback_for_edp(struct intel_dp *intel_dp,
|
||||
int mode_rate, max_rate;
|
||||
|
||||
mode_rate = intel_dp_link_required(fixed_mode->clock, 18);
|
||||
max_rate = intel_dp_max_data_rate(link_rate, lane_count);
|
||||
max_rate = intel_dp_max_link_data_rate(intel_dp, link_rate, lane_count);
|
||||
if (mode_rate > max_rate)
|
||||
return false;
|
||||
|
||||
@ -1205,11 +1200,13 @@ bool intel_dp_need_bigjoiner(struct intel_dp *intel_dp,
|
||||
int hdisplay, int clock)
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
struct intel_connector *connector = intel_dp->attached_connector;
|
||||
|
||||
if (!intel_dp_can_bigjoiner(intel_dp))
|
||||
return false;
|
||||
|
||||
return clock > i915->max_dotclk_freq || hdisplay > 5120;
|
||||
return clock > i915->max_dotclk_freq || hdisplay > 5120 ||
|
||||
connector->force_bigjoiner_enable;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
@ -1260,7 +1257,8 @@ intel_dp_mode_valid(struct drm_connector *_connector,
|
||||
max_link_clock = intel_dp_max_link_rate(intel_dp);
|
||||
max_lanes = intel_dp_max_lane_count(intel_dp);
|
||||
|
||||
max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
|
||||
max_rate = intel_dp_max_link_data_rate(intel_dp, max_link_clock, max_lanes);
|
||||
|
||||
mode_rate = intel_dp_link_required(target_clock,
|
||||
intel_dp_mode_min_output_bpp(connector, mode));
|
||||
|
||||
@ -1610,8 +1608,10 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
|
||||
for (lane_count = limits->min_lane_count;
|
||||
lane_count <= limits->max_lane_count;
|
||||
lane_count <<= 1) {
|
||||
link_avail = intel_dp_max_data_rate(link_rate,
|
||||
lane_count);
|
||||
link_avail = intel_dp_max_link_data_rate(intel_dp,
|
||||
link_rate,
|
||||
lane_count);
|
||||
|
||||
|
||||
if (mode_rate <= link_avail) {
|
||||
pipe_config->lane_count = lane_count;
|
||||
@ -2387,6 +2387,17 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
|
||||
limits);
|
||||
}
|
||||
|
||||
int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
const struct drm_display_mode *adjusted_mode =
|
||||
&crtc_state->hw.adjusted_mode;
|
||||
int bpp = crtc_state->dsc.compression_enable ?
|
||||
to_bpp_int_roundup(crtc_state->dsc.compressed_bpp_x16) :
|
||||
crtc_state->pipe_bpp;
|
||||
|
||||
return intel_dp_link_required(adjusted_mode->crtc_clock, bpp);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_dp_compute_link_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
@ -2454,31 +2465,16 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pipe_config->dsc.compression_enable) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"DP lane count %d clock %d Input bpp %d Compressed bpp " BPP_X16_FMT "\n",
|
||||
pipe_config->lane_count, pipe_config->port_clock,
|
||||
pipe_config->pipe_bpp,
|
||||
BPP_X16_ARGS(pipe_config->dsc.compressed_bpp_x16));
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"DP lane count %d clock %d bpp input %d compressed " BPP_X16_FMT " link rate required %d available %d\n",
|
||||
pipe_config->lane_count, pipe_config->port_clock,
|
||||
pipe_config->pipe_bpp,
|
||||
BPP_X16_ARGS(pipe_config->dsc.compressed_bpp_x16),
|
||||
intel_dp_config_required_rate(pipe_config),
|
||||
intel_dp_max_link_data_rate(intel_dp,
|
||||
pipe_config->port_clock,
|
||||
pipe_config->lane_count));
|
||||
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"DP link rate required %i available %i\n",
|
||||
intel_dp_link_required(adjusted_mode->crtc_clock,
|
||||
to_bpp_int_roundup(pipe_config->dsc.compressed_bpp_x16)),
|
||||
intel_dp_max_data_rate(pipe_config->port_clock,
|
||||
pipe_config->lane_count));
|
||||
} else {
|
||||
drm_dbg_kms(&i915->drm, "DP lane count %d clock %d bpp %d\n",
|
||||
pipe_config->lane_count, pipe_config->port_clock,
|
||||
pipe_config->pipe_bpp);
|
||||
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"DP link rate required %i available %i\n",
|
||||
intel_dp_link_required(adjusted_mode->crtc_clock,
|
||||
pipe_config->pipe_bpp),
|
||||
intel_dp_max_data_rate(pipe_config->port_clock,
|
||||
pipe_config->lane_count));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2840,12 +2836,47 @@ intel_dp_audio_compute_config(struct intel_encoder *encoder,
|
||||
intel_dp_is_uhbr(pipe_config);
|
||||
}
|
||||
|
||||
void intel_dp_queue_modeset_retry_work(struct intel_connector *connector)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||
|
||||
drm_connector_get(&connector->base);
|
||||
if (!queue_work(i915->unordered_wq, &connector->modeset_retry_work))
|
||||
drm_connector_put(&connector->base);
|
||||
}
|
||||
|
||||
void
|
||||
intel_dp_queue_modeset_retry_for_link(struct intel_atomic_state *state,
|
||||
struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_connector *connector;
|
||||
struct intel_digital_connector_state *conn_state;
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
int i;
|
||||
|
||||
if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) {
|
||||
intel_dp_queue_modeset_retry_work(intel_dp->attached_connector);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for_each_new_intel_connector_in_state(state, connector, conn_state, i) {
|
||||
if (!conn_state->base.crtc)
|
||||
continue;
|
||||
|
||||
if (connector->mst_port == intel_dp)
|
||||
intel_dp_queue_modeset_retry_work(connector);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
intel_dp_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state);
|
||||
struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
const struct drm_display_mode *fixed_mode;
|
||||
@ -2946,7 +2977,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
|
||||
intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state);
|
||||
intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state);
|
||||
|
||||
return 0;
|
||||
return intel_dp_tunnel_atomic_compute_stream_bw(state, intel_dp, connector,
|
||||
pipe_config);
|
||||
}
|
||||
|
||||
void intel_dp_set_link_params(struct intel_dp *intel_dp,
|
||||
@ -3282,18 +3314,21 @@ void intel_dp_sync_state(struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
|
||||
if (!crtc_state)
|
||||
return;
|
||||
bool dpcd_updated = false;
|
||||
|
||||
/*
|
||||
* Don't clobber DPCD if it's been already read out during output
|
||||
* setup (eDP) or detect.
|
||||
*/
|
||||
if (intel_dp->dpcd[DP_DPCD_REV] == 0)
|
||||
if (crtc_state && intel_dp->dpcd[DP_DPCD_REV] == 0) {
|
||||
intel_dp_get_dpcd(intel_dp);
|
||||
dpcd_updated = true;
|
||||
}
|
||||
|
||||
intel_dp_reset_max_link_params(intel_dp);
|
||||
intel_dp_tunnel_resume(intel_dp, crtc_state, dpcd_updated);
|
||||
|
||||
if (crtc_state)
|
||||
intel_dp_reset_max_link_params(intel_dp);
|
||||
}
|
||||
|
||||
bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
|
||||
@ -3959,6 +3994,13 @@ intel_dp_has_sink_count(struct intel_dp *intel_dp)
|
||||
&intel_dp->desc);
|
||||
}
|
||||
|
||||
void intel_dp_update_sink_caps(struct intel_dp *intel_dp)
|
||||
{
|
||||
intel_dp_set_sink_rates(intel_dp);
|
||||
intel_dp_set_max_sink_lane_count(intel_dp);
|
||||
intel_dp_set_common_rates(intel_dp);
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_dp_get_dpcd(struct intel_dp *intel_dp)
|
||||
{
|
||||
@ -3975,9 +4017,7 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
|
||||
drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
|
||||
drm_dp_is_branch(intel_dp->dpcd));
|
||||
|
||||
intel_dp_set_sink_rates(intel_dp);
|
||||
intel_dp_set_max_sink_lane_count(intel_dp);
|
||||
intel_dp_set_common_rates(intel_dp);
|
||||
intel_dp_update_sink_caps(intel_dp);
|
||||
}
|
||||
|
||||
if (intel_dp_has_sink_count(intel_dp)) {
|
||||
@ -4868,13 +4908,15 @@ static bool intel_dp_mst_link_status(struct intel_dp *intel_dp)
|
||||
* - %true if pending interrupts were serviced (or no interrupts were
|
||||
* pending) w/o detecting an error condition.
|
||||
* - %false if an error condition - like AUX failure or a loss of link - is
|
||||
* detected, which needs servicing from the hotplug work.
|
||||
* detected, or another condition - like a DP tunnel BW state change - needs
|
||||
* servicing from the hotplug work.
|
||||
*/
|
||||
static bool
|
||||
intel_dp_check_mst_status(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
bool link_ok = true;
|
||||
bool reprobe_needed = false;
|
||||
|
||||
drm_WARN_ON_ONCE(&i915->drm, intel_dp->active_mst_links < 0);
|
||||
|
||||
@ -4901,6 +4943,13 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
|
||||
|
||||
intel_dp_mst_hpd_irq(intel_dp, esi, ack);
|
||||
|
||||
if (esi[3] & DP_TUNNELING_IRQ) {
|
||||
if (drm_dp_tunnel_handle_irq(i915->display.dp_tunnel_mgr,
|
||||
&intel_dp->aux))
|
||||
reprobe_needed = true;
|
||||
ack[3] |= DP_TUNNELING_IRQ;
|
||||
}
|
||||
|
||||
if (!memchr_inv(ack, 0, sizeof(ack)))
|
||||
break;
|
||||
|
||||
@ -4911,7 +4960,7 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
|
||||
drm_dp_mst_hpd_irq_send_new_request(&intel_dp->mst_mgr);
|
||||
}
|
||||
|
||||
return link_ok;
|
||||
return link_ok && !reprobe_needed;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -5038,9 +5087,10 @@ int intel_dp_get_active_pipes(struct intel_dp *intel_dp,
|
||||
if (!crtc_state->hw.active)
|
||||
continue;
|
||||
|
||||
if (conn_state->commit &&
|
||||
!try_wait_for_completion(&conn_state->commit->hw_done))
|
||||
continue;
|
||||
if (conn_state->commit)
|
||||
drm_WARN_ON(&i915->drm,
|
||||
!wait_for_completion_timeout(&conn_state->commit->hw_done,
|
||||
msecs_to_jiffies(5000)));
|
||||
|
||||
*pipe_mask |= BIT(crtc->pipe);
|
||||
}
|
||||
@ -5270,23 +5320,32 @@ static void intel_dp_check_device_service_irq(struct intel_dp *intel_dp)
|
||||
drm_dbg_kms(&i915->drm, "Sink specific irq unhandled\n");
|
||||
}
|
||||
|
||||
static void intel_dp_check_link_service_irq(struct intel_dp *intel_dp)
|
||||
static bool intel_dp_check_link_service_irq(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
bool reprobe_needed = false;
|
||||
u8 val;
|
||||
|
||||
if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (drm_dp_dpcd_readb(&intel_dp->aux,
|
||||
DP_LINK_SERVICE_IRQ_VECTOR_ESI0, &val) != 1 || !val)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if ((val & DP_TUNNELING_IRQ) &&
|
||||
drm_dp_tunnel_handle_irq(i915->display.dp_tunnel_mgr,
|
||||
&intel_dp->aux))
|
||||
reprobe_needed = true;
|
||||
|
||||
if (drm_dp_dpcd_writeb(&intel_dp->aux,
|
||||
DP_LINK_SERVICE_IRQ_VECTOR_ESI0, val) != 1)
|
||||
return;
|
||||
return reprobe_needed;
|
||||
|
||||
if (val & HDMI_LINK_STATUS_CHANGED)
|
||||
intel_dp_handle_hdmi_link_status_change(intel_dp);
|
||||
|
||||
return reprobe_needed;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5307,6 +5366,7 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
|
||||
u8 old_sink_count = intel_dp->sink_count;
|
||||
bool reprobe_needed = false;
|
||||
bool ret;
|
||||
|
||||
/*
|
||||
@ -5329,7 +5389,7 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
|
||||
}
|
||||
|
||||
intel_dp_check_device_service_irq(intel_dp);
|
||||
intel_dp_check_link_service_irq(intel_dp);
|
||||
reprobe_needed = intel_dp_check_link_service_irq(intel_dp);
|
||||
|
||||
/* Handle CEC interrupts, if any */
|
||||
drm_dp_cec_irq(&intel_dp->aux);
|
||||
@ -5356,10 +5416,10 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
|
||||
* FIXME get rid of the ad-hoc phy test modeset code
|
||||
* and properly incorporate it into the normal modeset.
|
||||
*/
|
||||
return false;
|
||||
reprobe_needed = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return !reprobe_needed;
|
||||
}
|
||||
|
||||
/* XXX this is probably wrong for multiple downstream ports */
|
||||
@ -5669,6 +5729,7 @@ intel_dp_detect(struct drm_connector *connector,
|
||||
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||
struct intel_encoder *encoder = &dig_port->base;
|
||||
enum drm_connector_status status;
|
||||
int ret;
|
||||
|
||||
drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n",
|
||||
connector->base.id, connector->name);
|
||||
@ -5704,9 +5765,18 @@ intel_dp_detect(struct drm_connector *connector,
|
||||
intel_dp->is_mst);
|
||||
}
|
||||
|
||||
intel_dp_tunnel_disconnect(intel_dp);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = intel_dp_tunnel_detect(intel_dp, ctx);
|
||||
if (ret == -EDEADLK)
|
||||
return ret;
|
||||
|
||||
if (ret == 1)
|
||||
intel_connector->base.epoch_counter++;
|
||||
|
||||
intel_dp_detect_dsc_caps(intel_dp, intel_connector);
|
||||
|
||||
intel_dp_configure_mst(intel_dp);
|
||||
@ -5737,8 +5807,6 @@ intel_dp_detect(struct drm_connector *connector,
|
||||
* with an IRQ_HPD, so force a link status check.
|
||||
*/
|
||||
if (!intel_dp_is_edp(intel_dp)) {
|
||||
int ret;
|
||||
|
||||
ret = intel_dp_retrain_link(encoder, ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -5878,6 +5946,8 @@ void intel_dp_encoder_flush_work(struct drm_encoder *encoder)
|
||||
|
||||
intel_dp_mst_encoder_cleanup(dig_port);
|
||||
|
||||
intel_dp_tunnel_destroy(intel_dp);
|
||||
|
||||
intel_pps_vdd_off_sync(intel_dp);
|
||||
|
||||
/*
|
||||
@ -5894,6 +5964,8 @@ void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(intel_encoder);
|
||||
|
||||
intel_pps_vdd_off_sync(intel_dp);
|
||||
|
||||
intel_dp_tunnel_suspend(intel_dp);
|
||||
}
|
||||
|
||||
void intel_dp_encoder_shutdown(struct intel_encoder *intel_encoder)
|
||||
@ -6031,6 +6103,15 @@ static int intel_dp_connector_atomic_check(struct drm_connector *conn,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!intel_connector_needs_modeset(state, conn))
|
||||
return 0;
|
||||
|
||||
ret = intel_dp_tunnel_atomic_check_state(state,
|
||||
intel_dp,
|
||||
intel_conn);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* We don't enable port sync on BDW due to missing w/as and
|
||||
* due to not having adjusted the modeset sequence appropriately.
|
||||
@ -6038,9 +6119,6 @@ static int intel_dp_connector_atomic_check(struct drm_connector *conn,
|
||||
if (DISPLAY_VER(dev_priv) < 9)
|
||||
return 0;
|
||||
|
||||
if (!intel_connector_needs_modeset(state, conn))
|
||||
return 0;
|
||||
|
||||
if (conn->has_tile) {
|
||||
ret = intel_modeset_tile_group(state, conn->tile_group->id);
|
||||
if (ret)
|
||||
@ -6097,6 +6175,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *dig_port, bool long_hpd)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
struct intel_dp *intel_dp = &dig_port->dp;
|
||||
u8 dpcd[DP_RECEIVER_CAP_SIZE];
|
||||
|
||||
if (dig_port->base.type == INTEL_OUTPUT_EDP &&
|
||||
(long_hpd || !intel_pps_have_panel_power_or_vdd(intel_dp))) {
|
||||
@ -6119,6 +6198,17 @@ intel_dp_hpd_pulse(struct intel_digital_port *dig_port, bool long_hpd)
|
||||
dig_port->base.base.name,
|
||||
long_hpd ? "long" : "short");
|
||||
|
||||
/*
|
||||
* TBT DP tunnels require the GFX driver to read out the DPRX caps in
|
||||
* response to long HPD pulses. The DP hotplug handler does that,
|
||||
* however the hotplug handler may be blocked by another
|
||||
* connector's/encoder's hotplug handler. Since the TBT CM may not
|
||||
* complete the DP tunnel BW request for the latter connector/encoder
|
||||
* waiting for this encoder's DPRX read, perform a dummy read here.
|
||||
*/
|
||||
if (long_hpd)
|
||||
intel_dp_read_dprx_caps(intel_dp, dpcd);
|
||||
|
||||
if (long_hpd) {
|
||||
intel_dp->reset_link_params = true;
|
||||
return IRQ_NONE;
|
||||
@ -6439,6 +6529,14 @@ static void intel_dp_modeset_retry_work_fn(struct work_struct *work)
|
||||
mutex_unlock(&connector->dev->mode_config.mutex);
|
||||
/* Send Hotplug uevent so userspace can reprobe */
|
||||
drm_kms_helper_connector_hotplug_event(connector);
|
||||
|
||||
drm_connector_put(connector);
|
||||
}
|
||||
|
||||
void intel_dp_init_modeset_retry_work(struct intel_connector *connector)
|
||||
{
|
||||
INIT_WORK(&connector->modeset_retry_work,
|
||||
intel_dp_modeset_retry_work_fn);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -6455,8 +6553,7 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
|
||||
int type;
|
||||
|
||||
/* Initialize the work for modeset in case of link train failure */
|
||||
INIT_WORK(&intel_connector->modeset_retry_work,
|
||||
intel_dp_modeset_retry_work_fn);
|
||||
intel_dp_init_modeset_retry_work(intel_connector);
|
||||
|
||||
if (drm_WARN(dev, dig_port->max_lanes < 1,
|
||||
"Not enough lanes (%d) for DP on [ENCODER:%d:%s]\n",
|
||||
|
@ -43,6 +43,12 @@ void intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
|
||||
bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state,
|
||||
const struct drm_connector_state *conn_state);
|
||||
int intel_dp_min_bpp(enum intel_output_format output_format);
|
||||
void intel_dp_init_modeset_retry_work(struct intel_connector *connector);
|
||||
void intel_dp_queue_modeset_retry_work(struct intel_connector *connector);
|
||||
void
|
||||
intel_dp_queue_modeset_retry_for_link(struct intel_atomic_state *state,
|
||||
struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *crtc_state);
|
||||
bool intel_dp_init_connector(struct intel_digital_port *dig_port,
|
||||
struct intel_connector *intel_connector);
|
||||
void intel_dp_set_link_params(struct intel_dp *intel_dp,
|
||||
@ -94,7 +100,11 @@ void intel_dp_mst_suspend(struct drm_i915_private *dev_priv);
|
||||
void intel_dp_mst_resume(struct drm_i915_private *dev_priv);
|
||||
int intel_dp_max_link_rate(struct intel_dp *intel_dp);
|
||||
int intel_dp_max_lane_count(struct intel_dp *intel_dp);
|
||||
int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state);
|
||||
int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
|
||||
int intel_dp_max_common_rate(struct intel_dp *intel_dp);
|
||||
int intel_dp_max_common_lane_count(struct intel_dp *intel_dp);
|
||||
void intel_dp_update_sink_caps(struct intel_dp *intel_dp);
|
||||
|
||||
void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
|
||||
u8 *link_bw, u8 *rate_select);
|
||||
@ -105,7 +115,8 @@ bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp);
|
||||
int intel_dp_link_required(int pixel_clock, int bpp);
|
||||
int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16,
|
||||
int bw_overhead);
|
||||
int intel_dp_max_data_rate(int max_link_rate, int max_lanes);
|
||||
int intel_dp_max_link_data_rate(struct intel_dp *intel_dp,
|
||||
int max_dprx_rate, int max_dprx_lanes);
|
||||
bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp);
|
||||
bool intel_dp_needs_vsc_sdp(const struct intel_crtc_state *crtc_state,
|
||||
const struct drm_connector_state *conn_state);
|
||||
|
@ -36,8 +36,10 @@ static u32 transcoder_to_stream_enc_status(enum transcoder cpu_transcoder)
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout)
|
||||
static void intel_dp_hdcp_wait_for_cp_irq(struct intel_connector *connector,
|
||||
int timeout)
|
||||
{
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
long ret;
|
||||
|
||||
#define C (hdcp->cp_irq_count_cached != atomic_read(&hdcp->cp_irq_count))
|
||||
@ -45,7 +47,8 @@ static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout)
|
||||
msecs_to_jiffies(timeout));
|
||||
|
||||
if (!ret)
|
||||
DRM_DEBUG_KMS("Timedout at waiting for CP_IRQ\n");
|
||||
drm_dbg_kms(connector->base.dev,
|
||||
"Timedout at waiting for CP_IRQ\n");
|
||||
}
|
||||
|
||||
static
|
||||
@ -122,13 +125,13 @@ static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *dig_port,
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp_read_bcaps(struct intel_digital_port *dig_port,
|
||||
int intel_dp_hdcp_read_bcaps(struct drm_dp_aux *aux,
|
||||
struct drm_i915_private *i915,
|
||||
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,
|
||||
ret = drm_dp_dpcd_read(aux, DP_AUX_HDCP_BCAPS,
|
||||
bcaps, 1);
|
||||
if (ret != 1) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
@ -143,10 +146,11 @@ static
|
||||
int intel_dp_hdcp_repeater_present(struct intel_digital_port *dig_port,
|
||||
bool *repeater_present)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
ssize_t ret;
|
||||
u8 bcaps;
|
||||
|
||||
ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
|
||||
ret = intel_dp_hdcp_read_bcaps(&dig_port->dp.aux, i915, &bcaps);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -265,13 +269,14 @@ bool intel_dp_hdcp_check_link(struct intel_digital_port *dig_port,
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp_capable(struct intel_digital_port *dig_port,
|
||||
bool *hdcp_capable)
|
||||
int intel_dp_hdcp_get_capability(struct intel_digital_port *dig_port,
|
||||
bool *hdcp_capable)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
ssize_t ret;
|
||||
u8 bcaps;
|
||||
|
||||
ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
|
||||
ret = intel_dp_hdcp_read_bcaps(&dig_port->dp.aux, i915, &bcaps);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -330,23 +335,13 @@ static const struct hdcp2_dp_msg_data hdcp2_dp_msg_data[] = {
|
||||
0, 0 },
|
||||
};
|
||||
|
||||
static struct drm_dp_aux *
|
||||
intel_dp_hdcp_get_aux(struct intel_connector *connector)
|
||||
{
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
|
||||
if (intel_encoder_is_mst(connector->encoder))
|
||||
return &connector->port->aux;
|
||||
else
|
||||
return &dig_port->dp.aux;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_dp_hdcp2_read_rx_status(struct intel_connector *connector,
|
||||
u8 *rx_status)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||
struct drm_dp_aux *aux = intel_dp_hdcp_get_aux(connector);
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
struct drm_dp_aux *aux = &dig_port->dp.aux;
|
||||
ssize_t ret;
|
||||
|
||||
ret = drm_dp_dpcd_read(aux,
|
||||
@ -387,7 +382,8 @@ int hdcp2_detect_msg_availability(struct intel_connector *connector,
|
||||
*msg_ready = true;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Unidentified msg_id: %d\n", msg_id);
|
||||
drm_err(connector->base.dev,
|
||||
"Unidentified msg_id: %d\n", msg_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -399,7 +395,9 @@ intel_dp_hdcp2_wait_for_msg(struct intel_connector *connector,
|
||||
const struct hdcp2_dp_msg_data *hdcp2_msg_data)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
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;
|
||||
@ -421,7 +419,7 @@ intel_dp_hdcp2_wait_for_msg(struct intel_connector *connector,
|
||||
* 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);
|
||||
intel_dp_hdcp_wait_for_cp_irq(connector, timeout);
|
||||
ret = hdcp2_detect_msg_availability(connector, msg_id,
|
||||
&msg_ready);
|
||||
if (!msg_ready)
|
||||
@ -454,8 +452,9 @@ int intel_dp_hdcp2_write_msg(struct intel_connector *connector,
|
||||
unsigned int offset;
|
||||
u8 *byte = buf;
|
||||
ssize_t ret, bytes_to_write, len;
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
struct drm_dp_aux *aux = &dig_port->dp.aux;
|
||||
const struct hdcp2_dp_msg_data *hdcp2_msg_data;
|
||||
struct drm_dp_aux *aux;
|
||||
|
||||
hdcp2_msg_data = get_hdcp2_dp_msg_data(*byte);
|
||||
if (!hdcp2_msg_data)
|
||||
@ -463,8 +462,6 @@ int intel_dp_hdcp2_write_msg(struct intel_connector *connector,
|
||||
|
||||
offset = hdcp2_msg_data->offset;
|
||||
|
||||
aux = intel_dp_hdcp_get_aux(connector);
|
||||
|
||||
/* No msg_id in DP HDCP2.2 msgs */
|
||||
bytes_to_write = size - 1;
|
||||
byte++;
|
||||
@ -490,7 +487,8 @@ static
|
||||
ssize_t get_receiver_id_list_rx_info(struct intel_connector *connector,
|
||||
u32 *dev_cnt, u8 *byte)
|
||||
{
|
||||
struct drm_dp_aux *aux = intel_dp_hdcp_get_aux(connector);
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
struct drm_dp_aux *aux = &dig_port->dp.aux;
|
||||
ssize_t ret;
|
||||
u8 *rx_info = byte;
|
||||
|
||||
@ -515,8 +513,9 @@ int intel_dp_hdcp2_read_msg(struct intel_connector *connector,
|
||||
{
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
struct drm_dp_aux *aux;
|
||||
struct drm_dp_aux *aux = &dig_port->dp.aux;
|
||||
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_recv, len;
|
||||
@ -530,8 +529,6 @@ int intel_dp_hdcp2_read_msg(struct intel_connector *connector,
|
||||
return -EINVAL;
|
||||
offset = hdcp2_msg_data->offset;
|
||||
|
||||
aux = intel_dp_hdcp_get_aux(connector);
|
||||
|
||||
ret = intel_dp_hdcp2_wait_for_msg(connector, hdcp2_msg_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -561,13 +558,8 @@ int intel_dp_hdcp2_read_msg(struct intel_connector *connector,
|
||||
|
||||
/* Entire msg read timeout since initiate of msg read */
|
||||
if (bytes_to_recv == size - 1 && hdcp2_msg_data->msg_read_timeout > 0) {
|
||||
if (intel_encoder_is_mst(connector->encoder))
|
||||
msg_end = ktime_add_ms(ktime_get_raw(),
|
||||
hdcp2_msg_data->msg_read_timeout *
|
||||
connector->port->parent->num_ports);
|
||||
else
|
||||
msg_end = ktime_add_ms(ktime_get_raw(),
|
||||
hdcp2_msg_data->msg_read_timeout);
|
||||
msg_end = ktime_add_ms(ktime_get_raw(),
|
||||
hdcp2_msg_data->msg_read_timeout);
|
||||
}
|
||||
|
||||
ret = drm_dp_dpcd_read(aux, offset,
|
||||
@ -648,25 +640,69 @@ int intel_dp_hdcp2_check_link(struct intel_digital_port *dig_port,
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp2_capable(struct intel_connector *connector,
|
||||
bool *capable)
|
||||
int _intel_dp_hdcp2_get_capability(struct drm_dp_aux *aux,
|
||||
bool *capable)
|
||||
{
|
||||
struct drm_dp_aux *aux;
|
||||
u8 rx_caps[3];
|
||||
int ret;
|
||||
|
||||
aux = intel_dp_hdcp_get_aux(connector);
|
||||
int ret, i;
|
||||
|
||||
*capable = false;
|
||||
ret = drm_dp_dpcd_read(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;
|
||||
/*
|
||||
* Some HDCP monitors act really shady by not giving the correct hdcp
|
||||
* capability on the first rx_caps read and usually take an extra read
|
||||
* to give the capability. We read rx_caps three times before we
|
||||
* declare a monitor not capable of HDCP 2.2.
|
||||
*/
|
||||
for (i = 0; i < 3; i++) {
|
||||
ret = drm_dp_dpcd_read(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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp2_get_capability(struct intel_connector *connector,
|
||||
bool *capable)
|
||||
{
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
struct drm_dp_aux *aux = &dig_port->dp.aux;
|
||||
|
||||
return _intel_dp_hdcp2_get_capability(aux, capable);
|
||||
}
|
||||
|
||||
static
|
||||
int intel_dp_hdcp_get_remote_capability(struct intel_connector *connector,
|
||||
bool *hdcp_capable,
|
||||
bool *hdcp2_capable)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||
struct drm_dp_aux *aux = &connector->port->aux;
|
||||
u8 bcaps;
|
||||
int ret;
|
||||
|
||||
if (!intel_encoder_is_mst(connector->encoder))
|
||||
return -EINVAL;
|
||||
|
||||
ret = _intel_dp_hdcp2_get_capability(aux, hdcp2_capable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = intel_dp_hdcp_read_bcaps(aux, i915, &bcaps);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*hdcp_capable = bcaps & DP_BCAPS_HDCP_CAPABLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -682,12 +718,12 @@ static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
|
||||
.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,
|
||||
.hdcp_get_capability = intel_dp_hdcp_get_capability,
|
||||
.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,
|
||||
.hdcp_2_2_get_capability = intel_dp_hdcp2_get_capability,
|
||||
.protocol = HDCP_PROTOCOL_DP,
|
||||
};
|
||||
|
||||
@ -812,13 +848,14 @@ static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
|
||||
.toggle_signalling = intel_dp_hdcp_toggle_signalling,
|
||||
.stream_encryption = intel_dp_mst_hdcp_stream_encryption,
|
||||
.check_link = intel_dp_hdcp_check_link,
|
||||
.hdcp_capable = intel_dp_hdcp_capable,
|
||||
.hdcp_get_capability = intel_dp_hdcp_get_capability,
|
||||
.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,
|
||||
.stream_2_2_encryption = intel_dp_mst_hdcp2_stream_encryption,
|
||||
.check_2_2_link = intel_dp_mst_hdcp2_check_link,
|
||||
.hdcp_2_2_capable = intel_dp_hdcp2_capable,
|
||||
.hdcp_2_2_get_capability = intel_dp_hdcp2_get_capability,
|
||||
.get_remote_hdcp_capability = intel_dp_hdcp_get_remote_capability,
|
||||
.protocol = HDCP_PROTOCOL_DP,
|
||||
};
|
||||
|
||||
|
@ -162,6 +162,28 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEI
|
||||
return lttpr_count;
|
||||
}
|
||||
|
||||
int intel_dp_read_dprx_caps(struct intel_dp *intel_dp, u8 dpcd[DP_RECEIVER_CAP_SIZE])
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
|
||||
if (intel_dp_is_edp(intel_dp))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Detecting LTTPRs must be avoided on platforms with an AUX timeout
|
||||
* period < 3.2ms. (see DP Standard v2.0, 2.11.2, 3.6.6.1).
|
||||
*/
|
||||
if (DISPLAY_VER(i915) >= 10 && !IS_GEMINILAKE(i915))
|
||||
if (drm_dp_dpcd_probe(&intel_dp->aux,
|
||||
DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV))
|
||||
return -EIO;
|
||||
|
||||
if (drm_dp_read_dpcd_caps(&intel_dp->aux, dpcd))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_init_lttpr_and_dprx_caps - detect LTTPR and DPRX caps, init the LTTPR link training mode
|
||||
* @intel_dp: Intel DP struct
|
||||
@ -192,12 +214,10 @@ int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp)
|
||||
if (!intel_dp_is_edp(intel_dp) &&
|
||||
(DISPLAY_VER(i915) >= 10 && !IS_GEMINILAKE(i915))) {
|
||||
u8 dpcd[DP_RECEIVER_CAP_SIZE];
|
||||
int err = intel_dp_read_dprx_caps(intel_dp, dpcd);
|
||||
|
||||
if (drm_dp_dpcd_probe(&intel_dp->aux, DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV))
|
||||
return -EIO;
|
||||
|
||||
if (drm_dp_read_dpcd_caps(&intel_dp->aux, dpcd))
|
||||
return -EIO;
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
lttpr_count = intel_dp_init_lttpr(intel_dp, dpcd);
|
||||
}
|
||||
@ -1075,7 +1095,6 @@ static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp,
|
||||
const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_connector *intel_connector = intel_dp->attached_connector;
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
|
||||
if (!intel_digital_port_connected(&dp_to_dig_port(intel_dp)->base)) {
|
||||
lt_dbg(intel_dp, DP_PHY_DPRX, "Link Training failed on disconnected sink.\n");
|
||||
@ -1093,7 +1112,7 @@ static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp,
|
||||
}
|
||||
|
||||
/* Schedule a Hotplug Uevent to userspace to start modeset */
|
||||
queue_work(i915->unordered_wq, &intel_connector->modeset_retry_work);
|
||||
intel_dp_queue_modeset_retry_work(intel_connector);
|
||||
}
|
||||
|
||||
/* Perform the link training on all LTTPRs and the DPRX on a link. */
|
||||
|
@ -11,6 +11,7 @@
|
||||
struct intel_crtc_state;
|
||||
struct intel_dp;
|
||||
|
||||
int intel_dp_read_dprx_caps(struct intel_dp *intel_dp, u8 dpcd[DP_RECEIVER_CAP_SIZE]);
|
||||
int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp);
|
||||
|
||||
void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "intel_dp.h"
|
||||
#include "intel_dp_hdcp.h"
|
||||
#include "intel_dp_mst.h"
|
||||
#include "intel_dp_tunnel.h"
|
||||
#include "intel_dpio_phy.h"
|
||||
#include "intel_hdcp.h"
|
||||
#include "intel_hotplug.h"
|
||||
@ -523,6 +524,7 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state);
|
||||
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
|
||||
struct intel_dp *intel_dp = &intel_mst->primary->dp;
|
||||
const struct intel_connector *connector =
|
||||
@ -619,7 +621,8 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
||||
|
||||
intel_psr_compute_config(intel_dp, pipe_config, conn_state);
|
||||
|
||||
return 0;
|
||||
return intel_dp_tunnel_atomic_compute_stream_bw(state, intel_dp, connector,
|
||||
pipe_config);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -876,6 +879,14 @@ intel_dp_mst_atomic_check(struct drm_connector *connector,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (intel_connector_needs_modeset(state, connector)) {
|
||||
ret = intel_dp_tunnel_atomic_check_state(state,
|
||||
intel_connector->mst_port,
|
||||
intel_connector);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return drm_dp_atomic_release_time_slots(&state->base,
|
||||
&intel_connector->mst_port->mst_mgr,
|
||||
intel_connector->port);
|
||||
@ -1197,6 +1208,7 @@ static bool intel_dp_mst_initial_fastset_check(struct intel_encoder *encoder,
|
||||
static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_connector *intel_connector = to_intel_connector(connector);
|
||||
struct drm_i915_private *i915 = to_i915(intel_connector->base.dev);
|
||||
struct intel_dp *intel_dp = intel_connector->mst_port;
|
||||
const struct drm_edid *drm_edid;
|
||||
int ret;
|
||||
@ -1204,6 +1216,9 @@ static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
|
||||
if (drm_connector_is_unregistered(connector))
|
||||
return intel_connector_update_modes(connector, NULL);
|
||||
|
||||
if (!intel_display_driver_check_access(i915))
|
||||
return drm_edid_connector_add_modes(connector);
|
||||
|
||||
drm_edid = drm_dp_mst_edid_read(connector, &intel_dp->mst_mgr, intel_connector->port);
|
||||
|
||||
ret = intel_connector_update_modes(connector, drm_edid);
|
||||
@ -1295,7 +1310,8 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector,
|
||||
max_link_clock = intel_dp_max_link_rate(intel_dp);
|
||||
max_lanes = intel_dp_max_lane_count(intel_dp);
|
||||
|
||||
max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
|
||||
max_rate = intel_dp_max_link_data_rate(intel_dp,
|
||||
max_link_clock, max_lanes);
|
||||
mode_rate = intel_dp_link_required(mode->clock, min_bpp);
|
||||
|
||||
ret = drm_modeset_lock(&mgr->base.lock, ctx);
|
||||
@ -1542,6 +1558,8 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
|
||||
intel_connector->port = port;
|
||||
drm_dp_mst_get_port_malloc(port);
|
||||
|
||||
intel_dp_init_modeset_retry_work(intel_connector);
|
||||
|
||||
intel_connector->dp.dsc_decompression_aux = drm_dp_mst_dsc_aux_for_port(port);
|
||||
intel_dp_mst_read_decompression_port_dsc_caps(intel_dp, intel_connector);
|
||||
intel_connector->dp.dsc_hblank_expansion_quirk =
|
||||
|
811
drivers/gpu/drm/i915/display/intel_dp_tunnel.c
Normal file
811
drivers/gpu/drm/i915/display/intel_dp_tunnel.c
Normal file
@ -0,0 +1,811 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright © 2023 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "i915_drv.h"
|
||||
|
||||
#include <drm/display/drm_dp_tunnel.h>
|
||||
|
||||
#include "intel_atomic.h"
|
||||
#include "intel_display_limits.h"
|
||||
#include "intel_display_types.h"
|
||||
#include "intel_dp.h"
|
||||
#include "intel_dp_link_training.h"
|
||||
#include "intel_dp_mst.h"
|
||||
#include "intel_dp_tunnel.h"
|
||||
#include "intel_link_bw.h"
|
||||
|
||||
struct intel_dp_tunnel_inherited_state {
|
||||
struct drm_dp_tunnel_ref ref[I915_MAX_PIPES];
|
||||
};
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_disconnect - Disconnect a DP tunnel from a port
|
||||
* @intel_dp: DP port object the tunnel is connected to
|
||||
*
|
||||
* Disconnect a DP tunnel from @intel_dp, destroying any related state. This
|
||||
* should be called after detecting a sink-disconnect event from the port.
|
||||
*/
|
||||
void intel_dp_tunnel_disconnect(struct intel_dp *intel_dp)
|
||||
{
|
||||
drm_dp_tunnel_destroy(intel_dp->tunnel);
|
||||
intel_dp->tunnel = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_destroy - Destroy a DP tunnel
|
||||
* @intel_dp: DP port object the tunnel is connected to
|
||||
*
|
||||
* Destroy a DP tunnel connected to @intel_dp, after disabling the BW
|
||||
* allocation mode on the tunnel. This should be called while destroying the
|
||||
* port.
|
||||
*/
|
||||
void intel_dp_tunnel_destroy(struct intel_dp *intel_dp)
|
||||
{
|
||||
if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
|
||||
drm_dp_tunnel_disable_bw_alloc(intel_dp->tunnel);
|
||||
|
||||
intel_dp_tunnel_disconnect(intel_dp);
|
||||
}
|
||||
|
||||
static int kbytes_to_mbits(int kbytes)
|
||||
{
|
||||
return DIV_ROUND_UP(kbytes * 8, 1000);
|
||||
}
|
||||
|
||||
static int get_current_link_bw(struct intel_dp *intel_dp,
|
||||
bool *below_dprx_bw)
|
||||
{
|
||||
int rate = intel_dp_max_common_rate(intel_dp);
|
||||
int lane_count = intel_dp_max_common_lane_count(intel_dp);
|
||||
int bw;
|
||||
|
||||
bw = intel_dp_max_link_data_rate(intel_dp, rate, lane_count);
|
||||
*below_dprx_bw = bw < drm_dp_max_dprx_data_rate(rate, lane_count);
|
||||
|
||||
return bw;
|
||||
}
|
||||
|
||||
static int update_tunnel_state(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
|
||||
bool old_bw_below_dprx;
|
||||
bool new_bw_below_dprx;
|
||||
int old_bw;
|
||||
int new_bw;
|
||||
int ret;
|
||||
|
||||
old_bw = get_current_link_bw(intel_dp, &old_bw_below_dprx);
|
||||
|
||||
ret = drm_dp_tunnel_update_state(intel_dp->tunnel);
|
||||
if (ret < 0) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[DPTUN %s][ENCODER:%d:%s] State update failed (err %pe)\n",
|
||||
drm_dp_tunnel_name(intel_dp->tunnel),
|
||||
encoder->base.base.id, encoder->base.name,
|
||||
ERR_PTR(ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret == 0 ||
|
||||
!drm_dp_tunnel_bw_alloc_is_enabled(intel_dp->tunnel))
|
||||
return 0;
|
||||
|
||||
intel_dp_update_sink_caps(intel_dp);
|
||||
|
||||
new_bw = get_current_link_bw(intel_dp, &new_bw_below_dprx);
|
||||
|
||||
/* Suppress the notification if the mode list can't change due to bw. */
|
||||
if (old_bw_below_dprx == new_bw_below_dprx &&
|
||||
!new_bw_below_dprx)
|
||||
return 0;
|
||||
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[DPTUN %s][ENCODER:%d:%s] Notify users about BW change: %d -> %d\n",
|
||||
drm_dp_tunnel_name(intel_dp->tunnel),
|
||||
encoder->base.base.id, encoder->base.name,
|
||||
kbytes_to_mbits(old_bw), kbytes_to_mbits(new_bw));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the BW for a tunnel on a DP connector/port if the connector/port
|
||||
* was already active when detecting the tunnel. The allocated BW must be
|
||||
* freed by the next atomic modeset, storing the BW in the
|
||||
* intel_atomic_state::inherited_dp_tunnels, and calling
|
||||
* intel_dp_tunnel_atomic_free_bw().
|
||||
*/
|
||||
static int allocate_initial_tunnel_bw_for_pipes(struct intel_dp *intel_dp, u8 pipe_mask)
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
|
||||
struct intel_crtc *crtc;
|
||||
int tunnel_bw = 0;
|
||||
int err;
|
||||
|
||||
for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, pipe_mask) {
|
||||
const struct intel_crtc_state *crtc_state =
|
||||
to_intel_crtc_state(crtc->base.state);
|
||||
int stream_bw = intel_dp_config_required_rate(crtc_state);
|
||||
|
||||
tunnel_bw += stream_bw;
|
||||
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[DPTUN %s][ENCODER:%d:%s][CRTC:%d:%s] Initial BW for stream %d: %d/%d Mb/s\n",
|
||||
drm_dp_tunnel_name(intel_dp->tunnel),
|
||||
encoder->base.base.id, encoder->base.name,
|
||||
crtc->base.base.id, crtc->base.name,
|
||||
crtc->pipe,
|
||||
kbytes_to_mbits(stream_bw), kbytes_to_mbits(tunnel_bw));
|
||||
}
|
||||
|
||||
err = drm_dp_tunnel_alloc_bw(intel_dp->tunnel, tunnel_bw);
|
||||
if (err) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[DPTUN %s][ENCODER:%d:%s] Initial BW allocation failed (err %pe)\n",
|
||||
drm_dp_tunnel_name(intel_dp->tunnel),
|
||||
encoder->base.base.id, encoder->base.name,
|
||||
ERR_PTR(err));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
return update_tunnel_state(intel_dp);
|
||||
}
|
||||
|
||||
static int allocate_initial_tunnel_bw(struct intel_dp *intel_dp,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
u8 pipe_mask;
|
||||
int err;
|
||||
|
||||
err = intel_dp_get_active_pipes(intel_dp, ctx, &pipe_mask);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return allocate_initial_tunnel_bw_for_pipes(intel_dp, pipe_mask);
|
||||
}
|
||||
|
||||
static int detect_new_tunnel(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
|
||||
struct drm_dp_tunnel *tunnel;
|
||||
int ret;
|
||||
|
||||
tunnel = drm_dp_tunnel_detect(i915->display.dp_tunnel_mgr,
|
||||
&intel_dp->aux);
|
||||
if (IS_ERR(tunnel))
|
||||
return PTR_ERR(tunnel);
|
||||
|
||||
intel_dp->tunnel = tunnel;
|
||||
|
||||
ret = drm_dp_tunnel_enable_bw_alloc(intel_dp->tunnel);
|
||||
if (ret) {
|
||||
if (ret == -EOPNOTSUPP)
|
||||
return 0;
|
||||
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[DPTUN %s][ENCODER:%d:%s] Failed to enable BW allocation mode (ret %pe)\n",
|
||||
drm_dp_tunnel_name(intel_dp->tunnel),
|
||||
encoder->base.base.id, encoder->base.name,
|
||||
ERR_PTR(ret));
|
||||
|
||||
/* Keep the tunnel with BWA disabled */
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = allocate_initial_tunnel_bw(intel_dp, ctx);
|
||||
if (ret < 0)
|
||||
intel_dp_tunnel_destroy(intel_dp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_detect - Detect a DP tunnel on a port
|
||||
* @intel_dp: DP port object
|
||||
* @ctx: lock context acquired by the connector detection handler
|
||||
*
|
||||
* Detect a DP tunnel on the @intel_dp port, enabling the BW allocation mode
|
||||
* on it if supported and allocating the BW required on an already active port.
|
||||
* The BW allocated this way must be freed by the next atomic modeset calling
|
||||
* intel_dp_tunnel_atomic_free_bw().
|
||||
*
|
||||
* If @intel_dp has already a tunnel detected on it, update the tunnel's state
|
||||
* wrt. its support for BW allocation mode and the available BW via the
|
||||
* tunnel. If the tunnel's state change requires this - for instance the
|
||||
* tunnel's group ID has changed - the tunnel will be dropped and recreated.
|
||||
*
|
||||
* Return 0 in case of success - after any tunnel detected and added to
|
||||
* @intel_dp - 1 in case the BW on an already existing tunnel has changed in a
|
||||
* way that requires notifying user space.
|
||||
*/
|
||||
int intel_dp_tunnel_detect(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (intel_dp_is_edp(intel_dp))
|
||||
return 0;
|
||||
|
||||
if (intel_dp->tunnel) {
|
||||
ret = update_tunnel_state(intel_dp);
|
||||
if (ret >= 0)
|
||||
return ret;
|
||||
|
||||
/* Try to recreate the tunnel after an update error. */
|
||||
intel_dp_tunnel_destroy(intel_dp);
|
||||
}
|
||||
|
||||
return detect_new_tunnel(intel_dp, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_bw_alloc_is_enabled - Query the BW allocation support on a tunnel
|
||||
* @intel_dp: DP port object
|
||||
*
|
||||
* Query whether a DP tunnel is connected on @intel_dp and the tunnel supports
|
||||
* the BW allocation mode.
|
||||
*
|
||||
* Returns %true if the BW allocation mode is supported on @intel_dp.
|
||||
*/
|
||||
bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp)
|
||||
{
|
||||
return drm_dp_tunnel_bw_alloc_is_enabled(intel_dp->tunnel);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_suspend - Suspend a DP tunnel connected on a port
|
||||
* @intel_dp: DP port object
|
||||
*
|
||||
* Suspend a DP tunnel on @intel_dp with BW allocation mode enabled on it.
|
||||
*/
|
||||
void intel_dp_tunnel_suspend(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
struct intel_connector *connector = intel_dp->attached_connector;
|
||||
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
|
||||
|
||||
if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
|
||||
return;
|
||||
|
||||
drm_dbg_kms(&i915->drm, "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s] Suspend\n",
|
||||
drm_dp_tunnel_name(intel_dp->tunnel),
|
||||
connector->base.base.id, connector->base.name,
|
||||
encoder->base.base.id, encoder->base.name);
|
||||
|
||||
drm_dp_tunnel_disable_bw_alloc(intel_dp->tunnel);
|
||||
|
||||
intel_dp->tunnel_suspended = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_resume - Resume a DP tunnel connected on a port
|
||||
* @intel_dp: DP port object
|
||||
* @crtc_state: CRTC state
|
||||
* @dpcd_updated: the DPCD DPRX capabilities got updated during resume
|
||||
*
|
||||
* Resume a DP tunnel on @intel_dp with BW allocation mode enabled on it.
|
||||
*/
|
||||
void intel_dp_tunnel_resume(struct intel_dp *intel_dp,
|
||||
const struct intel_crtc_state *crtc_state,
|
||||
bool dpcd_updated)
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
struct intel_connector *connector = intel_dp->attached_connector;
|
||||
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
|
||||
u8 dpcd[DP_RECEIVER_CAP_SIZE];
|
||||
u8 pipe_mask;
|
||||
int err = 0;
|
||||
|
||||
if (!intel_dp->tunnel_suspended)
|
||||
return;
|
||||
|
||||
intel_dp->tunnel_suspended = false;
|
||||
|
||||
drm_dbg_kms(&i915->drm, "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s] Resume\n",
|
||||
drm_dp_tunnel_name(intel_dp->tunnel),
|
||||
connector->base.base.id, connector->base.name,
|
||||
encoder->base.base.id, encoder->base.name);
|
||||
|
||||
/*
|
||||
* The TBT Connection Manager requires the GFX driver to read out
|
||||
* the sink's DPRX caps to be able to service any BW requests later.
|
||||
* During resume overriding the caps in @intel_dp cached before
|
||||
* suspend must be avoided, so do here only a dummy read, unless the
|
||||
* capabilities were updated already during resume.
|
||||
*/
|
||||
if (!dpcd_updated) {
|
||||
err = intel_dp_read_dprx_caps(intel_dp, dpcd);
|
||||
|
||||
if (err) {
|
||||
drm_dp_tunnel_set_io_error(intel_dp->tunnel);
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
||||
err = drm_dp_tunnel_enable_bw_alloc(intel_dp->tunnel);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
pipe_mask = 0;
|
||||
if (crtc_state) {
|
||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||
|
||||
/* TODO: Add support for MST */
|
||||
pipe_mask |= BIT(crtc->pipe);
|
||||
}
|
||||
|
||||
err = allocate_initial_tunnel_bw_for_pipes(intel_dp, pipe_mask);
|
||||
if (err < 0)
|
||||
goto out_err;
|
||||
|
||||
return;
|
||||
|
||||
out_err:
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s] Tunnel can't be resumed, will drop and redect it (err %pe)\n",
|
||||
drm_dp_tunnel_name(intel_dp->tunnel),
|
||||
connector->base.base.id, connector->base.name,
|
||||
encoder->base.base.id, encoder->base.name,
|
||||
ERR_PTR(err));
|
||||
}
|
||||
|
||||
static struct drm_dp_tunnel *
|
||||
get_inherited_tunnel(struct intel_atomic_state *state, struct intel_crtc *crtc)
|
||||
{
|
||||
if (!state->inherited_dp_tunnels)
|
||||
return NULL;
|
||||
|
||||
return state->inherited_dp_tunnels->ref[crtc->pipe].tunnel;
|
||||
}
|
||||
|
||||
static int
|
||||
add_inherited_tunnel(struct intel_atomic_state *state,
|
||||
struct drm_dp_tunnel *tunnel,
|
||||
struct intel_crtc *crtc)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(state->base.dev);
|
||||
struct drm_dp_tunnel *old_tunnel;
|
||||
|
||||
old_tunnel = get_inherited_tunnel(state, crtc);
|
||||
if (old_tunnel) {
|
||||
drm_WARN_ON(&i915->drm, old_tunnel != tunnel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!state->inherited_dp_tunnels) {
|
||||
state->inherited_dp_tunnels = kzalloc(sizeof(*state->inherited_dp_tunnels),
|
||||
GFP_KERNEL);
|
||||
if (!state->inherited_dp_tunnels)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
drm_dp_tunnel_ref_get(tunnel, &state->inherited_dp_tunnels->ref[crtc->pipe]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_inherited_tunnel_state(struct intel_atomic_state *state,
|
||||
struct intel_dp *intel_dp,
|
||||
const struct intel_digital_connector_state *old_conn_state)
|
||||
{
|
||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
|
||||
struct intel_connector *connector =
|
||||
to_intel_connector(old_conn_state->base.connector);
|
||||
struct intel_crtc *old_crtc;
|
||||
const struct intel_crtc_state *old_crtc_state;
|
||||
|
||||
/*
|
||||
* If a BWA tunnel gets detected only after the corresponding
|
||||
* connector got enabled already without a BWA tunnel, or a different
|
||||
* BWA tunnel (which was removed meanwhile) the old CRTC state won't
|
||||
* contain the state of the current tunnel. This tunnel still has a
|
||||
* reserved BW, which needs to be released, add the state for such
|
||||
* inherited tunnels separately only to this atomic state.
|
||||
*/
|
||||
if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
|
||||
return 0;
|
||||
|
||||
if (!old_conn_state->base.crtc)
|
||||
return 0;
|
||||
|
||||
old_crtc = to_intel_crtc(old_conn_state->base.crtc);
|
||||
old_crtc_state = intel_atomic_get_old_crtc_state(state, old_crtc);
|
||||
|
||||
if (!old_crtc_state->hw.active ||
|
||||
old_crtc_state->dp_tunnel_ref.tunnel == intel_dp->tunnel)
|
||||
return 0;
|
||||
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s][CRTC:%d:%s] Adding state for inherited tunnel %p\n",
|
||||
drm_dp_tunnel_name(intel_dp->tunnel),
|
||||
connector->base.base.id, connector->base.name,
|
||||
encoder->base.base.id, encoder->base.name,
|
||||
old_crtc->base.base.id, old_crtc->base.name,
|
||||
intel_dp->tunnel);
|
||||
|
||||
return add_inherited_tunnel(state, intel_dp->tunnel, old_crtc);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_atomic_cleanup_inherited_state - Free any inherited DP tunnel state
|
||||
* @state: Atomic state
|
||||
*
|
||||
* Free the inherited DP tunnel state in @state.
|
||||
*/
|
||||
void intel_dp_tunnel_atomic_cleanup_inherited_state(struct intel_atomic_state *state)
|
||||
{
|
||||
enum pipe pipe;
|
||||
|
||||
if (!state->inherited_dp_tunnels)
|
||||
return;
|
||||
|
||||
for_each_pipe(to_i915(state->base.dev), pipe)
|
||||
if (state->inherited_dp_tunnels->ref[pipe].tunnel)
|
||||
drm_dp_tunnel_ref_put(&state->inherited_dp_tunnels->ref[pipe]);
|
||||
|
||||
kfree(state->inherited_dp_tunnels);
|
||||
state->inherited_dp_tunnels = NULL;
|
||||
}
|
||||
|
||||
static int intel_dp_tunnel_atomic_add_group_state(struct intel_atomic_state *state,
|
||||
struct drm_dp_tunnel *tunnel)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(state->base.dev);
|
||||
u32 pipe_mask;
|
||||
int err;
|
||||
|
||||
err = drm_dp_tunnel_atomic_get_group_streams_in_state(&state->base,
|
||||
tunnel, &pipe_mask);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
drm_WARN_ON(&i915->drm, pipe_mask & ~((1 << I915_MAX_PIPES) - 1));
|
||||
|
||||
return intel_modeset_pipes_in_mask_early(state, "DPTUN", pipe_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_atomic_add_state_for_crtc - Add CRTC specific DP tunnel state
|
||||
* @state: Atomic state
|
||||
* @crtc: CRTC to add the tunnel state for
|
||||
*
|
||||
* Add the DP tunnel state for @crtc if the CRTC (aka DP tunnel stream) is enabled
|
||||
* via a DP tunnel.
|
||||
*
|
||||
* Return 0 in case of success, a negative error code otherwise.
|
||||
*/
|
||||
int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
|
||||
struct intel_crtc *crtc)
|
||||
{
|
||||
const struct intel_crtc_state *new_crtc_state =
|
||||
intel_atomic_get_new_crtc_state(state, crtc);
|
||||
const struct drm_dp_tunnel_state *tunnel_state;
|
||||
struct drm_dp_tunnel *tunnel = new_crtc_state->dp_tunnel_ref.tunnel;
|
||||
|
||||
if (!tunnel)
|
||||
return 0;
|
||||
|
||||
tunnel_state = drm_dp_tunnel_atomic_get_state(&state->base, tunnel);
|
||||
if (IS_ERR(tunnel_state))
|
||||
return PTR_ERR(tunnel_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_group_state(struct intel_atomic_state *state,
|
||||
struct intel_dp *intel_dp,
|
||||
struct intel_connector *connector,
|
||||
struct intel_crtc *crtc)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(state->base.dev);
|
||||
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
|
||||
const struct intel_crtc_state *crtc_state =
|
||||
intel_atomic_get_new_crtc_state(state, crtc);
|
||||
|
||||
if (!crtc_state->dp_tunnel_ref.tunnel)
|
||||
return 0;
|
||||
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s][CRTC:%d:%s] Adding group state for tunnel %p\n",
|
||||
drm_dp_tunnel_name(intel_dp->tunnel),
|
||||
connector->base.base.id, connector->base.name,
|
||||
encoder->base.base.id, encoder->base.name,
|
||||
crtc->base.base.id, crtc->base.name,
|
||||
crtc_state->dp_tunnel_ref.tunnel);
|
||||
|
||||
return intel_dp_tunnel_atomic_add_group_state(state, crtc_state->dp_tunnel_ref.tunnel);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_atomic_check_state - Check a connector's DP tunnel specific state
|
||||
* @state: Atomic state
|
||||
* @intel_dp: DP port object
|
||||
* @connector: connector using @intel_dp
|
||||
*
|
||||
* Check and add the DP tunnel atomic state for @intel_dp/@connector to
|
||||
* @state, if there is a DP tunnel detected on @intel_dp with BW allocation
|
||||
* mode enabled on it, or if @intel_dp/@connector was previously enabled via a
|
||||
* DP tunnel.
|
||||
*
|
||||
* Returns 0 in case of success, or a negative error code otherwise.
|
||||
*/
|
||||
int intel_dp_tunnel_atomic_check_state(struct intel_atomic_state *state,
|
||||
struct intel_dp *intel_dp,
|
||||
struct intel_connector *connector)
|
||||
{
|
||||
const struct intel_digital_connector_state *old_conn_state =
|
||||
intel_atomic_get_old_connector_state(state, connector);
|
||||
const struct intel_digital_connector_state *new_conn_state =
|
||||
intel_atomic_get_new_connector_state(state, connector);
|
||||
int err;
|
||||
|
||||
if (old_conn_state->base.crtc) {
|
||||
err = check_group_state(state, intel_dp, connector,
|
||||
to_intel_crtc(old_conn_state->base.crtc));
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (new_conn_state->base.crtc &&
|
||||
new_conn_state->base.crtc != old_conn_state->base.crtc) {
|
||||
err = check_group_state(state, intel_dp, connector,
|
||||
to_intel_crtc(new_conn_state->base.crtc));
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return check_inherited_tunnel_state(state, intel_dp, old_conn_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_atomic_compute_stream_bw - Compute the BW required by a DP tunnel stream
|
||||
* @state: Atomic state
|
||||
* @intel_dp: DP object
|
||||
* @connector: connector using @intel_dp
|
||||
* @crtc_state: state of CRTC of the given DP tunnel stream
|
||||
*
|
||||
* Compute the required BW of CRTC (aka DP tunnel stream), storing this BW to
|
||||
* the DP tunnel state containing the stream in @state. Before re-calculating a
|
||||
* BW requirement in the crtc_state state the old BW requirement computed by this
|
||||
* function must be cleared by calling intel_dp_tunnel_atomic_clear_stream_bw().
|
||||
*
|
||||
* Returns 0 in case of success, a negative error code otherwise.
|
||||
*/
|
||||
int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
|
||||
struct intel_dp *intel_dp,
|
||||
const struct intel_connector *connector,
|
||||
struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(state->base.dev);
|
||||
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
|
||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||
int required_rate = intel_dp_config_required_rate(crtc_state);
|
||||
int ret;
|
||||
|
||||
if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
|
||||
return 0;
|
||||
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s][CRTC:%d:%s] Stream %d required BW %d Mb/s\n",
|
||||
drm_dp_tunnel_name(intel_dp->tunnel),
|
||||
connector->base.base.id, connector->base.name,
|
||||
encoder->base.base.id, encoder->base.name,
|
||||
crtc->base.base.id, crtc->base.name,
|
||||
crtc->pipe,
|
||||
kbytes_to_mbits(required_rate));
|
||||
|
||||
ret = drm_dp_tunnel_atomic_set_stream_bw(&state->base, intel_dp->tunnel,
|
||||
crtc->pipe, required_rate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
drm_dp_tunnel_ref_get(intel_dp->tunnel,
|
||||
&crtc_state->dp_tunnel_ref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_atomic_clear_stream_bw - Clear any DP tunnel stream BW requirement
|
||||
* @state: Atomic state
|
||||
* @crtc_state: state of CRTC of the given DP tunnel stream
|
||||
*
|
||||
* Clear any DP tunnel stream BW requirement set by
|
||||
* intel_dp_tunnel_atomic_compute_stream_bw().
|
||||
*/
|
||||
void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
|
||||
struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||
|
||||
if (!crtc_state->dp_tunnel_ref.tunnel)
|
||||
return;
|
||||
|
||||
drm_dp_tunnel_atomic_set_stream_bw(&state->base,
|
||||
crtc_state->dp_tunnel_ref.tunnel,
|
||||
crtc->pipe, 0);
|
||||
drm_dp_tunnel_ref_put(&crtc_state->dp_tunnel_ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_atomic_check_link - Check the DP tunnel atomic state
|
||||
* @state: intel atomic state
|
||||
* @limits: link BW limits
|
||||
*
|
||||
* Check the link configuration for all DP tunnels in @state. If the
|
||||
* configuration is invalid @limits will be updated if possible to
|
||||
* reduce the total BW, after which the configuration for all CRTCs in
|
||||
* @state must be recomputed with the updated @limits.
|
||||
*
|
||||
* Returns:
|
||||
* - 0 if the confugration is valid
|
||||
* - %-EAGAIN, if the configuration is invalid and @limits got updated
|
||||
* with fallback values with which the configuration of all CRTCs in
|
||||
* @state must be recomputed
|
||||
* - Other negative error, if the configuration is invalid without a
|
||||
* fallback possibility, or the check failed for another reason
|
||||
*/
|
||||
int intel_dp_tunnel_atomic_check_link(struct intel_atomic_state *state,
|
||||
struct intel_link_bw_limits *limits)
|
||||
{
|
||||
u32 failed_stream_mask;
|
||||
int err;
|
||||
|
||||
err = drm_dp_tunnel_atomic_check_stream_bws(&state->base,
|
||||
&failed_stream_mask);
|
||||
if (err != -ENOSPC)
|
||||
return err;
|
||||
|
||||
err = intel_link_bw_reduce_bpp(state, limits,
|
||||
failed_stream_mask, "DP tunnel link BW");
|
||||
|
||||
return err ? : -EAGAIN;
|
||||
}
|
||||
|
||||
static void atomic_decrease_bw(struct intel_atomic_state *state)
|
||||
{
|
||||
struct intel_crtc *crtc;
|
||||
const struct intel_crtc_state *old_crtc_state;
|
||||
const struct intel_crtc_state *new_crtc_state;
|
||||
int i;
|
||||
|
||||
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
|
||||
const struct drm_dp_tunnel_state *new_tunnel_state;
|
||||
struct drm_dp_tunnel *tunnel;
|
||||
int old_bw;
|
||||
int new_bw;
|
||||
|
||||
if (!intel_crtc_needs_modeset(new_crtc_state))
|
||||
continue;
|
||||
|
||||
tunnel = get_inherited_tunnel(state, crtc);
|
||||
if (!tunnel)
|
||||
tunnel = old_crtc_state->dp_tunnel_ref.tunnel;
|
||||
|
||||
if (!tunnel)
|
||||
continue;
|
||||
|
||||
old_bw = drm_dp_tunnel_get_allocated_bw(tunnel);
|
||||
|
||||
new_tunnel_state = drm_dp_tunnel_atomic_get_new_state(&state->base, tunnel);
|
||||
new_bw = drm_dp_tunnel_atomic_get_required_bw(new_tunnel_state);
|
||||
|
||||
if (new_bw >= old_bw)
|
||||
continue;
|
||||
|
||||
drm_dp_tunnel_alloc_bw(tunnel, new_bw);
|
||||
}
|
||||
}
|
||||
|
||||
static void queue_retry_work(struct intel_atomic_state *state,
|
||||
struct drm_dp_tunnel *tunnel,
|
||||
const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(state->base.dev);
|
||||
struct intel_encoder *encoder;
|
||||
|
||||
encoder = intel_get_crtc_new_encoder(state, crtc_state);
|
||||
|
||||
if (!intel_digital_port_connected(encoder))
|
||||
return;
|
||||
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[DPTUN %s][ENCODER:%d:%s] BW allocation failed on a connected sink\n",
|
||||
drm_dp_tunnel_name(tunnel),
|
||||
encoder->base.base.id,
|
||||
encoder->base.name);
|
||||
|
||||
intel_dp_queue_modeset_retry_for_link(state, encoder, crtc_state);
|
||||
}
|
||||
|
||||
static void atomic_increase_bw(struct intel_atomic_state *state)
|
||||
{
|
||||
struct intel_crtc *crtc;
|
||||
const struct intel_crtc_state *crtc_state;
|
||||
int i;
|
||||
|
||||
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
struct drm_dp_tunnel_state *tunnel_state;
|
||||
struct drm_dp_tunnel *tunnel = crtc_state->dp_tunnel_ref.tunnel;
|
||||
int bw;
|
||||
|
||||
if (!intel_crtc_needs_modeset(crtc_state))
|
||||
continue;
|
||||
|
||||
if (!tunnel)
|
||||
continue;
|
||||
|
||||
tunnel_state = drm_dp_tunnel_atomic_get_new_state(&state->base, tunnel);
|
||||
|
||||
bw = drm_dp_tunnel_atomic_get_required_bw(tunnel_state);
|
||||
|
||||
if (drm_dp_tunnel_alloc_bw(tunnel, bw) != 0)
|
||||
queue_retry_work(state, tunnel, crtc_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_atomic_alloc_bw - Allocate the BW for all modeset tunnels
|
||||
* @state: Atomic state
|
||||
*
|
||||
* Allocate the required BW for all tunnels in @state.
|
||||
*/
|
||||
void intel_dp_tunnel_atomic_alloc_bw(struct intel_atomic_state *state)
|
||||
{
|
||||
atomic_decrease_bw(state);
|
||||
atomic_increase_bw(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_mgr_init - Initialize the DP tunnel manager
|
||||
* @i915: i915 device object
|
||||
*
|
||||
* Initialize the DP tunnel manager. The tunnel manager will support the
|
||||
* detection/management of DP tunnels on all DP connectors, so the function
|
||||
* must be called after all these connectors have been registered already.
|
||||
*
|
||||
* Return 0 in case of success, a negative error code otherwise.
|
||||
*/
|
||||
int intel_dp_tunnel_mgr_init(struct drm_i915_private *i915)
|
||||
{
|
||||
struct drm_dp_tunnel_mgr *tunnel_mgr;
|
||||
struct drm_connector_list_iter connector_list_iter;
|
||||
struct intel_connector *connector;
|
||||
int dp_connectors = 0;
|
||||
|
||||
drm_connector_list_iter_begin(&i915->drm, &connector_list_iter);
|
||||
for_each_intel_connector_iter(connector, &connector_list_iter) {
|
||||
if (connector->base.connector_type != DRM_MODE_CONNECTOR_DisplayPort)
|
||||
continue;
|
||||
|
||||
dp_connectors++;
|
||||
}
|
||||
drm_connector_list_iter_end(&connector_list_iter);
|
||||
|
||||
tunnel_mgr = drm_dp_tunnel_mgr_create(&i915->drm, dp_connectors);
|
||||
if (IS_ERR(tunnel_mgr))
|
||||
return PTR_ERR(tunnel_mgr);
|
||||
|
||||
i915->display.dp_tunnel_mgr = tunnel_mgr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dp_tunnel_mgr_cleanup - Clean up the DP tunnel manager state
|
||||
* @i915: i915 device object
|
||||
*
|
||||
* Clean up the DP tunnel manager state.
|
||||
*/
|
||||
void intel_dp_tunnel_mgr_cleanup(struct drm_i915_private *i915)
|
||||
{
|
||||
drm_dp_tunnel_mgr_destroy(i915->display.dp_tunnel_mgr);
|
||||
i915->display.dp_tunnel_mgr = NULL;
|
||||
}
|
133
drivers/gpu/drm/i915/display/intel_dp_tunnel.h
Normal file
133
drivers/gpu/drm/i915/display/intel_dp_tunnel.h
Normal file
@ -0,0 +1,133 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2023 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __INTEL_DP_TUNNEL_H__
|
||||
#define __INTEL_DP_TUNNEL_H__
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct drm_i915_private;
|
||||
struct drm_connector_state;
|
||||
struct drm_modeset_acquire_ctx;
|
||||
|
||||
struct intel_atomic_state;
|
||||
struct intel_connector;
|
||||
struct intel_crtc;
|
||||
struct intel_crtc_state;
|
||||
struct intel_dp;
|
||||
struct intel_encoder;
|
||||
struct intel_link_bw_limits;
|
||||
|
||||
#if defined(CONFIG_DRM_I915_DP_TUNNEL) && defined(I915)
|
||||
|
||||
int intel_dp_tunnel_detect(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx);
|
||||
void intel_dp_tunnel_disconnect(struct intel_dp *intel_dp);
|
||||
void intel_dp_tunnel_destroy(struct intel_dp *intel_dp);
|
||||
void intel_dp_tunnel_resume(struct intel_dp *intel_dp,
|
||||
const struct intel_crtc_state *crtc_state,
|
||||
bool dpcd_updated);
|
||||
void intel_dp_tunnel_suspend(struct intel_dp *intel_dp);
|
||||
|
||||
bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp);
|
||||
|
||||
void
|
||||
intel_dp_tunnel_atomic_cleanup_inherited_state(struct intel_atomic_state *state);
|
||||
|
||||
int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
|
||||
struct intel_dp *intel_dp,
|
||||
const struct intel_connector *connector,
|
||||
struct intel_crtc_state *crtc_state);
|
||||
void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
|
||||
struct intel_crtc_state *crtc_state);
|
||||
|
||||
int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
|
||||
struct intel_crtc *crtc);
|
||||
int intel_dp_tunnel_atomic_check_link(struct intel_atomic_state *state,
|
||||
struct intel_link_bw_limits *limits);
|
||||
int intel_dp_tunnel_atomic_check_state(struct intel_atomic_state *state,
|
||||
struct intel_dp *intel_dp,
|
||||
struct intel_connector *connector);
|
||||
|
||||
void intel_dp_tunnel_atomic_alloc_bw(struct intel_atomic_state *state);
|
||||
|
||||
int intel_dp_tunnel_mgr_init(struct drm_i915_private *i915);
|
||||
void intel_dp_tunnel_mgr_cleanup(struct drm_i915_private *i915);
|
||||
|
||||
#else
|
||||
|
||||
static inline int
|
||||
intel_dp_tunnel_detect(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void intel_dp_tunnel_disconnect(struct intel_dp *intel_dp) {}
|
||||
static inline void intel_dp_tunnel_destroy(struct intel_dp *intel_dp) {}
|
||||
static inline void intel_dp_tunnel_resume(struct intel_dp *intel_dp,
|
||||
const struct intel_crtc_state *crtc_state,
|
||||
bool dpcd_updated) {}
|
||||
static inline void intel_dp_tunnel_suspend(struct intel_dp *intel_dp) {}
|
||||
|
||||
static inline bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
intel_dp_tunnel_atomic_cleanup_inherited_state(struct intel_atomic_state *state) {}
|
||||
|
||||
static inline int
|
||||
intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
|
||||
struct intel_dp *intel_dp,
|
||||
const struct intel_connector *connector,
|
||||
struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
|
||||
struct intel_crtc_state *crtc_state) {}
|
||||
|
||||
static inline int
|
||||
intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
|
||||
struct intel_crtc *crtc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
intel_dp_tunnel_atomic_check_link(struct intel_atomic_state *state,
|
||||
struct intel_link_bw_limits *limits)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
intel_dp_tunnel_atomic_check_state(struct intel_atomic_state *state,
|
||||
struct intel_dp *intel_dp,
|
||||
struct intel_connector *connector)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
intel_dp_tunnel_atomic_alloc_bw(struct intel_atomic_state *state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
intel_dp_tunnel_mgr_init(struct drm_i915_private *i915)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void intel_dp_tunnel_mgr_cleanup(struct drm_i915_private *i915) {}
|
||||
|
||||
#endif /* CONFIG_DRM_I915_DP_TUNNEL */
|
||||
|
||||
#endif /* __INTEL_DP_TUNNEL_H__ */
|
@ -109,6 +109,8 @@ struct intel_dpll_mgr {
|
||||
void (*update_ref_clks)(struct drm_i915_private *i915);
|
||||
void (*dump_hw_state)(struct drm_i915_private *i915,
|
||||
const struct intel_dpll_hw_state *hw_state);
|
||||
bool (*compare_hw_state)(const struct intel_dpll_hw_state *a,
|
||||
const struct intel_dpll_hw_state *b);
|
||||
};
|
||||
|
||||
static void
|
||||
@ -644,6 +646,15 @@ static void ibx_dump_hw_state(struct drm_i915_private *i915,
|
||||
hw_state->fp1);
|
||||
}
|
||||
|
||||
static bool ibx_compare_hw_state(const struct intel_dpll_hw_state *a,
|
||||
const struct intel_dpll_hw_state *b)
|
||||
{
|
||||
return a->dpll == b->dpll &&
|
||||
a->dpll_md == b->dpll_md &&
|
||||
a->fp0 == b->fp0 &&
|
||||
a->fp1 == b->fp1;
|
||||
}
|
||||
|
||||
static const struct intel_shared_dpll_funcs ibx_pch_dpll_funcs = {
|
||||
.enable = ibx_pch_dpll_enable,
|
||||
.disable = ibx_pch_dpll_disable,
|
||||
@ -662,6 +673,7 @@ static const struct intel_dpll_mgr pch_pll_mgr = {
|
||||
.get_dplls = ibx_get_dpll,
|
||||
.put_dplls = intel_put_dpll,
|
||||
.dump_hw_state = ibx_dump_hw_state,
|
||||
.compare_hw_state = ibx_compare_hw_state,
|
||||
};
|
||||
|
||||
static void hsw_ddi_wrpll_enable(struct drm_i915_private *i915,
|
||||
@ -1220,6 +1232,13 @@ static void hsw_dump_hw_state(struct drm_i915_private *i915,
|
||||
hw_state->wrpll, hw_state->spll);
|
||||
}
|
||||
|
||||
static bool hsw_compare_hw_state(const struct intel_dpll_hw_state *a,
|
||||
const struct intel_dpll_hw_state *b)
|
||||
{
|
||||
return a->wrpll == b->wrpll &&
|
||||
a->spll == b->spll;
|
||||
}
|
||||
|
||||
static const struct intel_shared_dpll_funcs hsw_ddi_wrpll_funcs = {
|
||||
.enable = hsw_ddi_wrpll_enable,
|
||||
.disable = hsw_ddi_wrpll_disable,
|
||||
@ -1278,6 +1297,7 @@ static const struct intel_dpll_mgr hsw_pll_mgr = {
|
||||
.put_dplls = intel_put_dpll,
|
||||
.update_ref_clks = hsw_update_dpll_ref_clks,
|
||||
.dump_hw_state = hsw_dump_hw_state,
|
||||
.compare_hw_state = hsw_compare_hw_state,
|
||||
};
|
||||
|
||||
struct skl_dpll_regs {
|
||||
@ -1929,6 +1949,14 @@ static void skl_dump_hw_state(struct drm_i915_private *i915,
|
||||
hw_state->cfgcr2);
|
||||
}
|
||||
|
||||
static bool skl_compare_hw_state(const struct intel_dpll_hw_state *a,
|
||||
const struct intel_dpll_hw_state *b)
|
||||
{
|
||||
return a->ctrl1 == b->ctrl1 &&
|
||||
a->cfgcr1 == b->cfgcr1 &&
|
||||
a->cfgcr2 == b->cfgcr2;
|
||||
}
|
||||
|
||||
static const struct intel_shared_dpll_funcs skl_ddi_pll_funcs = {
|
||||
.enable = skl_ddi_pll_enable,
|
||||
.disable = skl_ddi_pll_disable,
|
||||
@ -1959,6 +1987,7 @@ static const struct intel_dpll_mgr skl_pll_mgr = {
|
||||
.put_dplls = intel_put_dpll,
|
||||
.update_ref_clks = skl_update_dpll_ref_clks,
|
||||
.dump_hw_state = skl_dump_hw_state,
|
||||
.compare_hw_state = skl_compare_hw_state,
|
||||
};
|
||||
|
||||
static void bxt_ddi_pll_enable(struct drm_i915_private *i915,
|
||||
@ -2392,6 +2421,21 @@ static void bxt_dump_hw_state(struct drm_i915_private *i915,
|
||||
hw_state->pcsdw12);
|
||||
}
|
||||
|
||||
static bool bxt_compare_hw_state(const struct intel_dpll_hw_state *a,
|
||||
const struct intel_dpll_hw_state *b)
|
||||
{
|
||||
return a->ebb0 == b->ebb0 &&
|
||||
a->ebb4 == b->ebb4 &&
|
||||
a->pll0 == b->pll0 &&
|
||||
a->pll1 == b->pll1 &&
|
||||
a->pll2 == b->pll2 &&
|
||||
a->pll3 == b->pll3 &&
|
||||
a->pll6 == b->pll6 &&
|
||||
a->pll8 == b->pll8 &&
|
||||
a->pll10 == b->pll10 &&
|
||||
a->pcsdw12 == b->pcsdw12;
|
||||
}
|
||||
|
||||
static const struct intel_shared_dpll_funcs bxt_ddi_pll_funcs = {
|
||||
.enable = bxt_ddi_pll_enable,
|
||||
.disable = bxt_ddi_pll_disable,
|
||||
@ -2413,6 +2457,7 @@ static const struct intel_dpll_mgr bxt_pll_mgr = {
|
||||
.put_dplls = intel_put_dpll,
|
||||
.update_ref_clks = bxt_update_dpll_ref_clks,
|
||||
.dump_hw_state = bxt_dump_hw_state,
|
||||
.compare_hw_state = bxt_compare_hw_state,
|
||||
};
|
||||
|
||||
static void icl_wrpll_get_multipliers(int bestdiv, int *pdiv,
|
||||
@ -4005,6 +4050,25 @@ static void icl_dump_hw_state(struct drm_i915_private *i915,
|
||||
hw_state->mg_pll_tdc_coldst_bias);
|
||||
}
|
||||
|
||||
static bool icl_compare_hw_state(const struct intel_dpll_hw_state *a,
|
||||
const struct intel_dpll_hw_state *b)
|
||||
{
|
||||
/* FIXME split combo vs. mg more thoroughly */
|
||||
return a->cfgcr0 == b->cfgcr0 &&
|
||||
a->cfgcr1 == b->cfgcr1 &&
|
||||
a->div0 == b->div0 &&
|
||||
a->mg_refclkin_ctl == b->mg_refclkin_ctl &&
|
||||
a->mg_clktop2_coreclkctl1 == b->mg_clktop2_coreclkctl1 &&
|
||||
a->mg_clktop2_hsclkctl == b->mg_clktop2_hsclkctl &&
|
||||
a->mg_pll_div0 == b->mg_pll_div0 &&
|
||||
a->mg_pll_div1 == b->mg_pll_div1 &&
|
||||
a->mg_pll_lf == b->mg_pll_lf &&
|
||||
a->mg_pll_frac_lock == b->mg_pll_frac_lock &&
|
||||
a->mg_pll_ssc == b->mg_pll_ssc &&
|
||||
a->mg_pll_bias == b->mg_pll_bias &&
|
||||
a->mg_pll_tdc_coldst_bias == b->mg_pll_tdc_coldst_bias;
|
||||
}
|
||||
|
||||
static const struct intel_shared_dpll_funcs combo_pll_funcs = {
|
||||
.enable = combo_pll_enable,
|
||||
.disable = combo_pll_disable,
|
||||
@ -4046,6 +4110,7 @@ static const struct intel_dpll_mgr icl_pll_mgr = {
|
||||
.update_active_dpll = icl_update_active_dpll,
|
||||
.update_ref_clks = icl_update_dpll_ref_clks,
|
||||
.dump_hw_state = icl_dump_hw_state,
|
||||
.compare_hw_state = icl_compare_hw_state,
|
||||
};
|
||||
|
||||
static const struct dpll_info ehl_plls[] = {
|
||||
@ -4063,6 +4128,7 @@ static const struct intel_dpll_mgr ehl_pll_mgr = {
|
||||
.put_dplls = icl_put_dplls,
|
||||
.update_ref_clks = icl_update_dpll_ref_clks,
|
||||
.dump_hw_state = icl_dump_hw_state,
|
||||
.compare_hw_state = icl_compare_hw_state,
|
||||
};
|
||||
|
||||
static const struct intel_shared_dpll_funcs dkl_pll_funcs = {
|
||||
@ -4094,6 +4160,7 @@ static const struct intel_dpll_mgr tgl_pll_mgr = {
|
||||
.update_active_dpll = icl_update_active_dpll,
|
||||
.update_ref_clks = icl_update_dpll_ref_clks,
|
||||
.dump_hw_state = icl_dump_hw_state,
|
||||
.compare_hw_state = icl_compare_hw_state,
|
||||
};
|
||||
|
||||
static const struct dpll_info rkl_plls[] = {
|
||||
@ -4110,6 +4177,7 @@ static const struct intel_dpll_mgr rkl_pll_mgr = {
|
||||
.put_dplls = icl_put_dplls,
|
||||
.update_ref_clks = icl_update_dpll_ref_clks,
|
||||
.dump_hw_state = icl_dump_hw_state,
|
||||
.compare_hw_state = icl_compare_hw_state,
|
||||
};
|
||||
|
||||
static const struct dpll_info dg1_plls[] = {
|
||||
@ -4127,6 +4195,7 @@ static const struct intel_dpll_mgr dg1_pll_mgr = {
|
||||
.put_dplls = icl_put_dplls,
|
||||
.update_ref_clks = icl_update_dpll_ref_clks,
|
||||
.dump_hw_state = icl_dump_hw_state,
|
||||
.compare_hw_state = icl_compare_hw_state,
|
||||
};
|
||||
|
||||
static const struct dpll_info adls_plls[] = {
|
||||
@ -4144,6 +4213,7 @@ static const struct intel_dpll_mgr adls_pll_mgr = {
|
||||
.put_dplls = icl_put_dplls,
|
||||
.update_ref_clks = icl_update_dpll_ref_clks,
|
||||
.dump_hw_state = icl_dump_hw_state,
|
||||
.compare_hw_state = icl_compare_hw_state,
|
||||
};
|
||||
|
||||
static const struct dpll_info adlp_plls[] = {
|
||||
@ -4166,6 +4236,7 @@ static const struct intel_dpll_mgr adlp_pll_mgr = {
|
||||
.update_active_dpll = icl_update_active_dpll,
|
||||
.update_ref_clks = icl_update_dpll_ref_clks,
|
||||
.dump_hw_state = icl_dump_hw_state,
|
||||
.compare_hw_state = icl_compare_hw_state,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -4458,13 +4529,31 @@ void intel_dpll_dump_hw_state(struct drm_i915_private *i915,
|
||||
/* fallback for platforms that don't use the shared dpll
|
||||
* infrastructure
|
||||
*/
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, "
|
||||
"fp0: 0x%x, fp1: 0x%x\n",
|
||||
hw_state->dpll,
|
||||
hw_state->dpll_md,
|
||||
hw_state->fp0,
|
||||
hw_state->fp1);
|
||||
ibx_dump_hw_state(i915, hw_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_dpll_compare_hw_state - compare the two states
|
||||
* @i915: i915 drm device
|
||||
* @a: first DPLL hw state
|
||||
* @b: second DPLL hw state
|
||||
*
|
||||
* Compare DPLL hw states @a and @b.
|
||||
*
|
||||
* Returns: true if the states are equal, false if the differ
|
||||
*/
|
||||
bool intel_dpll_compare_hw_state(struct drm_i915_private *i915,
|
||||
const struct intel_dpll_hw_state *a,
|
||||
const struct intel_dpll_hw_state *b)
|
||||
{
|
||||
if (i915->display.dpll.mgr) {
|
||||
return i915->display.dpll.mgr->compare_hw_state(a, b);
|
||||
} else {
|
||||
/* fallback for platforms that don't use the shared dpll
|
||||
* infrastructure
|
||||
*/
|
||||
return ibx_compare_hw_state(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,6 +378,9 @@ void intel_dpll_sanitize_state(struct drm_i915_private *i915);
|
||||
|
||||
void intel_dpll_dump_hw_state(struct drm_i915_private *i915,
|
||||
const struct intel_dpll_hw_state *hw_state);
|
||||
bool intel_dpll_compare_hw_state(struct drm_i915_private *i915,
|
||||
const struct intel_dpll_hw_state *a,
|
||||
const struct intel_dpll_hw_state *b);
|
||||
enum intel_dpll_id icl_tc_port_to_pll_id(enum tc_port tc_port);
|
||||
bool intel_dpll_is_combophy(enum intel_dpll_id id);
|
||||
|
||||
|
@ -299,6 +299,7 @@ void intel_drrs_crtc_init(struct intel_crtc *crtc)
|
||||
static int intel_drrs_debugfs_status_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct intel_crtc *crtc = m->private;
|
||||
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
|
||||
const struct intel_crtc_state *crtc_state;
|
||||
int ret;
|
||||
|
||||
@ -310,6 +311,11 @@ static int intel_drrs_debugfs_status_show(struct seq_file *m, void *unused)
|
||||
|
||||
mutex_lock(&crtc->drrs.mutex);
|
||||
|
||||
seq_printf(m, "DRRS capable: %s\n",
|
||||
str_yes_no(crtc_state->has_drrs ||
|
||||
HAS_DOUBLE_BUFFERED_M_N(i915) ||
|
||||
intel_cpu_transcoder_has_m2_n2(i915, crtc_state->cpu_transcoder)));
|
||||
|
||||
seq_printf(m, "DRRS enabled: %s\n",
|
||||
str_yes_no(crtc_state->has_drrs));
|
||||
|
||||
|
@ -325,7 +325,7 @@ static int intel_dsb_dewake_scanline(const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
|
||||
const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
|
||||
unsigned int latency = skl_watermark_max_latency(i915);
|
||||
unsigned int latency = skl_watermark_max_latency(i915, 0);
|
||||
int vblank_start;
|
||||
|
||||
if (crtc_state->vrr.enable) {
|
||||
|
@ -57,9 +57,6 @@ struct intel_dsi {
|
||||
u16 phys; /* ICL DSI */
|
||||
};
|
||||
|
||||
/* if true, use HS mode, otherwise LP */
|
||||
bool hs;
|
||||
|
||||
/* virtual channel */
|
||||
int channel;
|
||||
|
||||
@ -93,7 +90,6 @@ struct intel_dsi {
|
||||
bool bgr_enabled;
|
||||
|
||||
u8 pixel_overlap;
|
||||
u32 port_bits;
|
||||
u32 bw_timer;
|
||||
u32 dphy_reg;
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_edid.h>
|
||||
|
||||
#include "i915_drv.h"
|
||||
#include "i915_reg.h"
|
||||
@ -338,8 +339,12 @@ intel_dvo_detect(struct drm_connector *_connector, bool force)
|
||||
static int intel_dvo_get_modes(struct drm_connector *_connector)
|
||||
{
|
||||
struct intel_connector *connector = to_intel_connector(_connector);
|
||||
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||
int num_modes;
|
||||
|
||||
if (!intel_display_driver_check_access(i915))
|
||||
return drm_edid_connector_add_modes(&connector->base);
|
||||
|
||||
/*
|
||||
* We should probably have an i2c driver get_modes function for those
|
||||
* devices which will have a fixed set of modes determined by the chip
|
||||
|
@ -53,12 +53,6 @@ struct intel_dvo_dev_ops {
|
||||
bool (*init)(struct intel_dvo_device *dvo,
|
||||
struct i2c_adapter *i2cbus);
|
||||
|
||||
/*
|
||||
* Called to allow the output a chance to create properties after the
|
||||
* RandR objects have been created.
|
||||
*/
|
||||
void (*create_resources)(struct intel_dvo_device *dvo);
|
||||
|
||||
/*
|
||||
* Turn on/off output.
|
||||
*
|
||||
@ -79,16 +73,6 @@ struct intel_dvo_dev_ops {
|
||||
enum drm_mode_status (*mode_valid)(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode);
|
||||
|
||||
/*
|
||||
* Callback for preparing mode changes on an output
|
||||
*/
|
||||
void (*prepare)(struct intel_dvo_device *dvo);
|
||||
|
||||
/*
|
||||
* Callback for committing mode changes on an output
|
||||
*/
|
||||
void (*commit)(struct intel_dvo_device *dvo);
|
||||
|
||||
/*
|
||||
* Callback for setting up a video mode after fixups have been made.
|
||||
*
|
||||
@ -111,15 +95,6 @@ struct intel_dvo_dev_ops {
|
||||
*/
|
||||
bool (*get_hw_state)(struct intel_dvo_device *dev);
|
||||
|
||||
/**
|
||||
* Query the device for the modes it provides.
|
||||
*
|
||||
* This function may also update MonInfo, mm_width, and mm_height.
|
||||
*
|
||||
* \return singly-linked list of modes or NULL if no modes found.
|
||||
*/
|
||||
struct drm_display_mode *(*get_modes)(struct intel_dvo_device *dvo);
|
||||
|
||||
/**
|
||||
* Clean up driver-specific bits of the output
|
||||
*/
|
||||
|
@ -1849,9 +1849,10 @@ static int intel_plane_check_stride(const struct intel_plane_state *plane_state)
|
||||
fb->modifier, rotation);
|
||||
|
||||
if (stride > max_stride) {
|
||||
DRM_DEBUG_KMS("[FB:%d] stride (%d) exceeds [PLANE:%d:%s] max stride (%d)\n",
|
||||
fb->base.id, stride,
|
||||
plane->base.base.id, plane->base.name, max_stride);
|
||||
drm_dbg_kms(plane->base.dev,
|
||||
"[FB:%d] stride (%d) exceeds [PLANE:%d:%s] max stride (%d)\n",
|
||||
fb->base.id, stride,
|
||||
plane->base.base.id, plane->base.name, max_stride);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -37,11 +37,11 @@ struct intel_global_obj {
|
||||
(__i)++) \
|
||||
for_each_if(obj)
|
||||
|
||||
#define for_each_old_global_obj_in_state(__state, obj, new_obj_state, __i) \
|
||||
#define for_each_old_global_obj_in_state(__state, obj, old_obj_state, __i) \
|
||||
for ((__i) = 0; \
|
||||
(__i) < (__state)->num_global_objs && \
|
||||
((obj) = (__state)->global_objs[__i].ptr, \
|
||||
(new_obj_state) = (__state)->global_objs[__i].old_state, 1); \
|
||||
(old_obj_state) = (__state)->global_objs[__i].old_state, 1); \
|
||||
(__i)++) \
|
||||
for_each_if(obj)
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
#define KEY_LOAD_TRIES 5
|
||||
#define HDCP2_LC_RETRY_CNT 3
|
||||
|
||||
static int intel_conn_to_vcpi(struct drm_atomic_state *state,
|
||||
static int intel_conn_to_vcpi(struct intel_atomic_state *state,
|
||||
struct intel_connector *connector)
|
||||
{
|
||||
struct drm_dp_mst_topology_mgr *mgr;
|
||||
@ -43,7 +43,7 @@ static int intel_conn_to_vcpi(struct drm_atomic_state *state,
|
||||
return 0;
|
||||
mgr = connector->port->mgr;
|
||||
|
||||
drm_modeset_lock(&mgr->base.lock, state->acquire_ctx);
|
||||
drm_modeset_lock(&mgr->base.lock, state->base.acquire_ctx);
|
||||
mst_state = to_drm_dp_mst_topology_state(mgr->base.state);
|
||||
payload = drm_atomic_get_mst_payload_state(mst_state, connector->port);
|
||||
if (drm_WARN_ON(mgr->dev, !payload))
|
||||
@ -68,19 +68,51 @@ out:
|
||||
* DP MST topology. Though it is not compulsory, security fw should change its
|
||||
* policy to mark different content_types for different streams.
|
||||
*/
|
||||
static void
|
||||
intel_hdcp_required_content_stream(struct intel_digital_port *dig_port)
|
||||
static int
|
||||
intel_hdcp_required_content_stream(struct intel_atomic_state *state,
|
||||
struct intel_digital_port *dig_port)
|
||||
{
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
struct intel_digital_port *conn_dig_port;
|
||||
struct intel_connector *connector;
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||
bool enforce_type0 = false;
|
||||
int k;
|
||||
|
||||
if (dig_port->hdcp_auth_status)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
data->k = 0;
|
||||
|
||||
if (!dig_port->hdcp_mst_type1_capable)
|
||||
enforce_type0 = true;
|
||||
|
||||
drm_connector_list_iter_begin(&i915->drm, &conn_iter);
|
||||
for_each_intel_connector_iter(connector, &conn_iter) {
|
||||
if (connector->base.status == connector_status_disconnected)
|
||||
continue;
|
||||
|
||||
if (!intel_encoder_is_mst(intel_attached_encoder(connector)))
|
||||
continue;
|
||||
|
||||
conn_dig_port = intel_attached_dig_port(connector);
|
||||
if (conn_dig_port != dig_port)
|
||||
continue;
|
||||
|
||||
data->streams[data->k].stream_id =
|
||||
intel_conn_to_vcpi(state, connector);
|
||||
data->k++;
|
||||
|
||||
/* if there is only one active stream */
|
||||
if (dig_port->dp.active_mst_links <= 1)
|
||||
break;
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
|
||||
if (drm_WARN_ON(&i915->drm, data->k > INTEL_NUM_PIPES(i915) || data->k == 0))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Apply common protection level across all streams in DP MST Topology.
|
||||
* Use highest supported content type for all streams in DP MST Topology.
|
||||
@ -88,19 +120,25 @@ intel_hdcp_required_content_stream(struct intel_digital_port *dig_port)
|
||||
for (k = 0; k < data->k; k++)
|
||||
data->streams[k].stream_type =
|
||||
enforce_type0 ? DRM_MODE_HDCP_CONTENT_TYPE0 : DRM_MODE_HDCP_CONTENT_TYPE1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void intel_hdcp_prepare_streams(struct intel_connector *connector)
|
||||
static int intel_hdcp_prepare_streams(struct intel_atomic_state *state,
|
||||
struct intel_connector *connector)
|
||||
{
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
|
||||
if (!intel_encoder_is_mst(intel_attached_encoder(connector))) {
|
||||
data->streams[0].stream_type = hdcp->content_type;
|
||||
} else {
|
||||
intel_hdcp_required_content_stream(dig_port);
|
||||
}
|
||||
if (intel_encoder_is_mst(intel_attached_encoder(connector)))
|
||||
return intel_hdcp_required_content_stream(state, dig_port);
|
||||
|
||||
data->k = 1;
|
||||
data->streams[0].stream_id = 0;
|
||||
data->streams[0].stream_type = hdcp->content_type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
@ -140,7 +178,7 @@ int intel_hdcp_read_valid_bksv(struct intel_digital_port *dig_port,
|
||||
}
|
||||
|
||||
/* Is HDCP1.4 capable on Platform and Sink */
|
||||
bool intel_hdcp_capable(struct intel_connector *connector)
|
||||
bool intel_hdcp_get_capability(struct intel_connector *connector)
|
||||
{
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
const struct intel_hdcp_shim *shim = connector->hdcp.shim;
|
||||
@ -150,8 +188,8 @@ bool intel_hdcp_capable(struct intel_connector *connector)
|
||||
if (!shim)
|
||||
return capable;
|
||||
|
||||
if (shim->hdcp_capable) {
|
||||
shim->hdcp_capable(dig_port, &capable);
|
||||
if (shim->hdcp_get_capability) {
|
||||
shim->hdcp_get_capability(dig_port, &capable);
|
||||
} else {
|
||||
if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
|
||||
capable = true;
|
||||
@ -160,12 +198,14 @@ bool intel_hdcp_capable(struct intel_connector *connector)
|
||||
return capable;
|
||||
}
|
||||
|
||||
/* Is HDCP2.2 capable on Platform and Sink */
|
||||
bool intel_hdcp2_capable(struct intel_connector *connector)
|
||||
/*
|
||||
* Check if the source has all the building blocks ready to make
|
||||
* HDCP 2.2 work
|
||||
*/
|
||||
static bool intel_hdcp2_prerequisite(struct intel_connector *connector)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
bool capable = false;
|
||||
|
||||
/* I915 support for HDCP2.2 */
|
||||
if (!hdcp->hdcp2_supported)
|
||||
@ -185,12 +225,40 @@ bool intel_hdcp2_capable(struct intel_connector *connector)
|
||||
}
|
||||
mutex_unlock(&i915->display.hdcp.hdcp_mutex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Is HDCP2.2 capable on Platform and Sink */
|
||||
bool intel_hdcp2_get_capability(struct intel_connector *connector)
|
||||
{
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
bool capable = false;
|
||||
|
||||
if (!intel_hdcp2_prerequisite(connector))
|
||||
return false;
|
||||
|
||||
/* Sink's capability for HDCP2.2 */
|
||||
hdcp->shim->hdcp_2_2_capable(connector, &capable);
|
||||
hdcp->shim->hdcp_2_2_get_capability(connector, &capable);
|
||||
|
||||
return capable;
|
||||
}
|
||||
|
||||
void intel_hdcp_get_remote_capability(struct intel_connector *connector,
|
||||
bool *hdcp_capable,
|
||||
bool *hdcp2_capable)
|
||||
{
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
|
||||
if (!hdcp->shim->get_remote_hdcp_capability)
|
||||
return;
|
||||
|
||||
hdcp->shim->get_remote_hdcp_capability(connector, hdcp_capable,
|
||||
hdcp2_capable);
|
||||
|
||||
if (!intel_hdcp2_prerequisite(connector))
|
||||
*hdcp2_capable = false;
|
||||
}
|
||||
|
||||
static bool intel_hdcp_in_use(struct drm_i915_private *i915,
|
||||
enum transcoder cpu_transcoder, enum port port)
|
||||
{
|
||||
@ -726,8 +794,8 @@ static int intel_hdcp_auth(struct intel_connector *connector)
|
||||
* whether the display supports HDCP before we write An. For HDMI
|
||||
* displays, this is not necessary.
|
||||
*/
|
||||
if (shim->hdcp_capable) {
|
||||
ret = shim->hdcp_capable(dig_port, &hdcp_capable);
|
||||
if (shim->hdcp_get_capability) {
|
||||
ret = shim->hdcp_get_capability(dig_port, &hdcp_capable);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!hdcp_capable) {
|
||||
@ -1058,15 +1126,9 @@ static int intel_hdcp_check_link(struct intel_connector *connector)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = intel_hdcp1_enable(connector);
|
||||
if (ret) {
|
||||
drm_err(&i915->drm, "Failed to enable hdcp (%d)\n", ret);
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_DESIRED,
|
||||
true);
|
||||
goto out;
|
||||
}
|
||||
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_DESIRED,
|
||||
true);
|
||||
out:
|
||||
mutex_unlock(&dig_port->hdcp_mutex);
|
||||
mutex_unlock(&hdcp->mutex);
|
||||
@ -1871,7 +1933,8 @@ hdcp2_propagate_stream_management_info(struct intel_connector *connector)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
|
||||
static int hdcp2_authenticate_and_encrypt(struct intel_atomic_state *state,
|
||||
struct intel_connector *connector)
|
||||
{
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||
@ -1880,7 +1943,13 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
|
||||
for (i = 0; i < tries && !dig_port->hdcp_auth_status; i++) {
|
||||
ret = hdcp2_authenticate_sink(connector);
|
||||
if (!ret) {
|
||||
intel_hdcp_prepare_streams(connector);
|
||||
ret = intel_hdcp_prepare_streams(state, connector);
|
||||
if (ret) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Prepare stream failed.(%d)\n",
|
||||
ret);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = hdcp2_propagate_stream_management_info(connector);
|
||||
if (ret) {
|
||||
@ -1925,7 +1994,8 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _intel_hdcp2_enable(struct intel_connector *connector)
|
||||
static int _intel_hdcp2_enable(struct intel_atomic_state *state,
|
||||
struct intel_connector *connector)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
@ -1935,7 +2005,7 @@ static int _intel_hdcp2_enable(struct intel_connector *connector)
|
||||
connector->base.base.id, connector->base.name,
|
||||
hdcp->content_type);
|
||||
|
||||
ret = hdcp2_authenticate_and_encrypt(connector);
|
||||
ret = hdcp2_authenticate_and_encrypt(state, connector);
|
||||
if (ret) {
|
||||
drm_dbg_kms(&i915->drm, "HDCP2 Type%d Enabling Failed. (%d)\n",
|
||||
hdcp->content_type, ret);
|
||||
@ -2038,17 +2108,6 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
|
||||
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"HDCP2.2 Downstream topology change\n");
|
||||
ret = hdcp2_authenticate_repeater_topology(connector);
|
||||
if (!ret) {
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_ENABLED,
|
||||
true);
|
||||
goto out;
|
||||
}
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[CONNECTOR:%d:%s] Repeater topology auth failed.(%d)\n",
|
||||
connector->base.base.id, connector->base.name,
|
||||
ret);
|
||||
} else {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[CONNECTOR:%d:%s] HDCP2.2 link failed, retrying auth\n",
|
||||
@ -2065,18 +2124,8 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = _intel_hdcp2_enable(connector);
|
||||
if (ret) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[CONNECTOR:%d:%s] Failed to enable hdcp2.2 (%d)\n",
|
||||
connector->base.base.id, connector->base.name,
|
||||
ret);
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_DESIRED,
|
||||
true);
|
||||
goto out;
|
||||
}
|
||||
|
||||
intel_hdcp_update_value(connector,
|
||||
DRM_MODE_CONTENT_PROTECTION_DESIRED, true);
|
||||
out:
|
||||
mutex_unlock(&dig_port->hdcp_mutex);
|
||||
mutex_unlock(&hdcp->mutex);
|
||||
@ -2284,52 +2333,6 @@ int intel_hdcp_init(struct intel_connector *connector,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_hdcp_set_streams(struct intel_digital_port *dig_port,
|
||||
struct intel_atomic_state *state)
|
||||
{
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
struct intel_digital_port *conn_dig_port;
|
||||
struct intel_connector *connector;
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||
|
||||
if (!intel_encoder_is_mst(&dig_port->base)) {
|
||||
data->k = 1;
|
||||
data->streams[0].stream_id = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
data->k = 0;
|
||||
|
||||
drm_connector_list_iter_begin(&i915->drm, &conn_iter);
|
||||
for_each_intel_connector_iter(connector, &conn_iter) {
|
||||
if (connector->base.status == connector_status_disconnected)
|
||||
continue;
|
||||
|
||||
if (!intel_encoder_is_mst(intel_attached_encoder(connector)))
|
||||
continue;
|
||||
|
||||
conn_dig_port = intel_attached_dig_port(connector);
|
||||
if (conn_dig_port != dig_port)
|
||||
continue;
|
||||
|
||||
data->streams[data->k].stream_id =
|
||||
intel_conn_to_vcpi(&state->base, connector);
|
||||
data->k++;
|
||||
|
||||
/* if there is only one active stream */
|
||||
if (dig_port->dp.active_mst_links <= 1)
|
||||
break;
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
|
||||
if (drm_WARN_ON(&i915->drm, data->k > INTEL_NUM_PIPES(i915) || data->k == 0))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _intel_hdcp_enable(struct intel_atomic_state *state,
|
||||
struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *pipe_config,
|
||||
@ -2374,25 +2377,18 @@ static int _intel_hdcp_enable(struct intel_atomic_state *state,
|
||||
* Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
|
||||
* is capable of HDCP2.2, it is preferred to use HDCP2.2.
|
||||
*/
|
||||
if (intel_hdcp2_capable(connector)) {
|
||||
ret = intel_hdcp_set_streams(dig_port, state);
|
||||
if (!ret) {
|
||||
ret = _intel_hdcp2_enable(connector);
|
||||
if (!ret)
|
||||
check_link_interval =
|
||||
DRM_HDCP2_CHECK_PERIOD_MS;
|
||||
} else {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Set content streams failed: (%d)\n",
|
||||
ret);
|
||||
}
|
||||
if (intel_hdcp2_get_capability(connector)) {
|
||||
ret = _intel_hdcp2_enable(state, connector);
|
||||
if (!ret)
|
||||
check_link_interval =
|
||||
DRM_HDCP2_CHECK_PERIOD_MS;
|
||||
}
|
||||
|
||||
/*
|
||||
* When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
|
||||
* be attempted.
|
||||
*/
|
||||
if (ret && intel_hdcp_capable(connector) &&
|
||||
if (ret && intel_hdcp_get_capability(connector) &&
|
||||
hdcp->content_type != DRM_MODE_HDCP_CONTENT_TYPE1) {
|
||||
ret = intel_hdcp1_enable(connector);
|
||||
}
|
||||
|
@ -38,8 +38,11 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state,
|
||||
const struct intel_crtc_state *crtc_state,
|
||||
const struct drm_connector_state *conn_state);
|
||||
bool is_hdcp_supported(struct drm_i915_private *i915, enum port port);
|
||||
bool intel_hdcp_capable(struct intel_connector *connector);
|
||||
bool intel_hdcp2_capable(struct intel_connector *connector);
|
||||
bool intel_hdcp_get_capability(struct intel_connector *connector);
|
||||
bool intel_hdcp2_get_capability(struct intel_connector *connector);
|
||||
void intel_hdcp_get_remote_capability(struct intel_connector *connector,
|
||||
bool *hdcp_capable,
|
||||
bool *hdcp2_capable);
|
||||
void intel_hdcp_component_init(struct drm_i915_private *i915);
|
||||
void intel_hdcp_component_fini(struct drm_i915_private *i915);
|
||||
void intel_hdcp_cleanup(struct intel_connector *connector);
|
||||
|
@ -1732,8 +1732,8 @@ int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
|
||||
}
|
||||
|
||||
static
|
||||
int intel_hdmi_hdcp2_capable(struct intel_connector *connector,
|
||||
bool *capable)
|
||||
int intel_hdmi_hdcp2_get_capability(struct intel_connector *connector,
|
||||
bool *capable)
|
||||
{
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
u8 hdcp2_version;
|
||||
@ -1762,7 +1762,7 @@ static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = {
|
||||
.write_2_2_msg = intel_hdmi_hdcp2_write_msg,
|
||||
.read_2_2_msg = intel_hdmi_hdcp2_read_msg,
|
||||
.check_2_2_link = intel_hdmi_hdcp2_check_link,
|
||||
.hdcp_2_2_capable = intel_hdmi_hdcp2_capable,
|
||||
.hdcp_2_2_get_capability = intel_hdmi_hdcp2_get_capability,
|
||||
.protocol = HDCP_PROTOCOL_HDMI,
|
||||
};
|
||||
|
||||
|
@ -6,26 +6,41 @@
|
||||
#include "i915_drv.h"
|
||||
|
||||
#include "intel_atomic.h"
|
||||
#include "intel_crtc.h"
|
||||
#include "intel_display_types.h"
|
||||
#include "intel_dp_mst.h"
|
||||
#include "intel_dp_tunnel.h"
|
||||
#include "intel_fdi.h"
|
||||
#include "intel_link_bw.h"
|
||||
|
||||
/**
|
||||
* intel_link_bw_init_limits - initialize BW limits
|
||||
* @i915: device instance
|
||||
* @state: Atomic state
|
||||
* @limits: link BW limits
|
||||
*
|
||||
* Initialize @limits.
|
||||
*/
|
||||
void intel_link_bw_init_limits(struct drm_i915_private *i915, struct intel_link_bw_limits *limits)
|
||||
void intel_link_bw_init_limits(struct intel_atomic_state *state,
|
||||
struct intel_link_bw_limits *limits)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(state->base.dev);
|
||||
enum pipe pipe;
|
||||
|
||||
limits->force_fec_pipes = 0;
|
||||
limits->bpp_limit_reached_pipes = 0;
|
||||
for_each_pipe(i915, pipe)
|
||||
limits->max_bpp_x16[pipe] = INT_MAX;
|
||||
for_each_pipe(i915, pipe) {
|
||||
const struct intel_crtc_state *crtc_state =
|
||||
intel_atomic_get_new_crtc_state(state,
|
||||
intel_crtc_for_pipe(i915, pipe));
|
||||
|
||||
if (state->base.duplicated && crtc_state) {
|
||||
limits->max_bpp_x16[pipe] = crtc_state->max_link_bpp_x16;
|
||||
if (crtc_state->fec_enable)
|
||||
limits->force_fec_pipes |= BIT(pipe);
|
||||
} else {
|
||||
limits->max_bpp_x16[pipe] = INT_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,6 +164,10 @@ static int check_all_link_config(struct intel_atomic_state *state,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = intel_dp_tunnel_atomic_check_link(state, limits);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = intel_fdi_atomic_check_link(state, limits);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -22,7 +22,7 @@ struct intel_link_bw_limits {
|
||||
int max_bpp_x16[I915_MAX_PIPES];
|
||||
};
|
||||
|
||||
void intel_link_bw_init_limits(struct drm_i915_private *i915,
|
||||
void intel_link_bw_init_limits(struct intel_atomic_state *state,
|
||||
struct intel_link_bw_limits *limits);
|
||||
int intel_link_bw_reduce_bpp(struct intel_atomic_state *state,
|
||||
struct intel_link_bw_limits *limits,
|
||||
|
@ -887,7 +887,7 @@ static int intel_load_vbt_firmware(struct drm_i915_private *dev_priv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (intel_bios_is_valid_vbt(fw->data, fw->size)) {
|
||||
if (intel_bios_is_valid_vbt(dev_priv, fw->data, fw->size)) {
|
||||
opregion->vbt_firmware = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
||||
if (opregion->vbt_firmware) {
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
@ -1034,7 +1034,7 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
|
||||
|
||||
vbt = opregion->rvda;
|
||||
vbt_size = opregion->asle->rvds;
|
||||
if (intel_bios_is_valid_vbt(vbt, vbt_size)) {
|
||||
if (intel_bios_is_valid_vbt(dev_priv, vbt, vbt_size)) {
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
"Found valid VBT in ACPI OpRegion (RVDA)\n");
|
||||
opregion->vbt = vbt;
|
||||
@ -1059,7 +1059,7 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv)
|
||||
vbt_size = (mboxes & MBOX_ASLE_EXT) ?
|
||||
OPREGION_ASLE_EXT_OFFSET : OPREGION_SIZE;
|
||||
vbt_size -= OPREGION_VBT_OFFSET;
|
||||
if (intel_bios_is_valid_vbt(vbt, vbt_size)) {
|
||||
if (intel_bios_is_valid_vbt(dev_priv, vbt, vbt_size)) {
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
"Found valid VBT in ACPI OpRegion (Mailbox #4)\n");
|
||||
opregion->vbt = vbt;
|
||||
|
@ -252,6 +252,7 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
|
||||
|
||||
static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = intel_sdvo->slave_addr,
|
||||
@ -271,7 +272,7 @@ static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
|
||||
if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2)
|
||||
return true;
|
||||
|
||||
DRM_DEBUG_KMS("i2c transfer returned %d\n", ret);
|
||||
drm_dbg_kms(&i915->drm, "i2c transfer returned %d\n", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -437,7 +438,8 @@ static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
|
||||
drm_WARN_ON(&dev_priv->drm, pos >= sizeof(buffer) - 1);
|
||||
#undef BUF_PRINT
|
||||
|
||||
DRM_DEBUG_KMS("%s: W: %02X %s\n", SDVO_NAME(intel_sdvo), cmd, buffer);
|
||||
drm_dbg_kms(&dev_priv->drm, "%s: W: %02X %s\n", SDVO_NAME(intel_sdvo),
|
||||
cmd, buffer);
|
||||
}
|
||||
|
||||
static const char * const cmd_status_names[] = {
|
||||
@ -462,6 +464,7 @@ static bool __intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
|
||||
const void *args, int args_len,
|
||||
bool unlocked)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
|
||||
u8 *buf, status;
|
||||
struct i2c_msg *msgs;
|
||||
int i, ret = true;
|
||||
@ -511,13 +514,13 @@ static bool __intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
|
||||
else
|
||||
ret = __i2c_transfer(intel_sdvo->i2c, msgs, i+3);
|
||||
if (ret < 0) {
|
||||
DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
|
||||
drm_dbg_kms(&i915->drm, "I2c transfer returned %d\n", ret);
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
if (ret != i+3) {
|
||||
/* failure in I2C transfer */
|
||||
DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3);
|
||||
drm_dbg_kms(&i915->drm, "I2c transfer returned %d/%d\n", ret, i+3);
|
||||
ret = false;
|
||||
}
|
||||
|
||||
@ -604,12 +607,13 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
|
||||
drm_WARN_ON(&dev_priv->drm, pos >= sizeof(buffer) - 1);
|
||||
#undef BUF_PRINT
|
||||
|
||||
DRM_DEBUG_KMS("%s: R: %s\n", SDVO_NAME(intel_sdvo), buffer);
|
||||
drm_dbg_kms(&dev_priv->drm, "%s: R: %s\n",
|
||||
SDVO_NAME(intel_sdvo), buffer);
|
||||
return true;
|
||||
|
||||
log_fail:
|
||||
DRM_DEBUG_KMS("%s: R: ... failed %s\n",
|
||||
SDVO_NAME(intel_sdvo), buffer);
|
||||
drm_dbg_kms(&dev_priv->drm, "%s: R: ... failed %s\n",
|
||||
SDVO_NAME(intel_sdvo), buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -758,7 +762,7 @@ static bool intel_sdvo_get_timing(struct intel_sdvo *intel_sdvo, u8 cmd,
|
||||
}
|
||||
|
||||
static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo,
|
||||
struct intel_sdvo_dtd *dtd)
|
||||
struct intel_sdvo_dtd *dtd)
|
||||
{
|
||||
return intel_sdvo_set_timing(intel_sdvo,
|
||||
SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd);
|
||||
@ -926,8 +930,8 @@ static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo)
|
||||
|
||||
BUILD_BUG_ON(sizeof(encode) != 2);
|
||||
return intel_sdvo_get_value(intel_sdvo,
|
||||
SDVO_CMD_GET_SUPP_ENCODE,
|
||||
&encode, sizeof(encode));
|
||||
SDVO_CMD_GET_SUPP_ENCODE,
|
||||
&encode, sizeof(encode));
|
||||
}
|
||||
|
||||
static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo,
|
||||
@ -1004,6 +1008,7 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
|
||||
unsigned int if_index, u8 tx_rate,
|
||||
const u8 *data, unsigned int length)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
|
||||
u8 set_buf_index[2] = { if_index, 0 };
|
||||
u8 hbuf_size, tmp[8];
|
||||
int i;
|
||||
@ -1016,8 +1021,9 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
|
||||
if (!intel_sdvo_get_hbuf_size(intel_sdvo, &hbuf_size))
|
||||
return false;
|
||||
|
||||
DRM_DEBUG_KMS("writing sdvo hbuf: %i, length %u, hbuf_size: %i\n",
|
||||
if_index, length, hbuf_size);
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"writing sdvo hbuf: %i, length %u, hbuf_size: %i\n",
|
||||
if_index, length, hbuf_size);
|
||||
|
||||
if (hbuf_size < length)
|
||||
return false;
|
||||
@ -1042,6 +1048,7 @@ static ssize_t intel_sdvo_read_infoframe(struct intel_sdvo *intel_sdvo,
|
||||
unsigned int if_index,
|
||||
u8 *data, unsigned int length)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
|
||||
u8 set_buf_index[2] = { if_index, 0 };
|
||||
u8 hbuf_size, tx_rate, av_split;
|
||||
int i;
|
||||
@ -1071,8 +1078,9 @@ static ssize_t intel_sdvo_read_infoframe(struct intel_sdvo *intel_sdvo,
|
||||
if (!intel_sdvo_get_hbuf_size(intel_sdvo, &hbuf_size))
|
||||
return false;
|
||||
|
||||
DRM_DEBUG_KMS("reading sdvo hbuf: %i, length %u, hbuf_size: %i\n",
|
||||
if_index, length, hbuf_size);
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"reading sdvo hbuf: %i, length %u, hbuf_size: %i\n",
|
||||
if_index, length, hbuf_size);
|
||||
|
||||
hbuf_size = min_t(unsigned int, length, hbuf_size);
|
||||
|
||||
@ -1151,6 +1159,7 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
|
||||
static void intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
|
||||
struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
|
||||
u8 sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
|
||||
union hdmi_infoframe *frame = &crtc_state->infoframes.avi;
|
||||
ssize_t len;
|
||||
@ -1162,7 +1171,7 @@ static void intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
|
||||
len = intel_sdvo_read_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
|
||||
sdvo_data, sizeof(sdvo_data));
|
||||
if (len < 0) {
|
||||
DRM_DEBUG_KMS("failed to read AVI infoframe\n");
|
||||
drm_dbg_kms(&i915->drm, "failed to read AVI infoframe\n");
|
||||
return;
|
||||
} else if (len == 0) {
|
||||
return;
|
||||
@ -1173,13 +1182,14 @@ static void intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
|
||||
|
||||
ret = hdmi_infoframe_unpack(frame, sdvo_data, len);
|
||||
if (ret) {
|
||||
DRM_DEBUG_KMS("Failed to unpack AVI infoframe\n");
|
||||
drm_dbg_kms(&i915->drm, "Failed to unpack AVI infoframe\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (frame->any.type != HDMI_INFOFRAME_TYPE_AVI)
|
||||
DRM_DEBUG_KMS("Found the wrong infoframe type 0x%x (expected 0x%02x)\n",
|
||||
frame->any.type, HDMI_INFOFRAME_TYPE_AVI);
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"Found the wrong infoframe type 0x%x (expected 0x%02x)\n",
|
||||
frame->any.type, HDMI_INFOFRAME_TYPE_AVI);
|
||||
}
|
||||
|
||||
static void intel_sdvo_get_eld(struct intel_sdvo *intel_sdvo,
|
||||
@ -1348,6 +1358,7 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
|
||||
struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
|
||||
struct intel_sdvo_connector *intel_sdvo_connector =
|
||||
to_intel_sdvo_connector(conn_state->connector);
|
||||
@ -1360,7 +1371,7 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("forcing bpc to 8 for SDVO\n");
|
||||
drm_dbg_kms(&i915->drm, "forcing bpc to 8 for SDVO\n");
|
||||
/* FIXME: Don't increase pipe_bpp */
|
||||
pipe_config->pipe_bpp = 8*3;
|
||||
pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB;
|
||||
@ -1439,7 +1450,7 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
|
||||
|
||||
if (!intel_sdvo_compute_avi_infoframe(intel_sdvo,
|
||||
pipe_config, conn_state)) {
|
||||
DRM_DEBUG_KMS("bad AVI infoframe\n");
|
||||
drm_dbg_kms(&i915->drm, "bad AVI infoframe\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1916,8 +1927,8 @@ static void intel_enable_sdvo(struct intel_atomic_state *state,
|
||||
*/
|
||||
if (success && !input1) {
|
||||
drm_dbg_kms(&dev_priv->drm,
|
||||
"First %s output reported failure to "
|
||||
"sync\n", SDVO_NAME(intel_sdvo));
|
||||
"First %s output reported failure to sync\n",
|
||||
SDVO_NAME(intel_sdvo));
|
||||
}
|
||||
|
||||
if (0)
|
||||
@ -1976,37 +1987,38 @@ intel_sdvo_mode_valid(struct drm_connector *connector,
|
||||
|
||||
static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
|
||||
BUILD_BUG_ON(sizeof(*caps) != 8);
|
||||
if (!intel_sdvo_get_value(intel_sdvo,
|
||||
SDVO_CMD_GET_DEVICE_CAPS,
|
||||
caps, sizeof(*caps)))
|
||||
return false;
|
||||
|
||||
DRM_DEBUG_KMS("SDVO capabilities:\n"
|
||||
" vendor_id: %d\n"
|
||||
" device_id: %d\n"
|
||||
" device_rev_id: %d\n"
|
||||
" sdvo_version_major: %d\n"
|
||||
" sdvo_version_minor: %d\n"
|
||||
" sdvo_num_inputs: %d\n"
|
||||
" smooth_scaling: %d\n"
|
||||
" sharp_scaling: %d\n"
|
||||
" up_scaling: %d\n"
|
||||
" down_scaling: %d\n"
|
||||
" stall_support: %d\n"
|
||||
" output_flags: %d\n",
|
||||
caps->vendor_id,
|
||||
caps->device_id,
|
||||
caps->device_rev_id,
|
||||
caps->sdvo_version_major,
|
||||
caps->sdvo_version_minor,
|
||||
caps->sdvo_num_inputs,
|
||||
caps->smooth_scaling,
|
||||
caps->sharp_scaling,
|
||||
caps->up_scaling,
|
||||
caps->down_scaling,
|
||||
caps->stall_support,
|
||||
caps->output_flags);
|
||||
drm_dbg_kms(&i915->drm, "SDVO capabilities:\n"
|
||||
" vendor_id: %d\n"
|
||||
" device_id: %d\n"
|
||||
" device_rev_id: %d\n"
|
||||
" sdvo_version_major: %d\n"
|
||||
" sdvo_version_minor: %d\n"
|
||||
" sdvo_num_inputs: %d\n"
|
||||
" smooth_scaling: %d\n"
|
||||
" sharp_scaling: %d\n"
|
||||
" up_scaling: %d\n"
|
||||
" down_scaling: %d\n"
|
||||
" stall_support: %d\n"
|
||||
" output_flags: %d\n",
|
||||
caps->vendor_id,
|
||||
caps->device_id,
|
||||
caps->device_rev_id,
|
||||
caps->sdvo_version_major,
|
||||
caps->sdvo_version_minor,
|
||||
caps->sdvo_num_inputs,
|
||||
caps->smooth_scaling,
|
||||
caps->sharp_scaling,
|
||||
caps->up_scaling,
|
||||
caps->down_scaling,
|
||||
caps->stall_support,
|
||||
caps->output_flags);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2038,7 +2050,7 @@ static u16 intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo)
|
||||
return 0;
|
||||
|
||||
if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT,
|
||||
&hotplug, sizeof(hotplug)))
|
||||
&hotplug, sizeof(hotplug)))
|
||||
return 0;
|
||||
|
||||
return hotplug;
|
||||
@ -2121,8 +2133,9 @@ intel_sdvo_connector_matches_edid(struct intel_sdvo_connector *sdvo,
|
||||
bool monitor_is_digital = drm_edid_is_digital(drm_edid);
|
||||
bool connector_is_digital = !!IS_DIGITAL(sdvo);
|
||||
|
||||
DRM_DEBUG_KMS("connector_is_digital? %d, monitor_is_digital? %d\n",
|
||||
connector_is_digital, monitor_is_digital);
|
||||
drm_dbg_kms(sdvo->base.base.dev,
|
||||
"connector_is_digital? %d, monitor_is_digital? %d\n",
|
||||
connector_is_digital, monitor_is_digital);
|
||||
return connector_is_digital == monitor_is_digital;
|
||||
}
|
||||
|
||||
@ -2135,8 +2148,8 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
|
||||
enum drm_connector_status ret;
|
||||
u16 response;
|
||||
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
|
||||
connector->base.id, connector->name);
|
||||
drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s]\n",
|
||||
connector->base.id, connector->name);
|
||||
|
||||
if (!intel_display_device_enabled(i915))
|
||||
return connector_status_disconnected;
|
||||
@ -2153,9 +2166,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
|
||||
&response, 2))
|
||||
return connector_status_unknown;
|
||||
|
||||
DRM_DEBUG_KMS("SDVO response %d %d [%x]\n",
|
||||
response & 0xff, response >> 8,
|
||||
intel_sdvo_connector->output_flag);
|
||||
drm_dbg_kms(&i915->drm, "SDVO response %d %d [%x]\n",
|
||||
response & 0xff, response >> 8,
|
||||
intel_sdvo_connector->output_flag);
|
||||
|
||||
if (response == 0)
|
||||
return connector_status_disconnected;
|
||||
@ -2189,11 +2202,15 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
|
||||
|
||||
static int intel_sdvo_get_ddc_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(connector->dev);
|
||||
int num_modes = 0;
|
||||
const struct drm_edid *drm_edid;
|
||||
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
|
||||
connector->base.id, connector->name);
|
||||
drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s]\n",
|
||||
connector->base.id, connector->name);
|
||||
|
||||
if (!intel_display_driver_check_access(i915))
|
||||
return drm_edid_connector_add_modes(connector);
|
||||
|
||||
/* set the bus switch and get the modes */
|
||||
drm_edid = intel_sdvo_get_edid(connector);
|
||||
@ -2287,6 +2304,7 @@ static const struct drm_display_mode sdvo_tv_modes[] = {
|
||||
static int intel_sdvo_get_tv_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector));
|
||||
struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
|
||||
struct intel_sdvo_connector *intel_sdvo_connector =
|
||||
to_intel_sdvo_connector(connector);
|
||||
const struct drm_connector_state *conn_state = connector->state;
|
||||
@ -2295,8 +2313,11 @@ static int intel_sdvo_get_tv_modes(struct drm_connector *connector)
|
||||
int num_modes = 0;
|
||||
int i;
|
||||
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
|
||||
connector->base.id, connector->name);
|
||||
drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s]\n",
|
||||
connector->base.id, connector->name);
|
||||
|
||||
if (!intel_display_driver_check_access(i915))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Read the list of supported input resolutions for the selected TV
|
||||
@ -2783,10 +2804,11 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type)
|
||||
struct drm_encoder *encoder = &intel_sdvo->base.base;
|
||||
struct drm_connector *connector;
|
||||
struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
|
||||
struct drm_i915_private *i915 = to_i915(intel_encoder->base.dev);
|
||||
struct intel_connector *intel_connector;
|
||||
struct intel_sdvo_connector *intel_sdvo_connector;
|
||||
|
||||
DRM_DEBUG_KMS("initialising DVI type 0x%x\n", type);
|
||||
drm_dbg_kms(&i915->drm, "initialising DVI type 0x%x\n", type);
|
||||
|
||||
intel_sdvo_connector = intel_sdvo_connector_alloc();
|
||||
if (!intel_sdvo_connector)
|
||||
@ -2797,7 +2819,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type)
|
||||
intel_connector = &intel_sdvo_connector->base;
|
||||
connector = &intel_connector->base;
|
||||
if (intel_sdvo_get_hotplug_support(intel_sdvo) &
|
||||
intel_sdvo_connector->output_flag) {
|
||||
intel_sdvo_connector->output_flag) {
|
||||
intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag;
|
||||
/*
|
||||
* Some SDVO devices have one-shot hotplug interrupts.
|
||||
@ -2832,12 +2854,13 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type)
|
||||
static bool
|
||||
intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, u16 type)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
|
||||
struct drm_encoder *encoder = &intel_sdvo->base.base;
|
||||
struct drm_connector *connector;
|
||||
struct intel_connector *intel_connector;
|
||||
struct intel_sdvo_connector *intel_sdvo_connector;
|
||||
|
||||
DRM_DEBUG_KMS("initialising TV type 0x%x\n", type);
|
||||
drm_dbg_kms(&i915->drm, "initialising TV type 0x%x\n", type);
|
||||
|
||||
intel_sdvo_connector = intel_sdvo_connector_alloc();
|
||||
if (!intel_sdvo_connector)
|
||||
@ -2871,12 +2894,13 @@ err:
|
||||
static bool
|
||||
intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, u16 type)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
|
||||
struct drm_encoder *encoder = &intel_sdvo->base.base;
|
||||
struct drm_connector *connector;
|
||||
struct intel_connector *intel_connector;
|
||||
struct intel_sdvo_connector *intel_sdvo_connector;
|
||||
|
||||
DRM_DEBUG_KMS("initialising analog type 0x%x\n", type);
|
||||
drm_dbg_kms(&i915->drm, "initialising analog type 0x%x\n", type);
|
||||
|
||||
intel_sdvo_connector = intel_sdvo_connector_alloc();
|
||||
if (!intel_sdvo_connector)
|
||||
@ -2908,7 +2932,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
|
||||
struct intel_connector *intel_connector;
|
||||
struct intel_sdvo_connector *intel_sdvo_connector;
|
||||
|
||||
DRM_DEBUG_KMS("initialising LVDS type 0x%x\n", type);
|
||||
drm_dbg_kms(&i915->drm, "initialising LVDS type 0x%x\n", type);
|
||||
|
||||
intel_sdvo_connector = intel_sdvo_connector_alloc();
|
||||
if (!intel_sdvo_connector)
|
||||
@ -2992,6 +3016,7 @@ static bool intel_sdvo_output_init(struct intel_sdvo *sdvo, u16 type)
|
||||
static bool
|
||||
intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
|
||||
static const u16 probe_order[] = {
|
||||
SDVO_OUTPUT_TMDS0,
|
||||
SDVO_OUTPUT_TMDS1,
|
||||
@ -3010,8 +3035,9 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo)
|
||||
flags = intel_sdvo_filter_output_flags(intel_sdvo->caps.output_flags);
|
||||
|
||||
if (flags == 0) {
|
||||
DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%04x)\n",
|
||||
SDVO_NAME(intel_sdvo), intel_sdvo->caps.output_flags);
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"%s: Unknown SDVO output type (0x%04x)\n",
|
||||
SDVO_NAME(intel_sdvo), intel_sdvo->caps.output_flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3073,8 +3099,8 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
|
||||
|
||||
|
||||
intel_sdvo_connector->tv_format =
|
||||
drm_property_create(dev, DRM_MODE_PROP_ENUM,
|
||||
"mode", intel_sdvo_connector->format_supported_num);
|
||||
drm_property_create(dev, DRM_MODE_PROP_ENUM,
|
||||
"mode", intel_sdvo_connector->format_supported_num);
|
||||
if (!intel_sdvo_connector->tv_format)
|
||||
return false;
|
||||
|
||||
@ -3100,8 +3126,8 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
|
||||
state_assignment = response; \
|
||||
drm_object_attach_property(&connector->base, \
|
||||
intel_sdvo_connector->name, 0); \
|
||||
DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \
|
||||
data_value[0], data_value[1], response); \
|
||||
drm_dbg_kms(dev, #name ": max %d, default %d, current %d\n", \
|
||||
data_value[0], data_value[1], response); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@ -3112,6 +3138,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
|
||||
struct intel_sdvo_connector *intel_sdvo_connector,
|
||||
struct intel_sdvo_enhancements_reply enhancements)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
|
||||
struct drm_device *dev = intel_sdvo->base.base.dev;
|
||||
struct drm_connector *connector = &intel_sdvo_connector->base.base;
|
||||
struct drm_connector_state *conn_state = connector->state;
|
||||
@ -3148,10 +3175,9 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
|
||||
return false;
|
||||
|
||||
drm_object_attach_property(&connector->base,
|
||||
intel_sdvo_connector->right, 0);
|
||||
DRM_DEBUG_KMS("h_overscan: max %d, "
|
||||
"default %d, current %d\n",
|
||||
data_value[0], data_value[1], response);
|
||||
intel_sdvo_connector->right, 0);
|
||||
drm_dbg_kms(&i915->drm, "h_overscan: max %d, default %d, current %d\n",
|
||||
data_value[0], data_value[1], response);
|
||||
}
|
||||
|
||||
if (enhancements.overscan_v) {
|
||||
@ -3170,7 +3196,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
|
||||
intel_sdvo_connector->max_vscan = data_value[0];
|
||||
intel_sdvo_connector->top =
|
||||
drm_property_create_range(dev, 0,
|
||||
"top_margin", 0, data_value[0]);
|
||||
"top_margin", 0, data_value[0]);
|
||||
if (!intel_sdvo_connector->top)
|
||||
return false;
|
||||
|
||||
@ -3179,15 +3205,14 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
|
||||
|
||||
intel_sdvo_connector->bottom =
|
||||
drm_property_create_range(dev, 0,
|
||||
"bottom_margin", 0, data_value[0]);
|
||||
"bottom_margin", 0, data_value[0]);
|
||||
if (!intel_sdvo_connector->bottom)
|
||||
return false;
|
||||
|
||||
drm_object_attach_property(&connector->base,
|
||||
intel_sdvo_connector->bottom, 0);
|
||||
DRM_DEBUG_KMS("v_overscan: max %d, "
|
||||
"default %d, current %d\n",
|
||||
data_value[0], data_value[1], response);
|
||||
intel_sdvo_connector->bottom, 0);
|
||||
drm_dbg_kms(&i915->drm, "v_overscan: max %d, default %d, current %d\n",
|
||||
data_value[0], data_value[1], response);
|
||||
}
|
||||
|
||||
ENHANCEMENT(&sdvo_state->tv, hpos, HPOS);
|
||||
@ -3215,7 +3240,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
|
||||
|
||||
drm_object_attach_property(&connector->base,
|
||||
intel_sdvo_connector->dot_crawl, 0);
|
||||
DRM_DEBUG_KMS("dot crawl: current %d\n", response);
|
||||
drm_dbg_kms(&i915->drm, "dot crawl: current %d\n", response);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -3240,6 +3265,7 @@ intel_sdvo_create_enhance_property_lvds(struct intel_sdvo *intel_sdvo,
|
||||
static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
|
||||
struct intel_sdvo_connector *intel_sdvo_connector)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
|
||||
union {
|
||||
struct intel_sdvo_enhancements_reply reply;
|
||||
u16 response;
|
||||
@ -3251,7 +3277,7 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
|
||||
SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
|
||||
&enhancements, sizeof(enhancements)) ||
|
||||
enhancements.response == 0) {
|
||||
DRM_DEBUG_KMS("No enhancement is supported\n");
|
||||
drm_dbg_kms(&i915->drm, "No enhancement is supported\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3471,23 +3497,23 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv,
|
||||
goto err_output;
|
||||
|
||||
drm_dbg_kms(&dev_priv->drm, "%s device VID/DID: %02X:%02X.%02X, "
|
||||
"clock range %dMHz - %dMHz, "
|
||||
"num inputs: %d, "
|
||||
"output 1: %c, output 2: %c\n",
|
||||
SDVO_NAME(intel_sdvo),
|
||||
intel_sdvo->caps.vendor_id, intel_sdvo->caps.device_id,
|
||||
intel_sdvo->caps.device_rev_id,
|
||||
intel_sdvo->pixel_clock_min / 1000,
|
||||
intel_sdvo->pixel_clock_max / 1000,
|
||||
intel_sdvo->caps.sdvo_num_inputs,
|
||||
/* check currently supported outputs */
|
||||
intel_sdvo->caps.output_flags &
|
||||
(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0 |
|
||||
SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_SVID0 |
|
||||
SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_YPRPB0) ? 'Y' : 'N',
|
||||
intel_sdvo->caps.output_flags &
|
||||
(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1 |
|
||||
SDVO_OUTPUT_LVDS1) ? 'Y' : 'N');
|
||||
"clock range %dMHz - %dMHz, "
|
||||
"num inputs: %d, "
|
||||
"output 1: %c, output 2: %c\n",
|
||||
SDVO_NAME(intel_sdvo),
|
||||
intel_sdvo->caps.vendor_id, intel_sdvo->caps.device_id,
|
||||
intel_sdvo->caps.device_rev_id,
|
||||
intel_sdvo->pixel_clock_min / 1000,
|
||||
intel_sdvo->pixel_clock_max / 1000,
|
||||
intel_sdvo->caps.sdvo_num_inputs,
|
||||
/* check currently supported outputs */
|
||||
intel_sdvo->caps.output_flags &
|
||||
(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0 |
|
||||
SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_SVID0 |
|
||||
SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_YPRPB0) ? 'Y' : 'N',
|
||||
intel_sdvo->caps.output_flags &
|
||||
(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1 |
|
||||
SDVO_OUTPUT_LVDS1) ? 'Y' : 'N');
|
||||
return true;
|
||||
|
||||
err_output:
|
||||
|
@ -948,6 +948,11 @@ static u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
|
||||
if (DISPLAY_VER(dev_priv) == 13)
|
||||
plane_ctl |= adlp_plane_ctl_arb_slots(plane_state);
|
||||
|
||||
if (GRAPHICS_VER(dev_priv) >= 20 &&
|
||||
fb->modifier == I915_FORMAT_MOD_4_TILED) {
|
||||
plane_ctl |= PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
|
||||
}
|
||||
|
||||
return plane_ctl;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,12 @@
|
||||
#include "skl_watermark.h"
|
||||
#include "skl_watermark_regs.h"
|
||||
|
||||
/*It is expected that DSB can do posted writes to every register in
|
||||
* the pipe and planes within 100us. For flip queue use case, the
|
||||
* recommended DSB execution time is 100us + one SAGV block time.
|
||||
*/
|
||||
#define DSB_EXE_TIME 100
|
||||
|
||||
static void skl_sagv_disable(struct drm_i915_private *i915);
|
||||
|
||||
/* Stores plane specific WM parameters */
|
||||
@ -2904,12 +2910,51 @@ static int skl_wm_add_affected_planes(struct intel_atomic_state *state,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If Fixed Refresh Rate:
|
||||
* Program DEEP PKG_C_LATENCY Pkg C with highest valid latency from
|
||||
* watermark level1 and up and above. If watermark level 1 is
|
||||
* invalid program it with all 1's.
|
||||
* Program PKG_C_LATENCY Added Wake Time = DSB execution time
|
||||
* If Variable Refresh Rate:
|
||||
* Program DEEP PKG_C_LATENCY Pkg C with all 1's.
|
||||
* Program PKG_C_LATENCY Added Wake Time = 0
|
||||
*/
|
||||
static void
|
||||
skl_program_dpkgc_latency(struct drm_i915_private *i915, bool vrr_enabled)
|
||||
{
|
||||
u32 max_latency = 0;
|
||||
u32 clear = 0, val = 0;
|
||||
u32 added_wake_time = 0;
|
||||
|
||||
if (DISPLAY_VER(i915) < 20)
|
||||
return;
|
||||
|
||||
if (vrr_enabled) {
|
||||
max_latency = LNL_PKG_C_LATENCY_MASK;
|
||||
added_wake_time = 0;
|
||||
} else {
|
||||
max_latency = skl_watermark_max_latency(i915, 1);
|
||||
if (max_latency == 0)
|
||||
max_latency = LNL_PKG_C_LATENCY_MASK;
|
||||
added_wake_time = DSB_EXE_TIME +
|
||||
i915->display.sagv.block_time_us;
|
||||
}
|
||||
|
||||
clear |= LNL_ADDED_WAKE_TIME_MASK | LNL_PKG_C_LATENCY_MASK;
|
||||
val |= REG_FIELD_PREP(LNL_PKG_C_LATENCY_MASK, max_latency);
|
||||
val |= REG_FIELD_PREP(LNL_ADDED_WAKE_TIME_MASK, added_wake_time);
|
||||
|
||||
intel_uncore_rmw(&i915->uncore, LNL_PKG_C_LATENCY, clear, val);
|
||||
}
|
||||
|
||||
static int
|
||||
skl_compute_wm(struct intel_atomic_state *state)
|
||||
{
|
||||
struct intel_crtc *crtc;
|
||||
struct intel_crtc_state __maybe_unused *new_crtc_state;
|
||||
int ret, i;
|
||||
bool vrr_enabled = false;
|
||||
|
||||
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
|
||||
ret = skl_build_pipe_wm(state, crtc);
|
||||
@ -2934,8 +2979,13 @@ skl_compute_wm(struct intel_atomic_state *state)
|
||||
ret = skl_wm_add_affected_planes(state, crtc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (new_crtc_state->vrr.enable)
|
||||
vrr_enabled = true;
|
||||
}
|
||||
|
||||
skl_program_dpkgc_latency(to_i915(state->base.dev), vrr_enabled);
|
||||
|
||||
skl_print_wm_changes(state);
|
||||
|
||||
return 0;
|
||||
@ -3731,11 +3781,11 @@ void skl_watermark_debugfs_register(struct drm_i915_private *i915)
|
||||
&intel_sagv_status_fops);
|
||||
}
|
||||
|
||||
unsigned int skl_watermark_max_latency(struct drm_i915_private *i915)
|
||||
unsigned int skl_watermark_max_latency(struct drm_i915_private *i915, int initial_wm_level)
|
||||
{
|
||||
int level;
|
||||
|
||||
for (level = i915->display.wm.num_levels - 1; level >= 0; level--) {
|
||||
for (level = i915->display.wm.num_levels - 1; level >= initial_wm_level; level--) {
|
||||
unsigned int latency = skl_wm_latency(i915, level, NULL);
|
||||
|
||||
if (latency)
|
||||
|
@ -46,8 +46,8 @@ void skl_watermark_ipc_update(struct drm_i915_private *i915);
|
||||
bool skl_watermark_ipc_enabled(struct drm_i915_private *i915);
|
||||
void skl_watermark_debugfs_register(struct drm_i915_private *i915);
|
||||
|
||||
unsigned int skl_watermark_max_latency(struct drm_i915_private *i915);
|
||||
|
||||
unsigned int skl_watermark_max_latency(struct drm_i915_private *i915,
|
||||
int initial_wm_level);
|
||||
void skl_wm_init(struct drm_i915_private *i915);
|
||||
|
||||
struct intel_dbuf_state {
|
||||
|
@ -157,4 +157,8 @@
|
||||
#define MTL_LATENCY_SAGV _MMIO(0x4578c)
|
||||
#define MTL_LATENCY_QCLK_SAGV REG_GENMASK(12, 0)
|
||||
|
||||
#define LNL_PKG_C_LATENCY _MMIO(0x46460)
|
||||
#define LNL_ADDED_WAKE_TIME_MASK REG_GENMASK(28, 16)
|
||||
#define LNL_PKG_C_LATENCY_MASK REG_GENMASK(12, 0)
|
||||
|
||||
#endif /* __SKL_WATERMARK_REGS_H__ */
|
||||
|
@ -206,8 +206,6 @@ struct intel_guc {
|
||||
u32 ads_golden_ctxt_size;
|
||||
/** @ads_capture_size: size of register lists in the ADS used for error capture */
|
||||
u32 ads_capture_size;
|
||||
/** @ads_engine_usage_size: size of engine usage in the ADS */
|
||||
u32 ads_engine_usage_size;
|
||||
|
||||
/** @lrc_desc_pool_v69: object allocated to hold the GuC LRC descriptor pool */
|
||||
struct i915_vma *lrc_desc_pool_v69;
|
||||
|
@ -152,17 +152,6 @@ struct intel_vgpu_cursor_plane_format {
|
||||
u32 y_hot; /* in pixels */
|
||||
};
|
||||
|
||||
struct intel_vgpu_pipe_format {
|
||||
struct intel_vgpu_primary_plane_format primary;
|
||||
struct intel_vgpu_sprite_plane_format sprite;
|
||||
struct intel_vgpu_cursor_plane_format cursor;
|
||||
enum DDI_PORT ddi_port; /* the DDI port that pipe is connected to */
|
||||
};
|
||||
|
||||
struct intel_vgpu_fb_format {
|
||||
struct intel_vgpu_pipe_format pipes[I915_MAX_PIPES];
|
||||
};
|
||||
|
||||
int intel_vgpu_decode_primary_plane(struct intel_vgpu *vgpu,
|
||||
struct intel_vgpu_primary_plane_format *plane);
|
||||
int intel_vgpu_decode_cursor_plane(struct intel_vgpu *vgpu,
|
||||
|
@ -93,8 +93,6 @@ struct intel_gvt_gtt_gma_ops {
|
||||
struct intel_gvt_gtt {
|
||||
const struct intel_gvt_gtt_pte_ops *pte_ops;
|
||||
const struct intel_gvt_gtt_gma_ops *gma_ops;
|
||||
int (*mm_alloc_page_table)(struct intel_vgpu_mm *mm);
|
||||
void (*mm_free_page_table)(struct intel_vgpu_mm *mm);
|
||||
struct list_head oos_page_use_list_head;
|
||||
struct list_head oos_page_free_list_head;
|
||||
struct mutex ppgtt_mm_lock;
|
||||
@ -210,7 +208,6 @@ struct intel_vgpu_scratch_pt {
|
||||
|
||||
struct intel_vgpu_gtt {
|
||||
struct intel_vgpu_mm *ggtt_mm;
|
||||
unsigned long active_ppgtt_mm_bitmap;
|
||||
struct list_head ppgtt_mm_list_head;
|
||||
struct radix_tree_root spt_tree;
|
||||
struct list_head oos_page_list_head;
|
||||
|
@ -89,7 +89,6 @@ struct intel_vgpu_gm {
|
||||
/* Fences owned by a vGPU */
|
||||
struct intel_vgpu_fence {
|
||||
struct i915_fence_reg *regs[INTEL_GVT_MAX_NUM_FENCES];
|
||||
u32 base;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
@ -119,7 +118,6 @@ struct intel_vgpu_irq {
|
||||
};
|
||||
|
||||
struct intel_vgpu_opregion {
|
||||
bool mapped;
|
||||
void *va;
|
||||
u32 gfn[INTEL_GVT_OPREGION_PAGES];
|
||||
};
|
||||
@ -223,7 +221,6 @@ struct intel_vgpu {
|
||||
|
||||
struct vfio_region *region;
|
||||
int num_regions;
|
||||
struct eventfd_ctx *intx_trigger;
|
||||
struct eventfd_ctx *msi_trigger;
|
||||
|
||||
/*
|
||||
@ -256,7 +253,6 @@ struct intel_gvt_fence {
|
||||
|
||||
/* Special MMIO blocks. */
|
||||
struct gvt_mmio_block {
|
||||
unsigned int device;
|
||||
i915_reg_t offset;
|
||||
unsigned int size;
|
||||
gvt_mmio_func read;
|
||||
@ -444,7 +440,6 @@ int intel_gvt_load_firmware(struct intel_gvt *gvt);
|
||||
#define vgpu_hidden_gmadr_end(vgpu) \
|
||||
(vgpu_hidden_gmadr_base(vgpu) + vgpu_hidden_sz(vgpu) - 1)
|
||||
|
||||
#define vgpu_fence_base(vgpu) (vgpu->fence.base)
|
||||
#define vgpu_fence_sz(vgpu) (vgpu->fence.size)
|
||||
|
||||
/* ring context size i.e. the first 0x50 dwords*/
|
||||
|
@ -40,7 +40,6 @@ struct intel_gvt_irq_info {
|
||||
char *name;
|
||||
i915_reg_t reg_base;
|
||||
enum intel_gvt_event_type bit_to_event[INTEL_GVT_IRQ_BITWIDTH];
|
||||
unsigned long warned;
|
||||
int group;
|
||||
DECLARE_BITMAP(downstream_irq_bitmap, INTEL_GVT_IRQ_BITWIDTH);
|
||||
bool has_upstream_irq;
|
||||
|
@ -177,7 +177,6 @@ enum intel_gvt_irq_type {
|
||||
/* per-event information */
|
||||
struct intel_gvt_event_info {
|
||||
int bit; /* map to register bit */
|
||||
int policy; /* forwarding policy */
|
||||
struct intel_gvt_irq_info *info; /* register info */
|
||||
gvt_event_virt_handler_t v_handler; /* for v_event */
|
||||
};
|
||||
@ -188,7 +187,6 @@ struct intel_gvt_irq {
|
||||
struct intel_gvt_irq_info *info[INTEL_GVT_IRQ_INFO_MAX];
|
||||
DECLARE_BITMAP(irq_info_bitmap, INTEL_GVT_IRQ_INFO_MAX);
|
||||
struct intel_gvt_event_info events[INTEL_GVT_EVENT_MAX];
|
||||
DECLARE_BITMAP(pending_events, INTEL_GVT_EVENT_MAX);
|
||||
struct intel_gvt_irq_map *irq_map;
|
||||
};
|
||||
|
||||
|
@ -62,10 +62,8 @@ typedef int (*gvt_mmio_func)(struct intel_vgpu *, unsigned int, void *,
|
||||
struct intel_gvt_mmio_info {
|
||||
u32 offset;
|
||||
u64 ro_mask;
|
||||
u32 device;
|
||||
gvt_mmio_func read;
|
||||
gvt_mmio_func write;
|
||||
u32 addr_range;
|
||||
struct hlist_node node;
|
||||
};
|
||||
|
||||
|
@ -104,10 +104,8 @@ struct intel_vgpu_workload {
|
||||
|
||||
/* execlist context information */
|
||||
struct execlist_ctx_descriptor_format ctx_desc;
|
||||
struct execlist_ring_context *ring_context;
|
||||
unsigned long rb_head, rb_tail, rb_ctl, rb_start, rb_len;
|
||||
unsigned long guest_rb_head;
|
||||
bool restore_inhibit;
|
||||
struct intel_vgpu_elsp_dwords elsp_dwords;
|
||||
bool emulate_schedule_in;
|
||||
atomic_t shadow_ctx_active;
|
||||
|
@ -24,8 +24,6 @@ struct drm_printer;
|
||||
struct i915_drm_client {
|
||||
struct kref kref;
|
||||
|
||||
unsigned int id;
|
||||
|
||||
spinlock_t ctx_lock; /* For add/remove from ctx_list. */
|
||||
struct list_head ctx_list; /* List of contexts belonging to client. */
|
||||
|
||||
|
@ -288,7 +288,6 @@ struct i915_perf_stream {
|
||||
struct i915_vma *vma;
|
||||
u8 *vaddr;
|
||||
u32 last_ctx_id;
|
||||
int size_exponent;
|
||||
|
||||
/**
|
||||
* @oa_buffer.ptr_lock: Locks reads and writes to all
|
||||
|
@ -52,7 +52,6 @@
|
||||
struct execute_cb {
|
||||
struct irq_work work;
|
||||
struct i915_sw_fence *fence;
|
||||
struct i915_request *signal;
|
||||
};
|
||||
|
||||
static struct kmem_cache *slab_requests;
|
||||
|
@ -290,7 +290,6 @@ struct i915_vma {
|
||||
|
||||
struct list_head obj_link; /* Link in the object's VMA list */
|
||||
struct rb_node obj_node;
|
||||
struct hlist_node obj_hash;
|
||||
|
||||
/** This vma's place in the eviction list */
|
||||
struct list_head evict_link;
|
||||
|
@ -50,8 +50,6 @@ enum intel_region_id {
|
||||
for_each_if((mr) = (i915)->mm.regions[id])
|
||||
|
||||
struct intel_memory_region_ops {
|
||||
unsigned int flags;
|
||||
|
||||
int (*init)(struct intel_memory_region *mem);
|
||||
int (*release)(struct intel_memory_region *mem);
|
||||
|
||||
|
@ -1081,6 +1081,7 @@
|
||||
# define STREAM_STATUS_CHANGED (1 << 2)
|
||||
# define HDMI_LINK_STATUS_CHANGED (1 << 3)
|
||||
# define CONNECTED_OFF_ENTRY_REQUESTED (1 << 4)
|
||||
# define DP_TUNNELING_IRQ (1 << 5)
|
||||
|
||||
#define DP_PSR_ERROR_STATUS 0x2006 /* XXX 1.2? */
|
||||
# define DP_PSR_LINK_CRC_ERROR (1 << 0)
|
||||
@ -1382,6 +1383,66 @@
|
||||
#define DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET 0x69494
|
||||
#define DP_HDCP_2_2_REG_DBG_OFFSET 0x69518
|
||||
|
||||
/* DP-tunneling */
|
||||
#define DP_TUNNELING_OUI 0xe0000
|
||||
#define DP_TUNNELING_OUI_BYTES 3
|
||||
|
||||
#define DP_TUNNELING_DEV_ID 0xe0003
|
||||
#define DP_TUNNELING_DEV_ID_BYTES 6
|
||||
|
||||
#define DP_TUNNELING_HW_REV 0xe0009
|
||||
#define DP_TUNNELING_HW_REV_MAJOR_SHIFT 4
|
||||
#define DP_TUNNELING_HW_REV_MAJOR_MASK (0xf << DP_TUNNELING_HW_REV_MAJOR_SHIFT)
|
||||
#define DP_TUNNELING_HW_REV_MINOR_SHIFT 0
|
||||
#define DP_TUNNELING_HW_REV_MINOR_MASK (0xf << DP_TUNNELING_HW_REV_MINOR_SHIFT)
|
||||
|
||||
#define DP_TUNNELING_SW_REV_MAJOR 0xe000a
|
||||
#define DP_TUNNELING_SW_REV_MINOR 0xe000b
|
||||
|
||||
#define DP_TUNNELING_CAPABILITIES 0xe000d
|
||||
#define DP_IN_BW_ALLOCATION_MODE_SUPPORT (1 << 7)
|
||||
#define DP_PANEL_REPLAY_OPTIMIZATION_SUPPORT (1 << 6)
|
||||
#define DP_TUNNELING_SUPPORT (1 << 0)
|
||||
|
||||
#define DP_IN_ADAPTER_INFO 0xe000e
|
||||
#define DP_IN_ADAPTER_NUMBER_BITS 7
|
||||
#define DP_IN_ADAPTER_NUMBER_MASK ((1 << DP_IN_ADAPTER_NUMBER_BITS) - 1)
|
||||
|
||||
#define DP_USB4_DRIVER_ID 0xe000f
|
||||
#define DP_USB4_DRIVER_ID_BITS 4
|
||||
#define DP_USB4_DRIVER_ID_MASK ((1 << DP_USB4_DRIVER_ID_BITS) - 1)
|
||||
|
||||
#define DP_USB4_DRIVER_BW_CAPABILITY 0xe0020
|
||||
#define DP_USB4_DRIVER_BW_ALLOCATION_MODE_SUPPORT (1 << 7)
|
||||
|
||||
#define DP_IN_ADAPTER_TUNNEL_INFORMATION 0xe0021
|
||||
#define DP_GROUP_ID_BITS 3
|
||||
#define DP_GROUP_ID_MASK ((1 << DP_GROUP_ID_BITS) - 1)
|
||||
|
||||
#define DP_BW_GRANULARITY 0xe0022
|
||||
#define DP_BW_GRANULARITY_MASK 0x3
|
||||
|
||||
#define DP_ESTIMATED_BW 0xe0023
|
||||
#define DP_ALLOCATED_BW 0xe0024
|
||||
|
||||
#define DP_TUNNELING_STATUS 0xe0025
|
||||
#define DP_BW_ALLOCATION_CAPABILITY_CHANGED (1 << 3)
|
||||
#define DP_ESTIMATED_BW_CHANGED (1 << 2)
|
||||
#define DP_BW_REQUEST_SUCCEEDED (1 << 1)
|
||||
#define DP_BW_REQUEST_FAILED (1 << 0)
|
||||
|
||||
#define DP_TUNNELING_MAX_LINK_RATE 0xe0028
|
||||
|
||||
#define DP_TUNNELING_MAX_LANE_COUNT 0xe0029
|
||||
#define DP_TUNNELING_MAX_LANE_COUNT_MASK 0x1f
|
||||
|
||||
#define DP_DPTX_BW_ALLOCATION_MODE_CONTROL 0xe0030
|
||||
#define DP_DISPLAY_DRIVER_BW_ALLOCATION_MODE_ENABLE (1 << 7)
|
||||
#define DP_UNMASK_BW_ALLOCATION_IRQ (1 << 6)
|
||||
|
||||
#define DP_REQUEST_BW 0xe0031
|
||||
#define MAX_DP_REQUEST_BW 255
|
||||
|
||||
/* LTTPR: Link Training (LT)-tunable PHY Repeaters */
|
||||
#define DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV 0xf0000 /* 1.3 */
|
||||
#define DP_MAX_LINK_RATE_PHY_REPEATER 0xf0001 /* 1.4a */
|
||||
|
@ -811,5 +811,6 @@ int drm_dp_bw_overhead(int lane_count, int hactive,
|
||||
int dsc_slice_count,
|
||||
int bpp_x16, unsigned long flags);
|
||||
int drm_dp_bw_channel_coding_efficiency(bool is_uhbr);
|
||||
int drm_dp_max_dprx_data_rate(int max_link_rate, int max_lanes);
|
||||
|
||||
#endif /* _DRM_DP_HELPER_H_ */
|
||||
|
248
include/drm/display/drm_dp_tunnel.h
Normal file
248
include/drm/display/drm_dp_tunnel.h
Normal file
@ -0,0 +1,248 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2023 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __DRM_DP_TUNNEL_H__
|
||||
#define __DRM_DP_TUNNEL_H__
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct drm_dp_aux;
|
||||
|
||||
struct drm_device;
|
||||
|
||||
struct drm_atomic_state;
|
||||
struct drm_dp_tunnel_mgr;
|
||||
struct drm_dp_tunnel_state;
|
||||
|
||||
struct ref_tracker;
|
||||
|
||||
struct drm_dp_tunnel_ref {
|
||||
struct drm_dp_tunnel *tunnel;
|
||||
struct ref_tracker *tracker;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DRM_DISPLAY_DP_TUNNEL
|
||||
|
||||
struct drm_dp_tunnel *
|
||||
drm_dp_tunnel_get(struct drm_dp_tunnel *tunnel, struct ref_tracker **tracker);
|
||||
|
||||
void
|
||||
drm_dp_tunnel_put(struct drm_dp_tunnel *tunnel, struct ref_tracker **tracker);
|
||||
|
||||
static inline void drm_dp_tunnel_ref_get(struct drm_dp_tunnel *tunnel,
|
||||
struct drm_dp_tunnel_ref *tunnel_ref)
|
||||
{
|
||||
tunnel_ref->tunnel = drm_dp_tunnel_get(tunnel, &tunnel_ref->tracker);
|
||||
}
|
||||
|
||||
static inline void drm_dp_tunnel_ref_put(struct drm_dp_tunnel_ref *tunnel_ref)
|
||||
{
|
||||
drm_dp_tunnel_put(tunnel_ref->tunnel, &tunnel_ref->tracker);
|
||||
tunnel_ref->tunnel = NULL;
|
||||
}
|
||||
|
||||
struct drm_dp_tunnel *
|
||||
drm_dp_tunnel_detect(struct drm_dp_tunnel_mgr *mgr,
|
||||
struct drm_dp_aux *aux);
|
||||
int drm_dp_tunnel_destroy(struct drm_dp_tunnel *tunnel);
|
||||
|
||||
int drm_dp_tunnel_enable_bw_alloc(struct drm_dp_tunnel *tunnel);
|
||||
int drm_dp_tunnel_disable_bw_alloc(struct drm_dp_tunnel *tunnel);
|
||||
bool drm_dp_tunnel_bw_alloc_is_enabled(const struct drm_dp_tunnel *tunnel);
|
||||
int drm_dp_tunnel_alloc_bw(struct drm_dp_tunnel *tunnel, int bw);
|
||||
int drm_dp_tunnel_get_allocated_bw(struct drm_dp_tunnel *tunnel);
|
||||
int drm_dp_tunnel_update_state(struct drm_dp_tunnel *tunnel);
|
||||
|
||||
void drm_dp_tunnel_set_io_error(struct drm_dp_tunnel *tunnel);
|
||||
|
||||
int drm_dp_tunnel_handle_irq(struct drm_dp_tunnel_mgr *mgr,
|
||||
struct drm_dp_aux *aux);
|
||||
|
||||
int drm_dp_tunnel_max_dprx_rate(const struct drm_dp_tunnel *tunnel);
|
||||
int drm_dp_tunnel_max_dprx_lane_count(const struct drm_dp_tunnel *tunnel);
|
||||
int drm_dp_tunnel_available_bw(const struct drm_dp_tunnel *tunnel);
|
||||
|
||||
const char *drm_dp_tunnel_name(const struct drm_dp_tunnel *tunnel);
|
||||
|
||||
struct drm_dp_tunnel_state *
|
||||
drm_dp_tunnel_atomic_get_state(struct drm_atomic_state *state,
|
||||
struct drm_dp_tunnel *tunnel);
|
||||
|
||||
struct drm_dp_tunnel_state *
|
||||
drm_dp_tunnel_atomic_get_old_state(struct drm_atomic_state *state,
|
||||
const struct drm_dp_tunnel *tunnel);
|
||||
|
||||
struct drm_dp_tunnel_state *
|
||||
drm_dp_tunnel_atomic_get_new_state(struct drm_atomic_state *state,
|
||||
const struct drm_dp_tunnel *tunnel);
|
||||
|
||||
int drm_dp_tunnel_atomic_set_stream_bw(struct drm_atomic_state *state,
|
||||
struct drm_dp_tunnel *tunnel,
|
||||
u8 stream_id, int bw);
|
||||
int drm_dp_tunnel_atomic_get_group_streams_in_state(struct drm_atomic_state *state,
|
||||
const struct drm_dp_tunnel *tunnel,
|
||||
u32 *stream_mask);
|
||||
|
||||
int drm_dp_tunnel_atomic_check_stream_bws(struct drm_atomic_state *state,
|
||||
u32 *failed_stream_mask);
|
||||
|
||||
int drm_dp_tunnel_atomic_get_required_bw(const struct drm_dp_tunnel_state *tunnel_state);
|
||||
|
||||
struct drm_dp_tunnel_mgr *
|
||||
drm_dp_tunnel_mgr_create(struct drm_device *dev, int max_group_count);
|
||||
void drm_dp_tunnel_mgr_destroy(struct drm_dp_tunnel_mgr *mgr);
|
||||
|
||||
#else
|
||||
|
||||
static inline struct drm_dp_tunnel *
|
||||
drm_dp_tunnel_get(struct drm_dp_tunnel *tunnel, struct ref_tracker **tracker)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
drm_dp_tunnel_put(struct drm_dp_tunnel *tunnel, struct ref_tracker **tracker) {}
|
||||
|
||||
static inline void drm_dp_tunnel_ref_get(struct drm_dp_tunnel *tunnel,
|
||||
struct drm_dp_tunnel_ref *tunnel_ref) {}
|
||||
|
||||
static inline void drm_dp_tunnel_ref_put(struct drm_dp_tunnel_ref *tunnel_ref) {}
|
||||
|
||||
static inline struct drm_dp_tunnel *
|
||||
drm_dp_tunnel_detect(struct drm_dp_tunnel_mgr *mgr,
|
||||
struct drm_dp_aux *aux)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline int
|
||||
drm_dp_tunnel_destroy(struct drm_dp_tunnel *tunnel)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int drm_dp_tunnel_enable_bw_alloc(struct drm_dp_tunnel *tunnel)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int drm_dp_tunnel_disable_bw_alloc(struct drm_dp_tunnel *tunnel)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline bool drm_dp_tunnel_bw_alloc_is_enabled(const struct drm_dp_tunnel *tunnel)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int
|
||||
drm_dp_tunnel_alloc_bw(struct drm_dp_tunnel *tunnel, int bw)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int
|
||||
drm_dp_tunnel_get_allocated_bw(struct drm_dp_tunnel *tunnel)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
drm_dp_tunnel_update_state(struct drm_dp_tunnel *tunnel)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void drm_dp_tunnel_set_io_error(struct drm_dp_tunnel *tunnel) {}
|
||||
|
||||
static inline int
|
||||
drm_dp_tunnel_handle_irq(struct drm_dp_tunnel_mgr *mgr,
|
||||
struct drm_dp_aux *aux)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int
|
||||
drm_dp_tunnel_max_dprx_rate(const struct drm_dp_tunnel *tunnel)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
drm_dp_tunnel_max_dprx_lane_count(const struct drm_dp_tunnel *tunnel)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
drm_dp_tunnel_available_bw(const struct drm_dp_tunnel *tunnel)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
drm_dp_tunnel_name(const struct drm_dp_tunnel *tunnel)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct drm_dp_tunnel_state *
|
||||
drm_dp_tunnel_atomic_get_state(struct drm_atomic_state *state,
|
||||
struct drm_dp_tunnel *tunnel)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline struct drm_dp_tunnel_state *
|
||||
drm_dp_tunnel_atomic_get_new_state(struct drm_atomic_state *state,
|
||||
const struct drm_dp_tunnel *tunnel)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline int
|
||||
drm_dp_tunnel_atomic_set_stream_bw(struct drm_atomic_state *state,
|
||||
struct drm_dp_tunnel *tunnel,
|
||||
u8 stream_id, int bw)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int
|
||||
drm_dp_tunnel_atomic_get_group_streams_in_state(struct drm_atomic_state *state,
|
||||
const struct drm_dp_tunnel *tunnel,
|
||||
u32 *stream_mask)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int
|
||||
drm_dp_tunnel_atomic_check_stream_bws(struct drm_atomic_state *state,
|
||||
u32 *failed_stream_mask)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int
|
||||
drm_dp_tunnel_atomic_get_required_bw(const struct drm_dp_tunnel_state *tunnel_state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct drm_dp_tunnel_mgr *
|
||||
drm_dp_tunnel_mgr_create(struct drm_device *dev, int max_group_count)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline
|
||||
void drm_dp_tunnel_mgr_destroy(struct drm_dp_tunnel_mgr *mgr) {}
|
||||
|
||||
#endif /* CONFIG_DRM_DISPLAY_DP_TUNNEL */
|
||||
|
||||
#endif /* __DRM_DP_TUNNEL_H__ */
|
@ -672,7 +672,9 @@
|
||||
#define INTEL_ADLN_IDS(info) \
|
||||
INTEL_VGA_DEVICE(0x46D0, info), \
|
||||
INTEL_VGA_DEVICE(0x46D1, info), \
|
||||
INTEL_VGA_DEVICE(0x46D2, info)
|
||||
INTEL_VGA_DEVICE(0x46D2, info), \
|
||||
INTEL_VGA_DEVICE(0x46D3, info), \
|
||||
INTEL_VGA_DEVICE(0x46D4, info)
|
||||
|
||||
/* RPL-S */
|
||||
#define INTEL_RPLS_IDS(info) \
|
||||
|
Loading…
Reference in New Issue
Block a user