* Re: [PATCH] usb: dwc3: imx8mp: make dwc3_imx_glue_ops static and rename to imx8mp
From: Ahmad Fatoum @ 2026-06-23 10:07 UTC (permalink / raw)
To: Ben Dooks, Thinh Nguyen, Greg Kroah-Hartman, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, linux-usb,
imx, linux-arm-kernel, linux-kernel
In-Reply-To: <20260623100554.735080-1-ben.dooks@codethink.co.uk>
On 6/23/26 12:05 PM, Ben Dooks wrote:
> The dwc3_imx_glue_ops is not used outside this file, and technically this
> is the dwc3-imx8mp driver so whilst making this static to avoid the
> following warning, rename it dwc3_imx8mp_glue_ops to distinguish it from
> the other driver which also has dwc3_imx_glue_ops.
>
> Fixes:
> drivers/usb/dwc3/dwc3-imx8mp.c:176:22: warning: symbol 'dwc3_imx_glue_ops' was not declared. Should it be static?
>
> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
> ---
> drivers/usb/dwc3/dwc3-imx8mp.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c
> index 1cf96540b66e..bc61a89b66b1 100644
> --- a/drivers/usb/dwc3/dwc3-imx8mp.c
> +++ b/drivers/usb/dwc3/dwc3-imx8mp.c
> @@ -173,8 +173,8 @@ static void dwc3_imx_pre_set_role(struct dwc3 *dwc, enum usb_role role)
> pm_runtime_use_autosuspend(dwc->dev);
> }
>
> -struct dwc3_glue_ops dwc3_imx_glue_ops = {
> - .pre_set_role = dwc3_imx_pre_set_role,
> +statc struct dwc3_glue_ops dwc3_imx8mp_glue_ops = {
Typo
> + .pre_set_role = dwc3_imx8mp_pre_set_role,
> };
>
> static int dwc3_imx8mp_probe(struct platform_device *pdev)
> @@ -266,7 +266,7 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
> goto put_dwc3;
> }
>
> - dwc3->glue_ops = &dwc3_imx_glue_ops;
> + dwc3->glue_ops = &dwc3_imx8mp_glue_ops;
>
> if (dwc3->dr_mode == USB_DR_MODE_HOST)
> pm_runtime_dont_use_autosuspend(dwc3->dev);
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [PATCH 1/4] device property: Introduce fwnode_graph_for_each_endpoint_scoped()
From: Andy Shevchenko @ 2026-06-23 10:09 UTC (permalink / raw)
To: Frank.Li
Cc: Daniel Scally, Heikki Krogerus, Sakari Ailus, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Mauro Carvalho Chehab,
Dafna Hirschfeld, Laurent Pinchart, Heiko Stuebner,
Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
driver-core, linux-acpi, linux-kernel, linux-media,
linux-rockchip, linux-arm-kernel, linux-arm-msm, imx, Guoniu Zhou,
Frank Li
In-Reply-To: <20260622-fw_scoped-v1-1-a37d0aac0a68@nxp.com>
On Mon, Jun 22, 2026 at 10:30:11AM -0400, Frank.Li@oss.nxp.com wrote:
> From: Frank Li <Frank.Li@nxp.com>
>
> Similar to recently propose for_each_child_of_node_scoped() this new
> version of the loop macro instantiates a new local struct fwnode_handle *
> that uses the __free(fwnode_handle) auto cleanup handling so that if a
> reference to a node is held on early exit from the loop the reference will
> be released. If the loop runs to completion, the child pointer will be NULL
> and no action will be taken.
>
> The reason this is useful is that it removes the need for
> fwnode_handle_put() on early loop exits. If there is a need to retain the
Just be consistent with 1-space versus 2-spaces gaps in the same text.
> reference, then return_ptr(child) or no_free_ptr(child) may be used to
> safely disable the auto cleanup.
No objections from me.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
See one nit-pick below.
But you will need driver core maintainers to Ack this.
...
> +#define fwnode_graph_for_each_endpoint_scoped(fwnode, child) \
> + for (struct fwnode_handle *child __free(fwnode_handle) = \
> + fwnode_graph_get_next_endpoint(fwnode, NULL); \
You should follow the existing style, the 'f' in fwnode should be under 'u' in
struct.
> + child; child = fwnode_graph_get_next_endpoint(fwnode, child))
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v2 0/5] mm: reduce mmap_lock contention and improve page fault performance
From: Hongru Zhang @ 2026-06-23 10:10 UTC (permalink / raw)
To: david
Cc: akpm, baohua, bhe, chentao, chrisl, jack, kasong, kunwu.chan,
liam, lianux.mm, linux-arm-kernel, linux-kernel, linux-mm,
linux-riscv, linux-s390, linuxppc-dev, liyangouwen1, ljs,
loongarch, mhocko, nphamcs, nzzhao, pfalcato, rppt, shikemeng,
surenb, vbabka, wanglian, willy, youngjun.park, zhanghongru06
In-Reply-To: <d04f745d-eb3e-4d2c-8ea2-5fdcf2cf27b8@kernel.org>
On 6/23/26 10:02, David Hildenbrand wrote:
> I know that especially browser usually use fork servers: a tiny
> (single-threaded) process just to create new child processes. Any information
> regarding the apps above that use fork() on small vs. large processes?
I wrote a second BPF tool (fork_info) that captures nr_threads and
map_count (VMA count) from the calling process at the exact moment
fork() is triggered. Results from 3 representative apps:
App (category) Fork caller Threads VMAs
-----------------------------------------------------------
Taobao (shopping) DaemonThread-6 526 8,987
Amap (navigation) DaemonThread-6 289 7,120
UC Browser (browser) OneNativeThread 350 8,144
These are all heavyweight multi-threaded processes (hundreds of threads,
7,000-9,000 VMAs), not fork servers.
> Above you write "some call fork() from multiple threads". Any further
> information on that?
Xiaohongshu (com.xingin.xhs, social media) is a clear example. In just
tens of seconds of normal usage, fork() was called 22 times from 4
different threads:
PID COMM THREADS VMAS
4206 com.xingin.xhs 85 4,140
4216 Thread-2208 85 4,157
4208 Thread-2208 90 4,211
5200 Thread-3200 337 6,519
5200 Thread-3200 343 6,563
5200 Thread-3200 361 6,769
5200 Thread-3200 453 7,793
5200 Thread-3200 450 7,779
5202 Thread-2219 459 7,846
5202 Thread-2219 462 7,875
5202 Thread-2219 465 7,899
4219 Thread-2219 465 7,903
4219 Thread-2219 468 7,922
5202 Thread-2219 467 7,917
4219 Thread-2219 467 7,921
4219 Thread-2219 468 7,929
5202 Thread-2219 464 7,909
5202 Thread-2219 460 7,889
5202 Thread-2219 459 7,884
4219 Thread-2219 433 7,771
4219 Thread-2219 433 7,771
4219 Thread-2219 434 7,778
The process grew from 85 threads / 4,140 VMAs at first fork to
434 threads / 7,778 VMAs at last fork, showing these are long-lived
heavyweight processes that fork repeatedly throughout their lifecycle.
Tracing tool:
https://gist.github.com/zhr250/ba7725d0ea55594bcafd3cd4806eed98
Hongru
^ permalink raw reply
* [PATCH v2] usb: dwc3: imx8mp: make dwc3_imx_glue_ops static and rename to imx8mp
From: Ben Dooks @ 2026-06-23 10:10 UTC (permalink / raw)
To: Thinh Nguyen, Greg Kroah-Hartman, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, linux-usb, imx,
linux-arm-kernel, linux-kernel
Cc: Ben Dooks
The dwc3_imx_glue_ops is not used outside this file, and technically this
is the dwc3-imx8mp driver so whilst making this static to avoid the
following warning, rename it dwc3_imx8mp_glue_ops to distinguish it from
the other driver which also has dwc3_imx_glue_ops.
Fixes:
drivers/usb/dwc3/dwc3-imx8mp.c:176:22: warning: symbol 'dwc3_imx_glue_ops' was not declared. Should it be static?
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
drivers/usb/dwc3/dwc3-imx8mp.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c
index 1cf96540b66e..de8c17bc940d 100644
--- a/drivers/usb/dwc3/dwc3-imx8mp.c
+++ b/drivers/usb/dwc3/dwc3-imx8mp.c
@@ -158,7 +158,7 @@ static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx)
return IRQ_HANDLED;
}
-static void dwc3_imx_pre_set_role(struct dwc3 *dwc, enum usb_role role)
+static void dwc3_imx8mp_pre_set_role(struct dwc3 *dwc, enum usb_role role)
{
if (role == USB_ROLE_HOST)
/*
@@ -173,8 +173,8 @@ static void dwc3_imx_pre_set_role(struct dwc3 *dwc, enum usb_role role)
pm_runtime_use_autosuspend(dwc->dev);
}
-struct dwc3_glue_ops dwc3_imx_glue_ops = {
- .pre_set_role = dwc3_imx_pre_set_role,
+static struct dwc3_glue_ops dwc3_imx8mp_glue_ops = {
+ .pre_set_role = dwc3_imx8mp_pre_set_role,
};
static int dwc3_imx8mp_probe(struct platform_device *pdev)
@@ -266,7 +266,7 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
goto put_dwc3;
}
- dwc3->glue_ops = &dwc3_imx_glue_ops;
+ dwc3->glue_ops = &dwc3_imx8mp_glue_ops;
if (dwc3->dr_mode == USB_DR_MODE_HOST)
pm_runtime_dont_use_autosuspend(dwc3->dev);
--
2.37.2.352.g3c44437643
^ permalink raw reply related
* Re: [PATCH] usb: dwc3: imx8mp: make dwc3_imx_glue_ops static and rename to imx8mp
From: Ben Dooks @ 2026-06-23 10:11 UTC (permalink / raw)
To: Ahmad Fatoum, Thinh Nguyen, Greg Kroah-Hartman, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, linux-usb,
imx, linux-arm-kernel, linux-kernel
In-Reply-To: <39a5d53d-2eb9-4f72-aca9-95def11edf25@pengutronix.de>
On 23/06/2026 11:07, Ahmad Fatoum wrote:
>
>
> On 6/23/26 12:05 PM, Ben Dooks wrote:
>> The dwc3_imx_glue_ops is not used outside this file, and technically this
>> is the dwc3-imx8mp driver so whilst making this static to avoid the
>> following warning, rename it dwc3_imx8mp_glue_ops to distinguish it from
>> the other driver which also has dwc3_imx_glue_ops.
>>
>> Fixes:
>> drivers/usb/dwc3/dwc3-imx8mp.c:176:22: warning: symbol 'dwc3_imx_glue_ops' was not declared. Should it be static?
>>
>> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
>> ---
>> drivers/usb/dwc3/dwc3-imx8mp.c | 6 +++---
>> 1 file changed, 3 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c
>> index 1cf96540b66e..bc61a89b66b1 100644
>> --- a/drivers/usb/dwc3/dwc3-imx8mp.c
>> +++ b/drivers/usb/dwc3/dwc3-imx8mp.c
>> @@ -173,8 +173,8 @@ static void dwc3_imx_pre_set_role(struct dwc3 *dwc, enum usb_role role)
>> pm_runtime_use_autosuspend(dwc->dev);
>> }
>>
>> -struct dwc3_glue_ops dwc3_imx_glue_ops = {
>> - .pre_set_role = dwc3_imx_pre_set_role,
>> +statc struct dwc3_glue_ops dwc3_imx8mp_glue_ops = {
>
> Typo
Thanks, forgot to re-run check after this. Sent v2
>
>> + .pre_set_role = dwc3_imx8mp_pre_set_role,
>> };
>>
>> static int dwc3_imx8mp_probe(struct platform_device *pdev)
>> @@ -266,7 +266,7 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
>> goto put_dwc3;
>> }
>>
>> - dwc3->glue_ops = &dwc3_imx_glue_ops;
>> + dwc3->glue_ops = &dwc3_imx8mp_glue_ops;
>>
>> if (dwc3->dr_mode == USB_DR_MODE_HOST)
>> pm_runtime_dont_use_autosuspend(dwc3->dev);
>
--
Ben Dooks http://www.codethink.co.uk/
Senior Engineer Codethink - Providing Genius
https://www.codethink.co.uk/privacy.html
^ permalink raw reply
* Re: [PATCH 3/4] media: rkisp1: use fwnode_graph_for_each_endpoint_scoped() to simplify code
From: Andy Shevchenko @ 2026-06-23 10:16 UTC (permalink / raw)
To: Frank.Li
Cc: Daniel Scally, Heikki Krogerus, Sakari Ailus, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Mauro Carvalho Chehab,
Dafna Hirschfeld, Laurent Pinchart, Heiko Stuebner,
Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
driver-core, linux-acpi, linux-kernel, linux-media,
linux-rockchip, linux-arm-kernel, linux-arm-msm, imx, Guoniu Zhou,
Frank Li
In-Reply-To: <20260622-fw_scoped-v1-3-a37d0aac0a68@nxp.com>
On Mon, Jun 22, 2026 at 10:30:13AM -0400, Frank.Li@oss.nxp.com wrote:
> Use fwnode_graph_for_each_endpoint_scoped() to simplify code.
>
> No functional changes.
...
> - fwnode_graph_for_each_endpoint(fwnode, ep) {
> + fwnode_graph_for_each_endpoint_scoped(fwnode, ep) {
> struct fwnode_handle *port;
> struct v4l2_fwnode_endpoint vep = { };
> struct rkisp1_sensor_async *rk_asd;
> @@ -286,7 +285,6 @@ static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1)
> }
>
> if (ret) {
> - fwnode_handle_put(ep);
> v4l2_async_nf_cleanup(ntf);
> return ret;
> }
In this case you can go further and actually replace all the
ret = -Exxx;
break;
with
v4l2_async_nf_cleanup(ntf);
return -Exx;
in the above loop.
but I assume the original is also fine as it's a common denominator for all of
them (and only one case has something in addition to that).
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH 0/4] media: add and use fwnode_graph_for_each_endpoint_scoped()
From: Andy Shevchenko @ 2026-06-23 10:17 UTC (permalink / raw)
To: Frank.Li
Cc: Daniel Scally, Heikki Krogerus, Sakari Ailus, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Mauro Carvalho Chehab,
Dafna Hirschfeld, Laurent Pinchart, Heiko Stuebner,
Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
driver-core, linux-acpi, linux-kernel, linux-media,
linux-rockchip, linux-arm-kernel, linux-arm-msm, imx, Guoniu Zhou,
Frank Li
In-Reply-To: <20260622-fw_scoped-v1-0-a37d0aac0a68@nxp.com>
On Mon, Jun 22, 2026 at 10:30:10AM -0400, Frank.Li@oss.nxp.com wrote:
> Add new helper macro fwnode_graph_for_each_endpoint_scoped() and use it
> simplify media code.
>
> Typical example should qualcomm's driver (camss.c), the v4l2_mc.c and
> rkisp1-dev.c only silience improvement.
>
> Anyways, *_for_each_*_scoped() already use widely and make code clean.
LGTM,
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
for patches 2, 3, and 4.
Patch 1 has individual comments.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* chipidea: usbmisc_imx: i.MX93 support
From: Stefan Wahren @ 2026-06-23 10:23 UTC (permalink / raw)
To: Xu Yang, Frank Li
Cc: Alexander Stein, Greg Kroah-Hartman, Linux ARM,
linux-usb@vger.kernel.org
Hi,
during debugging USB OTG on our custom i.MX93 board, we noticed
remarkable differences between the implementation of the
chipidea/usbmisc_imx and the official NXP i.MX93 Reference Manual [1].
Is the USB OTG part including PHY of the i.MX93 officially supported in
Linux Mainline?
According to imx91_93_common.dtsi the USB IP of the i.MX93 should be
identical to i.MX8MM [2]
usbmisc1: usbmisc@4c100200 {
compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc",
"fsl,imx6q-usbmisc";
But looking at the PHY register definition and reset values in the NXP
i.MX93 Reference Manual,
the registers are comparable to the i.MX95 [3] ones.
Could you please clarify which source is correct (Mainline DTS vs
Reference Manual)?
Looking deeper at chipidea/usbmisc_imx shows the usage of the following
register bits
#define MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL BIT(0)
#define MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0 BIT(1)
#define MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 BIT(2)
#define MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB BIT(3)
#define MX7D_USB_OTG_PHY_STATUS_LINE_STATE0 BIT(0)
#define MX7D_USB_OTG_PHY_STATUS_LINE_STATE1 BIT(1)
#define MX7D_USB_OTG_PHY_STATUS_CHRGDET BIT(29)
According to NXP i.MX93 & i.MX95 Reference Manual, these are bits reserved.
Is it correct that the chipidea/usbmisc_imx use these bits on i.MX93?
Best regards
[1] - https://www.nxp.com/docs/en/reference-manual/IMX93RM.pdf
<https://www.nxp.com/docs/en/reference-manual/IMX93RM.pdf>
[2] - https://www.nxp.com/docs/en/reference-manual/IMX8MMRM.pdf
<https://www.nxp.com/docs/en/reference-manual/IMX8MMRM.pdf>
[3] - https://www.nxp.com/docs/en/reference-manual/IMX95RM.pdf
<https://www.nxp.com/docs/en/reference-manual/IMX95RM.pdf>
^ permalink raw reply
* [PATCH] media: imx-jpeg: cancel timeout worker when streaming stops
From: Fan Wu @ 2026-06-23 10:30 UTC (permalink / raw)
To: mirela.rabulea, mchehab
Cc: shawnguo, s.hauer, kernel, festevam, imx, linux-media,
linux-arm-kernel, linux-kernel, stable, Fan Wu
Each per-fd context ctx owns a delayed_work (ctx->task_timer, callback
mxc_jpeg_device_run_timeout) armed via schedule_delayed_work() at the end
of mxc_jpeg_device_run() to recover a stalled encode/decode job. The only
existing cancellation is cancel_delayed_work() in the frame-done IRQ
handler, which de-queues a pending work item but does not wait for a
callback that has already started, and it only runs when a frame completes.
When the fd is closed while a job is in flight (the frame-done IRQ has not
fired yet), nothing syncs the worker before mxc_jpeg_release() frees ctx
with kfree() after v4l2_m2m_ctx_release(). A queued or executing
mxc_jpeg_device_run_timeout() can then recover ctx through
container_of(&ctx->task_timer) and dereference it (ctx->mxc_jpeg,
slot_data, dev_warn) after ctx has been freed.
Cancel the worker from mxc_jpeg_stop_streaming(). The cancel cannot live
in mxc_jpeg_release(): mxc_jpeg_device_run() arms the timer while holding
only hw_lock, not the mxc_jpeg->lock mutex that release holds, so a cancel
in release could still race a concurrent mxc_jpeg_device_run() that
re-arms the timer afterwards. mxc_jpeg_stop_streaming() instead runs inside
v4l2_m2m_ctx_release() -> vb2_queue_release(), i.e. after
v4l2_m2m_cancel_job() has set TRANS_ABORT and waited for any in-flight job
to finish (so __v4l2_m2m_try_queue() will not queue and v4l2_m2m_try_run()
will not run any further job for this context, which prevents
mxc_jpeg_device_run() from re-arming the timer) and before the m2m context
is freed. cancel_delayed_work_sync() removes a pending work item and waits
for a running callback, so the worker can no longer race with the
subsequent kfree(). The cancel is placed before the buffer-release loop so
a concurrently running timeout callback cannot race with it over the same
buffers. If the frame-done IRQ canceled a still-pending timer, this cancel
is a no-op; if the timeout callback has already started, it waits for the
callback to finish. The same mxc_jpeg_stop_streaming() call is also
reached from VIDIOC_STREAMOFF, which drains the worker early, although
STREAMOFF itself does not free ctx -- the use-after-free arises only
when the fd is later closed.
This bug was found by static analysis.
Fixes: cfed9632ca8e ("media: imx-jpeg: Add a timeout mechanism for each frame")
Cc: stable@vger.kernel.org
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
---
drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
index 9e4a813489c0..d85a9d196269 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
@@ -1735,6 +1735,8 @@ static void mxc_jpeg_stop_streaming(struct vb2_queue *q)
dev_dbg(ctx->mxc_jpeg->dev, "Stop streaming ctx=%p", ctx);
+ cancel_delayed_work_sync(&ctx->task_timer);
+
/* Release all active buffers */
for (;;) {
if (V4L2_TYPE_IS_OUTPUT(q->type))
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v3] drm/bridge: imx93-mipi-dsi: Fix mode validation
From: Luca Ceresoli @ 2026-06-23 10:41 UTC (permalink / raw)
To: Liu Ying, Luca Ceresoli
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Dmitry Baryshkov, dri-devel, imx, linux-arm-kernel, linux-kernel
In-Reply-To: <ajjpuroFPI_U2Fw6@raspi>
Hello Liu,
On Mon Jun 22, 2026 at 9:52 AM CEST, Liu Ying wrote:
> On Fri, Jun 19, 2026 at 06:49:55PM +0200, Luca Ceresoli wrote:
>> Hello Liu,
>
> Hi Luca,
>
>>
>> On Fri May 15, 2026 at 8:54 AM CEST, Liu Ying wrote:
>> > i.MX93 MIPI DPHY PLL has limitation for matching with some pixel clock
>> > rates, e.g., the best DPHY PLL frequency is 445.333333MHz for a typical
>> > 1920x1080p@60Hz CEA/DMT display mode with a pixel clock rate running
>> > at 148.5MHz with 4 data lanes + RGB888 pixel in MIPI DSI sync pulse mode,
>> > while the expected PLL frequency is (148.5 * 24) / 4 / 2 MHz = 445.5MHz.
>> > Fortunately, VESA Display Monitor Timing Standard allows +/-0.5% pixel
>> > clock rate deviation for timings. So, for those display modes read
>> > from EDID through a bridge with DRM_BRIDGE_OP_DETECT and DRM_BRIDGE_OP_EDID
>> > operation bit masks set, pixel clock rate could be adjusted to match
>> > with the PLL frequency(for the above example, the pixel clock rate is
>> > adjusted to be 148.444444MHz with about -0.03% deviation from the 148.5MHz
>> > nominal rate so that the adjusted rate matches with the 445.333333MHz PLL
>> > frequency).
>> >
>> > Instead of checking the last bridge's operation bit masks against
>> > DRM_BRIDGE_OP_DETECT and DRM_BRIDGE_OP_EDID to determine if allowing
>> > +/-0.5% pixel clock rate deviation, check any bridge after this bridge,
>> > because the last bridge is usually a display connector bridge without
>> > any operation bit mask when the clock rate deviation is allowed.
>> >
>> > Fixes: ce62f8ea7e3f ("drm/bridge: imx: Add i.MX93 MIPI DSI support")
>> > Fixes: 5849eff7f067 ("drm/bridge: imx93-mipi-dsi: use drm_bridge_chain_get_last_bridge()")
>> > Reviewed-by: Frank Li <Frank.Li@nxp.com>
>> > Signed-off-by: Liu Ying <victor.liu@nxp.com>
>>
>> I'm perhaps not the most qualified to review this change, but let me try.
>
> Thanks for your review.
>
>>
>> > --- a/drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c
>> > +++ b/drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c
>> > @@ -489,25 +489,43 @@ static int imx93_dsi_get_phy_configure_opts(struct imx93_dsi *dsi,
>> > return 0;
>> > }
>> >
>> > +static inline struct drm_bridge *
>> > +imx93_dsi_get_next_bridge_in_chain(struct drm_bridge *bridge)
>> > +{
>> > + struct drm_bridge *next = drm_bridge_get_next_bridge(bridge);
>> > +
>> > + drm_bridge_put(bridge);
>> > +
>> > + return next;
>> > +}
>> > +
>> > static enum drm_mode_status
>> > imx93_dsi_validate_mode(struct imx93_dsi *dsi, const struct drm_display_mode *mode)
>> > {
>> > struct drm_bridge *dmd_bridge = dw_mipi_dsi_get_bridge(dsi->dmd);
>> > - struct drm_bridge *last_bridge __free(drm_bridge_put) =
>> > - drm_bridge_chain_get_last_bridge(dmd_bridge->encoder);
>> > + struct drm_bridge *bridge;
>> >
>> > - if ((last_bridge->ops & DRM_BRIDGE_OP_DETECT) &&
>> > - (last_bridge->ops & DRM_BRIDGE_OP_EDID)) {
>> > - unsigned long pixel_clock_rate = mode->clock * 1000;
>> > - unsigned long rounded_rate;
>> > + for (bridge = drm_bridge_get_next_bridge(dmd_bridge);
>> > + bridge;
>> > + bridge = imx93_dsi_get_next_bridge_in_chain(bridge)) {
>> > + if ((bridge->ops & DRM_BRIDGE_OP_DETECT) &&
>> > + (bridge->ops & DRM_BRIDGE_OP_EDID)) {
>> > + unsigned long pixel_clock_rate = mode->clock * 1000;
>> > + unsigned long rounded_rate;
>> >
>> > - /* Allow +/-0.5% pixel clock rate deviation */
>> > - rounded_rate = clk_round_rate(dsi->clk_pixel, pixel_clock_rate);
>> > - if (rounded_rate < pixel_clock_rate * 995 / 1000 ||
>> > - rounded_rate > pixel_clock_rate * 1005 / 1000) {
>> > - dev_dbg(dsi->dev, "failed to round clock for mode " DRM_MODE_FMT "\n",
>> > - DRM_MODE_ARG(mode));
>> > - return MODE_NOCLOCK;
>> > + /* Allow +/-0.5% pixel clock rate deviation */
>> > + rounded_rate = clk_round_rate(dsi->clk_pixel, pixel_clock_rate);
>> > + if (rounded_rate < pixel_clock_rate * 995 / 1000 ||
>> > + rounded_rate > pixel_clock_rate * 1005 / 1000) {
>> > + dev_dbg(dsi->dev,
>> > + "failed to round clock for mode " DRM_MODE_FMT "\n",
>> > + DRM_MODE_ARG(mode));
>> > + drm_bridge_put(bridge);
>> > + return MODE_NOCLOCK;
>> > + }
>> > +
>> > + drm_bridge_put(bridge);
>> > + break;
>> > }
>> > }
>>
>> Is this logic specific to the imx93 MIPI DSI host only? Or should it be
>> made generic for all dw-hdmi users, or even every DSI host?
>
> I think it's kind of specific to the i.MX93 MIPI DSI host only, because
> 1) the i.MX93 MIPI DPHY PLL(integrated into i.MX93 MIPI DPHY IP) supports
> the best DPHY PLL frequency @445.333333MHz for the typical 1920x1080p@60Hz
> display mode, which is lower than the expected/nominal frequency @445.5MHz
> and 2) the generic DW MIPI DSI driver(dw-mipi-dsi.c) is PHY-agnostic, which
> means vendors may attach different MIPI DPHY IPs to the common MIPI DSI host
> IP and likely there would be no frequency mismatch between the pixel clock
> and the PLL like i.MX93 has.
I see, OK, thanks for the clarification!
>> Also, iterating over the bridge chain is not very clean. I'm working on
>> bridge hotplug (not upstream yet) and bad things would happen if a bridge
>> were hot-unplugged during this loop.
>
> The iterating is essentially the same to drm_for_each_bridge_in_chain_from()
> except that bridge_chain_mutex is not taken(since it's already taken) and
> the starting bridge is fixed to be the next bridge. A few bridge core APIs
> like drm_bridge_chain_mode_valid() call drm_for_each_bridge_in_chain_from().
> So, the iterating looks clean to me and I'm not aware of any bad things which
> would happen when bridge hotplug is considered.
I had missed this is called from drm_bridge_chain_mode_valid(), which
already takes the bridge_chain_mutex thanks to
drm_for_each_bridge_in_chain_from().
So that means this loop is safe, but it would be nice to add a comment to
make it clear to future readers. E.g. "/* we are called by
drm_bridge_chain_mode_valid(), so the bridge_chain_mutex is locked */".
Still I'm not a fan of having a loop over the bridge chain (this function)
inside another loop over the same bridge chain (in
drm_bridge_chain_mode_valid(). And even more I'm not a fan of drivers
walking around the bridge chain on their own, IMO the core (perhaps
drm_bridge.c in this case) should to the loops . However this is a general
concern, it happens also elsewhere, and I have no immediate proposal to
improve this, so don't consider it as a blocker for this patch.
>> If the core did this sort of algorithm
>> it would be able to be more robust.
>
> Is the core dw-mipi-dsi.c?
> If yes, do you think it's worth doing that even if the frequency mismatch
> between the pixel clock and the PLL is kind of specific to the i.MX93 MIPI
> DSI host?
>
>>
>> Finally, out of my utter ignorance on the subject, is the VESA +/-0.5%
>> margin generic enough that this driver can always rely on it?
>
> I see several upstream drivers rely on it, see "git grep '0.5%' drivers/gpu/"
> output. And every display mode allows -/+ 0.5% pixel clock rate deviation
> according to VESA Display Monitor Timing Standard [1], though [1] is a found
> by a random Google search.
>
> [1] https://glenwing.github.io/docs/VESA-DMT-1.13.pdf
As I said I'm quite ignorance about this aspect, so I asked to better
understand. In reply to another part fo the thread: no, I don't have a
specific concern if this is the common practice.
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH] ASoC: rockchip: rockchip_sai: Hand over hclk control exclusively to Runtime PM
From: Bui Duc Phuc @ 2026-06-23 10:53 UTC (permalink / raw)
To: Mark Brown
Cc: Heiko Stuebner, Liam Girdwood, Nicolas Frattaroli,
Krzysztof Kozlowski, Jaroslav Kysela, Takashi Iwai, linux-sound,
linux-rockchip, linux-arm-kernel, linux-kernel
In-Reply-To: <229ba136-66eb-4a30-a316-58377836b4dc@sirena.org.uk>
Hi Mark,
Thank you for your review.
> > 1 Reverting back to devm_clk_get() to remove the implicit devres
> > enable/disable behavior.
> > 2 Manually enabling and disabling hclk explicitly only around the
> > early register access before Runtime PM takes over.
> > 3 Dropping the stray clk_disable_unprepare() at the end of probe()
> > so Runtime PM solely owns hclk afterward.
>
> Note that runtime PM can be disabled at build time so we might not have
> runtime PM at all...
>
Thanks for pointing this out. You're right that with !CONFIG_PM, the
driver only relies on the
two manual calls to rokchip_sai_runtime_resume() / suspend(), so hclk
stays enabled the
whole time. I understand this is unvavoidable in that configuration,
throgh, since there's no
Runtime PM to re-enable the clock when it's needed.
I'll update the commit message to reflect that the driver uses a
combination of Runtime PM
and explicit manual enable/disable, rather than relying on Runtime PM alone.
> > Links:
> > 1 This change is based on the discussion around manual hclk handing during probe(),
> > as raised by Krysztof:
> > https://lore.kernel.org/all/20e4754b-ea9a-404d-b529-ec44a7263cbf@kernel.org/#t
> > 2 Background for the earlier devm_clk_get_enbabled() conversion:
> > https://lore.kernel.org/all/2818018.CQOukoFCf9@workhorse/
>
> > An alternative approach would be use devm_regmap_init_mmio_clk() and let regmap
> > manage clock enablement around register accesses. If preferred, I can rework the
> > driver accordingly.
>
> > - sai->hclk = devm_clk_get_enabled(&pdev->dev, "hclk");
> > + sai->hclk = devm_clk_get(&pdev->dev, "hclk");
> > if (IS_ERR(sai->hclk))
> > return dev_err_probe(&pdev->dev, PTR_ERR(sai->hclk),
> > "Failed to get hclk\n");
> >
> > + ret = clk_prepare_enable(sai->hclk);
> > + if (ret)
> > + return dev_err_probe(&pdev->dev, ret, "Failed to enable hclk\n");
> > +
>
> > @@ -1482,8 +1492,6 @@ static int rockchip_sai_probe(struct platform_device *pdev)
> > pm_runtime_use_autosuspend(&pdev->dev);
> > pm_runtime_put(&pdev->dev);
> >
> > - clk_disable_unprepare(sai->hclk);
> > -
> > return 0;
>
> Are you sure that the runtime PM state there is such that it knows a
> reference is held? The driver used pm_runtime_get_noresume() so the
> device didn't have RPM_ACTIVE set I think?
You are right, pm_runtime_get_noresume() doesn't set RPM_ACTIVE. I
think we need to add
pm_runtime_set_active() before pm_runtime_enable(). Otherwise, with CONFIG_PM,
the pm_runtime_put() at the end of probe() might skip the suspend,
since the core still considers
the device suspended .
>
> The runtime PM API really is a miserable collection of landmines :(
Yeah, plenty of landmines indeed :(
I checked, and rockchip_spdif.c does use devm_regmap_init_mmio_clk() for hclk,
rather than wrapping every register access in pm_runtime_get_sync() /
pm_runtime_put()
the way rockchip_sai does.
Best regards,
Phuc
^ permalink raw reply
* Re: [PATCH net v2] net: airoha: Add retry mechanism to airoha_qdma_set_trtcm_param()
From: Simon Horman @ 2026-06-23 10:53 UTC (permalink / raw)
To: lorenzo
Cc: Simon Horman, andrew+netdev, davem, edumazet, kuba, pabeni,
leto.liu, linux-arm-kernel, linux-mediatek, netdev, brown.huang
In-Reply-To: <20260622-airoha_qdma_set_trtcm_param-retry-fix-v2-1-95a83ac99dbd@kernel.org>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
Simon says: I'd appreciate it if you could look over the first two issues
flagged below in the context of this patch. While the third
and final issue looks like it is in possible separate follow-up
territory.
---
net: airoha: Add retry mechanism to airoha_qdma_set_trtcm_param()
This patch introduces a retry loop to airoha_qdma_set_trtcm_param() to mitigate
bus timeouts when configuring QDMA parameters. It attempts to verify that the
configuration is correctly applied to the hardware.
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> index 3370c3df7c107..bb5c0599a4eed 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.c
> +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> @@ -2673,14 +2673,30 @@ static int airoha_qdma_set_trtcm_param(struct airoha_qdma *qdma, int channel,
> FIELD_PREP(TRTCM_METER_GROUP_MASK, group) |
> FIELD_PREP(TRTCM_PARAM_INDEX_MASK, idx) |
> FIELD_PREP(TRTCM_PARAM_RATE_TYPE_MASK, mode);
> + int i;
>
> - airoha_qdma_wr(qdma, REG_TRTCM_DATA_LOW(addr), val);
> - airoha_qdma_wr(qdma, REG_TRTCM_CFG_PARAM(addr), config);
> + for (i = 0; i < 100; i++) {
> + u32 data;
>
> - return read_poll_timeout(airoha_qdma_rr, val,
> - val & TRTCM_PARAM_RW_DONE_MASK,
> - USEC_PER_MSEC, 10 * USEC_PER_MSEC, true,
> - qdma, REG_TRTCM_CFG_PARAM(addr));
> + airoha_qdma_wr(qdma, REG_TRTCM_DATA_LOW(addr), val);
> + wmb();
> + airoha_qdma_wr(qdma, REG_TRTCM_CFG_PARAM(addr), config);
> +
> + if (read_poll_timeout(airoha_qdma_rr, data,
> + data & TRTCM_PARAM_RW_DONE_MASK,
> + USEC_PER_MSEC, 10 * USEC_PER_MSEC,
> + true, qdma, REG_TRTCM_CFG_PARAM(addr)))
> + return -ETIMEDOUT;
[Severity: High]
If a bus timeout causes the write phase's read_poll_timeout() in
airoha_qdma_set_trtcm_param() to fail, this immediately returns -ETIMEDOUT,
aborting the 100-iteration retry loop.
Doesn't this defeat the mitigation?
> +
> + if (airoha_qdma_get_trtcm_param(qdma, channel, addr, param,
> + mode, &data, NULL))
> + continue;
[Severity: High]
If airoha_qdma_get_trtcm_param() times out during the verification phase, it
indicates the hardware hasn't finished the read command (DONE bit is still 0).
The continue statement then immediately starts the next iteration, writing new
commands to DATA_LOW and CFG_PARAM.
Can writing to command registers while the hardware state machine is actively
busy violate hardware protocols and lead to unrecoverable lockups?
> +
> + if (data == val)
> + return 0;
[Severity: High]
This isn't a bug introduced by this patch, but if the bus drops the command
write to REG_TRTCM_CFG_PARAM, the hardware never executes the command and the
TRTCM_PARAM_RW_DONE_MASK bit remains set from the previous operation.
Consequently, read_poll_timeout() returns an immediate false success.
If both the set and get command writes are dropped by the bus, the get
operation will read back the newly written DATA_LOW register value.
Will the data == val check evaluate to true and falsely report success without
the hardware ever processing the configuration?
> + }
> +
> + return -EBUSY;
> }
>
[ ... ]
> static int airoha_qdma_set_trtcm_config(struct airoha_qdma *qdma, int channel,
> u32 addr, enum trtcm_mode_type mode,
> bool enable, u32 enable_mask)
> {
> u32 val;
>
> if (airoha_qdma_get_trtcm_param(qdma, channel, addr, TRTCM_MISC_MODE,
> mode, &val, NULL))
> return -EINVAL;
[Severity: High]
Standalone calls to airoha_qdma_get_trtcm_param(), like this one in
airoha_qdma_set_trtcm_config(), lack a retry loop entirely.
Does this leave read-modify-write cycles fully vulnerable to the same bus
timeouts the patch attempts to mitigate?
[Severity: High]
This isn't a bug introduced by this patch, but the patch mitigates bus
timeouts in airoha_qdma_set_trtcm_param() while entirely missing
airoha_qdma_set_rl_param().
The latter performs the exact same write-and-poll sequence on identical QDMA
configuration registers:
drivers/net/ethernet/airoha/airoha_eth.c:airoha_qdma_set_rl_param() {
...
return read_poll_timeout(..., val & RATE_LIMIT_PARAM_RW_DONE_MASK, ...);
}
If bus timeouts affect QDMA access broadly as stated in the commit message, are
the rate-limiting configuration paths randomly vulnerable to the same failures?
[Severity: High]
This isn't a bug introduced by this patch, but in airoha_tc_remove_htb_queue(),
hardware teardown incorrectly uses queue + 1 instead of queue:
drivers/net/ethernet/airoha/airoha_eth.c:airoha_tc_remove_htb_queue() {
...
airoha_qdma_set_tx_rate_limit(netdev, queue + 1, 0, 0);
...
}
Does this leave the removed queue's hardware limits permanently active
(resource leak) and inadvertently disable the rate limits for queue + 1,
corrupting the QoS state of another active channel?
^ permalink raw reply
* [PATCH v2 00/12] Add thermal management support for sama7d65
From: Varshini Rajendran @ 2026-06-23 10:59 UTC (permalink / raw)
To: ehristev, jic23, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, srini,
linux-iio, devicetree, linux-arm-kernel, linux-kernel
Cc: varshini.rajendran
Apologies for the significant delay in following up this series.
Thank you for your patience and the earlier reviews.
This v2 reworks the series based on the feedback received on v1.
The thermal management system of sama7d65 includes:
- Temperature sensor as a part of ADC channel
- Temperature calibration data retrieved from the OTP memory for
improved accuracy of the readings
- DVFS implementation
- Thermal system with DVFS as cooling cell.
This patch series adds support for the following:
- Tag-based packet lookup for the NVMEM OTPC driver while preserving
backward compatibility with existing ID-based access
- Temperature calibration layout handling in the ADC driver to support
different SoC-specific calibration data formats
- ADC driver adaptation for sama7d65
- DT nodes for OTP, ADC, temperature sensor, and thermal zones for
sama7d65
Changes in v2:
- Preserved backward compatibility with ID-based packet lookup to
avoid breaking existing users
- Removed sama7g5 DTS changes (not needed with backward compatible
driver - will be sent later to update to the new access method)
- Preserved the packet data structure returned not to break the
consumers
- Reworked ADC driver to use a calibration layout structure instead of
hardcoded indexes, for scalability
- Fixed kernel-doc Return section
- Removed stray blank line in mchp_otpc_read()
- Removed unnecessary UL suffix in writel_relaxed()
- Dropped unused packet types
- Fixed stray spaces before exclamation marks in error messages
- Added ASCII representation to TAG macro definition
- Removed odd MAX enum with trailing comma and refactored
- Moved DTS patches to the end of series
- Used cleanup.h helpers for NVMEM data buffer handling in ADC driver
- Combined multiple v1 patches into logical units
- Used correct subject prefixes for dt-bindings patches
- Used fixed-layout NVMEM syntax for sama7d65 DTS and binding
instead of deprecated syntax
- Added cpu-supply linkage for proper DVFS voltage scaling
- Updated stale stride=4 comment in dt-bindings header
Link to v1: https://lore.kernel.org/linux-arm-kernel/20250804100219.63325-1-varshini.rajendran@microchip.com/
Varshini Rajendran (12):
dt-bindings: iio: adc: at91-sama5d2: document sama7d65
iio: adc: at91-sama5d2_adc: rework temp calibration layout handling
iio: adc: at91-sama5d2_adc: adapt the driver for sama7d65
dt-bindings: nvmem: microchip,sama7g5-otpc: add sama7d65 and dt node
example
nvmem: microchip-otpc: add tag-based packet lookup
ARM: dts: microchip: sama7d65: add cpu opps
ARM: dts: microchip: sama7d65: Add ADC node
ARM: dts: microchip: sama7d65_curiosity: Enable ADC, DVFS
ARM: dts: microchip: sama7d65: add otpc node
ARM: dts: microchip: sama7d65: add cells for temperature calibration
ARM: dts: microchip: sama7d65: add temperature sensor
ARM: dts: microchip: sama7d65: add thermal zones node
.../bindings/iio/adc/atmel,sama5d2-adc.yaml | 1 +
.../nvmem/microchip,sama7g5-otpc.yaml | 28 +++-
.../dts/microchip/at91-sama7d65_curiosity.dts | 27 ++++
arch/arm/boot/dts/microchip/sama7d65.dtsi | 132 ++++++++++++++++
drivers/iio/adc/at91-sama5d2_adc.c | 116 ++++++++++----
drivers/nvmem/microchip-otpc.c | 142 ++++++++++++++++--
.../nvmem/microchip,sama7g5-otpc.h | 4 +-
7 files changed, 409 insertions(+), 41 deletions(-)
--
2.34.1
^ permalink raw reply
* Re: [PATCH v3 4/4] clk: rockchip: rk3588: add GATE_GRF clocks for I2S MCLK output to IO
From: Diederik de Haas @ 2026-06-23 10:59 UTC (permalink / raw)
To: Daniele Briguglio, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner
Cc: Nicolas Frattaroli, linux-clk, devicetree, linux-arm-kernel,
linux-rockchip, linux-kernel, Ricardo Pardini
In-Reply-To: <20260320-rk3588-mclk-gate-grf-v3-4-980338eacd2c@superkali.me>
Hi,
On Fri Mar 20, 2026 at 11:34 AM CET, Daniele Briguglio wrote:
> The I2S MCLK outputs on RK3588 are gated by bits in the SYS_GRF
> register SOC_CON6 (offset 0x318). These gates control whether the
> internal CRU MCLK signals reach the external IO pins connected to
> audio codecs.
>
> The kernel should explicitly manage these gates so that audio
> functionality does not depend on bootloader register state. This is
> analogous to what was done for RK3576 SAI MCLK outputs [1].
>
> Register the SYS_GRF as an auxiliary GRF with grf_type_sys in the
> early clock init, and add GATE_GRF entries for all four I2S MCLK
> output gates:
>
> - I2S0_8CH_MCLKOUT_TO_IO (bit 0)
> - I2S1_8CH_MCLKOUT_TO_IO (bit 1)
> - I2S2_2CH_MCLKOUT_TO_IO (bit 2)
> - I2S3_2CH_MCLKOUT_TO_IO (bit 7)
>
> Board DTS files that need MCLK on an IO pin can reference these
> clocks, e.g.:
>
> clocks = <&cru I2S0_8CH_MCLKOUT_TO_IO>;
>
> Tested on the Youyeetoo YY3588 (RK3588) with an ES8388 codec on I2S0.
Doesn't this break audio on a lot of RK3588 based boards?
I have a kernel with this patch set and since then analog audio on my NanoPC-T6
LTS and my WIP NanoPC-T6 Plus stopped working.
Until I did s/I2S0_8CH_MCLKOUT/I2S0_8CH_MCLKOUT_TO_IO/ in my dts[i] files.
And I wouldn't be surprised if the same thing applies to other RK3588 based
boards? The same dtb file with a 7.1 kernel, without this patch set, works.
Cheers,
Diederik
> [1] https://lore.kernel.org/r/20250305-rk3576-sai-v1-2-64e6cf863e9a@collabora.com/
>
> Reviewed-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> Tested-by: Ricardo Pardini <ricardo@pardini.net>
> Signed-off-by: Daniele Briguglio <hello@superkali.me>
> ---
> drivers/clk/rockchip/clk-rk3588.c | 24 ++++++++++++++++++++++++
> 1 file changed, 24 insertions(+)
>
> diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c
> index 1694223f4f84..2cc85fb5b2cc 100644
> --- a/drivers/clk/rockchip/clk-rk3588.c
> +++ b/drivers/clk/rockchip/clk-rk3588.c
> @@ -5,11 +5,14 @@
> */
>
> #include <linux/clk-provider.h>
> +#include <linux/mfd/syscon.h>
> #include <linux/of.h>
> +#include <linux/slab.h>
> #include <linux/of_address.h>
> #include <linux/platform_device.h>
> #include <linux/syscore_ops.h>
> #include <dt-bindings/clock/rockchip,rk3588-cru.h>
> +#include <soc/rockchip/rk3588_grf.h>
> #include "clk.h"
>
> #define RK3588_GRF_SOC_STATUS0 0x600
> @@ -892,6 +895,8 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
> RK3588_CLKGATE_CON(8), 0, GFLAGS),
> MUX(I2S2_2CH_MCLKOUT, "i2s2_2ch_mclkout", i2s2_2ch_mclkout_p, CLK_SET_RATE_PARENT,
> RK3588_CLKSEL_CON(30), 2, 1, MFLAGS),
> + GATE_GRF(I2S2_2CH_MCLKOUT_TO_IO, "i2s2_2ch_mclkout_to_io", "i2s2_2ch_mclkout",
> + 0, RK3588_SYSGRF_SOC_CON6, 2, GFLAGS, grf_type_sys),
>
> COMPOSITE(CLK_I2S3_2CH_SRC, "clk_i2s3_2ch_src", gpll_aupll_p, 0,
> RK3588_CLKSEL_CON(30), 8, 1, MFLAGS, 3, 5, DFLAGS,
> @@ -907,6 +912,8 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
> RK3588_CLKGATE_CON(8), 4, GFLAGS),
> MUX(I2S3_2CH_MCLKOUT, "i2s3_2ch_mclkout", i2s3_2ch_mclkout_p, CLK_SET_RATE_PARENT,
> RK3588_CLKSEL_CON(32), 2, 1, MFLAGS),
> + GATE_GRF(I2S3_2CH_MCLKOUT_TO_IO, "i2s3_2ch_mclkout_to_io", "i2s3_2ch_mclkout",
> + 0, RK3588_SYSGRF_SOC_CON6, 7, GFLAGS, grf_type_sys),
> GATE(PCLK_ACDCDIG, "pclk_acdcdig", "pclk_audio_root", 0,
> RK3588_CLKGATE_CON(7), 11, GFLAGS),
> GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_audio_root", 0,
> @@ -935,6 +942,8 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
> RK3588_CLKGATE_CON(7), 10, GFLAGS),
> MUX(I2S0_8CH_MCLKOUT, "i2s0_8ch_mclkout", i2s0_8ch_mclkout_p, CLK_SET_RATE_PARENT,
> RK3588_CLKSEL_CON(28), 2, 2, MFLAGS),
> + GATE_GRF(I2S0_8CH_MCLKOUT_TO_IO, "i2s0_8ch_mclkout_to_io", "i2s0_8ch_mclkout",
> + 0, RK3588_SYSGRF_SOC_CON6, 0, GFLAGS, grf_type_sys),
>
> GATE(HCLK_PDM1, "hclk_pdm1", "hclk_audio_root", 0,
> RK3588_CLKGATE_CON(9), 6, GFLAGS),
> @@ -2220,6 +2229,8 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
> RK3588_PMU_CLKGATE_CON(2), 13, GFLAGS),
> MUX(I2S1_8CH_MCLKOUT, "i2s1_8ch_mclkout", i2s1_8ch_mclkout_p, CLK_SET_RATE_PARENT,
> RK3588_PMU_CLKSEL_CON(9), 2, 2, MFLAGS),
> + GATE_GRF(I2S1_8CH_MCLKOUT_TO_IO, "i2s1_8ch_mclkout_to_io", "i2s1_8ch_mclkout",
> + 0, RK3588_SYSGRF_SOC_CON6, 1, GFLAGS, grf_type_sys),
> GATE(PCLK_PMU1, "pclk_pmu1", "pclk_pmu0_root", CLK_IS_CRITICAL,
> RK3588_PMU_CLKGATE_CON(1), 0, GFLAGS),
> GATE(CLK_DDR_FAIL_SAFE, "clk_ddr_fail_safe", "clk_pmu0", CLK_IGNORE_UNUSED,
> @@ -2439,6 +2450,8 @@ static struct rockchip_clk_branch rk3588_clk_branches[] = {
> static void __init rk3588_clk_early_init(struct device_node *np)
> {
> struct rockchip_clk_provider *ctx;
> + struct rockchip_aux_grf *sys_grf_e;
> + struct regmap *sys_grf;
> unsigned long clk_nr_clks, max_clk_id1, max_clk_id2;
> void __iomem *reg_base;
>
> @@ -2479,6 +2492,17 @@ static void __init rk3588_clk_early_init(struct device_node *np)
> &rk3588_cpub1clk_data, rk3588_cpub1clk_rates,
> ARRAY_SIZE(rk3588_cpub1clk_rates));
>
> + /* Register SYS_GRF for I2S MCLK output to IO gate clocks */
> + sys_grf = syscon_regmap_lookup_by_compatible("rockchip,rk3588-sys-grf");
> + if (!IS_ERR(sys_grf)) {
> + sys_grf_e = kzalloc_obj(*sys_grf_e);
> + if (sys_grf_e) {
> + sys_grf_e->grf = sys_grf;
> + sys_grf_e->type = grf_type_sys;
> + hash_add(ctx->aux_grf_table, &sys_grf_e->node, grf_type_sys);
> + }
> + }
> +
> rockchip_clk_register_branches(ctx, rk3588_early_clk_branches,
> ARRAY_SIZE(rk3588_early_clk_branches));
>
^ permalink raw reply
* [PATCH v2 01/12] dt-bindings: iio: adc: at91-sama5d2: document sama7d65
From: Varshini Rajendran @ 2026-06-23 10:59 UTC (permalink / raw)
To: ehristev, jic23, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, srini,
linux-iio, devicetree, linux-arm-kernel, linux-kernel
Cc: varshini.rajendran, Krzysztof Kozlowski
In-Reply-To: <20260623105944.128840-1-varshini.rajendran@microchip.com>
Add dt-binding documentation for sama7d65 ADC.
Signed-off-by: Varshini Rajendran <varshini.rajendran@microchip.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml b/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml
index 4817b840977a..e8a65fdcd018 100644
--- a/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml
@@ -15,6 +15,7 @@ properties:
- atmel,sama5d2-adc
- microchip,sam9x60-adc
- microchip,sama7g5-adc
+ - microchip,sama7d65-adc
reg:
maxItems: 1
--
2.34.1
^ permalink raw reply related
* [PATCH v2 02/12] iio: adc: at91-sama5d2_adc: rework temp calibration layout handling
From: Varshini Rajendran @ 2026-06-23 10:59 UTC (permalink / raw)
To: ehristev, jic23, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, srini,
linux-iio, devicetree, linux-arm-kernel, linux-kernel
Cc: varshini.rajendran
In-Reply-To: <20260623105944.128840-1-varshini.rajendran@microchip.com>
Extend support to handle different temperature calibration layouts.
Add a temperature calibration data layout structure to describe indexes
of the factors P1, P4, P6, tag, minimum length of the packet and the
scaling factors for P1 (mul, div) which are SoC-specific instead of the
older non scalable id structure. This helps handle the differences in the
same function flow and prepare the calibration data to be applied. Add
additional condition to validate the calibration data read from the
NVMEM cell using the TAG of the packet.
Use cleanup helpers for NVMEM data buffer wherever applicable.
Signed-off-by: Varshini Rajendran <varshini.rajendran@microchip.com>
---
drivers/iio/adc/at91-sama5d2_adc.c | 85 ++++++++++++++++++++----------
1 file changed, 58 insertions(+), 27 deletions(-)
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index 255970b2e747..b569d175f4c3 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -445,6 +445,28 @@ static const struct at91_adc_reg_layout sama7g5_layout = {
#define at91_adc_writel(st, reg, val) \
writel_relaxed(val, (st)->base + (st)->soc_info.platform->layout->reg)
+#define AT91_TEMP_CALIB_TAG_ACST 0x41435354
+
+/**
+ * struct at91_adc_temp_calib_layout - temperature calibration packet layout
+ * @tag_idx: index of Packet tag in the NVMEM cell buffer
+ * @p1_idx: index of FT1_TEMP, equivalent to P1 in the NVMEM cell buffer
+ * @p4_idx: index of FT1_VPAT, equivalent to P4 in the NVMEM cell buffer
+ * @p6_idx: index of FT2_VBG, equivalent to P6 in the NVMEM cell buffer
+ * @min_len: minimum number of u32 words expected in the NVMEM cell buffer
+ * @p1_mul: multiplier applied to P1 to convert to millicelcius
+ * @p1_div: divider applied to P1 to convert to millicelcius
+ */
+struct at91_adc_temp_calib_layout {
+ unsigned int tag_idx;
+ unsigned int p1_idx;
+ unsigned int p4_idx;
+ unsigned int p6_idx;
+ unsigned int min_len;
+ unsigned int p1_mul;
+ unsigned int p1_div;
+};
+
/**
* struct at91_adc_platform - at91-sama5d2 platform information struct
* @layout: pointer to the reg layout struct
@@ -464,6 +486,7 @@ static const struct at91_adc_reg_layout sama7g5_layout = {
* @chan_realbits: realbits for registered channels
* @temp_chan: temperature channel index
* @temp_sensor: temperature sensor supported
+ * @temp_calib_layout: temperature calibration packet layout
*/
struct at91_adc_platform {
const struct at91_adc_reg_layout *layout;
@@ -481,6 +504,7 @@ struct at91_adc_platform {
unsigned int chan_realbits;
unsigned int temp_chan;
bool temp_sensor;
+ const struct at91_adc_temp_calib_layout *temp_calib_layout;
};
/**
@@ -496,18 +520,14 @@ struct at91_adc_temp_sensor_clb {
u32 p6;
};
-/**
- * enum at91_adc_ts_clb_idx - calibration indexes in NVMEM buffer
- * @AT91_ADC_TS_CLB_IDX_P1: index for P1
- * @AT91_ADC_TS_CLB_IDX_P4: index for P4
- * @AT91_ADC_TS_CLB_IDX_P6: index for P6
- * @AT91_ADC_TS_CLB_IDX_MAX: max index for temperature calibration packet in OTP
- */
-enum at91_adc_ts_clb_idx {
- AT91_ADC_TS_CLB_IDX_P1 = 2,
- AT91_ADC_TS_CLB_IDX_P4 = 5,
- AT91_ADC_TS_CLB_IDX_P6 = 7,
- AT91_ADC_TS_CLB_IDX_MAX = 19,
+static const struct at91_adc_temp_calib_layout sama7g5_temp_calib = {
+ .tag_idx = 1,
+ .p1_idx = 2,
+ .p4_idx = 5,
+ .p6_idx = 7,
+ .min_len = 19,
+ .p1_mul = 1000,
+ .p1_div = 1,
};
/* Temperature sensor calibration - Vtemp voltage sensitivity to temperature. */
@@ -745,6 +765,7 @@ static const struct at91_adc_platform sama7g5_platform = {
.chan_realbits = 16,
.temp_sensor = true,
.temp_chan = AT91_SAMA7G5_ADC_TEMP_CHANNEL,
+ .temp_calib_layout = &sama7g5_temp_calib,
};
static int at91_adc_chan_xlate(struct iio_dev *indio_dev, int chan)
@@ -2251,13 +2272,19 @@ static int at91_adc_temp_sensor_init(struct at91_adc_state *st,
{
struct at91_adc_temp_sensor_clb *clb = &st->soc_info.temp_sensor_clb;
struct nvmem_cell *temp_calib;
- u32 *buf;
+ const struct at91_adc_temp_calib_layout *layout;
+ void *cell_data;
+ u32 *buf __free(kfree) = NULL;
size_t len;
int ret = 0;
if (!st->soc_info.platform->temp_sensor)
return 0;
+ layout = st->soc_info.platform->temp_calib_layout;
+ if (!layout || !layout->p1_div)
+ return -EINVAL;
+
/* Get the calibration data from NVMEM. */
temp_calib = nvmem_cell_get(dev, "temperature_calib");
if (IS_ERR(temp_calib)) {
@@ -2267,31 +2294,35 @@ static int at91_adc_temp_sensor_init(struct at91_adc_state *st,
return ret;
}
- buf = nvmem_cell_read(temp_calib, &len);
+ cell_data = nvmem_cell_read(temp_calib, &len);
nvmem_cell_put(temp_calib);
- if (IS_ERR(buf)) {
+ if (IS_ERR(cell_data)) {
dev_err(dev, "Failed to read calibration data!\n");
- return PTR_ERR(buf);
+ return PTR_ERR(cell_data);
}
- if (len < AT91_ADC_TS_CLB_IDX_MAX * 4) {
+
+ buf = cell_data;
+
+ if (len < layout->min_len * sizeof(*buf) ||
+ buf[layout->tag_idx] != AT91_TEMP_CALIB_TAG_ACST) {
dev_err(dev, "Invalid calibration data!\n");
- ret = -EINVAL;
- goto free_buf;
+ return -EINVAL;
}
/* Store calibration data for later use. */
- clb->p1 = buf[AT91_ADC_TS_CLB_IDX_P1];
- clb->p4 = buf[AT91_ADC_TS_CLB_IDX_P4];
- clb->p6 = buf[AT91_ADC_TS_CLB_IDX_P6];
+ clb->p1 = buf[layout->p1_idx];
+ clb->p4 = buf[layout->p4_idx];
+ clb->p6 = buf[layout->p6_idx];
/*
- * We prepare here the conversion to milli to avoid doing it on hotpath.
+ * Here we prepare the conversion to milli to avoid doing it on hotpath.
+ * The p1 value is multiplied and divided with a scaling factor as per
+ * the SoC storage format described by per-platform calibration layout.
*/
- clb->p1 = clb->p1 * 1000;
+ clb->p1 *= layout->p1_mul;
+ clb->p1 /= layout->p1_div;
-free_buf:
- kfree(buf);
- return ret;
+ return 0;
}
static int at91_adc_probe(struct platform_device *pdev)
--
2.34.1
^ permalink raw reply related
* [PATCH v2 03/12] iio: adc: at91-sama5d2_adc: adapt the driver for sama7d65
From: Varshini Rajendran @ 2026-06-23 10:59 UTC (permalink / raw)
To: ehristev, jic23, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, srini,
linux-iio, devicetree, linux-arm-kernel, linux-kernel
Cc: varshini.rajendran
In-Reply-To: <20260623105944.128840-1-varshini.rajendran@microchip.com>
Add support for sama7d65 ADC. The differences are highlighted with the
compatible. The calibration data layout is the main difference.
Signed-off-by: Varshini Rajendran <varshini.rajendran@microchip.com>
---
drivers/iio/adc/at91-sama5d2_adc.c | 31 ++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index b569d175f4c3..237d339f342a 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -530,6 +530,16 @@ static const struct at91_adc_temp_calib_layout sama7g5_temp_calib = {
.p1_div = 1,
};
+static const struct at91_adc_temp_calib_layout sama7d65_temp_calib = {
+ .tag_idx = 1,
+ .p1_idx = 3,
+ .p4_idx = 2,
+ .p6_idx = 5,
+ .min_len = 11,
+ .p1_mul = 1,
+ .p1_div = 1000,
+};
+
/* Temperature sensor calibration - Vtemp voltage sensitivity to temperature. */
#define AT91_ADC_TS_VTEMP_DT (2080U)
@@ -768,6 +778,24 @@ static const struct at91_adc_platform sama7g5_platform = {
.temp_calib_layout = &sama7g5_temp_calib,
};
+static const struct at91_adc_platform sama7d65_platform = {
+ .layout = &sama7g5_layout,
+ .adc_channels = &at91_sama7g5_adc_channels,
+ .nr_channels = AT91_SAMA7G5_SINGLE_CHAN_CNT +
+ AT91_SAMA7G5_DIFF_CHAN_CNT +
+ AT91_SAMA7G5_TEMP_CHAN_CNT,
+ .max_channels = ARRAY_SIZE(at91_sama7g5_adc_channels),
+ .max_index = AT91_SAMA7G5_MAX_CHAN_IDX,
+ .hw_trig_cnt = AT91_SAMA7G5_HW_TRIG_CNT,
+ .osr_mask = GENMASK(18, 16),
+ .oversampling_avail = { 1, 4, 16, 64, 256, },
+ .oversampling_avail_no = 5,
+ .chan_realbits = 16,
+ .temp_sensor = true,
+ .temp_chan = AT91_SAMA7G5_ADC_TEMP_CHANNEL,
+ .temp_calib_layout = &sama7d65_temp_calib,
+};
+
static int at91_adc_chan_xlate(struct iio_dev *indio_dev, int chan)
{
int i;
@@ -2638,6 +2666,9 @@ static const struct of_device_id at91_adc_dt_match[] = {
}, {
.compatible = "microchip,sama7g5-adc",
.data = (const void *)&sama7g5_platform,
+ }, {
+ .compatible = "microchip,sama7d65-adc",
+ .data = (const void *)&sama7d65_platform,
}, {
/* sentinel */
}
--
2.34.1
^ permalink raw reply related
* [PATCH v2 04/12] dt-bindings: nvmem: microchip,sama7g5-otpc: add sama7d65 and dt node example
From: Varshini Rajendran @ 2026-06-23 10:59 UTC (permalink / raw)
To: ehristev, jic23, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, srini,
linux-iio, devicetree, linux-arm-kernel, linux-kernel
Cc: varshini.rajendran
In-Reply-To: <20260623105944.128840-1-varshini.rajendran@microchip.com>
Add support for sama7d65 and a dt node example that shows tag can be used
to reference a packet stored in the OTP memory.
Signed-off-by: Varshini Rajendran <varshini.rajendran@microchip.com>
---
.../nvmem/microchip,sama7g5-otpc.yaml | 28 +++++++++++++++++--
1 file changed, 25 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml b/Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml
index cc25f2927682..3cc16b0044a6 100644
--- a/Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml
+++ b/Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml
@@ -20,9 +20,15 @@ allOf:
properties:
compatible:
- items:
- - const: microchip,sama7g5-otpc
- - const: syscon
+ oneOf:
+ - items:
+ - const: microchip,sama7g5-otpc
+ - const: syscon
+ - items:
+ - enum:
+ - microchip,sama7d65-otpc
+ - const: microchip,sama7g5-otpc
+ - const: syscon
reg:
maxItems: 1
@@ -48,4 +54,20 @@ examples:
};
};
+ - |
+ otp_controller: efuse@e8c00000 {
+ compatible = "microchip,sama7d65-otpc", "microchip,sama7g5-otpc", "syscon";
+ reg = <0xe8c00000 0x100>;
+
+ nvmem-layout {
+ compatible = "fixed-layout";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ temp_calib: calib@41435354 {
+ reg = <0x41435354 0x2c>; /* Temp calib data packet TAG */
+ };
+ };
+ };
+
...
--
2.34.1
^ permalink raw reply related
* [PATCH v2 05/12] nvmem: microchip-otpc: add tag-based packet lookup
From: Varshini Rajendran @ 2026-06-23 10:59 UTC (permalink / raw)
To: ehristev, jic23, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, srini,
linux-iio, devicetree, linux-arm-kernel, linux-kernel
Cc: varshini.rajendran
In-Reply-To: <20260623105944.128840-1-varshini.rajendran@microchip.com>
Add support for accessing OTP packets by their 4-byte ASCII tag while
preserving backward compatibility with the existing ID-based lookup.
The OTP memory layout can vary across devices and may change over time,
making the packet ID approach unreliable when the memory map is not
known in advance. The packet tag provides a reliable way to identify
and access packets without prior knowledge of the OTP memory layout.
Two offset encoding are now supported:
1. Legacy ID-based: offset = OTP_PKT(id) = id * 4
Used in DT as: reg = <OTP_PKT(1) 76>;
2. TAG-based: offset = 4-byte ASCII packet tag
Used in DT as: reg = <0x41435354 0x4c>; (tag "ACST")
The driver resolves offsets matching valid legacy selectors (multiples
of 4 within the packet count) through ID lookup, falling back to tag
lookup for other values. This ensures existing device trees continue
to work while enabling new tag-based access.
During probe, packet meta data including the tag is read and cached.
The driver also validates OTP memory accessibility and emulation mode
status. When the boot packet is not configured, emulation mode allows
access to the other packets. When both are not available an
informational message is logged.
The stride of the nvmem memory is set to 1 in order to support tag based
offsets, comment in the header file is updated accordingly.
Signed-off-by: Varshini Rajendran <varshini.rajendran@microchip.com>
---
drivers/nvmem/microchip-otpc.c | 142 ++++++++++++++++--
.../nvmem/microchip,sama7g5-otpc.h | 4 +-
2 files changed, 135 insertions(+), 11 deletions(-)
diff --git a/drivers/nvmem/microchip-otpc.c b/drivers/nvmem/microchip-otpc.c
index df979e8549fd..cbb4822a97c0 100644
--- a/drivers/nvmem/microchip-otpc.c
+++ b/drivers/nvmem/microchip-otpc.c
@@ -18,16 +18,20 @@
#define MCHP_OTPC_CR_READ BIT(6)
#define MCHP_OTPC_MR (0x4)
#define MCHP_OTPC_MR_ADDR GENMASK(31, 16)
+#define MCHP_OTPC_MR_EMUL BIT(7)
#define MCHP_OTPC_AR (0x8)
#define MCHP_OTPC_SR (0xc)
#define MCHP_OTPC_SR_READ BIT(6)
#define MCHP_OTPC_HR (0x20)
#define MCHP_OTPC_HR_SIZE GENMASK(15, 8)
+#define MCHP_OTPC_HR_PACKET_TYPE GENMASK(2, 0)
#define MCHP_OTPC_DR (0x24)
#define MCHP_OTPC_NAME "mchp-otpc"
#define MCHP_OTPC_SIZE (11 * 1024)
+#define PACKET_TYPE_REGULAR 1
+
/**
* struct mchp_otpc - OTPC private data structure
* @base: base address
@@ -47,11 +51,15 @@ struct mchp_otpc {
* @list: list head
* @id: packet ID
* @offset: packet offset (in words) in OTP memory
+ * @type: type of the packet
+ * @tag: 4-byte ASCII tag of the packet
*/
struct mchp_otpc_packet {
struct list_head list;
u32 id;
u32 offset;
+ u32 type;
+ u32 tag;
};
static struct mchp_otpc_packet *mchp_otpc_id_to_packet(struct mchp_otpc *otpc,
@@ -70,6 +78,55 @@ static struct mchp_otpc_packet *mchp_otpc_id_to_packet(struct mchp_otpc *otpc,
return NULL;
}
+/**
+ * mchp_otpc_tag_to_packet() - find packet by tag
+ * @otpc: OTPC private data
+ * @tag: 4-byte ASCII tag to search for
+ *
+ * Return: pointer to packet if found, NULL otherwise
+ */
+static struct mchp_otpc_packet *mchp_otpc_tag_to_packet(struct mchp_otpc *otpc,
+ u32 tag)
+{
+ struct mchp_otpc_packet *packet;
+
+ list_for_each_entry(packet, &otpc->packets, list) {
+ if (packet->tag == tag)
+ return packet;
+ }
+
+ return NULL;
+}
+
+/**
+ * mchp_otpc_resolve_packet() - resolve offset to packet
+ * @otpc: OTPC private data
+ * @off: NVMEM offset (legacy ID-based or TAG-based)
+ *
+ * Legacy offsets (multiples of 4 within valid ID range) are resolved
+ * through ID lookup. Other offsets are treated as 4-byte ASCII tags.
+ *
+ * Return: pointer to packet if found, NULL otherwise
+ */
+static struct mchp_otpc_packet *mchp_otpc_resolve_packet(struct mchp_otpc *otpc,
+ u32 off)
+{
+ /*
+ * Legacy id based packet access: offset = id * 4
+ * Inside the driver we use continuous unsigned integer numbers
+ * for packet id, thus divide off by 4 before passing it to
+ * mchp_otpc_id_to_packet().
+ */
+
+ if (!(off % 4) && (off / 4) < otpc->npackets)
+ return mchp_otpc_id_to_packet(otpc, off / 4);
+
+ /*
+ * TAG-based packet access: offset is a 4-byte ASCII tag
+ */
+ return mchp_otpc_tag_to_packet(otpc, off);
+}
+
static int mchp_otpc_prepare_read(struct mchp_otpc *otpc,
unsigned int offset)
{
@@ -140,8 +197,29 @@ static int mchp_otpc_prepare_read(struct mchp_otpc *otpc,
* offset returned by hardware.
*
* For this, the read function will return the first requested bytes in the
- * packet. The user will have to be aware of the memory footprint before doing
- * the read request.
+ * packet.
+ *
+ * Two offset encoding are supported:
+ *
+ * 1. Legacy ID-based: offset = OTP_PKT(id) = id * 4
+ * Used in DT as: reg = <OTP_PKT(1) 76>;
+ * 2. TAG-based: offset = 4-byte ASCII packet tag
+ * Used in DT as: reg = <0x41435354 0x4c>; (tag "ACST")
+ *
+ * To use the legacy ID based packet lookup the user will have to be aware of
+ * the memory footprint before doing the read request.
+ *
+ * But by using the TAG based packet lookup, the user won't have to be aware
+ * of the memory footprint before doing the read request since this driver has
+ * it abstracted and taken care of.
+ *
+ * Practically, there is no way of knowing the mapping of the OTP memory table
+ * in advance for every device. But by using the packet tag - the identifier
+ * ASCII value, the packets can be recognized without being aware of the
+ * flashed OTP memory map table and the payload can be acquired reliably.
+ *
+ * While the legacy ID based lookup is still supported, TAG based approach is
+ * recommended.
*/
static int mchp_otpc_read(void *priv, unsigned int off, void *val,
size_t bytes)
@@ -154,12 +232,11 @@ static int mchp_otpc_read(void *priv, unsigned int off, void *val,
int ret, payload_size;
/*
- * We reach this point with off being multiple of stride = 4 to
- * be able to cross the subsystem. Inside the driver we use continuous
- * unsigned integer numbers for packet id, thus divide off by 4
- * before passing it to mchp_otpc_id_to_packet().
+ * From this point the offset has to be translated into the actual
+ * packet. For this we traverse the table of contents stored in a list
+ * "packet" based on the access type - packet id or tag.
*/
- packet = mchp_otpc_id_to_packet(otpc, off / 4);
+ packet = mchp_otpc_resolve_packet(otpc, off);
if (!packet)
return -EINVAL;
offset = packet->offset;
@@ -190,6 +267,29 @@ static int mchp_otpc_read(void *priv, unsigned int off, void *val,
return 0;
}
+/**
+ * mchp_otpc_read_packet_tag() - read tag from packet payload
+ * @otpc: OTPC private data
+ * @offset: packet offset in OTP memory
+ * @val: pointer to store the tag value
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+static int mchp_otpc_read_packet_tag(struct mchp_otpc *otpc, unsigned int offset,
+ unsigned int *val)
+{
+ int ret;
+
+ ret = mchp_otpc_prepare_read(otpc, offset);
+ if (ret)
+ return ret;
+
+ writel_relaxed(0, otpc->base + MCHP_OTPC_AR);
+ *val = readl_relaxed(otpc->base + MCHP_OTPC_DR);
+
+ return 0;
+}
+
static int mchp_otpc_init_packets_list(struct mchp_otpc *otpc, u32 *size)
{
struct mchp_otpc_packet *packet;
@@ -215,6 +315,17 @@ static int mchp_otpc_init_packets_list(struct mchp_otpc *otpc, u32 *size)
packet->id = id++;
packet->offset = word_pos;
+ packet->type = FIELD_GET(MCHP_OTPC_HR_PACKET_TYPE, word);
+
+ if (packet->type == PACKET_TYPE_REGULAR) {
+ ret = mchp_otpc_read_packet_tag(otpc, packet->offset,
+ &packet->tag);
+ if (ret)
+ return ret;
+ } else {
+ packet->tag = 0;
+ }
+
INIT_LIST_HEAD(&packet->list);
list_add_tail(&packet->list, &otpc->packets);
@@ -236,7 +347,7 @@ static struct nvmem_config mchp_nvmem_config = {
.type = NVMEM_TYPE_OTP,
.read_only = true,
.word_size = 4,
- .stride = 4,
+ .stride = 1,
.reg_read = mchp_otpc_read,
};
@@ -244,8 +355,9 @@ static int mchp_otpc_probe(struct platform_device *pdev)
{
struct nvmem_device *nvmem;
struct mchp_otpc *otpc;
- u32 size;
+ u32 size, tmp;
int ret;
+ bool emul_enable;
otpc = devm_kzalloc(&pdev->dev, sizeof(*otpc), GFP_KERNEL);
if (!otpc)
@@ -256,10 +368,22 @@ static int mchp_otpc_probe(struct platform_device *pdev)
return PTR_ERR(otpc->base);
otpc->dev = &pdev->dev;
+
+ tmp = readl_relaxed(otpc->base + MCHP_OTPC_MR);
+ emul_enable = tmp & MCHP_OTPC_MR_EMUL;
+ if (emul_enable)
+ dev_info(otpc->dev, "Emulation mode enabled\n");
+
ret = mchp_otpc_init_packets_list(otpc, &size);
if (ret)
return ret;
+ if (!size) {
+ dev_warn(otpc->dev, "Cannot access OTP memory\n");
+ if (!emul_enable)
+ dev_info(otpc->dev, "Boot packet not programmed and emulation mode disabled\n");
+ }
+
mchp_nvmem_config.dev = otpc->dev;
mchp_nvmem_config.add_legacy_fixed_of_cells = true;
mchp_nvmem_config.size = size;
diff --git a/include/dt-bindings/nvmem/microchip,sama7g5-otpc.h b/include/dt-bindings/nvmem/microchip,sama7g5-otpc.h
index f570b23165a2..5f72e75ad091 100644
--- a/include/dt-bindings/nvmem/microchip,sama7g5-otpc.h
+++ b/include/dt-bindings/nvmem/microchip,sama7g5-otpc.h
@@ -4,8 +4,8 @@
#define _DT_BINDINGS_NVMEM_MICROCHIP_OTPC_H
/*
- * Need to have it as a multiple of 4 as NVMEM memory is registered with
- * stride = 4.
+ * Need to have it as a multiple of 4 for the legacy id based packet
+ * access.
*/
#define OTP_PKT(id) ((id) * 4)
--
2.34.1
^ permalink raw reply related
* [PATCH v2 06/12] ARM: dts: microchip: sama7d65: add cpu opps
From: Varshini Rajendran @ 2026-06-23 10:59 UTC (permalink / raw)
To: ehristev, jic23, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, srini,
linux-iio, devicetree, linux-arm-kernel, linux-kernel
Cc: varshini.rajendran
In-Reply-To: <20260623105944.128840-1-varshini.rajendran@microchip.com>
Add CPU OPPs table for SAMA7D65.
Signed-off-by: Varshini Rajendran <varshini.rajendran@microchip.com>
---
arch/arm/boot/dts/microchip/sama7d65.dtsi | 36 +++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/arch/arm/boot/dts/microchip/sama7d65.dtsi b/arch/arm/boot/dts/microchip/sama7d65.dtsi
index 67253bbc08df..94d49e20dc79 100644
--- a/arch/arm/boot/dts/microchip/sama7d65.dtsi
+++ b/arch/arm/boot/dts/microchip/sama7d65.dtsi
@@ -35,6 +35,7 @@ cpu0: cpu@0 {
d-cache-size = <0x8000>; // L1, 32 KB
i-cache-size = <0x8000>; // L1, 32 KB
next-level-cache = <&L2>;
+ operating-points-v2 = <&cpu_opp_table>;
L2: l2-cache {
compatible = "cache";
@@ -45,6 +46,41 @@ L2: l2-cache {
};
};
+ cpu_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-90000000 {
+ opp-hz = /bits/ 64 <90000000>;
+ opp-microvolt = <1050000 1050000 1225000>;
+ clock-latency-ns = <320000>;
+ };
+
+ opp-250000000 {
+ opp-hz = /bits/ 64 <250000000>;
+ opp-microvolt = <1050000 1050000 1225000>;
+ clock-latency-ns = <320000>;
+ };
+
+ opp-600000000 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-microvolt = <1050000 1050000 1225000>;
+ clock-latency-ns = <320000>;
+ opp-suspend;
+ };
+
+ opp-800000000 {
+ opp-hz = /bits/ 64 <800000000>;
+ opp-microvolt = <1150000 1125000 1225000>;
+ clock-latency-ns = <320000>;
+ };
+
+ opp-1000000002 {
+ opp-hz = /bits/ 64 <1000000002>;
+ opp-microvolt = <1250000 1225000 1300000>;
+ clock-latency-ns = <320000>;
+ };
+ };
+
clocks {
main_xtal: clock-mainxtal {
compatible = "fixed-clock";
--
2.34.1
^ permalink raw reply related
* [PATCH v2 07/12] ARM: dts: microchip: sama7d65: Add ADC node
From: Varshini Rajendran @ 2026-06-23 10:59 UTC (permalink / raw)
To: ehristev, jic23, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, srini,
linux-iio, devicetree, linux-arm-kernel, linux-kernel
Cc: varshini.rajendran
In-Reply-To: <20260623105944.128840-1-varshini.rajendran@microchip.com>
Add node for the ADC controller in sama7d65 SoC.
Signed-off-by: Varshini Rajendran <varshini.rajendran@microchip.com>
---
arch/arm/boot/dts/microchip/sama7d65.dtsi | 29 +++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/arch/arm/boot/dts/microchip/sama7d65.dtsi b/arch/arm/boot/dts/microchip/sama7d65.dtsi
index 94d49e20dc79..ba775459a816 100644
--- a/arch/arm/boot/dts/microchip/sama7d65.dtsi
+++ b/arch/arm/boot/dts/microchip/sama7d65.dtsi
@@ -11,6 +11,7 @@
#include <dt-bindings/clock/at91.h>
#include <dt-bindings/dma/at91.h>
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/iio/adc/at91-sama5d2_adc.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/mfd/at91-usart.h>
@@ -95,6 +96,16 @@ slow_xtal: clock-slowxtal {
};
};
+ vddout25: fixed-regulator-vddout25 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "VDDOUT25";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-boot-on;
+ status = "disabled";
+ };
+
ns_sram: sram@100000 {
compatible = "mmio-sram";
reg = <0x100000 0x20000>;
@@ -296,6 +307,24 @@ can4: can@e0838000 {
status = "disabled";
};
+ adc: adc@e1000000 {
+ compatible = "microchip,sama7d65-adc";
+ reg = <0xe1000000 0x200>;
+ interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&pmc PMC_TYPE_GCK 25>;
+ assigned-clocks = <&pmc PMC_TYPE_GCK 25>;
+ assigned-clock-rates = <100000000>;
+ clock-names = "adc_clk";
+ dmas = <&dma0 AT91_XDMAC_DT_PERID(0)>;
+ dma-names = "rx";
+ atmel,min-sample-rate-hz = <200000>;
+ atmel,max-sample-rate-hz = <20000000>;
+ atmel,trigger-edge-type = <IRQ_TYPE_EDGE_RISING>;
+ atmel,startup-time-ms = <4>;
+ #io-channel-cells = <1>;
+ status = "disabled";
+ };
+
dma2: dma-controller@e1200000 {
compatible = "microchip,sama7d65-dma", "microchip,sama7g5-dma";
reg = <0xe1200000 0x1000>;
--
2.34.1
^ permalink raw reply related
* [PATCH v2 08/12] ARM: dts: microchip: sama7d65_curiosity: Enable ADC, DVFS
From: Varshini Rajendran @ 2026-06-23 10:59 UTC (permalink / raw)
To: ehristev, jic23, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, srini,
linux-iio, devicetree, linux-arm-kernel, linux-kernel
Cc: varshini.rajendran
In-Reply-To: <20260623105944.128840-1-varshini.rajendran@microchip.com>
Add regulator, pinmux and enable ADC for sama7d65 curiosity. Add
cpu-supply regulator for DVFS.
Signed-off-by: Varshini Rajendran <varshini.rajendran@microchip.com>
---
.../dts/microchip/at91-sama7d65_curiosity.dts | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/arch/arm/boot/dts/microchip/at91-sama7d65_curiosity.dts b/arch/arm/boot/dts/microchip/at91-sama7d65_curiosity.dts
index 927c27260b6c..a6a44a176f56 100644
--- a/arch/arm/boot/dts/microchip/at91-sama7d65_curiosity.dts
+++ b/arch/arm/boot/dts/microchip/at91-sama7d65_curiosity.dts
@@ -97,6 +97,18 @@ &can3 {
status = "okay";
};
+&adc {
+ vddana-supply = <&vddout25>;
+ vref-supply = <&vddout25>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_adc_default &pinctrl_adtrg_default>;
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <&vddcpu>;
+};
+
&dma0 {
status = "okay";
};
@@ -334,6 +346,16 @@ &main_xtal {
};
&pioa {
+ pinctrl_adc_default: adc-default {
+ pinmux = <PIN_PC5__GPIO>;
+ bias-disable;
+ };
+
+ pinctrl_adtrg_default: adtrg-default {
+ pinmux = <PIN_PB7__ADTRG>;
+ bias-pull-up;
+ };
+
pinctrl_can1_default: can1-default {
pinmux = <PIN_PD10__CANTX1>,
<PIN_PD11__CANRX1>;
@@ -457,3 +479,8 @@ input@0 {
&slow_xtal {
clock-frequency = <32768>;
};
+
+&vddout25 {
+ vin-supply = <&vdd_3v3>;
+ status = "okay";
+};
--
2.34.1
^ permalink raw reply related
* [PATCH v2 09/12] ARM: dts: microchip: sama7d65: add otpc node
From: Varshini Rajendran @ 2026-06-23 10:59 UTC (permalink / raw)
To: ehristev, jic23, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, srini,
linux-iio, devicetree, linux-arm-kernel, linux-kernel
Cc: varshini.rajendran
In-Reply-To: <20260623105944.128840-1-varshini.rajendran@microchip.com>
Add OTPC node along with temperature calibration cell.
Signed-off-by: Varshini Rajendran <varshini.rajendran@microchip.com>
---
arch/arm/boot/dts/microchip/sama7d65.dtsi | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/arch/arm/boot/dts/microchip/sama7d65.dtsi b/arch/arm/boot/dts/microchip/sama7d65.dtsi
index ba775459a816..5867fda378b1 100644
--- a/arch/arm/boot/dts/microchip/sama7d65.dtsi
+++ b/arch/arm/boot/dts/microchip/sama7d65.dtsi
@@ -15,6 +15,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/mfd/at91-usart.h>
+#include <dt-bindings/nvmem/microchip,sama7g5-otpc.h>
/ {
model = "Microchip SAMA7D65 family SoC";
@@ -1112,6 +1113,21 @@ ddr3phy: ddr3phy@e3804000 {
reg = <0xe3804000 0x1000>;
};
+ otpc: efuse@e8c00000 {
+ compatible = "microchip,sama7d65-otpc", "microchip,sama7g5-otpc", "syscon";
+ reg = <0xe8c00000 0x100>;
+
+ nvmem-layout {
+ compatible = "fixed-layout";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ temperature_calib: calib@41435354 {
+ reg = <0x41435354 0x2c>; /* Temp calib data packet TAG */
+ };
+ };
+ };
+
gic: interrupt-controller@e8c11000 {
compatible = "arm,cortex-a7-gic";
reg = <0xe8c11000 0x1000>,
--
2.34.1
^ permalink raw reply related
* [PATCH v2 10/12] ARM: dts: microchip: sama7d65: add cells for temperature calibration
From: Varshini Rajendran @ 2026-06-23 10:59 UTC (permalink / raw)
To: ehristev, jic23, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, srini,
linux-iio, devicetree, linux-arm-kernel, linux-kernel
Cc: varshini.rajendran
In-Reply-To: <20260623105944.128840-1-varshini.rajendran@microchip.com>
Add NVMEM cell to ADC for temperature calibration data.
Signed-off-by: Varshini Rajendran <varshini.rajendran@microchip.com>
---
arch/arm/boot/dts/microchip/sama7d65.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/boot/dts/microchip/sama7d65.dtsi b/arch/arm/boot/dts/microchip/sama7d65.dtsi
index 5867fda378b1..c336f863406d 100644
--- a/arch/arm/boot/dts/microchip/sama7d65.dtsi
+++ b/arch/arm/boot/dts/microchip/sama7d65.dtsi
@@ -323,6 +323,8 @@ adc: adc@e1000000 {
atmel,trigger-edge-type = <IRQ_TYPE_EDGE_RISING>;
atmel,startup-time-ms = <4>;
#io-channel-cells = <1>;
+ nvmem-cells = <&temperature_calib>;
+ nvmem-cell-names = "temperature_calib";
status = "disabled";
};
--
2.34.1
^ permalink raw reply related
* [PATCH v2 11/12] ARM: dts: microchip: sama7d65: add temperature sensor
From: Varshini Rajendran @ 2026-06-23 10:59 UTC (permalink / raw)
To: ehristev, jic23, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
nicolas.ferre, alexandre.belloni, claudiu.beznea, srini,
linux-iio, devicetree, linux-arm-kernel, linux-kernel
Cc: varshini.rajendran
In-Reply-To: <20260623105944.128840-1-varshini.rajendran@microchip.com>
Add temperature sensor node.
Signed-off-by: Varshini Rajendran <varshini.rajendran@microchip.com>
---
arch/arm/boot/dts/microchip/sama7d65.dtsi | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm/boot/dts/microchip/sama7d65.dtsi b/arch/arm/boot/dts/microchip/sama7d65.dtsi
index c336f863406d..89904397d021 100644
--- a/arch/arm/boot/dts/microchip/sama7d65.dtsi
+++ b/arch/arm/boot/dts/microchip/sama7d65.dtsi
@@ -120,6 +120,13 @@ pmu {
interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
};
+ thermal_sensor: thermal-sensor {
+ compatible = "generic-adc-thermal";
+ #thermal-sensor-cells = <0>;
+ io-channels = <&adc AT91_SAMA7G5_ADC_TEMP_CHANNEL>;
+ io-channel-names = "sensor-channel";
+ };
+
soc {
compatible = "simple-bus";
ranges;
--
2.34.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox