Devicetree
 help / color / mirror / Atom feed
* [PATCH 0/5] iio: adc: Add TI ADS126X ADC family support
From: Kurt Borja @ 2026-06-12 22:46 UTC (permalink / raw)
  To: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Linus Walleij, Bartosz Golaszewski
  Cc: David Lechner, Nuno Sá, Andy Shevchenko, linux-iio,
	devicetree, linux-kernel, linux-gpio, Kurt Borja,
	Jonathan Cameron

Hi all,

This series introduces support for TI ADS1262 and ADS1263 ADCs [1].
These devices are very similar (if not the same), except ADS1263
includes a secondary auxiliary ADC.

The main ADC has quite a few features supported the main driver
(ti-ads1262), including:

  - Power management
  - IIO direct and buffer modes
  - Channel hot-reloading
  - Internal or external oscillator
  - Internal or external voltage reference
  - Filter configuration
  - Sensor bias configuration
  - IDAC configuration
  - Level-shift voltage configuration
  - Manual calibration support
  - GPIO controller capabilities

I plan to add these features to the main driver soon:

  - SPI offload support (38400 SPS turns out to be too high for some
    systems)
  - User triggered, automatic calibration (Datasheet 9.4.9)

Additionally, full support for the (less capable) auxiliary ADC is
introduced by the auxiliary ti-ads1263-adc2 driver included in this
series.

The auxiliary ADC operates almost completely independent of the main
ADC. The only consideration that has to be taken for interoperability is
when reading conversion data in direct mode (Datasheet 9.4.7.1), which
happens only in buffer mode, when multiple channels are enabled.

When reading data in direct mode, all SPI activity is forbidden between
the data-ready signal and the data retrieval. To achieve this a second
mutex called xfer_lock was introduced to block SPI activity on the
device.

This is one of the biggest drivers I've developed, so I hope the code
and the comments are self-explainatory. If not, please let me know so I
can clarify them.

As always, thanks for your reviews and help. Submitting upstream is
always a great learning experience :)

[1] https://www.ti.com/lit/ds/symlink/ads1263.pdf

Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
Kurt Borja (5):
      dt-bindings: iio: adc: Add TI ADS126x ADC family
      iio: adc: Add ti-ads1262 driver
      iio: adc: ti-ads1262: Add GPIO controller support
      iio: adc: ti-ads1262: Add calibration support
      iio: adc: Add ti-ads1263-adc2 driver

 .../devicetree/bindings/iio/adc/ti,ads1262.yaml    |  308 +++
 .../bindings/iio/adc/ti,ads1263-adc2.yaml          |   49 +
 MAINTAINERS                                        |   10 +
 drivers/iio/adc/Kconfig                            |   26 +
 drivers/iio/adc/Makefile                           |    2 +
 drivers/iio/adc/ti-ads1262.c                       | 2180 ++++++++++++++++++++
 drivers/iio/adc/ti-ads1262.h                       |   39 +
 drivers/iio/adc/ti-ads1263-adc2.c                  |  470 +++++
 8 files changed, 3084 insertions(+)
---
base-commit: ae696dfa47c30016cd429b9db5e70b259b8f509e
change-id: 20251129-ads126x-fb6107505cae

-- 
Thanks, 
 ~ Kurt


^ permalink raw reply

* [PATCH v4 06/31] dt-bindings: firmware: arm,scmi: Add support for telemetry protocol
From: Cristian Marussi @ 2026-06-12 22:37 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-fsdevel,
	linux-doc
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, d-gole, jic23,
	elif.topuz, lukasz.luba, philip.radford, brauner,
	souvik.chakravarty, leitao, kas, puranjay, usama.arif,
	kernel-team, Cristian Marussi, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, devicetree
In-Reply-To: <20260612223802.1337232-1-cristian.marussi@arm.com>

Add new SCMI v4.0 Telemetry protocol bindings definitions.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v3 --> v4
 - changed protocol number to lowercase 1b
 - fixed misplaced block for protocol 0x1b

Cc: Rob Herring <robh@kernel.org>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: devicetree@vger.kernel.org
---
 Documentation/devicetree/bindings/firmware/arm,scmi.yaml | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
index d06cca9273c4..be733f8d60a0 100644
--- a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
+++ b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
@@ -324,6 +324,14 @@ properties:
     required:
       - reg
 
+  protocol@1b:
+    $ref: '#/$defs/protocol-node'
+    unevaluatedProperties: false
+
+    properties:
+      reg:
+        const: 0x1b
+
 unevaluatedProperties: false
 
 $defs:
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH v9 1/6] dt-bindings: embedded-controller: Add Qualcomm reference device EC description
From: Rob Herring @ 2026-06-12 22:22 UTC (permalink / raw)
  To: Anvesh Jain P
  Cc: Sibi Sankar, Krzysztof Kozlowski, Conor Dooley, Hans de Goede,
	Ilpo Järvinen, Bryan O'Donoghue, Bjorn Andersson,
	Konrad Dybcio, Randy Dunlap, linux-arm-msm, devicetree,
	linux-kernel, platform-driver-x86, Maya Matuszczyk,
	Krzysztof Kozlowski
In-Reply-To: <20260511-add-driver-for-ec-v9-1-e5437c39b7f8@oss.qualcomm.com>

On Mon, May 11, 2026 at 06:13:19PM +0530, Anvesh Jain P wrote:
> From: Maya Matuszczyk <maccraft123mc@gmail.com>
> 
> Add description for the EC firmware running on Hamoa/Purwa and Glymur
> reference devices.
> 
> Signed-off-by: Maya Matuszczyk <maccraft123mc@gmail.com>
> Co-developed-by: Sibi Sankar <sibi.sankar@oss.qualcomm.com>
> Signed-off-by: Sibi Sankar <sibi.sankar@oss.qualcomm.com>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
> Co-developed-by: Anvesh Jain P <anvesh.p@oss.qualcomm.com>
> Signed-off-by: Anvesh Jain P <anvesh.p@oss.qualcomm.com>
> ---
>  .../embedded-controller/qcom,hamoa-crd-ec.yaml     | 56 ++++++++++++++++++++++
>  1 file changed, 56 insertions(+)

Looks like this was missed, so I applied it. Please make sure your 
patches are applied. This should have been applied with the driver or 
.dts files.

Rob

^ permalink raw reply

* Re: [PATCH v2 0/5] ASoC: rockchip: Reorder clock enable sequence
From: Mark Brown @ 2026-06-11 19:49 UTC (permalink / raw)
  To: Heiko Stuebner, Liam Girdwood, Krzysztof Kozlowski, phucduc.bui
  Cc: Rob Herring, Conor Dooley, Jaroslav Kysela, Takashi Iwai,
	devicetree, linux-sound, linux-rockchip, linux-arm-kernel,
	linux-kernel
In-Reply-To: <20260602101608.45137-1-phucduc.bui@gmail.com>

On Tue, 02 Jun 2026 17:16:03 +0700, phucduc.bui@gmail.com wrote:
> ASoC: rockchip: Reorder clock enable sequence
> 
> From: bui duc phuc <phucduc.bui@gmail.com>
> 
> Hi all,
> 
> This series reorders the runtime resume clock enable sequence in the
> Rockchip SPDIF and PDM drivers to enable the bus clock before the
> functional controller clock.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-7.2

Thanks!

[1/5] ASoC: dt-bindings: rockchip-spdif: Correct SPDIF clock descriptions
      https://git.kernel.org/broonie/sound/c/d057cbc218ac
[2/5] ASoC: rockchip: spdif: Reorder clock enable sequence
      https://git.kernel.org/broonie/sound/c/74d3f01a90ca
[3/5] ASoC: rockchip: rockchip_pdm: Reorder clock enable sequence
      https://git.kernel.org/broonie/sound/c/3168721d6ec3
[4/5] ASoC: rockchip: spdif: Restore regcache cache-only mode on sync failure
      https://git.kernel.org/broonie/sound/c/3546e9aa691a
[5/5] ASoC: rockchip: rockchip_pdm: Handle runtime PM resume failures in set_fmt
      https://git.kernel.org/broonie/sound/c/ee7b5f7b3933

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark


^ permalink raw reply

* Re: [PATCH v6 1/7] dt-bindings: hwmon: Add Apple System Management Controller hwmon schema
From: Rob Herring @ 2026-06-12 22:07 UTC (permalink / raw)
  To: James Calligeros
  Cc: Sven Peter, Janne Grunau, Alyssa Rosenzweig, Neal Gompa,
	Lee Jones, Krzysztof Kozlowski, Conor Dooley, Alexandre Belloni,
	Jean Delvare, Guenter Roeck, Dmitry Torokhov, Jonathan Corbet,
	asahi, linux-arm-kernel, devicetree, linux-kernel, linux-rtc,
	linux-hwmon, linux-input, linux-doc
In-Reply-To: <20251215-macsmc-subdevs-v6-1-0518cb5f28ae@gmail.com>

On Mon, Dec 15, 2025 at 07:37:45PM +1000, James Calligeros wrote:
> Apple Silicon devices integrate a vast array of sensors, monitoring
> current, power, temperature, and voltage across almost every part of
> the system. The sensors themselves are all connected to the System
> Management Controller (SMC). The SMC firmware exposes the data
> reported by these sensors via its standard FourCC-based key-value
> API. The SMC is also responsible for monitoring and controlling any
> fans connected to the system, exposing them in the same way.
> 
> For reasons known only to Apple, each device exposes its sensors with
> an almost totally unique set of keys. This is true even for devices
> which share an SoC. An M1 Mac mini, for example, will report its core
> temperatures on different keys to an M1 MacBook Pro. Worse still, the
> SMC does not provide a way to enumerate the available keys at runtime,
> nor do the keys follow any sort of reasonable or consistent naming
> rules that could be used to deduce their purpose. We must therefore
> know which keys are present on any given device, and which function
> they serve, ahead of time.
> 
> Add a schema so that we can describe the available sensors for a given
> Apple Silicon device in the Devicetree.
> 
> Reviewed-by: Neal Gompa <neal@gompa.dev>
> Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
> ---
>  .../bindings/hwmon/apple,smc-hwmon.yaml  | 86 +++++++++++++++++++++++++
>  .../bindings/mfd/apple,smc.yaml          | 36 +++++++++++
>  MAINTAINERS                              |  1 +
>  3 files changed, 123 insertions(+)

I fixed up the error and applied. Please ensure all your patches get 
applied.

Rob

^ permalink raw reply

* Re: [PATCH v3 2/3] dt-bindings: iio: flow: add Sensirion SLF3S liquid flow sensor
From: Conor Dooley @ 2026-06-12 22:00 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Krzysztof Kozlowski, Wadim Mueller, Krzysztof Kozlowski,
	Rob Herring, Conor Dooley, David Lechner, Nuno Sá,
	Andy Shevchenko, Maxwell Doose, linux-iio, devicetree,
	linux-kernel
In-Reply-To: <20260612190543.34d90b87@jic23-huawei>

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

