Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] crypto: tstmgr - guard xxhash tests
From: Hamza Mahfooz @ 2026-04-09 17:18 UTC (permalink / raw)
  To: Herbert Xu
  Cc: linux-crypto, David S. Miller, Maxime Coquelin, Alexandre Torgue,
	linux-stm32, linux-arm-kernel, linux-kernel, Jeff Barnes,
	Paul Monson
In-Reply-To: <adYNClYB6RY820Xl@gondor.apana.org.au>

On Wed, Apr 08, 2026 at 04:08:42PM +0800, Herbert Xu wrote:
> Please show me the panic.  Normally it's not an issue if an algorithm
> is not present while the test vectors are.
> 

alg: hash: failed to allocate transform for xxhash64: -2
Kernel panic - not syncing: alg: self-tests for xxhash64 (xxhash64) failed in fips mode!
CPU: 0 PID: 425 Comm: modprobe Not tainted 6.6.130.2-2.azl3 #1
Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS Hyper-V UEFI Release v4.1 01/08/2026
Call Trace:
 <TASK>
 dump_stack_lvl+0x4c/0x70
 dump_stack+0x14/0x20
 panic+0x179/0x330
 alg_test+0x678/0x680
 ? __alloc_pages+0x1e2/0x340
 do_test+0x26f8/0x7670 [tcrypt]
 do_test+0x72c5/0x7670 [tcrypt]
 tcrypt_mod_init+0x65/0xff0 [tcrypt]
 ? __pfx_tcrypt_mod_init+0x10/0x10 [tcrypt]
 do_one_initcall+0x4e/0x330
 ? kmalloc_trace+0x2e/0xa0
 do_init_module+0x68/0x250
 load_module+0x1f2e/0x2150
 ? __do_sys_init_module+0xe6/0x1d0
 __do_sys_init_module+0x19c/0x1d0
 ? __do_sys_init_module+0x19c/0x1d0
 __x64_sys_init_module+0x1e/0x30
 x64_sys_call+0x11b3/0x1c90
 do_syscall_64+0x5a/0x80
 ? irqentry_exit_to_user_mode+0x29/0x50
 ? irqentry_exit+0x3f/0x50
 ? exc_page_fault+0x87/0x160
 entry_SYSCALL_64_after_hwframe+0x78/0xe2
RIP: 0033:0x7715f70fab9e
Code: 48 8b 0d 85 32 12 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 49 89 ca b8 af 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 52 32 12 00 f7 d8 64 89 01 48
RSP: 002b:00007ffde8fef6c8 EFLAGS: 00000246 ORIG_RAX: 00000000000000af
RAX: ffffffffffffffda RBX: 00005d0b39626af0 RCX: 00007715f70fab9e
RDX: 00005d0b1710197a RSI: 0000000000028c39 RDI: 00005d0b39635310
RBP: 00005d0b1710197a R08: 0000000000000001 R09: 0000000000000000
R10: 0000000000000071 R11: 0000000000000246 R12: 00005d0b39635310
R13: 0000000000000000 R14: 00005d0b39626c20 R15: 00005d0b39626da0
 </TASK>

Seems like crypto_alg_mod_lookup() [1] fails and that triggers the panic() at [2].

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/crypto/api.c?h=v7.0-rc7#n338
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/crypto/testmgr.c?h=v7.0-rc7#n5760

BR,
Hamza


^ permalink raw reply

* Re: [PATCH v2 0/3] media: imx-csi: cleanup media pipeline start
From: Michael Tretter @ 2026-04-09 17:17 UTC (permalink / raw)
  To: Frank Li
  Cc: Hans Verkuil, Steve Longerbeam, Philipp Zabel,
	Mauro Carvalho Chehab, Fabio Estevam, Greg Kroah-Hartman,
	Shawn Guo, Sascha Hauer, linux-media, imx, linux-arm-kernel,
	Pengutronix Kernel Team, linux-staging
In-Reply-To: <acqK9Ms_eRxg59Xa@lizhi-Precision-Tower-5810>

Hi Frank,

On Mon, 30 Mar 2026 10:38:44 -0400, Frank Li wrote:
> On Mon, Mar 30, 2026 at 10:49:22AM +0200, Michael Tretter wrote:
> > Hi Hans,
> >
> > On Fri, 23 Jan 2026 17:57:23 +0100, Michael Tretter wrote:
> > > On Thu, 18 Dec 2025 10:23:48 +0100, Michael Tretter wrote:
> > > > The imx media device currently assumes that there is only a single media
> > > > pipeline. However, the media graph has multiple imx capture devices.
> > > > These may be started separately on media pipelines if they don't cause
> > > > conflicts in the media graph.
> > > >
> > > > Move the media pipeline from the media device to the capture devices to
> > > > properly track and handle multiple media pipelines for the imx-csi.
> > > > Refactor the code to start the media pipeline from the driver to help
> > > > the reader.
> > >
> >
> > Could you take a look and apply this series for the imx-media driver,
> > too? The patches are already reviewed by Frank Li and Philipp Zabel.
> 
> Michael Tretter:
> 
> Sorry, I will take care imx's stage driver. I already sent pull-request,
> which included your other two patches.

Thanks for taking care! I found the other two patches in the
media-committers repository.

> 
> Do you have others patches, which need me take care. I am not sure if
> there are chance to send 2nd pull request for 7.1.

Currently, I have only the patches in this series.

Michael

> > >
> > > >
> > > > Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> > > > ---
> > > > Changes in v2:
> > > > - Improve code readability in Patch 2
> > > > - Update commit message of Patch 3 as suggested by Frank Li
> > > > - Link to v1: https://patch.msgid.link/20251107-media-imx-cleanup-v1-0-f82a693c28f4@pengutronix.de
> > > >
> > > > ---
> > > > Michael Tretter (3):
> > > >       media: imx-csi: move media_pipeline to video device
> > > >       media: imx-csi: explicitly start media pipeline on pad 0
> > > >       media: imx-csi: use media_pad_is_streaming helper
> > > >
> > > >  drivers/staging/media/imx/imx-media-capture.c |  8 ++++----
> > > >  drivers/staging/media/imx/imx-media-utils.c   | 12 ++++++++----
> > > >  drivers/staging/media/imx/imx-media.h         |  7 ++++---
> > > >  3 files changed, 16 insertions(+), 11 deletions(-)
> > > > ---
> > > > base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
> > > > change-id: 20251107-media-imx-cleanup-9022d941ae44


^ permalink raw reply

* Re: [PATCH v4 0/4] Introduce Allwinner H616 PWM controller
From: Paul Kocialkowski @ 2026-04-09 17:16 UTC (permalink / raw)
  To: Richard Genoud
  Cc: Uwe Kleine-König, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland,
	Philipp Zabel, Thomas Petazzoni, John Stultz, Joao Schim,
	linux-pwm, devicetree, linux-arm-kernel, linux-sunxi,
	linux-kernel
In-Reply-To: <20260305091959.2530374-1-richard.genoud@bootlin.com>

[-- Attachment #1: Type: text/plain, Size: 7856 bytes --]

Hi Richard,

On Thu 05 Mar 26, 10:19, Richard Genoud wrote:
> Allwinner H616 PWM controller is quite different from the A10 one.

As I've mentionned before, this PWM controller is not specific to the H616
but also appears in other chips, so the name of the driver and registers
should not mention H616.

After further investigation, I can see multiple versions of this new PWM IP
being used in different chips, starting with the R40/V40 (sun8iw11) in 2016.

The latest downstream BSP driver has a list of the different generations:
https://github.com/radxa/allwinner-bsp/blob/cubie-aiot-v1.4.6/drivers/pwm/pwm-sunxi.c#L1901

We have a first generation called v100/v101 for the following chips:
H616, R328 and R40. A second generation is called v200 and brings slight
register layout differences for A133, D1/T113-S3 and V851. Subsequent
iterations (v201-5) are used in more recent chips like A527 and A733 and
seem register-compatible with v200 (from a quick look).

So what I suggest here is to rename the driver "sun8i-pwm" and eventually add
a list of generations to the driver and different registers when needed, with
an appropriate suffix in their name.

But since you're currently only dealing with H616, this work can be done later
when introducing support for more chips.

> It can drive 6 PWM channels, and like for the A10, each channel has a
> bypass that permits to output a clock, bypassing the PWM logic, when
> enabled.
> 
> But, the channels are paired 2 by 2, sharing a first set of
> MUX/prescaler/gate.
> Then, for each channel, there's another prescaler (that will be bypassed
> if the bypass is enabled for this channel).
> 
> It looks like that:
>             _____      ______      ________
> OSC24M --->|     |    |      |    |        |
> APB1 ----->| Mux |--->| Gate |--->| /div_m |-----> PWM_clock_src_xy
>            |_____|    |______|    |________|
>                           ________
>                          |        |
>                       +->| /div_k |---> PWM_clock_x
>                       |  |________|
>                       |    ______
>                       |   |      |
>                       +-->| Gate |----> PWM_bypass_clock_x
>                       |   |______|
> PWM_clock_src_xy -----+   ________
>                       |  |        |
>                       +->| /div_k |---> PWM_clock_y
>                       |  |________|
>                       |    ______
>                       |   |      |
>                       +-->| Gate |----> PWM_bypass_clock_y
>                           |______|
> 
> Where xy can be 0/1, 2/3, 4/5
> 
> PWM_clock_x/y serve for the PWM purpose.
> PWM_bypass_clock_x/y serve for the clock-provider purpose.
> The common clock framework has been used to manage those clocks.
> 
> This PWM driver serves as a clock-provider for PWM_bypass_clocks.
> This is needed for example by the embedded AC300 PHY which clock comes
> from PMW5 pin (PB12).
> 
> Usually, to get a clock from a PWM driver, we use the pwm-clock driver
> so that the PWM driver doesn't need to be a clk-provider itself.
> While this works in most cases, here it just doesn't.
> That's because the pwm-clock request a period from the PWM driver,
> without any clue that it actually wants a clock at a specific frequency,
> and not a PWM signal with duty cycle capability.

From what I understand the pwm-clock driver will either assume a fixed rate
set in device-tree or deduce the rate from the pwm period. In any case it will
check that the pwm period (which it cannot change) is the same as the requested
clock period.

So I agree that pwm-clock is unable to change the clock rate at runtime and will
just use whatever frequency the pwm is running at (which is typically set
in the device-tree consumer property).

> So, the PWM driver doesn't know if it can use the bypass or not, it
> doesn't even have the real accurate frequency information (23809524 Hz
> instead of 24MHz) because PWM drivers only deal with periods.

I agree that the driver needs to register as a proper clock provider in
addition to pwm. But what happens if the same PWM clock is requested both from
the clk side and the pwm side?

> With pwm-clock, we loose a precious information along the way (that we
> actually want a clock and not a PWM signal).
> That's ok with simple PWM drivers that don't have multiple input clocks,
> but in this case, without this information, we can't know for sure which
> clock to use.
> And here, for instance, if we ask for a 24MHz clock, pwm-clock will
> requests 42ns (assigned-clocks doesn't help for that matter). The logic
> is to select the highest clock (100MHz) with no prescaler and a duty
> cycle value of 2/4 => we have 25MHz instead of 24MHz.
> And that's a perfectly fine choice for a PMW, because we still can
> change the duty cycle in the range [0-4]/4.
> But obviously for a clock, we don't care about the duty cycle, but more
> about the clock accuracy.
> 
> And actually, this PWM is really a PWM AND a real clock when the bypass
> is set.

Make sense to me.

> This series is based onto v6.19-rc4
> 
> NB: checkpatch is not happy with patch 2, but it's a false positive.
> It doesn't detect that PWM_XY_SRC_MUX/GATE/DIV are structures, but as
> it's more readable like that, I prefer keeping it that way.
> 
> NB2: for geopolitical reasons, I didn't re-use the old series that Paul
> was referring to.
> 
> Changes since v3:
> - gather Acked-by/Tested-by
> - fix cast from pointer to integer of different size (kernel test robot
>   with arc platform)
> - add devm_action for clk_hw_unregister_composite as suggested by Philipp
> - remove now unused pwm_remove as suggested by Philipp
> 
> Changes since v2:
> - use U32_MAX instead of defining UINT32_MAX
> - add a comment on U32_MAX usage in clk_round_rate()
> - change clk_table_div_m (use macros)
> - fix formatting (double space, superfluous comma, extra line feed)
> - fix the parent clock order
> - simplify code by using scoped_guard()
> - add missing const in to_h616_pwm_chip() and rename to
> h616_pwm_from_chip()
> - add/remove missing/superflous error messages
> - rename cnt->period_ticks, duty_cnt->duty_ticks
> - fix PWM_PERIOD_MAX
> - add .remove() callback
> - fix DIV_ROUND_CLOSEST_ULL->DIV_ROUND_UP_ULL
> - add H616_ prefix
> - protect _reg in macros
> - switch to waveforms instead of apply/get_state
> - shrink struct h616_pwm_channel
> - rebase on v6.19-rc4
> 
> Changes since v1:
> - rebase onto v6.19-rc1
> - add missing headers
> - remove MODULE_ALIAS (suggested by Krzysztof)
> - use sun4i-pwm binding instead of creating a new one (suggested by Krzysztof)
> - retrieve the parent clocks from the devicetree
> - switch num_parents to unsigned int
> 
> Richard Genoud (4):
>   dt-bindings: pwm: allwinner: add h616 pwm compatible
>   pwm: sun50i: Add H616 PWM support
>   arm64: dts: allwinner: h616: add PWM controller
>   MAINTAINERS: Add entry on Allwinner H616 PWM driver
> 
>  .../bindings/pwm/allwinner,sun4i-a10-pwm.yaml |  19 +-
>  MAINTAINERS                                   |   5 +
>  .../arm64/boot/dts/allwinner/sun50i-h616.dtsi |  47 +
>  drivers/pwm/Kconfig                           |  12 +
>  drivers/pwm/Makefile                          |   1 +
>  drivers/pwm/pwm-sun50i-h616.c                 | 936 ++++++++++++++++++
>  6 files changed, 1019 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/pwm/pwm-sun50i-h616.c
> 
> 
> base-commit: 11439c4635edd669ae435eec308f4ab8a0804808

-- 
Paul Kocialkowski,

Independent contractor - sys-base - https://www.sys-base.io/
Free software developer - https://www.paulk.fr/

Expert in multimedia, graphics and embedded hardware support with Linux.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* [PATCH RFC 12/12] drm/mediatek: Use dp_connector helpers to report link training state
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
  To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
	David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
	Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
	Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
  Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
	intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
	linux-arm-kernel, Simona Vetter, Kory Maincent
In-Reply-To: <20260409-feat_link_cap-v1-0-7069e8199ce2@bootlin.com>

Set DRM_BRIDGE_OP_DP and populate dp_link_train_caps with the supported
link rates, lane counts, voltage swing and pre-emphasis levels so the
bridge connector uses drmm_connector_dp_init() and exposes the link
training state properties to userspace.

Store per-lane voltage swing and pre-emphasis values in
mtk_dp_train_info and report the negotiated link parameters via
drm_connector_dp_set_link_train_properties() on training completion.
Clear them via drm_connector_dp_reset_link_train_properties() when a
disconnect is detected in the HPD event thread.

Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---

This patch has still not been tested. I am in the process of finding the
hardware for that.
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index c52cc7c2e2006..119718c1374c5 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -10,6 +10,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
+#include <drm/drm_dp_connector.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
@@ -72,6 +73,8 @@ struct mtk_dp_train_info {
 	/* link_rate is in multiple of 0.27Gbps */
 	int link_rate;
 	int lane_count;
+	u8 vswing[4];
+	u8 preemphasis[4];
 	unsigned int channel_eq_pattern;
 };
 
@@ -1561,6 +1564,9 @@ static void mtk_dp_train_update_swing_pre(struct mtk_dp *mtk_dp, int lanes,
 		mtk_dp_set_swing_pre_emphasis(mtk_dp, lane, swing, preemphasis);
 		drm_dp_dpcd_writeb(&mtk_dp->aux, DP_TRAINING_LANE0_SET + lane,
 				   val);
+
+		mtk_dp->train_info.vswing[lane] = swing;
+		mtk_dp->train_info.preemphasis[lane] = preemphasis;
 	}
 }
 
@@ -1812,6 +1818,21 @@ static void mtk_dp_train_change_mode(struct mtk_dp *mtk_dp)
 	mtk_dp_reset_swing_pre_emphasis(mtk_dp);
 }
 
+static int mtk_dp_report_link_train(struct mtk_dp *mtk_dp)
+{
+	struct drm_connector_dp_link_train dp_link_train;
+
+	dp_link_train.rate = drm_dp_bw_code_to_link_rate(mtk_dp->train_info.link_rate);
+	dp_link_train.nlanes = mtk_dp->train_info.lane_count;
+
+	for (int i = 0; i < mtk_dp->train_info.lane_count; i++) {
+		dp_link_train.v_swing[i] = 1 << mtk_dp->train_info.vswing[i];
+		dp_link_train.pre_emph[i] = 1 << mtk_dp->train_info.preemphasis[i];
+	}
+
+	return drm_connector_dp_set_link_train_properties(mtk_dp->conn, &dp_link_train);
+}
+
 static int mtk_dp_training(struct mtk_dp *mtk_dp)
 {
 	int ret;
@@ -1892,7 +1913,7 @@ static int mtk_dp_training(struct mtk_dp *mtk_dp)
 	mtk_dp_training_set_scramble(mtk_dp, true);
 	mtk_dp_set_enhanced_frame_mode(mtk_dp);
 
-	return 0;
+	return mtk_dp_report_link_train(mtk_dp);
 }
 
 static void mtk_dp_video_enable(struct mtk_dp *mtk_dp, bool enable)
@@ -2004,6 +2025,7 @@ static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev)
 			mtk_dp->need_debounce = false;
 			mod_timer(&mtk_dp->debounce_timer,
 				  jiffies + msecs_to_jiffies(100) - 1);
