* [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block
@ 2026-03-27 20:09 Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 01/16] dt-bindings: clock: Introduce nexus nodes Miquel Raynal (Schneider Electric)
` (15 more replies)
0 siblings, 16 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric), Herve Codina
Hello,
This is a series adding support for the EIP-150, which is a crypto block
containing:
- a public key accelerator
- a random number generator
- an interrupt controller
The series is a bit long but every subsystem may take its own share
independently. I might want to split it into several chunks in the
future if it expands but at as for now, here is the full picture.
For instance, the clock part has grown due to the inputs From Stephan
Boyd (addition of Kunit tests + a couple of misc preliminary changes).
Link: https://lore.kernel.org/linux-clk/20260129201003.288605-1-miquel.raynal@bootlin.com/
Regarding the big engine, the EIP-28 Public Key Accelerator, it
currently only supports RSA, but more algorithms might be added
later. The hardware supports (EC)DSA and (EC)DH. It also requires a
firmware.
The very last patch adds the block in the Renesas RZ/N1D DTSI, as this
is the platform I am using this hardware one.
Thanks,
Miquèl
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
Miquel Raynal (Schneider Electric) (16):
dt-bindings: clock: Introduce nexus nodes
dt-bindings: interrupt-controller: Describe EIP-201 AIC
dt-bindings: rng: Rename the title of the EIP-76 file
dt-bindings: crypto: eip28: Describe EIP-28 PKA
dt-bindings: bus: eip150: Describe the EIP-150 container node
clk: tests: Add clk_parse_clkspec() Kunit testing
clk: tests: Add Kunit testing for of_clk_get_parent_name()
clk: Improve a couple of comments
clk: Use the generic OF phandle parsing in only one place
clk: Add support for clock nexus dt bindings
clk: tests: Add Kunit testing for nexus nodes
irqchip/eip201-aic: Add support for Safexcel EIP-201 AIC
hwrng: omap: Enable on Renesas RZ/N1D
crypto: Group Inside-Secure IPs together and align the titles
crypto: eip28: Add support for SafeXcel EIP-28 Public Key Accelerator
ARM: dts: renesas: r9a06g032: Describe the EIP-150 block
.../bus/inside-secure,safexcel-eip150.yaml | 58 ++
.../bindings/clock/clock-nexus-node.yaml | 39 ++
.../crypto/inside-secure,safexcel-eip28.yaml | 31 +
.../inside-secure,safexcel-eip201.yaml | 41 ++
.../bindings/rng/inside-secure,safexcel-eip76.yaml | 2 +-
arch/arm/boot/dts/renesas/r9a06g032.dtsi | 42 ++
drivers/char/hw_random/Kconfig | 2 +-
drivers/clk/Makefile | 1 +
drivers/clk/clk.c | 12 +-
drivers/clk/clk_test.c | 154 +++++
drivers/clk/kunit_clk_parse_clkspec.dtso | 31 +
drivers/crypto/Kconfig | 55 +-
drivers/crypto/inside-secure/Makefile | 1 +
drivers/crypto/inside-secure/eip28.c | 760 +++++++++++++++++++++
drivers/crypto/inside-secure/eip93/Kconfig | 2 +-
drivers/irqchip/Kconfig | 8 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-eip201-aic.c | 221 ++++++
.../inside-secure,safexcel-eip201.h | 14 +
19 files changed, 1444 insertions(+), 31 deletions(-)
---
base-commit: f6ad621bcf627fe4719cbf97c1d3c9366cc49eff
change-id: 20260327-schneider-v7-0-rc1-crypto-58cd846ddb81
Best regards,
--
Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 01/16] dt-bindings: clock: Introduce nexus nodes
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 02/16] dt-bindings: interrupt-controller: Describe EIP-201 AIC Miquel Raynal (Schneider Electric)
` (14 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
Hardware containers can just decouple external resources like clock
without any more control. Nexus nodes already exist for PWM and GPIOs,
add a binding to allow them for clocks as well.
No examples are given, the file is litteraly a copy-paste from Hervé
Codina's work on PWM Nexus nodes, hence we just point to the examples
there which already illustrate very clearly the concept of the various
properties.
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
.../bindings/clock/clock-nexus-node.yaml | 39 ++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/clock-nexus-node.yaml b/Documentation/devicetree/bindings/clock/clock-nexus-node.yaml
new file mode 100644
index 000000000000..f07e2972e8aa
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/clock-nexus-node.yaml
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/clock-nexus-node.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Clock Nexus
+
+description: >
+ A nexus node allows to remap a phandle list in a consumer node through a
+ container or a connector node in a generic way. With this remapping,
+ the consumer node needs to know only about the nexus node. Resources
+ behind the nexus node are decoupled by the nexus node itself.
+
+maintainers:
+ - Miquel Raynal <miquel.raynal@bootlin.com>
+
+select: true
+
+properties:
+ '#clock-cells': true
+
+ clock-map:
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+
+ clock-map-mask:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+
+ clock-map-pass-thru:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+
+dependentRequired:
+ clock-map: ['#clock-cells']
+ clock-map-mask: [ clock-map ]
+ clock-map-pass-thru: [ clock-map ]
+
+additionalProperties: true
+
+# See the original pwm-nexus-node.yaml description for examples
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 02/16] dt-bindings: interrupt-controller: Describe EIP-201 AIC
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 01/16] dt-bindings: clock: Introduce nexus nodes Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 03/16] dt-bindings: rng: Rename the title of the EIP-76 file Miquel Raynal (Schneider Electric)
` (13 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
The EIP-201 Advanced Interrupt Controller is part of a bigger container
block from Inside Secure nicely named EIP-150. It typically takes one
clock from the EIP-150 and offers basic controls through a few simple
registers.
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
.../inside-secure,safexcel-eip201.yaml | 41 ++++++++++++++++++++++
.../inside-secure,safexcel-eip201.h | 14 ++++++++
2 files changed, 55 insertions(+)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/inside-secure,safexcel-eip201.yaml b/Documentation/devicetree/bindings/interrupt-controller/inside-secure,safexcel-eip201.yaml
new file mode 100644
index 000000000000..ddad8e5eab96
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/inside-secure,safexcel-eip201.yaml
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/inside-secure,safexcel-eip201.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Inside-Secure SafeXcel EIP-201 Advanced Interrupt Controller
+
+maintainers:
+ - Miquel Raynal <miquel.raynal@bootlin.com>
+
+allOf:
+ - $ref: /schemas/interrupt-controller.yaml#
+
+properties:
+ compatible:
+ const: inside-secure,safexcel-eip201
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ minItems: 1
+
+ interrupt-controller: true
+
+ "#interrupt-cells":
+ const: 2
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - interrupt-controller
+ - "#interrupt-cells"
+
+unevaluatedProperties: false
diff --git a/include/dt-bindings/interrupt-controller/inside-secure,safexcel-eip201.h b/include/dt-bindings/interrupt-controller/inside-secure,safexcel-eip201.h
new file mode 100644
index 000000000000..ead73bd96296
--- /dev/null
+++ b/include/dt-bindings/interrupt-controller/inside-secure,safexcel-eip201.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
+
+#ifndef _DT_BINDINGS_IRQ_SAFEXCEL_EIP201_AIC_H
+#define _DT_BINDINGS_IRQ_SAFEXCEL_EIP201_AIC_H
+
+#define AIC_PKA_INT0 0
+#define AIC_PKA_INT1 1
+#define AIC_PKA_INT2 2
+#define AIC_TRNG_INT 3
+#define AIC_RESERVED 4
+#define AIC_SL_ERR_INT 5
+#define AIC_PROTECTION_INT 6
+
+#endif
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 03/16] dt-bindings: rng: Rename the title of the EIP-76 file
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 01/16] dt-bindings: clock: Introduce nexus nodes Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 02/16] dt-bindings: interrupt-controller: Describe EIP-201 AIC Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 04/16] dt-bindings: crypto: eip28: Describe EIP-28 PKA Miquel Raynal (Schneider Electric)
` (12 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
Be a little more precise in the title by giving the family name and the
own name of the hardware block. Despite the original compatibles, this
file describes a SafeXcel EIP-76 hardware random number generator.
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
Documentation/devicetree/bindings/rng/inside-secure,safexcel-eip76.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/rng/inside-secure,safexcel-eip76.yaml b/Documentation/devicetree/bindings/rng/inside-secure,safexcel-eip76.yaml
index f501fc7691c6..92d906998211 100644
--- a/Documentation/devicetree/bindings/rng/inside-secure,safexcel-eip76.yaml
+++ b/Documentation/devicetree/bindings/rng/inside-secure,safexcel-eip76.yaml
@@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/rng/inside-secure,safexcel-eip76.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Inside-Secure HWRNG Module
+title: Inside-Secure SafeXcel EIP-76 HWRNG Module
maintainers:
- Jayesh Choudhary <j-choudhary@ti.com>
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 04/16] dt-bindings: crypto: eip28: Describe EIP-28 PKA
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
` (2 preceding siblings ...)
2026-03-27 20:09 ` [PATCH 03/16] dt-bindings: rng: Rename the title of the EIP-76 file Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 05/16] dt-bindings: bus: eip150: Describe the EIP-150 container node Miquel Raynal (Schneider Electric)
` (11 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
Describe the Public Key Accelerator named EIP-28 from Inside-Secure,
part of the SafeXcel family, it is typically included in a bigger
hardware container named EIP-150.
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
.../crypto/inside-secure,safexcel-eip28.yaml | 31 ++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/Documentation/devicetree/bindings/crypto/inside-secure,safexcel-eip28.yaml b/Documentation/devicetree/bindings/crypto/inside-secure,safexcel-eip28.yaml
new file mode 100644
index 000000000000..96acb257450a
--- /dev/null
+++ b/Documentation/devicetree/bindings/crypto/inside-secure,safexcel-eip28.yaml
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/crypto/inside-secure,safexcel-eip28.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Inside-Secure SafeXcel EIP-28 Public Key Accelerator
+
+maintainers:
+ - Miquel Raynal <miquel.raynal@bootlin.com>
+
+properties:
+ compatible:
+ const: inside-secure,safexcel-eip28
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 3
+
+ clocks:
+ minItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+
+additionalProperties: false
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 05/16] dt-bindings: bus: eip150: Describe the EIP-150 container node
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
` (3 preceding siblings ...)
2026-03-27 20:09 ` [PATCH 04/16] dt-bindings: crypto: eip28: Describe EIP-28 PKA Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 06/16] clk: tests: Add clk_parse_clkspec() Kunit testing Miquel Raynal (Schneider Electric)
` (10 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
Part of Inside-Secure's SafeXcel family, the EIP-150 is some kind of
container node composed of:
- a public key accelerator,
- random number generator,
- an interrupt controller.
It also acts as proxy for the clocks.
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
.../bus/inside-secure,safexcel-eip150.yaml | 58 ++++++++++++++++++++++
1 file changed, 58 insertions(+)
diff --git a/Documentation/devicetree/bindings/bus/inside-secure,safexcel-eip150.yaml b/Documentation/devicetree/bindings/bus/inside-secure,safexcel-eip150.yaml
new file mode 100644
index 000000000000..1b3d83a852f5
--- /dev/null
+++ b/Documentation/devicetree/bindings/bus/inside-secure,safexcel-eip150.yaml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/bus/inside-secure,safexcel-eip150.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Inside-Secure SafeXcel EIP-150 container
+
+maintainers:
+ - Miquel Raynal <miquel.raynal@bootlin.com>
+
+description:
+ The EIP-150 is a hardware container, it has its own interrupt
+ controller inside to which a random number generator and a public key
+ accelerator are wired.
+
+allOf:
+ - $ref: simple-pm-bus.yaml#
+ - $ref: /schemas/clock/clock-nexus-node.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: inside-secure,safexcel-eip150
+ - {} # simple-pm-bus, but not listed here to avoid false select
+
+ clocks:
+ minItems: 1
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 1
+
+ ranges: true
+
+patternProperties:
+ "^interrupt-controller@[0-9a-f]+$":
+ type: object
+ $ref: /schemas/interrupt-controller/inside-secure,safexcel-eip201.yaml#
+
+ "^rng@[0-9a-f]+$":
+ type: object
+ $ref: /schemas/rng/inside-secure,safexcel-eip76.yaml#
+
+ "^crypto@[0-9a-f]+$":
+ type: object
+ $ref: /schemas/crypto/inside-secure,safexcel-eip28.yaml#
+
+required:
+ - compatible
+ - clocks
+ - "#address-cells"
+ - "#size-cells"
+ - ranges
+
+unevaluatedProperties: false
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 06/16] clk: tests: Add clk_parse_clkspec() Kunit testing
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
` (4 preceding siblings ...)
2026-03-27 20:09 ` [PATCH 05/16] dt-bindings: bus: eip150: Describe the EIP-150 container node Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 07/16] clk: tests: Add Kunit testing for of_clk_get_parent_name() Miquel Raynal (Schneider Electric)
` (9 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
Create a new set of kunit tests to make sure clk_parse_clkspec() is
working as expected. We currently verify if we get a proper device when
using indexes and names. If we make an out of bounds request we expect
an error.
For testing purposes, we must ensure of_clk_get_hw()'s symbol is
exported.
Suggested-by: Stephen Boyd <sboyd@kernel.org>
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
drivers/clk/Makefile | 1 +
drivers/clk/clk.c | 1 +
drivers/clk/clk_test.c | 124 +++++++++++++++++++++++++++++++
drivers/clk/kunit_clk_parse_clkspec.dtso | 21 ++++++
4 files changed, 147 insertions(+)
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f7bce3951a30..97b621456bf5 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -19,6 +19,7 @@ clk-test-y := clk_test.o \
kunit_clk_assigned_rates_zero.dtbo.o \
kunit_clk_assigned_rates_zero_consumer.dtbo.o \
kunit_clk_hw_get_dev_of_node.dtbo.o \
+ kunit_clk_parse_clkspec.dtbo.o \
kunit_clk_parent_data_test.dtbo.o
obj-$(CONFIG_COMMON_CLK) += clk-divider.o
obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 47093cda9df3..1795246b10a0 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -5312,6 +5312,7 @@ struct clk_hw *of_clk_get_hw(struct device_node *np, int index,
return hw;
}
+EXPORT_SYMBOL_GPL(of_clk_get_hw);
static struct clk *__of_clk_get(struct device_node *np,
int index, const char *dev_id,
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index a268d7b5d4cb..b814b45f1f7e 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -3541,10 +3541,134 @@ static struct kunit_suite clk_hw_get_dev_of_node_test_suite = {
.test_cases = clk_hw_get_dev_of_node_test_cases,
};
+static const struct clk_init_data clk_parse_clkspec_1_init_data = {
+ .name = "clk_parse_clkspec_1",
+ .ops = &empty_clk_ops,
+};
+
+static const struct clk_init_data clk_parse_clkspec_2_init_data = {
+ .name = "clk_parse_clkspec_2",
+ .ops = &empty_clk_ops,
+};
+
+static struct clk_hw *kunit_clk_get(struct of_phandle_args *clkspec, void *data)
+{
+ return (struct clk_hw *)data;
+}
+
+struct clk_parse_clkspec_ctx {
+ struct device_node *prov1_np;
+ struct device_node *prov2_np;
+ struct device_node *cons_np;
+};
+
+static int clk_parse_clkspec_init(struct kunit *test)
+{
+ struct clk_parse_clkspec_ctx *ctx;
+ struct clk_hw *hw1, *hw2;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ test->priv = ctx;
+
+ KUNIT_ASSERT_EQ(test, 0, of_overlay_apply_kunit(test, kunit_clk_parse_clkspec));
+
+ /* Register provider 1 */
+ hw1 = kunit_kzalloc(test, sizeof(*hw1), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw1);
+ hw1->init = &clk_parse_clkspec_1_init_data;
+
+ ctx->prov1_np = of_find_compatible_node(NULL, NULL, "test,clock-provider1");
+ KUNIT_ASSERT_NOT_NULL(test, ctx->prov1_np);
+
+ KUNIT_ASSERT_EQ(test, 0, of_clk_hw_register_kunit(test, ctx->prov1_np, hw1));
+ of_clk_add_hw_provider(ctx->prov1_np, kunit_clk_get, hw1);
+ of_node_put(ctx->prov1_np);
+
+ /* Register provider 2 */
+ hw2 = kunit_kzalloc(test, sizeof(*hw2), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw2);
+ hw2->init = &clk_parse_clkspec_2_init_data;
+
+ ctx->prov2_np = of_find_compatible_node(NULL, NULL, "test,clock-provider2");
+ KUNIT_ASSERT_NOT_NULL(test, ctx->prov2_np);
+
+ KUNIT_ASSERT_EQ(test, 0, of_clk_hw_register_kunit(test, ctx->prov2_np, hw2));
+ of_clk_add_hw_provider(ctx->prov2_np, kunit_clk_get, hw2);
+ of_node_put(ctx->prov2_np);
+
+ ctx->cons_np = of_find_compatible_node(NULL, NULL, "test,clock-consumer");
+ KUNIT_ASSERT_NOT_NULL(test, ctx->cons_np);
+
+ return 0;
+}
+
+static void clk_parse_clkspec_exit(struct kunit *test)
+{
+ struct clk_parse_clkspec_ctx *ctx = test->priv;
+
+ of_node_put(ctx->prov1_np);
+ of_node_put(ctx->prov2_np);
+ of_node_put(ctx->cons_np);
+}
+
+/* Test DT phandle lookups using correct index or name succeed */
+static void clk_parse_clkspec_with_correct_index_and_name(struct kunit *test)
+{
+ struct clk_parse_clkspec_ctx *ctx = test->priv;
+ struct clk_hw *hw1, *hw2, *hw3, *hw4;
+
+ /* Get clocks by index */
+ hw1 = of_clk_get_hw(ctx->cons_np, 0, NULL);
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, hw1);
+
+ hw2 = of_clk_get_hw(ctx->cons_np, 1, NULL);
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, hw2);
+ KUNIT_EXPECT_PTR_NE(test, hw1, hw2);
+
+ /* Get clocks by name */
+ hw3 = of_clk_get_hw(ctx->cons_np, 0, "first_clock");
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, hw3);
+ KUNIT_EXPECT_PTR_EQ(test, hw1, hw3);
+
+ hw4 = of_clk_get_hw(ctx->cons_np, 0, "second_clock");
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, hw4);
+ KUNIT_EXPECT_PTR_EQ(test, hw2, hw4);
+}
+
+/* Test DT phandle lookups using wrong index or name fail */
+static void clk_parse_clkspec_with_incorrect_index_and_name(struct kunit *test)
+{
+ struct clk_parse_clkspec_ctx *ctx = test->priv;
+ struct clk_hw *hw;
+
+ /* Get clock by index */
+ hw = of_clk_get_hw(ctx->cons_np, 2, NULL);
+ KUNIT_EXPECT_TRUE(test, IS_ERR(hw));
+
+ /* Get clock by name */
+ hw = of_clk_get_hw(ctx->cons_np, 0, "third_clock");
+ KUNIT_EXPECT_TRUE(test, IS_ERR(hw));
+}
+
+static struct kunit_case clk_parse_clkspec_test_cases[] = {
+ KUNIT_CASE(clk_parse_clkspec_with_correct_index_and_name),
+ KUNIT_CASE(clk_parse_clkspec_with_incorrect_index_and_name),
+ {}
+};
+
+/* Test suite to verify clk_parse_clkspec() */
+static struct kunit_suite clk_parse_clkspec_test_suite = {
+ .name = "clk_parse_clkspec",
+ .init = clk_parse_clkspec_init,
+ .exit = clk_parse_clkspec_exit,
+ .test_cases = clk_parse_clkspec_test_cases,
+};
kunit_test_suites(
&clk_assigned_rates_suite,
&clk_hw_get_dev_of_node_test_suite,
+ &clk_parse_clkspec_test_suite,
&clk_leaf_mux_set_rate_parent_test_suite,
&clk_test_suite,
&clk_multiple_parents_mux_test_suite,
diff --git a/drivers/clk/kunit_clk_parse_clkspec.dtso b/drivers/clk/kunit_clk_parse_clkspec.dtso
new file mode 100644
index 000000000000..c93feb93e101
--- /dev/null
+++ b/drivers/clk/kunit_clk_parse_clkspec.dtso
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+&{/} {
+ kunit_clock_provider1: kunit-clock-provider1 {
+ compatible = "test,clock-provider1";
+ #clock-cells = <1>;
+ };
+
+ kunit_clock_provider2: kunit-clock-provider2 {
+ compatible = "test,clock-provider2";
+ #clock-cells = <1>;
+ };
+
+ kunit-clock-consumer {
+ compatible = "test,clock-consumer";
+ clocks = <&kunit_clock_provider1 0>, <&kunit_clock_provider2 0>;
+ clock-names = "first_clock", "second_clock";
+ };
+};
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 07/16] clk: tests: Add Kunit testing for of_clk_get_parent_name()
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
` (5 preceding siblings ...)
2026-03-27 20:09 ` [PATCH 06/16] clk: tests: Add clk_parse_clkspec() Kunit testing Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 08/16] clk: Improve a couple of comments Miquel Raynal (Schneider Electric)
` (8 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
Make sure this helper is never broken, especially since we will soon
make some changes in it.
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
drivers/clk/clk_test.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index b814b45f1f7e..8a17ad0d185f 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -3651,9 +3651,19 @@ static void clk_parse_clkspec_with_incorrect_index_and_name(struct kunit *test)
KUNIT_EXPECT_TRUE(test, IS_ERR(hw));
}
+static void clk_parse_and_get_parent_name(struct kunit *test)
+{
+ struct clk_parse_clkspec_ctx *ctx = test->priv;
+
+ KUNIT_EXPECT_STREQ(test,
+ of_clk_get_parent_name(ctx->cons_np, 0),
+ clk_parse_clkspec_1_init_data.name);
+}
+
static struct kunit_case clk_parse_clkspec_test_cases[] = {
KUNIT_CASE(clk_parse_clkspec_with_correct_index_and_name),
KUNIT_CASE(clk_parse_clkspec_with_incorrect_index_and_name),
+ KUNIT_CASE(clk_parse_and_get_parent_name),
{}
};
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 08/16] clk: Improve a couple of comments
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
` (6 preceding siblings ...)
2026-03-27 20:09 ` [PATCH 07/16] clk: tests: Add Kunit testing for of_clk_get_parent_name() Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 09/16] clk: Use the generic OF phandle parsing in only one place Miquel Raynal (Schneider Electric)
` (7 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
Avoid mentioning the function names directly in the comments, it makes
them easily out of sync with the rest of the code. Use a more generic
wording.
Suggested-by: Stephen Boyd <sboyd@kernel.org>
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
drivers/clk/clk.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 1795246b10a0..591c0780b61e 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -5213,7 +5213,7 @@ static int of_parse_clkspec(const struct device_node *np, int index,
/*
* For named clocks, first look up the name in the
* "clock-names" property. If it cannot be found, then index
- * will be an error code and of_parse_phandle_with_args() will
+ * will be an error code and the OF phandle parser will
* return -EINVAL.
*/
if (name)
@@ -5286,7 +5286,7 @@ of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec)
*
* This function looks up a struct clk from the registered list of clock
* providers, an input is a clock specifier data structure as returned
- * from the of_parse_phandle_with_args() function call.
+ * from the OF phandle parser.
*/
struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
{
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 09/16] clk: Use the generic OF phandle parsing in only one place
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
` (7 preceding siblings ...)
2026-03-27 20:09 ` [PATCH 08/16] clk: Improve a couple of comments Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 10/16] clk: Add support for clock nexus dt bindings Miquel Raynal (Schneider Electric)
` (6 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
There should be one single entry in the OF world, so that the way we
parse the DT is always the same. make sure this is the case by avoid
calling of_parse_phandle_with_args() from of_clk_get_parent_name(). This
is even more relevant as we currently fail to parse clock-ranges. As a
result, it seems to be safer to directly call of_parse_clkspec() there.
Suggested-by: Stephen Boyd <sboyd@kernel.org>
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
drivers/clk/clk.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 591c0780b61e..93e33ff30f3a 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -5375,8 +5375,7 @@ const char *of_clk_get_parent_name(const struct device_node *np, int index)
int count;
struct clk *clk;
- rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,
- &clkspec);
+ rc = of_parse_clkspec(np, index, NULL, &clkspec);
if (rc)
return NULL;
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 10/16] clk: Add support for clock nexus dt bindings
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
` (8 preceding siblings ...)
2026-03-27 20:09 ` [PATCH 09/16] clk: Use the generic OF phandle parsing in only one place Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 11/16] clk: tests: Add Kunit testing for nexus nodes Miquel Raynal (Schneider Electric)
` (5 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric), Herve Codina
A nexus node is some kind of parent device abstracting the outer
connections. They are particularly useful for describing connectors-like
interfaces but not only. Certain IP blocks will typically include inner
blocks and distribute resources to them.
In the case of clocks, there is already the concept of clock controller,
but this usually indicates some kind of control over the said clock,
ie. gate or rate control. When there is none of this, an existing
approach is to reference the upper clock, which is wrong from a hardware
point of view.
Nexus nodes are already part of the device-tree specification and clocks
are already mentioned:
https://github.com/devicetree-org/devicetree-specification/blob/v0.4/source/chapter2-devicetree-basics.rst#nexus-nodes-and-specifier-mapping
Following the introductions of nexus nodes support for interrupts, gpios
and pwms, here is the same logic applied again to the clk subsystem,
just by transitioning from of_parse_phandle_with_args() to
of_parse_phandle_with_args_map():
* Nexus OF support:
commit bd6f2fd5a1d5 ("of: Support parsing phandle argument lists through a nexus node")
* GPIO adoption:
commit c11e6f0f04db ("gpio: Support gpio nexus dt bindings")
* PWM adoption:
commit e71e46a6f19c ("pwm: Add support for pwm nexus dt bindings")
Expected Nexus properties supported:
- clock-map: maps inner clocks to inlet clocks,
- clock-map-mask: specifier cell(s) which will be remapped,
- clock-map-pass-thru: specifier cell(s) not used for remapping,
forwarded as-is.
In my own usage I had to deal with controllers where clock-map-mask and
clock-map-pass-thru were not relevant, but here is a made up example
showing how all these properties could go together:
Example:
soc_clk: clock-controller {
#clock-cells = <2>;
};
container: container {
#clock-cells = <2>;
clock-map = <0 0 &soc_clk 2 0>,
<1 0 &soc_clk 6 0>;
clock-map-mask = <0xffffffff 0x0>;
clock-map-pass-thru = <0x0 0xffffffff>;
child-device {
clocks = <&container 1 0>;
/* This is equivalent to <&soc_clk 6 0> */
};
};
The child device does not need to know about the outer implementation,
and only knows about what the nexus provides. The nexus acts as a
pass-through, with no extra control.
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
Reviewed-by: Herve Codina <herve.codina@bootlin.com>
---
drivers/clk/clk.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 93e33ff30f3a..196ba727e84b 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -5218,8 +5218,8 @@ static int of_parse_clkspec(const struct device_node *np, int index,
*/
if (name)
index = of_property_match_string(np, "clock-names", name);
- ret = of_parse_phandle_with_args(np, "clocks", "#clock-cells",
- index, out_args);
+ ret = of_parse_phandle_with_args_map(np, "clocks", "clock",
+ index, out_args);
if (!ret)
break;
if (name && index >= 0)
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 11/16] clk: tests: Add Kunit testing for nexus nodes
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
` (9 preceding siblings ...)
2026-03-27 20:09 ` [PATCH 10/16] clk: Add support for clock nexus dt bindings Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 12/16] irqchip/eip201-aic: Add support for Safexcel EIP-201 AIC Miquel Raynal (Schneider Electric)
` (4 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
Add a nexus node with a child requesting a mapped clock in the fake DT
overlay to verify that the parsing is also correctly working.
Suggested-by: Stephen Boyd <sboyd@kernel.org>
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
drivers/clk/clk_test.c | 20 ++++++++++++++++++++
drivers/clk/kunit_clk_parse_clkspec.dtso | 10 ++++++++++
2 files changed, 30 insertions(+)
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index 8a17ad0d185f..cb0071955146 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -3660,10 +3660,30 @@ static void clk_parse_and_get_parent_name(struct kunit *test)
clk_parse_clkspec_1_init_data.name);
}
+static void clk_parse_and_get_nexus(struct kunit *test)
+{
+ struct clk_parse_clkspec_ctx *ctx = test->priv;
+ struct clk_hw *hw1, *hw2;
+ struct device_node *np;
+
+ /* Get clocks by index */
+ np = of_find_node_by_name(NULL, "kunit-clock-nexus-child");
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, np);
+ hw1 = of_clk_get_hw(np, 0, NULL);
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, hw1);
+
+ hw2 = of_clk_get_hw(ctx->cons_np, 1, NULL);
+ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, hw2);
+ KUNIT_EXPECT_PTR_EQ(test, hw1, hw2);
+
+ of_node_put(np);
+}
+
static struct kunit_case clk_parse_clkspec_test_cases[] = {
KUNIT_CASE(clk_parse_clkspec_with_correct_index_and_name),
KUNIT_CASE(clk_parse_clkspec_with_incorrect_index_and_name),
KUNIT_CASE(clk_parse_and_get_parent_name),
+ KUNIT_CASE(clk_parse_and_get_nexus),
{}
};
diff --git a/drivers/clk/kunit_clk_parse_clkspec.dtso b/drivers/clk/kunit_clk_parse_clkspec.dtso
index c93feb93e101..a4115216d2aa 100644
--- a/drivers/clk/kunit_clk_parse_clkspec.dtso
+++ b/drivers/clk/kunit_clk_parse_clkspec.dtso
@@ -18,4 +18,14 @@ kunit-clock-consumer {
clocks = <&kunit_clock_provider1 0>, <&kunit_clock_provider2 0>;
clock-names = "first_clock", "second_clock";
};
+
+ kunit_clock_nexus: kunit-clock-nexus {
+ clocks = <&kunit_clock_provider2 0>;
+ clock-map = <&kunit_clock_provider2 0>;
+ #clock-cells = <0>;
+
+ kunit-clock-nexus-child {
+ clocks = <&kunit_clock_nexus>;
+ };
+ };
};
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 12/16] irqchip/eip201-aic: Add support for Safexcel EIP-201 AIC
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
` (10 preceding siblings ...)
2026-03-27 20:09 ` [PATCH 11/16] clk: tests: Add Kunit testing for nexus nodes Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-28 13:10 ` Thomas Gleixner
2026-03-27 20:09 ` [PATCH 13/16] hwrng: omap: Enable on Renesas RZ/N1D Miquel Raynal (Schneider Electric)
` (3 subsequent siblings)
15 siblings, 1 reply; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
Describe the EIP-201 Advanced Interrupt Controller from Inside Secure,
typically found in a bigger block named EIP-150. This controller is
rather simple and is driven using the generic irqchip model. Its
own interrupt domain is limited to just a few interrupts connected to
other inner blocks, such as a Random Number Generator and a Public Key
Accelerator.
The one I used receives only rising edge interrupts and uses its own
logic to track them. It is theoretically possible to wire devices with
level interrupts, but not in the context of the EIP-150.
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
drivers/irqchip/Kconfig | 8 ++
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-eip201-aic.c | 221 +++++++++++++++++++++++++++++++++++++++
3 files changed, 230 insertions(+)
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index f07b00d7fef9..b098bb00a224 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -826,4 +826,12 @@ config SUNPLUS_SP7021_INTC
chained controller, routing all interrupt source in P-Chip to
the primary controller on C-Chip.
+config SAFEXCEL_EIP201_AIC
+ tristate "Safexcel EIP201 AIC"
+ select IRQ_DOMAIN
+ help
+ Support for the Advanced Interrupt Controller (AIC) typically
+ inside Safexcel EIP150 IPs, gathering Public Key Accelerator
+ and True Random Number Generator interrupts.
+
endmenu
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 26aa3b6ec99f..80784a02f4a8 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -136,3 +136,4 @@ obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o
obj-$(CONFIG_MCHP_EIC) += irq-mchp-eic.o
obj-$(CONFIG_SOPHGO_SG2042_MSI) += irq-sg2042-msi.o
obj-$(CONFIG_SUNPLUS_SP7021_INTC) += irq-sp7021-intc.o
+obj-$(CONFIG_SAFEXCEL_EIP201_AIC) += irq-eip201-aic.o
diff --git a/drivers/irqchip/irq-eip201-aic.c b/drivers/irqchip/irq-eip201-aic.c
new file mode 100644
index 000000000000..514fd39e2777
--- /dev/null
+++ b/drivers/irqchip/irq-eip201-aic.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 Schneider Electric
+ * Authored by Miquel Raynal <miquel.raynal@bootlin.com>
+ * Based on the work from Mathieu Hadjimegrian <mathieu.hadjimegrian@non.se.com>
+ */
+
+#include "linux/irq.h"
+#include "linux/stddef.h"
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irqdomain.h>
+#include <linux/platform_device.h>
+
+#include <dt-bindings/interrupt-controller/inside-secure,safexcel-eip201.h>
+
+#define EIP201_AIC_POL_CTRL 0x0 /* RO */
+#define EIP201_AIC_POL_LOW_FALLING 0
+#define EIP201_AIC_POL_HIGH_RISING 1
+
+#define EIP201_AIC_TYP_CTRL 0x4 /* RO */
+#define EIP201_AIC_TYP_LEVEL 0
+#define EIP201_AIC_TYP_EDGE 1
+
+#define EIP201_AIC_ENABLE_SET 0xC /* WO */
+#define EIP201_AIC_ENABLED_STAT 0x10 /* RO */
+#define EIP201_AIC_ENABLE_CLR 0x14 /* WO */
+#define EIP201_AIC_ACK 0x10 /* WO */
+
+#define EIP201_AIC_REVISION 0x3FFC
+#define EIP201_AIC_REV_NUM(reg) FIELD_GET(GENMASK(7, 0), reg)
+#define EIP201_AIC_REV_COMP_NUM(reg) FIELD_GET(GENMASK(15, 8), reg)
+
+#define EIP201_AIC_INT(reg, int) field_get(BIT(int), reg)
+#define EIP201_AIC_NINT 7
+#define EIP201_AIC_INT_MASK (BIT(EIP201_AIC_NINT) - 1)
+
+struct eip201_aic {
+ struct device *dev;
+ void __iomem *regs;
+ struct irq_domain *domain;
+ struct irq_chip_generic *gc;
+ u32 type;
+ u32 pol;
+};
+
+static struct eip201_aic *irq_domain_to_aic(struct irq_domain *d)
+{
+ return d->host_data;
+}
+
+static int eip201_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_type)
+{
+ struct eip201_aic *aic = irq_domain_to_aic(d);
+ int ret;
+
+ ret = irq_domain_xlate_twocell(d, ctrlr, intspec, intsize, out_hwirq, out_type);
+ if (ret)
+ return ret;
+
+ /* One interrupt is reserved, two are for Inside Secure debugging purposes only */
+ switch (*out_hwirq) {
+ case AIC_PKA_INT0:
+ case AIC_PKA_INT1:
+ case AIC_RESERVED:
+ return -EINVAL;
+ default:
+ break;
+ }
+
+ /*
+ * Flow type is implementation specific and hardcoded, make sure it is corect,
+ * even though the documentation says EIP blocks generate edge interrupts.
+ */
+
+ /* Type register indicates:
+ * - '1' for edge interrupts
+ * - '0' for level interrupts
+ */
+ if (*out_type & IRQ_TYPE_LEVEL_MASK &&
+ EIP201_AIC_INT(aic->type, *out_hwirq))
+ return -EINVAL;
+
+ /*
+ * Polarity register indicates:
+ * - '1' for level high or rising edge
+ * - '0' for level low or falling edge
+ */
+ if (*out_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING) &&
+ EIP201_AIC_INT(aic->pol, *out_hwirq))
+ return -EINVAL;
+
+ return 0;
+}
+
+const struct irq_domain_ops eip201_aic_chip_ops = {
+ .map = irq_map_generic_chip,
+ .unmap = irq_unmap_generic_chip,
+ .xlate = eip201_aic_irq_domain_xlate,
+};
+
+static irqreturn_t eip201_aic_irq_handler(int irq, void *dev_id)
+{
+ struct eip201_aic *aic = dev_id;
+ unsigned long pending;
+ irq_hw_number_t hwirq;
+
+ pending = readl(aic->regs + EIP201_AIC_ENABLED_STAT);
+ if (!pending)
+ return IRQ_NONE;
+
+ /* Ack interrupts ASAP to decrease the likelyhood of missing an edge one */
+ writel(pending, aic->regs + EIP201_AIC_ACK);
+
+ for_each_set_bit(hwirq, &pending, EIP201_AIC_NINT)
+ generic_handle_domain_irq(aic->domain, hwirq);
+
+ return IRQ_HANDLED;
+}
+
+static int eip201_aic_probe(struct platform_device *pdev)
+{
+ struct eip201_aic *aic;
+ struct clk *clk;
+ u32 rev;
+ int irq;
+ int ret;
+
+ aic = devm_kzalloc(&pdev->dev, sizeof(*aic), GFP_KERNEL);
+ if (!aic)
+ return -ENOMEM;
+
+ aic->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (!aic->regs)
+ return -EINVAL;
+
+ clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ rev = readl(aic->regs + EIP201_AIC_REVISION);
+ if (!(EIP201_AIC_REV_NUM(rev) ^ EIP201_AIC_REV_COMP_NUM(rev)))
+ return -ENXIO;
+
+ platform_set_drvdata(pdev, aic);
+ aic->dev = &pdev->dev;
+
+ /* Cache the RO type and polarity of all interrupts */
+ aic->type = readl(aic->regs + EIP201_AIC_TYP_CTRL);
+ aic->pol = readl(aic->regs + EIP201_AIC_POL_CTRL);
+
+ /* Disable/clear all interrupts */
+ writel(EIP201_AIC_INT_MASK, aic->regs + EIP201_AIC_ENABLE_CLR);
+ writel(EIP201_AIC_INT_MASK, aic->regs + EIP201_AIC_ACK);
+
+ aic->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), EIP201_AIC_NINT,
+ &eip201_aic_chip_ops, aic);
+ if (!aic->domain)
+ return -ENXIO;
+
+ ret = irq_alloc_domain_generic_chips(aic->domain, EIP201_AIC_NINT, 1, "eip201-aic",
+ handle_edge_irq, 0, 0, 0);
+ if (ret)
+ goto remove_domain;
+
+ aic->gc = irq_get_domain_generic_chip(aic->domain, 0);
+ aic->gc->reg_base = aic->regs;
+ aic->gc->chip_types[0].regs.ack = EIP201_AIC_ACK;
+ aic->gc->chip_types[0].regs.enable = EIP201_AIC_ENABLE_SET;
+ aic->gc->chip_types[0].regs.disable = EIP201_AIC_ENABLE_CLR;
+ aic->gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
+ aic->gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg;
+ aic->gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg;
+ aic->gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(&pdev->dev, irq, eip201_aic_irq_handler, 0,
+ dev_name(&pdev->dev), aic);
+ if (ret < 0)
+ goto remove_gc;
+
+ return 0;
+
+remove_gc:
+ irq_remove_generic_chip(aic->gc, EIP201_AIC_INT_MASK, 0, 0);
+remove_domain:
+ irq_domain_remove(aic->domain);
+
+ return ret;
+}
+
+static void eip201_aic_remove(struct platform_device *pdev)
+{
+ struct eip201_aic *aic = platform_get_drvdata(pdev);
+
+ irq_remove_generic_chip(aic->gc, EIP201_AIC_INT_MASK, 0, 0);
+ irq_domain_remove(aic->domain);
+}
+
+static const struct of_device_id eip201_aic_of_match[] = {
+ { .compatible = "inside-secure,safexcel-eip201", },
+ {},
+};
+
+static struct platform_driver eip201_aic_driver = {
+ .probe = eip201_aic_probe,
+ .remove = eip201_aic_remove,
+ .driver = {
+ .name = "safexcel-eip201-aic",
+ .of_match_table = eip201_aic_of_match,
+ },
+};
+module_platform_driver(eip201_aic_driver);
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 13/16] hwrng: omap: Enable on Renesas RZ/N1D
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
` (11 preceding siblings ...)
2026-03-27 20:09 ` [PATCH 12/16] irqchip/eip201-aic: Add support for Safexcel EIP-201 AIC Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 14/16] crypto: Group Inside-Secure IPs together and align the titles Miquel Raynal (Schneider Electric)
` (2 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
The Kconfig symbol and associated seem to be badly named as they have
nothing OMAP specific but instead refer to Inside Secure Safexcel
devices which have been used in many SoCs from different
manufacturers (like OMAP, Marvell but also eg. Renesas).
The Renesas RZ/N1D features this IP, so add this architecture to the
dependency allow list. In practice this dependency list does not seem
very relevant and could be entirely dropped, given the fact that this IP
has been implemented by many different vendors and seems to be
architecture agnostic.
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
drivers/char/hw_random/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 492a2a61a65b..a26b705fb111 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -193,7 +193,7 @@ config HW_RANDOM_IXP4XX
config HW_RANDOM_OMAP
tristate "OMAP Random Number Generator support"
- depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS || ARCH_MVEBU || ARCH_K3 || COMPILE_TEST
+ depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS || ARCH_MVEBU || ARCH_K3 || ARCH_RZN1 || COMPILE_TEST
default HW_RANDOM
help
This driver provides kernel-side support for the Random Number
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 14/16] crypto: Group Inside-Secure IPs together and align the titles
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
` (12 preceding siblings ...)
2026-03-27 20:09 ` [PATCH 13/16] hwrng: omap: Enable on Renesas RZ/N1D Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 15/16] crypto: eip28: Add support for SafeXcel EIP-28 Public Key Accelerator Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 16/16] ARM: dts: renesas: r9a06g032: Describe the EIP-150 block Miquel Raynal (Schneider Electric)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
There are several drivers from the SafeXcel family already, the EIP-93,
the EIP-97 and EIP-197. We will soon also have the EIP-28.
Group them in the Kconfig menu and both titles to make explicit that
these components are from the same family and mimic the string used for
the Intel components (above in the menu).
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
drivers/crypto/Kconfig | 45 +++++++++++++++---------------
drivers/crypto/inside-secure/eip93/Kconfig | 2 +-
2 files changed, 24 insertions(+), 23 deletions(-)
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 8d3b5d2890f8..b3a6bbf0aacf 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -782,28 +782,6 @@ config CRYPTO_DEV_BCM_SPU
source "drivers/crypto/stm32/Kconfig"
-config CRYPTO_DEV_SAFEXCEL
- tristate "Inside Secure's SafeXcel cryptographic engine driver"
- depends on (OF || PCI || COMPILE_TEST) && HAS_IOMEM
- select CRYPTO_LIB_AES
- select CRYPTO_AUTHENC
- select CRYPTO_SKCIPHER
- select CRYPTO_LIB_DES
- select CRYPTO_HASH
- select CRYPTO_HMAC
- select CRYPTO_MD5
- select CRYPTO_SHA1
- select CRYPTO_SHA256
- select CRYPTO_SHA512
- select CRYPTO_CHACHA20POLY1305
- select CRYPTO_SHA3
- help
- This driver interfaces with the SafeXcel EIP-97 and EIP-197 cryptographic
- engines designed by Inside Secure. It currently accelerates DES, 3DES and
- AES block ciphers in ECB and CBC mode, as well as SHA1, SHA224, SHA256,
- SHA384 and SHA512 hash algorithms for both basic hash and HMAC.
- Additionally, it accelerates combined AES-CBC/HMAC-SHA AEAD operations.
-
config CRYPTO_DEV_ARTPEC6
tristate "Support for Axis ARTPEC-6/7 hardware crypto acceleration."
depends on ARM && (ARCH_ARTPEC || COMPILE_TEST)
@@ -876,6 +854,29 @@ config CRYPTO_DEV_SA2UL
source "drivers/crypto/aspeed/Kconfig"
source "drivers/crypto/starfive/Kconfig"
+
+config CRYPTO_DEV_SAFEXCEL
+ tristate "Support for Inside Secure's SafeXcel EIP-97/EIP-197"
+ depends on (OF || PCI || COMPILE_TEST) && HAS_IOMEM
+ select CRYPTO_LIB_AES
+ select CRYPTO_AUTHENC
+ select CRYPTO_SKCIPHER
+ select CRYPTO_LIB_DES
+ select CRYPTO_HASH
+ select CRYPTO_HMAC
+ select CRYPTO_MD5
+ select CRYPTO_SHA1
+ select CRYPTO_SHA256
+ select CRYPTO_SHA512
+ select CRYPTO_CHACHA20POLY1305
+ select CRYPTO_SHA3
+ help
+ This driver interfaces with the SafeXcel EIP-97 and EIP-197 cryptographic
+ engines designed by Inside Secure. It currently accelerates DES, 3DES and
+ AES block ciphers in ECB and CBC mode, as well as SHA1, SHA224, SHA256,
+ SHA384 and SHA512 hash algorithms for both basic hash and HMAC.
+ Additionally, it accelerates combined AES-CBC/HMAC-SHA AEAD operations.
+
source "drivers/crypto/inside-secure/eip93/Kconfig"
source "drivers/crypto/ti/Kconfig"
diff --git a/drivers/crypto/inside-secure/eip93/Kconfig b/drivers/crypto/inside-secure/eip93/Kconfig
index 8353d3d7ec9b..8a671b709a11 100644
--- a/drivers/crypto/inside-secure/eip93/Kconfig
+++ b/drivers/crypto/inside-secure/eip93/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
config CRYPTO_DEV_EIP93
- tristate "Support for EIP93 crypto HW accelerators"
+ tristate "Support for Inside Secure's SafeXcel EIP93"
depends on SOC_MT7621 || ARCH_AIROHA ||COMPILE_TEST
select CRYPTO_LIB_AES
select CRYPTO_LIB_DES
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 15/16] crypto: eip28: Add support for SafeXcel EIP-28 Public Key Accelerator
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
` (13 preceding siblings ...)
2026-03-27 20:09 ` [PATCH 14/16] crypto: Group Inside-Secure IPs together and align the titles Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 16/16] ARM: dts: renesas: r9a06g032: Describe the EIP-150 block Miquel Raynal (Schneider Electric)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
This engine provides offload for:
- RSA (RSA-PKCS1, FIPS 186-3)
- ECDSA (FIPS 186-3)
- ECDH (SP 800-56B)
The driver is stable and working, but currently only implements the RSA
algorithm. It successfully passes RSA selftests.
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
We are working on ECDSA and ECDH support, they will be added later.
We are also clarifying the terms and conditions to publish the firmware
in a repository like linux-firmwares, if ever possible.
---
drivers/crypto/Kconfig | 10 +
drivers/crypto/inside-secure/Makefile | 1 +
drivers/crypto/inside-secure/eip28.c | 760 ++++++++++++++++++++++++++++++++++
3 files changed, 771 insertions(+)
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index b3a6bbf0aacf..734649a223f7 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -877,6 +877,16 @@ config CRYPTO_DEV_SAFEXCEL
SHA384 and SHA512 hash algorithms for both basic hash and HMAC.
Additionally, it accelerates combined AES-CBC/HMAC-SHA AEAD operations.
+config CRYPTO_DEV_EIP28
+ tristate "Support Inside Secure's SafeXcel EIP28 PKA"
+ depends on SAFEXCEL_EIP201_AIC
+ select CRYPTO_AKCIPHER
+ help
+ EIP28 is a public key accelerator. It provides offload for:
+ - RSA (RSA-PKCS1, FIPS 186-3)
+ - ECDSA (FIPS 186-3)
+ - ECDH (SP 800-56B)
+
source "drivers/crypto/inside-secure/eip93/Kconfig"
source "drivers/crypto/ti/Kconfig"
diff --git a/drivers/crypto/inside-secure/Makefile b/drivers/crypto/inside-secure/Makefile
index 30d13fd5d58e..8a6f51dcec58 100644
--- a/drivers/crypto/inside-secure/Makefile
+++ b/drivers/crypto/inside-secure/Makefile
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_CRYPTO_DEV_SAFEXCEL) += crypto_safexcel.o
crypto_safexcel-objs := safexcel.o safexcel_ring.o safexcel_cipher.o safexcel_hash.o
+obj-$(CONFIG_CRYPTO_DEV_EIP28) += eip28.o
obj-y += eip93/
diff --git a/drivers/crypto/inside-secure/eip28.c b/drivers/crypto/inside-secure/eip28.c
new file mode 100644
index 000000000000..495a8cf6dfc0
--- /dev/null
+++ b/drivers/crypto/inside-secure/eip28.c
@@ -0,0 +1,760 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019-2026 Schneider Electric
+ */
+
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/scatterlist.h>
+#include <linux/of.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/firmware.h>
+#include <crypto/internal/akcipher.h>
+#include <crypto/internal/rsa.h>
+
+#define EIP28_PKA_APTR 0x0
+#define EIP28_PKA_BPTR 0x04
+#define EIP28_PKA_CPTR 0x08
+#define EIP28_PKA_DPTR 0x0c
+#define EIP28_PKA_ALENGTH 0x10
+#define EIP28_PKA_BLENGTH 0x14
+#define EIP28_PKA_VECTOR_MAXLEN 512
+#define EIP28_PKA_BITSHIFT 0x18
+#define EIP28_PKA_FUNCTION 0x1c
+#define EIP28_FUNCTION_MULTIPLY 0
+#define EIP28_FUNCTION_SEQ_MOD_EXP_CRT (1 << 12)
+#define EIP28_FUNCTION_SEQ_MOD_EXP_ACT4 (2 << 12)
+#define EIP28_FUNCTION_SEQ_ECC_ADD_AFFINE (3 << 12)
+#define EIP28_FUNCTION_SEQ_MOD_EXP_ACT2 (4 << 12)
+#define EIP28_FUNCTION_SEQ_ECC_MUL_AFFINE (5 << 12)
+#define EIP28_FUNCTION_SEQ_MOD_EXP_VAR (6 << 12)
+#define EIP28_FUNCTION_SEQ_MOD_INV (7 << 12)
+#define EIP28_FUNCTION_RUN BIT(15)
+#define EIP28_FUNCTION_SEQ_ECC_ADD_PROJECTIVE (16 << 12)
+#define EIP28_FUNCTION_SEQ_ECC_MUL_PROJECTIVE (17 << 12)
+
+#define EIP28_PKA_SEQ_CTRL 0xc8
+#define EIP28_CTRL_RESET BIT(31)
+#define EIP28_CTRL_STATUS(reg) FIELD_GET(GENMASK(15, 8), (reg))
+#define EIP28_CTRL_SEQ_IDLE 1
+
+#define EIP28_PKA_SW_REV 0xf8
+#define EIP28_PKA_REVISION 0xfc
+#define EIP28_REV_MAJOR(reg) FIELD_GET(GENMASK(27, 24), (reg))
+#define EIP28_REV_MINOR(reg) FIELD_GET(GENMASK(23, 20), (reg))
+#define EIP28_REV_PATCH_LVL(reg) FIELD_GET(GENMASK(16, 16), (reg))
+#define EIP28_REV_CAPABILITIES(reg) FIELD_GET(GENMASK(31, 28), (reg))
+
+#define EIP28_PKA_PROGRAM_RAM 0x2000
+#define EIP28_PKA_PROGRAM_RAM_SZ SZ_8K
+
+#define EIP28_PKA_NR_ODD_POW 2 /* 0 < bit_shift <= 16 */
+#define EIP28_FW_NAME "ram_code_eip28.bin"
+
+enum eip28_operation {
+ MOD_EXP_VAR,
+ MOD_EXP_ACT2,
+ MOD_EXP_ACT4,
+ MOD_EXP_CRT,
+ ECC_ADD_AFFINE,
+ ECC_ADD_PROJECTIVE,
+ ECC_MUL_AFFINE,
+ ECC_MUL_PROJECTIVE,
+ MULTIPLY,
+ MOD_INV
+};
+
+static struct eip28 *main_dev;
+
+struct eip28 {
+ void __iomem *regs;
+ struct device *dev;
+ struct clk *clk;
+ struct completion completion;
+ /* Serialize algorithms */
+ struct mutex lock;
+};
+
+struct eip28_rsa_ctx {
+ struct eip28 *priv;
+ u8 *n;
+ u8 *e;
+ u8 *d;
+ size_t n_sz;
+ size_t e_sz;
+ size_t d_sz;
+ unsigned char *message;
+};
+
+static void eip28_pkaram_write_word(struct eip28 *priv, u32 value, u32 word_off)
+{
+ writel(value, priv->regs + EIP28_PKA_PROGRAM_RAM + (word_off * 4));
+}
+
+static u32 eip28_pkaram_read_word(struct eip28 *priv, u32 word_off)
+{
+ return readl(priv->regs + EIP28_PKA_PROGRAM_RAM + (word_off * 4));
+}
+
+static void eip28_pkaram_write_vector(struct eip28 *priv, u32 *word_off,
+ const u8 *buf, u32 bytes_count)
+{
+ u32 off;
+ int i;
+
+ off = *word_off + (bytes_count / 4) - 1;
+ for (i = 0; i < bytes_count; i += 4, off -= 1)
+ eip28_pkaram_write_word(priv, cpu_to_be32(*(u32 *)(buf + i)), off);
+
+ *word_off = round_up(*word_off * 4 + bytes_count + 1, 8) / 4;
+}
+
+static void eip28_pkaram_read_vector(struct eip28 *priv, u32 start_word,
+ u8 *buf, u32 bytes_count)
+{
+ u32 off, *ptr;
+ int i;
+
+ memset(buf, 0, bytes_count);
+
+ off = start_word + (bytes_count / 4) - 1;
+ for (i = 0; i < bytes_count; i += 4, off -= 1) {
+ ptr = (u32 *)&buf[i];
+ *ptr = be32_to_cpu(eip28_pkaram_read_word(priv, off));
+ }
+}
+
+static size_t eip28_scratchpad_size(enum eip28_operation op)
+{
+ switch (op) {
+ case MOD_EXP_ACT2:
+ case MOD_EXP_ACT4:
+ case MOD_EXP_VAR:
+ return 9;
+ case MOD_EXP_CRT:
+ return 11;
+ case ECC_ADD_AFFINE:
+ case ECC_ADD_PROJECTIVE:
+ case ECC_MUL_AFFINE:
+ case ECC_MUL_PROJECTIVE:
+ return 19;
+ case MULTIPLY:
+ return 6;
+ case MOD_INV:
+ return 12;
+ default:
+ return 0;
+ }
+}
+
+static size_t eip28_work_area_size(enum eip28_operation op, u32 mod_len)
+{
+ u32 L = 0;
+
+ switch (op) {
+ case MOD_EXP_ACT2:
+ case MOD_EXP_ACT4:
+ case MOD_EXP_VAR:
+ /* (#odd powers + 3) x (B_len + 2) */
+ return (EIP28_PKA_NR_ODD_POW + 3) * (mod_len + 2);
+ case MOD_EXP_CRT:
+ /* (#odd powers + 3) x (B_len + 2) + (B_len + 2 - (B_len mod 2)) */
+ L = mod_len + 2 - (mod_len & 1);
+ return (EIP28_PKA_NR_ODD_POW + 3) * (mod_len + 2) + L;
+ case ECC_ADD_PROJECTIVE:
+ case ECC_ADD_AFFINE:
+ case ECC_MUL_PROJECTIVE:
+ case ECC_MUL_AFFINE:
+ /* 20 x (B_len + 2 + (B_len mod 2)) */
+ L = mod_len + 2 + (mod_len & 1);
+ return 20 * L;
+ case MULTIPLY:
+ case MOD_INV:
+ default:
+ return 0;
+ }
+}
+
+static size_t eip28_op_to_func(enum eip28_operation op)
+{
+ switch (op) {
+ case MOD_EXP_ACT2:
+ return EIP28_FUNCTION_SEQ_MOD_EXP_ACT2;
+ case MOD_EXP_ACT4:
+ return EIP28_FUNCTION_SEQ_MOD_EXP_ACT4;
+ case MOD_EXP_VAR:
+ return EIP28_FUNCTION_SEQ_MOD_EXP_VAR;
+ case MOD_EXP_CRT:
+ return EIP28_FUNCTION_SEQ_MOD_EXP_CRT;
+ case ECC_ADD_PROJECTIVE:
+ return EIP28_FUNCTION_SEQ_ECC_ADD_PROJECTIVE;
+ case ECC_ADD_AFFINE:
+ return EIP28_FUNCTION_SEQ_ECC_ADD_AFFINE;
+ case ECC_MUL_PROJECTIVE:
+ return EIP28_FUNCTION_SEQ_ECC_MUL_PROJECTIVE;
+ case ECC_MUL_AFFINE:
+ return EIP28_FUNCTION_SEQ_ECC_MUL_AFFINE;
+ case MULTIPLY:
+ return EIP28_FUNCTION_MULTIPLY;
+ case MOD_INV:
+ return EIP28_FUNCTION_SEQ_MOD_INV;
+ default:
+ WARN_ON_ONCE("EIP28 unsupported operation\n");
+ return 0;
+ }
+}
+
+static int eip28_vectors_overlap(u16 start_addr1, size_t len1, u16 start_addr2, size_t len2)
+{
+ u32 end_addr1 = start_addr1 + len1 - 1;
+ u32 end_addr2 = start_addr2 + len2 - 1;
+
+ return !(end_addr1 < start_addr2 || end_addr2 < start_addr1);
+}
+
+static void eip28_trigger_operation(struct eip28 *priv, enum eip28_operation op)
+{
+ writel(eip28_op_to_func(op) | EIP28_FUNCTION_RUN,
+ priv->regs + EIP28_PKA_FUNCTION);
+}
+
+static int eip28_run_mod_exp(struct eip28 *priv, u16 vector_a, u16 vector_b,
+ u16 vector_c, u16 vector_d, size_t a_wlen, size_t bc_wlen)
+{
+ size_t scratchpad_off, result_wlen;
+ u32 val;
+
+ /* 0 < a_wlen <= MAX */
+ if (!a_wlen || a_wlen > EIP28_PKA_VECTOR_MAXLEN)
+ return -EINVAL;
+
+ /* 1 < b_wlen <= MAX */
+ if (bc_wlen < 2 || bc_wlen > EIP28_PKA_VECTOR_MAXLEN)
+ return -EINVAL;
+
+ scratchpad_off = (EIP28_PKA_PROGRAM_RAM_SZ / 4) - eip28_scratchpad_size(MOD_EXP_VAR);
+ result_wlen = eip28_work_area_size(MOD_EXP_VAR, bc_wlen);
+
+ /*
+ * Make sure the area taken by each vector does not overlap with the
+ * scratchpad, the other input vectors not the result vector.
+ */
+ if ((vector_a + a_wlen > scratchpad_off) ||
+ (vector_b + bc_wlen > scratchpad_off) ||
+ (vector_c + bc_wlen > scratchpad_off) ||
+ (vector_d + result_wlen > scratchpad_off))
+ return -EINVAL;
+
+ /* Ensure 64-bit alignment (offsets are words) */
+ if (!IS_ALIGNED(vector_a, 2) || !IS_ALIGNED(vector_b, 2) ||
+ !IS_ALIGNED(vector_c, 2) || !IS_ALIGNED(vector_d, 2))
+ return -EINVAL;
+
+ /* Modulus must be odd */
+ val = eip28_pkaram_read_word(priv, vector_b);
+ if (!(val & 1))
+ return -EINVAL;
+
+ /*
+ * Make sure there is no overlap between any of the input vectors and
+ * the result vector. Only vector_c == vector_d is allowed.
+ */
+ if (eip28_vectors_overlap(vector_a, a_wlen, vector_d, result_wlen) ||
+ eip28_vectors_overlap(vector_b, bc_wlen, vector_d, result_wlen) ||
+ (vector_c != vector_d &&
+ eip28_vectors_overlap(vector_c, bc_wlen, vector_d, result_wlen)))
+ return -ERANGE;
+
+ writel(vector_a, priv->regs + EIP28_PKA_APTR);
+ writel(vector_b, priv->regs + EIP28_PKA_BPTR);
+ writel(vector_c, priv->regs + EIP28_PKA_CPTR);
+ writel(vector_d, priv->regs + EIP28_PKA_DPTR);
+ writel(a_wlen, priv->regs + EIP28_PKA_ALENGTH);
+ writel(bc_wlen, priv->regs + EIP28_PKA_BLENGTH);
+ writel(EIP28_PKA_NR_ODD_POW, priv->regs + EIP28_PKA_BITSHIFT);
+
+ eip28_trigger_operation(priv, MOD_EXP_VAR);
+
+ return 0;
+}
+
+/*
+ * EIP28 operates using vectors precisely located in PKARAM. A vector
+ * corresponds to a pointer of an element. In the RSA case:
+ * vector A = exponent (e or d)
+ * vector B = modulo (n)
+ * vector C = message
+ * vector D = result of the operations
+ *
+ * PKARAM Offset (pinternal_ram)
+ * +----------+ 0
+ * | vector A |
+ * +----------+ length(vector A)
+ * | vector B |
+ * +----------+ length(vector A) + length(vector B)
+ * | vector C |
+ * +----------+ length(vector A) + length(vector B) + length(vector C)
+ * | vector D |
+ * +----------+
+ */
+static int eip28_rsa_operation(struct akcipher_request *req, bool encrypt)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct eip28_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ u16 vector_a, vector_b, vector_c, vector_d;
+ struct eip28 *priv = ctx->priv;
+ unsigned int pkaram_off = 0;
+ size_t a_wlen, bc_wlen;
+ u32 reg;
+ int ret;
+
+ /* Sanity check */
+ if (req->src_len > ctx->n_sz)
+ return -EMSGSIZE;
+
+ /* Check if no computation is running */
+ reg = readl(priv->regs + EIP28_PKA_FUNCTION);
+ if (reg & EIP28_FUNCTION_RUN)
+ return -EBUSY;
+
+ /* Check if PKARAM is accessible */
+ reg = readl(priv->regs + EIP28_PKA_SEQ_CTRL);
+ if (reg & EIP28_CTRL_RESET) {
+ dev_err(priv->dev, "PKARAM not accessible\n");
+ return -EBUSY;
+ }
+
+ /* Initializes vector A with either 'e' or 'd' and move the internal pointer */
+ vector_a = 0;
+ if (encrypt) {
+ eip28_pkaram_write_vector(priv, &pkaram_off, ctx->e, ctx->e_sz);
+ a_wlen = ctx->e_sz / 4;
+ } else {
+ eip28_pkaram_write_vector(priv, &pkaram_off, ctx->d, ctx->d_sz);
+ a_wlen = ctx->d_sz / 4;
+ }
+
+ /* Initializes Vector B with the modulo 'n' */
+ vector_b = pkaram_off;
+ eip28_pkaram_write_vector(priv, &pkaram_off, ctx->n, ctx->n_sz);
+ bc_wlen = ctx->n_sz / 4;
+
+ /* Initializes Vector C with the message */
+ vector_c = pkaram_off;
+ memset(ctx->message, 0, ctx->n_sz - req->src_len);
+ sg_copy_to_buffer(req->src, 1, &ctx->message[ctx->n_sz - req->src_len], req->src_len);
+ eip28_pkaram_write_vector(priv, &pkaram_off, ctx->message, ctx->n_sz);
+
+ /* Initialize vector D, output will overwrite the message */
+ vector_d = vector_c;
+
+ /* Trigger operation */
+ ret = eip28_run_mod_exp(priv, vector_a, vector_b, vector_c, vector_d,
+ a_wlen, bc_wlen);
+ if (ret) {
+ dev_err(priv->dev, "Modular exponentiation error : %d\n", ret);
+ return ret;
+ }
+
+ ret = wait_for_completion_timeout(&priv->completion, msecs_to_jiffies(2000));
+ if (!ret) {
+ reinit_completion(&priv->completion);
+ return -ETIMEDOUT;
+ }
+
+ /* Retrieve result */
+ reg = readl(priv->regs + EIP28_PKA_SEQ_CTRL);
+ if (EIP28_CTRL_STATUS(reg) != EIP28_CTRL_SEQ_IDLE)
+ return -EIO;
+
+ memset(ctx->message, 0, ctx->n_sz);
+ eip28_pkaram_read_vector(priv, vector_d, ctx->message, ctx->n_sz);
+ sg_copy_from_buffer(req->dst, 1, ctx->message, ctx->n_sz);
+
+ return 0;
+}
+
+static int eip28_rsa_save_modulo(struct eip28_rsa_ctx *ctx, struct rsa_key *key)
+{
+ unsigned int nskip;
+
+ /* Skip the first empty bytes in the buffer */
+ for (nskip = 0; nskip < key->n_sz; nskip++)
+ if (key->n[nskip])
+ break;
+
+ ctx->n_sz = key->n_sz - nskip;
+
+ ctx->n = kzalloc(round_up(ctx->n_sz, 4), GFP_KERNEL);
+ if (!ctx->n)
+ return -ENOMEM;
+
+ memcpy(ctx->n, key->n + nskip, ctx->n_sz);
+ if (!ctx->n)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int eip28_rsa_save_keypart(u8 **dst, size_t *dest_sz, const u8 *src, size_t src_sz,
+ size_t modulo_size)
+{
+ unsigned int nskip, real_size_buf;
+
+ /* Skip the first empty bytes in the buffer */
+ for (nskip = 0; nskip < src_sz; nskip++)
+ if (src[nskip])
+ break;
+
+ real_size_buf = src_sz - nskip;
+ if (real_size_buf > modulo_size)
+ return -EINVAL;
+
+ /* Write data at the end of the buffer */
+ *dst = kzalloc(round_up(modulo_size, 4), GFP_KERNEL);
+ if (!*dst)
+ return -ENOMEM;
+
+ memcpy(*dst + (modulo_size - real_size_buf), src + nskip, real_size_buf);
+ *dest_sz = modulo_size;
+
+ return 0;
+}
+
+static void eip28_rsa_clean_ctx(struct eip28_rsa_ctx *ctx)
+{
+ struct eip28 *priv;
+
+ kfree(ctx->e);
+ kfree(ctx->n);
+ kfree(ctx->d);
+ kfree(ctx->message);
+
+ priv = ctx->priv;
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->priv = priv;
+}
+
+static unsigned int eip28_rsa_max_size(struct crypto_akcipher *tfm)
+{
+ struct eip28_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+
+ return ctx->n_sz;
+}
+
+static int eip28_rsa_encrypt(struct akcipher_request *req)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct eip28_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ int ret;
+
+ mutex_lock(&ctx->priv->lock);
+ ret = eip28_rsa_operation(req, true);
+ mutex_unlock(&ctx->priv->lock);
+
+ return ret;
+}
+
+static int eip28_rsa_decrypt(struct akcipher_request *req)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct eip28_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ int ret;
+
+ mutex_lock(&ctx->priv->lock);
+ ret = eip28_rsa_operation(req, false);
+ mutex_unlock(&ctx->priv->lock);
+
+ return ret;
+}
+
+static int eip28_rsa_check_key_length(unsigned int len)
+{
+ switch (len) {
+ case 256:
+ case 512:
+ case 1024:
+ case 2048:
+ case 4096:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int eip28_rsa_setkey(struct eip28_rsa_ctx *ctx, const void *key,
+ unsigned int key_len, bool private)
+{
+ struct rsa_key raw_key = {0};
+ int ret;
+
+ /* Parse the key elements: (n, e) for the public key, (n, d) for the private key */
+ if (private)
+ ret = rsa_parse_priv_key(&raw_key, key, key_len);
+ else
+ ret = rsa_parse_pub_key(&raw_key, key, key_len);
+ if (ret)
+ return ret;
+
+ /* Clean the buffers before copying the key elements */
+ eip28_rsa_clean_ctx(ctx);
+
+ /* Save the modulo 'n' */
+ ret = eip28_rsa_save_modulo(ctx, &raw_key);
+ if (ret)
+ goto clean_ctx;
+
+ ret = eip28_rsa_check_key_length(ctx->n_sz * 8);
+ if (ret)
+ goto clean_ctx;
+
+ /* Save the public exponent 'e' */
+ ret = eip28_rsa_save_keypart(&ctx->e, &ctx->e_sz,
+ raw_key.e, raw_key.e_sz, ctx->n_sz);
+ if (ret)
+ goto clean_ctx;
+
+ /* Save the private exponent 'd', if known */
+ if (private) {
+ ret = eip28_rsa_save_keypart(&ctx->d, &ctx->d_sz,
+ raw_key.d, raw_key.d_sz, ctx->n_sz);
+ if (ret)
+ goto clean_ctx;
+ }
+
+ /* Set the message buffer */
+ ctx->message = kzalloc(ctx->n_sz, GFP_KERNEL);
+ if (!ctx->message) {
+ ret = -ENOMEM;
+ goto clean_ctx;
+ }
+
+ return 0;
+
+clean_ctx:
+ eip28_rsa_clean_ctx(ctx);
+ return ret;
+}
+
+static int eip28_rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key,
+ unsigned int key_len)
+{
+ struct eip28_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+
+ return eip28_rsa_setkey(ctx, key, key_len, true);
+}
+
+static int eip28_rsa_set_pub_key(struct crypto_akcipher *tfm, const void *key,
+ unsigned int key_len)
+{
+ struct eip28_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+
+ return eip28_rsa_setkey(ctx, key, key_len, false);
+}
+
+static int eip28_rsa_init(struct crypto_akcipher *tfm)
+{
+ struct eip28_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+
+ ctx->priv = main_dev;
+
+ return 0;
+}
+
+static void eip28_rsa_exit(struct crypto_akcipher *tfm)
+{
+ struct eip28_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+
+ eip28_rsa_clean_ctx(ctx);
+}
+
+struct akcipher_alg eip28_rsa = {
+ .encrypt = eip28_rsa_encrypt,
+ .decrypt = eip28_rsa_decrypt,
+ .set_pub_key = eip28_rsa_set_pub_key,
+ .set_priv_key = eip28_rsa_set_priv_key,
+ .max_size = eip28_rsa_max_size,
+ .init = eip28_rsa_init,
+ .exit = eip28_rsa_exit,
+ .base = {
+ .cra_name = "rsa",
+ .cra_driver_name = "eip28-rsa",
+ .cra_flags = CRYPTO_ALG_TYPE_AKCIPHER,
+ .cra_priority = 300,
+ .cra_module = THIS_MODULE,
+ .cra_ctxsize = sizeof(struct eip28_rsa_ctx),
+ },
+};
+
+static int eip28_check_firmware(struct eip28 *priv)
+{
+ u32 reg;
+
+ reg = readl(priv->regs + EIP28_PKA_REVISION);
+ if (EIP28_REV_MAJOR(reg) != 2) {
+ dev_err(priv->dev, "Unsupported hardware revision: %lu.%lu.%lu\n",
+ EIP28_REV_MAJOR(reg), EIP28_REV_MINOR(reg), EIP28_REV_PATCH_LVL(reg));
+ return -EINVAL;
+ }
+
+ reg = readl(priv->regs + EIP28_PKA_SW_REV);
+ if ((EIP28_REV_MAJOR(reg) != 2) ||
+ (EIP28_REV_MINOR(reg) != 1) ||
+ (EIP28_REV_PATCH_LVL(reg) != 1) ||
+ (EIP28_REV_CAPABILITIES(reg) != 2)) {
+ dev_err(priv->dev, "Unsupported firmware revision: %lu.%lu.%lu.%lu\n",
+ EIP28_REV_MAJOR(reg), EIP28_REV_MINOR(reg),
+ EIP28_REV_PATCH_LVL(reg), EIP28_REV_CAPABILITIES(reg));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int eip28_write_firmware(struct eip28 *priv, const struct firmware *eip28_fw)
+{
+ const u32 *data = (const u32 *)eip28_fw->data;
+ u32 reg;
+ int i;
+
+ if (eip28_fw->size > EIP28_PKA_PROGRAM_RAM_SZ)
+ return -EOPNOTSUPP;
+
+ /* Enter reset mode, which allows writing of PKA_PROGRAM_RAM registers */
+ writel(EIP28_CTRL_RESET, priv->regs + EIP28_PKA_SEQ_CTRL);
+ reg = readl(priv->regs + EIP28_PKA_SEQ_CTRL);
+ if (reg != EIP28_CTRL_RESET)
+ return -EIO;
+
+ for (i = 0; i < (eip28_fw->size / sizeof(u32)); i++)
+ writel(data[i], priv->regs + EIP28_PKA_PROGRAM_RAM + (i * 4));
+
+ /* Release reset mode, start the EIP28 */
+ writel(0, priv->regs + EIP28_PKA_SEQ_CTRL);
+ reg = readl(priv->regs + EIP28_PKA_SEQ_CTRL);
+ if (reg & EIP28_CTRL_RESET)
+ return -EIO;
+
+ return 0;
+}
+
+static int eip28_load_firmware(struct eip28 *priv)
+{
+ const struct firmware *eip28_fw;
+ int ret = 0;
+
+ ret = request_firmware(&eip28_fw, EIP28_FW_NAME, priv->dev);
+ if (ret)
+ return ret;
+
+ /* Write the EIP28 firmware in RAM CODE registers */
+ ret = eip28_write_firmware(priv, eip28_fw);
+ release_firmware(eip28_fw);
+ if (ret) {
+ dev_err(priv->dev, "Unable to write firmware (%d)\n", ret);
+ return ret;
+ }
+
+ /*
+ * Once firmware is loaded, after releasing the reset bit the firmware
+ * starts executing and after a few clock cycles it clears the RUN bit,
+ * indicating initialization is done.
+ */
+ ret = wait_for_completion_timeout(&priv->completion, msecs_to_jiffies(1000));
+ if (!ret) {
+ dev_err(priv->dev, "Firmware loading failed\n");
+ return -ETIMEDOUT;
+ }
+
+ /* Verify the firmware: can be read, is valid, has the correct version */
+ return eip28_check_firmware(priv);
+}
+
+static irqreturn_t eip28_irq_handler(int irq, void *dev_id)
+{
+ struct eip28 *priv = dev_id;
+
+ complete(&priv->completion);
+
+ return IRQ_HANDLED;
+}
+
+static int eip28_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct eip28 *priv;
+ int irq, ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->regs))
+ return PTR_ERR(priv->regs);
+
+ priv->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return PTR_ERR(priv->regs);
+
+ irq = platform_get_irq(pdev, 2);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(dev, irq, eip28_irq_handler, 0, "eip28", priv);
+ if (ret)
+ return ret;
+
+ main_dev = priv;
+ priv->dev = dev;
+ init_completion(&priv->completion);
+ mutex_init(&priv->lock);
+
+ /* Initialize the code section of the internal RAM with the firmware */
+ ret = eip28_load_firmware(priv);
+ if (ret) {
+ dev_err(dev, "Unable to initialize EIP28 firmware (%d)\n", ret);
+ return ret;
+ }
+
+ /* Initializing crypto API for RSA keys */
+ ret = crypto_register_akcipher(&eip28_rsa);
+ if (ret) {
+ dev_err(dev, "Unable to initialize RSA\n");
+ return ret;
+ }
+
+ dev_info(dev, "EIP28 probed successfully\n");
+
+ return ret;
+}
+
+static void eip28_remove(struct platform_device *pdev)
+{
+ crypto_unregister_akcipher(&eip28_rsa);
+}
+
+static const struct of_device_id eip28_of_match_table[] = {
+ { .compatible = "inside-secure,safexcel-eip28", },
+ {}
+};
+
+static struct platform_driver eip28_driver = {
+ .probe = eip28_probe,
+ .remove = eip28_remove,
+ .driver = {
+ .name = "Safexcel EIP28 PKA",
+ .of_match_table = eip28_of_match_table,
+ },
+};
+module_platform_driver(eip28_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pierre Castellan <pierre.castellan@non.se.com>");
+MODULE_AUTHOR("Thomas Ghesquiere <thomas.ghesquierre@non.se.com>");
+MODULE_AUTHOR("Mathieu Hadjimegrian <mathieu.hadjimegrian@non.se.com>");
+MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
+MODULE_DESCRIPTION("SafeXcel EIP28 Public Key Accelerator driver");
+MODULE_FIRMWARE(EIP28_FW_NAME);
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 16/16] ARM: dts: renesas: r9a06g032: Describe the EIP-150 block
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
` (14 preceding siblings ...)
2026-03-27 20:09 ` [PATCH 15/16] crypto: eip28: Add support for SafeXcel EIP-28 Public Key Accelerator Miquel Raynal (Schneider Electric)
@ 2026-03-27 20:09 ` Miquel Raynal (Schneider Electric)
15 siblings, 0 replies; 18+ messages in thread
From: Miquel Raynal (Schneider Electric) @ 2026-03-27 20:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
Jayesh Choudhary, David S. Miller, Christian Marangi,
Antoine Tenart, Geert Uytterhoeven, Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
The EIP-150 is composed of 3 blocks:
* An interrupt controller named EIP-201 AIC
- fed by a clock coming from the EIP-150
- connected to the main GIC
* A random number generator named EIP-76
- fed by a clock coming from the EIP-150
- signalling interrupts through the AIC
* A public key accelerator engine named EIP-28
- Fed by a clock coming from the EIP-150
- Signalling interrupts through the AIC
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
---
arch/arm/boot/dts/renesas/r9a06g032.dtsi | 42 ++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/arch/arm/boot/dts/renesas/r9a06g032.dtsi b/arch/arm/boot/dts/renesas/r9a06g032.dtsi
index f4f760aff28b..6aaa93ed03d6 100644
--- a/arch/arm/boot/dts/renesas/r9a06g032.dtsi
+++ b/arch/arm/boot/dts/renesas/r9a06g032.dtsi
@@ -8,6 +8,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/r9a06g032-sysctrl.h>
+#include <dt-bindings/interrupt-controller/inside-secure,safexcel-eip201.h>
/ {
compatible = "renesas,r9a06g032";
@@ -170,6 +171,47 @@ usb@2,0 {
};
};
+ eip150: bus@40040000 {
+ compatible = "inside-secure,safexcel-eip150", "simple-pm-bus";
+ clocks = <&sysctrl R9A06G032_HCLK_CRYPTO_EIP150>;
+ #clock-cells = <0>;
+ clock-map = <&sysctrl R9A06G032_HCLK_CRYPTO_EIP150>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x40040000 0x40040000 0x10000>;
+ status = "disabled";
+
+ eip76_rng: rng@40040000 {
+ compatible = "inside-secure,safexcel-eip76";
+ reg = <0x40040000 0x80>;
+ interrupt-parent = <&eip201_aic>;
+ interrupts = <AIC_TRNG_INT IRQ_TYPE_EDGE_RISING>;
+ clocks = <&eip150>;
+ status = "disabled";
+ };
+
+ eip28_pka: crypto@40044000 {
+ compatible = "inside-secure,safexcel-eip28";
+ reg = <0x40044000 0x4000>;
+ interrupt-parent = <&eip201_aic>;
+ interrupts = <AIC_PKA_INT0 IRQ_TYPE_EDGE_RISING>,
+ <AIC_PKA_INT1 IRQ_TYPE_EDGE_RISING>,
+ <AIC_PKA_INT2 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&eip150>;
+ status = "disabled";
+ };
+
+ eip201_aic: interrupt-controller@40048000 {
+ compatible = "inside-secure,safexcel-eip201";
+ reg = <0x40048000 0x4000>;
+ interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&eip150>;
+ status = "disabled";
+ };
+ };
+
uart0: serial@40060000 {
compatible = "renesas,r9a06g032-uart", "renesas,rzn1-uart", "snps,dw-apb-uart";
reg = <0x40060000 0x400>;
--
2.51.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 12/16] irqchip/eip201-aic: Add support for Safexcel EIP-201 AIC
2026-03-27 20:09 ` [PATCH 12/16] irqchip/eip201-aic: Add support for Safexcel EIP-201 AIC Miquel Raynal (Schneider Electric)
@ 2026-03-28 13:10 ` Thomas Gleixner
0 siblings, 0 replies; 18+ messages in thread
From: Thomas Gleixner @ 2026-03-28 13:10 UTC (permalink / raw)
To: Miquel Raynal (Schneider Electric), Michael Turquette,
Stephen Boyd, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Olivia Mackall, Herbert Xu, Jayesh Choudhary, David S. Miller,
Christian Marangi, Antoine Tenart, Geert Uytterhoeven,
Magnus Damm
Cc: Thomas Petazzoni, Pascal EBERHARD, Wolfram Sang, linux-clk,
devicetree, linux-kernel, linux-crypto, linux-renesas-soc,
Miquel Raynal (Schneider Electric)
On Fri, Mar 27 2026 at 21:09, Miquel Raynal wrote:
> +config SAFEXCEL_EIP201_AIC
> + tristate "Safexcel EIP201 AIC"
TAB, not spaces please
> + select IRQ_DOMAIN
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2026 Schneider Electric
> + * Authored by Miquel Raynal <miquel.raynal@bootlin.com>
> + * Based on the work from Mathieu Hadjimegrian <mathieu.hadjimegrian@non.se.com>
> + */
> +
> +#include "linux/irq.h"
> +#include "linux/stddef.h"
That's not a standard include format.
> +
> +struct eip201_aic {
> + struct device *dev;
> + void __iomem *regs;
> + struct irq_domain *domain;
> + struct irq_chip_generic *gc;
> + u32 type;
> + u32 pol;
> +};
Please follow:
https://www.kernel.org/doc/html/latest/process/maintainer-tip.html#struct-declarations-and-initializers
> +
> + /* Type register indicates:
See 'comment style' in the same document.
> + * - '1' for edge interrupts
> + * - '0' for level interrupts
> + */
> + if (*out_type & IRQ_TYPE_LEVEL_MASK &&
> + EIP201_AIC_INT(aic->type, *out_hwirq))
No line break required. You have 100 characters.
> +static int eip201_aic_probe(struct platform_device *pdev)
> +{
> + struct eip201_aic *aic;
> + struct clk *clk;
> + u32 rev;
> + int irq;
> + int ret;
See 'variable declarations' in the same document.
> + irq = platform_get_irq(pdev, 0);
> + if (irq < 0)
> + return irq;
Leaks the chip and the domain.
> +static struct platform_driver eip201_aic_driver = {
> + .probe = eip201_aic_probe,
> + .remove = eip201_aic_remove,
> + .driver = {
> + .name = "safexcel-eip201-aic",
> + .of_match_table = eip201_aic_of_match,
See above.
Thanks,
tglx
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2026-03-28 13:10 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-27 20:09 [PATCH 00/16] Add support for Inside-Secure EIP-150 crypto block Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 01/16] dt-bindings: clock: Introduce nexus nodes Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 02/16] dt-bindings: interrupt-controller: Describe EIP-201 AIC Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 03/16] dt-bindings: rng: Rename the title of the EIP-76 file Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 04/16] dt-bindings: crypto: eip28: Describe EIP-28 PKA Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 05/16] dt-bindings: bus: eip150: Describe the EIP-150 container node Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 06/16] clk: tests: Add clk_parse_clkspec() Kunit testing Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 07/16] clk: tests: Add Kunit testing for of_clk_get_parent_name() Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 08/16] clk: Improve a couple of comments Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 09/16] clk: Use the generic OF phandle parsing in only one place Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 10/16] clk: Add support for clock nexus dt bindings Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 11/16] clk: tests: Add Kunit testing for nexus nodes Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 12/16] irqchip/eip201-aic: Add support for Safexcel EIP-201 AIC Miquel Raynal (Schneider Electric)
2026-03-28 13:10 ` Thomas Gleixner
2026-03-27 20:09 ` [PATCH 13/16] hwrng: omap: Enable on Renesas RZ/N1D Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 14/16] crypto: Group Inside-Secure IPs together and align the titles Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 15/16] crypto: eip28: Add support for SafeXcel EIP-28 Public Key Accelerator Miquel Raynal (Schneider Electric)
2026-03-27 20:09 ` [PATCH 16/16] ARM: dts: renesas: r9a06g032: Describe the EIP-150 block Miquel Raynal (Schneider Electric)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox