* Re: [PATCH v17 4/4] crypto: spacc - Add SPAcc Kconfig and Makefile
From: sashiko-bot @ 2026-07-20 11:53 UTC (permalink / raw)
To: Pavitrakumar Managutte; +Cc: devicetree, robh, conor+dt
In-Reply-To: <20260720113740.64960-5-pavitrakumarm@vayavyalabs.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] CRYPTO_DEV_SPACC_HASH is defined as a tristate option but controls a component of a composite module, leading to an undefined reference linker error when configured as 'm' while the main driver is 'y'.
--
--- Patch [4]: [PATCH v17 4/4] crypto: spacc - Add SPAcc Kconfig and Makefile ---
commit 6d5d2ec49262f31f1558921632e08b8a62362a2d
Author: Pavitrakumar Managutte <pavitrakumarm@vayavyalabs.com>
crypto: spacc - Add SPAcc Kconfig and Makefile
Add Makefile and Kconfig for SPAcc driver.
> diff --git a/drivers/crypto/dwc-spacc/Kconfig b/drivers/crypto/dwc-spacc/Kconfig
> new file mode 100644
> index 0000000000000..edc550562235e
> --- /dev/null
> +++ b/drivers/crypto/dwc-spacc/Kconfig
> @@ -0,0 +1,83 @@
[ ... ]
> +if CRYPTO_DEV_SPACC
> +
> +config CRYPTO_DEV_SPACC_HASH
> + tristate "Enable HASH functionality"
[Severity: Low]
Will this cause a build failure if CONFIG_CRYPTO_DEV_SPACC=y and
CONFIG_CRYPTO_DEV_SPACC_HASH=m?
Since CRYPTO_DEV_SPACC_HASH is a tristate, it can be set to 'm' while the
main driver is built-in ('y'). If that happens, Kbuild will add
spacc_ahash.o to snps-spacc-m in the Makefile:
snps-spacc-$(CONFIG_CRYPTO_DEV_SPACC_HASH) += spacc_ahash.o
Because snps-spacc is built-in, Kbuild ignores the -m list, meaning
spacc_ahash.o won't be linked into the final kernel image.
However, IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_HASH) evaluates to true for 'm'
as well. This can lead to undefined reference errors when spacc_crypto_probe()
tries to call spacc_probe_hashes() and spacc_unregister_hash_algs() in
spacc_device.c.
Should CRYPTO_DEV_SPACC_HASH be a bool instead to prevent this mismatch?
> + default CRYPTO_DEV_SPACC
> + select CRYPTO_HASH
> + select CRYPTO_SHA1
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720113740.64960-1-pavitrakumarm@vayavyalabs.com?part=4
^ permalink raw reply
* Re: [PATCH v3 0/2] PHY: Add support for MT8196 DSI PHY
From: Vinod Koul @ 2026-07-20 11:43 UTC (permalink / raw)
To: chunfeng.yun, AngeloGioacchino Del Regno
Cc: neil.armstrong, robh, krzk+dt, conor+dt, chunkuang.hu, p.zabel,
matthias.bgg, justin.yeh, linux-arm-kernel, linux-mediatek,
linux-phy, devicetree, linux-kernel, dri-devel, kernel
In-Reply-To: <20260713103805.23030-1-angelogioacchino.delregno@collabora.com>
On Mon, 13 Jul 2026 12:38:03 +0200, AngeloGioacchino Del Regno wrote:
> Changes in v3:
> - Actually sent the correct patch series (sorry, I had messed up v2)
> - Added definitions for minimum and maximum PLL rates
>
> Changes in v2:
> - Added a few comments and fix scheduling while atomic issue in clk
> enable ops by waiting with udelay() instead
> - Removed one unnecessary delay after clk/pwr isolation disablement
>
> [...]
Applied, thanks!
[1/2] dt-bindings: phy: mediatek,dsi-phy: Add support for MT8196
commit: 215cd5def8eca1c2aa7ca043483d96155a1c3ed6
[2/2] phy: mediatek: Add support for MT8196 MIPI DSI PHY
commit: 2ec9c210c1f931389709aee403d28e4f32676385
Best regards,
--
~Vinod
^ permalink raw reply
* Re: [PATCH v17 1/4] dt-bindings: crypto: Document support for SPAcc
From: sashiko-bot @ 2026-07-20 11:43 UTC (permalink / raw)
To: Pavitrakumar Managutte; +Cc: devicetree, conor+dt, robh
In-Reply-To: <20260720113740.64960-2-pavitrakumarm@vayavyalabs.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Low] The `reg` property size in the device tree example is incorrectly specified as 0x3ffff instead of 0x40000, representing an off-by-one error.
- [Low] The first sentence in the description block is a sentence fragment, and there is a missing space in the title.
--
--- Patch [1]: [PATCH v17 1/4] dt-bindings: crypto: Document support for SPAcc ---
commit 7ed8f2fc8bca4b54b48a471d2592cf36275dd72a
Author: Pavitrakumar Managutte <pavitrakumarm@vayavyalabs.com>
dt-bindings: crypto: Document support for SPAcc
Add DT bindings related to the SPAcc driver for Documentation.
DWC Synopsys Security Protocol Accelerator(SPAcc) Hardware Crypto
Engine is a crypto IP designed by Synopsys.
> diff --git a/Documentation/devicetree/bindings/crypto/snps,dwc-spacc.yaml b/Documentation/devicetree/bindings/crypto/snps,dwc-spacc.yaml
> new file mode 100644
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/crypto/snps,dwc-spacc.yaml
[ ... ]
> +$id: http://devicetree.org/schemas/crypto/snps,dwc-spacc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Synopsys DesignWare Security Protocol Accelerator(SPAcc) Crypto Engine
[Severity: Low]
This isn't a bug, but is it intentional to omit the space before the
parenthesis here?
> +
> +maintainers:
> + - Ross Bannerman <rbannerm@synopsys.com>
> +
> +description: |
> + The Synopsys DWC Security Protocol Accelerator (SPAcc), which is a
> + semiconductor IP designed to accelerate cryptographic operations,
> + such as encryption, decryption, and hashing.
[Severity: Low]
This isn't a bug, but this first sentence appears to be a fragment since it
uses a relative "which is" clause without a main verb. Could this be
rephrased for better readability?
[ ... ]
> +additionalProperties: false
> +
> +examples:
> + - |
> + crypto@40000000 {
> + compatible = "snps,nsimosci-hs-spacc";
> + reg = <0x40000000 0x3ffff>;
[Severity: Low]
Does this reg size represent an off-by-one error?
Device tree reg properties take <address length>, rather than
<address max_offset>. If a 256 KB memory region is intended, should this size
be 0x40000 instead of 0x3ffff?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720113740.64960-1-pavitrakumarm@vayavyalabs.com?part=1
^ permalink raw reply
* Re: [PATCH v2 0/2] riscv: spacemit: Add K3 PCIe/USB comb phy support
From: Vinod Koul @ 2026-07-20 11:43 UTC (permalink / raw)
To: Neil Armstrong, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Yixun Lan, Kees Cook, Gustavo A. R. Silva, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Alex Elder, Ze Huang,
Inochi Amaoto
Cc: linux-phy, devicetree, linux-riscv, spacemit, linux-kernel,
linux-hardening, Longbin Li, Yixun Lan
In-Reply-To: <20260703021024.495433-1-inochiama@gmail.com>
On Fri, 03 Jul 2026 10:10:21 +0800, Inochi Amaoto wrote:
> The PCIe/USB comb phy on K3 is a big phy that contains multiple
> standalone phys for each PCIe and USB controllers. This phy is
> required to configure a syscon device for mux configuration and
> calibration.
>
> Changed from v1:
> patch 1:
> 1. Add extra description for "#phy-cells" and "spacemit,apmu"
> patch 2:
> 1. Fix multiple spelling errors and copy-paste errors.
> 2. Make some magic number as meaningful macros.
> 3. Remove USB3 set_speed() callback as it is not needed.
> 4. Fix the wrong land data config and mask.
>
> [...]
Applied, thanks!
[1/2] dt-bindings: phy: Add Spacemit K3 USB3/PCIe comb phy support
commit: 013004374b4da621e292408112413b103dd28b03
[2/2] phy: spacemit: Add USB3/PCIe comb PHY driver for Spacemit K3
commit: 7a099760ea63ced7b194852b7dbbdcd951585f15
Best regards,
--
~Vinod
^ permalink raw reply
* Re: [PATCH v4 0/4] phy: qcom: qmp-pcie: Add PCIe PHY support for Hawi
From: Vinod Koul @ 2026-07-20 11:43 UTC (permalink / raw)
To: Neil Armstrong, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthew Leung
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel,
Krzysztof Kozlowski
In-Reply-To: <20260707-hawi-phy-pcie-v4-0-8d9cc6324947@oss.qualcomm.com>
On Tue, 07 Jul 2026 20:32:45 +0000, Matthew Leung wrote:
> This series adds QMP PCIe PHY support for the Qualcomm Hawi SoC. The Hawi
> platform features two PCIe PHY configurations: Gen3 x2 and Gen4 x1.
>
> The Gen3 x2 PHY uses v10 register definitions, while the Gen4 x1 PHY uses
> v10.60 register definitions.
>
> The series adds:
> - device tree bindings
> - v10 register offset headers
> - v10.60 register offset headers
> - driver support with PHY initialization tables for both configurations
>
> [...]
Applied, thanks!
[1/4] dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: Add Hawi compatibles
commit: d15224492d1aef8b28508f23b889ee0394b07b83
[2/4] phy: qcom-qmp: Add v10 register offsets
commit: 0696cc735dc7ff53297ad2ee649ceed3b1f93d07
[3/4] phy: qcom-qmp: Add v10.60 register offsets
commit: fdfe6417e2e699890f51bcc0b772734a0431e5d2
[4/4] phy: qcom: qmp-pcie: Add QMP PCIe PHY support for Hawi
commit: 9ef4e520912e4966081e276beda628b69aac85dd
Best regards,
--
~Vinod
^ permalink raw reply
* Re: [PATCH v7 05/10] arm64: dts: qcom: shikra: Add CDSP, LPAICP, MPSS remoteproc PAS nodes
From: sashiko-bot @ 2026-07-20 11:41 UTC (permalink / raw)
To: Komal Bajaj; +Cc: dmaengine, devicetree, robh, vkoul, conor+dt, Frank.Li
In-Reply-To: <20260720-shikra-dt-m1-v7-5-7dc99100c6dd@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Low] Incorrect IRQ type `IRQ_TYPE_NONE` specified for SMP2P interrupts in `remoteproc_lpaicp` node.
- [Low] Semantic API Violation: Usage of RPMh macro `RPMHPD_CX` with an RPM SMD power controller (`rpmpd`).
--
--- Patch [5]: [PATCH v7 05/10] arm64: dts: qcom: shikra: Add CDSP, LPAICP, MPSS remoteproc PAS nodes ---
commit 65c0930ecad74d3ed9ab1c696c97ce9cf5c374b0
Author: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
arm64: dts: qcom: shikra: Add CDSP, LPAICP, MPSS remoteproc PAS nodes
Add nodes for remoteproc PAS loader for CDSP, LPAICP, MPSS subsystem.
> diff --git a/arch/arm64/boot/dts/qcom/shikra.dtsi b/arch/arm64/boot/dts/qcom/shikra.dtsi
> --- a/arch/arm64/boot/dts/qcom/shikra.dtsi
> +++ b/arch/arm64/boot/dts/qcom/shikra.dtsi
[ ... ]
> @@ -1813,6 +1813,170 @@ &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>,
> };
> };
>
> + remoteproc_mpss: remoteproc@6080000 {
> + compatible = "qcom,shikra-mpss-pas";
> + reg = <0x0 0x06080000 0x0 0x100>;
[ ... ]
> + power-domains = <&rpmpd RPMHPD_CX>;
[Severity: Low]
Is this using the correct power domain macro? The Shikra SoC uses an RPM SMD
power controller (rpmpd), not RPMh, so shouldn't this be RPMPD_VDDCX instead of
RPMHPD_CX?
> +
> + memory-region = <&mpss_wlan_mem>;
[ ... ]
> + remoteproc_cdsp: remoteproc@b300000 {
> + compatible = "qcom,shikra-cdsp-pas";
> + reg = <0x0 0x0b300000 0x0 0x100000>;
[ ... ]
> + power-domains = <&rpmpd RPMHPD_CX>;
[Severity: Low]
Similar to the remoteproc_mpss node, shouldn't this use RPMPD_VDDCX instead of
the RPMh macro RPMHPD_CX?
> +
> + memory-region = <&cdsp_mem>;
[ ... ]
> + remoteproc_lpaicp: remoteproc@b800000 {
> + compatible = "qcom,shikra-lpaicp-pas";
> + reg = <0x0 0x0b800000 0x0 0x200000>;
> +
> + interrupts-extended = <&intc GIC_SPI 257 IRQ_TYPE_EDGE_RISING 0>,
> + <&lmcu_smp2p_in 0 IRQ_TYPE_NONE>,
> + <&lmcu_smp2p_in 1 IRQ_TYPE_NONE>,
> + <&lmcu_smp2p_in 2 IRQ_TYPE_NONE>,
> + <&lmcu_smp2p_in 3 IRQ_TYPE_NONE>;
[Severity: Low]
Are these lmcu_smp2p_in interrupts correctly defined as IRQ_TYPE_NONE? The
hardware SMP2P interrupts are edge-triggered, so should these be specified as
IRQ_TYPE_EDGE_RISING instead?
> +
> + interrupt-names = "wdog",
> + "fatal",
> + "ready",
> + "handover",
> + "stop-ack";
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720-shikra-dt-m1-v7-0-7dc99100c6dd@oss.qualcomm.com?part=5
^ permalink raw reply
* Re: [PATCH v5 3/5] dt-bindings: mfd: x-powers,axp152: Document AXP318W
From: sashiko-bot @ 2026-07-20 11:40 UTC (permalink / raw)
To: Jerome Brunet; +Cc: conor+dt, devicetree, robh
In-Reply-To: <20260720-axp318-regulator-v5-3-a1afa7ee24f9@baylibre.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The driver statically assigns hard-coded `.id` values inside its `mfd_cell` arrays and bypasses automatic ID allocation by passing `PLATFORM_DEVID_NONE` to `mfd_add_devices()`, violating the MFD subsystem guidelines.
--
--- Patch [3]: [PATCH v5 3/5] dt-bindings: mfd: x-powers,axp152: Document AXP318W ---
commit 0c5a5d45e78382d3cb52bdfeed22ad1c54a031fd
Author: Andre Przywara <andre.przywara@arm.com>
dt-bindings: mfd: x-powers,axp152: Document AXP318W
The X-Powers AXP318W is a PMIC used on some newer Allwinner devices.
Among a large number of both DCDC and LDO regulators it features the usual
ADC/IRQ/power key parts. Like other recent PMICs, it lacks the DC/DC converter
PWM frequency control register, that rate is fixed here.
> diff --git a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
> index 45f015d63df16..38556c32417b3 100644
> --- a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
> +++ b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
[ ... ]
> @@ -277,7 +303,7 @@ properties:
> Defines the work frequency of DC-DC in kHz.
>
> patternProperties:
> - "^(([a-f])?ldo[0-9]|dcdc[0-7a-e]|ldo(_|-)io(0|1)|(dc1)?sw|rtc(_|-)ldo|cpusldo|drivevbus|dc5ldo|boost)$":
> + "^(([a-f])?ldo[0-9]|dcdc[0-9a-e]|ldo(_|-)io(0|1)|(dc1)?sw|swout[1-2]|rtc(_|-)ldo|cpusldo|drivevbus|dc5ldo|boost)$":
> $ref: /schemas/regulator/regulator.yaml#
> type: object
> unevaluatedProperties: false
[Severity: High]
This is a pre-existing issue, but while reviewing these changes, I noticed
a potential problem with how the driver handles cell IDs in
drivers/mfd/axp20x.c.
The mfd_cell array explicitly hardcodes the subdevice cell ID to 1:
drivers/mfd/axp20x.c:axp313a_cells[] {
...
MFD_CELL_BASIC("axp20x-regulator", NULL, NULL, 0, 1),
...
}
The driver then forces the platform bus to consume these hard-coded cell IDs
rather than generating safe dynamic IDs:
drivers/mfd/axp20x.c:axp20x_device_probe() {
...
ret = mfd_add_devices(axp20x->dev, PLATFORM_DEVID_NONE, axp20x->cells,
axp20x->nr_cells, NULL, 0, NULL);
...
}
Could this lead to device naming collisions in sysfs and driver load failures
if multiple MFD instances of the same type are instantiated?
If multiple PMICs sharing the same cell definitions are present, they might
attempt to register subdevices with the same hardcoded name and ID.
This would result in a fatal probe failure for the colliding subdevices.
Should this code use PLATFORM_DEVID_AUTO instead of PLATFORM_DEVID_NONE to
ensure automatic cell indexing?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720-axp318-regulator-v5-0-a1afa7ee24f9@baylibre.com?part=3
^ permalink raw reply
* Re: [PATCH 2/2] media: i2c: Add a driver for Sony IMX708
From: Sakari Ailus @ 2026-07-20 11:40 UTC (permalink / raw)
To: Jai Luthra
Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Dave Stevenson, Naushir Patuck, David Plowman,
Kieran Bingham, Laurent Pinchart, linux-media, devicetree,
Raspberry Pi Kernel Maintenance, Nick Hollinghurst
In-Reply-To: <20260715-imx708-v1-2-1f36f54e14d4@ideasonboard.com>
Hi Jai,
Thanks for the set.
On Wed, Jul 15, 2026 at 11:01:29PM +0530, Jai Luthra wrote:
> Sony IMX708 is an 11.9 Megapixel CMOS sensor with a 16:9 aspect ratio.
> It is a quad-bayer sensor with support for remosaicing the output to
> a normal 2x2 bayer pattern.
>
> This basic driver adds supports for capturing the full active-area of
> 4608x2592, up to 14.35fps. The following features are supported by the
> driver:
> - MIPI RAW10 output
> - Fixed quad-bayer correction
> - Multiple link frequencies (different IOP_PLL_MPY)
> - VBLANK control for flexible frame-rate
> - Analogue gain and exposure control
> - Extremely long exposure time with LONG_EXP_SHIFT
> - Test pattern support
How close is this sensor actually to CCS? A lot of the registers look like
they're CCS registers while there are some MSRs set programmatically by the
driver, too.
--
Kind regards,
Sakari Ailus
^ permalink raw reply
* [PATCH v17 4/4] crypto: spacc - Add SPAcc Kconfig and Makefile
From: Pavitrakumar Managutte @ 2026-07-20 11:37 UTC (permalink / raw)
To: linux-crypto, linux-kernel, devicetree, herbert, robh
Cc: krzk, conor+dt, ruud.derwig, rbannerm, manjunath.hadli, adityak,
navami.telsang, bhoomikak, nazim.khan, Pavitrakumar Managutte
In-Reply-To: <20260720113740.64960-1-pavitrakumarm@vayavyalabs.com>
Add Makefile and Kconfig for SPAcc driver.
Acked-by: Ross Bannerman <rbannerm@synopsys.com>
Signed-off-by: Pavitrakumar Managutte <pavitrakumarm@vayavyalabs.com>
---
drivers/crypto/Kconfig | 1 +
drivers/crypto/Makefile | 1 +
drivers/crypto/dwc-spacc/Kconfig | 83 +++++++++++++++++++++++++++++++
drivers/crypto/dwc-spacc/Makefile | 6 +++
4 files changed, 91 insertions(+)
create mode 100644 drivers/crypto/dwc-spacc/Kconfig
create mode 100644 drivers/crypto/dwc-spacc/Makefile
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 0189dfdcbbe11..e0a8de643d6fa 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -734,6 +734,7 @@ config CRYPTO_DEV_BCM_SPU
ahash, and aead algorithms with the kernel cryptographic API.
source "drivers/crypto/stm32/Kconfig"
+source "drivers/crypto/dwc-spacc/Kconfig"
config CRYPTO_DEV_SAFEXCEL
tristate "Inside Secure's SafeXcel cryptographic engine driver"
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 2c33b83f3cfa6..b80f211598bbc 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_CRYPTO_DEV_BCM_SPU) += bcm/
obj-y += inside-secure/
obj-$(CONFIG_CRYPTO_DEV_ARTPEC6) += axis/
obj-y += xilinx/
+obj-y += dwc-spacc/
obj-y += hisilicon/
obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/
obj-y += intel/
diff --git a/drivers/crypto/dwc-spacc/Kconfig b/drivers/crypto/dwc-spacc/Kconfig
new file mode 100644
index 0000000000000..edc550562235e
--- /dev/null
+++ b/drivers/crypto/dwc-spacc/Kconfig
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config CRYPTO_DEV_SPACC
+ tristate "Support for dwc_spacc Security Protocol Accelerator"
+ depends on HAS_DMA
+ select CRYPTO_ENGINE
+ default n
+
+ help
+ This enables support for SPAcc Hardware Accelerator.
+
+if CRYPTO_DEV_SPACC
+
+config CRYPTO_DEV_SPACC_HASH
+ tristate "Enable HASH functionality"
+ default CRYPTO_DEV_SPACC
+ select CRYPTO_HASH
+ select CRYPTO_SHA1
+ select CRYPTO_MD5
+ select CRYPTO_SHA256
+ select CRYPTO_SHA512
+ select CRYPTO_HMAC
+ select CRYPTO_CMAC
+ select CRYPTO_XCBC
+ select CRYPTO_AES
+ select CRYPTO_SM4_GENERIC
+
+ help
+ Say y to enable Hash functionality of SPAcc.
+
+config CRYPTO_DEV_SPACC_AUTODETECT
+ bool "Enable Autodetect functionality"
+ default n
+ help
+ Say y to enable Autodetect functionality of SPAcc.
+
+config CRYPTO_DEV_SPACC_DEBUG_TRACE_IO
+ bool "Enable Trace MMIO reads/writes stats"
+ default n
+ help
+ Say y to enable Trace MMIO reads/writes stats.
+ To Debug and trace IO register read/write operations.
+
+config CRYPTO_DEV_SPACC_DEBUG_TRACE_DDT
+ bool "Enable Trace DDT entries stats"
+ default n
+ help
+ Say y to enable Enable DDT entry stats.
+ To Debug and trace DDT operation
+
+config CRYPTO_DEV_SPACC_SECURE_MODE
+ bool "Enable Spacc secure mode stats"
+ default n
+ help
+ Say y to enable SPAcc secure modes stats.
+
+config CRYPTO_DEV_SPACC_PRIORITY
+ int "VSPACC priority value"
+ range 0 15
+ default 1
+ help
+ Default arbitration priority weight for this Virtual SPAcc instance.
+ Hardware resets this to 1. Higher values means higher priority.
+
+config CRYPTO_DEV_SPACC_INTERNAL_COUNTER
+ int "SPAcc internal counter value"
+ range 100000 1048575
+ default 100000
+ help
+ This value configures a hardware watchdog counter in the SPAcc
+ engine.The counter starts ticking when a completed cryptographic
+ job is sitting in the STATUS FIFO. If the job remains unprocessed
+ for the configured duration, an interrupt is triggered to ensure
+ it is serviced.
+
+config CRYPTO_DEV_SPACC_CONFIG_DEBUG
+ bool "Enable SPAcc debug logs"
+ default n
+ help
+ Say y to enable additional debug prints and diagnostics in the
+ SPAcc driver. Disable this for production builds.
+
+endif # CRYPTO_DEV_SPACC
diff --git a/drivers/crypto/dwc-spacc/Makefile b/drivers/crypto/dwc-spacc/Makefile
new file mode 100644
index 0000000000000..d7010644c3dbc
--- /dev/null
+++ b/drivers/crypto/dwc-spacc/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_CRYPTO_DEV_SPACC) += snps-spacc.o
+snps-spacc-objs = spacc_hal.o spacc_core.o \
+spacc_manager.o spacc_interrupt.o spacc_device.o
+
+snps-spacc-$(CONFIG_CRYPTO_DEV_SPACC_HASH) += spacc_ahash.o
--
2.25.1
^ permalink raw reply related
* [PATCH v17 3/4] crypto: spacc - Add SPAcc AUTODETECT Support
From: Pavitrakumar Managutte @ 2026-07-20 11:37 UTC (permalink / raw)
To: linux-crypto, linux-kernel, devicetree, herbert, robh
Cc: krzk, conor+dt, ruud.derwig, rbannerm, manjunath.hadli, adityak,
navami.telsang, bhoomikak, nazim.khan, Pavitrakumar Managutte
In-Reply-To: <20260720113740.64960-1-pavitrakumarm@vayavyalabs.com>
SPAcc is configurable and it supports the below modes:
1. AUTODETECT configuration - Autodetects the supported algos.
2. Static configuration - The algo support is defined statically.
Co-developed-by: Aditya Kulkarni <adityak@vayavyalabs.com>
Signed-off-by: Aditya Kulkarni <adityak@vayavyalabs.com>
Acked-by: Ross Bannerman <rbannerm@synopsys.com>
Signed-off-by: Pavitrakumar Managutte <pavitrakumarm@vayavyalabs.com>
---
drivers/crypto/dwc-spacc/spacc_core.c | 1177 +++++++++++++++++++++++++
1 file changed, 1177 insertions(+)
diff --git a/drivers/crypto/dwc-spacc/spacc_core.c b/drivers/crypto/dwc-spacc/spacc_core.c
index e1de5f2df4f51..0aafac3ad1f99 100644
--- a/drivers/crypto/dwc-spacc/spacc_core.c
+++ b/drivers/crypto/dwc-spacc/spacc_core.c
@@ -201,6 +201,909 @@ static const unsigned char template[] = {
[CRYPTO_MODE_MAC_SM4_CMAC] = 130,
};
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_AUTODETECT)
+static const struct {
+ unsigned int min_version;
+ struct {
+ int outlen;
+ unsigned char data[64];
+ } test[7];
+} testdata[CRYPTO_MODE_LAST] = {
+
+ [CRYPTO_MODE_NULL] = {
+ .min_version = 0x65,
+ .test[0].outlen = 0
+ },
+
+ [CRYPTO_MODE_AES_ECB] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0xc6, 0xa1, 0x3b, 0x37,
+ 0x87, 0x8f, 0x5b, 0x82, 0x6f, 0x4f, 0x81, 0x62, 0xa1,
+ 0xc8, 0xd8, 0x79, },
+ .test[3].outlen = 16, .test[3].data = { 0x91, 0x62, 0x51, 0x82,
+ 0x1c, 0x73, 0xa5, 0x22, 0xc3, 0x96, 0xd6, 0x27, 0x38,
+ 0x01, 0x96, 0x07, },
+ .test[4].outlen = 16, .test[4].data = { 0xf2, 0x90, 0x00, 0xb6,
+ 0x2a, 0x49, 0x9f, 0xd0, 0xa9, 0xf3, 0x9a, 0x6a, 0xdd,
+ 0x2e, 0x77, 0x80, },
+ },
+
+ [CRYPTO_MODE_AES_CBC] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0x0a, 0x94, 0x0b, 0xb5,
+ 0x41, 0x6e, 0xf0, 0x45, 0xf1, 0xc3, 0x94, 0x58, 0xc6,
+ 0x53, 0xea, 0x5a, },
+ .test[3].outlen = 16, .test[3].data = { 0x00, 0x60, 0xbf, 0xfe,
+ 0x46, 0x83, 0x4b, 0xb8, 0xda, 0x5c, 0xf9, 0xa6, 0x1f,
+ 0xf2, 0x20, 0xae, },
+ .test[4].outlen = 16, .test[4].data = { 0x5a, 0x6e, 0x04, 0x57,
+ 0x08, 0xfb, 0x71, 0x96, 0xf0, 0x2e, 0x55, 0x3d, 0x02,
+ 0xc3, 0xa6, 0x92, },
+ },
+
+ [CRYPTO_MODE_AES_CTR] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0x0a, 0x94, 0x0b, 0xb5,
+ 0x41, 0x6e, 0xf0, 0x45, 0xf1, 0xc3, 0x94, 0x58, 0xc6,
+ 0x53, 0xea, 0x5a, },
+ .test[3].outlen = 16, .test[3].data = { 0x00, 0x60, 0xbf, 0xfe,
+ 0x46, 0x83, 0x4b, 0xb8, 0xda, 0x5c, 0xf9, 0xa6, 0x1f,
+ 0xf2, 0x20, 0xae, },
+ .test[4].outlen = 16, .test[4].data = { 0x5a, 0x6e, 0x04, 0x57,
+ 0x08, 0xfb, 0x71, 0x96, 0xf0, 0x2e, 0x55, 0x3d, 0x02,
+ 0xc3, 0xa6, 0x92, },
+ },
+
+ [CRYPTO_MODE_AES_CCM] = {
+ .min_version = 0x65,
+ .test[2].outlen = 32, .test[2].data = { 0x02, 0x63, 0xec, 0x94,
+ 0x66, 0x18, 0x72, 0x96, 0x9a, 0xda, 0xfd, 0x0f, 0x4b,
+ 0xa4, 0x0f, 0xdc, 0xa5, 0x09, 0x92, 0x93, 0xb6, 0xb4,
+ 0x38, 0x34, 0x63, 0x72, 0x50, 0x4c, 0xfc, 0x8a, 0x63,
+ 0x02, },
+ .test[3].outlen = 32, .test[3].data = { 0x29, 0xf7, 0x63, 0xe8,
+ 0xa1, 0x75, 0xc6, 0xbf, 0xa5, 0x54, 0x94, 0x89, 0x12,
+ 0x84, 0x45, 0xf5, 0x9b, 0x27, 0xeb, 0xb1, 0xa4, 0x65,
+ 0x93, 0x6e, 0x5a, 0xc0, 0xa2, 0xa3, 0xe2, 0x6c, 0x46,
+ 0x29, },
+ .test[4].outlen = 32, .test[4].data = { 0x60, 0xf3, 0x10, 0xd5,
+ 0xc3, 0x85, 0x58, 0x5d, 0x55, 0x16, 0xfb, 0x51, 0x72,
+ 0xe5, 0x20, 0xcf, 0x8e, 0x87, 0x6d, 0x72, 0xc8, 0x44,
+ 0xbe, 0x6d, 0xa2, 0xd6, 0xf4, 0xba, 0xec, 0xb4, 0xec,
+ 0x39, },
+ },
+
+ [CRYPTO_MODE_AES_GCM] = {
+ .min_version = 0x65,
+ .test[2].outlen = 32, .test[2].data = { 0x93, 0x6c, 0xa7, 0xce,
+ 0x66, 0x1b, 0xf7, 0x54, 0x4b, 0xd2, 0x61, 0x8a, 0x36,
+ 0xa3, 0x70, 0x08, 0xc0, 0xd7, 0xd0, 0x77, 0xc5, 0x64,
+ 0x76, 0xdb, 0x48, 0x4a, 0x53, 0xe3, 0x6c, 0x93, 0x34,
+ 0x0f, },
+ .test[3].outlen = 32, .test[3].data = { 0xe6, 0xf9, 0x22, 0x9b,
+ 0x99, 0xb9, 0xc9, 0x0e, 0xd0, 0x33, 0xdc, 0x82, 0xff,
+ 0xa9, 0xdc, 0x70, 0x4c, 0xcd, 0xc4, 0x1b, 0xa3, 0x5a,
+ 0x87, 0x5d, 0xd8, 0xef, 0xb6, 0x48, 0xbb, 0x0c, 0x92,
+ 0x60, },
+ .test[4].outlen = 32, .test[4].data = { 0x47, 0x02, 0xd6, 0x1b,
+ 0xc5, 0xe5, 0xc2, 0x1b, 0x8d, 0x41, 0x97, 0x8b, 0xb1,
+ 0xe9, 0x78, 0x6d, 0x48, 0x6f, 0x78, 0x81, 0xc7, 0x98,
+ 0xcc, 0xf5, 0x28, 0xf1, 0x01, 0x7c, 0xe8, 0xf6, 0x09,
+ 0x78, },
+ },
+
+ [CRYPTO_MODE_AES_F8] = {
+ .min_version = 0x65,
+ .test[0].outlen = 0
+ },
+
+ [CRYPTO_MODE_AES_XTS] = {
+ .min_version = 0x65,
+ .test[2].outlen = 32, .test[2].data = { 0xa0, 0x1a, 0x6f, 0x09,
+ 0xfa, 0xef, 0xd2, 0x72, 0xc3, 0x9b, 0xad, 0x35, 0x52,
+ 0xfc, 0xa1, 0xcb, 0x33, 0x69, 0x51, 0xc5, 0x23, 0xbe,
+ 0xac, 0xa5, 0x4a, 0xf2, 0xfc, 0x77, 0x71, 0x6f, 0x9a,
+ 0x86, },
+ .test[4].outlen = 32, .test[4].data = { 0x05, 0x45, 0x91, 0x86,
+ 0xf2, 0x2d, 0x97, 0x93, 0xf3, 0xa0, 0xbb, 0x29, 0xc7,
+ 0x9c, 0xc1, 0x4c, 0x3b, 0x8f, 0xdd, 0x9d, 0xda, 0xc7,
+ 0xb5, 0xaa, 0xc2, 0x7c, 0x2e, 0x71, 0xce, 0x7f, 0xce,
+ 0x0e, },
+ },
+
+ [CRYPTO_MODE_AES_CFB] = {
+ .min_version = 0x65,
+ .test[0].outlen = 0
+ },
+
+ [CRYPTO_MODE_AES_OFB] = {
+ .min_version = 0x65,
+ .test[0].outlen = 0
+ },
+
+ [CRYPTO_MODE_AES_CS1] = {
+ .min_version = 0x65,
+ .test[2].outlen = 31, .test[2].data = { 0x0a, 0x94, 0x0b, 0xb5,
+ 0x41, 0x6e, 0xf0, 0x45, 0xf1, 0xc3, 0x94, 0x58, 0xc6,
+ 0x53, 0xea, 0xae, 0xe7, 0x1e, 0xa5, 0x41, 0xd7, 0xae,
+ 0x4b, 0xeb, 0x60, 0xbe, 0xcc, 0x59, 0x3f, 0xb6, 0x63,
+ },
+ .test[3].outlen = 31, .test[3].data = { 0x00, 0x60, 0xbf, 0xfe,
+ 0x46, 0x83, 0x4b, 0xb8, 0xda, 0x5c, 0xf9, 0xa6, 0x1f,
+ 0xf2, 0x20, 0x2e, 0x84, 0xcb, 0x12, 0xa3, 0x59, 0x17,
+ 0xb0, 0x9e, 0x25, 0xa2, 0xa2, 0x3d, 0xf1, 0x9f, 0xdc,
+ },
+ .test[4].outlen = 31, .test[4].data = { 0x5a, 0x6e, 0x04, 0x57,
+ 0x08, 0xfb, 0x71, 0x96, 0xf0, 0x2e, 0x55, 0x3d, 0x02,
+ 0xc3, 0xa6, 0xcd, 0xfc, 0x25, 0x35, 0x31, 0x0b, 0xf5,
+ 0x6b, 0x2e, 0xb7, 0x8a, 0xa2, 0x5a, 0xdd, 0x77, 0x51,
+ },
+ },
+
+ [CRYPTO_MODE_AES_CS2] = {
+ .min_version = 0x65,
+ .test[2].outlen = 31, .test[2].data = { 0xae, 0xe7, 0x1e, 0xa5,
+ 0x41, 0xd7, 0xae, 0x4b, 0xeb, 0x60, 0xbe, 0xcc, 0x59,
+ 0x3f, 0xb6, 0x63, 0x0a, 0x94, 0x0b, 0xb5, 0x41, 0x6e,
+ 0xf0, 0x45, 0xf1, 0xc3, 0x94, 0x58, 0xc6, 0x53, 0xea,
+ },
+ .test[3].outlen = 31, .test[3].data = { 0x2e, 0x84, 0xcb, 0x12,
+ 0xa3, 0x59, 0x17, 0xb0, 0x9e, 0x25, 0xa2, 0xa2, 0x3d,
+ 0xf1, 0x9f, 0xdc, 0x00, 0x60, 0xbf, 0xfe, 0x46, 0x83,
+ 0x4b, 0xb8, 0xda, 0x5c, 0xf9, 0xa6, 0x1f, 0xf2, 0x20,
+ },
+ .test[4].outlen = 31, .test[4].data = { 0xcd, 0xfc, 0x25, 0x35,
+ 0x31, 0x0b, 0xf5, 0x6b, 0x2e, 0xb7, 0x8a, 0xa2, 0x5a,
+ 0xdd, 0x77, 0x51, 0x5a, 0x6e, 0x04, 0x57, 0x08, 0xfb,
+ 0x71, 0x96, 0xf0, 0x2e, 0x55, 0x3d, 0x02, 0xc3, 0xa6,
+ },
+ },
+
+ [CRYPTO_MODE_AES_CS3] = {
+ .min_version = 0x65,
+ .test[2].outlen = 31, .test[2].data = { 0xae, 0xe7, 0x1e, 0xa5,
+ 0x41, 0xd7, 0xae, 0x4b, 0xeb, 0x60, 0xbe, 0xcc, 0x59,
+ 0x3f, 0xb6, 0x63, 0x0a, 0x94, 0x0b, 0xb5, 0x41, 0x6e,
+ 0xf0, 0x45, 0xf1, 0xc3, 0x94, 0x58, 0xc6, 0x53, 0xea,
+ },
+ .test[3].outlen = 31, .test[3].data = { 0x2e, 0x84, 0xcb, 0x12,
+ 0xa3, 0x59, 0x17, 0xb0, 0x9e, 0x25, 0xa2, 0xa2, 0x3d,
+ 0xf1, 0x9f, 0xdc, 0x00, 0x60, 0xbf, 0xfe, 0x46, 0x83,
+ 0x4b, 0xb8, 0xda, 0x5c, 0xf9, 0xa6, 0x1f, 0xf2, 0x20,
+ },
+ .test[4].outlen = 31, .test[4].data = { 0xcd, 0xfc, 0x25, 0x35,
+ 0x31, 0x0b, 0xf5, 0x6b, 0x2e, 0xb7, 0x8a, 0xa2, 0x5a,
+ 0xdd, 0x77, 0x51, 0x5a, 0x6e, 0x04, 0x57, 0x08, 0xfb,
+ 0x71, 0x96, 0xf0, 0x2e, 0x55, 0x3d, 0x02, 0xc3, 0xa6,
+ },
+ },
+
+ [CRYPTO_MODE_MULTI2_ECB] = {
+ .min_version = 0x65,
+ .test[0].outlen = 0
+ },
+
+ [CRYPTO_MODE_MULTI2_CBC] = {
+ .min_version = 0x65,
+ .test[0].outlen = 0
+ },
+
+ [CRYPTO_MODE_MULTI2_OFB] = {
+ .min_version = 0x65,
+ .test[0].outlen = 0
+ },
+
+ [CRYPTO_MODE_MULTI2_CFB] = {
+ .min_version = 0x65,
+ .test[0].outlen = 0
+ },
+
+ [CRYPTO_MODE_3DES_CBC] = {
+ .min_version = 0x65,
+ .test[3].outlen = 16, .test[3].data = { 0x58, 0xed, 0x24, 0x8f,
+ 0x77, 0xf6, 0xb1, 0x9e, 0x47, 0xd9, 0xb7, 0x4a, 0x4f,
+ 0x5a, 0xe6, 0x6d, }
+ },
+
+ [CRYPTO_MODE_3DES_ECB] = {
+ .min_version = 0x65,
+ .test[3].outlen = 16, .test[3].data = { 0x89, 0x4b, 0xc3, 0x08,
+ 0x54, 0x26, 0xa4, 0x41, 0x89, 0x4b, 0xc3, 0x08, 0x54,
+ 0x26, 0xa4, 0x41, }
+ },
+
+ [CRYPTO_MODE_DES_CBC] = {
+ .min_version = 0x65,
+ .test[1].outlen = 16, .test[1].data = { 0xe1, 0xb2, 0x46, 0xe5,
+ 0xa7, 0xc7, 0x4c, 0xbc, 0xd5, 0xf0, 0x8e, 0x25, 0x3b,
+ 0xfa, 0x23, 0x80, }
+ },
+
+ [CRYPTO_MODE_DES_ECB] = {
+ .min_version = 0x65,
+ .test[1].outlen = 16, .test[1].data = { 0xa5, 0x17, 0x3a,
+ 0xd5, 0x95, 0x7b, 0x43, 0x70, 0xa5, 0x17, 0x3a, 0xd5,
+ 0x95, 0x7b, 0x43, 0x70, }
+ },
+
+ [CRYPTO_MODE_KASUMI_ECB] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0x04, 0x7d, 0x5d,
+ 0x2c, 0x8c, 0x2e, 0x91, 0xb3, 0x04, 0x7d, 0x5d, 0x2c,
+ 0x8c, 0x2e, 0x91, 0xb3, }
+ },
+
+ [CRYPTO_MODE_KASUMI_F8] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0xfc, 0xf7, 0x45,
+ 0xee, 0x1d, 0xbb, 0xa4, 0x57, 0xa7, 0x45, 0xdc, 0x6b,
+ 0x2a, 0x1b, 0x50, 0x88, }
+ },
+
+ [CRYPTO_MODE_SNOW3G_UEA2] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0x95, 0xd3, 0xc8,
+ 0x13, 0xc0, 0x20, 0x24, 0xa3, 0x76, 0x24, 0xd1, 0x98,
+ 0xb6, 0x67, 0x4d, 0x4c, }
+ },
+
+ [CRYPTO_MODE_ZUC_UEA3] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0xda, 0xdf, 0xb6,
+ 0xa2, 0xac, 0x9d, 0xba, 0xfe, 0x18, 0x9c, 0x0c, 0x75,
+ 0x79, 0xc6, 0xe0, 0x4e, }
+ },
+
+ [CRYPTO_MODE_CHACHA20_STREAM] = {
+ .min_version = 0x65,
+ .test[4].outlen = 16, .test[4].data = { 0x55, 0xdf, 0x91,
+ 0xe9, 0x27, 0x01, 0x37, 0x69, 0xdb, 0x38, 0xd4, 0x28,
+ 0x01, 0x79, 0x76, 0x64 }
+ },
+
+ [CRYPTO_MODE_CHACHA20_POLY1305] = {
+ .min_version = 0x65,
+ .test[4].outlen = 16, .test[4].data = { 0x89, 0xfb, 0x08,
+ 0x00, 0x29, 0x17, 0xa5, 0x40, 0xb7, 0x83, 0x3f, 0xf3,
+ 0x98, 0x1d, 0x0e, 0x63 }
+ },
+
+ [CRYPTO_MODE_SM4_ECB] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0x1e, 0x96, 0x34,
+ 0xb7, 0x70, 0xf9, 0xae, 0xba, 0xa9, 0x34, 0x4f, 0x5a,
+ 0xff, 0x9f, 0x82, 0xa3 }
+ },
+
+ [CRYPTO_MODE_SM4_CBC] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0x8f, 0x78, 0x76,
+ 0x3e, 0xe0, 0x60, 0x13, 0xe0, 0xb7, 0x62, 0x2c, 0x42,
+ 0x8f, 0xd0, 0x52, 0x8d }
+ },
+
+ [CRYPTO_MODE_SM4_CFB] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0x8f, 0x78, 0x76,
+ 0x3e, 0xe0, 0x60, 0x13, 0xe0, 0xb7, 0x62, 0x2c, 0x42,
+ 0x8f, 0xd0, 0x52, 0x8d }
+ },
+
+ [CRYPTO_MODE_SM4_OFB] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0x8f, 0x78, 0x76, 0x3e,
+ 0xe0, 0x60, 0x13, 0xe0, 0xb7, 0x62, 0x2c, 0x42, 0x8f,
+ 0xd0, 0x52, 0x8d }
+ },
+
+ [CRYPTO_MODE_SM4_CTR] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0x8f, 0x78, 0x76, 0x3e,
+ 0xe0, 0x60, 0x13, 0xe0, 0xb7, 0x62, 0x2c, 0x42, 0x8f,
+ 0xd0, 0x52, 0x8d }
+ },
+
+ [CRYPTO_MODE_SM4_CCM] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0x8e, 0x25, 0x5a,
+ 0x13, 0xc7, 0x43, 0x4d, 0x95, 0xef, 0x14, 0x15, 0x11,
+ 0xd0, 0xb9, 0x60, 0x5b }
+ },
+
+ [CRYPTO_MODE_SM4_GCM] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0x97, 0x46, 0xde,
+ 0xfb, 0xc9, 0x6a, 0x85, 0x00, 0xff, 0x9c, 0x74, 0x4d,
+ 0xd1, 0xbb, 0xf9, 0x66 }
+ },
+
+ [CRYPTO_MODE_SM4_F8] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0x77, 0x30, 0xff,
+ 0x70, 0x46, 0xbc, 0xf4, 0xe3, 0x11, 0xf6, 0x27, 0xe2,
+ 0xff, 0xd7, 0xc4, 0x2e }
+ },
+
+ [CRYPTO_MODE_SM4_XTS] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0x05, 0x3f, 0xb6,
+ 0xe9, 0xb1, 0xff, 0x09, 0x4f, 0x9d, 0x69, 0x4d, 0xc2,
+ 0xb6, 0xa1, 0x15, 0xde }
+ },
+
+ [CRYPTO_MODE_SM4_CS1] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0x8f, 0x78, 0x76,
+ 0x3e, 0xe0, 0x60, 0x13, 0xe0, 0xb7, 0x62, 0x2c, 0x42,
+ 0x8f, 0xd0, 0x52, 0xa0 }
+ },
+
+ [CRYPTO_MODE_SM4_CS2] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0xa0, 0x1c, 0xfe,
+ 0x91, 0xaa, 0x7e, 0xf1, 0x75, 0x6a, 0xe8, 0xbc, 0xe1,
+ 0x55, 0x08, 0xda, 0x71 }
+ },
+
+ [CRYPTO_MODE_SM4_CS3] = {
+ .min_version = 0x65,
+ .test[2].outlen = 16, .test[2].data = { 0xa0, 0x1c, 0xfe,
+ 0x91, 0xaa, 0x7e, 0xf1, 0x75, 0x6a, 0xe8, 0xbc, 0xe1,
+ 0x55, 0x08, 0xda, 0x71 }
+ },
+
+ /*
+ * Hashes ... note they use the 2nd keysize
+ * array so the indices mean different sizes!!!
+ */
+
+ [CRYPTO_MODE_HASH_MD5] = {
+ .min_version = 0x65,
+ .test[1].outlen = 16, .test[1].data = { 0x70, 0xbc, 0x8f, 0x4b,
+ 0x72, 0xa8, 0x69, 0x21, 0x46, 0x8b, 0xf8, 0xe8, 0x44,
+ 0x1d, 0xce, 0x51, }
+ },
+
+ [CRYPTO_MODE_HMAC_MD5] = {
+ .min_version = 0x65,
+ .test[1].outlen = 16, .test[1].data = { 0xb6, 0x39, 0xc8, 0x73,
+ 0x16, 0x38, 0x61, 0x8b, 0x70, 0x79, 0x72, 0xaa, 0x6e,
+ 0x96, 0xcf, 0x90, },
+ .test[4].outlen = 16, .test[4].data = { 0xb7, 0x79, 0x68, 0xea,
+ 0x17, 0x32, 0x1e, 0x32, 0x13, 0x90, 0x6c, 0x2e, 0x9f,
+ 0xd5, 0xc8, 0xb3, },
+ .test[5].outlen = 16, .test[5].data = { 0x80, 0x3e, 0x0a, 0x2f,
+ 0x8a, 0xd8, 0x31, 0x8f, 0x8e, 0x12, 0x28, 0x86, 0x22,
+ 0x59, 0x6b, 0x05, },
+ },
+
+ [CRYPTO_MODE_HASH_SHA1] = {
+ .min_version = 0x65,
+ .test[1].outlen = 20, .test[1].data = { 0xde, 0x8a, 0x84, 0x7b,
+ 0xff, 0x8c, 0x34, 0x3d, 0x69, 0xb8, 0x53, 0xa2, 0x15,
+ 0xe6, 0xee, 0x77, 0x5e, 0xf2, 0xef, 0x96, }
+ },
+
+ [CRYPTO_MODE_HMAC_SHA1] = {
+ .min_version = 0x65,
+ .test[1].outlen = 20, .test[1].data = { 0xf8, 0x54, 0x60, 0x50,
+ 0x49, 0x56, 0xd1, 0xcd, 0x55, 0x5c, 0x5d, 0xcd, 0x24,
+ 0x33, 0xbf, 0xdc, 0x5c, 0x99, 0x54, 0xc8, },
+ .test[4].outlen = 20, .test[4].data = { 0x66, 0x3f, 0x3a, 0x3c,
+ 0x08, 0xb6, 0x87, 0xb2, 0xd3, 0x0c, 0x5a, 0xa7, 0xcc,
+ 0x5c, 0xc3, 0x99, 0xb2, 0xb4, 0x58, 0x55, },
+ .test[5].outlen = 20, .test[5].data = { 0x9a, 0x28, 0x54, 0x2f,
+ 0xaf, 0xa7, 0x0b, 0x37, 0xbe, 0x2d, 0x3e, 0xd9, 0xd4,
+ 0x70, 0xbc, 0xdc, 0x0b, 0x54, 0x20, 0x06, },
+ },
+
+ [CRYPTO_MODE_HASH_SHA224] = {
+ .min_version = 0x65,
+ .test[1].outlen = 28, .test[1].data = { 0xb3, 0x38, 0xc7, 0x6b,
+ 0xcf, 0xfa, 0x1a, 0x0b, 0x3e, 0xad, 0x8d, 0xe5, 0x8d,
+ 0xfb, 0xff, 0x47, 0xb6, 0x3a, 0xb1, 0x15, 0x0e, 0x10,
+ 0xd8, 0xf1, 0x7f, 0x2b, 0xaf, 0xdf, }
+ },
+
+ [CRYPTO_MODE_HMAC_SHA224] = {
+ .min_version = 0x65,
+ .test[1].outlen = 28, .test[1].data = { 0xf3, 0xb4, 0x33, 0x78,
+ 0x53, 0x4c, 0x0c, 0x4a, 0x1e, 0x31, 0xc2, 0xce, 0xda,
+ 0xc8, 0xfe, 0x74, 0x4a, 0xd2, 0x9b, 0x7c, 0x1d, 0x2f,
+ 0x5e, 0xa1, 0xaa, 0x31, 0xb9, 0xf5, },
+ .test[4].outlen = 28, .test[4].data = { 0x4b, 0x6b, 0x3f, 0x9a,
+ 0x66, 0x47, 0x45, 0xe2, 0x60, 0xc9, 0x53, 0x86, 0x7a,
+ 0x34, 0x65, 0x7d, 0xe2, 0x24, 0x06, 0xcc, 0xf9, 0x17,
+ 0x20, 0x5d, 0xc2, 0xb6, 0x97, 0x9a, },
+ .test[5].outlen = 28, .test[5].data = { 0x90, 0xb0, 0x6e, 0xee,
+ 0x21, 0x57, 0x38, 0xc7, 0x65, 0xbb, 0x9a, 0xf5, 0xb4,
+ 0x31, 0x0a, 0x0e, 0xe5, 0x64, 0xc4, 0x49, 0x9d, 0xbd,
+ 0xe9, 0xf7, 0xac, 0x9f, 0xf8, 0x05, },
+ },
+
+ [CRYPTO_MODE_HASH_SHA256] = {
+ .min_version = 0x65,
+ .test[1].outlen = 32, .test[1].data = { 0x66, 0x68, 0x7a, 0xad,
+ 0xf8, 0x62, 0xbd, 0x77, 0x6c, 0x8f, 0xc1, 0x8b, 0x8e,
+ 0x9f, 0x8e, 0x20, 0x08, 0x97, 0x14, 0x85, 0x6e, 0xe2,
+ 0x33, 0xb3, 0x90, 0x2a, 0x59, 0x1d, 0x0d, 0x5f, 0x29,
+ 0x25, }
+ },
+
+ [CRYPTO_MODE_HMAC_SHA256] = {
+ .min_version = 0x65,
+ .test[1].outlen = 32, .test[1].data = { 0x75, 0x40, 0x84, 0x49,
+ 0x54, 0x0a, 0xf9, 0x80, 0x99, 0xeb, 0x93, 0x6b, 0xf6,
+ 0xd3, 0xff, 0x41, 0x05, 0x47, 0xcc, 0x82, 0x62, 0x76,
+ 0x32, 0xf3, 0x43, 0x74, 0x70, 0x54, 0xe2, 0x3b, 0xc0,
+ 0x90, },
+ .test[4].outlen = 32, .test[4].data = { 0x41, 0x6c, 0x53, 0x92,
+ 0xb9, 0xf3, 0x6d, 0xf1, 0x88, 0xe9, 0x0e, 0xb1, 0x4d,
+ 0x17, 0xbf, 0x0d, 0xa1, 0x90, 0xbf, 0xdb, 0x7f, 0x1f,
+ 0x49, 0x56, 0xe6, 0xe5, 0x66, 0xa5, 0x69, 0xc8, 0xb1,
+ 0x5c, },
+ .test[5].outlen = 32, .test[5].data = { 0x49, 0x1f, 0x58, 0x3b,
+ 0x05, 0xe2, 0x3a, 0x72, 0x1d, 0x11, 0x6d, 0xc1, 0x08,
+ 0xa0, 0x3f, 0x30, 0x37, 0x98, 0x36, 0x8a, 0x49, 0x4c,
+ 0x21, 0x1d, 0x56, 0xa5, 0x2a, 0xf3, 0x68, 0x28, 0xb7,
+ 0x69, },
+ },
+
+ [CRYPTO_MODE_HASH_SHA384] = {
+ .min_version = 0x65,
+ .test[1].outlen = 48, .test[1].data = { 0xa3, 0x8f, 0xff, 0x4b,
+ 0xa2, 0x6c, 0x15, 0xe4, 0xac, 0x9c, 0xde, 0x8c, 0x03,
+ 0x10, 0x3a, 0xc8, 0x90, 0x80, 0xfd, 0x47, 0x54, 0x5f,
+ 0xde, 0x94, 0x46, 0xc8, 0xf1, 0x92, 0x72, 0x9e, 0xab,
+ 0x7b, 0xd0, 0x3a, 0x4d, 0x5c, 0x31, 0x87, 0xf7, 0x5f,
+ 0xe2, 0xa7, 0x1b, 0x0e, 0xe5, 0x0a, 0x4a, 0x40, }
+ },
+
+ [CRYPTO_MODE_HMAC_SHA384] = {
+ .min_version = 0x65,
+ .test[1].outlen = 48, .test[1].data = { 0x6c, 0xd8, 0x89, 0xa0,
+ 0xca, 0x54, 0xa6, 0x1d, 0x24, 0xc4, 0x1d, 0xa1, 0x77,
+ 0x50, 0xd6, 0xf2, 0xf3, 0x43, 0x23, 0x0d, 0xb1, 0xf5,
+ 0xf7, 0xfc, 0xc0, 0x8c, 0xf6, 0xdf, 0x3c, 0x61, 0xfc,
+ 0x8a, 0xb9, 0xda, 0x12, 0x75, 0x97, 0xac, 0x51, 0x88,
+ 0x59, 0x19, 0x44, 0x13, 0xc0, 0x78, 0xa5, 0xa8, },
+ .test[4].outlen = 48, .test[4].data = { 0x0c, 0x91, 0x36, 0x46,
+ 0xd9, 0x17, 0x81, 0x46, 0x1d, 0x42, 0xb1, 0x00, 0xaa,
+ 0xfa, 0x26, 0x92, 0x9f, 0x05, 0xc0, 0x91, 0x8e, 0x20,
+ 0xd7, 0x75, 0x9d, 0xd2, 0xc8, 0x9b, 0x02, 0x18, 0x20,
+ 0x1f, 0xdd, 0xa3, 0x32, 0xe3, 0x1e, 0xa4, 0x2b, 0xc3,
+ 0xc8, 0xb9, 0xb1, 0x53, 0x4e, 0x6a, 0x49, 0xd2, },
+ .test[5].outlen = 48, .test[5].data = { 0x84, 0x78, 0xd2, 0xf1,
+ 0x44, 0x95, 0x6a, 0x22, 0x2d, 0x08, 0x19, 0xe8, 0xea,
+ 0x61, 0xb4, 0x86, 0xe8, 0xc6, 0xb0, 0x40, 0x51, 0x28,
+ 0x22, 0x54, 0x48, 0xc0, 0x70, 0x09, 0x81, 0xf9, 0xf5,
+ 0x47, 0x9e, 0xb3, 0x2c, 0x69, 0x19, 0xd5, 0x8d, 0x03,
+ 0x5d, 0x24, 0xca, 0x90, 0xa6, 0x9d, 0x80, 0x2a, },
+ .test[6].outlen = 48, .test[6].data = { 0x0e, 0x68, 0x17, 0x31,
+ 0x01, 0xa8, 0x28, 0x0a, 0x4e, 0x47, 0x22, 0xa6, 0x89,
+ 0xf0, 0xc6, 0xcd, 0x4e, 0x8c, 0x19, 0x4c, 0x44, 0x3d,
+ 0xb5, 0xa5, 0xf9, 0xfe, 0xea, 0xc7, 0x84, 0x0b, 0x57,
+ 0x0d, 0xd4, 0xe4, 0x8a, 0x3f, 0x68, 0x31, 0x20, 0xd9,
+ 0x1f, 0xc4, 0xa3, 0x76, 0xcf, 0xdd, 0x07, 0xa6, },
+ },
+
+ [CRYPTO_MODE_HASH_SHA512] = {
+ .min_version = 0x65,
+ .test[1].outlen = 64, .test[1].data = { 0x50, 0x46, 0xad, 0xc1,
+ 0xdb, 0xa8, 0x38, 0x86, 0x7b, 0x2b, 0xbb, 0xfd, 0xd0,
+ 0xc3, 0x42, 0x3e, 0x58, 0xb5, 0x79, 0x70, 0xb5, 0x26,
+ 0x7a, 0x90, 0xf5, 0x79, 0x60, 0x92, 0x4a, 0x87, 0xf1,
+ 0x96, 0x0a, 0x6a, 0x85, 0xea, 0xa6, 0x42, 0xda, 0xc8,
+ 0x35, 0x42, 0x4b, 0x5d, 0x7c, 0x8d, 0x63, 0x7c, 0x00,
+ 0x40, 0x8c, 0x7a, 0x73, 0xda, 0x67, 0x2b, 0x7f, 0x49,
+ 0x85, 0x21, 0x42, 0x0b, 0x6d, 0xd3, }
+ },
+
+ [CRYPTO_MODE_HMAC_SHA512] = {
+ .min_version = 0x65,
+ .test[1].outlen = 64, .test[1].data = { 0xec, 0xfd, 0x83, 0x74,
+ 0xc8, 0xa9, 0x2f, 0xd7, 0x71, 0x94, 0xd1, 0x1e, 0xe7,
+ 0x0f, 0x0f, 0x5e, 0x11, 0x29, 0x58, 0xb8, 0x36, 0xc6,
+ 0x39, 0xbc, 0xd6, 0x88, 0x6e, 0xdb, 0xc8, 0x06, 0x09,
+ 0x30, 0x27, 0xaa, 0x69, 0xb9, 0x2a, 0xd4, 0x67, 0x06,
+ 0x5c, 0x82, 0x8e, 0x90, 0xe9, 0x3e, 0x55, 0x88, 0x7d,
+ 0xb2, 0x2b, 0x48, 0xa2, 0x28, 0x92, 0x6c, 0x0f, 0xf1,
+ 0x57, 0xb5, 0xd0, 0x06, 0x1d, 0xf3, },
+ .test[4].outlen = 64, .test[4].data = { 0x47, 0x88, 0x91, 0xe9,
+ 0x12, 0x3e, 0xfd, 0xdc, 0x26, 0x29, 0x08, 0xd6, 0x30,
+ 0x8f, 0xcc, 0xb6, 0x93, 0x30, 0x58, 0x69, 0x4e, 0x81,
+ 0xee, 0x9d, 0xb6, 0x0f, 0xc5, 0x54, 0xe6, 0x7c, 0x84,
+ 0xc5, 0xbc, 0x89, 0x99, 0xf0, 0xf3, 0x7f, 0x6f, 0x3f,
+ 0xf5, 0x04, 0x2c, 0xdf, 0x76, 0x72, 0x6a, 0xbe, 0x28,
+ 0x3b, 0xb8, 0x05, 0xb3, 0x47, 0x45, 0xf5, 0x7f, 0xb1,
+ 0x21, 0x2d, 0xe0, 0x8d, 0x1e, 0x29, },
+ .test[5].outlen = 64, .test[5].data = { 0x7e, 0x55, 0xda, 0x88,
+ 0x28, 0xc1, 0x6e, 0x9a, 0x6a, 0x99, 0xa0, 0x37, 0x68,
+ 0xf0, 0x28, 0x5e, 0xe2, 0xbe, 0x00, 0xac, 0x76, 0x89,
+ 0x76, 0xcc, 0x5d, 0x98, 0x1b, 0x32, 0x1a, 0x14, 0xc4,
+ 0x2e, 0x9c, 0xe4, 0xf3, 0x3f, 0x5f, 0xa0, 0xae, 0x95,
+ 0x16, 0x0b, 0x14, 0xf5, 0xf5, 0x45, 0x29, 0xd8, 0xc9,
+ 0x43, 0xf2, 0xa9, 0xbc, 0xdc, 0x03, 0x81, 0x0d, 0x36,
+ 0x2f, 0xb1, 0x22, 0xe8, 0x13, 0xf8, },
+ .test[6].outlen = 64, .test[6].data = { 0x5d, 0xc4, 0x80, 0x90,
+ 0x6b, 0x00, 0x17, 0x04, 0x34, 0x63, 0x93, 0xf1, 0xad,
+ 0x9a, 0x3e, 0x13, 0x37, 0x6b, 0x86, 0xd7, 0xc4, 0x2b,
+ 0x22, 0x9c, 0x2e, 0xf2, 0x1d, 0xde, 0x35, 0x39, 0x03,
+ 0x3f, 0x2b, 0x3a, 0xc3, 0x49, 0xb3, 0x32, 0x86, 0x63,
+ 0x6b, 0x0f, 0x27, 0x95, 0x97, 0xe5, 0xe7, 0x2b, 0x9b,
+ 0x80, 0xea, 0x94, 0x4d, 0x84, 0x2e, 0x39, 0x44, 0x8f,
+ 0x56, 0xe3, 0xcd, 0xa7, 0x12, 0x3e, },
+ },
+
+ [CRYPTO_MODE_HASH_SHA512_224] = {
+ .min_version = 0x65,
+ .test[1].outlen = 28, .test[1].data = { 0x9e, 0x7d, 0x60, 0x80,
+ 0xde, 0xf4, 0xe1, 0xcc, 0xf4, 0xae, 0xaa, 0xc6, 0xf7,
+ 0xfa, 0xd0, 0x08, 0xd0, 0x60, 0xa6, 0xcf, 0x87, 0x06,
+ 0x20, 0x38, 0xd6, 0x16, 0x67, 0x74, }
+ },
+
+ [CRYPTO_MODE_HMAC_SHA512_224] = {
+ .min_version = 0x65,
+ .test[1].outlen = 28, .test[1].data = { 0xff, 0xfb, 0x43, 0x27,
+ 0xdd, 0x2e, 0x39, 0xa0, 0x18, 0xa8, 0xaf, 0xde, 0x84,
+ 0x0b, 0x5d, 0x0f, 0x3d, 0xdc, 0xc6, 0x17, 0xd1, 0xb6,
+ 0x2f, 0x8c, 0xf8, 0x7e, 0x34, 0x34, },
+ .test[4].outlen = 28, .test[4].data = { 0x00, 0x19, 0xe2, 0x2d,
+ 0x44, 0x80, 0x2d, 0xd8, 0x1c, 0x57, 0xf5, 0x57, 0x92,
+ 0x08, 0x13, 0xe7, 0x9d, 0xbb, 0x2b, 0xc2, 0x8d, 0x77,
+ 0xc1, 0xff, 0x71, 0x4c, 0xf0, 0xa9, },
+ .test[5].outlen = 28, .test[5].data = { 0x6a, 0xc4, 0xa8, 0x73,
+ 0x21, 0x54, 0xb2, 0x82, 0xee, 0x89, 0x8d, 0x45, 0xd4,
+ 0xe3, 0x76, 0x3e, 0x04, 0x03, 0xc9, 0x71, 0xee, 0x01,
+ 0x25, 0xd2, 0x7b, 0xa1, 0x20, 0xc4, },
+ .test[6].outlen = 28, .test[6].data = { 0x0f, 0x98, 0x15, 0x9b,
+ 0x11, 0xca, 0x60, 0xc7, 0x82, 0x39, 0x1a, 0x50, 0x8c,
+ 0xe4, 0x79, 0xfa, 0xa8, 0x0e, 0xc7, 0x12, 0xfd, 0x8c,
+ 0x9c, 0x99, 0x7a, 0xe8, 0x7e, 0x92, },
+ },
+
+ [CRYPTO_MODE_HASH_SHA512_256] = {
+ .min_version = 0x65,
+ .test[1].outlen = 32, .test[1].data = { 0xaf, 0x13, 0xc0, 0x48,
+ 0x99, 0x12, 0x24, 0xa5, 0xe4, 0xc6, 0x64, 0x44, 0x6b,
+ 0x68, 0x8a, 0xaf, 0x48, 0xfb, 0x54, 0x56, 0xdb, 0x36,
+ 0x29, 0x60, 0x1b, 0x00, 0xec, 0x16, 0x0c, 0x74, 0xe5,
+ 0x54, }
+ },
+
+ [CRYPTO_MODE_HMAC_SHA512_256] = {
+ .min_version = 0x65,
+ .test[1].outlen = 32, .test[1].data = { 0x3a, 0x2c, 0xd0, 0x2b,
+ 0xfa, 0xa6, 0x72, 0xe4, 0xf1, 0xab, 0x0a, 0x3e, 0x70,
+ 0xe4, 0x88, 0x1a, 0x92, 0xe1, 0x3b, 0x64, 0x5a, 0x9b,
+ 0xed, 0xb3, 0x97, 0xc0, 0x17, 0x1f, 0xd4, 0x05, 0xf1,
+ 0x72, },
+ .test[4].outlen = 32, .test[4].data = { 0x6f, 0x2d, 0xae, 0xc6,
+ 0xe4, 0xa6, 0x5b, 0x52, 0x0f, 0x26, 0x16, 0xf6, 0xa9,
+ 0xc1, 0x23, 0xc2, 0xb3, 0x67, 0xfc, 0x69, 0xac, 0x73,
+ 0x87, 0xa2, 0x5b, 0x6c, 0x44, 0xad, 0xc5, 0x26, 0x2b,
+ 0x10, },
+ .test[5].outlen = 32, .test[5].data = { 0x63, 0xe7, 0xb8, 0xd1,
+ 0x76, 0x33, 0x56, 0x29, 0xba, 0x99, 0x86, 0x42, 0x0d,
+ 0x4f, 0xf7, 0x54, 0x8c, 0xb9, 0x39, 0xf2, 0x72, 0x1d,
+ 0x0e, 0x9d, 0x80, 0x67, 0xd9, 0xab, 0x15, 0xb0, 0x68,
+ 0x18, },
+ .test[6].outlen = 32, .test[6].data = { 0x64, 0x78, 0x56, 0xd7,
+ 0xaf, 0x5b, 0x56, 0x08, 0xf1, 0x44, 0xf7, 0x4f, 0xa1,
+ 0xa1, 0x13, 0x79, 0x6c, 0xb1, 0x31, 0x11, 0xf3, 0x75,
+ 0xf4, 0x8c, 0xb4, 0x9f, 0xbf, 0xb1, 0x60, 0x38, 0x3d,
+ 0x28, },
+ },
+
+ [CRYPTO_MODE_MAC_XCBC] = {
+ .min_version = 0x65,
+ .test[1].outlen = 16, .test[1].data = { 0x35, 0xd9, 0xdc, 0xdb,
+ 0x82, 0x9f, 0xec, 0x33, 0x52, 0xe7, 0xbf, 0x10, 0xb8,
+ 0x4b, 0xe4, 0xa5, },
+ .test[3].outlen = 16, .test[3].data = { 0x39, 0x6f, 0x99, 0xb5,
+ 0x43, 0x33, 0x67, 0x4e, 0xd4, 0x45, 0x8f, 0x80, 0x77,
+ 0xe4, 0xd4, 0x14, },
+ .test[4].outlen = 16, .test[4].data = { 0x73, 0xd4, 0x7c, 0x38,
+ 0x37, 0x4f, 0x73, 0xd0, 0x78, 0xa8, 0xc6, 0xec, 0x05,
+ 0x67, 0xca, 0x5e, },
+ },
+
+ [CRYPTO_MODE_MAC_CMAC] = {
+ .min_version = 0x65,
+ .test[1].outlen = 16, .test[1].data = { 0x15, 0xbe, 0x1b, 0xfd,
+ 0x8c, 0xbb, 0xaf, 0x8b, 0x51, 0x9a, 0x64, 0x3b, 0x1b,
+ 0x46, 0xc1, 0x8f, },
+ .test[3].outlen = 16, .test[3].data = { 0x4e, 0x02, 0xd6, 0xec,
+ 0x92, 0x75, 0x88, 0xb4, 0x3e, 0x83, 0xa7, 0xac, 0x32,
+ 0xb6, 0x2b, 0xdb, },
+ .test[4].outlen = 16, .test[4].data = { 0xa7, 0x37, 0x01, 0xbe,
+ 0xe8, 0xce, 0xed, 0x44, 0x49, 0x4a, 0xbb, 0xf6, 0x9e,
+ 0xd9, 0x31, 0x3e, },
+ },
+
+ [CRYPTO_MODE_MAC_KASUMI_F9] = {
+ .min_version = 0x65,
+ .test[1].outlen = 4, .test[1].data = { 0x5b, 0x26, 0x81, 0x06 }
+ },
+
+ [CRYPTO_MODE_MAC_SNOW3G_UIA2] = {
+ .min_version = 0x65,
+ .test[1].outlen = 4, .test[1].data = { 0x08, 0xed, 0x2c, 0x76, }
+ },
+
+ [CRYPTO_MODE_MAC_ZUC_UIA3] = {
+ .min_version = 0x65,
+ .test[1].outlen = 4, .test[1].data = { 0x6a, 0x2b, 0x4c, 0x3a, }
+ },
+
+ [CRYPTO_MODE_MAC_POLY1305] = {
+ .min_version = 0x65,
+ .test[4].outlen = 16, .test[4].data = { 0xef, 0x91, 0x06, 0x4e,
+ 0xce, 0x99, 0x9c, 0x4e, 0xfd, 0x05, 0x6a, 0x8c, 0xe6,
+ 0x18, 0x23, 0xad }
+ },
+
+ [CRYPTO_MODE_SSLMAC_MD5] = {
+ .min_version = 0x65,
+ .test[1].outlen = 16, .test[1].data = { 0x0e, 0xf4, 0xca, 0x32,
+ 0x32, 0x40, 0x1d, 0x1b, 0xaa, 0xfd, 0x6d, 0xa8, 0x01,
+ 0x79, 0xed, 0xcd, },
+ },
+
+ [CRYPTO_MODE_SSLMAC_SHA1] = {
+ .min_version = 0x65,
+ .test[2].outlen = 20, .test[2].data = { 0x05, 0x9d, 0x99, 0xb4,
+ 0xf3, 0x03, 0x1e, 0xc5, 0x24, 0xbf, 0xec, 0xdf, 0x64,
+ 0x8e, 0x37, 0x2e, 0xf0, 0xef, 0x93, 0xa0, },
+ },
+
+ [CRYPTO_MODE_HASH_CRC32] = {
+ .min_version = 0x65,
+ .test[0].outlen = 0
+ },
+
+ [CRYPTO_MODE_MAC_MICHAEL] = {
+ .min_version = 0x65,
+ .test[0].outlen = 8, .test[0].data = { 0x16, 0xfb, 0xa0,
+ 0x0e, 0xe2, 0xab, 0x6c, 0x97, }
+ },
+
+ [CRYPTO_MODE_HASH_SHA3_224] = {
+ .min_version = 0x65,
+ .test[1].outlen = 28, .test[1].data = { 0x73, 0xe0, 0x87,
+ 0xae, 0x12, 0x71, 0xb2, 0xc5, 0xf6, 0x85, 0x46, 0xc9,
+ 0x3a, 0xb4, 0x25, 0x14, 0xa6, 0x9e, 0xef, 0x25, 0x2b,
+ 0xfd, 0xd1, 0x37, 0x55, 0x74, 0x8a, 0x00, }
+ },
+
+ [CRYPTO_MODE_HASH_SHA3_256] = {
+ .min_version = 0x65,
+ .test[1].outlen = 32, .test[1].data = { 0x9e, 0x62, 0x91, 0x97,
+ 0x0c, 0xb4, 0x4d, 0xd9, 0x40, 0x08, 0xc7, 0x9b, 0xca,
+ 0xf9, 0xd8, 0x6f, 0x18, 0xb4, 0xb4, 0x9b, 0xa5, 0xb2,
+ 0xa0, 0x47, 0x81, 0xdb, 0x71, 0x99, 0xed, 0x3b, 0x9e,
+ 0x4e, }
+ },
+
+ [CRYPTO_MODE_HASH_SHA3_384] = {
+ .min_version = 0x65,
+ .test[1].outlen = 48, .test[1].data = { 0x4b, 0xda, 0xab,
+ 0xf7, 0x88, 0xd3, 0xad, 0x1a, 0xd8, 0x3d, 0x6d, 0x93,
+ 0xc7, 0xe4, 0x49, 0x37, 0xc2, 0xe6, 0x49, 0x6a, 0xf2,
+ 0x3b, 0xe3, 0x35, 0x4d, 0x75, 0x69, 0x87, 0xf4, 0x51,
+ 0x60, 0xfc, 0x40, 0x23, 0xbd, 0xa9, 0x5e, 0xcd, 0xcb,
+ 0x3c, 0x7e, 0x31, 0xa6, 0x2f, 0x72, 0x6d, 0x70, 0x2c,
+ }
+ },
+
+ [CRYPTO_MODE_HASH_SHA3_512] = {
+ .min_version = 0x65,
+ .test[1].outlen = 64, .test[1].data = { 0xad, 0x56, 0xc3, 0x5c,
+ 0xab, 0x50, 0x63, 0xb9, 0xe7, 0xea, 0x56, 0x83, 0x14,
+ 0xec, 0x81, 0xc4, 0x0b, 0xa5, 0x77, 0xaa, 0xe6, 0x30,
+ 0xde, 0x90, 0x20, 0x04, 0x00, 0x9e, 0x88, 0xf1, 0x8d,
+ 0xa5, 0x7b, 0xbd, 0xfd, 0xaa, 0xa0, 0xfc, 0x18, 0x9c,
+ 0x66, 0xc8, 0xd8, 0x53, 0x24, 0x8b, 0x6b, 0x11, 0x88,
+ 0x44, 0xd5, 0x3f, 0x7d, 0x0b, 0xa1, 0x1d, 0xe0, 0xf3,
+ 0xbf, 0xaf, 0x4c, 0xdd, 0x9b, 0x3f, }
+ },
+
+ [CRYPTO_MODE_HASH_SHAKE128] = {
+ .min_version = 0x65,
+ .test[4].outlen = 16, .test[4].data = { 0x24, 0xa7, 0xca,
+ 0x4b, 0x75, 0xe3, 0x89, 0x8d, 0x4f, 0x12, 0xe7, 0x4d,
+ 0xea, 0x8c, 0xbb, 0x65 }
+ },
+
+ [CRYPTO_MODE_HASH_SHAKE256] = {
+ .min_version = 0x65,
+ .test[4].outlen = 32, .test[4].data = { 0xf5, 0x97, 0x7c,
+ 0x82, 0x83, 0x54, 0x6a, 0x63, 0x72, 0x3b, 0xc3, 0x1d,
+ 0x26, 0x19, 0x12, 0x4f,
+ 0x11, 0xdb, 0x46, 0x58, 0x64, 0x33, 0x36, 0x74, 0x1d,
+ 0xf8, 0x17, 0x57, 0xd5, 0xad, 0x30, 0x62 }
+ },
+
+ [CRYPTO_MODE_HASH_CSHAKE128] = {
+ .min_version = 0x65,
+ .test[1].outlen = 16, .test[1].data = { 0xe0, 0x6f, 0xd8,
+ 0x50, 0x57, 0x6f, 0xe4, 0xfa, 0x7e, 0x13, 0x42, 0xb5,
+ 0xf8, 0x13, 0xeb, 0x23 }
+ },
+
+ [CRYPTO_MODE_HASH_CSHAKE256] = {
+ .min_version = 0x65,
+ .test[1].outlen = 32, .test[1].data = { 0xf3, 0xf2, 0xb5,
+ 0x47, 0xf2, 0x16, 0xba, 0x6f, 0x49, 0x83, 0x3e, 0xad,
+ 0x1e, 0x46, 0x85, 0x54,
+ 0xd0, 0xd7, 0xf9, 0xc6, 0x7e, 0xe9, 0x27, 0xc6, 0xc3,
+ 0xc3, 0xdb, 0x91, 0xdb, 0x97, 0x04, 0x0f }
+ },
+
+ [CRYPTO_MODE_MAC_KMAC128] = {
+ .min_version = 0x65,
+ .test[1].outlen = 16, .test[1].data = { 0x6c, 0x3f, 0x29,
+ 0xfe, 0x01, 0x96, 0x59, 0x36, 0xb7, 0xae, 0xb7, 0xff,
+ 0x71, 0xe0, 0x3d, 0xff },
+ .test[4].outlen = 16, .test[4].data = { 0x58, 0xd9, 0x8d,
+ 0xe8, 0x1f, 0x64, 0xb4, 0xa3, 0x9f, 0x63, 0xaf, 0x21,
+ 0x99, 0x03, 0x97, 0x06 },
+ .test[5].outlen = 16, .test[5].data = { 0xf8, 0xf9, 0xb7,
+ 0xa4, 0x05, 0x3d, 0x90, 0x7c, 0xf2, 0xa1, 0x7c, 0x34,
+ 0x39, 0xc2, 0x87, 0x4b },
+ .test[6].outlen = 16, .test[6].data = { 0xef, 0x4a, 0xd5,
+ 0x1d, 0xd7, 0x83, 0x56, 0xd3, 0xa8, 0x3c, 0xf5, 0xf8,
+ 0xd1, 0x12, 0xf4, 0x44 }
+ },
+
+ [CRYPTO_MODE_MAC_KMAC256] = {
+ .min_version = 0x65,
+ .test[1].outlen = 32, .test[1].data = { 0x0d, 0x86, 0xfa,
+ 0x92, 0x92, 0xe4, 0x77, 0x24, 0x6a, 0xcc, 0x79, 0xa0,
+ 0x1e, 0xb4, 0xc3, 0xac,
+ 0xfc, 0x56, 0xbc, 0x63, 0xcc, 0x1b, 0x6e, 0xf6, 0xc8,
+ 0x99, 0xa5, 0x3a, 0x38, 0x14, 0xa2, 0x40 },
+ .test[4].outlen = 32, .test[4].data = { 0xad, 0x99, 0xed,
+ 0x20, 0x1f, 0xbe, 0x45, 0x07, 0x3d, 0xf4, 0xae, 0x9f,
+ 0xc2, 0xd8, 0x06, 0x18,
+ 0x31, 0x4e, 0x8c, 0xb6, 0x33, 0xe8, 0x31, 0x36, 0x00,
+ 0xdd, 0x42, 0x20, 0xda, 0x2b, 0xd5, 0x2b },
+ .test[5].outlen = 32, .test[5].data = { 0xf9, 0xc6, 0x2b,
+ 0x17, 0xa0, 0x04, 0xd9, 0xf2, 0x6c, 0xbf, 0x5d, 0xa5,
+ 0x9a, 0xd7, 0x36, 0x1d,
+ 0xad, 0x66, 0x6b, 0x3d, 0xb1, 0x52, 0xd3, 0x81, 0x39,
+ 0x20, 0xd4, 0xf0, 0x43, 0x72, 0x2c, 0xb7 },
+ .test[6].outlen = 32, .test[6].data = { 0xcc, 0x89, 0xe4,
+ 0x05, 0x58, 0x77, 0x38, 0x8b, 0x18, 0xa0, 0x7c, 0x8d,
+ 0x20, 0x99, 0xea, 0x6e,
+ 0x6b, 0xe9, 0xf7, 0x0c, 0xe1, 0xe5, 0xce, 0xbc, 0x55,
+ 0x4c, 0x80, 0xa5, 0xdc, 0xae, 0xf7, 0x94 }
+ },
+
+ [CRYPTO_MODE_MAC_KMACXOF128] = {
+ .min_version = 0x65,
+ .test[1].outlen = 16, .test[1].data = { 0x84, 0x07, 0x89,
+ 0x29, 0xa7, 0xf4, 0x98, 0x91, 0xf5, 0x64, 0x61, 0x8d,
+ 0xa5, 0x93, 0x00, 0x31 },
+ .test[4].outlen = 16, .test[4].data = { 0xf0, 0xa4, 0x1b,
+ 0x98, 0x0f, 0xb3, 0xf2, 0xbd, 0xc3, 0xfc, 0x64, 0x1f,
+ 0x73, 0x1f, 0xd4, 0x74 },
+ .test[5].outlen = 16, .test[5].data = { 0xa5, 0xc5, 0xad,
+ 0x25, 0x59, 0xf1, 0x5d, 0xea, 0x5b, 0x18, 0x0a, 0x52,
+ 0xce, 0x6c, 0xc0, 0x88 },
+ .test[6].outlen = 16, .test[6].data = { 0x1a, 0x81, 0xdd,
+ 0x81, 0x47, 0x89, 0xf4, 0x15, 0xcc, 0x18, 0x05, 0x81,
+ 0xe3, 0x95, 0x21, 0xc3 }
+ },
+
+ [CRYPTO_MODE_MAC_KMACXOF256] = {
+ .min_version = 0x65,
+ .test[1].outlen = 32, .test[1].data = { 0xff, 0x85, 0xe9,
+ 0x61, 0x67, 0x96, 0x35, 0x58, 0x33, 0x38, 0x2c, 0xe8,
+ 0x25, 0x77, 0xbe, 0x63,
+ 0xd5, 0x2c, 0xa7, 0xef, 0xce, 0x9b, 0x63, 0x71, 0xb2,
+ 0x09, 0x7c, 0xd8, 0x60, 0x4e, 0x5a, 0xfa },
+ .test[4].outlen = 32, .test[4].data = { 0x86, 0x89, 0xc2,
+ 0x4a, 0xe8, 0x18, 0x46, 0x10, 0x6b, 0xf2, 0x09, 0xd7,
+ 0x37, 0x83, 0xab, 0x77,
+ 0xb5, 0xce, 0x7c, 0x96, 0x9c, 0xfa, 0x0f, 0xa0, 0xd8,
+ 0xde, 0xb5, 0xb7, 0xc6, 0xcd, 0xa9, 0x8f },
+ .test[5].outlen = 32, .test[5].data = { 0x4d, 0x71, 0x81,
+ 0x5a, 0x5f, 0xac, 0x3b, 0x29, 0xf2, 0x5f, 0xb6, 0x56,
+ 0xf1, 0x76, 0xcf, 0xdc,
+ 0x51, 0x56, 0xd7, 0x3c, 0x47, 0xec, 0x6d, 0xea, 0xc6,
+ 0x3e, 0x54, 0xe7, 0x6f, 0xdc, 0xe8, 0x39 },
+ .test[6].outlen = 32, .test[6].data = { 0x5f, 0xc5, 0xe1,
+ 0x1e, 0xe7, 0x55, 0x0f, 0x62, 0x71, 0x29, 0xf3, 0x0a,
+ 0xb3, 0x30, 0x68, 0x06,
+ 0xea, 0xec, 0xe4, 0x37, 0x17, 0x37, 0x2d, 0x5d, 0x64,
+ 0x09, 0x70, 0x63, 0x94, 0x80, 0x9b, 0x80 }
+ },
+
+ [CRYPTO_MODE_HASH_SM3] = {
+ .min_version = 0x65,
+ .test[1].outlen = 32, .test[1].data = { 0xe0, 0xba, 0xb8,
+ 0xf4, 0xd8, 0x17, 0x2b, 0xa2, 0x45, 0x19, 0x0d, 0x13,
+ 0xc9, 0x41, 0x17, 0xe9,
+ 0x3b, 0x82, 0x16, 0x6c, 0x25, 0xb2, 0xb6, 0x98, 0x83,
+ 0x35, 0x0c, 0x19, 0x2c, 0x90, 0x51, 0x40 },
+ .test[4].outlen = 32, .test[4].data = { 0xe0, 0xba, 0xb8,
+ 0xf4, 0xd8, 0x17, 0x2b, 0xa2, 0x45, 0x19, 0x0d, 0x13,
+ 0xc9, 0x41, 0x17, 0xe9,
+ 0x3b, 0x82, 0x16, 0x6c, 0x25, 0xb2, 0xb6, 0x98, 0x83,
+ 0x35, 0x0c, 0x19, 0x2c, 0x90, 0x51, 0x40 },
+ .test[5].outlen = 32, .test[5].data = { 0xe0, 0xba, 0xb8,
+ 0xf4, 0xd8, 0x17, 0x2b, 0xa2, 0x45, 0x19, 0x0d, 0x13,
+ 0xc9, 0x41, 0x17, 0xe9,
+ 0x3b, 0x82, 0x16, 0x6c, 0x25, 0xb2, 0xb6, 0x98, 0x83,
+ 0x35, 0x0c, 0x19, 0x2c, 0x90, 0x51, 0x40 },
+ .test[6].outlen = 32, .test[6].data = { 0xe0, 0xba, 0xb8,
+ 0xf4, 0xd8, 0x17, 0x2b, 0xa2, 0x45, 0x19, 0x0d, 0x13,
+ 0xc9, 0x41, 0x17, 0xe9,
+ 0x3b, 0x82, 0x16, 0x6c, 0x25, 0xb2, 0xb6, 0x98, 0x83,
+ 0x35, 0x0c, 0x19, 0x2c, 0x90, 0x51, 0x40 }
+ },
+
+ [CRYPTO_MODE_HMAC_SM3] = {
+ .min_version = 0x65,
+ .test[1].outlen = 32, .test[1].data = { 0x68, 0xf0, 0x65,
+ 0xd8, 0xd8, 0xc9, 0xc2, 0x0e, 0x10, 0xfd, 0x52, 0x7c,
+ 0xf2, 0xd7, 0x42, 0xd3,
+ 0x08, 0x44, 0x22, 0xbc, 0xf0, 0x9d, 0xcc, 0x34, 0x7b,
+ 0x76, 0x13, 0x91, 0xba, 0xce, 0x4d, 0x17 },
+ .test[4].outlen = 32, .test[4].data = { 0xd8, 0xab, 0x2a,
+ 0x7b, 0x56, 0x21, 0xb1, 0x59, 0x64, 0xb2, 0xa3, 0xd6,
+ 0x72, 0xb3, 0x95, 0x81,
+ 0xa0, 0xcd, 0x96, 0x47, 0xf0, 0xbc, 0x8c, 0x16, 0x5b,
+ 0x9b, 0x7d, 0x2f, 0x71, 0x3f, 0x23, 0x19 },
+ .test[5].outlen = 32, .test[5].data = { 0xa0, 0xd1, 0xd5,
+ 0xa0, 0x9e, 0x4c, 0xca, 0x8c, 0x7b, 0xe0, 0x8f, 0x70,
+ 0x92, 0x2e, 0x3f, 0x4c,
+ 0xa0, 0xca, 0xef, 0xa1, 0x86, 0x9d, 0xb2, 0xe1, 0xc5,
+ 0xfa, 0x9d, 0xfa, 0xbc, 0x11, 0xcb, 0x1f },
+ .test[6].outlen = 32, .test[6].data = { 0xa0, 0xd1, 0xd5,
+ 0xa0, 0x9e, 0x4c, 0xca, 0x8c, 0x7b, 0xe0, 0x8f, 0x70,
+ 0x92, 0x2e, 0x3f, 0x4c,
+ 0xa0, 0xca, 0xef, 0xa1, 0x86, 0x9d, 0xb2, 0xe1, 0xc5,
+ 0xfa, 0x9d, 0xfa, 0xbc, 0x11, 0xcb, 0x1f }
+ },
+
+ [CRYPTO_MODE_MAC_SM4_XCBC] = {
+ .min_version = 0x65,
+ .test[1].outlen = 16, .test[1].data = {0xb5, 0x42, 0xd0, 0xbf,
+ 0x93, 0x57, 0x65, 0x69, 0x32, 0xb1, 0x4e, 0x4d, 0x8e,
+ 0xe4, 0xae, 0x51, },
+ .test[4].outlen = 16, .test[4].data = { 0x69, 0xaf, 0x45,
+ 0xe6, 0x0c, 0x78, 0x71, 0x7e, 0x44, 0x6c, 0xfe, 0x68,
+ 0xd4, 0xfe, 0x20, 0x8b },
+ .test[5].outlen = 16, .test[5].data = { 0x69, 0xaf, 0x45,
+ 0xe6, 0x0c, 0x78, 0x71, 0x7e, 0x44, 0x6c, 0xfe, 0x68,
+ 0xd4, 0xfe, 0x20, 0x8b },
+ .test[6].outlen = 16, .test[6].data = { 0x69, 0xaf, 0x45,
+ 0xe6, 0x0c, 0x78, 0x71, 0x7e, 0x44, 0x6c, 0xfe, 0x68,
+ 0xd4, 0xfe, 0x20, 0x8b }
+ },
+
+ [CRYPTO_MODE_MAC_SM4_CMAC] = {
+ .min_version = 0x65,
+ .test[1].outlen = 16, .test[1].data = {0x3d, 0x19, 0x10, 0x8e,
+ 0x5d, 0xd2, 0x2e, 0x96, 0x92, 0x1c, 0xeb, 0xea, 0x1d,
+ 0xb5, 0x1a, 0x4b, },
+ .test[4].outlen = 16, .test[4].data = { 0x36, 0xbe, 0xec,
+ 0x03, 0x9c, 0xc7, 0x0c, 0x28, 0x23, 0xdd, 0x71, 0x8b,
+ 0x3c, 0xbd, 0x7f, 0x37 },
+ .test[5].outlen = 16, .test[5].data = { 0x36, 0xbe, 0xec,
+ 0x03, 0x9c, 0xc7, 0x0c, 0x28, 0x23, 0xdd, 0x71, 0x8b,
+ 0x3c, 0xbd, 0x7f, 0x37 },
+ .test[6].outlen = 16, .test[6].data = { 0x36, 0xbe, 0xec,
+ 0x03, 0x9c, 0xc7, 0x0c, 0x28, 0x23, 0xdd, 0x71, 0x8b,
+ 0x3c, 0xbd, 0x7f, 0x37 }
+ },
+
+};
+#endif
+
int spacc_sg_to_ddt(struct device *dev, struct scatterlist *sg,
int nbytes, struct pdu_ddt *ddt, int dma_direction)
{
@@ -585,6 +1488,279 @@ int spacc_close(struct spacc_device *dev, int handle)
return spacc_job_release(dev, handle);
}
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_AUTODETECT)
+static int spacc_set_auxinfo(struct spacc_device *spacc, int jobid,
+ u32 direction, u32 bitsize)
+{
+ int ret = 0;
+ struct spacc_job *job;
+
+ if (jobid < 0 || jobid >= SPACC_MAX_JOBS)
+ return -EINVAL;
+
+ job = &spacc->job[jobid];
+ if (!job)
+ ret = -EINVAL;
+ else {
+ job->auxinfo_dir = direction;
+ job->auxinfo_bit_align = bitsize;
+ }
+
+ return ret;
+}
+
+static int spacc_check_modes(struct spacc_device *spacc, int algo_mode,
+ int keysz_idx, void *virt, char *key,
+ struct pdu_ddt *ddt)
+{
+ int enc;
+ int hash;
+ int aadlen;
+ int ivsize;
+ int proclen;
+ int rc = 0;
+ int err = 0;
+ bool output_zero_len;
+ bool output_mismatch;
+ struct spacc_job *job;
+
+ if ((template[algo_mode] & (1 << keysz_idx)) == 0)
+ return 0;
+
+ if (!testdata[algo_mode].test[keysz_idx].outlen) {
+ spacc->config.modes[algo_mode] &= ~(1 << keysz_idx);
+ return 0;
+ }
+
+ /*
+ * Testing keysizes[keysz_idx] with algo 'algo_mode' which
+ * should match the ENUMs above
+ */
+ if (template[algo_mode] & 128) {
+ enc = 0;
+ hash = algo_mode;
+ } else {
+ enc = algo_mode;
+ hash = 0;
+ }
+
+ rc = spacc_open(spacc, enc, hash, -1, 0, NULL, NULL);
+ if (rc < 0) {
+ spacc->config.modes[algo_mode] &= ~(1 << keysz_idx);
+ return 0;
+ }
+
+ if (template[algo_mode] & 128) {
+ /* hash-only: digest written at offset 0 in dst, proclen=0 */
+ spacc_set_operation(spacc, rc, OP_ENCRYPT, ICV_HASH,
+ IP_ICV_OFFSET, 0,
+ testdata[algo_mode].test[keysz_idx].outlen, 0);
+ } else {
+ spacc_set_operation(spacc, rc, OP_ENCRYPT, 0, IP_ICV_APPEND, 0,
+ 0, 0);
+ }
+
+ /* if this is a hash or mac */
+ if (template[algo_mode] & 128) {
+ const unsigned char *hash_key = key;
+ unsigned char local_key[128];
+ int klen;
+
+ switch (algo_mode) {
+ case CRYPTO_MODE_HASH_CSHAKE128:
+ case CRYPTO_MODE_HASH_CSHAKE256:
+ case CRYPTO_MODE_MAC_KMAC128:
+ case CRYPTO_MODE_MAC_KMAC256:
+ case CRYPTO_MODE_MAC_KMACXOF128:
+ case CRYPTO_MODE_MAC_KMACXOF256:
+ /*
+ * Special initial bytes to encode
+ * length for cust strings
+ */
+ memcpy(local_key, key, sizeof(local_key));
+ local_key[0] = 0x01;
+ local_key[1] = 0x70;
+ hash_key = local_key;
+ break;
+ }
+
+ klen = keysizes[1][keysz_idx] +
+ ((algo_mode == CRYPTO_MODE_MAC_XCBC ||
+ algo_mode == CRYPTO_MODE_MAC_SM4_XCBC) ? 32 : 0);
+ spacc_write_context(spacc, rc, SPACC_HASH_OPERATION,
+ hash_key, klen, hash_key, 16);
+ } else {
+ u32 keysize;
+
+ ivsize = 16;
+ keysize = keysizes[0][keysz_idx];
+
+ switch (algo_mode) {
+ case CRYPTO_MODE_CHACHA20_STREAM:
+ case CRYPTO_MODE_AES_CCM:
+ case CRYPTO_MODE_SM4_CCM:
+ ivsize = 16;
+ break;
+ case CRYPTO_MODE_SM4_GCM:
+ case CRYPTO_MODE_CHACHA20_POLY1305:
+ case CRYPTO_MODE_AES_GCM:
+ ivsize = 12;
+ break;
+ case CRYPTO_MODE_KASUMI_ECB:
+ case CRYPTO_MODE_KASUMI_F8:
+ case CRYPTO_MODE_3DES_CBC:
+ case CRYPTO_MODE_3DES_ECB:
+ case CRYPTO_MODE_DES_CBC:
+ case CRYPTO_MODE_DES_ECB:
+ ivsize = 8;
+ break;
+ case CRYPTO_MODE_SM4_XTS:
+ case CRYPTO_MODE_AES_XTS:
+ keysize <<= 1;
+ break;
+ }
+
+ spacc_write_context(spacc, rc, SPACC_CRYPTO_OPERATION,
+ key, keysize, key, ivsize);
+ }
+
+ spacc_set_key_exp(spacc, rc);
+
+ switch (algo_mode) {
+ case CRYPTO_MODE_ZUC_UEA3:
+ case CRYPTO_MODE_SNOW3G_UEA2:
+ case CRYPTO_MODE_MAC_SNOW3G_UIA2:
+ case CRYPTO_MODE_MAC_ZUC_UIA3:
+ case CRYPTO_MODE_KASUMI_F8:
+ spacc_set_auxinfo(spacc, rc, 0, 0);
+ break;
+ case CRYPTO_MODE_MAC_KASUMI_F9:
+ spacc_set_auxinfo(spacc, rc, 0, 8);
+ break;
+ }
+
+ memset(virt, 0, 256);
+
+ aadlen = 16;
+ proclen = 32;
+
+ if (!enc) {
+ aadlen = 0;
+ proclen = 32;
+ }
+
+ switch (algo_mode) {
+ case CRYPTO_MODE_SM4_CS1:
+ case CRYPTO_MODE_SM4_CS2:
+ case CRYPTO_MODE_SM4_CS3:
+ case CRYPTO_MODE_AES_CS1:
+ case CRYPTO_MODE_AES_CS2:
+ case CRYPTO_MODE_AES_CS3:
+ proclen = 31;
+ fallthrough;
+ case CRYPTO_MODE_SM4_XTS:
+ case CRYPTO_MODE_AES_XTS:
+ aadlen = 0;
+ }
+
+ err = spacc_packet_enqueue_ddt(spacc, rc, ddt, ddt, proclen, 0,
+ aadlen, 0, 0, 0);
+ job = &spacc->job[rc];
+
+ if (err == 0) {
+ /*
+ * No timeout, not interruptible: this only returns once
+ * job_done is actually true, i.e. the hardware has
+ * genuinely relinquished the job. That guarantees it is
+ * always safe to close the job/context and (via the
+ * caller) free the DMA buffer immediately below --
+ * there is no "unconfirmed" case left to handle.
+ *
+ * Tradeoff: if the hardware ever genuinely fails to
+ * complete a submitted job, this hangs here
+ * unkillably (TASK_UNINTERRUPTIBLE, no timeout) for the
+ * rest of probe. Accepted deliberately in place of the
+ * abandoned-job/UAF risk of giving up early with no
+ * hardware cancel available.
+ */
+ wait_event(job->waitq, job->job_done);
+
+ job->job_done = 0;
+ err = job->job_err;
+ }
+
+ output_zero_len = !testdata[algo_mode].test[keysz_idx].outlen;
+ output_mismatch = memcmp(testdata[algo_mode].test[keysz_idx].data, virt,
+ testdata[algo_mode].test[keysz_idx].outlen);
+
+ if (err != 0 || output_zero_len || output_mismatch)
+ spacc->config.modes[algo_mode] &= ~(1 << keysz_idx);
+
+ spacc_close(spacc, rc);
+
+ return 0;
+}
+
+int spacc_autodetect(struct spacc_device *spacc)
+{
+ int x, y;
+ void *virt;
+ dma_addr_t dma;
+ struct pdu_ddt ddt;
+ unsigned char key[128];
+
+ spacc->autodetect = true;
+
+ /* allocate DMA memory */
+ virt = dma_alloc_coherent(spacc->dptr, SPACC_TEST_DMA_BUFF_SIZE,
+ &dma, GFP_KERNEL);
+ if (!virt)
+ return -ENOMEM;
+
+ if (pdu_ddt_init(spacc->dptr, &ddt, 1)) {
+ dma_free_coherent(spacc->dptr, SPACC_TEST_DMA_BUFF_SIZE,
+ virt, dma);
+ return -EIO;
+ }
+
+ pdu_ddt_add(spacc->dptr, &ddt, dma, SPACC_TEST_DMA_BUFF_SIZE);
+
+ /* loop through and create a key for autodetect*/
+ for (x = 0; x < sizeof(key); x++)
+ key[x] = x & 0xff;
+
+ for (x = 0; x < ARRAY_SIZE(template); x++) {
+ if (!template[x] ||
+ spacc->config.version < testdata[x].min_version) {
+ spacc->config.modes[x] = 0;
+ continue;
+ }
+
+ spacc->config.modes[x] = template[x];
+ for (y = 0; y < ARRAY_SIZE(keysizes[0]); y++) {
+ /*
+ * spacc_check_modes() now always returns 0 --
+ * it only comes back once the job is confirmed
+ * done, closes it itself, and disables the mode
+ * bit internally on any failure/mismatch. Nothing
+ * left for this loop to branch on.
+ */
+ spacc_check_modes(spacc, x, y, virt, key, &ddt);
+ }
+
+ if (!(spacc->config.modes[x] & 0x7F))
+ spacc->config.modes[x] &= ~128;
+ }
+
+ pdu_ddt_free(&ddt);
+ dma_free_coherent(spacc->dptr, SPACC_TEST_DMA_BUFF_SIZE, virt, dma);
+ spacc->autodetect = false;
+
+ return 0;
+}
+
+#else
+
static void spacc_static_modes(struct spacc_device *spacc, int x, int y)
{
/* disable the algos that are not supported here */
@@ -621,6 +1797,7 @@ int spacc_static_config(struct spacc_device *spacc)
return 0;
}
+#endif
int spacc_clone_handle(struct spacc_device *spacc, int old_handle,
void *cbdata)
--
2.25.1
^ permalink raw reply related
* [PATCH v17 2/4] crypto: spacc - Add SPAcc ahash support
From: Pavitrakumar Managutte @ 2026-07-20 11:37 UTC (permalink / raw)
To: linux-crypto, linux-kernel, devicetree, herbert, robh
Cc: krzk, conor+dt, ruud.derwig, rbannerm, manjunath.hadli, adityak,
navami.telsang, bhoomikak, nazim.khan, Pavitrakumar Managutte
In-Reply-To: <20260720113740.64960-1-pavitrakumarm@vayavyalabs.com>
Add ahash support to SPAcc driver.
Below are the hash algos supported:
- cmac(aes)
- xcbc(aes)
- cmac(sm4)
- xcbc(sm4)
- hmac(md5)
- md5
- hmac(sha1)
- sha1
- sha224
- sha256
- sha384
- sha512
- hmac(sha224)
- hmac(sha256)
- hmac(sha384)
- hmac(sha512)
- sha3-224
- sha3-256
- sha3-384
- sha3-512
Co-developed-by: Bhoomika Kadabi <bhoomikak@vayavyalabs.com>
Signed-off-by: Bhoomika Kadabi <bhoomikak@vayavyalabs.com>
Acked-by: Ross Bannerman <rbannerm@synopsys.com>
Signed-off-by: Pavitrakumar Managutte <pavitrakumarm@vayavyalabs.com>
Signed-off-by: Manjunath Hadli <manjunath.hadli@vayavyalabs.com>
---
drivers/crypto/dwc-spacc/spacc_ahash.c | 990 ++++++++++++++
drivers/crypto/dwc-spacc/spacc_core.c | 1374 ++++++++++++++++++++
drivers/crypto/dwc-spacc/spacc_core.h | 857 ++++++++++++
drivers/crypto/dwc-spacc/spacc_device.c | 284 ++++
drivers/crypto/dwc-spacc/spacc_device.h | 242 ++++
drivers/crypto/dwc-spacc/spacc_hal.c | 344 +++++
drivers/crypto/dwc-spacc/spacc_hal.h | 119 ++
drivers/crypto/dwc-spacc/spacc_interrupt.c | 330 +++++
drivers/crypto/dwc-spacc/spacc_manager.c | 649 +++++++++
9 files changed, 5189 insertions(+)
create mode 100644 drivers/crypto/dwc-spacc/spacc_ahash.c
create mode 100644 drivers/crypto/dwc-spacc/spacc_core.c
create mode 100644 drivers/crypto/dwc-spacc/spacc_core.h
create mode 100644 drivers/crypto/dwc-spacc/spacc_device.c
create mode 100644 drivers/crypto/dwc-spacc/spacc_device.h
create mode 100644 drivers/crypto/dwc-spacc/spacc_hal.c
create mode 100644 drivers/crypto/dwc-spacc/spacc_hal.h
create mode 100644 drivers/crypto/dwc-spacc/spacc_interrupt.c
create mode 100644 drivers/crypto/dwc-spacc/spacc_manager.c
diff --git a/drivers/crypto/dwc-spacc/spacc_ahash.c b/drivers/crypto/dwc-spacc/spacc_ahash.c
new file mode 100644
index 0000000000000..9fc278222db0e
--- /dev/null
+++ b/drivers/crypto/dwc-spacc/spacc_ahash.c
@@ -0,0 +1,990 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/dmapool.h>
+#include <crypto/sha1.h>
+#include <crypto/sm4.h>
+#include <crypto/sha2.h>
+#include <crypto/sha3.h>
+#include <crypto/md5.h>
+#include <crypto/aes.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/internal/hash.h>
+#include <crypto/engine.h>
+#include <linux/delay.h>
+#include <linux/atomic.h>
+
+#include "spacc_device.h"
+#include "spacc_core.h"
+
+#define PPP_BUF_SIZE 128
+
+static struct mode_tab possible_hashes[] = {
+ { .keylen[0] = 16, MODE_TAB_HASH("cmac(aes)", MAC_CMAC, 16, 16) },
+ { .keylen[0] = 48 | MODE_TAB_HASH_XCBC, MODE_TAB_HASH("xcbc(aes)",
+ MAC_XCBC, 16, 16) },
+
+ { MODE_TAB_HASH("cmac(sm4)", MAC_SM4_CMAC, 16, 16) },
+ { .keylen[0] = 32 | MODE_TAB_HASH_XCBC, MODE_TAB_HASH("xcbc(sm4)",
+ MAC_SM4_XCBC, 16, 16) },
+
+ { MODE_TAB_HASH("hmac(md5)", HMAC_MD5, MD5_DIGEST_SIZE,
+ MD5_HMAC_BLOCK_SIZE) },
+ { MODE_TAB_HASH("md5", HASH_MD5, MD5_DIGEST_SIZE,
+ MD5_HMAC_BLOCK_SIZE) },
+
+ { MODE_TAB_HASH("hmac(sha1)", HMAC_SHA1, SHA1_DIGEST_SIZE,
+ SHA1_BLOCK_SIZE) },
+ { MODE_TAB_HASH("sha1", HASH_SHA1, SHA1_DIGEST_SIZE,
+ SHA1_BLOCK_SIZE) },
+
+ { MODE_TAB_HASH("sha224", HASH_SHA224, SHA224_DIGEST_SIZE,
+ SHA224_BLOCK_SIZE) },
+ { MODE_TAB_HASH("sha256", HASH_SHA256, SHA256_DIGEST_SIZE,
+ SHA256_BLOCK_SIZE) },
+ { MODE_TAB_HASH("sha384", HASH_SHA384, SHA384_DIGEST_SIZE,
+ SHA384_BLOCK_SIZE) },
+ { MODE_TAB_HASH("sha512", HASH_SHA512, SHA512_DIGEST_SIZE,
+ SHA512_BLOCK_SIZE) },
+
+ { MODE_TAB_HASH("hmac(sha512)", HMAC_SHA512, SHA512_DIGEST_SIZE,
+ SHA512_BLOCK_SIZE) },
+ { MODE_TAB_HASH("hmac(sha224)", HMAC_SHA224, SHA224_DIGEST_SIZE,
+ SHA224_BLOCK_SIZE) },
+ { MODE_TAB_HASH("hmac(sha256)", HMAC_SHA256, SHA256_DIGEST_SIZE,
+ SHA256_BLOCK_SIZE) },
+ { MODE_TAB_HASH("hmac(sha384)", HMAC_SHA384, SHA384_DIGEST_SIZE,
+ SHA384_BLOCK_SIZE) },
+
+ { MODE_TAB_HASH("sha3-224", HASH_SHA3_224, SHA3_224_DIGEST_SIZE,
+ SHA3_224_BLOCK_SIZE) },
+ { MODE_TAB_HASH("sha3-256", HASH_SHA3_256, SHA3_256_DIGEST_SIZE,
+ SHA3_256_BLOCK_SIZE) },
+ { MODE_TAB_HASH("sha3-384", HASH_SHA3_384, SHA3_384_DIGEST_SIZE,
+ SHA3_384_BLOCK_SIZE) },
+ { MODE_TAB_HASH("sha3-512", HASH_SHA3_512, SHA3_512_DIGEST_SIZE,
+ SHA3_512_BLOCK_SIZE) },
+};
+
+static void spacc_hash_cleanup_dma_dst(struct spacc_crypto_ctx *tctx,
+ struct ahash_request *req)
+{
+ struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+ pdu_ddt_free(&ctx->dst);
+}
+
+static void spacc_hash_cleanup_dma_src(struct spacc_crypto_ctx *tctx,
+ struct ahash_request *req)
+{
+ struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+ if (tctx->tmp_sgl && tctx->tmp_sgl[0].length != 0) {
+ dma_unmap_sg(tctx->dev, tctx->tmp_sgl, ctx->src_nents,
+ DMA_TO_DEVICE);
+ kfree(tctx->tmp_sgl_buff);
+ tctx->tmp_sgl_buff = NULL;
+ tctx->tmp_sgl[0].length = 0;
+ } else
+ dma_unmap_sg(tctx->dev, req->src, ctx->src_nents,
+ DMA_TO_DEVICE);
+
+ pdu_ddt_free(&ctx->src);
+}
+
+static int spacc_init_calg(struct crypto_alg *calg,
+ const struct mode_tab *mode)
+{
+ if (strscpy(calg->cra_name, mode->name) < 0)
+ return -ENAMETOOLONG;
+
+ if (snprintf(calg->cra_driver_name, CRYPTO_MAX_ALG_NAME,
+ "spacc-%s", mode->name) >= CRYPTO_MAX_ALG_NAME)
+ return -ENAMETOOLONG;
+
+ calg->cra_blocksize = mode->blocklen;
+
+ return 0;
+}
+
+static int spacc_ctx_clone_handle(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+ struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+ struct spacc_priv *priv = dev_get_drvdata(tctx->dev);
+
+ if (tctx->handle < 0)
+ return -EINVAL;
+
+ if (!priv)
+ return -ENODEV;
+
+ ctx->acb.new_handle = spacc_clone_handle(&priv->spacc, tctx->handle,
+ &ctx->acb);
+
+ if (ctx->acb.new_handle < 0)
+ return -ENOMEM;
+
+ ctx->acb.tctx = tctx;
+ ctx->acb.ctx = ctx;
+ ctx->acb.req = req;
+ ctx->acb.spacc = &priv->spacc;
+
+ return 0;
+}
+
+static int spacc_hash_init_dma(struct device *dev, struct ahash_request *req)
+{
+ int rc = -1;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+ struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+ struct spacc_priv *priv = dev_get_drvdata(dev);
+
+ /*
+ * do_one_request runs in a sleepable context ,
+ * so GFP_KERNEL is always safe here.
+ */
+ gfp_t mflags = GFP_KERNEL;
+
+ ctx->acb.new_handle = -1;
+
+ ctx->digest_buf = dma_pool_alloc(priv->hash_pool, mflags,
+ &ctx->digest_dma);
+
+ if (!ctx->digest_buf)
+ return -ENOMEM;
+
+ rc = pdu_ddt_init(dev, &ctx->dst, 1 | 0x80000000);
+ if (rc < 0) {
+ dev_err(dev, "ERR: PDU DDT init error\n");
+ rc = -EIO;
+ goto err_free_digest;
+ }
+
+ pdu_ddt_add(dev, &ctx->dst, ctx->digest_dma, SPACC_MAX_DIGEST_SIZE);
+
+ if (ctx->total_nents > 0 && ctx->single_shot) {
+ /* single shot */
+ rc = spacc_ctx_clone_handle(req);
+ if (rc < 0)
+ goto err_free_dst;
+
+ if (req->nbytes) {
+ rc = spacc_sg_to_ddt(dev, req->src, req->nbytes,
+ &ctx->src, DMA_TO_DEVICE);
+ } else {
+ memset(tctx->tmp_buffer, '\0', PPP_BUF_SIZE);
+ sg_set_buf(&tctx->tmp_sgl[0], tctx->tmp_buffer,
+ PPP_BUF_SIZE);
+ rc = spacc_sg_to_ddt(dev, &tctx->tmp_sgl[0],
+ tctx->tmp_sgl[0].length,
+ &ctx->src, DMA_TO_DEVICE);
+ }
+ } else if (ctx->total_nents == 0 && req->nbytes == 0) {
+ rc = spacc_ctx_clone_handle(req);
+ if (rc < 0)
+ goto err_free_dst;
+
+ /* zero length case */
+ memset(tctx->tmp_buffer, '\0', PPP_BUF_SIZE);
+ sg_set_buf(&tctx->tmp_sgl[0], tctx->tmp_buffer, PPP_BUF_SIZE);
+ rc = spacc_sg_to_ddt(dev, &tctx->tmp_sgl[0],
+ tctx->tmp_sgl[0].length,
+ &ctx->src, DMA_TO_DEVICE);
+ } else {
+ /*
+ * ctx->total_nents == 0 with req->nbytes > 0: an empty
+ * scatterlist can't supply the bytes the request claims to
+ * have. Neither branch above applies -- fail explicitly
+ * instead of silently falling through with a stale `rc`.
+ */
+ dev_err(dev, "ERR: empty src sg with nbytes=%u\n",
+ req->nbytes);
+ rc = -EINVAL;
+ goto err_free_dst;
+ }
+
+ if (rc < 0)
+ goto err_free_dst;
+
+ ctx->src_nents = rc;
+ return rc;
+
+err_free_dst:
+ /*
+ * If the handle was already cloned (semaphore count and job slot
+ * taken) before this failure, release it. Clone-failure paths
+ * leave new_handle < 0, so the guard skips them.
+ */
+ if (ctx->acb.new_handle >= 0) {
+ spacc_close(&priv->spacc, ctx->acb.new_handle);
+ ctx->acb.new_handle = -1;
+ }
+ pdu_ddt_free(&ctx->dst);
+err_free_digest:
+ dma_pool_free(priv->hash_pool, ctx->digest_buf, ctx->digest_dma);
+
+ return rc;
+}
+
+static void spacc_free_mems(struct spacc_crypto_reqctx *ctx,
+ struct spacc_crypto_ctx *tctx,
+ struct ahash_request *req)
+{
+ spacc_hash_cleanup_dma_dst(tctx, req);
+ spacc_hash_cleanup_dma_src(tctx, req);
+
+ if (ctx->single_shot) {
+ kfree(tctx->tmp_sgl);
+ tctx->tmp_sgl = NULL;
+
+ ctx->single_shot = 0;
+ if (ctx->total_nents)
+ ctx->total_nents = 0;
+ }
+}
+
+static void spacc_digest_cb(void *spacc, void *tfm)
+{
+ int err;
+ int dig_sz;
+ struct ahash_cb_data *cb = tfm;
+ struct spacc_device *device = spacc;
+ struct spacc_priv *priv = container_of(device, struct spacc_priv,
+ spacc);
+
+ dig_sz = crypto_ahash_digestsize(crypto_ahash_reqtfm(cb->req));
+
+ if (cb->ctx->single_shot)
+ memcpy(cb->req->result, cb->ctx->digest_buf, dig_sz);
+ else
+ memcpy(cb->tctx->digest_ctx_buf, cb->ctx->digest_buf, dig_sz);
+
+ err = cb->spacc->job[cb->new_handle].job_err;
+
+ dma_pool_free(priv->hash_pool, cb->ctx->digest_buf,
+ cb->ctx->digest_dma);
+
+ spacc_free_mems(cb->ctx, cb->tctx, cb->req);
+ spacc_close(cb->spacc, cb->new_handle);
+
+ local_bh_disable();
+ crypto_finalize_hash_request(priv->engine, cb->req, err);
+ local_bh_enable();
+}
+
+static int spacc_hash_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ unsigned int block_size;
+ unsigned int digest_size;
+ const struct spacc_alg *salg = spacc_tfm_ahash(&tfm->base);
+ struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+ struct spacc_priv *priv = dev_get_drvdata(salg->dev);
+
+ block_size = crypto_tfm_alg_blocksize(&tfm->base);
+ digest_size = crypto_ahash_digestsize(tfm);
+
+ /*
+ * We are using hardware for HMAC operations. The software fallback is
+ * only for key pre-processing in case of HMACs.
+ * This was meant for hashes but it also works for cmac/xcbc.
+ */
+ if (keylen > block_size && salg->mode->id != CRYPTO_MODE_MAC_CMAC) {
+ dev_dbg(salg->dev, "Exceeds keylen: %u\n", keylen);
+ dev_dbg(salg->dev, "Req. keylen hashing %s\n",
+ salg->calg->cra_name);
+
+ switch (salg->mode->id) {
+ case CRYPTO_MODE_HMAC_SHA224:
+ sha224(key, keylen, tctx->ipad);
+ break;
+
+ case CRYPTO_MODE_HMAC_SHA256:
+ sha256(key, keylen, tctx->ipad);
+ break;
+
+ case CRYPTO_MODE_HMAC_SHA384:
+ sha384(key, keylen, tctx->ipad);
+ break;
+
+ case CRYPTO_MODE_HMAC_SHA512:
+ sha512(key, keylen, tctx->ipad);
+ break;
+
+ case CRYPTO_MODE_HMAC_MD5:
+ md5(key, keylen, tctx->ipad);
+ break;
+
+ case CRYPTO_MODE_HMAC_SHA1:
+ sha1(key, keylen, tctx->ipad);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ keylen = digest_size;
+ dev_dbg(salg->dev, "updated keylen: %u\n", keylen);
+ } else {
+ /*
+ * CMAC/XCBC skip the hashing path above, and via AF_ALG the
+ * key length is fully user-controlled. tctx->ipad is a fixed
+ * 128-byte buffer, so reject anything that would not fit
+ * before copying to prevent a heap buffer overflow.
+ */
+ if (keylen > sizeof(tctx->ipad))
+ return -EINVAL;
+
+ /*
+ * Enforcing valid block-cipher * key sizes supported by SPAcc:
+ * AES-CMAC accepts 16/24/32,
+ * SM4-CMAC/XCBC/SM4-XCBC only 16.
+ */
+
+ memcpy(tctx->ipad, key, keylen);
+ }
+
+ if (!spacc_is_mode_keysize_supported(&priv->spacc, salg->mode->id,
+ keylen, 1)) {
+ dev_dbg(salg->dev, "keylen %u not supported for mode %d\n",
+ keylen, salg->mode->id);
+ return -EINVAL;
+ }
+
+ {
+ guard(mutex)(&tctx->lock);
+
+ tctx->keylen = keylen;
+
+ /*
+ * For CMAC/XCBC the shash fallback also needs the key so that
+ * the software path produces correct MACs when the HW
+ * context is not yet available.
+ */
+ if (tctx->shash_fb) {
+ int rc = crypto_shash_setkey(tctx->shash_fb, key,
+ keylen);
+
+ if (rc)
+ return rc;
+ }
+
+ /* Invalidate any cached HW context - key has changed. */
+ if (tctx->handle >= 0) {
+ spacc_close(&priv->spacc, tctx->handle);
+ tctx->handle = -1;
+ }
+
+ tctx->ctx_valid = false;
+ }
+
+ return 0;
+}
+
+/* Crypto engine hash operation */
+static int spacc_hash_do_one_request(struct crypto_engine *engine, void *areq)
+{
+ int rc = 0;
+ struct ahash_request *req = ahash_request_cast(areq);
+ struct crypto_ahash *reqtfm = crypto_ahash_reqtfm(req);
+ struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(reqtfm);
+ struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+ const struct spacc_alg *salg = spacc_tfm_ahash(&reqtfm->base);
+ /*
+ * Derive priv from the algorithm's stable device, not tctx->dev --
+ * the latter is mutated by setkey() concurrently with this
+ * function and is not safe to read outside tctx->lock.
+ */
+ struct spacc_priv *priv = dev_get_drvdata(salg->dev);
+
+ ctx->single_shot = 1;
+ ctx->total_nents = sg_nents(req->src);
+
+ tctx->tmp_sgl = kmalloc_array(2, sizeof(*tctx->tmp_sgl), GFP_KERNEL);
+
+ if (!tctx->tmp_sgl)
+ goto fallback;
+
+ sg_init_table(tctx->tmp_sgl, 2);
+ tctx->tmp_sgl[0].length = 0;
+
+ {
+ guard(mutex)(&tctx->lock);
+
+ if (tctx->handle < 0 || !tctx->ctx_valid) {
+ /*
+ * spacc_open() acquires ctx_sem which may sleep;
+ * do_one_request runs in the crypto_engine workqueue
+ * which is a sleepable context, so this is safe.
+ */
+ tctx->handle = spacc_open(&priv->spacc,
+ CRYPTO_MODE_NULL, salg->mode->id,
+ -1, 0, spacc_digest_cb, reqtfm);
+ if (tctx->handle < 0) {
+ dev_dbg(salg->dev,
+ "context open failed, fallback\n");
+ goto fallback;
+ }
+
+ rc = spacc_set_operation(&priv->spacc, tctx->handle,
+ OP_ENCRYPT, ICV_HASH, IP_ICV_OFFSET,
+ 0, 0, 0);
+
+ if (rc < 0) {
+ spacc_close(&priv->spacc, tctx->handle);
+ tctx->handle = -1;
+ goto fallback;
+ }
+
+ if (tctx->keylen > 0) {
+ u32 mode_id = salg->mode->id;
+
+ if (mode_id == CRYPTO_MODE_MAC_XCBC ||
+ mode_id == CRYPTO_MODE_MAC_SM4_XCBC) {
+ rc = spacc_compute_xcbc_key(
+ &priv->spacc,
+ mode_id,
+ tctx->handle,
+ tctx->ipad,
+ tctx->keylen,
+ tctx->ipad);
+ if (rc < 0) {
+ spacc_close(&priv->spacc,
+ tctx->handle);
+ tctx->handle = -1;
+ goto fallback;
+ }
+
+ rc = spacc_write_context(&priv->spacc,
+ tctx->handle,
+ SPACC_HASH_OPERATION,
+ tctx->ipad,
+ 32 + tctx->keylen,
+ NULL, 0);
+ } else {
+ rc = spacc_write_context(&priv->spacc,
+ tctx->handle,
+ SPACC_HASH_OPERATION,
+ tctx->ipad,
+ tctx->keylen,
+ NULL, 0);
+ }
+
+ if (rc < 0) {
+ spacc_close(&priv->spacc, tctx->handle);
+ tctx->handle = -1;
+ goto fallback;
+ }
+ }
+
+ memzero_explicit(tctx->ipad, sizeof(tctx->ipad));
+ tctx->ctx_valid = true;
+ }
+
+ rc = spacc_hash_init_dma(tctx->dev, req);
+ if (rc < 0) {
+ dev_dbg(salg->dev,
+ "DMA init failed (%d), falling back\n", rc);
+ goto fallback;
+ }
+ }
+ rc = spacc_packet_enqueue_ddt(&priv->spacc, ctx->acb.new_handle,
+ &ctx->src, &ctx->dst, req->nbytes,
+ 0, req->nbytes, 0, 0, 0);
+ if (rc < 0) {
+ spacc_free_mems(ctx, tctx, req);
+
+ dma_pool_free(priv->hash_pool, ctx->digest_buf,
+ ctx->digest_dma);
+ pdu_ddt_free(&ctx->dst);
+
+ if (ctx->acb.new_handle >= 0) {
+ spacc_close(&priv->spacc, ctx->acb.new_handle);
+ ctx->acb.new_handle = -1;
+ }
+
+ if (rc == -EBUSY)
+ dev_dbg(salg->dev, "HW full, failing request\n");
+
+ local_bh_disable();
+ crypto_finalize_hash_request(priv->engine, req, rc);
+ local_bh_enable();
+
+ return 0;
+ }
+
+ return 0;
+fallback:
+ kfree(tctx->tmp_sgl);
+ tctx->tmp_sgl = NULL;
+
+ if (tctx->shash_fb) {
+ SHASH_DESC_ON_STACK(desc, tctx->shash_fb);
+
+ desc->tfm = tctx->shash_fb;
+
+ rc = crypto_shash_init(desc);
+ if (!rc) {
+ struct sg_mapping_iter miter;
+ unsigned int remaining = req->nbytes;
+ int nents = sg_nents_for_len(req->src, req->nbytes);
+
+ if (nents < 0) {
+ rc = nents;
+ } else {
+ sg_miter_start(&miter, req->src, nents,
+ SG_MITER_ATOMIC | SG_MITER_FROM_SG);
+ while (remaining && sg_miter_next(&miter)) {
+ unsigned int len = min(miter.length,
+ remaining);
+
+ rc = crypto_shash_update(desc,
+ miter.addr, len);
+ if (rc)
+ break;
+
+ remaining -= len;
+ }
+ sg_miter_stop(&miter);
+
+ if (!rc && remaining)
+ rc = -EINVAL;
+ }
+ }
+ if (!rc)
+ rc = crypto_shash_final(desc, req->result);
+
+ shash_desc_zero(desc);
+ } else {
+ HASH_FBREQ_ON_STACK(fbreq, req);
+
+ rc = crypto_ahash_digest(fbreq);
+
+ HASH_REQUEST_ZERO(fbreq);
+ }
+
+ local_bh_disable();
+ crypto_finalize_hash_request(engine, req, rc);
+ local_bh_enable();
+
+ return 0;
+}
+
+static int spacc_hash_init_tfm(struct crypto_ahash *tfm)
+{
+ const struct spacc_alg *salg = container_of(crypto_ahash_alg(tfm),
+ struct spacc_alg,
+ alg.hash.base);
+ struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+
+ tctx->handle = -1;
+ tctx->ctx_valid = false;
+ tctx->dev = get_device(salg->dev);
+ tctx->shash_fb = NULL;
+ mutex_init(&tctx->lock);
+
+ /*
+ * CMAC and XCBC-AES require a shash fallback. Their ahash fallback
+ * would loop back into this driver; a shash implementation (e.g.
+ * generic cmac or xcbc) is the correct software path.
+ */
+ if (salg->mode->id == CRYPTO_MODE_MAC_CMAC ||
+ salg->mode->id == CRYPTO_MODE_MAC_XCBC ||
+ salg->mode->id == CRYPTO_MODE_MAC_SM4_CMAC ||
+ salg->mode->id == CRYPTO_MODE_MAC_SM4_XCBC) {
+ tctx->shash_fb = crypto_alloc_shash(
+ salg->alg.hash.base.halg.base.cra_name, 0, 0);
+ if (IS_ERR(tctx->shash_fb)) {
+ int err = PTR_ERR(tctx->shash_fb);
+
+ tctx->shash_fb = NULL;
+ put_device(tctx->dev);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static void spacc_hash_exit_tfm(struct crypto_ahash *tfm)
+{
+ struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+ struct spacc_priv *priv = dev_get_drvdata(tctx->dev);
+
+ if (tctx->shash_fb) {
+ crypto_free_shash(tctx->shash_fb);
+ tctx->shash_fb = NULL;
+ }
+
+ if (priv && tctx->handle >= 0)
+ spacc_close(&priv->spacc, tctx->handle);
+
+ put_device(tctx->dev);
+ mutex_destroy(&tctx->lock);
+}
+
+static int spacc_hash_init(struct ahash_request *req)
+{
+ int rc;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+ struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+ memset(ctx->state_buffer, 0, sizeof(ctx->state_buffer));
+
+ if (tctx->shash_fb) {
+ SHASH_DESC_ON_STACK(desc, tctx->shash_fb);
+
+ desc->tfm = tctx->shash_fb;
+ rc = crypto_shash_init(desc);
+ if (!rc)
+ rc = crypto_shash_export(desc, ctx->state_buffer);
+ shash_desc_zero(desc);
+ } else {
+ HASH_FBREQ_ON_STACK(fbreq, req);
+
+ rc = crypto_ahash_init(fbreq);
+ if (!rc)
+ rc = crypto_ahash_export(fbreq, ctx->state_buffer);
+ HASH_REQUEST_ZERO(fbreq);
+ }
+
+ return rc;
+}
+
+static int spacc_hash_update(struct ahash_request *req)
+{
+ int rc;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+ struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+ if (!req->nbytes)
+ return 0;
+
+ if (tctx->shash_fb) {
+ SHASH_DESC_ON_STACK(desc, tctx->shash_fb);
+ struct sg_mapping_iter miter;
+ size_t remaining;
+ int nents;
+
+ desc->tfm = tctx->shash_fb;
+ rc = crypto_shash_import(desc, ctx->state_buffer);
+ if (rc)
+ goto out_shash;
+
+ nents = sg_nents_for_len(req->src, req->nbytes);
+
+ if (nents < 0) {
+ rc = nents;
+ goto out_shash;
+ }
+
+ sg_miter_start(&miter, req->src, nents,
+ SG_MITER_ATOMIC | SG_MITER_FROM_SG);
+
+ remaining = req->nbytes;
+ while (sg_miter_next(&miter) && remaining > 0) {
+ size_t len = min_t(size_t, miter.length, remaining);
+
+ rc = crypto_shash_update(desc, miter.addr, len);
+ if (rc)
+ break;
+ remaining -= len;
+ }
+ sg_miter_stop(&miter);
+ if (!rc)
+ rc = crypto_shash_export(desc, ctx->state_buffer);
+out_shash:
+ shash_desc_zero(desc);
+ } else {
+ HASH_FBREQ_ON_STACK(fbreq, req);
+
+ rc = crypto_ahash_import(fbreq, ctx->state_buffer);
+ if (!rc)
+ rc = crypto_ahash_update(fbreq);
+ if (!rc)
+ rc = crypto_ahash_export(fbreq, ctx->state_buffer);
+ HASH_REQUEST_ZERO(fbreq);
+ }
+
+ return rc;
+}
+
+static int spacc_hash_final(struct ahash_request *req)
+{
+ int rc;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+ struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+ if (tctx->shash_fb) {
+ SHASH_DESC_ON_STACK(desc, tctx->shash_fb);
+
+ desc->tfm = tctx->shash_fb;
+ rc = crypto_shash_import(desc, ctx->state_buffer);
+ if (!rc)
+ rc = crypto_shash_final(desc, req->result);
+ shash_desc_zero(desc);
+ } else {
+ HASH_FBREQ_ON_STACK(fbreq, req);
+
+ rc = crypto_ahash_import(fbreq, ctx->state_buffer);
+ if (!rc)
+ rc = crypto_ahash_final(fbreq);
+ HASH_REQUEST_ZERO(fbreq);
+ }
+
+ return rc;
+}
+
+static int spacc_hash_digest(struct ahash_request *req)
+{
+ struct crypto_ahash *reqtfm = crypto_ahash_reqtfm(req);
+ struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(reqtfm);
+ struct spacc_priv *priv = dev_get_drvdata(tctx->dev);
+
+ if (!priv)
+ return -ENODEV;
+
+ return crypto_transfer_hash_request_to_engine(priv->engine, req);
+}
+
+static int spacc_hash_finup(struct ahash_request *req)
+{
+ int rc;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+ struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+ if (tctx->shash_fb) {
+ SHASH_DESC_ON_STACK(desc, tctx->shash_fb);
+ struct sg_mapping_iter miter;
+ size_t remaining;
+ int nents;
+
+ desc->tfm = tctx->shash_fb;
+ rc = crypto_shash_import(desc, ctx->state_buffer);
+ if (rc)
+ goto out_shash;
+
+ nents = sg_nents_for_len(req->src, req->nbytes);
+
+ if (nents < 0) {
+ rc = nents;
+ goto out_shash;
+ }
+
+ sg_miter_start(&miter, req->src, nents,
+ SG_MITER_ATOMIC | SG_MITER_FROM_SG);
+
+ remaining = req->nbytes;
+ while (sg_miter_next(&miter) && remaining > 0) {
+ size_t len = min_t(size_t, miter.length, remaining);
+
+ rc = crypto_shash_update(desc, miter.addr, len);
+ if (rc)
+ break;
+ remaining -= len;
+ }
+ sg_miter_stop(&miter);
+ if (!rc)
+ rc = crypto_shash_final(desc, req->result);
+out_shash:
+ shash_desc_zero(desc);
+ } else {
+ HASH_FBREQ_ON_STACK(fbreq, req);
+
+ rc = crypto_ahash_import(fbreq, ctx->state_buffer);
+ if (!rc)
+ rc = crypto_ahash_finup(fbreq);
+ HASH_REQUEST_ZERO(fbreq);
+ }
+
+ return rc;
+}
+
+static int spacc_hash_export(struct ahash_request *req, void *out)
+{
+ struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+ memcpy(out, ctx->state_buffer, HASH_MAX_STATESIZE);
+ return 0;
+}
+
+static int spacc_hash_import(struct ahash_request *req, const void *in)
+{
+ struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+ memcpy(ctx->state_buffer, in, HASH_MAX_STATESIZE);
+ return 0;
+}
+
+static void spacc_hash_alg_destroy(struct crypto_alg *alg)
+{
+ struct spacc_alg *salg = container_of(alg, struct spacc_alg,
+ alg.hash.base.halg.base);
+
+ kfree(salg);
+}
+
+static const struct ahash_engine_alg spacc_hash_template = {
+ .base = {
+ .init = spacc_hash_init,
+ .update = spacc_hash_update,
+ .final = spacc_hash_final,
+ .finup = spacc_hash_finup,
+ .digest = spacc_hash_digest,
+ .setkey = spacc_hash_setkey,
+ .export = spacc_hash_export,
+ .import = spacc_hash_import,
+ .init_tfm = spacc_hash_init_tfm,
+ .exit_tfm = spacc_hash_exit_tfm,
+
+ .halg.base = {
+ .cra_priority = 300,
+ .cra_module = THIS_MODULE,
+ .cra_ctxsize = sizeof(struct spacc_crypto_ctx),
+ .cra_reqsize = sizeof(struct spacc_crypto_reqctx),
+ .cra_destroy = spacc_hash_alg_destroy,
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+ CRYPTO_ALG_ASYNC
+ },
+ },
+ .op = {
+ .do_one_request = spacc_hash_do_one_request,
+ },
+};
+
+static int spacc_register_hash(struct spacc_alg *salg)
+{
+ int rc = 0;
+ struct spacc_priv *priv = dev_get_drvdata(salg->dev);
+
+ salg->calg = &salg->alg.hash.base.halg.base;
+ salg->alg.hash = spacc_hash_template;
+
+ rc = spacc_init_calg(salg->calg, salg->mode);
+ if (rc)
+ return rc;
+
+ salg->alg.hash.base.halg.digestsize = salg->mode->hashlen;
+ salg->alg.hash.base.halg.statesize = HASH_MAX_STATESIZE;
+
+ /*
+ * CMAC/XCBC-AES have a dedicated shash fallback (allocated in
+ * init_tfm). They must not advertise CRYPTO_ALG_OPTIONAL_KEY or
+ * the crypto API may try to use the generic ahash fallback for them,
+ * which would recurse back into this driver.
+ */
+ if (salg->mode->id == CRYPTO_MODE_MAC_CMAC ||
+ salg->mode->id == CRYPTO_MODE_MAC_XCBC ||
+ salg->mode->id == CRYPTO_MODE_MAC_SM4_CMAC ||
+ salg->mode->id == CRYPTO_MODE_MAC_SM4_XCBC) {
+ salg->alg.hash.base.halg.base.cra_flags =
+ CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NO_FALLBACK;
+ } else if (!strncmp(salg->mode->name, "hmac(", 5)) {
+ /*
+ * HMAC uses the software fallback path, which requires
+ * the crypto core to allocate a fallback tfm.
+ */
+ salg->alg.hash.base.halg.base.cra_flags =
+ CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK;
+ } else {
+ salg->alg.hash.base.halg.base.cra_flags =
+ CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_OPTIONAL_KEY | CRYPTO_ALG_NEED_FALLBACK;
+ }
+
+ rc = crypto_engine_register_ahash(&salg->alg.hash);
+ if (rc < 0)
+ return rc;
+
+ guard(mutex)(&priv->hash_alg_mutex);
+ list_add(&salg->list, &priv->hash_alg_list);
+
+ return 0;
+}
+
+int spacc_probe_hashes(struct platform_device *spacc_pdev)
+{
+ int rc = 0;
+ unsigned int index;
+ int registered = 0;
+ struct spacc_alg *salg;
+ struct spacc_priv *priv = dev_get_drvdata(&spacc_pdev->dev);
+ const char *name = NULL;
+
+ /* Create per-device DMA pool */
+ priv->hash_pool = dma_pool_create("spacc-digest", &spacc_pdev->dev,
+ SPACC_MAX_DIGEST_SIZE,
+ SPACC_DMA_ALIGN, SPACC_DMA_BOUNDARY);
+
+ if (!priv->hash_pool)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&priv->hash_alg_list);
+ mutex_init(&priv->hash_alg_mutex);
+
+ for (index = 0; index < ARRAY_SIZE(possible_hashes); index++) {
+ name = possible_hashes[index].name;
+
+ if (!crypto_has_ahash(name, 0, 0))
+ continue;
+
+ /* Just check hardware support - no .valid flag needed */
+ if (spacc_is_mode_keysize_supported(&priv->spacc,
+ possible_hashes[index].id & 0xFF,
+ possible_hashes[index].hashlen, 1)) {
+ salg = kmalloc_obj(*salg, GFP_KERNEL);
+ if (!salg) {
+ rc = -ENOMEM;
+ goto err_destroy_pool;
+ }
+
+ salg->mode = &possible_hashes[index];
+ salg->dev = &spacc_pdev->dev;
+
+ rc = spacc_register_hash(salg);
+ if (rc < 0) {
+ kfree(salg);
+ continue;
+ }
+
+ registered++;
+ }
+ }
+
+ return registered;
+
+err_destroy_pool:
+ spacc_unregister_hash_algs(priv);
+ return rc;
+}
+
+int spacc_unregister_hash_algs(struct spacc_priv *priv)
+{
+ struct spacc_alg *salg, *tmp;
+
+ if (!priv)
+ return 0;
+
+ guard(mutex)(&priv->hash_alg_mutex);
+
+ list_for_each_entry_safe(salg, tmp, &priv->hash_alg_list, list) {
+ crypto_engine_unregister_ahash(&salg->alg.hash);
+ list_del(&salg->list);
+ }
+
+ dma_pool_destroy(priv->hash_pool);
+ priv->hash_pool = NULL;
+
+ return 0;
+}
diff --git a/drivers/crypto/dwc-spacc/spacc_core.c b/drivers/crypto/dwc-spacc/spacc_core.c
new file mode 100644
index 0000000000000..e1de5f2df4f51
--- /dev/null
+++ b/drivers/crypto/dwc-spacc/spacc_core.c
@@ -0,0 +1,1374 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <crypto/skcipher.h>
+#include <linux/of.h>
+#include <linux/vmalloc.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+
+#include "spacc_core.h"
+#include "spacc_device.h"
+
+static const u8 spacc_ctrl_map[SPACC_CTRL_VER_SIZE][SPACC_CTRL_MAPSIZE] = {
+ { 0, 8, 4, 12, 24, 16, 31, 25, 26, 27, 28, 29, 14, 15 },
+ { 0, 8, 3, 12, 24, 16, 31, 25, 26, 27, 28, 29, 14, 15 },
+ { 0, 4, 8, 13, 15, 16, 24, 25, 26, 27, 28, 29, 30, 31 }
+};
+
+static const int keysizes[2][7] = {
+ /* 1 2 4 8 16 32 64 */
+ { 5, 8, 16, 24, 32, 0, 0 }, /* cipher key sizes */
+ { 8, 16, 20, 24, 32, 64, 128 }, /* hash key sizes */
+};
+
+static const struct enc_config enc_table[] = {
+ /* mode cipher_alg cipher_mode auxinfo_cs_mode */
+ {CRYPTO_MODE_NULL, 0, 0, 0},
+ {CRYPTO_MODE_AES_ECB, C_AES, CM_ECB, 0},
+ {CRYPTO_MODE_AES_CBC, C_AES, CM_CBC, 0},
+ {CRYPTO_MODE_AES_CS1, C_AES, CM_CBC, 1},
+ {CRYPTO_MODE_AES_CS2, C_AES, CM_CBC, 2},
+ {CRYPTO_MODE_AES_CS3, C_AES, CM_CBC, 3},
+ {CRYPTO_MODE_AES_CFB, C_AES, CM_CFB, 0},
+ {CRYPTO_MODE_AES_OFB, C_AES, CM_OFB, 0},
+ {CRYPTO_MODE_AES_CTR, C_AES, CM_CTR, 0},
+ {CRYPTO_MODE_AES_CCM, C_AES, CM_CCM, 0},
+ {CRYPTO_MODE_AES_GCM, C_AES, CM_GCM, 0},
+ {CRYPTO_MODE_AES_F8, C_AES, CM_F8, 0},
+ {CRYPTO_MODE_AES_XTS, C_AES, CM_XTS, 0},
+ {CRYPTO_MODE_MULTI2_ECB, C_MULTI2, CM_ECB, 0},
+ {CRYPTO_MODE_MULTI2_CBC, C_MULTI2, CM_CBC, 0},
+ {CRYPTO_MODE_MULTI2_OFB, C_MULTI2, CM_OFB, 0},
+ {CRYPTO_MODE_MULTI2_CFB, C_MULTI2, CM_CFB, 0},
+ {CRYPTO_MODE_3DES_CBC, C_DES, CM_CBC, 0},
+ {CRYPTO_MODE_DES_CBC, C_DES, CM_CBC, 0},
+ {CRYPTO_MODE_3DES_ECB, C_DES, CM_ECB, 0},
+ {CRYPTO_MODE_DES_ECB, C_DES, CM_ECB, 0},
+ {CRYPTO_MODE_KASUMI_ECB, C_KASUMI, CM_ECB, 0},
+ {CRYPTO_MODE_KASUMI_F8, C_KASUMI, CM_F8, 0},
+ {CRYPTO_MODE_SNOW3G_UEA2, C_SNOW3G_UEA2, CM_ECB, 0},
+ {CRYPTO_MODE_ZUC_UEA3, C_ZUC_UEA3, CM_ECB, 0},
+ {CRYPTO_MODE_CHACHA20_STREAM, C_CHACHA20, CM_CHACHA_STREAM, 0},
+ {CRYPTO_MODE_CHACHA20_POLY1305, C_CHACHA20, CM_CHACHA_AEAD, 0},
+ {CRYPTO_MODE_SM4_ECB, C_SM4, CM_ECB, 0},
+ {CRYPTO_MODE_SM4_CBC, C_SM4, CM_CBC, 0},
+ {CRYPTO_MODE_SM4_CS1, C_SM4, CM_CBC, 1},
+ {CRYPTO_MODE_SM4_CS2, C_SM4, CM_CBC, 2},
+ {CRYPTO_MODE_SM4_CS3, C_SM4, CM_CBC, 3},
+ {CRYPTO_MODE_SM4_CFB, C_SM4, CM_CFB, 0},
+ {CRYPTO_MODE_SM4_OFB, C_SM4, CM_OFB, 0},
+ {CRYPTO_MODE_SM4_CTR, C_SM4, CM_CTR, 0},
+ {CRYPTO_MODE_SM4_CCM, C_SM4, CM_CCM, 0},
+ {CRYPTO_MODE_SM4_GCM, C_SM4, CM_GCM, 0},
+ {CRYPTO_MODE_SM4_F8, C_SM4, CM_F8, 0},
+ {CRYPTO_MODE_SM4_XTS, C_SM4, CM_XTS, 0},
+};
+
+static const struct hash_config hash_table[] = {
+ /* mode hash_alg hash_mode auxinfo_dir */
+ {CRYPTO_MODE_NULL, H_NULL, 0, 0},
+ {CRYPTO_MODE_HMAC_SHA1, H_SHA1, HM_HMAC, 0},
+ {CRYPTO_MODE_HMAC_MD5, H_MD5, HM_HMAC, 0},
+ {CRYPTO_MODE_HMAC_SHA224, H_SHA224, HM_HMAC, 0},
+ {CRYPTO_MODE_HMAC_SHA256, H_SHA256, HM_HMAC, 0},
+ {CRYPTO_MODE_HMAC_SHA384, H_SHA384, HM_HMAC, 0},
+ {CRYPTO_MODE_HMAC_SHA512, H_SHA512, HM_HMAC, 0},
+ {CRYPTO_MODE_HMAC_SHA512_224, H_SHA512_224, HM_HMAC, 0},
+ {CRYPTO_MODE_HMAC_SHA512_256, H_SHA512_256, HM_HMAC, 0},
+ {CRYPTO_MODE_SSLMAC_MD5, H_MD5, HM_SSLMAC, 0},
+ {CRYPTO_MODE_SSLMAC_SHA1, H_SHA1, HM_SSLMAC, 0},
+ {CRYPTO_MODE_HASH_SHA1, H_SHA1, HM_RAW, 0},
+ {CRYPTO_MODE_HASH_MD5, H_MD5, HM_RAW, 0},
+ {CRYPTO_MODE_HASH_SHA224, H_SHA224, HM_RAW, 0},
+ {CRYPTO_MODE_HASH_SHA256, H_SHA256, HM_RAW, 0},
+ {CRYPTO_MODE_HASH_SHA384, H_SHA384, HM_RAW, 0},
+ {CRYPTO_MODE_HASH_SHA512, H_SHA512, HM_RAW, 0},
+ {CRYPTO_MODE_HASH_SHA512_224, H_SHA512_224, HM_RAW, 0},
+ {CRYPTO_MODE_HASH_SHA512_256, H_SHA512_256, HM_RAW, 0},
+ {CRYPTO_MODE_HASH_SHA3_224, H_SHA3_224, HM_RAW, 0},
+ {CRYPTO_MODE_HASH_SHA3_256, H_SHA3_256, HM_RAW, 0},
+ {CRYPTO_MODE_HASH_SHA3_384, H_SHA3_384, HM_RAW, 0},
+ {CRYPTO_MODE_HASH_SHA3_512, H_SHA3_512, HM_RAW, 0},
+ {CRYPTO_MODE_HASH_SHAKE128, H_SHAKE128, HM_SHAKE_SHAKE, 0},
+ {CRYPTO_MODE_HASH_SHAKE256, H_SHAKE256, HM_SHAKE_SHAKE, 0},
+ {CRYPTO_MODE_HASH_CSHAKE128, H_SHAKE128, HM_SHAKE_CSHAKE, 0},
+ {CRYPTO_MODE_HASH_CSHAKE256, H_SHAKE256, HM_SHAKE_CSHAKE, 0},
+ {CRYPTO_MODE_MAC_KMAC128, H_SHAKE128, HM_SHAKE_KMAC, 0},
+ {CRYPTO_MODE_MAC_KMAC256, H_SHAKE256, HM_SHAKE_KMAC, 0},
+ {CRYPTO_MODE_MAC_KMACXOF128, H_SHAKE128, HM_SHAKE_KMAC, 1},
+ {CRYPTO_MODE_MAC_KMACXOF256, H_SHAKE256, HM_SHAKE_KMAC, 1},
+ {CRYPTO_MODE_MAC_XCBC, H_XCBC, HM_RAW, 0},
+ {CRYPTO_MODE_MAC_CMAC, H_CMAC, HM_RAW, 0},
+ {CRYPTO_MODE_MAC_KASUMI_F9, H_KF9, HM_RAW, 0},
+ {CRYPTO_MODE_MAC_SNOW3G_UIA2, H_SNOW3G_UIA2, HM_RAW, 0},
+ {CRYPTO_MODE_MAC_ZUC_UIA3, H_ZUC_UIA3, HM_RAW, 0},
+ {CRYPTO_MODE_MAC_POLY1305, H_POLY1305, HM_RAW, 0},
+ {CRYPTO_MODE_HASH_CRC32, H_CRC32_I3E802_3, HM_RAW, 0},
+ {CRYPTO_MODE_MAC_MICHAEL, H_MICHAEL, HM_RAW, 0},
+ {CRYPTO_MODE_HASH_SM3, H_SM3, HM_RAW, 0},
+ {CRYPTO_MODE_HMAC_SM3, H_SM3, HM_HMAC, 0},
+ {CRYPTO_MODE_MAC_SM4_XCBC, H_SM4_XCBC_MAC, HM_RAW, 0},
+ {CRYPTO_MODE_MAC_SM4_CMAC, H_SM4_CMAC, HM_RAW, 0},
+};
+
+/* bits are 40, 64, 128, 192, 256, and top bit for hash */
+static const unsigned char template[] = {
+ [CRYPTO_MODE_NULL] = 0,
+ [CRYPTO_MODE_AES_ECB] = 28, /* AESECB 128/224/256 */
+ [CRYPTO_MODE_AES_CBC] = 28, /* AESCBC 128/224/256 */
+ [CRYPTO_MODE_AES_CTR] = 28, /* AESCTR 128/224/256 */
+ [CRYPTO_MODE_AES_CCM] = 28, /* AESCCM 128/224/256 */
+ [CRYPTO_MODE_AES_GCM] = 28, /* AESGCM 128/224/256 */
+ [CRYPTO_MODE_AES_F8] = 28, /* AESF8 128/224/256 */
+ [CRYPTO_MODE_AES_XTS] = 20, /* AESXTS 128/256 */
+ [CRYPTO_MODE_AES_CFB] = 28, /* AESCFB 128/224/256 */
+ [CRYPTO_MODE_AES_OFB] = 28, /* AESOFB 128/224/256 */
+ [CRYPTO_MODE_AES_CS1] = 28, /* AESCS1 128/224/256 */
+ [CRYPTO_MODE_AES_CS2] = 28, /* AESCS2 128/224/256 */
+ [CRYPTO_MODE_AES_CS3] = 28, /* AESCS3 128/224/256 */
+ [CRYPTO_MODE_MULTI2_ECB] = 0, /* MULTI2 */
+ [CRYPTO_MODE_MULTI2_CBC] = 0, /* MULTI2 */
+ [CRYPTO_MODE_MULTI2_OFB] = 0, /* MULTI2 */
+ [CRYPTO_MODE_MULTI2_CFB] = 0, /* MULTI2 */
+ [CRYPTO_MODE_3DES_CBC] = 8, /* 3DES CBC */
+ [CRYPTO_MODE_3DES_ECB] = 8, /* 3DES ECB */
+ [CRYPTO_MODE_DES_CBC] = 2, /* DES CBC */
+ [CRYPTO_MODE_DES_ECB] = 2, /* DES ECB */
+ [CRYPTO_MODE_KASUMI_ECB] = 4, /* KASUMI ECB */
+ [CRYPTO_MODE_KASUMI_F8] = 4, /* KASUMI F8 */
+ [CRYPTO_MODE_SNOW3G_UEA2] = 4, /* SNOW3G */
+ [CRYPTO_MODE_ZUC_UEA3] = 4, /* ZUC */
+ [CRYPTO_MODE_CHACHA20_STREAM] = 16, /* CHACHA20 */
+ [CRYPTO_MODE_CHACHA20_POLY1305] = 16, /* CHACHA20 */
+ [CRYPTO_MODE_SM4_ECB] = 4, /* SM4ECB 128 */
+ [CRYPTO_MODE_SM4_CBC] = 4, /* SM4CBC 128 */
+ [CRYPTO_MODE_SM4_CFB] = 4, /* SM4CFB 128 */
+ [CRYPTO_MODE_SM4_OFB] = 4, /* SM4OFB 128 */
+ [CRYPTO_MODE_SM4_CTR] = 4, /* SM4CTR 128 */
+ [CRYPTO_MODE_SM4_CCM] = 4, /* SM4CCM 128 */
+ [CRYPTO_MODE_SM4_GCM] = 4, /* SM4GCM 128 */
+ [CRYPTO_MODE_SM4_F8] = 4, /* SM4F8 128 */
+ [CRYPTO_MODE_SM4_XTS] = 4, /* SM4XTS 128 */
+ [CRYPTO_MODE_SM4_CS1] = 4, /* SM4CS1 128 */
+ [CRYPTO_MODE_SM4_CS2] = 4, /* SM4CS2 128 */
+ [CRYPTO_MODE_SM4_CS3] = 4, /* SM4CS3 128 */
+
+ [CRYPTO_MODE_HASH_MD5] = 242,
+ [CRYPTO_MODE_HMAC_MD5] = 242,
+ [CRYPTO_MODE_HASH_SHA1] = 242,
+ [CRYPTO_MODE_HMAC_SHA1] = 242,
+ [CRYPTO_MODE_HASH_SHA224] = 242,
+ [CRYPTO_MODE_HMAC_SHA224] = 242,
+ [CRYPTO_MODE_HASH_SHA256] = 242,
+ [CRYPTO_MODE_HMAC_SHA256] = 242,
+ [CRYPTO_MODE_HASH_SHA384] = 242,
+ [CRYPTO_MODE_HMAC_SHA384] = 242,
+ [CRYPTO_MODE_HASH_SHA512] = 242,
+ [CRYPTO_MODE_HMAC_SHA512] = 242,
+ [CRYPTO_MODE_HASH_SHA512_224] = 242,
+ [CRYPTO_MODE_HMAC_SHA512_224] = 242,
+ [CRYPTO_MODE_HASH_SHA512_256] = 242,
+ [CRYPTO_MODE_HMAC_SHA512_256] = 242,
+ [CRYPTO_MODE_MAC_XCBC] = 130, /* XCBC */
+ [CRYPTO_MODE_MAC_CMAC] = 154, /* CMAC */
+ [CRYPTO_MODE_MAC_KASUMI_F9] = 130, /* KASUMI */
+ [CRYPTO_MODE_MAC_SNOW3G_UIA2] = 130, /* SNOW */
+ [CRYPTO_MODE_MAC_ZUC_UIA3] = 130, /* ZUC */
+ [CRYPTO_MODE_MAC_POLY1305] = 144,
+ [CRYPTO_MODE_SSLMAC_MD5] = 130,
+ [CRYPTO_MODE_SSLMAC_SHA1] = 132,
+ [CRYPTO_MODE_HASH_CRC32] = 0,
+ [CRYPTO_MODE_MAC_MICHAEL] = 129,
+
+ [CRYPTO_MODE_HASH_SHA3_224] = 242,
+ [CRYPTO_MODE_HASH_SHA3_256] = 242,
+ [CRYPTO_MODE_HASH_SHA3_384] = 242,
+ [CRYPTO_MODE_HASH_SHA3_512] = 242,
+ [CRYPTO_MODE_HASH_SHAKE128] = 242,
+ [CRYPTO_MODE_HASH_SHAKE256] = 242,
+ [CRYPTO_MODE_HASH_CSHAKE128] = 130,
+ [CRYPTO_MODE_HASH_CSHAKE256] = 130,
+ [CRYPTO_MODE_MAC_KMAC128] = 242,
+ [CRYPTO_MODE_MAC_KMAC256] = 242,
+ [CRYPTO_MODE_MAC_KMACXOF128] = 242,
+ [CRYPTO_MODE_MAC_KMACXOF256] = 242,
+ [CRYPTO_MODE_HASH_SM3] = 242,
+ [CRYPTO_MODE_HMAC_SM3] = 242,
+ [CRYPTO_MODE_MAC_SM4_XCBC] = 130,
+ [CRYPTO_MODE_MAC_SM4_CMAC] = 130,
+};
+
+int spacc_sg_to_ddt(struct device *dev, struct scatterlist *sg,
+ int nbytes, struct pdu_ddt *ddt, int dma_direction)
+{
+ int i;
+ int nents;
+ int rc = 0;
+ int orig_nents;
+ struct scatterlist *sgl;
+ struct scatterlist *sg_entry;
+
+ /* Count the SG entries needed to cover the requested length. */
+ orig_nents = sg_nents_for_len(sg, nbytes);
+ if (orig_nents <= 0)
+ return orig_nents;
+
+ /*
+ * Ignore a trailing zero-length SG entry if present.
+ * Some callers use it as a terminator.
+ */
+ if (orig_nents > 1) {
+ sgl = sg_last(sg, orig_nents);
+ if (sgl->length == 0)
+ orig_nents--;
+ }
+
+ nents = dma_map_sg(dev, sg, orig_nents, dma_direction);
+ if (nents <= 0)
+ return -ENOMEM;
+
+ rc = pdu_ddt_init(dev, ddt, nents | 0x80000000);
+ if (rc < 0) {
+ dma_unmap_sg(dev, sg, orig_nents, dma_direction);
+ return -EIO;
+ }
+
+ /* Populate the descriptor table with the DMA-mapped SG entries. */
+ for_each_sg(sg, sg_entry, nents, i) {
+ pdu_ddt_add(dev, ddt, sg_dma_address(sg_entry),
+ sg_dma_len(sg_entry));
+ }
+
+ return orig_nents;
+}
+
+int spacc_set_operation(struct spacc_device *spacc, int handle, int op,
+ u32 prot, u32 icvcmd, u32 icvoff,
+ u32 icvsz, u32 sec_key)
+{
+ int ret = 0;
+ struct spacc_job *job = NULL;
+
+ if (handle < 0 || handle >= SPACC_MAX_JOBS)
+ return -EINVAL;
+
+ job = &spacc->job[handle];
+ if (!job)
+ return -EIO;
+
+ job->op = op;
+ if (op == OP_ENCRYPT)
+ job->ctrl |= SPACC_CTRL_MASK(SPACC_CTRL_ENCRYPT);
+ else
+ job->ctrl &= ~SPACC_CTRL_MASK(SPACC_CTRL_ENCRYPT);
+
+ switch (prot) {
+ case ICV_HASH:
+ /* HASH of plaintext */
+ job->ctrl |= SPACC_CTRL_MASK(SPACC_CTRL_ICV_PT);
+ break;
+ case ICV_HASH_ENCRYPT:
+ /*
+ * HASH the plaintext and encrypt the lot
+ * ICV_PT and ICV_APPEND must be set too
+ */
+ job->ctrl |= SPACC_CTRL_MASK(SPACC_CTRL_ICV_ENC);
+ job->ctrl |= SPACC_CTRL_MASK(SPACC_CTRL_ICV_PT);
+ /* this mode is not valid when BIT_ALIGN != 0 */
+ job->ctrl |= SPACC_CTRL_MASK(SPACC_CTRL_ICV_APPEND);
+ break;
+ case ICV_ENCRYPT_HASH:
+ /* HASH the ciphertext */
+ job->ctrl &= ~SPACC_CTRL_MASK(SPACC_CTRL_ICV_PT);
+ job->ctrl &= ~SPACC_CTRL_MASK(SPACC_CTRL_ICV_ENC);
+ break;
+ case ICV_IGNORE:
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ job->icv_len = icvsz;
+
+ switch (icvcmd) {
+ case IP_ICV_OFFSET:
+ job->icv_offset = icvoff;
+ job->ctrl &= ~SPACC_CTRL_MASK(SPACC_CTRL_ICV_APPEND);
+ break;
+ case IP_ICV_APPEND:
+ job->ctrl |= SPACC_CTRL_MASK(SPACC_CTRL_ICV_APPEND);
+ break;
+ case IP_ICV_IGNORE:
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (sec_key)
+ job->ctrl |= SPACC_CTRL_MASK(SPACC_CTRL_SEC_KEY);
+
+ return ret;
+}
+
+static int _spacc_fifo_full(struct spacc_device *spacc, uint32_t prio)
+{
+ if (spacc->config.is_qos)
+ return readl(spacc->regmap + SPACC_REG_FIFO_STAT) &
+ SPACC_FIFO_STAT_CMDX_FULL(prio);
+ else
+ return readl(spacc->regmap + SPACC_REG_FIFO_STAT) &
+ SPACC_FIFO_STAT_CMD0_FULL;
+}
+
+/*
+ * When proc_sz != 0 it overrides the ddt_len value
+ * defined in the context referenced by 'job_idx'
+ */
+int spacc_packet_enqueue_ddt_ex(struct spacc_device *spacc, int use_jb,
+ int job_idx, struct pdu_ddt *src_ddt,
+ struct pdu_ddt *dst_ddt, u32 proc_sz,
+ u32 aad_offset, u32 pre_aad_sz, u32 post_aad_sz,
+ u32 iv_offset, u32 prio,
+ unsigned long *lock_flag)
+{
+ int job_index;
+ int proc_len;
+ struct spacc_job *job;
+
+ if (job_idx < 0 || job_idx >= SPACC_MAX_JOBS)
+ return -EINVAL;
+
+ /*
+ * Handle priority jobs using cmd fifos, high priority
+ * defaults to cmd0 fifo, medium to cmd1 fifo and low
+ * to cmd2 fifo
+ */
+ switch (prio) {
+ case SPACC_SW_CTRL_PRIO_MED:
+ if (spacc->config.cmd1_fifo_depth == 0)
+ return -EINVAL;
+ break;
+ case SPACC_SW_CTRL_PRIO_LOW:
+ if (spacc->config.cmd2_fifo_depth == 0)
+ return -EINVAL;
+ break;
+ }
+
+ job = &spacc->job[job_idx];
+ if (!job)
+ return -EINVAL;
+
+ /* process any jobs in the jb */
+ if (use_jb && spacc_process_jb(spacc, lock_flag) != 0)
+ goto fifo_full;
+
+ if (_spacc_fifo_full(spacc, prio)) {
+ if (use_jb)
+ goto fifo_full;
+ else
+ return -EBUSY;
+ }
+
+ /*
+ * Compute the length we must process, in decrypt mode
+ * with an ICV (hash, hmac or CCM modes)
+ * we must subtract the icv length from the buffer size
+ */
+ if (proc_sz == SPACC_AUTO_SIZE) {
+ proc_len = src_ddt->len;
+
+ if (job->op == OP_DECRYPT &&
+ (job->hash_mode > 0 ||
+ job->enc_mode == CRYPTO_MODE_AES_CCM ||
+ job->enc_mode == CRYPTO_MODE_AES_GCM) &&
+ !(job->ctrl & SPACC_CTRL_MASK(SPACC_CTRL_ICV_ENC)))
+ proc_len = src_ddt->len - job->icv_len;
+ } else
+ proc_len = proc_sz;
+
+ if ((u32)(proc_len - job->post_aad_sz) > spacc->config.max_msg_size)
+ return -EMSGSIZE;
+
+ if (pre_aad_sz & SPACC_AADCOPY_FLAG) {
+ job->ctrl |= SPACC_CTRL_MASK(SPACC_CTRL_AAD_COPY);
+ pre_aad_sz &= ~(SPACC_AADCOPY_FLAG);
+ } else
+ job->ctrl &= ~SPACC_CTRL_MASK(SPACC_CTRL_AAD_COPY);
+
+ job->pre_aad_sz = pre_aad_sz;
+ job->post_aad_sz = post_aad_sz;
+
+ if (spacc->config.dma_type == SPACC_DMA_DDT) {
+ pdu_io_cached_write(spacc->dptr, spacc->regmap +
+ SPACC_REG_SRC_PTR, (uint32_t)src_ddt->phys,
+ &spacc->cache.src_ptr);
+ pdu_io_cached_write(spacc->dptr, spacc->regmap +
+ SPACC_REG_DST_PTR, (uint32_t)dst_ddt->phys,
+ &spacc->cache.dst_ptr);
+ } else if (spacc->config.dma_type == SPACC_DMA_LINEAR) {
+ if (src_ddt->idx != 1 || dst_ddt->idx != 1)
+ return -EINVAL;
+
+ pdu_io_cached_write(spacc->dptr, spacc->regmap +
+ SPACC_REG_SRC_PTR,
+ (uint32_t)src_ddt->virt[0],
+ &spacc->cache.src_ptr);
+ pdu_io_cached_write(spacc->dptr, spacc->regmap +
+ SPACC_REG_DST_PTR,
+ (uint32_t)dst_ddt->virt[0],
+ &spacc->cache.dst_ptr);
+ } else
+ return -EIO;
+
+ pdu_io_cached_write(spacc->dptr, spacc->regmap + SPACC_REG_PROC_LEN,
+ proc_len - job->post_aad_sz,
+ &spacc->cache.proc_len);
+ pdu_io_cached_write(spacc->dptr, spacc->regmap + SPACC_REG_ICV_LEN,
+ job->icv_len, &spacc->cache.icv_len);
+ pdu_io_cached_write(spacc->dptr, spacc->regmap + SPACC_REG_ICV_OFFSET,
+ job->icv_offset, &spacc->cache.icv_offset);
+ pdu_io_cached_write(spacc->dptr, spacc->regmap + SPACC_REG_PRE_AAD_LEN,
+ job->pre_aad_sz, &spacc->cache.pre_aad);
+ pdu_io_cached_write(spacc->dptr, spacc->regmap + SPACC_REG_POST_AAD_LEN,
+ job->post_aad_sz, &spacc->cache.post_aad);
+ pdu_io_cached_write(spacc->dptr, spacc->regmap + SPACC_REG_IV_OFFSET,
+ iv_offset, &spacc->cache.iv_offset);
+ pdu_io_cached_write(spacc->dptr, spacc->regmap + SPACC_REG_OFFSET,
+ aad_offset, &spacc->cache.offset);
+ pdu_io_cached_write(spacc->dptr, spacc->regmap + SPACC_REG_AUX_INFO,
+ AUX_DIR(job->auxinfo_dir) |
+ AUX_BIT_ALIGN(job->auxinfo_bit_align) |
+ AUX_CBC_CS(job->auxinfo_cs_mode),
+ &spacc->cache.aux);
+
+ if (job->first_use) {
+ writel(job->ckey_sz | SPACC_SET_KEY_CTX(job->ctx_idx),
+ spacc->regmap + SPACC_REG_KEY_SZ);
+ writel(job->hkey_sz | SPACC_SET_KEY_CTX(job->ctx_idx),
+ spacc->regmap + SPACC_REG_KEY_SZ);
+ }
+
+ {
+ unsigned int swid = spacc->job_next_swid;
+ unsigned int tries;
+
+ for (tries = 0; tries < SPACC_MAX_JOBS; tries++) {
+ if (spacc->job_lookup[swid] == SPACC_JOB_IDX_UNUSED)
+ break;
+ swid = (swid + 1) % SPACC_MAX_JOBS;
+ }
+
+ if (tries == SPACC_MAX_JOBS) {
+ /*
+ * Should be unreachable given the job_idx
+ * allocator's own bound; fail loudly rather than
+ * silently corrupting tracking if it ever isn't.
+ */
+ return -EBUSY;
+ }
+
+ job->job_swid = swid;
+ spacc->job_lookup[swid] = job_idx;
+ spacc->job_next_swid = (swid + 1) % SPACC_MAX_JOBS;
+ }
+
+ writel(SPACC_SW_CTRL_ID_SET(job->job_swid) |
+ SPACC_SW_CTRL_PRIO_SET(prio),
+ spacc->regmap + SPACC_REG_SW_CTRL);
+ writel(job->ctrl, spacc->regmap + SPACC_REG_CTRL);
+
+ /* clear an expansion key after the first call */
+ if (job->first_use) {
+ job->first_use = false;
+ job->ctrl &= ~SPACC_CTRL_MASK(SPACC_CTRL_KEY_EXP);
+ }
+
+ return 0;
+
+fifo_full:
+ job_index = spacc->jb_head + 1;
+ if (job_index == SPACC_MAX_JOB_BUFFERS)
+ job_index = 0;
+
+ if (job_index == spacc->jb_tail)
+ return -EBUSY;
+
+ spacc->job_buffer[spacc->jb_head] = (struct spacc_job_buffer) {
+ .active = 1,
+ .job_idx = job_idx,
+ .src = src_ddt,
+ .dst = dst_ddt,
+ .proc_sz = proc_sz,
+ .aad_offset = aad_offset,
+ .pre_aad_sz = pre_aad_sz,
+ .post_aad_sz = post_aad_sz,
+ .iv_offset = iv_offset,
+ .prio = prio
+ };
+
+ spacc->jb_head = job_index;
+
+ return 0;
+}
+
+int spacc_packet_enqueue_ddt(struct spacc_device *spacc, int job_idx,
+ struct pdu_ddt *src_ddt, struct pdu_ddt *dst_ddt,
+ u32 proc_sz, u32 aad_offset, u32 pre_aad_sz,
+ u32 post_aad_sz, u32 iv_offset, u32 prio)
+{
+ int ret = 0;
+ unsigned long lock_flags;
+
+ spin_lock_irqsave(&spacc->lock, lock_flags);
+ ret = spacc_packet_enqueue_ddt_ex(spacc, 1, job_idx, src_ddt,
+ dst_ddt, proc_sz, aad_offset,
+ pre_aad_sz, post_aad_sz,
+ iv_offset, prio, &lock_flags);
+ spin_unlock_irqrestore(&spacc->lock, lock_flags);
+
+ return ret;
+}
+
+/*
+ * Plain hashes, HMAC and KMAC/cSHAKE accept arbitrary key lengths, so
+ * they keep the bit-7 "any size" fast path. The block-cipher MAC modes
+ * have a fixed key size that must be validated against the (autodetected)
+ * capability bits. Add other keyed cipher-MAC modes here once their valid
+ * key sizes are confirmed.
+ */
+static bool spacc_mode_has_fixed_keysize(int mode)
+{
+ switch (mode) {
+ case CRYPTO_MODE_MAC_CMAC:
+ case CRYPTO_MODE_MAC_XCBC:
+ case CRYPTO_MODE_MAC_SM4_CMAC:
+ case CRYPTO_MODE_MAC_SM4_XCBC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Check if the keysize is supported for the input mode */
+int spacc_is_mode_keysize_supported(struct spacc_device *spacc, int mode,
+ int keysize, int keysz_index)
+{
+ int x;
+
+ if (mode < 0 || mode >= CRYPTO_MODE_LAST)
+ return SPACC_MODE_NOT_SUPPORTED;
+
+ if (mode == CRYPTO_MODE_NULL ||
+ ((spacc->config.modes[mode] & 128) &&
+ !spacc_mode_has_fixed_keysize(mode)))
+ return SPACC_MODE_SUPPORTED;
+
+ /* loop through and check for valid keysizes */
+ for (x = 0; x < 6; x++) {
+ if (keysizes[keysz_index][x] == keysize) {
+ if (spacc->config.modes[mode] & (1 << x))
+ return SPACC_MODE_SUPPORTED;
+ else
+ return SPACC_MODE_NOT_SUPPORTED;
+ }
+ }
+
+ return SPACC_MODE_NOT_SUPPORTED;
+}
+
+/* releases a crypto context back into appropriate module's pool */
+int spacc_close(struct spacc_device *dev, int handle)
+{
+ return spacc_job_release(dev, handle);
+}
+
+static void spacc_static_modes(struct spacc_device *spacc, int x, int y)
+{
+ /* disable the algos that are not supported here */
+ switch (x) {
+ case CRYPTO_MODE_AES_F8:
+ case CRYPTO_MODE_AES_CFB:
+ case CRYPTO_MODE_AES_OFB:
+ case CRYPTO_MODE_MULTI2_ECB:
+ case CRYPTO_MODE_MULTI2_CBC:
+ case CRYPTO_MODE_MULTI2_CFB:
+ case CRYPTO_MODE_MULTI2_OFB:
+ case CRYPTO_MODE_MAC_POLY1305:
+ case CRYPTO_MODE_HASH_CRC32:
+ /* disable the modes */
+ spacc->config.modes[x] &= ~(1 << y);
+ break;
+ default:
+ break; /* algos are enabled */
+ }
+}
+
+int spacc_static_config(struct spacc_device *spacc)
+{
+ int x, y;
+
+ for (x = 0; x < ARRAY_SIZE(template); x++) {
+ spacc->config.modes[x] = template[x];
+
+ for (y = 0; y < (ARRAY_SIZE(keysizes[0])); y++) {
+ /* list static modes */
+ spacc_static_modes(spacc, x, y);
+ }
+ }
+
+ return 0;
+}
+
+int spacc_clone_handle(struct spacc_device *spacc, int old_handle,
+ void *cbdata)
+{
+ int new_handle;
+ wait_queue_head_t saved_waitq;
+
+ new_handle = spacc_job_request(spacc, spacc->job[old_handle].ctx_idx);
+ if (new_handle < 0)
+ return new_handle;
+
+ /*
+ * Struct copy is safe here except for the embedded waitq -
+ * copying a wait_queue_head_t corrupts internal spinlock and
+ * list_head pointers. Save and restore it around the copy.
+ */
+ saved_waitq = spacc->job[new_handle].waitq;
+ spacc->job[new_handle] = spacc->job[old_handle];
+ spacc->job[new_handle].waitq = saved_waitq;
+ spacc->job[new_handle].job_used = new_handle;
+ spacc->job[new_handle].cbdata = cbdata;
+
+ return new_handle;
+}
+
+/*
+ * Allocate a job for spacc module context and initialize
+ * it with an appropriate type.
+ */
+int spacc_open(struct spacc_device *spacc, int enc, int hash, int ctxid,
+ int secure_mode, spacc_callback cb, void *cbdata)
+{
+ size_t i;
+ int ret = 0;
+ u32 ctrl = 0;
+ int job_idx = 0;
+ struct spacc_job *job = NULL;
+ const struct enc_config *enc_cfg = NULL;
+ const struct hash_config *hash_cfg = NULL;
+ unsigned long flags;
+
+ if (ctxid == -1) {
+ if (down_trylock(&spacc->ctx_sem)) {
+ dev_dbg(spacc->dptr, "No free HW context, fallback\n");
+ return -EBUSY;
+ }
+ }
+
+ spin_lock_irqsave(&spacc->ctx_lock, flags);
+ job_idx = spacc_job_request(spacc, ctxid);
+
+ if (job_idx < 0) {
+ spin_unlock_irqrestore(&spacc->ctx_lock, flags);
+ dev_dbg(spacc->dptr, "Failed to acquire context\n");
+ ret = -EIO;
+ goto err_release_sem;
+ }
+
+ job = &spacc->job[job_idx];
+
+ spin_unlock_irqrestore(&spacc->ctx_lock, flags);
+
+ if (secure_mode && job->ctx_idx > spacc->config.num_sec_ctx) {
+ dev_dbg(spacc->dptr, "ERR: For secure contexts\n");
+ dev_dbg(spacc->dptr,
+ "ERR: Job ctx ID is outside allowed range\n");
+ ret = -EIO;
+ goto err_release_job;
+ }
+
+ job->auxinfo_cs_mode = 0;
+ job->auxinfo_bit_align = 0;
+ job->auxinfo_dir = 0;
+ job->icv_len = 0;
+
+ /* Process encryption mode using the lookup table */
+ for (i = 0; i < ARRAY_SIZE(enc_table); ++i) {
+ if (enc == enc_table[i].mode) {
+ enc_cfg = &enc_table[i];
+ ctrl |= SPACC_CTRL_SET(SPACC_CTRL_CIPH_ALG,
+ enc_cfg->cipher_alg);
+ ctrl |= SPACC_CTRL_SET(SPACC_CTRL_CIPH_MODE,
+ enc_cfg->cipher_mode);
+ job->auxinfo_cs_mode = enc_cfg->auxinfo_cs_mode;
+ break;
+ }
+ }
+
+ if (enc != CRYPTO_MODE_NULL && !enc_cfg) {
+ ret = -EOPNOTSUPP;
+ goto err_release_job;
+ }
+
+ /* Process hash mode using the lookup table */
+ for (i = 0; i < ARRAY_SIZE(hash_table); ++i) {
+ if (hash == hash_table[i].mode) {
+ hash_cfg = &hash_table[i];
+ ctrl |= SPACC_CTRL_SET(SPACC_CTRL_HASH_ALG,
+ hash_cfg->hash_alg);
+ ctrl |= SPACC_CTRL_SET(SPACC_CTRL_HASH_MODE,
+ hash_cfg->hash_mode);
+ job->auxinfo_dir = hash_cfg->auxinfo_dir;
+ break;
+ }
+ }
+
+ if (hash != CRYPTO_MODE_NULL && !hash_cfg) {
+ ret = -EOPNOTSUPP;
+ goto err_release_job;
+ }
+
+ ctrl |= SPACC_CTRL_MASK(SPACC_CTRL_MSG_BEGIN) |
+ SPACC_CTRL_MASK(SPACC_CTRL_MSG_END);
+
+ /* Success path */
+ job->first_use = true;
+ job->enc_mode = enc;
+ job->hash_mode = hash;
+ job->ckey_sz = 0;
+ job->hkey_sz = 0;
+ job->job_done = 0;
+ job->job_swid = 0;
+ job->job_secure = !!secure_mode;
+ job->auxinfo_bit_align = 0;
+ job->job_err = -EINPROGRESS;
+ job->ctrl = ctrl | SPACC_CTRL_SET(SPACC_CTRL_CTX_IDX,
+ job->ctx_idx);
+ job->cb = cb;
+ job->cbdata = cbdata;
+
+ return job_idx;
+
+err_release_job:
+ /*
+ * spacc_job_release() -> spacc_ctx_release() already ups
+ * ctx_sem once the context's ref_cnt drops to zero, so we
+ * must NOT fall through into another up() below.
+ */
+ spacc_job_release(spacc, job_idx);
+ return ret;
+
+err_release_sem:
+ /*
+ * We only reach here without having allocated a context, so
+ * only undo the down_interruptible() above -- and only if we
+ * actually did one, i.e. ctxid == -1.
+ */
+ if (ctxid == -1)
+ up(&spacc->ctx_sem);
+
+ return ret;
+}
+
+/* Helper function to wait for job completion and check results */
+static bool spacc_wait_for_job_completion(struct spacc_device *spacc,
+ void *virt, unsigned char *expected_md)
+{
+ int stat;
+ u32 rbuf;
+
+ /*
+ * Poll until the status FIFO is non-empty, checking every 10us
+ * and giving up after 10ms. A bare count loop without delays
+ * exits in ~4us - far too fast for any real crypto operation.
+ */
+ if (readl_poll_timeout(spacc->regmap + SPACC_REG_FIFO_STAT, rbuf,
+ !(rbuf & SPACC_FIFO_STAT_STAT_EMPTY),
+ 10, 10000))
+ return false;
+
+ /* Pop the completed job and check its return code */
+ writel(1, spacc->regmap + SPACC_REG_STAT_POP);
+ rbuf = readl(spacc->regmap + SPACC_REG_STATUS);
+ stat = SPACC_GET_STATUS_RET_CODE(rbuf);
+
+ return (memcmp(virt, expected_md, 16) == 0) && (stat == SPACC_OK);
+}
+
+static int spacc_xof_stringsize_autodetect(struct spacc_device *spacc)
+{
+ void *virt;
+ int ss, alg;
+ dma_addr_t dma;
+ struct pdu_ddt ddt;
+ unsigned long buflen;
+ unsigned char *buf;
+ unsigned long spacc_ctrl[2] = {0xF400B400, 0xF400D400};
+ unsigned char test_str[6] = {0x01, 0x20, 0x54, 0x45, 0x53, 0x54};
+ unsigned char md[2][16] = {
+ {0xc3, 0x6d, 0x0a, 0x88, 0xfa, 0x37, 0x4c, 0x9b,
+ 0x44, 0x74, 0xeb, 0x00, 0x5f, 0xe8, 0xca, 0x25},
+ {0x68, 0x77, 0x04, 0x11, 0xf8, 0xe3, 0xb0, 0x1e,
+ 0x0d, 0xbf, 0x71, 0x6a, 0xe9, 0x87, 0x1a, 0x0d}};
+
+ buf = kzalloc(spacc->config.hash_page_size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ virt = dma_alloc_coherent(spacc->dptr, SPACC_TEST_DMA_BUFF_SIZE,
+ &dma, GFP_KERNEL);
+ if (!virt) {
+ kfree(buf);
+ return -EIO;
+ }
+
+ if (pdu_ddt_init(spacc->dptr, &ddt, 1)) {
+ kfree(buf);
+ dma_free_coherent(spacc->dptr, SPACC_TEST_DMA_BUFF_SIZE,
+ virt, dma);
+ return -EIO;
+ }
+
+ pdu_ddt_add(spacc->dptr, &ddt, dma, SPACC_TEST_DMA_BUFF_SIZE);
+
+ /* populate registers for jobs */
+ writel((uint32_t)ddt.phys, spacc->regmap + SPACC_REG_SRC_PTR);
+ writel((uint32_t)ddt.phys, spacc->regmap + SPACC_REG_DST_PTR);
+
+ writel(16, spacc->regmap + SPACC_REG_PROC_LEN);
+ writel(16, spacc->regmap + SPACC_REG_PRE_AAD_LEN);
+ writel(16, spacc->regmap + SPACC_REG_ICV_LEN);
+ writel(6, spacc->regmap + SPACC_REG_KEY_SZ);
+ writel(0, spacc->regmap + SPACC_REG_SW_CTRL);
+
+ /* repeat for 2 algorithms, CSHAKE128 and KMAC128 */
+ for (alg = 0; (alg < 2) && (spacc->config.string_size == 0); alg++) {
+ /* repeat for 4 string_size sizes */
+ for (ss = 0; ss < 4; ss++) {
+ buflen = (32UL << ss);
+ if (buflen > spacc->config.hash_page_size)
+ break;
+
+ /* clear I/O memory */
+ memset(virt, 0, SPACC_TEST_DMA_BUFF_SIZE);
+
+ /* clear buf and then insert test string */
+ memset(buf, 0, spacc->config.hash_page_size);
+ memcpy(buf, test_str, sizeof(test_str));
+ memcpy(buf + (buflen >> 1), test_str, sizeof(test_str));
+
+ /* write key context */
+ pdu_to_dev_s(spacc->regmap + SPACC_CTX_HASH_KEY, buf,
+ spacc->config.hash_page_size >> 2);
+
+ /* write ctrl register */
+ writel(spacc_ctrl[alg], spacc->regmap + SPACC_REG_CTRL);
+
+ /* wait for job to complete */
+ if (spacc_wait_for_job_completion(spacc, virt, md[alg]))
+ spacc->config.string_size = (16 << ss);
+ }
+ }
+
+ /* reset registers */
+ writel(0, spacc->regmap + SPACC_REG_IRQ_CTRL);
+ writel(0, spacc->regmap + SPACC_REG_IRQ_EN);
+ writel(0xFFFFFFFF, spacc->regmap + SPACC_REG_IRQ_STAT);
+
+ writel(0, spacc->regmap + SPACC_REG_SRC_PTR);
+ writel(0, spacc->regmap + SPACC_REG_DST_PTR);
+ writel(0, spacc->regmap + SPACC_REG_PROC_LEN);
+ writel(0, spacc->regmap + SPACC_REG_ICV_LEN);
+ writel(0, spacc->regmap + SPACC_REG_PRE_AAD_LEN);
+
+ kfree(buf);
+ pdu_ddt_free(&ddt);
+ dma_free_coherent(spacc->dptr, SPACC_TEST_DMA_BUFF_SIZE,
+ virt, dma);
+
+ return 0;
+}
+
+/* free up the memory */
+void spacc_fini(struct spacc_device *spacc)
+{
+ vfree(spacc->ctx);
+ vfree(spacc->job);
+}
+
+int spacc_init(void __iomem *baseaddr, struct spacc_device *spacc,
+ struct pdu_info *info, struct device *dev)
+{
+#ifdef CONFIG_CRYPTO_DEV_SPACC_CONFIG_DEBUG
+ unsigned long id;
+ char version_string[3][16] = { "SPACC", "SPACC-PDU" };
+ char idx_string[2][16] = { "(Normal Port)", "(Secure Port)" };
+ char dma_type_string[4][16] = { "Unknown", "Scattergather", "Linear",
+ "Unknown" };
+#endif
+
+ memset(spacc, 0, sizeof(*spacc));
+
+ /*
+ * Must be set before anything below that touches spacc->dptr --
+ * e.g. spacc_xof_stringsize_autodetect() further down in this
+ * function does DMA allocation using it. The memset() above wipes
+ * out whatever the caller may have set on spacc->dptr already, so
+ * this can't rely on being pre-set by spacc_device.c; it has to be
+ * passed in and set here, after the memset, every time.
+ */
+ spacc->dptr = dev;
+
+ spin_lock_init(&spacc->lock);
+ spin_lock_init(&spacc->ctx_lock);
+
+ /* assign the baseaddr */
+ spacc->regmap = baseaddr;
+
+ /* version info */
+ spacc->config.version = info->spacc_version.version;
+ spacc->config.pdu_version = (info->pdu_config.major << 4) |
+ info->pdu_config.minor;
+ spacc->config.project = info->spacc_version.project;
+ spacc->config.is_pdu = info->spacc_version.is_pdu;
+ spacc->config.is_qos = info->spacc_version.qos;
+
+ /* misc */
+ spacc->config.is_partial = info->spacc_version.partial;
+ spacc->config.num_ctx = info->spacc_config.num_ctx;
+
+ /*
+ * Initialize the counting semaphore. The count is set to the number
+ * of hardware contexts available, allowing that many "threads" to
+ * acquire a context before subsequent ones will sleep.
+ */
+ sema_init(&spacc->ctx_sem, spacc->config.num_ctx);
+
+ spacc->config.ciph_page_size = 1U <<
+ info->spacc_config.ciph_ctx_page_size;
+
+ spacc->config.hash_page_size = 1U <<
+ info->spacc_config.hash_ctx_page_size;
+
+ spacc->config.dma_type = info->spacc_config.dma_type;
+ spacc->config.idx = info->spacc_version.vspacc_id;
+ spacc->config.cmd0_fifo_depth = info->spacc_config.cmd0_fifo_depth;
+ spacc->config.cmd1_fifo_depth = info->spacc_config.cmd1_fifo_depth;
+ spacc->config.cmd2_fifo_depth = info->spacc_config.cmd2_fifo_depth;
+ spacc->config.stat_fifo_depth = info->spacc_config.stat_fifo_depth;
+ spacc->config.fifo_cnt = 1;
+ spacc->config.is_ivimport = info->spacc_version.ivimport;
+ spacc->wd_cnt_limit = false;
+
+ /* ctrl register map */
+ if (spacc->config.version <= 0x4E)
+ spacc->config.ctrl_map = spacc_ctrl_map[SPACC_CTRL_VER_0];
+ else if (spacc->config.version <= 0x60)
+ spacc->config.ctrl_map = spacc_ctrl_map[SPACC_CTRL_VER_1];
+ else
+ spacc->config.ctrl_map = spacc_ctrl_map[SPACC_CTRL_VER_2];
+
+ spacc->job_next_swid = 0;
+ spacc->wdcnt = 0;
+ spacc->config.wd_timer = SPACC_WD_TIMER_INIT;
+
+ /*
+ * Version 4.10 uses IRQ,
+ * above uses WD and we don't support below 4.00
+ */
+ if (spacc->config.version < 0x40) {
+ dev_dbg(spacc->dptr, "ERR: Unsupported SPAcc version\n");
+ return -EIO;
+ } else if (spacc->config.version < 0x4B)
+ spacc->op_mode = SPACC_OP_MODE_IRQ;
+ else
+ spacc->op_mode = SPACC_OP_MODE_WD;
+
+ /*
+ * Set threshold and enable irq
+ * on 4.11 and newer cores we can derive this
+ * from the HW reported depths.
+ */
+ if (spacc->config.stat_fifo_depth == 1)
+ spacc->config.ideal_stat_level = 1;
+ else if (spacc->config.stat_fifo_depth <= 4)
+ spacc->config.ideal_stat_level =
+ spacc->config.stat_fifo_depth - 1;
+ else if (spacc->config.stat_fifo_depth <= 8)
+ spacc->config.ideal_stat_level =
+ spacc->config.stat_fifo_depth - 2;
+ else
+ spacc->config.ideal_stat_level =
+ spacc->config.stat_fifo_depth - 4;
+
+ /* determine max proclen value */
+ writel(0xFFFFFFFF, spacc->regmap + SPACC_REG_PROC_LEN);
+ spacc->config.max_msg_size = readl(spacc->regmap + SPACC_REG_PROC_LEN);
+
+#ifdef CONFIG_CRYPTO_DEV_SPACC_CONFIG_DEBUG
+
+ /* read config info */
+ if (spacc->config.is_pdu) {
+ dev_dbg(spacc->dptr, "PDU:\n");
+ dev_dbg(spacc->dptr,
+ " MAJOR : %u\n", info->pdu_config.major);
+ dev_dbg(spacc->dptr,
+ " MINOR : %u\n", info->pdu_config.minor);
+ }
+
+ id = readl(spacc->regmap + SPACC_REG_ID);
+ dev_dbg(spacc->dptr, "SPACC ID: (%08lx)\n", (unsigned long)id);
+ dev_dbg(spacc->dptr, " MAJOR : %x\n", info->spacc_version.major);
+ dev_dbg(spacc->dptr, " MINOR : %x\n", info->spacc_version.minor);
+ dev_dbg(spacc->dptr, " QOS : %x\n", info->spacc_version.qos);
+ dev_dbg(spacc->dptr, " IVIMPORT : %x\n", spacc->config.is_ivimport);
+
+ if (spacc->config.version >= 0x48)
+ dev_dbg(spacc->dptr,
+ " TYPE : %lx (%s)\n", SPACC_ID_TYPE(id),
+ version_string[SPACC_ID_TYPE(id) & 3]);
+
+ dev_dbg(spacc->dptr, " AUX : %x\n", info->spacc_version.qos);
+ dev_dbg(spacc->dptr, " IDX : %lx %s\n", SPACC_ID_VIDX(id),
+ spacc->config.is_secure ?
+ (idx_string[spacc->config.is_secure_port & 1]) : "");
+ dev_dbg(spacc->dptr,
+ " PARTIAL : %x\n", info->spacc_version.partial);
+ dev_dbg(spacc->dptr,
+ " PROJECT : %x\n", info->spacc_version.project);
+
+ if (spacc->config.version >= 0x48)
+ id = readl(spacc->regmap + SPACC_REG_CONFIG);
+ else
+ id = 0xFFFFFFFF;
+
+ dev_dbg(spacc->dptr, "SPACC CFG: (%08lx)\n", id);
+ dev_dbg(spacc->dptr, " CTX CNT : %u\n", info->spacc_config.num_ctx);
+ dev_dbg(spacc->dptr,
+ " VSPACC CNT : %u\n", info->spacc_config.num_vspacc);
+ dev_dbg(spacc->dptr, " CIPH SZ : %-3lu bytes\n", 1UL <<
+ info->spacc_config.ciph_ctx_page_size);
+ dev_dbg(spacc->dptr, " HASH SZ : %-3lu bytes\n", 1UL <<
+ info->spacc_config.hash_ctx_page_size);
+ dev_dbg(spacc->dptr,
+ " DMA TYPE : %u (%s)\n", info->spacc_config.dma_type,
+ dma_type_string[info->spacc_config.dma_type & 3]);
+ dev_dbg(spacc->dptr, " MAX PROCLEN: %lu bytes\n", (unsigned long)
+ spacc->config.max_msg_size);
+ dev_dbg(spacc->dptr, " FIFO CONFIG :\n");
+ dev_dbg(spacc->dptr, "CMD0 DEPTH: %d\n", spacc->config.cmd0_fifo_depth);
+
+ if (spacc->config.is_qos) {
+ dev_dbg(spacc->dptr, " CMD1 DEPTH: %d\n",
+ spacc->config.cmd1_fifo_depth);
+ dev_dbg(spacc->dptr, " CMD2 DEPTH: %d\n",
+ spacc->config.cmd2_fifo_depth);
+ }
+ dev_dbg(spacc->dptr, "STAT DEPTH: %d\n", spacc->config.stat_fifo_depth);
+
+ if (spacc->config.dma_type == SPACC_DMA_DDT) {
+ writel(0x1234567F, baseaddr + SPACC_REG_DST_PTR);
+ writel(0xDEADBEEF, baseaddr + SPACC_REG_SRC_PTR);
+
+ if (((readl(baseaddr + SPACC_REG_DST_PTR)) !=
+ (0x1234567F & SPACC_DST_PTR_PTR)) ||
+ ((readl(baseaddr + SPACC_REG_SRC_PTR)) !=
+ (0xDEADBEEF & SPACC_SRC_PTR_PTR))) {
+ dev_dbg(spacc->dptr, "ERR: Failed to set pointers\n");
+ goto ERR;
+ }
+ }
+#endif
+
+ /*
+ * Zero the IRQ CTRL/EN register
+ * (to make sure we're in a sane state)
+ */
+ writel(0, spacc->regmap + SPACC_REG_IRQ_CTRL);
+ writel(0, spacc->regmap + SPACC_REG_IRQ_EN);
+ writel(0xFFFFFFFF, spacc->regmap + SPACC_REG_IRQ_STAT);
+
+ /* init cache */
+ memset(&spacc->cache, 0, sizeof(spacc->cache));
+ writel(0, spacc->regmap + SPACC_REG_SRC_PTR);
+ writel(0, spacc->regmap + SPACC_REG_DST_PTR);
+ writel(0, spacc->regmap + SPACC_REG_PROC_LEN);
+ writel(0, spacc->regmap + SPACC_REG_ICV_LEN);
+ writel(0, spacc->regmap + SPACC_REG_ICV_OFFSET);
+ writel(0, spacc->regmap + SPACC_REG_PRE_AAD_LEN);
+ writel(0, spacc->regmap + SPACC_REG_POST_AAD_LEN);
+ writel(0, spacc->regmap + SPACC_REG_IV_OFFSET);
+ writel(0, spacc->regmap + SPACC_REG_OFFSET);
+ writel(0, spacc->regmap + SPACC_REG_AUX_INFO);
+
+ spacc->ctx = vmalloc(sizeof(struct spacc_ctx) * spacc->config.num_ctx);
+ if (!spacc->ctx)
+ goto ERR;
+
+ spacc->job = vmalloc(sizeof(struct spacc_job) * SPACC_MAX_JOBS);
+ if (!spacc->job)
+ goto ERR;
+
+ /* initialize job_idx and lookup table */
+ spacc_job_init_all(spacc);
+
+ /* initialize contexts */
+ spacc_ctx_init_all(spacc);
+
+ /* autodetect and set string size setting */
+ if (spacc->config.version == 0x61 || spacc->config.version >= 0x65)
+ spacc_xof_stringsize_autodetect(spacc);
+
+ return 0;
+ERR:
+ spacc_fini(spacc);
+ dev_dbg(spacc->dptr, "ERR: Crypto Failed\n");
+
+ return -EIO;
+}
+
+/* callback function to initialize workqueue running */
+void spacc_pop_jobs(struct work_struct *data)
+{
+ int num = 0;
+ struct spacc_priv *priv = container_of(data, struct spacc_priv,
+ pop_jobs);
+ struct spacc_device *spacc = &priv->spacc;
+ unsigned long lock_flag;
+
+ /*
+ * Decrement the WD CNT here since
+ * now we're actually going to respond
+ * to the IRQ completely
+ * (under spacc->lock -- spacc_process_irq() increments/resets
+ * this same counter under the same lock from IRQ context)
+ */
+ spin_lock_irqsave(&spacc->lock, lock_flag);
+ if (spacc->wdcnt)
+ --(spacc->wdcnt);
+ spin_unlock_irqrestore(&spacc->lock, lock_flag);
+
+ spacc_pop_packets(spacc, &num);
+}
+
+int spacc_remove(struct platform_device *pdev)
+{
+ struct spacc_device *spacc;
+ struct spacc_priv *priv = platform_get_drvdata(pdev);
+
+ /* free test vector memory */
+ spacc = &priv->spacc;
+ spacc_fini(spacc);
+
+ /* devm functions do proper cleanup */
+ pdu_mem_deinit(&pdev->dev);
+
+ return 0;
+}
+
+int spacc_set_key_exp(struct spacc_device *spacc, int job_idx)
+{
+ struct spacc_ctx *ctx = NULL;
+ struct spacc_job *job = NULL;
+
+ if (job_idx < 0 || job_idx >= SPACC_MAX_JOBS) {
+ dev_dbg(spacc->dptr,
+ "ERR: Invalid Job id specified (out of range)\n");
+ return -EINVAL;
+ }
+
+ job = &spacc->job[job_idx];
+ ctx = spacc_context_lookup_by_job(spacc, job_idx);
+
+ if (!ctx) {
+ dev_dbg(spacc->dptr, "ERR: Failed to find ctx id\n");
+ return -EIO;
+ }
+
+ job->ctrl |= SPACC_CTRL_MASK(SPACC_CTRL_KEY_EXP);
+
+ return 0;
+}
+
+int spacc_compute_xcbc_key(struct spacc_device *spacc, int mode_id,
+ int job_idx, const unsigned char *key,
+ int keylen, unsigned char *xcbc_out)
+{
+ int i;
+ int usecbc;
+ int handle;
+ int err = 0;
+ int ctx_idx;
+ unsigned char *buf;
+ dma_addr_t bufphys;
+ struct pdu_ddt ddt;
+ unsigned char iv[16];
+ struct spacc_job *job;
+
+ if (job_idx >= 0 && job_idx < SPACC_MAX_JOBS)
+ ctx_idx = spacc->job[job_idx].ctx_idx;
+ else
+ ctx_idx = -1;
+
+ if (mode_id == CRYPTO_MODE_MAC_XCBC) {
+ /* figure out if we can schedule the key */
+ if (spacc_is_mode_keysize_supported(spacc, CRYPTO_MODE_AES_ECB,
+ 16, 0))
+ usecbc = 0;
+ else if (spacc_is_mode_keysize_supported(spacc,
+ CRYPTO_MODE_AES_CBC,
+ 16, 0))
+ usecbc = 1;
+ else
+ return -EINVAL;
+ } else if (mode_id == CRYPTO_MODE_MAC_SM4_XCBC) {
+ /* figure out if we can schedule the key */
+ if (spacc_is_mode_keysize_supported(spacc, CRYPTO_MODE_SM4_ECB,
+ 16, 0))
+ usecbc = 0;
+ else if (spacc_is_mode_keysize_supported(spacc,
+ CRYPTO_MODE_SM4_CBC,
+ 16, 0))
+ usecbc = 1;
+ else
+ return -EINVAL;
+ } else
+ return -EINVAL;
+
+ memset(iv, 0, sizeof(iv));
+ memset(&ddt, 0, sizeof(ddt));
+
+ buf = dma_alloc_coherent(spacc->dptr, 64, &bufphys, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ handle = -1;
+
+ /* set to 1111...., 2222...., 333... */
+ for (i = 0; i < 48; i++)
+ buf[i] = (i >> 4) + 1;
+
+ /* build DDT */
+ err = pdu_ddt_init(spacc->dptr, &ddt, 1);
+ if (err)
+ goto xcbc_err;
+
+ pdu_ddt_add(spacc->dptr, &ddt, bufphys, 48);
+
+ /* open a handle in either CBC or ECB mode */
+ if (mode_id == CRYPTO_MODE_MAC_XCBC) {
+ handle = spacc_open(spacc, (usecbc ?
+ CRYPTO_MODE_AES_CBC : CRYPTO_MODE_AES_ECB),
+ CRYPTO_MODE_NULL, ctx_idx, 0, NULL, NULL);
+
+ if (handle < 0) {
+ err = handle;
+ goto xcbc_err;
+ }
+
+ } else if (mode_id == CRYPTO_MODE_MAC_SM4_XCBC) {
+ handle = spacc_open(spacc, (usecbc ?
+ CRYPTO_MODE_SM4_CBC : CRYPTO_MODE_SM4_ECB),
+ CRYPTO_MODE_NULL, ctx_idx, 0, NULL, NULL);
+ if (handle < 0) {
+ err = handle;
+ goto xcbc_err;
+ }
+ }
+
+ spacc_set_operation(spacc, handle, OP_ENCRYPT, 0, 0, 0, 0, 0);
+ job = &spacc->job[handle];
+ init_waitqueue_head(&job->waitq);
+
+ if (usecbc) {
+ /*
+ * We can do the ECB work in CBC using three
+ * jobs with the IVreset to zero each time
+ */
+ for (i = 0; i < 3; i++) {
+ spacc_write_context(spacc, handle,
+ SPACC_CRYPTO_OPERATION, key,
+ keylen, iv, 16);
+ err = spacc_packet_enqueue_ddt(spacc, handle, &ddt,
+ &ddt, 16, (i * 16) |
+ ((i * 16) << 16), 0, 0,
+ 0, 0);
+ if (err != 0)
+ goto xcbc_err;
+
+ if (wait_event_interruptible(job->waitq,
+ job->job_done))
+ wait_event(job->waitq, job->job_done);
+ job->job_done = 0;
+ err = job->job_err;
+
+ if (err != 0)
+ goto xcbc_err;
+ }
+ } else {
+ /*
+ * Do the 48 bytes as a single SPAcc job this is the ideal case
+ * but only possible if ECB was enabled in the core
+ */
+ spacc_write_context(spacc, handle, SPACC_CRYPTO_OPERATION,
+ key, keylen, iv, 16);
+ err = spacc_packet_enqueue_ddt(spacc, handle, &ddt, &ddt, 48,
+ 0, 0, 0, 0, 0);
+ if (err != 0)
+ goto xcbc_err;
+
+ if (wait_event_interruptible(job->waitq, job->job_done))
+ wait_event(job->waitq, job->job_done);
+
+ job->job_done = 0;
+ err = job->job_err;
+
+ if (err != 0)
+ goto xcbc_err;
+ }
+
+ /* now we can copy the key */
+ memcpy(xcbc_out, buf, 48);
+ memzero_explicit(buf, 64);
+
+xcbc_err:
+ dma_free_coherent(spacc->dptr, 64, buf, bufphys);
+ pdu_ddt_free(&ddt);
+
+ if (handle >= 0)
+ spacc_close(spacc, handle);
+
+ if (err)
+ return -EINVAL;
+
+ return 0;
+}
+
+void spacc_set_priority(struct spacc_device *spacc, int priority)
+{
+ u32 vspacc_prio_reg;
+
+ if (!spacc || !spacc->regmap)
+ return;
+
+ if (priority < 0 || priority > 15) {
+ dev_warn(spacc->dptr,
+ "Invalid VSPAcc priority %d (valid:0-15)\n", priority);
+ return;
+ }
+
+ /* Build new register value with mode = 0 (WEIGHTED),
+ * weight = priority.
+ */
+ vspacc_prio_reg = VPRIO_SET(0, priority);
+
+ /* Write to the SPAcc virtual priority register */
+ writel(vspacc_prio_reg, spacc->regmap + SPACC_REG_VIRTUAL_PRIO);
+
+ dev_dbg(spacc->dptr, "Set VSPAcc priority: %d (reg = 0x%08x)\n",
+ priority, vspacc_prio_reg);
+}
diff --git a/drivers/crypto/dwc-spacc/spacc_core.h b/drivers/crypto/dwc-spacc/spacc_core.h
new file mode 100644
index 0000000000000..145e77852d9ca
--- /dev/null
+++ b/drivers/crypto/dwc-spacc/spacc_core.h
@@ -0,0 +1,857 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef SPACC_CORE_H_
+#define SPACC_CORE_H_
+
+#include <linux/interrupt.h>
+
+#include "spacc_hal.h"
+
+struct platform_device;
+
+enum dma_type {
+ SPACC_DMA_UNDEF = 0,
+ SPACC_DMA_DDT = 1,
+ SPACC_DMA_LINEAR = 2
+};
+
+enum op_mode {
+ SPACC_OP_MODE_IRQ = 0,
+ SPACC_OP_MODE_WD = 1 /* watchdog */
+};
+
+#define OP_ENCRYPT 0
+#define OP_DECRYPT 1
+#define SPACC_CTX_WAIT_TIMEOUT 5
+
+#define SPACC_CRYPTO_OPERATION 1
+#define SPACC_HASH_OPERATION 2
+
+#define SPACC_AADCOPY_FLAG 0x80000000
+
+#define SPACC_AUTO_SIZE (-1)
+
+#define SPACC_WD_LIMIT 0x80
+#define SPACC_WD_TIMER_INIT 0x40000
+
+#define SPACC_MODE_SUPPORTED 1
+#define SPACC_MODE_NOT_SUPPORTED 0
+
+#define SPACC_AUTODETECT_TIMEOUT_MS 10
+#define SPACC_AUTODETECT_MAX_TIMEOUTS 3
+
+/********* Register Offsets **********/
+#define SPACC_REG_IRQ_EN 0x00000L
+#define SPACC_REG_IRQ_STAT 0x00004L
+#define SPACC_REG_IRQ_CTRL 0x00008L
+#define SPACC_REG_FIFO_STAT 0x0000CL
+#define SPACC_REG_SDMA_BRST_SZ 0x00010L
+
+#define SPACC_REG_SRC_PTR 0x00020L
+#define SPACC_REG_DST_PTR 0x00024L
+#define SPACC_REG_OFFSET 0x00028L
+#define SPACC_REG_PRE_AAD_LEN 0x0002CL
+#define SPACC_REG_POST_AAD_LEN 0x00030L
+
+#define SPACC_REG_PROC_LEN 0x00034L
+#define SPACC_REG_ICV_LEN 0x00038L
+#define SPACC_REG_ICV_OFFSET 0x0003CL
+#define SPACC_REG_IV_OFFSET 0x00040L
+
+#define SPACC_REG_SW_CTRL 0x00044L
+#define SPACC_REG_AUX_INFO 0x00048L
+#define SPACC_REG_CTRL 0x0004CL
+
+#define SPACC_REG_STAT_POP 0x00050L
+#define SPACC_REG_STATUS 0x00054L
+
+#define SPACC_REG_STAT_WD_CTRL 0x00080L
+
+#define SPACC_REG_KEY_SZ 0x00100L
+
+#define SPACC_REG_VIRTUAL_RQST 0x00140L
+#define SPACC_REG_VIRTUAL_ALLOC 0x00144L
+#define SPACC_REG_VIRTUAL_PRIO 0x00148L
+
+#define SPACC_REG_ID 0x00180L
+#define SPACC_REG_CONFIG 0x00184L
+#define SPACC_REG_CONFIG2 0x00190L
+
+#define SPACC_REG_SECURE_CTRL 0x001C0L
+#define SPACC_REG_SECURE_RELEASE 0x001C4
+
+#define SPACC_REG_SK_LOAD 0x00200L
+#define SPACC_REG_SK_STAT 0x00204L
+#define SPACC_REG_SK_KEY 0x00240L
+
+#define SPACC_REG_VERSION_EXT_3 0x00194L
+
+/* out 8MB from base of SPACC */
+#define SPACC_REG_SKP 0x800000UL
+
+/********** Context Offsets **********/
+#define SPACC_CTX_CIPH_KEY 0x04000L
+#define SPACC_CTX_HASH_KEY 0x08000L
+
+/******** Sub-Context Offsets ********/
+#define SPACC_CTX_AES_KEY 0x00
+#define SPACC_CTX_AES_IV 0x20
+
+#define SPACC_CTX_DES_KEY 0x08
+#define SPACC_CTX_DES_IV 0x00
+
+/* use these to loop over CMDX macros */
+#define SPACC_CMDX_MAX 1
+#define SPACC_CMDX_MAX_QOS 3
+
+/********** IRQ_EN Bit Masks **********/
+
+#define _SPACC_IRQ_CMD0 0
+#define _SPACC_IRQ_STAT 4
+#define _SPACC_IRQ_STAT_WD 12
+#define _SPACC_IRQ_GLBL 31
+
+#define SPACC_IRQ_EN_CMD(x) (1UL << _SPACC_IRQ_CMD0 << (x))
+#define SPACC_IRQ_EN_STAT BIT(_SPACC_IRQ_STAT)
+#define SPACC_IRQ_EN_STAT_WD BIT(_SPACC_IRQ_STAT_WD)
+#define SPACC_IRQ_EN_GLBL BIT(_SPACC_IRQ_GLBL)
+
+/********* IRQ_STAT Bitmasks *********/
+
+#define SPACC_IRQ_STAT_CMDX(x) (1UL << _SPACC_IRQ_CMD0 << (x))
+#define SPACC_IRQ_STAT_STAT BIT(_SPACC_IRQ_STAT)
+#define SPACC_IRQ_STAT_STAT_WD BIT(_SPACC_IRQ_STAT_WD)
+
+#define SPACC_IRQ_STAT_CLEAR_STAT(spacc) writel(SPACC_IRQ_STAT_STAT, \
+ (spacc)->regmap + SPACC_REG_IRQ_STAT)
+
+#define SPACC_IRQ_STAT_CLEAR_STAT_WD(spacc) writel(SPACC_IRQ_STAT_STAT_WD, \
+ (spacc)->regmap + SPACC_REG_IRQ_STAT)
+
+#define SPACC_IRQ_STAT_CLEAR_CMDX(spacc, x) writel(SPACC_IRQ_STAT_CMDX(x), \
+ (spacc)->regmap + SPACC_REG_IRQ_STAT)
+
+/********* IRQ_CTRL Bitmasks *********/
+/* CMD0 = 0; for QOS, CMD1 = 8, CMD2 = 16 */
+#define _SPACC_IRQ_CTRL_CMDX_CNT(x) (8 * (x))
+#define SPACC_IRQ_CTRL_CMDX_CNT_SET(x, n) \
+ (((n) & 0xFF) << _SPACC_IRQ_CTRL_CMDX_CNT(x))
+#define SPACC_IRQ_CTRL_CMDX_CNT_MASK(x) \
+ (0xFF << _SPACC_IRQ_CTRL_CMDX_CNT(x))
+
+/* STAT_CNT is at 16 and for QOS at 24 */
+#define _SPACC_IRQ_CTRL_STAT_CNT 16
+#define SPACC_IRQ_CTRL_STAT_CNT_SET(n) ((n) << _SPACC_IRQ_CTRL_STAT_CNT)
+#define SPACC_IRQ_CTRL_STAT_CNT_MASK (0x1FF << _SPACC_IRQ_CTRL_STAT_CNT)
+
+#define _SPACC_IRQ_CTRL_STAT_CNT_QOS 24
+#define SPACC_IRQ_CTRL_STAT_CNT_SET_QOS(n) \
+ ((n) << _SPACC_IRQ_CTRL_STAT_CNT_QOS)
+#define SPACC_IRQ_CTRL_STAT_CNT_MASK_QOS \
+ (0x7F << _SPACC_IRQ_CTRL_STAT_CNT_QOS)
+
+/******** FIFO_STAT Bitmasks *********/
+
+/* SPACC with QOS */
+#define SPACC_FIFO_STAT_CMDX_CNT_MASK(x) (0x7F << ((x) * 8))
+#define SPACC_FIFO_STAT_CMDX_CNT_GET(x, y) \
+ (((y) & SPACC_FIFO_STAT_CMDX_CNT_MASK(x)) >> ((x) * 8))
+#define SPACC_FIFO_STAT_CMDX_FULL(x) (1UL << (7 + (x) * 8))
+
+#define _SPACC_FIFO_STAT_STAT_CNT_QOS 24
+#define SPACC_FIFO_STAT_STAT_CNT_MASK_QOS \
+ (0x7F << _SPACC_FIFO_STAT_STAT_CNT_QOS)
+#define SPACC_FIFO_STAT_STAT_CNT_GET_QOS(y) \
+ (((y) & \
+ SPACC_FIFO_STAT_STAT_CNT_MASK_QOS) >> _SPACC_FIFO_STAT_STAT_CNT_QOS)
+
+/* SPACC without QOS */
+#define SPACC_FIFO_STAT_CMD0_CNT_MASK (0x1FF)
+#define SPACC_FIFO_STAT_CMD0_CNT_GET(y) ((y) & SPACC_FIFO_STAT_CMD0_CNT_MASK)
+#define _SPACC_FIFO_STAT_CMD0_FULL 15
+#define SPACC_FIFO_STAT_CMD0_FULL BIT(_SPACC_FIFO_STAT_CMD0_FULL)
+
+#define _SPACC_FIFO_STAT_STAT_CNT 16
+#define SPACC_FIFO_STAT_STAT_CNT_MASK (0x1FF << _SPACC_FIFO_STAT_STAT_CNT)
+#define SPACC_FIFO_STAT_STAT_CNT_GET(y) \
+ (((y) & SPACC_FIFO_STAT_STAT_CNT_MASK) >> _SPACC_FIFO_STAT_STAT_CNT)
+
+/* both */
+#define _SPACC_FIFO_STAT_STAT_EMPTY 31
+#define SPACC_FIFO_STAT_STAT_EMPTY BIT(_SPACC_FIFO_STAT_STAT_EMPTY)
+
+/********* SRC/DST_PTR Bitmasks **********/
+
+#define SPACC_SRC_PTR_PTR 0xFFFFFFF8
+#define SPACC_DST_PTR_PTR 0xFFFFFFF8
+
+/********** OFFSET Bitmasks **********/
+
+#define SPACC_OFFSET_SRC_O 0
+#define SPACC_OFFSET_SRC_W 16
+#define SPACC_OFFSET_DST_O 16
+#define SPACC_OFFSET_DST_W 16
+
+#define SPACC_MIN_CHUNK_SIZE 1024
+#define SPACC_MAX_CHUNK_SIZE 16384
+
+/********* PKT_LEN Bitmasks **********/
+
+#ifndef _SPACC_PKT_LEN_PROC_LEN
+#define _SPACC_PKT_LEN_PROC_LEN 0
+#endif
+#ifndef _SPACC_PKT_LEN_AAD_LEN
+#define _SPACC_PKT_LEN_AAD_LEN 16
+#endif
+
+/********* SW_CTRL Bitmasks ***********/
+
+#define _SPACC_SW_CTRL_ID_0 0
+#define SPACC_SW_CTRL_ID_W 8
+#define SPACC_SW_CTRL_ID_MASK (0xFF << _SPACC_SW_CTRL_ID_0)
+#define SPACC_SW_CTRL_ID_GET(y) \
+ (((y) & SPACC_SW_CTRL_ID_MASK) >> _SPACC_SW_CTRL_ID_0)
+#define SPACC_SW_CTRL_ID_SET(id) \
+ (((id) & SPACC_SW_CTRL_ID_MASK) >> _SPACC_SW_CTRL_ID_0)
+
+#define _SPACC_SW_CTRL_PRIO 30
+#define SPACC_SW_CTRL_PRIO_MASK 0x3
+#define SPACC_SW_CTRL_PRIO_SET(prio) \
+ (((prio) & SPACC_SW_CTRL_PRIO_MASK) << _SPACC_SW_CTRL_PRIO)
+
+/* Priorities */
+#define SPACC_SW_CTRL_PRIO_HI 0
+#define SPACC_SW_CTRL_PRIO_MED 1
+#define SPACC_SW_CTRL_PRIO_LOW 2
+
+/*********** SECURE_CTRL bitmasks *********/
+#define _SPACC_SECURE_CTRL_MS_SRC 0
+#define _SPACC_SECURE_CTRL_MS_DST 1
+#define _SPACC_SECURE_CTRL_MS_DDT 2
+#define _SPACC_SECURE_CTRL_LOCK 31
+
+#define SPACC_SECURE_CTRL_MS_SRC BIT(_SPACC_SECURE_CTRL_MS_SRC)
+#define SPACC_SECURE_CTRL_MS_DST BIT(_SPACC_SECURE_CTRL_MS_DST)
+#define SPACC_SECURE_CTRL_MS_DDT BIT(_SPACC_SECURE_CTRL_MS_DDT)
+#define SPACC_SECURE_CTRL_LOCK BIT(_SPACC_SECURE_CTRL_LOCK)
+
+/********* SKP bits **************/
+#define _SPACC_SK_LOAD_CTX_IDX 0
+#define _SPACC_SK_LOAD_ALG 8
+#define _SPACC_SK_LOAD_MODE 12
+#define _SPACC_SK_LOAD_SIZE 16
+#define _SPACC_SK_LOAD_ENC_EN 30
+#define _SPACC_SK_LOAD_DEC_EN 31
+#define _SPACC_SK_STAT_BUSY 0
+
+#define SPACC_SK_LOAD_ENC_EN BIT(_SPACC_SK_LOAD_ENC_EN)
+#define SPACC_SK_LOAD_DEC_EN BIT(_SPACC_SK_LOAD_DEC_EN)
+#define SPACC_SK_STAT_BUSY BIT(_SPACC_SK_STAT_BUSY)
+
+/*********** CTRL Bitmasks ***********/
+/*
+ * These CTRL field locations vary with SPACC version
+ * and if they are used, they should be set accordingly
+ */
+#define _SPACC_CTRL_CIPH_ALG 0
+#define _SPACC_CTRL_HASH_ALG 4
+#define _SPACC_CTRL_CIPH_MODE 8
+#define _SPACC_CTRL_HASH_MODE 12
+#define _SPACC_CTRL_MSG_BEGIN 14
+#define _SPACC_CTRL_MSG_END 15
+#define _SPACC_CTRL_CTX_IDX 16
+#define _SPACC_CTRL_ENCRYPT 24
+#define _SPACC_CTRL_AAD_COPY 25
+#define _SPACC_CTRL_ICV_PT 26
+#define _SPACC_CTRL_ICV_ENC 27
+#define _SPACC_CTRL_ICV_APPEND 28
+#define _SPACC_CTRL_KEY_EXP 29
+#define _SPACC_CTRL_SEC_KEY 31
+
+/* CTRL bitmasks for 4.15+ cores */
+#define _SPACC_CTRL_CIPH_ALG_415 0
+#define _SPACC_CTRL_HASH_ALG_415 3
+#define _SPACC_CTRL_CIPH_MODE_415 8
+#define _SPACC_CTRL_HASH_MODE_415 12
+
+/********* Virtual Spacc Priority Bitmasks **********/
+#define _SPACC_VPRIO_MODE 0
+#define _SPACC_VPRIO_WEIGHT 8
+
+/********* AUX INFO Bitmasks *********/
+#define _SPACC_AUX_INFO_DIR 0
+#define _SPACC_AUX_INFO_BIT_ALIGN 1
+#define _SPACC_AUX_INFO_CBC_CS 16
+
+/********* STAT_POP Bitmasks *********/
+#define _SPACC_STAT_POP_POP 0
+#define SPACC_STAT_POP_POP BIT(_SPACC_STAT_POP_POP)
+
+/********** STATUS Bitmasks **********/
+#define _SPACC_STATUS_SW_ID 0
+#define _SPACC_STATUS_RET_CODE 24
+#define _SPACC_STATUS_SEC_CMD 31
+#define SPACC_GET_STATUS_RET_CODE(s) \
+ (((s) >> _SPACC_STATUS_RET_CODE) & 0x7)
+
+#define SPACC_STATUS_SW_ID_MASK (0xFF << _SPACC_STATUS_SW_ID)
+#define SPACC_STATUS_SW_ID_GET(y) \
+ (((y) & SPACC_STATUS_SW_ID_MASK) >> _SPACC_STATUS_SW_ID)
+
+/********** KEY_SZ Bitmasks **********/
+#define _SPACC_KEY_SZ_SIZE 0
+#define _SPACC_KEY_SZ_CTX_IDX 8
+#define _SPACC_KEY_SZ_CIPHER 31
+
+#define SPACC_KEY_SZ_CIPHER BIT(_SPACC_KEY_SZ_CIPHER)
+
+#define SPACC_SET_CIPHER_KEY_SZ(z) \
+ (((z) << _SPACC_KEY_SZ_SIZE) | (1UL << _SPACC_KEY_SZ_CIPHER))
+#define SPACC_SET_HASH_KEY_SZ(z) ((z) << _SPACC_KEY_SZ_SIZE)
+#define SPACC_SET_KEY_CTX(ctx) ((ctx) << _SPACC_KEY_SZ_CTX_IDX)
+
+/*****************************************************************************/
+
+#define AUX_DIR(a) ((a) << _SPACC_AUX_INFO_DIR)
+#define AUX_BIT_ALIGN(a) ((a) << _SPACC_AUX_INFO_BIT_ALIGN)
+#define AUX_CBC_CS(a) ((a) << _SPACC_AUX_INFO_CBC_CS)
+
+#define VPRIO_SET(mode, weight) \
+ (((mode) << _SPACC_VPRIO_MODE) | ((weight) << _SPACC_VPRIO_WEIGHT))
+
+#ifndef MAX_DDT_ENTRIES
+/* add one for null at end of list */
+#define MAX_DDT_ENTRIES \
+ ((SPACC_MAX_MSG_MALLOC_SIZE / SPACC_MAX_PARTICLE_SIZE) + 1)
+#endif
+
+#define DDT_ENTRY_SIZE (sizeof(ddt_entry) * MAX_DDT_ENTRIES)
+
+#ifndef SPACC_MAX_JOBS
+#define SPACC_MAX_JOBS BIT(SPACC_SW_CTRL_ID_W)
+#endif
+
+#if SPACC_MAX_JOBS > 256
+# error SPACC_MAX_JOBS cannot exceed 256.
+#endif
+
+#ifndef SPACC_MAX_JOB_BUFFERS
+#define SPACC_MAX_JOB_BUFFERS 192
+#endif
+
+/* max DDT particle size */
+#ifndef SPACC_MAX_PARTICLE_SIZE
+#define SPACC_MAX_PARTICLE_SIZE 4096
+#endif
+
+/*
+ * Max message size from HW configuration
+ * usually defined in ICD as (2 exponent 16) -1
+ */
+#ifndef _SPACC_MAX_MSG_MALLOC_SIZE
+#define _SPACC_MAX_MSG_MALLOC_SIZE 16
+#endif
+#define SPACC_MAX_MSG_MALLOC_SIZE BIT(_SPACC_MAX_MSG_MALLOC_SIZE)
+
+#ifndef SPACC_MAX_MSG_SIZE
+#define SPACC_MAX_MSG_SIZE (SPACC_MAX_MSG_MALLOC_SIZE - 1)
+#endif
+
+#define SPACC_LOOP_WAIT 1000000
+#define SPACC_CTR_IV_MAX8 ((u32)0xFF)
+#define SPACC_CTR_IV_MAX16 ((u32)0xFFFF)
+#define SPACC_CTR_IV_MAX32 ((u32)0xFFFFFFFF)
+#define SPACC_CTR_IV_MAX64 ((u64)0xFFFFFFFFFFFFFFFF)
+
+/* cipher algos */
+enum ecipher {
+ C_NULL = 0,
+ C_DES = 1,
+ C_AES = 2,
+ C_RC4 = 3,
+ C_MULTI2 = 4,
+ C_KASUMI = 5,
+ C_SNOW3G_UEA2 = 6,
+ C_ZUC_UEA3 = 7,
+ C_CHACHA20 = 8,
+ C_SM4 = 9,
+ C_MAX = 10
+};
+
+/* ctrl reg cipher modes */
+enum eciphermode {
+ CM_ECB = 0,
+ CM_CBC = 1,
+ CM_CTR = 2,
+ CM_CCM = 3,
+ CM_GCM = 5,
+ CM_OFB = 7,
+ CM_CFB = 8,
+ CM_F8 = 9,
+ CM_XTS = 10,
+ CM_MAX = 11
+};
+
+enum echachaciphermode {
+ CM_CHACHA_STREAM = 2,
+ CM_CHACHA_AEAD = 5
+};
+
+enum ehash {
+ H_NULL = 0,
+ H_MD5 = 1,
+ H_SHA1 = 2,
+ H_SHA224 = 3,
+ H_SHA256 = 4,
+ H_SHA384 = 5,
+ H_SHA512 = 6,
+ H_XCBC = 7,
+ H_CMAC = 8,
+ H_KF9 = 9,
+ H_SNOW3G_UIA2 = 10,
+ H_CRC32_I3E802_3 = 11,
+ H_ZUC_UIA3 = 12,
+ H_SHA512_224 = 13,
+ H_SHA512_256 = 14,
+ H_MICHAEL = 15,
+ H_SHA3_224 = 16,
+ H_SHA3_256 = 17,
+ H_SHA3_384 = 18,
+ H_SHA3_512 = 19,
+ H_SHAKE128 = 20,
+ H_SHAKE256 = 21,
+ H_POLY1305 = 22,
+ H_SM3 = 23,
+ H_SM4_XCBC_MAC = 24,
+ H_SM4_CMAC = 25,
+ H_MAX = 26
+};
+
+enum ehashmode {
+ HM_RAW = 0,
+ HM_SSLMAC = 1,
+ HM_HMAC = 2,
+ HM_MAX = 3
+};
+
+enum eshakehashmode {
+ HM_SHAKE_SHAKE = 0,
+ HM_SHAKE_CSHAKE = 1,
+ HM_SHAKE_KMAC = 2
+};
+
+enum spacc_ret_code {
+ SPACC_OK = 0,
+ SPACC_ICVFAIL = 1,
+ SPACC_MEMERR = 2,
+ SPACC_BLOCKERR = 3,
+ SPACC_SECERR = 4
+};
+
+enum eicvpos {
+ IP_ICV_OFFSET = 0,
+ IP_ICV_APPEND = 1,
+ IP_ICV_IGNORE = 2,
+ IP_MAX = 3
+};
+
+enum hash_icv {
+ /* HASH of plaintext */
+ ICV_HASH = 0,
+ /* HASH the plaintext and encrypt the plaintext and ICV */
+ ICV_HASH_ENCRYPT = 1,
+ /* HASH the ciphertext */
+ ICV_ENCRYPT_HASH = 2,
+ ICV_IGNORE = 3,
+ IM_MAX = 4
+};
+
+enum crypto_modes {
+ CRYPTO_MODE_NULL,
+ CRYPTO_MODE_AES_ECB,
+ CRYPTO_MODE_AES_CBC,
+ CRYPTO_MODE_AES_CTR,
+ CRYPTO_MODE_AES_CCM,
+ CRYPTO_MODE_AES_GCM,
+ CRYPTO_MODE_AES_F8,
+ CRYPTO_MODE_AES_XTS,
+ CRYPTO_MODE_AES_CFB,
+ CRYPTO_MODE_AES_OFB,
+ CRYPTO_MODE_AES_CS1,
+ CRYPTO_MODE_AES_CS2,
+ CRYPTO_MODE_AES_CS3,
+ CRYPTO_MODE_MULTI2_ECB,
+ CRYPTO_MODE_MULTI2_CBC,
+ CRYPTO_MODE_MULTI2_OFB,
+ CRYPTO_MODE_MULTI2_CFB,
+ CRYPTO_MODE_3DES_CBC,
+ CRYPTO_MODE_3DES_ECB,
+ CRYPTO_MODE_DES_CBC,
+ CRYPTO_MODE_DES_ECB,
+ CRYPTO_MODE_KASUMI_ECB,
+ CRYPTO_MODE_KASUMI_F8,
+ CRYPTO_MODE_SNOW3G_UEA2,
+ CRYPTO_MODE_ZUC_UEA3,
+ CRYPTO_MODE_CHACHA20_STREAM,
+ CRYPTO_MODE_CHACHA20_POLY1305,
+ CRYPTO_MODE_SM4_ECB,
+ CRYPTO_MODE_SM4_CBC,
+ CRYPTO_MODE_SM4_CFB,
+ CRYPTO_MODE_SM4_OFB,
+ CRYPTO_MODE_SM4_CTR,
+ CRYPTO_MODE_SM4_CCM,
+ CRYPTO_MODE_SM4_GCM,
+ CRYPTO_MODE_SM4_F8,
+ CRYPTO_MODE_SM4_XTS,
+ CRYPTO_MODE_SM4_CS1,
+ CRYPTO_MODE_SM4_CS2,
+ CRYPTO_MODE_SM4_CS3,
+
+ CRYPTO_MODE_HASH_MD5,
+ CRYPTO_MODE_HMAC_MD5,
+ CRYPTO_MODE_HASH_SHA1,
+ CRYPTO_MODE_HMAC_SHA1,
+ CRYPTO_MODE_HASH_SHA224,
+ CRYPTO_MODE_HMAC_SHA224,
+ CRYPTO_MODE_HASH_SHA256,
+ CRYPTO_MODE_HMAC_SHA256,
+ CRYPTO_MODE_HASH_SHA384,
+ CRYPTO_MODE_HMAC_SHA384,
+ CRYPTO_MODE_HASH_SHA512,
+ CRYPTO_MODE_HMAC_SHA512,
+ CRYPTO_MODE_HASH_SHA512_224,
+ CRYPTO_MODE_HMAC_SHA512_224,
+ CRYPTO_MODE_HASH_SHA512_256,
+ CRYPTO_MODE_HMAC_SHA512_256,
+
+ CRYPTO_MODE_MAC_XCBC,
+ CRYPTO_MODE_MAC_CMAC,
+ CRYPTO_MODE_MAC_KASUMI_F9,
+ CRYPTO_MODE_MAC_SNOW3G_UIA2,
+ CRYPTO_MODE_MAC_ZUC_UIA3,
+ CRYPTO_MODE_MAC_POLY1305,
+
+ CRYPTO_MODE_SSLMAC_MD5,
+ CRYPTO_MODE_SSLMAC_SHA1,
+ CRYPTO_MODE_HASH_CRC32,
+ CRYPTO_MODE_MAC_MICHAEL,
+
+ CRYPTO_MODE_HASH_SHA3_224,
+ CRYPTO_MODE_HASH_SHA3_256,
+ CRYPTO_MODE_HASH_SHA3_384,
+ CRYPTO_MODE_HASH_SHA3_512,
+
+ CRYPTO_MODE_HASH_SHAKE128,
+ CRYPTO_MODE_HASH_SHAKE256,
+ CRYPTO_MODE_HASH_CSHAKE128,
+ CRYPTO_MODE_HASH_CSHAKE256,
+ CRYPTO_MODE_MAC_KMAC128,
+ CRYPTO_MODE_MAC_KMAC256,
+ CRYPTO_MODE_MAC_KMACXOF128,
+ CRYPTO_MODE_MAC_KMACXOF256,
+
+ CRYPTO_MODE_HASH_SM3,
+ CRYPTO_MODE_HMAC_SM3,
+ CRYPTO_MODE_MAC_SM4_XCBC,
+ CRYPTO_MODE_MAC_SM4_CMAC,
+
+ CRYPTO_MODE_LAST
+};
+
+/* job descriptor */
+typedef void (*spacc_callback)(void *spacc_dev, void *data);
+
+struct spacc_job {
+ wait_queue_head_t waitq;
+
+ unsigned long
+ enc_mode, /* Encryption algorithm mode */
+ hash_mode, /* Hash algorithm mode */
+ icv_len,
+ icv_offset,
+ op, /* operation */
+ ctrl, /* CTRL shadow register */
+
+ /*
+ * Context just initialized or taken,
+ * and this is the first use.
+ */
+ pre_aad_sz, post_aad_sz, /* size of AAD for the latest packet */
+ hkey_sz,
+ ckey_sz;
+ bool first_use;
+
+ /* direction and bit alignment parameters for the AUX_INFO reg */
+ unsigned int auxinfo_dir, auxinfo_bit_align;
+ unsigned int auxinfo_cs_mode; /* AUX info setting for CBC-CS */
+
+ u32 ctx_idx;
+ unsigned int job_used;
+ unsigned int job_swid;
+ unsigned int job_done;
+ unsigned int job_err;
+ unsigned int job_secure;
+ spacc_callback cb;
+ void *cbdata;
+
+};
+
+#define SPACC_CTX_IDX_UNUSED 0xFFFFFFFF
+#define SPACC_JOB_IDX_UNUSED 0xFFFFFFFF
+
+struct spacc_ctx {
+ /* memory context to store cipher keys */
+ void __iomem *ciph_key;
+ /* memory context to store hash keys */
+ void __iomem *hash_key;
+ /* reference count of jobs using this context */
+ int ref_cnt;
+ /* number of contexts following related to this one */
+ int ncontig;
+};
+
+#define SPACC_CTRL_MASK(field) \
+ (1UL << spacc->config.ctrl_map[(field)])
+#define SPACC_CTRL_SET(field, value) \
+ ((value) << spacc->config.ctrl_map[(field)])
+
+enum ctrl_map {
+ SPACC_CTRL_VER_0,
+ SPACC_CTRL_VER_1,
+ SPACC_CTRL_VER_2,
+ SPACC_CTRL_VER_SIZE
+};
+
+enum ctrl_type {
+ SPACC_CTRL_CIPH_ALG,
+ SPACC_CTRL_CIPH_MODE,
+ SPACC_CTRL_HASH_ALG,
+ SPACC_CTRL_HASH_MODE,
+ SPACC_CTRL_ENCRYPT,
+ SPACC_CTRL_CTX_IDX,
+ SPACC_CTRL_SEC_KEY,
+ SPACC_CTRL_AAD_COPY,
+ SPACC_CTRL_ICV_PT,
+ SPACC_CTRL_ICV_ENC,
+ SPACC_CTRL_ICV_APPEND,
+ SPACC_CTRL_KEY_EXP,
+ SPACC_CTRL_MSG_BEGIN,
+ SPACC_CTRL_MSG_END,
+ SPACC_CTRL_MAPSIZE
+};
+
+struct spacc_device {
+ void __iomem *regmap;
+ bool wd_cnt_limit;
+ bool autodetect;
+
+ /* Manages the pool of available H/W contexts */
+ struct semaphore ctx_sem;
+
+ /* hardware configuration */
+ struct {
+ unsigned int version,
+ pdu_version,
+ project;
+ u32 max_msg_size; /* max PROCLEN value */
+
+ unsigned char modes[CRYPTO_MODE_LAST];
+
+ int num_ctx, /* no. of contexts */
+ num_sec_ctx, /* no. of SKP contexts */
+ sec_ctx_page_size, /* page size of SKP context in bytes */
+ ciph_page_size, /* cipher context page size in bytes */
+ hash_page_size, /* hash context page size in bytes */
+ string_size,
+ is_qos, /* QOS spacc? */
+ is_pdu, /* PDU spacc? */
+ is_secure,
+ is_secure_port, /* are we on the secure port? */
+ is_partial, /* Is partial processing enabled? */
+ is_ivimport, /* is ivimport enabled? */
+ dma_type, /* DMA type: linear or scattergather */
+ idx, /* which virtual spacc IDX is this? */
+ priority, /* weighted priority of virtual spacc */
+ cmd0_fifo_depth, /* CMD FIFO depths */
+ cmd1_fifo_depth,
+ cmd2_fifo_depth,
+ stat_fifo_depth, /* depth of STATUS FIFO */
+ fifo_cnt,
+ ideal_stat_level;
+
+ u32 wd_timer;
+ u64 oldtimer, timer;
+
+ const u8 *ctrl_map; /* map of ctrl register field offsets */
+ } config;
+
+ struct spacc_job_buffer {
+ int active;
+ int job_idx;
+ struct pdu_ddt *src, *dst;
+ u32 proc_sz, aad_offset, pre_aad_sz,
+ post_aad_sz, iv_offset, prio;
+ } job_buffer[SPACC_MAX_JOB_BUFFERS];
+
+ int jb_head, jb_tail;
+
+ int op_mode, /* operating mode and watchdog functionality */
+ wdcnt; /* number of pending WD IRQs */
+
+ /* SW_ID value which will be used for next job */
+ unsigned int job_next_swid;
+
+ struct spacc_ctx *ctx; /* this size changes per configured device */
+ struct spacc_job *job; /* allocate memory for [SPACC_MAX_JOBS]; */
+ int job_lookup[SPACC_MAX_JOBS]; /* correlate SW_ID back to job index */
+
+ spinlock_t lock; /* lock for register access */
+ spinlock_t ctx_lock;
+
+ /* callback functions for IRQ processing */
+ void (*irq_cb_cmdx)(struct spacc_device *spacc, int x);
+ void (*irq_cb_stat)(struct spacc_device *spacc);
+ void (*irq_cb_stat_wd)(struct spacc_device *spacc);
+
+ /*
+ * This is called after jobs have been popped off the STATUS FIFO
+ * useful so you can be told when there might be space available
+ * in the CMD FIFO
+ */
+ void (*spacc_notify_jobs)(struct spacc_device *spacc);
+
+ /* cache */
+ struct {
+ u32 src_ptr,
+ dst_ptr,
+ proc_len,
+ icv_len,
+ icv_offset,
+ pre_aad,
+ post_aad,
+ iv_offset,
+ offset,
+ aux;
+ } cache;
+
+ struct device *dptr;
+};
+
+struct spacc_priv {
+ struct spacc_device spacc;
+
+ /* dedicated workQ */
+ struct workqueue_struct *spacc_wq;
+ struct work_struct pop_jobs;
+ struct crypto_engine *engine;
+ unsigned long max_msg_len;
+ int irq;
+
+ /* Per-device DMA pools for multi-device safety */
+ struct dma_pool *hash_pool;
+ struct kmem_cache *iv_pool;
+ struct dma_pool *ddt_pool, *ddt16_pool, *ddt4_pool;
+
+ /* Per-device lists and mutexes for algorithm tracking */
+ struct list_head hash_alg_list;
+ struct mutex hash_alg_mutex;
+ struct list_head cipher_alg_list;
+ struct mutex cipher_alg_mutex;
+ struct list_head aead_alg_list;
+ struct mutex aead_alg_mutex;
+};
+
+/* Structure for encryption mode configuration */
+struct enc_config {
+ int mode;
+ u32 cipher_alg;
+ u32 cipher_mode;
+ int auxinfo_cs_mode;
+};
+
+/* Structure for hash mode configuration */
+struct hash_config {
+ int mode;
+ u32 hash_alg;
+ u32 hash_mode;
+ int auxinfo_dir;
+};
+
+int spacc_open(struct spacc_device *spacc, int enc, int hash, int ctx,
+ int secure_mode, spacc_callback cb, void *cbdata);
+int spacc_clone_handle(struct spacc_device *spacc, int old_handle,
+ void *cbdata);
+int spacc_close(struct spacc_device *spacc, int job_idx);
+int spacc_set_operation(struct spacc_device *spacc, int job_idx, int op,
+ u32 prot, u32 icvcmd, u32 icvoff,
+ u32 icvsz, u32 sec_key);
+int spacc_set_key_exp(struct spacc_device *spacc, int job_idx);
+
+int spacc_packet_enqueue_ddt_ex(struct spacc_device *spacc, int use_jb,
+ int job_idx, struct pdu_ddt *src_ddt,
+ struct pdu_ddt *dst_ddt, u32 proc_sz,
+ u32 aad_offset, u32 pre_aad_sz, u32 post_aad_sz,
+ u32 iv_offset, u32 prio,
+ unsigned long *lock_flag);
+int spacc_packet_enqueue_ddt(struct spacc_device *spacc, int job_idx,
+ struct pdu_ddt *src_ddt, struct pdu_ddt *dst_ddt,
+ u32 proc_sz, u32 aad_offset, u32 pre_aad_sz,
+ u32 post_aad_sz, u32 iv_offset, u32 prio);
+
+/* IRQ handling functions */
+void spacc_irq_cmdx_enable(struct spacc_device *spacc, int cmdx, int cmdx_cnt);
+void spacc_irq_cmdx_disable(struct spacc_device *spacc, int cmdx);
+void spacc_irq_stat_enable(struct spacc_device *spacc, int stat_cnt);
+void spacc_irq_stat_disable(struct spacc_device *spacc);
+void spacc_irq_stat_wd_enable(struct spacc_device *spacc);
+void spacc_irq_stat_wd_disable(struct spacc_device *spacc);
+void spacc_irq_glbl_enable(struct spacc_device *spacc);
+void spacc_irq_glbl_disable(struct spacc_device *spacc);
+uint32_t spacc_process_irq(struct spacc_device *spacc);
+void spacc_set_wd_count(struct spacc_device *spacc, uint32_t val);
+irqreturn_t spacc_irq_handler(int irq, void *dev);
+int spacc_sgs_to_ddt(struct device *dev,
+ struct scatterlist *sg1, int len1, int *ents1,
+ struct scatterlist *sg2, int len2, int *ents2,
+ struct scatterlist *sg3, int len3, int *ents3,
+ struct pdu_ddt *ddt, int dma_direction);
+int spacc_sg_to_ddt(struct device *dev, struct scatterlist *sg,
+ int nbytes, struct pdu_ddt *ddt, int dma_direction);
+
+/* context Manager */
+void spacc_ctx_init_all(struct spacc_device *spacc);
+
+/* SPAcc specific manipulation of context memory */
+int spacc_write_context(struct spacc_device *spacc, int job_idx, int op,
+ const unsigned char *key, int ksz,
+ const unsigned char *iv, int ivsz);
+
+int spacc_read_context(struct spacc_device *spacc, int job_idx, int op,
+ unsigned char *key, int ksz, unsigned char *iv,
+ int ivsz);
+
+/* job Manager */
+void spacc_job_init_all(struct spacc_device *spacc);
+int spacc_job_request(struct spacc_device *dev, int job_idx);
+int spacc_job_release(struct spacc_device *dev, int job_idx);
+
+/* helper functions */
+struct spacc_ctx *spacc_context_lookup_by_job(struct spacc_device *spacc,
+ int job_idx);
+int spacc_is_mode_keysize_supported(struct spacc_device *spacc, int mode,
+ int keysize, int keysz_index);
+int spacc_compute_xcbc_key(struct spacc_device *spacc, int mode_id,
+ int job_idx, const unsigned char *key,
+ int keylen, unsigned char *xcbc_out);
+
+int spacc_process_jb(struct spacc_device *spacc, unsigned long *lock_flag);
+int spacc_remove(struct platform_device *pdev);
+int spacc_static_config(struct spacc_device *spacc);
+int spacc_autodetect(struct spacc_device *spacc);
+void spacc_pop_jobs(struct work_struct *work);
+void spacc_fini(struct spacc_device *spacc);
+int spacc_init(void __iomem *baseaddr, struct spacc_device *spacc,
+ struct pdu_info *info, struct device *dev);
+int spacc_pop_packets(struct spacc_device *spacc, int *num_popped);
+void spacc_set_priority(struct spacc_device *spacc, int priority);
+
+#endif
diff --git a/drivers/crypto/dwc-spacc/spacc_device.c b/drivers/crypto/dwc-spacc/spacc_device.c
new file mode 100644
index 0000000000000..fc2b0ec2d1137
--- /dev/null
+++ b/drivers/crypto/dwc-spacc/spacc_device.c
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <crypto/engine.h>
+#include "spacc_device.h"
+
+static void spacc_cmd_process(struct spacc_device *spacc, int x)
+{
+ struct spacc_priv *priv = container_of(spacc, struct spacc_priv, spacc);
+
+ if (!work_pending(&priv->pop_jobs))
+ queue_work(priv->spacc_wq, &priv->pop_jobs);
+}
+
+static void spacc_stat_process(struct spacc_device *spacc)
+{
+ struct spacc_priv *priv = container_of(spacc, struct spacc_priv, spacc);
+
+ if (!work_pending(&priv->pop_jobs))
+ queue_work(priv->spacc_wq, &priv->pop_jobs);
+}
+
+static int spacc_init_device(struct platform_device *pdev)
+{
+ void __iomem *baseaddr;
+ struct pdu_info info;
+ struct spacc_priv *priv;
+ int err = 0;
+ int ret = 0;
+ int oldmode;
+ int irq_num;
+ int irq_ret;
+ const u64 oldtimer = SPACC_OLD_TIMER;
+
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (err) {
+ dev_err(&pdev->dev, "No usable 32-bit DMA configuration\n");
+ return err;
+ }
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ /*
+ * Set drvdata before pdu_mem_init(): DDT DMA pools are now kept
+ * per-device in priv (see spacc_core.h) instead of file-scope
+ * globals, and pdu_mem_init() resolves priv via dev_get_drvdata(),
+ * so drvdata must already be wired up by this point.
+ */
+ priv->spacc.dptr = &pdev->dev;
+ platform_set_drvdata(pdev, priv);
+
+ /* initialize DDT DMA pools based on this device's resources */
+ if (pdu_mem_init(&pdev->dev)) {
+ dev_err(&pdev->dev, "Could not initialize DMA pools\n");
+ return -ENOMEM;
+ }
+
+ priv->spacc.config.oldtimer = oldtimer;
+
+ /* Set the SPAcc internal counter value from kernel config */
+ priv->spacc.config.timer =
+ (u64)CONFIG_CRYPTO_DEV_SPACC_INTERNAL_COUNTER;
+ dev_dbg(&pdev->dev, "SPAcc internal counter set to: %llu\n",
+ priv->spacc.config.timer);
+
+ baseaddr = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(baseaddr)) {
+ dev_err(&pdev->dev, "Unable to map iomem\n");
+ err = PTR_ERR(baseaddr);
+ goto free_ddt_mem_pool;
+ }
+
+ pdu_get_version(baseaddr, &info);
+
+ ret = spacc_init(baseaddr, &priv->spacc, &info, &pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to initialize SPAcc device\n");
+ err = ret;
+ goto free_ddt_mem_pool;
+ }
+
+ /* Set the priority from kernel config */
+ priv->spacc.config.priority = CONFIG_CRYPTO_DEV_SPACC_PRIORITY;
+ dev_dbg(&pdev->dev, "VSPACC priority set from config: %u\n",
+ priv->spacc.config.priority);
+
+ /* Set the priority for this virtual SPAcc instance */
+ spacc_set_priority(&priv->spacc, priv->spacc.config.priority);
+
+ /* Initialize crypto engine */
+ priv->engine = crypto_engine_alloc_init(&pdev->dev, true);
+ if (!priv->engine) {
+ dev_err(&pdev->dev, "Could not allocate crypto engine\n");
+ err = -ENOMEM;
+ goto free_spacc_ctx;
+ }
+
+ err = crypto_engine_start(priv->engine);
+ if (err) {
+ dev_err(&pdev->dev, "Could not start crypto engine\n");
+ goto free_engine;
+ }
+
+ priv->spacc_wq = alloc_workqueue("spacc_workqueue", WQ_UNBOUND, 0);
+ if (!priv->spacc_wq) {
+ err = -ENOMEM;
+ goto free_engine;
+ }
+
+ INIT_WORK(&priv->pop_jobs, spacc_pop_jobs);
+ spacc_irq_glbl_disable(&priv->spacc);
+
+ irq_num = platform_get_irq(pdev, 0);
+ if (irq_num < 0) {
+ err = irq_num;
+ goto free_spacc_workq;
+ }
+ priv->irq = irq_num;
+
+ /* determine configured maximum message length */
+ priv->max_msg_len = priv->spacc.config.max_msg_size;
+
+ irq_ret = devm_request_irq(&pdev->dev, irq_num, spacc_irq_handler,
+ IRQF_SHARED, dev_name(&pdev->dev),
+ &pdev->dev);
+ if (irq_ret) {
+ dev_err(&pdev->dev, "Failed to request IRQ : %d\n", irq_ret);
+ err = irq_ret;
+ goto free_spacc_workq;
+ }
+
+ priv->spacc.irq_cb_stat = spacc_stat_process;
+ priv->spacc.irq_cb_cmdx = spacc_cmd_process;
+ oldmode = priv->spacc.op_mode;
+ priv->spacc.op_mode = SPACC_OP_MODE_IRQ;
+
+ /* Enable STAT and CMD interrupts */
+ spacc_irq_stat_enable(&priv->spacc, 1);
+ spacc_irq_cmdx_enable(&priv->spacc, 0, 1);
+ spacc_irq_stat_wd_disable(&priv->spacc);
+ spacc_irq_glbl_enable(&priv->spacc);
+
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_AUTODETECT)
+
+ err = spacc_autodetect(&priv->spacc);
+ if (err < 0) {
+ spacc_irq_glbl_disable(&priv->spacc);
+ goto free_irq;
+ }
+#else
+ err = spacc_static_config(&priv->spacc);
+ if (err < 0) {
+ spacc_irq_glbl_disable(&priv->spacc);
+ goto free_irq;
+ }
+#endif
+ priv->spacc.op_mode = oldmode;
+ if (priv->spacc.op_mode == SPACC_OP_MODE_IRQ) {
+ priv->spacc.irq_cb_stat = spacc_stat_process;
+ priv->spacc.irq_cb_cmdx = spacc_cmd_process;
+
+ /* Enable STAT and CMD interrupts */
+ spacc_irq_stat_enable(&priv->spacc, 1);
+ spacc_irq_cmdx_enable(&priv->spacc, 0, 1);
+ spacc_irq_glbl_enable(&priv->spacc);
+ } else {
+ priv->spacc.irq_cb_stat = spacc_stat_process;
+ priv->spacc.irq_cb_stat_wd = spacc_stat_process;
+
+ spacc_irq_stat_enable(&priv->spacc,
+ priv->spacc.config.ideal_stat_level);
+
+ /* Enable STAT and WD interrupts */
+ spacc_irq_cmdx_disable(&priv->spacc, 0);
+ spacc_irq_stat_wd_enable(&priv->spacc);
+ spacc_irq_glbl_enable(&priv->spacc);
+
+ /* enable the wd by setting the wd_timer = 100000 */
+ priv->spacc.config.wd_timer = priv->spacc.config.timer;
+ spacc_set_wd_count(&priv->spacc, priv->spacc.config.wd_timer);
+ }
+
+ /* unlock normal */
+ if (priv->spacc.config.is_secure_port) {
+ u32 t;
+
+ t = readl(baseaddr + SPACC_REG_SECURE_CTRL);
+ t &= ~(1UL << 31);
+ writel(t, baseaddr + SPACC_REG_SECURE_CTRL);
+ }
+
+ /* unlock device by default */
+ writel(0, baseaddr + SPACC_REG_SECURE_CTRL);
+
+ return 0;
+free_irq:
+ devm_free_irq(&pdev->dev, irq_num, &pdev->dev);
+free_spacc_workq:
+ destroy_workqueue(priv->spacc_wq);
+free_engine:
+ crypto_engine_exit(priv->engine);
+free_spacc_ctx:
+ spacc_fini(&priv->spacc);
+free_ddt_mem_pool:
+ pdu_mem_deinit(&pdev->dev);
+
+ return err;
+}
+
+static void spacc_unregister_algs(struct spacc_priv *priv)
+{
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_HASH)
+ spacc_unregister_hash_algs(priv);
+#endif
+}
+
+static void spacc_crypto_remove(struct platform_device *pdev)
+{
+ struct spacc_priv *priv = platform_get_drvdata(pdev);
+
+ spacc_irq_glbl_disable(&priv->spacc);
+ spacc_unregister_algs(priv);
+
+ if (priv->engine)
+ crypto_engine_exit(priv->engine);
+
+ devm_free_irq(&pdev->dev, priv->irq, &pdev->dev);
+
+ if (priv->spacc_wq)
+ destroy_workqueue(priv->spacc_wq);
+
+ spacc_remove(pdev);
+ platform_set_drvdata(pdev, NULL);
+}
+
+static int spacc_crypto_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+
+ rc = spacc_init_device(pdev);
+ if (rc < 0)
+ return rc;
+
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_HASH)
+ rc = spacc_probe_hashes(pdev);
+ if (rc < 0)
+ goto err;
+#endif
+
+ return 0;
+err:
+ spacc_crypto_remove(pdev);
+
+ return rc;
+}
+
+static const struct of_device_id snps_spacc_id[] = {
+ {.compatible = "snps,nsimosci-hs-spacc" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, snps_spacc_id);
+
+static struct platform_driver spacc_driver = {
+ .probe = spacc_crypto_probe,
+ .remove = spacc_crypto_remove,
+ .driver = {
+ .name = "spacc",
+ .of_match_table = snps_spacc_id,
+ },
+};
+
+module_platform_driver(spacc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Synopsys, Inc.");
+MODULE_DESCRIPTION("SPAcc Crypto Accelerator Driver");
diff --git a/drivers/crypto/dwc-spacc/spacc_device.h b/drivers/crypto/dwc-spacc/spacc_device.h
new file mode 100644
index 0000000000000..432d0f706d2dc
--- /dev/null
+++ b/drivers/crypto/dwc-spacc/spacc_device.h
@@ -0,0 +1,242 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef SPACC_DEVICE_H_
+#define SPACC_DEVICE_H_
+
+#include <crypto/hash.h>
+#include <crypto/ctr.h>
+#include <crypto/skcipher.h>
+#include <crypto/internal/aead.h>
+#include <crypto/engine.h>
+#include <linux/of.h>
+#include "spacc_core.h"
+
+#define MODE_TAB_AEAD(_name, _ciph, _hash, _hashlen, _ivlen, _blocklen) \
+ .name = _name, .aead = { .ciph = _ciph, .hash = _hash }, \
+ .hashlen = _hashlen, .ivlen = _ivlen, .blocklen = _blocklen
+
+/* helper macros for initializing the hash/cipher tables */
+#define MODE_TAB_COMMON(_name, _id_name, _blocklen) \
+ .name = _name, .id = CRYPTO_MODE_##_id_name, .blocklen = _blocklen
+
+#define MODE_TAB_HASH(_name, _id_name, _hashlen, _blocklen) \
+ MODE_TAB_COMMON(_name, _id_name, _blocklen), \
+ .hashlen = _hashlen, .testlen = _hashlen
+
+#define MODE_TAB_CIPH(_name, _id_name, _ivlen, _blocklen) \
+ MODE_TAB_COMMON(_name, _id_name, _blocklen), \
+ .ivlen = _ivlen
+
+#define MODE_TAB_HASH_XCBC 0x8000
+
+#define SPACC_OLD_TIMER 100000
+#define SPACC_MAX_DIGEST_SIZE 64
+#define SPACC_MAX_KEY_SIZE 32
+#define SPACC_MAX_IV_SIZE 16
+
+#define SPACC_DMA_ALIGN 4
+#define SPACC_DMA_BOUNDARY 0x10000
+#define SPACC_TEST_DMA_BUFF_SIZE 256
+
+/* flag means the IV is computed from setkey and crypt */
+#define SPACC_MANGLE_IV_FLAG 0x8000
+
+/* we're doing a CTR mangle (for RFC3686/IPsec) */
+#define SPACC_MANGLE_IV_RFC3686 0x0100
+
+/* we're doing GCM */
+#define SPACC_MANGLE_IV_RFC4106 0x0200
+
+/* we're doing GMAC */
+#define SPACC_MANGLE_IV_RFC4543 0x0300
+
+/* we're doing CCM */
+#define SPACC_MANGLE_IV_RFC4309 0x0400
+
+/* we're doing SM4 GCM/CCM */
+#define SPACC_MANGLE_IV_RFC8998 0x0500
+
+#define CRYPTO_MODE_AES_CTR_RFC3686 (CRYPTO_MODE_AES_CTR \
+ | SPACC_MANGLE_IV_FLAG \
+ | SPACC_MANGLE_IV_RFC3686)
+#define CRYPTO_MODE_AES_GCM_RFC4106 (CRYPTO_MODE_AES_GCM \
+ | SPACC_MANGLE_IV_FLAG \
+ | SPACC_MANGLE_IV_RFC4106)
+#define CRYPTO_MODE_AES_GCM_RFC4543 (CRYPTO_MODE_AES_GCM \
+ | SPACC_MANGLE_IV_FLAG \
+ | SPACC_MANGLE_IV_RFC4543)
+#define CRYPTO_MODE_AES_CCM_RFC4309 (CRYPTO_MODE_AES_CCM \
+ | SPACC_MANGLE_IV_FLAG \
+ | SPACC_MANGLE_IV_RFC4309)
+#define CRYPTO_MODE_SM4_GCM_RFC8998 (CRYPTO_MODE_SM4_GCM)
+#define CRYPTO_MODE_SM4_CCM_RFC8998 (CRYPTO_MODE_SM4_CCM)
+
+struct spacc_crypto_ctx {
+ struct device *dev;
+ unsigned int statesize;
+ int handle, mode, auth_size, key_len;
+ unsigned char *cipher_key;
+ struct mutex lock;
+
+ /*
+ * Indicates that the H/W context has been setup and can be used for
+ * crypto; otherwise, the software fallback will be used.
+ */
+ bool ctx_valid;
+
+ /* salt used for rfc3686/givencrypt mode */
+ unsigned char csalt[16];
+ u8 ipad[128] __aligned(sizeof(u32));
+ u8 digest_ctx_buf[128] __aligned(sizeof(u32));
+
+ /*
+ * tmp_buffer is mapped directly for DMA on zero-length requests.
+ * Must be cacheline-aligned to prevent cache maintenance operations
+ * from corrupting adjacent fields on non-coherent architectures.
+ */
+ u8 tmp_buffer[128] ____cacheline_aligned;
+
+ /* save keylen from setkey */
+ unsigned int keylen;
+ u8 key[256];
+ int zero_key;
+ unsigned char *tmp_sgl_buff;
+ struct scatterlist *tmp_sgl;
+
+ union {
+ struct crypto_ahash *hash;
+ struct crypto_aead *aead;
+ struct crypto_skcipher *cipher;
+ } fb;
+ struct crypto_shash *shash_fb;
+};
+
+struct spacc_crypto_reqctx {
+ struct pdu_ddt src, dst;
+ void *digest_buf, *iv_buf;
+ dma_addr_t digest_dma;
+ int dst_nents, src_nents, aead_nents, total_nents;
+ int encrypt_op, mode, single_shot;
+ unsigned int spacc_cipher_cryptlen, rem_nents;
+ u8 state_buffer[HASH_MAX_STATESIZE + 16]__aligned(8);
+
+ struct aead_cb_data {
+ int new_handle;
+ struct spacc_crypto_ctx *tctx;
+ struct spacc_crypto_reqctx *ctx;
+ struct aead_request *req;
+ struct spacc_device *spacc;
+ } cb;
+
+ struct ahash_cb_data {
+ int new_handle;
+ struct spacc_crypto_ctx *tctx;
+ struct spacc_crypto_reqctx *ctx;
+ struct ahash_request *req;
+ struct spacc_device *spacc;
+ } acb;
+
+ struct cipher_cb_data {
+ int new_handle;
+ struct spacc_crypto_ctx *tctx;
+ struct spacc_crypto_reqctx *ctx;
+ struct skcipher_request *req;
+ struct spacc_device *spacc;
+ } ccb;
+
+ union {
+ struct ahash_request hash_req;
+ struct skcipher_request cipher_req;
+ } fb;
+};
+
+struct mode_tab {
+ char name[128];
+ int valid;
+
+ /* mode ID used in hash/cipher mode but not aead */
+ int id;
+
+ /* ciph/hash mode used in aead */
+ struct {
+ int ciph, hash;
+ } aead;
+
+ unsigned int hashlen, ivlen, blocklen, keylen[3];
+ unsigned int keylen_mask, testlen;
+ unsigned int chunksize, walksize, min_keysize, max_keysize;
+
+ union {
+ unsigned char hash_test[SPACC_MAX_DIGEST_SIZE];
+ unsigned char ciph_test[3][2 * SPACC_MAX_IV_SIZE];
+ };
+};
+
+struct spacc_alg {
+ struct mode_tab *mode;
+ unsigned int keylen_mask;
+
+ struct device *dev;
+
+ struct list_head list;
+ struct crypto_alg *calg;
+ struct crypto_tfm *tfm;
+
+ union {
+ struct ahash_engine_alg hash;
+ struct aead_engine_alg aead;
+ struct skcipher_engine_alg skcipher;
+ } alg;
+};
+
+struct spacc_completion {
+ unsigned int wait_done;
+ struct completion spacc_wait_complete;
+ struct list_head list;
+};
+
+static inline const struct spacc_alg *spacc_tfm_ahash(struct crypto_tfm *tfm)
+{
+ const struct crypto_alg *calg = tfm->__crt_alg;
+
+ if ((calg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AHASH) {
+ return container_of(calg, struct spacc_alg,
+ alg.hash.base.halg.base);
+ }
+
+ return NULL;
+}
+
+static inline const struct spacc_alg *spacc_tfm_skcipher(struct crypto_tfm *tfm)
+{
+ const struct crypto_alg *calg = tfm->__crt_alg;
+
+ if ((calg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+ CRYPTO_ALG_TYPE_SKCIPHER)
+ return container_of(calg, struct spacc_alg,
+ alg.skcipher.base.base);
+
+ return NULL;
+}
+
+static inline const struct spacc_alg *spacc_tfm_aead(struct crypto_tfm *tfm)
+{
+ const struct crypto_alg *calg = tfm->__crt_alg;
+
+ if ((calg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AEAD)
+ return container_of(calg, struct spacc_alg, alg.aead.base.base);
+
+ return NULL;
+}
+
+int spacc_probe_hashes(struct platform_device *spacc_pdev);
+int spacc_unregister_hash_algs(struct spacc_priv *priv);
+
+int spacc_probe_aeads(struct platform_device *spacc_pdev);
+int spacc_unregister_aead_algs(struct spacc_priv *priv);
+
+int spacc_probe_ciphers(struct platform_device *spacc_pdev);
+int spacc_unregister_cipher_algs(struct spacc_priv *priv);
+
+irqreturn_t spacc_irq_handler(int irq, void *dev);
+#endif
diff --git a/drivers/crypto/dwc-spacc/spacc_hal.c b/drivers/crypto/dwc-spacc/spacc_hal.c
new file mode 100644
index 0000000000000..e8f598b3edae9
--- /dev/null
+++ b/drivers/crypto/dwc-spacc/spacc_hal.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include "spacc_hal.h"
+#include "spacc_core.h"
+#include <linux/unaligned.h>
+
+#define PDU_REG_SPACC_VERSION 0x00180UL
+#define PDU_REG_SPACC_CONFIG 0x00184UL
+#define PDU_REG_SPACC_CONFIG2 0x00190UL
+#define PDU_REG_SPACC_IV_OFFSET 0x00040UL
+#define PDU_REG_PDU_CONFIG 0x00188UL
+#define PDU_REG_SECURE_LOCK 0x001C0UL
+
+#define DDT_MAX_ENTRIES ((PDU_MAX_DDT + 1) * 8)
+#define DDT_16_ENTRIES ((16 + 1) * 8)
+#define DDT_4_ENTRIES ((4 + 1) * 8)
+
+int pdu_get_version(void __iomem *dev, struct pdu_info *inf)
+{
+ unsigned long reg_val;
+
+ if (!inf)
+ return -EINVAL;
+
+ memset(inf, 0, sizeof(*inf));
+ reg_val = readl(dev + PDU_REG_SPACC_VERSION);
+
+ /*
+ * Read the SPAcc version block; this tells us the revision,
+ * project, and a few other feature bits
+ *
+ * layout for v6.5+
+ */
+ inf->spacc_version = (struct spacc_version_block) {
+ .minor = SPACC_ID_MINOR(reg_val),
+ .major = SPACC_ID_MAJOR(reg_val),
+ .version = (SPACC_ID_MAJOR(reg_val) << 4) |
+ SPACC_ID_MINOR(reg_val),
+ .qos = SPACC_ID_QOS(reg_val),
+ .is_spacc = SPACC_ID_TYPE(reg_val) == SPACC_TYPE_SPACCQOS,
+ .is_pdu = SPACC_ID_TYPE(reg_val) == SPACC_TYPE_PDU,
+ .aux = SPACC_ID_AUX(reg_val),
+ .vspacc_id = SPACC_ID_VIDX(reg_val),
+ .partial = SPACC_ID_PARTIAL(reg_val),
+ .project = SPACC_ID_PROJECT(reg_val),
+ };
+
+ /* try to autodetect */
+ writel(0x80000000, dev + PDU_REG_SPACC_IV_OFFSET);
+
+ if (readl(dev + PDU_REG_SPACC_IV_OFFSET) == 0x80000000)
+ inf->spacc_version.ivimport = 1;
+ else
+ inf->spacc_version.ivimport = 0;
+
+ /*
+ * Read the SPAcc config block (v6.5+) which tells us how many
+ * contexts there are and context page sizes
+ * this register is only available in v6.5 and up
+ */
+ reg_val = readl(dev + PDU_REG_SPACC_CONFIG);
+ inf->spacc_config = (struct spacc_config_block) {
+ SPACC_CFG_CTX_CNT(reg_val),
+ SPACC_CFG_VSPACC_CNT(reg_val),
+ SPACC_CFG_CIPH_CTX_SZ(reg_val),
+ SPACC_CFG_HASH_CTX_SZ(reg_val),
+ SPACC_CFG_DMA_TYPE(reg_val),
+ 0, 0, 0, 0
+ };
+
+ /* CONFIG2 only present in v6.5+ cores */
+ reg_val = readl(dev + PDU_REG_SPACC_CONFIG2);
+ if (inf->spacc_version.qos) {
+ inf->spacc_config.cmd0_fifo_depth =
+ SPACC_CFG_CMD0_FIFO_QOS(reg_val);
+ inf->spacc_config.cmd1_fifo_depth =
+ SPACC_CFG_CMD1_FIFO(reg_val);
+ inf->spacc_config.cmd2_fifo_depth =
+ SPACC_CFG_CMD2_FIFO(reg_val);
+ inf->spacc_config.stat_fifo_depth =
+ SPACC_CFG_STAT_FIFO_QOS(reg_val);
+ } else {
+ inf->spacc_config.cmd0_fifo_depth =
+ SPACC_CFG_CMD0_FIFO(reg_val);
+ inf->spacc_config.stat_fifo_depth =
+ SPACC_CFG_STAT_FIFO(reg_val);
+ }
+
+ /* only read PDU config if it's actually a PDU engine */
+ if (inf->spacc_version.is_pdu) {
+ reg_val = readl(dev + PDU_REG_PDU_CONFIG);
+ inf->pdu_config = (struct pdu_config_block)
+ {SPACC_PDU_CFG_MINOR(reg_val),
+ SPACC_PDU_CFG_MAJOR(reg_val)};
+
+ /* unlock all cores by default */
+ writel(0, dev + PDU_REG_SECURE_LOCK);
+ }
+
+ return 0;
+}
+
+void pdu_to_dev(void __iomem *addr_, uint32_t *src, unsigned long nword)
+{
+ void __iomem *addr = addr_;
+
+ while (nword--) {
+ writel(*src++, addr);
+ addr += 4;
+ }
+}
+
+void pdu_from_dev(u32 *dst, void __iomem *addr_, unsigned long nword)
+{
+ void __iomem *addr = addr_;
+
+ while (nword--) {
+ *dst++ = readl(addr);
+ addr += 4;
+ }
+}
+
+/*
+ * Context key staging to and from the SPAcc registers.
+ *
+ * This driver supports little-endian SPAcc integrations only. The IP can
+ * be synthesized with a big-endian register interface but that configuration
+ * is not supported here and is not detected.
+ *
+ * src/dst are plain byte buffers holding key material in the order the
+ * SPAcc expects to see it and may be unaligned hence using
+ * get_unaligned_le32()/put_unaligned_le32() rather than a u32 cast and
+ * a direct dereference.
+ */
+void pdu_to_dev_s(void __iomem *addr, const unsigned char *src,
+ unsigned long nword)
+{
+ while (nword--) {
+ writel(get_unaligned_le32(src), addr);
+ src += 4;
+ addr += 4;
+ }
+}
+
+void pdu_from_dev_s(unsigned char *dst, void __iomem *addr,
+ unsigned long nword)
+{
+ while (nword--) {
+ put_unaligned_le32(readl(addr), dst);
+ addr += 4;
+ dst += 4;
+ }
+}
+
+void pdu_io_cached_write(struct device *dev, void __iomem *addr,
+ unsigned long val, uint32_t *cache)
+{
+ if (*cache == val) {
+#ifdef CONFIG_CRYPTO_DEV_SPACC_DEBUG_TRACE_IO
+
+ dev_dbg(dev, "pdu: write %.8lx -> %p (cached)\n", val, addr);
+#endif
+ return;
+ }
+
+ *cache = val;
+ writel(val, addr);
+}
+
+/* platform specific DDT routines */
+
+/*
+ * DDT DMA pools are part of per-device in struct spacc_priv (spacc_core.h).
+ * A single global pool set previously gets allocated against whichever
+ * device happened to probe first. Every other instance's DMA then run through
+ * an IOMMU domain that isn't its own and removing that first device destroys
+ * the pools out from under every other still-active instance.
+ * dev_get_drvdata() recovers the right instance's pools from any struct device
+ * belonging to this driver.
+ *
+ * Create a DMA pool for DDT entries, this should help from splitting
+ * pages for DDTs which by default are 520 bytes long otherwise it would
+ * waste 3576 bytes per DDT allocated.
+ * It also maintain a smaller table of 4 entries common for simple jobs
+ * which uses 480 fewer bytes of DMA memory and for good measure another
+ * table for 16 entries saving 384 bytes
+ */
+int pdu_mem_init(struct device *device)
+{
+ struct spacc_priv *priv = dev_get_drvdata(device);
+
+ if (priv->ddt_pool)
+ return 0; /* already setup for this device */
+
+ /* max of 64 DDT entries */
+ priv->ddt_pool = dma_pool_create("spaccddt", device,
+ DDT_MAX_ENTRIES, 8, 0);
+
+ if (!priv->ddt_pool)
+ return -ENOSPC;
+
+#if PDU_MAX_DDT > 16
+ /* max of 16 DDT entries */
+ priv->ddt16_pool = dma_pool_create("spaccddt16", device,
+ DDT_16_ENTRIES, 8, 0);
+ if (!priv->ddt16_pool) {
+ dma_pool_destroy(priv->ddt_pool);
+ priv->ddt_pool = NULL;
+ return -ENOSPC;
+ }
+#else
+ priv->ddt16_pool = priv->ddt_pool;
+#endif
+ /* max of 4 DDT entries */
+ priv->ddt4_pool = dma_pool_create("spaccddt4", device,
+ DDT_4_ENTRIES, 8, 0);
+ if (!priv->ddt4_pool) {
+ dma_pool_destroy(priv->ddt_pool);
+ priv->ddt_pool = NULL;
+#if PDU_MAX_DDT > 16
+ dma_pool_destroy(priv->ddt16_pool);
+#endif
+ priv->ddt16_pool = NULL;
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+/* Destroy this device's pools */
+void pdu_mem_deinit(struct device *device)
+{
+ struct spacc_priv *priv = dev_get_drvdata(device);
+
+ if (!priv->ddt_pool)
+ return; /* never set up, or already torn down */
+
+ dma_pool_destroy(priv->ddt_pool);
+
+#if PDU_MAX_DDT > 16
+ dma_pool_destroy(priv->ddt16_pool);
+#endif
+ dma_pool_destroy(priv->ddt4_pool);
+
+ priv->ddt_pool = NULL;
+ priv->ddt16_pool = NULL;
+ priv->ddt4_pool = NULL;
+}
+
+int pdu_ddt_init(struct device *dev, struct pdu_ddt *ddt, unsigned long limit)
+{
+ struct spacc_priv *priv = dev_get_drvdata(dev);
+ /*
+ * Set the MSB if we want to use an ATOMIC
+ * allocation required for top half processing
+ */
+ int flag = (limit & 0x80000000);
+
+ limit &= 0x7FFFFFFF;
+ if (limit + 1 >= SIZE_MAX / 8) {
+ /* too big to even compute DDT size */
+ return -EINVAL;
+ } else if (limit > PDU_MAX_DDT) {
+ size_t len = 8 * ((size_t)limit + 1);
+
+ ddt->virt = dma_alloc_coherent(dev, len, &ddt->phys,
+ flag ? GFP_ATOMIC : GFP_KERNEL);
+ } else if (limit > 16) {
+ ddt->virt = dma_pool_alloc(priv->ddt_pool, flag ? GFP_ATOMIC :
+ GFP_KERNEL, &ddt->phys);
+ } else if (limit > 4) {
+ ddt->virt = dma_pool_alloc(priv->ddt16_pool, flag ? GFP_ATOMIC :
+ GFP_KERNEL, &ddt->phys);
+ } else {
+ ddt->virt = dma_pool_alloc(priv->ddt4_pool, flag ? GFP_ATOMIC :
+ GFP_KERNEL, &ddt->phys);
+ }
+
+ ddt->dev = dev;
+ ddt->idx = 0;
+ ddt->len = 0;
+ ddt->limit = limit;
+
+ if (!ddt->virt)
+ return -EINVAL;
+#ifdef CONFIG_CRYPTO_DEV_SPACC_DEBUG_TRACE_DDT
+
+ dev_dbg(dev, " DDT[%.8lx]: allocated %lu fragments\n",
+ (unsigned long)ddt->phys, limit);
+#endif
+ return 0;
+}
+
+int pdu_ddt_add(struct device *dev, struct pdu_ddt *ddt, dma_addr_t phys,
+ unsigned long size)
+{
+#ifdef CONFIG_CRYPTO_DEV_SPACC_DEBUG_TRACE_DDT
+
+ dev_dbg(dev, " DDT[%.8lx]: 0x%.8lx size %lu\n",
+ (unsigned long)ddt->phys,
+ (unsigned long)phys, size);
+#endif
+
+ if (ddt->idx == ddt->limit)
+ return -EINVAL;
+
+ ddt->virt[ddt->idx * 2 + 0] = (uint32_t)phys;
+ ddt->virt[ddt->idx * 2 + 1] = size;
+ ddt->virt[ddt->idx * 2 + 2] = 0;
+ ddt->virt[ddt->idx * 2 + 3] = 0;
+
+ ddt->len += size;
+ ++(ddt->idx);
+
+ return 0;
+}
+
+int pdu_ddt_free(struct pdu_ddt *ddt)
+{
+ struct spacc_priv *priv;
+
+ if (ddt->virt) {
+ priv = dev_get_drvdata(ddt->dev);
+
+ if (ddt->limit > PDU_MAX_DDT) {
+ size_t len = 8 * ((size_t)ddt->limit + 1);
+
+ dma_free_coherent(ddt->dev, len, ddt->virt,
+ ddt->phys);
+ } else if (ddt->limit > 16) {
+ dma_pool_free(priv->ddt_pool, ddt->virt, ddt->phys);
+ } else if (ddt->limit > 4) {
+ dma_pool_free(priv->ddt16_pool, ddt->virt, ddt->phys);
+ } else {
+ dma_pool_free(priv->ddt4_pool, ddt->virt, ddt->phys);
+ }
+
+ ddt->virt = NULL;
+ }
+
+ return 0;
+}
diff --git a/drivers/crypto/dwc-spacc/spacc_hal.h b/drivers/crypto/dwc-spacc/spacc_hal.h
new file mode 100644
index 0000000000000..c29535bba54e4
--- /dev/null
+++ b/drivers/crypto/dwc-spacc/spacc_hal.h
@@ -0,0 +1,119 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef SPACC_HAL_H
+#define SPACC_HAL_H
+
+/* maximum number of DDT entries allowed */
+#ifndef PDU_MAX_DDT
+#define PDU_MAX_DDT 64
+#endif
+
+/* platform Generic */
+#define PDU_IRQ_EN_GLBL BIT(31)
+#define PDU_IRQ_EN_VSPACC(x) (1UL << (x))
+#define PDU_IRQ_EN_RNG BIT(16)
+
+#ifndef SPACC_ID_MINOR
+ #define SPACC_ID_MINOR(x) ((x) & 0x0F)
+ #define SPACC_ID_MAJOR(x) (((x) >> 4) & 0x0F)
+ #define SPACC_ID_QOS(x) (((x) >> 8) & 0x01)
+ #define SPACC_ID_TYPE(x) (((x) >> 9) & 0x03)
+ #define SPACC_ID_AUX(x) (((x) >> 11) & 0x01)
+ #define SPACC_ID_VIDX(x) (((x) >> 12) & 0x07)
+ #define SPACC_ID_PARTIAL(x) (((x) >> 15) & 0x01)
+ #define SPACC_ID_PROJECT(x) ((x) >> 16)
+
+ #define SPACC_TYPE_SPACCQOS 0
+ #define SPACC_TYPE_PDU 1
+
+ #define SPACC_CFG_CTX_CNT(x) ((x) & 0x7F)
+ #define SPACC_CFG_RC4_CTX_CNT(x) (((x) >> 8) & 0x7F)
+ #define SPACC_CFG_VSPACC_CNT(x) (((x) >> 16) & 0x0F)
+ #define SPACC_CFG_CIPH_CTX_SZ(x) (((x) >> 20) & 0x07)
+ #define SPACC_CFG_HASH_CTX_SZ(x) (((x) >> 24) & 0x0F)
+ #define SPACC_CFG_DMA_TYPE(x) (((x) >> 28) & 0x03)
+
+ #define SPACC_CFG_CMD0_FIFO_QOS(x) (((x) >> 0) & 0x7F)
+ #define SPACC_CFG_CMD0_FIFO(x) (((x) >> 0) & 0x1FF)
+ #define SPACC_CFG_CMD1_FIFO(x) (((x) >> 8) & 0x7F)
+ #define SPACC_CFG_CMD2_FIFO(x) (((x) >> 16) & 0x7F)
+ #define SPACC_CFG_STAT_FIFO_QOS(x) (((x) >> 24) & 0x7F)
+ #define SPACC_CFG_STAT_FIFO(x) (((x) >> 16) & 0x1FF)
+
+ #define SPACC_PDU_CFG_MINOR(x) ((x) & 0x0F)
+ #define SPACC_PDU_CFG_MAJOR(x) (((x) >> 4) & 0x0F)
+
+ #define PDU_SECURE_LOCK_SPACC(x) (x)
+ #define PDU_SECURE_LOCK_CFG BIT(30)
+ #define PDU_SECURE_LOCK_GLBL BIT(31)
+#endif /* SPACC_ID_MINOR */
+
+struct spacc_version_block {
+ unsigned int minor,
+ major,
+ version,
+ qos,
+ is_spacc,
+ is_pdu,
+ aux,
+ vspacc_id,
+ partial,
+ project,
+ ivimport;
+};
+
+struct spacc_config_block {
+ unsigned int num_ctx,
+ num_vspacc,
+ ciph_ctx_page_size,
+ hash_ctx_page_size,
+ dma_type,
+ cmd0_fifo_depth,
+ cmd1_fifo_depth,
+ cmd2_fifo_depth,
+ stat_fifo_depth;
+};
+
+struct pdu_config_block {
+ unsigned int minor,
+ major;
+};
+
+struct pdu_info {
+ u32 clockrate;
+ struct spacc_version_block spacc_version;
+ struct spacc_config_block spacc_config;
+ struct pdu_config_block pdu_config;
+};
+
+struct pdu_ddt {
+ dma_addr_t phys;
+ u32 *virt;
+ u32 *virt_orig;
+ struct device *dev;
+ unsigned long idx, limit, len;
+};
+
+void pdu_io_cached_write(struct device *dev, void __iomem *addr,
+ unsigned long val, uint32_t *cache);
+void pdu_to_dev(void __iomem *addr, uint32_t *src, unsigned long nword);
+void pdu_from_dev(u32 *dst, void __iomem *addr, unsigned long nword);
+
+/*
+ * Byte-buffer <-> SPAcc context register helpers. Little-endian SPAcc
+ * integrations only -- see the comment above pdu_to_dev_s() in
+ * spacc_hal.c for what that does and does not constrain.
+ */
+void pdu_from_dev_s(unsigned char *dst, void __iomem *addr,
+ unsigned long nword);
+void pdu_to_dev_s(void __iomem *addr, const unsigned char *src,
+ unsigned long nword);
+
+int pdu_mem_init(struct device *device);
+void pdu_mem_deinit(struct device *device);
+int pdu_ddt_init(struct device *dev, struct pdu_ddt *ddt, unsigned long limit);
+int pdu_ddt_add(struct device *dev, struct pdu_ddt *ddt, dma_addr_t phys,
+ unsigned long size);
+int pdu_ddt_free(struct pdu_ddt *ddt);
+int pdu_get_version(void __iomem *dev, struct pdu_info *inf);
+#endif
diff --git a/drivers/crypto/dwc-spacc/spacc_interrupt.c b/drivers/crypto/dwc-spacc/spacc_interrupt.c
new file mode 100644
index 0000000000000..e74188b0c1632
--- /dev/null
+++ b/drivers/crypto/dwc-spacc/spacc_interrupt.c
@@ -0,0 +1,330 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/interrupt.h>
+#include <linux/minmax.h>
+#include <crypto/scatterwalk.h>
+#include <linux/platform_device.h>
+#include "spacc_core.h"
+
+static inline uint32_t _spacc_get_stat_cnt(struct spacc_device *spacc)
+{
+ u32 fifo;
+
+ if (spacc->config.is_qos)
+ fifo = SPACC_FIFO_STAT_STAT_CNT_GET_QOS(readl(spacc->regmap +
+ SPACC_REG_FIFO_STAT));
+ else
+ fifo = SPACC_FIFO_STAT_STAT_CNT_GET(readl(spacc->regmap +
+ SPACC_REG_FIFO_STAT));
+ return fifo;
+}
+
+static int spacc_pop_packets_ex(struct spacc_device *spacc, int *num_popped,
+ unsigned long *lock_flag)
+{
+ int jobs;
+ int ret = -EINPROGRESS;
+ struct spacc_job *job = NULL;
+ u32 cmdstat, swid, spacc_errcode = SPACC_OK;
+ *num_popped = 0;
+
+ while ((jobs = _spacc_get_stat_cnt(spacc))) {
+ while (jobs-- > 0) {
+ /* write the pop register to get the next job */
+ writel(1, spacc->regmap + SPACC_REG_STAT_POP);
+ cmdstat = readl(spacc->regmap + SPACC_REG_STATUS);
+
+ swid = SPACC_STATUS_SW_ID_GET(cmdstat);
+
+ if (swid >= SPACC_MAX_JOBS) {
+ dev_warn(spacc->dptr,
+ "out-of-range swid %u from dropped\n",
+ swid);
+ continue;
+ }
+ if (spacc->job_lookup[swid] == SPACC_JOB_IDX_UNUSED) {
+ dev_warn(spacc->dptr,
+ "stale swid %u dropped\n", swid);
+ continue;
+ }
+
+ job = &spacc->job[spacc->job_lookup[swid]];
+
+ if (!job) {
+ ret = -EIO;
+ goto ERR;
+ }
+
+ spacc->job_lookup[swid] = SPACC_JOB_IDX_UNUSED;
+ spacc_errcode = SPACC_GET_STATUS_RET_CODE(cmdstat);
+
+ switch (spacc_errcode) {
+ case SPACC_ICVFAIL:
+ ret = -EBADMSG;
+ break;
+ case SPACC_MEMERR:
+ ret = -EINVAL;
+ break;
+ case SPACC_BLOCKERR:
+ ret = -EINVAL;
+ break;
+ case SPACC_SECERR:
+ ret = -EIO;
+ break;
+ case SPACC_OK:
+ ret = 0;
+ break;
+ default:
+ dev_err(spacc->dptr, "Invalid SPAcc Error\n");
+ }
+
+ job->job_err = ret;
+
+ if (spacc->autodetect) {
+ job->job_done = 1;
+ wake_up(&job->waitq);
+ }
+ /*
+ * We're done touching the SPAcc hw, so release the
+ * lock across the job callback. It must be reacquired
+ * before continuing to the next iteration.
+ */
+
+ if (job->cb) {
+ spin_unlock_irqrestore(&spacc->lock,
+ *lock_flag);
+ job->cb(spacc, job->cbdata);
+ spin_lock_irqsave(&spacc->lock, *lock_flag);
+ } else {
+ if (!spacc->autodetect) {
+ job->job_done = 1;
+ wake_up(&job->waitq);
+ }
+ }
+
+ (*num_popped)++;
+ }
+ }
+
+ if (!*num_popped)
+ dev_dbg(spacc->dptr, "Failed to pop a single job\n");
+
+ERR:
+ spacc_process_jb(spacc, lock_flag);
+
+ /* reset the WD timer to the original value */
+ if (spacc->op_mode == SPACC_OP_MODE_WD)
+ spacc_set_wd_count(spacc, spacc->config.wd_timer);
+
+ if (*num_popped && spacc->spacc_notify_jobs)
+ spacc->spacc_notify_jobs(spacc);
+
+ return ret;
+}
+
+int spacc_pop_packets(struct spacc_device *spacc, int *num_popped)
+{
+ int err = 0;
+ unsigned long lock_flag;
+
+ spin_lock_irqsave(&spacc->lock, lock_flag);
+ err = spacc_pop_packets_ex(spacc, num_popped, &lock_flag);
+ spin_unlock_irqrestore(&spacc->lock, lock_flag);
+
+ return err;
+}
+
+uint32_t spacc_process_irq(struct spacc_device *spacc)
+{
+ u32 irq_status;
+ int x, cmd_max;
+ unsigned long lock_flag;
+
+ spin_lock_irqsave(&spacc->lock, lock_flag);
+
+ irq_status = readl(spacc->regmap + SPACC_REG_IRQ_STAT);
+
+ /* clear interrupt pin and run registered callback */
+ if (irq_status & SPACC_IRQ_STAT_STAT) {
+ SPACC_IRQ_STAT_CLEAR_STAT(spacc);
+ if (spacc->op_mode == SPACC_OP_MODE_IRQ) {
+ spacc->config.fifo_cnt <<= 2;
+ spacc->config.fifo_cnt = min(spacc->config.fifo_cnt,
+ spacc->config.stat_fifo_depth);
+
+ /* update fifo count to allow more stats to pile up */
+ spacc_irq_stat_enable(spacc, spacc->config.fifo_cnt);
+
+ /* re-enable CMD0 empty interrupt */
+ spacc_irq_cmdx_enable(spacc, 0, 0);
+ }
+
+ /* Re-enable the watchdog interrupt */
+ if (spacc->op_mode == SPACC_OP_MODE_IRQ &&
+ spacc->wd_cnt_limit) {
+ spacc_irq_stat_wd_enable(spacc);
+ spacc->wdcnt = 0;
+ spacc->op_mode = SPACC_OP_MODE_WD;
+ spacc->wd_cnt_limit = false;
+ }
+
+ if (spacc->irq_cb_stat)
+ spacc->irq_cb_stat(spacc);
+ }
+
+ /* watchdog IRQ */
+ if (spacc->op_mode == SPACC_OP_MODE_WD &&
+ irq_status & SPACC_IRQ_STAT_STAT_WD) {
+ if (++spacc->wdcnt == SPACC_WD_LIMIT) {
+ /*
+ * This happens when you get too many IRQs that
+ * go unanswered
+ */
+ spacc_irq_stat_wd_disable(spacc);
+
+ /*
+ * We set the STAT CNT to 1 so that every job
+ * generates an IRQ now
+ */
+ spacc_irq_stat_enable(spacc, 1);
+ spacc->op_mode = SPACC_OP_MODE_IRQ;
+ spacc->wd_cnt_limit = true;
+ } else if (spacc->config.wd_timer < (0xFFFFFFUL >> 4)) {
+ /*
+ * If the timer isn't too high lets bump it up
+ * a bit so as to give the IRQ a chance to
+ * reply
+ */
+ spacc_set_wd_count(spacc,
+ spacc->config.wd_timer << 4);
+ }
+
+ SPACC_IRQ_STAT_CLEAR_STAT_WD(spacc);
+ if (spacc->irq_cb_stat_wd)
+ spacc->irq_cb_stat_wd(spacc);
+ }
+
+ if (spacc->op_mode == SPACC_OP_MODE_IRQ) {
+ cmd_max = (spacc->config.is_qos ? SPACC_CMDX_MAX_QOS :
+ SPACC_CMDX_MAX);
+ for (x = 0; x < cmd_max; x++) {
+ if (irq_status & SPACC_IRQ_STAT_CMDX(x)) {
+ spacc->config.fifo_cnt = 1;
+
+ /* disable CMD0 interrupt since STAT=1 */
+ spacc_irq_cmdx_disable(spacc, x);
+ spacc_irq_stat_enable(spacc,
+ spacc->config.fifo_cnt);
+
+ SPACC_IRQ_STAT_CLEAR_CMDX(spacc, x);
+
+ /* run registered callback */
+ if (spacc->irq_cb_cmdx)
+ spacc->irq_cb_cmdx(spacc, x);
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&spacc->lock, lock_flag);
+
+ return irq_status;
+}
+
+void spacc_set_wd_count(struct spacc_device *spacc, uint32_t val)
+{
+ writel(val, spacc->regmap + SPACC_REG_STAT_WD_CTRL);
+}
+
+/*
+ * cmdx and cmdx_cnt depend on HW config
+ * cmdx can be 0, 1 or 2
+ * cmdx_cnt must be 2^6 or less
+ */
+void spacc_irq_cmdx_enable(struct spacc_device *spacc, int cmdx, int cmdx_cnt)
+{
+ u32 reg_val;
+
+ /* read the reg, clear the bit range and set the new value */
+ reg_val = readl(spacc->regmap + SPACC_REG_IRQ_CTRL) &
+ (~SPACC_IRQ_CTRL_CMDX_CNT_MASK(cmdx));
+ reg_val |= SPACC_IRQ_CTRL_CMDX_CNT_SET(cmdx, cmdx_cnt);
+
+ writel(reg_val | SPACC_IRQ_CTRL_CMDX_CNT_SET(cmdx, cmdx_cnt),
+ spacc->regmap + SPACC_REG_IRQ_CTRL);
+
+ writel(readl(spacc->regmap + SPACC_REG_IRQ_EN) | SPACC_IRQ_EN_CMD(cmdx),
+ spacc->regmap + SPACC_REG_IRQ_EN);
+}
+
+void spacc_irq_cmdx_disable(struct spacc_device *spacc, int cmdx)
+{
+ writel(readl(spacc->regmap + SPACC_REG_IRQ_EN) &
+ (~SPACC_IRQ_EN_CMD(cmdx)), spacc->regmap + SPACC_REG_IRQ_EN);
+}
+
+void spacc_irq_stat_enable(struct spacc_device *spacc, int stat_cnt)
+{
+ u32 reg_val;
+
+ reg_val = readl(spacc->regmap + SPACC_REG_IRQ_CTRL);
+ if (spacc->config.is_qos) {
+ reg_val &= (~SPACC_IRQ_CTRL_STAT_CNT_MASK_QOS);
+ reg_val |= SPACC_IRQ_CTRL_STAT_CNT_SET_QOS(stat_cnt);
+ } else {
+ reg_val &= (~SPACC_IRQ_CTRL_STAT_CNT_MASK);
+ reg_val |= SPACC_IRQ_CTRL_STAT_CNT_SET(stat_cnt);
+ }
+
+ writel(reg_val, spacc->regmap + SPACC_REG_IRQ_CTRL);
+ writel(readl(spacc->regmap + SPACC_REG_IRQ_EN) | SPACC_IRQ_EN_STAT,
+ spacc->regmap + SPACC_REG_IRQ_EN);
+}
+
+void spacc_irq_stat_disable(struct spacc_device *spacc)
+{
+ writel(readl(spacc->regmap + SPACC_REG_IRQ_EN) & (~SPACC_IRQ_EN_STAT),
+ spacc->regmap + SPACC_REG_IRQ_EN);
+}
+
+void spacc_irq_stat_wd_enable(struct spacc_device *spacc)
+{
+ writel(readl(spacc->regmap + SPACC_REG_IRQ_EN) | SPACC_IRQ_EN_STAT_WD,
+ spacc->regmap + SPACC_REG_IRQ_EN);
+}
+
+void spacc_irq_stat_wd_disable(struct spacc_device *spacc)
+{
+ writel(readl(spacc->regmap + SPACC_REG_IRQ_EN) &
+ (~SPACC_IRQ_EN_STAT_WD), spacc->regmap + SPACC_REG_IRQ_EN);
+}
+
+void spacc_irq_glbl_enable(struct spacc_device *spacc)
+{
+ writel(readl(spacc->regmap + SPACC_REG_IRQ_EN) | SPACC_IRQ_EN_GLBL,
+ spacc->regmap + SPACC_REG_IRQ_EN);
+}
+
+void spacc_irq_glbl_disable(struct spacc_device *spacc)
+{
+ writel(readl(spacc->regmap + SPACC_REG_IRQ_EN) & (~SPACC_IRQ_EN_GLBL),
+ spacc->regmap + SPACC_REG_IRQ_EN);
+}
+
+/* Function to run callbacks in the IRQ handler */
+irqreturn_t spacc_irq_handler(int irq, void *dev)
+{
+ struct spacc_priv *priv = platform_get_drvdata(to_platform_device(dev));
+ struct spacc_device *spacc = &priv->spacc;
+
+ if (spacc->config.oldtimer != spacc->config.timer) {
+ spacc->config.wd_timer = spacc->config.timer;
+ spacc_set_wd_count(spacc, spacc->config.wd_timer);
+ spacc->config.oldtimer = spacc->config.timer;
+ }
+
+ /* check irq flags and process as required */
+ if (!spacc_process_irq(spacc))
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+}
diff --git a/drivers/crypto/dwc-spacc/spacc_manager.c b/drivers/crypto/dwc-spacc/spacc_manager.c
new file mode 100644
index 0000000000000..779a8ce3d3452
--- /dev/null
+++ b/drivers/crypto/dwc-spacc/spacc_manager.c
@@ -0,0 +1,649 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/minmax.h>
+#include <crypto/skcipher.h>
+#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include "spacc_core.h"
+
+/* Prevent reading past the end of the buffer */
+static void spacc_read_from_buf(unsigned char *dst, unsigned char *src,
+ int off, int n, int buflen)
+{
+ if (!dst)
+ return;
+
+ while (n > 0 && (off < buflen)) {
+ *dst++ = src[off++];
+ --n;
+ }
+}
+
+static void spacc_write_to_buf(unsigned char *dst, const unsigned char *src,
+ int off, int n, int buflen)
+{
+ if (!src)
+ return;
+
+ while (n > 0 && (off < buflen)) {
+ dst[off++] = *src++;
+ --n;
+ }
+}
+
+/*
+ * This is not meant to be called directly, it should be called
+ * from the job manager
+ */
+static int spacc_ctx_request(struct spacc_device *spacc,
+ int ctx_id, int ncontig)
+{
+ int ret = 0;
+ int x, y, count;
+
+ if (!spacc)
+ return -EINVAL;
+
+ if (ctx_id > spacc->config.num_ctx)
+ return -EINVAL;
+
+ if (ncontig < 1 || ncontig > spacc->config.num_ctx)
+ return -EINVAL;
+
+ /*
+ * Allocating scheme, look for contiguous contexts.
+ * Free contexts have a ref_cnt of 0.
+ * If specific ctx_id is requested, test the ncontig
+ * and then bump the ref_cnt
+ */
+ if (ctx_id != -1) {
+ if ((&spacc->ctx[ctx_id])->ncontig != ncontig - 1)
+ ret = -1;
+ goto NO_FREE_CTX;
+ }
+
+ /*
+ * Check to see if ncontig are free
+ * loop over all available contexts to find the first
+ * ncontig empty ones
+ */
+ for (x = 0; x <= (spacc->config.num_ctx - ncontig); ) {
+ count = ncontig;
+ while (count) {
+ if ((&spacc->ctx[x + count - 1])->ref_cnt != 0) {
+ /*
+ * Increment x to past failed count
+ * location
+ */
+ x += count;
+ break;
+ }
+ count--;
+ }
+
+ if (count != 0)
+ ret = -1;
+ else {
+ ctx_id = x;
+ ret = 0;
+ break;
+ }
+ }
+
+NO_FREE_CTX:
+
+ if (ret == 0) {
+ /* ctx_id is good so mark used */
+ for (y = 0; y < ncontig; y++)
+ (&spacc->ctx[ctx_id + y])->ref_cnt++;
+ (&spacc->ctx[ctx_id])->ncontig = ncontig - 1;
+ } else
+ ctx_id = -1;
+
+ return ctx_id;
+}
+
+static int spacc_ctx_release(struct spacc_device *spacc, int ctx_id)
+{
+ int y;
+ int ncontig;
+
+ if (ctx_id < 0 || ctx_id > spacc->config.num_ctx)
+ return -EINVAL;
+
+ /* release the base context and contiguous block */
+ ncontig = (&spacc->ctx[ctx_id])->ncontig;
+ for (y = 0; y <= ncontig; y++) {
+ if ((&spacc->ctx[ctx_id + y])->ref_cnt > 0)
+ (&spacc->ctx[ctx_id + y])->ref_cnt--;
+ }
+
+ if ((&spacc->ctx[ctx_id])->ref_cnt == 0) {
+ (&spacc->ctx[ctx_id])->ncontig = 0;
+
+#ifdef CONFIG_CRYPTO_DEV_SPACC_SECURE_MODE
+ /*
+ * TODO: This driver works in harmony with "normal" kernel
+ * processes so we release the context all the time
+ * normally this would be done from a "secure" kernel process
+ * (trustzone/etc). This hack is so that SPACC.0
+ * cores can both use the same context space.
+ */
+ writel(ctx_id, spacc->regmap + SPACC_REG_SECURE_RELEASE);
+#endif
+ /*
+ * Now, release the hardware context back to the pool by
+ * incrementing the semaphore count.
+ * This will wake up one sleeping task, if any.
+ */
+ up(&spacc->ctx_sem);
+ }
+
+ return 0;
+}
+
+/* Job init: will initialize all job data, pointers, etc */
+void spacc_job_init_all(struct spacc_device *spacc)
+{
+ int x;
+ struct spacc_job *job;
+
+ for (x = 0; x < (SPACC_MAX_JOBS); x++) {
+ job = &spacc->job[x];
+ memset(job, 0, sizeof(struct spacc_job));
+
+ job->job_swid = SPACC_JOB_IDX_UNUSED;
+ job->job_used = SPACC_JOB_IDX_UNUSED;
+ spacc->job_lookup[x] = SPACC_JOB_IDX_UNUSED;
+ init_waitqueue_head(&job->waitq);
+ }
+}
+
+/* Get a new job id and use a specific ctx_idx or -1 for a new one */
+int spacc_job_request(struct spacc_device *spacc, int ctx_idx)
+{
+ int x, ret = 0;
+ struct spacc_job *job;
+ unsigned long lock_flag;
+
+ if (!spacc)
+ return -EINVAL;
+
+ spin_lock_irqsave(&spacc->lock, lock_flag);
+
+ /* find the first available job id */
+ for (x = 0; x < SPACC_MAX_JOBS; x++) {
+ job = &spacc->job[x];
+ if (job->job_used == SPACC_JOB_IDX_UNUSED) {
+ job->job_used = x;
+ break;
+ }
+ }
+
+ if (x == SPACC_MAX_JOBS)
+ ret = -1;
+ else {
+ /* associate a single context to go with job */
+ ret = spacc_ctx_request(spacc, ctx_idx, 1);
+ if (ret != -1) {
+ job->ctx_idx = ret;
+ ret = x;
+ } else
+ job->job_used = SPACC_JOB_IDX_UNUSED;
+ }
+
+ spin_unlock_irqrestore(&spacc->lock, lock_flag);
+
+ return ret;
+}
+
+int spacc_job_release(struct spacc_device *spacc, int job_idx)
+{
+ int ret = 0;
+ struct spacc_job *job;
+ unsigned long lock_flag;
+
+ if (!spacc)
+ return -EINVAL;
+
+ if (job_idx < 0 || job_idx >= SPACC_MAX_JOBS)
+ return -EINVAL;
+
+ spin_lock_irqsave(&spacc->lock, lock_flag);
+
+ job = &spacc->job[job_idx];
+
+ /*
+ * If this job was actually submitted to hardware (job_swid is only
+ * ever set inside spacc_packet_enqueue_ddt()), job_lookup[] may
+ * still be pointing at this slot -- e.g. the caller is releasing
+ * it before its completion was ever popped off the STAT FIFO
+ * (software abort / enqueue-failure cleanup). Leaving that mapping
+ * in place lets a delayed hardware completion for the old swid
+ * find and misattribute itself to whatever unrelated job later
+ * reuses this slot. Only clear it if it still points at us --
+ * it may equally have already been cleared by a normal completion
+ * pop, or reassigned to a different job that has since reused the
+ * same swid, and we must not clobber that.
+ */
+ if (job->job_swid < SPACC_MAX_JOBS &&
+ spacc->job_lookup[job->job_swid] == job_idx)
+ spacc->job_lookup[job->job_swid] = SPACC_JOB_IDX_UNUSED;
+
+ /* release context that goes with job */
+ ret = spacc_ctx_release(spacc, job->ctx_idx);
+ job->ctx_idx = SPACC_CTX_IDX_UNUSED;
+ job->job_used = SPACC_JOB_IDX_UNUSED;
+ /* disable any callback */
+ job->cb = NULL;
+
+ /* NOTE: this leaves ctrl data in memory */
+ spin_unlock_irqrestore(&spacc->lock, lock_flag);
+
+ return ret;
+}
+
+/* Return a context structure for a job idx or null if invalid */
+struct spacc_ctx *spacc_context_lookup_by_job(struct spacc_device *spacc,
+ int job_idx)
+{
+ if (job_idx < 0 || job_idx >= SPACC_MAX_JOBS)
+ return NULL;
+
+ return &spacc->ctx[(&spacc->job[job_idx])->ctx_idx];
+}
+
+int spacc_process_jb(struct spacc_device *spacc, unsigned long *lock_flag)
+{
+ int tail;
+ int ret = 0;
+ struct spacc_job *job;
+
+ /* are there jobs in the buffer? */
+ while (spacc->jb_head != spacc->jb_tail) {
+ tail = spacc->jb_tail;
+
+ if (spacc->job_buffer[tail].active) {
+ ret = spacc_packet_enqueue_ddt_ex
+ (spacc, 0, spacc->job_buffer[tail].job_idx,
+ spacc->job_buffer[tail].src,
+ spacc->job_buffer[tail].dst,
+ spacc->job_buffer[tail].proc_sz,
+ spacc->job_buffer[tail].aad_offset,
+ spacc->job_buffer[tail].pre_aad_sz,
+ spacc->job_buffer[tail].post_aad_sz,
+ spacc->job_buffer[tail].iv_offset,
+ spacc->job_buffer[tail].prio, lock_flag);
+
+ if (ret == -EBUSY)
+ return -EBUSY;
+
+ spacc->job_buffer[tail].active = 0;
+
+ if (ret != 0) {
+ job = &spacc->job[
+ spacc->job_buffer[tail].job_idx];
+ job->job_err = ret;
+
+ if (spacc->autodetect) {
+ job->job_done = 1;
+ wake_up_interruptible(&job->waitq);
+ }
+
+ if (job->cb) {
+ spin_unlock_irqrestore(&spacc->lock,
+ *lock_flag);
+ job->cb(spacc, job->cbdata);
+ spin_lock_irqsave(&spacc->lock,
+ *lock_flag);
+ tail = spacc->jb_tail;
+ } else if (!spacc->autodetect) {
+ job->job_done = 1;
+ wake_up_interruptible(&job->waitq);
+ }
+ }
+ }
+
+ tail++;
+ if (tail == SPACC_MAX_JOB_BUFFERS)
+ tail = 0;
+
+ spacc->jb_tail = tail;
+ }
+
+ return 0;
+}
+
+/* Write appropriate context data which depends on operation and mode */
+int spacc_write_context(struct spacc_device *spacc, int job_idx, int op,
+ const unsigned char *key, int ksz,
+ const unsigned char *iv, int ivsz)
+{
+ int buflen;
+ int ret = 0;
+ unsigned char buf[300] __aligned(sizeof(u32));
+ struct spacc_ctx *ctx = NULL;
+ struct spacc_job *job = NULL;
+
+ if (job_idx < 0 || job_idx >= SPACC_MAX_JOBS)
+ return -EINVAL;
+
+ job = &spacc->job[job_idx];
+ ctx = spacc_context_lookup_by_job(spacc, job_idx);
+
+ if (!job || !ctx)
+ return -EIO;
+
+ switch (op) {
+ case SPACC_CRYPTO_OPERATION:
+ /*
+ * Get page size and then read so we can do a
+ * read-modify-write cycle
+ */
+ buflen = min(sizeof(buf),
+ (unsigned int)spacc->config.ciph_page_size);
+
+ pdu_from_dev_s(buf, ctx->ciph_key, buflen >> 2);
+
+ switch (job->enc_mode) {
+ case CRYPTO_MODE_SM4_ECB:
+ case CRYPTO_MODE_SM4_CBC:
+ case CRYPTO_MODE_SM4_CFB:
+ case CRYPTO_MODE_SM4_OFB:
+ case CRYPTO_MODE_SM4_CTR:
+ case CRYPTO_MODE_SM4_CCM:
+ case CRYPTO_MODE_SM4_GCM:
+ case CRYPTO_MODE_SM4_CS1:
+ case CRYPTO_MODE_SM4_CS2:
+ case CRYPTO_MODE_SM4_CS3:
+ case CRYPTO_MODE_AES_ECB:
+ case CRYPTO_MODE_AES_CBC:
+ case CRYPTO_MODE_AES_CS1:
+ case CRYPTO_MODE_AES_CS2:
+ case CRYPTO_MODE_AES_CS3:
+ case CRYPTO_MODE_AES_CFB:
+ case CRYPTO_MODE_AES_OFB:
+ case CRYPTO_MODE_AES_CTR:
+ case CRYPTO_MODE_AES_CCM:
+ case CRYPTO_MODE_AES_GCM:
+ spacc_write_to_buf(buf, key, 0, ksz, buflen);
+ if (iv) {
+ unsigned char one[4] = { 0, 0, 0, 1 };
+ unsigned long enc1, enc2;
+
+ enc1 = CRYPTO_MODE_AES_GCM;
+ enc2 = CRYPTO_MODE_SM4_GCM;
+
+ spacc_write_to_buf(buf, iv, 32, ivsz, buflen);
+ if (ivsz == 12 &&
+ (job->enc_mode == enc1 ||
+ job->enc_mode == enc2))
+ spacc_write_to_buf(buf, one, 11 * 4, 4,
+ buflen);
+ }
+ break;
+ case CRYPTO_MODE_SM4_F8:
+ case CRYPTO_MODE_AES_F8:
+ if (key) {
+ spacc_write_to_buf(buf, key + ksz, 0, ksz,
+ buflen);
+ spacc_write_to_buf(buf, key, 48, ksz, buflen);
+ }
+ spacc_write_to_buf(buf, iv, 32, 16, buflen);
+ break;
+ case CRYPTO_MODE_SM4_XTS:
+ case CRYPTO_MODE_AES_XTS:
+ if (key) {
+ spacc_write_to_buf(buf, key, 0,
+ ksz >> 1, buflen);
+ spacc_write_to_buf(buf, key + (ksz >> 1), 48,
+ ksz >> 1, buflen);
+ /*
+ * Divide by two since that's
+ * what we program the hardware
+ */
+ ksz = ksz >> 1;
+ }
+ spacc_write_to_buf(buf, iv, 32, 16, buflen);
+ break;
+ case CRYPTO_MODE_MULTI2_ECB:
+ case CRYPTO_MODE_MULTI2_CBC:
+ case CRYPTO_MODE_MULTI2_OFB:
+ case CRYPTO_MODE_MULTI2_CFB:
+ spacc_write_to_buf(buf, key, 0, ksz, buflen);
+ spacc_write_to_buf(buf, iv, 0x28, ivsz, buflen);
+ if (ivsz <= 8) {
+ /* default to 128 rounds */
+ unsigned char rounds[4] = { 0, 0, 0, 128};
+
+ spacc_write_to_buf(buf, rounds, 0x30, 4,
+ buflen);
+ }
+ break;
+ case CRYPTO_MODE_3DES_CBC:
+ case CRYPTO_MODE_3DES_ECB:
+ case CRYPTO_MODE_DES_CBC:
+ case CRYPTO_MODE_DES_ECB:
+ spacc_write_to_buf(buf, iv, 0, 8, buflen);
+ spacc_write_to_buf(buf, key, 8, ksz, buflen);
+ break;
+ case CRYPTO_MODE_KASUMI_ECB:
+ case CRYPTO_MODE_KASUMI_F8:
+ spacc_write_to_buf(buf, iv, 16, 8, buflen);
+ spacc_write_to_buf(buf, key, 0, 16, buflen);
+ break;
+ case CRYPTO_MODE_SNOW3G_UEA2:
+ case CRYPTO_MODE_ZUC_UEA3:
+ spacc_write_to_buf(buf, key, 0, 32, buflen);
+ break;
+ case CRYPTO_MODE_CHACHA20_STREAM:
+ case CRYPTO_MODE_CHACHA20_POLY1305:
+ spacc_write_to_buf(buf, key, 0, ksz, buflen);
+ spacc_write_to_buf(buf, iv, 32, ivsz, buflen);
+ break;
+ case CRYPTO_MODE_NULL:
+ break;
+ }
+
+ if (key) {
+ job->ckey_sz = SPACC_SET_CIPHER_KEY_SZ(ksz);
+ job->first_use = true;
+ }
+ pdu_to_dev_s(ctx->ciph_key, buf, buflen >> 2);
+ break;
+
+ case SPACC_HASH_OPERATION:
+ /*
+ * Get page size and then read so we can do a
+ * read-modify-write cycle
+ */
+ buflen = min(sizeof(buf),
+ (u32)spacc->config.hash_page_size);
+ pdu_from_dev_s(buf, ctx->hash_key, buflen >> 2);
+
+ switch (job->hash_mode) {
+ case CRYPTO_MODE_MAC_XCBC:
+ case CRYPTO_MODE_MAC_SM4_XCBC:
+ if (key) {
+ spacc_write_to_buf(buf, key + (ksz - 32),
+ 32, 32, buflen);
+ spacc_write_to_buf(buf, key, 0, (ksz - 32),
+ buflen);
+ job->hkey_sz = SPACC_SET_HASH_KEY_SZ(ksz - 32);
+ }
+ break;
+ case CRYPTO_MODE_HASH_CRC32:
+ case CRYPTO_MODE_MAC_SNOW3G_UIA2:
+ case CRYPTO_MODE_MAC_ZUC_UIA3:
+ if (key) {
+ spacc_write_to_buf(buf, key, 0, ksz, buflen);
+ job->hkey_sz = SPACC_SET_HASH_KEY_SZ(ksz);
+ }
+ break;
+ case CRYPTO_MODE_MAC_POLY1305:
+ spacc_write_to_buf(buf, key, 0, ksz, buflen);
+ spacc_write_to_buf(buf, iv, 32, ivsz, buflen);
+ break;
+ case CRYPTO_MODE_HASH_CSHAKE128:
+ case CRYPTO_MODE_HASH_CSHAKE256:
+ /* use "iv" and "key" to pass s-string & n-string */
+ spacc_write_to_buf(buf, iv, 0, ivsz, buflen);
+ spacc_write_to_buf(buf, key,
+ spacc->config.string_size, ksz, buflen);
+ break;
+ case CRYPTO_MODE_MAC_KMAC128:
+ case CRYPTO_MODE_MAC_KMAC256:
+ case CRYPTO_MODE_MAC_KMACXOF128:
+ case CRYPTO_MODE_MAC_KMACXOF256:
+ /* use "iv" and "key" to pass s-string & key */
+ spacc_write_to_buf(buf, iv, 0, ivsz, buflen);
+ spacc_write_to_buf(buf, key,
+ spacc->config.string_size, ksz,
+ buflen);
+ job->hkey_sz = SPACC_SET_HASH_KEY_SZ(ksz);
+ break;
+ default:
+ if (key) {
+ job->hkey_sz = SPACC_SET_HASH_KEY_SZ(ksz);
+ spacc_write_to_buf(buf, key, 0, ksz, buflen);
+ }
+ }
+ pdu_to_dev_s(ctx->hash_key, buf, buflen >> 2);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+int spacc_read_context(struct spacc_device *spacc, int job_idx,
+ int op, unsigned char *key, int ksz,
+ unsigned char *iv, int ivsz)
+{
+ int buflen;
+ int ret = 0;
+ unsigned char buf[300] __aligned(sizeof(u32));
+ struct spacc_ctx *ctx = NULL;
+ struct spacc_job *job = NULL;
+
+ if (job_idx < 0 || job_idx >= SPACC_MAX_JOBS)
+ return -EINVAL;
+
+ job = &spacc->job[job_idx];
+ ctx = spacc_context_lookup_by_job(spacc, job_idx);
+
+ if (!ctx)
+ return -EIO;
+
+ switch (op) {
+ case SPACC_CRYPTO_OPERATION:
+ buflen = min(sizeof(buf),
+ (u32)spacc->config.ciph_page_size);
+ pdu_from_dev_s(buf, ctx->ciph_key, buflen >> 2);
+
+ switch (job->enc_mode) {
+ case CRYPTO_MODE_SM4_ECB:
+ case CRYPTO_MODE_SM4_CBC:
+ case CRYPTO_MODE_SM4_CFB:
+ case CRYPTO_MODE_SM4_OFB:
+ case CRYPTO_MODE_SM4_CTR:
+ case CRYPTO_MODE_SM4_CCM:
+ case CRYPTO_MODE_SM4_GCM:
+ case CRYPTO_MODE_SM4_CS1:
+ case CRYPTO_MODE_SM4_CS2:
+ case CRYPTO_MODE_SM4_CS3:
+ case CRYPTO_MODE_AES_ECB:
+ case CRYPTO_MODE_AES_CBC:
+ case CRYPTO_MODE_AES_CS1:
+ case CRYPTO_MODE_AES_CS2:
+ case CRYPTO_MODE_AES_CS3:
+ case CRYPTO_MODE_AES_CFB:
+ case CRYPTO_MODE_AES_OFB:
+ case CRYPTO_MODE_AES_CTR:
+ case CRYPTO_MODE_AES_CCM:
+ case CRYPTO_MODE_AES_GCM:
+ spacc_read_from_buf(key, buf, 0, ksz, buflen);
+ spacc_read_from_buf(iv, buf, 32, 16, buflen);
+ break;
+ case CRYPTO_MODE_CHACHA20_STREAM:
+ spacc_read_from_buf(key, buf, 0, ksz, buflen);
+ spacc_read_from_buf(iv, buf, 32, 16, buflen);
+ break;
+ case CRYPTO_MODE_SM4_F8:
+ case CRYPTO_MODE_AES_F8:
+ if (key) {
+ spacc_read_from_buf(key + ksz, buf, 0, ksz,
+ buflen);
+ spacc_read_from_buf(key, buf, 48, ksz, buflen);
+ }
+ spacc_read_from_buf(iv, buf, 32, 16, buflen);
+ break;
+ case CRYPTO_MODE_SM4_XTS:
+ case CRYPTO_MODE_AES_XTS:
+ if (key) {
+ spacc_read_from_buf(key, buf, 0, ksz >> 1,
+ buflen);
+ spacc_read_from_buf(key + (ksz >> 1), buf,
+ 48, ksz >> 1, buflen);
+ }
+ spacc_read_from_buf(iv, buf, 32, 16, buflen);
+ break;
+ case CRYPTO_MODE_MULTI2_ECB:
+ case CRYPTO_MODE_MULTI2_CBC:
+ case CRYPTO_MODE_MULTI2_OFB:
+ case CRYPTO_MODE_MULTI2_CFB:
+ spacc_read_from_buf(key, buf, 0, ksz, buflen);
+ /* number of rounds at the end of the IV */
+ spacc_read_from_buf(iv, buf, 0x28, ivsz, buflen);
+ break;
+ case CRYPTO_MODE_3DES_CBC:
+ case CRYPTO_MODE_3DES_ECB:
+ spacc_read_from_buf(iv, buf, 0, 8, buflen);
+ spacc_read_from_buf(key, buf, 8, 24, buflen);
+ break;
+ case CRYPTO_MODE_DES_CBC:
+ case CRYPTO_MODE_DES_ECB:
+ spacc_read_from_buf(iv, buf, 0, 8, buflen);
+ spacc_read_from_buf(key, buf, 8, 8, buflen);
+ break;
+ case CRYPTO_MODE_KASUMI_ECB:
+ case CRYPTO_MODE_KASUMI_F8:
+ spacc_read_from_buf(iv, buf, 16, 8, buflen);
+ spacc_read_from_buf(key, buf, 0, 16, buflen);
+ break;
+ case CRYPTO_MODE_SNOW3G_UEA2:
+ case CRYPTO_MODE_ZUC_UEA3:
+ spacc_read_from_buf(key, buf, 0, 32, buflen);
+ break;
+ case CRYPTO_MODE_NULL:
+ break;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+/* Context manager: This will reset all reference counts, pointers, etc */
+void spacc_ctx_init_all(struct spacc_device *spacc)
+{
+ int x;
+ struct spacc_ctx *ctx;
+
+ /* initialize contexts */
+ for (x = 0; x < spacc->config.num_ctx; x++) {
+ ctx = &spacc->ctx[x];
+
+ /* sets everything including ref_cnt and ncontig to 0 */
+ memset(ctx, 0, sizeof(*ctx));
+
+ ctx->ciph_key = spacc->regmap + SPACC_CTX_CIPH_KEY +
+ (x * spacc->config.ciph_page_size);
+ ctx->hash_key = spacc->regmap + SPACC_CTX_HASH_KEY +
+ (x * spacc->config.hash_page_size);
+ }
+}
--
2.25.1
^ permalink raw reply related
* [PATCH v17 1/4] dt-bindings: crypto: Document support for SPAcc
From: Pavitrakumar Managutte @ 2026-07-20 11:37 UTC (permalink / raw)
To: linux-crypto, linux-kernel, devicetree, herbert, robh
Cc: krzk, conor+dt, ruud.derwig, rbannerm, manjunath.hadli, adityak,
navami.telsang, bhoomikak, nazim.khan, Pavitrakumar Managutte
In-Reply-To: <20260720113740.64960-1-pavitrakumarm@vayavyalabs.com>
Add DT bindings related to the SPAcc driver for Documentation.
DWC Synopsys Security Protocol Accelerator(SPAcc) Hardware Crypto
Engine is a crypto IP designed by Synopsys.
Co-developed-by: Bhoomika Kadabi <bhoomikak@vayavyalabs.com>
Signed-off-by: Bhoomika Kadabi <bhoomikak@vayavyalabs.com>
Acked-by: Ross Bannerman <rbannerm@synopsys.com>
Signed-off-by: Pavitrakumar Managutte <pavitrakumarm@vayavyalabs.com>
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
---
.../bindings/crypto/snps,dwc-spacc.yaml | 50 +++++++++++++++++++
1 file changed, 50 insertions(+)
create mode 100644 Documentation/devicetree/bindings/crypto/snps,dwc-spacc.yaml
diff --git a/Documentation/devicetree/bindings/crypto/snps,dwc-spacc.yaml b/Documentation/devicetree/bindings/crypto/snps,dwc-spacc.yaml
new file mode 100644
index 0000000000000..fe33ea361a8e1
--- /dev/null
+++ b/Documentation/devicetree/bindings/crypto/snps,dwc-spacc.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/crypto/snps,dwc-spacc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synopsys DesignWare Security Protocol Accelerator(SPAcc) Crypto Engine
+
+maintainers:
+ - Ross Bannerman <rbannerm@synopsys.com>
+
+description: |
+ The Synopsys DWC Security Protocol Accelerator (SPAcc), which is a
+ semiconductor IP designed to accelerate cryptographic operations,
+ such as encryption, decryption, and hashing.
+
+ In this configuration, the SPAcc IP is instantiated within the Synopsys
+ NSIMOSCI virtual SoC platform, a SystemC simulation environment used for
+ software development and testing. The device is accessed as a memory-mapped
+ peripheral and generates interrupts to the ARC interrupt controller.
+
+properties:
+ compatible:
+ items:
+ - const: snps,nsimosci-hs-spacc
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+additionalProperties: false
+
+examples:
+ - |
+ crypto@40000000 {
+ compatible = "snps,nsimosci-hs-spacc";
+ reg = <0x40000000 0x3ffff>;
+ interrupts = <28>;
+ clocks = <&clock>;
+ };
--
2.25.1
^ permalink raw reply related
* [PATCH v17 0/4] crypto: spacc - Add SPAcc Crypto Driver
From: Pavitrakumar Managutte @ 2026-07-20 11:37 UTC (permalink / raw)
To: linux-crypto, linux-kernel, devicetree, herbert, robh
Cc: krzk, conor+dt, ruud.derwig, rbannerm, manjunath.hadli, adityak,
navami.telsang, bhoomikak, nazim.khan, Pavitrakumar Managutte
Add the driver for SPAcc(Security Protocol Accelerator), which is a
crypto acceleration IP from Synopsys. The SPAcc supports multiple ciphers,
hashes and AEAD algorithms with various modes. The driver currently supports
below
hash:
- cmac(aes)
- xcbc(aes)
- cmac(sm4)
- xcbc(sm4)
- hmac(md5)
- md5
- hmac(sha1)
- sha1
- sha224
- sha256
- sha384
- sha512
- hmac(sha224)
- hmac(sha256)
- hmac(sha384)
- hmac(sha512)
- sha3-224
- sha3-256
- sha3-384
- sha3-512
changelog:
v1->v2 changes:
- Added local_bh_disable() and local_bh_enable() for the below calls.
a. for ciphers skcipher_request_complete()
b. for aead aead_request_complete()
c. for hash ahash_request_complete()
- dt-bindings updates
a. removed snps,vspacc-priority and made it into config option
b. renamed snps,spacc-wdtimer to snps,spacc-internal-counter
c. Added description to all properties
- Updated corresponding dt-binding changes to code
v2->v3 changes:
- cra_init and cra_exit replaced with init_tfm and exit_tfm for hashes.
- removed mutex_lock/unlock for spacc_skcipher_fallback call
- dt-bindings updates
a. updated SOC related information
b. renamed compatible string as per SOC
- Updated corresponding dt-binding changes to code
v3->v4 changes:
- removed snps,vspacc-id from the dt-bindings
- removed mutex_lock from ciphers
- replaced magic numbers with macros
- removed sw_fb variable from struct mode_tab and associated code from the
hashes
- polling code is replaced by wait_event_interruptible
v4->v5 changes:
- Updated to register with the crypto-engine
- Used semaphore to manage SPAcc device hardware context pool
- This patchset supports Hashes only
- Dropping the support for Ciphers and AEADs in this patchset
- Added Reviewed-by tag on the Device tree patch since it was reviewed on
v4 patch by Krzysztof Kozlowski and Rob Herring (Arm)
v5->v6 changes:
- Removed CRYPTO_DEV_SPACC_CIPHER and CRYPTO_DEV_SPACC_AEAD Kconfig options,
since the cipher and aead support is not part of this patchset
- Dropped spacc_skcipher.o and spacc_aead.o from Makefile to fix build errors
reported by kernel test robot
- Added Reported-by and Closes tags as suggested
v6->v7 changes:
- Fixed build error reported by Kernel test robot
- Added Reported-by and Closes tags as suggested
v7->v8 changes:
- Fixed misleading comment: Clarified that only HMAC key pre-processing
is done in software, while the actual HMAC operation is performed by
hardware
- Simplified do_shash() function signature by removing unused parameters
- Updated all do_shash() call sites to use new simplified signature
- Fixed commit message formatting by adding "crypto: spacc - <subject>" to
all patches
- used __free() for scope based resource management
v8->v9 changes:
- Updated the software fallback implementation to use HASH_FBREQ_ON_STACK
- Corrected dynamic allocation of statesize and reqsize in init_tfm
- Fixed synchronization issues in the digest request
v9->v10 changes:
- Fixed unused variable warning
v10->v11 changes:
- Removed the redundant crypto_alloc_ahash in the init_tfm function
- Removed the redundant crypto_free_ahash in exit_tfm function
- Removed the redundant crypto_ahash_setkey call in setkey function
v11->v12 changes:
- Removed do_shash() and switched to lib/crypto API in spacc_hash_setkey
- Dropped support for SM3 algorithm
- Improved multi-device safety by encapsulating handling within priv
- Added memzero_explicit() in sensitive paths
- Minor code cleanups and style fixes
- Algorithm registration cleanups
v12->v13 changes:
- Removed all the sleep function from setkey function
- Added shash implemntation for aes algorthims
v13->v14 changes:
-Added fixes based on the reports by Sashiko
-Removed the spacc_is_mode_keysize_supported call from do_one_request
v14->v15 changes:
-Added fixes based on the reports by Sashiko on 19/jun/2026
-Fixed styling in the Kconfig
v15->v16 changes:
-Added fixes based on the reports by Sashiko
v16->v17 changes:
-Added fixes based on the reports by Sashiko
Pavitrakumar Managutte (4):
dt-bindings: crypto: Document support for SPAcc
crypto: spacc - Add SPAcc ahash support
crypto: spacc - Add SPAcc AUTODETECT Support
crypto: spacc - Add SPAcc Kconfig and Makefile
.../bindings/crypto/snps,dwc-spacc.yaml | 50 +
drivers/crypto/Kconfig | 1 +
drivers/crypto/Makefile | 1 +
drivers/crypto/dwc-spacc/Kconfig | 83 +
drivers/crypto/dwc-spacc/Makefile | 6 +
drivers/crypto/dwc-spacc/spacc_ahash.c | 990 +++++++
drivers/crypto/dwc-spacc/spacc_core.c | 2551 +++++++++++++++++
drivers/crypto/dwc-spacc/spacc_core.h | 857 ++++++
drivers/crypto/dwc-spacc/spacc_device.c | 284 ++
drivers/crypto/dwc-spacc/spacc_device.h | 242 ++
drivers/crypto/dwc-spacc/spacc_hal.c | 344 +++
drivers/crypto/dwc-spacc/spacc_hal.h | 119 +
drivers/crypto/dwc-spacc/spacc_interrupt.c | 330 +++
drivers/crypto/dwc-spacc/spacc_manager.c | 649 +++++
14 files changed, 6507 insertions(+)
create mode 100644 Documentation/devicetree/bindings/crypto/snps,dwc-spacc.yaml
create mode 100644 drivers/crypto/dwc-spacc/Kconfig
create mode 100644 drivers/crypto/dwc-spacc/Makefile
create mode 100644 drivers/crypto/dwc-spacc/spacc_ahash.c
create mode 100644 drivers/crypto/dwc-spacc/spacc_core.c
create mode 100644 drivers/crypto/dwc-spacc/spacc_core.h
create mode 100644 drivers/crypto/dwc-spacc/spacc_device.c
create mode 100644 drivers/crypto/dwc-spacc/spacc_device.h
create mode 100644 drivers/crypto/dwc-spacc/spacc_hal.c
create mode 100644 drivers/crypto/dwc-spacc/spacc_hal.h
create mode 100644 drivers/crypto/dwc-spacc/spacc_interrupt.c
create mode 100644 drivers/crypto/dwc-spacc/spacc_manager.c
base-commit: df373d39c6f038d176af303ae72f02c7c70b953d
--
2.25.1
^ permalink raw reply
* Re: [PATCH v5 4/5] mfd: axp20x: Add support for AXP318W PMIC
From: sashiko-bot @ 2026-07-20 11:33 UTC (permalink / raw)
To: Jerome Brunet; +Cc: conor+dt, robh, devicetree
In-Reply-To: <20260720-axp318-regulator-v5-4-a1afa7ee24f9@baylibre.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The MFD cell array `axp318_cells` hard-codes the MFD cell ID to 1 instead of using `PLATFORM_DEVID_AUTO`, violating MFD subsystem guidelines.
--
--- Patch [4]: [PATCH v5 4/5] mfd: axp20x: Add support for AXP318W PMIC ---
commit 76c82c1e91d9894a1be9b93884198b1f956c4a6b
Author: Andre Przywara <andre.przywara@arm.com>
mfd: axp20x: Add support for AXP318W PMIC
This commit adds support for the X-Powers AXP318W PMIC to the axp20x driver.
It describes the regmap and MFD bits, and exposes the regulator and interrupt
registers via I2C.
> diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
> --- a/drivers/mfd/axp20x.c
> +++ b/drivers/mfd/axp20x.c
[ ... ]
> @@ -1061,6 +1129,10 @@ static const struct mfd_cell axp313a_cells[] = {
> MFD_CELL_RES("axp313a-pek", axp313a_pek_resources),
> };
>
> +static const struct mfd_cell axp318_cells[] = {
> + MFD_CELL_BASIC("axp20x-regulator", NULL, NULL, 0, 1),
[Severity: High]
Does this hard-coded MFD cell ID cause naming collisions in sysfs?
Setting the cell ID to 1 instead of using PLATFORM_DEVID_AUTO can cause
device registration to fail due to a name collision on axp20x-regulator.1
if multiple MFDs defining the same cell name and ID are instantiated on the
same system.
> +};
> +
> static const struct mfd_cell axp717_cells[] = {
> MFD_CELL_NAME("axp20x-regulator"),
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720-axp318-regulator-v5-0-a1afa7ee24f9@baylibre.com?part=4
^ permalink raw reply
* Re: [PATCH 4/4] iio: dac: ad5686: update device list and file header comments
From: Rodrigo Alencar @ 2026-07-20 11:27 UTC (permalink / raw)
To: Jonathan Cameron, Rodrigo Alencar via B4 Relay
Cc: Michael Auchter, linux, linux-iio, devicetree, linux-kernel,
Michael Hennerich, David Lechner, Andy Shevchenko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
In-Reply-To: <20260719223035.0acb57d6@jic23-huawei>
On 19/07/26 22:30, Jonathan Cameron wrote:
> On Sun, 19 Jul 2026 10:52:00 +0100
> Rodrigo Alencar via B4 Relay <devnull+rodrigo.alencar.analog.com@kernel.org> wrote:
>
> > From: Rodrigo Alencar <rodrigo.alencar@analog.com>
> >
> > Update device list entries in Kconfig and remove device description from
> > file headers. One can rely on the ID table(s) to check for supported
> > devices. Adjust comment header accordingly and update Copyright notice in
> > comment file headers with the current year.
> >
> > Signed-off-by: Rodrigo Alencar <rodrigo.alencar@analog.com>
> > ---
>
> Main comments here are about the patch break up. I think it needs
> just enough modification for a v2 to be needed.
>
> > drivers/iio/dac/Kconfig | 31 ++++++++++++++++++++++++-------
> > drivers/iio/dac/ad5686-spi.c | 7 ++-----
> > drivers/iio/dac/ad5686.c | 4 ++--
> > drivers/iio/dac/ad5696-i2c.c | 6 ++----
> > 4 files changed, 30 insertions(+), 18 deletions(-)
> >
> > diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
> > index d6d560c09e25..ba2065241af3 100644
> > --- a/drivers/iio/dac/Kconfig
> > +++ b/drivers/iio/dac/Kconfig
> > @@ -251,9 +251,18 @@ config AD5686_SPI
> > depends on SPI
> > select AD5686
> > help
> > - Say yes here to build support for Analog Devices AD5672R, AD5674R,
> > - AD5676, AD5676R, AD5679R, AD5684, AD5684R, AD5684R, AD5685R, AD5686,
> > - AD5686R Voltage Output Digital to Analog Converter.
>
> Given this is adding entrees that were in the previous patch, I'd have
> preferred to see the more complex dance of a precursor patch before that
> which did the reformat (and dropped the stuff form the c files)
>
> That would then be followed the new stuff being added as part of the previous
> patch.
>
> Whilst the ends result is the same I think it is worth doing a v2 just
> to clean that break down of patches up.
>
> > + Say yes here to build support for Analog Devices Voltage Output
> > + Digital to Analog Converters:
> > + - Single-channel:
> > + AD5310R, AD5681R, AD5682R, AD5683R, AD5683R
>
> Eagle eyed Sashiko spotted last entry is a duplicate.
Yeah, one of the entries should have been just AD5683...
Also, that this AD5337R was missing, which I didnt add because I could not
find documentation for this one. Maybe a device that does not exists or it
was deprecated.
>
> > + - Dual-channel:
> > + AD5313R, AD5687, AD5687R, AD5689, AD5689R
> > + - Quad-channel:
> > + AD5317R, AD5684, AD5684R, AD5685R, AD5686, AD5686R
> > + - 8-channel:
> > + AD5672R, AD5676, AD5676R
> > + - 16-channel:
> > + AD5674, AD5674R, AD5679, AD5679R
> >
> > To compile this driver as a module, choose M here: the
> > module will be called ad5686.
> > @@ -263,10 +272,18 @@ config AD5696_I2C
> > depends on I2C
> > select AD5686
> > help
> > - Say yes here to build support for Analog Devices AD5311R, AD5337,
> > - AD5338R, AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693,
> > - AD5693R, AD5694, AD5694R, AD5695R, AD5696, and AD5696R Digital to
> > - Analog converters.
> > + Say yes here to build support for Analog Devices Voltage Output
> > + Digital to Analog Converters:
> > + - Single-channel:
> > + AD5311R, AD5691R, AD5692R, AD5693, AD5693R
> > + - Dual-channel:
> > + AD5338R, AD5697R
> > + - Quad-channel:
> > + AD5316R, AD5694, AD5694R, AD5695R, AD5696, AD5696R
> > + - 8-channel:
> > + AD5671R, AD5675, AD5675R
> > + - 16-channel:
> > + AD5673R, AD5677R
> >
> > To compile this driver as a module, choose M here: the module will be
> > called ad5696.
> > diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c
> > index 003541edb742..b4531b49cb22 100644
> > --- a/drivers/iio/dac/ad5686-spi.c
> > +++ b/drivers/iio/dac/ad5686-spi.c
> > @@ -1,11 +1,8 @@
> > // SPDX-License-Identifier: GPL-2.0
> > /*
> > - * AD5672R, AD5674R, AD5676, AD5676R, AD5679R,
> > - * AD5681R, AD5682R, AD5683, AD5683R, AD5684,
> > - * AD5684R, AD5685R, AD5686, AD5686R
> > - * Digital to analog converters driver
> > + * SPI driver for AD5686 and similar Digital to Analog Converters
> > *
> > - * Copyright 2018 Analog Devices Inc.
> > + * Copyright 2018-2026 Analog Devices Inc.
>
> That definitely belongs in the patch that made a real change, not one
> that is just messing with comments.
Will drop this one. As I was touching the file headers I assumed it was fine
to put this here, given that I ended up adding a lot of changes to these files
lately.
--
Kind regards,
Rodrigo Alencar
^ permalink raw reply
* Re: [PATCH v6 2/4] dt-bindings: phy: qcs615-qmp-usb3dp: Add support for Shikra SoC
From: Vinod Koul @ 2026-07-20 11:23 UTC (permalink / raw)
To: Krishna Kurapati, Krzysztof Kozlowski
Cc: Neil Armstrong, Rob Herring, Conor Dooley, Wesley Cheng,
Xiangxu Yin, linux-arm-msm, linux-phy, devicetree, linux-kernel
In-Reply-To: <20260712-usb-shikra-phy-v6-v6-2-1b3e51bf1541@oss.qualcomm.com>
On 12-07-26, 20:58, Krishna Kurapati wrote:
Krzysztof okay with this..?
> Declare the USB-C QMP PHY present on the Qualcomm Shikra SoC. Shikra uses
> 3 resets to be programmed before initialising the phy. As per the hardware
> documentation, the third reset is PHY_PRIM_SP0_BCR, hence naming it "phy".
>
> Also, add remote endpoints and orientation switch support for getting
> Type-C orientation information.
>
> Signed-off-by: Krishna Kurapati <krishna.kurapati@oss.qualcomm.com>
> ---
> .../bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml | 49 +++++++++++++++++++++-
> 1 file changed, 48 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml
> index efb465c71c1b..98397006fa62 100644
> --- a/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml
> +++ b/Documentation/devicetree/bindings/phy/qcom,qcs615-qmp-usb3dp-phy.yaml
> @@ -18,6 +18,7 @@ properties:
> compatible:
> enum:
> - qcom,qcs615-qmp-usb3-dp-phy
> + - qcom,shikra-qmp-usb3-dp-phy
>
> reg:
> maxItems: 1
> @@ -33,12 +34,15 @@ properties:
> - const: pipe
>
> resets:
> - maxItems: 2
> + minItems: 2
> + maxItems: 3
>
> reset-names:
> + minItems: 2
> items:
> - const: phy_phy
> - const: dp_phy
> + - const: phy
>
> vdda-phy-supply: true
>
> @@ -63,6 +67,22 @@ properties:
> - description: offset of the PHY mode register
> description: Clamp and PHY mode register present in the TCSR
>
> + orientation-switch:
> + description:
> + Flag the PHY as possible handler of USB Type-C orientation switching
> + type: boolean
> +
> + ports:
> + $ref: /schemas/graph.yaml#/properties/ports
> + properties:
> + port@0:
> + $ref: /schemas/graph.yaml#/properties/port
> + description: Output endpoint of the PHY
> +
> + port@1:
> + $ref: /schemas/graph.yaml#/properties/port
> + description: Incoming endpoint from the USB controller
> +
> required:
> - compatible
> - reg
> @@ -78,6 +98,33 @@ required:
>
> additionalProperties: false
>
> +allOf:
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - qcom,shikra-qmp-usb3-dp-phy
> + then:
> + properties:
> + resets:
> + minItems: 3
> + reset-names:
> + minItems: 3
> +
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - qcom,qcs615-qmp-usb3-dp-phy
> + then:
> + properties:
> + resets:
> + maxItems: 2
> + reset-names:
> + maxItems: 2
> +
> examples:
> - |
> #include <dt-bindings/clock/qcom,qcs615-gcc.h>
>
> --
> 2.34.1
--
~Vinod
^ permalink raw reply
* Re: [PATCH 3/4] iio: adc: ade9000: add support for ADE9078
From: sashiko-bot @ 2026-07-20 11:22 UTC (permalink / raw)
To: Antoniu Miclaus; +Cc: conor+dt, robh, devicetree
In-Reply-To: <20260720110754.7674-4-antoniu.miclaus@analog.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Duplicate and overlapping `scan_index` values assigned to phase B and C channels break the IIO buffer subsystem.
--
--- Patch [3]: [PATCH 3/4] iio: adc: ade9000: add support for ADE9078 ---
commit b9467a190f2a74b5ff3993276ef11d90860fe13b
Author: Antoniu Miclaus <antoniu.miclaus@analog.com>
iio: adc: ade9000: add support for ADE9078
This commit adds support for the ADE9078 polyphase energy metering device,
which is register-compatible with the ADE9000 but lacks dip/swell detection.
It introduces a dedicated channel table to omit those events and adds matching
chip_info for the full-scale codes.
> diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c
> index 52ad87ef05d0c..0d5aa26f6667b 100644
> --- a/drivers/iio/adc/ade9000.c
> +++ b/drivers/iio/adc/ade9000.c
[ ... ]
> +#define ADE9000_DECLARE_CHANNELS(_name, altvoltage_rms) \
> + static const struct iio_chan_spec _name[] = { \
> + /* Phase A channels */ \
> + ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_A_NR), \
> + ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_A_NR), \
[ ... ]
> + /* Phase B channels */ \
> + ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_B_NR), \
> + ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_B_NR), \
[Severity: High]
This is a pre-existing issue, but does this channel declaration cause the
driver probe to fail during IIO device registration?
Looking at the channel macros in drivers/iio/adc/ade9000.c:
ADE9000_CURRENT_CHANNEL(num) sets .scan_index = num
ADE9000_VOLTAGE_CHANNEL(num) sets .scan_index = num + 1
With ADE9000_PHASE_A_NR (0) and ADE9000_PHASE_B_NR (1), Phase A's voltage
channel gets scan_index 1, which perfectly collides with Phase B's current
channel (also scan_index 1).
Since ade9000_probe() calls devm_iio_kfifo_buffer_setup(), the
INDIO_BUFFER_SOFTWARE mode flag is set. When devm_iio_device_register() is
called, the IIO core invokes iio_check_unique_scan_index(), detects the
duplicate scan_index, and unconditionally returns -EINVAL.
It looks like ade9000_waveform_buffer_config() expects Phase B Current to
map to BIT(2), so shouldn't these macros use num * 2 and num * 2 + 1
instead?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720110754.7674-1-antoniu.miclaus@analog.com?part=3
^ permalink raw reply
* Re: [PATCH v5 2/2] device property: add test cases for fwnode_for_each_child_node()
From: Andy Shevchenko @ 2026-07-20 11:21 UTC (permalink / raw)
To: Xu Yang
Cc: gregkh, rafael, dakr, robh, saravanak, bartosz.golaszewski,
driver-core, linux-kernel, devicetree, imx
In-Reply-To: <20260720104730.1285552-2-xu.yang_2@oss.nxp.com>
On Mon, Jul 20, 2026 at 06:47:30PM +0800, Xu Yang wrote:
> Add test cases for fwnode_for_each_child_node() API.
> Test command:
> $ ./tools/testing/kunit/kunit.py run property-entry
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Nope, I haven't Signed-off it here, it's your new submission where you are
the author. I only made a few cosmetic changes, if you want to give a credit
you can mention that in the comment block (SoB+Co-developed-by here seems
like an overkill).
...
You have a series of two patches but I haven't seen the cover letter.
I use this script [1] that helps me not to forget this.
[1]: https://github.com/andy-shev/home-bin-tools/blob/master/ge2maintainer.sh
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [PATCH v5 5/5] regulator: axp20x: add support for the AXP318W
From: Jerome Brunet @ 2026-07-20 11:20 UTC (permalink / raw)
To: Andre Przywara, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Liam Girdwood, Mark Brown
Cc: devicetree, linux-kernel, Jerome Brunet
In-Reply-To: <20260720-axp318-regulator-v5-0-a1afa7ee24f9@baylibre.com>
From: Andre Przywara <andre.przywara@arm.com>
The X-Powers AXP318W is a typical PMIC from X-Powers, featuring nine
DC/DC converters and 28 LDOs, on the regulator side.
Describe the chip's voltage settings and switch registers, how the
voltages are encoded, and connect this to the MFD device via its
regulator ID.
We use just "318" for the internal identifiers, for easier typing and
less churn. If something else other than the "AXP318W" shows up, that's
an easy change, externally visible strings carry the additional letter
already.
Reviewed-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Co-developed-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/regulator/axp20x-regulator.c | 324 ++++++++++++++++++++++++++++++++++-
include/linux/mfd/axp20x.h | 45 +++++
2 files changed, 360 insertions(+), 9 deletions(-)
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index da891415efc0..9e81e2cb7542 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -138,6 +138,29 @@
#define AXP313A_DCDC_V_OUT_MASK GENMASK(6, 0)
#define AXP313A_LDO_V_OUT_MASK GENMASK(4, 0)
+#define AXP318_DCDC1_PFM_PWM_CTRL BIT(7)
+#define AXP318_DCDC23_POLYPHASE_CTRL BIT(6)
+#define AXP318_DCDC45_POLYPHASE_CTRL BIT(7)
+#define AXP318_DCDC1_V_OUT_MASK GENMASK(4, 0)
+#define AXP318_DCDC2_V_OUT_MASK GENMASK(6, 0)
+#define AXP318_LDO_V_OUT_MASK GENMASK(4, 0)
+#define AXP318_ELDO_V_OUT_MASK GENMASK(5, 0)
+#define AXP318_THRESHOLD_VOLTAGE 1540000
+/*
+ * FIXME:
+ * Some LDOs of the AXP318 may be fed by different supplies and
+ * the documentation repeatedly warns that output voltage must
+ * be less than the supply, which is the case for any LDO really.
+ *
+ * The best way to let the framework handle this is to set the
+ * min_dropout_uV field. However the AXP318 documentation
+ * does not provide any information about this.
+ *
+ * Realistically, it can't be less than 1uV so use this
+ * for all LDOs until we know more.
+ */
+#define AXP318_LDO_MIN_DROPOUT 1 /* uV */
+
#define AXP717_DCDC1_NUM_VOLTAGES 88
#define AXP717_DCDC2_NUM_VOLTAGES 107
#define AXP717_DCDC3_NUM_VOLTAGES 103
@@ -371,8 +394,8 @@
.ops = &axp20x_ops, \
}
-#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
- _vmask, _ereg, _emask) \
+#define AXP_DESC_EXT(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _ops, _bpreg, _bpmask, _dropout) \
[_family##_##_id] = { \
.name = (_match), \
.supply_name = (_supply), \
@@ -384,13 +407,32 @@
.owner = THIS_MODULE, \
.min_uV = (_min) * 1000, \
.uV_step = (_step) * 1000, \
+ .min_dropout_uV = (_dropout), \
.vsel_reg = (_vreg), \
.vsel_mask = (_vmask), \
.enable_reg = (_ereg), \
.enable_mask = (_emask), \
- .ops = &axp20x_ops, \
+ .bypass_reg = (_bpreg), \
+ .bypass_mask = (_bpmask), \
+ .ops = (_ops), \
}
+#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask) \
+ AXP_DESC_EXT(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, &axp20x_ops, 0, 0, 0)
+
+#define AXP_DESC_DO(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _dropout) \
+ AXP_DESC_EXT(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, &axp20x_ops, 0, 0, _dropout)
+
+#define AXP_DESC_BYPASS(_family, _id, _match, _supply, _min, _max, _step, _vreg,\
+ _vmask, _ereg, _emask, _bpreg, _bpmask, _dropout) \
+ AXP_DESC_EXT(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, &axp20x_bypass_ops, _bpreg, \
+ _bpmask, _dropout)
+
#define AXP_DESC_SW(_family, _id, _match, _supply, _ereg, _emask) \
[_family##_##_id] = { \
.name = (_match), \
@@ -419,8 +461,9 @@
.ops = &axp20x_ops_fixed \
}
-#define AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, _n_voltages, \
- _vreg, _vmask, _ereg, _emask, _ramp_delay) \
+#define AXP_DESC_RANGES_DELAY_OPS(_family, _id, _match, _supply, _ranges, \
+ _n_voltages, _vreg, _vmask, _ereg, _emask, \
+ _ramp_delay, _ops) \
[_family##_##_id] = { \
.name = (_match), \
.supply_name = (_supply), \
@@ -436,10 +479,23 @@
.enable_mask = (_emask), \
.linear_ranges = (_ranges), \
.n_linear_ranges = ARRAY_SIZE(_ranges), \
- .ramp_delay = (_ramp_delay), \
- .ops = &axp20x_ops_range, \
+ .ramp_delay = (_ramp_delay), \
+ .ops = (_ops), \
}
+#define AXP_DESC_RANGES_THRESHOLD(_family, _id, _match, _supply, _ranges, \
+ _n_voltages, _vreg, _vmask, _ereg, _emask) \
+ AXP_DESC_RANGES_DELAY_OPS(_family, _id, _match, _supply, _ranges, \
+ _n_voltages, _vreg, _vmask, _ereg, _emask, \
+ 0, &axp318_threshold_ops_range)
+
+#define AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, \
+ _n_voltages, _vreg, _vmask, _ereg, _emask, \
+ _ramp_delay) \
+ AXP_DESC_RANGES_DELAY_OPS(_family, _id, _match, _supply, _ranges, \
+ _n_voltages, _vreg, _vmask, _ereg, _emask, \
+ _ramp_delay, &axp20x_ops_range)
+
#define AXP_DESC_RANGES(_family, _id, _match, _supply, _ranges, _n_voltages, \
_vreg, _vmask, _ereg, _emask) \
AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, \
@@ -567,6 +623,50 @@ static int axp20x_regulator_enable_regmap(struct regulator_dev *rdev)
return regulator_enable_regmap(rdev);
};
+static int axp318_threshold_check(struct regulator_dev *rdev,
+ unsigned int sel)
+{
+ int old_sel, old_uV, new_uV, enabled;
+
+ /* Only applicable if the regulator is enabled */
+ enabled = rdev->desc->ops->is_enabled(rdev);
+ if (enabled <= 0)
+ return enabled;
+
+ old_sel = rdev->desc->ops->get_voltage_sel(rdev);
+ if (old_sel < 0)
+ return old_sel;
+
+ old_uV = rdev->desc->ops->list_voltage(rdev, old_sel);
+ if (old_uV < 0)
+ return old_uV;
+
+ new_uV = rdev->desc->ops->list_voltage(rdev, sel);
+ if (new_uV < 0)
+ return new_uV;
+
+ /* Crossing the threshold ? */
+ if ((old_uV <= AXP318_THRESHOLD_VOLTAGE &&
+ new_uV > AXP318_THRESHOLD_VOLTAGE) ||
+ (new_uV <= AXP318_THRESHOLD_VOLTAGE &&
+ old_uV > AXP318_THRESHOLD_VOLTAGE))
+ return -EBUSY;
+
+ return 0;
+}
+
+static int axp318_threshold_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int sel)
+{
+ int ret;
+
+ ret = axp318_threshold_check(rdev, sel);
+ if (ret < 0)
+ return ret;
+
+ return regulator_set_voltage_sel_regmap(rdev, sel);
+}
+
static const struct regulator_ops axp20x_ops_fixed = {
.list_voltage = regulator_list_voltage_linear,
};
@@ -580,6 +680,15 @@ static const struct regulator_ops axp20x_ops_range = {
.is_enabled = regulator_is_enabled_regmap,
};
+static const struct regulator_ops axp318_threshold_ops_range = {
+ .set_voltage_sel = axp318_threshold_set_voltage_sel,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
static const struct regulator_ops axp20x_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -590,6 +699,18 @@ static const struct regulator_ops axp20x_ops = {
.set_ramp_delay = axp20x_set_ramp_delay,
};
+static const struct regulator_ops axp20x_bypass_ops = {
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .enable = axp20x_regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_ramp_delay = axp20x_set_ramp_delay,
+ .get_bypass = regulator_get_bypass_regmap,
+ .set_bypass = regulator_set_bypass_regmap,
+};
+
static const struct regulator_ops axp20x_ops_sw = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -765,6 +886,158 @@ static const struct regulator_desc axp313a_regulators[] = {
AXP_DESC_FIXED(AXP313A, RTC_LDO, "rtc-ldo", "vin1", 1800),
};
+static const struct linear_range axp318_dcdc2_ranges[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
+ REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000),
+};
+
+static const struct linear_range axp318_dcdc6_ranges[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
+ REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000),
+ REGULATOR_LINEAR_RANGE(1800000, 88, 118, 20000),
+ REGULATOR_LINEAR_RANGE(2440000, 119, 127, 40000),
+};
+
+static const struct linear_range axp318_dcdc7_ranges[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
+ REGULATOR_LINEAR_RANGE(1220000, 71, 102, 20000),
+};
+
+static const struct linear_range axp318_dcdc8_ranges[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
+ REGULATOR_LINEAR_RANGE(1220000, 71, 102, 20000),
+ REGULATOR_LINEAR_RANGE(1900000, 103, 118, 100000),
+};
+
+static const struct regulator_desc axp318_regulators[] = {
+ AXP_DESC(AXP318, DCDC1, "dcdc1", "vin19", 1000, 3400, 100,
+ AXP318_DCDC1_CONTROL, AXP318_DCDC1_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(0)),
+ AXP_DESC_RANGES(AXP318, DCDC2, "dcdc2", "vin23",
+ axp318_dcdc2_ranges, 88,
+ AXP318_DCDC2_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(1)),
+ AXP_DESC_RANGES(AXP318, DCDC3, "dcdc3", "vin23",
+ axp318_dcdc2_ranges, 88,
+ AXP318_DCDC3_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(2)),
+ AXP_DESC_RANGES(AXP318, DCDC4, "dcdc4", "vin45",
+ axp318_dcdc2_ranges, 88,
+ AXP318_DCDC4_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(3)),
+ AXP_DESC_RANGES(AXP318, DCDC5, "dcdc5", "vin45",
+ axp318_dcdc2_ranges, 88,
+ AXP318_DCDC5_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(4)),
+ AXP_DESC_RANGES_THRESHOLD(AXP318, DCDC6, "dcdc6", "vin678",
+ axp318_dcdc6_ranges, 128,
+ AXP318_DCDC6_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(5)),
+ AXP_DESC_RANGES_THRESHOLD(AXP318, DCDC7, "dcdc7", "vin678",
+ axp318_dcdc7_ranges, 103,
+ AXP318_DCDC7_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(6)),
+ AXP_DESC_RANGES_THRESHOLD(AXP318, DCDC8, "dcdc8", "vin678",
+ axp318_dcdc8_ranges, 119,
+ AXP318_DCDC8_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL1, BIT(7)),
+ AXP_DESC_RANGES_THRESHOLD(AXP318, DCDC9, "dcdc9", "vin19",
+ axp318_dcdc8_ranges, 119,
+ AXP318_DCDC9_CONTROL, AXP318_DCDC2_V_OUT_MASK,
+ AXP318_DCDC_OUTPUT_CONTROL2, BIT(0)),
+ AXP_DESC_SW(AXP318, SWOUT1, "swout1", NULL,
+ AXP318_DCDC_OUTPUT_CONTROL2, BIT(3)),
+ AXP_DESC_SW(AXP318, SWOUT2, "swout2", NULL,
+ AXP318_DCDC_OUTPUT_CONTROL2, BIT(4)),
+ AXP_DESC_DO(AXP318, ALDO1, "aldo1", "aldo156in", 500, 3400, 100,
+ AXP318_ALDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(0), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ALDO2, "aldo2", "aldo234in", 500, 3400, 100,
+ AXP318_ALDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(1), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ALDO3, "aldo3", "aldo234in", 500, 3400, 100,
+ AXP318_ALDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(2), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ALDO4, "aldo4", "aldo234in", 500, 3400, 100,
+ AXP318_ALDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(3), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ALDO5, "aldo5", "aldo156in", 500, 3400, 100,
+ AXP318_ALDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(4), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ALDO6, "aldo6", "aldo156in", 500, 3400, 100,
+ AXP318_ALDO6_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(5), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, BLDO1, "bldo1", "bldoin", 500, 3400, 100,
+ AXP318_BLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(6), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, BLDO2, "bldo2", "bldoin", 500, 3400, 100,
+ AXP318_BLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL1, BIT(7), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, BLDO3, "bldo3", "bldoin", 500, 3400, 100,
+ AXP318_BLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(0), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, BLDO4, "bldo4", "bldoin", 500, 3400, 100,
+ AXP318_BLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(1), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, BLDO5, "bldo5", "bldoin", 500, 3400, 100,
+ AXP318_BLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(2), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, CLDO1, "cldo1", "cldoin", 500, 3400, 100,
+ AXP318_CLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(3), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, CLDO2, "cldo2", "cldoin", 500, 3400, 100,
+ AXP318_CLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(4), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, CLDO3, "cldo3", "cldoin", 500, 3400, 100,
+ AXP318_CLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(5), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, CLDO4, "cldo4", "cldoin", 500, 3400, 100,
+ AXP318_CLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(6), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, CLDO5, "cldo5", "cldoin", 500, 3400, 100,
+ AXP318_CLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL2, BIT(7), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, DLDO1, "dldo1", "dldoin", 500, 3400, 100,
+ AXP318_DLDO1_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(0), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, DLDO2, "dldo2", "dldoin", 500, 3400, 100,
+ AXP318_DLDO2_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(1), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, DLDO3, "dldo3", "dldoin", 500, 3400, 100,
+ AXP318_DLDO3_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(2), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, DLDO4, "dldo4", "dldoin", 500, 3400, 100,
+ AXP318_DLDO4_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(3), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, DLDO5, "dldo5", "dldoin", 500, 3400, 100,
+ AXP318_DLDO5_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(4), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, DLDO6, "dldo6", "dldoin", 500, 3400, 100,
+ AXP318_DLDO6_CONTROL, AXP318_LDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(5), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ELDO1, "eldo1", "eldoin", 500, 1500, 25,
+ AXP318_ELDO1_CONTROL, AXP318_ELDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(6), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ELDO2, "eldo2", "eldoin", 500, 1500, 25,
+ AXP318_ELDO2_CONTROL, AXP318_ELDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL3, BIT(7), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ELDO3, "eldo3", "eldoin", 500, 1500, 25,
+ AXP318_ELDO3_CONTROL, AXP318_ELDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL4, BIT(0), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_BYPASS(AXP318, ELDO4, "eldo4", "eldoin", 500, 1500, 25,
+ AXP318_ELDO4_CONTROL, AXP318_ELDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL4, BIT(1),
+ AXP318_ELDO4_CONTROL, BIT(6), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_BYPASS(AXP318, ELDO5, "eldo5", "eldoin", 500, 1500, 25,
+ AXP318_ELDO5_CONTROL, AXP318_ELDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL4, BIT(2),
+ AXP318_ELDO5_CONTROL, BIT(6), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_DO(AXP318, ELDO6, "eldo6", "eldoin", 500, 1500, 25,
+ AXP318_ELDO6_CONTROL, AXP318_ELDO_V_OUT_MASK,
+ AXP318_LDO_OUTPUT_CONTROL4, BIT(3), AXP318_LDO_MIN_DROPOUT),
+ AXP_DESC_FIXED(AXP318, RTC_LDO, "rtc-ldo", "ips", 1800),
+};
+
static const struct linear_range axp717_dcdc1_ranges[] = {
REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000),
@@ -1347,6 +1620,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
step = 150;
break;
case AXP313A_ID:
+ case AXP318_ID:
case AXP323_ID:
case AXP717_ID:
case AXP15060_ID:
@@ -1430,6 +1704,20 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work
workmode <<= ffs(mask) - 1;
break;
+ case AXP318_ID:
+ /*
+ * Only DCDC1 has PWM control on the AXP318
+ * The other DCDCs control DVM through bit 7 of the related
+ * registers. Work mode could possibly extended to deal with
+ * this but it is not how it is documented at the moment
+ */
+ if (id != AXP318_DCDC1)
+ return -EINVAL;
+ reg = AXP318_DCDC1_CONTROL;
+ mask = AXP318_DCDC1_PFM_PWM_CTRL;
+ workmode <<= ffs(mask) - 1;
+ break;
+
case AXP806_ID:
/*
* AXP806 DCDC regulator IDs have the same range as AXP22X.
@@ -1543,6 +1831,17 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id)
}
break;
+ case AXP318_ID:
+ regmap_read(axp20x->regmap, AXP318_DCDC_CONTROL1, ®);
+
+ switch (id) {
+ case AXP318_DCDC3:
+ return !!(reg & AXP318_DCDC23_POLYPHASE_CTRL);
+ case AXP318_DCDC5:
+ return !!(reg & AXP318_DCDC45_POLYPHASE_CTRL);
+ }
+ break;
+
default:
return false;
}
@@ -1585,6 +1884,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
regulators = axp313a_regulators;
nregulators = AXP313A_REG_ID_MAX;
break;
+ case AXP318_ID:
+ regulators = axp318_regulators;
+ nregulators = AXP318_REG_ID_MAX;
+ break;
case AXP717_ID:
regulators = axp717_regulators;
nregulators = AXP717_REG_ID_MAX;
@@ -1651,7 +1954,9 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
if ((regulators == axp22x_regulators && i == AXP22X_DC1SW) ||
(regulators == axp803_regulators && i == AXP803_DC1SW) ||
(regulators == axp809_regulators && i == AXP809_DC1SW) ||
- (regulators == axp15060_regulators && i == AXP15060_SW)) {
+ (regulators == axp15060_regulators && i == AXP15060_SW) ||
+ (regulators == axp318_regulators && i == AXP318_SWOUT1) ||
+ (regulators == axp318_regulators && i == AXP318_SWOUT2)) {
new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc),
GFP_KERNEL);
if (!new_desc)
@@ -1709,7 +2014,8 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
*/
if ((regulators == axp22x_regulators && i == AXP22X_DCDC1) ||
(regulators == axp809_regulators && i == AXP809_DCDC1) ||
- (regulators == axp15060_regulators && i == AXP15060_DCDC1))
+ (regulators == axp15060_regulators && i == AXP15060_DCDC1) ||
+ (regulators == axp318_regulators && i == AXP318_DCDC1))
of_property_read_string(rdev->dev.of_node,
"regulator-name",
&dcdc1_name);
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
index 0191467de4ec..251f057ea76d 100644
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -128,6 +128,7 @@ enum axp20x_variants {
#define AXP318_DCDC7_CONTROL 0x18
#define AXP318_DCDC8_CONTROL 0x19
#define AXP318_DCDC9_CONTROL 0x1a
+#define AXP318_DCDC_CONTROL1 0x1b
#define AXP318_LDO_OUTPUT_CONTROL1 0x20
#define AXP318_LDO_OUTPUT_CONTROL2 0x21
#define AXP318_LDO_OUTPUT_CONTROL3 0x22
@@ -564,6 +565,50 @@ enum {
AXP313A_REG_ID_MAX,
};
+enum {
+ AXP318_DCDC1 = 0,
+ AXP318_DCDC2,
+ AXP318_DCDC3,
+ AXP318_DCDC4,
+ AXP318_DCDC5,
+ AXP318_DCDC6,
+ AXP318_DCDC7,
+ AXP318_DCDC8,
+ AXP318_DCDC9,
+ AXP318_ALDO1,
+ AXP318_ALDO2,
+ AXP318_ALDO3,
+ AXP318_ALDO4,
+ AXP318_ALDO5,
+ AXP318_ALDO6,
+ AXP318_BLDO1,
+ AXP318_BLDO2,
+ AXP318_BLDO3,
+ AXP318_BLDO4,
+ AXP318_BLDO5,
+ AXP318_CLDO1,
+ AXP318_CLDO2,
+ AXP318_CLDO3,
+ AXP318_CLDO4,
+ AXP318_CLDO5,
+ AXP318_DLDO1,
+ AXP318_DLDO2,
+ AXP318_DLDO3,
+ AXP318_DLDO4,
+ AXP318_DLDO5,
+ AXP318_DLDO6,
+ AXP318_ELDO1,
+ AXP318_ELDO2,
+ AXP318_ELDO3,
+ AXP318_ELDO4,
+ AXP318_ELDO5,
+ AXP318_ELDO6,
+ AXP318_SWOUT1,
+ AXP318_SWOUT2,
+ AXP318_RTC_LDO,
+ AXP318_REG_ID_MAX,
+};
+
enum {
AXP717_DCDC1 = 0,
AXP717_DCDC2,
--
2.47.3
^ permalink raw reply related
* [PATCH v5 4/5] mfd: axp20x: Add support for AXP318W PMIC
From: Jerome Brunet @ 2026-07-20 11:20 UTC (permalink / raw)
To: Andre Przywara, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Liam Girdwood, Mark Brown
Cc: devicetree, linux-kernel, Jerome Brunet
In-Reply-To: <20260720-axp318-regulator-v5-0-a1afa7ee24f9@baylibre.com>
From: Andre Przywara <andre.przywara@arm.com>
The AXP318W is a PMIC chip produced by X-Powers, it can be connected to
an I2C bus.
It has a large number of regulators: 9(!) DCDC buck converters, and 28
LDOs, also some ADCs, interrupts, and a power key.
Describe the regmap and the MFD bits, along with the registers exposed
via I2C only. This covers the regulators and interrupts for now.
Advertise the device using the new compatible string.
We use just "318" for the internal identifiers, for easier typing and
less churn, but use "318W" for anything externally visible. If something
else other than the "AXP318W" shows up, that's an easy change then.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/mfd/axp20x-i2c.c | 2 ++
drivers/mfd/axp20x.c | 81 ++++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/axp20x.h | 88 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 171 insertions(+)
diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
index a76bec5604c4..64c212b76e5e 100644
--- a/drivers/mfd/axp20x-i2c.c
+++ b/drivers/mfd/axp20x-i2c.c
@@ -66,6 +66,7 @@ static const struct of_device_id axp20x_i2c_of_match[] = {
{ .compatible = "x-powers,axp221", .data = (void *)AXP221_ID },
{ .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
{ .compatible = "x-powers,axp313a", .data = (void *)AXP313A_ID },
+ { .compatible = "x-powers,axp318w", .data = (void *)AXP318_ID },
{ .compatible = "x-powers,axp323", .data = (void *)AXP323_ID },
{ .compatible = "x-powers,axp717", .data = (void *)AXP717_ID },
{ .compatible = "x-powers,axp803", .data = (void *)AXP803_ID },
@@ -84,6 +85,7 @@ static const struct i2c_device_id axp20x_i2c_id[] = {
{ .name = "axp221", .driver_data = AXP221_ID },
{ .name = "axp223", .driver_data = AXP223_ID },
{ .name = "axp313a", .driver_data = AXP313A_ID },
+ { .name = "axp318w", .driver_data = AXP318_ID },
{ .name = "axp323", .driver_data = AXP323_ID },
{ .name = "axp717", .driver_data = AXP717_ID },
{ .name = "axp803", .driver_data = AXP803_ID },
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 84839d4aa1ca..ea00c0cdce58 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -42,6 +42,7 @@ static const char * const axp20x_model_names[] = {
[AXP223_ID] = "AXP223",
[AXP288_ID] = "AXP288",
[AXP313A_ID] = "AXP313a",
+ [AXP318_ID] = "AXP318W",
[AXP323_ID] = "AXP323",
[AXP717_ID] = "AXP717",
[AXP803_ID] = "AXP803",
@@ -218,6 +219,31 @@ static const struct regmap_access_table axp313a_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(axp313a_volatile_ranges),
};
+static const struct regmap_range axp318_writeable_ranges[] = {
+ regmap_reg_range(AXP318_DCDC_OUTPUT_CONTROL1, AXP318_IRQ_STATE4),
+ regmap_reg_range(AXP318_SHUTDOWN_SRC_CTRL1, AXP318_TEMP_ADC_H_EN),
+ regmap_reg_range(AXP318_DIE_TEMP_ADC_H_EN, AXP318_DIE_TEMP_ADC_H_EN),
+ regmap_reg_range(AXP318_GPADC_H_EN, AXP318_GPADC_H_EN),
+ regmap_reg_range(AXP318_GPIO_CTRL, AXP318_WDOG_CTRL),
+};
+
+static const struct regmap_range axp318_volatile_ranges[] = {
+ regmap_reg_range(AXP318_IRQ_EN1, AXP318_IRQ_STATE4),
+ regmap_reg_range(AXP318_POWER_REASON, AXP318_SHUTDOWN_SOURCE),
+ regmap_reg_range(AXP318_TEMP_ADC_H_EN, AXP318_GPADC_L),
+ regmap_reg_range(AXP318_GPIO_INPUT, AXP318_GPIO_INPUT),
+};
+
+static const struct regmap_access_table axp318_writeable_table = {
+ .yes_ranges = axp318_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp318_writeable_ranges),
+};
+
+static const struct regmap_access_table axp318_volatile_table = {
+ .yes_ranges = axp318_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp318_volatile_ranges),
+};
+
static const struct regmap_range axp717_writeable_ranges[] = {
regmap_reg_range(AXP717_PMU_FAULT, AXP717_MODULE_EN_CONTROL_1),
regmap_reg_range(AXP717_MIN_SYS_V_CONTROL, AXP717_BOOST_CONTROL),
@@ -447,6 +473,15 @@ static const struct regmap_config axp313a_regmap_config = {
.cache_type = REGCACHE_MAPLE,
};
+static const struct regmap_config axp318_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .wr_table = &axp318_writeable_table,
+ .volatile_table = &axp318_volatile_table,
+ .max_register = AXP318_WDOG_CTRL,
+ .cache_type = REGCACHE_MAPLE,
+};
+
static const struct regmap_config axp323_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -663,6 +698,28 @@ static const struct regmap_irq axp313a_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP313A, DIE_TEMP_HIGH, 0, 0),
};
+static const struct regmap_irq axp318_regmap_irqs[] = {
+ INIT_REGMAP_IRQ(AXP318, DCDC8_V_LOW, 0, 7),
+ INIT_REGMAP_IRQ(AXP318, DCDC7_V_LOW, 0, 6),
+ INIT_REGMAP_IRQ(AXP318, DCDC6_V_LOW, 0, 5),
+ INIT_REGMAP_IRQ(AXP318, DCDC5_V_LOW, 0, 4),
+ INIT_REGMAP_IRQ(AXP318, DCDC4_V_LOW, 0, 3),
+ INIT_REGMAP_IRQ(AXP318, DCDC3_V_LOW, 0, 2),
+ INIT_REGMAP_IRQ(AXP318, DCDC2_V_LOW, 0, 1),
+ INIT_REGMAP_IRQ(AXP318, DCDC1_V_LOW, 0, 0),
+ INIT_REGMAP_IRQ(AXP318, PEK_RIS_EDGE, 1, 6),
+ INIT_REGMAP_IRQ(AXP318, PEK_FAL_EDGE, 1, 5),
+ INIT_REGMAP_IRQ(AXP318, PEK_LONG, 1, 4),
+ INIT_REGMAP_IRQ(AXP318, PEK_SHORT, 1, 3),
+ INIT_REGMAP_IRQ(AXP318, DIE_TEMP_HIGH_LV2, 1, 2),
+ INIT_REGMAP_IRQ(AXP318, DIE_TEMP_HIGH_LV1, 1, 1),
+ INIT_REGMAP_IRQ(AXP318, DCDC9_V_LOW, 1, 0),
+ INIT_REGMAP_IRQ(AXP318, GPIO3_INPUT, 2, 6),
+ INIT_REGMAP_IRQ(AXP318, GPIO2_INPUT, 2, 5),
+ INIT_REGMAP_IRQ(AXP318, GPIO1_INPUT, 2, 4),
+ INIT_REGMAP_IRQ(AXP318, WDOG_EXPIRE, 3, 0),
+};
+
static const struct regmap_irq axp717_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP717, SOC_DROP_LVL2, 0, 7),
INIT_REGMAP_IRQ(AXP717, SOC_DROP_LVL1, 0, 6),
@@ -884,6 +941,17 @@ static const struct regmap_irq_chip axp313a_regmap_irq_chip = {
.num_regs = 1,
};
+static const struct regmap_irq_chip axp318_regmap_irq_chip = {
+ .name = "axp318w_irq_chip",
+ .status_base = AXP318_IRQ_STATE1,
+ .ack_base = AXP318_IRQ_STATE1,
+ .unmask_base = AXP318_IRQ_EN1,
+ .init_ack_masked = true,
+ .irqs = axp318_regmap_irqs,
+ .num_irqs = ARRAY_SIZE(axp318_regmap_irqs),
+ .num_regs = 4,
+};
+
static const struct regmap_irq_chip axp717_regmap_irq_chip = {
.name = "axp717_irq_chip",
.status_base = AXP717_IRQ0_STATE,
@@ -1061,6 +1129,10 @@ static const struct mfd_cell axp313a_cells[] = {
MFD_CELL_RES("axp313a-pek", axp313a_pek_resources),
};
+static const struct mfd_cell axp318_cells[] = {
+ MFD_CELL_BASIC("axp20x-regulator", NULL, NULL, 0, 1),
+};
+
static const struct mfd_cell axp717_cells[] = {
MFD_CELL_NAME("axp20x-regulator"),
MFD_CELL_RES("axp20x-pek", axp717_pek_resources),
@@ -1248,6 +1320,9 @@ static int axp20x_power_off(struct sys_off_data *data)
case AXP313A_ID:
shutdown_reg = AXP313A_SHUTDOWN_CTRL;
break;
+ case AXP318_ID:
+ shutdown_reg = AXP318_SHUTDOWN_CTRL;
+ break;
default:
shutdown_reg = AXP20X_OFF_CTRL;
break;
@@ -1312,6 +1387,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
axp20x->regmap_cfg = &axp313a_regmap_config;
axp20x->regmap_irq_chip = &axp313a_regmap_irq_chip;
break;
+ case AXP318_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp318_cells);
+ axp20x->cells = axp318_cells;
+ axp20x->regmap_cfg = &axp318_regmap_config;
+ axp20x->regmap_irq_chip = &axp318_regmap_irq_chip;
+ break;
case AXP323_ID:
axp20x->nr_cells = ARRAY_SIZE(axp313a_cells);
axp20x->cells = axp313a_cells;
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
index 1badb4868d17..0191467de4ec 100644
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -19,6 +19,7 @@ enum axp20x_variants {
AXP223_ID,
AXP288_ID,
AXP313A_ID,
+ AXP318_ID,
AXP323_ID,
AXP717_ID,
AXP803_ID,
@@ -116,6 +117,71 @@ enum axp20x_variants {
#define AXP313A_IRQ_STATE 0x21
#define AXP323_DCDC_MODE_CTRL2 0x22
+#define AXP318_DCDC_OUTPUT_CONTROL1 0x10
+#define AXP318_DCDC_OUTPUT_CONTROL2 0x11
+#define AXP318_DCDC1_CONTROL 0x12
+#define AXP318_DCDC2_CONTROL 0x13
+#define AXP318_DCDC3_CONTROL 0x14
+#define AXP318_DCDC4_CONTROL 0x15
+#define AXP318_DCDC5_CONTROL 0x16
+#define AXP318_DCDC6_CONTROL 0x17
+#define AXP318_DCDC7_CONTROL 0x18
+#define AXP318_DCDC8_CONTROL 0x19
+#define AXP318_DCDC9_CONTROL 0x1a
+#define AXP318_LDO_OUTPUT_CONTROL1 0x20
+#define AXP318_LDO_OUTPUT_CONTROL2 0x21
+#define AXP318_LDO_OUTPUT_CONTROL3 0x22
+#define AXP318_LDO_OUTPUT_CONTROL4 0x23
+#define AXP318_ALDO1_CONTROL 0x24
+#define AXP318_ALDO2_CONTROL 0x25
+#define AXP318_ALDO3_CONTROL 0x26
+#define AXP318_ALDO4_CONTROL 0x27
+#define AXP318_ALDO5_CONTROL 0x28
+#define AXP318_ALDO6_CONTROL 0x29
+#define AXP318_BLDO1_CONTROL 0x2a
+#define AXP318_BLDO2_CONTROL 0x2b
+#define AXP318_BLDO3_CONTROL 0x2c
+#define AXP318_BLDO4_CONTROL 0x2d
+#define AXP318_BLDO5_CONTROL 0x2e
+#define AXP318_CLDO1_CONTROL 0x2f
+#define AXP318_CLDO2_CONTROL 0x30
+#define AXP318_CLDO3_CONTROL 0x31
+#define AXP318_CLDO4_CONTROL 0x32
+#define AXP318_CLDO5_CONTROL 0x33
+#define AXP318_DLDO1_CONTROL 0x34
+#define AXP318_DLDO2_CONTROL 0x35
+#define AXP318_DLDO3_CONTROL 0x36
+#define AXP318_DLDO4_CONTROL 0x37
+#define AXP318_DLDO5_CONTROL 0x38
+#define AXP318_DLDO6_CONTROL 0x39
+#define AXP318_ELDO1_CONTROL 0x3a
+#define AXP318_ELDO2_CONTROL 0x3b
+#define AXP318_ELDO3_CONTROL 0x3c
+#define AXP318_ELDO4_CONTROL 0x3d
+#define AXP318_ELDO5_CONTROL 0x3e
+#define AXP318_ELDO6_CONTROL 0x3f
+#define AXP318_IRQ_EN1 0x40
+#define AXP318_IRQ_EN2 0x41
+#define AXP318_IRQ_EN3 0x42
+#define AXP318_IRQ_EN4 0x43
+#define AXP318_IRQ_STATE1 0x48
+#define AXP318_IRQ_STATE2 0x49
+#define AXP318_IRQ_STATE3 0x4a
+#define AXP318_IRQ_STATE4 0x4b
+#define AXP318_POWER_REASON 0x50
+#define AXP318_SHUTDOWN_SOURCE 0x51
+#define AXP318_SHUTDOWN_SRC_CTRL1 0x52
+#define AXP318_SHUTDOWN_SRC_CTRL2 0x53
+#define AXP318_SHUTDOWN_CTRL 0x55
+#define AXP318_TEMP_ADC_H_EN 0x65
+#define AXP318_TEMP_ADC_L 0x66
+#define AXP318_DIE_TEMP_ADC_H_EN 0x67
+#define AXP318_GPADC_H_EN 0x69
+#define AXP318_GPADC_L 0x6a
+#define AXP318_GPIO_CTRL 0x70
+#define AXP318_GPIO_INPUT 0x71
+#define AXP318_WDOG_CTRL 0x77
+
#define AXP717_ON_INDICATE 0x00
#define AXP717_PMU_STATUS_2 0x01
#define AXP717_BC_DETECT 0x05
@@ -819,6 +885,28 @@ enum axp313a_irqs {
AXP313A_IRQ_PEK_RIS_EDGE,
};
+enum axp318_irqs {
+ AXP318_IRQ_DCDC1_V_LOW,
+ AXP318_IRQ_DCDC2_V_LOW,
+ AXP318_IRQ_DCDC3_V_LOW,
+ AXP318_IRQ_DCDC4_V_LOW,
+ AXP318_IRQ_DCDC5_V_LOW,
+ AXP318_IRQ_DCDC6_V_LOW,
+ AXP318_IRQ_DCDC7_V_LOW,
+ AXP318_IRQ_DCDC8_V_LOW,
+ AXP318_IRQ_DCDC9_V_LOW,
+ AXP318_IRQ_DIE_TEMP_HIGH_LV1,
+ AXP318_IRQ_DIE_TEMP_HIGH_LV2,
+ AXP318_IRQ_PEK_SHORT,
+ AXP318_IRQ_PEK_LONG,
+ AXP318_IRQ_PEK_FAL_EDGE,
+ AXP318_IRQ_PEK_RIS_EDGE,
+ AXP318_IRQ_GPIO1_INPUT = 20,
+ AXP318_IRQ_GPIO2_INPUT,
+ AXP318_IRQ_GPIO3_INPUT,
+ AXP318_IRQ_WDOG_EXPIRE = 24,
+};
+
enum axp717_irqs {
AXP717_IRQ_VBUS_FAULT,
AXP717_IRQ_VBUS_OVER_V,
--
2.47.3
^ permalink raw reply related
* [PATCH v5 3/5] dt-bindings: mfd: x-powers,axp152: Document AXP318W
From: Jerome Brunet @ 2026-07-20 11:20 UTC (permalink / raw)
To: Andre Przywara, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Liam Girdwood, Mark Brown
Cc: devicetree, linux-kernel, Conor Dooley, Jerome Brunet
In-Reply-To: <20260720-axp318-regulator-v5-0-a1afa7ee24f9@baylibre.com>
From: Andre Przywara <andre.przywara@arm.com>
The X-Powers AXP318W is a PMIC used on some newer Allwinner devices.
Among a large number of both DCDC and LDO regulators it features the usual
ADC/IRQ/power key parts.
Like other recent PMICs, it lacks the DC/DC converter PWM frequency control
register, that rate is fixed here (1.5MHz on DCDC1, 3 MHz on the others).
Add the new compatible string, and add that to the list of PMICs without
the PWM frequency property.
Also add more input supply properties, for the split DCDC and ALDO
supplies.
The PMIC features *two* switched outputs, hanging of DCDC1, and the
manual calls them swout1 and swout2, so follow suit here and add those
names to the pattern for matching the node names.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Chen-Yu Tsai <wens@kernel.org>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
.../devicetree/bindings/mfd/x-powers,axp152.yaml | 28 +++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
index 45f015d63df1..38556c32417b 100644
--- a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
+++ b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
@@ -83,6 +83,7 @@ allOf:
contains:
enum:
- x-powers,axp313a
+ - x-powers,axp318w
- x-powers,axp323
- x-powers,axp15060
- x-powers,axp717
@@ -102,6 +103,7 @@ properties:
- x-powers,axp221
- x-powers,axp223
- x-powers,axp313a
+ - x-powers,axp318w
- x-powers,axp323
- x-powers,axp717
- x-powers,axp803
@@ -156,10 +158,18 @@ properties:
description: >
DCDC1 power supply node, if present.
+ vin19-supply:
+ description: >
+ Combined DCDC1/DCDC9 power supply node, if present.
+
vin2-supply:
description: >
DCDC2 power supply node, if present.
+ vin23-supply:
+ description: >
+ Combined DCDC2/DCDC3 power supply node, if present.
+
vin3-supply:
description: >
DCDC3 power supply node, if present.
@@ -168,6 +178,10 @@ properties:
description: >
DCDC4 power supply node, if present.
+ vin45-supply:
+ description: >
+ Combined DCDC4/DCDC5 power supply node, if present.
+
vin5-supply:
description: >
DCDC5 power supply node, if present.
@@ -176,6 +190,10 @@ properties:
description: >
DCDC6 power supply node, if present.
+ vin678-supply:
+ description: >
+ Combined DCDC6/DCDC7/DCDC8 power supply node, if present.
+
vin7-supply:
description: >
DCDC7 power supply node, if present.
@@ -220,6 +238,14 @@ properties:
description: >
ALDO* power supply node, if present.
+ aldo156in-supply:
+ description: >
+ ALDO* power supply node, if present.
+
+ aldo234in-supply:
+ description: >
+ ALDO* power supply node, if present.
+
bldoin-supply:
description: >
BLDO* power supply node, if present.
@@ -277,7 +303,7 @@ properties:
Defines the work frequency of DC-DC in kHz.
patternProperties:
- "^(([a-f])?ldo[0-9]|dcdc[0-7a-e]|ldo(_|-)io(0|1)|(dc1)?sw|rtc(_|-)ldo|cpusldo|drivevbus|dc5ldo|boost)$":
+ "^(([a-f])?ldo[0-9]|dcdc[0-9a-e]|ldo(_|-)io(0|1)|(dc1)?sw|swout[1-2]|rtc(_|-)ldo|cpusldo|drivevbus|dc5ldo|boost)$":
$ref: /schemas/regulator/regulator.yaml#
type: object
unevaluatedProperties: false
--
2.47.3
^ permalink raw reply related
* [PATCH v5 2/5] mfd: axp20x-i2c: Fix i2c instantiation
From: Jerome Brunet @ 2026-07-20 11:20 UTC (permalink / raw)
To: Andre Przywara, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Liam Girdwood, Mark Brown
Cc: devicetree, linux-kernel, Sashiko, Jerome Brunet
In-Reply-To: <20260720-axp318-regulator-v5-0-a1afa7ee24f9@baylibre.com>
Apparently this device never really supported i2c instantiation via
sysfs, because the driver does not even look at the i2c driver, which are
not set. It would only probe if the device matched through DT.
Fix that for correctness, even-though it is probably useless.
Add the missing AXP323 while at it.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/r/20260717090209.2A09B1F000E9@smtp.kernel.org
Fixes: 41751b033aaa ("mfd: axp20x-i2c: Add i2c-ids to fix module auto-loading")
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/mfd/axp20x-i2c.c | 24 +++++++++++++-----------
drivers/mfd/axp20x-rsb.c | 1 +
drivers/mfd/axp20x.c | 1 -
include/linux/mfd/axp20x.h | 3 +--
4 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
index 5c93136f977e..a76bec5604c4 100644
--- a/drivers/mfd/axp20x-i2c.c
+++ b/drivers/mfd/axp20x-i2c.c
@@ -35,6 +35,7 @@ static int axp20x_i2c_probe(struct i2c_client *i2c)
axp20x->irq = i2c->irq;
dev_set_drvdata(axp20x->dev, axp20x);
+ axp20x->variant = (kernel_ulong_t)i2c_get_match_data(i2c);
ret = axp20x_match_device(axp20x);
if (ret)
return ret;
@@ -76,17 +77,18 @@ MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match);
#endif
static const struct i2c_device_id axp20x_i2c_id[] = {
- { "axp152" },
- { "axp192" },
- { "axp202" },
- { "axp209" },
- { "axp221" },
- { "axp223" },
- { "axp313a" },
- { "axp717" },
- { "axp803" },
- { "axp806" },
- { "axp15060" },
+ { .name = "axp152", .driver_data = AXP152_ID },
+ { .name = "axp192", .driver_data = AXP192_ID },
+ { .name = "axp202", .driver_data = AXP202_ID },
+ { .name = "axp209", .driver_data = AXP209_ID },
+ { .name = "axp221", .driver_data = AXP221_ID },
+ { .name = "axp223", .driver_data = AXP223_ID },
+ { .name = "axp313a", .driver_data = AXP313A_ID },
+ { .name = "axp323", .driver_data = AXP323_ID },
+ { .name = "axp717", .driver_data = AXP717_ID },
+ { .name = "axp803", .driver_data = AXP803_ID },
+ { .name = "axp806", .driver_data = AXP806_ID },
+ { .name = "axp15060", .driver_data = AXP15060_ID },
{ }
};
MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
diff --git a/drivers/mfd/axp20x-rsb.c b/drivers/mfd/axp20x-rsb.c
index 059656f2a1bd..8fdc870c1fe4 100644
--- a/drivers/mfd/axp20x-rsb.c
+++ b/drivers/mfd/axp20x-rsb.c
@@ -35,6 +35,7 @@ static int axp20x_rsb_probe(struct sunxi_rsb_device *rdev)
axp20x->irq = rdev->irq;
dev_set_drvdata(&rdev->dev, axp20x);
+ axp20x->variant = (kernel_ulong_t)device_get_match_data(axp20x->dev);
ret = axp20x_match_device(axp20x);
if (ret)
return ret;
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 22baab6e10fa..84839d4aa1ca 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -1267,7 +1267,6 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
const struct mfd_cell *cells_no_irq = NULL;
int nr_cells_no_irq = 0;
- axp20x->variant = (long)device_get_match_data(dev);
switch (axp20x->variant) {
case AXP152_ID:
axp20x->nr_cells = ARRAY_SIZE(axp152_cells);
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
index b352661d99a1..1badb4868d17 100644
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -997,8 +997,7 @@ static inline int axp20x_read_variable_width(struct regmap *regmap,
/**
* axp20x_match_device(): Setup axp20x variant related fields
*
- * @axp20x: axp20x device to setup (.dev field must be set)
- * @dev: device associated with this axp20x device
+ * @axp20x: axp20x device to setup (.dev and variant fields must be set)
*
* This lets the axp20x core configure the mfd cells and register maps
* for later use.
--
2.47.3
^ permalink raw reply related
* [PATCH v5 1/5] mfd: axp20x: Constify axp313 and axp717 cells
From: Jerome Brunet @ 2026-07-20 11:20 UTC (permalink / raw)
To: Andre Przywara, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Liam Girdwood, Mark Brown
Cc: devicetree, linux-kernel, Jerome Brunet
In-Reply-To: <20260720-axp318-regulator-v5-0-a1afa7ee24f9@baylibre.com>
mfd_cells array should generally be const and there does not seem to be
anything against it for the axp313 and axp717.
Constify the mfd_cells array for the axp313 and axp717 to be consitent
with the other supported chips
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/mfd/axp20x.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 679364189ea5..22baab6e10fa 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -1055,13 +1055,13 @@ static const struct mfd_cell axp152_cells[] = {
},
};
-static struct mfd_cell axp313a_cells[] = {
+static const struct mfd_cell axp313a_cells[] = {
/* AXP323 is sometimes paired with AXP717 as sub-PMIC */
MFD_CELL_BASIC("axp20x-regulator", NULL, NULL, 0, 1),
MFD_CELL_RES("axp313a-pek", axp313a_pek_resources),
};
-static struct mfd_cell axp717_cells[] = {
+static const struct mfd_cell axp717_cells[] = {
MFD_CELL_NAME("axp20x-regulator"),
MFD_CELL_RES("axp20x-pek", axp717_pek_resources),
MFD_CELL_OF("axp717-adc",
--
2.47.3
^ permalink raw reply related
* [PATCH v5 0/5] regulator: Add X-Powers AXP318W PMIC support
From: Jerome Brunet @ 2026-07-20 11:20 UTC (permalink / raw)
To: Andre Przywara, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Chen-Yu Tsai, Liam Girdwood, Mark Brown
Cc: devicetree, linux-kernel, Jerome Brunet, Sashiko, Conor Dooley
This patch series adds support for the X-Powers AXP318W PMIC, which is
used recently on new boards with Allwinner SoCs (the A733).
The PMIC features 9 DCDC buck converters and 28 LDOs, plus the usual ADC,
interrupts, and power key components.
A datasheet can be found linked in this Wiki table:
https://linux-sunxi.org/AXP_PMICs
There was an unclosed topic regarding the handling of LDOs output
voltage being limited to input voltage being provided by the supply.
Chen-Yu noted the min_dropout_uV would be a good fit for that but
the actual minimal dropout value was unknown. I've arbitrarily picked
1uV because it is the minimum the framework supports. Realistically a low
dropout regulator is bound to have some dropout. This choice does the
trick for now and is certain be less restrictive than what it is in
reality.
If anyone has problems because the dropout is actually higher
* it is arguably an HW design error
* it is a good time to let us know what the actual dropout is
Changes in v5:
- Fix shutdown register offset
- Re-order patches to put fixes first
- Tighten DT regexp around swout
- Other points raised by Sashiko on v4 are unrelated to the addition
of the AXP318 support and pre-exist the series. They are not
addressed ATM.
- Link to v4: https://patch.msgid.link/20260717-axp318-regulator-v4-0-50aff97084dd@baylibre.com
Changes in v4:
- Capitalize patch 3 title
- regulator: add support for workmode and poly-phase.
- i2c: fix probe through i2c sysfs
- Link to v3: https://patch.msgid.link/20260717-axp318-regulator-v3-0-779dc1b97dd4@baylibre.com
Changes in v3:
- Correct mess up v2 errors regarding ops and ids.
- Correctly propagate errors when checking axp318 threshold.
- Fix DT binding regex regarding dcdc max ids
- Add missing RTCLDO.
- Remove axp318 PEK MFD cell:
As pointed out by sashiko, the driver name did not match anything in the
pek driver. While the device does support some handling of the power
button, it does not seem to match the existing driver. Register 0x36
relates to DLDO3, not the power key, as expected by the misc driver.
Leave this out for now.
- Constify axp313 and axp717 mfd_cells array for consistency.
- Link to v2: https://patch.msgid.link/20260710-axp318-regulator-v2-0-ee5f1c56b49f@baylibre.com
Changes in v2:
- Dropped _NUM_VOLTAGES macros
- Use min_dropout_uV to limit LDO voltage to supplies
- Add bypass mode for EDLO4/5
- Prevent crossing 1.54V threshold for DCDC6/7/8/9
- Link to v1: https://lore.kernel.org/r/20251021112013.2710903-1-andre.przywara@arm.com
---
Andre Przywara (3):
dt-bindings: mfd: x-powers,axp152: Document AXP318W
mfd: axp20x: Add support for AXP318W PMIC
regulator: axp20x: add support for the AXP318W
Jerome Brunet (2):
mfd: axp20x: Constify axp313 and axp717 cells
mfd: axp20x-i2c: Fix i2c instantiation
.../devicetree/bindings/mfd/x-powers,axp152.yaml | 28 +-
drivers/mfd/axp20x-i2c.c | 26 +-
drivers/mfd/axp20x-rsb.c | 1 +
drivers/mfd/axp20x.c | 86 +++++-
drivers/regulator/axp20x-regulator.c | 324 ++++++++++++++++++++-
include/linux/mfd/axp20x.h | 136 ++++++++-
6 files changed, 575 insertions(+), 26 deletions(-)
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260710-axp318-regulator-43545ce3261f
Best regards,
--
Jerome
^ permalink raw reply
* Re: [PATCH v3 0/4] phy: qcom: Introduce USB support for Hawi
From: Vinod Koul @ 2026-07-20 11:18 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Ronak Raheja, krzk+dt, conor+dt, robh, neil.armstrong, gregkh,
dmitry.baryshkov, konrad.dybcio, abel.vesa, wesley.cheng,
krzysztof.kozlowski, linux-arm-msm, linux-phy, devicetree,
linux-usb, linux-kernel
In-Reply-To: <chf57j2dkhhjzigpguldadfld5utepa4sxwbo7fjxk5nq37bhp@yci5agzh46ly>
On 13-07-26, 13:12, Manivannan Sadhasivam wrote:
> On Fri, May 08, 2026 at 02:32:30PM -0700, Ronak Raheja wrote:
> > This series adds USB PHY support for the Hawi SoC. It documents the
> > QMP USB3-DP combo PHY and M31 eUSB2 PHY bindings, adds the Hawi
> > compatible to the DWC3 USB binding, and adds the PHY initialization
> > sequences to the qmp-combo driver.
> >
>
> Vinod, does this series look good to you?
It doesnt apply for me, can you folks rebase and resend
--
~Vinod
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox