Commit bfed5b02 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'drm-intel-next-2024-04-24' of...

Merge tag 'drm-intel-next-2024-04-24' of https://anongit.freedesktop.org/git/drm/drm-intel

 into drm-next

Core Changes:
- Some DP/DP_MST DRM helpers (Imre)

Driver Changes (i915 Display):
- PLL refactoring (Ville)
- Limit eDP MSO pipe only for display version 20 (Luca)
- More display refactor towards independence from i915 dev_priv (Jani)
- QGV/SAGV related refactor (Stanislav)
- Few MTL/DSC and a UHBR monitor fix (Imre)
- BXT/GLK per-lane vswing and PHY reg cleanup (Ville)

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

From: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/Zik0LKEtN1PwXXGb@intel.com
parents 83221064 6068bc20
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -2281,6 +2281,8 @@ static const struct dpcd_quirk dpcd_quirk_list[] = {
	{ OUI(0x90, 0xCC, 0x24), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) },
	/* Synaptics DP1.4 MST hubs require DSC for some modes on which it applies HBLANK expansion. */
	{ OUI(0x90, 0xCC, 0x24), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_HBLANK_EXPANSION_REQUIRES_DSC) },
	/* MediaTek panels (at least in U3224KBA) require DSC for modes with a short HBLANK on UHBR links. */
	{ OUI(0x00, 0x0C, 0xE7), DEVICE_ID_ANY, false, BIT(DP_DPCD_QUIRK_HBLANK_EXPANSION_REQUIRES_DSC) },
	/* Apple MacBookPro 2017 15 inch eDP Retina panel reports too low DP_MAX_LINK_RATE */
	{ OUI(0x00, 0x10, 0xfa), DEVICE_ID(101, 68, 21, 101, 98, 97), false, BIT(DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS) },
};
+19 −3
Original line number Diff line number Diff line
@@ -2274,7 +2274,7 @@ drm_dp_mst_port_add_connector(struct drm_dp_mst_branch *mstb,

	if (port->pdt != DP_PEER_DEVICE_NONE &&
	    drm_dp_mst_is_end_device(port->pdt, port->mcs) &&
	    port->port_num >= DP_MST_LOGICAL_PORT_0)
	    drm_dp_mst_port_is_logical(port))
		port->cached_edid = drm_edid_read_ddc(port->connector,
						      &port->aux.ddc);

@@ -4219,7 +4219,7 @@ drm_dp_mst_detect_port(struct drm_connector *connector,
	case DP_PEER_DEVICE_SST_SINK:
		ret = connector_status_connected;
		/* for logical ports - cache the EDID */
		if (port->port_num >= DP_MST_LOGICAL_PORT_0 && !port->cached_edid)
		if (drm_dp_mst_port_is_logical(port) && !port->cached_edid)
			port->cached_edid = drm_edid_read_ddc(connector, &port->aux.ddc);
		break;
	case DP_PEER_DEVICE_DP_LEGACY_CONV:
@@ -5983,7 +5983,7 @@ static bool drm_dp_mst_is_virtual_dpcd(struct drm_dp_mst_port *port)
		return false;

	/* Virtual DP Sink (Internal Display Panel) */
	if (port->port_num >= 8)
	if (drm_dp_mst_port_is_logical(port))
		return true;

	/* DP-to-HDMI Protocol Converter */
@@ -6010,6 +6010,22 @@ static bool drm_dp_mst_is_virtual_dpcd(struct drm_dp_mst_port *port)
	return false;
}

/**
 * drm_dp_mst_aux_for_parent() - Get the AUX device for an MST port's parent
 * @port: MST port whose parent's AUX device is returned
 *
 * Return the AUX device for @port's parent or NULL if port's parent is the
 * root port.
 */
struct drm_dp_aux *drm_dp_mst_aux_for_parent(struct drm_dp_mst_port *port)
{
	if (!port->parent || !port->parent->port_parent)
		return NULL;

	return &port->parent->port_parent->aux;
}
EXPORT_SYMBOL(drm_dp_mst_aux_for_parent);

/**
 * drm_dp_mst_dsc_aux_for_port() - Find the correct aux for DSC
 * @port: The port to check. A leaf of the MST tree with an attached display.
+273 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: MIT */
/*
 * Copyright © 2023 Intel Corporation
 */

#ifndef __BXT_DPIO_PHY_REGS_H__
#define __BXT_DPIO_PHY_REGS_H__

#include "intel_display_reg_defs.h"

/* BXT PHY registers */
#define _BXT_PHY0_BASE			0x6C000
#define _BXT_PHY1_BASE			0x162000
#define _BXT_PHY2_BASE			0x163000
#define BXT_PHY_BASE(phy) \
	 _PICK_EVEN_2RANGES(phy, 1, \
			    _BXT_PHY0_BASE, _BXT_PHY0_BASE, \
			    _BXT_PHY1_BASE, _BXT_PHY2_BASE)