On Fri, Jun 12, 2026 at 07:05:43PM +0100, Jonathan Cameron wrote:
> On Sun, 7 Jun 2026 10:30:07 +0200
> Krzysztof Kozlowski <krzk@kernel.org> wrote:
> 
> > On Fri, Jun 05, 2026 at 01:21:35PM +0100, Jonathan Cameron wrote:
> > > On Thu, 4 Jun 2026 13:22:17 +0200
> > > Krzysztof Kozlowski <krzk@kernel.org> wrote:
> > >   
> > > > On 04/06/2026 11:03, Jonathan Cameron wrote:  
> > > > > On Wed, 3 Jun 2026 16:29:10 +0200
> > > > > Krzysztof Kozlowski <krzk@kernel.org> wrote:
> > > > >     
> > > > >> On 01/06/2026 16:09, Jonathan Cameron wrote:    
> > > > >>> On Mon, 1 Jun 2026 13:53:23 +0200
> > > > >>> Krzysztof Kozlowski <krzk@kernel.org> wrote:
> > > > >>>       
> > > > >>>> On Sat, May 30, 2026 at 10:54:31PM +0200, Wadim Mueller wrote:      
> > > > >>>>> Document the bindings for the Sensirion SLF3S family of digital
> > > > >>>>> liquid-flow sensors on I2C.  The family currently covers the
> > > > >>>>> SLF3S-0600F, SLF3S-1300F and SLF3S-4000B variants.
> > > > >>>>>
> > > > >>>>> The driver auto-detects the variant from the product-information
> > > > >>>>> register at probe time; the per-variant compatible strings exist
> > > > >>>>> for documentation and dt_binding_check purposes.        
> > > > >>>>
> > > > >>>> Here...
> > > > >>>>      
> > > > >>>>> +description:
> > > > >>>>> +  Family of digital liquid-flow sensors from Sensirion with I2C
> > > > >>>>> +  interface.  All family members share the same register map; sub-types
> > > > >>>>> +  differ only in the flow scale factor and the calibrated measurement
> > > > >>>>> +  range, both of which are detected at probe time via the
> > > > >>>>> +  product-information register.        
> > > > >>>>
> > > > >>>> And here...
> > > > >>>>      
> > > > >>>>> +
> > > > >>>>> +properties:
> > > > >>>>> +  compatible:
> > > > >>>>> +    enum:
> > > > >>>>> +      - sensirion,slf3s-0600f
> > > > >>>>> +      - sensirion,slf3s-1300f
> > > > >>>>> +      - sensirion,slf3s-4000b        
> > > > >>>>
> > > > >>>> And here something else. Confusing. Didn't you say device variants are
> > > > >>>> auto-detectable? So you have only one compatible sensirion,slf3s.      
> > > > >>>
> > > > >>> And then future fallback compatibles can never work. 
> > > > >>> Basically as far as I have ever been able to establish this is why
> > > > >>> generic compatibles are almost always the wrong way to go.
> > > > >>>
> > > > >>> If we get a future part with an unknown ID and don't have these existing
> > > > >>> specific compatibles, then we have no way to specify which one it is      
> > > > >>
> > > > >> But why would you have future part with unknown ID?    
> > > > > 
> > > > > That's what manufacturers do on a very frequent basis.  They tweak something
> > > > > that has no affect on the interface or channel scaling etc and release a new part
> > > > > with a different ID.  Can be something like a part suited to different operating
> > > > > conditions, or with a different supply tolerance.    
> > > > 
> > > > and it will have a different, known that time ID. How could be "unknown"?  
> > > 
> > > Known to us, sure, know to old kernel (or other software), not so much.
> > > For this sort of driver the main use of fallback compatibles is to work on
> > > a not yet aware kernel.  
> > 
> > So you mean a case that sometime in the future, someone will write a DTS
> > with sensirion,slf3s fallback for a sensirion,slf3s-WAHTEVER_NEW_MODEL, use
> > old kernel and be surprised it does not work?
> 
> To me that is exactly what a fallback compatible is promising - if we have
> any kernel / driver that supports the part that we are saying is a valid
> fallback then we are saying we support at least the functionality of that
> part (sure there may be extra stuff that doesn't work)
> 
> We had a long discussion a few years back on whether code that did
> 
> 	if (read_reg_whoami() != EXPECTED_ID)
> 		return -ENODEV;
> 
> was correct. Someone (maybe Rob?) strongly argued that we must not
> do that because it effectively made fallbacks pointless as we always
> needed to upgrade the driver. I argued against this (on basis that
> swapping in incompatible parts is annoyingly common) but was eventually
> persuaded.
> 
> If that is not a valid reading of what fallback compatibles mean, is
> there any documentation of the rules I can refer to?
> 
> > 
> > Our goal is not to stop whatever poor code people can ever come up with.
> > 
> > Every future user wanting to the fallback MUST understand what the
> > fallback means.
> 
> This is where we disagree.
> 
> This is not hard to support, it just means not using generic compatibles
> when the device differ (and they are not self describing which these are
> not).

FWIW, I think the no generic compatible approach is reasonable.
The devices might be able to self-identify, but the featureset is not
discoverable, which makes the self-identification much less valuable.
Permitting drop-in replacement parts (or knock off devices from other
manufacturers etc) to use a compatible device as a fallback seems to me
exactly what fallbacks are intended for.

If the driver has to be updated every time a new device is created then
I think a generic compatible has effectively no value.

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

^ permalink raw reply

* Re: [PATCH net v5 3/4] net: ethernet: oa_tc6: Remove FCS size in RX frame
From: sashiko-bot @ 2026-06-12 21:56 UTC (permalink / raw)
  To: Selvamani Rajagopal via B4 Relay; +Cc: robh, devicetree, conor+dt
In-Reply-To: <20260611-level-trigger-v5-3-4533a9e85ce2@onsemi.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing check for `tc6->rx_skb` leads to a NULL pointer dereference when processing orphaned ongoing or end chunks.
- [High] Missing size bounds check for received chunks allows the MAC-PHY to cause a kernel panic via `skb_over_panic()`.
- [High] Unconditional SKB allocation on RX frame start overwrites existing SKBs.
--

commit 47aca7211ccbe61f3e2557dd3549950a622fcf9d
Author: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>

net: ethernet: oa_tc6: Remove FCS size in RX frame

OA TC6 MAC-PHY appends FCS to the incoming frame. It must be
removed from the frame before being passed to the stack.

> diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
> index 477ceefde2c54..0727d53345a33 100644
> --- a/drivers/net/ethernet/oa_tc6.c
> +++ b/drivers/net/ethernet/oa_tc6.c
> @@ -785,6 +785,17 @@ static int oa_tc6_process_rx_chunk_footer(struct oa_tc6 *tc6, u32 footer)
>  
>  static void oa_tc6_submit_rx_skb(struct oa_tc6 *tc6)
>  {
> +	/* MAC-PHY delivers each frame with its Ethernet FCS attached.
> +	 * Strip it before handing over to the stack, unless the user
> +	 * has asked to keep it via NETIF_F_RXFCS. Keeping the FCS
> +	 * in the frame is harmless for IP traffic, but is parsed as
> +	 * a (malformed) suffix TLV by PTP, which makes ptp4l reject
> +	 * every message with "bad message" error.
> +	 */
> +	if (!(tc6->netdev->features & NETIF_F_RXFCS) &&
> +	    tc6->rx_skb->len > ETH_FCS_LEN)
> +		skb_trim(tc6->rx_skb, tc6->rx_skb->len - ETH_FCS_LEN);
> +
>  	tc6->rx_skb->protocol = eth_type_trans(tc6->rx_skb, tc6->netdev);
>  	tc6->netdev->stats.rx_packets++;
>  	tc6->netdev->stats.rx_bytes += tc6->rx_skb->len;

While reviewing this patch, I noticed a few pre-existing issues in the
same file:

drivers/net/ethernet/oa_tc6.c:oa_tc6_prcs_rx_chunk_payload() {
...
	/* Process the chunk with only rx frame end */
	if (end_valid && !start_valid) {
		size = end_byte_offset + 1;
		oa_tc6_prcs_rx_frame_end(tc6, data, size);
		return 0;
	}
...
	/* Process the chunk with ongoing rx frame data */
	oa_tc6_prcs_ongoing_rx_frame(tc6, data, footer);
}

[Severity: High]
This isn't a bug introduced by this patch, but does this lead to a NULL
pointer dereference?

If a MAC-PHY sends an ongoing chunk or an end chunk without a preceding
start chunk, oa_tc6_prcs_rx_frame_end() or oa_tc6_prcs_ongoing_rx_frame()
will be called.

Both functions unconditionally call oa_tc6_update_rx_skb(), which blindly
calls skb_put(tc6->rx_skb, length). If tc6->rx_skb is NULL because no
start_valid was received, skb_put() will crash the system.


drivers/net/ethernet/oa_tc6.c:oa_tc6_prcs_ongoing_rx_frame() {
	oa_tc6_update_rx_skb(tc6, payload, OA_TC6_CHUNK_PAYLOAD_SIZE);
}

drivers/net/ethernet/oa_tc6.c:oa_tc6_update_rx_skb() {
	memcpy(skb_put(tc6->rx_skb, length), payload, length);
}

[Severity: High]
This isn't a bug introduced by this patch, but can this cause a kernel
panic via skb_over_panic()?

The driver allocates the SKB with a fixed tailroom
(MTU + ETH_HLEN + ETH_FCS_LEN). There is no bounds check to ensure the
accumulated length from ongoing chunks does not exceed the allocated
tailroom.

An endless stream of chunks without an end_valid bit might cause skb_put()
to exceed the tailroom and trigger a bounds check panic.


drivers/net/ethernet/oa_tc6.c:oa_tc6_prcs_rx_chunk_payload() {
...
	/* Process the chunk with only rx frame start */
	if (start_valid && !end_valid) {
		size = OA_TC6_CHUNK_PAYLOAD_SIZE - start_byte_offset;
		return oa_tc6_prcs_rx_frame_start(tc6,
						  &data[start_byte_offset],
						  size);
	}
...
}

drivers/net/ethernet/oa_tc6.c:oa_tc6_allocate_rx_skb() {
	tc6->rx_skb = netdev_alloc_skb_ip_align(tc6->netdev, tc6->netdev->mtu +
						ETH_HLEN + ETH_FCS_LEN);
...
}

[Severity: High]
This isn't a bug introduced by this patch, but could this unconditional
allocation overwrite and leak existing SKBs?

When an RX chunk with start_valid=1 is received, oa_tc6_allocate_rx_skb()
assigns a new SKB to tc6->rx_skb.

If the MAC-PHY sends consecutive chunks with start_valid=1 (or leaves a
previous frame incomplete), the prior tc6->rx_skb pointer appears to be
overwritten and permanently leaked.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260611-level-trigger-v5-0-4533a9e85ce2@onsemi.com?part=3

^ permalink raw reply

* Re: [PATCH net v5 1/4] net: ethernet: oa_tc6: Interrupt is active low, level triggered.
From: sashiko-bot @ 2026-06-12 21:56 UTC (permalink / raw)
  To: Selvamani Rajagopal via B4 Relay; +Cc: robh, devicetree, conor+dt
In-Reply-To: <20260611-level-trigger-v5-1-4533a9e85ce2@onsemi.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [Medium] Lockless access to `tc6->waiting_tx_skb` causes a data race and SKB memory leak on the error path.

Pre-existing issues:
- [High] A Time-of-Check to Time-of-Use (TOCTOU) race condition between `oa_tc6_start_xmit` and `oa_tc6_try_spi_transfer` permanently stalls the network TX queue under normal load.
--

commit 6fa7a5c7acb261bf354f20bcc76ccf99dc36a384
Author: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>

net: ethernet: oa_tc6: Interrupt is active low, level triggered.

According OPEN Alliance 10BASET1x MAC-PHY Serial Interface
specification, interrupt is active low, level triggered.

Code used edge triggered interrupt which has the risk of losing an
interrupt on instances like when interrupt is disabled. Level
triggered interrupt won't be deasserted unless handler runs and
clear the interrupting conditions.

Interrupt handler mechanism is changed to threaded irq from
interrupt handler and kernel thread waiting on work queue.

Introduced a logic to disable the device interrupt on error. Error
could be due in data chunk's header and footer or SPI interface itself.

> diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
> index 91a906a7918a2..f3ac2875adfb7 100644
> --- a/drivers/net/ethernet/oa_tc6.c
> +++ b/drivers/net/ethernet/oa_tc6.c

[ ... ]

> @@ -669,6 +671,38 @@ static void oa_tc6_cleanup_ongoing_tx_skb(struct oa_tc6 *tc6)
>  	}
>  }
>  
> +static void oa_tc6_cleanup_waiting_tx_skb(struct oa_tc6 *tc6)
> +{
> +	if (tc6->waiting_tx_skb) {
> +		tc6->netdev->stats.tx_dropped++;
> +		kfree_skb(tc6->waiting_tx_skb);
> +		tc6->waiting_tx_skb = NULL;
> +	}
> +}
> +

[ ... ]

> @@ -1202,7 +1240,7 @@ EXPORT_SYMBOL_GPL(oa_tc6_zero_align_receive_frame_enable);
>   */
>  netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, struct sk_buff *skb)
>  {
> -	if (tc6->waiting_tx_skb) {
> +	if (tc6->disable_traffic || tc6->waiting_tx_skb) {

[Severity: High]
This is a pre-existing issue, but does this lockless check open a race
window that can permanently stall the network TX queue?

If oa_tc6_start_xmit() sees tc6->waiting_tx_skb as populated, it prepares
to stop the queue. Meanwhile, the SPI thread running
oa_tc6_try_spi_transfer() might transfer the SKB, clear waiting_tx_skb
under lock, and check netif_queue_stopped():

oa_tc6_try_spi_transfer()
    if (!tc6->waiting_tx_skb && netif_queue_stopped(tc6->netdev))
        netif_wake_queue(tc6->netdev);

If the SPI thread checks netif_queue_stopped() before oa_tc6_start_xmit()
actually calls netif_stop_queue(), it reads false and skips waking the
queue. oa_tc6_start_xmit() then stops the queue, but waiting_tx_skb is
already cleared.

Could this leave the TX queue permanently deadlocked until an external RX
packet triggers an interrupt?

[Severity: Medium]
Could this also lead to a data race and an SKB memory leak on the error
path?

If oa_tc6_start_xmit() observes tc6->disable_traffic as false and proceeds,
and concurrently the IRQ thread hits a fatal SPI error, it will call
oa_tc6_disable_traffic(). This invokes the new lockless cleanup in
oa_tc6_cleanup_waiting_tx_skb().

If the cleanup happens while waiting_tx_skb is still NULL, it does nothing.
Then oa_tc6_start_xmit() continues, acquires the lock, and assigns the new
SKB to waiting_tx_skb.

Since disable_traffic is now true, the IRQ thread will skip processing, and
the SKB will be leaked indefinitely.

Additionally, oa_tc6_cleanup_waiting_tx_skb() locklessly reads, frees, and
clears tc6->waiting_tx_skb, which appears to cause a data race against
these concurrent accesses.

>  		netif_stop_queue(tc6->netdev);
>  		return NETDEV_TX_BUSY;
>  	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260611-level-trigger-v5-0-4533a9e85ce2@onsemi.com?part=1

^ permalink raw reply

* Re: [PATCH net v5 2/4] net: ethernet: oa_tc6: mdiobus->parent initialized with NULL
From: sashiko-bot @ 2026-06-12 21:56 UTC (permalink / raw)
  To: Selvamani Rajagopal via B4 Relay; +Cc: robh, devicetree, conor+dt
In-Reply-To: <20260611-level-trigger-v5-2-4533a9e85ce2@onsemi.com>

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing bounds check before `skb_put()` can lead to kernel panic via `skb_over_panic()` if an oversized frame is received or infinite chunks are streamed.
- [High] Race condition caused by ad-hoc synchronization flag and lockless SKB access leads to leaked TX socket buffers.
- [High] MDIO read failures are incorrectly treated as successful reads of value 1.
- [High] Unexpected RX chunk from MAC-PHY causes immediate NULL pointer dereference via `skb_put`.
- [High] A transient `-ENOMEM` from SKB allocation causes the network device to permanently disable itself.
- [High] Memory leak of `tc6->rx_skb` when receiving multiple RX start chunks without an end chunk.
--

commit 965184b0f5c3d3772f6dd68237d5d4a9d23389f0
Author: Selvamani Rajagopal <Selvamani.Rajagopal@onsemi.com>

net: ethernet: oa_tc6: mdiobus->parent initialized with NULL

As dev pointer in oa_tc6 structure is never initialized, mbiobus->parent
was initialized with NULL. This change fixes it by initializing it with
device pointer of spi.

> diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
> index f3ac2875adfb7..477ceefde2c54 100644
> --- a/drivers/net/ethernet/oa_tc6.c
> +++ b/drivers/net/ethernet/oa_tc6.c
> @@ -110,7 +110,6 @@
>  
>  /* Internal structure for MAC-PHY drivers */
>  struct oa_tc6 {
> -	struct device *dev;
>  	struct net_device *netdev;
>  	struct phy_device *phydev;
>  	struct mii_bus *mdiobus;
[ ... ]

While reviewing this patch, I noticed a few pre-existing issues in this file
that might be worth addressing:

[Severity: High]
This isn't a bug introduced by this patch, but is it possible for skb_put()
to exceed the allocated size here?

In oa_tc6_prcs_rx_chunk_payload(), when processing ongoing frames:

    oa_tc6_prcs_ongoing_rx_frame(tc6, data, footer);

This eventually calls into oa_tc6_update_rx_skb():

    memcpy(skb_put(tc6->rx_skb, length), payload, length);

If the MAC-PHY hardware sends continuous chunks without an end_valid flag or
sends a frame larger than expected, will this trigger an skb_over_panic()
since there is no bounds checking against the SKB's tailroom?


[Severity: High]
This is a pre-existing issue, but is there a race condition with
tc6->disable_traffic that could leak the waiting TX SKB?

In oa_tc6_start_xmit(), disable_traffic is read locklessly:

    if (tc6->disable_traffic || tc6->waiting_tx_skb) {
        netif_stop_queue(tc6->netdev);
        return NETDEV_TX_BUSY;
    }
    ...
    spin_lock_bh(&tc6->tx_skb_lock);
    tc6->waiting_tx_skb = skb;
    spin_unlock_bh(&tc6->tx_skb_lock);

Concurrently, if an error calls oa_tc6_disable_traffic(), it sets
disable_traffic = true and calls oa_tc6_cleanup_waiting_tx_skb() without
holding tx_skb_lock:

    if (tc6->waiting_tx_skb) {
        tc6->netdev->stats.tx_dropped++;
        kfree_skb(tc6->waiting_tx_skb);
        tc6->waiting_tx_skb = NULL;
    }

Could the cleanup path observe waiting_tx_skb as NULL before the assignment
in start_xmit() completes? If so, start_xmit() would then assign the SKB,
but since traffic is disabled and the queue stopped, the SKB would never
be transmitted or cleaned up.


[Severity: High]
This isn't a bug introduced by this patch, but does oa_tc6_mdiobus_read()
mask read failures?

In oa_tc6_mdiobus_read():

    bool ret;

    ret = oa_tc6_read_register(tc6, OA_TC6_PHY_STD_REG_ADDR_BASE |
                       (regnum & OA_TC6_PHY_STD_REG_ADDR_MASK),
                       &regval);
    if (ret)
        return ret;

Since ret is declared as a bool, if oa_tc6_read_register() returns a
negative error code like -ENODEV, it evaluates to true (1). Will this cause
the MDIO layer to misinterpret a failed register read as a successful read
returning the value 1?


[Severity: High]
This is a pre-existing issue, but what happens if a chunk arrives without
start_valid set when rx_skb is NULL?

In oa_tc6_prcs_rx_chunk_payload(), if a chunk bypasses the start_valid
allocation:

    /* Process the chunk with ongoing rx frame data */
    oa_tc6_prcs_ongoing_rx_frame(tc6, data, footer);

This directly invokes oa_tc6_update_rx_skb():

    memcpy(skb_put(tc6->rx_skb, length), payload, length);

If tc6->rx_skb is NULL because it was never initialized by a start_valid=1
chunk, will this cause an immediate NULL pointer dereference?


[Severity: High]
This isn't a bug introduced by this patch, but is it intended for a
transient memory allocation failure to permanently disable the device?

In oa_tc6_try_spi_transfer(), if oa_tc6_process_spi_data_rx_buf() returns
-ENOMEM from an SKB allocation failure:

    ret = oa_tc6_process_spi_data_rx_buf(tc6, spi_len);
    if (ret) {
        if (ret == -EAGAIN)
            continue;
        oa_tc6_cleanup_ongoing_tx_skb(tc6);
        oa_tc6_cleanup_ongoing_rx_skb(tc6);
        netdev_err(tc6->netdev, "Device error: %d\n", ret);
        return ret;
    }

The error bubbles up to oa_tc6_macphy_threaded_irq():

    ret = oa_tc6_try_spi_transfer(tc6);
    if (ret) {
        disable_irq_nosync(tc6->spi->irq);
        oa_tc6_disable_traffic(tc6);
        break;
    }

Does this mean an -ENOMEM error permanently shuts down the MAC-PHY
interrupt and data processing, completely breaking the network interface
until the module is reloaded?


[Severity: High]
This is a pre-existing issue, but does this code leak the rx_skb if
consecutive start_valid chunks arrive?

In oa_tc6_prcs_rx_chunk_payload():

    /* Process the chunk with only rx frame start */
    if (start_valid && !end_valid) {
        size = OA_TC6_CHUNK_PAYLOAD_SIZE - start_byte_offset;
        return oa_tc6_prcs_rx_frame_start(tc6, &data[start_byte_offset],
                                          size);
    }

This function calls oa_tc6_allocate_rx_skb():

    ret = oa_tc6_allocate_rx_skb(tc6);
    if (ret)
        return ret;

If the driver is already processing a frame and tc6->rx_skb is already
populated, won't receiving another start_valid=1 without an intervening
end_valid=1 overwrite the tc6->rx_skb pointer with a new allocation and
leak the previous one?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260611-level-trigger-v5-0-4533a9e85ce2@onsemi.com?part=2

^ permalink raw reply

* [PATCH] dt-bindings: power: maxim,max17042: Fix temp types to signed
From: Rob Herring (Arm) @ 2026-06-12 21:53 UTC (permalink / raw)
  To: Hans de Goede, Krzysztof Kozlowski, Marek Szyprowski,
	Sebastian Krzyszkowiak, Purism Kernel Team, Sebastian Reichel,
	Conor Dooley
  Cc: linux-pm, devicetree, linux-kernel

The max17042 binding described "maxim,cold-temp" and
"maxim,over-heat-temp" as unsigned values, but in-tree DTS examples
use negative temperatures such as a cold threshold below zero degrees.

Document the temperature properties as signed int32 values so the
schema matches existing DTS data and the driver can use signed helpers.

Assisted-by: Codex:gpt-5-5
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
---
 .../devicetree/bindings/power/supply/maxim,max17042.yaml      | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml b/Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml
index 242b33f2bcba..8687009b4057 100644
--- a/Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml
+++ b/Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml
@@ -44,13 +44,13 @@ properties:
       Defining this property enables current-sense functionality.
 
   maxim,cold-temp:
-    $ref: /schemas/types.yaml#/definitions/uint32
+    $ref: /schemas/types.yaml#/definitions/int32
     description:
       Temperature threshold to report battery as cold (in tenths of degree Celsius).
       Default is not to report cold events.
 
   maxim,over-heat-temp:
-    $ref: /schemas/types.yaml#/definitions/uint32
+    $ref: /schemas/types.yaml#/definitions/int32
     description:
       Temperature threshold to report battery as over heated (in tenths of degree Celsius).
       Default is not to report over heating events.
-- 
2.53.0


^ permalink raw reply related

* [PATCH] dt-bindings: dma: xilinx: Fix "xlnx,irq-delay" type
From: Rob Herring (Arm) @ 2026-06-12 21:52 UTC (permalink / raw)
  To: Vinod Koul, Frank Li, Krzysztof Kozlowski, Conor Dooley,
	Michal Simek, Shyam Pandey, Abin Joseph
  Cc: dmaengine, devicetree, linux-arm-kernel, linux-kernel

"xlnx,irq-delay" programs an 8-bit delay field in the DMA control
register, and the driver stores and reads it as a byte. The binding
described the property as a uint32 cell, which made the helper type
check report the driver as wrong.

Document "xlnx,irq-delay" as uint8 so the generated schema reflects
the hardware field width and the existing driver access.

Assisted-by: Codex:gpt-5-5
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
---
 Documentation/devicetree/bindings/dma/xilinx/xlnx,axi-dma.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/dma/xilinx/xlnx,axi-dma.yaml b/Documentation/devicetree/bindings/dma/xilinx/xlnx,axi-dma.yaml
index 340ae9e91cb0..ba0fc515d825 100644
--- a/Documentation/devicetree/bindings/dma/xilinx/xlnx,axi-dma.yaml
+++ b/Documentation/devicetree/bindings/dma/xilinx/xlnx,axi-dma.yaml
@@ -93,7 +93,7 @@ properties:
       Width in bits of the length register as configured in hardware.
 
   xlnx,irq-delay:
-    $ref: /schemas/types.yaml#/definitions/uint32
+    $ref: /schemas/types.yaml#/definitions/uint8
     minimum: 0
     maximum: 255
     description:
-- 
2.53.0


^ permalink raw reply related

* [PATCH] ASoC: dt-bindings: Fix RT5677 "realtek,gpio-config" type
From: Rob Herring (Arm) @ 2026-06-12 21:49 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Krzysztof Kozlowski, Conor Dooley,
	Animesh Agarwal
  Cc: linux-sound, devicetree, linux-kernel

"realtek,gpio-config" is described as six 8-bit GPIO configuration
values, and the RT5677 driver stores and reads those values as bytes.
The binding incorrectly documented the property as a uint32 array.

Document "realtek,gpio-config" as a uint8-array so the generated
schema matches the hardware definition and the existing driver helper.

Assisted-by: Codex:gpt-5-5
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
---
 Documentation/devicetree/bindings/sound/realtek,rt5677.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5677.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5677.yaml
index 9ce23e58e5ea..ae27ae78b1b2 100644
--- a/Documentation/devicetree/bindings/sound/realtek,rt5677.yaml
+++ b/Documentation/devicetree/bindings/sound/realtek,rt5677.yaml
@@ -58,7 +58,7 @@ properties:
       0 - floating (reset value)
       1 - pull down
       2 - pull up
-    $ref: /schemas/types.yaml#/definitions/uint32-array
+    $ref: /schemas/types.yaml#/definitions/uint8-array
     minItems: 6
     maxItems: 6
     items:
@@ -130,6 +130,6 @@ examples:
             realtek,pow-ldo2-gpio = <&gpio 3 GPIO_ACTIVE_HIGH>;
             realtek,reset-gpio = <&gpio 3 GPIO_ACTIVE_LOW>;
             realtek,in1-differential;
-            realtek,gpio-config = <0 0 0 0 0 2>;
+            realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>;
         };
     };
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH v2 phy-next 8/8] phy: lynx-10g: use RCW override procedure for dynamic protocol change
From: sashiko-bot @ 2026-06-12 21:30 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: vkoul, neil.armstrong, linux-phy, robh, conor+dt, devicetree,
	olteanv
In-Reply-To: <20260612210859.266759-9-vladimir.oltean@nxp.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] Read-modify-write in `fsl_guts_rmw()` drops dynamic overrides of other lanes sharing the same register.
- [High] If `fsl_guts_init()` fails during `soc_device_register()`, the newly added call to `fsl_guts_lane_set_mode()` will trigger an uninitialized spinlock BUG.
--

