- Vswing / Pre-emphasis Override (Michal)

- Enable AS SDP Skip Frames (Uma)
 - Handle negative configuration index on DP link caps for robustness (Luca)
 - Perform full wedge on display reset (Ville)
 - PSR related revert and fix (Nemesa)
 - Preparation for enabling SDR plane color pipeline (Chaitanya, Pranay)
 - An eDP quirk for HP Pavilion Plus (Ankit)
 - DP MST fixes (Imre)
 - General display fixes and small improvements (Jani, Lalit, Vinod, Sebastian)
 - Introduce PME (Power Management Event) support on display hotplug (Vinod)
 - Force eDP sink awake on dpcd init (Arun)
 - Stop using the configurable fence timeout and other cleanups (Jani)
 - Add support for Common SDP Transmission Line (Ankit, Arun)
 - Map AUX power domains to DC_off (Suraj)
 - Handle VSC SDP revision 7 in unpack (Juasheem)
 - Disable VRR DC balance by default (Mitul)
 - Switch to modern drm_dp_dpcd* accessors (Jani)
 - Lg DPCD access errors (Suraj)
 - Fixes to make i915 work well with PREEMPT_RT (Maarten, Sebastian)
 - Update the CMN_SDP_TL in fastset path (Ankit)
 - Use a shared gtt_view_types.h header (Jani)
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEbSBwaO7dZQkcLOKj+mJfZA7rE8oFAmrAA8IACgkQ+mJfZA7r
 E8rItggAt2YC091NcyHoA31t9cSzr93+TGn8SRJEU1gB96YVWh0xUDsVDQux2yYS
 aNsIMS0+B9lfexM7vwlWiAQGV6HPpWp2B4GJ5AEc+BvLZpp2n1bXiKnBgO5VRvF3
 TTKpeKnhFUkuJfAYq1Glv+yfHpiXxzocvsowzvoTc+nI7ZN/McoShzH/B245b/Ko
 CuTQGvAanYziLdCbkvhr4sO39DWoKAyYtgfTywDRjgYcTS+2W/cx+EJV+8D0yZCJ
 W6MpuuSI/UY2R2w9l7QfNMNz42M8yHbgvsNdkg7JGsvZT8nkiBjMYFiBomIHe670
 rjVU2qSwOU0wEFdJEl4u5ia3weDpwA==
 =PrrV
 -----END PGP SIGNATURE-----

Merge tag 'drm-intel-next-2026-10-02' of https://gitlab.freedesktop.org/drm/i915/kernel into drm-next

[airlied: add xe fixup]
- Vswing / Pre-emphasis Override (Michal)
- Enable AS SDP Skip Frames (Uma)
- Handle negative configuration index on DP link caps for robustness (Luca)
- Perform full wedge on display reset (Ville)
- PSR related revert and fix (Nemesa)
- Preparation for enabling SDR plane color pipeline (Chaitanya, Pranay)
- An eDP quirk for HP Pavilion Plus (Ankit)
- DP MST fixes (Imre)
- General display fixes and small improvements (Jani, Lalit, Vinod, Sebastian)
- Introduce PME (Power Management Event) support on display hotplug (Vinod)
- Force eDP sink awake on dpcd init (Arun)
- Stop using the configurable fence timeout and other cleanups (Jani)
- Add support for Common SDP Transmission Line (Ankit, Arun)
- Map AUX power domains to DC_off (Suraj)
- Handle VSC SDP revision 7 in unpack (Juasheem)
- Disable VRR DC balance by default (Mitul)
- Switch to modern drm_dp_dpcd* accessors (Jani)
- Lg DPCD access errors (Suraj)
- Fixes to make i915 work well with PREEMPT_RT (Maarten, Sebastian)
- Update the CMN_SDP_TL in fastset path (Ankit)
- Use a shared gtt_view_types.h header (Jani)

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patch.msgid.link/asAD6RRGxlbIPdhz@intel.com
This commit is contained in:
Dave Airlie 2026-10-09 19:00:31 +10:00
commit f2bf20011b
79 changed files with 1987 additions and 779 deletions

View File

@ -349,6 +349,7 @@ i915-y += \
display/intel_cx0_phy.o \
display/intel_ddi.o \
display/intel_ddi_buf_trans.o \
display/intel_dip.o \
display/intel_display_device.o \
display/intel_display_trace.o \
display/intel_dkl_phy.o \

View File

@ -375,6 +375,142 @@ static u32 get_pr_alpm_as_sdp_transmission_time(const struct intel_crtc_state *c
}
}
/*
* Periodic Adaptive-Sync SDP skip frames.
*
* While Panel Replay is active the transcoder timing generator runs at the
* panel's maximum refresh rate. To drive the panel down to its minimum
* refresh rate the Adaptive-Sync SDP only needs to reach the panel once per
* minimum-rate frame, so transmitting it on every (maximum-rate) frame is
* unnecessary and shows up as repeated SDPs on the link. Program the HW skip
* counter so that a single AS SDP is followed by
* (max_vrefresh / min_vrefresh - 1) idle frames, i.e. one AS SDP per slowest
* panel frame.
*
* The maximum and minimum refresh rates come from the panel's adaptive-sync
* monitor range, so this is independent of the current content/flip rate.
*/
static u32 intel_pr_as_sdp_skip_frames(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
const struct drm_display_info *info =
&intel_dp->attached_connector->base.display_info;
int max_vrefresh = info->monitor_range.max_vfreq;
int min_vrefresh = info->monitor_range.min_vfreq;
/* Off by default; gated by the enable_periodic_assdp debugfs knob. */
if (!display->params.enable_periodic_assdp)
return 0;
if (min_vrefresh <= 0 || max_vrefresh <= min_vrefresh)
return 0;
return min_t(u32, max_vrefresh / min_vrefresh - 1,
REG_FIELD_MAX(PR_ALPM_CTL_AS_SDP_SKIP_FRAMES_MASK));
}
/*
* Whether periodic AS SDP transmission (AS SDP skip frames) will be programmed
* for this Panel Replay config. The skip counter needs the AS SDP to keep
* flowing during PR active, which is incompatible with DC3co, so this is used
* to keep DC3co disabled while skip frames is enabled.
*/
bool intel_alpm_pr_as_sdp_skip_frames_enabled(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(intel_dp);
/*
* The AS SDP skip frames field only exists on Xe3p_LPD+. Periodic AS SDP
* drives the panel down to its minimum refresh rate on its own, so it is
* only used when VRR is not actively driving the refresh rate.
*/
if (DISPLAY_VER(display) < 35 || !intel_dp->as_sdp_supported ||
!crtc_state->has_panel_replay || crtc_state->vrr.enable)
return false;
return intel_pr_as_sdp_skip_frames(intel_dp) > 0;
}
/*
* Program the AS SDP portion of PR_ALPM_CTL: the transmission position, the
* skip-frame counter and the coupled AS SDP transmission / DC3CO idle-protocol
* bits. This is a full recompute of those fields (the base value is built from
* scratch, not read back), so it can be called both at PR enable time and when
* VRR is toggled seamlessly - which changes whether periodic AS SDP is used.
*
* Caller must hold intel_dp->alpm.lock.
*/
static void intel_alpm_configure_pr_as_sdp(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(intel_dp);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
u32 pr_alpm_ctl = get_pr_alpm_as_sdp_transmission_time(crtc_state);
u32 skip_frames = 0;
if (intel_alpm_pr_as_sdp_skip_frames_enabled(intel_dp, crtc_state))
skip_frames = intel_pr_as_sdp_skip_frames(intel_dp);
if (crtc_state->link_off_after_as_sdp_when_pr_active)
pr_alpm_ctl |= PR_ALPM_CTL_ALLOW_LINK_OFF_BETWEEN_AS_SDP_AND_SU;
/*
* Skip frames needs the AS SDP to keep flowing during PR active, so it
* is mutually exclusive with disabling AS SDP transmission in active and
* with the DC3CO idle protocol.
*/
if (skip_frames) {
pr_alpm_ctl |= PR_ALPM_CTL_AS_SDP_SKIP_FRAMES(skip_frames);
pr_alpm_ctl &= ~PR_ALPM_CTL_AS_SDP_TRANSMISSION_IN_ACTIVE_DISABLE;
pr_alpm_ctl &= ~PR_ALPM_CTL_USE_DC3CO_IDLE_PROTOCOL;
} else {
pr_alpm_ctl &= ~PR_ALPM_CTL_AS_SDP_SKIP_FRAMES_MASK;
if (crtc_state->disable_as_sdp_when_pr_active)
pr_alpm_ctl |= PR_ALPM_CTL_AS_SDP_TRANSMISSION_IN_ACTIVE_DISABLE;
if (intel_display_power_dc3co_allowed(display))
pr_alpm_ctl |= PR_ALPM_CTL_USE_DC3CO_IDLE_PROTOCOL;
}
intel_de_write(display, PR_ALPM_CTL(display, cpu_transcoder), pr_alpm_ctl);
}
/*
* VRR can be enabled or disabled seamlessly, i.e. without a modeset and without
* cycling Panel Replay, so the AS SDP skip-frame programming done at PR enable
* time would otherwise go stale across a VRR toggle. Reprogram it here so the
* skip counter (and the coupled bits) matches the new VRR state.
*/
void intel_alpm_pr_as_sdp_update(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
struct intel_encoder *encoder;
/* AS SDP skip frames field only exists on Xe3p_LPD+ */
if (DISPLAY_VER(display) < 35)
return;
for_each_intel_encoder_mask(display->drm, encoder,
crtc_state->uapi.encoder_mask) {
struct intel_dp *intel_dp;
if (!intel_encoder_is_dp(encoder))
continue;
intel_dp = enc_to_intel_dp(encoder);
if (!intel_dp->as_sdp_supported ||
!intel_alpm_is_alpm_aux_less(intel_dp, crtc_state))
continue;
mutex_lock(&intel_dp->alpm.lock);
intel_alpm_configure_pr_as_sdp(intel_dp, crtc_state);
mutex_unlock(&intel_dp->alpm.lock);
}
}
static void lnl_alpm_configure(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state)
{
@ -397,22 +533,8 @@ static void lnl_alpm_configure(struct intel_dp *intel_dp,
ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_50_SYMBOLS |
ALPM_CTL_AUX_LESS_WAKE_TIME(crtc_state->alpm_state.aux_less_wake_lines);
if (intel_dp->as_sdp_supported) {
u32 pr_alpm_ctl = get_pr_alpm_as_sdp_transmission_time(crtc_state);
if (crtc_state->link_off_after_as_sdp_when_pr_active)
pr_alpm_ctl |= PR_ALPM_CTL_ALLOW_LINK_OFF_BETWEEN_AS_SDP_AND_SU;
if (crtc_state->disable_as_sdp_when_pr_active)
pr_alpm_ctl |= PR_ALPM_CTL_AS_SDP_TRANSMISSION_IN_ACTIVE_DISABLE;
if (intel_display_power_dc3co_allowed(display))
pr_alpm_ctl |= PR_ALPM_CTL_USE_DC3CO_IDLE_PROTOCOL;
else
pr_alpm_ctl &= ~PR_ALPM_CTL_USE_DC3CO_IDLE_PROTOCOL;
intel_de_write(display, PR_ALPM_CTL(display, cpu_transcoder),
pr_alpm_ctl);
}
if (intel_dp->as_sdp_supported)
intel_alpm_configure_pr_as_sdp(intel_dp, crtc_state);
} else {
alpm_ctl = ALPM_CTL_EXTENDED_FAST_WAKE_ENABLE |
@ -506,7 +628,7 @@ void intel_alpm_enable_sink(struct intel_dp *intel_dp,
intel_alpm_aux_less_wake_supported(intel_dp)))
val |= DP_ALPM_MODE_AUX_LESS;
drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, val);
drm_dp_dpcd_write_byte(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, val);
}
void intel_alpm_lobf_enable(const struct intel_crtc_state *new_crtc_state)
@ -629,12 +751,12 @@ bool intel_alpm_get_error(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
struct drm_dp_aux *aux = &intel_dp->aux;
int ret;
u8 val;
int r;
r = drm_dp_dpcd_readb(aux, DP_RECEIVER_ALPM_STATUS, &val);
if (r != 1) {
drm_err(display->drm, "Error reading ALPM status\n");
ret = drm_dp_dpcd_read_byte(aux, DP_RECEIVER_ALPM_STATUS, &val);
if (ret < 0) {
drm_err(display->drm, "Error reading ALPM status (%pe)\n", ERR_PTR(ret));
return true;
}
@ -642,7 +764,7 @@ bool intel_alpm_get_error(struct intel_dp *intel_dp)
drm_dbg_kms(display->drm, "ALPM lock timeout error\n");
/* Clearing error */
drm_dp_dpcd_writeb(aux, DP_RECEIVER_ALPM_STATUS, val);
drm_dp_dpcd_write_byte(aux, DP_RECEIVER_ALPM_STATUS, val);
return true;
}

View File

@ -34,6 +34,9 @@ bool intel_alpm_aux_wake_supported(struct intel_dp *intel_dp);
bool intel_alpm_aux_less_wake_supported(struct intel_dp *intel_dp);
bool intel_alpm_is_alpm_aux_less(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state);
bool intel_alpm_pr_as_sdp_skip_frames_enabled(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state);
void intel_alpm_pr_as_sdp_update(const struct intel_crtc_state *crtc_state);
void intel_alpm_disable(struct intel_dp *intel_dp);
bool intel_alpm_get_error(struct intel_dp *intel_dp);
void intel_alpm_lobf_compute_config_late(struct intel_dp *intel_dp,

View File

@ -34,6 +34,7 @@
#include <drm/drm_fixed.h>
#include <drm/drm_print.h>
#include "intel_ddi_buf_trans.h"
#include "intel_display.h"
#include "intel_display_core.h"
#include "intel_display_rpm.h"
@ -72,6 +73,8 @@
struct intel_bios_encoder_data {
struct intel_display *display;
struct intel_ddi_buf_trans *vspeo;
union intel_ddi_buf_trans_entry *entries;
struct child_device_config child;
struct dsc_compression_parameters_entry *dsc;
struct list_head node;
@ -200,6 +203,8 @@ static const struct {
.min_size = sizeof(struct bdb_mipi_sequence) },
{ .section_id = BDB_COMPRESSION_PARAMETERS,
.min_size = sizeof(struct bdb_compression_parameters), },
{ .section_id = BDB_VSWING_PREEMPH,
.min_size = sizeof(struct bdb_vswing_preemph), },
{ .section_id = BDB_GENERIC_DTD,
.min_size = sizeof(struct bdb_generic_dtd), },
};
@ -2203,6 +2208,31 @@ parse_compression_parameters(struct intel_display *display)
}
}
static int vswing_preemph_num_rows(struct intel_display *display)
{
return DISPLAY_VER(display) >= 14 ? 16 : 10;
}
static void
parse_vswing_preemph_override(struct intel_display *display)
{
const struct bdb_vswing_preemph *block;
if (display->vbt.version < 218)
return;
block = bdb_find_section(display, BDB_VSWING_PREEMPH);
/* pre-ICL GOPs don't have VBT #57 */
if (!block)
return;
display->vbt.vspeo.tables = block->tables;
display->vbt.vspeo.num_tables = block->num_tables;
display->vbt.vspeo.num_columns = block->num_columns;
display->vbt.vspeo.num_rows = vswing_preemph_num_rows(display);
}
static u8 translate_iboost(struct intel_display *display, u8 val)
{
static const u8 mapping[] = { 1, 3, 7 }; /* See VBT spec */
@ -2621,6 +2651,30 @@ static void sanitize_device_type(struct intel_bios_encoder_data *devdata,
devdata->child.device_type |= DEVICE_TYPE_NOT_HDMI_OUTPUT;
}
static void allocate_vswing_preemph_override(struct intel_bios_encoder_data *devdata)
{
int num_rows = devdata->display->vbt.vspeo.num_rows;
union intel_ddi_buf_trans_entry *entries;
struct intel_ddi_buf_trans *vspeo;
if (!intel_bios_encoder_requests_vspeo(devdata))
return;
vspeo = kzalloc_obj(*vspeo);
if (!vspeo)
return;
entries = kzalloc_objs(*entries, num_rows);
if (!entries) {
kfree(vspeo);
return;
}
devdata->entries = entries;
devdata->vspeo = vspeo;
devdata->vspeo->num_entries = num_rows;
}
static void sanitize_hdmi_level_shift(struct intel_bios_encoder_data *devdata,
enum port port)
{
@ -2737,7 +2791,6 @@ static bool is_port_valid(struct intel_display *display, enum port port)
static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
{
struct intel_display *display = devdata->display;
const struct child_device_config *child = &devdata->child;
bool is_dvi, is_hdmi, is_dp, is_edp, is_dsi, is_crt, supports_typec_usb, supports_tbt;
int dp_boost_level, dp_max_link_rate, hdmi_boost_level, hdmi_level_shift, max_tmds_clock;
enum port port;
@ -2774,6 +2827,11 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
"Port %c supports dynamic DDI allocation in TCSS\n",
port_name(port));
if (intel_bios_encoder_requests_vspeo(devdata))
drm_dbg_kms(display->drm,
"Port %c requests vswing/pre-emphasis override\n",
port_name(port));
hdmi_level_shift = intel_bios_hdmi_level_shift(devdata);
if (hdmi_level_shift >= 0) {
drm_dbg_kms(display->drm,
@ -2805,14 +2863,6 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
drm_dbg_kms(display->drm,
"Port %c VBT DP max link rate: %d\n",
port_name(port), dp_max_link_rate);
/*
* FIXME need to implement support for VBT
* vswing/preemph tables should this ever trigger.
*/
drm_WARN(display->drm, child->use_vbt_vswing,
"Port %c asks to use VBT vswing/preemph tables\n",
port_name(port));
}
static void parse_ddi_port(struct intel_bios_encoder_data *devdata)
@ -2834,6 +2884,7 @@ static void parse_ddi_port(struct intel_bios_encoder_data *devdata)
sanitize_dedicated_external(devdata, port);
sanitize_device_type(devdata, port);
sanitize_hdmi_level_shift(devdata, port);
allocate_vswing_preemph_override(devdata);
}
static bool has_ddi_port_info(struct intel_display *display)
@ -3291,6 +3342,7 @@ void intel_bios_init(struct intel_display *display)
parse_general_features(display);
parse_general_definitions(display);
parse_driver_features(display);
parse_vswing_preemph_override(display);
/* Depends on child device list */
parse_compression_parameters(display);
@ -3370,6 +3422,9 @@ void intel_bios_driver_remove(struct intel_display *display)
list_for_each_entry_safe(devdata, nd, &display->vbt.display_devices,
node) {
list_del(&devdata->node);
kfree(devdata->entries);
kfree(devdata->vspeo);
kfree(devdata->dsc);
kfree(devdata);
}
@ -3801,6 +3856,11 @@ int intel_bios_hdmi_ddc_pin(const struct intel_bios_encoder_data *devdata)
return map_ddc_pin(devdata->display, devdata->child.ddc_pin);
}
bool intel_bios_encoder_requests_vspeo(const struct intel_bios_encoder_data *devdata)
{
return devdata->display->vbt.version >= 218 && devdata->child.use_vbt_vswing;
}
bool intel_bios_encoder_supports_typec_usb(const struct intel_bios_encoder_data *devdata)
{
return devdata->display->vbt.version >= 195 && devdata->child.dp_usb_type_c;
@ -3811,6 +3871,190 @@ bool intel_bios_encoder_supports_tbt(const struct intel_bios_encoder_data *devda
return devdata->display->vbt.version >= 209 && devdata->child.tbt;
}
static bool
validate_vspeo(const struct intel_bios_encoder_data *devdata, bool has_dp)
{
struct intel_ddi_buf_trans *vspeo;
vspeo = devdata->vspeo;
if (!vspeo)
return false;
if (!has_dp)
return false;
return true;
}
const struct intel_ddi_buf_trans *
intel_bios_get_c20_vspeo(const struct intel_bios_encoder_data *devdata,
bool has_dp, bool is_uhbr)
{
struct intel_display *display = devdata->display;
union intel_ddi_buf_trans_entry *entries = devdata->entries;
struct intel_ddi_buf_trans *vspeo = devdata->vspeo;
const u32 *tables = display->vbt.vspeo.tables;
int num_columns = display->vbt.vspeo.num_columns;
int num_rows = display->vbt.vspeo.num_rows;
int idx = is_uhbr ? 5 : 4;
size_t offset = 0;
int level;
if (!validate_vspeo(devdata, has_dp))
return NULL;
offset += idx * num_rows * num_columns;
for (level = 0; level < num_rows; level++) {
u32 vswing = tables[offset];
u32 pre_cursor = tables[offset + 1];
u32 post_cursor = tables[offset + 2];
entries[level].snps.vswing = vswing;
entries[level].snps.pre_cursor = pre_cursor;
entries[level].snps.post_cursor = post_cursor;
offset += num_columns;
}
vspeo->entries = entries;
return vspeo;
}
const struct intel_ddi_buf_trans *
intel_bios_get_c10_vspeo(const struct intel_bios_encoder_data *devdata,
bool has_dp, int port_clock, bool has_edp)
{
struct intel_display *display = devdata->display;
union intel_ddi_buf_trans_entry *entries = devdata->entries;
struct intel_ddi_buf_trans *vspeo = devdata->vspeo;
const u32 *tables = display->vbt.vspeo.tables;
int num_columns = display->vbt.vspeo.num_columns;
int num_rows = display->vbt.vspeo.num_rows;
size_t offset = 0;
int level, idx;
if (!validate_vspeo(devdata, has_dp))
return NULL;
if (has_edp)
idx = port_clock > 540000 ? 3 : 2;
else
idx = port_clock > 270000 ? 1 : 0;
offset += idx * num_rows * num_columns;
for (level = 0; level < num_rows; level++) {
u32 vswing = tables[offset];
u32 pre_cursor = tables[offset + 1];
u32 post_cursor = tables[offset + 2];
entries[level].snps.vswing = vswing;
entries[level].snps.pre_cursor = pre_cursor;
entries[level].snps.post_cursor = post_cursor;
offset += num_columns;
}
vspeo->entries = entries;
return vspeo;
}
const struct intel_ddi_buf_trans *
intel_bios_get_ehl_combo_vspeo(const struct intel_bios_encoder_data *devdata,
bool has_dp, int port_clock, bool low_vswing_edp)
{
struct intel_display *display = devdata->display;
union intel_ddi_buf_trans_entry *entries = devdata->entries;
struct intel_ddi_buf_trans *vspeo = devdata->vspeo;
const u32 *tables = display->vbt.vspeo.tables;
int num_columns = display->vbt.vspeo.num_columns;
int num_rows = display->vbt.vspeo.num_rows;
size_t offset = 0;
int level, idx;
if (!validate_vspeo(devdata, has_dp))
return NULL;
if (low_vswing_edp)
idx = port_clock > 540000 ? 2 : 1;
else
idx = port_clock > 270000 ? 1 : 0;
offset += idx * num_rows * num_columns;
for (level = 0; level < num_rows; level++) {
u32 dw2_swing_sel = tables[offset];
u32 dw7_n_scalar = tables[offset + 1];
u32 dw4_cursor_coeff = tables[offset + 2];
u32 dw4_post_cursor_2 = tables[offset + 3];
u32 dw4_post_cursor_1 = tables[offset + 4];
entries[level].icl.dw2_swing_sel = dw2_swing_sel;
entries[level].icl.dw7_n_scalar = dw7_n_scalar;
entries[level].icl.dw4_cursor_coeff = dw4_cursor_coeff;
entries[level].icl.dw4_post_cursor_2 = dw4_post_cursor_2;
entries[level].icl.dw4_post_cursor_1 = dw4_post_cursor_1;
offset += num_columns;
}
vspeo->entries = entries;
return vspeo;
}
const struct intel_ddi_buf_trans *
intel_bios_get_jsl_combo_vspeo(const struct intel_bios_encoder_data *devdata,
bool has_dp, int port_clock, bool low_vswing_edp)
{
struct intel_display *display = devdata->display;
union intel_ddi_buf_trans_entry *entries = devdata->entries;
struct intel_ddi_buf_trans *vspeo = devdata->vspeo;
const u32 *tables = display->vbt.vspeo.tables;
int num_columns = display->vbt.vspeo.num_columns;
int num_rows = display->vbt.vspeo.num_rows;
size_t offset = 0;
int idx = 0;
int level;
if (!validate_vspeo(devdata, has_dp))
return NULL;
if (low_vswing_edp) {
if (port_clock > 540000)
idx = 0;
else if (port_clock > 270000)
idx = 2;
else
idx = 1;
}
offset += idx * num_rows * num_columns;
for (level = 0; level < num_rows; level++) {
u32 dw2_swing_sel = tables[offset];
u32 dw7_n_scalar = tables[offset + 1];
u32 dw4_cursor_coeff = tables[offset + 2];
u32 dw4_post_cursor_2 = tables[offset + 3];
u32 dw4_post_cursor_1 = tables[offset + 4];
entries[level].icl.dw2_swing_sel = dw2_swing_sel;
entries[level].icl.dw7_n_scalar = dw7_n_scalar;
entries[level].icl.dw4_cursor_coeff = dw4_cursor_coeff;
entries[level].icl.dw4_post_cursor_2 = dw4_post_cursor_2;
entries[level].icl.dw4_post_cursor_1 = dw4_post_cursor_1;
offset += num_columns;
}
vspeo->entries = entries;
return vspeo;
}
bool intel_bios_encoder_is_dedicated_external(const struct intel_bios_encoder_data *devdata)
{
return devdata->display->vbt.version >= 264 &&

View File

@ -73,6 +73,20 @@ bool intel_bios_get_dsc_params(struct intel_encoder *encoder,
const struct intel_bios_encoder_data *
intel_bios_encoder_data_lookup(struct intel_display *display, enum port port);
const struct intel_ddi_buf_trans *
intel_bios_get_c20_vspeo(const struct intel_bios_encoder_data *devdata,
bool has_dp, bool is_uhbr);
const struct intel_ddi_buf_trans *
intel_bios_get_c10_vspeo(const struct intel_bios_encoder_data *devdata,
bool has_dp, int port_clock, bool has_edp);
const struct intel_ddi_buf_trans *
intel_bios_get_ehl_combo_vspeo(const struct intel_bios_encoder_data *devdata,
bool has_dp, int port_clock, bool low_vswing_edp);
const struct intel_ddi_buf_trans *
intel_bios_get_jsl_combo_vspeo(const struct intel_bios_encoder_data *devdata,
bool has_dp, int port_clock, bool low_vswing_edp);
bool intel_bios_encoder_requests_vspeo(const struct intel_bios_encoder_data *devdata);
bool intel_bios_encoder_supports_dvi(const struct intel_bios_encoder_data *devdata);
bool intel_bios_encoder_supports_hdmi(const struct intel_bios_encoder_data *devdata);
bool intel_bios_encoder_supports_dp(const struct intel_bios_encoder_data *devdata);

View File

@ -3998,25 +3998,17 @@ xelpd_program_plane_pre_csc_lut(struct intel_dsb *dsb,
}
static void
xelpd_program_plane_post_csc_lut(struct intel_dsb *dsb,
const struct intel_plane_state *plane_state)
xelpd_load_hdr_post_csc_lut(struct intel_display *display,
struct intel_dsb *dsb,
enum pipe pipe,
enum plane_id plane,
const struct drm_color_lut32 *post_csc_lut)
{
struct intel_display *display = to_intel_display(plane_state);
const struct drm_plane_state *state = &plane_state->uapi;
enum pipe pipe = to_intel_plane(state->plane)->pipe;
enum plane_id plane = to_intel_plane(state->plane)->id;
const struct drm_color_lut32 *post_csc_lut = plane_state->hw.gamma_lut->data;
int i, lut_size = 32;
u32 lut_val;
if (!icl_is_hdr_plane(display, plane))
return;
intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, 0),
PLANE_PAL_PREC_AUTO_INCREMENT);
/* TODO: Add macro */
intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, 0),
PLANE_PAL_PREC_AUTO_INCREMENT);
for (i = 0; i < lut_size + 3; i++) {
if (post_csc_lut) {
@ -4036,8 +4028,62 @@ xelpd_program_plane_post_csc_lut(struct intel_dsb *dsb,
}
intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, 0), 0);
intel_de_write_dsb(display, dsb,
PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, 0), 0);
}
static void
xelpd_load_sdr_post_csc_lut(struct intel_display *display,
struct intel_dsb *dsb,
enum pipe pipe,
enum plane_id plane,
const struct drm_color_lut32 *post_csc_lut)
{
int i, lut_size = 32;
u32 lut_val;
/*
* First 3 planes are HDR, so reduce by 3 to get to the right
* SDR plane offset
*/
plane = plane - 3;
intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX(pipe, plane, 0),
PLANE_PAL_PREC_AUTO_INCREMENT);
for (i = 0; i < lut_size + 3; i++) {
if (post_csc_lut) {
if (i < lut_size)
lut_val = drm_color_lut32_extract(post_csc_lut[i].green, 16);
/* else duplicate last lut_val */
} else {
if (i < lut_size)
lut_val = (i * ((1 << 16) - 1)) / (lut_size - 1);
else
lut_val = 1 << 16;
}
intel_de_write_dsb(display, dsb,
PLANE_POST_CSC_GAMC_DATA(pipe, plane, 0),
lut_val);
}
intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX(pipe, plane, 0), 0);
}
static void
xelpd_program_plane_post_csc_lut(struct intel_dsb *dsb,
const struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane_state);
const struct drm_plane_state *state = &plane_state->uapi;
enum pipe pipe = to_intel_plane(state->plane)->pipe;
enum plane_id plane = to_intel_plane(state->plane)->id;
const struct drm_color_lut32 *post_csc_lut = plane_state->hw.gamma_lut ?
plane_state->hw.gamma_lut->data : NULL;
if (icl_is_hdr_plane(display, plane))
xelpd_load_hdr_post_csc_lut(display, dsb, pipe, plane, post_csc_lut);
else
xelpd_load_sdr_post_csc_lut(display, dsb, pipe, plane, post_csc_lut);
}
static void

View File

@ -12,7 +12,7 @@
#include "skl_universal_plane.h"
#define MAX_COLOR_PIPELINES 1
#define MAX_COLOROP 4
#define MAX_COLOROP 5
#define PLANE_DEGAMMA_SIZE 128
#define PLANE_GAMMA_SIZE 32
@ -31,6 +31,7 @@ static const struct drm_colorop_funcs intel_colorop_funcs = {
* the pipeline totally unusable.
*/
static const enum intel_color_block xe3plpd_primary_plane_pipeline[] = {
INTEL_PLANE_CB_CSC_FF,
INTEL_PLANE_CB_PRE_CSC_LUT,
INTEL_PLANE_CB_CSC,
INTEL_PLANE_CB_3DLUT,
@ -38,11 +39,25 @@ static const enum intel_color_block xe3plpd_primary_plane_pipeline[] = {
};
static const enum intel_color_block hdr_plane_pipeline[] = {
INTEL_PLANE_CB_CSC_FF,
INTEL_PLANE_CB_PRE_CSC_LUT,
INTEL_PLANE_CB_CSC,
INTEL_PLANE_CB_POST_CSC_LUT,
};
static const enum intel_color_block sdr_plane_yuv_pipeline[] = {
INTEL_PLANE_CB_CSC_FF,
INTEL_PLANE_CB_POST_CSC_LUT,
};
static const u64 intel_plane_supported_csc_ff =
BIT(DRM_COLOROP_FM_YCBCR601_FULL_RGB) |
BIT(DRM_COLOROP_FM_YCBCR601_LIMITED_RGB) |
BIT(DRM_COLOROP_FM_YCBCR709_FULL_RGB) |
BIT(DRM_COLOROP_FM_YCBCR709_LIMITED_RGB) |
BIT(DRM_COLOROP_FM_YCBCR2020_NC_FULL_RGB) |
BIT(DRM_COLOROP_FM_YCBCR2020_NC_LIMITED_RGB);
static bool plane_has_3dlut(struct intel_display *display, enum pipe pipe,
struct drm_plane *plane)
{
@ -92,6 +107,12 @@ struct intel_colorop *intel_color_pipeline_plane_add_colorop(struct drm_plane *p
DRM_COLOROP_LUT1D_INTERPOLATION_LINEAR,
DRM_COLOROP_FLAG_ALLOW_BYPASS);
break;
case INTEL_PLANE_CB_CSC_FF:
ret = drm_plane_colorop_fixed_matrix_init(dev, &colorop->base, plane,
&intel_colorop_funcs,
intel_plane_supported_csc_ff,
DRM_COLOROP_FLAG_ALLOW_BYPASS);
break;
default:
drm_err(plane->dev, "Invalid colorop id [%d]", id);
ret = -EINVAL;
@ -126,9 +147,12 @@ int _intel_color_pipeline_plane_init(struct drm_plane *plane, struct drm_prop_en
if (plane_has_3dlut(display, pipe, plane)) {
pipeline = xe3plpd_primary_plane_pipeline;
pipeline_len = ARRAY_SIZE(xe3plpd_primary_plane_pipeline);
} else {
} else if (icl_is_hdr_plane(display, to_intel_plane(plane)->id)) {
pipeline = hdr_plane_pipeline;
pipeline_len = ARRAY_SIZE(hdr_plane_pipeline);
} else {
pipeline = sdr_plane_yuv_pipeline;
pipeline_len = ARRAY_SIZE(sdr_plane_yuv_pipeline);
}
for (i = 0; i < pipeline_len; i++) {
@ -155,17 +179,11 @@ int _intel_color_pipeline_plane_init(struct drm_plane *plane, struct drm_prop_en
int intel_color_pipeline_plane_init(struct drm_plane *plane, enum pipe pipe)
{
struct drm_device *dev = plane->dev;
struct intel_display *display = to_intel_display(dev);
struct drm_prop_enum_list pipelines[MAX_COLOR_PIPELINES] = {};
int len = 0;
int ret = 0;
int i;
/* Currently expose pipeline only for HDR planes */
if (!icl_is_hdr_plane(display, to_intel_plane(plane)->id))
return 0;
/* Add pipeline consisting of transfer functions */
ret = _intel_color_pipeline_plane_init(plane, &pipelines[len], pipe);
if (ret)

View File

@ -251,6 +251,15 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config,
str_enabled_disabled(pipe_config->has_panel_replay),
str_enabled_disabled(pipe_config->enable_psr2_sel_fetch));
drm_printf(&p, "minimum hblank: %d\n", pipe_config->min_hblank);
drm_printf(&p, "DIP Transmission Lines: EMP/AS SDP: %u\n",
pipe_config->dip.emp_as_sdp_tl);
drm_printf(&p, "DIP Transmission Lines: Common Base SDP: %u, GMP SDP: %u, PPS SDP: %u, VSC SDP: %u, VSC_EXT SDP: %u\n",
pipe_config->dip.cmn_sdp_tl,
pipe_config->dip.gmp_sdp_tl,
pipe_config->dip.pps_sdp_tl,
pipe_config->dip.vsc_sdp_tl,
pipe_config->dip.vsc_ext_sdp_tl);
}
drm_printf(&p, "audio: %i, infoframes: %i, infoframes enabled: 0x%x\n",

View File

@ -5,6 +5,7 @@
#include <linux/log2.h>
#include <linux/math64.h>
#include <linux/string_choices.h>
#include <drm/drm_print.h>
@ -189,7 +190,7 @@ int intel_cx0_wait_for_ack(struct intel_encoder *encoder,
drm_dbg_kms(display->drm,
"PHY %c Error occurred during %s command. Status: 0x%x\n",
phy_name(phy),
command == XELPDP_PORT_P2M_COMMAND_READ_ACK ? "read" : "write", *val);
str_read_write(command == XELPDP_PORT_P2M_COMMAND_READ_ACK), *val);
intel_cx0_bus_reset(encoder, lane);
return -EINVAL;
}
@ -198,7 +199,7 @@ int intel_cx0_wait_for_ack(struct intel_encoder *encoder,
drm_dbg_kms(display->drm,
"PHY %c Not a %s response. MSGBUS Status: 0x%x.\n",
phy_name(phy),
command == XELPDP_PORT_P2M_COMMAND_READ_ACK ? "read" : "write", *val);
str_read_write(command == XELPDP_PORT_P2M_COMMAND_READ_ACK), *val);
intel_cx0_bus_reset(encoder, lane);
return -EINVAL;
}

View File

@ -49,6 +49,7 @@
#include "intel_ddi.h"
#include "intel_ddi_buf_trans.h"
#include "intel_de.h"
#include "intel_dip.h"
#include "intel_display_power.h"
#include "intel_display_regs.h"
#include "intel_display_types.h"
@ -2331,15 +2332,17 @@ static void intel_dp_sink_set_msa_timing_par_ignore_state(struct intel_dp *intel
bool enable)
{
struct intel_display *display = to_intel_display(intel_dp);
int ret;
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)
ret = drm_dp_dpcd_write_byte(&intel_dp->aux, DP_DOWNSPREAD_CTRL,
enable ? DP_MSA_TIMING_PAR_IGNORE_EN : 0);
if (ret < 0)
drm_dbg_kms(display->drm,
"Failed to %s MSA_TIMING_PAR_IGNORE in the sink\n",
str_enable_disable(enable));
"Failed to %s MSA_TIMING_PAR_IGNORE in the sink (%pe)\n",
str_enable_disable(enable), ERR_PTR(ret));
}
static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp,
@ -2347,19 +2350,25 @@ static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp,
bool enable)
{
struct intel_display *display = to_intel_display(intel_dp);
int ret;
if (!crtc_state->fec_enable)
return;
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION,
enable ? DP_FEC_READY : 0) <= 0)
drm_dbg_kms(display->drm, "Failed to set FEC_READY to %s in the sink\n",
str_enabled_disabled(enable));
ret = drm_dp_dpcd_write_byte(&intel_dp->aux, DP_FEC_CONFIGURATION,
enable ? DP_FEC_READY : 0);
if (ret < 0)
drm_dbg_kms(display->drm, "Failed to set FEC_READY to %s in the sink (%pe)\n",
str_enabled_disabled(enable), ERR_PTR(ret));
if (enable &&
drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_STATUS,
DP_FEC_DECODE_EN_DETECTED | DP_FEC_DECODE_DIS_DETECTED) <= 0)
drm_dbg_kms(display->drm, "Failed to clear FEC detected flags\n");
if (enable) {
ret = drm_dp_dpcd_write_byte(&intel_dp->aux, DP_FEC_STATUS,
DP_FEC_DECODE_EN_DETECTED |
DP_FEC_DECODE_DIS_DETECTED);
if (ret < 0)
drm_dbg_kms(display->drm, "Failed to clear FEC detected flags (%pe)\n",
ERR_PTR(ret));
}
}
static int wait_for_fec_detected(struct drm_dp_aux *aux, bool enabled)
@ -2736,6 +2745,8 @@ static void mtl_ddi_pre_enable_dp(struct intel_atomic_state *state,
/* 6.o Configure and enable FEC if needed */
intel_ddi_enable_fec(encoder, crtc_state);
intel_dip_cmn_sdp_transmission_line_enable(crtc_state);
/* 7.a 128b/132b SST. */
if (!is_mst && intel_dp_is_uhbr(crtc_state)) {
/* VCPID 1, start slot 0 for 128b/132b, tu slots */
@ -3123,6 +3134,7 @@ static void intel_ddi_buf_disable(struct intel_encoder *encoder,
DP_TP_CTL_ENABLE, 0);
}
intel_dip_cmn_sdp_transmission_line_disable(crtc_state);
intel_ddi_disable_fec(encoder, crtc_state);
if (DISPLAY_VER(display) < 14)
@ -4235,6 +4247,7 @@ static void intel_ddi_get_config(struct intel_encoder *encoder,
intel_read_dp_sdp(encoder, pipe_config, HDMI_PACKET_TYPE_GAMUT_METADATA);
intel_read_dp_sdp(encoder, pipe_config, DP_SDP_VSC);
intel_read_dp_sdp(encoder, pipe_config, DP_SDP_ADAPTIVE_SYNC);
intel_dip_sdp_transmission_line_get_config(pipe_config);
intel_audio_codec_get_config(encoder, pipe_config);
}

View File

@ -1784,6 +1784,70 @@ xe3plpd_get_lt_buf_trans(struct intel_encoder *encoder,
return intel_get_buf_trans(&xe3plpd_lt_trans_dp14, n_entries);
}
static const struct intel_ddi_buf_trans *
jsl_get_combo_buf_trans_override(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
int *n_entries)
{
const struct intel_bios_encoder_data *devdata = encoder->devdata;
bool has_edp, has_dp;
int port_clock;
has_edp = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP);
has_dp = intel_crtc_has_dp_encoder(crtc_state);
port_clock = crtc_state->port_clock;
return intel_bios_get_jsl_combo_vspeo(devdata, has_dp, port_clock,
has_edp && use_edp_low_vswing(encoder));
}
static const struct intel_ddi_buf_trans *
ehl_get_combo_buf_trans_override(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
int *n_entries)
{
const struct intel_bios_encoder_data *devdata = encoder->devdata;
bool has_edp, has_dp;
int port_clock;
has_edp = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP);
has_dp = intel_crtc_has_dp_encoder(crtc_state);
port_clock = crtc_state->port_clock;
return intel_bios_get_ehl_combo_vspeo(devdata, has_dp, port_clock,
has_edp && use_edp_low_vswing(encoder));
}
static const struct intel_ddi_buf_trans *
mtl_get_c10_buf_trans_override(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
int *n_entries)
{
const struct intel_bios_encoder_data *devdata = encoder->devdata;
bool has_edp, has_dp;
int port_clock;
has_edp = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP);
has_dp = intel_crtc_has_dp_encoder(crtc_state);
port_clock = crtc_state->port_clock;
return intel_bios_get_c10_vspeo(devdata, has_dp, port_clock, has_edp);
}
static const struct intel_ddi_buf_trans *
mtl_get_c20_buf_trans_override(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
int *n_entries)
{
const struct intel_bios_encoder_data *devdata = encoder->devdata;
bool has_dp, is_uhbr;
has_dp = intel_crtc_has_dp_encoder(crtc_state);
is_uhbr = intel_dp_is_uhbr(crtc_state);
return intel_bios_get_c20_vspeo(devdata, has_dp, is_uhbr);
}
void intel_ddi_buf_trans_init(struct intel_encoder *encoder)
{
struct intel_display *display = to_intel_display(encoder);
@ -1791,10 +1855,13 @@ void intel_ddi_buf_trans_init(struct intel_encoder *encoder)
if (HAS_LT_PHY(display)) {
encoder->get_buf_trans = xe3plpd_get_lt_buf_trans;
} else if (DISPLAY_VER(display) >= 14) {
if (intel_encoder_is_c10phy(encoder))
if (intel_encoder_is_c10phy(encoder)) {
encoder->get_buf_trans = mtl_get_c10_buf_trans;
else
encoder->get_buf_trans_override = mtl_get_c10_buf_trans_override;
} else {
encoder->get_buf_trans = mtl_get_c20_buf_trans;
encoder->get_buf_trans_override = mtl_get_c20_buf_trans_override;
}
} else if (display->platform.dg2) {
encoder->get_buf_trans = dg2_get_snps_buf_trans;
} else if (display->platform.alderlake_p) {
@ -1814,14 +1881,17 @@ void intel_ddi_buf_trans_init(struct intel_encoder *encoder)
else
encoder->get_buf_trans = tgl_get_dkl_buf_trans;
} else if (DISPLAY_VER(display) == 11) {
if (display->platform.jasperlake)
if (display->platform.jasperlake) {
encoder->get_buf_trans = jsl_get_combo_buf_trans;
else if (display->platform.elkhartlake)
encoder->get_buf_trans_override = jsl_get_combo_buf_trans_override;
} else if (display->platform.elkhartlake) {
encoder->get_buf_trans = ehl_get_combo_buf_trans;
else if (intel_encoder_is_combo(encoder))
encoder->get_buf_trans_override = ehl_get_combo_buf_trans_override;
} else if (intel_encoder_is_combo(encoder)) {
encoder->get_buf_trans = icl_get_combo_buf_trans;
else
} else {
encoder->get_buf_trans = icl_get_mg_buf_trans;
}
} else if (display->platform.geminilake || display->platform.broxton) {
encoder->get_buf_trans = bxt_get_buf_trans;
} else if (display->platform.cometlake_ulx ||
@ -1857,5 +1927,13 @@ const struct intel_ddi_buf_trans *intel_ddi_buf_trans_get(struct intel_encoder *
const struct intel_crtc_state *crtc_state,
int *n_entries)
{
if (encoder->get_buf_trans_override) {
const struct intel_ddi_buf_trans *override;
override = encoder->get_buf_trans_override(encoder, crtc_state, n_entries);
if (override)
return intel_get_buf_trans(override, n_entries);
}
return encoder->get_buf_trans(encoder, crtc_state, n_entries);
}

View File

@ -0,0 +1,215 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2026 Intel Corporation
*
*/
#include <drm/drm_print.h>
#include "intel_de.h"
#include "intel_dip.h"
#include "intel_dip_regs.h"
#include "intel_display_types.h"
#include "intel_hdmi.h"
static int intel_dip_get_as_sdp_transmission_line(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
if (!HAS_EMP_AS_SDP_TL(display))
return 0;
/*
* EMP_AS_SDP_TL defines the T1 position as the default AS SDP
* Transmission Line, which corresponds to the start of the
* VSYNC pulse.
*
* Use the T1 position for now.
*/
return crtc_state->vrr.vsync_start;
}
u16 intel_dip_read_emp_as_sdp_tl(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
u32 val;
if (!HAS_EMP_AS_SDP_TL(display))
return 0;
val = intel_de_read(display, EMP_AS_SDP_TL(display, cpu_transcoder));
return REG_FIELD_GET(EMP_AS_SDP_DB_TL_MASK, val);
}
void intel_dip_write_emp_as_sdp_tl(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
if (!HAS_EMP_AS_SDP_TL(display))
return;
intel_de_write(display,
EMP_AS_SDP_TL(display, cpu_transcoder),
EMP_AS_SDP_DB_TL(crtc_state->dip.emp_as_sdp_tl));
}
static int intel_dip_sdp_stagger_to_tl(struct intel_crtc_state *crtc_state,
int stagger)
{
return crtc_state->dip.cmn_sdp_tl + stagger;
}
static
void intel_dip_cmn_sdp_tl_compute_config_late(struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
bool as_sdp;
if (!HAS_COMMON_SDP_TL(display))
return;
as_sdp = crtc_state->infoframes.enable &
intel_hdmi_infoframe_enable(DP_SDP_ADAPTIVE_SYNC);
/*
* When AS SDP is enabled :
* - The common SDP Transmission Line matches the EMP SDP Transmission Line.
*
* When AS SDP is disabled:
* - Bspec mentions the positions as lines of delayed vblank.
* - Guardband = 1st line of delayed vblank
* - Common SDP Transmission line is set to 2nd line of delayed vblank.
*/
if (as_sdp)
crtc_state->dip.cmn_sdp_tl = crtc_state->dip.emp_as_sdp_tl;
else
crtc_state->dip.cmn_sdp_tl = crtc_state->vrr.guardband - 1;
if (drm_WARN_ON(display->drm,
crtc_state->dip.cmn_sdp_tl >=
crtc_state->vrr.guardband + crtc_state->set_context_latency))
return;
/*
* Currently we are programming the default stagger values, but these
* can be optimized if required, based on number of SDPs enabled.
*
* Default values of the Transmission lines for SDPs other than AS SDP:
* VSC : CMN SDP Transmission line
* GMP : CMN SDP Transmission line
* PPS : CMN SDP Transmission line + 1
* VSC_EXT: CMN SDP Transmission line + 2
*/
crtc_state->dip.vsc_sdp_tl = crtc_state->dip.cmn_sdp_tl;
crtc_state->dip.gmp_sdp_tl =
intel_dip_sdp_stagger_to_tl(crtc_state, GMP_STAGGER_DEFAULT);
crtc_state->dip.pps_sdp_tl =
intel_dip_sdp_stagger_to_tl(crtc_state, PPS_STAGGER_DEFAULT);
crtc_state->dip.vsc_ext_sdp_tl =
intel_dip_sdp_stagger_to_tl(crtc_state, VSC_EXT_STAGGER_DEFAULT);
}
void intel_dip_sdp_tl_compute_config_late(struct intel_crtc_state *crtc_state)
{
crtc_state->dip.emp_as_sdp_tl = intel_dip_get_as_sdp_transmission_line(crtc_state);
intel_dip_cmn_sdp_tl_compute_config_late(crtc_state);
}
static
void intel_dip_cmn_sdp_transmission_line_get_config(struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
u16 vsc_ext_stagger, pps_stagger, gmp_stagger;
u32 val;
if (!HAS_COMMON_SDP_TL(display))
return;
val = intel_de_read(display, CMN_SDP_TL(display, cpu_transcoder));
if (!(val & TRANSMISSION_LINE_ENABLE))
return;
crtc_state->dip.cmn_sdp_tl = REG_FIELD_GET(BASE_TRANSMISSION_LINE_MASK, val);
/* SDP VSC uses same transmission line as CMN base transmission line */
crtc_state->dip.vsc_sdp_tl = crtc_state->dip.cmn_sdp_tl;
val = intel_de_read(display, CMN_SDP_TL_STGR_CTL(display, cpu_transcoder));
vsc_ext_stagger = REG_FIELD_GET(VSC_EXT_STAGGER_MASK, val);
pps_stagger = REG_FIELD_GET(PPS_STAGGER_MASK, val);
gmp_stagger = REG_FIELD_GET(GMP_STAGGER_MASK, val);
crtc_state->dip.vsc_ext_sdp_tl =
intel_dip_sdp_stagger_to_tl(crtc_state, vsc_ext_stagger);
crtc_state->dip.pps_sdp_tl =
intel_dip_sdp_stagger_to_tl(crtc_state, pps_stagger);
crtc_state->dip.gmp_sdp_tl =
intel_dip_sdp_stagger_to_tl(crtc_state, gmp_stagger);
}
void intel_dip_sdp_transmission_line_get_config(struct intel_crtc_state *crtc_state)
{
crtc_state->dip.emp_as_sdp_tl = intel_dip_read_emp_as_sdp_tl(crtc_state);
intel_dip_cmn_sdp_transmission_line_get_config(crtc_state);
}
static int intel_dip_sdp_tl_to_stagger(const struct intel_crtc_state *crtc_state,
u16 sdp_transmission_line)
{
return sdp_transmission_line - crtc_state->dip.cmn_sdp_tl;
}
void intel_dip_cmn_sdp_transmission_line_enable(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
int gmp_stagger;
int pps_stagger;
int vsc_ext_stagger;
if (!HAS_COMMON_SDP_TL(display))
return;
gmp_stagger = intel_dip_sdp_tl_to_stagger(crtc_state,
crtc_state->dip.gmp_sdp_tl);
pps_stagger = intel_dip_sdp_tl_to_stagger(crtc_state,
crtc_state->dip.pps_sdp_tl);
vsc_ext_stagger = intel_dip_sdp_tl_to_stagger(crtc_state,
crtc_state->dip.vsc_ext_sdp_tl);
if (drm_WARN_ON(display->drm, gmp_stagger < 0))
return;
if (drm_WARN_ON(display->drm, pps_stagger < 0))
return;
if (drm_WARN_ON(display->drm, vsc_ext_stagger < 0))
return;
intel_de_write(display, CMN_SDP_TL_STGR_CTL(display, cpu_transcoder),
GMP_STAGGER(gmp_stagger) |
PPS_STAGGER(pps_stagger) |
VSC_EXT_STAGGER(vsc_ext_stagger));
intel_de_write(display, CMN_SDP_TL(display, cpu_transcoder),
TRANSMISSION_LINE_ENABLE |
BASE_TRANSMISSION_LINE(crtc_state->dip.cmn_sdp_tl));
}
void intel_dip_cmn_sdp_transmission_line_disable(const struct intel_crtc_state *old_crtc_state)
{
struct intel_display *display = to_intel_display(old_crtc_state);
enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;
if (!HAS_COMMON_SDP_TL(display))
return;
intel_de_write(display, CMN_SDP_TL(display, cpu_transcoder), 0);
}

View File

@ -0,0 +1,53 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2026 Intel Corporation
*/
#ifndef __INTEL_DIP_H__
#define __INTEL_DIP_H__
#include "intel_display_device.h"
/*
* Video DIP (Data Island Packet) helpers.
*
* This file contains helpers for programming video DIP related hardware.
*
* TODO: Currently, this is only used for programming EMP_AS_SDP_TL i.e. to
* program Transmission Line for HDMI 2.1 Extended Metadata Packet (EMP) and
* DP Adaptive Sync (AS) Secondary Data Packet (SDP). However, all low level
* DIP buffer read/write and related helpers should be extracted here later.
*/
struct intel_crtc_state;
/*
* EMP AS SDP TL: Extended Metadata Packet (EMP) Adaptive Sync (AS)
* Secondary Data Packet (SDP) Transmission Line (TL).
*
* Starting with BMG (display ver 14.01) and LNL+ (display ver 20+),
* the AS SDP transmission line is programmable via the EMP AS SDP TL
* register.
*/
#define HAS_EMP_AS_SDP_TL(__display) (DISPLAY_VERx100(__display) == 1401 || \
DISPLAY_VER(__display) >= 20)
/*
* CMN SDP TL: Common Secondary Data Packet Transmission Line.
*
* Xe3p_lpd introduces new register CMN_SDP_TL to program a common SDP
* Transmission line that will be used by the Hardware to position the
* SDPs. Along with this, another new register CMN_SDP_TL_STGR_CTL is
* also added to stagger the different SDPs.
*/
#define HAS_COMMON_SDP_TL(__display) (DISPLAY_VER(__display) >= 35)
u16 intel_dip_read_emp_as_sdp_tl(const struct intel_crtc_state *crtc_state);
void intel_dip_write_emp_as_sdp_tl(const struct intel_crtc_state *crtc_state);
void intel_dip_sdp_tl_compute_config_late(struct intel_crtc_state *crtc_state);
void intel_dip_sdp_transmission_line_get_config(struct intel_crtc_state *crtc_state);
void intel_dip_cmn_sdp_transmission_line_enable(const struct intel_crtc_state *crtc_state);
void intel_dip_cmn_sdp_transmission_line_disable(const struct intel_crtc_state *old_crtc_state);
#endif /* __INTEL_DIP_H__ */

View File

@ -0,0 +1,38 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2026 Intel Corporation
*/
#ifndef __INTEL_DIP_REGS_H__
#define __INTEL_DIP_REGS_H__
#include "intel_display_reg_defs.h"
/* EMP (Extended Metadata Packet) AS (Adaptive Sync) SDP Transmission Line */
#define _EMP_AS_SDP_TL_A 0x60204
#define EMP_AS_SDP_TL(display, trans) _MMIO_TRANS2((display), (trans), _EMP_AS_SDP_TL_A)
#define EMP_AS_SDP_DB_TL_MASK REG_GENMASK(12, 0)
#define EMP_AS_SDP_DB_TL(db_transmit_line) REG_FIELD_PREP(EMP_AS_SDP_DB_TL_MASK, \
(db_transmit_line))
/* COMMON SDP TRANSMISSION LINE */
#define _CMN_SDP_TL_A 0x6020c
#define CMN_SDP_TL(display, trans) _MMIO_TRANS2(display, (trans), _CMN_SDP_TL_A)
#define TRANSMISSION_LINE_ENABLE REG_BIT(31)
#define BASE_TRANSMISSION_LINE_MASK REG_GENMASK(12, 0)
#define BASE_TRANSMISSION_LINE(x) REG_FIELD_PREP(BASE_TRANSMISSION_LINE_MASK, x)
#define _CMN_SDP_TL_STGR_CTL_A 0x60214
#define CMN_SDP_TL_STGR_CTL(display, trans) _MMIO_TRANS2(display, (trans), \
_CMN_SDP_TL_STGR_CTL_A)
#define VSC_EXT_STAGGER_MASK REG_GENMASK(11, 8)
#define VSC_EXT_STAGGER(x) REG_FIELD_PREP(VSC_EXT_STAGGER_MASK, x)
#define VSC_EXT_STAGGER_DEFAULT 0x2
#define PPS_STAGGER_MASK REG_GENMASK(7, 4)
#define PPS_STAGGER(x) REG_FIELD_PREP(PPS_STAGGER_MASK, x)
#define PPS_STAGGER_DEFAULT 0x1
#define GMP_STAGGER_MASK REG_GENMASK(3, 0)
#define GMP_STAGGER(x) REG_FIELD_PREP(GMP_STAGGER_MASK, x)
#define GMP_STAGGER_DEFAULT 0x0
#endif /* __INTEL_DIP_REGS_H__ */

View File

@ -50,7 +50,6 @@
#include "g4x_dp.h"
#include "g4x_hdmi.h"
#include "hsw_ips.h"
#include "i915_config.h"
#include "i9xx_plane.h"
#include "i9xx_plane_regs.h"
#include "i9xx_wm.h"
@ -70,6 +69,7 @@
#include "intel_cx0_phy.h"
#include "intel_ddi.h"
#include "intel_de.h"
#include "intel_dip.h"
#include "intel_display_driver.h"
#include "intel_display_power.h"
#include "intel_display_regs.h"
@ -1000,6 +1000,15 @@ static bool cmrr_params_changed(const struct intel_crtc_state *old_crtc_state,
old_crtc_state->vrr.cmrr.cmrr_n != new_crtc_state->vrr.cmrr.cmrr_n;
}
static bool cmn_sdp_changed(const struct intel_crtc_state *old_crtc_state,
const struct intel_crtc_state *new_crtc_state)
{
return old_crtc_state->dip.cmn_sdp_tl != new_crtc_state->dip.cmn_sdp_tl ||
old_crtc_state->dip.gmp_sdp_tl != new_crtc_state->dip.gmp_sdp_tl ||
old_crtc_state->dip.pps_sdp_tl != new_crtc_state->dip.pps_sdp_tl ||
old_crtc_state->dip.vsc_ext_sdp_tl != new_crtc_state->dip.vsc_ext_sdp_tl;
}
static bool intel_crtc_vrr_enabling(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
@ -1232,6 +1241,14 @@ static void intel_pre_plane_update(struct intel_atomic_state *state,
intel_vrr_disable(old_crtc_state);
intel_vrr_dcb_reset(old_crtc_state, crtc);
intel_crtc_update_active_timings(old_crtc_state, false);
/*
* VRR is being disabled seamlessly (no modeset, Panel Replay
* stays enabled), so re-apply the AS SDP skip-frame programming
* for the new (VRR off) state.
*/
if (!intel_crtc_needs_modeset(new_crtc_state))
intel_alpm_pr_as_sdp_update(new_crtc_state);
}
if (audio_disabling(old_crtc_state, new_crtc_state))
@ -5594,6 +5611,12 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_I(vrr.dc_balance.max_increase);
PIPE_CONF_CHECK_I(vrr.dc_balance.max_decrease);
PIPE_CONF_CHECK_I(vrr.dc_balance.vblank_target);
PIPE_CONF_CHECK_I(dip.emp_as_sdp_tl);
PIPE_CONF_CHECK_I(dip.gmp_sdp_tl);
PIPE_CONF_CHECK_I(dip.pps_sdp_tl);
PIPE_CONF_CHECK_I(dip.vsc_sdp_tl);
PIPE_CONF_CHECK_I(dip.vsc_ext_sdp_tl);
PIPE_CONF_CHECK_I(dip.cmn_sdp_tl);
}
if (!fastset || intel_vrr_always_use_vrr_tg(display)) {
@ -6911,6 +6934,9 @@ static void intel_pre_update_crtc(struct intel_atomic_state *state,
if (vrr_params_changed(old_crtc_state, new_crtc_state) ||
cmrr_params_changed(old_crtc_state, new_crtc_state))
intel_vrr_set_transcoder_timings(new_crtc_state);
if (cmn_sdp_changed(old_crtc_state, new_crtc_state))
intel_dip_cmn_sdp_transmission_line_enable(new_crtc_state);
}
intel_fbc_update(state, crtc);
@ -6971,6 +6997,16 @@ static void intel_update_crtc(struct intel_atomic_state *state,
intel_crtc_update_active_timings(new_crtc_state,
new_crtc_state->vrr.enable);
/*
* VRR is being enabled seamlessly (no modeset, Panel Replay stays
* enabled), so re-apply the AS SDP skip-frame programming for the new
* (VRR on) state. Done here, outside the vblank-evasion critical section
* (which runs with interrupts disabled), because it takes alpm.lock.
*/
if (intel_crtc_vrr_enabling(state, crtc) &&
!intel_crtc_needs_modeset(new_crtc_state))
intel_alpm_pr_as_sdp_update(new_crtc_state);
if (new_crtc_state->vrr.dc_balance.enable)
intel_vrr_dcb_increment_flip_count(new_crtc_state, crtc);
@ -7271,23 +7307,27 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)
drm_WARN_ON(display->drm, update_pipes);
}
static void intel_atomic_commit_fence_wait(struct intel_atomic_state *intel_state)
static void intel_atomic_commit_fence_wait(struct intel_atomic_state *state)
{
struct intel_display *display = to_intel_display(state);
struct drm_plane *plane;
struct drm_plane_state *new_plane_state;
long ret;
int i;
for_each_new_plane_in_state(&intel_state->base, plane, new_plane_state, i) {
if (new_plane_state->fence) {
ret = dma_fence_wait_timeout(new_plane_state->fence, false,
i915_fence_timeout());
if (ret <= 0)
break;
for_each_new_plane_in_state(&state->base, plane, new_plane_state, i) {
if (!new_plane_state->fence)
continue;
dma_fence_put(new_plane_state->fence);
new_plane_state->fence = NULL;
ret = dma_fence_wait(new_plane_state->fence, false);
if (ret < 0) {
drm_dbg_kms(display->drm, "[PLANE:%d:%s] fence wait failed (%pe)\n",
plane->base.id, plane->name, ERR_PTR(ret));
break;
}
dma_fence_put(new_plane_state->fence);
new_plane_state->fence = NULL;
}
}

View File

@ -244,6 +244,13 @@ struct intel_vbt_data {
struct list_head display_devices;
struct list_head bdb_blocks;
struct {
const u32 *tables;
int num_tables;
int num_columns;
int num_rows;
} vspeo;
struct sdvo_device_mapping {
u8 initialized;
u8 dvo_port;

View File

@ -2217,8 +2217,10 @@ static void gen11_display_irq_reset(struct intel_display *display)
enum pipe pipe;
u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) |
BIT(TRANSCODER_C) | BIT(TRANSCODER_D);
bool reset_hpd = !intel_display_rpm_pme_enabled(display);
intel_de_write(display, GEN11_DISPLAY_INT_CTL, 0);
if (reset_hpd)
intel_de_write(display, GEN11_DISPLAY_INT_CTL, 0);
if (DISPLAY_VER(display) >= 12) {
enum transcoder trans;
@ -2250,13 +2252,15 @@ static void gen11_display_irq_reset(struct intel_display *display)
irq_reset(display, GEN8_DE_PORT_IRQ_REGS);
irq_reset(display, GEN8_DE_MISC_IRQ_REGS);
if (DISPLAY_VER(display) >= 14)
irq_reset(display, PICAINTERRUPT_IRQ_REGS);
else
irq_reset(display, GEN11_DE_HPD_IRQ_REGS);
if (reset_hpd) {
if (DISPLAY_VER(display) >= 14)
irq_reset(display, PICAINTERRUPT_IRQ_REGS);
else
irq_reset(display, GEN11_DE_HPD_IRQ_REGS);
if (INTEL_PCH_TYPE(display) >= PCH_ICP)
irq_reset(display, SDE_IRQ_REGS);
if (INTEL_PCH_TYPE(display) >= PCH_ICP)
irq_reset(display, SDE_IRQ_REGS);
}
}
void gen8_irq_power_well_post_enable(struct intel_display *display,

View File

@ -169,6 +169,7 @@ enum aux_ch {
enum intel_color_block {
INTEL_PLANE_CB_PRE_CSC_LUT,
INTEL_PLANE_CB_CSC,
INTEL_PLANE_CB_CSC_FF,
INTEL_PLANE_CB_POST_CSC_LUT,
INTEL_PLANE_CB_3DLUT,

View File

@ -51,6 +51,11 @@ struct drm_printer;
param(bool, psr_safest_params, false, 0400) \
param(bool, enable_psr2_sel_fetch, true, 0400) \
param(int, enable_dmc_wl, -1, 0400) \
/*
* Debugfs-only knob (per-device): no matching module_param is registered
* in intel_display_params.c on purpose. Runtime-toggle via debugfs.
*/ \
param(bool, enable_periodic_assdp, false, 0600) \
#define MEMBER(T, member, ...) T member;
struct intel_display_params {

View File

@ -10,6 +10,7 @@
#include <drm/intel/intel_pcode_regs.h>
#include <drm/intel/step.h>
#include "intel_alpm.h"
#include "intel_backlight_regs.h"
#include "intel_cdclk.h"
#include "intel_clock_gating.h"
@ -488,6 +489,14 @@ void intel_display_power_dc3co_compute(struct intel_atomic_state *state)
if (crtc_state->has_sel_update)
trigger |= DC3CO_TRIGGER_PSR2;
/*
* Periodic AS SDP (skip frames) needs the AS SDP to keep flowing during
* PR active, which is incompatible with DC3co. Keep DC3co disabled while
* skip frames is enabled.
*/
if (intel_alpm_pr_as_sdp_skip_frames_enabled(intel_dp, crtc_state))
trigger = DC3CO_TRIGGER_NONE;
done:
intel_display_power_dc3co_update(display, trigger);
}

View File

@ -1759,6 +1759,44 @@ static const struct i915_power_well_desc_list wcl_power_wells[] = {
I915_PW_DESCRIPTORS(wcl_power_wells_aux),
};
I915_DECL_PW_DOMAINS(xe3plpd_pwdoms_dc_off,
POWER_DOMAIN_DC_OFF,
XE3LPD_PW_2_POWER_DOMAINS,
XE3LPD_PW_C_POWER_DOMAINS,
XE3LPD_PW_D_POWER_DOMAINS,
POWER_DOMAIN_AUDIO_MMIO,
POWER_DOMAIN_AUDIO_PLAYBACK,
POWER_DOMAIN_AUX_A,
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_AUX_USBC1,
POWER_DOMAIN_AUX_USBC2,
POWER_DOMAIN_AUX_USBC3,
POWER_DOMAIN_AUX_USBC4,
POWER_DOMAIN_AUX_TBT1,
POWER_DOMAIN_AUX_TBT2,
POWER_DOMAIN_AUX_TBT3,
POWER_DOMAIN_AUX_TBT4,
POWER_DOMAIN_INIT);
static const struct i915_power_well_desc xe3plpd_power_wells_dcoff[] = {
{
.instances = &I915_PW_INSTANCES(
I915_PW("DC_off", &xe3plpd_pwdoms_dc_off,
.id = SKL_DISP_DC_OFF),
),
.ops = &gen9_dc_off_power_well_ops,
},
};
static const struct i915_power_well_desc_list xe3plpd_power_wells[] = {
I915_PW_DESCRIPTORS(i9xx_power_wells_always_on),
I915_PW_DESCRIPTORS(icl_power_wells_pw_1),
I915_PW_DESCRIPTORS(xe3plpd_power_wells_dcoff),
I915_PW_DESCRIPTORS(xe3lpd_power_wells_main),
I915_PW_DESCRIPTORS(xe2lpd_power_wells_pica),
I915_PW_DESCRIPTORS(xelpdp_power_wells_aux),
};
static void init_power_well_domains(const struct i915_power_well_instance *inst,
struct i915_power_well *power_well)
{
@ -1865,7 +1903,9 @@ int intel_display_power_map_init(struct i915_power_domains *power_domains)
return 0;
}
if (DISPLAY_VERx100(display) == 3002)
if (DISPLAY_VER(display) >= 35)
return set_power_wells(power_domains, xe3plpd_power_wells);
else if (DISPLAY_VERx100(display) == 3002)
return set_power_wells(power_domains, wcl_power_wells);
else if (DISPLAY_VER(display) >= 30)
return set_power_wells(power_domains, xe3lpd_power_wells);

View File

@ -46,6 +46,13 @@ bool intel_display_rpm_suspended(struct intel_display *display)
return display->parent->rpm->suspended(display->drm);
}
bool intel_display_rpm_pme_enabled(struct intel_display *display)
{
const struct intel_display_rpm_interface *rpm = display->parent->rpm;
return rpm->pme_enabled && rpm->pme_enabled(display->drm);
}
void assert_display_rpm_held(struct intel_display *display)
{
display->parent->rpm->assert_held(display->drm);

View File

@ -21,6 +21,7 @@ void intel_display_rpm_put(struct intel_display *display, struct ref_tracker *wa
/* Only for special cases. */
bool intel_display_rpm_suspended(struct intel_display *display);
bool intel_display_rpm_pme_enabled(struct intel_display *display);
void assert_display_rpm_held(struct intel_display *display);
void intel_display_rpm_assert_block(struct intel_display *display);

View File

@ -41,10 +41,10 @@
#include <drm/drm_panel.h>
#include <drm/drm_rect.h>
#include <drm/drm_vblank_work.h>
#include <drm/intel/gtt_view_types.h>
#include <drm/intel/i915_hdcp_interface.h>
#include <uapi/drm/i915_drm.h>
#include "i915_gtt_view_types.h"
#include "intel_bios.h"
#include "intel_display.h"
#include "intel_display_conversion.h"
@ -111,7 +111,7 @@ struct intel_fb_view {
* In the normal view the FB object's backing store sg list is used
* directly and hence the remap information here is not used.
*/
struct i915_gtt_view gtt;
struct intel_gtt_view gtt;
/*
* The GTT view (gtt.type) specific information for each FB color
@ -289,6 +289,9 @@ struct intel_encoder {
*/
enum icl_port_dpll_id (*port_pll_type)(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state);
const struct intel_ddi_buf_trans *(*get_buf_trans_override)(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
int *n_entries);
const struct intel_ddi_buf_trans *(*get_buf_trans)(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
int *n_entries);
@ -683,6 +686,7 @@ struct intel_plane_state {
enum drm_color_range color_range;
enum drm_scaling_filter scaling_filter;
struct drm_property_blob *ctm, *degamma_lut, *gamma_lut, *lut_3d;
bool csc_ff_enable;
} hw;
struct i915_vma *ggtt_vma;
@ -1003,6 +1007,20 @@ struct intel_casf {
bool enable;
};
struct intel_dip {
/*
* DIP Transmission line, relative to the Vtotal.
* The programmed transmit line is (Vtotal - value)
*/
u16 emp_as_sdp_tl;
u16 gmp_sdp_tl;
u16 pps_sdp_tl;
u16 vsc_sdp_tl;
u16 vsc_ext_sdp_tl;
/* Common SDP Base transmission line (Xe3p_lpd+) */
u16 cmn_sdp_tl;
};
struct intel_crtc_state {
/*
* uapi (drm) state. This is the software state shown to userspace.
@ -1311,6 +1329,8 @@ struct intel_crtc_state {
struct drm_dp_as_sdp as_sdp;
} infoframes;
struct intel_dip dip;
u8 eld[MAX_ELD_BYTES];
/* HDMI scrambling status */

View File

@ -61,6 +61,8 @@
#include "intel_cx0_phy.h"
#include "intel_ddi.h"
#include "intel_de.h"
#include "intel_dip.h"
#include "intel_dip_regs.h"
#include "intel_display_driver.h"
#include "intel_display_jiffies.h"
#include "intel_display_utils.h"
@ -3734,19 +3736,19 @@ static bool downstream_hpd_needs_d0(struct intel_dp *intel_dp)
static int
write_dsc_decompression_flag(struct drm_dp_aux *aux, u8 flag, bool set)
{
int err;
int ret;
u8 val;
err = drm_dp_dpcd_readb(aux, DP_DSC_ENABLE, &val);
if (err < 0)
return err;
ret = drm_dp_dpcd_read_byte(aux, DP_DSC_ENABLE, &val);
if (ret < 0)
return ret;
if (set)
val |= flag;
else
val &= ~flag;
return drm_dp_dpcd_writeb(aux, DP_DSC_ENABLE, val);
return drm_dp_dpcd_write_byte(aux, DP_DSC_ENABLE, val);
}
static void
@ -3910,6 +3912,7 @@ intel_dp_init_source_oui(struct intel_dp *intel_dp)
struct intel_display *display = to_intel_display(intel_dp);
u8 oui[] = { 0x00, 0xaa, 0x01 };
u8 buf[3] = {};
int ret;
if (READ_ONCE(intel_dp->oui_valid))
return;
@ -3920,8 +3923,9 @@ intel_dp_init_source_oui(struct intel_dp *intel_dp)
* During driver init, we want to be careful and avoid changing the source OUI if it's
* already set to what we want, so as to avoid clearing any state by accident
*/
if (drm_dp_dpcd_read(&intel_dp->aux, DP_SOURCE_OUI, buf, sizeof(buf)) < 0)
drm_dbg_kms(display->drm, "Failed to read source OUI\n");
ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_SOURCE_OUI, buf, sizeof(buf));
if (ret < 0)
drm_dbg_kms(display->drm, "Failed to read source OUI (%pe)\n", ERR_PTR(ret));
if (memcmp(oui, buf, sizeof(oui)) == 0) {
/* Assume the OUI was written now. */
@ -3929,8 +3933,9 @@ intel_dp_init_source_oui(struct intel_dp *intel_dp)
return;
}
if (drm_dp_dpcd_write(&intel_dp->aux, DP_SOURCE_OUI, oui, sizeof(oui)) < 0) {
drm_dbg_kms(display->drm, "Failed to write source OUI\n");
ret = drm_dp_dpcd_write_data(&intel_dp->aux, DP_SOURCE_OUI, oui, sizeof(oui));
if (ret < 0) {
drm_dbg_kms(display->drm, "Failed to write source OUI (%pe)\n", ERR_PTR(ret));
WRITE_ONCE(intel_dp->oui_valid, false);
}
@ -3971,7 +3976,7 @@ void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode)
if (downstream_hpd_needs_d0(intel_dp))
return;
ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, mode);
ret = drm_dp_dpcd_write_byte(&intel_dp->aux, DP_SET_POWER, mode);
} else {
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
@ -3985,21 +3990,21 @@ void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode)
* time to wake up.
*/
for (i = 0; i < 3; i++) {
ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, mode);
if (ret == 1)
ret = drm_dp_dpcd_write_byte(&intel_dp->aux, DP_SET_POWER, mode);
if (!ret)
break;
msleep(1);
}
if (ret == 1 && intel_lspcon_active(dig_port))
if (!ret && intel_lspcon_active(dig_port))
intel_lspcon_wait_pcon_mode(dig_port);
}
if (ret != 1)
if (ret < 0)
drm_dbg_kms(display->drm,
"[ENCODER:%d:%s] Set power to %s failed\n",
"[ENCODER:%d:%s] Set power to %s failed (%pe)\n",
encoder->base.base.id, encoder->base.name,
mode == DP_SET_POWER_D0 ? "D0" : "D3");
mode == DP_SET_POWER_D0 ? "D0" : "D3", ERR_PTR(ret));
}
static bool
@ -4086,6 +4091,7 @@ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder,
static void intel_dp_get_pcon_dsc_cap(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
int ret;
/* Clear the cached register set to avoid using stale values */
@ -4094,11 +4100,12 @@ static void intel_dp_get_pcon_dsc_cap(struct intel_dp *intel_dp)
if (!drm_dp_is_branch(intel_dp->dpcd))
return;
if (drm_dp_dpcd_read(&intel_dp->aux, DP_PCON_DSC_ENCODER,
intel_dp->pcon_dsc_dpcd,
sizeof(intel_dp->pcon_dsc_dpcd)) < 0)
drm_err(display->drm, "Failed to read DPCD register 0x%x\n",
DP_PCON_DSC_ENCODER);
ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_PCON_DSC_ENCODER,
intel_dp->pcon_dsc_dpcd,
sizeof(intel_dp->pcon_dsc_dpcd));
if (ret < 0)
drm_err(display->drm, "Failed to read DPCD register 0x%x (%pe)\n",
DP_PCON_DSC_ENCODER, ERR_PTR(ret));
drm_dbg_kms(display->drm, "PCON ENCODER DSC DPCD: %*ph\n",
(int)sizeof(intel_dp->pcon_dsc_dpcd), intel_dp->pcon_dsc_dpcd);
@ -4255,13 +4262,13 @@ int intel_dp_pcon_set_tmds_mode(struct intel_dp *intel_dp)
/* Set PCON source control mode */
buf |= DP_PCON_ENABLE_SOURCE_CTL_MODE;
ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_PCON_HDMI_LINK_CONFIG_1, buf);
ret = drm_dp_dpcd_write_byte(&intel_dp->aux, DP_PCON_HDMI_LINK_CONFIG_1, buf);
if (ret < 0)
return ret;
/* Set HDMI LINK ENABLE */
buf |= DP_PCON_ENABLE_HDMI_LINK;
ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_PCON_HDMI_LINK_CONFIG_1, buf);
ret = drm_dp_dpcd_write_byte(&intel_dp->aux, DP_PCON_HDMI_LINK_CONFIG_1, buf);
if (ret < 0)
return ret;
@ -4407,6 +4414,7 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
bool ycbcr444_to_420 = false;
bool rgb_to_ycbcr = false;
u8 tmp;
int ret;
if (intel_dp->dpcd[DP_DPCD_REV] < 0x13)
return;
@ -4416,11 +4424,13 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
tmp = intel_dp_has_hdmi_sink(intel_dp) ? DP_HDMI_DVI_OUTPUT_CONFIG : 0;
if (drm_dp_dpcd_writeb(&intel_dp->aux,
DP_PROTOCOL_CONVERTER_CONTROL_0, tmp) != 1)
ret = drm_dp_dpcd_write_byte(&intel_dp->aux,
DP_PROTOCOL_CONVERTER_CONTROL_0, tmp);
if (ret < 0)
drm_dbg_kms(display->drm,
"Failed to %s protocol converter HDMI mode\n",
str_enable_disable(intel_dp_has_hdmi_sink(intel_dp)));
"Failed to %s protocol converter HDMI mode (%pe)\n",
str_enable_disable(intel_dp_has_hdmi_sink(intel_dp)),
ERR_PTR(ret));
if (crtc_state->sink_format == INTEL_OUTPUT_FORMAT_YCBCR420) {
switch (crtc_state->output_format) {
@ -4452,26 +4462,29 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
tmp = ycbcr444_to_420 ? DP_CONVERSION_TO_YCBCR420_ENABLE : 0;
if (drm_dp_dpcd_writeb(&intel_dp->aux,
DP_PROTOCOL_CONVERTER_CONTROL_1, tmp) != 1)
ret = drm_dp_dpcd_write_byte(&intel_dp->aux,
DP_PROTOCOL_CONVERTER_CONTROL_1, tmp);
if (ret < 0)
drm_dbg_kms(display->drm,
"Failed to %s protocol converter YCbCr 4:2:0 conversion mode\n",
str_enable_disable(intel_dp->dfp.ycbcr_444_to_420));
"Failed to %s protocol converter YCbCr 4:2:0 conversion mode (%pe)\n",
str_enable_disable(intel_dp->dfp.ycbcr_444_to_420),
ERR_PTR(ret));
tmp = rgb_to_ycbcr ? DP_CONVERSION_BT709_RGB_YCBCR_ENABLE : 0;
if (drm_dp_pcon_convert_rgb_to_ycbcr(&intel_dp->aux, tmp) < 0)
ret = drm_dp_pcon_convert_rgb_to_ycbcr(&intel_dp->aux, tmp);
if (ret < 0)
drm_dbg_kms(display->drm,
"Failed to %s protocol converter RGB->YCbCr conversion mode\n",
str_enable_disable(tmp));
"Failed to %s protocol converter RGB->YCbCr conversion mode (%pe)\n",
str_enable_disable(tmp), ERR_PTR(ret));
}
static u8 intel_dp_read_dprx_feature_enum(struct intel_dp *intel_dp)
{
u8 dprx = 0;
drm_dp_dpcd_read_data(&intel_dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST,
&dprx, sizeof(dprx));
drm_dp_dpcd_read_byte(&intel_dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST, &dprx);
return dprx;
}
@ -4490,9 +4503,8 @@ static int intel_dp_read_dsc_dpcd(struct drm_dp_aux *aux,
{
int ret;
ret = drm_dp_dpcd_read_data(aux, DP_DSC_SUPPORT, dsc_dpcd,
DP_DSC_RECEIVER_CAP_SIZE);
if (ret) {
ret = drm_dp_dpcd_read_data(aux, DP_DSC_SUPPORT, dsc_dpcd, DP_DSC_RECEIVER_CAP_SIZE);
if (ret < 0) {
drm_dbg_kms(aux->drm_dev,
"Could not read DSC DPCD register 0x%x Error: %pe\n",
DP_DSC_SUPPORT, ERR_PTR(ret));
@ -4508,7 +4520,7 @@ static int intel_dp_read_dsc_dpcd(struct drm_dp_aux *aux,
static void init_dsc_overall_throughput_limits(struct intel_connector *connector, bool is_branch)
{
u8 branch_caps[DP_DSC_BRANCH_CAP_SIZE];
int line_width;
int line_width, ret;
connector->dp.dsc_branch_caps.overall_throughput.rgb_yuv444 = INT_MAX;
connector->dp.dsc_branch_caps.overall_throughput.yuv422_420 = INT_MAX;
@ -4517,9 +4529,10 @@ static void init_dsc_overall_throughput_limits(struct intel_connector *connector
if (!is_branch)
return;
if (drm_dp_dpcd_read_data(connector->dp.dsc_decompression_aux,
DP_DSC_BRANCH_OVERALL_THROUGHPUT_0, branch_caps,
sizeof(branch_caps)) != 0)
ret = drm_dp_dpcd_read_data(connector->dp.dsc_decompression_aux,
DP_DSC_BRANCH_OVERALL_THROUGHPUT_0, branch_caps,
sizeof(branch_caps));
if (ret < 0)
return;
connector->dp.dsc_branch_caps.overall_throughput.rgb_yuv444 =
@ -4537,6 +4550,7 @@ void intel_dp_get_dsc_sink_cap(u8 dpcd_rev,
struct intel_connector *connector)
{
struct intel_display *display = to_intel_display(connector);
int ret;
/*
* Clear the cached register set to avoid using stale values
@ -4553,13 +4567,16 @@ void intel_dp_get_dsc_sink_cap(u8 dpcd_rev,
if (dpcd_rev < DP_DPCD_REV_14)
return;
if (intel_dp_read_dsc_dpcd(connector->dp.dsc_decompression_aux,
connector->dp.dsc_dpcd) < 0)
ret = intel_dp_read_dsc_dpcd(connector->dp.dsc_decompression_aux,
connector->dp.dsc_dpcd);
if (ret < 0)
return;
if (drm_dp_dpcd_readb(connector->dp.dsc_decompression_aux, DP_FEC_CAPABILITY,
&connector->dp.fec_capability) < 0) {
drm_dbg_kms(display->drm, "Could not read FEC DPCD register\n");
ret = drm_dp_dpcd_read_byte(connector->dp.dsc_decompression_aux, DP_FEC_CAPABILITY,
&connector->dp.fec_capability);
if (ret < 0) {
drm_dbg_kms(display->drm, "Could not read FEC DPCD register (%pe)\n",
ERR_PTR(ret));
return;
}
@ -4668,13 +4685,15 @@ static void intel_edp_mso_init(struct intel_dp *intel_dp)
struct intel_display *display = to_intel_display(intel_dp);
struct intel_connector *connector = intel_dp->attached_connector;
struct drm_display_info *info = &connector->base.display_info;
int ret;
u8 mso;
if (intel_dp->edp_dpcd[0] < DP_EDP_14)
return;
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_MSO_LINK_CAPABILITIES, &mso) != 1) {
drm_err(display->drm, "Failed to read MSO cap\n");
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_EDP_MSO_LINK_CAPABILITIES, &mso);
if (ret < 0) {
drm_err(display->drm, "Failed to read MSO cap (%pe)\n", ERR_PTR(ret));
return;
}
@ -4779,6 +4798,38 @@ intel_edp_set_sink_rates(struct intel_dp *intel_dp)
intel_edp_set_data_override_rates(intel_dp);
}
static void intel_edp_wake_sink(struct intel_dp *intel_dp)
{
u8 value = 0;
int ret;
/*
* Read the current sink power state. drm_dp_dpcd_read_byte() already
* retries the AUX transaction internally, so a single read suffices.
* First commercial eDP panels are Ver1.0 or 1.1, on which DPCD
* DP_SET_POWER is supported.
*/
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_SET_POWER, &value);
/*
* If the AUX read failed the sink may be asleep and not responding,
* or it read back D3; in either case wake it up to D0.
* In case of AUX read failure which is usually a POR case, the
* remaining bits of register 0x600 is set to '0' on POR. So a bare
* write should be fine.
*/
if (ret < 0 || value == DP_SET_POWER_D3) {
value &= ~DP_SET_POWER_MASK;
value |= DP_SET_POWER_D0;
drm_dp_dpcd_write_byte(&intel_dp->aux, DP_SET_POWER,
value);
/* After setting to D0 need a min of 1ms to wake (Spec DP2.1 sec 2.3.1.2) */
fsleep(1000);
drm_dp_dpcd_write_byte(&intel_dp->aux, DP_SET_POWER,
value);
}
}
static bool
intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector)
{
@ -4789,6 +4840,12 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector
/* this function is meant to be called only once */
drm_WARN_ON(display->drm, intel_dp->dpcd[DP_DPCD_REV] != 0);
/*
* Spec DP2.1 Section 3.5.2.16 page 966.
* Also if sink is asleep, this will wake the sink.
*/
intel_edp_wake_sink(intel_dp);
if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd) != 0)
return false;
@ -4813,9 +4870,9 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector
* method). The display control registers should read zero if they're
* not supported anyway.
*/
if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_DPCD_REV,
intel_dp->edp_dpcd, sizeof(intel_dp->edp_dpcd)) ==
sizeof(intel_dp->edp_dpcd)) {
ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_EDP_DPCD_REV,
intel_dp->edp_dpcd, sizeof(intel_dp->edp_dpcd));
if (!ret) {
drm_dbg_kms(display->drm, "eDP DPCD: %*ph\n",
(int)sizeof(intel_dp->edp_dpcd),
intel_dp->edp_dpcd);
@ -5044,6 +5101,7 @@ static bool
intel_dp_get_sink_irq_esi(struct intel_dp *intel_dp, u8 *esi)
{
struct intel_display *display = to_intel_display(intel_dp);
int ret;
/*
* Display WA for HSD #13013007775: mtl/arl/lnl
@ -5052,24 +5110,30 @@ intel_dp_get_sink_irq_esi(struct intel_dp *intel_dp, u8 *esi)
* inadvertently.
*/
if (IS_DISPLAY_VER(display, 14, 20) && !display->platform.battlemage) {
if (drm_dp_dpcd_read(&intel_dp->aux, DP_SINK_COUNT_ESI, esi, 3) != 3)
ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_SINK_COUNT_ESI, esi, 3);
if (ret < 0)
return false;
/* DP_SINK_COUNT_ESI + 3 == DP_LINK_SERVICE_IRQ_VECTOR_ESI0 */
return drm_dp_dpcd_readb(&intel_dp->aux, DP_LINK_SERVICE_IRQ_VECTOR_ESI0,
&esi[3]) == 1;
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_LINK_SERVICE_IRQ_VECTOR_ESI0,
&esi[3]);
return ret == 0;
}
return drm_dp_dpcd_read(&intel_dp->aux, DP_SINK_COUNT_ESI, esi, 4) == 4;
ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_SINK_COUNT_ESI, esi, 4);
return ret == 0;
}
static bool intel_dp_ack_sink_irq_esi(struct intel_dp *intel_dp, u8 esi[4])
{
int retry;
int ret;
for (retry = 0; retry < 3; retry++) {
if (drm_dp_dpcd_write(&intel_dp->aux, DP_SINK_COUNT_ESI + 1,
&esi[1], 3) == 3)
ret = drm_dp_dpcd_write_data(&intel_dp->aux, DP_SINK_COUNT_ESI + 1,
&esi[1], 3);
if (!ret)
return true;
}
@ -5079,20 +5143,24 @@ static bool intel_dp_ack_sink_irq_esi(struct intel_dp *intel_dp, u8 esi[4])
/* Return %true if reading the ESI vector succeeded, %false otherwise. */
static bool intel_dp_get_sink_irq_esi_sst(struct intel_dp *intel_dp, u8 esi[4])
{
int ret;
memset(esi, 0, 4);
/*
* TODO: For DP_DPCD_REV >= 0x12 read
* DP_SINK_COUNT_ESI and DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0.
*/
if (drm_dp_dpcd_read_data(&intel_dp->aux, DP_SINK_COUNT, esi, 2) != 0)
ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_SINK_COUNT, esi, 2);
if (ret < 0)
return false;
if (intel_dp->dpcd[DP_DPCD_REV] < DP_DPCD_REV_12)
return true;
/* TODO: Read DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1 as well */
if (drm_dp_dpcd_read_byte(&intel_dp->aux, DP_LINK_SERVICE_IRQ_VECTOR_ESI0, &esi[3]) != 0)
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_LINK_SERVICE_IRQ_VECTOR_ESI0, &esi[3]);
if (ret < 0)
return false;
return true;
@ -5101,18 +5169,22 @@ static bool intel_dp_get_sink_irq_esi_sst(struct intel_dp *intel_dp, u8 esi[4])
/* Return %true if acking the ESI vector IRQ events succeeded, %false otherwise. */
static bool intel_dp_ack_sink_irq_esi_sst(struct intel_dp *intel_dp, u8 esi[4])
{
int ret;
/*
* TODO: For DP_DPCD_REV >= 0x12 write
* DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0
*/
if (drm_dp_dpcd_write_byte(&intel_dp->aux, DP_DEVICE_SERVICE_IRQ_VECTOR, esi[1]) != 0)
ret = drm_dp_dpcd_write_byte(&intel_dp->aux, DP_DEVICE_SERVICE_IRQ_VECTOR, esi[1]);
if (ret < 0)
return false;
if (intel_dp->dpcd[DP_DPCD_REV] < DP_DPCD_REV_12)
return true;
/* TODO: Read DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1 as well */
if (drm_dp_dpcd_write_byte(&intel_dp->aux, DP_LINK_SERVICE_IRQ_VECTOR_ESI0, esi[3]) != 0)
ret = drm_dp_dpcd_write_byte(&intel_dp->aux, DP_LINK_SERVICE_IRQ_VECTOR_ESI0, esi[3]);
if (ret < 0)
return false;
return true;
@ -5435,11 +5507,15 @@ static int intel_dp_vsc_sdp_unpack(struct drm_dp_vsc_sdp *vsc,
* VSC SDP supporting 3D stereo + Panel Replay.
*/
return 0;
} else if (sdp->sdp_header.HB2 == 0x5 && sdp->sdp_header.HB3 == 0x13) {
} else if ((sdp->sdp_header.HB2 == 0x5 || sdp->sdp_header.HB2 == 0x7) &&
sdp->sdp_header.HB3 == 0x13) {
/*
* - HB2 = 0x5, HB3 = 0x13
* VSC SDP supporting 3D stereo + PSR2 + Pixel Encoding/Colorimetry
* Format.
* - HB2 = 0x7, HB3 = 0x13
* VSC SDP supporting 3D stereo + Panel Replay + Pixel Encoding/Colorimetry
* Format.
*/
vsc->pixelformat = (sdp->db[16] >> 4) & 0xf;
vsc->colorimetry = sdp->db[16] & 0xf;
@ -5706,14 +5782,17 @@ intel_dp_handle_hdmi_link_status_change(struct intel_dp *intel_dp)
{
bool is_active;
u8 buf = 0;
int ret;
is_active = drm_dp_pcon_hdmi_link_active(&intel_dp->aux);
if (intel_dp->frl.is_trained && !is_active) {
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_PCON_HDMI_LINK_CONFIG_1, &buf) < 0)
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_PCON_HDMI_LINK_CONFIG_1, &buf);
if (ret < 0)
return;
buf &= ~DP_PCON_ENABLE_HDMI_LINK;
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_PCON_HDMI_LINK_CONFIG_1, buf) < 0)
ret = drm_dp_dpcd_write_byte(&intel_dp->aux, DP_PCON_HDMI_LINK_CONFIG_1, buf);
if (ret < 0)
return;
drm_dp_pcon_hdmi_frl_link_error_count(&intel_dp->aux, &intel_dp->attached_connector->base);
@ -6218,6 +6297,7 @@ static bool
intel_dp_sink_supports_as_sdp_v2(struct intel_dp *intel_dp)
{
u8 rx_features;
int ret;
/*
* The DP spec does not explicitly provide the AS SDP v2 capability.
@ -6240,9 +6320,10 @@ intel_dp_sink_supports_as_sdp_v2(struct intel_dp *intel_dp)
* support from Display ID.
*/
if (drm_dp_dpcd_read_byte(&intel_dp->aux,
DP_DPRX_FEATURE_ENUMERATION_LIST_CONT_1,
&rx_features) == 1) {
ret = drm_dp_dpcd_read_byte(&intel_dp->aux,
DP_DPRX_FEATURE_ENUMERATION_LIST_CONT_1,
&rx_features);
if (!ret) {
if (rx_features & DP_AS_SDP_FAVT_PAYLOAD_FIELDS_PARSING_SUPPORTED)
return true;
}
@ -7324,6 +7405,8 @@ int intel_dp_sdp_compute_config_late(struct intel_crtc_state *crtc_state)
return -EINVAL;
}
intel_dip_sdp_tl_compute_config_late(crtc_state);
return 0;
}
@ -7345,9 +7428,58 @@ int intel_dp_compute_config_late(struct intel_encoder *encoder,
return 0;
}
static
int intel_dp_get_lines_for_cmn_sdp_tl(u32 type)
{
u32 stagger_val;
/*
* Since we are using default stagger values similar to the case
* where CMN SDP TL is not set, the different SDP transmission
* lines are:
* base : 2nd line of delayed vblank:
* GMP : 2 + GMP_STAGGER
* VSC_EXT: 2 + VSC_EXT_STAGGER
* VSC : 2
* PPS : 2 + PPS_STAGGER
*
* SDP Setup = 1 + MAX(GMP, VSC_EXT, VSC, PPS setup lines)
*
* For EMP_AS_SDP_TL guardband should be more than vrr.vsync_start.
*/
switch (type) {
case DP_SDP_VSC_EXT_VESA:
case DP_SDP_VSC_EXT_CEA:
stagger_val = VSC_EXT_STAGGER_DEFAULT;
break;
case HDMI_PACKET_TYPE_GAMUT_METADATA:
stagger_val = GMP_STAGGER_DEFAULT;
break;
case DP_SDP_PPS:
stagger_val = PPS_STAGGER_DEFAULT;
break;
case DP_SDP_VSC:
stagger_val = 0;
break;
default:
return 0;
}
return 1 + 2 + stagger_val;
}
static
int intel_dp_get_lines_for_sdp(const struct intel_crtc_state *crtc_state, u32 type)
{
struct intel_display *display = to_intel_display(crtc_state);
if (type == DP_SDP_ADAPTIVE_SYNC)
return crtc_state->vrr.vsync_start + 1;
if (HAS_COMMON_SDP_TL(display))
return intel_dp_get_lines_for_cmn_sdp_tl(type);
switch (type) {
case DP_SDP_VSC_EXT_VESA:
case DP_SDP_VSC_EXT_CEA:
@ -7356,8 +7488,8 @@ int intel_dp_get_lines_for_sdp(const struct intel_crtc_state *crtc_state, u32 ty
return 8;
case DP_SDP_PPS:
return 7;
case DP_SDP_ADAPTIVE_SYNC:
return crtc_state->vrr.vsync_start + 1;
case DP_SDP_VSC:
return 3;
default:
break;
}
@ -7387,6 +7519,11 @@ int intel_dp_sdp_min_guardband(const struct intel_crtc_state *crtc_state,
sdp_guardband = max(sdp_guardband,
intel_dp_get_lines_for_sdp(crtc_state, DP_SDP_ADAPTIVE_SYNC));
if (crtc_state->infoframes.enable &
intel_hdmi_infoframe_enable(DP_SDP_VSC))
sdp_guardband = max(sdp_guardband,
intel_dp_get_lines_for_sdp(crtc_state, DP_SDP_VSC));
return sdp_guardband;
}

View File

@ -120,8 +120,8 @@ intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector)
intel_dp_wait_source_oui(intel_dp);
ret = drm_dp_dpcd_read(aux, INTEL_EDP_HDR_TCON_CAP0, tcon_cap, sizeof(tcon_cap));
if (ret != sizeof(tcon_cap))
ret = drm_dp_dpcd_read_data(aux, INTEL_EDP_HDR_TCON_CAP0, tcon_cap, sizeof(tcon_cap));
if (ret < 0)
return false;
drm_dbg_kms(display->drm,
@ -178,11 +178,13 @@ intel_dp_aux_hdr_get_backlight(struct intel_connector *connector, enum pipe pipe
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
u8 tmp;
u8 buf[2] = {};
int ret;
if (drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &tmp) != 1) {
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &tmp);
if (ret < 0) {
drm_err(display->drm,
"[CONNECTOR:%d:%s] Failed to read current backlight mode from DPCD\n",
connector->base.base.id, connector->base.name);
"[CONNECTOR:%d:%s] Failed to read current backlight mode from DPCD (%pe)\n",
connector->base.base.id, connector->base.name, ERR_PTR(ret));
return 0;
}
@ -197,11 +199,12 @@ intel_dp_aux_hdr_get_backlight(struct intel_connector *connector, enum pipe pipe
return panel->backlight.max;
}
if (drm_dp_dpcd_read(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf,
sizeof(buf)) != sizeof(buf)) {
ret = drm_dp_dpcd_read_data(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf,
sizeof(buf));
if (ret < 0) {
drm_err(display->drm,
"[CONNECTOR:%d:%s] Failed to read brightness from DPCD\n",
connector->base.base.id, connector->base.name);
"[CONNECTOR:%d:%s] Failed to read brightness from DPCD (%pe)\n",
connector->base.base.id, connector->base.name, ERR_PTR(ret));
return 0;
}
@ -215,14 +218,16 @@ intel_dp_aux_hdr_set_aux_backlight(const struct drm_connector_state *conn_state,
struct drm_device *dev = connector->base.dev;
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
u8 buf[4] = {};
int ret;
buf[0] = level & 0xFF;
buf[1] = (level & 0xFF00) >> 8;
if (drm_dp_dpcd_write(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf,
sizeof(buf)) != sizeof(buf))
drm_err(dev, "[CONNECTOR:%d:%s] Failed to write brightness level to DPCD\n",
connector->base.base.id, connector->base.name);
ret = drm_dp_dpcd_write_data(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf,
sizeof(buf));
if (ret < 0)
drm_err(dev, "[CONNECTOR:%d:%s] Failed to write brightness level to DPCD (%pe)\n",
connector->base.base.id, connector->base.name, ERR_PTR(ret));
}
static void
@ -258,13 +263,12 @@ intel_dp_aux_write_content_luminance(struct intel_connector *connector,
buf[2] = hdr_metadata->hdmi_metadata_type1.max_fall & 0xFF;
buf[3] = (hdr_metadata->hdmi_metadata_type1.max_fall & 0xFF00) >> 8;
ret = drm_dp_dpcd_write(&intel_dp->aux,
INTEL_EDP_HDR_CONTENT_LUMINANCE,
buf, sizeof(buf));
ret = drm_dp_dpcd_write_data(&intel_dp->aux,
INTEL_EDP_HDR_CONTENT_LUMINANCE,
buf, sizeof(buf));
if (ret < 0)
drm_dbg_kms(display->drm,
"Content Luminance DPCD reg write failed, err:-%d\n",
ret);
"Content Luminance DPCD reg write failed (%pe)\n", ERR_PTR(ret));
}
static void
@ -313,11 +317,11 @@ intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state,
intel_dp_wait_source_oui(intel_dp);
ret = drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &old_ctrl);
if (ret != 1) {
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &old_ctrl);
if (ret < 0) {
drm_err(display->drm,
"[CONNECTOR:%d:%s] Failed to read current backlight control mode: %d\n",
connector->base.base.id, connector->base.name, ret);
"[CONNECTOR:%d:%s] Failed to read current backlight control mode (%pe)\n",
connector->base.base.id, connector->base.name, ERR_PTR(ret));
return;
}
@ -337,11 +341,14 @@ intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state,
intel_dp_aux_fill_hdr_tcon_params(conn_state, &ctrl);
if (ctrl != old_ctrl &&
drm_dp_dpcd_writeb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, ctrl) != 1)
drm_err(display->drm,
"[CONNECTOR:%d:%s] Failed to configure DPCD brightness controls\n",
connector->base.base.id, connector->base.name);
if (ctrl != old_ctrl) {
ret = drm_dp_dpcd_write_byte(&intel_dp->aux,
INTEL_EDP_HDR_GETSET_CTRL_PARAMS, ctrl);
if (ret < 0)
drm_err(display->drm,
"[CONNECTOR:%d:%s] Failed to configure DPCD brightness controls (%pe)\n",
connector->base.base.id, connector->base.name, ERR_PTR(ret));
}
if (intel_dp_in_hdr_mode(conn_state)) {
hdr_metadata = conn_state->hdr_output_metadata->data;
@ -392,13 +399,12 @@ intel_dp_aux_write_panel_luminance_override(struct intel_connector *connector)
buf[2] = panel->backlight.max & 0xFF;
buf[3] = (panel->backlight.max & 0xFF00) >> 8;
ret = drm_dp_dpcd_write(&intel_dp->aux,
INTEL_EDP_HDR_PANEL_LUMINANCE_OVERRIDE,
buf, sizeof(buf));
ret = drm_dp_dpcd_write_data(&intel_dp->aux,
INTEL_EDP_HDR_PANEL_LUMINANCE_OVERRIDE,
buf, sizeof(buf));
if (ret < 0)
drm_dbg_kms(display->drm,
"Panel Luminance DPCD reg write failed, err:-%d\n",
ret);
"Panel Luminance DPCD reg write failed (%pe)\n", ERR_PTR(ret));
}
static int
@ -456,12 +462,12 @@ static u32 intel_dp_aux_vesa_get_backlight(struct intel_connector *connector, en
int ret;
if (panel->backlight.edp.vesa.luminance_control_support) {
ret = drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_PANEL_TARGET_LUMINANCE_VALUE, buf,
sizeof(buf));
ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_EDP_PANEL_TARGET_LUMINANCE_VALUE, buf,
sizeof(buf));
if (ret < 0) {
drm_err(intel_dp->aux.drm_dev,
"[CONNECTOR:%d:%s] Failed to read Luminance from DPCD\n",
connector->base.base.id, connector->base.name);
"[CONNECTOR:%d:%s] Failed to read Luminance from DPCD (%pe)\n",
connector->base.base.id, connector->base.name, ERR_PTR(ret));
return 0;
}

View File

@ -60,16 +60,15 @@ int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
{
struct intel_display *display = to_intel_display(dig_port);
u8 aksv[DRM_HDCP_KSV_LEN] = {};
ssize_t dpcd_ret;
int ret;
/* Output An first, that's easy */
dpcd_ret = drm_dp_dpcd_write(&dig_port->dp.aux, DP_AUX_HDCP_AN,
ret = drm_dp_dpcd_write_data(&dig_port->dp.aux, DP_AUX_HDCP_AN,
an, DRM_HDCP_AN_LEN);
if (dpcd_ret != DRM_HDCP_AN_LEN) {
if (ret < 0) {
drm_dbg_kms(display->drm,
"Failed to write An over DP/AUX (%zd)\n",
dpcd_ret);
return dpcd_ret >= 0 ? -EIO : dpcd_ret;
"Failed to write An over DP/AUX (%pe)\n", ERR_PTR(ret));
return ret;
}
/*
@ -79,14 +78,14 @@ int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
* the destination address which will tickle the hardware to output the
* Aksv on our behalf after the header is sent.
*/
dpcd_ret = drm_dp_dpcd_write(&dig_port->dp.aux, DP_AUX_HDCP_AKSV,
ret = drm_dp_dpcd_write_data(&dig_port->dp.aux, DP_AUX_HDCP_AKSV,
aksv, DRM_HDCP_KSV_LEN);
if (dpcd_ret != DRM_HDCP_KSV_LEN) {
if (ret < 0) {
drm_dbg_kms(display->drm,
"Failed to write Aksv over DP/AUX (%zd)\n",
dpcd_ret);
return dpcd_ret >= 0 ? -EIO : dpcd_ret;
"Failed to write Aksv over DP/AUX (%pe)\n", ERR_PTR(ret));
return ret;
}
return 0;
}
@ -94,15 +93,16 @@ static int intel_dp_hdcp_read_bksv(struct intel_digital_port *dig_port,
u8 *bksv)
{
struct intel_display *display = to_intel_display(dig_port);
ssize_t ret;
int ret;
ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BKSV, bksv,
DRM_HDCP_KSV_LEN);
if (ret != DRM_HDCP_KSV_LEN) {
ret = drm_dp_dpcd_read_data(&dig_port->dp.aux, DP_AUX_HDCP_BKSV, bksv,
DRM_HDCP_KSV_LEN);
if (ret < 0) {
drm_dbg_kms(display->drm,
"Read Bksv from DP/AUX failed (%zd)\n", ret);
return ret >= 0 ? -EIO : ret;
"Read Bksv from DP/AUX failed (%pe)\n", ERR_PTR(ret));
return ret;
}
return 0;
}
@ -110,20 +110,21 @@ static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *dig_port,
u8 *bstatus)
{
struct intel_display *display = to_intel_display(dig_port);
ssize_t ret;
int ret;
/*
* For some reason the HDMI and DP HDCP specs call this register
* definition by different names. In the HDMI spec, it's called BSTATUS,
* but in DP it's called BINFO.
*/
ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BINFO,
bstatus, DRM_HDCP_BSTATUS_LEN);
if (ret != DRM_HDCP_BSTATUS_LEN) {
ret = drm_dp_dpcd_read_data(&dig_port->dp.aux, DP_AUX_HDCP_BINFO,
bstatus, DRM_HDCP_BSTATUS_LEN);
if (ret < 0) {
drm_dbg_kms(display->drm,
"Read bstatus from DP/AUX failed (%zd)\n", ret);
return ret >= 0 ? -EIO : ret;
"Read bstatus from DP/AUX failed (%pe)\n", ERR_PTR(ret));
return ret;
}
return 0;
}
@ -132,14 +133,13 @@ int intel_dp_hdcp_read_bcaps(struct drm_dp_aux *aux,
struct intel_display *display,
u8 *bcaps)
{
ssize_t ret;
int ret;
ret = drm_dp_dpcd_read(aux, DP_AUX_HDCP_BCAPS,
bcaps, 1);
if (ret != 1) {
ret = drm_dp_dpcd_read_byte(aux, DP_AUX_HDCP_BCAPS, bcaps);
if (ret < 0) {
drm_dbg_kms(display->drm,
"Read bcaps from DP/AUX failed (%zd)\n", ret);
return ret >= 0 ? -EIO : ret;
"Read bcaps from DP/AUX failed (%pe)\n", ERR_PTR(ret));
return ret;
}
return 0;
@ -166,16 +166,16 @@ int intel_dp_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
u8 *ri_prime)
{
struct intel_display *display = to_intel_display(dig_port);
ssize_t ret;
int ret;
ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_RI_PRIME,
ri_prime, DRM_HDCP_RI_LEN);
if (ret != DRM_HDCP_RI_LEN) {
ret = drm_dp_dpcd_read_data(&dig_port->dp.aux, DP_AUX_HDCP_RI_PRIME,
ri_prime, DRM_HDCP_RI_LEN);
if (ret < 0) {
drm_dbg_kms(display->drm,
"Read Ri' from DP/AUX failed (%zd)\n",
ret);
return ret >= 0 ? -EIO : ret;
"Read Ri' from DP/AUX failed (%pe)\n", ERR_PTR(ret));
return ret;
}
return 0;
}
@ -184,17 +184,18 @@ int intel_dp_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
bool *ksv_ready)
{
struct intel_display *display = to_intel_display(dig_port);
ssize_t ret;
u8 bstatus;
int ret;
ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
&bstatus, 1);
if (ret != 1) {
ret = drm_dp_dpcd_read_byte(&dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
&bstatus);
if (ret < 0) {
drm_dbg_kms(display->drm,
"Read bstatus from DP/AUX failed (%zd)\n", ret);
return ret >= 0 ? -EIO : ret;
"Read bstatus from DP/AUX failed (%pe)\n", ERR_PTR(ret));
return ret;
}
*ksv_ready = bstatus & DP_BSTATUS_READY;
return 0;
}
@ -203,23 +204,24 @@ int intel_dp_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
int num_downstream, u8 *ksv_fifo)
{
struct intel_display *display = to_intel_display(dig_port);
ssize_t ret;
int ret;
int i;
/* KSV list is read via 15 byte window (3 entries @ 5 bytes each) */
for (i = 0; i < num_downstream; i += 3) {
size_t len = min(num_downstream - i, 3) * DRM_HDCP_KSV_LEN;
ret = drm_dp_dpcd_read(&dig_port->dp.aux,
DP_AUX_HDCP_KSV_FIFO,
ksv_fifo + i * DRM_HDCP_KSV_LEN,
len);
if (ret != len) {
ret = drm_dp_dpcd_read_data(&dig_port->dp.aux,
DP_AUX_HDCP_KSV_FIFO,
ksv_fifo + i * DRM_HDCP_KSV_LEN,
len);
if (ret < 0) {
drm_dbg_kms(display->drm,
"Read ksv[%d] from DP/AUX failed (%zd)\n",
i, ret);
return ret >= 0 ? -EIO : ret;
"Read ksv[%d] from DP/AUX failed (%pe)\n",
i, ERR_PTR(ret));
return ret;
}
}
return 0;
}
@ -228,19 +230,19 @@ int intel_dp_hdcp_read_v_prime_part(struct intel_digital_port *dig_port,
int i, u32 *part)
{
struct intel_display *display = to_intel_display(dig_port);
ssize_t ret;
int ret;
if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
return -EINVAL;
ret = drm_dp_dpcd_read(&dig_port->dp.aux,
DP_AUX_HDCP_V_PRIME(i), part,
DRM_HDCP_V_PRIME_PART_LEN);
if (ret != DRM_HDCP_V_PRIME_PART_LEN) {
ret = drm_dp_dpcd_read_data(&dig_port->dp.aux, DP_AUX_HDCP_V_PRIME(i), part,
DRM_HDCP_V_PRIME_PART_LEN);
if (ret < 0) {
drm_dbg_kms(display->drm,
"Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
return ret >= 0 ? -EIO : ret;
"Read v'[%d] from DP/AUX failed (%pe)\n", i, ERR_PTR(ret));
return ret;
}
return 0;
}
@ -258,14 +260,13 @@ bool intel_dp_hdcp_check_link(struct intel_digital_port *dig_port,
struct intel_connector *connector)
{
struct intel_display *display = to_intel_display(dig_port);
ssize_t ret;
u8 bstatus;
int ret;
ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
&bstatus, 1);
if (ret != 1) {
ret = drm_dp_dpcd_read_byte(&dig_port->dp.aux, DP_AUX_HDCP_BSTATUS, &bstatus);
if (ret < 0) {
drm_dbg_kms(display->drm,
"Read bstatus from DP/AUX failed (%zd)\n", ret);
"Read bstatus from DP/AUX failed (%pe)\n", ERR_PTR(ret));
return false;
}
@ -346,15 +347,14 @@ intel_dp_hdcp2_read_rx_status(struct intel_connector *connector,
struct intel_display *display = to_intel_display(connector);
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
struct drm_dp_aux *aux = &dig_port->dp.aux;
ssize_t ret;
int ret;
ret = drm_dp_dpcd_read(aux,
DP_HDCP_2_2_REG_RXSTATUS_OFFSET, rx_status,
HDCP_2_2_DP_RXSTATUS_LEN);
if (ret != HDCP_2_2_DP_RXSTATUS_LEN) {
ret = drm_dp_dpcd_read_data(aux, DP_HDCP_2_2_REG_RXSTATUS_OFFSET, rx_status,
HDCP_2_2_DP_RXSTATUS_LEN);
if (ret < 0) {
drm_dbg_kms(display->drm,
"Read bstatus from DP/AUX failed (%zd)\n", ret);
return ret >= 0 ? -EIO : ret;
"Read bstatus from DP/AUX failed (%pe)\n", ERR_PTR(ret));
return ret;
}
return 0;
@ -474,8 +474,8 @@ int intel_dp_hdcp2_write_msg(struct intel_connector *connector,
len = bytes_to_write > DP_AUX_MAX_PAYLOAD_BYTES ?
DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_write;
ret = drm_dp_dpcd_write(aux,
offset, (void *)byte, len);
/* Note: This may return < len for partial writes. */
ret = drm_dp_dpcd_write(aux, offset, byte, len);
if (ret < 0)
return ret;
@ -487,20 +487,20 @@ int intel_dp_hdcp2_write_msg(struct intel_connector *connector,
return size;
}
/* return number of bytes read on success */
static
ssize_t get_receiver_id_list_rx_info(struct intel_connector *connector,
u32 *dev_cnt, u8 *byte)
{
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
struct drm_dp_aux *aux = &dig_port->dp.aux;
ssize_t ret;
u8 *rx_info = byte;
int ret;
ret = drm_dp_dpcd_read(aux,
DP_HDCP_2_2_REG_RXINFO_OFFSET,
(void *)rx_info, HDCP_2_2_RXINFO_LEN);
if (ret != HDCP_2_2_RXINFO_LEN)
return ret >= 0 ? -EIO : ret;
ret = drm_dp_dpcd_read_data(aux, DP_HDCP_2_2_REG_RXINFO_OFFSET,
rx_info, HDCP_2_2_RXINFO_LEN);
if (ret < 0)
return ret;
*dev_cnt = (HDCP_2_2_DEV_COUNT_HI(rx_info[0]) << 4 |
HDCP_2_2_DEV_COUNT_LO(rx_info[1]));
@ -508,7 +508,7 @@ ssize_t get_receiver_id_list_rx_info(struct intel_connector *connector,
if (*dev_cnt > HDCP_2_2_MAX_DEVICE_COUNT)
*dev_cnt = HDCP_2_2_MAX_DEVICE_COUNT;
return ret;
return HDCP_2_2_RXINFO_LEN;
}
static
@ -566,11 +566,11 @@ int intel_dp_hdcp2_read_msg(struct intel_connector *connector,
hdcp2_msg_data->msg_read_timeout);
}
ret = drm_dp_dpcd_read(aux, offset,
(void *)byte, len);
/* Note: This may return < len for partial reads. */
ret = drm_dp_dpcd_read(aux, offset, byte, len);
if (ret < 0) {
drm_dbg_kms(display->drm, "msg_id %d, ret %zd\n",
msg_id, ret);
drm_dbg_kms(display->drm, "msg_id %d, ret %pe\n",
msg_id, ERR_PTR(ret));
return ret;
}
@ -660,11 +660,11 @@ int _intel_dp_hdcp2_get_capability(struct drm_dp_aux *aux,
* declare a monitor not capable of HDCP 2.2.
*/
for (i = 0; i < 3; i++) {
ret = drm_dp_dpcd_read(aux,
DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
rx_caps, HDCP_2_2_RXCAPS_LEN);
if (ret != HDCP_2_2_RXCAPS_LEN)
return ret >= 0 ? -EIO : ret;
ret = drm_dp_dpcd_read_data(aux,
DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
rx_caps, HDCP_2_2_RXCAPS_LEN);
if (ret < 0)
return ret;
if (rx_caps[0] == HDCP_2_2_RX_CAPS_VERSION_VAL &&
HDCP_2_2_DP_HDCP_CAPABLE(rx_caps[2])) {

View File

@ -929,7 +929,7 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
{
int reg = intel_dp_training_pattern_set_reg(intel_dp, dp_phy);
u8 buf[sizeof(intel_dp->train_set) + 1];
int len;
int ret, len;
intel_dp_program_link_training_pattern(intel_dp, crtc_state,
dp_phy, dp_train_pat);
@ -939,7 +939,9 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
memcpy(buf + 1, intel_dp->train_set, crtc_state->lane_count);
len = crtc_state->lane_count + 1;
return drm_dp_dpcd_write(&intel_dp->aux, reg, buf, len) == len;
ret = drm_dp_dpcd_write_data(&intel_dp->aux, reg, buf, len);
return !ret;
}
static char dp_training_pattern_name(u8 train_pat)
@ -1046,10 +1048,10 @@ intel_dp_update_link_train(struct intel_dp *intel_dp,
intel_dp_set_signal_levels(intel_dp, crtc_state, dp_phy);
ret = drm_dp_dpcd_write(&intel_dp->aux, reg,
intel_dp->train_set, crtc_state->lane_count);
ret = drm_dp_dpcd_write_data(&intel_dp->aux, reg,
intel_dp->train_set, crtc_state->lane_count);
return ret == crtc_state->lane_count;
return !ret;
}
/* 128b/132b */
@ -1115,7 +1117,7 @@ void intel_dp_link_training_set_mode(struct intel_dp *intel_dp, int link_rate,
link_config[0] |= pr_with_as_sdp_enable ? DP_FIXED_VTOTAL_AS_SDP_EN_IN_PR_ACTIVE : 0;
link_config[1] = drm_dp_is_uhbr_rate(link_rate) ?
DP_SET_ANSI_128B132B : DP_SET_ANSI_8B10B;
drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
drm_dp_dpcd_write_data(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
}
static bool
@ -1163,8 +1165,8 @@ void intel_dp_link_training_set_bw(struct intel_dp *intel_dp,
/* DP and eDP v1.3 and earlier link bw set method. */
u8 link_config[] = { link_bw, lane_count };
drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config,
ARRAY_SIZE(link_config));
drm_dp_dpcd_write_data(&intel_dp->aux, DP_LINK_BW_SET, link_config,
sizeof(link_config));
} else {
/*
* eDP v1.4 and later link rate set method.
@ -1175,8 +1177,8 @@ void intel_dp_link_training_set_bw(struct intel_dp *intel_dp,
* eDP v1.5 sinks allow choosing either, and the last choice
* shall be active.
*/
drm_dp_dpcd_writeb(&intel_dp->aux, DP_LANE_COUNT_SET, lane_count);
drm_dp_dpcd_writeb(&intel_dp->aux, DP_LINK_RATE_SET, rate_select);
drm_dp_dpcd_write_byte(&intel_dp->aux, DP_LANE_COUNT_SET, lane_count);
drm_dp_dpcd_write_byte(&intel_dp->aux, DP_LINK_RATE_SET, rate_select);
}
}
@ -1286,8 +1288,8 @@ intel_dp_prepare_link_train(struct intel_dp *intel_dp,
lt_dbg(intel_dp, DP_PHY_DPRX, "Reloading eDP link rates\n");
drm_dp_dpcd_read(&intel_dp->aux, DP_SUPPORTED_LINK_RATES,
sink_rates, sizeof(sink_rates));
drm_dp_dpcd_read_data(&intel_dp->aux, DP_SUPPORTED_LINK_RATES,
sink_rates, sizeof(sink_rates));
}
if (link_bw)
@ -1612,7 +1614,7 @@ static void intel_dp_stop_post_lt_adj_req(struct intel_dp *intel_dp,
if (crtc_state->enhanced_framing)
lane_count |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
drm_dp_dpcd_writeb(&intel_dp->aux, DP_LANE_COUNT_SET, lane_count);
drm_dp_dpcd_write_byte(&intel_dp->aux, DP_LANE_COUNT_SET, lane_count);
}
static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp,
@ -1621,7 +1623,7 @@ static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp,
int reg = intel_dp_training_pattern_set_reg(intel_dp, dp_phy);
u8 val = DP_TRAINING_PATTERN_DISABLE;
return drm_dp_dpcd_write(&intel_dp->aux, reg, &val, 1) == 1;
return drm_dp_dpcd_write_byte(&intel_dp->aux, reg, val) == 0;
}
static int
@ -1631,10 +1633,11 @@ intel_dp_128b132b_intra_hop(struct intel_dp *intel_dp,
u8 sink_status;
int ret;
ret = drm_dp_dpcd_readb(&intel_dp->aux, DP_SINK_STATUS, &sink_status);
if (ret != 1) {
lt_dbg(intel_dp, DP_PHY_DPRX, "Failed to read sink status\n");
return ret < 0 ? ret : -EIO;
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_SINK_STATUS, &sink_status);
if (ret < 0) {
lt_dbg(intel_dp, DP_PHY_DPRX, "Failed to read sink status (%pe)\n",
ERR_PTR(ret));
return ret;
}
return sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION ? 1 : 0;
@ -2173,10 +2176,13 @@ intel_dp_128b132b_lane_cds(struct intel_dp *intel_dp,
{
u8 link_status[DP_LINK_STATUS_SIZE];
unsigned long deadline;
int ret;
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
DP_TRAINING_PATTERN_2_CDS) != 1) {
lt_err(intel_dp, DP_PHY_DPRX, "Failed to start 128b/132b TPS2 CDS\n");
ret = drm_dp_dpcd_write_byte(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
DP_TRAINING_PATTERN_2_CDS);
if (ret < 0) {
lt_err(intel_dp, DP_PHY_DPRX, "Failed to start 128b/132b TPS2 CDS (%pe)\n",
ERR_PTR(ret));
return false;
}
@ -2363,9 +2369,9 @@ void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp,
return;
/* DP v2.0 SCR on SDP CRC16 for 128b/132b Link Layer */
drm_dp_dpcd_writeb(&intel_dp->aux,
DP_SDP_ERROR_DETECTION_CONFIGURATION,
DP_SDP_CRC16_128B132B_EN);
drm_dp_dpcd_write_byte(&intel_dp->aux,
DP_SDP_ERROR_DETECTION_CONFIGURATION,
DP_SDP_CRC16_128B132B_EN);
lt_dbg(intel_dp, DP_PHY_DPRX, "DP2.0 SDP CRC16 for 128b/132b enabled\n");
}

View File

@ -2252,7 +2252,7 @@ bool intel_dp_mst_verify_dpcd_state(struct intel_dp *intel_dp)
if (!intel_dp->is_mst)
return true;
ret = drm_dp_dpcd_readb(intel_dp->mst.mgr.aux, DP_MSTM_CTRL, &val);
ret = drm_dp_dpcd_read_byte(intel_dp->mst.mgr.aux, DP_MSTM_CTRL, &val);
/* Adjust the expected register value for SST + SideBand. */
if (ret < 0 || val != (DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC)) {

View File

@ -147,26 +147,25 @@ bool intel_dp_test_compute_config(struct intel_connector *connector,
static u8 intel_dp_autotest_link_training(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
int status = 0;
int ret;
int test_link_rate;
u8 test_lane_count, test_link_bw;
/* (DP CTS 1.2)
* 4.3.1.11
*/
/* Read the TEST_LANE_COUNT and TEST_LINK_RTAE fields (DP CTS 3.1.4) */
status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_LANE_COUNT,
&test_lane_count);
if (status <= 0) {
drm_dbg_kms(display->drm, "Lane count read failed\n");
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_TEST_LANE_COUNT,
&test_lane_count);
if (ret < 0) {
drm_dbg_kms(display->drm, "Lane count read failed (%pe)\n", ERR_PTR(ret));
return DP_TEST_NAK;
}
test_lane_count &= DP_MAX_LANE_COUNT_MASK;
status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_LINK_RATE,
&test_link_bw);
if (status <= 0) {
drm_dbg_kms(display->drm, "Link Rate read failed\n");
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_TEST_LINK_RATE,
&test_link_bw);
if (ret < 0) {
drm_dbg_kms(display->drm, "Link Rate read failed (%pe)\n", ERR_PTR(ret));
return DP_TEST_NAK;
}
test_link_rate = drm_dp_bw_code_to_link_rate(test_link_bw);
@ -188,36 +187,34 @@ static u8 intel_dp_autotest_video_pattern(struct intel_dp *intel_dp)
u8 test_pattern;
u8 test_misc;
__be16 h_width, v_height;
int status = 0;
int ret;
/* Read the TEST_PATTERN (DP CTS 3.1.5) */
status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_PATTERN,
&test_pattern);
if (status <= 0) {
drm_dbg_kms(display->drm, "Test pattern read failed\n");
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_TEST_PATTERN,
&test_pattern);
if (ret < 0) {
drm_dbg_kms(display->drm, "Test pattern read failed (%pe)\n", ERR_PTR(ret));
return DP_TEST_NAK;
}
if (test_pattern != DP_COLOR_RAMP)
return DP_TEST_NAK;
status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_H_WIDTH_HI,
&h_width, 2);
if (status <= 0) {
drm_dbg_kms(display->drm, "H Width read failed\n");
ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_TEST_H_WIDTH_HI, &h_width, 2);
if (ret < 0) {
drm_dbg_kms(display->drm, "H Width read failed (%pe)\n", ERR_PTR(ret));
return DP_TEST_NAK;
}
status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_V_HEIGHT_HI,
&v_height, 2);
if (status <= 0) {
drm_dbg_kms(display->drm, "V Height read failed\n");
ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_TEST_V_HEIGHT_HI,
&v_height, 2);
if (ret < 0) {
drm_dbg_kms(display->drm, "V Height read failed (%pe)\n", ERR_PTR(ret));
return DP_TEST_NAK;
}
status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_MISC0,
&test_misc);
if (status <= 0) {
drm_dbg_kms(display->drm, "TEST MISC read failed\n");
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_TEST_MISC0, &test_misc);
if (ret < 0) {
drm_dbg_kms(display->drm, "TEST MISC read failed (%pe)\n", ERR_PTR(ret));
return DP_TEST_NAK;
}
if ((test_misc & DP_TEST_COLOR_FORMAT_MASK) != DP_COLOR_FORMAT_RGB)
@ -250,6 +247,7 @@ static u8 intel_dp_autotest_edid(struct intel_dp *intel_dp)
u8 test_result = DP_TEST_ACK;
struct intel_connector *intel_connector = intel_dp->attached_connector;
struct drm_connector *connector = &intel_connector->base;
int ret;
if (!intel_connector->detect_edid || connector->edid_corrupt ||
intel_dp->aux.i2c_defer_count > 6) {
@ -274,10 +272,11 @@ static u8 intel_dp_autotest_edid(struct intel_dp *intel_dp)
/* We have to write the checksum of the last block read */
block += block->extensions;
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_EDID_CHECKSUM,
block->checksum) <= 0)
ret = drm_dp_dpcd_write_byte(&intel_dp->aux, DP_TEST_EDID_CHECKSUM,
block->checksum);
if (ret < 0)
drm_dbg_kms(display->drm,
"Failed to write EDID checksum\n");
"Failed to write EDID checksum (%pe)\n", ERR_PTR(ret));
test_result = DP_TEST_ACK | DP_TEST_EDID_CHECKSUM_WRITE;
intel_dp->compliance.test_data.edid = INTEL_DP_RESOLUTION_PREFERRED;
@ -397,8 +396,8 @@ static void intel_dp_process_phy_request(struct intel_dp *intel_dp,
intel_dp_phy_pattern_update(intel_dp, crtc_state);
drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
intel_dp->train_set, crtc_state->lane_count);
drm_dp_dpcd_write_data(&intel_dp->aux, DP_TRAINING_LANE0_SET,
intel_dp->train_set, crtc_state->lane_count);
drm_dp_set_phy_test_pattern(&intel_dp->aux, data,
intel_dp->dpcd[DP_DPCD_REV]);
@ -427,12 +426,12 @@ void intel_dp_test_request(struct intel_dp *intel_dp)
struct intel_display *display = to_intel_display(intel_dp);
u8 response = DP_TEST_NAK;
u8 request = 0;
int status;
int ret;
status = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_REQUEST, &request);
if (status <= 0) {
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_TEST_REQUEST, &request);
if (ret < 0) {
drm_dbg_kms(display->drm,
"Could not read test request from sink\n");
"Could not read test request from sink (%pe)\n", ERR_PTR(ret));
goto update_status;
}
@ -463,10 +462,10 @@ void intel_dp_test_request(struct intel_dp *intel_dp)
intel_dp->compliance.test_type = request;
update_status:
status = drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_RESPONSE, response);
if (status <= 0)
ret = drm_dp_dpcd_write_byte(&intel_dp->aux, DP_TEST_RESPONSE, response);
if (ret < 0)
drm_dbg_kms(display->drm,
"Could not write test response to sink\n");
"Could not write test response to sink (%pe)\n", ERR_PTR(ret));
}
/* phy test */

