Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] pmdomain: ti_sci: add wakeup constraint to parent devices of wakeup source
From: Vitor Soares @ 2026-05-13  9:40 UTC (permalink / raw)
  To: Kendall Willis
  Cc: Nishanth Menon, Tero Kristo, Santosh Shilimkar, Ulf Hansson,
	Kevin Hilman, Dhruva Gole, linux-arm-kernel, linux-pm,
	linux-kernel, stable, tomi.valkeinen, sebin.francis, devarsht,
	vigneshr, vishalm, vitor.soares
In-Reply-To: <20260512161737.pflweaz2r3q3nrfl@uda0506412>

On Tue, 2026-05-12 at 11:17 -0500, Kendall Willis wrote:
> On 17:51-20260511, Vitor Soares wrote:
> > Hi Kendall,
> > 
> > On Wed, 2026-05-06 at 22:16 -0500, Kendall Willis wrote:
> > > Set wakeup constraint for any device in a wakeup path. All parent devices
> > > of a wakeup device should not be turned off during suspend. This ensures
> > > the wakeup device is kept on while the system is suspended.
> > > 
> > 
> > Thanks for the patch.
> > 
> > I tested it on our Verdin AM62P. As expected, suspend now fails cleanly with
> > "-
> > 19" when an SDIO WiFi module is registered as a wakeup source, instead of
> > crashing on resume:
> > 
> > ti-sci 44043000.system-controller: PM: failed to suspend: error -19
> > 
> > I did not test the IO daisy chain wakeup path, since that is out of scope
> > for
> > this patch.
> > 
> > Best regards,
> > Vitor Soares
> > 
> 
> Hi Vitor,
> 
> Thanks for testing the patch! Could you add your Tested-by tag?
> 
> Best,
> Kendall

Hi Kendall,

Sure:
Tested-by: Vitor Soares vitor.soares@toradex.com

Best regards,
Vitor


^ permalink raw reply

* Re: [PATCH 01/16] ACPI: GTDT: Parse information related to the EL2 virtual timer
From: Sudeep Holla @ 2026-05-13  9:41 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: linux-arm-kernel, linux-acpi, linux-kernel, devicetree,
	Sudeep Holla, Lorenzo Pieralisi, Hanjun Guo, Catalin Marinas,
	Will Deacon, Rafael J. Wysocki, Mark Rutland, Daniel Lezcano,
	Thomas Gleixner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Chen-Yu Tsai, Jernej Skrabec, Samuel Holland, Neil Armstrong,
	Kevin Hilman, Jerome Brunet, Martin Blumenstingl, Ge Gordon,
	BST Linux Kernel Upstream Group, Jesper Nilsson, Lars Persson,
	Alim Akhtar, Ivaylo Ivanov, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Dinh Nguyen,
	Matthias Brugger, AngeloGioacchino Del Regno, Thierry Reding,
	Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
	Andreas Färber, Heiko Stuebner, Shawn Lin, Orson Zhai,
	Baolin Wang, Michal Simek
In-Reply-To: <20260507125544.2903406-2-maz@kernel.org>

On Thu, May 07, 2026 at 01:55:29PM +0100, Marc Zyngier wrote:
> Since ARMv8.1, the architecture has grown an EL2-private virtual
> timer. This has been described in ACPI since ACPI v6.3 and revision
> 3 of the GTDT table.
> 
> An aditional structure was added in ACPICA, though in a rather
> bizarre way, and merged in v5.1 as 8f5a14d053100 ("ACPICA: ACPI 6.3:
> add GTDT Revision 3 support").
> 
> Finally plug the table parsing in GTDT, and allow it to be eventually
> presented to the architected timer driver.
> 
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
>  drivers/acpi/arm64/gtdt.c | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
> 
> diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c
> index ffc867bac2d60..1a58007fccf0a 100644
> --- a/drivers/acpi/arm64/gtdt.c
> +++ b/drivers/acpi/arm64/gtdt.c
> @@ -88,6 +88,19 @@ static int __init map_gt_gsi(u32 interrupt, u32 flags)
>  	return acpi_register_gsi(NULL, interrupt, trigger, polarity);
>  }
>  
> +struct gtdt_v3 {
> +	struct acpi_table_gtdt	gtdt_v2;
> +	struct acpi_gtdt_el2	el2_vtimer;
> +};
> +
> +static struct acpi_gtdt_el2 *gtdt_to_el2_vtimer(struct acpi_table_gtdt *gtdt)
> +{
> +	if (gtdt->header.revision < 3)
> +		return NULL;
> +

We should validate the length as well just in case some platform bumped version
but didn't add these fields. Again it is problem if the platform timers are
also missing. We can just add the check in acpi_gtdt_init() if the version >=3
perhaps? If (gtdt->header.length < sizeof(struct gtdt_v3) invalid table or
something.

Also we have in platform_timer_valid()
	platform_timer >= (void *)(acpi_gtdt_desc.gtdt + 1)
which is still valid, but again if someone messes up in v3 keeping
offset where virtual EL2 timer GSI should be present as they just copied
it from v2, then we might allow it as valid.

Do it make sense to add that check as well in acpi_gtdt_init()? I mean
the offset should be >= sizeof(struct gtdt_v3).

Both checks can be added to acpi_gtdt_init() to avoid checking for each
platform timer instance may be ?

Other than this couple of minor nit, this patch looks fine.

Reviewed-by: Sudeep Holla <sudeep.holla@kernel.org>

-- 
Regards,
Sudeep


^ permalink raw reply

* [PATCH v2 4/6] devfreq: Add module owner to devfreq governor
From: Jie Zhan @ 2026-05-13  9:38 UTC (permalink / raw)
  To: cwchoi00, cw00.choi, myungjoo.ham, kyungmin.park, linux-pm,
	linux-arm-kernel
  Cc: linuxarm, tianyaxiong, zhanjie9, zhenglifeng1, zhangpengjie2,
	lihuisong, prime.zeng
In-Reply-To: <20260513093832.1645890-1-zhanjie9@hisilicon.com>

Add an 'owner' member to struct devfreq_governor, such that we can find
the module that holds the governor code when it's compiled as a kernel
module.  This allows the devfreq core to properly manage the lifecycle
of governors.

Update devfreq_add_governor() and devm_devfreq_add_governor() to
automatically set 'owner' to THIS_MODULE via helper macros.

This is a prerequisite for implementing governor reference counting to
prevent a governor module from being unloaded (except for force unload)
while a governor is in use.

Signed-off-by: Jie Zhan <zhanjie9@hisilicon.com>
---
 drivers/devfreq/devfreq.c        | 26 +++++++++-----------------
 include/linux/devfreq-governor.h | 26 +++++++++++++++++++++++---
 2 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 9e3e6a7348f8..e1363ab69173 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -1301,11 +1301,8 @@ void devfreq_resume(void)
 	mutex_unlock(&devfreq_list_lock);
 }
 
-/**
- * devfreq_add_governor() - Add devfreq governor
- * @governor:	the devfreq governor to be added
- */
-int devfreq_add_governor(struct devfreq_governor *governor)
+int __devfreq_add_governor(struct devfreq_governor *governor,
+			   struct module *mod)
 {
 	struct devfreq_governor *g;
 
@@ -1322,37 +1319,32 @@ int devfreq_add_governor(struct devfreq_governor *governor)
 		return -EINVAL;
 	}
 
+	governor->owner = mod;
 	list_add(&governor->node, &devfreq_governor_list);
 
 	return 0;
 }
-EXPORT_SYMBOL(devfreq_add_governor);
+EXPORT_SYMBOL(__devfreq_add_governor);
 
 static void devm_devfreq_remove_governor(void *governor)
 {
 	WARN_ON(devfreq_remove_governor(governor));
 }
 
-/**
- * devm_devfreq_add_governor() - Add devfreq governor
- * @dev:	device which adds devfreq governor
- * @governor:	the devfreq governor to be added
- *
- * This is a resource-managed variant of devfreq_add_governor().
- */
-int devm_devfreq_add_governor(struct device *dev,
-			      struct devfreq_governor *governor)
+int __devm_devfreq_add_governor(struct device *dev,
+				struct devfreq_governor *governor,
+				struct module *mod)
 {
 	int err;
 
-	err = devfreq_add_governor(governor);
+	err = __devfreq_add_governor(governor, mod);
 	if (err)
 		return err;
 
 	return devm_add_action_or_reset(dev, devm_devfreq_remove_governor,
 					governor);
 }
-EXPORT_SYMBOL(devm_devfreq_add_governor);
+EXPORT_SYMBOL(__devm_devfreq_add_governor);
 
 /**
  * devfreq_remove_governor() - Remove devfreq feature from a device.
diff --git a/include/linux/devfreq-governor.h b/include/linux/devfreq-governor.h
index dfdd0160a29f..1c4ff57e24de 100644
--- a/include/linux/devfreq-governor.h
+++ b/include/linux/devfreq-governor.h
@@ -12,6 +12,7 @@
 #define __LINUX_DEVFREQ_DEVFREQ_H__
 
 #include <linux/devfreq.h>
+struct module;
 
 #define DEVFREQ_NAME_LEN			16
 
@@ -50,6 +51,7 @@
 /**
  * struct devfreq_governor - Devfreq policy governor
  * @node:		list node - contains registered devfreq governors
+ * @owner:		Module that this governor belongs to
  * @name:		Governor's name
  * @attrs:		Governor's sysfs attribute flags
  * @flags:		Governor's feature flags
@@ -67,6 +69,7 @@
 struct devfreq_governor {
 	struct list_head node;
 
+	struct module *owner;
 	const char name[DEVFREQ_NAME_LEN];
 	const u64 attrs;
 	const u64 flags;
@@ -81,11 +84,28 @@ void devfreq_monitor_suspend(struct devfreq *devfreq);
 void devfreq_monitor_resume(struct devfreq *devfreq);
 void devfreq_update_interval(struct devfreq *devfreq, unsigned int *delay);
 
-int devfreq_add_governor(struct devfreq_governor *governor);
+/**
+ * devfreq_add_governor() - Add devfreq governor
+ * @governor:	The devfreq governor to be added
+ */
+#define devfreq_add_governor(governor) \
+	__devfreq_add_governor((governor), THIS_MODULE)
+int __devfreq_add_governor(struct devfreq_governor *governor,
+			   struct module *mod);
 int devfreq_remove_governor(struct devfreq_governor *governor);
 
-int devm_devfreq_add_governor(struct device *dev,
-			      struct devfreq_governor *governor);
+/**
+ * devm_devfreq_add_governor() - Add devfreq governor
+ * @dev:	device which adds devfreq governor
+ * @governor:	the devfreq governor to be added
+ *
+ * This is a resource-managed variant of devfreq_add_governor().
+ */
+#define devm_devfreq_add_governor(dev, governor) \
+	__devm_devfreq_add_governor((dev), (governor), THIS_MODULE)
+int __devm_devfreq_add_governor(struct device *dev,
+				struct devfreq_governor *governor,
+				struct module *mod);
 
 int devfreq_update_status(struct devfreq *devfreq, unsigned long freq);
 int devfreq_update_target(struct devfreq *devfreq, unsigned long freq);
-- 
2.43.0



^ permalink raw reply related

* [PATCH v2 0/6] devfreq: Add refcounts for governor modules
From: Jie Zhan @ 2026-05-13  9:38 UTC (permalink / raw)
  To: cwchoi00, cw00.choi, myungjoo.ham, kyungmin.park, linux-pm,
	linux-arm-kernel
  Cc: linuxarm, tianyaxiong, zhanjie9, zhenglifeng1, zhangpengjie2,
	lihuisong, prime.zeng

A governor module can be dynamically inserted or removed if compiled as a
kernel module.  'devfreq->governor' would become NULL if the governor
module is removed when it's in use.

For user-friendliness, get and put the module refcount of a governor module
when it's in use.  As a result, unloading a governor module in use returns
an error, e.g.:

$ cat governor
performance
$ rmmod governor_performance
rmmod: ERROR: Module governor_performance is in use

Note that this can't stop force unload, so it's more of a
user-friendliness improvement rather than strict protection.  The
existing code that keeps devfreq working when 'devfreq->governor' is
NULL should still be there.

Patch 1-3 clean up mutex with guards and factor out a common governor
setting function, so as to prepare for implementing governor reference
counting.  They can be applied separately.

Patch 4-6 add the reference counting mechanism for devfreq governor modules.

Changelog:
v2:
- Rebase on devfreq-next of 7.1-rc1.
- Drop the patches related to the NULL pointer deference issue of
  'devfreq->governor', which has been solved and merged recently.
- Remove the dedicated mutex for 'devfreq_governor_list' because the
  refcount changes don't depend on that.
- Some minor cleanups and fixes.

v1:
https://lore.kernel.org/all/20260326123428.800407-1-zhanjie9@hisilicon.com/

Jie Zhan (6):
  devfreq: Use mutex guard in governor_store()
  devfreq: Use mutex guard in devfreq_add/remove_governor()
  devfreq: Factor out devfreq_set_governor()
  devfreq: Add module owner to devfreq governor
  devfreq: Get and put module refcount when switching governor
  devfreq: Get module refcount in try_then_request_governor()

 drivers/devfreq/devfreq.c        | 210 +++++++++++++++----------------
 include/linux/devfreq-governor.h |  26 +++-
 2 files changed, 127 insertions(+), 109 deletions(-)

-- 
2.43.0



^ permalink raw reply

* [PATCH v2 6/6] devfreq: Get module refcount in try_then_request_governor()
From: Jie Zhan @ 2026-05-13  9:38 UTC (permalink / raw)
  To: cwchoi00, cw00.choi, myungjoo.ham, kyungmin.park, linux-pm,
	linux-arm-kernel
  Cc: linuxarm, tianyaxiong, zhanjie9, zhenglifeng1, zhangpengjie2,
	lihuisong, prime.zeng
In-Reply-To: <20260513093832.1645890-1-zhanjie9@hisilicon.com>

Get a refcount of the governor module in try_then_request_governor() so
that the governor module cannot be unloaded between finding the governor
and the caller using it.

Signed-off-by: Jie Zhan <zhanjie9@hisilicon.com>
---
 drivers/devfreq/devfreq.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 2ea42325d030..fb1a7aa168aa 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -285,6 +285,9 @@ static struct devfreq_governor *find_devfreq_governor(const char *name)
  * and the driver that call devfreq_add_device) are built as modules.
  * devfreq_list_lock should be held by the caller. Returns the matched
  * governor's pointer or an error pointer.
+ * On success, this holds a refcount of the governor module to prevent the
+ * module from being unloaded during usage, so the caller should put a module
+ * refcount after using it.
  */
 static struct devfreq_governor *try_then_request_governor(const char *name)
 {
@@ -313,8 +316,13 @@ static struct devfreq_governor *try_then_request_governor(const char *name)
 			return (err < 0) ? ERR_PTR(err) : ERR_PTR(-EINVAL);
 
 		governor = find_devfreq_governor(name);
+		if (IS_ERR(governor))
+			return governor;
 	}
 
+	if (!try_module_get(governor->owner))
+		return ERR_PTR(-EBUSY);
+
 	return governor;
 }
 
@@ -1009,6 +1017,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
 	}
 
 	err = devfreq_set_governor(devfreq, governor);
+	module_put(governor->owner);
 	if (err) {
 		dev_err_probe(dev, err,
 			"%s: Unable to start governor for the device\n",
@@ -1446,6 +1455,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
 		return PTR_ERR(governor);
 
 	ret = devfreq_set_governor(df, governor);
+	module_put(governor->owner);
 	if (ret)
 		return ret;
 
-- 
2.43.0



^ permalink raw reply related

* [PATCH v2 1/6] devfreq: Use mutex guard in governor_store()
From: Jie Zhan @ 2026-05-13  9:38 UTC (permalink / raw)
  To: cwchoi00, cw00.choi, myungjoo.ham, kyungmin.park, linux-pm,
	linux-arm-kernel
  Cc: linuxarm, tianyaxiong, zhanjie9, zhenglifeng1, zhangpengjie2,
	lihuisong, prime.zeng
In-Reply-To: <20260513093832.1645890-1-zhanjie9@hisilicon.com>

Use mutex guard in governor_store() so as to simplify the locking logic.

No functional impact intended.

Signed-off-by: Jie Zhan <zhanjie9@hisilicon.com>
---
 drivers/devfreq/devfreq.c | 38 ++++++++++++++++----------------------
 1 file changed, 16 insertions(+), 22 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index f08fc6966eae..7a70dd051644 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -1394,23 +1394,20 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
 	if (ret != 1)
 		return -EINVAL;
 
-	mutex_lock(&devfreq_list_lock);
+	guard(mutex)(&devfreq_list_lock);
 	governor = try_then_request_governor(str_governor);
-	if (IS_ERR(governor)) {
-		ret = PTR_ERR(governor);
-		goto out;
-	}
+	if (IS_ERR(governor))
+		return PTR_ERR(governor);
+
 	if (!df->governor)
 		goto start_new_governor;
 
-	if (df->governor == governor) {
-		ret = 0;
-		goto out;
-	} else if (IS_SUPPORTED_FLAG(df->governor->flags, IMMUTABLE)
-		|| IS_SUPPORTED_FLAG(governor->flags, IMMUTABLE)) {
-		ret = -EINVAL;
-		goto out;
-	}
+	if (df->governor == governor)
+		return count;
+
+	if (IS_SUPPORTED_FLAG(df->governor->flags, IMMUTABLE) ||
+	    IS_SUPPORTED_FLAG(governor->flags, IMMUTABLE))
+		return -EINVAL;
 
 	/*
 	 * Stop the current governor and remove the specific sysfs files
@@ -1420,7 +1417,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
 	if (ret) {
 		dev_warn(dev, "%s: Governor %s not stopped(%d)\n",
 			 __func__, df->governor->name, ret);
-		goto out;
+		return ret;
 	}
 
 start_new_governor:
@@ -1438,7 +1435,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
 		/* Restore previous governor */
 		df->governor = prev_governor;
 		if (!df->governor)
-			goto out;
+			return ret;
 
 		ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
 		if (ret) {
@@ -1446,7 +1443,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
 				"%s: reverting to Governor %s failed (%d)\n",
 				__func__, prev_governor->name, ret);
 			df->governor = NULL;
-			goto out;
+			return ret;
 		}
 	}
 
@@ -1455,13 +1452,10 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
 	 * the new governor, restore the sysfs files of previous governor.
 	 */
 	ret = sysfs_update_group(&df->dev.kobj, &gov_attr_group);
+	if (ret)
+		return ret;
 
-out:
-	mutex_unlock(&devfreq_list_lock);
-
-	if (!ret)
-		ret = count;
-	return ret;
+	return count;
 }
 static DEVICE_ATTR_RW(governor);
 
-- 
2.43.0



^ permalink raw reply related

* [PATCH v2 3/6] devfreq: Factor out devfreq_set_governor()
From: Jie Zhan @ 2026-05-13  9:38 UTC (permalink / raw)
  To: cwchoi00, cw00.choi, myungjoo.ham, kyungmin.park, linux-pm,
	linux-arm-kernel
  Cc: linuxarm, tianyaxiong, zhanjie9, zhenglifeng1, zhangpengjie2,
	lihuisong, prime.zeng
In-Reply-To: <20260513093832.1645890-1-zhanjie9@hisilicon.com>

Factor out common governor setting logic into devfreq_set_governor() so as
to consolidate the code in governor_store() and devfreq_add_device().

The caller is expected to hold 'devfreq_list_lock', enforced via
lockdep_assert_held().  This is required because devfreq_add_device() must
hold the lock from setting governor until the device is added to
'devfreq_list', so that a concurrent devfreq_remove_governor() cannot free
the governor in between.

Signed-off-by: Jie Zhan <zhanjie9@hisilicon.com>
---
 drivers/devfreq/devfreq.c | 117 ++++++++++++++++++--------------------
 1 file changed, 56 insertions(+), 61 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 53c40d795a13..9e3e6a7348f8 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -318,6 +318,59 @@ static struct devfreq_governor *try_then_request_governor(const char *name)
 	return governor;
 }
 
+static int devfreq_set_governor(struct devfreq *df,
+				const struct devfreq_governor *new_gov)
+{
+	const struct devfreq_governor *old_gov;
+	struct device *dev;
+	int ret;
+
+	lockdep_assert_held(&devfreq_list_lock);
+
+	old_gov = df->governor;
+	dev = &df->dev;
+
+	if (old_gov) {
+		if (old_gov == new_gov)
+			return 0;
+
+		if (IS_SUPPORTED_FLAG(old_gov->flags, IMMUTABLE) ||
+		    IS_SUPPORTED_FLAG(new_gov->flags, IMMUTABLE))
+			return -EINVAL;
+
+		/* Stop the current governor */
+		ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL);
+		if (ret) {
+			dev_warn(dev, "%s: Governor %s not stopped(%d)\n",
+				 __func__, df->governor->name, ret);
+			return ret;
+		}
+	}
+
+	/* Start the new governor */
+	df->governor = new_gov;
+	ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
+	if (ret) {
+		dev_warn(dev, "%s: Governor %s not started(%d)\n",
+			 __func__, df->governor->name, ret);
+
+		/* Restore previous governor */
+		df->governor = old_gov;
+		if (!df->governor)
+			return ret;
+
+		ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
+		if (ret) {
+			dev_err(dev, "%s: restore Governor %s failed (%d)\n",
+				__func__, df->governor->name, ret);
+			df->governor = NULL;
+			return ret;
+		}
+	}
+
+	return sysfs_update_group(&df->dev.kobj, &gov_attr_group);
+}
+
 static int devfreq_notify_transition(struct devfreq *devfreq,
 		struct devfreq_freqs *freqs, unsigned int state)
 {
@@ -942,9 +995,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
 		goto err_init;
 	}
 
-	devfreq->governor = governor;
-	err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START,
-						NULL);
+	err = devfreq_set_governor(devfreq, governor);
 	if (err) {
 		dev_err_probe(dev, err,
 			"%s: Unable to start governor for the device\n",
@@ -952,10 +1003,6 @@ struct devfreq *devfreq_add_device(struct device *dev,
 		goto err_init;
 	}
 
-	err = sysfs_update_group(&devfreq->dev.kobj, &gov_attr_group);
-	if (err)
-		goto err_init;
-
 	list_add(&devfreq->node, &devfreq_list);
 
 	mutex_unlock(&devfreq_list_lock);
@@ -1380,7 +1427,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
 	struct devfreq *df = to_devfreq(dev);
 	int ret;
 	char str_governor[DEVFREQ_NAME_LEN + 1];
-	const struct devfreq_governor *governor, *prev_governor;
+	const struct devfreq_governor *governor;
 
 	ret = sscanf(buf, "%" __stringify(DEVFREQ_NAME_LEN) "s", str_governor);
 	if (ret != 1)
@@ -1391,59 +1438,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
 	if (IS_ERR(governor))
 		return PTR_ERR(governor);
 
-	if (!df->governor)
-		goto start_new_governor;
-
-	if (df->governor == governor)
-		return count;
-
-	if (IS_SUPPORTED_FLAG(df->governor->flags, IMMUTABLE) ||
-	    IS_SUPPORTED_FLAG(governor->flags, IMMUTABLE))
-		return -EINVAL;
-
-	/*
-	 * Stop the current governor and remove the specific sysfs files
-	 * which depend on current governor.
-	 */
-	ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL);
-	if (ret) {
-		dev_warn(dev, "%s: Governor %s not stopped(%d)\n",
-			 __func__, df->governor->name, ret);
-		return ret;
-	}
-
-start_new_governor:
-	/*
-	 * Start the new governor and create the specific sysfs files
-	 * which depend on the new governor.
-	 */
-	prev_governor = df->governor;
-	df->governor = governor;
-	ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
-	if (ret) {
-		dev_warn(dev, "%s: Governor %s not started(%d)\n",
-			 __func__, df->governor->name, ret);
-
-		/* Restore previous governor */
-		df->governor = prev_governor;
-		if (!df->governor)
-			return ret;
-
-		ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
-		if (ret) {
-			dev_err(dev,
-				"%s: reverting to Governor %s failed (%d)\n",
-				__func__, prev_governor->name, ret);
-			df->governor = NULL;
-			return ret;
-		}
-	}
-
-	/*
-	 * Create the sysfs files for the new governor. But if failed to start
-	 * the new governor, restore the sysfs files of previous governor.
-	 */
-	ret = sysfs_update_group(&df->dev.kobj, &gov_attr_group);
+	ret = devfreq_set_governor(df, governor);
 	if (ret)
 		return ret;
 
-- 
2.43.0



^ permalink raw reply related

* [PATCH v2 5/6] devfreq: Get and put module refcount when switching governor
From: Jie Zhan @ 2026-05-13  9:38 UTC (permalink / raw)
  To: cwchoi00, cw00.choi, myungjoo.ham, kyungmin.park, linux-pm,
	linux-arm-kernel
  Cc: linuxarm, tianyaxiong, zhanjie9, zhenglifeng1, zhangpengjie2,
	lihuisong, prime.zeng
In-Reply-To: <20260513093832.1645890-1-zhanjie9@hisilicon.com>

A governor module can be dynamically inserted or removed if compiled as a
kernel module.  'devfreq->governor' would become NULL if the governor
module is removed when it's in use.

To prevent the governor module from being removed (except for force
unload) when it's in use, get and put a refcount of the governor module
when starting and stopping the governor.

As a result, unloading a governor module in use returns an error, e.g.:
  $ cat governor
  performance
  $ rmmod governor_performance
  rmmod: ERROR: Module governor_performance is in use

Signed-off-by: Jie Zhan <zhanjie9@hisilicon.com>
---
 drivers/devfreq/devfreq.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index e1363ab69173..2ea42325d030 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -345,24 +345,37 @@ static int devfreq_set_governor(struct devfreq *df,
 				 __func__, df->governor->name, ret);
 			return ret;
 		}
+		module_put(old_gov->owner);
 	}
 
 	/* Start the new governor */
+	if (!try_module_get(new_gov->owner)) {
+		df->governor = NULL;
+		return -EINVAL;
+	}
+
 	df->governor = new_gov;
 	ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
 	if (ret) {
 		dev_warn(dev, "%s: Governor %s not started(%d)\n",
 			 __func__, df->governor->name, ret);
+		module_put(new_gov->owner);
 
 		/* Restore previous governor */
 		df->governor = old_gov;
 		if (!df->governor)
 			return ret;
 
+		if (!try_module_get(old_gov->owner)) {
+			df->governor = NULL;
+			return -EINVAL;
+		}
+
 		ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL);
 		if (ret) {
 			dev_err(dev, "%s: restore Governor %s failed (%d)\n",
 				__func__, df->governor->name, ret);
+			module_put(old_gov->owner);
 			df->governor = NULL;
 			return ret;
 		}
@@ -1040,9 +1053,11 @@ int devfreq_remove_device(struct devfreq *devfreq)
 
 	devfreq_cooling_unregister(devfreq->cdev);
 
-	if (devfreq->governor)
+	if (devfreq->governor) {
 		devfreq->governor->event_handler(devfreq,
 						 DEVFREQ_GOV_STOP, NULL);
+		module_put(devfreq->governor->owner);
+	}
 	device_unregister(&devfreq->dev);
 
 	return 0;
-- 
2.43.0



^ permalink raw reply related

* [PATCH v2 2/6] devfreq: Use mutex guard in devfreq_add/remove_governor()
From: Jie Zhan @ 2026-05-13  9:38 UTC (permalink / raw)
  To: cwchoi00, cw00.choi, myungjoo.ham, kyungmin.park, linux-pm,
	linux-arm-kernel
  Cc: linuxarm, tianyaxiong, zhanjie9, zhenglifeng1, zhangpengjie2,
	lihuisong, prime.zeng
In-Reply-To: <20260513093832.1645890-1-zhanjie9@hisilicon.com>

Use mutex guard in devfreq_add/remove_governor() so as to simplify the
locking logic.

No functional impact intended.

Signed-off-by: Jie Zhan <zhanjie9@hisilicon.com>
---
 drivers/devfreq/devfreq.c | 22 +++++++---------------
 1 file changed, 7 insertions(+), 15 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 7a70dd051644..53c40d795a13 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -1261,28 +1261,23 @@ void devfreq_resume(void)
 int devfreq_add_governor(struct devfreq_governor *governor)
 {
 	struct devfreq_governor *g;
-	int err = 0;
 
 	if (!governor) {
 		pr_err("%s: Invalid parameters.\n", __func__);
 		return -EINVAL;
 	}
 
-	mutex_lock(&devfreq_list_lock);
+	guard(mutex)(&devfreq_list_lock);
 	g = find_devfreq_governor(governor->name);
 	if (!IS_ERR(g)) {
 		pr_err("%s: governor %s already registered\n", __func__,
 		       g->name);
-		err = -EINVAL;
-		goto err_out;
+		return -EINVAL;
 	}
 
 	list_add(&governor->node, &devfreq_governor_list);
 
-err_out:
-	mutex_unlock(&devfreq_list_lock);
-
-	return err;
+	return 0;
 }
 EXPORT_SYMBOL(devfreq_add_governor);
 
@@ -1320,21 +1315,20 @@ int devfreq_remove_governor(struct devfreq_governor *governor)
 {
 	struct devfreq_governor *g;
 	struct devfreq *devfreq;
-	int err = 0;
 
 	if (!governor) {
 		pr_err("%s: Invalid parameters.\n", __func__);
 		return -EINVAL;
 	}
 
-	mutex_lock(&devfreq_list_lock);
+	guard(mutex)(&devfreq_list_lock);
 	g = find_devfreq_governor(governor->name);
 	if (IS_ERR(g)) {
 		pr_err("%s: governor %s not registered\n", __func__,
 		       governor->name);
-		err = PTR_ERR(g);
-		goto err_out;
+		return PTR_ERR(g);
 	}
+
 	list_for_each_entry(devfreq, &devfreq_list, node) {
 		int ret;
 		struct device *dev = devfreq->dev.parent;
@@ -1356,10 +1350,8 @@ int devfreq_remove_governor(struct devfreq_governor *governor)
 	}
 
 	list_del(&governor->node);
-err_out:
-	mutex_unlock(&devfreq_list_lock);
 
-	return err;
+	return 0;
 }
 EXPORT_SYMBOL(devfreq_remove_governor);
 
-- 
2.43.0



^ permalink raw reply related

* Re: [PATCH v4 2/2] coco: guest: arm64: Drop dummy RSI platform device stub
From: Aneesh Kumar K.V @ 2026-05-13  9:51 UTC (permalink / raw)
  To: Greg KH
  Cc: Catalin Marinas, linux-kernel, linux-arm-kernel, Jeremy Linton,
	Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
	Will Deacon, Jonathan Cameron, Suzuki K Poulose
In-Reply-To: <yq5a4ikbu1w2.fsf@kernel.org>

Aneesh Kumar K.V <aneesh.kumar@kernel.org> writes:

> Greg KH <gregkh@linuxfoundation.org> writes:
>
>> On Wed, May 13, 2026 at 12:28:12PM +0530, Aneesh Kumar K.V wrote:
>>> Catalin Marinas <catalin.marinas@arm.com> writes:
>>> 
>>> > + Suzuki again
>>> >
>>> > On Mon, Apr 27, 2026 at 11:46:15AM +0530, Aneesh Kumar K.V (Arm) wrote:
>>> >> The SMCCC firmware driver now creates the `arm-smccc` platform device
>>> >> and also creates the CCA auxiliary devices once the RSI ABI is
>>> >> discovered. This makes the arch-specific arm64_create_dummy_rsi_dev()
>>> >> helper redundant. Remove the arm-cca-dev platform device registration
>>> >> and let the SMCCC probe manage the RSI device.
>>> >> 
>>> >> systemd match on platform:arm-cca-dev for confidential vm detection [1].
>>> >> Losing the platform device registration can break that. Keeping this
>>> >> removal in its own change makes it easy to revert if that regression
>>> >> blocks the rollout.
>>> >> 
>>> >> [1] https://lore.kernel.org/all/4a7d84b2-2ec4-4773-a2d5-7b63d5c683cf@arm.com
>>> >
>>> > I wouldn't merge this now given that systemd checks this file. Could we
>>> > have a symbolic link instead for some time until systemd eventually gets
>>> > updated (years?).
>>> >
>>> 
>>> I’ll add this in the next revision.
>>> 
>>> static int create_rsi_compat_link(struct device *target_dev)
>>> {
>>> 	struct kobject *platform_kobj;
>>> 	/*
>>> 	 * target_dev is:
>>> 	 * /sys/devices/platform/arm-smccc/arm_cca_guest.arm-rsi-dev.0
>>> 	 * Create compat link /sys/devices/platform/arm-cca-dev
>>> 	 */
>>> 	platform_kobj = target_dev->kobj.parent->parent;
>>
>> What?  That is crazy, you don't know that is always going to be ok.
>>
>>> 	return sysfs_create_link(platform_kobj,
>>> 				 &target_dev->kobj,
>>> 				 "arm-cca-dev");
>>
>> No, don't do that, if a driver calls a sysfs* function, something is
>> almost always wrong.  Don't be making random sysfs symlinks please.
>>
>
> Sure, but could you explain why this is wrong? Below is the full version
> of the updated patch.
>
> coco: guest: arm64 Replace RSI platform device with compat symlink
>
> The SMCCC firmware driver now creates the arm-smccc platform device and
> registers the RSI device as an auxiliary device once the RSI ABI has been
> discovered. This makes the arch-specific arm64 arm-cca-dev platform device
> redundant.
>
> Remove the arm64 platform device stub and let the SMCCC core manage RSI
> device creation.
>
> This changes the real device location from the old platform device path to:
>
>   /sys/devices/platform/arm-smccc/arm_cca_guest.arm-rsi-dev.0
>
> Keep userspace compatibility by creating a sysfs symlink at the old path:
>
>   /sys/devices/platform/arm-cca-dev
>
> A Debian Code Search check found systemd matching on the old
> platform:arm-cca-dev device path for confidential VM detection. No other
> userspace dependency on the old platform device path was found, but keeping
> the compatibility symlink avoids breaking existing systemd-based detection
> [1].
>
> [1] https://lore.kernel.org/all/4a7d84b2-2ec4-4773-a2d5-7b63d5c683cf@arm.com
>
> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
>
> modified   arch/arm64/kernel/rsi.c
> @@ -159,18 +159,3 @@ void __init arm64_rsi_init(void)
>  
>  	static_branch_enable(&rsi_present);
>  }
> -
> -static struct platform_device rsi_dev = {
> -	.name = "arm-cca-dev",
> -	.id = PLATFORM_DEVID_NONE
> -};
> -
> -static int __init arm64_create_dummy_rsi_dev(void)
> -{
> -	if (is_realm_world() &&
> -	    platform_device_register(&rsi_dev))
> -		pr_err("failed to register rsi platform device\n");
> -	return 0;
> -}
> -
> -arch_initcall(arm64_create_dummy_rsi_dev)
> modified   drivers/firmware/smccc/rmm.c
> @@ -4,13 +4,31 @@
>   */
>  
>  #include <linux/auxiliary_bus.h>
> +#include <linux/sysfs.h>
> +#include <linux/device.h>
>  
>  #include "rmm.h"
>  
> +static int create_rsi_compat_link(struct device *target_dev)
> +{
> +	struct kobject *platform_kobj;
> +	/*
> +	 * target_dev is:
> +	 * /sys/devices/platform/arm-smccc/arm_cca_guest.arm-rsi-dev.0
> +	 * Create compat link /sys/devices/platform/arm-cca-dev
> +	 */
> +	platform_kobj = target_dev->kobj.parent->parent;
> +
> +	return sysfs_create_link(platform_kobj,
> +				 &target_dev->kobj,
> +				 "arm-cca-dev");
> +}
> +
>  void __init register_rsi_device(struct platform_device *pdev)
>  {
>  	unsigned long ret;
>  	unsigned long ver_lower, ver_higher;
> +	struct auxiliary_device *adev;
>  
>  	if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC)
>  		return;
> @@ -19,6 +37,10 @@ void __init register_rsi_device(struct platform_device *pdev)
>  	if (ret != RSI_SUCCESS)
>  		return;
>  
> -	__devm_auxiliary_device_create(&pdev->dev,
> -				       "arm_cca_guest", RSI_DEV_NAME, NULL, 0);
> +	adev = __devm_auxiliary_device_create(&pdev->dev,
> +				"arm_cca_guest", RSI_DEV_NAME, NULL, 0);
> +	if (!adev)
> +		return;
> +
> +	create_rsi_compat_link(&adev->dev);
>  }

To make this clear, the above implies that adev parent is a platform
device and hence target_dev->kobj.parent->parent should be platform
kobject?

>
>
>>
>> If userspace can not find the device anymore, that's fine, that's how
>> sysfs works, devices move around all the time.  Especially platform
>> devices as those are almost always not supposed to be platform devices :)
>>
>> thanks,
>>
>> greg k-h
>

-aneesh


^ permalink raw reply

* [PATCH] iio: adc: sun20i-gpadc: support non-contiguous channel lookups
From: Michal Piekos @ 2026-05-13  9:51 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Chen-Yu Tsai, Jernej Skrabec, Samuel Holland
  Cc: linux-iio, linux-arm-kernel, linux-sunxi, linux-kernel,
	Michal Piekos

Using consumer driver like iio-hwmon which resolve channels thorugh
io-channels phandles will fail for sparse channels because IIO core
threats phandle argument as index into channel array.
        eg. <&gpadc 1> will fail if there is only channel@1 specified

Add fwnode_xlate which maps DT phandle to the registered channel whose
chan->channel matches the hardware channel number. It allows sparse
channel maps to be consumed by drivers like iio-hwmon.

Tested on Radxa Cubie A5E.

Signed-off-by: Michal Piekos <michal.piekos@mmpsystems.pl>
---
 drivers/iio/adc/sun20i-gpadc-iio.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/iio/adc/sun20i-gpadc-iio.c b/drivers/iio/adc/sun20i-gpadc-iio.c
index 861c14da75ad..95f34a352158 100644
--- a/drivers/iio/adc/sun20i-gpadc-iio.c
+++ b/drivers/iio/adc/sun20i-gpadc-iio.c
@@ -139,8 +139,21 @@ static irqreturn_t sun20i_gpadc_irq_handler(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static int sun20i_gpadc_fwnode_xlate(struct iio_dev *indio_dev,
+		const struct fwnode_reference_args *iiospec)
+{
+	int i;
+
+	for (i = 0; i < indio_dev->num_channels; i++)
+		if (indio_dev->channels[i].channel == iiospec->args[0])
+			return i;
+
+	return -EINVAL;
+}
+
 static const struct iio_info sun20i_gpadc_iio_info = {
 	.read_raw = sun20i_gpadc_read_raw,
+	.fwnode_xlate = sun20i_gpadc_fwnode_xlate,
 };
 
 static void sun20i_gpadc_reset_assert(void *data)

---
base-commit: 1d5dcaa3bd65f2e8c9baa14a393d3a2dc5db7524
change-id: 20260513-fix-sunxi-gpadc-sparse-channels-2b6b2063bd49

Best regards,
--  
Michal Piekos <michal.piekos@mmpsystems.pl>



^ permalink raw reply related

* Re: [PATCH] coresight: trbe: Hide enable_sink sysfs file
From: Leo Yan @ 2026-05-13  9:54 UTC (permalink / raw)
  To: James Clark
  Cc: Suzuki K Poulose, Mike Leach, Alexander Shishkin, coresight,
	linux-arm-kernel, linux-kernel
In-Reply-To: <cfb27efd-4887-4d47-8b38-99fc2d7bcfac@linaro.org>

On Wed, May 13, 2026 at 10:33:40AM +0100, James Clark wrote:

[...]

> > > +static umode_t coresight_attr_is_visible(struct kobject *kobj,
> > > +					 struct attribute *attr, int n)
> > >   {
> > >   	struct device *dev = kobj_to_dev(kobj);
> > > +	struct coresight_device *csdev = to_coresight_device(dev);
> > >   	if (attr == &dev_attr_label.attr) {
> > >   		if (fwnode_property_present(dev_fwnode(dev), "label"))
> > >   			return attr->mode;
> > >   		else
> > >   			return 0;
> > > +	} else if (attr == &dev_attr_enable_sink.attr ||
> > > +		   attr == &dev_attr_enable_source.attr) {
> > > +		if (csdev->no_sysfs_mode)
> > > +			return 0;
> > > +		else
> > > +			return attr->mode;
> > 
> > I'd prefer no_sysfs_mode to work as a general flag rather than being
> > limited to sink/source devices only. Otherwise, LGTM.
> 
> Which other files would you hide though? These are the only two that I could
> think of.
> 
> I wouldn't hide all sysfs files for 'no_sysfs_mode' as there are read only
> things that aren't strictly related to sysfs mode.

In coresight-sysfs.c, there are two kinds of attributes: the label and
the sink/source enable knobs.

The label is already handled separately. So we can hide the rest
attributes when no_sysfs_mode is set?

Thanks,
Leo


^ permalink raw reply

* [PATCH 0/3] arm64: dts: imx93-11x11-evk: Add DY1212W-4856 LVDS panel
From: Liu Ying @ 2026-05-13 10:02 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Peng Fan
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Liu Ying

Hi,

This patch series aims to add DY1212W-4856 [1] LVDS panel to i.MX93 11x11
EVK board.

Patch 1 allows LVDS Display Bridge (LDB) child node in i.MX93 mediamix
blk-ctrl DT binding.
Patch 2 adds LDB child node to mediamix blk-ctrl node in imx93.dtsi.
Patch 3 adds a DT overlay to support the DY1212W-4856 LVDS panel on
i.MX93 11x11 EVK board.

[1] https://www.nxp.com/design/design-center/development-boards-and-designs/dy1212w-4856-tft-lcd-panel-with-lvds-interface:DY1212W-4856

Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
Liu Ying (3):
      dt-bindings: soc: imx: fsl,imx93-media-blk-ctrl: Allow LVDS Display Bridge child node
      arm64: dts: imx93: Add LVDS Display Bridge support
      arm64: dts: imx93-11x11-evk: Add DY1212W-4856 LVDS panel

 .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 38 ++++++++++
 arch/arm64/boot/dts/freescale/Makefile             |  4 ++
 .../freescale/imx93-11x11-evk-dy1212w-4856.dtso    | 81 ++++++++++++++++++++++
 arch/arm64/boot/dts/freescale/imx93.dtsi           | 37 ++++++++++
 4 files changed, 160 insertions(+)
---
base-commit: e98d21c170b01ddef366f023bbfcf6b31509fa83
change-id: 20260513-imx93-ldb-c5a4194e41ce

Best regards,
--  
Regards,
Liu Ying



^ permalink raw reply

* [PATCH 1/3] dt-bindings: soc: imx: fsl,imx93-media-blk-ctrl: Allow LVDS Display Bridge child node
From: Liu Ying @ 2026-05-13 10:02 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Peng Fan
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Liu Ying
In-Reply-To: <20260513-imx93-ldb-v1-0-d11c5c3cc197@nxp.com>

i.MX93 SoC mediamix blk-ctrl contains one LDB_CTRL register and one LVDS
register which control video output through a LVDS interface.  Allow the
LVDS Display Bridge(LDB) child node and add the child node to example.

Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
 .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 38 ++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
index d828c2e82965..ab563b457e07 100644
--- a/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
+++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml
@@ -26,6 +26,12 @@ properties:
   reg:
     maxItems: 1
 
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 1
+
   '#power-domain-cells':
     const: 1
 
@@ -92,6 +98,11 @@ properties:
       - compatible
       - ports
 
+  bridge@20:
+    type: object
+    $ref: /schemas/display/bridge/fsl,ldb.yaml#
+    unevaluatedProperties: false
+
 allOf:
   - if:
       properties:
@@ -163,6 +174,8 @@ examples:
                <&clk IMX93_CLK_MIPI_DSI_GATE>;
                clock-names = "apb", "axi", "nic", "disp", "cam",
                              "pxp", "lcdif", "isi", "csi", "dsi";
+      #address-cells = <1>;
+      #size-cells = <1>;
       #power-domain-cells = <1>;
 
       dpi-bridge {
@@ -190,4 +203,29 @@ examples:
           };
         };
       };
+
+      bridge@20 {
+        compatible = "fsl,imx93-ldb";
+        reg = <0x20 0x4>, <0x24 0x4>;
+        reg-names = "ldb", "lvds";
+        clocks = <&clk IMX93_CLK_LVDS_GATE>;
+        clock-names = "ldb";
+
+        ports {
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          port@0 {
+            reg = <0>;
+
+            endpoint {
+              remote-endpoint = <&lcdif_to_ldb>;
+            };
+          };
+
+          port@1 {
+            reg = <1>;
+          };
+        };
+      };
     };

