Commit 14a60290 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'soc-drivers-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc

Pull SoC driver updates from Arnd Bergmann:
 "As usual, these are updates for drivers that are specific to certain
  SoCs or firmware running on them.

  Notable updates include

   - The new STMicroelectronics STM32 "firewall" bus driver that is used
     to provide a barrier between different parts of an SoC

   - Lots of updates for the Qualcomm platform drivers, in particular
     SCM, which gets a rewrite of its initialization code

   - Firmware driver updates for Arm FF-A notification interrupts and
     indirect messaging, SCMI firmware support for pin control and
     vendor specific interfaces, and TEE firmware interface changes
     across multiple TEE drivers

   - A larger cleanup of the Mediatek CMDQ driver and some related bits

   - Kconfig changes for riscv drivers to prepare for adding Kanaan k230
     support

   - Multiple minor updates for the TI sysc bus driver, memory
     controllers, hisilicon hccs and more"

* tag 'soc-drivers-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (103 commits)
  firmware: qcom: uefisecapp: Allow on sc8180x Primus and Flex 5G
  soc: qcom: pmic_glink: Make client-lock non-sleeping
  dt-bindings: soc: qcom,wcnss: fix bluetooth address example
  soc/tegra: pmc: Add EQOS wake event for Tegra194 and Tegra234
  bus: stm32_firewall: fix off by one in stm32_firewall_get_firewall()
  bus: etzpc: introduce ETZPC firewall controller driver
  firmware: arm_ffa: Avoid queuing work when running on the worker queue
  bus: ti-sysc: Drop legacy idle quirk handling
  bus: ti-sysc: Drop legacy quirk handling for smartreflex
  bus: ti-sysc: Drop legacy quirk handling for uarts
  bus: ti-sysc: Add a description and copyrights
  bus: ti-sysc: Move check for no-reset-on-init
  soc: hisilicon: kunpeng_hccs: replace MAILBOX dependency with PCC
  soc: hisilicon: kunpeng_hccs: Add the check for obtaining complete port attribute
  firmware: arm_ffa: Fix memory corruption in ffa_msg_send2()
  bus: rifsc: introduce RIFSC firewall controller driver
  of: property: fw_devlink: Add support for "access-controller"
  soc: mediatek: mtk-socinfo: Correct the marketing name for MT8188GV
  soc: mediatek: mtk-socinfo: Add entry for MT8395AV/ZA Genio 1200
  soc: mediatek: mtk-mutex: Add support for MT8188 VPPSYS
  ...
parents 6c60000f 1c97fe39
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/access-controllers/access-controllers.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Generic Domain Access Controllers
maintainers:
- Oleksii Moisieiev <oleksii_moisieiev@epam.com>
description: |+
Common access controllers properties
Access controllers are in charge of stating which of the hardware blocks under
their responsibility (their domain) can be accesssed by which compartment. A
compartment can be a cluster of CPUs (or coprocessors), a range of addresses
or a group of hardware blocks. An access controller's domain is the set of
resources covered by the access controller.
This device tree binding can be used to bind devices to their access
controller provided by access-controllers property. In this case, the device
is a consumer and the access controller is the provider.
An access controller can be represented by any node in the device tree and
can provide one or more configuration parameters, needed to control parameters
of the consumer device. A consumer node can refer to the provider by phandle
and a set of phandle arguments, specified by '#access-controller-cells'
property in the access controller node.
Access controllers are typically used to set/read the permissions of a
hardware block and grant access to it. Any of which depends on the access
controller. The capabilities of each access controller are defined by the
binding of the access controller device.
Each node can be a consumer for the several access controllers.
# always select the core schema
select: true
properties:
"#access-controller-cells":
description:
Number of cells in an access-controllers specifier;
Can be any value as specified by device tree binding documentation
of a particular provider. The node is an access controller.
access-controller-names:
$ref: /schemas/types.yaml#/definitions/string-array
description:
A list of access-controllers names, sorted in the same order as
access-controllers entries. Consumer drivers will use
access-controller-names to match with existing access-controllers entries.
access-controllers:
$ref: /schemas/types.yaml#/definitions/phandle-array
description:
A list of access controller specifiers, as defined by the
bindings of the access-controllers provider.
additionalProperties: true
examples:
- |
clock_controller: access-controllers@50000 {
reg = <0x50000 0x400>;
#access-controller-cells = <2>;
};
bus_controller: bus@60000 {
reg = <0x60000 0x10000>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
#access-controller-cells = <3>;
uart4: serial@60100 {
reg = <0x60100 0x400>;
clocks = <&clk_serial>;
access-controllers = <&clock_controller 1 2>,
<&bus_controller 1 3 5>;
access-controller-names = "clock", "bus";
};
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/bus/st,stm32-etzpc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: STM32 Extended TrustZone protection controller
description: |
The ETZPC configures TrustZone security in a SoC having bus masters and
devices with programmable-security attributes (securable resources).
maintainers:
- Gatien Chevallier <gatien.chevallier@foss.st.com>
select:
properties:
compatible:
contains:
const: st,stm32-etzpc
required:
- compatible
properties:
compatible:
items:
- const: st,stm32-etzpc
- const: simple-bus
reg:
maxItems: 1
"#address-cells":
const: 1
"#size-cells":
const: 1
ranges: true
"#access-controller-cells":
const: 1
description:
Contains the firewall ID associated to the peripheral.
patternProperties:
"^.*@[0-9a-f]+$":
description: Peripherals
type: object
additionalProperties: true
required:
- access-controllers
required:
- compatible
- reg
- "#address-cells"
- "#size-cells"
- "#access-controller-cells"
- ranges
additionalProperties: false
examples:
- |
// In this example, the usart2 device refers to rifsc as its access
// controller.
// Access rights are verified before creating devices.
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/stm32mp13-clks.h>
#include <dt-bindings/reset/stm32mp13-resets.h>
etzpc: bus@5c007000 {
compatible = "st,stm32-etzpc", "simple-bus";
reg = <0x5c007000 0x400>;
#address-cells = <1>;
#size-cells = <1>;
#access-controller-cells = <1>;
ranges;
usart2: serial@4c001000 {
compatible = "st,stm32h7-uart";
reg = <0x4c001000 0x400>;
interrupts-extended = <&exti 27 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&rcc USART2_K>;
resets = <&rcc USART2_R>;
wakeup-source;
dmas = <&dmamux1 43 0x400 0x5>,
<&dmamux1 44 0x400 0x1>;
dma-names = "rx", "tx";
access-controllers = <&etzpc 17>;
};
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/bus/st,stm32mp25-rifsc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: STM32 Resource isolation framework security controller
maintainers:
- Gatien Chevallier <gatien.chevallier@foss.st.com>
description: |
Resource isolation framework (RIF) is a comprehensive set of hardware blocks
designed to enforce and manage isolation of STM32 hardware resources like
memory and peripherals.
The RIFSC (RIF security controller) is composed of three sets of registers,
each managing a specific set of hardware resources:
- RISC registers associated with RISUP logic (resource isolation device unit
for peripherals), assign all non-RIF aware peripherals to zero, one or
any security domains (secure, privilege, compartment).
- RIMC registers: associated with RIMU logic (resource isolation master
unit), assign all non RIF-aware bus master to one security domain by
setting secure, privileged and compartment information on the system bus.
Alternatively, the RISUP logic controlling the device port access to a
peripheral can assign target bus attributes to this peripheral master port
(supported attribute: CID).
- RISC registers associated with RISAL logic (resource isolation device unit
for address space - Lite version), assign address space subregions to one
security domains (secure, privilege, compartment).
select:
properties:
compatible:
contains:
const: st,stm32mp25-rifsc
required:
- compatible
properties:
compatible:
items:
- const: st,stm32mp25-rifsc
- const: simple-bus
reg:
maxItems: 1
"#address-cells":
const: 1
"#size-cells":
const: 1
ranges: true
"#access-controller-cells":
const: 1
description:
Contains the firewall ID associated to the peripheral.
patternProperties:
"^.*@[0-9a-f]+$":
description: Peripherals
type: object
additionalProperties: true
required:
- access-controllers
required:
- compatible
- reg
- "#address-cells"
- "#size-cells"
- "#access-controller-cells"
- ranges
additionalProperties: false
examples:
- |
// In this example, the usart2 device refers to rifsc as its domain
// controller.
// Access rights are verified before creating devices.
#include <dt-bindings/interrupt-controller/arm-gic.h>
rifsc: bus@42080000 {
compatible = "st,stm32mp25-rifsc", "simple-bus";
reg = <0x42080000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
#access-controller-cells = <1>;
ranges;
usart2: serial@400e0000 {
compatible = "st,stm32h7-uart";
reg = <0x400e0000 0x400>;
interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ck_flexgen_08>;
access-controllers = <&rifsc 32>;
};
};
......@@ -46,6 +46,10 @@ properties:
power-domains:
maxItems: 1
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- reg
......
......@@ -51,6 +51,10 @@ properties:
power-domains:
maxItems: 1
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- reg
......
......@@ -82,6 +82,10 @@ properties:
description: if defined, it indicates that the controller
supports memory-to-memory transfer
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- reg
......
......@@ -28,6 +28,10 @@ properties:
resets:
maxItems: 1
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- reg
......
......@@ -247,6 +247,37 @@ properties:
reg:
const: 0x18
protocol@19:
type: object
allOf:
- $ref: '#/$defs/protocol-node'
- $ref: /schemas/pinctrl/pinctrl.yaml
unevaluatedProperties: false
properties:
reg:
const: 0x19
patternProperties:
'-pins$':
type: object
allOf:
- $ref: /schemas/pinctrl/pincfg-node.yaml#
- $ref: /schemas/pinctrl/pinmux-node.yaml#
unevaluatedProperties: false
description:
A pin multiplexing sub-node describes how to configure a
set of pins in some desired function.
A single sub-node may define several pin configurations.
This sub-node is using the default pinctrl bindings to configure
pin multiplexing and using SCMI protocol to apply a specified
configuration.
required:
- reg
additionalProperties: false
$defs:
......@@ -355,7 +386,7 @@ examples:
scmi_dvfs: protocol@13 {
reg = <0x13>;
#clock-cells = <1>;
#power-domain-cells = <1>;
mboxes = <&mhuB 1 0>,
<&mhuB 1 1>;
......@@ -401,6 +432,25 @@ examples:
scmi_powercap: protocol@18 {
reg = <0x18>;
};
scmi_pinctrl: protocol@19 {
reg = <0x19>;
i2c2-pins {
groups = "g_i2c2_a", "g_i2c2_b";
function = "f_i2c2";
};
mdio-pins {
groups = "g_avb_mdio";
drive-strength = <24>;
};
keys_pins: keys-pins {
pins = "gpio_5_17", "gpio_5_20", "gpio_5_22", "gpio_2_1";
bias-pull-up;
};
};
};
};
......@@ -468,7 +518,7 @@ examples:
reg = <0x13>;
linaro,optee-channel-id = <1>;
shmem = <&cpu_optee_lpri0>;
#clock-cells = <1>;
#power-domain-cells = <1>;
};
scmi_clk0: protocol@14 {
......
......@@ -127,6 +127,10 @@ properties:
wakeup-source: true
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- reg
......
......@@ -93,6 +93,10 @@ properties:
'#size-cells':
const: 0
access-controllers:
minItems: 1
maxItems: 2
allOf:
- if:
properties:
......
......@@ -59,6 +59,10 @@ properties:
If not, SPI CLKOUT frequency will not be accurate.
maximum: 20000000
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- reg
......
......@@ -45,6 +45,10 @@ properties:
'#size-cells':
const: 0
access-controllers:
minItems: 1
maxItems: 2
additionalProperties: false
required:
......
......@@ -29,6 +29,10 @@ properties:
- const: cec
- const: hdmi-cec
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- reg
......
......@@ -36,6 +36,10 @@ properties:
resets:
maxItems: 1
access-controllers:
minItems: 1
maxItems: 2
port:
$ref: /schemas/graph.yaml#/$defs/port-base
unevaluatedProperties: false
......
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/samsung,s5pv210-dmc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung S5Pv210 SoC Dynamic Memory Controller
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
description:
Dynamic Memory Controller interfaces external JEDEC DDR-type SDRAM.
properties:
compatible:
const: samsung,s5pv210-dmc
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
memory-controller@f0000000 {
compatible = "samsung,s5pv210-dmc";
reg = <0xf0000000 0x1000>;
};
......@@ -50,6 +50,10 @@ properties:
Reflects the memory layout with four integer values per bank. Format:
<bank-number> 0 <address of the bank> <size>
access-controllers:
minItems: 1
maxItems: 2
patternProperties:
"^.*@[0-4],[a-f0-9]+$":
additionalProperties: true
......
......@@ -44,6 +44,10 @@ properties:
wakeup-source: true
access-controllers:
minItems: 1
maxItems: 2
pwm:
type: object
additionalProperties: false
......
......@@ -67,6 +67,10 @@ properties:
"#size-cells":
const: 0
access-controllers:
minItems: 1
maxItems: 2
pwm:
type: object
additionalProperties: false
......
......@@ -79,6 +79,10 @@ properties:
- const: rx
- const: tx
access-controllers:
minItems: 1
maxItems: 2
power-domains: true
resets:
......
......@@ -118,6 +118,10 @@ properties:
phys:
maxItems: 1
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- reg
......
......@@ -93,6 +93,10 @@ properties:
select RCC clock instead of ETH_REF_CLK.
type: boolean
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- clocks
......
......@@ -55,6 +55,10 @@ properties:
description: number of clock cells for ck_usbo_48m consumer
const: 0
access-controllers:
minItems: 1
maxItems: 2
# Required child nodes:
patternProperties:
......
......@@ -30,6 +30,10 @@ properties:
vdda-supply:
description: phandle to the vdda input analog voltage.
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- reg
......
......@@ -37,6 +37,10 @@ properties:
description: If set, the RNG configuration in RNG_CR, RNG_HTCR and
RNG_NSCR will be locked.
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- reg
......
......@@ -73,6 +73,10 @@ properties:
enum: [1, 2, 4, 8, 12, 14, 16]
default: 8
access-controllers:
minItems: 1
maxItems: 2
allOf:
- $ref: rs485.yaml#
- $ref: serial.yaml#
......
......@@ -116,8 +116,8 @@ examples:
bluetooth {
compatible = "qcom,wcnss-bt";
/* BD address 00:11:22:33:44:55 */
local-bd-address = [ 55 44 33 22 11 00 ];
/* Updated by boot firmware (little-endian order) */
local-bd-address = [ 00 00 00 00 00 00 ];
};
wifi {
......
......@@ -65,6 +65,10 @@ properties:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- "#sound-dai-cells"
......
......@@ -48,6 +48,10 @@ properties:
clock-names:
maxItems: 3
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- reg
......
......@@ -50,6 +50,10 @@ properties:
resets:
maxItems: 1
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- "#sound-dai-cells"
......
......@@ -46,6 +46,10 @@ properties:
- const: tx
- const: rx
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- reg
......
......@@ -52,6 +52,10 @@ properties:
- const: rx
- const: tx
access-controllers:
minItems: 1
maxItems: 2
required:
- compatible
- reg
......
......@@ -172,6 +172,10 @@ properties:
tpl-support: true
access-controllers:
minItems: 1
maxItems: 2
dependencies:
port: [ usb-role-switch ]
role-switch-default-mode: [ usb-role-switch ]
......
......@@ -10,6 +10,7 @@ TEE Subsystem
tee
op-tee
amd-tee
ts-tee
.. only:: subproject and html
......
.. SPDX-License-Identifier: GPL-2.0
=================================
TS-TEE (Trusted Services project)
=================================
This driver provides access to secure services implemented by Trusted Services.
Trusted Services [1] is a TrustedFirmware.org project that provides a framework
for developing and deploying device Root of Trust services in FF-A [2] S-EL0
Secure Partitions. The project hosts the reference implementation of the Arm
Platform Security Architecture [3] for Arm A-profile devices.
The FF-A Secure Partitions (SP) are accessible through the FF-A driver [4] which
provides the low level communication for this driver. On top of that the Trusted
Services RPC protocol is used [5]. To use the driver from user space a reference
implementation is provided at [6], which is part of the Trusted Services client
library called libts [7].
All Trusted Services (TS) SPs have the same FF-A UUID; it identifies the TS RPC
protocol. A TS SP can host one or more services (e.g. PSA Crypto, PSA ITS, etc).
A service is identified by its service UUID; the same type of service cannot be
present twice in the same SP. During SP boot each service in the SP is assigned
an "interface ID". This is just a short ID to simplify message addressing.
The generic TEE design is to share memory at once with the Trusted OS, which can
then be reused to communicate with multiple applications running on the Trusted
OS. However, in case of FF-A, memory sharing works on an endpoint level, i.e.
memory is shared with a specific SP. User space has to be able to separately
share memory with each SP based on its endpoint ID; therefore a separate TEE
device is registered for each discovered TS SP. Opening the SP corresponds to
opening the TEE device and creating a TEE context. A TS SP hosts one or more
services. Opening a service corresponds to opening a session in the given
tee_context.
Overview of a system with Trusted Services components::
User space Kernel space Secure world
~~~~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~~~~~~
+--------+ +-------------+
| Client | | Trusted |
+--------+ | Services SP |
/\ +-------------+
|| /\
|| ||
|| ||
\/ \/
+-------+ +----------+--------+ +-------------+
| libts | | TEE | TS-TEE | | FF-A SPMC |
| | | subsys | driver | | + SPMD |
+-------+----------------+----+-----+--------+-----------+-------------+
| Generic TEE API | | FF-A | TS RPC protocol |
| IOCTL (TEE_IOC_*) | | driver | over FF-A |
+-----------------------------+ +--------+-------------------------+
References
==========
[1] https://www.trustedfirmware.org/projects/trusted-services/
[2] https://developer.arm.com/documentation/den0077/
[3] https://www.arm.com/architecture/security-features/platform-security
[4] drivers/firmware/arm_ffa/
[5] https://trusted-services.readthedocs.io/en/v1.0.0/developer/service-access-protocols.html#abi
[6] https://git.trustedfirmware.org/TS/trusted-services.git/tree/components/rpc/ts_rpc/caller/linux/ts_rpc_caller_linux.c?h=v1.0.0
[7] https://git.trustedfirmware.org/TS/trusted-services.git/tree/deployments/libts/arm-linux/CMakeLists.txt?h=v1.0.0
......@@ -2585,12 +2585,8 @@ F: arch/arm64/boot/dts/qcom/sc7180*
F: arch/arm64/boot/dts/qcom/sc7280*
F: arch/arm64/boot/dts/qcom/sdm845-cheza*
ARM/QUALCOMM SUPPORT
M: Bjorn Andersson <andersson@kernel.org>
M: Konrad Dybcio <konrad.dybcio@linaro.org>
ARM/QUALCOMM MAILING LIST
L: linux-arm-msm@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git
F: Documentation/devicetree/bindings/*/qcom*
F: Documentation/devicetree/bindings/soc/qcom/
F: arch/arm/boot/dts/qcom/
......@@ -2627,6 +2623,33 @@ F: include/dt-bindings/*/qcom*
F: include/linux/*/qcom*
F: include/linux/soc/qcom/
ARM/QUALCOMM SUPPORT
M: Bjorn Andersson <andersson@kernel.org>
M: Konrad Dybcio <konrad.dybcio@linaro.org>
L: linux-arm-msm@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git
F: Documentation/devicetree/bindings/arm/qcom-soc.yaml
F: Documentation/devicetree/bindings/arm/qcom.yaml
F: Documentation/devicetree/bindings/bus/qcom*
F: Documentation/devicetree/bindings/cache/qcom,llcc.yaml
F: Documentation/devicetree/bindings/firmware/qcom,scm.yaml
F: Documentation/devicetree/bindings/reserved-memory/qcom
F: Documentation/devicetree/bindings/soc/qcom/
F: arch/arm/boot/dts/qcom/
F: arch/arm/configs/qcom_defconfig
F: arch/arm/mach-qcom/
F: arch/arm64/boot/dts/qcom/
F: drivers/bus/qcom*
F: drivers/firmware/qcom/
F: drivers/soc/qcom/
F: include/dt-bindings/arm/qcom,ids.h
F: include/dt-bindings/firmware/qcom,scm.h
F: include/dt-bindings/soc/qcom*
F: include/linux/firmware/qcom
F: include/linux/soc/qcom/
F: include/soc/qcom/
ARM/RDA MICRO ARCHITECTURE
M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
......@@ -20833,6 +20856,13 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/st,st-mipid02.yaml
F: drivers/media/i2c/st-mipid02.c
ST STM32 FIREWALL
M: Gatien Chevallier <gatien.chevallier@foss.st.com>
S: Maintained
F: drivers/bus/stm32_etzpc.c
F: drivers/bus/stm32_firewall.c
F: drivers/bus/stm32_rifsc.c
ST STM32 I2C/SMBUS DRIVER
M: Pierre-Yves MORDRET <pierre-yves.mordret@foss.st.com>
M: Alain Volmat <alain.volmat@foss.st.com>
......@@ -21475,6 +21505,7 @@ F: drivers/cpufreq/sc[mp]i-cpufreq.c
F: drivers/firmware/arm_scmi/
F: drivers/firmware/arm_scpi.c
F: drivers/hwmon/scmi-hwmon.c
F: drivers/pinctrl/pinctrl-scmi.c
F: drivers/pmdomain/arm/
F: drivers/powercap/arm_scmi_powercap.c
F: drivers/regulator/scmi-regulator.c
......@@ -21706,6 +21737,7 @@ F: Documentation/driver-api/tee.rst
F: Documentation/tee/
F: Documentation/userspace-api/tee.rst
F: drivers/tee/
F: include/linux/tee_core.h
F: include/linux/tee_drv.h
F: include/uapi/linux/tee.h
......@@ -22499,6 +22531,15 @@ F: Documentation/ABI/testing/configfs-tsm
F: drivers/virt/coco/tsm.c
F: include/linux/tsm.h
TRUSTED SERVICES TEE DRIVER
M: Balint Dobszay <balint.dobszay@arm.com>
M: Sudeep Holla <sudeep.holla@arm.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: trusted-services@lists.trustedfirmware.org
S: Maintained
F: Documentation/tee/ts-tee.rst
F: drivers/tee/tstee/
TTY LAYER AND SERIAL DRIVERS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
M: Jiri Slaby <jirislaby@kernel.org>
......
......@@ -12,6 +12,7 @@ menuconfig ARCH_STM32
select PINCTRL
select RESET_CONTROLLER
select STM32_EXTI
select STM32_FIREWALL
help
Support for STMicroelectronics STM32 processors.
......
......@@ -305,6 +305,7 @@ config ARCH_STM32
select ARM_SMC_MBOX
select ARM_SCMI_PROTOCOL
select COMMON_CLK_SCMI
select STM32_FIREWALL
help
This enables support for ARMv8 based STMicroelectronics
STM32 family, including:
......
menu "SoC selection"
config ARCH_MICROCHIP_POLARFIRE
def_bool SOC_MICROCHIP_POLARFIRE
def_bool ARCH_MICROCHIP
config SOC_MICROCHIP_POLARFIRE
bool "Microchip PolarFire SoCs"
config ARCH_MICROCHIP
bool "Microchip SoCs"
help
This enables support for Microchip PolarFire SoC platforms.
This enables support for Microchip SoC platforms.
config ARCH_RENESAS
bool "Renesas RISC-V SoCs"
......@@ -14,9 +14,6 @@ config ARCH_RENESAS
This enables support for the RISC-V based Renesas SoCs.
config ARCH_SIFIVE
def_bool SOC_SIFIVE
config SOC_SIFIVE
bool "SiFive SoCs"
select ERRATA_SIFIVE if !XIP_KERNEL
help
......@@ -55,9 +52,6 @@ config ARCH_THEAD
This enables support for the RISC-V based T-HEAD SoCs.
config ARCH_VIRT
def_bool SOC_VIRT
config SOC_VIRT
bool "QEMU Virt Machine"
select CLINT_TIMER if RISCV_M_MODE
select POWER_RESET
......@@ -72,11 +66,13 @@ config SOC_VIRT
This enables support for QEMU Virt Machine.
config ARCH_CANAAN
def_bool SOC_CANAAN
bool "Canaan Kendryte SoC"
help
This enables support for Canaan Kendryte series SoC platform hardware.
config SOC_CANAAN
config SOC_CANAAN_K210
bool "Canaan Kendryte K210 SoC"
depends on !MMU
depends on !MMU && ARCH_CANAAN
select CLINT_TIMER if RISCV_M_MODE
select ARCH_HAS_RESET_CONTROLLER
select PINCTRL
......
......@@ -154,7 +154,7 @@ vdso-install-y += arch/riscv/kernel/vdso/vdso.so.dbg
vdso-install-$(CONFIG_COMPAT) += arch/riscv/kernel/compat_vdso/compat_vdso.so.dbg
ifneq ($(CONFIG_XIP_KERNEL),y)
ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_ARCH_CANAAN),yy)
ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_SOC_CANAAN_K210),yy)
KBUILD_IMAGE := $(boot)/loader.bin
else
ifeq ($(CONFIG_EFI_ZBOOT),)
......
......@@ -25,14 +25,15 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_EXPERT=y
# CONFIG_SYSFS_SYSCALL is not set
CONFIG_PROFILING=y
CONFIG_SOC_MICROCHIP_POLARFIRE=y
CONFIG_ARCH_MICROCHIP=y
CONFIG_ARCH_RENESAS=y
CONFIG_SOC_SIFIVE=y
CONFIG_ARCH_SIFIVE=y
CONFIG_ARCH_SOPHGO=y
CONFIG_SOC_STARFIVE=y
CONFIG_ARCH_SUNXI=y
CONFIG_ARCH_THEAD=y
CONFIG_SOC_VIRT=y
CONFIG_ARCH_VIRT=y
CONFIG_ARCH_CANAAN=y
CONFIG_SMP=y
CONFIG_HOTPLUG_CPU=y
CONFIG_PM=y
......
......@@ -27,7 +27,8 @@ CONFIG_EXPERT=y
CONFIG_SLUB=y
CONFIG_SLUB_TINY=y
# CONFIG_MMU is not set
CONFIG_SOC_CANAAN=y
CONFIG_ARCH_CANAAN=y
CONFIG_SOC_CANAAN_K210=y
CONFIG_NONPORTABLE=y
CONFIG_SMP=y
CONFIG_NR_CPUS=2
......
......@@ -19,7 +19,8 @@ CONFIG_EXPERT=y
CONFIG_SLUB=y
CONFIG_SLUB_TINY=y
# CONFIG_MMU is not set
CONFIG_SOC_CANAAN=y
CONFIG_ARCH_CANAAN=y
CONFIG_SOC_CANAAN_K210=y
CONFIG_NONPORTABLE=y
CONFIG_SMP=y
CONFIG_NR_CPUS=2
......
......@@ -24,7 +24,7 @@ CONFIG_EXPERT=y
CONFIG_SLUB=y
CONFIG_SLUB_TINY=y
# CONFIG_MMU is not set
CONFIG_SOC_VIRT=y
CONFIG_ARCH_VIRT=y
CONFIG_NONPORTABLE=y
CONFIG_SMP=y
CONFIG_CMDLINE="root=/dev/vda rw earlycon=uart8250,mmio,0x10000000,115200n8 console=ttyS0"
......
......@@ -163,6 +163,16 @@ config QCOM_SSC_BLOCK_BUS
i2c/spi/uart controllers, a hexagon core, and a clock controller
which provides clocks for the above.
config STM32_FIREWALL
bool "STM32 Firewall framework"
depends on (ARCH_STM32 || COMPILE_TEST) && OF
select OF_DYNAMIC
help
Say y to enable STM32 firewall framework and its services. Firewall
controllers will be able to register to the framework. Access for
hardware resources linked to a firewall controller can be requested
through this STM32 framework.
config SUN50I_DE2_BUS
bool "Allwinner A64 DE2 Bus Driver"
default ARM64
......
......@@ -26,6 +26,7 @@ obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o
obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
obj-$(CONFIG_QCOM_EBI2) += qcom-ebi2.o
obj-$(CONFIG_QCOM_SSC_BLOCK_BUS) += qcom-ssc-block-bus.o
obj-$(CONFIG_STM32_FIREWALL) += stm32_firewall.o stm32_rifsc.o stm32_etzpc.o
obj-$(CONFIG_SUN50I_DE2_BUS) += sun50i-de2.o
obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
obj-$(CONFIG_OF) += simple-pm-bus.o
......
......@@ -410,6 +410,7 @@ static const struct of_device_id brcmstb_gisb_arb_of_match[] = {
{ .compatible = "brcm,bcm74165-gisb-arb", .data = gisb_offsets_bcm74165 },
{ },
};
MODULE_DEVICE_TABLE(of, brcmstb_gisb_arb_of_match);
static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
{
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2023, STMicroelectronics - All Rights Reserved
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include "stm32_firewall.h"
/*
* ETZPC registers
*/
#define ETZPC_DECPROT 0x10
#define ETZPC_HWCFGR 0x3F0
/*
* HWCFGR register
*/
#define ETZPC_HWCFGR_NUM_TZMA GENMASK(7, 0)
#define ETZPC_HWCFGR_NUM_PER_SEC GENMASK(15, 8)
#define ETZPC_HWCFGR_NUM_AHB_SEC GENMASK(23, 16)
#define ETZPC_HWCFGR_CHUNKS1N4 GENMASK(31, 24)
/*
* ETZPC miscellaneous
*/
#define ETZPC_PROT_MASK GENMASK(1, 0)
#define ETZPC_PROT_A7NS 0x3
#define ETZPC_DECPROT_SHIFT 1
#define IDS_PER_DECPROT_REGS 16
static int stm32_etzpc_grant_access(struct stm32_firewall_controller *ctrl, u32 firewall_id)
{
u32 offset, reg_offset, sec_val;
if (firewall_id >= ctrl->max_entries) {
dev_err(ctrl->dev, "Invalid sys bus ID %u", firewall_id);
return -EINVAL;
}
/* Check access configuration, 16 peripherals per register */
reg_offset = ETZPC_DECPROT + 0x4 * (firewall_id / IDS_PER_DECPROT_REGS);
offset = (firewall_id % IDS_PER_DECPROT_REGS) << ETZPC_DECPROT_SHIFT;
/* Verify peripheral is non-secure and attributed to cortex A7 */
sec_val = (readl(ctrl->mmio + reg_offset) >> offset) & ETZPC_PROT_MASK;
if (sec_val != ETZPC_PROT_A7NS) {
dev_dbg(ctrl->dev, "Invalid bus configuration: reg_offset %#x, value %d\n",
reg_offset, sec_val);
return -EACCES;
}
return 0;
}
static void stm32_etzpc_release_access(struct stm32_firewall_controller *ctrl __maybe_unused,
u32 firewall_id __maybe_unused)
{
}
static int stm32_etzpc_probe(struct platform_device *pdev)
{
struct stm32_firewall_controller *etzpc_controller;
struct device_node *np = pdev->dev.of_node;
u32 nb_per, nb_master;
struct resource *res;
void __iomem *mmio;
int rc;
etzpc_controller = devm_kzalloc(&pdev->dev, sizeof(*etzpc_controller), GFP_KERNEL);
if (!etzpc_controller)
return -ENOMEM;
mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(mmio))
return PTR_ERR(mmio);
etzpc_controller->dev = &pdev->dev;
etzpc_controller->mmio = mmio;
etzpc_controller->name = dev_driver_string(etzpc_controller->dev);
etzpc_controller->type = STM32_PERIPHERAL_FIREWALL | STM32_MEMORY_FIREWALL;
etzpc_controller->grant_access = stm32_etzpc_grant_access;
etzpc_controller->release_access = stm32_etzpc_release_access;
/* Get number of etzpc entries*/
nb_per = FIELD_GET(ETZPC_HWCFGR_NUM_PER_SEC,
readl(etzpc_controller->mmio + ETZPC_HWCFGR));
nb_master = FIELD_GET(ETZPC_HWCFGR_NUM_AHB_SEC,
readl(etzpc_controller->mmio + ETZPC_HWCFGR));
etzpc_controller->max_entries = nb_per + nb_master;
platform_set_drvdata(pdev, etzpc_controller);
rc = stm32_firewall_controller_register(etzpc_controller);
if (rc) {
dev_err(etzpc_controller->dev, "Couldn't register as a firewall controller: %d",
rc);
return rc;
}
rc = stm32_firewall_populate_bus(etzpc_controller);
if (rc) {
dev_err(etzpc_controller->dev, "Couldn't populate ETZPC bus: %d",
rc);
return rc;
}
/* Populate all allowed nodes */
return of_platform_populate(np, NULL, NULL, &pdev->dev);
}
static const struct of_device_id stm32_etzpc_of_match[] = {
{ .compatible = "st,stm32-etzpc" },
{}
};
MODULE_DEVICE_TABLE(of, stm32_etzpc_of_match);
static struct platform_driver stm32_etzpc_driver = {
.probe = stm32_etzpc_probe,
.driver = {
.name = "stm32-etzpc",
.of_match_table = stm32_etzpc_of_match,
},
};
module_platform_driver(stm32_etzpc_driver);
MODULE_AUTHOR("Gatien Chevallier <gatien.chevallier@foss.st.com>");
MODULE_DESCRIPTION("STMicroelectronics ETZPC driver");
MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2023, STMicroelectronics - All Rights Reserved
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/bus/stm32_firewall_device.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/slab.h>
#include "stm32_firewall.h"
/* Corresponds to STM32_FIREWALL_MAX_EXTRA_ARGS + firewall ID */
#define STM32_FIREWALL_MAX_ARGS (STM32_FIREWALL_MAX_EXTRA_ARGS + 1)
static LIST_HEAD(firewall_controller_list);
static DEFINE_MUTEX(firewall_controller_list_lock);
/* Firewall device API */
int stm32_firewall_get_firewall(struct device_node *np, struct stm32_firewall *firewall,
unsigned int nb_firewall)
{
struct stm32_firewall_controller *ctrl;
struct of_phandle_iterator it;
unsigned int i, j = 0;
int err;
if (!firewall || !nb_firewall)
return -EINVAL;
/* Parse property with phandle parsed out */
of_for_each_phandle(&it, err, np, "access-controllers", "#access-controller-cells", 0) {
struct of_phandle_args provider_args;
struct device_node *provider = it.node;
const char *fw_entry;
bool match = false;
if (err) {
pr_err("Unable to get access-controllers property for node %s\n, err: %d",
np->full_name, err);
of_node_put(provider);
return err;
}
if (j >= nb_firewall) {
pr_err("Too many firewall controllers");
of_node_put(provider);
return -EINVAL;
}
provider_args.args_count = of_phandle_iterator_args(&it, provider_args.args,
STM32_FIREWALL_MAX_ARGS);
/* Check if the parsed phandle corresponds to a registered firewall controller */
mutex_lock(&firewall_controller_list_lock);
list_for_each_entry(ctrl, &firewall_controller_list, entry) {
if (ctrl->dev->of_node->phandle == it.phandle) {
match = true;
firewall[j].firewall_ctrl = ctrl;
break;
}
}
mutex_unlock(&firewall_controller_list_lock);
if (!match) {
firewall[j].firewall_ctrl = NULL;
pr_err("No firewall controller registered for %s\n", np->full_name);
of_node_put(provider);
return -ENODEV;
}
err = of_property_read_string_index(np, "access-controller-names", j, &fw_entry);
if (err == 0)
firewall[j].entry = fw_entry;
/* Handle the case when there are no arguments given along with the phandle */
if (provider_args.args_count < 0 ||
provider_args.args_count > STM32_FIREWALL_MAX_ARGS) {
of_node_put(provider);
return -EINVAL;
} else if (provider_args.args_count == 0) {
firewall[j].extra_args_size = 0;
firewall[j].firewall_id = U32_MAX;
j++;
continue;
}
/* The firewall ID is always the first argument */
firewall[j].firewall_id = provider_args.args[0];
/* Extra args start at the second argument */
for (i = 0; i < provider_args.args_count - 1; i++)
firewall[j].extra_args[i] = provider_args.args[i + 1];
/* Remove the firewall ID arg that is not an extra argument */
firewall[j].extra_args_size = provider_args.args_count - 1;
j++;
}
return 0;
}
EXPORT_SYMBOL_GPL(stm32_firewall_get_firewall);
int stm32_firewall_grant_access(struct stm32_firewall *firewall)
{
struct stm32_firewall_controller *firewall_controller;
if (!firewall || firewall->firewall_id == U32_MAX)
return -EINVAL;
firewall_controller = firewall->firewall_ctrl;
if (!firewall_controller)
return -ENODEV;
return firewall_controller->grant_access(firewall_controller, firewall->firewall_id);
}
EXPORT_SYMBOL_GPL(stm32_firewall_grant_access);
int stm32_firewall_grant_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id)
{
struct stm32_firewall_controller *firewall_controller;
if (!firewall || subsystem_id == U32_MAX || firewall->firewall_id == U32_MAX)
return -EINVAL;
firewall_controller = firewall->firewall_ctrl;
if (!firewall_controller)
return -ENODEV;
return firewall_controller->grant_access(firewall_controller, subsystem_id);
}
EXPORT_SYMBOL_GPL(stm32_firewall_grant_access_by_id);
void stm32_firewall_release_access(struct stm32_firewall *firewall)
{
struct stm32_firewall_controller *firewall_controller;
if (!firewall || firewall->firewall_id == U32_MAX) {
pr_debug("Incorrect arguments when releasing a firewall access\n");
return;
}
firewall_controller = firewall->firewall_ctrl;
if (!firewall_controller) {
pr_debug("No firewall controller to release\n");
return;
}
firewall_controller->release_access(firewall_controller, firewall->firewall_id);
}
EXPORT_SYMBOL_GPL(stm32_firewall_release_access);
void stm32_firewall_release_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id)
{
struct stm32_firewall_controller *firewall_controller;
if (!firewall || subsystem_id == U32_MAX || firewall->firewall_id == U32_MAX) {
pr_debug("Incorrect arguments when releasing a firewall access");
return;
}
firewall_controller = firewall->firewall_ctrl;
if (!firewall_controller) {
pr_debug("No firewall controller to release");
return;
}
firewall_controller->release_access(firewall_controller, subsystem_id);
}
EXPORT_SYMBOL_GPL(stm32_firewall_release_access_by_id);
/* Firewall controller API */
int stm32_firewall_controller_register(struct stm32_firewall_controller *firewall_controller)
{
struct stm32_firewall_controller *ctrl;
if (!firewall_controller)
return -ENODEV;
pr_info("Registering %s firewall controller\n", firewall_controller->name);
mutex_lock(&firewall_controller_list_lock);
list_for_each_entry(ctrl, &firewall_controller_list, entry) {
if (ctrl == firewall_controller) {
pr_debug("%s firewall controller already registered\n",
firewall_controller->name);
mutex_unlock(&firewall_controller_list_lock);
return 0;
}
}
list_add_tail(&firewall_controller->entry, &firewall_controller_list);
mutex_unlock(&firewall_controller_list_lock);
return 0;
}
EXPORT_SYMBOL_GPL(stm32_firewall_controller_register);
void stm32_firewall_controller_unregister(struct stm32_firewall_controller *firewall_controller)
{
struct stm32_firewall_controller *ctrl;
bool controller_removed = false;
if (!firewall_controller) {
pr_debug("Null reference while unregistering firewall controller\n");
return;
}
mutex_lock(&firewall_controller_list_lock);
list_for_each_entry(ctrl, &firewall_controller_list, entry) {
if (ctrl == firewall_controller) {
controller_removed = true;
list_del_init(&ctrl->entry);
break;
}
}
mutex_unlock(&firewall_controller_list_lock);
if (!controller_removed)
pr_debug("There was no firewall controller named %s to unregister\n",
firewall_controller->name);
}
EXPORT_SYMBOL_GPL(stm32_firewall_controller_unregister);
int stm32_firewall_populate_bus(struct stm32_firewall_controller *firewall_controller)
{
struct stm32_firewall *firewalls;
struct device_node *child;
struct device *parent;
unsigned int i;
int len;
int err;
parent = firewall_controller->dev;
dev_dbg(parent, "Populating %s system bus\n", dev_name(firewall_controller->dev));
for_each_available_child_of_node(dev_of_node(parent), child) {
/* The access-controllers property is mandatory for firewall bus devices */
len = of_count_phandle_with_args(child, "access-controllers",
"#access-controller-cells");
if (len <= 0) {
of_node_put(child);
return -EINVAL;
}
firewalls = kcalloc(len, sizeof(*firewalls), GFP_KERNEL);
if (!firewalls) {
of_node_put(child);
return -ENOMEM;
}
err = stm32_firewall_get_firewall(child, firewalls, (unsigned int)len);
if (err) {
kfree(firewalls);
of_node_put(child);
return err;
}
for (i = 0; i < len; i++) {
if (firewall_controller->grant_access(firewall_controller,
firewalls[i].firewall_id)) {
/*
* Peripheral access not allowed or not defined.
* Mark the node as populated so platform bus won't probe it
*/
of_detach_node(child);
dev_err(parent, "%s: Device driver will not be probed\n",
child->full_name);
}
}
kfree(firewalls);
}
return 0;
}
EXPORT_SYMBOL_GPL(stm32_firewall_populate_bus);
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2023, STMicroelectronics - All Rights Reserved
*/
#ifndef _STM32_FIREWALL_H
#define _STM32_FIREWALL_H
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/types.h>
/**
* STM32_PERIPHERAL_FIREWALL: This type of firewall protects peripherals
* STM32_MEMORY_FIREWALL: This type of firewall protects memories/subsets of memory
* zones
* STM32_NOTYPE_FIREWALL: Undefined firewall type
*/
#define STM32_PERIPHERAL_FIREWALL BIT(1)
#define STM32_MEMORY_FIREWALL BIT(2)
#define STM32_NOTYPE_FIREWALL BIT(3)
/**
* struct stm32_firewall_controller - Information on firewall controller supplying services
*
* @name: Name of the firewall controller
* @dev: Device reference of the firewall controller
* @mmio: Base address of the firewall controller
* @entry: List entry of the firewall controller list
* @type: Type of firewall
* @max_entries: Number of entries covered by the firewall
* @grant_access: Callback used to grant access for a device access against a
* firewall controller
* @release_access: Callback used to release resources taken by a device when access was
* granted
* @grant_memory_range_access: Callback used to grant access for a device to a given memory region
*/
struct stm32_firewall_controller {
const char *name;
struct device *dev;
void __iomem *mmio;
struct list_head entry;
unsigned int type;
unsigned int max_entries;
int (*grant_access)(struct stm32_firewall_controller *ctrl, u32 id);
void (*release_access)(struct stm32_firewall_controller *ctrl, u32 id);
int (*grant_memory_range_access)(struct stm32_firewall_controller *ctrl, phys_addr_t paddr,
size_t size);
};
/**
* stm32_firewall_controller_register - Register a firewall controller to the STM32 firewall
* framework
* @firewall_controller: Firewall controller to register
*
* Returns 0 in case of success or -ENODEV if no controller was given.
*/
int stm32_firewall_controller_register(struct stm32_firewall_controller *firewall_controller);
/**
* stm32_firewall_controller_unregister - Unregister a firewall controller from the STM32
* firewall framework
* @firewall_controller: Firewall controller to unregister
*/
void stm32_firewall_controller_unregister(struct stm32_firewall_controller *firewall_controller);
/**
* stm32_firewall_populate_bus - Populate device tree nodes that have a correct firewall
* configuration. This is used at boot-time only, as a sanity check
* between device tree and firewalls hardware configurations to
* prevent a kernel crash when a device driver is not granted access
*
* @firewall_controller: Firewall controller which nodes will be populated or not
*
* Returns 0 in case of success or appropriate errno code if error occurred.
*/
int stm32_firewall_populate_bus(struct stm32_firewall_controller *firewall_controller);
#endif /* _STM32_FIREWALL_H */
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2023, STMicroelectronics - All Rights Reserved
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include "stm32_firewall.h"
/*
* RIFSC offset register
*/
#define RIFSC_RISC_SECCFGR0 0x10
#define RIFSC_RISC_PRIVCFGR0 0x30
#define RIFSC_RISC_PER0_CIDCFGR 0x100
#define RIFSC_RISC_PER0_SEMCR 0x104
#define RIFSC_RISC_HWCFGR2 0xFEC
/*
* SEMCR register
*/
#define SEMCR_MUTEX BIT(0)
/*
* HWCFGR2 register
*/
#define HWCFGR2_CONF1_MASK GENMASK(15, 0)
#define HWCFGR2_CONF2_MASK GENMASK(23, 16)
#define HWCFGR2_CONF3_MASK GENMASK(31, 24)
/*
* RIFSC miscellaneous
*/
#define RIFSC_RISC_CFEN_MASK BIT(0)
#define RIFSC_RISC_SEM_EN_MASK BIT(1)
#define RIFSC_RISC_SCID_MASK GENMASK(6, 4)
#define RIFSC_RISC_SEML_SHIFT 16
#define RIFSC_RISC_SEMWL_MASK GENMASK(23, 16)
#define RIFSC_RISC_PER_ID_MASK GENMASK(31, 24)
#define RIFSC_RISC_PERx_CID_MASK (RIFSC_RISC_CFEN_MASK | \
RIFSC_RISC_SEM_EN_MASK | \
RIFSC_RISC_SCID_MASK | \
RIFSC_RISC_SEMWL_MASK)
#define IDS_PER_RISC_SEC_PRIV_REGS 32
/* RIF miscellaneous */
/*
* CIDCFGR register fields
*/
#define CIDCFGR_CFEN BIT(0)
#define CIDCFGR_SEMEN BIT(1)
#define CIDCFGR_SEMWL(x) BIT(RIFSC_RISC_SEML_SHIFT + (x))
#define SEMWL_SHIFT 16
/* Compartiment IDs */
#define RIF_CID0 0x0
#define RIF_CID1 0x1
static bool stm32_rifsc_is_semaphore_available(void __iomem *addr)
{
return !(readl(addr) & SEMCR_MUTEX);
}
static int stm32_rif_acquire_semaphore(struct stm32_firewall_controller *stm32_firewall_controller,
int id)
{
void __iomem *addr = stm32_firewall_controller->mmio + RIFSC_RISC_PER0_SEMCR + 0x8 * id;
writel(SEMCR_MUTEX, addr);
/* Check that CID1 has the semaphore */
if (stm32_rifsc_is_semaphore_available(addr) ||
FIELD_GET(RIFSC_RISC_SCID_MASK, readl(addr)) != RIF_CID1)
return -EACCES;
return 0;
}
static void stm32_rif_release_semaphore(struct stm32_firewall_controller *stm32_firewall_controller,
int id)
{
void __iomem *addr = stm32_firewall_controller->mmio + RIFSC_RISC_PER0_SEMCR + 0x8 * id;
if (stm32_rifsc_is_semaphore_available(addr))
return;
writel(SEMCR_MUTEX, addr);
/* Ok if another compartment takes the semaphore before the check */
WARN_ON(!stm32_rifsc_is_semaphore_available(addr) &&
FIELD_GET(RIFSC_RISC_SCID_MASK, readl(addr)) == RIF_CID1);
}
static int stm32_rifsc_grant_access(struct stm32_firewall_controller *ctrl, u32 firewall_id)
{
struct stm32_firewall_controller *rifsc_controller = ctrl;
u32 reg_offset, reg_id, sec_reg_value, cid_reg_value;
int rc;
if (firewall_id >= rifsc_controller->max_entries) {
dev_err(rifsc_controller->dev, "Invalid sys bus ID %u", firewall_id);
return -EINVAL;
}
/*
* RIFSC_RISC_PRIVCFGRx and RIFSC_RISC_SECCFGRx both handle configuration access for
* 32 peripherals. On the other hand, there is one _RIFSC_RISC_PERx_CIDCFGR register
* per peripheral
*/
reg_id = firewall_id / IDS_PER_RISC_SEC_PRIV_REGS;
reg_offset = firewall_id % IDS_PER_RISC_SEC_PRIV_REGS;
sec_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_SECCFGR0 + 0x4 * reg_id);
cid_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_PER0_CIDCFGR + 0x8 * firewall_id);
/* First check conditions for semaphore mode, which doesn't take into account static CID. */
if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) {
if (cid_reg_value & BIT(RIF_CID1 + SEMWL_SHIFT)) {
/* Static CID is irrelevant if semaphore mode */
goto skip_cid_check;
} else {
dev_dbg(rifsc_controller->dev,
"Invalid bus semaphore configuration: index %d\n", firewall_id);
return -EACCES;
}
}
/*
* Skip CID check if CID filtering isn't enabled or filtering is enabled on CID0, which
* corresponds to whatever CID.
*/
if (!(cid_reg_value & CIDCFGR_CFEN) ||
FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) == RIF_CID0)
goto skip_cid_check;
/* Coherency check with the CID configuration */
if (FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) != RIF_CID1) {
dev_dbg(rifsc_controller->dev, "Invalid CID configuration for peripheral: %d\n",
firewall_id);
return -EACCES;
}
skip_cid_check:
/* Check security configuration */
if (sec_reg_value & BIT(reg_offset)) {
dev_dbg(rifsc_controller->dev,
"Invalid security configuration for peripheral: %d\n", firewall_id);
return -EACCES;
}
/*
* If the peripheral is in semaphore mode, take the semaphore so that
* the CID1 has the ownership.
*/
if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) {
rc = stm32_rif_acquire_semaphore(rifsc_controller, firewall_id);
if (rc) {
dev_err(rifsc_controller->dev,
"Couldn't acquire semaphore for peripheral: %d\n", firewall_id);
return rc;
}
}
return 0;
}
static void stm32_rifsc_release_access(struct stm32_firewall_controller *ctrl, u32 firewall_id)
{
stm32_rif_release_semaphore(ctrl, firewall_id);
}
static int stm32_rifsc_probe(struct platform_device *pdev)
{
struct stm32_firewall_controller *rifsc_controller;
struct device_node *np = pdev->dev.of_node;
u32 nb_risup, nb_rimu, nb_risal;
struct resource *res;
void __iomem *mmio;
int rc;
rifsc_controller = devm_kzalloc(&pdev->dev, sizeof(*rifsc_controller), GFP_KERNEL);
if (!rifsc_controller)
return -ENOMEM;
mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(mmio))
return PTR_ERR(mmio);
rifsc_controller->dev = &pdev->dev;
rifsc_controller->mmio = mmio;
rifsc_controller->name = dev_driver_string(rifsc_controller->dev);
rifsc_controller->type = STM32_PERIPHERAL_FIREWALL | STM32_MEMORY_FIREWALL;
rifsc_controller->grant_access = stm32_rifsc_grant_access;
rifsc_controller->release_access = stm32_rifsc_release_access;
/* Get number of RIFSC entries*/
nb_risup = readl(rifsc_controller->mmio + RIFSC_RISC_HWCFGR2) & HWCFGR2_CONF1_MASK;
nb_rimu = readl(rifsc_controller->mmio + RIFSC_RISC_HWCFGR2) & HWCFGR2_CONF2_MASK;
nb_risal = readl(rifsc_controller->mmio + RIFSC_RISC_HWCFGR2) & HWCFGR2_CONF3_MASK;
rifsc_controller->max_entries = nb_risup + nb_rimu + nb_risal;
platform_set_drvdata(pdev, rifsc_controller);
rc = stm32_firewall_controller_register(rifsc_controller);
if (rc) {
dev_err(rifsc_controller->dev, "Couldn't register as a firewall controller: %d",
rc);
return rc;
}
rc = stm32_firewall_populate_bus(rifsc_controller);
if (rc) {
dev_err(rifsc_controller->dev, "Couldn't populate RIFSC bus: %d",
rc);
return rc;
}
/* Populate all allowed nodes */
return of_platform_populate(np, NULL, NULL, &pdev->dev);
}
static const struct of_device_id stm32_rifsc_of_match[] = {
{ .compatible = "st,stm32mp25-rifsc" },
{}
};
MODULE_DEVICE_TABLE(of, stm32_rifsc_of_match);
static struct platform_driver stm32_rifsc_driver = {
.probe = stm32_rifsc_probe,
.driver = {
.name = "stm32-rifsc",
.of_match_table = stm32_rifsc_of_match,
},
};
module_platform_driver(stm32_rifsc_driver);
MODULE_AUTHOR("Gatien Chevallier <gatien.chevallier@foss.st.com>");
MODULE_DESCRIPTION("STMicroelectronics RIFSC driver");
MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0
/*
* ti-sysc.c - Texas Instruments sysc interconnect target driver
*
* TI SoCs have an interconnect target wrapper IP for many devices. The wrapper
* IP manages clock gating, resets, and PM capabilities for the connected devices.
*
* Copyright (C) 2017-2024 Texas Instruments Incorporated - https://www.ti.com/
*
* Many features are based on the earlier omap_hwmod arch code with thanks to all
* the people who developed and debugged the code over the years:
*
* Copyright (C) 2009-2011 Nokia Corporation
* Copyright (C) 2011-2021 Texas Instruments Incorporated - https://www.ti.com/
*/
#include <linux/io.h>
......@@ -1458,8 +1469,7 @@ static int __maybe_unused sysc_noirq_suspend(struct device *dev)
ddata = dev_get_drvdata(dev);
if (ddata->cfg.quirks &
(SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_NO_IDLE))
if (ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE)
return 0;
if (!ddata->enabled)
......@@ -1477,8 +1487,7 @@ static int __maybe_unused sysc_noirq_resume(struct device *dev)
ddata = dev_get_drvdata(dev);
if (ddata->cfg.quirks &
(SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_NO_IDLE))
if (ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE)
return 0;
if (ddata->cfg.quirks & SYSC_QUIRK_REINIT_ON_RESUME) {
......@@ -1529,19 +1538,6 @@ struct sysc_revision_quirk {
}
static const struct sysc_revision_quirk sysc_revision_quirks[] = {
/* These drivers need to be fixed to not use pm_runtime_irq_safe() */
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
/* Uarts on omap4 and later */
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffff00ff,
SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47422e03, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47424e03, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
/* Quirks that need to be set based on the module address */
SYSC_QUIRK("mcpdm", 0x40132000, 0, 0x10, -ENODEV, 0x50000800, 0xffffffff,
SYSC_QUIRK_EXT_OPT_CLOCK | SYSC_QUIRK_NO_RESET_ON_INIT |
......@@ -1599,6 +1595,17 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
SYSC_QUIRK("sata", 0, 0xfc, 0x1100, -ENODEV, 0x5e412000, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE_ACT),
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE_ACT),
/* Uarts on omap4 and later */
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffff00ff,
SYSC_QUIRK_SWSUP_SIDLE_ACT),
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47422e03, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE_ACT),
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47424e03, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE_ACT),
SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -ENODEV, 0x50700101, 0xffffffff,
......@@ -2145,8 +2152,7 @@ static int sysc_reset(struct sysc *ddata)
sysc_offset = ddata->offsets[SYSC_SYSCONFIG];
if (ddata->legacy_mode ||
ddata->cap->regbits->srst_shift < 0 ||
ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
ddata->cap->regbits->srst_shift < 0)
return 0;
sysc_mask = BIT(ddata->cap->regbits->srst_shift);
......@@ -2240,12 +2246,14 @@ static int sysc_init_module(struct sysc *ddata)
goto err_main_clocks;
}
if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)) {
error = sysc_reset(ddata);
if (error)
dev_err(ddata->dev, "Reset failed with %d\n", error);
if (error && !ddata->legacy_mode)
sysc_disable_module(ddata->dev);
}
err_main_clocks:
if (error)
......@@ -2447,89 +2455,6 @@ static int __maybe_unused sysc_child_runtime_resume(struct device *dev)
return pm_generic_runtime_resume(dev);
}
#ifdef CONFIG_PM_SLEEP
static int sysc_child_suspend_noirq(struct device *dev)
{
struct sysc *ddata;
int error;
ddata = sysc_child_to_parent(dev);
dev_dbg(ddata->dev, "%s %s\n", __func__,
ddata->name ? ddata->name : "");
error = pm_generic_suspend_noirq(dev);
if (error) {
dev_err(dev, "%s error at %i: %i\n",
__func__, __LINE__, error);
return error;
}
if (!pm_runtime_status_suspended(dev)) {
error = pm_generic_runtime_suspend(dev);
if (error) {
dev_dbg(dev, "%s busy at %i: %i\n",
__func__, __LINE__, error);
return 0;
}
error = sysc_runtime_suspend(ddata->dev);
if (error) {
dev_err(dev, "%s error at %i: %i\n",
__func__, __LINE__, error);
return error;
}
ddata->child_needs_resume = true;
}
return 0;
}
static int sysc_child_resume_noirq(struct device *dev)
{
struct sysc *ddata;
int error;
ddata = sysc_child_to_parent(dev);
dev_dbg(ddata->dev, "%s %s\n", __func__,
ddata->name ? ddata->name : "");
if (ddata->child_needs_resume) {
ddata->child_needs_resume = false;
error = sysc_runtime_resume(ddata->dev);
if (error)
dev_err(ddata->dev,
"%s runtime resume error: %i\n",
__func__, error);
error = pm_generic_runtime_resume(dev);
if (error)
dev_err(ddata->dev,
"%s generic runtime resume: %i\n",
__func__, error);
}
return pm_generic_resume_noirq(dev);
}
#endif
static struct dev_pm_domain sysc_child_pm_domain = {
.ops = {
SET_RUNTIME_PM_OPS(sysc_child_runtime_suspend,
sysc_child_runtime_resume,
NULL)
USE_PLATFORM_PM_SLEEP_OPS
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sysc_child_suspend_noirq,
sysc_child_resume_noirq)
}
};
/* Caller needs to take list_lock if ever used outside of cpu_pm */
static void sysc_reinit_modules(struct sysc_soc_info *soc)
{
......@@ -2600,25 +2525,6 @@ static void sysc_add_restored(struct sysc *ddata)
mutex_unlock(&sysc_soc->list_lock);
}
/**
* sysc_legacy_idle_quirk - handle children in omap_device compatible way
* @ddata: device driver data
* @child: child device driver
*
* Allow idle for child devices as done with _od_runtime_suspend().
* Otherwise many child devices will not idle because of the permanent
* parent usecount set in pm_runtime_irq_safe().
*
* Note that the long term solution is to just modify the child device
* drivers to not set pm_runtime_irq_safe() and then this can be just
* dropped.
*/
static void sysc_legacy_idle_quirk(struct sysc *ddata, struct device *child)
{
if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
dev_pm_domain_set(child, &sysc_child_pm_domain);
}
static int sysc_notifier_call(struct notifier_block *nb,
unsigned long event, void *device)
{
......@@ -2635,7 +2541,6 @@ static int sysc_notifier_call(struct notifier_block *nb,
error = sysc_child_add_clocks(ddata, dev);
if (error)
return error;
sysc_legacy_idle_quirk(ddata, dev);
break;
default:
break;
......@@ -2859,8 +2764,7 @@ static const struct sysc_capabilities sysc_34xx_sr = {
.type = TI_SYSC_OMAP34XX_SR,
.sysc_mask = SYSC_OMAP2_CLOCKACTIVITY,
.regbits = &sysc_regbits_omap34xx_sr,
.mod_quirks = SYSC_QUIRK_USE_CLOCKACT | SYSC_QUIRK_UNCACHED |
SYSC_QUIRK_LEGACY_IDLE,
.mod_quirks = SYSC_QUIRK_USE_CLOCKACT | SYSC_QUIRK_UNCACHED,
};
/*
......@@ -2881,13 +2785,12 @@ static const struct sysc_capabilities sysc_36xx_sr = {
.type = TI_SYSC_OMAP36XX_SR,
.sysc_mask = SYSC_OMAP3_SR_ENAWAKEUP,
.regbits = &sysc_regbits_omap36xx_sr,
.mod_quirks = SYSC_QUIRK_UNCACHED | SYSC_QUIRK_LEGACY_IDLE,
.mod_quirks = SYSC_QUIRK_UNCACHED,
};
static const struct sysc_capabilities sysc_omap4_sr = {
.type = TI_SYSC_OMAP4_SR,
.regbits = &sysc_regbits_omap36xx_sr,
.mod_quirks = SYSC_QUIRK_LEGACY_IDLE,
};
/*
......
......@@ -451,8 +451,8 @@ config COMMON_CLK_FIXED_MMIO
config COMMON_CLK_K210
bool "Clock driver for the Canaan Kendryte K210 SoC"
depends on OF && RISCV && SOC_CANAAN
default SOC_CANAAN
depends on OF && RISCV && SOC_CANAAN_K210
default SOC_CANAAN_K210
help
Support for the Canaan Kendryte K210 RISC-V SoC clocks.
......
......@@ -101,11 +101,12 @@ struct ffa_drv_info {
bool bitmap_created;
bool notif_enabled;
unsigned int sched_recv_irq;
unsigned int notif_pend_irq;
unsigned int cpuhp_state;
struct ffa_pcpu_irq __percpu *irq_pcpu;
struct workqueue_struct *notif_pcpu_wq;
struct work_struct notif_pcpu_work;
struct work_struct irq_work;
struct work_struct sched_recv_irq_work;
struct xarray partition_info;
DECLARE_HASHTABLE(notifier_hash, ilog2(FFA_MAX_NOTIFICATIONS));
struct mutex notify_lock; /* lock to protect notifier hashtable */
......@@ -344,6 +345,38 @@ static int ffa_msg_send_direct_req(u16 src_id, u16 dst_id, bool mode_32bit,
return -EINVAL;
}
static int ffa_msg_send2(u16 src_id, u16 dst_id, void *buf, size_t sz)
{
u32 src_dst_ids = PACK_TARGET_INFO(src_id, dst_id);
struct ffa_indirect_msg_hdr *msg;
ffa_value_t ret;
int retval = 0;
if (sz > (RXTX_BUFFER_SIZE - sizeof(*msg)))
return -ERANGE;
mutex_lock(&drv_info->tx_lock);
msg = drv_info->tx_buffer;
msg->flags = 0;
msg->res0 = 0;
msg->offset = sizeof(*msg);
msg->send_recv_id = src_dst_ids;
msg->size = sz;
memcpy((u8 *)msg + msg->offset, buf, sz);
/* flags = 0, sender VMID = 0 works for both physical/virtual NS */
invoke_ffa_fn((ffa_value_t){
.a0 = FFA_MSG_SEND2, .a1 = 0, .a2 = 0
}, &ret);
if (ret.a0 == FFA_ERROR)
retval = ffa_to_linux_errno((int)ret.a2);
mutex_unlock(&drv_info->tx_lock);
return retval;
}
static int ffa_mem_first_frag(u32 func_id, phys_addr_t buf, u32 buf_sz,
u32 frag_len, u32 len, u64 *handle)
{
......@@ -870,6 +903,11 @@ static int ffa_sync_send_receive(struct ffa_device *dev,
dev->mode_32bit, data);
}
static int ffa_indirect_msg_send(struct ffa_device *dev, void *buf, size_t sz)
{
return ffa_msg_send2(drv_info->vm_id, dev->vm_id, buf, sz);
}
static int ffa_memory_share(struct ffa_mem_ops_args *args)
{
if (drv_info->mem_ops_native)
......@@ -1108,7 +1146,7 @@ static void handle_notif_callbacks(u64 bitmap, enum notify_type type)
}
}
static void notif_pcpu_irq_work_fn(struct work_struct *work)
static void notif_get_and_handle(void *unused)
{
int rc;
struct ffa_notify_bitmaps bitmaps;
......@@ -1131,10 +1169,17 @@ ffa_self_notif_handle(u16 vcpu, bool is_per_vcpu, void *cb_data)
struct ffa_drv_info *info = cb_data;
if (!is_per_vcpu)
notif_pcpu_irq_work_fn(&info->notif_pcpu_work);
notif_get_and_handle(info);
else
queue_work_on(vcpu, info->notif_pcpu_wq,
&info->notif_pcpu_work);
smp_call_function_single(vcpu, notif_get_and_handle, info, 0);
}
static void notif_pcpu_irq_work_fn(struct work_struct *work)
{
struct ffa_drv_info *info = container_of(work, struct ffa_drv_info,
notif_pcpu_work);
ffa_self_notif_handle(smp_processor_id(), true, info);
}
static const struct ffa_info_ops ffa_drv_info_ops = {
......@@ -1145,6 +1190,7 @@ static const struct ffa_info_ops ffa_drv_info_ops = {
static const struct ffa_msg_ops ffa_drv_msg_ops = {
.mode_32bit_set = ffa_mode_32bit_set,
.sync_send_receive = ffa_sync_send_receive,
.indirect_send = ffa_indirect_msg_send,
};
static const struct ffa_mem_ops ffa_drv_mem_ops = {
......@@ -1227,6 +1273,8 @@ static int ffa_setup_partitions(void)
continue;
}
ffa_dev->properties = tpbuf->properties;
if (drv_info->version > FFA_VERSION_1_0 &&
!(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC))
ffa_mode_32bit_set(ffa_dev);
......@@ -1291,12 +1339,23 @@ static void ffa_partitions_cleanup(void)
#define FFA_FEAT_SCHEDULE_RECEIVER_INT (2)
#define FFA_FEAT_MANAGED_EXIT_INT (3)
static irqreturn_t irq_handler(int irq, void *irq_data)
static irqreturn_t ffa_sched_recv_irq_handler(int irq, void *irq_data)
{
struct ffa_pcpu_irq *pcpu = irq_data;
struct ffa_drv_info *info = pcpu->info;
queue_work(info->notif_pcpu_wq, &info->irq_work);
queue_work(info->notif_pcpu_wq, &info->sched_recv_irq_work);
return IRQ_HANDLED;
}
static irqreturn_t notif_pend_irq_handler(int irq, void *irq_data)
{
struct ffa_pcpu_irq *pcpu = irq_data;
struct ffa_drv_info *info = pcpu->info;
queue_work_on(smp_processor_id(), info->notif_pcpu_wq,
&info->notif_pcpu_work);
return IRQ_HANDLED;
}
......@@ -1306,15 +1365,23 @@ static void ffa_sched_recv_irq_work_fn(struct work_struct *work)
ffa_notification_info_get();
}
static int ffa_sched_recv_irq_map(void)
static int ffa_irq_map(u32 id)
{
int ret, irq, sr_intid;
char *err_str;
int ret, irq, intid;
if (id == FFA_FEAT_NOTIFICATION_PENDING_INT)
err_str = "Notification Pending Interrupt";
else if (id == FFA_FEAT_SCHEDULE_RECEIVER_INT)
err_str = "Schedule Receiver Interrupt";
else
err_str = "Unknown ID";
/* The returned sr_intid is assumed to be SGI donated to NS world */
ret = ffa_features(FFA_FEAT_SCHEDULE_RECEIVER_INT, 0, &sr_intid, NULL);
/* The returned intid is assumed to be SGI donated to NS world */
ret = ffa_features(id, 0, &intid, NULL);
if (ret < 0) {
if (ret != -EOPNOTSUPP)
pr_err("Failed to retrieve scheduler Rx interrupt\n");
pr_err("Failed to retrieve FF-A %s %u\n", err_str, id);
return ret;
}
......@@ -1329,12 +1396,12 @@ static int ffa_sched_recv_irq_map(void)
oirq.np = gic;
oirq.args_count = 1;
oirq.args[0] = sr_intid;
oirq.args[0] = intid;
irq = irq_create_of_mapping(&oirq);
of_node_put(gic);
#ifdef CONFIG_ACPI
} else {
irq = acpi_register_gsi(NULL, sr_intid, ACPI_EDGE_SENSITIVE,
irq = acpi_register_gsi(NULL, intid, ACPI_EDGE_SENSITIVE,
ACPI_ACTIVE_HIGH);
#endif
}
......@@ -1347,23 +1414,28 @@ static int ffa_sched_recv_irq_map(void)
return irq;
}
static void ffa_sched_recv_irq_unmap(void)
static void ffa_irq_unmap(unsigned int irq)
{
if (drv_info->sched_recv_irq) {
irq_dispose_mapping(drv_info->sched_recv_irq);
drv_info->sched_recv_irq = 0;
}
if (!irq)
return;
irq_dispose_mapping(irq);
}
static int ffa_cpuhp_pcpu_irq_enable(unsigned int cpu)
{
if (drv_info->sched_recv_irq)
enable_percpu_irq(drv_info->sched_recv_irq, IRQ_TYPE_NONE);
if (drv_info->notif_pend_irq)
enable_percpu_irq(drv_info->notif_pend_irq, IRQ_TYPE_NONE);
return 0;
}
static int ffa_cpuhp_pcpu_irq_disable(unsigned int cpu)
{
if (drv_info->sched_recv_irq)
disable_percpu_irq(drv_info->sched_recv_irq);
if (drv_info->notif_pend_irq)
disable_percpu_irq(drv_info->notif_pend_irq);
return 0;
}
......@@ -1382,13 +1454,16 @@ static void ffa_uninit_pcpu_irq(void)
if (drv_info->sched_recv_irq)
free_percpu_irq(drv_info->sched_recv_irq, drv_info->irq_pcpu);
if (drv_info->notif_pend_irq)
free_percpu_irq(drv_info->notif_pend_irq, drv_info->irq_pcpu);
if (drv_info->irq_pcpu) {
free_percpu(drv_info->irq_pcpu);
drv_info->irq_pcpu = NULL;
}
}
static int ffa_init_pcpu_irq(unsigned int irq)
static int ffa_init_pcpu_irq(void)
{
struct ffa_pcpu_irq __percpu *irq_pcpu;
int ret, cpu;
......@@ -1402,13 +1477,31 @@ static int ffa_init_pcpu_irq(unsigned int irq)
drv_info->irq_pcpu = irq_pcpu;
ret = request_percpu_irq(irq, irq_handler, "ARM-FFA", irq_pcpu);
if (drv_info->sched_recv_irq) {
ret = request_percpu_irq(drv_info->sched_recv_irq,
ffa_sched_recv_irq_handler,
"ARM-FFA-SRI", irq_pcpu);
if (ret) {
pr_err("Error registering percpu SRI nIRQ %d : %d\n",
drv_info->sched_recv_irq, ret);
drv_info->sched_recv_irq = 0;
return ret;
}
}
if (drv_info->notif_pend_irq) {
ret = request_percpu_irq(drv_info->notif_pend_irq,
notif_pend_irq_handler,
"ARM-FFA-NPI", irq_pcpu);
if (ret) {
pr_err("Error registering notification IRQ %d: %d\n", irq, ret);
pr_err("Error registering percpu NPI nIRQ %d : %d\n",
drv_info->notif_pend_irq, ret);
drv_info->notif_pend_irq = 0;
return ret;
}
}
INIT_WORK(&drv_info->irq_work, ffa_sched_recv_irq_work_fn);
INIT_WORK(&drv_info->sched_recv_irq_work, ffa_sched_recv_irq_work_fn);
INIT_WORK(&drv_info->notif_pcpu_work, notif_pcpu_irq_work_fn);
drv_info->notif_pcpu_wq = create_workqueue("ffa_pcpu_irq_notification");
if (!drv_info->notif_pcpu_wq)
......@@ -1428,7 +1521,10 @@ static int ffa_init_pcpu_irq(unsigned int irq)
static void ffa_notifications_cleanup(void)
{
ffa_uninit_pcpu_irq();
ffa_sched_recv_irq_unmap();
ffa_irq_unmap(drv_info->sched_recv_irq);
drv_info->sched_recv_irq = 0;
ffa_irq_unmap(drv_info->notif_pend_irq);
drv_info->notif_pend_irq = 0;
if (drv_info->bitmap_created) {
ffa_notification_bitmap_destroy();
......@@ -1439,30 +1535,31 @@ static void ffa_notifications_cleanup(void)
static void ffa_notifications_setup(void)
{
int ret, irq;
int ret;
ret = ffa_features(FFA_NOTIFICATION_BITMAP_CREATE, 0, NULL, NULL);
if (ret) {
pr_info("Notifications not supported, continuing with it ..\n");
return;
}
if (!ret) {
ret = ffa_notification_bitmap_create();
if (ret) {
pr_info("Notification bitmap create error %d\n", ret);
pr_err("Notification bitmap create error %d\n", ret);
return;
}
drv_info->bitmap_created = true;
irq = ffa_sched_recv_irq_map();
if (irq <= 0) {
ret = irq;
goto cleanup;
drv_info->bitmap_created = true;
}
drv_info->sched_recv_irq = irq;
ret = ffa_irq_map(FFA_FEAT_SCHEDULE_RECEIVER_INT);
if (ret > 0)
drv_info->sched_recv_irq = ret;
ret = ffa_irq_map(FFA_FEAT_NOTIFICATION_PENDING_INT);
if (ret > 0)
drv_info->notif_pend_irq = ret;
if (!drv_info->sched_recv_irq && !drv_info->notif_pend_irq)
goto cleanup;
ret = ffa_init_pcpu_irq(irq);
ret = ffa_init_pcpu_irq();
if (ret)
goto cleanup;
......
......@@ -10,7 +10,8 @@ scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += smc.o
scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.o
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += virtio.o
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += optee.o
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o powercap.o
scmi-protocols-y := base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o powercap.o
scmi-protocols-y += pinctrl.o
scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) $(scmi-transport-y)
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o
......
......@@ -301,6 +301,17 @@ extern const struct scmi_desc scmi_optee_desc;
void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv);
enum scmi_bad_msg {
MSG_UNEXPECTED = -1,
MSG_INVALID = -2,
MSG_UNKNOWN = -3,
MSG_NOMEM = -4,
MSG_MBOX_SPURIOUS = -5,
};
void scmi_bad_message_trace(struct scmi_chan_info *cinfo, u32 msg_hdr,
enum scmi_bad_msg err);
/* shmem related declarations */
struct scmi_shared_mem;
......
This diff is collapsed.
......@@ -56,6 +56,9 @@ static void rx_callback(struct mbox_client *cl, void *m)
*/
if (cl->knows_txdone && !shmem_channel_free(smbox->shmem)) {
dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n");
scmi_bad_message_trace(smbox->cinfo,
shmem_read_header(smbox->shmem),
MSG_MBOX_SPURIOUS);
return;
}
......
......@@ -1513,17 +1513,12 @@ static int scmi_devm_notifier_register(struct scmi_device *sdev,
static int scmi_devm_notifier_match(struct device *dev, void *res, void *data)
{
struct scmi_notifier_devres *dres = res;
struct scmi_notifier_devres *xres = data;
struct notifier_block *nb = data;
if (WARN_ON(!dres || !xres))
if (WARN_ON(!dres || !nb))
return 0;
return dres->proto_id == xres->proto_id &&
dres->evt_id == xres->evt_id &&
dres->nb == xres->nb &&
((!dres->src_id && !xres->src_id) ||
(dres->src_id && xres->src_id &&
dres->__src_id == xres->__src_id));
return dres->nb == nb;
}
/**
......@@ -1531,10 +1526,6 @@ static int scmi_devm_notifier_match(struct device *dev, void *res, void *data)
* notifier_block for an event
* @sdev: A reference to an scmi_device whose embedded struct device is to
* be used for devres accounting.
* @proto_id: Protocol ID
* @evt_id: Event ID
* @src_id: Source ID, when NULL register for events coming form ALL possible
* sources
* @nb: A standard notifier block to register for the specified event
*
* Generic devres managed helper to explicitly un-register a notifier_block
......@@ -1544,25 +1535,12 @@ static int scmi_devm_notifier_match(struct device *dev, void *res, void *data)
* Return: 0 on Success
*/
static int scmi_devm_notifier_unregister(struct scmi_device *sdev,
u8 proto_id, u8 evt_id,
const u32 *src_id,
struct notifier_block *nb)
{
int ret;
struct scmi_notifier_devres dres;
dres.handle = sdev->handle;
dres.proto_id = proto_id;
dres.evt_id = evt_id;
if (src_id) {
dres.__src_id = *src_id;
dres.src_id = &dres.__src_id;
} else {
dres.src_id = NULL;
}
ret = devres_release(&sdev->dev, scmi_devm_release_notifier,
scmi_devm_notifier_match, &dres);
scmi_devm_notifier_match, nb);
WARN_ON(ret);
......
......@@ -387,8 +387,8 @@ process_response_opp(struct device *dev, struct perf_dom_info *dom,
ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
if (ret)
dev_warn(dev, "Failed to add opps_by_lvl at %d - ret:%d\n",
opp->perf, ret);
dev_warn(dev, "Failed to add opps_by_lvl at %d for %s - ret:%d\n",
opp->perf, dom->info.name, ret);
}
static inline void
......@@ -405,8 +405,8 @@ process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
if (ret)
dev_warn(dev, "Failed to add opps_by_lvl at %d - ret:%d\n",
opp->perf, ret);
dev_warn(dev, "Failed to add opps_by_lvl at %d for %s - ret:%d\n",
opp->perf, dom->info.name, ret);
/* Note that PERF v4 reports always five 32-bit words */
opp->indicative_freq = le32_to_cpu(r->opp[loop_idx].indicative_freq);
......@@ -417,8 +417,8 @@ process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
GFP_KERNEL);
if (ret)
dev_warn(dev,
"Failed to add opps_by_idx at %d - ret:%d\n",
opp->level_index, ret);
"Failed to add opps_by_idx at %d for %s - ret:%d\n",
opp->level_index, dom->info.name, ret);
hash_add(dom->opps_by_freq, &opp->hash, opp->indicative_freq);
}
......@@ -879,7 +879,8 @@ static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph,
ret = dev_pm_opp_add_dynamic(dev, &data);
if (ret) {
dev_warn(dev, "failed to add opp %luHz\n", freq);
dev_warn(dev, "[%d][%s]: Failed to add OPP[%d] %lu\n",
domain, dom->info.name, idx, freq);
dev_pm_opp_remove_all_dynamic(dev);
return ret;
}
......
This diff is collapsed.
......@@ -29,6 +29,8 @@
#define PROTOCOL_REV_MAJOR(x) ((u16)(FIELD_GET(PROTOCOL_REV_MAJOR_MASK, (x))))
#define PROTOCOL_REV_MINOR(x) ((u16)(FIELD_GET(PROTOCOL_REV_MINOR_MASK, (x))))
#define SCMI_PROTOCOL_VENDOR_BASE 0x80
enum scmi_common_cmd {
PROTOCOL_VERSION = 0x0,
PROTOCOL_ATTRIBUTES = 0x1,
......@@ -258,6 +260,7 @@ struct scmi_fc_info {
* @fastchannel_init: A common helper used to initialize FC descriptors by
* gathering FC descriptions from the SCMI platform server.
* @fastchannel_db_ring: A common helper to ring a FC doorbell.
* @get_max_msg_size: A common helper to get the maximum message size.
*/
struct scmi_proto_helpers_ops {
int (*extended_name_get)(const struct scmi_protocol_handle *ph,
......@@ -277,6 +280,7 @@ struct scmi_proto_helpers_ops {
struct scmi_fc_db_info **p_db,
u32 *rate_limit);
void (*fastchannel_db_ring)(struct scmi_fc_db_info *db);
int (*get_max_msg_size)(const struct scmi_protocol_handle *ph);
};
/**
......@@ -323,6 +327,16 @@ typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *);
* protocol by the agent. Each protocol implementation
* in the agent is supposed to downgrade to match the
* protocol version supported by the platform.
* @vendor_id: A firmware vendor string for vendor protocols matching.
* Ignored when @id identifies a standard protocol, cannot be NULL
* otherwise.
* @sub_vendor_id: A firmware sub_vendor string for vendor protocols matching.
* Ignored if NULL or when @id identifies a standard protocol.
* @impl_ver: A firmware implementation version for vendor protocols matching.
* Ignored if zero or if @id identifies a standard protocol.
*
* Note that vendor protocols matching at load time is performed by attempting
* the closest match first against the tuple (vendor, sub_vendor, impl_ver)
*/
struct scmi_protocol {
const u8 id;
......@@ -332,6 +346,9 @@ struct scmi_protocol {
const void *ops;
const struct scmi_protocol_events *events;
unsigned int supported_version;
char *vendor_id;
char *sub_vendor_id;
u32 impl_ver;
};
#define DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(name, proto) \
......@@ -353,6 +370,7 @@ void __exit scmi_##name##_unregister(void) \
DECLARE_SCMI_REGISTER_UNREGISTER(base);
DECLARE_SCMI_REGISTER_UNREGISTER(clock);
DECLARE_SCMI_REGISTER_UNREGISTER(perf);
DECLARE_SCMI_REGISTER_UNREGISTER(pinctrl);
DECLARE_SCMI_REGISTER_UNREGISTER(power);
DECLARE_SCMI_REGISTER_UNREGISTER(reset);
DECLARE_SCMI_REGISTER_UNREGISTER(sensors);
......
......@@ -4,6 +4,8 @@
*/
#include <linux/arm-smccc.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/cpumask.h>
......@@ -114,6 +116,10 @@ static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
#define QCOM_SMC_WAITQ_FLAG_WAKE_ONE BIT(0)
#define QCOM_SMC_WAITQ_FLAG_WAKE_ALL BIT(1)
#define QCOM_DLOAD_MASK GENMASK(5, 4)
#define QCOM_DLOAD_NODUMP 0
#define QCOM_DLOAD_FULLDUMP 1
static const char * const qcom_scm_convention_names[] = {
[SMC_CONVENTION_UNKNOWN] = "unknown",
[SMC_CONVENTION_ARM_32] = "smc arm 32",
......@@ -163,9 +169,6 @@ static int qcom_scm_bw_enable(void)
if (!__scm->path)
return 0;
if (IS_ERR(__scm->path))
return -EINVAL;
mutex_lock(&__scm->scm_bw_lock);
if (!__scm->scm_vote_count) {
ret = icc_set_bw(__scm->path, 0, UINT_MAX);
......@@ -183,7 +186,7 @@ static int qcom_scm_bw_enable(void)
static void qcom_scm_bw_disable(void)
{
if (IS_ERR_OR_NULL(__scm->path))
if (!__scm->path)
return;
mutex_lock(&__scm->scm_bw_lock);
......@@ -496,19 +499,32 @@ static int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
return qcom_scm_call_atomic(__scm->dev, &desc, NULL);
}
static int qcom_scm_io_rmw(phys_addr_t addr, unsigned int mask, unsigned int val)
{
unsigned int old;
unsigned int new;
int ret;
ret = qcom_scm_io_readl(addr, &old);
if (ret)
return ret;
new = (old & ~mask) | (val & mask);
return qcom_scm_io_writel(addr, new);
}
static void qcom_scm_set_download_mode(bool enable)
{
bool avail;
u32 val = enable ? QCOM_DLOAD_FULLDUMP : QCOM_DLOAD_NODUMP;
int ret = 0;
avail = __qcom_scm_is_call_available(__scm->dev,
QCOM_SCM_SVC_BOOT,
QCOM_SCM_BOOT_SET_DLOAD_MODE);
if (avail) {
if (__scm->dload_mode_addr) {
ret = qcom_scm_io_rmw(__scm->dload_mode_addr, QCOM_DLOAD_MASK,
FIELD_PREP(QCOM_DLOAD_MASK, val));
} else if (__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_BOOT,
QCOM_SCM_BOOT_SET_DLOAD_MODE)) {
ret = __qcom_scm_set_dload_mode(__scm->dev, enable);
} else if (__scm->dload_mode_addr) {
ret = qcom_scm_io_writel(__scm->dload_mode_addr,
enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0);
} else {
dev_err(__scm->dev,
"No available mechanism for setting download mode\n");
......@@ -557,10 +573,9 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size,
*/
mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys,
GFP_KERNEL);
if (!mdata_buf) {
dev_err(__scm->dev, "Allocation of metadata buffer failed.\n");
if (!mdata_buf)
return -ENOMEM;
}
memcpy(mdata_buf, metadata, size);
ret = qcom_scm_clk_enable();
......@@ -569,13 +584,14 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size,
ret = qcom_scm_bw_enable();
if (ret)
return ret;
goto disable_clk;
desc.args[1] = mdata_phys;
ret = qcom_scm_call(__scm->dev, &desc, &res);
qcom_scm_bw_disable();
disable_clk:
qcom_scm_clk_disable();
out:
......@@ -637,10 +653,12 @@ int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size)
ret = qcom_scm_bw_enable();
if (ret)
return ret;
goto disable_clk;
ret = qcom_scm_call(__scm->dev, &desc, &res);
qcom_scm_bw_disable();
disable_clk:
qcom_scm_clk_disable();
return ret ? : res.result[0];
......@@ -672,10 +690,12 @@ int qcom_scm_pas_auth_and_reset(u32 peripheral)
ret = qcom_scm_bw_enable();
if (ret)
return ret;
goto disable_clk;
ret = qcom_scm_call(__scm->dev, &desc, &res);
qcom_scm_bw_disable();
disable_clk:
qcom_scm_clk_disable();
return ret ? : res.result[0];
......@@ -706,11 +726,12 @@ int qcom_scm_pas_shutdown(u32 peripheral)
ret = qcom_scm_bw_enable();
if (ret)
return ret;
goto disable_clk;
ret = qcom_scm_call(__scm->dev, &desc, &res);
qcom_scm_bw_disable();
disable_clk:
qcom_scm_clk_disable();
return ret ? : res.result[0];
......@@ -1624,8 +1645,10 @@ EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_send);
* We do not yet support re-entrant calls via the qseecom interface. To prevent
+ any potential issues with this, only allow validated machines for now.
*/
static const struct of_device_id qcom_scm_qseecom_allowlist[] = {
static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = {
{ .compatible = "lenovo,flex-5g" },
{ .compatible = "lenovo,thinkpad-x13s", },
{ .compatible = "qcom,sc8180x-primus" },
{ }
};
......@@ -1713,7 +1736,7 @@ static int qcom_scm_qseecom_init(struct qcom_scm *scm)
*/
bool qcom_scm_is_available(void)
{
return !!__scm;
return !!READ_ONCE(__scm);
}
EXPORT_SYMBOL_GPL(qcom_scm_is_available);
......@@ -1744,7 +1767,7 @@ int qcom_scm_wait_for_wq_completion(u32 wq_ctx)
return 0;
}
static int qcom_scm_waitq_wakeup(struct qcom_scm *scm, unsigned int wq_ctx)
static int qcom_scm_waitq_wakeup(unsigned int wq_ctx)
{
int ret;
......@@ -1776,7 +1799,7 @@ static irqreturn_t qcom_scm_irq_handler(int irq, void *data)
goto out;
}
ret = qcom_scm_waitq_wakeup(scm, wq_ctx);
ret = qcom_scm_waitq_wakeup(wq_ctx);
if (ret)
goto out;
} while (more_pending);
......@@ -1794,10 +1817,12 @@ static int qcom_scm_probe(struct platform_device *pdev)
if (!scm)
return -ENOMEM;
scm->dev = &pdev->dev;
ret = qcom_scm_find_dload_address(&pdev->dev, &scm->dload_mode_addr);
if (ret < 0)
return ret;
init_completion(&scm->waitq_comp);
mutex_init(&scm->scm_bw_lock);
scm->path = devm_of_icc_get(&pdev->dev, NULL);
......@@ -1829,10 +1854,8 @@ static int qcom_scm_probe(struct platform_device *pdev)
if (ret)
return ret;
__scm = scm;
__scm->dev = &pdev->dev;
init_completion(&__scm->waitq_comp);
/* Let all above stores be available after this */
smp_store_release(&__scm, scm);
irq = platform_get_irq_optional(pdev, 0);
if (irq < 0) {
......
......@@ -87,7 +87,6 @@ struct ti_sci_desc {
* struct ti_sci_info - Structure representing a TI SCI instance
* @dev: Device pointer
* @desc: SoC description for this instance
* @nb: Reboot Notifier block
* @d: Debugfs file entry
* @debug_region: Memory region where the debug message are available
* @debug_region_size: Debug region size
......@@ -103,7 +102,6 @@ struct ti_sci_desc {
*/
struct ti_sci_info {
struct device *dev;
struct notifier_block nb;
const struct ti_sci_desc *desc;
struct dentry *d;
void __iomem *debug_region;
......@@ -122,7 +120,6 @@ struct ti_sci_info {
#define cl_to_ti_sci_info(c) container_of(c, struct ti_sci_info, cl)
#define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle)
#define reboot_to_ti_sci_info(n) container_of(n, struct ti_sci_info, nb)
#ifdef CONFIG_DEBUG_FS
......@@ -3254,10 +3251,9 @@ devm_ti_sci_get_resource(const struct ti_sci_handle *handle, struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_ti_sci_get_resource);
static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode,
void *cmd)
static int tisci_reboot_handler(struct sys_off_data *data)
{
struct ti_sci_info *info = reboot_to_ti_sci_info(nb);
struct ti_sci_info *info = data->cb_data;
const struct ti_sci_handle *handle = &info->handle;
ti_sci_cmd_core_reboot(handle);
......@@ -3303,7 +3299,6 @@ static int ti_sci_probe(struct platform_device *pdev)
struct mbox_client *cl;
int ret = -EINVAL;
int i;
int reboot = 0;
u32 h_id;
desc = device_get_match_data(dev);
......@@ -3327,8 +3322,6 @@ static int ti_sci_probe(struct platform_device *pdev)
}
}
reboot = of_property_read_bool(dev->of_node,
"ti,system-reboot-controller");
INIT_LIST_HEAD(&info->node);
minfo = &info->minfo;
......@@ -3399,16 +3392,11 @@ static int ti_sci_probe(struct platform_device *pdev)
ti_sci_setup_ops(info);
if (reboot) {
info->nb.notifier_call = tisci_reboot_handler;
info->nb.priority = 128;
ret = register_restart_handler(&info->nb);
ret = devm_register_restart_handler(dev, tisci_reboot_handler, info);
if (ret) {
dev_err(dev, "reboot registration fail(%d)\n", ret);
goto out;
}
}
dev_info(dev, "ABI: %d.%d (firmware rev 0x%04x '%s')\n",
info->handle.version.abi_major, info->handle.version.abi_minor,
......
......@@ -243,6 +243,7 @@ static const struct of_device_id brcmstb_memc_of_match[] = {
},
{}
};
MODULE_DEVICE_TABLE(of, brcmstb_memc_of_match);
static int brcmstb_memc_suspend(struct device *dev)
{
......
......@@ -450,6 +450,7 @@ static const struct of_device_id mtk_smi_larb_of_ids[] = {
{.compatible = "mediatek,mt8195-smi-larb", .data = &mtk_smi_larb_mt8195},
{}
};
MODULE_DEVICE_TABLE(of, mtk_smi_larb_of_ids);
static int mtk_smi_larb_sleep_ctrl_enable(struct mtk_smi_larb *larb)
{
......@@ -735,6 +736,7 @@ static const struct of_device_id mtk_smi_common_of_ids[] = {
{.compatible = "mediatek,mt8365-smi-common", .data = &mtk_smi_common_mt8365},
{}
};
MODULE_DEVICE_TABLE(of, mtk_smi_common_of_ids);
static int mtk_smi_common_probe(struct platform_device *pdev)
{
......
......@@ -1252,6 +1252,7 @@ DEFINE_SIMPLE_PROP(backlight, "backlight", NULL)
DEFINE_SIMPLE_PROP(panel, "panel", NULL)
DEFINE_SIMPLE_PROP(msi_parent, "msi-parent", "#msi-cells")
DEFINE_SIMPLE_PROP(post_init_providers, "post-init-providers", NULL)
DEFINE_SIMPLE_PROP(access_controllers, "access-controllers", "#access-controller-cells")
DEFINE_SUFFIX_PROP(regulators, "-supply", NULL)
DEFINE_SUFFIX_PROP(gpio, "-gpio", "#gpio-cells")
......@@ -1359,6 +1360,7 @@ static const struct supplier_bindings of_supplier_bindings[] = {
{ .parse_prop = parse_msi_parent, },
{ .parse_prop = parse_gpio_compat, },
{ .parse_prop = parse_interrupts, },
{ .parse_prop = parse_access_controllers, },
{ .parse_prop = parse_regulators, },
{ .parse_prop = parse_gpio, },
{ .parse_prop = parse_gpios, },
......
......@@ -235,13 +235,13 @@ config PINCTRL_INGENIC
config PINCTRL_K210
bool "Pinctrl driver for the Canaan Kendryte K210 SoC"
depends on RISCV && SOC_CANAAN && OF
depends on RISCV && SOC_CANAAN_K210 && OF
select GENERIC_PINMUX_FUNCTIONS
select GENERIC_PINCONF
select GPIOLIB
select OF_GPIO
select REGMAP_MMIO
default SOC_CANAAN
default SOC_CANAAN_K210
help
Add support for the Canaan Kendryte K210 RISC-V SOC Field
Programmable IO Array (FPIOA) controller.
......@@ -450,6 +450,17 @@ config PINCTRL_ROCKCHIP
help
This support pinctrl and GPIO driver for Rockchip SoCs.
config PINCTRL_SCMI
tristate "Pinctrl driver using SCMI protocol interface"
depends on ARM_SCMI_PROTOCOL || COMPILE_TEST
select PINMUX
select GENERIC_PINCONF
help
This driver provides support for pinctrl which is controlled
by firmware that implements the SCMI interface.
It uses SCMI Message Protocol to interact with the
firmware providing all the pinctrl controls.
config PINCTRL_SINGLE
tristate "One-register-per-pin type device tree based pinctrl driver"
depends on OF
......
......@@ -45,6 +45,7 @@ obj-$(CONFIG_PINCTRL_PIC32) += pinctrl-pic32.o
obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o
obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o
obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
obj-$(CONFIG_PINCTRL_SCMI) += pinctrl-scmi.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o
......
This diff is collapsed.
......@@ -103,9 +103,9 @@ config RESET_INTEL_GW
config RESET_K210
bool "Reset controller driver for Canaan Kendryte K210 SoC"
depends on (SOC_CANAAN || COMPILE_TEST) && OF
depends on (SOC_CANAAN_K210 || COMPILE_TEST) && OF
select MFD_SYSCON
default SOC_CANAAN
default SOC_CANAAN_K210
help
Support for the Canaan Kendryte K210 RISC-V SoC reset controller.
Say Y if you want to control reset signals provided by this
......
......@@ -7,7 +7,7 @@ obj-y += apple/
obj-y += aspeed/
obj-$(CONFIG_ARCH_AT91) += atmel/
obj-y += bcm/
obj-$(CONFIG_SOC_CANAAN) += canaan/
obj-$(CONFIG_ARCH_CANAAN) += canaan/
obj-$(CONFIG_ARCH_DOVE) += dove/
obj-$(CONFIG_MACH_DOVE) += dove/
obj-y += fsl/
......
......@@ -2,9 +2,9 @@
config SOC_K210_SYSCTL
bool "Canaan Kendryte K210 SoC system controller"
depends on RISCV && SOC_CANAAN && OF
depends on RISCV && SOC_CANAAN_K210 && OF
depends on COMMON_CLK_K210
default SOC_CANAAN
default SOC_CANAAN_K210
select PM
select MFD_SYSCON
help
......
......@@ -6,7 +6,7 @@ menu "Hisilicon SoC drivers"
config KUNPENG_HCCS
tristate "HCCS driver on Kunpeng SoC"
depends on ACPI
depends on MAILBOX
depends on PCC
depends on ARM64 || COMPILE_TEST
help
The Huawei Cache Coherence System (HCCS) is a multi-chip
......
......@@ -556,6 +556,12 @@ static int hccs_get_all_port_attr(struct hccs_dev *hdev,
start_id = rsp_head.next_id;
}
if (left_buf_len != 0) {
dev_err(hdev->dev, "failed to get the expected port number(%u) attribute.\n",
size);
return -EINVAL;
}
return 0;
}
......
This diff is collapsed.
......@@ -496,6 +496,39 @@ static const unsigned int mt8188_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_MERGE5] = MT8188_MUTEX_MOD_DISP1_VPP_MERGE4,
};
static const unsigned int mt8188_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
[MUTEX_MOD_IDX_MDP_RDMA0] = MT8195_MUTEX_MOD_MDP_RDMA0,
[MUTEX_MOD_IDX_MDP_RDMA2] = MT8195_MUTEX_MOD_MDP_RDMA2,
[MUTEX_MOD_IDX_MDP_RDMA3] = MT8195_MUTEX_MOD_MDP_RDMA3,
[MUTEX_MOD_IDX_MDP_FG0] = MT8195_MUTEX_MOD_MDP_FG0,
[MUTEX_MOD_IDX_MDP_FG2] = MT8195_MUTEX_MOD_MDP_FG2,
[MUTEX_MOD_IDX_MDP_FG3] = MT8195_MUTEX_MOD_MDP_FG3,
[MUTEX_MOD_IDX_MDP_HDR0] = MT8195_MUTEX_MOD_MDP_HDR0,
[MUTEX_MOD_IDX_MDP_HDR2] = MT8195_MUTEX_MOD_MDP_HDR2,
[MUTEX_MOD_IDX_MDP_HDR3] = MT8195_MUTEX_MOD_MDP_HDR3,
[MUTEX_MOD_IDX_MDP_AAL0] = MT8195_MUTEX_MOD_MDP_AAL0,
[MUTEX_MOD_IDX_MDP_AAL2] = MT8195_MUTEX_MOD_MDP_AAL2,
[MUTEX_MOD_IDX_MDP_AAL3] = MT8195_MUTEX_MOD_MDP_AAL3,
[MUTEX_MOD_IDX_MDP_RSZ0] = MT8195_MUTEX_MOD_MDP_RSZ0,
[MUTEX_MOD_IDX_MDP_RSZ2] = MT8195_MUTEX_MOD_MDP_RSZ2,
[MUTEX_MOD_IDX_MDP_RSZ3] = MT8195_MUTEX_MOD_MDP_RSZ3,
[MUTEX_MOD_IDX_MDP_MERGE2] = MT8195_MUTEX_MOD_MDP_MERGE2,
[MUTEX_MOD_IDX_MDP_MERGE3] = MT8195_MUTEX_MOD_MDP_MERGE3,
[MUTEX_MOD_IDX_MDP_TDSHP0] = MT8195_MUTEX_MOD_MDP_TDSHP0,
[MUTEX_MOD_IDX_MDP_TDSHP2] = MT8195_MUTEX_MOD_MDP_TDSHP2,
[MUTEX_MOD_IDX_MDP_TDSHP3] = MT8195_MUTEX_MOD_MDP_TDSHP3,
[MUTEX_MOD_IDX_MDP_COLOR0] = MT8195_MUTEX_MOD_MDP_COLOR0,
[MUTEX_MOD_IDX_MDP_COLOR2] = MT8195_MUTEX_MOD_MDP_COLOR2,
[MUTEX_MOD_IDX_MDP_COLOR3] = MT8195_MUTEX_MOD_MDP_COLOR3,
[MUTEX_MOD_IDX_MDP_OVL0] = MT8195_MUTEX_MOD_MDP_OVL0,
[MUTEX_MOD_IDX_MDP_PAD0] = MT8195_MUTEX_MOD_MDP_PAD0,
[MUTEX_MOD_IDX_MDP_PAD2] = MT8195_MUTEX_MOD_MDP_PAD2,
[MUTEX_MOD_IDX_MDP_PAD3] = MT8195_MUTEX_MOD_MDP_PAD3,
[MUTEX_MOD_IDX_MDP_WROT0] = MT8195_MUTEX_MOD_MDP_WROT0,
[MUTEX_MOD_IDX_MDP_WROT2] = MT8195_MUTEX_MOD_MDP_WROT2,
[MUTEX_MOD_IDX_MDP_WROT3] = MT8195_MUTEX_MOD_MDP_WROT3,
};
static const unsigned int mt8192_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_AAL0] = MT8192_MUTEX_MOD_DISP_AAL0,
[DDP_COMPONENT_CCORR] = MT8192_MUTEX_MOD_DISP_CCORR0,
......@@ -735,6 +768,13 @@ static const struct mtk_mutex_data mt8188_mutex_driver_data = {
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
};
static const struct mtk_mutex_data mt8188_vpp_mutex_driver_data = {
.mutex_sof = mt8188_mutex_sof,
.mutex_mod_reg = MT8183_MUTEX0_MOD0,
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
.mutex_table_mod = mt8188_mdp_mutex_table_mod,
};
static const struct mtk_mutex_data mt8192_mutex_driver_data = {
.mutex_mod = mt8192_mutex_mod,
.mutex_sof = mt8183_mutex_sof,
......@@ -1089,6 +1129,7 @@ static const struct of_device_id mutex_driver_dt_match[] = {
{ .compatible = "mediatek,mt8186-disp-mutex", .data = &mt8186_mutex_driver_data },
{ .compatible = "mediatek,mt8186-mdp3-mutex", .data = &mt8186_mdp_mutex_driver_data },
{ .compatible = "mediatek,mt8188-disp-mutex", .data = &mt8188_mutex_driver_data },
{ .compatible = "mediatek,mt8188-vpp-mutex", .data = &mt8188_vpp_mutex_driver_data },
{ .compatible = "mediatek,mt8192-disp-mutex", .data = &mt8192_mutex_driver_data },
{ .compatible = "mediatek,mt8195-disp-mutex", .data = &mt8195_mutex_driver_data },
{ .compatible = "mediatek,mt8195-vpp-mutex", .data = &mt8195_vpp_mutex_driver_data },
......
......@@ -48,14 +48,15 @@ static struct socinfo_data socinfo_data_table[] = {
MTK_SOCINFO_ENTRY("MT8183", "MT8183V/AZA", "Kompanio 500", 0x00010043, 0x00000940),
MTK_SOCINFO_ENTRY("MT8186", "MT8186GV/AZA", "Kompanio 520", 0x81861001, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8186T", "MT8186TV/AZA", "Kompanio 528", 0x81862001, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8188", "MT8188GV/AZA", "Kompanio 830", 0x81880000, 0x00000010),
MTK_SOCINFO_ENTRY("MT8188", "MT8188GV/HZA", "Kompanio 830", 0x81880000, 0x00000011),
MTK_SOCINFO_ENTRY("MT8188", "MT8188GV/AZA", "Kompanio 838", 0x81880000, 0x00000010),
MTK_SOCINFO_ENTRY("MT8188", "MT8188GV/HZA", "Kompanio 838", 0x81880000, 0x00000011),
MTK_SOCINFO_ENTRY("MT8192", "MT8192V/AZA", "Kompanio 820", 0x00001100, 0x00040080),
MTK_SOCINFO_ENTRY("MT8192T", "MT8192V/ATZA", "Kompanio 828", 0x00000100, 0x000400C0),
MTK_SOCINFO_ENTRY("MT8195", "MT8195GV/EZA", "Kompanio 1200", 0x81950300, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8195", "MT8195GV/EHZA", "Kompanio 1200", 0x81950304, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EZA", "Kompanio 1380", 0x81950400, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EHZA", "Kompanio 1380", 0x81950404, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8395", "MT8395AV/ZA", "Genio 1200", 0x83950100, CELL_NOT_USED),
};
static int mtk_socinfo_create_socinfo_node(struct mtk_socinfo *mtk_socinfop)
......@@ -144,7 +145,14 @@ static int mtk_socinfo_get_socinfo_data(struct mtk_socinfo *mtk_socinfop)
}
}
return match_socinfo_index >= 0 ? match_socinfo_index : -ENOENT;
if (match_socinfo_index < 0) {
dev_warn(mtk_socinfop->dev,
"Unknown MediaTek SoC with ID 0x%08x 0x%08x\n",
cell_data[0], cell_data[1]);
return -ENOENT;
}
return match_socinfo_index;
}
static int mtk_socinfo_probe(struct platform_device *pdev)
......
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2016-2018, 2020, The Linux Foundation. All rights reserved. */
/*
* Copyright (c) 2016-2018, 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/bitfield.h>
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
......@@ -17,6 +21,8 @@
#define MAX_SLV_ID 8
#define SLAVE_ID_MASK 0x7
#define SLAVE_ID_SHIFT 16
#define SLAVE_ID(addr) FIELD_GET(GENMASK(19, 16), addr)
#define VRM_ADDR(addr) FIELD_GET(GENMASK(19, 4), addr)
/**
* struct entry_header: header for each entry in cmddb
......@@ -147,12 +153,7 @@ static int cmd_db_get_header(const char *id, const struct entry_header **eh,
if (ret)
return ret;
/*
* Pad out query string to same length as in DB. NOTE: the output
* query string is not necessarily '\0' terminated if it bumps up
* against the max size. That's OK and expected.
*/
strncpy(query, id, sizeof(query));
strtomem_pad(query, id, 0);
for (i = 0; i < MAX_SLV_ID; i++) {
rsc_hdr = &cmd_db_header->header[i];
......@@ -220,6 +221,30 @@ const void *cmd_db_read_aux_data(const char *id, size_t *len)
}
EXPORT_SYMBOL_GPL(cmd_db_read_aux_data);
/**
* cmd_db_match_resource_addr() - Compare if both Resource addresses are same
*
* @addr1: Resource address to compare
* @addr2: Resource address to compare
*
* Return: true if two addresses refer to the same resource, false otherwise
*/
bool cmd_db_match_resource_addr(u32 addr1, u32 addr2)
{
/*
* Each RPMh VRM accelerator resource has 3 or 4 contiguous 4-byte
* aligned addresses associated with it. Ignore the offset to check
* for VRM requests.
*/
if (addr1 == addr2)
return true;
else if (SLAVE_ID(addr1) == CMD_DB_HW_VRM && VRM_ADDR(addr1) == VRM_ADDR(addr2))
return true;
return false;
}
EXPORT_SYMBOL_GPL(cmd_db_match_resource_addr);
/**
* cmd_db_read_slave_id - Get the slave ID for a given resource address
*
......@@ -362,7 +387,7 @@ static int __init cmd_db_device_init(void)
{
return platform_driver_register(&cmd_db_dev_driver);
}
arch_initcall(cmd_db_device_init);
core_initcall(cmd_db_device_init);
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Command DB Driver");
MODULE_LICENSE("GPL v2");
This diff is collapsed.
This diff is collapsed.
......@@ -150,6 +150,10 @@ static const struct rpmsg_device_id pmic_pdcharger_ulog_rpmsg_id_match[] = {
{ "PMIC_LOGS_ADSP_APPS" },
{}
};
/*
* No MODULE_DEVICE_TABLE intentionally: that's a debugging module, to be
* loaded manually only.
*/
static struct rpmsg_driver pmic_pdcharger_ulog_rpmsg_driver = {
.probe = pmic_pdcharger_ulog_rpmsg_probe,
......
......@@ -35,11 +35,15 @@ static const struct subsystem_data subsystems[] = {
{ "wpss", 605, 13 },
{ "adsp", 606, 2 },
{ "cdsp", 607, 5 },
{ "cdsp1", 607, 12 },
{ "gpdsp0", 607, 17 },
{ "gpdsp1", 607, 18 },
{ "slpi", 608, 3 },
{ "gpu", 609, 0 },
{ "display", 610, 0 },
{ "adsp_island", 613, 2 },
{ "slpi_island", 613, 3 },
{ "apss", 631, QCOM_SMEM_HOST_ANY },
};
struct stats_config {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment