Commit b8979c6b authored by Linus Torvalds's avatar Linus Torvalds

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

Pull SoC driver updates from Arnd Bergmann:
 "The driver updates seem larger this time around, with changes is many
  of the SoC specific drivers, both the custom drivers/soc ones and the
  closely related subsystems (memory, bus, firmware, reset, ...).

  The at91 platform gains support for sam9x7 chips in the soc and power
  management code. This is the latest variant of one of the oldest still
  supported SoC families, using the ARM9 (ARMv5) core.

  As usual, the qualcomm snapdragon platform gets a ton of updates in
  many of their drivers to add more features and additional SoC support.
  Most of these are somewhat firmware related as the platform has a
  number of firmware based interfaces to the kernel. A notable addition
  here is the inclusion of trace events to two of these drivers.

  Herve Codina and Christophe Leroy are now sending updates for
  drivers/soc/fsl/ code through the SoC tree, this contains both PowerPC
  and Arm specific platforms and has previously been problematic to
  maintain. The first update here contains support for newer PowerPC
  variants and some cleanups.

  The turris mox firmware driver has a number of updates, mostly
  cleanups.

  The Arm SCMI firmware driver gets a major rework to modularize the
  existing code into separately loadable drivers for the various
  transports, the addition of custom NXP i.MX9 interfaces and a number
  of smaller updates.

  The Arm FF-A firmware driver gets a feature update to support the v1.2
  version of the specification.

  The reset controller drivers have some smaller cleanups and a newly
  added driver for the Intel/Mobileye EyeQ5/EyeQ6 MIPS SoCs.

  The memory controller drivers get some cleanups and refactoring for
  Tegra, TI, Freescale/NXP and a couple more platforms.

  Finally there are lots of minor updates to firmware (raspberry pi,
  tegra, imx), bus (sunxi, omap, tegra) and soc (rockchips, tegra,
  amlogic, mediatek) drivers and their DT bindings"

* tag 'soc-drivers-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (212 commits)
  firmware: imx: remove duplicate scmi_imx_misc_ctrl_get()
  platform: cznic: turris-omnia-mcu: Fix error check in omnia_mcu_register_trng()
  bus: sunxi-rsb: Simplify code with dev_err_probe()
  soc: fsl: qe: ucc: Export ucc_mux_set_grant_tsa_bkpt
  soc: fsl: cpm1: qmc: Fix dependency on fsl_soc.h
  dt-bindings: arm: rockchip: Add rk3576 compatible string to pmu.yaml
  soc: fsl: qbman: Remove redundant warnings
  soc: fsl: qbman: Use iommu_paging_domain_alloc()
  MAINTAINERS: Add QE files related to the Freescale QMC controller
  soc: fsl: cpm1: qmc: Handle QUICC Engine (QE) soft-qmc firmware
  soc: fsl: cpm1: qmc: Add support for QUICC Engine (QE) implementation
  soc: fsl: qe: Add missing PUSHSCHED command
  soc: fsl: qe: Add resource-managed muram allocators
  soc: fsl: cpm1: qmc: Introduce qmc_version
  soc: fsl: cpm1: qmc: Rename SCC_GSMRL_MODE_QMC
  soc: fsl: cpm1: qmc: Handle RPACK initialization
  soc: fsl: cpm1: qmc: Rename qmc_chan_command()
  soc: fsl: cpm1: qmc: Introduce qmc_{init,exit}_xcc() and their CPM1 version
  soc: fsl: cpm1: qmc: Introduce qmc_init_resource() and its CPM1 version
  soc: fsl: cpm1: qmc: Re-order probe() operations
  ...