#define _BXT_PHY(phy, reg) \
	_MMIO(BXT_PHY_BASE(phy) - _BXT_PHY0_BASE + (reg))

#define _BXT_PHY_CH(phy, ch, reg_ch0, reg_ch1) \
	(BXT_PHY_BASE(phy) + _PIPE((ch), (reg_ch0) - _BXT_PHY0_BASE, \
					 (reg_ch1) - _BXT_PHY0_BASE))
#define _MMIO_BXT_PHY_CH(phy, ch, reg_ch0, reg_ch1) \
	_MMIO(_BXT_PHY_CH(phy, ch, reg_ch0, reg_ch1))
#define _BXT_LANE_OFFSET(lane)           (((lane) >> 1) * 0x200 + \
					  ((lane) & 1) * 0x80)
#define _MMIO_BXT_PHY_CH_LN(phy, ch, lane, reg_ch0, reg_ch1) \
	_MMIO(_BXT_PHY_CH(phy, ch, reg_ch0, reg_ch1) + _BXT_LANE_OFFSET(lane))

/* BXT PHY PLL registers */
#define _PORT_PLL_A			0x46074
#define _PORT_PLL_B			0x46078
#define _PORT_PLL_C			0x4607c
#define   PORT_PLL_ENABLE		REG_BIT(31)
#define   PORT_PLL_LOCK			REG_BIT(30)
#define   PORT_PLL_REF_SEL		REG_BIT(27)
#define   PORT_PLL_POWER_ENABLE		REG_BIT(26)
#define   PORT_PLL_POWER_STATE		REG_BIT(25)
#define BXT_PORT_PLL_ENABLE(port)	_MMIO_PORT(port, _PORT_PLL_A, _PORT_PLL_B)

#define _PORT_PLL_EBB_0_A		0x162034
#define _PORT_PLL_EBB_0_B		0x6C034
#define _PORT_PLL_EBB_0_C		0x6C340
#define   PORT_PLL_P1_MASK		REG_GENMASK(15, 13)
#define   PORT_PLL_P1(p1)		REG_FIELD_PREP(PORT_PLL_P1_MASK, (p1))
#define   PORT_PLL_P2_MASK		REG_GENMASK(12, 8)
#define   PORT_PLL_P2(p2)		REG_FIELD_PREP(PORT_PLL_P2_MASK, (p2))
#define BXT_PORT_PLL_EBB_0(phy, ch)	_MMIO_BXT_PHY_CH(phy, ch, \
							 _PORT_PLL_EBB_0_B, \
							 _PORT_PLL_EBB_0_C)

#define _PORT_PLL_EBB_4_A		0x162038
#define _PORT_PLL_EBB_4_B		0x6C038
#define _PORT_PLL_EBB_4_C		0x6C344
#define   PORT_PLL_RECALIBRATE		REG_BIT(14)
#define   PORT_PLL_10BIT_CLK_ENABLE	REG_BIT(13)
#define BXT_PORT_PLL_EBB_4(phy, ch)	_MMIO_BXT_PHY_CH(phy, ch, \
							 _PORT_PLL_EBB_4_B, \
							 _PORT_PLL_EBB_4_C)

#define _PORT_PLL_0_A			0x162100
#define _PORT_PLL_0_B			0x6C100
#define _PORT_PLL_0_C			0x6C380
/* PORT_PLL_0_A */
#define   PORT_PLL_M2_INT_MASK		REG_GENMASK(7, 0)
#define   PORT_PLL_M2_INT(m2_int)	REG_FIELD_PREP(PORT_PLL_M2_INT_MASK, (m2_int))
/* PORT_PLL_1_A */
#define   PORT_PLL_N_MASK		REG_GENMASK(11, 8)
#define   PORT_PLL_N(n)			REG_FIELD_PREP(PORT_PLL_N_MASK, (n))
/* PORT_PLL_2_A */
#define   PORT_PLL_M2_FRAC_MASK		REG_GENMASK(21, 0)
#define   PORT_PLL_M2_FRAC(m2_frac)	REG_FIELD_PREP(PORT_PLL_M2_FRAC_MASK, (m2_frac))
/* PORT_PLL_3_A */
#define   PORT_PLL_M2_FRAC_ENABLE	REG_BIT(16)
/* PORT_PLL_6_A */
#define   PORT_PLL_GAIN_CTL_MASK	REG_GENMASK(18, 16)
#define   PORT_PLL_GAIN_CTL(x)		REG_FIELD_PREP(PORT_PLL_GAIN_CTL_MASK, (x))
#define   PORT_PLL_INT_COEFF_MASK	REG_GENMASK(12, 8)
#define   PORT_PLL_INT_COEFF(x)		REG_FIELD_PREP(PORT_PLL_INT_COEFF_MASK, (x))
#define   PORT_PLL_PROP_COEFF_MASK	REG_GENMASK(3, 0)
#define   PORT_PLL_PROP_COEFF(x)	REG_FIELD_PREP(PORT_PLL_PROP_COEFF_MASK, (x))
/* PORT_PLL_8_A */
#define   PORT_PLL_TARGET_CNT_MASK	REG_GENMASK(9, 0)
#define   PORT_PLL_TARGET_CNT(x)	REG_FIELD_PREP(PORT_PLL_TARGET_CNT_MASK, (x))
/* PORT_PLL_9_A */
#define  PORT_PLL_LOCK_THRESHOLD_MASK	REG_GENMASK(3, 1)
#define  PORT_PLL_LOCK_THRESHOLD(x)	REG_FIELD_PREP(PORT_PLL_LOCK_THRESHOLD_MASK, (x))
/* PORT_PLL_10_A */
#define  PORT_PLL_DCO_AMP_OVR_EN_H	REG_BIT(27)
#define  PORT_PLL_DCO_AMP_MASK		REG_GENMASK(13, 10)
#define  PORT_PLL_DCO_AMP(x)		REG_FIELD_PREP(PORT_PLL_DCO_AMP_MASK, (x))
#define _PORT_PLL_BASE(phy, ch)		_BXT_PHY_CH(phy, ch, \
						    _PORT_PLL_0_B, \
						    _PORT_PLL_0_C)
