Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v3] i2c: imx: mark I2C adapter when hardware is powered down
From: Mukesh Savaliya @ 2026-05-21 12:39 UTC (permalink / raw)
  To: Carlos Song (OSS), Mukesh Savaliya, o.rempel@pengutronix.de,
	kernel@pengutronix.de, andi.shyti@kernel.org, Frank Li,
	s.hauer@pengutronix.de, festevam@gmail.com, Carlos Song,
	Bough Chen
  Cc: linux-i2c@vger.kernel.org, imx@lists.linux.dev,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, stable@vger.kernel.org
In-Reply-To: <AM0PR04MB68024A0FAF0637726C08B87BE80E2@AM0PR04MB6802.eurprd04.prod.outlook.com>



On 5/21/2026 5:32 PM, Carlos Song (OSS) wrote:
> 
> 
>> -----Original Message-----
>> From: Mukesh Savaliya <mukesh.savaliya@oss.qualcomm.com>
>> Sent: Thursday, May 21, 2026 7:14 PM
>> To: Carlos Song (OSS) <carlos.song@oss.nxp.com>; Mukesh Savaliya
>> <mukesh.savaliya@oss.qualcomm.com>; o.rempel@pengutronix.de;
>> kernel@pengutronix.de; andi.shyti@kernel.org; Frank Li <frank.li@nxp.com>;
>> s.hauer@pengutronix.de; festevam@gmail.com; Carlos Song
>> <carlos.song@nxp.com>; Bough Chen <haibo.chen@nxp.com>
>> Cc: linux-i2c@vger.kernel.org; imx@lists.linux.dev;
>> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org;
>> stable@vger.kernel.org
>> Subject: Re: [PATCH v3] i2c: imx: mark I2C adapter when hardware is powered
>> down
>>
>>
>> On 5/21/2026 4:21 PM, Carlos Song (OSS) wrote:
>>
>> [...]
>>
>>>>>> -----Original Message-----
>>>>>> From: Mukesh Savaliya <mukesh.savaliya@oss.qualcomm.com>
>>>>>> Sent: Thursday, May 21, 2026 3:40 PM
>>>>>> To: Carlos Song (OSS) <carlos.song@oss.nxp.com>;
>>>>>> o.rempel@pengutronix.de; kernel@pengutronix.de;
>>>>>> andi.shyti@kernel.org; Frank Li <frank.li@nxp.com>;
>>>>>> s.hauer@pengutronix.de; festevam@gmail.com; Carlos Song
>>>>>> <carlos.song@nxp.com>; Bough Chen <haibo.chen@nxp.com>
>>>>>> Cc: linux-i2c@vger.kernel.org; imx@lists.linux.dev;
>>>>>> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org;
>>>>>> stable@vger.kernel.org
>>>>>> Subject: Re: [PATCH v3] i2c: imx: mark I2C adapter when hardware is
>>>>>> powered down
>>>>>>
>>>>>> Hi Carlos,
>>>>>>
>>>>>> On 5/20/2026 3:45 PM, Carlos Song (OSS) wrote:
>>>>>>> From: Carlos Song <carlos.song@nxp.com>
>>>>>>>
>>>>>>> Mark the I2C adapter as suspended during system suspend to block
>>>>>>> further transfers, and resume it on system resume. This prevents
>>>>>>> potential hangs when the hardware is powered down but clients
>>>>>>> still attempt
>>>>>> I2C transfers.
>>>>>>>
>>>> what was the reason of this hang ? I was thinking you don't have
>>>> interrupts working when client requested transfer but adapter was
>>>> suspended. Please correct me if wrong.
>>>>
>>>> And it would be good to mention the actual problem and why/how it
>> occurred.
>>>>>> Code changes looks fine to me but have comment on commit log.
>>>>>>
>>>>>> It seems, you are adding support of _noirq() callbacks to allow
>>>>>> transfers during suspend/resume noirq phase of PM.
>>>>>>
>>>>>> Would it make sense if you can write "Replace system PM callbacks
>>>>>> with noirq PM callbacks" OR "Allow transfers during _noirq phase of
>>>>>> the PM ops" instead of "mark I2C adapter when hardware is powered
>>>> down" ?
>>>>>>
>>>>>
>>>>> Hi,
>>>>>
>>>>> Thank you for your comments!
>>>>>
>>>>> But this patch is added is not for support noirq PM callback or
>>>>> transfer in noirq
>>>> phase.
>>>>>
>>>> Okay, may be actual problem description can help me.
>>>>> In fact, this fix is to mark the I2C adapter as suspended during
>>>>> system noirq suspend to block further transfers, and resume it on
>>>>> system noirq resume. This is to prohibit I2C device calling the I2C
>>>>> controller after the system noirq suspend and before noirq resume,
>>>>> because at
>>>> this time the I2C instance is powered off or the clock is disabled
>>>> ... So I want to keep current commit. How do you think?
>>>> completely Makes sense. Please help add how this problem occurred and
>> why ?
>>>> So the change/fix will be good to understand against it.
>>>
>>> Hi,
>>>
>>> In some I.MX platform, some I2C devices will keep a work queue all
>>> time, the work queue will trigger I2C xfer every once in a while, but the work
>> queue shouldn't be free in system suspend.
>>>
>>
>> work queue has transfers queued even if system is suspended ? IMO, the client
>> i2c devices should not let system go to suspend.
>>
> 
> Hi Mukesh,
> 
> Thank you for the detailed discussion.
> 
> Yes, I totally agree that I2C client drivers should ideally stop
> issuing transfers when the system is suspending.
> 
> However, in practice there are many different I2C clients, and not all
> of them strictly adhere to this requirement. Some clients may still
> trigger transfers through workqueues or deferred contexts during the
> suspend/resume window.
> 
> Therefore, adding this protection at the I2C controller side helps to
> avoid unexpected accesses when the hardware resources are unavailable,
> making the system more robust.
> 

Agreed !

>>> Within a very short time window, possibly from noirq_suspend to the
>>> system actually being suspended, or possibly from the system starting
>>> to resume to before noirq_resume, this work queue will trigger an I2C
>>> transfer, and at this time the I2C controller's clk and pinctrl have
>>> not yet been restored, reading and
>>
>> Right, this kind of explains the problem to me. I think you are trying to serve
>> i2c transfers when your resources(clk, pinctrl) are not turned ON and also
>> interrupt remains disabled. And that's why you need to add
>> _noir() PM callbacks supports along with IRQF_NO_SUSPEND |
>> IRQF_EARLY_RESUME flags.
>>
>>> writing I2C registers causes the system to hang. This patch make all
>>> I2C operations are performed in a safe hardware state.
>>>
>>> Is it better if I add these comment to patch commit log?
>>>>>
>> if my latest comments makes sense against the issue, you may write
>> accordingly. if i am wrong, then your explanation makes sense. Cause of the
>> hang needs to be clearly mention int the commit log in your next patch.
>>
> 
> Based on our discussion, I have updated the commit log as below:
> 
> On some i.MX platforms, certain I2C client drivers keep a periodic
> workqueue which continues to trigger I2C transfers.
> 
> During system suspend/resume, there exists a time window between:
>    - noirq_suspend and full suspend
>    - resume start and noirq_resume

- noirq_resume and resume start [Just opposite ?]

> 
> In this window, the I2C controller resources such as clock and pinctrl
> may already be disabled or not yet restored.
> 
> If a workqueue triggers an I2C transfer in this period, the driver
> attempts to access I2C registers while the hardware resources are
> unavailable, which may lead to system hang.
> 
> Mark the I2C adapter as suspended during noirq suspend and block new
> transfers until resume, ensuring that I2C transfers are only issued
> when hardware resources are available.
> 
> Does this look good to you?
>
Looks good, Thanks !

>>>>
>>>
> 



^ permalink raw reply

* Re: [PATCH] irqchip/exynos-combiner: switch to raw_spinlock
From: Thomas Gleixner @ 2026-05-21 12:31 UTC (permalink / raw)
  To: Marek Szyprowski, linux-arm-kernel, linux-samsung-soc,
	linux-rt-devel
  Cc: Krzysztof Kozlowski, Alim Akhtar, Sebastian Andrzej Siewior,
	Clark Williams, Steven Rostedt
In-Reply-To: <97f33a9d-5fdd-4766-aaff-d10d5f5fdf28@samsung.com>

On Thu, May 21 2026 at 13:26, Marek Szyprowski wrote:
> On 21.05.2026 11:06, Thomas Gleixner wrote:
>> What is this lock actually protecting?
>>
>> Each combiner has it's own @base address, so there is no concurrency
>> problem between two cascade interrupts being handled at the same time.
>>
>> That means the only possible problem would be that the same cascade
>> interrupt is handled on two CPUs concurrently. Is that even possible?
> Frankly speaking I did this conversion mechanically, late in the evening to fix
> the bug warning I've spotted. Indeed this spinlock looks like a copy&paste or
> development leftover. The only side-effect of it I see is a memory barrier,
> which might affect how the register access happens, but this should not affect
> cascade operation imho. Do You want me to send a patch removing it completely?

I've applied the fixup for now. But, yes please send a removal against

  git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/urgent

Thanks,

        tglx



^ permalink raw reply

* Re: [PATCH v22 08/13] mfd: core: Add firmware-node support to MFD cells
From: Bartosz Golaszewski @ 2026-05-21 12:29 UTC (permalink / raw)
  To: Lee Jones
  Cc: Shivendra Pratap, Sebastian Reichel, Mark Rutland,
	Lorenzo Pieralisi, Rafael J. Wysocki, Daniel Lezcano,
	Christian Loehle, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Arnd Bergmann,
	Souvik Chakravarty, Andy Yan, Matthias Brugger, John Stultz,
	Moritz Fischer, Sudeep Holla, linux-pm, linux-kernel,
	linux-arm-msm, linux-arm-kernel, devicetree, Florian Fainelli,
	Krzysztof Kozlowski, Dmitry Baryshkov, Mukesh Ojha, Andre Draszik,
	Greg Kroah-Hartman, Kathiravan Thirumoorthy, Srinivas Kandagatla,
	Bartosz Golaszewski
In-Reply-To: <20260521112638.GD2921053@google.com>

