* Re: [PATCH v3 06/11] iommu: Defer __iommu_group_free_device() to be outside group->mutex
From: Baolu Lu @ 2026-04-23 7:55 UTC (permalink / raw)
To: Nicolin Chen, Will Deacon, Robin Murphy, Joerg Roedel,
Bjorn Helgaas, Jason Gunthorpe
Cc: Rafael J . Wysocki, Len Brown, Pranjal Shrivastava, Mostafa Saleh,
Kevin Tian, linux-arm-kernel, iommu, linux-kernel, linux-acpi,
linux-pci, vsethi, Shuai Xue
In-Reply-To: <3f5d229267d1f4d918641bc5b896f54b5c4b7782.1776381841.git.nicolinc@nvidia.com>
On 4/17/26 07:28, Nicolin Chen wrote:
> __iommu_group_remove_device() holds group->mutex across the entire call to
> __iommu_group_free_device() that performs sysfs removals, tracing, and the
> final kfree_rcu(). But in fact, most of these operations don't really need
> the group->mutex.
>
> The group_device structure will support a work_struct to quarantine broken
> devices asynchronously. The work function must hold group->mutex to safely
> update group state. cancel_work_sync() must be called, to cancel that work
> before freeing the device. But doing so under group->mutex would deadlock
> if the worker is already running and waiting to acquire the same lock.
>
> Separate the assertion from __iommu_group_free_device() to another helper
> __iommu_group_empty_assert_owner_cnt().
>
> Defer the __iommu_group_free_device() until the mutex is released.
>
> This is a preparatory refactor with no functional change.
>
> Signed-off-by: Nicolin Chen<nicolinc@nvidia.com>
> ---
> drivers/iommu/iommu.c | 35 +++++++++++++++++++++++------------
> 1 file changed, 23 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index d1be62a07904a..810e7b94a1ae2 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -627,6 +627,19 @@ static struct iommu_domain *pasid_array_entry_to_domain(void *entry)
>
> DEFINE_MUTEX(iommu_probe_device_lock);
>
> +static void __iommu_group_empty_assert_owner_cnt(struct iommu_group *group)
> +{
> + lockdep_assert_held(&group->mutex);
> + /*
> + * If the group has become empty then ownership must have been
> + * released, and the current domain must be set back to NULL or
> + * the default domain.
> + */
Nit: this comment doesn't quite match the following code. The code
doesn't check "group->domain != NULL". Or perhaps in that case,
group->default_domain must be NULL?
Furthermore, if a device is currently quarantined, group->domain will be
the blocking_domain. If that quarantined device is then hot-removed and
happens to be the last device in the group, will this WARN_ON trigger
unnecessarily?
> + if (list_empty(&group->devices))
> + WARN_ON(group->owner_cnt ||
> + group->domain != group->default_domain);
> +}
> +
> static int __iommu_probe_device(struct device *dev, struct list_head *group_list)
> {
> struct iommu_group *group;
Thanks,
baolu
^ permalink raw reply
* Re: [PATCH v2 0/2] gpio: drop bitmap_complement() where feasible
From: Bartosz Golaszewski @ 2026-04-23 7:58 UTC (permalink / raw)
To: Linus Walleij, Andy Shevchenko, Bartosz Golaszewski,
Shubhrajyoti Datta, Srinivas Neeli, Michal Simek, Yury Norov,
linux-gpio, linux-kernel, linux-arm-kernel, Yury Norov
Cc: Bartosz Golaszewski
In-Reply-To: <20260417175955.375275-1-ynorov@nvidia.com>
On Fri, 17 Apr 2026 13:59:52 -0400, Yury Norov wrote:
> The gpio drivers reproduce the following pattern:
>
> bitmap_complement(tmp, data1, nbits);
> bitmap_and(dst, data2, tmp, nbits);
>
> This can be done in a single pass:
>
> [...]
Tweaked the grammar in commit messages and applied, thanks!
[1/2] gpio: pca953x: drop bitmap_complement() where feasible
https://git.kernel.org/brgl/c/a56604e397575647bfc425a8df176948577a364e
[2/2] gpio: xilinx: drop bitmap_complement() where feasible
https://git.kernel.org/brgl/c/2757a5b1bca76a1b6378496b669a2baf1faddec5
Best regards,
--
Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH] arm64: traps: Add a macro to simplify the condition codes check
From: Marc Zyngier @ 2026-04-23 8:04 UTC (permalink / raw)
To: Anshuman Khandual
Cc: mark.rutland, smostafa, kees, catalin.marinas, Jinjie Ruan,
linux-kernel, mrigendra.chaubey, leitao, will, linux-arm-kernel
In-Reply-To: <ae6f2b57-4644-424e-aab7-84042dca23e6@arm.com>
On Thu, 23 Apr 2026 06:29:09 +0100,
Anshuman Khandual <anshuman.khandual@arm.com> wrote:
>
>
>
> On 20/03/26 1:58 PM, Jinjie Ruan wrote:
> > Add DEFINE_COND_CHECK macro to define the simple __check_* functions
> > to simplify the condition codes check.
> >
> > No functional changes.
> >
> > Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
> > ---
> > arch/arm64/kernel/traps.c | 59 ++++++++++-----------------------------
> > 1 file changed, 15 insertions(+), 44 deletions(-)
> >
> > diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
> > index 914282016069..6216fe9e8e42 100644
> > --- a/arch/arm64/kernel/traps.c
> > +++ b/arch/arm64/kernel/traps.c
> > @@ -49,45 +49,21 @@
> > #include <asm/system_misc.h>
> > #include <asm/sysreg.h>
> >
> > -static bool __kprobes __check_eq(unsigned long pstate)
> > -{
> > - return (pstate & PSR_Z_BIT) != 0;
> > -}
> > -
> > -static bool __kprobes __check_ne(unsigned long pstate)
> > -{
> > - return (pstate & PSR_Z_BIT) == 0;
> > -}
> > -
> > -static bool __kprobes __check_cs(unsigned long pstate)
> > -{
> > - return (pstate & PSR_C_BIT) != 0;
> > -}
> > -
> > -static bool __kprobes __check_cc(unsigned long pstate)
> > -{
> > - return (pstate & PSR_C_BIT) == 0;
> > -}
> > -
> > -static bool __kprobes __check_mi(unsigned long pstate)
> > -{
> > - return (pstate & PSR_N_BIT) != 0;
> > -}
> > -
> > -static bool __kprobes __check_pl(unsigned long pstate)
> > -{
> > - return (pstate & PSR_N_BIT) == 0;
> > -}
> > -
> > -static bool __kprobes __check_vs(unsigned long pstate)
> > -{
> > - return (pstate & PSR_V_BIT) != 0;
> > -}
> > -
> > -static bool __kprobes __check_vc(unsigned long pstate)
> > -{
> > - return (pstate & PSR_V_BIT) == 0;
> > -}
> > +#define DEFINE_COND_CHECK(name, flag, expected) \
> > +static bool __kprobes __check_##name(unsigned long pstate) \
> > +{ \
> > + return ((pstate & (flag)) != 0) == (expected); \
> > +}
> > +
> > +DEFINE_COND_CHECK(eq, PSR_Z_BIT, true)
> > +DEFINE_COND_CHECK(ne, PSR_Z_BIT, false)
> > +DEFINE_COND_CHECK(cs, PSR_C_BIT, true)
> > +DEFINE_COND_CHECK(cc, PSR_C_BIT, false)
> > +DEFINE_COND_CHECK(mi, PSR_N_BIT, true)
> > +DEFINE_COND_CHECK(pl, PSR_N_BIT, false)
> > +DEFINE_COND_CHECK(vs, PSR_V_BIT, true)
> > +DEFINE_COND_CHECK(vc, PSR_V_BIT, false)
> > +DEFINE_COND_CHECK(al, 0, false) /* Always true */
>
> (((pstate & 0 == 0) != 0) == false) ---> return true
>
> Although this looks OK but wondering if __check_al() should
> be left unchanged for simplicity. OR could all its call sites
> be changed assuming an unconditional 'true' return thus later
> __check_al() can be dropped.
Which call site? We emulate an instruction, and we're not in control
of the condition code associated with it. The condition code directly
indexes into aarch32_opcode_cond_checks[].
Anyway, this is a moot point, as we have consensus to not touch that
code at all.
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply
* Re: [PATCH] KVM: arm64: Validate the FF-A memory access descriptor placement
From: Marc Zyngier @ 2026-04-23 8:08 UTC (permalink / raw)
To: Sebastian Ene
Cc: oupton, will, ayrton, catalin.marinas, joey.gouly, korneld,
kvmarm, linux-arm-kernel, linux-kernel, android-kvm,
mrigendra.chaubey, perlarsen, suzuki.poulose, yuzenghui, stable
In-Reply-To: <aejOu98q1lEZoFfW@google.com>
On Wed, 22 Apr 2026 14:35:55 +0100,
Sebastian Ene <sebastianene@google.com> wrote:
>
> On Wed, Apr 22, 2026 at 01:24:02PM +0100, Marc Zyngier wrote:
> > On Wed, 22 Apr 2026 11:25:40 +0100,
> > Sebastian Ene <sebastianene@google.com> wrote:
> > >
> > > Prevent the pKVM hypervisor from making assumptions that the
> > > endpoint memory access descriptor (EMAD) comes right after the
> > > FF-A memory region header and enforce a strict placement for it
> > > when validating an FF-A memory lend/share transaction.
>
> Hello Marc,
>
> >
> > As I read this, you want to remove a bad assumption...
> >
> > >
> > > Prior to FF-A version 1.1 the header of the memory region
> > > didn't contain an offset to the endpoint memory access descriptor.
> > > The layout of a memory transaction looks like this:
> > >
> > > Field name | Offset
> > > -- 0
> > > [ Header (ffa_mem_region) |__ ep_mem_offset
> > > EMAD 1 (ffa_mem_region_attributes) |
> > > ]
> > >
> > > Reject the host from specifying a memory access descriptor offset
> > > that is different than the size of the memory region header.
> >
> > And yet you decide that you want to enforce this assumption. I don't
> > understand how you arrive to this conclusion.
> >
> > Looking at the spec, it appears that the offset is *designed* to allow
> > a gap between the header and the EMAD. Refusing to handle a it seems to be a
> > violation of the spec.
> >
> > What am I missing?
>
> While the spec allows the gap to be variable (since version 1.1), the
> arm ff-a driver places it at a fixed position in:
> ffa_mem_region_additional_setup()
> https://elixir.bootlin.com/linux/v7.0/source/drivers/firmware/arm_ffa/driver.c#L671
That's an implementation detail, and you shouldn't rely on this.
> and makes use of the same assumption in: ffa_mem_desc_offset().
> https://elixir.bootlin.com/linux/v7.0/source/include/linux/arm_ffa.h#L448
> The later one seems wrong IMO. because we should compute the offset
> based on the value stored in ep_mem_offset and not adding it up with
> sizeof(struct ffa_mem_region).
>
> Maybe this should be the fix instead and not the one in pKVM ? What do
> you think ?
I think you should parse the buffers as the spec intends them, without
assumptions or limitations.
>
> The current implementation in pKVM makes use of the
> ffa_mem_desc_offset() to validate the first EMAD. If a compromised host
> places an EMAD at a different offset than sizeof(struct ffa_mem_region),
> then pKVM will not validate that EMAD.
Why compromised? Isn't that a perfectly valid thing to do? What I
understand is that the FFA 1.1 implementation in pKVM doesn't match
the expectations of the spec. If that's indeed the case, pKVM should
be fixed to accept these messages correctly, or stop using FFA 1.1.
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply
* Re: [PATCH] crypto: ixp4xx: Fix null-pointer dereference in chainup_buffers()
From: Herbert Xu @ 2026-04-23 8:11 UTC (permalink / raw)
To: Ruoyu Wang
Cc: clabbe, linusw, kaloz, davem, linux-crypto, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260421093917.1001688-1-ruoyuw560@gmail.com>
On Tue, Apr 21, 2026 at 05:39:17PM +0800, Ruoyu Wang wrote:
> chainup_buffers() builds a linked list of buffer descriptors for a
> scatterlist. If dma_pool_alloc() fails while constructing the list, the
> current code sets buf to NULL and later dereferences it unconditionally
> at the end of the function:
>
> buf->next = NULL;
> buf->phys_next = 0;
>
> This can lead to a null-pointer dereference on allocation failure.
>
> If the failure happens after part of the descriptor chain has already
> been allocated and DMA-mapped, the partially constructed chain also
> needs to be released.
>
> Fix this by unwinding the partially constructed chain, resetting the
> caller-provided hook descriptor, and returning NULL on allocation
> failure.
>
> Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
> ---
> drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c | 24 +++++++++++++++++----
> 1 file changed, 20 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c b/drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c
> index fcc0cf4df637..63ef28cd5766 100644
> --- a/drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c
> +++ b/drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c
> @@ -874,6 +874,11 @@ static struct buffer_desc *chainup_buffers(struct device *dev,
> struct buffer_desc *buf, gfp_t flags,
> enum dma_data_direction dir)
> {
> + struct buffer_desc *first = buf;
> +
> + first->next = NULL;
> + first->phys_next = 0;
> +
> for (; nbytes > 0; sg = sg_next(sg)) {
> unsigned int len = min(nbytes, sg->length);
> struct buffer_desc *next_buf;
> @@ -883,10 +888,15 @@ static struct buffer_desc *chainup_buffers(struct device *dev,
> nbytes -= len;
> ptr = sg_virt(sg);
> next_buf = dma_pool_alloc(buffer_pool, flags, &next_buf_phys);
> - if (!next_buf) {
> - buf = NULL;
> - break;
> - }
> + if (!next_buf)
> + goto err_unwind;
> +
> + /*
> + * Keep the chain well-formed even on partial construction,
> + * so free_buf_chain() can safely unwind it on failure.
> + */
> + next_buf->next = NULL;
> + next_buf->phys_next = 0;
> sg_dma_address(sg) = dma_map_single(dev, ptr, len, dir);
> buf->next = next_buf;
> buf->phys_next = next_buf_phys;
> @@ -899,6 +909,12 @@ static struct buffer_desc *chainup_buffers(struct device *dev,
> buf->next = NULL;
> buf->phys_next = 0;
> return buf;
> +
> +err_unwind:
> + free_buf_chain(dev, first->next, first->phys_next);
> + first->next = NULL;
> + first->phys_next = 0;
> + return NULL;
All callers of chainup_buffers try to unwind by calling free_buf_chain
too, although a couple of them might do so incorrectly.
It looks like the callers need the unwind path anyway, so perhaps
just fix up the callers so that their unwind paths actually work?
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH net] net: airoha: fix BQL imbalance in TX path
From: Lorenzo Bianconi @ 2026-04-23 8:12 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Hariprasad Kelam
Cc: Simon Horman, linux-arm-kernel, linux-mediatek, netdev
In-Reply-To: <20260421-airoha-fix-bql-v1-1-f135afe4275b@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 4017 bytes --]
> Fix a possible BQL imbalance in airoha_dev_xmit(), where inflight
> packets are accounted only for the AIROHA_NUM_TX_RING netdev TX
> queues. The queue index is computed as:
>
> qid = skb_get_queue_mapping(skb) % ARRAY_SIZE(qdma->q_tx)
> txq = netdev_get_tx_queue(dev, qid);
>
> However, airoha_qdma_tx_napi_poll() accounts completions across all
> netdev TX queues (num_tx_queues), leading to inconsistent BQL
> accounting.
>
> Also reset all netdev TX queues in the ndo_stop callback.
>
> Fixes: 1d304174106c ("net: airoha: Implement BQL support")
> Fixes: c9f947769b77 ("net: airoha: Reset BQL stopping the netdevice")
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
> ---
> drivers/net/ethernet/airoha/airoha_eth.c | 7 +++----
> 1 file changed, 3 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> index 19f67c7dd8e1..6c7390f0de5d 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.c
> +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> @@ -929,10 +929,9 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
> q->queued--;
>
> if (skb) {
> - u16 queue = skb_get_queue_mapping(skb);
> struct netdev_queue *txq;
>
> - txq = netdev_get_tx_queue(skb->dev, queue);
> + txq = skb_get_tx_queue(skb->dev, skb);
> netdev_tx_completed_queue(txq, 1, skb->len);
> dev_kfree_skb_any(skb);
> }
> @@ -1711,7 +1710,7 @@ static int airoha_dev_stop(struct net_device *dev)
> if (err)
> return err;
>
> - for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++)
> + for (i = 0; i < dev->num_tx_queues; i++)
> netdev_tx_reset_subqueue(dev, i);
>
> airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id),
> @@ -2002,7 +2001,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
>
> spin_lock_bh(&q->lock);
>
> - txq = netdev_get_tx_queue(dev, qid);
> + txq = skb_get_tx_queue(dev, skb);
> nr_frags = 1 + skb_shinfo(skb)->nr_frags;
>
> if (q->queued + nr_frags >= q->ndesc) {
>
> ---
> base-commit: a663bac71a2f0b3ac6c373168ca57b2a6e6381aa
> change-id: 20260421-airoha-fix-bql-7fff7cebbc9a
>
> Best regards,
> --
> Lorenzo Bianconi <lorenzo@kernel.org>
>
commenting on Sashiko reported issues:
https://sashiko.dev/#/patchset/20260421-airoha-fix-bql-v1-1-f135afe4275b%40kernel.org
- This isn't a bug in this patch, but does using 0xff as a sentinel value cause a permanent stall?
I do not think this is a real issue since, according to my understanding, the NIC
never writes 0xff in irq_q queue.
- This is another pre-existing issue, but does freeing the SKB here cause a DMA use-after-free
for multi-fragment packets?
This issue is not related to this patch, and I will fix it in a dedicated
patch storing the skb pointer in the last descriptor in airoha_dev_xmit()
- Since the QDMA hardware and NAPI instance are shared among multiple ports (qdma->users),
could active NAPI polling cause a BUG_ON() in dql_completed()?
This is not an issue related to this patch since here we are just resetting
all the netdev tx queues instead of just the first ARRAY_SIZE(qdma->q_tx)
ones.
- This isn't a bug in this patch, but does failing to wait for the DMA engines to become
idle before unmapping buffers cause memory corruption?
This issue is not related to this patch and it will be fixed with a dedicated
patch.
- This is also pre-existing, but can this mapping cause a kernel panic on highmem systems?
Can we have fragments in high memory? e.g on ARM architecture? Anyway, as
pointed out by Sashiko, this issue is not related to this patch.
- This isn't introduced here, but does this logic cause a permanent TX stall?
this issue is already fixed in the following patch:
https://patchwork.kernel.org/project/netdevbpf/patch/20260421-airoha-xmit-stop-condition-v1-1-e670d6a48467@kernel.org/
Regards,
Lorenzo
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* [PATCH v2 0/7] media: synopsys: enhancements and i.MX95 support
From: Guoniu Zhou @ 2026-04-23 8:22 UTC (permalink / raw)
To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Laurent Pinchart, Frank Li, Sakari Ailus, Bryan O'Donoghue,
Mehdi Djait, Hans Verkuil
Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
linux-rockchip, Guoniu Zhou
This series enhances the Synopsys DesignWare MIPI CSI-2 receiver driver
with multiple stream support and adds i.MX95 platform support.
The i.MX95 variant is similar to i.MX93 but uses IDI instead of IPI. Since
IDI is software transparent, only a different register map is needed.
Tested on i.MX93 and i.MX95 platforms.
Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
Changes in v2:
- Add two new patches
- Simplify error handling by keeping goto labels instead of early returns
- Removes redundant register availability check
- Uses read_poll_timeout() with dw_mipi_csi2rx_read() instead of
readl_poll_timeout() with direct register address
- Fixes stopstate condition logic
- Check PHY stopstate after sensor enable instead of before to ensure
correct timing.
- Optimize PHY stopstate polling parameters (1000us->10us, 2s->1ms) to
balance performance and responsiveness.
- Add dedicated constraint block for i.MX95 to reflect different clock
requirements (only per clock needed vs i.MX93 which needs both per and
pixel clocks)
- Update commit message to include more details about interface differences
- Add Reviewed-by tag from Frank Li <Frank.Li@nxp.com>
- Update commit message
- See each patch's changelog for details.
- Link to v1: https://lore.kernel.org/r/20260415-csi2_imx95-v1-0-7d63f3508719@oss.nxp.com
---
Guoniu Zhou (7):
media: synopsys: Fix out-of-bounds check in enum_mbus_code
media: synopsys: Fix IPI using hardcoded datatype
media: synopsys: Add support for RAW16 Bayer formats
media: synopsys: Add support for multiple streams
media: synopsys: Add PHY stopstate wait for i.MX93
media: dt-bindings: add NXP i.MX95 compatible string
media: synopsys: Add support for i.MX95
.../bindings/media/rockchip,rk3568-mipi-csi2.yaml | 16 +++
drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 109 +++++++++++++++++++--
2 files changed, 118 insertions(+), 7 deletions(-)
---
base-commit: 4fbeef21f5387234111b5d52924e77757626faa5
change-id: 20260414-csi2_imx95-65ad0e7f630a
Best regards,
--
Guoniu Zhou <guoniu.zhou@oss.nxp.com>
^ permalink raw reply
* [PATCH v2 1/7] media: synopsys: Fix out-of-bounds check in enum_mbus_code
From: Guoniu Zhou @ 2026-04-23 8:22 UTC (permalink / raw)
To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Laurent Pinchart, Frank Li, Sakari Ailus, Bryan O'Donoghue,
Mehdi Djait, Hans Verkuil
Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
linux-rockchip, Guoniu Zhou
In-Reply-To: <20260423-csi2_imx95-v2-0-934c02f3422a@oss.nxp.com>
dw_mipi_csi2rx_enum_mbus_code() contains an off-by-one error in the
bounds check for code->index, allowing an access past the end of the
formats array.
Fixes: 355a11004066 ("media: synopsys: add driver for the designware mipi csi-2 receiver")
Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
Changes in v2:
- New added in v2
---
drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index ce17f986279e..02eb4a6cafad 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -430,7 +430,7 @@ dw_mipi_csi2rx_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
case DW_MIPI_CSI2RX_PAD_SINK:
- if (code->index > csi2->formats_num)
+ if (code->index >= csi2->formats_num)
return -EINVAL;
code->code = csi2->formats[code->index].code;
--
2.34.1
^ permalink raw reply related
* [PATCH v2 2/7] media: synopsys: Fix IPI using hardcoded datatype
From: Guoniu Zhou @ 2026-04-23 8:22 UTC (permalink / raw)
To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Laurent Pinchart, Frank Li, Sakari Ailus, Bryan O'Donoghue,
Mehdi Djait, Hans Verkuil
Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
linux-rockchip, Guoniu Zhou
In-Reply-To: <20260423-csi2_imx95-v2-0-934c02f3422a@oss.nxp.com>
The imx93_csi2rx_dphy_ipi_enable() function configures the IPI datatype
using csi2->formats->csi_dt, which is initialized during probe but never
updated in set_fmt(). This causes the IPI to always use the probe-time
default datatype, ignoring the actual media bus format negotiated at
runtime. When userspace requests a different format, the IPI hardware is
configured with the wrong datatype, resulting in incorrect image output.
Fix by updating csi2->formats in the set_fmt callback to reflect the
currently negotiated format, ensuring the IPI configuration matches the
runtime datatype.
Fixes: ec40b431f0ab ("media: synopsys: csi2rx: add i.MX93 support")
Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
Changes in v2:
- New added in v2
---
drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index 02eb4a6cafad..b3f90da8b43c 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -470,6 +470,11 @@ static int dw_mipi_csi2rx_set_fmt(struct v4l2_subdev *sd,
*src = *sink;
+ /* Store the CSIS format descriptor for active formats. */
+ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ csi2->formats = fmt ? :
+ dw_mipi_csi2rx_find_format(csi2, default_format.code);
+
return 0;
}
--
2.34.1
^ permalink raw reply related
* [PATCH v2 3/7] media: synopsys: Add support for RAW16 Bayer formats
From: Guoniu Zhou @ 2026-04-23 8:22 UTC (permalink / raw)
To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Laurent Pinchart, Frank Li, Sakari Ailus, Bryan O'Donoghue,
Mehdi Djait, Hans Verkuil
Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
linux-rockchip, Guoniu Zhou
In-Reply-To: <20260423-csi2_imx95-v2-0-934c02f3422a@oss.nxp.com>
Add higher bit-depth raw image data support for the sensors, which supports
16-bit output.
Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
Changes in v2:
- Update commit message
---
drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index b3f90da8b43c..d572d2eb3bcb 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -252,6 +252,26 @@ static const struct dw_mipi_csi2rx_format formats[] = {
.depth = 12,
.csi_dt = MIPI_CSI2_DT_RAW12,
},
+ {
+ .code = MEDIA_BUS_FMT_SBGGR16_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RAW16,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGBRG16_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RAW16,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGRBG16_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RAW16,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SRGGB16_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RAW16,
+ },
};
static inline struct dw_mipi_csi2rx_device *to_csi2(struct v4l2_subdev *sd)
--
2.34.1
^ permalink raw reply related
* [PATCH v2 4/7] media: synopsys: Add support for multiple streams
From: Guoniu Zhou @ 2026-04-23 8:22 UTC (permalink / raw)
To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Laurent Pinchart, Frank Li, Sakari Ailus, Bryan O'Donoghue,
Mehdi Djait, Hans Verkuil
Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
linux-rockchip, Guoniu Zhou
In-Reply-To: <20260423-csi2_imx95-v2-0-934c02f3422a@oss.nxp.com>
The current driver only supports single stream operation. Add support
for multiple concurrent streams by tracking enabled streams with a
bitmask and only initializing the hardware once for the first stream.
This enables use cases such as surround view systems where multiple
camera streams need to be processed simultaneously through the same
CSI-2 receiver interface.
Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
Changes in v2:
- Simplify error handling by keeping goto labels instead of early returns
---
drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index d572d2eb3bcb..5a2e74d055c0 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -113,6 +113,7 @@ struct dw_mipi_csi2rx_device {
enum v4l2_mbus_type bus_type;
u32 lanes_num;
+ u64 enabled_streams;
const struct dw_mipi_csi2rx_drvdata *drvdata;
};
@@ -537,20 +538,26 @@ static int dw_mipi_csi2rx_enable_streams(struct v4l2_subdev *sd,
if (ret)
goto err;
- ret = dw_mipi_csi2rx_start(csi2);
- if (ret) {
- dev_err(dev, "failed to enable CSI hardware\n");
- goto err_pm_runtime_put;
+ if (!csi2->enabled_streams) {
+ ret = dw_mipi_csi2rx_start(csi2);
+ if (ret) {
+ dev_err(dev, "failed to enable CSI hardware\n");
+ goto err_pm_runtime_put;
+ }
}
ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index, mask);
if (ret)
goto err_csi_stop;
+ csi2->enabled_streams |= streams_mask;
+
return 0;
err_csi_stop:
- dw_mipi_csi2rx_stop(csi2);
+ /* Stop CSI hardware if no streams are enabled */
+ if (!csi2->enabled_streams)
+ dw_mipi_csi2rx_stop(csi2);
err_pm_runtime_put:
pm_runtime_put(dev);
err:
@@ -577,11 +584,16 @@ static int dw_mipi_csi2rx_disable_streams(struct v4l2_subdev *sd,
&streams_mask);
ret = v4l2_subdev_disable_streams(remote_sd, remote_pad->index, mask);
+ if (ret)
+ dev_err(dev, "failed to disable streams on remote subdev: %d\n", ret);
- dw_mipi_csi2rx_stop(csi2);
+ csi2->enabled_streams &= ~streams_mask;
pm_runtime_put(dev);
+ if (!csi2->enabled_streams)
+ dw_mipi_csi2rx_stop(csi2);
+
return ret;
}
--
2.34.1
^ permalink raw reply related
* [PATCH v2 5/7] media: synopsys: Add PHY stopstate wait for i.MX93
From: Guoniu Zhou @ 2026-04-23 8:23 UTC (permalink / raw)
To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Laurent Pinchart, Frank Li, Sakari Ailus, Bryan O'Donoghue,
Mehdi Djait, Hans Verkuil
Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
linux-rockchip, Guoniu Zhou
In-Reply-To: <20260423-csi2_imx95-v2-0-934c02f3422a@oss.nxp.com>
Implement waiting for D-PHY lanes to enter stop state on i.MX93. This
ensures proper PHY initialization by verifying that the clock lane and
all active data lanes have entered the stop state before proceeding with
further operations.
Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
Changes in v2:
- Removes redundant register availability check
- Uses read_poll_timeout() with dw_mipi_csi2rx_read() instead of
readl_poll_timeout() with direct register address
- Fixes stopstate condition logic
- Check PHY stopstate after sensor enable instead of before to ensure
correct timing.
- Optimize PHY stopstate polling parameters (1000us->10us, 2s->1ms) to
balance performance and responsiveness.
---
drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 36 ++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index 5a2e74d055c0..8c38fe8a3f06 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -11,6 +11,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
@@ -35,6 +36,8 @@
#define DW_REG_EXIST BIT(31)
#define DW_REG(x) (DW_REG_EXIST | (x))
+#define DPHY_STOPSTATE_CLK_LANE BIT(16)
+
#define DPHY_TEST_CTRL0_TEST_CLR BIT(0)
#define IPI_VCID_VC(x) FIELD_PREP(GENMASK(1, 0), (x))
@@ -65,6 +68,7 @@ enum dw_mipi_csi2rx_regs_index {
DW_MIPI_CSI2RX_PHY_TST_CTRL0,
DW_MIPI_CSI2RX_PHY_TST_CTRL1,
DW_MIPI_CSI2RX_PHY_SHUTDOWNZ,
+ DW_MIPI_CSI2RX_PHY_STOPSTATE,
DW_MIPI_CSI2RX_IPI_DATATYPE,
DW_MIPI_CSI2RX_IPI_MEM_FLUSH,
DW_MIPI_CSI2RX_IPI_MODE,
@@ -87,6 +91,7 @@ struct dw_mipi_csi2rx_drvdata {
void (*dphy_assert_reset)(struct dw_mipi_csi2rx_device *csi2);
void (*dphy_deassert_reset)(struct dw_mipi_csi2rx_device *csi2);
void (*ipi_enable)(struct dw_mipi_csi2rx_device *csi2);
+ int (*wait_for_phy_stopstate)(struct dw_mipi_csi2rx_device *csi2);
};
struct dw_mipi_csi2rx_format {
@@ -139,6 +144,7 @@ static const u32 imx93_regs[DW_MIPI_CSI2RX_MAX] = {
[DW_MIPI_CSI2RX_PHY_SHUTDOWNZ] = DW_REG(0x40),
[DW_MIPI_CSI2RX_DPHY_RSTZ] = DW_REG(0x44),
[DW_MIPI_CSI2RX_PHY_STATE] = DW_REG(0x48),
+ [DW_MIPI_CSI2RX_PHY_STOPSTATE] = DW_REG(0x4c),
[DW_MIPI_CSI2RX_PHY_TST_CTRL0] = DW_REG(0x50),
[DW_MIPI_CSI2RX_PHY_TST_CTRL1] = DW_REG(0x54),
[DW_MIPI_CSI2RX_IPI_MODE] = DW_REG(0x80),
@@ -550,10 +556,19 @@ static int dw_mipi_csi2rx_enable_streams(struct v4l2_subdev *sd,
if (ret)
goto err_csi_stop;
+ if (!csi2->enabled_streams &&
+ csi2->drvdata->wait_for_phy_stopstate) {
+ ret = csi2->drvdata->wait_for_phy_stopstate(csi2);
+ if (ret)
+ goto err_disable_streams;
+ }
+
csi2->enabled_streams |= streams_mask;
return 0;
+err_disable_streams:
+ v4l2_subdev_disable_streams(remote_sd, remote_pad->index, mask);
err_csi_stop:
/* Stop CSI hardware if no streams are enabled */
if (!csi2->enabled_streams)
@@ -864,11 +879,32 @@ static void imx93_csi2rx_dphy_ipi_enable(struct dw_mipi_csi2rx_device *csi2)
dw_mipi_csi2rx_write(csi2, DW_MIPI_CSI2RX_IPI_MODE, val);
}
+static int imx93_csi2rx_wait_for_phy_stopstate(struct dw_mipi_csi2rx_device *csi2)
+{
+ struct device *dev = csi2->dev;
+ u32 stopstate_mask;
+ u32 val;
+ int ret;
+
+ stopstate_mask = DPHY_STOPSTATE_CLK_LANE | GENMASK(csi2->lanes_num - 1, 0);
+
+ ret = read_poll_timeout(dw_mipi_csi2rx_read, val,
+ (val & stopstate_mask) == stopstate_mask,
+ 10, 1000, true,
+ csi2, DW_MIPI_CSI2RX_PHY_STOPSTATE);
+ if (ret)
+ dev_err(dev, "lanes are not in stop state: %#x, expected %#x\n",
+ val, stopstate_mask);
+
+ return ret;
+}
+
static const struct dw_mipi_csi2rx_drvdata imx93_drvdata = {
.regs = imx93_regs,
.dphy_assert_reset = imx93_csi2rx_dphy_assert_reset,
.dphy_deassert_reset = imx93_csi2rx_dphy_deassert_reset,
.ipi_enable = imx93_csi2rx_dphy_ipi_enable,
+ .wait_for_phy_stopstate = imx93_csi2rx_wait_for_phy_stopstate,
};
static const struct of_device_id dw_mipi_csi2rx_of_match[] = {
--
2.34.1
^ permalink raw reply related
* [PATCH v2 6/7] media: dt-bindings: add NXP i.MX95 compatible string
From: Guoniu Zhou @ 2026-04-23 8:23 UTC (permalink / raw)
To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Laurent Pinchart, Frank Li, Sakari Ailus, Bryan O'Donoghue,
Mehdi Djait, Hans Verkuil
Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
linux-rockchip, Guoniu Zhou
In-Reply-To: <20260423-csi2_imx95-v2-0-934c02f3422a@oss.nxp.com>
The i.MX95 CSI-2 controller is nearly identical to i.MX93, with the
main difference being the data output interface:
i.MX93 use IPI (Image Pixel Interface), which requires:
- Pixel clock input
- Software configuration through registers
i.MX95 uses IDI (Image Data Interface), which:
- Does not require pixel clock
- Is software transparent (no register configuration needed)
Due to these differences in register layout and initialization needs,
the two variants cannot share the same compatible string. The driver
needs to distinguish between them to handle the interface correctly.
Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
Changes in v2:
- Add dedicated constraint block for i.MX95 to reflect different clock
requirements (only per clock needed vs i.MX93 which needs both per
and pixel clocks)
- Update commit message to include more details about interface differences
---
.../bindings/media/rockchip,rk3568-mipi-csi2.yaml | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/Documentation/devicetree/bindings/media/rockchip,rk3568-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/rockchip,rk3568-mipi-csi2.yaml
index 4ac4a3b6f406..4e0bc75c2136 100644
--- a/Documentation/devicetree/bindings/media/rockchip,rk3568-mipi-csi2.yaml
+++ b/Documentation/devicetree/bindings/media/rockchip,rk3568-mipi-csi2.yaml
@@ -18,6 +18,7 @@ properties:
compatible:
enum:
- fsl,imx93-mipi-csi2
+ - fsl,imx95-mipi-csi2
- rockchip,rk3568-mipi-csi2
reg:
@@ -135,6 +136,21 @@ allOf:
clock-names:
minItems: 2
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: fsl,imx95-mipi-csi2
+ then:
+ properties:
+ interrupts:
+ maxItems: 1
+ interrupt-names: false
+ clocks:
+ maxItems: 1
+ clock-names:
+ maxItems: 1
+
examples:
- |
#include <dt-bindings/clock/rk3568-cru.h>
--
2.34.1
^ permalink raw reply related
* [PATCH v2 7/7] media: synopsys: Add support for i.MX95
From: Guoniu Zhou @ 2026-04-23 8:23 UTC (permalink / raw)
To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Laurent Pinchart, Frank Li, Sakari Ailus, Bryan O'Donoghue,
Mehdi Djait, Hans Verkuil
Cc: linux-media, linux-kernel, devicetree, imx, linux-arm-kernel,
linux-rockchip, Guoniu Zhou
In-Reply-To: <20260423-csi2_imx95-v2-0-934c02f3422a@oss.nxp.com>
Add support for the i.MX95 MIPI CSI-2 receiver. The i.MX95 variant is
nearly identical to i.MX93, with the main difference being the use of
IDI (Image Data Interface) instead of IPI (Image Pixel Interface).
However, the IDI interface is transparent to software, requiring only
a different register map definition while sharing the same PHY control
functions with i.MX93.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
---
Changes in v2:
- Add Reviewed-by tag from Frank Li <Frank.Li@nxp.com>
---
drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index 8c38fe8a3f06..62910d61eb64 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -154,6 +154,17 @@ static const u32 imx93_regs[DW_MIPI_CSI2RX_MAX] = {
[DW_MIPI_CSI2RX_IPI_SOFTRSTN] = DW_REG(0xa0),
};
+static const u32 imx95_regs[DW_MIPI_CSI2RX_MAX] = {
+ [DW_MIPI_CSI2RX_N_LANES] = DW_REG(0x4),
+ [DW_MIPI_CSI2RX_RESETN] = DW_REG(0x8),
+ [DW_MIPI_CSI2RX_PHY_SHUTDOWNZ] = DW_REG(0x40),
+ [DW_MIPI_CSI2RX_DPHY_RSTZ] = DW_REG(0x44),
+ [DW_MIPI_CSI2RX_PHY_STATE] = DW_REG(0x48),
+ [DW_MIPI_CSI2RX_PHY_STOPSTATE] = DW_REG(0x4c),
+ [DW_MIPI_CSI2RX_PHY_TST_CTRL0] = DW_REG(0x50),
+ [DW_MIPI_CSI2RX_PHY_TST_CTRL1] = DW_REG(0x54),
+};
+
static const struct v4l2_mbus_framefmt default_format = {
.width = 3840,
.height = 2160,
@@ -907,11 +918,22 @@ static const struct dw_mipi_csi2rx_drvdata imx93_drvdata = {
.wait_for_phy_stopstate = imx93_csi2rx_wait_for_phy_stopstate,
};
+static const struct dw_mipi_csi2rx_drvdata imx95_drvdata = {
+ .regs = imx95_regs,
+ .dphy_assert_reset = imx93_csi2rx_dphy_assert_reset,
+ .dphy_deassert_reset = imx93_csi2rx_dphy_deassert_reset,
+ .wait_for_phy_stopstate = imx93_csi2rx_wait_for_phy_stopstate,
+};
+
static const struct of_device_id dw_mipi_csi2rx_of_match[] = {
{
.compatible = "fsl,imx93-mipi-csi2",
.data = &imx93_drvdata,
},
+ {
+ .compatible = "fsl,imx95-mipi-csi2",
+ .data = &imx95_drvdata,
+ },
{
.compatible = "rockchip,rk3568-mipi-csi2",
.data = &rk3568_drvdata,
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v3 3/3] ARM: at91: remove unnecessary of_platform_default_populate calls
From: Alexander Dahl @ 2026-04-23 8:24 UTC (permalink / raw)
To: Rob Herring (Arm)
Cc: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Nicolas Ferre, Alexandre Belloni, Claudiu Beznea, Russell King,
linux-mtd, linux-arm-kernel, linux-kernel
In-Reply-To: <20260105-at91-probe-v3-3-594013ff2965@kernel.org>
Hello everyone,
I'm afraid this patch breaks finding rootfs on raw nand on sam9x60,
see below:
Am Mon, Jan 05, 2026 at 03:06:45PM -0600 schrieb Rob Herring (Arm):
> The DT core will call of_platform_default_populate, so it is not
> necessary for machine specific code to call it unless there are custom
> match entries, auxdata or parent device. Neither of those apply here, so
> remove the call.
>
> Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> Tested-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
Not sure what was actually tested, but this change breaks booting from
raw NAND flash on our sam9x60 based board. I bisected the boot
failure to this exact change. Before the change I see the nand
controller messages in the kernel log like this:
atmel-nand-controller 10000000.ebi:nand-controller: using dma0chan5 for DMA transfers
nand: device found, Manufacturer ID: 0x01, Chip ID: 0xda
nand: AMD/Spansion S34ML02G1
nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
After the change, there are no kernel log messages related to nand at
all, the driver does not seem to load. This of course leads to no mtd
and ubi devices created, no ubi volumes found, no rootfs, and
eventually this message:
VFS: Cannot open root device "ubi0:rootfs2" or unknown-block(0,253): error -19
I tried to understand the whole patch series, and to my understanding
the intend was the device nodes still get populated, and the drivers
loaded, right? Patch 1/3 is related to the atmel nand controller, and
that one is not in the tree yet when bisecting to the end. However it
is present in v7.0-rc1 (and later) and trying to boot that kernel (or
7.0 or todays master) fails, too. (Also I don't see those probe defer
messages related to SRAM on v7.0-rc1, so I assume that's not the
problem?)
Now the strange thing is: on a different hardware based on sama5d2
v7.0-rc1 boots fine from raw nand flash. I wonder what's the
difference which makes it work on one atmel platform and not work on
the other?
I compared kernel .config of both boards, no obvious pieces missing.
Looking at the dts (and included dtsi) files of both boards I could
spot no mistake. Also no obvious flaws in sama5d2.dtsi or
sam9x60.dtsi.
Note: raw NAND flash is the only storage for rootfs on our platforms,
we can not simply put rootfs to a different storage. I could try
setting up NFS boot for further investigation, but that will take a
while.
Does anyone have an idea how to make booting from raw NAND flash work
on sam9x60 again (despite the obviously not desired revert)? What can
I try? What information would be interesting for debugging?
Greets
Alex
> ---
> v3:
> - Fixup split between patch 2 and 3.
>
> v2:
> - Dust off and rebase to 6.18-rc1
> - Add new platforms added since v1
> ---
> arch/arm/mach-at91/at91rm9200.c | 9 ---------
> arch/arm/mach-at91/at91sam9.c | 9 ---------
> arch/arm/mach-at91/sam9x60.c | 9 ---------
> arch/arm/mach-at91/sam9x7.c | 9 ---------
> arch/arm/mach-at91/sama5.c | 16 ----------------
> arch/arm/mach-at91/sama7.c | 9 ---------
> 6 files changed, 61 deletions(-)
>
> diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
> index 2ac564eb8bbb..d15997fff5d7 100644
> --- a/arch/arm/mach-at91/at91rm9200.c
> +++ b/arch/arm/mach-at91/at91rm9200.c
> @@ -7,18 +7,10 @@
> * 2012 Joachim Eastwood <manabian@gmail.com>
> */
>
> -#include <linux/of.h>
> -#include <linux/of_platform.h>
> -
> #include <asm/mach/arch.h>
>
> #include "generic.h"
>
> -static void __init at91rm9200_dt_device_init(void)
> -{
> - of_platform_default_populate(NULL, NULL, NULL);
> -}
> -
> static const char *const at91rm9200_dt_board_compat[] __initconst = {
> "atmel,at91rm9200",
> NULL
> @@ -26,6 +18,5 @@ static const char *const at91rm9200_dt_board_compat[] __initconst = {
>
> DT_MACHINE_START(at91rm9200_dt, "Atmel AT91RM9200")
> .init_late = at91rm9200_pm_init,
> - .init_machine = at91rm9200_dt_device_init,
> .dt_compat = at91rm9200_dt_board_compat,
> MACHINE_END
> diff --git a/arch/arm/mach-at91/at91sam9.c b/arch/arm/mach-at91/at91sam9.c
> index cf07cba4ee5d..b9d2909d1b65 100644
> --- a/arch/arm/mach-at91/at91sam9.c
> +++ b/arch/arm/mach-at91/at91sam9.c
> @@ -6,19 +6,11 @@
> * 2011 Nicolas Ferre <nicolas.ferre@atmel.com>
> */
>
> -#include <linux/of.h>
> -#include <linux/of_platform.h>
> -
> #include <asm/mach/arch.h>
> #include <asm/system_misc.h>
>
> #include "generic.h"
>
> -static void __init at91sam9_init(void)
> -{
> - of_platform_default_populate(NULL, NULL, NULL);
> -}
> -
> static const char *const at91_dt_board_compat[] __initconst = {
> "atmel,at91sam9",
> NULL
> @@ -27,6 +19,5 @@ static const char *const at91_dt_board_compat[] __initconst = {
> DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM9")
> /* Maintainer: Atmel */
> .init_late = at91sam9_pm_init,
> - .init_machine = at91sam9_init,
> .dt_compat = at91_dt_board_compat,
> MACHINE_END
> diff --git a/arch/arm/mach-at91/sam9x60.c b/arch/arm/mach-at91/sam9x60.c
> index a31beaaeffcd..744bab2cbb92 100644
> --- a/arch/arm/mach-at91/sam9x60.c
> +++ b/arch/arm/mach-at91/sam9x60.c
> @@ -7,19 +7,11 @@
> * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
> */
>
> -#include <linux/of.h>
> -#include <linux/of_platform.h>
> -
> #include <asm/mach/arch.h>
> #include <asm/system_misc.h>
>
> #include "generic.h"
>
> -static void __init sam9x60_init(void)
> -{
> - of_platform_default_populate(NULL, NULL, NULL);
> -}
> -
> static const char *const sam9x60_dt_board_compat[] __initconst = {
> "microchip,sam9x60",
> NULL
> @@ -28,6 +20,5 @@ static const char *const sam9x60_dt_board_compat[] __initconst = {
> DT_MACHINE_START(sam9x60_dt, "Microchip SAM9X60")
> /* Maintainer: Microchip */
> .init_late = sam9x60_pm_init,
> - .init_machine = sam9x60_init,
> .dt_compat = sam9x60_dt_board_compat,
> MACHINE_END
> diff --git a/arch/arm/mach-at91/sam9x7.c b/arch/arm/mach-at91/sam9x7.c
> index 0c73f7fefd4f..166c8625509d 100644
> --- a/arch/arm/mach-at91/sam9x7.c
> +++ b/arch/arm/mach-at91/sam9x7.c
> @@ -7,18 +7,10 @@
> * Author: Varshini Rajendran <varshini.rajendran@microchip.com>
> */
>
> -#include <linux/of.h>
> -#include <linux/of_platform.h>
> -
> #include <asm/mach/arch.h>
>
> #include "generic.h"
>
> -static void __init sam9x7_init(void)
> -{
> - of_platform_default_populate(NULL, NULL, NULL);
> -}
> -
> static const char * const sam9x7_dt_board_compat[] __initconst = {
> "microchip,sam9x7",
> NULL
> @@ -27,6 +19,5 @@ static const char * const sam9x7_dt_board_compat[] __initconst = {
> DT_MACHINE_START(sam9x7_dt, "Microchip SAM9X7")
> /* Maintainer: Microchip */
> .init_late = sam9x7_pm_init,
> - .init_machine = sam9x7_init,
> .dt_compat = sam9x7_dt_board_compat,
> MACHINE_END
> diff --git a/arch/arm/mach-at91/sama5.c b/arch/arm/mach-at91/sama5.c
> index 576654cba82d..e56022f00800 100644
> --- a/arch/arm/mach-at91/sama5.c
> +++ b/arch/arm/mach-at91/sama5.c
> @@ -6,9 +6,6 @@
> * 2013 Ludovic Desroches <ludovic.desroches@atmel.com>
> */
>
> -#include <linux/of.h>
> -#include <linux/of_platform.h>
> -
> #include <asm/hardware/cache-l2x0.h>
> #include <asm/mach/arch.h>
> #include <asm/mach/map.h>
> @@ -30,11 +27,6 @@ static void __init sama5_secure_cache_init(void)
> outer_cache.write_sec = sama5_l2c310_write_sec;
> }
>
> -static void __init sama5_dt_device_init(void)
> -{
> - of_platform_default_populate(NULL, NULL, NULL);
> -}
> -
> static const char *const sama5_dt_board_compat[] __initconst = {
> "atmel,sama5",
> NULL
> @@ -43,7 +35,6 @@ static const char *const sama5_dt_board_compat[] __initconst = {
> DT_MACHINE_START(sama5_dt, "Atmel SAMA5")
> /* Maintainer: Atmel */
> .init_late = sama5_pm_init,
> - .init_machine = sama5_dt_device_init,
> .dt_compat = sama5_dt_board_compat,
> MACHINE_END
>
> @@ -54,17 +45,11 @@ static const char *const sama5_alt_dt_board_compat[] __initconst = {
>
> DT_MACHINE_START(sama5_alt_dt, "Atmel SAMA5")
> /* Maintainer: Atmel */
> - .init_machine = sama5_dt_device_init,
> .init_late = sama5_pm_init,
> .dt_compat = sama5_alt_dt_board_compat,
> .l2c_aux_mask = ~0UL,
> MACHINE_END
>
> -static void __init sama5d2_init(void)
> -{
> - of_platform_default_populate(NULL, NULL, NULL);
> -}
> -
> static const char *const sama5d2_compat[] __initconst = {
> "atmel,sama5d2",
> NULL
> @@ -72,7 +57,6 @@ static const char *const sama5d2_compat[] __initconst = {
>
> DT_MACHINE_START(sama5d2, "Atmel SAMA5")
> /* Maintainer: Atmel */
> - .init_machine = sama5d2_init,
> .init_early = sama5_secure_cache_init,
> .init_late = sama5d2_pm_init,
> .dt_compat = sama5d2_compat,
> diff --git a/arch/arm/mach-at91/sama7.c b/arch/arm/mach-at91/sama7.c
> index 8bf57a020f1c..f56828d61199 100644
> --- a/arch/arm/mach-at91/sama7.c
> +++ b/arch/arm/mach-at91/sama7.c
> @@ -6,19 +6,11 @@
> *
> */
>
> -#include <linux/of.h>
> -#include <linux/of_platform.h>
> -
> #include <asm/mach/arch.h>
> #include <asm/system_misc.h>
>
> #include "generic.h"
>
> -static void __init sama7_dt_device_init(void)
> -{
> - of_platform_default_populate(NULL, NULL, NULL);
> -}
> -
> static const char *const sama7_dt_board_compat[] __initconst = {
> "microchip,sama7",
> NULL
> @@ -27,7 +19,6 @@ static const char *const sama7_dt_board_compat[] __initconst = {
> DT_MACHINE_START(sama7_dt, "Microchip SAMA7")
> /* Maintainer: Microchip */
> .init_late = sama7_pm_init,
> - .init_machine = sama7_dt_device_init,
> .dt_compat = sama7_dt_board_compat,
> MACHINE_END
>
>
> --
> 2.51.0
>
>
^ permalink raw reply
* Re: [PATCH RFC 2/2] clk: scmi: Add support for two #clock-cells to pass rate rounding mode
From: Sudeep Holla @ 2026-04-23 8:25 UTC (permalink / raw)
To: Peng Fan
Cc: Michael Turquette, Sudeep Holla, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Cristian Marussi, linux-kernel,
linux-clk, devicetree, arm-scmi, linux-arm-kernel, Peng Fan
In-Reply-To: <aelzO5W2HD8zAgxf@shlinux89>
On Thu, Apr 23, 2026 at 09:17:47AM +0800, Peng Fan wrote:
> On Wed, Apr 22, 2026 at 07:51:03PM +0100, Sudeep Holla wrote:
> >On Wed, Apr 22, 2026 at 10:00:23PM +0800, Peng Fan wrote:
> >> Hi Sudeep,
> >>
> >> Thanks for giving a look.
> >>
> >> On Wed, Apr 22, 2026 at 02:14:56PM +0100, Sudeep Holla wrote:
> >> >On Fri, Mar 06, 2026 at 02:20:13PM +0800, Peng Fan (OSS) wrote:
> >> >> From: Peng Fan <peng.fan@nxp.com>
> >> >>
> >> >> SCMI CLOCK_RATE_SET allows the caller to specify the rounding behaviour
> >> >> when setting a clock rate. The previously added dt-bindings header
> >> >> defines three modes:
> >> >>
> >> >> ROUND_DOWN / ROUND_UP / ROUND_AUTO
> >> >>
> >> >> To enable device tree clients to select a rounding mode, extend the
> >> >> SCMI clock provider to support "#clock-cells = <2>", where the second
> >> >> cell encodes the desired rounding mode. The default remains
> >> >> ROUND_DOWN for backwards compatibility with existing device trees.
> >> >>
> >> >
> >> >Where is the binding update documented ? It's not in 1/2.
> >>
> >> This was missed in this patchset, I will fix in new version, if this
> >> patchset does not have big design flaw.
> >>
> >> >
> >> >Also if it can be static in the device tree, why can't it be
> >> >autonomously handled in the platform firmware ? I think I know the
> >>
> >> Linux passes ROUND_DOWN, SCMI firmware uses round down for clk calculation.
> >>
> >> >answer for this but I want to make sure it is a valid use-case and
> >> >gets documented here as part of binding updates.
> >>
> >> Per info from our video software team.
> >> We have some video modes where the best pixel clock rate is slightly above the
> >> nominal rate, and the default round down rule (CLOCK_ROUND_RULE_CEILING in SM
> >> firmware) can cause the resulting clock rate to be much lower than expected.
> >>
> >> disp1pix = 96200000 Hz (desired pixel clock rate)
> >>
> >> The MIPI DPHY cannot hit the exact frequency of 288600000 Hz needed for this
> >> pixel clock rate, so the next best DPHY PLL frequency is 289000000 Hz. This
> >> corresponds to a pixel clock frequency of 96333333 Hz, which is slightly higher
> >> than the nominal rate of 96200000 Hz the video mode specifies.
> >>
> >> Setting the VIDEOPLL (disp1pix parent) to 289000000 Hz should divide down to
> >> the adjusted disp1pix frequency of 96333333 Hz, but here is what happens in the
> >> SM firmware:
> >>
> >> quotient = 289000000 / (96200000 + 1) = 3.004 => 3 (notice that the SM always
> >> receives the nominal clock rate, not the adjusted rate)
> >>
> >> If the rounding rule is round down (CLOCK_ROUND_RULE_CEILING),
> >> quotient = quotient + 1. Therefore, quotient becomes 4.
> >>
> >> disp1pix = 289000000 / 4 = 72250000, which is nowhere close to the target of
> >> 96333333.
> >>
> >
> >I do not think this is the correct interpretation of `CLOCK_ROUND_DOWN/UP`.
> >
> >`CLOCK_ROUND_DOWN/UP` should apply to the requested `disp1pix` rate itself,
> >not to the divider choice in a way that forces selection of the next integer
> >divisor and produces a much lower output clock.
> >
> >Here, the requested `disp1pix` is `96,200,000 Hz`, and the parent rate is
> >`289,000,000 Hz`. The achievable child rates nearby are:
> >
> >`289,000,000 / 3 = 96,333,333 Hz`
> >`289,000,000 / 4 = 72,250,000 Hz`
> >
> >Given those options, the firmware should be able to round the request
> >autonomously to the nearest supported `disp1pix` rate, which is `96,333,333
> >Hz` (`289,000,000 / 3`).
> >
> >Under that interpretation:
> >
> >`CLOCK_ROUND_UP` would permit choosing `96,333,333`
> >`CLOCK_ROUND_AUTO` would also likely choose `96,333,333`
> >Choosing `/4` and ending up at `72,250,000` does not look like a meaningful
> >rounding of `96,200,000`
> >
> >So the issue appears to be that the firmware is applying the rounding rule to
> >divider selection rather than to the resulting `disp1pix` frequency.
>
> User requests 96.2 MHz with ROUND_DOWN semantics, expecting the closest
> achievable frequency that does not meaningfully deviate from the request.
>
> Firmware evaluates the parent rate of 289,000,000 Hz and computes:
>
> 289,000,000 / 3 = 96,333,333 Hz
>
> Since this resulting frequency is slightly higher than the requested
> 96.2 MHz, the firmware, applying a strict `output <= requested` rule,
> rejects divider 3 and selects divider 4 instead, producing:
>
> 289,000,000 / 4 = 72,250,000 Hz
>
> This leads to an output frequency that is much farther from the requested
> value.
>
> My question is: if the firmware were to select divider 3 and produce
> 96,333,333 Hz (only ~0.13% higher than the request), would that be
> considered a violation of ROUND_DOWN semantics, or is ROUND_DOWN intended
> to select the closest achievable output frequency rather than enforcing
> a strict inequality against the requested rate?
>
We can change the driver to default to ROUND_AUTO if that helps. I fully
understand the default ROUND_DOWN is not good but if firmware can't handle
your use case with ROUND_AUTO, it is firmware issue.
--
Regards,
Sudeep
^ permalink raw reply
* Re: [PATCH v17 0/5] ring-buffer: Making persistent ring buffers robust
From: Masami Hiramatsu @ 2026-04-23 8:26 UTC (permalink / raw)
To: Masami Hiramatsu (Google)
Cc: Steven Rostedt, Catalin Marinas, Will Deacon, Mathieu Desnoyers,
linux-kernel, linux-trace-kernel, Ian Rogers, linux-arm-kernel
In-Reply-To: <177687458572.932171.10907864814735342737.stgit@mhiramat.tok.corp.google.com>
Hi,
Sashiko[1] pointed out other problems. Let me review it.
I also found one mistake (not by this series), so I will fix it too.
[1] https://sashiko.dev/#/patchset/177687458572.932171.10907864814735342737.stgit%40mhiramat.tok.corp.google.com
Thanks,
On Thu, 23 Apr 2026 01:16:26 +0900
"Masami Hiramatsu (Google)" <mhiramat@kernel.org> wrote:
> Hi,
>
> Here is the 17th version of improvement patches for making persistent
> ring buffers robust to failures.
> The previous version is here:
>
> https://lore.kernel.org/all/177547105523.259641.14385891517704197263.stgit@mhiramat.tok.corp.google.com/
>
> This version fixes some review comments from Sashiko[1], which
> includes:
> [2/5] Fix to use rb_page_size() of rewound pages for entry_bytes.
> [3/5] - Fix to verify head_page at first before using its timestamp.
> - Reset timestamp if the page is invalid.
> [4/5] - In rb_test_inject_invalid_pages(), changed entry_bytes and
> idx to unsigned long
> - Added NULL checks for cpu_buffer and meta.
> - In allocate_trace_buffer(), added a NULL check for tr->name
> before comparing it with strcmp.
> [5/5] Added NULL check for dpage in rbm_show in ring_buffer.c.
>
> [1] https://sashiko.dev/#/patchset/177552432201.853249.5125045538812833325.stgit%40mhiramat.tok.corp.google.com
>
> Thank you,
>
> Masami Hiramatsu (Google) (5):
> ring-buffer: Flush and stop persistent ring buffer on panic
> ring-buffer: Skip invalid sub-buffers when validating persistent ring buffer
> ring-buffer: Skip invalid sub-buffers when rewinding persistent ring buffer
> ring-buffer: Add persistent ring buffer invalid-page inject test
> ring-buffer: Show commit numbers in buffer_meta file
>
>
> arch/alpha/include/asm/Kbuild | 1
> arch/arc/include/asm/Kbuild | 1
> arch/arm/include/asm/Kbuild | 1
> arch/arm64/include/asm/ring_buffer.h | 10 +
> arch/csky/include/asm/Kbuild | 1
> arch/hexagon/include/asm/Kbuild | 1
> arch/loongarch/include/asm/Kbuild | 1
> arch/m68k/include/asm/Kbuild | 1
> arch/microblaze/include/asm/Kbuild | 1
> arch/mips/include/asm/Kbuild | 1
> arch/nios2/include/asm/Kbuild | 1
> arch/openrisc/include/asm/Kbuild | 1
> arch/parisc/include/asm/Kbuild | 1
> arch/powerpc/include/asm/Kbuild | 1
> arch/riscv/include/asm/Kbuild | 1
> arch/s390/include/asm/Kbuild | 1
> arch/sh/include/asm/Kbuild | 1
> arch/sparc/include/asm/Kbuild | 1
> arch/um/include/asm/Kbuild | 1
> arch/x86/include/asm/Kbuild | 1
> arch/xtensa/include/asm/Kbuild | 1
> include/asm-generic/ring_buffer.h | 13 ++
> include/linux/ring_buffer.h | 1
> kernel/trace/Kconfig | 34 ++++
> kernel/trace/ring_buffer.c | 275 ++++++++++++++++++++++++++--------
> kernel/trace/trace.c | 4
> 26 files changed, 290 insertions(+), 67 deletions(-)
> create mode 100644 arch/arm64/include/asm/ring_buffer.h
> create mode 100644 include/asm-generic/ring_buffer.h
>
>
> base-commit: 6170922f137231b98fc568571befef63e1edff3f
> --
> Masami Hiramatsu (Google) <mhiramat@kernel.org>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply
* [PATCH v3 0/3] Add RP1 PWM controller support
From: Andrea della Porta @ 2026-04-23 8:30 UTC (permalink / raw)
To: Uwe Kleine-König, linux-pwm, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Broadcom internal kernel review list, Andrea della Porta,
devicetree, linux-rpi-kernel, linux-arm-kernel, linux-kernel,
Naushir Patuck, Stanimir Varbanov, mbrugger
This patchset adds support for the PWM controller found on the
Raspberry Pi RP1 southbridge. This is necessary to operate the
cooling fan connected to one of the PWM channels.
The tachometer pin for the fan speed is managed by the firmware
running on the RP1's M-core. It uses the PHASE2 register
to report the RPM, which is then exported by this driver via
syscon registers. A subsequent patch will add a new device
and driver to read the RPM and export this value via hwmon.
Subsequent patches will also add the CPU thermal zone, which
acts as a consumer of the PWM device.
Best regards,
Andrea
CHANGES in V3:
- Refactored all the register macros. They now have RP1_PWM_ prefix
and follow the register name.
- Dropped the tab alignment in front of struct declarations (use a space
instead).
- Added a check in tohw() to test (and bail out quickly) in case that
period_length_ns is zero.
- Probing now returns an error if clk_rate > 1 GHz.
- Added a check on minimum period ticks. Return 1 to signal round-up.
- Fixed inverted polarity detection on edge cases.
- Fixed rounding errors (in both tohwi() and fromhw()) in inverted
polarity calculations.
- Dropped a redundant check on period >= duty.
- Replaced memset by inline struct init.
- Disabling a channel now is faster, skipping the duty/period/polarity
setup.
- Fixed an error string (s/Fail/Failed)
- Used %pe to signal error string instead of an integer.
- Added several new sections to the Limitations paragraph to better
explain what will happen on edge cases.
- Maximum period is now U32_MAX-1 to allow 100% duty cycle on all
selectable periods.
- The hw period register now takes into account for the extra tick at
the end of the period (subtracted one to wfhw->period_ticks in tohw
and added 1 in fromhw).
- Added .remove() callback to free resources even if the driver is
not unbindable/unloadable, to avoid accumulating tech debt.
Naushir Patuck (2):
dt-bindings: pwm: Add Raspberry Pi RP1 PWM controller
pwm: rp1: Add RP1 PWM controller driver
Stanimir Varbanov (1):
arm64: dts: broadcom: rpi-5: Add RP1 PWM node
.../bindings/pwm/raspberrypi,rp1-pwm.yaml | 54 +++
.../boot/dts/broadcom/bcm2712-rpi-5-b.dts | 12 +
arch/arm64/boot/dts/broadcom/rp1-common.dtsi | 10 +
drivers/pwm/Kconfig | 9 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-rp1.c | 414 ++++++++++++++++++
6 files changed, 500 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml
create mode 100644 drivers/pwm/pwm-rp1.c
--
2.35.3
^ permalink raw reply
* [PATCH v3 1/3] dt-bindings: pwm: Add Raspberry Pi RP1 PWM controller
From: Andrea della Porta @ 2026-04-23 8:30 UTC (permalink / raw)
To: Uwe Kleine-König, linux-pwm, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Broadcom internal kernel review list, Andrea della Porta,
devicetree, linux-rpi-kernel, linux-arm-kernel, linux-kernel,
Naushir Patuck, Stanimir Varbanov, mbrugger
Cc: Krzysztof Kozlowski
In-Reply-To: <cover.1776932336.git.andrea.porta@suse.com>
From: Naushir Patuck <naush@raspberrypi.com>
Add the devicetree binding documentation for the PWM
controller found in the Raspberry Pi RP1 chipset.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Co-developed-by: Stanimir Varbanov <svarbanov@suse.de>
Signed-off-by: Stanimir Varbanov <svarbanov@suse.de>
Signed-off-by: Andrea della Porta <andrea.porta@suse.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
.../bindings/pwm/raspberrypi,rp1-pwm.yaml | 54 +++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml
diff --git a/Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml b/Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml
new file mode 100644
index 0000000000000..6f8461d0454f7
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/raspberrypi,rp1-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Raspberry Pi RP1 PWM controller
+
+maintainers:
+ - Naushir Patuck <naush@raspberrypi.com>
+
+allOf:
+ - $ref: pwm.yaml#
+
+description: |
+ The PWM peripheral is a flexible waveform generator with a
+ variety of operational modes. It has the following features:
+ - four independent output channels
+ - 32-bit counter widths
+ - Seven output generation modes
+ - Optional per-channel output inversion
+ - Optional duty-cycle data FIFO with DMA support
+ - Optional sigma-delta noise shaping engine
+ Serves as a fan speed provider to other nodes for a PWM-connected
+ fan using shared registers (syscon).
+
+properties:
+ compatible:
+ const: raspberrypi,rp1-pwm
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ "#pwm-cells":
+ const: 3
+
+required:
+ - compatible
+ - reg
+ - clocks
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ pwm@98000 {
+ compatible = "raspberrypi,rp1-pwm";
+ reg = <0x98000 0x100>;
+ clocks = <&rp1_clocks 17>;
+ #pwm-cells = <3>;
+ };
--
2.35.3
^ permalink raw reply related
* [PATCH v3 3/3] arm64: dts: broadcom: rpi-5: Add RP1 PWM node
From: Andrea della Porta @ 2026-04-23 8:30 UTC (permalink / raw)
To: Uwe Kleine-König, linux-pwm, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Broadcom internal kernel review list, Andrea della Porta,
devicetree, linux-rpi-kernel, linux-arm-kernel, linux-kernel,
Naushir Patuck, Stanimir Varbanov, mbrugger
In-Reply-To: <cover.1776932336.git.andrea.porta@suse.com>
From: Stanimir Varbanov <svarbanov@suse.de>
The RP1 chipset used on the Raspberry Pi 5 features an integrated
PWM controller to drive the cooling fan.
Add the corresponding DT node for this PWM controller.
Signed-off-by: Stanimir Varbanov <svarbanov@suse.de>
Co-developed-by: Andrea della Porta <andrea.porta@suse.com>
Signed-off-by: Andrea della Porta <andrea.porta@suse.com>
---
arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 12 ++++++++++++
arch/arm64/boot/dts/broadcom/rp1-common.dtsi | 10 ++++++++++
2 files changed, 22 insertions(+)
diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
index 2856082814462..a4e5ba23bf536 100644
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
@@ -64,12 +64,24 @@ phy1: ethernet-phy@1 {
};
&rp1_gpio {
+ fan_pwm_default_state: fan-pwm-default-state {
+ function = "pwm1";
+ pins = "gpio45";
+ bias-pull-down;
+ };
+
usb_vbus_default_state: usb-vbus-default-state {
function = "vbus1";
groups = "vbus1";
};
};
+&rp1_pwm {
+ pinctrl-0 = <&fan_pwm_default_state>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
&rp1_usb0 {
pinctrl-0 = <&usb_vbus_default_state>;
pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/broadcom/rp1-common.dtsi b/arch/arm64/boot/dts/broadcom/rp1-common.dtsi
index 5a815c3797945..d0f4d6be75500 100644
--- a/arch/arm64/boot/dts/broadcom/rp1-common.dtsi
+++ b/arch/arm64/boot/dts/broadcom/rp1-common.dtsi
@@ -26,6 +26,16 @@ rp1_clocks: clocks@40018000 {
<200000000>; // RP1_CLK_SYS
};
+ rp1_pwm: pwm@4009c000 {
+ compatible = "raspberrypi,rp1-pwm";
+ reg = <0x00 0x4009c000 0x0 0x100>;
+ clocks = <&rp1_clocks RP1_CLK_PWM1>;
+ assigned-clocks = <&rp1_clocks RP1_CLK_PWM1>;
+ assigned-clock-rates = <50000000>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
rp1_gpio: pinctrl@400d0000 {
compatible = "raspberrypi,rp1-gpio";
reg = <0x00 0x400d0000 0x0 0xc000>,
--
2.35.3
^ permalink raw reply related
* [PATCH v3 2/3] pwm: rp1: Add RP1 PWM controller driver
From: Andrea della Porta @ 2026-04-23 8:30 UTC (permalink / raw)
To: Uwe Kleine-König, linux-pwm, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Broadcom internal kernel review list, Andrea della Porta,
devicetree, linux-rpi-kernel, linux-arm-kernel, linux-kernel,
Naushir Patuck, Stanimir Varbanov, mbrugger
In-Reply-To: <cover.1776932336.git.andrea.porta@suse.com>
From: Naushir Patuck <naush@raspberrypi.com>
The Raspberry Pi RP1 southbridge features an embedded PWM
controller with 4 output channels, alongside an RPM interface
to read the fan speed on the Raspberry Pi 5.
Add the supporting driver.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Co-developed-by: Stanimir Varbanov <svarbanov@suse.de>
Signed-off-by: Stanimir Varbanov <svarbanov@suse.de>
Signed-off-by: Andrea della Porta <andrea.porta@suse.com>
---
drivers/pwm/Kconfig | 9 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-rp1.c | 414 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 424 insertions(+)
create mode 100644 drivers/pwm/pwm-rp1.c
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 6f3147518376a..32031f2af75af 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -625,6 +625,15 @@ config PWM_ROCKCHIP
Generic PWM framework driver for the PWM controller found on
Rockchip SoCs.
+config PWM_RASPBERRYPI_RP1
+ bool "RP1 PWM support"
+ depends on MISC_RP1 || COMPILE_TEST
+ depends on HAS_IOMEM
+ select REGMAP_MMIO
+ select MFD_SYSCON
+ help
+ PWM framework driver for Raspberry Pi RP1 controller.
+
config PWM_SAMSUNG
tristate "Samsung PWM support"
depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 0dc0d2b69025d..59f29f60f9123 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_PWM_RENESAS_RZG2L_GPT) += pwm-rzg2l-gpt.o
obj-$(CONFIG_PWM_RENESAS_RZ_MTU3) += pwm-rz-mtu3.o
obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o
obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
+obj-$(CONFIG_PWM_RASPBERRYPI_RP1) += pwm-rp1.o
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o
obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o
diff --git a/drivers/pwm/pwm-rp1.c b/drivers/pwm/pwm-rp1.c
new file mode 100644
index 0000000000000..15087917a18e9
--- /dev/null
+++ b/drivers/pwm/pwm-rp1.c
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * pwm-rp1.c
+ *
+ * Raspberry Pi RP1 PWM.
+ *
+ * Copyright © 2026 Raspberry Pi Ltd.
+ *
+ * Author: Naushir Patuck (naush@raspberrypi.com)
+ *
+ * Based on the pwm-bcm2835 driver by:
+ * Bart Tanghe <bart.tanghe@thomasmore.be>
+ *
+ * Datasheet: https://pip-assets.raspberrypi.com/categories/892-raspberry-pi-5/documents/RP-008370-DS-1-rp1-peripherals.pdf?disposition=inline
+ *
+ * Limitations:
+ * - Channels can be enabled/disabled through a global update flag, while the
+ * period and duty per-channel registers are independently updatable, and
+ * they are latched on the end of (specific channel) period strobe.
+ * This means that period and duty changes might result in glitches if the
+ * period/duty is changed exactly during an end of period strobe.
+ * - Since the duty/period registers are freely updatable (do not depend on
+ * the global update flag), setting one of them close to the period end and
+ * the other right afterwards results in a mixed output for that cycle because
+ * the write ops are not atomic.
+ * - The global update flag prevents mis-sampling of multi-bit bus signals in
+ * the PWM clock domain. This ensures that all PWM channel settings update
+ * on the same PWM clock cycle. Channels start in sync only if they share the
+ * same period.
+ * - If both duty and period are set to 0, the output is a constant low signal
+ * if polarity is normal or a constant high signal if polarity is inversed.
+ * - When disabled the output is driven to 0 if polarity is normal, or to 1
+ * if polarity is inversed.
+ * - Disabling the PWM stops the output immediately, without waiting for current
+ * period to complete first.
+ * - Channels are phase-capable, but on RPi5, the firmware can use a channel
+ * phase register to report the RPM of the fan connected to that PWM
+ * channel. As a result, phase control will be ignored for now.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/units.h>
+
+#define RP1_PWM_GLB_CTRL 0x000
+#define RP1_PWM_GLB_CTRL_CHANNEL_ENABLE(chan) BIT(chan)
+#define RP1_PWM_GLB_CTRL_SET_UPDATE BIT(31)
+
+#define RP1_PWM_CHAN_CTRL(chan) (0x014 + ((chan) * 0x10))
+#define RP1_PWM_CHAN_CTRL_POLARITY BIT(3)
+#define RP1_PWM_CHAN_CTRL_FIFO_POP_MASK BIT(8)
+#define RP1_PWM_CHAN_CTRL_MODE GENMASK(2, 0)
+enum rp1_pwm_ctrl_mode {
+ RP1_PWM_CHAN_CTRL_MODE_ZERO,
+ RP1_PWM_CHAN_CTRL_MODE_TE_MS,
+ RP1_PWM_CHAN_CTRL_MODE_PC_MS,
+ RP1_PWM_CHAN_CTRL_MODE_PD_ENC,
+ RP1_PWM_CHAN_CTRL_MODE_MSB_SER,
+ RP1_PWM_CHAN_CTRL_MODE_PPM,
+ RP1_PWM_CHAN_CTRL_MODE_LE_MS,
+ RP1_PWM_CHAN_CTRL_MODE_LSB_SER,
+};
+
+#define RP1_PWM_CHAN_CTRL_DEFAULT (RP1_PWM_CHAN_CTRL_FIFO_POP_MASK + \
+ FIELD_PREP(RP1_PWM_CHAN_CTRL_MODE, \
+ RP1_PWM_CHAN_CTRL_MODE_TE_MS))
+
+#define RP1_PWM_RANGE(chan) (0x018 + ((chan) * 0x10))
+#define RP1_PWM_PHASE(chan) (0x01C + ((chan) * 0x10))
+#define RP1_PWM_DUTY(chan) (0x020 + ((chan) * 0x10))
+
+#define RP1_PWM_NUM_PWMS 4
+
+struct rp1_pwm {
+ struct regmap *regmap;
+ struct clk *clk;
+ unsigned long clk_rate;
+ bool clk_enabled;
+};
+
+struct rp1_pwm_waveform {
+ u32 period_ticks;
+ u32 duty_ticks;
+ bool enabled;
+ bool inverted_polarity;
+};
+
+static const struct regmap_config rp1_pwm_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x60,
+};
+
+static void rp1_pwm_apply_config(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+ u32 value;
+
+ /* update the changed registers on the next strobe to avoid glitches */
+ regmap_read(rp1->regmap, RP1_PWM_GLB_CTRL, &value);
+ value |= RP1_PWM_GLB_CTRL_SET_UPDATE;
+ regmap_write(rp1->regmap, RP1_PWM_GLB_CTRL, value);
+}
+
+static int rp1_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+
+ /* init channel to reset defaults */
+ regmap_write(rp1->regmap, RP1_PWM_CHAN_CTRL(pwm->hwpwm), RP1_PWM_CHAN_CTRL_DEFAULT);
+ return 0;
+}
+
+static int rp1_pwm_round_waveform_tohw(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ const struct pwm_waveform *wf,
+ void *_wfhw)
+{
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+ u64 period_ticks, duty_ticks, offset_ticks;
+ struct rp1_pwm_waveform *wfhw = _wfhw;
+ u64 clk_rate = rp1->clk_rate;
+ int ret = 0;
+
+ if (!wf->period_length_ns) {
+ wfhw->enabled = false;
+ return 0;
+ }
+
+ period_ticks = mul_u64_u64_div_u64(wf->period_length_ns, clk_rate, NSEC_PER_SEC);
+
+ /*
+ * The period is limited to U32_MAX - 1
+ * to allow 100% duty cycle.
+ */
+ if (period_ticks > U32_MAX) {
+ period_ticks = U32_MAX - 1;
+ } else if (!period_ticks) {
+ period_ticks = 2;
+ ret = 1;
+ }
+
+ duty_ticks = mul_u64_u64_div_u64(wf->duty_length_ns, clk_rate, NSEC_PER_SEC);
+ offset_ticks = mul_u64_u64_div_u64(wf->duty_offset_ns, clk_rate, NSEC_PER_SEC);
+ if (duty_ticks && offset_ticks &&
+ duty_ticks + offset_ticks >= period_ticks) {
+ wfhw->duty_ticks = period_ticks - duty_ticks;
+ wfhw->inverted_polarity = true;
+ } else {
+ wfhw->duty_ticks = duty_ticks;
+ wfhw->inverted_polarity = false;
+ }
+ /* Account for the extra tick at the end of the period */
+ wfhw->period_ticks = period_ticks - 1;
+
+ wfhw->enabled = true;
+
+ return ret;
+}
+
+static int rp1_pwm_round_waveform_fromhw(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ const void *_wfhw,
+ struct pwm_waveform *wf)
+{
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+ const struct rp1_pwm_waveform *wfhw = _wfhw;
+ u64 clk_rate = rp1->clk_rate;
+ u32 ticks;
+
+ *wf = (struct pwm_waveform){ };
+
+ if (!wfhw->enabled)
+ return 0;
+
+ wf->period_length_ns = DIV_ROUND_UP_ULL((u64)(wfhw->period_ticks + 1) * NSEC_PER_SEC,
+ clk_rate);
+
+ if (!wfhw->inverted_polarity) {
+ wf->duty_length_ns = DIV_ROUND_UP_ULL((u64)wfhw->duty_ticks * NSEC_PER_SEC,
+ clk_rate);
+ } else {
+ ticks = wfhw->period_ticks + 1 - wfhw->duty_ticks;
+ wf->duty_length_ns = DIV_ROUND_UP_ULL((u64)ticks * NSEC_PER_SEC, clk_rate);
+ wf->duty_offset_ns = wf->period_length_ns - wf->duty_length_ns;
+ }
+
+ return 0;
+}
+
+static int rp1_pwm_write_waveform(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ const void *_wfhw)
+{
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+ const struct rp1_pwm_waveform *wfhw = _wfhw;
+ u32 value, ctrl;
+
+ /* early exit if disabled */
+ regmap_read(rp1->regmap, RP1_PWM_GLB_CTRL, &ctrl);
+ if (!wfhw->enabled) {
+ ctrl &= ~RP1_PWM_GLB_CTRL_CHANNEL_ENABLE(pwm->hwpwm);
+ goto exit_disable;
+ }
+
+ /* set period and duty cycle */
+ regmap_write(rp1->regmap,
+ RP1_PWM_RANGE(pwm->hwpwm), wfhw->period_ticks);
+ regmap_write(rp1->regmap,
+ RP1_PWM_DUTY(pwm->hwpwm), wfhw->duty_ticks);
+
+ /* set polarity */
+ regmap_read(rp1->regmap, RP1_PWM_CHAN_CTRL(pwm->hwpwm), &value);
+ if (!wfhw->inverted_polarity)
+ value &= ~RP1_PWM_CHAN_CTRL_POLARITY;
+ else
+ value |= RP1_PWM_CHAN_CTRL_POLARITY;
+ regmap_write(rp1->regmap, RP1_PWM_CHAN_CTRL(pwm->hwpwm), value);
+
+ /* enable the channel */
+ ctrl |= RP1_PWM_GLB_CTRL_CHANNEL_ENABLE(pwm->hwpwm);
+exit_disable:
+ regmap_write(rp1->regmap, RP1_PWM_GLB_CTRL, ctrl);
+
+ rp1_pwm_apply_config(chip, pwm);
+
+ return 0;
+}
+
+static int rp1_pwm_read_waveform(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ void *_wfhw)
+{
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+ struct rp1_pwm_waveform *wfhw = _wfhw;
+ u32 value;
+
+ regmap_read(rp1->regmap, RP1_PWM_GLB_CTRL, &value);
+ wfhw->enabled = !!(value & RP1_PWM_GLB_CTRL_CHANNEL_ENABLE(pwm->hwpwm));
+
+ regmap_read(rp1->regmap, RP1_PWM_CHAN_CTRL(pwm->hwpwm), &value);
+ wfhw->inverted_polarity = !!(value & RP1_PWM_CHAN_CTRL_POLARITY);
+
+ if (wfhw->enabled) {
+ regmap_read(rp1->regmap, RP1_PWM_RANGE(pwm->hwpwm), &wfhw->period_ticks);
+ regmap_read(rp1->regmap, RP1_PWM_DUTY(pwm->hwpwm), &wfhw->duty_ticks);
+ } else {
+ wfhw->period_ticks = 0;
+ wfhw->duty_ticks = 0;
+ }
+
+ return 0;
+}
+
+static const struct pwm_ops rp1_pwm_ops = {
+ .sizeof_wfhw = sizeof(struct rp1_pwm_waveform),
+ .request = rp1_pwm_request,
+ .round_waveform_tohw = rp1_pwm_round_waveform_tohw,
+ .round_waveform_fromhw = rp1_pwm_round_waveform_fromhw,
+ .read_waveform = rp1_pwm_read_waveform,
+ .write_waveform = rp1_pwm_write_waveform,
+};
+
+static int rp1_pwm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ unsigned long clk_rate;
+ struct pwm_chip *chip;
+ void __iomem *base;
+ struct rp1_pwm *rp1;
+ int ret;
+
+ chip = devm_pwmchip_alloc(dev, RP1_PWM_NUM_PWMS, sizeof(*rp1));
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ rp1 = pwmchip_get_drvdata(chip);
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ rp1->regmap = devm_regmap_init_mmio(dev, base, &rp1_pwm_regmap_config);
+ if (IS_ERR(rp1->regmap))
+ return dev_err_probe(dev, PTR_ERR(rp1->regmap), "Cannot initialize regmap\n");
+
+ ret = of_syscon_register_regmap(np, rp1->regmap);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register syscon\n");
+
+ rp1->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(rp1->clk))
+ return dev_err_probe(dev, PTR_ERR(rp1->clk), "Clock not found\n");
+
+ ret = clk_prepare_enable(rp1->clk);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable clock\n");
+ rp1->clk_enabled = true;
+
+ ret = devm_clk_rate_exclusive_get(dev, rp1->clk);
+ if (ret) {
+ dev_err_probe(dev, ret, "Failed to get exclusive rate\n");
+ goto err_disable_clk;
+ }
+
+ clk_rate = clk_get_rate(rp1->clk);
+ if (!clk_rate) {
+ ret = dev_err_probe(dev, -EINVAL, "Failed to get clock rate\n");
+ goto err_disable_clk;
+ }
+ /*
+ * To prevent u64 overflow in period calculations:
+ * mul_u64_u64_div_u64(period_ns, clk_rate, NSEC_PER_SEC)
+ * If clk_rate > 1 GHz, the result can overflow.
+ */
+ if (clk_rate > HZ_PER_GHZ) {
+ ret = dev_err_probe(dev, -EINVAL, "Clock rate > 1 GHz is not supported\n");
+ goto err_disable_clk;
+ }
+ rp1->clk_rate = clk_rate;
+
+ chip->ops = &rp1_pwm_ops;
+
+ platform_set_drvdata(pdev, chip);
+
+ ret = pwmchip_add(chip);
+ if (ret) {
+ dev_err_probe(dev, ret, "Failed to register PWM chip\n");
+ goto err_disable_clk;
+ }
+
+ return 0;
+
+err_disable_clk:
+ clk_disable_unprepare(rp1->clk);
+
+ return ret;
+}
+
+static void rp1_pwm_remove(struct platform_device *pdev)
+{
+ struct pwm_chip *chip = platform_get_drvdata(pdev);
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+
+ pwmchip_remove(chip);
+
+ if (rp1->clk_enabled) {
+ clk_disable_unprepare(rp1->clk);
+ rp1->clk_enabled = false;
+ }
+}
+
+static int rp1_pwm_suspend(struct device *dev)
+{
+ struct rp1_pwm *rp1 = dev_get_drvdata(dev);
+
+ if (rp1->clk_enabled) {
+ clk_disable_unprepare(rp1->clk);
+ rp1->clk_enabled = false;
+ }
+
+ return 0;
+}
+
+static int rp1_pwm_resume(struct device *dev)
+{
+ struct rp1_pwm *rp1 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(rp1->clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable clock on resume: %pe\n", ERR_PTR(ret));
+ return ret;
+ }
+
+ rp1->clk_enabled = true;
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(rp1_pwm_pm_ops, rp1_pwm_suspend, rp1_pwm_resume);
+
+static const struct of_device_id rp1_pwm_of_match[] = {
+ { .compatible = "raspberrypi,rp1-pwm" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rp1_pwm_of_match);
+
+static struct platform_driver rp1_pwm_driver = {
+ .probe = rp1_pwm_probe,
+ .remove = rp1_pwm_remove,
+ .driver = {
+ .name = "rp1-pwm",
+ .of_match_table = rp1_pwm_of_match,
+ .pm = pm_ptr(&rp1_pwm_pm_ops),
+ .suppress_bind_attrs = true,
+ },
+};
+module_platform_driver(rp1_pwm_driver);
+
+MODULE_DESCRIPTION("RP1 PWM driver");
+MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com>");
+MODULE_AUTHOR("Andrea della Porta <andrea.porta@suse.com>");
+MODULE_LICENSE("GPL");
--
2.35.3
^ permalink raw reply related
* Re: [PATCH v2] perf/arm_pmu: Skip PMCCNTR_EL0 on NVIDIA Olympus
From: James Clark @ 2026-04-23 8:29 UTC (permalink / raw)
To: Besar Wicaksono
Cc: linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org,
Thierry Reding, Jon Hunter, Vikram Sethi, Rich Wiley,
Shanker Donthineni, Matt Ochs, Nirmoy Das, Sean Kelley,
will@kernel.org, mark.rutland@arm.com
In-Reply-To: <SN7PR12MB722693E924425893F4A62D54A02D2@SN7PR12MB7226.namprd12.prod.outlook.com>
On 22/04/2026 21:17, Besar Wicaksono wrote:
>
>
>> -----Original Message-----
>> From: James Clark <james.clark@linaro.org>
>> Sent: Wednesday, April 22, 2026 5:33 AM
>> To: Besar Wicaksono <bwicaksono@nvidia.com>; will@kernel.org;
>> mark.rutland@arm.com
>> Cc: linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; linux-
>> tegra@vger.kernel.org; Thierry Reding <treding@nvidia.com>; Jon Hunter
>> <jonathanh@nvidia.com>; Vikram Sethi <vsethi@nvidia.com>; Rich Wiley
>> <rwiley@nvidia.com>; Shanker Donthineni <sdonthineni@nvidia.com>; Matt
>> Ochs <mochs@nvidia.com>; Nirmoy Das <nirmoyd@nvidia.com>; Sean Kelley
>> <skelley@nvidia.com>
>> Subject: Re: [PATCH v2] perf/arm_pmu: Skip PMCCNTR_EL0 on NVIDIA
>> Olympus
>>
>> External email: Use caution opening links or attachments
>>
>>
>> On 21/04/2026 21:38, Besar Wicaksono wrote:
>>> The PMCCNTR_EL0 in NVIDIA Olympus CPU may increment while
>>> in WFI/WFE, which does not align with counting CPU_CYCLES
>>> on a programmable counter. Add a MIDR range entry and
>>> refuse PMCCNTR_EL0 for cycle events on affected parts so
>>> perf does not mix the two behaviors.
>>>
>>> Signed-off-by: Besar Wicaksono <bwicaksono@nvidia.com>
>>> ---
>>>
>>> Changes from v1:
>>> * add CONFIG_ARM64 check to fix build error found by kernel test robot
>>> * add explicit include of <asm/cputype.h>
>>> v1: https://lore.kernel.org/linux-arm-kernel/20260406232034.2566133-1-
>> bwicaksono@nvidia.com/
>>>
>>> ---
>>> drivers/perf/arm_pmuv3.c | 44
>> ++++++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 44 insertions(+)
>>>
>>> diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c
>>> index 8014ff766cff..7c39d0804b9f 100644
>>> --- a/drivers/perf/arm_pmuv3.c
>>> +++ b/drivers/perf/arm_pmuv3.c
>>> @@ -8,6 +8,7 @@
>>> * This code is based heavily on the ARMv7 perf event code.
>>> */
>>>
>>> +#include <asm/cputype.h>
>>> #include <asm/irq_regs.h>
>>> #include <asm/perf_event.h>
>>> #include <asm/virt.h>
>>> @@ -978,6 +979,41 @@ static int armv8pmu_get_chain_idx(struct
>> pmu_hw_events *cpuc,
>>> return -EAGAIN;
>>> }
>>>
>>> +#ifdef CONFIG_ARM64
>>> +/*
>>> + * List of CPUs that should avoid using PMCCNTR_EL0.
>>> + */
>>> +static struct midr_range armv8pmu_avoid_pmccntr_cpus[] = {
>>> + /*
>>> + * The PMCCNTR_EL0 in Olympus CPU may still increment while in
>> WFI/WFE state.
>>> + * This is an implementation specific behavior and not an erratum.
>>> + *
>>> + * From ARM DDI0487 D14.4:
>>> + * It is IMPLEMENTATION SPECIFIC whether CPU_CYCLES and PMCCNTR
>> count
>>> + * when the PE is in WFI or WFE state, even if the clocks are not stopped.
>>> + *
>>> + * From ARM DDI0487 D24.5.2:
>>> + * All counters are subject to any changes in clock frequency, including
>>> + * clock stopping caused by the WFI and WFE instructions.
>>> + * This means that it is CONSTRAINED UNPREDICTABLE whether or not
>>> + * PMCCNTR_EL0 continues to increment when clocks are stopped by
>> WFI and
>>> + * WFE instructions.
>>> + */
>>> + MIDR_ALL_VERSIONS(MIDR_NVIDIA_OLYMPUS),
>>> + {}
>>> +};
>>> +
>>> +static bool armv8pmu_is_in_avoid_pmccntr_cpus(void)
>>> +{
>>> + return is_midr_in_range_list(armv8pmu_avoid_pmccntr_cpus);
>>> +}
>>> +#else
>>> +static bool armv8pmu_is_in_avoid_pmccntr_cpus(void)
>>> +{
>>> + return false;
>>> +}
>>> +#endif
>>> +
>>> static bool armv8pmu_can_use_pmccntr(struct pmu_hw_events *cpuc,
>>> struct perf_event *event)
>>> {
>>> @@ -1011,6 +1047,14 @@ static bool armv8pmu_can_use_pmccntr(struct
>> pmu_hw_events *cpuc,
>>> if (cpu_pmu->has_smt)
>>> return false;
>>>
>>> + /*
>>> + * On some CPUs, PMCCNTR_EL0 does not match the behavior of
>> CPU_CYCLES
>>> + * programmable counter, so avoid routing cycles through PMCCNTR_EL0
>> to
>>> + * prevent inconsistency in the results.
>>> + */
>>> + if (armv8pmu_is_in_avoid_pmccntr_cpus())
>>> + return false;
>>> +
>>
>> Hi Besar,
>>
>> This is called from armpmu_event_init() before the event is scheduled on
>> the CPU so I don't think reading the MIDR at this point is safe.
>>
>> When the PMU is probed you probably need to do an SMP call to get the
>> MIDR of CPUs in that PMU's mask and then cache the "avoid pmccntr"
>> result like has_smt. Or even rename has_smt to avoid_pmccntr and combine
>> the two results there.
>>
>> I don't know what will happen if none of those CPUs are online when the
>> PMU is probed though...
>>
>
> Hi James,
>
> has_smt, iiuc, is common to all the supported CPUs of the PMU context.
> It is configured based on the first CPU in supported cpu list.
>
> pmu->has_smt = topology_core_has_smt(cpumask_first(&pmu->supported_cpus));
>
> Is it okay to use same approach? Can we assume all CPUs in supported_cpus have same midr?
>
They should have the same MIDR otherwise it would be misconfigured, or
at least the PMUs should behave exactly the same way for all CPUs in the
mask. I think the whole point of separate PMUs is for heterogeneous systems.
As long as all CPUs in that mask behave the same way, then reading the
MIDR from any CPU in that mask should be ok. We do it that way for SPE
as well:
/* Make sure we probe the hardware on a relevant CPU */
ret = smp_call_function_any(mask, __arm_spe_pmu_dev_probe, spe_pmu, 1);
> Thanks,
> Besar
>
>
>
>
^ permalink raw reply
* Re: [PATCH net v2] net: dsa: mt7530: fix .get_stats64 sleeping in atomic context
From: Paolo Abeni @ 2026-04-23 8:30 UTC (permalink / raw)
To: Daniel Golle, Chester A. Unal, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Matthias Brugger,
AngeloGioacchino Del Regno, Russell King, Christian Marangi,
netdev, linux-kernel, linux-arm-kernel, linux-mediatek
Cc: Frank Wunderlich, John Crispin
In-Reply-To: <58aff8b5b1d691872342a6ffd3315f27854788a6.1776595131.git.daniel@makrotopia.org>
On 4/19/26 12:43 PM, Daniel Golle wrote:
> The .get_stats64 callback runs in atomic context, but on
> MDIO-connected switches every register read acquires the MDIO bus
> mutex, which can sleep:
> [ 12.645973] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:609
> [ 12.654442] in_atomic(): 0, irqs_disabled(): 0, non_block: 0, pid: 759, name: grep
> [ 12.663377] preempt_count: 0, expected: 0
> [ 12.667410] RCU nest depth: 1, expected: 0
> [ 12.671511] INFO: lockdep is turned off.
> [ 12.675441] CPU: 0 UID: 0 PID: 759 Comm: grep Tainted: G S W 7.0.0+ #0 PREEMPT
> [ 12.675453] Tainted: [S]=CPU_OUT_OF_SPEC, [W]=WARN
> [ 12.675456] Hardware name: Bananapi BPI-R64 (DT)
> [ 12.675459] Call trace:
> [ 12.675462] show_stack+0x14/0x1c (C)
> [ 12.675477] dump_stack_lvl+0x68/0x8c
> [ 12.675487] dump_stack+0x14/0x1c
> [ 12.675495] __might_resched+0x14c/0x220
> [ 12.675504] __might_sleep+0x44/0x80
> [ 12.675511] __mutex_lock+0x50/0xb10
> [ 12.675523] mutex_lock_nested+0x20/0x30
> [ 12.675532] mt7530_get_stats64+0x40/0x2ac
> [ 12.675542] dsa_user_get_stats64+0x2c/0x40
> [ 12.675553] dev_get_stats+0x44/0x1e0
> [ 12.675564] dev_seq_printf_stats+0x24/0xe0
> [ 12.675575] dev_seq_show+0x14/0x3c
> [ 12.675583] seq_read_iter+0x37c/0x480
> [ 12.675595] seq_read+0xd0/0xec
> [ 12.675605] proc_reg_read+0x94/0xe4
> [ 12.675615] vfs_read+0x98/0x29c
> [ 12.675625] ksys_read+0x54/0xdc
> [ 12.675633] __arm64_sys_read+0x18/0x20
> [ 12.675642] invoke_syscall.constprop.0+0x54/0xec
> [ 12.675653] do_el0_svc+0x3c/0xb4
> [ 12.675662] el0_svc+0x38/0x200
> [ 12.675670] el0t_64_sync_handler+0x98/0xdc
> [ 12.675679] el0t_64_sync+0x158/0x15c
>
> For MDIO-connected switches, poll MIB counters asynchronously using a
> delayed workqueue every second and let .get_stats64 return the cached
> values under a spinlock. A mod_delayed_work() call on each read
> triggers an immediate refresh so counters stay responsive when queried
> more frequently.
>
> MMIO-connected switches (MT7988, EN7581, AN7583) are not affected
> because their regmap does not sleep, so they continue to read MIB
> counters directly in .get_stats64.
>
> Fixes: 88c810f35ed5 ("net: dsa: mt7530: implement .get_stats64")
> Signed-off-by: Daniel Golle <daniel@makrotopia.org>
> Acked-by: Chester A. Unal <chester.a.unal@arinc9.com>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>
> ---
> v2:
> * use spin_lock_bh()/spin_unlock_bh() to prevent potential deadlock
> * rate-limit mod_delayed_work() refresh to at most once per 100ms
> * move cancel_delayed_work_sync() after dsa_unregister_switch()
> * add mt753x_teardown() callback to cancel the stats work
> * fix commit message
>
> drivers/net/dsa/mt7530.c | 66 ++++++++++++++++++++++++++++++++++++++--
> drivers/net/dsa/mt7530.h | 8 +++++
> 2 files changed, 71 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
> index b9423389c2ef0..8c1186ba2279b 100644
> --- a/drivers/net/dsa/mt7530.c
> +++ b/drivers/net/dsa/mt7530.c
> @@ -25,6 +25,9 @@
>
> #include "mt7530.h"
>
> +#define MT7530_STATS_POLL_INTERVAL (1 * HZ)
> +#define MT7530_STATS_RATE_LIMIT (HZ / 10)
> +
> static struct mt753x_pcs *pcs_to_mt753x_pcs(struct phylink_pcs *pcs)
> {
> return container_of(pcs, struct mt753x_pcs, pcs);
> @@ -906,10 +909,9 @@ static void mt7530_get_rmon_stats(struct dsa_switch *ds, int port,
> *ranges = mt7530_rmon_ranges;
> }
>
> -static void mt7530_get_stats64(struct dsa_switch *ds, int port,
> - struct rtnl_link_stats64 *storage)
> +static void mt7530_read_port_stats64(struct mt7530_priv *priv, int port,
> + struct rtnl_link_stats64 *storage)
> {
> - struct mt7530_priv *priv = ds->priv;
> uint64_t data;
>
> /* MIB counter doesn't provide a FramesTransmittedOK but instead
> @@ -951,6 +953,45 @@ static void mt7530_get_stats64(struct dsa_switch *ds, int port,
> &storage->rx_crc_errors);
> }
>
> +static void mt7530_stats_poll(struct work_struct *work)
> +{
> + struct mt7530_priv *priv = container_of(work, struct mt7530_priv,
> + stats_work.work);
> + struct rtnl_link_stats64 stats = {};
> + struct dsa_port *dp;
> + int port;
> +
> + dsa_switch_for_each_user_port(dp, priv->ds) {
> + port = dp->index;
> +
> + mt7530_read_port_stats64(priv, port, &stats);
> +
> + spin_lock_bh(&priv->stats_lock);
> + priv->ports[port].stats = stats;
> + spin_unlock_bh(&priv->stats_lock);
> + }
> +
> + priv->stats_last = jiffies;
> + schedule_delayed_work(&priv->stats_work,
> + MT7530_STATS_POLL_INTERVAL);
> +}
> +
> +static void mt7530_get_stats64(struct dsa_switch *ds, int port,
> + struct rtnl_link_stats64 *storage)
> +{
> + struct mt7530_priv *priv = ds->priv;
> +
> + if (priv->bus) {
> + spin_lock_bh(&priv->stats_lock);
> + *storage = priv->ports[port].stats;
> + spin_unlock_bh(&priv->stats_lock);
> + if (time_after(jiffies, priv->stats_last + MT7530_STATS_RATE_LIMIT))
Since both the `stats_last` access and read are lockless, it looks like
they may race leading wrong/unexpected delay. I think it would be better
move both under the spinlock (yes, the write will happen multiple times
per stats update, I don't think it will matter).
/P
^ permalink raw reply
* Re: [RFC PATCH v2 4/4] firmware: arm_ffa: check pkvm initailised when initailise ffa driver
From: Marc Zyngier @ 2026-04-23 8:34 UTC (permalink / raw)
To: Yeoreum Yun
Cc: linux-security-module, linux-kernel, linux-integrity,
linux-arm-kernel, kvmarm, paul, jmorris, serge, zohar,
roberto.sassu, dmitry.kasatkin, eric.snowberg, jarkko, jgg,
sudeep.holla, oupton, joey.gouly, suzuki.poulose, yuzenghui,
catalin.marinas, will, noodles, sebastianene
In-Reply-To: <20260422162449.1814615-5-yeoreum.yun@arm.com>
On Wed, 22 Apr 2026 17:24:49 +0100,
Yeoreum Yun <yeoreum.yun@arm.com> wrote:
>
> When pKVM is enabled, the FF-A driver must be initialized after pKVM.
> Otherwise, pKVM cannot negotiate the FF-A version or
> obtain RX/TX buffer information, leading to failures in FF-A calls.
>
> During FF-A driver initialization, check whether pKVM has been initialized.
> If pKVM isn't initailised, register notifier and do initialisation
> of FF-A driver when pKVM is initialized.
>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> arch/arm64/include/asm/virt.h | 11 ++++++++++
> arch/arm64/kvm/arm.c | 21 ++++++++++++++++++
> arch/arm64/kvm/pkvm.c | 2 ++
> drivers/firmware/arm_ffa/common.h | 4 ++--
> drivers/firmware/arm_ffa/driver.c | 36 ++++++++++++++++++++++++++++++-
> drivers/firmware/arm_ffa/smccc.c | 2 +-
> 6 files changed, 72 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
> index b51ab6840f9c..ad038a3b8727 100644
> --- a/arch/arm64/include/asm/virt.h
> +++ b/arch/arm64/include/asm/virt.h
> @@ -68,6 +68,8 @@
> #include <asm/sysreg.h>
> #include <asm/cpufeature.h>
>
> +struct notifier_block;
> +
> /*
> * __boot_cpu_mode records what mode CPUs were booted in.
> * A correctly-implemented bootloader must start all CPUs in the same mode:
> @@ -166,6 +168,15 @@ static inline bool is_hyp_nvhe(void)
> return is_hyp_mode_available() && !is_kernel_in_hyp_mode();
> }
>
> +enum kvm_arm_event {
> + PKVM_INITIALISED,
> + KVM_ARM_EVENT_MAX,
> +};
Well, no.
You are adding a whole infrastructure for something that happens
*once* in the lifetime of the system. What's next? D-Bus?
We already have a dependency mechanism, which I pointed to you last
time, and that you conveniently ignored. If that's not working for
you, then consider improving it.
If we had a whole set of in-kernel users depending on some global KVM
state change, we could look into it. But they are none, and all KVM
state changes are per-vcpu rather global.
So I'm not entertaining this invasive infrastructure for something so
limited.
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply
* [PATCH net-next v6 0/3] net: stmmac: eic7700: fix EIC7700 eth1 RX sampling timing
From: lizhi2 @ 2026-04-23 8:55 UTC (permalink / raw)
To: devicetree, andrew+netdev, davem, edumazet, kuba, robh, krzk+dt,
conor+dt, netdev, pabeni, mcoquelin.stm32, alexandre.torgue,
rmk+kernel, pjw, palmer, aou, alex, linux-riscv, linux-stm32,
linux-arm-kernel, linux-kernel, maxime.chevallier
Cc: ningyu, linmin, pinkesh.vaghela, pritesh.patel, weishangjuan,
horms, Zhi Li
From: Zhi Li <lizhi2@eswincomputing.com>
v5 -> v6:
- Update DTS/DTSI descriptions to fix invalid phandle references reported by DTC:
- Add missing GMAC provider nodes required for proper hardware description:
- HSP power domain: GMAC nodes moved under this domain to reflect
hardware power hierarchy.
- Clock nodes: added to provide clk phandles referenced by GMAC.
- Reset nodes: added to provide reset phandles referenced by GMAC.
- Pinctrl nodes: defines pinctrl settings for GMAC signals
(pinctrl_gpio106, pinctrl_gpio111).
- Move GMAC nodes under the correct HSP power domain.
- Ensure DTS builds without dtc errors and all phandle references
(clk/reset/pinctrl/power-domain) are valid.
- This update does not change runtime behavior; it only improves DTS
consistency and resolves issues reported by dtc.
- Note:
- The patch 3/3 for DTS changes in this series provide an overview of the GMAC
integration and its dependencies, as discussed previously:
https://lore.kernel.org/lkml/64bf6b40-b947-4ffa-8d48-4d6341931327@lunn.ch/
- It is **not intended for upstream inclusion** in its current form,
and is provided solely for architecture overview and integration
context.
- A fully cleaned and upstream-ready DTS series will be submitted
separately once all related components (pinctrl, clock, power-domain,
etc.) are finalized.
- dtbs_check has been run on top of net-next for reference purposes.
Remaining warnings are expected due to missing EIC7700 clock binding[1]
in net-next and do not reflect issues in the DTS design itself.
- One remaining warning:
- eswin,eic7700-clock
- The clock binding has already been applied to upstream and is present
in mainline, but not yet available in net-next.
- The syscon binding is extended in this series to include the
eswin,eic7700-syscfg compatible.
- Any further refinement of the syscfg binding will be handled in
separate patches if needed.
- Dependencies:
- [1]EIC7700 clock binding:
https://lore.kernel.org/lkml/20260303080637.2100-1-dongxuyang@eswincomputing.com/
(already applied to upstream)
- Link to v5:
https://lore.kernel.org/lkml/20260324073017.376-1-lizhi2@eswincomputing.com/
v4 -> v5:
- eswin,eic7700-eth.yaml:
- Add Acked-by from Conor Dooley
- No functional changes
- Update dwmac-eic7700.c:
- Disable clocks on the error path to fix a clock leak in
eic7700_dwmac_init() when regmap_set_bits() fails
(reported by Simon Horman <horms@kernel.org>)
- Link to v4:
https://lore.kernel.org/lkml/20260313075234.1567-1-lizhi2@eswincomputing.com/
v3 -> v4:
- Update eswin,eic7700-eth.yaml:
- Improve commit message in dt-bindings patch to clarify the
hardware difference of the eth1 MAC and why a new compatible
string is required.
- Move the newly added eswin,hsp-sp-csr item to the end of the list
to avoid inserting entries in the middle of the binding schema.
- Simplify the compatible schema by replacing the previous oneOf
construct with an enum.
- Update dwmac-eic7700.c:
- Fix build issues.
- Adjust code to match the updated binding definition.
- Update DTS/DTSI descriptions:
- Move SoC-level descriptions to the .dtsi file.
- Keep board-specific configuration in the .dts file.
- Link to v3:
https://lore.kernel.org/lkml/20260303061525.846-1-lizhi2@eswincomputing.com/
v2 -> v3:
- Update eswin,eic7700-eth.yaml:
- Extend rx-internal-delay-ps and tx-internal-delay-ps range
from 0-2400 to 0-2540 to match the full 7-bit hardware delay
field (127 * 20 ps).
- Add "multipleOf: 20" constraint to reflect the 20 ps hardware
step size.
- Make rx-internal-delay-ps and tx-internal-delay-ps optional.
A well-designed board should not require internal delay tuning.
- Remove rx-internal-delay-ps and tx-internal-delay-ps from the
example to avoid encouraging blind copy into board DTs.
- Update dwmac-eic7700.c:
- Treat rx-internal-delay-ps and tx-internal-delay-ps as optional
DT properties.
- Apply delay configuration only when properties are present.
- Keep TX/RX delay registers cleared by default to ensure a
deterministic state when no delay is specified.
- Describe Ethernet configuration for the HiFive Premier P550 board:
- Add GMAC controller nodes for the HiFive Premier P550 board
to describe the on-board Ethernet configuration.
The Ethernet controller depends on clock, reset, pinctrl
and HSP subsystem providers which are currently under
upstream review. These dependent nodes will be submitted
separately once the corresponding drivers are merged.
Due to these missing dependencies, dt-binding-check may
report warnings or failures for this series.
- No functional changes to RX clock inversion logic.
- Link to v2:
https://lore.kernel.org/lkml/20260209094628.886-1-lizhi2@eswincomputing.com/
- This series is based on the EIC7700 clock support series:
https://lore.kernel.org/all/20260210095008.726-1-dongxuyang@eswincomputing.com/
The clock series is currently under review.
v1 -> v2:
- Update eswin,eic7700-eth.yaml:
- Drop the vendor-specific properties eswin,rx-clk-invert and
eswin,tx-clk-invert.
- Introduce a distinct compatible string
"eswin,eic7700-qos-eth-clk-inversion" to describe MAC instances that
require internal RGMII clock inversion.
This models the SoC-specific hardware difference directly via the
compatible string and avoids per-board configuration properties.
- Change rx-internal-delay-ps and tx-internal-delay-ps from enum to
minimum/maximum to reflect the actual delay range (0-2400 ps)
- Add reference to High-Speed Subsystem documentation in eswin,hsp-sp-csr
description. The HSP CSR block is described in Chapter 10
("High-Speed Interface") of the EIC7700X SoC Technical Reference Manual,
Part 4 (EIC7700X_SoC_Technical_Reference_Manual_Part4.pdf):
https://github.com/eswincomputing/EIC7700X-SoC-Technical-Reference-Manual/releases
- Update dwmac-eic7700.c:
- Remove handling of eswin,rx-clk-invert and eswin,tx-clk-invert
properties.
- Select RX clock inversion based on the new
"eswin,eic7700-qos-eth-clk-inversion" compatible string, using
match data to apply the required configuration for affected MAC
instances (eth1).
- Link to v1:
https://lore.kernel.org/lkml/20260109080601.1262-1-lizhi2@eswincomputing.com/
Zhi Li (3):
dt-bindings: ethernet: eswin: add clock sampling control
net: stmmac: eic7700: enable clocks before syscon access and correct
RX sampling timing
riscv: dts: eswin: eic7700-hifive-premier-p550: enable Ethernet
controller
.../devicetree/bindings/mfd/syscon.yaml | 2 +
.../bindings/net/eswin,eic7700-eth.yaml | 69 ++++--
.../dts/eswin/eic7700-hifive-premier-p550.dts | 232 ++++++++++++++++++
arch/riscv/boot/dts/eswin/eic7700.dtsi | 103 ++++++++
.../ethernet/stmicro/stmmac/dwmac-eic7700.c | 183 ++++++++++----
5 files changed, 532 insertions(+), 57 deletions(-)
--
2.25.1
^ permalink raw reply
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