#define BXT_PORT_PLL(phy, ch, idx)	_MMIO(_PORT_PLL_BASE(phy, ch) + \
					      (idx) * 4)

/* BXT PHY common lane registers */
#define _PORT_CL1CM_DW0_A		0x162000
#define _PORT_CL1CM_DW0_BC		0x6C000
#define   PHY_POWER_GOOD		REG_BIT(16)
#define   PHY_RESERVED			REG_BIT(7)
#define BXT_PORT_CL1CM_DW0(phy)		_BXT_PHY((phy), _PORT_CL1CM_DW0_BC)

#define _PORT_CL1CM_DW9_A		0x162024
#define _PORT_CL1CM_DW9_BC		0x6C024
#define   IREF0RC_OFFSET_MASK		REG_GENMASK(15, 8)
#define   IREF0RC_OFFSET(x)		REG_FIELD_PREP(IREF0RC_OFFSET_MASK, (x))
#define BXT_PORT_CL1CM_DW9(phy)		_BXT_PHY((phy), _PORT_CL1CM_DW9_BC)

#define _PORT_CL1CM_DW10_A		0x162028
#define _PORT_CL1CM_DW10_BC		0x6C028
#define   IREF1RC_OFFSET_MASK		REG_GENMASK(15, 8)
#define   IREF1RC_OFFSET(x)		REG_FIELD_PREP(IREF1RC_OFFSET_MASK, (x))
#define BXT_PORT_CL1CM_DW10(phy)	_BXT_PHY((phy), _PORT_CL1CM_DW10_BC)

#define _PORT_CL1CM_DW28_A		0x162070
#define _PORT_CL1CM_DW28_BC		0x6C070
#define   OCL1_POWER_DOWN_EN		REG_BIT(23)
#define   DW28_OLDO_DYN_PWR_DOWN_EN	REG_BIT(22)
#define   SUS_CLK_CONFIG		REG_GENMASK(1, 0)
#define BXT_PORT_CL1CM_DW28(phy)	_BXT_PHY((phy), _PORT_CL1CM_DW28_BC)

#define _PORT_CL1CM_DW30_A		0x162078
#define _PORT_CL1CM_DW30_BC		0x6C078
#define   OCL2_LDOFUSE_PWR_DIS		REG_BIT(6)
#define BXT_PORT_CL1CM_DW30(phy)	_BXT_PHY((phy), _PORT_CL1CM_DW30_BC)

/* The spec defines this only for BXT PHY0, but lets assume that this
 * would exist for PHY1 too if it had a second channel.
 */
#define _PORT_CL2CM_DW6_A		0x162358
#define _PORT_CL2CM_DW6_BC		0x6C358
#define BXT_PORT_CL2CM_DW6(phy)		_BXT_PHY((phy), _PORT_CL2CM_DW6_BC)
#define   DW6_OLDO_DYN_PWR_DOWN_EN	REG_BIT(28)

/* BXT PHY Ref registers */
#define _PORT_REF_DW3_A			0x16218C
#define _PORT_REF_DW3_BC		0x6C18C
#define   GRC_DONE			REG_BIT(22)
#define BXT_PORT_REF_DW3(phy)		_BXT_PHY((phy), _PORT_REF_DW3_BC)

#define _PORT_REF_DW6_A			0x162198
#define _PORT_REF_DW6_BC		0x6C198
#define   GRC_CODE_MASK			REG_GENMASK(31, 24)
#define   GRC_CODE(x)			REG_FIELD_PREP(GRC_CODE_MASK, (x))
#define   GRC_CODE_FAST_MASK		REG_GENMASK(23, 16)
#define   GRC_CODE_FAST(x)		REG_FIELD_PREP(GRC_CODE_FAST_MASK, (x))
#define   GRC_CODE_SLOW_MASK		REG_GENMASK(15, 8)
#define   GRC_CODE_SLOW(x)		REG_FIELD_PREP(GRC_CODE_SLOW_MASK, (x))
#define   GRC_CODE_NOM_MASK		REG_GENMASK(7, 0)
#define   GRC_CODE_NOM(x)		REG_FIELD_PREP(GRC_CODE_NOM_MASK, (x))
#define BXT_PORT_REF_DW6(phy)		_BXT_PHY((phy), _PORT_REF_DW6_BC)

#define _PORT_REF_DW8_A			0x1621A0
#define _PORT_REF_DW8_BC		0x6C1A0
#define   GRC_DIS			REG_BIT(15)
#define   GRC_RDY_OVRD			REG_BIT(1)
#define BXT_PORT_REF_DW8(phy)		_BXT_PHY((phy), _PORT_REF_DW8_BC)

/* BXT PHY PCS registers */
#define _PORT_PCS_DW10_LN01_A		0x162428
#define _PORT_PCS_DW10_LN01_B		0x6C428
#define _PORT_PCS_DW10_LN01_C		0x6C828
#define _PORT_PCS_DW10_GRP_A		0x162C28
#define _PORT_PCS_DW10_GRP_B		0x6CC28
#define _PORT_PCS_DW10_GRP_C		0x6CE28
#define BXT_PORT_PCS_DW10_LN01(phy, ch)	_MMIO_BXT_PHY_CH(phy, ch, \
							 _PORT_PCS_DW10_LN01_B, \
							 _PORT_PCS_DW10_LN01_C)
#define BXT_PORT_PCS_DW10_GRP(phy, ch)	_MMIO_BXT_PHY_CH(phy, ch, \
							 _PORT_PCS_DW10_GRP_B, \
							 _PORT_PCS_DW10_GRP_C)

#define   TX2_SWING_CALC_INIT		REG_BIT(31)
#define   TX1_SWING_CALC_INIT		REG_BIT(30)

#define _PORT_PCS_DW12_LN01_A		0x162430
#define _PORT_PCS_DW12_LN01_B		0x6C430
#define _PORT_PCS_DW12_LN01_C		0x6C830
#define _PORT_PCS_DW12_LN23_A		0x162630
#define _PORT_PCS_DW12_LN23_B		0x6C630
#define _PORT_PCS_DW12_LN23_C		0x6CA30
#define _PORT_PCS_DW12_GRP_A		0x162c30
#define _PORT_PCS_DW12_GRP_B		0x6CC30
#define _PORT_PCS_DW12_GRP_C		0x6CE30
#define   LANESTAGGER_STRAP_OVRD	REG_BIT(6)
#define   LANE_STAGGER_MASK		REG_GENMASK(4, 0)
#define BXT_PORT_PCS_DW12_LN01(phy, ch)	_MMIO_BXT_PHY_CH(phy, ch, \
							 _PORT_PCS_DW12_LN01_B, \
							 _PORT_PCS_DW12_LN01_C)
#define BXT_PORT_PCS_DW12_LN23(phy, ch)	_MMIO_BXT_PHY_CH(phy, ch, \
							 _PORT_PCS_DW12_LN23_B, \
							 _PORT_PCS_DW12_LN23_C)
#define BXT_PORT_PCS_DW12_GRP(phy, ch)	_MMIO_BXT_PHY_CH(phy, ch, \
							 _PORT_PCS_DW12_GRP_B, \
							 _PORT_PCS_DW12_GRP_C)

/* BXT PHY TX registers */
#define _PORT_TX_DW2_LN0_A		0x162508
#define _PORT_TX_DW2_LN0_B		0x6C508
#define _PORT_TX_DW2_LN0_C		0x6C908
#define _PORT_TX_DW2_GRP_A		0x162D08
#define _PORT_TX_DW2_GRP_B		0x6CD08
#define _PORT_TX_DW2_GRP_C		0x6CF08
#define BXT_PORT_TX_DW2_LN(phy, ch, lane)	_MMIO_BXT_PHY_CH_LN(phy, ch, lane, \
								    _PORT_TX_DW2_LN0_B,	\
								    _PORT_TX_DW2_LN0_C)
#define BXT_PORT_TX_DW2_GRP(phy, ch)	_MMIO_BXT_PHY_CH(phy, ch, \
							 _PORT_TX_DW2_GRP_B, \
							 _PORT_TX_DW2_GRP_C)