parents 7b17f5eb b6280073
...@@ -25,10 +25,18 @@ select: ...@@ -25,10 +25,18 @@ select:
properties: properties:
compatible: compatible:
items: oneOf:
- const: amlogic,meson-gx-ao-secure - items:
- const: syscon - const: amlogic,meson-gx-ao-secure
- const: syscon
- items:
- enum:
- amlogic,a4-ao-secure
- amlogic,c3-ao-secure
- amlogic,s4-ao-secure
- amlogic,t7-ao-secure
- const: amlogic,meson-gx-ao-secure
- const: syscon
reg: reg:
maxItems: 1 maxItems: 1
......
...@@ -11,7 +11,8 @@ PIT Timer required properties: ...@@ -11,7 +11,8 @@ PIT Timer required properties:
shared across all System Controller members. shared across all System Controller members.
PIT64B Timer required properties: PIT64B Timer required properties:
- compatible: Should be "microchip,sam9x60-pit64b" - compatible: Should be "microchip,sam9x60-pit64b" or
"microchip,sam9x7-pit64b", "microchip,sam9x60-pit64b"
- reg: Should contain registers location and length - reg: Should contain registers location and length
- interrupts: Should contain interrupt for PIT64B timer - interrupts: Should contain interrupt for PIT64B timer
- clocks: Should contain the available clock sources for PIT64B timer. - clocks: Should contain the available clock sources for PIT64B timer.
...@@ -31,7 +32,8 @@ RAMC SDRAM/DDR Controller required properties: ...@@ -31,7 +32,8 @@ RAMC SDRAM/DDR Controller required properties:
"atmel,at91sam9g45-ddramc", "atmel,at91sam9g45-ddramc",
"atmel,sama5d3-ddramc", "atmel,sama5d3-ddramc",
"microchip,sam9x60-ddramc", "microchip,sam9x60-ddramc",
"microchip,sama7g5-uddrc" "microchip,sama7g5-uddrc",
"microchip,sam9x7-ddramc", "atmel,sama5d3-ddramc".
- reg: Should contain registers location and length - reg: Should contain registers location and length
Examples: Examples:
......
...@@ -26,6 +26,7 @@ select: ...@@ -26,6 +26,7 @@ select:
- rockchip,rk3368-pmu - rockchip,rk3368-pmu
- rockchip,rk3399-pmu - rockchip,rk3399-pmu
- rockchip,rk3568-pmu - rockchip,rk3568-pmu
- rockchip,rk3576-pmu
- rockchip,rk3588-pmu - rockchip,rk3588-pmu
- rockchip,rv1126-pmu - rockchip,rv1126-pmu
...@@ -43,6 +44,7 @@ properties: ...@@ -43,6 +44,7 @@ properties:
- rockchip,rk3368-pmu - rockchip,rk3368-pmu
- rockchip,rk3399-pmu - rockchip,rk3399-pmu
- rockchip,rk3568-pmu - rockchip,rk3568-pmu
- rockchip,rk3576-pmu
- rockchip,rk3588-pmu - rockchip,rk3588-pmu
- rockchip,rv1126-pmu - rockchip,rv1126-pmu
- const: syscon - const: syscon
......
...@@ -139,7 +139,7 @@ examples: ...@@ -139,7 +139,7 @@ examples:
- | - |
rpm { rpm {
rpm-requests { rpm-requests {
compatible = "qcom,rpm-msm8916"; compatible = "qcom,rpm-msm8916", "qcom,smd-rpm";
qcom,smd-channels = "rpm_requests"; qcom,smd-channels = "rpm_requests";
clock-controller { clock-controller {
......
...@@ -22,6 +22,9 @@ description: | ...@@ -22,6 +22,9 @@ description: |
[0] https://developer.arm.com/documentation/den0056/latest [0] https://developer.arm.com/documentation/den0056/latest
anyOf:
- $ref: /schemas/firmware/nxp,imx95-scmi.yaml
properties: properties:
$nodename: $nodename:
const: scmi const: scmi
...@@ -121,6 +124,13 @@ properties: ...@@ -121,6 +124,13 @@ properties:
atomic mode of operation, even if requested. atomic mode of operation, even if requested.
default: 0 default: 0
max-rx-timeout-ms:
description:
An optional time value, expressed in milliseconds, representing the
transport maximum timeout value for the receive channel. The value should
be a non-zero value if set.
minimum: 1
arm,smc-id: arm,smc-id:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
description: description:
...@@ -145,6 +155,14 @@ properties: ...@@ -145,6 +155,14 @@ properties:
required: required:
- '#power-domain-cells' - '#power-domain-cells'
protocol@12:
$ref: '#/$defs/protocol-node'
unevaluatedProperties: false
properties:
reg:
const: 0x12
protocol@13: protocol@13:
$ref: '#/$defs/protocol-node' $ref: '#/$defs/protocol-node'
unevaluatedProperties: false unevaluatedProperties: false
...@@ -284,7 +302,7 @@ properties: ...@@ -284,7 +302,7 @@ properties:
required: required:
- reg - reg
additionalProperties: false unevaluatedProperties: false
$defs: $defs:
protocol-node: protocol-node:
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright 2024 NXP
%YAML 1.2
---
$id: http://devicetree.org/schemas/firmware/nxp,imx95-scmi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: i.MX95 System Control and Management Interface(SCMI) Vendor Protocols Extension
maintainers:
- Peng Fan <peng.fan@nxp.com>
properties:
protocol@81:
$ref: '/schemas/firmware/arm,scmi.yaml#/$defs/protocol-node'
unevaluatedProperties: false
properties:
reg:
const: 0x81
protocol@84:
$ref: '/schemas/firmware/arm,scmi.yaml#/$defs/protocol-node'
unevaluatedProperties: false
properties:
reg:
const: 0x84
nxp,ctrl-ids:
description:
Each entry consists of 2 integers, represents the ctrl id and the value
items:
items:
- description: the ctrl id index
enum: [0, 1, 2, 3, 4, 5, 6, 7, 0x8000, 0x8001, 0x8002, 0x8003,
0x8004, 0x8005, 0x8006, 0x8007]
- description: the value assigned to the ctrl id
minItems: 1
maxItems: 16
$ref: /schemas/types.yaml#/definitions/uint32-matrix
additionalProperties: true
...@@ -134,9 +134,8 @@ allOf: ...@@ -134,9 +134,8 @@ allOf:
properties: properties:
fsl,weim-cs-timing: fsl,weim-cs-timing:
items: items:
items: - description: CSxU
- description: CSxU - description: CSxL
- description: CSxL
- if: - if:
properties: properties:
compatible: compatible:
...@@ -151,10 +150,9 @@ allOf: ...@@ -151,10 +150,9 @@ allOf:
properties: properties:
fsl,weim-cs-timing: fsl,weim-cs-timing:
items: items:
items: - description: CSCRxU
- description: CSCRxU - description: CSCRxL
- description: CSCRxL - description: CSCRxA
- description: CSCRxA
- if: - if:
properties: properties:
compatible: compatible:
...@@ -171,13 +169,12 @@ allOf: ...@@ -171,13 +169,12 @@ allOf:
properties: properties:
fsl,weim-cs-timing: fsl,weim-cs-timing:
items: items:
items: - description: CSxGCR1
- description: CSxGCR1 - description: CSxGCR2
- description: CSxGCR2 - description: CSxRCR1
- description: CSxRCR1 - description: CSxRCR2
- description: CSxRCR2 - description: CSxWCR1
- description: CSxWCR1 - description: CSxWCR2
- description: CSxWCR2
additionalProperties: false additionalProperties: false
......
...@@ -67,7 +67,9 @@ properties: ...@@ -67,7 +67,9 @@ properties:
- const: dirmap - const: dirmap
- const: wbuf - const: wbuf
clocks: true clocks:
minItems: 1
maxItems: 2
interrupts: interrupts:
maxItems: 1 maxItems: 1
......
...@@ -50,6 +50,7 @@ properties: ...@@ -50,6 +50,7 @@ properties:
- rockchip,rk3188-io-voltage-domain - rockchip,rk3188-io-voltage-domain
- rockchip,rk3228-io-voltage-domain - rockchip,rk3228-io-voltage-domain
- rockchip,rk3288-io-voltage-domain - rockchip,rk3288-io-voltage-domain
- rockchip,rk3308-io-voltage-domain
- rockchip,rk3328-io-voltage-domain - rockchip,rk3328-io-voltage-domain
- rockchip,rk3368-io-voltage-domain - rockchip,rk3368-io-voltage-domain
- rockchip,rk3368-pmu-io-voltage-domain - rockchip,rk3368-pmu-io-voltage-domain
...@@ -71,6 +72,7 @@ allOf: ...@@ -71,6 +72,7 @@ allOf:
- $ref: "#/$defs/rk3188" - $ref: "#/$defs/rk3188"
- $ref: "#/$defs/rk3228" - $ref: "#/$defs/rk3228"
- $ref: "#/$defs/rk3288" - $ref: "#/$defs/rk3288"
- $ref: "#/$defs/rk3308"
- $ref: "#/$defs/rk3328" - $ref: "#/$defs/rk3328"
- $ref: "#/$defs/rk3368" - $ref: "#/$defs/rk3368"
- $ref: "#/$defs/rk3368-pmu" - $ref: "#/$defs/rk3368-pmu"
...@@ -194,6 +196,28 @@ $defs: ...@@ -194,6 +196,28 @@ $defs:
wifi-supply: wifi-supply:
description: The supply connected to APIO3_VDD. Also known as SDIO0. description: The supply connected to APIO3_VDD. Also known as SDIO0.
rk3308:
if:
properties:
compatible:
contains:
const: rockchip,rk3308-io-voltage-domain
then:
properties:
vccio0-supply:
description: The supply connected to VCCIO0.
vccio1-supply:
description: The supply connected to VCCIO1.
vccio2-supply:
description: The supply connected to VCCIO2.
vccio3-supply:
description: The supply connected to VCCIO3.
vccio4-supply:
description: The supply connected to VCCIO4.
vccio5-supply:
description: The supply connected to VCCIO5.
rk3328: rk3328:
if: if:
properties: properties:
......
...@@ -90,7 +90,7 @@ examples: ...@@ -90,7 +90,7 @@ examples:
qcom,rpm-msg-ram = <&rpm_msg_ram>; qcom,rpm-msg-ram = <&rpm_msg_ram>;
rpm-requests { rpm-requests {
compatible = "qcom,rpm-msm8996"; compatible = "qcom,rpm-msm8996", "qcom,glink-smd-rpm";
qcom,glink-channels = "rpm_requests"; qcom,glink-channels = "rpm_requests";
/* ... */ /* ... */
......
...@@ -142,7 +142,7 @@ examples: ...@@ -142,7 +142,7 @@ examples:
qcom,smd-edge = <15>; qcom,smd-edge = <15>;
rpm-requests { rpm-requests {
compatible = "qcom,rpm-msm8916"; compatible = "qcom,rpm-msm8916", "qcom,smd-rpm";
qcom,smd-channels = "rpm_requests"; qcom,smd-channels = "rpm_requests";
/* ... */ /* ... */
}; };
...@@ -163,7 +163,7 @@ examples: ...@@ -163,7 +163,7 @@ examples:
mboxes = <&apcs_glb 0>; mboxes = <&apcs_glb 0>;
rpm-requests { rpm-requests {
compatible = "qcom,rpm-qcm2290"; compatible = "qcom,rpm-qcm2290", "qcom,glink-smd-rpm";
qcom,glink-channels = "rpm_requests"; qcom,glink-channels = "rpm_requests";
/* ... */ /* ... */
}; };
......
...@@ -19,6 +19,7 @@ properties: ...@@ -19,6 +19,7 @@ properties:
- amlogic,meson-a1-reset # Reset Controller on A1 and compatible SoCs - amlogic,meson-a1-reset # Reset Controller on A1 and compatible SoCs
- amlogic,meson-s4-reset # Reset Controller on S4 and compatible SoCs - amlogic,meson-s4-reset # Reset Controller on S4 and compatible SoCs
- amlogic,c3-reset # Reset Controller on C3 and compatible SoCs - amlogic,c3-reset # Reset Controller on C3 and compatible SoCs
- amlogic,t7-reset
reg: reg:
maxItems: 1 maxItems: 1
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/reset/mobileye,eyeq5-reset.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mobileye EyeQ5 reset controller
description:
The EyeQ5 reset driver handles three reset domains. Its registers live in a
shared region called OLB.
maintainers:
- Grégory Clement <gregory.clement@bootlin.com>
- Théo Lebrun <theo.lebrun@bootlin.com>
- Vladimir Kondratiev <vladimir.kondratiev@mobileye.com>
properties:
compatible:
const: mobileye,eyeq5-reset
reg:
maxItems: 3
reg-names:
items:
- const: d0
- const: d1
- const: d2
"#reset-cells":
const: 2
description:
The first cell is the domain (0 to 2 inclusive) and the second one is the
reset index inside that domain.
required:
- compatible
- reg
- reg-names
- "#reset-cells"
additionalProperties: false
...@@ -38,13 +38,17 @@ properties: ...@@ -38,13 +38,17 @@ properties:
minItems: 1 minItems: 1
maxItems: 2 maxItems: 2
clock-names: true clock-names:
minItems: 1
maxItems: 2
resets: resets:
minItems: 1 minItems: 1
maxItems: 2 maxItems: 2
reset-names: true reset-names:
minItems: 1
maxItems: 2
allOf: allOf:
- if: - if:
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qe-tsa.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: PowerQUICC QE Time-slot assigner (TSA) controller
maintainers:
- Herve Codina <herve.codina@bootlin.com>
description:
The TSA is the time-slot assigner that can be found on some PowerQUICC SoC.
Its purpose is to route some TDM time-slots to other internal serial
controllers.
properties:
compatible:
items:
- enum:
- fsl,mpc8321-tsa
- const: fsl,qe-tsa
reg:
items:
- description: SI (Serial Interface) register base
- description: SI RAM base
reg-names:
items:
- const: si_regs
- const: si_ram
'#address-cells':
const: 1
'#size-cells':
const: 0
patternProperties:
'^tdm@[0-3]$':
description:
The TDM managed by this controller
type: object
additionalProperties: false
properties:
reg:
minimum: 0
maximum: 3
description:
The TDM number for this TDM, 0 for TDMa, 1 for TDMb, 2 for TDMc and 3
for TDMd.
fsl,common-rxtx-pins:
$ref: /schemas/types.yaml#/definitions/flag
description:
The hardware can use four dedicated pins for Tx clock, Tx sync, Rx
clock and Rx sync or use only two pins, Tx/Rx clock and Tx/Rx sync.
Without the 'fsl,common-rxtx-pins' property, the four pins are used.
With the 'fsl,common-rxtx-pins' property, two pins are used.
clocks:
minItems: 2
items:
- description: Receive sync clock
- description: Receive data clock
- description: Transmit sync clock
- description: Transmit data clock
clock-names:
minItems: 2
items:
- const: rsync
- const: rclk
- const: tsync
- const: tclk
fsl,rx-frame-sync-delay-bits:
enum: [0, 1, 2, 3]
default: 0
description: |
Receive frame sync delay in number of bits.
Indicates the delay between the Rx sync and the first bit of the Rx
frame.
fsl,tx-frame-sync-delay-bits:
enum: [0, 1, 2, 3]
default: 0
description: |
Transmit frame sync delay in number of bits.
Indicates the delay between the Tx sync and the first bit of the Tx
frame.
fsl,clock-falling-edge:
$ref: /schemas/types.yaml#/definitions/flag
description:
Data is sent on falling edge of the clock (and received on the rising
edge). If not present, data is sent on the rising edge (and received
on the falling edge).
fsl,fsync-rising-edge:
$ref: /schemas/types.yaml#/definitions/flag
description:
Frame sync pulses are sampled with the rising edge of the channel
clock. If not present, pulses are sampled with the falling edge.
fsl,fsync-active-low:
$ref: /schemas/types.yaml#/definitions/flag
description:
Frame sync signals are active on low logic level.
If not present, sync signals are active on high level.
fsl,double-speed-clock:
$ref: /schemas/types.yaml#/definitions/flag
description:
The channel clock is twice the data rate.
patternProperties:
'^fsl,[rt]x-ts-routes$':
$ref: /schemas/types.yaml#/definitions/uint32-matrix
description: |
A list of tuple that indicates the Tx or Rx time-slots routes.
items:
items:
- description:
The number of time-slots
minimum: 1
maximum: 64
- description: |
The source (Tx) or destination (Rx) serial interface
(dt-bindings/soc/qe-fsl,tsa.h defines these values)
- 0: No destination
- 1: UCC1
- 2: UCC2
- 3: UCC3
- 4: UCC4
- 5: UCC5
enum: [0, 1, 2, 3, 4, 5]
minItems: 1
maxItems: 64
allOf:
# If fsl,common-rxtx-pins is present, only 2 clocks are needed.
# Else, the 4 clocks must be present.
- if:
required:
- fsl,common-rxtx-pins
then:
properties:
clocks:
maxItems: 2
clock-names:
maxItems: 2
else:
properties:
clocks:
minItems: 4
clock-names:
minItems: 4
required:
- reg
- clocks
- clock-names
required:
- compatible
- reg
- reg-names
- '#address-cells'
- '#size-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/soc/qe-fsl,tsa.h>
tsa@ae0 {
compatible = "fsl,mpc8321-tsa", "fsl,qe-tsa";
reg = <0xae0 0x10>,
<0xc00 0x200>;
reg-names = "si_regs", "si_ram";
#address-cells = <1>;
#size-cells = <0>;
tdm@0 {
/* TDMa */
reg = <0>;
clocks = <&clk_l1rsynca>, <&clk_l1rclka>;
clock-names = "rsync", "rclk";
fsl,common-rxtx-pins;
fsl,fsync-rising-edge;
fsl,tx-ts-routes = <2 0>, /* TS 0..1 */
<24 FSL_QE_TSA_UCC4>, /* TS 2..25 */
<1 0>, /* TS 26 */
<5 FSL_QE_TSA_UCC3>; /* TS 27..31 */
fsl,rx-ts-routes = <2 0>, /* TS 0..1 */
<24 FSL_QE_TSA_UCC4>, /* 2..25 */
<1 0>, /* TS 26 */
<5 FSL_QE_TSA_UCC3>; /* TS 27..31 */
};
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: PowerQUICC QE QUICC Multichannel Controller (QMC)
maintainers:
- Herve Codina <herve.codina@bootlin.com>
description:
The QMC (QUICC Multichannel Controller) emulates up to 64 channels within one
serial controller using the same TDM physical interface routed from TSA.
properties:
compatible:
items:
- enum:
- fsl,mpc8321-ucc-qmc
- const: fsl,qe-ucc-qmc
reg:
items:
- description: UCC (Unified communication controller) register base
- description: Dual port ram base
reg-names:
items:
- const: ucc_regs
- const: dpram
interrupts:
maxItems: 1
description: UCC interrupt line in the QE interrupt controller
fsl,tsa-serial:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- items:
- description: phandle to TSA node
- enum: [1, 2, 3, 4, 5]
description: |
TSA serial interface (dt-bindings/soc/qe-fsl,tsa.h defines these
values)
- 1: UCC1
- 2: UCC2
- 3: UCC3
- 4: UCC4
- 5: UCC5
description:
Should be a phandle/number pair. The phandle to TSA node and the TSA
serial interface to use.
fsl,soft-qmc:
$ref: /schemas/types.yaml#/definitions/string
description:
Soft QMC firmware name to load. If this property is omitted, no firmware
are used.
'#address-cells':
const: 1
'#size-cells':
const: 0
patternProperties:
'^channel@([0-9]|[1-5][0-9]|6[0-3])$':
description:
A channel managed by this controller
type: object
additionalProperties: false
properties:
compatible:
items:
- enum:
- fsl,mpc8321-ucc-qmc-hdlc
- const: fsl,qe-ucc-qmc-hdlc
- const: fsl,qmc-hdlc
reg:
minimum: 0
maximum: 63
description:
The channel number
fsl,operational-mode:
$ref: /schemas/types.yaml#/definitions/string
enum: [transparent, hdlc]
default: transparent
description: |
The channel operational mode
- hdlc: The channel handles HDLC frames
- transparent: The channel handles raw data without any processing
fsl,reverse-data:
$ref: /schemas/types.yaml#/definitions/flag
description:
The bit order as seen on the channels is reversed,
transmitting/receiving the MSB of each octet first.
This flag is used only in 'transparent' mode.
fsl,tx-ts-mask:
$ref: /schemas/types.yaml#/definitions/uint64
description:
Channel assigned Tx time-slots within the Tx time-slots routed by the
TSA to this cell.
fsl,rx-ts-mask:
$ref: /schemas/types.yaml#/definitions/uint64
description:
Channel assigned Rx time-slots within the Rx time-slots routed by the
TSA to this cell.
fsl,framer:
$ref: /schemas/types.yaml#/definitions/phandle
description:
phandle to the framer node. The framer is in charge of an E1/T1 line
interface connected to the TDM bus. It can be used to get the E1/T1 line
status such as link up/down.
allOf:
- if:
properties:
compatible:
not:
contains:
const: fsl,qmc-hdlc
then:
properties:
fsl,framer: false
required:
- reg
- fsl,tx-ts-mask
- fsl,rx-ts-mask
required:
- compatible
- reg
- reg-names
- interrupts
- fsl,tsa-serial
- '#address-cells'
- '#size-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/soc/qe-fsl,tsa.h>
qmc@a60 {
compatible = "fsl,mpc8321-ucc-qmc", "fsl,qe-ucc-qmc";
reg = <0x3200 0x200>,
<0x10000 0x1000>;
reg-names = "ucc_regs", "dpram";
interrupts = <35>;
interrupt-parent = <&qeic>;
fsl,soft-qmc = "fsl_qe_ucode_qmc_8321_11.bin";
#address-cells = <1>;
#size-cells = <0>;
fsl,tsa-serial = <&tsa FSL_QE_TSA_UCC4>;
channel@16 {
/* Ch16 : First 4 even TS from all routed from TSA */
reg = <16>;
fsl,operational-mode = "transparent";
fsl,reverse-data;
fsl,tx-ts-mask = <0x00000000 0x000000aa>;
fsl,rx-ts-mask = <0x00000000 0x000000aa>;
};
channel@17 {
/* Ch17 : First 4 odd TS from all routed from TSA */
reg = <17>;
fsl,operational-mode = "transparent";
fsl,reverse-data;
fsl,tx-ts-mask = <0x00000000 0x00000055>;
fsl,rx-ts-mask = <0x00000000 0x00000055>;
};
channel@19 {
/* Ch19 : 8 TS (TS 8..15) from all routed from TSA */
compatible = "fsl,mpc8321-ucc-qmc-hdlc",
"fsl,qe-ucc-qmc-hdlc",
"fsl,qmc-hdlc";
reg = <19>;
fsl,operational-mode = "hdlc";
fsl,tx-ts-mask = <0x00000000 0x0000ff00>;
fsl,rx-ts-mask = <0x00000000 0x0000ff00>;
fsl,framer = <&framer>;
};
};
...@@ -30,6 +30,11 @@ properties: ...@@ -30,6 +30,11 @@ properties:
- qcom,sm8450-pmic-glink - qcom,sm8450-pmic-glink
- qcom,sm8550-pmic-glink - qcom,sm8550-pmic-glink
- const: qcom,pmic-glink - const: qcom,pmic-glink
- items:
- enum:
- qcom,sm7325-pmic-glink
- const: qcom,qcm6490-pmic-glink
- const: qcom,pmic-glink
- items: - items:
- enum: - enum:
- qcom,sm8650-pmic-glink - qcom,sm8650-pmic-glink
......
...@@ -30,31 +30,37 @@ maintainers: ...@@ -30,31 +30,37 @@ maintainers:
properties: properties:
compatible: compatible:
enum: oneOf:
- qcom,rpm-apq8084 - items:
- qcom,rpm-ipq6018 - enum:
- qcom,rpm-ipq9574 - qcom,rpm-apq8084
- qcom,rpm-mdm9607 - qcom,rpm-mdm9607
- qcom,rpm-msm8226 - qcom,rpm-msm8226
- qcom,rpm-msm8610 - qcom,rpm-msm8610
- qcom,rpm-msm8909 - qcom,rpm-msm8909
- qcom,rpm-msm8916 - qcom,rpm-msm8916
- qcom,rpm-msm8917 - qcom,rpm-msm8917
- qcom,rpm-msm8936 - qcom,rpm-msm8936
- qcom,rpm-msm8937 - qcom,rpm-msm8937
- qcom,rpm-msm8952 - qcom,rpm-msm8952
- qcom,rpm-msm8953 - qcom,rpm-msm8953
- qcom,rpm-msm8974 - qcom,rpm-msm8974
- qcom,rpm-msm8976 - qcom,rpm-msm8976
- qcom,rpm-msm8994 - qcom,rpm-msm8994
- qcom,rpm-msm8996 - const: qcom,smd-rpm
- qcom,rpm-msm8998 - items:
- qcom,rpm-qcm2290 - enum:
- qcom,rpm-qcs404 - qcom,rpm-ipq6018
- qcom,rpm-sdm660 - qcom,rpm-ipq9574
- qcom,rpm-sm6115 - qcom,rpm-msm8996
- qcom,rpm-sm6125 - qcom,rpm-msm8998
- qcom,rpm-sm6375 - qcom,rpm-qcm2290
- qcom,rpm-qcs404
- qcom,rpm-sdm660
- qcom,rpm-sm6115
- qcom,rpm-sm6125
- qcom,rpm-sm6375
- const: qcom,glink-smd-rpm
clock-controller: clock-controller:
$ref: /schemas/clock/qcom,rpmcc.yaml# $ref: /schemas/clock/qcom,rpmcc.yaml#
...@@ -84,21 +90,7 @@ if: ...@@ -84,21 +90,7 @@ if:
properties: properties:
compatible: compatible:
contains: contains:
enum: const: qcom,smd-rpm
- qcom,rpm-apq8084
- qcom,rpm-mdm9607
- qcom,rpm-msm8226
- qcom,rpm-msm8610
- qcom,rpm-msm8909
- qcom,rpm-msm8916
- qcom,rpm-msm8917
- qcom,rpm-msm8936
- qcom,rpm-msm8937
- qcom,rpm-msm8952
- qcom,rpm-msm8953
- qcom,rpm-msm8974
- qcom,rpm-msm8976
- qcom,rpm-msm8994
then: then:
properties: properties:
qcom,glink-channels: false qcom,glink-channels: false
...@@ -129,7 +121,7 @@ examples: ...@@ -129,7 +121,7 @@ examples:
qcom,smd-edge = <15>; qcom,smd-edge = <15>;
rpm-requests { rpm-requests {
compatible = "qcom,rpm-msm8916"; compatible = "qcom,rpm-msm8916", "qcom,smd-rpm";
qcom,smd-channels = "rpm_requests"; qcom,smd-channels = "rpm_requests";
clock-controller { clock-controller {
......
...@@ -56,7 +56,7 @@ examples: ...@@ -56,7 +56,7 @@ examples:
qcom,smd-edge = <15>; qcom,smd-edge = <15>;
rpm-requests { rpm-requests {
compatible = "qcom,rpm-msm8974"; compatible = "qcom,rpm-msm8974", "qcom,smd-rpm";
qcom,smd-channels = "rpm_requests"; qcom,smd-channels = "rpm_requests";
clock-controller { clock-controller {
......
...@@ -20,6 +20,20 @@ properties: ...@@ -20,6 +20,20 @@ properties:
- rockchip,rk3568-pipe-grf - rockchip,rk3568-pipe-grf
- rockchip,rk3568-pipe-phy-grf - rockchip,rk3568-pipe-phy-grf
- rockchip,rk3568-usb2phy-grf - rockchip,rk3568-usb2phy-grf
- rockchip,rk3576-bigcore-grf
- rockchip,rk3576-cci-grf
- rockchip,rk3576-gpu-grf
- rockchip,rk3576-litcore-grf
- rockchip,rk3576-npu-grf
- rockchip,rk3576-php-grf
- rockchip,rk3576-pipe-phy-grf
- rockchip,rk3576-pmu1-grf
- rockchip,rk3576-sdgmac-grf
- rockchip,rk3576-sys-grf
- rockchip,rk3576-usb-grf
- rockchip,rk3576-usbdpphy-grf
- rockchip,rk3576-vo0-grf
- rockchip,rk3576-vop-grf
- rockchip,rk3588-bigcore0-grf - rockchip,rk3588-bigcore0-grf
- rockchip,rk3588-bigcore1-grf - rockchip,rk3588-bigcore1-grf
- rockchip,rk3588-hdptxphy-grf - rockchip,rk3588-hdptxphy-grf
...@@ -64,6 +78,8 @@ properties: ...@@ -64,6 +78,8 @@ properties:
- rockchip,rk3399-pmugrf - rockchip,rk3399-pmugrf
- rockchip,rk3568-grf - rockchip,rk3568-grf
- rockchip,rk3568-pmugrf - rockchip,rk3568-pmugrf
- rockchip,rk3576-ioc-grf
- rockchip,rk3576-pmu0-grf
- rockchip,rk3588-usb2phy-grf - rockchip,rk3588-usb2phy-grf
- rockchip,rv1108-grf - rockchip,rv1108-grf
- rockchip,rv1108-pmugrf - rockchip,rv1108-pmugrf
......
...@@ -32,11 +32,16 @@ properties: ...@@ -32,11 +32,16 @@ properties:
- enum: - enum:
- samsung,exynos850-usi - samsung,exynos850-usi
reg: true reg:
maxItems: 1
clocks: true clocks:
maxItems: 2
clock-names: true clock-names:
items:
- const: pclk
- const: ipclk
ranges: true ranges: true
...@@ -113,9 +118,7 @@ then: ...@@ -113,9 +118,7 @@ then:
- description: Operating clock for UART/SPI/I2C protocol - description: Operating clock for UART/SPI/I2C protocol
clock-names: clock-names:
items: maxItems: 2
- const: pclk
- const: ipclk
required: required:
- reg - reg
......
...@@ -9051,6 +9051,7 @@ M: Herve Codina <herve.codina@bootlin.com> ...@@ -9051,6 +9051,7 @@ M: Herve Codina <herve.codina@bootlin.com>
L: linuxppc-dev@lists.ozlabs.org L: linuxppc-dev@lists.ozlabs.org
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml
F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml
F: drivers/soc/fsl/qe/qmc.c F: drivers/soc/fsl/qe/qmc.c
F: include/soc/fsl/qe/qmc.h F: include/soc/fsl/qe/qmc.h
...@@ -9066,9 +9067,11 @@ M: Herve Codina <herve.codina@bootlin.com> ...@@ -9066,9 +9067,11 @@ M: Herve Codina <herve.codina@bootlin.com>
L: linuxppc-dev@lists.ozlabs.org L: linuxppc-dev@lists.ozlabs.org
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-tsa.yaml F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-tsa.yaml
F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-tsa.yaml
F: drivers/soc/fsl/qe/tsa.c F: drivers/soc/fsl/qe/tsa.c
F: drivers/soc/fsl/qe/tsa.h F: drivers/soc/fsl/qe/tsa.h
F: include/dt-bindings/soc/cpm1-fsl,tsa.h F: include/dt-bindings/soc/cpm1-fsl,tsa.h
F: include/dt-bindings/soc/qe-fsl,tsa.h
FREESCALE QUICC ENGINE UCC ETHERNET DRIVER FREESCALE QUICC ENGINE UCC ETHERNET DRIVER
L: netdev@vger.kernel.org L: netdev@vger.kernel.org
...@@ -18963,6 +18966,7 @@ L: linux-arm-msm@vger.kernel.org ...@@ -18963,6 +18966,7 @@ L: linux-arm-msm@vger.kernel.org
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml F: Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml
F: drivers/soc/qcom/icc-bwmon.c F: drivers/soc/qcom/icc-bwmon.c
F: drivers/soc/qcom/trace_icc-bwmon.h
QUALCOMM IOMMU QUALCOMM IOMMU
M: Rob Clark <robdclark@gmail.com> M: Rob Clark <robdclark@gmail.com>
......
...@@ -141,11 +141,27 @@ config SOC_SAM9X60 ...@@ -141,11 +141,27 @@ config SOC_SAM9X60
help help
Select this if you are using Microchip's SAM9X60 SoC Select this if you are using Microchip's SAM9X60 SoC
config SOC_SAM9X7
bool "SAM9X7"
depends on ARCH_MULTI_V5
select ATMEL_AIC5_IRQ
select ATMEL_PM if PM
select CPU_ARM926T
select HAVE_AT91_USB_CLK
select HAVE_AT91_GENERATED_CLK
select HAVE_AT91_SAM9X60_PLL
select MEMORY
select PINCTRL_AT91
select SOC_SAM_V4_V5
select SRAM if PM
help
Select this if you are using Microchip's SAM9X7 SoC
comment "Clocksource driver selection" comment "Clocksource driver selection"
config ATMEL_CLOCKSOURCE_PIT config ATMEL_CLOCKSOURCE_PIT
bool "Periodic Interval Timer (PIT) support" bool "Periodic Interval Timer (PIT) support"
depends on SOC_AT91SAM9 || SOC_SAM9X60 || SOC_SAMA5 depends on SOC_AT91SAM9 || SOC_SAM9X60 || SOC_SAM9X7 || SOC_SAMA5
default SOC_AT91SAM9 || SOC_SAMA5 default SOC_AT91SAM9 || SOC_SAMA5
select ATMEL_PIT select ATMEL_PIT
help help
...@@ -155,7 +171,7 @@ config ATMEL_CLOCKSOURCE_PIT ...@@ -155,7 +171,7 @@ config ATMEL_CLOCKSOURCE_PIT
config ATMEL_CLOCKSOURCE_TCB config ATMEL_CLOCKSOURCE_TCB
bool "Timer Counter Blocks (TCB) support" bool "Timer Counter Blocks (TCB) support"
default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAM9X60 || SOC_SAMA5 default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAM9X60 || SOC_SAM9X7 || SOC_SAMA5
select ATMEL_TCB_CLKSRC select ATMEL_TCB_CLKSRC
help help
Select this to get a high precision clocksource based on a Select this to get a high precision clocksource based on a
...@@ -166,7 +182,7 @@ config ATMEL_CLOCKSOURCE_TCB ...@@ -166,7 +182,7 @@ config ATMEL_CLOCKSOURCE_TCB
config MICROCHIP_CLOCKSOURCE_PIT64B config MICROCHIP_CLOCKSOURCE_PIT64B
bool "64-bit Periodic Interval Timer (PIT64B) support" bool "64-bit Periodic Interval Timer (PIT64B) support"
default SOC_SAM9X60 || SOC_SAMA7 default SOC_SAM9X60 || SOC_SAM9X7 || SOC_SAMA7
select MICROCHIP_PIT64B select MICROCHIP_PIT64B
help help
Select this to get a high resolution clockevent (SAM9X60) or Select this to get a high resolution clockevent (SAM9X60) or
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o
obj-$(CONFIG_SOC_AT91SAM9) += at91sam9.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9.o
obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o
obj-$(CONFIG_SOC_SAM9X7) += sam9x7.o
obj-$(CONFIG_SOC_SAMA5) += sama5.o sam_secure.o obj-$(CONFIG_SOC_SAMA5) += sama5.o sam_secure.o
obj-$(CONFIG_SOC_SAMA7) += sama7.o obj-$(CONFIG_SOC_SAMA7) += sama7.o
obj-$(CONFIG_SOC_SAMV7) += samv7.o obj-$(CONFIG_SOC_SAMV7) += samv7.o
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
extern void __init at91rm9200_pm_init(void); extern void __init at91rm9200_pm_init(void);
extern void __init at91sam9_pm_init(void); extern void __init at91sam9_pm_init(void);
extern void __init sam9x60_pm_init(void); extern void __init sam9x60_pm_init(void);
extern void __init sam9x7_pm_init(void);
extern void __init sama5_pm_init(void); extern void __init sama5_pm_init(void);
extern void __init sama5d2_pm_init(void); extern void __init sama5d2_pm_init(void);
extern void __init sama7_pm_init(void); extern void __init sama7_pm_init(void);
...@@ -19,6 +20,7 @@ extern void __init sama7_pm_init(void); ...@@ -19,6 +20,7 @@ extern void __init sama7_pm_init(void);
static inline void __init at91rm9200_pm_init(void) { } static inline void __init at91rm9200_pm_init(void) { }
static inline void __init at91sam9_pm_init(void) { } static inline void __init at91sam9_pm_init(void) { }
static inline void __init sam9x60_pm_init(void) { } static inline void __init sam9x60_pm_init(void) { }
static inline void __init sam9x7_pm_init(void) { }
static inline void __init sama5_pm_init(void) { } static inline void __init sama5_pm_init(void) { }
static inline void __init sama5d2_pm_init(void) { } static inline void __init sama5d2_pm_init(void) { }
static inline void __init sama7_pm_init(void) { } static inline void __init sama7_pm_init(void) { }
......
...@@ -233,6 +233,13 @@ static const struct of_device_id sama7g5_ws_ids[] = { ...@@ -233,6 +233,13 @@ static const struct of_device_id sama7g5_ws_ids[] = {
{ /* sentinel */ } { /* sentinel */ }
}; };
static const struct of_device_id sam9x7_ws_ids[] = {
{ .compatible = "microchip,sam9x7-rtc", .data = &ws_info[1] },
{ .compatible = "microchip,sam9x7-rtt", .data = &ws_info[4] },
{ .compatible = "microchip,sam9x7-gem", .data = &ws_info[5] },
{ /* sentinel */ }
};
static int at91_pm_config_ws(unsigned int pm_mode, bool set) static int at91_pm_config_ws(unsigned int pm_mode, bool set)
{ {
const struct wakeup_source_info *wsi; const struct wakeup_source_info *wsi;
...@@ -1361,6 +1368,7 @@ static const struct of_device_id atmel_pmc_ids[] __initconst = { ...@@ -1361,6 +1368,7 @@ static const struct of_device_id atmel_pmc_ids[] __initconst = {
{ .compatible = "atmel,sama5d4-pmc", .data = &pmc_infos[1] }, { .compatible = "atmel,sama5d4-pmc", .data = &pmc_infos[1] },
{ .compatible = "atmel,sama5d2-pmc", .data = &pmc_infos[1] }, { .compatible = "atmel,sama5d2-pmc", .data = &pmc_infos[1] },
{ .compatible = "microchip,sam9x60-pmc", .data = &pmc_infos[4] }, { .compatible = "microchip,sam9x60-pmc", .data = &pmc_infos[4] },
{ .compatible = "microchip,sam9x7-pmc", .data = &pmc_infos[4] },
{ .compatible = "microchip,sama7g5-pmc", .data = &pmc_infos[5] }, { .compatible = "microchip,sama7g5-pmc", .data = &pmc_infos[5] },
{ /* sentinel */ }, { /* sentinel */ },
}; };
...@@ -1499,6 +1507,27 @@ void __init sam9x60_pm_init(void) ...@@ -1499,6 +1507,27 @@ void __init sam9x60_pm_init(void)
soc_pm.config_pmc_ws = at91_sam9x60_config_pmc_ws; soc_pm.config_pmc_ws = at91_sam9x60_config_pmc_ws;
} }
void __init sam9x7_pm_init(void)
{
static const int modes[] __initconst = {
AT91_PM_STANDBY, AT91_PM_ULP0,
};
int ret;
if (!IS_ENABLED(CONFIG_SOC_SAM9X7))
return;
at91_pm_modes_validate(modes, ARRAY_SIZE(modes));
ret = at91_dt_ramc(false);
if (ret)
return;
at91_pm_init(NULL);
soc_pm.ws_ids = sam9x7_ws_ids;
soc_pm.config_pmc_ws = at91_sam9x60_config_pmc_ws;
}
void __init at91sam9_pm_init(void) void __init at91sam9_pm_init(void)
{ {
int ret; int ret;
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Setup code for SAM9X7.
*
* Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries
*
* Author: Varshini Rajendran <varshini.rajendran@microchip.com>
*/
#include <linux/of.h>
#include <linux/of_platform.h>
#include <asm/mach/arch.h>
#include "generic.h"
static void __init sam9x7_init(void)
{
of_platform_default_populate(NULL, NULL, NULL);
sam9x7_pm_init();
}
static const char * const sam9x7_dt_board_compat[] __initconst = {
"microchip,sam9x7",
NULL
};
DT_MACHINE_START(sam9x7_dt, "Microchip SAM9X7")
/* Maintainer: Microchip */
.init_machine = sam9x7_init,
.dt_compat = sam9x7_dt_board_compat,
MACHINE_END
...@@ -70,6 +70,7 @@ static void __init realview_smp_prepare_cpus(unsigned int max_cpus) ...@@ -70,6 +70,7 @@ static void __init realview_smp_prepare_cpus(unsigned int max_cpus)
return; return;
} }
map = syscon_node_to_regmap(np); map = syscon_node_to_regmap(np);
of_node_put(np);
if (IS_ERR(map)) { if (IS_ERR(map)) {
pr_err("PLATSMP: No syscon regmap\n"); pr_err("PLATSMP: No syscon regmap\n");
return; return;
......
...@@ -89,7 +89,7 @@ config HISILICON_LPC ...@@ -89,7 +89,7 @@ config HISILICON_LPC
config IMX_WEIM config IMX_WEIM
bool "Freescale EIM DRIVER" bool "Freescale EIM DRIVER"
depends on ARCH_MXC depends on ARCH_MXC || COMPILE_TEST
help help
Driver for i.MX WEIM controller. Driver for i.MX WEIM controller.
The WEIM(Wireless External Interface Module) works like a bus. The WEIM(Wireless External Interface Module) works like a bus.
......
...@@ -85,6 +85,7 @@ static int integrator_ap_lm_probe(struct platform_device *pdev) ...@@ -85,6 +85,7 @@ static int integrator_ap_lm_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
} }
map = syscon_node_to_regmap(syscon); map = syscon_node_to_regmap(syscon);
of_node_put(syscon);
if (IS_ERR(map)) { if (IS_ERR(map)) {
dev_err(dev, dev_err(dev,
"could not find Integrator/AP system controller\n"); "could not find Integrator/AP system controller\n");
......
...@@ -282,22 +282,18 @@ static int weim_probe(struct platform_device *pdev) ...@@ -282,22 +282,18 @@ static int weim_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, priv); dev_set_drvdata(&pdev->dev, priv);
/* get the clock */ /* get the clock */
clk = devm_clk_get(&pdev->dev, NULL); clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(clk)) if (IS_ERR(clk))
return PTR_ERR(clk); return PTR_ERR(clk);
ret = clk_prepare_enable(clk);
if (ret)
return ret;
/* parse the device node */ /* parse the device node */
ret = weim_parse_dt(pdev); ret = weim_parse_dt(pdev);
if (ret) if (ret)
clk_disable_unprepare(clk); return ret;
else
dev_info(&pdev->dev, "Driver registered.\n");
return ret; dev_info(&pdev->dev, "Driver registered.\n");
return 0;
} }
#if IS_ENABLED(CONFIG_OF_DYNAMIC) #if IS_ENABLED(CONFIG_OF_DYNAMIC)
......
...@@ -751,12 +751,10 @@ static int sunxi_rsb_probe(struct platform_device *pdev) ...@@ -751,12 +751,10 @@ static int sunxi_rsb_probe(struct platform_device *pdev)
int irq, ret; int irq, ret;
of_property_read_u32(np, "clock-frequency", &clk_freq); of_property_read_u32(np, "clock-frequency", &clk_freq);
if (clk_freq > RSB_MAX_FREQ) { if (clk_freq > RSB_MAX_FREQ)
dev_err(dev, return dev_err_probe(dev, -EINVAL,
"clock-frequency (%u Hz) is too high (max = 20MHz)\n", "clock-frequency (%u Hz) is too high (max = 20MHz)\n",
clk_freq); clk_freq);
return -EINVAL;
}
rsb = devm_kzalloc(dev, sizeof(*rsb), GFP_KERNEL); rsb = devm_kzalloc(dev, sizeof(*rsb), GFP_KERNEL);
if (!rsb) if (!rsb)
...@@ -774,28 +772,22 @@ static int sunxi_rsb_probe(struct platform_device *pdev) ...@@ -774,28 +772,22 @@ static int sunxi_rsb_probe(struct platform_device *pdev)
return irq; return irq;
rsb->clk = devm_clk_get(dev, NULL); rsb->clk = devm_clk_get(dev, NULL);
if (IS_ERR(rsb->clk)) { if (IS_ERR(rsb->clk))
ret = PTR_ERR(rsb->clk); return dev_err_probe(dev, PTR_ERR(rsb->clk),
dev_err(dev, "failed to retrieve clk: %d\n", ret); "failed to retrieve clk\n");
return ret;
}
rsb->rstc = devm_reset_control_get(dev, NULL); rsb->rstc = devm_reset_control_get(dev, NULL);
if (IS_ERR(rsb->rstc)) { if (IS_ERR(rsb->rstc))
ret = PTR_ERR(rsb->rstc); return dev_err_probe(dev, PTR_ERR(rsb->rstc),
dev_err(dev, "failed to retrieve reset controller: %d\n", ret); "failed to retrieve reset controller\n");
return ret;
}
init_completion(&rsb->complete); init_completion(&rsb->complete);
mutex_init(&rsb->lock); mutex_init(&rsb->lock);
ret = devm_request_irq(dev, irq, sunxi_rsb_irq, 0, RSB_CTRL_NAME, rsb); ret = devm_request_irq(dev, irq, sunxi_rsb_irq, 0, RSB_CTRL_NAME, rsb);
if (ret) { if (ret)
dev_err(dev, "can't register interrupt handler irq %d: %d\n", return dev_err_probe(dev, ret,
irq, ret); "can't register interrupt handler irq %d\n", irq);
return ret;
}
ret = sunxi_rsb_hw_init(rsb); ret = sunxi_rsb_hw_init(rsb);
if (ret) if (ret)
......
...@@ -126,7 +126,6 @@ static const char * const clock_names[SYSC_MAX_CLOCKS] = { ...@@ -126,7 +126,6 @@ static const char * const clock_names[SYSC_MAX_CLOCKS] = {
* @enabled: sysc runtime enabled status * @enabled: sysc runtime enabled status
* @needs_resume: runtime resume needed on resume from suspend * @needs_resume: runtime resume needed on resume from suspend
* @child_needs_resume: runtime resume needed for child on resume from suspend * @child_needs_resume: runtime resume needed for child on resume from suspend
* @disable_on_idle: status flag used for disabling modules with resets
* @idle_work: work structure used to perform delayed idle on a module * @idle_work: work structure used to perform delayed idle on a module
* @pre_reset_quirk: module specific pre-reset quirk * @pre_reset_quirk: module specific pre-reset quirk
* @post_reset_quirk: module specific post-reset quirk * @post_reset_quirk: module specific post-reset quirk
...@@ -2569,14 +2568,12 @@ static const struct sysc_dts_quirk sysc_dts_quirks[] = { ...@@ -2569,14 +2568,12 @@ static const struct sysc_dts_quirk sysc_dts_quirks[] = {
static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np, static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
bool is_child) bool is_child)
{ {
const struct property *prop; int i;
int i, len;
for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) { for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) {
const char *name = sysc_dts_quirks[i].name; const char *name = sysc_dts_quirks[i].name;
prop = of_get_property(np, name, &len); if (!of_property_present(np, name))
if (!prop)
continue; continue;
ddata->cfg.quirks |= sysc_dts_quirks[i].mask; ddata->cfg.quirks |= sysc_dts_quirks[i].mask;
......
This diff is collapsed.
...@@ -55,116 +55,22 @@ config ARM_SCMI_RAW_MODE_SUPPORT_COEX ...@@ -55,116 +55,22 @@ config ARM_SCMI_RAW_MODE_SUPPORT_COEX
operate normally, thing which could make an SCMI test suite using the operate normally, thing which could make an SCMI test suite using the
SCMI Raw mode support unreliable. If unsure, say N. SCMI Raw mode support unreliable. If unsure, say N.
config ARM_SCMI_HAVE_TRANSPORT config ARM_SCMI_DEBUG_COUNTERS
bool bool "Enable SCMI communication debug metrics tracking"
help select ARM_SCMI_NEED_DEBUGFS
This declares whether at least one SCMI transport has been configured. depends on DEBUG_FS
Used to trigger a build bug when trying to build SCMI without any default n
configured transport.
config ARM_SCMI_HAVE_SHMEM
bool
help
This declares whether a shared memory based transport for SCMI is
available.
config ARM_SCMI_HAVE_MSG
bool
help
This declares whether a message passing based transport for SCMI is
available.
config ARM_SCMI_TRANSPORT_MAILBOX
bool "SCMI transport based on Mailbox"
depends on MAILBOX
select ARM_SCMI_HAVE_TRANSPORT
select ARM_SCMI_HAVE_SHMEM
default y
help
Enable mailbox based transport for SCMI.
If you want the ARM SCMI PROTOCOL stack to include support for a
transport based on mailboxes, answer Y.
config ARM_SCMI_TRANSPORT_OPTEE
bool "SCMI transport based on OP-TEE service"
depends on OPTEE=y || OPTEE=ARM_SCMI_PROTOCOL
select ARM_SCMI_HAVE_TRANSPORT
select ARM_SCMI_HAVE_SHMEM
select ARM_SCMI_HAVE_MSG
default y
help
This enables the OP-TEE service based transport for SCMI.
If you want the ARM SCMI PROTOCOL stack to include support for a
transport based on OP-TEE SCMI service, answer Y.
config ARM_SCMI_TRANSPORT_SMC
bool "SCMI transport based on SMC"
depends on HAVE_ARM_SMCCC_DISCOVERY
select ARM_SCMI_HAVE_TRANSPORT
select ARM_SCMI_HAVE_SHMEM
default y
help
Enable SMC based transport for SCMI.
If you want the ARM SCMI PROTOCOL stack to include support for a
transport based on SMC, answer Y.
config ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE
bool "Enable atomic mode support for SCMI SMC transport"
depends on ARM_SCMI_TRANSPORT_SMC
help
Enable support of atomic operation for SCMI SMC based transport.
If you want the SCMI SMC based transport to operate in atomic
mode, avoiding any kind of sleeping behaviour for selected
transactions on the TX path, answer Y.
Enabling atomic mode operations allows any SCMI driver using this
transport to optionally ask for atomic SCMI transactions and operate
in atomic context too, at the price of using a number of busy-waiting
primitives all over instead. If unsure say N.
config ARM_SCMI_TRANSPORT_VIRTIO
bool "SCMI transport based on VirtIO"
depends on VIRTIO=y || VIRTIO=ARM_SCMI_PROTOCOL
select ARM_SCMI_HAVE_TRANSPORT
select ARM_SCMI_HAVE_MSG
help
This enables the virtio based transport for SCMI.
If you want the ARM SCMI PROTOCOL stack to include support for a
transport based on VirtIO, answer Y.
config ARM_SCMI_TRANSPORT_VIRTIO_VERSION1_COMPLIANCE
bool "SCMI VirtIO transport Version 1 compliance"
depends on ARM_SCMI_TRANSPORT_VIRTIO
default y
help
This enforces strict compliance with VirtIO Version 1 specification.
If you want the ARM SCMI VirtIO transport layer to refuse to work
with Legacy VirtIO backends and instead support only VirtIO Version 1
devices (or above), answer Y.
If you want instead to support also old Legacy VirtIO backends (like
the ones implemented by kvmtool) and let the core Kernel VirtIO layer
take care of the needed conversions, say N.
config ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE
bool "Enable atomic mode for SCMI VirtIO transport"
depends on ARM_SCMI_TRANSPORT_VIRTIO
help help
Enable support of atomic operation for SCMI VirtIO based transport. Enables tracking of some key communication metrics for debug
purposes. It may track metrics like how many messages were sent
or received, were there any failures, what kind of failures, ..etc.
If you want the SCMI VirtIO based transport to operate in atomic Enable this option to create a new debugfs directory which contains
mode, avoiding any kind of sleeping behaviour for selected such useful debug counters. This can be helpful for debugging and
transactions on the TX path, answer Y. SCMI monitoring.
Enabling atomic mode operations allows any SCMI driver using this source "drivers/firmware/arm_scmi/transports/Kconfig"
transport to optionally ask for atomic SCMI transactions and operate source "drivers/firmware/arm_scmi/vendors/imx/Kconfig"
in atomic context too, at the price of using a number of busy-waiting
primitives all over instead. If unsure say N.
endif #ARM_SCMI_PROTOCOL endif #ARM_SCMI_PROTOCOL
......
...@@ -5,23 +5,15 @@ scmi-core-objs := $(scmi-bus-y) ...@@ -5,23 +5,15 @@ scmi-core-objs := $(scmi-bus-y)
scmi-driver-y = driver.o notify.o scmi-driver-y = driver.o notify.o
scmi-driver-$(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT) += raw_mode.o scmi-driver-$(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT) += raw_mode.o
scmi-transport-$(CONFIG_ARM_SCMI_HAVE_SHMEM) = shmem.o scmi-transport-$(CONFIG_ARM_SCMI_HAVE_SHMEM) = shmem.o
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) += mailbox.o
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += smc.o
scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.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-protocols-y += pinctrl.o
scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) $(scmi-transport-y) scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) $(scmi-transport-y)
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += transports/
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += vendors/imx/
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o
obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) += scmi_power_control.o obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) += scmi_power_control.o
ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy)
# The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame
# pointer in Thumb2 mode, which is forcibly enabled by Clang when profiling
# hooks are inserted via the -pg switch.
CFLAGS_REMOVE_smc.o += $(CC_FLAGS_FTRACE)
endif
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "notify.h" #include "notify.h"
/* Updated only after ALL the mandatory features for that version are merged */ /* Updated only after ALL the mandatory features for that version are merged */
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001
#define SCMI_BASE_NUM_SOURCES 1 #define SCMI_BASE_NUM_SOURCES 1
#define SCMI_BASE_MAX_CMD_ERR_COUNT 1024 #define SCMI_BASE_MAX_CMD_ERR_COUNT 1024
...@@ -42,7 +42,6 @@ struct scmi_msg_resp_base_discover_agent { ...@@ -42,7 +42,6 @@ struct scmi_msg_resp_base_discover_agent {
u8 name[SCMI_SHORT_NAME_MAX_SIZE]; u8 name[SCMI_SHORT_NAME_MAX_SIZE];
}; };
struct scmi_msg_base_error_notify { struct scmi_msg_base_error_notify {
__le32 event_control; __le32 event_control;
#define BASE_TP_NOTIFY_ALL BIT(0) #define BASE_TP_NOTIFY_ALL BIT(0)
...@@ -105,7 +104,6 @@ scmi_base_vendor_id_get(const struct scmi_protocol_handle *ph, bool sub_vendor) ...@@ -105,7 +104,6 @@ scmi_base_vendor_id_get(const struct scmi_protocol_handle *ph, bool sub_vendor)
struct scmi_xfer *t; struct scmi_xfer *t;
struct scmi_revision_info *rev = ph->get_priv(ph); struct scmi_revision_info *rev = ph->get_priv(ph);
if (sub_vendor) { if (sub_vendor) {
cmd = BASE_DISCOVER_SUB_VENDOR; cmd = BASE_DISCOVER_SUB_VENDOR;
vendor_id = rev->sub_vendor_id; vendor_id = rev->sub_vendor_id;
...@@ -386,7 +384,7 @@ static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph) ...@@ -386,7 +384,7 @@ static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph)
if (ret) if (ret)
return ret; return ret;
rev->major_ver = PROTOCOL_REV_MAJOR(version), rev->major_ver = PROTOCOL_REV_MAJOR(version);
rev->minor_ver = PROTOCOL_REV_MINOR(version); rev->minor_ver = PROTOCOL_REV_MINOR(version);
ph->set_priv(ph, rev, version); ph->set_priv(ph, rev, version);
......
...@@ -365,6 +365,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph, ...@@ -365,6 +365,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
ret = ph->xops->do_xfer(ph, t); ret = ph->xops->do_xfer(ph, t);
if (!ret) { if (!ret) {
u32 latency = 0; u32 latency = 0;
attributes = le32_to_cpu(attr->attributes); attributes = le32_to_cpu(attr->attributes);
strscpy(clk->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE); strscpy(clk->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
/* clock_enable_latency field is present only since SCMI v3.1 */ /* clock_enable_latency field is present only since SCMI v3.1 */
......
This diff is collapsed.
This diff is collapsed.
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* *
* Derived from shm.c. * Derived from shm.c.
* *
* Copyright (C) 2019-2021 ARM Ltd. * Copyright (C) 2019-2024 ARM Ltd.
* Copyright (C) 2020-2021 OpenSynergy GmbH * Copyright (C) 2020-2021 OpenSynergy GmbH
*/ */
...@@ -30,7 +30,7 @@ struct scmi_msg_payld { ...@@ -30,7 +30,7 @@ struct scmi_msg_payld {
* *
* Return: transport SDU size. * Return: transport SDU size.
*/ */
size_t msg_command_size(struct scmi_xfer *xfer) static size_t msg_command_size(struct scmi_xfer *xfer)
{ {
return sizeof(struct scmi_msg_payld) + xfer->tx.len; return sizeof(struct scmi_msg_payld) + xfer->tx.len;
} }
...@@ -42,7 +42,7 @@ size_t msg_command_size(struct scmi_xfer *xfer) ...@@ -42,7 +42,7 @@ size_t msg_command_size(struct scmi_xfer *xfer)
* *
* Return: transport SDU size. * Return: transport SDU size.
*/ */
size_t msg_response_size(struct scmi_xfer *xfer) static size_t msg_response_size(struct scmi_xfer *xfer)
{ {
return sizeof(struct scmi_msg_payld) + sizeof(__le32) + xfer->rx.len; return sizeof(struct scmi_msg_payld) + sizeof(__le32) + xfer->rx.len;
} }
...@@ -53,7 +53,7 @@ size_t msg_response_size(struct scmi_xfer *xfer) ...@@ -53,7 +53,7 @@ size_t msg_response_size(struct scmi_xfer *xfer)
* @msg: transport SDU for command * @msg: transport SDU for command
* @xfer: message which is being sent * @xfer: message which is being sent
*/ */
void msg_tx_prepare(struct scmi_msg_payld *msg, struct scmi_xfer *xfer) static void msg_tx_prepare(struct scmi_msg_payld *msg, struct scmi_xfer *xfer)
{ {
msg->msg_header = cpu_to_le32(pack_scmi_header(&xfer->hdr)); msg->msg_header = cpu_to_le32(pack_scmi_header(&xfer->hdr));
if (xfer->tx.buf) if (xfer->tx.buf)
...@@ -67,7 +67,7 @@ void msg_tx_prepare(struct scmi_msg_payld *msg, struct scmi_xfer *xfer) ...@@ -67,7 +67,7 @@ void msg_tx_prepare(struct scmi_msg_payld *msg, struct scmi_xfer *xfer)
* *
* Return: SCMI header * Return: SCMI header
*/ */
u32 msg_read_header(struct scmi_msg_payld *msg) static u32 msg_read_header(struct scmi_msg_payld *msg)
{ {
return le32_to_cpu(msg->msg_header); return le32_to_cpu(msg->msg_header);
} }
...@@ -79,8 +79,8 @@ u32 msg_read_header(struct scmi_msg_payld *msg) ...@@ -79,8 +79,8 @@ u32 msg_read_header(struct scmi_msg_payld *msg)
* @len: transport SDU size * @len: transport SDU size
* @xfer: message being responded to * @xfer: message being responded to
*/ */
void msg_fetch_response(struct scmi_msg_payld *msg, size_t len, static void msg_fetch_response(struct scmi_msg_payld *msg,
struct scmi_xfer *xfer) size_t len, struct scmi_xfer *xfer)
{ {
size_t prefix_len = sizeof(*msg) + sizeof(msg->msg_payload[0]); size_t prefix_len = sizeof(*msg) + sizeof(msg->msg_payload[0]);
...@@ -100,8 +100,8 @@ void msg_fetch_response(struct scmi_msg_payld *msg, size_t len, ...@@ -100,8 +100,8 @@ void msg_fetch_response(struct scmi_msg_payld *msg, size_t len,
* @max_len: maximum SCMI payload size to fetch * @max_len: maximum SCMI payload size to fetch
* @xfer: notification message * @xfer: notification message
*/ */
void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len, static void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len,
size_t max_len, struct scmi_xfer *xfer) size_t max_len, struct scmi_xfer *xfer)
{ {
xfer->rx.len = min_t(size_t, max_len, xfer->rx.len = min_t(size_t, max_len,
len >= sizeof(*msg) ? len - sizeof(*msg) : 0); len >= sizeof(*msg) ? len - sizeof(*msg) : 0);
...@@ -109,3 +109,17 @@ void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len, ...@@ -109,3 +109,17 @@ void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len,
/* Take a copy to the rx buffer.. */ /* Take a copy to the rx buffer.. */
memcpy(xfer->rx.buf, msg->msg_payload, xfer->rx.len); memcpy(xfer->rx.buf, msg->msg_payload, xfer->rx.len);
} }
static const struct scmi_message_operations scmi_msg_ops = {
.tx_prepare = msg_tx_prepare,
.command_size = msg_command_size,
.response_size = msg_response_size,
.read_header = msg_read_header,
.fetch_response = msg_fetch_response,
.fetch_notification = msg_fetch_notification,
};
const struct scmi_message_operations *scmi_message_operations_get(void)
{
return &scmi_msg_ops;
}
...@@ -310,7 +310,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, ...@@ -310,7 +310,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
} }
if (!dom_info->mult_factor) if (!dom_info->mult_factor)
dev_warn(ph->dev, dev_warn(ph->dev,
"Wrong sustained perf/frequency(domain %d)\n", "Wrong sustained perf/frequency(domain %d)\n",
dom_info->id); dom_info->id);
strscpy(dom_info->info.name, attr->name, strscpy(dom_info->info.name, attr->name,
......
...@@ -913,4 +913,5 @@ static const struct scmi_protocol scmi_pinctrl = { ...@@ -913,4 +913,5 @@ static const struct scmi_protocol scmi_pinctrl = {
.ops = &pinctrl_proto_ops, .ops = &pinctrl_proto_ops,
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
}; };
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(pinctrl, scmi_pinctrl) DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(pinctrl, scmi_pinctrl)
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "notify.h" #include "notify.h"
/* Updated only after ALL the mandatory features for that version are merged */ /* Updated only after ALL the mandatory features for that version are merged */
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30001
enum scmi_power_protocol_cmd { enum scmi_power_protocol_cmd {
POWER_DOMAIN_ATTRIBUTES = 0x3, POWER_DOMAIN_ATTRIBUTES = 0x3,
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "notify.h" #include "notify.h"
/* Updated only after ALL the mandatory features for that version are merged */ /* Updated only after ALL the mandatory features for that version are merged */
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30001
enum scmi_reset_protocol_cmd { enum scmi_reset_protocol_cmd {
RESET_DOMAIN_ATTRIBUTES = 0x3, RESET_DOMAIN_ATTRIBUTES = 0x3,
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include "notify.h" #include "notify.h"
/* Updated only after ALL the mandatory features for that version are merged */ /* Updated only after ALL the mandatory features for that version are merged */
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30001
#define SCMI_MAX_NUM_SENSOR_AXIS 63 #define SCMI_MAX_NUM_SENSOR_AXIS 63
#define SCMIv2_SENSOR_PROTOCOL 0x10000 #define SCMIv2_SENSOR_PROTOCOL 0x10000
......
...@@ -2,11 +2,13 @@ ...@@ -2,11 +2,13 @@
/* /*
* For transport using shared mem structure. * For transport using shared mem structure.
* *
* Copyright (C) 2019 ARM Ltd. * Copyright (C) 2019-2024 ARM Ltd.
*/ */
#include <linux/ktime.h> #include <linux/ktime.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/processor.h> #include <linux/processor.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -32,8 +34,9 @@ struct scmi_shared_mem { ...@@ -32,8 +34,9 @@ struct scmi_shared_mem {
u8 msg_payload[]; u8 msg_payload[];
}; };
void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, static void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem,
struct scmi_xfer *xfer, struct scmi_chan_info *cinfo) struct scmi_xfer *xfer,
struct scmi_chan_info *cinfo)
{ {
ktime_t stop; ktime_t stop;
...@@ -73,13 +76,13 @@ void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, ...@@ -73,13 +76,13 @@ void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem,
memcpy_toio(shmem->msg_payload, xfer->tx.buf, xfer->tx.len); memcpy_toio(shmem->msg_payload, xfer->tx.buf, xfer->tx.len);
} }
u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem) static u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem)
{ {
return ioread32(&shmem->msg_header); return ioread32(&shmem->msg_header);
} }
void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, static void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem,
struct scmi_xfer *xfer) struct scmi_xfer *xfer)
{ {
size_t len = ioread32(&shmem->length); size_t len = ioread32(&shmem->length);
...@@ -91,8 +94,8 @@ void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, ...@@ -91,8 +94,8 @@ void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem,
memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len); memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len);
} }
void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, static void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem,
size_t max_len, struct scmi_xfer *xfer) size_t max_len, struct scmi_xfer *xfer)
{ {
size_t len = ioread32(&shmem->length); size_t len = ioread32(&shmem->length);
...@@ -103,13 +106,13 @@ void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, ...@@ -103,13 +106,13 @@ void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem,
memcpy_fromio(xfer->rx.buf, shmem->msg_payload, xfer->rx.len); memcpy_fromio(xfer->rx.buf, shmem->msg_payload, xfer->rx.len);
} }
void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem) static void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem)
{ {
iowrite32(SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE, &shmem->channel_status); iowrite32(SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE, &shmem->channel_status);
} }
bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, static bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
struct scmi_xfer *xfer) struct scmi_xfer *xfer)
{ {
u16 xfer_id; u16 xfer_id;
...@@ -123,13 +126,69 @@ bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, ...@@ -123,13 +126,69 @@ bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
} }
bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem) static bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem)
{ {
return (ioread32(&shmem->channel_status) & return (ioread32(&shmem->channel_status) &
SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
} }
bool shmem_channel_intr_enabled(struct scmi_shared_mem __iomem *shmem) static bool shmem_channel_intr_enabled(struct scmi_shared_mem __iomem *shmem)
{ {
return ioread32(&shmem->flags) & SCMI_SHMEM_FLAG_INTR_ENABLED; return ioread32(&shmem->flags) & SCMI_SHMEM_FLAG_INTR_ENABLED;
} }
static void __iomem *shmem_setup_iomap(struct scmi_chan_info *cinfo,
struct device *dev, bool tx,
struct resource *res)
{
struct device_node *shmem __free(device_node);
const char *desc = tx ? "Tx" : "Rx";
int ret, idx = tx ? 0 : 1;
struct device *cdev = cinfo->dev;
struct resource lres = {};
resource_size_t size;
void __iomem *addr;
shmem = of_parse_phandle(cdev->of_node, "shmem", idx);
if (!shmem)
return IOMEM_ERR_PTR(-ENODEV);
if (!of_device_is_compatible(shmem, "arm,scmi-shmem"))
return IOMEM_ERR_PTR(-ENXIO);
/* Use a local on-stack as a working area when not provided */
if (!res)
res = &lres;
ret = of_address_to_resource(shmem, 0, res);
if (ret) {
dev_err(cdev, "failed to get SCMI %s shared memory\n", desc);
return IOMEM_ERR_PTR(ret);
}
size = resource_size(res);
addr = devm_ioremap(dev, res->start, size);
if (!addr) {
dev_err(dev, "failed to ioremap SCMI %s shared memory\n", desc);
return IOMEM_ERR_PTR(-EADDRNOTAVAIL);
}
return addr;
}
static const struct scmi_shared_mem_operations scmi_shmem_ops = {
.tx_prepare = shmem_tx_prepare,
.read_header = shmem_read_header,
.fetch_response = shmem_fetch_response,
.fetch_notification = shmem_fetch_notification,
.clear_channel = shmem_clear_channel,
.poll_done = shmem_poll_done,
.channel_free = shmem_channel_free,
.channel_intr_enabled = shmem_channel_intr_enabled,
.setup_iomap = shmem_setup_iomap,
};
const struct scmi_shared_mem_operations *scmi_shared_mem_operations_get(void)
{
return &scmi_shmem_ops;
}
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "notify.h" #include "notify.h"
/* Updated only after ALL the mandatory features for that version are merged */ /* Updated only after ALL the mandatory features for that version are merged */
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001
#define SCMI_SYSTEM_NUM_SOURCES 1 #define SCMI_SYSTEM_NUM_SOURCES 1
......
# SPDX-License-Identifier: GPL-2.0-only
menu "SCMI Transport Drivers"
config ARM_SCMI_HAVE_TRANSPORT
bool
help
This declares whether at least one SCMI transport has been configured.
Used to trigger a build bug when trying to build SCMI without any
configured transport.
config ARM_SCMI_HAVE_SHMEM
bool
help
This declares whether a shared memory based transport for SCMI is
available.
config ARM_SCMI_HAVE_MSG
bool
help
This declares whether a message passing based transport for SCMI is
available.
config ARM_SCMI_TRANSPORT_MAILBOX
tristate "SCMI transport based on Mailbox"
depends on MAILBOX
select ARM_SCMI_HAVE_TRANSPORT
select ARM_SCMI_HAVE_SHMEM
default y
help
Enable mailbox based transport for SCMI.
If you want the ARM SCMI PROTOCOL stack to include support for a
transport based on mailboxes, answer Y.
This driver can also be built as a module. If so, the module
will be called scmi_transport_mailbox.
config ARM_SCMI_TRANSPORT_SMC
tristate "SCMI transport based on SMC"
depends on HAVE_ARM_SMCCC_DISCOVERY
select ARM_SCMI_HAVE_TRANSPORT
select ARM_SCMI_HAVE_SHMEM
default y
help
Enable SMC based transport for SCMI.
If you want the ARM SCMI PROTOCOL stack to include support for a
transport based on SMC, answer Y.
This driver can also be built as a module. If so, the module
will be called scmi_transport_smc.
config ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE
bool "Enable atomic mode support for SCMI SMC transport"
depends on ARM_SCMI_TRANSPORT_SMC
help
Enable support of atomic operation for SCMI SMC based transport.
If you want the SCMI SMC based transport to operate in atomic
mode, avoiding any kind of sleeping behaviour for selected
transactions on the TX path, answer Y.
Enabling atomic mode operations allows any SCMI driver using this
transport to optionally ask for atomic SCMI transactions and operate
in atomic context too, at the price of using a number of busy-waiting
primitives all over instead. If unsure say N.
config ARM_SCMI_TRANSPORT_OPTEE
tristate "SCMI transport based on OP-TEE service"
depends on OPTEE
select ARM_SCMI_HAVE_TRANSPORT
select ARM_SCMI_HAVE_SHMEM
select ARM_SCMI_HAVE_MSG
default y
help
This enables the OP-TEE service based transport for SCMI.
If you want the ARM SCMI PROTOCOL stack to include support for a
transport based on OP-TEE SCMI service, answer Y.
This driver can also be built as a module. If so, the module
will be called scmi_transport_optee.
config ARM_SCMI_TRANSPORT_VIRTIO
tristate "SCMI transport based on VirtIO"
depends on VIRTIO
select ARM_SCMI_HAVE_TRANSPORT
select ARM_SCMI_HAVE_MSG
help
This enables the virtio based transport for SCMI.
If you want the ARM SCMI PROTOCOL stack to include support for a
transport based on VirtIO, answer Y.
This driver can also be built as a module. If so, the module
will be called scmi_transport_virtio.
config ARM_SCMI_TRANSPORT_VIRTIO_VERSION1_COMPLIANCE
bool "SCMI VirtIO transport Version 1 compliance"
depends on ARM_SCMI_TRANSPORT_VIRTIO
default y
help
This enforces strict compliance with VirtIO Version 1 specification.
If you want the ARM SCMI VirtIO transport layer to refuse to work
with Legacy VirtIO backends and instead support only VirtIO Version 1
devices (or above), answer Y.
If you want instead to support also old Legacy VirtIO backends (like
the ones implemented by kvmtool) and let the core Kernel VirtIO layer
take care of the needed conversions, say N.
config ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE
bool "Enable atomic mode for SCMI VirtIO transport"
depends on ARM_SCMI_TRANSPORT_VIRTIO
help
Enable support of atomic operation for SCMI VirtIO based transport.
If you want the SCMI VirtIO based transport to operate in atomic
mode, avoiding any kind of sleeping behaviour for selected
transactions on the TX path, answer Y.
Enabling atomic mode operations allows any SCMI driver using this
transport to optionally ask for atomic SCMI transactions and operate
in atomic context too, at the price of using a number of busy-waiting
primitives all over instead. If unsure say N.
endmenu
# SPDX-License-Identifier: GPL-2.0-only
scmi_transport_mailbox-objs := mailbox.o
obj-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) += scmi_transport_mailbox.o
scmi_transport_smc-objs := smc.o
obj-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += scmi_transport_smc.o
scmi_transport_optee-objs := optee.o
obj-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += scmi_transport_optee.o
scmi_transport_virtio-objs := virtio.o
obj-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += scmi_transport_virtio.o
ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy)
# The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame
# pointer in Thumb2 mode, which is forcibly enabled by Clang when profiling
# hooks are inserted via the -pg switch.
CFLAGS_REMOVE_smc.o += $(CC_FLAGS_FTRACE)
endif
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* System Control and Management Interface (SCMI) Message Mailbox Transport * System Control and Management Interface (SCMI) Message Mailbox Transport
* driver. * driver.
* *
* Copyright (C) 2019 ARM Ltd. * Copyright (C) 2019-2024 ARM Ltd.
*/ */
#include <linux/err.h> #include <linux/err.h>
...@@ -11,9 +11,10 @@ ...@@ -11,9 +11,10 @@
#include <linux/mailbox_client.h> #include <linux/mailbox_client.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "common.h" #include "../common.h"
/** /**
* struct scmi_mailbox - Structure representing a SCMI mailbox transport * struct scmi_mailbox - Structure representing a SCMI mailbox transport
...@@ -36,11 +37,13 @@ struct scmi_mailbox { ...@@ -36,11 +37,13 @@ struct scmi_mailbox {
#define client_to_scmi_mailbox(c) container_of(c, struct scmi_mailbox, cl) #define client_to_scmi_mailbox(c) container_of(c, struct scmi_mailbox, cl)
static struct scmi_transport_core_operations *core;
static void tx_prepare(struct mbox_client *cl, void *m) static void tx_prepare(struct mbox_client *cl, void *m)
{ {
struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl); struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl);
shmem_tx_prepare(smbox->shmem, m, smbox->cinfo); core->shmem->tx_prepare(smbox->shmem, m, smbox->cinfo);
} }
static void rx_callback(struct mbox_client *cl, void *m) static void rx_callback(struct mbox_client *cl, void *m)
...@@ -56,15 +59,17 @@ static void rx_callback(struct mbox_client *cl, void *m) ...@@ -56,15 +59,17 @@ static void rx_callback(struct mbox_client *cl, void *m)
* a previous timed-out reply which arrived late could be wrongly * a previous timed-out reply which arrived late could be wrongly
* associated with the next pending transaction. * associated with the next pending transaction.
*/ */
if (cl->knows_txdone && !shmem_channel_free(smbox->shmem)) { if (cl->knows_txdone &&
!core->shmem->channel_free(smbox->shmem)) {
dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n"); dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n");
scmi_bad_message_trace(smbox->cinfo, core->bad_message_trace(smbox->cinfo,
shmem_read_header(smbox->shmem), core->shmem->read_header(smbox->shmem),
MSG_MBOX_SPURIOUS); MSG_MBOX_SPURIOUS);
return; return;
} }
scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem), NULL); core->rx_callback(smbox->cinfo,
core->shmem->read_header(smbox->shmem), NULL);
} }
static bool mailbox_chan_available(struct device_node *of_node, int idx) static bool mailbox_chan_available(struct device_node *of_node, int idx)
...@@ -124,18 +129,16 @@ static int mailbox_chan_validate(struct device *cdev, int *a2p_rx_chan, ...@@ -124,18 +129,16 @@ static int mailbox_chan_validate(struct device *cdev, int *a2p_rx_chan,
/* Bail out if provided shmem descriptors do not refer distinct areas */ /* Bail out if provided shmem descriptors do not refer distinct areas */
if (num_sh > 1) { if (num_sh > 1) {
struct device_node *np_tx, *np_rx; struct device_node *np_tx __free(device_node) =
of_parse_phandle(np, "shmem", 0);
struct device_node *np_rx __free(device_node) =
of_parse_phandle(np, "shmem", 1);
np_tx = of_parse_phandle(np, "shmem", 0);
np_rx = of_parse_phandle(np, "shmem", 1);
if (!np_tx || !np_rx || np_tx == np_rx) { if (!np_tx || !np_rx || np_tx == np_rx) {
dev_warn(cdev, "Invalid shmem descriptor for '%s'\n", dev_warn(cdev, "Invalid shmem descriptor for '%s'\n",
of_node_full_name(np)); of_node_full_name(np));
ret = -EINVAL; ret = -EINVAL;
} }
of_node_put(np_tx);
of_node_put(np_rx);
} }
/* Calculate channels IDs to use depending on mboxes/shmem layout */ /* Calculate channels IDs to use depending on mboxes/shmem layout */
...@@ -178,11 +181,8 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, ...@@ -178,11 +181,8 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
const char *desc = tx ? "Tx" : "Rx"; const char *desc = tx ? "Tx" : "Rx";
struct device *cdev = cinfo->dev; struct device *cdev = cinfo->dev;
struct scmi_mailbox *smbox; struct scmi_mailbox *smbox;
struct device_node *shmem; int ret, a2p_rx_chan, p2a_chan, p2a_rx_chan;
int ret, a2p_rx_chan, p2a_chan, p2a_rx_chan, idx = tx ? 0 : 1;
struct mbox_client *cl; struct mbox_client *cl;
resource_size_t size;
struct resource res;
ret = mailbox_chan_validate(cdev, &a2p_rx_chan, &p2a_chan, &p2a_rx_chan); ret = mailbox_chan_validate(cdev, &a2p_rx_chan, &p2a_chan, &p2a_rx_chan);
if (ret) if (ret)
...@@ -195,25 +195,9 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, ...@@ -195,25 +195,9 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
if (!smbox) if (!smbox)
return -ENOMEM; return -ENOMEM;
shmem = of_parse_phandle(cdev->of_node, "shmem", idx); smbox->shmem = core->shmem->setup_iomap(cinfo, dev, tx, NULL);
if (!of_device_is_compatible(shmem, "arm,scmi-shmem")) { if (IS_ERR(smbox->shmem))
of_node_put(shmem); return PTR_ERR(smbox->shmem);
return -ENXIO;
}
ret = of_address_to_resource(shmem, 0, &res);
of_node_put(shmem);
if (ret) {
dev_err(cdev, "failed to get SCMI %s shared memory\n", desc);
return ret;
}
size = resource_size(&res);
smbox->shmem = devm_ioremap(dev, res.start, size);
if (!smbox->shmem) {
dev_err(dev, "failed to ioremap SCMI %s shared memory\n", desc);
return -EADDRNOTAVAIL;
}
cl = &smbox->cl; cl = &smbox->cl;
cl->dev = cdev; cl->dev = cdev;
...@@ -252,7 +236,6 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, ...@@ -252,7 +236,6 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
} }
} }
cinfo->transport_info = smbox; cinfo->transport_info = smbox;
smbox->cinfo = cinfo; smbox->cinfo = cinfo;
...@@ -312,7 +295,7 @@ static void mailbox_fetch_response(struct scmi_chan_info *cinfo, ...@@ -312,7 +295,7 @@ static void mailbox_fetch_response(struct scmi_chan_info *cinfo,
{ {
struct scmi_mailbox *smbox = cinfo->transport_info; struct scmi_mailbox *smbox = cinfo->transport_info;
shmem_fetch_response(smbox->shmem, xfer); core->shmem->fetch_response(smbox->shmem, xfer);
} }
static void mailbox_fetch_notification(struct scmi_chan_info *cinfo, static void mailbox_fetch_notification(struct scmi_chan_info *cinfo,
...@@ -320,7 +303,7 @@ static void mailbox_fetch_notification(struct scmi_chan_info *cinfo, ...@@ -320,7 +303,7 @@ static void mailbox_fetch_notification(struct scmi_chan_info *cinfo,
{ {
struct scmi_mailbox *smbox = cinfo->transport_info; struct scmi_mailbox *smbox = cinfo->transport_info;
shmem_fetch_notification(smbox->shmem, max_len, xfer); core->shmem->fetch_notification(smbox->shmem, max_len, xfer);
} }
static void mailbox_clear_channel(struct scmi_chan_info *cinfo) static void mailbox_clear_channel(struct scmi_chan_info *cinfo)
...@@ -329,9 +312,9 @@ static void mailbox_clear_channel(struct scmi_chan_info *cinfo) ...@@ -329,9 +312,9 @@ static void mailbox_clear_channel(struct scmi_chan_info *cinfo)
struct mbox_chan *intr_chan; struct mbox_chan *intr_chan;
int ret; int ret;
shmem_clear_channel(smbox->shmem); core->shmem->clear_channel(smbox->shmem);
if (!shmem_channel_intr_enabled(smbox->shmem)) if (!core->shmem->channel_intr_enabled(smbox->shmem))
return; return;
if (smbox->chan_platform_receiver) if (smbox->chan_platform_receiver)
...@@ -354,7 +337,7 @@ mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) ...@@ -354,7 +337,7 @@ mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
{ {
struct scmi_mailbox *smbox = cinfo->transport_info; struct scmi_mailbox *smbox = cinfo->transport_info;
return shmem_poll_done(smbox->shmem, xfer); return core->shmem->poll_done(smbox->shmem, xfer);
} }
static const struct scmi_transport_ops scmi_mailbox_ops = { static const struct scmi_transport_ops scmi_mailbox_ops = {
...@@ -369,9 +352,22 @@ static const struct scmi_transport_ops scmi_mailbox_ops = { ...@@ -369,9 +352,22 @@ static const struct scmi_transport_ops scmi_mailbox_ops = {
.poll_done = mailbox_poll_done, .poll_done = mailbox_poll_done,
}; };
const struct scmi_desc scmi_mailbox_desc = { static struct scmi_desc scmi_mailbox_desc = {
.ops = &scmi_mailbox_ops, .ops = &scmi_mailbox_ops,
.max_rx_timeout_ms = 30, /* We may increase this if required */ .max_rx_timeout_ms = 30, /* We may increase this if required */
.max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */ .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */
.max_msg_size = 128, .max_msg_size = 128,
}; };
static const struct of_device_id scmi_of_match[] = {
{ .compatible = "arm,scmi" },
{ /* Sentinel */ },
};
DEFINE_SCMI_TRANSPORT_DRIVER(scmi_mailbox, scmi_mailbox_driver,
scmi_mailbox_desc, scmi_of_match, core);
module_platform_driver(scmi_mailbox_driver);
MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
MODULE_DESCRIPTION("SCMI Mailbox Transport driver");
MODULE_LICENSE("GPL");
...@@ -9,12 +9,13 @@ ...@@ -9,12 +9,13 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/tee_drv.h> #include <linux/tee_drv.h>
#include <linux/uuid.h> #include <linux/uuid.h>
#include <uapi/linux/tee.h> #include <uapi/linux/tee.h>
#include "common.h" #include "../common.h"
#define SCMI_OPTEE_MAX_MSG_SIZE 128 #define SCMI_OPTEE_MAX_MSG_SIZE 128
...@@ -148,12 +149,11 @@ struct scmi_optee_agent { ...@@ -148,12 +149,11 @@ struct scmi_optee_agent {
struct list_head channel_list; struct list_head channel_list;
}; };
static struct scmi_transport_core_operations *core;
/* There can be only 1 SCMI service in OP-TEE we connect to */ /* There can be only 1 SCMI service in OP-TEE we connect to */
static struct scmi_optee_agent *scmi_optee_private; static struct scmi_optee_agent *scmi_optee_private;
/* Forward reference to scmi_optee transport initialization */
static int scmi_optee_init(void);
/* Open a session toward SCMI OP-TEE service with REE_KERNEL identity */ /* Open a session toward SCMI OP-TEE service with REE_KERNEL identity */
static int open_session(struct scmi_optee_agent *agent, u32 *tee_session) static int open_session(struct scmi_optee_agent *agent, u32 *tee_session)
{ {
...@@ -312,24 +312,6 @@ static int invoke_process_msg_channel(struct scmi_optee_channel *channel, size_t ...@@ -312,24 +312,6 @@ static int invoke_process_msg_channel(struct scmi_optee_channel *channel, size_t
return 0; return 0;
} }
static int scmi_optee_link_supplier(struct device *dev)
{
if (!scmi_optee_private) {
if (scmi_optee_init())
dev_dbg(dev, "Optee bus not yet ready\n");
/* Wait for optee bus */
return -EPROBE_DEFER;
}
if (!device_link_add(dev, scmi_optee_private->dev, DL_FLAG_AUTOREMOVE_CONSUMER)) {
dev_err(dev, "Adding link to supplier optee device failed\n");
return -ECANCELED;
}
return 0;
}
static bool scmi_optee_chan_available(struct device_node *of_node, int idx) static bool scmi_optee_chan_available(struct device_node *of_node, int idx)
{ {
u32 channel_id; u32 channel_id;
...@@ -343,7 +325,7 @@ static void scmi_optee_clear_channel(struct scmi_chan_info *cinfo) ...@@ -343,7 +325,7 @@ static void scmi_optee_clear_channel(struct scmi_chan_info *cinfo)
struct scmi_optee_channel *channel = cinfo->transport_info; struct scmi_optee_channel *channel = cinfo->transport_info;
if (!channel->tee_shm) if (!channel->tee_shm)
shmem_clear_channel(channel->req.shmem); core->shmem->clear_channel(channel->req.shmem);
} }
static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *channel) static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *channel)
...@@ -368,38 +350,11 @@ static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *ch ...@@ -368,38 +350,11 @@ static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *ch
static int setup_static_shmem(struct device *dev, struct scmi_chan_info *cinfo, static int setup_static_shmem(struct device *dev, struct scmi_chan_info *cinfo,
struct scmi_optee_channel *channel) struct scmi_optee_channel *channel)
{ {
struct device_node *np; channel->req.shmem = core->shmem->setup_iomap(cinfo, dev, true, NULL);
resource_size_t size; if (IS_ERR(channel->req.shmem))
struct resource res; return PTR_ERR(channel->req.shmem);
int ret;
np = of_parse_phandle(cinfo->dev->of_node, "shmem", 0); return 0;
if (!of_device_is_compatible(np, "arm,scmi-shmem")) {
ret = -ENXIO;
goto out;
}
ret = of_address_to_resource(np, 0, &res);
if (ret) {
dev_err(dev, "Failed to get SCMI Tx shared memory\n");
goto out;
}
size = resource_size(&res);
channel->req.shmem = devm_ioremap(dev, res.start, size);
if (!channel->req.shmem) {
dev_err(dev, "Failed to ioremap SCMI Tx shared memory\n");
ret = -EADDRNOTAVAIL;
goto out;
}
ret = 0;
out:
of_node_put(np);
return ret;
} }
static int setup_shmem(struct device *dev, struct scmi_chan_info *cinfo, static int setup_shmem(struct device *dev, struct scmi_chan_info *cinfo,
...@@ -473,6 +428,13 @@ static int scmi_optee_chan_free(int id, void *p, void *data) ...@@ -473,6 +428,13 @@ static int scmi_optee_chan_free(int id, void *p, void *data)
struct scmi_chan_info *cinfo = p; struct scmi_chan_info *cinfo = p;
struct scmi_optee_channel *channel = cinfo->transport_info; struct scmi_optee_channel *channel = cinfo->transport_info;
/*
* Different protocols might share the same chan info, so a previous
* call might have already freed the structure.
*/
if (!channel)
return 0;
mutex_lock(&scmi_optee_private->mu); mutex_lock(&scmi_optee_private->mu);
list_del(&channel->link); list_del(&channel->link);
mutex_unlock(&scmi_optee_private->mu); mutex_unlock(&scmi_optee_private->mu);
...@@ -499,10 +461,11 @@ static int scmi_optee_send_message(struct scmi_chan_info *cinfo, ...@@ -499,10 +461,11 @@ static int scmi_optee_send_message(struct scmi_chan_info *cinfo,
mutex_lock(&channel->mu); mutex_lock(&channel->mu);
if (channel->tee_shm) { if (channel->tee_shm) {
msg_tx_prepare(channel->req.msg, xfer); core->msg->tx_prepare(channel->req.msg, xfer);
ret = invoke_process_msg_channel(channel, msg_command_size(xfer)); ret = invoke_process_msg_channel(channel,
core->msg->command_size(xfer));
} else { } else {
shmem_tx_prepare(channel->req.shmem, xfer, cinfo); core->shmem->tx_prepare(channel->req.shmem, xfer, cinfo);
ret = invoke_process_smt_channel(channel); ret = invoke_process_smt_channel(channel);
} }
...@@ -518,9 +481,10 @@ static void scmi_optee_fetch_response(struct scmi_chan_info *cinfo, ...@@ -518,9 +481,10 @@ static void scmi_optee_fetch_response(struct scmi_chan_info *cinfo,
struct scmi_optee_channel *channel = cinfo->transport_info; struct scmi_optee_channel *channel = cinfo->transport_info;
if (channel->tee_shm) if (channel->tee_shm)
msg_fetch_response(channel->req.msg, channel->rx_len, xfer); core->msg->fetch_response(channel->req.msg,
channel->rx_len, xfer);
else else
shmem_fetch_response(channel->req.shmem, xfer); core->shmem->fetch_response(channel->req.shmem, xfer);
} }
static void scmi_optee_mark_txdone(struct scmi_chan_info *cinfo, int ret, static void scmi_optee_mark_txdone(struct scmi_chan_info *cinfo, int ret,
...@@ -532,7 +496,6 @@ static void scmi_optee_mark_txdone(struct scmi_chan_info *cinfo, int ret, ...@@ -532,7 +496,6 @@ static void scmi_optee_mark_txdone(struct scmi_chan_info *cinfo, int ret,
} }
static struct scmi_transport_ops scmi_optee_ops = { static struct scmi_transport_ops scmi_optee_ops = {
.link_supplier = scmi_optee_link_supplier,
.chan_available = scmi_optee_chan_available, .chan_available = scmi_optee_chan_available,
.chan_setup = scmi_optee_chan_setup, .chan_setup = scmi_optee_chan_setup,
.chan_free = scmi_optee_chan_free, .chan_free = scmi_optee_chan_free,
...@@ -547,6 +510,22 @@ static int scmi_optee_ctx_match(struct tee_ioctl_version_data *ver, const void * ...@@ -547,6 +510,22 @@ static int scmi_optee_ctx_match(struct tee_ioctl_version_data *ver, const void *
return ver->impl_id == TEE_IMPL_ID_OPTEE; return ver->impl_id == TEE_IMPL_ID_OPTEE;
} }
static struct scmi_desc scmi_optee_desc = {
.ops = &scmi_optee_ops,
.max_rx_timeout_ms = 30,
.max_msg = 20,
.max_msg_size = SCMI_OPTEE_MAX_MSG_SIZE,
.sync_cmds_completed_on_ret = true,
};
static const struct of_device_id scmi_of_match[] = {
{ .compatible = "linaro,scmi-optee" },
{ /* Sentinel */ },
};
DEFINE_SCMI_TRANSPORT_DRIVER(scmi_optee, scmi_optee_driver, scmi_optee_desc,
scmi_of_match, core);
static int scmi_optee_service_probe(struct device *dev) static int scmi_optee_service_probe(struct device *dev)
{ {
struct scmi_optee_agent *agent; struct scmi_optee_agent *agent;
...@@ -582,6 +561,12 @@ static int scmi_optee_service_probe(struct device *dev) ...@@ -582,6 +561,12 @@ static int scmi_optee_service_probe(struct device *dev)
smp_mb(); smp_mb();
scmi_optee_private = agent; scmi_optee_private = agent;
ret = platform_driver_register(&scmi_optee_driver);
if (ret) {
scmi_optee_private = NULL;
goto err;
}
return 0; return 0;
err: err:
...@@ -597,6 +582,8 @@ static int scmi_optee_service_remove(struct device *dev) ...@@ -597,6 +582,8 @@ static int scmi_optee_service_remove(struct device *dev)
if (!scmi_optee_private) if (!scmi_optee_private)
return -EINVAL; return -EINVAL;
platform_driver_unregister(&scmi_optee_driver);
if (!list_empty(&scmi_optee_private->channel_list)) if (!list_empty(&scmi_optee_private->channel_list))
return -EBUSY; return -EBUSY;
...@@ -618,7 +605,7 @@ static const struct tee_client_device_id scmi_optee_service_id[] = { ...@@ -618,7 +605,7 @@ static const struct tee_client_device_id scmi_optee_service_id[] = {
MODULE_DEVICE_TABLE(tee, scmi_optee_service_id); MODULE_DEVICE_TABLE(tee, scmi_optee_service_id);
static struct tee_client_driver scmi_optee_driver = { static struct tee_client_driver scmi_optee_service_driver = {
.id_table = scmi_optee_service_id, .id_table = scmi_optee_service_id,
.driver = { .driver = {
.name = "scmi-optee", .name = "scmi-optee",
...@@ -628,22 +615,18 @@ static struct tee_client_driver scmi_optee_driver = { ...@@ -628,22 +615,18 @@ static struct tee_client_driver scmi_optee_driver = {
}, },
}; };
static int scmi_optee_init(void) static int __init scmi_transport_optee_init(void)
{ {
return driver_register(&scmi_optee_driver.driver); return driver_register(&scmi_optee_service_driver.driver);
} }
module_init(scmi_transport_optee_init);
static void scmi_optee_exit(void) static void __exit scmi_transport_optee_exit(void)
{ {
if (scmi_optee_private) driver_unregister(&scmi_optee_service_driver.driver);
driver_unregister(&scmi_optee_driver.driver);
} }
module_exit(scmi_transport_optee_exit);
const struct scmi_desc scmi_optee_desc = { MODULE_AUTHOR("Etienne Carriere <etienne.carriere@foss.st.com>");
.transport_exit = scmi_optee_exit, MODULE_DESCRIPTION("SCMI OPTEE Transport driver");
.ops = &scmi_optee_ops, MODULE_LICENSE("GPL");
.max_rx_timeout_ms = 30,
.max_msg = 20,
.max_msg_size = SCMI_OPTEE_MAX_MSG_SIZE,
.sync_cmds_completed_on_ret = true,
};
...@@ -16,10 +16,11 @@ ...@@ -16,10 +16,11 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <linux/platform_device.h>
#include <linux/processor.h> #include <linux/processor.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "common.h" #include "../common.h"
/* /*
* The shmem address is split into 4K page and offset. * The shmem address is split into 4K page and offset.
...@@ -69,23 +70,25 @@ struct scmi_smc { ...@@ -69,23 +70,25 @@ struct scmi_smc {
unsigned long cap_id; unsigned long cap_id;
}; };
static struct scmi_transport_core_operations *core;
static irqreturn_t smc_msg_done_isr(int irq, void *data) static irqreturn_t smc_msg_done_isr(int irq, void *data)
{ {
struct scmi_smc *scmi_info = data; struct scmi_smc *scmi_info = data;
scmi_rx_callback(scmi_info->cinfo, core->rx_callback(scmi_info->cinfo,
shmem_read_header(scmi_info->shmem), NULL); core->shmem->read_header(scmi_info->shmem), NULL);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static bool smc_chan_available(struct device_node *of_node, int idx) static bool smc_chan_available(struct device_node *of_node, int idx)
{ {
struct device_node *np = of_parse_phandle(of_node, "shmem", 0); struct device_node *np __free(device_node) =
of_parse_phandle(of_node, "shmem", 0);
if (!np) if (!np)
return false; return false;
of_node_put(np);
return true; return true;
} }
...@@ -130,9 +133,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, ...@@ -130,9 +133,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
struct device *cdev = cinfo->dev; struct device *cdev = cinfo->dev;
unsigned long cap_id = ULONG_MAX; unsigned long cap_id = ULONG_MAX;
struct scmi_smc *scmi_info; struct scmi_smc *scmi_info;
resource_size_t size; struct resource res = {};
struct resource res;
struct device_node *np;
u32 func_id; u32 func_id;
int ret; int ret;
...@@ -143,31 +144,16 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, ...@@ -143,31 +144,16 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
if (!scmi_info) if (!scmi_info)
return -ENOMEM; return -ENOMEM;
np = of_parse_phandle(cdev->of_node, "shmem", 0); scmi_info->shmem = core->shmem->setup_iomap(cinfo, dev, tx, &res);
if (!of_device_is_compatible(np, "arm,scmi-shmem")) { if (IS_ERR(scmi_info->shmem))
of_node_put(np); return PTR_ERR(scmi_info->shmem);
return -ENXIO;
}
ret = of_address_to_resource(np, 0, &res);
of_node_put(np);
if (ret) {
dev_err(cdev, "failed to get SCMI Tx shared memory\n");
return ret;
}
size = resource_size(&res);
scmi_info->shmem = devm_ioremap(dev, res.start, size);
if (!scmi_info->shmem) {
dev_err(dev, "failed to ioremap SCMI Tx shared memory\n");
return -EADDRNOTAVAIL;
}
ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id); ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (of_device_is_compatible(dev->of_node, "qcom,scmi-smc")) { if (of_device_is_compatible(dev->of_node, "qcom,scmi-smc")) {
resource_size_t size = resource_size(&res);
void __iomem *ptr = (void __iomem *)scmi_info->shmem + size - 8; void __iomem *ptr = (void __iomem *)scmi_info->shmem + size - 8;
/* The capability-id is kept in last 8 bytes of shmem. /* The capability-id is kept in last 8 bytes of shmem.
* +-------+ <-- 0 * +-------+ <-- 0
...@@ -243,7 +229,7 @@ static int smc_send_message(struct scmi_chan_info *cinfo, ...@@ -243,7 +229,7 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
*/ */
smc_channel_lock_acquire(scmi_info, xfer); smc_channel_lock_acquire(scmi_info, xfer);
shmem_tx_prepare(scmi_info->shmem, xfer, cinfo); core->shmem->tx_prepare(scmi_info->shmem, xfer, cinfo);
if (scmi_info->cap_id != ULONG_MAX) if (scmi_info->cap_id != ULONG_MAX)
arm_smccc_1_1_invoke(scmi_info->func_id, scmi_info->cap_id, 0, arm_smccc_1_1_invoke(scmi_info->func_id, scmi_info->cap_id, 0,
...@@ -267,7 +253,7 @@ static void smc_fetch_response(struct scmi_chan_info *cinfo, ...@@ -267,7 +253,7 @@ static void smc_fetch_response(struct scmi_chan_info *cinfo,
{ {
struct scmi_smc *scmi_info = cinfo->transport_info; struct scmi_smc *scmi_info = cinfo->transport_info;
shmem_fetch_response(scmi_info->shmem, xfer); core->shmem->fetch_response(scmi_info->shmem, xfer);
} }
static void smc_mark_txdone(struct scmi_chan_info *cinfo, int ret, static void smc_mark_txdone(struct scmi_chan_info *cinfo, int ret,
...@@ -287,7 +273,7 @@ static const struct scmi_transport_ops scmi_smc_ops = { ...@@ -287,7 +273,7 @@ static const struct scmi_transport_ops scmi_smc_ops = {
.fetch_response = smc_fetch_response, .fetch_response = smc_fetch_response,
}; };
const struct scmi_desc scmi_smc_desc = { static struct scmi_desc scmi_smc_desc = {
.ops = &scmi_smc_ops, .ops = &scmi_smc_ops,
.max_rx_timeout_ms = 30, .max_rx_timeout_ms = 30,
.max_msg = 20, .max_msg = 20,
...@@ -303,3 +289,19 @@ const struct scmi_desc scmi_smc_desc = { ...@@ -303,3 +289,19 @@ const struct scmi_desc scmi_smc_desc = {
.sync_cmds_completed_on_ret = true, .sync_cmds_completed_on_ret = true,
.atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE), .atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE),
}; };
static const struct of_device_id scmi_of_match[] = {
{ .compatible = "arm,scmi-smc" },
{ .compatible = "arm,scmi-smc-param" },
{ .compatible = "qcom,scmi-smc" },
{ /* Sentinel */ },
};
DEFINE_SCMI_TRANSPORT_DRIVER(scmi_smc, scmi_smc_driver, scmi_smc_desc,
scmi_of_match, core);
module_platform_driver(scmi_smc_driver);
MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
MODULE_AUTHOR("Nikunj Kela <quic_nkela@quicinc.com>");
MODULE_DESCRIPTION("SCMI SMC Transport driver");
MODULE_LICENSE("GPL");
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* (SCMI). * (SCMI).
* *
* Copyright (C) 2020-2022 OpenSynergy. * Copyright (C) 2020-2022 OpenSynergy.
* Copyright (C) 2021-2022 ARM Ltd. * Copyright (C) 2021-2024 ARM Ltd.
*/ */
/** /**
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/refcount.h> #include <linux/refcount.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/virtio.h> #include <linux/virtio.h>
...@@ -27,7 +28,7 @@ ...@@ -27,7 +28,7 @@
#include <uapi/linux/virtio_ids.h> #include <uapi/linux/virtio_ids.h>
#include <uapi/linux/virtio_scmi.h> #include <uapi/linux/virtio_scmi.h>
#include "common.h" #include "../common.h"
#define VIRTIO_MAX_RX_TIMEOUT_MS 60000 #define VIRTIO_MAX_RX_TIMEOUT_MS 60000
#define VIRTIO_SCMI_MAX_MSG_SIZE 128 /* Value may be increased. */ #define VIRTIO_SCMI_MAX_MSG_SIZE 128 /* Value may be increased. */
...@@ -108,6 +109,8 @@ struct scmi_vio_msg { ...@@ -108,6 +109,8 @@ struct scmi_vio_msg {
refcount_t users; refcount_t users;
}; };
static struct scmi_transport_core_operations *core;
/* Only one SCMI VirtIO device can possibly exist */ /* Only one SCMI VirtIO device can possibly exist */
static struct virtio_device *scmi_vdev; static struct virtio_device *scmi_vdev;
...@@ -294,8 +297,9 @@ static void scmi_vio_complete_cb(struct virtqueue *vqueue) ...@@ -294,8 +297,9 @@ static void scmi_vio_complete_cb(struct virtqueue *vqueue)
if (msg) { if (msg) {
msg->rx_len = length; msg->rx_len = length;
scmi_rx_callback(vioch->cinfo, core->rx_callback(vioch->cinfo,
msg_read_header(msg->input), msg); core->msg->read_header(msg->input),
msg);
scmi_finalize_message(vioch, msg); scmi_finalize_message(vioch, msg);
} }
...@@ -339,8 +343,9 @@ static void scmi_vio_deferred_tx_worker(struct work_struct *work) ...@@ -339,8 +343,9 @@ static void scmi_vio_deferred_tx_worker(struct work_struct *work)
* is no more processed elsewhere so no poll_lock needed. * is no more processed elsewhere so no poll_lock needed.
*/ */
if (msg->poll_status == VIO_MSG_NOT_POLLED) if (msg->poll_status == VIO_MSG_NOT_POLLED)
scmi_rx_callback(vioch->cinfo, core->rx_callback(vioch->cinfo,
msg_read_header(msg->input), msg); core->msg->read_header(msg->input),
msg);
/* Free the processed message once done */ /* Free the processed message once done */
scmi_vio_msg_release(vioch, msg); scmi_vio_msg_release(vioch, msg);
...@@ -366,23 +371,6 @@ static unsigned int virtio_get_max_msg(struct scmi_chan_info *base_cinfo) ...@@ -366,23 +371,6 @@ static unsigned int virtio_get_max_msg(struct scmi_chan_info *base_cinfo)
return vioch->max_msg; return vioch->max_msg;
} }
static int virtio_link_supplier(struct device *dev)
{
if (!scmi_vdev) {
dev_notice(dev,
"Deferring probe after not finding a bound scmi-virtio device\n");
return -EPROBE_DEFER;
}
if (!device_link_add(dev, &scmi_vdev->dev,
DL_FLAG_AUTOREMOVE_CONSUMER)) {
dev_err(dev, "Adding link to supplier virtio device failed\n");
return -ECANCELED;
}
return 0;
}
static bool virtio_chan_available(struct device_node *of_node, int idx) static bool virtio_chan_available(struct device_node *of_node, int idx)
{ {
struct scmi_vio_channel *channels, *vioch = NULL; struct scmi_vio_channel *channels, *vioch = NULL;
...@@ -510,10 +498,10 @@ static int virtio_send_message(struct scmi_chan_info *cinfo, ...@@ -510,10 +498,10 @@ static int virtio_send_message(struct scmi_chan_info *cinfo,
return -EBUSY; return -EBUSY;
} }
msg_tx_prepare(msg->request, xfer); core->msg->tx_prepare(msg->request, xfer);
sg_init_one(&sg_out, msg->request, msg_command_size(xfer)); sg_init_one(&sg_out, msg->request, core->msg->command_size(xfer));
sg_init_one(&sg_in, msg->input, msg_response_size(xfer)); sg_init_one(&sg_in, msg->input, core->msg->response_size(xfer));
spin_lock_irqsave(&vioch->lock, flags); spin_lock_irqsave(&vioch->lock, flags);
...@@ -560,7 +548,7 @@ static void virtio_fetch_response(struct scmi_chan_info *cinfo, ...@@ -560,7 +548,7 @@ static void virtio_fetch_response(struct scmi_chan_info *cinfo,
struct scmi_vio_msg *msg = xfer->priv; struct scmi_vio_msg *msg = xfer->priv;
if (msg) if (msg)
msg_fetch_response(msg->input, msg->rx_len, xfer); core->msg->fetch_response(msg->input, msg->rx_len, xfer);
} }
static void virtio_fetch_notification(struct scmi_chan_info *cinfo, static void virtio_fetch_notification(struct scmi_chan_info *cinfo,
...@@ -569,7 +557,8 @@ static void virtio_fetch_notification(struct scmi_chan_info *cinfo, ...@@ -569,7 +557,8 @@ static void virtio_fetch_notification(struct scmi_chan_info *cinfo,
struct scmi_vio_msg *msg = xfer->priv; struct scmi_vio_msg *msg = xfer->priv;
if (msg) if (msg)
msg_fetch_notification(msg->input, msg->rx_len, max_len, xfer); core->msg->fetch_notification(msg->input, msg->rx_len,
max_len, xfer);
} }
/** /**
...@@ -669,7 +658,7 @@ static void virtio_mark_txdone(struct scmi_chan_info *cinfo, int ret, ...@@ -669,7 +658,7 @@ static void virtio_mark_txdone(struct scmi_chan_info *cinfo, int ret,
* the message we are polling for could be alternatively delivered via usual * the message we are polling for could be alternatively delivered via usual
* IRQs callbacks on another core which happened to have IRQs enabled while we * IRQs callbacks on another core which happened to have IRQs enabled while we
* are actively polling for it here: in such a case it will be handled as such * are actively polling for it here: in such a case it will be handled as such
* by scmi_rx_callback() and the polling loop in the SCMI Core TX path will be * by rx_callback() and the polling loop in the SCMI Core TX path will be
* transparently terminated anyway. * transparently terminated anyway.
* *
* Return: True once polling has successfully completed. * Return: True once polling has successfully completed.
...@@ -790,7 +779,6 @@ static bool virtio_poll_done(struct scmi_chan_info *cinfo, ...@@ -790,7 +779,6 @@ static bool virtio_poll_done(struct scmi_chan_info *cinfo,
} }
static const struct scmi_transport_ops scmi_virtio_ops = { static const struct scmi_transport_ops scmi_virtio_ops = {
.link_supplier = virtio_link_supplier,
.chan_available = virtio_chan_available, .chan_available = virtio_chan_available,
.chan_setup = virtio_chan_setup, .chan_setup = virtio_chan_setup,
.chan_free = virtio_chan_free, .chan_free = virtio_chan_free,
...@@ -802,6 +790,23 @@ static const struct scmi_transport_ops scmi_virtio_ops = { ...@@ -802,6 +790,23 @@ static const struct scmi_transport_ops scmi_virtio_ops = {
.poll_done = virtio_poll_done, .poll_done = virtio_poll_done,
}; };
static struct scmi_desc scmi_virtio_desc = {
.ops = &scmi_virtio_ops,
/* for non-realtime virtio devices */
.max_rx_timeout_ms = VIRTIO_MAX_RX_TIMEOUT_MS,
.max_msg = 0, /* overridden by virtio_get_max_msg() */
.max_msg_size = VIRTIO_SCMI_MAX_MSG_SIZE,
.atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE),
};
static const struct of_device_id scmi_of_match[] = {
{ .compatible = "arm,scmi-virtio" },
{ /* Sentinel */ },
};
DEFINE_SCMI_TRANSPORT_DRIVER(scmi_virtio, scmi_virtio_driver, scmi_virtio_desc,
scmi_of_match, core);
static int scmi_vio_probe(struct virtio_device *vdev) static int scmi_vio_probe(struct virtio_device *vdev)
{ {
struct device *dev = &vdev->dev; struct device *dev = &vdev->dev;
...@@ -861,14 +866,27 @@ static int scmi_vio_probe(struct virtio_device *vdev) ...@@ -861,14 +866,27 @@ static int scmi_vio_probe(struct virtio_device *vdev)
} }
vdev->priv = channels; vdev->priv = channels;
/* Ensure initialized scmi_vdev is visible */ /* Ensure initialized scmi_vdev is visible */
smp_store_mb(scmi_vdev, vdev); smp_store_mb(scmi_vdev, vdev);
ret = platform_driver_register(&scmi_virtio_driver);
if (ret) {
vdev->priv = NULL;
vdev->config->del_vqs(vdev);
/* Ensure NULLified scmi_vdev is visible */
smp_store_mb(scmi_vdev, NULL);
return ret;
}
return 0; return 0;
} }
static void scmi_vio_remove(struct virtio_device *vdev) static void scmi_vio_remove(struct virtio_device *vdev)
{ {
platform_driver_unregister(&scmi_virtio_driver);
/* /*
* Once we get here, virtio_chan_free() will have already been called by * Once we get here, virtio_chan_free() will have already been called by
* the SCMI core for any existing channel and, as a consequence, all the * the SCMI core for any existing channel and, as a consequence, all the
...@@ -913,23 +931,10 @@ static struct virtio_driver virtio_scmi_driver = { ...@@ -913,23 +931,10 @@ static struct virtio_driver virtio_scmi_driver = {
.validate = scmi_vio_validate, .validate = scmi_vio_validate,
}; };
static int __init virtio_scmi_init(void) module_virtio_driver(virtio_scmi_driver);
{
return register_virtio_driver(&virtio_scmi_driver);
}
static void virtio_scmi_exit(void)
{
unregister_virtio_driver(&virtio_scmi_driver);
}
const struct scmi_desc scmi_virtio_desc = { MODULE_AUTHOR("Igor Skalkin <igor.skalkin@opensynergy.com>");
.transport_init = virtio_scmi_init, MODULE_AUTHOR("Peter Hilber <peter.hilber@opensynergy.com>");
.transport_exit = virtio_scmi_exit, MODULE_AUTHOR("Cristian Marussi <cristian.marussi@arm.com>");
.ops = &scmi_virtio_ops, MODULE_DESCRIPTION("SCMI VirtIO Transport driver");
/* for non-realtime virtio devices */ MODULE_LICENSE("GPL");
.max_rx_timeout_ms = VIRTIO_MAX_RX_TIMEOUT_MS,
.max_msg = 0, /* overridden by virtio_get_max_msg() */
.max_msg_size = VIRTIO_SCMI_MAX_MSG_SIZE,
.atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE),
};
# SPDX-License-Identifier: GPL-2.0-only
menu "ARM SCMI NXP i.MX Vendor Protocols"
config IMX_SCMI_BBM_EXT
tristate "i.MX SCMI BBM EXTENSION"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
default y if ARCH_MXC
help
This enables i.MX System BBM control logic which supports RTC
and BUTTON.
To compile this driver as a module, choose M here: the
module will be called imx-sm-bbm.
config IMX_SCMI_MISC_EXT
tristate "i.MX SCMI MISC EXTENSION"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
default y if ARCH_MXC
help
This enables i.MX System MISC control logic such as gpio expander
wakeup
To compile this driver as a module, choose M here: the
module will be called imx-sm-misc.
endmenu
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_IMX_SCMI_BBM_EXT) += imx-sm-bbm.o
obj-$(CONFIG_IMX_SCMI_MISC_EXT) += imx-sm-misc.o
// SPDX-License-Identifier: GPL-2.0
/*
* System Control and Management Interface (SCMI) NXP BBM Protocol
*
* Copyright 2024 NXP
*/
#define pr_fmt(fmt) "SCMI Notifications BBM - " fmt
#include <linux/bits.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/scmi_protocol.h>
#include <linux/scmi_imx_protocol.h>
#include "../../protocols.h"
#include "../../notify.h"
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000
enum scmi_imx_bbm_protocol_cmd {
IMX_BBM_GPR_SET = 0x3,
IMX_BBM_GPR_GET = 0x4,
IMX_BBM_RTC_ATTRIBUTES = 0x5,
IMX_BBM_RTC_TIME_SET = 0x6,
IMX_BBM_RTC_TIME_GET = 0x7,
IMX_BBM_RTC_ALARM_SET = 0x8,
IMX_BBM_BUTTON_GET = 0x9,
IMX_BBM_RTC_NOTIFY = 0xA,
IMX_BBM_BUTTON_NOTIFY = 0xB,
};
#define GET_RTCS_NR(x) le32_get_bits((x), GENMASK(23, 16))
#define GET_GPRS_NR(x) le32_get_bits((x), GENMASK(15, 0))
#define SCMI_IMX_BBM_NOTIFY_RTC_UPDATED BIT(2)
#define SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER BIT(1)
#define SCMI_IMX_BBM_NOTIFY_RTC_ALARM BIT(0)
#define SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG BIT(0)
#define SCMI_IMX_BBM_NOTIFY_RTC_FLAG \
(SCMI_IMX_BBM_NOTIFY_RTC_UPDATED | SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER | \
SCMI_IMX_BBM_NOTIFY_RTC_ALARM)
#define SCMI_IMX_BBM_EVENT_RTC_MASK GENMASK(31, 24)
struct scmi_imx_bbm_info {
u32 version;
int nr_rtc;
int nr_gpr;
};
struct scmi_msg_imx_bbm_protocol_attributes {
__le32 attributes;
};
struct scmi_imx_bbm_set_time {
__le32 id;
__le32 flags;
__le32 value_low;
__le32 value_high;
};
struct scmi_imx_bbm_get_time {
__le32 id;
__le32 flags;
};
struct scmi_imx_bbm_alarm_time {
__le32 id;
__le32 flags;
__le32 value_low;
__le32 value_high;
};
struct scmi_msg_imx_bbm_rtc_notify {
__le32 rtc_id;
__le32 flags;
};
struct scmi_msg_imx_bbm_button_notify {
__le32 flags;
};
struct scmi_imx_bbm_notify_payld {
__le32 flags;
};
static int scmi_imx_bbm_attributes_get(const struct scmi_protocol_handle *ph,
struct scmi_imx_bbm_info *pi)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_imx_bbm_protocol_attributes *attr;
ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, sizeof(*attr), &t);
if (ret)
return ret;
attr = t->rx.buf;
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
pi->nr_rtc = GET_RTCS_NR(attr->attributes);
pi->nr_gpr = GET_GPRS_NR(attr->attributes);
}
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_bbm_notify(const struct scmi_protocol_handle *ph,
u32 src_id, int message_id, bool enable)
{
int ret;
struct scmi_xfer *t;
if (message_id == IMX_BBM_RTC_NOTIFY) {
struct scmi_msg_imx_bbm_rtc_notify *rtc_notify;
ret = ph->xops->xfer_get_init(ph, message_id,
sizeof(*rtc_notify), 0, &t);
if (ret)
return ret;
rtc_notify = t->tx.buf;
rtc_notify->rtc_id = cpu_to_le32(0);
rtc_notify->flags =
cpu_to_le32(enable ? SCMI_IMX_BBM_NOTIFY_RTC_FLAG : 0);
} else if (message_id == IMX_BBM_BUTTON_NOTIFY) {
struct scmi_msg_imx_bbm_button_notify *button_notify;
ret = ph->xops->xfer_get_init(ph, message_id,
sizeof(*button_notify), 0, &t);
if (ret)
return ret;
button_notify = t->tx.buf;
button_notify->flags = cpu_to_le32(enable ? 1 : 0);
} else {
return -EINVAL;
}
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static enum scmi_imx_bbm_protocol_cmd evt_2_cmd[] = {
IMX_BBM_RTC_NOTIFY,
IMX_BBM_BUTTON_NOTIFY
};
static int scmi_imx_bbm_set_notify_enabled(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret, cmd_id;
if (evt_id >= ARRAY_SIZE(evt_2_cmd))
return -EINVAL;
cmd_id = evt_2_cmd[evt_id];
ret = scmi_imx_bbm_notify(ph, src_id, cmd_id, enable);
if (ret)
pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
evt_id, src_id, ret);
return ret;
}
static void *scmi_imx_bbm_fill_custom_report(const struct scmi_protocol_handle *ph,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
{
const struct scmi_imx_bbm_notify_payld *p = payld;
struct scmi_imx_bbm_notif_report *r = report;
if (sizeof(*p) != payld_sz)
return NULL;
if (evt_id == SCMI_EVENT_IMX_BBM_RTC) {
r->is_rtc = true;
r->is_button = false;
r->timestamp = timestamp;
r->rtc_id = le32_get_bits(p->flags, SCMI_IMX_BBM_EVENT_RTC_MASK);
r->rtc_evt = le32_get_bits(p->flags, SCMI_IMX_BBM_NOTIFY_RTC_FLAG);
dev_dbg(ph->dev, "RTC: %d evt: %x\n", r->rtc_id, r->rtc_evt);
*src_id = r->rtc_evt;
} else if (evt_id == SCMI_EVENT_IMX_BBM_BUTTON) {
r->is_rtc = false;
r->is_button = true;
r->timestamp = timestamp;
dev_dbg(ph->dev, "BBM Button\n");
*src_id = 0;
} else {
WARN_ON_ONCE(1);
return NULL;
}
return r;
}
static const struct scmi_event scmi_imx_bbm_events[] = {
{
.id = SCMI_EVENT_IMX_BBM_RTC,
.max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld),
.max_report_sz = sizeof(struct scmi_imx_bbm_notif_report),
},
{
.id = SCMI_EVENT_IMX_BBM_BUTTON,
.max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld),
.max_report_sz = sizeof(struct scmi_imx_bbm_notif_report),
},
};
static const struct scmi_event_ops scmi_imx_bbm_event_ops = {
.set_notify_enabled = scmi_imx_bbm_set_notify_enabled,
.fill_custom_report = scmi_imx_bbm_fill_custom_report,
};
static const struct scmi_protocol_events scmi_imx_bbm_protocol_events = {
.queue_sz = SCMI_PROTO_QUEUE_SZ,
.ops = &scmi_imx_bbm_event_ops,
.evts = scmi_imx_bbm_events,
.num_events = ARRAY_SIZE(scmi_imx_bbm_events),
.num_sources = 1,
};
static int scmi_imx_bbm_rtc_time_set(const struct scmi_protocol_handle *ph,
u32 rtc_id, u64 sec)
{
struct scmi_imx_bbm_info *pi = ph->get_priv(ph);
struct scmi_imx_bbm_set_time *cfg;
struct scmi_xfer *t;
int ret;
if (rtc_id >= pi->nr_rtc)
return -EINVAL;
ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_SET, sizeof(*cfg), 0, &t);
if (ret)
return ret;
cfg = t->tx.buf;
cfg->id = cpu_to_le32(rtc_id);
cfg->flags = 0;
cfg->value_low = cpu_to_le32(lower_32_bits(sec));
cfg->value_high = cpu_to_le32(upper_32_bits(sec));
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_bbm_rtc_time_get(const struct scmi_protocol_handle *ph,
u32 rtc_id, u64 *value)
{
struct scmi_imx_bbm_info *pi = ph->get_priv(ph);
struct scmi_imx_bbm_get_time *cfg;
struct scmi_xfer *t;
int ret;
if (rtc_id >= pi->nr_rtc)
return -EINVAL;
ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_GET, sizeof(*cfg),
sizeof(u64), &t);
if (ret)
return ret;
cfg = t->tx.buf;
cfg->id = cpu_to_le32(rtc_id);
cfg->flags = 0;
ret = ph->xops->do_xfer(ph, t);
if (!ret)
*value = get_unaligned_le64(t->rx.buf);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_bbm_rtc_alarm_set(const struct scmi_protocol_handle *ph,
u32 rtc_id, bool enable, u64 sec)
{
struct scmi_imx_bbm_info *pi = ph->get_priv(ph);
struct scmi_imx_bbm_alarm_time *cfg;
struct scmi_xfer *t;
int ret;
if (rtc_id >= pi->nr_rtc)
return -EINVAL;
ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_ALARM_SET, sizeof(*cfg), 0, &t);
if (ret)
return ret;
cfg = t->tx.buf;
cfg->id = cpu_to_le32(rtc_id);
cfg->flags = enable ?
cpu_to_le32(SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG) : 0;
cfg->value_low = cpu_to_le32(lower_32_bits(sec));
cfg->value_high = cpu_to_le32(upper_32_bits(sec));
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_bbm_button_get(const struct scmi_protocol_handle *ph, u32 *state)
{
struct scmi_xfer *t;
int ret;
ret = ph->xops->xfer_get_init(ph, IMX_BBM_BUTTON_GET, 0, sizeof(u32), &t);
if (ret)
return ret;
ret = ph->xops->do_xfer(ph, t);
if (!ret)
*state = get_unaligned_le32(t->rx.buf);
ph->xops->xfer_put(ph, t);
return ret;
}
static const struct scmi_imx_bbm_proto_ops scmi_imx_bbm_proto_ops = {
.rtc_time_get = scmi_imx_bbm_rtc_time_get,
.rtc_time_set = scmi_imx_bbm_rtc_time_set,
.rtc_alarm_set = scmi_imx_bbm_rtc_alarm_set,
.button_get = scmi_imx_bbm_button_get,
};
static int scmi_imx_bbm_protocol_init(const struct scmi_protocol_handle *ph)
{
u32 version;
int ret;
struct scmi_imx_bbm_info *binfo;
ret = ph->xops->version_get(ph, &version);
if (ret)
return ret;
dev_info(ph->dev, "NXP SM BBM Version %d.%d\n",
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
binfo = devm_kzalloc(ph->dev, sizeof(*binfo), GFP_KERNEL);
if (!binfo)
return -ENOMEM;
ret = scmi_imx_bbm_attributes_get(ph, binfo);
if (ret)
return ret;
return ph->set_priv(ph, binfo, version);
}
static const struct scmi_protocol scmi_imx_bbm = {
.id = SCMI_PROTOCOL_IMX_BBM,
.owner = THIS_MODULE,
.instance_init = &scmi_imx_bbm_protocol_init,
.ops = &scmi_imx_bbm_proto_ops,
.events = &scmi_imx_bbm_protocol_events,
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
.vendor_id = "NXP",
.sub_vendor_id = "IMX",
};
module_scmi_protocol(scmi_imx_bbm);
MODULE_DESCRIPTION("i.MX SCMI BBM driver");
MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0
/*
* System control and Management Interface (SCMI) NXP MISC Protocol
*
* Copyright 2024 NXP
*/
#define pr_fmt(fmt) "SCMI Notifications MISC - " fmt
#include <linux/bits.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/scmi_protocol.h>
#include <linux/scmi_imx_protocol.h>
#include "../../protocols.h"
#include "../../notify.h"
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000
#define MAX_MISC_CTRL_SOURCES GENMASK(15, 0)
enum scmi_imx_misc_protocol_cmd {
SCMI_IMX_MISC_CTRL_SET = 0x3,
SCMI_IMX_MISC_CTRL_GET = 0x4,
SCMI_IMX_MISC_CTRL_NOTIFY = 0x8,
};
struct scmi_imx_misc_info {
u32 version;
u32 nr_dev_ctrl;
u32 nr_brd_ctrl;
u32 nr_reason;
};
struct scmi_msg_imx_misc_protocol_attributes {
__le32 attributes;
};
#define GET_BRD_CTRLS_NR(x) le32_get_bits((x), GENMASK(31, 24))
#define GET_REASONS_NR(x) le32_get_bits((x), GENMASK(23, 16))
#define GET_DEV_CTRLS_NR(x) le32_get_bits((x), GENMASK(15, 0))
#define BRD_CTRL_START_ID BIT(15)
struct scmi_imx_misc_ctrl_set_in {
__le32 id;
__le32 num;
__le32 value[];
};
struct scmi_imx_misc_ctrl_notify_in {
__le32 ctrl_id;
__le32 flags;
};
struct scmi_imx_misc_ctrl_notify_payld {
__le32 ctrl_id;
__le32 flags;
};
struct scmi_imx_misc_ctrl_get_out {
__le32 num;
__le32 val[];
};
static int scmi_imx_misc_attributes_get(const struct scmi_protocol_handle *ph,
struct scmi_imx_misc_info *mi)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_imx_misc_protocol_attributes *attr;
ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
sizeof(*attr), &t);
if (ret)
return ret;
attr = t->rx.buf;
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
mi->nr_dev_ctrl = GET_DEV_CTRLS_NR(attr->attributes);
mi->nr_brd_ctrl = GET_BRD_CTRLS_NR(attr->attributes);
mi->nr_reason = GET_REASONS_NR(attr->attributes);
dev_info(ph->dev, "i.MX MISC NUM DEV CTRL: %d, NUM BRD CTRL: %d,NUM Reason: %d\n",
mi->nr_dev_ctrl, mi->nr_brd_ctrl, mi->nr_reason);
}
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_misc_ctrl_validate_id(const struct scmi_protocol_handle *ph,
u32 ctrl_id)
{
struct scmi_imx_misc_info *mi = ph->get_priv(ph);
/*
* [0, BRD_CTRL_START_ID) is for Dev Ctrl which is SOC related
* [BRD_CTRL_START_ID, 0xffff) is for Board Ctrl which is board related
*/
if (ctrl_id < BRD_CTRL_START_ID && ctrl_id > mi->nr_dev_ctrl)
return -EINVAL;
if (ctrl_id >= BRD_CTRL_START_ID + mi->nr_brd_ctrl)
return -EINVAL;
return 0;
}
static int scmi_imx_misc_ctrl_notify(const struct scmi_protocol_handle *ph,
u32 ctrl_id, u32 evt_id, u32 flags)
{
struct scmi_imx_misc_ctrl_notify_in *in;
struct scmi_xfer *t;
int ret;
ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);
if (ret)
return ret;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_NOTIFY,
sizeof(*in), 0, &t);
if (ret)
return ret;
in = t->tx.buf;
in->ctrl_id = cpu_to_le32(ctrl_id);
in->flags = cpu_to_le32(flags);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int
scmi_imx_misc_ctrl_set_notify_enabled(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
/* misc_ctrl_req_notify is for enablement */
if (enable)
return 0;
ret = scmi_imx_misc_ctrl_notify(ph, src_id, evt_id, 0);
if (ret)
dev_err(ph->dev, "FAIL_ENABLED - evt[%X] src[%d] - ret:%d\n",
evt_id, src_id, ret);
return ret;
}
static void *
scmi_imx_misc_ctrl_fill_custom_report(const struct scmi_protocol_handle *ph,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
{
const struct scmi_imx_misc_ctrl_notify_payld *p = payld;
struct scmi_imx_misc_ctrl_notify_report *r = report;
if (sizeof(*p) != payld_sz)
return NULL;
r->timestamp = timestamp;
r->ctrl_id = le32_to_cpu(p->ctrl_id);
r->flags = le32_to_cpu(p->flags);
if (src_id)
*src_id = r->ctrl_id;
dev_dbg(ph->dev, "%s: ctrl_id: %d flags: %d\n", __func__,
r->ctrl_id, r->flags);
return r;
}
static const struct scmi_event_ops scmi_imx_misc_event_ops = {
.set_notify_enabled = scmi_imx_misc_ctrl_set_notify_enabled,
.fill_custom_report = scmi_imx_misc_ctrl_fill_custom_report,
};
static const struct scmi_event scmi_imx_misc_events[] = {
{
.id = SCMI_EVENT_IMX_MISC_CONTROL,
.max_payld_sz = sizeof(struct scmi_imx_misc_ctrl_notify_payld),
.max_report_sz = sizeof(struct scmi_imx_misc_ctrl_notify_report),
},
};
static struct scmi_protocol_events scmi_imx_misc_protocol_events = {
.queue_sz = SCMI_PROTO_QUEUE_SZ,
.ops = &scmi_imx_misc_event_ops,
.evts = scmi_imx_misc_events,
.num_events = ARRAY_SIZE(scmi_imx_misc_events),
.num_sources = MAX_MISC_CTRL_SOURCES,
};
static int scmi_imx_misc_ctrl_get(const struct scmi_protocol_handle *ph,
u32 ctrl_id, u32 *num, u32 *val)
{
struct scmi_imx_misc_ctrl_get_out *out;
struct scmi_xfer *t;
int ret, i;
int max_msg_size = ph->hops->get_max_msg_size(ph);
int max_num = (max_msg_size - sizeof(*out)) / sizeof(__le32);
ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);
if (ret)
return ret;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_GET, sizeof(u32),
0, &t);
if (ret)
return ret;
put_unaligned_le32(ctrl_id, t->tx.buf);
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
out = t->rx.buf;
*num = le32_to_cpu(out->num);
if (*num >= max_num ||
*num * sizeof(__le32) > t->rx.len - sizeof(__le32)) {
ph->xops->xfer_put(ph, t);
return -EINVAL;
}
for (i = 0; i < *num; i++)
val[i] = le32_to_cpu(out->val[i]);
}
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_misc_ctrl_set(const struct scmi_protocol_handle *ph,
u32 ctrl_id, u32 num, u32 *val)
{
struct scmi_imx_misc_ctrl_set_in *in;
struct scmi_xfer *t;
int ret, i;
int max_msg_size = ph->hops->get_max_msg_size(ph);
int max_num = (max_msg_size - sizeof(*in)) / sizeof(__le32);
ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);
if (ret)
return ret;
if (num > max_num)
return -EINVAL;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_SET, sizeof(*in),
0, &t);
if (ret)
return ret;
in = t->tx.buf;
in->id = cpu_to_le32(ctrl_id);
in->num = cpu_to_le32(num);
for (i = 0; i < num; i++)
in->value[i] = cpu_to_le32(val[i]);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static const struct scmi_imx_misc_proto_ops scmi_imx_misc_proto_ops = {
.misc_ctrl_set = scmi_imx_misc_ctrl_set,
.misc_ctrl_get = scmi_imx_misc_ctrl_get,
.misc_ctrl_req_notify = scmi_imx_misc_ctrl_notify,
};
static int scmi_imx_misc_protocol_init(const struct scmi_protocol_handle *ph)
{
struct scmi_imx_misc_info *minfo;
u32 version;
int ret;
ret = ph->xops->version_get(ph, &version);
if (ret)
return ret;
dev_info(ph->dev, "NXP SM MISC Version %d.%d\n",
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
minfo = devm_kzalloc(ph->dev, sizeof(*minfo), GFP_KERNEL);
if (!minfo)
return -ENOMEM;
ret = scmi_imx_misc_attributes_get(ph, minfo);
if (ret)
return ret;
return ph->set_priv(ph, minfo, version);
}
static const struct scmi_protocol scmi_imx_misc = {
.id = SCMI_PROTOCOL_IMX_MISC,
.owner = THIS_MODULE,
.instance_init = &scmi_imx_misc_protocol_init,
.ops = &scmi_imx_misc_proto_ops,
.events = &scmi_imx_misc_protocol_events,
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
.vendor_id = "NXP",
.sub_vendor_id = "IMX",
};
module_scmi_protocol(scmi_imx_misc);
MODULE_DESCRIPTION("i.MX SCMI MISC driver");
MODULE_LICENSE("GPL");
This diff is collapsed.
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include "protocols.h" #include "protocols.h"
/* Updated only after ALL the mandatory features for that version are merged */ /* Updated only after ALL the mandatory features for that version are merged */
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001
#define VOLTAGE_DOMS_NUM_MASK GENMASK(15, 0) #define VOLTAGE_DOMS_NUM_MASK GENMASK(15, 0)
#define REMAINING_LEVELS_MASK GENMASK(31, 16) #define REMAINING_LEVELS_MASK GENMASK(31, 16)
...@@ -229,8 +229,10 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph, ...@@ -229,8 +229,10 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
/* Retrieve domain attributes at first ... */ /* Retrieve domain attributes at first ... */
put_unaligned_le32(dom, td->tx.buf); put_unaligned_le32(dom, td->tx.buf);
/* Skip domain on comms error */ /* Skip domain on comms error */
if (ph->xops->do_xfer(ph, td)) if (ph->xops->do_xfer(ph, td)) {
ph->xops->reset_rx_to_maxsz(ph, td);
continue; continue;
}
v = vinfo->domains + dom; v = vinfo->domains + dom;
v->id = dom; v->id = dom;
......
...@@ -22,3 +22,14 @@ config IMX_SCU ...@@ -22,3 +22,14 @@ config IMX_SCU
This driver manages the IPC interface between host CPU and the This driver manages the IPC interface between host CPU and the
SCU firmware running on M4. SCU firmware running on M4.
config IMX_SCMI_MISC_DRV
tristate "IMX SCMI MISC Protocol driver"
depends on IMX_SCMI_MISC_EXT || COMPILE_TEST
default y if ARCH_MXC
help
The System Controller Management Interface firmware (SCMI FW) is
a low-level system function which runs on a dedicated Cortex-M
core that could provide misc functions such as board control.
This driver can also be built as a module.
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_IMX_DSP) += imx-dsp.o obj-$(CONFIG_IMX_DSP) += imx-dsp.o
obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o
obj-${CONFIG_IMX_SCMI_MISC_DRV} += sm-misc.o
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2024 NXP
*/
#include <linux/firmware/imx/sm.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/scmi_protocol.h>
#include <linux/scmi_imx_protocol.h>
static const struct scmi_imx_misc_proto_ops *imx_misc_ctrl_ops;
static struct scmi_protocol_handle *ph;
struct notifier_block scmi_imx_misc_ctrl_nb;
int scmi_imx_misc_ctrl_set(u32 id, u32 val)
{
if (!ph)
return -EPROBE_DEFER;
return imx_misc_ctrl_ops->misc_ctrl_set(ph, id, 1, &val);
};
EXPORT_SYMBOL(scmi_imx_misc_ctrl_set);
int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val)
{
if (!ph)
return -EPROBE_DEFER;
return imx_misc_ctrl_ops->misc_ctrl_get(ph, id, num, val);
}
EXPORT_SYMBOL(scmi_imx_misc_ctrl_get);
static int scmi_imx_misc_ctrl_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
/*
* notifier_chain_register requires a valid notifier_block and
* valid notifier_call. SCMI_EVENT_IMX_MISC_CONTROL is needed
* to let SCMI firmware enable control events, but the hook here
* is just a dummy function to avoid kernel panic as of now.
*/
return 0;
}
static int scmi_imx_misc_ctrl_probe(struct scmi_device *sdev)
{
const struct scmi_handle *handle = sdev->handle;
struct device_node *np = sdev->dev.of_node;
u32 src_id, flags;
int ret, i, num;
if (!handle)
return -ENODEV;
if (imx_misc_ctrl_ops) {
dev_err(&sdev->dev, "misc ctrl already initialized\n");
return -EEXIST;
}
imx_misc_ctrl_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_IMX_MISC, &ph);
if (IS_ERR(imx_misc_ctrl_ops))
return PTR_ERR(imx_misc_ctrl_ops);
num = of_property_count_u32_elems(np, "nxp,ctrl-ids");
if (num % 2) {
dev_err(&sdev->dev, "Invalid wakeup-sources\n");
return -EINVAL;
}
scmi_imx_misc_ctrl_nb.notifier_call = &scmi_imx_misc_ctrl_notifier;
for (i = 0; i < num; i += 2) {
ret = of_property_read_u32_index(np, "nxp,ctrl-ids", i, &src_id);
if (ret) {
dev_err(&sdev->dev, "Failed to read ctrl-id: %i\n", i);
continue;
}
ret = of_property_read_u32_index(np, "nxp,ctrl-ids", i + 1, &flags);
if (ret) {
dev_err(&sdev->dev, "Failed to read ctrl-id value: %d\n", i + 1);
continue;
}
ret = handle->notify_ops->devm_event_notifier_register(sdev, SCMI_PROTOCOL_IMX_MISC,
SCMI_EVENT_IMX_MISC_CONTROL,
&src_id,
&scmi_imx_misc_ctrl_nb);
if (ret) {
dev_err(&sdev->dev, "Failed to register scmi misc event: %d\n", src_id);
} else {
ret = imx_misc_ctrl_ops->misc_ctrl_req_notify(ph, src_id,
SCMI_EVENT_IMX_MISC_CONTROL,
flags);
if (ret)
dev_err(&sdev->dev, "Failed to req notify: %d\n", src_id);
}
}
return 0;
}
static const struct scmi_device_id scmi_id_table[] = {
{ SCMI_PROTOCOL_IMX_MISC, "imx-misc-ctrl" },
{ },
};
MODULE_DEVICE_TABLE(scmi, scmi_id_table);
static struct scmi_driver scmi_imx_misc_ctrl_driver = {
.name = "scmi-imx-misc-ctrl",
.probe = scmi_imx_misc_ctrl_probe,
.id_table = scmi_id_table,
};
module_scmi_driver(scmi_imx_misc_ctrl_driver);
MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
MODULE_DESCRIPTION("IMX SM MISC driver");
MODULE_LICENSE("GPL");
...@@ -41,17 +41,6 @@ config QCOM_TZMEM_MODE_SHMBRIDGE ...@@ -41,17 +41,6 @@ config QCOM_TZMEM_MODE_SHMBRIDGE
endchoice endchoice
config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
bool "Qualcomm download mode enabled by default"
depends on QCOM_SCM
help
A device with "download mode" enabled will upon an unexpected
warm-restart enter a special debug mode that allows the user to
"download" memory content over USB for offline postmortem analysis.
The feature can be enabled/disabled on the kernel command line.
Say Y here to enable "download mode" by default.
config QCOM_QSEECOM config QCOM_QSEECOM
bool "Qualcomm QSEECOM interface driver" bool "Qualcomm QSEECOM interface driver"
depends on QCOM_SCM=y depends on QCOM_SCM=y
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/interconnect.h> #include <linux/interconnect.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kstrtox.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
...@@ -32,8 +33,7 @@ ...@@ -32,8 +33,7 @@
#include "qcom_scm.h" #include "qcom_scm.h"
#include "qcom_tzmem.h" #include "qcom_tzmem.h"
static bool download_mode = IS_ENABLED(CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT); static u32 download_mode;
module_param(download_mode, bool, 0);
struct qcom_scm { struct qcom_scm {
struct device *dev; struct device *dev;
...@@ -126,6 +126,8 @@ static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = { ...@@ -126,6 +126,8 @@ static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
#define QCOM_DLOAD_MASK GENMASK(5, 4) #define QCOM_DLOAD_MASK GENMASK(5, 4)
#define QCOM_DLOAD_NODUMP 0 #define QCOM_DLOAD_NODUMP 0
#define QCOM_DLOAD_FULLDUMP 1 #define QCOM_DLOAD_FULLDUMP 1
#define QCOM_DLOAD_MINIDUMP 2
#define QCOM_DLOAD_BOTHDUMP 3
static const char * const qcom_scm_convention_names[] = { static const char * const qcom_scm_convention_names[] = {
[SMC_CONVENTION_UNKNOWN] = "unknown", [SMC_CONVENTION_UNKNOWN] = "unknown",
...@@ -134,6 +136,13 @@ static const char * const qcom_scm_convention_names[] = { ...@@ -134,6 +136,13 @@ static const char * const qcom_scm_convention_names[] = {
[SMC_CONVENTION_LEGACY] = "smc legacy", [SMC_CONVENTION_LEGACY] = "smc legacy",
}; };
static const char * const download_mode_name[] = {
[QCOM_DLOAD_NODUMP] = "off",
[QCOM_DLOAD_FULLDUMP] = "full",
[QCOM_DLOAD_MINIDUMP] = "mini",
[QCOM_DLOAD_BOTHDUMP] = "full,mini",
};
static struct qcom_scm *__scm; static struct qcom_scm *__scm;
static int qcom_scm_clk_enable(void) static int qcom_scm_clk_enable(void)
...@@ -526,17 +535,16 @@ static int qcom_scm_io_rmw(phys_addr_t addr, unsigned int mask, unsigned int val ...@@ -526,17 +535,16 @@ static int qcom_scm_io_rmw(phys_addr_t addr, unsigned int mask, unsigned int val
return qcom_scm_io_writel(addr, new); return qcom_scm_io_writel(addr, new);
} }
static void qcom_scm_set_download_mode(bool enable) static void qcom_scm_set_download_mode(u32 dload_mode)
{ {
u32 val = enable ? QCOM_DLOAD_FULLDUMP : QCOM_DLOAD_NODUMP;
int ret = 0; int ret = 0;
if (__scm->dload_mode_addr) { if (__scm->dload_mode_addr) {
ret = qcom_scm_io_rmw(__scm->dload_mode_addr, QCOM_DLOAD_MASK, ret = qcom_scm_io_rmw(__scm->dload_mode_addr, QCOM_DLOAD_MASK,
FIELD_PREP(QCOM_DLOAD_MASK, val)); FIELD_PREP(QCOM_DLOAD_MASK, dload_mode));
} else if (__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_BOOT, } else if (__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_BOOT,
QCOM_SCM_BOOT_SET_DLOAD_MODE)) { QCOM_SCM_BOOT_SET_DLOAD_MODE)) {
ret = __qcom_scm_set_dload_mode(__scm->dev, enable); ret = __qcom_scm_set_dload_mode(__scm->dev, !!dload_mode);
} else { } else {
dev_err(__scm->dev, dev_err(__scm->dev,
"No available mechanism for setting download mode\n"); "No available mechanism for setting download mode\n");
...@@ -1724,7 +1732,10 @@ EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_send); ...@@ -1724,7 +1732,10 @@ EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_send);
*/ */
static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = { static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = {
{ .compatible = "lenovo,flex-5g" }, { .compatible = "lenovo,flex-5g" },
{ .compatible = "lenovo,thinkpad-t14s" },
{ .compatible = "lenovo,thinkpad-x13s", }, { .compatible = "lenovo,thinkpad-x13s", },
{ .compatible = "microsoft,romulus13", },
{ .compatible = "microsoft,romulus15", },
{ .compatible = "qcom,sc8180x-primus" }, { .compatible = "qcom,sc8180x-primus" },
{ .compatible = "qcom,x1e80100-crd" }, { .compatible = "qcom,x1e80100-crd" },
{ .compatible = "qcom,x1e80100-qcp" }, { .compatible = "qcom,x1e80100-qcp" },
...@@ -1886,6 +1897,45 @@ static irqreturn_t qcom_scm_irq_handler(int irq, void *data) ...@@ -1886,6 +1897,45 @@ static irqreturn_t qcom_scm_irq_handler(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int get_download_mode(char *buffer, const struct kernel_param *kp)
{
if (download_mode >= ARRAY_SIZE(download_mode_name))
return sysfs_emit(buffer, "unknown mode\n");
return sysfs_emit(buffer, "%s\n", download_mode_name[download_mode]);
}
static int set_download_mode(const char *val, const struct kernel_param *kp)
{
bool tmp;
int ret;
ret = sysfs_match_string(download_mode_name, val);
if (ret < 0) {
ret = kstrtobool(val, &tmp);
if (ret < 0) {
pr_err("qcom_scm: err: %d\n", ret);
return ret;
}
ret = tmp ? 1 : 0;
}
download_mode = ret;
if (__scm)
qcom_scm_set_download_mode(download_mode);
return 0;
}
static const struct kernel_param_ops download_mode_param_ops = {
.get = get_download_mode,
.set = set_download_mode,
};
module_param_cb(download_mode, &download_mode_param_ops, NULL, 0644);
MODULE_PARM_DESC(download_mode, "download mode: off/0/N for no dump mode, full/on/1/Y for full dump mode, mini for minidump mode and full,mini for both full and minidump mode together are acceptable values");
static int qcom_scm_probe(struct platform_device *pdev) static int qcom_scm_probe(struct platform_device *pdev)
{ {
struct qcom_tzmem_pool_config pool_config; struct qcom_tzmem_pool_config pool_config;
...@@ -1950,18 +2000,16 @@ static int qcom_scm_probe(struct platform_device *pdev) ...@@ -1950,18 +2000,16 @@ static int qcom_scm_probe(struct platform_device *pdev)
__get_convention(); __get_convention();
/* /*
* If requested enable "download mode", from this point on warmboot * If "download mode" is requested, from this point on warmboot
* will cause the boot stages to enter download mode, unless * will cause the boot stages to enter download mode, unless
* disabled below by a clean shutdown/reboot. * disabled below by a clean shutdown/reboot.
*/ */
if (download_mode) qcom_scm_set_download_mode(download_mode);
qcom_scm_set_download_mode(true);
/* /*
* Disable SDI if indicated by DT that it is enabled by default. * Disable SDI if indicated by DT that it is enabled by default.
*/ */
if (of_property_read_bool(pdev->dev.of_node, "qcom,sdi-enabled")) if (of_property_read_bool(pdev->dev.of_node, "qcom,sdi-enabled") || !download_mode)
qcom_scm_disable_sdi(); qcom_scm_disable_sdi();
ret = of_reserved_mem_device_init(__scm->dev); ret = of_reserved_mem_device_init(__scm->dev);
...@@ -2003,7 +2051,7 @@ static int qcom_scm_probe(struct platform_device *pdev) ...@@ -2003,7 +2051,7 @@ static int qcom_scm_probe(struct platform_device *pdev)
static void qcom_scm_shutdown(struct platform_device *pdev) static void qcom_scm_shutdown(struct platform_device *pdev)
{ {
/* Clean shutdown, disable download mode to allow normal restart */ /* Clean shutdown, disable download mode to allow normal restart */
qcom_scm_set_download_mode(false); qcom_scm_set_download_mode(QCOM_DLOAD_NODUMP);
} }
static const struct of_device_id qcom_scm_dt_match[] = { static const struct of_device_id qcom_scm_dt_match[] = {
......
...@@ -62,7 +62,6 @@ rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data) ...@@ -62,7 +62,6 @@ rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data)
ret = 0; ret = 0;
} else { } else {
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
WARN_ONCE(1, "Firmware transaction timeout");
} }
} else { } else {
dev_err(fw->cl.dev, "mbox_send_message returned %d\n", ret); dev_err(fw->cl.dev, "mbox_send_message returned %d\n", ret);
...@@ -125,6 +124,8 @@ int rpi_firmware_property_list(struct rpi_firmware *fw, ...@@ -125,6 +124,8 @@ int rpi_firmware_property_list(struct rpi_firmware *fw,
dev_err(fw->cl.dev, "Request 0x%08x returned status 0x%08x\n", dev_err(fw->cl.dev, "Request 0x%08x returned status 0x%08x\n",
buf[2], buf[1]); buf[2], buf[1]);
ret = -EINVAL; ret = -EINVAL;
} else if (ret == -ETIMEDOUT) {
WARN_ONCE(1, "Firmware transaction 0x%08x timeout", buf[2]);
} }
dma_free_coherent(fw->chan->mbox->dev, PAGE_ALIGN(size), buf, bus_addr); dma_free_coherent(fw->chan->mbox->dev, PAGE_ALIGN(size), buf, bus_addr);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
*/ */
#include <linux/cleanup.h>
#include <linux/clk/tegra.h> #include <linux/clk/tegra.h>
#include <linux/genalloc.h> #include <linux/genalloc.h>
#include <linux/mailbox_client.h> #include <linux/mailbox_client.h>
...@@ -24,12 +25,6 @@ ...@@ -24,12 +25,6 @@
#define MSG_RING BIT(1) #define MSG_RING BIT(1)
#define TAG_SZ 32 #define TAG_SZ 32
static inline struct tegra_bpmp *
mbox_client_to_bpmp(struct mbox_client *client)
{
return container_of(client, struct tegra_bpmp, mbox.client);
}
static inline const struct tegra_bpmp_ops * static inline const struct tegra_bpmp_ops *
channel_to_ops(struct tegra_bpmp_channel *channel) channel_to_ops(struct tegra_bpmp_channel *channel)
{ {
...@@ -40,29 +35,24 @@ channel_to_ops(struct tegra_bpmp_channel *channel) ...@@ -40,29 +35,24 @@ channel_to_ops(struct tegra_bpmp_channel *channel)
struct tegra_bpmp *tegra_bpmp_get(struct device *dev) struct tegra_bpmp *tegra_bpmp_get(struct device *dev)
{ {
struct device_node *np __free(device_node);
struct platform_device *pdev; struct platform_device *pdev;
struct tegra_bpmp *bpmp; struct tegra_bpmp *bpmp;
struct device_node *np;
np = of_parse_phandle(dev->of_node, "nvidia,bpmp", 0); np = of_parse_phandle(dev->of_node, "nvidia,bpmp", 0);
if (!np) if (!np)
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
pdev = of_find_device_by_node(np); pdev = of_find_device_by_node(np);
if (!pdev) { if (!pdev)
bpmp = ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
goto put;
}
bpmp = platform_get_drvdata(pdev); bpmp = platform_get_drvdata(pdev);
if (!bpmp) { if (!bpmp) {
bpmp = ERR_PTR(-EPROBE_DEFER);
put_device(&pdev->dev); put_device(&pdev->dev);
goto put; return ERR_PTR(-EPROBE_DEFER);
} }
put:
of_node_put(np);
return bpmp; return bpmp;
} }
EXPORT_SYMBOL_GPL(tegra_bpmp_get); EXPORT_SYMBOL_GPL(tegra_bpmp_get);
......
This diff is collapsed.
...@@ -466,6 +466,17 @@ config KEYBOARD_IMX ...@@ -466,6 +466,17 @@ config KEYBOARD_IMX
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called imx_keypad. module will be called imx_keypad.
config KEYBOARD_IMX_BBM_SCMI
tristate "IMX BBM SCMI Key Driver"
depends on IMX_SCMI_BBM_EXT || COMPILE_TEST
default y if ARCH_MXC
help
This is the BBM key driver for NXP i.MX SoCs managed through
SCMI protocol.
To compile this driver as a module, choose M here: the
module will be called scmi-imx-bbm-key.
config KEYBOARD_IMX_SC_KEY config KEYBOARD_IMX_SC_KEY
tristate "IMX SCU Key Driver" tristate "IMX SCU Key Driver"
depends on IMX_SCU depends on IMX_SCU
......
...@@ -31,6 +31,7 @@ obj-$(CONFIG_KEYBOARD_IPAQ_MICRO) += ipaq-micro-keys.o ...@@ -31,6 +31,7 @@ obj-$(CONFIG_KEYBOARD_IPAQ_MICRO) += ipaq-micro-keys.o
obj-$(CONFIG_KEYBOARD_IQS62X) += iqs62x-keys.o obj-$(CONFIG_KEYBOARD_IQS62X) += iqs62x-keys.o
obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
obj-$(CONFIG_KEYBOARD_IMX_SC_KEY) += imx_sc_key.o obj-$(CONFIG_KEYBOARD_IMX_SC_KEY) += imx_sc_key.o
obj-$(CONFIG_KEYBOARD_IMX_BBM_SCMI) += imx-sm-bbm-key.o
obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
......
This diff is collapsed.
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com> * Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com>
*/ */
#include <linux/cleanup.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
...@@ -517,7 +518,7 @@ static int atmel_ebi_dev_disable(struct atmel_ebi *ebi, struct device_node *np) ...@@ -517,7 +518,7 @@ static int atmel_ebi_dev_disable(struct atmel_ebi *ebi, struct device_node *np)
static int atmel_ebi_probe(struct platform_device *pdev) static int atmel_ebi_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *child, *np = dev->of_node, *smc_np; struct device_node *np = dev->of_node;
struct atmel_ebi *ebi; struct atmel_ebi *ebi;
int ret, reg_cells; int ret, reg_cells;
struct clk *clk; struct clk *clk;
...@@ -541,30 +542,24 @@ static int atmel_ebi_probe(struct platform_device *pdev) ...@@ -541,30 +542,24 @@ static int atmel_ebi_probe(struct platform_device *pdev)
ebi->clk = clk; ebi->clk = clk;
smc_np = of_parse_phandle(dev->of_node, "atmel,smc", 0); struct device_node *smc_np __free(device_node) =
of_parse_phandle(dev->of_node, "atmel,smc", 0);
ebi->smc.regmap = syscon_node_to_regmap(smc_np); ebi->smc.regmap = syscon_node_to_regmap(smc_np);
if (IS_ERR(ebi->smc.regmap)) { if (IS_ERR(ebi->smc.regmap))
ret = PTR_ERR(ebi->smc.regmap); return PTR_ERR(ebi->smc.regmap);
goto put_node;
}
ebi->smc.layout = atmel_hsmc_get_reg_layout(smc_np); ebi->smc.layout = atmel_hsmc_get_reg_layout(smc_np);
if (IS_ERR(ebi->smc.layout)) { if (IS_ERR(ebi->smc.layout))
ret = PTR_ERR(ebi->smc.layout); return PTR_ERR(ebi->smc.layout);
goto put_node;
}
ebi->smc.clk = of_clk_get(smc_np, 0); ebi->smc.clk = of_clk_get(smc_np, 0);
if (IS_ERR(ebi->smc.clk)) { if (IS_ERR(ebi->smc.clk)) {
if (PTR_ERR(ebi->smc.clk) != -ENOENT) { if (PTR_ERR(ebi->smc.clk) != -ENOENT)
ret = PTR_ERR(ebi->smc.clk); return PTR_ERR(ebi->smc.clk);
goto put_node;
}
ebi->smc.clk = NULL; ebi->smc.clk = NULL;
} }
of_node_put(smc_np);
ret = clk_prepare_enable(ebi->smc.clk); ret = clk_prepare_enable(ebi->smc.clk);
if (ret) if (ret)
return ret; return ret;
...@@ -597,7 +592,7 @@ static int atmel_ebi_probe(struct platform_device *pdev) ...@@ -597,7 +592,7 @@ static int atmel_ebi_probe(struct platform_device *pdev)
reg_cells += val; reg_cells += val;
for_each_available_child_of_node(np, child) { for_each_available_child_of_node_scoped(np, child) {
if (!of_property_present(child, "reg")) if (!of_property_present(child, "reg"))
continue; continue;
...@@ -607,18 +602,12 @@ static int atmel_ebi_probe(struct platform_device *pdev) ...@@ -607,18 +602,12 @@ static int atmel_ebi_probe(struct platform_device *pdev)
child); child);
ret = atmel_ebi_dev_disable(ebi, child); ret = atmel_ebi_dev_disable(ebi, child);
if (ret) { if (ret)
of_node_put(child);
return ret; return ret;
}
} }
} }
return of_platform_populate(np, NULL, NULL, dev); return of_platform_populate(np, NULL, NULL, dev);
put_node:
of_node_put(smc_np);
return ret;
} }
static __maybe_unused int atmel_ebi_resume(struct device *dev) static __maybe_unused int atmel_ebi_resume(struct device *dev)
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* Aneesh V <aneesh@ti.com> * Aneesh V <aneesh@ti.com>
* Santosh Shilimkar <santosh.shilimkar@ti.com> * Santosh Shilimkar <santosh.shilimkar@ti.com>
*/ */
#include <linux/cleanup.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/reboot.h> #include <linux/reboot.h>
...@@ -57,7 +58,6 @@ struct emif_data { ...@@ -57,7 +58,6 @@ struct emif_data {
u8 temperature_level; u8 temperature_level;
u8 lpmode; u8 lpmode;
struct list_head node; struct list_head node;
unsigned long irq_state;
void __iomem *base; void __iomem *base;
struct device *dev; struct device *dev;
struct emif_regs *regs_cache[EMIF_MAX_NUM_FREQUENCIES]; struct emif_regs *regs_cache[EMIF_MAX_NUM_FREQUENCIES];
...@@ -69,7 +69,6 @@ struct emif_data { ...@@ -69,7 +69,6 @@ struct emif_data {
static struct emif_data *emif1; static struct emif_data *emif1;
static DEFINE_SPINLOCK(emif_lock); static DEFINE_SPINLOCK(emif_lock);
static unsigned long irq_state;
static LIST_HEAD(device_list); static LIST_HEAD(device_list);
static void do_emif_regdump_show(struct seq_file *s, struct emif_data *emif, static void do_emif_regdump_show(struct seq_file *s, struct emif_data *emif,
...@@ -523,18 +522,18 @@ static void setup_temperature_sensitive_regs(struct emif_data *emif, ...@@ -523,18 +522,18 @@ static void setup_temperature_sensitive_regs(struct emif_data *emif,
static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif) static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
{ {
u32 old_temp_level; u32 old_temp_level;
irqreturn_t ret = IRQ_HANDLED; irqreturn_t ret;
struct emif_custom_configs *custom_configs; struct emif_custom_configs *custom_configs;
spin_lock_irqsave(&emif_lock, irq_state); guard(spinlock_irqsave)(&emif_lock);
old_temp_level = emif->temperature_level; old_temp_level = emif->temperature_level;
get_temperature_level(emif); get_temperature_level(emif);
if (unlikely(emif->temperature_level == old_temp_level)) { if (unlikely(emif->temperature_level == old_temp_level)) {
goto out; return IRQ_HANDLED;
} else if (!emif->curr_regs) { } else if (!emif->curr_regs) {
dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n"); dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n");
goto out; return IRQ_HANDLED;
} }
custom_configs = emif->plat_data->custom_configs; custom_configs = emif->plat_data->custom_configs;
...@@ -554,8 +553,7 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif) ...@@ -554,8 +553,7 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
* from thread context * from thread context
*/ */
emif->temperature_level = SDRAM_TEMP_VERY_HIGH_SHUTDOWN; emif->temperature_level = SDRAM_TEMP_VERY_HIGH_SHUTDOWN;
ret = IRQ_WAKE_THREAD; return IRQ_WAKE_THREAD;
goto out;
} }
} }
...@@ -571,10 +569,9 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif) ...@@ -571,10 +569,9 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
/* Temperature is going up - handle immediately */ /* Temperature is going up - handle immediately */
setup_temperature_sensitive_regs(emif, emif->curr_regs); setup_temperature_sensitive_regs(emif, emif->curr_regs);
do_freq_update(); do_freq_update();
ret = IRQ_HANDLED;
} }
out:
spin_unlock_irqrestore(&emif_lock, irq_state);
return ret; return ret;
} }
...@@ -617,6 +614,7 @@ static irqreturn_t emif_interrupt_handler(int irq, void *dev_id) ...@@ -617,6 +614,7 @@ static irqreturn_t emif_interrupt_handler(int irq, void *dev_id)
static irqreturn_t emif_threaded_isr(int irq, void *dev_id) static irqreturn_t emif_threaded_isr(int irq, void *dev_id)
{ {
struct emif_data *emif = dev_id; struct emif_data *emif = dev_id;
unsigned long irq_state;
if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) { if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n"); dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n");
...@@ -864,7 +862,7 @@ static void of_get_custom_configs(struct device_node *np_emif, ...@@ -864,7 +862,7 @@ static void of_get_custom_configs(struct device_node *np_emif,
be32_to_cpup(poll_intvl); be32_to_cpup(poll_intvl);
} }
if (of_find_property(np_emif, "extended-temp-part", &len)) if (of_property_read_bool(np_emif, "extended-temp-part"))
cust_cfgs->mask |= EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART; cust_cfgs->mask |= EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART;
if (!is_custom_config_valid(cust_cfgs, emif->dev)) { if (!is_custom_config_valid(cust_cfgs, emif->dev)) {
...@@ -880,13 +878,9 @@ static void of_get_ddr_info(struct device_node *np_emif, ...@@ -880,13 +878,9 @@ static void of_get_ddr_info(struct device_node *np_emif,
struct ddr_device_info *dev_info) struct ddr_device_info *dev_info)
{ {
u32 density = 0, io_width = 0; u32 density = 0, io_width = 0;
int len;
if (of_find_property(np_emif, "cs1-used", &len)) dev_info->cs1_used = of_property_read_bool(np_emif, "cs1-used");
dev_info->cs1_used = true; dev_info->cal_resistors_per_cs = of_property_read_bool(np_emif, "cal-resistor-per-cs");
if (of_find_property(np_emif, "cal-resistor-per-cs", &len))
dev_info->cal_resistors_per_cs = true;
if (of_device_is_compatible(np_ddr, "jedec,lpddr2-s4")) if (of_device_is_compatible(np_ddr, "jedec,lpddr2-s4"))
dev_info->type = DDR_TYPE_LPDDR2_S4; dev_info->type = DDR_TYPE_LPDDR2_S4;
...@@ -916,7 +910,6 @@ static struct emif_data *of_get_memory_device_details( ...@@ -916,7 +910,6 @@ static struct emif_data *of_get_memory_device_details(
struct ddr_device_info *dev_info = NULL; struct ddr_device_info *dev_info = NULL;
struct emif_platform_data *pd = NULL; struct emif_platform_data *pd = NULL;
struct device_node *np_ddr; struct device_node *np_ddr;
int len;
np_ddr = of_parse_phandle(np_emif, "device-handle", 0); np_ddr = of_parse_phandle(np_emif, "device-handle", 0);
if (!np_ddr) if (!np_ddr)
...@@ -944,7 +937,7 @@ static struct emif_data *of_get_memory_device_details( ...@@ -944,7 +937,7 @@ static struct emif_data *of_get_memory_device_details(
of_property_read_u32(np_emif, "phy-type", &pd->phy_type); of_property_read_u32(np_emif, "phy-type", &pd->phy_type);
if (of_find_property(np_emif, "hw-caps-ll-interface", &len)) if (of_property_read_bool(np_emif, "hw-caps-ll-interface"))
pd->hw_caps |= EMIF_HW_CAPS_LL_INTERFACE; pd->hw_caps |= EMIF_HW_CAPS_LL_INTERFACE;
of_get_ddr_info(np_emif, np_ddr, dev_info); of_get_ddr_info(np_emif, np_ddr, dev_info);
......
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.
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