* Re: [PATCH 3/4] memory: brcmstb_dpfe: support DPFE API v4
From: Markus Mayer @ 2026-06-22 20:38 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Florian Fainelli, Rob Herring, Conor Dooley,
Linux ARM Kernel List, Device Tree Mailing List,
Linux Kernel Mailing List
In-Reply-To: <CAGt4E5tGHJFXswic6vTx-ThN2K9xBtO8oA4ybrXg+q5cA6GYCA@mail.gmail.com>
On Thu, 28 May 2026 at 14:45, Markus Mayer <mmayer@broadcom.com> wrote:
> > > Thanks for providing justification, quite reasonable. A pity that none
> > > of the commit msgs answered this way.
> >
> > The real pity is how this API was designed, making all of this
> > necessary in the first place.
> >
> > We can definitely spell out more clearly in the commit messages what
> > is going on and why all of this is needed. I'll pull all the pieces
> > together from the various responses. As long as there's a way we can
> > reasonably implement what we need, we'll be happy.
>
> It has been a minute, but we'd like to resume this effort[1] to
> upstream these changes or some variation thereof.
>
> What are the best steps to resume this undertaking? There are still a
> few topics where I am not entirely clear on how to better explain
> things or how to address the feedback provided. My apologies for that.
> I will do my best to address whatever concerns there are.
>
> Should I put together a new pull request that contains improved commit
> messages and addresses some of the feedback and we hash out whatever
> questions remain on the new thread? Or would it be better for me to
> reply to the old thread with some of the questions that remain before
> sending a revised series?
Any advice on how to best proceed from here?
Thanks,
-Markus
> [1] https://lore.kernel.org/all/20231205184741.3092376-1-mmayer@broadcom.com/
^ permalink raw reply
* Re: [PATCH 3/3] soc: samsung: exynos-pmu: fix error paths in cpuhotplug/idle states setup
From: Peter Griffin @ 2026-06-22 20:43 UTC (permalink / raw)
To: Alexey Klimov
Cc: Krzysztof Kozlowski, Alim Akhtar, Sam Protsenko,
linux-samsung-soc, linux-arm-kernel, linux-kernel, stable,
Sashiko
In-Reply-To: <DJFT3TXC0OJA.1ZK17YA2RSQXK@linaro.org>
Hi Alexey,
On Mon, 22 Jun 2026 at 19:57, Alexey Klimov <alexey.klimov@linaro.org> wrote:
[..]
> >> >
> >> > I originally made the failure non-fatal because the system still boots
> >> > without the notifiers registered (and all other Arm64 Exynos SoCs
> >> > upstream don't register notifiers and AFAICT have broken cpu hotplug
> >> > and cpu idle).
> >> >
> >> > In hindsight, that seems like a mistake. I think your patch to fully
> >> > unwind everything in case of failure makes more sense. See small
> >> > comment below about destroy_cpuhp_and_cpuidle()
> >>
> >> Wait, setup_cpuhp_and_cpuidle() should be non-fatal and shouldn't
> >> return any errors?
> >
> > I suggest you re-read my above comment above ^^
>
> Could you please clarify what specifically addresses my question about
> notifiers?
Sure, I was referring to this part of my previous reply:
> >> > In hindsight, that seems like a mistake. I think your patch to fully
> >> > unwind everything in case of failure makes more sense.
[..]
>
> If c2 idles are used during reboot/shutdown then they fail or what?
This followed similar logic to the Samsung downstream kernel drivers.
I have no extra information about it beyond the downstream kernel
source. It seemed reasonable though that CPU's will be hotplugged
during suspend and reboot so you may wish to ignore these.
The proper solution of course is a fully PSCI compliant firmware,
which doesn't require these side channel hints.
>
> I am not saying that patch is correct and some rework is needed but I don't
> get why we should completely ignore errors from hotplug states registration
> and should not check registration of notifiers. At least warning should be
> shown to user that pm functionality might be unreliable.
As mentioned above, and in my previous reply, I think your proposed
patch is a good idea.
regards,
Peter
^ permalink raw reply
* Re: [PATCH] iommu/arm-smmu-v3: Disable PRI when no priq IRQ is available
From: Nicolin Chen @ 2026-06-22 20:51 UTC (permalink / raw)
To: Breno Leitao
Cc: Will Deacon, Robin Murphy, Joerg Roedel (AMD), linux-arm-kernel,
iommu, linux-kernel, rmikey, rneu, kernel-team
In-Reply-To: <20260622-smmu_pri-v1-1-14ad92b6043f@debian.org>
On Mon, Jun 22, 2026 at 09:17:03AM -0700, Breno Leitao wrote:
> When platform firmware advertises an SMMU as PRI-capable in IDR0.PRI
> but does not assign a GSIV for its priq, arm_smmu_setup_unique_irqs()
> warns and continues. ARM_SMMU_FEAT_PRI remains set, so the driver
> still allocates the PRI queue, programs PRIQ_BASE/PROD/CONS, enables
> IRQ_CTRL_PRIQ_IRQEN, and lets IOMMU_DEV_FEAT_IOPF be advertised to
> upper layers. Page Request messages from devices land in a queue no
> one drains, and SVA binds appear to succeed while silently dropping
> every page fault.
>
> Clear ARM_SMMU_FEAT_PRI in the missing-IRQ path so every PRI-gated
> site in the driver consistently treats the SMMU as PRI-less, instead of
> the half-baked stated.
>
> Signed-off-by: Breno Leitao <leitao@debian.org>
> ---
> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index a10affb483a4f..44bafbb38e242 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -4659,7 +4659,8 @@ static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu)
> dev_warn(smmu->dev,
> "failed to enable priq irq\n");
> } else {
> - dev_warn(smmu->dev, "no priq irq - PRI will be broken\n");
> + dev_warn(smmu->dev, "no priq irq - disabling PRI\n");
> + smmu->features &= ~ARM_SMMU_FEAT_PRI;
This is covered by PATCH-7 in my PRI series:
https://lore.kernel.org/linux-iommu/cover.1779944354.git.nicolinc@nvidia.com/
FWIW, changing arm_smmu_setup_unique_irqs() alone isn't complete,
as Sashiko pointed it out:
https://sashiko.dev/#/patchset/20260622-smmu_pri-v1-1-14ad92b6043f%40debian.org
Nicolin
^ permalink raw reply
* Re: [PATCH v2 0/5] mm: reduce mmap_lock contention and improve page fault performance
From: Barry Song @ 2026-06-22 21:35 UTC (permalink / raw)
To: Liam R. Howlett
Cc: Matthew Wilcox, Suren Baghdasaryan, Lorenzo Stoakes,
David Hildenbrand (Arm), akpm, linux-mm, vbabka, rppt, mhocko,
jack, pfalcato, wanglian, chentao, lianux.mm, kunwu.chan,
liyangouwen1, chrisl, kasong, shikemeng, nphamcs, bhe,
youngjun.park, linux-arm-kernel, linux-kernel, loongarch,
linuxppc-dev, linux-riscv, linux-s390, Nanzhe Zhao, Hongru Zhang
In-Reply-To: <c5soxcu245cerfljr2ddto4h7xqksfxzxti47mq6sqn6pnmnxh@th5kxapvnaj3>
On Mon, Jun 22, 2026 at 10:50 PM Liam R. Howlett <liam@infradead.org> wrote:
>
> On 26/06/22 08:15AM, Barry Song wrote:
> > On Mon, Jun 22, 2026 at 4:49 AM Matthew Wilcox <willy@infradead.org> wrote:
> > >
> > > On Sat, Jun 20, 2026 at 04:48:57PM -0700, Suren Baghdasaryan wrote:
> > > > Just checking in on the followup plans. IIUC the RFC mentioned will
> > > > try to implement the solution we discussed at LSFMM: splitting
> > > > VM_FAULT_RETRY into two flags - one for retrying under per-VMA locks
> > > > and another one to fallback to mmap_lock.
> > >
> > > I continue to hate this idea. I don't believe that those who were
> > > pushing for it have ever tried to understand the whole fault path.
> > > It's utterly byzantine.
> > >
> > > I defy anyone to make sense of this:
> > >
> > > /*
> > > * NOTE! This will make us return with VM_FAULT_RETRY, but with
> > > * the fault lock still held. That's how FAULT_FLAG_RETRY_NOWAIT
> > > * is supposed to work. We have way too many special cases..
> > > */
> > > if (vmf->flags & FAULT_FLAG_RETRY_NOWAIT)
> > > return 0;
> > >
> > > *fpin = maybe_unlock_mmap_for_io(vmf, *fpin);
> > > if (vmf->flags & FAULT_FLAG_KILLABLE) {
> > > if (__folio_lock_killable(folio)) {
> > > /*
> > > * We didn't have the right flags to drop the
> > > * fault lock, but all fault_handlers only check
> > > * for fatal signals if we return VM_FAULT_RETRY,
> > > * so we need to drop the fault lock here and
> > > * return 0 if we don't have a fpin.
> > > */
> > > if (*fpin == NULL)
> > > release_fault_lock(vmf);
> > > return 0;
> > > }
> > >
> > > Wed need to simplify the fault path, not add additional complexity.
> > > Josef has said he wouldn't've done the lock dropping had we had per-VMA
> > > locks. We should rip it out.
> >
> > I think you have agreed that, at least for anon vma, we can
> > keep the current policy, since anon vma is much more volatile
> > than file vma.
>
> I don't think any of the above has to do with anon vmas. Does any anon
> vma handling have anything to do with your problem?
Hi Liam,
I think there may be a misunderstanding about the motivation behind
this series.
Currently, for both file-backed and anonymous VMAs, when a page fault
cannot lock the required folios—for example, because a folio is under
I/O during a major fault—the fault handler drops any locks it is
holding (either per-VMA locks or the mmap lock) and retries the fault
under the mmap_lock. This page-fault retry pattern requiring the
mmap_lock can lead to significant mmap_lock contention.
The entire purpose of this series is to avoid reacquiring the mmap_lock
where possible, while ensuring that the implementation does not
introduce new priority inversion issues or unnecessary complexity.
We have two possible approaches:
1. Keep the page-fault retry path, but retry under the per-VMA lock
whenever possible. In this case, we would need a flag to indicate
whether the retry should be performed under the per-VMA lock or the
mmap_lock.
2. Remove the page-fault retry path entirely. Instead, wait for the
folio to become lockable while retaining the locks currently held,
and continue the fault handling without retrying the page fault.
Approach 1 is the direction taken by both the current patch and the
RFC that was suggested.
Approach 2 is a potential alternative, but I have never posted an RFC
proposing it.
For Approach 1, the primary concern seems to be the added complexity.
For Approach 2, my concern is the increased risk of priority
inversion. With this approach, we may end up holding a lock while
waiting for I/O completion, potentially for a considerable amount of
time. As a result, a concurrent VMA writer, along with any subsequent
mmap_lock acquirers blocked behind it, could be stalled for an
extended period.
If there is an approach 3, it could be:
for file VMAs, we take approach 2; for anonymous VMAs, we take
approach 1.
>
> This would be needed if anon vmas were being faulted while being
> unmapped or merged? Do we really need a fast path for that? Note that
> anon vmas cannot be merged if the vma chain... you know what, I wonder
> how many people know what I'm talking about here... Let's just say that
> they can't be merged if they were around for a fork.
In terms of fork(), this is the concern I raised when considering
approach 2—holding the VMA lock while performing I/O, since a
concurrent fork would need to acquire the VMA write lock.
I had Hongru add some tracing code and run it against the top 200
Android applications in the China market. All of them are heavily
multi-threaded. Unfortunately, we found that 82 of these 200 Android
applications call fork(), and some even call fork() from multiple
threads.
So, although it may be technically a bad idea to call fork() in a
multi-threaded application, it appears that in practice it is still
widely used in real-world applications.
I guess Hongru (Cc-ed) will share his observations later today or
tomorrow.
>
> So, then, we're looking at anon vmas taking the mmap lock on:
> 1. single task anon vmas being expanded and faulted at the same time
> 2. single task anon vmas being unmapped and faulted at the same time
>
> I think that's it?
Yes and no. It could also include mprotect, UFFDIO_REGISTER,
UFFDIO_UNREGISTER, and setting VMA names, etc.
Note that Java GC may also invoke UFFDIO_REGISTER and
UFFDIO_UNREGISTER on Java heaps.
Note that priority inversion can still occur between threads that are
not operating on the same VMA if we take approach 2.
For example:
Thread A: page fault in vma1, holding the VMA lock and waiting for I/O.
Thread B: concurrent write on vma1 (takes mmap_lock and then waits for
the VMA write lock);
Thread C: concurrent write on vma2 or do VMA iteration (acquires
mmap_lock).
In this scenario, Thread C may end up indirectly waiting for Thread A.
>
> But maybe I missed something critical about your use case here?
>
> I don't understand why you are involving anon vmas in this discussion,
> so I must have missed something with your IO completion issue. Is there
> an anon vma causing your priority inversion?
As explained, the primary goal is to reduce mmap_lock contention by
avoiding taking the mmap_lock whenever possible, while ensuring that
the implementation does not introduce new priority inversion issues.
>
> > Concurrent page faults and VMA modifications can happen more
> > often than with file VMAs.
>
> But it's only a problem for anon vmas with per-vma locking if it's the
> same vma (or the vma lock sequence counter overflows, but let's say
> that's a statistically insignificant non-zero value).
>
> >
> > For file vmas, how much code can we actually remove, given that
> > the first page fault might already be holding mmap_lock?
>
> How much complexity can we remove and maintain the performance, might be
> a better question.
Right, thanks for improving the question.
>
> > It could be the case that lock_vma_under_rcu() fails, and then
> > on the first page fault we end up holding mmap_lock before
> > retrying. So are we also going to rip out the lock release,
> > even if it risks holding mmap_lock for a long time?
> >
> > vma = lock_vma_under_rcu(mm, addr);
> > if (!vma)
> > goto lock_mmap;
> > ...
> > lock_mmap:
> >
> > vma = lock_mm_and_find_vma(mm, addr, regs);
> > if (unlikely(!vma)) {
> > fault = 0;
> > si_code = SEGV_MAPERR;
> > goto bad_area;
> > }
> >
> > If we still need to keep the page fault retry code there, it
> > doesn't seem like "ripping out" really reduces complexity in
> > the page fault code?
>
> This seems unrelated to be above complexity that might be the target of
> removal?
I think it is highly related. If we take approach 2—holding locks to
perform I/O and removing the page-fault retry path—we need to
consider whether the same behavior should also apply when we are
already holding the mmap_lock. We should understand the full picture
before focusing on a specific part in isolation.
Thanks
Barry
^ permalink raw reply
* Re: [RFC PATCH v2 1/3] mm/huge_memory: make persistent huge zero folio read-only
From: Yang Shi @ 2026-06-22 22:07 UTC (permalink / raw)
To: David Hildenbrand (Arm), Xueyuan Chen
Cc: dave.hansen, akpm, linux-mm, linux-kernel, linux-arm-kernel, x86,
catalin.marinas, will, tglx, mingo, bp, dave.hansen, luto, peterz,
hpa, ljs, liam, vbabka, rppt, surenb, mhocko, ziy, baolin.wang,
npache, ryan.roberts, dev.jain, baohua, lance.yang, jannh
In-Reply-To: <f679fc68-5ff6-4715-9a07-9eb3074b2d1e@kernel.org>
On 6/19/26 4:09 AM, David Hildenbrand (Arm) wrote:
> On 6/19/26 04:55, Xueyuan Chen wrote:
>> On Thu, Jun 18, 2026 at 02:36:25PM +0200, David Hildenbrand (Arm) wrote:
>>
>> Hi, David
>>
>> [...]
>>
>>> Best to wait for some feedback.
>> Sure.
>>
>>> I do wonder whether we want to pass an address instead of a page.
>>>
>>> https://lore.kernel.org/r/20260410151746.61150-2-kalyazin@amazon.com
>>>
>>> Wants to convert existing ones as well.
>>>
>>> That would imply that the caller must check for highmem.
>>>
>>> But then, we could just use existing set_memory_ro(), right?
>>>
>> Agreed. Passing an address and reusing the existing set_memory_ro()
>> definitely makes things simpler.
>>
>> However, there is an arm64 specific limitation:
>> currently, the set_memory_r* api on arm64 only support the vmap
>> region and do not handle linear map addresses.
>>
>> If we go this route, should I extend the arm64 set_memory_r*
>> implementation in the next version? The plan would be to make it check
>> for the bblm2 feature and modify the linear map PTEs accordingly.
>> What do you think?
> Good point! It's not really clear on which ranges set_memory*() is supposed to
> work ...
>
> arm64 only works on vmalloc/vmap, x86 and riscv on ordinary directmap ... what a
> mess.
arm64 version works on vmalloc/vmap *and* the linear map alias if rodata
is on (a.k.a. full before). It should be not hard to make it work for
linear map address (w/o vmalloc/vmap alias). I think we can just follow
riscv's implementation by doing:
if (vmalloc or vmap address)
...
else if (linear map address)
...
Thanks,
Yang
>
> Having a new direct-map specific function with clear semantics might indeed
> avoid even messing with that.
>
> So, yeah, given that we have
>
> set_direct_map_invalid_noflush
> set_direct_map_default_noflush
> set_direct_map_valid_noflush
>
> Let's add a
>
> set_direct_map_ro()
>
> Or (my preference)
>
> change_direct_map_ro()
>
> But given the existing naming scheme ... maybe just set_direct_map_ro() and
> we'll clean this up another day.
>
>
> Now, should there also be a "_noflush" in there, or who is supposed to flush the
> TLB (or don't we flush at all, because it's used early during boot so far)?
>
> In any case, for this function we should add excessive documentation and define
> clear semantics.
>
^ permalink raw reply
* Re: [PATCH] remoteproc: xlnx: refactor start & stop ops
From: Shah, Tanmay @ 2026-06-22 22:29 UTC (permalink / raw)
To: Michal Simek, Tanmay Shah, andersson, mathieu.poirier
Cc: linux-arm-kernel, linux-kernel, linux-remoteproc
In-Reply-To: <4a4e518a-61e6-4beb-aaeb-5056fbe2a07a@amd.com>
Hello,
On 6/22/2026 7:25 AM, Michal Simek wrote:
>
>
> On 6/19/26 18:38, Tanmay Shah wrote:
>> Current _start and _stop ops are implemented using various APIs from the
>> platform management firmware driver. Instead provide respective RPU
>> start and stop API in the firmware driver and move the logic to interact
>> with the PM firmware in the firmware driver. The remoteproc driver
>> doesn't
>> need to know actual logic, but only the final result i.e. RPU start/stop
>> was success or not. This refactor keeps the remoteproc driver simple and
>> moves firmware interaction logic to the firmware driver.
>>
>> Signed-off-by: Tanmay Shah <tanmay.shah@amd.com>
>> ---
>> drivers/firmware/xilinx/zynqmp.c | 93 +++++++++++++++++++++++++
>> drivers/remoteproc/xlnx_r5_remoteproc.c | 68 ++----------------
>> include/linux/firmware/xlnx-zynqmp.h | 12 ++++
>> 3 files changed, 110 insertions(+), 63 deletions(-)
>>
>> diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/
>> xilinx/zynqmp.c
>> index af838b2dc327..f9a3a95b0638 100644
>> --- a/drivers/firmware/xilinx/zynqmp.c
>> +++ b/drivers/firmware/xilinx/zynqmp.c
>> @@ -1513,6 +1513,99 @@ int zynqmp_pm_request_wake(const u32 node,
>> }
>> EXPORT_SYMBOL_GPL(zynqmp_pm_request_wake);
>> +/**
>> + * zynqmp_pm_start_rpu - Boot Real-time Processing Unit (Cortex-R) on
>> SoC
>> + *
>> + * @node: power-domains id of the core
>> + * @bootaddr: Boot address of elf
>> + *
>> + * Return: status, either success or error+reason
>> + */
>> +int zynqmp_pm_start_rpu(const u32 node, const u64 bootaddr)
>> +{
>> + enum rpu_boot_mem bootmem;
>> + int ret;
>> +
>> + /*
>> + * The exception vector pointers (EVP) refer to the base-address of
>> + * exception vectors (for reset, IRQ, FIQ, etc). The reset-vector
>> + * starts at the base-address and subsequent vectors are on 4-byte
>> + * boundaries.
>> + *
>> + * Exception vectors can start either from 0x0000_0000 (LOVEC) or
>> + * from 0xFFFF_0000 (HIVEC) which is mapped in the OCM (On-Chip
>> Memory)
>
> here
>
>> + *
>> + * Usually firmware will put Exception vectors at LOVEC.
>> + *
>> + * It is not recommend that you change the exception vector.
>> + * Changing the EVP to HIVEC will result in increased interrupt
>> latency
>> + * and jitter. Also, if the OCM is secured and the Cortex-R5F
>> processor
>> + * is non-secured, then the Cortex-R5F processor cannot access the
>> + * HIVEC exception vectors in the OCM.
>> + */
>> + bootmem = (bootaddr >= 0xFFFC0000) ?
>
> and here you have different values without any explanation why.
>
The value in the comment is correct, but the check is done for all of
OCM address range. This is just refactoring of the interfaces and not
the actual logic. There is a separate patch which actually refactors the
logic, I will send it later. I would like to keep this as it is because
this was originally there, and the intent of the commit is not to modify it.
Thanks,
Tanmay
> The rest looks good to me. It is a step in a right direction.
>
> Thanks,
> Michal
>
^ permalink raw reply
* [PATCH] ARM: entry: Convert IRQ handling to generic IRQ entry
From: Linus Walleij @ 2026-06-22 22:52 UTC (permalink / raw)
To: Paul E. McKenney, Jinjie Ruan, Arnd Bergmann, Russell King,
Oleg Nesterov, Thomas Gleixner
Cc: linux-arm-kernel, linux-kernel, Linus Walleij
Bring ARM to the same level of generic-ness as ARM64 by enabling
GENERIC_IRQ_ENTRY.
Route ARM IRQ entry through C wrappers that use the generic IRQ entry
helpers. Conversely put the FIQ entry under the generic NMI-style entry
helpers.
Select GENERIC_IRQ_ENTRY, add the ARM entry prototypes, and provide
regs_irqs_disabled() for the generic IRQ entry return path.
The kernel-mode IRQ return path relies on the generic IRQ entry
preemption handling, matching the arm64 structure and avoiding the old
assembly reschedule check.
The reschedule check is now done in raw_irqentry_exit_cond_resched()
in kernel/entry/common.c.
User-mode IRQs __irq_usr is neither calling ct_user_exit/enter
or asm_trace_hardirqs_off/on anymore. The corresponding calls happen on
irqentry_enter/exit() call paths, e.g the irq-disabled C variants
__ct_user_exit/enter() are called instead.
As __irq_usr no longer returns by jumping to ret_to_user_from_irq,
the corresponding code has been inlined, except the slow_work_pending
part, which is now also handled by generic entry. ret_to_user_from_irq
is only called from v7m so it has been renamed accordingly.
arch_do_signal_or_restart() is required, but we only need a very small
stub, since we keep the existing syscall restart code around in assembly.
Tested on with multi_v7_defconfig and qemu-system-arm vexpress-a15
using vexpress-v2p-ca15-tc1.dtb and some different loads.
A note on V7M: the reason we cannot switch the V7M entry over to generic
entry is that it raises a "pendable service call" ("pendv") exception to
process deferred work at the end of the interrupt handler. This is done
so higher priority work can come in. This has no corresponding structure
in other ARM cores.
This is a reduced patch based on the earlier generic entry series avoiding
all the syscall handling changes.
Link: https://lore.kernel.org/linux-arm-kernel/20250420-arm-generic-entry-v6-0-95f1fcdfeeb2@linaro.org/
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
arch/arm/Kconfig | 1 +
arch/arm/include/asm/entry-common.h | 7 ++++
arch/arm/include/asm/entry.h | 10 +++++
arch/arm/include/asm/ptrace.h | 7 +++-
arch/arm/kernel/Makefile | 2 +-
arch/arm/kernel/entry-armv.S | 75 ++++++++-----------------------------
arch/arm/kernel/entry-common.S | 5 ++-
| 7 +++-
arch/arm/kernel/entry-v7m.S | 2 +-
arch/arm/kernel/entry.c | 51 +++++++++++++++++++++++++
arch/arm/kernel/irq.c | 6 +++
arch/arm/kernel/irq.h | 2 +
arch/arm/kernel/signal.c | 6 +++
13 files changed, 116 insertions(+), 65 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 73e6647bea46..aad21d645ff3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -71,6 +71,7 @@ config ARM
select GENERIC_CPU_AUTOPROBE
select GENERIC_CPU_DEVICES
select GENERIC_EARLY_IOREMAP
+ select GENERIC_IRQ_ENTRY if !CPU_V7M
select GENERIC_IDLE_POLL_SETUP
select GENERIC_IRQ_MULTI_HANDLER
select GENERIC_IRQ_PROBE
diff --git a/arch/arm/include/asm/entry-common.h b/arch/arm/include/asm/entry-common.h
new file mode 100644
index 000000000000..c017df5f39d5
--- /dev/null
+++ b/arch/arm/include/asm/entry-common.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_ARM_ENTRY_COMMON_H
+#define __ASM_ARM_ENTRY_COMMON_H
+
+#include <asm/stacktrace.h>
+
+#endif
diff --git a/arch/arm/include/asm/entry.h b/arch/arm/include/asm/entry.h
new file mode 100644
index 000000000000..864c9b3abbf1
--- /dev/null
+++ b/arch/arm/include/asm/entry.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_ENTRY_H__
+#define __ASM_ENTRY_H__
+
+struct pt_regs;
+
+void arm_irq_handler(struct pt_regs *regs, int mode);
+void arm_fiq_handler(struct pt_regs *regs);
+
+#endif /* __ASM_ENTRY_H__ */
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 6eb311fb2da0..88ddb9371a02 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -46,8 +46,13 @@ struct svc_pt_regs {
#define processor_mode(regs) \
((regs)->ARM_cpsr & MODE_MASK)
+static inline bool regs_irqs_disabled(const struct pt_regs *regs)
+{
+ return regs->ARM_cpsr & PSR_I_BIT;
+}
+
#define interrupts_enabled(regs) \
- (!((regs)->ARM_cpsr & PSR_I_BIT))
+ (!regs_irqs_disabled(regs))
#define fast_interrupts_enabled(regs) \
(!((regs)->ARM_cpsr & PSR_F_BIT))
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index b36cf0cfd4a7..3b8a62f6f54d 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -17,7 +17,7 @@ CFLAGS_REMOVE_return_address.o = -pg
# Object file lists.
-obj-y := elf.o entry-common.o irq.o opcodes.o \
+obj-y := elf.o entry.o entry-common.o irq.o opcodes.o \
process.o ptrace.o reboot.o io.o \
setup.o signal.o sigreturn_codes.o \
stacktrace.o sys_arm.o time.o traps.o
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index a3d050ce9b79..8ac7f1512ee8 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -36,35 +36,6 @@
#define RELOC_TEXT_NONE
#endif
-/*
- * Interrupt handling.
- */
- .macro irq_handler, from_user:req
- mov r1, sp
- ldr_this_cpu r2, irq_stack_ptr, r2, r3
- .if \from_user == 0
- @
- @ If we took the interrupt while running in the kernel, we may already
- @ be using the IRQ stack, so revert to the original value in that case.
- @
- subs r3, r2, r1 @ SP above bottom of IRQ stack?
- rsbscs r3, r3, #THREAD_SIZE @ ... and below the top?
-#ifdef CONFIG_VMAP_STACK
- ldr_va r3, high_memory, cc @ End of the linear region
- cmpcc r3, r1 @ Stack pointer was below it?
-#endif
- bcc 0f @ If not, switch to the IRQ stack
- mov r0, r1
- bl generic_handle_arch_irq
- b 1f
-0:
- .endif
-
- mov_l r0, generic_handle_arch_irq
- bl call_with_stack
-1:
- .endm
-
.macro pabt_helper
@ PABORT handler takes pt_regs in r2, fault address in r4 and psr in r5
#ifdef MULTI_PABORT
@@ -224,34 +195,17 @@ ENDPROC(__dabt_svc)
.align 5
__irq_svc:
- svc_entry
- irq_handler from_user=0
-
-#ifdef CONFIG_PREEMPTION
- ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
- ldr r0, [tsk, #TI_FLAGS] @ get flags
- teq r8, #0 @ if preempt count != 0
- movne r0, #0 @ force flags to 0
- tst r0, #_TIF_NEED_RESCHED
- blne svc_preempt
-#endif
+ svc_entry trace=0
+ mov r0, sp @ regs
+ mov r1, #0 @ from kernel mode
+ bl arm_irq_handler
- svc_exit r5, irq = 1 @ return from exception
+ svc_exit r5, irqentry = 1 @ return from exception
UNWIND(.fnend )
ENDPROC(__irq_svc)
.ltorg
-#ifdef CONFIG_PREEMPTION
-svc_preempt:
- mov r8, lr
-1: bl preempt_schedule_irq @ irq en/disable is done inside
- ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS
- tst r0, #_TIF_NEED_RESCHED
- reteq r8 @ go again
- b 1b
-#endif
-
__und_fault:
@ Correct the PC such that it is pointing at the instruction
@ which caused the fault. If the faulting instruction was ARM
@@ -302,7 +256,7 @@ ENDPROC(__pabt_svc)
__fiq_svc:
svc_entry trace=0
mov r0, sp @ struct pt_regs *regs
- bl handle_fiq_as_nmi
+ bl arm_fiq_handler
svc_exit_via_fiq
UNWIND(.fnend )
ENDPROC(__fiq_svc)
@@ -331,7 +285,7 @@ __fiq_abt:
stmfd sp!, {r1 - r2}
add r0, sp, #8 @ struct pt_regs *regs
- bl handle_fiq_as_nmi
+ bl arm_fiq_handler
ldmfd sp!, {r1 - r2}
ARM( msr cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
@@ -438,12 +392,15 @@ ENDPROC(__dabt_usr)
.align 5
__irq_usr:
- usr_entry
+ usr_entry trace=0
kuser_cmpxchg_check
- irq_handler from_user=1
- get_thread_info tsk
- mov why, #0
- b ret_to_user_from_irq
+ mov r0, sp @ regs
+ mov r1, #1 @ from user mode
+ bl arm_irq_handler
+#ifdef CONFIG_KSTACK_ERASE
+ bl stackleak_erase_on_task_stack
+#endif
+ restore_user_regs fast = 0, offset = 0
UNWIND(.fnend )
ENDPROC(__irq_usr)
@@ -498,7 +455,7 @@ __fiq_usr:
usr_entry trace=0
kuser_cmpxchg_check
mov r0, sp @ struct pt_regs *regs
- bl handle_fiq_as_nmi
+ bl arm_fiq_handler
get_thread_info tsk
restore_user_regs fast = 0, offset = 0
UNWIND(.fnend )
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 88336a1292bb..d5fdb234c1d4 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -110,7 +110,8 @@ ret_slow_syscall:
bl do_rseq_syscall
#endif
disable_irq_notrace @ disable interrupts
-ENTRY(ret_to_user_from_irq)
+ENTRY(v7m_ret_to_user_from_irq)
+ /* Only the v7m jumps directly to v7m_ret_to_user_from_irq */
ldr r1, [tsk, #TI_FLAGS]
movs r1, r1, lsl #16
bne slow_work_pending
@@ -123,7 +124,7 @@ no_work_pending:
bl stackleak_erase_on_task_stack
#endif
restore_user_regs fast = 0, offset = 0
-ENDPROC(ret_to_user_from_irq)
+ENDPROC(v7m_ret_to_user_from_irq)
ENDPROC(ret_to_user)
/*
--git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 99411fa91350..e83f2fb8a592 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -199,7 +199,11 @@
.endm
- .macro svc_exit, rpsr, irq = 0
+ .macro svc_exit, rpsr, irq = 0, irqentry = 0
+ .if \irqentry != 0
+ @ Generic IRQ entry already handled tracing and lockdep state.
+ disable_irq_notrace
+ .else
.if \irq != 0
@ IRQs already off
#ifdef CONFIG_TRACE_IRQFLAGS
@@ -216,6 +220,7 @@
tst \rpsr, #PSR_I_BIT
blne trace_hardirqs_off
#endif
+ .endif
.endif
uaccess_exit tsk, r0, r1
diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
index 52bacf07ba16..49a3a34e2913 100644
--- a/arch/arm/kernel/entry-v7m.S
+++ b/arch/arm/kernel/entry-v7m.S
@@ -94,7 +94,7 @@ __pendsv_entry:
@ execute the pending work, including reschedule
get_thread_info tsk
mov why, #0
- b ret_to_user_from_irq
+ b v7m_ret_to_user_from_irq
ENDPROC(__pendsv_entry)
/*
diff --git a/arch/arm/kernel/entry.c b/arch/arm/kernel/entry.c
new file mode 100644
index 000000000000..1142e418d161
--- /dev/null
+++ b/arch/arm/kernel/entry.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/hardirq.h>
+#include <linux/irq-entry-common.h>
+#include <linux/irq.h>
+
+#include <asm/entry.h>
+#include <asm/stacktrace.h>
+#include <asm/traps.h>
+
+#include "irq.h"
+
+static void noinstr handle_arm_irq(void *data)
+{
+ struct pt_regs *regs = data;
+ struct pt_regs *old_regs;
+
+ irq_enter_rcu();
+ old_regs = set_irq_regs(regs);
+
+ handle_arch_irq(regs);
+
+ set_irq_regs(old_regs);
+ irq_exit_rcu();
+}
+
+noinstr void arm_irq_handler(struct pt_regs *regs, int mode)
+{
+ irqentry_state_t state = irqentry_enter(regs);
+
+ /*
+ * mode == 1 means we came from userspace, and then we
+ * should just immediately switch to the irq stack.
+ * Then we check of we are on the thread stack. If we are
+ * not, then by definition we are already using the irq stack.
+ */
+ if (mode == 1 || on_thread_stack())
+ call_on_irq_stack(handle_arm_irq, regs);
+ else
+ handle_arm_irq(regs);
+
+ irqentry_exit(regs, state);
+}
+
+noinstr void arm_fiq_handler(struct pt_regs *regs)
+{
+ irqentry_state_t state = irqentry_nmi_enter(regs);
+
+ handle_fiq_as_nmi(regs);
+
+ irqentry_nmi_exit(regs, state);
+}
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index e1993e28a9ec..f99d6b24d8ff 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -43,6 +43,7 @@
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
+#include "irq.h"
#include "reboot.h"
unsigned long irq_err_count;
@@ -71,6 +72,11 @@ static void __init init_irq_stacks(void)
}
}
+void call_on_irq_stack(void (*fn)(void *), void *arg)
+{
+ call_with_stack(fn, arg, __this_cpu_read(irq_stack_ptr));
+}
+
#ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
static void ____do_softirq(void *arg)
{
diff --git a/arch/arm/kernel/irq.h b/arch/arm/kernel/irq.h
new file mode 100644
index 000000000000..80dd5bfe6403
--- /dev/null
+++ b/arch/arm/kernel/irq.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+void call_on_irq_stack(void (*fn)(void *), void *arg);
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 7be9188d83d9..9084c04c07f7 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -12,6 +12,7 @@
#include <linux/resume_user_mode.h>
#include <linux/uprobes.h>
#include <linux/syscalls.h>
+#include <linux/irq-entry-common.h>
#include <asm/elf.h>
#include <asm/cacheflush.h>
@@ -599,6 +600,11 @@ static int do_signal(struct pt_regs *regs, int syscall)
return 0;
}
+void arch_do_signal_or_restart(struct pt_regs *regs)
+{
+ do_signal(regs, 0);
+}
+
asmlinkage int
do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
{
---
base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
change-id: 20260622-arm-generic-irq-entry-v7-1-ff6c1d6c9c48
Best regards,
--
Linus Walleij <linusw@kernel.org>
^ permalink raw reply related
* Re: [PATCH 0/2] KVM: arm64: Fix and test MMIO sign-extending loads
From: Oliver Upton @ 2026-06-23 0:20 UTC (permalink / raw)
To: Fuad Tabba
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Steffen Eiden, Catalin Marinas, Will Deacon, Shuah Khan,
Christoffer Dall, Victor Kamensky, linux-arm-kernel, kvmarm,
linux-kernel
In-Reply-To: <20260622190701.2039766-1-fuad.tabba@linux.dev>
On Mon, Jun 22, 2026 at 08:06:59PM +0100, Fuad Tabba wrote:
> Hi folks,
>
> A sign-extending load (LDRSB/LDRSH/LDRSW) from emulated MMIO returns a
> zero-extended value rather than the sign-extended one the architecture
> requires; vcpu_data_host_to_guest() strips the sign bits when it masks
> the data to the access width.
>
> If my git archeology is right, the masking dates to 2014 (b30070862edbd,
> big-endian support) and has been wrong ever since, but sign-extending
> loads from device memory are rare enough that nobody hit it. Patch 1
> fixes it; patch 2 adds a selftest so it doesn't regress.
>
> Cheers,
> /fuad
>
> Fuad Tabba (2):
> KVM: arm64: Fix sign-extension of MMIO loads
> KVM: arm64: selftests: Add MMIO sign-extending load test
For the oddball guest :)
Reviewed-by: Oliver Upton <oupton@kernel.org>
Thanks,
Oliver
^ permalink raw reply
* Re: [PATCH net v2] net: ethernet: ti: icssg: guard PA stat lookups
From: patchwork-bot+netdevbpf @ 2026-06-23 0:40 UTC (permalink / raw)
To: Philippe Schenker
Cc: netdev, philippe.schenker, horms, danishanwar, rogerq,
linux-arm-kernel, stable, andrew+netdev, devnexen, davem,
edumazet, jacob.e.keller, kuba, haokexin, m-malladi, pabeni,
vadim.fedorenko, linux-kernel
In-Reply-To: <20260618093037.3448858-1-dev@pschenker.ch>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Thu, 18 Jun 2026 11:30:24 +0200 you wrote:
> From: Philippe Schenker <philippe.schenker@impulsing.ch>
>
> icssg_ndo_get_stats64() unconditionally calls emac_get_stat_by_name()
> with FW PA stat names regardless of whether the PA stats block is
> present on the hardware. emac_get_stat_by_name() already guards the
> PA stats lookup with `if (emac->prueth->pa_stats)`; when that pointer
> is NULL the lookup falls through to netdev_err() and returns -EINVAL.
> Because ndo_get_stats64 is polled regularly by the networking stack
> this produces thousands of log entries of the form:
>
> [...]
Here is the summary with links:
- [net,v2] net: ethernet: ti: icssg: guard PA stat lookups
https://git.kernel.org/netdev/net/c/27b9daba5060
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH 5/8] iommu/arm-smmu-qcom: Add SM8450 MDSS compatible
From: Esteban Urrutia via B4 Relay @ 2026-06-23 0:54 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Rob Clark, Will Deacon, Robin Murphy, Joerg Roedel (AMD),
Vinod Koul, Neil Armstrong
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy, Esteban Urrutia
In-Reply-To: <20260622-sm8450-qol-v1-0-37e2ee8df9da@proton.me>
From: Esteban Urrutia <esteuwu@proton.me>
Add the compatible for the MDSS client on the Snapdragon 8 Gen 1 so it
can be properly configured by the IOMMU driver.
Otherwise, there is an unhandled context fault.
Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
---
drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
index e2c914fccd6f..795e8ec7e8fa 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
@@ -425,6 +425,7 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = {
{ .compatible = "qcom,sm6375-mdss" },
{ .compatible = "qcom,sm8150-mdss" },
{ .compatible = "qcom,sm8250-mdss" },
+ { .compatible = "qcom,sm8450-mdss" },
{ .compatible = "qcom,x1e80100-mdss" },
{ }
};
--
2.54.0
^ permalink raw reply related
* [PATCH 3/8] arm64: dts: qcom: sm8450: Modify GPU operating points
From: Esteban Urrutia via B4 Relay @ 2026-06-23 0:54 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Rob Clark, Will Deacon, Robin Murphy, Joerg Roedel (AMD),
Vinod Koul, Neil Armstrong
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy, Esteban Urrutia
In-Reply-To: <20260622-sm8450-qol-v1-0-37e2ee8df9da@proton.me>
From: Esteban Urrutia <esteuwu@proton.me>
These frecuencies don't exist in downstream device trees.
Both 220MHz and 285MHz belong to SM8475, and I'm not sure where 317MHz
came from.
Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
---
arch/arm64/boot/dts/qcom/sm8450.dtsi | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi
index e34e3c05bf74..5e331a25e22a 100644
--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi
@@ -2495,21 +2495,6 @@ opp-350000000 {
opp-hz = /bits/ 64 <350000000>;
opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>;
};
-
- opp-317000000 {
- opp-hz = /bits/ 64 <317000000>;
- opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS>;
- };
-
- opp-285000000 {
- opp-hz = /bits/ 64 <285000000>;
- opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS_D1>;
- };
-
- opp-220000000 {
- opp-hz = /bits/ 64 <220000000>;
- opp-level = <RPMH_REGULATOR_LEVEL_LOW_SVS_D1>;
- };
};
};
--
2.54.0
^ permalink raw reply related
* [PATCH 8/8] arm64: defconfig: Add SM8450 camcc
From: Esteban Urrutia via B4 Relay @ 2026-06-23 0:54 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Rob Clark, Will Deacon, Robin Murphy, Joerg Roedel (AMD),
Vinod Koul, Neil Armstrong
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy, Esteban Urrutia
In-Reply-To: <20260622-sm8450-qol-v1-0-37e2ee8df9da@proton.me>
From: Esteban Urrutia <esteuwu@proton.me>
Add SM8450 camcc as a module since it's enabled in SM8450 dtsi.
Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
---
arch/arm64/configs/defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index f2e6ae93e533..8c50c16ee0b8 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1541,6 +1541,7 @@ CONFIG_SDX_GCC_75=y
CONFIG_SM_CAMCC_6350=m
CONFIG_SM_CAMCC_MILOS=m
CONFIG_SM_CAMCC_8250=m
+CONFIG_SM_CAMCC_8450=m
CONFIG_SM_CAMCC_8550=m
CONFIG_SM_CAMCC_8650=m
CONFIG_SM_CAMCC_8750=m
--
2.54.0
^ permalink raw reply related
* [PATCH 6/8] phy: qcom: qmp-combo: Drop qmp_v4_calibrate_dp_phy
From: Esteban Urrutia via B4 Relay @ 2026-06-23 0:54 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Rob Clark, Will Deacon, Robin Murphy, Joerg Roedel (AMD),
Vinod Koul, Neil Armstrong
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy, Esteban Urrutia
In-Reply-To: <20260622-sm8450-qol-v1-0-37e2ee8df9da@proton.me>
From: Esteban Urrutia <esteuwu@proton.me>
There are no downstream device trees that specify five values in the
qcom,aux-cfg1-settings array.
Plus, after cross referencing both downstream device trees and entries
which refer this function, only 0x13 is specified.
Since 0x13 is written at initialization time, drop this function as a
whole, and remove now unused variable assignations.
Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
---
drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 31 -------------------------------
1 file changed, 31 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index cdcfad2e86b1..9bd666ac2c49 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -2325,7 +2325,6 @@ static int qmp_v3_calibrate_dp_phy(struct qmp_combo *qmp);
static void qmp_v4_dp_aux_init(struct qmp_combo *qmp);
static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp);
static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp);
-static int qmp_v4_calibrate_dp_phy(struct qmp_combo *qmp);
static void qmp_v8_dp_aux_init(struct qmp_combo *qmp);
static int qmp_v8_configure_dp_clocks(struct qmp_combo *qmp);
@@ -2466,7 +2465,6 @@ static const struct qmp_phy_cfg sar2130p_usb3dpphy_cfg = {
.configure_dp_tx = qmp_v4_configure_dp_tx,
.configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
- .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
.regs = qmp_v6_usb3phy_regs_layout,
.reset_list = msm8996_usb3phy_reset_l,
@@ -2603,7 +2601,6 @@ static const struct qmp_phy_cfg sc8180x_usb3dpphy_cfg = {
.configure_dp_tx = qmp_v4_configure_dp_tx,
.configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
- .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
.reset_list = msm8996_usb3phy_reset_l,
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
@@ -2650,7 +2647,6 @@ static const struct qmp_phy_cfg sc8280xp_usb43dpphy_cfg = {
.configure_dp_tx = qmp_v4_configure_dp_tx,
.configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
- .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
.reset_list = msm8996_usb3phy_reset_l,
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
@@ -2696,7 +2692,6 @@ static const struct qmp_phy_cfg x1e80100_usb3dpphy_cfg = {
.configure_dp_tx = qmp_v4_configure_dp_tx,
.configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
- .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
.reset_list = msm8996_usb3phy_reset_l,
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
@@ -2785,7 +2780,6 @@ static const struct qmp_phy_cfg sm8250_usb3dpphy_cfg = {
.configure_dp_tx = qmp_v4_configure_dp_tx,
.configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
- .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
.reset_list = msm8996_usb3phy_reset_l,
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
@@ -2834,7 +2828,6 @@ static const struct qmp_phy_cfg sm8350_usb3dpphy_cfg = {
.configure_dp_tx = qmp_v4_configure_dp_tx,
.configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
- .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
.reset_list = msm8996_usb3phy_reset_l,
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
@@ -2882,7 +2875,6 @@ static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = {
.configure_dp_tx = qmp_v4_configure_dp_tx,
.configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
- .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
.regs = qmp_v6_usb3phy_regs_layout,
.reset_list = msm8996_usb3phy_reset_l,
@@ -2928,7 +2920,6 @@ static const struct qmp_phy_cfg sm8650_usb3dpphy_cfg = {
.configure_dp_tx = qmp_v4_configure_dp_tx,
.configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
- .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
.regs = qmp_v6_usb3phy_regs_layout,
.reset_list = msm8996_usb3phy_reset_l,
@@ -2974,7 +2965,6 @@ static const struct qmp_phy_cfg sm8750_usb3dpphy_cfg = {
.configure_dp_tx = qmp_v4_configure_dp_tx,
.configure_dp_clocks = qmp_v3_configure_dp_clocks,
.configure_dp_phy = qmp_v4_configure_dp_phy,
- .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
.regs = qmp_v8_usb3phy_regs_layout,
.reset_list = msm8996_usb3phy_reset_l,
@@ -3020,7 +3010,6 @@ static const struct qmp_phy_cfg glymur_usb3dpphy_cfg = {
.configure_dp_tx = qmp_v4_configure_dp_tx,
.configure_dp_clocks = qmp_v8_configure_dp_clocks,
.configure_dp_phy = qmp_v8_configure_dp_phy,
- .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
.regs = qmp_v8_n3_usb43dpphy_regs_layout,
.reset_list = msm8996_usb3phy_reset_l,
@@ -3316,7 +3305,6 @@ static void qmp_v4_dp_aux_init(struct qmp_combo *qmp)
writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG7);
writel(0xb7, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG8);
writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG9);
- qmp->dp_aux_cfg = 0;
writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK |
PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK |
@@ -3345,7 +3333,6 @@ static void qmp_v8_dp_aux_init(struct qmp_combo *qmp)
writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG7);
writel(0xb7, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG8);
writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG9);
- qmp->dp_aux_cfg = 0;
writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK |
PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK |
@@ -3605,24 +3592,6 @@ static int qmp_v8_configure_dp_phy(struct qmp_combo *qmp)
return 0;
}
-/*
- * We need to calibrate the aux setting here as many times
- * as the caller tries
- */
-static int qmp_v4_calibrate_dp_phy(struct qmp_combo *qmp)
-{
- static const u8 cfg1_settings[] = { 0x20, 0x13, 0x23, 0x1d };
- u8 val;
-
- qmp->dp_aux_cfg++;
- qmp->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
- val = cfg1_settings[qmp->dp_aux_cfg];
-
- writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1);
-
- return 0;
-}
-
static int qmp_combo_dp_configure(struct phy *phy, union phy_configure_opts *opts)
{
const struct phy_configure_opts_dp *dp_opts = &opts->dp;
--
2.54.0
^ permalink raw reply related
* [PATCH 4/8] arm64: dts: qcom: sm8450: Add missing PCM_OUT port
From: Esteban Urrutia via B4 Relay @ 2026-06-23 0:54 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Rob Clark, Will Deacon, Robin Murphy, Joerg Roedel (AMD),
Vinod Koul, Neil Armstrong
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy, Esteban Urrutia
In-Reply-To: <20260622-sm8450-qol-v1-0-37e2ee8df9da@proton.me>
From: Esteban Urrutia <esteuwu@proton.me>
An error in dmesg shows there is a mismatch between controller and DT
dout-ports.
Add PCM_OUT port to fix this.
Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
---
arch/arm64/boot/dts/qcom/sm8450.dtsi | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi
index 5e331a25e22a..8fc58a02e5c5 100644
--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi
@@ -2914,20 +2914,20 @@ swr1: soundwire@3210000 {
clock-names = "iface";
label = "RX";
qcom,din-ports = <0>;
- qcom,dout-ports = <5>;
+ qcom,dout-ports = <6>;
pinctrl-0 = <&rx_swr_active>;
pinctrl-names = "default";
- qcom,ports-sinterval-low = /bits/ 8 <0x03 0x1f 0x1f 0x07 0x00>;
- qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x0b 0x01 0x00>;
- qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x0b 0x00 0x00>;
- qcom,ports-hstart = /bits/ 8 <0xff 0x03 0xff 0xff 0xff>;
- qcom,ports-hstop = /bits/ 8 <0xff 0x06 0xff 0xff 0xff>;
- qcom,ports-word-length = /bits/ 8 <0x01 0x07 0x04 0xff 0xff>;
- qcom,ports-block-pack-mode = /bits/ 8 <0xff 0x00 0x01 0xff 0xff>;
- qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff 0x00>;
- qcom,ports-lane-control = /bits/ 8 <0x01 0x00 0x00 0x00 0x00>;
+ qcom,ports-sinterval = /bits/ 16 <0x03 0x3f 0x1f 0x07 0x00 0x18f>;
+ qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x0b 0x01 0x00 0x00>;
+ qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x0b 0x00 0x00 0x00>;
+ qcom,ports-hstart = /bits/ 8 <0xff 0x03 0xff 0xff 0xff 0x08>;
+ qcom,ports-hstop = /bits/ 8 <0xff 0x06 0xff 0xff 0xff 0x08>;
+ qcom,ports-word-length = /bits/ 8 <0x01 0x07 0x04 0xff 0xff 0x0f>;
+ qcom,ports-block-pack-mode = /bits/ 8 <0xff 0x00 0x01 0xff 0xff 0x00>;
+ qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff 0x00 0x00>;
+ qcom,ports-lane-control = /bits/ 8 <0x01 0x00 0x00 0x00 0x00 0x00>;
#address-cells = <2>;
#size-cells = <0>;
--
2.54.0
^ permalink raw reply related
* [PATCH 1/8] clk: qcom: dispcc-sm8450: Fix mdss clocks
From: Esteban Urrutia via B4 Relay @ 2026-06-23 0:54 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Rob Clark, Will Deacon, Robin Murphy, Joerg Roedel (AMD),
Vinod Koul, Neil Armstrong
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy, Esteban Urrutia
In-Reply-To: <20260622-sm8450-qol-v1-0-37e2ee8df9da@proton.me>
From: Esteban Urrutia <esteuwu@proton.me>
Both of these changes allow the framebuffer to show upon boot and let
the mdss driver take over afterwards.
Before, none of these actions were possible. Only mdss takeover was
possible, but screen had to be turned off first.
OLE configuration may have been a misinterpretation... that's not
something that's done on the downstream driver.
Changing disp_cc_mdss_mdp_clk_src from clk_rcg2_shared_ops to
clk_rcg2_shared_no_init_park_ops fixes this warning as well:
[ 0.075780] ------------[ cut here ]------------
[ 0.075791] disp_cc_mdss_mdp_clk_src: rcg didn't update its configuration.
[ 0.075812] WARNING: drivers/clk/qcom/clk-rcg2.c:136 at update_config+0xd4/0xe4, CPU#3: swapper/0/1
[ 0.075840] Modules linked in:
[ 0.075856] CPU: 3 UID: 0 PID: 1 Comm: swapper/0 Tainted: G S 7.1.0-rc2+ #320 PREEMPT
[ 0.075870] Tainted: [S]=CPU_OUT_OF_SPEC
[ 0.075877] Hardware name: Motorola ThinkPhone by motorola (DT)
[ 0.075887] pstate: 61400005 (nZCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
[ 0.075897] pc : update_config+0xd4/0xe4
[ 0.075906] lr : update_config+0xd4/0xe4
[ 0.075914] sp : ffff80008005b9f0
[ 0.075921] x29: ffff80008005ba00 x28: 0000000000000004 x27: ffff000782892200
[ 0.075937] x26: ffff0007823a46c0 x25: 0000000000000004 x24: ffffffffffffffff
[ 0.075953] x23: ffff0007823a0240 x22: ffffdbc0a0940220 x21: ffffdbc0a0940220
[ 0.075967] x20: ffffdbc0a0dcb388 x19: 0000000000000000 x18: 0000000000000048
[ 0.075981] x17: 0000000000000014 x16: 0000000000010008 x15: fffffffffffea870
[ 0.075996] x14: ffffdbc0a0c5d580 x13: ffffdbc0a0c5d600 x12: 00000000000001ee
[ 0.076010] x11: fffffffffffea870 x10: fffffffffffea828 x9 : ffffdbc0a0c5d600
[ 0.076024] x8 : 3fffffffffffefff x7 : ffffdbc0a0cb5600 x6 : 00000000000001ef
[ 0.076038] x5 : 3ffffffffffff1ee x4 : 00000000000001ee x3 : 0000000000000000
[ 0.076052] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff00078066adc0
[ 0.076067] Call trace:
[ 0.076074] update_config+0xd4/0xe4 (P)
[ 0.076085] clk_rcg2_shared_disable+0x50/0x80
[ 0.076096] clk_rcg2_shared_init+0x10/0x20
[ 0.076107] __clk_register+0x1b4/0x9ec
[ 0.076118] devm_clk_hw_register+0x5c/0xd4
[ 0.076128] devm_clk_register_regmap+0x44/0x84
[ 0.076139] qcom_cc_really_probe+0x304/0x514
[ 0.076149] disp_cc_sm8450_probe+0x104/0x200
[ 0.076160] platform_probe+0x5c/0xa4
[ 0.076172] really_probe+0xbc/0x2ac
[ 0.076182] __driver_probe_device+0x80/0x154
[ 0.076193] driver_probe_device+0x3c/0x184
[ 0.076203] __driver_attach+0x90/0x18c
[ 0.076213] bus_for_each_dev+0x7c/0xdc
[ 0.076224] driver_attach+0x24/0x30
[ 0.076233] bus_add_driver+0xe4/0x20c
[ 0.076243] driver_register+0x68/0x130
[ 0.076251] __platform_driver_register+0x20/0x2c
[ 0.076260] disp_cc_sm8450_driver_init+0x1c/0x28
[ 0.076273] do_one_initcall+0x60/0x1d4
[ 0.076287] kernel_init_freeable+0x24c/0x2d4
[ 0.076299] kernel_init+0x24/0x140
[ 0.076311] ret_from_fork+0x10/0x20
[ 0.076323] ---[ end trace 0000000000000000 ]---
Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
---
drivers/clk/qcom/dispcc-sm8450.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c
index 2e91332dd92a..b99d3eb5e195 100644
--- a/drivers/clk/qcom/dispcc-sm8450.c
+++ b/drivers/clk/qcom/dispcc-sm8450.c
@@ -614,7 +614,7 @@ static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = {
.parent_data = disp_cc_parent_data_5,
.num_parents = ARRAY_SIZE(disp_cc_parent_data_5),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_shared_ops,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
},
};
@@ -1824,8 +1824,8 @@ static int disp_cc_sm8450_probe(struct platform_device *pdev)
disp_cc_pll1.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE];
disp_cc_pll1.clkr.hw.init = &sm8475_disp_cc_pll1_init;
- clk_lucid_ole_pll_configure(&disp_cc_pll0, regmap, &sm8475_disp_cc_pll0_config);
- clk_lucid_ole_pll_configure(&disp_cc_pll1, regmap, &sm8475_disp_cc_pll1_config);
+ clk_lucid_evo_pll_configure(&disp_cc_pll0, regmap, &sm8475_disp_cc_pll0_config);
+ clk_lucid_evo_pll_configure(&disp_cc_pll1, regmap, &sm8475_disp_cc_pll1_config);
} else {
clk_lucid_evo_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config);
clk_lucid_evo_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config);
--
2.54.0
^ permalink raw reply related
* [PATCH 0/8] SM8450 QoL changes
From: Esteban Urrutia via B4 Relay @ 2026-06-23 0:54 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Rob Clark, Will Deacon, Robin Murphy, Joerg Roedel (AMD),
Vinod Koul, Neil Armstrong
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy, Esteban Urrutia
Hello. This is my first attempt at contributing to the Linux kernel.
I've been mainlining an SM8475 based device for quite some time now and
I feel now's the proper time to start submitting patches.
I'm starting with the smallest part which are mostly modifications
regarding the current support for the SM8450 SoC.
Regards,
Esteban
Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
---
Esteban Urrutia (8):
clk: qcom: dispcc-sm8450: Fix mdss clocks
arm64: dts: qcom: sm8450: Remove unneeded reserved memory nodes
arm64: dts: qcom: sm8450: Modify GPU operating points
arm64: dts: qcom: sm8450: Add missing PCM_OUT port
iommu/arm-smmu-qcom: Add SM8450 MDSS compatible
phy: qcom: qmp-combo: Drop qmp_v4_calibrate_dp_phy
phy: qcom: qmp-combo: Correct pre-emphasis table for QMP v4 DP PHYs
arm64: defconfig: Add SM8450 camcc
arch/arm64/boot/dts/qcom/sm8450.dtsi | 50 ++++++------------------------
arch/arm64/configs/defconfig | 1 +
drivers/clk/qcom/dispcc-sm8450.c | 6 ++--
drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 1 +
drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 33 +-------------------
5 files changed, 16 insertions(+), 75 deletions(-)
---
base-commit: 948efecf22e49aa4bf55bb73ec79a0ddcfd38571
change-id: 20260622-sm8450-qol-466b8c07eb5f
Best regards,
--
Esteban Urrutia <esteuwu@proton.me>
^ permalink raw reply
* [PATCH 7/8] phy: qcom: qmp-combo: Correct pre-emphasis table for QMP v4 DP PHYs
From: Esteban Urrutia via B4 Relay @ 2026-06-23 0:54 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Rob Clark, Will Deacon, Robin Murphy, Joerg Roedel (AMD),
Vinod Koul, Neil Armstrong
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy, Esteban Urrutia
In-Reply-To: <20260622-sm8450-qol-v1-0-37e2ee8df9da@proton.me>
From: Esteban Urrutia <esteuwu@proton.me>
Comparing sm8350 and sm8450 tables, this seems to be typo.
Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
---
drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index 9bd666ac2c49..5b278fd54a16 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -2108,7 +2108,7 @@ static const u8 qmp_dp_v4_pre_emphasis_hbr3_hbr2[4][4] = {
static const u8 qmp_dp_v4_pre_emphasis_hbr_rbr[4][4] = {
{ 0x00, 0x0d, 0x14, 0x1a },
{ 0x00, 0x0e, 0x15, 0xff },
- { 0x00, 0x0d, 0xff, 0xff },
+ { 0x00, 0x0e, 0xff, 0xff },
{ 0x03, 0xff, 0xff, 0xff }
};
--
2.54.0
^ permalink raw reply related
* [PATCH 2/8] arm64: dts: qcom: sm8450: Remove unneeded reserved memory nodes
From: Esteban Urrutia via B4 Relay @ 2026-06-23 0:54 UTC (permalink / raw)
To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Rob Clark, Will Deacon, Robin Murphy, Joerg Roedel (AMD),
Vinod Koul, Neil Armstrong
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy, Esteban Urrutia
In-Reply-To: <20260622-sm8450-qol-v1-0-37e2ee8df9da@proton.me>
From: Esteban Urrutia <esteuwu@proton.me>
These nodes are not present on downstream device trees and only take
memory away from the AP.
No crashes occur without these nodes, so remove them.
Signed-off-by: Esteban Urrutia <esteuwu@proton.me>
---
arch/arm64/boot/dts/qcom/sm8450.dtsi | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi
index 56cb6e959e4e..e34e3c05bf74 100644
--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi
@@ -752,11 +752,6 @@ oem_vm_mem: memory@bb000000 {
no-map;
};
- mte_mem: memory@c0000000 {
- reg = <0x0 0xc0000000 0x0 0x20000000>;
- no-map;
- };
-
qheebsp_reserved_mem: memory@e0000000 {
reg = <0x0 0xe0000000 0x0 0x600000>;
no-map;
@@ -806,16 +801,6 @@ qtee_mem: memory@e9b00000 {
reg = <0x0 0xe9b00000 0x0 0x500000>;
no-map;
};
-
- trusted_apps_mem: memory@ea000000 {
- reg = <0x0 0xea000000 0x0 0x3900000>;
- no-map;
- };
-
- trusted_apps_ext_mem: memory@ed900000 {
- reg = <0x0 0xed900000 0x0 0x3b00000>;
- no-map;
- };
};
smp2p-adsp {
--
2.54.0
^ permalink raw reply related
* [linusw-nomadik:b4/ux500-power-domains-v7-1] BUILD SUCCESS 5c7e86c0a0a94d9f688526aea7499aa552102968
From: kernel test robot @ 2026-06-23 1:07 UTC (permalink / raw)
To: Linus Walleij; +Cc: linux-arm-kernel
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git b4/ux500-power-domains-v7-1
branch HEAD: 5c7e86c0a0a94d9f688526aea7499aa552102968 ARM: dts: ux500: Remove DB8500 EPOD regulators
elapsed time: 1338m
configs tested: 173
configs skipped: 4
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-16.1.0
alpha allyesconfig gcc-16.1.0
alpha defconfig gcc-16.1.0
arc allmodconfig clang-23
arc allmodconfig gcc-16.1.0
arc allnoconfig gcc-16.1.0
arc allyesconfig clang-23
arc allyesconfig gcc-16.1.0
arc defconfig gcc-16.1.0
arc randconfig-001-20260622 gcc-8.5.0
arc randconfig-002-20260622 gcc-8.5.0
arm allnoconfig gcc-16.1.0
arm allyesconfig clang-23
arm allyesconfig gcc-16.1.0
arm defconfig gcc-16.1.0
arm randconfig-001-20260622 gcc-8.5.0
arm randconfig-002-20260622 gcc-8.5.0
arm randconfig-003-20260622 gcc-8.5.0
arm randconfig-004-20260622 gcc-8.5.0
arm64 allmodconfig clang-23
arm64 allnoconfig gcc-16.1.0
arm64 defconfig gcc-16.1.0
arm64 randconfig-001-20260622 gcc-8.5.0
arm64 randconfig-002-20260622 gcc-8.5.0
arm64 randconfig-003-20260622 gcc-8.5.0
arm64 randconfig-004-20260622 gcc-8.5.0
csky allmodconfig gcc-16.1.0
csky allnoconfig gcc-16.1.0
csky defconfig gcc-16.1.0
csky randconfig-001-20260622 gcc-8.5.0
csky randconfig-002-20260622 gcc-8.5.0
hexagon allmodconfig gcc-16.1.0
hexagon allnoconfig gcc-16.1.0
hexagon defconfig gcc-16.1.0
hexagon randconfig-001-20260622 gcc-8.5.0
hexagon randconfig-002-20260622 gcc-8.5.0
i386 allmodconfig clang-22
i386 allmodconfig gcc-14
i386 allnoconfig gcc-16.1.0
i386 allyesconfig clang-22
i386 allyesconfig gcc-14
i386 buildonly-randconfig-001-20260622 gcc-14
i386 buildonly-randconfig-002-20260622 gcc-14
i386 buildonly-randconfig-003-20260622 gcc-14
i386 buildonly-randconfig-004-20260622 gcc-14
i386 buildonly-randconfig-005-20260622 gcc-14
i386 buildonly-randconfig-006-20260622 gcc-14
i386 defconfig gcc-16.1.0
i386 randconfig-001-20260622 clang-22
i386 randconfig-002-20260622 clang-22
i386 randconfig-003-20260622 clang-22
i386 randconfig-004-20260622 clang-22
i386 randconfig-005-20260622 clang-22
i386 randconfig-006-20260622 clang-22
i386 randconfig-007-20260622 clang-22
i386 randconfig-011-20260622 gcc-14
i386 randconfig-012-20260622 gcc-14
i386 randconfig-013-20260622 gcc-14
i386 randconfig-014-20260622 gcc-14
i386 randconfig-015-20260622 gcc-14
i386 randconfig-016-20260622 gcc-14
i386 randconfig-017-20260622 gcc-14
loongarch allmodconfig clang-19
loongarch allmodconfig clang-23
loongarch allnoconfig gcc-16.1.0
loongarch defconfig clang-23
loongarch randconfig-001-20260622 gcc-8.5.0
loongarch randconfig-002-20260622 gcc-8.5.0
m68k allmodconfig gcc-16.1.0
m68k allnoconfig gcc-16.1.0
m68k allyesconfig clang-23
m68k allyesconfig gcc-16.1.0
m68k defconfig clang-23
m68k m5249evb_defconfig gcc-16.1.0
microblaze allnoconfig gcc-16.1.0
microblaze allyesconfig gcc-16.1.0
microblaze defconfig clang-23
mips allmodconfig gcc-16.1.0
mips allnoconfig gcc-16.1.0
mips allyesconfig gcc-16.1.0
nios2 allmodconfig clang-20
nios2 allnoconfig clang-23
nios2 defconfig clang-23
nios2 randconfig-001-20260622 gcc-8.5.0
nios2 randconfig-002-20260622 gcc-8.5.0
openrisc allmodconfig clang-20
openrisc allnoconfig clang-23
openrisc defconfig gcc-16.1.0
parisc allmodconfig gcc-16.1.0
parisc allnoconfig clang-23
parisc allyesconfig clang-17
parisc allyesconfig gcc-16.1.0
parisc defconfig gcc-16.1.0
parisc randconfig-001-20260622 gcc-14.3.0
parisc randconfig-002-20260622 gcc-14.3.0
parisc64 defconfig clang-23
powerpc akebono_defconfig clang-23
powerpc allmodconfig gcc-16.1.0
powerpc allnoconfig clang-23
powerpc randconfig-001-20260622 gcc-14.3.0
powerpc randconfig-002-20260622 gcc-14.3.0
powerpc64 randconfig-001-20260622 gcc-14.3.0
powerpc64 randconfig-002-20260622 gcc-14.3.0
riscv allmodconfig clang-23
riscv allnoconfig clang-23
riscv allyesconfig clang-23
riscv defconfig gcc-16.1.0
riscv randconfig-001-20260622 clang-17
s390 allmodconfig clang-17
s390 allmodconfig clang-23
s390 allnoconfig clang-23
s390 allyesconfig gcc-16.1.0
s390 defconfig gcc-16.1.0
s390 randconfig-001-20260622 clang-17
s390 randconfig-002-20260622 clang-17
sh allmodconfig gcc-16.1.0
sh allnoconfig clang-23
sh allyesconfig clang-17
sh allyesconfig gcc-16.1.0
sh randconfig-001-20260622 clang-17
sh randconfig-002-20260622 clang-17
sparc allnoconfig clang-23
sparc defconfig gcc-16.1.0
sparc randconfig-001-20260622 gcc-16.1.0
sparc randconfig-002-20260622 gcc-16.1.0
sparc64 allmodconfig clang-20
sparc64 randconfig-001-20260622 gcc-16.1.0
sparc64 randconfig-002-20260622 gcc-16.1.0
um allmodconfig clang-17
um allmodconfig clang-23
um allnoconfig clang-23
um allyesconfig gcc-16.1.0
um randconfig-001-20260622 gcc-16.1.0
um randconfig-002-20260622 gcc-16.1.0
x86_64 allmodconfig clang-22
x86_64 allnoconfig clang-23
x86_64 allyesconfig clang-22
x86_64 buildonly-randconfig-001-20260622 clang-22
x86_64 buildonly-randconfig-002-20260622 clang-22
x86_64 buildonly-randconfig-003-20260622 clang-22
x86_64 buildonly-randconfig-004-20260622 clang-22
x86_64 buildonly-randconfig-005-20260622 clang-22
x86_64 buildonly-randconfig-006-20260622 clang-22
x86_64 kexec clang-22
x86_64 randconfig-001-20260622 clang-22
x86_64 randconfig-002-20260622 clang-22
x86_64 randconfig-003-20260622 clang-22
x86_64 randconfig-004-20260622 clang-22
x86_64 randconfig-005-20260622 clang-22
x86_64 randconfig-006-20260622 clang-22
x86_64 randconfig-011-20260622 clang-22
x86_64 randconfig-012-20260622 clang-22
x86_64 randconfig-013-20260622 clang-22
x86_64 randconfig-014-20260622 clang-22
x86_64 randconfig-015-20260622 clang-22
x86_64 randconfig-016-20260622 clang-22
x86_64 randconfig-071-20260623 gcc-14
x86_64 randconfig-072-20260623 gcc-14
x86_64 randconfig-073-20260623 gcc-14
x86_64 randconfig-074-20260623 gcc-14
x86_64 randconfig-075-20260623 gcc-14
x86_64 randconfig-076-20260623 gcc-14
x86_64 rhel-9.4 clang-22
x86_64 rhel-9.4-bpf gcc-14
x86_64 rhel-9.4-func clang-22
x86_64 rhel-9.4-kselftests clang-22
x86_64 rhel-9.4-kunit gcc-14
x86_64 rhel-9.4-ltp gcc-14
x86_64 rhel-9.4-rust clang-22
xtensa allnoconfig clang-23
xtensa allyesconfig clang-20
xtensa randconfig-001-20260622 gcc-16.1.0
xtensa randconfig-002-20260622 gcc-16.1.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [PATCH v33 0/5] Add ASPEED AST2600 I2C controller driver
From: Ryan Chen @ 2026-06-23 1:15 UTC (permalink / raw)
To: jk, andriy.shevchenko, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
Benjamin Herrenschmidt, Rayn Chen, Philipp Zabel
Cc: linux-i2c, devicetree, linux-arm-kernel, linux-aspeed,
linux-kernel, openbmc, Ryan Chen, Conor Dooley
This series adds support for the AST2600 I2C controller “new register
set” implementation.
The AST2600 I2C controller introduces a revised register layout which
separates controller and target functionality into distinct register
blocks, and extends clock divider configuration and packet-based
transfer support compared to the legacy mixed register layout used on
earlier ASPEED SoCs.
The current driver implementation for the AST2600 I2C peripheral is
through the hardware's "compatibility mode", which exposes a register
set that matches the previous generation hardware (AST2500 and earlier).
Instead, add a driver that works in new-register-set mode, to allow the
new features, and will provide support for future hardware that will
not implement compatibility mode.
In order to support the new mode, we need a DT binding change to
reflect the reference to the global register set. Since the binding
still represents the same (AST2600 SoC) physical hardware, we continue
to use the existing compatible string of "aspeed,ast2600-i2c-bus".
However: since we're changing semantics for an existing binding, we
allow backwards compatibility by selecting on presence/absence of the
newly-added properties, and fall back to the old driver (ie., in
compatibility mode) when we detect a DT using the old binding spec.
Specifically:
- ast2600-i2c-bus nodes that provide the `aspeed,global-regs` property
(present in the new binding and absent in the legacy binding) will be
successfully probed by the new driver
- ast2600-i2c-bus nodes without `aspeed,global-regs` continue to use the
existing driver (in legacy register mode), ensuring that platforms
with the current DTBs remain functional
Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
---
Changes in v33:
- 4/5: Fix missing NAK on the last byte of an intermediate read
message: set RX_CMD_LAST on the final chunk of every read message
and append STOP_CMD only when it is also the last message of the
transfer.
- Link to v32: https://lore.kernel.org/r/20260611-upstream_i2c-v32-0-b66eba921d01@aspeedtech.com
Changes in v32:
- 1/5: add MAINTAINERS entry for aspeed,ast2600-i2c.yaml in the same
patch that creates the file.
- 3/5: add if/then conditional schema: when aspeed,global-regs is
present, require reg to have at least two items. The new driver
unconditionally maps resource index 1 (the buffer SRAM region); a DT
with one reg entry and aspeed,global-regs passes schema validation but
fails probe. The constraint makes the schema consistent with driver
behaviour.
- 4/5: address follow-on code review issues:
- add MAINTAINERS entry for drivers/i2c/busses/i2c-ast2600.c.
- fix interrupt storm when msgs is NULL: clear PKT_DONE in the IRQ
handler; per the datasheet this auto-clears all associated status
bits.
- fix out-of-bounds: guard msgs_index against msgs_count before
indexing msgs array in ast2600_i2c_controller_packet_irq().
- fix use-after-free: WRITE_ONCE() null msgs before complete() in
all IRQ completion paths so trailing IRQs bail out immediately.
- fix race in timeout path: null msgs before re-enabling IER so a
late IRQ cannot access the caller's freed message buffer.
- fix 0-length SMBus block read hanging the bus: issue STOP via
CONTROLLER_TRIGGER_LAST_STOP, set stop_pending, poll for NORMAL_STOP.
- initialise clk_div_reg to I2CCG_DIV_CTRL and global_ctrl to 0
to avoid uninitialized values if regmap_read() fails.
- guard against clock-frequency = <0> in DT; default to 100 kHz
to prevent divide-by-zero in ast2600_i2c_ac_timing_config().
- remove AST2600_I2CM_BUS_RECOVER_FAIL from IER writes; bit 15 is
Reserved in I2CM10 (IER) and only exists as a status bit in I2CM14.
- 5/5: address follow-on code review issues:
- fix target RX data loss in master-abort path: remove BUFF_CTRL
zeroing that discarded pending target RX data stored in bits [29:24].
- fix use-after-free in master-abort path: null msgs and re-enable
IER before complete(), not after, preventing stale IRQ from touching
the newly-installed msgs of the next transfer.
- fix shared-buffer corruption on coalesced STOP+SLAVE_MATCH IRQ:
restore the SLAVE_PENDING guard on target_active = false. SLAVE_PENDING
(bit 29) is set when a new address-match is queued before the previous
DMA receive completes; clearing target_active in that case allows the
controller to overwrite the shared Tx/Rx buffer.
- use READ_ONCE() for all process-context reads of target_active;
the IRQ path writes it with WRITE_ONCE() and plain loads allow the
compiler to cache a stale value across the IER-disable window.
- Link to v31: https://lore.kernel.org/r/20260603-upstream_i2c-v31-0-ba7a02714f22@aspeedtech.com
Changes in v31:
- 1/5: clarify in the commit message that the second reg region is
optional (minItems: 1), matching the schema change from v30.
- 2/5: zero-initialise struct i2c_timings so the bus-frequency fallback
correctly triggers when clock-frequency is absent in the DT.
- 4/5: fix zero-length RX: ast2600_i2c_setup_buff_rx() now returns
-EINVAL for xfer_len <= 0, propagated through the controller packet
IRQ handler to abort the transfer instead of hanging until SW timeout.
- 4/5: address follow-on code review issues:
- Guard controller_packet_irq() against NULL msgs (post-timeout UAF).
- Clamp HW-reported xfer_len via ast2600_i2c_clamp_len() in TX_ACK
and RX_DONE to prevent out-of-bounds writes on HW length glitches.
- Use regmap_update_bits() for I2CG_CTRL to avoid clobbering shared
global bits across parallel bus probes (TOCTOU fix).
- Fix SMBus block read with recv_len == 0: set controller_xfer_cnt =
msg->len to satisfy the "msg done" check without an extra 1-byte RX.
- Mirror the controller timeout sequence in recover_bus() timeout path
(disable IER, synchronize_irq(), W1C ISR, reset master, restore IER).
- Remove unused #include <linux/of_device.h>.
- Remove dead adap.algo_data assignment in probe().
- 5/5: address follow-on target-mode code review issues:
- Clear target_active on any STOP (not just STOP without SLAVE_PENDING),
fixing a deadlock under coalesced IRQ events.
- Enable target IER in reg_target() rather than unconditionally in
probe(), matching the disable in unreg_target().
- Re-arm HW in SLAVE_PENDING|RX_DONE|WAIT_TX_DMA|STOP ISR case
(missing CMD_STS write left bus SCL-stretched until INACTIVE_TO).
- Default target ISR case: write TARGET_TRIGGER_CMD instead of
silently breaking, preventing bus hang on unhandled states.
- W1C-clear ADDR1/2/3_NAK bits in HW in target_irq() to prevent
stale NAK bits from bouncing controller transfers with -EBUSY.
- unreg_target(): write 0 to ADDR_CTRL instead of masking with
ADDR1_MASK, which left ADDR1_ENABLE (BIT(7)) set after unregister.
- Link to v30: https://lore.kernel.org/r/20260528-upstream_i2c-v30-0-5d4f9adc3530@aspeedtech.com
Changes in v30:
- 1/5: aspeed,ast2600-i2c.yaml: keep backward compatibility for
existing in-tree AST2600 device trees (Sashiko AI review).
- reg: add minItems: 1 so legacy single-reg DTs still validate.
- retain bus-frequency as a deprecated property so DTs that still
use it are not rejected by unevaluatedProperties: false.
- 2/5: new patch "i2c: aspeed: Read clock-frequency via
i2c_parse_fw_timings()". The legacy i2c-aspeed driver now reads
the standard clock-frequency property first and falls back to
bus-frequency, avoiding a silent 100 kHz downgrade when a DT
follows the updated binding but still binds to the legacy
driver (Sashiko AI review).
- 4/5: address Sashiko AI code review feedback:
- Use manual i2c_add_adapter() / i2c_del_adapter() instead of
devm_i2c_add_adapter() so the adapter is torn down before the
hardware is disabled in remove(); otherwise client .remove()
callbacks can fail or hang after FUN_CTRL/IER have been cleared.
- synchronize_irq() and clear pending IRQ status on the controller
timeout path to avoid the ISR racing with the next transfer and
touching freed msgs.
- Use clamp_t() for AC TIMING divisor / scl_low / scl_high so
extreme clock-frequency values cannot underflow into the unsigned
domain and corrupt the AC TIMING register.
- Derive the RX buffer offset from buf_size instead of hardcoding
0x10, since the dual-pool split is configurable.
- Clamp i2c-scl-clk-low-timeout-us to the TTIMEOUT field's 5-bit
range (max 31 * 1024us) and emit a dev_warn() instead of letting
AST2600_I2CC_TTIMEOUT()'s mask silently truncate larger values.
- Return -EBUSY (not -ENOMEM) for every ast2600_i2c_do_start()
failure path in the controller packet IRQ handler (NORMAL_STOP,
TX_ACK, and RX_DONE branches).
- Advertise I2C_AQ_NO_ZERO_LEN_READ via i2c_adapter_quirks so the
i2c-core rejects zero-byte reads before they reach the driver.
The AST2600 packet engine cannot encode a zero-length RX command
and would otherwise stall waiting for an RX_DONE that never
arrives.
- 5/5: address Sashiko AI code review feedback:
- Force-stop path (target IRQ aborting an in-flight controller
transfer): disable the controller IER and W1C-clear pending ISR
before calling complete(), then restore the IER after the
wake-up. Without the disable/clear sequence the controller IRQ
handler can race with the target abort path and double-complete
or touch freed msgs.
- unreg_target() teardown ordering: disable the target IER first,
then disable SLAVE_EN / clear ADDR_CTRL, synchronize_irq(), W1C
pending ISR, and only then NULL i2c_bus->target and clear
target_active. The old order left IER enabled while target was
being cleared, allowing an in-flight handler to dereference a
target pointer the caller had already freed.
- reg_target() bring-up ordering: assign i2c_bus->target before
enabling SLAVE_EN. Otherwise an IRQ that fires after SLAVE_EN
is set but before the pointer is stored finds target == NULL,
exits without clearing the ISR, and the unmasked event re-fires
as an IRQ storm.
- Use writel() instead of writeb() when staging a TX byte into
the target buffer. The AST2600 buffer SRAM only supports 32-bit
accesses; byte writes are silently dropped (or, on some
revisions, raise a bus fault), so a SLAVE_READ_REQUESTED reply
never reaches the master.
- reg_target() rejects 10-bit client addresses with
-EAFNOSUPPORT. AST2600_I2CS_ADDR1 is only a 7-bit field;
without the check, the high bits of a 10-bit address overflow
into the adjacent ADDR2 field and silently corrupt a second
target slot.
- Initialise the local `u8 value` to 0 in the target packet IRQ
handler. Its address is passed to i2c_slave_event() for events
such as I2C_SLAVE_STOP / I2C_SLAVE_READ_REQUESTED; a slave
backend that reads the byte before writing would otherwise leak
uninitialised kernel stack.
- Link to v29: https://lore.kernel.org/r/20260415-upstream_i2c-v29-0-317c1a905ae1@aspeedtech.com
Changes in v29:
- 2/4: remove aspeed,enable-dma properties.
- 3/4: update commit message remove transfer mode selection.
- 3/4: remove sysfs file.
- 3/4: remove define I2C_TARGET_MSG_BUF_SIZE and AST2600_I2C_DMA_SIZE.
- 3/4: remove buf_index in struct ast2600_i2c_bus.
- 3/4, 4/4: remove dma/byte mode, use buffer mode only.
- 4/4: fix race between unreg_target and IRQ handler.
- 4/4: move i2cs ier enable from ast2600_i2c_init to probe after master ier enable.
- Link to v28: https://lore.kernel.org/r/20260330-upstream_i2c-v28-0-17bdae39c5cb@aspeedtech.com
Changes in v28:
- 2/4: update commit message correspond with aspeed,enable-dma.
- 2/4: remove aspeed,transfer-mode and add aspeed,enable-dma property
and description.
- 2/4: Fix aspeed,enable-dma description to reflect hardware capability
rather than software behavior.
- 3/4: Separate xfer_mode_store into distinct parse and availability-check
steps by introducing ast2600_i2c_xfer_mode_check().
- 3/4: fix tx dma memcpy source point address.
- 3/4: Use a temporary variable for devm_platform_get_and_ioremap_resource()
to avoid storing an ERR_PTR in i2c_bus->buf_base; drop the redundant
NULL assignment in the error path since i2c_bus is kzalloc()ed.
- 3/4: Add ABI documentation file
Documentation/ABI/testing/sysfs-driver-ast2600-i2c.
- 4/4: fix typo condication -> condition.
- 4/4: fix compile error, when disable CONFIG_I2C_SLAVE.
- Link to v27: https://lore.kernel.org/r/20260324-upstream_i2c-v27-0-f19b511c8c28@aspeedtech.com
Changes in v27:
- 1/4 use aspeed,enable-dma instead aspeed,transfer-mode.
- 2/4 remove aspeed,transfer-mode selection instad aspeed,transfer-mode
- 2/4 add sysfs for xfer mode.
- Link to v26: https://lore.kernel.org/r/20260309-upstream_i2c-v26-0-5fedcff8ffe8@aspeedtech.com
Changes in v26:
- 1/4: binding reworks based on review feedback
- Link to v25: https://lore.kernel.org/r/20260225-upstream_i2c-v25-0-9f4bdd954f3f@aspeedtech.com
Changes in v25:
- Use b4 to send series.
- Rebase on v7.0-rc1.
- Clarify cover letter and commit logs based on review feedback.
- Remove the i2c-aspeed-core multiplexer infrastructure and
implement driver selection via conditional -ENODEV handling
in individual probe() functions.
- 3/4: incorporate review feedback and refactor new driver
- Link to v24: https://lore.kernel.org/r/20251118014034.820988-1-ryan_chen@aspeedtech.com
Changes in v24:
- aspeed,ast2600-i2c.yaml
- fix make dt_binding_check blank warning.
- Link to v23: https://lore.kernel.org/all/20251117025040.3622984-1-ryan_chen@aspeedtech.com/
Changes in v23:
- update typo patch (1/4) commit message.
- aspeed,ast2600-i2c.yaml
- update reg and description.
- i2c-ast2600.c controller
- replace ast2600_select_i2c_clock to ast2600_i2c_ac_timing_config.
- i2c-ast2600.c target
- I2C_TARGET_MSG_BUF_SIZE 256 to 4096
- remove blank line.
- refine Master comment description to controller
- Link to v22: https://lore.kernel.org/all/20251112085649.1903631-1-ryan_chen@aspeedtech.com/
Changes in v22:
- update patch (1/4) commit message add dts example reason.
- aspeed,ast2600-i2c.yaml @patch (1/4)
- rename ast2600-i2c.yaml to aspeed,ast2600-i2c.yaml.
- update reg, clock-frequency description.
- aspeed,ast2600-i2c.yaml @patch (2/4)
- aspeed,transfer-mode, aspeed,transfer-mode add for ast2600.
- i2c-aspeed-core.c,h @patch (3/4)
- add i2c-aspeed-core allow both old and new device trees using the
same compatible string "aspeed,ast2600-i2c-bus".
- Link to v21: https://lore.kernel.org/all/20251027061240.3427875-1-ryan_chen@aspeedtech.com/
Changes in v21:
- update patch (1/4) commit message
- i2c-ast2600.c
- move rst to local variable in ast2600_i2c_probe().
- Link to v20: https://lore.kernel.org/all/20251021013548.2375190-1-ryan_chen@aspeedtech.com/
Changes in v20:
- ast2600-i2c.yaml
- fix warning at make dt_binding_check.
- Link to v19: https://lore.kernel.org/all/20251020013200.1858325-1-ryan_chen@aspeedtech.com/
Changes in v19:
- Split AST2600 binding into its own YAML file
- Removed `aspeed,ast2600-i2c-bus` from `aspeed,i2c.yaml`
- Added `aspeed,global-regs` and `aspeed,transfer-mode` to AST2600 binding
- Link to v18: https://lore.kernel.org/all/20250820051832.3605405-1-ryan_chen@aspeedtech.com/
Changes in v18:
- refine patch (1/3) commit message (reason for commit not list.)
- i2c-ast2600.c
- remove redundant reset_control_deassert in driver probe.
- remove reset_control_assert(i2c_bus->rst) in driver remove.
- Link to v17: https://lore.kernel.org/all/20250814084156.1650432-1-ryan_chen@aspeedtech.com/
Changes in v17:
- move i2c new mode register and feature into driver commit message.
- aspeed,i2c.yaml
- remove multi-master properties.
- use aspeed,transfer-mode properties for aspeed,enable-byte/enable-dma.
-i2c-ast2600.c
- rename dma_safe_buf to controller_dma_safe_buf.
- fix ast2600_i2c_recover_bus return overflow warnings.
- add ast2600_i2c_target_packet_buff_irq unhandle case.
- add parameter "cmd" in ast2600_i2c_setup_dma_rx,
ast2600_i2c_setup_buff_rx, ast2600_i2c_setup_byte_rx
- use reset_control_deassert replace
devm_reset_control_get_shared_deasserted.
- useaspeed,transfer-mode properties for transfer mode setting.
- change compatible = "aspeed,ast2600-i2cv2" to "aspeed,ast2600-i2c-bus".
- Link to v16: https://lore.kernel.org/all/20250224055936.1804279-1-ryan_chen@aspeedtech.com/
Changes in v16:
- aspeed,i2c.yaml: add aspeed,enable-byte properties for force byte mode.
- i2c-ast2600.c
- change include asm/unaligned.h to linux/unaligned.h.
- add reset timeout councter when slave active timeout.
- modify issue i2c_recovery_bus before slave re-enable.
- add aspeed,enable-byte properties.
- Link to v15: https://lore.kernel.org/all/20241007035235.2254138-1-ryan_chen@aspeedtech.com/
Changes in v15:
- i2c-ast2600.c
- add include unaligned.h
- rename all master -> controller, slave -> target.
- keep multi-master to align property.
- remove no used element in ast2600_i2c_bus.
- Link to v14: https://lore.kernel.org/all/20241002070213.1165263-1-ryan_chen@aspeedtech.com/
Changes in v14:
- aspeed,i2c.yaml
- v13 change people reviewed-by tag, v14 fixed to original people tag,
modify to Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
- struct ast2600_i2c_bus layout optimal.
- ast2600_select_i2c_clock refine.
- ast2600_i2c_recover_bus overridden fix.
- dma_mapping_error() returned error code shadowed modify.
- buffer register in a 4-byte aligned simplified
- remove smbus alert
- Link to v13: https://lore.kernel.org/all/20240819092850.1590758-1-ryan_chen@aspeedtech.com/
Changes in v13:
- separate i2c master and slave driver to be two patchs.
- modify include header list, add bits.h include. remove of*.h
- modify (((x) >> 24) & GENMASK(5, 0)) to (((x) & GENMASK(29, 24)) >> 24)
- modify ast2600_select_i2c_clock function implement.
- modify ast2600_i2c_recover_bus function u32 claim to
u32 state = readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF);
- Link to v12: https://lore.kernel.org/all/20230714074522.23827-1-ryan_chen@aspeedtech.com/
Changes in v12:
- aspeed,i2c.yaml
- add Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
- i2c-ast2600.c
- update include by alphabetical order
- make just a one TAB and put the last two lines on the single one
- remove no used timing_table structre
- remove enum explicit assinment
- rewritten to avoid this and using loop in ast2600_select_i2c_clock
- use GENMASK for most 0xffff
- remove too many parentheses
- use str_read_write replace read write string
- remove redundant blank line after ast2600_i2c_bus_of_table
- fix wrong multi-line style of the comment
- use macro for i2c standard speeds
- remove useless noise dev_info
- Link to v11: https://lore.kernel.org/all/20230430041712.3247998-1-ryan_chen@aspeedtech.com/
Changes in v11:
- aspeed,i2c.yaml
- no change, the same with v10.
- i2c-ast2600.c
- modify alert_enable from int -> boolean.
- modify dbg string recovery -> recover.
- remove no need to init 0.
- remove new line after break.
- remove unneeded empty line.
- modify dma_alloc_coherent to dmam_alloc_coherent
- modify probe nomem return dev_err_probe
- modify i2c_add_adapter to devm_i2c_adapter
- modify checkpatch: Alignment should match open parenthesis
- modify checkpatch: braces {} should be used on all arms of this statement
- modify checkpatch: Unbalanced braces around else statement
- Link to v10: https://lore.kernel.org/all/20230415012848.1777768-1-ryan_chen@aspeedtech.com/
Changes in v10:
- aspeed,i2c.yaml
- move unevaluatedProperties after allOf.
- remove extra one blank line.
- i2c-ast2600.c
- no change, the same with v8.
- Link to v9: https://lore.kernel.org/all/20230405022825.333246-1-ryan_chen@aspeedtech.com/
Changes in v9:
- aspeed,i2c.yaml
- backoff to v7.
- no fix typo in maintainer's name and email. this would be another patch.
- no remove address-cells, size-cells, this would be another patch.
- use aspeed,enable-dma property instead of aspeed,xfer-mode selection.
- fix allOf and else false properties for aspeed,ast2600-i2cv2.
- i2c-ast2600.c
- no change, the same with v8
- Link to v8: https://lore.kernel.org/all/20230330073259.485606-1-ryan_chen@aspeedtech.com/
Changes in v8:
- aspeed,i2c.yaml
- modify commit message.
- Fix typo in maintainer's name and email.
- remove address-cells, size-cells.
- i2c-ast2600.c
- move "i2c timeout counter" comment description before property_read.
- remove redundant code "return ret" in probe end.
- Link to v7: https://lore.kernel.org/all/20230327092524.3916389-1-ryan_chen@aspeedtech.com/
Changes in v7:
- aspeed,i2c.yaml
- Update ASPEED I2C maintainers email.
- use aspeed,enable-dma property instead of aspeed,xfer-mode selection.
- fix allOf and else false properties for aspeed,ast2600-i2cv2.
- i2c-ast2600.c
- remove aspeed,xfer-mode instead of aspeed,enable-dma mode. buffer mode
is default.
- remove aspeed,timeout instead of i2c-scl-clk-low-timeout-us for
timeout setting.
- Link to v6: https://lore.kernel.org/all/20230226031321.3126756-1-ryan_chen@aspeedtech.com/
Changes in v6:
- remove aspeed,i2cv2.yaml, merge to aspeed,i2c.yaml -add support for
i2cv2 properites.
- i2c-ast2600.c
- fix ast2600_i2c_remove ordering.
- remove ast2600_i2c_probe goto labels, and add dev_err_probe -remove
redundant deb_dbg debug message.
- rename gr_regmap -> global_regs
- Link to v5: https://lore.kernel.org/all/20230220061745.1973981-1-ryan_chen@aspeedtech.com/
Changes in v5:
- remove ast2600-i2c-global.yaml, i2c-ast2600-global.c.
- i2c-ast2600.c
- remove legacy clock divide, all go for new clock divide.
- remove duplicated read isr.
- remove no used driver match
- fix probe return for each labels return.
- global use mfd driver, driver use phandle to regmap read/write.
- rename aspeed,i2c-ast2600.yaml to aspeed,i2cv2.yaml -remove bus-frequency.
- add required aspeed,gr
- add timeout, byte-mode, buff-mode properites.
- Link to v4: https://lore.kernel.org/all/20230201103359.1742140-1-ryan_chen@aspeedtech.com/
Changes in v4:
- fix i2c-ast2600.c driver buffer mode use single buffer conflit in
master slave mode both enable.
- fix kmemleak issue when use dma mode.
- fix typo aspeed,i2c-ast2600.yaml compatible is "aspeed,ast2600-i2c"
- fix typo aspeed,i2c-ast2600.ymal to aspeed,i2c-ast2600.yaml
- Link to v3: https://lore.kernel.org/all/20220516064900.30517-1-ryan_chen@aspeedtech.com/
Changes in v3:
- fix i2c global clock divide default value.
- remove i2c slave no used dev_dbg info.
- Link to v2: https://lore.kernel.org/all/20220413101735.27678-1-ryan_chen@aspeedtech.com/
Changes in v2:
- add i2c global ymal file commit.
- rename file name from new to ast2600.
aspeed-i2c-new-global.c -> i2c-ast2600-global.c
aspeed-i2c-new-global.h -> i2c-ast2600-global.h
i2c-new-aspeed.c -> i2c-ast2600.c
- rename all driver function name to ast2600.
- Link to v1: https://lore.kernel.org/all/20220323004009.943298-1-ryan_chen@aspeedtech.com/
---
Ryan Chen (5):
dt-bindings: i2c: Split AST2600 binding into a new YAML
i2c: aspeed: Read clock-frequency via i2c_parse_fw_timings()
dt-bindings: i2c: ast2600-i2c.yaml: Add global-regs properties
i2c: ast2600: Add controller driver for AST2600 new register set
i2c: ast2600: Add target mode support
.../bindings/i2c/aspeed,ast2600-i2c.yaml | 88 ++
.../devicetree/bindings/i2c/aspeed,i2c.yaml | 3 +-
MAINTAINERS | 2 +
drivers/i2c/busses/Makefile | 2 +-
drivers/i2c/busses/i2c-aspeed.c | 24 +-
drivers/i2c/busses/i2c-ast2600.c | 1292 ++++++++++++++++++++
6 files changed, 1402 insertions(+), 9 deletions(-)
---
base-commit: a293ec25d59dd96309058c70df5a4dd0f889a1e4
change-id: 20260223-upstream_i2c-ebd07f89739c
Best regards,
--
Ryan Chen <ryan_chen@aspeedtech.com>
^ permalink raw reply
* [PATCH v33 1/5] dt-bindings: i2c: Split AST2600 binding into a new YAML
From: Ryan Chen @ 2026-06-23 1:15 UTC (permalink / raw)
To: jk, andriy.shevchenko, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
Benjamin Herrenschmidt, Rayn Chen, Philipp Zabel
Cc: linux-i2c, devicetree, linux-arm-kernel, linux-aspeed,
linux-kernel, openbmc, Ryan Chen, Conor Dooley
In-Reply-To: <20260623-upstream_i2c-v33-0-6d5338fc56ed@aspeedtech.com>
The AST2600 I2C controller introduces a completely new register layout
with separate controller and target register blocks, unlike the mixed
register layout used by AST2400/AST2500.
Move AST2600 I2C binding from aspeed,i2c.yaml to a dedicated
aspeed,ast2600-i2c.yaml schema.
Besides the split, this also adjusts for AST2600-specific requirements.
- describe two reg regions (controller register block + buffer block);
the second region is optional (minItems: 1) so existing AST2600 DTs
that only declare the controller register block continue to validate
- use clock-frequency for bus speed description
- interrupts are required on AST2600
- use correct DTS coding style in example
No compatible strings are changed.
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
---
Changes in v31:
- Commit message body: clarify that the second reg region is optional
(minItems: 1) rather than required, matching the schema and the v30
backward-compatibility fix (Sashiko AI review).
Changes in v30:
- Add minItems: 1 to reg so existing AST2600 DTs with a single reg
region continue to validate (Sashiko AI review)
- Retain bus-frequency as a deprecated property to avoid breaking
existing AST2600 DTs under unevaluatedProperties: false
(Sashiko AI review)
Changes in v26:
- commit message: include details of changes from original binding
- fix example property ordering to follow DTS coding style
- use consistent "AST2600" naming
---
.../bindings/i2c/aspeed,ast2600-i2c.yaml | 73 ++++++++++++++++++++++
.../devicetree/bindings/i2c/aspeed,i2c.yaml | 3 +-
MAINTAINERS | 1 +
3 files changed, 75 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/i2c/aspeed,ast2600-i2c.yaml b/Documentation/devicetree/bindings/i2c/aspeed,ast2600-i2c.yaml
new file mode 100644
index 000000000000..abc614315dff
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/aspeed,ast2600-i2c.yaml
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i2c/aspeed,ast2600-i2c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED I2C on the AST2600 SoCs
+
+maintainers:
+ - Ryan Chen <ryan_chen@aspeedtech.com>
+
+allOf:
+ - $ref: /schemas/i2c/i2c-controller.yaml#
+
+properties:
+ compatible:
+ enum:
+ - aspeed,ast2600-i2c-bus
+
+ reg:
+ minItems: 1
+ items:
+ - description: controller registers
+ - description: controller buffer space
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-frequency:
+ description: Desired operating frequency of the I2C bus in Hz.
+ minimum: 500
+ maximum: 4000000
+ default: 100000
+
+ bus-frequency:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ deprecated: true
+ description:
+ Legacy name for clock-frequency. Existing AST2600 device trees
+ used this before the binding was split out. New device trees
+ should use the standard clock-frequency property instead.
+ minimum: 500
+ maximum: 4000000
+
+ resets:
+ maxItems: 1
+
+required:
+ - reg
+ - compatible
+ - clocks
+ - resets
+ - interrupts
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/aspeed-clock.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ i2c@80 {
+ compatible = "aspeed,ast2600-i2c-bus";
+ reg = <0x80 0x80>, <0xc00 0x20>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ clock-frequency = <100000>;
+ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+ };
diff --git a/Documentation/devicetree/bindings/i2c/aspeed,i2c.yaml b/Documentation/devicetree/bindings/i2c/aspeed,i2c.yaml
index 5b9bd2feda3b..d4e4f412feba 100644
--- a/Documentation/devicetree/bindings/i2c/aspeed,i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/aspeed,i2c.yaml
@@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/i2c/aspeed,i2c.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: ASPEED I2C on the AST24XX, AST25XX, and AST26XX SoCs
+title: ASPEED I2C on the AST24XX, AST25XX SoCs
maintainers:
- Rayn Chen <rayn_chen@aspeedtech.com>
@@ -17,7 +17,6 @@ properties:
enum:
- aspeed,ast2400-i2c-bus
- aspeed,ast2500-i2c-bus
- - aspeed,ast2600-i2c-bus
reg:
minItems: 1
diff --git a/MAINTAINERS b/MAINTAINERS
index 882214b0e7db..f9c929e86e64 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2596,6 +2596,7 @@ R: Joel Stanley <joel@jms.id.au>
L: linux-i2c@vger.kernel.org
L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
S: Maintained
+F: Documentation/devicetree/bindings/i2c/aspeed,ast2600-i2c.yaml
F: Documentation/devicetree/bindings/i2c/aspeed,i2c.yaml
F: Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2400-i2c-ic.yaml
F: drivers/i2c/busses/i2c-aspeed.c
--
2.34.1
^ permalink raw reply related
* [PATCH v33 2/5] i2c: aspeed: Read clock-frequency via i2c_parse_fw_timings()
From: Ryan Chen @ 2026-06-23 1:15 UTC (permalink / raw)
To: jk, andriy.shevchenko, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
Benjamin Herrenschmidt, Rayn Chen, Philipp Zabel
Cc: linux-i2c, devicetree, linux-arm-kernel, linux-aspeed,
linux-kernel, openbmc, Ryan Chen
In-Reply-To: <20260623-upstream_i2c-v33-0-6d5338fc56ed@aspeedtech.com>
Use i2c_parse_fw_timings() to read the standard "clock-frequency"
property, and fall back to "bus-frequency" only when the standard
property is absent.
This honors device trees written against the updated
aspeed,ast2600-i2c binding without silently falling back to 100 kHz,
while keeping existing in-tree device trees using "bus-frequency"
working.
Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
---
Changes in v31:
- Zero-initialise `struct i2c_timings timings` so the bus-frequency
fallback runs when clock-frequency is absent (Sashiko AI review).
---
drivers/i2c/busses/i2c-aspeed.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
index a26b74c71206..f00bd779146e 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -1000,6 +1000,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
const struct of_device_id *match;
struct aspeed_i2c_bus *bus;
struct clk *parent_clk;
+ struct i2c_timings timings = {};
int irq, ret;
bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
@@ -1025,12 +1026,18 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
}
reset_control_deassert(bus->rst);
- ret = of_property_read_u32(pdev->dev.of_node,
- "bus-frequency", &bus->bus_frequency);
- if (ret < 0) {
- dev_err(&pdev->dev,
- "Could not read bus-frequency property\n");
- bus->bus_frequency = I2C_MAX_STANDARD_MODE_FREQ;
+ i2c_parse_fw_timings(&pdev->dev, &timings, false);
+ if (timings.bus_freq_hz) {
+ bus->bus_frequency = timings.bus_freq_hz;
+ } else {
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "bus-frequency",
+ &bus->bus_frequency);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Could not read clock-frequency or bus-frequency property\n");
+ bus->bus_frequency = I2C_MAX_STANDARD_MODE_FREQ;
+ }
}
match = of_match_node(aspeed_i2c_bus_of_table, pdev->dev.of_node);
--
2.34.1
^ permalink raw reply related
* [PATCH v33 3/5] dt-bindings: i2c: ast2600-i2c.yaml: Add global-regs properties
From: Ryan Chen @ 2026-06-23 1:15 UTC (permalink / raw)
To: jk, andriy.shevchenko, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
Benjamin Herrenschmidt, Rayn Chen, Philipp Zabel
Cc: linux-i2c, devicetree, linux-arm-kernel, linux-aspeed,
linux-kernel, openbmc, Ryan Chen, Conor Dooley
In-Reply-To: <20260623-upstream_i2c-v33-0-6d5338fc56ed@aspeedtech.com>
Add the aspeed,global-regs phandle to reference the AST2600 global
registers syscon node, containing the SoC-common I2C register set.
These properties apply only to the AST2600 binding. Legacy DTs remain
unchanged.
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
---
Changes in v32:
- Add if/then conditional schema: when aspeed,global-regs is present,
require reg to have at least two items. The new driver unconditionally
maps resource index 1 (the buffer SRAM region); a DT with one reg
entry and aspeed,global-regs passes schema validation but fails probe.
The constraint makes the schema consistent with driver behaviour.
- Fix binding example to use the correct AST2600 clock header
(ast2600-clock.h) and ASPEED_CLK_APB2 instead of the legacy
aspeed-clock.h, where index 26 (ASPEED_CLK_APB) maps to the
UART5 gate clock on AST2600 rather than the APB2 bus clock
used by the I2C controller.
Changes in v29:
- remove aspeed,enable-dma properties.
Changes in v28:
- update commit message correspond with aspeed,enable-dma.
- remove aspeed,transfer-mode and add aspeed,enable-dma property and
description.
- Fix aspeed,enable-dma description to reflect hardware capability rather
than software behavior
Changes in v27:
- change aspeed,transfer-mode to aspeed,enable-dma.
---
.../devicetree/bindings/i2c/aspeed,ast2600-i2c.yaml | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/i2c/aspeed,ast2600-i2c.yaml b/Documentation/devicetree/bindings/i2c/aspeed,ast2600-i2c.yaml
index abc614315dff..eb6e316c112f 100644
--- a/Documentation/devicetree/bindings/i2c/aspeed,ast2600-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/aspeed,ast2600-i2c.yaml
@@ -48,6 +48,12 @@ properties:
resets:
maxItems: 1
+ aspeed,global-regs:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ Phandle reference to the i2c global syscon node, containing the
+ SoC-common i2c register set.
+
required:
- reg
- compatible
@@ -55,19 +61,28 @@ required:
- resets
- interrupts
+if:
+ required:
+ - aspeed,global-regs
+then:
+ properties:
+ reg:
+ minItems: 2
+
unevaluatedProperties: false
examples:
- |
- #include <dt-bindings/clock/aspeed-clock.h>
+ #include <dt-bindings/clock/ast2600-clock.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
i2c@80 {
compatible = "aspeed,ast2600-i2c-bus";
reg = <0x80 0x80>, <0xc00 0x20>;
#address-cells = <1>;
#size-cells = <0>;
- clocks = <&syscon ASPEED_CLK_APB>;
+ clocks = <&syscon ASPEED_CLK_APB2>;
resets = <&syscon ASPEED_RESET_I2C>;
clock-frequency = <100000>;
interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+ aspeed,global-regs = <&i2c_global>;
};
--
2.34.1
^ permalink raw reply related
* [PATCH v33 5/5] i2c: ast2600: Add target mode support
From: Ryan Chen @ 2026-06-23 1:15 UTC (permalink / raw)
To: jk, andriy.shevchenko, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
Benjamin Herrenschmidt, Rayn Chen, Philipp Zabel
Cc: linux-i2c, devicetree, linux-arm-kernel, linux-aspeed,
linux-kernel, openbmc, Ryan Chen
In-Reply-To: <20260623-upstream_i2c-v33-0-6d5338fc56ed@aspeedtech.com>
Add target mode support to the AST2600 I2C driver.
Target mode features implemented include:
- Add target interrupt handling
- Address match and response logic
This complements the existing controller-mode support, enabling
dual-role capability.
Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
---
Changes in v32:
- Fix target RX data loss in the master-abort fast path: remove the
BUFF_CTRL zeroing that preceded the controller IER clear. The shared
BUFF_CTRL register holds the pending target RX length in bits [29:24];
zeroing it before the switch statement causes target_rx_len to read
back as 0, silently discarding all bytes already received by the
target.
- Fix use-after-free in master-abort fast path: null msgs and re-enable
the controller IER before calling complete(), not after. Calling
complete() first allows process context to immediately start a new
i2c_transfer() and install a new msgs pointer; a stale controller IRQ
firing during the subsequent IER restore would then dereference the
new transfer's msgs buffer.
- Fix shared-buffer corruption on coalesced STOP+SLAVE_MATCH IRQ:
restore the SLAVE_PENDING guard on the target_active = false
transition. SLAVE_PENDING (bit 29) is set precisely when a new
address-match is already queued while the previous DMA receive has
not yet been processed. Clearing target_active unconditionally on
STOP in that case lets the controller side overwrite the shared Tx/Rx
buffer before the new target transaction has been re-armed.
- Use READ_ONCE() for all process-context reads of target_active.
The IRQ path writes target_active with WRITE_ONCE(); plain loads in
process context allow the compiler to cache the value across the
IER-disable window, potentially seeing a stale false and starting a
controller transfer that races with an active target transaction.
Changes in v31:
- Address Sashiko AI code review feedback on the target patch:
- Clear target_active on any STOP. The previous condition
`(sts & STOP) && !(sts & SLAVE_PENDING)` failed under coalesced
STOP+SLAVE_PENDING IRQs and left target_active stuck true,
deadlocking controller_xfer() with -EBUSY forever.
- Enable the target IER inside reg_target() instead of
unconditionally in probe(). unreg_target() disables it; without
matching re-enable in reg_target() a subsequent re-registration
would never receive IRQs. Also avoids spurious IRQ activity when
no slave is registered.
- Add the missing CMD_STS write in the
SLAVE_PENDING|RX_DONE|WAIT_TX_DMA|STOP target ISR case so the
HW state machine is re-armed (TRIGGER | TX_BUFF_EN); otherwise
the controller stretches SCL until INACTIVE_TO recovers.
- Default target ISR case now writes TARGET_TRIGGER_CMD to re-arm
the HW state machine instead of silently breaking, which
previously left the bus hung on unhandled sts combinations.
- W1C-clear the ADDR1/2/3_NAK bits in HW (not just locally) in
ast2600_i2c_target_irq(); stale ADDR_NAK bits made
controller_xfer() see I2CS_ISR != 0 and bounce every transfer
with -EBUSY.
- unreg_target(): replace masked ADDR_CTRL write with writel(0, ...);
AST2600_I2CS_ADDR1_MASK covers only bits[6:0] (the 7-bit address),
leaving ADDR1_ENABLE (BIT(7)) set after unregister. Although SLAVE_EN
is cleared first, writing 0 is the correct and complete teardown.
Changes in v30:
- Address Sashiko AI code review feedback:
- Force-stop path (target IRQ aborting an in-flight controller
transfer): disable the controller IER and W1C-clear pending ISR
before calling complete(), then restore the IER after the wake-up.
Without the disable/clear sequence the controller IRQ handler can
race with the target abort path and double-complete or touch
freed msgs.
- unreg_target() teardown ordering: disable the target IER first,
then disable SLAVE_EN / clear ADDR_CTRL, synchronize_irq(), W1C
pending ISR, and only then NULL i2c_bus->target and clear
target_active. The old order left IER enabled while target was
being cleared, allowing an in-flight handler to dereference a
target pointer the caller had already freed.
- reg_target() bring-up ordering: assign i2c_bus->target before
enabling SLAVE_EN. Otherwise an IRQ that fires after SLAVE_EN is
set but before the pointer is stored finds target == NULL, exits
without clearing the ISR, and the unmasked event re-fires as an
IRQ storm.
- Use writel() instead of writeb() when staging a TX byte into the
target buffer. The AST2600 buffer SRAM only supports 32-bit
accesses; byte writes are silently dropped (or, on some
revisions, raise a bus fault), so a SLAVE_READ_REQUESTED reply
never reaches the master.
- reg_target() rejects 10-bit client addresses with -EAFNOSUPPORT.
AST2600_I2CS_ADDR1 is only a 7-bit field; without the check, the
high bits of a 10-bit address overflow into the adjacent ADDR2
field and silently corrupt a second target slot.
- Initialise the local `u8 value` to 0 in the target packet IRQ
handler. Its address is passed to i2c_slave_event() for events
such as I2C_SLAVE_STOP / I2C_SLAVE_READ_REQUESTED; a slave
backend that reads the byte before writing would otherwise leak
uninitialised kernel stack.
Changes in v29:
- fix race between unreg_target and IRQ handler.
- move i2cs ier enable from ast2600_i2c_init to probe after master ier enable.
- remove dma/byte transfer, use buffer mode only.
Changes in v28:
- fix typo condication -> condition
- fix compile error, when disable CONFIG_I2C_SLAVE
Changes in v26:
- change int to bool target_operate
- rename target_operate to target_active
- use i2c_bus->target replace require IO
- use WRITE_ONCE replace target_operate write.
---
drivers/i2c/busses/i2c-ast2600.c | 359 +++++++++++++++++++++++++++++++++++++++
1 file changed, 359 insertions(+)
diff --git a/drivers/i2c/busses/i2c-ast2600.c b/drivers/i2c/busses/i2c-ast2600.c
index 5cb2d91b78e0..af950a4c4d6d 100644
--- a/drivers/i2c/busses/i2c-ast2600.c
+++ b/drivers/i2c/busses/i2c-ast2600.c
@@ -255,6 +255,11 @@ struct ast2600_i2c_bus {
bool multi_master;
bool stop_pending;
void __iomem *buf_base;
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ /* target structure */
+ bool target_active;
+ struct i2c_client *target;
+#endif
};
static void ast2600_i2c_ac_timing_config(struct ast2600_i2c_bus *i2c_bus)
@@ -348,6 +353,253 @@ static int ast2600_i2c_recover_bus(struct ast2600_i2c_bus *i2c_bus)
return ret;
}
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+static void ast2600_i2c_target_packet_buff_irq(struct ast2600_i2c_bus *i2c_bus, u32 sts)
+{
+ u8 value = 0;
+ int target_rx_len = 0;
+ u32 cmd = 0;
+ int i;
+
+ /* due to controller target is common buffer, need force the master stop not issue */
+ if (readl(i2c_bus->reg_base + AST2600_I2CM_CMD_STS) & GENMASK(15, 0)) {
+ writel(0, i2c_bus->reg_base + AST2600_I2CM_CMD_STS);
+ writel(0, i2c_bus->reg_base + AST2600_I2CM_IER);
+ writel(readl(i2c_bus->reg_base + AST2600_I2CM_ISR),
+ i2c_bus->reg_base + AST2600_I2CM_ISR);
+ i2c_bus->cmd_err = -EBUSY;
+ WRITE_ONCE(i2c_bus->msgs, NULL);
+ writel(AST2600_I2CM_PKT_DONE | AST2600_I2CM_BUS_RECOVER,
+ i2c_bus->reg_base + AST2600_I2CM_IER);
+ complete(&i2c_bus->cmd_complete);
+ }
+
+ /* Handle i2c target timeout condition */
+ if (sts & AST2600_I2CS_INACTIVE_TO) {
+ /* Reset timeout counter */
+ u32 ac_timing = readl(i2c_bus->reg_base + AST2600_I2CC_AC_TIMING) &
+ AST2600_I2CC_AC_TIMING_MASK;
+
+ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING);
+ ac_timing |= AST2600_I2CC_TTIMEOUT(i2c_bus->timeout);
+ writel(ac_timing, i2c_bus->reg_base + AST2600_I2CC_AC_TIMING);
+ writel(TARGET_TRIGGER_CMD, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);
+ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR);
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);
+ WRITE_ONCE(i2c_bus->target_active, false);
+ return;
+ }
+
+ sts &= ~(AST2600_I2CS_PKT_DONE | AST2600_I2CS_PKT_ERROR);
+
+ if (sts & AST2600_I2CS_SLAVE_MATCH)
+ WRITE_ONCE(i2c_bus->target_active, true);
+
+ switch (sts) {
+ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_WAIT_RX_DMA |
+ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:
+ case AST2600_I2CS_SLAVE_PENDING |
+ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:
+ case AST2600_I2CS_SLAVE_PENDING |
+ AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_STOP:
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);
+ fallthrough;
+ case AST2600_I2CS_SLAVE_PENDING |
+ AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE:
+ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE:
+ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_SLAVE_MATCH:
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value);
+ cmd = TARGET_TRIGGER_CMD;
+ if (sts & AST2600_I2CS_RX_DONE) {
+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +
+ AST2600_I2CC_BUFF_CTRL));
+ for (i = 0; i < target_rx_len; i++) {
+ value = readb(i2c_bus->buf_base + i2c_bus->buf_size + i);
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);
+ }
+ }
+ if (readl(i2c_bus->reg_base + AST2600_I2CS_CMD_STS) & AST2600_I2CS_RX_BUFF_EN)
+ cmd = 0;
+ else
+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_BUFF_EN;
+
+ writel(AST2600_I2CC_SET_RX_BUF_LEN(i2c_bus->buf_size),
+ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);
+ break;
+ case AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_RX_DONE:
+ cmd = TARGET_TRIGGER_CMD;
+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +
+ AST2600_I2CC_BUFF_CTRL));
+ for (i = 0; i < target_rx_len; i++) {
+ value = readb(i2c_bus->buf_base + i2c_bus->buf_size + i);
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);
+ }
+ cmd |= AST2600_I2CS_RX_BUFF_EN;
+ writel(AST2600_I2CC_SET_RX_BUF_LEN(i2c_bus->buf_size),
+ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);
+ break;
+ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_WAIT_RX_DMA |
+ AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:
+ cmd = TARGET_TRIGGER_CMD;
+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +
+ AST2600_I2CC_BUFF_CTRL));
+ for (i = 0; i < target_rx_len; i++) {
+ value = readb(i2c_bus->buf_base + i2c_bus->buf_size + i);
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);
+ }
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);
+ cmd |= AST2600_I2CS_RX_BUFF_EN;
+ writel(AST2600_I2CC_SET_RX_BUF_LEN(i2c_bus->buf_size),
+ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);
+ break;
+ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:
+ cmd = TARGET_TRIGGER_CMD;
+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +
+ AST2600_I2CC_BUFF_CTRL));
+ for (i = 0; i < target_rx_len; i++) {
+ value = readb(i2c_bus->buf_base + i2c_bus->buf_size + i);
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);
+ }
+ /* workaround for avoid next start with len != 0 */
+ writel(BIT(0), i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);
+ break;
+ case AST2600_I2CS_RX_DONE | AST2600_I2CS_STOP:
+ cmd = TARGET_TRIGGER_CMD;
+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +
+ AST2600_I2CC_BUFF_CTRL));
+ for (i = 0; i < target_rx_len; i++) {
+ value = readb(i2c_bus->buf_base + i2c_bus->buf_size + i);
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);
+ }
+ /* workaround for avoid next start with len != 0 */
+ writel(BIT(0), i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);
+ break;
+ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_RX_DONE |
+ AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_STOP:
+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +
+ AST2600_I2CC_BUFF_CTRL));
+ for (i = 0; i < target_rx_len; i++) {
+ value = readb(i2c_bus->buf_base + i2c_bus->buf_size + i);
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);
+ }
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value);
+ writel(value, i2c_bus->buf_base);
+ writel(AST2600_I2CC_SET_TX_BUF_LEN(1),
+ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);
+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_BUFF_EN;
+ break;
+ case AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_SLAVE_MATCH:
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value);
+ writel(value, i2c_bus->buf_base);
+ writel(AST2600_I2CC_SET_TX_BUF_LEN(1),
+ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);
+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_BUFF_EN;
+ break;
+ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_STOP |
+ AST2600_I2CS_TX_NAK | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE:
+ case AST2600_I2CS_SLAVE_PENDING | AST2600_I2CS_WAIT_RX_DMA | AST2600_I2CS_STOP |
+ AST2600_I2CS_TX_NAK | AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE:
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value);
+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +
+ AST2600_I2CC_BUFF_CTRL));
+ for (i = 0; i < target_rx_len; i++) {
+ value = readb(i2c_bus->buf_base + i2c_bus->buf_size + i);
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);
+ }
+ writel(AST2600_I2CC_SET_RX_BUF_LEN(i2c_bus->buf_size),
+ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);
+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_BUFF_EN;
+ break;
+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_RX_DONE:
+ case AST2600_I2CS_WAIT_TX_DMA | AST2600_I2CS_RX_DONE:
+ case AST2600_I2CS_WAIT_TX_DMA:
+ if (sts & AST2600_I2CS_SLAVE_MATCH)
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value);
+
+ if (sts & AST2600_I2CS_RX_DONE) {
+ target_rx_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +
+ AST2600_I2CC_BUFF_CTRL));
+ for (i = 0; i < target_rx_len; i++) {
+ value = readb(i2c_bus->buf_base + i2c_bus->buf_size + i);
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_RECEIVED, &value);
+ }
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_REQUESTED, &value);
+ } else {
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_READ_PROCESSED, &value);
+ }
+ writel(value, i2c_bus->buf_base);
+ writel(AST2600_I2CC_SET_TX_BUF_LEN(1),
+ i2c_bus->reg_base + AST2600_I2CC_BUFF_CTRL);
+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_TX_BUFF_EN;
+ break;
+ /* workaround : trigger the cmd twice to fix next state keep 1000000 */
+ case AST2600_I2CS_SLAVE_MATCH | AST2600_I2CS_RX_DONE:
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_WRITE_REQUESTED, &value);
+ cmd = TARGET_TRIGGER_CMD | AST2600_I2CS_RX_BUFF_EN;
+ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);
+ break;
+ case AST2600_I2CS_TX_NAK | AST2600_I2CS_STOP:
+ case AST2600_I2CS_STOP:
+ cmd = TARGET_TRIGGER_CMD;
+ i2c_slave_event(i2c_bus->target, I2C_SLAVE_STOP, &value);
+ break;
+ default:
+ dev_dbg(i2c_bus->dev, "unhandled target isr case %x, sts %x\n", sts,
+ readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF));
+ cmd = TARGET_TRIGGER_CMD;
+ break;
+ }
+
+ if (cmd)
+ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);
+
+ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_ISR);
+ readl(i2c_bus->reg_base + AST2600_I2CS_ISR);
+
+ if ((sts & AST2600_I2CS_STOP) && !(sts & AST2600_I2CS_SLAVE_PENDING))
+ WRITE_ONCE(i2c_bus->target_active, false);
+}
+
+static int ast2600_i2c_target_irq(struct ast2600_i2c_bus *i2c_bus)
+{
+ u32 ier = readl(i2c_bus->reg_base + AST2600_I2CS_IER);
+ u32 isr = readl(i2c_bus->reg_base + AST2600_I2CS_ISR);
+
+ if (!(isr & ier))
+ return 0;
+
+ /*
+ * Target interrupt coming after controller packet done
+ * So need handle controller first.
+ */
+ if (readl(i2c_bus->reg_base + AST2600_I2CM_ISR) & AST2600_I2CM_PKT_DONE)
+ return 0;
+
+ isr &= ~(AST2600_I2CS_ADDR_INDICATE_MASK);
+
+ if (isr & (AST2600_I2CS_ADDR1_NAK | AST2600_I2CS_ADDR2_NAK |
+ AST2600_I2CS_ADDR3_NAK)) {
+ writel(isr & (AST2600_I2CS_ADDR1_NAK | AST2600_I2CS_ADDR2_NAK |
+ AST2600_I2CS_ADDR3_NAK),
+ i2c_bus->reg_base + AST2600_I2CS_ISR);
+ isr &= ~(AST2600_I2CS_ADDR1_NAK | AST2600_I2CS_ADDR2_NAK |
+ AST2600_I2CS_ADDR3_NAK);
+ }
+
+ if (AST2600_I2CS_ADDR_MASK & isr)
+ isr &= ~AST2600_I2CS_ADDR_MASK;
+
+ if (AST2600_I2CS_PKT_DONE & isr)
+ ast2600_i2c_target_packet_buff_irq(i2c_bus, isr);
+
+ return 1;
+}
+#endif
+
static int ast2600_i2c_setup_buff_tx(u32 cmd, struct ast2600_i2c_bus *i2c_bus)
{
struct i2c_msg *msg = &i2c_bus->msgs[i2c_bus->msgs_index];
@@ -561,6 +813,20 @@ static void ast2600_i2c_controller_packet_irq(struct ast2600_i2c_bus *i2c_bus, u
}
break;
case AST2600_I2CM_RX_DONE:
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ /*
+ * Workaround for controller/target packet mode enable rx done stuck issue
+ * When controller go for first read (RX_DONE), target mode will also effect
+ * Then controller will send nack, not operate anymore.
+ */
+ if (readl(i2c_bus->reg_base + AST2600_I2CS_CMD_STS) & AST2600_I2CS_PKT_MODE_EN) {
+ u32 target_cmd = readl(i2c_bus->reg_base + AST2600_I2CS_CMD_STS);
+
+ writel(0, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);
+ writel(target_cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);
+ }
+ fallthrough;
+#endif
case AST2600_I2CM_RX_DONE | AST2600_I2CM_NORMAL_STOP:
xfer_len = AST2600_I2CC_GET_RX_BUF_LEN(readl(i2c_bus->reg_base +
AST2600_I2CC_BUFF_CTRL));
@@ -668,6 +934,12 @@ static irqreturn_t ast2600_i2c_bus_irq(int irq, void *dev_id)
{
struct ast2600_i2c_bus *i2c_bus = dev_id;
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ if (i2c_bus->target) {
+ if (ast2600_i2c_target_irq(i2c_bus))
+ return IRQ_HANDLED;
+ }
+#endif
return IRQ_RETVAL(ast2600_i2c_controller_irq(i2c_bus));
}
@@ -684,6 +956,21 @@ static int ast2600_i2c_controller_xfer(struct i2c_adapter *adap, struct i2c_msg
return ret;
}
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ if (READ_ONCE(i2c_bus->target_active))
+ return -EBUSY;
+ /*
+ * Controller and target share the same buffer register. A target
+ * transaction can update buffer state asynchronously via IRQ, so block
+ * controller transfers while target is active to avoid buffer corruption.
+ */
+ writel(0, i2c_bus->reg_base + AST2600_I2CS_IER);
+ if (readl(i2c_bus->reg_base + AST2600_I2CS_ISR) || READ_ONCE(i2c_bus->target_active)) {
+ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_IER);
+ return -EBUSY;
+ }
+#endif
+
i2c_bus->cmd_err = 0;
i2c_bus->msgs = msgs;
i2c_bus->msgs_index = 0;
@@ -691,6 +978,10 @@ static int ast2600_i2c_controller_xfer(struct i2c_adapter *adap, struct i2c_msg
WRITE_ONCE(i2c_bus->stop_pending, false);
reinit_completion(&i2c_bus->cmd_complete);
ret = ast2600_i2c_do_start(i2c_bus);
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ /* avoid race condition target is wait and controller wait 1st target operate */
+ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_IER);
+#endif
if (ret)
goto controller_out;
timeout = wait_for_completion_timeout(&i2c_bus->cmd_complete, i2c_bus->adap.timeout);
@@ -719,6 +1010,9 @@ static int ast2600_i2c_controller_xfer(struct i2c_adapter *adap, struct i2c_msg
* if the bus is still busy.
*/
if (i2c_bus->multi_master &&
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ !READ_ONCE(i2c_bus->target_active) &&
+#endif
(readl(i2c_bus->reg_base + AST2600_I2CC_STS_AND_BUFF) &
AST2600_I2CC_BUS_BUSY_STS))
ast2600_i2c_recover_bus(i2c_bus);
@@ -767,8 +1061,66 @@ static int ast2600_i2c_init(struct ast2600_i2c_bus *i2c_bus)
/* Clear Interrupt */
writel(GENMASK(27, 0), i2c_bus->reg_base + AST2600_I2CM_ISR);
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ writel(GENMASK(27, 0), i2c_bus->reg_base + AST2600_I2CS_ISR);
+#endif
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+static int ast2600_i2c_reg_target(struct i2c_client *client)
+{
+ struct ast2600_i2c_bus *i2c_bus = i2c_get_adapdata(client->adapter);
+ u32 cmd = TARGET_TRIGGER_CMD;
+
+ if (i2c_bus->target)
+ return -EINVAL;
+
+ if (client->flags & I2C_CLIENT_TEN)
+ return -EAFNOSUPPORT;
+
+ dev_dbg(i2c_bus->dev, "target addr %x\n", client->addr);
+
+ writel(0, i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL);
+
+ i2c_bus->target = client;
+
+ writel(AST2600_I2CC_SLAVE_EN | readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL),
+ i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL);
+
+ writel(cmd, i2c_bus->reg_base + AST2600_I2CS_CMD_STS);
+ /* Set target addr. */
+ writel(client->addr | AST2600_I2CS_ADDR1_ENABLE,
+ i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL);
+
+ writel(AST2600_I2CS_PKT_DONE, i2c_bus->reg_base + AST2600_I2CS_IER);
+
+ return 0;
+}
+
+static int ast2600_i2c_unreg_target(struct i2c_client *client)
+{
+ struct ast2600_i2c_bus *i2c_bus = i2c_get_adapdata(client->adapter);
+ u32 val;
+
+ writel(0, i2c_bus->reg_base + AST2600_I2CS_IER);
+
+ val = readl(i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL);
+ writel(val & ~AST2600_I2CC_SLAVE_EN, i2c_bus->reg_base + AST2600_I2CC_FUN_CTRL);
+ writel(0, i2c_bus->reg_base + AST2600_I2CS_ADDR_CTRL);
+
+ synchronize_irq(i2c_bus->irq);
+
+ writel(readl(i2c_bus->reg_base + AST2600_I2CS_ISR),
+ i2c_bus->reg_base + AST2600_I2CS_ISR);
+
+ i2c_bus->target = NULL;
+ WRITE_ONCE(i2c_bus->target_active, false);
+
return 0;
}
+#endif
static u32 ast2600_i2c_functionality(struct i2c_adapter *adap)
{
@@ -778,6 +1130,10 @@ static u32 ast2600_i2c_functionality(struct i2c_adapter *adap)
static const struct i2c_algorithm i2c_ast2600_algorithm = {
.xfer = ast2600_i2c_controller_xfer,
.functionality = ast2600_i2c_functionality,
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ .reg_target = ast2600_i2c_reg_target,
+ .unreg_target = ast2600_i2c_unreg_target,
+#endif
};
static const struct i2c_adapter_quirks ast2600_i2c_quirks = {
@@ -821,6 +1177,9 @@ static int ast2600_i2c_probe(struct platform_device *pdev)
regmap_write(i2c_bus->global_regs, AST2600_I2CG_CLK_DIV_CTRL, I2CCG_DIV_CTRL);
}
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ WRITE_ONCE(i2c_bus->target_active, false);
+#endif
i2c_bus->dev = dev;
i2c_bus->multi_master = device_property_read_bool(dev, "multi-master");
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v3] drm/bridge: imx93-mipi-dsi: Fix mode validation
From: Liu Ying @ 2026-06-23 1:43 UTC (permalink / raw)
To: Maxime Ripard
Cc: Luca Ceresoli, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Dmitry Baryshkov, dri-devel, imx, linux-arm-kernel, linux-kernel
In-Reply-To: <20260622-strong-messy-hare-2372cd@houat>
On Mon, Jun 22, 2026 at 11:38:19AM +0200, Maxime Ripard wrote:
> On Mon, Jun 22, 2026 at 03:52:26PM +0800, Liu Ying wrote:
> > > Finally, out of my utter ignorance on the subject, is the VESA +/-0.5%
> > > margin generic enough that this driver can always rely on it?
> >
> > I see several upstream drivers rely on it, see "git grep '0.5%' drivers/gpu/"
> > output. And every display mode allows -/+ 0.5% pixel clock rate deviation
> > according to VESA Display Monitor Timing Standard [1], though [1] is a found
> > by a random Google search.
>
> Yes, it's what we've been using for some time now. Is there any
> particular concern about it?
I have no concern about it. Luca, do you have any concern?
>
> Maxime
--
Regards,
Liu Ying
^ 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