-- 
2.43.0



^ permalink raw reply related

* [PATCH 2/3] arm64: dts: imx93: Add LVDS Display Bridge support
From: Liu Ying @ 2026-05-13 10:02 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Peng Fan
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Liu Ying
In-Reply-To: <20260513-imx93-ldb-v1-0-d11c5c3cc197@nxp.com>

Add LVDS Display Bridge(LDB) child node to mediamix blk-ctrl node
so that video could be output through a LVDS interface.

Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
 arch/arm64/boot/dts/freescale/imx93.dtsi | 37 ++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi
index b9abe143cb56..79fb4a15b733 100644
--- a/arch/arm64/boot/dts/freescale/imx93.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93.dtsi
@@ -178,6 +178,7 @@ &lcdif {
 	port {
 		lcdif_to_ldb: endpoint@1 {
 			reg = <1>;
+			remote-endpoint = <&ldb_from_lcdif>;
 		};
 
 		lcdif_to_dsi: endpoint@2 {
@@ -186,6 +187,42 @@ lcdif_to_dsi: endpoint@2 {
 	};
 };
 
+&media_blk_ctrl {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	lvds_bridge: bridge@20 {
+		compatible = "fsl,imx93-ldb";
+		reg = <0x20 0x4>, <0x24 0x4>;
+		reg-names = "ldb", "lvds";
+		clocks = <&clk IMX93_CLK_LVDS_GATE>;
+		clock-names = "ldb";
+		assigned-clocks = <&clk IMX93_CLK_MEDIA_LDB>;
+		assigned-clock-parents = <&clk IMX93_CLK_VIDEO_PLL>;
+		status = "disabled";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+
+				ldb_from_lcdif: endpoint {
+					remote-endpoint = <&lcdif_to_ldb>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+
+				ldb_lvds_ch0: endpoint {
+				};
+			};
+		};
+	};
+};
+
 &src {
 	mlmix: power-domain@44461800 {
 		compatible = "fsl,imx93-src-slice";

-- 
2.43.0



^ permalink raw reply related

* [PATCH 3/3] arm64: dts: imx93-11x11-evk: Add DY1212W-4856 LVDS panel
From: Liu Ying @ 2026-05-13 10:02 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Peng Fan
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Liu Ying
In-Reply-To: <20260513-imx93-ldb-v1-0-d11c5c3cc197@nxp.com>

DY1212W-4856 [1] is a 12.1" (WXGA) TFT LCD panel with LVDS interface.
The panel's 40-pin connector allows it to be directly connected to
i.MX93 11x11 EVK board.

Link: https://www.nxp.com/design/design-center/development-boards-and-designs/dy1212w-4856-tft-lcd-panel-with-lvds-interface:DY1212W-4856 [1]
Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
 arch/arm64/boot/dts/freescale/Makefile             |  4 ++
 .../freescale/imx93-11x11-evk-dy1212w-4856.dtso    | 81 ++++++++++++++++++++++
 2 files changed, 85 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index d1bb303962db..42f655986987 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -467,6 +467,10 @@ dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb-i3c.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb-ontat-kd50g21-40nt-a1.dtb
 
 dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk.dtb
+
+imx93-11x11-evk-dy1212w-4856-dtbs += imx93-11x11-evk.dtb imx93-11x11-evk-dy1212w-4856.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk-dy1212w-4856.dtb
+
 dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-frdm.dtb
 
 imx93-11x11-frdm-pixpaper-dtbs += imx93-11x11-frdm.dtb imx93-11x11-frdm-pixpaper.dtbo
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dy1212w-4856.dtso b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dy1212w-4856.dtso
new file mode 100644
index 000000000000..35f7c5699e3a
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dy1212w-4856.dtso
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2026 NXP
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/imx93-clock.h>
+
+&{/} {
+	panel-lvds {
+		compatible = "boe,ev121wxm-n10-1850";
+		backlight = <&backlight_lvds>;
+		power-supply = <&buck4>;
+
+		panel-timing {
+			/*
+			 * Set clock frequency to 71142858Hz to accommodate
+			 * IMX93_CLK_VIDEO_PLL rate at 498000000Hz in a rate
+			 * table.
+			 */
+			clock-frequency = <71142858>;
+			hactive = <1280>;
+			vactive = <800>;
+			hfront-porch = <48>;
+			hback-porch = <80>;
+			hsync-len = <32>;
+			vfront-porch = <3>;
+			vback-porch = <14>;
+			vsync-len = <6>;
+		};
+
+		port {
+			panel_lvds_in: endpoint {
+				remote-endpoint = <&ldb_lvds_ch0>;
+			};
+		};
+	};
+};
+
+&backlight_lvds {
+	status = "okay";
+};
+
+&lcdif {
+	status = "okay";
+};
+
+&lvds_bridge {
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port@1 {
+			reg = <1>;
+
+			ldb_lvds_ch0: endpoint {
+				remote-endpoint = <&panel_lvds_in>;
+			};
+		};
+	};
+};
+
+&media_blk_ctrl {
+	assigned-clocks = <&clk IMX93_CLK_MEDIA_AXI>,
+			  <&clk IMX93_CLK_MEDIA_APB>,
+			  <&clk IMX93_CLK_MEDIA_DISP_PIX>,
+			  <&clk IMX93_CLK_VIDEO_PLL>;
+	assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1>,
+				 <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>,
+				 <&clk IMX93_CLK_VIDEO_PLL>;
+	/*
+	 * Set IMX93_CLK_MEDIA_DISP_PIX rate to 71142858Hz to accommodate
+	 * IMX93_CLK_VIDEO_PLL rate at 498000000Hz in a rate table.
+	 */
+	assigned-clock-rates = <400000000>, <133333333>, <71142858>, <498000000>;
+	status = "okay";
+};

-- 
2.43.0



^ permalink raw reply related

* [PATCH v3 0/3] i2c: xiic: fix SMBus block read and PEC support
From: Abdurrahman Hussain @ 2026-05-13 10:09 UTC (permalink / raw)
  To: Michal Simek, Andi Shyti
  Cc: linux-arm-kernel, linux-i2c, linux-kernel, Abdurrahman Hussain

This series fixes three independent bugs in the Xilinx AXI IIC driver
that together make SMBus block reads with PEC return -EBADMSG or -EIO
on otherwise clean transfers. They only surface when the client has
I2C_CLIENT_PEC set; non-PEC block reads happen to mask each issue in
turn.

The problems were uncovered driving an adm1266 PMBus device behind a
Xilinx AXI IIC FPGA block and reading its 64-byte blackbox record.

Patch 1 stops xiic_smbus_block_read_setup() from truncating rx_msg->len.
The i2c core appends a byte to msg->len when PEC is enabled, so
overwriting the length to "block size + 1" silently drops the PEC byte
and i2c_smbus_check_pec() then reads the last payload byte as the PEC.

Patch 2 raises the RX_FULL threshold so the interrupt only fires once
every remaining byte (payload plus optional PEC) is already buffered in
the FIFO. The previous threshold of rxmsg_len - 2 caused the
bytes_rem == 1 path in xiic_read_rx() to NACK a byte still on the wire.
The chunk-vs-defer guard now also accounts for the PEC byte so a
rxmsg_len == IIC_RX_FIFO_DEPTH PEC-enabled read does not push
XIIC_RFD_REG_OFFSET past its 4-bit range.

Patch 3 stops the BNB handler from forcing tx_msg->len = 1 to signal
completion. tx_msg and rx_msg alias the same i2c_msg during a receive,
so this also clobbered rx_msg->len; and because tx_pos is already at 2
in the PEC case, the unsigned subtraction in xiic_tx_space() underflowed
and the STATE_DONE check fell through to STATE_ERROR. Advancing tx_pos
up to msg->len drives tx_space to zero without touching the length.

All three patches are pure bug fixes; non-PEC behaviour is unchanged.
Tested on real hardware -- a Xilinx AXI IIC controller talking to an
adm1266, where 64-byte PEC-checked block reads now complete cleanly.

Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
---
Changes in v3 (addresses the sashiko automated review of v2):
- Patch 1: handle short SMBus block reads where the controller pads
  rx_msg->len up to SMBUS_BLOCK_READ_MIN_LEN for its end-of-message
  workaround. In v2 this branch left the PEC byte at the padded
  offset rather than the actual end-of-payload, so the i2c core's
  PEC validator read past the chip data. Track the on-wire length
  in a new smbus_actual_len field populated in the minlen branch
  of xiic_smbus_block_read_setup(), and trim rx_msg->len back at
  RX_FULL completion before passing the message up. Addresses
  sashiko's v2 note about the pec_len adjustment missing the
  rxmsg_len < 3 padding branch; that branch was indeed the cause
  of pmbus_check_block_register() silently failing on zero-length
  MFR_* fields and skipping debugfs auto-discovery on affected
  hardware.
- Patch 3: defensively reset smbus_actual_len in the BNB completion
  handler so a subsequent non-SMBus transfer cannot see a stale
  trim value from a completed short block read.
- Patch 2 is unchanged from v2. sashiko's two other v2 notes were
  investigated and judged not to require code changes: the concern
  about removed padding in the chunked-vs-deferred drain misread
  the patch (the padding survives via the else branch and the new
  PEC-aware guard preserves the original semantics), and the
  flagged unsigned underflow in xiic_tx_space() is unreachable
  because tx_pos is bounded by tx_msg->len at the call site.
- Link to v2: https://patch.msgid.link/20260511-i2c-xiic-v2-0-c16380cb1594@nexthop.ai

Changes in v2:
- Patch 2: widen the chunk-vs-defer guard in xiic_smbus_block_read_setup()
  to include pec_len, so a 16-byte PEC-enabled block read routes through
  the chunked drain rather than writing 16 into the 4-bit
  XIIC_RFD_REG_OFFSET register. No tree-level change to patches 1 or 3.
- Link to v1: https://patch.msgid.link/20260427-i2c-xiic-v1-0-e6207f9aa5ad@nexthop.ai

To: Michal Simek <michal.simek@amd.com>
To: Andi Shyti <andi.shyti@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-i2c@vger.kernel.org
Cc: linux-kernel@vger.kernel.org

---
Abdurrahman Hussain (3):
      i2c: xiic: preserve PEC byte length in SMBus block read setup
      i2c: xiic: defer RX_FULL until all trailing bytes are in FIFO
      i2c: xiic: don't clobber msg->len to signal block-read completion

 drivers/i2c/busses/i2c-xiic.c | 67 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 50 insertions(+), 17 deletions(-)
---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
change-id: 20260427-i2c-xiic-2aeb501ec02a

Best regards,
--  
Abdurrahman Hussain <abdurrahman@nexthop.ai>



^ permalink raw reply

* [PATCH v3 3/3] i2c: xiic: don't clobber msg->len to signal block-read completion
From: Abdurrahman Hussain @ 2026-05-13 10:09 UTC (permalink / raw)
  To: Michal Simek, Andi Shyti
  Cc: linux-arm-kernel, linux-i2c, linux-kernel, Abdurrahman Hussain
In-Reply-To: <20260513-i2c-xiic-v3-0-ccb3cf70ba03@nexthop.ai>

At the end of a SMBus block read the BNB handler force-set
tx_msg->len = 1 to push xiic_tx_space() to zero so the STATE_DONE
branch would fire. Two problems:

1. tx_msg and rx_msg alias the same i2c_msg struct during a receive
   (see xiic_start_recv), so overwriting tx_msg->len also changes
   rx_msg->len. The i2c core's i2c_smbus_check_pec() then reads the
   PEC from the wrong offset -- buf[0] instead of buf[rxmsg_len + 1]
   -- and either mis-validates or returns -EBADMSG.

2. xiic_start_recv sets tx_pos = msg->len (typically 2 when PEC is
   enabled). xiic_tx_space() is unsigned msg->len - tx_pos, so
   setting msg->len = 1 with tx_pos = 2 underflows to 0xFFFFFFFF and
   xiic_tx_space() never compares equal to 0 -- the STATE_DONE check
   falls through to STATE_ERROR, giving -EIO.

Instead, advance tx_pos up to msg->len. That drives tx_space to 0
without touching msg->len, preserving the buffer length that
xiic_smbus_block_read_setup() already grew to cover the length byte,
the payload and the optional PEC byte.

Also clear smbus_actual_len here so a subsequent non-SMBus transfer
does not see a stale trim value from this completed block read.

Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
---
 drivers/i2c/busses/i2c-xiic.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index 2bdba6c0931f..8eaa411411c1 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -889,8 +889,17 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
 
 		if (i2c->tx_msg && i2c->smbus_block_read) {
 			i2c->smbus_block_read = false;
-			/* Set requested message len=1 to indicate STATE_DONE */
-			i2c->tx_msg->len = 1;
+			/*
+			 * Defensive: reset the per-transfer trim state in case
+			 * the rx phase completed via an error path that
+			 * skipped the trim site in the RX_FULL branch above.
+			 */
+			i2c->smbus_actual_len = 0;
+			/*
+			 * Drive xiic_tx_space() to 0 to signal STATE_DONE
+			 * without truncating the rx_msg length.
+			 */
+			i2c->tx_pos = i2c->tx_msg->len;
 		}
 
 		if (!i2c->tx_msg)

-- 
2.53.0



^ permalink raw reply related

* [PATCH v3 2/3] i2c: xiic: defer RX_FULL until all trailing bytes are in FIFO
From: Abdurrahman Hussain @ 2026-05-13 10:09 UTC (permalink / raw)
  To: Michal Simek, Andi Shyti
  Cc: linux-arm-kernel, linux-i2c, linux-kernel, Abdurrahman Hussain
In-Reply-To: <20260513-i2c-xiic-v3-0-ccb3cf70ba03@nexthop.ai>

For the normal path of xiic_smbus_block_read_setup() (rxmsg_len less
than IIC_RX_FIFO_DEPTH), RFD was programmed to rxmsg_len - 2, which
fires the RX_FULL interrupt while the last payload byte is still in
flight. xiic_read_rx()'s bytes_rem == 1 branch then sets NACK on that
byte still on the wire, truncating the read in the PEC-enabled case.

Raise the threshold so RX_FULL fires only once every remaining byte
(payload plus optional PEC) is already buffered in the FIFO. That
routes the drain through xiic_read_rx()'s bytes_rem == 0 path, which
reads everything out and emits the stop cleanly. For the non-PEC path
the full payload is still read out through the same bytes_rem == 0
branch; the only user-visible change is that the controller waits one
extra byte-time before servicing the interrupt.

The deferred-fire formula is rxmsg_len + pec_len - 1, and the RFD
register at XIIC_RFD_REG_OFFSET is a 4-bit field. Widen the
chunk-vs-defer guard to (rxmsg_len + pec_len > IIC_RX_FIFO_DEPTH) so
the boundary case rxmsg_len == IIC_RX_FIFO_DEPTH with PEC enabled
cannot write 16 into that 4-bit register; it routes through the
chunked drain instead, which already caps RFD at IIC_RX_FIFO_DEPTH - 1.

Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
---
 drivers/i2c/busses/i2c-xiic.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index d4308716d461..2bdba6c0931f 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -548,10 +548,11 @@ static void xiic_smbus_block_read_setup(struct xiic_i2c *i2c)
 		unsigned int pec_len = i2c->rx_msg->len - 1;
 
 		/* Set Receive fifo depth */
-		if (rxmsg_len > IIC_RX_FIFO_DEPTH) {
+		if (rxmsg_len + pec_len > IIC_RX_FIFO_DEPTH) {
 			/*
-			 * When Rx msg len greater than or equal to Rx fifo capacity
-			 * Receive fifo depth should set to Rx fifo capacity minus 1
+			 * Trailing payload (data + optional PEC) exceeds Rx FIFO
+			 * capacity; drain in chunks. Fire RX_FULL when the FIFO is
+			 * full and let the ISR re-arm for the remainder.
 			 */
 			rfd_set = IIC_RX_FIFO_DEPTH - 1;
 			i2c->rx_msg->len = rxmsg_len + 1 + pec_len;
@@ -572,11 +573,8 @@ static void xiic_smbus_block_read_setup(struct xiic_i2c *i2c)
 			i2c->rx_msg->len = SMBUS_BLOCK_READ_MIN_LEN;
 			i2c->smbus_actual_len = 1 + rxmsg_len + pec_len;
 		} else {
-			/*
-			 * When Rx msg len less than Rx fifo capacity
-			 * Receive fifo depth should set to Rx msg len minus 2
-			 */
-			rfd_set = rxmsg_len - 2;
+			/* Defer RX_FULL until all trailing bytes are in FIFO. */
+			rfd_set = rxmsg_len + pec_len - 1;
 			i2c->rx_msg->len = rxmsg_len + 1 + pec_len;
 		}
 		xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rfd_set);

-- 
2.53.0



^ permalink raw reply related

* [PATCH v3 1/3] i2c: xiic: preserve PEC byte length in SMBus block read setup
From: Abdurrahman Hussain @ 2026-05-13 10:09 UTC (permalink / raw)
  To: Michal Simek, Andi Shyti
  Cc: linux-arm-kernel, linux-i2c, linux-kernel, Abdurrahman Hussain
In-Reply-To: <20260513-i2c-xiic-v3-0-ccb3cf70ba03@nexthop.ai>

xiic_smbus_block_read_setup() recalculates i2c->rx_msg->len based on the
length byte returned by the device, but historically clobbered the PEC
byte expectation the SMBus core had baked into msg->len. That dropped
the PEC byte from the caller's buffer on the normal and chunked
receive-fifo branches.

Compute pec_len up-front as (i2c->rx_msg->len - 1) and add it to the
new length in every branch:

  - chunked (rxmsg_len + pec_len > IIC_RX_FIFO_DEPTH): set the drain
    target to rxmsg_len + 1 + pec_len.

  - deferred (small enough to drain in one fill but >= MIN_LEN total):
    same.

  - padded (1 + rxmsg_len + pec_len < SMBUS_BLOCK_READ_MIN_LEN): the
    hardware needs at least 3 bytes on the bus to exit the read
    cleanly (the second byte is already being clocked in by the time
    the ISR reads the length byte and is too late to NACK), so we
    still pad rx_msg->len up to SMBUS_BLOCK_READ_MIN_LEN. The dummy
    trailing byte that gets drained must then be trimmed off before
    handing the message back to the SMBus core; otherwise
    i2c_smbus_check_pec() reads buf[len-1] (= dummy) instead of the
    real PEC byte at buf[1] and rejects every clean zero-length block
    read with -EBADMSG.

    Record the true valid byte count in a new field
    i2c->smbus_actual_len and have xiic_process()'s RX_FULL completion
    site trim rx_msg->len down to it before clearing rx_msg.

    Widen the branch condition from the old "(rxmsg_len == 1) ||
    (rxmsg_len == 0)" to "(1 + rxmsg_len + pec_len) < MIN_LEN" so that
    user requests with multi-byte trailing bytes (e.g. pec_len == 2 on
    a zero-length block) flow through the deferred branch instead of
    getting truncated to MIN_LEN here.

Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
---
 drivers/i2c/busses/i2c-xiic.c | 40 +++++++++++++++++++++++++++++++++-------
 1 file changed, 33 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index 3e7735e1dae0..d4308716d461 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -73,6 +73,11 @@ enum i2c_scl_freq {
  * @prev_msg_tx: Previous message is Tx
  * @quirks: To hold platform specific bug info
  * @smbus_block_read: Flag to handle block read
+ * @smbus_actual_len: For SMBus block reads padded to SMBUS_BLOCK_READ_MIN_LEN,
+ *	the number of bytes that are actually valid (length byte + payload +
+ *	optional PEC). msg->len gets trimmed to this on transfer completion so
+ *	the SMBus core sees the real PEC byte and not the trailing dummy.
+ *	Zero when no trimming is needed.
  * @input_clk: Input clock to I2C controller
  * @i2c_clk: I2C SCL frequency
  * @atomic: Mode of transfer
@@ -98,6 +103,7 @@ struct xiic_i2c {
 	bool prev_msg_tx;
 	u32 quirks;
 	bool smbus_block_read;
+	unsigned int smbus_actual_len;
 	unsigned long input_clk;
 	unsigned int i2c_clk;
 	bool atomic;
@@ -539,6 +545,8 @@ static void xiic_smbus_block_read_setup(struct xiic_i2c *i2c)
 
 	/* Check if received length is valid */
 	if (rxmsg_len <= I2C_SMBUS_BLOCK_MAX) {
+		unsigned int pec_len = i2c->rx_msg->len - 1;
+
 		/* Set Receive fifo depth */
 		if (rxmsg_len > IIC_RX_FIFO_DEPTH) {
 			/*
@@ -546,23 +554,30 @@ static void xiic_smbus_block_read_setup(struct xiic_i2c *i2c)
 			 * Receive fifo depth should set to Rx fifo capacity minus 1
 			 */
 			rfd_set = IIC_RX_FIFO_DEPTH - 1;
-			i2c->rx_msg->len = rxmsg_len + 1;
-		} else if ((rxmsg_len == 1) ||
-			(rxmsg_len == 0)) {
+			i2c->rx_msg->len = rxmsg_len + 1 + pec_len;
+		} else if (1 + rxmsg_len + pec_len < SMBUS_BLOCK_READ_MIN_LEN) {
 			/*
-			 * Minimum of 3 bytes required to exit cleanly. 1 byte
-			 * already received, Second byte is being received. Have
-			 * to set NACK in read_rx before receiving the last byte
+			 * Hardware requires at least SMBUS_BLOCK_READ_MIN_LEN
+			 * bytes on the bus to exit the read cleanly: by the
+			 * time the ISR pulls the length byte from the FIFO,
+			 * the second byte is already being clocked in and
+			 * cannot be NACKed in time. Pad the drain target so
+			 * the HW reaches the minimum, but remember the true
+			 * valid byte count and trim msg->len back on transfer
+			 * completion -- otherwise the SMBus core's PEC check
+			 * reads the trailing dummy byte instead of the real
+			 * PEC byte and rejects clean transfers with -EBADMSG.
 			 */
 			rfd_set = 0;
 			i2c->rx_msg->len = SMBUS_BLOCK_READ_MIN_LEN;
+			i2c->smbus_actual_len = 1 + rxmsg_len + pec_len;
 		} else {
 			/*
 			 * When Rx msg len less than Rx fifo capacity
 			 * Receive fifo depth should set to Rx msg len minus 2
 			 */
 			rfd_set = rxmsg_len - 2;
-			i2c->rx_msg->len = rxmsg_len + 1;
+			i2c->rx_msg->len = rxmsg_len + 1 + pec_len;
 		}
 		xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rfd_set);
 
@@ -797,6 +812,17 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
 
 		xiic_read_rx(i2c);
 		if (xiic_rx_space(i2c) == 0) {
+			/*
+			 * If the setup path padded a short SMBus block read up
+			 * to SMBUS_BLOCK_READ_MIN_LEN for the HW exit
+			 * workaround, trim rx_msg->len back to the number of
+			 * bytes that are actually valid so the SMBus core's
+			 * PEC check reads the right index. Must happen before
+			 * the rx_msg = NULL below.
+			 */
+			if (i2c->rx_msg && i2c->smbus_actual_len)
+				i2c->rx_msg->len = i2c->smbus_actual_len;
+
 			/* this is the last part of the message */
 			i2c->rx_msg = NULL;
 

-- 
2.53.0



^ permalink raw reply related

* Re: [RFC PATCH 0/4] arm64: realm: Support for probing RSI earlier
From: Suzuki K Poulose @ 2026-05-13 10:17 UTC (permalink / raw)
  To: Lorenzo Pieralisi
  Cc: linux-arm-kernel, linux-kernel, catalin.marinas, will, ardb,
	mark.rutland, steven.price, aneesh.kumar, sudeep.holla, robh, maz
In-Reply-To: <af3DiIibnKvu+Tpt@lpieralisi>

On 08/05/2026 12:05, Lorenzo Pieralisi wrote:
> On Fri, May 08, 2026 at 09:28:32AM +0100, Suzuki K Poulose wrote:
>> Hi Lorenzo,
>>
>>
>> On 08/05/2026 09:09, Lorenzo Pieralisi wrote:
>>> On Wed, Apr 29, 2026 at 11:35:31AM +0100, Suzuki K Poulose wrote:
>>>> The Realm Guest linux support is broken without rodata=full (fortunately default
>>>> for arm64), as we detect the RSI support after we have created the Linear map
>>>> with Block/Contiguous mappings. If the boot CPU doesn't support BBML2_NOABORT
>>>> (there are CPUs out there with FEAT_RME and no - useable - BBML2_NOABORT)
>>>> we are then not able to split the page tables down to PTE level if the system
>>>> as such doesn't support BBML2.
>>>>
>>>> See the following link for the discussion.
>>>>
>>>> https://lore.kernel.org/all/20260330161705.3349825-2-ryan.roberts@arm.com/
>>>>
>>>> The available options are :
>>>>    1. Start with PTE level mappings at paging_init() and then "FOLD" the page tables
>>>>       to Block/Cont mappings after we have the full picture available. Looking at the
>>>>       future (with BBML3), this might mean "additional work" for most of the systems
>>>>       at boot. But not bad as splitting them ?
>>>>    2. Hold the secondary CPUs in busy loop with MMU disabled and split the mappings
>>>>       by the boot CPU with MMU off (if Boot CPU can't support BBML2). This is tricky
>>>>       with the page allocations required to add the page-tables.
>>>>    3. Move the detection of Realm support earlier to make a better decision for
>>>>       paging_init(), with an added bonus of earlycon support for Realms without
>>>>       the user having to work out the "top bit" for the Realm.
>>>>
>>>> This series is an attempt to implement (3) (without the earlycon support). We try
>>>> to probe the PSCI conduit early from the DT/ACPI. DT is not flattened at this time.
>>>
>>> Nit: you mean unflattened here.
>>
>> Yep, thats right.
>>
>>>
>>>> ACPI table is not mapped in full, so we have to map one table at a time and walk
>>>> from the Root of the table (RSDP) through to XSDT and find the FADT table from
>>>> the array of table pointers there. Minimal verification is performed on the
>>>> tables (e.g., revision checks, standard FADT sanity checks). Checksum is not
>>>> verified, but should be possible to do for the parts we consume.
>>>
>>> I went back to tracing acpi_boot_table_init() (joy :)) and it does what you
>>
>> Welcome back ;-)
>>
>>> describe here above (it has been a while since I touched that code) relying on
>>> early_memremap() mappings (as you re-do in this series) before acpi_permanent_mmap
>>> is set in acpi_early_init() (that happens later in the boot process).
>>>
>>> I am sure there are caveats in moving acpi_boot_table_init() before
>>> paging_init() but I thought I'd mention it in case (3) is what we are
>>> pursuing (I am most definitely in favour of alternatives if there are
>>> any).
>>
>> I believe we might have issues with acpi_table_upgrade(), which would
>> need access to initramfs for any tables. We may not have the initramfs
>> mapped by then ? Anyways, FADT cannot be upgraded from the initramfs,
> 
> I think it can:
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/acpi/tables.c?h=v7.1-rc2#n407

Oh! I misread the FACS as FADT :facepalm:

Thank you for correcting me.

> 
> Obviously this is a debugging/bootstrapping tool but hey, here we go.
> 
>> so if we can work out a way to do the necessary may be something
>> worth checking.
> 
> I don't think we can init the tables before enabling the upgrade (which
> requires reading from initrd).
> 
> I will try to think a bit more to see whether we can reuse some code
> (again - if that's what we eventually want to do).

I will continue to explore this too.

Much appreciated

Cheers
Suzuki


> 
> Lorenzo
> 
>>>
>>>> With arm64, during the normal boot, we could fallback to using DT if the ACPI
>>>> tables are not useable. So, during the early probe, we try to follow the similar
>>>> logic and probe the conduit from both DT and ACPI where available. If both of
>>>> them contain a conduit, we only proceed if they match. Otherwise, we skip the
>>>> early probe and do things the normal way. (Any sane system shouldn't have such
>>>> a mismatch, but..)
>>>>
>>>> Once we probe the PSCI conduit, PSCI is probed, along with the presence of SMCCC.
>>>> With that in place, we try to probe the RSI support after the early probe and
>>>> advertise the Realm World. If the early probe wasn't successful, we fall back
>>>> to the late mode, where we could end up with (on a possibly rare broken firmware).
>>>>
>>>> NOTE: This is an early RFC attempt to moving the PSCI detection earlier. The other
>>>> option(s) that may be worth exploring are:
>>>>
>>>> 1. On systems with EFI, parse this from EFI Stub and pass the data back in the
>>>>      DT Stub, under chosen node. e.g., "linux,uefi-arm-psci-conduit".
>>>>      Challenge: EFI stub doesn't seem to be ACPI aware. We could make that change,
>>>>      we only need a few table walks.
>>>
>>> What would we gain compared to (3) above ?
>>
>> EFI stub has 1x1 map for the areas and we don't have to do the map/unmap
>> dancein the kernel and potentially end up crashing ourselves.
>>
>> Suzuki
>>
>>>
>>> Thanks,
>>> Lorenzo
>>>
>>>> 2. Have EFI firmware provide this information (with my limited knowledge on the
>>>>      area, this looks like too much work, and bending the standards)
>>>> 3. Append arm64 boot protocol to have this information passed to the kernel.
>>>>      (Firmware provided) - (Steven's idea)
>>>> 4. Any other options ?
>>>>
>>>>
>>>> This series is also available here :
>>>>
>>>> git@git.gitlab.arm.com:linux-arm/linux-cca.git	cca-guest/early-rsi-detection/rfc-v1
>>>>
>>>> Thoughts ?
>>>>
>>>> Suzuki
>>>>
>>>>
>>>> Suzuki K Poulose (4):
>>>>     arm64: acpi: Refactor FADT table verification
>>>>     psci: Add support for Early detection and init
>>>>     arm64: psci: Move detection and SMCCC probe earlier
>>>>     arm64: realm: Move RSI detection earlier
>>>>
>>>>    arch/arm64/include/asm/acpi.h |   1 +
>>>>    arch/arm64/include/asm/rsi.h  |   1 +
>>>>    arch/arm64/kernel/acpi.c      | 136 +++++++++++++++++++++++++++-------
>>>>    arch/arm64/kernel/rsi.c       |  23 +++++-
>>>>    arch/arm64/kernel/setup.c     |  69 +++++++++++++++++
>>>>    drivers/firmware/psci/psci.c  |  49 +++++++++++-
>>>>    include/linux/psci.h          |   2 +
>>>>    7 files changed, 252 insertions(+), 29 deletions(-)
>>>>
>>>> -- 
>>>> 2.43.0
>>>>
>>



^ permalink raw reply

* Re: [PATCH] perf arm-spe: Don't warn about the discard bit if it doesn't exist
From: Leo Yan @ 2026-05-13 10:20 UTC (permalink / raw)
  To: James Clark
  Cc: John Garry, Will Deacon, Mike Leach, Leo Yan, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
	linux-arm-kernel, linux-perf-users, linux-kernel
In-Reply-To: <20260410-james-spe-discard-warning-v1-1-985c02756ee4@linaro.org>

On Fri, Apr 10, 2026 at 12:05:12PM +0100, James Clark wrote:
> Opening an SPE event shows a warning that doesn't concern the user:
> 
>   $ perf record -e arm_spe
>   Unknown/empty format name: discard
> 
> Perf only wants to know if the discard bit is set for configuring the
> event, not in response to anything the user has done. Fix it by adding
> another helper that returns if a config bit exists without warning.
> 
> We should probably keep the warning in evsel__get_config_val() to avoid
> having every caller having to do it, and most format bits should never
> be missing.
> 
> Add a test for the new helper. Rename the parent test function to be
> more generic rather than adding a new one as it requires a lot of
> boilerplate.
> 
> Signed-off-by: James Clark <james.clark@linaro.org>

Reviewed-by: Leo Yan <leo.yan@arm.com>


^ permalink raw reply

* Re: [PATCH 2/2] arm64: dts: amlogic: t7: khadas-vim4: add PWM-driven status LED
From: Ronald Claveau @ 2026-05-13 10:26 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
	Kevin Hilman, Jerome Brunet, Martin Blumenstingl, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
In-Reply-To: <7ad282ae-fffa-4d0a-9cec-65d8f6b40544@linaro.org>

On 5/13/26 10:05 AM, Neil Armstrong wrote:
> On 5/12/26 19:47, Ronald Claveau via B4 Relay wrote:
>> From: Ronald Claveau <linux-kernel-dev@aliel.fr>
>>
>> The VIM4 board exposes a status LED wired to the PWM_AO_C_D output.
>> Enable the pwm_ao_cd controller with its pinmux, and declare a
>> pwm-leds node with a heartbeat trigger.
>>
>> Also, move the xtal-clk node to restore alphabetical ordering.
> 
> Please send a separate patch for that
> 

Thanks for your review, I will add a new patch.

>>
>> Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
>> ---
>>   .../dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts  | 30 ++++++++++++
>> +++++-----
>>   1 file changed, 23 insertions(+), 7 deletions(-)
>>
>> diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-
>> vim4.dts b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
>> index 69d6118ba57e7..c41525a34b721 100644
>> --- a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
>> +++ b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
>> @@ -45,13 +45,6 @@ secmon_reserved_bl32: secmon@5300000 {
>>           };
>>       };
>>   -    xtal: xtal-clk {
>> -        compatible = "fixed-clock";
>> -        clock-frequency = <24000000>;
>> -        clock-output-names = "xtal";
>> -        #clock-cells = <0>;
>> -    };
>> -
>>       dc_in: regulator-dc-in {
>>           compatible = "regulator-fixed";
>>           regulator-name = "DC_IN";
>> @@ -60,6 +53,16 @@ dc_in: regulator-dc-in {
>>           regulator-always-on;
>>       };
>>   +    pwm-leds {
>> +        compatible = "pwm-leds";
>> +
>> +        status {
>> +            linux,default-trigger="heartbeat";
>> +            max-brightness = <255>;
>> +            pwms = <&pwm_ao_cd 0 30040 0>;
>> +        };
>> +    };
>> +
>>       sd_3v3: regulator-sdcard-3v3 {
>>           compatible = "regulator-fixed";
>>           regulator-name = "SD_3V3";
>> @@ -155,6 +158,13 @@ wifi32k: wifi32k {
>>           clock-frequency = <32768>;
>>               pwms = <&pwm_ab 0 30518 0>;
>>       };
>> +
>> +    xtal: xtal-clk {
>> +        compatible = "fixed-clock";
>> +        clock-frequency = <24000000>;
>> +        clock-output-names = "xtal";
>> +        #clock-cells = <0>;
>> +    };
>>   };
>>     &pwm_ab {
>> @@ -163,6 +173,12 @@ &pwm_ab {
>>       pinctrl-names = "default";
>>   };
>>   +&pwm_ao_cd {
>> +    status = "okay";
>> +    pinctrl-0 = <&pwm_ao_c_d_pins>;
>> +    pinctrl-names = "default";
>> +};
>> +
>>   /* SDIO */
>>   &sd_emmc_a {
>>       status = "okay";
>>
> 


-- 
Best regards,
Ronald


^ permalink raw reply

* Re: [PATCH 2/4] Revert "dt-bindings: display: bridge: ldb: Fill in reg property"
From: Marco Felsch @ 2026-05-13 10:26 UTC (permalink / raw)
  To: Rob Herring
  Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter,
	Krzysztof Kozlowski, Conor Dooley, Marek Vasut, Frank Li,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	laurentiu.palcu, victor.liu, dri-devel, devicetree, linux-kernel,
	imx, linux-arm-kernel
In-Reply-To: <CAL_JsqJWyRPh_hmJW8p7+VvtcqpS0a_azjMO-PyQgkqQUfLAGA@mail.gmail.com>

On 26-05-07, Rob Herring wrote:
> On Thu, May 7, 2026 at 6:55 AM Marco Felsch <m.felsch@pengutronix.de> wrote:

...

> > > But nowhere have you said the LDB registers are mixed with other
> > > functions. If they aren't, then there is absolutely nothing to change
> > > in the binding. If they are, then yes, we shouldn't have 'reg'.
> >
> > No they aren't mixed with other functions (for now).
> 
> For now? Is the h/w going to change or is the binding *still* incomplete.

Sorry for the confusion. By for now I mean that NXP tend to reuse IPs
but with minor changes. So no, the binding is not incomplete with our
current HW knowledge.

> > Can you please
> > confirm that mixing 'reg' based sub-device nodes with non 'reg' based
> > sub-device nodes  is allowed? E.g. if the below example is allowed?
> >
> >         system-controller@4ac10000 {
> >                 compatible = "fsl,imx93-media-blk-ctrl", "syscon";
> >                 reg = <0x4ac10000 0x10000>;
> >                 #address-cells = <1>;
> >                 #size-cells = <1>;
> >
> >                 ...
> >
> >                 bridge@5c {
> >                         compatible = "fsl,imx8mp-ldb";
> >                         reg = <0x5c 0x4>, <0x128 0x4>;
> >                         reg-names = "ldb", "lvds";
> >
> >                         ...
> >                 };
> >
> >                 dpi-bridge {
> >                         compatible = "nxp,imx93-pdfc";
> >
> >                         ...
> 
> Depends what is in "...". If only a compatible, then no. If there are
> actual resources defined, then yes.

Please see the below full example, is this allowed?

system-controller@4ac10000 {
	compatible = "fsl,imx93-media-blk-ctrl", "syscon";
	reg = <0x4ac10000 0x10000>;
	#address-cells = <1>;
	#size-cells = <1>;

	...

	bridge@5c {
		compatible = "fsl,imx8mp-ldb";
		reg = <0x5c 0x4>, <0x128 0x4>;
		reg-names = "ldb", "lvds";
		clocks = <&clk IMX8MP_CLK_MEDIA_LDB_ROOT>;
		clock-names = "ldb";
		assigned-clocks = <&clk IMX8MP_CLK_MEDIA_LDB>;
		assigned-clock-parents = <&clk IMX8MP_VIDEO_PLL1_OUT>;
		status = "disabled";

		ports {
			#address-cells = <1>;
			#size-cells = <0>;

			port@0 {
				reg = <0>;

				ldb_from_lcdif2: endpoint {
					remote-endpoint = <&lcdif2_to_ldb>;
				};
			};

			port@1 {
				reg = <1>;

				ldb_lvds_ch0: endpoint {
				};
			};

			port@2 {
				reg = <2>;

				ldb_lvds_ch1: endpoint {
				};
			};
		};
	};

	dpi-bridge {
		compatible = "nxp,imx93-pdfc";
		status = "disabled";

		ports {
			#address-cells = <1>;
			#size-cells = <0>;

			port@0 {
				reg = <0>;

				dpi_from_lcdif: endpoint {
					remote-endpoint = <&lcdif_to_dpi>;
				};
			};

			port@1 {
				reg = <1>;

				dpi_to_panel: endpoint {
				};
			};
		};
	};
};

> > Furthermore I thought that for the MMIO bridge@5c device, the 'reg'
> > porperty would either require the full register address, e.g. 0x4ac1005c
> > or there needs to be a ranges property.
> 
> There should be a ranges property no matter what.

Good point, something to fix too :/

Regards,
  Marco


^ permalink raw reply

* Re: [PATCH v4 02/15] mm: Make empty_zero_page __ro_after_init
From: Mike Rapoport @ 2026-05-13 10:28 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Jann Horn, Ard Biesheuvel, linux-arm-kernel, linux-kernel,
	Will Deacon, Catalin Marinas, Mark Rutland, Ryan Roberts,
	Anshuman Khandual, Liz Prucka, Seth Jenkins, Kees Cook,
	David Hildenbrand, Andrew Morton, linux-mm, linux-hardening
In-Reply-To: <49d30ffe-b7e1-4b05-89e0-c3fe01348bb6@app.fastmail.com>

On Wed, May 13, 2026 at 10:53:08AM +0200, Ard Biesheuvel wrote:
> 
> On Wed, 13 May 2026, at 10:50, Mike Rapoport wrote:
> > On Tue, May 12, 2026 at 02:56:16PM +0200, Ard Biesheuvel wrote:
> >> On Mon, 11 May 2026, at 16:40, Jann Horn wrote:
> >> > On Mon, May 11, 2026 at 10:59 AM Ard Biesheuvel <ardb@kernel.org> wrote:
> >> >> I think we should simply do something along the lines of the below,
> >> >> considering that the size of a data object tends to correlate with
> >> >> its minimum alignment.
> >> >>
> >> >> I do find it rather puzzling that the compiler emits empty_zero_page
> >> >> *after* zero_page_pfn - ideally, we'd combine the below with
> >> >> -fdata-sections so that the linker sees all individual objects, but
> >> >> I suspect that would create some problems elsewhere.
> >> >>
> >> >>
> >> >> --- a/include/asm-generic/vmlinux.lds.h
> >> >> +++ b/include/asm-generic/vmlinux.lds.h
> >> >> @@ -452,7 +452,7 @@
> >> >>  #define RO_AFTER_INIT_DATA                                   \
> >> >>         . = ALIGN(8);                                         \
> >> >>         __start_ro_after_init = .;                            \
> >> >> -       *(.data..ro_after_init)                               \
> >> >> +       *(SORT_BY_ALIGNMENT(.data..ro_after_init))            \
> >> >
> >> > Oh, neat, I didn't realize that's possible. That seems like a nicer
> >> > approach...
> >> 
> >> Neat but rather ineffective, unfortunately. (I don't see a size
> >> difference with the arm64 defconfig kernel)
> >> 
> >> Given that empty_zero_page only ever gets its address taken, we
> >> might just move it into the linker script if that requires tweaking
> >> anyway. We can just place it at the start of .rodata, which is
> >> already page aligned on most architectures (and will become page
> >> aligned unless EMPTY_ZERO_PAGE is #define'd by the arch linker
> >> script to something else)
> >> 
> >> 
> >> --- a/include/asm-generic/vmlinux.lds.h
> >> +++ b/include/asm-generic/vmlinux.lds.h
> >> @@ -472,6 +472,17 @@
> >>  #endif
> >>  #endif
> >>  
> >> +#ifndef EMPTY_ZERO_PAGE
> >> +#ifndef __HAVE_COLOR_ZERO_PAGE
> >
> > I don't think we want let architectures that don't use colored zero pages
> > redefine it.
> > If it will be really required we can add the ability to redefine
> > EMPTY_ZERO_PAGE later.
> >
> 
> I was actually intending to add use this for arm64 in the next patch. It
> already has a reserved_pg_dir in .rodata which is page-sized (i.e., up
> to 64k in size) and guaranteed to remain all zeroes, so empty_zero_page
> could actually be an alias for that. This is what I had in a previous
> revision, before you turned the empty_zero_page definition into common
> code:

Works for me if from arm64 perspective that's ok :)
 
> https://lore.kernel.org/all/20260320145934.2349881-16-ardb+git@google.com/

-- 
Sincerely yours,
Mike.


^ 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