View File

@ -596,7 +596,7 @@ u64 *intel_fb_plane_get_modifiers(struct intel_display *display,
count++;
}
list = kmalloc_array(count, sizeof(*list), GFP_KERNEL);
list = kmalloc_objs(*list, count);
if (drm_WARN_ON(display->drm, !list))
return NULL;
@ -1289,7 +1289,7 @@ bool intel_plane_uses_fence(const struct intel_plane_state *plane_state)
return intel_plane_needs_fence(display) ||
(plane->fbc && !plane_state->no_fbc_reason &&
i915_gtt_view_is_normal(&plane_state->view.gtt));
intel_gtt_view_is_normal(&plane_state->view.gtt));
}
static int intel_fb_pitch(const struct intel_framebuffer *fb, int color_plane, unsigned int rotation)
@ -1511,7 +1511,7 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p
plane_view_height_tiles(fb, color_plane, dims, y));
}
if (i915_gtt_view_is_rotated(&view->gtt)) {
if (intel_gtt_view_is_rotated(&view->gtt)) {
drm_WARN_ON(display->drm, remap_info->linear);
check_array_bounds(display, view->gtt.rotated.plane, color_plane);
@ -1536,7 +1536,7 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p
/* rotate the tile dimensions to match the GTT view */
swap(tile_width, tile_height);
} else {
drm_WARN_ON(display->drm, !i915_gtt_view_is_remapped(&view->gtt));
drm_WARN_ON(display->drm, !intel_gtt_view_is_remapped(&view->gtt));
check_array_bounds(display, view->gtt.remapped.plane, color_plane);
@ -1632,13 +1632,13 @@ calc_plane_normal_size(const struct intel_framebuffer *fb, int color_plane,
static void intel_fb_view_init(struct intel_display *display,
struct intel_fb_view *view,
enum i915_gtt_view_type view_type,
enum intel_gtt_view_type view_type,
const struct intel_framebuffer *fb)
{
memset(view, 0, sizeof(*view));
view->gtt.type = view_type;
if (i915_gtt_view_is_remapped(&view->gtt) &&
if (intel_gtt_view_is_remapped(&view->gtt) &&
intel_fb_needs_pot_stride_remap(fb))
view->gtt.remapped.plane_alignment = SZ_2M / PAGE_SIZE;
}
@ -1706,7 +1706,7 @@ int intel_fill_fb_info(struct intel_display *display, struct intel_framebuffer *
unsigned int tile_size = intel_tile_size(display);
intel_fb_view_init(display, &fb->normal_view,
I915_GTT_VIEW_NORMAL, fb);
INTEL_GTT_VIEW_NORMAL, fb);
drm_WARN_ON(display->drm,
intel_fb_supports_90_270_rotation(fb) &&
@ -1714,10 +1714,10 @@ int intel_fill_fb_info(struct intel_display *display, struct intel_framebuffer *
if (intel_fb_supports_90_270_rotation(fb))
intel_fb_view_init(display, &fb->rotated_view,
I915_GTT_VIEW_ROTATED, fb);
INTEL_GTT_VIEW_ROTATED, fb);
if (intel_fb_needs_pot_stride_remap(fb))
intel_fb_view_init(display, &fb->remapped_view,
I915_GTT_VIEW_REMAPPED, fb);
INTEL_GTT_VIEW_REMAPPED, fb);
for (i = 0; i < num_planes; i++) {
struct fb_plane_view_dims view_dims;
@ -1845,7 +1845,7 @@ static void intel_plane_remap_gtt(struct intel_plane_state *plane_state)
intel_fb_view_init(display, &plane_state->view,
drm_rotation_90_or_270(rotation) ?
I915_GTT_VIEW_ROTATED : I915_GTT_VIEW_REMAPPED,
INTEL_GTT_VIEW_ROTATED : INTEL_GTT_VIEW_REMAPPED,
intel_fb);
src_x = plane_state->uapi.src.x1 >> 16;

View File

@ -1196,23 +1196,13 @@ xe3p_lpd_fbc_fp16_format_is_valid(const struct intel_plane_state *plane_state)
static bool xe3p_lpd_fbc_pixel_format_is_valid(const struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->hw.fb;
if (lnl_fbc_pixel_format_is_valid(plane_state))
return true;
if (xe3p_lpd_fbc_fp16_format_is_valid(plane_state))
return true;
switch (fb->format->format) {
case DRM_FORMAT_XRGB16161616:
case DRM_FORMAT_XBGR16161616:
case DRM_FORMAT_ARGB16161616:
case DRM_FORMAT_ABGR16161616:
return true;
default:
return false;
}
return false;
}
bool intel_fbc_need_pixel_normalizer(const struct intel_plane_state *plane_state)

View File

@ -867,6 +867,11 @@ void intel_hpd_poll_enable(struct intel_display *display)
if (!HAS_DISPLAY(display) || !intel_display_device_enabled(display))
return;
if (intel_display_rpm_pme_enabled(display)) {
drm_dbg_kms(display->drm, "PME wake capable device, skipping HPD polling.\n");
return;
}
WRITE_ONCE(display->hotplug.poll_enabled, true);
/*

View File

@ -137,11 +137,10 @@ bool intel_lspcon_detect_hdr_capability(struct intel_digital_port *dig_port)
u8 hdr_caps;
int ret;
ret = drm_dp_dpcd_read(&intel_dp->aux, get_hdr_status_reg(lspcon),
&hdr_caps, 1);
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, get_hdr_status_reg(lspcon), &hdr_caps);
if (ret < 0) {
drm_dbg_kms(display->drm, "HDR capability detection failed\n");
drm_dbg_kms(display->drm, "HDR capability detection failed (%pe)\n",
ERR_PTR(ret));
lspcon->hdr_supported = false;
} else if (hdr_caps & 0x1) {
drm_dbg_kms(display->drm, "LSPCON capable of HDR\n");
@ -244,11 +243,12 @@ static bool lspcon_wake_native_aux_ch(struct intel_lspcon *lspcon)
{
struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
struct intel_display *display = to_intel_display(intel_dp);
int ret;
u8 rev;
if (drm_dp_dpcd_readb(&lspcon_to_intel_dp(lspcon)->aux, DP_DPCD_REV,
&rev) != 1) {
drm_dbg_kms(display->drm, "Native AUX CH down\n");
ret = drm_dp_dpcd_read_byte(&lspcon_to_intel_dp(lspcon)->aux, DP_DPCD_REV, &rev);
if (ret < 0) {
drm_dbg_kms(display->drm, "Native AUX CH down (%pe)\n", ERR_PTR(ret));
return false;
}
@ -331,17 +331,17 @@ static bool lspcon_parade_fw_ready(struct drm_dp_aux *aux)
{
u8 avi_if_ctrl;
u8 retry;
ssize_t ret;
int ret;
/* Check if LSPCON FW is ready for data */
for (retry = 0; retry < 5; retry++) {
if (retry)
usleep_range(200, 300);
ret = drm_dp_dpcd_read(aux, LSPCON_PARADE_AVI_IF_CTRL,
&avi_if_ctrl, 1);
ret = drm_dp_dpcd_read_byte(aux, LSPCON_PARADE_AVI_IF_CTRL, &avi_if_ctrl);
if (ret < 0) {
drm_err(aux->drm_dev, "Failed to read AVI IF control\n");
drm_err(aux->drm_dev, "Failed to read AVI IF control (%pe)\n",
ERR_PTR(ret));
return false;
}
@ -371,10 +371,10 @@ static bool _lspcon_parade_write_infoframe_blocks(struct drm_dp_aux *aux,
reg = LSPCON_PARADE_AVI_IF_WRITE_OFFSET;
data = avi_buf + block_count * 8;
ret = drm_dp_dpcd_write(aux, reg, data, 8);
ret = drm_dp_dpcd_write_data(aux, reg, data, 8);
if (ret < 0) {
drm_err(aux->drm_dev, "Failed to write AVI IF block %d\n",
block_count);
drm_err(aux->drm_dev, "Failed to write AVI IF block %d (%pe)\n",
block_count, ERR_PTR(ret));
return false;
}
@ -386,10 +386,10 @@ static bool _lspcon_parade_write_infoframe_blocks(struct drm_dp_aux *aux,
*/
reg = LSPCON_PARADE_AVI_IF_CTRL;
avi_if_ctrl = LSPCON_PARADE_AVI_IF_KICKOFF | block_count;
ret = drm_dp_dpcd_write(aux, reg, &avi_if_ctrl, 1);
ret = drm_dp_dpcd_write_byte(aux, reg, avi_if_ctrl);
if (ret < 0) {
drm_err(aux->drm_dev, "Failed to update (0x%x), block %d\n",
reg, block_count);
drm_err(aux->drm_dev, "Failed to update (0x%x), block %d (%pe)\n",
reg, block_count, ERR_PTR(ret));
return false;
}
@ -435,35 +435,38 @@ static bool _lspcon_write_avi_infoframe_parade(struct drm_dp_aux *aux,
static bool _lspcon_write_avi_infoframe_mca(struct drm_dp_aux *aux,
const u8 *buffer, ssize_t len)
{
int ret;
u32 val = 0;
int ret, written = 0;
u32 retry;
u16 reg;
const u8 *data = buffer;
u8 val;
reg = LSPCON_MCA_AVI_IF_WRITE_OFFSET;
while (val < len) {
while (written < len) {
/* DPCD write for AVI IF can fail on a slow FW day, so retry */
for (retry = 0; retry < 5; retry++) {
ret = drm_dp_dpcd_write(aux, reg, (void *)data, 1);
if (ret == 1) {
ret = drm_dp_dpcd_write_byte(aux, reg, *data);
if (!ret) {
break;
} else if (retry < 4) {
mdelay(50);
continue;
} else {
drm_err(aux->drm_dev, "DPCD write failed at:0x%x\n", reg);
drm_err(aux->drm_dev, "DPCD write failed at:0x%x (%pe)\n",
reg, ERR_PTR(ret));
return false;
}
}
val++; reg++; data++;
written++;
reg++;
data++;
}
val = 0;
reg = LSPCON_MCA_AVI_IF_CTRL;
ret = drm_dp_dpcd_read(aux, reg, &val, 1);
ret = drm_dp_dpcd_read_byte(aux, reg, &val);
if (ret < 0) {
drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
drm_err(aux->drm_dev, "DPCD read failed, address 0x%x (%pe)\n",
reg, ERR_PTR(ret));
return false;
}
@ -471,16 +474,17 @@ static bool _lspcon_write_avi_infoframe_mca(struct drm_dp_aux *aux,
val &= ~LSPCON_MCA_AVI_IF_HANDLED;
val |= LSPCON_MCA_AVI_IF_KICKOFF;
ret = drm_dp_dpcd_write(aux, reg, &val, 1);
ret = drm_dp_dpcd_write_byte(aux, reg, val);
if (ret < 0) {
drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
drm_err(aux->drm_dev, "DPCD write failed at:0x%x (%pe)\n",
reg, ERR_PTR(ret));
return false;
}
val = 0;
ret = drm_dp_dpcd_read(aux, reg, &val, 1);
ret = drm_dp_dpcd_read_byte(aux, reg, &val);
if (ret < 0) {
drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
drm_err(aux->drm_dev, "DPCD read failed, address 0x%x (%pe)\n",
reg, ERR_PTR(ret));
return false;
}
@ -612,12 +616,13 @@ void lspcon_set_infoframes(struct intel_encoder *encoder,
static bool _lspcon_read_avi_infoframe_enabled_mca(struct drm_dp_aux *aux)
{
int ret;
u32 val = 0;
u16 reg = LSPCON_MCA_AVI_IF_CTRL;
u8 val;
ret = drm_dp_dpcd_read(aux, reg, &val, 1);
ret = drm_dp_dpcd_read_byte(aux, reg, &val);
if (ret < 0) {
drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
drm_err(aux->drm_dev, "DPCD read failed, address 0x%x (%pe)\n",
reg, ERR_PTR(ret));
return false;
}
@ -627,12 +632,13 @@ static bool _lspcon_read_avi_infoframe_enabled_mca(struct drm_dp_aux *aux)
static bool _lspcon_read_avi_infoframe_enabled_parade(struct drm_dp_aux *aux)
{
int ret;
u32 val = 0;
u16 reg = LSPCON_PARADE_AVI_IF_CTRL;
u8 val;
ret = drm_dp_dpcd_read(aux, reg, &val, 1);
ret = drm_dp_dpcd_read_byte(aux, reg, &val);
if (ret < 0) {
drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
drm_err(aux->drm_dev, "DPCD read failed, address 0x%x (%pe)\n",
reg, ERR_PTR(ret));
return false;
}

View File

@ -94,9 +94,9 @@ void intel_parent_fb_pin_dpt_unpin(struct intel_display *display,
struct i915_vma *intel_parent_fb_pin_reuse_vma(struct intel_display *display,
struct i915_vma *old_ggtt_vma,
struct drm_gem_object *old_obj,
const struct i915_gtt_view *old_view,
const struct intel_gtt_view *old_view,
struct drm_gem_object *new_obj,
const struct i915_gtt_view *new_view,
const struct intel_gtt_view *new_view,
u32 *out_offset)
{
if (!display->parent->fb_pin->reuse_vma)

View File

@ -11,12 +11,12 @@ struct dma_fence;
struct drm_file;
struct drm_gem_object;
struct drm_scanout_buffer;
struct i915_gtt_view;
struct i915_vma;
struct intel_display;
struct intel_dpt;
struct intel_fb_pin_params;
struct intel_frontbuffer;
struct intel_gtt_view;
struct intel_hdcp_gsc_context;
struct intel_panic;
struct intel_stolen_node;
@ -53,9 +53,9 @@ void intel_parent_fb_pin_dpt_unpin(struct intel_display *display,
struct i915_vma *intel_parent_fb_pin_reuse_vma(struct intel_display *display,
struct i915_vma *old_ggtt_vma,
struct drm_gem_object *old_obj,
const struct i915_gtt_view *old_view,
const struct intel_gtt_view *old_view,
struct drm_gem_object *new_obj,
const struct i915_gtt_view *new_view,
const struct intel_gtt_view *new_view,
u32 *out_offset);
void intel_parent_fb_pin_get_map(struct intel_display *display,
struct i915_vma *vma, struct iosys_map *map);

View File

@ -462,6 +462,42 @@ intel_plane_colorop_replace_blob(struct intel_plane_state *plane_state,
return false;
}
static u32
fixedmatrix_colorop_to_encoding(enum drm_colorop_fixed_matrix_type fm_type)
{
switch (fm_type) {
case DRM_COLOROP_FM_YCBCR709_FULL_RGB:
case DRM_COLOROP_FM_YCBCR709_LIMITED_RGB:
return DRM_COLOR_YCBCR_BT709;
case DRM_COLOROP_FM_YCBCR2020_NC_FULL_RGB:
case DRM_COLOROP_FM_YCBCR2020_NC_LIMITED_RGB:
return DRM_COLOR_YCBCR_BT2020;
case DRM_COLOROP_FM_YCBCR601_FULL_RGB:
case DRM_COLOROP_FM_YCBCR601_LIMITED_RGB:
default:
return DRM_COLOR_YCBCR_BT601;
}
}
static u32
fixedmatrix_colorop_to_range(enum drm_colorop_fixed_matrix_type fm_type)
{
switch (fm_type) {
case DRM_COLOROP_FM_YCBCR601_FULL_RGB:
case DRM_COLOROP_FM_YCBCR709_FULL_RGB:
case DRM_COLOROP_FM_YCBCR2020_NC_FULL_RGB:
return DRM_COLOR_YCBCR_FULL_RANGE;
case DRM_COLOROP_FM_YCBCR601_LIMITED_RGB:
case DRM_COLOROP_FM_YCBCR709_LIMITED_RGB:
case DRM_COLOROP_FM_YCBCR2020_NC_LIMITED_RGB:
default:
return DRM_COLOR_YCBCR_LIMITED_RANGE;
}
}
static void
intel_plane_color_copy_uapi_to_hw_state(struct intel_atomic_state *state,
struct intel_plane_state *plane_state,
@ -474,6 +510,7 @@ intel_plane_color_copy_uapi_to_hw_state(struct intel_atomic_state *state,
struct drm_property_blob *blob;
struct intel_crtc_state *new_crtc_state = state ?
intel_atomic_get_new_crtc_state(state, crtc) : NULL;
enum drm_colorop_fixed_matrix_type fm_type;
bool changed = false;
int i = 0;
@ -485,11 +522,23 @@ intel_plane_color_copy_uapi_to_hw_state(struct intel_atomic_state *state,
while (iter_colorop) {
for_each_new_colorop_in_state(&state->base, colorop, new_colorop_state, i) {
if (new_colorop_state->colorop == iter_colorop) {
blob = new_colorop_state->bypass ? NULL : new_colorop_state->data;
intel_colorop = to_intel_colorop(colorop);
changed |= intel_plane_colorop_replace_blob(plane_state,
if (intel_colorop->id == INTEL_PLANE_CB_CSC_FF) {
fm_type = new_colorop_state->fixed_matrix_type;
plane_state->hw.csc_ff_enable =
!new_colorop_state->bypass;
plane_state->hw.color_encoding =
fixedmatrix_colorop_to_encoding(fm_type);
plane_state->hw.color_range =
fixedmatrix_colorop_to_range(fm_type);
} else {
blob = new_colorop_state->bypass ?
NULL : new_colorop_state->data;
changed |= intel_plane_colorop_replace_blob(plane_state,
intel_colorop,
blob);
}
}
}
iter_colorop = iter_colorop->next;

View File

@ -471,13 +471,15 @@ static u8 intel_dp_get_sink_sync_latency(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
u8 val = 8; /* assume the worst if we can't read the value */
int ret;
if (drm_dp_dpcd_readb(&intel_dp->aux,
DP_SYNCHRONIZATION_LATENCY_IN_SINK, &val) == 1)
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_SYNCHRONIZATION_LATENCY_IN_SINK, &val);
if (!ret)
val &= DP_MAX_RESYNC_FRAME_COUNT_MASK;
else
drm_dbg_kms(display->drm,
"Unable to get sink synchronization latency, assuming 8 frames\n");
"Unable to get sink synchronization latency, assuming 8 frames (%pe)\n",
ERR_PTR(ret));
return val;
}
@ -485,7 +487,7 @@ static void _psr_compute_su_granularity(struct intel_dp *intel_dp,
struct intel_connector *connector)
{
struct intel_display *display = to_intel_display(intel_dp);
ssize_t r;
int ret;
__le16 w;
u8 y;
@ -500,21 +502,23 @@ static void _psr_compute_su_granularity(struct intel_dp *intel_dp,
goto exit;
}
r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_X_GRANULARITY, &w, sizeof(w));
if (r != sizeof(w))
ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_PSR2_SU_X_GRANULARITY, &w, sizeof(w));
if (ret < 0)
drm_dbg_kms(display->drm,
"Unable to read selective update x granularity\n");
"Unable to read selective update x granularity (%pe)\n",
ERR_PTR(ret));
/*
* Spec says that if the value read is 0 the default granularity should
* be used instead.
*/
if (r != sizeof(w) || w == 0)
if (ret < 0 || w == 0)
w = cpu_to_le16(4);
r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_Y_GRANULARITY, &y, 1);
if (r != 1) {
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_PSR2_SU_Y_GRANULARITY, &y);
if (ret < 0) {
drm_dbg_kms(display->drm,
"Unable to read selective update y granularity\n");
"Unable to read selective update y granularity (%pe)\n",
ERR_PTR(ret));
y = 4;
}
if (y == 0)
@ -796,11 +800,11 @@ static void _panel_replay_enable_sink(struct intel_dp *intel_dp,
panel_replay_config[1] |=
DP_PANEL_REPLAY_SU_REGION_SCANLINE_CAPTURE;
drm_dp_dpcd_write(&intel_dp->aux, PANEL_REPLAY_CONFIG,
panel_replay_config, sizeof(panel_replay_config));
drm_dp_dpcd_write_data(&intel_dp->aux, PANEL_REPLAY_CONFIG,
panel_replay_config, sizeof(panel_replay_config));
panel_replay_config_3 = intel_dp_as_sdp_transmission_time();
drm_dp_dpcd_writeb(&intel_dp->aux, PANEL_REPLAY_CONFIG3, panel_replay_config_3);
drm_dp_dpcd_write_byte(&intel_dp->aux, PANEL_REPLAY_CONFIG3, panel_replay_config_3);
}
static void _psr_enable_sink(struct intel_dp *intel_dp,
@ -827,10 +831,10 @@ static void _psr_enable_sink(struct intel_dp *intel_dp,
if (intel_dp->psr.entry_setup_frames > 0)
val |= DP_PSR_FRAME_CAPTURE;
drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, val);
drm_dp_dpcd_write_byte(&intel_dp->aux, DP_PSR_EN_CFG, val);
val |= DP_PSR_ENABLE;
drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, val);
drm_dp_dpcd_write_byte(&intel_dp->aux, DP_PSR_EN_CFG, val);
}
static void intel_psr_enable_sink(struct intel_dp *intel_dp,
@ -843,7 +847,7 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp,
_psr_enable_sink(intel_dp, crtc_state);
if (intel_dp_is_edp(intel_dp))
drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
drm_dp_dpcd_write_byte(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
}
void intel_psr_panel_replay_enable_sink(struct intel_dp *intel_dp)
@ -854,8 +858,8 @@ void intel_psr_panel_replay_enable_sink(struct intel_dp *intel_dp)
* ensure this bit is cleared/set accordingly.
*/
if (CAN_PANEL_REPLAY(intel_dp) && panel_replay_global_enabled(intel_dp))
drm_dp_dpcd_writeb(&intel_dp->aux, PANEL_REPLAY_CONFIG,
DP_PANEL_REPLAY_ENABLE);
drm_dp_dpcd_write_byte(&intel_dp->aux, PANEL_REPLAY_CONFIG,
DP_PANEL_REPLAY_ENABLE);
}
static u32 intel_psr1_get_tp_time(struct intel_dp *intel_dp)
@ -2373,11 +2377,11 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp)
/* Disable PSR on Sink */
if (!intel_dp->psr.panel_replay_enabled) {
drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, 0);
drm_dp_dpcd_write_byte(&intel_dp->aux, DP_PSR_EN_CFG, 0);
if (intel_dp->psr.sel_update_enabled)
drm_dp_dpcd_writeb(&intel_dp->aux,
DP_RECEIVER_ALPM_CONFIG, 0);
drm_dp_dpcd_write_byte(&intel_dp->aux,
DP_RECEIVER_ALPM_CONFIG, 0);
}
/* Wa_16025596647 */
@ -3517,7 +3521,7 @@ static void intel_psr_handle_irq(struct intel_dp *intel_dp)
intel_psr_disable_locked(intel_dp);
psr->sink_not_reliable = true;
/* let's make sure that sink is awaken */
drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
drm_dp_dpcd_write_byte(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
}
static void intel_psr_work(struct work_struct *work)
@ -3796,15 +3800,15 @@ static int psr_get_status_and_error_status(struct intel_dp *intel_dp,
offset = intel_dp->psr.panel_replay_enabled ?
DP_SINK_DEVICE_PR_AND_FRAME_LOCK_STATUS : DP_PSR_STATUS;
ret = drm_dp_dpcd_readb(aux, offset, status);
if (ret != 1)
ret = drm_dp_dpcd_read_byte(aux, offset, status);
if (ret < 0)
return ret;
offset = intel_dp->psr.panel_replay_enabled ?
DP_PANEL_REPLAY_ERROR_STATUS : DP_PSR_ERROR_STATUS;
ret = drm_dp_dpcd_readb(aux, offset, error_status);
if (ret != 1)
ret = drm_dp_dpcd_read_byte(aux, offset, error_status);
if (ret < 0)
return ret;
*status = *status & DP_PSR_SINK_STATE_MASK;
@ -3829,12 +3833,12 @@ static void psr_capability_changed_check(struct intel_dp *intel_dp)
{
struct intel_display *display = to_intel_display(intel_dp);
struct intel_psr *psr = &intel_dp->psr;
int ret;
u8 val;
int r;
r = drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_ESI, &val);
if (r != 1) {
drm_err(display->drm, "Error reading DP_PSR_ESI\n");
ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_PSR_ESI, &val);
if (ret < 0) {
drm_err(display->drm, "Error reading DP_PSR_ESI (%pe)\n", ERR_PTR(ret));
return;
}
@ -3845,7 +3849,7 @@ static void psr_capability_changed_check(struct intel_dp *intel_dp)
"Sink PSR capability changed, disabling PSR\n");
/* Clearing it */
drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_ESI, val);
drm_dp_dpcd_write_byte(&intel_dp->aux, DP_PSR_ESI, val);
}
}
@ -3913,10 +3917,10 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp)
"PSR_ERROR_STATUS unhandled errors %x\n",
error_status & ~errors);
/* clear status register */
drm_dp_dpcd_writeb(&intel_dp->aux,
panel_replay_enabled ?
DP_PANEL_REPLAY_ERROR_STATUS : DP_PSR_ERROR_STATUS,
error_status);
drm_dp_dpcd_write_byte(&intel_dp->aux,
panel_replay_enabled ?
DP_PANEL_REPLAY_ERROR_STATUS : DP_PSR_ERROR_STATUS,
error_status);
if (!psr->panel_replay_enabled) {
psr_alpm_check(intel_dp);

View File

@ -276,6 +276,8 @@
#define PR_ALPM_CTL_ADAPTIVE_SYNC_SDP_POSITION_T1_OR_T2 REG_FIELD_PREP(PR_ALPM_CTL_ADAPTIVE_SYNC_SDP_POSITION_MASK, 0)
#define PR_ALPM_CTL_ADAPTIVE_SYNC_SDP_POSITION_T1 REG_FIELD_PREP(PR_ALPM_CTL_ADAPTIVE_SYNC_SDP_POSITION_MASK, 1)
#define PR_ALPM_CTL_ADAPTIVE_SYNC_SDP_POSITION_T2 REG_FIELD_PREP(PR_ALPM_CTL_ADAPTIVE_SYNC_SDP_POSITION_MASK, 2)
#define PR_ALPM_CTL_AS_SDP_SKIP_FRAMES_MASK REG_GENMASK(27, 16)
#define PR_ALPM_CTL_AS_SDP_SKIP_FRAMES(frames) REG_FIELD_PREP(PR_ALPM_CTL_AS_SDP_SKIP_FRAMES_MASK, (frames))
#define _ALPM_CTL_A 0x60950
#define ALPM_CTL(dev_priv, tran) _MMIO_TRANS2(dev_priv, tran, _ALPM_CTL_A)

View File

@ -17,6 +17,8 @@
#include "intel_cmtg.h"
#include "intel_crtc.h"
#include "intel_de.h"
#include "intel_dip.h"
#include "intel_dip_regs.h"
#include "intel_display_limits.h"
#include "intel_display_regs.h"
#include "intel_display_types.h"
@ -712,17 +714,7 @@ void intel_vrr_set_transcoder_timings(const struct intel_crtc_state *crtc_state)
VRR_VSYNC_END(crtc_state->vrr.vsync_end) |
VRR_VSYNC_START(crtc_state->vrr.vsync_start));
/*
* For BMG and LNL+ onwards the EMP_AS_SDP_TL is used for programming
* double buffering point and transmission line for VRR packets for
* HDMI2.1/DP/eDP/DP->HDMI2.1 PCON.
* Since currently we support VRR only for DP/eDP, so this is programmed
* to for Adaptive Sync SDP to Vsync start.
*/
if (DISPLAY_VERx100(display) == 1401 || DISPLAY_VER(display) >= 20)
intel_de_write(display,
EMP_AS_SDP_TL(display, cpu_transcoder),
EMP_AS_SDP_DB_TL(crtc_state->vrr.vsync_start));
intel_dip_write_emp_as_sdp_tl(crtc_state);
}
void

View File

@ -174,12 +174,6 @@
#define VRR_VSYNC_START_MASK REG_GENMASK(12, 0)
#define VRR_VSYNC_START(vsync_start) REG_FIELD_PREP(VRR_VSYNC_START_MASK, (vsync_start))
/* Common register for HDMI EMP and DP AS SDP */
#define _EMP_AS_SDP_TL_A 0x60204
#define EMP_AS_SDP_TL(display, trans) _MMIO_TRANS2((display), (trans), _EMP_AS_SDP_TL_A)
#define EMP_AS_SDP_DB_TL_MASK REG_GENMASK(12, 0)
#define EMP_AS_SDP_DB_TL(db_transmit_line) REG_FIELD_PREP(EMP_AS_SDP_DB_TL_MASK, (db_transmit_line))
#define _TRANS_CMRR_M_LO_A 0x604F0
#define TRANS_CMRR_M_LO(display, trans) _MMIO_TRANS2((display), (trans), _TRANS_CMRR_M_LO_A)

View File

@ -1242,36 +1242,46 @@ static u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state)
return plane_color_ctl;
}
static u32 glk_plane_color_ctl(const struct intel_plane_state *plane_state)
static u32 glk_plane_color_ctl_input_csc(const struct intel_plane_state *plane_state)
{
struct intel_display *display = to_intel_display(plane_state);
const struct drm_framebuffer *fb = plane_state->hw.fb;
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
bool color_pipeline = !!plane_state->uapi.color_pipeline;
bool needs_csc = color_pipeline ? plane_state->hw.csc_ff_enable : fb->format->is_yuv;
u32 ctl = 0;
if (!needs_csc)
return 0;
if (!icl_is_hdr_plane(display, plane->id)) {
switch (plane_state->hw.color_encoding) {
case DRM_COLOR_YCBCR_BT709:
ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709;
break;
case DRM_COLOR_YCBCR_BT2020:
ctl |= PLANE_COLOR_CSC_MODE_YUV2020_TO_RGB2020;
break;
default:
ctl |= PLANE_COLOR_CSC_MODE_YUV601_TO_RGB601;
}
} else {
ctl |= PLANE_COLOR_INPUT_CSC_ENABLE;
}
if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
return ctl;
}
static u32 glk_plane_color_ctl(const struct intel_plane_state *plane_state)
{
u32 plane_color_ctl = 0;
plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE;
plane_color_ctl |= glk_plane_color_ctl_alpha(plane_state);
if (fb->format->is_yuv && !icl_is_hdr_plane(display, plane->id)) {
switch (plane_state->hw.color_encoding) {
case DRM_COLOR_YCBCR_BT709:
plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709;
break;
case DRM_COLOR_YCBCR_BT2020:
plane_color_ctl |=
PLANE_COLOR_CSC_MODE_YUV2020_TO_RGB2020;
break;
default:
plane_color_ctl |=
PLANE_COLOR_CSC_MODE_YUV601_TO_RGB601;
}
if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
} else if (fb->format->is_yuv) {
plane_color_ctl |= PLANE_COLOR_INPUT_CSC_ENABLE;
if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
}
plane_color_ctl |= glk_plane_color_ctl_input_csc(plane_state);
if (plane_state->force_black)
plane_color_ctl |= PLANE_COLOR_PLANE_CSC_ENABLE;
@ -1613,7 +1623,8 @@ icl_plane_update_noarm(struct intel_dsb *dsb,
intel_de_write_dsb(display, dsb, PLANE_COLOR_CTL(pipe, plane_id),
plane_color_ctl);
if (fb->format->is_yuv && icl_is_hdr_plane(display, plane_id))
if (icl_is_hdr_plane(display, plane_id) &&
(fb->format->is_yuv || plane_state->hw.csc_ff_enable))
icl_program_input_csc(dsb, plane, plane_state);
skl_write_plane_wm(dsb, plane, crtc_state);

View File

@ -421,7 +421,7 @@ struct i915_vma *
i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
struct i915_gem_ww_ctx *ww,
u32 alignment, unsigned int guard,
const struct i915_gtt_view *view,
const struct intel_gtt_view *view,
unsigned int flags)
{
struct drm_i915_private *i915 = to_i915(obj->base.dev);
@ -462,7 +462,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
*/
vma = ERR_PTR(-ENOSPC);
if ((flags & PIN_MAPPABLE) == 0 &&
(!view || view->type == I915_GTT_VIEW_NORMAL))
(!view || intel_gtt_view_is_normal(view)))
vma = i915_gem_object_ggtt_pin_ww(obj, ww, view, 0, alignment,
flags | PIN_MAPPABLE |
PIN_NONBLOCK);

View File

@ -196,17 +196,17 @@ int i915_gem_mmap_gtt_version(void)
return 5;
}
static inline struct i915_gtt_view
static inline struct intel_gtt_view
compute_partial_view(const struct drm_i915_gem_object *obj,
pgoff_t page_offset,
unsigned int chunk)
{
struct i915_gtt_view view;
struct intel_gtt_view view;
if (i915_gem_object_is_tiled(obj))
chunk = roundup(chunk, tile_row_pages(obj) ?: 1);
view.type = I915_GTT_VIEW_PARTIAL;
view.type = INTEL_GTT_VIEW_PARTIAL;
view.partial.offset = rounddown(page_offset, chunk);
view.partial.size =
min_t(unsigned int, chunk,
@ -214,7 +214,7 @@ compute_partial_view(const struct drm_i915_gem_object *obj,
/* If the partial covers the entire object, just create a normal VMA. */
if (chunk >= obj->base.size >> PAGE_SHIFT)
view.type = I915_GTT_VIEW_NORMAL;
view.type = INTEL_GTT_VIEW_NORMAL;
return view;
}
@ -391,12 +391,12 @@ static vm_fault_t vm_fault_gtt(struct vm_fault *vmf)
PIN_NOEVICT);
if (IS_ERR(vma) && vma != ERR_PTR(-EDEADLK)) {
/* Use a partial view if it is bigger than available space */
struct i915_gtt_view view =
struct intel_gtt_view view =
compute_partial_view(obj, page_offset, MIN_CHUNK_PAGES);
unsigned int flags;
flags = PIN_MAPPABLE | PIN_NOSEARCH;
if (view.type == I915_GTT_VIEW_NORMAL)
if (intel_gtt_view_is_normal(&view))
flags |= PIN_NONBLOCK; /* avoid warnings for pinned */
/*
@ -407,7 +407,7 @@ static vm_fault_t vm_fault_gtt(struct vm_fault *vmf)
vma = i915_gem_object_ggtt_pin_ww(obj, &ww, &view, 0, 0, flags);
if (IS_ERR(vma) && vma != ERR_PTR(-EDEADLK)) {
flags = PIN_MAPPABLE;
view.type = I915_GTT_VIEW_PARTIAL;
view.type = INTEL_GTT_VIEW_PARTIAL;
vma = i915_gem_object_ggtt_pin_ww(obj, &ww, &view, 0, 0, flags);
}

View File

@ -776,7 +776,7 @@ struct i915_vma * __must_check
i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
struct i915_gem_ww_ctx *ww,
u32 alignment, unsigned int guard,
const struct i915_gtt_view *view,
const struct intel_gtt_view *view,
unsigned int flags);
void i915_gem_object_make_unshrinkable(struct drm_i915_gem_object *obj);

View File

@ -97,7 +97,7 @@ static int check_partial_mapping(struct drm_i915_gem_object *obj,
{
const unsigned long npages = obj->base.size / PAGE_SIZE;
struct drm_i915_private *i915 = to_i915(obj->base.dev);
struct i915_gtt_view view;
struct intel_gtt_view view;
struct i915_vma *vma;
unsigned long offset;
unsigned long page;
@ -214,7 +214,7 @@ static int check_partial_mappings(struct drm_i915_gem_object *obj,
}
for_each_prime_number_from(page, 1, npages) {
struct i915_gtt_view view =
struct intel_gtt_view view =
compute_partial_view(obj, page, MIN_CHUNK_PAGES);
unsigned long offset;
u32 __iomem *io;

View File

@ -1607,7 +1607,7 @@ u64 intel_engine_get_last_batch_head(const struct intel_engine_cs *engine)
static unsigned long stop_timeout(const struct intel_engine_cs *engine)
{
if (in_atomic() || irqs_disabled()) /* inside atomic preempt-reset? */
if (in_atomic() || irqs_disabled() || rcu_preempt_depth()) /* inside atomic preempt-reset? */
return 0;
/*

View File

@ -1300,7 +1300,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
* and context switches) submission.
*/
spin_lock(&sched_engine->lock);
spin_lock_irq(&sched_engine->lock);
/*
* If the queue is higher priority than the last
@ -1400,7 +1400,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
* Even if ELSP[1] is occupied and not worthy
* of timeslices, our queue might be.
*/
spin_unlock(&sched_engine->lock);
spin_unlock_irq(&sched_engine->lock);
return;
}
}
@ -1426,7 +1426,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
if (last && !can_merge_rq(last, rq)) {
spin_unlock(&ve->base.sched_engine->lock);
spin_unlock(&engine->sched_engine->lock);
spin_unlock_irq(&engine->sched_engine->lock);
return; /* leave this for another sibling */
}
@ -1588,7 +1588,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
*/
sched_engine->queue_priority_hint = queue_prio(sched_engine);
i915_sched_engine_reset_on_empty(sched_engine);
spin_unlock(&sched_engine->lock);
spin_unlock_irq(&sched_engine->lock);
/*
* We can skip poking the HW if we ended up with exactly the same set
@ -1614,13 +1614,6 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
}
}
static void execlists_dequeue_irq(struct intel_engine_cs *engine)
{
local_irq_disable(); /* Suspend interrupts across request submission */
execlists_dequeue(engine);
local_irq_enable(); /* flush irq_work (e.g. breadcrumb enabling) */
}
static void clear_ports(struct i915_request **ports, int count)
{
memset_p((void **)ports, NULL, count);
@ -2475,7 +2468,7 @@ static void execlists_submission_tasklet(struct tasklet_struct *t)
}
if (!engine->execlists.pending[0]) {
execlists_dequeue_irq(engine);
execlists_dequeue(engine);
start_timeslice(engine);
}

View File

@ -1433,13 +1433,7 @@ static void intel_gt_reset_global(struct intel_gt *gt,
need_display_reset;
if (reset_display) {
if (atomic_read(&i915->pending_fb_pin)) {
drm_dbg_kms(&i915->drm,
"Modeset potentially stuck, unbreaking through wedging\n");
intel_gt_set_wedged(gt);
}
intel_gt_set_wedged(gt);
intel_display_reset_prepare(display);
}

View File

@ -277,11 +277,11 @@ static int live_engine_busy_stats(void *arg)
st_engine_heartbeat_disable(engine);
ENGINE_TRACE(engine, "measuring idle time\n");
preempt_disable();
migrate_disable();
de = intel_engine_get_busy_time(engine, &t[0]);
udelay(100);
de = ktime_sub(intel_engine_get_busy_time(engine, &t[1]), de);
preempt_enable();
migrate_enable();
dt = ktime_sub(t[1], t[0]);
if (de < 0 || de > 10) {
pr_err("%s: reported %lldns [%d%%] busyness while sleeping [for %lldns]\n",
@ -316,11 +316,11 @@ static int live_engine_busy_stats(void *arg)
}
ENGINE_TRACE(engine, "measuring busy time\n");
preempt_disable();
migrate_disable();
de = intel_engine_get_busy_time(engine, &t[0]);
mdelay(100);
de = ktime_sub(intel_engine_get_busy_time(engine, &t[1]), de);
preempt_enable();
migrate_enable();
dt = ktime_sub(t[1], t[0]);
if (100 * de < 95 * dt || 95 * de > 100 * dt) {
pr_err("%s: reported %lldns [%d%%] busyness while spinning [for %lldns]\n",

View File

@ -362,7 +362,7 @@ static inline int intel_guc_send_busy_loop(struct intel_guc *guc,
{
int err;
unsigned int sleep_period_ms = 1;
bool not_atomic = !in_atomic() && !irqs_disabled();
bool not_atomic = !in_atomic() && !irqs_disabled() && !rcu_preempt_depth();
/*
* FIXME: Have caller pass in if we are in an atomic context to avoid

View File

@ -34,6 +34,8 @@
*
*/
#include <linux/string_choices.h>
#include <drm/drm_print.h>
#include "gt/intel_ggtt_fencing.h"
@ -76,7 +78,7 @@ static int alloc_gm(struct intel_vgpu *vgpu, bool high_gm)
mutex_unlock(&gt->ggtt->vm.mutex);
if (ret)
gvt_err("fail to alloc %s gm space from host\n",
high_gm ? "high" : "low");
str_high_low(high_gm));
return ret;
}

View File

@ -179,7 +179,7 @@ i915_debugfs_describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
struct i915_vma *vma;
int pin_count = 0;
seq_printf(m, "%pK: %c%c%c %8zdKiB %02x %02x %s%s%s",
seq_printf(m, "%p: %c%c%c %8zdKiB %02x %02x %s%s%s",
&obj->base,
get_tiling_flag(obj),
get_global_flag(obj),
@ -209,18 +209,13 @@ i915_debugfs_describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
stringify_page_sizes(vma->resource->page_sizes_gtt,
NULL, 0));
if (i915_vma_is_ggtt(vma) || i915_vma_is_dpt(vma)) {
switch (vma->gtt_view.type) {
case I915_GTT_VIEW_NORMAL:
if (intel_gtt_view_is_normal(&vma->gtt_view)) {
seq_puts(m, ", normal");
break;
case I915_GTT_VIEW_PARTIAL:
} else if (intel_gtt_view_is_partial(&vma->gtt_view)) {
seq_printf(m, ", partial [%08llx+%x]",
vma->gtt_view.partial.offset << PAGE_SHIFT,
vma->gtt_view.partial.size << PAGE_SHIFT);
break;
case I915_GTT_VIEW_ROTATED:
} else if (intel_gtt_view_is_rotated(&vma->gtt_view)) {
seq_printf(m, ", rotated [(%ux%u, src_stride=%u, dst_stride=%u, offset=%u), (%ux%u, src_stride=%u, dst_stride=%u, offset=%u)]",
vma->gtt_view.rotated.plane[0].width,
vma->gtt_view.rotated.plane[0].height,
@ -232,9 +227,7 @@ i915_debugfs_describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
vma->gtt_view.rotated.plane[1].src_stride,
vma->gtt_view.rotated.plane[1].dst_stride,
vma->gtt_view.rotated.plane[1].offset);
break;
case I915_GTT_VIEW_REMAPPED:
} else if (intel_gtt_view_is_remapped(&vma->gtt_view)) {
seq_printf(m, ", remapped [(%ux%u, src_stride=%u, dst_stride=%u, offset=%u), (%ux%u, src_stride=%u, dst_stride=%u, offset=%u)]",
vma->gtt_view.remapped.plane[0].width,
vma->gtt_view.remapped.plane[0].height,
@ -246,11 +239,8 @@ i915_debugfs_describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
vma->gtt_view.remapped.plane[1].src_stride,
vma->gtt_view.remapped.plane[1].dst_stride,
vma->gtt_view.remapped.plane[1].offset);
break;
default:
} else {
MISSING_CASE(vma->gtt_view.type);
break;
}
}
if (vma->fence)

View File

@ -139,7 +139,6 @@ struct i915_vma *i915_dpt_pin_to_ggtt(struct intel_dpt *dpt, unsigned int alignm
pin_flags |= PIN_MAPPABLE;
wakeref = intel_runtime_pm_get(&i915->runtime_pm);
atomic_inc(&i915->pending_fb_pin);
for_i915_gem_ww(&ww, err, true) {
err = i915_gem_object_lock(dpt->obj, &ww);
@ -169,7 +168,6 @@ struct i915_vma *i915_dpt_pin_to_ggtt(struct intel_dpt *dpt, unsigned int alignm
dpt->obj->mm.dirty = true;
atomic_dec(&i915->pending_fb_pin);
intel_runtime_pm_put(&i915->runtime_pm, wakeref);
return err ? ERR_PTR(err) : vma;

View File

@ -315,8 +315,6 @@ struct drm_i915_private {
/* The TTM device structure. */
struct ttm_device bdev;
atomic_t pending_fb_pin;
I915_SELFTEST_DECLARE(struct i915_selftest_stash selftest;)
/*

View File

@ -35,8 +35,6 @@ intel_fb_pin_to_dpt(struct drm_gem_object *_obj, struct intel_dpt *dpt,
if (WARN_ON(!i915_gem_object_is_framebuffer(obj)))
return ERR_PTR(-EINVAL);
atomic_inc(&i915->pending_fb_pin);
for_i915_gem_ww(&ww, ret, true) {
ret = i915_gem_object_lock(obj, &ww);
if (ret)
@ -98,7 +96,6 @@ intel_fb_pin_to_dpt(struct drm_gem_object *_obj, struct intel_dpt *dpt,
*/
drm_WARN_ON(&i915->drm, i915_dpt_offset(vma));
err:
atomic_dec(&i915->pending_fb_pin);
return vma;
}
@ -132,8 +129,6 @@ intel_fb_pin_to_ggtt(struct drm_gem_object *_obj,
*/
wakeref = intel_runtime_pm_get(&i915->runtime_pm);
atomic_inc(&i915->pending_fb_pin);
pinctl = 0;
/* PIN_MAPPABLE limits the address to GMADR size */
if (pin_params->needs_low_address)
@ -206,7 +201,6 @@ intel_fb_pin_to_ggtt(struct drm_gem_object *_obj,
if (ret)
vma = ERR_PTR(ret);
atomic_dec(&i915->pending_fb_pin);
intel_runtime_pm_put(&i915->runtime_pm, wakeref);
return vma;
}

View File

@ -902,7 +902,7 @@ static void discard_ggtt_vma(struct i915_vma *vma)
struct i915_vma *
i915_gem_object_ggtt_pin_ww(struct drm_i915_gem_object *obj,
struct i915_gem_ww_ctx *ww,
const struct i915_gtt_view *view,
const struct intel_gtt_view *view,
u64 size, u64 alignment, u64 flags)
{
struct drm_i915_private *i915 = to_i915(obj->base.dev);
@ -913,7 +913,7 @@ i915_gem_object_ggtt_pin_ww(struct drm_i915_gem_object *obj,
GEM_WARN_ON(!ww);
if (flags & PIN_MAPPABLE &&
(!view || view->type == I915_GTT_VIEW_NORMAL)) {
(!view || intel_gtt_view_is_normal(view))) {
/*
* If the required space is larger than the available
* aperture, we will not able to find a slot for the
@ -1004,7 +1004,7 @@ i915_gem_object_ggtt_pin_ww(struct drm_i915_gem_object *obj,
struct i915_vma * __must_check
i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
const struct i915_gtt_view *view,
const struct intel_gtt_view *view,
u64 size, u64 alignment, u64 flags)
{
struct i915_gem_ww_ctx ww;

View File

@ -36,8 +36,8 @@ struct drm_file;
struct drm_i915_gem_object;
struct drm_i915_private;
struct i915_gem_ww_ctx;
struct i915_gtt_view;
struct i915_vma;
struct intel_gtt_view;
#define I915_GEM_GPU_DOMAINS \
(I915_GEM_DOMAIN_RENDER | \
@ -55,12 +55,12 @@ void i915_gem_drain_workqueue(struct drm_i915_private *i915);
struct i915_vma * __must_check
i915_gem_object_ggtt_pin_ww(struct drm_i915_gem_object *obj,
struct i915_gem_ww_ctx *ww,
const struct i915_gtt_view *view,
const struct intel_gtt_view *view,
u64 size, u64 alignment, u64 flags);
struct i915_vma * __must_check
i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
const struct i915_gtt_view *view,
const struct intel_gtt_view *view,
u64 size, u64 alignment, u64 flags);
int i915_gem_object_unbind(struct drm_i915_gem_object *obj,

View File

@ -1,74 +0,0 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2025 Intel Corporation */
#ifndef __I915_GTT_VIEW_TYPES_H__
#define __I915_GTT_VIEW_TYPES_H__
#include <linux/types.h>
struct intel_remapped_plane_info {
/* in gtt pages */
u32 offset:31;
u32 linear:1;
union {
/* in gtt pages for !linear */
struct {
u16 width;
u16 height;
u16 src_stride;
u16 dst_stride;
};
/* in gtt pages for linear */
u32 size;
};
} __packed;
struct intel_rotation_info {
struct intel_remapped_plane_info plane[2];
} __packed;
struct intel_partial_info {
u64 offset;
unsigned int size;
} __packed;
struct intel_remapped_info {
struct intel_remapped_plane_info plane[4];
/* in gtt pages */
u32 plane_alignment;
} __packed;
enum i915_gtt_view_type {
I915_GTT_VIEW_NORMAL = 0,
I915_GTT_VIEW_ROTATED = sizeof(struct intel_rotation_info),
I915_GTT_VIEW_PARTIAL = sizeof(struct intel_partial_info),
I915_GTT_VIEW_REMAPPED = sizeof(struct intel_remapped_info),
};
struct i915_gtt_view {
enum i915_gtt_view_type type;
union {
/* Members need to contain no holes/padding */
struct intel_partial_info partial;
struct intel_rotation_info rotated;
struct intel_remapped_info remapped;
};
};
static inline bool i915_gtt_view_is_normal(const struct i915_gtt_view *view)
{
return view->type == I915_GTT_VIEW_NORMAL;
}
static inline bool i915_gtt_view_is_remapped(const struct i915_gtt_view *view)
{
return view->type == I915_GTT_VIEW_REMAPPED;
}
static inline bool i915_gtt_view_is_rotated(const struct i915_gtt_view *view)
{
return view->type == I915_GTT_VIEW_ROTATED;
}
#endif /* __I915_GTT_VIEW_TYPES_H__ */

View File

@ -354,14 +354,11 @@ static struct i915_vma *i915_overlay_pin_fb(struct drm_device *drm,
struct drm_gem_object *obj,
u32 *offset)
{
struct drm_i915_private *i915 = to_i915(drm);
struct drm_i915_gem_object *new_bo = to_intel_bo(obj);
struct i915_gem_ww_ctx ww;
struct i915_vma *vma;
int ret;
atomic_inc(&i915->pending_fb_pin);
i915_gem_ww_ctx_init(&ww, true);
retry:
ret = i915_gem_object_lock(new_bo, &ww);
@ -377,8 +374,6 @@ static struct i915_vma *i915_overlay_pin_fb(struct drm_device *drm,
}
i915_gem_ww_ctx_fini(&ww);
atomic_dec(&i915->pending_fb_pin);
if (ret)
return ERR_PTR(ret);

View File

@ -610,7 +610,6 @@ bool __i915_request_submit(struct i915_request *request)
RQ_TRACE(request, "\n");
GEM_BUG_ON(!irqs_disabled());
lockdep_assert_held(&engine->sched_engine->lock);
/*
@ -719,7 +718,6 @@ void __i915_request_unsubmit(struct i915_request *request)
*/
RQ_TRACE(request, "\n");
GEM_BUG_ON(!irqs_disabled());
lockdep_assert_held(&engine->sched_engine->lock);
/*

View File

@ -147,7 +147,7 @@ static void __i915_vma_retire(struct i915_active *ref)
static struct i915_vma *
vma_create(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
const struct i915_gtt_view *view)
const struct intel_gtt_view *view)
{
struct i915_vma *pos = ERR_PTR(-E2BIG);
struct i915_vma *vma;
@ -179,9 +179,9 @@ vma_create(struct drm_i915_gem_object *obj,
INIT_LIST_HEAD(&vma->obj_link);
RB_CLEAR_NODE(&vma->obj_node);
if (view && view->type != I915_GTT_VIEW_NORMAL) {
if (view && !intel_gtt_view_is_normal(view)) {
vma->gtt_view = *view;
if (view->type == I915_GTT_VIEW_PARTIAL) {
if (intel_gtt_view_is_partial(view)) {
GEM_BUG_ON(range_overflows_t(u64,
view->partial.offset,
view->partial.size,
@ -189,10 +189,10 @@ vma_create(struct drm_i915_gem_object *obj,
vma->size = view->partial.size;
vma->size <<= PAGE_SHIFT;
GEM_BUG_ON(vma->size > obj->base.size);
} else if (view->type == I915_GTT_VIEW_ROTATED) {
} else if (intel_gtt_view_is_rotated(view)) {
vma->size = intel_rotation_info_size(&view->rotated);
vma->size <<= PAGE_SHIFT;
} else if (view->type == I915_GTT_VIEW_REMAPPED) {
} else if (intel_gtt_view_is_remapped(view)) {
vma->size = intel_remapped_info_size(&view->remapped);
vma->size <<= PAGE_SHIFT;
}
@ -286,7 +286,7 @@ vma_create(struct drm_i915_gem_object *obj,
static struct i915_vma *
i915_vma_lookup(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
const struct i915_gtt_view *view)
const struct intel_gtt_view *view)
{
struct rb_node *rb;
@ -324,7 +324,7 @@ i915_vma_lookup(struct drm_i915_gem_object *obj,
struct i915_vma *
i915_vma_instance(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
const struct i915_gtt_view *view)
const struct intel_gtt_view *view)
{
struct i915_vma *vma;
@ -1267,7 +1267,7 @@ intel_remap_pages(struct intel_remapped_info *rem_info,
}
static noinline struct sg_table *
intel_partial_pages(const struct i915_gtt_view *view,
intel_partial_pages(const struct intel_gtt_view *view,
struct drm_i915_gem_object *obj)
{
struct sg_table *st;
@ -1311,27 +1311,15 @@ __i915_vma_get_pages(struct i915_vma *vma)
*/
GEM_BUG_ON(!i915_gem_object_has_pinned_pages(vma->obj));
switch (vma->gtt_view.type) {
default:
GEM_BUG_ON(vma->gtt_view.type);
fallthrough;
case I915_GTT_VIEW_NORMAL:
pages = vma->obj->mm.pages;
break;
case I915_GTT_VIEW_ROTATED:
pages =
intel_rotate_pages(&vma->gtt_view.rotated, vma->obj);
break;
case I915_GTT_VIEW_REMAPPED:
pages =
intel_remap_pages(&vma->gtt_view.remapped, vma->obj);
break;
case I915_GTT_VIEW_PARTIAL:
if (intel_gtt_view_is_rotated(&vma->gtt_view)) {
pages = intel_rotate_pages(&vma->gtt_view.rotated, vma->obj);
} else if (intel_gtt_view_is_remapped(&vma->gtt_view)) {
pages = intel_remap_pages(&vma->gtt_view.remapped, vma->obj);
} else if (intel_gtt_view_is_partial(&vma->gtt_view)) {
pages = intel_partial_pages(&vma->gtt_view, vma->obj);
break;
} else {
GEM_BUG_ON(!intel_gtt_view_is_normal(&vma->gtt_view));
pages = vma->obj->mm.pages;
}
if (IS_ERR(pages)) {

View File

@ -43,7 +43,7 @@
struct i915_vma *
i915_vma_instance(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
const struct i915_gtt_view *view);
const struct intel_gtt_view *view);
void i915_vma_unpin_and_release(struct i915_vma **p_vma, unsigned int flags);
#define I915_VMA_RELEASE_MAP BIT(0)
@ -207,7 +207,7 @@ static inline void i915_vma_put(struct i915_vma *vma)
static inline long
i915_vma_compare(struct i915_vma *vma,
struct i915_address_space *vm,
const struct i915_gtt_view *view)
const struct intel_gtt_view *view)
{
ptrdiff_t cmp;
@ -217,7 +217,7 @@ i915_vma_compare(struct i915_vma *vma,
if (cmp)
return cmp;
BUILD_BUG_ON(I915_GTT_VIEW_NORMAL != 0);
BUILD_BUG_ON(INTEL_GTT_VIEW_NORMAL != 0);
cmp = vma->gtt_view.type;
if (!view)
return cmp;
@ -238,9 +238,9 @@ i915_vma_compare(struct i915_vma *vma,
* we assert above that all branches have the same address, and that
* each branch has a unique type/size.
*/
BUILD_BUG_ON(I915_GTT_VIEW_NORMAL >= I915_GTT_VIEW_PARTIAL);
BUILD_BUG_ON(I915_GTT_VIEW_PARTIAL >= I915_GTT_VIEW_ROTATED);
BUILD_BUG_ON(I915_GTT_VIEW_ROTATED >= I915_GTT_VIEW_REMAPPED);
BUILD_BUG_ON(INTEL_GTT_VIEW_NORMAL >= INTEL_GTT_VIEW_PARTIAL);
BUILD_BUG_ON(INTEL_GTT_VIEW_PARTIAL >= INTEL_GTT_VIEW_ROTATED);
BUILD_BUG_ON(INTEL_GTT_VIEW_ROTATED >= INTEL_GTT_VIEW_REMAPPED);
BUILD_BUG_ON(offsetof(typeof(*view), rotated) !=
offsetof(typeof(*view), partial));
BUILD_BUG_ON(offsetof(typeof(*view), rotated) !=

View File

@ -29,11 +29,10 @@
#include <linux/rbtree.h>
#include <drm/drm_mm.h>
#include <drm/intel/gtt_view_types.h>
#include "gem/i915_gem_object_types.h"
#include "i915_gtt_view_types.h"
/**
* DOC: Global GTT views
*
@ -67,22 +66,22 @@
* Implementation and usage
*
* GGTT views are implemented using VMAs and are distinguished via enum
* i915_gtt_view_type and struct i915_gtt_view.
* intel_gtt_view_type and struct intel_gtt_view.
*
* A new flavour of core GEM functions which work with GGTT bound objects were
* added with the _ggtt_ infix, and sometimes with _view postfix to avoid
* renaming in large amounts of code. They take the struct i915_gtt_view
* renaming in large amounts of code. They take the struct intel_gtt_view
* parameter encapsulating all metadata required to implement a view.
*
* As a helper for callers which are only interested in the normal view,
* globally const i915_gtt_view_normal singleton instance exists. All old core
* globally const intel_gtt_view_normal singleton instance exists. All old core
* GEM API functions, the ones not taking the view parameter, are operating on,
* or with the normal GGTT view.
*
* Code wanting to add or use a new GGTT view needs to:
*
* 1. Add a new enum with a suitable name.
* 2. Extend the metadata in the i915_gtt_view structure if required.
* 2. Extend the metadata in the intel_gtt_view structure if required.
* 3. Add support to i915_get_vma_pages().
*
* New views are required to build a scatter-gather table from within the
@ -90,7 +89,7 @@
* exists for the lifetime of an VMA.
*
* Core API is designed to have copy semantics which means that passed in
* struct i915_gtt_view does not need to be persistent (left around after
* struct intel_gtt_view does not need to be persistent (left around after
* calling the core API functions).
*
*/
@ -112,11 +111,11 @@ static inline void assert_i915_gem_gtt_types(void)
/* As we encode the size of each branch inside the union into its type,
* we have to be careful that each branch has a unique size.
*/
switch ((enum i915_gtt_view_type)0) {
case I915_GTT_VIEW_NORMAL:
case I915_GTT_VIEW_PARTIAL:
case I915_GTT_VIEW_ROTATED:
case I915_GTT_VIEW_REMAPPED:
switch ((enum intel_gtt_view_type)0) {
case INTEL_GTT_VIEW_NORMAL:
case INTEL_GTT_VIEW_PARTIAL:
case INTEL_GTT_VIEW_ROTATED:
case INTEL_GTT_VIEW_REMAPPED:
/* gcc complains if these are identical cases */
break;
}
@ -231,11 +230,11 @@ struct i915_vma {
/**
* Support different GGTT views into the same object.
* This means there can be multiple VMA mappings per object and per VM.
* i915_gtt_view_type is used to distinguish between those entries.
* The default one of zero (I915_GTT_VIEW_NORMAL) is default and also
* intel_gtt_view_type is used to distinguish between those entries.
* The default one of zero (INTEL_GTT_VIEW_NORMAL) is default and also
* assumed in GEM functions which take no ggtt view parameter.
*/
struct i915_gtt_view gtt_view;
struct intel_gtt_view gtt_view;
/** This object's place on the active/inactive lists */
struct list_head vm_link;

View File

@ -51,7 +51,7 @@ static bool assert_vma(struct i915_vma *vma,
ok = false;
}
if (vma->gtt_view.type != I915_GTT_VIEW_NORMAL) {
if (!intel_gtt_view_is_normal(&vma->gtt_view)) {
pr_err("VMA created with wrong type [%d]\n",
vma->gtt_view.type);
ok = false;
@ -63,7 +63,7 @@ static bool assert_vma(struct i915_vma *vma,
static struct i915_vma *
checked_vma_instance(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
const struct i915_gtt_view *view)
const struct intel_gtt_view *view)
{
struct i915_vma *vma;
bool ok = true;
@ -533,12 +533,12 @@ assert_remapped(struct drm_i915_gem_object *obj,
return sg;
}
static unsigned int remapped_size(enum i915_gtt_view_type view_type,
static unsigned int remapped_size(const struct intel_gtt_view *view,
const struct intel_remapped_plane_info *a,
const struct intel_remapped_plane_info *b)
{
if (view_type == I915_GTT_VIEW_ROTATED)
if (intel_gtt_view_is_rotated(view))
return a->dst_stride * a->width + b->dst_stride * b->width;
else
return a->dst_stride * a->height + b->dst_stride * b->height;
@ -572,9 +572,9 @@ static int igt_vma_rotate_remap(void *arg)
{ }
}, *a, *b;
enum i915_gtt_view_type types[] = {
I915_GTT_VIEW_ROTATED,
I915_GTT_VIEW_REMAPPED,
enum intel_gtt_view_type types[] = {
INTEL_GTT_VIEW_ROTATED,
INTEL_GTT_VIEW_REMAPPED,
0,
}, *t;
const unsigned int max_pages = 64;
@ -592,7 +592,7 @@ static int igt_vma_rotate_remap(void *arg)
for (t = types; *t; t++) {
for (a = planes; a->width; a++) {
for (b = planes + ARRAY_SIZE(planes); b-- != planes; ) {
struct i915_gtt_view view = {
struct intel_gtt_view view = {
.type = *t,
.remapped.plane[0] = *a,
.remapped.plane[1] = *b,
@ -606,11 +606,11 @@ static int igt_vma_rotate_remap(void *arg)
max_offset = max_pages - max_offset;
if (!plane_info[0].dst_stride)
plane_info[0].dst_stride = view.type == I915_GTT_VIEW_ROTATED ?
plane_info[0].dst_stride = intel_gtt_view_is_rotated(&view) ?
plane_info[0].height :
plane_info[0].width;
if (!plane_info[1].dst_stride)
plane_info[1].dst_stride = view.type == I915_GTT_VIEW_ROTATED ?
plane_info[1].dst_stride = intel_gtt_view_is_rotated(&view) ?
plane_info[1].height :
plane_info[1].width;
@ -632,9 +632,9 @@ static int igt_vma_rotate_remap(void *arg)
goto out_object;
}
expected_pages = remapped_size(view.type, &plane_info[0], &plane_info[1]);
expected_pages = remapped_size(&view, &plane_info[0], &plane_info[1]);
if (view.type == I915_GTT_VIEW_ROTATED &&
if (intel_gtt_view_is_rotated(&view) &&
vma->size != expected_pages * PAGE_SIZE) {
pr_err("VMA is wrong size, expected %lu, found %llu\n",
PAGE_SIZE * expected_pages, vma->size);
@ -642,7 +642,7 @@ static int igt_vma_rotate_remap(void *arg)
goto out_object;
}
if (view.type == I915_GTT_VIEW_REMAPPED &&
if (intel_gtt_view_is_remapped(&view) &&
vma->size > expected_pages * PAGE_SIZE) {
pr_err("VMA is wrong size, expected %lu, found %llu\n",
PAGE_SIZE * expected_pages, vma->size);
@ -672,13 +672,13 @@ static int igt_vma_rotate_remap(void *arg)
sg = vma->pages->sgl;
for (n = 0; n < ARRAY_SIZE(view.rotated.plane); n++) {
if (view.type == I915_GTT_VIEW_ROTATED)
if (intel_gtt_view_is_rotated(&view))
sg = assert_rotated(obj, &view.rotated, n, sg);
else
sg = assert_remapped(obj, &view.remapped, n, sg);
if (IS_ERR(sg)) {
pr_err("Inconsistent %s VMA pages for plane %d: [(%d, %d, %d, %d, %d), (%d, %d, %d, %d, %d)]\n",
view.type == I915_GTT_VIEW_ROTATED ?
intel_gtt_view_is_rotated(&view) ?
"rotated" : "remapped", n,
plane_info[0].width,
plane_info[0].height,
@ -745,7 +745,7 @@ static bool assert_partial(struct drm_i915_gem_object *obj,
}
static bool assert_pin(struct i915_vma *vma,
struct i915_gtt_view *view,
struct intel_gtt_view *view,
u64 size,
const char *name)
{
@ -763,7 +763,7 @@ static bool assert_pin(struct i915_vma *vma,
ok = false;
}
if (view && view->type != I915_GTT_VIEW_NORMAL) {
if (view && !intel_gtt_view_is_normal(view)) {
if (memcmp(&vma->gtt_view, view, sizeof(*view))) {
pr_err("(%s) VMA mismatch upon creation!\n",
name);
@ -776,7 +776,7 @@ static bool assert_pin(struct i915_vma *vma,
ok = false;
}
} else {
if (vma->gtt_view.type != I915_GTT_VIEW_NORMAL) {
if (!intel_gtt_view_is_normal(&vma->gtt_view)) {
pr_err("Not the normal ggtt view! Found %d\n",
vma->gtt_view.type);
ok = false;
@ -823,14 +823,14 @@ static int igt_vma_partial(void *arg)
nvma = 0;
for_each_prime_number_from(sz, 1, npages) {
for_each_prime_number_from(offset, 0, npages - sz) {
struct i915_gtt_view view;
struct intel_gtt_view view;
view.type = I915_GTT_VIEW_PARTIAL;
view.type = INTEL_GTT_VIEW_PARTIAL;
view.partial.offset = offset;
view.partial.size = sz;
if (sz == npages)
view.type = I915_GTT_VIEW_NORMAL;
view.type = INTEL_GTT_VIEW_NORMAL;
vma = checked_vma_instance(obj, vm, &view);
if (IS_ERR(vma)) {
@ -981,9 +981,9 @@ static int igt_vma_remapped_gtt(void *arg)
{ }
}, *p;
enum i915_gtt_view_type types[] = {
I915_GTT_VIEW_ROTATED,
I915_GTT_VIEW_REMAPPED,
enum intel_gtt_view_type types[] = {
INTEL_GTT_VIEW_ROTATED,
INTEL_GTT_VIEW_REMAPPED,
0,
}, *t;
struct drm_i915_gem_object *obj;
@ -1001,7 +1001,7 @@ static int igt_vma_remapped_gtt(void *arg)
for (t = types; *t; t++) {
for (p = planes; p->width; p++) {
struct i915_gtt_view view = {
struct intel_gtt_view view = {
.type = *t,
.rotated.plane[0] = *p,
};
@ -1017,7 +1017,7 @@ static int igt_vma_remapped_gtt(void *arg)
goto out;
if (!plane_info[0].dst_stride)
plane_info[0].dst_stride = *t == I915_GTT_VIEW_ROTATED ?
plane_info[0].dst_stride = intel_gtt_view_is_rotated(&view) ?
p->height : p->width;
vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, PIN_MAPPABLE);
@ -1040,7 +1040,7 @@ static int igt_vma_remapped_gtt(void *arg)
unsigned int offset;
u32 val = y << 16 | x;
if (*t == I915_GTT_VIEW_ROTATED)
if (intel_gtt_view_is_rotated(&view))
offset = (x * plane_info[0].dst_stride + y) * PAGE_SIZE;
else
offset = (y * plane_info[0].dst_stride + x) * PAGE_SIZE;
@ -1057,7 +1057,7 @@ static int igt_vma_remapped_gtt(void *arg)
goto out;
}
GEM_BUG_ON(vma->gtt_view.type != I915_GTT_VIEW_NORMAL);
GEM_BUG_ON(!intel_gtt_view_is_normal(&vma->gtt_view));
map = i915_vma_pin_iomap(vma);
i915_vma_unpin(vma);
@ -1072,7 +1072,7 @@ static int igt_vma_remapped_gtt(void *arg)
u32 exp = y << 16 | x;
u32 val;
if (*t == I915_GTT_VIEW_ROTATED)
if (intel_gtt_view_is_rotated(&view))
src_idx = rotated_index(&view.rotated, 0, x, y);
else
src_idx = remapped_index(&view.remapped, 0, x, y);
@ -1081,7 +1081,7 @@ static int igt_vma_remapped_gtt(void *arg)
val = ioread32(&map[offset / sizeof(*map)]);
if (val != exp) {
pr_err("%s VMA write test failed, expected 0x%x, found 0x%x\n",
*t == I915_GTT_VIEW_ROTATED ? "Rotated" : "Remapped",
intel_gtt_view_is_rotated(&view) ? "Rotated" : "Remapped",
exp, val);
i915_vma_unpin_iomap(vma);
err = -EINVAL;

View File

@ -39,7 +39,14 @@ static void __hardirq_end(void)
local_irq_enable();
}
static void __maybe_unused __nop(void)
{}
const struct igt_atomic_section igt_atomic_phases[] = {
#if IS_ENABLED(CONFIG_PREEMPT_RT)
{ "sleeping", __nop, __nop },
{ },
#endif
{ "preempt", __preempt_begin, __preempt_end },
{ "softirq", __softirq_begin, __softirq_end },
{ "hardirq", __hardirq_begin, __hardirq_end },

View File

@ -3,6 +3,8 @@
* Copyright © 2013-2021 Intel Corporation
*/
#include <linux/string_choices.h>
#include <drm/drm_print.h>
#include <drm/intel/display_parent_interface.h>
@ -101,7 +103,7 @@ static int vlv_sideband_rw(struct drm_i915_private *i915,
VLV_IOSF_DOORBELL_REQ, IOSF_SB_BUSY, 0,
5)) {
drm_dbg(&i915->drm, "IOSF sideband idle wait (%s) timed out\n",
is_read ? "read" : "write");
str_read_write(is_read));
return -EAGAIN;
}
@ -125,7 +127,7 @@ static int vlv_sideband_rw(struct drm_i915_private *i915,
err = 0;
} else {
drm_dbg(&i915->drm, "IOSF sideband finish wait (%s) timed out\n",
is_read ? "read" : "write");
str_read_write(is_read));
err = -ETIMEDOUT;
}

View File

@ -260,6 +260,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
i915-display/intel_ddi.o \
i915-display/intel_ddi_buf_trans.o \
i915-display/intel_de.o \
i915-display/intel_dip.o \
i915-display/intel_display.o \
i915-display/intel_display_conversion.o \
i915-display/intel_display_device.o \

View File

@ -1,16 +0,0 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef __I915_CONFIG_H__
#define __I915_CONFIG_H__
#include <linux/sched.h>
static inline unsigned long i915_fence_timeout(void)
{
return MAX_SCHEDULE_TIMEOUT;
}
#endif /* __I915_CONFIG_H__ */

View File

@ -1,7 +0,0 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2025 Intel Corporation */
#include "../../i915/i915_gtt_view_types.h"
/* Partial view not supported in xe, fail build if used. */
#define I915_GTT_VIEW_PARTIAL

View File

@ -6,31 +6,23 @@
#include "xe_display.h"
#include "regs/xe_irq_regs.h"
#include <linux/fb.h>
#include <linux/acpi.h>
#include <drm/drm_client.h>
#include <drm/drm_client_event.h>
#include <drm/drm_drv.h>
#include <drm/drm_managed.h>
#include <drm/drm_probe_helper.h>
#include <drm/intel/display_member.h>
#include <drm/intel/display_parent_interface.h>
#include <uapi/drm/xe_drm.h>
#include "intel_acpi.h"
#include "intel_display.h"
#include "intel_display_core.h"
#include "intel_display_device.h"
#include "intel_display_driver.h"
#include "intel_display_irq.h"
#include "intel_display_types.h"
#include "intel_dmc.h"
#include "intel_dmc_wl.h"
#include "intel_dp.h"
#include "intel_fbdev.h"
#include "intel_hotplug.h"
#include "intel_opregion.h"
#include "skl_watermark.h"
#include "xe_device.h"
#include "xe_display_bo.h"
#include "xe_display_pcode.h"

View File

@ -45,6 +45,11 @@ static bool xe_display_rpm_suspended(const struct drm_device *drm)
return pm_runtime_suspended(xe->drm.dev);
}
static bool xe_display_rpm_pme_enabled(const struct drm_device *drm)
{
return xe_pm_pme_enabled(to_xe_device(drm));
}
static void xe_display_rpm_assert_held(const struct drm_device *drm)
{
/* FIXME */
@ -69,6 +74,7 @@ const struct intel_display_rpm_interface xe_display_rpm_interface = {
.put_raw = xe_display_rpm_put,
.put_unchecked = xe_display_rpm_put_unchecked,
.suspended = xe_display_rpm_suspended,
.pme_enabled = xe_display_rpm_pme_enabled,
.assert_held = xe_display_rpm_assert_held,
.assert_block = xe_display_rpm_assert_block,
.assert_unblock = xe_display_rpm_assert_unblock

View File

@ -4,11 +4,9 @@
*/
#include <drm/intel/display_parent_interface.h>
#include <drm/intel/gtt_view_types.h>
#include <drm/ttm/ttm_bo.h>
/* FIXME move the types to parent interface? */
#include "i915_gtt_view_types.h"
/* FIXME move intel_remapped_info_size() & co. to parent interface? */
#include "intel_fb.h"
@ -150,13 +148,13 @@ static int __xe_pin_fb_vma_dpt(struct drm_gem_object *obj,
struct xe_device *xe = to_xe_device(obj->dev);
struct xe_tile *tile0 = xe_device_get_root_tile(xe);
struct xe_ggtt *ggtt = tile0->mem.ggtt;
const struct i915_gtt_view *view = pin_params->view;
const struct intel_gtt_view *view = pin_params->view;
struct xe_bo *bo = gem_to_xe_bo(obj), *dpt;
u32 dpt_size, size = bo->ttm.base.size;
if (view->type == I915_GTT_VIEW_NORMAL)
if (intel_gtt_view_is_normal(view))
dpt_size = ALIGN(size / XE_PAGE_SIZE * 8, XE_PAGE_SIZE);
else if (view->type == I915_GTT_VIEW_REMAPPED)
else if (intel_gtt_view_is_remapped(view))
dpt_size = ALIGN(intel_remapped_info_size(&view->remapped) * 8,
XE_PAGE_SIZE);
else
@ -175,7 +173,7 @@ static int __xe_pin_fb_vma_dpt(struct drm_gem_object *obj,
if (IS_ERR(dpt))
return PTR_ERR(dpt);
if (view->type == I915_GTT_VIEW_NORMAL) {
if (intel_gtt_view_is_normal(view)) {
u64 pte = xe_ggtt_encode_pte_flags(ggtt, bo, xe_cache_pat_idx(xe, XE_CACHE_NONE));
u32 x;
@ -184,7 +182,7 @@ static int __xe_pin_fb_vma_dpt(struct drm_gem_object *obj,
iosys_map_wr(&dpt->vmap, x * 8, u64, pte | addr);
}
} else if (view->type == I915_GTT_VIEW_REMAPPED) {
} else if (intel_gtt_view_is_remapped(view)) {
write_dpt_remapped(bo, &view->remapped, &dpt->vmap);
} else {
const struct intel_rotation_info *rot_info = &view->rotated;
@ -233,7 +231,7 @@ write_ggtt_rotated(struct xe_ggtt *ggtt, u32 *ggtt_ofs,
}
struct fb_rotate_args {
const struct i915_gtt_view *view;
const struct intel_gtt_view *view;
struct xe_bo *bo;
};
@ -258,7 +256,7 @@ static int __xe_pin_fb_vma_ggtt(struct drm_gem_object *obj,
const struct intel_fb_pin_params *pin_params,
struct i915_vma *vma)
{
const struct i915_gtt_view *view = pin_params->view;
const struct intel_gtt_view *view = pin_params->view;
struct xe_bo *bo = gem_to_xe_bo(obj);
struct xe_device *xe = to_xe_device(obj->dev);
struct xe_tile *tile0 = xe_device_get_root_tile(xe);
@ -277,7 +275,7 @@ static int __xe_pin_fb_vma_ggtt(struct drm_gem_object *obj,
align = max(align, SZ_64K);
/* Fast case, preallocated GGTT view? */
if (bo->ggtt_node[tile0->id] && view->type == I915_GTT_VIEW_NORMAL) {
if (bo->ggtt_node[tile0->id] && intel_gtt_view_is_normal(view)) {
vma->node = bo->ggtt_node[tile0->id];
return 0;
}
@ -285,7 +283,7 @@ static int __xe_pin_fb_vma_ggtt(struct drm_gem_object *obj,
/* TODO: Consider sharing framebuffer mapping?
* embed i915_vma inside intel_framebuffer
*/
if (view->type == I915_GTT_VIEW_NORMAL)
if (intel_gtt_view_is_normal(view))
size = xe_bo_size(bo);
else
/* display uses tiles instead of bytes here, so convert it back.. */
@ -294,7 +292,7 @@ static int __xe_pin_fb_vma_ggtt(struct drm_gem_object *obj,
pte = xe_ggtt_encode_pte_flags(ggtt, bo, xe_cache_pat_idx(xe, XE_CACHE_NONE));
vma->node = xe_ggtt_insert_node_transform(ggtt, bo, pte,
ALIGN(size, align), align,
view->type == I915_GTT_VIEW_NORMAL ?
intel_gtt_view_is_normal(view) ?
NULL : write_ggtt_rotated_node,
&(struct fb_rotate_args){view, bo});
if (IS_ERR(vma->node))
@ -459,9 +457,9 @@ static void xe_fb_pin_dpt_unpin(struct intel_dpt *dpt,
static struct i915_vma *
xe_fb_pin_reuse_vma(struct i915_vma *old_ggtt_vma,
struct drm_gem_object *old_obj,
const struct i915_gtt_view *old_view,
const struct intel_gtt_view *old_view,
struct drm_gem_object *new_obj,
const struct i915_gtt_view *new_view,
const struct intel_gtt_view *new_view,
u32 *out_offset)
{
if (old_ggtt_vma && old_obj == new_obj &&

View File

@ -466,6 +466,19 @@ struct xe_device {
struct mutex lock;
} d3cold;
/** @pme: Encapsulate pme related stuff */
struct {
/** @pme.capable: Indicates if device is PME capable */
bool capable;
/** @pme.enabled:
*
* Indicates if PME is enabled - depends on user controllable
* sysfs interface as well
*/
bool enabled;
} pme;
/** @pm_notifier: Our PM notifier to perform actions in response to various PM events. */
struct notifier_block pm_notifier;
/** @pm_block: Completion to block validating tasks on suspend / hibernate prepare */

View File

@ -1384,6 +1384,8 @@ static int xe_pci_runtime_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct xe_device *xe = pdev_to_xe_device(pdev);
unsigned int flags;
bool pme_enabled;
int err, ret;
/*
@ -1395,9 +1397,25 @@ static int xe_pci_runtime_suspend(struct device *dev)
xe_assert(xe, !IS_SRIOV_VF(xe));
xe_assert(xe, !pci_num_vf(pdev));
flags = memalloc_noreclaim_save();
pme_enabled = xe->pme.capable && !xe->d3cold.allowed &&
pci_enable_wake(pdev, PCI_D3hot, true) == 0;
memalloc_noreclaim_restore(flags);
xe_pm_update_pme_enabled(xe, pme_enabled);
err = xe_pm_runtime_suspend(xe);
if (err)
if (err) {
if (pme_enabled) {
flags = memalloc_noreclaim_save();
pci_enable_wake(pdev, PCI_D3hot, false);
memalloc_noreclaim_restore(flags);
xe_pm_update_pme_enabled(xe, false);
}
return err;
}
err = xe_pm_wait_all_c6(xe);
if (err) {
@ -1437,6 +1455,8 @@ static int xe_pci_runtime_resume(struct device *dev)
pci_restore_state(pdev);
xe_pm_update_pme_enabled(xe, false);
if (xe->d3cold.allowed) {
err = pci_enable_device(pdev);
if (err)

View File

@ -78,6 +78,8 @@
* management (RPS).
*/
#define HAS_PM_PME_SUPPORT(xe) (GRAPHICS_VERx100(xe) >= 3500)
#ifdef CONFIG_LOCKDEP
static struct lockdep_map xe_pm_runtime_d3cold_map = {
.name = "xe_rpm_d3cold_map"
@ -384,6 +386,14 @@ int xe_pm_init_early(struct xe_device *xe)
}
ALLOW_ERROR_INJECTION(xe_pm_init_early, ERRNO); /* See xe_pci_probe() */
static bool xe_pm_pci_pme_capable(struct xe_device *xe)
{
struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
return HAS_PM_PME_SUPPORT(xe) ?
pci_pme_capable(pdev, PCI_D3hot) : false;
}
/**
* xe_pm_probe() - Initialize Xe Power Management
* @xe: the &xe_device instance
@ -397,6 +407,16 @@ int xe_pm_probe(struct xe_device *xe)
xe->d3cold.capable = xe_pm_pci_d3cold_capable(xe);
xe_dbg(xe, "d3cold: capable=%s\n", str_yes_no(xe->d3cold.capable));
xe->pme.capable = xe_pm_pci_pme_capable(xe);
xe_dbg(xe, "pme: capable=%s\n", str_yes_no(xe->pme.capable));
if (xe->pme.capable) {
int err = devm_device_init_wakeup(xe->drm.dev);
if (err)
return err;
}
return 0;
}
@ -650,6 +670,7 @@ int xe_pm_runtime_suspend(struct xe_device *xe)
return 0;
out_resume:
xe_pm_update_pme_enabled(xe, false);
xe_display_pm_runtime_resume(xe);
xe_pxp_pm_resume(xe->pxp);
out:
@ -993,6 +1014,30 @@ int xe_pm_set_vram_threshold(struct xe_device *xe, u32 threshold)
return 0;
}
/**
* xe_pm_pme_enabled - get the current status of PME enabled
* @xe: xe device instance
*
* Returns: True if PME is enabled, false otherwise.
*/
bool xe_pm_pme_enabled(struct xe_device *xe)
{
return xe->pme.enabled;
}
/**
* xe_pm_update_pme_enabled - Update the PME enabled state
* @xe: xe device instance
* @status: New PME enabled status
*
* Called during runtime suspend / resume. Status is set to True if PME is
* enabled during runtime_suspend. Cleared on runtime_resume.
*/
void xe_pm_update_pme_enabled(struct xe_device *xe, bool status)
{
xe->pme.enabled = status;
}
/**
* xe_pm_d3cold_allowed_toggle - Check conditions to toggle d3cold.allowed
* @xe: xe device instance

View File

@ -33,6 +33,8 @@ bool xe_pm_runtime_resume_and_get(struct xe_device *xe);
void xe_pm_assert_unbounded_bridge(struct xe_device *xe);
int xe_pm_set_vram_threshold(struct xe_device *xe, u32 threshold);
void xe_pm_d3cold_allowed_toggle(struct xe_device *xe);
bool xe_pm_pme_enabled(struct xe_device *xe);
void xe_pm_update_pme_enabled(struct xe_device *xe, bool status);
bool xe_rpm_reclaim_safe(const struct xe_device *xe);
struct task_struct *xe_pm_read_callback_task(struct xe_device *xe);
int xe_pm_block_on_suspend(struct xe_device *xe);

View File

@ -16,11 +16,11 @@ struct drm_mode_fb_cmd2;
struct drm_plane_state;
struct drm_scanout_buffer;
struct fb_info;
struct i915_gtt_view;
struct i915_vma;
struct intel_dpt;
struct intel_dsb_buffer;
struct intel_frontbuffer;
struct intel_gtt_view;
struct intel_hdcp_gsc_context;
struct intel_initial_plane_config;
struct intel_panic;
@ -31,7 +31,7 @@ struct seq_file;
struct vm_area_struct;
struct intel_fb_pin_params {
const struct i915_gtt_view *view;
const struct intel_gtt_view *view;
unsigned int alignment;
unsigned int phys_alignment;
unsigned int vtd_guard;
@ -101,9 +101,9 @@ struct intel_display_fb_pin_interface {
struct i915_vma *ggtt_vma);
struct i915_vma *(*reuse_vma)(struct i915_vma *old_ggtt_vma,
struct drm_gem_object *old_obj,
const struct i915_gtt_view *old_view,
const struct intel_gtt_view *old_view,
struct drm_gem_object *new_obj,
const struct i915_gtt_view *new_view,
const struct intel_gtt_view *new_view,
u32 *out_offset);
void (*get_map)(struct i915_vma *vma, struct iosys_map *map);
};
@ -196,6 +196,7 @@ struct intel_display_rpm_interface {
void (*put_unchecked)(const struct drm_device *drm);
bool (*suspended)(const struct drm_device *drm);
bool (*pme_enabled)(const struct drm_device *drm); /* Optional */
void (*assert_held)(const struct drm_device *drm);
void (*assert_block)(const struct drm_device *drm);
void (*assert_unblock)(const struct drm_device *drm);

View File

@ -0,0 +1,79 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2025 Intel Corporation */
#ifndef __DRM_INTEL_GTT_VIEW_TYPES_H__
#define __DRM_INTEL_GTT_VIEW_TYPES_H__
#include <linux/types.h>
struct intel_remapped_plane_info {
/* in gtt pages */
u32 offset:31;
u32 linear:1;
union {
/* in gtt pages for !linear */
struct {
u16 width;
u16 height;
u16 src_stride;
u16 dst_stride;
};
/* in gtt pages for linear */
u32 size;
};
} __packed;
struct intel_rotation_info {
struct intel_remapped_plane_info plane[2];
} __packed;
struct intel_partial_info {
u64 offset;
unsigned int size;
} __packed;
struct intel_remapped_info {
struct intel_remapped_plane_info plane[4];
/* in gtt pages */
u32 plane_alignment;
} __packed;
enum intel_gtt_view_type {
INTEL_GTT_VIEW_NORMAL = 0,
INTEL_GTT_VIEW_ROTATED = sizeof(struct intel_rotation_info),
INTEL_GTT_VIEW_PARTIAL = sizeof(struct intel_partial_info),
INTEL_GTT_VIEW_REMAPPED = sizeof(struct intel_remapped_info),
};
struct intel_gtt_view {
enum intel_gtt_view_type type;
union {
/* Members need to contain no holes/padding */
struct intel_partial_info partial;
struct intel_rotation_info rotated;
struct intel_remapped_info remapped;
};
};
static inline bool intel_gtt_view_is_normal(const struct intel_gtt_view *view)
{
return view->type == INTEL_GTT_VIEW_NORMAL;
}
static inline bool intel_gtt_view_is_remapped(const struct intel_gtt_view *view)
{
return view->type == INTEL_GTT_VIEW_REMAPPED;
}
static inline bool intel_gtt_view_is_rotated(const struct intel_gtt_view *view)
{
return view->type == INTEL_GTT_VIEW_ROTATED;
}
static inline bool intel_gtt_view_is_partial(const struct intel_gtt_view *view)
{
return view->type == INTEL_GTT_VIEW_PARTIAL;
}
#endif /* __DRM_INTEL_GTT_VIEW_TYPES_H__ */