ARM: SoC drivers for 6.9

This is the usual mix of updates for drivers that are used on (mostly
 ARM) SoCs with no other top-level subsystem tree, including:
 
  - The SCMI firmware subsystem gains support for version 3.2 of the
    specification and updates to the notification code.
 
  - Feature updates for Tegra and Qualcomm platforms for added
    hardware support.
 
  - A number of platforms get soc_device additions for identifying newly
    added chips from Renesas, Qualcomm, Mediatek and Google.
 
  - Trivial improvements for firmware and memory drivers amongst
    others, in particular 'const' annotations throughout multiple
    subsystems.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEiK/NIGsWEZVxh/FrYKtH/8kJUicFAmXvgbsACgkQYKtH/8kJ
 UieH8Q/+LRzESrScIwFq0/V7lE1AadmhwMwcEf1Fsq8aMrelvPm/SWvHgIWIHTvV
 IZ/g3XS/CnBxr1JG3nbyMMe/2otEY7JxsUOOqixIuZ2gdzJvzZOBHMi54xDwbFRx
 4NbP0CRTy8K35XNnOkJO3TnwBFP+q2Fu6qHY90as8M2GIxQpWb8OONJHh8N2qPq+
 Hi3H0jjKXMInnOKpNIEQI60N4F2djGMHWkDySwFtHu40RaJjCIfmVd3PWQGz7RHl
 WQHjZ6CB+/BDgqfG0ccQ7Cikc4BLorZsjKCn8bsaLtdp4HvRCTp2ZpuFFTRq6vay
 IxqJCXrgpKjM1k9plehObEhMv4lNMbD1djG8Y6hqC+PPKbDfOLvlcat3xUK2AGgb
 ROJtKDQMXfAeSnLpw9n4Ox+BZRmwMIOcTU/20N72hlcZKY1jq/KuSqQn+LPVKIrW
 pJIhWd1B8R+2O1TewuIe3fjvfQwgATMBHBUVNRkSrzqkpcZNGQ3M5koMpClVvY6T
 Z/+hdAg58EQw0K6ukJLyrevxs1pHHhYXLCECIoU/xPs4NX4hDk7rKTFv6fdLS4Y2
 24qzjhIGYdhRXmhRQdVq+06cr3cvtm1z7Fqna3tW1+J6wtBnHO/xZ63M9n5saPcm
 NgKMAN7YLLMYuUNrd39W7U2wLGQCgknjhrbH8ZmxPypk467v08k=
 =bV/K
 -----END PGP SIGNATURE-----

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

Pull ARM SoC driver updates from Arnd Bergmann:
 "This is the usual mix of updates for drivers that are used on (mostly
  ARM) SoCs with no other top-level subsystem tree, including:

   - The SCMI firmware subsystem gains support for version 3.2 of the
     specification and updates to the notification code

   - Feature updates for Tegra and Qualcomm platforms for added hardware
     support

   - A number of platforms get soc_device additions for identifying
     newly added chips from Renesas, Qualcomm, Mediatek and Google

   - Trivial improvements for firmware and memory drivers amongst
     others, in particular 'const' annotations throughout multiple
     subsystems"

* tag 'soc-drivers-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (96 commits)
  tee: make tee_bus_type const
  soc: qcom: aoss: add missing kerneldoc for qmp members
  soc: qcom: geni-se: drop unused kerneldoc struct geni_wrapper param
  soc: qcom: spm: fix building with CONFIG_REGULATOR=n
  bus: ti-sysc: constify the struct device_type usage
  memory: stm32-fmc2-ebi: keep power domain on
  memory: stm32-fmc2-ebi: add MP25 RIF support
  memory: stm32-fmc2-ebi: add MP25 support
  memory: stm32-fmc2-ebi: check regmap_read return value
  dt-bindings: memory-controller: st,stm32: add MP25 support
  dt-bindings: bus: imx-weim: convert to YAML
  watchdog: s3c2410_wdt: use exynos_get_pmu_regmap_by_phandle() for PMU regs
  soc: samsung: exynos-pmu: Add regmap support for SoCs that protect PMU regs
  MAINTAINERS: Update SCMI entry with HWMON driver
  MAINTAINERS: samsung: gs101: match patches touching Google Tensor SoC
  memory: tegra: Fix indentation
  memory: tegra: Add BPMP and ICC info for DLA clients
  memory: tegra: Correct DLA client names
  dt-bindings: memory: renesas,rpc-if: Document R-Car V4M support
  firmware: arm_scmi: Update the supported clock protocol version
  ...
This commit is contained in:
Linus Torvalds 2024-03-12 10:35:24 -07:00
commit 2184dbcde4
83 changed files with 3170 additions and 540 deletions

View File

@ -1,58 +0,0 @@
SPM AVS Wrapper 2 (SAW2)
The SAW2 is a wrapper around the Subsystem Power Manager (SPM) and the
Adaptive Voltage Scaling (AVS) hardware. The SPM is a programmable
power-controller that transitions a piece of hardware (like a processor or
subsystem) into and out of low power modes via a direct connection to
the PMIC. It can also be wired up to interact with other processors in the
system, notifying them when a low power state is entered or exited.
Multiple revisions of the SAW hardware are supported using these Device Nodes.
SAW2 revisions differ in the register offset and configuration data. Also, the
same revision of the SAW in different SoCs may have different configuration
data due the differences in hardware capabilities. Hence the SoC name, the
version of the SAW hardware in that SoC and the distinction between cpu (big
or Little) or cache, may be needed to uniquely identify the SAW register
configuration and initialization data. The compatible string is used to
indicate this parameter.
PROPERTIES
- compatible:
Usage: required
Value type: <string>
Definition: Must have
"qcom,saw2"
A more specific value could be one of:
"qcom,apq8064-saw2-v1.1-cpu"
"qcom,msm8226-saw2-v2.1-cpu"
"qcom,msm8974-saw2-v2.1-cpu"
"qcom,apq8084-saw2-v2.1-cpu"
- reg:
Usage: required
Value type: <prop-encoded-array>
Definition: the first element specifies the base address and size of
the register region. An optional second element specifies
the base address and size of the alias register region.
- regulator:
Usage: optional
Value type: boolean
Definition: Indicates that this SPM device acts as a regulator device
device for the core (CPU or Cache) the SPM is attached
to.
Example 1:
power-controller@2099000 {
compatible = "qcom,saw2";
reg = <0x02099000 0x1000>, <0x02009000 0x1000>;
regulator;
};
Example 2:
saw0: power-controller@f9089000 {
compatible = "qcom,apq8084-saw2-v2.1-cpu", "qcom,saw2";
reg = <0xf9089000 0x1000>, <0xf9009000 0x1000>;
};

View File

@ -1,117 +0,0 @@
Device tree bindings for i.MX Wireless External Interface Module (WEIM)
The term "wireless" does not imply that the WEIM is literally an interface
without wires. It simply means that this module was originally designed for
wireless and mobile applications that use low-power technology.
The actual devices are instantiated from the child nodes of a WEIM node.
Required properties:
- compatible: Should contain one of the following:
"fsl,imx1-weim"
"fsl,imx27-weim"
"fsl,imx51-weim"
"fsl,imx50-weim"
"fsl,imx6q-weim"
- reg: A resource specifier for the register space
(see the example below)
- clocks: the clock, see the example below.
- #address-cells: Must be set to 2 to allow memory address translation
- #size-cells: Must be set to 1 to allow CS address passing
- ranges: Must be set up to reflect the memory layout with four
integer values for each chip-select line in use:
<cs-number> 0 <physical address of mapping> <size>
Optional properties:
- fsl,weim-cs-gpr: For "fsl,imx50-weim" and "fsl,imx6q-weim" type of
devices, it should be the phandle to the system General
Purpose Register controller that contains WEIM CS GPR
register, e.g. IOMUXC_GPR1 on i.MX6Q. IOMUXC_GPR1[11:0]
should be set up as one of the following 4 possible
values depending on the CS space configuration.
IOMUXC_GPR1[11:0] CS0 CS1 CS2 CS3
---------------------------------------------
05 128M 0M 0M 0M
033 64M 64M 0M 0M
0113 64M 32M 32M 0M
01111 32M 32M 32M 32M
In case that the property is absent, the reset value or
what bootloader sets up in IOMUXC_GPR1[11:0] will be
used.
- fsl,burst-clk-enable For "fsl,imx50-weim" and "fsl,imx6q-weim" type of
devices, the presence of this property indicates that
the weim bus should operate in Burst Clock Mode.
- fsl,continuous-burst-clk Make Burst Clock to output continuous clock.
Without this option Burst Clock will output clock
only when necessary. This takes effect only if
"fsl,burst-clk-enable" is set.
Timing property for child nodes. It is mandatory, not optional.
- fsl,weim-cs-timing: The timing array, contains timing values for the
child node. We get the CS indexes from the address
ranges in the child node's "reg" property.
The number of registers depends on the selected chip:
For i.MX1, i.MX21 ("fsl,imx1-weim") there are two
registers: CSxU, CSxL.
For i.MX25, i.MX27, i.MX31 and i.MX35 ("fsl,imx27-weim")
there are three registers: CSCRxU, CSCRxL, CSCRxA.
For i.MX50, i.MX53 ("fsl,imx50-weim"),
i.MX51 ("fsl,imx51-weim") and i.MX6Q ("fsl,imx6q-weim")
there are six registers: CSxGCR1, CSxGCR2, CSxRCR1,
CSxRCR2, CSxWCR1, CSxWCR2.
Example for an imx6q-sabreauto board, the NOR flash connected to the WEIM:
weim: weim@21b8000 {
compatible = "fsl,imx6q-weim";
reg = <0x021b8000 0x4000>;
clocks = <&clks 196>;
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0x08000000 0x08000000>;
fsl,weim-cs-gpr = <&gpr>;
nor@0,0 {
compatible = "cfi-flash";
reg = <0 0 0x02000000>;
#address-cells = <1>;
#size-cells = <1>;
bank-width = <2>;
fsl,weim-cs-timing = <0x00620081 0x00000001 0x1c022000
0x0000c000 0x1404a38e 0x00000000>;
};
};
Example for an imx6q-based board, a multi-chipselect device connected to WEIM:
In this case, both chip select 0 and 1 will be configured with the same timing
array values.
weim: weim@21b8000 {
compatible = "fsl,imx6q-weim";
reg = <0x021b8000 0x4000>;
clocks = <&clks 196>;
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0x08000000 0x02000000
1 0 0x0a000000 0x02000000
2 0 0x0c000000 0x02000000
3 0 0x0e000000 0x02000000>;
fsl,weim-cs-gpr = <&gpr>;
acme@0 {
compatible = "acme,whatever";
reg = <0 0 0x100>, <0 0x400000 0x800>,
<1 0x400000 0x800>;
fsl,weim-cs-timing = <0x024400b1 0x00001010 0x20081100
0x00000000 0xa0000240 0x00000000>;
};
};

View File

@ -33,6 +33,7 @@ properties:
- const: samsung,exynos7-hsi2c
- items:
- enum:
- google,gs101-hsi2c
- samsung,exynos850-hsi2c
- const: samsung,exynosautov9-hsi2c
- const: samsung,exynos5-hsi2c # Exynos5250 and Exynos5420

View File

@ -0,0 +1,31 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/fsl/fsl,imx-weim-peripherals.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: i.MX WEIM Bus Peripheral Nodes
maintainers:
- Shawn Guo <shawnguo@kernel.org>
- Sascha Hauer <s.hauer@pengutronix.de>
description:
This binding is meant for the child nodes of the WEIM node. The node
represents any device connected to the WEIM bus. It may be a Flash chip,
RAM chip or Ethernet controller, etc. These properties are meant for
configuring the WEIM settings/timings and will accompany the bindings
supported by the respective device.
properties:
reg: true
fsl,weim-cs-timing:
$ref: /schemas/types.yaml#/definitions/uint32-array
description:
Timing values for the child node.
minItems: 2
maxItems: 6
# the WEIM child will have its own native properties
additionalProperties: true

View File

@ -0,0 +1,204 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/fsl/fsl,imx-weim.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: i.MX Wireless External Interface Module (WEIM)
maintainers:
- Shawn Guo <shawnguo@kernel.org>
- Sascha Hauer <s.hauer@pengutronix.de>
description:
The term "wireless" does not imply that the WEIM is literally an interface
without wires. It simply means that this module was originally designed for
wireless and mobile applications that use low-power technology. The actual
devices are instantiated from the child nodes of a WEIM node.
properties:
$nodename:
pattern: "^memory-controller@[0-9a-f]+$"
compatible:
oneOf:
- enum:
- fsl,imx1-weim
- fsl,imx27-weim
- fsl,imx50-weim
- fsl,imx51-weim
- fsl,imx6q-weim
- items:
- enum:
- fsl,imx31-weim
- fsl,imx35-weim
- const: fsl,imx27-weim
- items:
- enum:
- fsl,imx6sx-weim
- fsl,imx6ul-weim
- const: fsl,imx6q-weim
"#address-cells":
const: 2
"#size-cells":
const: 1
reg:
maxItems: 1
clocks:
maxItems: 1
interrupts:
maxItems: 1
ranges: true
fsl,weim-cs-gpr:
$ref: /schemas/types.yaml#/definitions/phandle
description: |
Phandle to the system General Purpose Register controller that contains
WEIM CS GPR register, e.g. IOMUXC_GPR1 on i.MX6Q. IOMUXC_GPR1[11:0]
should be set up as one of the following 4 possible values depending on
the CS space configuration.
IOMUXC_GPR1[11:0] CS0 CS1 CS2 CS3
---------------------------------------------
05 128M 0M 0M 0M
033 64M 64M 0M 0M
0113 64M 32M 32M 0M
01111 32M 32M 32M 32M
In case that the property is absent, the reset value or what bootloader
sets up in IOMUXC_GPR1[11:0] will be used.
fsl,burst-clk-enable:
type: boolean
description:
The presence of this property indicates that the weim bus should operate
in Burst Clock Mode.
fsl,continuous-burst-clk:
type: boolean
description:
Make Burst Clock to output continuous clock. Without this option Burst
Clock will output clock only when necessary.
patternProperties:
"^.*@[0-7],[0-9a-f]+$":
type: object
description: Devices attached to chip selects are represented as subnodes.
$ref: fsl,imx-weim-peripherals.yaml
additionalProperties: true
required:
- fsl,weim-cs-timing
required:
- compatible
- reg
- clocks
- "#address-cells"
- "#size-cells"
- ranges
allOf:
- if:
properties:
compatible:
not:
contains:
enum:
- fsl,imx50-weim
- fsl,imx6q-weim
then:
properties:
fsl,weim-cs-gpr: false
fsl,burst-clk-enable: false
- if:
not:
required:
- fsl,burst-clk-enable
then:
properties:
fsl,continuous-burst-clk: false
- if:
properties:
compatible:
contains:
const: fsl,imx1-weim
then:
patternProperties:
"^.*@[0-7],[0-9a-f]+$":
properties:
fsl,weim-cs-timing:
items:
items:
- description: CSxU
- description: CSxL
- if:
properties:
compatible:
contains:
enum:
- fsl,imx27-weim
- fsl,imx31-weim
- fsl,imx35-weim
then:
patternProperties:
"^.*@[0-7],[0-9a-f]+$":
properties:
fsl,weim-cs-timing:
items:
items:
- description: CSCRxU
- description: CSCRxL
- description: CSCRxA
- if:
properties:
compatible:
contains:
enum:
- fsl,imx50-weim
- fsl,imx51-weim
- fsl,imx6q-weim
- fsl,imx6sx-weim
- fsl,imx6ul-weim
then:
patternProperties:
"^.*@[0-7],[0-9a-f]+$":
properties:
fsl,weim-cs-timing:
items:
items:
- description: CSxGCR1
- description: CSxGCR2
- description: CSxRCR1
- description: CSxRCR2
- description: CSxWCR1
- description: CSxWCR2
additionalProperties: false
examples:
- |
memory-controller@21b8000 {
compatible = "fsl,imx6q-weim";
reg = <0x021b8000 0x4000>;
clocks = <&clks 196>;
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0x08000000 0x08000000>;
fsl,weim-cs-gpr = <&gpr>;
flash@0,0 {
compatible = "cfi-flash";
reg = <0 0 0x02000000>;
#address-cells = <1>;
#size-cells = <1>;
bank-width = <2>;
fsl,weim-cs-timing = <0x00620081 0x00000001 0x1c022000
0x0000c000 0x1404a38e 0x00000000>;
};
};

View File

@ -37,5 +37,6 @@ allOf:
- $ref: ingenic,nemc-peripherals.yaml#
- $ref: intel,ixp4xx-expansion-peripheral-props.yaml#
- $ref: ti,gpmc-child.yaml#
- $ref: fsl/fsl,imx-weim-peripherals.yaml
additionalProperties: true

View File

@ -145,7 +145,7 @@ patternProperties:
"^emc-table@[0-9]+$":
$ref: "#/$defs/emc-table"
"^emc-tables@[a-z0-9-]+$":
"^emc-tables@[a-f0-9-]+$":
type: object
properties:
reg:

View File

@ -45,6 +45,7 @@ properties:
- items:
- enum:
- renesas,r8a779g0-rpc-if # R-Car V4H
- renesas,r8a779h0-rpc-if # R-Car V4M
- const: renesas,rcar-gen4-rpc-if # a generic R-Car gen4 device
- items:

View File

@ -23,7 +23,9 @@ maintainers:
properties:
compatible:
const: st,stm32mp1-fmc2-ebi
enum:
- st,stm32mp1-fmc2-ebi
- st,stm32mp25-fmc2-ebi
reg:
maxItems: 1
@ -34,6 +36,9 @@ properties:
resets:
maxItems: 1
power-domains:
maxItems: 1
"#address-cells":
const: 2

View File

@ -0,0 +1,46 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/soc/qcom/qcom,pbs.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Technologies, Inc. Programmable Boot Sequencer
maintainers:
- Anjelique Melendez <quic_amelende@quicinc.com>
description: |
The Qualcomm Technologies, Inc. Programmable Boot Sequencer (PBS)
supports triggering power up and power down sequences for clients
upon request.
properties:
compatible:
items:
- enum:
- qcom,pmi632-pbs
- const: qcom,pbs
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/spmi/spmi.h>
pmic@0 {
reg = <0x0 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
pbs@7400 {
compatible = "qcom,pmi632-pbs", "qcom,pbs";
reg = <0x7400>;
};
};

View File

@ -32,6 +32,7 @@ properties:
- items:
- enum:
- qcom,sm8650-pmic-glink
- qcom,x1e80100-pmic-glink
- const: qcom,sm8550-pmic-glink
- const: qcom,pmic-glink
@ -65,6 +66,7 @@ allOf:
enum:
- qcom,sm8450-pmic-glink
- qcom,sm8550-pmic-glink
- qcom,x1e80100-pmic-glink
then:
properties:
orientation-gpios: false

View File

@ -35,6 +35,8 @@ properties:
description: Phandle to an RPM MSG RAM slice containing the master stats
minItems: 1
maxItems: 5
items:
maxItems: 1
qcom,master-names:
$ref: /schemas/types.yaml#/definitions/string-array

View File

@ -1,23 +1,33 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/soc/qcom/qcom,spm.yaml#
$id: http://devicetree.org/schemas/soc/qcom/qcom,saw2.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Subsystem Power Manager
title: Qualcomm Subsystem Power Manager / SPM AVS Wrapper 2 (SAW2)
maintainers:
- Andy Gross <agross@kernel.org>
- Bjorn Andersson <bjorn.andersson@linaro.org>
description: |
This binding describes the Qualcomm Subsystem Power Manager, used to control
the peripheral logic surrounding the application cores in Qualcomm platforms.
The Qualcomm Subsystem Power Manager is used to control the peripheral logic
surrounding the application cores in Qualcomm platforms.
The SAW2 is a wrapper around the Subsystem Power Manager (SPM) and the
Adaptive Voltage Scaling (AVS) hardware. The SPM is a programmable
power-controller that transitions a piece of hardware (like a processor or
subsystem) into and out of low power modes via a direct connection to
the PMIC. It can also be wired up to interact with other processors in the
system, notifying them when a low power state is entered or exited.
properties:
compatible:
items:
- enum:
- qcom,ipq4019-saw2-cpu
- qcom,ipq4019-saw2-l2
- qcom,ipq8064-saw2-cpu
- qcom,sdm660-gold-saw2-v4.1-l2
- qcom,sdm660-silver-saw2-v4.1-l2
- qcom,msm8998-gold-saw2-v4.1-l2
@ -26,16 +36,27 @@ properties:
- qcom,msm8916-saw2-v3.0-cpu
- qcom,msm8939-saw2-v3.0-cpu
- qcom,msm8226-saw2-v2.1-cpu
- qcom,msm8226-saw2-v2.1-l2
- qcom,msm8960-saw2-cpu
- qcom,msm8974-saw2-v2.1-cpu
- qcom,msm8974-saw2-v2.1-l2
- qcom,msm8976-gold-saw2-v2.3-l2
- qcom,msm8976-silver-saw2-v2.3-l2
- qcom,apq8084-saw2-v2.1-cpu
- qcom,apq8084-saw2-v2.1-l2
- qcom,apq8064-saw2-v1.1-cpu
- const: qcom,saw2
reg:
description: Base address and size of the SPM register region
maxItems: 1
items:
- description: Base address and size of the SPM register region
- description: Base address and size of the alias register region
minItems: 1
regulator:
$ref: /schemas/regulator/regulator.yaml#
description: Indicates that this SPM device acts as a regulator device
device for the core (CPU or Cache) the SPM is attached to.
required:
- compatible
@ -82,4 +103,17 @@ examples:
reg = <0x17912000 0x1000>;
};
- |
/*
* Example 3: SAW2 with the bundled regulator definition.
*/
power-manager@2089000 {
compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2";
reg = <0x02089000 0x1000>, <0x02009000 0x1000>;
regulator {
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1300000>;
};
};
...

View File

@ -72,6 +72,8 @@ allOf:
compatible:
contains:
enum:
- google,gs101-peric0-sysreg
- google,gs101-peric1-sysreg
- samsung,exynos850-cmgp-sysreg
- samsung,exynos850-peri-sysreg
- samsung,exynos850-sysreg

View File

@ -9091,6 +9091,7 @@ F: Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
F: arch/arm64/boot/dts/exynos/google/
F: drivers/clk/samsung/clk-gs101.c
F: include/dt-bindings/clock/google,gs101.h
K: [gG]oogle.?[tT]ensor
GPD POCKET FAN DRIVER
M: Hans de Goede <hdegoede@redhat.com>
@ -17369,7 +17370,6 @@ F: Documentation/devicetree/bindings/pinctrl/renesas,*
F: drivers/pinctrl/renesas/
PIN CONTROLLER - SAMSUNG
M: Tomasz Figa <tomasz.figa@gmail.com>
M: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
M: Sylwester Nawrocki <s.nawrocki@samsung.com>
R: Alim Akhtar <alim.akhtar@samsung.com>
@ -19428,7 +19428,6 @@ F: drivers/media/platform/samsung/exynos4-is/
SAMSUNG SOC CLOCK DRIVERS
M: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
M: Sylwester Nawrocki <s.nawrocki@samsung.com>
M: Tomasz Figa <tomasz.figa@gmail.com>
M: Chanwoo Choi <cw00.choi@samsung.com>
R: Alim Akhtar <alim.akhtar@samsung.com>
L: linux-samsung-soc@vger.kernel.org
@ -21348,6 +21347,7 @@ F: drivers/clk/clk-sc[mp]i.c
F: drivers/cpufreq/sc[mp]i-cpufreq.c
F: drivers/firmware/arm_scmi/
F: drivers/firmware/arm_scpi.c
F: drivers/hwmon/scmi-hwmon.c
F: drivers/pmdomain/arm/
F: drivers/powercap/arm_scmi_powercap.c
F: drivers/regulator/scmi-regulator.c

View File

@ -186,11 +186,12 @@ config SUNXI_RSB
config TEGRA_ACONNECT
tristate "Tegra ACONNECT Bus Driver"
depends on ARCH_TEGRA_210_SOC
depends on ARCH_TEGRA
depends on OF && PM
help
Driver for the Tegra ACONNECT bus which is used to interface with
the devices inside the Audio Processing Engine (APE) for Tegra210.
the devices inside the Audio Processing Engine (APE) for
Tegra210 and later.
config TEGRA_GMI
tristate "Tegra Generic Memory Interface bus driver"

View File

@ -128,7 +128,7 @@ struct sunxi_rsb {
};
/* bus / slave device related functions */
static struct bus_type sunxi_rsb_bus;
static const struct bus_type sunxi_rsb_bus;
static int sunxi_rsb_device_match(struct device *dev, struct device_driver *drv)
{
@ -177,7 +177,7 @@ static int sunxi_rsb_device_modalias(const struct device *dev, struct kobj_ueven
return of_device_uevent_modalias(dev, env);
}
static struct bus_type sunxi_rsb_bus = {
static const struct bus_type sunxi_rsb_bus = {
.name = RSB_CTRL_NAME,
.match = sunxi_rsb_device_match,
.probe = sunxi_rsb_device_probe,

View File

@ -2400,7 +2400,7 @@ static int sysc_child_add_clocks(struct sysc *ddata,
return 0;
}
static struct device_type sysc_device_type = {
static const struct device_type sysc_device_type = {
};
static struct sysc *sysc_child_to_parent(struct device *dev)

View File

@ -105,7 +105,7 @@ static struct attribute *ffa_device_attributes_attrs[] = {
};
ATTRIBUTE_GROUPS(ffa_device_attributes);
struct bus_type ffa_bus_type = {
const struct bus_type ffa_bus_type = {
.name = "arm_ffa",
.match = ffa_device_match,
.probe = ffa_device_probe,

View File

@ -141,6 +141,17 @@ out:
return ret;
}
static int scmi_protocol_table_register(const struct scmi_device_id *id_table)
{
int ret = 0;
const struct scmi_device_id *entry;
for (entry = id_table; entry->name && ret == 0; entry++)
ret = scmi_protocol_device_request(entry);
return ret;
}
/**
* scmi_protocol_device_unrequest - Helper to unrequest a device
*
@ -186,6 +197,15 @@ static void scmi_protocol_device_unrequest(const struct scmi_device_id *id_table
mutex_unlock(&scmi_requested_devices_mtx);
}
static void
scmi_protocol_table_unregister(const struct scmi_device_id *id_table)
{
const struct scmi_device_id *entry;
for (entry = id_table; entry->name; entry++)
scmi_protocol_device_unrequest(entry);
}
static const struct scmi_device_id *
scmi_dev_match_id(struct scmi_device *scmi_dev, struct scmi_driver *scmi_drv)
{
@ -263,7 +283,7 @@ static void scmi_dev_remove(struct device *dev)
scmi_drv->remove(scmi_dev);
}
struct bus_type scmi_bus_type = {
const struct bus_type scmi_bus_type = {
.name = "scmi_protocol",
.match = scmi_dev_match,
.probe = scmi_dev_probe,
@ -279,7 +299,7 @@ int scmi_driver_register(struct scmi_driver *driver, struct module *owner,
if (!driver->probe)
return -EINVAL;
retval = scmi_protocol_device_request(driver->id_table);
retval = scmi_protocol_table_register(driver->id_table);
if (retval)
return retval;
@ -299,7 +319,7 @@ EXPORT_SYMBOL_GPL(scmi_driver_register);
void scmi_driver_unregister(struct scmi_driver *driver)
{
driver_unregister(&driver->driver);
scmi_protocol_device_unrequest(driver->id_table);
scmi_protocol_table_unregister(driver->id_table);
}
EXPORT_SYMBOL_GPL(scmi_driver_unregister);

View File

@ -13,7 +13,7 @@
#include "notify.h"
/* Updated only after ALL the mandatory features for that version are merged */
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000
enum scmi_clock_protocol_cmd {
CLOCK_ATTRIBUTES = 0x3,
@ -28,8 +28,13 @@ enum scmi_clock_protocol_cmd {
CLOCK_POSSIBLE_PARENTS_GET = 0xC,
CLOCK_PARENT_SET = 0xD,
CLOCK_PARENT_GET = 0xE,
CLOCK_GET_PERMISSIONS = 0xF,
};
#define CLOCK_STATE_CONTROL_ALLOWED BIT(31)
#define CLOCK_PARENT_CONTROL_ALLOWED BIT(30)
#define CLOCK_RATE_CONTROL_ALLOWED BIT(29)
enum clk_state {
CLK_STATE_DISABLE,
CLK_STATE_ENABLE,
@ -49,6 +54,8 @@ struct scmi_msg_resp_clock_attributes {
#define SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(x) ((x) & BIT(30))
#define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(29))
#define SUPPORTS_PARENT_CLOCK(x) ((x) & BIT(28))
#define SUPPORTS_EXTENDED_CONFIG(x) ((x) & BIT(27))
#define SUPPORTS_GET_PERMISSIONS(x) ((x) & BIT(1))
u8 name[SCMI_SHORT_NAME_MAX_SIZE];
__le32 clock_enable_latency;
};
@ -152,14 +159,18 @@ struct clock_info {
u32 version;
int num_clocks;
int max_async_req;
bool notify_rate_changed_cmd;
bool notify_rate_change_requested_cmd;
atomic_t cur_async_req;
struct scmi_clock_info *clk;
int (*clock_config_set)(const struct scmi_protocol_handle *ph,
u32 clk_id, enum clk_state state,
u8 oem_type, u32 oem_val, bool atomic);
enum scmi_clock_oem_config oem_type,
u32 oem_val, bool atomic);
int (*clock_config_get)(const struct scmi_protocol_handle *ph,
u32 clk_id, u8 oem_type, u32 *attributes,
bool *enabled, u32 *oem_val, bool atomic);
u32 clk_id, enum scmi_clock_oem_config oem_type,
u32 *attributes, bool *enabled, u32 *oem_val,
bool atomic);
};
static enum scmi_clock_protocol_cmd evt_2_cmd[] = {
@ -167,6 +178,15 @@ static enum scmi_clock_protocol_cmd evt_2_cmd[] = {
CLOCK_RATE_CHANGE_REQUESTED_NOTIFY,
};
static inline struct scmi_clock_info *
scmi_clock_domain_lookup(struct clock_info *ci, u32 clk_id)
{
if (clk_id >= ci->num_clocks)
return ERR_PTR(-EINVAL);
return ci->clk + clk_id;
}
static int
scmi_clock_protocol_attributes_get(const struct scmi_protocol_handle *ph,
struct clock_info *ci)
@ -189,6 +209,17 @@ scmi_clock_protocol_attributes_get(const struct scmi_protocol_handle *ph,
}
ph->xops->xfer_put(ph, t);
if (!ret) {
if (!ph->hops->protocol_msg_check(ph, CLOCK_RATE_NOTIFY, NULL))
ci->notify_rate_changed_cmd = true;
if (!ph->hops->protocol_msg_check(ph,
CLOCK_RATE_CHANGE_REQUESTED_NOTIFY,
NULL))
ci->notify_rate_change_requested_cmd = true;
}
return ret;
}
@ -284,14 +315,44 @@ static int scmi_clock_possible_parents(const struct scmi_protocol_handle *ph, u3
return ret;
}
static int
scmi_clock_get_permissions(const struct scmi_protocol_handle *ph, u32 clk_id,
struct scmi_clock_info *clk)
{
struct scmi_xfer *t;
u32 perm;
int ret;
ret = ph->xops->xfer_get_init(ph, CLOCK_GET_PERMISSIONS,
sizeof(clk_id), sizeof(perm), &t);
if (ret)
return ret;
put_unaligned_le32(clk_id, t->tx.buf);
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
perm = get_unaligned_le32(t->rx.buf);
clk->state_ctrl_forbidden = !(perm & CLOCK_STATE_CONTROL_ALLOWED);
clk->rate_ctrl_forbidden = !(perm & CLOCK_RATE_CONTROL_ALLOWED);
clk->parent_ctrl_forbidden = !(perm & CLOCK_PARENT_CONTROL_ALLOWED);
}
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
u32 clk_id, struct scmi_clock_info *clk,
u32 clk_id, struct clock_info *cinfo,
u32 version)
{
int ret;
u32 attributes;
struct scmi_xfer *t;
struct scmi_msg_resp_clock_attributes *attr;
struct scmi_clock_info *clk = cinfo->clk + clk_id;
ret = ph->xops->xfer_get_init(ph, CLOCK_ATTRIBUTES,
sizeof(clk_id), sizeof(*attr), &t);
@ -324,12 +385,20 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
NULL, clk->name,
SCMI_MAX_STR_SIZE);
if (SUPPORTS_RATE_CHANGED_NOTIF(attributes))
if (cinfo->notify_rate_changed_cmd &&
SUPPORTS_RATE_CHANGED_NOTIF(attributes))
clk->rate_changed_notifications = true;
if (SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(attributes))
if (cinfo->notify_rate_change_requested_cmd &&
SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(attributes))
clk->rate_change_requested_notifications = true;
if (SUPPORTS_PARENT_CLOCK(attributes))
scmi_clock_possible_parents(ph, clk_id, clk);
if (PROTOCOL_REV_MAJOR(version) >= 0x3) {
if (SUPPORTS_PARENT_CLOCK(attributes))
scmi_clock_possible_parents(ph, clk_id, clk);
if (SUPPORTS_GET_PERMISSIONS(attributes))
scmi_clock_get_permissions(ph, clk_id, clk);
if (SUPPORTS_EXTENDED_CONFIG(attributes))
clk->extended_config = true;
}
}
return ret;
@ -502,6 +571,14 @@ static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph,
struct scmi_xfer *t;
struct scmi_clock_set_rate *cfg;
struct clock_info *ci = ph->get_priv(ph);
struct scmi_clock_info *clk;
clk = scmi_clock_domain_lookup(ci, clk_id);
if (IS_ERR(clk))
return PTR_ERR(clk);
if (clk->rate_ctrl_forbidden)
return -EACCES;
ret = ph->xops->xfer_get_init(ph, CLOCK_RATE_SET, sizeof(*cfg), 0, &t);
if (ret)
@ -543,7 +620,8 @@ static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph,
static int
scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id,
enum clk_state state, u8 __unused0, u32 __unused1,
enum clk_state state,
enum scmi_clock_oem_config __unused0, u32 __unused1,
bool atomic)
{
int ret;
@ -580,14 +658,16 @@ scmi_clock_set_parent(const struct scmi_protocol_handle *ph, u32 clk_id,
struct clock_info *ci = ph->get_priv(ph);
struct scmi_clock_info *clk;
if (clk_id >= ci->num_clocks)
return -EINVAL;
clk = ci->clk + clk_id;
clk = scmi_clock_domain_lookup(ci, clk_id);
if (IS_ERR(clk))
return PTR_ERR(clk);
if (parent_id >= clk->num_parents)
return -EINVAL;
if (clk->parent_ctrl_forbidden)
return -EACCES;
ret = ph->xops->xfer_get_init(ph, CLOCK_PARENT_SET,
sizeof(*cfg), 0, &t);
if (ret)
@ -628,10 +708,11 @@ scmi_clock_get_parent(const struct scmi_protocol_handle *ph, u32 clk_id,
return ret;
}
/* For SCMI clock v2.1 and onwards */
/* For SCMI clock v3.0 and onwards */
static int
scmi_clock_config_set_v2(const struct scmi_protocol_handle *ph, u32 clk_id,
enum clk_state state, u8 oem_type, u32 oem_val,
enum clk_state state,
enum scmi_clock_oem_config oem_type, u32 oem_val,
bool atomic)
{
int ret;
@ -671,6 +752,14 @@ static int scmi_clock_enable(const struct scmi_protocol_handle *ph, u32 clk_id,
bool atomic)
{
struct clock_info *ci = ph->get_priv(ph);
struct scmi_clock_info *clk;
clk = scmi_clock_domain_lookup(ci, clk_id);
if (IS_ERR(clk))
return PTR_ERR(clk);
if (clk->state_ctrl_forbidden)
return -EACCES;
return ci->clock_config_set(ph, clk_id, CLK_STATE_ENABLE,
NULL_OEM_TYPE, 0, atomic);
@ -680,16 +769,24 @@ static int scmi_clock_disable(const struct scmi_protocol_handle *ph, u32 clk_id,
bool atomic)
{
struct clock_info *ci = ph->get_priv(ph);
struct scmi_clock_info *clk;
clk = scmi_clock_domain_lookup(ci, clk_id);
if (IS_ERR(clk))
return PTR_ERR(clk);
if (clk->state_ctrl_forbidden)
return -EACCES;
return ci->clock_config_set(ph, clk_id, CLK_STATE_DISABLE,
NULL_OEM_TYPE, 0, atomic);
}
/* For SCMI clock v2.1 and onwards */
/* For SCMI clock v3.0 and onwards */
static int
scmi_clock_config_get_v2(const struct scmi_protocol_handle *ph, u32 clk_id,
u8 oem_type, u32 *attributes, bool *enabled,
u32 *oem_val, bool atomic)
enum scmi_clock_oem_config oem_type, u32 *attributes,
bool *enabled, u32 *oem_val, bool atomic)
{
int ret;
u32 flags;
@ -730,8 +827,8 @@ scmi_clock_config_get_v2(const struct scmi_protocol_handle *ph, u32 clk_id,
static int
scmi_clock_config_get(const struct scmi_protocol_handle *ph, u32 clk_id,
u8 oem_type, u32 *attributes, bool *enabled,
u32 *oem_val, bool atomic)
enum scmi_clock_oem_config oem_type, u32 *attributes,
bool *enabled, u32 *oem_val, bool atomic)
{
int ret;
struct scmi_xfer *t;
@ -768,20 +865,38 @@ static int scmi_clock_state_get(const struct scmi_protocol_handle *ph,
}
static int scmi_clock_config_oem_set(const struct scmi_protocol_handle *ph,
u32 clk_id, u8 oem_type, u32 oem_val,
bool atomic)
u32 clk_id,
enum scmi_clock_oem_config oem_type,
u32 oem_val, bool atomic)
{
struct clock_info *ci = ph->get_priv(ph);
struct scmi_clock_info *clk;
clk = scmi_clock_domain_lookup(ci, clk_id);
if (IS_ERR(clk))
return PTR_ERR(clk);
if (!clk->extended_config)
return -EOPNOTSUPP;
return ci->clock_config_set(ph, clk_id, CLK_STATE_UNCHANGED,
oem_type, oem_val, atomic);
}
static int scmi_clock_config_oem_get(const struct scmi_protocol_handle *ph,
u32 clk_id, u8 oem_type, u32 *oem_val,
u32 *attributes, bool atomic)
u32 clk_id,
enum scmi_clock_oem_config oem_type,
u32 *oem_val, u32 *attributes, bool atomic)
{
struct clock_info *ci = ph->get_priv(ph);
struct scmi_clock_info *clk;
clk = scmi_clock_domain_lookup(ci, clk_id);
if (IS_ERR(clk))
return PTR_ERR(clk);
if (!clk->extended_config)
return -EOPNOTSUPP;
return ci->clock_config_get(ph, clk_id, oem_type, attributes,
NULL, oem_val, atomic);
@ -800,10 +915,10 @@ scmi_clock_info_get(const struct scmi_protocol_handle *ph, u32 clk_id)
struct scmi_clock_info *clk;
struct clock_info *ci = ph->get_priv(ph);
if (clk_id >= ci->num_clocks)
clk = scmi_clock_domain_lookup(ci, clk_id);
if (IS_ERR(clk))
return NULL;
clk = ci->clk + clk_id;
if (!clk->name[0])
return NULL;
@ -824,6 +939,28 @@ static const struct scmi_clk_proto_ops clk_proto_ops = {
.parent_get = scmi_clock_get_parent,
};
static bool scmi_clk_notify_supported(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id)
{
bool supported;
struct scmi_clock_info *clk;
struct clock_info *ci = ph->get_priv(ph);
if (evt_id >= ARRAY_SIZE(evt_2_cmd))
return false;
clk = scmi_clock_domain_lookup(ci, src_id);
if (IS_ERR(clk))
return false;
if (evt_id == SCMI_EVENT_CLOCK_RATE_CHANGED)
supported = clk->rate_changed_notifications;
else
supported = clk->rate_change_requested_notifications;
return supported;
}
static int scmi_clk_rate_notify(const struct scmi_protocol_handle *ph,
u32 clk_id, int message_id, bool enable)
{
@ -908,6 +1045,7 @@ static const struct scmi_event clk_events[] = {
};
static const struct scmi_event_ops clk_event_ops = {
.is_notify_supported = scmi_clk_notify_supported,
.get_num_sources = scmi_clk_get_num_sources,
.set_notify_enabled = scmi_clk_set_notify_enabled,
.fill_custom_report = scmi_clk_fill_custom_report,
@ -949,7 +1087,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
for (clkid = 0; clkid < cinfo->num_clocks; clkid++) {
struct scmi_clock_info *clk = cinfo->clk + clkid;
ret = scmi_clock_attributes_get(ph, clkid, clk, version);
ret = scmi_clock_attributes_get(ph, clkid, cinfo, version);
if (!ret)
scmi_clock_describe_rates_get(ph, clkid, clk);
}

View File

@ -141,7 +141,7 @@ scmi_revision_area_get(const struct scmi_protocol_handle *ph);
void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph,
u8 *prot_imp);
extern struct bus_type scmi_bus_type;
extern const struct bus_type scmi_bus_type;
#define SCMI_BUS_NOTIFY_DEVICE_REQUEST 0
#define SCMI_BUS_NOTIFY_DEVICE_UNREQUEST 1

View File

@ -86,6 +86,12 @@ struct scmi_xfers_info {
* @users: A refcount to track effective users of this protocol.
* @priv: Reference for optional protocol private data.
* @version: Protocol version supported by the platform as detected at runtime.
* @negotiated_version: When the platform supports a newer protocol version,
* the agent will try to negotiate with the platform the
* usage of the newest version known to it, since
* backward compatibility is NOT automatically assured.
* This field is NON-zero when a successful negotiation
* has completed.
* @ph: An embedded protocol handle that will be passed down to protocol
* initialization code to identify this instance.
*
@ -99,6 +105,7 @@ struct scmi_protocol_instance {
refcount_t users;
void *priv;
unsigned int version;
unsigned int negotiated_version;
struct scmi_protocol_handle ph;
};
@ -1754,10 +1761,44 @@ static void scmi_common_fastchannel_db_ring(struct scmi_fc_db_info *db)
#endif
}
/**
* scmi_protocol_msg_check - Check protocol message attributes
*
* @ph: A reference to the protocol handle.
* @message_id: The ID of the message to check.
* @attributes: A parameter to optionally return the retrieved message
* attributes, in case of Success.
*
* An helper to check protocol message attributes for a specific protocol
* and message pair.
*
* Return: 0 on SUCCESS
*/
static int scmi_protocol_msg_check(const struct scmi_protocol_handle *ph,
u32 message_id, u32 *attributes)
{
int ret;
struct scmi_xfer *t;
ret = xfer_get_init(ph, PROTOCOL_MESSAGE_ATTRIBUTES,
sizeof(__le32), 0, &t);
if (ret)
return ret;
put_unaligned_le32(message_id, t->tx.buf);
ret = do_xfer(ph, t);
if (!ret && attributes)
*attributes = get_unaligned_le32(t->rx.buf);
xfer_put(ph, t);
return ret;
}
static const struct scmi_proto_helpers_ops helpers_ops = {
.extended_name_get = scmi_common_extended_name_get,
.iter_response_init = scmi_iterator_init,
.iter_response_run = scmi_iterator_run,
.protocol_msg_check = scmi_protocol_msg_check,
.fastchannel_init = scmi_common_fastchannel_init,
.fastchannel_db_ring = scmi_common_fastchannel_db_ring,
};
@ -1781,6 +1822,44 @@ scmi_revision_area_get(const struct scmi_protocol_handle *ph)
return pi->handle->version;
}
/**
* scmi_protocol_version_negotiate - Negotiate protocol version
*
* @ph: A reference to the protocol handle.
*
* An helper to negotiate a protocol version different from the latest
* advertised as supported from the platform: on Success backward
* compatibility is assured by the platform.
*
* Return: 0 on Success
*/
static int scmi_protocol_version_negotiate(struct scmi_protocol_handle *ph)
{
int ret;
struct scmi_xfer *t;
struct scmi_protocol_instance *pi = ph_to_pi(ph);
/* At first check if NEGOTIATE_PROTOCOL_VERSION is supported ... */
ret = scmi_protocol_msg_check(ph, NEGOTIATE_PROTOCOL_VERSION, NULL);
if (ret)
return ret;
/* ... then attempt protocol version negotiation */
ret = xfer_get_init(ph, NEGOTIATE_PROTOCOL_VERSION,
sizeof(__le32), 0, &t);
if (ret)
return ret;
put_unaligned_le32(pi->proto->supported_version, t->tx.buf);
ret = do_xfer(ph, t);
if (!ret)
pi->negotiated_version = pi->proto->supported_version;
xfer_put(ph, t);
return ret;
}
/**
* scmi_alloc_init_protocol_instance - Allocate and initialize a protocol
* instance descriptor.
@ -1853,11 +1932,21 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info,
devres_close_group(handle->dev, pi->gid);
dev_dbg(handle->dev, "Initialized protocol: 0x%X\n", pi->proto->id);
if (pi->version > proto->supported_version)
dev_warn(handle->dev,
"Detected UNSUPPORTED higher version 0x%X for protocol 0x%X."
"Backward compatibility is NOT assured.\n",
pi->version, pi->proto->id);
if (pi->version > proto->supported_version) {
ret = scmi_protocol_version_negotiate(&pi->ph);
if (!ret) {
dev_info(handle->dev,
"Protocol 0x%X successfully negotiated version 0x%X\n",
proto->id, pi->negotiated_version);
} else {
dev_warn(handle->dev,
"Detected UNSUPPORTED higher version 0x%X for protocol 0x%X.\n",
pi->version, pi->proto->id);
dev_warn(handle->dev,
"Trying version 0x%X. Backward compatibility is NOT assured.\n",
pi->proto->supported_version);
}
}
return pi;

View File

@ -99,6 +99,7 @@
#define PROTO_ID_MASK GENMASK(31, 24)
#define EVT_ID_MASK GENMASK(23, 16)
#define SRC_ID_MASK GENMASK(15, 0)
#define NOTIF_UNSUPP -1
/*
* Builds an unsigned 32bit key from the given input tuple to be used
@ -788,6 +789,7 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
pd->ph = ph;
for (i = 0; i < ee->num_events; i++, evt++) {
int id;
struct scmi_registered_event *r_evt;
r_evt = devm_kzalloc(ni->handle->dev, sizeof(*r_evt),
@ -809,6 +811,11 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
if (!r_evt->report)
return -ENOMEM;
for (id = 0; id < r_evt->num_sources; id++)
if (ee->ops->is_notify_supported &&
!ee->ops->is_notify_supported(ph, r_evt->evt->id, id))
refcount_set(&r_evt->sources[id], NOTIF_UNSUPP);
pd->registered_events[i] = r_evt;
/* Ensure events are updated */
smp_wmb();
@ -1166,7 +1173,13 @@ static inline int __scmi_enable_evt(struct scmi_registered_event *r_evt,
int ret = 0;
sid = &r_evt->sources[src_id];
if (refcount_read(sid) == 0) {
if (refcount_read(sid) == NOTIF_UNSUPP) {
dev_dbg(r_evt->proto->ph->dev,
"Notification NOT supported - proto_id:%d evt_id:%d src_id:%d",
r_evt->proto->id, r_evt->evt->id,
src_id);
ret = -EOPNOTSUPP;
} else if (refcount_read(sid) == 0) {
ret = REVT_NOTIFY_ENABLE(r_evt, r_evt->evt->id,
src_id);
if (!ret)
@ -1179,6 +1192,8 @@ static inline int __scmi_enable_evt(struct scmi_registered_event *r_evt,
} else {
for (; num_sources; src_id++, num_sources--) {
sid = &r_evt->sources[src_id];
if (refcount_read(sid) == NOTIF_UNSUPP)
continue;
if (refcount_dec_and_test(sid))
REVT_NOTIFY_DISABLE(r_evt,
r_evt->evt->id, src_id);

View File

@ -35,6 +35,8 @@ struct scmi_protocol_handle;
/**
* struct scmi_event_ops - Protocol helpers called by the notification core.
* @is_notify_supported: Return 0 if the specified notification for the
* specified resource (src_id) is supported.
* @get_num_sources: Returns the number of possible events' sources for this
* protocol
* @set_notify_enabled: Enable/disable the required evt_id/src_id notifications
@ -50,6 +52,8 @@ struct scmi_protocol_handle;
* process context.
*/
struct scmi_event_ops {
bool (*is_notify_supported)(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id);
int (*get_num_sources)(const struct scmi_protocol_handle *ph);
int (*set_notify_enabled)(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enabled);

View File

@ -109,8 +109,10 @@ enum scmi_optee_pta_cmd {
* @rx_len: Response size
* @mu: Mutex protection on channel access
* @cinfo: SCMI channel information
* @shmem: Virtual base address of the shared memory
* @req: Shared memory protocol handle for SCMI request and synchronous response
* @req: union for SCMI interface
* @req.shmem: Virtual base address of the shared memory
* @req.msg: Shared memory protocol handle for SCMI request and
* synchronous response
* @tee_shm: TEE shared memory handle @req or NULL if using IOMEM shmem
* @link: Reference in agent's channel list
*/

View File

@ -182,6 +182,8 @@ struct scmi_perf_info {
enum scmi_power_scale power_scale;
u64 stats_addr;
u32 stats_size;
bool notify_lvl_cmd;
bool notify_lim_cmd;
struct perf_dom_info *dom_info;
};
@ -222,6 +224,15 @@ static int scmi_perf_attributes_get(const struct scmi_protocol_handle *ph,
}
ph->xops->xfer_put(ph, t);
if (!ret) {
if (!ph->hops->protocol_msg_check(ph, PERF_NOTIFY_LEVEL, NULL))
pi->notify_lvl_cmd = true;
if (!ph->hops->protocol_msg_check(ph, PERF_NOTIFY_LIMITS, NULL))
pi->notify_lim_cmd = true;
}
return ret;
}
@ -239,6 +250,7 @@ static void scmi_perf_xa_destroy(void *data)
static int
scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
struct perf_dom_info *dom_info,
bool notify_lim_cmd, bool notify_lvl_cmd,
u32 version)
{
int ret;
@ -260,8 +272,12 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
dom_info->set_limits = SUPPORTS_SET_LIMITS(flags);
dom_info->info.set_perf = SUPPORTS_SET_PERF_LVL(flags);
dom_info->perf_limit_notify = SUPPORTS_PERF_LIMIT_NOTIFY(flags);
dom_info->perf_level_notify = SUPPORTS_PERF_LEVEL_NOTIFY(flags);
if (notify_lim_cmd)
dom_info->perf_limit_notify =
SUPPORTS_PERF_LIMIT_NOTIFY(flags);
if (notify_lvl_cmd)
dom_info->perf_level_notify =
SUPPORTS_PERF_LEVEL_NOTIFY(flags);
dom_info->perf_fastchannels = SUPPORTS_PERF_FASTCHANNELS(flags);
if (PROTOCOL_REV_MAJOR(version) >= 0x4)
dom_info->level_indexing_mode =
@ -270,15 +286,30 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
le32_to_cpu(attr->sustained_freq_khz);
dom_info->sustained_perf_level =
le32_to_cpu(attr->sustained_perf_level);
/*
* sustained_freq_khz = mult_factor * sustained_perf_level
* mult_factor must be non zero positive integer(not fraction)
*/
if (!dom_info->sustained_freq_khz ||
!dom_info->sustained_perf_level ||
dom_info->level_indexing_mode)
dom_info->level_indexing_mode) {
/* CPUFreq converts to kHz, hence default 1000 */
dom_info->mult_factor = 1000;
else
} else {
dom_info->mult_factor =
(dom_info->sustained_freq_khz * 1000UL)
/ dom_info->sustained_perf_level;
if ((dom_info->sustained_freq_khz * 1000UL) %
dom_info->sustained_perf_level)
dev_warn(ph->dev,
"multiplier for domain %d rounded\n",
dom_info->id);
}
if (!dom_info->mult_factor)
dev_warn(ph->dev,
"Wrong sustained perf/frequency(domain %d)\n",
dom_info->id);
strscpy(dom_info->info.name, attr->name,
SCMI_SHORT_NAME_MAX_SIZE);
}
@ -295,9 +326,9 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
dom_info->id, NULL, dom_info->info.name,
SCMI_MAX_STR_SIZE);
xa_init(&dom_info->opps_by_lvl);
if (dom_info->level_indexing_mode) {
xa_init(&dom_info->opps_by_idx);
xa_init(&dom_info->opps_by_lvl);
hash_init(dom_info->opps_by_freq);
}
@ -340,13 +371,21 @@ static int iter_perf_levels_update_state(struct scmi_iterator_state *st,
}
static inline void
process_response_opp(struct scmi_opp *opp, unsigned int loop_idx,
process_response_opp(struct device *dev, struct perf_dom_info *dom,
struct scmi_opp *opp, unsigned int loop_idx,
const struct scmi_msg_resp_perf_describe_levels *r)
{
int ret;
opp->perf = le32_to_cpu(r->opp[loop_idx].perf_val);
opp->power = le32_to_cpu(r->opp[loop_idx].power);
opp->trans_latency_us =
le16_to_cpu(r->opp[loop_idx].transition_latency_us);
ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
if (ret)
dev_warn(dev, "Failed to add opps_by_lvl at %d - ret:%d\n",
opp->perf, ret);
}
static inline void
@ -354,16 +393,21 @@ process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
struct scmi_opp *opp, unsigned int loop_idx,
const struct scmi_msg_resp_perf_describe_levels_v4 *r)
{
int ret;
opp->perf = le32_to_cpu(r->opp[loop_idx].perf_val);
opp->power = le32_to_cpu(r->opp[loop_idx].power);
opp->trans_latency_us =
le16_to_cpu(r->opp[loop_idx].transition_latency_us);
ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
if (ret)
dev_warn(dev, "Failed to add opps_by_lvl at %d - ret:%d\n",
opp->perf, ret);
/* Note that PERF v4 reports always five 32-bit words */
opp->indicative_freq = le32_to_cpu(r->opp[loop_idx].indicative_freq);
if (dom->level_indexing_mode) {
int ret;
opp->level_index = le32_to_cpu(r->opp[loop_idx].level_index);
ret = xa_insert(&dom->opps_by_idx, opp->level_index, opp,
@ -373,12 +417,6 @@ process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
"Failed to add opps_by_idx at %d - ret:%d\n",
opp->level_index, ret);
ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
if (ret)
dev_warn(dev,
"Failed to add opps_by_lvl at %d - ret:%d\n",
opp->perf, ret);
hash_add(dom->opps_by_freq, &opp->hash, opp->indicative_freq);
}
}
@ -393,7 +431,8 @@ iter_perf_levels_process_response(const struct scmi_protocol_handle *ph,
opp = &p->perf_dom->opp[st->desc_index + st->loop_idx];
if (PROTOCOL_REV_MAJOR(p->version) <= 0x3)
process_response_opp(opp, st->loop_idx, response);
process_response_opp(ph->dev, p->perf_dom, opp, st->loop_idx,
response);
else
process_response_opp_v4(ph->dev, p->perf_dom, opp, st->loop_idx,
response);
@ -978,6 +1017,27 @@ static const struct scmi_perf_proto_ops perf_proto_ops = {
.power_scale_get = scmi_power_scale_get,
};
static bool scmi_perf_notify_supported(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id)
{
bool supported;
struct perf_dom_info *dom;
if (evt_id >= ARRAY_SIZE(evt_2_cmd))
return false;
dom = scmi_perf_domain_lookup(ph, src_id);
if (IS_ERR(dom))
return false;
if (evt_id == SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED)
supported = dom->perf_limit_notify;
else
supported = dom->perf_level_notify;
return supported;
}
static int scmi_perf_set_notify_enabled(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enable)
{
@ -995,18 +1055,47 @@ static int scmi_perf_set_notify_enabled(const struct scmi_protocol_handle *ph,
return ret;
}
static int
scmi_perf_xlate_opp_to_freq(struct perf_dom_info *dom,
unsigned int index, unsigned long *freq)
{
struct scmi_opp *opp;
if (!dom || !freq)
return -EINVAL;
if (!dom->level_indexing_mode) {
opp = xa_load(&dom->opps_by_lvl, index);
if (!opp)
return -ENODEV;
*freq = opp->perf * dom->mult_factor;
} else {
opp = xa_load(&dom->opps_by_idx, index);
if (!opp)
return -ENODEV;
*freq = opp->indicative_freq * dom->mult_factor;
}
return 0;
}
static void *scmi_perf_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)
{
int ret;
void *rep = NULL;
struct perf_dom_info *dom;
switch (evt_id) {
case SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED:
{
const struct scmi_perf_limits_notify_payld *p = payld;
struct scmi_perf_limits_report *r = report;
unsigned long freq_min, freq_max;
if (sizeof(*p) != payld_sz)
break;
@ -1016,14 +1105,36 @@ static void *scmi_perf_fill_custom_report(const struct scmi_protocol_handle *ph,
r->domain_id = le32_to_cpu(p->domain_id);
r->range_max = le32_to_cpu(p->range_max);
r->range_min = le32_to_cpu(p->range_min);
/* Check if the reported domain exist at all */
dom = scmi_perf_domain_lookup(ph, r->domain_id);
if (IS_ERR(dom))
break;
/*
* Event will be reported from this point on...
* ...even if, later, xlated frequencies were not retrieved.
*/
*src_id = r->domain_id;
rep = r;
ret = scmi_perf_xlate_opp_to_freq(dom, r->range_max, &freq_max);
if (ret)
break;
ret = scmi_perf_xlate_opp_to_freq(dom, r->range_min, &freq_min);
if (ret)
break;
/* Report translated freqs ONLY if both available */
r->range_max_freq = freq_max;
r->range_min_freq = freq_min;
break;
}
case SCMI_EVENT_PERFORMANCE_LEVEL_CHANGED:
{
const struct scmi_perf_level_notify_payld *p = payld;
struct scmi_perf_level_report *r = report;
unsigned long freq;
if (sizeof(*p) != payld_sz)
break;
@ -1031,9 +1142,27 @@ static void *scmi_perf_fill_custom_report(const struct scmi_protocol_handle *ph,
r->timestamp = timestamp;
r->agent_id = le32_to_cpu(p->agent_id);
r->domain_id = le32_to_cpu(p->domain_id);
/* Report translated freqs ONLY if available */
r->performance_level = le32_to_cpu(p->performance_level);
/* Check if the reported domain exist at all */
dom = scmi_perf_domain_lookup(ph, r->domain_id);
if (IS_ERR(dom))
break;
/*
* Event will be reported from this point on...
* ...even if, later, xlated frequencies were not retrieved.
*/
*src_id = r->domain_id;
rep = r;
/* Report translated freqs ONLY if available */
ret = scmi_perf_xlate_opp_to_freq(dom, r->performance_level,
&freq);
if (ret)
break;
r->performance_level_freq = freq;
break;
}
default:
@ -1067,6 +1196,7 @@ static const struct scmi_event perf_events[] = {
};
static const struct scmi_event_ops perf_event_ops = {
.is_notify_supported = scmi_perf_notify_supported,
.get_num_sources = scmi_perf_get_num_sources,
.set_notify_enabled = scmi_perf_set_notify_enabled,
.fill_custom_report = scmi_perf_fill_custom_report,
@ -1111,7 +1241,8 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
struct perf_dom_info *dom = pinfo->dom_info + domain;
dom->id = domain;
scmi_perf_domain_attributes_get(ph, dom, version);
scmi_perf_domain_attributes_get(ph, dom, pinfo->notify_lim_cmd,
pinfo->notify_lvl_cmd, version);
scmi_perf_describe_levels_get(ph, dom, version);
if (dom->perf_fastchannels)

View File

@ -68,6 +68,7 @@ struct power_dom_info {
struct scmi_power_info {
u32 version;
bool notify_state_change_cmd;
int num_domains;
u64 stats_addr;
u32 stats_size;
@ -97,13 +98,18 @@ static int scmi_power_attributes_get(const struct scmi_protocol_handle *ph,
}
ph->xops->xfer_put(ph, t);
if (!ret)
if (!ph->hops->protocol_msg_check(ph, POWER_STATE_NOTIFY, NULL))
pi->notify_state_change_cmd = true;
return ret;
}
static int
scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
u32 domain, struct power_dom_info *dom_info,
u32 version)
u32 version, bool notify_state_change_cmd)
{
int ret;
u32 flags;
@ -122,7 +128,9 @@ scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
if (!ret) {
flags = le32_to_cpu(attr->flags);
dom_info->state_set_notify = SUPPORTS_STATE_SET_NOTIFY(flags);
if (notify_state_change_cmd)
dom_info->state_set_notify =
SUPPORTS_STATE_SET_NOTIFY(flags);
dom_info->state_set_async = SUPPORTS_STATE_SET_ASYNC(flags);
dom_info->state_set_sync = SUPPORTS_STATE_SET_SYNC(flags);
strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
@ -231,6 +239,20 @@ static int scmi_power_request_notify(const struct scmi_protocol_handle *ph,
return ret;
}
static bool scmi_power_notify_supported(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id)
{
struct power_dom_info *dom;
struct scmi_power_info *pinfo = ph->get_priv(ph);
if (evt_id != SCMI_EVENT_POWER_STATE_CHANGED ||
src_id >= pinfo->num_domains)
return false;
dom = pinfo->dom_info + src_id;
return dom->state_set_notify;
}
static int scmi_power_set_notify_enabled(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enable)
{
@ -285,6 +307,7 @@ static const struct scmi_event power_events[] = {
};
static const struct scmi_event_ops power_event_ops = {
.is_notify_supported = scmi_power_notify_supported,
.get_num_sources = scmi_power_get_num_sources,
.set_notify_enabled = scmi_power_set_notify_enabled,
.fill_custom_report = scmi_power_fill_custom_report,
@ -326,7 +349,8 @@ static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph)
for (domain = 0; domain < pinfo->num_domains; domain++) {
struct power_dom_info *dom = pinfo->dom_info + domain;
scmi_power_domain_attributes_get(ph, domain, dom, version);
scmi_power_domain_attributes_get(ph, domain, dom, version,
pinfo->notify_state_change_cmd);
}
pinfo->version = version;

View File

@ -124,6 +124,8 @@ struct scmi_powercap_state {
struct powercap_info {
u32 version;
int num_domains;
bool notify_cap_cmd;
bool notify_measurements_cmd;
struct scmi_powercap_state *states;
struct scmi_powercap_info *powercaps;
};
@ -157,6 +159,18 @@ scmi_powercap_attributes_get(const struct scmi_protocol_handle *ph,
}
ph->xops->xfer_put(ph, t);
if (!ret) {
if (!ph->hops->protocol_msg_check(ph,
POWERCAP_CAP_NOTIFY, NULL))
pi->notify_cap_cmd = true;
if (!ph->hops->protocol_msg_check(ph,
POWERCAP_MEASUREMENTS_NOTIFY,
NULL))
pi->notify_measurements_cmd = true;
}
return ret;
}
@ -200,10 +214,12 @@ scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
flags = le32_to_cpu(resp->attributes);
dom_info->id = domain;
dom_info->notify_powercap_cap_change =
SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(flags);
dom_info->notify_powercap_measurement_change =
SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
if (pinfo->notify_cap_cmd)
dom_info->notify_powercap_cap_change =
SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(flags);
if (pinfo->notify_measurements_cmd)
dom_info->notify_powercap_measurement_change =
SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
dom_info->async_powercap_cap_set =
SUPPORTS_ASYNC_POWERCAP_CAP_SET(flags);
dom_info->powercap_cap_config =
@ -788,6 +804,26 @@ static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
return ret;
}
static bool
scmi_powercap_notify_supported(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id)
{
bool supported = false;
const struct scmi_powercap_info *dom_info;
struct powercap_info *pi = ph->get_priv(ph);
if (evt_id >= ARRAY_SIZE(evt_2_cmd) || src_id >= pi->num_domains)
return false;
dom_info = pi->powercaps + src_id;
if (evt_id == SCMI_EVENT_POWERCAP_CAP_CHANGED)
supported = dom_info->notify_powercap_cap_change;
else if (evt_id == SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED)
supported = dom_info->notify_powercap_measurement_change;
return supported;
}
static int
scmi_powercap_set_notify_enabled(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enable)
@ -904,6 +940,7 @@ static const struct scmi_event powercap_events[] = {
};
static const struct scmi_event_ops powercap_event_ops = {
.is_notify_supported = scmi_powercap_notify_supported,
.get_num_sources = scmi_powercap_get_num_sources,
.set_notify_enabled = scmi_powercap_set_notify_enabled,
.fill_custom_report = scmi_powercap_fill_custom_report,

View File

@ -33,6 +33,7 @@ enum scmi_common_cmd {
PROTOCOL_VERSION = 0x0,
PROTOCOL_ATTRIBUTES = 0x1,
PROTOCOL_MESSAGE_ATTRIBUTES = 0x2,
NEGOTIATE_PROTOCOL_VERSION = 0x10,
};
/**
@ -251,6 +252,8 @@ struct scmi_fc_info {
* provided in @ops.
* @iter_response_run: A common helper to trigger the run of a previously
* initialized iterator.
* @protocol_msg_check: A common helper to check is a specific protocol message
* is supported.
* @fastchannel_init: A common helper used to initialize FC descriptors by
* gathering FC descriptions from the SCMI platform server.
* @fastchannel_db_ring: A common helper to ring a FC doorbell.
@ -264,6 +267,8 @@ struct scmi_proto_helpers_ops {
unsigned int max_resources, u8 msg_id,
size_t tx_size, void *priv);
int (*iter_response_run)(void *iter);
int (*protocol_msg_check)(const struct scmi_protocol_handle *ph,
u32 message_id, u32 *attributes);
void (*fastchannel_init)(const struct scmi_protocol_handle *ph,
u8 describe_id, u32 message_id,
u32 valid_size, u32 domain,

View File

@ -67,6 +67,7 @@ struct reset_dom_info {
struct scmi_reset_info {
u32 version;
int num_domains;
bool notify_reset_cmd;
struct reset_dom_info *dom_info;
};
@ -89,18 +90,24 @@ static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph,
}
ph->xops->xfer_put(ph, t);
if (!ret)
if (!ph->hops->protocol_msg_check(ph, RESET_NOTIFY, NULL))
pi->notify_reset_cmd = true;
return ret;
}
static int
scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
u32 domain, struct reset_dom_info *dom_info,
u32 version)
struct scmi_reset_info *pinfo,
u32 domain, u32 version)
{
int ret;
u32 attributes;
struct scmi_xfer *t;
struct scmi_msg_resp_reset_domain_attributes *attr;
struct reset_dom_info *dom_info = pinfo->dom_info + domain;
ret = ph->xops->xfer_get_init(ph, RESET_DOMAIN_ATTRIBUTES,
sizeof(domain), sizeof(*attr), &t);
@ -115,7 +122,9 @@ scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
attributes = le32_to_cpu(attr->attributes);
dom_info->async_reset = SUPPORTS_ASYNC_RESET(attributes);
dom_info->reset_notify = SUPPORTS_NOTIFY_RESET(attributes);
if (pinfo->notify_reset_cmd)
dom_info->reset_notify =
SUPPORTS_NOTIFY_RESET(attributes);
dom_info->latency_us = le32_to_cpu(attr->latency);
if (dom_info->latency_us == U32_MAX)
dom_info->latency_us = 0;
@ -226,6 +235,20 @@ static const struct scmi_reset_proto_ops reset_proto_ops = {
.deassert = scmi_reset_domain_deassert,
};
static bool scmi_reset_notify_supported(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id)
{
struct reset_dom_info *dom;
struct scmi_reset_info *pi = ph->get_priv(ph);
if (evt_id != SCMI_EVENT_RESET_ISSUED || src_id >= pi->num_domains)
return false;
dom = pi->dom_info + src_id;
return dom->reset_notify;
}
static int scmi_reset_notify(const struct scmi_protocol_handle *ph,
u32 domain_id, bool enable)
{
@ -301,6 +324,7 @@ static const struct scmi_event reset_events[] = {
};
static const struct scmi_event_ops reset_event_ops = {
.is_notify_supported = scmi_reset_notify_supported,
.get_num_sources = scmi_reset_get_num_sources,
.set_notify_enabled = scmi_reset_set_notify_enabled,
.fill_custom_report = scmi_reset_fill_custom_report,
@ -339,11 +363,8 @@ static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
if (!pinfo->dom_info)
return -ENOMEM;
for (domain = 0; domain < pinfo->num_domains; domain++) {
struct reset_dom_info *dom = pinfo->dom_info + domain;
scmi_reset_domain_attributes_get(ph, domain, dom, version);
}
for (domain = 0; domain < pinfo->num_domains; domain++)
scmi_reset_domain_attributes_get(ph, pinfo, domain, version);
pinfo->version = version;
return ph->set_priv(ph, pinfo, version);

View File

@ -215,6 +215,8 @@ struct scmi_sensor_update_notify_payld {
struct sensors_info {
u32 version;
bool notify_trip_point_cmd;
bool notify_continuos_update_cmd;
int num_sensors;
int max_requests;
u64 reg_addr;
@ -246,6 +248,18 @@ static int scmi_sensor_attributes_get(const struct scmi_protocol_handle *ph,
}
ph->xops->xfer_put(ph, t);
if (!ret) {
if (!ph->hops->protocol_msg_check(ph,
SENSOR_TRIP_POINT_NOTIFY, NULL))
si->notify_trip_point_cmd = true;
if (!ph->hops->protocol_msg_check(ph,
SENSOR_CONTINUOUS_UPDATE_NOTIFY,
NULL))
si->notify_continuos_update_cmd = true;
}
return ret;
}
@ -594,7 +608,8 @@ iter_sens_descr_process_response(const struct scmi_protocol_handle *ph,
* Such bitfields are assumed to be zeroed on non
* relevant fw versions...assuming fw not buggy !
*/
s->update = SUPPORTS_UPDATE_NOTIFY(attrl);
if (si->notify_continuos_update_cmd)
s->update = SUPPORTS_UPDATE_NOTIFY(attrl);
s->timestamped = SUPPORTS_TIMESTAMP(attrl);
if (s->timestamped)
s->tstamp_scale = S32_EXT(SENSOR_TSTAMP_EXP(attrl));
@ -988,6 +1003,25 @@ static const struct scmi_sensor_proto_ops sensor_proto_ops = {
.config_set = scmi_sensor_config_set,
};
static bool scmi_sensor_notify_supported(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id)
{
bool supported = false;
const struct scmi_sensor_info *s;
struct sensors_info *sinfo = ph->get_priv(ph);
s = scmi_sensor_info_get(ph, src_id);
if (!s)
return false;
if (evt_id == SCMI_EVENT_SENSOR_TRIP_POINT_EVENT)
supported = sinfo->notify_trip_point_cmd;
else if (evt_id == SCMI_EVENT_SENSOR_UPDATE)
supported = s->update;
return supported;
}
static int scmi_sensor_set_notify_enabled(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enable)
{
@ -1099,6 +1133,7 @@ static const struct scmi_event sensor_events[] = {
};
static const struct scmi_event_ops sensor_event_ops = {
.is_notify_supported = scmi_sensor_notify_supported,
.get_num_sources = scmi_sensor_get_num_sources,
.set_notify_enabled = scmi_sensor_set_notify_enabled,
.fill_custom_report = scmi_sensor_fill_custom_report,

View File

@ -214,6 +214,13 @@ static int smc_chan_free(int id, void *p, void *data)
struct scmi_chan_info *cinfo = p;
struct scmi_smc *scmi_info = cinfo->transport_info;
/*
* Different protocols might share the same chan info, so a previous
* smc_chan_free call might have already freed the structure.
*/
if (!scmi_info)
return 0;
/* Ignore any possible further reception on the IRQ path */
if (scmi_info->irq > 0)
free_irq(scmi_info->irq, scmi_info);

View File

@ -36,8 +36,20 @@ struct scmi_system_power_state_notifier_payld {
struct scmi_system_info {
u32 version;
bool graceful_timeout_supported;
bool power_state_notify_cmd;
};
static bool scmi_system_notify_supported(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id)
{
struct scmi_system_info *pinfo = ph->get_priv(ph);
if (evt_id != SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER)
return false;
return pinfo->power_state_notify_cmd;
}
static int scmi_system_request_notify(const struct scmi_protocol_handle *ph,
bool enable)
{
@ -114,6 +126,7 @@ static const struct scmi_event system_events[] = {
};
static const struct scmi_event_ops system_event_ops = {
.is_notify_supported = scmi_system_notify_supported,
.set_notify_enabled = scmi_system_set_notify_enabled,
.fill_custom_report = scmi_system_fill_custom_report,
};
@ -147,6 +160,9 @@ static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph)
if (PROTOCOL_REV_MAJOR(pinfo->version) >= 0x2)
pinfo->graceful_timeout_supported = true;
if (!ph->hops->protocol_msg_check(ph, SYSTEM_POWER_STATE_NOTIFY, NULL))
pinfo->power_state_notify_cmd = true;
return ph->set_priv(ph, pinfo, version);
}

View File

@ -77,7 +77,7 @@ static const char *get_filename(struct tegra_bpmp *bpmp,
root_path_buf = kzalloc(root_path_buf_len, GFP_KERNEL);
if (!root_path_buf)
goto out;
return NULL;
root_path = dentry_path(bpmp->debugfs_mirror, root_path_buf,
root_path_buf_len);

View File

@ -72,7 +72,6 @@ static DEFINE_SPINLOCK(emif_lock);
static unsigned long irq_state;
static LIST_HEAD(device_list);
#ifdef CONFIG_DEBUG_FS
static void do_emif_regdump_show(struct seq_file *s, struct emif_data *emif,
struct emif_regs *regs)
{
@ -140,31 +139,24 @@ static int emif_mr4_show(struct seq_file *s, void *unused)
DEFINE_SHOW_ATTRIBUTE(emif_mr4);
static int __init_or_module emif_debugfs_init(struct emif_data *emif)
static void emif_debugfs_init(struct emif_data *emif)
{
emif->debugfs_root = debugfs_create_dir(dev_name(emif->dev), NULL);
debugfs_create_file("regcache_dump", S_IRUGO, emif->debugfs_root, emif,
&emif_regdump_fops);
debugfs_create_file("mr4", S_IRUGO, emif->debugfs_root, emif,
&emif_mr4_fops);
return 0;
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
emif->debugfs_root = debugfs_create_dir(dev_name(emif->dev), NULL);
debugfs_create_file("regcache_dump", S_IRUGO, emif->debugfs_root, emif,
&emif_regdump_fops);
debugfs_create_file("mr4", S_IRUGO, emif->debugfs_root, emif,
&emif_mr4_fops);
}
}
static void __exit emif_debugfs_exit(struct emif_data *emif)
static void emif_debugfs_exit(struct emif_data *emif)
{
debugfs_remove_recursive(emif->debugfs_root);
emif->debugfs_root = NULL;
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
debugfs_remove_recursive(emif->debugfs_root);
emif->debugfs_root = NULL;
}
}
#else
static inline int __init_or_module emif_debugfs_init(struct emif_data *emif)
{
return 0;
}
static inline void __exit emif_debugfs_exit(struct emif_data *emif)
{
}
#endif
/*
* Get bus width used by EMIF. Note that this may be different from the
@ -679,7 +671,7 @@ static void disable_and_clear_all_interrupts(struct emif_data *emif)
clear_all_interrupts(emif);
}
static int __init_or_module setup_interrupts(struct emif_data *emif, u32 irq)
static int setup_interrupts(struct emif_data *emif, u32 irq)
{
u32 interrupts, type;
void __iomem *base = emif->base;
@ -710,7 +702,7 @@ static int __init_or_module setup_interrupts(struct emif_data *emif, u32 irq)
}
static void __init_or_module emif_onetime_settings(struct emif_data *emif)
static void emif_onetime_settings(struct emif_data *emif)
{
u32 pwr_mgmt_ctrl, zq, temp_alert_cfg;
void __iomem *base = emif->base;
@ -834,8 +826,7 @@ static int is_custom_config_valid(struct emif_custom_configs *cust_cfgs,
return valid;
}
#if defined(CONFIG_OF)
static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
static void of_get_custom_configs(struct device_node *np_emif,
struct emif_data *emif)
{
struct emif_custom_configs *cust_cfgs = NULL;
@ -884,7 +875,7 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
emif->plat_data->custom_configs = cust_cfgs;
}
static void __init_or_module of_get_ddr_info(struct device_node *np_emif,
static void of_get_ddr_info(struct device_node *np_emif,
struct device_node *np_ddr,
struct ddr_device_info *dev_info)
{
@ -918,7 +909,7 @@ static void __init_or_module of_get_ddr_info(struct device_node *np_emif,
dev_info->io_width = __fls(io_width) - 1;
}
static struct emif_data * __init_or_module of_get_memory_device_details(
static struct emif_data *of_get_memory_device_details(
struct device_node *np_emif, struct device *dev)
{
struct emif_data *emif = NULL;
@ -991,16 +982,7 @@ out:
return emif;
}
#else
static struct emif_data * __init_or_module of_get_memory_device_details(
struct device_node *np_emif, struct device *dev)
{
return NULL;
}
#endif
static struct emif_data *__init_or_module get_device_details(
static struct emif_data *get_device_details(
struct platform_device *pdev)
{
u32 size;
@ -1104,7 +1086,7 @@ error:
return NULL;
}
static int __init_or_module emif_probe(struct platform_device *pdev)
static int emif_probe(struct platform_device *pdev)
{
struct emif_data *emif;
int irq, ret;
@ -1159,7 +1141,7 @@ error:
return -ENODEV;
}
static void __exit emif_remove(struct platform_device *pdev)
static void emif_remove(struct platform_device *pdev)
{
struct emif_data *emif = platform_get_drvdata(pdev);
@ -1183,7 +1165,8 @@ MODULE_DEVICE_TABLE(of, emif_of_match);
#endif
static struct platform_driver emif_driver = {
.remove_new = __exit_p(emif_remove),
.probe = emif_probe,
.remove_new = emif_remove,
.shutdown = emif_shutdown,
.driver = {
.name = "emif",
@ -1191,7 +1174,7 @@ static struct platform_driver emif_driver = {
},
};
module_platform_driver_probe(emif_driver, emif_probe);
module_platform_driver(emif_driver);
MODULE_DESCRIPTION("TI EMIF SDRAM Controller Driver");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@ -92,6 +92,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0RDB,
.name = "dla0rdb",
.bpmp_id = TEGRA_ICC_BPMP_DLA_0,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@ -102,6 +104,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0RDB1,
.name = "dla0rdb1",
.bpmp_id = TEGRA_ICC_BPMP_DLA_0,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@ -112,6 +116,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0WRB,
.name = "dla0wrb",
.bpmp_id = TEGRA_ICC_BPMP_DLA_0,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@ -121,7 +127,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1RDB,
.name = "dla0rdb",
.name = "dla1rdb",
.bpmp_id = TEGRA_ICC_BPMP_DLA_1,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
@ -407,7 +415,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1RDB1,
.name = "dla0rdb1",
.name = "dla1rdb1",
.bpmp_id = TEGRA_ICC_BPMP_DLA_1,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
@ -417,7 +427,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1WRB,
.name = "dla0wrb",
.name = "dla1wrb",
.bpmp_id = TEGRA_ICC_BPMP_DLA_1,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
@ -539,7 +551,7 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
.bpmp_id = TEGRA_ICC_BPMP_NVJPG_0,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVJPG,
.regs = {
.regs = {
.sid = {
.override = 0x3f8,
.security = 0x3fc,
@ -660,6 +672,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0RDA,
.name = "dla0rda",
.bpmp_id = TEGRA_ICC_BPMP_DLA_0,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@ -670,6 +684,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0FALRDB,
.name = "dla0falrdb",
.bpmp_id = TEGRA_ICC_BPMP_DLA_0,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@ -680,6 +696,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0WRA,
.name = "dla0wra",
.bpmp_id = TEGRA_ICC_BPMP_DLA_0,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@ -690,6 +708,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0FALWRB,
.name = "dla0falwrb",
.bpmp_id = TEGRA_ICC_BPMP_DLA_0,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@ -699,7 +719,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1RDA,
.name = "dla0rda",
.name = "dla1rda",
.bpmp_id = TEGRA_ICC_BPMP_DLA_1,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
@ -709,7 +731,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1FALRDB,
.name = "dla0falrdb",
.name = "dla1falrdb",
.bpmp_id = TEGRA_ICC_BPMP_DLA_1,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
@ -719,7 +743,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1WRA,
.name = "dla0wra",
.name = "dla1wra",
.bpmp_id = TEGRA_ICC_BPMP_DLA_1,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
@ -729,7 +755,9 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1FALWRB,
.name = "dla0falwrb",
.name = "dla1falwrb",
.bpmp_id = TEGRA_ICC_BPMP_DLA_1,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {
@ -908,6 +936,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0RDA1,
.name = "dla0rda1",
.bpmp_id = TEGRA_ICC_BPMP_DLA_0,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_NVDLA0,
.regs = {
.sid = {
@ -917,7 +947,7 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA1RDA1,
.name = "dla0rda1",
.name = "dla1rda1",
.sid = TEGRA234_SID_NVDLA1,
.regs = {
.sid = {

View File

@ -217,7 +217,6 @@ static struct rpmhpd *sa8540p_rpmhpds[] = {
[SC8280XP_CX] = &cx,
[SC8280XP_CX_AO] = &cx_ao,
[SC8280XP_EBI] = &ebi,
[SC8280XP_GFX] = &gfx,
[SC8280XP_LCX] = &lcx,
[SC8280XP_LMX] = &lmx,
[SC8280XP_MMCX] = &mmcx,

View File

@ -68,4 +68,13 @@ config MTK_SVS
chip process corner, temperatures and other factors. Then DVFS
driver could apply SVS bank voltage to PMIC/Buck.
config MTK_SOCINFO
tristate "MediaTek SoC Information"
default y
depends on NVMEM_MTK_EFUSE
help
The MediaTek SoC Information (mtk-socinfo) driver provides
information about the SoC to the userspace including the
manufacturer name, marketing name and soc name.
endmenu

View File

@ -7,3 +7,4 @@ obj-$(CONFIG_MTK_REGULATOR_COUPLER) += mtk-regulator-coupler.o
obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o
obj-$(CONFIG_MTK_SVS) += mtk-svs.o
obj-$(CONFIG_MTK_SOCINFO) += mtk-socinfo.o

View File

@ -0,0 +1,191 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023 MediaTek Inc.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/nvmem-consumer.h>
#include <linux/device.h>
#include <linux/device/bus.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/string.h>
#include <linux/sys_soc.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#define MTK_SOCINFO_ENTRY(_soc_name, _segment_name, _marketing_name, _cell_data1, _cell_data2) {\
.soc_name = _soc_name, \
.segment_name = _segment_name, \
.marketing_name = _marketing_name, \
.cell_data = {_cell_data1, _cell_data2} \
}
#define CELL_NOT_USED (0xFFFFFFFF)
#define MAX_CELLS (2)
struct mtk_socinfo {
struct device *dev;
struct name_data *name_data;
struct socinfo_data *socinfo_data;
struct soc_device *soc_dev;
};
struct socinfo_data {
char *soc_name;
char *segment_name;
char *marketing_name;
u32 cell_data[MAX_CELLS];
};
static const char *cell_names[MAX_CELLS] = {"socinfo-data1", "socinfo-data2"};
static struct socinfo_data socinfo_data_table[] = {
MTK_SOCINFO_ENTRY("MT8173", "MT8173V/AC", "MT8173", 0x6CA20004, 0x10000000),
MTK_SOCINFO_ENTRY("MT8183", "MT8183V/AZA", "Kompanio 500", 0x00010043, 0x00000840),
MTK_SOCINFO_ENTRY("MT8183", "MT8183V/AZA", "Kompanio 500", 0x00010043, 0x00000940),
MTK_SOCINFO_ENTRY("MT8186", "MT8186GV/AZA", "Kompanio 520", 0x81861001, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8186T", "MT8186TV/AZA", "Kompanio 528", 0x81862001, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8188", "MT8188GV/AZA", "Kompanio 830", 0x81880000, 0x00000010),
MTK_SOCINFO_ENTRY("MT8188", "MT8188GV/HZA", "Kompanio 830", 0x81880000, 0x00000011),
MTK_SOCINFO_ENTRY("MT8192", "MT8192V/AZA", "Kompanio 820", 0x00001100, 0x00040080),
MTK_SOCINFO_ENTRY("MT8192T", "MT8192V/ATZA", "Kompanio 828", 0x00000100, 0x000400C0),
MTK_SOCINFO_ENTRY("MT8195", "MT8195GV/EZA", "Kompanio 1200", 0x81950300, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8195", "MT8195GV/EHZA", "Kompanio 1200", 0x81950304, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EZA", "Kompanio 1380", 0x81950400, CELL_NOT_USED),
MTK_SOCINFO_ENTRY("MT8195", "MT8195TV/EHZA", "Kompanio 1380", 0x81950404, CELL_NOT_USED),
};
static int mtk_socinfo_create_socinfo_node(struct mtk_socinfo *mtk_socinfop)
{
struct soc_device_attribute *attrs;
static char machine[30] = {0};
static const char *soc_manufacturer = "MediaTek";
attrs = devm_kzalloc(mtk_socinfop->dev, sizeof(*attrs), GFP_KERNEL);
if (!attrs)
return -ENOMEM;
snprintf(machine, sizeof(machine), "%s (%s)", mtk_socinfop->socinfo_data->marketing_name,
mtk_socinfop->socinfo_data->soc_name);
attrs->family = soc_manufacturer;
attrs->machine = machine;
mtk_socinfop->soc_dev = soc_device_register(attrs);
if (IS_ERR(mtk_socinfop->soc_dev))
return PTR_ERR(mtk_socinfop->soc_dev);
dev_info(mtk_socinfop->dev, "%s %s SoC detected.\n", soc_manufacturer, attrs->machine);
return 0;
}
static u32 mtk_socinfo_read_cell(struct device *dev, const char *name)
{
struct nvmem_device *nvmemp;
struct device_node *np, *nvmem_node = dev->parent->of_node;
u32 offset;
u32 cell_val = CELL_NOT_USED;
/* should never fail since the nvmem driver registers this child */
nvmemp = nvmem_device_find(nvmem_node, device_match_of_node);
if (IS_ERR(nvmemp))
goto out;
np = of_get_child_by_name(nvmem_node, name);
if (!np)
goto put_device;
if (of_property_read_u32_index(np, "reg", 0, &offset))
goto put_node;
nvmem_device_read(nvmemp, offset, sizeof(cell_val), &cell_val);
put_node:
of_node_put(np);
put_device:
nvmem_device_put(nvmemp);
out:
return cell_val;
}
static int mtk_socinfo_get_socinfo_data(struct mtk_socinfo *mtk_socinfop)
{
unsigned int i, j;
unsigned int num_cell_data = 0;
u32 cell_data[MAX_CELLS] = {0};
bool match_socinfo;
int match_socinfo_index = -1;
for (i = 0; i < MAX_CELLS; i++) {
cell_data[i] = mtk_socinfo_read_cell(mtk_socinfop->dev, cell_names[i]);
if (cell_data[i] != CELL_NOT_USED)
num_cell_data++;
else
break;
}
if (!num_cell_data)
return -ENOENT;
for (i = 0; i < ARRAY_SIZE(socinfo_data_table); i++) {
match_socinfo = true;
for (j = 0; j < num_cell_data; j++) {
if (cell_data[j] != socinfo_data_table[i].cell_data[j]) {
match_socinfo = false;
break;
}
}
if (match_socinfo) {
mtk_socinfop->socinfo_data = &(socinfo_data_table[i]);
match_socinfo_index = i;
break;
}
}
return match_socinfo_index >= 0 ? match_socinfo_index : -ENOENT;
}
static int mtk_socinfo_probe(struct platform_device *pdev)
{
struct mtk_socinfo *mtk_socinfop;
int ret;
mtk_socinfop = devm_kzalloc(&pdev->dev, sizeof(*mtk_socinfop), GFP_KERNEL);
if (!mtk_socinfop)
return -ENOMEM;
mtk_socinfop->dev = &pdev->dev;
ret = mtk_socinfo_get_socinfo_data(mtk_socinfop);
if (ret < 0)
return dev_err_probe(mtk_socinfop->dev, ret, "Failed to get socinfo data\n");
ret = mtk_socinfo_create_socinfo_node(mtk_socinfop);
if (ret)
return dev_err_probe(mtk_socinfop->dev, ret, "Cannot create node\n");
platform_set_drvdata(pdev, mtk_socinfop);
return 0;
}
static void mtk_socinfo_remove(struct platform_device *pdev)
{
struct mtk_socinfo *mtk_socinfop = platform_get_drvdata(pdev);
soc_device_unregister(mtk_socinfop->soc_dev);
}
static struct platform_driver mtk_socinfo = {
.probe = mtk_socinfo_probe,
.remove_new = mtk_socinfo_remove,
.driver = {
.name = "mtk-socinfo",
},
};
module_platform_driver(mtk_socinfo);
MODULE_AUTHOR("William-TW LIN <william-tw.lin@mediatek.com>");
MODULE_DESCRIPTION("MediaTek socinfo driver");
MODULE_LICENSE("GPL");

View File

@ -268,4 +268,13 @@ config QCOM_INLINE_CRYPTO_ENGINE
tristate
select QCOM_SCM
config QCOM_PBS
tristate "PBS trigger support for Qualcomm Technologies, Inc. PMICS"
depends on SPMI
help
This driver supports configuring software programmable boot sequencer (PBS)
trigger event through PBS RAM on Qualcomm Technologies, Inc. PMICs.
This module provides the APIs to the client drivers that wants to send the
PBS trigger event to the PBS RAM.
endmenu

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
CFLAGS_rpmh-rsc.o := -I$(src)
CFLAGS_qcom_aoss.o := -I$(src)
obj-$(CONFIG_QCOM_AOSS_QMP) += qcom_aoss.o
obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o
obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
@ -34,3 +35,4 @@ obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o
obj-$(CONFIG_QCOM_ICC_BWMON) += icc-bwmon.o
qcom_ice-objs += ice.o
obj-$(CONFIG_QCOM_INLINE_CRYPTO_ENGINE) += qcom_ice.o
obj-$(CONFIG_QCOM_PBS) += qcom-pbs.o

View File

@ -399,7 +399,7 @@ static int apr_uevent(const struct device *dev, struct kobj_uevent_env *env)
return add_uevent_var(env, "MODALIAS=apr:%s", adev->name);
}
struct bus_type aprbus = {
const struct bus_type aprbus = {
.name = "aprbus",
.match = apr_device_match,
.probe = apr_device_probe,

View File

@ -859,6 +859,8 @@ static int llcc_update_act_ctrl(u32 sid,
ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
slice_status, !(slice_status & status),
0, LLCC_STATUS_READ_DELAY);
if (ret)
return ret;
if (drv_data->version >= LLCC_VERSION_4_1_0_0)
ret = regmap_write(drv_data->bcast_regmap, act_clear_reg,

View File

@ -89,7 +89,6 @@
* @base: Base address of this instance of QUP wrapper core
* @clks: Handle to the primary & optional secondary AHB clocks
* @num_clks: Count of clocks
* @to_core: Core ICC path
*/
struct geni_wrapper {
struct device *dev;

236
drivers/soc/qcom/qcom-pbs.c Normal file
View File

@ -0,0 +1,236 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <linux/spmi.h>
#include <linux/soc/qcom/qcom-pbs.h>
#define PBS_CLIENT_TRIG_CTL 0x42
#define PBS_CLIENT_SW_TRIG_BIT BIT(7)
#define PBS_CLIENT_SCRATCH1 0x50
#define PBS_CLIENT_SCRATCH2 0x51
#define PBS_CLIENT_SCRATCH2_ERROR 0xFF
#define RETRIES 2000
#define DELAY 1100
struct pbs_dev {
struct device *dev;
struct regmap *regmap;
struct mutex lock;
struct device_link *link;
u32 base;
};
static int qcom_pbs_wait_for_ack(struct pbs_dev *pbs, u8 bit_pos)
{
unsigned int val;
int ret;
ret = regmap_read_poll_timeout(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2,
val, val & BIT(bit_pos), DELAY, DELAY * RETRIES);
if (ret < 0) {
dev_err(pbs->dev, "Timeout for PBS ACK/NACK for bit %u\n", bit_pos);
return -ETIMEDOUT;
}
if (val == PBS_CLIENT_SCRATCH2_ERROR) {
ret = regmap_write(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, 0);
dev_err(pbs->dev, "NACK from PBS for bit %u\n", bit_pos);
return -EINVAL;
}
dev_dbg(pbs->dev, "PBS sequence for bit %u executed!\n", bit_pos);
return 0;
}
/**
* qcom_pbs_trigger_event() - Trigger the PBS RAM sequence
* @pbs: Pointer to PBS device
* @bitmap: bitmap
*
* This function is used to trigger the PBS RAM sequence to be
* executed by the client driver.
*
* The PBS trigger sequence involves
* 1. setting the PBS sequence bit in PBS_CLIENT_SCRATCH1
* 2. Initiating the SW PBS trigger
* 3. Checking the equivalent bit in PBS_CLIENT_SCRATCH2 for the
* completion of the sequence.
* 4. If PBS_CLIENT_SCRATCH2 == 0xFF, the PBS sequence failed to execute
*
* Return: 0 on success, < 0 on failure
*/
int qcom_pbs_trigger_event(struct pbs_dev *pbs, u8 bitmap)
{
unsigned int val;
u16 bit_pos;
int ret;
if (WARN_ON(!bitmap))
return -EINVAL;
if (IS_ERR_OR_NULL(pbs))
return -EINVAL;
mutex_lock(&pbs->lock);
ret = regmap_read(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, &val);
if (ret < 0)
goto out;
if (val == PBS_CLIENT_SCRATCH2_ERROR) {
/* PBS error - clear SCRATCH2 register */
ret = regmap_write(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, 0);
if (ret < 0)
goto out;
}
for (bit_pos = 0; bit_pos < 8; bit_pos++) {
if (!(bitmap & BIT(bit_pos)))
continue;
/* Clear the PBS sequence bit position */
ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2,
BIT(bit_pos), 0);
if (ret < 0)
goto out_clear_scratch1;
/* Set the PBS sequence bit position */
ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH1,
BIT(bit_pos), BIT(bit_pos));
if (ret < 0)
goto out_clear_scratch1;
/* Initiate the SW trigger */
ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_TRIG_CTL,
PBS_CLIENT_SW_TRIG_BIT, PBS_CLIENT_SW_TRIG_BIT);
if (ret < 0)
goto out_clear_scratch1;
ret = qcom_pbs_wait_for_ack(pbs, bit_pos);
if (ret < 0)
goto out_clear_scratch1;
/* Clear the PBS sequence bit position */
regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH1, BIT(bit_pos), 0);
regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, BIT(bit_pos), 0);
}
out_clear_scratch1:
/* Clear all the requested bitmap */
ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH1, bitmap, 0);
out:
mutex_unlock(&pbs->lock);
return ret;
}
EXPORT_SYMBOL_GPL(qcom_pbs_trigger_event);
/**
* get_pbs_client_device() - Get the PBS device used by client
* @dev: Client device
*
* This function is used to get the PBS device that is being
* used by the client.
*
* Return: pbs_dev on success, ERR_PTR on failure
*/
struct pbs_dev *get_pbs_client_device(struct device *dev)
{
struct device_node *pbs_dev_node;
struct platform_device *pdev;
struct pbs_dev *pbs;
pbs_dev_node = of_parse_phandle(dev->of_node, "qcom,pbs", 0);
if (!pbs_dev_node) {
dev_err(dev, "Missing qcom,pbs property\n");
return ERR_PTR(-ENODEV);
}
pdev = of_find_device_by_node(pbs_dev_node);
if (!pdev) {
dev_err(dev, "Unable to find PBS dev_node\n");
pbs = ERR_PTR(-EPROBE_DEFER);
goto out;
}
pbs = platform_get_drvdata(pdev);
if (!pbs) {
dev_err(dev, "Cannot get pbs instance from %s\n", dev_name(&pdev->dev));
platform_device_put(pdev);
pbs = ERR_PTR(-EPROBE_DEFER);
goto out;
}
pbs->link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
if (!pbs->link) {
dev_err(&pdev->dev, "Failed to create device link to consumer %s\n", dev_name(dev));
platform_device_put(pdev);
pbs = ERR_PTR(-EINVAL);
goto out;
}
out:
of_node_put(pbs_dev_node);
return pbs;
}
EXPORT_SYMBOL_GPL(get_pbs_client_device);
static int qcom_pbs_probe(struct platform_device *pdev)
{
struct pbs_dev *pbs;
u32 val;
int ret;
pbs = devm_kzalloc(&pdev->dev, sizeof(*pbs), GFP_KERNEL);
if (!pbs)
return -ENOMEM;
pbs->dev = &pdev->dev;
pbs->regmap = dev_get_regmap(pbs->dev->parent, NULL);
if (!pbs->regmap) {
dev_err(pbs->dev, "Couldn't get parent's regmap\n");
return -EINVAL;
}
ret = device_property_read_u32(pbs->dev, "reg", &val);
if (ret < 0) {
dev_err(pbs->dev, "Couldn't find reg, ret = %d\n", ret);
return ret;
}
pbs->base = val;
mutex_init(&pbs->lock);
platform_set_drvdata(pdev, pbs);
return 0;
}
static const struct of_device_id qcom_pbs_match_table[] = {
{ .compatible = "qcom,pbs" },
{}
};
MODULE_DEVICE_TABLE(of, qcom_pbs_match_table);
static struct platform_driver qcom_pbs_driver = {
.driver = {
.name = "qcom-pbs",
.of_match_table = qcom_pbs_match_table,
},
.probe = qcom_pbs_probe,
};
module_platform_driver(qcom_pbs_driver)
MODULE_DESCRIPTION("QCOM PBS DRIVER");
MODULE_LICENSE("GPL");

View File

@ -3,6 +3,7 @@
* Copyright (c) 2019, Linaro Ltd
*/
#include <linux/clk-provider.h>
#include <linux/debugfs.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/mailbox_client.h>
@ -13,6 +14,9 @@
#include <linux/slab.h>
#include <linux/soc/qcom/qcom_aoss.h>
#define CREATE_TRACE_POINTS
#include "trace-aoss.h"
#define QMP_DESC_MAGIC 0x0
#define QMP_DESC_VERSION 0x4
#define QMP_DESC_FEATURES 0x8
@ -44,6 +48,8 @@
#define QMP_NUM_COOLING_RESOURCES 2
#define QMP_DEBUGFS_FILES 4
static bool qmp_cdev_max_state = 1;
struct qmp_cooling_device {
@ -65,6 +71,8 @@ struct qmp_cooling_device {
* @tx_lock: provides synchronization between multiple callers of qmp_send()
* @qdss_clk: QDSS clock hw struct
* @cooling_devs: thermal cooling devices
* @debugfs_root: directory for the developer/tester interface
* @debugfs_files: array of individual debugfs entries under debugfs_root
*/
struct qmp {
void __iomem *msgram;
@ -82,6 +90,8 @@ struct qmp {
struct clk_hw qdss_clk;
struct qmp_cooling_device *cooling_devs;
struct dentry *debugfs_root;
struct dentry *debugfs_files[QMP_DEBUGFS_FILES];
};
static void qmp_kick(struct qmp *qmp)
@ -214,7 +224,7 @@ static bool qmp_message_empty(struct qmp *qmp)
*
* Return: 0 on success, negative errno on failure
*/
int qmp_send(struct qmp *qmp, const char *fmt, ...)
int __printf(2, 3) qmp_send(struct qmp *qmp, const char *fmt, ...)
{
char buf[QMP_MSG_LEN];
long time_left;
@ -235,6 +245,8 @@ int qmp_send(struct qmp *qmp, const char *fmt, ...)
mutex_lock(&qmp->tx_lock);
trace_aoss_send(buf);
/* The message RAM only implements 32-bit accesses */
__iowrite32_copy(qmp->msgram + qmp->offset + sizeof(u32),
buf, sizeof(buf) / sizeof(u32));
@ -256,6 +268,8 @@ int qmp_send(struct qmp *qmp, const char *fmt, ...)
ret = 0;
}
trace_aoss_send_done(buf, ret);
mutex_unlock(&qmp->tx_lock);
return ret;
@ -475,6 +489,91 @@ void qmp_put(struct qmp *qmp)
}
EXPORT_SYMBOL_GPL(qmp_put);
struct qmp_debugfs_entry {
const char *name;
const char *fmt;
bool is_bool;
const char *true_val;
const char *false_val;
};
static const struct qmp_debugfs_entry qmp_debugfs_entries[QMP_DEBUGFS_FILES] = {
{ "ddr_frequency_mhz", "{class: ddr, res: fixed, val: %u}", false },
{ "prevent_aoss_sleep", "{class: aoss_slp, res: sleep: %s}", true, "enable", "disable" },
{ "prevent_cx_collapse", "{class: cx_mol, res: cx, val: %s}", true, "mol", "off" },
{ "prevent_ddr_collapse", "{class: ddr_mol, res: ddr, val: %s}", true, "mol", "off" },
};
static ssize_t qmp_debugfs_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *pos)
{
const struct qmp_debugfs_entry *entry = NULL;
struct qmp *qmp = file->private_data;
char buf[QMP_MSG_LEN];
unsigned int uint_val;
const char *str_val;
bool bool_val;
int ret;
int i;
for (i = 0; i < ARRAY_SIZE(qmp->debugfs_files); i++) {
if (qmp->debugfs_files[i] == file->f_path.dentry) {
entry = &qmp_debugfs_entries[i];
break;
}
}
if (WARN_ON(!entry))
return -EFAULT;
if (entry->is_bool) {
ret = kstrtobool_from_user(user_buf, count, &bool_val);
if (ret)
return ret;
str_val = bool_val ? entry->true_val : entry->false_val;
ret = snprintf(buf, sizeof(buf), entry->fmt, str_val);
if (ret >= sizeof(buf))
return -EINVAL;
} else {
ret = kstrtou32_from_user(user_buf, count, 0, &uint_val);
if (ret)
return ret;
ret = snprintf(buf, sizeof(buf), entry->fmt, uint_val);
if (ret >= sizeof(buf))
return -EINVAL;
}
ret = qmp_send(qmp, buf);
if (ret < 0)
return ret;
return count;
}
static const struct file_operations qmp_debugfs_fops = {
.open = simple_open,
.write = qmp_debugfs_write,
};
static void qmp_debugfs_create(struct qmp *qmp)
{
const struct qmp_debugfs_entry *entry;
int i;
qmp->debugfs_root = debugfs_create_dir("qcom_aoss", NULL);
for (i = 0; i < ARRAY_SIZE(qmp->debugfs_files); i++) {
entry = &qmp_debugfs_entries[i];
qmp->debugfs_files[i] = debugfs_create_file(entry->name, 0200,
qmp->debugfs_root,
qmp,
&qmp_debugfs_fops);
}
}
static int qmp_probe(struct platform_device *pdev)
{
struct qmp *qmp;
@ -523,6 +622,8 @@ static int qmp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, qmp);
qmp_debugfs_create(qmp);
return 0;
err_close_qmp:
@ -537,6 +638,8 @@ static void qmp_remove(struct platform_device *pdev)
{
struct qmp *qmp = platform_get_drvdata(pdev);
debugfs_remove_recursive(qmp->debugfs_root);
qmp_qdss_clk_remove(qmp);
qmp_cooling_devices_remove(qmp);

View File

@ -655,8 +655,6 @@ invalid_canary:
void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
{
struct smem_partition *part;
unsigned long flags;
int ret;
void *ptr = ERR_PTR(-EPROBE_DEFER);
if (!__smem)
@ -665,12 +663,6 @@ void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
if (WARN_ON(item >= __smem->item_count))
return ERR_PTR(-EINVAL);
ret = hwspin_lock_timeout_irqsave(__smem->hwlock,
HWSPINLOCK_TIMEOUT,
&flags);
if (ret)
return ERR_PTR(ret);
if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) {
part = &__smem->partitions[host];
ptr = qcom_smem_get_private(__smem, part, item, size);
@ -681,10 +673,7 @@ void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
ptr = qcom_smem_get_global(__smem, item, size);
}
hwspin_unlock_irqrestore(__smem->hwlock, &flags);
return ptr;
}
EXPORT_SYMBOL_GPL(qcom_smem_get);

View File

@ -58,8 +58,8 @@
* @valid_entries: number of allocated entries
* @flags:
* @entries: individual communication entries
* @name: name of the entry
* @value: content of the entry
* @entries.name: name of the entry
* @entries.value: content of the entry
*/
struct smp2p_smem_item {
u32 magic;
@ -275,6 +275,8 @@ static void qcom_smp2p_notify_in(struct qcom_smp2p *smp2p)
*
* Handle notifications from the remote side to handle newly allocated entries
* or any changes to the state bits of existing entries.
*
* Return: %IRQ_HANDLED
*/
static irqreturn_t qcom_smp2p_intr(int irq, void *data)
{

View File

@ -124,7 +124,7 @@ static const char *const pmic_models[] = {
[50] = "PM8350B",
[51] = "PMR735A",
[52] = "PMR735B",
[55] = "PM2250",
[55] = "PM4125",
[58] = "PM8450",
[65] = "PM8010",
[69] = "PM8550VS",
@ -424,8 +424,11 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(IPQ9510) },
{ qcom_board_id(QRB4210) },
{ qcom_board_id(QRB2210) },
{ qcom_board_id(SM8475) },
{ qcom_board_id(SM8475P) },
{ qcom_board_id(SA8775P) },
{ qcom_board_id(QRU1000) },
{ qcom_board_id(SM8475_2) },
{ qcom_board_id(QDU1000) },
{ qcom_board_id(SM8650) },
{ qcom_board_id(SM4450) },
@ -437,6 +440,8 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(IPQ5322) },
{ qcom_board_id(IPQ5312) },
{ qcom_board_id(IPQ5302) },
{ qcom_board_id(QCS8550) },
{ qcom_board_id(QCM8550) },
{ qcom_board_id(IPQ5300) },
};

View File

@ -6,20 +6,40 @@
* SAW power controller driver
*/
#include <linux/kernel.h>
#include <linux/bitfield.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/linear_range.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/regulator/driver.h>
#include <soc/qcom/spm.h>
#define FIELD_SET(current, mask, val) \
(((current) & ~(mask)) | FIELD_PREP((mask), (val)))
#define SPM_CTL_INDEX 0x7f
#define SPM_CTL_INDEX_SHIFT 4
#define SPM_CTL_EN BIT(0)
/* These registers might be specific to SPM 1.1 */
#define SPM_VCTL_VLVL GENMASK(7, 0)
#define SPM_PMIC_DATA_0_VLVL GENMASK(7, 0)
#define SPM_PMIC_DATA_1_MIN_VSEL GENMASK(5, 0)
#define SPM_PMIC_DATA_1_MAX_VSEL GENMASK(21, 16)
#define SPM_1_1_AVS_CTL_AVS_ENABLED BIT(27)
#define SPM_AVS_CTL_MAX_VLVL GENMASK(22, 17)
#define SPM_AVS_CTL_MIN_VLVL GENMASK(15, 10)
enum spm_reg {
SPM_REG_CFG,
SPM_REG_SPM_CTL,
@ -29,13 +49,44 @@ enum spm_reg {
SPM_REG_PMIC_DATA_1,
SPM_REG_VCTL,
SPM_REG_SEQ_ENTRY,
SPM_REG_SPM_STS,
SPM_REG_STS0,
SPM_REG_STS1,
SPM_REG_PMIC_STS,
SPM_REG_AVS_CTL,
SPM_REG_AVS_LIMIT,
SPM_REG_RST,
SPM_REG_NR,
};
#define MAX_PMIC_DATA 2
#define MAX_SEQ_DATA 64
struct spm_reg_data {
const u16 *reg_offset;
u32 spm_cfg;
u32 spm_dly;
u32 pmic_dly;
u32 pmic_data[MAX_PMIC_DATA];
u32 avs_ctl;
u32 avs_limit;
u8 seq[MAX_SEQ_DATA];
u8 start_index[PM_SLEEP_MODE_NR];
smp_call_func_t set_vdd;
/* for now we support only a single range */
struct linear_range *range;
unsigned int ramp_delay;
unsigned int init_uV;
};
struct spm_driver_data {
void __iomem *reg_base;
const struct spm_reg_data *reg_data;
struct device *dev;
unsigned int volt_sel;
int reg_cpu;
};
static const u16 spm_reg_offset_v4_1[SPM_REG_NR] = {
[SPM_REG_AVS_CTL] = 0x904,
[SPM_REG_AVS_LIMIT] = 0x908,
@ -169,6 +220,10 @@ static const struct spm_reg_data spm_reg_8226_cpu = {
static const u16 spm_reg_offset_v1_1[SPM_REG_NR] = {
[SPM_REG_CFG] = 0x08,
[SPM_REG_STS0] = 0x0c,
[SPM_REG_STS1] = 0x10,
[SPM_REG_VCTL] = 0x14,
[SPM_REG_AVS_CTL] = 0x18,
[SPM_REG_SPM_CTL] = 0x20,
[SPM_REG_PMIC_DLY] = 0x24,
[SPM_REG_PMIC_DATA_0] = 0x28,
@ -176,7 +231,12 @@ static const u16 spm_reg_offset_v1_1[SPM_REG_NR] = {
[SPM_REG_SEQ_ENTRY] = 0x80,
};
static void smp_set_vdd_v1_1(void *data);
/* SPM register data for 8064 */
static struct linear_range spm_v1_1_regulator_range =
REGULATOR_LINEAR_RANGE(700000, 0, 56, 12500);
static const struct spm_reg_data spm_reg_8064_cpu = {
.reg_offset = spm_reg_offset_v1_1,
.spm_cfg = 0x1F,
@ -187,6 +247,10 @@ static const struct spm_reg_data spm_reg_8064_cpu = {
0x10, 0x54, 0x30, 0x0C, 0x24, 0x30, 0x0F },
.start_index[PM_SLEEP_MODE_STBY] = 0,
.start_index[PM_SLEEP_MODE_SPC] = 2,
.set_vdd = smp_set_vdd_v1_1,
.range = &spm_v1_1_regulator_range,
.init_uV = 1300000,
.ramp_delay = 1250,
};
static inline void spm_register_write(struct spm_driver_data *drv,
@ -238,6 +302,178 @@ void spm_set_low_power_mode(struct spm_driver_data *drv,
spm_register_write_sync(drv, SPM_REG_SPM_CTL, ctl_val);
}
static int spm_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector)
{
struct spm_driver_data *drv = rdev_get_drvdata(rdev);
drv->volt_sel = selector;
/* Always do the SAW register writes on the corresponding CPU */
return smp_call_function_single(drv->reg_cpu, drv->reg_data->set_vdd, drv, true);
}
static int spm_get_voltage_sel(struct regulator_dev *rdev)
{
struct spm_driver_data *drv = rdev_get_drvdata(rdev);
return drv->volt_sel;
}
static const struct regulator_ops spm_reg_ops = {
.set_voltage_sel = spm_set_voltage_sel,
.get_voltage_sel = spm_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear_range,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
};
static void smp_set_vdd_v1_1(void *data)
{
struct spm_driver_data *drv = data;
unsigned int vctl, data0, data1, avs_ctl, sts;
unsigned int vlevel, volt_sel;
bool avs_enabled;
volt_sel = drv->volt_sel;
vlevel = volt_sel | 0x80; /* band */
avs_ctl = spm_register_read(drv, SPM_REG_AVS_CTL);
vctl = spm_register_read(drv, SPM_REG_VCTL);
data0 = spm_register_read(drv, SPM_REG_PMIC_DATA_0);
data1 = spm_register_read(drv, SPM_REG_PMIC_DATA_1);
avs_enabled = avs_ctl & SPM_1_1_AVS_CTL_AVS_ENABLED;
/* If AVS is enabled, switch it off during the voltage change */
if (avs_enabled) {
avs_ctl &= ~SPM_1_1_AVS_CTL_AVS_ENABLED;
spm_register_write(drv, SPM_REG_AVS_CTL, avs_ctl);
}
/* Kick the state machine back to idle */
spm_register_write(drv, SPM_REG_RST, 1);
vctl = FIELD_SET(vctl, SPM_VCTL_VLVL, vlevel);
data0 = FIELD_SET(data0, SPM_PMIC_DATA_0_VLVL, vlevel);
data1 = FIELD_SET(data1, SPM_PMIC_DATA_1_MIN_VSEL, volt_sel);
data1 = FIELD_SET(data1, SPM_PMIC_DATA_1_MAX_VSEL, volt_sel);
spm_register_write(drv, SPM_REG_VCTL, vctl);
spm_register_write(drv, SPM_REG_PMIC_DATA_0, data0);
spm_register_write(drv, SPM_REG_PMIC_DATA_1, data1);
if (read_poll_timeout_atomic(spm_register_read,
sts, sts == vlevel,
1, 200, false,
drv, SPM_REG_STS1)) {
dev_err_ratelimited(drv->dev, "timeout setting the voltage (%x %x)!\n", sts, vlevel);
goto enable_avs;
}
if (avs_enabled) {
unsigned int max_avs = volt_sel;
unsigned int min_avs = max(max_avs, 4U) - 4;
avs_ctl = FIELD_SET(avs_ctl, SPM_AVS_CTL_MIN_VLVL, min_avs);
avs_ctl = FIELD_SET(avs_ctl, SPM_AVS_CTL_MAX_VLVL, max_avs);
spm_register_write(drv, SPM_REG_AVS_CTL, avs_ctl);
}
enable_avs:
if (avs_enabled) {
avs_ctl |= SPM_1_1_AVS_CTL_AVS_ENABLED;
spm_register_write(drv, SPM_REG_AVS_CTL, avs_ctl);
}
}
static int spm_get_cpu(struct device *dev)
{
int cpu;
bool found;
for_each_possible_cpu(cpu) {
struct device_node *cpu_node, *saw_node;
cpu_node = of_cpu_device_node_get(cpu);
if (!cpu_node)
continue;
saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0);
found = (saw_node == dev->of_node);
of_node_put(saw_node);
of_node_put(cpu_node);
if (found)
return cpu;
}
/* L2 SPM is not bound to any CPU, voltage setting is not supported */
return -EOPNOTSUPP;
}
static int spm_register_regulator(struct device *dev, struct spm_driver_data *drv)
{
struct regulator_config config = {
.dev = dev,
.driver_data = drv,
};
struct regulator_desc *rdesc;
struct regulator_dev *rdev;
int ret;
bool found;
if (!drv->reg_data->set_vdd)
return 0;
rdesc = devm_kzalloc(dev, sizeof(*rdesc), GFP_KERNEL);
if (!rdesc)
return -ENOMEM;
rdesc->name = "spm";
rdesc->of_match = of_match_ptr("regulator");
rdesc->type = REGULATOR_VOLTAGE;
rdesc->owner = THIS_MODULE;
rdesc->ops = &spm_reg_ops;
rdesc->linear_ranges = drv->reg_data->range;
rdesc->n_linear_ranges = 1;
rdesc->n_voltages = rdesc->linear_ranges[rdesc->n_linear_ranges - 1].max_sel + 1;
rdesc->ramp_delay = drv->reg_data->ramp_delay;
ret = spm_get_cpu(dev);
if (ret < 0)
return ret;
drv->reg_cpu = ret;
dev_dbg(dev, "SAW2 bound to CPU %d\n", drv->reg_cpu);
/*
* Program initial voltage, otherwise registration will also try
* setting the voltage, which might result in undervolting the CPU.
*/
drv->volt_sel = DIV_ROUND_UP(drv->reg_data->init_uV - rdesc->min_uV,
rdesc->uV_step);
ret = linear_range_get_selector_high(drv->reg_data->range,
drv->reg_data->init_uV,
&drv->volt_sel,
&found);
if (ret) {
dev_err(dev, "Initial uV value out of bounds\n");
return ret;
}
/* Always do the SAW register writes on the corresponding CPU */
smp_call_function_single(drv->reg_cpu, drv->reg_data->set_vdd, drv, true);
rdev = devm_regulator_register(dev, rdesc, &config);
if (IS_ERR(rdev)) {
dev_err(dev, "failed to register regulator\n");
return PTR_ERR(rdev);
}
return 0;
}
static const struct of_device_id spm_match_table[] = {
{ .compatible = "qcom,sdm660-gold-saw2-v4.1-l2",
.data = &spm_reg_660_gold_l2 },
@ -288,6 +524,7 @@ static int spm_dev_probe(struct platform_device *pdev)
return -ENODEV;
drv->reg_data = match_id->data;
drv->dev = &pdev->dev;
platform_set_drvdata(pdev, drv);
/* Write the SPM sequences first.. */
@ -315,6 +552,9 @@ static int spm_dev_probe(struct platform_device *pdev)
if (drv->reg_data->reg_offset[SPM_REG_SPM_CTL])
spm_set_low_power_mode(drv, PM_SLEEP_MODE_STBY);
if (IS_ENABLED(CONFIG_REGULATOR))
return spm_register_regulator(&pdev->dev, drv);
return 0;
}

View File

@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM qcom_aoss
#if !defined(_TRACE_QCOM_AOSS_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_QCOM_AOSS_H
#include <linux/tracepoint.h>
TRACE_EVENT(aoss_send,
TP_PROTO(const char *msg),
TP_ARGS(msg),
TP_STRUCT__entry(
__string(msg, msg)
),
TP_fast_assign(
__assign_str(msg, msg);
),
TP_printk("%s", __get_str(msg))
);
TRACE_EVENT(aoss_send_done,
TP_PROTO(const char *msg, int ret),
TP_ARGS(msg, ret),
TP_STRUCT__entry(
__string(msg, msg)
__field(int, ret)
),
TP_fast_assign(
__assign_str(msg, msg);
__entry->ret = ret;
),
TP_printk("%s: %d", __get_str(msg), __entry->ret)
);
#endif /* _TRACE_QCOM_AOSS_H */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE trace-aoss
#include <trace/define_trace.h>

View File

@ -34,6 +34,10 @@ config ARCH_RCAR_GEN3
select SYS_SUPPORTS_SH_CMT
select SYS_SUPPORTS_SH_TMU
config ARCH_RCAR_GEN4
bool
select ARCH_RCAR_GEN3
config ARCH_RMOBILE
bool
select PM
@ -240,7 +244,7 @@ config ARCH_R8A77961
config ARCH_R8A779F0
bool "ARM64 Platform support for R-Car S4-8"
select ARCH_RCAR_GEN3
select ARCH_RCAR_GEN4
select SYSC_R8A779F0
help
This enables support for the Renesas R-Car S4-8 SoC.
@ -261,18 +265,25 @@ config ARCH_R8A77970
config ARCH_R8A779A0
bool "ARM64 Platform support for R-Car V3U"
select ARCH_RCAR_GEN3
select ARCH_RCAR_GEN4
select SYSC_R8A779A0
help
This enables support for the Renesas R-Car V3U SoC.
config ARCH_R8A779G0
bool "ARM64 Platform support for R-Car V4H"
select ARCH_RCAR_GEN3
select ARCH_RCAR_GEN4
select SYSC_R8A779G0
help
This enables support for the Renesas R-Car V4H SoC.
config ARCH_R8A779H0
bool "ARM64 Platform support for R-Car V4M"
select ARCH_RCAR_GEN4
select SYSC_R8A779H0
help
This enables support for the Renesas R-Car V4M SoC.
config ARCH_R8A774C0
bool "ARM64 Platform support for RZ/G2E"
select ARCH_RCAR_GEN3

View File

@ -117,6 +117,7 @@ static const struct of_device_id rcar_rst_matches[] __initconst = {
{ .compatible = "renesas,r8a779a0-rst", .data = &rcar_rst_v3u },
{ .compatible = "renesas,r8a779f0-rst", .data = &rcar_rst_gen4 },
{ .compatible = "renesas,r8a779g0-rst", .data = &rcar_rst_gen4 },
{ .compatible = "renesas,r8a779h0-rst", .data = &rcar_rst_gen4 },
{ /* sentinel */ }
};

View File

@ -270,6 +270,11 @@ static const struct renesas_soc soc_rcar_v4h __initconst __maybe_unused = {
.id = 0x5c,
};
static const struct renesas_soc soc_rcar_v4m __initconst __maybe_unused = {
.family = &fam_rcar_gen4,
.id = 0x5d,
};
static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = {
.family = &fam_shmobile,
.id = 0x37,
@ -380,6 +385,9 @@ static const struct of_device_id renesas_socs[] __initconst __maybe_unused = {
#ifdef CONFIG_ARCH_R8A779G0
{ .compatible = "renesas,r8a779g0", .data = &soc_rcar_v4h },
#endif
#ifdef CONFIG_ARCH_R8A779H0
{ .compatible = "renesas,r8a779h0", .data = &soc_rcar_v4m },
#endif
#ifdef CONFIG_ARCH_R9A07G043
#ifdef CONFIG_RISCV
{ .compatible = "renesas,r9a07g043", .data = &soc_rz_five },

View File

@ -42,6 +42,7 @@ config EXYNOS_PMU
depends on ARCH_EXYNOS || ((ARM || ARM64) && COMPILE_TEST)
select EXYNOS_PMU_ARM_DRIVERS if ARM && ARCH_EXYNOS
select MFD_CORE
select REGMAP_MMIO
# There is no need to enable these drivers for ARMv8
config EXYNOS_PMU_ARM_DRIVERS

View File

@ -5,6 +5,7 @@
//
// Exynos - CPU PMU(Power Management Unit) support
#include <linux/arm-smccc.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/mfd/core.h>
@ -12,19 +13,134 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
#include <linux/soc/samsung/exynos-pmu.h>
#include "exynos-pmu.h"
#define PMUALIVE_MASK GENMASK(13, 0)
#define TENSOR_SET_BITS (BIT(15) | BIT(14))
#define TENSOR_CLR_BITS BIT(15)
#define TENSOR_SMC_PMU_SEC_REG 0x82000504
#define TENSOR_PMUREG_READ 0
#define TENSOR_PMUREG_WRITE 1
#define TENSOR_PMUREG_RMW 2
struct exynos_pmu_context {
struct device *dev;
const struct exynos_pmu_data *pmu_data;
struct regmap *pmureg;
};
void __iomem *pmu_base_addr;
static struct exynos_pmu_context *pmu_context;
/* forward declaration */
static struct platform_driver exynos_pmu_driver;
/*
* Tensor SoCs are configured so that PMU_ALIVE registers can only be written
* from EL3, but are still read accessible. As Linux needs to write some of
* these registers, the following functions are provided and exposed via
* regmap.
*
* Note: This SMC interface is known to be implemented on gs101 and derivative
* SoCs.
*/
/* Write to a protected PMU register. */
static int tensor_sec_reg_write(void *context, unsigned int reg,
unsigned int val)
{
struct arm_smccc_res res;
unsigned long pmu_base = (unsigned long)context;
arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg,
TENSOR_PMUREG_WRITE, val, 0, 0, 0, 0, &res);
/* returns -EINVAL if access isn't allowed or 0 */
if (res.a0)
pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0);
return (int)res.a0;
}
/* Read/Modify/Write a protected PMU register. */
static int tensor_sec_reg_rmw(void *context, unsigned int reg,
unsigned int mask, unsigned int val)
{
struct arm_smccc_res res;
unsigned long pmu_base = (unsigned long)context;
arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg,
TENSOR_PMUREG_RMW, mask, val, 0, 0, 0, &res);
/* returns -EINVAL if access isn't allowed or 0 */
if (res.a0)
pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0);
return (int)res.a0;
}
/*
* Read a protected PMU register. All PMU registers can be read by Linux.
* Note: The SMC read register is not used, as only registers that can be
* written are readable via SMC.
*/
static int tensor_sec_reg_read(void *context, unsigned int reg,
unsigned int *val)
{
*val = pmu_raw_readl(reg);
return 0;
}
/*
* For SoCs that have set/clear bit hardware this function can be used when
* the PMU register will be accessed by multiple masters.
*
* For example, to set bits 13:8 in PMU reg offset 0x3e80
* tensor_set_bits_atomic(ctx, 0x3e80, 0x3f00, 0x3f00);
*
* Set bit 8, and clear bits 13:9 PMU reg offset 0x3e80
* tensor_set_bits_atomic(0x3e80, 0x100, 0x3f00);
*/
static int tensor_set_bits_atomic(void *ctx, unsigned int offset, u32 val,
u32 mask)
{
int ret;
unsigned int i;
for (i = 0; i < 32; i++) {
if (!(mask & BIT(i)))
continue;
offset &= ~TENSOR_SET_BITS;
if (val & BIT(i))
offset |= TENSOR_SET_BITS;
else
offset |= TENSOR_CLR_BITS;
ret = tensor_sec_reg_write(ctx, offset, i);
if (ret)
return ret;
}
return ret;
}
static int tensor_sec_update_bits(void *ctx, unsigned int reg,
unsigned int mask, unsigned int val)
{
/*
* Use atomic operations for PMU_ALIVE registers (offset 0~0x3FFF)
* as the target registers can be accessed by multiple masters.
*/
if (reg > PMUALIVE_MASK)
return tensor_sec_reg_rmw(ctx, reg, mask, val);
return tensor_set_bits_atomic(ctx, reg, val, mask);
}
void pmu_raw_writel(u32 val, u32 offset)
{
@ -75,11 +191,41 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode)
#define exynos_pmu_data_arm_ptr(data) NULL
#endif
static const struct regmap_config regmap_smccfg = {
.name = "pmu_regs",
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.fast_io = true,
.use_single_read = true,
.use_single_write = true,
.reg_read = tensor_sec_reg_read,
.reg_write = tensor_sec_reg_write,
.reg_update_bits = tensor_sec_update_bits,
};
static const struct regmap_config regmap_mmiocfg = {
.name = "pmu_regs",
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.fast_io = true,
.use_single_read = true,
.use_single_write = true,
};
static const struct exynos_pmu_data gs101_pmu_data = {
.pmu_secure = true
};
/*
* PMU platform driver and devicetree bindings.
*/
static const struct of_device_id exynos_pmu_of_device_ids[] = {
{
.compatible = "google,gs101-pmu",
.data = &gs101_pmu_data,
}, {
.compatible = "samsung,exynos3250-pmu",
.data = exynos_pmu_data_arm_ptr(exynos3250_pmu_data),
}, {
@ -113,19 +259,75 @@ static const struct mfd_cell exynos_pmu_devs[] = {
{ .name = "exynos-clkout", },
};
/**
* exynos_get_pmu_regmap() - Obtain pmureg regmap
*
* Find the pmureg regmap previously configured in probe() and return regmap
* pointer.
*
* Return: A pointer to regmap if found or ERR_PTR error value.
*/
struct regmap *exynos_get_pmu_regmap(void)
{
struct device_node *np = of_find_matching_node(NULL,
exynos_pmu_of_device_ids);
if (np)
return syscon_node_to_regmap(np);
return exynos_get_pmu_regmap_by_phandle(np, NULL);
return ERR_PTR(-ENODEV);
}
EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap);
/**
* exynos_get_pmu_regmap_by_phandle() - Obtain pmureg regmap via phandle
* @np: Device node holding PMU phandle property
* @propname: Name of property holding phandle value
*
* Find the pmureg regmap previously configured in probe() and return regmap
* pointer.
*
* Return: A pointer to regmap if found or ERR_PTR error value.
*/
struct regmap *exynos_get_pmu_regmap_by_phandle(struct device_node *np,
const char *propname)
{
struct exynos_pmu_context *ctx;
struct device_node *pmu_np;
struct device *dev;
if (propname)
pmu_np = of_parse_phandle(np, propname, 0);
else
pmu_np = np;
if (!pmu_np)
return ERR_PTR(-ENODEV);
/*
* Determine if exynos-pmu device has probed and therefore regmap
* has been created and can be returned to the caller. Otherwise we
* return -EPROBE_DEFER.
*/
dev = driver_find_device_by_of_node(&exynos_pmu_driver.driver,
(void *)pmu_np);
if (propname)
of_node_put(pmu_np);
if (!dev)
return ERR_PTR(-EPROBE_DEFER);
ctx = dev_get_drvdata(dev);
return ctx->pmureg;
}
EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap_by_phandle);
static int exynos_pmu_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct regmap_config pmu_regmcfg;
struct regmap *regmap;
struct resource *res;
int ret;
pmu_base_addr = devm_platform_ioremap_resource(pdev, 0);
@ -137,9 +339,38 @@ static int exynos_pmu_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!pmu_context)
return -ENOMEM;
pmu_context->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
pmu_context->pmu_data = of_device_get_match_data(dev);
/* For SoCs that secure PMU register writes use custom regmap */
if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_secure) {
pmu_regmcfg = regmap_smccfg;
pmu_regmcfg.max_register = resource_size(res) -
pmu_regmcfg.reg_stride;
/* Need physical address for SMC call */
regmap = devm_regmap_init(dev, NULL,
(void *)(uintptr_t)res->start,
&pmu_regmcfg);
} else {
/* All other SoCs use a MMIO regmap */
pmu_regmcfg = regmap_mmiocfg;
pmu_regmcfg.max_register = resource_size(res) -
pmu_regmcfg.reg_stride;
regmap = devm_regmap_init_mmio(dev, pmu_base_addr,
&pmu_regmcfg);
}
if (IS_ERR(regmap))
return dev_err_probe(&pdev->dev, PTR_ERR(regmap),
"regmap init failed\n");
pmu_context->pmureg = regmap;
pmu_context->dev = dev;
if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_init)
pmu_context->pmu_data->pmu_init();

View File

@ -21,6 +21,7 @@ struct exynos_pmu_conf {
struct exynos_pmu_data {
const struct exynos_pmu_conf *pmu_config;
const struct exynos_pmu_conf *pmu_config_extra;
bool pmu_secure;
void (*pmu_init)(void);
void (*powerdown_conf)(enum sys_powerdown);

View File

@ -133,6 +133,11 @@ config ARCH_TEGRA_234_SOC
help
Enable support for the NVIDIA Tegra234 SoC.
config ARCH_TEGRA_241_SOC
bool "NVIDIA Tegra241 SoC"
help
Enable support for the NVIDIA Tegra241 SoC.
endif
endif

View File

@ -3,11 +3,13 @@
* Copyright (c) 2013-2023, NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/kobject.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/mod_devicetable.h>
#include <linux/nvmem-consumer.h>
#include <linux/nvmem-provider.h>
#include <linux/of.h>
@ -113,6 +115,28 @@ static void tegra_fuse_restore(void *base)
fuse->clk = NULL;
}
static void tegra_fuse_print_sku_info(struct tegra_sku_info *tegra_sku_info)
{
pr_info("Tegra Revision: %s SKU: %d CPU Process: %d SoC Process: %d\n",
tegra_revision_name[tegra_sku_info->revision],
tegra_sku_info->sku_id, tegra_sku_info->cpu_process_id,
tegra_sku_info->soc_process_id);
pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n",
tegra_sku_info->cpu_speedo_id, tegra_sku_info->soc_speedo_id);
}
static int tegra_fuse_add_lookups(struct tegra_fuse *fuse)
{
fuse->lookups = kmemdup_array(fuse->soc->lookups, sizeof(*fuse->lookups),
fuse->soc->num_lookups, GFP_KERNEL);
if (!fuse->lookups)
return -ENOMEM;
nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups);
return 0;
}
static int tegra_fuse_probe(struct platform_device *pdev)
{
void __iomem *base = fuse->base;
@ -130,15 +154,46 @@ static int tegra_fuse_probe(struct platform_device *pdev)
return PTR_ERR(fuse->base);
fuse->phys = res->start;
fuse->clk = devm_clk_get(&pdev->dev, "fuse");
if (IS_ERR(fuse->clk)) {
if (PTR_ERR(fuse->clk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "failed to get FUSE clock: %ld",
PTR_ERR(fuse->clk));
/* Initialize the soc data and lookups if using ACPI boot. */
if (is_acpi_node(dev_fwnode(&pdev->dev)) && !fuse->soc) {
u8 chip;
return PTR_ERR(fuse->clk);
tegra_acpi_init_apbmisc();
chip = tegra_get_chip_id();
switch (chip) {
#if defined(CONFIG_ARCH_TEGRA_194_SOC)
case TEGRA194:
fuse->soc = &tegra194_fuse_soc;
break;
#endif
#if defined(CONFIG_ARCH_TEGRA_234_SOC)
case TEGRA234:
fuse->soc = &tegra234_fuse_soc;
break;
#endif
#if defined(CONFIG_ARCH_TEGRA_241_SOC)
case TEGRA241:
fuse->soc = &tegra241_fuse_soc;
break;
#endif
default:
return dev_err_probe(&pdev->dev, -EINVAL, "Unsupported SoC: %02x\n", chip);
}
fuse->soc->init(fuse);
tegra_fuse_print_sku_info(&tegra_sku_info);
tegra_soc_device_register();
err = tegra_fuse_add_lookups(fuse);
if (err)
return dev_err_probe(&pdev->dev, err, "failed to add FUSE lookups\n");
}
fuse->clk = devm_clk_get_optional(&pdev->dev, "fuse");
if (IS_ERR(fuse->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(fuse->clk), "failed to get FUSE clock\n");
platform_set_drvdata(pdev, fuse);
fuse->dev = &pdev->dev;
@ -179,12 +234,8 @@ static int tegra_fuse_probe(struct platform_device *pdev)
}
fuse->rst = devm_reset_control_get_optional(&pdev->dev, "fuse");
if (IS_ERR(fuse->rst)) {
err = PTR_ERR(fuse->rst);
dev_err(&pdev->dev, "failed to get FUSE reset: %pe\n",
fuse->rst);
return err;
}
if (IS_ERR(fuse->rst))
return dev_err_probe(&pdev->dev, PTR_ERR(fuse->rst), "failed to get FUSE reset\n");
/*
* FUSE clock is enabled at a boot time, hence this resume/suspend
@ -262,10 +313,17 @@ static const struct dev_pm_ops tegra_fuse_pm = {
SET_SYSTEM_SLEEP_PM_OPS(tegra_fuse_suspend, tegra_fuse_resume)
};
static const struct acpi_device_id tegra_fuse_acpi_match[] = {
{ "NVDA200F" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(acpi, tegra_fuse_acpi_match);
static struct platform_driver tegra_fuse_driver = {
.driver = {
.name = "tegra-fuse",
.of_match_table = tegra_fuse_match,
.acpi_match_table = tegra_fuse_acpi_match,
.pm = &tegra_fuse_pm,
.suppress_bind_attrs = true,
},
@ -287,7 +345,16 @@ u32 __init tegra_fuse_read_early(unsigned int offset)
int tegra_fuse_readl(unsigned long offset, u32 *value)
{
if (!fuse->read || !fuse->clk)
if (!fuse->dev)
return -EPROBE_DEFER;
/*
* Wait for fuse->clk to be initialized if device-tree boot is used.
*/
if (is_of_node(dev_fwnode(fuse->dev)) && !fuse->clk)
return -EPROBE_DEFER;
if (!fuse->read)
return -EPROBE_DEFER;
if (IS_ERR(fuse->clk))
@ -343,7 +410,8 @@ const struct attribute_group tegra_soc_attr_group = {
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) || \
IS_ENABLED(CONFIG_ARCH_TEGRA_241_SOC)
static ssize_t platform_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@ -370,7 +438,7 @@ const struct attribute_group tegra194_soc_attr_group = {
};
#endif
struct device * __init tegra_soc_device_register(void)
struct device *tegra_soc_device_register(void)
{
struct soc_device_attribute *attr;
struct soc_device *dev;
@ -407,6 +475,7 @@ static int __init tegra_init_fuse(void)
const struct of_device_id *match;
struct device_node *np;
struct resource regs;
int err;
tegra_init_apbmisc();
@ -497,22 +566,13 @@ static int __init tegra_init_fuse(void)
fuse->soc->init(fuse);
pr_info("Tegra Revision: %s SKU: %d CPU Process: %d SoC Process: %d\n",
tegra_revision_name[tegra_sku_info.revision],
tegra_sku_info.sku_id, tegra_sku_info.cpu_process_id,
tegra_sku_info.soc_process_id);
pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n",
tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id);
tegra_fuse_print_sku_info(&tegra_sku_info);
if (fuse->soc->lookups) {
size_t size = sizeof(*fuse->lookups) * fuse->soc->num_lookups;
err = tegra_fuse_add_lookups(fuse);
if (err)
pr_err("failed to add FUSE lookups\n");
fuse->lookups = kmemdup(fuse->soc->lookups, size, GFP_KERNEL);
if (fuse->lookups)
nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups);
}
return 0;
return err;
}
early_initcall(tegra_init_fuse);

View File

@ -38,7 +38,8 @@
defined(CONFIG_ARCH_TEGRA_210_SOC) || \
defined(CONFIG_ARCH_TEGRA_186_SOC) || \
defined(CONFIG_ARCH_TEGRA_194_SOC) || \
defined(CONFIG_ARCH_TEGRA_234_SOC)
defined(CONFIG_ARCH_TEGRA_234_SOC) || \
defined(CONFIG_ARCH_TEGRA_241_SOC)
static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset)
{
if (WARN_ON(!fuse->base))
@ -678,3 +679,23 @@ const struct tegra_fuse_soc tegra234_fuse_soc = {
.clk_suspend_on = false,
};
#endif
#if defined(CONFIG_ARCH_TEGRA_241_SOC)
static const struct tegra_fuse_info tegra241_fuse_info = {
.read = tegra30_fuse_read,
.size = 0x16008,
.spare = 0xcf0,
};
static const struct nvmem_keepout tegra241_fuse_keepouts[] = {
{ .start = 0xc, .end = 0x1600c }
};
const struct tegra_fuse_soc tegra241_fuse_soc = {
.init = tegra30_fuse_init,
.info = &tegra241_fuse_info,
.keepouts = tegra241_fuse_keepouts,
.num_keepouts = ARRAY_SIZE(tegra241_fuse_keepouts),
.soc_attr_group = &tegra194_soc_attr_group,
};
#endif

View File

@ -69,6 +69,7 @@ struct tegra_fuse {
void tegra_init_revision(void);
void tegra_init_apbmisc(void);
void tegra_acpi_init_apbmisc(void);
u32 __init tegra_fuse_read_spare(unsigned int spare);
u32 __init tegra_fuse_read_early(unsigned int offset);
@ -123,7 +124,8 @@ extern const struct tegra_fuse_soc tegra186_fuse_soc;
#endif
#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) || \
IS_ENABLED(CONFIG_ARCH_TEGRA_241_SOC)
extern const struct attribute_group tegra194_soc_attr_group;
#endif
@ -135,4 +137,8 @@ extern const struct tegra_fuse_soc tegra194_fuse_soc;
extern const struct tegra_fuse_soc tegra234_fuse_soc;
#endif
#ifdef CONFIG_ARCH_TEGRA_241_SOC
extern const struct tegra_fuse_soc tegra241_fuse_soc;
#endif
#endif

View File

@ -3,9 +3,11 @@
* Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/acpi.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/of_address.h>
@ -62,6 +64,7 @@ bool tegra_is_silicon(void)
switch (tegra_get_chip_id()) {
case TEGRA194:
case TEGRA234:
case TEGRA241:
case TEGRA264:
if (tegra_get_platform() == 0)
return true;
@ -160,9 +163,34 @@ void __init tegra_init_revision(void)
tegra_sku_info.platform = tegra_get_platform();
}
void __init tegra_init_apbmisc(void)
static void tegra_init_apbmisc_resources(struct resource *apbmisc,
struct resource *straps)
{
void __iomem *strapping_base;
apbmisc_base = ioremap(apbmisc->start, resource_size(apbmisc));
if (apbmisc_base)
chipid = readl_relaxed(apbmisc_base + 4);
else
pr_err("failed to map APBMISC registers\n");
strapping_base = ioremap(straps->start, resource_size(straps));
if (strapping_base) {
strapping = readl_relaxed(strapping_base);
iounmap(strapping_base);
} else {
pr_err("failed to map strapping options registers\n");
}
}
/**
* tegra_init_apbmisc - Initializes Tegra APBMISC and Strapping registers.
*
* This is called during early init as some of the old 32-bit ARM code needs
* information from the APBMISC registers very early during boot.
*/
void __init tegra_init_apbmisc(void)
{
struct resource apbmisc, straps;
struct device_node *np;
@ -219,23 +247,73 @@ void __init tegra_init_apbmisc(void)
}
}
apbmisc_base = ioremap(apbmisc.start, resource_size(&apbmisc));
if (!apbmisc_base) {
pr_err("failed to map APBMISC registers\n");
} else {
chipid = readl_relaxed(apbmisc_base + 4);
}
strapping_base = ioremap(straps.start, resource_size(&straps));
if (!strapping_base) {
pr_err("failed to map strapping options registers\n");
} else {
strapping = readl_relaxed(strapping_base);
iounmap(strapping_base);
}
tegra_init_apbmisc_resources(&apbmisc, &straps);
long_ram_code = of_property_read_bool(np, "nvidia,long-ram-code");
put:
of_node_put(np);
}
#ifdef CONFIG_ACPI
static const struct acpi_device_id apbmisc_acpi_match[] = {
{ "NVDA2010" },
{ /* sentinel */ }
};
void tegra_acpi_init_apbmisc(void)
{
struct resource *resources[2] = { NULL };
struct resource_entry *rentry;
struct acpi_device *adev = NULL;
struct list_head resource_list;
int rcount = 0;
int ret;
adev = acpi_dev_get_first_match_dev(apbmisc_acpi_match[0].id, NULL, -1);
if (!adev)
return;
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_memory_resources(adev, &resource_list);
if (ret < 0) {
pr_err("failed to get APBMISC memory resources");
goto out_put_acpi_dev;
}
/*
* Get required memory resources.
*
* resources[0]: apbmisc.
* resources[1]: straps.
*/
resource_list_for_each_entry(rentry, &resource_list) {
if (rcount >= ARRAY_SIZE(resources))
break;
resources[rcount++] = rentry->res;
}
if (!resources[0]) {
pr_err("failed to get APBMISC registers\n");
goto out_free_resource_list;
}
if (!resources[1]) {
pr_err("failed to get strapping options registers\n");
goto out_free_resource_list;
}
tegra_init_apbmisc_resources(resources[0], resources[1]);
out_free_resource_list:
acpi_dev_free_resource_list(&resource_list);
out_put_acpi_dev:
acpi_dev_put(adev);
}
#else
void tegra_acpi_init_apbmisc(void)
{
}
#endif

View File

@ -3,7 +3,7 @@
* drivers/soc/tegra/pmc.c
*
* Copyright (c) 2010 Google, Inc
* Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@google.com>
@ -384,6 +384,7 @@ struct tegra_pmc_soc {
bool has_blink_output;
bool has_usb_sleepwalk;
bool supports_core_domain;
bool has_single_mmio_aperture;
};
/**
@ -1777,30 +1778,6 @@ static int tegra_io_pad_get_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id)
return TEGRA_IO_PAD_VOLTAGE_3V3;
}
/**
* tegra_io_rail_power_on() - enable power to I/O rail
* @id: Tegra I/O pad ID for which to enable power
*
* See also: tegra_io_pad_power_enable()
*/
int tegra_io_rail_power_on(unsigned int id)
{
return tegra_io_pad_power_enable(id);
}
EXPORT_SYMBOL(tegra_io_rail_power_on);
/**
* tegra_io_rail_power_off() - disable power to I/O rail
* @id: Tegra I/O pad ID for which to disable power
*
* See also: tegra_io_pad_power_disable()
*/
int tegra_io_rail_power_off(unsigned int id)
{
return tegra_io_pad_power_disable(id);
}
EXPORT_SYMBOL(tegra_io_rail_power_off);
#ifdef CONFIG_PM_SLEEP
enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
{
@ -2909,31 +2886,33 @@ static int tegra_pmc_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wake");
if (res) {
if (pmc->soc->has_single_mmio_aperture) {
pmc->wake = base;
pmc->aotag = base;
pmc->scratch = base;
} else {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"wake");
pmc->wake = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(pmc->wake))
return PTR_ERR(pmc->wake);
} else {
pmc->wake = base;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aotag");
if (res) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"aotag");
pmc->aotag = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(pmc->aotag))
return PTR_ERR(pmc->aotag);
} else {
pmc->aotag = base;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scratch");
if (res) {
pmc->scratch = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(pmc->scratch))
return PTR_ERR(pmc->scratch);
} else {
pmc->scratch = base;
/* "scratch" is an optional aperture */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"scratch");
if (res) {
pmc->scratch = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(pmc->scratch))
return PTR_ERR(pmc->scratch);
} else {
pmc->scratch = NULL;
}
}
pmc->clk = devm_clk_get_optional(&pdev->dev, "pclk");
@ -2945,12 +2924,15 @@ static int tegra_pmc_probe(struct platform_device *pdev)
* PMC should be last resort for restarting since it soft-resets
* CPU without resetting everything else.
*/
err = devm_register_reboot_notifier(&pdev->dev,
&tegra_pmc_reboot_notifier);
if (err) {
dev_err(&pdev->dev, "unable to register reboot notifier, %d\n",
err);
return err;
if (pmc->scratch) {
err = devm_register_reboot_notifier(&pdev->dev,
&tegra_pmc_reboot_notifier);
if (err) {
dev_err(&pdev->dev,
"unable to register reboot notifier, %d\n",
err);
return err;
}
}
err = devm_register_sys_off_handler(&pdev->dev,
@ -3324,6 +3306,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
.num_pmc_clks = 0,
.has_blink_output = true,
.has_usb_sleepwalk = true,
.has_single_mmio_aperture = true,
};
static const char * const tegra30_powergates[] = {
@ -3385,6 +3368,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
.has_blink_output = true,
.has_usb_sleepwalk = true,
.has_single_mmio_aperture = true,
};
static const char * const tegra114_powergates[] = {
@ -3442,6 +3426,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
.has_blink_output = true,
.has_usb_sleepwalk = true,
.has_single_mmio_aperture = true,
};
static const char * const tegra124_powergates[] = {
@ -3586,6 +3571,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
.has_blink_output = true,
.has_usb_sleepwalk = true,
.has_single_mmio_aperture = true,
};
static const char * const tegra210_powergates[] = {
@ -3749,6 +3735,7 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
.num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data),
.has_blink_output = true,
.has_usb_sleepwalk = true,
.has_single_mmio_aperture = true,
};
static const struct tegra_io_pad_soc tegra186_io_pads[] = {
@ -3946,6 +3933,7 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
.num_pmc_clks = 0,
.has_blink_output = false,
.has_usb_sleepwalk = false,
.has_single_mmio_aperture = false,
};
static const struct tegra_io_pad_soc tegra194_io_pads[] = {
@ -4131,6 +4119,7 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
.num_pmc_clks = 0,
.has_blink_output = false,
.has_usb_sleepwalk = false,
.has_single_mmio_aperture = false,
};
static const struct tegra_io_pad_soc tegra234_io_pads[] = {
@ -4220,6 +4209,7 @@ static const char * const tegra234_reset_sources[] = {
};
static const struct tegra_wake_event tegra234_wake_events[] = {
TEGRA_WAKE_GPIO("sd-wake", 8, 0, TEGRA234_MAIN_GPIO(G, 7)),
TEGRA_WAKE_IRQ("pmu", 24, 209),
TEGRA_WAKE_GPIO("power", 29, 1, TEGRA234_AON_GPIO(EE, 4)),
TEGRA_WAKE_GPIO("mgbe", 56, 0, TEGRA234_MAIN_GPIO(Y, 3)),
@ -4259,6 +4249,7 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = {
.pmc_clks_data = NULL,
.num_pmc_clks = 0,
.has_blink_output = false,
.has_single_mmio_aperture = false,
};
static const struct of_device_id tegra_pmc_match[] = {

View File

@ -48,7 +48,7 @@ Example of usage:
-----------------
This example places the bridge on top of the i.MX WEIM parallel bus, see:
Documentation/devicetree/bindings/bus/imx-weim.txt
Documentation/devicetree/bindings/memory-controllers/fsl/fsl,imx-weim.yaml
&weim {
controller@0,0 {

View File

@ -1226,7 +1226,7 @@ static int tee_client_device_uevent(const struct device *dev,
return add_uevent_var(env, "MODALIAS=tee:%pUb", dev_id);
}
struct bus_type tee_bus_type = {
const struct bus_type tee_bus_type = {
.name = "tee",
.match = tee_client_device_match,
.uevent = tee_client_device_uevent,

View File

@ -512,7 +512,6 @@ config S3C2410_WATCHDOG
tristate "S3C6410/S5Pv210/Exynos Watchdog"
depends on ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
select WATCHDOG_CORE
select MFD_SYSCON if ARCH_EXYNOS
help
Watchdog timer block in the Samsung S3C64xx, S5Pv210 and Exynos
SoCs. This will reboot the system when the timer expires with

View File

@ -24,9 +24,9 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/delay.h>
#include <linux/soc/samsung/exynos-pmu.h>
#define S3C2410_WTCON 0x00
#define S3C2410_WTDAT 0x04
@ -699,11 +699,11 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
return ret;
if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) {
wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
"samsung,syscon-phandle");
wdt->pmureg = exynos_get_pmu_regmap_by_phandle(dev->of_node,
"samsung,syscon-phandle");
if (IS_ERR(wdt->pmureg))
return dev_err_probe(dev, PTR_ERR(wdt->pmureg),
"syscon regmap lookup failed.\n");
"PMU regmap lookup failed.\n");
}
wdt_irq = platform_get_irq(pdev, 0);

View File

@ -252,8 +252,11 @@
#define QCOM_ID_IPQ9510 521
#define QCOM_ID_QRB4210 523
#define QCOM_ID_QRB2210 524
#define QCOM_ID_SM8475 530
#define QCOM_ID_SM8475P 531
#define QCOM_ID_SA8775P 534
#define QCOM_ID_QRU1000 539
#define QCOM_ID_SM8475_2 540
#define QCOM_ID_QDU1000 545
#define QCOM_ID_SM8650 557
#define QCOM_ID_SM4450 568
@ -265,6 +268,8 @@
#define QCOM_ID_IPQ5322 593
#define QCOM_ID_IPQ5312 594
#define QCOM_ID_IPQ5302 595
#define QCOM_ID_QCS8550 603
#define QCOM_ID_QCM8550 604
#define QCOM_ID_IPQ5300 624
/*

View File

@ -209,7 +209,7 @@ bool ffa_device_is_valid(struct ffa_device *ffa_dev) { return false; }
#define module_ffa_driver(__ffa_driver) \
module_driver(__ffa_driver, ffa_register, ffa_unregister)
extern struct bus_type ffa_bus_type;
extern const struct bus_type ffa_bus_type;
/* FFA transport related */
struct ffa_partition_info {

View File

@ -47,6 +47,10 @@ struct scmi_clock_info {
bool rate_discrete;
bool rate_changed_notifications;
bool rate_change_requested_notifications;
bool state_ctrl_forbidden;
bool rate_ctrl_forbidden;
bool parent_ctrl_forbidden;
bool extended_config;
union {
struct {
int num_rates;
@ -72,6 +76,13 @@ struct scmi_handle;
struct scmi_device;
struct scmi_protocol_handle;
enum scmi_clock_oem_config {
SCMI_CLOCK_CFG_DUTY_CYCLE = 0x1,
SCMI_CLOCK_CFG_PHASE,
SCMI_CLOCK_CFG_OEM_START = 0x80,
SCMI_CLOCK_CFG_OEM_END = 0xFF,
};
/**
* struct scmi_clk_proto_ops - represents the various operations provided
* by SCMI Clock Protocol
@ -104,10 +115,11 @@ struct scmi_clk_proto_ops {
int (*state_get)(const struct scmi_protocol_handle *ph, u32 clk_id,
bool *enabled, bool atomic);
int (*config_oem_get)(const struct scmi_protocol_handle *ph, u32 clk_id,
u8 oem_type, u32 *oem_val, u32 *attributes,
bool atomic);
enum scmi_clock_oem_config oem_type,
u32 *oem_val, u32 *attributes, bool atomic);
int (*config_oem_set)(const struct scmi_protocol_handle *ph, u32 clk_id,
u8 oem_type, u32 oem_val, bool atomic);
enum scmi_clock_oem_config oem_type,
u32 oem_val, bool atomic);
int (*parent_get)(const struct scmi_protocol_handle *ph, u32 clk_id, u32 *parent_id);
int (*parent_set)(const struct scmi_protocol_handle *ph, u32 clk_id, u32 parent_id);
};
@ -953,6 +965,8 @@ struct scmi_perf_limits_report {
unsigned int domain_id;
unsigned int range_max;
unsigned int range_min;
unsigned long range_max_freq;
unsigned long range_min_freq;
};
struct scmi_perf_level_report {
@ -960,6 +974,7 @@ struct scmi_perf_level_report {
unsigned int agent_id;
unsigned int domain_id;
unsigned int performance_level;
unsigned long performance_level_freq;
};
struct scmi_sensor_trip_point_report {

View File

@ -9,7 +9,7 @@
#include <dt-bindings/soc/qcom,apr.h>
#include <dt-bindings/soc/qcom,gpr.h>
extern struct bus_type aprbus;
extern const struct bus_type aprbus;
#define APR_HDR_LEN(hdr_len) ((hdr_len)/4)

View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _QCOM_PBS_H
#define _QCOM_PBS_H
#include <linux/errno.h>
#include <linux/types.h>
struct device_node;
struct pbs_dev;
#if IS_ENABLED(CONFIG_QCOM_PBS)
int qcom_pbs_trigger_event(struct pbs_dev *pbs, u8 bitmap);
struct pbs_dev *get_pbs_client_device(struct device *client_dev);
#else
static inline int qcom_pbs_trigger_event(struct pbs_dev *pbs, u8 bitmap)
{
return -ENODEV;
}
static inline struct pbs_dev *get_pbs_client_device(struct device *client_dev)
{
return ERR_PTR(-ENODEV);
}
#endif
#endif

View File

@ -10,6 +10,7 @@
#define __LINUX_SOC_EXYNOS_PMU_H
struct regmap;
struct device_node;
enum sys_powerdown {
SYS_AFTR,
@ -20,12 +21,20 @@ enum sys_powerdown {
extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
#ifdef CONFIG_EXYNOS_PMU
extern struct regmap *exynos_get_pmu_regmap(void);
struct regmap *exynos_get_pmu_regmap(void);
struct regmap *exynos_get_pmu_regmap_by_phandle(struct device_node *np,
const char *propname);
#else
static inline struct regmap *exynos_get_pmu_regmap(void)
{
return ERR_PTR(-ENODEV);
}
static inline struct regmap *exynos_get_pmu_regmap_by_phandle(struct device_node *np,
const char *propname)
{
return ERR_PTR(-ENODEV);
}
#endif
#endif /* __LINUX_SOC_EXYNOS_PMU_H */

View File

@ -217,6 +217,7 @@ extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
extern void *kmemdup(const void *src, size_t len, gfp_t gfp) __realloc_size(2);
extern void *kvmemdup(const void *src, size_t len, gfp_t gfp) __realloc_size(2);
extern char *kmemdup_nul(const char *s, size_t len, gfp_t gfp);
extern void *kmemdup_array(const void *src, size_t element_size, size_t count, gfp_t gfp);
extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
extern void argv_free(char **argv);

View File

@ -482,7 +482,7 @@ static inline bool tee_param_is_memref(struct tee_param *param)
}
}
extern struct bus_type tee_bus_type;
extern const struct bus_type tee_bus_type;
/**
* struct tee_client_device - tee based device

View File

@ -49,7 +49,7 @@
#define PMK8350_SUBTYPE 0x2f
#define PMR735B_SUBTYPE 0x34
#define PM6350_SUBTYPE 0x36
#define PM2250_SUBTYPE 0x37
#define PM4125_SUBTYPE 0x37
#define PMI8998_FAB_ID_SMIC 0x11
#define PMI8998_FAB_ID_GF 0x30

View File

@ -7,11 +7,6 @@
#ifndef __SPM_H__
#define __SPM_H__
#include <linux/cpuidle.h>
#define MAX_PMIC_DATA 2
#define MAX_SEQ_DATA 64
enum pm_sleep_mode {
PM_SLEEP_MODE_STBY,
PM_SLEEP_MODE_RET,
@ -20,23 +15,7 @@ enum pm_sleep_mode {
PM_SLEEP_MODE_NR,
};
struct spm_reg_data {
const u16 *reg_offset;
u32 spm_cfg;
u32 spm_dly;
u32 pmic_dly;
u32 pmic_data[MAX_PMIC_DATA];
u32 avs_ctl;
u32 avs_limit;
u8 seq[MAX_SEQ_DATA];
u8 start_index[PM_SLEEP_MODE_NR];
};
struct spm_driver_data {
void __iomem *reg_base;
const struct spm_reg_data *reg_data;
};
struct spm_driver_data;
void spm_set_low_power_mode(struct spm_driver_data *drv,
enum pm_sleep_mode mode);

View File

@ -17,6 +17,7 @@
#define TEGRA186 0x18
#define TEGRA194 0x19
#define TEGRA234 0x23
#define TEGRA241 0x24
#define TEGRA264 0x26
#define TEGRA_FUSE_SKU_CALIB_0 0xf0

View File

@ -148,10 +148,6 @@ enum tegra_io_pad {
TEGRA_IO_PAD_AO_HV,
};
/* deprecated, use TEGRA_IO_PAD_{HDMI,LVDS} instead */
#define TEGRA_IO_RAIL_HDMI TEGRA_IO_PAD_HDMI
#define TEGRA_IO_RAIL_LVDS TEGRA_IO_PAD_LVDS
#ifdef CONFIG_SOC_TEGRA_PMC
int tegra_powergate_power_on(unsigned int id);
int tegra_powergate_power_off(unsigned int id);
@ -164,10 +160,6 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
int tegra_io_pad_power_enable(enum tegra_io_pad id);
int tegra_io_pad_power_disable(enum tegra_io_pad id);
/* deprecated, use tegra_io_pad_power_{enable,disable}() instead */
int tegra_io_rail_power_on(unsigned int id);
int tegra_io_rail_power_off(unsigned int id);
void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
@ -211,16 +203,6 @@ static inline int tegra_io_pad_get_voltage(enum tegra_io_pad id)
return -ENOSYS;
}
static inline int tegra_io_rail_power_on(unsigned int id)
{
return -ENOSYS;
}
static inline int tegra_io_rail_power_off(unsigned int id)
{
return -ENOSYS;
}
static inline void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode)
{
}

View File

@ -135,6 +135,23 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp)
}
EXPORT_SYMBOL(kmemdup);
/**
* kmemdup_array - duplicate a given array.
*
* @src: array to duplicate.
* @element_size: size of each element of array.
* @count: number of elements to duplicate from array.
* @gfp: GFP mask to use.
*
* Return: duplicated array of @src or %NULL in case of error,
* result is physically contiguous. Use kfree() to free.
*/
void *kmemdup_array(const void *src, size_t element_size, size_t count, gfp_t gfp)
{
return kmemdup(src, size_mul(element_size, count), gfp);
}
EXPORT_SYMBOL(kmemdup_array);
/**
* kvmemdup - duplicate region of memory
*