+			drm_connector_dp_reset_link_train_properties(mtk_dp->conn);
 		} else {
 			mtk_dp_aux_panel_poweron(mtk_dp, true);
 
@@ -2742,6 +2764,14 @@ static int mtk_dp_edp_link_panel(struct drm_dp_aux *mtk_aux)
 
 static int mtk_dp_probe(struct platform_device *pdev)
 {
+	static const u32 dp_rates[] = {162000, 270000, 540000, 810000};
+	static const struct drm_connector_dp_link_train_caps dp_link_train_caps = {
+		.nlanes = DRM_DP_1LANE | DRM_DP_2LANE | DRM_DP_4LANE,
+		.nrates = ARRAY_SIZE(dp_rates),
+		.rates = dp_rates,
+		.v_swings = DRM_DP_VOLTAGE_SWING_LEVEL_MASK,
+		.pre_emphs = DRM_DP_PRE_EMPH_LEVEL_MASK,
+	};
 	struct mtk_dp *mtk_dp;
 	struct device *dev = &pdev->dev;
 	int ret;
@@ -2809,6 +2839,8 @@ static int mtk_dp_probe(struct platform_device *pdev)
 
 	mtk_dp->bridge.of_node = dev->of_node;
 	mtk_dp->bridge.type = mtk_dp->data->bridge_type;
+	mtk_dp->bridge.dp_link_train_caps = &dp_link_train_caps;
+	mtk_dp->bridge.ops = DRM_BRIDGE_OP_DP;
 
 	if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP) {
 		/*

-- 
2.43.0



^ permalink raw reply related

* [PATCH RFC 11/12] drm/bridge: Wire drmm_connector_dp_init() via new DRM_BRIDGE_OP_DP flag
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
  To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
	David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
	Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
	Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
  Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
	intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
	linux-arm-kernel, Simona Vetter, Kory Maincent
In-Reply-To: <20260409-feat_link_cap-v1-0-7069e8199ce2@bootlin.com>

Introduce DRM_BRIDGE_OP_DP, a new bridge operation flag for bridges
that provide DisplayPort connector operations with link training support.
Bridges advertising this flag must fill the dp_link_train_caps field in
struct drm_bridge with their link training capabilities.

In drm_bridge_connector_init(), when a bridge sets DRM_BRIDGE_OP_DP,
use drmm_connector_dp_init() instead of the generic drmm_connector_init()
so the connector exposes link training state properties to userspace.
This mirrors the existing pattern used for HDMI bridges.

Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 26 +++++++++++++++++++++++++-
 include/drm/drm_bridge.h                       | 13 +++++++++++++
 2 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 39cc18f78eda1..e20b61bb03f12 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -13,7 +13,7 @@
 #include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_bridge_connector.h>
-#include <drm/drm_connector.h>
+#include <drm/drm_dp_connector.h>
 #include <drm/drm_device.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_managed.h>
@@ -108,6 +108,13 @@ struct drm_bridge_connector {
 	 * HDMI Audio infrastructure, if any (see &DRM_BRIDGE_OP_HDMI_AUDIO).
 	 */
 	struct drm_bridge *bridge_hdmi_audio;
+	/**
+	 * @bridge_dp:
+	 *
+	 * The bridge in the chain that implements necessary support for the
+	 * DisplayPort connector infrastructure, if any (see &DRM_BRIDGE_OP_DP).
+	 */
+	struct drm_bridge *bridge_dp;
 	/**
 	 * @bridge_dp_audio:
 	 *
@@ -766,6 +773,7 @@ static void drm_bridge_connector_put_bridges(struct drm_device *dev, void *data)
 	drm_bridge_put(bridge_connector->bridge_hdmi_audio);
 	drm_bridge_put(bridge_connector->bridge_dp_audio);
 	drm_bridge_put(bridge_connector->bridge_hdmi_cec);
+	drm_bridge_put(bridge_connector->bridge_dp);
 }
 
 /**
@@ -898,6 +906,15 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
 			bridge_connector->bridge_hdmi_audio = drm_bridge_get(bridge);
 		}
 
+		if (bridge->ops & DRM_BRIDGE_OP_DP) {
+			if (bridge_connector->bridge_dp)
+				return ERR_PTR(-EBUSY);
+			if (!bridge->dp_link_train_caps)
+				return ERR_PTR(-EINVAL);
+
+			bridge_connector->bridge_dp = drm_bridge_get(bridge);
+		}
+
 		if (bridge->ops & DRM_BRIDGE_OP_DP_AUDIO) {
 			if (bridge_connector->bridge_dp_audio)
 				return ERR_PTR(-EBUSY);
@@ -986,6 +1003,13 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
 					       max_bpc);
 		if (ret)
 			return ERR_PTR(ret);
+	} else if (bridge_connector->bridge_dp) {
+		ret = drmm_connector_dp_init(drm, connector,
+					     &drm_bridge_connector_funcs,
+					     bridge_connector->bridge_dp->dp_link_train_caps,
+					     connector_type, ddc);
+		if (ret)
+			return ERR_PTR(ret);
 	} else {
 		ret = drmm_connector_init(drm, connector,
 					  &drm_bridge_connector_funcs,
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index a8d67bd9ee505..b3df9dffd5bcc 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1092,6 +1092,14 @@ enum drm_bridge_ops {
 	 * &drm_bridge_funcs->hdmi_clear_spd_infoframe callbacks.
 	 */
 	DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME = BIT(10),
+	/**
+	 * @DRM_BRIDGE_OP_DP: The bridge provides DisplayPort connector
+	 * operations, including link training support. Bridges that set
+	 * this flag must provide DisplayPort-related information and
+	 * fill the &drm_bridge->dp_link_train_caps link training
+	 * capabilities.
+	 */
+	DRM_BRIDGE_OP_DP = BIT(11),
 };
 
 /**
@@ -1267,6 +1275,11 @@ struct drm_bridge {
 	 */
 	void *hpd_data;
 
+	/**
+	 * @dp_link_train_caps: DisplayPort link training capabilities
+	 */
+	const struct drm_connector_dp_link_train_caps *dp_link_train_caps;
+
 	/**
 	 * @next_bridge: Pointer to the following bridge, automatically put
 	 * when this bridge is freed (i.e. at destroy time). This is for

-- 
2.43.0



^ permalink raw reply related

* [PATCH RFC 10/12] drm/i915/display/dp: Adopt dp_connector helpers to expose link training state
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
  To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
	David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
	Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
	Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
  Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
	intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
	linux-arm-kernel, Simona Vetter, Kory Maincent
In-Reply-To: <20260409-feat_link_cap-v1-0-7069e8199ce2@bootlin.com>

Switch the i915 DP connector initialization from drmm_connector_init()
to drmm_connector_dp_init(), providing the source link capabilities
(supported lane counts, link rates, DSC support, voltage swing and
pre-emphasis levels).

Add intel_dp_report_link_train() to collect the negotiated link
parameters (rate, lane count, DSC enable, per-lane voltage swing and
pre-emphasis) and report them via drm_connector_dp_set_link_train_properties()
once link training completes successfully.

Reset the link training properties via
drm_connector_dp_reset_link_train_properties() when the connector is
reported as disconnected or when the display device is disabled, so
the exposed state always reflects the current link status.

Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c            | 31 +++++++++++++++++++---
 .../gpu/drm/i915/display/intel_dp_link_training.c  | 25 +++++++++++++++++
 2 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 2af64de9c81de..641406bdc0cc9 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -45,6 +45,7 @@
 #include <drm/display/drm_hdmi_helper.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
+#include <drm/drm_dp_connector.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_fixed.h>
 #include <drm/drm_managed.h>
@@ -6337,8 +6338,10 @@ intel_dp_detect(struct drm_connector *_connector,
 	drm_WARN_ON(display->drm,
 		    !drm_modeset_is_locked(&display->drm->mode_config.connection_mutex));
 
-	if (!intel_display_device_enabled(display))
+	if (!intel_display_device_enabled(display)) {
+		drm_connector_dp_reset_link_train_properties(_connector);
 		return connector_status_disconnected;
+	}
 
 	if (!intel_display_driver_check_access(display))
 		return connector->base.status;
@@ -6388,6 +6391,8 @@ intel_dp_detect(struct drm_connector *_connector,
 
 		intel_dp_tunnel_disconnect(intel_dp);
 
+		drm_connector_dp_reset_link_train_properties(_connector);
+
 		goto out_unset_edid;
 	}
 
@@ -7162,10 +7167,12 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
 			struct intel_connector *connector)
 {
 	struct intel_display *display = to_intel_display(dig_port);
+	struct drm_connector_dp_link_train_caps link_caps;
 	struct intel_dp *intel_dp = &dig_port->dp;
 	struct intel_encoder *encoder = &dig_port->base;
 	struct drm_device *dev = encoder->base.dev;
 	enum port port = encoder->port;
+	u32 *rates;
 	int type;
 
 	if (drm_WARN(dev, dig_port->max_lanes < 1,
@@ -7213,8 +7220,25 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
 		    type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP",
 		    encoder->base.base.id, encoder->base.name);
 
-	drmm_connector_init(dev, &connector->base, &intel_dp_connector_funcs,
-			    type, &intel_dp->aux.ddc);
+	intel_dp_set_source_rates(intel_dp);
+	link_caps.nlanes = DRM_DP_1LANE | DRM_DP_2LANE | DRM_DP_4LANE;
+	link_caps.nrates = intel_dp->num_source_rates;
+	rates = kzalloc_objs(*rates, intel_dp->num_source_rates);
+	if (!rates)
+		goto fail;
+
+	for (int i = 0; i < intel_dp->num_source_rates; i++)
+		rates[i] = intel_dp->source_rates[i];
+
+	link_caps.rates = rates;
+	link_caps.dsc = true;
+	link_caps.v_swings = DRM_DP_VOLTAGE_SWING_LEVEL_MASK;
+	link_caps.pre_emphs = DRM_DP_PRE_EMPH_LEVEL_MASK;
+
+	drmm_connector_dp_init(dev, &connector->base, &intel_dp_connector_funcs,
+			       &link_caps, type, &intel_dp->aux.ddc);
+	kfree(rates);
+
 	drm_connector_helper_add(&connector->base, &intel_dp_connector_helper_funcs);
 
 	if (drmm_add_action_or_reset(dev, intel_connector_destroy, connector)) {
@@ -7240,7 +7264,6 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
 	if (!intel_edp_init_connector(intel_dp, connector))
 		goto fail;
 
-	intel_dp_set_source_rates(intel_dp);
 	intel_dp_set_common_rates(intel_dp);
 	intel_dp_reset_link_params(intel_dp);
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 54c585c59b900..c2fd46a323650 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -25,6 +25,7 @@
 #include <linux/iopoll.h>
 
 #include <drm/display/drm_dp_helper.h>
+#include <drm/drm_dp_connector.h>
 #include <drm/drm_print.h>
 
 #include "intel_display_core.h"
@@ -1116,6 +1117,27 @@ intel_dp_128b132b_intra_hop(struct intel_dp *intel_dp,
 	return sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION ? 1 : 0;
 }
 
+static void intel_dp_report_link_train(struct intel_dp *intel_dp)
+{
+	struct intel_connector *connector = intel_dp->attached_connector;
+	struct drm_connector_dp_link_train dp_link_train;
+
+	dp_link_train.rate = intel_dp->link_rate;
+	dp_link_train.nlanes = intel_dp->lane_count;
+	dp_link_train.dsc_en = connector->dp.dsc_decompression_enabled;
+
+	for (int i = 0; i < intel_dp->lane_count; i++) {
+		int v_swing_level = (intel_dp->train_set[i] &
+				     DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT;
+		int pre_emph_level = (intel_dp->train_set[i] &
+				      DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
+		dp_link_train.v_swing[i] = 1 << v_swing_level;
+		dp_link_train.pre_emph[i] = 1 << pre_emph_level;
+	}
+
+	drm_connector_dp_set_link_train_properties(&connector->base, &dp_link_train);
+}
+
 /**
  * intel_dp_stop_link_train - stop link training
  * @intel_dp: DP struct
@@ -1144,6 +1166,9 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp,
 	intel_dp_program_link_training_pattern(intel_dp, crtc_state, DP_PHY_DPRX,
 					       DP_TRAINING_PATTERN_DISABLE);
 
+	if (!intel_dp->is_mst)
+		intel_dp_report_link_train(intel_dp);
+
 	if (intel_dp_is_uhbr(crtc_state)) {
 		ret = poll_timeout_us(ret = intel_dp_128b132b_intra_hop(intel_dp, crtc_state),
 				      ret == 0,

-- 
2.43.0



^ permalink raw reply related

* [PATCH RFC 09/12] drm: Introduce drmm_connector_dp_init() with link training state properties
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
  To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
	David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
	Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
	Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
  Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
	intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
	linux-arm-kernel, Simona Vetter, Kory Maincent
In-Reply-To: <20260409-feat_link_cap-v1-0-7069e8199ce2@bootlin.com>

Add a managed DisplayPort connector initialization helper,
drmm_connector_dp_init(), modeled after the existing HDMI counterpart
drmm_connector_hdmi_init(). Cleanup is handled automatically via a
DRM-managed action.

The helper creates the following immutable connector properties to expose
DP link training capabilities and state to userspace:

  - num_lanes: bitmask of supported lane counts (1, 2, 4)
  - link_rate: Array of supported link rates.
  - dsc_en: Display Stream Compression supported
  - voltage_swingN: per-lane voltage swing level bitmask
  - pre-emphasisN: per-lane pre-emphasis level bitmask

Link rates are passed by the driver in deca-kbps, following the DRM
convention, but exposed to userspace in kbps for clarity.

Two additional helpers are provided to update and reset those properties
at runtime:
  - drm_connector_dp_set_link_train_properties()
  - drm_connector_dp_reset_link_train_properties()

Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
 drivers/gpu/drm/Makefile           |   1 +
 drivers/gpu/drm/drm_dp_connector.c | 344 +++++++++++++++++++++++++++++++++++++
 include/drm/drm_connector.h        |  38 ++++
 include/drm/drm_dp_connector.h     | 109 ++++++++++++
 4 files changed, 492 insertions(+)

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index e97faabcd7830..8ff08c2fb863e 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -42,6 +42,7 @@ drm-y := \
 	drm_color_mgmt.o \
 	drm_colorop.o \
 	drm_connector.o \
+	drm_dp_connector.o \
 	drm_crtc.o \
 	drm_displayid.o \
 	drm_drv.o \
diff --git a/drivers/gpu/drm/drm_dp_connector.c b/drivers/gpu/drm/drm_dp_connector.c
new file mode 100644
index 0000000000000..b25637a4378d5
--- /dev/null
+++ b/drivers/gpu/drm/drm_dp_connector.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Google
+ * Author: Kory Maincent <kory.maincent@bootlin.com>
+ */
+#include <drm/drm_dp_connector.h>
+#include <drm/drm_print.h>
+#include <linux/list.h>
+
+/**
+ * drm_connector_dp_link_reset_properties() - Reset DisplayPort link configuration
+ * @connector: DRM connector
+ * @dp_link: Link training informations
+ *
+ * Returns: Zero on success, or an errno code otherwise.
+ */
+int
+drm_connector_dp_set_link_train_properties(struct drm_connector *connector,
+					   const struct drm_connector_dp_link_train *dp_link_train)
+{
+	u32 lrate = 0;
+	int ret;
+
+	if (!connector)
+		return -ENODEV;
+
+	if (dp_link_train->nlanes && !is_power_of_2(dp_link_train->nlanes & DRM_NLANES_MASK)) {
+		drm_err(connector->dev, "Wrong lane number");
+		return -EINVAL;
+	}
+
+	if (dp_link_train->rate) {
+		struct drm_property_enum *prop_enum;
+		bool found = false;
+
+		list_for_each_entry(prop_enum, &connector->dp.link_rate_property->enum_list, head) {
+			u32 parsed_rate;
+
+			/* Convert dp_link_train->rate from deca-kbps to kbps */
+			if (!kstrtou32(prop_enum->name, 10, &parsed_rate) &&
+			    dp_link_train->rate * 10 == parsed_rate) {
+				lrate = 1 << prop_enum->value;
+				found = true;
+				break;
+			}
+		}
+
+		if (!found) {
+			drm_err(connector->dev, "Wrong rate value");
+			return -EINVAL;
+		}
+	}
+
+	ret = drm_object_property_set_value(&connector->base, connector->dp.nlanes_property,
+					    dp_link_train->nlanes);
+	if (ret)
+		return ret;
+
+	ret = drm_object_property_set_value(&connector->base, connector->dp.link_rate_property,
+					    lrate);
+	if (ret)
+		return ret;
+
+	if (connector->dp.dsc_en_property) {
+		ret = drm_object_property_set_value(&connector->base, connector->dp.dsc_en_property,
+						    dp_link_train->dsc_en);
+		if (ret)
+			return ret;
+	}
+
+	for (int i = 0; i < 4; i++) {
+		if (connector->dp.v_swing_property[i]) {
+			ret = drm_object_property_set_value(&connector->base,
+							    connector->dp.v_swing_property[i],
+							    dp_link_train->v_swing[i]);
+			if (ret)
+				return ret;
+		}
+
+		if (connector->dp.pre_emph_property[i]) {
+			ret = drm_object_property_set_value(&connector->base,
+							    connector->dp.pre_emph_property[i],
+							    dp_link_train->pre_emph[i]);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_connector_dp_set_link_train_properties);
+
+/**
+ * drm_connector_dp_link_reset_properties() - Reset DisplayPort link configuration
+ * @connector: DRM connector
+ */
+void drm_connector_dp_reset_link_train_properties(struct drm_connector *connector)
+{
+	struct drm_connector_dp_link_train dp_link_train = {0};
+
+	drm_connector_dp_set_link_train_properties(connector, &dp_link_train);
+}
+EXPORT_SYMBOL(drm_connector_dp_reset_link_train_properties);
+
+static int drm_connector_create_nlanes_prop(struct drm_connector *connector,
+					    u8 sup_nlanes)
+{
+	static const struct drm_prop_enum_list props[] = {
+		{__builtin_ffs(DRM_DP_1LANE) - 1, "1" },
+		{__builtin_ffs(DRM_DP_2LANE) - 1, "2" },
+		{__builtin_ffs(DRM_DP_4LANE) - 1, "4" },
+	};
+	struct drm_property *prop;
+
+	if (drm_WARN_ON(connector->dev, sup_nlanes != (sup_nlanes & DRM_NLANES_MASK)))
+		return -EINVAL;
+
+	prop = drm_property_create_bitmask(connector->dev, DRM_MODE_PROP_IMMUTABLE,
+					   "num_lanes", props, ARRAY_SIZE(props),
+					   sup_nlanes);
+	if (!prop)
+		return -ENOMEM;
+
+	drm_object_attach_property(&connector->base, prop, 0);
+
+	connector->dp.nlanes_property = prop;
+
+	return 0;
+}
+
+static int drm_connector_create_lrate_prop(struct drm_connector *connector,
+					   u32 sup_nlrates,
+					   const u32 *sup_lrates)
+{
+	struct drm_prop_enum_list *props;
+	u32 supp_nlrates_bitmask = 0;
+	struct drm_property *prop;
+	int ret = 0;
+
+	if (!sup_nlrates || !sup_lrates)
+		return 0;
+
+	props = kcalloc(sup_nlrates, sizeof(*props), GFP_KERNEL);
+	if (!props)
+		return -ENOMEM;
+
+	for (int i = 0; i < sup_nlrates; i++) {
+		props[i].type = i;
+		/* Convert deca-kbps to kbps */
+		props[i].name = kasprintf(GFP_KERNEL, "%d", sup_lrates[i] * 10);
+		if (!props[i].name) {
+			while (i--)
+				kfree(props[i].name);
+			kfree(props);
+			return -ENOMEM;
+		}
+		supp_nlrates_bitmask |= 1 << i;
+	}
+
+	prop = drm_property_create_bitmask(connector->dev, DRM_MODE_PROP_IMMUTABLE,
+					   "link_rate", props, sup_nlrates,
+					   supp_nlrates_bitmask);
+	if (!prop) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	drm_object_attach_property(&connector->base, prop, 0);
+
+	connector->dp.link_rate_property = prop;
+
+out:
+	for (int i = 0; i < sup_nlrates; i++)
+		kfree(props[i].name);
+
+	kfree(props);
+	return ret;
+}
+
+static int drm_connector_create_dsc_prop(struct drm_connector *connector)
+{
+	struct drm_property *prop;
+
+	prop = drm_property_create_bool(connector->dev, DRM_MODE_PROP_IMMUTABLE, "dsc_en");
+	if (!prop)
+		return -ENOMEM;
+
+	drm_object_attach_property(&connector->base, prop, 0);
+
+	connector->dp.dsc_en_property = prop;
+
+	return 0;
+}
+
+static int drm_connector_create_vswing_prop(struct drm_connector *connector,
+					    u8 sup_v_swings, int id)
+{
+	static const struct drm_prop_enum_list props[] = {
+		{__builtin_ffs(DRM_DP_VOLTAGE_SWING_LEVEL_0) - 1, "level_0" },
+		{__builtin_ffs(DRM_DP_VOLTAGE_SWING_LEVEL_1) - 1, "level_1" },
+		{__builtin_ffs(DRM_DP_VOLTAGE_SWING_LEVEL_2) - 1, "level_2" },
+		{__builtin_ffs(DRM_DP_VOLTAGE_SWING_LEVEL_3) - 1, "level_3" },
+	};
+	struct drm_property *prop;
+	char str[16];
+
+	if (!sup_v_swings)
+		return 0;
+
+	if (drm_WARN_ON(connector->dev, sup_v_swings != (sup_v_swings &
+						   DRM_DP_VOLTAGE_SWING_LEVEL_MASK)))
+		return -EINVAL;
+
+	snprintf(str, sizeof(str), "voltage_swing%d", id);
+	prop = drm_property_create_bitmask(connector->dev, DRM_MODE_PROP_IMMUTABLE,
+					   str, props, ARRAY_SIZE(props),
+					   sup_v_swings);
+	if (!prop)
+		return -ENOMEM;
+
+	drm_object_attach_property(&connector->base, prop, 0);
+
+	connector->dp.v_swing_property[id] = prop;
+
+	return 0;
+}
+
+static int drm_connector_create_pre_emph_prop(struct drm_connector *connector,
+					      u8 sup_pre_emph, int id)
+{
+	static const struct drm_prop_enum_list props[] = {
+		{__builtin_ffs(DRM_DP_PRE_EMPH_LEVEL_0) - 1, "level_0" },
+		{__builtin_ffs(DRM_DP_PRE_EMPH_LEVEL_1) - 1, "level_1" },
+		{__builtin_ffs(DRM_DP_PRE_EMPH_LEVEL_2) - 1, "level_2" },
+		{__builtin_ffs(DRM_DP_PRE_EMPH_LEVEL_3) - 1, "level_3" },
+	};
+	struct drm_property *prop;
+	char str[16];
+
+	if (!sup_pre_emph)
+		return 0;
+
+	if (drm_WARN_ON(connector->dev, sup_pre_emph != (sup_pre_emph &
+						   DRM_DP_PRE_EMPH_LEVEL_MASK)))
+		return -EINVAL;
+
+	snprintf(str, sizeof(str), "pre_emphasis%d", id);
+	prop = drm_property_create_bitmask(connector->dev, DRM_MODE_PROP_IMMUTABLE,
+					   str, props, ARRAY_SIZE(props),
+					   sup_pre_emph);
+	if (!prop)
+		return -ENOMEM;
+
+	drm_object_attach_property(&connector->base, prop, 0);
+
+	connector->dp.pre_emph_property[id] = prop;
+
+	return 0;
+}
+
+static int
+drm_connector_dp_create_props(struct drm_connector *connector,
+			      const struct drm_connector_dp_link_train_caps *dp_link_train_caps)
+{
+	u8 nlanes;
+	int ret;
+
+	ret = drm_connector_create_nlanes_prop(connector, dp_link_train_caps->nlanes);
+	if (ret)
+		return ret;
+
+	ret = drm_connector_create_lrate_prop(connector, dp_link_train_caps->nrates,
+					      dp_link_train_caps->rates);
+	if (ret)
+		return ret;
+
+	if (dp_link_train_caps->dsc) {
+		ret = drm_connector_create_dsc_prop(connector);
+		if (ret)
+			return ret;
+	}
+
+	nlanes = 1 << (fls(dp_link_train_caps->nlanes) - 1);
+	for (int i = 0; i < nlanes; i++) {
+		ret = drm_connector_create_vswing_prop(connector,
+						       dp_link_train_caps->v_swings, i);
+		if (ret)
+			return ret;
+
+		ret = drm_connector_create_pre_emph_prop(connector,
+							 dp_link_train_caps->pre_emphs, i);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * drmm_connector_dp_init - Init a preallocated DisplayPort connector
+ * @dev: DRM device
+ * @connector: A pointer to the DisplayPort connector to init
+ * @funcs: callbacks for this connector
+ * @dp_link_train_caps: DisplayPort link training capabilities. The pointer
+ *			is not kept by the DRM core
+ * @connector_type: user visible type of the connector
+ * @ddc: optional pointer to the associated ddc adapter
+ *
+ * Initialises a preallocated DisplayPort connector. Connectors can be
+ * subclassed as part of driver connector objects.
+ *
+ * Cleanup is automatically handled with a call to
+ * drm_connector_cleanup() in a DRM-managed action.
+ *
+ * The connector structure should be allocated with drmm_kzalloc().
+ *
+ * The @drm_connector_funcs.destroy hook must be NULL.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drmm_connector_dp_init(struct drm_device *dev,
+			   struct drm_connector *connector,
+			   const struct drm_connector_funcs *funcs,
+			   const struct drm_connector_dp_link_train_caps *dp_link_train_caps,
+			   int connector_type,
+			   struct i2c_adapter *ddc)
+{
+	int ret;
+
+	if (!(connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
+	      connector_type == DRM_MODE_CONNECTOR_eDP))
+		return -EINVAL;
+
+	if (!dp_link_train_caps)
+		return -EINVAL;
+
+	ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
+	if (ret)
+		return ret;
+
+	return drm_connector_dp_create_props(connector, dp_link_train_caps);
+}
+EXPORT_SYMBOL(drmm_connector_dp_init);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index f83f28cae2075..df3a71fed35b1 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1987,6 +1987,39 @@ struct drm_connector_cec {
 	void *data;
 };
 
+/**
+ * struct drm_connector_dp - DRM Connector DisplayPort-related structure
+ */
+struct drm_connector_dp {
+	/**
+	 * @nlanes_property: Connector property to report the number of lanes
+	 */
+	struct drm_property *nlanes_property;
+
+	/**
+	 * @link_rate_property: Connector property to report the link rate
+	 */
+	struct drm_property *link_rate_property;
+
+	/**
+	 * @dsc_en_property: Connector property to report the Display Stream
+	 * Compression supporrt
+	 */
+	struct drm_property *dsc_en_property;
+
+	/**
+	 * @v_swing_property: Connector property to report the voltage
+	 * swing per lane
+	 */
+	struct drm_property *v_swing_property[4];
+
+	/**
+	 * @pre_emph_property: Connector property to report the
+	 * pre-emphasis per lane
+	 */
+	struct drm_property *pre_emph_property[4];
+};
+
 /**
  * struct drm_connector - central DRM connector control structure
  *
@@ -2410,6 +2443,11 @@ struct drm_connector {
 	 * @cec: CEC-related data.
 	 */
 	struct drm_connector_cec cec;
+
+	/**
+	 * @dp: DisplayPort-related variable and properties.
+	 */
+	struct drm_connector_dp dp;
 };
 
 #define obj_to_connector(x) container_of(x, struct drm_connector, base)
diff --git a/include/drm/drm_dp_connector.h b/include/drm/drm_dp_connector.h
new file mode 100644
index 0000000000000..77d2f4bb6df68
--- /dev/null
+++ b/include/drm/drm_dp_connector.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef DRM_DP_CONNECTOR_H_
+#define DRM_DP_CONNECTOR_H_
+
+#include <drm/drm_connector.h>
+
+#define DRM_DP_1LANE	BIT(0)
+#define DRM_DP_2LANE	BIT(1)
+#define DRM_DP_4LANE	BIT(2)
+#define DRM_NLANES_MASK (DRM_DP_1LANE | DRM_DP_2LANE | DRM_DP_4LANE)
+#define DRM_DP_VOLTAGE_SWING_LEVEL_0 BIT(0)
+#define DRM_DP_VOLTAGE_SWING_LEVEL_1 BIT(1)
+#define DRM_DP_VOLTAGE_SWING_LEVEL_2 BIT(2)
+#define DRM_DP_VOLTAGE_SWING_LEVEL_3 BIT(3)
+#define DRM_DP_VOLTAGE_SWING_LEVEL_MASK (DRM_DP_VOLTAGE_SWING_LEVEL_0 | \
+					 DRM_DP_VOLTAGE_SWING_LEVEL_1 | \
+					 DRM_DP_VOLTAGE_SWING_LEVEL_2 | \
+					 DRM_DP_VOLTAGE_SWING_LEVEL_3)
+#define DRM_DP_PRE_EMPH_LEVEL_0 BIT(0)
+#define DRM_DP_PRE_EMPH_LEVEL_1 BIT(1)
+#define DRM_DP_PRE_EMPH_LEVEL_2 BIT(2)
+#define DRM_DP_PRE_EMPH_LEVEL_3 BIT(3)
+#define DRM_DP_PRE_EMPH_LEVEL_MASK (DRM_DP_PRE_EMPH_LEVEL_0 | \
+				    DRM_DP_PRE_EMPH_LEVEL_1 | \
+				    DRM_DP_PRE_EMPH_LEVEL_2 | \
+				    DRM_DP_PRE_EMPH_LEVEL_3)
+
+/**
+ * struct drm_connector_dp_link_train_caps - DRM DisplayPort link training
+ * capabilities
+ */
+struct drm_connector_dp_link_train_caps {
+	/**
+	 * @nlanes: Bitmask of lanes number supported
+	 */
+	u8 nlanes;
+
+	/**
+	 * @nrates: Number of link rates supported
+	 */
+	u32 nrates;
+
+	/**
+	 * @rates: Array listing the supported link rates in deca-kbps
+	 */
+	const u32 *rates;
+
+	/**
+	 * @dsc: Display Stream Compression supported
+	 */
+	bool dsc;
+
+	/**
+	 * @v_swings: Bitmask of voltage swing level supported
+	 */
+	u8 v_swings;
+
+	/**
+	 * @pre_emphs: Bitmask of pre-emphasis level supported
+	 */
+	u8 pre_emphs;
+};
+
+/**
+ * struct drm_connector_dp_link_train - DRM DisplayPort link training
+ * information report
+ */
+struct drm_connector_dp_link_train {
+	/**
+	 * @nlanes: The number of lanes used
+	 */
+	u8 nlanes;
+
+	/**
+	 * @rates: Link rate value selected in deca-kbps
+	 */
+	u32 rate;
+
+	/**
+	 * @dsc: Display Stream Compression enabled
+	 */
+	bool dsc_en;
+
+	/**
+	 * @v_swings: Array listing the bitmask voltage swing level per lanes
+	 */
+	u8 v_swing[4];
+
+	/**
+	 * @pre_emph: Array listing the bitmask pre-emphasis level per lanes
+	 */
+	u8 pre_emph[4];
+};
+
+int drmm_connector_dp_init(struct drm_device *dev,
+			   struct drm_connector *connector,
+			   const struct drm_connector_funcs *funcs,
+			   const struct drm_connector_dp_link_train_caps *dp_link_train_caps,
+			   int connector_type,
+			   struct i2c_adapter *ddc);
+
+int
+drm_connector_dp_set_link_train_properties(struct drm_connector *con,
+					   const struct drm_connector_dp_link_train *dp_link_train);
+
+void drm_connector_dp_reset_link_train_properties(struct drm_connector *connector);
+
+#endif // DRM_DP_CONNECTOR_H_

-- 
2.43.0



^ permalink raw reply related

* [PATCH RFC 08/12] drm/i915/display: Switch to managed for connector
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
  To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
	David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
	Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
	Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
  Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
	intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
	linux-arm-kernel, Simona Vetter, Kory Maincent
In-Reply-To: <20260409-feat_link_cap-v1-0-7069e8199ce2@bootlin.com>

The current i915 driver uses non-managed function to create connector. It
is not an issue yet, but in order to comply with the latest DRM
requirement, convert this code to use drm and device managed helpers.

Assisted-by: Claude Code:2.1.90
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
 drivers/gpu/drm/i915/display/g4x_dp.c          | 14 ++---
 drivers/gpu/drm/i915/display/g4x_hdmi.c        | 10 ++--
 drivers/gpu/drm/i915/display/icl_dsi.c         | 30 +++++------
 drivers/gpu/drm/i915/display/intel_connector.c | 26 ++++++---
 drivers/gpu/drm/i915/display/intel_connector.h |  5 +-
 drivers/gpu/drm/i915/display/intel_crt.c       | 19 +++----
 drivers/gpu/drm/i915/display/intel_ddi.c       | 14 +++--
 drivers/gpu/drm/i915/display/intel_dp.c        | 12 +++--
 drivers/gpu/drm/i915/display/intel_dp_mst.c    | 13 ++++-
 drivers/gpu/drm/i915/display/intel_dvo.c       | 21 ++++----
 drivers/gpu/drm/i915/display/intel_hdmi.c      | 15 ++++--
 drivers/gpu/drm/i915/display/intel_lvds.c      | 18 ++++---
 drivers/gpu/drm/i915/display/intel_sdvo.c      | 73 +++++++++-----------------
 drivers/gpu/drm/i915/display/intel_tv.c        | 15 +++---
 drivers/gpu/drm/i915/display/vlv_dsi.c         | 20 ++++---
 15 files changed, 153 insertions(+), 152 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c
index 99b6c5ce39b2a..e7c3d72d223ee 100644
--- a/drivers/gpu/drm/i915/display/g4x_dp.c
+++ b/drivers/gpu/drm/i915/display/g4x_dp.c
@@ -1299,7 +1299,7 @@ bool g4x_dp_init(struct intel_display *display,
 	if (!dig_port)
 		return false;
 
-	intel_connector = intel_connector_alloc();
+	intel_connector = intel_connector_alloc(display->drm);
 	if (!intel_connector)
 		return false;
 
@@ -1311,11 +1311,11 @@ bool g4x_dp_init(struct intel_display *display,
 	if (drmm_encoder_init(display->drm, &intel_encoder->base,
 			      &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS,
 			      "DP %c", port_name(port)))
-		goto err_encoder_init;
+		return false;
 
 	if (drmm_add_action_or_reset(display->drm,
 				     intel_dp_encoder_flush_work_cleanup, encoder))
-		goto err_encoder_init;
+		return false;
 
 	intel_encoder_link_check_init(intel_encoder, intel_dp_link_check);
 
@@ -1412,14 +1412,10 @@ bool g4x_dp_init(struct intel_display *display,
 
 	dig_port->aux_ch = intel_dp_aux_ch(intel_encoder);
 	if (dig_port->aux_ch == AUX_CH_NONE)
-		goto err_encoder_init;
+		return false;
 
 	if (!intel_dp_init_connector(dig_port, intel_connector))
-		goto err_encoder_init;
+		return false;
 
 	return true;
-
-err_encoder_init:
-	kfree(intel_connector);
-	return false;
 }
diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c
index 45ee1ad504bc1..ab964194e63d0 100644
--- a/drivers/gpu/drm/i915/display/g4x_hdmi.c
+++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c
@@ -690,7 +690,7 @@ bool g4x_hdmi_init(struct intel_display *display,
 	if (!dig_port)
 		return false;
 
-	intel_connector = intel_connector_alloc();
+	intel_connector = intel_connector_alloc(display->drm);
 	if (!intel_connector)
 		return false;
 
@@ -701,7 +701,7 @@ bool g4x_hdmi_init(struct intel_display *display,
 	if (drmm_encoder_init(display->drm, &intel_encoder->base,
 			      &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
 			      "HDMI %c", port_name(port)))
-		goto err_encoder_init;
+		return false;
 
 	intel_encoder->hotplug = intel_hdmi_hotplug;
 	intel_encoder->compute_config = g4x_hdmi_compute_config;
@@ -763,11 +763,7 @@ bool g4x_hdmi_init(struct intel_display *display,
 	intel_infoframe_init(dig_port);
 
 	if (!intel_hdmi_init_connector(dig_port, intel_connector))
-		goto err_encoder_init;
+		return false;
 
 	return true;
-err_encoder_init:
-	kfree(intel_connector);
-
-	return false;
 }
diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
index cfee173a2367a..3d7372f473d95 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi.c
+++ b/drivers/gpu/drm/i915/display/icl_dsi.c
@@ -1783,7 +1783,6 @@ static const struct drm_connector_funcs gen11_dsi_connector_funcs = {
 	.detect = intel_panel_detect,
 	.late_register = intel_connector_register,
 	.early_unregister = intel_connector_unregister,
-	.destroy = intel_connector_destroy,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.atomic_get_property = intel_digital_connector_atomic_get_property,
 	.atomic_set_property = intel_digital_connector_atomic_set_property,
@@ -1935,11 +1934,9 @@ void icl_dsi_init(struct intel_display *display,
 	if (IS_ERR(intel_dsi))
 		return;
 
-	intel_connector = intel_connector_alloc();
-	if (!intel_connector) {
-		kfree(intel_dsi);
+	intel_connector = intel_connector_alloc(display->drm);
+	if (!intel_connector)
 		return;
-	}
 
 	encoder = &intel_dsi->base;
 	intel_dsi->attached_connector = intel_connector;
@@ -1969,10 +1966,16 @@ void icl_dsi_init(struct intel_display *display,
 	encoder->shutdown = intel_dsi_shutdown;
 
 	/* register DSI connector with DRM subsystem */
-	drm_connector_init(display->drm, connector,
-			   &gen11_dsi_connector_funcs,
-			   DRM_MODE_CONNECTOR_DSI);
+	drmm_connector_init(display->drm, connector,
+			    &gen11_dsi_connector_funcs,
+			    DRM_MODE_CONNECTOR_DSI, NULL);
 	drm_connector_helper_add(connector, &gen11_dsi_connector_helper_funcs);
+
+	if (drmm_add_action_or_reset(display->drm, intel_connector_destroy, intel_connector)) {
+		drm_err(display->drm, "Failed to register intel_connector_destroy clean-up.\n");
+		return;
+	}
+
 	connector->display_info.subpixel_order = SubPixelHorizontalRGB;
 	intel_connector->get_hw_state = intel_connector_get_hw_state;
 
@@ -1989,7 +1992,7 @@ void icl_dsi_init(struct intel_display *display,
 
 	if (!intel_panel_preferred_fixed_mode(intel_connector)) {
 		drm_err(display->drm, "DSI fixed mode info missing\n");
-		goto err;
+		return;
 	}
 
 	intel_panel_init(intel_connector, NULL);
@@ -2012,22 +2015,17 @@ void icl_dsi_init(struct intel_display *display,
 
 		host = intel_dsi_host_init(intel_dsi, &gen11_dsi_host_ops, port);
 		if (!host)
-			goto err;
+			return;
 
 		intel_dsi->dsi_hosts[port] = host;
 	}
 
 	if (!intel_dsi_vbt_init(intel_dsi, MIPI_DSI_GENERIC_PANEL_ID)) {
 		drm_dbg_kms(display->drm, "no device found\n");
-		goto err;
+		return;
 	}
 
 	icl_dphy_param_init(intel_dsi);
 
 	icl_dsi_add_properties(intel_connector);
-	return;
-
-err:
-	drm_connector_cleanup(connector);
-	kfree(intel_connector);
 }
diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c
index 7ef9338d67abf..6fb64c6f4c9e4 100644
--- a/drivers/gpu/drm/i915/display/intel_connector.c
+++ b/drivers/gpu/drm/i915/display/intel_connector.c
@@ -28,6 +28,7 @@
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 
@@ -101,7 +102,21 @@ static int intel_connector_init(struct intel_connector *connector)
 	return 0;
 }
 
-struct intel_connector *intel_connector_alloc(void)
+struct intel_connector *intel_connector_alloc(struct drm_device *dev)
+{
+	struct intel_connector *connector;
+
+	connector = drmm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
+	if (!connector)
+		return NULL;
+
+	if (intel_connector_init(connector) < 0)
+		return NULL;
+
+	return connector;
+}
+
+struct intel_connector *intel_subconnector_alloc(void)
 {
 	struct intel_connector *connector;
 
@@ -127,15 +142,14 @@ struct intel_connector *intel_connector_alloc(void)
 void intel_connector_free(struct intel_connector *connector)
 {
 	kfree(to_intel_digital_connector_state(connector->base.state));
-	kfree(connector);
 }
 
 /*
  * Connector type independent destroy hook for drm_connector_funcs.
  */
-void intel_connector_destroy(struct drm_connector *connector)
+void intel_connector_destroy(struct drm_device *dev, void *data)
 {
-	struct intel_connector *intel_connector = to_intel_connector(connector);
+	struct intel_connector *intel_connector = (struct intel_connector *)data;
 
 	drm_edid_free(intel_connector->detect_edid);
 
@@ -143,12 +157,8 @@ void intel_connector_destroy(struct drm_connector *connector)
 
 	intel_panel_fini(intel_connector);
 
-	drm_connector_cleanup(connector);
-
 	if (intel_connector->mst.port)
 		drm_dp_mst_put_port_malloc(intel_connector->mst.port);
-
-	kfree(connector);
 }
 
 int intel_connector_register(struct drm_connector *_connector)
diff --git a/drivers/gpu/drm/i915/display/intel_connector.h b/drivers/gpu/drm/i915/display/intel_connector.h
index 0aa86626e6463..6c47ca46c1d18 100644
--- a/drivers/gpu/drm/i915/display/intel_connector.h
+++ b/drivers/gpu/drm/i915/display/intel_connector.h
@@ -14,9 +14,10 @@ struct i2c_adapter;
 struct intel_connector;
 struct intel_encoder;
 
-struct intel_connector *intel_connector_alloc(void);
+struct intel_connector *intel_connector_alloc(struct drm_device *dev);
+struct intel_connector *intel_subconnector_alloc(void);
 void intel_connector_free(struct intel_connector *connector);
-void intel_connector_destroy(struct drm_connector *connector);
+void intel_connector_destroy(struct drm_device *dev, void *data);
 int intel_connector_register(struct drm_connector *connector);
 void intel_connector_unregister(struct drm_connector *connector);
 void intel_connector_attach_encoder(struct intel_connector *connector,
diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
index 39bb115955f5a..8af76d141888b 100644
--- a/drivers/gpu/drm/i915/display/intel_crt.c
+++ b/drivers/gpu/drm/i915/display/intel_crt.c
@@ -992,7 +992,6 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = {
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.late_register = intel_connector_register,
 	.early_unregister = intel_connector_unregister,
-	.destroy = intel_connector_destroy,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 };
@@ -1046,19 +1045,21 @@ void intel_crt_init(struct intel_display *display)
 	if (IS_ERR(crt))
 		return;
 
-	connector = intel_connector_alloc();
-	if (!connector) {
-		kfree(crt);
+	connector = intel_connector_alloc(display->drm);
+	if (!connector)
 		return;
-	}
 
 	ddc_pin = display->vbt.crt_ddc_pin;
 
-	drm_connector_init_with_ddc(display->drm, &connector->base,
-				    &intel_crt_connector_funcs,
-				    DRM_MODE_CONNECTOR_VGA,
-				    intel_gmbus_get_adapter(display, ddc_pin));
+	drmm_connector_init(display->drm, &connector->base,
+			    &intel_crt_connector_funcs,
+			    DRM_MODE_CONNECTOR_VGA,
+			    intel_gmbus_get_adapter(display, ddc_pin));
 
+	if (drmm_add_action_or_reset(display->drm, intel_connector_destroy, connector)) {
+		drm_err(display->drm, "Failed to register intel_connector_destroy clean-up.\n");
+		return;
+	}
 
 	intel_connector_attach_encoder(connector, &crt->base);
 
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 003287ad5bc59..bb87a7361aa92 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -4694,7 +4694,7 @@ static int intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
 	struct intel_connector *connector;
 	enum port port = dig_port->base.port;
 
-	connector = intel_connector_alloc();
+	connector = intel_connector_alloc(display->drm);
 	if (!connector)
 		return -ENOMEM;
 
@@ -4709,10 +4709,8 @@ static int intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
 	dig_port->dp.voltage_max = intel_ddi_dp_voltage_max;
 	dig_port->dp.preemph_max = intel_ddi_dp_preemph_max;
 
-	if (!intel_dp_init_connector(dig_port, connector)) {
-		kfree(connector);
+	if (!intel_dp_init_connector(dig_port, connector))
 		return -EINVAL;
-	}
 
 	if (dig_port->base.type == INTEL_OUTPUT_EDP) {
 		struct drm_privacy_screen *privacy_screen;
@@ -4892,12 +4890,13 @@ static bool bdw_digital_port_connected(struct intel_encoder *encoder)
 	return intel_de_read(display, GEN8_DE_PORT_ISR) & bit;
 }
 
-static int intel_ddi_init_hdmi_connector(struct intel_digital_port *dig_port)
+static int intel_ddi_init_hdmi_connector(struct drm_device *dev,
+					 struct intel_digital_port *dig_port)
 {
 	struct intel_connector *connector;
 	enum port port = dig_port->base.port;
 
-	connector = intel_connector_alloc();
+	connector = intel_connector_alloc(dev);
 	if (!connector)
 		return -ENOMEM;
 
@@ -4910,7 +4909,6 @@ static int intel_ddi_init_hdmi_connector(struct intel_digital_port *dig_port)
 		 * don't fail the entire DDI init.
 		 */
 		dig_port->hdmi.hdmi_reg = INVALID_MMIO_REG;
-		kfree(connector);
 	}
 
 	return 0;
@@ -5499,7 +5497,7 @@ void intel_ddi_init(struct intel_display *display,
 	 * but leave it just in case we have some really bad VBTs...
 	 */
 	if (encoder->type != INTEL_OUTPUT_EDP && init_hdmi) {
-		if (intel_ddi_init_hdmi_connector(dig_port))
+		if (intel_ddi_init_hdmi_connector(display->drm, dig_port))
 			return;
 	}
 }
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 71f206adbebd3..2af64de9c81de 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -47,6 +47,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_fixed.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 
@@ -6810,7 +6811,6 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
 	.atomic_set_property = intel_digital_connector_atomic_set_property,
 	.late_register = intel_dp_connector_register,
 	.early_unregister = intel_dp_connector_unregister,
-	.destroy = intel_connector_destroy,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 	.atomic_duplicate_state = intel_digital_connector_duplicate_state,
 	.oob_hotplug_event = intel_dp_oob_hotplug_event,
@@ -7213,10 +7213,15 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
 		    type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP",
 		    encoder->base.base.id, encoder->base.name);
 
-	drm_connector_init_with_ddc(dev, &connector->base, &intel_dp_connector_funcs,
-				    type, &intel_dp->aux.ddc);
+	drmm_connector_init(dev, &connector->base, &intel_dp_connector_funcs,
+			    type, &intel_dp->aux.ddc);
 	drm_connector_helper_add(&connector->base, &intel_dp_connector_helper_funcs);
 
+	if (drmm_add_action_or_reset(dev, intel_connector_destroy, connector)) {
+		drm_err(dev, "Failed to register intel_connector_destroy clean-up.\n");
+		goto fail;
+	}
+
 	if (!HAS_GMCH(display) && DISPLAY_VER(display) < 12)
 		connector->base.interlace_allowed = true;
 
@@ -7260,7 +7265,6 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
 
 fail:
 	intel_display_power_flush_work(display);
-	drm_connector_cleanup(&connector->base);
 
 	return false;
 }
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 5fe6fbcaf9371..4b0cdb61c33d6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -1438,13 +1438,22 @@ mst_connector_early_unregister(struct drm_connector *_connector)
 	drm_dp_mst_connector_early_unregister(&connector->base, connector->mst.port);
 }
 
+static void mst_connector_destroy(struct drm_connector *connector)
+{
+	struct intel_connector *intel_connector = to_intel_connector(connector);
+
+	intel_connector_destroy(connector->dev, intel_connector);
+	drm_connector_cleanup(connector);
+	kfree(connector);
+}
+
 static const struct drm_connector_funcs mst_connector_funcs = {
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.atomic_get_property = intel_digital_connector_atomic_get_property,
 	.atomic_set_property = intel_digital_connector_atomic_set_property,
 	.late_register = mst_connector_late_register,
 	.early_unregister = mst_connector_early_unregister,
-	.destroy = intel_connector_destroy,
+	.destroy = mst_connector_destroy,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 	.atomic_duplicate_state = intel_digital_connector_duplicate_state,
 };
@@ -1769,7 +1778,7 @@ mst_topology_add_connector(struct drm_dp_mst_topology_mgr *mgr,
 	enum pipe pipe;
 	int ret;
 
-	connector = intel_connector_alloc();
+	connector = intel_subconnector_alloc();
 	if (!connector)
 		return NULL;
 
diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c
index ea2f6426fd77d..1f84cc44598bf 100644
--- a/drivers/gpu/drm/i915/display/intel_dvo.c
+++ b/drivers/gpu/drm/i915/display/intel_dvo.c
@@ -362,7 +362,6 @@ static const struct drm_connector_funcs intel_dvo_connector_funcs = {
 	.detect = intel_dvo_detect,
 	.late_register = intel_connector_register,
 	.early_unregister = intel_connector_unregister,
-	.destroy = intel_connector_destroy,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -496,11 +495,9 @@ void intel_dvo_init(struct intel_display *display)
 	if (!intel_dvo)
 		return;
 
-	connector = intel_connector_alloc();
-	if (!connector) {
-		kfree(intel_dvo);
+	connector = intel_connector_alloc(display->drm);
+	if (!connector)
 		return;
-	}
 
 	intel_dvo->attached_connector = connector;
 
@@ -547,13 +544,19 @@ void intel_dvo_init(struct intel_display *display)
 			DRM_CONNECTOR_POLL_DISCONNECT;
 	connector->base.polled = connector->polled;
 
-	drm_connector_init_with_ddc(display->drm, &connector->base,
-				    &intel_dvo_connector_funcs,
-				    intel_dvo_connector_type(&intel_dvo->dev),
-				    intel_gmbus_get_adapter(display, GMBUS_PIN_DPC));
+	drmm_connector_init(display->drm, &connector->base,
+			    &intel_dvo_connector_funcs,
+			    intel_dvo_connector_type(&intel_dvo->dev),
+			    intel_gmbus_get_adapter(display, GMBUS_PIN_DPC));
 
 	drm_connector_helper_add(&connector->base,
 				 &intel_dvo_connector_helper_funcs);
+
+	if (drmm_add_action_or_reset(display->drm, intel_connector_destroy, connector)) {
+		drm_err(display->drm, "Failed to register intel_connector_destroy clean-up.\n");
+		return;
+	}
+
 	connector->base.display_info.subpixel_order = SubPixelHorizontalRGB;
 
 	intel_connector_attach_encoder(connector, encoder);
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 05e898d10a2be..f744bae14eaf2 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -39,6 +39,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/intel/intel_lpe_audio.h>
@@ -2650,7 +2651,6 @@ static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
 	.atomic_set_property = intel_digital_connector_atomic_set_property,
 	.late_register = intel_hdmi_connector_register,
 	.early_unregister = intel_hdmi_connector_unregister,
-	.destroy = intel_connector_destroy,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 	.atomic_duplicate_state = intel_digital_connector_duplicate_state,
 };
@@ -3083,13 +3083,18 @@ bool intel_hdmi_init_connector(struct intel_digital_port *dig_port,
 	if (!ddc_pin)
 		return false;
 
-	drm_connector_init_with_ddc(dev, connector,
-				    &intel_hdmi_connector_funcs,
-				    DRM_MODE_CONNECTOR_HDMIA,
-				    intel_gmbus_get_adapter(display, ddc_pin));
+	drmm_connector_init(dev, connector,
+			    &intel_hdmi_connector_funcs,
+			    DRM_MODE_CONNECTOR_HDMIA,
+			    intel_gmbus_get_adapter(display, ddc_pin));
 
 	drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
 
+	if (drmm_add_action_or_reset(display->drm, intel_connector_destroy, intel_connector)) {
+		drm_err(dev, "Failed to register intel_connector_destroy clean-up.\n");
+		return false;
+	}
+
 	if (DISPLAY_VER(display) < 12)
 		connector->interlace_allowed = true;
 
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index 7bb99eb44a5a4..567eda1720261 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -512,7 +512,6 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = {
 	.atomic_set_property = intel_digital_connector_atomic_set_property,
 	.late_register = intel_connector_register,
 	.early_unregister = intel_connector_unregister,
-	.destroy = intel_connector_destroy,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 	.atomic_duplicate_state = intel_digital_connector_duplicate_state,
 };
@@ -891,18 +890,23 @@ void intel_lvds_init(struct intel_display *display)
 	if (IS_ERR(lvds_encoder))
 		return;
 
-	connector = intel_connector_alloc();
+	encoder = &lvds_encoder->base;
+
+	connector = intel_connector_alloc(display->drm);
 	if (!connector)
 		return;
 
 	lvds_encoder->attached_connector = connector;
-	encoder = &lvds_encoder->base;
 
-	drm_connector_init_with_ddc(display->drm, &connector->base,
-				    &intel_lvds_connector_funcs,
-				    DRM_MODE_CONNECTOR_LVDS,
-				    intel_gmbus_get_adapter(display, ddc_pin));
+	drmm_connector_init(display->drm, &connector->base,
+			    &intel_lvds_connector_funcs,
+			    DRM_MODE_CONNECTOR_LVDS,
+			    intel_gmbus_get_adapter(display, ddc_pin));
 
+	if (drmm_add_action_or_reset(display->drm, intel_connector_destroy, connector)) {
+		drm_err(display->drm, "Failed to register intel_connector_destroy clean-up.\n");
+		return;
+	}
 
 	encoder->enable = intel_enable_lvds;
 	encoder->pre_enable = intel_pre_enable_lvds;
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index f5aaa38002674..af3a250f637e1 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -2507,7 +2507,6 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
 	.atomic_set_property = intel_sdvo_connector_atomic_set_property,
 	.late_register = intel_connector_register,
 	.early_unregister = intel_connector_unregister,
-	.destroy = intel_connector_destroy,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 	.atomic_duplicate_state = intel_sdvo_connector_duplicate_state,
 };
@@ -2730,17 +2729,23 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
 	if (HAS_DDC(connector))
 		ddc = intel_sdvo_select_ddc_bus(encoder, connector);
 
-	ret = drm_connector_init_with_ddc(encoder->base.base.dev,
-					  &connector->base.base,
-					  &intel_sdvo_connector_funcs,
-					  connector->base.base.connector_type,
-					  ddc ? &ddc->ddc : NULL);
+	ret = drmm_connector_init(encoder->base.base.dev,
+				  &connector->base.base,
+				  &intel_sdvo_connector_funcs,
+				  connector->base.base.connector_type,
+				  ddc ? &ddc->ddc : NULL);
 	if (ret < 0)
 		return ret;
 
 	drm_connector_helper_add(&connector->base.base,
 				 &intel_sdvo_connector_helper_funcs);
 
+	ret = drmm_add_action_or_reset(display->drm, intel_connector_destroy, &connector->base);
+	if (ret) {
+		drm_err(display->drm, "Failed to register intel_connector_destroy clean-up.\n");
+		return ret;
+	}
+
 	connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
 	connector->base.base.interlace_allowed = true;
 	connector->base.get_hw_state = intel_sdvo_connector_get_hw_state;
@@ -2765,20 +2770,18 @@ intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo,
 	intel_attach_aspect_ratio_property(&connector->base.base);
 }
 
-static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void)
+static struct intel_sdvo_connector *intel_sdvo_connector_alloc(struct drm_device *dev)
 {
 	struct intel_sdvo_connector *sdvo_connector;
 	struct intel_sdvo_connector_state *conn_state;
 
-	sdvo_connector = kzalloc_obj(*sdvo_connector);
+	sdvo_connector = drmm_kzalloc(dev, sizeof(*sdvo_connector), GFP_KERNEL);
 	if (!sdvo_connector)
 		return NULL;
 
 	conn_state = kzalloc_obj(*conn_state);
-	if (!conn_state) {
-		kfree(sdvo_connector);
+	if (!conn_state)
 		return NULL;
-	}
 
 	__drm_atomic_helper_connector_reset(&sdvo_connector->base.base,
 					    &conn_state->base.base);
@@ -2800,7 +2803,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type)
 
 	drm_dbg_kms(display->drm, "initialising DVI type 0x%x\n", type);
 
-	intel_sdvo_connector = intel_sdvo_connector_alloc();
+	intel_sdvo_connector = intel_sdvo_connector_alloc(display->drm);
 	if (!intel_sdvo_connector)
 		return false;
 
@@ -2830,10 +2833,8 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type)
 		intel_sdvo_connector->is_hdmi = true;
 	}
 
-	if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
-		kfree(intel_sdvo_connector);
+	if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0)
 		return false;
-	}
 
 	if (intel_sdvo_connector->is_hdmi)
 		intel_sdvo_add_hdmi_properties(intel_sdvo, intel_sdvo_connector);
@@ -2852,7 +2853,7 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, u16 type)
 
 	drm_dbg_kms(display->drm, "initialising TV type 0x%x\n", type);
 
-	intel_sdvo_connector = intel_sdvo_connector_alloc();
+	intel_sdvo_connector = intel_sdvo_connector_alloc(display->drm);
 	if (!intel_sdvo_connector)
 		return false;
 
@@ -2863,10 +2864,8 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, u16 type)
 
 	intel_sdvo_connector->output_flag = type;
 