commit b8f6b1d355d36a951d62ed32d06cbd69afef40c2
Author: Vladimir Oltean <vladimir.oltean@nxp.com>

phy: lynx-10g: use RCW override procedure for dynamic protocol change

This patch enables dynamic protocol changes beyond 1000Base-X/SGMII and
2500Base-X. It removes the previous limitations by utilizing the RCW
override procedure provided by the guts driver.

diff --git a/drivers/phy/freescale/phy-fsl-lynx-10g.c b/drivers/phy/freescale/phy-fsl-lynx-10g.c
index 38def160ef1aa..5ece7889aed7b 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-10g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-10g.c

[ ... ]

@@ -1225,6 +1223,13 @@ static int lynx_10g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
 	if (powered_up)
 		lynx_10g_lane_halt(phy);
 
+	if (lynx_10g_lane_mode_needs_rcw_override(lane, lane_mode)) {
+		err = fsl_guts_lane_set_mode(priv->info->index, lane->id,
+					     lane_mode);
                 ^^^^^^^^^^^^^^^^^^^^^^

[Severity: High]
This isn't a bug introduced by this patch, but does calling
fsl_guts_lane_set_mode() here expose a bug in fsl_guts_rmw() where dynamic
overrides on other lanes are dropped?

When fsl_guts_lane_set_mode() calls fsl_guts_rmw() to update the hardware mux,
it incorrectly reads from the boot-time status register (RCWSR) instead of the
control register (RCWCR):

drivers/soc/fsl/guts.c:fsl_guts_rmw() {
    ...
    u32 tmp = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[offset]);

    tmp &= ~mask;
    tmp |= val;
    fsl_guts_write(&soc.dcfg_dcsr->rcwcr[offset], tmp);
    ...
}

Because RCWSR is read-only and reflects the boot-time configuration, and
multiple lanes share the same register, won't dynamically changing the
protocol of one lane revert any previous dynamic changes applied to the other
lanes?

[Severity: High]
This is a pre-existing issue, but could this also trigger an uninitialized
spinlock BUG if fsl_guts_init() fails?

In drivers/soc/fsl/guts.c, if fsl_guts_init() fails during
soc_device_register(), the error path doesn't clean up the global soc.data
and skips initializing soc.rcwcr_lock:

drivers/soc/fsl/guts.c:fsl_guts_init() {
    ...
    soc_dev = soc_device_register(soc_dev_attr);
    if (IS_ERR(soc_dev)) {
        ret = PTR_ERR(soc_dev);
        goto err;
    }

    spin_lock_init(&soc.rcwcr_lock);
    ...
}

Since soc.data is left populated, the readiness check in
fsl_guts_lane_set_mode() will pass. Won't this then proceed to acquire the
uninitialized soc.rcwcr_lock, triggering a SPIN_BUG_ON?

> +		if (err)
> +			goto out;
> +	}
> +
> 	err = lynx_10g_lane_disable_pcvt(lane, lane->mode);
> 	if (err)

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612210859.266759-1-vladimir.oltean@nxp.com?part=8

^ permalink raw reply

* Re: [PATCH v2 phy-next 7/8] soc: fsl: guts: implement the RCW override procedure
From: sashiko-bot @ 2026-06-12 21:22 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: linux-phy, vkoul, olteanv, devicetree, robh, conor+dt,
	neil.armstrong
In-Reply-To: <20260612210859.266759-8-vladimir.oltean@nxp.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Failure to clear global pointers on error paths allows exported APIs to operate on dangling I/O pointers.
- [High] The Read-Modify-Write logic relies on a read-only boot status register, causing runtime overrides on other lanes to be silently discarded.
- [Medium] Direct returns and bypassed error labels in `fsl_guts_init` leak I/O memory mappings.
- [Medium] Exported APIs contradict their own zero-based indexing documentation and lack parameter bounds checking.
--

commit 2b919af199a087611275f238825912a50ae47330
Author: Ioana Ciornei <ioana.ciornei@nxp.com>
Date:   Fri Jun 12 21:08:58 2026 +0000

    soc: fsl: guts: implement the RCW override procedure
    
    Add support for the RCW override procedure which enables runtime
    reconfiguration of the protocol running on a SerDes lane. The procedure
    is done through the DCFG DCSR space which now can be defined as the
    second memory region of the guts DT node.

> diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
> index 9f2aff07a2744..0fa2bd99d3c10 100644
> --- a/drivers/soc/fsl/guts.c
> +++ b/drivers/soc/fsl/guts.c

[ ... ]

> +/* Some fields of the Reset Configuration Word (RCW) can be overridden at
> + * runtime by writing to the RCWCRn registers contained within the DCSR space
> + * of the Device Configuration (DCFG) block. The layout of the RCWCRn registers
> + * is identical with the read-only RCWSRn from the CCSR space.
> + */
> +static void fsl_guts_rmw(int offset, u32 val, u32 mask)
> +{
> +	u32 tmp = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[offset]);
> +
> +	tmp &= ~mask;
> +	tmp |= val;
> +	fsl_guts_write(&soc.dcfg_dcsr->rcwcr[offset], tmp);
> +}

[Severity: High]
Does this read-modify-write logic accidentally discard previous runtime
overrides?

Since rcwsr is a read-only boot status register, it reflects the static boot
state. If multiple lanes share the same register, reading from rcwsr to update
a subsequent lane will overwrite any dynamic configurations previously written
to the write-only rcwcr register. 

Would it be safer to use a software shadow register to track the runtime state
of rcwcr?

[ ... ]

> +/**
> + * fsl_guts_lane_init() - Notify guts module of SerDes lane configuration
> + * @serdes_idx: zero-based SerDes block index
> + * @lane: zero-based lane index within SerDes
> + *
> + * On the LS208xA SoC, the RCW override procedure needs to be aware of all link
> + * modes which are configured on a SerDes block.
> + */
> +void fsl_guts_lane_init(int serdes_idx, int lane, enum lynx_lane_mode lane_mode)
> +{
> +	soc.lane_mode[serdes_idx - 1][lane] = lane_mode;
> +}
> +EXPORT_SYMBOL_NS_GPL(fsl_guts_lane_init, "FSL_GUTS");

[Severity: Medium]
Is the documentation out of sync with the implementation?

The docstring specifies that serdes_idx is a zero-based index, but the code
subtracts 1. If a caller follows the documentation and passes 0, won't this
result in an out-of-bounds array access?

Additionally, is there a risk of out-of-bounds access if the lane parameter
exceeds MAX_NUM_LANES? An unvalidated lane value could also cause undefined
behavior later when expanded by the GENMASK macros in the override lookup
functions.

[ ... ]

> @@ -250,6 +522,8 @@ static int __init fsl_guts_init(void)
>  		of_node_put(np);
>  		return -ENOMEM;
>  	}
> +	/* DCFG_DCSR is optional */
> +	soc.dcfg_dcsr = of_iomap(np, DCFG_DCSR);
>  
>  	soc.little_endian = of_property_read_bool(np, "little-endian");
>  	soc.svr = fsl_guts_read(&soc.dcfg_ccsr->svr);
> @@ -274,7 +548,7 @@ static int __init fsl_guts_init(void)
>  	/* Register soc device */
>  	soc_dev_attr = kzalloc_obj(*soc_dev_attr);
>  	if (!soc_dev_attr)
>  		return -ENOMEM;

[Severity: Medium]
Will this direct return leak the I/O memory mapped earlier?

If kzalloc_obj() fails, the function returns immediately without unmapping
soc.dcfg_ccsr or the newly added soc.dcfg_dcsr.

[ ... ]

> @@ -296,6 +570,8 @@ static int __init fsl_guts_init(void)
>  		goto err;
>  	}

[Severity: Medium]
Does jumping to the err label skip the necessary unmapping?

If soc_device_register() fails, the code uses goto err. Because err is
placed after err_nomem, the iounmap() calls are bypassed, leaving the memory
mappings leaked.

[ ... ]

>  err_nomem:
>  	ret = -ENOMEM;
> -
> +	if (soc.dcfg_dcsr)
> +		iounmap(soc.dcfg_dcsr);
>  	iounmap(soc.dcfg_ccsr);
>  err:
>  	kfree(soc_dev_attr->family);

[Severity: High]
Should the global pointers be set to NULL after unmapping?

If fsl_guts_init() fails, it unmaps soc.dcfg_ccsr and soc.dcfg_dcsr but
leaves the global pointers dangling. Since this is a core_initcall, the boot
process will continue even if initialization fails.

If an exported API like fsl_guts_lane_set_mode() is called later, it checks
the pointer validity:

	if (!soc.dcfg_dcsr) {
		pr_debug("Device tree does not define DCFG_DCSR...");
		return -EINVAL;
	}

Since the pointer isn't NULL, this validation passes, which could lead to a
use-after-free when the driver attempts to write to the unmapped memory or
acquires the uninitialized spinlock.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612210859.266759-1-vladimir.oltean@nxp.com?part=7

^ permalink raw reply

* Re: [PATCH v2 phy-next 5/8] soc: fsl: guts: make fsl_soc_data available after fsl_guts_init()
From: sashiko-bot @ 2026-06-12 21:21 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: neil.armstrong, vkoul, olteanv, linux-phy, robh, conor+dt,
	devicetree
In-Reply-To: <20260612210859.266759-6-vladimir.oltean@nxp.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The iomem mappings `soc.dcfg_ccsr` and `soc.dcfg_dcsr` are leaked on multiple error paths during initialization.
- [High] The global `soc.data`, `soc.dcfg_ccsr` and `soc.dcfg_dcsr` pointers are not cleared on error paths, leading to dangling pointers, Use-After-Free, and uninitialized spinlock access.
--

commit 9f45015d702d2f4ca41d93015c23b3d9950743a7
Author: Vladimir Oltean <vladimir.oltean@nxp.com>

soc: fsl: guts: make fsl_soc_data available after fsl_guts_init()

In a future change, struct fsl_soc_data will be extended with methods
for performing RCW override.

Since this will be performed from a calling context outside
fsl_guts_init(), we need to keep track of the soc_data that we determine
at fsl_guts_init() time, so we can reference it later.

> diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
> index 1494b545bbb47..9f2aff07a2744 100644
> --- a/drivers/soc/fsl/guts.c
> +++ b/drivers/soc/fsl/guts.c
> @@ -243,7 +243,7 @@ static int __init fsl_guts_init(void)
>  	np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match);
>  	if (!np)
>  		return 0;
> -	soc_data = match->data;
> +	soc.data = match->data;
>  
>  	soc.dcfg_ccsr = of_iomap(np, DCFG_CCSR);
>  	if (!soc.dcfg_ccsr) {

[Severity: High]
Does this code leak the soc.dcfg_ccsr and soc.dcfg_dcsr mappings on error paths?

Looking at fsl_guts_init(), if the soc_dev_attr allocation fails, the function
returns directly, leaking the mappings:

fsl_guts_init() {
    ...
	soc_dev_attr = kzalloc_obj(*soc_dev_attr);
	if (!soc_dev_attr)
		return -ENOMEM;
    ...
}

If soc_device_register() fails, the code jumps to the err label, which bypasses
the err_nomem block where iounmap() is called, also leaking the mappings:

fsl_guts_init() {
    ...
	soc_dev = soc_device_register(soc_dev_attr);
	if (IS_ERR(soc_dev)) {
		ret = PTR_ERR(soc_dev);
		goto err;
	}
    ...
err_nomem:
	ret = -ENOMEM;

	iounmap(soc.dcfg_ccsr);
err:
    ...
}

Could the error paths be updated to ensure iounmap() is called when these
failures occur?

[Severity: High]
Are the global soc.data, soc.dcfg_ccsr, and soc.dcfg_dcsr pointers cleared on
error paths?

In fsl_guts_init(), global state is set early:

fsl_guts_init() {
    ...
	soc.data = match->data;

	soc.dcfg_ccsr = of_iomap(np, DCFG_CCSR);
    ...
}

If an error occurs later, the memory is unmapped but the global pointers are
not cleared to NULL:

fsl_guts_init() {
    ...
err_nomem:
	ret = -ENOMEM;
	if (soc.dcfg_dcsr)
		iounmap(soc.dcfg_dcsr);
	iounmap(soc.dcfg_ccsr);
    ...
}

External callers checking if the driver is initialized via if (!soc.data) or
if (!soc.dcfg_dcsr) could bypass the checks and access the unmapped IO memory
or an uninitialized spinlock:

fsl_guts_lane_set_mode() {
    ...
	spin_lock(&soc.rcwcr_lock);

	if (soc.data->serdes_init_rcwcr)
		soc.data->serdes_init_rcwcr(serdes_idx);

	fsl_guts_rmw(override.offset, override.val << __bf_shf(override.mask),
		     override.mask);
    ...
}

Could the error paths be updated to set these pointers to NULL?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612210859.266759-1-vladimir.oltean@nxp.com?part=5

^ permalink raw reply

* Re: [PATCH v2 phy-next 2/8] soc: fsl: guts: add a global structure to hold state
From: sashiko-bot @ 2026-06-12 21:18 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: olteanv, linux-phy, robh, conor+dt, devicetree, vkoul,
	neil.armstrong
In-Reply-To: <20260612210859.266759-3-vladimir.oltean@nxp.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The global `soc.dcfg_ccsr` pointer is not cleared after being unmapped on the error path, resulting in a dangling pointer.
- [Medium] The globally mapped `soc.dcfg_ccsr` is leaked on multiple error paths during initialization.
--

commit 28927a6c50db9adc7ddb8b131d5e08a366298fb3
Author: Ioana Ciornei <ioana.ciornei@nxp.com>

soc: fsl: guts: add a global structure to hold state

Add the fsl_soc_guts structure in order to pass information like base
addresses, endianness etc between the init time and the runtime
operations. There is no point in mapping and unmapping the DCFG CCSR
space every time we need to make a read, just map it once and keep its
reference in this new global structure.

> diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
> index f87ee47c15035..a0a52a5603a5f 100644
> --- a/drivers/soc/fsl/guts.c
> +++ b/drivers/soc/fsl/guts.c

[ ... ]

> @@ -199,18 +202,17 @@ static int __init fsl_guts_init(void)
>  		return 0;
>  	soc_data = match->data;
>  
> -	regs = of_iomap(np, DCFG_CCSR);
> -	if (!regs) {
> +	soc.dcfg_ccsr = of_iomap(np, DCFG_CCSR);
> +	if (!soc.dcfg_ccsr) {
>  		of_node_put(np);
>  		return -ENOMEM;
>  	}
>  
> -	little_endian = of_property_read_bool(np, "little-endian");
> -	if (little_endian)
> -		svr = ioread32(&regs->svr);
> +	soc.little_endian = of_property_read_bool(np, "little-endian");
> +	if (soc.little_endian)
> +		svr = ioread32(&soc.dcfg_ccsr->svr);
>  	else
> -		svr = ioread32be(&regs->svr);
> -	iounmap(regs);
> +		svr = ioread32be(&soc.dcfg_ccsr->svr);
>  	of_node_put(np);
>  
>  	/* Register soc device */

[Severity: Medium]
Since the iounmap() was removed here to keep soc.dcfg_ccsr mapped, what
happens if the subsequent soc_dev_attr allocation fails?

fsl_guts_init()
	/* Register soc device */
	soc_dev_attr = kzalloc_obj(*soc_dev_attr);
	if (!soc_dev_attr)
		return -ENOMEM;

Does this direct return leak the soc.dcfg_ccsr mapping?

Also, if soc_device_register() fails later in this function, the code does a
goto err:

	soc_dev = soc_device_register(soc_dev_attr);
	if (IS_ERR(soc_dev)) {
		ret = PTR_ERR(soc_dev);
		goto err;
	}

Because this bypasses the err_nomem label, does it also leak the
soc.dcfg_ccsr mapping?

> @@ -263,6 +265,8 @@ static int __init fsl_guts_init(void)
>  
>  err_nomem:
>  	ret = -ENOMEM;
> +
> +	iounmap(soc.dcfg_ccsr);

[Severity: High]
Since soc is a static global structure, does calling iounmap() here leave
soc.dcfg_ccsr with a dangling, non-NULL pointer?

If a client driver later attempts to use the API and checks this pointer
after an initialization failure, could it lead to a kernel oops?

>  err:
>  	kfree(soc_dev_attr->family);
>  	kfree(soc_dev_attr->soc_id);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612210859.266759-1-vladimir.oltean@nxp.com?part=2

^ permalink raw reply

* Re: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
From: Sebastian Reichel @ 2026-06-12 21:15 UTC (permalink / raw)
  To: Diederik de Haas
  Cc: Midgy Balon, Chaoyi Chen, tomeu, ogabbay, heiko, robh, krzk+dt,
	conor+dt, joro, will, robin.murphy, dri-devel, linux-rockchip,
	devicetree, linux-arm-kernel, iommu, linux-kernel, Simon Xue,
	Finley Xiao, Jonas Karlman
In-Reply-To: <DJ5FUW50YM2N.6ZTY4WK27ZP5@cknow-tech.com>

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

Hi,

On Wed, Jun 10, 2026 at 04:28:17PM +0200, Diederik de Haas wrote:
> On Wed Jun 10, 2026 at 3:36 PM CEST, Midgy Balon wrote:
> [    2.110935] rockchip-pm-domain fd8d8000.power-management:power-controller: Failed to create device link (0x180) with supplier 2-0042 for /power-management@fd8d8000/power-controller/power-domain@8
> [    2.557459] sdhci-dwcmshc fe2e0000.mmc: Can't reduce the clock below 52MHz in HS200/HS400 mode
> [    2.647174] rockchip-pm-domain fd8d8000.power-management:power-controller: Failed to create device link (0x180) with supplier 2-0042 for /power-management@fd8d8000/power-controller/power-domain@8
> [    2.945089] rockchip-pm-domain fd8d8000.power-management:power-controller: Failed to create device link (0x180) with supplier spi2.0 for /power-management@fd8d8000/power-controller/power-domain@12
> 
> 8 = NPU; 12 = GPU
> 
> on both nanopc-t6-lts and nanopc-t6-plus (both RK3588).
> And on a 6.18 dmesg output I have for Rock 5B, I see the ~ same, but then
> it's 1-0042 instead of 2-0042. 
> 
> I don't know if it's bad or harmless, but it is consistent.

The fw_devlink framework tries to figure out a sensible probe order
by analyzing links between devices. The warning is because there is
a cyclic dependency. This happens because all power domains are
provided by one device (power-controller).

Now if you want to probe the I2C regulator 2-0042, you need the
I2C controller and to probe the I2C controller you need the I2C
power domain and for that you need the power-controller. But for
the power-controller you need 2-0042 (for the NPU power-domain).
At this point fw_devlink gives up and prints the warning.

Apart from the warning this results in the kernel missing dependency
information, so there might be some extra probe calls ending in
-EPROBE_DEFER (which wastes CPU power and delays the boot process).

So it's neither super bad, nor completely harmless. Fixing this
properly requires some heavy restructuring of the Rockchip
power-controller driver.

Greetings,

-- Sebastian

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

^ permalink raw reply

* Re: [PATCH 1/2] dt-bindings: hwmon: pmbus: ti,lm25066: add current limit properties
From: Conor Dooley @ 2026-06-12 21:13 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Potin Lai, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Zev Weiss, linux-hwmon, devicetree, linux-kernel, Cosmo Chou,
	Mike Hsieh, Potin Lai
In-Reply-To: <059f9ce2-39f0-4553-909d-58585d46edd3@roeck-us.net>

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

On Fri, Jun 12, 2026 at 10:19:14AM -0700, Guenter Roeck wrote:
> On 6/12/26 09:12, Conor Dooley wrote:
> > On Fri, Jun 12, 2026 at 05:10:38PM +0800, Potin Lai wrote:
> > > On Fri, Jun 12, 2026 at 1:27 AM Conor Dooley <conor@kernel.org> wrote:
> > > > 
> > > > On Thu, Jun 11, 2026 at 05:58:44PM +0800, Potin Lai wrote:
> > > > > Add mutually exclusive 'ti,cl-smbus-high' and 'ti,cl-smbus-low' boolean
> > > > > properties to configure the device's Current Limit (CL) behavior using
> > > > > SMBus settings instead of physical pins.
> > > > > 
> > > > > Signed-off-by: Potin Lai <potin.lai.pt@gmail.com>
> > > > > ---
> > > > >   .../devicetree/bindings/hwmon/pmbus/ti,lm25066.yaml  | 20 ++++++++++++++++++++
> > > > >   1 file changed, 20 insertions(+)
> > > > > 
> > > > > diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/ti,lm25066.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/ti,lm25066.yaml
> > > > > index a20f140dc79a..95ea7c26dec2 100644
> > > > > --- a/Documentation/devicetree/bindings/hwmon/pmbus/ti,lm25066.yaml
> > > > > +++ b/Documentation/devicetree/bindings/hwmon/pmbus/ti,lm25066.yaml
> > > > > @@ -46,6 +46,26 @@ properties:
> > > > > 
> > > > >       additionalProperties: false
> > > > > 
> > > > > +  ti,cl-smbus-high:
> > > > > +    description: |
> > > > > +      Configure the Current Limit (CL) to use the SMBus high setting.
> > > > > +    type: boolean
> > > > > +
> > > > > +  ti,cl-smbus-low:
> > > > > +    description: |
> > > > > +      Configure the Current Limit (CL) to use the SMBus low setting.
> > > > > +    type: boolean
> > > > 
> > > > What's smbus specific about this? If the pin was connected to a GPIO,
> > > > you'd then need to have different properties or use these ones with an
> > > > inaccurate name.
> > > > 
> > > 
> > > The "smbus" in the property name was originally meant to indicate
> > > that the setting is configured via the internal register over the SMBus (I2C)
> > > interface, rather than physical pins.
> > 
> > Right, but if you do it via the physical pins using a gpio, you still
> > need a way to say what limit is. The status quo only works if the limit
> > pin is tied high or low.
> > 
> 
> The physical pin is supposed to be connected to ground or left floating.
> It seems unlikely that anyone would ever have the idea of connecting it
> to a GPIO pin, and doing so would for sure mess up the driver because
> its state is only read in the probe function. The configuration here

Well yeah, "obviously" if someone wanted to use a GPIO the driver would
have to change to handle that - but probably not that much since it'd be
a static setting that could be done at probe.

I get that it may be unlikely, but it seems like a reasonable thing that
someone might want to do, and renaming the property to not exclude that
usecase seems to be "free".

> is for setting the limit range (scale) with a configuration register
> to override the configuration obtained from the external pin.

> Either case, even _if_ the CL pin is connected to a GPIO pin, the status
> of that pin would be read from the configuration register. A devicetree

This isn't true, I don't think, unless you're using GPIO hogs?
The GPIO state when linux comes up could be the reset value of the
controller, rather than the correct configuration. You'd need a way to
tell the driver what way to drive it.

> property is not needed for that. The properties are to _override_ the pin
> configuration, not to reflect it.

TL;DR, I think the removal of smbus from the property name (I'm not
asking for it to be taken out of the description) is reasonable.


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

^ permalink raw reply

* [PATCH v2 phy-next 8/8] phy: lynx-10g: use RCW override procedure for dynamic protocol change
From: Vladimir Oltean @ 2026-06-12 21:08 UTC (permalink / raw)
  To: linux-phy
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
	Vinod Koul, Neil Armstrong, Tanjeff Moos,
	Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
	linux-kernel
In-Reply-To: <20260612210859.266759-1-vladimir.oltean@nxp.com>

Up until this patch, the only protocol change supported was between
1000Base-X/SGMII and 2500Base-X. The others require an RCW override
procedure which was lacking.

Since now the guts driver provides the means of applying this procedure,
make use of it and remove any comment which mentioned the limitation.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v2: none
---
 drivers/phy/freescale/Kconfig            |  1 +
 drivers/phy/freescale/phy-fsl-lynx-10g.c | 24 +++++++++++++++---------
 2 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig
index 5bf3864fbe64..d4e189fffbf8 100644
--- a/drivers/phy/freescale/Kconfig
+++ b/drivers/phy/freescale/Kconfig
@@ -58,6 +58,7 @@ config PHY_FSL_LYNX_10G
 	tristate "Freescale Layerscape Lynx 10G SerDes PHY support"
 	depends on OF
 	depends on ARCH_LAYERSCAPE || COMPILE_TEST
+	select FSL_GUTS
 	select GENERIC_PHY
 	select PHY_FSL_LYNX_CORE
 	help
diff --git a/drivers/phy/freescale/phy-fsl-lynx-10g.c b/drivers/phy/freescale/phy-fsl-lynx-10g.c
index 38def160ef1a..5ece7889aed7 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-10g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-10g.c
@@ -8,6 +8,7 @@
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
 #include <linux/workqueue.h>
+#include <linux/fsl/guts.h>
 
 #include "phy-fsl-lynx-core.h"
 
@@ -446,6 +447,7 @@ static void lynx_10g_lane_read_configuration(struct lynx_lane *lane)
 	}
 
 	lynx_10g_backup_pccr_val(lane);
+	fsl_guts_lane_init(priv->info->index, lane->id, lane->mode);
 }
 
 static int ls1028a_get_pccr(enum lynx_lane_mode lane_mode, int lane,
@@ -1167,14 +1169,7 @@ static bool lynx_10g_lane_mode_needs_rcw_override(struct lynx_lane *lane,
 
 	/* Major protocol changes, which involve changing the PCS connection to
 	 * the GMII MAC with the one to the XGMII MAC, require an RCW override
-	 * procedure to reconfigure an internal mux, as documented here:
-	 * https://lore.kernel.org/linux-phy/20230810102631.bvozjer3t67r67iy@skbuf/
-	 * This is SoC-specific, and not yet implemented in drivers/soc/fsl/guts.c.
-	 *
-	 * So the supported set of protocols depends on the initial lane mode.
-	 *
-	 * Minor protocol changes (SGMII <-> 1000Base-X <-> 2500Base-X or
-	 * 10GBase-R <-> USXGMII) are supported.
+	 * procedure to reconfigure an internal mux.
 	 */
 	if ((lynx_lane_mode_uses_gmii_mac(curr) &&
 	     lynx_lane_mode_uses_xgmii_mac(new)) ||
@@ -1189,6 +1184,7 @@ static int lynx_10g_validate(struct phy *phy, enum phy_mode mode, int submode,
 			     union phy_configure_opts *opts)
 {
 	struct lynx_lane *lane = phy_get_drvdata(phy);
+	struct lynx_priv *priv = lane->priv;
 	enum lynx_lane_mode lane_mode;
 	int err;
 
@@ -1197,7 +1193,8 @@ static int lynx_10g_validate(struct phy *phy, enum phy_mode mode, int submode,
 		return err;
 
 	if (lynx_10g_lane_mode_needs_rcw_override(lane, lane_mode))
-		return -EINVAL;
+		return fsl_guts_lane_validate(priv->info->index, lane->id,
+					      lane_mode);
 
 	return 0;
 }
@@ -1205,6 +1202,7 @@ static int lynx_10g_validate(struct phy *phy, enum phy_mode mode, int submode,
 static int lynx_10g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
 {
 	struct lynx_lane *lane = phy_get_drvdata(phy);
+	struct lynx_priv *priv = lane->priv;
 	bool powered_up = lane->powered_up;
 	enum lynx_lane_mode lane_mode;
 	int err;
@@ -1225,6 +1223,13 @@ static int lynx_10g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
 	if (powered_up)
 		lynx_10g_lane_halt(phy);
 
+	if (lynx_10g_lane_mode_needs_rcw_override(lane, lane_mode)) {
+		err = fsl_guts_lane_set_mode(priv->info->index, lane->id,
+					     lane_mode);
+		if (err)
+			goto out;
+	}
+
 	err = lynx_10g_lane_disable_pcvt(lane, lane->mode);
 	if (err)
 		goto out;
@@ -1314,6 +1319,7 @@ static struct platform_driver lynx_10g_driver = {
 };
 module_platform_driver(lynx_10g_driver);
 
+MODULE_IMPORT_NS("FSL_GUTS");
 MODULE_IMPORT_NS("PHY_FSL_LYNX");
 MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>");
 MODULE_AUTHOR("Vladimir Oltean <vladimir.oltean@nxp.com>");
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 phy-next 7/8] soc: fsl: guts: implement the RCW override procedure
From: Vladimir Oltean @ 2026-06-12 21:08 UTC (permalink / raw)
  To: linux-phy
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
	Vinod Koul, Neil Armstrong, Tanjeff Moos,
	Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
	linux-kernel
In-Reply-To: <20260612210859.266759-1-vladimir.oltean@nxp.com>

From: Ioana Ciornei <ioana.ciornei@nxp.com>

Add support for the RCW override procedure which enables runtime
reconfiguration of the protocol running on a SerDes lane. The procedure
is done through the DCFG DCSR space which now can be defined as the
second memory region of the guts DT node.
Support is added on the following SoCs: LS1046A, LS1088A, LS2088A.

The procedure is exported to the "client" driver - the Lynx10G SerDes
PHY driver - through the following functions:
- fsl_guts_lane_init() used to notify the initial / boot time lane mode
  running on a SerDes lane.
- fsl_guts_lane_validate() used to validate that changing the protocol
  on a specific lane is supported.
- fsl_guts_lane_set_mode() which can be used to request the RCW
  procedure be executed for a specific lane.

Since the RCW override procedure is different depending on the SoC, the
private fsl_soc_data structure is updated with two new per SoC callbacks
(.serdes_get_rcw_override() and .serdes_init_rcwcr()) which get used
from the generic fsl_guts_lane_set_mode() function. These two callbacks
hide all the SoC specific register offsets, masks and values so that the
_set_mode() procedure is straightforward.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v2:
- drop DT maintainers from explicit CC
- keep devicetree@vger.kernel.org CCed on entire series
- include missing <linux/bitfield.h>
- namespace SRDS_PRTCL values for LS1046A and LS1088A, even if they are
  the same. For LS1028A (not covered here) they are not.
- prefix SRDS_CLK_SEL_{GMII,XGMII} with LS2088A_
- reorder alphanumerically (LS1046A should come before LS1088A)
---
 drivers/soc/fsl/guts.c   | 285 ++++++++++++++++++++++++++++++++++++++-
 include/linux/fsl/guts.h |  20 ++-
 2 files changed, 298 insertions(+), 7 deletions(-)

diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index 9f2aff07a274..0fa2bd99d3c1 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2016 Freescale Semiconductor, Inc.
  */
 
+#include <linux/bitfield.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -15,6 +16,28 @@
 #include <linux/fsl/guts.h>
 
 #define DCFG_CCSR	0
+#define DCFG_DCSR	1
+
+#define MAX_NUM_LANES	8
+#define MAX_NUM_SERDES	2
+
+#define LS1046A_RCWSR5_SRDS_PRTCL_S1(lane)	\
+	GENMASK(19 + 4 * (lane), 16 + 4 * (lane))
+#define LS1046A_SRDS_PRTCL_XFI				1
+#define LS1046A_SRDS_PRTCL_100BASEX_SGMII		3
+
+#define LS1088A_RCWSR29_SRDS_PRTCL_S1_LNn(lane)	\
+	GENMASK(19 + 4 * (3 - lane), 16 + 4 * (3 - lane))
+#define LS1088A_RCWSR30_SRDS_PRTCL_S2_LNn(lane)	\
+	GENMASK(3 + 4 * (3 - lane), 4 * (3 - lane))
+#define LS1088A_SRDS_PRTCL_XFI				1
+#define LS1088A_SRDS_PRTCL_100BASEX_SGMII		3
+
+#define LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1	BIT(14)
+#define LS2088A_RCWSR30_SRDS_CLK_SEL_XGMII_Ln_S1(lane)	BIT(6 + (7 - (lane)))
+#define LS2088A_RCWSR30_SRDS_CLK_SEL_MSK		GENMASK(13, 6)
+#define LS2088A_SRDS_CLK_SEL_XGMII			1
+#define LS2088A_SRDS_CLK_SEL_GMII			0
 
 struct fsl_soc_die_attr {
 	char	*die;
@@ -22,9 +45,19 @@ struct fsl_soc_die_attr {
 	u32	mask;
 };
 
+struct fsl_soc_serdes_rcw_override {
+	int offset;
+	int mask;
+	int val;
+};
+
 struct fsl_soc_data {
 	const char *sfp_compat;
 	u32 uid_offset;
+	int (*serdes_get_rcw_override)(int index, int lane,
+				       enum lynx_lane_mode lane_mode,
+				       struct fsl_soc_serdes_rcw_override *override);
+	void (*serdes_init_rcwcr)(int index);
 };
 
 enum qoriq_die {
@@ -138,9 +171,13 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
 
 static struct fsl_soc_guts {
 	struct ccsr_guts __iomem *dcfg_ccsr;
+	struct ccsr_guts __iomem *dcfg_dcsr;
 	const struct fsl_soc_data *data;
 	bool little_endian;
 	u32 svr;
+	enum lynx_lane_mode lane_mode[MAX_NUM_SERDES][MAX_NUM_LANES];
+	bool rcwcr_init_done;
+	spinlock_t rcwcr_lock; /* serializes concurrent writes to the RCWCR */
 } soc;
 
 static unsigned int fsl_guts_read(const void __iomem *reg)
@@ -151,6 +188,28 @@ static unsigned int fsl_guts_read(const void __iomem *reg)
 	return ioread32be(reg);
 }
 
+static void fsl_guts_write(void __iomem *reg, u32 val)
+{
+	if (soc.little_endian)
+		iowrite32(val, reg);
+	else
+		iowrite32be(val, reg);
+}
+
+/* Some fields of the Reset Configuration Word (RCW) can be overridden at
+ * runtime by writing to the RCWCRn registers contained within the DCSR space
+ * of the Device Configuration (DCFG) block. The layout of the RCWCRn registers
+ * is identical with the read-only RCWSRn from the CCSR space.
+ */
+static void fsl_guts_rmw(int offset, u32 val, u32 mask)
+{
+	u32 tmp = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[offset]);
+
+	tmp &= ~mask;
+	tmp |= val;
+	fsl_guts_write(&soc.dcfg_dcsr->rcwcr[offset], tmp);
+}
+
 static bool fsl_soc_die_match_one(u32 svr, const struct fsl_soc_die_attr *match)
 {
 	return match->svr == (svr & match->mask);
@@ -167,6 +226,97 @@ static const struct fsl_soc_die_attr *fsl_soc_die_match(
 	return NULL;
 }
 
+static int
+fsl_guts_serdes_get_rcw_override(int serdes_idx, int lane,
+				 enum lynx_lane_mode lane_mode,
+				 struct fsl_soc_serdes_rcw_override *override)
+{
+	if ((!fsl_soc_die_match_one(soc.svr, &fsl_soc_die[DIE_LS1088A]) &&
+	     !fsl_soc_die_match_one(soc.svr, &fsl_soc_die[DIE_LS2088A]) &&
+	     !fsl_soc_die_match_one(soc.svr, &fsl_soc_die[DIE_LS1046A])) ||
+	    !soc.data || !soc.data->serdes_get_rcw_override) {
+		pr_debug("RCW override not implemented for SoC\n");
+		return -EINVAL;
+	}
+
+	if (!soc.dcfg_dcsr) {
+		pr_debug("Device tree does not define DCFG_DCSR region necessary for RCW override\n");
+		return -EINVAL;
+	}
+
+	return soc.data->serdes_get_rcw_override(serdes_idx, lane, lane_mode,
+						 override);
+}
+
+/**
+ * fsl_guts_lane_init() - Notify guts module of SerDes lane configuration
+ * @serdes_idx: zero-based SerDes block index
+ * @lane: zero-based lane index within SerDes
+ * @lane_mode: initial / boot time SerDes protocol for lane
+ *
+ * On the LS208xA SoC, the RCW override procedure needs to be aware of all link
+ * modes which are configured on a SerDes block.
+ */
+void fsl_guts_lane_init(int serdes_idx, int lane, enum lynx_lane_mode lane_mode)
+{
+	soc.lane_mode[serdes_idx - 1][lane] = lane_mode;
+}
+EXPORT_SYMBOL_NS_GPL(fsl_guts_lane_init, "FSL_GUTS");
+
+/**
+ * fsl_guts_lane_validate() - Validate that SerDes protocol is implemented and
+ *	supported on current SoC
+ * @serdes_idx: zero-based SerDes block index
+ * @lane: zero-based lane index within SerDes
+ * @lane_mode: requested SerDes protocol
+ *
+ * Should be called before actually requesting the RCW override procedure to be
+ * applied using %fsl_guts_lane_set_mode()
+ *
+ * Return: 0 if RCW override to protocol is possible, negative error otherwise
+ */
+int fsl_guts_lane_validate(int serdes_idx, int lane, enum lynx_lane_mode lane_mode)
+{
+	struct fsl_soc_serdes_rcw_override override;
+
+	return fsl_guts_serdes_get_rcw_override(serdes_idx, lane, lane_mode,
+						&override);
+}
+EXPORT_SYMBOL_NS_GPL(fsl_guts_lane_validate, "FSL_GUTS");
+
+/**
+ * fsl_guts_lane_set_mode() - apply RCW override procedure for SerDes lane
+ * @serdes_idx: zero-based SerDes block index
+ * @lane: zero-based lane index within SerDes
+ * @lane_mode: requested SerDes protocol
+ *
+ * Return: 0 on success, negative error otherwise
+ */
+int fsl_guts_lane_set_mode(int serdes_idx, int lane, enum lynx_lane_mode lane_mode)
+{
+	struct fsl_soc_serdes_rcw_override override;
+	int err;
+
+	err = fsl_guts_serdes_get_rcw_override(serdes_idx, lane, lane_mode,
+					       &override);
+	if (err)
+		return err;
+
+	spin_lock(&soc.rcwcr_lock);
+
+	if (soc.data->serdes_init_rcwcr)
+		soc.data->serdes_init_rcwcr(serdes_idx);
+
+	fsl_guts_rmw(override.offset, override.val << __bf_shf(override.mask),
+		     override.mask);
+	soc.lane_mode[serdes_idx - 1][lane] = lane_mode;
+
+	spin_unlock(&soc.rcwcr_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(fsl_guts_lane_set_mode, "FSL_GUTS");
+
 static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset)
 {
 	struct device_node *np;
@@ -193,6 +343,128 @@ static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset)
 	return uid;
 }
 
+static int ls1046a_serdes_get_rcw_override(int index, int lane,
+					   enum lynx_lane_mode lane_mode,
+					   struct fsl_soc_serdes_rcw_override *override)
+{
+	/* The RCW override procedure has to write to different registers
+	 * depending on the SerDes block index.
+	 */
+	switch (index) {
+	case 1:
+		override->offset = 4;
+		override->mask = LS1046A_RCWSR5_SRDS_PRTCL_S1(lane);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (lynx_lane_mode_uses_xgmii_mac(lane_mode))
+		override->val = LS1046A_SRDS_PRTCL_XFI;
+	else if (lynx_lane_mode_uses_gmii_mac(lane_mode))
+		override->val = LS1046A_SRDS_PRTCL_100BASEX_SGMII;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ls1088a_serdes_get_rcw_override(int index, int lane,
+					   enum lynx_lane_mode lane_mode,
+					   struct fsl_soc_serdes_rcw_override *override)
+{
+	/* The RCW override procedure has to write to different registers
+	 * depending on the SerDes block index.
+	 */
+	switch (index) {
+	case 1:
+		override->offset = 28;
+		override->mask = LS1088A_RCWSR29_SRDS_PRTCL_S1_LNn(lane);
+		break;
+	case 2:
+		override->offset = 29;
+		override->mask = LS1088A_RCWSR30_SRDS_PRTCL_S2_LNn(lane);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (lynx_lane_mode_uses_xgmii_mac(lane_mode))
+		override->val = LS1088A_SRDS_PRTCL_XFI;
+	else if (lynx_lane_mode_uses_gmii_mac(lane_mode))
+		override->val = LS1088A_SRDS_PRTCL_100BASEX_SGMII;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ls2088a_serdes_get_rcw_override(int index, int lane,
+					   enum lynx_lane_mode lane_mode,
+					   struct fsl_soc_serdes_rcw_override *override)
+{
+	switch (index) {
+	case 1:
+		override->offset = 29;
+		override->mask = LS2088A_RCWSR30_SRDS_CLK_SEL_XGMII_Ln_S1(lane);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (lynx_lane_mode_uses_xgmii_mac(lane_mode))
+		override->val = LS2088A_SRDS_CLK_SEL_XGMII;
+	else if (lynx_lane_mode_uses_gmii_mac(lane_mode))
+		override->val = LS2088A_SRDS_CLK_SEL_GMII;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static void ls2088a_serdes_init_rcwcr(int serdes_idx)
+{
+	u32 reg;
+	int i;
+
+	if (serdes_idx != 1)
+		return;
+	if (soc.rcwcr_init_done)
+		return;
+
+	/* SRDS_CLK_EN_SEL_XGMII_S1: SerDes Clock Enable Select XGMII Serdes 1:
+	 * Enables to select GMII/XGMII clock according to
+	 * SRDS_CLK_SEL_XGMII_Ln_S1
+	 */
+	reg = LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1;
+
+	/* We need to configure the initial state of all lanes for
+	 * the SerDes block #1
+	 */
+	for (i = 0; i < MAX_NUM_LANES; i++)
+		if (lynx_lane_mode_uses_xgmii_mac(soc.lane_mode[serdes_idx - 1][i]))
+			reg |= LS2088A_RCWSR30_SRDS_CLK_SEL_XGMII_Ln_S1(i);
+
+	fsl_guts_rmw(29, reg,
+		     LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1 |
+		     LS2088A_RCWSR30_SRDS_CLK_SEL_MSK);
+
+	soc.rcwcr_init_done = true;
+}
+
+static const struct fsl_soc_data ls1088a_data = {
+	.serdes_get_rcw_override = ls1088a_serdes_get_rcw_override,
+};
+
+static const struct fsl_soc_data ls1046a_data = {
+	.serdes_get_rcw_override = ls1046a_serdes_get_rcw_override,
+};
+
+static const struct fsl_soc_data ls2088a_data = {
+	.serdes_get_rcw_override = ls2088a_serdes_get_rcw_override,
+	.serdes_init_rcwcr = ls2088a_serdes_init_rcwcr,
+};
+
 static const struct fsl_soc_data ls1028a_data = {
 	.sfp_compat = "fsl,ls1028a-sfp",
 	.uid_offset = 0x21c,
@@ -221,10 +493,10 @@ static const struct of_device_id fsl_guts_of_match[] = {
 	{ .compatible = "fsl,mpc8572-guts", },
 	{ .compatible = "fsl,ls1021a-dcfg", },
 	{ .compatible = "fsl,ls1043a-dcfg", },
-	{ .compatible = "fsl,ls2080a-dcfg", },
-	{ .compatible = "fsl,ls1088a-dcfg", },
+	{ .compatible = "fsl,ls2080a-dcfg", .data = &ls2088a_data},
+	{ .compatible = "fsl,ls1088a-dcfg", .data = &ls1088a_data},
 	{ .compatible = "fsl,ls1012a-dcfg", },
-	{ .compatible = "fsl,ls1046a-dcfg", },
+	{ .compatible = "fsl,ls1046a-dcfg", .data = &ls1046a_data},
 	{ .compatible = "fsl,lx2160a-dcfg", },
 	{ .compatible = "fsl,ls1028a-dcfg", .data = &ls1028a_data},
 	{}
@@ -250,6 +522,8 @@ static int __init fsl_guts_init(void)
 		of_node_put(np);
 		return -ENOMEM;
 	}
+	/* DCFG_DCSR is optional */
+	soc.dcfg_dcsr = of_iomap(np, DCFG_DCSR);
 
 	soc.little_endian = of_property_read_bool(np, "little-endian");
 	soc.svr = fsl_guts_read(&soc.dcfg_ccsr->svr);
@@ -296,6 +570,8 @@ static int __init fsl_guts_init(void)
 		goto err;
 	}
 
+	spin_lock_init(&soc.rcwcr_lock);
+
 	pr_info("Machine: %s\n", soc_dev_attr->machine);
 	pr_info("SoC family: %s\n", soc_dev_attr->family);
 	pr_info("SoC ID: %s, Revision: %s\n",
@@ -305,7 +581,8 @@ static int __init fsl_guts_init(void)
 
 err_nomem:
 	ret = -ENOMEM;
-
+	if (soc.dcfg_dcsr)
+		iounmap(soc.dcfg_dcsr);
 	iounmap(soc.dcfg_ccsr);
 err:
 	kfree(soc_dev_attr->family);
diff --git a/include/linux/fsl/guts.h b/include/linux/fsl/guts.h
index fdb55ca47a4f..176842531241 100644
--- a/include/linux/fsl/guts.h
+++ b/include/linux/fsl/guts.h
@@ -13,6 +13,7 @@
 
 #include <linux/types.h>
 #include <linux/io.h>
+#include <soc/fsl/phy-fsl-lynx.h>
 
 /*
  * Global Utility Registers.
@@ -91,9 +92,15 @@ struct ccsr_guts {
 	u32	iovselsr;	/* 0x.00c0 - I/O voltage select status register
 					     Called 'elbcvselcr' on 86xx SOCs */
 	u8	res0c4[0x100 - 0xc4];
-	u32	rcwsr[16];	/* 0x.0100 - Reset Control Word Status registers
-					     There are 16 registers */
-	u8	res140[0x224 - 0x140];
+	/* 0x.0100 - read-only Reset Configuration Word Status registers in
+	 * CCSR, or write-only Reset Configuration Word Control registers in
+	 * DCSR. In both cases there are 32 registers.
+	 */
+	union {
+		u32	rcwsr[32];
+		u32	rcwcr[32];
+	};
+	u8	res180[0x224 - 0x180];
 	u32	iodelay1;	/* 0x.0224 - IO delay control register 1 */
 	u32	iodelay2;	/* 0x.0228 - IO delay control register 2 */
 	u8	res22c[0x604 - 0x22c];
@@ -131,6 +138,13 @@ struct ccsr_guts {
 	u32	srds2cr1;	/* 0x.0f44 - SerDes2 Control Register 0 */
 } __attribute__ ((packed));
 
+void fsl_guts_lane_init(int serdes_idx, int lane,
+			enum lynx_lane_mode lane_mode);
+int fsl_guts_lane_validate(int serdes_idx, int lane,
+			   enum lynx_lane_mode lane_mode);
+int fsl_guts_lane_set_mode(int serdes_idx, int lane,
+			   enum lynx_lane_mode lane_mode);
+
 /* Alternate function signal multiplex control */
 #define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x))
 
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 phy-next 6/8] dt-bindings: fsl: layerscape-dcfg: define DCFG_DCSR region
From: Vladimir Oltean @ 2026-06-12 21:08 UTC (permalink / raw)
  To: linux-phy
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
	Vinod Koul, Neil Armstrong, Tanjeff Moos,
	Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
	linux-kernel, Conor Dooley, Conor Dooley, Krzysztof Kozlowski,
	Rob Herring
In-Reply-To: <20260612210859.266759-1-vladimir.oltean@nxp.com>

In Layerscape (Arm) and QorIQ (PowerPC) devices, hardware peripherals
are accessed by the CPU through a portion of the SoC address space
called CCSR ("Configuration, Control, and Status Registers"). All
hardware IP blocks have their registers mapped here, and the Device
Configuration block makes no exception.

However, there exists a secondary range of the address space named DCSR
("Debug Control and Status Registers") which, like CCSR, also holds
registers of hardware IP blocks, except the DCSR contents is hidden in
all public reference manuals.

The intention of the CCSR/DCSR split, to the best of my knowledge, was
to place the functionality that is too low level for normal use, and
which is necessary only for debug, in a completely separate address
space which can be hidden.

A use case has appeared where networking SerDes lanes need to be
reconfigured at runtime for a different protocol (example: 10GBase-R to
SGMII), and the architecture of the SoCs does not normally permit that.
The Reset Configuration Word (RCW) is a data structure read by the SoC
preboot loader (PBL) which contains stuff like pinmuxing and SerDes
protocol mapping for each lane.

The RCW that the PBL has loaded is visible in the DCFG block's normal
status registers (from CCSR), as read only. Turns out, the RCW is also
mapped in the DCFG's shadow register map (in DCSR), in a write-only
form. Writing to the RCW registers from the DCFG's DCSR space to change
what the PBL has loaded is called "RCW override".

It has been validated that the RCW override procedure is necessary to
reconfigure the networking data path when a SerDes lane performs a major
protocol change. It changes some internal muxes which connect the PCS to
either the 10G MAC or to the 1G MAC.

Defining the DCSR area of the DCFG as a secondary 'reg' array element
allows operating systems to perform RCW overrides. Since it is
introduced late in the binding's lifetime, it is optional. It can be
identified by name, but also by index (first 'reg' is CCSR).

Note that while all SoCs should have a DCFG register block in DCSR, we
only need to expose it for the SoCs where the RCW override procedure is
known to be needed and has been validated.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
---
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Rob Herring <robh@kernel.org>

v1->v2:
- add Conor's review tag
- update email addresses of DT maintainers
---
 .../bindings/soc/fsl/fsl,layerscape-dcfg.yaml     | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml b/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml
index 3fb0534ea597..fc14fd0bf84b 100644
--- a/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml
+++ b/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml
@@ -36,7 +36,20 @@ properties:
           - const: simple-mfd
 
   reg:
-    maxItems: 1
+    minItems: 1
+    items:
+      - description:
+          Customer-visible DCFG register map from CCSR address space
+          (Configuration, Control and Status Registers)
+      - description:
+          Customer-hidden DCFG register map from DCSR address space
+          (Debug Control and Status Registers)
+
+  reg-names:
+    minItems: 1
+    items:
+      - const: dcfg_ccsr
+      - const: dcfg_dcsr
 
   little-endian: true
   big-endian: true
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 phy-next 5/8] soc: fsl: guts: make fsl_soc_data available after fsl_guts_init()
From: Vladimir Oltean @ 2026-06-12 21:08 UTC (permalink / raw)
  To: linux-phy
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
	Vinod Koul, Neil Armstrong, Tanjeff Moos,
	Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
	linux-kernel
In-Reply-To: <20260612210859.266759-1-vladimir.oltean@nxp.com>

In a future change, struct fsl_soc_data will be extended with methods
for performing RCW override.

Since this will be performed from a calling context outside
fsl_guts_init(), we need to keep track of the soc_data that we determine
at fsl_guts_init() time, so we can reference it later.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v2: none
---
 drivers/soc/fsl/guts.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index 1494b545bbb4..9f2aff07a274 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -138,6 +138,7 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
 
 static struct fsl_soc_guts {
 	struct ccsr_guts __iomem *dcfg_ccsr;
+	const struct fsl_soc_data *data;
 	bool little_endian;
 	u32 svr;
 } soc;
@@ -234,7 +235,6 @@ static int __init fsl_guts_init(void)
 	struct soc_device_attribute *soc_dev_attr;
 	static struct soc_device *soc_dev;
 	const struct fsl_soc_die_attr *soc_die;
-	const struct fsl_soc_data *soc_data;
 	const struct of_device_id *match;
 	struct device_node *np;
 	u64 soc_uid = 0;
@@ -243,7 +243,7 @@ static int __init fsl_guts_init(void)
 	np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match);
 	if (!np)
 		return 0;
-	soc_data = match->data;
+	soc.data = match->data;
 
 	soc.dcfg_ccsr = of_iomap(np, DCFG_CCSR);
 	if (!soc.dcfg_ccsr) {
@@ -283,9 +283,9 @@ static int __init fsl_guts_init(void)
 	if (!soc_dev_attr->revision)
 		goto err_nomem;
 
-	if (soc_data)
-		soc_uid = fsl_guts_get_soc_uid(soc_data->sfp_compat,
-					       soc_data->uid_offset);
+	if (soc.data)
+		soc_uid = fsl_guts_get_soc_uid(soc.data->sfp_compat,
+					       soc.data->uid_offset);
 	if (soc_uid)
 		soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX",
 							soc_uid);
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 phy-next 4/8] soc: fsl: guts: make it easier to determine on which SoC we are running
From: Vladimir Oltean @ 2026-06-12 21:08 UTC (permalink / raw)
  To: linux-phy
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
	Vinod Koul, Neil Armstrong, Tanjeff Moos,
	Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
	linux-kernel
In-Reply-To: <20260612210859.266759-1-vladimir.oltean@nxp.com>

From: Ioana Ciornei <ioana.ciornei@nxp.com>

The guts driver will need to easily determine on which SoC it's running
when it will need to perform RCW override at runtime. The guts driver
knows this already because fsl_guts_init() reads the QorIQ/Layerscape
architectural System Version Register (SVR), but it doesn't save this
for later lookups.

Add a new qoriq_die enum to be used as an index in the fsl_soc_die
array. A new fsl_soc_die_match_one() function is also added so that we
can directly determine if the SVR is a match with a specific die.
The SVR value read from the DCFG CCSR is also kept in the global soc
structure so that it can be accessed when needed.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v2: none
---
 drivers/soc/fsl/guts.c | 47 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 41 insertions(+), 6 deletions(-)

diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index dc1a42cd9544..1494b545bbb4 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -27,6 +27,23 @@ struct fsl_soc_data {
 	u32 uid_offset;
 };
 
+enum qoriq_die {
+	DIE_T4240,
+	DIE_T1040,
+	DIE_T2080,
+	DIE_T1024,
+	DIE_LS1043A,
+	DIE_LS2080A,
+	DIE_LS1088A,
+	DIE_LS1012A,
+	DIE_LS1046A,
+	DIE_LS2088A,
+	DIE_LS1021A,
+	DIE_LX2160A,
+	DIE_LS1028A,
+	DIE_MAX,
+};
+
 /* SoC die attribute definition for QorIQ platform */
 static const struct fsl_soc_die_attr fsl_soc_die[] = {
 	/*
@@ -34,21 +51,25 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
 	 */
 
 	/* Die: T4240, SoC: T4240/T4160/T4080 */
+	[DIE_T4240] =
 	{ .die		= "T4240",
 	  .svr		= 0x82400000,
 	  .mask		= 0xfff00000,
 	},
 	/* Die: T1040, SoC: T1040/T1020/T1042/T1022 */
+	[DIE_T1040] =
 	{ .die		= "T1040",
 	  .svr		= 0x85200000,
 	  .mask		= 0xfff00000,
 	},
 	/* Die: T2080, SoC: T2080/T2081 */
+	[DIE_T2080] =
 	{ .die		= "T2080",
 	  .svr		= 0x85300000,
 	  .mask		= 0xfff00000,
 	},
 	/* Die: T1024, SoC: T1024/T1014/T1023/T1013 */
+	[DIE_T1024] =
 	{ .die		= "T1024",
 	  .svr		= 0x85400000,
 	  .mask		= 0xfff00000,
@@ -59,46 +80,55 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
 	 */
 
 	/* Die: LS1043A, SoC: LS1043A/LS1023A */
+	[DIE_LS1043A] =
 	{ .die		= "LS1043A",
 	  .svr		= 0x87920000,
 	  .mask		= 0xffff0000,
 	},
 	/* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */
+	[DIE_LS2080A] =
 	{ .die		= "LS2080A",
 	  .svr		= 0x87010000,
 	  .mask		= 0xff3f0000,
 	},
 	/* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */
+	[DIE_LS1088A] =
 	{ .die		= "LS1088A",
 	  .svr		= 0x87030000,
 	  .mask		= 0xff3f0000,
 	},
 	/* Die: LS1012A, SoC: LS1012A */
+	[DIE_LS1012A] =
 	{ .die		= "LS1012A",
 	  .svr		= 0x87040000,
 	  .mask		= 0xffff0000,
 	},
 	/* Die: LS1046A, SoC: LS1046A/LS1026A */
+	[DIE_LS1046A] =
 	{ .die		= "LS1046A",
 	  .svr		= 0x87070000,
 	  .mask		= 0xffff0000,
 	},
 	/* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */
+	[DIE_LS2088A] =
 	{ .die		= "LS2088A",
 	  .svr		= 0x87090000,
 	  .mask		= 0xff3f0000,
 	},
 	/* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */
+	[DIE_LS1021A] =
 	{ .die		= "LS1021A",
 	  .svr		= 0x87000000,
 	  .mask		= 0xfff70000,
 	},
 	/* Die: LX2160A, SoC: LX2160A/LX2120A/LX2080A */
+	[DIE_LX2160A] =
 	{ .die          = "LX2160A",
 	  .svr          = 0x87360000,
 	  .mask         = 0xff3f0000,
 	},
 	/* Die: LS1028A, SoC: LS1028A */
+	[DIE_LS1028A] =
 	{ .die          = "LS1028A",
 	  .svr          = 0x870b0000,
 	  .mask         = 0xff3f0000,
@@ -109,6 +139,7 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
 static struct fsl_soc_guts {
 	struct ccsr_guts __iomem *dcfg_ccsr;
 	bool little_endian;
+	u32 svr;
 } soc;
 
 static unsigned int fsl_guts_read(const void __iomem *reg)
@@ -119,11 +150,16 @@ static unsigned int fsl_guts_read(const void __iomem *reg)
 	return ioread32be(reg);
 }
 
+static bool fsl_soc_die_match_one(u32 svr, const struct fsl_soc_die_attr *match)
+{
+	return match->svr == (svr & match->mask);
+}
+
 static const struct fsl_soc_die_attr *fsl_soc_die_match(
 	u32 svr, const struct fsl_soc_die_attr *matches)
 {
 	while (matches->svr) {
-		if (matches->svr == (svr & matches->mask))
+		if (fsl_soc_die_match_one(svr, matches))
 			return matches;
 		matches++;
 	}
@@ -202,7 +238,6 @@ static int __init fsl_guts_init(void)
 	const struct of_device_id *match;
 	struct device_node *np;
 	u64 soc_uid = 0;
-	u32 svr;
 	int ret;
 
 	np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match);
@@ -217,7 +252,7 @@ static int __init fsl_guts_init(void)
 	}
 
 	soc.little_endian = of_property_read_bool(np, "little-endian");
-	svr = fsl_guts_read(&soc.dcfg_ccsr->svr);
+	soc.svr = fsl_guts_read(&soc.dcfg_ccsr->svr);
 	of_node_put(np);
 
 	/* Register soc device */
@@ -229,7 +264,7 @@ static int __init fsl_guts_init(void)
 	if (ret)
 		of_machine_read_compatible(&soc_dev_attr->machine, 0);
 
-	soc_die = fsl_soc_die_match(svr, fsl_soc_die);
+	soc_die = fsl_soc_die_match(soc.svr, fsl_soc_die);
 	if (soc_die) {
 		soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ %s",
 						 soc_die->die);
@@ -239,12 +274,12 @@ static int __init fsl_guts_init(void)
 	if (!soc_dev_attr->family)
 		goto err_nomem;
 
-	soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", svr);
+	soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", soc.svr);
 	if (!soc_dev_attr->soc_id)
 		goto err_nomem;
 
 	soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
-					   (svr >>  4) & 0xf, svr & 0xf);
+					   (soc.svr >>  4) & 0xf, soc.svr & 0xf);
 	if (!soc_dev_attr->revision)
 		goto err_nomem;
 
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 phy-next 3/8] soc: fsl: guts: add a central fsl_guts_read() function
From: Vladimir Oltean @ 2026-06-12 21:08 UTC (permalink / raw)
  To: linux-phy
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
	Vinod Koul, Neil Armstrong, Tanjeff Moos,
	Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
	linux-kernel
In-Reply-To: <20260612210859.266759-1-vladimir.oltean@nxp.com>

From: Ioana Ciornei <ioana.ciornei@nxp.com>

Add a central fsl_guts_read() function which will take into account the
endianness that was already determined. No point is duplicating the
if-else statement each time we need to read a DCFG register.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v2: none
---
 drivers/soc/fsl/guts.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index a0a52a5603a5..dc1a42cd9544 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -111,6 +111,14 @@ static struct fsl_soc_guts {
 	bool little_endian;
 } soc;
 
+static unsigned int fsl_guts_read(const void __iomem *reg)
+{
+	if (soc.little_endian)
+		return ioread32(reg);
+
+	return ioread32be(reg);
+}
+
 static const struct fsl_soc_die_attr *fsl_soc_die_match(
 	u32 svr, const struct fsl_soc_die_attr *matches)
 {
@@ -209,10 +217,7 @@ static int __init fsl_guts_init(void)
 	}
 
 	soc.little_endian = of_property_read_bool(np, "little-endian");
-	if (soc.little_endian)
-		svr = ioread32(&soc.dcfg_ccsr->svr);
-	else
-		svr = ioread32be(&soc.dcfg_ccsr->svr);
+	svr = fsl_guts_read(&soc.dcfg_ccsr->svr);
 	of_node_put(np);
 
 	/* Register soc device */
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 phy-next 2/8] soc: fsl: guts: add a global structure to hold state
From: Vladimir Oltean @ 2026-06-12 21:08 UTC (permalink / raw)
  To: linux-phy
  Cc: devicetree, linuxppc-dev, linux-arm-kernel, Ioana Ciornei,
	Vinod Koul, Neil Armstrong, Tanjeff Moos,
	Christophe Leroy (CS GROUP), Michael Walle, Shawn Guo, Frank Li,
	linux-kernel
In-Reply-To: <20260612210859.266759-1-vladimir.oltean@nxp.com>

From: Ioana Ciornei <ioana.ciornei@nxp.com>

Add the fsl_soc_guts structure in order to pass information like base
addresses, endianness etc between the init time and the runtime
operations (RCW override) which will get added in future patches.
There is no point in mapping and unmapping the DCFG CCSR space every
time we need to make a read, just map it once and keep its reference in
this new global struture.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v2: none
---
 drivers/soc/fsl/guts.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
index f87ee47c1503..a0a52a5603a5 100644
--- a/drivers/soc/fsl/guts.c
+++ b/drivers/soc/fsl/guts.c
@@ -106,6 +106,11 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
 	{ },
 };
 
+static struct fsl_soc_guts {
+	struct ccsr_guts __iomem *dcfg_ccsr;
+	bool little_endian;
+} soc;
+
 static const struct fsl_soc_die_attr *fsl_soc_die_match(
 	u32 svr, const struct fsl_soc_die_attr *matches)
 {
@@ -187,9 +192,7 @@ static int __init fsl_guts_init(void)
 	const struct fsl_soc_die_attr *soc_die;
 	const struct fsl_soc_data *soc_data;
 	const struct of_device_id *match;
-	struct ccsr_guts __iomem *regs;
 	struct device_node *np;
-	bool little_endian;
 	u64 soc_uid = 0;
 	u32 svr;
 	int ret;
@@ -199,18 +202,17 @@ static int __init fsl_guts_init(void)
 		return 0;
 	soc_data = match->data;
 
-	regs = of_iomap(np, DCFG_CCSR);
-	if (!regs) {
+	soc.dcfg_ccsr = of_iomap(np, DCFG_CCSR);
+	if (!soc.dcfg_ccsr) {
 		of_node_put(np);
 		return -ENOMEM;
 	}
 
-	little_endian = of_property_read_bool(np, "little-endian");
-	if (little_endian)
-		svr = ioread32(&regs->svr);
+	soc.little_endian = of_property_read_bool(np, "little-endian");
+	if (soc.little_endian)
+		svr = ioread32(&soc.dcfg_ccsr->svr);
 	else
-		svr = ioread32be(&regs->svr);
-	iounmap(regs);
+		svr = ioread32be(&soc.dcfg_ccsr->svr);
 	of_node_put(np);
 
 	/* Register soc device */
@@ -263,6 +265,8 @@ static int __init fsl_guts_init(void)
 
 err_nomem:
 	ret = -ENOMEM;
+
+	iounmap(soc.dcfg_ccsr);
 err:
 	kfree(soc_dev_attr->family);
 	kfree(soc_dev_attr->soc_id);
-- 
2.34.1


^ permalink raw reply related


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