On Thu, May 21, 2026 at 1:26 PM Lee Jones <lee@kernel.org> wrote:
>
> On Thu, 14 May 2026, Shivendra Pratap wrote:
>
> > MFD core has no way to register a child device using an explicit firmware
> > node. This prevents drivers from registering child nodes when those nodes
> > do not define a compatible string. One such example is the PSCI
> > "reboot-mode" node, which omits a compatible string as it describes
> > boot-states provided by the underlying firmware.
> >
> > Extend struct mfd_cell with a callback that allows drivers to provide an
> > explicit firmware node. The node is added to the MFD child device during
> > registration when none is assigned by device tree, ACPI, or software
> > matching.
> >
> > Suggested-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> > Signed-off-by: Shivendra Pratap <shivendra.pratap@oss.qualcomm.com>
> > ---
> >  drivers/mfd/mfd-core.c   | 30 ++++++++++++++++++++++++++++++
> >  include/linux/mfd/core.h | 14 ++++++++++++++
> >  2 files changed, 44 insertions(+)
> >
> > diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
> > index 7aa32b90cf1eb7fa0a05bf3dc506e60a262c9850..cc2a2a924d6d3044e29a9f864b536ee325ed797b 100644
> > --- a/drivers/mfd/mfd-core.c
> > +++ b/drivers/mfd/mfd-core.c
> > @@ -10,6 +10,7 @@
> >  #include <linux/kernel.h>
> >  #include <linux/platform_device.h>
> >  #include <linux/acpi.h>
> > +#include <linux/fwnode.h>
> >  #include <linux/list.h>
> >  #include <linux/property.h>
> >  #include <linux/mfd/core.h>
> > @@ -148,6 +149,11 @@ static int mfd_match_of_node_to_dev(struct platform_device *pdev,
> >       return 0;
> >  }
> >
> > +static void mfd_child_fwnode_put(void *data)
> > +{
> > +     fwnode_handle_put(data);
> > +}
> > +
> >  static int mfd_add_device(struct device *parent, int id,
> >                         const struct mfd_cell *cell,
> >                         struct resource *mem_base,
> > @@ -156,6 +162,7 @@ static int mfd_add_device(struct device *parent, int id,
> >       struct resource *res;
> >       struct platform_device *pdev;
> >       struct mfd_of_node_entry *of_entry, *tmp;
> > +     struct fwnode_handle *fwnode;
> >       bool disabled = false;
> >       int ret = -ENOMEM;
> >       int platform_id;
> > @@ -224,6 +231,29 @@ static int mfd_add_device(struct device *parent, int id,
> >
> >       mfd_acpi_add_device(cell, pdev);
> >
> > +     if (!pdev->dev.fwnode && cell->get_child_fwnode) {
> > +             fwnode = cell->get_child_fwnode(parent);
> > +             if (fwnode) {
> > +                     device_set_node(&pdev->dev, fwnode);
> > +
> > +                     /*
> > +                      * platform_device_release() drops only of_node refs.
> > +                      * Track non-OF fwnodes explicitly so they are put on
> > +                      * all teardown paths.
> > +                      */
> > +                     if (!to_of_node(fwnode)) {
> > +                             ret = devm_add_action(&pdev->dev,
> > +                                                   mfd_child_fwnode_put,
> > +                                                   fwnode);
> > +                             if (ret) {
> > +                                     device_set_node(&pdev->dev, NULL);
> > +                                     fwnode_handle_put(fwnode);
> > +                                     goto fail_of_entry;
> > +                             }
> > +                     }
> > +             }
> > +     }
>
> mfd_add_device() is getting very busy now with support for all of these
> different registration APIs.  Suggest that we start breaking them out.
>
> > +
> >       if (cell->pdata_size) {
> >               ret = platform_device_add_data(pdev,
> >                                       cell->platform_data, cell->pdata_size);
> > diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
> > index faeea7abd688f223fb0b31cde0a9b69dfe2a61ff..abfc26c057d6ee46947ba2b6f2e99f420e74b127 100644
> > --- a/include/linux/mfd/core.h
> > +++ b/include/linux/mfd/core.h
> > @@ -50,6 +50,7 @@
> >  #define MFD_DEP_LEVEL_HIGH 1
> >
> >  struct irq_domain;
> > +struct fwnode_handle;
> >  struct software_node;
> >
> >  /* Matches ACPI PNP id, either _HID or _CID, or ACPI _ADR */
> > @@ -80,6 +81,19 @@ struct mfd_cell {
> >
> >       /* Software node for the device. */
> >       const struct software_node *swnode;
> > +     /*
> > +      * Callback to return an explicit firmware node.
> > +      * @parent: MFD parent device passed to mfd_add_devices().
> > +      *
> > +      * Called only if OF/ACPI matching did not assign a fwnode.
> > +      * Ownership of the returned reference is transferred to MFD core.
> > +      *
> > +      * Return a referenced fwnode or NULL if none is available.
> > +      *
> > +      * mfd_cell must be zero-initialized or get_child_fwnode must be NULL
> > +      * when unused.
> > +      */
> > +     struct fwnode_handle *(*get_child_fwnode)(struct device *parent);
>
> I'm very much against pointers to functions if they can be avoided.  Why
> does fwnode need this and none of the other APIs do?
>

I suggested it because of its flexibility. The alternative I had in
mind is something like a new field in mfd_cell:

    const char *cell_node_name;

Which - if set - would tell MFD to look up an fwnode that's a child of
the parent device's node by name - as it may not have a compatible.

Bart


^ permalink raw reply

* [PATCH] arm: Implement _THIS_IP_ using inline asm
From: Marco Elver @ 2026-05-21 12:29 UTC (permalink / raw)
  To: elver, Russell King; +Cc: linux-arm-kernel, linux-kernel, kasan-dev

Both GCC [1] and Clang [2] consider the generic version of _THIS_IP_ to
be broken:

        #define _THIS_IP_  ({ __label__ __here; __here: (unsigned long)&&__here; })

In particular, the address of a label is only expected to be used with a
computed goto.

While the generic version more or less works today, it is known to be
brittle and may break with current and future optimizations. For
example, Clang -O2 always returns 1 when this function is inlined:

        static inline unsigned long get_ip(void)
        { return ({ __label__ __here; __here: (unsigned long)&&__here; }); }

Fix it by overriding _THIS_IP_ in <asm/linkage.h> (which is included by
<linux/instruction_pointer.h>) using an architecture-specific inline asm
version. Additionally, avoiding taking the address of a label prevents
compilers from emitting spurious indirect branch targets (e.g. ENDBR or
BTI) under control-flow integrity schemes.

Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120071 [1]
Link: https://github.com/llvm/llvm-project/issues/138272 [2]
Signed-off-by: Marco Elver <elver@google.com>
---
 arch/arm/include/asm/linkage.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/include/asm/linkage.h b/arch/arm/include/asm/linkage.h
index c4670694ada7..416e6a242dc4 100644
--- a/arch/arm/include/asm/linkage.h
+++ b/arch/arm/include/asm/linkage.h
@@ -9,4 +9,6 @@
   .type name, %function; \
   END(name)
 
+#define _THIS_IP_ ({ unsigned long __ip; asm volatile("1: adr %0, 1b" : "=r" (__ip)); __ip; })
+
 #endif
-- 
2.54.0.746.g67dd491aae-goog



^ permalink raw reply related

* Re: [PATCH v02] mailbox: pcc: report errors for PCC clients
From: lihuisong (C) @ 2026-05-21 12:26 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: Adam Young, Jassi Brar, linux-kernel, linux-hwmon,
	Rafael J . Wysocki, Len Brown, linux-acpi, Andi Shyti,
	Guenter Roeck, MyungJoo Ham, Kyungmin Park, Chanwoo Choi,
	linux-arm-kernel
In-Reply-To: <20260520-optimal-nightingale-of-champagne-0bbdfe@sudeepholla>


On 5/20/2026 9:32 PM, Sudeep Holla wrote:
> On Wed, May 20, 2026 at 07:53:45PM +0800, lihuisong (C) wrote:
>> On 5/20/2026 12:25 AM, Sudeep Holla wrote:
>>> On Tue, May 19, 2026 at 09:54:47PM +0800, lihuisong (C) wrote:
> [...]
>
>>>> @Sudeep, I have always had doubts about the addition of this line of code in
>>>> the
>>>>    commit 9c753f7c953c (mailbox: pcc: Mark Tx as complete in PCC IRQ handler).
>>>> The patch seems to avoid the timeouts in the mailbox core according to its
>>>> commit log.
>>>> Regardless of whether the command succeeds or fails, each mbox client
>>>> driver, like cppc_acpi/acpi_pcc,kunpeng_hccs and so on, is responsible to
>>>> call mbox_chan_txdone() to tell mailbox core.
>>> Few controller drivers do have mbox_chan_txdone(), so Tx complete is detected
>> Which controller driver?
> git grep mbox_chan_txdone drivers/mailbox/
Ok
>
>>> by PCC, so not sure why you think this is not the right place to do. The irq
>> Because many mbox client drivers call mbox_chan_txdone() after running
>> rx_callback() in mbox_chan_received_data().
> OK, but why can't the controller hide that for the clients ? What am I missing?
Now I know what you want to do.
It's ok for me to do that in controller on irq scene.
But we also need to fix the mbox_chan_txdone() code in all client drivers.
>
>> These drivers doesn't set chan->cl->tx_block to true.
>> It seems that the client driver having tx_block need to set
>> chan->tx_complete in tx_tick().
>> Do you add this code for them?
> I don't quite follow you.
please ship this.
>
>>> is to indicate the completion. I am confused as why you think otherwise.
>>> It is defined in include/linux/mailbox_controller.h for the same reason.
>>>
>>> The client drivers can you mbox_client_txdone() if they wish to as defined
>>> in include/linux/mailbox_client.h
>> mbox_client_txdone() is used in the case that txdone_method is
>> MBOX_TXDONE_BY_ACK.
> Yes and agreed.
>
>> And mbox clinte driver using IRQ method need to use mbox_chan_txdone().
> Client doesn't handle IRQ its always controller driver and client must have
> no business to do that IMO.
Ack
mbox_chan_txdone should be used by controller as this function comment 
said.
>
>> It seems that all the current client drivers are used in this way.
>> These interface internal would verify chan->txdone_method.
>>
> Yes, sounds wrong to me.
>
> drivers/acpi/acpi_pcc.c
> drivers/acpi/cppc_acpi.c
> drivers/hwmon/xgene-hwmon.c
> drivers/i2c/busses/i2c-xgene-slimpro.c
> drivers/soc/hisilicon/kunpeng_hccs.c
>
> It is very clear from the code in mailbox.c, mbox_client_txdone() is for
> the client drivers and mbox_chan_txdone() is for the controller. We need
> to fix the above list but I need to check if there is anything I am missing
> to understand first. Please let me know.
Agreed.
>
>> In addition, I find that you also modify the txdone_irq/poll in the commit
>> 3349f800609e (mailbox: pcc: Set txdone_irq/txdone_poll based on PCCT flags).
>> The txdone_method will change from MBOX_TXDONE_BY_ACK to MBOX_TXDONE_BY_POLL
>> on the platform using poll mode.
>> This may lead to the original mbox client driver printing exceptions in
>> mbox_client_txdone.
>> I haven't observed it based on the latest code yet, it's just code analysis.
> Right, I do remember seeing something and wonder if I moved to
> mbox_chan_txdone() in drivers/acpi/acpi_pcc.c for that reason. But if the
> expectations I have mentioned are correct, then we need to fix the framework
> to avoid throwing that warnings.
Yeah, we also need to do something for your another commit
3349f800609e (mailbox: pcc: Set txdone_irq/txdone_poll based on PCCT 
flags).
>


^ permalink raw reply

* Re: [PATCH v14 03/44] arm64: RME: Handle Granule Protection Faults (GPFs)
From: Marc Zyngier @ 2026-05-21 12:25 UTC (permalink / raw)
  To: Steven Price
  Cc: kvm, kvmarm, Catalin Marinas, Will Deacon, James Morse,
	Oliver Upton, Suzuki K Poulose, Zenghui Yu, linux-arm-kernel,
	linux-kernel, Joey Gouly, Alexandru Elisei, Christoffer Dall,
	Fuad Tabba, linux-coco, Ganapatrao Kulkarni, Gavin Shan,
	Shanker Donthineni, Alper Gun, Aneesh Kumar K . V, Emi Kisanuki,
	Vishal Annapurve, WeiLin.Chang, Lorenzo.Pieralisi2
In-Reply-To: <20260513131757.116630-4-steven.price@arm.com>

On Wed, 13 May 2026 14:17:11 +0100,
Steven Price <steven.price@arm.com> wrote:
> 
> If the host attempts to access granules that have been delegated for use
> in a realm these accesses will be caught and will trigger a Granule
> Protection Fault (GPF).
> 
> A fault during a page walk signals a bug in the kernel and is handled by
> oopsing the kernel. A non-page walk fault could be caused by user space
> having access to a page which has been delegated to the kernel and will
> trigger a SIGBUS to allow debugging why user space is trying to access a
> delegated page.
> 
> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
> Reviewed-by: Gavin Shan <gshan@redhat.com>
> Signed-off-by: Steven Price <steven.price@arm.com>
> ---
> Changes since v10:
>  * Don't call arm64_notify_die() in do_gpf() but simply return 1.
> Changes since v2:
>  * Include missing "Granule Protection Fault at level -1"
> ---
>  arch/arm64/mm/fault.c | 28 ++++++++++++++++++++++------
>  1 file changed, 22 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
> index 0f3c5c7ca054..6358ea4787ba 100644
> --- a/arch/arm64/mm/fault.c
> +++ b/arch/arm64/mm/fault.c
> @@ -905,6 +905,22 @@ static int do_tag_check_fault(unsigned long far, unsigned long esr,
>  	return 0;
>  }
>  
> +static int do_gpf_ptw(unsigned long far, unsigned long esr, struct pt_regs *regs)
> +{
> +	const struct fault_info *inf = esr_to_fault_info(esr);
> +
> +	die_kernel_fault(inf->name, far, esr, regs);
> +	return 0;
> +}
> +
> +static int do_gpf(unsigned long far, unsigned long esr, struct pt_regs *regs)
> +{
> +	if (!is_el1_instruction_abort(esr) && fixup_exception(regs, esr))
> +		return 0;
> +
> +	return 1;
> +}
> +
>  static const struct fault_info fault_info[] = {
>  	{ do_bad,		SIGKILL, SI_KERNEL,	"ttbr address size fault"	},
>  	{ do_bad,		SIGKILL, SI_KERNEL,	"level 1 address size fault"	},
> @@ -941,12 +957,12 @@ static const struct fault_info fault_info[] = {
>  	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 32"			},
>  	{ do_alignment_fault,	SIGBUS,  BUS_ADRALN,	"alignment fault"		},
>  	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 34"			},
> -	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 35"			},
> -	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 36"			},
> -	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 37"			},
> -	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 38"			},
> -	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 39"			},
> -	{ do_bad,		SIGKILL, SI_KERNEL,	"unknown 40"			},
> +	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level -1" },
> +	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 0" },
> +	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 1" },
> +	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 2" },
> +	{ do_gpf_ptw,		SIGKILL, SI_KERNEL,	"Granule Protection Fault at level 3" },
> +	{ do_gpf,		SIGBUS,  SI_KERNEL,	"Granule Protection Fault not on table walk" },

It wouldn't hurt to align the textual description with what we have
for other fault syndromes:

	"level X granule protection fault (translation table walk)"

for the PTW-trigger faults, and

	"granule protection fault"

for the non PTW case.

Thanks,

	M.

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


^ permalink raw reply

* [PATCH v9 4/4] coresight: cti: expose banked sysfs registers for Qualcomm extended CTI
From: Yingchao Deng @ 2026-05-21 12:16 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Leo Yan,
	Alexander Shishkin
  Cc: coresight, linux-arm-kernel, linux-kernel, linux-arm-msm,
	jinlong.mao, quic_yingdeng, tingwei.zhang, jie.gan, Yingchao Deng
In-Reply-To: <20260521-extended_cti-v9-0-d21f4f92c51e@oss.qualcomm.com>

Qualcomm extended CTI implements banked trigger status and integration
registers, where each bank covers 32 triggers. Multiple instances of
these registers are required to expose the full trigger space.

Add coresight_cti_reg_index(), coresight_cti_reg_rw_index(), and
coresight_cti_reg_wo_index() macros that carry the bank index in the
cs_off_attribute.index field, keeping the base offset and index
separate rather than encoding them together.

Add static sysfs entries for the banked CTI registers and control
their visibility based on the underlying hardware configuration.
Visibility is determined by comparing the attribute's index against
the number of banks implied by nr_trig_max (32 triggers per bank).
Registers beyond the hardware capacity are hidden, preserving the
existing ABI on standard ARM CTIs while exposing the full register
set on Qualcomm CTIs.

Signed-off-by: Yingchao Deng <yingchao.deng@oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-cti-sysfs.c | 58 +++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
index 7191a478b2da..feecc9d6563f 100644
--- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
@@ -207,6 +207,15 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
 	   }								\
 	})[0].attr.attr)
 
+#define coresight_cti_reg_index(name, offset, idx)			\
+	(&((struct cs_off_attribute[]) {				\
+	   {								\
+		__ATTR(name, 0444, coresight_cti_reg_show, NULL),	\
+		offset,							\
+		idx							\
+	   }								\
+	})[0].attr.attr)
+
 #define coresight_cti_reg_rw(name, offset)				\
 	(&((struct cs_off_attribute[]) {				\
 	   {								\
@@ -217,6 +226,16 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
 	   }								\
 	})[0].attr.attr)
 
+#define coresight_cti_reg_rw_index(name, offset, idx)			\
+	(&((struct cs_off_attribute[]) {				\
+	   {								\
+		__ATTR(name, 0644, coresight_cti_reg_show,		\
+		       coresight_cti_reg_store),			\
+		offset,							\
+		idx							\
+	   }								\
+	})[0].attr.attr)
+
 #define coresight_cti_reg_wo(name, offset)				\
 	(&((struct cs_off_attribute[]) {				\
 	   {								\
@@ -226,6 +245,15 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
 	   }								\
 	})[0].attr.attr)
 
+#define coresight_cti_reg_wo_index(name, offset, idx)			\
+	(&((struct cs_off_attribute[]) {				\
+	   {								\
+		__ATTR(name, 0200, NULL, coresight_cti_reg_store),	\
+		offset,							\
+		idx							\
+	   }								\
+	})[0].attr.attr)
+
 /* coresight management registers */
 static struct attribute *coresight_cti_mgmt_attrs[] = {
 	coresight_cti_reg(devaff0, CTIDEVAFF0),
@@ -515,18 +543,36 @@ static struct attribute *coresight_cti_regs_attrs[] = {
 	&dev_attr_appclear.attr,
 	&dev_attr_apppulse.attr,
 	coresight_cti_reg(triginstatus, CTITRIGINSTATUS),
+	coresight_cti_reg_index(triginstatus1, CTITRIGINSTATUS, 1),
+	coresight_cti_reg_index(triginstatus2, CTITRIGINSTATUS, 2),
+	coresight_cti_reg_index(triginstatus3, CTITRIGINSTATUS, 3),
 	coresight_cti_reg(trigoutstatus, CTITRIGOUTSTATUS),
+	coresight_cti_reg_index(trigoutstatus1, CTITRIGOUTSTATUS, 1),
+	coresight_cti_reg_index(trigoutstatus2, CTITRIGOUTSTATUS, 2),
+	coresight_cti_reg_index(trigoutstatus3, CTITRIGOUTSTATUS, 3),
 	coresight_cti_reg(chinstatus, CTICHINSTATUS),
 	coresight_cti_reg(choutstatus, CTICHOUTSTATUS),
 #ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS
 	coresight_cti_reg_rw(itctrl, CORESIGHT_ITCTRL),
 	coresight_cti_reg(ittrigin, ITTRIGIN),
+	coresight_cti_reg_index(ittrigin1, ITTRIGIN, 1),
+	coresight_cti_reg_index(ittrigin2, ITTRIGIN, 2),
+	coresight_cti_reg_index(ittrigin3, ITTRIGIN, 3),
 	coresight_cti_reg(itchin, ITCHIN),
 	coresight_cti_reg_rw(ittrigout, ITTRIGOUT),
+	coresight_cti_reg_rw_index(ittrigout1, ITTRIGOUT, 1),
+	coresight_cti_reg_rw_index(ittrigout2, ITTRIGOUT, 2),
+	coresight_cti_reg_rw_index(ittrigout3, ITTRIGOUT, 3),
 	coresight_cti_reg_rw(itchout, ITCHOUT),
 	coresight_cti_reg(itchoutack, ITCHOUTACK),
 	coresight_cti_reg(ittrigoutack, ITTRIGOUTACK),
+	coresight_cti_reg_index(ittrigoutack1, ITTRIGOUTACK, 1),
+	coresight_cti_reg_index(ittrigoutack2, ITTRIGOUTACK, 2),
+	coresight_cti_reg_index(ittrigoutack3, ITTRIGOUTACK, 3),
 	coresight_cti_reg_wo(ittriginack, ITTRIGINACK),
+	coresight_cti_reg_wo_index(ittriginack1, ITTRIGINACK, 1),
+	coresight_cti_reg_wo_index(ittriginack2, ITTRIGINACK, 2),
+	coresight_cti_reg_wo_index(ittriginack3, ITTRIGINACK, 3),
 	coresight_cti_reg_wo(itchinack, ITCHINACK),
 #endif
 	NULL,
@@ -537,10 +583,22 @@ static umode_t coresight_cti_regs_is_visible(struct kobject *kobj,
 {
 	struct device *dev = kobj_to_dev(kobj);
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	struct device_attribute *dev_attr;
+	struct cs_off_attribute *cti_attr;
+	int max_bank;
 
 	if (attr == &dev_attr_asicctl.attr && !drvdata->config.asicctl_impl)
 		return 0;
 
+	dev_attr = container_of(attr, struct device_attribute, attr);
+	if (dev_attr->show == coresight_cti_reg_show ||
+	    dev_attr->store == coresight_cti_reg_store) {
+		cti_attr = container_of(dev_attr, struct cs_off_attribute, attr);
+		max_bank = DIV_ROUND_UP(drvdata->config.nr_trig_max, 32);
+		if (cti_attr->index >= max_bank)
+			return 0;
+	}
+
 	return attr->mode;
 }
 

-- 
2.43.0



^ permalink raw reply related

* [PATCH v9 3/4] coresight: cti: add Qualcomm extended CTI identification and quirks
From: Yingchao Deng @ 2026-05-21 12:16 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Leo Yan,
	Alexander Shishkin
  Cc: coresight, linux-arm-kernel, linux-kernel, linux-arm-msm,
	jinlong.mao, quic_yingdeng, tingwei.zhang, jie.gan, Yingchao Deng
In-Reply-To: <20260521-extended_cti-v9-0-d21f4f92c51e@oss.qualcomm.com>

Qualcomm implements an extended variant of the ARM CoreSight CTI with a
different register layout and vendor-specific behavior. While the
programming model remains largely compatible, the register offsets differ
from the standard ARM CTI and require explicit handling.

Detect Qualcomm CTIs via the DEVARCH register and record this in the CTI
driver data. Introduce a small mapping layer to translate standard CTI
register offsets to Qualcomm-specific offsets, allowing the rest of the
driver to use a common register access path.

Additionally, handle a Qualcomm-specific quirk where the CLAIMSET
register is incorrectly initialized to a non-zero value, which can cause
tools or drivers to assume the component is already claimed. Clear the
register during probe to reflect the actual unclaimed state.

No functional change is intended for standard ARM CTI devices.

Co-developed-by: Jinlong Mao <jinlong.mao@oss.qualcomm.com>
Signed-off-by: Jinlong Mao <jinlong.mao@oss.qualcomm.com>
Signed-off-by: Yingchao Deng <yingchao.deng@oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-cti-core.c | 27 +++++++++-
 drivers/hwtracing/coresight/coresight-cti.h      |  7 ++-
 drivers/hwtracing/coresight/qcom-cti.h           | 65 ++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
index c5cc2706e241..2dac5eb4ecca 100644
--- a/drivers/hwtracing/coresight/coresight-cti-core.c
+++ b/drivers/hwtracing/coresight/coresight-cti-core.c
@@ -21,6 +21,7 @@
 
 #include "coresight-priv.h"
 #include "coresight-cti.h"
+#include "qcom-cti.h"
 
 /*
  * CTI devices can be associated with a PE, or be connected to CoreSight
@@ -45,6 +46,9 @@ static DEFINE_MUTEX(ect_mutex);
 static void __iomem *__reg_addr(struct cti_drvdata *drvdata, u32 off,
 				u32 index)
 {
+	if (unlikely(rvdata->is_qcom_cti))
+		off = cti_qcom_reg_off(off);
+
 	return drvdata->base + off + sizeof(u32) * index;
 }
 
@@ -172,6 +176,9 @@ void cti_write_intack(struct device *dev, u32 ackval)
 /* DEVID[19:16] - number of CTM channels */
 #define CTI_DEVID_CTMCHANNELS(devid_val) ((int) BMVAL(devid_val, 16, 19))
 
+/* DEVARCH[31:21] - ARCHITECT */
+#define CTI_DEVARCH_ARCHITECT(devarch_val) ((int)BMVAL(devarch_val, 21, 31))
+
 static int cti_set_default_config(struct device *dev,
 				  struct cti_drvdata *drvdata)
 {
@@ -702,6 +709,7 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
 	struct coresight_desc cti_desc;
 	struct coresight_platform_data *pdata = NULL;
 	struct resource *res = &adev->res;
+	u32 devarch;
 
 	/* driver data*/
 	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
@@ -726,6 +734,22 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
 
 	raw_spin_lock_init(&drvdata->spinlock);
 
+	devarch = readl_relaxed(drvdata->base + CORESIGHT_DEVARCH);
+	if (CTI_DEVARCH_ARCHITECT(devarch) == ARCHITECT_QCOM) {
+		drvdata->is_qcom_cti = true;
+		/*
+		 * QCOM CTI does not implement Claimtag functionality as
+		 * per CoreSight specification, but its CLAIMSET register
+		 * is incorrectly initialized to 0xF. This can mislead
+		 * tools or drivers into thinking the component is claimed.
+		 *
+		 * Reset CLAIMSET to 0 to reflect that no claims are active.
+		 */
+		CS_UNLOCK(drvdata->base);
+		writel_relaxed(0, drvdata->base + CORESIGHT_CLAIMSET);
+		CS_LOCK(drvdata->base);
+	}
+
 	/* initialise CTI driver config values */
 	ret = cti_set_default_config(dev, drvdata);
 	if (ret)
@@ -782,7 +806,8 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
 
 	/* all done - dec pm refcount */
 	pm_runtime_put(&adev->dev);
-	dev_info(&drvdata->csdev->dev, "CTI initialized\n");
+	dev_info(&drvdata->csdev->dev,
+		 "%sCTI initialized\n", drvdata->is_qcom_cti ? "QCOM " : "");
 	return 0;
 }
 
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h
index 98b8de8a3687..08ea6daf5b3c 100644
--- a/drivers/hwtracing/coresight/coresight-cti.h
+++ b/drivers/hwtracing/coresight/coresight-cti.h
@@ -54,10 +54,11 @@ struct fwnode_handle;
 /*
  * CTI CSSoc 600 has a max of 32 trigger signals per direction.
  * CTI CSSoc 400 has 8 IO triggers - other CTIs can be impl def.
+ * QCOM CTI supports up to 128 trigger signals per direction.
  * Max of in and out defined in the DEVID register.
  * - pick up actual number used from .dts parameters if present.
  */
-#define CTIINOUTEN_MAX		32
+#define CTIINOUTEN_MAX		128
 
 /**
  * Group of related trigger signals
@@ -168,6 +169,9 @@ struct cti_config {
  * @spinlock:	Control data access to one at a time.
  * @config:	Configuration data for this CTI device.
  * @node:	List entry of this device in the list of CTI devices.
+ * @is_qcom_cti: True if this CTI is a Qualcomm vendor-specific
+ *		 variant that requires register offset translation
+ *		 via cti_qcom_reg_off().
  */
 struct cti_drvdata {
 	void __iomem *base;
@@ -176,6 +180,7 @@ struct cti_drvdata {
 	raw_spinlock_t spinlock;
 	struct cti_config config;
 	struct list_head node;
+	bool is_qcom_cti;
 };
 
 /*
diff --git a/drivers/hwtracing/coresight/qcom-cti.h b/drivers/hwtracing/coresight/qcom-cti.h
new file mode 100644
index 000000000000..d3846613a0de
--- /dev/null
+++ b/drivers/hwtracing/coresight/qcom-cti.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _CORESIGHT_QCOM_CTI_H
+#define _CORESIGHT_QCOM_CTI_H
+
+#include "coresight-cti.h"
+
+#define ARCHITECT_QCOM 0x477
+
+/* CTI programming registers */
+#define QCOM_CTIINTACK		0x020
+#define QCOM_CTIAPPSET		0x004
+#define QCOM_CTIAPPCLEAR	0x008
+#define QCOM_CTIAPPPULSE	0x00C
+#define QCOM_CTIINEN		0x400
+#define QCOM_CTIOUTEN		0x800
+#define QCOM_CTITRIGINSTATUS	0x040
+#define QCOM_CTITRIGOUTSTATUS	0x060
+#define QCOM_CTICHINSTATUS	0x080
+#define QCOM_CTICHOUTSTATUS	0x084
+#define QCOM_CTIGATE		0x088
+#define QCOM_ASICCTL		0x08C
+/* Integration test registers */
+#define QCOM_ITCHINACK		0xE70
+#define QCOM_ITTRIGINACK	0xE80
+#define QCOM_ITCHOUT		0xE74
+#define QCOM_ITTRIGOUT		0xEA0
+#define QCOM_ITCHOUTACK		0xE78
+#define QCOM_ITTRIGOUTACK	0xEC0
+#define QCOM_ITCHIN		0xE7C
+#define QCOM_ITTRIGIN		0xEE0
+
+static inline u32 cti_qcom_reg_off(u32 offset)
+{
+	switch (offset) {
+	case CTIINTACK:		return QCOM_CTIINTACK;
+	case CTIAPPSET:		return QCOM_CTIAPPSET;
+	case CTIAPPCLEAR:	return QCOM_CTIAPPCLEAR;
+	case CTIAPPPULSE:	return QCOM_CTIAPPPULSE;
+	case CTIINEN:		return QCOM_CTIINEN;
+	case CTIOUTEN:		return QCOM_CTIOUTEN;
+	case CTITRIGINSTATUS:	return QCOM_CTITRIGINSTATUS;
+	case CTITRIGOUTSTATUS:	return QCOM_CTITRIGOUTSTATUS;
+	case CTICHINSTATUS:	return QCOM_CTICHINSTATUS;
+	case CTICHOUTSTATUS:	return QCOM_CTICHOUTSTATUS;
+	case CTIGATE:		return QCOM_CTIGATE;
+	case ASICCTL:		return QCOM_ASICCTL;
+	case ITCHINACK:		return QCOM_ITCHINACK;
+	case ITTRIGINACK:	return QCOM_ITTRIGINACK;
+	case ITCHOUT:		return QCOM_ITCHOUT;
+	case ITTRIGOUT:		return QCOM_ITTRIGOUT;
+	case ITCHOUTACK:	return QCOM_ITCHOUTACK;
+	case ITTRIGOUTACK:	return QCOM_ITTRIGOUTACK;
+	case ITCHIN:		return QCOM_ITCHIN;
+	case ITTRIGIN:		return QCOM_ITTRIGIN;
+
+	default:
+		return offset;
+	}
+}
+
+#endif  /* _CORESIGHT_QCOM_CTI_H */

-- 
2.43.0



^ permalink raw reply related

* [PATCH v9 2/4] coresight: cti: use __reg_addr() helper for register access
From: Yingchao Deng @ 2026-05-21 12:16 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Leo Yan,
	Alexander Shishkin
  Cc: coresight, linux-arm-kernel, linux-kernel, linux-arm-msm,
	jinlong.mao, quic_yingdeng, tingwei.zhang, jie.gan, Yingchao Deng
In-Reply-To: <20260521-extended_cti-v9-0-d21f4f92c51e@oss.qualcomm.com>

Introduce __reg_addr(drvdata, off, index) to compute MMIO addresses
from a base offset and a per-trigger index, replacing the function-like
CTIINEN(n)/CTIOUTEN(n) macros with base offsets and explicit index
arithmetic. Add reg_addr and reg_index_addr convenience macros for
zero-index and indexed access respectively.

Extend cs_off_attribute with a u32 index field and update
cti_read_single_reg() and cti_write_single_reg() to accept separate
offset and index parameters, allowing sysfs show/store handlers to
use the attribute's index field directly.

Signed-off-by: Yingchao Deng <yingchao.deng@oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-cti-core.c  | 45 ++++++++++++++---------
 drivers/hwtracing/coresight/coresight-cti-sysfs.c | 25 +++++++------
 drivers/hwtracing/coresight/coresight-cti.h       |  9 +++--
 drivers/hwtracing/coresight/coresight-priv.h      |  4 +-
 4 files changed, 50 insertions(+), 33 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
index 4e7d12bd2d3e..c5cc2706e241 100644
--- a/drivers/hwtracing/coresight/coresight-cti-core.c
+++ b/drivers/hwtracing/coresight/coresight-cti-core.c
@@ -42,6 +42,15 @@ static DEFINE_MUTEX(ect_mutex);
 #define csdev_to_cti_drvdata(csdev)	\
 	dev_get_drvdata(csdev->dev.parent)
 
+static void __iomem *__reg_addr(struct cti_drvdata *drvdata, u32 off,
+				u32 index)
+{
+	return drvdata->base + off + sizeof(u32) * index;
+}
+
+#define reg_addr(drvdata, off)		__reg_addr((drvdata), (off), 0)
+#define reg_index_addr(drvdata, off, i)	__reg_addr((drvdata), (off), (i))
+
 /* write set of regs to hardware - call with spinlock claimed */
 void cti_write_all_hw_regs(struct cti_drvdata *drvdata)
 {
@@ -55,16 +64,17 @@ void cti_write_all_hw_regs(struct cti_drvdata *drvdata)
 
 	/* write the CTI trigger registers */
 	for (i = 0; i < config->nr_trig_max; i++) {
-		writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i));
+		writel_relaxed(config->ctiinen[i],
+			       reg_index_addr(drvdata, CTIINEN, i));
 		writel_relaxed(config->ctiouten[i],
-			       drvdata->base + CTIOUTEN(i));
+			       reg_index_addr(drvdata, CTIOUTEN, i));
 	}
 
 	/* other regs */
-	writel_relaxed(config->ctigate, drvdata->base + CTIGATE);
+	writel_relaxed(config->ctigate, reg_addr(drvdata, CTIGATE));
 	if (config->asicctl_impl)
-		writel_relaxed(config->asicctl, drvdata->base + ASICCTL);
-	writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET);
+		writel_relaxed(config->asicctl, reg_addr(drvdata, ASICCTL));
+	writel_relaxed(config->ctiappset, reg_addr(drvdata, CTIAPPSET));
 
 	/* re-enable CTI */
 	writel_relaxed(1, drvdata->base + CTICONTROL);
@@ -122,21 +132,22 @@ static int cti_disable_hw(struct cti_drvdata *drvdata)
 	return 0;
 }
 
-u32 cti_read_single_reg(struct cti_drvdata *drvdata, int offset)
+u32 cti_read_single_reg(struct cti_drvdata *drvdata, u32 off, u32 index)
 {
-	int val;
+	u32 val;
 
 	CS_UNLOCK(drvdata->base);
-	val = readl_relaxed(drvdata->base + offset);
+	val = readl_relaxed(reg_index_addr(drvdata, off, index));
 	CS_LOCK(drvdata->base);
 
 	return val;
 }
 
-void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value)
+void cti_write_single_reg(struct cti_drvdata *drvdata, u32 off, u32 index,
+			  u32 value)
 {
 	CS_UNLOCK(drvdata->base);
-	writel_relaxed(value, drvdata->base + offset);
+	writel_relaxed(value, reg_index_addr(drvdata, off, index));
 	CS_LOCK(drvdata->base);
 }
 
@@ -149,7 +160,7 @@ void cti_write_intack(struct device *dev, u32 ackval)
 
 	/* write if enabled */
 	if (cti_is_active(config))
-		cti_write_single_reg(drvdata, CTIINTACK, ackval);
+		cti_write_single_reg(drvdata, CTIINTACK, 0, ackval);
 }
 
 /*
@@ -322,7 +333,7 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
 	struct cti_config *config = &drvdata->config;
 	u32 chan_bitmask;
 	u32 reg_value;
-	int reg_offset;
+	u32 reg_offset;
 
 	/* ensure indexes in range */
 	if ((channel_idx >= config->nr_ctm_channels) ||
@@ -344,8 +355,7 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
 
 	/* update the local register values */
 	chan_bitmask = BIT(channel_idx);
-	reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
-		      CTIOUTEN(trigger_idx));
+	reg_offset = (direction == CTI_TRIG_IN ? CTIINEN : CTIOUTEN);
 
 	guard(raw_spinlock_irqsave)(&drvdata->spinlock);
 
@@ -365,7 +375,8 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
 
 	/* write through if enabled */
 	if (cti_is_active(config))
-		cti_write_single_reg(drvdata, reg_offset, reg_value);
+		cti_write_single_reg(drvdata, reg_offset, trigger_idx,
+				     reg_value);
 
 	return 0;
 }