-	if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
-		kfree(intel_sdvo_connector);
+	if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0)
 		return false;
-	}
 
 	if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
 		return false;
@@ -2888,7 +2887,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, u16 type)
 
 	drm_dbg_kms(display->drm, "initialising analog type 0x%x\n", type);
 
-	intel_sdvo_connector = intel_sdvo_connector_alloc();
+	intel_sdvo_connector = intel_sdvo_connector_alloc(display->drm);
 	if (!intel_sdvo_connector)
 		return false;
 
@@ -2901,10 +2900,8 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, u16 type)
 
 	intel_sdvo_connector->output_flag = type;
 
-	if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
-		kfree(intel_sdvo_connector);
+	if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0)
 		return false;
-	}
 
 	return true;
 }
@@ -2920,7 +2917,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
 
 	drm_dbg_kms(display->drm, "initialising LVDS type 0x%x\n", type);
 
-	intel_sdvo_connector = intel_sdvo_connector_alloc();
+	intel_sdvo_connector = intel_sdvo_connector_alloc(display->drm);
 	if (!intel_sdvo_connector)
 		return false;
 
@@ -2931,10 +2928,8 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
 
 	intel_sdvo_connector->output_flag = type;
 
-	if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
-		kfree(intel_sdvo_connector);
+	if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0)
 		return false;