#define   MARGIN_000_MASK		REG_GENMASK(23, 16)
#define   MARGIN_000(x)			REG_FIELD_PREP(MARGIN_000_MASK, (x))
#define   UNIQ_TRANS_SCALE_MASK		REG_GENMASK(15, 8)
#define   UNIQ_TRANS_SCALE(x)		REG_FIELD_PREP(UNIQ_TRANS_SCALE_MASK, (x))

#define _PORT_TX_DW3_LN0_A		0x16250C
#define _PORT_TX_DW3_LN0_B		0x6C50C
#define _PORT_TX_DW3_LN0_C		0x6C90C
#define _PORT_TX_DW3_GRP_A		0x162D0C
#define _PORT_TX_DW3_GRP_B		0x6CD0C
#define _PORT_TX_DW3_GRP_C		0x6CF0C
#define BXT_PORT_TX_DW3_LN(phy, ch, lane)	_MMIO_BXT_PHY_CH_LN(phy, ch, lane, \
								    _PORT_TX_DW3_LN0_B, \
								    _PORT_TX_DW3_LN0_C)
#define BXT_PORT_TX_DW3_GRP(phy, ch)	_MMIO_BXT_PHY_CH(phy, ch, \
							 _PORT_TX_DW3_GRP_B, \
							 _PORT_TX_DW3_GRP_C)
#define   SCALE_DCOMP_METHOD		REG_BIT(26)
#define   UNIQUE_TRANGE_EN_METHOD	REG_BIT(27)

#define _PORT_TX_DW4_LN0_A		0x162510
#define _PORT_TX_DW4_LN0_B		0x6C510
#define _PORT_TX_DW4_LN0_C		0x6C910
#define _PORT_TX_DW4_GRP_A		0x162D10
#define _PORT_TX_DW4_GRP_B		0x6CD10
#define _PORT_TX_DW4_GRP_C		0x6CF10
#define BXT_PORT_TX_DW4_LN(phy, ch, lane)	_MMIO_BXT_PHY_CH_LN(phy, ch, lane, \
								    _PORT_TX_DW4_LN0_B, \
								    _PORT_TX_DW4_LN0_C)
#define BXT_PORT_TX_DW4_GRP(phy, ch)	_MMIO_BXT_PHY_CH(phy, ch, \
							 _PORT_TX_DW4_GRP_B, \
							 _PORT_TX_DW4_GRP_C)
#define   DE_EMPHASIS_MASK		REG_GENMASK(31, 24)
#define   DE_EMPHASIS(x)		REG_FIELD_PREP(DE_EMPHASIS_MASK, (x))

#define _PORT_TX_DW5_LN0_A		0x162514
#define _PORT_TX_DW5_LN0_B		0x6C514
#define _PORT_TX_DW5_LN0_C		0x6C914
#define _PORT_TX_DW5_GRP_A		0x162D14
#define _PORT_TX_DW5_GRP_B		0x6CD14
#define _PORT_TX_DW5_GRP_C		0x6CF14
#define BXT_PORT_TX_DW5_LN(phy, ch, lane)	_MMIO_BXT_PHY_CH_LN(phy, ch, lane, \
								    _PORT_TX_DW5_LN0_B, \
								    _PORT_TX_DW5_LN0_C)
#define BXT_PORT_TX_DW5_GRP(phy, ch)	_MMIO_BXT_PHY_CH(phy, ch, \
							 _PORT_TX_DW5_GRP_B, \
							 _PORT_TX_DW5_GRP_C)
#define   DCC_DELAY_RANGE_1		REG_BIT(9)
#define   DCC_DELAY_RANGE_2		REG_BIT(8)

#define _PORT_TX_DW14_LN0_A		0x162538
#define _PORT_TX_DW14_LN0_B		0x6C538
#define _PORT_TX_DW14_LN0_C		0x6C938
#define   LATENCY_OPTIM			REG_BIT(30)
#define BXT_PORT_TX_DW14_LN(phy, ch, lane)	_MMIO_BXT_PHY_CH_LN(phy, ch, lane, \
								    _PORT_TX_DW14_LN0_B, \
								    _PORT_TX_DW14_LN0_C)

#endif /* __BXT_DPIO_PHY_REGS_H__ */
+20 −20
Original line number Diff line number Diff line
@@ -83,16 +83,16 @@ static u32 scale_hw_to_user(struct intel_connector *connector,

u32 intel_backlight_invert_pwm_level(struct intel_connector *connector, u32 val)
{
	struct drm_i915_private *i915 = to_i915(connector->base.dev);
	struct intel_display *display = to_intel_display(connector);
	struct intel_panel *panel = &connector->panel;

	drm_WARN_ON(&i915->drm, panel->backlight.pwm_level_max == 0);
	drm_WARN_ON(display->drm, panel->backlight.pwm_level_max == 0);

	if (i915->display.params.invert_brightness < 0)
	if (display->params.invert_brightness < 0)
		return val;

	if (i915->display.params.invert_brightness > 0 ||
	    intel_has_quirk(i915, QUIRK_INVERT_BRIGHTNESS)) {
	if (display->params.invert_brightness > 0 ||
	    intel_has_quirk(display, QUIRK_INVERT_BRIGHTNESS)) {
		return panel->backlight.pwm_level_max - val + panel->backlight.pwm_level_min;
	}

@@ -126,15 +126,15 @@ u32 intel_backlight_level_to_pwm(struct intel_connector *connector, u32 val)

u32 intel_backlight_level_from_pwm(struct intel_connector *connector, u32 val)
{
	struct drm_i915_private *i915 = to_i915(connector->base.dev);
	struct intel_display *display = to_intel_display(connector);
	struct intel_panel *panel = &connector->panel;

	drm_WARN_ON_ONCE(&i915->drm,
	drm_WARN_ON_ONCE(display->drm,
			 panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0);

	if (i915->display.params.invert_brightness > 0 ||
	    (i915->display.params.invert_brightness == 0 &&
	     intel_has_quirk(i915, QUIRK_INVERT_BRIGHTNESS)))
	if (display->params.invert_brightness > 0 ||
	    (display->params.invert_brightness == 0 &&
	     intel_has_quirk(display, QUIRK_INVERT_BRIGHTNESS)))
		val = panel->backlight.pwm_level_max - (val - panel->backlight.pwm_level_min);

	return scale(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max,
@@ -1642,17 +1642,17 @@ void intel_backlight_update(struct intel_atomic_state *state,

int intel_backlight_setup(struct intel_connector *connector, enum pipe pipe)
{
	struct drm_i915_private *i915 = to_i915(connector->base.dev);
	struct intel_display *display = to_intel_display(connector);
	struct intel_panel *panel = &connector->panel;
	int ret;

	if (!connector->panel.vbt.backlight.present) {
		if (intel_has_quirk(i915, QUIRK_BACKLIGHT_PRESENT)) {
			drm_dbg_kms(&i915->drm,
		if (intel_has_quirk(display, QUIRK_BACKLIGHT_PRESENT)) {
			drm_dbg_kms(display->drm,
				    "[CONNECTOR:%d:%s] no backlight present per VBT, but present per quirk\n",
				    connector->base.base.id, connector->base.name);
		} else {
			drm_dbg_kms(&i915->drm,
			drm_dbg_kms(display->drm,
				    "[CONNECTOR:%d:%s] no backlight present per VBT\n",
				    connector->base.base.id, connector->base.name);
			return 0;
@@ -1660,16 +1660,16 @@ int intel_backlight_setup(struct intel_connector *connector, enum pipe pipe)
	}

	/* ensure intel_panel has been initialized first */
	if (drm_WARN_ON(&i915->drm, !panel->backlight.funcs))
	if (drm_WARN_ON(display->drm, !panel->backlight.funcs))
		return -ENODEV;

	/* set level and max in panel struct */
	mutex_lock(&i915->display.backlight.lock);
	mutex_lock(&display->backlight.lock);
	ret = panel->backlight.funcs->setup(connector, pipe);
	mutex_unlock(&i915->display.backlight.lock);
	mutex_unlock(&display->backlight.lock);

	if (ret) {
		drm_dbg_kms(&i915->drm,
		drm_dbg_kms(display->drm,
			    "[CONNECTOR:%d:%s] failed to setup backlight\n",
			    connector->base.base.id, connector->base.name);
		return ret;
@@ -1677,7 +1677,7 @@ int intel_backlight_setup(struct intel_connector *connector, enum pipe pipe)

	panel->backlight.present = true;

	drm_dbg_kms(&i915->drm,
	drm_dbg_kms(display->drm,
		    "[CONNECTOR:%d:%s] backlight initialized, %s, brightness %u/%u\n",
		    connector->base.base.id, connector->base.name,
		    str_enabled_disabled(panel->backlight.enabled),
@@ -1821,7 +1821,7 @@ void intel_backlight_init_funcs(struct intel_panel *panel)
		if (intel_dp_aux_init_backlight_funcs(connector) == 0)
			return;

		if (!intel_has_quirk(i915, QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK))
		if (!intel_has_quirk(&i915->display, QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK))
			connector->panel.backlight.power = intel_pps_backlight_power;
	}

+119 −41
Original line number Diff line number Diff line
@@ -162,7 +162,9 @@ int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv,
				1);

	if (ret < 0) {
		drm_err(&dev_priv->drm, "Failed to disable qgv points (%d) points: 0x%x\n", ret, points_mask);
		drm_err(&dev_priv->drm,
			"Failed to disable qgv points (0x%x) points: 0x%x\n",
			ret, points_mask);
		return ret;
	}

@@ -290,8 +292,10 @@ static int icl_get_qgv_points(struct drm_i915_private *dev_priv,
		struct intel_qgv_point *sp = &qi->points[i];

		ret = intel_read_qgv_point_info(dev_priv, sp, i);
		if (ret)
		if (ret) {
			drm_dbg_kms(&dev_priv->drm, "Could not read QGV %d info\n", i);
			return ret;
		}

		drm_dbg_kms(&dev_priv->drm,
			    "QGV %d: DCLK=%d tRP=%d tRDPRE=%d tRAS=%d tRCD=%d tRC=%d\n",
@@ -659,6 +663,22 @@ static unsigned int adl_psf_bw(struct drm_i915_private *dev_priv,
	return bi->psf_bw[psf_gv_point];
}

static unsigned int icl_qgv_bw(struct drm_i915_private *i915,
			       int num_active_planes, int qgv_point)
{
	unsigned int idx;

	if (DISPLAY_VER(i915) >= 12)
		idx = tgl_max_bw_index(i915, num_active_planes, qgv_point);
	else
		idx = icl_max_bw_index(i915, num_active_planes, qgv_point);

	if (idx >= ARRAY_SIZE(i915->display.bw.max))
		return 0;

	return i915->display.bw.max[idx].deratedbw[qgv_point];
}

void intel_bw_init_hw(struct drm_i915_private *dev_priv)
{
	if (!HAS_DISPLAY(dev_priv))
@@ -735,6 +755,7 @@ void intel_bw_crtc_update(struct intel_bw_state *bw_state,
		intel_bw_crtc_data_rate(crtc_state);
	bw_state->num_active_planes[crtc->pipe] =
		intel_bw_crtc_num_active_planes(crtc_state);
	bw_state->force_check_qgv = true;

	drm_dbg_kms(&i915->drm, "pipe %c data rate %u num active planes %u\n",
		    pipe_name(crtc->pipe),
@@ -804,6 +825,80 @@ intel_atomic_get_bw_state(struct intel_atomic_state *state)
	return to_intel_bw_state(bw_state);
}

static unsigned int icl_max_bw_qgv_point_mask(struct drm_i915_private *i915,
					      int num_active_planes)
{
	unsigned int num_qgv_points = i915->display.bw.max[0].num_qgv_points;
	unsigned int max_bw_point = 0;
	unsigned int max_bw = 0;
	int i;

	for (i = 0; i < num_qgv_points; i++) {
		unsigned int max_data_rate =
			icl_qgv_bw(i915, num_active_planes, i);

		/*
		 * We need to know which qgv point gives us
		 * maximum bandwidth in order to disable SAGV
		 * if we find that we exceed SAGV block time
		 * with watermarks. By that moment we already
		 * have those, as it is calculated earlier in
		 * intel_atomic_check,
		 */
		if (max_data_rate > max_bw) {
			max_bw_point = BIT(i);
			max_bw = max_data_rate;
		}
	}

	return max_bw_point;
}

static u16 icl_prepare_qgv_points_mask(struct drm_i915_private *i915,
				       unsigned int qgv_points,
				       unsigned int psf_points)
{
	return ~(ICL_PCODE_REQ_QGV_PT(qgv_points) |
		 ADLS_PCODE_REQ_PSF_PT(psf_points)) & icl_qgv_points_mask(i915);
}

static unsigned int icl_max_bw_psf_gv_point_mask(struct drm_i915_private *i915)
{
	unsigned int num_psf_gv_points = i915->display.bw.max[0].num_psf_gv_points;
	unsigned int max_bw_point_mask = 0;
	unsigned int max_bw = 0;
	int i;

	for (i = 0; i < num_psf_gv_points; i++) {
		unsigned int max_data_rate = adl_psf_bw(i915, i);

		if (max_data_rate > max_bw) {
			max_bw_point_mask = BIT(i);
			max_bw = max_data_rate;
		} else if (max_data_rate == max_bw) {
			max_bw_point_mask |= BIT(i);
		}
	}

	return max_bw_point_mask;
}

static void icl_force_disable_sagv(struct drm_i915_private *i915,
				   struct intel_bw_state *bw_state)
{
	unsigned int qgv_points = icl_max_bw_qgv_point_mask(i915, 0);
	unsigned int psf_points = icl_max_bw_psf_gv_point_mask(i915);

	bw_state->qgv_points_mask = icl_prepare_qgv_points_mask(i915,
								qgv_points,
								psf_points);

	drm_dbg_kms(&i915->drm, "Forcing SAGV disable: mask 0x%x\n",
		    bw_state->qgv_points_mask);

	icl_pcode_restrict_qgv_points(i915, bw_state->qgv_points_mask);
}

static int mtl_find_qgv_points(struct drm_i915_private *i915,
			       unsigned int data_rate,
			       unsigned int num_active_planes,
@@ -881,8 +976,6 @@ static int icl_find_qgv_points(struct drm_i915_private *i915,
			       const struct intel_bw_state *old_bw_state,
			       struct intel_bw_state *new_bw_state)
{
	unsigned int max_bw_point = 0;
	unsigned int max_bw = 0;
	unsigned int num_psf_gv_points = i915->display.bw.max[0].num_psf_gv_points;
	unsigned int num_qgv_points = i915->display.bw.max[0].num_qgv_points;
	u16 psf_points = 0;
@@ -895,31 +988,8 @@ static int icl_find_qgv_points(struct drm_i915_private *i915,
		return ret;

	for (i = 0; i < num_qgv_points; i++) {
		unsigned int idx;
		unsigned int max_data_rate;

		if (DISPLAY_VER(i915) >= 12)
			idx = tgl_max_bw_index(i915, num_active_planes, i);
		else
			idx = icl_max_bw_index(i915, num_active_planes, i);

		if (idx >= ARRAY_SIZE(i915->display.bw.max))
			continue;

		max_data_rate = i915->display.bw.max[idx].deratedbw[i];

		/*
		 * We need to know which qgv point gives us
		 * maximum bandwidth in order to disable SAGV
		 * if we find that we exceed SAGV block time
		 * with watermarks. By that moment we already
		 * have those, as it is calculated earlier in
		 * intel_atomic_check,
		 */
		if (max_data_rate > max_bw) {
			max_bw_point = i;
			max_bw = max_data_rate;
		}
		unsigned int max_data_rate = icl_qgv_bw(i915,
							num_active_planes, i);
		if (max_data_rate >= data_rate)
			qgv_points |= BIT(i);

@@ -963,20 +1033,18 @@ static int icl_find_qgv_points(struct drm_i915_private *i915,
	 * cause.
	 */
	if (!intel_can_enable_sagv(i915, new_bw_state)) {
		qgv_points = BIT(max_bw_point);
		drm_dbg_kms(&i915->drm, "No SAGV, using single QGV point %d\n",
			    max_bw_point);
		qgv_points = icl_max_bw_qgv_point_mask(i915, num_active_planes);
		drm_dbg_kms(&i915->drm, "No SAGV, using single QGV point mask 0x%x\n",
			    qgv_points);
	}

	/*
	 * We store the ones which need to be masked as that is what PCode
	 * actually accepts as a parameter.
	 */
	new_bw_state->qgv_points_mask =
		~(ICL_PCODE_REQ_QGV_PT(qgv_points) |
		  ADLS_PCODE_REQ_PSF_PT(psf_points)) &
		icl_qgv_points_mask(i915);

	new_bw_state->qgv_points_mask = icl_prepare_qgv_points_mask(i915,
								    qgv_points,
								    psf_points);
	/*
	 * If the actual mask had changed we need to make sure that
	 * the commits are serialized(in case this is a nomodeset, nonblocking)
@@ -1272,8 +1340,9 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
	new_bw_state = intel_atomic_get_new_bw_state(state);

	if (new_bw_state &&
	    intel_can_enable_sagv(i915, old_bw_state) !=
	    intel_can_enable_sagv(i915, new_bw_state))
	    (intel_can_enable_sagv(i915, old_bw_state) !=
	     intel_can_enable_sagv(i915, new_bw_state) ||
	     new_bw_state->force_check_qgv))
		changed = true;

	/*
@@ -1287,6 +1356,8 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
	if (ret)
		return ret;

	new_bw_state->force_check_qgv = false;

	return 0;
}

@@ -1313,7 +1384,7 @@ static const struct intel_global_state_funcs intel_bw_funcs = {
	.atomic_destroy_state = intel_bw_destroy_state,
};

int intel_bw_init(struct drm_i915_private *dev_priv)
int intel_bw_init(struct drm_i915_private *i915)
{
	struct intel_bw_state *state;

@@ -1321,8 +1392,15 @@ int intel_bw_init(struct drm_i915_private *dev_priv)
	if (!state)
		return -ENOMEM;

	intel_atomic_global_obj_init(dev_priv, &dev_priv->display.bw.obj,
	intel_atomic_global_obj_init(i915, &i915->display.bw.obj,
				     &state->base, &intel_bw_funcs);

	/*
	 * Limit this only if we have SAGV. And for Display version 14 onwards
	 * sagv is handled though pmdemand requests
	 */
	if (intel_has_sagv(i915) && IS_DISPLAY_VER(i915, 11, 13))
		icl_force_disable_sagv(i915, state);

	return 0;
}
Loading