@@ -403,7 +414,7 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,
 	if (err == 0) {
 		config->ctigate = reg_value;
 		if (cti_is_active(config))
-			cti_write_single_reg(drvdata, CTIGATE, reg_value);
+			cti_write_single_reg(drvdata, CTIGATE, 0, reg_value);
 	}
 
 	return err;
@@ -452,7 +463,7 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
 	}
 
 	if ((err == 0) && cti_is_active(config))
-		cti_write_single_reg(drvdata, reg_offset, reg_value);
+		cti_write_single_reg(drvdata, reg_offset, 0, reg_value);
 
 	return err;
 }
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
index 2bbfa405cb6b..7191a478b2da 100644
--- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
@@ -171,7 +171,7 @@ static ssize_t coresight_cti_reg_show(struct device *dev,
 	pm_runtime_get_sync(dev->parent);
 
 	scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock)
-		val = cti_read_single_reg(drvdata, cti_attr->off);
+		val = cti_read_single_reg(drvdata, cti_attr->off, cti_attr->index);
 
 	pm_runtime_put_sync(dev->parent);
 	return sysfs_emit(buf, "0x%x\n", val);
@@ -192,7 +192,7 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
 	pm_runtime_get_sync(dev->parent);
 
 	scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock)
-		cti_write_single_reg(drvdata, cti_attr->off, val);
+		cti_write_single_reg(drvdata, cti_attr->off, cti_attr->index, val);
 
 	pm_runtime_put_sync(dev->parent);
 	return size;
@@ -202,7 +202,8 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
 	(&((struct cs_off_attribute[]) {				\
 	   {								\
 		__ATTR(name, 0444, coresight_cti_reg_show, NULL),	\
-		offset							\
+		offset,							\
+		0							\
 	   }								\
 	})[0].attr.attr)
 
@@ -211,7 +212,8 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
 	   {								\
 		__ATTR(name, 0644, coresight_cti_reg_show,		\
 		       coresight_cti_reg_store),			\
-		offset							\
+		offset,							\
+		0							\
 	   }								\
 	})[0].attr.attr)
 
@@ -219,7 +221,8 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
 	(&((struct cs_off_attribute[]) {				\
 	   {								\
 		__ATTR(name, 0200, NULL, coresight_cti_reg_store),	\
-		offset							\
+		offset,							\
+		0							\
 	   }								\
 	})[0].attr.attr)
 