-	}
 
 	if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
 		return false;
@@ -3038,19 +3033,6 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo)
 	return true;
 }
 
-static void intel_sdvo_output_cleanup(struct intel_sdvo *intel_sdvo)
-{
-	struct intel_display *display = to_intel_display(&intel_sdvo->base);
-	struct drm_connector *connector, *tmp;
-
-	list_for_each_entry_safe(connector, tmp,
-				 &display->drm->mode_config.connector_list, head) {
-		if (intel_attached_encoder(to_intel_connector(connector)) == &intel_sdvo->base) {
-			drm_connector_unregister(connector);
-			intel_connector_destroy(connector);
-		}
-	}
-}
 
 static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
 					  struct intel_sdvo_connector *intel_sdvo_connector,
@@ -3443,7 +3425,7 @@ bool intel_sdvo_init(struct intel_display *display,
 			    "SDVO output failed to setup on %s\n",
 			    SDVO_NAME(intel_sdvo));
 		/* Output_setup can leave behind connectors! */
-		goto err_output;
+		return false;
 	}
 
 	/*
@@ -3469,12 +3451,12 @@ bool intel_sdvo_init(struct intel_display *display,
 
 	/* Set the input timing to the screen. Assume always input 0. */
 	if (!intel_sdvo_set_target_input(intel_sdvo))
-		goto err_output;
+		return false;
 
 	if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,
 						    &intel_sdvo->pixel_clock_min,
 						    &intel_sdvo->pixel_clock_max))
-		goto err_output;
+		return false;
 
 	drm_dbg_kms(display->drm, "%s device VID/DID: %02X:%02X.%02X, "
 		    "clock range %dMHz - %dMHz, "
@@ -3495,9 +3477,4 @@ bool intel_sdvo_init(struct intel_display *display,
 		    (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1 |
 		     SDVO_OUTPUT_LVDS1) ? 'Y' : 'N');
 	return true;
-
-err_output:
-	intel_sdvo_output_cleanup(intel_sdvo);
-
-	return false;
 }
diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c
index 05df0acc6dc3e..d473d915909e0 100644
--- a/drivers/gpu/drm/i915/display/intel_tv.c
+++ b/drivers/gpu/drm/i915/display/intel_tv.c
@@ -1841,7 +1841,6 @@ intel_tv_get_modes(struct drm_connector *connector)
 static const struct drm_connector_funcs intel_tv_connector_funcs = {
 	.late_register = intel_connector_register,
 	.early_unregister = intel_connector_unregister,
-	.destroy = intel_connector_destroy,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 	.atomic_duplicate_state = intel_tv_connector_duplicate_state,
@@ -1971,11 +1970,9 @@ intel_tv_init(struct intel_display *display)
 	if (IS_ERR(intel_tv))
 		return;
 
-	intel_connector = intel_connector_alloc();
-	if (!intel_connector) {
-		kfree(intel_tv);
+	intel_connector = intel_connector_alloc(display->drm);
+	if (!intel_connector)
 		return;
-	}
 
 	intel_encoder = &intel_tv->base;
 	connector = &intel_connector->base;
@@ -1993,9 +1990,13 @@ intel_tv_init(struct intel_display *display)
 	intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
 	intel_connector->base.polled = intel_connector->polled;
 
-	drm_connector_init(display->drm, connector, &intel_tv_connector_funcs,
-			   DRM_MODE_CONNECTOR_SVIDEO);
+	drmm_connector_init(display->drm, connector, &intel_tv_connector_funcs,
+			    DRM_MODE_CONNECTOR_SVIDEO, NULL);
 
+	if (drmm_add_action_or_reset(display->drm, intel_connector_destroy, intel_connector)) {
+		drm_err(display->drm, "Failed to register intel_connector_destroy clean-up.\n");
+		return;
+	}
 
 	intel_encoder->compute_config = intel_tv_compute_config;
 	intel_encoder->get_config = intel_tv_get_config;
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c
index e84edb6242716..726f4190a8398 100644
--- a/drivers/gpu/drm/i915/display/vlv_dsi.c
+++ b/drivers/gpu/drm/i915/display/vlv_dsi.c
@@ -1560,7 +1560,6 @@ static const struct drm_connector_funcs intel_dsi_connector_funcs = {
 	.detect = intel_panel_detect,
 	.late_register = intel_connector_register,
 	.early_unregister = intel_connector_unregister,
-	.destroy = intel_connector_destroy,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.atomic_get_property = intel_digital_connector_atomic_get_property,
 	.atomic_set_property = intel_digital_connector_atomic_set_property,
@@ -1924,7 +1923,7 @@ void vlv_dsi_init(struct intel_display *display)
 	if (IS_ERR(intel_dsi))
 		return;
 
-	connector = intel_connector_alloc();
+	connector = intel_connector_alloc(display->drm);
 	if (!connector)
 		return;
 
@@ -2011,11 +2010,16 @@ void vlv_dsi_init(struct intel_display *display)
 	intel_dsi_vbt_gpio_init(intel_dsi,
 				intel_dsi_get_hw_state(encoder, &pipe));
 
-	drm_connector_init(display->drm, &connector->base, &intel_dsi_connector_funcs,
-			   DRM_MODE_CONNECTOR_DSI);
+	drmm_connector_init(display->drm, &connector->base, &intel_dsi_connector_funcs,
+			    DRM_MODE_CONNECTOR_DSI, NULL);
 
 	drm_connector_helper_add(&connector->base, &intel_dsi_connector_helper_funcs);
 
+	if (drmm_add_action_or_reset(display->drm, intel_connector_destroy, connector)) {
+		drm_err(display->drm, "Failed to register intel_connector_destroy clean-up.\n");
+		return;
+	}
+
 	connector->base.display_info.subpixel_order = SubPixelHorizontalRGB; /*XXX*/
 
 	intel_connector_attach_encoder(connector, encoder);
@@ -2026,7 +2030,7 @@ void vlv_dsi_init(struct intel_display *display)
 
 	if (!intel_panel_preferred_fixed_mode(connector)) {
 		drm_dbg_kms(display->drm, "no fixed mode\n");
-		goto err_cleanup_connector;
+		return;
 	}
 
 	dmi_id = dmi_first_match(vlv_dsi_dmi_quirk_table);
@@ -2042,10 +2046,4 @@ void vlv_dsi_init(struct intel_display *display)
 	intel_backlight_setup(connector, INVALID_PIPE);
 
 	vlv_dsi_add_properties(connector);
-
-	return;
-
-err_cleanup_connector:
-	drm_connector_cleanup(&connector->base);
-	kfree(connector);
 }

-- 
2.43.0



^ permalink raw reply related

* [PATCH RFC 07/12] drm/i915/display: Switch to managed for encoder
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
  To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
	David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
	Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
	Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
  Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
	intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
	linux-arm-kernel, Simona Vetter, Kory Maincent
In-Reply-To: <20260409-feat_link_cap-v1-0-7069e8199ce2@bootlin.com>

The current i915 driver uses non-managed function to create encoder. It
is not an issue yet, but in order to comply with the latest DRM
requirement, convert this code to use drm and device managed helpers.

Assisted-by: Claude Code:2.1.90
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
 drivers/gpu/drm/i915/display/g4x_dp.c        | 31 ++++++++---------
 drivers/gpu/drm/i915/display/g4x_hdmi.c      | 19 ++++-------
 drivers/gpu/drm/i915/display/icl_dsi.c       | 20 +++--------
 drivers/gpu/drm/i915/display/intel_crt.c     |  9 +++--
 drivers/gpu/drm/i915/display/intel_ddi.c     | 50 +++++++++++++++-------------
 drivers/gpu/drm/i915/display/intel_display.c |  8 -----
 drivers/gpu/drm/i915/display/intel_display.h |  1 -
 drivers/gpu/drm/i915/display/intel_dp_mst.c  | 20 +++--------
 drivers/gpu/drm/i915/display/intel_dvo.c     | 22 ++++++------
 drivers/gpu/drm/i915/display/intel_encoder.c |  6 ++--
 drivers/gpu/drm/i915/display/intel_encoder.h |  3 +-
 drivers/gpu/drm/i915/display/intel_lvds.c    | 13 +++-----
 drivers/gpu/drm/i915/display/intel_sdvo.c    | 45 +++++++++++--------------
 drivers/gpu/drm/i915/display/intel_tv.c      | 11 +++---
 drivers/gpu/drm/i915/display/vlv_dsi.c       | 22 +++++-------
 15 files changed, 114 insertions(+), 166 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c
index 5e74d8a3ba5c8..99b6c5ce39b2a 100644
--- a/drivers/gpu/drm/i915/display/g4x_dp.c
+++ b/drivers/gpu/drm/i915/display/g4x_dp.c
@@ -7,6 +7,7 @@
 
 #include <linux/string_helpers.h>
 
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 
 #include "g4x_dp.h"
@@ -1250,12 +1251,9 @@ static void g4x_dp_suspend_complete(struct intel_encoder *encoder)
 	intel_encoder_link_check_flush_work(encoder);
 }
 
-static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
+static void intel_dp_encoder_flush_work_cleanup(struct drm_device *drm, void *data)
 {
-	intel_dp_encoder_flush_work(encoder);
-
-	drm_encoder_cleanup(encoder);
-	kfree(enc_to_dig_port(to_intel_encoder(encoder)));
+	intel_dp_encoder_flush_work(data);
 }
 
 static void intel_dp_encoder_reset(struct drm_encoder *encoder)
@@ -1276,7 +1274,6 @@ static void intel_dp_encoder_reset(struct drm_encoder *encoder)
 
 static const struct drm_encoder_funcs intel_dp_enc_funcs = {
 	.reset = intel_dp_encoder_reset,
-	.destroy = intel_dp_encoder_destroy,
 };
 
 bool g4x_dp_init(struct intel_display *display,
@@ -1298,22 +1295,26 @@ bool g4x_dp_init(struct intel_display *display,
 		drm_dbg_kms(display->drm, "No VBT child device for DP-%c\n",
 			    port_name(port));
 
-	dig_port = intel_dig_port_alloc();
+	dig_port = intel_dig_port_alloc(display->drm);
 	if (!dig_port)
 		return false;
 
 	intel_connector = intel_connector_alloc();
 	if (!intel_connector)
-		goto err_connector_alloc;
+		return false;
 
 	intel_encoder = &dig_port->base;
 	encoder = &intel_encoder->base;
 
 	intel_encoder->devdata = devdata;
 
-	if (drm_encoder_init(display->drm, &intel_encoder->base,
-			     &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS,
-			     "DP %c", port_name(port)))
+	if (drmm_encoder_init(display->drm, &intel_encoder->base,
+			      &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS,
+			      "DP %c", port_name(port)))
+		goto err_encoder_init;
+
+	if (drmm_add_action_or_reset(display->drm,
+				     intel_dp_encoder_flush_work_cleanup, encoder))
 		goto err_encoder_init;
 
 	intel_encoder_link_check_init(intel_encoder, intel_dp_link_check);
@@ -1411,18 +1412,14 @@ bool g4x_dp_init(struct intel_display *display,
 
 	dig_port->aux_ch = intel_dp_aux_ch(intel_encoder);
 	if (dig_port->aux_ch == AUX_CH_NONE)
-		goto err_init_connector;
+		goto err_encoder_init;
 
 	if (!intel_dp_init_connector(dig_port, intel_connector))
-		goto err_init_connector;
+		goto err_encoder_init;
 
 	return true;
 
-err_init_connector:
-	drm_encoder_cleanup(encoder);
 err_encoder_init:
 	kfree(intel_connector);
-err_connector_alloc:
-	kfree(dig_port);
 	return false;
 }
diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c
index 5fe5067c4237c..45ee1ad504bc1 100644
--- a/drivers/gpu/drm/i915/display/g4x_hdmi.c
+++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c
@@ -5,6 +5,7 @@
  * HDMI support for G4x,ILK,SNB,IVB,VLV,CHV (HSW+ handled by the DDI code).
  */
 
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 
 #include "g4x_hdmi.h"
@@ -562,7 +563,6 @@ static void chv_hdmi_pre_enable(struct intel_atomic_state *state,
 }
 
 static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
-	.destroy = intel_encoder_destroy,
 };
 
 static enum intel_hotplug_state
@@ -686,21 +686,21 @@ bool g4x_hdmi_init(struct intel_display *display,
 		drm_dbg_kms(display->drm, "No VBT child device for HDMI-%c\n",
 			    port_name(port));
 
-	dig_port = intel_dig_port_alloc();
+	dig_port = intel_dig_port_alloc(display->drm);
 	if (!dig_port)
 		return false;
 
 	intel_connector = intel_connector_alloc();
 	if (!intel_connector)
-		goto err_connector_alloc;
+		return false;
 
 	intel_encoder = &dig_port->base;
 
 	intel_encoder->devdata = devdata;
 
-	if (drm_encoder_init(display->drm, &intel_encoder->base,
-			     &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
-			     "HDMI %c", port_name(port)))
+	if (drmm_encoder_init(display->drm, &intel_encoder->base,
+			      &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
+			      "HDMI %c", port_name(port)))
 		goto err_encoder_init;
 
 	intel_encoder->hotplug = intel_hdmi_hotplug;
@@ -763,16 +763,11 @@ bool g4x_hdmi_init(struct intel_display *display,
 	intel_infoframe_init(dig_port);
 
 	if (!intel_hdmi_init_connector(dig_port, intel_connector))
-		goto err_init_connector;
+		goto err_encoder_init;
 
 	return true;
-
-err_init_connector:
-	drm_encoder_cleanup(&intel_encoder->base);
 err_encoder_init:
 	kfree(intel_connector);
-err_connector_alloc:
-	kfree(dig_port);
 
 	return false;
 }
diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
index afbaa0465842a..cfee173a2367a 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi.c
+++ b/drivers/gpu/drm/i915/display/icl_dsi.c
@@ -30,6 +30,7 @@
 #include <drm/display/drm_dsc_helper.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_fixed.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
@@ -1775,13 +1776,7 @@ static bool gen11_dsi_initial_fastset_check(struct intel_encoder *encoder,
 	return true;
 }
 
-static void gen11_dsi_encoder_destroy(struct drm_encoder *encoder)
-{
-	intel_encoder_destroy(encoder);
-}
-
 static const struct drm_encoder_funcs gen11_dsi_encoder_funcs = {
-	.destroy = gen11_dsi_encoder_destroy,
 };
 
 static const struct drm_connector_funcs gen11_dsi_connector_funcs = {
@@ -1934,8 +1929,10 @@ void icl_dsi_init(struct intel_display *display,
 	if (port == PORT_NONE)
 		return;
 
-	intel_dsi = kzalloc_obj(*intel_dsi);
-	if (!intel_dsi)
+	intel_dsi = drmm_encoder_alloc(display->drm, struct intel_dsi, base.base,
+				       &gen11_dsi_encoder_funcs,
+				       DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port));
+	if (IS_ERR(intel_dsi))
 		return;
 
 	intel_connector = intel_connector_alloc();
@@ -1950,11 +1947,6 @@ void icl_dsi_init(struct intel_display *display,
 
 	encoder->devdata = devdata;
 
-	/* register DSI encoder with DRM subsystem */
-	drm_encoder_init(display->drm, &encoder->base,
-			 &gen11_dsi_encoder_funcs,
-			 DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port));
-
 	encoder->pre_pll_enable = gen11_dsi_pre_pll_enable;
 	encoder->pre_enable = gen11_dsi_pre_enable;
 	encoder->enable = gen11_dsi_enable;
@@ -2037,7 +2029,5 @@ void icl_dsi_init(struct intel_display *display,
 
 err:
 	drm_connector_cleanup(connector);
-	drm_encoder_cleanup(&encoder->base);
-	kfree(intel_dsi);
 	kfree(intel_connector);
 }
diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
index 6aa6a1dd6e1b0..39bb115955f5a 100644
--- a/drivers/gpu/drm/i915/display/intel_crt.c
+++ b/drivers/gpu/drm/i915/display/intel_crt.c
@@ -31,6 +31,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 #include <video/vga.h>
@@ -1004,7 +1005,6 @@ static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs
 
 static const struct drm_encoder_funcs intel_crt_enc_funcs = {
 	.reset = intel_crt_reset,
-	.destroy = intel_encoder_destroy,
 };
 
 void intel_crt_init(struct intel_display *display)
@@ -1041,8 +1041,9 @@ void intel_crt_init(struct intel_display *display)
 		intel_de_write(display, adpa_reg, adpa);
 	}
 
-	crt = kzalloc_obj(struct intel_crt);
-	if (!crt)
+	crt = drmm_encoder_alloc(display->drm, struct intel_crt, base.base,
+				 &intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC, "CRT");
+	if (IS_ERR(crt))
 		return;
 
 	connector = intel_connector_alloc();
@@ -1058,8 +1059,6 @@ void intel_crt_init(struct intel_display *display)
 				    DRM_MODE_CONNECTOR_VGA,
 				    intel_gmbus_get_adapter(display, ddc_pin));
 
-	drm_encoder_init(display->drm, &crt->base.base, &intel_crt_enc_funcs,
-			 DRM_MODE_ENCODER_DAC, "CRT");
 
 	intel_connector_attach_encoder(connector, &crt->base);
 
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index ebefa889bc8c5..003287ad5bc59 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -31,6 +31,7 @@
 
 #include <drm/display/drm_dp_helper.h>
 #include <drm/display/drm_scdc_helper.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_privacy_screen_consumer.h>
 
@@ -4644,19 +4645,19 @@ static int intel_ddi_compute_config_late(struct intel_encoder *encoder,
 	return 0;
 }
 
-static void intel_ddi_encoder_destroy(struct drm_encoder *encoder)
+static void intel_ddi_encoder_cleanup(struct drm_device *drm, void *data)
 {
-	struct intel_display *display = to_intel_display(encoder->dev);
-	struct intel_digital_port *dig_port = enc_to_dig_port(to_intel_encoder(encoder));
+	struct intel_digital_port *dig_port = data;
+	struct intel_display *display = to_intel_display(&dig_port->base);
 
-	intel_dp_encoder_flush_work(encoder);
-	if (intel_encoder_is_tc(&dig_port->base))
-		intel_tc_port_cleanup(dig_port);
+	intel_dp_encoder_flush_work(&dig_port->base.base);
 	intel_display_power_flush_work(display);
-
-	drm_encoder_cleanup(encoder);
 	kfree(dig_port->hdcp.port_data.streams);
-	kfree(dig_port);
+}
+
+static void intel_tc_port_cleanup_action(struct drm_device *drm, void *data)
+{
+	intel_tc_port_cleanup(data);
 }
 
 static void intel_ddi_encoder_reset(struct drm_encoder *encoder)
@@ -4684,7 +4685,6 @@ static int intel_ddi_encoder_late_register(struct drm_encoder *_encoder)
 
 static const struct drm_encoder_funcs intel_ddi_funcs = {
 	.reset = intel_ddi_encoder_reset,
-	.destroy = intel_ddi_encoder_destroy,
 	.late_register = intel_ddi_encoder_late_register,
 };
 
@@ -5243,16 +5243,20 @@ void intel_ddi_init(struct intel_display *display,
 			    phy_name(phy));
 	}
 
-	dig_port = intel_dig_port_alloc();
+	dig_port = intel_dig_port_alloc(display->drm);
 	if (!dig_port)
 		return;
 
 	encoder = &dig_port->base;
 	encoder->devdata = devdata;
 
-	drm_encoder_init(display->drm, &encoder->base, &intel_ddi_funcs,
-			 DRM_MODE_ENCODER_TMDS, "%s",
-			 intel_ddi_encoder_name(display, port, phy, &encoder_name));
+	if (drmm_encoder_init(display->drm, &encoder->base, &intel_ddi_funcs,
+			      DRM_MODE_ENCODER_TMDS, "%s",
+			      intel_ddi_encoder_name(display, port, phy, &encoder_name)))
+		return;
+
+	if (drmm_add_action_or_reset(display->drm, intel_ddi_encoder_cleanup, dig_port))
+		return;
 
 	intel_encoder_link_check_init(encoder, intel_ddi_link_check);
 
@@ -5411,7 +5415,7 @@ void intel_ddi_init(struct intel_display *display,
 	if (need_aux_ch(encoder, init_dp)) {
 		dig_port->aux_ch = intel_dp_aux_ch(encoder);
 		if (dig_port->aux_ch == AUX_CH_NONE)
-			goto err;
+			return;
 	}
 
 	/*
@@ -5447,7 +5451,11 @@ void intel_ddi_init(struct intel_display *display,
 		dig_port->unlock = intel_tc_port_unlock;
 
 		if (intel_tc_port_init(dig_port, is_legacy) < 0)
-			goto err;
+			return;
+
+		if (drmm_add_action_or_reset(display->drm,
+					     intel_tc_port_cleanup_action, dig_port))
+			return;
 	}
 
 	drm_WARN_ON(display->drm, port > PORT_I);
@@ -5478,7 +5486,7 @@ void intel_ddi_init(struct intel_display *display,
 
 	if (init_dp) {
 		if (intel_ddi_init_dp_connector(dig_port))
-			goto err;
+			return;
 
 		dig_port->hpd_pulse = intel_dp_hpd_pulse;
 
@@ -5492,12 +5500,6 @@ void intel_ddi_init(struct intel_display *display,
 	 */
 	if (encoder->type != INTEL_OUTPUT_EDP && init_hdmi) {
 		if (intel_ddi_init_hdmi_connector(dig_port))
-			goto err;
+			return;
 	}
-
-	return;
-
-err:
-	drm_encoder_cleanup(&encoder->base);
-	kfree(dig_port);
 }
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 10b6c6fcb03f6..049a796da4c38 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -2192,14 +2192,6 @@ static void i9xx_crtc_disable(struct intel_atomic_state *state,
 		i830_enable_pipe(display, pipe);
 }
 
