ARM: SoC drivers for v6.4

The most notable updates this time are for Qualcomm Snapdragon platforms.
 The Inline-Crypto-Engine gets a new DT binding and driver. A number of
 drivers now support additional Snapdragon variants, in particular the
 rsc, scm, geni, bwm, glink and socinfo, while the llcc (edac) and rpm
 drivers get notable functionality updates.
 
 Updates on other platforms include:
 
  - Various updates to the Mediatek mutex and mmsys drivers, including
    support for the Helio X10 SoC
 
  - Support for unidirectional mailbox channels in Arm SCMI firmware
 
  - Support for per cpu asynchronous notification in OP-TEE firmware
 
  - Minor updates for memory controller drivers.
 
  - Minor updates for Renesas, TI, Amlogic, Apple, Broadcom, Tegra,
    Allwinner, Versatile Express, Canaan, Microchip, Mediatek and i.MX
    SoC drivers, mainly updating the use of MODULE_LICENSE() macros and
    obsolete DT driver interfaces.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEiK/NIGsWEZVxh/FrYKtH/8kJUicFAmRGmncACgkQYKtH/8kJ
 Uif6ghAAw1TiPTJzJLLCNx+txOVFB62WDglv3T1CufjfcWp0Eh0RJSCcsCOPV+/7
 UHi4+X4nPAcudeOFMFtslCR8ExLRWY4j7t2ZYo/k+VI3jdB8Qkbr6NAQgAuRdLYX
 WZ1cV6o76B3bhO2HqSVNVZ8/3Z7OAYw4j9VDD/4AbW+l3GyentlQTjabpJNREvSS
 5HzT3ZI33o7M8mM4uYmmEXVrg8sCupbRyL9S7jTiFXRLcfqujclhfezJ4UrJJv7b
 wxGf+e2YNMqKH6PiKYufzN1TYI2D0YQeB1m56Y9FsAKxgAyHh2xWpsHeyVnaw0jc
 KaKjRN/H3JDlW/VCMAjQOIShCZdAs02xHnEXxY6pKLMM6i8/FkzzNIxNQwXrx5KH
 zYESXVd6suOI0eCZT8zkKKLHRT5EJRaliUv5Z+Qp2BBe3vJVZD0JqSlZ7lOznplF
 lviwL6ydAMr2cfTgfMxbRiYQVDzncFkfnR3t55SC6rYjGt6QWjeS0dDbGHf4WVC4
 FDbnST4JaBmi+frh55VooX7EpzIv9wa0/taayaChd9qvXnh22uqaqho1sPYKZ6BI
 OXduHQ3qojJhKKKK1VJKzN5Ef3OHLQLNrvcc1DsKILrrES4w4LX1C9dmyh2CLXLo
 q5cX6L1iB1Hx5tujalDYBsHBBmbiT/1tNM2S7pAGigiGy4KEc28=
 =r6jm
 -----END PGP SIGNATURE-----

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

Pull ARM SoC driver updates from Arnd Bergmann:
 "The most notable updates this time are for Qualcomm Snapdragon
  platforms. The Inline-Crypto-Engine gets a new DT binding and driver,
  and a number of drivers now support additional Snapdragon variants, in
  particular the rsc, scm, geni, bwm, glink and socinfo, while the llcc
  (edac) and rpm drivers get notable functionality updates.

  Updates on other platforms include:

   - Various updates to the Mediatek mutex and mmsys drivers, including
     support for the Helio X10 SoC

   - Support for unidirectional mailbox channels in Arm SCMI firmware

   - Support for per cpu asynchronous notification in OP-TEE firmware

   - Minor updates for memory controller drivers.

   - Minor updates for Renesas, TI, Amlogic, Apple, Broadcom, Tegra,
     Allwinner, Versatile Express, Canaan, Microchip, Mediatek and i.MX
     SoC drivers, mainly updating the use of MODULE_LICENSE() macros and
     obsolete DT driver interfaces"

* tag 'soc-drivers-6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (165 commits)
  soc: ti: smartreflex: Simplify getting the opam_sr pointer
  bus: vexpress-config: Add explicit of_platform.h include
  soc: mediatek: Kconfig: Add MTK_CMDQ dependency to MTK_MMSYS
  memory: mtk-smi: mt8365: Add SMI Support
  dt-bindings: memory-controllers: mediatek,smi-larb: add mt8365
  dt-bindings: memory-controllers: mediatek,smi-common: add mt8365
  memory: tegra: read values from correct device
  dt-bindings: crypto: Add Qualcomm Inline Crypto Engine
  soc: qcom: Make the Qualcomm UFS/SDCC ICE a dedicated driver
  dt-bindings: firmware: document Qualcomm QCM2290 SCM
  soc: qcom: rpmh-rsc: Support RSC v3 minor versions
  soc: qcom: smd-rpm: Use GFP_ATOMIC in write path
  soc/tegra: fuse: Remove nvmem root only access
  soc/tegra: cbb: tegra194: Use of_address_count() helper
  soc/tegra: cbb: Remove MODULE_LICENSE in non-modules
  ARM: tegra: Remove MODULE_LICENSE in non-modules
  soc/tegra: flowctrl: Use devm_platform_get_and_ioremap_resource()
  soc: tegra: cbb: Drop empty platform remove function
  firmware: arm_scmi: Add support for unidirectional mailbox channels
  dt-bindings: firmware: arm,scmi: Support mailboxes unidirectional channels
  ...
This commit is contained in:
Linus Torvalds 2023-04-25 12:02:16 -07:00
commit a907047732
129 changed files with 3013 additions and 2018 deletions

View File

@ -2,8 +2,8 @@
# Copyright 2019 BayLibre, SAS
%YAML 1.2
---
$id: "http://devicetree.org/schemas/arm/amlogic/amlogic,meson-gx-ao-secure.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/arm/amlogic/amlogic,meson-gx-ao-secure.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic Meson Firmware registers Interface

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/arm/amlogic/amlogic,meson-mx-secbus2.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/arm/amlogic/amlogic,meson-mx-secbus2.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic Meson8/Meson8b/Meson8m2 SECBUS2 register interface

View File

@ -28,7 +28,8 @@ properties:
maxItems: 1
description: |
This interrupt which is used to signal an event by the secure world
software is expected to be edge-triggered.
software is expected to be either a per-cpu interrupt or an
edge-triggered peripheral interrupt.
method:
enum: [smc, hvc]

View File

@ -7,8 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Last Level Cache Controller
maintainers:
- Rishabh Bhatnagar <rishabhb@codeaurora.org>
- Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
- Bjorn Andersson <andersson@kernel.org>
description: |
LLCC (Last Level Cache Controller) provides last level of cache memory in SoC,
@ -27,6 +26,7 @@ properties:
- qcom,sc8280xp-llcc
- qcom,sdm845-llcc
- qcom,sm6350-llcc
- qcom,sm7150-llcc
- qcom,sm8150-llcc
- qcom,sm8250-llcc
- qcom,sm8350-llcc
@ -34,14 +34,12 @@ properties:
- qcom,sm8550-llcc
reg:
items:
- description: LLCC base register region
- description: LLCC broadcast base register region
minItems: 2
maxItems: 9
reg-names:
items:
- const: llcc_base
- const: llcc_broadcast_base
minItems: 2
maxItems: 9
interrupts:
maxItems: 1
@ -51,15 +49,120 @@ required:
- reg
- reg-names
allOf:
- if:
properties:
compatible:
contains:
enum:
- qcom,sc7180-llcc
- qcom,sm6350-llcc
then:
properties:
reg:
items:
- description: LLCC0 base register region
- description: LLCC broadcast base register region
reg-names:
items:
- const: llcc0_base
- const: llcc_broadcast_base
- if:
properties:
compatible:
contains:
enum:
- qcom,sc7280-llcc
then:
properties:
reg:
items:
- description: LLCC0 base register region
- description: LLCC1 base register region
- description: LLCC broadcast base register region
reg-names:
items:
- const: llcc0_base
- const: llcc1_base
- const: llcc_broadcast_base
- if:
properties:
compatible:
contains:
enum:
- qcom,sc8180x-llcc
- qcom,sc8280xp-llcc
then:
properties:
reg:
items:
- description: LLCC0 base register region
- description: LLCC1 base register region
- description: LLCC2 base register region
- description: LLCC3 base register region
- description: LLCC4 base register region
- description: LLCC5 base register region
- description: LLCC6 base register region
- description: LLCC7 base register region
- description: LLCC broadcast base register region
reg-names:
items:
- const: llcc0_base
- const: llcc1_base
- const: llcc2_base
- const: llcc3_base
- const: llcc4_base
- const: llcc5_base
- const: llcc6_base
- const: llcc7_base
- const: llcc_broadcast_base
- if:
properties:
compatible:
contains:
enum:
- qcom,sdm845-llcc
- qcom,sm8150-llcc
- qcom,sm8250-llcc
- qcom,sm8350-llcc
- qcom,sm8450-llcc
then:
properties:
reg:
items:
- description: LLCC0 base register region
- description: LLCC1 base register region
- description: LLCC2 base register region
- description: LLCC3 base register region
- description: LLCC broadcast base register region
reg-names:
items:
- const: llcc0_base
- const: llcc1_base
- const: llcc2_base
- const: llcc3_base
- const: llcc_broadcast_base
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
system-cache-controller@1100000 {
compatible = "qcom,sdm845-llcc";
reg = <0x1100000 0x200000>, <0x1300000 0x50000> ;
reg-names = "llcc_base", "llcc_broadcast_base";
interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>;
soc {
#address-cells = <2>;
#size-cells = <2>;
system-cache-controller@1100000 {
compatible = "qcom,sdm845-llcc";
reg = <0 0x01100000 0 0x50000>, <0 0x01180000 0 0x50000>,
<0 0x01200000 0 0x50000>, <0 0x01280000 0 0x50000>,
<0 0x01300000 0 0x50000>;
reg-names = "llcc0_base", "llcc1_base", "llcc2_base",
"llcc3_base", "llcc_broadcast_base";
interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>;
};
};

View File

@ -0,0 +1,42 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/crypto/qcom,inline-crypto-engine.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Technologies, Inc. (QTI) Inline Crypto Engine
maintainers:
- Bjorn Andersson <andersson@kernel.org>
properties:
compatible:
items:
- enum:
- qcom,sm8550-inline-crypto-engine
- const: qcom,inline-crypto-engine
reg:
maxItems: 1
clocks:
maxItems: 1
required:
- compatible
- reg
- clocks
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,sm8550-gcc.h>
crypto@1d88000 {
compatible = "qcom,sm8550-inline-crypto-engine",
"qcom,inline-crypto-engine";
reg = <0x01d88000 0x8000>;
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>;
};
...

View File

@ -56,17 +56,38 @@ properties:
description:
Specifies the mailboxes used to communicate with SCMI compliant
firmware.
items:
- const: tx
- const: rx
oneOf:
- items:
- const: tx
- const: rx
minItems: 1
- items:
- const: tx
- const: tx_reply
- const: rx
minItems: 2
mboxes:
description:
List of phandle and mailbox channel specifiers. It should contain
exactly one or two mailboxes, one for transmitting messages("tx")
and another optional for receiving the notifications("rx") if supported.
exactly one, two or three mailboxes; the first one or two for transmitting
messages ("tx") and another optional ("rx") for receiving notifications
and delayed responses, if supported by the platform.
The number of mailboxes needed for transmitting messages depends on the
type of channels exposed by the specific underlying mailbox controller;
one single channel descriptor is enough if such channel is bidirectional,
while two channel descriptors are needed to represent the SCMI ("tx")
channel if the underlying mailbox channels are of unidirectional type.
The effective combination in numbers of mboxes and shmem descriptors let
the SCMI subsystem determine unambiguosly which type of SCMI channels are
made available by the underlying mailbox controller and how to use them.
1 mbox / 1 shmem => SCMI TX over 1 mailbox bidirectional channel
2 mbox / 2 shmem => SCMI TX and RX over 2 mailbox bidirectional channels
2 mbox / 1 shmem => SCMI TX over 2 mailbox unidirectional channels
3 mbox / 2 shmem => SCMI TX and RX over 3 mailbox unidirectional channels
Any other combination of mboxes and shmem is invalid.
minItems: 1
maxItems: 2
maxItems: 3
shmem:
description:
@ -228,13 +249,20 @@ $defs:
maxItems: 1
mbox-names:
items:
- const: tx
- const: rx
oneOf:
- items:
- const: tx
- const: rx
minItems: 1
- items:
- const: tx
- const: tx_reply
- const: rx
minItems: 2
mboxes:
minItems: 1
maxItems: 2
maxItems: 3
shmem:
minItems: 1

View File

@ -24,9 +24,11 @@ properties:
- qcom,scm-apq8064
- qcom,scm-apq8084
- qcom,scm-ipq4019
- qcom,scm-ipq5332
- qcom,scm-ipq6018
- qcom,scm-ipq806x
- qcom,scm-ipq8074
- qcom,scm-ipq9574
- qcom,scm-mdm9607
- qcom,scm-msm8226
- qcom,scm-msm8660
@ -38,10 +40,12 @@ properties:
- qcom,scm-msm8994
- qcom,scm-msm8996
- qcom,scm-msm8998
- qcom,scm-qcm2290
- qcom,scm-qdu1000
- qcom,scm-sa8775p
- qcom,scm-sc7180
- qcom,scm-sc7280
- qcom,scm-sc8180x
- qcom,scm-sc8280xp
- qcom,scm-sdm670
- qcom,scm-sdm845
@ -107,6 +111,7 @@ allOf:
- qcom,scm-msm8960
- qcom,scm-msm8974
- qcom,scm-msm8976
- qcom,scm-qcm2290
- qcom,scm-sm6375
then:
required:
@ -125,6 +130,7 @@ allOf:
- qcom,scm-apq8064
- qcom,scm-msm8660
- qcom,scm-msm8960
- qcom,scm-qcm2290
- qcom,scm-sm6375
then:
properties:
@ -166,6 +172,7 @@ allOf:
compatible:
contains:
enum:
- qcom,scm-qdu1000
- qcom,scm-sm8450
- qcom,scm-sm8550
then:

View File

@ -43,6 +43,7 @@ properties:
- mediatek,mt8195-smi-common-vdo
- mediatek,mt8195-smi-common-vpp
- mediatek,mt8195-smi-sub-common
- mediatek,mt8365-smi-common
- description: for mt7623
items:
@ -133,6 +134,7 @@ allOf:
- mediatek,mt8192-smi-common
- mediatek,mt8195-smi-common-vdo
- mediatek,mt8195-smi-common-vpp
- mediatek,mt8365-smi-common
then:
properties:

View File

@ -34,6 +34,10 @@ properties:
- const: mediatek,mt7623-smi-larb
- const: mediatek,mt2701-smi-larb
- items:
- const: mediatek,mt8365-smi-larb
- const: mediatek,mt8186-smi-larb
reg:
maxItems: 1

View File

@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/memory-controllers/renesas,dbsc.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/memory-controllers/renesas,dbsc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas DDR Bus Controllers

View File

@ -20,7 +20,7 @@ description: |
- if it contains "cfi-flash", then HyperFlash is used.
allOf:
- $ref: "/schemas/spi/spi-controller.yaml#"
- $ref: /schemas/spi/spi-controller.yaml#
properties:
compatible:

View File

@ -42,7 +42,7 @@ properties:
maxItems: 8
devfreq-events:
$ref: '/schemas/types.yaml#/definitions/phandle-array'
$ref: /schemas/types.yaml#/definitions/phandle-array
minItems: 1
maxItems: 16
items:
@ -50,7 +50,7 @@ properties:
description: phandles of the PPMU events used by the controller.
device-handle:
$ref: '/schemas/types.yaml#/definitions/phandle'
$ref: /schemas/types.yaml#/definitions/phandle
description: |
phandle of the connected DRAM memory device. For more information please
refer to jedec,lpddr3.yaml.
@ -73,7 +73,7 @@ properties:
- description: registers of DREX1
samsung,syscon-clk:
$ref: '/schemas/types.yaml#/definitions/phandle'
$ref: /schemas/types.yaml#/definitions/phandle
description: |
Phandle of the clock register set used by the controller, these registers
are used for enabling a 'pause' feature and are not exposed by clock

View File

@ -2,8 +2,8 @@
# Copyright 2019 BayLibre, SAS
%YAML 1.2
---
$id: "http://devicetree.org/schemas/soc/amlogic/amlogic,canvas.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
$id: http://devicetree.org/schemas/soc/amlogic/amlogic,canvas.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic Canvas Video Lookup Table

View File

@ -0,0 +1,40 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/soc/amlogic/amlogic,meson-gx-clk-measure.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic Internal Clock Measurer
description:
The Amlogic SoCs contains an IP to measure the internal clocks.
The precision is multiple of MHz, useful to debug the clock states.
maintainers:
- Neil Armstrong <neil.armstrong@linaro.org>
properties:
compatible:
enum:
- amlogic,meson-gx-clk-measure
- amlogic,meson8-clk-measure
- amlogic,meson8b-clk-measure
- amlogic,meson-axg-clk-measure
- amlogic,meson-g12a-clk-measure
- amlogic,meson-sm1-clk-measure
reg:
maxItems: 1
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
clock-measure@8758 {
compatible = "amlogic,meson-gx-clk-measure";
reg = <0x8758 0x10>;
};

View File

@ -1,21 +0,0 @@
Amlogic Internal Clock Measurer
===============================
The Amlogic SoCs contains an IP to measure the internal clocks.
The precision is multiple of MHz, useful to debug the clock states.
Required properties:
- compatible: Shall contain one of the following :
"amlogic,meson-gx-clk-measure" for GX SoCs
"amlogic,meson8-clk-measure" for Meson8 SoCs
"amlogic,meson8b-clk-measure" for Meson8b SoCs
"amlogic,meson-axg-clk-measure" for AXG SoCs
"amlogic,meson-g12a-clk-measure" for G12a SoCs
"amlogic,meson-sm1-clk-measure" for SM1 SoCs
- reg: base address and size of the Clock Measurer register space.
Example:
clock-measure@8758 {
compatible = "amlogic,meson-gx-clk-measure";
reg = <0x0 0x8758 0x0 0x10>;
};

View File

@ -35,6 +35,8 @@ properties:
- mediatek,mt8188-disp-mutex
- mediatek,mt8192-disp-mutex
- mediatek,mt8195-disp-mutex
- mediatek,mt8195-vpp-mutex
- mediatek,mt8365-disp-mutex
reg:
maxItems: 1
@ -70,12 +72,30 @@ properties:
4 arguments defined in this property. Each GCE subsys id is mapping to
a client defined in the header include/dt-bindings/gce/<chip>-gce.h.
allOf:
- if:
properties:
compatible:
contains:
enum:
- mediatek,mt2701-disp-mutex
- mediatek,mt2712-disp-mutex
- mediatek,mt6795-disp-mutex
- mediatek,mt8173-disp-mutex
- mediatek,mt8186-disp-mutex
- mediatek,mt8186-mdp3-mutex
- mediatek,mt8192-disp-mutex
- mediatek,mt8195-disp-mutex
then:
required:
- clocks
required:
- compatible
- reg
- interrupts
- power-domains
- clocks
additionalProperties: false

View File

@ -25,6 +25,7 @@ properties:
compatible:
items:
- enum:
- qcom,qdu1000-aoss-qmp
- qcom,sc7180-aoss-qmp
- qcom,sc7280-aoss-qmp
- qcom,sc8180x-aoss-qmp

View File

@ -62,7 +62,14 @@ properties:
maxItems: 1
qcom,intents:
$ref: /schemas/types.yaml#/definitions/uint32-array
$ref: /schemas/types.yaml#/definitions/uint32-matrix
minItems: 1
maxItems: 32
items:
items:
- description: size of each intent to preallocate
- description: amount of intents to preallocate
minimum: 1
description:
List of (size, amount) pairs describing what intents should be
preallocated for this virtual channel. This can be used to tweak the

View File

@ -25,6 +25,8 @@ properties:
- qcom,sc8180x-pmic-glink
- qcom,sc8280xp-pmic-glink
- qcom,sm8350-pmic-glink
- qcom,sm8450-pmic-glink
- qcom,sm8550-pmic-glink
- const: qcom,pmic-glink
'#address-cells':

View File

@ -33,6 +33,7 @@ properties:
enum:
- qcom,rpm-apq8084
- qcom,rpm-ipq6018
- qcom,rpm-ipq9574
- qcom,rpm-msm8226
- qcom,rpm-msm8909
- qcom,rpm-msm8916
@ -40,6 +41,7 @@ properties:
- qcom,rpm-msm8953
- qcom,rpm-msm8974
- qcom,rpm-msm8976
- qcom,rpm-msm8994
- qcom,rpm-msm8996
- qcom,rpm-msm8998
- qcom,rpm-sdm660
@ -84,6 +86,7 @@ if:
- qcom,rpm-msm8974
- qcom,rpm-msm8976
- qcom,rpm-msm8953
- qcom,rpm-msm8994
then:
properties:
qcom,glink-channels: false

View File

@ -26,6 +26,7 @@ properties:
- qcom,sdm845-imem
- qcom,sdx55-imem
- qcom,sdx65-imem
- qcom,sm6375-imem
- qcom,sm8450-imem
- const: syscon
- const: simple-mfd

View File

@ -214,6 +214,57 @@ call is done from the thread assisting the interrupt handler. This is a
building block for OP-TEE OS in secure world to implement the top half and
bottom half style of device drivers.
OPTEE_INSECURE_LOAD_IMAGE Kconfig option
----------------------------------------
The OPTEE_INSECURE_LOAD_IMAGE Kconfig option enables the ability to load the
BL32 OP-TEE image from the kernel after the kernel boots, rather than loading
it from the firmware before the kernel boots. This also requires enabling the
corresponding option in Trusted Firmware for Arm. The Trusted Firmware for Arm
documentation [8] explains the security threat associated with enabling this as
well as mitigations at the firmware and platform level.
There are additional attack vectors/mitigations for the kernel that should be
addressed when using this option.
1. Boot chain security.
* Attack vector: Replace the OP-TEE OS image in the rootfs to gain control of
the system.
* Mitigation: There must be boot chain security that verifies the kernel and
rootfs, otherwise an attacker can modify the loaded OP-TEE binary by
modifying it in the rootfs.
2. Alternate boot modes.
* Attack vector: Using an alternate boot mode (i.e. recovery mode), the
OP-TEE driver isn't loaded, leaving the SMC hole open.
* Mitigation: If there are alternate methods of booting the device, such as a
recovery mode, it should be ensured that the same mitigations are applied
in that mode.
3. Attacks prior to SMC invocation.
* Attack vector: Code that is executed prior to issuing the SMC call to load
OP-TEE can be exploited to then load an alternate OS image.
* Mitigation: The OP-TEE driver must be loaded before any potential attack
vectors are opened up. This should include mounting of any modifiable
filesystems, opening of network ports or communicating with external
devices (e.g. USB).
4. Blocking SMC call to load OP-TEE.
* Attack vector: Prevent the driver from being probed, so the SMC call to
load OP-TEE isn't executed when desired, leaving it open to being executed
later and loading a modified OS.
* Mitigation: It is recommended to build the OP-TEE driver as builtin driver
rather than as a module to prevent exploits that may cause the module to
not be loaded.
AMD-TEE driver
==============
@ -309,3 +360,5 @@ References
[6] include/linux/psp-tee.h
[7] drivers/tee/amdtee/amdtee_if.h
[8] https://trustedfirmware-a.readthedocs.io/en/latest/threat_model/threat_model.html

View File

@ -2654,6 +2654,7 @@ F: arch/arm64/boot/dts/renesas/
F: arch/riscv/boot/dts/renesas/
F: drivers/soc/renesas/
F: include/linux/soc/renesas/
K: \brenesas,
ARM/RISCPC ARCHITECTURE
M: Russell King <linux@armlinux.org.uk>

View File

@ -285,5 +285,4 @@ module_platform_driver(tegra_ahb_driver);
MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
MODULE_DESCRIPTION("Tegra AHB driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);

View File

@ -401,12 +401,10 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
struct device_node *dn = pdev->dev.of_node;
struct brcmstb_gisb_arb_device *gdev;
const struct of_device_id *of_id;
struct resource *r;
int err, timeout_irq, tea_irq, bp_irq;
unsigned int num_masters, j = 0;
int i, first, last;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
timeout_irq = platform_get_irq(pdev, 0);
tea_irq = platform_get_irq(pdev, 1);
bp_irq = platform_get_irq(pdev, 2);
@ -418,7 +416,7 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
mutex_init(&gdev->lock);
INIT_LIST_HEAD(&gdev->next);
gdev->base = devm_ioremap_resource(&pdev->dev, r);
gdev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(gdev->base))
return PTR_ERR(gdev->base);

View File

@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
@ -86,8 +87,8 @@ MODULE_DEVICE_TABLE(of, weim_id_table);
static int imx_weim_gpr_setup(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct property *prop;
const __be32 *p;
struct of_range_parser parser;
struct of_range range;
struct regmap *gpr;
u32 gprvals[4] = {
05, /* CS0(128M) CS1(0M) CS2(0M) CS3(0M) */
@ -106,13 +107,13 @@ static int imx_weim_gpr_setup(struct platform_device *pdev)
return 0;
}
of_property_for_each_u32(np, "ranges", prop, p, val) {
if (i % 4 == 0) {
cs = val;
} else if (i % 4 == 3 && val) {
val = (val / SZ_32M) | 1;
gprval |= val << cs * 3;
}
if (of_range_parser_init(&parser, np))
goto err;
for_each_of_range(&parser, &range) {
cs = range.bus_addr >> 32;
val = (range.size / SZ_32M) | 1;
gprval |= val << cs * 3;
i++;
}

View File

@ -648,43 +648,20 @@ static int sysc_init_resets(struct sysc *ddata)
static int sysc_parse_and_check_child_range(struct sysc *ddata)
{
struct device_node *np = ddata->dev->of_node;
const __be32 *ranges;
u32 nr_addr, nr_size;
int len, error;
struct of_range_parser parser;
struct of_range range;
int error;
ranges = of_get_property(np, "ranges", &len);
if (!ranges) {
dev_err(ddata->dev, "missing ranges for %pOF\n", np);
return -ENOENT;
}
len /= sizeof(*ranges);
if (len < 3) {
dev_err(ddata->dev, "incomplete ranges for %pOF\n", np);
return -EINVAL;
}
error = of_property_read_u32(np, "#address-cells", &nr_addr);
error = of_range_parser_init(&parser, np);
if (error)
return -ENOENT;
return error;
error = of_property_read_u32(np, "#size-cells", &nr_size);
if (error)
return -ENOENT;
if (nr_addr != 1 || nr_size != 1) {
dev_err(ddata->dev, "invalid ranges for %pOF\n", np);
return -EINVAL;
for_each_of_range(&parser, &range) {
ddata->module_pa = range.cpu_addr;
ddata->module_size = range.size;
break;
}
ranges++;
ddata->module_pa = of_translate_address(np, ranges++);
ddata->module_size = be32_to_cpup(ranges);
return 0;
}
@ -913,7 +890,7 @@ static int sysc_check_registers(struct sysc *ddata)
* within the interconnect target module range. For example, SGX has
* them at offset 0x1fc00 in the 32MB module address space. And cpsw
* has them at offset 0x1200 in the CPSW_WR child. Usually the
* the interconnect target module registers are at the beginning of
* interconnect target module registers are at the beginning of
* the module range though.
*/
static int sysc_ioremap(struct sysc *ddata)
@ -964,7 +941,7 @@ static int sysc_map_and_check_registers(struct sysc *ddata)
sysc_check_children(ddata);
if (!of_get_property(np, "reg", NULL))
if (!of_property_present(np, "reg"))
return 0;
error = sysc_parse_registers(ddata);
@ -2530,11 +2507,9 @@ static struct dev_pm_domain sysc_child_pm_domain = {
static void sysc_reinit_modules(struct sysc_soc_info *soc)
{
struct sysc_module *module;
struct list_head *pos;
struct sysc *ddata;
list_for_each(pos, &sysc_soc->restored_modules) {
module = list_entry(pos, struct sysc_module, node);
list_for_each_entry(module, &sysc_soc->restored_modules, node) {
ddata = module->ddata;
sysc_reinit_module(ddata, ddata->enabled);
}
@ -3214,12 +3189,10 @@ static void sysc_cleanup_static_data(void)
static int sysc_check_disabled_devices(struct sysc *ddata)
{
struct sysc_address *disabled_module;
struct list_head *pos;
int error = 0;
mutex_lock(&sysc_soc->list_lock);
list_for_each(pos, &sysc_soc->disabled_modules) {
disabled_module = list_entry(pos, struct sysc_address, node);
list_for_each_entry(disabled_module, &sysc_soc->disabled_modules, node) {
if (ddata->module_pa == disabled_module->base) {
dev_dbg(ddata->dev, "module disabled for this SoC\n");
error = -ENODEV;

View File

@ -10,7 +10,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/vexpress.h>

View File

@ -76,6 +76,8 @@
#define DRP0_INTERRUPT_ENABLE BIT(6)
#define SB_DB_DRP_INTERRUPT_ENABLE 0x3
#define ECC_POLL_MSEC 5000
enum {
LLCC_DRAM_CE = 0,
LLCC_DRAM_UE,
@ -213,7 +215,7 @@ dump_syn_reg_values(struct llcc_drv_data *drv, u32 bank, int err_type)
for (i = 0; i < reg_data.reg_cnt; i++) {
synd_reg = reg_data.synd_reg + (i * 4);
ret = regmap_read(drv->regmap, drv->offsets[bank] + synd_reg,
ret = regmap_read(drv->regmaps[bank], synd_reg,
&synd_val);
if (ret)
goto clear;
@ -222,8 +224,7 @@ dump_syn_reg_values(struct llcc_drv_data *drv, u32 bank, int err_type)
reg_data.name, i, synd_val);
}
ret = regmap_read(drv->regmap,
drv->offsets[bank] + reg_data.count_status_reg,
ret = regmap_read(drv->regmaps[bank], reg_data.count_status_reg,
&err_cnt);
if (ret)
goto clear;
@ -233,8 +234,7 @@ dump_syn_reg_values(struct llcc_drv_data *drv, u32 bank, int err_type)
edac_printk(KERN_CRIT, EDAC_LLCC, "%s: Error count: 0x%4x\n",
reg_data.name, err_cnt);
ret = regmap_read(drv->regmap,
drv->offsets[bank] + reg_data.ways_status_reg,
ret = regmap_read(drv->regmaps[bank], reg_data.ways_status_reg,
&err_ways);
if (ret)
goto clear;
@ -285,8 +285,7 @@ dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, u32 bank)
return ret;
}
static irqreturn_t
llcc_ecc_irq_handler(int irq, void *edev_ctl)
static irqreturn_t llcc_ecc_irq_handler(int irq, void *edev_ctl)
{
struct edac_device_ctl_info *edac_dev_ctl = edev_ctl;
struct llcc_drv_data *drv = edac_dev_ctl->dev->platform_data;
@ -296,8 +295,7 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl)
/* Iterate over the banks and look for Tag RAM or Data RAM errors */
for (i = 0; i < drv->num_banks; i++) {
ret = regmap_read(drv->regmap,
drv->offsets[i] + DRP_INTERRUPT_STATUS,
ret = regmap_read(drv->regmaps[i], DRP_INTERRUPT_STATUS,
&drp_error);
if (!ret && (drp_error & SB_ECC_ERROR)) {
@ -312,8 +310,7 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl)
if (!ret)
irq_rc = IRQ_HANDLED;
ret = regmap_read(drv->regmap,
drv->offsets[i] + TRP_INTERRUPT_0_STATUS,
ret = regmap_read(drv->regmaps[i], TRP_INTERRUPT_0_STATUS,
&trp_error);
if (!ret && (trp_error & SB_ECC_ERROR)) {
@ -332,6 +329,11 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl)
return irq_rc;
}
static void llcc_ecc_check(struct edac_device_ctl_info *edev_ctl)
{
llcc_ecc_irq_handler(0, edev_ctl);
}
static int qcom_llcc_edac_probe(struct platform_device *pdev)
{
struct llcc_drv_data *llcc_driv_data = pdev->dev.platform_data;
@ -359,30 +361,32 @@ static int qcom_llcc_edac_probe(struct platform_device *pdev)
edev_ctl->ctl_name = "llcc";
edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE;
/* Check if LLCC driver has passed ECC IRQ */
ecc_irq = llcc_driv_data->ecc_irq;
if (ecc_irq > 0) {
/* Use interrupt mode if IRQ is available */
rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler,
IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
if (!rc) {
edac_op_state = EDAC_OPSTATE_INT;
goto irq_done;
}
}
/* Fall back to polling mode otherwise */
edev_ctl->poll_msec = ECC_POLL_MSEC;
edev_ctl->edac_check = llcc_ecc_check;
edac_op_state = EDAC_OPSTATE_POLL;
irq_done:
rc = edac_device_add_device(edev_ctl);
if (rc)
goto out_mem;
if (rc) {
edac_device_free_ctl_info(edev_ctl);
return rc;
}
platform_set_drvdata(pdev, edev_ctl);
/* Request for ecc irq */
ecc_irq = llcc_driv_data->ecc_irq;
if (ecc_irq < 0) {
rc = -ENODEV;
goto out_dev;
}
rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler,
IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
if (rc)
goto out_dev;
return rc;
out_dev:
edac_device_del_device(edev_ctl->dev);
out_mem:
edac_device_free_ctl_info(edev_ctl);
return rc;
}

View File

@ -2289,7 +2289,7 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo)
return ret;
ret = __scmi_xfer_info_init(sinfo, &sinfo->tx_minfo);
if (!ret && idr_find(&sinfo->rx_idr, SCMI_PROTOCOL_BASE))
if (!ret && !idr_is_empty(&sinfo->rx_idr))
ret = __scmi_xfer_info_init(sinfo, &sinfo->rx_minfo);
return ret;

View File

@ -19,13 +19,15 @@
* struct scmi_mailbox - Structure representing a SCMI mailbox transport
*
* @cl: Mailbox Client
* @chan: Transmit/Receive mailbox channel
* @chan: Transmit/Receive mailbox uni/bi-directional channel
* @chan_receiver: Optional Receiver mailbox unidirectional channel
* @cinfo: SCMI channel info
* @shmem: Transmit/Receive shared memory area
*/
struct scmi_mailbox {
struct mbox_client cl;
struct mbox_chan *chan;
struct mbox_chan *chan_receiver;
struct scmi_chan_info *cinfo;
struct scmi_shared_mem __iomem *shmem;
};
@ -48,30 +50,62 @@ static void rx_callback(struct mbox_client *cl, void *m)
static bool mailbox_chan_available(struct device_node *of_node, int idx)
{
int num_mb;
/*
* Just check if bidirrectional channels are involved, and check the
* index accordingly; proper full validation will be made later
* in mailbox_chan_setup().
*/
num_mb = of_count_phandle_with_args(of_node, "mboxes", "#mbox-cells");
if (num_mb == 3 && idx == 1)
idx = 2;
return !of_parse_phandle_with_args(of_node, "mboxes",
"#mbox-cells", idx, NULL);
}
static int mailbox_chan_validate(struct device *cdev)
/**
* mailbox_chan_validate - Validate transport configuration and map channels
*
* @cdev: Reference to the underlying transport device carrying the
* of_node descriptor to analyze.
* @a2p_rx_chan: A reference to an optional unidirectional channel to use
* for replies on the a2p channel. Set as zero if not present.
* @p2a_chan: A reference to the optional p2a channel.
* Set as zero if not present.
*
* At first, validate the transport configuration as described in terms of
* 'mboxes' and 'shmem', then determin which mailbox channel indexes are
* appropriate to be use in the current configuration.
*
* Return: 0 on Success or error
*/
static int mailbox_chan_validate(struct device *cdev,
int *a2p_rx_chan, int *p2a_chan)
{
int num_mb, num_sh, ret = 0;
struct device_node *np = cdev->of_node;
num_mb = of_count_phandle_with_args(np, "mboxes", "#mbox-cells");
num_sh = of_count_phandle_with_args(np, "shmem", NULL);
dev_dbg(cdev, "Found %d mboxes and %d shmems !\n", num_mb, num_sh);
/* Bail out if mboxes and shmem descriptors are inconsistent */
if (num_mb <= 0 || num_sh > 2 || num_mb != num_sh) {
dev_warn(cdev, "Invalid channel descriptor for '%s'\n",
of_node_full_name(np));
if (num_mb <= 0 || num_sh <= 0 || num_sh > 2 || num_mb > 3 ||
(num_mb == 1 && num_sh != 1) || (num_mb == 3 && num_sh != 2)) {
dev_warn(cdev,
"Invalid channel descriptor for '%s' - mbs:%d shm:%d\n",
of_node_full_name(np), num_mb, num_sh);
return -EINVAL;
}
/* Bail out if provided shmem descriptors do not refer distinct areas */
if (num_sh > 1) {
struct device_node *np_tx, *np_rx;
np_tx = of_parse_phandle(np, "shmem", 0);
np_rx = of_parse_phandle(np, "shmem", 1);
/* SCMI Tx and Rx shared mem areas have to be distinct */
if (!np_tx || !np_rx || np_tx == np_rx) {
dev_warn(cdev, "Invalid shmem descriptor for '%s'\n",
of_node_full_name(np));
@ -82,6 +116,29 @@ static int mailbox_chan_validate(struct device *cdev)
of_node_put(np_rx);
}
/* Calculate channels IDs to use depending on mboxes/shmem layout */
if (!ret) {
switch (num_mb) {
case 1:
*a2p_rx_chan = 0;
*p2a_chan = 0;
break;
case 2:
if (num_sh == 2) {
*a2p_rx_chan = 0;
*p2a_chan = 1;
} else {
*a2p_rx_chan = 1;
*p2a_chan = 0;
}
break;
case 3:
*a2p_rx_chan = 1;
*p2a_chan = 2;
break;
}
}
return ret;
}
@ -92,15 +149,18 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
struct device *cdev = cinfo->dev;
struct scmi_mailbox *smbox;
struct device_node *shmem;
int ret, idx = tx ? 0 : 1;
int ret, a2p_rx_chan, p2a_chan, idx = tx ? 0 : 1;
struct mbox_client *cl;
resource_size_t size;
struct resource res;
ret = mailbox_chan_validate(cdev);
ret = mailbox_chan_validate(cdev, &a2p_rx_chan, &p2a_chan);
if (ret)
return ret;
if (!tx && !p2a_chan)
return -ENODEV;
smbox = devm_kzalloc(dev, sizeof(*smbox), GFP_KERNEL);
if (!smbox)
return -ENOMEM;
@ -130,15 +190,26 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
cl->tx_block = false;
cl->knows_txdone = tx;
smbox->chan = mbox_request_channel(cl, tx ? 0 : 1);
smbox->chan = mbox_request_channel(cl, tx ? 0 : p2a_chan);
if (IS_ERR(smbox->chan)) {
ret = PTR_ERR(smbox->chan);
if (ret != -EPROBE_DEFER)
dev_err(cdev, "failed to request SCMI %s mailbox\n",
tx ? "Tx" : "Rx");
dev_err(cdev,
"failed to request SCMI %s mailbox\n", desc);
return ret;
}
/* Additional unidirectional channel for TX if needed */
if (tx && a2p_rx_chan) {
smbox->chan_receiver = mbox_request_channel(cl, a2p_rx_chan);
if (IS_ERR(smbox->chan_receiver)) {
ret = PTR_ERR(smbox->chan_receiver);
if (ret != -EPROBE_DEFER)
dev_err(cdev, "failed to request SCMI Tx Receiver mailbox\n");
return ret;
}
}
cinfo->transport_info = smbox;
smbox->cinfo = cinfo;
@ -152,8 +223,10 @@ static int mailbox_chan_free(int id, void *p, void *data)
if (smbox && !IS_ERR(smbox->chan)) {
mbox_free_channel(smbox->chan);
mbox_free_channel(smbox->chan_receiver);
cinfo->transport_info = NULL;
smbox->chan = NULL;
smbox->chan_receiver = NULL;
smbox->cinfo = NULL;
}

View File

@ -403,7 +403,7 @@ out:
static int setup_shmem(struct device *dev, struct scmi_chan_info *cinfo,
struct scmi_optee_channel *channel)
{
if (of_find_property(cinfo->dev->of_node, "shmem", NULL))
if (of_property_present(cinfo->dev->of_node, "shmem"))
return setup_static_shmem(dev, cinfo, channel);
else
return setup_dynamic_shmem(dev, channel);

View File

@ -310,9 +310,8 @@ static int imx_scu_probe(struct platform_device *pdev)
sc_chan->ch = mbox_request_channel_byname(cl, chan_name);
if (IS_ERR(sc_chan->ch)) {
ret = PTR_ERR(sc_chan->ch);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to request mbox chan %s ret %d\n",
chan_name, ret);
dev_err_probe(dev, ret, "Failed to request mbox chan %s\n",
chan_name);
kfree(chan_name);
return ret;
}

View File

@ -180,7 +180,11 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
/* LVDS SS */
{ "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 },
{ "lvds0-pwm", IMX_SC_R_LVDS_0_PWM_0, 1, false, 0 },
{ "lvds0-lpi2c", IMX_SC_R_LVDS_0_I2C_0, 2, true, 0 },
{ "lvds1", IMX_SC_R_LVDS_1, 1, false, 0 },
{ "lvds1-pwm", IMX_SC_R_LVDS_1_PWM_0, 1, false, 0 },
{ "lvds1-lpi2c", IMX_SC_R_LVDS_1_I2C_0, 2, true, 0 },
/* DC SS */
{ "dc0", IMX_SC_R_DC_0, 1, false, 0 },

View File

@ -311,11 +311,14 @@ static int __init meson_sm_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, fw);
pr_info("secure-monitor enabled\n");
if (devm_of_platform_populate(dev))
goto out_in_base;
if (sysfs_create_group(&pdev->dev.kobj, &meson_sm_sysfs_attr_group))
goto out_in_base;
pr_info("secure-monitor enabled\n");
return 0;
out_in_base:

View File

@ -905,7 +905,7 @@ static int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region,
* Return negative errno on failure or 0 on success with @srcvm updated.
*/
int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
unsigned int *srcvm,
u64 *srcvm,
const struct qcom_scm_vmperm *newvm,
unsigned int dest_cnt)
{
@ -922,9 +922,9 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
__le32 *src;
void *ptr;
int ret, i, b;
unsigned long srcvm_bits = *srcvm;
u64 srcvm_bits = *srcvm;
src_sz = hweight_long(srcvm_bits) * sizeof(*src);
src_sz = hweight64(srcvm_bits) * sizeof(*src);
mem_to_map_sz = sizeof(*mem_to_map);
dest_sz = dest_cnt * sizeof(*destvm);
ptr_sz = ALIGN(src_sz, SZ_64) + ALIGN(mem_to_map_sz, SZ_64) +
@ -937,8 +937,10 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
/* Fill source vmid detail */
src = ptr;
i = 0;
for_each_set_bit(b, &srcvm_bits, BITS_PER_LONG)
src[i++] = cpu_to_le32(b);
for (b = 0; b < BITS_PER_TYPE(u64); b++) {
if (srcvm_bits & BIT(b))
src[i++] = cpu_to_le32(b);
}
/* Fill details of mem buff to map */
mem_to_map = ptr + ALIGN(src_sz, SZ_64);
@ -1506,8 +1508,7 @@ static int qcom_scm_probe(struct platform_device *pdev)
static void qcom_scm_shutdown(struct platform_device *pdev)
{
/* Clean shutdown, disable download mode to allow normal restart */
if (download_mode)
qcom_scm_set_download_mode(false);
qcom_scm_set_download_mode(false);
}
static const struct of_device_id qcom_scm_dt_match[] = {
@ -1542,6 +1543,7 @@ static const struct of_device_id qcom_scm_dt_match[] = {
},
{ .compatible = "qcom,scm-msm8994" },
{ .compatible = "qcom,scm-msm8996" },
{ .compatible = "qcom,scm-sm6375", .data = (void *)SCM_HAS_CORE_CLK },
{ .compatible = "qcom,scm" },
{}
};

View File

@ -193,7 +193,7 @@ static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name,
},
};
u32 fd = 0, len = 0;
int remaining, err;
int remaining, err, close_err;
mutex_lock(&bpmp_debug_lock);
err = mrq_debug_open(bpmp, name, &fd, &len, 0);
@ -231,7 +231,9 @@ static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name,
*nbytes = len;
close:
err = mrq_debug_close(bpmp, fd);
close_err = mrq_debug_close(bpmp, fd);
if (!err)
err = close_err;
out:
mutex_unlock(&bpmp_debug_lock);
return err;
@ -319,7 +321,7 @@ static int bpmp_debug_show(struct seq_file *m, void *p)
},
};
u32 fd = 0, len = 0;
int remaining, err;
int remaining, err, close_err;
filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf));
if (!filename)
@ -353,7 +355,9 @@ static int bpmp_debug_show(struct seq_file *m, void *p)
}
close:
err = mrq_debug_close(bpmp, fd);
close_err = mrq_debug_close(bpmp, fd);
if (!err)
err = close_err;
out:
mutex_unlock(&bpmp_debug_lock);
return err;

View File

@ -764,19 +764,19 @@ static int tegra_bpmp_probe(struct platform_device *pdev)
if (err < 0)
goto free_mrq;
if (of_find_property(pdev->dev.of_node, "#clock-cells", NULL)) {
if (of_property_present(pdev->dev.of_node, "#clock-cells")) {
err = tegra_bpmp_init_clocks(bpmp);
if (err < 0)
goto free_mrq;
}
if (of_find_property(pdev->dev.of_node, "#reset-cells", NULL)) {
if (of_property_present(pdev->dev.of_node, "#reset-cells")) {
err = tegra_bpmp_init_resets(bpmp);
if (err < 0)
goto free_mrq;
}
if (of_find_property(pdev->dev.of_node, "#power-domain-cells", NULL)) {
if (of_property_present(pdev->dev.of_node, "#power-domain-cells")) {
err = tegra_bpmp_init_powergates(bpmp);
if (err < 0)
goto free_mrq;

View File

@ -39,7 +39,7 @@
#define SCB_CTRL_NOTIFY_MASK BIT(SCB_CTRL_NOTIFY)
#define SCB_CTRL_POS (16)
#define SCB_CTRL_MASK GENMASK_ULL(SCB_CTRL_POS + SCB_MASK_WIDTH, SCB_CTRL_POS)
#define SCB_CTRL_MASK GENMASK(SCB_CTRL_POS + SCB_MASK_WIDTH - 1, SCB_CTRL_POS)
/* SCBCTRL service status register */
@ -79,6 +79,27 @@ static bool mpfs_mbox_busy(struct mpfs_mbox *mbox)
return status & SCB_STATUS_BUSY_MASK;
}
static bool mpfs_mbox_last_tx_done(struct mbox_chan *chan)
{
struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
struct mpfs_mss_response *response = mbox->response;
u32 val;
if (mpfs_mbox_busy(mbox))
return false;
/*
* The service status is stored in bits 31:16 of the SERVICES_SR
* register & is only valid when the system controller is not busy.
* Failed services are intended to generated interrupts, but in reality
* this does not happen, so the status must be checked here.
*/
val = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET);
response->resp_status = (val & SCB_STATUS_MASK) >> SCB_STATUS_POS;
return true;
}
static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data)
{
struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
@ -118,6 +139,7 @@ static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data)
}
opt_sel = ((msg->mbox_offset << 7u) | (msg->cmd_opcode & 0x7fu));
tx_trigger = (opt_sel << SCB_CTRL_POS) & SCB_CTRL_MASK;
tx_trigger |= SCB_CTRL_REQ_MASK | SCB_STATUS_NOTIFY_MASK;
writel_relaxed(tx_trigger, mbox->ctrl_base + SERVICES_CR_OFFSET);
@ -130,7 +152,7 @@ static void mpfs_mbox_rx_data(struct mbox_chan *chan)
struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
struct mpfs_mss_response *response = mbox->response;
u16 num_words = ALIGN((response->resp_size), (4)) / 4U;
u32 i, status;
u32 i;
if (!response->resp_msg) {
dev_err(mbox->dev, "failed to assign memory for response %d\n", -ENOMEM);
@ -138,8 +160,6 @@ static void mpfs_mbox_rx_data(struct mbox_chan *chan)
}
/*
* The status is stored in bits 31:16 of the SERVICES_SR register.
* It is only valid when BUSY == 0.
* We should *never* get an interrupt while the controller is
* still in the busy state. If we do, something has gone badly
* wrong & the content of the mailbox would not be valid.
@ -150,24 +170,10 @@ static void mpfs_mbox_rx_data(struct mbox_chan *chan)
return;
}
status = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET);
/*
* If the status of the individual servers is non-zero, the service has
* failed. The contents of the mailbox at this point are not be valid,
* so don't bother reading them. Set the status so that the driver
* implementing the service can handle the result.
*/
response->resp_status = (status & SCB_STATUS_MASK) >> SCB_STATUS_POS;
if (response->resp_status)
return;
if (!mpfs_mbox_busy(mbox)) {
for (i = 0; i < num_words; i++) {
response->resp_msg[i] =
readl_relaxed(mbox->mbox_base
+ mbox->resp_offset + i * 0x4);
}
for (i = 0; i < num_words; i++) {
response->resp_msg[i] =
readl_relaxed(mbox->mbox_base
+ mbox->resp_offset + i * 0x4);
}
mbox_chan_received_data(chan, response);
@ -182,7 +188,6 @@ static irqreturn_t mpfs_mbox_inbox_isr(int irq, void *data)
mpfs_mbox_rx_data(chan);
mbox_chan_txdone(chan, 0);
return IRQ_HANDLED;
}
@ -212,6 +217,7 @@ static const struct mbox_chan_ops mpfs_mbox_ops = {
.send_data = mpfs_mbox_send_data,
.startup = mpfs_mbox_startup,
.shutdown = mpfs_mbox_shutdown,
.last_tx_done = mpfs_mbox_last_tx_done,
};
static int mpfs_mbox_probe(struct platform_device *pdev)
@ -247,7 +253,8 @@ static int mpfs_mbox_probe(struct platform_device *pdev)
mbox->controller.num_chans = 1;
mbox->controller.chans = mbox->chans;
mbox->controller.ops = &mpfs_mbox_ops;
mbox->controller.txdone_irq = true;
mbox->controller.txdone_poll = true;
mbox->controller.txpoll_period = 10u;
ret = devm_mbox_controller_register(&pdev->dev, &mbox->controller);
if (ret) {

View File

@ -228,7 +228,7 @@ config RENESAS_RPCIF
config STM32_FMC2_EBI
tristate "Support for FMC2 External Bus Interface on STM32MP SoCs"
depends on MACH_STM32MP157 || COMPILE_TEST
depends on ARCH_STM32 || COMPILE_TEST
select MFD_SYSCON
help
Select this option to enable the STM32 FMC2 External Bus Interface

View File

@ -598,7 +598,7 @@ static int atmel_ebi_probe(struct platform_device *pdev)
reg_cells += val;
for_each_available_child_of_node(np, child) {
if (!of_find_property(child, "reg", NULL))
if (!of_property_present(child, "reg"))
continue;
ret = atmel_ebi_dev_setup(ebi, child, reg_cells);

View File

@ -321,4 +321,3 @@ module_platform_driver(l2_ctl_driver);
MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
MODULE_DESCRIPTION("Baikal-T1 L2-cache driver");
MODULE_LICENSE("GPL v2");

View File

@ -164,4 +164,3 @@ module_platform_driver(da8xx_ddrctl_driver);
MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
MODULE_DESCRIPTION("TI da8xx DDR2/mDDR controller driver");
MODULE_LICENSE("GPL v2");

View File

@ -327,6 +327,5 @@ static int __init fsl_ifc_init(void)
}
subsys_initcall(fsl_ifc_init);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Freescale Semiconductor");
MODULE_DESCRIPTION("Freescale Integrated Flash Controller driver");

View File

@ -713,6 +713,11 @@ static const struct mtk_smi_common_plat mtk_smi_sub_common_mt8195 = {
.has_gals = true,
};
static const struct mtk_smi_common_plat mtk_smi_common_mt8365 = {
.type = MTK_SMI_GEN2,
.bus_sel = F_MMU1_LARB(2) | F_MMU1_LARB(4),
};
static const struct of_device_id mtk_smi_common_of_ids[] = {
{.compatible = "mediatek,mt2701-smi-common", .data = &mtk_smi_common_gen1},
{.compatible = "mediatek,mt2712-smi-common", .data = &mtk_smi_common_gen2},
@ -728,6 +733,7 @@ static const struct of_device_id mtk_smi_common_of_ids[] = {
{.compatible = "mediatek,mt8195-smi-common-vdo", .data = &mtk_smi_common_mt8195_vdo},
{.compatible = "mediatek,mt8195-smi-common-vpp", .data = &mtk_smi_common_mt8195_vpp},
{.compatible = "mediatek,mt8195-smi-sub-common", .data = &mtk_smi_sub_common_mt8195},
{.compatible = "mediatek,mt8365-smi-common", .data = &mtk_smi_common_mt8365},
{}
};

View File

@ -341,6 +341,5 @@ static int __init mvebu_devbus_init(void)
}
module_init(mvebu_devbus_init);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>");
MODULE_DESCRIPTION("Marvell EBU SoC Device Bus controller");

View File

@ -983,4 +983,3 @@ arch_initcall(tegra_mc_init);
MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
MODULE_DESCRIPTION("NVIDIA Tegra Memory Controller driver");
MODULE_LICENSE("GPL v2");

View File

@ -280,4 +280,3 @@ module_platform_driver(tegra186_emc_driver);
MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
MODULE_DESCRIPTION("NVIDIA Tegra186 External Memory Controller driver");
MODULE_LICENSE("GPL v2");

View File

@ -277,7 +277,7 @@ static u32 update_clock_tree_delay(struct tegra210_emc *emc, int type)
/*
* Dev1 LSB.
*/
value = tegra210_emc_mrr_read(emc, 2, 18);
value = tegra210_emc_mrr_read(emc, 1, 18);
for (i = 0; i < emc->num_channels; i++) {
temp[i][0] |= (value & 0x00ff) >> 0;

View File

@ -22,8 +22,6 @@ static int tegra210_emc_table_device_init(struct reserved_mem *rmem,
return -ENOMEM;
}
count = 0;
for (i = 0; i < TEGRA_EMC_MAX_FREQS; i++) {
if (timings[i].revision == 0)
break;

View File

@ -262,7 +262,7 @@ struct fastrpc_channel_ctx {
int domain_id;
int sesscount;
int vmcount;
u32 perms;
u64 perms;
struct qcom_scm_vmperm vmperms[FASTRPC_MAX_VMIDS];
struct rpmsg_device *rpdev;
struct fastrpc_session_ctx session[FASTRPC_MAX_SESSIONS];

View File

@ -33,7 +33,7 @@ static int ath10k_qmi_map_msa_permission(struct ath10k_qmi *qmi,
{
struct qcom_scm_vmperm dst_perms[3];
struct ath10k *ar = qmi->ar;
unsigned int src_perms;
u64 src_perms;
u32 perm_count;
int ret;
@ -65,7 +65,7 @@ static int ath10k_qmi_unmap_msa_permission(struct ath10k_qmi *qmi,
{
struct qcom_scm_vmperm dst_perms;
struct ath10k *ar = qmi->ar;
unsigned int src_perms;
u64 src_perms;
int ret;
src_perms = BIT(QCOM_SCM_VMID_MSS_MSA) | BIT(QCOM_SCM_VMID_WLAN);

View File

@ -235,8 +235,8 @@ struct q6v5 {
bool has_qaccept_regs;
bool has_ext_cntl_regs;
bool has_vq6;
int mpss_perm;
int mba_perm;
u64 mpss_perm;
u64 mba_perm;
const char *hexagon_mdt_image;
int version;
};
@ -414,7 +414,7 @@ static void q6v5_pds_disable(struct q6v5 *qproc, struct device **pds,
}
}
static int q6v5_xfer_mem_ownership(struct q6v5 *qproc, int *current_perm,
static int q6v5_xfer_mem_ownership(struct q6v5 *qproc, u64 *current_perm,
bool local, bool remote, phys_addr_t addr,
size_t size)
{
@ -967,7 +967,7 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw,
unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
dma_addr_t phys;
void *metadata;
int mdata_perm;
u64 mdata_perm;
int xferop_ret;
size_t size;
void *ptr;

View File

@ -94,7 +94,7 @@ struct qcom_adsp {
size_t region_assign_size;
int region_assign_idx;
int region_assign_perms;
u64 region_assign_perms;
struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_subdev smd_subdev;

View File

@ -308,11 +308,9 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
}
rstc = devm_reset_control_array_get_exclusive(&pdev->dev);
if (IS_ERR(rstc)) {
if (PTR_ERR(rstc) != -EPROBE_DEFER)
dev_err(&pdev->dev, "failed to get reset lines\n");
return PTR_ERR(rstc);
}
if (IS_ERR(rstc))
return dev_err_probe(&pdev->dev, PTR_ERR(rstc),
"failed to get reset lines\n");
vpu_clk = devm_clk_get(&pdev->dev, "vpu");
if (IS_ERR(vpu_clk)) {

View File

@ -55,7 +55,7 @@ enum {
#define APPLE_RTKIT_BUFFER_REQUEST 1
#define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK_ULL(51, 44)
#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK_ULL(41, 0)
#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK_ULL(43, 0)
#define APPLE_RTKIT_SYSLOG_TYPE GENMASK_ULL(59, 52)
@ -409,11 +409,17 @@ static void apple_rtkit_syslog_rx_init(struct apple_rtkit *rtk, u64 msg)
rtk->syslog_n_entries, rtk->syslog_msg_size);
}
static bool should_crop_syslog_char(char c)
{
return c == '\n' || c == '\r' || c == ' ' || c == '\0';
}
static void apple_rtkit_syslog_rx_log(struct apple_rtkit *rtk, u64 msg)
{
u8 idx = msg & 0xff;
char log_context[24];
size_t entry_size = 0x20 + rtk->syslog_msg_size;
int msglen;
if (!rtk->syslog_msg_buffer) {
dev_warn(
@ -446,7 +452,13 @@ static void apple_rtkit_syslog_rx_log(struct apple_rtkit *rtk, u64 msg)
rtk->syslog_msg_size);
log_context[sizeof(log_context) - 1] = 0;
rtk->syslog_msg_buffer[rtk->syslog_msg_size - 1] = 0;
msglen = rtk->syslog_msg_size - 1;
while (msglen > 0 &&
should_crop_syslog_char(rtk->syslog_msg_buffer[msglen - 1]))
msglen--;
rtk->syslog_msg_buffer[msglen] = 0;
dev_info(rtk->dev, "RTKit: syslog message: %s: %s\n", log_context,
rtk->syslog_msg_buffer);

View File

@ -711,4 +711,3 @@ module_platform_driver(bcm2835_power_driver);
MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset");
MODULE_LICENSE("GPL");

View File

@ -4,8 +4,6 @@ if SOC_BRCMSTB
config BRCMSTB_PM
bool "Support suspend/resume for STB platforms"
default y
depends on PM
depends on ARCH_BRCMSTB || BMIPS_GENERIC
select ARM_CPU_SUSPEND if ARM
depends on PM && BMIPS_GENERIC
endif # SOC_BRCMSTB

View File

@ -288,6 +288,10 @@ static int __init setup_hifcpubiuctrl_regs(struct device_node *np)
if (BRCM_ID(family_id) == 0x7260 && BRCM_REV(family_id) == 0)
cpubiuctrl_regs = b53_cpubiuctrl_no_wb_regs;
out:
if (ret && cpubiuctrl_base) {
iounmap(cpubiuctrl_base);
cpubiuctrl_base = NULL;
}
return ret;
}

View File

@ -1,3 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_ARM) += s2-arm.o pm-arm.o
obj-$(CONFIG_BMIPS_GENERIC) += s2-mips.o s3-mips.o pm-mips.o

View File

@ -1,105 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Always ON (AON) register interface between bootloader and Linux
*
* Copyright © 2014-2017 Broadcom
*/
#ifndef __BRCMSTB_AON_DEFS_H__
#define __BRCMSTB_AON_DEFS_H__
#include <linux/compiler.h>
/* Magic number in upper 16-bits */
#define BRCMSTB_S3_MAGIC_MASK 0xffff0000
#define BRCMSTB_S3_MAGIC_SHORT 0x5AFE0000
enum {
/* Restore random key for AES memory verification (off = fixed key) */
S3_FLAG_LOAD_RANDKEY = (1 << 0),
/* Scratch buffer page table is present */
S3_FLAG_SCRATCH_BUFFER_TABLE = (1 << 1),
/* Skip all memory verification */
S3_FLAG_NO_MEM_VERIFY = (1 << 2),
/*
* Modification of this bit reserved for bootloader only.
* 1=PSCI started Linux, 0=Direct jump to Linux.
*/
S3_FLAG_PSCI_BOOT = (1 << 3),
/*
* Modification of this bit reserved for bootloader only.
* 1=64 bit boot, 0=32 bit boot.
*/
S3_FLAG_BOOTED64 = (1 << 4),
};
#define BRCMSTB_HASH_LEN (128 / 8) /* 128-bit hash */
#define AON_REG_MAGIC_FLAGS 0x00
#define AON_REG_CONTROL_LOW 0x04
#define AON_REG_CONTROL_HIGH 0x08
#define AON_REG_S3_HASH 0x0c /* hash of S3 params */
#define AON_REG_CONTROL_HASH_LEN 0x1c
#define AON_REG_PANIC 0x20
#define BRCMSTB_S3_MAGIC 0x5AFEB007
#define BRCMSTB_PANIC_MAGIC 0x512E115E
#define BOOTLOADER_SCRATCH_SIZE 64
#define BRCMSTB_DTU_STATE_MAP_ENTRIES (8*1024)
#define BRCMSTB_DTU_CONFIG_ENTRIES (512)
#define BRCMSTB_DTU_COUNT (2)
#define IMAGE_DESCRIPTORS_BUFSIZE (2 * 1024)
#define S3_BOOTLOADER_RESERVED (S3_FLAG_PSCI_BOOT | S3_FLAG_BOOTED64)
struct brcmstb_bootloader_dtu_table {
uint32_t dtu_state_map[BRCMSTB_DTU_STATE_MAP_ENTRIES];
uint32_t dtu_config[BRCMSTB_DTU_CONFIG_ENTRIES];
};
/*
* Bootloader utilizes a custom parameter block left in DRAM for handling S3
* warm resume
*/
struct brcmstb_s3_params {
/* scratch memory for bootloader */
uint8_t scratch[BOOTLOADER_SCRATCH_SIZE];
uint32_t magic; /* BRCMSTB_S3_MAGIC */
uint64_t reentry; /* PA */
/* descriptors */
uint32_t hash[BRCMSTB_HASH_LEN / 4];
/*
* If 0, then ignore this parameter (there is only one set of
* descriptors)
*
* If non-0, then a second set of descriptors is stored at:
*
* descriptors + desc_offset_2
*
* The MAC result of both descriptors is XOR'd and stored in @hash
*/
uint32_t desc_offset_2;
/*
* (Physical) address of a brcmstb_bootloader_scratch_table, for
* providing a large DRAM buffer to the bootloader
*/
uint64_t buffer_table;
uint32_t spare[70];
uint8_t descriptors[IMAGE_DESCRIPTORS_BUFSIZE];
/*
* Must be last member of struct. See brcmstb_pm_s3_finish() for reason.
*/
struct brcmstb_bootloader_dtu_table dtu[BRCMSTB_DTU_COUNT];
} __packed;
#endif /* __BRCMSTB_AON_DEFS_H__ */

View File

@ -1,874 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* ARM-specific support for Broadcom STB S2/S3/S5 power management
*
* S2: clock gate CPUs and as many peripherals as possible
* S3: power off all of the chip except the Always ON (AON) island; keep DDR is
* self-refresh
* S5: (a.k.a. S3 cold boot) much like S3, except DDR is powered down, so we
* treat this mode like a soft power-off, with wakeup allowed from AON
*
* Copyright © 2014-2017 Broadcom
*/
#define pr_fmt(fmt) "brcmstb-pm: " fmt
#include <linux/bitops.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kconfig.h>
#include <linux/kernel.h>
#include <linux/memblock.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/panic_notifier.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/printk.h>
#include <linux/proc_fs.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/sort.h>
#include <linux/suspend.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/soc/brcmstb/brcmstb.h>
#include <asm/fncpy.h>
#include <asm/setup.h>
#include <asm/suspend.h>
#include "pm.h"
#include "aon_defs.h"
#define SHIMPHY_DDR_PAD_CNTRL 0x8c
/* Method #0 */
#define SHIMPHY_PAD_PLL_SEQUENCE BIT(8)
#define SHIMPHY_PAD_GATE_PLL_S3 BIT(9)
/* Method #1 */
#define PWRDWN_SEQ_NO_SEQUENCING 0
#define PWRDWN_SEQ_HOLD_CHANNEL 1
#define PWRDWN_SEQ_RESET_PLL 2
#define PWRDWN_SEQ_POWERDOWN_PLL 3
#define SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK 0x00f00000
#define SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT 20
#define DDR_FORCE_CKE_RST_N BIT(3)
#define DDR_PHY_RST_N BIT(2)
#define DDR_PHY_CKE BIT(1)
#define DDR_PHY_NO_CHANNEL 0xffffffff
#define MAX_NUM_MEMC 3
struct brcmstb_memc {
void __iomem *ddr_phy_base;
void __iomem *ddr_shimphy_base;
void __iomem *ddr_ctrl;
};
struct brcmstb_pm_control {
void __iomem *aon_ctrl_base;
void __iomem *aon_sram;
struct brcmstb_memc memcs[MAX_NUM_MEMC];
void __iomem *boot_sram;
size_t boot_sram_len;
bool support_warm_boot;
size_t pll_status_offset;
int num_memc;
struct brcmstb_s3_params *s3_params;
dma_addr_t s3_params_pa;
int s3entry_method;
u32 warm_boot_offset;
u32 phy_a_standby_ctrl_offs;
u32 phy_b_standby_ctrl_offs;
bool needs_ddr_pad;
struct platform_device *pdev;
};
enum bsp_initiate_command {
BSP_CLOCK_STOP = 0x00,
BSP_GEN_RANDOM_KEY = 0x4A,
BSP_RESTORE_RANDOM_KEY = 0x55,
BSP_GEN_FIXED_KEY = 0x63,
};
#define PM_INITIATE 0x01
#define PM_INITIATE_SUCCESS 0x00
#define PM_INITIATE_FAIL 0xfe
static struct brcmstb_pm_control ctrl;
noinline int brcmstb_pm_s3_finish(void);
static int (*brcmstb_pm_do_s2_sram)(void __iomem *aon_ctrl_base,
void __iomem *ddr_phy_pll_status);
static int brcmstb_init_sram(struct device_node *dn)
{
void __iomem *sram;
struct resource res;
int ret;
ret = of_address_to_resource(dn, 0, &res);
if (ret)
return ret;
/* Uncached, executable remapping of SRAM */
sram = __arm_ioremap_exec(res.start, resource_size(&res), false);
if (!sram)
return -ENOMEM;
ctrl.boot_sram = sram;
ctrl.boot_sram_len = resource_size(&res);
return 0;
}
static const struct of_device_id sram_dt_ids[] = {
{ .compatible = "mmio-sram" },
{ /* sentinel */ }
};
static int do_bsp_initiate_command(enum bsp_initiate_command cmd)
{
void __iomem *base = ctrl.aon_ctrl_base;
int ret;
int timeo = 1000 * 1000; /* 1 second */
writel_relaxed(0, base + AON_CTRL_PM_INITIATE);
(void)readl_relaxed(base + AON_CTRL_PM_INITIATE);
/* Go! */
writel_relaxed((cmd << 1) | PM_INITIATE, base + AON_CTRL_PM_INITIATE);
/*
* If firmware doesn't support the 'ack', then just assume it's done
* after 10ms. Note that this only works for command 0, BSP_CLOCK_STOP
*/
if (of_machine_is_compatible("brcm,bcm74371a0")) {
(void)readl_relaxed(base + AON_CTRL_PM_INITIATE);
mdelay(10);
return 0;
}
for (;;) {
ret = readl_relaxed(base + AON_CTRL_PM_INITIATE);
if (!(ret & PM_INITIATE))
break;
if (timeo <= 0) {
pr_err("error: timeout waiting for BSP (%x)\n", ret);
break;
}
timeo -= 50;
udelay(50);
}
return (ret & 0xff) != PM_INITIATE_SUCCESS;
}
static int brcmstb_pm_handshake(void)
{
void __iomem *base = ctrl.aon_ctrl_base;
u32 tmp;
int ret;
/* BSP power handshake, v1 */
tmp = readl_relaxed(base + AON_CTRL_HOST_MISC_CMDS);
tmp &= ~1UL;
writel_relaxed(tmp, base + AON_CTRL_HOST_MISC_CMDS);
(void)readl_relaxed(base + AON_CTRL_HOST_MISC_CMDS);
ret = do_bsp_initiate_command(BSP_CLOCK_STOP);
if (ret)
pr_err("BSP handshake failed\n");
/*
* HACK: BSP may have internal race on the CLOCK_STOP command.
* Avoid touching the BSP for a few milliseconds.
*/
mdelay(3);
return ret;
}
static inline void shimphy_set(u32 value, u32 mask)
{
int i;
if (!ctrl.needs_ddr_pad)
return;
for (i = 0; i < ctrl.num_memc; i++) {
u32 tmp;
tmp = readl_relaxed(ctrl.memcs[i].ddr_shimphy_base +
SHIMPHY_DDR_PAD_CNTRL);
tmp = value | (tmp & mask);
writel_relaxed(tmp, ctrl.memcs[i].ddr_shimphy_base +
SHIMPHY_DDR_PAD_CNTRL);
}
wmb(); /* Complete sequence in order. */
}
static inline void ddr_ctrl_set(bool warmboot)
{
int i;
for (i = 0; i < ctrl.num_memc; i++) {
u32 tmp;
tmp = readl_relaxed(ctrl.memcs[i].ddr_ctrl +
ctrl.warm_boot_offset);
if (warmboot)
tmp |= 1;
else
tmp &= ~1; /* Cold boot */
writel_relaxed(tmp, ctrl.memcs[i].ddr_ctrl +
ctrl.warm_boot_offset);
}
/* Complete sequence in order */
wmb();
}
static inline void s3entry_method0(void)
{
shimphy_set(SHIMPHY_PAD_GATE_PLL_S3 | SHIMPHY_PAD_PLL_SEQUENCE,
0xffffffff);
}
static inline void s3entry_method1(void)
{
/*
* S3 Entry Sequence
* -----------------
* Step 1: SHIMPHY_ADDR_CNTL_0_DDR_PAD_CNTRL [ S3_PWRDWN_SEQ ] = 3
* Step 2: MEMC_DDR_0_WARM_BOOT [ WARM_BOOT ] = 1
*/
shimphy_set((PWRDWN_SEQ_POWERDOWN_PLL <<
SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT),
~SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK);
ddr_ctrl_set(true);
}
static inline void s5entry_method1(void)
{
int i;
/*
* S5 Entry Sequence
* -----------------
* Step 1: SHIMPHY_ADDR_CNTL_0_DDR_PAD_CNTRL [ S3_PWRDWN_SEQ ] = 3
* Step 2: MEMC_DDR_0_WARM_BOOT [ WARM_BOOT ] = 0
* Step 3: DDR_PHY_CONTROL_REGS_[AB]_0_STANDBY_CONTROL[ CKE ] = 0
* DDR_PHY_CONTROL_REGS_[AB]_0_STANDBY_CONTROL[ RST_N ] = 0
*/
shimphy_set((PWRDWN_SEQ_POWERDOWN_PLL <<
SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT),
~SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK);
ddr_ctrl_set(false);
for (i = 0; i < ctrl.num_memc; i++) {
u32 tmp;
/* Step 3: Channel A (RST_N = CKE = 0) */
tmp = readl_relaxed(ctrl.memcs[i].ddr_phy_base +
ctrl.phy_a_standby_ctrl_offs);
tmp &= ~(DDR_PHY_RST_N | DDR_PHY_RST_N);
writel_relaxed(tmp, ctrl.memcs[i].ddr_phy_base +
ctrl.phy_a_standby_ctrl_offs);
/* Step 3: Channel B? */
if (ctrl.phy_b_standby_ctrl_offs != DDR_PHY_NO_CHANNEL) {
tmp = readl_relaxed(ctrl.memcs[i].ddr_phy_base +
ctrl.phy_b_standby_ctrl_offs);
tmp &= ~(DDR_PHY_RST_N | DDR_PHY_RST_N);
writel_relaxed(tmp, ctrl.memcs[i].ddr_phy_base +
ctrl.phy_b_standby_ctrl_offs);
}
}
/* Must complete */
wmb();
}
/*
* Run a Power Management State Machine (PMSM) shutdown command and put the CPU
* into a low-power mode
*/
static void brcmstb_do_pmsm_power_down(unsigned long base_cmd, bool onewrite)
{
void __iomem *base = ctrl.aon_ctrl_base;
if ((ctrl.s3entry_method == 1) && (base_cmd == PM_COLD_CONFIG))
s5entry_method1();
/* pm_start_pwrdn transition 0->1 */
writel_relaxed(base_cmd, base + AON_CTRL_PM_CTRL);
if (!onewrite) {
(void)readl_relaxed(base + AON_CTRL_PM_CTRL);
writel_relaxed(base_cmd | PM_PWR_DOWN, base + AON_CTRL_PM_CTRL);
(void)readl_relaxed(base + AON_CTRL_PM_CTRL);
}
wfi();
}
/* Support S5 cold boot out of "poweroff" */
static void brcmstb_pm_poweroff(void)
{
brcmstb_pm_handshake();
/* Clear magic S3 warm-boot value */
writel_relaxed(0, ctrl.aon_sram + AON_REG_MAGIC_FLAGS);
(void)readl_relaxed(ctrl.aon_sram + AON_REG_MAGIC_FLAGS);
/* Skip wait-for-interrupt signal; just use a countdown */
writel_relaxed(0x10, ctrl.aon_ctrl_base + AON_CTRL_PM_CPU_WAIT_COUNT);
(void)readl_relaxed(ctrl.aon_ctrl_base + AON_CTRL_PM_CPU_WAIT_COUNT);
if (ctrl.s3entry_method == 1) {
shimphy_set((PWRDWN_SEQ_POWERDOWN_PLL <<
SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT),
~SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK);
ddr_ctrl_set(false);
brcmstb_do_pmsm_power_down(M1_PM_COLD_CONFIG, true);
return; /* We should never actually get here */
}
brcmstb_do_pmsm_power_down(PM_COLD_CONFIG, false);
}
static void *brcmstb_pm_copy_to_sram(void *fn, size_t len)
{
unsigned int size = ALIGN(len, FNCPY_ALIGN);
if (ctrl.boot_sram_len < size) {
pr_err("standby code will not fit in SRAM\n");
return NULL;
}
return fncpy(ctrl.boot_sram, fn, size);
}
/*
* S2 suspend/resume picks up where we left off, so we must execute carefully
* from SRAM, in order to allow DDR to come back up safely before we continue.
*/
static int brcmstb_pm_s2(void)
{
/* A previous S3 can set a value hazardous to S2, so make sure. */
if (ctrl.s3entry_method == 1) {
shimphy_set((PWRDWN_SEQ_NO_SEQUENCING <<
SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT),
~SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK);
ddr_ctrl_set(false);
}
brcmstb_pm_do_s2_sram = brcmstb_pm_copy_to_sram(&brcmstb_pm_do_s2,
brcmstb_pm_do_s2_sz);
if (!brcmstb_pm_do_s2_sram)
return -EINVAL;
return brcmstb_pm_do_s2_sram(ctrl.aon_ctrl_base,
ctrl.memcs[0].ddr_phy_base +
ctrl.pll_status_offset);
}
/*
* This function is called on a new stack, so don't allow inlining (which will
* generate stack references on the old stack). It cannot be made static because
* it is referenced from brcmstb_pm_s3()
*/
noinline int brcmstb_pm_s3_finish(void)
{
struct brcmstb_s3_params *params = ctrl.s3_params;
dma_addr_t params_pa = ctrl.s3_params_pa;
phys_addr_t reentry = virt_to_phys(&cpu_resume_arm);
enum bsp_initiate_command cmd;
u32 flags;
/*
* Clear parameter structure, but not DTU area, which has already been
* filled in. We know DTU is a the end, so we can just subtract its
* size.
*/
memset(params, 0, sizeof(*params) - sizeof(params->dtu));
flags = readl_relaxed(ctrl.aon_sram + AON_REG_MAGIC_FLAGS);
flags &= S3_BOOTLOADER_RESERVED;
flags |= S3_FLAG_NO_MEM_VERIFY;
flags |= S3_FLAG_LOAD_RANDKEY;
/* Load random / fixed key */
if (flags & S3_FLAG_LOAD_RANDKEY)
cmd = BSP_GEN_RANDOM_KEY;
else
cmd = BSP_GEN_FIXED_KEY;
if (do_bsp_initiate_command(cmd)) {
pr_info("key loading failed\n");
return -EIO;
}
params->magic = BRCMSTB_S3_MAGIC;
params->reentry = reentry;
/* No more writes to DRAM */
flush_cache_all();
flags |= BRCMSTB_S3_MAGIC_SHORT;
writel_relaxed(flags, ctrl.aon_sram + AON_REG_MAGIC_FLAGS);
writel_relaxed(lower_32_bits(params_pa),
ctrl.aon_sram + AON_REG_CONTROL_LOW);
writel_relaxed(upper_32_bits(params_pa),
ctrl.aon_sram + AON_REG_CONTROL_HIGH);
switch (ctrl.s3entry_method) {
case 0:
s3entry_method0();
brcmstb_do_pmsm_power_down(PM_WARM_CONFIG, false);
break;
case 1:
s3entry_method1();
brcmstb_do_pmsm_power_down(M1_PM_WARM_CONFIG, true);
break;
default:
return -EINVAL;
}
/* Must have been interrupted from wfi()? */
return -EINTR;
}
static int brcmstb_pm_do_s3(unsigned long sp)
{
unsigned long save_sp;
int ret;
asm volatile (
"mov %[save], sp\n"
"mov sp, %[new]\n"
"bl brcmstb_pm_s3_finish\n"
"mov %[ret], r0\n"
"mov %[new], sp\n"
"mov sp, %[save]\n"
: [save] "=&r" (save_sp), [ret] "=&r" (ret)
: [new] "r" (sp)
);
return ret;
}
static int brcmstb_pm_s3(void)
{
void __iomem *sp = ctrl.boot_sram + ctrl.boot_sram_len;
return cpu_suspend((unsigned long)sp, brcmstb_pm_do_s3);
}
static int brcmstb_pm_standby(bool deep_standby)
{
int ret;
if (brcmstb_pm_handshake())
return -EIO;
if (deep_standby)
ret = brcmstb_pm_s3();
else
ret = brcmstb_pm_s2();
if (ret)
pr_err("%s: standby failed\n", __func__);
return ret;
}
static int brcmstb_pm_enter(suspend_state_t state)
{
int ret = -EINVAL;
switch (state) {
case PM_SUSPEND_STANDBY:
ret = brcmstb_pm_standby(false);
break;
case PM_SUSPEND_MEM:
ret = brcmstb_pm_standby(true);
break;
}
return ret;
}
static int brcmstb_pm_valid(suspend_state_t state)
{
switch (state) {
case PM_SUSPEND_STANDBY:
return true;
case PM_SUSPEND_MEM:
return ctrl.support_warm_boot;
default:
return false;
}
}
static const struct platform_suspend_ops brcmstb_pm_ops = {
.enter = brcmstb_pm_enter,
.valid = brcmstb_pm_valid,
};
static const struct of_device_id aon_ctrl_dt_ids[] = {
{ .compatible = "brcm,brcmstb-aon-ctrl" },
{}
};
struct ddr_phy_ofdata {
bool supports_warm_boot;
size_t pll_status_offset;
int s3entry_method;
u32 warm_boot_offset;
u32 phy_a_standby_ctrl_offs;
u32 phy_b_standby_ctrl_offs;
};
static struct ddr_phy_ofdata ddr_phy_71_1 = {
.supports_warm_boot = true,
.pll_status_offset = 0x0c,
.s3entry_method = 1,
.warm_boot_offset = 0x2c,
.phy_a_standby_ctrl_offs = 0x198,
.phy_b_standby_ctrl_offs = DDR_PHY_NO_CHANNEL
};
static struct ddr_phy_ofdata ddr_phy_72_0 = {
.supports_warm_boot = true,
.pll_status_offset = 0x10,
.s3entry_method = 1,
.warm_boot_offset = 0x40,
.phy_a_standby_ctrl_offs = 0x2a4,
.phy_b_standby_ctrl_offs = 0x8a4
};
static struct ddr_phy_ofdata ddr_phy_225_1 = {
.supports_warm_boot = false,
.pll_status_offset = 0x4,
.s3entry_method = 0
};
static struct ddr_phy_ofdata ddr_phy_240_1 = {
.supports_warm_boot = true,
.pll_status_offset = 0x4,
.s3entry_method = 0
};
static const struct of_device_id ddr_phy_dt_ids[] = {
{
.compatible = "brcm,brcmstb-ddr-phy-v71.1",
.data = &ddr_phy_71_1,
},
{
.compatible = "brcm,brcmstb-ddr-phy-v72.0",
.data = &ddr_phy_72_0,
},
{
.compatible = "brcm,brcmstb-ddr-phy-v225.1",
.data = &ddr_phy_225_1,
},
{
.compatible = "brcm,brcmstb-ddr-phy-v240.1",
.data = &ddr_phy_240_1,
},
{
/* Same as v240.1, for the registers we care about */
.compatible = "brcm,brcmstb-ddr-phy-v240.2",
.data = &ddr_phy_240_1,
},
{}
};
struct ddr_seq_ofdata {
bool needs_ddr_pad;
u32 warm_boot_offset;
};
static const struct ddr_seq_ofdata ddr_seq_b22 = {
.needs_ddr_pad = false,
.warm_boot_offset = 0x2c,
};
static const struct ddr_seq_ofdata ddr_seq = {
.needs_ddr_pad = true,
};
static const struct of_device_id ddr_shimphy_dt_ids[] = {
{ .compatible = "brcm,brcmstb-ddr-shimphy-v1.0" },
{}
};
static const struct of_device_id brcmstb_memc_of_match[] = {
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.1",
.data = &ddr_seq,
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.2",
.data = &ddr_seq_b22,
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.2.3",
.data = &ddr_seq_b22,
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.3.0",
.data = &ddr_seq_b22,
},
{
.compatible = "brcm,brcmstb-memc-ddr-rev-b.3.1",
.data = &ddr_seq_b22,
},
{
.compatible = "brcm,brcmstb-memc-ddr",
.data = &ddr_seq,
},
{},
};
static void __iomem *brcmstb_ioremap_match(const struct of_device_id *matches,
int index, const void **ofdata)
{
struct device_node *dn;
const struct of_device_id *match;
dn = of_find_matching_node_and_match(NULL, matches, &match);
if (!dn)
return ERR_PTR(-EINVAL);
if (ofdata)
*ofdata = match->data;
return of_io_request_and_map(dn, index, dn->full_name);
}
/*
* The AON is a small domain in the SoC that can retain its state across
* various system wide sleep states and specific reset conditions; the
* AON DATA RAM is a small RAM of a few words (< 1KB) which can store
* persistent information across such events.
*
* The purpose of the below panic notifier is to help with notifying
* the bootloader that a panic occurred and so that it should try its
* best to preserve the DRAM contents holding that buffer for recovery
* by the kernel as opposed to wiping out DRAM clean again.
*
* Reference: comment from Florian Fainelli, at
* https://lore.kernel.org/lkml/781cafb0-8d06-8b56-907a-5175c2da196a@gmail.com
*/
static int brcmstb_pm_panic_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
writel_relaxed(BRCMSTB_PANIC_MAGIC, ctrl.aon_sram + AON_REG_PANIC);
return NOTIFY_DONE;
}
static struct notifier_block brcmstb_pm_panic_nb = {
.notifier_call = brcmstb_pm_panic_notify,
};
static int brcmstb_pm_probe(struct platform_device *pdev)
{
const struct ddr_phy_ofdata *ddr_phy_data;
const struct ddr_seq_ofdata *ddr_seq_data;
const struct of_device_id *of_id = NULL;
struct device_node *dn;
void __iomem *base;
int ret, i, s;
/* AON ctrl registers */
base = brcmstb_ioremap_match(aon_ctrl_dt_ids, 0, NULL);
if (IS_ERR(base)) {
pr_err("error mapping AON_CTRL\n");
ret = PTR_ERR(base);
goto aon_err;
}
ctrl.aon_ctrl_base = base;
/* AON SRAM registers */
base = brcmstb_ioremap_match(aon_ctrl_dt_ids, 1, NULL);
if (IS_ERR(base)) {
/* Assume standard offset */
ctrl.aon_sram = ctrl.aon_ctrl_base +
AON_CTRL_SYSTEM_DATA_RAM_OFS;
s = 0;
} else {
ctrl.aon_sram = base;
s = 1;
}
writel_relaxed(0, ctrl.aon_sram + AON_REG_PANIC);
/* DDR PHY registers */
base = brcmstb_ioremap_match(ddr_phy_dt_ids, 0,
(const void **)&ddr_phy_data);
if (IS_ERR(base)) {
pr_err("error mapping DDR PHY\n");
ret = PTR_ERR(base);
goto ddr_phy_err;
}
ctrl.support_warm_boot = ddr_phy_data->supports_warm_boot;
ctrl.pll_status_offset = ddr_phy_data->pll_status_offset;
/* Only need DDR PHY 0 for now? */
ctrl.memcs[0].ddr_phy_base = base;
ctrl.s3entry_method = ddr_phy_data->s3entry_method;
ctrl.phy_a_standby_ctrl_offs = ddr_phy_data->phy_a_standby_ctrl_offs;
ctrl.phy_b_standby_ctrl_offs = ddr_phy_data->phy_b_standby_ctrl_offs;
/*
* Slightly gross to use the phy ver to get a memc,
* offset but that is the only versioned things so far
* we can test for.
*/
ctrl.warm_boot_offset = ddr_phy_data->warm_boot_offset;
/* DDR SHIM-PHY registers */
for_each_matching_node(dn, ddr_shimphy_dt_ids) {
i = ctrl.num_memc;
if (i >= MAX_NUM_MEMC) {
of_node_put(dn);
pr_warn("too many MEMCs (max %d)\n", MAX_NUM_MEMC);
break;
}
base = of_io_request_and_map(dn, 0, dn->full_name);
if (IS_ERR(base)) {
of_node_put(dn);
if (!ctrl.support_warm_boot)
break;
pr_err("error mapping DDR SHIMPHY %d\n", i);
ret = PTR_ERR(base);
goto ddr_shimphy_err;
}
ctrl.memcs[i].ddr_shimphy_base = base;
ctrl.num_memc++;
}
/* Sequencer DRAM Param and Control Registers */
i = 0;
for_each_matching_node(dn, brcmstb_memc_of_match) {
base = of_iomap(dn, 0);
if (!base) {
of_node_put(dn);
pr_err("error mapping DDR Sequencer %d\n", i);
ret = -ENOMEM;
goto brcmstb_memc_err;
}
of_id = of_match_node(brcmstb_memc_of_match, dn);
if (!of_id) {
iounmap(base);
of_node_put(dn);
ret = -EINVAL;
goto brcmstb_memc_err;
}
ddr_seq_data = of_id->data;
ctrl.needs_ddr_pad = ddr_seq_data->needs_ddr_pad;
/* Adjust warm boot offset based on the DDR sequencer */
if (ddr_seq_data->warm_boot_offset)
ctrl.warm_boot_offset = ddr_seq_data->warm_boot_offset;
ctrl.memcs[i].ddr_ctrl = base;
i++;
}
pr_debug("PM: supports warm boot:%d, method:%d, wboffs:%x\n",
ctrl.support_warm_boot, ctrl.s3entry_method,
ctrl.warm_boot_offset);
dn = of_find_matching_node(NULL, sram_dt_ids);
if (!dn) {
pr_err("SRAM not found\n");
ret = -EINVAL;
goto brcmstb_memc_err;
}
ret = brcmstb_init_sram(dn);
of_node_put(dn);
if (ret) {
pr_err("error setting up SRAM for PM\n");
goto brcmstb_memc_err;
}
ctrl.pdev = pdev;
ctrl.s3_params = kmalloc(sizeof(*ctrl.s3_params), GFP_KERNEL);
if (!ctrl.s3_params) {
ret = -ENOMEM;
goto s3_params_err;
}
ctrl.s3_params_pa = dma_map_single(&pdev->dev, ctrl.s3_params,
sizeof(*ctrl.s3_params),
DMA_TO_DEVICE);
if (dma_mapping_error(&pdev->dev, ctrl.s3_params_pa)) {
pr_err("error mapping DMA memory\n");
ret = -ENOMEM;
goto out;
}
atomic_notifier_chain_register(&panic_notifier_list,
&brcmstb_pm_panic_nb);
pm_power_off = brcmstb_pm_poweroff;
suspend_set_ops(&brcmstb_pm_ops);
return 0;
out:
kfree(ctrl.s3_params);
s3_params_err:
iounmap(ctrl.boot_sram);
brcmstb_memc_err:
for (i--; i >= 0; i--)
iounmap(ctrl.memcs[i].ddr_ctrl);
ddr_shimphy_err:
for (i = 0; i < ctrl.num_memc; i++)
iounmap(ctrl.memcs[i].ddr_shimphy_base);
iounmap(ctrl.memcs[0].ddr_phy_base);
ddr_phy_err:
iounmap(ctrl.aon_ctrl_base);
if (s)
iounmap(ctrl.aon_sram);
aon_err:
pr_warn("PM: initialization failed with code %d\n", ret);
return ret;
}
static struct platform_driver brcmstb_pm_driver = {
.driver = {
.name = "brcmstb-pm",
.of_match_table = aon_ctrl_dt_ids,
},
};
static int __init brcmstb_pm_init(void)
{
return platform_driver_probe(&brcmstb_pm_driver,
brcmstb_pm_probe);
}
module_init(brcmstb_pm_init);

View File

@ -1,69 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright © 2014-2017 Broadcom
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
#include "pm.h"
.arch armv7-a
.text
.align 3
#define AON_CTRL_REG r10
#define DDR_PHY_STATUS_REG r11
/*
* r0: AON_CTRL base address
* r1: DDRY PHY PLL status register address
*/
ENTRY(brcmstb_pm_do_s2)
stmfd sp!, {r4-r11, lr}
mov AON_CTRL_REG, r0
mov DDR_PHY_STATUS_REG, r1
/* Flush memory transactions */
dsb
/* Cache DDR_PHY_STATUS_REG translation */
ldr r0, [DDR_PHY_STATUS_REG]
/* power down request */
ldr r0, =PM_S2_COMMAND
ldr r1, =0
str r1, [AON_CTRL_REG, #AON_CTRL_PM_CTRL]
ldr r1, [AON_CTRL_REG, #AON_CTRL_PM_CTRL]
str r0, [AON_CTRL_REG, #AON_CTRL_PM_CTRL]
ldr r0, [AON_CTRL_REG, #AON_CTRL_PM_CTRL]
/* Wait for interrupt */
wfi
nop
/* Bring MEMC back up */
1: ldr r0, [DDR_PHY_STATUS_REG]
ands r0, #1
beq 1b
/* Power-up handshake */
ldr r0, =1
str r0, [AON_CTRL_REG, #AON_CTRL_HOST_MISC_CMDS]
ldr r0, [AON_CTRL_REG, #AON_CTRL_HOST_MISC_CMDS]
ldr r0, =0
str r0, [AON_CTRL_REG, #AON_CTRL_PM_CTRL]
ldr r0, [AON_CTRL_REG, #AON_CTRL_PM_CTRL]
/* Return to caller */
ldr r0, =0
ldmfd sp!, {r4-r11, pc}
ENDPROC(brcmstb_pm_do_s2)
/* Place literal pool here */
.ltorg
ENTRY(brcmstb_pm_do_s2_sz)
.word . - brcmstb_pm_do_s2

View File

@ -243,4 +243,3 @@ builtin_platform_driver(rpi_power_driver);
MODULE_AUTHOR("Alexander Aring <aar@pengutronix.de>");
MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
MODULE_DESCRIPTION("Raspberry Pi power domain driver");
MODULE_LICENSE("GPL v2");

View File

@ -3,8 +3,9 @@
config SOC_K210_SYSCTL
bool "Canaan Kendryte K210 SoC system controller"
depends on RISCV && SOC_CANAAN && OF
depends on COMMON_CLK_K210
default SOC_CANAAN
select PM
select MFD_SYSCON
select PM
select MFD_SYSCON
help
Canaan Kendryte K210 SoC system controller driver.

View File

@ -10,7 +10,7 @@ config IMX_GPCV2_PM_DOMAINS
default y if SOC_IMX7D
config SOC_IMX8M
bool "i.MX8M SoC family support"
tristate "i.MX8M SoC family support"
depends on ARCH_MXC || COMPILE_TEST
default ARCH_MXC && ARM64
select SOC_BUS

View File

@ -38,10 +38,10 @@ struct imx8m_blk_ctrl {
struct imx8m_blk_ctrl_domain_data {
const char *name;
const char * const *clk_names;
int num_clks;
const char * const *path_names;
int num_paths;
const char *gpc_name;
int num_clks;
int num_paths;
u32 rst_mask;
u32 clk_mask;
@ -210,7 +210,7 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
if (!bc->onecell_data.domains)
return -ENOMEM;
bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
bc->bus_power_dev = dev_pm_domain_attach_by_name(dev, "bus");
if (IS_ERR(bc->bus_power_dev)) {
if (PTR_ERR(bc->bus_power_dev) == -ENODEV)
return dev_err_probe(dev, -EPROBE_DEFER,
@ -310,6 +310,10 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
dev_set_drvdata(dev, bc);
ret = devm_of_platform_populate(dev);
if (ret)
goto cleanup_provider;
return 0;
cleanup_provider:
@ -891,3 +895,4 @@ static struct platform_driver imx8m_blk_ctrl_driver = {
},
};
module_platform_driver(imx8m_blk_ctrl_driver);
MODULE_LICENSE("GPL");

View File

@ -642,7 +642,7 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
if (!bc->onecell_data.domains)
return -ENOMEM;
bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
bc->bus_power_dev = dev_pm_domain_attach_by_name(dev, "bus");
if (IS_ERR(bc->bus_power_dev))
return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
"failed to attach bus power domain\n");
@ -852,7 +852,7 @@ static const struct of_device_id imx8mp_blk_ctrl_of_match[] = {
/* Sentinel */
}
};
MODULE_DEVICE_TABLE(of, imx8m_blk_ctrl_of_match);
MODULE_DEVICE_TABLE(of, imx8mp_blk_ctrl_of_match);
static struct platform_driver imx8mp_blk_ctrl_driver = {
.probe = imx8mp_blk_ctrl_probe,
@ -864,3 +864,4 @@ static struct platform_driver imx8mp_blk_ctrl_driver = {
},
};
module_platform_driver(imx8mp_blk_ctrl_driver);
MODULE_LICENSE("GPL");

View File

@ -242,3 +242,4 @@ free_soc:
return ret;
}
device_initcall(imx8_soc_init);
MODULE_LICENSE("GPL");

View File

@ -76,6 +76,7 @@ config MTK_MMSYS
tristate "MediaTek MMSYS Support"
default ARCH_MEDIATEK
depends on HAS_IOMEM
depends on MTK_CMDQ || MTK_CMDQ=n
help
Say yes here to add support for the MediaTek Multimedia
Subsystem (MMSYS).

View File

@ -0,0 +1,95 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __SOC_MEDIATEK_MT8173_MMSYS_H
#define __SOC_MEDIATEK_MT8173_MMSYS_H
#define MT8173_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x040
#define MT8173_DISP_REG_CONFIG_DISP_OVL1_MOUT_EN 0x044
#define MT8173_DISP_REG_CONFIG_DISP_OD_MOUT_EN 0x048
#define MT8173_DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN 0x04c
#define MT8173_DISP_REG_CONFIG_DISP_UFOE_MOUT_EN 0x050
#define MT8173_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084
#define MT8173_DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088
#define MT8173_DISP_REG_CONFIG_DISP_AAL_SEL_IN 0x08c
#define MT8173_DISP_REG_CONFIG_DISP_UFOE_SEL_IN 0x0a0
#define MT8173_DISP_REG_CONFIG_DSI0_SEL_IN 0x0a4
#define MT8173_DISP_REG_CONFIG_DPI_SEL_IN 0x0ac
#define MT8173_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN 0x0b0
#define MT8173_DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN 0x0c8
#define MT8173_DISP_REG_CONFIG_DISP_COLOR0_SOUT_SEL_IN 0x0bc
#define MT8173_AAL_SEL_IN_MERGE BIT(0)
#define MT8173_COLOR0_SEL_IN_OVL0 BIT(0)
#define MT8173_COLOR0_SOUT_MERGE BIT(0)
#define MT8173_DPI0_SEL_IN_MASK GENMASK(1, 0)
#define MT8173_DPI0_SEL_IN_RDMA1 BIT(0)
#define MT8173_DSI0_SEL_IN_UFOE BIT(0)
#define MT8173_GAMMA_MOUT_EN_RDMA1 BIT(0)
#define MT8173_OD0_MOUT_EN_RDMA0 BIT(0)
#define MT8173_OVL0_MOUT_EN_COLOR0 BIT(0)
#define MT8173_OVL1_MOUT_EN_COLOR1 BIT(0)
#define MT8173_UFOE_MOUT_EN_DSI0 BIT(0)
#define MT8173_UFOE_SEL_IN_RDMA0 BIT(0)
#define MT8173_RDMA0_SOUT_COLOR0 BIT(0)
static const struct mtk_mmsys_routes mt8173_mmsys_routing_table[] = {
{
DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0,
MT8173_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN,
MT8173_OVL0_MOUT_EN_COLOR0, MT8173_OVL0_MOUT_EN_COLOR0
}, {
DDP_COMPONENT_OD0, DDP_COMPONENT_RDMA0,
MT8173_DISP_REG_CONFIG_DISP_OD_MOUT_EN,
MT8173_OD0_MOUT_EN_RDMA0, MT8173_OD0_MOUT_EN_RDMA0
}, {
DDP_COMPONENT_UFOE, DDP_COMPONENT_DSI0,
MT8173_DISP_REG_CONFIG_DISP_UFOE_MOUT_EN,
MT8173_UFOE_MOUT_EN_DSI0, MT8173_UFOE_MOUT_EN_DSI0
}, {
DDP_COMPONENT_COLOR0, DDP_COMPONENT_AAL0,
MT8173_DISP_REG_CONFIG_DISP_COLOR0_SOUT_SEL_IN,
MT8173_COLOR0_SOUT_MERGE, 0 /* SOUT to AAL */
}, {
DDP_COMPONENT_RDMA0, DDP_COMPONENT_UFOE,
MT8173_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN,
MT8173_RDMA0_SOUT_COLOR0, 0 /* SOUT to UFOE */
}, {
DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0,
MT8173_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN,
MT8173_COLOR0_SEL_IN_OVL0, MT8173_COLOR0_SEL_IN_OVL0
}, {
DDP_COMPONENT_AAL0, DDP_COMPONENT_COLOR0,
MT8173_DISP_REG_CONFIG_DISP_AAL_SEL_IN,
MT8173_AAL_SEL_IN_MERGE, 0 /* SEL_IN from COLOR0 */
}, {
DDP_COMPONENT_RDMA0, DDP_COMPONENT_UFOE,
MT8173_DISP_REG_CONFIG_DISP_UFOE_SEL_IN,
MT8173_UFOE_SEL_IN_RDMA0, 0 /* SEL_IN from RDMA0 */
}, {
DDP_COMPONENT_UFOE, DDP_COMPONENT_DSI0,
MT8173_DISP_REG_CONFIG_DSI0_SEL_IN,
MT8173_DSI0_SEL_IN_UFOE, 0, /* SEL_IN from UFOE */
}, {
DDP_COMPONENT_OVL1, DDP_COMPONENT_COLOR1,
MT8173_DISP_REG_CONFIG_DISP_OVL1_MOUT_EN,
MT8173_OVL1_MOUT_EN_COLOR1, MT8173_OVL1_MOUT_EN_COLOR1
}, {
DDP_COMPONENT_GAMMA, DDP_COMPONENT_RDMA1,
MT8173_DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN,
MT8173_GAMMA_MOUT_EN_RDMA1, MT8173_GAMMA_MOUT_EN_RDMA1
}, {
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
MT8173_DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN,
RDMA1_SOUT_MASK, RDMA1_SOUT_DPI0
}, {
DDP_COMPONENT_OVL1, DDP_COMPONENT_COLOR1,
MT8173_DISP_REG_CONFIG_DISP_COLOR1_SEL_IN,
COLOR1_SEL_IN_OVL1, COLOR1_SEL_IN_OVL1
}, {
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
MT8173_DISP_REG_CONFIG_DPI_SEL_IN,
MT8173_DPI0_SEL_IN_MASK, MT8173_DPI0_SEL_IN_RDMA1
}
};
#endif /* __SOC_MEDIATEK_MT8173_MMSYS_H */

View File

@ -146,6 +146,19 @@
#define MT8195_VDO1_MIXER_SOUT_SEL_IN 0xf68
#define MT8195_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER 0
/* VPPSYS1 */
#define MT8195_VPP1_HW_DCM_1ST_DIS0 0x150
#define MT8195_VPP1_HW_DCM_1ST_DIS1 0x160
#define MT8195_VPP1_HW_DCM_2ND_DIS0 0x1a0
#define MT8195_VPP1_HW_DCM_2ND_DIS1 0x1b0
#define MT8195_SVPP2_BUF_BF_RSZ_SWITCH 0xf48
#define MT8195_SVPP3_BUF_BF_RSZ_SWITCH 0xf74
/* VPPSYS1 HW DCM client*/
#define MT8195_SVPP1_MDP_RSZ BIT(25)
#define MT8195_SVPP2_MDP_RSZ BIT(4)
#define MT8195_SVPP3_MDP_RSZ BIT(5)
static const struct mtk_mmsys_routes mmsys_mt8195_routing_table[] = {
{
DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,

View File

@ -15,6 +15,7 @@
#include "mtk-mmsys.h"
#include "mt8167-mmsys.h"
#include "mt8173-mmsys.h"
#include "mt8183-mmsys.h"
#include "mt8186-mmsys.h"
#include "mt8188-mmsys.h"
@ -40,6 +41,14 @@ static const struct mtk_mmsys_driver_data mt6779_mmsys_driver_data = {
.clk_driver = "clk-mt6779-mm",
};
static const struct mtk_mmsys_driver_data mt6795_mmsys_driver_data = {
.clk_driver = "clk-mt6795-mm",
.routes = mt8173_mmsys_routing_table,
.num_routes = ARRAY_SIZE(mt8173_mmsys_routing_table),
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
.num_resets = 64,
};
static const struct mtk_mmsys_driver_data mt6797_mmsys_driver_data = {
.clk_driver = "clk-mt6797-mm",
};
@ -52,10 +61,10 @@ static const struct mtk_mmsys_driver_data mt8167_mmsys_driver_data = {
static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
.clk_driver = "clk-mt8173-mm",
.routes = mmsys_default_routing_table,
.num_routes = ARRAY_SIZE(mmsys_default_routing_table),
.routes = mt8173_mmsys_routing_table,
.num_routes = ARRAY_SIZE(mt8173_mmsys_routing_table),
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
.num_resets = 32,
.num_resets = 64,
};
static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
@ -121,6 +130,8 @@ static const struct mtk_mmsys_driver_data mt8365_mmsys_driver_data = {
struct mtk_mmsys {
void __iomem *regs;
const struct mtk_mmsys_driver_data *data;
struct platform_device *clks_pdev;
struct platform_device *drm_pdev;
spinlock_t lock; /* protects mmsys_sw_rst_b reg */
struct reset_controller_dev rcdev;
struct cmdq_client_reg cmdq_base;
@ -129,21 +140,18 @@ struct mtk_mmsys {
static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val,
struct cmdq_pkt *cmdq_pkt)
{
int ret;
u32 tmp;
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
if (cmdq_pkt) {
if (mmsys->cmdq_base.size == 0) {
pr_err("mmsys lose gce property, failed to update mmsys bits with cmdq");
if (mmsys->cmdq_base.size && cmdq_pkt) {
ret = cmdq_pkt_write_mask(cmdq_pkt, mmsys->cmdq_base.subsys,
mmsys->cmdq_base.offset + offset, val,
mask);
if (ret)
pr_debug("CMDQ unavailable: using CPU write\n");
else
return;
}
cmdq_pkt_write_mask(cmdq_pkt, mmsys->cmdq_base.subsys,
mmsys->cmdq_base.offset + offset, val,
mask);
return;
}
#endif
tmp = readl_relaxed(mmsys->regs + offset);
tmp = (tmp & ~mask) | (val & mask);
writel_relaxed(tmp, mmsys->regs + offset);
@ -242,6 +250,50 @@ void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val)
}
EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_dpi_fmt_config);
void mtk_mmsys_vpp_rsz_merge_config(struct device *dev, u32 id, bool enable,
struct cmdq_pkt *cmdq_pkt)
{
u32 reg;
switch (id) {
case 2:
reg = MT8195_SVPP2_BUF_BF_RSZ_SWITCH;
break;
case 3:
reg = MT8195_SVPP3_BUF_BF_RSZ_SWITCH;
break;
default:
dev_err(dev, "Invalid id %d\n", id);
return;
}
mtk_mmsys_update_bits(dev_get_drvdata(dev), reg, ~0, enable, cmdq_pkt);
}
EXPORT_SYMBOL_GPL(mtk_mmsys_vpp_rsz_merge_config);
void mtk_mmsys_vpp_rsz_dcm_config(struct device *dev, bool enable,
struct cmdq_pkt *cmdq_pkt)
{
u32 client;
client = MT8195_SVPP1_MDP_RSZ;
mtk_mmsys_update_bits(dev_get_drvdata(dev),
MT8195_VPP1_HW_DCM_1ST_DIS0, client,
((enable) ? client : 0), cmdq_pkt);
mtk_mmsys_update_bits(dev_get_drvdata(dev),
MT8195_VPP1_HW_DCM_2ND_DIS0, client,
((enable) ? client : 0), cmdq_pkt);
client = MT8195_SVPP2_MDP_RSZ | MT8195_SVPP3_MDP_RSZ;
mtk_mmsys_update_bits(dev_get_drvdata(dev),
MT8195_VPP1_HW_DCM_1ST_DIS1, client,
((enable) ? client : 0), cmdq_pkt);
mtk_mmsys_update_bits(dev_get_drvdata(dev),
MT8195_VPP1_HW_DCM_2ND_DIS1, client,
((enable) ? client : 0), cmdq_pkt);
}
EXPORT_SYMBOL_GPL(mtk_mmsys_vpp_rsz_dcm_config);
static int mtk_mmsys_reset_update(struct reset_controller_dev *rcdev, unsigned long id,
bool assert)
{
@ -330,11 +382,10 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
}
}
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
/* CMDQ is optional */
ret = cmdq_dev_get_client_reg(dev, &mmsys->cmdq_base, 0);
if (ret)
dev_dbg(dev, "No mediatek,gce-client-reg!\n");
#endif
platform_set_drvdata(pdev, mmsys);
@ -342,6 +393,7 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
PLATFORM_DEVID_AUTO, NULL, 0);
if (IS_ERR(clks))
return PTR_ERR(clks);
mmsys->clks_pdev = clks;
if (mmsys->data->is_vppsys)
goto out_probe_done;
@ -352,78 +404,44 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
platform_device_unregister(clks);
return PTR_ERR(drm);
}
mmsys->drm_pdev = drm;
out_probe_done:
return 0;
}
static int mtk_mmsys_remove(struct platform_device *pdev)
{
struct mtk_mmsys *mmsys = platform_get_drvdata(pdev);
platform_device_unregister(mmsys->drm_pdev);
platform_device_unregister(mmsys->clks_pdev);
return 0;
}
static const struct of_device_id of_match_mtk_mmsys[] = {
{
.compatible = "mediatek,mt2701-mmsys",
.data = &mt2701_mmsys_driver_data,
},
{
.compatible = "mediatek,mt2712-mmsys",
.data = &mt2712_mmsys_driver_data,
},
{
.compatible = "mediatek,mt6779-mmsys",
.data = &mt6779_mmsys_driver_data,
},
{
.compatible = "mediatek,mt6797-mmsys",
.data = &mt6797_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8167-mmsys",
.data = &mt8167_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8173-mmsys",
.data = &mt8173_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8183-mmsys",
.data = &mt8183_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8186-mmsys",
.data = &mt8186_mmsys_driver_data,
},
{
.compatible = "mediatek,mt8188-vdosys0",
.data = &mt8188_vdosys0_driver_data,
},
{
.compatible = "mediatek,mt8192-mmsys",
.data = &mt8192_mmsys_driver_data,
},
{ /* deprecated compatible */
.compatible = "mediatek,mt8195-mmsys",
.data = &mt8195_vdosys0_driver_data,
},
{
.compatible = "mediatek,mt8195-vdosys0",
.data = &mt8195_vdosys0_driver_data,
},
{
.compatible = "mediatek,mt8195-vdosys1",
.data = &mt8195_vdosys1_driver_data,
},
{
.compatible = "mediatek,mt8195-vppsys0",
.data = &mt8195_vppsys0_driver_data,
},
{
.compatible = "mediatek,mt8195-vppsys1",
.data = &mt8195_vppsys1_driver_data,
},
{
.compatible = "mediatek,mt8365-mmsys",
.data = &mt8365_mmsys_driver_data,
},
{ }
{ .compatible = "mediatek,mt2701-mmsys", .data = &mt2701_mmsys_driver_data },
{ .compatible = "mediatek,mt2712-mmsys", .data = &mt2712_mmsys_driver_data },
{ .compatible = "mediatek,mt6779-mmsys", .data = &mt6779_mmsys_driver_data },
{ .compatible = "mediatek,mt6795-mmsys", .data = &mt6795_mmsys_driver_data },
{ .compatible = "mediatek,mt6797-mmsys", .data = &mt6797_mmsys_driver_data },
{ .compatible = "mediatek,mt8167-mmsys", .data = &mt8167_mmsys_driver_data },
{ .compatible = "mediatek,mt8173-mmsys", .data = &mt8173_mmsys_driver_data },
{ .compatible = "mediatek,mt8183-mmsys", .data = &mt8183_mmsys_driver_data },
{ .compatible = "mediatek,mt8186-mmsys", .data = &mt8186_mmsys_driver_data },
{ .compatible = "mediatek,mt8188-vdosys0", .data = &mt8188_vdosys0_driver_data },
{ .compatible = "mediatek,mt8192-mmsys", .data = &mt8192_mmsys_driver_data },
/* "mediatek,mt8195-mmsys" compatible is deprecated */
{ .compatible = "mediatek,mt8195-mmsys", .data = &mt8195_vdosys0_driver_data },
{ .compatible = "mediatek,mt8195-vdosys0", .data = &mt8195_vdosys0_driver_data },
{ .compatible = "mediatek,mt8195-vdosys1", .data = &mt8195_vdosys1_driver_data },
{ .compatible = "mediatek,mt8195-vppsys0", .data = &mt8195_vppsys0_driver_data },
{ .compatible = "mediatek,mt8195-vppsys1", .data = &mt8195_vppsys1_driver_data },
{ .compatible = "mediatek,mt8365-mmsys", .data = &mt8365_mmsys_driver_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_mtk_mmsys);
static struct platform_driver mtk_mmsys_drv = {
.driver = {
@ -431,20 +449,9 @@ static struct platform_driver mtk_mmsys_drv = {
.of_match_table = of_match_mtk_mmsys,
},
.probe = mtk_mmsys_probe,
.remove = mtk_mmsys_remove,
};
static int __init mtk_mmsys_init(void)
{
return platform_driver_register(&mtk_mmsys_drv);
}
static void __exit mtk_mmsys_exit(void)
{
platform_driver_unregister(&mtk_mmsys_drv);
}
module_init(mtk_mmsys_init);
module_exit(mtk_mmsys_exit);
module_platform_driver(mtk_mmsys_drv);
MODULE_AUTHOR("Yongqiang Niu <yongqiang.niu@mediatek.com>");
MODULE_DESCRIPTION("MediaTek SoC MMSYS driver");

View File

@ -96,7 +96,7 @@ struct mtk_mmsys_driver_data {
};
/*
* Routes in mt8173, mt2701, mt2712 are different. That means
* Routes in mt2701 and mt2712 are different. That means
* in the same register address, it controls different input/output
* selection for each SoC. But, right now, they use the same table as
* default routes meet their requirements. But we don't have the complete

View File

@ -14,6 +14,8 @@
#include <linux/soc/mediatek/mtk-mutex.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
#define MTK_MUTEX_MAX_HANDLES 10
#define MT2701_MUTEX0_MOD0 0x2c
#define MT2701_MUTEX0_SOF0 0x30
#define MT8183_MUTEX0_MOD0 0x30
@ -23,6 +25,7 @@
#define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n))
#define DISP_REG_MUTEX_RST(n) (0x28 + 0x20 * (n))
#define DISP_REG_MUTEX_MOD(mutex_mod_reg, n) (mutex_mod_reg + 0x20 * (n))
#define DISP_REG_MUTEX_MOD1(mutex_mod_reg, n) ((mutex_mod_reg) + 0x20 * (n) + 0x4)
#define DISP_REG_MUTEX_SOF(mutex_sof_reg, n) (mutex_sof_reg + 0x20 * (n))
#define DISP_REG_MUTEX_MOD2(n) (0x34 + 0x20 * (n))
@ -163,6 +166,53 @@
#define MT8195_MUTEX_MOD_DISP1_DPI1 26
#define MT8195_MUTEX_MOD_DISP1_DP_INTF0 27
/* VPPSYS0 */
#define MT8195_MUTEX_MOD_MDP_RDMA0 0
#define MT8195_MUTEX_MOD_MDP_FG0 1
#define MT8195_MUTEX_MOD_MDP_STITCH0 2
#define MT8195_MUTEX_MOD_MDP_HDR0 3
#define MT8195_MUTEX_MOD_MDP_AAL0 4
#define MT8195_MUTEX_MOD_MDP_RSZ0 5
#define MT8195_MUTEX_MOD_MDP_TDSHP0 6
#define MT8195_MUTEX_MOD_MDP_COLOR0 7
#define MT8195_MUTEX_MOD_MDP_OVL0 8
#define MT8195_MUTEX_MOD_MDP_PAD0 9
#define MT8195_MUTEX_MOD_MDP_TCC0 10
#define MT8195_MUTEX_MOD_MDP_WROT0 11
/* VPPSYS1 */
#define MT8195_MUTEX_MOD_MDP_TCC1 3
#define MT8195_MUTEX_MOD_MDP_RDMA1 4
#define MT8195_MUTEX_MOD_MDP_RDMA2 5
#define MT8195_MUTEX_MOD_MDP_RDMA3 6
#define MT8195_MUTEX_MOD_MDP_FG1 7
#define MT8195_MUTEX_MOD_MDP_FG2 8
#define MT8195_MUTEX_MOD_MDP_FG3 9
#define MT8195_MUTEX_MOD_MDP_HDR1 10
#define MT8195_MUTEX_MOD_MDP_HDR2 11
#define MT8195_MUTEX_MOD_MDP_HDR3 12
#define MT8195_MUTEX_MOD_MDP_AAL1 13
#define MT8195_MUTEX_MOD_MDP_AAL2 14
#define MT8195_MUTEX_MOD_MDP_AAL3 15
#define MT8195_MUTEX_MOD_MDP_RSZ1 16
#define MT8195_MUTEX_MOD_MDP_RSZ2 17
#define MT8195_MUTEX_MOD_MDP_RSZ3 18
#define MT8195_MUTEX_MOD_MDP_TDSHP1 19
#define MT8195_MUTEX_MOD_MDP_TDSHP2 20
#define MT8195_MUTEX_MOD_MDP_TDSHP3 21
#define MT8195_MUTEX_MOD_MDP_MERGE2 22
#define MT8195_MUTEX_MOD_MDP_MERGE3 23
#define MT8195_MUTEX_MOD_MDP_COLOR1 24
#define MT8195_MUTEX_MOD_MDP_COLOR2 25
#define MT8195_MUTEX_MOD_MDP_COLOR3 26
#define MT8195_MUTEX_MOD_MDP_OVL1 27
#define MT8195_MUTEX_MOD_MDP_PAD1 28
#define MT8195_MUTEX_MOD_MDP_PAD2 29
#define MT8195_MUTEX_MOD_MDP_PAD3 30
#define MT8195_MUTEX_MOD_MDP_WROT1 31
#define MT8195_MUTEX_MOD_MDP_WROT2 32
#define MT8195_MUTEX_MOD_MDP_WROT3 33
#define MT8365_MUTEX_MOD_DISP_OVL0 7
#define MT8365_MUTEX_MOD_DISP_OVL0_2L 8
#define MT8365_MUTEX_MOD_DISP_RDMA0 9
@ -234,7 +284,7 @@
#define MT8195_MUTEX_EOF_DPI1 (MT8195_MUTEX_SOF_DPI1 << 7)
struct mtk_mutex {
int id;
u8 id;
bool claimed;
};
@ -264,7 +314,7 @@ struct mtk_mutex_ctx {
struct device *dev;
struct clk *clk;
void __iomem *regs;
struct mtk_mutex mutex[10];
struct mtk_mutex mutex[MTK_MUTEX_MAX_HANDLES];
const struct mtk_mutex_data *data;
phys_addr_t addr;
struct cmdq_client_reg cmdq_reg;
@ -443,6 +493,52 @@ static const unsigned int mt8195_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_DP_INTF1] = MT8195_MUTEX_MOD_DISP1_DP_INTF0,
};
static const unsigned int mt8195_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
[MUTEX_MOD_IDX_MDP_RDMA0] = MT8195_MUTEX_MOD_MDP_RDMA0,
[MUTEX_MOD_IDX_MDP_RDMA1] = MT8195_MUTEX_MOD_MDP_RDMA1,
[MUTEX_MOD_IDX_MDP_RDMA2] = MT8195_MUTEX_MOD_MDP_RDMA2,
[MUTEX_MOD_IDX_MDP_RDMA3] = MT8195_MUTEX_MOD_MDP_RDMA3,
[MUTEX_MOD_IDX_MDP_STITCH0] = MT8195_MUTEX_MOD_MDP_STITCH0,
[MUTEX_MOD_IDX_MDP_FG0] = MT8195_MUTEX_MOD_MDP_FG0,
[MUTEX_MOD_IDX_MDP_FG1] = MT8195_MUTEX_MOD_MDP_FG1,
[MUTEX_MOD_IDX_MDP_FG2] = MT8195_MUTEX_MOD_MDP_FG2,
[MUTEX_MOD_IDX_MDP_FG3] = MT8195_MUTEX_MOD_MDP_FG3,
[MUTEX_MOD_IDX_MDP_HDR0] = MT8195_MUTEX_MOD_MDP_HDR0,
[MUTEX_MOD_IDX_MDP_HDR1] = MT8195_MUTEX_MOD_MDP_HDR1,
[MUTEX_MOD_IDX_MDP_HDR2] = MT8195_MUTEX_MOD_MDP_HDR2,
[MUTEX_MOD_IDX_MDP_HDR3] = MT8195_MUTEX_MOD_MDP_HDR3,
[MUTEX_MOD_IDX_MDP_AAL0] = MT8195_MUTEX_MOD_MDP_AAL0,
[MUTEX_MOD_IDX_MDP_AAL1] = MT8195_MUTEX_MOD_MDP_AAL1,
[MUTEX_MOD_IDX_MDP_AAL2] = MT8195_MUTEX_MOD_MDP_AAL2,
[MUTEX_MOD_IDX_MDP_AAL3] = MT8195_MUTEX_MOD_MDP_AAL3,
[MUTEX_MOD_IDX_MDP_RSZ0] = MT8195_MUTEX_MOD_MDP_RSZ0,
[MUTEX_MOD_IDX_MDP_RSZ1] = MT8195_MUTEX_MOD_MDP_RSZ1,
[MUTEX_MOD_IDX_MDP_RSZ2] = MT8195_MUTEX_MOD_MDP_RSZ2,
[MUTEX_MOD_IDX_MDP_RSZ3] = MT8195_MUTEX_MOD_MDP_RSZ3,
[MUTEX_MOD_IDX_MDP_MERGE2] = MT8195_MUTEX_MOD_MDP_MERGE2,
[MUTEX_MOD_IDX_MDP_MERGE3] = MT8195_MUTEX_MOD_MDP_MERGE3,
[MUTEX_MOD_IDX_MDP_TDSHP0] = MT8195_MUTEX_MOD_MDP_TDSHP0,
[MUTEX_MOD_IDX_MDP_TDSHP1] = MT8195_MUTEX_MOD_MDP_TDSHP1,
[MUTEX_MOD_IDX_MDP_TDSHP2] = MT8195_MUTEX_MOD_MDP_TDSHP2,
[MUTEX_MOD_IDX_MDP_TDSHP3] = MT8195_MUTEX_MOD_MDP_TDSHP3,
[MUTEX_MOD_IDX_MDP_COLOR0] = MT8195_MUTEX_MOD_MDP_COLOR0,
[MUTEX_MOD_IDX_MDP_COLOR1] = MT8195_MUTEX_MOD_MDP_COLOR1,
[MUTEX_MOD_IDX_MDP_COLOR2] = MT8195_MUTEX_MOD_MDP_COLOR2,
[MUTEX_MOD_IDX_MDP_COLOR3] = MT8195_MUTEX_MOD_MDP_COLOR3,
[MUTEX_MOD_IDX_MDP_OVL0] = MT8195_MUTEX_MOD_MDP_OVL0,
[MUTEX_MOD_IDX_MDP_OVL1] = MT8195_MUTEX_MOD_MDP_OVL1,
[MUTEX_MOD_IDX_MDP_PAD0] = MT8195_MUTEX_MOD_MDP_PAD0,
[MUTEX_MOD_IDX_MDP_PAD1] = MT8195_MUTEX_MOD_MDP_PAD1,
[MUTEX_MOD_IDX_MDP_PAD2] = MT8195_MUTEX_MOD_MDP_PAD2,
[MUTEX_MOD_IDX_MDP_PAD3] = MT8195_MUTEX_MOD_MDP_PAD3,
[MUTEX_MOD_IDX_MDP_TCC0] = MT8195_MUTEX_MOD_MDP_TCC0,
[MUTEX_MOD_IDX_MDP_TCC1] = MT8195_MUTEX_MOD_MDP_TCC1,
[MUTEX_MOD_IDX_MDP_WROT0] = MT8195_MUTEX_MOD_MDP_WROT0,
[MUTEX_MOD_IDX_MDP_WROT1] = MT8195_MUTEX_MOD_MDP_WROT1,
[MUTEX_MOD_IDX_MDP_WROT2] = MT8195_MUTEX_MOD_MDP_WROT2,
[MUTEX_MOD_IDX_MDP_WROT3] = MT8195_MUTEX_MOD_MDP_WROT3,
};
static const unsigned int mt8365_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_AAL0] = MT8365_MUTEX_MOD_DISP_AAL,
[DDP_COMPONENT_CCORR] = MT8365_MUTEX_MOD_DISP_CCORR,
@ -603,6 +699,13 @@ static const struct mtk_mutex_data mt8195_mutex_driver_data = {
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
};
static const struct mtk_mutex_data mt8195_vpp_mutex_driver_data = {
.mutex_sof = mt8195_mutex_sof,
.mutex_mod_reg = MT8183_MUTEX0_MOD0,
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
.mutex_table_mod = mt8195_mutex_table_mod,
};
static const struct mtk_mutex_data mt8365_mutex_driver_data = {
.mutex_mod = mt8365_mutex_mod,
.mutex_sof = mt8183_mutex_sof,
@ -616,7 +719,7 @@ struct mtk_mutex *mtk_mutex_get(struct device *dev)
struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev);
int i;
for (i = 0; i < 10; i++)
for (i = 0; i < MTK_MUTEX_MAX_HANDLES; i++)
if (!mtx->mutex[i].claimed) {
mtx->mutex[i].claimed = true;
return &mtx->mutex[i];
@ -768,23 +871,18 @@ int mtk_mutex_enable_by_cmdq(struct mtk_mutex *mutex, void *pkt)
{
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]);
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
struct cmdq_pkt *cmdq_pkt = (struct cmdq_pkt *)pkt;
WARN_ON(&mtx->mutex[mutex->id] != mutex);
if (!mtx->cmdq_reg.size) {
dev_err(mtx->dev, "mediatek,gce-client-reg hasn't been set");
return -EINVAL;
return -ENODEV;
}
cmdq_pkt_write(cmdq_pkt, mtx->cmdq_reg.subsys,
mtx->addr + DISP_REG_MUTEX_EN(mutex->id), 1);
return 0;
#else
dev_err(mtx->dev, "Not support for enable MUTEX by CMDQ");
return -ENODEV;
#endif
}
EXPORT_SYMBOL_GPL(mtk_mutex_enable_by_cmdq);
@ -828,7 +926,7 @@ int mtk_mutex_write_mod(struct mtk_mutex *mutex,
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]);
unsigned int reg;
unsigned int offset;
u32 reg_offset, id_offset = 0;
WARN_ON(&mtx->mutex[mutex->id] != mutex);
@ -838,16 +936,34 @@ int mtk_mutex_write_mod(struct mtk_mutex *mutex,
return -EINVAL;
}
offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
mutex->id);
reg = readl_relaxed(mtx->regs + offset);
/*
* Some SoCs may have multiple MUTEX_MOD registers as more than 32 mods
* are present, hence requiring multiple 32-bits registers.
*
* The mutex_table_mod fully represents that by defining the number of
* the mod sequentially, later used as a bit number, which can be more
* than 0..31.
*
* In order to retain compatibility with older SoCs, we perform R/W on
* the single 32 bits registers, but this requires us to translate the
* mutex ID bit accordingly.
*/
if (mtx->data->mutex_table_mod[idx] < 32) {
reg_offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
mutex->id);
} else {
reg_offset = DISP_REG_MUTEX_MOD1(mtx->data->mutex_mod_reg,
mutex->id);
id_offset = 32;
}
reg = readl_relaxed(mtx->regs + reg_offset);
if (clear)
reg &= ~BIT(mtx->data->mutex_table_mod[idx]);
reg &= ~BIT(mtx->data->mutex_table_mod[idx] - id_offset);
else
reg |= BIT(mtx->data->mutex_table_mod[idx]);
reg |= BIT(mtx->data->mutex_table_mod[idx] - id_offset);
writel_relaxed(reg, mtx->regs + offset);
writel_relaxed(reg, mtx->regs + reg_offset);
return 0;
}
@ -879,27 +995,21 @@ static int mtk_mutex_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct mtk_mutex_ctx *mtx;
struct resource *regs;
int i;
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
int ret;
#endif
int i, ret;
mtx = devm_kzalloc(dev, sizeof(*mtx), GFP_KERNEL);
if (!mtx)
return -ENOMEM;
for (i = 0; i < 10; i++)
for (i = 0; i < MTK_MUTEX_MAX_HANDLES; i++)
mtx->mutex[i].id = i;
mtx->data = of_device_get_match_data(dev);
if (!mtx->data->no_clk) {
mtx->clk = devm_clk_get(dev, NULL);
if (IS_ERR(mtx->clk)) {
if (PTR_ERR(mtx->clk) != -EPROBE_DEFER)
dev_err(dev, "Failed to get clock\n");
return PTR_ERR(mtx->clk);
}
if (IS_ERR(mtx->clk))
return dev_err_probe(dev, PTR_ERR(mtx->clk), "Failed to get clock\n");
}
mtx->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
@ -909,11 +1019,10 @@ static int mtk_mutex_probe(struct platform_device *pdev)
}
mtx->addr = regs->start;
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
/* CMDQ is optional */
ret = cmdq_dev_get_client_reg(dev, &mtx->cmdq_reg, 0);
if (ret)
dev_dbg(dev, "No mediatek,gce-client-reg!\n");
#endif
platform_set_drvdata(pdev, mtx);
@ -921,31 +1030,20 @@ static int mtk_mutex_probe(struct platform_device *pdev)
}
static const struct of_device_id mutex_driver_dt_match[] = {
{ .compatible = "mediatek,mt2701-disp-mutex",
.data = &mt2701_mutex_driver_data},
{ .compatible = "mediatek,mt2712-disp-mutex",
.data = &mt2712_mutex_driver_data},
{ .compatible = "mediatek,mt6795-disp-mutex",
.data = &mt6795_mutex_driver_data},
{ .compatible = "mediatek,mt8167-disp-mutex",
.data = &mt8167_mutex_driver_data},
{ .compatible = "mediatek,mt8173-disp-mutex",
.data = &mt8173_mutex_driver_data},
{ .compatible = "mediatek,mt8183-disp-mutex",
.data = &mt8183_mutex_driver_data},
{ .compatible = "mediatek,mt8186-disp-mutex",
.data = &mt8186_mutex_driver_data},
{ .compatible = "mediatek,mt8186-mdp3-mutex",
.data = &mt8186_mdp_mutex_driver_data},
{ .compatible = "mediatek,mt8188-disp-mutex",
.data = &mt8188_mutex_driver_data},
{ .compatible = "mediatek,mt8192-disp-mutex",
.data = &mt8192_mutex_driver_data},
{ .compatible = "mediatek,mt8195-disp-mutex",
.data = &mt8195_mutex_driver_data},
{ .compatible = "mediatek,mt8365-disp-mutex",
.data = &mt8365_mutex_driver_data},
{},
{ .compatible = "mediatek,mt2701-disp-mutex", .data = &mt2701_mutex_driver_data },
{ .compatible = "mediatek,mt2712-disp-mutex", .data = &mt2712_mutex_driver_data },
{ .compatible = "mediatek,mt6795-disp-mutex", .data = &mt6795_mutex_driver_data },
{ .compatible = "mediatek,mt8167-disp-mutex", .data = &mt8167_mutex_driver_data },
{ .compatible = "mediatek,mt8173-disp-mutex", .data = &mt8173_mutex_driver_data },
{ .compatible = "mediatek,mt8183-disp-mutex", .data = &mt8183_mutex_driver_data },
{ .compatible = "mediatek,mt8186-disp-mutex", .data = &mt8186_mutex_driver_data },
{ .compatible = "mediatek,mt8186-mdp3-mutex", .data = &mt8186_mdp_mutex_driver_data },
{ .compatible = "mediatek,mt8188-disp-mutex", .data = &mt8188_mutex_driver_data },
{ .compatible = "mediatek,mt8192-disp-mutex", .data = &mt8192_mutex_driver_data },
{ .compatible = "mediatek,mt8195-disp-mutex", .data = &mt8195_mutex_driver_data },
{ .compatible = "mediatek,mt8195-vpp-mutex", .data = &mt8195_vpp_mutex_driver_data },
{ .compatible = "mediatek,mt8365-disp-mutex", .data = &mt8365_mutex_driver_data },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, mutex_driver_dt_match);
@ -957,19 +1055,7 @@ static struct platform_driver mtk_mutex_driver = {
.of_match_table = mutex_driver_dt_match,
},
};
static int __init mtk_mutex_init(void)
{
return platform_driver_register(&mtk_mutex_driver);
}
static void __exit mtk_mutex_exit(void)
{
platform_driver_unregister(&mtk_mutex_driver);
}
module_init(mtk_mutex_init);
module_exit(mtk_mutex_exit);
module_platform_driver(mtk_mutex_driver);
MODULE_AUTHOR("Yongqiang Niu <yongqiang.niu@mediatek.com>");
MODULE_DESCRIPTION("MediaTek SoC MUTEX driver");

View File

@ -558,7 +558,7 @@ static int svs_adjust_pm_opp_volts(struct svs_bank *svsb)
}
/* Get thermal effect */
if (svsb->phase == SVSB_PHASE_MON) {
if (!IS_ERR_OR_NULL(svsb->tzd)) {
ret = thermal_zone_get_temp(svsb->tzd, &tzone_temp);
if (ret || (svsb->temp > SVSB_TEMP_UPPER_BOUND &&
svsb->temp < SVSB_TEMP_LOWER_BOUND)) {
@ -573,7 +573,8 @@ static int svs_adjust_pm_opp_volts(struct svs_bank *svsb)
temp_voffset += svsb->tzone_ltemp_voffset;
/* 2-line bank update all opp volts when running mon mode */
if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) {
if (svsb->phase == SVSB_PHASE_MON && (svsb->type == SVSB_HIGH ||
svsb->type == SVSB_LOW)) {
opp_start = 0;
opp_stop = svsb->opp_count;
}
@ -589,11 +590,6 @@ static int svs_adjust_pm_opp_volts(struct svs_bank *svsb)
/* do nothing */
goto unlock_mutex;
case SVSB_PHASE_INIT02:
svsb_volt = max(svsb->volt[i], svsb->vmin);
opp_volt = svs_bank_volt_to_opp_volt(svsb_volt,
svsb->volt_step,
svsb->volt_base);
break;
case SVSB_PHASE_MON:
svsb_volt = max(svsb->volt[i] + temp_voffset, svsb->vmin);
opp_volt = svs_bank_volt_to_opp_volt(svsb_volt,
@ -624,6 +620,25 @@ unlock_mutex:
return ret;
}
static void svs_bank_disable_and_restore_default_volts(struct svs_platform *svsp,
struct svs_bank *svsb)
{
unsigned long flags;
if (svsb->mode_support == SVSB_MODE_ALL_DISABLE)
return;
spin_lock_irqsave(&svs_lock, flags);
svsp->pbank = svsb;
svs_switch_bank(svsp);
svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
spin_unlock_irqrestore(&svs_lock, flags);
svsb->phase = SVSB_PHASE_ERROR;
svs_adjust_pm_opp_volts(svsb);
}
#ifdef CONFIG_DEBUG_FS
static int svs_dump_debug_show(struct seq_file *m, void *p)
{
@ -700,7 +715,6 @@ static ssize_t svs_enable_debug_write(struct file *filp,
{
struct svs_bank *svsb = file_inode(filp)->i_private;
struct svs_platform *svsp = dev_get_drvdata(svsb->dev);
unsigned long flags;
int enabled, ret;
char *buf = NULL;
@ -716,16 +730,8 @@ static ssize_t svs_enable_debug_write(struct file *filp,
return ret;
if (!enabled) {
spin_lock_irqsave(&svs_lock, flags);
svsp->pbank = svsb;
svs_bank_disable_and_restore_default_volts(svsp, svsb);
svsb->mode_support = SVSB_MODE_ALL_DISABLE;
svs_switch_bank(svsp);
svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
spin_unlock_irqrestore(&svs_lock, flags);
svsb->phase = SVSB_PHASE_ERROR;
svs_adjust_pm_opp_volts(svsb);
}
kfree(buf);
@ -1508,16 +1514,7 @@ static int svs_init02(struct svs_platform *svsp)
out_of_init02:
for (idx = 0; idx < svsp->bank_max; idx++) {
svsb = &svsp->banks[idx];
spin_lock_irqsave(&svs_lock, flags);
svsp->pbank = svsb;
svs_switch_bank(svsp);
svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
spin_unlock_irqrestore(&svs_lock, flags);
svsb->phase = SVSB_PHASE_ERROR;
svs_adjust_pm_opp_volts(svsb);
svs_bank_disable_and_restore_default_volts(svsp, svsb);
}
return ret;
@ -1563,23 +1560,12 @@ static int svs_suspend(struct device *dev)
{
struct svs_platform *svsp = dev_get_drvdata(dev);
struct svs_bank *svsb;
unsigned long flags;
int ret;
u32 idx;
for (idx = 0; idx < svsp->bank_max; idx++) {
svsb = &svsp->banks[idx];
/* This might wait for svs_isr() process */
spin_lock_irqsave(&svs_lock, flags);
svsp->pbank = svsb;
svs_switch_bank(svsp);
svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
spin_unlock_irqrestore(&svs_lock, flags);
svsb->phase = SVSB_PHASE_ERROR;
svs_adjust_pm_opp_volts(svsb);
svs_bank_disable_and_restore_default_volts(svsp, svsb);
}
ret = reset_control_assert(svsp->rst);
@ -1693,7 +1679,7 @@ static int svs_bank_resource_setup(struct svs_platform *svsp)
}
}
if (svsb->mode_support & SVSB_MODE_MON) {
if (!IS_ERR_OR_NULL(svsb->tzone_name)) {
svsb->tzd = thermal_zone_get_zone_by_name(svsb->tzone_name);
if (IS_ERR(svsb->tzd)) {
dev_err(svsb->dev, "cannot get \"%s\" thermal zone\n",
@ -1729,26 +1715,28 @@ static int svs_bank_resource_setup(struct svs_platform *svsp)
return 0;
}
static int svs_thermal_efuse_get_data(struct svs_platform *svsp)
static int svs_get_efuse_data(struct svs_platform *svsp,
const char *nvmem_cell_name,
u32 **svsp_efuse, size_t *svsp_efuse_max)
{
struct nvmem_cell *cell;
/* Thermal efuse parsing */
cell = nvmem_cell_get(svsp->dev, "t-calibration-data");
if (IS_ERR_OR_NULL(cell)) {
dev_err(svsp->dev, "no \"t-calibration-data\"? %ld\n", PTR_ERR(cell));
cell = nvmem_cell_get(svsp->dev, nvmem_cell_name);
if (IS_ERR(cell)) {
dev_err(svsp->dev, "no \"%s\"? %ld\n",
nvmem_cell_name, PTR_ERR(cell));
return PTR_ERR(cell);
}
svsp->tefuse = nvmem_cell_read(cell, &svsp->tefuse_max);
if (IS_ERR(svsp->tefuse)) {
dev_err(svsp->dev, "cannot read thermal efuse: %ld\n",
PTR_ERR(svsp->tefuse));
*svsp_efuse = nvmem_cell_read(cell, svsp_efuse_max);
if (IS_ERR(*svsp_efuse)) {
dev_err(svsp->dev, "cannot read \"%s\" efuse: %ld\n",
nvmem_cell_name, PTR_ERR(*svsp_efuse));
nvmem_cell_put(cell);
return PTR_ERR(svsp->tefuse);
return PTR_ERR(*svsp_efuse);
}
svsp->tefuse_max /= sizeof(u32);
*svsp_efuse_max /= sizeof(u32);
nvmem_cell_put(cell);
return 0;
@ -1796,7 +1784,8 @@ static bool svs_mt8192_efuse_parsing(struct svs_platform *svsp)
svsb->vmax += svsb->dvt_fixed;
}
ret = svs_thermal_efuse_get_data(svsp);
ret = svs_get_efuse_data(svsp, "t-calibration-data",
&svsp->tefuse, &svsp->tefuse_max);
if (ret)
return false;
@ -1901,7 +1890,8 @@ static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
}
}
ret = svs_thermal_efuse_get_data(svsp);
ret = svs_get_efuse_data(svsp, "t-calibration-data",
&svsp->tefuse, &svsp->tefuse_max);
if (ret)
return false;
@ -2003,32 +1993,6 @@ remove_mt8183_svsb_mon_mode:
return true;
}
static bool svs_is_efuse_data_correct(struct svs_platform *svsp)
{
struct nvmem_cell *cell;
/* Get svs efuse by nvmem */
cell = nvmem_cell_get(svsp->dev, "svs-calibration-data");
if (IS_ERR(cell)) {
dev_err(svsp->dev, "no \"svs-calibration-data\"? %ld\n",
PTR_ERR(cell));
return false;
}
svsp->efuse = nvmem_cell_read(cell, &svsp->efuse_max);
if (IS_ERR(svsp->efuse)) {
dev_err(svsp->dev, "cannot read svs efuse: %ld\n",
PTR_ERR(svsp->efuse));
nvmem_cell_put(cell);
return false;
}
svsp->efuse_max /= sizeof(u32);
nvmem_cell_put(cell);
return true;
}
static struct device *svs_get_subsys_device(struct svs_platform *svsp,
const char *node_name)
{
@ -2059,11 +2023,6 @@ static struct device *svs_add_device_link(struct svs_platform *svsp,
struct device *dev;
struct device_link *sup_link;
if (!node_name) {
dev_err(svsp->dev, "node name cannot be null\n");
return ERR_PTR(-EINVAL);
}
dev = svs_get_subsys_device(svsp, node_name);
if (IS_ERR(dev))
return dev;
@ -2159,6 +2118,7 @@ static struct svs_bank svs_mt8192_banks[] = {
.type = SVSB_LOW,
.set_freq_pct = svs_set_bank_freq_pct_v3,
.get_volts = svs_get_bank_volts_v3,
.tzone_name = "gpu1",
.volt_flags = SVSB_REMOVE_DVTFIXED_VOLT,
.mode_support = SVSB_MODE_INIT02,
.opp_count = MAX_OPP_ENTRIES,
@ -2176,6 +2136,10 @@ static struct svs_bank svs_mt8192_banks[] = {
.core_sel = 0x0fff0100,
.int_st = BIT(0),
.ctl0 = 0x00540003,
.tzone_htemp = 85000,
.tzone_htemp_voffset = 0,
.tzone_ltemp = 25000,
.tzone_ltemp_voffset = 7,
},
{
.sw_id = SVSB_GPU,
@ -2364,8 +2328,9 @@ static int svs_probe(struct platform_device *pdev)
if (ret)
return ret;
if (!svs_is_efuse_data_correct(svsp)) {
dev_notice(svsp->dev, "efuse data isn't correct\n");
ret = svs_get_efuse_data(svsp, "svs-calibration-data",
&svsp->efuse, &svsp->efuse_max);
if (ret) {
ret = -EPERM;
goto svs_probe_free_efuse;
}
@ -2373,19 +2338,19 @@ static int svs_probe(struct platform_device *pdev)
if (!svsp_data->efuse_parsing(svsp)) {
dev_err(svsp->dev, "efuse data parsing failed\n");
ret = -EPERM;
goto svs_probe_free_resource;
goto svs_probe_free_tefuse;
}
ret = svs_bank_resource_setup(svsp);
if (ret) {
dev_err(svsp->dev, "svs bank resource setup fail: %d\n", ret);
goto svs_probe_free_resource;
goto svs_probe_free_tefuse;
}
svsp_irq = platform_get_irq(pdev, 0);
if (svsp_irq < 0) {
ret = svsp_irq;
goto svs_probe_free_resource;
goto svs_probe_free_tefuse;
}
svsp->main_clk = devm_clk_get(svsp->dev, "main");
@ -2393,13 +2358,13 @@ static int svs_probe(struct platform_device *pdev)
dev_err(svsp->dev, "failed to get clock: %ld\n",
PTR_ERR(svsp->main_clk));
ret = PTR_ERR(svsp->main_clk);
goto svs_probe_free_resource;
goto svs_probe_free_tefuse;
}
ret = clk_prepare_enable(svsp->main_clk);
if (ret) {
dev_err(svsp->dev, "cannot enable main clk: %d\n", ret);
goto svs_probe_free_resource;
goto svs_probe_free_tefuse;
}
svsp->base = of_iomap(svsp->dev->of_node, 0);
@ -2439,7 +2404,7 @@ svs_probe_iounmap:
svs_probe_clk_disable:
clk_disable_unprepare(svsp->main_clk);
svs_probe_free_resource:
svs_probe_free_tefuse:
if (!IS_ERR_OR_NULL(svsp->tefuse))
kfree(svsp->tefuse);

View File

@ -11,12 +11,19 @@
#include <linux/slab.h>
#include <linux/kref.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/interrupt.h>
#include <linux/of_platform.h>
#include <linux/mailbox_client.h>
#include <linux/platform_device.h>
#include <soc/microchip/mpfs.h>
/*
* This timeout must be long, as some services (example: image authentication)
* take significant time to complete
*/
#define MPFS_SYS_CTRL_TIMEOUT_MS 30000
static DEFINE_MUTEX(transaction_lock);
struct mpfs_sys_controller {
@ -28,35 +35,47 @@ struct mpfs_sys_controller {
int mpfs_blocking_transaction(struct mpfs_sys_controller *sys_controller, struct mpfs_mss_msg *msg)
{
int ret, err;
unsigned long timeout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS);
int ret;
err = mutex_lock_interruptible(&transaction_lock);
if (err)
return err;
ret = mutex_lock_interruptible(&transaction_lock);
if (ret)
return ret;
reinit_completion(&sys_controller->c);
ret = mbox_send_message(sys_controller->chan, msg);
if (ret >= 0) {
if (wait_for_completion_timeout(&sys_controller->c, HZ)) {
ret = 0;
} else {
ret = -ETIMEDOUT;
dev_warn(sys_controller->client.dev,
"MPFS sys controller transaction timeout\n");
}
} else {
dev_err(sys_controller->client.dev,
"mpfs sys controller transaction returned %d\n", ret);
if (ret < 0) {
dev_warn(sys_controller->client.dev, "MPFS sys controller service timeout\n");
goto out;
}
/*
* Unfortunately, the system controller will only deliver an interrupt
* if a service succeeds. mbox_send_message() will block until the busy
* flag is gone. If the busy flag is gone but no interrupt has arrived
* to trigger the rx callback then the service can be deemed to have
* failed.
* The caller can then interrogate msg::response::resp_status to
* determine the cause of the failure.
* mbox_send_message() returns positive integers in the success path, so
* ret needs to be cleared if we do get an interrupt.
*/
if (!wait_for_completion_timeout(&sys_controller->c, timeout)) {
ret = -EBADMSG;
dev_warn(sys_controller->client.dev, "MPFS sys controller service failed\n");
} else {
ret = 0;
}
out:
mutex_unlock(&transaction_lock);
return ret;
}
EXPORT_SYMBOL(mpfs_blocking_transaction);
static void rx_callback(struct mbox_client *client, void *msg)
static void mpfs_sys_controller_rx_callback(struct mbox_client *client, void *msg)
{
struct mpfs_sys_controller *sys_controller =
container_of(client, struct mpfs_sys_controller, client);
@ -66,8 +85,8 @@ static void rx_callback(struct mbox_client *client, void *msg)
static void mpfs_sys_controller_delete(struct kref *kref)
{
struct mpfs_sys_controller *sys_controller = container_of(kref, struct mpfs_sys_controller,
consumers);
struct mpfs_sys_controller *sys_controller =
container_of(kref, struct mpfs_sys_controller, consumers);
mbox_free_channel(sys_controller->chan);
kfree(sys_controller);
@ -102,8 +121,9 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev)
return -ENOMEM;
sys_controller->client.dev = dev;
sys_controller->client.rx_callback = rx_callback;
sys_controller->client.rx_callback = mpfs_sys_controller_rx_callback;
sys_controller->client.tx_block = 1U;
sys_controller->client.tx_tout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS);
sys_controller->chan = mbox_request_channel(&sys_controller->client, 0);
if (IS_ERR(sys_controller->chan)) {

View File

@ -72,7 +72,7 @@ config QCOM_LLCC
config QCOM_KRYO_L2_ACCESSORS
bool
depends on ARCH_QCOM && ARM64 || COMPILE_TEST
depends on (ARCH_QCOM || COMPILE_TEST) && ARM64
config QCOM_MDT_LOADER
tristate
@ -275,4 +275,8 @@ config QCOM_ICC_BWMON
the fixed bandwidth votes from cpufreq (CPU nodes) thus achieve high
memory throughput even with lower CPU frequencies.
config QCOM_INLINE_CRYPTO_ENGINE
tristate
select QCOM_SCM
endmenu

View File

@ -32,3 +32,4 @@ obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o
obj-$(CONFIG_QCOM_ICC_BWMON) += icc-bwmon.o
obj-$(CONFIG_QCOM_INLINE_CRYPTO_ENGINE) += ice.o

View File

@ -34,14 +34,27 @@
/* Internal sampling clock frequency */
#define HW_TIMER_HZ 19200000
#define BWMON_V4_GLOBAL_IRQ_CLEAR 0x008
#define BWMON_V4_GLOBAL_IRQ_ENABLE 0x00c
#define BWMON_V4_GLOBAL_IRQ_CLEAR 0x108
#define BWMON_V4_GLOBAL_IRQ_ENABLE 0x10c
/*
* All values here and further are matching regmap fields, so without absolute
* register offsets.
*/
#define BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE BIT(0)
/*
* Starting with SDM845, the BWMON4 register space has changed a bit:
* the global registers were jammed into the beginning of the monitor region.
* To keep the proper offsets, one would have to map <GLOBAL_BASE 0x200> and
* <GLOBAL_BASE+0x100 0x300>, which is straight up wrong.
* To facilitate for that, while allowing the older, arguably more proper
* implementations to work, offset the global registers by -0x100 to avoid
* having to map half of the global registers twice.
*/
#define BWMON_V4_845_OFFSET 0x100
#define BWMON_V4_GLOBAL_IRQ_CLEAR_845 (BWMON_V4_GLOBAL_IRQ_CLEAR - BWMON_V4_845_OFFSET)
#define BWMON_V4_GLOBAL_IRQ_ENABLE_845 (BWMON_V4_GLOBAL_IRQ_ENABLE - BWMON_V4_845_OFFSET)
#define BWMON_V4_IRQ_STATUS 0x100
#define BWMON_V4_IRQ_CLEAR 0x108
@ -118,9 +131,13 @@
#define BWMON_NEEDS_FORCE_CLEAR BIT(1)
enum bwmon_fields {
/* Global region fields, keep them at the top */
F_GLOBAL_IRQ_CLEAR,
F_GLOBAL_IRQ_ENABLE,
F_IRQ_STATUS,
F_NUM_GLOBAL_FIELDS,
/* Monitor region fields */
F_IRQ_STATUS = F_NUM_GLOBAL_FIELDS,
F_IRQ_CLEAR,
F_IRQ_ENABLE,
F_ENABLE,
@ -157,6 +174,9 @@ struct icc_bwmon_data {
const struct regmap_config *regmap_cfg;
const struct reg_field *regmap_fields;
const struct regmap_config *global_regmap_cfg;
const struct reg_field *global_regmap_fields;
};
struct icc_bwmon {
@ -164,8 +184,8 @@ struct icc_bwmon {
const struct icc_bwmon_data *data;
int irq;
struct regmap *regmap;
struct regmap_field *regs[F_NUM_FIELDS];
struct regmap_field *global_regs[F_NUM_GLOBAL_FIELDS];
unsigned int max_bw_kbps;
unsigned int min_bw_kbps;
@ -175,8 +195,8 @@ struct icc_bwmon {
/* BWMON v4 */
static const struct reg_field msm8998_bwmon_reg_fields[] = {
[F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR, 0, 0),
[F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE, 0, 0),
[F_GLOBAL_IRQ_CLEAR] = {},
[F_GLOBAL_IRQ_ENABLE] = {},
[F_IRQ_STATUS] = REG_FIELD(BWMON_V4_IRQ_STATUS, 4, 7),
[F_IRQ_CLEAR] = REG_FIELD(BWMON_V4_IRQ_CLEAR, 4, 7),
[F_IRQ_ENABLE] = REG_FIELD(BWMON_V4_IRQ_ENABLE, 4, 7),
@ -202,7 +222,6 @@ static const struct reg_field msm8998_bwmon_reg_fields[] = {
};
static const struct regmap_range msm8998_bwmon_reg_noread_ranges[] = {
regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR, BWMON_V4_GLOBAL_IRQ_CLEAR),
regmap_reg_range(BWMON_V4_IRQ_CLEAR, BWMON_V4_IRQ_CLEAR),
regmap_reg_range(BWMON_V4_CLEAR, BWMON_V4_CLEAR),
};
@ -222,16 +241,33 @@ static const struct regmap_access_table msm8998_bwmon_reg_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(msm8998_bwmon_reg_volatile_ranges),
};
static const struct reg_field msm8998_bwmon_global_reg_fields[] = {
[F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR, 0, 0),
[F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE, 0, 0),
};
static const struct regmap_range msm8998_bwmon_global_reg_noread_ranges[] = {
regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR, BWMON_V4_GLOBAL_IRQ_CLEAR),
};
static const struct regmap_access_table msm8998_bwmon_global_reg_read_table = {
.no_ranges = msm8998_bwmon_global_reg_noread_ranges,
.n_no_ranges = ARRAY_SIZE(msm8998_bwmon_global_reg_noread_ranges),
};
/*
* Fill the cache for non-readable registers only as rest does not really
* matter and can be read from the device.
*/
static const struct reg_default msm8998_bwmon_reg_defaults[] = {
{ BWMON_V4_GLOBAL_IRQ_CLEAR, 0x0 },
{ BWMON_V4_IRQ_CLEAR, 0x0 },
{ BWMON_V4_CLEAR, 0x0 },
};
static const struct reg_default msm8998_bwmon_global_reg_defaults[] = {
{ BWMON_V4_GLOBAL_IRQ_CLEAR, 0x0 },
};
static const struct regmap_config msm8998_bwmon_regmap_cfg = {
.reg_bits = 32,
.reg_stride = 4,
@ -252,6 +288,93 @@ static const struct regmap_config msm8998_bwmon_regmap_cfg = {
.cache_type = REGCACHE_RBTREE,
};
static const struct regmap_config msm8998_bwmon_global_regmap_cfg = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
/*
* No concurrent access expected - driver has one interrupt handler,
* regmap is not shared, no driver or user-space API.
*/
.disable_locking = true,
.rd_table = &msm8998_bwmon_global_reg_read_table,
.reg_defaults = msm8998_bwmon_global_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(msm8998_bwmon_global_reg_defaults),
/*
* Cache is necessary for using regmap fields with non-readable
* registers.
*/
.cache_type = REGCACHE_RBTREE,
};
static const struct reg_field sdm845_cpu_bwmon_reg_fields[] = {
[F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR_845, 0, 0),
[F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE_845, 0, 0),
[F_IRQ_STATUS] = REG_FIELD(BWMON_V4_IRQ_STATUS, 4, 7),
[F_IRQ_CLEAR] = REG_FIELD(BWMON_V4_IRQ_CLEAR, 4, 7),
[F_IRQ_ENABLE] = REG_FIELD(BWMON_V4_IRQ_ENABLE, 4, 7),
/* F_ENABLE covers entire register to disable other features */
[F_ENABLE] = REG_FIELD(BWMON_V4_ENABLE, 0, 31),
[F_CLEAR] = REG_FIELD(BWMON_V4_CLEAR, 0, 1),
[F_SAMPLE_WINDOW] = REG_FIELD(BWMON_V4_SAMPLE_WINDOW, 0, 23),
[F_THRESHOLD_HIGH] = REG_FIELD(BWMON_V4_THRESHOLD_HIGH, 0, 11),
[F_THRESHOLD_MED] = REG_FIELD(BWMON_V4_THRESHOLD_MED, 0, 11),
[F_THRESHOLD_LOW] = REG_FIELD(BWMON_V4_THRESHOLD_LOW, 0, 11),
[F_ZONE_ACTIONS_ZONE0] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 0, 7),
[F_ZONE_ACTIONS_ZONE1] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 8, 15),
[F_ZONE_ACTIONS_ZONE2] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 16, 23),
[F_ZONE_ACTIONS_ZONE3] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 24, 31),
[F_THRESHOLD_COUNT_ZONE0] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 0, 7),
[F_THRESHOLD_COUNT_ZONE1] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 8, 15),
[F_THRESHOLD_COUNT_ZONE2] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 16, 23),
[F_THRESHOLD_COUNT_ZONE3] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 24, 31),
[F_ZONE0_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(0), 0, 11),
[F_ZONE1_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(1), 0, 11),
[F_ZONE2_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(2), 0, 11),
[F_ZONE3_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(3), 0, 11),
};
static const struct regmap_range sdm845_cpu_bwmon_reg_noread_ranges[] = {
regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR_845, BWMON_V4_GLOBAL_IRQ_CLEAR_845),
regmap_reg_range(BWMON_V4_IRQ_CLEAR, BWMON_V4_IRQ_CLEAR),
regmap_reg_range(BWMON_V4_CLEAR, BWMON_V4_CLEAR),
};
static const struct regmap_access_table sdm845_cpu_bwmon_reg_read_table = {
.no_ranges = sdm845_cpu_bwmon_reg_noread_ranges,
.n_no_ranges = ARRAY_SIZE(sdm845_cpu_bwmon_reg_noread_ranges),
};
/*
* Fill the cache for non-readable registers only as rest does not really
* matter and can be read from the device.
*/
static const struct reg_default sdm845_cpu_bwmon_reg_defaults[] = {
{ BWMON_V4_GLOBAL_IRQ_CLEAR_845, 0x0 },
{ BWMON_V4_IRQ_CLEAR, 0x0 },
{ BWMON_V4_CLEAR, 0x0 },
};
static const struct regmap_config sdm845_cpu_bwmon_regmap_cfg = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
/*
* No concurrent access expected - driver has one interrupt handler,
* regmap is not shared, no driver or user-space API.
*/
.disable_locking = true,
.rd_table = &sdm845_cpu_bwmon_reg_read_table,
.volatile_table = &msm8998_bwmon_reg_volatile_table,
.reg_defaults = sdm845_cpu_bwmon_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(sdm845_cpu_bwmon_reg_defaults),
/*
* Cache is necessary for using regmap fields with non-readable
* registers.
*/
.cache_type = REGCACHE_RBTREE,
};
/* BWMON v5 */
static const struct reg_field sdm845_llcc_bwmon_reg_fields[] = {
[F_GLOBAL_IRQ_CLEAR] = {},
@ -350,6 +473,13 @@ static void bwmon_clear_counters(struct icc_bwmon *bwmon, bool clear_all)
static void bwmon_clear_irq(struct icc_bwmon *bwmon)
{
struct regmap_field *global_irq_clr;
if (bwmon->data->global_regmap_fields)
global_irq_clr = bwmon->global_regs[F_GLOBAL_IRQ_CLEAR];
else
global_irq_clr = bwmon->regs[F_GLOBAL_IRQ_CLEAR];
/*
* Clear zone and global interrupts. The order and barriers are
* important. Quoting downstream Qualcomm msm-4.9 tree:
@ -370,15 +500,22 @@ static void bwmon_clear_irq(struct icc_bwmon *bwmon)
if (bwmon->data->quirks & BWMON_NEEDS_FORCE_CLEAR)
regmap_field_force_write(bwmon->regs[F_IRQ_CLEAR], 0);
if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ)
regmap_field_force_write(bwmon->regs[F_GLOBAL_IRQ_CLEAR],
regmap_field_force_write(global_irq_clr,
BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE);
}
static void bwmon_disable(struct icc_bwmon *bwmon)
{
struct regmap_field *global_irq_en;
if (bwmon->data->global_regmap_fields)
global_irq_en = bwmon->global_regs[F_GLOBAL_IRQ_ENABLE];
else
global_irq_en = bwmon->regs[F_GLOBAL_IRQ_ENABLE];
/* Disable interrupts. Strict ordering, see bwmon_clear_irq(). */
if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ)
regmap_field_write(bwmon->regs[F_GLOBAL_IRQ_ENABLE], 0x0);
regmap_field_write(global_irq_en, 0x0);
regmap_field_write(bwmon->regs[F_IRQ_ENABLE], 0x0);
/*
@ -390,10 +527,18 @@ static void bwmon_disable(struct icc_bwmon *bwmon)
static void bwmon_enable(struct icc_bwmon *bwmon, unsigned int irq_enable)
{
struct regmap_field *global_irq_en;
if (bwmon->data->global_regmap_fields)
global_irq_en = bwmon->global_regs[F_GLOBAL_IRQ_ENABLE];
else
global_irq_en = bwmon->regs[F_GLOBAL_IRQ_ENABLE];
/* Enable interrupts */
if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ)
regmap_field_write(bwmon->regs[F_GLOBAL_IRQ_ENABLE],
regmap_field_write(global_irq_en,
BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE);
regmap_field_write(bwmon->regs[F_IRQ_ENABLE], irq_enable);
/* Enable bwmon */
@ -556,7 +701,9 @@ static int bwmon_init_regmap(struct platform_device *pdev,
struct device *dev = &pdev->dev;
void __iomem *base;
struct regmap *map;
int ret;
/* Map the monitor base */
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return dev_err_probe(dev, PTR_ERR(base),
@ -567,12 +714,35 @@ static int bwmon_init_regmap(struct platform_device *pdev,
return dev_err_probe(dev, PTR_ERR(map),
"failed to initialize regmap\n");
BUILD_BUG_ON(ARRAY_SIZE(msm8998_bwmon_global_reg_fields) != F_NUM_GLOBAL_FIELDS);
BUILD_BUG_ON(ARRAY_SIZE(msm8998_bwmon_reg_fields) != F_NUM_FIELDS);
BUILD_BUG_ON(ARRAY_SIZE(sdm845_cpu_bwmon_reg_fields) != F_NUM_FIELDS);
BUILD_BUG_ON(ARRAY_SIZE(sdm845_llcc_bwmon_reg_fields) != F_NUM_FIELDS);
return devm_regmap_field_bulk_alloc(dev, map, bwmon->regs,
ret = devm_regmap_field_bulk_alloc(dev, map, bwmon->regs,
bwmon->data->regmap_fields,
F_NUM_FIELDS);
if (ret)
return ret;
if (bwmon->data->global_regmap_cfg) {
/* Map the global base, if separate */
base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(base))
return dev_err_probe(dev, PTR_ERR(base),
"failed to map bwmon global registers\n");
map = devm_regmap_init_mmio(dev, base, bwmon->data->global_regmap_cfg);
if (IS_ERR(map))
return dev_err_probe(dev, PTR_ERR(map),
"failed to initialize global regmap\n");
ret = devm_regmap_field_bulk_alloc(dev, map, bwmon->global_regs,
bwmon->data->global_regmap_fields,
F_NUM_GLOBAL_FIELDS);
}
return ret;
}
static int bwmon_probe(struct platform_device *pdev)
@ -645,6 +815,21 @@ static const struct icc_bwmon_data msm8998_bwmon_data = {
.quirks = BWMON_HAS_GLOBAL_IRQ,
.regmap_fields = msm8998_bwmon_reg_fields,
.regmap_cfg = &msm8998_bwmon_regmap_cfg,
.global_regmap_fields = msm8998_bwmon_global_reg_fields,
.global_regmap_cfg = &msm8998_bwmon_global_regmap_cfg,
};
static const struct icc_bwmon_data sdm845_cpu_bwmon_data = {
.sample_ms = 4,
.count_unit_kb = 64,
.default_highbw_kbps = 4800 * 1024, /* 4.8 GBps */
.default_medbw_kbps = 512 * 1024, /* 512 MBps */
.default_lowbw_kbps = 0,
.zone1_thres_count = 16,
.zone3_thres_count = 1,
.quirks = BWMON_HAS_GLOBAL_IRQ,
.regmap_fields = sdm845_cpu_bwmon_reg_fields,
.regmap_cfg = &sdm845_cpu_bwmon_regmap_cfg,
};
static const struct icc_bwmon_data sdm845_llcc_bwmon_data = {
@ -673,16 +858,18 @@ static const struct icc_bwmon_data sc7280_llcc_bwmon_data = {
};
static const struct of_device_id bwmon_of_match[] = {
{
.compatible = "qcom,msm8998-bwmon",
.data = &msm8998_bwmon_data
}, {
.compatible = "qcom,sdm845-llcc-bwmon",
.data = &sdm845_llcc_bwmon_data
}, {
.compatible = "qcom,sc7280-llcc-bwmon",
.data = &sc7280_llcc_bwmon_data
},
/* BWMONv4, separate monitor and global register spaces */
{ .compatible = "qcom,msm8998-bwmon", .data = &msm8998_bwmon_data },
/* BWMONv4, unified register space */
{ .compatible = "qcom,sdm845-bwmon", .data = &sdm845_cpu_bwmon_data },
/* BWMONv5 */
{ .compatible = "qcom,sdm845-llcc-bwmon", .data = &sdm845_llcc_bwmon_data },
{ .compatible = "qcom,sc7280-llcc-bwmon", .data = &sc7280_llcc_bwmon_data },
/* Compatibles kept for legacy reasons */
{ .compatible = "qcom,sc7280-cpu-bwmon", .data = &sdm845_cpu_bwmon_data },
{ .compatible = "qcom,sc8280xp-cpu-bwmon", .data = &sdm845_cpu_bwmon_data },
{ .compatible = "qcom,sm8550-cpu-bwmon", .data = &sdm845_cpu_bwmon_data },
{}
};
MODULE_DEVICE_TABLE(of, bwmon_of_match);

366
drivers/soc/qcom/ice.c Normal file
View File

@ -0,0 +1,366 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Qualcomm ICE (Inline Crypto Engine) support.
*
* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2019, Google LLC
* Copyright (c) 2023, Linaro Limited
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
#include <linux/of_platform.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <soc/qcom/ice.h>
#define AES_256_XTS_KEY_SIZE 64
/* QCOM ICE registers */
#define QCOM_ICE_REG_VERSION 0x0008
#define QCOM_ICE_REG_FUSE_SETTING 0x0010
#define QCOM_ICE_REG_BIST_STATUS 0x0070
#define QCOM_ICE_REG_ADVANCED_CONTROL 0x1000
/* BIST ("built-in self-test") status flags */
#define QCOM_ICE_BIST_STATUS_MASK GENMASK(31, 28)
#define QCOM_ICE_FUSE_SETTING_MASK 0x1
#define QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK 0x2
#define QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK 0x4
#define qcom_ice_writel(engine, val, reg) \
writel((val), (engine)->base + (reg))
#define qcom_ice_readl(engine, reg) \
readl((engine)->base + (reg))
struct qcom_ice {
struct device *dev;
void __iomem *base;
struct device_link *link;
struct clk *core_clk;
};
static bool qcom_ice_check_supported(struct qcom_ice *ice)
{
u32 regval = qcom_ice_readl(ice, QCOM_ICE_REG_VERSION);
struct device *dev = ice->dev;
int major = FIELD_GET(GENMASK(31, 24), regval);
int minor = FIELD_GET(GENMASK(23, 16), regval);
int step = FIELD_GET(GENMASK(15, 0), regval);
/* For now this driver only supports ICE version 3 and 4. */
if (major != 3 && major != 4) {
dev_warn(dev, "Unsupported ICE version: v%d.%d.%d\n",
major, minor, step);
return false;
}
dev_info(dev, "Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n",
major, minor, step);
/* If fuses are blown, ICE might not work in the standard way. */
regval = qcom_ice_readl(ice, QCOM_ICE_REG_FUSE_SETTING);
if (regval & (QCOM_ICE_FUSE_SETTING_MASK |
QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK |
QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK)) {
dev_warn(dev, "Fuses are blown; ICE is unusable!\n");
return false;
}
return true;
}
static void qcom_ice_low_power_mode_enable(struct qcom_ice *ice)
{
u32 regval;
regval = qcom_ice_readl(ice, QCOM_ICE_REG_ADVANCED_CONTROL);
/* Enable low power mode sequence */
regval |= 0x7000;
qcom_ice_writel(ice, regval, QCOM_ICE_REG_ADVANCED_CONTROL);
}
static void qcom_ice_optimization_enable(struct qcom_ice *ice)
{
u32 regval;
/* ICE Optimizations Enable Sequence */
regval = qcom_ice_readl(ice, QCOM_ICE_REG_ADVANCED_CONTROL);
regval |= 0xd807100;
/* ICE HPG requires delay before writing */
udelay(5);
qcom_ice_writel(ice, regval, QCOM_ICE_REG_ADVANCED_CONTROL);
udelay(5);
}
/*
* Wait until the ICE BIST (built-in self-test) has completed.
*
* This may be necessary before ICE can be used.
* Note that we don't really care whether the BIST passed or failed;
* we really just want to make sure that it isn't still running. This is
* because (a) the BIST is a FIPS compliance thing that never fails in
* practice, (b) ICE is documented to reject crypto requests if the BIST
* fails, so we needn't do it in software too, and (c) properly testing
* storage encryption requires testing the full storage stack anyway,
* and not relying on hardware-level self-tests.
*/
static int qcom_ice_wait_bist_status(struct qcom_ice *ice)
{
u32 regval;
int err;
err = readl_poll_timeout(ice->base + QCOM_ICE_REG_BIST_STATUS,
regval, !(regval & QCOM_ICE_BIST_STATUS_MASK),
50, 5000);
if (err)
dev_err(ice->dev, "Timed out waiting for ICE self-test to complete\n");
return err;
}
int qcom_ice_enable(struct qcom_ice *ice)
{
qcom_ice_low_power_mode_enable(ice);
qcom_ice_optimization_enable(ice);
return qcom_ice_wait_bist_status(ice);
}
EXPORT_SYMBOL_GPL(qcom_ice_enable);
int qcom_ice_resume(struct qcom_ice *ice)
{
struct device *dev = ice->dev;
int err;
err = clk_prepare_enable(ice->core_clk);
if (err) {
dev_err(dev, "failed to enable core clock (%d)\n",
err);
return err;
}
return qcom_ice_wait_bist_status(ice);
}
EXPORT_SYMBOL_GPL(qcom_ice_resume);
int qcom_ice_suspend(struct qcom_ice *ice)
{
clk_disable_unprepare(ice->core_clk);
return 0;
}
EXPORT_SYMBOL_GPL(qcom_ice_suspend);
int qcom_ice_program_key(struct qcom_ice *ice,
u8 algorithm_id, u8 key_size,
const u8 crypto_key[], u8 data_unit_size,
int slot)
{
struct device *dev = ice->dev;
union {
u8 bytes[AES_256_XTS_KEY_SIZE];
u32 words[AES_256_XTS_KEY_SIZE / sizeof(u32)];
} key;
int i;
int err;
/* Only AES-256-XTS has been tested so far. */
if (algorithm_id != QCOM_ICE_CRYPTO_ALG_AES_XTS ||
key_size != QCOM_ICE_CRYPTO_KEY_SIZE_256) {
dev_err_ratelimited(dev,
"Unhandled crypto capability; algorithm_id=%d, key_size=%d\n",
algorithm_id, key_size);
return -EINVAL;
}
memcpy(key.bytes, crypto_key, AES_256_XTS_KEY_SIZE);
/* The SCM call requires that the key words are encoded in big endian */
for (i = 0; i < ARRAY_SIZE(key.words); i++)
__cpu_to_be32s(&key.words[i]);
err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE,
QCOM_SCM_ICE_CIPHER_AES_256_XTS,
data_unit_size);
memzero_explicit(&key, sizeof(key));
return err;
}
EXPORT_SYMBOL_GPL(qcom_ice_program_key);
int qcom_ice_evict_key(struct qcom_ice *ice, int slot)
{
return qcom_scm_ice_invalidate_key(slot);
}
EXPORT_SYMBOL_GPL(qcom_ice_evict_key);
static struct qcom_ice *qcom_ice_create(struct device *dev,
void __iomem *base)
{
struct qcom_ice *engine;
if (!qcom_scm_is_available())
return ERR_PTR(-EPROBE_DEFER);
if (!qcom_scm_ice_available()) {
dev_warn(dev, "ICE SCM interface not found\n");
return NULL;
}
engine = devm_kzalloc(dev, sizeof(*engine), GFP_KERNEL);
if (!engine)
return ERR_PTR(-ENOMEM);
engine->dev = dev;
engine->base = base;
/*
* Legacy DT binding uses different clk names for each consumer,
* so lets try those first. If none of those are a match, it means
* the we only have one clock and it is part of the dedicated DT node.
* Also, enable the clock before we check what HW version the driver
* supports.
*/
engine->core_clk = devm_clk_get_optional_enabled(dev, "ice_core_clk");
if (!engine->core_clk)
engine->core_clk = devm_clk_get_optional_enabled(dev, "ice");
if (!engine->core_clk)
engine->core_clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(engine->core_clk))
return ERR_CAST(engine->core_clk);
if (!qcom_ice_check_supported(engine))
return ERR_PTR(-EOPNOTSUPP);
dev_dbg(dev, "Registered Qualcomm Inline Crypto Engine\n");
return engine;
}
/**
* of_qcom_ice_get() - get an ICE instance from a DT node
* @dev: device pointer for the consumer device
*
* This function will provide an ICE instance either by creating one for the
* consumer device if its DT node provides the 'ice' reg range and the 'ice'
* clock (for legacy DT style). On the other hand, if consumer provides a
* phandle via 'qcom,ice' property to an ICE DT, the ICE instance will already
* be created and so this function will return that instead.
*
* Return: ICE pointer on success, NULL if there is no ICE data provided by the
* consumer or ERR_PTR() on error.
*/
struct qcom_ice *of_qcom_ice_get(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct qcom_ice *ice;
struct device_node *node;
struct resource *res;
void __iomem *base;
if (!dev || !dev->of_node)
return ERR_PTR(-ENODEV);
/*
* In order to support legacy style devicetree bindings, we need
* to create the ICE instance using the consumer device and the reg
* range called 'ice' it provides.
*/
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ice");
if (res) {
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return ERR_CAST(base);
/* create ICE instance using consumer dev */
return qcom_ice_create(&pdev->dev, base);
}
/*
* If the consumer node does not provider an 'ice' reg range
* (legacy DT binding), then it must at least provide a phandle
* to the ICE devicetree node, otherwise ICE is not supported.
*/
node = of_parse_phandle(dev->of_node, "qcom,ice", 0);
if (!node)
return NULL;
pdev = of_find_device_by_node(node);
if (!pdev) {
dev_err(dev, "Cannot find device node %s\n", node->name);
ice = ERR_PTR(-EPROBE_DEFER);
goto out;
}
ice = platform_get_drvdata(pdev);
if (!ice) {
dev_err(dev, "Cannot get ice instance from %s\n",
dev_name(&pdev->dev));
platform_device_put(pdev);
ice = ERR_PTR(-EPROBE_DEFER);
goto out;
}
ice->link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
if (!ice->link) {
dev_err(&pdev->dev,
"Failed to create device link to consumer %s\n",
dev_name(dev));
platform_device_put(pdev);
ice = ERR_PTR(-EINVAL);
}
out:
of_node_put(node);
return ice;
}
EXPORT_SYMBOL_GPL(of_qcom_ice_get);
static int qcom_ice_probe(struct platform_device *pdev)
{
struct qcom_ice *engine;
void __iomem *base;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base)) {
dev_warn(&pdev->dev, "ICE registers not found\n");
return PTR_ERR(base);
}
engine = qcom_ice_create(&pdev->dev, base);
if (IS_ERR(engine))
return PTR_ERR(engine);
platform_set_drvdata(pdev, engine);
return 0;
}
static const struct of_device_id qcom_ice_of_match_table[] = {
{ .compatible = "qcom,inline-crypto-engine" },
{ },
};
MODULE_DEVICE_TABLE(of, qcom_ice_of_match_table);
static struct platform_driver qcom_ice_driver = {
.probe = qcom_ice_probe,
.driver = {
.name = "qcom-ice",
.of_match_table = qcom_ice_of_match_table,
},
};
module_platform_driver(qcom_ice_driver);
MODULE_DESCRIPTION("Qualcomm Inline Crypto Engine driver");
MODULE_LICENSE("GPL");

View File

@ -62,8 +62,6 @@
#define LLCC_TRP_WRSC_CACHEABLE_EN 0x21f2c
#define LLCC_TRP_ALGO_CFG8 0x21f30
#define BANK_OFFSET_STRIDE 0x80000
#define LLCC_VERSION_2_0_0_0 0x02000000
#define LLCC_VERSION_2_1_0_0 0x02010000
#define LLCC_VERSION_4_1_0_0 0x04010000
@ -122,10 +120,11 @@ struct llcc_slice_config {
struct qcom_llcc_config {
const struct llcc_slice_config *sct_data;
int size;
bool need_llcc_cfg;
const u32 *reg_offset;
const struct llcc_edac_reg_offset *edac_reg_offset;
int size;
bool need_llcc_cfg;
bool no_edac;
};
enum llcc_reg_offset {
@ -227,6 +226,14 @@ static const struct llcc_slice_config sm6350_data[] = {
{ LLCC_MODPE, 29, 64, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
};
static const struct llcc_slice_config sm7150_data[] = {
{ LLCC_CPUSS, 1, 512, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 1 },
{ LLCC_MDM, 8, 128, 2, 0, 0xF, 0x0, 0, 0, 0, 1, 0 },
{ LLCC_GPUHTW, 11, 256, 1, 1, 0xF, 0x0, 0, 0, 0, 1, 0 },
{ LLCC_GPU, 12, 256, 1, 1, 0xF, 0x0, 0, 0, 0, 1, 0 },
{ LLCC_NPU, 23, 512, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 0 },
};
static const struct llcc_slice_config sm8150_data[] = {
{ LLCC_CPUSS, 1, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 1 },
{ LLCC_VIDSC0, 2, 512, 2, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
@ -454,6 +461,7 @@ static const struct qcom_llcc_config sdm845_cfg = {
.need_llcc_cfg = false,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
.no_edac = true,
};
static const struct qcom_llcc_config sm6350_cfg = {
@ -464,6 +472,14 @@ static const struct qcom_llcc_config sm6350_cfg = {
.edac_reg_offset = &llcc_v1_edac_reg_offset,
};
static const struct qcom_llcc_config sm7150_cfg = {
.sct_data = sm7150_data,
.size = ARRAY_SIZE(sm7150_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
};
static const struct qcom_llcc_config sm8150_cfg = {
.sct_data = sm8150_data,
.size = ARRAY_SIZE(sm8150_data),
@ -898,8 +914,8 @@ static int qcom_llcc_remove(struct platform_device *pdev)
return 0;
}
static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev,
const char *name)
static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev, u8 index,
const char *name)
{
void __iomem *base;
struct regmap_config llcc_regmap_config = {
@ -909,7 +925,7 @@ static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev,
.fast_io = true,
};
base = devm_platform_ioremap_resource_byname(pdev, name);
base = devm_platform_ioremap_resource(pdev, index);
if (IS_ERR(base))
return ERR_CAST(base);
@ -927,6 +943,7 @@ static int qcom_llcc_probe(struct platform_device *pdev)
const struct llcc_slice_config *llcc_cfg;
u32 sz;
u32 version;
struct regmap *regmap;
drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
if (!drv_data) {
@ -934,21 +951,51 @@ static int qcom_llcc_probe(struct platform_device *pdev)
goto err;
}
drv_data->regmap = qcom_llcc_init_mmio(pdev, "llcc_base");
if (IS_ERR(drv_data->regmap)) {
ret = PTR_ERR(drv_data->regmap);
goto err;
}
drv_data->bcast_regmap =
qcom_llcc_init_mmio(pdev, "llcc_broadcast_base");
if (IS_ERR(drv_data->bcast_regmap)) {
ret = PTR_ERR(drv_data->bcast_regmap);
/* Initialize the first LLCC bank regmap */
regmap = qcom_llcc_init_mmio(pdev, 0, "llcc0_base");
if (IS_ERR(regmap)) {
ret = PTR_ERR(regmap);
goto err;
}
cfg = of_device_get_match_data(&pdev->dev);
ret = regmap_read(regmap, cfg->reg_offset[LLCC_COMMON_STATUS0], &num_banks);
if (ret)
goto err;
num_banks &= LLCC_LB_CNT_MASK;
num_banks >>= LLCC_LB_CNT_SHIFT;
drv_data->num_banks = num_banks;
drv_data->regmaps = devm_kcalloc(dev, num_banks, sizeof(*drv_data->regmaps), GFP_KERNEL);
if (!drv_data->regmaps) {
ret = -ENOMEM;
goto err;
}
drv_data->regmaps[0] = regmap;
/* Initialize rest of LLCC bank regmaps */
for (i = 1; i < num_banks; i++) {
char *base = kasprintf(GFP_KERNEL, "llcc%d_base", i);
drv_data->regmaps[i] = qcom_llcc_init_mmio(pdev, i, base);
if (IS_ERR(drv_data->regmaps[i])) {
ret = PTR_ERR(drv_data->regmaps[i]);
kfree(base);
goto err;
}
kfree(base);
}
drv_data->bcast_regmap = qcom_llcc_init_mmio(pdev, i, "llcc_broadcast_base");
if (IS_ERR(drv_data->bcast_regmap)) {
ret = PTR_ERR(drv_data->bcast_regmap);
goto err;
}
/* Extract version of the IP */
ret = regmap_read(drv_data->bcast_regmap, cfg->reg_offset[LLCC_COMMON_HW_INFO],
&version);
@ -957,15 +1004,6 @@ static int qcom_llcc_probe(struct platform_device *pdev)
drv_data->version = version;
ret = regmap_read(drv_data->regmap, cfg->reg_offset[LLCC_COMMON_STATUS0],
&num_banks);
if (ret)
goto err;
num_banks &= LLCC_LB_CNT_MASK;
num_banks >>= LLCC_LB_CNT_SHIFT;
drv_data->num_banks = num_banks;
llcc_cfg = cfg->sct_data;
sz = cfg->size;
@ -973,16 +1011,6 @@ static int qcom_llcc_probe(struct platform_device *pdev)
if (llcc_cfg[i].slice_id > drv_data->max_slices)
drv_data->max_slices = llcc_cfg[i].slice_id;
drv_data->offsets = devm_kcalloc(dev, num_banks, sizeof(u32),
GFP_KERNEL);
if (!drv_data->offsets) {
ret = -ENOMEM;
goto err;
}
for (i = 0; i < num_banks; i++)
drv_data->offsets[i] = i * BANK_OFFSET_STRIDE;
drv_data->bitmap = devm_bitmap_zalloc(dev, drv_data->max_slices,
GFP_KERNEL);
if (!drv_data->bitmap) {
@ -1001,7 +1029,14 @@ static int qcom_llcc_probe(struct platform_device *pdev)
goto err;
drv_data->ecc_irq = platform_get_irq_optional(pdev, 0);
if (drv_data->ecc_irq >= 0) {
/*
* On some platforms, the access to EDAC registers will be locked by
* the bootloader. So probing the EDAC driver will result in a crash.
* Hence, disable the creation of EDAC platform device for the
* problematic platforms.
*/
if (!cfg->no_edac) {
llcc_edac = platform_device_register_data(&pdev->dev,
"qcom_llcc_edac", -1, drv_data,
sizeof(*drv_data));
@ -1022,6 +1057,7 @@ static const struct of_device_id qcom_llcc_of_match[] = {
{ .compatible = "qcom,sc8280xp-llcc", .data = &sc8280xp_cfg },
{ .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfg },
{ .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfg },
{ .compatible = "qcom,sm7150-llcc", .data = &sm7150_cfg },
{ .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfg },
{ .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg },
{ .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfg },

View File

@ -4,6 +4,7 @@
* Copyright (c) 2022, Linaro Ltd
*/
#include <linux/auxiliary_bus.h>
#include <linux/of_device.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/rpmsg.h>
@ -11,12 +12,23 @@
#include <linux/soc/qcom/pdr.h>
#include <linux/soc/qcom/pmic_glink.h>
enum {
PMIC_GLINK_CLIENT_BATT = 0,
PMIC_GLINK_CLIENT_ALTMODE,
PMIC_GLINK_CLIENT_UCSI,
};
#define PMIC_GLINK_CLIENT_DEFAULT (BIT(PMIC_GLINK_CLIENT_BATT) | \
BIT(PMIC_GLINK_CLIENT_ALTMODE))
struct pmic_glink {
struct device *dev;
struct pdr_handle *pdr;
struct rpmsg_endpoint *ept;
unsigned long client_mask;
struct auxiliary_device altmode_aux;
struct auxiliary_device ps_aux;
struct auxiliary_device ucsi_aux;
@ -233,6 +245,7 @@ static struct rpmsg_driver pmic_glink_rpmsg_driver = {
static int pmic_glink_probe(struct platform_device *pdev)
{
const unsigned long *match_data;
struct pdr_service *service;
struct pmic_glink *pg;
int ret;
@ -249,12 +262,27 @@ static int pmic_glink_probe(struct platform_device *pdev)
mutex_init(&pg->client_lock);
mutex_init(&pg->state_lock);
ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode");
if (ret)
return ret;
ret = pmic_glink_add_aux_device(pg, &pg->ps_aux, "power-supply");
if (ret)
goto out_release_altmode_aux;
match_data = (unsigned long *)of_device_get_match_data(&pdev->dev);
if (match_data)
pg->client_mask = *match_data;
else
pg->client_mask = PMIC_GLINK_CLIENT_DEFAULT;
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) {
ret = pmic_glink_add_aux_device(pg, &pg->ucsi_aux, "ucsi");
if (ret)
return ret;
}
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) {
ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode");
if (ret)
goto out_release_ucsi_aux;
}
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) {
ret = pmic_glink_add_aux_device(pg, &pg->ps_aux, "power-supply");
if (ret)
goto out_release_altmode_aux;
}
pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg);
if (IS_ERR(pg->pdr)) {
@ -278,9 +306,14 @@ static int pmic_glink_probe(struct platform_device *pdev)
out_release_pdr_handle:
pdr_handle_release(pg->pdr);
out_release_aux_devices:
pmic_glink_del_aux_device(pg, &pg->ps_aux);
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT))
pmic_glink_del_aux_device(pg, &pg->ps_aux);
out_release_altmode_aux:
pmic_glink_del_aux_device(pg, &pg->altmode_aux);
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE))
pmic_glink_del_aux_device(pg, &pg->altmode_aux);
out_release_ucsi_aux:
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI))
pmic_glink_del_aux_device(pg, &pg->ucsi_aux);
return ret;
}
@ -291,8 +324,12 @@ static int pmic_glink_remove(struct platform_device *pdev)
pdr_handle_release(pg->pdr);
pmic_glink_del_aux_device(pg, &pg->ps_aux);
pmic_glink_del_aux_device(pg, &pg->altmode_aux);
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT))
pmic_glink_del_aux_device(pg, &pg->ps_aux);
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE))
pmic_glink_del_aux_device(pg, &pg->altmode_aux);
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI))
pmic_glink_del_aux_device(pg, &pg->ucsi_aux);
mutex_lock(&__pmic_glink_lock);
__pmic_glink = NULL;
@ -301,8 +338,14 @@ static int pmic_glink_remove(struct platform_device *pdev)
return 0;
}
/* Do not handle altmode for now on those platforms */
static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
BIT(PMIC_GLINK_CLIENT_UCSI);
static const struct of_device_id pmic_glink_of_match[] = {
{ .compatible = "qcom,pmic-glink", },
{ .compatible = "qcom,sm8450-pmic-glink", .data = &pmic_glink_sm8450_client_mask },
{ .compatible = "qcom,sm8550-pmic-glink", .data = &pmic_glink_sm8450_client_mask },
{ .compatible = "qcom,pmic-glink" },
{}
};
MODULE_DEVICE_TABLE(of, pmic_glink_of_match);

View File

@ -395,7 +395,7 @@ static int qmp_cooling_devices_register(struct qmp *qmp)
return -ENOMEM;
for_each_available_child_of_node(np, child) {
if (!of_find_property(child, "#cooling-cells", NULL))
if (!of_property_present(child, "#cooling-cells"))
continue;
ret = qmp_cooling_device_add(qmp, &qmp->cooling_devs[count++],
child);

View File

@ -114,7 +114,7 @@ struct gsbi_info {
struct regmap *tcsr;
};
static const struct of_device_id tcsr_dt_match[] = {
static const struct of_device_id tcsr_dt_match[] __maybe_unused = {
{ .compatible = "qcom,tcsr-ipq8064", .data = &config_ipq8064},
{ .compatible = "qcom,tcsr-apq8064", .data = &config_apq8064},
{ .compatible = "qcom,tcsr-msm8960", .data = &config_msm8960},

View File

@ -31,7 +31,7 @@ struct qcom_rmtfs_mem {
unsigned int client_id;
unsigned int perms;
u64 perms;
};
static ssize_t qcom_rmtfs_mem_show(struct device *dev,

View File

@ -1073,7 +1073,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
drv->ver.minor = rsc_id & (MINOR_VER_MASK << MINOR_VER_SHIFT);
drv->ver.minor >>= MINOR_VER_SHIFT;
if (drv->ver.major == 3 && drv->ver.minor == 0)
if (drv->ver.major == 3 && drv->ver.minor >= 0)
drv->regs = rpmh_rsc_reg_offset_ver_3_0;
else
drv->regs = rpmh_rsc_reg_offset_ver_2_7;

View File

@ -40,57 +40,6 @@
#define MAX_CORNER_RPMPD_STATE 6
#define DEFINE_RPMPD_PAIR(_platform, _name, _active, r_type, r_key, \
r_id) \
static struct rpmpd _platform##_##_active; \
static struct rpmpd _platform##_##_name = { \
.pd = { .name = #_name, }, \
.peer = &_platform##_##_active, \
.res_type = RPMPD_##r_type, \
.res_id = r_id, \
.key = KEY_##r_key, \
}; \
static struct rpmpd _platform##_##_active = { \
.pd = { .name = #_active, }, \
.peer = &_platform##_##_name, \
.active_only = true, \
.res_type = RPMPD_##r_type, \
.res_id = r_id, \
.key = KEY_##r_key, \
}
#define DEFINE_RPMPD_CORNER(_platform, _name, r_type, r_id) \
static struct rpmpd _platform##_##_name = { \
.pd = { .name = #_name, }, \
.res_type = RPMPD_##r_type, \
.res_id = r_id, \
.key = KEY_CORNER, \
}
#define DEFINE_RPMPD_LEVEL(_platform, _name, r_type, r_id) \
static struct rpmpd _platform##_##_name = { \
.pd = { .name = #_name, }, \
.res_type = RPMPD_##r_type, \
.res_id = r_id, \
.key = KEY_LEVEL, \
}
#define DEFINE_RPMPD_VFC(_platform, _name, r_type, r_id) \
static struct rpmpd _platform##_##_name = { \
.pd = { .name = #_name, }, \
.res_type = RPMPD_##r_type, \
.res_id = r_id, \
.key = KEY_FLOOR_CORNER, \
}
#define DEFINE_RPMPD_VFL(_platform, _name, r_type, r_id) \
static struct rpmpd _platform##_##_name = { \
.pd = { .name = #_name, }, \
.res_type = RPMPD_##r_type, \
.res_id = r_id, \
.key = KEY_FLOOR_LEVEL, \
}
struct rpmpd_req {
__le32 key;
__le32 nbytes;
@ -99,6 +48,7 @@ struct rpmpd_req {
struct rpmpd {
struct generic_pm_domain pd;
struct generic_pm_domain *parent;
struct rpmpd *peer;
const bool active_only;
unsigned int corner;
@ -118,19 +68,459 @@ struct rpmpd_desc {
static DEFINE_MUTEX(rpmpd_lock);
/* mdm9607 RPM Power Domains */
DEFINE_RPMPD_PAIR(mdm9607, vddcx, vddcx_ao, SMPA, LEVEL, 3);
DEFINE_RPMPD_VFL(mdm9607, vddcx_vfl, SMPA, 3);
/* CX */
static struct rpmpd cx_rwcx0_lvl_ao;
static struct rpmpd cx_rwcx0_lvl = {
.pd = { .name = "cx", },
.peer = &cx_rwcx0_lvl_ao,
.res_type = RPMPD_RWCX,
.res_id = 0,
.key = KEY_LEVEL,
};
static struct rpmpd cx_rwcx0_lvl_ao = {
.pd = { .name = "cx_ao", },
.peer = &cx_rwcx0_lvl,
.active_only = true,
.res_type = RPMPD_RWCX,
.res_id = 0,
.key = KEY_LEVEL,
};
static struct rpmpd cx_s1a_corner_ao;
static struct rpmpd cx_s1a_corner = {
.pd = { .name = "cx", },
.peer = &cx_s1a_corner_ao,
.res_type = RPMPD_SMPA,
.res_id = 1,
.key = KEY_CORNER,
};
static struct rpmpd cx_s1a_corner_ao = {
.pd = { .name = "cx_ao", },
.peer = &cx_s1a_corner,
.active_only = true,
.res_type = RPMPD_SMPA,
.res_id = 1,
.key = KEY_CORNER,
};
static struct rpmpd cx_s2a_corner_ao;
static struct rpmpd cx_s2a_corner = {
.pd = { .name = "cx", },
.peer = &cx_s2a_corner_ao,
.res_type = RPMPD_SMPA,
.res_id = 2,
.key = KEY_CORNER,
};
static struct rpmpd cx_s2a_corner_ao = {
.pd = { .name = "cx_ao", },
.peer = &cx_s2a_corner,
.active_only = true,
.res_type = RPMPD_SMPA,
.res_id = 2,
.key = KEY_CORNER,
};
static struct rpmpd cx_s2a_lvl_ao;
static struct rpmpd cx_s2a_lvl = {
.pd = { .name = "cx", },
.peer = &cx_s2a_lvl_ao,
.res_type = RPMPD_SMPA,
.res_id = 2,
.key = KEY_LEVEL,
};
static struct rpmpd cx_s2a_lvl_ao = {
.pd = { .name = "cx_ao", },
.peer = &cx_s2a_lvl,
.active_only = true,
.res_type = RPMPD_SMPA,
.res_id = 2,
.key = KEY_LEVEL,
};
static struct rpmpd cx_s3a_lvl_ao;
static struct rpmpd cx_s3a_lvl = {
.pd = { .name = "cx", },
.peer = &cx_s3a_lvl_ao,
.res_type = RPMPD_SMPA,
.res_id = 3,
.key = KEY_LEVEL,
};
static struct rpmpd cx_s3a_lvl_ao = {
.pd = { .name = "cx_ao", },
.peer = &cx_s3a_lvl,
.active_only = true,
.res_type = RPMPD_SMPA,
.res_id = 3,
.key = KEY_LEVEL,
};
static struct rpmpd cx_rwcx0_vfl = {
.pd = { .name = "cx_vfl", },
.res_type = RPMPD_RWCX,
.res_id = 0,
.key = KEY_FLOOR_LEVEL,
};
static struct rpmpd cx_rwsc2_vfl = {
.pd = { .name = "cx_vfl", },
.res_type = RPMPD_RWSC,
.res_id = 2,
.key = KEY_FLOOR_LEVEL,
};
static struct rpmpd cx_s1a_vfc = {
.pd = { .name = "cx_vfc", },
.res_type = RPMPD_SMPA,
.res_id = 1,
.key = KEY_FLOOR_CORNER,
};
static struct rpmpd cx_s2a_vfc = {
.pd = { .name = "cx_vfc", },
.res_type = RPMPD_SMPA,
.res_id = 2,
.key = KEY_FLOOR_CORNER,
};
static struct rpmpd cx_s2a_vfl = {
.pd = { .name = "cx_vfl", },
.res_type = RPMPD_SMPA,
.res_id = 2,
.key = KEY_FLOOR_LEVEL,
};
static struct rpmpd cx_s3a_vfl = {
.pd = { .name = "cx_vfl", },
.res_type = RPMPD_SMPA,
.res_id = 3,
.key = KEY_FLOOR_LEVEL,
};
/* G(F)X */
static struct rpmpd gfx_s2b_corner = {
.pd = { .name = "gfx", },
.res_type = RPMPD_SMPB,
.res_id = 2,
.key = KEY_CORNER,
};
static struct rpmpd gfx_s2b_vfc = {
.pd = { .name = "gfx_vfc", },
.res_type = RPMPD_SMPB,
.res_id = 2,
.key = KEY_FLOOR_CORNER,
};
static struct rpmpd mx_rwmx0_lvl;
static struct rpmpd gx_rwgx0_lvl_ao;
static struct rpmpd gx_rwgx0_lvl = {
.pd = { .name = "gx", },
.peer = &gx_rwgx0_lvl_ao,
.res_type = RPMPD_RWGX,
.parent = &mx_rwmx0_lvl.pd,
.res_id = 0,
.key = KEY_LEVEL,
};
static struct rpmpd mx_rwmx0_lvl_ao;
static struct rpmpd gx_rwgx0_lvl_ao = {
.pd = { .name = "gx_ao", },
.peer = &gx_rwgx0_lvl,
.parent = &mx_rwmx0_lvl_ao.pd,
.active_only = true,
.res_type = RPMPD_RWGX,
.res_id = 0,
.key = KEY_LEVEL,
};
/* MX */
static struct rpmpd mx_l3a_corner_ao;
static struct rpmpd mx_l3a_corner = {
.pd = { .name = "mx", },
.peer = &mx_l3a_corner_ao,
.res_type = RPMPD_LDOA,
.res_id = 3,
.key = KEY_CORNER,
};
static struct rpmpd mx_l3a_corner_ao = {
.pd = { .name = "mx_ao", },
.peer = &mx_l3a_corner,
.active_only = true,
.res_type = RPMPD_LDOA,
.res_id = 3,
.key = KEY_CORNER,
};
static struct rpmpd mx_l12a_lvl_ao;
static struct rpmpd mx_l12a_lvl = {
.pd = { .name = "mx", },
.peer = &mx_l12a_lvl_ao,
.res_type = RPMPD_LDOA,
.res_id = 12,
.key = KEY_LEVEL,
};
static struct rpmpd mx_l12a_lvl_ao = {
.pd = { .name = "mx_ao", },
.peer = &mx_l12a_lvl,
.active_only = true,
.res_type = RPMPD_LDOA,
.res_id = 12,
.key = KEY_LEVEL,
};
static struct rpmpd mx_s2a_corner_ao;
static struct rpmpd mx_s2a_corner = {
.pd = { .name = "mx", },
.peer = &mx_s2a_corner_ao,
.res_type = RPMPD_SMPA,
.res_id = 2,
.key = KEY_CORNER,
};
static struct rpmpd mx_s2a_corner_ao = {
.pd = { .name = "mx_ao", },
.peer = &mx_s2a_corner,
.active_only = true,
.res_type = RPMPD_SMPA,
.res_id = 2,
.key = KEY_CORNER,
};
static struct rpmpd mx_rwmx0_lvl_ao;
static struct rpmpd mx_rwmx0_lvl = {
.pd = { .name = "mx", },
.peer = &mx_rwmx0_lvl_ao,
.res_type = RPMPD_RWMX,
.res_id = 0,
.key = KEY_LEVEL,
};
static struct rpmpd mx_rwmx0_lvl_ao = {
.pd = { .name = "mx_ao", },
.peer = &mx_rwmx0_lvl,
.active_only = true,
.res_type = RPMPD_RWMX,
.res_id = 0,
.key = KEY_LEVEL,
};
static struct rpmpd mx_s6a_lvl_ao;
static struct rpmpd mx_s6a_lvl = {
.pd = { .name = "mx", },
.peer = &mx_s6a_lvl_ao,
.res_type = RPMPD_SMPA,
.res_id = 6,
.key = KEY_LEVEL,
};
static struct rpmpd mx_s6a_lvl_ao = {
.pd = { .name = "mx_ao", },
.peer = &mx_s6a_lvl,
.active_only = true,
.res_type = RPMPD_SMPA,
.res_id = 6,
.key = KEY_LEVEL,
};
static struct rpmpd mx_s7a_lvl_ao;
static struct rpmpd mx_s7a_lvl = {
.pd = { .name = "mx", },
.peer = &mx_s7a_lvl_ao,
.res_type = RPMPD_SMPA,
.res_id = 7,
.key = KEY_LEVEL,
};
static struct rpmpd mx_s7a_lvl_ao = {
.pd = { .name = "mx_ao", },
.peer = &mx_s7a_lvl,
.active_only = true,
.res_type = RPMPD_SMPA,
.res_id = 7,
.key = KEY_LEVEL,
};
static struct rpmpd mx_l12a_vfl = {
.pd = { .name = "mx_vfl", },
.res_type = RPMPD_LDOA,
.res_id = 12,
.key = KEY_FLOOR_LEVEL,
};
static struct rpmpd mx_rwmx0_vfl = {
.pd = { .name = "mx_vfl", },
.res_type = RPMPD_RWMX,
.res_id = 0,
.key = KEY_FLOOR_LEVEL,
};
static struct rpmpd mx_rwsm6_vfl = {
.pd = { .name = "mx_vfl", },
.res_type = RPMPD_RWSM,
.res_id = 6,
.key = KEY_FLOOR_LEVEL,
};
/* MD */
static struct rpmpd md_s1a_corner_ao;
static struct rpmpd md_s1a_corner = {
.pd = { .name = "md", },
.peer = &md_s1a_corner_ao,
.res_type = RPMPD_SMPA,
.res_id = 1,
.key = KEY_CORNER,
};
static struct rpmpd md_s1a_corner_ao = {
.pd = { .name = "md_ao", },
.peer = &md_s1a_corner,
.active_only = true,
.res_type = RPMPD_SMPA,
.res_id = 1,
.key = KEY_CORNER,
};
static struct rpmpd md_s1a_lvl_ao;
static struct rpmpd md_s1a_lvl = {
.pd = { .name = "md", },
.peer = &md_s1a_lvl_ao,
.res_type = RPMPD_SMPA,
.res_id = 1,
.key = KEY_LEVEL,
};
static struct rpmpd md_s1a_lvl_ao = {
.pd = { .name = "md_ao", },
.peer = &md_s1a_lvl,
.active_only = true,
.res_type = RPMPD_SMPA,
.res_id = 1,
.key = KEY_LEVEL,
};
static struct rpmpd md_s1a_vfc = {
.pd = { .name = "md_vfc", },
.res_type = RPMPD_SMPA,
.res_id = 1,
.key = KEY_FLOOR_CORNER,
};
/* LPI_CX */
static struct rpmpd lpi_cx_rwlc0_lvl = {
.pd = { .name = "lpi_cx", },
.res_type = RPMPD_RWLC,
.res_id = 0,
.key = KEY_LEVEL,
};
static struct rpmpd lpi_cx_rwlc0_vfl = {
.pd = { .name = "lpi_cx_vfl", },
.res_type = RPMPD_RWLC,
.res_id = 0,
.key = KEY_FLOOR_LEVEL,
};
/* LPI_MX */
static struct rpmpd lpi_mx_rwlm0_lvl = {
.pd = { .name = "lpi_mx", },
.res_type = RPMPD_RWLM,
.res_id = 0,
.key = KEY_LEVEL,
};
static struct rpmpd lpi_mx_rwlm0_vfl = {
.pd = { .name = "lpi_mx_vfl", },
.res_type = RPMPD_RWLM,
.res_id = 0,
.key = KEY_FLOOR_LEVEL,
};
/* SSC_CX */
static struct rpmpd ssc_cx_l26a_corner = {
.pd = { .name = "ssc_cx", },
.res_type = RPMPD_LDOA,
.res_id = 26,
.key = KEY_CORNER,
};
static struct rpmpd ssc_cx_rwlc0_lvl = {
.pd = { .name = "ssc_cx", },
.res_type = RPMPD_RWLC,
.res_id = 0,
.key = KEY_LEVEL,
};
static struct rpmpd ssc_cx_rwsc0_lvl = {
.pd = { .name = "ssc_cx", },
.res_type = RPMPD_RWSC,
.res_id = 0,
.key = KEY_LEVEL,
};
static struct rpmpd ssc_cx_l26a_vfc = {
.pd = { .name = "ssc_cx_vfc", },
.res_type = RPMPD_LDOA,
.res_id = 26,
.key = KEY_FLOOR_CORNER,
};
static struct rpmpd ssc_cx_rwlc0_vfl = {
.pd = { .name = "ssc_cx_vfl", },
.res_type = RPMPD_RWLC,
.res_id = 0,
.key = KEY_FLOOR_LEVEL,
};
static struct rpmpd ssc_cx_rwsc0_vfl = {
.pd = { .name = "ssc_cx_vfl", },
.res_type = RPMPD_RWSC,
.res_id = 0,
.key = KEY_FLOOR_LEVEL,
};
/* SSC_MX */
static struct rpmpd ssc_mx_rwlm0_lvl = {
.pd = { .name = "ssc_mx", },
.res_type = RPMPD_RWLM,
.res_id = 0,
.key = KEY_LEVEL,
};
static struct rpmpd ssc_mx_rwsm0_lvl = {
.pd = { .name = "ssc_mx", },
.res_type = RPMPD_RWSM,
.res_id = 0,
.key = KEY_LEVEL,
};
static struct rpmpd ssc_mx_rwlm0_vfl = {
.pd = { .name = "ssc_mx_vfl", },
.res_type = RPMPD_RWLM,
.res_id = 0,
.key = KEY_FLOOR_LEVEL,
};
static struct rpmpd ssc_mx_rwsm0_vfl = {
.pd = { .name = "ssc_mx_vfl", },
.res_type = RPMPD_RWSM,
.res_id = 0,
.key = KEY_FLOOR_LEVEL,
};
DEFINE_RPMPD_PAIR(mdm9607, vddmx, vddmx_ao, LDOA, LEVEL, 12);
DEFINE_RPMPD_VFL(mdm9607, vddmx_vfl, LDOA, 12);
static struct rpmpd *mdm9607_rpmpds[] = {
[MDM9607_VDDCX] = &mdm9607_vddcx,
[MDM9607_VDDCX_AO] = &mdm9607_vddcx_ao,
[MDM9607_VDDCX_VFL] = &mdm9607_vddcx_vfl,
[MDM9607_VDDMX] = &mdm9607_vddmx,
[MDM9607_VDDMX_AO] = &mdm9607_vddmx_ao,
[MDM9607_VDDMX_VFL] = &mdm9607_vddmx_vfl,
[MDM9607_VDDCX] = &cx_s3a_lvl,
[MDM9607_VDDCX_AO] = &cx_s3a_lvl_ao,
[MDM9607_VDDCX_VFL] = &cx_s3a_vfl,
[MDM9607_VDDMX] = &mx_l12a_lvl,
[MDM9607_VDDMX_AO] = &mx_l12a_lvl_ao,
[MDM9607_VDDMX_VFL] = &mx_l12a_vfl,
};
static const struct rpmpd_desc mdm9607_desc = {
@ -139,14 +529,10 @@ static const struct rpmpd_desc mdm9607_desc = {
.max_state = RPM_SMD_LEVEL_TURBO,
};
/* msm8226 RPM Power Domains */
DEFINE_RPMPD_PAIR(msm8226, vddcx, vddcx_ao, SMPA, CORNER, 1);
DEFINE_RPMPD_VFC(msm8226, vddcx_vfc, SMPA, 1);
static struct rpmpd *msm8226_rpmpds[] = {
[MSM8226_VDDCX] = &msm8226_vddcx,
[MSM8226_VDDCX_AO] = &msm8226_vddcx_ao,
[MSM8226_VDDCX_VFC] = &msm8226_vddcx_vfc,
[MSM8226_VDDCX] = &cx_s1a_corner,
[MSM8226_VDDCX_AO] = &cx_s1a_corner_ao,
[MSM8226_VDDCX_VFC] = &cx_s1a_vfc,
};
static const struct rpmpd_desc msm8226_desc = {
@ -155,24 +541,15 @@ static const struct rpmpd_desc msm8226_desc = {
.max_state = MAX_CORNER_RPMPD_STATE,
};
/* msm8939 RPM Power Domains */
DEFINE_RPMPD_PAIR(msm8939, vddmd, vddmd_ao, SMPA, CORNER, 1);
DEFINE_RPMPD_VFC(msm8939, vddmd_vfc, SMPA, 1);
DEFINE_RPMPD_PAIR(msm8939, vddcx, vddcx_ao, SMPA, CORNER, 2);
DEFINE_RPMPD_VFC(msm8939, vddcx_vfc, SMPA, 2);
DEFINE_RPMPD_PAIR(msm8939, vddmx, vddmx_ao, LDOA, CORNER, 3);
static struct rpmpd *msm8939_rpmpds[] = {
[MSM8939_VDDMDCX] = &msm8939_vddmd,
[MSM8939_VDDMDCX_AO] = &msm8939_vddmd_ao,
[MSM8939_VDDMDCX_VFC] = &msm8939_vddmd_vfc,
[MSM8939_VDDCX] = &msm8939_vddcx,
[MSM8939_VDDCX_AO] = &msm8939_vddcx_ao,
[MSM8939_VDDCX_VFC] = &msm8939_vddcx_vfc,
[MSM8939_VDDMX] = &msm8939_vddmx,
[MSM8939_VDDMX_AO] = &msm8939_vddmx_ao,
[MSM8939_VDDMDCX] = &md_s1a_corner,
[MSM8939_VDDMDCX_AO] = &md_s1a_corner_ao,
[MSM8939_VDDMDCX_VFC] = &md_s1a_vfc,
[MSM8939_VDDCX] = &cx_s2a_corner,
[MSM8939_VDDCX_AO] = &cx_s2a_corner_ao,
[MSM8939_VDDCX_VFC] = &cx_s2a_vfc,
[MSM8939_VDDMX] = &mx_l3a_corner,
[MSM8939_VDDMX_AO] = &mx_l3a_corner_ao,
};
static const struct rpmpd_desc msm8939_desc = {
@ -181,18 +558,12 @@ static const struct rpmpd_desc msm8939_desc = {
.max_state = MAX_CORNER_RPMPD_STATE,
};
/* msm8916 RPM Power Domains */
DEFINE_RPMPD_PAIR(msm8916, vddcx, vddcx_ao, SMPA, CORNER, 1);
DEFINE_RPMPD_PAIR(msm8916, vddmx, vddmx_ao, LDOA, CORNER, 3);
DEFINE_RPMPD_VFC(msm8916, vddcx_vfc, SMPA, 1);
static struct rpmpd *msm8916_rpmpds[] = {
[MSM8916_VDDCX] = &msm8916_vddcx,
[MSM8916_VDDCX_AO] = &msm8916_vddcx_ao,
[MSM8916_VDDCX_VFC] = &msm8916_vddcx_vfc,
[MSM8916_VDDMX] = &msm8916_vddmx,
[MSM8916_VDDMX_AO] = &msm8916_vddmx_ao,
[MSM8916_VDDCX] = &cx_s1a_corner,
[MSM8916_VDDCX_AO] = &cx_s1a_corner_ao,
[MSM8916_VDDCX_VFC] = &cx_s1a_vfc,
[MSM8916_VDDMX] = &mx_l3a_corner,
[MSM8916_VDDMX_AO] = &mx_l3a_corner_ao,
};
static const struct rpmpd_desc msm8916_desc = {
@ -201,21 +572,14 @@ static const struct rpmpd_desc msm8916_desc = {
.max_state = MAX_CORNER_RPMPD_STATE,
};
/* msm8953 RPM Power Domains */
DEFINE_RPMPD_PAIR(msm8953, vddmd, vddmd_ao, SMPA, LEVEL, 1);
DEFINE_RPMPD_PAIR(msm8953, vddcx, vddcx_ao, SMPA, LEVEL, 2);
DEFINE_RPMPD_PAIR(msm8953, vddmx, vddmx_ao, SMPA, LEVEL, 7);
DEFINE_RPMPD_VFL(msm8953, vddcx_vfl, SMPA, 2);
static struct rpmpd *msm8953_rpmpds[] = {
[MSM8953_VDDMD] = &msm8953_vddmd,
[MSM8953_VDDMD_AO] = &msm8953_vddmd_ao,
[MSM8953_VDDCX] = &msm8953_vddcx,
[MSM8953_VDDCX_AO] = &msm8953_vddcx_ao,
[MSM8953_VDDCX_VFL] = &msm8953_vddcx_vfl,
[MSM8953_VDDMX] = &msm8953_vddmx,
[MSM8953_VDDMX_AO] = &msm8953_vddmx_ao,
[MSM8953_VDDMD] = &md_s1a_lvl,
[MSM8953_VDDMD_AO] = &md_s1a_lvl_ao,
[MSM8953_VDDCX] = &cx_s2a_lvl,
[MSM8953_VDDCX_AO] = &cx_s2a_lvl_ao,
[MSM8953_VDDCX_VFL] = &cx_s2a_vfl,
[MSM8953_VDDMX] = &mx_s7a_lvl,
[MSM8953_VDDMX_AO] = &mx_s7a_lvl_ao,
};
static const struct rpmpd_desc msm8953_desc = {
@ -224,20 +588,13 @@ static const struct rpmpd_desc msm8953_desc = {
.max_state = RPM_SMD_LEVEL_TURBO,
};
/* msm8976 RPM Power Domains */
DEFINE_RPMPD_PAIR(msm8976, vddcx, vddcx_ao, SMPA, LEVEL, 2);
DEFINE_RPMPD_PAIR(msm8976, vddmx, vddmx_ao, SMPA, LEVEL, 6);
DEFINE_RPMPD_VFL(msm8976, vddcx_vfl, RWSC, 2);
DEFINE_RPMPD_VFL(msm8976, vddmx_vfl, RWSM, 6);
static struct rpmpd *msm8976_rpmpds[] = {
[MSM8976_VDDCX] = &msm8976_vddcx,
[MSM8976_VDDCX_AO] = &msm8976_vddcx_ao,
[MSM8976_VDDCX_VFL] = &msm8976_vddcx_vfl,
[MSM8976_VDDMX] = &msm8976_vddmx,
[MSM8976_VDDMX_AO] = &msm8976_vddmx_ao,
[MSM8976_VDDMX_VFL] = &msm8976_vddmx_vfl,
[MSM8976_VDDCX] = &cx_s2a_lvl,
[MSM8976_VDDCX_AO] = &cx_s2a_lvl_ao,
[MSM8976_VDDCX_VFL] = &cx_rwsc2_vfl,
[MSM8976_VDDMX] = &mx_s6a_lvl,
[MSM8976_VDDMX_AO] = &mx_s6a_lvl_ao,
[MSM8976_VDDMX_VFL] = &mx_rwsm6_vfl,
};
static const struct rpmpd_desc msm8976_desc = {
@ -246,23 +603,16 @@ static const struct rpmpd_desc msm8976_desc = {
.max_state = RPM_SMD_LEVEL_TURBO_HIGH,
};
/* msm8994 RPM Power domains */
DEFINE_RPMPD_PAIR(msm8994, vddcx, vddcx_ao, SMPA, CORNER, 1);
DEFINE_RPMPD_PAIR(msm8994, vddmx, vddmx_ao, SMPA, CORNER, 2);
/* Attention! *Some* 8994 boards with pm8004 may use SMPC here! */
DEFINE_RPMPD_CORNER(msm8994, vddgfx, SMPB, 2);
DEFINE_RPMPD_VFC(msm8994, vddcx_vfc, SMPA, 1);
DEFINE_RPMPD_VFC(msm8994, vddgfx_vfc, SMPB, 2);
static struct rpmpd *msm8994_rpmpds[] = {
[MSM8994_VDDCX] = &msm8994_vddcx,
[MSM8994_VDDCX_AO] = &msm8994_vddcx_ao,
[MSM8994_VDDCX_VFC] = &msm8994_vddcx_vfc,
[MSM8994_VDDMX] = &msm8994_vddmx,
[MSM8994_VDDMX_AO] = &msm8994_vddmx_ao,
[MSM8994_VDDGFX] = &msm8994_vddgfx,
[MSM8994_VDDGFX_VFC] = &msm8994_vddgfx_vfc,
[MSM8994_VDDCX] = &cx_s1a_corner,
[MSM8994_VDDCX_AO] = &cx_s1a_corner_ao,
[MSM8994_VDDCX_VFC] = &cx_s1a_vfc,
[MSM8994_VDDMX] = &mx_s2a_corner,
[MSM8994_VDDMX_AO] = &mx_s2a_corner_ao,
/* Attention! *Some* 8994 boards with pm8004 may use SMPC here! */
[MSM8994_VDDGFX] = &gfx_s2b_corner,
[MSM8994_VDDGFX_VFC] = &gfx_s2b_vfc,
};
static const struct rpmpd_desc msm8994_desc = {
@ -271,22 +621,14 @@ static const struct rpmpd_desc msm8994_desc = {
.max_state = MAX_CORNER_RPMPD_STATE,
};
/* msm8996 RPM Power domains */
DEFINE_RPMPD_PAIR(msm8996, vddcx, vddcx_ao, SMPA, CORNER, 1);
DEFINE_RPMPD_PAIR(msm8996, vddmx, vddmx_ao, SMPA, CORNER, 2);
DEFINE_RPMPD_CORNER(msm8996, vddsscx, LDOA, 26);
DEFINE_RPMPD_VFC(msm8996, vddcx_vfc, SMPA, 1);
DEFINE_RPMPD_VFC(msm8996, vddsscx_vfc, LDOA, 26);
static struct rpmpd *msm8996_rpmpds[] = {
[MSM8996_VDDCX] = &msm8996_vddcx,
[MSM8996_VDDCX_AO] = &msm8996_vddcx_ao,
[MSM8996_VDDCX_VFC] = &msm8996_vddcx_vfc,
[MSM8996_VDDMX] = &msm8996_vddmx,
[MSM8996_VDDMX_AO] = &msm8996_vddmx_ao,
[MSM8996_VDDSSCX] = &msm8996_vddsscx,
[MSM8996_VDDSSCX_VFC] = &msm8996_vddsscx_vfc,
[MSM8996_VDDCX] = &cx_s1a_corner,
[MSM8996_VDDCX_AO] = &cx_s1a_corner_ao,
[MSM8996_VDDCX_VFC] = &cx_s1a_vfc,
[MSM8996_VDDMX] = &mx_s2a_corner,
[MSM8996_VDDMX_AO] = &mx_s2a_corner_ao,
[MSM8996_VDDSSCX] = &ssc_cx_l26a_corner,
[MSM8996_VDDSSCX_VFC] = &ssc_cx_l26a_vfc,
};
static const struct rpmpd_desc msm8996_desc = {
@ -295,30 +637,17 @@ static const struct rpmpd_desc msm8996_desc = {
.max_state = MAX_CORNER_RPMPD_STATE,
};
/* msm8998 RPM Power domains */
DEFINE_RPMPD_PAIR(msm8998, vddcx, vddcx_ao, RWCX, LEVEL, 0);
DEFINE_RPMPD_VFL(msm8998, vddcx_vfl, RWCX, 0);
DEFINE_RPMPD_PAIR(msm8998, vddmx, vddmx_ao, RWMX, LEVEL, 0);
DEFINE_RPMPD_VFL(msm8998, vddmx_vfl, RWMX, 0);
DEFINE_RPMPD_LEVEL(msm8998, vdd_ssccx, RWSC, 0);
DEFINE_RPMPD_VFL(msm8998, vdd_ssccx_vfl, RWSC, 0);
DEFINE_RPMPD_LEVEL(msm8998, vdd_sscmx, RWSM, 0);
DEFINE_RPMPD_VFL(msm8998, vdd_sscmx_vfl, RWSM, 0);
static struct rpmpd *msm8998_rpmpds[] = {
[MSM8998_VDDCX] = &msm8998_vddcx,
[MSM8998_VDDCX_AO] = &msm8998_vddcx_ao,
[MSM8998_VDDCX_VFL] = &msm8998_vddcx_vfl,
[MSM8998_VDDMX] = &msm8998_vddmx,
[MSM8998_VDDMX_AO] = &msm8998_vddmx_ao,
[MSM8998_VDDMX_VFL] = &msm8998_vddmx_vfl,
[MSM8998_SSCCX] = &msm8998_vdd_ssccx,
[MSM8998_SSCCX_VFL] = &msm8998_vdd_ssccx_vfl,
[MSM8998_SSCMX] = &msm8998_vdd_sscmx,
[MSM8998_SSCMX_VFL] = &msm8998_vdd_sscmx_vfl,
[MSM8998_VDDCX] = &cx_rwcx0_lvl,
[MSM8998_VDDCX_AO] = &cx_rwcx0_lvl_ao,
[MSM8998_VDDCX_VFL] = &cx_rwcx0_vfl,
[MSM8998_VDDMX] = &mx_rwmx0_lvl,
[MSM8998_VDDMX_AO] = &mx_rwmx0_lvl_ao,
[MSM8998_VDDMX_VFL] = &mx_rwmx0_vfl,
[MSM8998_SSCCX] = &ssc_cx_rwsc0_lvl,
[MSM8998_SSCCX_VFL] = &ssc_cx_rwsc0_vfl,
[MSM8998_SSCMX] = &ssc_mx_rwsm0_lvl,
[MSM8998_SSCMX_VFL] = &ssc_mx_rwsm0_vfl,
};
static const struct rpmpd_desc msm8998_desc = {
@ -327,24 +656,14 @@ static const struct rpmpd_desc msm8998_desc = {
.max_state = RPM_SMD_LEVEL_BINNING,
};
/* qcs404 RPM Power domains */
DEFINE_RPMPD_PAIR(qcs404, vddmx, vddmx_ao, RWMX, LEVEL, 0);
DEFINE_RPMPD_VFL(qcs404, vddmx_vfl, RWMX, 0);
DEFINE_RPMPD_LEVEL(qcs404, vdd_lpicx, RWLC, 0);
DEFINE_RPMPD_VFL(qcs404, vdd_lpicx_vfl, RWLC, 0);
DEFINE_RPMPD_LEVEL(qcs404, vdd_lpimx, RWLM, 0);
DEFINE_RPMPD_VFL(qcs404, vdd_lpimx_vfl, RWLM, 0);
static struct rpmpd *qcs404_rpmpds[] = {
[QCS404_VDDMX] = &qcs404_vddmx,
[QCS404_VDDMX_AO] = &qcs404_vddmx_ao,
[QCS404_VDDMX_VFL] = &qcs404_vddmx_vfl,
[QCS404_LPICX] = &qcs404_vdd_lpicx,
[QCS404_LPICX_VFL] = &qcs404_vdd_lpicx_vfl,
[QCS404_LPIMX] = &qcs404_vdd_lpimx,
[QCS404_LPIMX_VFL] = &qcs404_vdd_lpimx_vfl,
[QCS404_VDDMX] = &mx_rwmx0_lvl,
[QCS404_VDDMX_AO] = &mx_rwmx0_lvl_ao,
[QCS404_VDDMX_VFL] = &mx_rwmx0_vfl,
[QCS404_LPICX] = &lpi_cx_rwlc0_lvl,
[QCS404_LPICX_VFL] = &lpi_cx_rwlc0_vfl,
[QCS404_LPIMX] = &lpi_mx_rwlm0_lvl,
[QCS404_LPIMX_VFL] = &lpi_mx_rwlm0_vfl,
};
static const struct rpmpd_desc qcs404_desc = {
@ -353,30 +672,17 @@ static const struct rpmpd_desc qcs404_desc = {
.max_state = RPM_SMD_LEVEL_BINNING,
};
/* sdm660 RPM Power domains */
DEFINE_RPMPD_PAIR(sdm660, vddcx, vddcx_ao, RWCX, LEVEL, 0);
DEFINE_RPMPD_VFL(sdm660, vddcx_vfl, RWCX, 0);
DEFINE_RPMPD_PAIR(sdm660, vddmx, vddmx_ao, RWMX, LEVEL, 0);
DEFINE_RPMPD_VFL(sdm660, vddmx_vfl, RWMX, 0);
DEFINE_RPMPD_LEVEL(sdm660, vdd_ssccx, RWLC, 0);
DEFINE_RPMPD_VFL(sdm660, vdd_ssccx_vfl, RWLC, 0);
DEFINE_RPMPD_LEVEL(sdm660, vdd_sscmx, RWLM, 0);
DEFINE_RPMPD_VFL(sdm660, vdd_sscmx_vfl, RWLM, 0);
static struct rpmpd *sdm660_rpmpds[] = {
[SDM660_VDDCX] = &sdm660_vddcx,
[SDM660_VDDCX_AO] = &sdm660_vddcx_ao,
[SDM660_VDDCX_VFL] = &sdm660_vddcx_vfl,
[SDM660_VDDMX] = &sdm660_vddmx,
[SDM660_VDDMX_AO] = &sdm660_vddmx_ao,
[SDM660_VDDMX_VFL] = &sdm660_vddmx_vfl,
[SDM660_SSCCX] = &sdm660_vdd_ssccx,
[SDM660_SSCCX_VFL] = &sdm660_vdd_ssccx_vfl,
[SDM660_SSCMX] = &sdm660_vdd_sscmx,
[SDM660_SSCMX_VFL] = &sdm660_vdd_sscmx_vfl,
[SDM660_VDDCX] = &cx_rwcx0_lvl,
[SDM660_VDDCX_AO] = &cx_rwcx0_lvl_ao,
[SDM660_VDDCX_VFL] = &cx_rwcx0_vfl,
[SDM660_VDDMX] = &mx_rwmx0_lvl,
[SDM660_VDDMX_AO] = &mx_rwmx0_lvl_ao,
[SDM660_VDDMX_VFL] = &mx_rwmx0_vfl,
[SDM660_SSCCX] = &ssc_cx_rwlc0_lvl,
[SDM660_SSCCX_VFL] = &ssc_cx_rwlc0_vfl,
[SDM660_SSCMX] = &ssc_mx_rwlm0_lvl,
[SDM660_SSCMX_VFL] = &ssc_mx_rwlm0_vfl,
};
static const struct rpmpd_desc sdm660_desc = {
@ -385,25 +691,15 @@ static const struct rpmpd_desc sdm660_desc = {
.max_state = RPM_SMD_LEVEL_TURBO,
};
/* sm4250/6115 RPM Power domains */
DEFINE_RPMPD_PAIR(sm6115, vddcx, vddcx_ao, RWCX, LEVEL, 0);
DEFINE_RPMPD_VFL(sm6115, vddcx_vfl, RWCX, 0);
DEFINE_RPMPD_PAIR(sm6115, vddmx, vddmx_ao, RWMX, LEVEL, 0);
DEFINE_RPMPD_VFL(sm6115, vddmx_vfl, RWMX, 0);
DEFINE_RPMPD_LEVEL(sm6115, vdd_lpi_cx, RWLC, 0);
DEFINE_RPMPD_LEVEL(sm6115, vdd_lpi_mx, RWLM, 0);
static struct rpmpd *sm6115_rpmpds[] = {
[SM6115_VDDCX] = &sm6115_vddcx,
[SM6115_VDDCX_AO] = &sm6115_vddcx_ao,
[SM6115_VDDCX_VFL] = &sm6115_vddcx_vfl,
[SM6115_VDDMX] = &sm6115_vddmx,
[SM6115_VDDMX_AO] = &sm6115_vddmx_ao,
[SM6115_VDDMX_VFL] = &sm6115_vddmx_vfl,
[SM6115_VDD_LPI_CX] = &sm6115_vdd_lpi_cx,
[SM6115_VDD_LPI_MX] = &sm6115_vdd_lpi_mx,
[SM6115_VDDCX] = &cx_rwcx0_lvl,
[SM6115_VDDCX_AO] = &cx_rwcx0_lvl_ao,
[SM6115_VDDCX_VFL] = &cx_rwcx0_vfl,
[SM6115_VDDMX] = &mx_rwmx0_lvl,
[SM6115_VDDMX_AO] = &mx_rwmx0_lvl_ao,
[SM6115_VDDMX_VFL] = &mx_rwmx0_vfl,
[SM6115_VDD_LPI_CX] = &lpi_cx_rwlc0_lvl,
[SM6115_VDD_LPI_MX] = &lpi_mx_rwlm0_lvl,
};
static const struct rpmpd_desc sm6115_desc = {
@ -412,20 +708,13 @@ static const struct rpmpd_desc sm6115_desc = {
.max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
};
/* sm6125 RPM Power domains */
DEFINE_RPMPD_PAIR(sm6125, vddcx, vddcx_ao, RWCX, LEVEL, 0);
DEFINE_RPMPD_VFL(sm6125, vddcx_vfl, RWCX, 0);
DEFINE_RPMPD_PAIR(sm6125, vddmx, vddmx_ao, RWMX, LEVEL, 0);
DEFINE_RPMPD_VFL(sm6125, vddmx_vfl, RWMX, 0);
static struct rpmpd *sm6125_rpmpds[] = {
[SM6125_VDDCX] = &sm6125_vddcx,
[SM6125_VDDCX_AO] = &sm6125_vddcx_ao,
[SM6125_VDDCX_VFL] = &sm6125_vddcx_vfl,
[SM6125_VDDMX] = &sm6125_vddmx,
[SM6125_VDDMX_AO] = &sm6125_vddmx_ao,
[SM6125_VDDMX_VFL] = &sm6125_vddmx_vfl,
[SM6125_VDDCX] = &cx_rwcx0_lvl,
[SM6125_VDDCX_AO] = &cx_rwcx0_lvl_ao,
[SM6125_VDDCX_VFL] = &cx_rwcx0_vfl,
[SM6125_VDDMX] = &mx_rwmx0_lvl,
[SM6125_VDDMX_AO] = &mx_rwmx0_lvl_ao,
[SM6125_VDDMX_VFL] = &mx_rwmx0_vfl,
};
static const struct rpmpd_desc sm6125_desc = {
@ -434,18 +723,17 @@ static const struct rpmpd_desc sm6125_desc = {
.max_state = RPM_SMD_LEVEL_BINNING,
};
DEFINE_RPMPD_PAIR(sm6375, vddgx, vddgx_ao, RWGX, LEVEL, 0);
static struct rpmpd *sm6375_rpmpds[] = {
[SM6375_VDDCX] = &sm6125_vddcx,
[SM6375_VDDCX_AO] = &sm6125_vddcx_ao,
[SM6375_VDDCX_VFL] = &sm6125_vddcx_vfl,
[SM6375_VDDMX] = &sm6125_vddmx,
[SM6375_VDDMX_AO] = &sm6125_vddmx_ao,
[SM6375_VDDMX_VFL] = &sm6125_vddmx_vfl,
[SM6375_VDDGX] = &sm6375_vddgx,
[SM6375_VDDGX_AO] = &sm6375_vddgx_ao,
[SM6375_VDD_LPI_CX] = &sm6115_vdd_lpi_cx,
[SM6375_VDD_LPI_MX] = &sm6115_vdd_lpi_mx,
[SM6375_VDDCX] = &cx_rwcx0_lvl,
[SM6375_VDDCX_AO] = &cx_rwcx0_lvl_ao,
[SM6375_VDDCX_VFL] = &cx_rwcx0_vfl,
[SM6375_VDDMX] = &mx_rwmx0_lvl,
[SM6375_VDDMX_AO] = &mx_rwmx0_lvl_ao,
[SM6375_VDDMX_VFL] = &mx_rwmx0_vfl,
[SM6375_VDDGX] = &gx_rwgx0_lvl,
[SM6375_VDDGX_AO] = &gx_rwgx0_lvl_ao,
[SM6375_VDD_LPI_CX] = &lpi_cx_rwlc0_lvl,
[SM6375_VDD_LPI_MX] = &lpi_mx_rwlm0_lvl,
};
static const struct rpmpd_desc sm6375_desc = {
@ -455,14 +743,14 @@ static const struct rpmpd_desc sm6375_desc = {
};
static struct rpmpd *qcm2290_rpmpds[] = {
[QCM2290_VDDCX] = &sm6115_vddcx,
[QCM2290_VDDCX_AO] = &sm6115_vddcx_ao,
[QCM2290_VDDCX_VFL] = &sm6115_vddcx_vfl,
[QCM2290_VDDMX] = &sm6115_vddmx,
[QCM2290_VDDMX_AO] = &sm6115_vddmx_ao,
[QCM2290_VDDMX_VFL] = &sm6115_vddmx_vfl,
[QCM2290_VDD_LPI_CX] = &sm6115_vdd_lpi_cx,
[QCM2290_VDD_LPI_MX] = &sm6115_vdd_lpi_mx,
[QCM2290_VDDCX] = &cx_rwcx0_lvl,
[QCM2290_VDDCX_AO] = &cx_rwcx0_lvl_ao,
[QCM2290_VDDCX_VFL] = &cx_rwcx0_vfl,
[QCM2290_VDDMX] = &mx_rwmx0_lvl,
[QCM2290_VDDMX_AO] = &mx_rwmx0_lvl_ao,
[QCM2290_VDDMX_VFL] = &mx_rwmx0_vfl,
[QCM2290_VDD_LPI_CX] = &lpi_cx_rwlc0_lvl,
[QCM2290_VDD_LPI_MX] = &lpi_mx_rwlm0_lvl,
};
static const struct rpmpd_desc qcm2290_desc = {
@ -673,6 +961,15 @@ static int rpmpd_probe(struct platform_device *pdev)
data->domains[i] = &rpmpds[i]->pd;
}
/* Add subdomains */
for (i = 0; i < num; i++) {
if (!rpmpds[i])
continue;
if (rpmpds[i]->parent)
pm_genpd_add_subdomain(rpmpds[i]->parent, &rpmpds[i]->pd);
}
return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
}

View File

@ -113,7 +113,7 @@ int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm,
if (WARN_ON(size >= 256))
return -EINVAL;
pkt = kmalloc(size, GFP_KERNEL);
pkt = kmalloc(size, GFP_ATOMIC);
if (!pkt)
return -ENOMEM;

View File

@ -85,7 +85,7 @@
#define SMEM_GLOBAL_HOST 0xfffe
/* Max number of processors/hosts in a system */
#define SMEM_HOST_COUNT 15
#define SMEM_HOST_COUNT 20
/**
* struct smem_proc_comm - proc_comm communication struct (legacy)
@ -1045,7 +1045,7 @@ static int qcom_smem_probe(struct platform_device *pdev)
int i;
num_regions = 1;
if (of_find_property(pdev->dev.of_node, "qcom,rpm-msg-ram", NULL))
if (of_property_present(pdev->dev.of_node, "qcom,rpm-msg-ram"))
num_regions++;
array_size = num_regions * sizeof(struct smem_region);

View File

@ -452,11 +452,10 @@ static int smsm_get_size_info(struct qcom_smsm *smsm)
} *info;
info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_SMSM_SIZE_INFO, &size);
if (IS_ERR(info) && PTR_ERR(info) != -ENOENT) {
if (PTR_ERR(info) != -EPROBE_DEFER)
dev_err(smsm->dev, "unable to retrieve smsm size info\n");
return PTR_ERR(info);
} else if (IS_ERR(info) || size != sizeof(*info)) {
if (IS_ERR(info) && PTR_ERR(info) != -ENOENT)
return dev_err_probe(smsm->dev, PTR_ERR(info),
"unable to retrieve smsm size info\n");
else if (IS_ERR(info) || size != sizeof(*info)) {
dev_warn(smsm->dev, "no smsm size info, using defaults\n");
smsm->num_entries = SMSM_DEFAULT_NUM_ENTRIES;
smsm->num_hosts = SMSM_DEFAULT_NUM_HOSTS;
@ -510,7 +509,7 @@ static int qcom_smsm_probe(struct platform_device *pdev)
return -ENOMEM;
for_each_child_of_node(pdev->dev.of_node, local_node) {
if (of_find_property(local_node, "#qcom,smem-state-cells", NULL))
if (of_property_present(local_node, "#qcom,smem-state-cells"))
break;
}
if (!local_node) {

View File

@ -109,15 +109,20 @@ static const char *const pmic_models[] = {
[32] = "PM8150B",
[33] = "PMK8002",
[36] = "PM8009",
[37] = "PMI632",
[38] = "PM8150C",
[40] = "PM6150",
[41] = "SMB2351",
[44] = "PM8008",
[45] = "PM6125",
[46] = "PM7250B",
[47] = "PMK8350",
[48] = "PM8350",
[49] = "PM8350C",
[50] = "PM8350B",
[51] = "PMR735A",
[52] = "PMR735B",
[55] = "PM2250",
[58] = "PM8450",
[65] = "PM8010",
};
@ -405,6 +410,7 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(SA8155) },
{ qcom_board_id(SDA439) },
{ qcom_board_id(SDA429) },
{ qcom_board_id(SM7150) },
{ qcom_board_id(IPQ8070) },
{ qcom_board_id(IPQ8071) },
{ qcom_board_id(QM215) },
@ -426,6 +432,7 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(QCM2150) },
{ qcom_board_id(SDA429W) },
{ qcom_board_id(SM8350) },
{ qcom_board_id(QCM2290) },
{ qcom_board_id(SM6115) },
{ qcom_board_id(SC8280XP) },
{ qcom_board_id(IPQ6005) },
@ -441,7 +448,16 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(SC7280) },
{ qcom_board_id(SC7180P) },
{ qcom_board_id(SM6375) },
{ qcom_board_id(IPQ9514) },
{ qcom_board_id(IPQ9550) },
{ qcom_board_id(IPQ9554) },
{ qcom_board_id(IPQ9570) },
{ qcom_board_id(IPQ9574) },
{ qcom_board_id(SM8550) },
{ qcom_board_id(IPQ9510) },
{ qcom_board_id(QRB4210) },
{ qcom_board_id(QRB2210) },
{ qcom_board_id(SA8775P) },
{ qcom_board_id(QRU1000) },
{ qcom_board_id(QDU1000) },
{ qcom_board_id(QDU1010) },

View File

@ -206,13 +206,6 @@ config ARCH_R8A77990
This enables support for the Renesas R-Car E3 SoC.
This includes different gradings like R-Car E3e.
config ARCH_R8A77950
bool "ARM64 Platform support for R-Car H3 ES1.x"
select ARCH_RCAR_GEN3
select SYSC_R8A7795
help
This enables support for the Renesas R-Car H3 SoC (revision 1.x).
config ARCH_R8A77951
bool "ARM64 Platform support for R-Car H3 ES2.0+"
select ARCH_RCAR_GEN3

View File

@ -131,7 +131,7 @@ static struct platform_driver rzv2m_pwc_driver = {
.probe = rzv2m_pwc_probe,
.driver = {
.name = "rzv2m_pwc",
.of_match_table = of_match_ptr(rzv2m_pwc_of_match),
.of_match_table = rzv2m_pwc_of_match,
},
};
module_platform_driver(rzv2m_pwc_driver);

View File

@ -38,8 +38,6 @@ static struct rcar_sysc_area r8a7795_areas[] __initdata = {
{ "a3vp", 0x340, 0, R8A7795_PD_A3VP, R8A7795_PD_ALWAYS_ON },
{ "cr7", 0x240, 0, R8A7795_PD_CR7, R8A7795_PD_ALWAYS_ON },
{ "a3vc", 0x380, 0, R8A7795_PD_A3VC, R8A7795_PD_ALWAYS_ON },
/* A2VC0 exists on ES1.x only */
{ "a2vc0", 0x3c0, 0, R8A7795_PD_A2VC0, R8A7795_PD_A3VC },
{ "a2vc1", 0x3c0, 1, R8A7795_PD_A2VC1, R8A7795_PD_A3VC },
{ "3dg-a", 0x100, 0, R8A7795_PD_3DG_A, R8A7795_PD_ALWAYS_ON },
{ "3dg-b", 0x100, 1, R8A7795_PD_3DG_B, R8A7795_PD_3DG_A },
@ -54,14 +52,10 @@ static struct rcar_sysc_area r8a7795_areas[] __initdata = {
* Fixups for R-Car H3 revisions
*/
#define HAS_A2VC0 BIT(0) /* Power domain A2VC0 is present */
#define NO_EXTMASK BIT(1) /* Missing SYSCEXTMASK register */
static const struct soc_device_attribute r8a7795_quirks_match[] __initconst = {
{
.soc_id = "r8a7795", .revision = "ES1.*",
.data = (void *)(HAS_A2VC0 | NO_EXTMASK),
}, {
.soc_id = "r8a7795", .revision = "ES2.*",
.data = (void *)(NO_EXTMASK),
},
@ -77,10 +71,6 @@ static int __init r8a7795_sysc_init(void)
if (attr)
quirks = (uintptr_t)attr->data;
if (!(quirks & HAS_A2VC0))
rcar_sysc_nullify(r8a7795_areas, ARRAY_SIZE(r8a7795_areas),
R8A7795_PD_A2VC0);
if (quirks & NO_EXTMASK)
r8a7795_sysc_info.extmask_val = 0;

View File

@ -269,7 +269,7 @@ static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = {
};
static const struct of_device_id renesas_socs[] __initconst = {
static const struct of_device_id renesas_socs[] __initconst __maybe_unused = {
#ifdef CONFIG_ARCH_R7S72100
{ .compatible = "renesas,r7s72100", .data = &soc_rz_a1h },
#endif
@ -330,10 +330,8 @@ static const struct of_device_id renesas_socs[] __initconst = {
#ifdef CONFIG_ARCH_R8A7794
{ .compatible = "renesas,r8a7794", .data = &soc_rcar_e2 },
#endif
#if defined(CONFIG_ARCH_R8A77950) || defined(CONFIG_ARCH_R8A77951)
{ .compatible = "renesas,r8a7795", .data = &soc_rcar_h3 },
#endif
#ifdef CONFIG_ARCH_R8A77951
{ .compatible = "renesas,r8a7795", .data = &soc_rcar_h3 },
{ .compatible = "renesas,r8a779m0", .data = &soc_rcar_h3 },
{ .compatible = "renesas,r8a779m1", .data = &soc_rcar_h3 },
{ .compatible = "renesas,r8a779m8", .data = &soc_rcar_h3 },
@ -375,20 +373,20 @@ static const struct of_device_id renesas_socs[] __initconst = {
#ifdef CONFIG_ARCH_R8A779G0
{ .compatible = "renesas,r8a779g0", .data = &soc_rcar_v4h },
#endif
#if defined(CONFIG_ARCH_R9A07G043)
#ifdef CONFIG_ARCH_R9A07G043
#ifdef CONFIG_RISCV
{ .compatible = "renesas,r9a07g043", .data = &soc_rz_five },
#else
{ .compatible = "renesas,r9a07g043", .data = &soc_rz_g2ul },
#endif
#endif
#if defined(CONFIG_ARCH_R9A07G044)
#ifdef CONFIG_ARCH_R9A07G044
{ .compatible = "renesas,r9a07g044", .data = &soc_rz_g2l },
#endif
#if defined(CONFIG_ARCH_R9A07G054)
#ifdef CONFIG_ARCH_R9A07G054
{ .compatible = "renesas,r9a07g054", .data = &soc_rz_v2l },
#endif
#if defined(CONFIG_ARCH_R9A09G011)
#ifdef CONFIG_ARCH_R9A09G011
{ .compatible = "renesas,r9a09g011", .data = &soc_rz_v2m },
#endif
#ifdef CONFIG_ARCH_SH73A0
@ -471,8 +469,11 @@ static int __init renesas_soc_init(void)
}
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
if (!soc_dev_attr)
if (!soc_dev_attr) {
if (chipid)
iounmap(chipid);
return -ENOMEM;
}
np = of_find_node_by_path("/");
of_property_read_string(np, "model", &soc_dev_attr->machine);

View File

@ -343,7 +343,7 @@ static int __init rmobile_init_pm_domains(void)
break;
}
fwnode_dev_initialized(&np->fwnode, true);
fwnode_dev_initialized(of_fwnode_handle(np), true);
}
put_special_pds();

View File

@ -82,7 +82,7 @@ static int sunxi_mbus_notifier(struct notifier_block *nb,
* Older DTs or SoCs who are not clearly understood need to set
* that DMA offset though.
*/
if (of_find_property(dev->of_node, "interconnects", NULL))
if (of_property_present(dev->of_node, "interconnects"))
return NOTIFY_DONE;
ret = dma_direct_set_offset(dev, PHYS_OFFSET, 0, SZ_4G);

View File

@ -424,4 +424,3 @@ builtin_platform_driver_probe(sunxi_sram_driver, sunxi_sram_probe);
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
MODULE_DESCRIPTION("Allwinner sunXi SRAM Controller Driver");
MODULE_LICENSE("GPL");

View File

@ -16,7 +16,6 @@
#include <linux/of_address.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/version.h>
#include <soc/tegra/fuse.h>
#include <soc/tegra/tegra-cbb.h>

Some files were not shown because too many files have changed in this diff Show More