Merge tag 'drm-intel-next-2021-01-27' of git://anongit.freedesktop.org/drm/drm-intel into drm-next
- HDCP 2.2 and HDCP 1.4 Gen12 DP MST support (Anshuman) - Fix DP vswing settings and handling (Imre, Ville) - Various display code clean-up (Jani, Ville) - Various display refactoring, including split out of pps, aux, and fdi (Ja\ ni, Dave) - Add DG1 missing workarounds (Jose) - Fix display color conversion (Chris, Ville) - Try to guess PCH type even without ISA bridge (Zhenyu) - More backlight refactor (Lyude) - Support two CSC module on gen11 and later (Lee) - Async flips for all ilk+ platforms (Ville) - Clear color support for TGL (RK) - Add a helper to read data from a GEM object page (Imre) - VRR/Adaptive Sync Enabling on DP/eDP for TGL+ (Manasi, Ville Aditya) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210127140822.GA711686@intel.com
This commit is contained in:
@@ -1236,7 +1236,7 @@ bool drm_dp_read_sink_count_cap(struct drm_connector *connector,
|
|||||||
return connector->connector_type != DRM_MODE_CONNECTOR_eDP &&
|
return connector->connector_type != DRM_MODE_CONNECTOR_eDP &&
|
||||||
dpcd[DP_DPCD_REV] >= DP_DPCD_REV_11 &&
|
dpcd[DP_DPCD_REV] >= DP_DPCD_REV_11 &&
|
||||||
dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT &&
|
dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT &&
|
||||||
!drm_dp_has_quirk(desc, 0, DP_DPCD_QUIRK_NO_SINK_COUNT);
|
!drm_dp_has_quirk(desc, DP_DPCD_QUIRK_NO_SINK_COUNT);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_dp_read_sink_count_cap);
|
EXPORT_SYMBOL(drm_dp_read_sink_count_cap);
|
||||||
|
|
||||||
@@ -1957,87 +1957,6 @@ drm_dp_get_quirks(const struct drm_dp_dpcd_ident *ident, bool is_branch)
|
|||||||
#undef DEVICE_ID_ANY
|
#undef DEVICE_ID_ANY
|
||||||
#undef DEVICE_ID
|
#undef DEVICE_ID
|
||||||
|
|
||||||
struct edid_quirk {
|
|
||||||
u8 mfg_id[2];
|
|
||||||
u8 prod_id[2];
|
|
||||||
u32 quirks;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MFG(first, second) { (first), (second) }
|
|
||||||
#define PROD_ID(first, second) { (first), (second) }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Some devices have unreliable OUIDs where they don't set the device ID
|
|
||||||
* correctly, and as a result we need to use the EDID for finding additional
|
|
||||||
* DP quirks in such cases.
|
|
||||||
*/
|
|
||||||
static const struct edid_quirk edid_quirk_list[] = {
|
|
||||||
/* Optional 4K AMOLED panel in the ThinkPad X1 Extreme 2nd Generation
|
|
||||||
* only supports DPCD backlight controls
|
|
||||||
*/
|
|
||||||
{ MFG(0x4c, 0x83), PROD_ID(0x41, 0x41), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
|
|
||||||
/*
|
|
||||||
* Some Dell CML 2020 systems have panels support both AUX and PWM
|
|
||||||
* backlight control, and some only support AUX backlight control. All
|
|
||||||
* said panels start up in AUX mode by default, and we don't have any
|
|
||||||
* support for disabling HDR mode on these panels which would be
|
|
||||||
* required to switch to PWM backlight control mode (plus, I'm not
|
|
||||||
* even sure we want PWM backlight controls over DPCD backlight
|
|
||||||
* controls anyway...). Until we have a better way of detecting these,
|
|
||||||
* force DPCD backlight mode on all of them.
|
|
||||||
*/
|
|
||||||
{ MFG(0x06, 0xaf), PROD_ID(0x9b, 0x32), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
|
|
||||||
{ MFG(0x06, 0xaf), PROD_ID(0xeb, 0x41), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
|
|
||||||
{ MFG(0x4d, 0x10), PROD_ID(0xc7, 0x14), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
|
|
||||||
{ MFG(0x4d, 0x10), PROD_ID(0xe6, 0x14), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
|
|
||||||
{ MFG(0x4c, 0x83), PROD_ID(0x47, 0x41), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
|
|
||||||
{ MFG(0x09, 0xe5), PROD_ID(0xde, 0x08), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) },
|
|
||||||
};
|
|
||||||
|
|
||||||
#undef MFG
|
|
||||||
#undef PROD_ID
|
|
||||||
|
|
||||||
/**
|
|
||||||
* drm_dp_get_edid_quirks() - Check the EDID of a DP device to find additional
|
|
||||||
* DP-specific quirks
|
|
||||||
* @edid: The EDID to check
|
|
||||||
*
|
|
||||||
* While OUIDs are meant to be used to recognize a DisplayPort device, a lot
|
|
||||||
* of manufacturers don't seem to like following standards and neglect to fill
|
|
||||||
* the dev-ID in, making it impossible to only use OUIDs for determining
|
|
||||||
* quirks in some cases. This function can be used to check the EDID and look
|
|
||||||
* up any additional DP quirks. The bits returned by this function correspond
|
|
||||||
* to the quirk bits in &drm_dp_quirk.
|
|
||||||
*
|
|
||||||
* Returns: a bitmask of quirks, if any. The driver can check this using
|
|
||||||
* drm_dp_has_quirk().
|
|
||||||
*/
|
|
||||||
u32 drm_dp_get_edid_quirks(const struct edid *edid)
|
|
||||||
{
|
|
||||||
const struct edid_quirk *quirk;
|
|
||||||
u32 quirks = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!edid)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) {
|
|
||||||
quirk = &edid_quirk_list[i];
|
|
||||||
if (memcmp(quirk->mfg_id, edid->mfg_id,
|
|
||||||
sizeof(edid->mfg_id)) == 0 &&
|
|
||||||
memcmp(quirk->prod_id, edid->prod_code,
|
|
||||||
sizeof(edid->prod_code)) == 0)
|
|
||||||
quirks |= quirk->quirks;
|
|
||||||
}
|
|
||||||
|
|
||||||
DRM_DEBUG_KMS("DP sink: EDID mfg %*phD prod-ID %*phD quirks: 0x%04x\n",
|
|
||||||
(int)sizeof(edid->mfg_id), edid->mfg_id,
|
|
||||||
(int)sizeof(edid->prod_code), edid->prod_code, quirks);
|
|
||||||
|
|
||||||
return quirks;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(drm_dp_get_edid_quirks);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* drm_dp_read_desc - read sink/branch descriptor from DPCD
|
* drm_dp_read_desc - read sink/branch descriptor from DPCD
|
||||||
* @aux: DisplayPort AUX channel
|
* @aux: DisplayPort AUX channel
|
||||||
|
|||||||
@@ -5824,8 +5824,7 @@ struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port)
|
|||||||
if (drm_dp_read_desc(port->mgr->aux, &desc, true))
|
if (drm_dp_read_desc(port->mgr->aux, &desc, true))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (drm_dp_has_quirk(&desc, 0,
|
if (drm_dp_has_quirk(&desc, DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) &&
|
||||||
DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) &&
|
|
||||||
port->mgr->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14 &&
|
port->mgr->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14 &&
|
||||||
port->parent == port->mgr->mst_primary) {
|
port->parent == port->mgr->mst_primary) {
|
||||||
u8 downstreamport;
|
u8 downstreamport;
|
||||||
|
|||||||
@@ -201,14 +201,17 @@ i915-y += \
|
|||||||
display/intel_color.o \
|
display/intel_color.o \
|
||||||
display/intel_combo_phy.o \
|
display/intel_combo_phy.o \
|
||||||
display/intel_connector.o \
|
display/intel_connector.o \
|
||||||
|
display/intel_crtc.o \
|
||||||
display/intel_csr.o \
|
display/intel_csr.o \
|
||||||
display/intel_cursor.o \
|
display/intel_cursor.o \
|
||||||
display/intel_display.o \
|
display/intel_display.o \
|
||||||
display/intel_display_power.o \
|
display/intel_display_power.o \
|
||||||
display/intel_dpio_phy.o \
|
display/intel_dpio_phy.o \
|
||||||
|
display/intel_dpll.o \
|
||||||
display/intel_dpll_mgr.o \
|
display/intel_dpll_mgr.o \
|
||||||
display/intel_dsb.o \
|
display/intel_dsb.o \
|
||||||
display/intel_fbc.o \
|
display/intel_fbc.o \
|
||||||
|
display/intel_fdi.o \
|
||||||
display/intel_fifo_underrun.o \
|
display/intel_fifo_underrun.o \
|
||||||
display/intel_frontbuffer.o \
|
display/intel_frontbuffer.o \
|
||||||
display/intel_global_state.o \
|
display/intel_global_state.o \
|
||||||
@@ -240,6 +243,7 @@ i915-y += \
|
|||||||
display/intel_crt.o \
|
display/intel_crt.o \
|
||||||
display/intel_ddi.o \
|
display/intel_ddi.o \
|
||||||
display/intel_dp.o \
|
display/intel_dp.o \
|
||||||
|
display/intel_dp_aux.o \
|
||||||
display/intel_dp_aux_backlight.o \
|
display/intel_dp_aux_backlight.o \
|
||||||
display/intel_dp_hdcp.o \
|
display/intel_dp_hdcp.o \
|
||||||
display/intel_dp_link_training.o \
|
display/intel_dp_link_training.o \
|
||||||
@@ -253,9 +257,11 @@ i915-y += \
|
|||||||
display/intel_lspcon.o \
|
display/intel_lspcon.o \
|
||||||
display/intel_lvds.o \
|
display/intel_lvds.o \
|
||||||
display/intel_panel.o \
|
display/intel_panel.o \
|
||||||
|
display/intel_pps.o \
|
||||||
display/intel_sdvo.o \
|
display/intel_sdvo.o \
|
||||||
display/intel_tv.o \
|
display/intel_tv.o \
|
||||||
display/intel_vdsc.o \
|
display/intel_vdsc.o \
|
||||||
|
display/intel_vrr.o \
|
||||||
display/vlv_dsi.o \
|
display/vlv_dsi.o \
|
||||||
display/vlv_dsi_pll.o
|
display/vlv_dsi_pll.o
|
||||||
|
|
||||||
|
|||||||
@@ -452,7 +452,7 @@ void intel_update_plane(struct intel_plane *plane,
|
|||||||
trace_intel_update_plane(&plane->base, crtc);
|
trace_intel_update_plane(&plane->base, crtc);
|
||||||
|
|
||||||
if (crtc_state->uapi.async_flip && plane->async_flip)
|
if (crtc_state->uapi.async_flip && plane->async_flip)
|
||||||
plane->async_flip(plane, crtc_state, plane_state);
|
plane->async_flip(plane, crtc_state, plane_state, true);
|
||||||
else
|
else
|
||||||
plane->update_plane(plane, crtc_state, plane_state);
|
plane->update_plane(plane, crtc_state, plane_state);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1485,6 +1485,7 @@ static u32 ivb_csc_mode(const struct intel_crtc_state *crtc_state)
|
|||||||
|
|
||||||
static int ivb_color_check(struct intel_crtc_state *crtc_state)
|
static int ivb_color_check(struct intel_crtc_state *crtc_state)
|
||||||
{
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
|
||||||
bool limited_color_range = ilk_csc_limited_range(crtc_state);
|
bool limited_color_range = ilk_csc_limited_range(crtc_state);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -1492,6 +1493,13 @@ static int ivb_color_check(struct intel_crtc_state *crtc_state)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB &&
|
||||||
|
crtc_state->hw.ctm) {
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"YCBCR and CTM together are not possible\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
crtc_state->gamma_enable =
|
crtc_state->gamma_enable =
|
||||||
(crtc_state->hw.gamma_lut ||
|
(crtc_state->hw.gamma_lut ||
|
||||||
crtc_state->hw.degamma_lut) &&
|
crtc_state->hw.degamma_lut) &&
|
||||||
@@ -1525,12 +1533,20 @@ static u32 glk_gamma_mode(const struct intel_crtc_state *crtc_state)
|
|||||||
|
|
||||||
static int glk_color_check(struct intel_crtc_state *crtc_state)
|
static int glk_color_check(struct intel_crtc_state *crtc_state)
|
||||||
{
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = check_luts(crtc_state);
|
ret = check_luts(crtc_state);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB &&
|
||||||
|
crtc_state->hw.ctm) {
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"YCBCR and CTM together are not possible\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
crtc_state->gamma_enable =
|
crtc_state->gamma_enable =
|
||||||
crtc_state->hw.gamma_lut &&
|
crtc_state->hw.gamma_lut &&
|
||||||
!crtc_state->c8_planes;
|
!crtc_state->c8_planes;
|
||||||
|
|||||||
325
drivers/gpu/drm/i915/display/intel_crtc.c
Normal file
325
drivers/gpu/drm/i915/display/intel_crtc.c
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
/*
|
||||||
|
* Copyright © 2020 Intel Corporation
|
||||||
|
*/
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#include <drm/drm_atomic_helper.h>
|
||||||
|
#include <drm/drm_fourcc.h>
|
||||||
|
#include <drm/drm_plane.h>
|
||||||
|
#include <drm/drm_plane_helper.h>
|
||||||
|
|
||||||
|
#include "intel_atomic.h"
|
||||||
|
#include "intel_atomic_plane.h"
|
||||||
|
#include "intel_color.h"
|
||||||
|
#include "intel_crtc.h"
|
||||||
|
#include "intel_cursor.h"
|
||||||
|
#include "intel_display_debugfs.h"
|
||||||
|
#include "intel_display_types.h"
|
||||||
|
#include "intel_pipe_crc.h"
|
||||||
|
#include "intel_sprite.h"
|
||||||
|
#include "i9xx_plane.h"
|
||||||
|
|
||||||
|
static void assert_vblank_disabled(struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
if (I915_STATE_WARN_ON(drm_crtc_vblank_get(crtc) == 0))
|
||||||
|
drm_crtc_vblank_put(crtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = crtc->base.dev;
|
||||||
|
struct drm_vblank_crtc *vblank = &dev->vblank[drm_crtc_index(&crtc->base)];
|
||||||
|
|
||||||
|
if (!vblank->max_vblank_count)
|
||||||
|
return (u32)drm_crtc_accurate_vblank_count(&crtc->base);
|
||||||
|
|
||||||
|
return crtc->base.funcs->get_vblank_counter(&crtc->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
|
||||||
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||||
|
u32 mode_flags = crtc->mode_flags;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From Gen 11, In case of dsi cmd mode, frame counter wouldnt
|
||||||
|
* have updated at the beginning of TE, if we want to use
|
||||||
|
* the hw counter, then we would find it updated in only
|
||||||
|
* the next TE, hence switching to sw counter.
|
||||||
|
*/
|
||||||
|
if (mode_flags & (I915_MODE_FLAG_DSI_USE_TE0 | I915_MODE_FLAG_DSI_USE_TE1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On i965gm the hardware frame counter reads
|
||||||
|
* zero when the TV encoder is enabled :(
|
||||||
|
*/
|
||||||
|
if (IS_I965GM(dev_priv) &&
|
||||||
|
(crtc_state->output_types & BIT(INTEL_OUTPUT_TVOUT)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
|
||||||
|
return 0xffffffff; /* full 32 bit counter */
|
||||||
|
else if (INTEL_GEN(dev_priv) >= 3)
|
||||||
|
return 0xffffff; /* only 24 bits of frame count */
|
||||||
|
else
|
||||||
|
return 0; /* Gen2 doesn't have a hardware frame counter */
|
||||||
|
}
|
||||||
|
|
||||||
|
void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||||
|
|
||||||
|
assert_vblank_disabled(&crtc->base);
|
||||||
|
drm_crtc_set_max_vblank_count(&crtc->base,
|
||||||
|
intel_crtc_max_vblank_count(crtc_state));
|
||||||
|
drm_crtc_vblank_on(&crtc->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void intel_crtc_vblank_off(const struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||||
|
|
||||||
|
drm_crtc_vblank_off(&crtc->base);
|
||||||
|
assert_vblank_disabled(&crtc->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct intel_crtc_state *crtc_state;
|
||||||
|
|
||||||
|
crtc_state = kmalloc(sizeof(*crtc_state), GFP_KERNEL);
|
||||||
|
|
||||||
|
if (crtc_state)
|
||||||
|
intel_crtc_state_reset(crtc_state, crtc);
|
||||||
|
|
||||||
|
return crtc_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
|
||||||
|
struct intel_crtc *crtc)
|
||||||
|
{
|
||||||
|
memset(crtc_state, 0, sizeof(*crtc_state));
|
||||||
|
|
||||||
|
__drm_atomic_helper_crtc_state_reset(&crtc_state->uapi, &crtc->base);
|
||||||
|
|
||||||
|
crtc_state->cpu_transcoder = INVALID_TRANSCODER;
|
||||||
|
crtc_state->master_transcoder = INVALID_TRANSCODER;
|
||||||
|
crtc_state->hsw_workaround_pipe = INVALID_PIPE;
|
||||||
|
crtc_state->output_format = INTEL_OUTPUT_FORMAT_INVALID;
|
||||||
|
crtc_state->scaler_state.scaler_id = -1;
|
||||||
|
crtc_state->mst_master_transcoder = INVALID_TRANSCODER;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct intel_crtc *intel_crtc_alloc(void)
|
||||||
|
{
|
||||||
|
struct intel_crtc_state *crtc_state;
|
||||||
|
struct intel_crtc *crtc;
|
||||||
|
|
||||||
|
crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
|
||||||
|
if (!crtc)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
crtc_state = intel_crtc_state_alloc(crtc);
|
||||||
|
if (!crtc_state) {
|
||||||
|
kfree(crtc);
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
crtc->base.state = &crtc_state->uapi;
|
||||||
|
crtc->config = crtc_state;
|
||||||
|
|
||||||
|
return crtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void intel_crtc_free(struct intel_crtc *crtc)
|
||||||
|
{
|
||||||
|
intel_crtc_destroy_state(&crtc->base, crtc->base.state);
|
||||||
|
kfree(crtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void intel_crtc_destroy(struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||||
|
|
||||||
|
drm_crtc_cleanup(crtc);
|
||||||
|
kfree(intel_crtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int intel_crtc_late_register(struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
intel_crtc_debugfs_add(crtc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INTEL_CRTC_FUNCS \
|
||||||
|
.set_config = drm_atomic_helper_set_config, \
|
||||||
|
.destroy = intel_crtc_destroy, \
|
||||||
|
.page_flip = drm_atomic_helper_page_flip, \
|
||||||
|
.atomic_duplicate_state = intel_crtc_duplicate_state, \
|
||||||
|
.atomic_destroy_state = intel_crtc_destroy_state, \
|
||||||
|
.set_crc_source = intel_crtc_set_crc_source, \
|
||||||
|
.verify_crc_source = intel_crtc_verify_crc_source, \
|
||||||
|
.get_crc_sources = intel_crtc_get_crc_sources, \
|
||||||
|
.late_register = intel_crtc_late_register
|
||||||
|
|
||||||
|
static const struct drm_crtc_funcs bdw_crtc_funcs = {
|
||||||
|
INTEL_CRTC_FUNCS,
|
||||||
|
|
||||||
|
.get_vblank_counter = g4x_get_vblank_counter,
|
||||||
|
.enable_vblank = bdw_enable_vblank,
|
||||||
|
.disable_vblank = bdw_disable_vblank,
|
||||||
|
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct drm_crtc_funcs ilk_crtc_funcs = {
|
||||||
|
INTEL_CRTC_FUNCS,
|
||||||
|
|
||||||
|
.get_vblank_counter = g4x_get_vblank_counter,
|
||||||
|
.enable_vblank = ilk_enable_vblank,
|
||||||
|
.disable_vblank = ilk_disable_vblank,
|
||||||
|
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct drm_crtc_funcs g4x_crtc_funcs = {
|
||||||
|
INTEL_CRTC_FUNCS,
|
||||||
|
|
||||||
|
.get_vblank_counter = g4x_get_vblank_counter,
|
||||||
|
.enable_vblank = i965_enable_vblank,
|
||||||
|
.disable_vblank = i965_disable_vblank,
|
||||||
|
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct drm_crtc_funcs i965_crtc_funcs = {
|
||||||
|
INTEL_CRTC_FUNCS,
|
||||||
|
|
||||||
|
.get_vblank_counter = i915_get_vblank_counter,
|
||||||
|
.enable_vblank = i965_enable_vblank,
|
||||||
|
.disable_vblank = i965_disable_vblank,
|
||||||
|
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct drm_crtc_funcs i915gm_crtc_funcs = {
|
||||||
|
INTEL_CRTC_FUNCS,
|
||||||
|
|
||||||
|
.get_vblank_counter = i915_get_vblank_counter,
|
||||||
|
.enable_vblank = i915gm_enable_vblank,
|
||||||
|
.disable_vblank = i915gm_disable_vblank,
|
||||||
|
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct drm_crtc_funcs i915_crtc_funcs = {
|
||||||
|
INTEL_CRTC_FUNCS,
|
||||||
|
|
||||||
|
.get_vblank_counter = i915_get_vblank_counter,
|
||||||
|
.enable_vblank = i8xx_enable_vblank,
|
||||||
|
.disable_vblank = i8xx_disable_vblank,
|
||||||
|
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct drm_crtc_funcs i8xx_crtc_funcs = {
|
||||||
|
INTEL_CRTC_FUNCS,
|
||||||
|
|
||||||
|
/* no hw vblank counter */
|
||||||
|
.enable_vblank = i8xx_enable_vblank,
|
||||||
|
.disable_vblank = i8xx_disable_vblank,
|
||||||
|
.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
|
||||||
|
};
|
||||||
|
|
||||||
|
int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
|
||||||
|
{
|
||||||
|
struct intel_plane *primary, *cursor;
|
||||||
|
const struct drm_crtc_funcs *funcs;
|
||||||
|
struct intel_crtc *crtc;
|
||||||
|
int sprite, ret;
|
||||||
|
|
||||||
|
crtc = intel_crtc_alloc();
|
||||||
|
if (IS_ERR(crtc))
|
||||||
|
return PTR_ERR(crtc);
|
||||||
|
|
||||||
|
crtc->pipe = pipe;
|
||||||
|
crtc->num_scalers = RUNTIME_INFO(dev_priv)->num_scalers[pipe];
|
||||||
|
|
||||||
|
primary = intel_primary_plane_create(dev_priv, pipe);
|
||||||
|
if (IS_ERR(primary)) {
|
||||||
|
ret = PTR_ERR(primary);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
crtc->plane_ids_mask |= BIT(primary->id);
|
||||||
|
|
||||||
|
for_each_sprite(dev_priv, pipe, sprite) {
|
||||||
|
struct intel_plane *plane;
|
||||||
|
|
||||||
|
plane = intel_sprite_plane_create(dev_priv, pipe, sprite);
|
||||||
|
if (IS_ERR(plane)) {
|
||||||
|
ret = PTR_ERR(plane);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
crtc->plane_ids_mask |= BIT(plane->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = intel_cursor_plane_create(dev_priv, pipe);
|
||||||
|
if (IS_ERR(cursor)) {
|
||||||
|
ret = PTR_ERR(cursor);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
crtc->plane_ids_mask |= BIT(cursor->id);
|
||||||
|
|
||||||
|
if (HAS_GMCH(dev_priv)) {
|
||||||
|
if (IS_CHERRYVIEW(dev_priv) ||
|
||||||
|
IS_VALLEYVIEW(dev_priv) || IS_G4X(dev_priv))
|
||||||
|
funcs = &g4x_crtc_funcs;
|
||||||
|
else if (IS_GEN(dev_priv, 4))
|
||||||
|
funcs = &i965_crtc_funcs;
|
||||||
|
else if (IS_I945GM(dev_priv) || IS_I915GM(dev_priv))
|
||||||
|
funcs = &i915gm_crtc_funcs;
|
||||||
|
else if (IS_GEN(dev_priv, 3))
|
||||||
|
funcs = &i915_crtc_funcs;
|
||||||
|
else
|
||||||
|
funcs = &i8xx_crtc_funcs;
|
||||||
|
} else {
|
||||||
|
if (INTEL_GEN(dev_priv) >= 8)
|
||||||
|
funcs = &bdw_crtc_funcs;
|
||||||
|
else
|
||||||
|
funcs = &ilk_crtc_funcs;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = drm_crtc_init_with_planes(&dev_priv->drm, &crtc->base,
|
||||||
|
&primary->base, &cursor->base,
|
||||||
|
funcs, "pipe %c", pipe_name(pipe));
|
||||||
|
if (ret)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
BUG_ON(pipe >= ARRAY_SIZE(dev_priv->pipe_to_crtc_mapping) ||
|
||||||
|
dev_priv->pipe_to_crtc_mapping[pipe] != NULL);
|
||||||
|
dev_priv->pipe_to_crtc_mapping[pipe] = crtc;
|
||||||
|
|
||||||
|
if (INTEL_GEN(dev_priv) < 9) {
|
||||||
|
enum i9xx_plane_id i9xx_plane = primary->i9xx_plane;
|
||||||
|
|
||||||
|
BUG_ON(i9xx_plane >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
|
||||||
|
dev_priv->plane_to_crtc_mapping[i9xx_plane] != NULL);
|
||||||
|
dev_priv->plane_to_crtc_mapping[i9xx_plane] = crtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (INTEL_GEN(dev_priv) >= 10)
|
||||||
|
drm_crtc_create_scaling_filter_property(&crtc->base,
|
||||||
|
BIT(DRM_SCALING_FILTER_DEFAULT) |
|
||||||
|
BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
|
||||||
|
|
||||||
|
intel_color_init(crtc);
|
||||||
|
|
||||||
|
intel_crtc_crc_init(crtc);
|
||||||
|
|
||||||
|
drm_WARN_ON(&dev_priv->drm, drm_crtc_index(&crtc->base) != crtc->pipe);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
intel_crtc_free(crtc);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
22
drivers/gpu/drm/i915/display/intel_crtc.h
Normal file
22
drivers/gpu/drm/i915/display/intel_crtc.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
/*
|
||||||
|
* Copyright © 2020 Intel Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INTEL_CRTC_H_
|
||||||
|
#define _INTEL_CRTC_H_
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
enum pipe;
|
||||||
|
struct drm_i915_private;
|
||||||
|
struct intel_crtc;
|
||||||
|
struct intel_crtc_state;
|
||||||
|
|
||||||
|
u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state);
|
||||||
|
int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe);
|
||||||
|
struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc);
|
||||||
|
void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
|
||||||
|
struct intel_crtc *crtc);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -46,10 +46,12 @@
|
|||||||
#include "intel_hotplug.h"
|
#include "intel_hotplug.h"
|
||||||
#include "intel_lspcon.h"
|
#include "intel_lspcon.h"
|
||||||
#include "intel_panel.h"
|
#include "intel_panel.h"
|
||||||
|
#include "intel_pps.h"
|
||||||
#include "intel_psr.h"
|
#include "intel_psr.h"
|
||||||
#include "intel_sprite.h"
|
#include "intel_sprite.h"
|
||||||
#include "intel_tc.h"
|
#include "intel_tc.h"
|
||||||
#include "intel_vdsc.h"
|
#include "intel_vdsc.h"
|
||||||
|
#include "intel_vrr.h"
|
||||||
|
|
||||||
struct ddi_buf_trans {
|
struct ddi_buf_trans {
|
||||||
u32 trans1; /* balance leg enable, de-emph level */
|
u32 trans1; /* balance leg enable, de-emph level */
|
||||||
@@ -2099,9 +2101,9 @@ void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
|
int intel_ddi_toggle_hdcp_bits(struct intel_encoder *intel_encoder,
|
||||||
enum transcoder cpu_transcoder,
|
enum transcoder cpu_transcoder,
|
||||||
bool enable)
|
bool enable, u32 hdcp_mask)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = intel_encoder->base.dev;
|
struct drm_device *dev = intel_encoder->base.dev;
|
||||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
@@ -2116,9 +2118,9 @@ int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
|
|||||||
|
|
||||||
tmp = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder));
|
tmp = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder));
|
||||||
if (enable)
|
if (enable)
|
||||||
tmp |= TRANS_DDI_HDCP_SIGNALLING;
|
tmp |= hdcp_mask;
|
||||||
else
|
else
|
||||||
tmp &= ~TRANS_DDI_HDCP_SIGNALLING;
|
tmp &= ~hdcp_mask;
|
||||||
intel_de_write(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder), tmp);
|
intel_de_write(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder), tmp);
|
||||||
intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
|
intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -2701,15 +2703,11 @@ static void icl_ddi_combo_vswing_program(struct intel_encoder *encoder,
|
|||||||
ddi_translations = ehl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
|
ddi_translations = ehl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
|
||||||
else
|
else
|
||||||
ddi_translations = icl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
|
ddi_translations = icl_get_combo_buf_trans(encoder, crtc_state, &n_entries);
|
||||||
if (!ddi_translations)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (level >= n_entries) {
|
if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations))
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
return;
|
||||||
"DDI translation not found for level %d. Using %d instead.",
|
if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries))
|
||||||
level, n_entries - 1);
|
|
||||||
level = n_entries - 1;
|
level = n_entries - 1;
|
||||||
}
|
|
||||||
|
|
||||||
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) {
|
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) {
|
||||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||||
@@ -2830,13 +2828,11 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
|
|||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
ddi_translations = icl_get_mg_buf_trans(encoder, crtc_state, &n_entries);
|
ddi_translations = icl_get_mg_buf_trans(encoder, crtc_state, &n_entries);
|
||||||
/* The table does not have values for level 3 and level 9. */
|
|
||||||
if (level >= n_entries || level == 3 || level == 9) {
|
if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations))
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
return;
|
||||||
"DDI translation not found for level %d. Using %d instead.",
|
if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries))
|
||||||
level, n_entries - 2);
|
level = n_entries - 1;
|
||||||
level = n_entries - 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set MG_TX_LINK_PARAMS cri_use_fs32 to 0. */
|
/* Set MG_TX_LINK_PARAMS cri_use_fs32 to 0. */
|
||||||
for (ln = 0; ln < 2; ln++) {
|
for (ln = 0; ln < 2; ln++) {
|
||||||
@@ -2968,7 +2964,9 @@ tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder,
|
|||||||
|
|
||||||
ddi_translations = tgl_get_dkl_buf_trans(encoder, crtc_state, &n_entries);
|
ddi_translations = tgl_get_dkl_buf_trans(encoder, crtc_state, &n_entries);
|
||||||
|
|
||||||
if (level >= n_entries)
|
if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations))
|
||||||
|
return;
|
||||||
|
if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries))
|
||||||
level = n_entries - 1;
|
level = n_entries - 1;
|
||||||
|
|
||||||
dpcnt_mask = (DKL_TX_PRESHOOT_COEFF_MASK |
|
dpcnt_mask = (DKL_TX_PRESHOOT_COEFF_MASK |
|
||||||
@@ -3555,6 +3553,22 @@ i915_reg_t dp_tp_status_reg(struct intel_encoder *encoder,
|
|||||||
return DP_TP_STATUS(encoder->port);
|
return DP_TP_STATUS(encoder->port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void intel_dp_sink_set_msa_timing_par_ignore_state(struct intel_dp *intel_dp,
|
||||||
|
const struct intel_crtc_state *crtc_state,
|
||||||
|
bool enable)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||||
|
|
||||||
|
if (!crtc_state->vrr.enable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_DOWNSPREAD_CTRL,
|
||||||
|
enable ? DP_MSA_TIMING_PAR_IGNORE_EN : 0) <= 0)
|
||||||
|
drm_dbg_kms(&i915->drm,
|
||||||
|
"Failed to set MSA_TIMING_PAR_IGNORE %s in the sink\n",
|
||||||
|
enable ? "enable" : "disable");
|
||||||
|
}
|
||||||
|
|
||||||
static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp,
|
static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp,
|
||||||
const struct intel_crtc_state *crtc_state)
|
const struct intel_crtc_state *crtc_state)
|
||||||
{
|
{
|
||||||
@@ -3625,7 +3639,7 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* 2. Enable Panel Power if PPS is required */
|
/* 2. Enable Panel Power if PPS is required */
|
||||||
intel_edp_panel_on(intel_dp);
|
intel_pps_on(intel_dp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 3. For non-TBT Type-C ports, set FIA lane count
|
* 3. For non-TBT Type-C ports, set FIA lane count
|
||||||
@@ -3768,7 +3782,7 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,
|
|||||||
crtc_state->port_clock,
|
crtc_state->port_clock,
|
||||||
crtc_state->lane_count);
|
crtc_state->lane_count);
|
||||||
|
|
||||||
intel_edp_panel_on(intel_dp);
|
intel_pps_on(intel_dp);
|
||||||
|
|
||||||
intel_ddi_clk_select(encoder, crtc_state);
|
intel_ddi_clk_select(encoder, crtc_state);
|
||||||
|
|
||||||
@@ -4010,8 +4024,8 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state,
|
|||||||
if (INTEL_GEN(dev_priv) >= 12)
|
if (INTEL_GEN(dev_priv) >= 12)
|
||||||
intel_ddi_disable_pipe_clock(old_crtc_state);
|
intel_ddi_disable_pipe_clock(old_crtc_state);
|
||||||
|
|
||||||
intel_edp_panel_vdd_on(intel_dp);
|
intel_pps_vdd_on(intel_dp);
|
||||||
intel_edp_panel_off(intel_dp);
|
intel_pps_off(intel_dp);
|
||||||
|
|
||||||
if (!intel_phy_is_tc(dev_priv, phy) ||
|
if (!intel_phy_is_tc(dev_priv, phy) ||
|
||||||
dig_port->tc_mode != TC_PORT_TBT_ALT)
|
dig_port->tc_mode != TC_PORT_TBT_ALT)
|
||||||
@@ -4062,6 +4076,8 @@ static void intel_ddi_post_disable(struct intel_atomic_state *state,
|
|||||||
|
|
||||||
intel_disable_pipe(old_crtc_state);
|
intel_disable_pipe(old_crtc_state);
|
||||||
|
|
||||||
|
intel_vrr_disable(old_crtc_state);
|
||||||
|
|
||||||
intel_ddi_disable_transcoder_func(old_crtc_state);
|
intel_ddi_disable_transcoder_func(old_crtc_state);
|
||||||
|
|
||||||
intel_dsc_disable(old_crtc_state);
|
intel_dsc_disable(old_crtc_state);
|
||||||
@@ -4313,6 +4329,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
|
|||||||
if (!crtc_state->bigjoiner_slave)
|
if (!crtc_state->bigjoiner_slave)
|
||||||
intel_ddi_enable_transcoder_func(encoder, crtc_state);
|
intel_ddi_enable_transcoder_func(encoder, crtc_state);
|
||||||
|
|
||||||
|
intel_vrr_enable(encoder, crtc_state);
|
||||||
|
|
||||||
intel_enable_pipe(crtc_state);
|
intel_enable_pipe(crtc_state);
|
||||||
|
|
||||||
intel_crtc_vblank_on(crtc_state);
|
intel_crtc_vblank_on(crtc_state);
|
||||||
@@ -4326,7 +4344,7 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
|
|||||||
if (conn_state->content_protection ==
|
if (conn_state->content_protection ==
|
||||||
DRM_MODE_CONTENT_PROTECTION_DESIRED)
|
DRM_MODE_CONTENT_PROTECTION_DESIRED)
|
||||||
intel_hdcp_enable(to_intel_connector(conn_state->connector),
|
intel_hdcp_enable(to_intel_connector(conn_state->connector),
|
||||||
crtc_state->cpu_transcoder,
|
crtc_state,
|
||||||
(u8)conn_state->hdcp_content_type);
|
(u8)conn_state->hdcp_content_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4349,6 +4367,9 @@ static void intel_disable_ddi_dp(struct intel_atomic_state *state,
|
|||||||
/* Disable the decompression in DP Sink */
|
/* Disable the decompression in DP Sink */
|
||||||
intel_dp_sink_set_decompression_state(intel_dp, old_crtc_state,
|
intel_dp_sink_set_decompression_state(intel_dp, old_crtc_state,
|
||||||
false);
|
false);
|
||||||
|
/* Disable Ignore_MSA bit in DP Sink */
|
||||||
|
intel_dp_sink_set_msa_timing_par_ignore_state(intel_dp, old_crtc_state,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void intel_disable_ddi_hdmi(struct intel_atomic_state *state,
|
static void intel_disable_ddi_hdmi(struct intel_atomic_state *state,
|
||||||
@@ -5039,6 +5060,8 @@ static void intel_ddi_encoder_destroy(struct drm_encoder *encoder)
|
|||||||
intel_dp_encoder_flush_work(encoder);
|
intel_dp_encoder_flush_work(encoder);
|
||||||
|
|
||||||
drm_encoder_cleanup(encoder);
|
drm_encoder_cleanup(encoder);
|
||||||
|
if (dig_port)
|
||||||
|
kfree(dig_port->hdcp_port_data.streams);
|
||||||
kfree(dig_port);
|
kfree(dig_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5192,12 +5215,20 @@ intel_ddi_hotplug(struct intel_encoder *encoder,
|
|||||||
{
|
{
|
||||||
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
|
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
|
||||||
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
|
struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
|
||||||
|
struct intel_dp *intel_dp = &dig_port->dp;
|
||||||
enum phy phy = intel_port_to_phy(i915, encoder->port);
|
enum phy phy = intel_port_to_phy(i915, encoder->port);
|
||||||
bool is_tc = intel_phy_is_tc(i915, phy);
|
bool is_tc = intel_phy_is_tc(i915, phy);
|
||||||
struct drm_modeset_acquire_ctx ctx;
|
struct drm_modeset_acquire_ctx ctx;
|
||||||
enum intel_hotplug_state state;
|
enum intel_hotplug_state state;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (intel_dp->compliance.test_active &&
|
||||||
|
intel_dp->compliance.test_type == DP_TEST_LINK_PHY_TEST_PATTERN) {
|
||||||
|
intel_dp_phy_test(encoder);
|
||||||
|
/* just do the PHY test and nothing else */
|
||||||
|
return INTEL_HOTPLUG_UNCHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
state = intel_encoder_hotplug(encoder, connector);
|
state = intel_encoder_hotplug(encoder, connector);
|
||||||
|
|
||||||
drm_modeset_acquire_init(&ctx, 0);
|
drm_modeset_acquire_init(&ctx, 0);
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ u32 bxt_signal_levels(struct intel_dp *intel_dp,
|
|||||||
const struct intel_crtc_state *crtc_state);
|
const struct intel_crtc_state *crtc_state);
|
||||||
u32 ddi_signal_levels(struct intel_dp *intel_dp,
|
u32 ddi_signal_levels(struct intel_dp *intel_dp,
|
||||||
const struct intel_crtc_state *crtc_state);
|
const struct intel_crtc_state *crtc_state);
|
||||||
int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
|
int intel_ddi_toggle_hdcp_bits(struct intel_encoder *intel_encoder,
|
||||||
enum transcoder cpu_transcoder,
|
enum transcoder cpu_transcoder,
|
||||||
bool enable);
|
bool enable, u32 hdcp_mask);
|
||||||
void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder);
|
void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder);
|
||||||
|
|
||||||
#endif /* __INTEL_DDI_H__ */
|
#endif /* __INTEL_DDI_H__ */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -546,7 +546,6 @@ unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info
|
|||||||
unsigned int intel_remapped_info_size(const struct intel_remapped_info *rem_info);
|
unsigned int intel_remapped_info_size(const struct intel_remapped_info *rem_info);
|
||||||
bool intel_has_pending_fb_unpin(struct drm_i915_private *dev_priv);
|
bool intel_has_pending_fb_unpin(struct drm_i915_private *dev_priv);
|
||||||
int intel_display_suspend(struct drm_device *dev);
|
int intel_display_suspend(struct drm_device *dev);
|
||||||
void intel_pps_unlock_regs_wa(struct drm_i915_private *dev_priv);
|
|
||||||
void intel_encoder_destroy(struct drm_encoder *encoder);
|
void intel_encoder_destroy(struct drm_encoder *encoder);
|
||||||
struct drm_display_mode *
|
struct drm_display_mode *
|
||||||
intel_encoder_current_mode(struct intel_encoder *encoder);
|
intel_encoder_current_mode(struct intel_encoder *encoder);
|
||||||
@@ -643,7 +642,7 @@ void intel_display_print_error_state(struct drm_i915_error_state_buf *e,
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info,
|
intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info,
|
||||||
uint64_t modifier);
|
u64 modifier);
|
||||||
|
|
||||||
int intel_plane_compute_gtt(struct intel_plane_state *plane_state);
|
int intel_plane_compute_gtt(struct intel_plane_state *plane_state);
|
||||||
u32 intel_plane_compute_aligned_offset(int *x, int *y,
|
u32 intel_plane_compute_aligned_offset(int *x, int *y,
|
||||||
@@ -651,6 +650,9 @@ u32 intel_plane_compute_aligned_offset(int *x, int *y,
|
|||||||
int color_plane);
|
int color_plane);
|
||||||
int intel_plane_pin_fb(struct intel_plane_state *plane_state);
|
int intel_plane_pin_fb(struct intel_plane_state *plane_state);
|
||||||
void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state);
|
void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state);
|
||||||
|
struct intel_encoder *
|
||||||
|
intel_get_crtc_new_encoder(const struct intel_atomic_state *state,
|
||||||
|
const struct intel_crtc_state *crtc_state);
|
||||||
|
|
||||||
/* modesetting */
|
/* modesetting */
|
||||||
void intel_modeset_init_hw(struct drm_i915_private *i915);
|
void intel_modeset_init_hw(struct drm_i915_private *i915);
|
||||||
|
|||||||
@@ -1139,7 +1139,6 @@ static ssize_t i915_ipc_status_write(struct file *file, const char __user *ubuf,
|
|||||||
if (!dev_priv->ipc_enabled && enable)
|
if (!dev_priv->ipc_enabled && enable)
|
||||||
drm_info(&dev_priv->drm,
|
drm_info(&dev_priv->drm,
|
||||||
"Enabling IPC: WM will be proper only after next commit\n");
|
"Enabling IPC: WM will be proper only after next commit\n");
|
||||||
dev_priv->wm.distrust_bios_wm = true;
|
|
||||||
dev_priv->ipc_enabled = enable;
|
dev_priv->ipc_enabled = enable;
|
||||||
intel_enable_ipc(dev_priv);
|
intel_enable_ipc(dev_priv);
|
||||||
}
|
}
|
||||||
@@ -2155,13 +2154,13 @@ static int i915_panel_show(struct seq_file *m, void *data)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
seq_printf(m, "Panel power up delay: %d\n",
|
seq_printf(m, "Panel power up delay: %d\n",
|
||||||
intel_dp->panel_power_up_delay);
|
intel_dp->pps.panel_power_up_delay);
|
||||||
seq_printf(m, "Panel power down delay: %d\n",
|
seq_printf(m, "Panel power down delay: %d\n",
|
||||||
intel_dp->panel_power_down_delay);
|
intel_dp->pps.panel_power_down_delay);
|
||||||
seq_printf(m, "Backlight on delay: %d\n",
|
seq_printf(m, "Backlight on delay: %d\n",
|
||||||
intel_dp->backlight_on_delay);
|
intel_dp->pps.backlight_on_delay);
|
||||||
seq_printf(m, "Backlight off delay: %d\n",
|
seq_printf(m, "Backlight off delay: %d\n",
|
||||||
intel_dp->backlight_off_delay);
|
intel_dp->pps.backlight_off_delay);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "display/intel_crt.h"
|
#include "display/intel_crt.h"
|
||||||
#include "display/intel_dp.h"
|
|
||||||
|
|
||||||
#include "i915_drv.h"
|
#include "i915_drv.h"
|
||||||
#include "i915_irq.h"
|
#include "i915_irq.h"
|
||||||
@@ -16,6 +15,7 @@
|
|||||||
#include "intel_dpio_phy.h"
|
#include "intel_dpio_phy.h"
|
||||||
#include "intel_hotplug.h"
|
#include "intel_hotplug.h"
|
||||||
#include "intel_pm.h"
|
#include "intel_pm.h"
|
||||||
|
#include "intel_pps.h"
|
||||||
#include "intel_sideband.h"
|
#include "intel_sideband.h"
|
||||||
#include "intel_tc.h"
|
#include "intel_tc.h"
|
||||||
#include "intel_vga.h"
|
#include "intel_vga.h"
|
||||||
@@ -936,7 +936,7 @@ static void bxt_enable_dc9(struct drm_i915_private *dev_priv)
|
|||||||
* because PPS registers are always on.
|
* because PPS registers are always on.
|
||||||
*/
|
*/
|
||||||
if (!HAS_PCH_SPLIT(dev_priv))
|
if (!HAS_PCH_SPLIT(dev_priv))
|
||||||
intel_power_sequencer_reset(dev_priv);
|
intel_pps_reset_all(dev_priv);
|
||||||
gen9_set_dc_state(dev_priv, DC_STATE_EN_DC9);
|
gen9_set_dc_state(dev_priv, DC_STATE_EN_DC9);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1446,7 +1446,7 @@ static void vlv_display_power_well_deinit(struct drm_i915_private *dev_priv)
|
|||||||
/* make sure we're done processing display irqs */
|
/* make sure we're done processing display irqs */
|
||||||
intel_synchronize_irq(dev_priv);
|
intel_synchronize_irq(dev_priv);
|
||||||
|
|
||||||
intel_power_sequencer_reset(dev_priv);
|
intel_pps_reset_all(dev_priv);
|
||||||
|
|
||||||
/* Prevent us from re-enabling polling on accident in late suspend */
|
/* Prevent us from re-enabling polling on accident in late suspend */
|
||||||
if (!dev_priv->drm.dev->power.is_suspended)
|
if (!dev_priv->drm.dev->power.is_suspended)
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ struct intel_encoder {
|
|||||||
struct intel_panel_bl_funcs {
|
struct intel_panel_bl_funcs {
|
||||||
/* Connector and platform specific backlight functions */
|
/* Connector and platform specific backlight functions */
|
||||||
int (*setup)(struct intel_connector *connector, enum pipe pipe);
|
int (*setup)(struct intel_connector *connector, enum pipe pipe);
|
||||||
u32 (*get)(struct intel_connector *connector);
|
u32 (*get)(struct intel_connector *connector, enum pipe pipe);
|
||||||
void (*set)(const struct drm_connector_state *conn_state, u32 level);
|
void (*set)(const struct drm_connector_state *conn_state, u32 level);
|
||||||
void (*disable)(const struct drm_connector_state *conn_state, u32 level);
|
void (*disable)(const struct drm_connector_state *conn_state, u32 level);
|
||||||
void (*enable)(const struct intel_crtc_state *crtc_state,
|
void (*enable)(const struct intel_crtc_state *crtc_state,
|
||||||
@@ -252,17 +252,28 @@ struct intel_panel {
|
|||||||
bool alternate_pwm_increment; /* lpt+ */
|
bool alternate_pwm_increment; /* lpt+ */
|
||||||
|
|
||||||
/* PWM chip */
|
/* PWM chip */
|
||||||
|
u32 pwm_level_min;
|
||||||
|
u32 pwm_level_max;
|
||||||
|
bool pwm_enabled;
|
||||||
bool util_pin_active_low; /* bxt+ */
|
bool util_pin_active_low; /* bxt+ */
|
||||||
u8 controller; /* bxt+ only */
|
u8 controller; /* bxt+ only */
|
||||||
struct pwm_device *pwm;
|
struct pwm_device *pwm;
|
||||||
struct pwm_state pwm_state;
|
struct pwm_state pwm_state;
|
||||||
|
|
||||||
/* DPCD backlight */
|
/* DPCD backlight */
|
||||||
u8 pwmgen_bit_count;
|
union {
|
||||||
|
struct {
|
||||||
|
u8 pwmgen_bit_count;
|
||||||
|
} vesa;
|
||||||
|
struct {
|
||||||
|
bool sdr_uses_aux;
|
||||||
|
} intel;
|
||||||
|
} edp;
|
||||||
|
|
||||||
struct backlight_device *device;
|
struct backlight_device *device;
|
||||||
|
|
||||||
const struct intel_panel_bl_funcs *funcs;
|
const struct intel_panel_bl_funcs *funcs;
|
||||||
|
const struct intel_panel_bl_funcs *pwm_funcs;
|
||||||
void (*power)(struct intel_connector *, bool enable);
|
void (*power)(struct intel_connector *, bool enable);
|
||||||
} backlight;
|
} backlight;
|
||||||
};
|
};
|
||||||
@@ -343,6 +354,10 @@ struct intel_hdcp_shim {
|
|||||||
enum transcoder cpu_transcoder,
|
enum transcoder cpu_transcoder,
|
||||||
bool enable);
|
bool enable);
|
||||||
|
|
||||||
|
/* Enable/Disable stream encryption on DP MST Transport Link */
|
||||||
|
int (*stream_encryption)(struct intel_connector *connector,
|
||||||
|
bool enable);
|
||||||
|
|
||||||
/* Ensures the link is still protected */
|
/* Ensures the link is still protected */
|
||||||
bool (*check_link)(struct intel_digital_port *dig_port,
|
bool (*check_link)(struct intel_digital_port *dig_port,
|
||||||
struct intel_connector *connector);
|
struct intel_connector *connector);
|
||||||
@@ -374,8 +389,13 @@ struct intel_hdcp_shim {
|
|||||||
int (*config_stream_type)(struct intel_digital_port *dig_port,
|
int (*config_stream_type)(struct intel_digital_port *dig_port,
|
||||||
bool is_repeater, u8 type);
|
bool is_repeater, u8 type);
|
||||||
|
|
||||||
|
/* Enable/Disable HDCP 2.2 stream encryption on DP MST Transport Link */
|
||||||
|
int (*stream_2_2_encryption)(struct intel_connector *connector,
|
||||||
|
bool enable);
|
||||||
|
|
||||||
/* HDCP2.2 Link Integrity Check */
|
/* HDCP2.2 Link Integrity Check */
|
||||||
int (*check_2_2_link)(struct intel_digital_port *dig_port);
|
int (*check_2_2_link)(struct intel_digital_port *dig_port,
|
||||||
|
struct intel_connector *connector);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct intel_hdcp {
|
struct intel_hdcp {
|
||||||
@@ -402,7 +422,6 @@ struct intel_hdcp {
|
|||||||
* content can flow only through a link protected by HDCP2.2.
|
* content can flow only through a link protected by HDCP2.2.
|
||||||
*/
|
*/
|
||||||
u8 content_type;
|
u8 content_type;
|
||||||
struct hdcp_port_data port_data;
|
|
||||||
|
|
||||||
bool is_paired;
|
bool is_paired;
|
||||||
bool is_repeater;
|
bool is_repeater;
|
||||||
@@ -436,6 +455,8 @@ struct intel_hdcp {
|
|||||||
* Hence caching the transcoder here.
|
* Hence caching the transcoder here.
|
||||||
*/
|
*/
|
||||||
enum transcoder cpu_transcoder;
|
enum transcoder cpu_transcoder;
|
||||||
|
/* Only used for DP MST stream encryption */
|
||||||
|
enum transcoder stream_transcoder;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct intel_connector {
|
struct intel_connector {
|
||||||
@@ -535,7 +556,7 @@ struct intel_plane_state {
|
|||||||
struct drm_framebuffer *fb;
|
struct drm_framebuffer *fb;
|
||||||
|
|
||||||
u16 alpha;
|
u16 alpha;
|
||||||
uint16_t pixel_blend_mode;
|
u16 pixel_blend_mode;
|
||||||
unsigned int rotation;
|
unsigned int rotation;
|
||||||
enum drm_color_encoding color_encoding;
|
enum drm_color_encoding color_encoding;
|
||||||
enum drm_color_range color_range;
|
enum drm_color_range color_range;
|
||||||
@@ -610,6 +631,9 @@ struct intel_plane_state {
|
|||||||
struct drm_intel_sprite_colorkey ckey;
|
struct drm_intel_sprite_colorkey ckey;
|
||||||
|
|
||||||
struct drm_rect psr2_sel_fetch_area;
|
struct drm_rect psr2_sel_fetch_area;
|
||||||
|
|
||||||
|
/* Clear Color Value */
|
||||||
|
u64 ccval;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct intel_initial_plane_config {
|
struct intel_initial_plane_config {
|
||||||
@@ -669,6 +693,8 @@ struct intel_crtc_scaler_state {
|
|||||||
#define I915_MODE_FLAG_DSI_USE_TE1 (1<<4)
|
#define I915_MODE_FLAG_DSI_USE_TE1 (1<<4)
|
||||||
/* Flag to indicate mipi dsi periodic command mode where we do not get TE */
|
/* Flag to indicate mipi dsi periodic command mode where we do not get TE */
|
||||||
#define I915_MODE_FLAG_DSI_PERIODIC_CMD_MODE (1<<5)
|
#define I915_MODE_FLAG_DSI_PERIODIC_CMD_MODE (1<<5)
|
||||||
|
/* Do tricks to make vblank timestamps sane with VRR? */
|
||||||
|
#define I915_MODE_FLAG_VRR (1<<6)
|
||||||
|
|
||||||
struct intel_wm_level {
|
struct intel_wm_level {
|
||||||
bool enable;
|
bool enable;
|
||||||
@@ -1127,6 +1153,13 @@ struct intel_crtc_state {
|
|||||||
struct intel_dsb *dsb;
|
struct intel_dsb *dsb;
|
||||||
|
|
||||||
u32 psr2_man_track_ctl;
|
u32 psr2_man_track_ctl;
|
||||||
|
|
||||||
|
/* Variable Refresh Rate state */
|
||||||
|
struct {
|
||||||
|
bool enable;
|
||||||
|
u8 pipeline_full;
|
||||||
|
u16 flipline, vmin, vmax;
|
||||||
|
} vrr;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum intel_pipe_crc_source {
|
enum intel_pipe_crc_source {
|
||||||
@@ -1169,6 +1202,8 @@ struct intel_crtc {
|
|||||||
/* I915_MODE_FLAG_* */
|
/* I915_MODE_FLAG_* */
|
||||||
u8 mode_flags;
|
u8 mode_flags;
|
||||||
|
|
||||||
|
u16 vmax_vblank_start;
|
||||||
|
|
||||||
struct intel_display_power_domain_set enabled_power_domains;
|
struct intel_display_power_domain_set enabled_power_domains;
|
||||||
struct intel_overlay *overlay;
|
struct intel_overlay *overlay;
|
||||||
|
|
||||||
@@ -1221,6 +1256,7 @@ struct intel_plane {
|
|||||||
enum pipe pipe;
|
enum pipe pipe;
|
||||||
bool has_fbc;
|
bool has_fbc;
|
||||||
bool has_ccs;
|
bool has_ccs;
|
||||||
|
bool need_async_flip_disable_wa;
|
||||||
u32 frontbuffer_bit;
|
u32 frontbuffer_bit;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -1257,7 +1293,10 @@ struct intel_plane {
|
|||||||
const struct intel_plane_state *plane_state);
|
const struct intel_plane_state *plane_state);
|
||||||
void (*async_flip)(struct intel_plane *plane,
|
void (*async_flip)(struct intel_plane *plane,
|
||||||
const struct intel_crtc_state *crtc_state,
|
const struct intel_crtc_state *crtc_state,
|
||||||
const struct intel_plane_state *plane_state);
|
const struct intel_plane_state *plane_state,
|
||||||
|
bool async_flip);
|
||||||
|
void (*enable_flip_done)(struct intel_plane *plane);
|
||||||
|
void (*disable_flip_done)(struct intel_plane *plane);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct intel_watermark_params {
|
struct intel_watermark_params {
|
||||||
@@ -1344,6 +1383,38 @@ struct intel_dp_pcon_frl {
|
|||||||
int trained_rate_gbps;
|
int trained_rate_gbps;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct intel_pps {
|
||||||
|
int panel_power_up_delay;
|
||||||
|
int panel_power_down_delay;
|
||||||
|
int panel_power_cycle_delay;
|
||||||
|
int backlight_on_delay;
|
||||||
|
int backlight_off_delay;
|
||||||
|
struct delayed_work panel_vdd_work;
|
||||||
|
bool want_panel_vdd;
|
||||||
|
unsigned long last_power_on;
|
||||||
|
unsigned long last_backlight_off;
|
||||||
|
ktime_t panel_power_off_time;
|
||||||
|
intel_wakeref_t vdd_wakeref;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pipe whose power sequencer is currently locked into
|
||||||
|
* this port. Only relevant on VLV/CHV.
|
||||||
|
*/
|
||||||
|
enum pipe pps_pipe;
|
||||||
|
/*
|
||||||
|
* Pipe currently driving the port. Used for preventing
|
||||||
|
* the use of the PPS for any pipe currentrly driving
|
||||||
|
* external DP as that will mess things up on VLV.
|
||||||
|
*/
|
||||||
|
enum pipe active_pipe;
|
||||||
|
/*
|
||||||
|
* Set if the sequencer may be reset due to a power transition,
|
||||||
|
* requiring a reinitialization. Only relevant on BXT.
|
||||||
|
*/
|
||||||
|
bool pps_reset;
|
||||||
|
struct edp_power_seq pps_delays;
|
||||||
|
};
|
||||||
|
|
||||||
struct intel_dp {
|
struct intel_dp {
|
||||||
i915_reg_t output_reg;
|
i915_reg_t output_reg;
|
||||||
u32 DP;
|
u32 DP;
|
||||||
@@ -1380,39 +1451,11 @@ struct intel_dp {
|
|||||||
int max_link_rate;
|
int max_link_rate;
|
||||||
/* sink or branch descriptor */
|
/* sink or branch descriptor */
|
||||||
struct drm_dp_desc desc;
|
struct drm_dp_desc desc;
|
||||||
u32 edid_quirks;
|
|
||||||
struct drm_dp_aux aux;
|
struct drm_dp_aux aux;
|
||||||
u32 aux_busy_last_status;
|
u32 aux_busy_last_status;
|
||||||
u8 train_set[4];
|
u8 train_set[4];
|
||||||
int panel_power_up_delay;
|
|
||||||
int panel_power_down_delay;
|
|
||||||
int panel_power_cycle_delay;
|
|
||||||
int backlight_on_delay;
|
|
||||||
int backlight_off_delay;
|
|
||||||
struct delayed_work panel_vdd_work;
|
|
||||||
bool want_panel_vdd;
|
|
||||||
unsigned long last_power_on;
|
|
||||||
unsigned long last_backlight_off;
|
|
||||||
ktime_t panel_power_off_time;
|
|
||||||
intel_wakeref_t vdd_wakeref;
|
|
||||||
|
|
||||||
/*
|
struct intel_pps pps;
|
||||||
* Pipe whose power sequencer is currently locked into
|
|
||||||
* this port. Only relevant on VLV/CHV.
|
|
||||||
*/
|
|
||||||
enum pipe pps_pipe;
|
|
||||||
/*
|
|
||||||
* Pipe currently driving the port. Used for preventing
|
|
||||||
* the use of the PPS for any pipe currentrly driving
|
|
||||||
* external DP as that will mess things up on VLV.
|
|
||||||
*/
|
|
||||||
enum pipe active_pipe;
|
|
||||||
/*
|
|
||||||
* Set if the sequencer may be reset due to a power transition,
|
|
||||||
* requiring a reinitialization. Only relevant on BXT.
|
|
||||||
*/
|
|
||||||
bool pps_reset;
|
|
||||||
struct edp_power_seq pps_delays;
|
|
||||||
|
|
||||||
bool can_mst; /* this port supports mst */
|
bool can_mst; /* this port supports mst */
|
||||||
bool is_mst;
|
bool is_mst;
|
||||||
@@ -1511,10 +1554,14 @@ struct intel_digital_port {
|
|||||||
enum phy_fia tc_phy_fia;
|
enum phy_fia tc_phy_fia;
|
||||||
u8 tc_phy_fia_idx;
|
u8 tc_phy_fia_idx;
|
||||||
|
|
||||||
/* protects num_hdcp_streams reference count */
|
/* protects num_hdcp_streams reference count, hdcp_port_data and hdcp_auth_status */
|
||||||
struct mutex hdcp_mutex;
|
struct mutex hdcp_mutex;
|
||||||
/* the number of pipes using HDCP signalling out of this port */
|
/* the number of pipes using HDCP signalling out of this port */
|
||||||
unsigned int num_hdcp_streams;
|
unsigned int num_hdcp_streams;
|
||||||
|
/* port HDCP auth status */
|
||||||
|
bool hdcp_auth_status;
|
||||||
|
/* HDCP port data need to pass to security f/w */
|
||||||
|
struct hdcp_port_data hdcp_port_data;
|
||||||
|
|
||||||
void (*write_infoframe)(struct intel_encoder *encoder,
|
void (*write_infoframe)(struct intel_encoder *encoder,
|
||||||
const struct intel_crtc_state *crtc_state,
|
const struct intel_crtc_state *crtc_state,
|
||||||
@@ -1825,4 +1872,26 @@ to_intel_frontbuffer(struct drm_framebuffer *fb)
|
|||||||
return fb ? to_intel_framebuffer(fb)->frontbuffer : NULL;
|
return fb ? to_intel_framebuffer(fb)->frontbuffer : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
|
||||||
|
{
|
||||||
|
if (dev_priv->params.panel_use_ssc >= 0)
|
||||||
|
return dev_priv->params.panel_use_ssc != 0;
|
||||||
|
return dev_priv->vbt.lvds_use_ssc
|
||||||
|
&& !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 i9xx_dpll_compute_fp(struct dpll *dpll)
|
||||||
|
{
|
||||||
|
return dpll->n << 16 | dpll->m1 << 8 | dpll->m2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv,
|
||||||
|
const struct intel_crtc_state *pipe_config)
|
||||||
|
{
|
||||||
|
if (HAS_DDI(dev_priv))
|
||||||
|
return pipe_config->port_clock; /* SPLL */
|
||||||
|
else
|
||||||
|
return dev_priv->fdi_pll_freq;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __INTEL_DISPLAY_TYPES_H__ */
|
#endif /* __INTEL_DISPLAY_TYPES_H__ */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -70,16 +70,11 @@ enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *dig_port,
|
|||||||
void intel_edp_backlight_on(const struct intel_crtc_state *crtc_state,
|
void intel_edp_backlight_on(const struct intel_crtc_state *crtc_state,
|
||||||
const struct drm_connector_state *conn_state);
|
const struct drm_connector_state *conn_state);
|
||||||
void intel_edp_backlight_off(const struct drm_connector_state *conn_state);
|
void intel_edp_backlight_off(const struct drm_connector_state *conn_state);
|
||||||
void intel_edp_panel_vdd_on(struct intel_dp *intel_dp);
|
|
||||||
void intel_edp_panel_on(struct intel_dp *intel_dp);
|
|
||||||
void intel_edp_panel_off(struct intel_dp *intel_dp);
|
|
||||||
void intel_dp_mst_suspend(struct drm_i915_private *dev_priv);
|
void intel_dp_mst_suspend(struct drm_i915_private *dev_priv);
|
||||||
void intel_dp_mst_resume(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_link_rate(struct intel_dp *intel_dp);
|
||||||
int intel_dp_max_lane_count(struct intel_dp *intel_dp);
|
int intel_dp_max_lane_count(struct intel_dp *intel_dp);
|
||||||
int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
|
int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
|
||||||
void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
|
|
||||||
u32 intel_dp_pack_aux(const u8 *src, int src_bytes);
|
|
||||||
|
|
||||||
void intel_edp_drrs_enable(struct intel_dp *intel_dp,
|
void intel_edp_drrs_enable(struct intel_dp *intel_dp,
|
||||||
const struct intel_crtc_state *crtc_state);
|
const struct intel_crtc_state *crtc_state);
|
||||||
@@ -96,9 +91,6 @@ void
|
|||||||
intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
|
intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
|
||||||
const struct intel_crtc_state *crtc_state,
|
const struct intel_crtc_state *crtc_state,
|
||||||
u8 dp_train_pat);
|
u8 dp_train_pat);
|
||||||
void
|
|
||||||
intel_dp_set_signal_levels(struct intel_dp *intel_dp,
|
|
||||||
const struct intel_crtc_state *crtc_state);
|
|
||||||
void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
|
void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
|
||||||
u8 *link_bw, u8 *rate_select);
|
u8 *link_bw, u8 *rate_select);
|
||||||
bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
|
bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
|
||||||
@@ -144,9 +136,11 @@ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
|
|||||||
struct intel_crtc_state *crtc_state);
|
struct intel_crtc_state *crtc_state);
|
||||||
void intel_dp_sync_state(struct intel_encoder *encoder,
|
void intel_dp_sync_state(struct intel_encoder *encoder,
|
||||||
const struct intel_crtc_state *crtc_state);
|
const struct intel_crtc_state *crtc_state);
|
||||||
|
const struct dpll *vlv_get_dpll(struct drm_i915_private *i915);
|
||||||
|
|
||||||
void intel_dp_check_frl_training(struct intel_dp *intel_dp);
|
void intel_dp_check_frl_training(struct intel_dp *intel_dp);
|
||||||
void intel_dp_pcon_dsc_configure(struct intel_dp *intel_dp,
|
void intel_dp_pcon_dsc_configure(struct intel_dp *intel_dp,
|
||||||
const struct intel_crtc_state *crtc_state);
|
const struct intel_crtc_state *crtc_state);
|
||||||
|
void intel_dp_phy_test(struct intel_encoder *encoder);
|
||||||
|
|
||||||
#endif /* __INTEL_DP_H__ */
|
#endif /* __INTEL_DP_H__ */
|
||||||
|
|||||||
692
drivers/gpu/drm/i915/display/intel_dp_aux.c
Normal file
692
drivers/gpu/drm/i915/display/intel_dp_aux.c
Normal file
@@ -0,0 +1,692 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
/*
|
||||||
|
* Copyright © 2020-2021 Intel Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "i915_drv.h"
|
||||||
|
#include "i915_trace.h"
|
||||||
|
#include "intel_display_types.h"
|
||||||
|
#include "intel_dp_aux.h"
|
||||||
|
#include "intel_pps.h"
|
||||||
|
#include "intel_tc.h"
|
||||||
|
|
||||||
|
u32 intel_dp_pack_aux(const u8 *src, int src_bytes)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u32 v = 0;
|
||||||
|
|
||||||
|
if (src_bytes > 4)
|
||||||
|
src_bytes = 4;
|
||||||
|
for (i = 0; i < src_bytes; i++)
|
||||||
|
v |= ((u32)src[i]) << ((3 - i) * 8);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void intel_dp_unpack_aux(u32 src, u8 *dst, int dst_bytes)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (dst_bytes > 4)
|
||||||
|
dst_bytes = 4;
|
||||||
|
for (i = 0; i < dst_bytes; i++)
|
||||||
|
dst[i] = src >> ((3 - i) * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32
|
||||||
|
intel_dp_aux_wait_done(struct intel_dp *intel_dp)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||||
|
i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
|
||||||
|
const unsigned int timeout_ms = 10;
|
||||||
|
u32 status;
|
||||||
|
bool done;
|
||||||
|
|
||||||
|
#define C (((status = intel_uncore_read_notrace(&i915->uncore, ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
|
||||||
|
done = wait_event_timeout(i915->gmbus_wait_queue, C,
|
||||||
|
msecs_to_jiffies_timeout(timeout_ms));
|
||||||
|
|
||||||
|
/* just trace the final value */
|
||||||
|
trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
|
||||||
|
|
||||||
|
if (!done)
|
||||||
|
drm_err(&i915->drm,
|
||||||
|
"%s: did not complete or timeout within %ums (status 0x%08x)\n",
|
||||||
|
intel_dp->aux.name, timeout_ms, status);
|
||||||
|
#undef C
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
|
||||||
|
|
||||||
|
if (index)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The clock divider is based off the hrawclk, and would like to run at
|
||||||
|
* 2MHz. So, take the hrawclk value and divide by 2000 and use that
|
||||||
|
*/
|
||||||
|
return DIV_ROUND_CLOSEST(RUNTIME_INFO(dev_priv)->rawclk_freq, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
|
||||||
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
|
u32 freq;
|
||||||
|
|
||||||
|
if (index)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The clock divider is based off the cdclk or PCH rawclk, and would
|
||||||
|
* like to run at 2MHz. So, take the cdclk or PCH rawclk value and
|
||||||
|
* divide by 2000 and use that
|
||||||
|
*/
|
||||||
|
if (dig_port->aux_ch == AUX_CH_A)
|
||||||
|
freq = dev_priv->cdclk.hw.cdclk;
|
||||||
|
else
|
||||||
|
freq = RUNTIME_INFO(dev_priv)->rawclk_freq;
|
||||||
|
return DIV_ROUND_CLOSEST(freq, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
|
||||||
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
|
|
||||||
|
if (dig_port->aux_ch != AUX_CH_A && HAS_PCH_LPT_H(dev_priv)) {
|
||||||
|
/* Workaround for non-ULT HSW */
|
||||||
|
switch (index) {
|
||||||
|
case 0: return 63;
|
||||||
|
case 1: return 72;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ilk_get_aux_clock_divider(intel_dp, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 skl_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* SKL doesn't need us to program the AUX clock divider (Hardware will
|
||||||
|
* derive the clock from CDCLK automatically). We still implement the
|
||||||
|
* get_aux_clock_divider vfunc to plug-in into the existing code.
|
||||||
|
*/
|
||||||
|
return index ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 g4x_get_aux_send_ctl(struct intel_dp *intel_dp,
|
||||||
|
int send_bytes,
|
||||||
|
u32 aux_clock_divider)
|
||||||
|
{
|
||||||
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
|
struct drm_i915_private *dev_priv =
|
||||||
|
to_i915(dig_port->base.base.dev);
|
||||||
|
u32 precharge, timeout;
|
||||||
|
|
||||||
|
if (IS_GEN(dev_priv, 6))
|
||||||
|
precharge = 3;
|
||||||
|
else
|
||||||
|
precharge = 5;
|
||||||
|
|
||||||
|
if (IS_BROADWELL(dev_priv))
|
||||||
|
timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
|
||||||
|
else
|
||||||
|
timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
|
||||||
|
|
||||||
|
return DP_AUX_CH_CTL_SEND_BUSY |
|
||||||
|
DP_AUX_CH_CTL_DONE |
|
||||||
|
DP_AUX_CH_CTL_INTERRUPT |
|
||||||
|
DP_AUX_CH_CTL_TIME_OUT_ERROR |
|
||||||
|
timeout |
|
||||||
|
DP_AUX_CH_CTL_RECEIVE_ERROR |
|
||||||
|
(send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
|
||||||
|
(precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
|
||||||
|
(aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 skl_get_aux_send_ctl(struct intel_dp *intel_dp,
|
||||||
|
int send_bytes,
|
||||||
|
u32 unused)
|
||||||
|
{
|
||||||
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
|
struct drm_i915_private *i915 =
|
||||||
|
to_i915(dig_port->base.base.dev);
|
||||||
|
enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
|
||||||
|
u32 ret;
|
||||||
|
|
||||||
|
ret = DP_AUX_CH_CTL_SEND_BUSY |
|
||||||
|
DP_AUX_CH_CTL_DONE |
|
||||||
|
DP_AUX_CH_CTL_INTERRUPT |
|
||||||
|
DP_AUX_CH_CTL_TIME_OUT_ERROR |
|
||||||
|
DP_AUX_CH_CTL_TIME_OUT_MAX |
|
||||||
|
DP_AUX_CH_CTL_RECEIVE_ERROR |
|
||||||
|
(send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
|
||||||
|
DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(32) |
|
||||||
|
DP_AUX_CH_CTL_SYNC_PULSE_SKL(32);
|
||||||
|
|
||||||
|
if (intel_phy_is_tc(i915, phy) &&
|
||||||
|
dig_port->tc_mode == TC_PORT_TBT_ALT)
|
||||||
|
ret |= DP_AUX_CH_CTL_TBT_IO;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
intel_dp_aux_xfer(struct intel_dp *intel_dp,
|
||||||
|
const u8 *send, int send_bytes,
|
||||||
|
u8 *recv, int recv_size,
|
||||||
|
u32 aux_send_ctl_flags)
|
||||||
|
{
|
||||||
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
|
struct drm_i915_private *i915 =
|
||||||
|
to_i915(dig_port->base.base.dev);
|
||||||
|
struct intel_uncore *uncore = &i915->uncore;
|
||||||
|
enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
|
||||||
|
bool is_tc_port = intel_phy_is_tc(i915, phy);
|
||||||
|
i915_reg_t ch_ctl, ch_data[5];
|
||||||
|
u32 aux_clock_divider;
|
||||||
|
enum intel_display_power_domain aux_domain;
|
||||||
|
intel_wakeref_t aux_wakeref;
|
||||||
|
intel_wakeref_t pps_wakeref;
|
||||||
|
int i, ret, recv_bytes;
|
||||||
|
int try, clock = 0;
|
||||||
|
u32 status;
|
||||||
|
bool vdd;
|
||||||
|
|
||||||
|
ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
|
||||||
|
for (i = 0; i < ARRAY_SIZE(ch_data); i++)
|
||||||
|
ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i);
|
||||||
|
|
||||||
|
if (is_tc_port)
|
||||||
|
intel_tc_port_lock(dig_port);
|
||||||
|
|
||||||
|
aux_domain = intel_aux_power_domain(dig_port);
|
||||||
|
|
||||||
|
aux_wakeref = intel_display_power_get(i915, aux_domain);
|
||||||
|
pps_wakeref = intel_pps_lock(intel_dp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We will be called with VDD already enabled for dpcd/edid/oui reads.
|
||||||
|
* In such cases we want to leave VDD enabled and it's up to upper layers
|
||||||
|
* to turn it off. But for eg. i2c-dev access we need to turn it on/off
|
||||||
|
* ourselves.
|
||||||
|
*/
|
||||||
|
vdd = intel_pps_vdd_on_unlocked(intel_dp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dp aux is extremely sensitive to irq latency, hence request the
|
||||||
|
* lowest possible wakeup latency and so prevent the cpu from going into
|
||||||
|
* deep sleep states.
|
||||||
|
*/
|
||||||
|
cpu_latency_qos_update_request(&intel_dp->pm_qos, 0);
|
||||||
|
|
||||||
|
intel_pps_check_power_unlocked(intel_dp);
|
||||||
|
|
||||||
|
/* Try to wait for any previous AUX channel activity */
|
||||||
|
for (try = 0; try < 3; try++) {
|
||||||
|
status = intel_uncore_read_notrace(uncore, ch_ctl);
|
||||||
|
if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
|
||||||
|
break;
|
||||||
|
msleep(1);
|
||||||
|
}
|
||||||
|
/* just trace the final value */
|
||||||
|
trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
|
||||||
|
|
||||||
|
if (try == 3) {
|
||||||
|
const u32 status = intel_uncore_read(uncore, ch_ctl);
|
||||||
|
|
||||||
|
if (status != intel_dp->aux_busy_last_status) {
|
||||||
|
drm_WARN(&i915->drm, 1,
|
||||||
|
"%s: not started (status 0x%08x)\n",
|
||||||
|
intel_dp->aux.name, status);
|
||||||
|
intel_dp->aux_busy_last_status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only 5 data registers! */
|
||||||
|
if (drm_WARN_ON(&i915->drm, send_bytes > 20 || recv_size > 20)) {
|
||||||
|
ret = -E2BIG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
|
||||||
|
u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
|
||||||
|
send_bytes,
|
||||||
|
aux_clock_divider);
|
||||||
|
|
||||||
|
send_ctl |= aux_send_ctl_flags;
|
||||||
|
|
||||||
|
/* Must try at least 3 times according to DP spec */
|
||||||
|
for (try = 0; try < 5; try++) {
|
||||||
|
/* Load the send data into the aux channel data registers */
|
||||||
|
for (i = 0; i < send_bytes; i += 4)
|
||||||
|
intel_uncore_write(uncore,
|
||||||
|
ch_data[i >> 2],
|
||||||
|
intel_dp_pack_aux(send + i,
|
||||||
|
send_bytes - i));
|
||||||
|
|
||||||
|
/* Send the command and wait for it to complete */
|
||||||
|
intel_uncore_write(uncore, ch_ctl, send_ctl);
|
||||||
|
|
||||||
|
status = intel_dp_aux_wait_done(intel_dp);
|
||||||
|
|
||||||
|
/* Clear done status and any errors */
|
||||||
|
intel_uncore_write(uncore,
|
||||||
|
ch_ctl,
|
||||||
|
status |
|
||||||
|
DP_AUX_CH_CTL_DONE |
|
||||||
|
DP_AUX_CH_CTL_TIME_OUT_ERROR |
|
||||||
|
DP_AUX_CH_CTL_RECEIVE_ERROR);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DP CTS 1.2 Core Rev 1.1, 4.2.1.1 & 4.2.1.2
|
||||||
|
* 400us delay required for errors and timeouts
|
||||||
|
* Timeout errors from the HW already meet this
|
||||||
|
* requirement so skip to next iteration
|
||||||
|
*/
|
||||||
|
if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
|
||||||
|
usleep_range(400, 500);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (status & DP_AUX_CH_CTL_DONE)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status & DP_AUX_CH_CTL_DONE) == 0) {
|
||||||
|
drm_err(&i915->drm, "%s: not done (status 0x%08x)\n",
|
||||||
|
intel_dp->aux.name, status);
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
/*
|
||||||
|
* Check for timeout or receive error. Timeouts occur when the sink is
|
||||||
|
* not connected.
|
||||||
|
*/
|
||||||
|
if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
|
||||||
|
drm_err(&i915->drm, "%s: receive error (status 0x%08x)\n",
|
||||||
|
intel_dp->aux.name, status);
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Timeouts occur when the device isn't connected, so they're "normal"
|
||||||
|
* -- don't fill the kernel log with these
|
||||||
|
*/
|
||||||
|
if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
|
||||||
|
drm_dbg_kms(&i915->drm, "%s: timeout (status 0x%08x)\n",
|
||||||
|
intel_dp->aux.name, status);
|
||||||
|
ret = -ETIMEDOUT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unload any bytes sent back from the other side */
|
||||||
|
recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
|
||||||
|
DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* By BSpec: "Message sizes of 0 or >20 are not allowed."
|
||||||
|
* We have no idea of what happened so we return -EBUSY so
|
||||||
|
* drm layer takes care for the necessary retries.
|
||||||
|
*/
|
||||||
|
if (recv_bytes == 0 || recv_bytes > 20) {
|
||||||
|
drm_dbg_kms(&i915->drm,
|
||||||
|
"%s: Forbidden recv_bytes = %d on aux transaction\n",
|
||||||
|
intel_dp->aux.name, recv_bytes);
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recv_bytes > recv_size)
|
||||||
|
recv_bytes = recv_size;
|
||||||
|
|
||||||
|
for (i = 0; i < recv_bytes; i += 4)
|
||||||
|
intel_dp_unpack_aux(intel_uncore_read(uncore, ch_data[i >> 2]),
|
||||||
|
recv + i, recv_bytes - i);
|
||||||
|
|
||||||
|
ret = recv_bytes;
|
||||||
|
out:
|
||||||
|
cpu_latency_qos_update_request(&intel_dp->pm_qos, PM_QOS_DEFAULT_VALUE);
|
||||||
|
|
||||||
|
if (vdd)
|
||||||
|
intel_pps_vdd_off_unlocked(intel_dp, false);
|
||||||
|
|
||||||
|
intel_pps_unlock(intel_dp, pps_wakeref);
|
||||||
|
intel_display_power_put_async(i915, aux_domain, aux_wakeref);
|
||||||
|
|
||||||
|
if (is_tc_port)
|
||||||
|
intel_tc_port_unlock(dig_port);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BARE_ADDRESS_SIZE 3
|
||||||
|
#define HEADER_SIZE (BARE_ADDRESS_SIZE + 1)
|
||||||
|
|
||||||
|
static void
|
||||||
|
intel_dp_aux_header(u8 txbuf[HEADER_SIZE],
|
||||||
|
const struct drm_dp_aux_msg *msg)
|
||||||
|
{
|
||||||
|
txbuf[0] = (msg->request << 4) | ((msg->address >> 16) & 0xf);
|
||||||
|
txbuf[1] = (msg->address >> 8) & 0xff;
|
||||||
|
txbuf[2] = msg->address & 0xff;
|
||||||
|
txbuf[3] = msg->size - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 intel_dp_aux_xfer_flags(const struct drm_dp_aux_msg *msg)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If we're trying to send the HDCP Aksv, we need to set a the Aksv
|
||||||
|
* select bit to inform the hardware to send the Aksv after our header
|
||||||
|
* since we can't access that data from software.
|
||||||
|
*/
|
||||||
|
if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE &&
|
||||||
|
msg->address == DP_AUX_HDCP_AKSV)
|
||||||
|
return DP_AUX_CH_CTL_AUX_AKSV_SELECT;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
|
||||||
|
{
|
||||||
|
struct intel_dp *intel_dp = container_of(aux, struct intel_dp, aux);
|
||||||
|
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||||
|
u8 txbuf[20], rxbuf[20];
|
||||||
|
size_t txsize, rxsize;
|
||||||
|
u32 flags = intel_dp_aux_xfer_flags(msg);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
intel_dp_aux_header(txbuf, msg);
|
||||||
|
|
||||||
|
switch (msg->request & ~DP_AUX_I2C_MOT) {
|
||||||
|
case DP_AUX_NATIVE_WRITE:
|
||||||
|
case DP_AUX_I2C_WRITE:
|
||||||
|
case DP_AUX_I2C_WRITE_STATUS_UPDATE:
|
||||||
|
txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE;
|
||||||
|
rxsize = 2; /* 0 or 1 data bytes */
|
||||||
|
|
||||||
|
if (drm_WARN_ON(&i915->drm, txsize > 20))
|
||||||
|
return -E2BIG;
|
||||||
|
|
||||||
|
drm_WARN_ON(&i915->drm, !msg->buffer != !msg->size);
|
||||||
|
|
||||||
|
if (msg->buffer)
|
||||||
|
memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
|
||||||
|
|
||||||
|
ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
|
||||||
|
rxbuf, rxsize, flags);
|
||||||
|
if (ret > 0) {
|
||||||
|
msg->reply = rxbuf[0] >> 4;
|
||||||
|
|
||||||
|
if (ret > 1) {
|
||||||
|
/* Number of bytes written in a short write. */
|
||||||
|
ret = clamp_t(int, rxbuf[1], 0, msg->size);
|
||||||
|
} else {
|
||||||
|
/* Return payload size. */
|
||||||
|
ret = msg->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DP_AUX_NATIVE_READ:
|
||||||
|
case DP_AUX_I2C_READ:
|
||||||
|
txsize = msg->size ? HEADER_SIZE : BARE_ADDRESS_SIZE;
|
||||||
|
rxsize = msg->size + 1;
|
||||||
|
|
||||||
|
if (drm_WARN_ON(&i915->drm, rxsize > 20))
|
||||||
|
return -E2BIG;
|
||||||
|
|
||||||
|
ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
|
||||||
|
rxbuf, rxsize, flags);
|
||||||
|
if (ret > 0) {
|
||||||
|
msg->reply = rxbuf[0] >> 4;
|
||||||
|
/*
|
||||||
|
* Assume happy day, and copy the data. The caller is
|
||||||
|
* expected to check msg->reply before touching it.
|
||||||
|
*
|
||||||
|
* Return payload size.
|
||||||
|
*/
|
||||||
|
ret--;
|
||||||
|
memcpy(msg->buffer, rxbuf + 1, ret);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static i915_reg_t g4x_aux_ctl_reg(struct intel_dp *intel_dp)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
|
||||||
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
|
enum aux_ch aux_ch = dig_port->aux_ch;
|
||||||
|
|
||||||
|
switch (aux_ch) {
|
||||||
|
case AUX_CH_B:
|
||||||
|
case AUX_CH_C:
|
||||||
|
case AUX_CH_D:
|
||||||
|
return DP_AUX_CH_CTL(aux_ch);
|
||||||
|
default:
|
||||||
|
MISSING_CASE(aux_ch);
|
||||||
|
return DP_AUX_CH_CTL(AUX_CH_B);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static i915_reg_t g4x_aux_data_reg(struct intel_dp *intel_dp, int index)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
|
||||||
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
|
enum aux_ch aux_ch = dig_port->aux_ch;
|
||||||
|
|
||||||
|
switch (aux_ch) {
|
||||||
|
case AUX_CH_B:
|
||||||
|
case AUX_CH_C:
|
||||||
|
case AUX_CH_D:
|
||||||
|
return DP_AUX_CH_DATA(aux_ch, index);
|
||||||
|
default:
|
||||||
|
MISSING_CASE(aux_ch);
|
||||||
|
return DP_AUX_CH_DATA(AUX_CH_B, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static i915_reg_t ilk_aux_ctl_reg(struct intel_dp *intel_dp)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
|
||||||
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
|
enum aux_ch aux_ch = dig_port->aux_ch;
|
||||||
|
|
||||||
|
switch (aux_ch) {
|
||||||
|
case AUX_CH_A:
|
||||||
|
return DP_AUX_CH_CTL(aux_ch);
|
||||||
|
case AUX_CH_B:
|
||||||
|
case AUX_CH_C:
|
||||||
|
case AUX_CH_D:
|
||||||
|
return PCH_DP_AUX_CH_CTL(aux_ch);
|
||||||
|
default:
|
||||||
|
MISSING_CASE(aux_ch);
|
||||||
|
return DP_AUX_CH_CTL(AUX_CH_A);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static i915_reg_t ilk_aux_data_reg(struct intel_dp *intel_dp, int index)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
|
||||||
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
|
enum aux_ch aux_ch = dig_port->aux_ch;
|
||||||
|
|
||||||
|
switch (aux_ch) {
|
||||||
|
case AUX_CH_A:
|
||||||
|
return DP_AUX_CH_DATA(aux_ch, index);
|
||||||
|
case AUX_CH_B:
|
||||||
|
case AUX_CH_C:
|
||||||
|
case AUX_CH_D:
|
||||||
|
return PCH_DP_AUX_CH_DATA(aux_ch, index);
|
||||||
|
default:
|
||||||
|
MISSING_CASE(aux_ch);
|
||||||
|
return DP_AUX_CH_DATA(AUX_CH_A, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
|
||||||
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
|
enum aux_ch aux_ch = dig_port->aux_ch;
|
||||||
|
|
||||||
|
switch (aux_ch) {
|
||||||
|
case AUX_CH_A:
|
||||||
|
case AUX_CH_B:
|
||||||
|
case AUX_CH_C:
|
||||||
|
case AUX_CH_D:
|
||||||
|
case AUX_CH_E:
|
||||||
|
case AUX_CH_F:
|
||||||
|
return DP_AUX_CH_CTL(aux_ch);
|
||||||
|
default:
|
||||||
|
MISSING_CASE(aux_ch);
|
||||||
|
return DP_AUX_CH_CTL(AUX_CH_A);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
|
||||||
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
|
enum aux_ch aux_ch = dig_port->aux_ch;
|
||||||
|
|
||||||
|
switch (aux_ch) {
|
||||||
|
case AUX_CH_A:
|
||||||
|
case AUX_CH_B:
|
||||||
|
case AUX_CH_C:
|
||||||
|
case AUX_CH_D:
|
||||||
|
case AUX_CH_E:
|
||||||
|
case AUX_CH_F:
|
||||||
|
return DP_AUX_CH_DATA(aux_ch, index);
|
||||||
|
default:
|
||||||
|
MISSING_CASE(aux_ch);
|
||||||
|
return DP_AUX_CH_DATA(AUX_CH_A, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static i915_reg_t tgl_aux_ctl_reg(struct intel_dp *intel_dp)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
|
||||||
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
|
enum aux_ch aux_ch = dig_port->aux_ch;
|
||||||
|
|
||||||
|
switch (aux_ch) {
|
||||||
|
case AUX_CH_A:
|
||||||
|
case AUX_CH_B:
|
||||||
|
case AUX_CH_C:
|
||||||
|
case AUX_CH_USBC1:
|
||||||
|
case AUX_CH_USBC2:
|
||||||
|
case AUX_CH_USBC3:
|
||||||
|
case AUX_CH_USBC4:
|
||||||
|
case AUX_CH_USBC5:
|
||||||
|
case AUX_CH_USBC6:
|
||||||
|
return DP_AUX_CH_CTL(aux_ch);
|
||||||
|
default:
|
||||||
|
MISSING_CASE(aux_ch);
|
||||||
|
return DP_AUX_CH_CTL(AUX_CH_A);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static i915_reg_t tgl_aux_data_reg(struct intel_dp *intel_dp, int index)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
|
||||||
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
|
enum aux_ch aux_ch = dig_port->aux_ch;
|
||||||
|
|
||||||
|
switch (aux_ch) {
|
||||||
|
case AUX_CH_A:
|
||||||
|
case AUX_CH_B:
|
||||||
|
case AUX_CH_C:
|
||||||
|
case AUX_CH_USBC1:
|
||||||
|
case AUX_CH_USBC2:
|
||||||
|
case AUX_CH_USBC3:
|
||||||
|
case AUX_CH_USBC4:
|
||||||
|
case AUX_CH_USBC5:
|
||||||
|
case AUX_CH_USBC6:
|
||||||
|
return DP_AUX_CH_DATA(aux_ch, index);
|
||||||
|
default:
|
||||||
|
MISSING_CASE(aux_ch);
|
||||||
|
return DP_AUX_CH_DATA(AUX_CH_A, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void intel_dp_aux_fini(struct intel_dp *intel_dp)
|
||||||
|
{
|
||||||
|
if (cpu_latency_qos_request_active(&intel_dp->pm_qos))
|
||||||
|
cpu_latency_qos_remove_request(&intel_dp->pm_qos);
|
||||||
|
|
||||||
|
kfree(intel_dp->aux.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void intel_dp_aux_init(struct intel_dp *intel_dp)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
|
||||||
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
|
struct intel_encoder *encoder = &dig_port->base;
|
||||||
|
enum aux_ch aux_ch = dig_port->aux_ch;
|
||||||
|
|
||||||
|
if (INTEL_GEN(dev_priv) >= 12) {
|
||||||
|
intel_dp->aux_ch_ctl_reg = tgl_aux_ctl_reg;
|
||||||
|
intel_dp->aux_ch_data_reg = tgl_aux_data_reg;
|
||||||
|
} else if (INTEL_GEN(dev_priv) >= 9) {
|
||||||
|
intel_dp->aux_ch_ctl_reg = skl_aux_ctl_reg;
|
||||||
|
intel_dp->aux_ch_data_reg = skl_aux_data_reg;
|
||||||
|
} else if (HAS_PCH_SPLIT(dev_priv)) {
|
||||||
|
intel_dp->aux_ch_ctl_reg = ilk_aux_ctl_reg;
|
||||||
|
intel_dp->aux_ch_data_reg = ilk_aux_data_reg;
|
||||||
|
} else {
|
||||||
|
intel_dp->aux_ch_ctl_reg = g4x_aux_ctl_reg;
|
||||||
|
intel_dp->aux_ch_data_reg = g4x_aux_data_reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (INTEL_GEN(dev_priv) >= 9)
|
||||||
|
intel_dp->get_aux_clock_divider = skl_get_aux_clock_divider;
|
||||||
|
else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
|
||||||
|
intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider;
|
||||||
|
else if (HAS_PCH_SPLIT(dev_priv))
|
||||||
|
intel_dp->get_aux_clock_divider = ilk_get_aux_clock_divider;
|
||||||
|
else
|
||||||
|
intel_dp->get_aux_clock_divider = g4x_get_aux_clock_divider;
|
||||||
|
|
||||||
|
if (INTEL_GEN(dev_priv) >= 9)
|
||||||
|
intel_dp->get_aux_send_ctl = skl_get_aux_send_ctl;
|
||||||
|
else
|
||||||
|
intel_dp->get_aux_send_ctl = g4x_get_aux_send_ctl;
|
||||||
|
|
||||||
|
drm_dp_aux_init(&intel_dp->aux);
|
||||||
|
|
||||||
|
/* Failure to allocate our preferred name is not critical */
|
||||||
|
if (INTEL_GEN(dev_priv) >= 12 && aux_ch >= AUX_CH_USBC1)
|
||||||
|
intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX USBC%c/%s",
|
||||||
|
aux_ch - AUX_CH_USBC1 + '1',
|
||||||
|
encoder->base.name);
|
||||||
|
else
|
||||||
|
intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/%s",
|
||||||
|
aux_ch_name(aux_ch),
|
||||||
|
encoder->base.name);
|
||||||
|
|
||||||
|
intel_dp->aux.transfer = intel_dp_aux_transfer;
|
||||||
|
cpu_latency_qos_add_request(&intel_dp->pm_qos, PM_QOS_DEFAULT_VALUE);
|
||||||
|
}
|
||||||
18
drivers/gpu/drm/i915/display/intel_dp_aux.h
Normal file
18
drivers/gpu/drm/i915/display/intel_dp_aux.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
/*
|
||||||
|
* Copyright © 2020-2021 Intel Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __INTEL_DP_AUX_H__
|
||||||
|
#define __INTEL_DP_AUX_H__
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
struct intel_dp;
|
||||||
|
|
||||||
|
u32 intel_dp_pack_aux(const u8 *src, int src_bytes);
|
||||||
|
|
||||||
|
void intel_dp_aux_fini(struct intel_dp *intel_dp);
|
||||||
|
void intel_dp_aux_init(struct intel_dp *intel_dp);
|
||||||
|
|
||||||
|
#endif /* __INTEL_DP_AUX_H__ */
|
||||||
@@ -22,8 +22,26 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Laptops with Intel GPUs which have panels that support controlling the
|
||||||
|
* backlight through DP AUX can actually use two different interfaces: Intel's
|
||||||
|
* proprietary DP AUX backlight interface, and the standard VESA backlight
|
||||||
|
* interface. Unfortunately, at the time of writing this a lot of laptops will
|
||||||
|
* advertise support for the standard VESA backlight interface when they
|
||||||
|
* don't properly support it. However, on these systems the Intel backlight
|
||||||
|
* interface generally does work properly. Additionally, these systems will
|
||||||
|
* usually just indicate that they use PWM backlight controls in their VBIOS
|
||||||
|
* for some reason.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "intel_display_types.h"
|
#include "intel_display_types.h"
|
||||||
#include "intel_dp_aux_backlight.h"
|
#include "intel_dp_aux_backlight.h"
|
||||||
|
#include "intel_panel.h"
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
* Implement HDR, right now we just implement the bare minimum to bring us back into SDR mode so we
|
||||||
|
* can make people's backlights work in the mean time
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DP AUX registers for Intel's proprietary HDR backlight interface. We define
|
* DP AUX registers for Intel's proprietary HDR backlight interface. We define
|
||||||
@@ -77,6 +95,178 @@
|
|||||||
|
|
||||||
#define INTEL_EDP_BRIGHTNESS_OPTIMIZATION_1 0x359
|
#define INTEL_EDP_BRIGHTNESS_OPTIMIZATION_1 0x359
|
||||||
|
|
||||||
|
/* Intel EDP backlight callbacks */
|
||||||
|
static bool
|
||||||
|
intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
|
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
|
||||||
|
struct drm_dp_aux *aux = &intel_dp->aux;
|
||||||
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
int ret;
|
||||||
|
u8 tcon_cap[4];
|
||||||
|
|
||||||
|
ret = drm_dp_dpcd_read(aux, INTEL_EDP_HDR_TCON_CAP0, tcon_cap, sizeof(tcon_cap));
|
||||||
|
if (ret < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!(tcon_cap[1] & INTEL_EDP_HDR_TCON_BRIGHTNESS_NITS_CAP))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (tcon_cap[0] >= 1) {
|
||||||
|
drm_dbg_kms(&i915->drm, "Detected Intel HDR backlight interface version %d\n",
|
||||||
|
tcon_cap[0]);
|
||||||
|
} else {
|
||||||
|
drm_dbg_kms(&i915->drm, "Detected unsupported HDR backlight interface version %d\n",
|
||||||
|
tcon_cap[0]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
panel->backlight.edp.intel.sdr_uses_aux =
|
||||||
|
tcon_cap[2] & INTEL_EDP_SDR_TCON_BRIGHTNESS_AUX_CAP;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32
|
||||||
|
intel_dp_aux_hdr_get_backlight(struct intel_connector *connector, enum pipe pipe)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
|
||||||
|
u8 tmp;
|
||||||
|
u8 buf[2] = { 0 };
|
||||||
|
|
||||||
|
if (drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &tmp) < 0) {
|
||||||
|
drm_err(&i915->drm, "Failed to read current backlight mode from DPCD\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(tmp & INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE)) {
|
||||||
|
if (!panel->backlight.edp.intel.sdr_uses_aux) {
|
||||||
|
u32 pwm_level = panel->backlight.pwm_funcs->get(connector, pipe);
|
||||||
|
|
||||||
|
return intel_panel_backlight_level_from_pwm(connector, pwm_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assume 100% brightness if backlight controls aren't enabled yet */
|
||||||
|
return panel->backlight.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drm_dp_dpcd_read(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf, sizeof(buf)) < 0) {
|
||||||
|
drm_err(&i915->drm, "Failed to read brightness from DPCD\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (buf[1] << 8 | buf[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
intel_dp_aux_hdr_set_aux_backlight(const struct drm_connector_state *conn_state, u32 level)
|
||||||
|
{
|
||||||
|
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
||||||
|
struct drm_device *dev = connector->base.dev;
|
||||||
|
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
|
||||||
|
u8 buf[4] = { 0 };
|
||||||
|
|
||||||
|
buf[0] = level & 0xFF;
|
||||||
|
buf[1] = (level & 0xFF00) >> 8;
|
||||||
|
|
||||||
|
if (drm_dp_dpcd_write(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf, 4) < 0)
|
||||||
|
drm_err(dev, "Failed to write brightness level to DPCD\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
intel_dp_aux_hdr_set_backlight(const struct drm_connector_state *conn_state, u32 level)
|
||||||
|
{
|
||||||
|
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
||||||
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
|
||||||
|
if (panel->backlight.edp.intel.sdr_uses_aux) {
|
||||||
|
intel_dp_aux_hdr_set_aux_backlight(conn_state, level);
|
||||||
|
} else {
|
||||||
|
const u32 pwm_level = intel_panel_backlight_level_to_pwm(connector, level);
|
||||||
|
|
||||||
|
intel_panel_set_pwm_level(conn_state, pwm_level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state,
|
||||||
|
const struct drm_connector_state *conn_state, u32 level)
|
||||||
|
{
|
||||||
|
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
||||||
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
|
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
|
||||||
|
int ret;
|
||||||
|
u8 old_ctrl, ctrl;
|
||||||
|
|
||||||
|
ret = drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &old_ctrl);
|
||||||
|
if (ret < 0) {
|
||||||
|
drm_err(&i915->drm, "Failed to read current backlight control mode: %d\n", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl = old_ctrl;
|
||||||
|
if (panel->backlight.edp.intel.sdr_uses_aux) {
|
||||||
|
ctrl |= INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE;
|
||||||
|
intel_dp_aux_hdr_set_aux_backlight(conn_state, level);
|
||||||
|
} else {
|
||||||
|
u32 pwm_level = intel_panel_backlight_level_to_pwm(connector, level);
|
||||||
|
|
||||||
|
panel->backlight.pwm_funcs->enable(crtc_state, conn_state, pwm_level);
|
||||||
|
|
||||||
|
ctrl &= ~INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctrl != old_ctrl)
|
||||||
|
if (drm_dp_dpcd_writeb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, ctrl) < 0)
|
||||||
|
drm_err(&i915->drm, "Failed to configure DPCD brightness controls\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
intel_dp_aux_hdr_disable_backlight(const struct drm_connector_state *conn_state, u32 level)
|
||||||
|
{
|
||||||
|
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
||||||
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
|
||||||
|
/* Nothing to do for AUX based backlight controls */
|
||||||
|
if (panel->backlight.edp.intel.sdr_uses_aux)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Note we want the actual pwm_level to be 0, regardless of pwm_min */
|
||||||
|
panel->backlight.pwm_funcs->disable(conn_state, intel_panel_invert_pwm_level(connector, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
intel_dp_aux_hdr_setup_backlight(struct intel_connector *connector, enum pipe pipe)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (panel->backlight.edp.intel.sdr_uses_aux) {
|
||||||
|
drm_dbg_kms(&i915->drm, "SDR backlight is controlled through DPCD\n");
|
||||||
|
} else {
|
||||||
|
drm_dbg_kms(&i915->drm, "SDR backlight is controlled through PWM\n");
|
||||||
|
|
||||||
|
ret = panel->backlight.pwm_funcs->setup(connector, pipe);
|
||||||
|
if (ret < 0) {
|
||||||
|
drm_err(&i915->drm,
|
||||||
|
"Failed to setup SDR backlight controls through PWM: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panel->backlight.max = 512;
|
||||||
|
panel->backlight.min = 0;
|
||||||
|
panel->backlight.level = intel_dp_aux_hdr_get_backlight(connector, pipe);
|
||||||
|
panel->backlight.enabled = panel->backlight.level != 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* VESA backlight callbacks */
|
/* VESA backlight callbacks */
|
||||||
static void set_vesa_backlight_enable(struct intel_dp *intel_dp, bool enable)
|
static void set_vesa_backlight_enable(struct intel_dp *intel_dp, bool enable)
|
||||||
{
|
{
|
||||||
@@ -128,7 +318,7 @@ static bool intel_dp_aux_vesa_backlight_dpcd_mode(struct intel_connector *connec
|
|||||||
* Read the current backlight value from DPCD register(s) based
|
* Read the current backlight value from DPCD register(s) based
|
||||||
* on if 8-bit(MSB) or 16-bit(MSB and LSB) values are supported
|
* on if 8-bit(MSB) or 16-bit(MSB and LSB) values are supported
|
||||||
*/
|
*/
|
||||||
static u32 intel_dp_aux_vesa_get_backlight(struct intel_connector *connector)
|
static u32 intel_dp_aux_vesa_get_backlight(struct intel_connector *connector, enum pipe unused)
|
||||||
{
|
{
|
||||||
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
||||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||||
@@ -195,7 +385,7 @@ static bool intel_dp_aux_vesa_set_pwm_freq(struct intel_connector *connector)
|
|||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
||||||
const u8 pn = connector->panel.backlight.pwmgen_bit_count;
|
const u8 pn = connector->panel.backlight.edp.vesa.pwmgen_bit_count;
|
||||||
int freq, fxp, f, fxp_actual, fxp_min, fxp_max;
|
int freq, fxp, f, fxp_actual, fxp_min, fxp_max;
|
||||||
|
|
||||||
freq = dev_priv->vbt.backlight.pwm_freq_hz;
|
freq = dev_priv->vbt.backlight.pwm_freq_hz;
|
||||||
@@ -236,6 +426,7 @@ intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state,
|
|||||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
u8 dpcd_buf, new_dpcd_buf, edp_backlight_mode;
|
u8 dpcd_buf, new_dpcd_buf, edp_backlight_mode;
|
||||||
|
u8 pwmgen_bit_count = panel->backlight.edp.vesa.pwmgen_bit_count;
|
||||||
|
|
||||||
if (drm_dp_dpcd_readb(&intel_dp->aux,
|
if (drm_dp_dpcd_readb(&intel_dp->aux,
|
||||||
DP_EDP_BACKLIGHT_MODE_SET_REGISTER, &dpcd_buf) != 1) {
|
DP_EDP_BACKLIGHT_MODE_SET_REGISTER, &dpcd_buf) != 1) {
|
||||||
@@ -256,7 +447,7 @@ intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state,
|
|||||||
|
|
||||||
if (drm_dp_dpcd_writeb(&intel_dp->aux,
|
if (drm_dp_dpcd_writeb(&intel_dp->aux,
|
||||||
DP_EDP_PWMGEN_BIT_COUNT,
|
DP_EDP_PWMGEN_BIT_COUNT,
|
||||||
panel->backlight.pwmgen_bit_count) < 0)
|
pwmgen_bit_count) < 0)
|
||||||
drm_dbg_kms(&i915->drm,
|
drm_dbg_kms(&i915->drm,
|
||||||
"Failed to write aux pwmgen bit count\n");
|
"Failed to write aux pwmgen bit count\n");
|
||||||
|
|
||||||
@@ -364,7 +555,7 @@ static u32 intel_dp_aux_vesa_calc_max_backlight(struct intel_connector *connecto
|
|||||||
"Failed to write aux pwmgen bit count\n");
|
"Failed to write aux pwmgen bit count\n");
|
||||||
return max_backlight;
|
return max_backlight;
|
||||||
}
|
}
|
||||||
panel->backlight.pwmgen_bit_count = pn;
|
panel->backlight.edp.vesa.pwmgen_bit_count = pn;
|
||||||
|
|
||||||
max_backlight = (1 << pn) - 1;
|
max_backlight = (1 << pn) - 1;
|
||||||
|
|
||||||
@@ -381,7 +572,7 @@ static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector,
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
panel->backlight.min = 0;
|
panel->backlight.min = 0;
|
||||||
panel->backlight.level = intel_dp_aux_vesa_get_backlight(connector);
|
panel->backlight.level = intel_dp_aux_vesa_get_backlight(connector, pipe);
|
||||||
panel->backlight.enabled = intel_dp_aux_vesa_backlight_dpcd_mode(connector) &&
|
panel->backlight.enabled = intel_dp_aux_vesa_backlight_dpcd_mode(connector) &&
|
||||||
panel->backlight.level != 0;
|
panel->backlight.level != 0;
|
||||||
|
|
||||||
@@ -395,9 +586,14 @@ intel_dp_aux_supports_vesa_backlight(struct intel_connector *connector)
|
|||||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||||
|
|
||||||
/* Check the eDP Display control capabilities registers to determine if
|
/* Check the eDP Display control capabilities registers to determine if
|
||||||
* the panel can support backlight control over the aux channel
|
* the panel can support backlight control over the aux channel.
|
||||||
|
*
|
||||||
|
* TODO: We currently only support AUX only backlight configurations, not backlights which
|
||||||
|
* require a mix of PWM and AUX controls to work. In the mean time, these machines typically
|
||||||
|
* work just fine using normal PWM controls anyway.
|
||||||
*/
|
*/
|
||||||
if (intel_dp->edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP &&
|
if (intel_dp->edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP &&
|
||||||
|
(intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP) &&
|
||||||
(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP)) {
|
(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP)) {
|
||||||
drm_dbg_kms(&i915->drm, "AUX Backlight Control Supported!\n");
|
drm_dbg_kms(&i915->drm, "AUX Backlight Control Supported!\n");
|
||||||
return true;
|
return true;
|
||||||
@@ -405,6 +601,14 @@ intel_dp_aux_supports_vesa_backlight(struct intel_connector *connector)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct intel_panel_bl_funcs intel_dp_hdr_bl_funcs = {
|
||||||
|
.setup = intel_dp_aux_hdr_setup_backlight,
|
||||||
|
.enable = intel_dp_aux_hdr_enable_backlight,
|
||||||
|
.disable = intel_dp_aux_hdr_disable_backlight,
|
||||||
|
.set = intel_dp_aux_hdr_set_backlight,
|
||||||
|
.get = intel_dp_aux_hdr_get_backlight,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct intel_panel_bl_funcs intel_dp_vesa_bl_funcs = {
|
static const struct intel_panel_bl_funcs intel_dp_vesa_bl_funcs = {
|
||||||
.setup = intel_dp_aux_vesa_setup_backlight,
|
.setup = intel_dp_aux_vesa_setup_backlight,
|
||||||
.enable = intel_dp_aux_vesa_enable_backlight,
|
.enable = intel_dp_aux_vesa_enable_backlight,
|
||||||
@@ -413,36 +617,73 @@ static const struct intel_panel_bl_funcs intel_dp_vesa_bl_funcs = {
|
|||||||
.get = intel_dp_aux_vesa_get_backlight,
|
.get = intel_dp_aux_vesa_get_backlight,
|
||||||
};
|
};
|
||||||
|
|
||||||
int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector)
|
enum intel_dp_aux_backlight_modparam {
|
||||||
|
INTEL_DP_AUX_BACKLIGHT_AUTO = -1,
|
||||||
|
INTEL_DP_AUX_BACKLIGHT_OFF = 0,
|
||||||
|
INTEL_DP_AUX_BACKLIGHT_ON = 1,
|
||||||
|
INTEL_DP_AUX_BACKLIGHT_FORCE_VESA = 2,
|
||||||
|
INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
|
||||||
{
|
{
|
||||||
struct intel_panel *panel = &intel_connector->panel;
|
struct drm_device *dev = connector->base.dev;
|
||||||
struct intel_dp *intel_dp = enc_to_intel_dp(intel_connector->encoder);
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
|
||||||
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
|
||||||
|
bool try_intel_interface = false, try_vesa_interface = false;
|
||||||
|
|
||||||
if (i915->params.enable_dpcd_backlight == 0 ||
|
/* Check the VBT and user's module parameters to figure out which
|
||||||
!intel_dp_aux_supports_vesa_backlight(intel_connector))
|
* interfaces to probe
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* There are a lot of machines that don't advertise the backlight
|
|
||||||
* control interface to use properly in their VBIOS, :\
|
|
||||||
*/
|
*/
|
||||||
if (i915->vbt.backlight.type !=
|
switch (i915->params.enable_dpcd_backlight) {
|
||||||
INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE &&
|
case INTEL_DP_AUX_BACKLIGHT_OFF:
|
||||||
i915->params.enable_dpcd_backlight != 1 &&
|
|
||||||
!drm_dp_has_quirk(&intel_dp->desc, intel_dp->edid_quirks,
|
|
||||||
DP_QUIRK_FORCE_DPCD_BACKLIGHT)) {
|
|
||||||
drm_info(&i915->drm,
|
|
||||||
"Panel advertises DPCD backlight support, but "
|
|
||||||
"VBT disagrees. If your backlight controls "
|
|
||||||
"don't work try booting with "
|
|
||||||
"i915.enable_dpcd_backlight=1. If your machine "
|
|
||||||
"needs this, please file a _new_ bug report on "
|
|
||||||
"drm/i915, see " FDO_BUG_URL " for details.\n");
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
case INTEL_DP_AUX_BACKLIGHT_AUTO:
|
||||||
|
switch (i915->vbt.backlight.type) {
|
||||||
|
case INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE:
|
||||||
|
try_vesa_interface = true;
|
||||||
|
break;
|
||||||
|
case INTEL_BACKLIGHT_DISPLAY_DDI:
|
||||||
|
try_intel_interface = true;
|
||||||
|
try_vesa_interface = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INTEL_DP_AUX_BACKLIGHT_ON:
|
||||||
|
if (i915->vbt.backlight.type != INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE)
|
||||||
|
try_intel_interface = true;
|
||||||
|
|
||||||
|
try_vesa_interface = true;
|
||||||
|
break;
|
||||||
|
case INTEL_DP_AUX_BACKLIGHT_FORCE_VESA:
|
||||||
|
try_vesa_interface = true;
|
||||||
|
break;
|
||||||
|
case INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL:
|
||||||
|
try_intel_interface = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
panel->backlight.funcs = &intel_dp_vesa_bl_funcs;
|
/*
|
||||||
|
* A lot of eDP panels in the wild will report supporting both the
|
||||||
|
* Intel proprietary backlight control interface, and the VESA
|
||||||
|
* backlight control interface. Many of these panels are liars though,
|
||||||
|
* and will only work with the Intel interface. So, always probe for
|
||||||
|
* that first.
|
||||||
|
*/
|
||||||
|
if (try_intel_interface && intel_dp_aux_supports_hdr_backlight(connector)) {
|
||||||
|
drm_dbg_kms(dev, "Using Intel proprietary eDP backlight controls\n");
|
||||||
|
panel->backlight.funcs = &intel_dp_hdr_bl_funcs;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
if (try_vesa_interface && intel_dp_aux_supports_vesa_backlight(connector)) {
|
||||||
|
drm_dbg_kms(dev, "Using VESA eDP backlight controls\n");
|
||||||
|
panel->backlight.funcs = &intel_dp_vesa_bl_funcs;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,30 @@
|
|||||||
#include "intel_dp.h"
|
#include "intel_dp.h"
|
||||||
#include "intel_hdcp.h"
|
#include "intel_hdcp.h"
|
||||||
|
|
||||||
|
static unsigned int transcoder_to_stream_enc_status(enum transcoder cpu_transcoder)
|
||||||
|
{
|
||||||
|
u32 stream_enc_mask;
|
||||||
|
|
||||||
|
switch (cpu_transcoder) {
|
||||||
|
case TRANSCODER_A:
|
||||||
|
stream_enc_mask = HDCP_STATUS_STREAM_A_ENC;
|
||||||
|
break;
|
||||||
|
case TRANSCODER_B:
|
||||||
|
stream_enc_mask = HDCP_STATUS_STREAM_B_ENC;
|
||||||
|
break;
|
||||||
|
case TRANSCODER_C:
|
||||||
|
stream_enc_mask = HDCP_STATUS_STREAM_C_ENC;
|
||||||
|
break;
|
||||||
|
case TRANSCODER_D:
|
||||||
|
stream_enc_mask = HDCP_STATUS_STREAM_D_ENC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
stream_enc_mask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream_enc_mask;
|
||||||
|
}
|
||||||
|
|
||||||
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_hdcp *hdcp, int timeout)
|
||||||
{
|
{
|
||||||
long ret;
|
long ret;
|
||||||
@@ -561,7 +585,8 @@ int intel_dp_hdcp2_config_stream_type(struct intel_digital_port *dig_port,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int intel_dp_hdcp2_check_link(struct intel_digital_port *dig_port)
|
int intel_dp_hdcp2_check_link(struct intel_digital_port *dig_port,
|
||||||
|
struct intel_connector *connector)
|
||||||
{
|
{
|
||||||
u8 rx_status;
|
u8 rx_status;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -622,46 +647,151 @@ static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
intel_dp_mst_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
|
intel_dp_mst_toggle_hdcp_stream_select(struct intel_connector *connector,
|
||||||
enum transcoder cpu_transcoder,
|
bool enable)
|
||||||
bool enable)
|
|
||||||
{
|
{
|
||||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
|
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!enable)
|
ret = intel_ddi_toggle_hdcp_bits(&dig_port->base,
|
||||||
usleep_range(6, 60); /* Bspec says >= 6us */
|
hdcp->stream_transcoder, enable,
|
||||||
|
TRANS_DDI_HDCP_SELECT);
|
||||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base,
|
|
||||||
cpu_transcoder, enable);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
drm_dbg_kms(&i915->drm, "%s HDCP signalling failed (%d)\n",
|
drm_err(&i915->drm, "%s HDCP stream select failed (%d)\n",
|
||||||
enable ? "Enable" : "Disable", ret);
|
enable ? "Enable" : "Disable", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
intel_dp_mst_hdcp_stream_encryption(struct intel_connector *connector,
|
||||||
|
bool enable)
|
||||||
|
{
|
||||||
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
|
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||||
|
enum port port = dig_port->base.port;
|
||||||
|
enum transcoder cpu_transcoder = hdcp->stream_transcoder;
|
||||||
|
u32 stream_enc_status;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = intel_dp_mst_toggle_hdcp_stream_select(connector, enable);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
stream_enc_status = transcoder_to_stream_enc_status(cpu_transcoder);
|
||||||
|
if (!stream_enc_status)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Wait for encryption confirmation */
|
||||||
|
if (intel_de_wait_for_register(i915,
|
||||||
|
HDCP_STATUS(i915, cpu_transcoder, port),
|
||||||
|
stream_enc_status,
|
||||||
|
enable ? stream_enc_status : 0,
|
||||||
|
HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS)) {
|
||||||
|
drm_err(&i915->drm, "Timed out waiting for transcoder: %s stream encryption %s\n",
|
||||||
|
transcoder_name(cpu_transcoder), enable ? "enabled" : "disabled");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool intel_dp_mst_get_qses_status(struct intel_digital_port *dig_port,
|
||||||
|
struct intel_connector *connector)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||||
|
struct drm_dp_query_stream_enc_status_ack_reply reply;
|
||||||
|
struct intel_dp *intel_dp = &dig_port->dp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = drm_dp_send_query_stream_enc_status(&intel_dp->mst_mgr,
|
||||||
|
connector->port, &reply);
|
||||||
|
if (ret) {
|
||||||
|
drm_dbg_kms(&i915->drm,
|
||||||
|
"[%s:%d] failed QSES ret=%d\n",
|
||||||
|
connector->base.name, connector->base.base.id, ret);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_dbg_kms(&i915->drm, "[%s:%d] QSES stream auth: %d stream enc: %d\n",
|
||||||
|
connector->base.name, connector->base.base.id,
|
||||||
|
reply.auth_completed, reply.encryption_enabled);
|
||||||
|
|
||||||
|
return reply.auth_completed && reply.encryption_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
bool intel_dp_mst_hdcp_check_link(struct intel_digital_port *dig_port,
|
bool intel_dp_mst_hdcp_check_link(struct intel_digital_port *dig_port,
|
||||||
struct intel_connector *connector)
|
struct intel_connector *connector)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
|
||||||
struct intel_dp *intel_dp = &dig_port->dp;
|
|
||||||
struct drm_dp_query_stream_enc_status_ack_reply reply;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!intel_dp_hdcp_check_link(dig_port, connector))
|
if (!intel_dp_hdcp_check_link(dig_port, connector))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ret = drm_dp_send_query_stream_enc_status(&intel_dp->mst_mgr,
|
return intel_dp_mst_get_qses_status(dig_port, connector);
|
||||||
connector->port, &reply);
|
}
|
||||||
if (ret) {
|
|
||||||
drm_dbg_kms(&i915->drm,
|
static int
|
||||||
"[CONNECTOR:%d:%s] failed QSES ret=%d\n",
|
intel_dp_mst_hdcp2_stream_encryption(struct intel_connector *connector,
|
||||||
connector->base.base.id, connector->base.name, ret);
|
bool enable)
|
||||||
return false;
|
{
|
||||||
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
|
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||||
|
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||||
|
enum transcoder cpu_transcoder = hdcp->stream_transcoder;
|
||||||
|
enum pipe pipe = (enum pipe)cpu_transcoder;
|
||||||
|
enum port port = dig_port->base.port;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
drm_WARN_ON(&i915->drm, enable &&
|
||||||
|
!!(intel_de_read(i915, HDCP2_AUTH_STREAM(i915, cpu_transcoder, port))
|
||||||
|
& AUTH_STREAM_TYPE) != data->streams[0].stream_type);
|
||||||
|
|
||||||
|
ret = intel_dp_mst_toggle_hdcp_stream_select(connector, enable);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Wait for encryption confirmation */
|
||||||
|
if (intel_de_wait_for_register(i915,
|
||||||
|
HDCP2_STREAM_STATUS(i915, cpu_transcoder, pipe),
|
||||||
|
STREAM_ENCRYPTION_STATUS,
|
||||||
|
enable ? STREAM_ENCRYPTION_STATUS : 0,
|
||||||
|
HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS)) {
|
||||||
|
drm_err(&i915->drm, "Timed out waiting for transcoder: %s stream encryption %s\n",
|
||||||
|
transcoder_name(cpu_transcoder), enable ? "enabled" : "disabled");
|
||||||
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return reply.auth_completed && reply.encryption_enabled;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DP v2.0 I.3.3 ignore the stream signature L' in QSES reply msg reply.
|
||||||
|
* I.3.5 MST source device may use a QSES msg to query downstream status
|
||||||
|
* for a particular stream.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int intel_dp_mst_hdcp2_check_link(struct intel_digital_port *dig_port,
|
||||||
|
struct intel_connector *connector)
|
||||||
|
{
|
||||||
|
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We do need to do the Link Check only for the connector involved with
|
||||||
|
* HDCP port authentication and encryption.
|
||||||
|
* We can re-use the hdcp->is_repeater flag to know that the connector
|
||||||
|
* involved with HDCP port authentication and encryption.
|
||||||
|
*/
|
||||||
|
if (hdcp->is_repeater) {
|
||||||
|
ret = intel_dp_hdcp2_check_link(dig_port, connector);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return intel_dp_mst_get_qses_status(dig_port, connector) ? 0 : -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
|
static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
|
||||||
@@ -673,10 +803,16 @@ static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
|
|||||||
.read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
|
.read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
|
||||||
.read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
|
.read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
|
||||||
.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
|
.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
|
||||||
.toggle_signalling = intel_dp_mst_hdcp_toggle_signalling,
|
.toggle_signalling = intel_dp_hdcp_toggle_signalling,
|
||||||
|
.stream_encryption = intel_dp_mst_hdcp_stream_encryption,
|
||||||
.check_link = intel_dp_mst_hdcp_check_link,
|
.check_link = intel_dp_mst_hdcp_check_link,
|
||||||
.hdcp_capable = intel_dp_hdcp_capable,
|
.hdcp_capable = intel_dp_hdcp_capable,
|
||||||
|
.write_2_2_msg = intel_dp_hdcp2_write_msg,
|
||||||
|
.read_2_2_msg = intel_dp_hdcp2_read_msg,
|
||||||
|
.config_stream_type = intel_dp_hdcp2_config_stream_type,
|
||||||
|
.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,
|
||||||
.protocol = HDCP_PROTOCOL_DP,
|
.protocol = HDCP_PROTOCOL_DP,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -693,10 +829,10 @@ int intel_dp_init_hdcp(struct intel_digital_port *dig_port,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (intel_connector->mst_port)
|
if (intel_connector->mst_port)
|
||||||
return intel_hdcp_init(intel_connector, port,
|
return intel_hdcp_init(intel_connector, dig_port,
|
||||||
&intel_dp_mst_hdcp_shim);
|
&intel_dp_mst_hdcp_shim);
|
||||||
else if (!intel_dp_is_edp(intel_dp))
|
else if (!intel_dp_is_edp(intel_dp))
|
||||||
return intel_hdcp_init(intel_connector, port,
|
return intel_hdcp_init(intel_connector, dig_port,
|
||||||
&intel_dp_hdcp_shim);
|
&intel_dp_hdcp_shim);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -334,6 +334,27 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
|
|||||||
return drm_dp_dpcd_write(&intel_dp->aux, reg, buf, len) == len;
|
return drm_dp_dpcd_write(&intel_dp->aux, reg, buf, len) == len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void intel_dp_set_signal_levels(struct intel_dp *intel_dp,
|
||||||
|
const struct intel_crtc_state *crtc_state,
|
||||||
|
enum drm_dp_phy dp_phy)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
|
||||||
|
u8 train_set = intel_dp->train_set[0];
|
||||||
|
char phy_name[10];
|
||||||
|
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "Using vswing level %d%s, pre-emphasis level %d%s, at %s\n",
|
||||||
|
train_set & DP_TRAIN_VOLTAGE_SWING_MASK,
|
||||||
|
train_set & DP_TRAIN_MAX_SWING_REACHED ? " (max)" : "",
|
||||||
|
(train_set & DP_TRAIN_PRE_EMPHASIS_MASK) >>
|
||||||
|
DP_TRAIN_PRE_EMPHASIS_SHIFT,
|
||||||
|
train_set & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED ?
|
||||||
|
" (max)" : "",
|
||||||
|
intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)));
|
||||||
|
|
||||||
|
if (intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy))
|
||||||
|
intel_dp->set_signal_levels(intel_dp, crtc_state);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
intel_dp_reset_link_train(struct intel_dp *intel_dp,
|
intel_dp_reset_link_train(struct intel_dp *intel_dp,
|
||||||
const struct intel_crtc_state *crtc_state,
|
const struct intel_crtc_state *crtc_state,
|
||||||
@@ -341,7 +362,7 @@ intel_dp_reset_link_train(struct intel_dp *intel_dp,
|
|||||||
u8 dp_train_pat)
|
u8 dp_train_pat)
|
||||||
{
|
{
|
||||||
memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
|
memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
|
||||||
intel_dp_set_signal_levels(intel_dp, crtc_state);
|
intel_dp_set_signal_levels(intel_dp, crtc_state, dp_phy);
|
||||||
return intel_dp_set_link_train(intel_dp, crtc_state, dp_phy, dp_train_pat);
|
return intel_dp_set_link_train(intel_dp, crtc_state, dp_phy, dp_train_pat);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +376,7 @@ intel_dp_update_link_train(struct intel_dp *intel_dp,
|
|||||||
DP_TRAINING_LANE0_SET_PHY_REPEATER(dp_phy);
|
DP_TRAINING_LANE0_SET_PHY_REPEATER(dp_phy);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
intel_dp_set_signal_levels(intel_dp, crtc_state);
|
intel_dp_set_signal_levels(intel_dp, crtc_state, dp_phy);
|
||||||
|
|
||||||
ret = drm_dp_dpcd_write(&intel_dp->aux, reg,
|
ret = drm_dp_dpcd_write(&intel_dp->aux, reg,
|
||||||
intel_dp->train_set, crtc_state->lane_count);
|
intel_dp->train_set, crtc_state->lane_count);
|
||||||
@@ -413,7 +434,7 @@ intel_dp_prepare_link_train(struct intel_dp *intel_dp,
|
|||||||
drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
|
drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
|
||||||
&rate_select, 1);
|
&rate_select, 1);
|
||||||
|
|
||||||
link_config[0] = 0;
|
link_config[0] = crtc_state->vrr.enable ? DP_MSA_TIMING_PAR_IGNORE_EN : 0;
|
||||||
link_config[1] = DP_SET_ANSI_8B10B;
|
link_config[1] = DP_SET_ANSI_8B10B;
|
||||||
drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
|
drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
|
||||||
|
|
||||||
@@ -676,9 +697,9 @@ static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp,
|
|||||||
* @intel_dp: DP struct
|
* @intel_dp: DP struct
|
||||||
* @crtc_state: state for CRTC attached to the encoder
|
* @crtc_state: state for CRTC attached to the encoder
|
||||||
*
|
*
|
||||||
* Stop the link training of the @intel_dp port, disabling the test pattern
|
* Stop the link training of the @intel_dp port, disabling the training
|
||||||
* symbol generation on the port and disabling the training pattern in
|
* pattern in the sink's DPCD, and disabling the test pattern symbol
|
||||||
* the sink's DPCD.
|
* generation on the port.
|
||||||
*
|
*
|
||||||
* What symbols are output on the port after this point is
|
* What symbols are output on the port after this point is
|
||||||
* platform specific: On DDI/VLV/CHV platforms it will be the idle pattern
|
* platform specific: On DDI/VLV/CHV platforms it will be the idle pattern
|
||||||
@@ -692,10 +713,9 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp,
|
|||||||
{
|
{
|
||||||
intel_dp->link_trained = true;
|
intel_dp->link_trained = true;
|
||||||
|
|
||||||
intel_dp_program_link_training_pattern(intel_dp,
|
|
||||||
crtc_state,
|
|
||||||
DP_TRAINING_PATTERN_DISABLE);
|
|
||||||
intel_dp_disable_dpcd_training_pattern(intel_dp, DP_PHY_DPRX);
|
intel_dp_disable_dpcd_training_pattern(intel_dp, DP_PHY_DPRX);
|
||||||
|
intel_dp_program_link_training_pattern(intel_dp, crtc_state,
|
||||||
|
DP_TRAINING_PATTERN_DISABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
|
|||||||
const struct intel_crtc_state *crtc_state,
|
const struct intel_crtc_state *crtc_state,
|
||||||
enum drm_dp_phy dp_phy,
|
enum drm_dp_phy dp_phy,
|
||||||
const u8 link_status[DP_LINK_STATUS_SIZE]);
|
const u8 link_status[DP_LINK_STATUS_SIZE]);
|
||||||
|
void intel_dp_set_signal_levels(struct intel_dp *intel_dp,
|
||||||
|
const struct intel_crtc_state *crtc_state,
|
||||||
|
enum drm_dp_phy dp_phy);
|
||||||
void intel_dp_start_link_train(struct intel_dp *intel_dp,
|
void intel_dp_start_link_train(struct intel_dp *intel_dp,
|
||||||
const struct intel_crtc_state *crtc_state);
|
const struct intel_crtc_state *crtc_state);
|
||||||
void intel_dp_stop_link_train(struct intel_dp *intel_dp,
|
void intel_dp_stop_link_train(struct intel_dp *intel_dp,
|
||||||
|
|||||||
@@ -53,8 +53,7 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
|
|||||||
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
const struct drm_display_mode *adjusted_mode =
|
const struct drm_display_mode *adjusted_mode =
|
||||||
&crtc_state->hw.adjusted_mode;
|
&crtc_state->hw.adjusted_mode;
|
||||||
bool constant_n = drm_dp_has_quirk(&intel_dp->desc, 0,
|
bool constant_n = drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_CONSTANT_N);
|
||||||
DP_DPCD_QUIRK_CONSTANT_N);
|
|
||||||
int bpp, slots = -EINVAL;
|
int bpp, slots = -EINVAL;
|
||||||
|
|
||||||
crtc_state->lane_count = limits->max_lane_count;
|
crtc_state->lane_count = limits->max_lane_count;
|
||||||
@@ -569,7 +568,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
|
|||||||
if (conn_state->content_protection ==
|
if (conn_state->content_protection ==
|
||||||
DRM_MODE_CONTENT_PROTECTION_DESIRED)
|
DRM_MODE_CONTENT_PROTECTION_DESIRED)
|
||||||
intel_hdcp_enable(to_intel_connector(conn_state->connector),
|
intel_hdcp_enable(to_intel_connector(conn_state->connector),
|
||||||
pipe_config->cpu_transcoder,
|
pipe_config,
|
||||||
(u8)conn_state->hdcp_content_type);
|
(u8)conn_state->hdcp_content_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -829,12 +828,11 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
|
|||||||
intel_attach_force_audio_property(connector);
|
intel_attach_force_audio_property(connector);
|
||||||
intel_attach_broadcast_rgb_property(connector);
|
intel_attach_broadcast_rgb_property(connector);
|
||||||
|
|
||||||
|
if (INTEL_GEN(dev_priv) <= 12) {
|
||||||
/* TODO: Figure out how to make HDCP work on GEN12+ */
|
|
||||||
if (INTEL_GEN(dev_priv) < 12) {
|
|
||||||
ret = intel_dp_init_hdcp(dig_port, intel_connector);
|
ret = intel_dp_init_hdcp(dig_port, intel_connector);
|
||||||
if (ret)
|
if (ret)
|
||||||
DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
|
drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP MST init failed, skipping.\n",
|
||||||
|
connector->name, connector->base.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
1363
drivers/gpu/drm/i915/display/intel_dpll.c
Normal file
1363
drivers/gpu/drm/i915/display/intel_dpll.c
Normal file
File diff suppressed because it is too large
Load Diff
23
drivers/gpu/drm/i915/display/intel_dpll.h
Normal file
23
drivers/gpu/drm/i915/display/intel_dpll.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
/*
|
||||||
|
* Copyright © 2020 Intel Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INTEL_DPLL_H_
|
||||||
|
#define _INTEL_DPLL_H_
|
||||||
|
|
||||||
|
struct dpll;
|
||||||
|
struct drm_i915_private;
|
||||||
|
struct intel_crtc;
|
||||||
|
struct intel_crtc_state;
|
||||||
|
|
||||||
|
void intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv);
|
||||||
|
int vlv_calc_dpll_params(int refclk, struct dpll *clock);
|
||||||
|
int pnv_calc_dpll_params(int refclk, struct dpll *clock);
|
||||||
|
int i9xx_calc_dpll_params(int refclk, struct dpll *clock);
|
||||||
|
void vlv_compute_dpll(struct intel_crtc *crtc,
|
||||||
|
struct intel_crtc_state *pipe_config);
|
||||||
|
void chv_compute_dpll(struct intel_crtc *crtc,
|
||||||
|
struct intel_crtc_state *pipe_config);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
#define PANEL_PWM_MAX_VALUE 0xFF
|
#define PANEL_PWM_MAX_VALUE 0xFF
|
||||||
|
|
||||||
static u32 dcs_get_backlight(struct intel_connector *connector)
|
static u32 dcs_get_backlight(struct intel_connector *connector, enum pipe unused)
|
||||||
{
|
{
|
||||||
struct intel_encoder *encoder = intel_attached_encoder(connector);
|
struct intel_encoder *encoder = intel_attached_encoder(connector);
|
||||||
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
|
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
|
||||||
|
|||||||
@@ -676,7 +676,7 @@ static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool tiling_is_valid(struct drm_i915_private *dev_priv,
|
static bool tiling_is_valid(struct drm_i915_private *dev_priv,
|
||||||
uint64_t modifier)
|
u64 modifier)
|
||||||
{
|
{
|
||||||
switch (modifier) {
|
switch (modifier) {
|
||||||
case DRM_FORMAT_MOD_LINEAR:
|
case DRM_FORMAT_MOD_LINEAR:
|
||||||
|
|||||||
683
drivers/gpu/drm/i915/display/intel_fdi.c
Normal file
683
drivers/gpu/drm/i915/display/intel_fdi.c
Normal file
@@ -0,0 +1,683 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
/*
|
||||||
|
* Copyright © 2020 Intel Corporation
|
||||||
|
*/
|
||||||
|
#include "intel_atomic.h"
|
||||||
|
#include "intel_display_types.h"
|
||||||
|
#include "intel_fdi.h"
|
||||||
|
|
||||||
|
/* units of 100MHz */
|
||||||
|
static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
if (crtc_state->hw.enable && crtc_state->has_pch_encoder)
|
||||||
|
return crtc_state->fdi_lanes;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
|
||||||
|
struct intel_crtc_state *pipe_config)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
|
struct drm_atomic_state *state = pipe_config->uapi.state;
|
||||||
|
struct intel_crtc *other_crtc;
|
||||||
|
struct intel_crtc_state *other_crtc_state;
|
||||||
|
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"checking fdi config on pipe %c, lanes %i\n",
|
||||||
|
pipe_name(pipe), pipe_config->fdi_lanes);
|
||||||
|
if (pipe_config->fdi_lanes > 4) {
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"invalid fdi lane config on pipe %c: %i lanes\n",
|
||||||
|
pipe_name(pipe), pipe_config->fdi_lanes);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
|
||||||
|
if (pipe_config->fdi_lanes > 2) {
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"only 2 lanes on haswell, required: %i lanes\n",
|
||||||
|
pipe_config->fdi_lanes);
|
||||||
|
return -EINVAL;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (INTEL_NUM_PIPES(dev_priv) == 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Ivybridge 3 pipe is really complicated */
|
||||||
|
switch (pipe) {
|
||||||
|
case PIPE_A:
|
||||||
|
return 0;
|
||||||
|
case PIPE_B:
|
||||||
|
if (pipe_config->fdi_lanes <= 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
other_crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_C);
|
||||||
|
other_crtc_state =
|
||||||
|
intel_atomic_get_crtc_state(state, other_crtc);
|
||||||
|
if (IS_ERR(other_crtc_state))
|
||||||
|
return PTR_ERR(other_crtc_state);
|
||||||
|
|
||||||
|
if (pipe_required_fdi_lanes(other_crtc_state) > 0) {
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"invalid shared fdi lane config on pipe %c: %i lanes\n",
|
||||||
|
pipe_name(pipe), pipe_config->fdi_lanes);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case PIPE_C:
|
||||||
|
if (pipe_config->fdi_lanes > 2) {
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"only 2 lanes on pipe %c: required %i lanes\n",
|
||||||
|
pipe_name(pipe), pipe_config->fdi_lanes);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
other_crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_B);
|
||||||
|
other_crtc_state =
|
||||||
|
intel_atomic_get_crtc_state(state, other_crtc);
|
||||||
|
if (IS_ERR(other_crtc_state))
|
||||||
|
return PTR_ERR(other_crtc_state);
|
||||||
|
|
||||||
|
if (pipe_required_fdi_lanes(other_crtc_state) > 2) {
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"fdi link B uses too many lanes to enable link C\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ilk_fdi_compute_config(struct intel_crtc *intel_crtc,
|
||||||
|
struct intel_crtc_state *pipe_config)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = intel_crtc->base.dev;
|
||||||
|
struct drm_i915_private *i915 = to_i915(dev);
|
||||||
|
const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
|
||||||
|
int lane, link_bw, fdi_dotclock, ret;
|
||||||
|
bool needs_recompute = false;
|
||||||
|
|
||||||
|
retry:
|
||||||
|
/* FDI is a binary signal running at ~2.7GHz, encoding
|
||||||
|
* each output octet as 10 bits. The actual frequency
|
||||||
|
* is stored as a divider into a 100MHz clock, and the
|
||||||
|
* mode pixel clock is stored in units of 1KHz.
|
||||||
|
* Hence the bw of each lane in terms of the mode signal
|
||||||
|
* is:
|
||||||
|
*/
|
||||||
|
link_bw = intel_fdi_link_freq(i915, pipe_config);
|
||||||
|
|
||||||
|
fdi_dotclock = adjusted_mode->crtc_clock;
|
||||||
|
|
||||||
|
lane = ilk_get_lanes_required(fdi_dotclock, link_bw,
|
||||||
|
pipe_config->pipe_bpp);
|
||||||
|
|
||||||
|
pipe_config->fdi_lanes = lane;
|
||||||
|
|
||||||
|
intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock,
|
||||||
|
link_bw, &pipe_config->fdi_m_n, false, false);
|
||||||
|
|
||||||
|
ret = ilk_check_fdi_lanes(dev, intel_crtc->pipe, pipe_config);
|
||||||
|
if (ret == -EDEADLK)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) {
|
||||||
|
pipe_config->pipe_bpp -= 2*3;
|
||||||
|
drm_dbg_kms(&i915->drm,
|
||||||
|
"fdi link bw constraint, reducing pipe bpp to %i\n",
|
||||||
|
pipe_config->pipe_bpp);
|
||||||
|
needs_recompute = true;
|
||||||
|
pipe_config->bw_constrained = true;
|
||||||
|
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needs_recompute)
|
||||||
|
return I915_DISPLAY_CONFIG_RETRY;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void intel_fdi_normal_train(struct intel_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = crtc->base.dev;
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
|
enum pipe pipe = crtc->pipe;
|
||||||
|
i915_reg_t reg;
|
||||||
|
u32 temp;
|
||||||
|
|
||||||
|
/* enable normal train */
|
||||||
|
reg = FDI_TX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
if (IS_IVYBRIDGE(dev_priv)) {
|
||||||
|
temp &= ~FDI_LINK_TRAIN_NONE_IVB;
|
||||||
|
temp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE;
|
||||||
|
} else {
|
||||||
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
||||||
|
temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
|
||||||
|
}
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
reg = FDI_RX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
if (HAS_PCH_CPT(dev_priv)) {
|
||||||
|
temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
|
||||||
|
temp |= FDI_LINK_TRAIN_NORMAL_CPT;
|
||||||
|
} else {
|
||||||
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
||||||
|
temp |= FDI_LINK_TRAIN_NONE;
|
||||||
|
}
|
||||||
|
intel_de_write(dev_priv, reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
|
||||||
|
|
||||||
|
/* wait one idle pattern time */
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(1000);
|
||||||
|
|
||||||
|
/* IVB wants error correction enabled */
|
||||||
|
if (IS_IVYBRIDGE(dev_priv))
|
||||||
|
intel_de_write(dev_priv, reg,
|
||||||
|
intel_de_read(dev_priv, reg) | FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The FDI link training functions for ILK/Ibexpeak. */
|
||||||
|
static void ilk_fdi_link_train(struct intel_crtc *crtc,
|
||||||
|
const struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = crtc->base.dev;
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
|
enum pipe pipe = crtc->pipe;
|
||||||
|
i915_reg_t reg;
|
||||||
|
u32 temp, tries;
|
||||||
|
|
||||||
|
/* FDI needs bits from pipe first */
|
||||||
|
assert_pipe_enabled(dev_priv, crtc_state->cpu_transcoder);
|
||||||
|
|
||||||
|
/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
|
||||||
|
for train result */
|
||||||
|
reg = FDI_RX_IMR(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_RX_SYMBOL_LOCK;
|
||||||
|
temp &= ~FDI_RX_BIT_LOCK;
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
intel_de_read(dev_priv, reg);
|
||||||
|
udelay(150);
|
||||||
|
|
||||||
|
/* enable CPU FDI TX and PCH FDI RX */
|
||||||
|
reg = FDI_TX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_DP_PORT_WIDTH_MASK;
|
||||||
|
temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
|
||||||
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_1;
|
||||||
|
intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
|
||||||
|
|
||||||
|
reg = FDI_RX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_1;
|
||||||
|
intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(150);
|
||||||
|
|
||||||
|
/* Ironlake workaround, enable clock pointer after FDI enable*/
|
||||||
|
intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
|
||||||
|
FDI_RX_PHASE_SYNC_POINTER_OVR);
|
||||||
|
intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
|
||||||
|
FDI_RX_PHASE_SYNC_POINTER_OVR | FDI_RX_PHASE_SYNC_POINTER_EN);
|
||||||
|
|
||||||
|
reg = FDI_RX_IIR(pipe);
|
||||||
|
for (tries = 0; tries < 5; tries++) {
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
|
||||||
|
|
||||||
|
if ((temp & FDI_RX_BIT_LOCK)) {
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "FDI train 1 done.\n");
|
||||||
|
intel_de_write(dev_priv, reg, temp | FDI_RX_BIT_LOCK);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tries == 5)
|
||||||
|
drm_err(&dev_priv->drm, "FDI train 1 fail!\n");
|
||||||
|
|
||||||
|
/* Train 2 */
|
||||||
|
reg = FDI_TX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_2;
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
reg = FDI_RX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_2;
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(150);
|
||||||
|
|
||||||
|
reg = FDI_RX_IIR(pipe);
|
||||||
|
for (tries = 0; tries < 5; tries++) {
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
|
||||||
|
|
||||||
|
if (temp & FDI_RX_SYMBOL_LOCK) {
|
||||||
|
intel_de_write(dev_priv, reg,
|
||||||
|
temp | FDI_RX_SYMBOL_LOCK);
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "FDI train 2 done.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tries == 5)
|
||||||
|
drm_err(&dev_priv->drm, "FDI train 2 fail!\n");
|
||||||
|
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "FDI train done\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int snb_b_fdi_train_param[] = {
|
||||||
|
FDI_LINK_TRAIN_400MV_0DB_SNB_B,
|
||||||
|
FDI_LINK_TRAIN_400MV_6DB_SNB_B,
|
||||||
|
FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
|
||||||
|
FDI_LINK_TRAIN_800MV_0DB_SNB_B,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The FDI link training functions for SNB/Cougarpoint. */
|
||||||
|
static void gen6_fdi_link_train(struct intel_crtc *crtc,
|
||||||
|
const struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = crtc->base.dev;
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
|
enum pipe pipe = crtc->pipe;
|
||||||
|
i915_reg_t reg;
|
||||||
|
u32 temp, i, retry;
|
||||||
|
|
||||||
|
/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
|
||||||
|
for train result */
|
||||||
|
reg = FDI_RX_IMR(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_RX_SYMBOL_LOCK;
|
||||||
|
temp &= ~FDI_RX_BIT_LOCK;
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(150);
|
||||||
|
|
||||||
|
/* enable CPU FDI TX and PCH FDI RX */
|
||||||
|
reg = FDI_TX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_DP_PORT_WIDTH_MASK;
|
||||||
|
temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
|
||||||
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_1;
|
||||||
|
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
|
||||||
|
/* SNB-B */
|
||||||
|
temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
|
||||||
|
intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
|
||||||
|
|
||||||
|
intel_de_write(dev_priv, FDI_RX_MISC(pipe),
|
||||||
|
FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
|
||||||
|
|
||||||
|
reg = FDI_RX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
if (HAS_PCH_CPT(dev_priv)) {
|
||||||
|
temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
|
||||||
|
} else {
|
||||||
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_1;
|
||||||
|
}
|
||||||
|
intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(150);
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
reg = FDI_TX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
|
||||||
|
temp |= snb_b_fdi_train_param[i];
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(500);
|
||||||
|
|
||||||
|
for (retry = 0; retry < 5; retry++) {
|
||||||
|
reg = FDI_RX_IIR(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
|
||||||
|
if (temp & FDI_RX_BIT_LOCK) {
|
||||||
|
intel_de_write(dev_priv, reg,
|
||||||
|
temp | FDI_RX_BIT_LOCK);
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"FDI train 1 done.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
udelay(50);
|
||||||
|
}
|
||||||
|
if (retry < 5)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == 4)
|
||||||
|
drm_err(&dev_priv->drm, "FDI train 1 fail!\n");
|
||||||
|
|
||||||
|
/* Train 2 */
|
||||||
|
reg = FDI_TX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_2;
|
||||||
|
if (IS_GEN(dev_priv, 6)) {
|
||||||
|
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
|
||||||
|
/* SNB-B */
|
||||||
|
temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
|
||||||
|
}
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
reg = FDI_RX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
if (HAS_PCH_CPT(dev_priv)) {
|
||||||
|
temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
|
||||||
|
} else {
|
||||||
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_2;
|
||||||
|
}
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(150);
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
reg = FDI_TX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
|
||||||
|
temp |= snb_b_fdi_train_param[i];
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(500);
|
||||||
|
|
||||||
|
for (retry = 0; retry < 5; retry++) {
|
||||||
|
reg = FDI_RX_IIR(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
|
||||||
|
if (temp & FDI_RX_SYMBOL_LOCK) {
|
||||||
|
intel_de_write(dev_priv, reg,
|
||||||
|
temp | FDI_RX_SYMBOL_LOCK);
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"FDI train 2 done.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
udelay(50);
|
||||||
|
}
|
||||||
|
if (retry < 5)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == 4)
|
||||||
|
drm_err(&dev_priv->drm, "FDI train 2 fail!\n");
|
||||||
|
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "FDI train done.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Manual link training for Ivy Bridge A0 parts */
|
||||||
|
static void ivb_manual_fdi_link_train(struct intel_crtc *crtc,
|
||||||
|
const struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = crtc->base.dev;
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
|
enum pipe pipe = crtc->pipe;
|
||||||
|
i915_reg_t reg;
|
||||||
|
u32 temp, i, j;
|
||||||
|
|
||||||
|
/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
|
||||||
|
for train result */
|
||||||
|
reg = FDI_RX_IMR(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_RX_SYMBOL_LOCK;
|
||||||
|
temp &= ~FDI_RX_BIT_LOCK;
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(150);
|
||||||
|
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR before link train 0x%x\n",
|
||||||
|
intel_de_read(dev_priv, FDI_RX_IIR(pipe)));
|
||||||
|
|
||||||
|
/* Try each vswing and preemphasis setting twice before moving on */
|
||||||
|
for (j = 0; j < ARRAY_SIZE(snb_b_fdi_train_param) * 2; j++) {
|
||||||
|
/* disable first in case we need to retry */
|
||||||
|
reg = FDI_TX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB);
|
||||||
|
temp &= ~FDI_TX_ENABLE;
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
reg = FDI_RX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_LINK_TRAIN_AUTO;
|
||||||
|
temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
|
||||||
|
temp &= ~FDI_RX_ENABLE;
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
/* enable CPU FDI TX and PCH FDI RX */
|
||||||
|
reg = FDI_TX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_DP_PORT_WIDTH_MASK;
|
||||||
|
temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
|
||||||
|
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
|
||||||
|
temp |= snb_b_fdi_train_param[j/2];
|
||||||
|
temp |= FDI_COMPOSITE_SYNC;
|
||||||
|
intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
|
||||||
|
|
||||||
|
intel_de_write(dev_priv, FDI_RX_MISC(pipe),
|
||||||
|
FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
|
||||||
|
|
||||||
|
reg = FDI_RX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
|
||||||
|
temp |= FDI_COMPOSITE_SYNC;
|
||||||
|
intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(1); /* should be 0.5us */
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
reg = FDI_RX_IIR(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
|
||||||
|
|
||||||
|
if (temp & FDI_RX_BIT_LOCK ||
|
||||||
|
(intel_de_read(dev_priv, reg) & FDI_RX_BIT_LOCK)) {
|
||||||
|
intel_de_write(dev_priv, reg,
|
||||||
|
temp | FDI_RX_BIT_LOCK);
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"FDI train 1 done, level %i.\n",
|
||||||
|
i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
udelay(1); /* should be 0.5us */
|
||||||
|
}
|
||||||
|
if (i == 4) {
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"FDI train 1 fail on vswing %d\n", j / 2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Train 2 */
|
||||||
|
reg = FDI_TX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_LINK_TRAIN_NONE_IVB;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_2_IVB;
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
reg = FDI_RX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(2); /* should be 1.5us */
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
reg = FDI_RX_IIR(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
|
||||||
|
|
||||||
|
if (temp & FDI_RX_SYMBOL_LOCK ||
|
||||||
|
(intel_de_read(dev_priv, reg) & FDI_RX_SYMBOL_LOCK)) {
|
||||||
|
intel_de_write(dev_priv, reg,
|
||||||
|
temp | FDI_RX_SYMBOL_LOCK);
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"FDI train 2 done, level %i.\n",
|
||||||
|
i);
|
||||||
|
goto train_done;
|
||||||
|
}
|
||||||
|
udelay(2); /* should be 1.5us */
|
||||||
|
}
|
||||||
|
if (i == 4)
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"FDI train 2 fail on vswing %d\n", j / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
train_done:
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "FDI train done.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
|
||||||
|
enum pipe pipe = intel_crtc->pipe;
|
||||||
|
i915_reg_t reg;
|
||||||
|
u32 temp;
|
||||||
|
|
||||||
|
/* enable PCH FDI RX PLL, wait warmup plus DMI latency */
|
||||||
|
reg = FDI_RX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16));
|
||||||
|
temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
|
||||||
|
temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
|
||||||
|
intel_de_write(dev_priv, reg, temp | FDI_RX_PLL_ENABLE);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(200);
|
||||||
|
|
||||||
|
/* Switch from Rawclk to PCDclk */
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
intel_de_write(dev_priv, reg, temp | FDI_PCDCLK);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(200);
|
||||||
|
|
||||||
|
/* Enable CPU FDI TX PLL, always on for Ironlake */
|
||||||
|
reg = FDI_TX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
if ((temp & FDI_TX_PLL_ENABLE) == 0) {
|
||||||
|
intel_de_write(dev_priv, reg, temp | FDI_TX_PLL_ENABLE);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ilk_fdi_pll_disable(struct intel_crtc *intel_crtc)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = intel_crtc->base.dev;
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
|
enum pipe pipe = intel_crtc->pipe;
|
||||||
|
i915_reg_t reg;
|
||||||
|
u32 temp;
|
||||||
|
|
||||||
|
/* Switch from PCDclk to Rawclk */
|
||||||
|
reg = FDI_RX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
intel_de_write(dev_priv, reg, temp & ~FDI_PCDCLK);
|
||||||
|
|
||||||
|
/* Disable CPU FDI TX PLL */
|
||||||
|
reg = FDI_TX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
intel_de_write(dev_priv, reg, temp & ~FDI_TX_PLL_ENABLE);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(100);
|
||||||
|
|
||||||
|
reg = FDI_RX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
intel_de_write(dev_priv, reg, temp & ~FDI_RX_PLL_ENABLE);
|
||||||
|
|
||||||
|
/* Wait for the clocks to turn off. */
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ilk_fdi_disable(struct intel_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||||
|
enum pipe pipe = crtc->pipe;
|
||||||
|
i915_reg_t reg;
|
||||||
|
u32 temp;
|
||||||
|
|
||||||
|
/* disable CPU FDI tx and PCH FDI rx */
|
||||||
|
reg = FDI_TX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
intel_de_write(dev_priv, reg, temp & ~FDI_TX_ENABLE);
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
|
||||||
|
reg = FDI_RX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~(0x7 << 16);
|
||||||
|
temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
|
||||||
|
intel_de_write(dev_priv, reg, temp & ~FDI_RX_ENABLE);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(100);
|
||||||
|
|
||||||
|
/* Ironlake workaround, disable clock pointer after downing FDI */
|
||||||
|
if (HAS_PCH_IBX(dev_priv))
|
||||||
|
intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
|
||||||
|
FDI_RX_PHASE_SYNC_POINTER_OVR);
|
||||||
|
|
||||||
|
/* still set train pattern 1 */
|
||||||
|
reg = FDI_TX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_1;
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
reg = FDI_RX_CTL(pipe);
|
||||||
|
temp = intel_de_read(dev_priv, reg);
|
||||||
|
if (HAS_PCH_CPT(dev_priv)) {
|
||||||
|
temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
|
||||||
|
} else {
|
||||||
|
temp &= ~FDI_LINK_TRAIN_NONE;
|
||||||
|
temp |= FDI_LINK_TRAIN_PATTERN_1;
|
||||||
|
}
|
||||||
|
/* BPC in FDI rx is consistent with that in PIPECONF */
|
||||||
|
temp &= ~(0x07 << 16);
|
||||||
|
temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
|
||||||
|
intel_de_write(dev_priv, reg, temp);
|
||||||
|
|
||||||
|
intel_de_posting_read(dev_priv, reg);
|
||||||
|
udelay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
intel_fdi_init_hook(struct drm_i915_private *dev_priv)
|
||||||
|
{
|
||||||
|
if (IS_GEN(dev_priv, 5)) {
|
||||||
|
dev_priv->display.fdi_link_train = ilk_fdi_link_train;
|
||||||
|
} else if (IS_GEN(dev_priv, 6)) {
|
||||||
|
dev_priv->display.fdi_link_train = gen6_fdi_link_train;
|
||||||
|
} else if (IS_IVYBRIDGE(dev_priv)) {
|
||||||
|
/* FIXME: detect B0+ stepping and use auto training */
|
||||||
|
dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
drivers/gpu/drm/i915/display/intel_fdi.h
Normal file
22
drivers/gpu/drm/i915/display/intel_fdi.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
/*
|
||||||
|
* Copyright © 2020 Intel Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INTEL_FDI_H_
|
||||||
|
#define _INTEL_FDI_H_
|
||||||
|
|
||||||
|
struct drm_i915_private;
|
||||||
|
struct intel_crtc;
|
||||||
|
struct intel_crtc_state;
|
||||||
|
|
||||||
|
#define I915_DISPLAY_CONFIG_RETRY 1
|
||||||
|
int ilk_fdi_compute_config(struct intel_crtc *intel_crtc,
|
||||||
|
struct intel_crtc_state *pipe_config);
|
||||||
|
void intel_fdi_normal_train(struct intel_crtc *crtc);
|
||||||
|
void ilk_fdi_disable(struct intel_crtc *crtc);
|
||||||
|
void ilk_fdi_pll_disable(struct intel_crtc *intel_crtc);
|
||||||
|
void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state);
|
||||||
|
void intel_fdi_init_hook(struct drm_i915_private *dev_priv);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <drm/drm_hdcp.h>
|
#include <drm/drm_hdcp.h>
|
||||||
#include <drm/i915_component.h>
|
#include <drm/i915_component.h>
|
||||||
|
|
||||||
|
#include "i915_drv.h"
|
||||||
#include "i915_reg.h"
|
#include "i915_reg.h"
|
||||||
#include "intel_display_power.h"
|
#include "intel_display_power.h"
|
||||||
#include "intel_display_types.h"
|
#include "intel_display_types.h"
|
||||||
@@ -23,9 +24,78 @@
|
|||||||
#include "intel_connector.h"
|
#include "intel_connector.h"
|
||||||
|
|
||||||
#define KEY_LOAD_TRIES 5
|
#define KEY_LOAD_TRIES 5
|
||||||
#define ENCRYPT_STATUS_CHANGE_TIMEOUT_MS 50
|
|
||||||
#define HDCP2_LC_RETRY_CNT 3
|
#define HDCP2_LC_RETRY_CNT 3
|
||||||
|
|
||||||
|
static int intel_conn_to_vcpi(struct intel_connector *connector)
|
||||||
|
{
|
||||||
|
/* For HDMI this is forced to be 0x0. For DP SST also this is 0x0. */
|
||||||
|
return connector->port ? connector->port->vcpi.vcpi : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* intel_hdcp_required_content_stream selects the most highest common possible HDCP
|
||||||
|
* content_type for all streams in DP MST topology because security f/w doesn't
|
||||||
|
* have any provision to mark content_type for each stream separately, it marks
|
||||||
|
* all available streams with the content_type proivided at the time of port
|
||||||
|
* authentication. This may prohibit the userspace to use type1 content on
|
||||||
|
* HDCP 2.2 capable sink because of other sink are not capable of HDCP 2.2 in
|
||||||
|
* DP MST topology. Though it is not compulsory, security fw should change its
|
||||||
|
* policy to mark different content_types for different streams.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
intel_hdcp_required_content_stream(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;
|
||||||
|
|
||||||
|
data->k = 0;
|
||||||
|
|
||||||
|
if (dig_port->hdcp_auth_status)
|
||||||
|
return 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;
|
||||||
|
|
||||||
|
if (!enforce_type0 && !intel_hdcp2_capable(connector))
|
||||||
|
enforce_type0 = true;
|
||||||
|
|
||||||
|
data->streams[data->k].stream_id = intel_conn_to_vcpi(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.
|
||||||
|
*/
|
||||||
|
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
|
static
|
||||||
bool intel_hdcp_is_ksv_valid(u8 *ksv)
|
bool intel_hdcp_is_ksv_valid(u8 *ksv)
|
||||||
{
|
{
|
||||||
@@ -762,15 +832,22 @@ static int intel_hdcp_auth(struct intel_connector *connector)
|
|||||||
if (intel_de_wait_for_set(dev_priv,
|
if (intel_de_wait_for_set(dev_priv,
|
||||||
HDCP_STATUS(dev_priv, cpu_transcoder, port),
|
HDCP_STATUS(dev_priv, cpu_transcoder, port),
|
||||||
HDCP_STATUS_ENC,
|
HDCP_STATUS_ENC,
|
||||||
ENCRYPT_STATUS_CHANGE_TIMEOUT_MS)) {
|
HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS)) {
|
||||||
drm_err(&dev_priv->drm, "Timed out waiting for encryption\n");
|
drm_err(&dev_priv->drm, "Timed out waiting for encryption\n");
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* DP MST Auth Part 1 Step 2.a and Step 2.b */
|
||||||
* XXX: If we have MST-connected devices, we need to enable encryption
|
if (shim->stream_encryption) {
|
||||||
* on those as well.
|
ret = shim->stream_encryption(connector, true);
|
||||||
*/
|
if (ret) {
|
||||||
|
drm_err(&dev_priv->drm, "[%s:%d] Failed to enable HDCP 1.4 stream enc\n",
|
||||||
|
connector->base.name, connector->base.base.id);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s stream encrypted\n",
|
||||||
|
transcoder_name(hdcp->stream_transcoder));
|
||||||
|
}
|
||||||
|
|
||||||
if (repeater_present)
|
if (repeater_present)
|
||||||
return intel_hdcp_auth_downstream(connector);
|
return intel_hdcp_auth_downstream(connector);
|
||||||
@@ -792,24 +869,29 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
|
|||||||
drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being disabled...\n",
|
drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being disabled...\n",
|
||||||
connector->base.name, connector->base.base.id);
|
connector->base.name, connector->base.base.id);
|
||||||
|
|
||||||
/*
|
if (hdcp->shim->stream_encryption) {
|
||||||
* If there are other connectors on this port using HDCP, don't disable
|
ret = hdcp->shim->stream_encryption(connector, false);
|
||||||
* it. Instead, toggle the HDCP signalling off on that particular
|
if (ret) {
|
||||||
* connector/pipe and exit.
|
drm_err(&dev_priv->drm, "[%s:%d] Failed to disable HDCP 1.4 stream enc\n",
|
||||||
*/
|
connector->base.name, connector->base.base.id);
|
||||||
if (dig_port->num_hdcp_streams > 0) {
|
return ret;
|
||||||
ret = hdcp->shim->toggle_signalling(dig_port,
|
}
|
||||||
cpu_transcoder, false);
|
drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s stream encryption disabled\n",
|
||||||
if (ret)
|
transcoder_name(hdcp->stream_transcoder));
|
||||||
DRM_ERROR("Failed to disable HDCP signalling\n");
|
/*
|
||||||
return ret;
|
* If there are other connectors on this port using HDCP,
|
||||||
|
* don't disable it until it disabled HDCP encryption for
|
||||||
|
* all connectors in MST topology.
|
||||||
|
*/
|
||||||
|
if (dig_port->num_hdcp_streams > 0)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
hdcp->hdcp_encrypted = false;
|
hdcp->hdcp_encrypted = false;
|
||||||
intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder, port), 0);
|
intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder, port), 0);
|
||||||
if (intel_de_wait_for_clear(dev_priv,
|
if (intel_de_wait_for_clear(dev_priv,
|
||||||
HDCP_STATUS(dev_priv, cpu_transcoder, port),
|
HDCP_STATUS(dev_priv, cpu_transcoder, port),
|
||||||
~0, ENCRYPT_STATUS_CHANGE_TIMEOUT_MS)) {
|
~0, HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS)) {
|
||||||
drm_err(&dev_priv->drm,
|
drm_err(&dev_priv->drm,
|
||||||
"Failed to disable HDCP, timeout clearing status\n");
|
"Failed to disable HDCP, timeout clearing status\n");
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
@@ -1014,7 +1096,8 @@ static int
|
|||||||
hdcp2_prepare_ake_init(struct intel_connector *connector,
|
hdcp2_prepare_ake_init(struct intel_connector *connector,
|
||||||
struct hdcp2_ake_init *ake_data)
|
struct hdcp2_ake_init *ake_data)
|
||||||
{
|
{
|
||||||
struct hdcp_port_data *data = &connector->hdcp.port_data;
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
|
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct i915_hdcp_comp_master *comp;
|
struct i915_hdcp_comp_master *comp;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1043,7 +1126,8 @@ hdcp2_verify_rx_cert_prepare_km(struct intel_connector *connector,
|
|||||||
struct hdcp2_ake_no_stored_km *ek_pub_km,
|
struct hdcp2_ake_no_stored_km *ek_pub_km,
|
||||||
size_t *msg_sz)
|
size_t *msg_sz)
|
||||||
{
|
{
|
||||||
struct hdcp_port_data *data = &connector->hdcp.port_data;
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
|
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct i915_hdcp_comp_master *comp;
|
struct i915_hdcp_comp_master *comp;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1070,7 +1154,8 @@ hdcp2_verify_rx_cert_prepare_km(struct intel_connector *connector,
|
|||||||
static int hdcp2_verify_hprime(struct intel_connector *connector,
|
static int hdcp2_verify_hprime(struct intel_connector *connector,
|
||||||
struct hdcp2_ake_send_hprime *rx_hprime)
|
struct hdcp2_ake_send_hprime *rx_hprime)
|
||||||
{
|
{
|
||||||
struct hdcp_port_data *data = &connector->hdcp.port_data;
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
|
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct i915_hdcp_comp_master *comp;
|
struct i915_hdcp_comp_master *comp;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1095,7 +1180,8 @@ static int
|
|||||||
hdcp2_store_pairing_info(struct intel_connector *connector,
|
hdcp2_store_pairing_info(struct intel_connector *connector,
|
||||||
struct hdcp2_ake_send_pairing_info *pairing_info)
|
struct hdcp2_ake_send_pairing_info *pairing_info)
|
||||||
{
|
{
|
||||||
struct hdcp_port_data *data = &connector->hdcp.port_data;
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
|
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct i915_hdcp_comp_master *comp;
|
struct i915_hdcp_comp_master *comp;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1121,7 +1207,8 @@ static int
|
|||||||
hdcp2_prepare_lc_init(struct intel_connector *connector,
|
hdcp2_prepare_lc_init(struct intel_connector *connector,
|
||||||
struct hdcp2_lc_init *lc_init)
|
struct hdcp2_lc_init *lc_init)
|
||||||
{
|
{
|
||||||
struct hdcp_port_data *data = &connector->hdcp.port_data;
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
|
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct i915_hdcp_comp_master *comp;
|
struct i915_hdcp_comp_master *comp;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1147,7 +1234,8 @@ static int
|
|||||||
hdcp2_verify_lprime(struct intel_connector *connector,
|
hdcp2_verify_lprime(struct intel_connector *connector,
|
||||||
struct hdcp2_lc_send_lprime *rx_lprime)
|
struct hdcp2_lc_send_lprime *rx_lprime)
|
||||||
{
|
{
|
||||||
struct hdcp_port_data *data = &connector->hdcp.port_data;
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
|
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct i915_hdcp_comp_master *comp;
|
struct i915_hdcp_comp_master *comp;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1172,7 +1260,8 @@ hdcp2_verify_lprime(struct intel_connector *connector,
|
|||||||
static int hdcp2_prepare_skey(struct intel_connector *connector,
|
static int hdcp2_prepare_skey(struct intel_connector *connector,
|
||||||
struct hdcp2_ske_send_eks *ske_data)
|
struct hdcp2_ske_send_eks *ske_data)
|
||||||
{
|
{
|
||||||
struct hdcp_port_data *data = &connector->hdcp.port_data;
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
|
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct i915_hdcp_comp_master *comp;
|
struct i915_hdcp_comp_master *comp;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1200,7 +1289,8 @@ hdcp2_verify_rep_topology_prepare_ack(struct intel_connector *connector,
|
|||||||
*rep_topology,
|
*rep_topology,
|
||||||
struct hdcp2_rep_send_ack *rep_send_ack)
|
struct hdcp2_rep_send_ack *rep_send_ack)
|
||||||
{
|
{
|
||||||
struct hdcp_port_data *data = &connector->hdcp.port_data;
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
|
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct i915_hdcp_comp_master *comp;
|
struct i915_hdcp_comp_master *comp;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1228,7 +1318,8 @@ static int
|
|||||||
hdcp2_verify_mprime(struct intel_connector *connector,
|
hdcp2_verify_mprime(struct intel_connector *connector,
|
||||||
struct hdcp2_rep_stream_ready *stream_ready)
|
struct hdcp2_rep_stream_ready *stream_ready)
|
||||||
{
|
{
|
||||||
struct hdcp_port_data *data = &connector->hdcp.port_data;
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
|
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct i915_hdcp_comp_master *comp;
|
struct i915_hdcp_comp_master *comp;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1251,7 +1342,8 @@ hdcp2_verify_mprime(struct intel_connector *connector,
|
|||||||
|
|
||||||
static int hdcp2_authenticate_port(struct intel_connector *connector)
|
static int hdcp2_authenticate_port(struct intel_connector *connector)
|
||||||
{
|
{
|
||||||
struct hdcp_port_data *data = &connector->hdcp.port_data;
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
|
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct i915_hdcp_comp_master *comp;
|
struct i915_hdcp_comp_master *comp;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1275,6 +1367,7 @@ static int hdcp2_authenticate_port(struct intel_connector *connector)
|
|||||||
|
|
||||||
static int hdcp2_close_mei_session(struct intel_connector *connector)
|
static int hdcp2_close_mei_session(struct intel_connector *connector)
|
||||||
{
|
{
|
||||||
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct i915_hdcp_comp_master *comp;
|
struct i915_hdcp_comp_master *comp;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1288,7 +1381,7 @@ static int hdcp2_close_mei_session(struct intel_connector *connector)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = comp->ops->close_hdcp_session(comp->mei_dev,
|
ret = comp->ops->close_hdcp_session(comp->mei_dev,
|
||||||
&connector->hdcp.port_data);
|
&dig_port->hdcp_port_data);
|
||||||
mutex_unlock(&dev_priv->hdcp_comp_mutex);
|
mutex_unlock(&dev_priv->hdcp_comp_mutex);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1448,13 +1541,14 @@ static
|
|||||||
int _hdcp2_propagate_stream_management_info(struct intel_connector *connector)
|
int _hdcp2_propagate_stream_management_info(struct intel_connector *connector)
|
||||||
{
|
{
|
||||||
struct intel_digital_port *dig_port = intel_attached_dig_port(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;
|
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||||
union {
|
union {
|
||||||
struct hdcp2_rep_stream_manage stream_manage;
|
struct hdcp2_rep_stream_manage stream_manage;
|
||||||
struct hdcp2_rep_stream_ready stream_ready;
|
struct hdcp2_rep_stream_ready stream_ready;
|
||||||
} msgs;
|
} msgs;
|
||||||
const struct intel_hdcp_shim *shim = hdcp->shim;
|
const struct intel_hdcp_shim *shim = hdcp->shim;
|
||||||
int ret;
|
int ret, streams_size_delta, i;
|
||||||
|
|
||||||
if (connector->hdcp.seq_num_m > HDCP_2_2_SEQ_NUM_MAX)
|
if (connector->hdcp.seq_num_m > HDCP_2_2_SEQ_NUM_MAX)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
@@ -1463,16 +1557,18 @@ int _hdcp2_propagate_stream_management_info(struct intel_connector *connector)
|
|||||||
msgs.stream_manage.msg_id = HDCP_2_2_REP_STREAM_MANAGE;
|
msgs.stream_manage.msg_id = HDCP_2_2_REP_STREAM_MANAGE;
|
||||||
drm_hdcp_cpu_to_be24(msgs.stream_manage.seq_num_m, hdcp->seq_num_m);
|
drm_hdcp_cpu_to_be24(msgs.stream_manage.seq_num_m, hdcp->seq_num_m);
|
||||||
|
|
||||||
/* K no of streams is fixed as 1. Stored as big-endian. */
|
msgs.stream_manage.k = cpu_to_be16(data->k);
|
||||||
msgs.stream_manage.k = cpu_to_be16(1);
|
|
||||||
|
|
||||||
/* For HDMI this is forced to be 0x0. For DP SST also this is 0x0. */
|
for (i = 0; i < data->k; i++) {
|
||||||
msgs.stream_manage.streams[0].stream_id = 0;
|
msgs.stream_manage.streams[i].stream_id = data->streams[i].stream_id;
|
||||||
msgs.stream_manage.streams[0].stream_type = hdcp->content_type;
|
msgs.stream_manage.streams[i].stream_type = data->streams[i].stream_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
streams_size_delta = (HDCP_2_2_MAX_CONTENT_STREAMS_CNT - data->k) *
|
||||||
|
sizeof(struct hdcp2_streamid_type);
|
||||||
/* Send it to Repeater */
|
/* Send it to Repeater */
|
||||||
ret = shim->write_2_2_msg(dig_port, &msgs.stream_manage,
|
ret = shim->write_2_2_msg(dig_port, &msgs.stream_manage,
|
||||||
sizeof(msgs.stream_manage));
|
sizeof(msgs.stream_manage) - streams_size_delta);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -1481,8 +1577,8 @@ int _hdcp2_propagate_stream_management_info(struct intel_connector *connector)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
hdcp->port_data.seq_num_m = hdcp->seq_num_m;
|
data->seq_num_m = hdcp->seq_num_m;
|
||||||
hdcp->port_data.streams[0].stream_type = hdcp->content_type;
|
|
||||||
ret = hdcp2_verify_mprime(connector, &msgs.stream_ready);
|
ret = hdcp2_verify_mprime(connector, &msgs.stream_ready);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@@ -1606,6 +1702,36 @@ static int hdcp2_authenticate_sink(struct intel_connector *connector)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int hdcp2_enable_stream_encryption(struct intel_connector *connector)
|
||||||
|
{
|
||||||
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
|
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||||
|
enum transcoder cpu_transcoder = hdcp->cpu_transcoder;
|
||||||
|
enum port port = dig_port->base.port;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!(intel_de_read(dev_priv, HDCP2_STATUS(dev_priv, cpu_transcoder, port)) &
|
||||||
|
LINK_ENCRYPTION_STATUS)) {
|
||||||
|
drm_err(&dev_priv->drm, "[%s:%d] HDCP 2.2 Link is not encrypted\n",
|
||||||
|
connector->base.name, connector->base.base.id);
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdcp->shim->stream_2_2_encryption) {
|
||||||
|
ret = hdcp->shim->stream_2_2_encryption(connector, true);
|
||||||
|
if (ret) {
|
||||||
|
drm_err(&dev_priv->drm, "[%s:%d] Failed to enable HDCP 2.2 stream enc\n",
|
||||||
|
connector->base.name, connector->base.base.id);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "HDCP 2.2 transcoder: %s stream encrypted\n",
|
||||||
|
transcoder_name(hdcp->stream_transcoder));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int hdcp2_enable_encryption(struct intel_connector *connector)
|
static int hdcp2_enable_encryption(struct intel_connector *connector)
|
||||||
{
|
{
|
||||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
@@ -1641,7 +1767,8 @@ static int hdcp2_enable_encryption(struct intel_connector *connector)
|
|||||||
HDCP2_STATUS(dev_priv, cpu_transcoder,
|
HDCP2_STATUS(dev_priv, cpu_transcoder,
|
||||||
port),
|
port),
|
||||||
LINK_ENCRYPTION_STATUS,
|
LINK_ENCRYPTION_STATUS,
|
||||||
ENCRYPT_STATUS_CHANGE_TIMEOUT_MS);
|
HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS);
|
||||||
|
dig_port->hdcp_auth_status = true;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1665,7 +1792,7 @@ static int hdcp2_disable_encryption(struct intel_connector *connector)
|
|||||||
HDCP2_STATUS(dev_priv, cpu_transcoder,
|
HDCP2_STATUS(dev_priv, cpu_transcoder,
|
||||||
port),
|
port),
|
||||||
LINK_ENCRYPTION_STATUS,
|
LINK_ENCRYPTION_STATUS,
|
||||||
ENCRYPT_STATUS_CHANGE_TIMEOUT_MS);
|
HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS);
|
||||||
if (ret == -ETIMEDOUT)
|
if (ret == -ETIMEDOUT)
|
||||||
drm_dbg_kms(&dev_priv->drm, "Disable Encryption Timedout");
|
drm_dbg_kms(&dev_priv->drm, "Disable Encryption Timedout");
|
||||||
|
|
||||||
@@ -1714,11 +1841,11 @@ hdcp2_propagate_stream_management_info(struct intel_connector *connector)
|
|||||||
|
|
||||||
static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
|
static int hdcp2_authenticate_and_encrypt(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);
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
int ret = 0, i, tries = 3;
|
||||||
int ret, i, tries = 3;
|
|
||||||
|
|
||||||
for (i = 0; i < tries; i++) {
|
for (i = 0; i < tries && !dig_port->hdcp_auth_status; i++) {
|
||||||
ret = hdcp2_authenticate_sink(connector);
|
ret = hdcp2_authenticate_sink(connector);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
ret = hdcp2_propagate_stream_management_info(connector);
|
ret = hdcp2_propagate_stream_management_info(connector);
|
||||||
@@ -1728,8 +1855,7 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
|
|||||||
ret);
|
ret);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
hdcp->port_data.streams[0].stream_type =
|
|
||||||
hdcp->content_type;
|
|
||||||
ret = hdcp2_authenticate_port(connector);
|
ret = hdcp2_authenticate_port(connector);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
break;
|
break;
|
||||||
@@ -1744,7 +1870,7 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
|
|||||||
drm_dbg_kms(&i915->drm, "Port deauth failed.\n");
|
drm_dbg_kms(&i915->drm, "Port deauth failed.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret && !dig_port->hdcp_auth_status) {
|
||||||
/*
|
/*
|
||||||
* Ensuring the required 200mSec min time interval between
|
* Ensuring the required 200mSec min time interval between
|
||||||
* Session Key Exchange and encryption.
|
* Session Key Exchange and encryption.
|
||||||
@@ -1759,12 +1885,16 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = hdcp2_enable_stream_encryption(connector);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _intel_hdcp2_enable(struct intel_connector *connector)
|
static int _intel_hdcp2_enable(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);
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
|
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -1772,6 +1902,16 @@ static int _intel_hdcp2_enable(struct intel_connector *connector)
|
|||||||
connector->base.name, connector->base.base.id,
|
connector->base.name, connector->base.base.id,
|
||||||
hdcp->content_type);
|
hdcp->content_type);
|
||||||
|
|
||||||
|
/* Stream which requires encryption */
|
||||||
|
if (!intel_encoder_is_mst(intel_attached_encoder(connector))) {
|
||||||
|
data->k = 1;
|
||||||
|
data->streams[0].stream_type = hdcp->content_type;
|
||||||
|
} else {
|
||||||
|
ret = intel_hdcp_required_content_stream(dig_port);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ret = hdcp2_authenticate_and_encrypt(connector);
|
ret = hdcp2_authenticate_and_encrypt(connector);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
drm_dbg_kms(&i915->drm, "HDCP2 Type%d Enabling Failed. (%d)\n",
|
drm_dbg_kms(&i915->drm, "HDCP2 Type%d Enabling Failed. (%d)\n",
|
||||||
@@ -1789,18 +1929,37 @@ static int _intel_hdcp2_enable(struct intel_connector *connector)
|
|||||||
|
|
||||||
static int _intel_hdcp2_disable(struct intel_connector *connector)
|
static int _intel_hdcp2_disable(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);
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
|
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||||
|
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
drm_dbg_kms(&i915->drm, "[%s:%d] HDCP2.2 is being Disabled\n",
|
drm_dbg_kms(&i915->drm, "[%s:%d] HDCP2.2 is being Disabled\n",
|
||||||
connector->base.name, connector->base.base.id);
|
connector->base.name, connector->base.base.id);
|
||||||
|
|
||||||
|
if (hdcp->shim->stream_2_2_encryption) {
|
||||||
|
ret = hdcp->shim->stream_2_2_encryption(connector, false);
|
||||||
|
if (ret) {
|
||||||
|
drm_err(&i915->drm, "[%s:%d] Failed to disable HDCP 2.2 stream enc\n",
|
||||||
|
connector->base.name, connector->base.base.id);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
drm_dbg_kms(&i915->drm, "HDCP 2.2 transcoder: %s stream encryption disabled\n",
|
||||||
|
transcoder_name(hdcp->stream_transcoder));
|
||||||
|
|
||||||
|
if (dig_port->num_hdcp_streams > 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ret = hdcp2_disable_encryption(connector);
|
ret = hdcp2_disable_encryption(connector);
|
||||||
|
|
||||||
if (hdcp2_deauthenticate_port(connector) < 0)
|
if (hdcp2_deauthenticate_port(connector) < 0)
|
||||||
drm_dbg_kms(&i915->drm, "Port deauth failed.\n");
|
drm_dbg_kms(&i915->drm, "Port deauth failed.\n");
|
||||||
|
|
||||||
connector->hdcp.hdcp2_encrypted = false;
|
connector->hdcp.hdcp2_encrypted = false;
|
||||||
|
dig_port->hdcp_auth_status = false;
|
||||||
|
data->k = 0;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1816,6 +1975,7 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
mutex_lock(&hdcp->mutex);
|
mutex_lock(&hdcp->mutex);
|
||||||
|
mutex_lock(&dig_port->hdcp_mutex);
|
||||||
cpu_transcoder = hdcp->cpu_transcoder;
|
cpu_transcoder = hdcp->cpu_transcoder;
|
||||||
|
|
||||||
/* hdcp2_check_link is expected only when HDCP2.2 is Enabled */
|
/* hdcp2_check_link is expected only when HDCP2.2 is Enabled */
|
||||||
@@ -1837,7 +1997,7 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = hdcp->shim->check_2_2_link(dig_port);
|
ret = hdcp->shim->check_2_2_link(dig_port, connector);
|
||||||
if (ret == HDCP_LINK_PROTECTED) {
|
if (ret == HDCP_LINK_PROTECTED) {
|
||||||
if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
|
if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
|
||||||
intel_hdcp_update_value(connector,
|
intel_hdcp_update_value(connector,
|
||||||
@@ -1893,6 +2053,7 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
mutex_unlock(&dig_port->hdcp_mutex);
|
||||||
mutex_unlock(&hdcp->mutex);
|
mutex_unlock(&hdcp->mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1968,12 +2129,13 @@ static enum mei_fw_tc intel_get_mei_fw_tc(enum transcoder cpu_transcoder)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int initialize_hdcp_port_data(struct intel_connector *connector,
|
static int initialize_hdcp_port_data(struct intel_connector *connector,
|
||||||
enum port port,
|
struct intel_digital_port *dig_port,
|
||||||
const struct intel_hdcp_shim *shim)
|
const struct intel_hdcp_shim *shim)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
|
struct hdcp_port_data *data = &dig_port->hdcp_port_data;
|
||||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||||
struct hdcp_port_data *data = &hdcp->port_data;
|
enum port port = dig_port->base.port;
|
||||||
|
|
||||||
if (INTEL_GEN(dev_priv) < 12)
|
if (INTEL_GEN(dev_priv) < 12)
|
||||||
data->fw_ddi = intel_get_mei_fw_ddi_index(port);
|
data->fw_ddi = intel_get_mei_fw_ddi_index(port);
|
||||||
@@ -1994,16 +2156,15 @@ static int initialize_hdcp_port_data(struct intel_connector *connector,
|
|||||||
data->port_type = (u8)HDCP_PORT_TYPE_INTEGRATED;
|
data->port_type = (u8)HDCP_PORT_TYPE_INTEGRATED;
|
||||||
data->protocol = (u8)shim->protocol;
|
data->protocol = (u8)shim->protocol;
|
||||||
|
|
||||||
data->k = 1;
|
|
||||||
if (!data->streams)
|
if (!data->streams)
|
||||||
data->streams = kcalloc(data->k,
|
data->streams = kcalloc(INTEL_NUM_PIPES(dev_priv),
|
||||||
sizeof(struct hdcp2_streamid_type),
|
sizeof(struct hdcp2_streamid_type),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!data->streams) {
|
if (!data->streams) {
|
||||||
drm_err(&dev_priv->drm, "Out of Memory\n");
|
drm_err(&dev_priv->drm, "Out of Memory\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
/* For SST */
|
||||||
data->streams[0].stream_id = 0;
|
data->streams[0].stream_id = 0;
|
||||||
data->streams[0].stream_type = hdcp->content_type;
|
data->streams[0].stream_type = hdcp->content_type;
|
||||||
|
|
||||||
@@ -2046,14 +2207,15 @@ void intel_hdcp_component_init(struct drm_i915_private *dev_priv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void intel_hdcp2_init(struct intel_connector *connector, enum port port,
|
static void intel_hdcp2_init(struct intel_connector *connector,
|
||||||
|
struct intel_digital_port *dig_port,
|
||||||
const struct intel_hdcp_shim *shim)
|
const struct intel_hdcp_shim *shim)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = initialize_hdcp_port_data(connector, port, shim);
|
ret = initialize_hdcp_port_data(connector, dig_port, shim);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
drm_dbg_kms(&i915->drm, "Mei hdcp data init failed\n");
|
drm_dbg_kms(&i915->drm, "Mei hdcp data init failed\n");
|
||||||
return;
|
return;
|
||||||
@@ -2063,7 +2225,7 @@ static void intel_hdcp2_init(struct intel_connector *connector, enum port port,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int intel_hdcp_init(struct intel_connector *connector,
|
int intel_hdcp_init(struct intel_connector *connector,
|
||||||
enum port port,
|
struct intel_digital_port *dig_port,
|
||||||
const struct intel_hdcp_shim *shim)
|
const struct intel_hdcp_shim *shim)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
@@ -2073,15 +2235,15 @@ int intel_hdcp_init(struct intel_connector *connector,
|
|||||||
if (!shim)
|
if (!shim)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (is_hdcp2_supported(dev_priv) && !connector->mst_port)
|
if (is_hdcp2_supported(dev_priv))
|
||||||
intel_hdcp2_init(connector, port, shim);
|
intel_hdcp2_init(connector, dig_port, shim);
|
||||||
|
|
||||||
ret =
|
ret =
|
||||||
drm_connector_attach_content_protection_property(&connector->base,
|
drm_connector_attach_content_protection_property(&connector->base,
|
||||||
hdcp->hdcp2_supported);
|
hdcp->hdcp2_supported);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
hdcp->hdcp2_supported = false;
|
hdcp->hdcp2_supported = false;
|
||||||
kfree(hdcp->port_data.streams);
|
kfree(dig_port->hdcp_port_data.streams);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2095,7 +2257,7 @@ int intel_hdcp_init(struct intel_connector *connector,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int intel_hdcp_enable(struct intel_connector *connector,
|
int intel_hdcp_enable(struct intel_connector *connector,
|
||||||
enum transcoder cpu_transcoder, u8 content_type)
|
const struct intel_crtc_state *pipe_config, u8 content_type)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||||
@@ -2106,15 +2268,28 @@ int intel_hdcp_enable(struct intel_connector *connector,
|
|||||||
if (!hdcp->shim)
|
if (!hdcp->shim)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
|
if (!connector->encoder) {
|
||||||
|
drm_err(&dev_priv->drm, "[%s:%d] encoder is not initialized\n",
|
||||||
|
connector->base.name, connector->base.base.id);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_lock(&hdcp->mutex);
|
mutex_lock(&hdcp->mutex);
|
||||||
mutex_lock(&dig_port->hdcp_mutex);
|
mutex_lock(&dig_port->hdcp_mutex);
|
||||||
drm_WARN_ON(&dev_priv->drm,
|
drm_WARN_ON(&dev_priv->drm,
|
||||||
hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED);
|
hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED);
|
||||||
hdcp->content_type = content_type;
|
hdcp->content_type = content_type;
|
||||||
hdcp->cpu_transcoder = cpu_transcoder;
|
|
||||||
|
if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) {
|
||||||
|
hdcp->cpu_transcoder = pipe_config->mst_master_transcoder;
|
||||||
|
hdcp->stream_transcoder = pipe_config->cpu_transcoder;
|
||||||
|
} else {
|
||||||
|
hdcp->cpu_transcoder = pipe_config->cpu_transcoder;
|
||||||
|
hdcp->stream_transcoder = INVALID_TRANSCODER;
|
||||||
|
}
|
||||||
|
|
||||||
if (INTEL_GEN(dev_priv) >= 12)
|
if (INTEL_GEN(dev_priv) >= 12)
|
||||||
hdcp->port_data.fw_tc = intel_get_mei_fw_tc(cpu_transcoder);
|
dig_port->hdcp_port_data.fw_tc = intel_get_mei_fw_tc(hdcp->cpu_transcoder);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
|
* Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
|
||||||
@@ -2234,7 +2409,7 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state,
|
|||||||
|
|
||||||
if (desired_and_not_enabled || content_protection_type_changed)
|
if (desired_and_not_enabled || content_protection_type_changed)
|
||||||
intel_hdcp_enable(connector,
|
intel_hdcp_enable(connector,
|
||||||
crtc_state->cpu_transcoder,
|
crtc_state,
|
||||||
(u8)conn_state->hdcp_content_type);
|
(u8)conn_state->hdcp_content_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2284,7 +2459,6 @@ void intel_hdcp_cleanup(struct intel_connector *connector)
|
|||||||
drm_WARN_ON(connector->base.dev, work_pending(&hdcp->prop_work));
|
drm_WARN_ON(connector->base.dev, work_pending(&hdcp->prop_work));
|
||||||
|
|
||||||
mutex_lock(&hdcp->mutex);
|
mutex_lock(&hdcp->mutex);
|
||||||
kfree(hdcp->port_data.streams);
|
|
||||||
hdcp->shim = NULL;
|
hdcp->shim = NULL;
|
||||||
mutex_unlock(&hdcp->mutex);
|
mutex_unlock(&hdcp->mutex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#define HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS 50
|
||||||
|
|
||||||
struct drm_connector;
|
struct drm_connector;
|
||||||
struct drm_connector_state;
|
struct drm_connector_state;
|
||||||
struct drm_i915_private;
|
struct drm_i915_private;
|
||||||
@@ -16,16 +18,18 @@ struct intel_connector;
|
|||||||
struct intel_crtc_state;
|
struct intel_crtc_state;
|
||||||
struct intel_encoder;
|
struct intel_encoder;
|
||||||
struct intel_hdcp_shim;
|
struct intel_hdcp_shim;
|
||||||
|
struct intel_digital_port;
|
||||||
enum port;
|
enum port;
|
||||||
enum transcoder;
|
enum transcoder;
|
||||||
|
|
||||||
void intel_hdcp_atomic_check(struct drm_connector *connector,
|
void intel_hdcp_atomic_check(struct drm_connector *connector,
|
||||||
struct drm_connector_state *old_state,
|
struct drm_connector_state *old_state,
|
||||||
struct drm_connector_state *new_state);
|
struct drm_connector_state *new_state);
|
||||||
int intel_hdcp_init(struct intel_connector *connector, enum port port,
|
int intel_hdcp_init(struct intel_connector *connector,
|
||||||
|
struct intel_digital_port *dig_port,
|
||||||
const struct intel_hdcp_shim *hdcp_shim);
|
const struct intel_hdcp_shim *hdcp_shim);
|
||||||
int intel_hdcp_enable(struct intel_connector *connector,
|
int intel_hdcp_enable(struct intel_connector *connector,
|
||||||
enum transcoder cpu_transcoder, u8 content_type);
|
const struct intel_crtc_state *pipe_config, u8 content_type);
|
||||||
int intel_hdcp_disable(struct intel_connector *connector);
|
int intel_hdcp_disable(struct intel_connector *connector);
|
||||||
void intel_hdcp_update_pipe(struct intel_atomic_state *state,
|
void intel_hdcp_update_pipe(struct intel_atomic_state *state,
|
||||||
struct intel_encoder *encoder,
|
struct intel_encoder *encoder,
|
||||||
|
|||||||
@@ -1494,15 +1494,16 @@ static int kbl_repositioning_enc_en_signal(struct intel_connector *connector,
|
|||||||
usleep_range(25, 50);
|
usleep_range(25, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base, cpu_transcoder,
|
ret = intel_ddi_toggle_hdcp_bits(&dig_port->base, cpu_transcoder,
|
||||||
false);
|
false, TRANS_DDI_HDCP_SIGNALLING);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
drm_err(&dev_priv->drm,
|
drm_err(&dev_priv->drm,
|
||||||
"Disable HDCP signalling failed (%d)\n", ret);
|
"Disable HDCP signalling failed (%d)\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base, cpu_transcoder,
|
|
||||||
true);
|
ret = intel_ddi_toggle_hdcp_bits(&dig_port->base, cpu_transcoder,
|
||||||
|
true, TRANS_DDI_HDCP_SIGNALLING);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
drm_err(&dev_priv->drm,
|
drm_err(&dev_priv->drm,
|
||||||
"Enable HDCP signalling failed (%d)\n", ret);
|
"Enable HDCP signalling failed (%d)\n", ret);
|
||||||
@@ -1525,8 +1526,9 @@ int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
|
|||||||
if (!enable)
|
if (!enable)
|
||||||
usleep_range(6, 60); /* Bspec says >= 6us */
|
usleep_range(6, 60); /* Bspec says >= 6us */
|
||||||
|
|
||||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base, cpu_transcoder,
|
ret = intel_ddi_toggle_hdcp_bits(&dig_port->base,
|
||||||
enable);
|
cpu_transcoder, enable,
|
||||||
|
TRANS_DDI_HDCP_SIGNALLING);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
drm_err(&dev_priv->drm, "%s HDCP signalling failed (%d)\n",
|
drm_err(&dev_priv->drm, "%s HDCP signalling failed (%d)\n",
|
||||||
enable ? "Enable" : "Disable", ret);
|
enable ? "Enable" : "Disable", ret);
|
||||||
@@ -1731,7 +1733,8 @@ int intel_hdmi_hdcp2_read_msg(struct intel_digital_port *dig_port,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port)
|
int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
|
||||||
|
struct intel_connector *connector)
|
||||||
{
|
{
|
||||||
u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN];
|
u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN];
|
||||||
int ret;
|
int ret;
|
||||||
@@ -3290,7 +3293,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
|
|||||||
intel_hdmi->attached_connector = intel_connector;
|
intel_hdmi->attached_connector = intel_connector;
|
||||||
|
|
||||||
if (is_hdcp_supported(dev_priv, port)) {
|
if (is_hdcp_supported(dev_priv, port)) {
|
||||||
int ret = intel_hdcp_init(intel_connector, port,
|
int ret = intel_hdcp_init(intel_connector, dig_port,
|
||||||
&intel_hdmi_hdcp_shim);
|
&intel_hdmi_hdcp_shim);
|
||||||
if (ret)
|
if (ret)
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
|||||||
@@ -511,40 +511,79 @@ static u32 scale_hw_to_user(struct intel_connector *connector,
|
|||||||
0, user_max);
|
0, user_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 intel_panel_compute_brightness(struct intel_connector *connector,
|
u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 val)
|
||||||
u32 val)
|
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
|
||||||
drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0);
|
drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0);
|
||||||
|
|
||||||
if (dev_priv->params.invert_brightness < 0)
|
if (dev_priv->params.invert_brightness < 0)
|
||||||
return val;
|
return val;
|
||||||
|
|
||||||
if (dev_priv->params.invert_brightness > 0 ||
|
if (dev_priv->params.invert_brightness > 0 ||
|
||||||
dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
|
dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
|
||||||
return panel->backlight.max - val + panel->backlight.min;
|
return panel->backlight.pwm_level_max - val + panel->backlight.pwm_level_min;
|
||||||
}
|
}
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 lpt_get_backlight(struct intel_connector *connector)
|
void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 val)
|
||||||
|
{
|
||||||
|
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
||||||
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
|
||||||
|
drm_dbg_kms(&i915->drm, "set backlight PWM = %d\n", val);
|
||||||
|
panel->backlight.pwm_funcs->set(conn_state, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 val)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
|
||||||
|
drm_WARN_ON_ONCE(&dev_priv->drm,
|
||||||
|
panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0);
|
||||||
|
|
||||||
|
val = scale(val, panel->backlight.min, panel->backlight.max,
|
||||||
|
panel->backlight.pwm_level_min, panel->backlight.pwm_level_max);
|
||||||
|
|
||||||
|
return intel_panel_invert_pwm_level(connector, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
|
||||||
|
drm_WARN_ON_ONCE(&dev_priv->drm,
|
||||||
|
panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0);
|
||||||
|
|
||||||
|
if (dev_priv->params.invert_brightness > 0 ||
|
||||||
|
(dev_priv->params.invert_brightness == 0 && dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS))
|
||||||
|
val = panel->backlight.pwm_level_max - (val - panel->backlight.pwm_level_min);
|
||||||
|
|
||||||
|
return scale(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max,
|
||||||
|
panel->backlight.min, panel->backlight.max);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 lpt_get_backlight(struct intel_connector *connector, enum pipe unused)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
|
|
||||||
return intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
|
return intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 pch_get_backlight(struct intel_connector *connector)
|
static u32 pch_get_backlight(struct intel_connector *connector, enum pipe unused)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
|
|
||||||
return intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
|
return intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 i9xx_get_backlight(struct intel_connector *connector)
|
static u32 i9xx_get_backlight(struct intel_connector *connector, enum pipe unused)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
@@ -564,23 +603,17 @@ static u32 i9xx_get_backlight(struct intel_connector *connector)
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 _vlv_get_backlight(struct drm_i915_private *dev_priv, enum pipe pipe)
|
static u32 vlv_get_backlight(struct intel_connector *connector, enum pipe pipe)
|
||||||
{
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
|
|
||||||
if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B))
|
if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK;
|
return intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 vlv_get_backlight(struct intel_connector *connector)
|
static u32 bxt_get_backlight(struct intel_connector *connector, enum pipe unused)
|
||||||
{
|
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
|
||||||
enum pipe pipe = intel_connector_get_pipe(connector);
|
|
||||||
|
|
||||||
return _vlv_get_backlight(dev_priv, pipe);
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32 bxt_get_backlight(struct intel_connector *connector)
|
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
@@ -589,7 +622,7 @@ static u32 bxt_get_backlight(struct intel_connector *connector)
|
|||||||
BXT_BLC_PWM_DUTY(panel->backlight.controller));
|
BXT_BLC_PWM_DUTY(panel->backlight.controller));
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 ext_pwm_get_backlight(struct intel_connector *connector)
|
static u32 ext_pwm_get_backlight(struct intel_connector *connector, enum pipe unused)
|
||||||
{
|
{
|
||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
struct pwm_state state;
|
struct pwm_state state;
|
||||||
@@ -624,12 +657,12 @@ static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32
|
|||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
u32 tmp, mask;
|
u32 tmp, mask;
|
||||||
|
|
||||||
drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0);
|
drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0);
|
||||||
|
|
||||||
if (panel->backlight.combination_mode) {
|
if (panel->backlight.combination_mode) {
|
||||||
u8 lbpc;
|
u8 lbpc;
|
||||||
|
|
||||||
lbpc = level * 0xfe / panel->backlight.max + 1;
|
lbpc = level * 0xfe / panel->backlight.pwm_level_max + 1;
|
||||||
level /= lbpc;
|
level /= lbpc;
|
||||||
pci_write_config_byte(dev_priv->drm.pdev, LBPC, lbpc);
|
pci_write_config_byte(dev_priv->drm.pdev, LBPC, lbpc);
|
||||||
}
|
}
|
||||||
@@ -681,9 +714,8 @@ intel_panel_actually_set_backlight(const struct drm_connector_state *conn_state,
|
|||||||
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
|
||||||
drm_dbg_kms(&i915->drm, "set backlight PWM = %d\n", level);
|
drm_dbg_kms(&i915->drm, "set backlight level = %d\n", level);
|
||||||
|
|
||||||
level = intel_panel_compute_brightness(connector, level);
|
|
||||||
panel->backlight.funcs->set(conn_state, level);
|
panel->backlight.funcs->set(conn_state, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -732,7 +764,7 @@ static void lpt_disable_backlight(const struct drm_connector_state *old_conn_sta
|
|||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
intel_panel_actually_set_backlight(old_conn_state, level);
|
intel_panel_set_pwm_level(old_conn_state, level);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Although we don't support or enable CPU PWM with LPT/SPT based
|
* Although we don't support or enable CPU PWM with LPT/SPT based
|
||||||
@@ -760,7 +792,7 @@ static void pch_disable_backlight(const struct drm_connector_state *old_conn_sta
|
|||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
intel_panel_actually_set_backlight(old_conn_state, val);
|
intel_panel_set_pwm_level(old_conn_state, val);
|
||||||
|
|
||||||
tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
|
tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
|
||||||
intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
|
intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
|
||||||
@@ -771,7 +803,7 @@ static void pch_disable_backlight(const struct drm_connector_state *old_conn_sta
|
|||||||
|
|
||||||
static void i9xx_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
|
static void i9xx_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
|
||||||
{
|
{
|
||||||
intel_panel_actually_set_backlight(old_conn_state, val);
|
intel_panel_set_pwm_level(old_conn_state, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void i965_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
|
static void i965_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
|
||||||
@@ -779,7 +811,7 @@ static void i965_disable_backlight(const struct drm_connector_state *old_conn_st
|
|||||||
struct drm_i915_private *dev_priv = to_i915(old_conn_state->connector->dev);
|
struct drm_i915_private *dev_priv = to_i915(old_conn_state->connector->dev);
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
intel_panel_actually_set_backlight(old_conn_state, val);
|
intel_panel_set_pwm_level(old_conn_state, val);
|
||||||
|
|
||||||
tmp = intel_de_read(dev_priv, BLC_PWM_CTL2);
|
tmp = intel_de_read(dev_priv, BLC_PWM_CTL2);
|
||||||
intel_de_write(dev_priv, BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE);
|
intel_de_write(dev_priv, BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE);
|
||||||
@@ -792,7 +824,7 @@ static void vlv_disable_backlight(const struct drm_connector_state *old_conn_sta
|
|||||||
enum pipe pipe = to_intel_crtc(old_conn_state->crtc)->pipe;
|
enum pipe pipe = to_intel_crtc(old_conn_state->crtc)->pipe;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
intel_panel_actually_set_backlight(old_conn_state, val);
|
intel_panel_set_pwm_level(old_conn_state, val);
|
||||||
|
|
||||||
tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe));
|
tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe));
|
||||||
intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe),
|
intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe),
|
||||||
@@ -806,7 +838,7 @@ static void bxt_disable_backlight(const struct drm_connector_state *old_conn_sta
|
|||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
intel_panel_actually_set_backlight(old_conn_state, val);
|
intel_panel_set_pwm_level(old_conn_state, val);
|
||||||
|
|
||||||
tmp = intel_de_read(dev_priv,
|
tmp = intel_de_read(dev_priv,
|
||||||
BXT_BLC_PWM_CTL(panel->backlight.controller));
|
BXT_BLC_PWM_CTL(panel->backlight.controller));
|
||||||
@@ -827,7 +859,7 @@ static void cnp_disable_backlight(const struct drm_connector_state *old_conn_sta
|
|||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
intel_panel_actually_set_backlight(old_conn_state, val);
|
intel_panel_set_pwm_level(old_conn_state, val);
|
||||||
|
|
||||||
tmp = intel_de_read(dev_priv,
|
tmp = intel_de_read(dev_priv,
|
||||||
BXT_BLC_PWM_CTL(panel->backlight.controller));
|
BXT_BLC_PWM_CTL(panel->backlight.controller));
|
||||||
@@ -906,7 +938,7 @@ static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state,
|
|||||||
intel_de_write(dev_priv, SOUTH_CHICKEN1, schicken);
|
intel_de_write(dev_priv, SOUTH_CHICKEN1, schicken);
|
||||||
}
|
}
|
||||||
|
|
||||||
pch_ctl2 = panel->backlight.max << 16;
|
pch_ctl2 = panel->backlight.pwm_level_max << 16;
|
||||||
intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2);
|
intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2);
|
||||||
|
|
||||||
pch_ctl1 = 0;
|
pch_ctl1 = 0;
|
||||||
@@ -923,7 +955,7 @@ static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state,
|
|||||||
pch_ctl1 | BLM_PCH_PWM_ENABLE);
|
pch_ctl1 | BLM_PCH_PWM_ENABLE);
|
||||||
|
|
||||||
/* This won't stick until the above enable. */
|
/* This won't stick until the above enable. */
|
||||||
intel_panel_actually_set_backlight(conn_state, level);
|
intel_panel_set_pwm_level(conn_state, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pch_enable_backlight(const struct intel_crtc_state *crtc_state,
|
static void pch_enable_backlight(const struct intel_crtc_state *crtc_state,
|
||||||
@@ -958,9 +990,9 @@ static void pch_enable_backlight(const struct intel_crtc_state *crtc_state,
|
|||||||
intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE);
|
intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE);
|
||||||
|
|
||||||
/* This won't stick until the above enable. */
|
/* This won't stick until the above enable. */
|
||||||
intel_panel_actually_set_backlight(conn_state, level);
|
intel_panel_set_pwm_level(conn_state, level);
|
||||||
|
|
||||||
pch_ctl2 = panel->backlight.max << 16;
|
pch_ctl2 = panel->backlight.pwm_level_max << 16;
|
||||||
intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2);
|
intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2);
|
||||||
|
|
||||||
pch_ctl1 = 0;
|
pch_ctl1 = 0;
|
||||||
@@ -987,7 +1019,7 @@ static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state,
|
|||||||
intel_de_write(dev_priv, BLC_PWM_CTL, 0);
|
intel_de_write(dev_priv, BLC_PWM_CTL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
freq = panel->backlight.max;
|
freq = panel->backlight.pwm_level_max;
|
||||||
if (panel->backlight.combination_mode)
|
if (panel->backlight.combination_mode)
|
||||||
freq /= 0xff;
|
freq /= 0xff;
|
||||||
|
|
||||||
@@ -1001,7 +1033,7 @@ static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state,
|
|||||||
intel_de_posting_read(dev_priv, BLC_PWM_CTL);
|
intel_de_posting_read(dev_priv, BLC_PWM_CTL);
|
||||||
|
|
||||||
/* XXX: combine this into above write? */
|
/* XXX: combine this into above write? */
|
||||||
intel_panel_actually_set_backlight(conn_state, level);
|
intel_panel_set_pwm_level(conn_state, level);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Needed to enable backlight on some 855gm models. BLC_HIST_CTL is
|
* Needed to enable backlight on some 855gm models. BLC_HIST_CTL is
|
||||||
@@ -1028,7 +1060,7 @@ static void i965_enable_backlight(const struct intel_crtc_state *crtc_state,
|
|||||||
intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2);
|
intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2);
|
||||||
}
|
}
|
||||||
|
|
||||||
freq = panel->backlight.max;
|
freq = panel->backlight.pwm_level_max;
|
||||||
if (panel->backlight.combination_mode)
|
if (panel->backlight.combination_mode)
|
||||||
freq /= 0xff;
|
freq /= 0xff;
|
||||||
|
|
||||||
@@ -1044,7 +1076,7 @@ static void i965_enable_backlight(const struct intel_crtc_state *crtc_state,
|
|||||||
intel_de_posting_read(dev_priv, BLC_PWM_CTL2);
|
intel_de_posting_read(dev_priv, BLC_PWM_CTL2);
|
||||||
intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE);
|
intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE);
|
||||||
|
|
||||||
intel_panel_actually_set_backlight(conn_state, level);
|
intel_panel_set_pwm_level(conn_state, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vlv_enable_backlight(const struct intel_crtc_state *crtc_state,
|
static void vlv_enable_backlight(const struct intel_crtc_state *crtc_state,
|
||||||
@@ -1063,11 +1095,11 @@ static void vlv_enable_backlight(const struct intel_crtc_state *crtc_state,
|
|||||||
intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2);
|
intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctl = panel->backlight.max << 16;
|
ctl = panel->backlight.pwm_level_max << 16;
|
||||||
intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), ctl);
|
intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), ctl);
|
||||||
|
|
||||||
/* XXX: combine this into above write? */
|
/* XXX: combine this into above write? */
|
||||||
intel_panel_actually_set_backlight(conn_state, level);
|
intel_panel_set_pwm_level(conn_state, level);
|
||||||
|
|
||||||
ctl2 = 0;
|
ctl2 = 0;
|
||||||
if (panel->backlight.active_low_pwm)
|
if (panel->backlight.active_low_pwm)
|
||||||
@@ -1116,9 +1148,9 @@ static void bxt_enable_backlight(const struct intel_crtc_state *crtc_state,
|
|||||||
|
|
||||||
intel_de_write(dev_priv,
|
intel_de_write(dev_priv,
|
||||||
BXT_BLC_PWM_FREQ(panel->backlight.controller),
|
BXT_BLC_PWM_FREQ(panel->backlight.controller),
|
||||||
panel->backlight.max);
|
panel->backlight.pwm_level_max);
|
||||||
|
|
||||||
intel_panel_actually_set_backlight(conn_state, level);
|
intel_panel_set_pwm_level(conn_state, level);
|
||||||
|
|
||||||
pwm_ctl = 0;
|
pwm_ctl = 0;
|
||||||
if (panel->backlight.active_low_pwm)
|
if (panel->backlight.active_low_pwm)
|
||||||
@@ -1152,9 +1184,9 @@ static void cnp_enable_backlight(const struct intel_crtc_state *crtc_state,
|
|||||||
|
|
||||||
intel_de_write(dev_priv,
|
intel_de_write(dev_priv,
|
||||||
BXT_BLC_PWM_FREQ(panel->backlight.controller),
|
BXT_BLC_PWM_FREQ(panel->backlight.controller),
|
||||||
panel->backlight.max);
|
panel->backlight.pwm_level_max);
|
||||||
|
|
||||||
intel_panel_actually_set_backlight(conn_state, level);
|
intel_panel_set_pwm_level(conn_state, level);
|
||||||
|
|
||||||
pwm_ctl = 0;
|
pwm_ctl = 0;
|
||||||
if (panel->backlight.active_low_pwm)
|
if (panel->backlight.active_low_pwm)
|
||||||
@@ -1174,7 +1206,6 @@ static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state,
|
|||||||
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
|
||||||
level = intel_panel_compute_brightness(connector, level);
|
|
||||||
pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100);
|
pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100);
|
||||||
panel->backlight.pwm_state.enabled = true;
|
panel->backlight.pwm_state.enabled = true;
|
||||||
pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
|
pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
|
||||||
@@ -1232,10 +1263,8 @@ static u32 intel_panel_get_backlight(struct intel_connector *connector)
|
|||||||
|
|
||||||
mutex_lock(&dev_priv->backlight_lock);
|
mutex_lock(&dev_priv->backlight_lock);
|
||||||
|
|
||||||
if (panel->backlight.enabled) {
|
if (panel->backlight.enabled)
|
||||||
val = panel->backlight.funcs->get(connector);
|
val = panel->backlight.funcs->get(connector, intel_connector_get_pipe(connector));
|
||||||
val = intel_panel_compute_brightness(connector, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&dev_priv->backlight_lock);
|
mutex_unlock(&dev_priv->backlight_lock);
|
||||||
|
|
||||||
@@ -1566,13 +1595,13 @@ static u32 get_backlight_max_vbt(struct intel_connector *connector)
|
|||||||
u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv);
|
u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv);
|
||||||
u32 pwm;
|
u32 pwm;
|
||||||
|
|
||||||
if (!panel->backlight.funcs->hz_to_pwm) {
|
if (!panel->backlight.pwm_funcs->hz_to_pwm) {
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
"backlight frequency conversion not supported\n");
|
"backlight frequency conversion not supported\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pwm = panel->backlight.funcs->hz_to_pwm(connector, pwm_freq_hz);
|
pwm = panel->backlight.pwm_funcs->hz_to_pwm(connector, pwm_freq_hz);
|
||||||
if (!pwm) {
|
if (!pwm) {
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
"backlight frequency conversion failed\n");
|
"backlight frequency conversion failed\n");
|
||||||
@@ -1591,7 +1620,7 @@ static u32 get_backlight_min_vbt(struct intel_connector *connector)
|
|||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
int min;
|
int min;
|
||||||
|
|
||||||
drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0);
|
drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX: If the vbt value is 255, it makes min equal to max, which leads
|
* XXX: If the vbt value is 255, it makes min equal to max, which leads
|
||||||
@@ -1608,7 +1637,7 @@ static u32 get_backlight_min_vbt(struct intel_connector *connector)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* vbt value is a coefficient in range [0..255] */
|
/* vbt value is a coefficient in range [0..255] */
|
||||||
return scale(min, 0, 255, 0, panel->backlight.max);
|
return scale(min, 0, 255, 0, panel->backlight.pwm_level_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused)
|
static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused)
|
||||||
@@ -1628,29 +1657,27 @@ static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unus
|
|||||||
panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
|
panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
|
||||||
|
|
||||||
pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2);
|
pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2);
|
||||||
panel->backlight.max = pch_ctl2 >> 16;
|
panel->backlight.pwm_level_max = pch_ctl2 >> 16;
|
||||||
|
|
||||||
cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
|
cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
|
||||||
|
|
||||||
if (!panel->backlight.max)
|
if (!panel->backlight.pwm_level_max)
|
||||||
panel->backlight.max = get_backlight_max_vbt(connector);
|
panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
|
||||||
|
|
||||||
if (!panel->backlight.max)
|
if (!panel->backlight.pwm_level_max)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
panel->backlight.min = get_backlight_min_vbt(connector);
|
panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
|
||||||
|
|
||||||
panel->backlight.enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE;
|
panel->backlight.pwm_enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE;
|
||||||
|
|
||||||
cpu_mode = panel->backlight.enabled && HAS_PCH_LPT(dev_priv) &&
|
cpu_mode = panel->backlight.pwm_enabled && HAS_PCH_LPT(dev_priv) &&
|
||||||
!(pch_ctl1 & BLM_PCH_OVERRIDE_ENABLE) &&
|
!(pch_ctl1 & BLM_PCH_OVERRIDE_ENABLE) &&
|
||||||
(cpu_ctl2 & BLM_PWM_ENABLE);
|
(cpu_ctl2 & BLM_PWM_ENABLE);
|
||||||
if (cpu_mode)
|
|
||||||
val = pch_get_backlight(connector);
|
|
||||||
else
|
|
||||||
val = lpt_get_backlight(connector);
|
|
||||||
|
|
||||||
if (cpu_mode) {
|
if (cpu_mode) {
|
||||||
|
val = pch_get_backlight(connector, unused);
|
||||||
|
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
"CPU backlight register was enabled, switching to PCH override\n");
|
"CPU backlight register was enabled, switching to PCH override\n");
|
||||||
|
|
||||||
@@ -1663,10 +1690,6 @@ static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unus
|
|||||||
cpu_ctl2 & ~BLM_PWM_ENABLE);
|
cpu_ctl2 & ~BLM_PWM_ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
val = intel_panel_compute_brightness(connector, val);
|
|
||||||
panel->backlight.level = clamp(val, panel->backlight.min,
|
|
||||||
panel->backlight.max);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1674,29 +1697,24 @@ static int pch_setup_backlight(struct intel_connector *connector, enum pipe unus
|
|||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
|
u32 cpu_ctl2, pch_ctl1, pch_ctl2;
|
||||||
|
|
||||||
pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
|
pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
|
||||||
panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
|
panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
|
||||||
|
|
||||||
pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2);
|
pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2);
|
||||||
panel->backlight.max = pch_ctl2 >> 16;
|
panel->backlight.pwm_level_max = pch_ctl2 >> 16;
|
||||||
|
|
||||||
if (!panel->backlight.max)
|
if (!panel->backlight.pwm_level_max)
|
||||||
panel->backlight.max = get_backlight_max_vbt(connector);
|
panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
|
||||||
|
|
||||||
if (!panel->backlight.max)
|
if (!panel->backlight.pwm_level_max)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
panel->backlight.min = get_backlight_min_vbt(connector);
|
panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
|
||||||
|
|
||||||
val = pch_get_backlight(connector);
|
|
||||||
val = intel_panel_compute_brightness(connector, val);
|
|
||||||
panel->backlight.level = clamp(val, panel->backlight.min,
|
|
||||||
panel->backlight.max);
|
|
||||||
|
|
||||||
cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
|
cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
|
||||||
panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
|
panel->backlight.pwm_enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
|
||||||
(pch_ctl1 & BLM_PCH_PWM_ENABLE);
|
(pch_ctl1 & BLM_PCH_PWM_ENABLE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1716,27 +1734,26 @@ static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unu
|
|||||||
if (IS_PINEVIEW(dev_priv))
|
if (IS_PINEVIEW(dev_priv))
|
||||||
panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV;
|
panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV;
|
||||||
|
|
||||||
panel->backlight.max = ctl >> 17;
|
panel->backlight.pwm_level_max = ctl >> 17;
|
||||||
|
|
||||||
if (!panel->backlight.max) {
|
if (!panel->backlight.pwm_level_max) {
|
||||||
panel->backlight.max = get_backlight_max_vbt(connector);
|
panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
|
||||||
panel->backlight.max >>= 1;
|
panel->backlight.pwm_level_max >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!panel->backlight.max)
|
if (!panel->backlight.pwm_level_max)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (panel->backlight.combination_mode)
|
if (panel->backlight.combination_mode)
|
||||||
panel->backlight.max *= 0xff;
|
panel->backlight.pwm_level_max *= 0xff;
|
||||||
|
|
||||||
panel->backlight.min = get_backlight_min_vbt(connector);
|
panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
|
||||||
|
|
||||||
val = i9xx_get_backlight(connector);
|
val = i9xx_get_backlight(connector, unused);
|
||||||
val = intel_panel_compute_brightness(connector, val);
|
val = intel_panel_invert_pwm_level(connector, val);
|
||||||
panel->backlight.level = clamp(val, panel->backlight.min,
|
val = clamp(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max);
|
||||||
panel->backlight.max);
|
|
||||||
|
|
||||||
panel->backlight.enabled = val != 0;
|
panel->backlight.pwm_enabled = val != 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1745,32 +1762,27 @@ static int i965_setup_backlight(struct intel_connector *connector, enum pipe unu
|
|||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
u32 ctl, ctl2, val;
|
u32 ctl, ctl2;
|
||||||
|
|
||||||
ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2);
|
ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2);
|
||||||
panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE;
|
panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE;
|
||||||
panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
|
panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
|
||||||
|
|
||||||
ctl = intel_de_read(dev_priv, BLC_PWM_CTL);
|
ctl = intel_de_read(dev_priv, BLC_PWM_CTL);
|
||||||
panel->backlight.max = ctl >> 16;
|
panel->backlight.pwm_level_max = ctl >> 16;
|
||||||
|
|
||||||
if (!panel->backlight.max)
|
if (!panel->backlight.pwm_level_max)
|
||||||
panel->backlight.max = get_backlight_max_vbt(connector);
|
panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
|
||||||
|
|
||||||
if (!panel->backlight.max)
|
if (!panel->backlight.pwm_level_max)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (panel->backlight.combination_mode)
|
if (panel->backlight.combination_mode)
|
||||||
panel->backlight.max *= 0xff;
|
panel->backlight.pwm_level_max *= 0xff;
|
||||||
|
|
||||||
panel->backlight.min = get_backlight_min_vbt(connector);
|
panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
|
||||||
|
|
||||||
val = i9xx_get_backlight(connector);
|
panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE;
|
||||||
val = intel_panel_compute_brightness(connector, val);
|
|
||||||
panel->backlight.level = clamp(val, panel->backlight.min,
|
|
||||||
panel->backlight.max);
|
|
||||||
|
|
||||||
panel->backlight.enabled = ctl2 & BLM_PWM_ENABLE;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1779,7 +1791,7 @@ static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe
|
|||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
u32 ctl, ctl2, val;
|
u32 ctl, ctl2;
|
||||||
|
|
||||||
if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B))
|
if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@@ -1788,22 +1800,17 @@ static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe
|
|||||||
panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
|
panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
|
||||||
|
|
||||||
ctl = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe));
|
ctl = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe));
|
||||||
panel->backlight.max = ctl >> 16;
|
panel->backlight.pwm_level_max = ctl >> 16;
|
||||||
|
|
||||||
if (!panel->backlight.max)
|
if (!panel->backlight.pwm_level_max)
|
||||||
panel->backlight.max = get_backlight_max_vbt(connector);
|
panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
|
||||||
|
|
||||||
if (!panel->backlight.max)
|
if (!panel->backlight.pwm_level_max)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
panel->backlight.min = get_backlight_min_vbt(connector);
|
panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
|
||||||
|
|
||||||
val = _vlv_get_backlight(dev_priv, pipe);
|
panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE;
|
||||||
val = intel_panel_compute_brightness(connector, val);
|
|
||||||
panel->backlight.level = clamp(val, panel->backlight.min,
|
|
||||||
panel->backlight.max);
|
|
||||||
|
|
||||||
panel->backlight.enabled = ctl2 & BLM_PWM_ENABLE;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1828,24 +1835,18 @@ bxt_setup_backlight(struct intel_connector *connector, enum pipe unused)
|
|||||||
}
|
}
|
||||||
|
|
||||||
panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
|
panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
|
||||||
panel->backlight.max =
|
panel->backlight.pwm_level_max =
|
||||||
intel_de_read(dev_priv,
|
intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller));
|
||||||
BXT_BLC_PWM_FREQ(panel->backlight.controller));
|
|
||||||
|
|
||||||
if (!panel->backlight.max)
|
if (!panel->backlight.pwm_level_max)
|
||||||
panel->backlight.max = get_backlight_max_vbt(connector);
|
panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
|
||||||
|
|
||||||
if (!panel->backlight.max)
|
if (!panel->backlight.pwm_level_max)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
panel->backlight.min = get_backlight_min_vbt(connector);
|
panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
|
||||||
|
|
||||||
val = bxt_get_backlight(connector);
|
panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
|
||||||
val = intel_panel_compute_brightness(connector, val);
|
|
||||||
panel->backlight.level = clamp(val, panel->backlight.min,
|
|
||||||
panel->backlight.max);
|
|
||||||
|
|
||||||
panel->backlight.enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1855,7 +1856,7 @@ cnp_setup_backlight(struct intel_connector *connector, enum pipe unused)
|
|||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
struct intel_panel *panel = &connector->panel;
|
struct intel_panel *panel = &connector->panel;
|
||||||
u32 pwm_ctl, val;
|
u32 pwm_ctl;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CNP has the BXT implementation of backlight, but with only one
|
* CNP has the BXT implementation of backlight, but with only one
|
||||||
@@ -1868,24 +1869,18 @@ cnp_setup_backlight(struct intel_connector *connector, enum pipe unused)
|
|||||||
BXT_BLC_PWM_CTL(panel->backlight.controller));
|
BXT_BLC_PWM_CTL(panel->backlight.controller));
|
||||||
|
|
||||||
panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
|
panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
|
||||||
panel->backlight.max =
|
panel->backlight.pwm_level_max =
|
||||||
intel_de_read(dev_priv,
|
intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller));
|
||||||
BXT_BLC_PWM_FREQ(panel->backlight.controller));
|
|
||||||
|
|
||||||
if (!panel->backlight.max)
|
if (!panel->backlight.pwm_level_max)
|
||||||
panel->backlight.max = get_backlight_max_vbt(connector);
|
panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
|
||||||
|
|
||||||
if (!panel->backlight.max)
|
if (!panel->backlight.pwm_level_max)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
panel->backlight.min = get_backlight_min_vbt(connector);
|
panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
|
||||||
|
|
||||||
val = bxt_get_backlight(connector);
|
panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
|
||||||
val = intel_panel_compute_brightness(connector, val);
|
|
||||||
panel->backlight.level = clamp(val, panel->backlight.min,
|
|
||||||
panel->backlight.max);
|
|
||||||
|
|
||||||
panel->backlight.enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1915,8 +1910,8 @@ static int ext_pwm_setup_backlight(struct intel_connector *connector,
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
panel->backlight.max = 100; /* 100% */
|
panel->backlight.pwm_level_max = 100; /* 100% */
|
||||||
panel->backlight.min = get_backlight_min_vbt(connector);
|
panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
|
||||||
|
|
||||||
if (pwm_is_enabled(panel->backlight.pwm)) {
|
if (pwm_is_enabled(panel->backlight.pwm)) {
|
||||||
/* PWM is already enabled, use existing settings */
|
/* PWM is already enabled, use existing settings */
|
||||||
@@ -1924,10 +1919,8 @@ static int ext_pwm_setup_backlight(struct intel_connector *connector,
|
|||||||
|
|
||||||
level = pwm_get_relative_duty_cycle(&panel->backlight.pwm_state,
|
level = pwm_get_relative_duty_cycle(&panel->backlight.pwm_state,
|
||||||
100);
|
100);
|
||||||
level = intel_panel_compute_brightness(connector, level);
|
level = intel_panel_invert_pwm_level(connector, level);
|
||||||
panel->backlight.level = clamp(level, panel->backlight.min,
|
panel->backlight.pwm_enabled = true;
|
||||||
panel->backlight.max);
|
|
||||||
panel->backlight.enabled = true;
|
|
||||||
|
|
||||||
drm_dbg_kms(&dev_priv->drm, "PWM already enabled at freq %ld, VBT freq %d, level %d\n",
|
drm_dbg_kms(&dev_priv->drm, "PWM already enabled at freq %ld, VBT freq %d, level %d\n",
|
||||||
NSEC_PER_SEC / (unsigned long)panel->backlight.pwm_state.period,
|
NSEC_PER_SEC / (unsigned long)panel->backlight.pwm_state.period,
|
||||||
@@ -1943,6 +1936,58 @@ static int ext_pwm_setup_backlight(struct intel_connector *connector,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void intel_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level)
|
||||||
|
{
|
||||||
|
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
||||||
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
|
||||||
|
panel->backlight.pwm_funcs->set(conn_state,
|
||||||
|
intel_panel_invert_pwm_level(connector, level));
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 intel_pwm_get_backlight(struct intel_connector *connector, enum pipe pipe)
|
||||||
|
{
|
||||||
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
|
||||||
|
return intel_panel_invert_pwm_level(connector,
|
||||||
|
panel->backlight.pwm_funcs->get(connector, pipe));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void intel_pwm_enable_backlight(const struct intel_crtc_state *crtc_state,
|
||||||
|
const struct drm_connector_state *conn_state, u32 level)
|
||||||
|
{
|
||||||
|
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
||||||
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
|
||||||
|
panel->backlight.pwm_funcs->enable(crtc_state, conn_state,
|
||||||
|
intel_panel_invert_pwm_level(connector, level));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void intel_pwm_disable_backlight(const struct drm_connector_state *conn_state, u32 level)
|
||||||
|
{
|
||||||
|
struct intel_connector *connector = to_intel_connector(conn_state->connector);
|
||||||
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
|
||||||
|
panel->backlight.pwm_funcs->disable(conn_state,
|
||||||
|
intel_panel_invert_pwm_level(connector, level));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int intel_pwm_setup_backlight(struct intel_connector *connector, enum pipe pipe)
|
||||||
|
{
|
||||||
|
struct intel_panel *panel = &connector->panel;
|
||||||
|
int ret = panel->backlight.pwm_funcs->setup(connector, pipe);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
panel->backlight.min = panel->backlight.pwm_level_min;
|
||||||
|
panel->backlight.max = panel->backlight.pwm_level_max;
|
||||||
|
panel->backlight.level = intel_pwm_get_backlight(connector, pipe);
|
||||||
|
panel->backlight.enabled = panel->backlight.pwm_enabled;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void intel_panel_update_backlight(struct intel_atomic_state *state,
|
void intel_panel_update_backlight(struct intel_atomic_state *state,
|
||||||
struct intel_encoder *encoder,
|
struct intel_encoder *encoder,
|
||||||
const struct intel_crtc_state *crtc_state,
|
const struct intel_crtc_state *crtc_state,
|
||||||
@@ -2016,7 +2061,7 @@ static void intel_panel_destroy_backlight(struct intel_panel *panel)
|
|||||||
panel->backlight.present = false;
|
panel->backlight.present = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct intel_panel_bl_funcs bxt_funcs = {
|
static const struct intel_panel_bl_funcs bxt_pwm_funcs = {
|
||||||
.setup = bxt_setup_backlight,
|
.setup = bxt_setup_backlight,
|
||||||
.enable = bxt_enable_backlight,
|
.enable = bxt_enable_backlight,
|
||||||
.disable = bxt_disable_backlight,
|
.disable = bxt_disable_backlight,
|
||||||
@@ -2025,7 +2070,7 @@ static const struct intel_panel_bl_funcs bxt_funcs = {
|
|||||||
.hz_to_pwm = bxt_hz_to_pwm,
|
.hz_to_pwm = bxt_hz_to_pwm,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_panel_bl_funcs cnp_funcs = {
|
static const struct intel_panel_bl_funcs cnp_pwm_funcs = {
|
||||||
.setup = cnp_setup_backlight,
|
.setup = cnp_setup_backlight,
|
||||||
.enable = cnp_enable_backlight,
|
.enable = cnp_enable_backlight,
|
||||||
.disable = cnp_disable_backlight,
|
.disable = cnp_disable_backlight,
|
||||||
@@ -2034,7 +2079,7 @@ static const struct intel_panel_bl_funcs cnp_funcs = {
|
|||||||
.hz_to_pwm = cnp_hz_to_pwm,
|
.hz_to_pwm = cnp_hz_to_pwm,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_panel_bl_funcs lpt_funcs = {
|
static const struct intel_panel_bl_funcs lpt_pwm_funcs = {
|
||||||
.setup = lpt_setup_backlight,
|
.setup = lpt_setup_backlight,
|
||||||
.enable = lpt_enable_backlight,
|
.enable = lpt_enable_backlight,
|
||||||
.disable = lpt_disable_backlight,
|
.disable = lpt_disable_backlight,
|
||||||
@@ -2043,7 +2088,7 @@ static const struct intel_panel_bl_funcs lpt_funcs = {
|
|||||||
.hz_to_pwm = lpt_hz_to_pwm,
|
.hz_to_pwm = lpt_hz_to_pwm,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_panel_bl_funcs spt_funcs = {
|
static const struct intel_panel_bl_funcs spt_pwm_funcs = {
|
||||||
.setup = lpt_setup_backlight,
|
.setup = lpt_setup_backlight,
|
||||||
.enable = lpt_enable_backlight,
|
.enable = lpt_enable_backlight,
|
||||||
.disable = lpt_disable_backlight,
|
.disable = lpt_disable_backlight,
|
||||||
@@ -2052,7 +2097,7 @@ static const struct intel_panel_bl_funcs spt_funcs = {
|
|||||||
.hz_to_pwm = spt_hz_to_pwm,
|
.hz_to_pwm = spt_hz_to_pwm,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_panel_bl_funcs pch_funcs = {
|
static const struct intel_panel_bl_funcs pch_pwm_funcs = {
|
||||||
.setup = pch_setup_backlight,
|
.setup = pch_setup_backlight,
|
||||||
.enable = pch_enable_backlight,
|
.enable = pch_enable_backlight,
|
||||||
.disable = pch_disable_backlight,
|
.disable = pch_disable_backlight,
|
||||||
@@ -2069,7 +2114,7 @@ static const struct intel_panel_bl_funcs ext_pwm_funcs = {
|
|||||||
.get = ext_pwm_get_backlight,
|
.get = ext_pwm_get_backlight,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_panel_bl_funcs vlv_funcs = {
|
static const struct intel_panel_bl_funcs vlv_pwm_funcs = {
|
||||||
.setup = vlv_setup_backlight,
|
.setup = vlv_setup_backlight,
|
||||||
.enable = vlv_enable_backlight,
|
.enable = vlv_enable_backlight,
|
||||||
.disable = vlv_disable_backlight,
|
.disable = vlv_disable_backlight,
|
||||||
@@ -2078,7 +2123,7 @@ static const struct intel_panel_bl_funcs vlv_funcs = {
|
|||||||
.hz_to_pwm = vlv_hz_to_pwm,
|
.hz_to_pwm = vlv_hz_to_pwm,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_panel_bl_funcs i965_funcs = {
|
static const struct intel_panel_bl_funcs i965_pwm_funcs = {
|
||||||
.setup = i965_setup_backlight,
|
.setup = i965_setup_backlight,
|
||||||
.enable = i965_enable_backlight,
|
.enable = i965_enable_backlight,
|
||||||
.disable = i965_disable_backlight,
|
.disable = i965_disable_backlight,
|
||||||
@@ -2087,7 +2132,7 @@ static const struct intel_panel_bl_funcs i965_funcs = {
|
|||||||
.hz_to_pwm = i965_hz_to_pwm,
|
.hz_to_pwm = i965_hz_to_pwm,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_panel_bl_funcs i9xx_funcs = {
|
static const struct intel_panel_bl_funcs i9xx_pwm_funcs = {
|
||||||
.setup = i9xx_setup_backlight,
|
.setup = i9xx_setup_backlight,
|
||||||
.enable = i9xx_enable_backlight,
|
.enable = i9xx_enable_backlight,
|
||||||
.disable = i9xx_disable_backlight,
|
.disable = i9xx_disable_backlight,
|
||||||
@@ -2096,6 +2141,14 @@ static const struct intel_panel_bl_funcs i9xx_funcs = {
|
|||||||
.hz_to_pwm = i9xx_hz_to_pwm,
|
.hz_to_pwm = i9xx_hz_to_pwm,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct intel_panel_bl_funcs pwm_bl_funcs = {
|
||||||
|
.setup = intel_pwm_setup_backlight,
|
||||||
|
.enable = intel_pwm_enable_backlight,
|
||||||
|
.disable = intel_pwm_disable_backlight,
|
||||||
|
.set = intel_pwm_set_backlight,
|
||||||
|
.get = intel_pwm_get_backlight,
|
||||||
|
};
|
||||||
|
|
||||||
/* Set up chip specific backlight functions */
|
/* Set up chip specific backlight functions */
|
||||||
static void
|
static void
|
||||||
intel_panel_init_backlight_funcs(struct intel_panel *panel)
|
intel_panel_init_backlight_funcs(struct intel_panel *panel)
|
||||||
@@ -2104,36 +2157,39 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel)
|
|||||||
container_of(panel, struct intel_connector, panel);
|
container_of(panel, struct intel_connector, panel);
|
||||||
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
|
||||||
|
|
||||||
if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP &&
|
|
||||||
intel_dp_aux_init_backlight_funcs(connector) == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI &&
|
if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI &&
|
||||||
intel_dsi_dcs_init_backlight_funcs(connector) == 0)
|
intel_dsi_dcs_init_backlight_funcs(connector) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (IS_GEN9_LP(dev_priv)) {
|
if (IS_GEN9_LP(dev_priv)) {
|
||||||
panel->backlight.funcs = &bxt_funcs;
|
panel->backlight.pwm_funcs = &bxt_pwm_funcs;
|
||||||
} else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) {
|
} else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) {
|
||||||
panel->backlight.funcs = &cnp_funcs;
|
panel->backlight.pwm_funcs = &cnp_pwm_funcs;
|
||||||
} else if (INTEL_PCH_TYPE(dev_priv) >= PCH_LPT) {
|
} else if (INTEL_PCH_TYPE(dev_priv) >= PCH_LPT) {
|
||||||
if (HAS_PCH_LPT(dev_priv))
|
if (HAS_PCH_LPT(dev_priv))
|
||||||
panel->backlight.funcs = &lpt_funcs;
|
panel->backlight.pwm_funcs = &lpt_pwm_funcs;
|
||||||
else
|
else
|
||||||
panel->backlight.funcs = &spt_funcs;
|
panel->backlight.pwm_funcs = &spt_pwm_funcs;
|
||||||
} else if (HAS_PCH_SPLIT(dev_priv)) {
|
} else if (HAS_PCH_SPLIT(dev_priv)) {
|
||||||
panel->backlight.funcs = &pch_funcs;
|
panel->backlight.pwm_funcs = &pch_pwm_funcs;
|
||||||
} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
|
} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
|
||||||
if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) {
|
if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) {
|
||||||
panel->backlight.funcs = &ext_pwm_funcs;
|
panel->backlight.pwm_funcs = &ext_pwm_funcs;
|
||||||
} else {
|
} else {
|
||||||
panel->backlight.funcs = &vlv_funcs;
|
panel->backlight.pwm_funcs = &vlv_pwm_funcs;
|
||||||
}
|
}
|
||||||
} else if (IS_GEN(dev_priv, 4)) {
|
} else if (IS_GEN(dev_priv, 4)) {
|
||||||
panel->backlight.funcs = &i965_funcs;
|
panel->backlight.pwm_funcs = &i965_pwm_funcs;
|
||||||
} else {
|
} else {
|
||||||
panel->backlight.funcs = &i9xx_funcs;
|
panel->backlight.pwm_funcs = &i9xx_pwm_funcs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP &&
|
||||||
|
intel_dp_aux_init_backlight_funcs(connector) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* We're using a standard PWM backlight interface */
|
||||||
|
panel->backlight.funcs = &pwm_bl_funcs;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum drm_connector_status
|
enum drm_connector_status
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ struct drm_display_mode *
|
|||||||
intel_panel_edid_fixed_mode(struct intel_connector *connector);
|
intel_panel_edid_fixed_mode(struct intel_connector *connector);
|
||||||
struct drm_display_mode *
|
struct drm_display_mode *
|
||||||
intel_panel_vbt_fixed_mode(struct intel_connector *connector);
|
intel_panel_vbt_fixed_mode(struct intel_connector *connector);
|
||||||
|
void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 level);
|
||||||
|
u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 level);
|
||||||
|
u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 level);
|
||||||
|
u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
|
#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
|
||||||
int intel_backlight_device_register(struct intel_connector *connector);
|
int intel_backlight_device_register(struct intel_connector *connector);
|
||||||
|
|||||||
1406
drivers/gpu/drm/i915/display/intel_pps.c
Normal file
1406
drivers/gpu/drm/i915/display/intel_pps.c
Normal file
File diff suppressed because it is too large
Load Diff
52
drivers/gpu/drm/i915/display/intel_pps.h
Normal file
52
drivers/gpu/drm/i915/display/intel_pps.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
/*
|
||||||
|
* Copyright © 2020 Intel Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __INTEL_PPS_H__
|
||||||
|
#define __INTEL_PPS_H__
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#include "intel_wakeref.h"
|
||||||
|
|
||||||
|
struct drm_i915_private;
|
||||||
|
struct intel_connector;
|
||||||
|
struct intel_crtc_state;
|
||||||
|
struct intel_dp;
|
||||||
|
struct intel_encoder;
|
||||||
|
|
||||||
|
intel_wakeref_t intel_pps_lock(struct intel_dp *intel_dp);
|
||||||
|
intel_wakeref_t intel_pps_unlock(struct intel_dp *intel_dp, intel_wakeref_t wakeref);
|
||||||
|
|
||||||
|
#define with_intel_pps_lock(dp, wf) \
|
||||||
|
for ((wf) = intel_pps_lock(dp); (wf); (wf) = intel_pps_unlock((dp), (wf)))
|
||||||
|
|
||||||
|
void intel_pps_backlight_on(struct intel_dp *intel_dp);
|
||||||
|
void intel_pps_backlight_off(struct intel_dp *intel_dp);
|
||||||
|
void intel_pps_backlight_power(struct intel_connector *connector, bool enable);
|
||||||
|
|
||||||
|
bool intel_pps_vdd_on_unlocked(struct intel_dp *intel_dp);
|
||||||
|
void intel_pps_vdd_off_unlocked(struct intel_dp *intel_dp, bool sync);
|
||||||
|
void intel_pps_on_unlocked(struct intel_dp *intel_dp);
|
||||||
|
void intel_pps_off_unlocked(struct intel_dp *intel_dp);
|
||||||
|
void intel_pps_check_power_unlocked(struct intel_dp *intel_dp);
|
||||||
|
|
||||||
|
void intel_pps_vdd_on(struct intel_dp *intel_dp);
|
||||||
|
void intel_pps_on(struct intel_dp *intel_dp);
|
||||||
|
void intel_pps_off(struct intel_dp *intel_dp);
|
||||||
|
void intel_pps_vdd_off_sync(struct intel_dp *intel_dp);
|
||||||
|
bool intel_pps_have_power(struct intel_dp *intel_dp);
|
||||||
|
void intel_pps_wait_power_cycle(struct intel_dp *intel_dp);
|
||||||
|
|
||||||
|
void intel_pps_init(struct intel_dp *intel_dp);
|
||||||
|
void intel_pps_encoder_reset(struct intel_dp *intel_dp);
|
||||||
|
void intel_pps_reset_all(struct drm_i915_private *i915);
|
||||||
|
|
||||||
|
void vlv_pps_init(struct intel_encoder *encoder,
|
||||||
|
const struct intel_crtc_state *crtc_state);
|
||||||
|
|
||||||
|
void intel_pps_unlock_regs_wa(struct drm_i915_private *i915);
|
||||||
|
void intel_pps_setup(struct drm_i915_private *i915);
|
||||||
|
|
||||||
|
#endif /* __INTEL_PPS_H__ */
|
||||||
@@ -28,9 +28,10 @@
|
|||||||
#include "i915_drv.h"
|
#include "i915_drv.h"
|
||||||
#include "intel_atomic.h"
|
#include "intel_atomic.h"
|
||||||
#include "intel_display_types.h"
|
#include "intel_display_types.h"
|
||||||
|
#include "intel_dp_aux.h"
|
||||||
|
#include "intel_hdmi.h"
|
||||||
#include "intel_psr.h"
|
#include "intel_psr.h"
|
||||||
#include "intel_sprite.h"
|
#include "intel_sprite.h"
|
||||||
#include "intel_hdmi.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOC: Panel Self Refresh (PSR/SRD)
|
* DOC: Panel Self Refresh (PSR/SRD)
|
||||||
@@ -305,7 +306,7 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp)
|
|||||||
drm_dbg_kms(&dev_priv->drm, "eDP panel supports PSR version %x\n",
|
drm_dbg_kms(&dev_priv->drm, "eDP panel supports PSR version %x\n",
|
||||||
intel_dp->psr_dpcd[0]);
|
intel_dp->psr_dpcd[0]);
|
||||||
|
|
||||||
if (drm_dp_has_quirk(&intel_dp->desc, 0, DP_DPCD_QUIRK_NO_PSR)) {
|
if (drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_NO_PSR)) {
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
"PSR support not currently available for this panel\n");
|
"PSR support not currently available for this panel\n");
|
||||||
return;
|
return;
|
||||||
@@ -811,6 +812,13 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
|
|||||||
&crtc_state->hw.adjusted_mode;
|
&crtc_state->hw.adjusted_mode;
|
||||||
int psr_setup_time;
|
int psr_setup_time;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Current PSR panels dont work reliably with VRR enabled
|
||||||
|
* So if VRR is enabled, do not enable PSR.
|
||||||
|
*/
|
||||||
|
if (crtc_state->vrr.enable)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!CAN_PSR(dev_priv))
|
if (!CAN_PSR(dev_priv))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
#include "intel_dsi.h"
|
#include "intel_dsi.h"
|
||||||
#include "intel_sprite.h"
|
#include "intel_sprite.h"
|
||||||
#include "i9xx_plane.h"
|
#include "i9xx_plane.h"
|
||||||
|
#include "intel_vrr.h"
|
||||||
|
|
||||||
int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
|
int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
|
||||||
int usecs)
|
int usecs)
|
||||||
@@ -62,6 +63,16 @@ int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
|
|||||||
1000 * adjusted_mode->crtc_htotal);
|
1000 * adjusted_mode->crtc_htotal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int intel_mode_vblank_start(const struct drm_display_mode *mode)
|
||||||
|
{
|
||||||
|
int vblank_start = mode->crtc_vblank_start;
|
||||||
|
|
||||||
|
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||||
|
vblank_start = DIV_ROUND_UP(vblank_start, 2);
|
||||||
|
|
||||||
|
return vblank_start;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* intel_pipe_update_start() - start update of a set of display registers
|
* intel_pipe_update_start() - start update of a set of display registers
|
||||||
* @new_crtc_state: the new crtc state
|
* @new_crtc_state: the new crtc state
|
||||||
@@ -90,9 +101,10 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state)
|
|||||||
if (new_crtc_state->uapi.async_flip)
|
if (new_crtc_state->uapi.async_flip)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
vblank_start = adjusted_mode->crtc_vblank_start;
|
if (new_crtc_state->vrr.enable)
|
||||||
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
|
vblank_start = intel_vrr_vmax_vblank_start(new_crtc_state);
|
||||||
vblank_start = DIV_ROUND_UP(vblank_start, 2);
|
else
|
||||||
|
vblank_start = intel_mode_vblank_start(adjusted_mode);
|
||||||
|
|
||||||
/* FIXME needs to be calibrated sensibly */
|
/* FIXME needs to be calibrated sensibly */
|
||||||
min = vblank_start - intel_usecs_to_scanlines(adjusted_mode,
|
min = vblank_start - intel_usecs_to_scanlines(adjusted_mode,
|
||||||
@@ -258,6 +270,9 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state)
|
|||||||
|
|
||||||
local_irq_enable();
|
local_irq_enable();
|
||||||
|
|
||||||
|
/* Send VRR Push to terminate Vblank */
|
||||||
|
intel_vrr_send_push(new_crtc_state);
|
||||||
|
|
||||||
if (intel_vgpu_active(dev_priv))
|
if (intel_vgpu_active(dev_priv))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -771,7 +786,8 @@ icl_program_input_csc(struct intel_plane *plane,
|
|||||||
static void
|
static void
|
||||||
skl_plane_async_flip(struct intel_plane *plane,
|
skl_plane_async_flip(struct intel_plane *plane,
|
||||||
const struct intel_crtc_state *crtc_state,
|
const struct intel_crtc_state *crtc_state,
|
||||||
const struct intel_plane_state *plane_state)
|
const struct intel_plane_state *plane_state,
|
||||||
|
bool async_flip)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
@@ -782,6 +798,9 @@ skl_plane_async_flip(struct intel_plane *plane,
|
|||||||
|
|
||||||
plane_ctl |= skl_plane_ctl_crtc(crtc_state);
|
plane_ctl |= skl_plane_ctl_crtc(crtc_state);
|
||||||
|
|
||||||
|
if (async_flip)
|
||||||
|
plane_ctl |= PLANE_CTL_ASYNC_FLIP;
|
||||||
|
|
||||||
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
|
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
|
||||||
|
|
||||||
intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl);
|
intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl);
|
||||||
@@ -867,6 +886,10 @@ skl_program_plane(struct intel_plane *plane,
|
|||||||
if (fb->format->is_yuv && icl_is_hdr_plane(dev_priv, plane_id))
|
if (fb->format->is_yuv && icl_is_hdr_plane(dev_priv, plane_id))
|
||||||
icl_program_input_csc(plane, crtc_state, plane_state);
|
icl_program_input_csc(plane, crtc_state, plane_state);
|
||||||
|
|
||||||
|
if (fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC)
|
||||||
|
intel_uncore_write64_fw(&dev_priv->uncore,
|
||||||
|
PLANE_CC_VAL(pipe, plane_id), plane_state->ccval);
|
||||||
|
|
||||||
skl_write_plane_wm(plane, crtc_state);
|
skl_write_plane_wm(plane, crtc_state);
|
||||||
|
|
||||||
intel_de_write_fw(dev_priv, PLANE_KEYVAL(pipe, plane_id),
|
intel_de_write_fw(dev_priv, PLANE_KEYVAL(pipe, plane_id),
|
||||||
@@ -958,6 +981,28 @@ skl_plane_get_hw_state(struct intel_plane *plane,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
skl_plane_enable_flip_done(struct intel_plane *plane)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *i915 = to_i915(plane->base.dev);
|
||||||
|
enum pipe pipe = plane->pipe;
|
||||||
|
|
||||||
|
spin_lock_irq(&i915->irq_lock);
|
||||||
|
bdw_enable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id));
|
||||||
|
spin_unlock_irq(&i915->irq_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
skl_plane_disable_flip_done(struct intel_plane *plane)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *i915 = to_i915(plane->base.dev);
|
||||||
|
enum pipe pipe = plane->pipe;
|
||||||
|
|
||||||
|
spin_lock_irq(&i915->irq_lock);
|
||||||
|
bdw_disable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id));
|
||||||
|
spin_unlock_irq(&i915->irq_lock);
|
||||||
|
}
|
||||||
|
|
||||||
static void i9xx_plane_linear_gamma(u16 gamma[8])
|
static void i9xx_plane_linear_gamma(u16 gamma[8])
|
||||||
{
|
{
|
||||||
/* The points are not evenly spaced. */
|
/* The points are not evenly spaced. */
|
||||||
@@ -2366,7 +2411,8 @@ static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state,
|
|||||||
fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
|
fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
|
||||||
fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
|
fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
|
||||||
fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
|
fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
|
||||||
fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS)) {
|
fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ||
|
||||||
|
fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC)) {
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
"Y/Yf tiling not supported in IF-ID mode\n");
|
"Y/Yf tiling not supported in IF-ID mode\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -2856,6 +2902,7 @@ static const u64 skl_plane_format_modifiers_ccs[] = {
|
|||||||
static const u64 gen12_plane_format_modifiers_mc_ccs[] = {
|
static const u64 gen12_plane_format_modifiers_mc_ccs[] = {
|
||||||
I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
|
I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
|
||||||
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
|
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
|
||||||
|
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC,
|
||||||
I915_FORMAT_MOD_Y_TILED,
|
I915_FORMAT_MOD_Y_TILED,
|
||||||
I915_FORMAT_MOD_X_TILED,
|
I915_FORMAT_MOD_X_TILED,
|
||||||
DRM_FORMAT_MOD_LINEAR,
|
DRM_FORMAT_MOD_LINEAR,
|
||||||
@@ -2864,6 +2911,7 @@ static const u64 gen12_plane_format_modifiers_mc_ccs[] = {
|
|||||||
|
|
||||||
static const u64 gen12_plane_format_modifiers_rc_ccs[] = {
|
static const u64 gen12_plane_format_modifiers_rc_ccs[] = {
|
||||||
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
|
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
|
||||||
|
I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC,
|
||||||
I915_FORMAT_MOD_Y_TILED,
|
I915_FORMAT_MOD_Y_TILED,
|
||||||
I915_FORMAT_MOD_X_TILED,
|
I915_FORMAT_MOD_X_TILED,
|
||||||
DRM_FORMAT_MOD_LINEAR,
|
DRM_FORMAT_MOD_LINEAR,
|
||||||
@@ -3054,6 +3102,7 @@ static bool gen12_plane_format_mod_supported(struct drm_plane *_plane,
|
|||||||
case I915_FORMAT_MOD_X_TILED:
|
case I915_FORMAT_MOD_X_TILED:
|
||||||
case I915_FORMAT_MOD_Y_TILED:
|
case I915_FORMAT_MOD_Y_TILED:
|
||||||
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
|
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
|
||||||
|
case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@@ -3290,7 +3339,13 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv,
|
|||||||
plane->get_hw_state = skl_plane_get_hw_state;
|
plane->get_hw_state = skl_plane_get_hw_state;
|
||||||
plane->check_plane = skl_plane_check;
|
plane->check_plane = skl_plane_check;
|
||||||
plane->min_cdclk = skl_plane_min_cdclk;
|
plane->min_cdclk = skl_plane_min_cdclk;
|
||||||
plane->async_flip = skl_plane_async_flip;
|
|
||||||
|
if (plane_id == PLANE_PRIMARY) {
|
||||||
|
plane->need_async_flip_disable_wa = IS_GEN_RANGE(dev_priv, 9, 10);
|
||||||
|
plane->async_flip = skl_plane_async_flip;
|
||||||
|
plane->enable_flip_done = skl_plane_enable_flip_done;
|
||||||
|
plane->disable_flip_done = skl_plane_disable_flip_done;
|
||||||
|
}
|
||||||
|
|
||||||
if (INTEL_GEN(dev_priv) >= 11)
|
if (INTEL_GEN(dev_priv) >= 11)
|
||||||
formats = icl_get_plane_formats(dev_priv, pipe,
|
formats = icl_get_plane_formats(dev_priv, pipe,
|
||||||
|
|||||||
209
drivers/gpu/drm/i915/display/intel_vrr.c
Normal file
209
drivers/gpu/drm/i915/display/intel_vrr.c
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
/*
|
||||||
|
* Copyright © 2020 Intel Corporation
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "i915_drv.h"
|
||||||
|
#include "intel_display_types.h"
|
||||||
|
#include "intel_vrr.h"
|
||||||
|
|
||||||
|
bool intel_vrr_is_capable(struct drm_connector *connector)
|
||||||
|
{
|
||||||
|
struct intel_dp *intel_dp;
|
||||||
|
const struct drm_display_info *info = &connector->display_info;
|
||||||
|
struct drm_i915_private *i915 = to_i915(connector->dev);
|
||||||
|
|
||||||
|
if (connector->connector_type != DRM_MODE_CONNECTOR_eDP &&
|
||||||
|
connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
intel_dp = intel_attached_dp(to_intel_connector(connector));
|
||||||
|
/*
|
||||||
|
* DP Sink is capable of VRR video timings if
|
||||||
|
* Ignore MSA bit is set in DPCD.
|
||||||
|
* EDID monitor range also should be atleast 10 for reasonable
|
||||||
|
* Adaptive Sync or Variable Refresh Rate end user experience.
|
||||||
|
*/
|
||||||
|
return HAS_VRR(i915) &&
|
||||||
|
drm_dp_sink_can_do_video_without_timing_msa(intel_dp->dpcd) &&
|
||||||
|
info->monitor_range.max_vfreq - info->monitor_range.min_vfreq > 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
intel_vrr_check_modeset(struct intel_atomic_state *state)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct intel_crtc_state *old_crtc_state, *new_crtc_state;
|
||||||
|
struct intel_crtc *crtc;
|
||||||
|
|
||||||
|
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
|
||||||
|
new_crtc_state, i) {
|
||||||
|
if (new_crtc_state->uapi.vrr_enabled !=
|
||||||
|
old_crtc_state->uapi.vrr_enabled)
|
||||||
|
new_crtc_state->uapi.mode_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Without VRR registers get latched at:
|
||||||
|
* vblank_start
|
||||||
|
*
|
||||||
|
* With VRR the earliest registers can get latched is:
|
||||||
|
* intel_vrr_vmin_vblank_start(), which if we want to maintain
|
||||||
|
* the correct min vtotal is >=vblank_start+1
|
||||||
|
*
|
||||||
|
* The latest point registers can get latched is the vmax decision boundary:
|
||||||
|
* intel_vrr_vmax_vblank_start()
|
||||||
|
*
|
||||||
|
* Between those two points the vblank exit starts (and hence registers get
|
||||||
|
* latched) ASAP after a push is sent.
|
||||||
|
*
|
||||||
|
* framestart_delay is programmable 0-3.
|
||||||
|
*/
|
||||||
|
static int intel_vrr_vblank_exit_length(const struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||||
|
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
|
||||||
|
|
||||||
|
/* The hw imposes the extra scanline before frame start */
|
||||||
|
return crtc_state->vrr.pipeline_full + i915->framestart_delay + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int intel_vrr_vmin_vblank_start(const struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
/* Min vblank actually determined by flipline that is always >=vmin+1 */
|
||||||
|
return crtc_state->vrr.vmin + 1 - intel_vrr_vblank_exit_length(crtc_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
int intel_vrr_vmax_vblank_start(const struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
return crtc_state->vrr.vmax - intel_vrr_vblank_exit_length(crtc_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
intel_vrr_compute_config(struct intel_crtc_state *crtc_state,
|
||||||
|
struct drm_connector_state *conn_state)
|
||||||
|
{
|
||||||
|
struct intel_connector *connector =
|
||||||
|
to_intel_connector(conn_state->connector);
|
||||||
|
struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
|
||||||
|
const struct drm_display_info *info = &connector->base.display_info;
|
||||||
|
int vmin, vmax;
|
||||||
|
|
||||||
|
if (!intel_vrr_is_capable(&connector->base))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!crtc_state->uapi.vrr_enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vmin = DIV_ROUND_UP(adjusted_mode->crtc_clock * 1000,
|
||||||
|
adjusted_mode->crtc_htotal * info->monitor_range.max_vfreq);
|
||||||
|
vmax = adjusted_mode->crtc_clock * 1000 /
|
||||||
|
(adjusted_mode->crtc_htotal * info->monitor_range.min_vfreq);
|
||||||
|
|
||||||
|
vmin = max_t(int, vmin, adjusted_mode->crtc_vtotal);
|
||||||
|
vmax = max_t(int, vmax, adjusted_mode->crtc_vtotal);
|
||||||
|
|
||||||
|
if (vmin >= vmax)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* flipline determines the min vblank length the hardware will
|
||||||
|
* generate, and flipline>=vmin+1, hence we reduce vmin by one
|
||||||
|
* to make sure we can get the actual min vblank length.
|
||||||
|
*/
|
||||||
|
crtc_state->vrr.vmin = vmin - 1;
|
||||||
|
crtc_state->vrr.vmax = vmax;
|
||||||
|
crtc_state->vrr.enable = true;
|
||||||
|
|
||||||
|
crtc_state->vrr.flipline = crtc_state->vrr.vmin + 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: s/4/framestart_delay+1/ to get consistent
|
||||||
|
* earliest/latest points for register latching regardless
|
||||||
|
* of the framestart_delay used?
|
||||||
|
*
|
||||||
|
* FIXME: this really needs the extra scanline to provide consistent
|
||||||
|
* behaviour for all framestart_delay values. Otherwise with
|
||||||
|
* framestart_delay==3 we will end up extending the min vblank by
|
||||||
|
* one extra line.
|
||||||
|
*/
|
||||||
|
crtc_state->vrr.pipeline_full =
|
||||||
|
min(255, crtc_state->vrr.vmin - adjusted_mode->crtc_vdisplay - 4 - 1);
|
||||||
|
|
||||||
|
crtc_state->mode_flags |= I915_MODE_FLAG_VRR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void intel_vrr_enable(struct intel_encoder *encoder,
|
||||||
|
const struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||||
|
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
|
||||||
|
u32 trans_vrr_ctl;
|
||||||
|
|
||||||
|
if (!crtc_state->vrr.enable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
trans_vrr_ctl = VRR_CTL_VRR_ENABLE |
|
||||||
|
VRR_CTL_IGN_MAX_SHIFT | VRR_CTL_FLIP_LINE_EN |
|
||||||
|
VRR_CTL_PIPELINE_FULL(crtc_state->vrr.pipeline_full) |
|
||||||
|
VRR_CTL_PIPELINE_FULL_OVERRIDE;
|
||||||
|
|
||||||
|
intel_de_write(dev_priv, TRANS_VRR_VMIN(cpu_transcoder), crtc_state->vrr.vmin - 1);
|
||||||
|
intel_de_write(dev_priv, TRANS_VRR_VMAX(cpu_transcoder), crtc_state->vrr.vmax - 1);
|
||||||
|
intel_de_write(dev_priv, TRANS_VRR_CTL(cpu_transcoder), trans_vrr_ctl);
|
||||||
|
intel_de_write(dev_priv, TRANS_VRR_FLIPLINE(cpu_transcoder), crtc_state->vrr.flipline - 1);
|
||||||
|
intel_de_write(dev_priv, TRANS_PUSH(cpu_transcoder), TRANS_PUSH_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void intel_vrr_send_push(const struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||||
|
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
|
||||||
|
|
||||||
|
if (!crtc_state->vrr.enable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
intel_de_write(dev_priv, TRANS_PUSH(cpu_transcoder),
|
||||||
|
TRANS_PUSH_EN | TRANS_PUSH_SEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state)
|
||||||
|
{
|
||||||
|
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||||
|
enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;
|
||||||
|
|
||||||
|
if (!old_crtc_state->vrr.enable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
intel_de_write(dev_priv, TRANS_VRR_CTL(cpu_transcoder), 0);
|
||||||
|
intel_de_write(dev_priv, TRANS_PUSH(cpu_transcoder), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void intel_vrr_get_config(struct intel_crtc *crtc,
|
||||||
|
struct intel_crtc_state *crtc_state)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||||
|
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
|
||||||
|
u32 trans_vrr_ctl;
|
||||||
|
|
||||||
|
trans_vrr_ctl = intel_de_read(dev_priv, TRANS_VRR_CTL(cpu_transcoder));
|
||||||
|
crtc_state->vrr.enable = trans_vrr_ctl & VRR_CTL_VRR_ENABLE;
|
||||||
|
if (!crtc_state->vrr.enable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (trans_vrr_ctl & VRR_CTL_PIPELINE_FULL_OVERRIDE)
|
||||||
|
crtc_state->vrr.pipeline_full = REG_FIELD_GET(VRR_CTL_PIPELINE_FULL_MASK, trans_vrr_ctl);
|
||||||
|
if (trans_vrr_ctl & VRR_CTL_FLIP_LINE_EN)
|
||||||
|
crtc_state->vrr.flipline = intel_de_read(dev_priv, TRANS_VRR_FLIPLINE(cpu_transcoder)) + 1;
|
||||||
|
crtc_state->vrr.vmax = intel_de_read(dev_priv, TRANS_VRR_VMAX(cpu_transcoder)) + 1;
|
||||||
|
crtc_state->vrr.vmin = intel_de_read(dev_priv, TRANS_VRR_VMIN(cpu_transcoder)) + 1;
|
||||||
|
|
||||||
|
crtc_state->mode_flags |= I915_MODE_FLAG_VRR;
|
||||||
|
}
|
||||||
33
drivers/gpu/drm/i915/display/intel_vrr.h
Normal file
33
drivers/gpu/drm/i915/display/intel_vrr.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
/*
|
||||||
|
* Copyright © 2019 Intel Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __INTEL_VRR_H__
|
||||||
|
#define __INTEL_VRR_H__
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
struct drm_connector;
|
||||||
|
struct drm_connector_state;
|
||||||
|
struct intel_atomic_state;
|
||||||
|
struct intel_crtc;
|
||||||
|
struct intel_crtc_state;
|
||||||
|
struct intel_dp;
|
||||||
|
struct intel_encoder;
|
||||||
|
struct intel_crtc;
|
||||||
|
|
||||||
|
bool intel_vrr_is_capable(struct drm_connector *connector);
|
||||||
|
void intel_vrr_check_modeset(struct intel_atomic_state *state);
|
||||||
|
void intel_vrr_compute_config(struct intel_crtc_state *crtc_state,
|
||||||
|
struct drm_connector_state *conn_state);
|
||||||
|
void intel_vrr_enable(struct intel_encoder *encoder,
|
||||||
|
const struct intel_crtc_state *crtc_state);
|
||||||
|
void intel_vrr_send_push(const struct intel_crtc_state *crtc_state);
|
||||||
|
void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state);
|
||||||
|
void intel_vrr_get_config(struct intel_crtc *crtc,
|
||||||
|
struct intel_crtc_state *crtc_state);
|
||||||
|
int intel_vrr_vmax_vblank_start(const struct intel_crtc_state *crtc_state);
|
||||||
|
int intel_vrr_vmin_vblank_start(const struct intel_crtc_state *crtc_state);
|
||||||
|
|
||||||
|
#endif /* __INTEL_VRR_H__ */
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "i915_gem_mman.h"
|
#include "i915_gem_mman.h"
|
||||||
#include "i915_gem_object.h"
|
#include "i915_gem_object.h"
|
||||||
#include "i915_globals.h"
|
#include "i915_globals.h"
|
||||||
|
#include "i915_memcpy.h"
|
||||||
#include "i915_trace.h"
|
#include "i915_trace.h"
|
||||||
|
|
||||||
static struct i915_global_object {
|
static struct i915_global_object {
|
||||||
@@ -336,6 +337,70 @@ void __i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
i915_gem_object_read_from_page_kmap(struct drm_i915_gem_object *obj, u64 offset, void *dst, int size)
|
||||||
|
{
|
||||||
|
void *src_map;
|
||||||
|
void *src_ptr;
|
||||||
|
|
||||||
|
src_map = kmap_atomic(i915_gem_object_get_page(obj, offset >> PAGE_SHIFT));
|
||||||
|
|
||||||
|
src_ptr = src_map + offset_in_page(offset);
|
||||||
|
if (!(obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_READ))
|
||||||
|
drm_clflush_virt_range(src_ptr, size);
|
||||||
|
memcpy(dst, src_ptr, size);
|
||||||
|
|
||||||
|
kunmap_atomic(src_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
i915_gem_object_read_from_page_iomap(struct drm_i915_gem_object *obj, u64 offset, void *dst, int size)
|
||||||
|
{
|
||||||
|
void __iomem *src_map;
|
||||||
|
void __iomem *src_ptr;
|
||||||
|
dma_addr_t dma = i915_gem_object_get_dma_address(obj, offset >> PAGE_SHIFT);
|
||||||
|
|
||||||
|
src_map = io_mapping_map_wc(&obj->mm.region->iomap,
|
||||||
|
dma - obj->mm.region->region.start,
|
||||||
|
PAGE_SIZE);
|
||||||
|
|
||||||
|
src_ptr = src_map + offset_in_page(offset);
|
||||||
|
if (!i915_memcpy_from_wc(dst, (void __force *)src_ptr, size))
|
||||||
|
memcpy_fromio(dst, src_ptr, size);
|
||||||
|
|
||||||
|
io_mapping_unmap(src_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i915_gem_object_read_from_page - read data from the page of a GEM object
|
||||||
|
* @obj: GEM object to read from
|
||||||
|
* @offset: offset within the object
|
||||||
|
* @dst: buffer to store the read data
|
||||||
|
* @size: size to read
|
||||||
|
*
|
||||||
|
* Reads data from @obj at the specified offset. The requested region to read
|
||||||
|
* from can't cross a page boundary. The caller must ensure that @obj pages
|
||||||
|
* are pinned and that @obj is synced wrt. any related writes.
|
||||||
|
*
|
||||||
|
* Returns 0 on success or -ENODEV if the type of @obj's backing store is
|
||||||
|
* unsupported.
|
||||||
|
*/
|
||||||
|
int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset, void *dst, int size)
|
||||||
|
{
|
||||||
|
GEM_BUG_ON(offset >= obj->base.size);
|
||||||
|
GEM_BUG_ON(offset_in_page(offset) > PAGE_SIZE - size);
|
||||||
|
GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
|
||||||
|
|
||||||
|
if (i915_gem_object_has_struct_page(obj))
|
||||||
|
i915_gem_object_read_from_page_kmap(obj, offset, dst, size);
|
||||||
|
else if (i915_gem_object_has_iomem(obj))
|
||||||
|
i915_gem_object_read_from_page_iomap(obj, offset, dst, size);
|
||||||
|
else
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void i915_gem_init__objects(struct drm_i915_private *i915)
|
void i915_gem_init__objects(struct drm_i915_private *i915)
|
||||||
{
|
{
|
||||||
INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
|
INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
|
||||||
|
|||||||
@@ -218,6 +218,12 @@ i915_gem_object_has_struct_page(const struct drm_i915_gem_object *obj)
|
|||||||
return i915_gem_object_type_has(obj, I915_GEM_OBJECT_HAS_STRUCT_PAGE);
|
return i915_gem_object_type_has(obj, I915_GEM_OBJECT_HAS_STRUCT_PAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
i915_gem_object_has_iomem(const struct drm_i915_gem_object *obj)
|
||||||
|
{
|
||||||
|
return i915_gem_object_type_has(obj, I915_GEM_OBJECT_HAS_IOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
i915_gem_object_is_shrinkable(const struct drm_i915_gem_object *obj)
|
i915_gem_object_is_shrinkable(const struct drm_i915_gem_object *obj)
|
||||||
{
|
{
|
||||||
@@ -548,6 +554,8 @@ i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj,
|
|||||||
__i915_gem_object_invalidate_frontbuffer(obj, origin);
|
__i915_gem_object_invalidate_frontbuffer(obj, origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset, void *dst, int size);
|
||||||
|
|
||||||
bool i915_gem_object_is_shmem(const struct drm_i915_gem_object *obj);
|
bool i915_gem_object_is_shmem(const struct drm_i915_gem_object *obj);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -58,6 +58,7 @@
|
|||||||
#include "display/intel_hotplug.h"
|
#include "display/intel_hotplug.h"
|
||||||
#include "display/intel_overlay.h"
|
#include "display/intel_overlay.h"
|
||||||
#include "display/intel_pipe_crc.h"
|
#include "display/intel_pipe_crc.h"
|
||||||
|
#include "display/intel_pps.h"
|
||||||
#include "display/intel_sprite.h"
|
#include "display/intel_sprite.h"
|
||||||
#include "display/intel_vga.h"
|
#include "display/intel_vga.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1122,15 +1122,6 @@ struct drm_i915_private {
|
|||||||
* crtc_state->wm.need_postvbl_update.
|
* crtc_state->wm.need_postvbl_update.
|
||||||
*/
|
*/
|
||||||
struct mutex wm_mutex;
|
struct mutex wm_mutex;
|
||||||
|
|
||||||
/*
|
|
||||||
* Set during HW readout of watermarks/DDB. Some platforms
|
|
||||||
* need to know when we're still using BIOS-provided values
|
|
||||||
* (which we don't fully trust).
|
|
||||||
*
|
|
||||||
* FIXME get rid of this.
|
|
||||||
*/
|
|
||||||
bool distrust_bios_wm;
|
|
||||||
} wm;
|
} wm;
|
||||||
|
|
||||||
struct dram_info {
|
struct dram_info {
|
||||||
@@ -1182,6 +1173,8 @@ struct drm_i915_private {
|
|||||||
struct file *mmap_singleton;
|
struct file *mmap_singleton;
|
||||||
} gem;
|
} gem;
|
||||||
|
|
||||||
|
u8 framestart_delay;
|
||||||
|
|
||||||
u8 pch_ssc_use;
|
u8 pch_ssc_use;
|
||||||
|
|
||||||
/* For i915gm/i945gm vblank irq workaround */
|
/* For i915gm/i945gm vblank irq workaround */
|
||||||
@@ -1758,10 +1751,17 @@ tgl_revids_get(struct drm_i915_private *dev_priv)
|
|||||||
|
|
||||||
#define HAS_DISPLAY(dev_priv) (INTEL_INFO(dev_priv)->pipe_mask != 0)
|
#define HAS_DISPLAY(dev_priv) (INTEL_INFO(dev_priv)->pipe_mask != 0)
|
||||||
|
|
||||||
|
#define HAS_VRR(i915) (INTEL_GEN(i915) >= 12)
|
||||||
|
|
||||||
/* Only valid when HAS_DISPLAY() is true */
|
/* Only valid when HAS_DISPLAY() is true */
|
||||||
#define INTEL_DISPLAY_ENABLED(dev_priv) \
|
#define INTEL_DISPLAY_ENABLED(dev_priv) \
|
||||||
(drm_WARN_ON(&(dev_priv)->drm, !HAS_DISPLAY(dev_priv)), !(dev_priv)->params.disable_display)
|
(drm_WARN_ON(&(dev_priv)->drm, !HAS_DISPLAY(dev_priv)), !(dev_priv)->params.disable_display)
|
||||||
|
|
||||||
|
static inline bool run_as_guest(void)
|
||||||
|
{
|
||||||
|
return !hypervisor_is_type(X86_HYPER_NATIVE);
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool intel_vtd_active(void)
|
static inline bool intel_vtd_active(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_INTEL_IOMMU
|
#ifdef CONFIG_INTEL_IOMMU
|
||||||
@@ -1770,7 +1770,7 @@ static inline bool intel_vtd_active(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Running as a guest, we assume the host is enforcing VT'd */
|
/* Running as a guest, we assume the host is enforcing VT'd */
|
||||||
return !hypervisor_is_type(X86_HYPER_NATIVE);
|
return run_as_guest();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool intel_scanout_needs_vtd_wa(struct drm_i915_private *dev_priv)
|
static inline bool intel_scanout_needs_vtd_wa(struct drm_i915_private *dev_priv)
|
||||||
|
|||||||
@@ -718,25 +718,15 @@ u32 g4x_get_vblank_counter(struct drm_crtc *crtc)
|
|||||||
return intel_uncore_read(&dev_priv->uncore, PIPE_FRMCOUNT_G4X(pipe));
|
return intel_uncore_read(&dev_priv->uncore, PIPE_FRMCOUNT_G4X(pipe));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static u32 intel_crtc_scanlines_since_frame_timestamp(struct intel_crtc *crtc)
|
||||||
* On certain encoders on certain platforms, pipe
|
|
||||||
* scanline register will not work to get the scanline,
|
|
||||||
* since the timings are driven from the PORT or issues
|
|
||||||
* with scanline register updates.
|
|
||||||
* This function will use Framestamp and current
|
|
||||||
* timestamp registers to calculate the scanline.
|
|
||||||
*/
|
|
||||||
static u32 __intel_get_crtc_scanline_from_timestamp(struct intel_crtc *crtc)
|
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||||
struct drm_vblank_crtc *vblank =
|
struct drm_vblank_crtc *vblank =
|
||||||
&crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
|
&crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
|
||||||
const struct drm_display_mode *mode = &vblank->hwmode;
|
const struct drm_display_mode *mode = &vblank->hwmode;
|
||||||
u32 vblank_start = mode->crtc_vblank_start;
|
|
||||||
u32 vtotal = mode->crtc_vtotal;
|
|
||||||
u32 htotal = mode->crtc_htotal;
|
u32 htotal = mode->crtc_htotal;
|
||||||
u32 clock = mode->crtc_clock;
|
u32 clock = mode->crtc_clock;
|
||||||
u32 scanline, scan_prev_time, scan_curr_time, scan_post_time;
|
u32 scan_prev_time, scan_curr_time, scan_post_time;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To avoid the race condition where we might cross into the
|
* To avoid the race condition where we might cross into the
|
||||||
@@ -763,8 +753,28 @@ static u32 __intel_get_crtc_scanline_from_timestamp(struct intel_crtc *crtc)
|
|||||||
PIPE_FRMTMSTMP(crtc->pipe));
|
PIPE_FRMTMSTMP(crtc->pipe));
|
||||||
} while (scan_post_time != scan_prev_time);
|
} while (scan_post_time != scan_prev_time);
|
||||||
|
|
||||||
scanline = div_u64(mul_u32_u32(scan_curr_time - scan_prev_time,
|
return div_u64(mul_u32_u32(scan_curr_time - scan_prev_time,
|
||||||
clock), 1000 * htotal);
|
clock), 1000 * htotal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On certain encoders on certain platforms, pipe
|
||||||
|
* scanline register will not work to get the scanline,
|
||||||
|
* since the timings are driven from the PORT or issues
|
||||||
|
* with scanline register updates.
|
||||||
|
* This function will use Framestamp and current
|
||||||
|
* timestamp registers to calculate the scanline.
|
||||||
|
*/
|
||||||
|
static u32 __intel_get_crtc_scanline_from_timestamp(struct intel_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct drm_vblank_crtc *vblank =
|
||||||
|
&crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
|
||||||
|
const struct drm_display_mode *mode = &vblank->hwmode;
|
||||||
|
u32 vblank_start = mode->crtc_vblank_start;
|
||||||
|
u32 vtotal = mode->crtc_vtotal;
|
||||||
|
u32 scanline;
|
||||||
|
|
||||||
|
scanline = intel_crtc_scanlines_since_frame_timestamp(crtc);
|
||||||
scanline = min(scanline, vtotal - 1);
|
scanline = min(scanline, vtotal - 1);
|
||||||
scanline = (scanline + vblank_start) % vtotal;
|
scanline = (scanline + vblank_start) % vtotal;
|
||||||
|
|
||||||
@@ -883,7 +893,20 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc,
|
|||||||
if (stime)
|
if (stime)
|
||||||
*stime = ktime_get();
|
*stime = ktime_get();
|
||||||
|
|
||||||
if (use_scanline_counter) {
|
if (crtc->mode_flags & I915_MODE_FLAG_VRR) {
|
||||||
|
int scanlines = intel_crtc_scanlines_since_frame_timestamp(crtc);
|
||||||
|
|
||||||
|
position = __intel_get_crtc_scanline(crtc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Already exiting vblank? If so, shift our position
|
||||||
|
* so it looks like we're already apporaching the full
|
||||||
|
* vblank end. This should make the generated timestamp
|
||||||
|
* more or less match when the active portion will start.
|
||||||
|
*/
|
||||||
|
if (position >= vbl_start && scanlines < position)
|
||||||
|
position = min(crtc->vmax_vblank_start + scanlines, vtotal - 1);
|
||||||
|
} else if (use_scanline_counter) {
|
||||||
/* No obvious pixelcount register. Only query vertical
|
/* No obvious pixelcount register. Only query vertical
|
||||||
* scanout position from Display scan line register.
|
* scanout position from Display scan line register.
|
||||||
*/
|
*/
|
||||||
@@ -2079,7 +2102,7 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
|
|||||||
intel_opregion_asle_intr(dev_priv);
|
intel_opregion_asle_intr(dev_priv);
|
||||||
|
|
||||||
for_each_pipe(dev_priv, pipe) {
|
for_each_pipe(dev_priv, pipe) {
|
||||||
if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
|
if (de_iir & DE_PIPE_VBLANK_IVB(pipe))
|
||||||
intel_handle_vblank(dev_priv, pipe);
|
intel_handle_vblank(dev_priv, pipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2822,19 +2845,6 @@ int bdw_enable_vblank(struct drm_crtc *crtc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void skl_enable_flip_done(struct intel_crtc *crtc)
|
|
||||||
{
|
|
||||||
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
|
|
||||||
enum pipe pipe = crtc->pipe;
|
|
||||||
unsigned long irqflags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&i915->irq_lock, irqflags);
|
|
||||||
|
|
||||||
bdw_enable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE1_FLIP_DONE);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&i915->irq_lock, irqflags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Called from drm generic code, passed 'crtc' which
|
/* Called from drm generic code, passed 'crtc' which
|
||||||
* we use as a pipe index
|
* we use as a pipe index
|
||||||
*/
|
*/
|
||||||
@@ -2899,19 +2909,6 @@ void bdw_disable_vblank(struct drm_crtc *crtc)
|
|||||||
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
|
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void skl_disable_flip_done(struct intel_crtc *crtc)
|
|
||||||
{
|
|
||||||
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
|
|
||||||
enum pipe pipe = crtc->pipe;
|
|
||||||
unsigned long irqflags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&i915->irq_lock, irqflags);
|
|
||||||
|
|
||||||
bdw_disable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE1_FLIP_DONE);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&i915->irq_lock, irqflags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ibx_irq_reset(struct drm_i915_private *dev_priv)
|
static void ibx_irq_reset(struct drm_i915_private *dev_priv)
|
||||||
{
|
{
|
||||||
struct intel_uncore *uncore = &dev_priv->uncore;
|
struct intel_uncore *uncore = &dev_priv->uncore;
|
||||||
|
|||||||
@@ -118,9 +118,6 @@ void i965_disable_vblank(struct drm_crtc *crtc);
|
|||||||
void ilk_disable_vblank(struct drm_crtc *crtc);
|
void ilk_disable_vblank(struct drm_crtc *crtc);
|
||||||
void bdw_disable_vblank(struct drm_crtc *crtc);
|
void bdw_disable_vblank(struct drm_crtc *crtc);
|
||||||
|
|
||||||
void skl_enable_flip_done(struct intel_crtc *crtc);
|
|
||||||
void skl_disable_flip_done(struct intel_crtc *crtc);
|
|
||||||
|
|
||||||
void gen2_irq_reset(struct intel_uncore *uncore);
|
void gen2_irq_reset(struct intel_uncore *uncore);
|
||||||
void gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr,
|
void gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr,
|
||||||
i915_reg_t iir, i915_reg_t ier);
|
i915_reg_t iir, i915_reg_t ier);
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ i915_param_named_unsafe(inject_probe_failure, uint, 0400,
|
|||||||
|
|
||||||
i915_param_named(enable_dpcd_backlight, int, 0400,
|
i915_param_named(enable_dpcd_backlight, int, 0400,
|
||||||
"Enable support for DPCD backlight control"
|
"Enable support for DPCD backlight control"
|
||||||
"(-1=use per-VBT LFP backlight type setting [default], 0=disabled, 1=enabled)");
|
"(-1=use per-VBT LFP backlight type setting [default], 0=disabled, 1=enable, 2=force VESA interface, 3=force Intel interface)");
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_DRM_I915_GVT)
|
#if IS_ENABLED(CONFIG_DRM_I915_GVT)
|
||||||
i915_param_named(enable_gvt, bool, 0400,
|
i915_param_named(enable_gvt, bool, 0400,
|
||||||
|
|||||||
@@ -4346,13 +4346,13 @@ enum {
|
|||||||
#define _TRANS_VRR_CTL_B 0x61420
|
#define _TRANS_VRR_CTL_B 0x61420
|
||||||
#define _TRANS_VRR_CTL_C 0x62420
|
#define _TRANS_VRR_CTL_C 0x62420
|
||||||
#define _TRANS_VRR_CTL_D 0x63420
|
#define _TRANS_VRR_CTL_D 0x63420
|
||||||
#define TRANS_VRR_CTL(trans) _MMIO_TRANS2(trans, _TRANS_VRR_CTL_A)
|
#define TRANS_VRR_CTL(trans) _MMIO_TRANS2(trans, _TRANS_VRR_CTL_A)
|
||||||
#define VRR_CTL_VRR_ENABLE REG_BIT(31)
|
#define VRR_CTL_VRR_ENABLE REG_BIT(31)
|
||||||
#define VRR_CTL_IGN_MAX_SHIFT REG_BIT(30)
|
#define VRR_CTL_IGN_MAX_SHIFT REG_BIT(30)
|
||||||
#define VRR_CTL_FLIP_LINE_EN REG_BIT(29)
|
#define VRR_CTL_FLIP_LINE_EN REG_BIT(29)
|
||||||
#define VRR_CTL_LINE_COUNT_MASK REG_GENMASK(10, 3)
|
#define VRR_CTL_PIPELINE_FULL_MASK REG_GENMASK(10, 3)
|
||||||
#define VRR_CTL_LINE_COUNT(x) REG_FIELD_PREP(VRR_CTL_LINE_COUNT_MASK, (x))
|
#define VRR_CTL_PIPELINE_FULL(x) REG_FIELD_PREP(VRR_CTL_PIPELINE_FULL_MASK, (x))
|
||||||
#define VRR_CTL_SW_FULLLINE_COUNT REG_BIT(0)
|
#define VRR_CTL_PIPELINE_FULL_OVERRIDE REG_BIT(0)
|
||||||
|
|
||||||
#define _TRANS_VRR_VMAX_A 0x60424
|
#define _TRANS_VRR_VMAX_A 0x60424
|
||||||
#define _TRANS_VRR_VMAX_B 0x61424
|
#define _TRANS_VRR_VMAX_B 0x61424
|
||||||
@@ -7070,6 +7070,8 @@ enum {
|
|||||||
#define _PLANE_KEYMAX_1_A 0x701a0
|
#define _PLANE_KEYMAX_1_A 0x701a0
|
||||||
#define _PLANE_KEYMAX_2_A 0x702a0
|
#define _PLANE_KEYMAX_2_A 0x702a0
|
||||||
#define PLANE_KEYMAX_ALPHA(a) ((a) << 24)
|
#define PLANE_KEYMAX_ALPHA(a) ((a) << 24)
|
||||||
|
#define _PLANE_CC_VAL_1_A 0x701b4
|
||||||
|
#define _PLANE_CC_VAL_2_A 0x702b4
|
||||||
#define _PLANE_AUX_DIST_1_A 0x701c0
|
#define _PLANE_AUX_DIST_1_A 0x701c0
|
||||||
#define _PLANE_AUX_DIST_2_A 0x702c0
|
#define _PLANE_AUX_DIST_2_A 0x702c0
|
||||||
#define _PLANE_AUX_OFFSET_1_A 0x701c4
|
#define _PLANE_AUX_OFFSET_1_A 0x701c4
|
||||||
@@ -7111,6 +7113,13 @@ enum {
|
|||||||
#define _PLANE_NV12_BUF_CFG_1_A 0x70278
|
#define _PLANE_NV12_BUF_CFG_1_A 0x70278
|
||||||
#define _PLANE_NV12_BUF_CFG_2_A 0x70378
|
#define _PLANE_NV12_BUF_CFG_2_A 0x70378
|
||||||
|
|
||||||
|
#define _PLANE_CC_VAL_1_B 0x711b4
|
||||||
|
#define _PLANE_CC_VAL_2_B 0x712b4
|
||||||
|
#define _PLANE_CC_VAL_1(pipe) _PIPE(pipe, _PLANE_CC_VAL_1_A, _PLANE_CC_VAL_1_B)
|
||||||
|
#define _PLANE_CC_VAL_2(pipe) _PIPE(pipe, _PLANE_CC_VAL_2_A, _PLANE_CC_VAL_2_B)
|
||||||
|
#define PLANE_CC_VAL(pipe, plane) \
|
||||||
|
_MMIO_PLANE(plane, _PLANE_CC_VAL_1(pipe), _PLANE_CC_VAL_2(pipe))
|
||||||
|
|
||||||
/* Input CSC Register Definitions */
|
/* Input CSC Register Definitions */
|
||||||
#define _PLANE_INPUT_CSC_RY_GY_1_A 0x701E0
|
#define _PLANE_INPUT_CSC_RY_GY_1_A 0x701E0
|
||||||
#define _PLANE_INPUT_CSC_RY_GY_2_A 0x702E0
|
#define _PLANE_INPUT_CSC_RY_GY_2_A 0x702E0
|
||||||
@@ -9872,6 +9881,7 @@ enum skl_power_gate {
|
|||||||
_PORTD_HDCP2_BASE, \
|
_PORTD_HDCP2_BASE, \
|
||||||
_PORTE_HDCP2_BASE, \
|
_PORTE_HDCP2_BASE, \
|
||||||
_PORTF_HDCP2_BASE) + (x))
|
_PORTF_HDCP2_BASE) + (x))
|
||||||
|
|
||||||
#define PORT_HDCP2_AUTH(port) _PORT_HDCP2_BASE(port, 0x98)
|
#define PORT_HDCP2_AUTH(port) _PORT_HDCP2_BASE(port, 0x98)
|
||||||
#define _TRANSA_HDCP2_AUTH 0x66498
|
#define _TRANSA_HDCP2_AUTH 0x66498
|
||||||
#define _TRANSB_HDCP2_AUTH 0x66598
|
#define _TRANSB_HDCP2_AUTH 0x66598
|
||||||
@@ -9911,6 +9921,44 @@ enum skl_power_gate {
|
|||||||
TRANS_HDCP2_STATUS(trans) : \
|
TRANS_HDCP2_STATUS(trans) : \
|
||||||
PORT_HDCP2_STATUS(port))
|
PORT_HDCP2_STATUS(port))
|
||||||
|
|
||||||
|
#define _PIPEA_HDCP2_STREAM_STATUS 0x668C0
|
||||||
|
#define _PIPEB_HDCP2_STREAM_STATUS 0x665C0
|
||||||
|
#define _PIPEC_HDCP2_STREAM_STATUS 0x666C0
|
||||||
|
#define _PIPED_HDCP2_STREAM_STATUS 0x667C0
|
||||||
|
#define PIPE_HDCP2_STREAM_STATUS(pipe) _MMIO(_PICK((pipe), \
|
||||||
|
_PIPEA_HDCP2_STREAM_STATUS, \
|
||||||
|
_PIPEB_HDCP2_STREAM_STATUS, \
|
||||||
|
_PIPEC_HDCP2_STREAM_STATUS, \
|
||||||
|
_PIPED_HDCP2_STREAM_STATUS))
|
||||||
|
|
||||||
|
#define _TRANSA_HDCP2_STREAM_STATUS 0x664C0
|
||||||
|
#define _TRANSB_HDCP2_STREAM_STATUS 0x665C0
|
||||||
|
#define TRANS_HDCP2_STREAM_STATUS(trans) _MMIO_TRANS(trans, \
|
||||||
|
_TRANSA_HDCP2_STREAM_STATUS, \
|
||||||
|
_TRANSB_HDCP2_STREAM_STATUS)
|
||||||
|
#define STREAM_ENCRYPTION_STATUS BIT(31)
|
||||||
|
#define STREAM_TYPE_STATUS BIT(30)
|
||||||
|
#define HDCP2_STREAM_STATUS(dev_priv, trans, port) \
|
||||||
|
(INTEL_GEN(dev_priv) >= 12 ? \
|
||||||
|
TRANS_HDCP2_STREAM_STATUS(trans) : \
|
||||||
|
PIPE_HDCP2_STREAM_STATUS(pipe))
|
||||||
|
|
||||||
|
#define _PORTA_HDCP2_AUTH_STREAM 0x66F00
|
||||||
|
#define _PORTB_HDCP2_AUTH_STREAM 0x66F04
|
||||||
|
#define PORT_HDCP2_AUTH_STREAM(port) _MMIO_PORT(port, \
|
||||||
|
_PORTA_HDCP2_AUTH_STREAM, \
|
||||||
|
_PORTB_HDCP2_AUTH_STREAM)
|
||||||
|
#define _TRANSA_HDCP2_AUTH_STREAM 0x66F00
|
||||||
|
#define _TRANSB_HDCP2_AUTH_STREAM 0x66F04
|
||||||
|
#define TRANS_HDCP2_AUTH_STREAM(trans) _MMIO_TRANS(trans, \
|
||||||
|
_TRANSA_HDCP2_AUTH_STREAM, \
|
||||||
|
_TRANSB_HDCP2_AUTH_STREAM)
|
||||||
|
#define AUTH_STREAM_TYPE BIT(31)
|
||||||
|
#define HDCP2_AUTH_STREAM(dev_priv, trans, port) \
|
||||||
|
(INTEL_GEN(dev_priv) >= 12 ? \
|
||||||
|
TRANS_HDCP2_AUTH_STREAM(trans) : \
|
||||||
|
PORT_HDCP2_AUTH_STREAM(port))
|
||||||
|
|
||||||
/* Per-pipe DDI Function Control */
|
/* Per-pipe DDI Function Control */
|
||||||
#define _TRANS_DDI_FUNC_CTL_A 0x60400
|
#define _TRANS_DDI_FUNC_CTL_A 0x60400
|
||||||
#define _TRANS_DDI_FUNC_CTL_B 0x61400
|
#define _TRANS_DDI_FUNC_CTL_B 0x61400
|
||||||
@@ -9960,6 +10008,7 @@ enum skl_power_gate {
|
|||||||
#define TRANS_DDI_DP_VC_PAYLOAD_ALLOC (1 << 8)
|
#define TRANS_DDI_DP_VC_PAYLOAD_ALLOC (1 << 8)
|
||||||
#define TRANS_DDI_HDMI_SCRAMBLER_CTS_ENABLE (1 << 7)
|
#define TRANS_DDI_HDMI_SCRAMBLER_CTS_ENABLE (1 << 7)
|
||||||
#define TRANS_DDI_HDMI_SCRAMBLER_RESET_FREQ (1 << 6)
|
#define TRANS_DDI_HDMI_SCRAMBLER_RESET_FREQ (1 << 6)
|
||||||
|
#define TRANS_DDI_HDCP_SELECT REG_BIT(5)
|
||||||
#define TRANS_DDI_BFI_ENABLE (1 << 4)
|
#define TRANS_DDI_BFI_ENABLE (1 << 4)
|
||||||
#define TRANS_DDI_HIGH_TMDS_CHAR_RATE (1 << 4)
|
#define TRANS_DDI_HIGH_TMDS_CHAR_RATE (1 << 4)
|
||||||
#define TRANS_DDI_HDMI_SCRAMBLING (1 << 0)
|
#define TRANS_DDI_HDMI_SCRAMBLING (1 << 0)
|
||||||
|
|||||||
@@ -143,8 +143,9 @@ static bool intel_is_virt_pch(unsigned short id,
|
|||||||
sdevice == PCI_SUBDEVICE_ID_QEMU));
|
sdevice == PCI_SUBDEVICE_ID_QEMU));
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned short
|
static void
|
||||||
intel_virt_detect_pch(const struct drm_i915_private *dev_priv)
|
intel_virt_detect_pch(const struct drm_i915_private *dev_priv,
|
||||||
|
unsigned short *pch_id, enum intel_pch *pch_type)
|
||||||
{
|
{
|
||||||
unsigned short id = 0;
|
unsigned short id = 0;
|
||||||
|
|
||||||
@@ -181,12 +182,21 @@ intel_virt_detect_pch(const struct drm_i915_private *dev_priv)
|
|||||||
else
|
else
|
||||||
drm_dbg_kms(&dev_priv->drm, "Assuming no PCH\n");
|
drm_dbg_kms(&dev_priv->drm, "Assuming no PCH\n");
|
||||||
|
|
||||||
return id;
|
*pch_type = intel_pch_type(dev_priv, id);
|
||||||
|
|
||||||
|
/* Sanity check virtual PCH id */
|
||||||
|
if (drm_WARN_ON(&dev_priv->drm,
|
||||||
|
id && *pch_type == PCH_NONE))
|
||||||
|
id = 0;
|
||||||
|
|
||||||
|
*pch_id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void intel_detect_pch(struct drm_i915_private *dev_priv)
|
void intel_detect_pch(struct drm_i915_private *dev_priv)
|
||||||
{
|
{
|
||||||
struct pci_dev *pch = NULL;
|
struct pci_dev *pch = NULL;
|
||||||
|
unsigned short id;
|
||||||
|
enum intel_pch pch_type;
|
||||||
|
|
||||||
/* DG1 has south engine display on the same PCI device */
|
/* DG1 has south engine display on the same PCI device */
|
||||||
if (IS_DG1(dev_priv)) {
|
if (IS_DG1(dev_priv)) {
|
||||||
@@ -206,9 +216,6 @@ void intel_detect_pch(struct drm_i915_private *dev_priv)
|
|||||||
* of only checking the first one.
|
* of only checking the first one.
|
||||||
*/
|
*/
|
||||||
while ((pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, pch))) {
|
while ((pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, pch))) {
|
||||||
unsigned short id;
|
|
||||||
enum intel_pch pch_type;
|
|
||||||
|
|
||||||
if (pch->vendor != PCI_VENDOR_ID_INTEL)
|
if (pch->vendor != PCI_VENDOR_ID_INTEL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -221,14 +228,7 @@ void intel_detect_pch(struct drm_i915_private *dev_priv)
|
|||||||
break;
|
break;
|
||||||
} else if (intel_is_virt_pch(id, pch->subsystem_vendor,
|
} else if (intel_is_virt_pch(id, pch->subsystem_vendor,
|
||||||
pch->subsystem_device)) {
|
pch->subsystem_device)) {
|
||||||
id = intel_virt_detect_pch(dev_priv);
|
intel_virt_detect_pch(dev_priv, &id, &pch_type);
|
||||||
pch_type = intel_pch_type(dev_priv, id);
|
|
||||||
|
|
||||||
/* Sanity check virtual PCH id */
|
|
||||||
if (drm_WARN_ON(&dev_priv->drm,
|
|
||||||
id && pch_type == PCH_NONE))
|
|
||||||
id = 0;
|
|
||||||
|
|
||||||
dev_priv->pch_type = pch_type;
|
dev_priv->pch_type = pch_type;
|
||||||
dev_priv->pch_id = id;
|
dev_priv->pch_id = id;
|
||||||
break;
|
break;
|
||||||
@@ -244,10 +244,15 @@ void intel_detect_pch(struct drm_i915_private *dev_priv)
|
|||||||
"Display disabled, reverting to NOP PCH\n");
|
"Display disabled, reverting to NOP PCH\n");
|
||||||
dev_priv->pch_type = PCH_NOP;
|
dev_priv->pch_type = PCH_NOP;
|
||||||
dev_priv->pch_id = 0;
|
dev_priv->pch_id = 0;
|
||||||
|
} else if (!pch) {
|
||||||
|
if (run_as_guest() && HAS_DISPLAY(dev_priv)) {
|
||||||
|
intel_virt_detect_pch(dev_priv, &id, &pch_type);
|
||||||
|
dev_priv->pch_type = pch_type;
|
||||||
|
dev_priv->pch_id = id;
|
||||||
|
} else {
|
||||||
|
drm_dbg_kms(&dev_priv->drm, "No PCH found.\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pch)
|
|
||||||
drm_dbg_kms(&dev_priv->drm, "No PCH found.\n");
|
|
||||||
|
|
||||||
pci_dev_put(pch);
|
pci_dev_put(pch);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4017,30 +4017,10 @@ static int intel_compute_sagv_mask(struct intel_atomic_state *state)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int intel_dbuf_size(struct drm_i915_private *dev_priv)
|
||||||
* Calculate initial DBuf slice offset, based on slice size
|
|
||||||
* and mask(i.e if slice size is 1024 and second slice is enabled
|
|
||||||
* offset would be 1024)
|
|
||||||
*/
|
|
||||||
static unsigned int
|
|
||||||
icl_get_first_dbuf_slice_offset(u32 dbuf_slice_mask,
|
|
||||||
u32 slice_size,
|
|
||||||
u32 ddb_size)
|
|
||||||
{
|
{
|
||||||
unsigned int offset = 0;
|
int ddb_size = INTEL_INFO(dev_priv)->ddb_size;
|
||||||
|
|
||||||
if (!dbuf_slice_mask)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
offset = (ffs(dbuf_slice_mask) - 1) * slice_size;
|
|
||||||
|
|
||||||
WARN_ON(offset >= ddb_size);
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 intel_get_ddb_size(struct drm_i915_private *dev_priv)
|
|
||||||
{
|
|
||||||
u16 ddb_size = INTEL_INFO(dev_priv)->ddb_size;
|
|
||||||
drm_WARN_ON(&dev_priv->drm, ddb_size == 0);
|
drm_WARN_ON(&dev_priv->drm, ddb_size == 0);
|
||||||
|
|
||||||
if (INTEL_GEN(dev_priv) < 11)
|
if (INTEL_GEN(dev_priv) < 11)
|
||||||
@@ -4049,11 +4029,36 @@ u16 intel_get_ddb_size(struct drm_i915_private *dev_priv)
|
|||||||
return ddb_size;
|
return ddb_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int intel_dbuf_slice_size(struct drm_i915_private *dev_priv)
|
||||||
|
{
|
||||||
|
return intel_dbuf_size(dev_priv) /
|
||||||
|
INTEL_INFO(dev_priv)->num_supported_dbuf_slices;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
skl_ddb_entry_for_slices(struct drm_i915_private *dev_priv, u8 slice_mask,
|
||||||
|
struct skl_ddb_entry *ddb)
|
||||||
|
{
|
||||||
|
int slice_size = intel_dbuf_slice_size(dev_priv);
|
||||||
|
|
||||||
|
if (!slice_mask) {
|
||||||
|
ddb->start = 0;
|
||||||
|
ddb->end = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ddb->start = (ffs(slice_mask) - 1) * slice_size;
|
||||||
|
ddb->end = fls(slice_mask) * slice_size;
|
||||||
|
|
||||||
|
WARN_ON(ddb->start >= ddb->end);
|
||||||
|
WARN_ON(ddb->end > intel_dbuf_size(dev_priv));
|
||||||
|
}
|
||||||
|
|
||||||
u32 skl_ddb_dbuf_slice_mask(struct drm_i915_private *dev_priv,
|
u32 skl_ddb_dbuf_slice_mask(struct drm_i915_private *dev_priv,
|
||||||
const struct skl_ddb_entry *entry)
|
const struct skl_ddb_entry *entry)
|
||||||
{
|
{
|
||||||
u32 slice_mask = 0;
|
u32 slice_mask = 0;
|
||||||
u16 ddb_size = intel_get_ddb_size(dev_priv);
|
u16 ddb_size = intel_dbuf_size(dev_priv);
|
||||||
u16 num_supported_slices = INTEL_INFO(dev_priv)->num_supported_dbuf_slices;
|
u16 num_supported_slices = INTEL_INFO(dev_priv)->num_supported_dbuf_slices;
|
||||||
u16 slice_size = ddb_size / num_supported_slices;
|
u16 slice_size = ddb_size / num_supported_slices;
|
||||||
u16 start_slice;
|
u16 start_slice;
|
||||||
@@ -4077,116 +4082,40 @@ u32 skl_ddb_dbuf_slice_mask(struct drm_i915_private *dev_priv,
|
|||||||
return slice_mask;
|
return slice_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 skl_compute_dbuf_slices(const struct intel_crtc_state *crtc_state,
|
static unsigned int intel_crtc_ddb_weight(const struct intel_crtc_state *crtc_state)
|
||||||
u8 active_pipes);
|
|
||||||
|
|
||||||
static int
|
|
||||||
skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv,
|
|
||||||
const struct intel_crtc_state *crtc_state,
|
|
||||||
const u64 total_data_rate,
|
|
||||||
struct skl_ddb_entry *alloc, /* out */
|
|
||||||
int *num_active /* out */)
|
|
||||||
{
|
{
|
||||||
struct drm_atomic_state *state = crtc_state->uapi.state;
|
const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode;
|
||||||
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
|
int hdisplay, vdisplay;
|
||||||
struct drm_crtc *for_crtc = crtc_state->uapi.crtc;
|
|
||||||
const struct intel_crtc *crtc;
|
|
||||||
u32 pipe_width = 0, total_width_in_range = 0, width_before_pipe_in_range = 0;
|
|
||||||
enum pipe for_pipe = to_intel_crtc(for_crtc)->pipe;
|
|
||||||
struct intel_dbuf_state *new_dbuf_state =
|
|
||||||
intel_atomic_get_new_dbuf_state(intel_state);
|
|
||||||
const struct intel_dbuf_state *old_dbuf_state =
|
|
||||||
intel_atomic_get_old_dbuf_state(intel_state);
|
|
||||||
u8 active_pipes = new_dbuf_state->active_pipes;
|
|
||||||
u16 ddb_size;
|
|
||||||
u32 ddb_range_size;
|
|
||||||
u32 i;
|
|
||||||
u32 dbuf_slice_mask;
|
|
||||||
u32 offset;
|
|
||||||
u32 slice_size;
|
|
||||||
u32 total_slice_mask;
|
|
||||||
u32 start, end;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
*num_active = hweight8(active_pipes);
|
if (!crtc_state->hw.active)
|
||||||
|
|
||||||
if (!crtc_state->hw.active) {
|
|
||||||
alloc->start = 0;
|
|
||||||
alloc->end = 0;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
ddb_size = intel_get_ddb_size(dev_priv);
|
|
||||||
|
|
||||||
slice_size = ddb_size / INTEL_INFO(dev_priv)->num_supported_dbuf_slices;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the state doesn't change the active CRTC's or there is no
|
|
||||||
* modeset request, then there's no need to recalculate;
|
|
||||||
* the existing pipe allocation limits should remain unchanged.
|
|
||||||
* Note that we're safe from racing commits since any racing commit
|
|
||||||
* that changes the active CRTC list or do modeset would need to
|
|
||||||
* grab _all_ crtc locks, including the one we currently hold.
|
|
||||||
*/
|
|
||||||
if (old_dbuf_state->active_pipes == new_dbuf_state->active_pipes &&
|
|
||||||
!dev_priv->wm.distrust_bios_wm) {
|
|
||||||
/*
|
|
||||||
* alloc may be cleared by clear_intel_crtc_state,
|
|
||||||
* copy from old state to be sure
|
|
||||||
*
|
|
||||||
* FIXME get rid of this mess
|
|
||||||
*/
|
|
||||||
*alloc = to_intel_crtc_state(for_crtc->state)->wm.skl.ddb;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get allowed DBuf slices for correspondent pipe and platform.
|
|
||||||
*/
|
|
||||||
dbuf_slice_mask = skl_compute_dbuf_slices(crtc_state, active_pipes);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Figure out at which DBuf slice we start, i.e if we start at Dbuf S2
|
|
||||||
* and slice size is 1024, the offset would be 1024
|
|
||||||
*/
|
|
||||||
offset = icl_get_first_dbuf_slice_offset(dbuf_slice_mask,
|
|
||||||
slice_size, ddb_size);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Figure out total size of allowed DBuf slices, which is basically
|
|
||||||
* a number of allowed slices for that pipe multiplied by slice size.
|
|
||||||
* Inside of this
|
|
||||||
* range ddb entries are still allocated in proportion to display width.
|
|
||||||
*/
|
|
||||||
ddb_range_size = hweight8(dbuf_slice_mask) * slice_size;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Watermark/ddb requirement highly depends upon width of the
|
* Watermark/ddb requirement highly depends upon width of the
|
||||||
* framebuffer, So instead of allocating DDB equally among pipes
|
* framebuffer, So instead of allocating DDB equally among pipes
|
||||||
* distribute DDB based on resolution/width of the display.
|
* distribute DDB based on resolution/width of the display.
|
||||||
*/
|
*/
|
||||||
total_slice_mask = dbuf_slice_mask;
|
drm_mode_get_hv_timing(pipe_mode, &hdisplay, &vdisplay);
|
||||||
for_each_new_intel_crtc_in_state(intel_state, crtc, crtc_state, i) {
|
|
||||||
const struct drm_display_mode *pipe_mode =
|
|
||||||
&crtc_state->hw.pipe_mode;
|
|
||||||
enum pipe pipe = crtc->pipe;
|
|
||||||
int hdisplay, vdisplay;
|
|
||||||
u32 pipe_dbuf_slice_mask;
|
|
||||||
|
|
||||||
if (!crtc_state->hw.active)
|
return hdisplay;
|
||||||
continue;
|
}
|
||||||
|
|
||||||
pipe_dbuf_slice_mask = skl_compute_dbuf_slices(crtc_state,
|
static void intel_crtc_dbuf_weights(const struct intel_dbuf_state *dbuf_state,
|
||||||
active_pipes);
|
enum pipe for_pipe,
|
||||||
|
unsigned int *weight_start,
|
||||||
|
unsigned int *weight_end,
|
||||||
|
unsigned int *weight_total)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv =
|
||||||
|
to_i915(dbuf_state->base.state->base.dev);
|
||||||
|
enum pipe pipe;
|
||||||
|
|
||||||
/*
|
*weight_start = 0;
|
||||||
* According to BSpec pipe can share one dbuf slice with another
|
*weight_end = 0;
|
||||||
* pipes or pipe can use multiple dbufs, in both cases we
|
*weight_total = 0;
|
||||||
* account for other pipes only if they have exactly same mask.
|
|
||||||
* However we need to account how many slices we should enable
|
for_each_pipe(dev_priv, pipe) {
|
||||||
* in total.
|
int weight = dbuf_state->weight[pipe];
|
||||||
*/
|
|
||||||
total_slice_mask |= pipe_dbuf_slice_mask;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do not account pipes using other slice sets
|
* Do not account pipes using other slice sets
|
||||||
@@ -4195,42 +4124,78 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv,
|
|||||||
* i.e no partial intersection), so it is enough to check for
|
* i.e no partial intersection), so it is enough to check for
|
||||||
* equality for now.
|
* equality for now.
|
||||||
*/
|
*/
|
||||||
if (dbuf_slice_mask != pipe_dbuf_slice_mask)
|
if (dbuf_state->slices[pipe] != dbuf_state->slices[for_pipe])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
drm_mode_get_hv_timing(pipe_mode, &hdisplay, &vdisplay);
|
*weight_total += weight;
|
||||||
|
if (pipe < for_pipe) {
|
||||||
|
*weight_start += weight;
|
||||||
|
*weight_end += weight;
|
||||||
|
} else if (pipe == for_pipe) {
|
||||||
|
*weight_end += weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
total_width_in_range += hdisplay;
|
static int
|
||||||
|
skl_crtc_allocate_ddb(struct intel_atomic_state *state, struct intel_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||||
|
unsigned int weight_total, weight_start, weight_end;
|
||||||
|
const struct intel_dbuf_state *old_dbuf_state =
|
||||||
|
intel_atomic_get_old_dbuf_state(state);
|
||||||
|
struct intel_dbuf_state *new_dbuf_state =
|
||||||
|
intel_atomic_get_new_dbuf_state(state);
|
||||||
|
struct intel_crtc_state *crtc_state;
|
||||||
|
struct skl_ddb_entry ddb_slices;
|
||||||
|
enum pipe pipe = crtc->pipe;
|
||||||
|
u32 ddb_range_size;
|
||||||
|
u32 dbuf_slice_mask;
|
||||||
|
u32 start, end;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (pipe < for_pipe)
|
if (new_dbuf_state->weight[pipe] == 0) {
|
||||||
width_before_pipe_in_range += hdisplay;
|
new_dbuf_state->ddb[pipe].start = 0;
|
||||||
else if (pipe == for_pipe)
|
new_dbuf_state->ddb[pipe].end = 0;
|
||||||
pipe_width = hdisplay;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
dbuf_slice_mask = new_dbuf_state->slices[pipe];
|
||||||
* FIXME: For now we always enable slice S1 as per
|
|
||||||
* the Bspec display initialization sequence.
|
|
||||||
*/
|
|
||||||
new_dbuf_state->enabled_slices = total_slice_mask | BIT(DBUF_S1);
|
|
||||||
|
|
||||||
if (old_dbuf_state->enabled_slices != new_dbuf_state->enabled_slices) {
|
skl_ddb_entry_for_slices(dev_priv, dbuf_slice_mask, &ddb_slices);
|
||||||
ret = intel_atomic_serialize_global_state(&new_dbuf_state->base);
|
ddb_range_size = skl_ddb_entry_size(&ddb_slices);
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
start = ddb_range_size * width_before_pipe_in_range / total_width_in_range;
|
intel_crtc_dbuf_weights(new_dbuf_state, pipe,
|
||||||
end = ddb_range_size *
|
&weight_start, &weight_end, &weight_total);
|
||||||
(width_before_pipe_in_range + pipe_width) / total_width_in_range;
|
|
||||||
|
|
||||||
alloc->start = offset + start;
|
start = ddb_range_size * weight_start / weight_total;
|
||||||
alloc->end = offset + end;
|
end = ddb_range_size * weight_end / weight_total;
|
||||||
|
|
||||||
|
new_dbuf_state->ddb[pipe].start = ddb_slices.start + start;
|
||||||
|
new_dbuf_state->ddb[pipe].end = ddb_slices.start + end;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (skl_ddb_entry_equal(&old_dbuf_state->ddb[pipe],
|
||||||
|
&new_dbuf_state->ddb[pipe]))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = intel_atomic_lock_global_state(&new_dbuf_state->base);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
|
||||||
|
if (IS_ERR(crtc_state))
|
||||||
|
return PTR_ERR(crtc_state);
|
||||||
|
|
||||||
|
crtc_state->wm.skl.ddb = new_dbuf_state->ddb[pipe];
|
||||||
|
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
"[CRTC:%d:%s] dbuf slices 0x%x, ddb (%d - %d), active pipes 0x%x\n",
|
"[CRTC:%d:%s] dbuf slices 0x%x -> 0x%x, ddb (%d - %d) -> (%d - %d), active pipes 0x%x -> 0x%x\n",
|
||||||
for_crtc->base.id, for_crtc->name,
|
crtc->base.base.id, crtc->base.name,
|
||||||
dbuf_slice_mask, alloc->start, alloc->end, active_pipes);
|
old_dbuf_state->slices[pipe], new_dbuf_state->slices[pipe],
|
||||||
|
old_dbuf_state->ddb[pipe].start, old_dbuf_state->ddb[pipe].end,
|
||||||
|
new_dbuf_state->ddb[pipe].start, new_dbuf_state->ddb[pipe].end,
|
||||||
|
old_dbuf_state->active_pipes, new_dbuf_state->active_pipes);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -4632,10 +4597,8 @@ static u8 tgl_compute_dbuf_slices(enum pipe pipe, u8 active_pipes)
|
|||||||
return compute_dbuf_slices(pipe, active_pipes, tgl_allowed_dbufs);
|
return compute_dbuf_slices(pipe, active_pipes, tgl_allowed_dbufs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 skl_compute_dbuf_slices(const struct intel_crtc_state *crtc_state,
|
static u8 skl_compute_dbuf_slices(struct intel_crtc *crtc, u8 active_pipes)
|
||||||
u8 active_pipes)
|
|
||||||
{
|
{
|
||||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
|
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||||
enum pipe pipe = crtc->pipe;
|
enum pipe pipe = crtc->pipe;
|
||||||
|
|
||||||
@@ -4798,55 +4761,30 @@ skl_plane_wm_level(const struct intel_crtc_state *crtc_state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
skl_allocate_pipe_ddb(struct intel_atomic_state *state,
|
skl_allocate_plane_ddb(struct intel_atomic_state *state,
|
||||||
struct intel_crtc *crtc)
|
struct intel_crtc *crtc)
|
||||||
{
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||||
struct intel_crtc_state *crtc_state =
|
struct intel_crtc_state *crtc_state =
|
||||||
intel_atomic_get_new_crtc_state(state, crtc);
|
intel_atomic_get_new_crtc_state(state, crtc);
|
||||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
const struct intel_dbuf_state *dbuf_state =
|
||||||
struct skl_ddb_entry *alloc = &crtc_state->wm.skl.ddb;
|
intel_atomic_get_new_dbuf_state(state);
|
||||||
|
const struct skl_ddb_entry *alloc = &dbuf_state->ddb[crtc->pipe];
|
||||||
|
int num_active = hweight8(dbuf_state->active_pipes);
|
||||||
u16 alloc_size, start = 0;
|
u16 alloc_size, start = 0;
|
||||||
u16 total[I915_MAX_PLANES] = {};
|
u16 total[I915_MAX_PLANES] = {};
|
||||||
u16 uv_total[I915_MAX_PLANES] = {};
|
u16 uv_total[I915_MAX_PLANES] = {};
|
||||||
u64 total_data_rate;
|
u64 total_data_rate;
|
||||||
enum plane_id plane_id;
|
enum plane_id plane_id;
|
||||||
int num_active;
|
|
||||||
u32 blocks;
|
u32 blocks;
|
||||||
int level;
|
int level;
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Clear the partitioning for disabled planes. */
|
/* Clear the partitioning for disabled planes. */
|
||||||
memset(crtc_state->wm.skl.plane_ddb_y, 0, sizeof(crtc_state->wm.skl.plane_ddb_y));
|
memset(crtc_state->wm.skl.plane_ddb_y, 0, sizeof(crtc_state->wm.skl.plane_ddb_y));
|
||||||
memset(crtc_state->wm.skl.plane_ddb_uv, 0, sizeof(crtc_state->wm.skl.plane_ddb_uv));
|
memset(crtc_state->wm.skl.plane_ddb_uv, 0, sizeof(crtc_state->wm.skl.plane_ddb_uv));
|
||||||
|
|
||||||
if (!crtc_state->hw.active) {
|
if (!crtc_state->hw.active)
|
||||||
struct intel_atomic_state *state =
|
|
||||||
to_intel_atomic_state(crtc_state->uapi.state);
|
|
||||||
struct intel_dbuf_state *new_dbuf_state =
|
|
||||||
intel_atomic_get_new_dbuf_state(state);
|
|
||||||
const struct intel_dbuf_state *old_dbuf_state =
|
|
||||||
intel_atomic_get_old_dbuf_state(state);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME hack to make sure we compute this sensibly when
|
|
||||||
* turning off all the pipes. Otherwise we leave it at
|
|
||||||
* whatever we had previously, and then runtime PM will
|
|
||||||
* mess it up by turning off all but S1. Remove this
|
|
||||||
* once the dbuf state computation flow becomes sane.
|
|
||||||
*/
|
|
||||||
if (new_dbuf_state->active_pipes == 0) {
|
|
||||||
new_dbuf_state->enabled_slices = BIT(DBUF_S1);
|
|
||||||
|
|
||||||
if (old_dbuf_state->enabled_slices != new_dbuf_state->enabled_slices) {
|
|
||||||
ret = intel_atomic_serialize_global_state(&new_dbuf_state->base);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
alloc->start = alloc->end = 0;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (INTEL_GEN(dev_priv) >= 11)
|
if (INTEL_GEN(dev_priv) >= 11)
|
||||||
total_data_rate =
|
total_data_rate =
|
||||||
@@ -4855,12 +4793,6 @@ skl_allocate_pipe_ddb(struct intel_atomic_state *state,
|
|||||||
total_data_rate =
|
total_data_rate =
|
||||||
skl_get_total_relative_data_rate(state, crtc);
|
skl_get_total_relative_data_rate(state, crtc);
|
||||||
|
|
||||||
ret = skl_ddb_get_pipe_allocation_limits(dev_priv, crtc_state,
|
|
||||||
total_data_rate,
|
|
||||||
alloc, &num_active);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
alloc_size = skl_ddb_entry_size(alloc);
|
alloc_size = skl_ddb_entry_size(alloc);
|
||||||
if (alloc_size == 0)
|
if (alloc_size == 0)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -5731,6 +5663,18 @@ static bool skl_ddb_entries_overlap(const struct skl_ddb_entry *a,
|
|||||||
return a->start < b->end && b->start < a->end;
|
return a->start < b->end && b->start < a->end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void skl_ddb_entry_union(struct skl_ddb_entry *a,
|
||||||
|
const struct skl_ddb_entry *b)
|
||||||
|
{
|
||||||
|
if (a->end && b->end) {
|
||||||
|
a->start = min(a->start, b->start);
|
||||||
|
a->end = max(a->end, b->end);
|
||||||
|
} else if (b->end) {
|
||||||
|
a->start = b->start;
|
||||||
|
a->end = b->end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb,
|
bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb,
|
||||||
const struct skl_ddb_entry *entries,
|
const struct skl_ddb_entry *entries,
|
||||||
int num_entries, int ignore_idx)
|
int num_entries, int ignore_idx)
|
||||||
@@ -5775,20 +5719,106 @@ skl_ddb_add_affected_planes(const struct intel_crtc_state *old_crtc_state,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u8 intel_dbuf_enabled_slices(const struct intel_dbuf_state *dbuf_state)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(dbuf_state->base.state->base.dev);
|
||||||
|
u8 enabled_slices;
|
||||||
|
enum pipe pipe;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: For now we always enable slice S1 as per
|
||||||
|
* the Bspec display initialization sequence.
|
||||||
|
*/
|
||||||
|
enabled_slices = BIT(DBUF_S1);
|
||||||
|
|
||||||
|
for_each_pipe(dev_priv, pipe)
|
||||||
|
enabled_slices |= dbuf_state->slices[pipe];
|
||||||
|
|
||||||
|
return enabled_slices;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
skl_compute_ddb(struct intel_atomic_state *state)
|
skl_compute_ddb(struct intel_atomic_state *state)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
||||||
const struct intel_dbuf_state *old_dbuf_state;
|
const struct intel_dbuf_state *old_dbuf_state;
|
||||||
const struct intel_dbuf_state *new_dbuf_state;
|
struct intel_dbuf_state *new_dbuf_state = NULL;
|
||||||
const struct intel_crtc_state *old_crtc_state;
|
const struct intel_crtc_state *old_crtc_state;
|
||||||
struct intel_crtc_state *new_crtc_state;
|
struct intel_crtc_state *new_crtc_state;
|
||||||
struct intel_crtc *crtc;
|
struct intel_crtc *crtc;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
|
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
|
||||||
|
new_dbuf_state = intel_atomic_get_dbuf_state(state);
|
||||||
|
if (IS_ERR(new_dbuf_state))
|
||||||
|
return PTR_ERR(new_dbuf_state);
|
||||||
|
|
||||||
|
old_dbuf_state = intel_atomic_get_old_dbuf_state(state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!new_dbuf_state)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
new_dbuf_state->active_pipes =
|
||||||
|
intel_calc_active_pipes(state, old_dbuf_state->active_pipes);
|
||||||
|
|
||||||
|
if (old_dbuf_state->active_pipes != new_dbuf_state->active_pipes) {
|
||||||
|
ret = intel_atomic_lock_global_state(&new_dbuf_state->base);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_intel_crtc(&dev_priv->drm, crtc) {
|
||||||
|
enum pipe pipe = crtc->pipe;
|
||||||
|
|
||||||
|
new_dbuf_state->slices[pipe] =
|
||||||
|
skl_compute_dbuf_slices(crtc, new_dbuf_state->active_pipes);
|
||||||
|
|
||||||
|
if (old_dbuf_state->slices[pipe] == new_dbuf_state->slices[pipe])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = intel_atomic_lock_global_state(&new_dbuf_state->base);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_dbuf_state->enabled_slices = intel_dbuf_enabled_slices(new_dbuf_state);
|
||||||
|
|
||||||
|
if (old_dbuf_state->enabled_slices != new_dbuf_state->enabled_slices) {
|
||||||
|
ret = intel_atomic_serialize_global_state(&new_dbuf_state->base);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"Enabled dbuf slices 0x%x -> 0x%x (out of %d dbuf slices)\n",
|
||||||
|
old_dbuf_state->enabled_slices,
|
||||||
|
new_dbuf_state->enabled_slices,
|
||||||
|
INTEL_INFO(dev_priv)->num_supported_dbuf_slices);
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
|
||||||
|
enum pipe pipe = crtc->pipe;
|
||||||
|
|
||||||
|
new_dbuf_state->weight[pipe] = intel_crtc_ddb_weight(new_crtc_state);
|
||||||
|
|
||||||
|
if (old_dbuf_state->weight[pipe] == new_dbuf_state->weight[pipe])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = intel_atomic_lock_global_state(&new_dbuf_state->base);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_intel_crtc(&dev_priv->drm, crtc) {
|
||||||
|
ret = skl_crtc_allocate_ddb(state, crtc);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
|
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
|
||||||
new_crtc_state, i) {
|
new_crtc_state, i) {
|
||||||
ret = skl_allocate_pipe_ddb(state, crtc);
|
ret = skl_allocate_plane_ddb(state, crtc);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -5798,17 +5828,6 @@ skl_compute_ddb(struct intel_atomic_state *state)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
old_dbuf_state = intel_atomic_get_old_dbuf_state(state);
|
|
||||||
new_dbuf_state = intel_atomic_get_new_dbuf_state(state);
|
|
||||||
|
|
||||||
if (new_dbuf_state &&
|
|
||||||
new_dbuf_state->enabled_slices != old_dbuf_state->enabled_slices)
|
|
||||||
drm_dbg_kms(&dev_priv->drm,
|
|
||||||
"Enabled dbuf slices 0x%x -> 0x%x (out of %d dbuf slices)\n",
|
|
||||||
old_dbuf_state->enabled_slices,
|
|
||||||
new_dbuf_state->enabled_slices,
|
|
||||||
INTEL_INFO(dev_priv)->num_supported_dbuf_slices);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5944,83 +5963,6 @@ skl_print_wm_changes(struct intel_atomic_state *state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int intel_add_affected_pipes(struct intel_atomic_state *state,
|
|
||||||
u8 pipe_mask)
|
|
||||||
{
|
|
||||||
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
|
||||||
struct intel_crtc *crtc;
|
|
||||||
|
|
||||||
for_each_intel_crtc(&dev_priv->drm, crtc) {
|
|
||||||
struct intel_crtc_state *crtc_state;
|
|
||||||
|
|
||||||
if ((pipe_mask & BIT(crtc->pipe)) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
|
|
||||||
if (IS_ERR(crtc_state))
|
|
||||||
return PTR_ERR(crtc_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
skl_ddb_add_affected_pipes(struct intel_atomic_state *state)
|
|
||||||
{
|
|
||||||
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
|
|
||||||
struct intel_crtc_state *crtc_state;
|
|
||||||
struct intel_crtc *crtc;
|
|
||||||
int i, ret;
|
|
||||||
|
|
||||||
if (dev_priv->wm.distrust_bios_wm) {
|
|
||||||
/*
|
|
||||||
* skl_ddb_get_pipe_allocation_limits() currently requires
|
|
||||||
* all active pipes to be included in the state so that
|
|
||||||
* it can redistribute the dbuf among them, and it really
|
|
||||||
* wants to recompute things when distrust_bios_wm is set
|
|
||||||
* so we add all the pipes to the state.
|
|
||||||
*/
|
|
||||||
ret = intel_add_affected_pipes(state, ~0);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
|
|
||||||
struct intel_dbuf_state *new_dbuf_state;
|
|
||||||
const struct intel_dbuf_state *old_dbuf_state;
|
|
||||||
|
|
||||||
new_dbuf_state = intel_atomic_get_dbuf_state(state);
|
|
||||||
if (IS_ERR(new_dbuf_state))
|
|
||||||
return PTR_ERR(new_dbuf_state);
|
|
||||||
|
|
||||||
old_dbuf_state = intel_atomic_get_old_dbuf_state(state);
|
|
||||||
|
|
||||||
new_dbuf_state->active_pipes =
|
|
||||||
intel_calc_active_pipes(state, old_dbuf_state->active_pipes);
|
|
||||||
|
|
||||||
if (old_dbuf_state->active_pipes == new_dbuf_state->active_pipes)
|
|
||||||
break;
|
|
||||||
|
|
||||||
ret = intel_atomic_lock_global_state(&new_dbuf_state->base);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* skl_ddb_get_pipe_allocation_limits() currently requires
|
|
||||||
* all active pipes to be included in the state so that
|
|
||||||
* it can redistribute the dbuf among them.
|
|
||||||
*/
|
|
||||||
ret = intel_add_affected_pipes(state,
|
|
||||||
new_dbuf_state->active_pipes);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To make sure the cursor watermark registers are always consistent
|
* To make sure the cursor watermark registers are always consistent
|
||||||
* with our computed state the following scenario needs special
|
* with our computed state the following scenario needs special
|
||||||
@@ -6088,15 +6030,6 @@ skl_compute_wm(struct intel_atomic_state *state)
|
|||||||
struct intel_crtc_state *new_crtc_state;
|
struct intel_crtc_state *new_crtc_state;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
ret = skl_ddb_add_affected_pipes(state);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate WM's for all pipes that are part of this transaction.
|
|
||||||
* Note that skl_ddb_add_affected_pipes may have added more CRTC's that
|
|
||||||
* weren't otherwise being modified if pipe allocations had to change.
|
|
||||||
*/
|
|
||||||
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
|
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
|
||||||
ret = skl_build_pipe_wm(state, crtc);
|
ret = skl_build_pipe_wm(state, crtc);
|
||||||
if (ret)
|
if (ret)
|
||||||
@@ -6255,20 +6188,49 @@ void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc,
|
|||||||
|
|
||||||
void skl_wm_get_hw_state(struct drm_i915_private *dev_priv)
|
void skl_wm_get_hw_state(struct drm_i915_private *dev_priv)
|
||||||
{
|
{
|
||||||
|
struct intel_dbuf_state *dbuf_state =
|
||||||
|
to_intel_dbuf_state(dev_priv->dbuf.obj.state);
|
||||||
struct intel_crtc *crtc;
|
struct intel_crtc *crtc;
|
||||||
struct intel_crtc_state *crtc_state;
|
|
||||||
|
|
||||||
for_each_intel_crtc(&dev_priv->drm, crtc) {
|
for_each_intel_crtc(&dev_priv->drm, crtc) {
|
||||||
crtc_state = to_intel_crtc_state(crtc->base.state);
|
struct intel_crtc_state *crtc_state =
|
||||||
|
to_intel_crtc_state(crtc->base.state);
|
||||||
|
enum pipe pipe = crtc->pipe;
|
||||||
|
enum plane_id plane_id;
|
||||||
|
|
||||||
skl_pipe_wm_get_hw_state(crtc, &crtc_state->wm.skl.optimal);
|
skl_pipe_wm_get_hw_state(crtc, &crtc_state->wm.skl.optimal);
|
||||||
crtc_state->wm.skl.raw = crtc_state->wm.skl.optimal;
|
crtc_state->wm.skl.raw = crtc_state->wm.skl.optimal;
|
||||||
|
|
||||||
|
memset(&dbuf_state->ddb[pipe], 0, sizeof(dbuf_state->ddb[pipe]));
|
||||||
|
|
||||||
|
for_each_plane_id_on_crtc(crtc, plane_id) {
|
||||||
|
struct skl_ddb_entry *ddb_y =
|
||||||
|
&crtc_state->wm.skl.plane_ddb_y[plane_id];
|
||||||
|
struct skl_ddb_entry *ddb_uv =
|
||||||
|
&crtc_state->wm.skl.plane_ddb_uv[plane_id];
|
||||||
|
|
||||||
|
skl_ddb_get_hw_plane_state(dev_priv, crtc->pipe,
|
||||||
|
plane_id, ddb_y, ddb_uv);
|
||||||
|
|
||||||
|
skl_ddb_entry_union(&dbuf_state->ddb[pipe], ddb_y);
|
||||||
|
skl_ddb_entry_union(&dbuf_state->ddb[pipe], ddb_uv);
|
||||||
|
}
|
||||||
|
|
||||||
|
dbuf_state->slices[pipe] =
|
||||||
|
skl_compute_dbuf_slices(crtc, dbuf_state->active_pipes);
|
||||||
|
|
||||||
|
dbuf_state->weight[pipe] = intel_crtc_ddb_weight(crtc_state);
|
||||||
|
|
||||||
|
crtc_state->wm.skl.ddb = dbuf_state->ddb[pipe];
|
||||||
|
|
||||||
|
drm_dbg_kms(&dev_priv->drm,
|
||||||
|
"[CRTC:%d:%s] dbuf slices 0x%x, ddb (%d - %d), active pipes 0x%x\n",
|
||||||
|
crtc->base.base.id, crtc->base.name,
|
||||||
|
dbuf_state->slices[pipe], dbuf_state->ddb[pipe].start,
|
||||||
|
dbuf_state->ddb[pipe].end, dbuf_state->active_pipes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev_priv->active_pipes) {
|
dbuf_state->enabled_slices = dev_priv->dbuf.enabled_slices;
|
||||||
/* Fully recompute DDB on first atomic commit */
|
|
||||||
dev_priv->wm.distrust_bios_wm = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ilk_pipe_wm_get_hw_state(struct intel_crtc *crtc)
|
static void ilk_pipe_wm_get_hw_state(struct intel_crtc *crtc)
|
||||||
@@ -7103,24 +7065,26 @@ static void icl_init_clock_gating(struct drm_i915_private *dev_priv)
|
|||||||
0, CNL_DELAY_PMRSP);
|
0, CNL_DELAY_PMRSP);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tgl_init_clock_gating(struct drm_i915_private *dev_priv)
|
static void gen12lp_init_clock_gating(struct drm_i915_private *dev_priv)
|
||||||
{
|
{
|
||||||
/* Wa_1409120013:tgl */
|
/* Wa_1409120013:tgl,rkl,adl_s,dg1 */
|
||||||
intel_uncore_write(&dev_priv->uncore, ILK_DPFC_CHICKEN,
|
intel_uncore_write(&dev_priv->uncore, ILK_DPFC_CHICKEN,
|
||||||
ILK_DPFC_CHICKEN_COMP_DUMMY_PIXEL);
|
ILK_DPFC_CHICKEN_COMP_DUMMY_PIXEL);
|
||||||
|
|
||||||
/* Wa_1409825376:tgl (pre-prod)*/
|
/* Wa_1409825376:tgl (pre-prod)*/
|
||||||
if (IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_B1))
|
if (IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_B1))
|
||||||
intel_uncore_write(&dev_priv->uncore, GEN9_CLKGATE_DIS_3, intel_uncore_read(&dev_priv->uncore, GEN9_CLKGATE_DIS_3) |
|
intel_uncore_write(&dev_priv->uncore, GEN9_CLKGATE_DIS_3, intel_uncore_read(&dev_priv->uncore, GEN9_CLKGATE_DIS_3) |
|
||||||
TGL_VRH_GATING_DIS);
|
TGL_VRH_GATING_DIS);
|
||||||
|
|
||||||
/* Wa_14011059788:tgl */
|
/* Wa_14011059788:tgl,rkl,adl_s,dg1 */
|
||||||
intel_uncore_rmw(&dev_priv->uncore, GEN10_DFR_RATIO_EN_AND_CHICKEN,
|
intel_uncore_rmw(&dev_priv->uncore, GEN10_DFR_RATIO_EN_AND_CHICKEN,
|
||||||
0, DFR_DISABLE);
|
0, DFR_DISABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dg1_init_clock_gating(struct drm_i915_private *dev_priv)
|
static void dg1_init_clock_gating(struct drm_i915_private *dev_priv)
|
||||||
{
|
{
|
||||||
|
gen12lp_init_clock_gating(dev_priv);
|
||||||
|
|
||||||
/* Wa_1409836686:dg1[a0] */
|
/* Wa_1409836686:dg1[a0] */
|
||||||
if (IS_DG1_REVID(dev_priv, DG1_REVID_A0, DG1_REVID_A0))
|
if (IS_DG1_REVID(dev_priv, DG1_REVID_A0, DG1_REVID_A0))
|
||||||
intel_uncore_write(&dev_priv->uncore, GEN9_CLKGATE_DIS_3, intel_uncore_read(&dev_priv->uncore, GEN9_CLKGATE_DIS_3) |
|
intel_uncore_write(&dev_priv->uncore, GEN9_CLKGATE_DIS_3, intel_uncore_read(&dev_priv->uncore, GEN9_CLKGATE_DIS_3) |
|
||||||
@@ -7583,7 +7547,7 @@ void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv)
|
|||||||
if (IS_DG1(dev_priv))
|
if (IS_DG1(dev_priv))
|
||||||
dev_priv->display.init_clock_gating = dg1_init_clock_gating;
|
dev_priv->display.init_clock_gating = dg1_init_clock_gating;
|
||||||
else if (IS_GEN(dev_priv, 12))
|
else if (IS_GEN(dev_priv, 12))
|
||||||
dev_priv->display.init_clock_gating = tgl_init_clock_gating;
|
dev_priv->display.init_clock_gating = gen12lp_init_clock_gating;
|
||||||
else if (IS_GEN(dev_priv, 11))
|
else if (IS_GEN(dev_priv, 11))
|
||||||
dev_priv->display.init_clock_gating = icl_init_clock_gating;
|
dev_priv->display.init_clock_gating = icl_init_clock_gating;
|
||||||
else if (IS_CANNONLAKE(dev_priv))
|
else if (IS_CANNONLAKE(dev_priv))
|
||||||
|
|||||||
@@ -9,8 +9,10 @@
|
|||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
#include "display/intel_bw.h"
|
#include "display/intel_bw.h"
|
||||||
|
#include "display/intel_display.h"
|
||||||
#include "display/intel_global_state.h"
|
#include "display/intel_global_state.h"
|
||||||
|
|
||||||
|
#include "i915_drv.h"
|
||||||
#include "i915_reg.h"
|
#include "i915_reg.h"
|
||||||
|
|
||||||
struct drm_device;
|
struct drm_device;
|
||||||
@@ -40,7 +42,6 @@ void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
|
|||||||
struct skl_ddb_entry *ddb_y,
|
struct skl_ddb_entry *ddb_y,
|
||||||
struct skl_ddb_entry *ddb_uv);
|
struct skl_ddb_entry *ddb_uv);
|
||||||
void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv);
|
void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv);
|
||||||
u16 intel_get_ddb_size(struct drm_i915_private *dev_priv);
|
|
||||||
u32 skl_ddb_dbuf_slice_mask(struct drm_i915_private *dev_priv,
|
u32 skl_ddb_dbuf_slice_mask(struct drm_i915_private *dev_priv,
|
||||||
const struct skl_ddb_entry *entry);
|
const struct skl_ddb_entry *entry);
|
||||||
void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc,
|
void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc,
|
||||||
@@ -69,6 +70,10 @@ bool intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable);
|
|||||||
struct intel_dbuf_state {
|
struct intel_dbuf_state {
|
||||||
struct intel_global_state base;
|
struct intel_global_state base;
|
||||||
|
|
||||||
|
struct skl_ddb_entry ddb[I915_MAX_PIPES];
|
||||||
|
unsigned int weight[I915_MAX_PIPES];
|
||||||
|
u8 slices[I915_MAX_PIPES];
|
||||||
|
|
||||||
u8 enabled_slices;
|
u8 enabled_slices;
|
||||||
u8 active_pipes;
|
u8 active_pipes;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1420,16 +1420,14 @@ void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)
|
|||||||
static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl)
|
static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl)
|
||||||
{
|
{
|
||||||
u8 *dpcd = ctrl->panel->dpcd;
|
u8 *dpcd = ctrl->panel->dpcd;
|
||||||
u32 edid_quirks = 0;
|
|
||||||
|
|
||||||
edid_quirks = drm_dp_get_edid_quirks(ctrl->panel->edid);
|
|
||||||
/*
|
/*
|
||||||
* For better interop experience, used a fixed NVID=0x8000
|
* For better interop experience, used a fixed NVID=0x8000
|
||||||
* whenever connected to a VGA dongle downstream.
|
* whenever connected to a VGA dongle downstream.
|
||||||
*/
|
*/
|
||||||
if (drm_dp_is_branch(dpcd))
|
if (drm_dp_is_branch(dpcd))
|
||||||
return (drm_dp_has_quirk(&ctrl->panel->desc, edid_quirks,
|
return (drm_dp_has_quirk(&ctrl->panel->desc,
|
||||||
DP_DPCD_QUIRK_CONSTANT_N));
|
DP_DPCD_QUIRK_CONSTANT_N));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -569,8 +569,7 @@ static int mei_hdcp_verify_mprime(struct device *dev,
|
|||||||
verify_mprime_in->header.api_version = HDCP_API_VERSION;
|
verify_mprime_in->header.api_version = HDCP_API_VERSION;
|
||||||
verify_mprime_in->header.command_id = WIRED_REPEATER_AUTH_STREAM_REQ;
|
verify_mprime_in->header.command_id = WIRED_REPEATER_AUTH_STREAM_REQ;
|
||||||
verify_mprime_in->header.status = ME_HDCP_STATUS_SUCCESS;
|
verify_mprime_in->header.status = ME_HDCP_STATUS_SUCCESS;
|
||||||
verify_mprime_in->header.buffer_len =
|
verify_mprime_in->header.buffer_len = cmd_size - sizeof(verify_mprime_in->header);
|
||||||
WIRED_CMD_BUF_LEN_REPEATER_AUTH_STREAM_REQ_MIN_IN;
|
|
||||||
|
|
||||||
verify_mprime_in->port.integrated_port_type = data->port_type;
|
verify_mprime_in->port.integrated_port_type = data->port_type;
|
||||||
verify_mprime_in->port.physical_port = (u8)data->fw_ddi;
|
verify_mprime_in->port.physical_port = (u8)data->fw_ddi;
|
||||||
|
|||||||
@@ -2029,16 +2029,13 @@ struct drm_dp_desc {
|
|||||||
|
|
||||||
int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc,
|
int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc,
|
||||||
bool is_branch);
|
bool is_branch);
|
||||||
u32 drm_dp_get_edid_quirks(const struct edid *edid);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum drm_dp_quirk - Display Port sink/branch device specific quirks
|
* enum drm_dp_quirk - Display Port sink/branch device specific quirks
|
||||||
*
|
*
|
||||||
* Display Port sink and branch devices in the wild have a variety of bugs, try
|
* Display Port sink and branch devices in the wild have a variety of bugs, try
|
||||||
* to collect them here. The quirks are shared, but it's up to the drivers to
|
* to collect them here. The quirks are shared, but it's up to the drivers to
|
||||||
* implement workarounds for them. Note that because some devices have
|
* implement workarounds for them.
|
||||||
* unreliable OUIDs, the EDID of sinks should also be checked for quirks using
|
|
||||||
* drm_dp_get_edid_quirks().
|
|
||||||
*/
|
*/
|
||||||
enum drm_dp_quirk {
|
enum drm_dp_quirk {
|
||||||
/**
|
/**
|
||||||
@@ -2070,16 +2067,6 @@ enum drm_dp_quirk {
|
|||||||
* The DSC caps can be read from the physical aux instead.
|
* The DSC caps can be read from the physical aux instead.
|
||||||
*/
|
*/
|
||||||
DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD,
|
DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD,
|
||||||
/**
|
|
||||||
* @DP_QUIRK_FORCE_DPCD_BACKLIGHT:
|
|
||||||
*
|
|
||||||
* The device is telling the truth when it says that it uses DPCD
|
|
||||||
* backlight controls, even if the system's firmware disagrees. This
|
|
||||||
* quirk should be checked against both the ident and panel EDID.
|
|
||||||
* When present, the driver should honor the DPCD backlight
|
|
||||||
* capabilities advertised.
|
|
||||||
*/
|
|
||||||
DP_QUIRK_FORCE_DPCD_BACKLIGHT,
|
|
||||||
/**
|
/**
|
||||||
* @DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS:
|
* @DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS:
|
||||||
*
|
*
|
||||||
@@ -2092,16 +2079,14 @@ enum drm_dp_quirk {
|
|||||||
/**
|
/**
|
||||||
* drm_dp_has_quirk() - does the DP device have a specific quirk
|
* drm_dp_has_quirk() - does the DP device have a specific quirk
|
||||||
* @desc: Device descriptor filled by drm_dp_read_desc()
|
* @desc: Device descriptor filled by drm_dp_read_desc()
|
||||||
* @edid_quirks: Optional quirk bitmask filled by drm_dp_get_edid_quirks()
|
|
||||||
* @quirk: Quirk to query for
|
* @quirk: Quirk to query for
|
||||||
*
|
*
|
||||||
* Return true if DP device identified by @desc has @quirk.
|
* Return true if DP device identified by @desc has @quirk.
|
||||||
*/
|
*/
|
||||||
static inline bool
|
static inline bool
|
||||||
drm_dp_has_quirk(const struct drm_dp_desc *desc, u32 edid_quirks,
|
drm_dp_has_quirk(const struct drm_dp_desc *desc, enum drm_dp_quirk quirk)
|
||||||
enum drm_dp_quirk quirk)
|
|
||||||
{
|
{
|
||||||
return (desc->quirks | edid_quirks) & BIT(quirk);
|
return desc->quirks & BIT(quirk);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_DRM_DP_CEC
|
#ifdef CONFIG_DRM_DP_CEC
|
||||||
|
|||||||
@@ -101,11 +101,11 @@
|
|||||||
|
|
||||||
/* Following Macros take a byte at a time for bit(s) masking */
|
/* Following Macros take a byte at a time for bit(s) masking */
|
||||||
/*
|
/*
|
||||||
* TODO: This has to be changed for DP MST, as multiple stream on
|
* TODO: HDCP_2_2_MAX_CONTENT_STREAMS_CNT is based upon actual
|
||||||
* same port is possible.
|
* H/W MST streams capacity.
|
||||||
* For HDCP2.2 on HDMI and DP SST this value is always 1.
|
* This required to be moved out to platform specific header.
|
||||||
*/
|
*/
|
||||||
#define HDCP_2_2_MAX_CONTENT_STREAMS_CNT 1
|
#define HDCP_2_2_MAX_CONTENT_STREAMS_CNT 4
|
||||||
#define HDCP_2_2_TXCAP_MASK_LEN 2
|
#define HDCP_2_2_TXCAP_MASK_LEN 2
|
||||||
#define HDCP_2_2_RXCAPS_LEN 3
|
#define HDCP_2_2_RXCAPS_LEN 3
|
||||||
#define HDCP_2_2_RX_REPEATER(x) ((x) & BIT(0))
|
#define HDCP_2_2_RX_REPEATER(x) ((x) & BIT(0))
|
||||||
|
|||||||
@@ -527,6 +527,25 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
#define I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS fourcc_mod_code(INTEL, 7)
|
#define I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS fourcc_mod_code(INTEL, 7)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Intel Color Control Surface with Clear Color (CCS) for Gen-12 render
|
||||||
|
* compression.
|
||||||
|
*
|
||||||
|
* The main surface is Y-tiled and is at plane index 0 whereas CCS is linear
|
||||||
|
* and at index 1. The clear color is stored at index 2, and the pitch should
|
||||||
|
* be ignored. The clear color structure is 256 bits. The first 128 bits
|
||||||
|
* represents Raw Clear Color Red, Green, Blue and Alpha color each represented
|
||||||
|
* by 32 bits. The raw clear color is consumed by the 3d engine and generates
|
||||||
|
* the converted clear color of size 64 bits. The first 32 bits store the Lower
|
||||||
|
* Converted Clear Color value and the next 32 bits store the Higher Converted
|
||||||
|
* Clear Color value when applicable. The Converted Clear Color values are
|
||||||
|
* consumed by the DE. The last 64 bits are used to store Color Discard Enable
|
||||||
|
* and Depth Clear Value Valid which are ignored by the DE. A CCS cache line
|
||||||
|
* corresponds to an area of 4x1 tiles in the main surface. The main surface
|
||||||
|
* pitch is required to be a multiple of 4 tile widths.
|
||||||
|
*/
|
||||||
|
#define I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC fourcc_mod_code(INTEL, 8)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tiled, NV12MT, grouped in 64 (pixels) x 32 (lines) -sized macroblocks
|
* Tiled, NV12MT, grouped in 64 (pixels) x 32 (lines) -sized macroblocks
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user