-void intel_encoder_destroy(struct drm_encoder *encoder)
-{
-	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-
-	drm_encoder_cleanup(encoder);
-	kfree(intel_encoder);
-}
-
 static bool intel_crtc_supports_double_wide(const struct intel_crtc *crtc)
 {
 	struct intel_display *display = to_intel_display(crtc);
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index 552a59d19e0f6..6c2681738e6b2 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -416,7 +416,6 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state);
 void i830_enable_pipe(struct intel_display *display, enum pipe pipe);
 void i830_disable_pipe(struct intel_display *display, enum pipe pipe);
 bool intel_has_pending_fb_unpin(struct intel_display *display);
-void intel_encoder_destroy(struct drm_encoder *encoder);
 struct drm_display_mode *
 intel_encoder_current_mode(struct intel_encoder *encoder);
 void intel_encoder_get_config(struct intel_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 887b6de14e467..5fe6fbcaf9371 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -30,6 +30,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_fixed.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 
@@ -1645,16 +1646,7 @@ static const struct drm_connector_helper_funcs mst_connector_helper_funcs = {
 	.detect_ctx = mst_connector_detect_ctx,
 };
 
-static void mst_stream_encoder_destroy(struct drm_encoder *encoder)
-{
-	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(to_intel_encoder(encoder));
-
-	drm_encoder_cleanup(encoder);
-	kfree(intel_mst);
-}
-
 static const struct drm_encoder_funcs mst_stream_encoder_funcs = {
-	.destroy = mst_stream_encoder_destroy,
 };
 
 static bool mst_connector_get_hw_state(struct intel_connector *connector)
@@ -1850,18 +1842,16 @@ mst_stream_encoder_create(struct intel_digital_port *dig_port, enum pipe pipe)
 	struct intel_dp_mst_encoder *intel_mst;
 	struct intel_encoder *encoder;
 
-	intel_mst = kzalloc_obj(*intel_mst);
-
-	if (!intel_mst)
+	intel_mst = drmm_encoder_alloc(display->drm, struct intel_dp_mst_encoder,
+				       base.base, &mst_stream_encoder_funcs,
+				       DRM_MODE_ENCODER_DPMST, "DP-MST %c", pipe_name(pipe));
+	if (IS_ERR(intel_mst))
 		return NULL;
 
 	intel_mst->pipe = pipe;
 	encoder = &intel_mst->base;
 	intel_mst->primary = dig_port;
 
-	drm_encoder_init(display->drm, &encoder->base, &mst_stream_encoder_funcs,
-			 DRM_MODE_ENCODER_DPMST, "DP-MST %c", pipe_name(pipe));
-
 	encoder->type = INTEL_OUTPUT_DP_MST;
 	encoder->power_domain = primary_encoder->power_domain;
 	encoder->port = primary_encoder->port;
diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c
index 405b33aca9dde..ea2f6426fd77d 100644
--- a/drivers/gpu/drm/i915/display/intel_dvo.c
+++ b/drivers/gpu/drm/i915/display/intel_dvo.c
@@ -31,6 +31,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 
@@ -372,18 +373,15 @@ static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs
 	.get_modes = intel_dvo_get_modes,
 };
 
-static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
+static void intel_dvo_dev_destroy(struct drm_device *drm, void *data)
 {
-	struct intel_dvo *intel_dvo = enc_to_dvo(to_intel_encoder(encoder));
+	struct intel_dvo *intel_dvo = data;
 
 	if (intel_dvo->dev.dev_ops->destroy)
 		intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev);
-
-	intel_encoder_destroy(encoder);
 }
 
 static const struct drm_encoder_funcs intel_dvo_enc_funcs = {
-	.destroy = intel_dvo_enc_destroy,
 };
 
 static int intel_dvo_encoder_type(const struct intel_dvo_device *dvo)
@@ -494,7 +492,7 @@ void intel_dvo_init(struct intel_display *display)
 	struct intel_encoder *encoder;
 	struct intel_dvo *intel_dvo;
 
-	intel_dvo = kzalloc_obj(*intel_dvo);
+	intel_dvo = drmm_kzalloc(display->drm, sizeof(*intel_dvo), GFP_KERNEL);
 	if (!intel_dvo)
 		return;
 
@@ -517,13 +515,15 @@ void intel_dvo_init(struct intel_display *display)
 	connector->get_hw_state = intel_dvo_connector_get_hw_state;
 
 	if (!intel_dvo_probe(display, intel_dvo)) {
-		kfree(intel_dvo);
 		intel_connector_free(connector);
 		return;
 	}
 
 	assert_port_valid(display, intel_dvo->dev.port);
 
+	if (drmm_add_action_or_reset(display->drm, intel_dvo_dev_destroy, intel_dvo))
+		return;
+
 	encoder->type = INTEL_OUTPUT_DVO;
 	encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
 	encoder->port = intel_dvo->dev.port;
@@ -533,10 +533,10 @@ void intel_dvo_init(struct intel_display *display)
 		encoder->cloneable = BIT(INTEL_OUTPUT_ANALOG) |
 			BIT(INTEL_OUTPUT_DVO);
 
-	drm_encoder_init(display->drm, &encoder->base,
-			 &intel_dvo_enc_funcs,
-			 intel_dvo_encoder_type(&intel_dvo->dev),
-			 "DVO %c", port_name(encoder->port));
+	drmm_encoder_init(display->drm, &encoder->base,
+			  &intel_dvo_enc_funcs,
+			  intel_dvo_encoder_type(&intel_dvo->dev),
+			  "DVO %c", port_name(encoder->port));
 
 	drm_dbg_kms(display->drm, "[ENCODER:%d:%s] detected %s\n",
 		    encoder->base.base.id, encoder->base.name,
diff --git a/drivers/gpu/drm/i915/display/intel_encoder.c b/drivers/gpu/drm/i915/display/intel_encoder.c
index d01b081a60740..2ebd1e4457482 100644
--- a/drivers/gpu/drm/i915/display/intel_encoder.c
+++ b/drivers/gpu/drm/i915/display/intel_encoder.c
@@ -5,6 +5,8 @@
 
 #include <linux/workqueue.h>
 
+#include <drm/drm_managed.h>
+
 #include "intel_display_core.h"
 #include "intel_display_types.h"
 #include "intel_encoder.h"
@@ -104,11 +106,11 @@ void intel_encoder_shutdown_all(struct intel_display *display)
 			encoder->shutdown_complete(encoder);
 }
 
-struct intel_digital_port *intel_dig_port_alloc(void)
+struct intel_digital_port *intel_dig_port_alloc(struct drm_device *drm)
 {
 	struct intel_digital_port *dig_port;
 
-	dig_port = kzalloc_obj(*dig_port);
+	dig_port = drmm_kzalloc(drm, sizeof(*dig_port), GFP_KERNEL);
 	if (!dig_port)
 		return NULL;
 
diff --git a/drivers/gpu/drm/i915/display/intel_encoder.h b/drivers/gpu/drm/i915/display/intel_encoder.h
index ace0fe1a8f27a..42f3982970065 100644
--- a/drivers/gpu/drm/i915/display/intel_encoder.h
+++ b/drivers/gpu/drm/i915/display/intel_encoder.h
@@ -6,6 +6,7 @@
 #ifndef __INTEL_ENCODER_H__
 #define __INTEL_ENCODER_H__
 
+struct drm_device;
 struct intel_digital_port;
 struct intel_display;
 struct intel_encoder;
@@ -21,6 +22,6 @@ void intel_encoder_shutdown_all(struct intel_display *display);
 void intel_encoder_block_all_hpds(struct intel_display *display);
 void intel_encoder_unblock_all_hpds(struct intel_display *display);
 
-struct intel_digital_port *intel_dig_port_alloc(void);
+struct intel_digital_port *intel_dig_port_alloc(struct drm_device *drm);
 
 #endif /* __INTEL_ENCODER_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index e78a41e2b268c..7bb99eb44a5a4 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -37,6 +37,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 
@@ -517,7 +518,6 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = {
 };
 
 static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
-	.destroy = intel_encoder_destroy,
 };
 
 static int intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
@@ -886,15 +886,14 @@ void intel_lvds_init(struct intel_display *display)
 			    "LVDS is not present in VBT, but enabled anyway\n");
 	}
 
-	lvds_encoder = kzalloc_obj(*lvds_encoder);
-	if (!lvds_encoder)
+	lvds_encoder = drmm_encoder_alloc(display->drm, struct intel_lvds_encoder, base.base,
+					  &intel_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS, "LVDS");
+	if (IS_ERR(lvds_encoder))
 		return;
 
 	connector = intel_connector_alloc();
-	if (!connector) {
-		kfree(lvds_encoder);
+	if (!connector)
 		return;
-	}
 
 	lvds_encoder->attached_connector = connector;
 	encoder = &lvds_encoder->base;
@@ -904,8 +903,6 @@ void intel_lvds_init(struct intel_display *display)
 				    DRM_MODE_CONNECTOR_LVDS,
 				    intel_gmbus_get_adapter(display, ddc_pin));
 
-	drm_encoder_init(display->drm, &encoder->base, &intel_lvds_enc_funcs,
-			 DRM_MODE_ENCODER_LVDS, "LVDS");
 
 	encoder->enable = intel_enable_lvds;
 	encoder->pre_enable = intel_pre_enable_lvds;
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index 6eb2b4b45a9b4..f5aaa38002674 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -36,6 +36,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_eld.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 
@@ -2542,24 +2543,19 @@ static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs
 	.atomic_check = intel_sdvo_atomic_check,
 };
 
-static void intel_sdvo_encoder_destroy(struct drm_encoder *_encoder)
+static void intel_sdvo_unselect_i2c_bus(struct intel_sdvo *sdvo);
+
+static void intel_sdvo_cleanup(struct drm_device *drm, void *data)
 {
-	struct intel_encoder *encoder = to_intel_encoder(_encoder);
-	struct intel_sdvo *sdvo = to_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = data;
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(sdvo->ddc); i++) {
-		if (sdvo->ddc[i].ddc_bus)
-			i2c_del_adapter(&sdvo->ddc[i].ddc);
+	for (i = 0; i < ARRAY_SIZE(intel_sdvo->ddc); i++) {
+		if (intel_sdvo->ddc[i].ddc_bus)
+			i2c_del_adapter(&intel_sdvo->ddc[i].ddc);
 	}
-
-	drm_encoder_cleanup(&encoder->base);
-	kfree(sdvo);
-};
-
-static const struct drm_encoder_funcs intel_sdvo_enc_funcs = {
-	.destroy = intel_sdvo_encoder_destroy,
-};
+	intel_sdvo_unselect_i2c_bus(intel_sdvo);
+}
 
 static int
 intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo,