@@ -257,7 +260,7 @@ static ssize_t cti_reg32_show(struct device *dev, char *buf,
 
 	scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) {
 		if (cti_is_active(config)) {
-			val = cti_read_single_reg(drvdata, reg_offset);
+			val = cti_read_single_reg(drvdata, reg_offset, 0);
 			if (pcached_val)
 				*pcached_val = val;
 		} else if (pcached_val) {
@@ -293,7 +296,7 @@ static ssize_t cti_reg32_store(struct device *dev, const char *buf,
 
 		/* write through if offset and enabled */
 		if (cti_is_active(config))
-			cti_write_single_reg(drvdata, reg_offset, val);
+			cti_write_single_reg(drvdata, reg_offset, 0, val);
 	}
 
 	return size;
@@ -386,7 +389,7 @@ static ssize_t inen_store(struct device *dev,
 
 	/* write through if enabled */
 	if (cti_is_active(config))
-		cti_write_single_reg(drvdata, CTIINEN(index), val);
+		cti_write_single_reg(drvdata, CTIINEN, index, val);
 
 	return size;
 }
@@ -427,7 +430,7 @@ static ssize_t outen_store(struct device *dev,
 
 	/* write through if enabled */
 	if (cti_is_active(config))
-		cti_write_single_reg(drvdata, CTIOUTEN(index), val);
+		cti_write_single_reg(drvdata, CTIOUTEN, index, val);
 
 	return size;
 }
@@ -469,7 +472,7 @@ static ssize_t appclear_store(struct device *dev,
 
 	/* write through if enabled */
 	if (cti_is_active(config))
-		cti_write_single_reg(drvdata, CTIAPPCLEAR, val);
+		cti_write_single_reg(drvdata, CTIAPPCLEAR, 0, val);
 
 	return size;
 }
@@ -490,7 +493,7 @@ static ssize_t apppulse_store(struct device *dev,
 
 	/* write through if enabled */
 	if (cti_is_active(config))
-		cti_write_single_reg(drvdata, CTIAPPPULSE, val);
+		cti_write_single_reg(drvdata, CTIAPPPULSE, 0, val);
 
 	return size;
 }
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h
index ef079fc18b72..98b8de8a3687 100644
--- a/drivers/hwtracing/coresight/coresight-cti.h
+++ b/drivers/hwtracing/coresight/coresight-cti.h
@@ -30,8 +30,8 @@ struct fwnode_handle;
 #define CTIAPPSET		0x014
 #define CTIAPPCLEAR		0x018
 #define CTIAPPPULSE		0x01C
-#define CTIINEN(n)		(0x020 + (4 * n))
-#define CTIOUTEN(n)		(0x0A0 + (4 * n))
+#define CTIINEN			0x020
+#define CTIOUTEN		0x0A0
 #define CTITRIGINSTATUS		0x130
 #define CTITRIGOUTSTATUS	0x134
 #define CTICHINSTATUS		0x138
@@ -217,8 +217,9 @@ int cti_enable(struct coresight_device *csdev, enum cs_mode mode,
 int cti_disable(struct coresight_device *csdev, struct coresight_path *path);
 void cti_write_all_hw_regs(struct cti_drvdata *drvdata);
 void cti_write_intack(struct device *dev, u32 ackval);
-void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value);
-u32 cti_read_single_reg(struct cti_drvdata *drvdata, int offset);
+void cti_write_single_reg(struct cti_drvdata *drvdata, u32 off, u32 index,
+			  u32 value);
+u32 cti_read_single_reg(struct cti_drvdata *drvdata, u32 off, u32 index);
 int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
 			enum cti_trig_dir direction, u32 channel_idx,
 			u32 trigger_idx);
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 770a8dc881b3..4aa25dda856c 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -68,6 +68,7 @@ struct cs_pair_attribute {
 struct cs_off_attribute {
 	struct device_attribute attr;
 	u32 off;
+	u32 index;
 };
 
 ssize_t coresight_simple_show32(struct device *_dev, struct device_attribute *attr, char *buf);
@@ -77,7 +78,8 @@ ssize_t coresight_simple_show_pair(struct device *_dev, struct device_attribute
 	(&((struct cs_off_attribute[]) {				\
 	   {								\
 		__ATTR(name, 0444, coresight_simple_show32, NULL),	\
-		offset							\
+		offset,							\
+		0							\
 	   }								\
 	})[0].attr.attr)
 

-- 
2.43.0



^ permalink raw reply related

* [PATCH v9 1/4] coresight: cti: Convert trigger usage fields to dynamic
From: Yingchao Deng @ 2026-05-21 12:16 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Leo Yan,
	Alexander Shishkin
  Cc: coresight, linux-arm-kernel, linux-kernel, linux-arm-msm,
	jinlong.mao, quic_yingdeng, tingwei.zhang, jie.gan, Yingchao Deng
In-Reply-To: <20260521-extended_cti-v9-0-d21f4f92c51e@oss.qualcomm.com>

Replace the fixed-size u32 fields in the cti_config and cti_trig_grp
structure with dynamically allocated bitmaps and arrays. This allows
memory to be allocated based on the actual number of triggers during probe
time, reducing memory footprint and improving scalability for platforms
with varying trigger counts.

Signed-off-by: Yingchao Deng <yingchao.deng@oss.qualcomm.com>
---
 drivers/hwtracing/coresight/coresight-cti-core.c   | 59 +++++++++++++++++-----
 .../hwtracing/coresight/coresight-cti-platform.c   | 26 +++++++---
 drivers/hwtracing/coresight/coresight-cti-sysfs.c  | 14 ++---
 drivers/hwtracing/coresight/coresight-cti.h        | 12 ++---
 4 files changed, 76 insertions(+), 35 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
index 2f4c9362709a..4e7d12bd2d3e 100644
--- a/drivers/hwtracing/coresight/coresight-cti-core.c
+++ b/drivers/hwtracing/coresight/coresight-cti-core.c
@@ -161,8 +161,8 @@ void cti_write_intack(struct device *dev, u32 ackval)
 /* DEVID[19:16] - number of CTM channels */
 #define CTI_DEVID_CTMCHANNELS(devid_val) ((int) BMVAL(devid_val, 16, 19))
 
-static void cti_set_default_config(struct device *dev,
-				   struct cti_drvdata *drvdata)
+static int cti_set_default_config(struct device *dev,
+				  struct cti_drvdata *drvdata)
 {
 	struct cti_config *config = &drvdata->config;
 	u32 devid;
@@ -181,6 +181,26 @@ static void cti_set_default_config(struct device *dev,
 		config->nr_trig_max = CTIINOUTEN_MAX;
 	}
 
+	config->trig_in_use = devm_bitmap_zalloc(dev, config->nr_trig_max, GFP_KERNEL);
+	if (!config->trig_in_use)
+		return -ENOMEM;
+
+	config->trig_out_use = devm_bitmap_zalloc(dev, config->nr_trig_max, GFP_KERNEL);
+	if (!config->trig_out_use)
+		return -ENOMEM;
+
+	config->trig_out_filter = devm_bitmap_zalloc(dev, config->nr_trig_max, GFP_KERNEL);
+	if (!config->trig_out_filter)
+		return -ENOMEM;
+
+	config->ctiinen = devm_kcalloc(dev, config->nr_trig_max, sizeof(u32), GFP_KERNEL);
+	if (!config->ctiinen)
+		return -ENOMEM;
+
+	config->ctiouten = devm_kcalloc(dev, config->nr_trig_max, sizeof(u32), GFP_KERNEL);
+	if (!config->ctiouten)
+		return -ENOMEM;
+
 	config->nr_ctm_channels = CTI_DEVID_CTMCHANNELS(devid);
 
 	/* Most regs default to 0 as zalloc'ed except...*/
@@ -189,6 +209,7 @@ static void cti_set_default_config(struct device *dev,
 	config->enable_req_count = 0;
 
 	config->asicctl_impl = !!FIELD_GET(GENMASK(4, 0), devid);
+	return 0;
 }
 
 /*
@@ -219,8 +240,10 @@ int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata,
 	cti_dev->nr_trig_con++;
 
 	/* add connection usage bit info to overall info */
-	drvdata->config.trig_in_use |= tc->con_in->used_mask;
-	drvdata->config.trig_out_use |= tc->con_out->used_mask;
+	bitmap_or(drvdata->config.trig_in_use, drvdata->config.trig_in_use,
+		  tc->con_in->used_mask, drvdata->config.nr_trig_max);
+	bitmap_or(drvdata->config.trig_out_use, drvdata->config.trig_out_use,
+		  tc->con_out->used_mask, drvdata->config.nr_trig_max);
 
 	return 0;
 }
@@ -231,6 +254,8 @@ struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,
 {
 	struct cti_trig_con *tc = NULL;
 	struct cti_trig_grp *in = NULL, *out = NULL;
+	struct cti_drvdata *drvdata = dev_get_drvdata(dev);
+	int n_trigs = drvdata->config.nr_trig_max;
 
 	tc = devm_kzalloc(dev, sizeof(struct cti_trig_con), GFP_KERNEL);
 	if (!tc)
@@ -242,12 +267,20 @@ struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,
 	if (!in)
 		return NULL;
 
+	in->used_mask = devm_bitmap_zalloc(dev, n_trigs, GFP_KERNEL);
+	if (!in->used_mask)
+		return NULL;
+
 	out = devm_kzalloc(dev,
 			   offsetof(struct cti_trig_grp, sig_types[out_sigs]),
 			   GFP_KERNEL);
 	if (!out)
 		return NULL;
 
+	out->used_mask = devm_bitmap_zalloc(dev, n_trigs, GFP_KERNEL);
+	if (!out->used_mask)
+		return NULL;
+
 	tc->con_in = in;
 	tc->con_out = out;
 	tc->con_in->nr_sigs = in_sigs;
@@ -263,7 +296,6 @@ int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata)
 {
 	int ret = 0;
 	int n_trigs = drvdata->config.nr_trig_max;
-	u32 n_trig_mask = GENMASK(n_trigs - 1, 0);
 	struct cti_trig_con *tc = NULL;
 
 	/*
@@ -274,8 +306,8 @@ int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata)
 	if (!tc)
 		return -ENOMEM;
 
-	tc->con_in->used_mask = n_trig_mask;
-	tc->con_out->used_mask = n_trig_mask;
+	bitmap_fill(tc->con_in->used_mask, n_trigs);
+	bitmap_fill(tc->con_out->used_mask, n_trigs);
 	ret = cti_add_connection_entry(dev, drvdata, tc, NULL, "default");
 	return ret;
 }
@@ -288,7 +320,6 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
 {
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	struct cti_config *config = &drvdata->config;
-	u32 trig_bitmask;
 	u32 chan_bitmask;
 	u32 reg_value;
 	int reg_offset;
@@ -298,18 +329,16 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
 	   (trigger_idx >= config->nr_trig_max))
 		return -EINVAL;
 
-	trig_bitmask = BIT(trigger_idx);
-
 	/* ensure registered triggers and not out filtered */
 	if (direction == CTI_TRIG_IN)	{
-		if (!(trig_bitmask & config->trig_in_use))
+		if (!(test_bit(trigger_idx, config->trig_in_use)))
 			return -EINVAL;
 	} else {
-		if (!(trig_bitmask & config->trig_out_use))
+		if (!(test_bit(trigger_idx, config->trig_out_use)))
 			return -EINVAL;
 
 		if ((config->trig_filter_enable) &&
-		    (config->trig_out_filter & trig_bitmask))
+		    test_bit(trigger_idx, config->trig_out_filter))
 			return -EINVAL;
 	}
 
@@ -687,7 +716,9 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
 	raw_spin_lock_init(&drvdata->spinlock);
 
 	/* initialise CTI driver config values */
-	cti_set_default_config(dev, drvdata);
+	ret = cti_set_default_config(dev, drvdata);
+	if (ret)
+		return ret;
 
 	pdata = coresight_cti_get_platform_data(dev);
 	if (IS_ERR(pdata)) {
diff --git a/drivers/hwtracing/coresight/coresight-cti-platform.c b/drivers/hwtracing/coresight/coresight-cti-platform.c
index d6d5388705c3..ba5a7e4b6bff 100644
--- a/drivers/hwtracing/coresight/coresight-cti-platform.c
+++ b/drivers/hwtracing/coresight/coresight-cti-platform.c
@@ -136,8 +136,8 @@ static int cti_plat_create_v8_etm_connection(struct device *dev,
 		goto create_v8_etm_out;
 
 	/* build connection data */
-	tc->con_in->used_mask = 0xF0; /* sigs <4,5,6,7> */
-	tc->con_out->used_mask = 0xF0; /* sigs <4,5,6,7> */
+	bitmap_set(tc->con_in->used_mask, 4, 4); /* sigs <4,5,6,7> */
+	bitmap_set(tc->con_out->used_mask, 4, 4); /* sigs <4,5,6,7> */
 
 	/*
 	 * The EXTOUT type signals from the ETM are connected to a set of input
@@ -194,10 +194,10 @@ static int cti_plat_create_v8_connections(struct device *dev,
 		goto of_create_v8_out;
 
 	/* Set the v8 PE CTI connection data */
-	tc->con_in->used_mask = 0x3; /* sigs <0 1> */
+	bitmap_set(tc->con_in->used_mask, 0, 2); /* sigs <0 1> */
 	tc->con_in->sig_types[0] = PE_DBGTRIGGER;
 	tc->con_in->sig_types[1] = PE_PMUIRQ;
-	tc->con_out->used_mask = 0x7; /* sigs <0 1 2 > */
+	bitmap_set(tc->con_out->used_mask, 0, 3); /* sigs <0 1 2 > */
 	tc->con_out->sig_types[0] = PE_EDBGREQ;
 	tc->con_out->sig_types[1] = PE_DBGRESTART;
 	tc->con_out->sig_types[2] = PE_CTIIRQ;
@@ -213,7 +213,7 @@ static int cti_plat_create_v8_connections(struct device *dev,
 		goto of_create_v8_out;
 
 	/* filter pe_edbgreq - PE trigout sig <0> */
-	drvdata->config.trig_out_filter |= 0x1;
+	set_bit(0, drvdata->config.trig_out_filter);
 
 of_create_v8_out:
 	return ret;
@@ -257,7 +257,7 @@ static int cti_plat_read_trig_group(struct cti_trig_grp *tgrp,
 	if (!err) {
 		/* set the signal usage mask */
 		for (idx = 0; idx < tgrp->nr_sigs; idx++)
-			tgrp->used_mask |= BIT(values[idx]);
+			set_bit(values[idx], tgrp->used_mask);
 	}
 
 	kfree(values);
@@ -316,24 +316,34 @@ static int cti_plat_process_filter_sigs(struct cti_drvdata *drvdata,
 {
 	struct cti_trig_grp *tg = NULL;
 	int err = 0, nr_filter_sigs;
+	int nr_trigs = drvdata->config.nr_trig_max;
 
 	nr_filter_sigs = cti_plat_count_sig_elements(fwnode,
 						     CTI_DT_FILTER_OUT_SIGS);
 	if (nr_filter_sigs == 0)
 		return 0;
 
-	if (nr_filter_sigs > drvdata->config.nr_trig_max)
+	if (nr_filter_sigs > nr_trigs)
 		return -EINVAL;
 
 	tg = kzalloc_obj(*tg);
 	if (!tg)
 		return -ENOMEM;
 
+	tg->used_mask = bitmap_zalloc(nr_trigs, GFP_KERNEL);
+	if (!tg->used_mask) {
+		kfree(tg);
+		return -ENOMEM;
+	}
+
 	tg->nr_sigs = nr_filter_sigs;
 	err = cti_plat_read_trig_group(tg, fwnode, CTI_DT_FILTER_OUT_SIGS);
 	if (!err)
-		drvdata->config.trig_out_filter |= tg->used_mask;
+		bitmap_or(drvdata->config.trig_out_filter,
+			  drvdata->config.trig_out_filter,
+			  tg->used_mask, nr_trigs);
 
+	bitmap_free(tg->used_mask);
 	kfree(tg);
 	return err;
 }
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
index 3fe2c916d228..2bbfa405cb6b 100644
--- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
@@ -719,12 +719,12 @@ static ssize_t trigout_filtered_show(struct device *dev,
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	struct cti_config *cfg = &drvdata->config;
 	int nr_trig_max = cfg->nr_trig_max;
-	unsigned long mask = cfg->trig_out_filter;
+	unsigned long *mask = cfg->trig_out_filter;
 
-	if (mask == 0)
+	if (bitmap_empty(mask, nr_trig_max))
 		return 0;
 
-	return sysfs_emit(buf, "%*pbl\n", nr_trig_max, &mask);
+	return sysfs_emit(buf, "%*pbl\n", nr_trig_max, mask);
 }
 static DEVICE_ATTR_RO(trigout_filtered);
 
@@ -931,9 +931,9 @@ static ssize_t trigin_sig_show(struct device *dev,
 	struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	struct cti_config *cfg = &drvdata->config;
-	unsigned long mask = con->con_in->used_mask;
+	unsigned long *mask = con->con_in->used_mask;
 
-	return sysfs_emit(buf, "%*pbl\n", cfg->nr_trig_max, &mask);
+	return sysfs_emit(buf, "%*pbl\n", cfg->nr_trig_max, mask);
 }
 
 static ssize_t trigout_sig_show(struct device *dev,
@@ -945,9 +945,9 @@ static ssize_t trigout_sig_show(struct device *dev,
 	struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	struct cti_config *cfg = &drvdata->config;
-	unsigned long mask = con->con_out->used_mask;
+	unsigned long *mask = con->con_out->used_mask;
 
-	return sysfs_emit(buf, "%*pbl\n", cfg->nr_trig_max, &mask);
+	return sysfs_emit(buf, "%*pbl\n", cfg->nr_trig_max, mask);
 }
 
 /* convert a sig type id to a name */
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h
index c5f9e79fabc6..ef079fc18b72 100644
--- a/drivers/hwtracing/coresight/coresight-cti.h
+++ b/drivers/hwtracing/coresight/coresight-cti.h
@@ -68,7 +68,7 @@ struct fwnode_handle;
  */
 struct cti_trig_grp {
 	int nr_sigs;
-	u32 used_mask;
+	unsigned long *used_mask;
 	int sig_types[];
 };
 
@@ -145,17 +145,17 @@ struct cti_config {
 	int enable_req_count;
 
 	/* registered triggers and filtering */
-	u32 trig_in_use;
-	u32 trig_out_use;
-	u32 trig_out_filter;
+	unsigned long *trig_in_use;
+	unsigned long *trig_out_use;
+	unsigned long *trig_out_filter;
 	bool trig_filter_enable;
 	u8 xtrig_rchan_sel;
 
 	/* cti cross trig programmable regs */
 	u32 ctiappset;
 	u8 ctiinout_sel;
-	u32 ctiinen[CTIINOUTEN_MAX];
-	u32 ctiouten[CTIINOUTEN_MAX];
+	u32 *ctiinen;
+	u32 *ctiouten;
 	u32 ctigate;
 	u32 asicctl;
 };

-- 
2.43.0



^ permalink raw reply related

* [PATCH v9 0/4] Add Qualcomm extended CTI support
From: Yingchao Deng @ 2026-05-21 12:16 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, Leo Yan,
	Alexander Shishkin
  Cc: coresight, linux-arm-kernel, linux-kernel, linux-arm-msm,
	jinlong.mao, quic_yingdeng, tingwei.zhang, jie.gan, Yingchao Deng

The Qualcomm extended CTI is a heavily parameterized version of ARM’s
CSCTI. It allows a debugger to send to trigger events to a processor or to
send a trigger event to one or more processors when a trigger event occurs
on another processor on the same SoC, or even between SoCs.

Qualcomm extended CTI supports up to 128 triggers. And some of the register
offsets are changed.

The commands to configure CTI triggers are the same as ARM's CTI.

Prerequisites:
   This series depends on the following CoreSight fix:
   [PATCH v2 1/1] coresight: fix issue where coresight component has no claimtags
Link: https://lore.kernel.org/all/20251027223545.2801-2-mike.leach@linaro.org/

Changes in v9:
1. rebase on top of linux-next-20260518.
2. patch 2: Replace the "encode index into offset high bits" scheme with a cleaner
   __reg_addr(drvdata, off, index) helper; update cti_read/write_single_reg() to
   take separate off and index arguments; add u32 index field to cs_off_attribute
   (moved to coresight-priv.h); drop CTI_REG_SET/GET/CLR_NR macros and
   <linux/bitfield.h>; update commit subject accordingly.
3. patch 4: Add three index-aware sysfs macros (coresight_cti_reg_index,
   _rw_index, _wo_index); replace string-matching visibility logic with
   cs_off_attribute.index field check;
Link to v8 - https://lore.kernel.org/all/20260426-extended-cti-v8-0-23b900a4902f@oss.qualcomm.com/

Changes in v8:
1. Rebased on top of linux-next-20260424.
2. patch 1: Use devm_bitmap_zalloc() with nr_trig_max instead of per-connection
   signal counts; add bitmap_zalloc() for filter trigger group.
3. patch 2: Add #include <linux/bitfield.h>; move CTIINOUTEN_MAX expansion
   to patch3.
4. patch 3: wrap CLAIMSET clear with CS_UNLOCK/CS_LOCK; move CTIINOUTEN_MAX
   to 128 here with comment; fix macro alignment in qcom-cti.h.
5. patch 4: Make qcom_suffix_registers[] static.
Link to v7 - https://lore.kernel.org/all/20260325-extended_cti-v7-0-bb406005089f@oss.qualcomm.com/

Changes in v7:
1. Split the extended CTI support into smaller, logically independent
   patches to improve reviewability.
2. Removed the dual offset-array based register access used in v6 for
   standard and Qualcomm CTIs. Register addressing is now unified through
   a single code path by encoding the register index together with the base
   offset and applying variant-specific translation at the final MMIO
   access point. 
3. Removed ext_reg_sel, extend the CTI sysfs interface to expose banked 
   register instances on Qualcomm CTIs only. Numbered sysfs nodes are
   hidden on standard ARM CTIs, and on Qualcomm CTIs their visibility is
   derived from nr_trig_max (32 triggers per bank), ensuring that only
   registers backed by hardware are exposed.
Link to v6 - https://lore.kernel.org/all/20251202-extended_cti-v6-0-ab68bb15c4f5@oss.qualcomm.com/

Changes in v6:
1. Rename regs_idx to ext_reg_sel and add information in documentation
   file.
2. Reset CLAIMSET to zero for qcom-cti during probe.
3. Retrieve idx value under spinlock.
4. Use yearless copyright for qcom-cti.h.
Link to v5 - https://lore.kernel.org/all/20251020-extended_cti-v5-0-6f193da2d467@oss.qualcomm.com/

Changes in v5:
1. Move common part in qcom-cti.h to coresight-cti.h.
2. Convert trigger usage fields to dynamic bitmaps and arrays.
3. Fix holes in struct cti_config to save some space.
4. Revert the previous changes related to the claim tag in
   cti_enable/disable_hw.
Link to v4 - https://lore.kernel.org/linux-arm-msm/20250902-extended_cti-v4-1-7677de04b416@oss.qualcomm.com/

Changes in v4:
1. Read the DEVARCH registers to identify Qualcomm CTI.
2. Add a reg_idx node, and refactor the coresight_cti_reg_show() and
coresight_cti_reg_store() functions accordingly.
3. The register offsets specific to Qualcomm CTI are moved to qcom_cti.h.
Link to v3 - https://lore.kernel.org/linux-arm-msm/20250722081405.2947294-1-quic_jinlmao@quicinc.com/

Changes in v3:
1. Rename is_extended_cti() to of_is_extended_cti().
2. Add the missing 'i' when write the CTI trigger registers.
3. Convert the multi-line output in sysfs to single line.
4. Initialize offset arrays using designated initializer.
Link to V2 - https://lore.kernel.org/all/20250429071841.1158315-3-quic_jinlmao@quicinc.com/

Changes in V2:
1. Add enum for compatible items.
2. Move offset arrays to coresight-cti-core

Signed-off-by: Yingchao Deng <yingchao.deng@oss.qualcomm.com>
---
Yingchao Deng (4):
      coresight: cti: Convert trigger usage fields to dynamic
      coresight: cti: use __reg_addr() helper for register access
      coresight: cti: add Qualcomm extended CTI identification and quirks
      coresight: cti: expose banked sysfs registers for Qualcomm extended CTI

 drivers/hwtracing/coresight/coresight-cti-core.c   | 131 ++++++++++++++++-----
 .../hwtracing/coresight/coresight-cti-platform.c   |  26 ++--
 drivers/hwtracing/coresight/coresight-cti-sysfs.c  |  97 ++++++++++++---
 drivers/hwtracing/coresight/coresight-cti.h        |  28 +++--
 drivers/hwtracing/coresight/coresight-priv.h       |   4 +-
 drivers/hwtracing/coresight/qcom-cti.h             |  65 ++++++++++
 6 files changed, 281 insertions(+), 70 deletions(-)
---
base-commit: f0d051a4a0ad6d37c1a88fee7f6a611f2e3dfa77
change-id: 20260520-extended_cti-305ed12f0348

Best regards,
-- 
Yingchao Deng <yingchao.deng@oss.qualcomm.com>



^ permalink raw reply

* Re: [PATCH v2 11/11] iio: dac: add mcf54415 DAC
From: Angelo Dureghello @ 2026-05-21 12:14 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Angelo Dureghello, Greg Ungerer, Geert Uytterhoeven, Steven King,
	Arnd Bergmann, Maxime Coquelin, Alexandre Torgue,
	Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Greg Ungerer, linux-m68k, linux-kernel, linux-stm32,
	linux-arm-kernel, linux-iio
In-Reply-To: <agTe7vZ94DnmD4Ed@ashevche-desk.local>

Hi Andy,

just few points below, the rest has been fixed:

On Wed, May 13, 2026 at 11:28:30PM +0300, Andy Shevchenko wrote:
> On Wed, May 13, 2026 at 11:14:35AM +0200, Angelo Dureghello wrote:
> >
> > Add basic version of mcf54415 DAC driver. DAC is embedded in the cpu and
> > DAC configuration registers are mapped in the internal IO address space.
> >
> > The DAC accepts a 12-bit digital signal and creates a monotonic 12-bit
> > analog output varying from DAC_VREFL to DAC_VREFH. The DAC module
> > consists of a conversion unit, an output amplifier, and the associated
> > digital control blocks. Default register values for DAC_VREFL and DAC_VREFH
> > are respectively 0 and 0xfff, left untouched in this initial version.
> >
> > This initial version of the driver is minimalistic, "output raw" only, to
> > be extended in the future. DMA and external sync are disabled, default mode
> > is high speed, default format is right-justified 12bit on 16bit word.
>
> ...
>
> > +#include <linux/array_size.h>
> > +#include <linux/bitfield.h>
> > +#include <linux/bits.h>
> > +#include <linux/clk.h>
> > +#include <linux/compiler_types.h>
> > +#include <linux/delay.h>
>
> + err.h
>
> > +#include <linux/io.h>
> > +#include <linux/module.h>
> > +#include <linux/mutex.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
>
> ...
>
> > +struct mcf54415_dac {
> > +	struct clk *clk;
> > +	struct regmap *map;
>
> I believe that regmap pointer is used more often, can you check with
> bloat-o-meter that swapping these two (by the order) gives any benefit in
> object size?
>

checking size in ColdFire arch with last kernel.org gcc had no benefit,
anyway put regmap before

> > +};
>
> ...
>
> > +	.max_register = 0x1F,
>
> No definition? What datasheet says about this? Perhaps define the MAX as per
> last defined register in the datasheet?
>
> > +};
>
> ...
>
> > +static void mcf54415_dac_init(struct mcf54415_dac *info)
> > +{
> > +	/* Keeping defaults and enable DAC (bit 0 set to 0) */
> > +	regmap_write(info->map, MCF54415_DAC_CR, MCF54415_DAC_CR_FILT |
> > +		     FIELD_PREP(MCF54415_DAC_CR_WMLVL, 1));
>
> Seems the whole driver ignores IO errors, why?
>
> > +	/* DAC is ready after 12us, from RM table 40-3  */
> > +	fsleep(12);
> > +}
>
> ...
>
> > +static void mcf54415_dac_exit(void *data)
> > +{
> > +	struct mcf54415_dac *info = data;
> > +
> > +	regmap_update_bits(info->map, MCF54415_DAC_CR, MCF54415_DAC_CR_PDN,
> > +			   MCF54415_DAC_CR_PDN);
>
> regmap_set_bits()
>
> > +}
>
> ...
>
> > +static int mcf54415_write_raw(struct iio_dev *indio_dev,
> > +			      struct iio_chan_spec const *chan,
> > +			      int val, int val2, long mask)
> > +{
> > +	struct mcf54415_dac *info = iio_priv(indio_dev);
> > +
> > +	switch (mask) {
> > +	case IIO_CHAN_INFO_RAW:
> > +		if (val < 0 || val > 4095)
>
> Do we have a definition for the resolution? I'm fine with the plain numbers,
> but it's better to add a short comment to say that this is "based on the
> resolution of XXX register per datasheet".
>
> > +			return -EINVAL;
> > +		regmap_write(info->map, MCF54415_DAC_DATA, val);
> > +		return 0;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
>
> ...
>
> > +static int mcf54415_dac_probe(struct platform_device *pdev)
> > +{
> > +	struct device *dev = &pdev->dev;
> > +	struct iio_dev *indio_dev;
> > +	struct mcf54415_dac *info;
> > +	void __iomem *regs;
> > +	int ret;
> > +
> > +	indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
> > +	if (!indio_dev)
> > +		return -ENOMEM;
> > +
> > +	info = iio_priv(indio_dev);
> > +
> > +	regs = devm_platform_ioremap_resource(pdev, 0);
> > +	if (IS_ERR(regs))
> > +		return dev_err_probe(dev, PTR_ERR(regs),
> > +				     "failed to get io regs\n");
>
> One line.
>

i decided to stay inside 80 in all the file, is it ok ?

> > +
> > +	info->map = devm_regmap_init_mmio(dev, regs,
> > +					  &mcf54415_dac_regmap_config);
> > +	if (IS_ERR(info->map))
> > +		return PTR_ERR(info->map);
> > +
> > +	info->clk = devm_clk_get_enabled(dev, "dac");
> > +	if (IS_ERR(info->clk))
> > +		return dev_err_probe(dev, PTR_ERR(info->clk),
> > +				     "failed getting clock\n");
>
> Also can be a single line, but this one a bit longer than above, gives
> 88 characters.

same as above

>
> > +	platform_set_drvdata(pdev, indio_dev);
> > +
> > +	indio_dev->name = "mcf54415";
> > +	indio_dev->info = &mcf54415_dac_iio_info;
> > +	indio_dev->modes = INDIO_DIRECT_MODE;
> > +	indio_dev->channels = mcf54415_dac_iio_channels;
> > +	indio_dev->num_channels = ARRAY_SIZE(mcf54415_dac_iio_channels);
> > +
> > +	mcf54415_dac_init(info);
> > +
> > +	ret = devm_add_action_or_reset(dev, mcf54415_dac_exit, info);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return devm_iio_device_register(dev, indio_dev);
> > +}
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
Regards,
angelo


^ permalink raw reply

* Re: [PATCH v4 4/5] KVM: arm64: Fix bounds checking in do_ffa_mem_reclaim()
From: Marc Zyngier @ 2026-05-21 12:12 UTC (permalink / raw)
  To: Mostafa Saleh
  Cc: op-tee, linux-kernel, kvmarm, linux-arm-kernel, oupton,
	joey.gouly, suzuki.poulose, catalin.marinas, jens.wiklander,
	sumit.garg, sebastianene, vdonnefort, sudeep.holla
In-Reply-To: <CAFgf54qpNVvzSiV89g12-4jWeacm=06LMjCooeU1Mt+3sqWDLQ@mail.gmail.com>

On Thu, 21 May 2026 11:43:58 +0100,
Mostafa Saleh <smostafa@google.com> wrote:
> 
> On Thu, May 21, 2026 at 11:30 AM Mostafa Saleh <smostafa@google.com> wrote:
> >
> > Hi Marc,
> >
> > On Thu, May 21, 2026 at 09:28:46AM +0100, Marc Zyngier wrote:
> > > On Wed, 20 May 2026 21:49:47 +0100,
> > > Mostafa Saleh <smostafa@google.com> wrote:
> > > >
> > > > Sashiko (locally) reports out of bound write possiblity if SPMD
> > > > returns an invalid data.
> > > >
> > > > While SPMD is considered trusted, pKVM does some basic checks,
> > > > for offset to be less than or equal len.
> > > >
> > > > However, that is incorrect as even if the offset is smaller than
> > > > len pKVM can still access out of bound memory in the next
> > > > ffa_host_unshare_ranges().
> > > >
> > > > Split this check into 2:
> > > > 1- Check that the fixed portion of the descriptor fits.
> > > > 2- After getting reg, check the variable array size addr_range_cnt
> > > >    fits.
> > > >
> > > > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > > > ---
> > > >  arch/arm64/kvm/hyp/nvhe/ffa.c | 7 ++++++-
> > > >  1 file changed, 6 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
> > > > index 1af722771178..e6aa2bfa63b1 100644
> > > > --- a/arch/arm64/kvm/hyp/nvhe/ffa.c
> > > > +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
> > > > @@ -607,7 +607,7 @@ static void do_ffa_mem_reclaim(struct arm_smccc_1_2_regs *res,
> > > >      * check that we end up with something that doesn't look _completely_
> > > >      * bogus.
> > > >      */
> > > > -   if (WARN_ON(offset > len ||
> > > > +   if (WARN_ON(offset + CONSTITUENTS_OFFSET(0) > len ||
> > > >                 fraglen > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE)) {
> > >
> > > Do you really want to keep this a WARN_ON(), given that this results
> > > in a panic in most pKVM configurations?
> >
> > Which kind of configuration will that check fail on?
> > Does that mean at the moment pKVM does out-of-bound access for
> > the header?
> >
> I might have misunderstood the point. I thought you meant the new
> change would cause a panic on most configurations, or were you
> suggesting just removing the WARN_ON?

Just dropping the WARN_ON(), because for most users, that means just
killing the machine (only configurations with debug will give you a
stack trace).

> I can do that, I just updated the current faulty check and left the
> WARN_ON as is.

I'd be all for that.

Thanks,

	M.

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


^ permalink raw reply

* Re: [PATCH] clocksource/drivers/owl: fix refcount leak
From: Markus Elfring @ 2026-05-21 12:10 UTC (permalink / raw)
  To: Alexander A. Klimov, linux-actions, linux-arm-kernel,
	Andreas Färber, Daniel Lezcano, Manivannan Sadhasivam,
	Thomas Gleixner
  Cc: LKML
In-Reply-To: <20260521041901.542964-1-grandmaster@al2klimov.de>

> Every value returned from of_clk_get() is supposed to be cleaned up
> via clk_put() once not needed anymore.

How do you think about to add a wording like “Thus add a missing function call.”?
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v7.1-rc4#n94

Would the application of another guard become helpful?

How will chances evolve to adjust variable scopes accordingly?
https://elixir.bootlin.com/linux/v7.1-rc4/source/drivers/clocksource/timer-owl.c#L116-L173

Regards,
Markus


^ permalink raw reply

* Re: [PATCH 2/2] kselftest/arm64: Add test for atomic futex uaccess with POE
From: Mark Brown @ 2026-05-21 12:06 UTC (permalink / raw)
  To: Kevin Brodsky
  Cc: linux-arm-kernel, Catalin Marinas, Joey Gouly, Shuah Khan,
	Will Deacon, linux-kernel, linux-kselftest
In-Reply-To: <c140c0da-4ad7-48ed-ad83-663ada282b14@arm.com>

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

On Thu, May 21, 2026 at 02:01:17PM +0200, Kevin Brodsky wrote:
> On 21/05/2026 13:22, Mark Brown wrote:

> > Doesn't matter while there's only one test but we should probably
> > munmap() this when we're done.

> Fair enough, I was being lazy :) A pkey_free() is also in order to be
> comprehensive, another wrapper to add. I considered using
> ../../mm/pkey-helpers.h but helpers there aren't implemented inline...
> Maybe refactoring for later.

There was another thread librifying the GUP helpers which might be a
good model:

   https://lore.kernel.org/linux-mm/20260521111801.173019-1-sarthak.sharma@arm.com/T/#t

I'm always a bit nervous about peering inside other selftest
directories, it can work well but some instances of it are relatively
frequent sources of regressions as people working in the main directory
don't think about users in other directories when doing updates.

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

^ permalink raw reply

* Re: [PATCH RESEND v3 1/6] drm/connector: report IRQ_HPD events to drm_connector_oob_hotplug_event()
From: Dmitry Baryshkov @ 2026-05-21 12:05 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
	Heikki Krogerus, Greg Kroah-Hartman, Andrzej Hajda,
	Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
	Jernej Skrabec, Adrien Grassein, Jani Nikula, Rodrigo Vivi,
	Joonas Lahtinen, Tvrtko Ursulin, Kevin Hilman, Jerome Brunet,
	Martin Blumenstingl, Rob Clark, Dmitry Baryshkov, Abhinav Kumar,
	Jessica Zhang, Sean Paul, Marijn Suijten, Tomi Valkeinen,
	Bjorn Andersson, Konrad Dybcio, Pengyu Luo, Nikita Travkin,
	Yongxing Mou, dri-devel, linux-kernel, linux-usb, intel-gfx,
	intel-xe, linux-amlogic, linux-arm-kernel, linux-arm-msm,
	freedreno
In-Reply-To: <20260521-funny-astonishing-mackerel-cc5a01@penduick>

On Thu, May 21, 2026 at 09:47:29AM +0200, Maxime Ripard wrote:
> On Wed, May 13, 2026 at 09:23:21PM +0300, Dmitry Baryshkov wrote:
> > The DisplayPort standard defines a special kind of events called IRQ.
> > These events are used to notify DP Source about the events on the Sink
> > side. It is extremely important for DP MST handling, where the MST
> > events are reported through this IRQ.
> > 
> > In case of the USB-C DP AltMode there is no actual HPD pulse, but the
> > events are ported through the bits in the AltMode VDOs.
> > 
> > Extend the drm_connector_oob_hotplug_event() interface and report IRQ
> > events to the DisplayPort Sink drivers.
> > 
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> > ---
> >  drivers/gpu/drm/drm_connector.c          |  5 ++++-
> >  drivers/usb/typec/altmodes/displayport.c | 15 +++++++++++----
> >  include/drm/drm_connector.h              | 19 ++++++++++++++++++-
> >  3 files changed, 33 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> > index 47dc53c4a738..edee9daccd51 100644
> > --- a/drivers/gpu/drm/drm_connector.c
> > +++ b/drivers/gpu/drm/drm_connector.c
> > @@ -3510,6 +3510,8 @@ struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode)
> >   * drm_connector_oob_hotplug_event - Report out-of-band hotplug event to connector
> >   * @connector_fwnode: fwnode_handle to report the event on
> >   * @status: hot plug detect logical state
> > + * @extra_status: additional information provided by the sink without changing
> > + * the HPD state (or in addition to such a change).
> >   *
> >   * On some hardware a hotplug event notification may come from outside the display
> >   * driver / device. An example of this is some USB Type-C setups where the hardware
> > @@ -3520,7 +3522,8 @@ struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode)
> >   * a drm_connector reference through calling drm_connector_find_by_fwnode().
> >   */
> >  void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode,
> > -				     enum drm_connector_status status)
> > +				     enum drm_connector_status status,
> > +				     enum drm_connector_status_extra extra_status)
> >  {
> >  	struct drm_connector *connector;
> >  
> > diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c
> > index 35d9c3086990..7182a8e2e710 100644
> > --- a/drivers/usb/typec/altmodes/displayport.c
> > +++ b/drivers/usb/typec/altmodes/displayport.c
> > @@ -189,7 +189,9 @@ static int dp_altmode_status_update(struct dp_altmode *dp)
> >  	} else {
> >  		drm_connector_oob_hotplug_event(dp->connector_fwnode,
> >  						hpd ? connector_status_connected :
> > -						      connector_status_disconnected);
> > +						      connector_status_disconnected,
> > +						(hpd && irq_hpd) ? DRM_CONNECTOR_DP_IRQ_HPD :
> > +								   DRM_CONNECTOR_NO_EXTRA_STATUS);
> 
> Since the extra status itself, and what the options mean, are DP specific, do we really want to
> extend drm_connector_oob_hotplug_event()? I think I'd prefer to have a DP specific variant, with its
> own set of parameters.

I can try arguing that drm_connector_oob_hotplug_event() is DP-specific,
there are no other users for it, only the DP AltMode driver.

Anyway, do you just mean new API here or new API and a new connector
callback?

-- 
With best wishes
Dmitry


^ permalink raw reply

* RE: [PATCH v3] i2c: imx: mark I2C adapter when hardware is powered down
From: Carlos Song (OSS) @ 2026-05-21 12:02 UTC (permalink / raw)
  To: Mukesh Savaliya, Carlos Song (OSS), o.rempel@pengutronix.de,
	kernel@pengutronix.de, andi.shyti@kernel.org, Frank Li,
	s.hauer@pengutronix.de, festevam@gmail.com, Carlos Song,
	Bough Chen
  Cc: linux-i2c@vger.kernel.org, imx@lists.linux.dev,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, stable@vger.kernel.org
In-Reply-To: <ab96c900-9c77-455a-88f1-b6d8d8e4ff78@oss.qualcomm.com>



> -----Original Message-----
> From: Mukesh Savaliya <mukesh.savaliya@oss.qualcomm.com>
> Sent: Thursday, May 21, 2026 7:14 PM
> To: Carlos Song (OSS) <carlos.song@oss.nxp.com>; Mukesh Savaliya
> <mukesh.savaliya@oss.qualcomm.com>; o.rempel@pengutronix.de;
> kernel@pengutronix.de; andi.shyti@kernel.org; Frank Li <frank.li@nxp.com>;
> s.hauer@pengutronix.de; festevam@gmail.com; Carlos Song
> <carlos.song@nxp.com>; Bough Chen <haibo.chen@nxp.com>
> Cc: linux-i2c@vger.kernel.org; imx@lists.linux.dev;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org;
> stable@vger.kernel.org
> Subject: Re: [PATCH v3] i2c: imx: mark I2C adapter when hardware is powered
> down
> 
> 
> On 5/21/2026 4:21 PM, Carlos Song (OSS) wrote:
> 
> [...]
> 
> >>>> -----Original Message-----
> >>>> From: Mukesh Savaliya <mukesh.savaliya@oss.qualcomm.com>
> >>>> Sent: Thursday, May 21, 2026 3:40 PM
> >>>> To: Carlos Song (OSS) <carlos.song@oss.nxp.com>;
> >>>> o.rempel@pengutronix.de; kernel@pengutronix.de;
> >>>> andi.shyti@kernel.org; Frank Li <frank.li@nxp.com>;
> >>>> s.hauer@pengutronix.de; festevam@gmail.com; Carlos Song
> >>>> <carlos.song@nxp.com>; Bough Chen <haibo.chen@nxp.com>
> >>>> Cc: linux-i2c@vger.kernel.org; imx@lists.linux.dev;
> >>>> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org;
> >>>> stable@vger.kernel.org
> >>>> Subject: Re: [PATCH v3] i2c: imx: mark I2C adapter when hardware is
> >>>> powered down
> >>>>
> >>>> Hi Carlos,
> >>>>
> >>>> On 5/20/2026 3:45 PM, Carlos Song (OSS) wrote:
> >>>>> From: Carlos Song <carlos.song@nxp.com>
> >>>>>
> >>>>> Mark the I2C adapter as suspended during system suspend to block
> >>>>> further transfers, and resume it on system resume. This prevents
> >>>>> potential hangs when the hardware is powered down but clients
> >>>>> still attempt
> >>>> I2C transfers.
> >>>>>
> >> what was the reason of this hang ? I was thinking you don't have
> >> interrupts working when client requested transfer but adapter was
> >> suspended. Please correct me if wrong.
> >>
> >> And it would be good to mention the actual problem and why/how it
> occurred.
> >>>> Code changes looks fine to me but have comment on commit log.
> >>>>
> >>>> It seems, you are adding support of _noirq() callbacks to allow
> >>>> transfers during suspend/resume noirq phase of PM.
> >>>>
> >>>> Would it make sense if you can write "Replace system PM callbacks
> >>>> with noirq PM callbacks" OR "Allow transfers during _noirq phase of
> >>>> the PM ops" instead of "mark I2C adapter when hardware is powered
> >> down" ?
> >>>>
> >>>
> >>> Hi,
> >>>
> >>> Thank you for your comments!
> >>>
> >>> But this patch is added is not for support noirq PM callback or
> >>> transfer in noirq
> >> phase.
> >>>
> >> Okay, may be actual problem description can help me.
> >>> In fact, this fix is to mark the I2C adapter as suspended during
> >>> system noirq suspend to block further transfers, and resume it on
> >>> system noirq resume. This is to prohibit I2C device calling the I2C
> >>> controller after the system noirq suspend and before noirq resume,
> >>> because at
> >> this time the I2C instance is powered off or the clock is disabled
> >> ... So I want to keep current commit. How do you think?
> >> completely Makes sense. Please help add how this problem occurred and
> why ?
> >> So the change/fix will be good to understand against it.
> >
> > Hi,
> >
> > In some I.MX platform, some I2C devices will keep a work queue all
> > time, the work queue will trigger I2C xfer every once in a while, but the work
> queue shouldn't be free in system suspend.
> >
> 
> work queue has transfers queued even if system is suspended ? IMO, the client
> i2c devices should not let system go to suspend.
> 

Hi Mukesh,

Thank you for the detailed discussion.

Yes, I totally agree that I2C client drivers should ideally stop
issuing transfers when the system is suspending.

However, in practice there are many different I2C clients, and not all
of them strictly adhere to this requirement. Some clients may still
trigger transfers through workqueues or deferred contexts during the
suspend/resume window.

Therefore, adding this protection at the I2C controller side helps to
avoid unexpected accesses when the hardware resources are unavailable,
making the system more robust.

> > Within a very short time window, possibly from noirq_suspend to the
> > system actually being suspended, or possibly from the system starting
> > to resume to before noirq_resume, this work queue will trigger an I2C
> > transfer, and at this time the I2C controller's clk and pinctrl have
> > not yet been restored, reading and
> 
> Right, this kind of explains the problem to me. I think you are trying to serve
> i2c transfers when your resources(clk, pinctrl) are not turned ON and also
> interrupt remains disabled. And that's why you need to add
> _noir() PM callbacks supports along with IRQF_NO_SUSPEND |
> IRQF_EARLY_RESUME flags.
> 
> > writing I2C registers causes the system to hang. This patch make all
> > I2C operations are performed in a safe hardware state.
> >
> > Is it better if I add these comment to patch commit log?
> >>>
> if my latest comments makes sense against the issue, you may write
> accordingly. if i am wrong, then your explanation makes sense. Cause of the
> hang needs to be clearly mention int the commit log in your next patch.
> 

Based on our discussion, I have updated the commit log as below:

On some i.MX platforms, certain I2C client drivers keep a periodic
workqueue which continues to trigger I2C transfers.

During system suspend/resume, there exists a time window between:
  - noirq_suspend and full suspend
  - resume start and noirq_resume

In this window, the I2C controller resources such as clock and pinctrl
may already be disabled or not yet restored.

If a workqueue triggers an I2C transfer in this period, the driver
attempts to access I2C registers while the hardware resources are
unavailable, which may lead to system hang.

Mark the I2C adapter as suspended during noirq suspend and block new
transfers until resume, ensuring that I2C transfers are only issued
when hardware resources are available.

Does this look good to you?

> >>
> >


^ permalink raw reply

* Re: [PATCH 2/2] kselftest/arm64: Add test for atomic futex uaccess with POE
From: Kevin Brodsky @ 2026-05-21 12:01 UTC (permalink / raw)
  To: Mark Brown
  Cc: linux-arm-kernel, Catalin Marinas, Joey Gouly, Shuah Khan,
	Will Deacon, linux-kernel, linux-kselftest
In-Reply-To: <8fc7713d-6451-4f05-86cd-df833cedd94b@sirena.org.uk>

On 21/05/2026 13:22, Mark Brown wrote:
> On Thu, May 21, 2026 at 10:42:31AM +0100, Kevin Brodsky wrote:
>
>> Add a new test to ensure that atomic futex uaccess succeeds on
>> memory mapped with a non-default POIndex/pkey.
>> +	ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
>> +		   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
>> +	ASSERT_NE(ptr, MAP_FAILED);
> Doesn't matter while there's only one test but we should probably
> munmap() this when we're done.

Fair enough, I was being lazy :) A pkey_free() is also in order to be
comprehensive, another wrapper to add. I considered using
../../mm/pkey-helpers.h but helpers there aren't implemented inline...
Maybe refactoring for later.

- Kevin


^ permalink raw reply

* Re: [PATCH v4 13/13] x86/amd-gart: preserve the direct DMA address until GART mapping succeeds
From: Aneesh Kumar K.V @ 2026-05-21 11:54 UTC (permalink / raw)
  To: iommu, linux-arm-kernel, linux-kernel, linux-coco
  Cc: Robin Murphy, Marek Szyprowski, Will Deacon, Marc Zyngier,
	Steven Price, Suzuki K Poulose, Catalin Marinas, Jiri Pirko,
	Jason Gunthorpe, Mostafa Saleh, Petr Tesarik,
	Alexey Kardashevskiy, Dan Williams, Xu Yilun, linuxppc-dev,
	linux-s390, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
	Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger, Sven Schnelle, x86
In-Reply-To: <20260512090408.794195-14-aneesh.kumar@kernel.org>

"Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org> writes:

> gart_alloc_coherent() first allocates memory through dma_direct_alloc(),
> which returns a direct-mapped DMA address in dma_addr. When force_iommu is
> enabled, the buffer is then remapped.
>
> Do not overwrite dma_addr before dma_map_area() has succeeded. Keep the
> dma_map_area result in a temporary variable so the direct DMA address
> remains available for dma_direct_free() on the error path.
>
> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
> ---
>  arch/x86/kernel/amd_gart_64.c | 10 ++++++----
>  1 file changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/kernel/amd_gart_64.c b/arch/x86/kernel/amd_gart_64.c
> index b5f1f031d45b..a109649c5649 100644
> --- a/arch/x86/kernel/amd_gart_64.c
> +++ b/arch/x86/kernel/amd_gart_64.c
> @@ -467,18 +467,20 @@ gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr,
>  		    gfp_t flag, unsigned long attrs)
>  {
>  	void *vaddr;
> +	dma_addr_t dma_map_addr;
>  
>  	vaddr = dma_direct_alloc(dev, size, dma_addr, flag, attrs);
>  	if (!vaddr ||
>  	    !force_iommu || dev->coherent_dma_mask <= DMA_BIT_MASK(24))
>  		return vaddr;
>  
> -	*dma_addr = dma_map_area(dev, virt_to_phys(vaddr), size,
> -				 DMA_BIDIRECTIONAL,
> -				 (1UL << get_order(size)) - 1, attrs);
> +	dma_map_addr = dma_map_area(dev, virt_to_phys(vaddr), size,
> +				     DMA_BIDIRECTIONAL,
> +				     (1UL << get_order(size)) - 1, attrs);
>  	flush_gart();
> -	if (unlikely(*dma_addr == DMA_MAPPING_ERROR))
> +	if (unlikely(dma_map_addr == DMA_MAPPING_ERROR))
>  		goto out_free;
> +	*dma_addr = dma_map_addr;
>  	return vaddr;
>  out_free:
>  	dma_direct_free(dev, size, vaddr, *dma_addr, attrs);
> -- 
> 2.43.0
>

This needs corresponding changes on the gart_free_coherent() side as well.

https://sashiko.dev/#/patchset/20260512090408.794195-1-aneesh.kumar%40kernel.org?part=13

I will avoid making that change as part of this series, since I assume
it would require specific testing.

-aneesh


^ permalink raw reply

* Re: [PATCH v4 4/6] media: synopsys: Add PHY stopstate wait for i.MX93
From: Alexander Stein @ 2026-05-21 11:52 UTC (permalink / raw)
  To: Michael Riesch, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
	Laurent Pinchart, Frank Li, Sakari Ailus, Bryan O'Donoghue,
	Mehdi Djait, Hans Verkuil, G.N. Zhou (OSS), G.N. Zhou (OSS)
  Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org,
	devicetree@vger.kernel.org, imx@lists.linux.dev,
	linux-arm-kernel@lists.infradead.org,
	linux-rockchip@lists.infradead.org, G.N. Zhou (OSS)
In-Reply-To: <AS8PR04MB9080D3B1A6B522F3F9342E23FA0E2@AS8PR04MB9080.eurprd04.prod.outlook.com>

Hi,

thanks for the replay.

Am Donnerstag, 21. Mai 2026, 11:29:39 CEST schrieb G.N. Zhou (OSS):
> Hi Alexander,
> 
> > -----Original Message-----
> > From: Alexander Stein <alexander.stein@ew.tq-group.com>
> > Sent: Wednesday, May 20, 2026 7:12 PM
> > To: Michael Riesch <michael.riesch@collabora.com>; Mauro Carvalho Chehab
> > <mchehab@kernel.org>; Rob Herring <robh@kernel.org>; Krzysztof Kozlowski
> > <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Heiko Stuebner
> > <heiko@sntech.de>; Laurent Pinchart <laurent.pinchart@ideasonboard.com>;
> > Frank Li <frank.li@nxp.com>; Sakari Ailus <sakari.ailus@linux.intel.com>; Bryan
> > O'Donoghue <bryan.odonoghue@linaro.org>; Mehdi Djait
> > <mehdi.djait@linux.intel.com>; Hans Verkuil <hverkuil+cisco@kernel.org>;
> > G.N. Zhou (OSS) <guoniu.zhou@oss.nxp.com>
> > Cc: linux-media@vger.kernel.org; linux-kernel@vger.kernel.org;
> > devicetree@vger.kernel.org; imx@lists.linux.dev; linux-arm-
> > kernel@lists.infradead.org; linux-rockchip@lists.infradead.org; G.N. Zhou (OSS)
> > <guoniu.zhou@oss.nxp.com>
> > Subject: Re: [PATCH v4 4/6] media: synopsys: Add PHY stopstate wait for
> > i.MX93
> > 
> > Hi,
> > 
> > Am Dienstag, 19. Mai 2026, 04:07:41 CEST schrieb Guoniu Zhou:
> > > Implement waiting for D-PHY lanes to enter stop state on i.MX93. This
> > > ensures proper PHY initialization by verifying that the clock lane and
> > > all active data lanes have entered the stop state before proceeding
> > > with further operations.
> > >
> > > Reviewed-by: Frank Li <Frank.Li@nxp.com>
> > > Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
> > > ---
> > > Changes in v2:
> > > - Removes redundant register availability check
> > > - Uses read_poll_timeout() with dw_mipi_csi2rx_read() instead of
> > >   readl_poll_timeout() with direct register address
> > > - Fixes stopstate condition logic
> > > - Check PHY stopstate after sensor enable instead of before to ensure
> > >   correct timing.
> > > - Optimize PHY stopstate polling parameters (1000us->10us, 2s->1ms) to
> > >   balance performance and responsiveness.
> > > ---
> > >  drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 36
> > > ++++++++++++++++++++++++
> > >  1 file changed, 36 insertions(+)
> > >
> > > diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
> > > b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
> > > index 92178a3dec5d..8a34aec550ad 100644
> > > --- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
> > > +++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
> > > @@ -11,6 +11,7 @@
> > >  #include <linux/clk.h>
> > >  #include <linux/delay.h>
> > >  #include <linux/io.h>
> > > +#include <linux/iopoll.h>
> > >  #include <linux/module.h>
> > >  #include <linux/of.h>
> > >  #include <linux/phy/phy.h>
> > > @@ -35,6 +36,8 @@
> > >  #define DW_REG_EXIST		BIT(31)
> > >  #define DW_REG(x)		(DW_REG_EXIST | (x))
> > >
> > > +#define DPHY_STOPSTATE_CLK_LANE		BIT(16)
> > > +
> > >  #define DPHY_TEST_CTRL0_TEST_CLR	BIT(0)
> > >
> > >  #define IPI_VCID_VC(x)			FIELD_PREP(GENMASK(1, 0),
> > (x))
> > > @@ -65,6 +68,7 @@ enum dw_mipi_csi2rx_regs_index {
> > >  	DW_MIPI_CSI2RX_PHY_TST_CTRL0,
> > >  	DW_MIPI_CSI2RX_PHY_TST_CTRL1,
> > >  	DW_MIPI_CSI2RX_PHY_SHUTDOWNZ,
> > > +	DW_MIPI_CSI2RX_PHY_STOPSTATE,
> > >  	DW_MIPI_CSI2RX_IPI_DATATYPE,
> > >  	DW_MIPI_CSI2RX_IPI_MEM_FLUSH,
> > >  	DW_MIPI_CSI2RX_IPI_MODE,
> > > @@ -87,6 +91,7 @@ struct dw_mipi_csi2rx_drvdata {
> > >  	void (*dphy_assert_reset)(struct dw_mipi_csi2rx_device *csi2);
> > >  	void (*dphy_deassert_reset)(struct dw_mipi_csi2rx_device *csi2);
> > >  	void (*ipi_enable)(struct dw_mipi_csi2rx_device *csi2);
> > > +	int (*wait_for_phy_stopstate)(struct dw_mipi_csi2rx_device *csi2);
> > >  };
> > >
> > >  struct dw_mipi_csi2rx_format {
> > > @@ -139,6 +144,7 @@ static const u32 imx93_regs[DW_MIPI_CSI2RX_MAX]
> > = {
> > >  	[DW_MIPI_CSI2RX_PHY_SHUTDOWNZ] = DW_REG(0x40),
> > >  	[DW_MIPI_CSI2RX_DPHY_RSTZ] = DW_REG(0x44),
> > >  	[DW_MIPI_CSI2RX_PHY_STATE] = DW_REG(0x48),
> > > +	[DW_MIPI_CSI2RX_PHY_STOPSTATE] = DW_REG(0x4c),
> > >  	[DW_MIPI_CSI2RX_PHY_TST_CTRL0] = DW_REG(0x50),
> > >  	[DW_MIPI_CSI2RX_PHY_TST_CTRL1] = DW_REG(0x54),
> > >  	[DW_MIPI_CSI2RX_IPI_MODE] = DW_REG(0x80), @@ -556,10 +562,19
> > @@
> > > static int dw_mipi_csi2rx_enable_streams(struct v4l2_subdev *sd,
> > >  	if (ret)
> > >  		goto err_csi_stop;
> > >
> > > +	if (!csi2->enabled_streams &&
> > > +	    csi2->drvdata->wait_for_phy_stopstate) {
> > > +		ret = csi2->drvdata->wait_for_phy_stopstate(csi2);
> > > +		if (ret)
> > > +			goto err_disable_streams;
> > > +	}
> > > +
> > >  	csi2->enabled_streams |= streams_mask;
> > >
> > >  	return 0;
> > >
> > > +err_disable_streams:
> > > +	v4l2_subdev_disable_streams(remote_sd, remote_pad->index, mask);
> > >  err_csi_stop:
> > >  	/* Stop CSI hardware if no streams are enabled */
> > >  	if (!csi2->enabled_streams)
> > > @@ -871,11 +886,32 @@ static void imx93_csi2rx_dphy_ipi_enable(struct
> > dw_mipi_csi2rx_device *csi2)
> > >  	dw_mipi_csi2rx_write(csi2, DW_MIPI_CSI2RX_IPI_MODE, val);  }
> > >
> > > +static int imx93_csi2rx_wait_for_phy_stopstate(struct
> > > +dw_mipi_csi2rx_device *csi2) {
> > > +	struct device *dev = csi2->dev;
> > > +	u32 stopstate_mask;
> > > +	u32 val;
> > > +	int ret;
> > > +
> > > +	stopstate_mask = DPHY_STOPSTATE_CLK_LANE | GENMASK(csi2-
> > >lanes_num -
> > > +1, 0);
> > > +
> > > +	ret = read_poll_timeout(dw_mipi_csi2rx_read, val,
> > > +				(val & stopstate_mask) == stopstate_mask,
> > > +				 10, 1000, true,
> > > +				 csi2, DW_MIPI_CSI2RX_PHY_STOPSTATE);
> > > +	if (ret)
> > > +		dev_err(dev, "lanes are not in stop state: %#x,
> > expected %#x\n",
> > > +			val, stopstate_mask);
> > 
> > Did you actually test this on imx93? I'm trying to get my imx327 sensor to run,
> > but only run into this error message:
> > dw-mipi-csi2rx 4ae00000.mipi-csi: lanes are not in stop state: 0x0, expected
> > 0x10003
> 
> Thanks for testing. Regarding the lane stop state error on i.MX93 with imx327:
> 
> This error indicates the CSI-2 lanes are not in LP-11 (stop) state when 
> expected. Please check:
> 
> 1) Verify the sensor PHY is in LP-11 state before returning from the sensor's 
>    s_stream(1) call. The CSI-2 receiver expects lanes to be in stop state 
>    initially.

Well, this might be tricky as I don't have D-PHY capable scopes.
I can successfully use this sensor on a imx8mp, so I am expecting this to be
okay.

> 2) Check if the imx327 driver has a delay between starting the stream and 
>    returning from s_stream(). If the sensor transitions PHY out of LP-11 
>    state during this delay, the CSI driver's lane state check will fail 
>    when it runs later. The sensor should remain in LP-11 until the CSI 
>    controller completes its initialization.

In imx290_set_stream() and subsequently imx290_start_streaming() setting
IMX290_XMSTA starts the stream. I expect this is the point when the sensors
switches from LP-11 to HS. But again, I can't verify.

With enabling debug
> echo "module videodev +p" > /sys/kernel/debug/dynamic_debug/control
> echo 0xff > /sys/class/video4linux/video0/dev_debug

After I setup the media pipeline, running the command
> v4l2-ctl -z "platform:4ae40000.isi" -d "mxc_isi.0.capture" --stream-mmap --stream-count=1 --stream-to=imx93.raw
I get the following debug output:

--8<--
plane 0: bytesperline=3840 sizeimage=4147200
mxc-isi 4ae40000.isi: validating link "crossbar":2 -> "mxc_isi.0":0
mxc-isi 4ae40000.isi: validating stream "crossbar":2:0 -> "mxc_isi.0":0:0
mxc-isi 4ae40000.isi: validating link "dw-mipi-csi2rx 4ae00000.mipi-csi":1 -> "crossbar":0
mxc-isi 4ae40000.isi: validating stream "dw-mipi-csi2rx 4ae00000.mipi-csi":1:0 -> "crossbar":0:0
mxc-isi 4ae40000.isi: validating link "imx327 4-001a":0 -> "dw-mipi-csi2rx 4ae00000.mipi-csi":0
mxc-isi 4ae40000.isi: validating stream "imx327 4-001a":0:0 -> "dw-mipi-csi2rx 4ae00000.mipi-csi":0:0
mxc-isi 4ae40000.isi: enable streams "crossbar":2/0x1
mxc-isi 4ae40000.isi: collect_streams: "crossbar":2: found 0x1 enabled 0x0
imx290 4-001a: Frame descriptor on pad 0, type CSI-2
imx290 4-001a:   stream 0, code 0x300f, length 0, flags 0x0000, vc 0, dt 0x2b
dw-mipi-csi2rx 4ae00000.mipi-csi: Frame descriptor on pad 1, type CSI-2
dw-mipi-csi2rx 4ae00000.mipi-csi:        stream 0, code 0x300f, length 0, flags 0x0000, vc 0, dt 0x2b
mxc-isi 4ae40000.isi: enable streams "dw-mipi-csi2rx 4ae00000.mipi-csi":1/0x1
dw-mipi-csi2rx 4ae00000.mipi-csi: collect_streams: "dw-mipi-csi2rx 4ae00000.mipi-csi":1: found 0x1 enabled 0x0
mxc-isi 4ae40000.isi: enable streams "imx327 4-001a":0/0x1
imx290 4-001a: collect_streams: sub-device "imx327 4-001a" does not support streams
dw-mipi-csi2rx 4ae00000.mipi-csi: lanes are not in stop state: 0x0, expected 0x10003
mxc-isi 4ae40000.isi: disable streams "imx327 4-001a":0/0x1
imx290 4-001a: collect_streams: sub-device "imx327 4-001a" does not support streams
mxc-isi 4ae40000.isi: enable streams 1:0x1 failed: -110
mxc-isi 4ae40000.isi: failed to enable streams 0x1 on 'dw-mipi-csi2rx 4ae00000.mipi-csi':1: -110
mxc-isi 4ae40000.isi: enable streams 2:0x1 failed: -110
mxc-isi 4ae40000.isi: Failed to enable pipe 0
video0: VIDIOC_STREAMON: error -110: type=vid-cap-mplane
videodev: v4l2_release: video0: release
--8<--

For completeness this is my media device config
--8<--
# media-ctl  -p
Media controller API version 7.1.0

Media device information
------------------------
driver          mxc-isi
model           FSL Capture Media Device
serial          
bus info        platform:4ae40000.isi
hw revision     0x0
driver version  7.1.0

Device topology
- entity 1: crossbar (3 pads, 2 links, 1 route)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev0
        routes:
                0/0 -> 2/0 [ACTIVE]
        pad0: SINK,MUST_CONNECT
                [stream:0 fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw]
                <- "dw-mipi-csi2rx 4ae00000.mipi-cs":1 [ENABLED,IMMUTABLE]
        pad1: SINK,MUST_CONNECT
        pad2: SOURCE
                [stream:0 fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw]
                -> "mxc_isi.0":0 [ENABLED,IMMUTABLE]

- entity 5: mxc_isi.0 (2 pads, 2 links, 0 routes)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev1
        pad0: SINK
                [stream:0 fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw
                 compose.bounds:(0,0)/1920x1080
                 compose:(0,0)/1920x1080]
                <- "crossbar":2 [ENABLED,IMMUTABLE]
        pad1: SOURCE
                [stream:0 fmt:SRGGB10_1X10/1920x1080 field:none colorspace:jpeg xfer:srgb ycbcr:601 quantization:full-range
                 crop.bounds:(0,0)/1920x1080
                 crop:(0,0)/1920x1080]
                -> "mxc_isi.0.capture":0 [ENABLED,IMMUTABLE]

- entity 8: mxc_isi.0.capture (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video0
        pad0: SINK
                <- "mxc_isi.0":1 [ENABLED,IMMUTABLE]

- entity 16: dw-mipi-csi2rx 4ae00000.mipi-cs (2 pads, 2 links, 1 route)
             type V4L2 subdev subtype Unknown flags 0
             device node name /dev/v4l-subdev2
        routes:
                0/0 -> 1/0 [ACTIVE]
        pad0: SINK,MUST_CONNECT
                [stream:0 fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range]
                <- "imx327 4-001a":0 [ENABLED]
        pad1: SOURCE
                [stream:0 fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range]
                -> "crossbar":0 [ENABLED,IMMUTABLE]

- entity 21: imx327 4-001a (1 pad, 1 link, 0 routes)
             type V4L2 subdev subtype Sensor flags 0
             device node name /dev/v4l-subdev3
        pad0: SOURCE
                [stream:0 fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range
                 crop.bounds:(0,0)/1945x1097
                 crop:(12,8)/1920x1080]
                -> "dw-mipi-csi2rx 4ae00000.mipi-cs":0 [ENABLED]
--8<--

Anything odd here?

> You may need to remove any delays in the imx327 s_stream implementation, or 
> ensure the sensor stays in LP-11 state until the CSI receiver is ready.
> 
> If possible, could you share the imx327 driver code or check its s_stream implementation?

It's essentially upstream in drivers/media/i2c/imx290.c.
I only have a dummy implementation for get_frame_desc and a small adjustement
for my camera module regarding i2c access.

--8<--
static int imx290_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
				 struct v4l2_mbus_frame_desc *fd)
{
	const struct v4l2_mbus_framefmt *format;
	struct v4l2_subdev_state *state;

	state = v4l2_subdev_lock_and_get_active_state(sd);
	format = v4l2_subdev_state_get_format(state, pad);
	v4l2_subdev_unlock_state(state);

	fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
	fd->num_entries = 1;
	fd->entry[0].pixelcode = format->code;
	fd->entry[0].stream = 0;
	fd->entry[0].bus.csi2.vc = 0;
	fd->entry[0].bus.csi2.dt = MIPI_CSI2_DT_RAW10; //TODO: get_data_type_by_code(format->code);

	return 0;
}
--8<--

Another thing. I use https://lore.kernel.org/imx/20250701-95_cam-v1-2-c5172bab387b@nxp.com/
for the D-PHY. Is there any update/progress on that driver?

Best regards,
Alexander
-- 
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
http://www.tq-group.com/




^ permalink raw reply

* Re: [PATCH v2 1/1] arm64: dts: imx8mq-evk: Enable MIPI CSI and dual OV5640 cameras
From: Robby Cai @ 2026-05-21 11:49 UTC (permalink / raw)
  To: Frank Li
  Cc: robh, krzk+dt, conor+dt, s.hauer, festevam,
	sebastian.krzyszkowiak, kernel, devicetree, imx, linux-arm-kernel,
	linux-kernel
In-Reply-To: <ag4C6MjnOJGjEpKN@lizhi-Precision-Tower-5810>

On Wed, May 20, 2026 at 02:52:24PM -0400, Frank Li wrote:
> On Wed, May 20, 2026 at 02:54:52PM +0800, Robby Cai wrote:
> > On Fri, May 15, 2026 at 10:01:47AM -0400, Frank Li wrote:
> > > On Fri, May 15, 2026 at 07:11:43PM +0800, Robby Cai wrote:
> > > > Enable the MIPI CSI bridges and corresponding CSI-2 host interfaces
> > > > on the i.MX8MQ EVK, and add two OV5640 camera sensors.
> > > >
> > > > The sensors are connected via I2C1 and I2C2, each with proper
> > > > endpoint descriptions to form complete media pipelines.
> > > >
> > > > The resulting pipelines are:
> > > >
> > > >   - OV5640 (I2C2) -> MIPI CSI1 -> CSI1 bridge
> > > >   - OV5640 (I2C1) -> MIPI CSI2 -> CSI2 bridge
> > > >
> > > > Both pipelines have been validated on the i.MX8MQ EVK using the
> > > > upstream OV5640 driver.
> > > >
> > > > Both OV5640 sensors share a single reset GPIO on this board,
> > > > which prevents independent hardware reset when both cameras
> > > > are enabled. As a result, the reset line is kept deasserted
> > > > via a GPIO hog, and sensor reset is performed via software.
> > >
> > > Does reset_control_get_shared() resolve this problem?
> > >
> >
> > No, reset_control_get_shared() does not really solve this issue.
> >
> > The problem here is not about software coordination, but about the
> > hardware topology: both sensors are physically tied to the same reset
> > line. This means any reset operation will always affect both devices
> > simultaneously, regardless of how the reset framework is used.
> 
> Reset framework is resolve this problem. It is quite common that many devices
> shared one reset pin.

okay, I'll try to switch to use this approach in next revision.

Some devices require coordinated RESET and PWDN sequencing, but in this
case the device can be properly initialized with RESET held inactive and
controlled solely via the PWDN signal, which makes this approach viable.

> 
> >
> > While reset_control_get_shared() introduces reference counting to avoid
> > unintended assertions, it does not allow independent reset control.
> > In particular:
> >
> >   - A reset operation (assert) will still impact both sensors.
> 
> yes, only when first devices toggle reset signal. Second device do nothing.
> 
> >   - It does not solve the requirement for per-device hardware reset.
> 
> It is hardware limitation.
> 
> >
> > Therefore, using a shared reset control does not provide true isolation
> > between the two OV5640 instances.
> 
> It is not isolation. Just don't allow second device to toggle reset pin.
> 
> >
> > Keeping the reset line permanently deasserted (e.g. via GPIO hog) and
> > handling initialization through software/power sequencing is a valid
> > and practical solution for this hardware design.
> 
> If use i2c gpio, expandor driver may probe after sensor driver probe. So
> reset may happen after sensor driver probe.


Just to clarify, the reset GPIO in this design is provided by the SoC GPIO
controller (gpio1), not an external I2C GPIO expander.

Therefore, the "late reset" issue you mentioned does not apply here.

Regards,
Robby
> 
> Frank
> >
> > This matches the intention of the upstream changes as well, where GPIO-
> > based resets are treated as simple control signals rather than fully
> > isolated reset domains.
> >
> > In practice, using a shared reset here can even introduce subtle
> > interference between the two cameras during probe or power cycling,
> > so it is safer to avoid using reset for runtime control entirely.
> >
> > Regards,
> > Robby
> >


^ permalink raw reply

* [PATCH v2 2/3] dt-bindings: rockchip: analogix-dp: Add data-lanes example
From: Damon Ding @ 2026-05-21 11:44 UTC (permalink / raw)
  To: hjc, heiko, andy.yan, maarten.lankhorst, mripard, tzimmermann,
	airlied, simona, robh, krzk+dt, conor+dt, andrzej.hajda,
	neil.armstrong, rfoss
  Cc: Laurent.pinchart, jonas, jernej.skrabec, nicolas.frattaroli,
	cristian.ciocaltea, sebastian.reichel, dmitry.baryshkov,
	luca.ceresoli, dianders, m.szyprowski, dri-devel, devicetree,
	linux-arm-kernel, linux-rockchip, linux-kernel, Damon Ding
In-Reply-To: <20260521114459.1394264-1-damon.ding@rock-chips.com>

Add data-lanes setting in endpoint example to show actual lane mapping
usage.

Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
---
 .../bindings/display/rockchip/rockchip,analogix-dp.yaml          | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml
index bb75d898a5c5..cf75c926318b 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml
@@ -151,6 +151,7 @@ examples:
           reg = <1>;
 
           edp_out_panel: endpoint {
+            data-lanes = <0 1>;
             remote-endpoint = <&panel_in_edp>;
           };
         };
-- 
2.34.1



^ permalink raw reply related

* [PATCH v2 3/3] drm/bridge: analogix_dp: Add support for optional data-lanes mapping
From: Damon Ding @ 2026-05-21 11:44 UTC (permalink / raw)
  To: hjc, heiko, andy.yan, maarten.lankhorst, mripard, tzimmermann,
	airlied, simona, robh, krzk+dt, conor+dt, andrzej.hajda,
	neil.armstrong, rfoss
  Cc: Laurent.pinchart, jonas, jernej.skrabec, nicolas.frattaroli,
	cristian.ciocaltea, sebastian.reichel, dmitry.baryshkov,
	luca.ceresoli, dianders, m.szyprowski, dri-devel, devicetree,
	linux-arm-kernel, linux-rockchip, linux-kernel, Damon Ding
In-Reply-To: <20260521114459.1394264-1-damon.ding@rock-chips.com>

Parse the optional 'data-lanes' device tree property to support
custom physical lane mapping configuration.

If no valid configuration is found, fall back to the default
lane map (0, 1, 2, 3) automatically and keep the driver running.

Lane mapping is mainly used for below scenarios:
1. Correct PCB lane swap and differential line routing crossover
   without hardware changes;
2. Adapt mismatched lane pin definitions between SoC and eDP panel;
3. Support multiple panel hardware variants on the same board
   by configuring data-lanes in device tree only.

Signed-off-by: Damon Ding <damon.ding@rock-chips.com>

---

Changes in v2:
- Add lane mapping application scenarios in commit message.
---
 .../drm/bridge/analogix/analogix_dp_core.c    | 56 +++++++++++++++++++
 .../drm/bridge/analogix/analogix_dp_core.h    |  4 +-
 .../gpu/drm/bridge/analogix/analogix_dp_reg.c | 15 +++--
 .../gpu/drm/bridge/analogix/analogix_dp_reg.h |  4 ++
 4 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5dc07ff84cd3..d1c6365118de 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1234,6 +1234,59 @@ static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
 	.detect = analogix_dp_bridge_detect,
 };
 
+static int analogix_dp_dt_parse_lanes_map(struct analogix_dp_device *dp)
+{
+	struct video_info *video_info = &dp->video_info;
+	struct device_node *endpoint;
+	u32 tmp[LANE_COUNT4];
+	u32 map[LANE_COUNT4] = {0, 1, 2, 3};
+	bool used[LANE_COUNT4] = {false};
+	int num_lanes;
+	int ret, i;
+
+	memcpy(video_info->lane_map, map, sizeof(map));
+
+	num_lanes = drm_of_get_data_lanes_count_ep(dp->dev->of_node, 1, 0, 1,
+						   video_info->max_lane_count);
+	if (num_lanes < 0)
+		return -EINVAL;
+
+	endpoint = of_graph_get_endpoint_by_regs(dp->dev->of_node, 1, -1);
+	if (!endpoint)
+		return -EINVAL;
+
+	ret = of_property_read_u32_array(endpoint, "data-lanes", tmp, num_lanes);
+	of_node_put(endpoint);
+	if (ret)
+		return -EINVAL;
+
+	for (i = 0; i < num_lanes; i++) {
+		if (tmp[i] >= LANE_COUNT4) {
+			dev_dbg(dp->dev, "data-lanes[%d] = %u is out of range\n", i, tmp[i]);
+			return -EINVAL;
+		}
+
+		if (used[tmp[i]]) {
+			dev_dbg(dp->dev, "data-lanes[%d] = %u is duplicate\n", i, tmp[i]);
+			return -EINVAL;
+		}
+
+		used[tmp[i]] = true;
+		map[i] = tmp[i];
+	}
+
+	for (i = 0; i < LANE_COUNT4 && num_lanes < LANE_COUNT4; i++) {
+		if (!used[i])
+			map[num_lanes++] = i;
+	}
+
+	dev_dbg(dp->dev, "Using parsed lane map: <%u %u %u %u>\n", map[0], map[1], map[2], map[3]);
+
+	memcpy(video_info->lane_map, map, sizeof(map));
+
+	return 0;
+}
+
 static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
 {
 	struct device_node *dp_node = dp->dev->of_node;
@@ -1266,6 +1319,9 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
 		break;
 	}
 
+	if (analogix_dp_dt_parse_lanes_map(dp))
+		dev_dbg(dp->dev, "No valid data-lanes found, using default lane map\n");
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 94348c4e3623..a75d0fb8f980 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -137,6 +137,8 @@ struct video_info {
 
 	int max_link_rate;
 	enum link_lane_count_type max_lane_count;
+
+	u32 lane_map[LANE_COUNT4];
 };
 
 struct link_train {
@@ -175,7 +177,7 @@ struct analogix_dp_device {
 /* analogix_dp_reg.c */
 void analogix_dp_enable_video_mute(struct analogix_dp_device *dp, bool enable);
 void analogix_dp_stop_video(struct analogix_dp_device *dp);
-void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable);
+void analogix_dp_lane_mapping(struct analogix_dp_device *dp);
 void analogix_dp_init_analog_param(struct analogix_dp_device *dp);
 void analogix_dp_init_interrupt(struct analogix_dp_device *dp);
 void analogix_dp_reset(struct analogix_dp_device *dp);
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index ea8401293a23..c1344a3f013a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -48,16 +48,15 @@ void analogix_dp_stop_video(struct analogix_dp_device *dp)
 	writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);
 }
 
-void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable)
+void analogix_dp_lane_mapping(struct analogix_dp_device *dp)
 {
+	u32 *lane_map = dp->video_info.lane_map;
 	u32 reg;
 
-	if (enable)
-		reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
-		      LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
-	else
-		reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
-		      LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
+	reg = lane_map[0] << LANE0_MAP_SHIFT;
+	reg |= lane_map[1] << LANE1_MAP_SHIFT;
+	reg |= lane_map[2] << LANE2_MAP_SHIFT;
+	reg |= lane_map[3] << LANE3_MAP_SHIFT;
 
 	writel(reg, dp->reg_base + ANALOGIX_DP_LANE_MAP);
 }
@@ -140,7 +139,7 @@ void analogix_dp_reset(struct analogix_dp_device *dp)
 
 	usleep_range(20, 30);
 
-	analogix_dp_lane_swap(dp, 0);
+	analogix_dp_lane_mapping(dp);
 
 	writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_1);
 	writel(0x40, dp->reg_base + ANALOGIX_DP_SYS_CTL_2);
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
index 12735139046c..ac914e37089b 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
@@ -209,6 +209,10 @@
 #define LANE0_MAP_LOGIC_LANE_1			(0x1 << 0)
 #define LANE0_MAP_LOGIC_LANE_2			(0x2 << 0)
 #define LANE0_MAP_LOGIC_LANE_3			(0x3 << 0)
+#define LANE3_MAP_SHIFT				(6)
+#define LANE2_MAP_SHIFT				(4)
+#define LANE1_MAP_SHIFT				(2)
+#define LANE0_MAP_SHIFT				(0)
 
 /* ANALOGIX_DP_ANALOG_CTL_1 */
 #define TX_TERMINAL_CTRL_50_OHM			(0x1 << 4)
-- 
2.34.1



^ permalink raw reply related

* [PATCH v2 1/3] dt-bindings: display: bridge: analogix-dp: Add data-lanes support for endpoint
From: Damon Ding @ 2026-05-21 11:44 UTC (permalink / raw)
  To: hjc, heiko, andy.yan, maarten.lankhorst, mripard, tzimmermann,
	airlied, simona, robh, krzk+dt, conor+dt, andrzej.hajda,
	neil.armstrong, rfoss
  Cc: Laurent.pinchart, jonas, jernej.skrabec, nicolas.frattaroli,
	cristian.ciocaltea, sebastian.reichel, dmitry.baryshkov,
	luca.ceresoli, dianders, m.szyprowski, dri-devel, devicetree,
	linux-arm-kernel, linux-rockchip, linux-kernel, Damon Ding
In-Reply-To: <20260521114459.1394264-1-damon.ding@rock-chips.com>

Add data-lanes property support to the port@1 endpoint for physical
lane mapping configuration.

Lane mapping is mainly used for below scenarios:
1. Correct PCB lane swap and differential line routing crossover
   without hardware changes;
2. Adapt mismatched lane pin definitions between SoC and eDP panel;
3. Support multiple panel hardware variants on the same board
   by configuring data-lanes in device tree only.

Signed-off-by: Damon Ding <damon.ding@rock-chips.com>

---

Changes in v2:
- Add lane mapping application scenarios in commit message.
- Remove redundant deprecated property 'data-lanes' for eDP node.
- Update port@1 $ref to /schemas/graph.yaml#/$defs/port-base.
---
 .../bindings/display/bridge/analogix,dp.yaml    | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/analogix,dp.yaml b/Documentation/devicetree/bindings/display/bridge/analogix,dp.yaml
index 62f0521b0924..e34fdb21adb4 100644
--- a/Documentation/devicetree/bindings/display/bridge/analogix,dp.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/analogix,dp.yaml
@@ -42,13 +42,20 @@ properties:
     properties:
       port@0:
         $ref: /schemas/graph.yaml#/properties/port
-        description:
-          Input node to receive pixel data.
+        description: Input node to receive pixel data.
 
       port@1:
-        $ref: /schemas/graph.yaml#/properties/port
-        description:
-          Port node with one endpoint connected to a dp-connector node.
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        description: Port node with one endpoint connected to sink device node.
+        properties:
+          endpoint:
+            $ref: /schemas/media/video-interfaces.yaml#
+            properties:
+              data-lanes:
+                minItems: 1
+                maxItems: 4
+                items:
+                  enum: [ 0, 1, 2, 3 ]
 
     required:
       - port@0
-- 
2.34.1



^ permalink raw reply related

* [PATCH v2 0/3] Add eDP lane mapping support
From: Damon Ding @ 2026-05-21 11:44 UTC (permalink / raw)
  To: hjc, heiko, andy.yan, maarten.lankhorst, mripard, tzimmermann,
	airlied, simona, robh, krzk+dt, conor+dt, andrzej.hajda,
	neil.armstrong, rfoss
  Cc: Laurent.pinchart, jonas, jernej.skrabec, nicolas.frattaroli,
	cristian.ciocaltea, sebastian.reichel, dmitry.baryshkov,
	luca.ceresoli, dianders, m.szyprowski, dri-devel, devicetree,
	linux-arm-kernel, linux-rockchip, linux-kernel, Damon Ding

This series adds configurable eDP/DP physical lane mapping support
via device tree data-lanes property.

Lane mapping is mainly used for below scenarios:
1. Correct PCB lane swap and differential line routing crossover
   without hardware changes;
2. Adapt mismatched lane pin definitions between SoC and eDP panel;
3. Support multiple panel hardware variants on the same board
   by configuring data-lanes in device tree only.

The series includes driver implementation and device tree binding
updates to support custom lane mapping configuration from endpoint
node, and keeps default linear lane order if no configuration is given.

Patch 1: Add endpoint data-lanes property to analogix-dp binding
Patch 2: Add data-lanes property example in rockchip analogix-dp binding
Patch 3: Implement lane mapping in analogix_dp driver

Damon Ding (3):
  dt-bindings: display: bridge: analogix-dp: Add data-lanes support for
    endpoint
  dt-bindings: rockchip: analogix-dp: Add data-lanes example
  drm/bridge: analogix_dp: Add support for optional data-lanes mapping

 .../bindings/display/bridge/analogix,dp.yaml  | 17 ++++--
 .../rockchip/rockchip,analogix-dp.yaml        |  1 +
 .../drm/bridge/analogix/analogix_dp_core.c    | 56 +++++++++++++++++++
 .../drm/bridge/analogix/analogix_dp_core.h    |  4 +-
 .../gpu/drm/bridge/analogix/analogix_dp_reg.c | 15 +++--
 .../gpu/drm/bridge/analogix/analogix_dp_reg.h |  4 ++
 6 files changed, 83 insertions(+), 14 deletions(-)

---

Changes in v2:
- Add lane mapping application scenarios in commit message.
- Remove redundant deprecated property 'data-lanes' for eDP node.
- Update port@1 $ref to /schemas/graph.yaml#/$defs/port-base.

-- 
2.34.1



^ permalink raw reply


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