@@ -3381,8 +3377,9 @@ bool intel_sdvo_init(struct intel_display *display,
 	if (!assert_sdvo_port_valid(display, port))
 		return false;
 
-	intel_sdvo = kzalloc_obj(*intel_sdvo);
-	if (!intel_sdvo)
+	intel_sdvo = drmm_encoder_alloc(display->drm, struct intel_sdvo, base.base,
+					NULL, 0, "SDVO %c", port_name(port));
+	if (IS_ERR(intel_sdvo))
 		return false;
 
 	/* encoder type will be decided later */
@@ -3391,15 +3388,14 @@ bool intel_sdvo_init(struct intel_display *display,
 	intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
 	intel_encoder->port = port;
 
-	drm_encoder_init(display->drm, &intel_encoder->base,
-			 &intel_sdvo_enc_funcs, 0,
-			 "SDVO %c", port_name(port));
-
 	intel_sdvo->sdvo_reg = sdvo_reg;
 	intel_sdvo->target_addr = intel_sdvo_get_target_addr(intel_sdvo) >> 1;
 
 	intel_sdvo_select_i2c_bus(intel_sdvo);
 
+	if (drmm_add_action_or_reset(display->drm, intel_sdvo_cleanup, intel_sdvo))
+		return false;
+
 	/* Read the regs to test if we can talk to the device */
 	for (i = 0; i < 0x40; i++) {
 		u8 byte;
@@ -3408,7 +3404,7 @@ bool intel_sdvo_init(struct intel_display *display,
 			drm_dbg_kms(display->drm,
 				    "No SDVO device found on %s\n",
 				    SDVO_NAME(intel_sdvo));
-			goto err;
+			return false;
 		}
 	}
 
@@ -3428,7 +3424,7 @@ bool intel_sdvo_init(struct intel_display *display,
 
 	/* In default case sdvo lvds is false */
 	if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
-		goto err;
+		return false;
 
 	intel_sdvo->colorimetry_cap =
 		intel_sdvo_get_colorimetry_cap(intel_sdvo);
@@ -3439,7 +3435,7 @@ bool intel_sdvo_init(struct intel_display *display,
 		ret = intel_sdvo_init_ddc_proxy(&intel_sdvo->ddc[i],
 						intel_sdvo, i + 1);
 		if (ret)
-			goto err;
+			return false;
 	}
 
 	if (!intel_sdvo_output_setup(intel_sdvo)) {
@@ -3502,9 +3498,6 @@ bool intel_sdvo_init(struct intel_display *display,
 
 err_output:
 	intel_sdvo_output_cleanup(intel_sdvo);
-err:
-	intel_sdvo_unselect_i2c_bus(intel_sdvo);
-	intel_sdvo_encoder_destroy(&intel_encoder->base);
 
 	return false;
 }
diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c
index 8fbf0adb56992..05df0acc6dc3e 100644
--- a/drivers/gpu/drm/i915/display/intel_tv.c
+++ b/drivers/gpu/drm/i915/display/intel_tv.c
@@ -33,6 +33,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 
@@ -1881,7 +1882,6 @@ static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs =
 };
 
 static const struct drm_encoder_funcs intel_tv_enc_funcs = {
-	.destroy = intel_encoder_destroy,
 };
 
 static void intel_tv_add_properties(struct drm_connector *connector)
@@ -1966,10 +1966,10 @@ intel_tv_init(struct intel_display *display)
 	    (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
 		return;
 
-	intel_tv = kzalloc_obj(*intel_tv);
-	if (!intel_tv) {
+	intel_tv = drmm_encoder_alloc(display->drm, struct intel_tv, base.base,
+				      &intel_tv_enc_funcs, DRM_MODE_ENCODER_TVDAC, "TV");
+	if (IS_ERR(intel_tv))
 		return;
-	}
 
 	intel_connector = intel_connector_alloc();
 	if (!intel_connector) {
@@ -1996,9 +1996,6 @@ intel_tv_init(struct intel_display *display)
 	drm_connector_init(display->drm, connector, &intel_tv_connector_funcs,
 			   DRM_MODE_CONNECTOR_SVIDEO);
 
-	drm_encoder_init(display->drm, &intel_encoder->base,
-			 &intel_tv_enc_funcs,
-			 DRM_MODE_ENCODER_TVDAC, "TV");
 
 	intel_encoder->compute_config = intel_tv_compute_config;
 	intel_encoder->get_config = intel_tv_get_config;
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c
index d4db73c184e5c..e84edb6242716 100644
--- a/drivers/gpu/drm/i915/display/vlv_dsi.c
+++ b/drivers/gpu/drm/i915/display/vlv_dsi.c
@@ -30,6 +30,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_mipi_dsi.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 
@@ -1531,7 +1532,6 @@ static void intel_dsi_unprepare(struct intel_encoder *encoder)
 }
 
 static const struct drm_encoder_funcs intel_dsi_funcs = {
-	.destroy = intel_encoder_destroy,
 };
 
 static enum drm_mode_status vlv_dsi_mode_valid(struct drm_connector *connector,
@@ -1918,22 +1918,19 @@ void vlv_dsi_init(struct intel_display *display)
 	else
 		display->dsi.mmio_base = VLV_MIPI_BASE;
 
-	intel_dsi = kzalloc_obj(*intel_dsi);
-	if (!intel_dsi)
+	intel_dsi = drmm_encoder_alloc(display->drm, struct intel_dsi, base.base,
+				       &intel_dsi_funcs, DRM_MODE_ENCODER_DSI,
+				       "DSI %c", port_name(port));
+	if (IS_ERR(intel_dsi))
 		return;
 
 	connector = intel_connector_alloc();
-	if (!connector) {
-		kfree(intel_dsi);
+	if (!connector)
 		return;
-	}
 
 	encoder = &intel_dsi->base;
 	intel_dsi->attached_connector = connector;
 
-	drm_encoder_init(display->drm, &encoder->base, &intel_dsi_funcs,
-			 DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port));
-
 	encoder->compute_config = intel_dsi_compute_config;
 	encoder->pre_enable = intel_dsi_pre_enable;
 	if (display->platform.geminilake || display->platform.broxton)
@@ -1985,14 +1982,14 @@ void vlv_dsi_init(struct intel_display *display)
 		host = intel_dsi_host_init(intel_dsi, &intel_dsi_host_ops,
 					   port);
 		if (!host)
-			goto err;
+			return;
 
 		intel_dsi->dsi_hosts[port] = host;
 	}
 
 	if (!intel_dsi_vbt_init(intel_dsi, MIPI_DSI_GENERIC_PANEL_ID)) {
 		drm_dbg_kms(display->drm, "no device found\n");
-		goto err;
+		return;
 	}
 
 	/* Use clock read-back from current hw-state for fastboot */
@@ -2050,8 +2047,5 @@ void vlv_dsi_init(struct intel_display *display)
 
 err_cleanup_connector:
 	drm_connector_cleanup(&connector->base);
-err:
-	drm_encoder_cleanup(&encoder->base);
-	kfree(intel_dsi);
 	kfree(connector);
 }

-- 
2.43.0



^ permalink raw reply related

* [PATCH RFC 06/12] drm/i915/display: Switch to managed for plane
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
  To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
	David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
	Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
	Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
  Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
	intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
	linux-arm-kernel, Simona Vetter, Kory Maincent
In-Reply-To: <20260409-feat_link_cap-v1-0-7069e8199ce2@bootlin.com>

The current i915 driver uses non-managed function to create plane. It
is not an issue yet, but in order to comply with the latest DRM
requirement, convert this code to use drm and device managed helpers.

Assisted-by: Claude Code:2.1.90
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
 drivers/gpu/drm/i915/display/i9xx_plane.c          |  97 ++++++++---------
 drivers/gpu/drm/i915/display/intel_cursor.c        |  41 ++++---
 drivers/gpu/drm/i915/display/intel_plane.c         |  45 +-------
 drivers/gpu/drm/i915/display/intel_plane.h         |   5 +-
 drivers/gpu/drm/i915/display/intel_sprite.c        | 119 ++++++++++-----------
 drivers/gpu/drm/i915/display/skl_universal_plane.c | 102 +++++++++---------
 6 files changed, 181 insertions(+), 228 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c
index 9c16753a1f3ba..032c56b478dfc 100644
--- a/drivers/gpu/drm/i915/display/i9xx_plane.c
+++ b/drivers/gpu/drm/i915/display/i9xx_plane.c
@@ -8,6 +8,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_blend.h>
 #include <drm/drm_fourcc.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 
 #include "i9xx_plane.h"
@@ -882,7 +883,6 @@ static unsigned int i9xx_plane_min_alignment(struct intel_plane *plane,
 static const struct drm_plane_funcs i965_plane_funcs = {
 	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = intel_plane_destroy,
 	.atomic_duplicate_state = intel_plane_duplicate_state,
 	.atomic_destroy_state = intel_plane_destroy_state,
 	.format_mod_supported = i965_plane_format_mod_supported,
@@ -892,7 +892,6 @@ static const struct drm_plane_funcs i965_plane_funcs = {
 static const struct drm_plane_funcs i8xx_plane_funcs = {
 	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = intel_plane_destroy,
 	.atomic_duplicate_state = intel_plane_duplicate_state,
 	.atomic_destroy_state = intel_plane_destroy_state,
 	.format_mod_supported = i8xx_plane_format_mod_supported,
@@ -923,32 +922,15 @@ static void i9xx_disable_tiling(struct intel_plane *plane)
 struct intel_plane *
 intel_primary_plane_create(struct intel_display *display, enum pipe pipe)
 {
+	struct intel_plane_state *plane_state;
 	struct intel_plane *plane;
 	const struct drm_plane_funcs *plane_funcs;
 	unsigned int supported_rotations;
 	const u64 *modifiers;
 	const u32 *formats;
 	int num_formats;
-	int ret, zpos;
-
-	plane = intel_plane_alloc();
-	if (IS_ERR(plane))
-		return plane;
-
-	plane->pipe = pipe;
-	/*
-	 * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS
-	 * port is hooked to pipe B. Hence we want plane A feeding pipe B.
-	 */
-	if (HAS_FBC(display) && DISPLAY_VER(display) < 4 &&
-	    INTEL_NUM_PIPES(display) == 2)
-		plane->i9xx_plane = (enum i9xx_plane_id) !pipe;
-	else
-		plane->i9xx_plane = (enum i9xx_plane_id) pipe;
-	plane->id = PLANE_PRIMARY;
-	plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
-
-	intel_fbc_add_plane(i9xx_plane_fbc(display, plane->i9xx_plane), plane);
+	enum i9xx_plane_id i9xx_plane;
+	int zpos;
 
 	if (display->platform.valleyview || display->platform.cherryview) {
 		formats = vlv_primary_formats;
@@ -984,6 +966,46 @@ intel_primary_plane_create(struct intel_display *display, enum pipe pipe)
 	else
 		plane_funcs = &i8xx_plane_funcs;
 
+	/*
+	 * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS
+	 * port is hooked to pipe B. Hence we want plane A feeding pipe B.
+	 */
+	if (HAS_FBC(display) && DISPLAY_VER(display) < 4 &&
+	    INTEL_NUM_PIPES(display) == 2)
+		i9xx_plane = (enum i9xx_plane_id)!pipe;
+	else
+		i9xx_plane = (enum i9xx_plane_id)pipe;
+
+	modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_TILING_X);
+
+	if (DISPLAY_VER(display) >= 5 || display->platform.g4x)
+		plane = drmm_universal_plane_alloc(display->drm, struct intel_plane, base,
+						   0, plane_funcs,
+						   formats, num_formats,
+						   modifiers,
+						   DRM_PLANE_TYPE_PRIMARY,
+						   "primary %c", pipe_name(pipe));
+	else
+		plane = drmm_universal_plane_alloc(display->drm, struct intel_plane, base,
+						   0, plane_funcs,
+						   formats, num_formats,
+						   modifiers,
+						   DRM_PLANE_TYPE_PRIMARY,
+						   "plane %c",
+						   plane_name(i9xx_plane));
+
+	kfree(modifiers);
+
+	if (IS_ERR(plane))
+		return plane;
+
+	plane->pipe = pipe;
+	plane->i9xx_plane = i9xx_plane;
+	plane->id = PLANE_PRIMARY;
+	plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
+
+	intel_fbc_add_plane(i9xx_plane_fbc(display, plane->i9xx_plane), plane);
+
 	if (display->platform.valleyview || display->platform.cherryview)
 		plane->min_cdclk = vlv_plane_min_cdclk;
 	else if (display->platform.broadwell || display->platform.haswell)
@@ -1069,28 +1091,12 @@ intel_primary_plane_create(struct intel_display *display, enum pipe pipe)
 
 	plane->disable_tiling = i9xx_disable_tiling;
 
-	modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_TILING_X);
-
-	if (DISPLAY_VER(display) >= 5 || display->platform.g4x)
-		ret = drm_universal_plane_init(display->drm, &plane->base,
-					       0, plane_funcs,
-					       formats, num_formats,
-					       modifiers,
-					       DRM_PLANE_TYPE_PRIMARY,
-					       "primary %c", pipe_name(pipe));
-	else
-		ret = drm_universal_plane_init(display->drm, &plane->base,
-					       0, plane_funcs,
-					       formats, num_formats,
-					       modifiers,
-					       DRM_PLANE_TYPE_PRIMARY,
-					       "plane %c",
-					       plane_name(plane->i9xx_plane));
-
-	kfree(modifiers);
+	plane_state = kzalloc_obj(*plane_state);
+	if (!plane_state)
+		return ERR_PTR(-ENOMEM);
 
-	if (ret)
-		goto fail;
+	intel_plane_state_reset(plane_state, plane);
+	plane->base.state = &plane_state->uapi;
 
 	if (display->platform.cherryview && pipe == PIPE_B) {
 		supported_rotations =
@@ -1114,11 +1120,6 @@ intel_primary_plane_create(struct intel_display *display, enum pipe pipe)
 	intel_plane_helper_add(plane);
 
 	return plane;
-
-fail:
-	intel_plane_free(plane);
-
-	return ERR_PTR(ret);
 }
 
 static int i9xx_format_to_fourcc(int format)
diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c
index 18d1014de3613..2493baf25fbe2 100644
--- a/drivers/gpu/drm/i915/display/intel_cursor.c
+++ b/drivers/gpu/drm/i915/display/intel_cursor.c
@@ -9,6 +9,7 @@
 #include <drm/drm_blend.h>
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_fourcc.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_vblank.h>
 
@@ -971,7 +972,6 @@ intel_legacy_cursor_update(struct drm_plane *_plane,
 static const struct drm_plane_funcs intel_cursor_plane_funcs = {
 	.update_plane = intel_legacy_cursor_update,
 	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = intel_plane_destroy,
 	.atomic_duplicate_state = intel_plane_duplicate_state,
 	.atomic_destroy_state = intel_plane_destroy_state,
 	.format_mod_supported = intel_cursor_format_mod_supported,
@@ -1004,11 +1004,23 @@ struct intel_plane *
 intel_cursor_plane_create(struct intel_display *display,
 			  enum pipe pipe)
 {
+	struct intel_plane_state *plane_state;
 	struct intel_plane *cursor;
-	int ret, zpos;
+	int zpos;
 	u64 *modifiers;
 
-	cursor = intel_plane_alloc();
+	modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_NONE);
+
+	cursor = drmm_universal_plane_alloc(display->drm, struct intel_plane, base,
+					    0, &intel_cursor_plane_funcs,
+					    intel_cursor_formats,
+					    ARRAY_SIZE(intel_cursor_formats),
+					    modifiers,
+					    DRM_PLANE_TYPE_CURSOR,
+					    "cursor %c", pipe_name(pipe));
+
+	kfree(modifiers);
+
 	if (IS_ERR(cursor))
 		return cursor;
 
@@ -1056,20 +1068,12 @@ intel_cursor_plane_create(struct intel_display *display,
 	if (display->platform.i845g || display->platform.i865g || HAS_CUR_FBC(display))
 		cursor->cursor.size = ~0;
 
-	modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_NONE);
-
-	ret = drm_universal_plane_init(display->drm, &cursor->base,
-				       0, &intel_cursor_plane_funcs,
-				       intel_cursor_formats,
-				       ARRAY_SIZE(intel_cursor_formats),
-				       modifiers,
-				       DRM_PLANE_TYPE_CURSOR,
-				       "cursor %c", pipe_name(pipe));
-
-	kfree(modifiers);
+	plane_state = kzalloc_obj(*plane_state);
+	if (!plane_state)
+		return ERR_PTR(-ENOMEM);
 
-	if (ret)
-		goto fail;
+	intel_plane_state_reset(plane_state, cursor);
+	cursor->base.state = &plane_state->uapi;
 
 	if (DISPLAY_VER(display) >= 4)
 		drm_plane_create_rotation_property(&cursor->base,
@@ -1088,11 +1092,6 @@ intel_cursor_plane_create(struct intel_display *display,
 	intel_plane_helper_add(cursor);
 
 	return cursor;
-
-fail:
-	intel_plane_free(cursor);
-
-	return ERR_PTR(ret);
 }
 
 void intel_cursor_mode_config_init(struct intel_display *display)
diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c
index 5390ceb21ca42..05c2dc0902f5c 100644
--- a/drivers/gpu/drm/i915/display/intel_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_plane.c
@@ -62,8 +62,8 @@
 #include "skl_universal_plane.h"
 #include "skl_watermark.h"
 
-static void intel_plane_state_reset(struct intel_plane_state *plane_state,
-				    struct intel_plane *plane)
+void intel_plane_state_reset(struct intel_plane_state *plane_state,
+			     struct intel_plane *plane)
 {
 	memset(plane_state, 0, sizeof(*plane_state));
 
@@ -72,47 +72,6 @@ static void intel_plane_state_reset(struct intel_plane_state *plane_state,
 	plane_state->scaler_id = -1;
 }
 
-struct intel_plane *intel_plane_alloc(void)
-{
-	struct intel_plane_state *plane_state;
-	struct intel_plane *plane;
-
-	plane = kzalloc_obj(*plane);
-	if (!plane)
-		return ERR_PTR(-ENOMEM);
-
-	plane_state = kzalloc_obj(*plane_state);
-	if (!plane_state) {
-		kfree(plane);
-		return ERR_PTR(-ENOMEM);
-	}
-
-	intel_plane_state_reset(plane_state, plane);
-
-	plane->base.state = &plane_state->uapi;
-
-	return plane;
-}
-
-void intel_plane_free(struct intel_plane *plane)
-{
-	intel_plane_destroy_state(&plane->base, plane->base.state);
-	kfree(plane);
-}
-
-/**
- * intel_plane_destroy - destroy a plane
- * @plane: plane to destroy
- *
- * Common destruction function for all types of planes (primary, cursor,
- * sprite).
- */
-void intel_plane_destroy(struct drm_plane *plane)
-{
-	drm_plane_cleanup(plane);
-	kfree(to_intel_plane(plane));
-}
-
 /**
  * intel_plane_duplicate_state - duplicate plane state
  * @plane: drm plane
diff --git a/drivers/gpu/drm/i915/display/intel_plane.h b/drivers/gpu/drm/i915/display/intel_plane.h
index 5a8f2f3baab5f..56221619a2b29 100644
--- a/drivers/gpu/drm/i915/display/intel_plane.h
+++ b/drivers/gpu/drm/i915/display/intel_plane.h
@@ -55,9 +55,8 @@ void intel_plane_update_arm(struct intel_dsb *dsb,
 void intel_plane_disable_arm(struct intel_dsb *dsb,
 			     struct intel_plane *plane,
 			     const struct intel_crtc_state *crtc_state);
-struct intel_plane *intel_plane_alloc(void);
-void intel_plane_free(struct intel_plane *plane);
-void intel_plane_destroy(struct drm_plane *plane);
+void intel_plane_state_reset(struct intel_plane_state *plane_state,
+			     struct intel_plane *plane);
 struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane);
 void intel_plane_destroy_state(struct drm_plane *plane,
 			       struct drm_plane_state *state);
diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c
index 6a65f92e8a031..f285d15734ee5 100644
--- a/drivers/gpu/drm/i915/display/intel_sprite.c
+++ b/drivers/gpu/drm/i915/display/intel_sprite.c
@@ -36,6 +36,7 @@
 #include <drm/drm_blend.h>
 #include <drm/drm_color_mgmt.h>
 #include <drm/drm_fourcc.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_rect.h>
 
@@ -1563,7 +1564,6 @@ static bool vlv_sprite_format_mod_supported(struct drm_plane *_plane,
 static const struct drm_plane_funcs g4x_sprite_funcs = {
 	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = intel_plane_destroy,
 	.atomic_duplicate_state = intel_plane_duplicate_state,
 	.atomic_destroy_state = intel_plane_destroy_state,
 	.format_mod_supported = g4x_sprite_format_mod_supported,
@@ -1573,7 +1573,6 @@ static const struct drm_plane_funcs g4x_sprite_funcs = {
 static const struct drm_plane_funcs snb_sprite_funcs = {
 	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = intel_plane_destroy,
 	.atomic_duplicate_state = intel_plane_duplicate_state,
 	.atomic_destroy_state = intel_plane_destroy_state,
 	.format_mod_supported = snb_sprite_format_mod_supported,
@@ -1583,7 +1582,6 @@ static const struct drm_plane_funcs snb_sprite_funcs = {
 static const struct drm_plane_funcs vlv_sprite_funcs = {
 	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = intel_plane_destroy,
 	.atomic_duplicate_state = intel_plane_duplicate_state,
 	.atomic_destroy_state = intel_plane_destroy_state,
 	.format_mod_supported = vlv_sprite_format_mod_supported,
@@ -1594,18 +1592,69 @@ struct intel_plane *
 intel_sprite_plane_create(struct intel_display *display,
 			  enum pipe pipe, int sprite)
 {
+	struct intel_plane_state *plane_state;
 	struct intel_plane *plane;
 	const struct drm_plane_funcs *plane_funcs;
 	unsigned int supported_rotations;
 	const u64 *modifiers;
 	const u32 *formats;
 	int num_formats;
-	int ret, zpos;
+	int zpos;
+
+	if (display->platform.valleyview || display->platform.cherryview) {
+		if (display->platform.cherryview && pipe == PIPE_B) {
+			formats = chv_pipe_b_sprite_formats;
+			num_formats = ARRAY_SIZE(chv_pipe_b_sprite_formats);
+		} else {
+			formats = vlv_sprite_formats;
+			num_formats = ARRAY_SIZE(vlv_sprite_formats);
+		}
+
+		plane_funcs = &vlv_sprite_funcs;
+	} else if (DISPLAY_VER(display) >= 7) {
+		formats = snb_sprite_formats;
+		num_formats = ARRAY_SIZE(snb_sprite_formats);
+
+		plane_funcs = &snb_sprite_funcs;
+	} else {
+		if (display->platform.sandybridge) {
+			formats = snb_sprite_formats;
+			num_formats = ARRAY_SIZE(snb_sprite_formats);
+
+			plane_funcs = &snb_sprite_funcs;
+		} else {
+			formats = g4x_sprite_formats;
+			num_formats = ARRAY_SIZE(g4x_sprite_formats);
+
+			plane_funcs = &g4x_sprite_funcs;
+		}
+	}
+
+	if (display->platform.cherryview && pipe == PIPE_B) {
+		supported_rotations =
+			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
+			DRM_MODE_REFLECT_X;
+	} else {
+		supported_rotations =
+			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
+	}
+
+	modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_TILING_X);
+
+	plane = drmm_universal_plane_alloc(display->drm, struct intel_plane, base,
+					   0, plane_funcs,
+					   formats, num_formats, modifiers,
+					   DRM_PLANE_TYPE_OVERLAY,
+					   "sprite %c", sprite_name(display, pipe, sprite));
+	kfree(modifiers);
 
-	plane = intel_plane_alloc();
 	if (IS_ERR(plane))
 		return plane;
 
+	plane->pipe = pipe;
+	plane->id = PLANE_SPRITE0 + sprite;
+	plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
+
 	if (display->platform.valleyview || display->platform.cherryview) {
 		plane->update_noarm = vlv_sprite_update_noarm;
 		plane->update_arm = vlv_sprite_update_arm;
@@ -1621,16 +1670,6 @@ intel_sprite_plane_create(struct intel_display *display,
 		/* FIXME undocumented for VLV/CHV so not sure what's actually needed */
 		if (intel_scanout_needs_vtd_wa(display))
 			plane->vtd_guard = 128;
-
-		if (display->platform.cherryview && pipe == PIPE_B) {
-			formats = chv_pipe_b_sprite_formats;
-			num_formats = ARRAY_SIZE(chv_pipe_b_sprite_formats);
-		} else {
-			formats = vlv_sprite_formats;
-			num_formats = ARRAY_SIZE(vlv_sprite_formats);
-		}
-
-		plane_funcs = &vlv_sprite_funcs;
 	} else if (DISPLAY_VER(display) >= 7) {
 		plane->update_noarm = ivb_sprite_update_noarm;
 		plane->update_arm = ivb_sprite_update_arm;
@@ -1652,11 +1691,6 @@ intel_sprite_plane_create(struct intel_display *display,
 
 		if (intel_scanout_needs_vtd_wa(display))
 			plane->vtd_guard = 64;
-
-		formats = snb_sprite_formats;
-		num_formats = ARRAY_SIZE(snb_sprite_formats);
-
-		plane_funcs = &snb_sprite_funcs;
 	} else {
 		plane->update_noarm = g4x_sprite_update_noarm;
 		plane->update_arm = g4x_sprite_update_arm;
@@ -1671,44 +1705,14 @@ intel_sprite_plane_create(struct intel_display *display,
 
 		if (intel_scanout_needs_vtd_wa(display))
 			plane->vtd_guard = 64;
-
-		if (display->platform.sandybridge) {
-			formats = snb_sprite_formats;
-			num_formats = ARRAY_SIZE(snb_sprite_formats);
-
-			plane_funcs = &snb_sprite_funcs;
-		} else {
-			formats = g4x_sprite_formats;
-			num_formats = ARRAY_SIZE(g4x_sprite_formats);
-
-			plane_funcs = &g4x_sprite_funcs;
-		}
 	}
 
-	if (display->platform.cherryview && pipe == PIPE_B) {
-		supported_rotations =
-			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
-			DRM_MODE_REFLECT_X;
-	} else {
-		supported_rotations =
-			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
-	}
+	plane_state = kzalloc_obj(*plane_state);
+	if (!plane_state)
+		return ERR_PTR(-ENOMEM);
 
-	plane->pipe = pipe;
-	plane->id = PLANE_SPRITE0 + sprite;
-	plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
-
-	modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_TILING_X);
-
-	ret = drm_universal_plane_init(display->drm, &plane->base,
-				       0, plane_funcs,
-				       formats, num_formats, modifiers,
-				       DRM_PLANE_TYPE_OVERLAY,
-				       "sprite %c", sprite_name(display, pipe, sprite));
-	kfree(modifiers);
-
-	if (ret)
-		goto fail;
+	intel_plane_state_reset(plane_state, plane);
+	plane->base.state = &plane_state->uapi;
 
 	drm_plane_create_rotation_property(&plane->base,
 					   DRM_MODE_ROTATE_0,
@@ -1728,9 +1732,4 @@ intel_sprite_plane_create(struct intel_display *display,
 	intel_plane_helper_add(plane);
 
 	return plane;
-
-fail:
-	intel_plane_free(plane);
-
-	return ERR_PTR(ret);
 }
diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c
index 11ba42c67e3ed..6d6b108bf7e46 100644
--- a/drivers/gpu/drm/i915/display/skl_universal_plane.c
+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c
@@ -7,6 +7,7 @@
 #include <drm/drm_blend.h>
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_fourcc.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 
 #include "intel_bo.h"
@@ -2690,7 +2691,6 @@ static bool tgl_plane_format_mod_supported(struct drm_plane *_plane,
 static const struct drm_plane_funcs skl_plane_funcs = {
 	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = intel_plane_destroy,
 	.atomic_duplicate_state = intel_plane_duplicate_state,
 	.atomic_destroy_state = intel_plane_destroy_state,
 	.format_mod_supported = skl_plane_format_mod_supported,
@@ -2700,7 +2700,6 @@ static const struct drm_plane_funcs skl_plane_funcs = {
 static const struct drm_plane_funcs icl_plane_funcs = {
 	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = intel_plane_destroy,
 	.atomic_duplicate_state = intel_plane_duplicate_state,
 	.atomic_destroy_state = intel_plane_destroy_state,
 	.format_mod_supported = icl_plane_format_mod_supported,
@@ -2710,7 +2709,6 @@ static const struct drm_plane_funcs icl_plane_funcs = {
 static const struct drm_plane_funcs tgl_plane_funcs = {
 	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = intel_plane_destroy,
 	.atomic_duplicate_state = intel_plane_duplicate_state,
 	.atomic_destroy_state = intel_plane_destroy_state,
 	.format_mod_supported = tgl_plane_format_mod_supported,
@@ -2850,6 +2848,7 @@ struct intel_plane *
 skl_universal_plane_create(struct intel_display *display,
 			   enum pipe pipe, enum plane_id plane_id)
 {
+	struct intel_plane_state *plane_state;
 	const struct drm_plane_funcs *plane_funcs;
 	struct intel_plane *plane;
 	enum drm_plane_type plane_type;
@@ -2858,10 +2857,50 @@ skl_universal_plane_create(struct intel_display *display,
 	const u64 *modifiers;
 	const u32 *formats;
 	int num_formats;
-	int ret;
 	u8 caps;
 
-	plane = intel_plane_alloc();
+	if (DISPLAY_VER(display) >= 11)
+		formats = icl_get_plane_formats(display, pipe,
+						plane_id, &num_formats);
+	else if (DISPLAY_VER(display) >= 10)
+		formats = glk_get_plane_formats(display, pipe,
+						plane_id, &num_formats);
+	else
+		formats = skl_get_plane_formats(display, pipe,
+						plane_id, &num_formats);
+
+	if (DISPLAY_VER(display) >= 12)
+		plane_funcs = &tgl_plane_funcs;
+	else if (DISPLAY_VER(display) == 11)
+		plane_funcs = &icl_plane_funcs;
+	else
+		plane_funcs = &skl_plane_funcs;
+
+	if (plane_id == PLANE_1)
+		plane_type = DRM_PLANE_TYPE_PRIMARY;
+	else
+		plane_type = DRM_PLANE_TYPE_OVERLAY;
+
+	if (DISPLAY_VER(display) >= 12)
+		caps = tgl_plane_caps(display, pipe, plane_id);
+	else if (DISPLAY_VER(display) == 11)
+		caps = icl_plane_caps(display, pipe, plane_id);
+	else if (DISPLAY_VER(display) == 10)
+		caps = glk_plane_caps(display, pipe, plane_id);
+	else
+		caps = skl_plane_caps(display, pipe, plane_id);
+
+	modifiers = intel_fb_plane_get_modifiers(display, caps);
+
+	plane = drmm_universal_plane_alloc(display->drm, struct intel_plane, base,
+					   0, plane_funcs,
+					   formats, num_formats, modifiers,
+					   plane_type,
+					   "plane %d%c", plane_id + 1,
+					   pipe_name(pipe));
+
+	kfree(modifiers);
+
 	if (IS_ERR(plane))
 		return plane;
 
@@ -2940,50 +2979,12 @@ skl_universal_plane_create(struct intel_display *display,
 			plane->can_async_flip = skl_plane_can_async_flip;
 	}
 
-	if (DISPLAY_VER(display) >= 11)
-		formats = icl_get_plane_formats(display, pipe,
-						plane_id, &num_formats);
-	else if (DISPLAY_VER(display) >= 10)
-		formats = glk_get_plane_formats(display, pipe,
-						plane_id, &num_formats);
-	else
-		formats = skl_get_plane_formats(display, pipe,
-						plane_id, &num_formats);
+	plane_state = kzalloc_obj(*plane_state);
+	if (!plane_state)
+		return ERR_PTR(-ENOMEM);
 
-	if (DISPLAY_VER(display) >= 12)
-		plane_funcs = &tgl_plane_funcs;
-	else if (DISPLAY_VER(display) == 11)
-		plane_funcs = &icl_plane_funcs;
-	else
-		plane_funcs = &skl_plane_funcs;
-
-	if (plane_id == PLANE_1)
-		plane_type = DRM_PLANE_TYPE_PRIMARY;
-	else
-		plane_type = DRM_PLANE_TYPE_OVERLAY;
-
-	if (DISPLAY_VER(display) >= 12)
-		caps = tgl_plane_caps(display, pipe, plane_id);
-	else if (DISPLAY_VER(display) == 11)
-		caps = icl_plane_caps(display, pipe, plane_id);
-	else if (DISPLAY_VER(display) == 10)
-		caps = glk_plane_caps(display, pipe, plane_id);
-	else
-		caps = skl_plane_caps(display, pipe, plane_id);
-
-	modifiers = intel_fb_plane_get_modifiers(display, caps);
-
-	ret = drm_universal_plane_init(display->drm, &plane->base,
-				       0, plane_funcs,
-				       formats, num_formats, modifiers,
-				       plane_type,
-				       "plane %d%c", plane_id + 1,
-				       pipe_name(pipe));
-
-	kfree(modifiers);
-
-	if (ret)
-		goto fail;
+	intel_plane_state_reset(plane_state, plane);
+	plane->base.state = &plane_state->uapi;
 
 	if (DISPLAY_VER(display) >= 13)
 		supported_rotations = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
@@ -3033,11 +3034,6 @@ skl_universal_plane_create(struct intel_display *display,
 	intel_plane_helper_add(plane);
 
 	return plane;
-
-fail:
-	intel_plane_free(plane);
-
-	return ERR_PTR(ret);
 }
 
 void

-- 
2.43.0



^ permalink raw reply related

* [PATCH RFC 05/12] drm/i915/display: Switch to managed for crtc
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
  To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
	David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
	Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
	Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
  Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
	intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
	linux-arm-kernel, Simona Vetter, Kory Maincent
In-Reply-To: <20260409-feat_link_cap-v1-0-7069e8199ce2@bootlin.com>

The current i915 driver uses non-managed function to create crtc. It
is not an issue yet, but in order to comply with the latest DRM
requirement, convert this code to use drm and device managed helpers.

Assisted-by: Claude Code:2.1.90
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
 drivers/gpu/drm/i915/display/intel_crtc.c | 102 ++++++++++--------------------
 1 file changed, 35 insertions(+), 67 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
index b8189cd5d864a..e2f995313acf2 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
@@ -8,6 +8,7 @@
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_fourcc.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_plane.h>
 #include <drm/drm_print.h>
 #include <drm/drm_vblank.h>
@@ -191,41 +192,11 @@ void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
 	crtc_state->max_link_bpp_x16 = INT_MAX;
 }
 
-static struct intel_crtc *intel_crtc_alloc(void)
+static void intel_crtc_vblank_pm_qos_cleanup(struct drm_device *drm, void *data)
 {
-	struct intel_crtc_state *crtc_state;
-	struct intel_crtc *crtc;
-
-	crtc = kzalloc_obj(*crtc);
-	if (!crtc)
-		return ERR_PTR(-ENOMEM);
-
-	crtc_state = intel_crtc_state_alloc(crtc);
-	if (!crtc_state) {
-		kfree(crtc);
-		return ERR_PTR(-ENOMEM);
-	}
-
-	crtc->base.state = &crtc_state->uapi;
-	crtc->config = crtc_state;
-
-	return crtc;
-}
-
-static void intel_crtc_free(struct intel_crtc *crtc)
-{
-	intel_crtc_destroy_state(&crtc->base, crtc->base.state);
-	kfree(crtc);
-}
-
-static void intel_crtc_destroy(struct drm_crtc *_crtc)
-{
-	struct intel_crtc *crtc = to_intel_crtc(_crtc);
+	struct intel_crtc *crtc = data;
 
 	cpu_latency_qos_remove_request(&crtc->vblank_pm_qos);
-
-	drm_crtc_cleanup(&crtc->base);
-	kfree(crtc);
 }
 
 static int intel_crtc_late_register(struct drm_crtc *crtc)
@@ -236,7 +207,6 @@ static int intel_crtc_late_register(struct drm_crtc *crtc)
 
 #define INTEL_CRTC_FUNCS \
 	.set_config = drm_atomic_helper_set_config, \
-	.destroy = intel_crtc_destroy, \
 	.page_flip = drm_atomic_helper_page_flip, \
 	.atomic_duplicate_state = intel_crtc_duplicate_state, \
 	.atomic_destroy_state = intel_crtc_destroy_state, \
@@ -311,28 +281,19 @@ static const struct drm_crtc_funcs i8xx_crtc_funcs = {
 static int __intel_crtc_init(struct intel_display *display, enum pipe pipe)
 {
 	struct intel_plane *primary, *cursor;
+	struct intel_crtc_state *crtc_state;
 	const struct drm_crtc_funcs *funcs;
 	struct intel_crtc *crtc;
+	u32 plane_ids_mask = 0;
 	int sprite, ret;
 
-	crtc = intel_crtc_alloc();
-	if (IS_ERR(crtc))
-		return PTR_ERR(crtc);
-
-	crtc->pipe = pipe;
-	crtc->num_scalers = DISPLAY_RUNTIME_INFO(display)->num_scalers[pipe];
-
 	if (DISPLAY_VER(display) >= 9)
 		primary = skl_universal_plane_create(display, pipe, PLANE_1);
 	else
 		primary = intel_primary_plane_create(display, pipe);
-	if (IS_ERR(primary)) {
-		ret = PTR_ERR(primary);
-		goto fail;
-	}
-	crtc->plane_ids_mask |= BIT(primary->id);
-
-	intel_init_fifo_underrun_reporting(display, crtc, false);
+	if (IS_ERR(primary))
+		return PTR_ERR(primary);
+	plane_ids_mask |= BIT(primary->id);
 
 	for_each_sprite(display, pipe, sprite) {
 		struct intel_plane *plane;
@@ -341,19 +302,15 @@ static int __intel_crtc_init(struct intel_display *display, enum pipe pipe)
 			plane = skl_universal_plane_create(display, pipe, PLANE_2 + sprite);
 		else
 			plane = intel_sprite_plane_create(display, pipe, sprite);
-		if (IS_ERR(plane)) {
-			ret = PTR_ERR(plane);
-			goto fail;
-		}
-		crtc->plane_ids_mask |= BIT(plane->id);
+		if (IS_ERR(plane))
+			return PTR_ERR(plane);
+		plane_ids_mask |= BIT(plane->id);
 	}
 
 	cursor = intel_cursor_plane_create(display, pipe);
-	if (IS_ERR(cursor)) {
-		ret = PTR_ERR(cursor);
-		goto fail;
-	}
-	crtc->plane_ids_mask |= BIT(cursor->id);
+	if (IS_ERR(cursor))
+		return PTR_ERR(cursor);
+	plane_ids_mask |= BIT(cursor->id);
 
 	if (HAS_GMCH(display)) {
 		if (display->platform.cherryview ||
@@ -376,11 +333,23 @@ static int __intel_crtc_init(struct intel_display *display, enum pipe pipe)
 			funcs = &ilk_crtc_funcs;
 	}
 
-	ret = drm_crtc_init_with_planes(display->drm, &crtc->base,
-					&primary->base, &cursor->base,
-					funcs, "pipe %c", pipe_name(pipe));
-	if (ret)
-		goto fail;
+	crtc = drmm_crtc_alloc_with_planes(display->drm, struct intel_crtc, base,
+					   &primary->base, &cursor->base,
+					   funcs, "pipe %c", pipe_name(pipe));
+	if (IS_ERR(crtc))
+		return PTR_ERR(crtc);
+
+	crtc->pipe = pipe;
+	crtc->num_scalers = DISPLAY_RUNTIME_INFO(display)->num_scalers[pipe];
+	crtc->plane_ids_mask = plane_ids_mask;
+
+	crtc_state = intel_crtc_state_alloc(crtc);
+	if (!crtc_state)
+		return -ENOMEM;
+	crtc->base.state = &crtc_state->uapi;
+	crtc->config = crtc_state;
+
+	intel_init_fifo_underrun_reporting(display, crtc, false);
 
 	if (DISPLAY_VER(display) >= 11)
 		drm_crtc_create_scaling_filter_property(&crtc->base,
@@ -393,17 +362,16 @@ static int __intel_crtc_init(struct intel_display *display, enum pipe pipe)
 
 	cpu_latency_qos_add_request(&crtc->vblank_pm_qos, PM_QOS_DEFAULT_VALUE);
 
+	ret = drmm_add_action_or_reset(display->drm, intel_crtc_vblank_pm_qos_cleanup, crtc);
+	if (ret)
+		return ret;
+
 	drm_WARN_ON(display->drm, drm_crtc_index(&crtc->base) != crtc->pipe);
 
 	if (HAS_CASF(display) && crtc->num_scalers >= 2)
 		drm_crtc_create_sharpness_strength_property(&crtc->base);
 
 	return 0;
-
-fail:
-	intel_crtc_free(crtc);
-
-	return ret;
 }
 
 int intel_crtc_init(struct intel_display *display)

-- 
2.43.0



^ permalink raw reply related

* [PATCH RFC 04/12] drm/i915/display: Switch to drmm_mode_config_init() and drop manual cleanup
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
  To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
	David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
	Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
	Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
  Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
	intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
	linux-arm-kernel, Simona Vetter, Kory Maincent
In-Reply-To: <20260409-feat_link_cap-v1-0-7069e8199ce2@bootlin.com>

Replace drm_mode_config_init() with drmm_mode_config_init() in
intel_mode_config_init(). The managed variant automatically registers
drm_mode_config_cleanup() with devres, so drivers must no longer call it
directly.

Since intel_mode_config_cleanup() was solely a wrapper combining
intel_atomic_global_obj_cleanup() and drm_mode_config_cleanup(), and the
latter is now handled by DRM core, remove it entirely. Instead, register
intel_atomic_global_obj_cleanup() as a devres action so it still runs just
before drm_mode_config_cleanup() during teardown, preserving the correct
cleanup ordering.

Change intel_mode_config_init() to return int to propagate any error from
drmm_mode_config_init().

Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
 .../gpu/drm/i915/display/intel_display_driver.c    | 37 ++++++++++++++--------
 1 file changed, 24 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c
index 23bfecc983e8d..d02393053cef4 100644
--- a/drivers/gpu/drm/i915/display/intel_display_driver.c
+++ b/drivers/gpu/drm/i915/display/intel_display_driver.c
@@ -12,6 +12,7 @@
 #include <drm/display/drm_dp_mst_helper.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_client_event.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_mode_config.h>
 #include <drm/drm_privacy_screen_consumer.h>
 #include <drm/drm_print.h>
@@ -48,6 +49,7 @@
 #include "intel_fbdev.h"
 #include "intel_fdi.h"
 #include "intel_flipq.h"
+#include "intel_global_state.h"
 #include "intel_gmbus.h"
 #include "intel_hdcp.h"
 #include "intel_hotplug.h"
@@ -111,13 +113,28 @@ static const struct drm_mode_config_helper_funcs intel_mode_config_funcs = {
 	.atomic_commit_setup = drm_dp_mst_atomic_setup_commit,
 };
 
-static void intel_mode_config_init(struct intel_display *display)
+static void intel_atomic_global_obj_cleanup_action(struct drm_device *drm, void *data)
+{
+	intel_atomic_global_obj_cleanup((struct intel_display *)data);
+}
+
+static int intel_mode_config_init(struct intel_display *display)
 {
 	struct drm_mode_config *mode_config = &display->drm->mode_config;
+	int ret;
+
+	ret = drmm_mode_config_init(display->drm);
+	if (ret)
+		return ret;
 
-	drm_mode_config_init(display->drm);
 	INIT_LIST_HEAD(&display->global.obj_list);
 
+	ret = drmm_add_action_or_reset(display->drm,
+				       intel_atomic_global_obj_cleanup_action,
+				       display);
+	if (ret)
+		return ret;
+
 	mode_config->min_width = 0;
 	mode_config->min_height = 0;
 
@@ -148,12 +165,8 @@ static void intel_mode_config_init(struct intel_display *display)
 	}
 
 	intel_cursor_mode_config_init(display);
-}
 
-static void intel_mode_config_cleanup(struct intel_display *display)
-{
-	intel_atomic_global_obj_cleanup(display);
-	drm_mode_config_cleanup(display->drm);
+	return 0;
 }
 
 static void intel_plane_possible_crtcs_init(struct intel_display *display)
@@ -255,7 +268,9 @@ int intel_display_driver_probe_noirq(struct intel_display *display)
 
 	intel_dmc_init(display);
 
-	intel_mode_config_init(display);
+	ret = intel_mode_config_init(display);
+	if (ret)
+		goto cleanup_wq_unordered;
 
 	ret = intel_cdclk_init(display);
 	if (ret)
@@ -456,7 +471,7 @@ int intel_display_driver_probe_nogem(struct intel_display *display)
 
 	ret = intel_crtc_init(display);
 	if (ret)
-		goto err_mode_config;
+		return ret;
 
 	intel_plane_possible_crtcs_init(display);
 	intel_dpll_init(display);
@@ -497,8 +512,6 @@ int intel_display_driver_probe_nogem(struct intel_display *display)
 
 err_hdcp:
 	intel_hdcp_component_fini(display);
-err_mode_config:
-	intel_mode_config_cleanup(display);
 
 	return ret;
 }
@@ -618,8 +631,6 @@ void intel_display_driver_remove_noirq(struct intel_display *display)
 
 	intel_hdcp_component_fini(display);
 
-	intel_mode_config_cleanup(display);
-
 	intel_dp_tunnel_mgr_cleanup(display);
 
 	intel_overlay_cleanup(display);

-- 
2.43.0



^ permalink raw reply related

* [PATCH RFC 03/12] drm/i915/display/intel_dp: Drop redundant intel_dp_aux_fini() on init failure
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
  To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
	David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
	Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
	Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
  Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
	intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
	linux-arm-kernel, Simona Vetter, Kory Maincent
In-Reply-To: <20260409-feat_link_cap-v1-0-7069e8199ce2@bootlin.com>

intel_dp_aux_fini() is already invoked via intel_dp_encoder_flush_work()
in the encoder destroy path (intel_dp_encoder_destroy() and
intel_ddi_encoder_destroy()). Calling it explicitly when
intel_edp_init_connector() fails before jumping to the fail label
therefore results in a double invocation. Drop the redundant call.

Fixes: c191eca110a37 ("drm/i915: Move intel_connector->unregister to connector->early_unregister")
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 4955bd8b11d7a..71f206adbebd3 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -7232,10 +7232,8 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
 		connector->get_hw_state = intel_connector_get_hw_state;
 	connector->sync_state = intel_dp_connector_sync_state;
 
-	if (!intel_edp_init_connector(intel_dp, connector)) {
-		intel_dp_aux_fini(intel_dp);
+	if (!intel_edp_init_connector(intel_dp, connector))
 		goto fail;
-	}
 
 	intel_dp_set_source_rates(intel_dp);
 	intel_dp_set_common_rates(intel_dp);

-- 
2.43.0



^ permalink raw reply related

* [PATCH RFC 02/12] drm/i915/display/intel_lvds: Drop redundant manual cleanup on init failure
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
  To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
	David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
	Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
	Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
  Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
	intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
	linux-arm-kernel, Simona Vetter, Kory Maincent
In-Reply-To: <20260409-feat_link_cap-v1-0-7069e8199ce2@bootlin.com>

intel_lvds_init() had a goto-based error path that manually called
drm_connector_cleanup(), drm_encoder_cleanup(), kfree() and
intel_connector_free() when no LVDS panel mode could be found.

Once drm_connector_init_with_ddc() and drm_encoder_init() have been
called, the DRM core takes ownership of these objects and will invoke
their .destroy callbacks (intel_connector_destroy and
intel_encoder_destroy) during device teardown. The manual cleanup in
the failed: label is therefore redundant.

Remove it and replace the goto with a simple early return.

Fixes: 79e539453b34e ("DRM: i915: add mode setting support")
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---

Not tested as I don't have such hardware.
---
 drivers/gpu/drm/i915/display/intel_lvds.c | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index cc6d4bfcff102..e78a41e2b268c 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -991,8 +991,10 @@ void intel_lvds_init(struct intel_display *display)
 	mutex_unlock(&display->drm->mode_config.mutex);
 
 	/* If we still don't have a mode after all that, give up. */
-	if (!intel_panel_preferred_fixed_mode(connector))
-		goto failed;
+	if (!intel_panel_preferred_fixed_mode(connector)) {
+		drm_dbg_kms(display->drm, "No LVDS modes found, disabling.\n");
+		return;
+	}
 
 	intel_panel_init(connector, drm_edid);
 
@@ -1005,12 +1007,4 @@ void intel_lvds_init(struct intel_display *display)
 	lvds_encoder->a3_power = lvds & LVDS_A3_POWER_MASK;
 
 	return;
-
-failed:
-	drm_dbg_kms(display->drm, "No LVDS modes found, disabling.\n");
-	drm_connector_cleanup(&connector->base);
-	drm_encoder_cleanup(&encoder->base);
-	kfree(lvds_encoder);
-	intel_connector_free(connector);
-	return;
 }

-- 
2.43.0



^ permalink raw reply related

* [PATCH RFC 00/12] Add support for DisplayPort link training information report
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
  To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
	David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
	Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
	Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
  Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
	intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
	linux-arm-kernel, Simona Vetter, Kory Maincent

DisplayPort link training negotiates the physical-layer parameters needed
for a reliable connection: lane count, link rate, voltage swing,
pre-emphasis, and optionally Display Stream Compression (DSC). Currently,
each driver exposes this state in its own way, often through
driver-specific debugfs entries, with no standard interface for userspace
diagnostic and monitoring tools.

This series introduces a generic, DRM-managed framework for exposing DP
link training state as standard connector properties, modeled after the
existing HDMI helper drmm_connector_hdmi_init().

The new drmm_connector_dp_init() helper initializes a DP connector and
registers the following connector properties to expose the negotiated link
state to userspace:

- num_lanes:      negotiated lane count (1, 2 or 4)
- link_rate:      negotiated link rate
- dsc_en:         whether Display Stream Compression is active
- voltage_swingN: per-lane voltage swing level (lanes 0-3)
- pre_emphasisN:  per-lane pre-emphasis level (lanes 0-3)

Two runtime helpers update and clear these properties when link training
completes or the link goes down:
- drm_connector_dp_set_link_train_properties()
- drm_connector_dp_reset_link_train_properties()

Two drivers are updated as reference implementations: i915 (direct
connector path) and MediaTek (via the bridge connector framework using a
new DRM_BRIDGE_OP_DP flag). The i915 patches are preceded by a series of
conversions to DRM managed resources, which are required before adopting
drmm_connector_dp_init().

The MST case in i915 driver is not supported yet.

Patches 1-3:  Fix two error-path cleanup bugs in i915 sdvo and lvds
[Will probably be sent standalone]
Patches 4-8: Convert i915 display resources to DRM managed lifetime
Patch 9: Introduce the core drmm_connector_dp_init() framework
Patch 10: Wire the i915 DP connector to use the new helpers
Patch 11: Introduce DRM_BRIDGE_OP_DP and wire bridge connectors
Patch 12: Wire the MediaTek DP bridge to the new helpers [untested]

Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---
Kory Maincent (12):
      drm/i915/display/intel_sdvo: Fix double connector destroy in error paths
      drm/i915/display/intel_lvds: Drop redundant manual cleanup on init failure
      drm/i915/display/intel_dp: Drop redundant intel_dp_aux_fini() on init failure
      drm/i915/display: Switch to drmm_mode_config_init() and drop manual cleanup
      drm/i915/display: Switch to managed for crtc
      drm/i915/display: Switch to managed for plane
      drm/i915/display: Switch to managed for encoder
      drm/i915/display: Switch to managed for connector
      drm: Introduce drmm_connector_dp_init() with link training state properties
      drm/i915/display/dp: Adopt dp_connector helpers to expose link training state
      drm/bridge: Wire drmm_connector_dp_init() via new DRM_BRIDGE_OP_DP flag
      drm/mediatek: Use dp_connector helpers to report link training state

 drivers/gpu/drm/Makefile                           |   1 +
 drivers/gpu/drm/display/drm_bridge_connector.c     |  26 +-
 drivers/gpu/drm/drm_dp_connector.c                 | 344 +++++++++++++++++++++
 drivers/gpu/drm/i915/display/g4x_dp.c              |  39 +--
 drivers/gpu/drm/i915/display/g4x_hdmi.c            |  27 +-
 drivers/gpu/drm/i915/display/i9xx_plane.c          |  97 +++---
 drivers/gpu/drm/i915/display/icl_dsi.c             |  50 ++-
 drivers/gpu/drm/i915/display/intel_connector.c     |  26 +-
 drivers/gpu/drm/i915/display/intel_connector.h     |   5 +-
 drivers/gpu/drm/i915/display/intel_crt.c           |  28 +-
 drivers/gpu/drm/i915/display/intel_crtc.c          | 102 +++---
 drivers/gpu/drm/i915/display/intel_cursor.c        |  41 ++-
 drivers/gpu/drm/i915/display/intel_ddi.c           |  64 ++--
 drivers/gpu/drm/i915/display/intel_display.c       |   8 -
 drivers/gpu/drm/i915/display/intel_display.h       |   1 -
 .../gpu/drm/i915/display/intel_display_driver.c    |  37 ++-
 drivers/gpu/drm/i915/display/intel_dp.c            |  43 ++-
 .../gpu/drm/i915/display/intel_dp_link_training.c  |  25 ++
 drivers/gpu/drm/i915/display/intel_dp_mst.c        |  33 +-
 drivers/gpu/drm/i915/display/intel_dvo.c           |  43 +--
 drivers/gpu/drm/i915/display/intel_encoder.c       |   6 +-
 drivers/gpu/drm/i915/display/intel_encoder.h       |   3 +-
 drivers/gpu/drm/i915/display/intel_hdmi.c          |  15 +-
 drivers/gpu/drm/i915/display/intel_lvds.c          |  45 ++-
 drivers/gpu/drm/i915/display/intel_plane.c         |  45 +--
 drivers/gpu/drm/i915/display/intel_plane.h         |   5 +-
 drivers/gpu/drm/i915/display/intel_sdvo.c          | 134 +++-----
 drivers/gpu/drm/i915/display/intel_sprite.c        | 119 ++++---
 drivers/gpu/drm/i915/display/intel_tv.c            |  26 +-
 drivers/gpu/drm/i915/display/skl_universal_plane.c | 102 +++---
 drivers/gpu/drm/i915/display/vlv_dsi.c             |  42 +--
 drivers/gpu/drm/mediatek/mtk_dp.c                  |  34 +-
 include/drm/drm_bridge.h                           |  13 +
 include/drm/drm_connector.h                        |  38 +++
 include/drm/drm_dp_connector.h                     | 109 +++++++
 35 files changed, 1125 insertions(+), 651 deletions(-)
---
base-commit: db5a75cfd29766536be62aece9f19c6e7a858fa6
change-id: 20260226-feat_link_cap-20cbb6f31d40

Best regards,
-- 
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com



^ permalink raw reply

* [PATCH RFC 01/12] drm/i915/display/intel_sdvo: Fix double connector destroy in error paths
From: Kory Maincent @ 2026-04-09 17:08 UTC (permalink / raw)
  To: Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
	David Airlie, Simona Vetter, Dave Airlie, Jesse Barnes,
	Eric Anholt, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
	Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson
  Cc: Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
	intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
	linux-arm-kernel, Simona Vetter, Kory Maincent
In-Reply-To: <20260409-feat_link_cap-v1-0-7069e8199ce2@bootlin.com>

intel_sdvo_connector_funcs registers intel_connector_destroy() as the
.destroy callback. Once drm_connector_init_with_ddc() succeeds inside
intel_sdvo_connector_init(), the DRM core takes ownership of the
connector object and will call .destroy on teardown.

The error labels in intel_sdvo_tv_init() and intel_sdvo_lvds_init()
call intel_connector_destroy() explicitly before returning false,
causing it to be invoked twice: once in the error path and again by
the DRM core through the registered .destroy callback.

Remove the manual intel_connector_destroy() calls from the error labels
and return false directly instead.

Fixes: 32aad86fe88e7 ("drm/i915/sdvo: Propagate errors from reading/writing control bus.")
Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
---

Not tested as I don't have such hardware.
---
 drivers/gpu/drm/i915/display/intel_sdvo.c | 16 ++++------------
 1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index 2e1af9e869ded..6eb2b4b45a9b4 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -2873,16 +2873,12 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, u16 type)
 	}
 
 	if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
-		goto err;
+		return false;
 
 	if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
-		goto err;
+		return false;
 
 	return true;
-
-err:
-	intel_connector_destroy(connector);
-	return false;
 }
 
 static bool
@@ -2945,7 +2941,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
 	}
 
 	if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
-		goto err;
+		return false;
 
 	intel_bios_init_panel_late(display, &intel_connector->panel, NULL, NULL);
 
@@ -2967,13 +2963,9 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
 	intel_panel_init(intel_connector, NULL);
 
 	if (!intel_panel_preferred_fixed_mode(intel_connector))
-		goto err;
+		return false;
 
 	return true;
-
-err:
-	intel_connector_destroy(connector);
-	return false;
 }
 
 static u16 intel_sdvo_filter_output_flags(u16 flags)

-- 
2.43.0



^ permalink raw reply related

* Re: [PATCH] KVM: arm64: Add KVM_CAP_ARM_NATIVE_CACHE_CONFIG vcpu capability
From: Marc Zyngier @ 2026-04-09 17:07 UTC (permalink / raw)
  To: David Woodhouse
  Cc: Gutierrez Cantu, Bernardo, alexandru.elisei, alyssa, asahi,
	broonie, catalin.marinas, james.morse, kvmarm, linux-arm-kernel,
	linux-kernel, marcan, mathieu.poirier, oliver.upton,
	suzuki.poulose, sven, will
In-Reply-To: <7fb7b823c68e04321eb532a5b8ae21a818d4926d.camel@infradead.org>

On Thu, 09 Apr 2026 16:29:06 +0100,
David Woodhouse <dwmw2@infradead.org> wrote:
> 
> [1  <text/plain; UTF-8 (quoted-printable)>]
> From: David Woodhouse <dwmw@amazon.co.uk>
> 
> Commit 7af0c2534f4c5 ("KVM: arm64: Normalize cache configuration")
> fabricates CLIDR_EL1 and CCSIDR_EL1 values instead of using the real
> hardware values. While this provides consistent values across
> heterogeneous CPUs, it does cause visible changes in the CPU model
> exposed to guests.
> 
> The commit claims that userspace can restore the original values, but
> there is no way for userspace to obtain the real CLIDR_EL1 register
> value — it is not fully reconstructible from sysfs, which lacks the
> LoC, LoUU, and LoUIS fields.
> 
> Add a per-vcpu KVM_CAP_ARM_NATIVE_CACHE_CONFIG capability that reads
> the real CLIDR_EL1 and all CCSIDR_EL1 values from the current physical
> CPU and sets them on the vcpu.
> 
> This allows hypervisors to present the real hardware cache configuration
> to guests, which is important for consistency of the environment across
> kernel versions and for migration compatibility with hosts running
> older kernels that exposed the real values.
> 
> Fixes: 7af0c2534f4c ("KVM: arm64: Normalize cache configuration")
> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
> ---
>  Documentation/virt/kvm/api.rst                | 23 ++++++++
>  arch/arm64/include/asm/kvm_host.h             |  1 +
>  arch/arm64/kvm/arm.c                          | 17 ++++++
>  arch/arm64/kvm/sys_regs.c                     | 26 ++++++++++
>  include/uapi/linux/kvm.h                      |  1 +
>  tools/testing/selftests/kvm/Makefile.kvm      |  1 +
>  .../selftests/kvm/arm64/native_cache_config.c | 52 +++++++++++++++++++
>  7 files changed, 121 insertions(+)
>  create mode 100644 tools/testing/selftests/kvm/arm64/native_cache_config.c
> 
> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> index e3b3bd9edeec..ee47dc07ceac 100644
> --- a/Documentation/virt/kvm/api.rst
> +++ b/Documentation/virt/kvm/api.rst
> @@ -8930,6 +8930,29 @@ no-op.
>  
>  ``KVM_CHECK_EXTENSION`` returns the bitmask of exits that can be disabled.
>  
> +7.48 KVM_CAP_ARM_NATIVE_CACHE_CONFIG
> +-------------------------------------
> +
> +:Architecture: arm64
> +:Target: vcpu
> +:Parameters: none
> +:Returns: 0 on success, -ENOMEM on allocation failure, -EINVAL if
> +          args[0] or flags are non-zero.
> +
> +This per-vcpu capability reads the real CLIDR_EL1 and CCSIDR_EL1 values
> +from the physical CPU on which the ioctl is executed, and sets them on
> +the vcpu. This replaces the fabricated cache configuration that KVM
> +provides by default.
> +
> +The caller should ensure the vcpu thread is pinned to the desired
> +physical CPU before invoking this capability, so that the correct cache
> +topology is captured. On heterogeneous systems, different physical CPUs
> +may have different cache configurations.
> +
> +After this capability is enabled, the vcpu's CLIDR_EL1 and CCSIDR_EL1
> +values can still be overridden individually via ``KVM_SET_ONE_REG`` and
> +the ``KVM_REG_ARM_DEMUX`` interface.
> +
>  8. Other capabilities.
>  ======================
>  
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index a1bb025c641f..c9713a472c47 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -1296,6 +1296,7 @@ void kvm_sys_regs_create_debugfs(struct kvm *kvm);
>  void kvm_reset_sys_regs(struct kvm_vcpu *vcpu);
>  
>  int __init kvm_sys_reg_table_init(void);
> +int kvm_vcpu_set_native_cache_config(struct kvm_vcpu *vcpu);
>  struct sys_reg_desc;
>  int __init populate_sysreg_config(const struct sys_reg_desc *sr,
>  				  unsigned int idx);
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index 326a99fea753..579583e8dc5c 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -393,6 +393,10 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>  	case KVM_CAP_ARM_DISABLE_EXITS:
>  		r = KVM_ARM_DISABLE_VALID_EXITS;
>  		break;
> +	case KVM_CAP_ARM_NATIVE_CACHE_CONFIG:
> +	case KVM_CAP_ENABLE_CAP:
> +		r = 1;
> +		break;
>  	case KVM_CAP_SET_GUEST_DEBUG2:
>  		return KVM_GUESTDBG_VALID_MASK;
>  	case KVM_CAP_ARM_SET_DEVICE_ADDR:
> @@ -1793,6 +1797,19 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>  		r = kvm_arch_vcpu_ioctl_vcpu_init(vcpu, &init);
>  		break;
>  	}
> +	case KVM_ENABLE_CAP: {
> +		struct kvm_enable_cap cap;
> +
> +		r = -EFAULT;
> +		if (copy_from_user(&cap, argp, sizeof(cap)))
> +			break;
> +
> +		r = -EINVAL;
> +		if (cap.cap == KVM_CAP_ARM_NATIVE_CACHE_CONFIG &&
> +		    !cap.args[0] && !cap.flags)
> +			r = kvm_vcpu_set_native_cache_config(vcpu);
> +		break;
> +	}
>  	case KVM_SET_ONE_REG:
>  	case KVM_GET_ONE_REG: {
>  		struct kvm_one_reg reg;
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 1b4cacb6e918..c19d84e48f8b 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -484,6 +484,32 @@ static int set_ccsidr(struct kvm_vcpu *vcpu, u32 csselr, u32 val)
>  	return 0;
>  }
>  
> +int kvm_vcpu_set_native_cache_config(struct kvm_vcpu *vcpu)
> +{
> +	u32 csselr;
> +
> +	if (!vcpu->arch.ccsidr) {
> +		vcpu->arch.ccsidr = kmalloc_array(CSSELR_MAX, sizeof(u32),
> +						  GFP_KERNEL_ACCOUNT);
> +		if (!vcpu->arch.ccsidr)
> +			return -ENOMEM;
> +	}

Well, no.

The moment you decide to expose all of the host's crap, you really
need to put everything on the table. It means fully handling
FEAT_CCIDX, which we were careful not to expose anywhere because it is
a terrible idea.

So CCSIDR_EL1 becomes a 64bit value, is complemented with CCSIDR2_EL1,
and needs to be advertised as such through the idregs.  CCSIDR2_EL1
must be exposed to userspace and made writable, but only if the
feature exists. You also need to conditionally undef CCSIDR2_EL1
depending on the VM configuration.

The "amusing" thing is that, before we introduced the cache hierarchy
sanitisation, we would happily report something completely senseless
on CCIDX hardware. It didn't matter, because nobody can make any use
of that information, apart from EL3 firmware.

But if you want this to be a reflection of the underlying HW, then so
be it.

> +	for (csselr = 0; csselr < CSSELR_MAX; csselr++) {
> +		write_sysreg(csselr, csselr_el1);
> +		isb();
> +		vcpu->arch.ccsidr[csselr] = read_sysreg(ccsidr_el1);

That's not how the selection register works. CLIDR_EL1 tells you what
each cache level is (Instructions, Data, Unified, Tags), and that must
be combined with the index (which doesn't start at bit 0).

I also wonder how you reconcile not exposing MTE when the cache
hierarchy indicate support for tags. That clearly contradicts "report
what the HW has".

	M.

-- 
Without deviation from the norm, progress is not possible.


^ permalink raw reply

* Re: [PATCH V11 02/12] PCI: host-generic: Add common helpers for parsing Root Port properties
From: Manivannan Sadhasivam @ 2026-04-09 16:58 UTC (permalink / raw)
  To: Sherry Sun
  Cc: robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
	Frank Li, s.hauer@pengutronix.de, kernel@pengutronix.de,
	festevam@gmail.com, lpieralisi@kernel.org, kwilczynski@kernel.org,
	bhelgaas@google.com, Hongxing Zhu, l.stach@pengutronix.de,
	imx@lists.linux.dev, linux-pci@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <VI0PR04MB1211419BB996B4790AE04170F92582@VI0PR04MB12114.eurprd04.prod.outlook.com>

On Thu, Apr 09, 2026 at 02:58:21AM +0000, Sherry Sun wrote:
> > On Wed, Apr 08, 2026 at 06:34:02AM +0000, Sherry Sun wrote:
> > 
> > [...]
> > 
> > > > > +/**
> > > > > + * pci_host_common_parse_port - Parse a single Root Port node
> > > > > + * @dev: Device pointer
> > > > > + * @bridge: PCI host bridge
> > > > > + * @node: Device tree node of the Root Port
> > > > > + *
> > > > > + * Returns: 0 on success, negative error code on failure  */
> > > > > +static int pci_host_common_parse_port(struct device *dev,
> > > > > +				      struct pci_host_bridge *bridge,
> > > > > +				      struct device_node *node) {
> > > > > +	struct pci_host_port *port;
> > > > > +	struct gpio_desc *reset;
> > > > > +
> > > > > +	reset = devm_fwnode_gpiod_get(dev, of_fwnode_handle(node),
> > > > > +				      "reset", GPIOD_ASIS, "PERST#");
> > > >
> > > > Sorry, I missed this earlier.
> > > >
> > > > Since PERST# is optional, you cannot reliably detect whether the
> > > > Root Port binding intentionally skipped the PERST# GPIO or legacy
> > > > binding is used, just by checking for PERST# in Root Port node.
> > > >
> > > > So this helper should do 3 things:
> > > >
> > > > 1. If PERST# is found in Root Port node, use it.
> > > > 2. If not, check the RC node and if present, return -ENOENT to
> > > > fallback to the legacy binding.
> > > > 3. If not found in both nodes, assume that the PERST# is not present
> > > > in the design, and proceed with parsing Root Port binding further.
> > >
> > > Hi Mani, understand, does the following code looks ok for above three
> > cases?
> > >
> > >     /* Check if PERST# is present in Root Port node */
> > >     reset = devm_fwnode_gpiod_get(dev, of_fwnode_handle(node),
> > >                       "reset", GPIOD_ASIS, "PERST#");
> > >     if (IS_ERR(reset)) {
> > >         /* If error is not -ENOENT, it's a real error */
> > >         if (PTR_ERR(reset) != -ENOENT)
> > >             return PTR_ERR(reset);
> > >
> > >         /* PERST# not found in Root Port node, check RC node */
> > >         rc_has_reset = of_property_read_bool(dev->of_node, "reset-gpios") ||
> > >                    of_property_read_bool(dev->of_node, "reset-gpio");
> > 
> > Just:
> > 		if (of_property_read_bool(dev->of_node, "reset-gpios") ||
> > 		    of_property_read_bool(dev->of_node, "reset-gpio")) {
> > 			return -ENOENT;
> > 		}
> 
> Ok, will do.
> 
> > 
> > >         if (rc_has_reset)
> > >             return -ENOENT;
> > >
> > >         /* No PERST# in either node, assume not present in design */
> > >         reset = NULL;
> > >     }
> > >
> > >     port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> > >     if (!port)
> > >         return -ENOMEM;
> > > ...
> > >
> > > >
> > > > But there is one more important limitation here. Right now, this API
> > > > only handles PERST#. But if another vendor tries to use it and if
> > > > they need other properties such as PHY, clocks etc... those
> > > > resources should be fetched optionally only by this helper. But if
> > > > the controller has a hard dependency on those resources, the driver will
> > fail to operate.
> > > >
> > > > I don't think we can fix this limitation though and those platforms
> > > > should ensure that the resource dependency is correctly modeled in
> > > > DT binding and the DTS is validated properly. It'd be good to
> > > > mention this in the kernel doc of this API.
> > >
> > > Ok, I will add a NOTE for this in this API description.
> > >
> > > >
> > > > > +	if (IS_ERR(reset))
> > > > > +		return PTR_ERR(reset);
> > > > > +
> > > > > +	port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> > > > > +	if (!port)
> > > > > +		return -ENOMEM;
> > > > > +
> > > > > +	port->reset = reset;
> > > > > +	INIT_LIST_HEAD(&port->list);
> > > > > +	list_add_tail(&port->list, &bridge->ports);
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +/**
> > > > > + * pci_host_common_parse_ports - Parse Root Port nodes from
> > > > > +device tree
> > > > > + * @dev: Device pointer
> > > > > + * @bridge: PCI host bridge
> > > > > + *
> > > > > + * This function iterates through child nodes of the host bridge
> > > > > +and parses
> > > > > + * Root Port properties (currently only reset GPIO).
> > > > > + *
> > > > > + * Returns: 0 on success, -ENOENT if no ports found, other
> > > > > +negative error codes
> > > > > + * on failure
> > > > > + */
> > > > > +int pci_host_common_parse_ports(struct device *dev, struct
> > > > > +pci_host_bridge *bridge) {
> > > > > +	int ret = -ENOENT;
> > > > > +
> > > > > +	for_each_available_child_of_node_scoped(dev->of_node, of_port) {
> > > > > +		if (!of_node_is_type(of_port, "pci"))
> > > > > +			continue;
> > > > > +		ret = pci_host_common_parse_port(dev, bridge, of_port);
> > > > > +		if (ret)
> > > > > +			return ret;
> > > >
> > > > As Sashiko flagged, you need to make sure that
> > > > devm_add_action_or_reset() is added even during the error path:
> > >
> > > Yes, it needs to be fixed. We can handle it with the following two methods, I
> > am not sure which method is better or more preferable?
> > >
> > > #1: register cleanup action after first successful port parse and use
> > cleanup_registered flag to avoid duplicate register.
> > >     int ret = -ENOENT;
> > >     bool cleanup_registered = false;
> > >
> > >     for_each_available_child_of_node_scoped(dev->of_node, of_port) {
> > >         if (!of_node_is_type(of_port, "pci"))
> > >             continue;
> > >         ret = pci_host_common_parse_port(dev, bridge, of_port);
> > >         if (ret)
> > >             return ret;
> > >
> > >         /* Register cleanup action after first successful port parse */
> > >         if (!cleanup_registered) {
> > >             ret = devm_add_action_or_reset(dev,
> > >                                pci_host_common_delete_ports,
> > >                                &bridge->ports);
> > 
> > Even if you register devm_add_action_or_reset(), it won't be called when
> > pci_host_common_parse_port() fails since the legacy fallback will be used.
> > 
> > So you need to manually call pci_host_common_delete_ports() in the error
> > path.
> 
> Get your point, so seems I should just add the err_cleanup handle path like this, right?
> 
>     for_each_available_child_of_node_scoped(dev->of_node, of_port) {
>         if (!of_node_is_type(of_port, "pci"))
>             continue;
>         ret = pci_host_common_parse_port(dev, bridge, of_port);
>         if (ret)
>             goto err_cleanup;
>     }
> 
>     if (ret)
>         return ret;
> 
>     return devm_add_action_or_reset(dev, pci_host_common_delete_ports,
>                     &bridge->ports);
> 
> err_cleanup:
>     pci_host_common_delete_ports(&bridge->ports);
>     return ret;
> 

Yes!

- Mani

-- 
மணிவண்ணன் சதாசிவம்


^ permalink raw reply

* Re: [RFC net PATCH v1] net: pcs: pcs-mtk-lynxi: fix bpi-r3 serdes configuration
From: Vladimir Oltean @ 2026-04-09 16:49 UTC (permalink / raw)
  To: Frank Wunderlich, Chester A. Unal, Felix Fietkau
  Cc: Alexander Couzens, Daniel Golle, Andrew Lunn, Heiner Kallweit,
	Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Matthias Brugger, AngeloGioacchino Del Regno,
	Frank Wunderlich, netdev, linux-kernel, linux-arm-kernel,
	linux-mediatek
In-Reply-To: <20260409133344.129620-1-linux@fw-web.de>

On Thu, Apr 09, 2026 at 03:33:42PM +0200, Frank Wunderlich wrote:
> From: Frank Wunderlich <frank-w@public-files.de>
> 
> Commit 8871389da151 introduces common pcs dts properties which writes
> rx=normal,tx=normal polarity to register SGMSYS_QPHY_WRAP_CTRL of switch.
> This is initialized with tx-bit set and so change inverts polarity
> compared to before.
> 
> It looks like mt7531 has tx polarity inverted in hardware and set tx-bit
> by default to restore the normal polarity.
> 
> Till this patch the register write was only called when mediatek,pnswap
> property was set which cannot be done for switch because the fw-node param
> was always NULL from switch driver in the mtk_pcs_lynxi_create call.
> 
> Do not configure switch side like it's done before.
> 
> Fixes: 8871389da151 ("net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"")
> Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
> ---
>  drivers/net/pcs/pcs-mtk-lynxi.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c
> index c12f8087af9b..a753bd88cbc2 100644
> --- a/drivers/net/pcs/pcs-mtk-lynxi.c
> +++ b/drivers/net/pcs/pcs-mtk-lynxi.c
> @@ -129,6 +129,9 @@ static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs,
>         unsigned int val = 0;
>         int ret;
> 
> +       if (!fwnode)
> +               return 0;
> +
>         if (fwnode_property_read_bool(fwnode, "mediatek,pnswap"))
>                 default_pol = PHY_POL_INVERT;
> 
> --
> 2.43.0
>

I notice Arınc, listed by ./scripts/get_maintainer.pl drivers/net/dsa/mt7530.c,
and Felix, listed by ./scripts/get_maintainer.pl drivers/net/ethernet/mediatek/mtk_eth_soc.c,
are not on CC. Maybe they have more info.

Only the switch port has a chance of having a non-zero default polarity
setting? (coming from the efuse, if I understood this discussion properly)
https://lore.kernel.org/netdev/C59EED96-3973-4074-A4D8-C264949D447E@linux.dev/
The GMAC doesn't?


^ permalink raw reply

* Re: [PATCH v2 1/3] arm64: mm: Fix rodata=full block mapping support for realm guests
From: Yang Shi @ 2026-04-09 16:48 UTC (permalink / raw)
  To: Catalin Marinas, Kevin Brodsky
  Cc: Ryan Roberts, Will Deacon, David Hildenbrand (Arm), Dev Jain,
	Suzuki K Poulose, Jinjiang Tu, linux-arm-kernel, linux-kernel,
	stable
In-Reply-To: <adfDoatH8hj6zN7_@arm.com>



On 4/9/26 8:20 AM, Catalin Marinas wrote:
> On Thu, Apr 09, 2026 at 11:53:41AM +0200, Kevin Brodsky wrote:
>> On 07/04/2026 12:52, Catalin Marinas wrote:
>>>> if we have forced pte mapping then the value of
>>>> can_set_direct_map() is irrelevant - we will never need to split because we are
>>>> already pte-mapped.
>>> can_set_direct_map() is used in other places, so its value is
>>> relevant, e.g. sys_memfd_secret() is rejected if this function returns
>>> false.
>> Indeed, I have noticed this before: currently set_direct_map_*_noflush()
>> and other functions will either fail or do nothing if none of the
>> features (rodata=full, etc.) is enabled, even if we would be able to
>> split the linear map using BBML2-noabort.
> That's what I have been trying to say to Ryan ;), can_set_direct_map()
> has different meanings depending on the caller: hint that it might split
> or asking whether splitting is permitted. The latter is not captured.
> Ignoring realms, if we have BBML2_NOABORT the kernel won't force pte
> mappings under the assumption that split_kernel_leaf_mapping() is safe.
> However set_direct_map_*_noflush() won't even reach the split function
> because the "can" part says "no, you can't".
>
>> What would make more sense to me is to enable the use of BBML2-noabort
>> unconditionally if !force_pte_mapping(). We can then have
>> can_set_direct_map() return true if we have BBML2-noabort, and we no
>> longer need to check it in map_mem().
> Indeed.

I'm trying to wrap up my head for this discussion. IIUC, if none of the 
features is enabled, it means we don't need do anything because the 
direct map is not changed. For example, if vmalloc doesn't change direct 
map permission when rodata != full, there is no need to call 
set_direct_map_*_noflush(). So unconditionally checking BBML2_NOABORT 
will change the behavior unnecessarily. Did I miss something?

I think the only exception is secretmem if I don't miss something. 
Currently, secretmem is actually not supported if none of the features 
is enabled. But BBML2_NOABORT allows to lift the restriction.

Thanks,
Yang


>
>> This is a functional change that doesn't have anything to do with realms
>> so it should probably be a separate series - happy to take care of it
>> once the dust settles on the realm handling.
> I think it can be done in parallel, it shouldn't interfere with realms.
> The realm part should just affect force_pte_mapping() and
> can_set_direct_map() should return just what's possible, not what may
> need to set the direct map.
>



^ permalink raw reply

* Re: [PATCH v2 2/4] perf: Fix uninitialized bitfields in perf_clear_branch_entry_bitfields()
From: Leo Yan @ 2026-04-09 16:28 UTC (permalink / raw)
  To: Puranjay Mohan
  Cc: bpf, Puranjay Mohan, Alexei Starovoitov, Andrii Nakryiko,
	Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman,
	Kumar Kartikeya Dwivedi, Will Deacon, Mark Rutland,
	Catalin Marinas, Rob Herring, Breno Leitao, linux-arm-kernel,
	linux-perf-users, kernel-team
In-Reply-To: <20260318171706.2840512-3-puranjay@kernel.org>

On Wed, Mar 18, 2026 at 10:16:56AM -0700, Puranjay Mohan wrote:

[...]

> diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
> index 48d851fbd8ea..d7f39b7e9cda 100644
> --- a/include/linux/perf_event.h
> +++ b/include/linux/perf_event.h

BTW, I found you didn't include correct maintainers for perf core
changes.  You might need to loop them in the new version.


^ permalink raw reply

* Re: [PATCH] arm64: mte: Skip TFSR_EL1 checks and barriers in synchronous tag check mode
From: Catalin Marinas @ 2026-04-09 16:27 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Muhammad Usama Anjum, Will Deacon, Matthew Wilcox (Oracle),
	Thomas Huth, Andrew Morton, Lance Yang, Yeoreum Yun,
	linux-arm-kernel, linux-kernel
In-Reply-To: <c347fdc9-90b4-43ac-8c2e-559248777ba8@kernel.org>

On Wed, Mar 25, 2026 at 12:46:40PM +0100, David Hildenbrand wrote:
> On 3/11/26 18:50, Muhammad Usama Anjum wrote:
> > In MTE synchronous mode, tag check faults are reported as immediate
> > Data Abort exceptions. The TFSR_EL1.TF1 bit is never set, since faults
> > never go through the asynchronous path. Therefore, reading TFSR_EL1
> > and executing data and instruction barriers on kernel entry, exit,
> > context switch, and suspend is unnecessary overhead in sync mode.
> > 
> > The exit path (mte_check_tfsr_exit) and the assembly paths
> > (check_mte_async_tcf / clear_mte_async_tcf in entry.S) already had this
> > check.
> 
> Right, that's for user space (TFSR_EL1.TF0 IIUC). What you are adding is
> for KASAN. Maybe make that clearer.

Yeah, I'll tweak the commit message a bit. Even
system_uses_mte_async_or_asymm_mode() should be renamed to something
resembling kasan but I'll leave the function name as is for now.

-- 
Catalin


^ permalink raw reply

* [PATCH] arm64: Kconfig: fix duplicate word in CMDLINE help text
From: Michael Ugrin @ 2026-04-09 16:24 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon
  Cc: linux-arm-kernel, linux-kernel, Michael Ugrin

Remove duplicate 'the' in the CMDLINE config help text.

Signed-off-by: Michael Ugrin <mugrinphoto@gmail.com>
---
 arch/arm64/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 9ea19b74b..85d952740 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2373,7 +2373,7 @@ config CMDLINE
 	default ""
 	help
 	  Provide a set of default command-line options at build time by
-	  entering them here. As a minimum, you should specify the the
+	  entering them here. As a minimum, you should specify the
 	  root device (e.g. root=/dev/nfs).
 
 choice
-- 
2.51.2.windows.1



^ permalink raw reply related

* Re: BUG: net-next (7.0-rc6 based and later) fails to boot on Jetson Xavier NX
From: Russell King (Oracle) @ 2026-04-09 16:16 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Will Deacon, Robin Murphy, netdev, linux-arm-kernel, linux-kernel,
	iommu, linux-ext4, dmaengine, Marek Szyprowski, Theodore Ts'o,
	Andreas Dilger, Vinod Koul, Frank Li
In-Reply-To: <CAHk-=whO3F1u+nme4cnYMy5baYmb7CH=wE63dcNaPLWD0vKaew@mail.gmail.com>

On Thu, Apr 09, 2026 at 08:37:53AM -0700, Linus Torvalds wrote:
> On Thu, 9 Apr 2026 at 05:24, Will Deacon <will@kernel.org> wrote:
> >
> > On Wed, Apr 08, 2026 at 08:52:32PM +0100, Russell King (Oracle) wrote:
> > > What's the status on the iommu fix? Is it merged into mainline yet?
> > > If it isn't already, that means net-next remains unbootable going
> > > into the merge window without manually carrying the fix locally.
> >
> > I'll pick it up for 7.0 in the iommu tree.
> 
> ... and now it's in my tree.

Thanks, I see you merged it prior to the net tree, which should mean
the fix finds its way into net-next! Yay! Double thanks for that!

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


^ permalink raw reply

* Re: [PATCH] arm64: syscall: use cntvct_el0 for kstack offset randomization
From: Kees Cook @ 2026-04-09 16:17 UTC (permalink / raw)
  To: Xu Laiguang, Ryan Roberts
  Cc: catalin.marinas, will, gustavoars, linux-arm-kernel,
	linux-hardening
In-Reply-To: <20260409095322.1774250-1-xulaiguang@lixiang.com>

On Thu, Apr 09, 2026 at 09:53:22AM +0000, Xu Laiguang wrote:
> On PREEMPT_RT kernels, get_random_u16() can suffer significant lock
> contention in the syscall hot path.  The batched entropy layer uses
> local_lock, which on RT maps to a real spinlock.  When a batch refill
> is in progress, other tasks on the same CPU block on the lock.  Under
> heavy syscall load on a 24-core RT system, worst-case latencies of
> 16.65ms have been observed.
> 
>  contended   total wait     max wait     caller
>        307     86.18 ms     16.65 ms     get_random_u16+0x64
> 
> The kstack offset randomization only needs 6 bits of entropy (the
> value is masked by KSTACK_OFFSET_MAX to bits [9:4] on 64-bit).  This
> does not require cryptographic-strength randomness -- the goal is to
> make the kernel stack offset unpredictable enough to frustrate stack
> layout attacks.
> 
> Other architectures already use lightweight hardware counters for this
> purpose:
>   - x86:       rdtsc()              (arch/x86/include/asm/entry-common.h)
>   - powerpc:   mftb()               (arch/powerpc/kernel/syscall.c)
>   - loongarch: drdtime()            (arch/loongarch/kernel/syscall.c)
>   - s390:      get_tod_clock_fast()  (arch/s390/include/asm/entry-common.h)
> 
> Replace get_random_u16() with a bare read of cntvct_el0 (the ARM
> generic timer virtual count register).  The read is performed without
> ISB or arch_counter_enforce_ordering because kstack randomization does
> not require timing accuracy -- only unpredictability.
> 
> Signed-off-by: Xu Laiguang <xulaiguang@lixiang.com>

Everything here has been replaced recently. Can you check again with the
-next tree?

https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=for-next/hardening

See commits:
	randomize_kstack: Maintain kstack_offset per task
	randomize_kstack: Unify random source across arches

-Kees

> ---
>  arch/arm64/kernel/syscall.c | 17 ++++++++++++++++-
>  1 file changed, 16 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
> index c062badd1a56..c0ee9fa529ca 100644
> --- a/arch/arm64/kernel/syscall.c
> +++ b/arch/arm64/kernel/syscall.c
> @@ -35,6 +35,21 @@ static long __invoke_syscall(struct pt_regs *regs, syscall_fn_t syscall_fn)
>  	return syscall_fn(regs);
>  }
>  
> +/*
> + * Read the virtual counter without ISB or other ordering barriers.
> + * This is intentional: kstack randomization only needs unpredictability,
> + * not timing accuracy.  Speculative execution of the read, if it occurs,
> + * actually helps by making the precise value less predictable to an
> + * attacker.
> + */
> +static inline u64 kstack_entropy_cntvct(void)
> +{
> +	u64 cnt;
> +
> +	asm volatile("mrs %0, cntvct_el0" : "=r"(cnt));
> +	return cnt;
> +}
> +
>  static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
>  			   unsigned int sc_nr,
>  			   const syscall_fn_t syscall_table[])
> @@ -62,7 +77,7 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
>  	 *
>  	 * The resulting 6 bits of entropy is seen in SP[9:4].
>  	 */
> -	choose_random_kstack_offset(get_random_u16());
> +	choose_random_kstack_offset(kstack_entropy_cntvct());
>  }
>  
>  static inline bool has_syscall_work(unsigned long flags)
> -- 
> 2.43.0
> 
> 声明:这封邮件只允许文件接收者阅读,有很高的机密性要求。禁止其他人使用、打开、复制或转发里面的任何内容。如果本邮件错误地发给了你,请联系邮件发出者并删除这个文件。机密及法律的特权并不因为误发邮件而放弃或丧失。任何提出的观点或意见只属于作者的个人见解,并不一定代表本公司。
> Disclaimer: This email is intended to be read only by the designated recipient of the document and has high confidentiality requirements. Anyone else is prohibited from using, opening, copying or forwarding any of the contents inside. If this email was sent to you by mistake, please contact the sender of the email and delete this file immediately. Confidentiality and legal privileges are not waived or lost by misdirected emails. Any views or opinions expressed in the email are those of the author and do not necessarily represent those of the Company.
> 

-- 
Kees Cook


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox