mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
Merge tag 'arm-drivers-6.0' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull ARM SoC drivers from Arnd Bergmann:
"The SoC driver updates contain changes to improve support for
additional SoC variants, as well as cleanups an minor bugfixes
in a number of existing drivers.
Notable updates this time include:
- Support for Qualcomm MSM8909 (Snapdragon 210) in various drivers
- Updates for interconnect drivers on Qualcomm Snapdragon
- A new driver support for NMI interrupts on Fujitsu A64fx
- A rework of Broadcom BCMBCA Kconfig dependencies
- Improved support for BCM2711 (Raspberry Pi 4) power management to
allow the use of the V3D GPU
- Cleanups to the NXP guts driver
- Arm SCMI firmware driver updates to add tracing support, and use
the firmware interfaces for system power control and for power
capping"
* tag 'arm-drivers-6.0' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (125 commits)
soc: a64fx-diag: disable modular build
dt-bindings: soc: qcom: qcom,smd-rpm: add power-controller
dt-bindings: soc: qcom: aoss: document qcom,sm8450-aoss-qmp
dt-bindings: soc: qcom,rpmh-rsc: simplify qcom,tcs-config
ARM: mach-qcom: Add support for MSM8909
dt-bindings: arm: cpus: Document "qcom,msm8909-smp" enable-method
soc: qcom: spm: Add CPU data for MSM8909
dt-bindings: soc: qcom: spm: Add MSM8909 CPU compatible
soc: qcom: rpmpd: Add compatible for MSM8909
dt-bindings: power: qcom-rpmpd: Add MSM8909 power domains
soc: qcom: smd-rpm: Add compatible for MSM8909
dt-bindings: soc: qcom: smd-rpm: Add MSM8909
soc: qcom: icc-bwmon: Remove unnecessary print function dev_err()
soc: fujitsu: Add A64FX diagnostic interrupt driver
soc: qcom: socinfo: Fix the id of SA8540P SoC
soc: qcom: Make QCOM_RPMPD depend on PM
tty: serial: bcm63xx: bcmbca: Replace ARCH_BCM_63XX with ARCH_BCMBCA
spi: bcm63xx-hsspi: bcmbca: Replace ARCH_BCM_63XX with ARCH_BCMBCA
clk: bcm: bcmbca: Replace ARCH_BCM_63XX with ARCH_BCMBCA
hwrng: bcm2835: bcmbca: Replace ARCH_BCM_63XX with ARCH_BCMBCA
...
This commit is contained in:
@@ -221,6 +221,7 @@ properties:
|
|||||||
- qcom,kpss-acc-v1
|
- qcom,kpss-acc-v1
|
||||||
- qcom,kpss-acc-v2
|
- qcom,kpss-acc-v2
|
||||||
- qcom,msm8226-smp
|
- qcom,msm8226-smp
|
||||||
|
- qcom,msm8909-smp
|
||||||
# Only valid on ARM 32-bit, see above for ARM v8 64-bit
|
# Only valid on ARM 32-bit, see above for ARM v8 64-bit
|
||||||
- qcom,msm8916-smp
|
- qcom,msm8916-smp
|
||||||
- renesas,apmu
|
- renesas,apmu
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
|||||||
title: QCOM device tree bindings
|
title: QCOM device tree bindings
|
||||||
|
|
||||||
maintainers:
|
maintainers:
|
||||||
- Stephen Boyd <sboyd@codeaurora.org>
|
- Bjorn Andersson <bjorn.andersson@linaro.org>
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Some qcom based bootloaders identify the dtb blob based on a set of
|
Some qcom based bootloaders identify the dtb blob based on a set of
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: "http://devicetree.org/schemas/arm/tegra/nvidia,tegra194-axi2apb.yaml#"
|
||||||
|
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||||
|
|
||||||
|
title: NVIDIA Tegra194 AXI2APB bridge
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Sumit Gupta <sumitg@nvidia.com>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
$nodename:
|
||||||
|
pattern: "^axi2apb@([0-9a-f]+)$"
|
||||||
|
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- nvidia,tegra194-axi2apb
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 6
|
||||||
|
description: Physical base address and length of registers for all bridges
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
axi2apb: axi2apb@2390000 {
|
||||||
|
compatible = "nvidia,tegra194-axi2apb";
|
||||||
|
reg = <0x02390000 0x1000>,
|
||||||
|
<0x023a0000 0x1000>,
|
||||||
|
<0x023b0000 0x1000>,
|
||||||
|
<0x023c0000 0x1000>,
|
||||||
|
<0x023d0000 0x1000>,
|
||||||
|
<0x023e0000 0x1000>;
|
||||||
|
};
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: "http://devicetree.org/schemas/arm/tegra/nvidia,tegra194-cbb.yaml#"
|
||||||
|
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||||
|
|
||||||
|
title: NVIDIA Tegra194 CBB 1.0 bindings
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Sumit Gupta <sumitg@nvidia.com>
|
||||||
|
|
||||||
|
description: |+
|
||||||
|
The Control Backbone (CBB) is comprised of the physical path from an
|
||||||
|
initiator to a target's register configuration space. CBB 1.0 has
|
||||||
|
multiple hierarchical sub-NOCs (Network-on-Chip) and connects various
|
||||||
|
initiators and targets using different bridges like AXIP2P, AXI2APB.
|
||||||
|
|
||||||
|
This driver handles errors due to illegal register accesses reported
|
||||||
|
by the NOCs inside the CBB. NOCs reporting errors are cluster NOCs
|
||||||
|
"AON-NOC, SCE-NOC, RCE-NOC, BPMP-NOC, CV-NOC" and "CBB Central NOC"
|
||||||
|
which is the main NOC.
|
||||||
|
|
||||||
|
By default, the access issuing initiator is informed about the error
|
||||||
|
using SError or Data Abort exception unless the ERD (Error Response
|
||||||
|
Disable) is enabled/set for that initiator. If the ERD is enabled, then
|
||||||
|
SError or Data Abort is masked and the error is reported with interrupt.
|
||||||
|
|
||||||
|
- For CCPLEX (CPU Complex) initiator, the driver sets ERD bit. So, the
|
||||||
|
errors due to illegal accesses from CCPLEX are reported by interrupts.
|
||||||
|
If ERD is not set, then error is reported by SError.
|
||||||
|
- For other initiators, the ERD is disabled. So, the access issuing
|
||||||
|
initiator is informed about the illegal access by Data Abort exception.
|
||||||
|
In addition, an interrupt is also generated to CCPLEX. These initiators
|
||||||
|
include all engines using Cortex-R5 (which is ARMv7 CPU cluster) and
|
||||||
|
engines like TSEC (Security co-processor), NVDEC (NVIDIA Video Decoder
|
||||||
|
engine) etc which can initiate transactions.
|
||||||
|
|
||||||
|
The driver prints relevant debug information like Error Code, Error
|
||||||
|
Description, Master, Address, AXI ID, Cache, Protection, Security Group
|
||||||
|
etc on receiving error notification.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
$nodename:
|
||||||
|
pattern: "^[a-z]+-noc@[0-9a-f]+$"
|
||||||
|
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- nvidia,tegra194-cbb-noc
|
||||||
|
- nvidia,tegra194-aon-noc
|
||||||
|
- nvidia,tegra194-bpmp-noc
|
||||||
|
- nvidia,tegra194-rce-noc
|
||||||
|
- nvidia,tegra194-sce-noc
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
description:
|
||||||
|
CCPLEX receives secure or nonsecure interrupt depending on error type.
|
||||||
|
A secure interrupt is received for SEC(firewall) & SLV errors and a
|
||||||
|
non-secure interrupt is received for TMO & DEC errors.
|
||||||
|
items:
|
||||||
|
- description: non-secure interrupt
|
||||||
|
- description: secure interrupt
|
||||||
|
|
||||||
|
nvidia,axi2apb:
|
||||||
|
$ref: '/schemas/types.yaml#/definitions/phandle'
|
||||||
|
description:
|
||||||
|
Specifies the node having all axi2apb bridges which need to be checked
|
||||||
|
for any error logged in their status register.
|
||||||
|
|
||||||
|
nvidia,apbmisc:
|
||||||
|
$ref: '/schemas/types.yaml#/definitions/phandle'
|
||||||
|
description:
|
||||||
|
Specifies the apbmisc node which need to be used for reading the ERD
|
||||||
|
register.
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- nvidia,apbmisc
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
|
||||||
|
cbb-noc@2300000 {
|
||||||
|
compatible = "nvidia,tegra194-cbb-noc";
|
||||||
|
reg = <0x02300000 0x1000>;
|
||||||
|
interrupts = <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
nvidia,axi2apb = <&axi2apb>;
|
||||||
|
nvidia,apbmisc = <&apbmisc>;
|
||||||
|
};
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: "http://devicetree.org/schemas/arm/tegra/nvidia,tegra234-cbb.yaml#"
|
||||||
|
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||||
|
|
||||||
|
title: NVIDIA Tegra CBB 2.0 bindings
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Sumit Gupta <sumitg@nvidia.com>
|
||||||
|
|
||||||
|
description: |+
|
||||||
|
The Control Backbone (CBB) is comprised of the physical path from an
|
||||||
|
initiator to a target's register configuration space. CBB 2.0 consists
|
||||||
|
of multiple sub-blocks connected to each other to create a topology.
|
||||||
|
The Tegra234 SoC has different fabrics based on CBB 2.0 architecture
|
||||||
|
which include cluster fabrics BPMP, AON, PSC, SCE, RCE, DCE, FSI and
|
||||||
|
"CBB central fabric".
|
||||||
|
|
||||||
|
In CBB 2.0, each initiator which can issue transactions connects to a
|
||||||
|
Root Master Node (MN) before it connects to any other element of the
|
||||||
|
fabric. Each Root MN contains a Error Monitor (EM) which detects and
|
||||||
|
logs error. Interrupts from various EM blocks are collated by Error
|
||||||
|
Notifier (EN) which is per fabric and presents a single interrupt from
|
||||||
|
fabric to the SoC interrupt controller.
|
||||||
|
|
||||||
|
The driver handles errors from CBB due to illegal register accesses
|
||||||
|
and prints debug information about failed transaction on receiving
|
||||||
|
the interrupt from EN. Debug information includes Error Code, Error
|
||||||
|
Description, MasterID, Fabric, SlaveID, Address, Cache, Protection,
|
||||||
|
Security Group etc on receiving error notification.
|
||||||
|
|
||||||
|
If the Error Response Disable (ERD) is set/enabled for an initiator,
|
||||||
|
then SError or Data abort exception error response is masked and an
|
||||||
|
interrupt is used for reporting errors due to illegal accesses from
|
||||||
|
that initiator. The value returned on read failures is '0xFFFFFFFF'
|
||||||
|
for compatibility with PCIE.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
$nodename:
|
||||||
|
pattern: "^[a-z]+-fabric@[0-9a-f]+$"
|
||||||
|
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- nvidia,tegra234-aon-fabric
|
||||||
|
- nvidia,tegra234-bpmp-fabric
|
||||||
|
- nvidia,tegra234-cbb-fabric
|
||||||
|
- nvidia,tegra234-dce-fabric
|
||||||
|
- nvidia,tegra234-rce-fabric
|
||||||
|
- nvidia,tegra234-sce-fabric
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
items:
|
||||||
|
- description: secure interrupt from error notifier
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
|
||||||
|
cbb-fabric@1300000 {
|
||||||
|
compatible = "nvidia,tegra234-cbb-fabric";
|
||||||
|
reg = <0x13a00000 0x400000>;
|
||||||
|
interrupts = <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
};
|
||||||
@@ -183,6 +183,12 @@ properties:
|
|||||||
required:
|
required:
|
||||||
- reg
|
- reg
|
||||||
|
|
||||||
|
protocol@18:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
const: 0x18
|
||||||
|
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
|
||||||
patternProperties:
|
patternProperties:
|
||||||
@@ -323,6 +329,10 @@ examples:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
scmi_powercap: protocol@18 {
|
||||||
|
reg = <0x18>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -23,10 +23,13 @@ Required properties:
|
|||||||
* "qcom,scm-msm8994"
|
* "qcom,scm-msm8994"
|
||||||
* "qcom,scm-msm8996"
|
* "qcom,scm-msm8996"
|
||||||
* "qcom,scm-msm8998"
|
* "qcom,scm-msm8998"
|
||||||
|
* "qcom,scm-qcs404"
|
||||||
* "qcom,scm-sc7180"
|
* "qcom,scm-sc7180"
|
||||||
* "qcom,scm-sc7280"
|
* "qcom,scm-sc7280"
|
||||||
|
* "qcom,scm-sm6125"
|
||||||
* "qcom,scm-sdm845"
|
* "qcom,scm-sdm845"
|
||||||
* "qcom,scm-sdx55"
|
* "qcom,scm-sdx55"
|
||||||
|
* "qcom,scm-sdx65"
|
||||||
* "qcom,scm-sm6350"
|
* "qcom,scm-sm6350"
|
||||||
* "qcom,scm-sm8150"
|
* "qcom,scm-sm8150"
|
||||||
* "qcom,scm-sm8250"
|
* "qcom,scm-sm8250"
|
||||||
@@ -43,6 +46,7 @@ Required properties:
|
|||||||
clock and "bus" for the bus clock per the requirements of the compatible.
|
clock and "bus" for the bus clock per the requirements of the compatible.
|
||||||
- qcom,dload-mode: phandle to the TCSR hardware block and offset of the
|
- qcom,dload-mode: phandle to the TCSR hardware block and offset of the
|
||||||
download mode control register (optional)
|
download mode control register (optional)
|
||||||
|
- interconnects: Specifies the bandwidth requirements of the SCM interface (optional)
|
||||||
|
|
||||||
Example for MSM8916:
|
Example for MSM8916:
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/interconnect/qcom,msm8998-bwmon.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Qualcomm Interconnect Bandwidth Monitor
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
Bandwidth Monitor measures current throughput on buses between various NoC
|
||||||
|
fabrics and provides information when it crosses configured thresholds.
|
||||||
|
|
||||||
|
Certain SoCs might have more than one Bandwidth Monitors, for example on SDM845::
|
||||||
|
- Measuring the bandwidth between CPUs and Last Level Cache Controller -
|
||||||
|
called just BWMON,
|
||||||
|
- Measuring the bandwidth between Last Level Cache Controller and memory
|
||||||
|
(DDR) - called LLCC BWMON.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- qcom,sdm845-bwmon
|
||||||
|
- const: qcom,msm8998-bwmon
|
||||||
|
- const: qcom,msm8998-bwmon # BWMON v4
|
||||||
|
|
||||||
|
interconnects:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
operating-points-v2: true
|
||||||
|
opp-table: true
|
||||||
|
|
||||||
|
reg:
|
||||||
|
# BWMON v4 (currently described) and BWMON v5 use one register address
|
||||||
|
# space. BWMON v2 uses two register spaces - not yet described.
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- interconnects
|
||||||
|
- interrupts
|
||||||
|
- operating-points-v2
|
||||||
|
- opp-table
|
||||||
|
- reg
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interconnect/qcom,sdm845.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
|
||||||
|
pmu@1436400 {
|
||||||
|
compatible = "qcom,sdm845-bwmon", "qcom,msm8998-bwmon";
|
||||||
|
reg = <0x01436400 0x600>;
|
||||||
|
interrupts = <GIC_SPI 581 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_LLCC 3>;
|
||||||
|
|
||||||
|
operating-points-v2 = <&cpu_bwmon_opp_table>;
|
||||||
|
|
||||||
|
cpu_bwmon_opp_table: opp-table {
|
||||||
|
compatible = "operating-points-v2";
|
||||||
|
opp-0 {
|
||||||
|
opp-peak-kBps = <4800000>;
|
||||||
|
};
|
||||||
|
opp-1 {
|
||||||
|
opp-peak-kBps = <9216000>;
|
||||||
|
};
|
||||||
|
opp-2 {
|
||||||
|
opp-peak-kBps = <15052800>;
|
||||||
|
};
|
||||||
|
opp-3 {
|
||||||
|
opp-peak-kBps = <20889600>;
|
||||||
|
};
|
||||||
|
opp-4 {
|
||||||
|
opp-peak-kBps = <25497600>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -32,6 +32,7 @@ properties:
|
|||||||
- mediatek,mt2701-smi-common
|
- mediatek,mt2701-smi-common
|
||||||
- mediatek,mt2712-smi-common
|
- mediatek,mt2712-smi-common
|
||||||
- mediatek,mt6779-smi-common
|
- mediatek,mt6779-smi-common
|
||||||
|
- mediatek,mt6795-smi-common
|
||||||
- mediatek,mt8167-smi-common
|
- mediatek,mt8167-smi-common
|
||||||
- mediatek,mt8173-smi-common
|
- mediatek,mt8173-smi-common
|
||||||
- mediatek,mt8183-smi-common
|
- mediatek,mt8183-smi-common
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ properties:
|
|||||||
- mediatek,mt2701-smi-larb
|
- mediatek,mt2701-smi-larb
|
||||||
- mediatek,mt2712-smi-larb
|
- mediatek,mt2712-smi-larb
|
||||||
- mediatek,mt6779-smi-larb
|
- mediatek,mt6779-smi-larb
|
||||||
|
- mediatek,mt6795-smi-larb
|
||||||
- mediatek,mt8167-smi-larb
|
- mediatek,mt8167-smi-larb
|
||||||
- mediatek,mt8173-smi-larb
|
- mediatek,mt8173-smi-larb
|
||||||
- mediatek,mt8183-smi-larb
|
- mediatek,mt8183-smi-larb
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ properties:
|
|||||||
|
|
||||||
compatible:
|
compatible:
|
||||||
enum:
|
enum:
|
||||||
|
- mediatek,mt6795-power-controller
|
||||||
- mediatek,mt8167-power-controller
|
- mediatek,mt8167-power-controller
|
||||||
- mediatek,mt8173-power-controller
|
- mediatek,mt8173-power-controller
|
||||||
- mediatek,mt8183-power-controller
|
- mediatek,mt8183-power-controller
|
||||||
@@ -62,6 +63,7 @@ patternProperties:
|
|||||||
reg:
|
reg:
|
||||||
description: |
|
description: |
|
||||||
Power domain index. Valid values are defined in:
|
Power domain index. Valid values are defined in:
|
||||||
|
"include/dt-bindings/power/mt6795-power.h" - for MT8167 type power domain.
|
||||||
"include/dt-bindings/power/mt8167-power.h" - for MT8167 type power domain.
|
"include/dt-bindings/power/mt8167-power.h" - for MT8167 type power domain.
|
||||||
"include/dt-bindings/power/mt8173-power.h" - for MT8173 type power domain.
|
"include/dt-bindings/power/mt8173-power.h" - for MT8173 type power domain.
|
||||||
"include/dt-bindings/power/mt8183-power.h" - for MT8183 type power domain.
|
"include/dt-bindings/power/mt8183-power.h" - for MT8183 type power domain.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ properties:
|
|||||||
enum:
|
enum:
|
||||||
- qcom,mdm9607-rpmpd
|
- qcom,mdm9607-rpmpd
|
||||||
- qcom,msm8226-rpmpd
|
- qcom,msm8226-rpmpd
|
||||||
|
- qcom,msm8909-rpmpd
|
||||||
- qcom,msm8916-rpmpd
|
- qcom,msm8916-rpmpd
|
||||||
- qcom,msm8939-rpmpd
|
- qcom,msm8939-rpmpd
|
||||||
- qcom,msm8953-rpmpd
|
- qcom,msm8953-rpmpd
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ properties:
|
|||||||
compatible:
|
compatible:
|
||||||
enum:
|
enum:
|
||||||
- mediatek,mt6779-devapc
|
- mediatek,mt6779-devapc
|
||||||
|
- mediatek,mt8186-devapc
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
description: The base address of devapc register bank
|
description: The base address of devapc register bank
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
%YAML 1.2
|
%YAML 1.2
|
||||||
---
|
---
|
||||||
$id: http://devicetree.org/schemas/display/mediatek/mediatek,mutex.yaml#
|
$id: http://devicetree.org/schemas/soc/mediatek/mediatek,mutex.yaml#
|
||||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
title: Mediatek mutex
|
title: Mediatek mutex
|
||||||
@@ -55,6 +55,18 @@ properties:
|
|||||||
include/dt-bindings/gce/<chip>-gce.h of each chips.
|
include/dt-bindings/gce/<chip>-gce.h of each chips.
|
||||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||||
|
|
||||||
|
mediatek,gce-client-reg:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||||
|
items:
|
||||||
|
items:
|
||||||
|
- description: phandle of GCE
|
||||||
|
- description: GCE subsys id
|
||||||
|
- description: register offset
|
||||||
|
- description: register size
|
||||||
|
description: The register of client driver can be configured by gce with
|
||||||
|
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.
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reg
|
- reg
|
||||||
91
Documentation/devicetree/bindings/soc/mediatek/mtk-svs.yaml
Normal file
91
Documentation/devicetree/bindings/soc/mediatek/mtk-svs.yaml
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/soc/mediatek/mtk-svs.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: MediaTek Smart Voltage Scaling (SVS) Device Tree Bindings
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Roger Lu <roger.lu@mediatek.com>
|
||||||
|
- Matthias Brugger <matthias.bgg@gmail.com>
|
||||||
|
- Kevin Hilman <khilman@kernel.org>
|
||||||
|
|
||||||
|
description: |+
|
||||||
|
The SVS engine is a piece of hardware which has several
|
||||||
|
controllers(banks) for calculating suitable voltage to
|
||||||
|
different power domains(CPU/GPU/CCI) according to
|
||||||
|
chip process corner, temperatures and other factors. Then DVFS
|
||||||
|
driver could apply SVS bank voltage to PMIC/Buck.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- mediatek,mt8183-svs
|
||||||
|
- mediatek,mt8192-svs
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
description: Address range of the MTK SVS controller.
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
description: Main clock for MTK SVS controller to work.
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
const: main
|
||||||
|
|
||||||
|
nvmem-cells:
|
||||||
|
minItems: 1
|
||||||
|
description:
|
||||||
|
Phandle to the calibration data provided by a nvmem device.
|
||||||
|
items:
|
||||||
|
- description: SVS efuse for SVS controller
|
||||||
|
- description: Thermal efuse for SVS controller
|
||||||
|
|
||||||
|
nvmem-cell-names:
|
||||||
|
items:
|
||||||
|
- const: svs-calibration-data
|
||||||
|
- const: t-calibration-data
|
||||||
|
|
||||||
|
resets:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
reset-names:
|
||||||
|
items:
|
||||||
|
- const: svs_rst
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
- nvmem-cells
|
||||||
|
- nvmem-cell-names
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/clock/mt8183-clk.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
|
||||||
|
soc {
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <2>;
|
||||||
|
|
||||||
|
svs@1100b000 {
|
||||||
|
compatible = "mediatek,mt8183-svs";
|
||||||
|
reg = <0 0x1100b000 0 0x1000>;
|
||||||
|
interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_LOW>;
|
||||||
|
clocks = <&infracfg CLK_INFRA_THERM>;
|
||||||
|
clock-names = "main";
|
||||||
|
nvmem-cells = <&svs_calibration>, <&thermal_calibration>;
|
||||||
|
nvmem-cell-names = "svs-calibration-data", "t-calibration-data";
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -33,6 +33,7 @@ properties:
|
|||||||
- qcom,sm8150-aoss-qmp
|
- qcom,sm8150-aoss-qmp
|
||||||
- qcom,sm8250-aoss-qmp
|
- qcom,sm8250-aoss-qmp
|
||||||
- qcom,sm8350-aoss-qmp
|
- qcom,sm8350-aoss-qmp
|
||||||
|
- qcom,sm8450-aoss-qmp
|
||||||
- const: qcom,aoss-qmp
|
- const: qcom,aoss-qmp
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
|
|||||||
@@ -65,33 +65,22 @@ properties:
|
|||||||
|
|
||||||
qcom,tcs-config:
|
qcom,tcs-config:
|
||||||
$ref: /schemas/types.yaml#/definitions/uint32-matrix
|
$ref: /schemas/types.yaml#/definitions/uint32-matrix
|
||||||
|
minItems: 4
|
||||||
|
maxItems: 4
|
||||||
items:
|
items:
|
||||||
- items:
|
items:
|
||||||
- description: TCS type
|
- description: |
|
||||||
enum: [ 0, 1, 2, 3 ]
|
TCS type::
|
||||||
- description: Number of TCS
|
- ACTIVE_TCS
|
||||||
- items:
|
- SLEEP_TCS
|
||||||
- description: TCS type
|
- WAKE_TCS
|
||||||
enum: [ 0, 1, 2, 3 ]
|
- CONTROL_TCS
|
||||||
- description: Number of TCS
|
enum: [ 0, 1, 2, 3 ]
|
||||||
- items:
|
- description: Number of TCS
|
||||||
- description: TCS type
|
|
||||||
enum: [ 0, 1, 2, 3]
|
|
||||||
- description: Numbe r of TCS
|
|
||||||
- items:
|
|
||||||
- description: TCS type
|
|
||||||
enum: [ 0, 1, 2, 3 ]
|
|
||||||
- description: Number of TCS
|
|
||||||
description: |
|
description: |
|
||||||
The tuple defining the configuration of TCS. Must have two cells which
|
The tuple defining the configuration of TCS. Must have two cells which
|
||||||
describe each TCS type. The order of the TCS must match the hardware
|
describe each TCS type. The order of the TCS must match the hardware
|
||||||
configuration.
|
configuration.
|
||||||
Cell 1 (TCS Type):: TCS types to be specified::
|
|
||||||
- ACTIVE_TCS
|
|
||||||
- SLEEP_TCS
|
|
||||||
- WAKE_TCS
|
|
||||||
- CONTROL_TCS
|
|
||||||
Cell 2 (Number of TCS):: <u32>
|
|
||||||
|
|
||||||
qcom,tcs-offset:
|
qcom,tcs-offset:
|
||||||
$ref: /schemas/types.yaml#/definitions/uint32
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ properties:
|
|||||||
- qcom,rpm-apq8084
|
- qcom,rpm-apq8084
|
||||||
- qcom,rpm-ipq6018
|
- qcom,rpm-ipq6018
|
||||||
- qcom,rpm-msm8226
|
- qcom,rpm-msm8226
|
||||||
|
- qcom,rpm-msm8909
|
||||||
- qcom,rpm-msm8916
|
- qcom,rpm-msm8916
|
||||||
- qcom,rpm-msm8936
|
- qcom,rpm-msm8936
|
||||||
- qcom,rpm-msm8953
|
- qcom,rpm-msm8953
|
||||||
@@ -51,6 +52,9 @@ properties:
|
|||||||
$ref: /schemas/clock/qcom,rpmcc.yaml#
|
$ref: /schemas/clock/qcom,rpmcc.yaml#
|
||||||
unevaluatedProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
|
power-controller:
|
||||||
|
$ref: /schemas/power/qcom,rpmpd.yaml#
|
||||||
|
|
||||||
qcom,smd-channels:
|
qcom,smd-channels:
|
||||||
$ref: /schemas/types.yaml#/definitions/string-array
|
$ref: /schemas/types.yaml#/definitions/string-array
|
||||||
description: Channel name used for the RPM communication
|
description: Channel name used for the RPM communication
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ properties:
|
|||||||
- qcom,sdm660-silver-saw2-v4.1-l2
|
- qcom,sdm660-silver-saw2-v4.1-l2
|
||||||
- qcom,msm8998-gold-saw2-v4.1-l2
|
- qcom,msm8998-gold-saw2-v4.1-l2
|
||||||
- qcom,msm8998-silver-saw2-v4.1-l2
|
- qcom,msm8998-silver-saw2-v4.1-l2
|
||||||
|
- qcom,msm8909-saw2-v3.0-cpu
|
||||||
- qcom,msm8916-saw2-v3.0-cpu
|
- qcom,msm8916-saw2-v3.0-cpu
|
||||||
- qcom,msm8226-saw2-v2.1-cpu
|
- qcom,msm8226-saw2-v2.1-cpu
|
||||||
- qcom,msm8974-saw2-v2.1-cpu
|
- qcom,msm8974-saw2-v2.1-cpu
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ properties:
|
|||||||
Should reference the tx-enable and tx-rings-empty SMEM states.
|
Should reference the tx-enable and tx-rings-empty SMEM states.
|
||||||
|
|
||||||
qcom,smem-state-names:
|
qcom,smem-state-names:
|
||||||
$ref: /schemas/types.yaml#/definitions/string-array
|
|
||||||
items:
|
items:
|
||||||
- const: tx-enable
|
- const: tx-enable
|
||||||
- const: tx-rings-empty
|
- const: tx-rings-empty
|
||||||
|
|||||||
@@ -65,10 +65,11 @@ properties:
|
|||||||
- ti,am4376-pruss0 # for AM437x SoC family and PRUSS unit 0
|
- ti,am4376-pruss0 # for AM437x SoC family and PRUSS unit 0
|
||||||
- ti,am4376-pruss1 # for AM437x SoC family and PRUSS unit 1
|
- ti,am4376-pruss1 # for AM437x SoC family and PRUSS unit 1
|
||||||
- ti,am5728-pruss # for AM57xx SoC family
|
- ti,am5728-pruss # for AM57xx SoC family
|
||||||
- ti,k2g-pruss # for 66AK2G SoC family
|
- ti,am625-pruss # for K3 AM62x SoC family
|
||||||
|
- ti,am642-icssg # for K3 AM64x SoC family
|
||||||
- ti,am654-icssg # for K3 AM65x SoC family
|
- ti,am654-icssg # for K3 AM65x SoC family
|
||||||
- ti,j721e-icssg # for K3 J721E SoC family
|
- ti,j721e-icssg # for K3 J721E SoC family
|
||||||
- ti,am642-icssg # for K3 AM64x SoC family
|
- ti,k2g-pruss # for 66AK2G SoC family
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|||||||
12
MAINTAINERS
12
MAINTAINERS
@@ -242,6 +242,11 @@ F: include/trace/events/9p.h
|
|||||||
F: include/uapi/linux/virtio_9p.h
|
F: include/uapi/linux/virtio_9p.h
|
||||||
F: net/9p/
|
F: net/9p/
|
||||||
|
|
||||||
|
A64FX DIAG DRIVER
|
||||||
|
M: Hitomi Hasegawa <hasegawa-hitomi@fujitsu.com>
|
||||||
|
S: Supported
|
||||||
|
F: drivers/soc/fujitsu/a64fx-diag.c
|
||||||
|
|
||||||
A8293 MEDIA DRIVER
|
A8293 MEDIA DRIVER
|
||||||
M: Antti Palosaari <crope@iki.fi>
|
M: Antti Palosaari <crope@iki.fi>
|
||||||
L: linux-media@vger.kernel.org
|
L: linux-media@vger.kernel.org
|
||||||
@@ -16674,6 +16679,13 @@ S: Maintained
|
|||||||
F: Documentation/devicetree/bindings/i2c/i2c-qcom-cci.txt
|
F: Documentation/devicetree/bindings/i2c/i2c-qcom-cci.txt
|
||||||
F: drivers/i2c/busses/i2c-qcom-cci.c
|
F: drivers/i2c/busses/i2c-qcom-cci.c
|
||||||
|
|
||||||
|
QUALCOMM INTERCONNECT BWMON DRIVER
|
||||||
|
M: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
|
||||||
|
L: linux-arm-msm@vger.kernel.org
|
||||||
|
S: Maintained
|
||||||
|
F: Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml
|
||||||
|
F: drivers/soc/qcom/icc-bwmon.c
|
||||||
|
|
||||||
QUALCOMM IOMMU
|
QUALCOMM IOMMU
|
||||||
M: Rob Clark <robdclark@gmail.com>
|
M: Rob Clark <robdclark@gmail.com>
|
||||||
L: iommu@lists.linux.dev
|
L: iommu@lists.linux.dev
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ config ARCH_MSM8X60
|
|||||||
bool "Enable support for MSM8X60"
|
bool "Enable support for MSM8X60"
|
||||||
select CLKSRC_QCOM
|
select CLKSRC_QCOM
|
||||||
|
|
||||||
|
config ARCH_MSM8909
|
||||||
|
bool "Enable support for MSM8909"
|
||||||
|
select HAVE_ARM_ARCH_TIMER
|
||||||
|
|
||||||
config ARCH_MSM8916
|
config ARCH_MSM8916
|
||||||
bool "Enable support for MSM8916"
|
bool "Enable support for MSM8916"
|
||||||
select HAVE_ARM_ARCH_TIMER
|
select HAVE_ARM_ARCH_TIMER
|
||||||
|
|||||||
@@ -384,6 +384,7 @@ static const struct smp_operations qcom_smp_cortex_a7_ops __initconst = {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
CPU_METHOD_OF_DECLARE(qcom_smp_msm8226, "qcom,msm8226-smp", &qcom_smp_cortex_a7_ops);
|
CPU_METHOD_OF_DECLARE(qcom_smp_msm8226, "qcom,msm8226-smp", &qcom_smp_cortex_a7_ops);
|
||||||
|
CPU_METHOD_OF_DECLARE(qcom_smp_msm8909, "qcom,msm8909-smp", &qcom_smp_cortex_a7_ops);
|
||||||
CPU_METHOD_OF_DECLARE(qcom_smp_msm8916, "qcom,msm8916-smp", &qcom_smp_cortex_a7_ops);
|
CPU_METHOD_OF_DECLARE(qcom_smp_msm8916, "qcom,msm8916-smp", &qcom_smp_cortex_a7_ops);
|
||||||
|
|
||||||
static const struct smp_operations qcom_smp_kpssv1_ops __initconst = {
|
static const struct smp_operations qcom_smp_kpssv1_ops __initconst = {
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ config SATA_AHCI_PLATFORM
|
|||||||
config AHCI_BRCM
|
config AHCI_BRCM
|
||||||
tristate "Broadcom AHCI SATA support"
|
tristate "Broadcom AHCI SATA support"
|
||||||
depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_NSP || \
|
depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_NSP || \
|
||||||
ARCH_BCM_63XX || COMPILE_TEST
|
ARCH_BCMBCA || COMPILE_TEST
|
||||||
select SATA_HOST
|
select SATA_HOST
|
||||||
help
|
help
|
||||||
This option enables support for the AHCI SATA3 controller found on
|
This option enables support for the AHCI SATA3 controller found on
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ config HW_RANDOM_BA431
|
|||||||
config HW_RANDOM_BCM2835
|
config HW_RANDOM_BCM2835
|
||||||
tristate "Broadcom BCM2835/BCM63xx Random Number Generator support"
|
tristate "Broadcom BCM2835/BCM63xx Random Number Generator support"
|
||||||
depends on ARCH_BCM2835 || ARCH_BCM_NSP || ARCH_BCM_5301X || \
|
depends on ARCH_BCM2835 || ARCH_BCM_NSP || ARCH_BCM_5301X || \
|
||||||
ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC || COMPILE_TEST
|
ARCH_BCMBCA || BCM63XX || BMIPS_GENERIC || COMPILE_TEST
|
||||||
default HW_RANDOM
|
default HW_RANDOM
|
||||||
help
|
help
|
||||||
This driver provides kernel-side support for the Random Number
|
This driver provides kernel-side support for the Random Number
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ config CLK_BCM2835
|
|||||||
|
|
||||||
config CLK_BCM_63XX
|
config CLK_BCM_63XX
|
||||||
bool "Broadcom BCM63xx clock support"
|
bool "Broadcom BCM63xx clock support"
|
||||||
depends on ARCH_BCM_63XX || COMPILE_TEST
|
depends on ARCH_BCMBCA || COMPILE_TEST
|
||||||
select COMMON_CLK_IPROC
|
select COMMON_CLK_IPROC
|
||||||
default ARCH_BCM_63XX
|
default ARCH_BCMBCA
|
||||||
help
|
help
|
||||||
Enable common clock framework support for Broadcom BCM63xx DSL SoCs
|
Enable common clock framework support for Broadcom BCM63xx DSL SoCs
|
||||||
based on the ARM architecture
|
based on the ARM architecture
|
||||||
|
|||||||
@@ -149,4 +149,16 @@ config ARM_SCMI_POWER_DOMAIN
|
|||||||
will be called scmi_pm_domain. Note this may needed early in boot
|
will be called scmi_pm_domain. Note this may needed early in boot
|
||||||
before rootfs may be available.
|
before rootfs may be available.
|
||||||
|
|
||||||
|
config ARM_SCMI_POWER_CONTROL
|
||||||
|
tristate "SCMI system power control driver"
|
||||||
|
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
|
||||||
|
help
|
||||||
|
This enables System Power control logic which binds system shutdown or
|
||||||
|
reboot actions to SCMI System Power notifications generated by SCP
|
||||||
|
firmware.
|
||||||
|
|
||||||
|
This driver can also be built as a module. If so, the module will be
|
||||||
|
called scmi_power_control. Note this may needed early in boot to catch
|
||||||
|
early shutdown/reboot SCMI requests.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|||||||
@@ -7,11 +7,12 @@ scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += smc.o
|
|||||||
scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.o
|
scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.o
|
||||||
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += virtio.o
|
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += virtio.o
|
||||||
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += optee.o
|
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += optee.o
|
||||||
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o
|
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o powercap.o
|
||||||
scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \
|
scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \
|
||||||
$(scmi-transport-y)
|
$(scmi-transport-y)
|
||||||
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o
|
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o
|
||||||
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
|
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
|
||||||
|
obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) += scmi_power_control.o
|
||||||
|
|
||||||
ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy)
|
ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy)
|
||||||
# The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame
|
# The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/idr.h>
|
#include <linux/idr.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/io-64-nonatomic-hi-lo.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/ktime.h>
|
#include <linux/ktime.h>
|
||||||
#include <linux/hashtable.h>
|
#include <linux/hashtable.h>
|
||||||
@@ -60,6 +61,11 @@ static atomic_t transfer_last_id;
|
|||||||
static DEFINE_IDR(scmi_requested_devices);
|
static DEFINE_IDR(scmi_requested_devices);
|
||||||
static DEFINE_MUTEX(scmi_requested_devices_mtx);
|
static DEFINE_MUTEX(scmi_requested_devices_mtx);
|
||||||
|
|
||||||
|
/* Track globally the creation of SCMI SystemPower related devices */
|
||||||
|
static bool scmi_syspower_registered;
|
||||||
|
/* Protect access to scmi_syspower_registered */
|
||||||
|
static DEFINE_MUTEX(scmi_syspower_mtx);
|
||||||
|
|
||||||
struct scmi_requested_dev {
|
struct scmi_requested_dev {
|
||||||
const struct scmi_device_id *id_table;
|
const struct scmi_device_id *id_table;
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
@@ -660,6 +666,11 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo,
|
|||||||
smp_store_mb(xfer->priv, priv);
|
smp_store_mb(xfer->priv, priv);
|
||||||
info->desc->ops->fetch_notification(cinfo, info->desc->max_msg_size,
|
info->desc->ops->fetch_notification(cinfo, info->desc->max_msg_size,
|
||||||
xfer);
|
xfer);
|
||||||
|
|
||||||
|
trace_scmi_msg_dump(xfer->hdr.protocol_id, xfer->hdr.id, "NOTI",
|
||||||
|
xfer->hdr.seq, xfer->hdr.status,
|
||||||
|
xfer->rx.buf, xfer->rx.len);
|
||||||
|
|
||||||
scmi_notify(cinfo->handle, xfer->hdr.protocol_id,
|
scmi_notify(cinfo->handle, xfer->hdr.protocol_id,
|
||||||
xfer->hdr.id, xfer->rx.buf, xfer->rx.len, ts);
|
xfer->hdr.id, xfer->rx.buf, xfer->rx.len, ts);
|
||||||
|
|
||||||
@@ -694,6 +705,12 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo,
|
|||||||
smp_store_mb(xfer->priv, priv);
|
smp_store_mb(xfer->priv, priv);
|
||||||
info->desc->ops->fetch_response(cinfo, xfer);
|
info->desc->ops->fetch_response(cinfo, xfer);
|
||||||
|
|
||||||
|
trace_scmi_msg_dump(xfer->hdr.protocol_id, xfer->hdr.id,
|
||||||
|
xfer->hdr.type == MSG_TYPE_DELAYED_RESP ?
|
||||||
|
"DLYD" : "RESP",
|
||||||
|
xfer->hdr.seq, xfer->hdr.status,
|
||||||
|
xfer->rx.buf, xfer->rx.len);
|
||||||
|
|
||||||
trace_scmi_rx_done(xfer->transfer_id, xfer->hdr.id,
|
trace_scmi_rx_done(xfer->transfer_id, xfer->hdr.id,
|
||||||
xfer->hdr.protocol_id, xfer->hdr.seq,
|
xfer->hdr.protocol_id, xfer->hdr.seq,
|
||||||
xfer->hdr.type);
|
xfer->hdr.type);
|
||||||
@@ -827,6 +844,12 @@ static int scmi_wait_for_message_response(struct scmi_chan_info *cinfo,
|
|||||||
xfer->state = SCMI_XFER_RESP_OK;
|
xfer->state = SCMI_XFER_RESP_OK;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&xfer->lock, flags);
|
spin_unlock_irqrestore(&xfer->lock, flags);
|
||||||
|
|
||||||
|
/* Trace polled replies. */
|
||||||
|
trace_scmi_msg_dump(xfer->hdr.protocol_id, xfer->hdr.id,
|
||||||
|
"RESP",
|
||||||
|
xfer->hdr.seq, xfer->hdr.status,
|
||||||
|
xfer->rx.buf, xfer->rx.len);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* And we wait for the response. */
|
/* And we wait for the response. */
|
||||||
@@ -903,6 +926,10 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trace_scmi_msg_dump(xfer->hdr.protocol_id, xfer->hdr.id, "CMND",
|
||||||
|
xfer->hdr.seq, xfer->hdr.status,
|
||||||
|
xfer->tx.buf, xfer->tx.len);
|
||||||
|
|
||||||
ret = scmi_wait_for_message_response(cinfo, xfer);
|
ret = scmi_wait_for_message_response(cinfo, xfer);
|
||||||
if (!ret && xfer->hdr.status)
|
if (!ret && xfer->hdr.status)
|
||||||
ret = scmi_to_linux_errno(xfer->hdr.status);
|
ret = scmi_to_linux_errno(xfer->hdr.status);
|
||||||
@@ -1259,10 +1286,174 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct scmi_msg_get_fc_info {
|
||||||
|
__le32 domain;
|
||||||
|
__le32 message_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scmi_msg_resp_desc_fc {
|
||||||
|
__le32 attr;
|
||||||
|
#define SUPPORTS_DOORBELL(x) ((x) & BIT(0))
|
||||||
|
#define DOORBELL_REG_WIDTH(x) FIELD_GET(GENMASK(2, 1), (x))
|
||||||
|
__le32 rate_limit;
|
||||||
|
__le32 chan_addr_low;
|
||||||
|
__le32 chan_addr_high;
|
||||||
|
__le32 chan_size;
|
||||||
|
__le32 db_addr_low;
|
||||||
|
__le32 db_addr_high;
|
||||||
|
__le32 db_set_lmask;
|
||||||
|
__le32 db_set_hmask;
|
||||||
|
__le32 db_preserve_lmask;
|
||||||
|
__le32 db_preserve_hmask;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
scmi_common_fastchannel_init(const struct scmi_protocol_handle *ph,
|
||||||
|
u8 describe_id, u32 message_id, u32 valid_size,
|
||||||
|
u32 domain, void __iomem **p_addr,
|
||||||
|
struct scmi_fc_db_info **p_db)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u32 flags;
|
||||||
|
u64 phys_addr;
|
||||||
|
u8 size;
|
||||||
|
void __iomem *addr;
|
||||||
|
struct scmi_xfer *t;
|
||||||
|
struct scmi_fc_db_info *db = NULL;
|
||||||
|
struct scmi_msg_get_fc_info *info;
|
||||||
|
struct scmi_msg_resp_desc_fc *resp;
|
||||||
|
const struct scmi_protocol_instance *pi = ph_to_pi(ph);
|
||||||
|
|
||||||
|
if (!p_addr) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ph->xops->xfer_get_init(ph, describe_id,
|
||||||
|
sizeof(*info), sizeof(*resp), &t);
|
||||||
|
if (ret)
|
||||||
|
goto err_out;
|
||||||
|
|
||||||
|
info = t->tx.buf;
|
||||||
|
info->domain = cpu_to_le32(domain);
|
||||||
|
info->message_id = cpu_to_le32(message_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bail out on error leaving fc_info addresses zeroed; this includes
|
||||||
|
* the case in which the requested domain/message_id does NOT support
|
||||||
|
* fastchannels at all.
|
||||||
|
*/
|
||||||
|
ret = ph->xops->do_xfer(ph, t);
|
||||||
|
if (ret)
|
||||||
|
goto err_xfer;
|
||||||
|
|
||||||
|
resp = t->rx.buf;
|
||||||
|
flags = le32_to_cpu(resp->attr);
|
||||||
|
size = le32_to_cpu(resp->chan_size);
|
||||||
|
if (size != valid_size) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto err_xfer;
|
||||||
|
}
|
||||||
|
|
||||||
|
phys_addr = le32_to_cpu(resp->chan_addr_low);
|
||||||
|
phys_addr |= (u64)le32_to_cpu(resp->chan_addr_high) << 32;
|
||||||
|
addr = devm_ioremap(ph->dev, phys_addr, size);
|
||||||
|
if (!addr) {
|
||||||
|
ret = -EADDRNOTAVAIL;
|
||||||
|
goto err_xfer;
|
||||||
|
}
|
||||||
|
|
||||||
|
*p_addr = addr;
|
||||||
|
|
||||||
|
if (p_db && SUPPORTS_DOORBELL(flags)) {
|
||||||
|
db = devm_kzalloc(ph->dev, sizeof(*db), GFP_KERNEL);
|
||||||
|
if (!db) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto err_db;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = 1 << DOORBELL_REG_WIDTH(flags);
|
||||||
|
phys_addr = le32_to_cpu(resp->db_addr_low);
|
||||||
|
phys_addr |= (u64)le32_to_cpu(resp->db_addr_high) << 32;
|
||||||
|
addr = devm_ioremap(ph->dev, phys_addr, size);
|
||||||
|
if (!addr) {
|
||||||
|
ret = -EADDRNOTAVAIL;
|
||||||
|
goto err_db_mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
db->addr = addr;
|
||||||
|
db->width = size;
|
||||||
|
db->set = le32_to_cpu(resp->db_set_lmask);
|
||||||
|
db->set |= (u64)le32_to_cpu(resp->db_set_hmask) << 32;
|
||||||
|
db->mask = le32_to_cpu(resp->db_preserve_lmask);
|
||||||
|
db->mask |= (u64)le32_to_cpu(resp->db_preserve_hmask) << 32;
|
||||||
|
|
||||||
|
*p_db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
ph->xops->xfer_put(ph, t);
|
||||||
|
|
||||||
|
dev_dbg(ph->dev,
|
||||||
|
"Using valid FC for protocol %X [MSG_ID:%u / RES_ID:%u]\n",
|
||||||
|
pi->proto->id, message_id, domain);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
err_db_mem:
|
||||||
|
devm_kfree(ph->dev, db);
|
||||||
|
|
||||||
|
err_db:
|
||||||
|
*p_addr = NULL;
|
||||||
|
|
||||||
|
err_xfer:
|
||||||
|
ph->xops->xfer_put(ph, t);
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
dev_warn(ph->dev,
|
||||||
|
"Failed to get FC for protocol %X [MSG_ID:%u / RES_ID:%u] - ret:%d. Using regular messaging.\n",
|
||||||
|
pi->proto->id, message_id, domain, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SCMI_PROTO_FC_RING_DB(w) \
|
||||||
|
do { \
|
||||||
|
u##w val = 0; \
|
||||||
|
\
|
||||||
|
if (db->mask) \
|
||||||
|
val = ioread##w(db->addr) & db->mask; \
|
||||||
|
iowrite##w((u##w)db->set | val, db->addr); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static void scmi_common_fastchannel_db_ring(struct scmi_fc_db_info *db)
|
||||||
|
{
|
||||||
|
if (!db || !db->addr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (db->width == 1)
|
||||||
|
SCMI_PROTO_FC_RING_DB(8);
|
||||||
|
else if (db->width == 2)
|
||||||
|
SCMI_PROTO_FC_RING_DB(16);
|
||||||
|
else if (db->width == 4)
|
||||||
|
SCMI_PROTO_FC_RING_DB(32);
|
||||||
|
else /* db->width == 8 */
|
||||||
|
#ifdef CONFIG_64BIT
|
||||||
|
SCMI_PROTO_FC_RING_DB(64);
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
u64 val = 0;
|
||||||
|
|
||||||
|
if (db->mask)
|
||||||
|
val = ioread64_hi_lo(db->addr) & db->mask;
|
||||||
|
iowrite64_hi_lo(db->set | val, db->addr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static const struct scmi_proto_helpers_ops helpers_ops = {
|
static const struct scmi_proto_helpers_ops helpers_ops = {
|
||||||
.extended_name_get = scmi_common_extended_name_get,
|
.extended_name_get = scmi_common_extended_name_get,
|
||||||
.iter_response_init = scmi_iterator_init,
|
.iter_response_init = scmi_iterator_init,
|
||||||
.iter_response_run = scmi_iterator_run,
|
.iter_response_run = scmi_iterator_run,
|
||||||
|
.fastchannel_init = scmi_common_fastchannel_init,
|
||||||
|
.fastchannel_db_ring = scmi_common_fastchannel_db_ring,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1497,6 +1688,30 @@ static void scmi_devm_release_protocol(struct device *dev, void *res)
|
|||||||
scmi_protocol_release(dres->handle, dres->protocol_id);
|
scmi_protocol_release(dres->handle, dres->protocol_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct scmi_protocol_instance __must_check *
|
||||||
|
scmi_devres_protocol_instance_get(struct scmi_device *sdev, u8 protocol_id)
|
||||||
|
{
|
||||||
|
struct scmi_protocol_instance *pi;
|
||||||
|
struct scmi_protocol_devres *dres;
|
||||||
|
|
||||||
|
dres = devres_alloc(scmi_devm_release_protocol,
|
||||||
|
sizeof(*dres), GFP_KERNEL);
|
||||||
|
if (!dres)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
pi = scmi_get_protocol_instance(sdev->handle, protocol_id);
|
||||||
|
if (IS_ERR(pi)) {
|
||||||
|
devres_free(dres);
|
||||||
|
return pi;
|
||||||
|
}
|
||||||
|
|
||||||
|
dres->handle = sdev->handle;
|
||||||
|
dres->protocol_id = protocol_id;
|
||||||
|
devres_add(&sdev->dev, dres);
|
||||||
|
|
||||||
|
return pi;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* scmi_devm_protocol_get - Devres managed get protocol operations and handle
|
* scmi_devm_protocol_get - Devres managed get protocol operations and handle
|
||||||
* @sdev: A reference to an scmi_device whose embedded struct device is to
|
* @sdev: A reference to an scmi_device whose embedded struct device is to
|
||||||
@@ -1520,32 +1735,47 @@ scmi_devm_protocol_get(struct scmi_device *sdev, u8 protocol_id,
|
|||||||
struct scmi_protocol_handle **ph)
|
struct scmi_protocol_handle **ph)
|
||||||
{
|
{
|
||||||
struct scmi_protocol_instance *pi;
|
struct scmi_protocol_instance *pi;
|
||||||
struct scmi_protocol_devres *dres;
|
|
||||||
struct scmi_handle *handle = sdev->handle;
|
|
||||||
|
|
||||||
if (!ph)
|
if (!ph)
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
dres = devres_alloc(scmi_devm_release_protocol,
|
pi = scmi_devres_protocol_instance_get(sdev, protocol_id);
|
||||||
sizeof(*dres), GFP_KERNEL);
|
if (IS_ERR(pi))
|
||||||
if (!dres)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
pi = scmi_get_protocol_instance(handle, protocol_id);
|
|
||||||
if (IS_ERR(pi)) {
|
|
||||||
devres_free(dres);
|
|
||||||
return pi;
|
return pi;
|
||||||
}
|
|
||||||
|
|
||||||
dres->handle = handle;
|
|
||||||
dres->protocol_id = protocol_id;
|
|
||||||
devres_add(&sdev->dev, dres);
|
|
||||||
|
|
||||||
*ph = &pi->ph;
|
*ph = &pi->ph;
|
||||||
|
|
||||||
return pi->proto->ops;
|
return pi->proto->ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scmi_devm_protocol_acquire - Devres managed helper to get hold of a protocol
|
||||||
|
* @sdev: A reference to an scmi_device whose embedded struct device is to
|
||||||
|
* be used for devres accounting.
|
||||||
|
* @protocol_id: The protocol being requested.
|
||||||
|
*
|
||||||
|
* Get hold of a protocol accounting for its usage, possibly triggering its
|
||||||
|
* initialization but without getting access to its protocol specific operations
|
||||||
|
* and handle.
|
||||||
|
*
|
||||||
|
* Being a devres based managed method, protocol hold will be automatically
|
||||||
|
* released, and possibly de-initialized on last user, once the SCMI driver
|
||||||
|
* owning the scmi_device is unbound from it.
|
||||||
|
*
|
||||||
|
* Return: 0 on SUCCESS
|
||||||
|
*/
|
||||||
|
static int __must_check scmi_devm_protocol_acquire(struct scmi_device *sdev,
|
||||||
|
u8 protocol_id)
|
||||||
|
{
|
||||||
|
struct scmi_protocol_instance *pi;
|
||||||
|
|
||||||
|
pi = scmi_devres_protocol_instance_get(sdev, protocol_id);
|
||||||
|
if (IS_ERR(pi))
|
||||||
|
return PTR_ERR(pi);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int scmi_devm_protocol_match(struct device *dev, void *res, void *data)
|
static int scmi_devm_protocol_match(struct device *dev, void *res, void *data)
|
||||||
{
|
{
|
||||||
struct scmi_protocol_devres *dres = res;
|
struct scmi_protocol_devres *dres = res;
|
||||||
@@ -1849,21 +2079,39 @@ scmi_get_protocol_device(struct device_node *np, struct scmi_info *info,
|
|||||||
if (sdev)
|
if (sdev)
|
||||||
return sdev;
|
return sdev;
|
||||||
|
|
||||||
|
mutex_lock(&scmi_syspower_mtx);
|
||||||
|
if (prot_id == SCMI_PROTOCOL_SYSTEM && scmi_syspower_registered) {
|
||||||
|
dev_warn(info->dev,
|
||||||
|
"SCMI SystemPower protocol device must be unique !\n");
|
||||||
|
mutex_unlock(&scmi_syspower_mtx);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
pr_debug("Creating SCMI device (%s) for protocol %x\n", name, prot_id);
|
pr_debug("Creating SCMI device (%s) for protocol %x\n", name, prot_id);
|
||||||
|
|
||||||
sdev = scmi_device_create(np, info->dev, prot_id, name);
|
sdev = scmi_device_create(np, info->dev, prot_id, name);
|
||||||
if (!sdev) {
|
if (!sdev) {
|
||||||
dev_err(info->dev, "failed to create %d protocol device\n",
|
dev_err(info->dev, "failed to create %d protocol device\n",
|
||||||
prot_id);
|
prot_id);
|
||||||
|
mutex_unlock(&scmi_syspower_mtx);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scmi_txrx_setup(info, &sdev->dev, prot_id)) {
|
if (scmi_txrx_setup(info, &sdev->dev, prot_id)) {
|
||||||
dev_err(&sdev->dev, "failed to setup transport\n");
|
dev_err(&sdev->dev, "failed to setup transport\n");
|
||||||
scmi_device_destroy(sdev);
|
scmi_device_destroy(sdev);
|
||||||
|
mutex_unlock(&scmi_syspower_mtx);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prot_id == SCMI_PROTOCOL_SYSTEM)
|
||||||
|
scmi_syspower_registered = true;
|
||||||
|
|
||||||
|
mutex_unlock(&scmi_syspower_mtx);
|
||||||
|
|
||||||
return sdev;
|
return sdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2132,6 +2380,7 @@ static int scmi_probe(struct platform_device *pdev)
|
|||||||
handle = &info->handle;
|
handle = &info->handle;
|
||||||
handle->dev = info->dev;
|
handle->dev = info->dev;
|
||||||
handle->version = &info->version;
|
handle->version = &info->version;
|
||||||
|
handle->devm_protocol_acquire = scmi_devm_protocol_acquire;
|
||||||
handle->devm_protocol_get = scmi_devm_protocol_get;
|
handle->devm_protocol_get = scmi_devm_protocol_get;
|
||||||
handle->devm_protocol_put = scmi_devm_protocol_put;
|
handle->devm_protocol_put = scmi_devm_protocol_put;
|
||||||
|
|
||||||
@@ -2401,6 +2650,7 @@ static int __init scmi_driver_init(void)
|
|||||||
scmi_sensors_register();
|
scmi_sensors_register();
|
||||||
scmi_voltage_register();
|
scmi_voltage_register();
|
||||||
scmi_system_register();
|
scmi_system_register();
|
||||||
|
scmi_powercap_register();
|
||||||
|
|
||||||
return platform_driver_register(&scmi_driver);
|
return platform_driver_register(&scmi_driver);
|
||||||
}
|
}
|
||||||
@@ -2417,6 +2667,7 @@ static void __exit scmi_driver_exit(void)
|
|||||||
scmi_sensors_unregister();
|
scmi_sensors_unregister();
|
||||||
scmi_voltage_unregister();
|
scmi_voltage_unregister();
|
||||||
scmi_system_unregister();
|
scmi_system_unregister();
|
||||||
|
scmi_powercap_unregister();
|
||||||
|
|
||||||
scmi_bus_exit();
|
scmi_bus_exit();
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,14 @@
|
|||||||
#include <linux/bits.h>
|
#include <linux/bits.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/io-64-nonatomic-hi-lo.h>
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm_opp.h>
|
#include <linux/pm_opp.h>
|
||||||
#include <linux/scmi_protocol.h>
|
#include <linux/scmi_protocol.h>
|
||||||
#include <linux/sort.h>
|
#include <linux/sort.h>
|
||||||
|
|
||||||
|
#include <trace/events/scmi.h>
|
||||||
|
|
||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
|
||||||
@@ -35,6 +36,12 @@ enum scmi_performance_protocol_cmd {
|
|||||||
PERF_DOMAIN_NAME_GET = 0xc,
|
PERF_DOMAIN_NAME_GET = 0xc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PERF_FC_LEVEL,
|
||||||
|
PERF_FC_LIMIT,
|
||||||
|
PERF_FC_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
struct scmi_opp {
|
struct scmi_opp {
|
||||||
u32 perf;
|
u32 perf;
|
||||||
u32 power;
|
u32 power;
|
||||||
@@ -115,43 +122,6 @@ struct scmi_msg_resp_perf_describe_levels {
|
|||||||
} opp[];
|
} opp[];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scmi_perf_get_fc_info {
|
|
||||||
__le32 domain;
|
|
||||||
__le32 message_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct scmi_msg_resp_perf_desc_fc {
|
|
||||||
__le32 attr;
|
|
||||||
#define SUPPORTS_DOORBELL(x) ((x) & BIT(0))
|
|
||||||
#define DOORBELL_REG_WIDTH(x) FIELD_GET(GENMASK(2, 1), (x))
|
|
||||||
__le32 rate_limit;
|
|
||||||
__le32 chan_addr_low;
|
|
||||||
__le32 chan_addr_high;
|
|
||||||
__le32 chan_size;
|
|
||||||
__le32 db_addr_low;
|
|
||||||
__le32 db_addr_high;
|
|
||||||
__le32 db_set_lmask;
|
|
||||||
__le32 db_set_hmask;
|
|
||||||
__le32 db_preserve_lmask;
|
|
||||||
__le32 db_preserve_hmask;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct scmi_fc_db_info {
|
|
||||||
int width;
|
|
||||||
u64 set;
|
|
||||||
u64 mask;
|
|
||||||
void __iomem *addr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct scmi_fc_info {
|
|
||||||
void __iomem *level_set_addr;
|
|
||||||
void __iomem *limit_set_addr;
|
|
||||||
void __iomem *level_get_addr;
|
|
||||||
void __iomem *limit_get_addr;
|
|
||||||
struct scmi_fc_db_info *level_set_db;
|
|
||||||
struct scmi_fc_db_info *limit_set_db;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct perf_dom_info {
|
struct perf_dom_info {
|
||||||
bool set_limits;
|
bool set_limits;
|
||||||
bool set_perf;
|
bool set_perf;
|
||||||
@@ -360,40 +330,6 @@ scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, u32 domain,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SCMI_PERF_FC_RING_DB(w) \
|
|
||||||
do { \
|
|
||||||
u##w val = 0; \
|
|
||||||
\
|
|
||||||
if (db->mask) \
|
|
||||||
val = ioread##w(db->addr) & db->mask; \
|
|
||||||
iowrite##w((u##w)db->set | val, db->addr); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static void scmi_perf_fc_ring_db(struct scmi_fc_db_info *db)
|
|
||||||
{
|
|
||||||
if (!db || !db->addr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (db->width == 1)
|
|
||||||
SCMI_PERF_FC_RING_DB(8);
|
|
||||||
else if (db->width == 2)
|
|
||||||
SCMI_PERF_FC_RING_DB(16);
|
|
||||||
else if (db->width == 4)
|
|
||||||
SCMI_PERF_FC_RING_DB(32);
|
|
||||||
else /* db->width == 8 */
|
|
||||||
#ifdef CONFIG_64BIT
|
|
||||||
SCMI_PERF_FC_RING_DB(64);
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
u64 val = 0;
|
|
||||||
|
|
||||||
if (db->mask)
|
|
||||||
val = ioread64_hi_lo(db->addr) & db->mask;
|
|
||||||
iowrite64_hi_lo(db->set | val, db->addr);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int scmi_perf_mb_limits_set(const struct scmi_protocol_handle *ph,
|
static int scmi_perf_mb_limits_set(const struct scmi_protocol_handle *ph,
|
||||||
u32 domain, u32 max_perf, u32 min_perf)
|
u32 domain, u32 max_perf, u32 min_perf)
|
||||||
{
|
{
|
||||||
@@ -426,10 +362,14 @@ static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
|
|||||||
if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3 && !max_perf && !min_perf)
|
if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3 && !max_perf && !min_perf)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (dom->fc_info && dom->fc_info->limit_set_addr) {
|
if (dom->fc_info && dom->fc_info[PERF_FC_LIMIT].set_addr) {
|
||||||
iowrite32(max_perf, dom->fc_info->limit_set_addr);
|
struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LIMIT];
|
||||||
iowrite32(min_perf, dom->fc_info->limit_set_addr + 4);
|
|
||||||
scmi_perf_fc_ring_db(dom->fc_info->limit_set_db);
|
trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LIMITS_SET,
|
||||||
|
domain, min_perf, max_perf);
|
||||||
|
iowrite32(max_perf, fci->set_addr);
|
||||||
|
iowrite32(min_perf, fci->set_addr + 4);
|
||||||
|
ph->hops->fastchannel_db_ring(fci->set_db);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,9 +408,13 @@ static int scmi_perf_limits_get(const struct scmi_protocol_handle *ph,
|
|||||||
struct scmi_perf_info *pi = ph->get_priv(ph);
|
struct scmi_perf_info *pi = ph->get_priv(ph);
|
||||||
struct perf_dom_info *dom = pi->dom_info + domain;
|
struct perf_dom_info *dom = pi->dom_info + domain;
|
||||||
|
|
||||||
if (dom->fc_info && dom->fc_info->limit_get_addr) {
|
if (dom->fc_info && dom->fc_info[PERF_FC_LIMIT].get_addr) {
|
||||||
*max_perf = ioread32(dom->fc_info->limit_get_addr);
|
struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LIMIT];
|
||||||
*min_perf = ioread32(dom->fc_info->limit_get_addr + 4);
|
|
||||||
|
*max_perf = ioread32(fci->get_addr);
|
||||||
|
*min_perf = ioread32(fci->get_addr + 4);
|
||||||
|
trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LIMITS_GET,
|
||||||
|
domain, *min_perf, *max_perf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,9 +449,13 @@ static int scmi_perf_level_set(const struct scmi_protocol_handle *ph,
|
|||||||
struct scmi_perf_info *pi = ph->get_priv(ph);
|
struct scmi_perf_info *pi = ph->get_priv(ph);
|
||||||
struct perf_dom_info *dom = pi->dom_info + domain;
|
struct perf_dom_info *dom = pi->dom_info + domain;
|
||||||
|
|
||||||
if (dom->fc_info && dom->fc_info->level_set_addr) {
|
if (dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr) {
|
||||||
iowrite32(level, dom->fc_info->level_set_addr);
|
struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LEVEL];
|
||||||
scmi_perf_fc_ring_db(dom->fc_info->level_set_db);
|
|
||||||
|
trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LEVEL_SET,
|
||||||
|
domain, level, 0);
|
||||||
|
iowrite32(level, fci->set_addr);
|
||||||
|
ph->hops->fastchannel_db_ring(fci->set_db);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -542,8 +490,10 @@ static int scmi_perf_level_get(const struct scmi_protocol_handle *ph,
|
|||||||
struct scmi_perf_info *pi = ph->get_priv(ph);
|
struct scmi_perf_info *pi = ph->get_priv(ph);
|
||||||
struct perf_dom_info *dom = pi->dom_info + domain;
|
struct perf_dom_info *dom = pi->dom_info + domain;
|
||||||
|
|
||||||
if (dom->fc_info && dom->fc_info->level_get_addr) {
|
if (dom->fc_info && dom->fc_info[PERF_FC_LEVEL].get_addr) {
|
||||||
*level = ioread32(dom->fc_info->level_get_addr);
|
*level = ioread32(dom->fc_info[PERF_FC_LEVEL].get_addr);
|
||||||
|
trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LEVEL_GET,
|
||||||
|
domain, *level, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,100 +522,33 @@ static int scmi_perf_level_limits_notify(const struct scmi_protocol_handle *ph,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool scmi_perf_fc_size_is_valid(u32 msg, u32 size)
|
|
||||||
{
|
|
||||||
if ((msg == PERF_LEVEL_GET || msg == PERF_LEVEL_SET) && size == 4)
|
|
||||||
return true;
|
|
||||||
if ((msg == PERF_LIMITS_GET || msg == PERF_LIMITS_SET) && size == 8)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
scmi_perf_domain_desc_fc(const struct scmi_protocol_handle *ph, u32 domain,
|
|
||||||
u32 message_id, void __iomem **p_addr,
|
|
||||||
struct scmi_fc_db_info **p_db)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
u32 flags;
|
|
||||||
u64 phys_addr;
|
|
||||||
u8 size;
|
|
||||||
void __iomem *addr;
|
|
||||||
struct scmi_xfer *t;
|
|
||||||
struct scmi_fc_db_info *db;
|
|
||||||
struct scmi_perf_get_fc_info *info;
|
|
||||||
struct scmi_msg_resp_perf_desc_fc *resp;
|
|
||||||
|
|
||||||
if (!p_addr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ret = ph->xops->xfer_get_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
|
||||||
sizeof(*info), sizeof(*resp), &t);
|
|
||||||
if (ret)
|
|
||||||
return;
|
|
||||||
|
|
||||||
info = t->tx.buf;
|
|
||||||
info->domain = cpu_to_le32(domain);
|
|
||||||
info->message_id = cpu_to_le32(message_id);
|
|
||||||
|
|
||||||
ret = ph->xops->do_xfer(ph, t);
|
|
||||||
if (ret)
|
|
||||||
goto err_xfer;
|
|
||||||
|
|
||||||
resp = t->rx.buf;
|
|
||||||
flags = le32_to_cpu(resp->attr);
|
|
||||||
size = le32_to_cpu(resp->chan_size);
|
|
||||||
if (!scmi_perf_fc_size_is_valid(message_id, size))
|
|
||||||
goto err_xfer;
|
|
||||||
|
|
||||||
phys_addr = le32_to_cpu(resp->chan_addr_low);
|
|
||||||
phys_addr |= (u64)le32_to_cpu(resp->chan_addr_high) << 32;
|
|
||||||
addr = devm_ioremap(ph->dev, phys_addr, size);
|
|
||||||
if (!addr)
|
|
||||||
goto err_xfer;
|
|
||||||
*p_addr = addr;
|
|
||||||
|
|
||||||
if (p_db && SUPPORTS_DOORBELL(flags)) {
|
|
||||||
db = devm_kzalloc(ph->dev, sizeof(*db), GFP_KERNEL);
|
|
||||||
if (!db)
|
|
||||||
goto err_xfer;
|
|
||||||
|
|
||||||
size = 1 << DOORBELL_REG_WIDTH(flags);
|
|
||||||
phys_addr = le32_to_cpu(resp->db_addr_low);
|
|
||||||
phys_addr |= (u64)le32_to_cpu(resp->db_addr_high) << 32;
|
|
||||||
addr = devm_ioremap(ph->dev, phys_addr, size);
|
|
||||||
if (!addr)
|
|
||||||
goto err_xfer;
|
|
||||||
|
|
||||||
db->addr = addr;
|
|
||||||
db->width = size;
|
|
||||||
db->set = le32_to_cpu(resp->db_set_lmask);
|
|
||||||
db->set |= (u64)le32_to_cpu(resp->db_set_hmask) << 32;
|
|
||||||
db->mask = le32_to_cpu(resp->db_preserve_lmask);
|
|
||||||
db->mask |= (u64)le32_to_cpu(resp->db_preserve_hmask) << 32;
|
|
||||||
*p_db = db;
|
|
||||||
}
|
|
||||||
err_xfer:
|
|
||||||
ph->xops->xfer_put(ph, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
|
static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
|
||||||
u32 domain, struct scmi_fc_info **p_fc)
|
u32 domain, struct scmi_fc_info **p_fc)
|
||||||
{
|
{
|
||||||
struct scmi_fc_info *fc;
|
struct scmi_fc_info *fc;
|
||||||
|
|
||||||
fc = devm_kzalloc(ph->dev, sizeof(*fc), GFP_KERNEL);
|
fc = devm_kcalloc(ph->dev, PERF_FC_MAX, sizeof(*fc), GFP_KERNEL);
|
||||||
if (!fc)
|
if (!fc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
scmi_perf_domain_desc_fc(ph, domain, PERF_LEVEL_SET,
|
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
||||||
&fc->level_set_addr, &fc->level_set_db);
|
PERF_LEVEL_SET, 4, domain,
|
||||||
scmi_perf_domain_desc_fc(ph, domain, PERF_LEVEL_GET,
|
&fc[PERF_FC_LEVEL].set_addr,
|
||||||
&fc->level_get_addr, NULL);
|
&fc[PERF_FC_LEVEL].set_db);
|
||||||
scmi_perf_domain_desc_fc(ph, domain, PERF_LIMITS_SET,
|
|
||||||
&fc->limit_set_addr, &fc->limit_set_db);
|
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
||||||
scmi_perf_domain_desc_fc(ph, domain, PERF_LIMITS_GET,
|
PERF_LEVEL_GET, 4, domain,
|
||||||
&fc->limit_get_addr, NULL);
|
&fc[PERF_FC_LEVEL].get_addr, NULL);
|
||||||
|
|
||||||
|
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
||||||
|
PERF_LIMITS_SET, 8, domain,
|
||||||
|
&fc[PERF_FC_LIMIT].set_addr,
|
||||||
|
&fc[PERF_FC_LIMIT].set_db);
|
||||||
|
|
||||||
|
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
||||||
|
PERF_LIMITS_GET, 8, domain,
|
||||||
|
&fc[PERF_FC_LIMIT].get_addr, NULL);
|
||||||
|
|
||||||
*p_fc = fc;
|
*p_fc = fc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -789,7 +672,7 @@ static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph,
|
|||||||
|
|
||||||
dom = pi->dom_info + scmi_dev_domain_id(dev);
|
dom = pi->dom_info + scmi_dev_domain_id(dev);
|
||||||
|
|
||||||
return dom->fc_info && dom->fc_info->level_set_addr;
|
return dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool scmi_power_scale_mw_get(const struct scmi_protocol_handle *ph)
|
static bool scmi_power_scale_mw_get(const struct scmi_protocol_handle *ph)
|
||||||
|
|||||||
866
drivers/firmware/arm_scmi/powercap.c
Normal file
866
drivers/firmware/arm_scmi/powercap.c
Normal file
@@ -0,0 +1,866 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* System Control and Management Interface (SCMI) Powercap Protocol
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 ARM Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define pr_fmt(fmt) "SCMI Notifications POWERCAP - " fmt
|
||||||
|
|
||||||
|
#include <linux/bitfield.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/scmi_protocol.h>
|
||||||
|
|
||||||
|
#include <trace/events/scmi.h>
|
||||||
|
|
||||||
|
#include "protocols.h"
|
||||||
|
#include "notify.h"
|
||||||
|
|
||||||
|
enum scmi_powercap_protocol_cmd {
|
||||||
|
POWERCAP_DOMAIN_ATTRIBUTES = 0x3,
|
||||||
|
POWERCAP_CAP_GET = 0x4,
|
||||||
|
POWERCAP_CAP_SET = 0x5,
|
||||||
|
POWERCAP_PAI_GET = 0x6,
|
||||||
|
POWERCAP_PAI_SET = 0x7,
|
||||||
|
POWERCAP_DOMAIN_NAME_GET = 0x8,
|
||||||
|
POWERCAP_MEASUREMENTS_GET = 0x9,
|
||||||
|
POWERCAP_CAP_NOTIFY = 0xa,
|
||||||
|
POWERCAP_MEASUREMENTS_NOTIFY = 0xb,
|
||||||
|
POWERCAP_DESCRIBE_FASTCHANNEL = 0xc,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
POWERCAP_FC_CAP,
|
||||||
|
POWERCAP_FC_PAI,
|
||||||
|
POWERCAP_FC_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scmi_msg_resp_powercap_domain_attributes {
|
||||||
|
__le32 attributes;
|
||||||
|
#define SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(x) ((x) & BIT(31))
|
||||||
|
#define SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(x) ((x) & BIT(30))
|
||||||
|
#define SUPPORTS_ASYNC_POWERCAP_CAP_SET(x) ((x) & BIT(29))
|
||||||
|
#define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(28))
|
||||||
|
#define SUPPORTS_POWERCAP_CAP_CONFIGURATION(x) ((x) & BIT(27))
|
||||||
|
#define SUPPORTS_POWERCAP_MONITORING(x) ((x) & BIT(26))
|
||||||
|
#define SUPPORTS_POWERCAP_PAI_CONFIGURATION(x) ((x) & BIT(25))
|
||||||
|
#define SUPPORTS_POWERCAP_FASTCHANNELS(x) ((x) & BIT(22))
|
||||||
|
#define POWERCAP_POWER_UNIT(x) \
|
||||||
|
(FIELD_GET(GENMASK(24, 23), (x)))
|
||||||
|
#define SUPPORTS_POWER_UNITS_MW(x) \
|
||||||
|
(POWERCAP_POWER_UNIT(x) == 0x2)
|
||||||
|
#define SUPPORTS_POWER_UNITS_UW(x) \
|
||||||
|
(POWERCAP_POWER_UNIT(x) == 0x1)
|
||||||
|
u8 name[SCMI_SHORT_NAME_MAX_SIZE];
|
||||||
|
__le32 min_pai;
|
||||||
|
__le32 max_pai;
|
||||||
|
__le32 pai_step;
|
||||||
|
__le32 min_power_cap;
|
||||||
|
__le32 max_power_cap;
|
||||||
|
__le32 power_cap_step;
|
||||||
|
__le32 sustainable_power;
|
||||||
|
__le32 accuracy;
|
||||||
|
__le32 parent_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scmi_msg_powercap_set_cap_or_pai {
|
||||||
|
__le32 domain;
|
||||||
|
__le32 flags;
|
||||||
|
#define CAP_SET_ASYNC BIT(1)
|
||||||
|
#define CAP_SET_IGNORE_DRESP BIT(0)
|
||||||
|
__le32 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scmi_msg_resp_powercap_cap_set_complete {
|
||||||
|
__le32 domain;
|
||||||
|
__le32 power_cap;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scmi_msg_resp_powercap_meas_get {
|
||||||
|
__le32 power;
|
||||||
|
__le32 pai;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scmi_msg_powercap_notify_cap {
|
||||||
|
__le32 domain;
|
||||||
|
__le32 notify_enable;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scmi_msg_powercap_notify_thresh {
|
||||||
|
__le32 domain;
|
||||||
|
__le32 notify_enable;
|
||||||
|
__le32 power_thresh_low;
|
||||||
|
__le32 power_thresh_high;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scmi_powercap_cap_changed_notify_payld {
|
||||||
|
__le32 agent_id;
|
||||||
|
__le32 domain_id;
|
||||||
|
__le32 power_cap;
|
||||||
|
__le32 pai;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scmi_powercap_meas_changed_notify_payld {
|
||||||
|
__le32 agent_id;
|
||||||
|
__le32 domain_id;
|
||||||
|
__le32 power;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scmi_powercap_state {
|
||||||
|
bool meas_notif_enabled;
|
||||||
|
u64 thresholds;
|
||||||
|
#define THRESH_LOW(p, id) \
|
||||||
|
(lower_32_bits((p)->states[(id)].thresholds))
|
||||||
|
#define THRESH_HIGH(p, id) \
|
||||||
|
(upper_32_bits((p)->states[(id)].thresholds))
|
||||||
|
};
|
||||||
|
|
||||||
|
struct powercap_info {
|
||||||
|
u32 version;
|
||||||
|
int num_domains;
|
||||||
|
struct scmi_powercap_state *states;
|
||||||
|
struct scmi_powercap_info *powercaps;
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum scmi_powercap_protocol_cmd evt_2_cmd[] = {
|
||||||
|
POWERCAP_CAP_NOTIFY,
|
||||||
|
POWERCAP_MEASUREMENTS_NOTIFY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain, int message_id, bool enable);
|
||||||
|
|
||||||
|
static int
|
||||||
|
scmi_powercap_attributes_get(const struct scmi_protocol_handle *ph,
|
||||||
|
struct powercap_info *pi)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct scmi_xfer *t;
|
||||||
|
|
||||||
|
ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
|
||||||
|
sizeof(u32), &t);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = ph->xops->do_xfer(ph, t);
|
||||||
|
if (!ret) {
|
||||||
|
u32 attributes;
|
||||||
|
|
||||||
|
attributes = get_unaligned_le32(t->rx.buf);
|
||||||
|
pi->num_domains = FIELD_GET(GENMASK(15, 0), attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
ph->xops->xfer_put(ph, t);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
scmi_powercap_validate(unsigned int min_val, unsigned int max_val,
|
||||||
|
unsigned int step_val, bool configurable)
|
||||||
|
{
|
||||||
|
if (!min_val || !max_val)
|
||||||
|
return -EPROTO;
|
||||||
|
|
||||||
|
if ((configurable && min_val == max_val) ||
|
||||||
|
(!configurable && min_val != max_val))
|
||||||
|
return -EPROTO;
|
||||||
|
|
||||||
|
if (min_val != max_val && !step_val)
|
||||||
|
return -EPROTO;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
|
||||||
|
struct powercap_info *pinfo, u32 domain)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u32 flags;
|
||||||
|
struct scmi_xfer *t;
|
||||||
|
struct scmi_powercap_info *dom_info = pinfo->powercaps + domain;
|
||||||
|
struct scmi_msg_resp_powercap_domain_attributes *resp;
|
||||||
|
|
||||||
|
ret = ph->xops->xfer_get_init(ph, POWERCAP_DOMAIN_ATTRIBUTES,
|
||||||
|
sizeof(domain), sizeof(*resp), &t);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
put_unaligned_le32(domain, t->tx.buf);
|
||||||
|
resp = t->rx.buf;
|
||||||
|
|
||||||
|
ret = ph->xops->do_xfer(ph, t);
|
||||||
|
if (!ret) {
|
||||||
|
flags = le32_to_cpu(resp->attributes);
|
||||||
|
|
||||||
|
dom_info->id = domain;
|
||||||
|
dom_info->notify_powercap_cap_change =
|
||||||
|
SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(flags);
|
||||||
|
dom_info->notify_powercap_measurement_change =
|
||||||
|
SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
|
||||||
|
dom_info->async_powercap_cap_set =
|
||||||
|
SUPPORTS_ASYNC_POWERCAP_CAP_SET(flags);
|
||||||
|
dom_info->powercap_cap_config =
|
||||||
|
SUPPORTS_POWERCAP_CAP_CONFIGURATION(flags);
|
||||||
|
dom_info->powercap_monitoring =
|
||||||
|
SUPPORTS_POWERCAP_MONITORING(flags);
|
||||||
|
dom_info->powercap_pai_config =
|
||||||
|
SUPPORTS_POWERCAP_PAI_CONFIGURATION(flags);
|
||||||
|
dom_info->powercap_scale_mw =
|
||||||
|
SUPPORTS_POWER_UNITS_MW(flags);
|
||||||
|
dom_info->powercap_scale_uw =
|
||||||
|
SUPPORTS_POWER_UNITS_UW(flags);
|
||||||
|
dom_info->fastchannels =
|
||||||
|
SUPPORTS_POWERCAP_FASTCHANNELS(flags);
|
||||||
|
|
||||||
|
strscpy(dom_info->name, resp->name, SCMI_SHORT_NAME_MAX_SIZE);
|
||||||
|
|
||||||
|
dom_info->min_pai = le32_to_cpu(resp->min_pai);
|
||||||
|
dom_info->max_pai = le32_to_cpu(resp->max_pai);
|
||||||
|
dom_info->pai_step = le32_to_cpu(resp->pai_step);
|
||||||
|
ret = scmi_powercap_validate(dom_info->min_pai,
|
||||||
|
dom_info->max_pai,
|
||||||
|
dom_info->pai_step,
|
||||||
|
dom_info->powercap_pai_config);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(ph->dev,
|
||||||
|
"Platform reported inconsistent PAI config for domain %d - %s\n",
|
||||||
|
dom_info->id, dom_info->name);
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
dom_info->min_power_cap = le32_to_cpu(resp->min_power_cap);
|
||||||
|
dom_info->max_power_cap = le32_to_cpu(resp->max_power_cap);
|
||||||
|
dom_info->power_cap_step = le32_to_cpu(resp->power_cap_step);
|
||||||
|
ret = scmi_powercap_validate(dom_info->min_power_cap,
|
||||||
|
dom_info->max_power_cap,
|
||||||
|
dom_info->power_cap_step,
|
||||||
|
dom_info->powercap_cap_config);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(ph->dev,
|
||||||
|
"Platform reported inconsistent CAP config for domain %d - %s\n",
|
||||||
|
dom_info->id, dom_info->name);
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
dom_info->sustainable_power =
|
||||||
|
le32_to_cpu(resp->sustainable_power);
|
||||||
|
dom_info->accuracy = le32_to_cpu(resp->accuracy);
|
||||||
|
|
||||||
|
dom_info->parent_id = le32_to_cpu(resp->parent_id);
|
||||||
|
if (dom_info->parent_id != SCMI_POWERCAP_ROOT_ZONE_ID &&
|
||||||
|
(dom_info->parent_id >= pinfo->num_domains ||
|
||||||
|
dom_info->parent_id == dom_info->id)) {
|
||||||
|
dev_err(ph->dev,
|
||||||
|
"Platform reported inconsistent parent ID for domain %d - %s\n",
|
||||||
|
dom_info->id, dom_info->name);
|
||||||
|
ret = -ENODEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clean:
|
||||||
|
ph->xops->xfer_put(ph, t);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If supported overwrite short name with the extended one;
|
||||||
|
* on error just carry on and use already provided short name.
|
||||||
|
*/
|
||||||
|
if (!ret && SUPPORTS_EXTENDED_NAMES(flags))
|
||||||
|
ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET,
|
||||||
|
domain, dom_info->name,
|
||||||
|
SCMI_MAX_STR_SIZE);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scmi_powercap_num_domains_get(const struct scmi_protocol_handle *ph)
|
||||||
|
{
|
||||||
|
struct powercap_info *pi = ph->get_priv(ph);
|
||||||
|
|
||||||
|
return pi->num_domains;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct scmi_powercap_info *
|
||||||
|
scmi_powercap_dom_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
|
||||||
|
{
|
||||||
|
struct powercap_info *pi = ph->get_priv(ph);
|
||||||
|
|
||||||
|
if (domain_id >= pi->num_domains)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return pi->powercaps + domain_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain_id, u32 *power_cap)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct scmi_xfer *t;
|
||||||
|
|
||||||
|
ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_GET, sizeof(u32),
|
||||||
|
sizeof(u32), &t);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
put_unaligned_le32(domain_id, t->tx.buf);
|
||||||
|
ret = ph->xops->do_xfer(ph, t);
|
||||||
|
if (!ret)
|
||||||
|
*power_cap = get_unaligned_le32(t->rx.buf);
|
||||||
|
|
||||||
|
ph->xops->xfer_put(ph, t);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain_id, u32 *power_cap)
|
||||||
|
{
|
||||||
|
struct scmi_powercap_info *dom;
|
||||||
|
struct powercap_info *pi = ph->get_priv(ph);
|
||||||
|
|
||||||
|
if (!power_cap || domain_id >= pi->num_domains)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
dom = pi->powercaps + domain_id;
|
||||||
|
if (dom->fc_info && dom->fc_info[POWERCAP_FC_CAP].get_addr) {
|
||||||
|
*power_cap = ioread32(dom->fc_info[POWERCAP_FC_CAP].get_addr);
|
||||||
|
trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_GET,
|
||||||
|
domain_id, *power_cap, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scmi_powercap_xfer_cap_get(ph, domain_id, power_cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
|
||||||
|
const struct scmi_powercap_info *pc,
|
||||||
|
u32 power_cap, bool ignore_dresp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct scmi_xfer *t;
|
||||||
|
struct scmi_msg_powercap_set_cap_or_pai *msg;
|
||||||
|
|
||||||
|
ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_SET,
|
||||||
|
sizeof(*msg), 0, &t);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
msg = t->tx.buf;
|
||||||
|
msg->domain = cpu_to_le32(pc->id);
|
||||||
|
msg->flags =
|
||||||
|
cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC, !!pc->async_powercap_cap_set) |
|
||||||
|
FIELD_PREP(CAP_SET_IGNORE_DRESP, !!ignore_dresp));
|
||||||
|
msg->value = cpu_to_le32(power_cap);
|
||||||
|
|
||||||
|
if (!pc->async_powercap_cap_set || ignore_dresp) {
|
||||||
|
ret = ph->xops->do_xfer(ph, t);
|
||||||
|
} else {
|
||||||
|
ret = ph->xops->do_xfer_with_response(ph, t);
|
||||||
|
if (!ret) {
|
||||||
|
struct scmi_msg_resp_powercap_cap_set_complete *resp;
|
||||||
|
|
||||||
|
resp = t->rx.buf;
|
||||||
|
if (le32_to_cpu(resp->domain) == pc->id)
|
||||||
|
dev_dbg(ph->dev,
|
||||||
|
"Powercap ID %d CAP set async to %u\n",
|
||||||
|
pc->id,
|
||||||
|
get_unaligned_le32(&resp->power_cap));
|
||||||
|
else
|
||||||
|
ret = -EPROTO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ph->xops->xfer_put(ph, t);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain_id, u32 power_cap,
|
||||||
|
bool ignore_dresp)
|
||||||
|
{
|
||||||
|
const struct scmi_powercap_info *pc;
|
||||||
|
|
||||||
|
pc = scmi_powercap_dom_info_get(ph, domain_id);
|
||||||
|
if (!pc || !pc->powercap_cap_config || !power_cap ||
|
||||||
|
power_cap < pc->min_power_cap ||
|
||||||
|
power_cap > pc->max_power_cap)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (pc->fc_info && pc->fc_info[POWERCAP_FC_CAP].set_addr) {
|
||||||
|
struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_CAP];
|
||||||
|
|
||||||
|
iowrite32(power_cap, fci->set_addr);
|
||||||
|
ph->hops->fastchannel_db_ring(fci->set_db);
|
||||||
|
trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_SET,
|
||||||
|
domain_id, power_cap, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scmi_powercap_xfer_cap_set(ph, pc, power_cap, ignore_dresp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain_id, u32 *pai)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct scmi_xfer *t;
|
||||||
|
|
||||||
|
ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_GET, sizeof(u32),
|
||||||
|
sizeof(u32), &t);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
put_unaligned_le32(domain_id, t->tx.buf);
|
||||||
|
ret = ph->xops->do_xfer(ph, t);
|
||||||
|
if (!ret)
|
||||||
|
*pai = get_unaligned_le32(t->rx.buf);
|
||||||
|
|
||||||
|
ph->xops->xfer_put(ph, t);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scmi_powercap_pai_get(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain_id, u32 *pai)
|
||||||
|
{
|
||||||
|
struct scmi_powercap_info *dom;
|
||||||
|
struct powercap_info *pi = ph->get_priv(ph);
|
||||||
|
|
||||||
|
if (!pai || domain_id >= pi->num_domains)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
dom = pi->powercaps + domain_id;
|
||||||
|
if (dom->fc_info && dom->fc_info[POWERCAP_FC_PAI].get_addr) {
|
||||||
|
*pai = ioread32(dom->fc_info[POWERCAP_FC_PAI].get_addr);
|
||||||
|
trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_GET,
|
||||||
|
domain_id, *pai, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scmi_powercap_xfer_pai_get(ph, domain_id, pai);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain_id, u32 pai)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct scmi_xfer *t;
|
||||||
|
struct scmi_msg_powercap_set_cap_or_pai *msg;
|
||||||
|
|
||||||
|
ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_SET,
|
||||||
|
sizeof(*msg), 0, &t);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
msg = t->tx.buf;
|
||||||
|
msg->domain = cpu_to_le32(domain_id);
|
||||||
|
msg->flags = cpu_to_le32(0);
|
||||||
|
msg->value = cpu_to_le32(pai);
|
||||||
|
|
||||||
|
ret = ph->xops->do_xfer(ph, t);
|
||||||
|
|
||||||
|
ph->xops->xfer_put(ph, t);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scmi_powercap_pai_set(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain_id, u32 pai)
|
||||||
|
{
|
||||||
|
const struct scmi_powercap_info *pc;
|
||||||
|
|
||||||
|
pc = scmi_powercap_dom_info_get(ph, domain_id);
|
||||||
|
if (!pc || !pc->powercap_pai_config || !pai ||
|
||||||
|
pai < pc->min_pai || pai > pc->max_pai)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (pc->fc_info && pc->fc_info[POWERCAP_FC_PAI].set_addr) {
|
||||||
|
struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_PAI];
|
||||||
|
|
||||||
|
trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_SET,
|
||||||
|
domain_id, pai, 0);
|
||||||
|
iowrite32(pai, fci->set_addr);
|
||||||
|
ph->hops->fastchannel_db_ring(fci->set_db);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scmi_powercap_xfer_pai_set(ph, domain_id, pai);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scmi_powercap_measurements_get(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain_id, u32 *average_power,
|
||||||
|
u32 *pai)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct scmi_xfer *t;
|
||||||
|
struct scmi_msg_resp_powercap_meas_get *resp;
|
||||||
|
const struct scmi_powercap_info *pc;
|
||||||
|
|
||||||
|
pc = scmi_powercap_dom_info_get(ph, domain_id);
|
||||||
|
if (!pc || !pc->powercap_monitoring || !pai || !average_power)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ret = ph->xops->xfer_get_init(ph, POWERCAP_MEASUREMENTS_GET,
|
||||||
|
sizeof(u32), sizeof(*resp), &t);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
resp = t->rx.buf;
|
||||||
|
put_unaligned_le32(domain_id, t->tx.buf);
|
||||||
|
ret = ph->xops->do_xfer(ph, t);
|
||||||
|
if (!ret) {
|
||||||
|
*average_power = le32_to_cpu(resp->power);
|
||||||
|
*pai = le32_to_cpu(resp->pai);
|
||||||
|
}
|
||||||
|
|
||||||
|
ph->xops->xfer_put(ph, t);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
scmi_powercap_measurements_threshold_get(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain_id, u32 *power_thresh_low,
|
||||||
|
u32 *power_thresh_high)
|
||||||
|
{
|
||||||
|
struct powercap_info *pi = ph->get_priv(ph);
|
||||||
|
|
||||||
|
if (!power_thresh_low || !power_thresh_high ||
|
||||||
|
domain_id >= pi->num_domains)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
*power_thresh_low = THRESH_LOW(pi, domain_id);
|
||||||
|
*power_thresh_high = THRESH_HIGH(pi, domain_id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
scmi_powercap_measurements_threshold_set(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain_id, u32 power_thresh_low,
|
||||||
|
u32 power_thresh_high)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct powercap_info *pi = ph->get_priv(ph);
|
||||||
|
|
||||||
|
if (domain_id >= pi->num_domains ||
|
||||||
|
power_thresh_low > power_thresh_high)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Anything to do ? */
|
||||||
|
if (THRESH_LOW(pi, domain_id) == power_thresh_low &&
|
||||||
|
THRESH_HIGH(pi, domain_id) == power_thresh_high)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
pi->states[domain_id].thresholds =
|
||||||
|
(FIELD_PREP(GENMASK_ULL(31, 0), power_thresh_low) |
|
||||||
|
FIELD_PREP(GENMASK_ULL(63, 32), power_thresh_high));
|
||||||
|
|
||||||
|
/* Update thresholds if notification already enabled */
|
||||||
|
if (pi->states[domain_id].meas_notif_enabled)
|
||||||
|
ret = scmi_powercap_notify(ph, domain_id,
|
||||||
|
POWERCAP_MEASUREMENTS_NOTIFY,
|
||||||
|
true);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct scmi_powercap_proto_ops powercap_proto_ops = {
|
||||||
|
.num_domains_get = scmi_powercap_num_domains_get,
|
||||||
|
.info_get = scmi_powercap_dom_info_get,
|
||||||
|
.cap_get = scmi_powercap_cap_get,
|
||||||
|
.cap_set = scmi_powercap_cap_set,
|
||||||
|
.pai_get = scmi_powercap_pai_get,
|
||||||
|
.pai_set = scmi_powercap_pai_set,
|
||||||
|
.measurements_get = scmi_powercap_measurements_get,
|
||||||
|
.measurements_threshold_set = scmi_powercap_measurements_threshold_set,
|
||||||
|
.measurements_threshold_get = scmi_powercap_measurements_threshold_get,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void scmi_powercap_domain_init_fc(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain, struct scmi_fc_info **p_fc)
|
||||||
|
{
|
||||||
|
struct scmi_fc_info *fc;
|
||||||
|
|
||||||
|
fc = devm_kcalloc(ph->dev, POWERCAP_FC_MAX, sizeof(*fc), GFP_KERNEL);
|
||||||
|
if (!fc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
|
||||||
|
POWERCAP_CAP_SET, 4, domain,
|
||||||
|
&fc[POWERCAP_FC_CAP].set_addr,
|
||||||
|
&fc[POWERCAP_FC_CAP].set_db);
|
||||||
|
|
||||||
|
ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
|
||||||
|
POWERCAP_CAP_GET, 4, domain,
|
||||||
|
&fc[POWERCAP_FC_CAP].get_addr, NULL);
|
||||||
|
|
||||||
|
ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
|
||||||
|
POWERCAP_PAI_SET, 4, domain,
|
||||||
|
&fc[POWERCAP_FC_PAI].set_addr,
|
||||||
|
&fc[POWERCAP_FC_PAI].set_db);
|
||||||
|
|
||||||
|
ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
|
||||||
|
POWERCAP_PAI_GET, 4, domain,
|
||||||
|
&fc[POWERCAP_FC_PAI].get_addr, NULL);
|
||||||
|
|
||||||
|
*p_fc = fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
|
||||||
|
u32 domain, int message_id, bool enable)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct scmi_xfer *t;
|
||||||
|
|
||||||
|
switch (message_id) {
|
||||||
|
case POWERCAP_CAP_NOTIFY:
|
||||||
|
{
|
||||||
|
struct scmi_msg_powercap_notify_cap *notify;
|
||||||
|
|
||||||
|
ret = ph->xops->xfer_get_init(ph, message_id,
|
||||||
|
sizeof(*notify), 0, &t);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
notify = t->tx.buf;
|
||||||
|
notify->domain = cpu_to_le32(domain);
|
||||||
|
notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case POWERCAP_MEASUREMENTS_NOTIFY:
|
||||||
|
{
|
||||||
|
u32 low, high;
|
||||||
|
struct scmi_msg_powercap_notify_thresh *notify;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that we have to pick the most recently configured
|
||||||
|
* thresholds to build a proper POWERCAP_MEASUREMENTS_NOTIFY
|
||||||
|
* enable request and we fail, complaining, if no thresholds
|
||||||
|
* were ever set, since this is an indication the API has been
|
||||||
|
* used wrongly.
|
||||||
|
*/
|
||||||
|
ret = scmi_powercap_measurements_threshold_get(ph, domain,
|
||||||
|
&low, &high);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (enable && !low && !high) {
|
||||||
|
dev_err(ph->dev,
|
||||||
|
"Invalid Measurements Notify thresholds: %u/%u\n",
|
||||||
|
low, high);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ph->xops->xfer_get_init(ph, message_id,
|
||||||
|
sizeof(*notify), 0, &t);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
notify = t->tx.buf;
|
||||||
|
notify->domain = cpu_to_le32(domain);
|
||||||
|
notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
|
||||||
|
notify->power_thresh_low = cpu_to_le32(low);
|
||||||
|
notify->power_thresh_high = cpu_to_le32(high);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ph->xops->do_xfer(ph, t);
|
||||||
|
|
||||||
|
ph->xops->xfer_put(ph, t);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
scmi_powercap_set_notify_enabled(const struct scmi_protocol_handle *ph,
|
||||||
|
u8 evt_id, u32 src_id, bool enable)
|
||||||
|
{
|
||||||
|
int ret, cmd_id;
|
||||||
|
struct powercap_info *pi = ph->get_priv(ph);
|
||||||
|
|
||||||
|
if (evt_id >= ARRAY_SIZE(evt_2_cmd) || src_id >= pi->num_domains)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
cmd_id = evt_2_cmd[evt_id];
|
||||||
|
ret = scmi_powercap_notify(ph, src_id, cmd_id, enable);
|
||||||
|
if (ret)
|
||||||
|
pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
|
||||||
|
evt_id, src_id, ret);
|
||||||
|
else if (cmd_id == POWERCAP_MEASUREMENTS_NOTIFY)
|
||||||
|
/*
|
||||||
|
* On success save the current notification enabled state, so
|
||||||
|
* as to be able to properly update the notification thresholds
|
||||||
|
* when they are modified on a domain for which measurement
|
||||||
|
* notifications were currently enabled.
|
||||||
|
*
|
||||||
|
* This is needed because the SCMI Notification core machinery
|
||||||
|
* and API does not support passing per-notification custom
|
||||||
|
* arguments at callback registration time.
|
||||||
|
*
|
||||||
|
* Note that this can be done here with a simple flag since the
|
||||||
|
* SCMI core Notifications code takes care of keeping proper
|
||||||
|
* per-domain enables refcounting, so that this helper function
|
||||||
|
* will be called only once (for enables) when the first user
|
||||||
|
* registers a callback on this domain and once more (disable)
|
||||||
|
* when the last user de-registers its callback.
|
||||||
|
*/
|
||||||
|
pi->states[src_id].meas_notif_enabled = enable;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
scmi_powercap_fill_custom_report(const struct scmi_protocol_handle *ph,
|
||||||
|
u8 evt_id, ktime_t timestamp,
|
||||||
|
const void *payld, size_t payld_sz,
|
||||||
|
void *report, u32 *src_id)
|
||||||
|
{
|
||||||
|
void *rep = NULL;
|
||||||
|
|
||||||
|
switch (evt_id) {
|
||||||
|
case SCMI_EVENT_POWERCAP_CAP_CHANGED:
|
||||||
|
{
|
||||||
|
const struct scmi_powercap_cap_changed_notify_payld *p = payld;
|
||||||
|
struct scmi_powercap_cap_changed_report *r = report;
|
||||||
|
|
||||||
|
if (sizeof(*p) != payld_sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
r->timestamp = timestamp;
|
||||||
|
r->agent_id = le32_to_cpu(p->agent_id);
|
||||||
|
r->domain_id = le32_to_cpu(p->domain_id);
|
||||||
|
r->power_cap = le32_to_cpu(p->power_cap);
|
||||||
|
r->pai = le32_to_cpu(p->pai);
|
||||||
|
*src_id = r->domain_id;
|
||||||
|
rep = r;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED:
|
||||||
|
{
|
||||||
|
const struct scmi_powercap_meas_changed_notify_payld *p = payld;
|
||||||
|
struct scmi_powercap_meas_changed_report *r = report;
|
||||||
|
|
||||||
|
if (sizeof(*p) != payld_sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
r->timestamp = timestamp;
|
||||||
|
r->agent_id = le32_to_cpu(p->agent_id);
|
||||||
|
r->domain_id = le32_to_cpu(p->domain_id);
|
||||||
|
r->power = le32_to_cpu(p->power);
|
||||||
|
*src_id = r->domain_id;
|
||||||
|
rep = r;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rep;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
scmi_powercap_get_num_sources(const struct scmi_protocol_handle *ph)
|
||||||
|
{
|
||||||
|
struct powercap_info *pi = ph->get_priv(ph);
|
||||||
|
|
||||||
|
if (!pi)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return pi->num_domains;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct scmi_event powercap_events[] = {
|
||||||
|
{
|
||||||
|
.id = SCMI_EVENT_POWERCAP_CAP_CHANGED,
|
||||||
|
.max_payld_sz =
|
||||||
|
sizeof(struct scmi_powercap_cap_changed_notify_payld),
|
||||||
|
.max_report_sz =
|
||||||
|
sizeof(struct scmi_powercap_cap_changed_report),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED,
|
||||||
|
.max_payld_sz =
|
||||||
|
sizeof(struct scmi_powercap_meas_changed_notify_payld),
|
||||||
|
.max_report_sz =
|
||||||
|
sizeof(struct scmi_powercap_meas_changed_report),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct scmi_event_ops powercap_event_ops = {
|
||||||
|
.get_num_sources = scmi_powercap_get_num_sources,
|
||||||
|
.set_notify_enabled = scmi_powercap_set_notify_enabled,
|
||||||
|
.fill_custom_report = scmi_powercap_fill_custom_report,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct scmi_protocol_events powercap_protocol_events = {
|
||||||
|
.queue_sz = SCMI_PROTO_QUEUE_SZ,
|
||||||
|
.ops = &powercap_event_ops,
|
||||||
|
.evts = powercap_events,
|
||||||
|
.num_events = ARRAY_SIZE(powercap_events),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
|
||||||
|
{
|
||||||
|
int domain, ret;
|
||||||
|
u32 version;
|
||||||
|
struct powercap_info *pinfo;
|
||||||
|
|
||||||
|
ret = ph->xops->version_get(ph, &version);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
dev_dbg(ph->dev, "Powercap Version %d.%d\n",
|
||||||
|
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
|
||||||
|
|
||||||
|
pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
|
||||||
|
if (!pinfo)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = scmi_powercap_attributes_get(ph, pinfo);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
pinfo->powercaps = devm_kcalloc(ph->dev, pinfo->num_domains,
|
||||||
|
sizeof(*pinfo->powercaps),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!pinfo->powercaps)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that any failure in retrieving any domain attribute leads to
|
||||||
|
* the whole Powercap protocol initialization failure: this way the
|
||||||
|
* reported Powercap domains are all assured, when accessed, to be well
|
||||||
|
* formed and correlated by sane parent-child relationship (if any).
|
||||||
|
*/
|
||||||
|
for (domain = 0; domain < pinfo->num_domains; domain++) {
|
||||||
|
ret = scmi_powercap_domain_attributes_get(ph, pinfo, domain);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (pinfo->powercaps[domain].fastchannels)
|
||||||
|
scmi_powercap_domain_init_fc(ph, domain,
|
||||||
|
&pinfo->powercaps[domain].fc_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
pinfo->states = devm_kcalloc(ph->dev, pinfo->num_domains,
|
||||||
|
sizeof(*pinfo->states), GFP_KERNEL);
|
||||||
|
if (!pinfo->states)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
pinfo->version = version;
|
||||||
|
|
||||||
|
return ph->set_priv(ph, pinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct scmi_protocol scmi_powercap = {
|
||||||
|
.id = SCMI_PROTOCOL_POWERCAP,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.instance_init = &scmi_powercap_protocol_init,
|
||||||
|
.ops = &powercap_proto_ops,
|
||||||
|
.events = &powercap_protocol_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap)
|
||||||
@@ -215,6 +215,19 @@ struct scmi_iterator_ops {
|
|||||||
struct scmi_iterator_state *st, void *priv);
|
struct scmi_iterator_state *st, void *priv);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct scmi_fc_db_info {
|
||||||
|
int width;
|
||||||
|
u64 set;
|
||||||
|
u64 mask;
|
||||||
|
void __iomem *addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scmi_fc_info {
|
||||||
|
void __iomem *set_addr;
|
||||||
|
void __iomem *get_addr;
|
||||||
|
struct scmi_fc_db_info *set_db;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct scmi_proto_helpers_ops - References to common protocol helpers
|
* struct scmi_proto_helpers_ops - References to common protocol helpers
|
||||||
* @extended_name_get: A common helper function to retrieve extended naming
|
* @extended_name_get: A common helper function to retrieve extended naming
|
||||||
@@ -230,6 +243,9 @@ struct scmi_iterator_ops {
|
|||||||
* provided in @ops.
|
* provided in @ops.
|
||||||
* @iter_response_run: A common helper to trigger the run of a previously
|
* @iter_response_run: A common helper to trigger the run of a previously
|
||||||
* initialized iterator.
|
* initialized iterator.
|
||||||
|
* @fastchannel_init: A common helper used to initialize FC descriptors by
|
||||||
|
* gathering FC descriptions from the SCMI platform server.
|
||||||
|
* @fastchannel_db_ring: A common helper to ring a FC doorbell.
|
||||||
*/
|
*/
|
||||||
struct scmi_proto_helpers_ops {
|
struct scmi_proto_helpers_ops {
|
||||||
int (*extended_name_get)(const struct scmi_protocol_handle *ph,
|
int (*extended_name_get)(const struct scmi_protocol_handle *ph,
|
||||||
@@ -239,6 +255,12 @@ struct scmi_proto_helpers_ops {
|
|||||||
unsigned int max_resources, u8 msg_id,
|
unsigned int max_resources, u8 msg_id,
|
||||||
size_t tx_size, void *priv);
|
size_t tx_size, void *priv);
|
||||||
int (*iter_response_run)(void *iter);
|
int (*iter_response_run)(void *iter);
|
||||||
|
void (*fastchannel_init)(const struct scmi_protocol_handle *ph,
|
||||||
|
u8 describe_id, u32 message_id,
|
||||||
|
u32 valid_size, u32 domain,
|
||||||
|
void __iomem **p_addr,
|
||||||
|
struct scmi_fc_db_info **p_db);
|
||||||
|
void (*fastchannel_db_ring)(struct scmi_fc_db_info *db);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -315,5 +337,6 @@ DECLARE_SCMI_REGISTER_UNREGISTER(reset);
|
|||||||
DECLARE_SCMI_REGISTER_UNREGISTER(sensors);
|
DECLARE_SCMI_REGISTER_UNREGISTER(sensors);
|
||||||
DECLARE_SCMI_REGISTER_UNREGISTER(voltage);
|
DECLARE_SCMI_REGISTER_UNREGISTER(voltage);
|
||||||
DECLARE_SCMI_REGISTER_UNREGISTER(system);
|
DECLARE_SCMI_REGISTER_UNREGISTER(system);
|
||||||
|
DECLARE_SCMI_REGISTER_UNREGISTER(powercap);
|
||||||
|
|
||||||
#endif /* _SCMI_PROTOCOLS_H */
|
#endif /* _SCMI_PROTOCOLS_H */
|
||||||
|
|||||||
362
drivers/firmware/arm_scmi/scmi_power_control.c
Normal file
362
drivers/firmware/arm_scmi/scmi_power_control.c
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* SCMI Generic SystemPower Control driver.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020-2022 ARM Ltd.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* In order to handle platform originated SCMI SystemPower requests (like
|
||||||
|
* shutdowns or cold/warm resets) we register an SCMI Notification notifier
|
||||||
|
* block to react when such SCMI SystemPower events are emitted by platform.
|
||||||
|
*
|
||||||
|
* Once such a notification is received we act accordingly to perform the
|
||||||
|
* required system transition depending on the kind of request.
|
||||||
|
*
|
||||||
|
* Graceful requests are routed to userspace through the same API methods
|
||||||
|
* (orderly_poweroff/reboot()) used by ACPI when handling ACPI Shutdown bus
|
||||||
|
* events.
|
||||||
|
*
|
||||||
|
* Direct forceful requests are not supported since are not meant to be sent
|
||||||
|
* by the SCMI platform to an OSPM like Linux.
|
||||||
|
*
|
||||||
|
* Additionally, graceful request notifications can carry an optional timeout
|
||||||
|
* field stating the maximum amount of time allowed by the platform for
|
||||||
|
* completion after which they are converted to forceful ones: the assumption
|
||||||
|
* here is that even graceful requests can be upper-bound by a maximum final
|
||||||
|
* timeout strictly enforced by the platform itself which can ultimately cut
|
||||||
|
* the power off at will anytime; in order to avoid such extreme scenario, we
|
||||||
|
* track progress of graceful requests through the means of a reboot notifier
|
||||||
|
* converting timed-out graceful requests to forceful ones, so at least we
|
||||||
|
* try to perform a clean sync and shutdown/restart before the power is cut.
|
||||||
|
*
|
||||||
|
* Given the peculiar nature of SCMI SystemPower protocol, that is being in
|
||||||
|
* charge of triggering system wide shutdown/reboot events, there should be
|
||||||
|
* only one SCMI platform actively emitting SystemPower events.
|
||||||
|
* For this reason the SCMI core takes care to enforce the creation of one
|
||||||
|
* single unique device associated to the SCMI System Power protocol; no matter
|
||||||
|
* how many SCMI platforms are defined on the system, only one can be designated
|
||||||
|
* to support System Power: as a consequence this driver will never be probed
|
||||||
|
* more than once.
|
||||||
|
*
|
||||||
|
* For similar reasons as soon as the first valid SystemPower is received by
|
||||||
|
* this driver and the shutdown/reboot is started, any further notification
|
||||||
|
* possibly emitted by the platform will be ignored.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/math.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/printk.h>
|
||||||
|
#include <linux/reboot.h>
|
||||||
|
#include <linux/scmi_protocol.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/time64.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
|
#ifndef MODULE
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum scmi_syspower_state {
|
||||||
|
SCMI_SYSPOWER_IDLE,
|
||||||
|
SCMI_SYSPOWER_IN_PROGRESS,
|
||||||
|
SCMI_SYSPOWER_REBOOTING
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct scmi_syspower_conf - Common configuration
|
||||||
|
*
|
||||||
|
* @dev: A reference device
|
||||||
|
* @state: Current SystemPower state
|
||||||
|
* @state_mtx: @state related mutex
|
||||||
|
* @required_transition: The requested transition as decribed in the received
|
||||||
|
* SCMI SystemPower notification
|
||||||
|
* @userspace_nb: The notifier_block registered against the SCMI SystemPower
|
||||||
|
* notification to start the needed userspace interactions.
|
||||||
|
* @reboot_nb: A notifier_block optionally used to track reboot progress
|
||||||
|
* @forceful_work: A worker used to trigger a forceful transition once a
|
||||||
|
* graceful has timed out.
|
||||||
|
*/
|
||||||
|
struct scmi_syspower_conf {
|
||||||
|
struct device *dev;
|
||||||
|
enum scmi_syspower_state state;
|
||||||
|
/* Protect access to state */
|
||||||
|
struct mutex state_mtx;
|
||||||
|
enum scmi_system_events required_transition;
|
||||||
|
|
||||||
|
struct notifier_block userspace_nb;
|
||||||
|
struct notifier_block reboot_nb;
|
||||||
|
|
||||||
|
struct delayed_work forceful_work;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define userspace_nb_to_sconf(x) \
|
||||||
|
container_of(x, struct scmi_syspower_conf, userspace_nb)
|
||||||
|
|
||||||
|
#define reboot_nb_to_sconf(x) \
|
||||||
|
container_of(x, struct scmi_syspower_conf, reboot_nb)
|
||||||
|
|
||||||
|
#define dwork_to_sconf(x) \
|
||||||
|
container_of(x, struct scmi_syspower_conf, forceful_work)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scmi_reboot_notifier - A reboot notifier to catch an ongoing successful
|
||||||
|
* system transition
|
||||||
|
* @nb: Reference to the related notifier block
|
||||||
|
* @reason: The reason for the ongoing reboot
|
||||||
|
* @__unused: The cmd being executed on a restart request (unused)
|
||||||
|
*
|
||||||
|
* When an ongoing system transition is detected, compatible with the one
|
||||||
|
* requested by SCMI, cancel the delayed work.
|
||||||
|
*
|
||||||
|
* Return: NOTIFY_OK in any case
|
||||||
|
*/
|
||||||
|
static int scmi_reboot_notifier(struct notifier_block *nb,
|
||||||
|
unsigned long reason, void *__unused)
|
||||||
|
{
|
||||||
|
struct scmi_syspower_conf *sc = reboot_nb_to_sconf(nb);
|
||||||
|
|
||||||
|
mutex_lock(&sc->state_mtx);
|
||||||
|
switch (reason) {
|
||||||
|
case SYS_HALT:
|
||||||
|
case SYS_POWER_OFF:
|
||||||
|
if (sc->required_transition == SCMI_SYSTEM_SHUTDOWN)
|
||||||
|
sc->state = SCMI_SYSPOWER_REBOOTING;
|
||||||
|
break;
|
||||||
|
case SYS_RESTART:
|
||||||
|
if (sc->required_transition == SCMI_SYSTEM_COLDRESET ||
|
||||||
|
sc->required_transition == SCMI_SYSTEM_WARMRESET)
|
||||||
|
sc->state = SCMI_SYSPOWER_REBOOTING;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc->state == SCMI_SYSPOWER_REBOOTING) {
|
||||||
|
dev_dbg(sc->dev, "Reboot in progress...cancel delayed work.\n");
|
||||||
|
cancel_delayed_work_sync(&sc->forceful_work);
|
||||||
|
}
|
||||||
|
mutex_unlock(&sc->state_mtx);
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scmi_request_forceful_transition - Request forceful SystemPower transition
|
||||||
|
* @sc: A reference to the configuration data
|
||||||
|
*
|
||||||
|
* Initiates the required SystemPower transition without involving userspace:
|
||||||
|
* just trigger the action at the kernel level after issuing an emergency
|
||||||
|
* sync. (if possible at all)
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
scmi_request_forceful_transition(struct scmi_syspower_conf *sc)
|
||||||
|
{
|
||||||
|
dev_dbg(sc->dev, "Serving forceful request:%d\n",
|
||||||
|
sc->required_transition);
|
||||||
|
|
||||||
|
#ifndef MODULE
|
||||||
|
emergency_sync();
|
||||||
|
#endif
|
||||||
|
switch (sc->required_transition) {
|
||||||
|
case SCMI_SYSTEM_SHUTDOWN:
|
||||||
|
kernel_power_off();
|
||||||
|
break;
|
||||||
|
case SCMI_SYSTEM_COLDRESET:
|
||||||
|
case SCMI_SYSTEM_WARMRESET:
|
||||||
|
kernel_restart(NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scmi_forceful_work_func(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct scmi_syspower_conf *sc;
|
||||||
|
struct delayed_work *dwork;
|
||||||
|
|
||||||
|
if (system_state > SYSTEM_RUNNING)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dwork = to_delayed_work(work);
|
||||||
|
sc = dwork_to_sconf(dwork);
|
||||||
|
|
||||||
|
dev_dbg(sc->dev, "Graceful request timed out...forcing !\n");
|
||||||
|
mutex_lock(&sc->state_mtx);
|
||||||
|
/* avoid deadlock by unregistering reboot notifier first */
|
||||||
|
unregister_reboot_notifier(&sc->reboot_nb);
|
||||||
|
if (sc->state == SCMI_SYSPOWER_IN_PROGRESS)
|
||||||
|
scmi_request_forceful_transition(sc);
|
||||||
|
mutex_unlock(&sc->state_mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scmi_request_graceful_transition - Request graceful SystemPower transition
|
||||||
|
* @sc: A reference to the configuration data
|
||||||
|
* @timeout_ms: The desired timeout to wait for the shutdown to complete before
|
||||||
|
* system is forcibly shutdown.
|
||||||
|
*
|
||||||
|
* Initiates the required SystemPower transition, requesting userspace
|
||||||
|
* co-operation: it uses the same orderly_ methods used by ACPI Shutdown event
|
||||||
|
* processing.
|
||||||
|
*
|
||||||
|
* Takes care also to register a reboot notifier and to schedule a delayed work
|
||||||
|
* in order to detect if userspace actions are taking too long and in such a
|
||||||
|
* case to trigger a forceful transition.
|
||||||
|
*/
|
||||||
|
static void scmi_request_graceful_transition(struct scmi_syspower_conf *sc,
|
||||||
|
unsigned int timeout_ms)
|
||||||
|
{
|
||||||
|
unsigned int adj_timeout_ms = 0;
|
||||||
|
|
||||||
|
if (timeout_ms) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
sc->reboot_nb.notifier_call = &scmi_reboot_notifier;
|
||||||
|
ret = register_reboot_notifier(&sc->reboot_nb);
|
||||||
|
if (!ret) {
|
||||||
|
/* Wait only up to 75% of the advertised timeout */
|
||||||
|
adj_timeout_ms = mult_frac(timeout_ms, 3, 4);
|
||||||
|
INIT_DELAYED_WORK(&sc->forceful_work,
|
||||||
|
scmi_forceful_work_func);
|
||||||
|
schedule_delayed_work(&sc->forceful_work,
|
||||||
|
msecs_to_jiffies(adj_timeout_ms));
|
||||||
|
} else {
|
||||||
|
/* Carry on best effort even without a reboot notifier */
|
||||||
|
dev_warn(sc->dev,
|
||||||
|
"Cannot register reboot notifier !\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_dbg(sc->dev,
|
||||||
|
"Serving graceful req:%d (timeout_ms:%u adj_timeout_ms:%u)\n",
|
||||||
|
sc->required_transition, timeout_ms, adj_timeout_ms);
|
||||||
|
|
||||||
|
switch (sc->required_transition) {
|
||||||
|
case SCMI_SYSTEM_SHUTDOWN:
|
||||||
|
/*
|
||||||
|
* When triggered early at boot-time the 'orderly' call will
|
||||||
|
* partially fail due to the lack of userspace itself, but
|
||||||
|
* the force=true argument will start anyway a successful
|
||||||
|
* forced shutdown.
|
||||||
|
*/
|
||||||
|
orderly_poweroff(true);
|
||||||
|
break;
|
||||||
|
case SCMI_SYSTEM_COLDRESET:
|
||||||
|
case SCMI_SYSTEM_WARMRESET:
|
||||||
|
orderly_reboot();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scmi_userspace_notifier - Notifier callback to act on SystemPower
|
||||||
|
* Notifications
|
||||||
|
* @nb: Reference to the related notifier block
|
||||||
|
* @event: The SystemPower notification event id
|
||||||
|
* @data: The SystemPower event report
|
||||||
|
*
|
||||||
|
* This callback is in charge of decoding the received SystemPower report
|
||||||
|
* and act accordingly triggering a graceful or forceful system transition.
|
||||||
|
*
|
||||||
|
* Note that once a valid SCMI SystemPower event starts being served, any
|
||||||
|
* other following SystemPower notification received from the same SCMI
|
||||||
|
* instance (handle) will be ignored.
|
||||||
|
*
|
||||||
|
* Return: NOTIFY_OK once a valid SystemPower event has been successfully
|
||||||
|
* processed.
|
||||||
|
*/
|
||||||
|
static int scmi_userspace_notifier(struct notifier_block *nb,
|
||||||
|
unsigned long event, void *data)
|
||||||
|
{
|
||||||
|
struct scmi_system_power_state_notifier_report *er = data;
|
||||||
|
struct scmi_syspower_conf *sc = userspace_nb_to_sconf(nb);
|
||||||
|
|
||||||
|
if (er->system_state >= SCMI_SYSTEM_POWERUP) {
|
||||||
|
dev_err(sc->dev, "Ignoring unsupported system_state: 0x%X\n",
|
||||||
|
er->system_state);
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SCMI_SYSPOWER_IS_REQUEST_GRACEFUL(er->flags)) {
|
||||||
|
dev_err(sc->dev, "Ignoring forceful notification.\n");
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bail out if system is already shutting down or an SCMI SystemPower
|
||||||
|
* requested is already being served.
|
||||||
|
*/
|
||||||
|
if (system_state > SYSTEM_RUNNING)
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
mutex_lock(&sc->state_mtx);
|
||||||
|
if (sc->state != SCMI_SYSPOWER_IDLE) {
|
||||||
|
dev_dbg(sc->dev,
|
||||||
|
"Transition already in progress...ignore.\n");
|
||||||
|
mutex_unlock(&sc->state_mtx);
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
sc->state = SCMI_SYSPOWER_IN_PROGRESS;
|
||||||
|
mutex_unlock(&sc->state_mtx);
|
||||||
|
|
||||||
|
sc->required_transition = er->system_state;
|
||||||
|
|
||||||
|
/* Leaving a trace in logs of who triggered the shutdown/reboot. */
|
||||||
|
dev_info(sc->dev, "Serving shutdown/reboot request: %d\n",
|
||||||
|
sc->required_transition);
|
||||||
|
|
||||||
|
scmi_request_graceful_transition(sc, er->timeout);
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scmi_syspower_probe(struct scmi_device *sdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct scmi_syspower_conf *sc;
|
||||||
|
struct scmi_handle *handle = sdev->handle;
|
||||||
|
|
||||||
|
if (!handle)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
ret = handle->devm_protocol_acquire(sdev, SCMI_PROTOCOL_SYSTEM);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
sc = devm_kzalloc(&sdev->dev, sizeof(*sc), GFP_KERNEL);
|
||||||
|
if (!sc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
sc->state = SCMI_SYSPOWER_IDLE;
|
||||||
|
mutex_init(&sc->state_mtx);
|
||||||
|
sc->required_transition = SCMI_SYSTEM_MAX;
|
||||||
|
sc->userspace_nb.notifier_call = &scmi_userspace_notifier;
|
||||||
|
sc->dev = &sdev->dev;
|
||||||
|
|
||||||
|
return handle->notify_ops->devm_event_notifier_register(sdev,
|
||||||
|
SCMI_PROTOCOL_SYSTEM,
|
||||||
|
SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER,
|
||||||
|
NULL, &sc->userspace_nb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct scmi_device_id scmi_id_table[] = {
|
||||||
|
{ SCMI_PROTOCOL_SYSTEM, "syspower" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(scmi, scmi_id_table);
|
||||||
|
|
||||||
|
static struct scmi_driver scmi_system_power_driver = {
|
||||||
|
.name = "scmi-system-power",
|
||||||
|
.probe = scmi_syspower_probe,
|
||||||
|
.id_table = scmi_id_table,
|
||||||
|
};
|
||||||
|
module_scmi_driver(scmi_system_power_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Cristian Marussi <cristian.marussi@arm.com>");
|
||||||
|
MODULE_DESCRIPTION("ARM SCMI SystemPower Control driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
@@ -27,10 +27,12 @@ struct scmi_system_power_state_notifier_payld {
|
|||||||
__le32 agent_id;
|
__le32 agent_id;
|
||||||
__le32 flags;
|
__le32 flags;
|
||||||
__le32 system_state;
|
__le32 system_state;
|
||||||
|
__le32 timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scmi_system_info {
|
struct scmi_system_info {
|
||||||
u32 version;
|
u32 version;
|
||||||
|
bool graceful_timeout_supported;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int scmi_system_request_notify(const struct scmi_protocol_handle *ph,
|
static int scmi_system_request_notify(const struct scmi_protocol_handle *ph,
|
||||||
@@ -72,17 +74,27 @@ scmi_system_fill_custom_report(const struct scmi_protocol_handle *ph,
|
|||||||
const void *payld, size_t payld_sz,
|
const void *payld, size_t payld_sz,
|
||||||
void *report, u32 *src_id)
|
void *report, u32 *src_id)
|
||||||
{
|
{
|
||||||
|
size_t expected_sz;
|
||||||
const struct scmi_system_power_state_notifier_payld *p = payld;
|
const struct scmi_system_power_state_notifier_payld *p = payld;
|
||||||
struct scmi_system_power_state_notifier_report *r = report;
|
struct scmi_system_power_state_notifier_report *r = report;
|
||||||
|
struct scmi_system_info *pinfo = ph->get_priv(ph);
|
||||||
|
|
||||||
|
expected_sz = pinfo->graceful_timeout_supported ?
|
||||||
|
sizeof(*p) : sizeof(*p) - sizeof(__le32);
|
||||||
if (evt_id != SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER ||
|
if (evt_id != SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER ||
|
||||||
sizeof(*p) != payld_sz)
|
payld_sz != expected_sz)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
r->timestamp = timestamp;
|
r->timestamp = timestamp;
|
||||||
r->agent_id = le32_to_cpu(p->agent_id);
|
r->agent_id = le32_to_cpu(p->agent_id);
|
||||||
r->flags = le32_to_cpu(p->flags);
|
r->flags = le32_to_cpu(p->flags);
|
||||||
r->system_state = le32_to_cpu(p->system_state);
|
r->system_state = le32_to_cpu(p->system_state);
|
||||||
|
if (pinfo->graceful_timeout_supported &&
|
||||||
|
r->system_state == SCMI_SYSTEM_SHUTDOWN &&
|
||||||
|
SCMI_SYSPOWER_IS_REQUEST_GRACEFUL(r->flags))
|
||||||
|
r->timeout = le32_to_cpu(p->timeout);
|
||||||
|
else
|
||||||
|
r->timeout = 0x00;
|
||||||
*src_id = 0;
|
*src_id = 0;
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
@@ -129,6 +141,9 @@ static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
pinfo->version = version;
|
pinfo->version = version;
|
||||||
|
if (PROTOCOL_REV_MAJOR(pinfo->version) >= 0x2)
|
||||||
|
pinfo->graceful_timeout_supported = true;
|
||||||
|
|
||||||
return ph->set_priv(ph, pinfo);
|
return ph->set_priv(ph, pinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -815,7 +815,7 @@ static int scpi_init_versions(struct scpi_drvinfo *info)
|
|||||||
info->firmware_version = le32_to_cpu(caps.platform_version);
|
info->firmware_version = le32_to_cpu(caps.platform_version);
|
||||||
}
|
}
|
||||||
/* Ignore error if not implemented */
|
/* Ignore error if not implemented */
|
||||||
if (scpi_info->is_legacy && ret == -EOPNOTSUPP)
|
if (info->is_legacy && ret == -EOPNOTSUPP)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -913,13 +913,14 @@ static int scpi_probe(struct platform_device *pdev)
|
|||||||
struct resource res;
|
struct resource res;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct device_node *np = dev->of_node;
|
struct device_node *np = dev->of_node;
|
||||||
|
struct scpi_drvinfo *scpi_drvinfo;
|
||||||
|
|
||||||
scpi_info = devm_kzalloc(dev, sizeof(*scpi_info), GFP_KERNEL);
|
scpi_drvinfo = devm_kzalloc(dev, sizeof(*scpi_drvinfo), GFP_KERNEL);
|
||||||
if (!scpi_info)
|
if (!scpi_drvinfo)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (of_match_device(legacy_scpi_of_match, &pdev->dev))
|
if (of_match_device(legacy_scpi_of_match, &pdev->dev))
|
||||||
scpi_info->is_legacy = true;
|
scpi_drvinfo->is_legacy = true;
|
||||||
|
|
||||||
count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells");
|
count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells");
|
||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
@@ -927,19 +928,19 @@ static int scpi_probe(struct platform_device *pdev)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
scpi_info->channels = devm_kcalloc(dev, count, sizeof(struct scpi_chan),
|
scpi_drvinfo->channels =
|
||||||
GFP_KERNEL);
|
devm_kcalloc(dev, count, sizeof(struct scpi_chan), GFP_KERNEL);
|
||||||
if (!scpi_info->channels)
|
if (!scpi_drvinfo->channels)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = devm_add_action(dev, scpi_free_channels, scpi_info);
|
ret = devm_add_action(dev, scpi_free_channels, scpi_drvinfo);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
for (; scpi_info->num_chans < count; scpi_info->num_chans++) {
|
for (; scpi_drvinfo->num_chans < count; scpi_drvinfo->num_chans++) {
|
||||||
resource_size_t size;
|
resource_size_t size;
|
||||||
int idx = scpi_info->num_chans;
|
int idx = scpi_drvinfo->num_chans;
|
||||||
struct scpi_chan *pchan = scpi_info->channels + idx;
|
struct scpi_chan *pchan = scpi_drvinfo->channels + idx;
|
||||||
struct mbox_client *cl = &pchan->cl;
|
struct mbox_client *cl = &pchan->cl;
|
||||||
struct device_node *shmem = of_parse_phandle(np, "shmem", idx);
|
struct device_node *shmem = of_parse_phandle(np, "shmem", idx);
|
||||||
|
|
||||||
@@ -986,45 +987,53 @@ static int scpi_probe(struct platform_device *pdev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
scpi_info->commands = scpi_std_commands;
|
scpi_drvinfo->commands = scpi_std_commands;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, scpi_info);
|
platform_set_drvdata(pdev, scpi_drvinfo);
|
||||||
|
|
||||||
if (scpi_info->is_legacy) {
|
if (scpi_drvinfo->is_legacy) {
|
||||||
/* Replace with legacy variants */
|
/* Replace with legacy variants */
|
||||||
scpi_ops.clk_set_val = legacy_scpi_clk_set_val;
|
scpi_ops.clk_set_val = legacy_scpi_clk_set_val;
|
||||||
scpi_info->commands = scpi_legacy_commands;
|
scpi_drvinfo->commands = scpi_legacy_commands;
|
||||||
|
|
||||||
/* Fill priority bitmap */
|
/* Fill priority bitmap */
|
||||||
for (idx = 0; idx < ARRAY_SIZE(legacy_hpriority_cmds); idx++)
|
for (idx = 0; idx < ARRAY_SIZE(legacy_hpriority_cmds); idx++)
|
||||||
set_bit(legacy_hpriority_cmds[idx],
|
set_bit(legacy_hpriority_cmds[idx],
|
||||||
scpi_info->cmd_priority);
|
scpi_drvinfo->cmd_priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = scpi_init_versions(scpi_info);
|
scpi_info = scpi_drvinfo;
|
||||||
|
|
||||||
|
ret = scpi_init_versions(scpi_drvinfo);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "incorrect or no SCP firmware found\n");
|
dev_err(dev, "incorrect or no SCP firmware found\n");
|
||||||
|
scpi_info = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scpi_info->is_legacy && !scpi_info->protocol_version &&
|
if (scpi_drvinfo->is_legacy && !scpi_drvinfo->protocol_version &&
|
||||||
!scpi_info->firmware_version)
|
!scpi_drvinfo->firmware_version)
|
||||||
dev_info(dev, "SCP Protocol legacy pre-1.0 firmware\n");
|
dev_info(dev, "SCP Protocol legacy pre-1.0 firmware\n");
|
||||||
else
|
else
|
||||||
dev_info(dev, "SCP Protocol %lu.%lu Firmware %lu.%lu.%lu version\n",
|
dev_info(dev, "SCP Protocol %lu.%lu Firmware %lu.%lu.%lu version\n",
|
||||||
FIELD_GET(PROTO_REV_MAJOR_MASK,
|
FIELD_GET(PROTO_REV_MAJOR_MASK,
|
||||||
scpi_info->protocol_version),
|
scpi_drvinfo->protocol_version),
|
||||||
FIELD_GET(PROTO_REV_MINOR_MASK,
|
FIELD_GET(PROTO_REV_MINOR_MASK,
|
||||||
scpi_info->protocol_version),
|
scpi_drvinfo->protocol_version),
|
||||||
FIELD_GET(FW_REV_MAJOR_MASK,
|
FIELD_GET(FW_REV_MAJOR_MASK,
|
||||||
scpi_info->firmware_version),
|
scpi_drvinfo->firmware_version),
|
||||||
FIELD_GET(FW_REV_MINOR_MASK,
|
FIELD_GET(FW_REV_MINOR_MASK,
|
||||||
scpi_info->firmware_version),
|
scpi_drvinfo->firmware_version),
|
||||||
FIELD_GET(FW_REV_PATCH_MASK,
|
FIELD_GET(FW_REV_PATCH_MASK,
|
||||||
scpi_info->firmware_version));
|
scpi_drvinfo->firmware_version));
|
||||||
scpi_info->scpi_ops = &scpi_ops;
|
|
||||||
|
|
||||||
return devm_of_platform_populate(dev);
|
scpi_drvinfo->scpi_ops = &scpi_ops;
|
||||||
|
|
||||||
|
ret = devm_of_platform_populate(dev);
|
||||||
|
if (ret)
|
||||||
|
scpi_info = NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id scpi_of_match[] = {
|
static const struct of_device_id scpi_of_match[] = {
|
||||||
|
|||||||
@@ -120,6 +120,9 @@ static void __scm_legacy_do(const struct arm_smccc_args *smc,
|
|||||||
/**
|
/**
|
||||||
* scm_legacy_call() - Sends a command to the SCM and waits for the command to
|
* scm_legacy_call() - Sends a command to the SCM and waits for the command to
|
||||||
* finish processing.
|
* finish processing.
|
||||||
|
* @dev: device
|
||||||
|
* @desc: descriptor structure containing arguments and return values
|
||||||
|
* @res: results from SMC call
|
||||||
*
|
*
|
||||||
* A note on cache maintenance:
|
* A note on cache maintenance:
|
||||||
* Note that any buffers that are expected to be accessed by the secure world
|
* Note that any buffers that are expected to be accessed by the secure world
|
||||||
@@ -211,6 +214,7 @@ out:
|
|||||||
/**
|
/**
|
||||||
* scm_legacy_call_atomic() - Send an atomic SCM command with up to 5 arguments
|
* scm_legacy_call_atomic() - Send an atomic SCM command with up to 5 arguments
|
||||||
* and 3 return values
|
* and 3 return values
|
||||||
|
* @unused: device, legacy argument, not used, can be NULL
|
||||||
* @desc: SCM call descriptor containing arguments
|
* @desc: SCM call descriptor containing arguments
|
||||||
* @res: SCM call return values
|
* @res: SCM call return values
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <linux/cpumask.h>
|
#include <linux/cpumask.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/interconnect.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/qcom_scm.h>
|
#include <linux/qcom_scm.h>
|
||||||
@@ -31,8 +32,13 @@ struct qcom_scm {
|
|||||||
struct clk *core_clk;
|
struct clk *core_clk;
|
||||||
struct clk *iface_clk;
|
struct clk *iface_clk;
|
||||||
struct clk *bus_clk;
|
struct clk *bus_clk;
|
||||||
|
struct icc_path *path;
|
||||||
struct reset_controller_dev reset;
|
struct reset_controller_dev reset;
|
||||||
|
|
||||||
|
/* control access to the interconnect path */
|
||||||
|
struct mutex scm_bw_lock;
|
||||||
|
int scm_vote_count;
|
||||||
|
|
||||||
u64 dload_mode_addr;
|
u64 dload_mode_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -99,6 +105,42 @@ static void qcom_scm_clk_disable(void)
|
|||||||
clk_disable_unprepare(__scm->bus_clk);
|
clk_disable_unprepare(__scm->bus_clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qcom_scm_bw_enable(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!__scm->path)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (IS_ERR(__scm->path))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&__scm->scm_bw_lock);
|
||||||
|
if (!__scm->scm_vote_count) {
|
||||||
|
ret = icc_set_bw(__scm->path, 0, UINT_MAX);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(__scm->dev, "failed to set bandwidth request\n");
|
||||||
|
goto err_bw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__scm->scm_vote_count++;
|
||||||
|
err_bw:
|
||||||
|
mutex_unlock(&__scm->scm_bw_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcom_scm_bw_disable(void)
|
||||||
|
{
|
||||||
|
if (IS_ERR_OR_NULL(__scm->path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mutex_lock(&__scm->scm_bw_lock);
|
||||||
|
if (__scm->scm_vote_count-- == 1)
|
||||||
|
icc_set_bw(__scm->path, 0, 0);
|
||||||
|
mutex_unlock(&__scm->scm_bw_lock);
|
||||||
|
}
|
||||||
|
|
||||||
enum qcom_scm_convention qcom_scm_convention = SMC_CONVENTION_UNKNOWN;
|
enum qcom_scm_convention qcom_scm_convention = SMC_CONVENTION_UNKNOWN;
|
||||||
static DEFINE_SPINLOCK(scm_query_lock);
|
static DEFINE_SPINLOCK(scm_query_lock);
|
||||||
|
|
||||||
@@ -444,10 +486,15 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size,
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
ret = qcom_scm_bw_enable();
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
desc.args[1] = mdata_phys;
|
desc.args[1] = mdata_phys;
|
||||||
|
|
||||||
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
||||||
|
|
||||||
|
qcom_scm_bw_disable();
|
||||||
qcom_scm_clk_disable();
|
qcom_scm_clk_disable();
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@@ -507,7 +554,12 @@ int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = qcom_scm_bw_enable();
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
||||||
|
qcom_scm_bw_disable();
|
||||||
qcom_scm_clk_disable();
|
qcom_scm_clk_disable();
|
||||||
|
|
||||||
return ret ? : res.result[0];
|
return ret ? : res.result[0];
|
||||||
@@ -537,7 +589,12 @@ int qcom_scm_pas_auth_and_reset(u32 peripheral)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = qcom_scm_bw_enable();
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
||||||
|
qcom_scm_bw_disable();
|
||||||
qcom_scm_clk_disable();
|
qcom_scm_clk_disable();
|
||||||
|
|
||||||
return ret ? : res.result[0];
|
return ret ? : res.result[0];
|
||||||
@@ -566,8 +623,13 @@ int qcom_scm_pas_shutdown(u32 peripheral)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = qcom_scm_bw_enable();
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
ret = qcom_scm_call(__scm->dev, &desc, &res);
|
||||||
|
|
||||||
|
qcom_scm_bw_disable();
|
||||||
qcom_scm_clk_disable();
|
qcom_scm_clk_disable();
|
||||||
|
|
||||||
return ret ? : res.result[0];
|
return ret ? : res.result[0];
|
||||||
@@ -1277,8 +1339,15 @@ static int qcom_scm_probe(struct platform_device *pdev)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
mutex_init(&scm->scm_bw_lock);
|
||||||
|
|
||||||
clks = (unsigned long)of_device_get_match_data(&pdev->dev);
|
clks = (unsigned long)of_device_get_match_data(&pdev->dev);
|
||||||
|
|
||||||
|
scm->path = devm_of_icc_get(&pdev->dev, NULL);
|
||||||
|
if (IS_ERR(scm->path))
|
||||||
|
return dev_err_probe(&pdev->dev, PTR_ERR(scm->path),
|
||||||
|
"failed to acquire interconnect path\n");
|
||||||
|
|
||||||
scm->core_clk = devm_clk_get(&pdev->dev, "core");
|
scm->core_clk = devm_clk_get(&pdev->dev, "core");
|
||||||
if (IS_ERR(scm->core_clk)) {
|
if (IS_ERR(scm->core_clk)) {
|
||||||
if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER)
|
if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER)
|
||||||
@@ -1337,7 +1406,7 @@ static int qcom_scm_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If requested enable "download mode", from this point on warmboot
|
* If requested enable "download mode", from this point on warmboot
|
||||||
* will cause the the boot stages to enter download mode, unless
|
* will cause the boot stages to enter download mode, unless
|
||||||
* disabled below by a clean shutdown/reboot.
|
* disabled below by a clean shutdown/reboot.
|
||||||
*/
|
*/
|
||||||
if (download_mode)
|
if (download_mode)
|
||||||
|
|||||||
@@ -474,7 +474,7 @@ static int bpmp_populate_debugfs_inband(struct tegra_bpmp *bpmp,
|
|||||||
mode |= attrs & DEBUGFS_S_IWUSR ? 0200 : 0;
|
mode |= attrs & DEBUGFS_S_IWUSR ? 0200 : 0;
|
||||||
dentry = debugfs_create_file(name, mode, parent, bpmp,
|
dentry = debugfs_create_file(name, mode, parent, bpmp,
|
||||||
&bpmp_debug_fops);
|
&bpmp_debug_fops);
|
||||||
if (!dentry) {
|
if (IS_ERR(dentry)) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -725,7 +725,7 @@ static int bpmp_populate_dir(struct tegra_bpmp *bpmp, struct seqbuf *seqbuf,
|
|||||||
|
|
||||||
if (t & DEBUGFS_S_ISDIR) {
|
if (t & DEBUGFS_S_ISDIR) {
|
||||||
dentry = debugfs_create_dir(name, parent);
|
dentry = debugfs_create_dir(name, parent);
|
||||||
if (!dentry)
|
if (IS_ERR(dentry))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
err = bpmp_populate_dir(bpmp, seqbuf, dentry, depth+1);
|
err = bpmp_populate_dir(bpmp, seqbuf, dentry, depth+1);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
@@ -738,7 +738,7 @@ static int bpmp_populate_dir(struct tegra_bpmp *bpmp, struct seqbuf *seqbuf,
|
|||||||
dentry = debugfs_create_file(name, mode,
|
dentry = debugfs_create_file(name, mode,
|
||||||
parent, bpmp,
|
parent, bpmp,
|
||||||
&debugfs_fops);
|
&debugfs_fops);
|
||||||
if (!dentry)
|
if (IS_ERR(dentry))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -788,11 +788,11 @@ int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
root = debugfs_create_dir("bpmp", NULL);
|
root = debugfs_create_dir("bpmp", NULL);
|
||||||
if (!root)
|
if (IS_ERR(root))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
bpmp->debugfs_mirror = debugfs_create_dir("debug", root);
|
bpmp->debugfs_mirror = debugfs_create_dir("debug", root);
|
||||||
if (!bpmp->debugfs_mirror) {
|
if (IS_ERR(bpmp->debugfs_mirror)) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ static ssize_t __tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel,
|
|||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (data && size > 0)
|
if (data && size > 0)
|
||||||
memcpy(data, channel->ib->data, size);
|
memcpy_fromio(data, channel->ib->data, size);
|
||||||
|
|
||||||
err = tegra_bpmp_ack_response(channel);
|
err = tegra_bpmp_ack_response(channel);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
@@ -245,7 +245,7 @@ static ssize_t __tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel,
|
|||||||
channel->ob->flags = flags;
|
channel->ob->flags = flags;
|
||||||
|
|
||||||
if (data && size > 0)
|
if (data && size > 0)
|
||||||
memcpy(channel->ob->data, data, size);
|
memcpy_toio(channel->ob->data, data, size);
|
||||||
|
|
||||||
return tegra_bpmp_post_request(channel);
|
return tegra_bpmp_post_request(channel);
|
||||||
}
|
}
|
||||||
@@ -420,7 +420,7 @@ void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, int code,
|
|||||||
channel->ob->code = code;
|
channel->ob->code = code;
|
||||||
|
|
||||||
if (data && size > 0)
|
if (data && size > 0)
|
||||||
memcpy(channel->ob->data, data, size);
|
memcpy_toio(channel->ob->data, data, size);
|
||||||
|
|
||||||
err = tegra_bpmp_post_response(channel);
|
err = tegra_bpmp_post_response(channel);
|
||||||
if (WARN_ON(err < 0))
|
if (WARN_ON(err < 0))
|
||||||
|
|||||||
@@ -486,7 +486,7 @@ config I2C_BCM_KONA
|
|||||||
|
|
||||||
config I2C_BRCMSTB
|
config I2C_BRCMSTB
|
||||||
tristate "BRCM Settop/DSL I2C controller"
|
tristate "BRCM Settop/DSL I2C controller"
|
||||||
depends on ARCH_BCM2835 || ARCH_BCM4908 || ARCH_BCM_63XX || \
|
depends on ARCH_BCM2835 || ARCH_BCM4908 || ARCH_BCMBCA || \
|
||||||
ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
|
ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
|
|||||||
@@ -21,11 +21,13 @@
|
|||||||
/* SMI COMMON */
|
/* SMI COMMON */
|
||||||
#define SMI_L1LEN 0x100
|
#define SMI_L1LEN 0x100
|
||||||
|
|
||||||
|
#define SMI_L1_ARB 0x200
|
||||||
#define SMI_BUS_SEL 0x220
|
#define SMI_BUS_SEL 0x220
|
||||||
#define SMI_BUS_LARB_SHIFT(larbid) ((larbid) << 1)
|
#define SMI_BUS_LARB_SHIFT(larbid) ((larbid) << 1)
|
||||||
/* All are MMU0 defaultly. Only specialize mmu1 here. */
|
/* All are MMU0 defaultly. Only specialize mmu1 here. */
|
||||||
#define F_MMU1_LARB(larbid) (0x1 << SMI_BUS_LARB_SHIFT(larbid))
|
#define F_MMU1_LARB(larbid) (0x1 << SMI_BUS_LARB_SHIFT(larbid))
|
||||||
|
|
||||||
|
#define SMI_READ_FIFO_TH 0x230
|
||||||
#define SMI_M4U_TH 0x234
|
#define SMI_M4U_TH 0x234
|
||||||
#define SMI_FIFO_TH1 0x238
|
#define SMI_FIFO_TH1 0x238
|
||||||
#define SMI_FIFO_TH2 0x23c
|
#define SMI_FIFO_TH2 0x23c
|
||||||
@@ -360,6 +362,7 @@ static const struct of_device_id mtk_smi_larb_of_ids[] = {
|
|||||||
{.compatible = "mediatek,mt2701-smi-larb", .data = &mtk_smi_larb_mt2701},
|
{.compatible = "mediatek,mt2701-smi-larb", .data = &mtk_smi_larb_mt2701},
|
||||||
{.compatible = "mediatek,mt2712-smi-larb", .data = &mtk_smi_larb_mt2712},
|
{.compatible = "mediatek,mt2712-smi-larb", .data = &mtk_smi_larb_mt2712},
|
||||||
{.compatible = "mediatek,mt6779-smi-larb", .data = &mtk_smi_larb_mt6779},
|
{.compatible = "mediatek,mt6779-smi-larb", .data = &mtk_smi_larb_mt6779},
|
||||||
|
{.compatible = "mediatek,mt6795-smi-larb", .data = &mtk_smi_larb_mt8173},
|
||||||
{.compatible = "mediatek,mt8167-smi-larb", .data = &mtk_smi_larb_mt8167},
|
{.compatible = "mediatek,mt8167-smi-larb", .data = &mtk_smi_larb_mt8167},
|
||||||
{.compatible = "mediatek,mt8173-smi-larb", .data = &mtk_smi_larb_mt8173},
|
{.compatible = "mediatek,mt8173-smi-larb", .data = &mtk_smi_larb_mt8173},
|
||||||
{.compatible = "mediatek,mt8183-smi-larb", .data = &mtk_smi_larb_mt8183},
|
{.compatible = "mediatek,mt8183-smi-larb", .data = &mtk_smi_larb_mt8183},
|
||||||
@@ -544,6 +547,13 @@ static struct platform_driver mtk_smi_larb_driver = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct mtk_smi_reg_pair mtk_smi_common_mt6795_init[SMI_COMMON_INIT_REGS_NR] = {
|
||||||
|
{SMI_L1_ARB, 0x1b},
|
||||||
|
{SMI_M4U_TH, 0xce810c85},
|
||||||
|
{SMI_FIFO_TH1, 0x43214c8},
|
||||||
|
{SMI_READ_FIFO_TH, 0x191f},
|
||||||
|
};
|
||||||
|
|
||||||
static const struct mtk_smi_reg_pair mtk_smi_common_mt8195_init[SMI_COMMON_INIT_REGS_NR] = {
|
static const struct mtk_smi_reg_pair mtk_smi_common_mt8195_init[SMI_COMMON_INIT_REGS_NR] = {
|
||||||
{SMI_L1LEN, 0xb},
|
{SMI_L1LEN, 0xb},
|
||||||
{SMI_M4U_TH, 0xe100e10},
|
{SMI_M4U_TH, 0xe100e10},
|
||||||
@@ -568,6 +578,12 @@ static const struct mtk_smi_common_plat mtk_smi_common_mt6779 = {
|
|||||||
F_MMU1_LARB(5) | F_MMU1_LARB(6) | F_MMU1_LARB(7),
|
F_MMU1_LARB(5) | F_MMU1_LARB(6) | F_MMU1_LARB(7),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct mtk_smi_common_plat mtk_smi_common_mt6795 = {
|
||||||
|
.type = MTK_SMI_GEN2,
|
||||||
|
.bus_sel = F_MMU1_LARB(0),
|
||||||
|
.init = mtk_smi_common_mt6795_init,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct mtk_smi_common_plat mtk_smi_common_mt8183 = {
|
static const struct mtk_smi_common_plat mtk_smi_common_mt8183 = {
|
||||||
.type = MTK_SMI_GEN2,
|
.type = MTK_SMI_GEN2,
|
||||||
.has_gals = true,
|
.has_gals = true,
|
||||||
@@ -612,6 +628,7 @@ static const struct of_device_id mtk_smi_common_of_ids[] = {
|
|||||||
{.compatible = "mediatek,mt2701-smi-common", .data = &mtk_smi_common_gen1},
|
{.compatible = "mediatek,mt2701-smi-common", .data = &mtk_smi_common_gen1},
|
||||||
{.compatible = "mediatek,mt2712-smi-common", .data = &mtk_smi_common_gen2},
|
{.compatible = "mediatek,mt2712-smi-common", .data = &mtk_smi_common_gen2},
|
||||||
{.compatible = "mediatek,mt6779-smi-common", .data = &mtk_smi_common_mt6779},
|
{.compatible = "mediatek,mt6779-smi-common", .data = &mtk_smi_common_mt6779},
|
||||||
|
{.compatible = "mediatek,mt6795-smi-common", .data = &mtk_smi_common_mt6795},
|
||||||
{.compatible = "mediatek,mt8167-smi-common", .data = &mtk_smi_common_gen2},
|
{.compatible = "mediatek,mt8167-smi-common", .data = &mtk_smi_common_gen2},
|
||||||
{.compatible = "mediatek,mt8173-smi-common", .data = &mtk_smi_common_gen2},
|
{.compatible = "mediatek,mt8173-smi-common", .data = &mtk_smi_common_gen2},
|
||||||
{.compatible = "mediatek,mt8183-smi-common", .data = &mtk_smi_common_mt8183},
|
{.compatible = "mediatek,mt8183-smi-common", .data = &mtk_smi_common_mt8183},
|
||||||
|
|||||||
@@ -11,6 +11,76 @@
|
|||||||
|
|
||||||
static const struct tegra_mc_client tegra234_mc_clients[] = {
|
static const struct tegra_mc_client tegra234_mc_clients[] = {
|
||||||
{
|
{
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_MGBEARD,
|
||||||
|
.name = "mgbeard",
|
||||||
|
.sid = TEGRA234_SID_MGBE,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x2c0,
|
||||||
|
.security = 0x2c4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_MGBEBRD,
|
||||||
|
.name = "mgbebrd",
|
||||||
|
.sid = TEGRA234_SID_MGBE_VF1,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x2c8,
|
||||||
|
.security = 0x2cc,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_MGBECRD,
|
||||||
|
.name = "mgbecrd",
|
||||||
|
.sid = TEGRA234_SID_MGBE_VF2,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x2d0,
|
||||||
|
.security = 0x2d4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_MGBEDRD,
|
||||||
|
.name = "mgbedrd",
|
||||||
|
.sid = TEGRA234_SID_MGBE_VF3,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x2d8,
|
||||||
|
.security = 0x2dc,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_MGBEAWR,
|
||||||
|
.name = "mgbeawr",
|
||||||
|
.sid = TEGRA234_SID_MGBE,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x2e0,
|
||||||
|
.security = 0x2e4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_MGBEBWR,
|
||||||
|
.name = "mgbebwr",
|
||||||
|
.sid = TEGRA234_SID_MGBE_VF1,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x2f8,
|
||||||
|
.security = 0x2fc,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_MGBECWR,
|
||||||
|
.name = "mgbecwr",
|
||||||
|
.sid = TEGRA234_SID_MGBE_VF2,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x308,
|
||||||
|
.security = 0x30c,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
.id = TEGRA234_MEMORY_CLIENT_SDMMCRAB,
|
.id = TEGRA234_MEMORY_CLIENT_SDMMCRAB,
|
||||||
.name = "sdmmcrab",
|
.name = "sdmmcrab",
|
||||||
.sid = TEGRA234_SID_SDMMC4,
|
.sid = TEGRA234_SID_SDMMC4,
|
||||||
@@ -20,6 +90,16 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
|
|||||||
.security = 0x31c,
|
.security = 0x31c,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_MGBEDWR,
|
||||||
|
.name = "mgbedwr",
|
||||||
|
.sid = TEGRA234_SID_MGBE_VF3,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x328,
|
||||||
|
.security = 0x32c,
|
||||||
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
.id = TEGRA234_MEMORY_CLIENT_SDMMCWAB,
|
.id = TEGRA234_MEMORY_CLIENT_SDMMCWAB,
|
||||||
.name = "sdmmcwab",
|
.name = "sdmmcwab",
|
||||||
|
|||||||
@@ -25,9 +25,52 @@ static const struct mfd_cell bcm2835_power_devs[] = {
|
|||||||
{ .name = "bcm2835-power" },
|
{ .name = "bcm2835-power" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int bcm2835_pm_get_pdata(struct platform_device *pdev,
|
||||||
|
struct bcm2835_pm *pm)
|
||||||
|
{
|
||||||
|
if (of_find_property(pm->dev->of_node, "reg-names", NULL)) {
|
||||||
|
struct resource *res;
|
||||||
|
|
||||||
|
pm->base = devm_platform_ioremap_resource_byname(pdev, "pm");
|
||||||
|
if (IS_ERR(pm->base))
|
||||||
|
return PTR_ERR(pm->base);
|
||||||
|
|
||||||
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "asb");
|
||||||
|
if (res) {
|
||||||
|
pm->asb = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
if (IS_ERR(pm->asb))
|
||||||
|
pm->asb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||||
|
"rpivid_asb");
|
||||||
|
if (res) {
|
||||||
|
pm->rpivid_asb = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
if (IS_ERR(pm->rpivid_asb))
|
||||||
|
pm->rpivid_asb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If no 'reg-names' property is found we can assume we're using old DTB. */
|
||||||
|
pm->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
if (IS_ERR(pm->base))
|
||||||
|
return PTR_ERR(pm->base);
|
||||||
|
|
||||||
|
pm->asb = devm_platform_ioremap_resource(pdev, 1);
|
||||||
|
if (IS_ERR(pm->asb))
|
||||||
|
pm->asb = NULL;
|
||||||
|
|
||||||
|
pm->rpivid_asb = devm_platform_ioremap_resource(pdev, 2);
|
||||||
|
if (IS_ERR(pm->rpivid_asb))
|
||||||
|
pm->rpivid_asb = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int bcm2835_pm_probe(struct platform_device *pdev)
|
static int bcm2835_pm_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct resource *res;
|
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct bcm2835_pm *pm;
|
struct bcm2835_pm *pm;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -39,10 +82,9 @@ static int bcm2835_pm_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
pm->dev = dev;
|
pm->dev = dev;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
ret = bcm2835_pm_get_pdata(pdev, pm);
|
||||||
pm->base = devm_ioremap_resource(dev, res);
|
if (ret)
|
||||||
if (IS_ERR(pm->base))
|
return ret;
|
||||||
return PTR_ERR(pm->base);
|
|
||||||
|
|
||||||
ret = devm_mfd_add_devices(dev, -1,
|
ret = devm_mfd_add_devices(dev, -1,
|
||||||
bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs),
|
bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs),
|
||||||
@@ -50,30 +92,22 @@ static int bcm2835_pm_probe(struct platform_device *pdev)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* We'll use the presence of the AXI ASB regs in the
|
/*
|
||||||
|
* We'll use the presence of the AXI ASB regs in the
|
||||||
* bcm2835-pm binding as the key for whether we can reference
|
* bcm2835-pm binding as the key for whether we can reference
|
||||||
* the full PM register range and support power domains.
|
* the full PM register range and support power domains.
|
||||||
*/
|
*/
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
if (pm->asb)
|
||||||
if (res) {
|
return devm_mfd_add_devices(dev, -1, bcm2835_power_devs,
|
||||||
pm->asb = devm_ioremap_resource(dev, res);
|
ARRAY_SIZE(bcm2835_power_devs),
|
||||||
if (IS_ERR(pm->asb))
|
NULL, 0, NULL);
|
||||||
return PTR_ERR(pm->asb);
|
|
||||||
|
|
||||||
ret = devm_mfd_add_devices(dev, -1,
|
|
||||||
bcm2835_power_devs,
|
|
||||||
ARRAY_SIZE(bcm2835_power_devs),
|
|
||||||
NULL, 0, NULL);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id bcm2835_pm_of_match[] = {
|
static const struct of_device_id bcm2835_pm_of_match[] = {
|
||||||
{ .compatible = "brcm,bcm2835-pm-wdt", },
|
{ .compatible = "brcm,bcm2835-pm-wdt", },
|
||||||
{ .compatible = "brcm,bcm2835-pm", },
|
{ .compatible = "brcm,bcm2835-pm", },
|
||||||
|
{ .compatible = "brcm,bcm2711-pm", },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match);
|
MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match);
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ config PHY_NS2_USB_DRD
|
|||||||
config PHY_BRCM_SATA
|
config PHY_BRCM_SATA
|
||||||
tristate "Broadcom SATA PHY driver"
|
tristate "Broadcom SATA PHY driver"
|
||||||
depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || \
|
depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || \
|
||||||
ARCH_BCM_63XX || COMPILE_TEST
|
ARCH_BCMBCA || COMPILE_TEST
|
||||||
depends on OF
|
depends on OF
|
||||||
select GENERIC_PHY
|
select GENERIC_PHY
|
||||||
default ARCH_BCM_IPROC
|
default ARCH_BCM_IPROC
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ source "drivers/soc/atmel/Kconfig"
|
|||||||
source "drivers/soc/bcm/Kconfig"
|
source "drivers/soc/bcm/Kconfig"
|
||||||
source "drivers/soc/canaan/Kconfig"
|
source "drivers/soc/canaan/Kconfig"
|
||||||
source "drivers/soc/fsl/Kconfig"
|
source "drivers/soc/fsl/Kconfig"
|
||||||
|
source "drivers/soc/fujitsu/Kconfig"
|
||||||
source "drivers/soc/imx/Kconfig"
|
source "drivers/soc/imx/Kconfig"
|
||||||
source "drivers/soc/ixp4xx/Kconfig"
|
source "drivers/soc/ixp4xx/Kconfig"
|
||||||
source "drivers/soc/litex/Kconfig"
|
source "drivers/soc/litex/Kconfig"
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ obj-$(CONFIG_SOC_CANAAN) += canaan/
|
|||||||
obj-$(CONFIG_ARCH_DOVE) += dove/
|
obj-$(CONFIG_ARCH_DOVE) += dove/
|
||||||
obj-$(CONFIG_MACH_DOVE) += dove/
|
obj-$(CONFIG_MACH_DOVE) += dove/
|
||||||
obj-y += fsl/
|
obj-y += fsl/
|
||||||
|
obj-y += fujitsu/
|
||||||
obj-$(CONFIG_ARCH_GEMINI) += gemini/
|
obj-$(CONFIG_ARCH_GEMINI) += gemini/
|
||||||
obj-y += imx/
|
obj-y += imx/
|
||||||
obj-y += ixp4xx/
|
obj-y += ixp4xx/
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ static int __init meson_mx_socinfo_init(void)
|
|||||||
np = of_find_matching_node(NULL, meson_mx_socinfo_analog_top_ids);
|
np = of_find_matching_node(NULL, meson_mx_socinfo_analog_top_ids);
|
||||||
if (np) {
|
if (np) {
|
||||||
analog_top_regmap = syscon_node_to_regmap(np);
|
analog_top_regmap = syscon_node_to_regmap(np);
|
||||||
|
of_node_put(np);
|
||||||
if (IS_ERR(analog_top_regmap))
|
if (IS_ERR(analog_top_regmap))
|
||||||
return PTR_ERR(analog_top_regmap);
|
return PTR_ERR(analog_top_regmap);
|
||||||
|
|
||||||
|
|||||||
@@ -152,8 +152,10 @@ static int meson_secure_pwrc_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL);
|
pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL);
|
||||||
if (!pwrc)
|
if (!pwrc) {
|
||||||
|
of_node_put(sm_np);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
pwrc->fw = meson_sm_get(sm_np);
|
pwrc->fw = meson_sm_get(sm_np);
|
||||||
of_node_put(sm_np);
|
of_node_put(sm_np);
|
||||||
|
|||||||
@@ -126,8 +126,7 @@
|
|||||||
|
|
||||||
#define ASB_AXI_BRDG_ID 0x20
|
#define ASB_AXI_BRDG_ID 0x20
|
||||||
|
|
||||||
#define ASB_READ(reg) readl(power->asb + (reg))
|
#define BCM2835_BRDG_ID 0x62726467
|
||||||
#define ASB_WRITE(reg, val) writel(PM_PASSWORD | (val), power->asb + (reg))
|
|
||||||
|
|
||||||
struct bcm2835_power_domain {
|
struct bcm2835_power_domain {
|
||||||
struct generic_pm_domain base;
|
struct generic_pm_domain base;
|
||||||
@@ -142,24 +141,41 @@ struct bcm2835_power {
|
|||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
/* AXI Async bridge registers. */
|
/* AXI Async bridge registers. */
|
||||||
void __iomem *asb;
|
void __iomem *asb;
|
||||||
|
/* RPiVid bridge registers. */
|
||||||
|
void __iomem *rpivid_asb;
|
||||||
|
|
||||||
struct genpd_onecell_data pd_xlate;
|
struct genpd_onecell_data pd_xlate;
|
||||||
struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
|
struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
|
||||||
struct reset_controller_dev reset;
|
struct reset_controller_dev reset;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
|
static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable)
|
||||||
{
|
{
|
||||||
|
void __iomem *base = power->asb;
|
||||||
u64 start;
|
u64 start;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
if (!reg)
|
switch (reg) {
|
||||||
|
case 0:
|
||||||
return 0;
|
return 0;
|
||||||
|
case ASB_V3D_S_CTRL:
|
||||||
|
case ASB_V3D_M_CTRL:
|
||||||
|
if (power->rpivid_asb)
|
||||||
|
base = power->rpivid_asb;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
start = ktime_get_ns();
|
start = ktime_get_ns();
|
||||||
|
|
||||||
/* Enable the module's async AXI bridges. */
|
/* Enable the module's async AXI bridges. */
|
||||||
ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP);
|
if (enable) {
|
||||||
while (ASB_READ(reg) & ASB_ACK) {
|
val = readl(base + reg) & ~ASB_REQ_STOP;
|
||||||
|
} else {
|
||||||
|
val = readl(base + reg) | ASB_REQ_STOP;
|
||||||
|
}
|
||||||
|
writel(PM_PASSWORD | val, base + reg);
|
||||||
|
|
||||||
|
while (readl(base + reg) & ASB_ACK) {
|
||||||
cpu_relax();
|
cpu_relax();
|
||||||
if (ktime_get_ns() - start >= 1000)
|
if (ktime_get_ns() - start >= 1000)
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
@@ -168,30 +184,24 @@ static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
|
||||||
|
{
|
||||||
|
return bcm2835_asb_control(power, reg, true);
|
||||||
|
}
|
||||||
|
|
||||||
static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
|
static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
|
||||||
{
|
{
|
||||||
u64 start;
|
return bcm2835_asb_control(power, reg, false);
|
||||||
|
|
||||||
if (!reg)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
start = ktime_get_ns();
|
|
||||||
|
|
||||||
/* Enable the module's async AXI bridges. */
|
|
||||||
ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP);
|
|
||||||
while (!(ASB_READ(reg) & ASB_ACK)) {
|
|
||||||
cpu_relax();
|
|
||||||
if (ktime_get_ns() - start >= 1000)
|
|
||||||
return -ETIMEDOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg)
|
static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg)
|
||||||
{
|
{
|
||||||
struct bcm2835_power *power = pd->power;
|
struct bcm2835_power *power = pd->power;
|
||||||
|
|
||||||
|
/* We don't run this on BCM2711 */
|
||||||
|
if (power->rpivid_asb)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Enable functional isolation */
|
/* Enable functional isolation */
|
||||||
PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
|
PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
|
||||||
|
|
||||||
@@ -213,6 +223,10 @@ static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg)
|
|||||||
int inrush;
|
int inrush;
|
||||||
bool powok;
|
bool powok;
|
||||||
|
|
||||||
|
/* We don't run this on BCM2711 */
|
||||||
|
if (power->rpivid_asb)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* If it was already powered on by the fw, leave it that way. */
|
/* If it was already powered on by the fw, leave it that way. */
|
||||||
if (PM_READ(pm_reg) & PM_POWUP)
|
if (PM_READ(pm_reg) & PM_POWUP)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -626,13 +640,23 @@ static int bcm2835_power_probe(struct platform_device *pdev)
|
|||||||
power->dev = dev;
|
power->dev = dev;
|
||||||
power->base = pm->base;
|
power->base = pm->base;
|
||||||
power->asb = pm->asb;
|
power->asb = pm->asb;
|
||||||
|
power->rpivid_asb = pm->rpivid_asb;
|
||||||
|
|
||||||
id = ASB_READ(ASB_AXI_BRDG_ID);
|
id = readl(power->asb + ASB_AXI_BRDG_ID);
|
||||||
if (id != 0x62726467 /* "BRDG" */) {
|
if (id != BCM2835_BRDG_ID /* "BRDG" */) {
|
||||||
dev_err(dev, "ASB register ID returned 0x%08x\n", id);
|
dev_err(dev, "ASB register ID returned 0x%08x\n", id);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (power->rpivid_asb) {
|
||||||
|
id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID);
|
||||||
|
if (id != BCM2835_BRDG_ID /* "BRDG" */) {
|
||||||
|
dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n",
|
||||||
|
id);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
power->pd_xlate.domains = devm_kcalloc(dev,
|
power->pd_xlate.domains = devm_kcalloc(dev,
|
||||||
ARRAY_SIZE(power_domain_names),
|
ARRAY_SIZE(power_domain_names),
|
||||||
sizeof(*power->pd_xlate.domains),
|
sizeof(*power->pd_xlate.domains),
|
||||||
|
|||||||
@@ -340,12 +340,12 @@ static int __init brcmstb_biuctrl_init(void)
|
|||||||
|
|
||||||
ret = setup_hifcpubiuctrl_regs(np);
|
ret = setup_hifcpubiuctrl_regs(np);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto out_put;
|
||||||
|
|
||||||
ret = mcp_write_pairing_set();
|
ret = mcp_write_pairing_set();
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("MCP: Unable to disable write pairing!\n");
|
pr_err("MCP: Unable to disable write pairing!\n");
|
||||||
return ret;
|
goto out_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
a72_b53_rac_enable_all(np);
|
a72_b53_rac_enable_all(np);
|
||||||
@@ -353,6 +353,9 @@ static int __init brcmstb_biuctrl_init(void)
|
|||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
register_syscore_ops(&brcmstb_cpu_credit_syscore_ops);
|
register_syscore_ops(&brcmstb_cpu_credit_syscore_ops);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
ret = 0;
|
||||||
|
out_put:
|
||||||
|
of_node_put(np);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
early_initcall(brcmstb_biuctrl_init);
|
early_initcall(brcmstb_biuctrl_init);
|
||||||
|
|||||||
@@ -721,7 +721,7 @@ static int brcmstb_pm_probe(struct platform_device *pdev)
|
|||||||
ctrl.phy_a_standby_ctrl_offs = ddr_phy_data->phy_a_standby_ctrl_offs;
|
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;
|
ctrl.phy_b_standby_ctrl_offs = ddr_phy_data->phy_b_standby_ctrl_offs;
|
||||||
/*
|
/*
|
||||||
* Slightly grosss to use the phy ver to get a memc,
|
* Slightly gross to use the phy ver to get a memc,
|
||||||
* offset but that is the only versioned things so far
|
* offset but that is the only versioned things so far
|
||||||
* we can test for.
|
* we can test for.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -14,21 +14,16 @@
|
|||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/fsl/guts.h>
|
#include <linux/fsl/guts.h>
|
||||||
|
|
||||||
struct guts {
|
|
||||||
struct ccsr_guts __iomem *regs;
|
|
||||||
bool little_endian;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fsl_soc_die_attr {
|
struct fsl_soc_die_attr {
|
||||||
char *die;
|
char *die;
|
||||||
u32 svr;
|
u32 svr;
|
||||||
u32 mask;
|
u32 mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct guts *guts;
|
struct fsl_soc_data {
|
||||||
static struct soc_device_attribute soc_dev_attr;
|
const char *sfp_compat;
|
||||||
static struct soc_device *soc_dev;
|
u32 uid_offset;
|
||||||
|
};
|
||||||
|
|
||||||
/* SoC die attribute definition for QorIQ platform */
|
/* SoC die attribute definition for QorIQ platform */
|
||||||
static const struct fsl_soc_die_attr fsl_soc_die[] = {
|
static const struct fsl_soc_die_attr fsl_soc_die[] = {
|
||||||
@@ -120,88 +115,36 @@ static const struct fsl_soc_die_attr *fsl_soc_die_match(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 fsl_guts_get_svr(void)
|
static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset)
|
||||||
{
|
{
|
||||||
u32 svr = 0;
|
struct device_node *np;
|
||||||
|
void __iomem *sfp_base;
|
||||||
|
u64 uid;
|
||||||
|
|
||||||
if (!guts || !guts->regs)
|
np = of_find_compatible_node(NULL, NULL, compat);
|
||||||
return svr;
|
if (!np)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (guts->little_endian)
|
sfp_base = of_iomap(np, 0);
|
||||||
svr = ioread32(&guts->regs->svr);
|
if (!sfp_base) {
|
||||||
else
|
of_node_put(np);
|
||||||
svr = ioread32be(&guts->regs->svr);
|
return 0;
|
||||||
|
|
||||||
return svr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fsl_guts_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct device_node *root, *np = pdev->dev.of_node;
|
|
||||||
struct device *dev = &pdev->dev;
|
|
||||||
const struct fsl_soc_die_attr *soc_die;
|
|
||||||
const char *machine;
|
|
||||||
u32 svr;
|
|
||||||
|
|
||||||
/* Initialize guts */
|
|
||||||
guts = devm_kzalloc(dev, sizeof(*guts), GFP_KERNEL);
|
|
||||||
if (!guts)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
guts->little_endian = of_property_read_bool(np, "little-endian");
|
|
||||||
|
|
||||||
guts->regs = devm_platform_ioremap_resource(pdev, 0);
|
|
||||||
if (IS_ERR(guts->regs))
|
|
||||||
return PTR_ERR(guts->regs);
|
|
||||||
|
|
||||||
/* Register soc device */
|
|
||||||
root = of_find_node_by_path("/");
|
|
||||||
if (of_property_read_string(root, "model", &machine))
|
|
||||||
of_property_read_string_index(root, "compatible", 0, &machine);
|
|
||||||
if (machine) {
|
|
||||||
soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
|
|
||||||
if (!soc_dev_attr.machine) {
|
|
||||||
of_node_put(root);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
of_node_put(root);
|
|
||||||
|
|
||||||
svr = fsl_guts_get_svr();
|
uid = ioread32(sfp_base + offset);
|
||||||
soc_die = fsl_soc_die_match(svr, fsl_soc_die);
|
uid <<= 32;
|
||||||
if (soc_die) {
|
uid |= ioread32(sfp_base + offset + 4);
|
||||||
soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL,
|
|
||||||
"QorIQ %s", soc_die->die);
|
|
||||||
} else {
|
|
||||||
soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL, "QorIQ");
|
|
||||||
}
|
|
||||||
if (!soc_dev_attr.family)
|
|
||||||
return -ENOMEM;
|
|
||||||
soc_dev_attr.soc_id = devm_kasprintf(dev, GFP_KERNEL,
|
|
||||||
"svr:0x%08x", svr);
|
|
||||||
if (!soc_dev_attr.soc_id)
|
|
||||||
return -ENOMEM;
|
|
||||||
soc_dev_attr.revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d",
|
|
||||||
(svr >> 4) & 0xf, svr & 0xf);
|
|
||||||
if (!soc_dev_attr.revision)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
soc_dev = soc_device_register(&soc_dev_attr);
|
iounmap(sfp_base);
|
||||||
if (IS_ERR(soc_dev))
|
of_node_put(np);
|
||||||
return PTR_ERR(soc_dev);
|
|
||||||
|
|
||||||
pr_info("Machine: %s\n", soc_dev_attr.machine);
|
return uid;
|
||||||
pr_info("SoC family: %s\n", soc_dev_attr.family);
|
|
||||||
pr_info("SoC ID: %s, Revision: %s\n",
|
|
||||||
soc_dev_attr.soc_id, soc_dev_attr.revision);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fsl_guts_remove(struct platform_device *dev)
|
static const struct fsl_soc_data ls1028a_data = {
|
||||||
{
|
.sfp_compat = "fsl,ls1028a-sfp",
|
||||||
soc_device_unregister(soc_dev);
|
.uid_offset = 0x21c,
|
||||||
return 0;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Table for matching compatible strings, for device tree
|
* Table for matching compatible strings, for device tree
|
||||||
@@ -231,28 +174,106 @@ static const struct of_device_id fsl_guts_of_match[] = {
|
|||||||
{ .compatible = "fsl,ls1012a-dcfg", },
|
{ .compatible = "fsl,ls1012a-dcfg", },
|
||||||
{ .compatible = "fsl,ls1046a-dcfg", },
|
{ .compatible = "fsl,ls1046a-dcfg", },
|
||||||
{ .compatible = "fsl,lx2160a-dcfg", },
|
{ .compatible = "fsl,lx2160a-dcfg", },
|
||||||
{ .compatible = "fsl,ls1028a-dcfg", },
|
{ .compatible = "fsl,ls1028a-dcfg", .data = &ls1028a_data},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, fsl_guts_of_match);
|
|
||||||
|
|
||||||
static struct platform_driver fsl_guts_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = "fsl-guts",
|
|
||||||
.of_match_table = fsl_guts_of_match,
|
|
||||||
},
|
|
||||||
.probe = fsl_guts_probe,
|
|
||||||
.remove = fsl_guts_remove,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __init fsl_guts_init(void)
|
static int __init fsl_guts_init(void)
|
||||||
{
|
{
|
||||||
return platform_driver_register(&fsl_guts_driver);
|
struct soc_device_attribute *soc_dev_attr;
|
||||||
|
static struct soc_device *soc_dev;
|
||||||
|
const struct fsl_soc_die_attr *soc_die;
|
||||||
|
const struct fsl_soc_data *soc_data;
|
||||||
|
const struct of_device_id *match;
|
||||||
|
struct ccsr_guts __iomem *regs;
|
||||||
|
const char *machine = NULL;
|
||||||
|
struct device_node *np;
|
||||||
|
bool little_endian;
|
||||||
|
u64 soc_uid = 0;
|
||||||
|
u32 svr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match);
|
||||||
|
if (!np)
|
||||||
|
return 0;
|
||||||
|
soc_data = match->data;
|
||||||
|
|
||||||
|
regs = of_iomap(np, 0);
|
||||||
|
if (!regs) {
|
||||||
|
of_node_put(np);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
little_endian = of_property_read_bool(np, "little-endian");
|
||||||
|
if (little_endian)
|
||||||
|
svr = ioread32(®s->svr);
|
||||||
|
else
|
||||||
|
svr = ioread32be(®s->svr);
|
||||||
|
iounmap(regs);
|
||||||
|
of_node_put(np);
|
||||||
|
|
||||||
|
/* Register soc device */
|
||||||
|
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
|
||||||
|
if (!soc_dev_attr)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (of_property_read_string(of_root, "model", &machine))
|
||||||
|
of_property_read_string_index(of_root, "compatible", 0, &machine);
|
||||||
|
if (machine) {
|
||||||
|
soc_dev_attr->machine = kstrdup(machine, GFP_KERNEL);
|
||||||
|
if (!soc_dev_attr->machine)
|
||||||
|
goto err_nomem;
|
||||||
|
}
|
||||||
|
|
||||||
|
soc_die = fsl_soc_die_match(svr, fsl_soc_die);
|
||||||
|
if (soc_die) {
|
||||||
|
soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ %s",
|
||||||
|
soc_die->die);
|
||||||
|
} else {
|
||||||
|
soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ");
|
||||||
|
}
|
||||||
|
if (!soc_dev_attr->family)
|
||||||
|
goto err_nomem;
|
||||||
|
|
||||||
|
soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", svr);
|
||||||
|
if (!soc_dev_attr->soc_id)
|
||||||
|
goto err_nomem;
|
||||||
|
|
||||||
|
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
|
||||||
|
(svr >> 4) & 0xf, svr & 0xf);
|
||||||
|
if (!soc_dev_attr->revision)
|
||||||
|
goto err_nomem;
|
||||||
|
|
||||||
|
if (soc_data)
|
||||||
|
soc_uid = fsl_guts_get_soc_uid(soc_data->sfp_compat,
|
||||||
|
soc_data->uid_offset);
|
||||||
|
if (soc_uid)
|
||||||
|
soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX",
|
||||||
|
soc_uid);
|
||||||
|
|
||||||
|
soc_dev = soc_device_register(soc_dev_attr);
|
||||||
|
if (IS_ERR(soc_dev)) {
|
||||||
|
ret = PTR_ERR(soc_dev);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("Machine: %s\n", soc_dev_attr->machine);
|
||||||
|
pr_info("SoC family: %s\n", soc_dev_attr->family);
|
||||||
|
pr_info("SoC ID: %s, Revision: %s\n",
|
||||||
|
soc_dev_attr->soc_id, soc_dev_attr->revision);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_nomem:
|
||||||
|
ret = -ENOMEM;
|
||||||
|
err:
|
||||||
|
kfree(soc_dev_attr->machine);
|
||||||
|
kfree(soc_dev_attr->family);
|
||||||
|
kfree(soc_dev_attr->soc_id);
|
||||||
|
kfree(soc_dev_attr->revision);
|
||||||
|
kfree(soc_dev_attr->serial_number);
|
||||||
|
kfree(soc_dev_attr);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
core_initcall(fsl_guts_init);
|
core_initcall(fsl_guts_init);
|
||||||
|
|
||||||
static void __exit fsl_guts_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&fsl_guts_driver);
|
|
||||||
}
|
|
||||||
module_exit(fsl_guts_exit);
|
|
||||||
|
|||||||
16
drivers/soc/fujitsu/Kconfig
Normal file
16
drivers/soc/fujitsu/Kconfig
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
menu "fujitsu SoC drivers"
|
||||||
|
|
||||||
|
config A64FX_DIAG
|
||||||
|
bool "A64FX diag driver"
|
||||||
|
depends on ARM64
|
||||||
|
depends on ACPI
|
||||||
|
help
|
||||||
|
Say Y here if you want to enable diag interrupt on Fujitsu A64FX.
|
||||||
|
This driver enables BMC's diagnostic requests and enables
|
||||||
|
A64FX-specific interrupts. This allows administrators to obtain
|
||||||
|
kernel dumps via diagnostic requests using ipmitool, etc.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
|
endmenu
|
||||||
3
drivers/soc/fujitsu/Makefile
Normal file
3
drivers/soc/fujitsu/Makefile
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
obj-$(CONFIG_A64FX_DIAG) += a64fx-diag.o
|
||||||
154
drivers/soc/fujitsu/a64fx-diag.c
Normal file
154
drivers/soc/fujitsu/a64fx-diag.c
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* A64FX diag driver.
|
||||||
|
* Copyright (c) 2022 Fujitsu Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#define A64FX_DIAG_IRQ 1
|
||||||
|
#define BMC_DIAG_INTERRUPT_ENABLE 0x40
|
||||||
|
#define BMC_DIAG_INTERRUPT_STATUS 0x44
|
||||||
|
#define BMC_DIAG_INTERRUPT_MASK BIT(31)
|
||||||
|
|
||||||
|
struct a64fx_diag_priv {
|
||||||
|
void __iomem *mmsc_reg_base;
|
||||||
|
int irq;
|
||||||
|
bool has_nmi;
|
||||||
|
};
|
||||||
|
|
||||||
|
static irqreturn_t a64fx_diag_handler_nmi(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
nmi_panic(NULL, "a64fx_diag: interrupt received\n");
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t a64fx_diag_handler_irq(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
panic("a64fx_diag: interrupt received\n");
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void a64fx_diag_interrupt_clear(struct a64fx_diag_priv *priv)
|
||||||
|
{
|
||||||
|
void __iomem *diag_status_reg_addr;
|
||||||
|
u32 mmsc;
|
||||||
|
|
||||||
|
diag_status_reg_addr = priv->mmsc_reg_base + BMC_DIAG_INTERRUPT_STATUS;
|
||||||
|
mmsc = readl(diag_status_reg_addr);
|
||||||
|
if (mmsc & BMC_DIAG_INTERRUPT_MASK)
|
||||||
|
writel(BMC_DIAG_INTERRUPT_MASK, diag_status_reg_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void a64fx_diag_interrupt_enable(struct a64fx_diag_priv *priv)
|
||||||
|
{
|
||||||
|
void __iomem *diag_enable_reg_addr;
|
||||||
|
u32 mmsc;
|
||||||
|
|
||||||
|
diag_enable_reg_addr = priv->mmsc_reg_base + BMC_DIAG_INTERRUPT_ENABLE;
|
||||||
|
mmsc = readl(diag_enable_reg_addr);
|
||||||
|
if (!(mmsc & BMC_DIAG_INTERRUPT_MASK)) {
|
||||||
|
mmsc |= BMC_DIAG_INTERRUPT_MASK;
|
||||||
|
writel(mmsc, diag_enable_reg_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void a64fx_diag_interrupt_disable(struct a64fx_diag_priv *priv)
|
||||||
|
{
|
||||||
|
void __iomem *diag_enable_reg_addr;
|
||||||
|
u32 mmsc;
|
||||||
|
|
||||||
|
diag_enable_reg_addr = priv->mmsc_reg_base + BMC_DIAG_INTERRUPT_ENABLE;
|
||||||
|
mmsc = readl(diag_enable_reg_addr);
|
||||||
|
if (mmsc & BMC_DIAG_INTERRUPT_MASK) {
|
||||||
|
mmsc &= ~BMC_DIAG_INTERRUPT_MASK;
|
||||||
|
writel(mmsc, diag_enable_reg_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int a64fx_diag_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct a64fx_diag_priv *priv;
|
||||||
|
unsigned long irq_flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->mmsc_reg_base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
if (IS_ERR(priv->mmsc_reg_base))
|
||||||
|
return PTR_ERR(priv->mmsc_reg_base);
|
||||||
|
|
||||||
|
priv->irq = platform_get_irq(pdev, A64FX_DIAG_IRQ);
|
||||||
|
if (priv->irq < 0)
|
||||||
|
return priv->irq;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, priv);
|
||||||
|
|
||||||
|
irq_flags = IRQF_PERCPU | IRQF_NOBALANCING | IRQF_NO_AUTOEN |
|
||||||
|
IRQF_NO_THREAD;
|
||||||
|
ret = request_nmi(priv->irq, &a64fx_diag_handler_nmi, irq_flags,
|
||||||
|
"a64fx_diag_nmi", NULL);
|
||||||
|
if (ret) {
|
||||||
|
ret = request_irq(priv->irq, &a64fx_diag_handler_irq,
|
||||||
|
irq_flags, "a64fx_diag_irq", NULL);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "cannot register IRQ %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
enable_irq(priv->irq);
|
||||||
|
} else {
|
||||||
|
enable_nmi(priv->irq);
|
||||||
|
priv->has_nmi = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
a64fx_diag_interrupt_clear(priv);
|
||||||
|
a64fx_diag_interrupt_enable(priv);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int a64fx_diag_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct a64fx_diag_priv *priv = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
a64fx_diag_interrupt_disable(priv);
|
||||||
|
a64fx_diag_interrupt_clear(priv);
|
||||||
|
|
||||||
|
if (priv->has_nmi)
|
||||||
|
free_nmi(priv->irq, NULL);
|
||||||
|
else
|
||||||
|
free_irq(priv->irq, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct acpi_device_id a64fx_diag_acpi_match[] = {
|
||||||
|
{ "FUJI2007", 0 },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(acpi, a64fx_diag_acpi_match);
|
||||||
|
|
||||||
|
|
||||||
|
static struct platform_driver a64fx_diag_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "a64fx_diag_driver",
|
||||||
|
.acpi_match_table = ACPI_PTR(a64fx_diag_acpi_match),
|
||||||
|
},
|
||||||
|
.probe = a64fx_diag_probe,
|
||||||
|
.remove = a64fx_diag_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(a64fx_diag_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_AUTHOR("Hitomi Hasegawa <hasegawa-hitomi@fujitsu.com>");
|
||||||
|
MODULE_DESCRIPTION("A64FX diag driver");
|
||||||
@@ -328,7 +328,9 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
|
|||||||
if (!IS_ERR(domain->regulator)) {
|
if (!IS_ERR(domain->regulator)) {
|
||||||
ret = regulator_enable(domain->regulator);
|
ret = regulator_enable(domain->regulator);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(domain->dev, "failed to enable regulator\n");
|
dev_err(domain->dev,
|
||||||
|
"failed to enable regulator: %pe\n",
|
||||||
|
ERR_PTR(ret));
|
||||||
goto out_put_pm;
|
goto out_put_pm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -467,7 +469,9 @@ static int imx_pgc_power_down(struct generic_pm_domain *genpd)
|
|||||||
if (!IS_ERR(domain->regulator)) {
|
if (!IS_ERR(domain->regulator)) {
|
||||||
ret = regulator_disable(domain->regulator);
|
ret = regulator_disable(domain->regulator);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(domain->dev, "failed to disable regulator\n");
|
dev_err(domain->dev,
|
||||||
|
"failed to disable regulator: %pe\n",
|
||||||
|
ERR_PTR(ret));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
|
|||||||
bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
|
bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
|
||||||
if (IS_ERR(bc->bus_power_dev))
|
if (IS_ERR(bc->bus_power_dev))
|
||||||
return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
|
return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
|
||||||
"failed to attach power domain\n");
|
"failed to attach power domain \"bus\"\n");
|
||||||
|
|
||||||
for (i = 0; i < bc_data->num_domains; i++) {
|
for (i = 0; i < bc_data->num_domains; i++) {
|
||||||
const struct imx8m_blk_ctrl_domain_data *data = &bc_data->domains[i];
|
const struct imx8m_blk_ctrl_domain_data *data = &bc_data->domains[i];
|
||||||
@@ -238,7 +238,8 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
|
|||||||
dev_pm_domain_attach_by_name(dev, data->gpc_name);
|
dev_pm_domain_attach_by_name(dev, data->gpc_name);
|
||||||
if (IS_ERR(domain->power_dev)) {
|
if (IS_ERR(domain->power_dev)) {
|
||||||
dev_err_probe(dev, PTR_ERR(domain->power_dev),
|
dev_err_probe(dev, PTR_ERR(domain->power_dev),
|
||||||
"failed to attach power domain\n");
|
"failed to attach power domain \"%s\"\n",
|
||||||
|
data->gpc_name);
|
||||||
ret = PTR_ERR(domain->power_dev);
|
ret = PTR_ERR(domain->power_dev);
|
||||||
goto cleanup_pds;
|
goto cleanup_pds;
|
||||||
}
|
}
|
||||||
@@ -251,7 +252,9 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
ret = pm_genpd_init(&domain->genpd, NULL, true);
|
ret = pm_genpd_init(&domain->genpd, NULL, true);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err_probe(dev, ret, "failed to init power domain\n");
|
dev_err_probe(dev, ret,
|
||||||
|
"failed to init power domain \"%s\"\n",
|
||||||
|
data->gpc_name);
|
||||||
dev_pm_domain_detach(domain->power_dev, true);
|
dev_pm_domain_detach(domain->power_dev, true);
|
||||||
goto cleanup_pds;
|
goto cleanup_pds;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,4 +73,14 @@ config MTK_MMSYS
|
|||||||
Say yes here to add support for the MediaTek Multimedia
|
Say yes here to add support for the MediaTek Multimedia
|
||||||
Subsystem (MMSYS).
|
Subsystem (MMSYS).
|
||||||
|
|
||||||
|
config MTK_SVS
|
||||||
|
tristate "MediaTek Smart Voltage Scaling(SVS)"
|
||||||
|
depends on MTK_EFUSE && NVMEM
|
||||||
|
help
|
||||||
|
The Smart Voltage Scaling(SVS) engine is a piece of hardware
|
||||||
|
which has several controllers(banks) for calculating suitable
|
||||||
|
voltage to different power domains(CPU/GPU/CCI) according to
|
||||||
|
chip process corner, temperatures and other factors. Then DVFS
|
||||||
|
driver could apply SVS bank voltage to PMIC/Buck.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|||||||
@@ -7,3 +7,4 @@ obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
|
|||||||
obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o
|
obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o
|
||||||
obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
|
obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
|
||||||
obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o
|
obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o
|
||||||
|
obj-$(CONFIG_MTK_SVS) += mtk-svs.o
|
||||||
|
|||||||
112
drivers/soc/mediatek/mt6795-pm-domains.h
Normal file
112
drivers/soc/mediatek/mt6795-pm-domains.h
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
|
||||||
|
#ifndef __SOC_MEDIATEK_MT6795_PM_DOMAINS_H
|
||||||
|
#define __SOC_MEDIATEK_MT6795_PM_DOMAINS_H
|
||||||
|
|
||||||
|
#include "mtk-pm-domains.h"
|
||||||
|
#include <dt-bindings/power/mt6795-power.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MT6795 power domain support
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct scpsys_domain_data scpsys_domain_data_mt6795[] = {
|
||||||
|
[MT6795_POWER_DOMAIN_VDEC] = {
|
||||||
|
.name = "vdec",
|
||||||
|
.sta_mask = PWR_STATUS_VDEC,
|
||||||
|
.ctl_offs = SPM_VDE_PWR_CON,
|
||||||
|
.pwr_sta_offs = SPM_PWR_STATUS,
|
||||||
|
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
|
||||||
|
.sram_pdn_bits = GENMASK(11, 8),
|
||||||
|
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||||
|
},
|
||||||
|
[MT6795_POWER_DOMAIN_VENC] = {
|
||||||
|
.name = "venc",
|
||||||
|
.sta_mask = PWR_STATUS_VENC,
|
||||||
|
.ctl_offs = SPM_VEN_PWR_CON,
|
||||||
|
.pwr_sta_offs = SPM_PWR_STATUS,
|
||||||
|
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
|
||||||
|
.sram_pdn_bits = GENMASK(11, 8),
|
||||||
|
.sram_pdn_ack_bits = GENMASK(15, 12),
|
||||||
|
},
|
||||||
|
[MT6795_POWER_DOMAIN_ISP] = {
|
||||||
|
.name = "isp",
|
||||||
|
.sta_mask = PWR_STATUS_ISP,
|
||||||
|
.ctl_offs = SPM_ISP_PWR_CON,
|
||||||
|
.pwr_sta_offs = SPM_PWR_STATUS,
|
||||||
|
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
|
||||||
|
.sram_pdn_bits = GENMASK(11, 8),
|
||||||
|
.sram_pdn_ack_bits = GENMASK(13, 12),
|
||||||
|
},
|
||||||
|
[MT6795_POWER_DOMAIN_MM] = {
|
||||||
|
.name = "mm",
|
||||||
|
.sta_mask = PWR_STATUS_DISP,
|
||||||
|
.ctl_offs = SPM_DIS_PWR_CON,
|
||||||
|
.pwr_sta_offs = SPM_PWR_STATUS,
|
||||||
|
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
|
||||||
|
.sram_pdn_bits = GENMASK(11, 8),
|
||||||
|
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||||
|
.bp_infracfg = {
|
||||||
|
BUS_PROT_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MM_M0 |
|
||||||
|
MT8173_TOP_AXI_PROT_EN_MM_M1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[MT6795_POWER_DOMAIN_MJC] = {
|
||||||
|
.name = "mjc",
|
||||||
|
.sta_mask = BIT(20),
|
||||||
|
.ctl_offs = 0x298,
|
||||||
|
.pwr_sta_offs = SPM_PWR_STATUS,
|
||||||
|
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
|
||||||
|
.sram_pdn_bits = GENMASK(11, 8),
|
||||||
|
.sram_pdn_ack_bits = GENMASK(15, 12),
|
||||||
|
},
|
||||||
|
[MT6795_POWER_DOMAIN_AUDIO] = {
|
||||||
|
.name = "audio",
|
||||||
|
.sta_mask = PWR_STATUS_AUDIO,
|
||||||
|
.ctl_offs = SPM_AUDIO_PWR_CON,
|
||||||
|
.pwr_sta_offs = SPM_PWR_STATUS,
|
||||||
|
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
|
||||||
|
.sram_pdn_bits = GENMASK(11, 8),
|
||||||
|
.sram_pdn_ack_bits = GENMASK(15, 12),
|
||||||
|
},
|
||||||
|
[MT6795_POWER_DOMAIN_MFG_ASYNC] = {
|
||||||
|
.name = "mfg_async",
|
||||||
|
.sta_mask = PWR_STATUS_MFG_ASYNC,
|
||||||
|
.ctl_offs = SPM_MFG_ASYNC_PWR_CON,
|
||||||
|
.pwr_sta_offs = SPM_PWR_STATUS,
|
||||||
|
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
|
||||||
|
.sram_pdn_bits = GENMASK(11, 8),
|
||||||
|
.sram_pdn_ack_bits = 0,
|
||||||
|
},
|
||||||
|
[MT6795_POWER_DOMAIN_MFG_2D] = {
|
||||||
|
.name = "mfg_2d",
|
||||||
|
.sta_mask = PWR_STATUS_MFG_2D,
|
||||||
|
.ctl_offs = SPM_MFG_2D_PWR_CON,
|
||||||
|
.pwr_sta_offs = SPM_PWR_STATUS,
|
||||||
|
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
|
||||||
|
.sram_pdn_bits = GENMASK(11, 8),
|
||||||
|
.sram_pdn_ack_bits = GENMASK(13, 12),
|
||||||
|
},
|
||||||
|
[MT6795_POWER_DOMAIN_MFG] = {
|
||||||
|
.name = "mfg",
|
||||||
|
.sta_mask = PWR_STATUS_MFG,
|
||||||
|
.ctl_offs = SPM_MFG_PWR_CON,
|
||||||
|
.pwr_sta_offs = SPM_PWR_STATUS,
|
||||||
|
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
|
||||||
|
.sram_pdn_bits = GENMASK(13, 8),
|
||||||
|
.sram_pdn_ack_bits = GENMASK(21, 16),
|
||||||
|
.bp_infracfg = {
|
||||||
|
BUS_PROT_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MFG_S |
|
||||||
|
MT8173_TOP_AXI_PROT_EN_MFG_M0 |
|
||||||
|
MT8173_TOP_AXI_PROT_EN_MFG_M1 |
|
||||||
|
MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct scpsys_soc_data mt6795_scpsys_data = {
|
||||||
|
.domains_data = scpsys_domain_data_mt6795,
|
||||||
|
.num_domains = ARRAY_SIZE(scpsys_domain_data_mt6795),
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __SOC_MEDIATEK_MT6795_PM_DOMAINS_H */
|
||||||
@@ -41,6 +41,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||||||
.pwr_sta2nd_offs = 0x0184,
|
.pwr_sta2nd_offs = 0x0184,
|
||||||
.sram_pdn_bits = 0,
|
.sram_pdn_bits = 0,
|
||||||
.sram_pdn_ack_bits = 0,
|
.sram_pdn_ack_bits = 0,
|
||||||
|
.caps = MTK_SCPD_DOMAIN_SUPPLY,
|
||||||
},
|
},
|
||||||
[MT8183_POWER_DOMAIN_MFG] = {
|
[MT8183_POWER_DOMAIN_MFG] = {
|
||||||
.name = "mfg",
|
.name = "mfg",
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8186[] = {
|
|||||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||||
},
|
},
|
||||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
.caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
|
||||||
},
|
},
|
||||||
[MT8186_POWER_DOMAIN_MFG2] = {
|
[MT8186_POWER_DOMAIN_MFG2] = {
|
||||||
.name = "mfg2",
|
.name = "mfg2",
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||||||
.pwr_sta2nd_offs = 0x0170,
|
.pwr_sta2nd_offs = 0x0170,
|
||||||
.sram_pdn_bits = GENMASK(8, 8),
|
.sram_pdn_bits = GENMASK(8, 8),
|
||||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||||
|
.caps = MTK_SCPD_DOMAIN_SUPPLY,
|
||||||
},
|
},
|
||||||
[MT8192_POWER_DOMAIN_MFG1] = {
|
[MT8192_POWER_DOMAIN_MFG1] = {
|
||||||
.name = "mfg1",
|
.name = "mfg1",
|
||||||
@@ -85,6 +86,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||||||
MT8192_TOP_AXI_PROT_EN_2_CLR,
|
MT8192_TOP_AXI_PROT_EN_2_CLR,
|
||||||
MT8192_TOP_AXI_PROT_EN_2_STA1),
|
MT8192_TOP_AXI_PROT_EN_2_STA1),
|
||||||
},
|
},
|
||||||
|
.caps = MTK_SCPD_DOMAIN_SUPPLY,
|
||||||
},
|
},
|
||||||
[MT8192_POWER_DOMAIN_MFG2] = {
|
[MT8192_POWER_DOMAIN_MFG2] = {
|
||||||
.name = "mfg2",
|
.name = "mfg2",
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8195[] = {
|
|||||||
.ctl_offs = 0x334,
|
.ctl_offs = 0x334,
|
||||||
.pwr_sta_offs = 0x174,
|
.pwr_sta_offs = 0x174,
|
||||||
.pwr_sta2nd_offs = 0x178,
|
.pwr_sta2nd_offs = 0x178,
|
||||||
.caps = MTK_SCPD_ACTIVE_WAKEUP,
|
.caps = MTK_SCPD_ACTIVE_WAKEUP | MTK_SCPD_ALWAYS_ON,
|
||||||
},
|
},
|
||||||
[MT8195_POWER_DOMAIN_CSI_RX_TOP] = {
|
[MT8195_POWER_DOMAIN_CSI_RX_TOP] = {
|
||||||
.name = "csi_rx_top",
|
.name = "csi_rx_top",
|
||||||
@@ -162,7 +162,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8195[] = {
|
|||||||
MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
|
MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
|
||||||
MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
|
MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
|
||||||
},
|
},
|
||||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
.caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
|
||||||
},
|
},
|
||||||
[MT8195_POWER_DOMAIN_MFG2] = {
|
[MT8195_POWER_DOMAIN_MFG2] = {
|
||||||
.name = "mfg2",
|
.name = "mfg2",
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
#define MT8365_DISP_REG_CONFIG_DISP_RDMA0_RSZ0_SEL_IN 0xf60
|
#define MT8365_DISP_REG_CONFIG_DISP_RDMA0_RSZ0_SEL_IN 0xf60
|
||||||
#define MT8365_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0xf64
|
#define MT8365_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0xf64
|
||||||
#define MT8365_DISP_REG_CONFIG_DISP_DSI0_SEL_IN 0xf68
|
#define MT8365_DISP_REG_CONFIG_DISP_DSI0_SEL_IN 0xf68
|
||||||
|
#define MT8365_DISP_REG_CONFIG_DISP_RDMA1_SOUT_SEL 0xfd0
|
||||||
|
#define MT8365_DISP_REG_CONFIG_DISP_DPI0_SEL_IN 0xfd8
|
||||||
|
#define MT8365_DISP_REG_CONFIG_DISP_LVDS_SYS_CFG_00 0xfdc
|
||||||
|
|
||||||
#define MT8365_RDMA0_SOUT_COLOR0 0x1
|
#define MT8365_RDMA0_SOUT_COLOR0 0x1
|
||||||
#define MT8365_DITHER_MOUT_EN_DSI0 0x1
|
#define MT8365_DITHER_MOUT_EN_DSI0 0x1
|
||||||
@@ -18,6 +21,10 @@
|
|||||||
#define MT8365_RDMA0_RSZ0_SEL_IN_RDMA0 0x0
|
#define MT8365_RDMA0_RSZ0_SEL_IN_RDMA0 0x0
|
||||||
#define MT8365_DISP_COLOR_SEL_IN_COLOR0 0x0
|
#define MT8365_DISP_COLOR_SEL_IN_COLOR0 0x0
|
||||||
#define MT8365_OVL0_MOUT_PATH0_SEL BIT(0)
|
#define MT8365_OVL0_MOUT_PATH0_SEL BIT(0)
|
||||||
|
#define MT8365_RDMA1_SOUT_DPI0 0x1
|
||||||
|
#define MT8365_DPI0_SEL_IN_RDMA1 0x0
|
||||||
|
#define MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK 0x1
|
||||||
|
#define MT8365_DPI0_SEL_IN_RDMA1 0x0
|
||||||
|
|
||||||
static const struct mtk_mmsys_routes mt8365_mmsys_routing_table[] = {
|
static const struct mtk_mmsys_routes mt8365_mmsys_routing_table[] = {
|
||||||
{
|
{
|
||||||
@@ -55,6 +62,21 @@ static const struct mtk_mmsys_routes mt8365_mmsys_routing_table[] = {
|
|||||||
MT8365_DISP_REG_CONFIG_DISP_RDMA0_RSZ0_SEL_IN,
|
MT8365_DISP_REG_CONFIG_DISP_RDMA0_RSZ0_SEL_IN,
|
||||||
MT8365_RDMA0_RSZ0_SEL_IN_RDMA0, MT8365_RDMA0_RSZ0_SEL_IN_RDMA0
|
MT8365_RDMA0_RSZ0_SEL_IN_RDMA0, MT8365_RDMA0_RSZ0_SEL_IN_RDMA0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
|
||||||
|
MT8365_DISP_REG_CONFIG_DISP_LVDS_SYS_CFG_00,
|
||||||
|
MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK, MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
|
||||||
|
MT8365_DISP_REG_CONFIG_DISP_DPI0_SEL_IN,
|
||||||
|
MT8365_DPI0_SEL_IN_RDMA1, MT8365_DPI0_SEL_IN_RDMA1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
|
||||||
|
MT8365_DISP_REG_CONFIG_DISP_RDMA1_SOUT_SEL,
|
||||||
|
MT8365_RDMA1_SOUT_DPI0, MT8365_RDMA1_SOUT_DPI0
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __SOC_MEDIATEK_MT8365_MMSYS_H */
|
#endif /* __SOC_MEDIATEK_MT8365_MMSYS_H */
|
||||||
|
|||||||
@@ -31,10 +31,7 @@ struct mtk_devapc_vio_dbgs {
|
|||||||
u32 vio_dbg1;
|
u32 vio_dbg1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mtk_devapc_data {
|
struct mtk_devapc_regs_ofs {
|
||||||
/* numbers of violation index */
|
|
||||||
u32 vio_idx_num;
|
|
||||||
|
|
||||||
/* reg offset */
|
/* reg offset */
|
||||||
u32 vio_mask_offset;
|
u32 vio_mask_offset;
|
||||||
u32 vio_sta_offset;
|
u32 vio_sta_offset;
|
||||||
@@ -46,6 +43,12 @@ struct mtk_devapc_data {
|
|||||||
u32 vio_shift_con_offset;
|
u32 vio_shift_con_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mtk_devapc_data {
|
||||||
|
/* numbers of violation index */
|
||||||
|
u32 vio_idx_num;
|
||||||
|
const struct mtk_devapc_regs_ofs *regs_ofs;
|
||||||
|
};
|
||||||
|
|
||||||
struct mtk_devapc_context {
|
struct mtk_devapc_context {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
void __iomem *infra_base;
|
void __iomem *infra_base;
|
||||||
@@ -58,7 +61,7 @@ static void clear_vio_status(struct mtk_devapc_context *ctx)
|
|||||||
void __iomem *reg;
|
void __iomem *reg;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
reg = ctx->infra_base + ctx->data->vio_sta_offset;
|
reg = ctx->infra_base + ctx->data->regs_ofs->vio_sta_offset;
|
||||||
|
|
||||||
for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
|
for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
|
||||||
writel(GENMASK(31, 0), reg + 4 * i);
|
writel(GENMASK(31, 0), reg + 4 * i);
|
||||||
@@ -73,7 +76,7 @@ static void mask_module_irq(struct mtk_devapc_context *ctx, bool mask)
|
|||||||
u32 val;
|
u32 val;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
reg = ctx->infra_base + ctx->data->vio_mask_offset;
|
reg = ctx->infra_base + ctx->data->regs_ofs->vio_mask_offset;
|
||||||
|
|
||||||
if (mask)
|
if (mask)
|
||||||
val = GENMASK(31, 0);
|
val = GENMASK(31, 0);
|
||||||
@@ -116,11 +119,11 @@ static int devapc_sync_vio_dbg(struct mtk_devapc_context *ctx)
|
|||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
pd_vio_shift_sta_reg = ctx->infra_base +
|
pd_vio_shift_sta_reg = ctx->infra_base +
|
||||||
ctx->data->vio_shift_sta_offset;
|
ctx->data->regs_ofs->vio_shift_sta_offset;
|
||||||
pd_vio_shift_sel_reg = ctx->infra_base +
|
pd_vio_shift_sel_reg = ctx->infra_base +
|
||||||
ctx->data->vio_shift_sel_offset;
|
ctx->data->regs_ofs->vio_shift_sel_offset;
|
||||||
pd_vio_shift_con_reg = ctx->infra_base +
|
pd_vio_shift_con_reg = ctx->infra_base +
|
||||||
ctx->data->vio_shift_con_offset;
|
ctx->data->regs_ofs->vio_shift_con_offset;
|
||||||
|
|
||||||
/* Find the minimum shift group which has violation */
|
/* Find the minimum shift group which has violation */
|
||||||
val = readl(pd_vio_shift_sta_reg);
|
val = readl(pd_vio_shift_sta_reg);
|
||||||
@@ -161,8 +164,8 @@ static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
|
|||||||
void __iomem *vio_dbg0_reg;
|
void __iomem *vio_dbg0_reg;
|
||||||
void __iomem *vio_dbg1_reg;
|
void __iomem *vio_dbg1_reg;
|
||||||
|
|
||||||
vio_dbg0_reg = ctx->infra_base + ctx->data->vio_dbg0_offset;
|
vio_dbg0_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg0_offset;
|
||||||
vio_dbg1_reg = ctx->infra_base + ctx->data->vio_dbg1_offset;
|
vio_dbg1_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg1_offset;
|
||||||
|
|
||||||
vio_dbgs.vio_dbg0 = readl(vio_dbg0_reg);
|
vio_dbgs.vio_dbg0 = readl(vio_dbg0_reg);
|
||||||
vio_dbgs.vio_dbg1 = readl(vio_dbg1_reg);
|
vio_dbgs.vio_dbg1 = readl(vio_dbg1_reg);
|
||||||
@@ -200,7 +203,7 @@ static irqreturn_t devapc_violation_irq(int irq_number, void *data)
|
|||||||
*/
|
*/
|
||||||
static void start_devapc(struct mtk_devapc_context *ctx)
|
static void start_devapc(struct mtk_devapc_context *ctx)
|
||||||
{
|
{
|
||||||
writel(BIT(31), ctx->infra_base + ctx->data->apc_con_offset);
|
writel(BIT(31), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
|
||||||
|
|
||||||
mask_module_irq(ctx, false);
|
mask_module_irq(ctx, false);
|
||||||
}
|
}
|
||||||
@@ -212,11 +215,10 @@ static void stop_devapc(struct mtk_devapc_context *ctx)
|
|||||||
{
|
{
|
||||||
mask_module_irq(ctx, true);
|
mask_module_irq(ctx, true);
|
||||||
|
|
||||||
writel(BIT(2), ctx->infra_base + ctx->data->apc_con_offset);
|
writel(BIT(2), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct mtk_devapc_data devapc_mt6779 = {
|
static const struct mtk_devapc_regs_ofs devapc_regs_ofs_mt6779 = {
|
||||||
.vio_idx_num = 511,
|
|
||||||
.vio_mask_offset = 0x0,
|
.vio_mask_offset = 0x0,
|
||||||
.vio_sta_offset = 0x400,
|
.vio_sta_offset = 0x400,
|
||||||
.vio_dbg0_offset = 0x900,
|
.vio_dbg0_offset = 0x900,
|
||||||
@@ -227,10 +229,23 @@ static const struct mtk_devapc_data devapc_mt6779 = {
|
|||||||
.vio_shift_con_offset = 0xF20,
|
.vio_shift_con_offset = 0xF20,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct mtk_devapc_data devapc_mt6779 = {
|
||||||
|
.vio_idx_num = 511,
|
||||||
|
.regs_ofs = &devapc_regs_ofs_mt6779,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mtk_devapc_data devapc_mt8186 = {
|
||||||
|
.vio_idx_num = 519,
|
||||||
|
.regs_ofs = &devapc_regs_ofs_mt6779,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct of_device_id mtk_devapc_dt_match[] = {
|
static const struct of_device_id mtk_devapc_dt_match[] = {
|
||||||
{
|
{
|
||||||
.compatible = "mediatek,mt6779-devapc",
|
.compatible = "mediatek,mt6779-devapc",
|
||||||
.data = &devapc_mt6779,
|
.data = &devapc_mt6779,
|
||||||
|
}, {
|
||||||
|
.compatible = "mediatek,mt8186-devapc",
|
||||||
|
.data = &devapc_mt8186,
|
||||||
}, {
|
}, {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,10 +7,12 @@
|
|||||||
#include <linux/iopoll.h>
|
#include <linux/iopoll.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/soc/mediatek/mtk-mmsys.h>
|
#include <linux/soc/mediatek/mtk-mmsys.h>
|
||||||
#include <linux/soc/mediatek/mtk-mutex.h>
|
#include <linux/soc/mediatek/mtk-mutex.h>
|
||||||
|
#include <linux/soc/mediatek/mtk-cmdq.h>
|
||||||
|
|
||||||
#define MT2701_MUTEX0_MOD0 0x2c
|
#define MT2701_MUTEX0_MOD0 0x2c
|
||||||
#define MT2701_MUTEX0_SOF0 0x30
|
#define MT2701_MUTEX0_SOF0 0x30
|
||||||
@@ -80,6 +82,15 @@
|
|||||||
#define MT8183_MUTEX_MOD_DISP_GAMMA0 16
|
#define MT8183_MUTEX_MOD_DISP_GAMMA0 16
|
||||||
#define MT8183_MUTEX_MOD_DISP_DITHER0 17
|
#define MT8183_MUTEX_MOD_DISP_DITHER0 17
|
||||||
|
|
||||||
|
#define MT8183_MUTEX_MOD_MDP_RDMA0 2
|
||||||
|
#define MT8183_MUTEX_MOD_MDP_RSZ0 4
|
||||||
|
#define MT8183_MUTEX_MOD_MDP_RSZ1 5
|
||||||
|
#define MT8183_MUTEX_MOD_MDP_TDSHP0 6
|
||||||
|
#define MT8183_MUTEX_MOD_MDP_WROT0 7
|
||||||
|
#define MT8183_MUTEX_MOD_MDP_WDMA 8
|
||||||
|
#define MT8183_MUTEX_MOD_MDP_AAL0 23
|
||||||
|
#define MT8183_MUTEX_MOD_MDP_CCORR0 24
|
||||||
|
|
||||||
#define MT8173_MUTEX_MOD_DISP_OVL0 11
|
#define MT8173_MUTEX_MOD_DISP_OVL0 11
|
||||||
#define MT8173_MUTEX_MOD_DISP_OVL1 12
|
#define MT8173_MUTEX_MOD_DISP_OVL1 12
|
||||||
#define MT8173_MUTEX_MOD_DISP_RDMA0 13
|
#define MT8173_MUTEX_MOD_DISP_RDMA0 13
|
||||||
@@ -110,6 +121,20 @@
|
|||||||
#define MT8195_MUTEX_MOD_DISP_DP_INTF0 21
|
#define MT8195_MUTEX_MOD_DISP_DP_INTF0 21
|
||||||
#define MT8195_MUTEX_MOD_DISP_PWM0 27
|
#define MT8195_MUTEX_MOD_DISP_PWM0 27
|
||||||
|
|
||||||
|
#define MT8365_MUTEX_MOD_DISP_OVL0 7
|
||||||
|
#define MT8365_MUTEX_MOD_DISP_OVL0_2L 8
|
||||||
|
#define MT8365_MUTEX_MOD_DISP_RDMA0 9
|
||||||
|
#define MT8365_MUTEX_MOD_DISP_RDMA1 10
|
||||||
|
#define MT8365_MUTEX_MOD_DISP_WDMA0 11
|
||||||
|
#define MT8365_MUTEX_MOD_DISP_COLOR0 12
|
||||||
|
#define MT8365_MUTEX_MOD_DISP_CCORR 13
|
||||||
|
#define MT8365_MUTEX_MOD_DISP_AAL 14
|
||||||
|
#define MT8365_MUTEX_MOD_DISP_GAMMA 15
|
||||||
|
#define MT8365_MUTEX_MOD_DISP_DITHER 16
|
||||||
|
#define MT8365_MUTEX_MOD_DISP_DSI0 17
|
||||||
|
#define MT8365_MUTEX_MOD_DISP_PWM0 20
|
||||||
|
#define MT8365_MUTEX_MOD_DISP_DPI0 22
|
||||||
|
|
||||||
#define MT2712_MUTEX_MOD_DISP_PWM2 10
|
#define MT2712_MUTEX_MOD_DISP_PWM2 10
|
||||||
#define MT2712_MUTEX_MOD_DISP_OVL0 11
|
#define MT2712_MUTEX_MOD_DISP_OVL0 11
|
||||||
#define MT2712_MUTEX_MOD_DISP_OVL1 12
|
#define MT2712_MUTEX_MOD_DISP_OVL1 12
|
||||||
@@ -185,6 +210,7 @@ struct mtk_mutex_data {
|
|||||||
const unsigned int *mutex_sof;
|
const unsigned int *mutex_sof;
|
||||||
const unsigned int mutex_mod_reg;
|
const unsigned int mutex_mod_reg;
|
||||||
const unsigned int mutex_sof_reg;
|
const unsigned int mutex_sof_reg;
|
||||||
|
const unsigned int *mutex_table_mod;
|
||||||
const bool no_clk;
|
const bool no_clk;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -194,6 +220,8 @@ struct mtk_mutex_ctx {
|
|||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
struct mtk_mutex mutex[10];
|
struct mtk_mutex mutex[10];
|
||||||
const struct mtk_mutex_data *data;
|
const struct mtk_mutex_data *data;
|
||||||
|
phys_addr_t addr;
|
||||||
|
struct cmdq_client_reg cmdq_reg;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
|
static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
|
||||||
@@ -272,6 +300,17 @@ static const unsigned int mt8183_mutex_mod[DDP_COMPONENT_ID_MAX] = {
|
|||||||
[DDP_COMPONENT_WDMA0] = MT8183_MUTEX_MOD_DISP_WDMA0,
|
[DDP_COMPONENT_WDMA0] = MT8183_MUTEX_MOD_DISP_WDMA0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const unsigned int mt8183_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
|
||||||
|
[MUTEX_MOD_IDX_MDP_RDMA0] = MT8183_MUTEX_MOD_MDP_RDMA0,
|
||||||
|
[MUTEX_MOD_IDX_MDP_RSZ0] = MT8183_MUTEX_MOD_MDP_RSZ0,
|
||||||
|
[MUTEX_MOD_IDX_MDP_RSZ1] = MT8183_MUTEX_MOD_MDP_RSZ1,
|
||||||
|
[MUTEX_MOD_IDX_MDP_TDSHP0] = MT8183_MUTEX_MOD_MDP_TDSHP0,
|
||||||
|
[MUTEX_MOD_IDX_MDP_WROT0] = MT8183_MUTEX_MOD_MDP_WROT0,
|
||||||
|
[MUTEX_MOD_IDX_MDP_WDMA] = MT8183_MUTEX_MOD_MDP_WDMA,
|
||||||
|
[MUTEX_MOD_IDX_MDP_AAL0] = MT8183_MUTEX_MOD_MDP_AAL0,
|
||||||
|
[MUTEX_MOD_IDX_MDP_CCORR0] = MT8183_MUTEX_MOD_MDP_CCORR0,
|
||||||
|
};
|
||||||
|
|
||||||
static const unsigned int mt8186_mutex_mod[DDP_COMPONENT_ID_MAX] = {
|
static const unsigned int mt8186_mutex_mod[DDP_COMPONENT_ID_MAX] = {
|
||||||
[DDP_COMPONENT_AAL0] = MT8186_MUTEX_MOD_DISP_AAL0,
|
[DDP_COMPONENT_AAL0] = MT8186_MUTEX_MOD_DISP_AAL0,
|
||||||
[DDP_COMPONENT_CCORR] = MT8186_MUTEX_MOD_DISP_CCORR0,
|
[DDP_COMPONENT_CCORR] = MT8186_MUTEX_MOD_DISP_CCORR0,
|
||||||
@@ -315,6 +354,22 @@ static const unsigned int mt8195_mutex_mod[DDP_COMPONENT_ID_MAX] = {
|
|||||||
[DDP_COMPONENT_DP_INTF0] = MT8195_MUTEX_MOD_DISP_DP_INTF0,
|
[DDP_COMPONENT_DP_INTF0] = MT8195_MUTEX_MOD_DISP_DP_INTF0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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,
|
||||||
|
[DDP_COMPONENT_COLOR0] = MT8365_MUTEX_MOD_DISP_COLOR0,
|
||||||
|
[DDP_COMPONENT_DITHER0] = MT8365_MUTEX_MOD_DISP_DITHER,
|
||||||
|
[DDP_COMPONENT_DPI0] = MT8365_MUTEX_MOD_DISP_DPI0,
|
||||||
|
[DDP_COMPONENT_DSI0] = MT8365_MUTEX_MOD_DISP_DSI0,
|
||||||
|
[DDP_COMPONENT_GAMMA] = MT8365_MUTEX_MOD_DISP_GAMMA,
|
||||||
|
[DDP_COMPONENT_OVL0] = MT8365_MUTEX_MOD_DISP_OVL0,
|
||||||
|
[DDP_COMPONENT_OVL_2L0] = MT8365_MUTEX_MOD_DISP_OVL0_2L,
|
||||||
|
[DDP_COMPONENT_PWM0] = MT8365_MUTEX_MOD_DISP_PWM0,
|
||||||
|
[DDP_COMPONENT_RDMA0] = MT8365_MUTEX_MOD_DISP_RDMA0,
|
||||||
|
[DDP_COMPONENT_RDMA1] = MT8365_MUTEX_MOD_DISP_RDMA1,
|
||||||
|
[DDP_COMPONENT_WDMA0] = MT8365_MUTEX_MOD_DISP_WDMA0,
|
||||||
|
};
|
||||||
|
|
||||||
static const unsigned int mt2712_mutex_sof[DDP_MUTEX_SOF_MAX] = {
|
static const unsigned int mt2712_mutex_sof[DDP_MUTEX_SOF_MAX] = {
|
||||||
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
|
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
|
||||||
[MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
|
[MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
|
||||||
@@ -399,6 +454,7 @@ static const struct mtk_mutex_data mt8183_mutex_driver_data = {
|
|||||||
.mutex_sof = mt8183_mutex_sof,
|
.mutex_sof = mt8183_mutex_sof,
|
||||||
.mutex_mod_reg = MT8183_MUTEX0_MOD0,
|
.mutex_mod_reg = MT8183_MUTEX0_MOD0,
|
||||||
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
|
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
|
||||||
|
.mutex_table_mod = mt8183_mutex_table_mod,
|
||||||
.no_clk = true,
|
.no_clk = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -423,6 +479,14 @@ static const struct mtk_mutex_data mt8195_mutex_driver_data = {
|
|||||||
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
|
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct mtk_mutex_data mt8365_mutex_driver_data = {
|
||||||
|
.mutex_mod = mt8365_mutex_mod,
|
||||||
|
.mutex_sof = mt8183_mutex_sof,
|
||||||
|
.mutex_mod_reg = MT8183_MUTEX0_MOD0,
|
||||||
|
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
|
||||||
|
.no_clk = true,
|
||||||
|
};
|
||||||
|
|
||||||
struct mtk_mutex *mtk_mutex_get(struct device *dev)
|
struct mtk_mutex *mtk_mutex_get(struct device *dev)
|
||||||
{
|
{
|
||||||
struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev);
|
struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev);
|
||||||
@@ -572,6 +636,30 @@ void mtk_mutex_enable(struct mtk_mutex *mutex)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mtk_mutex_enable);
|
EXPORT_SYMBOL_GPL(mtk_mutex_enable);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
void mtk_mutex_disable(struct mtk_mutex *mutex)
|
void mtk_mutex_disable(struct mtk_mutex *mutex)
|
||||||
{
|
{
|
||||||
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
|
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
|
||||||
@@ -606,12 +694,67 @@ void mtk_mutex_release(struct mtk_mutex *mutex)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mtk_mutex_release);
|
EXPORT_SYMBOL_GPL(mtk_mutex_release);
|
||||||
|
|
||||||
|
int mtk_mutex_write_mod(struct mtk_mutex *mutex,
|
||||||
|
enum mtk_mutex_mod_index idx, bool clear)
|
||||||
|
{
|
||||||
|
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
|
||||||
|
mutex[mutex->id]);
|
||||||
|
unsigned int reg;
|
||||||
|
unsigned int offset;
|
||||||
|
|
||||||
|
WARN_ON(&mtx->mutex[mutex->id] != mutex);
|
||||||
|
|
||||||
|
if (idx < MUTEX_MOD_IDX_MDP_RDMA0 ||
|
||||||
|
idx >= MUTEX_MOD_IDX_MAX) {
|
||||||
|
dev_err(mtx->dev, "Not supported MOD table index : %d", idx);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
|
||||||
|
mutex->id);
|
||||||
|
reg = readl_relaxed(mtx->regs + offset);
|
||||||
|
|
||||||
|
if (clear)
|
||||||
|
reg &= ~BIT(mtx->data->mutex_table_mod[idx]);
|
||||||
|
else
|
||||||
|
reg |= BIT(mtx->data->mutex_table_mod[idx]);
|
||||||
|
|
||||||
|
writel_relaxed(reg, mtx->regs + offset);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtk_mutex_write_mod);
|
||||||
|
|
||||||
|
int mtk_mutex_write_sof(struct mtk_mutex *mutex,
|
||||||
|
enum mtk_mutex_sof_index idx)
|
||||||
|
{
|
||||||
|
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
|
||||||
|
mutex[mutex->id]);
|
||||||
|
|
||||||
|
WARN_ON(&mtx->mutex[mutex->id] != mutex);
|
||||||
|
|
||||||
|
if (idx < MUTEX_SOF_IDX_SINGLE_MODE ||
|
||||||
|
idx >= MUTEX_SOF_IDX_MAX) {
|
||||||
|
dev_err(mtx->dev, "Not supported SOF index : %d", idx);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
writel_relaxed(idx, mtx->regs +
|
||||||
|
DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg, mutex->id));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtk_mutex_write_sof);
|
||||||
|
|
||||||
static int mtk_mutex_probe(struct platform_device *pdev)
|
static int mtk_mutex_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct mtk_mutex_ctx *mtx;
|
struct mtk_mutex_ctx *mtx;
|
||||||
struct resource *regs;
|
struct resource *regs;
|
||||||
int i;
|
int i;
|
||||||
|
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
|
||||||
|
int ret;
|
||||||
|
#endif
|
||||||
|
|
||||||
mtx = devm_kzalloc(dev, sizeof(*mtx), GFP_KERNEL);
|
mtx = devm_kzalloc(dev, sizeof(*mtx), GFP_KERNEL);
|
||||||
if (!mtx)
|
if (!mtx)
|
||||||
@@ -631,12 +774,18 @@ static int mtk_mutex_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
mtx->regs = devm_platform_get_and_ioremap_resource(pdev, 0, ®s);
|
||||||
mtx->regs = devm_ioremap_resource(dev, regs);
|
|
||||||
if (IS_ERR(mtx->regs)) {
|
if (IS_ERR(mtx->regs)) {
|
||||||
dev_err(dev, "Failed to map mutex registers\n");
|
dev_err(dev, "Failed to map mutex registers\n");
|
||||||
return PTR_ERR(mtx->regs);
|
return PTR_ERR(mtx->regs);
|
||||||
}
|
}
|
||||||
|
mtx->addr = regs->start;
|
||||||
|
|
||||||
|
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
|
||||||
|
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);
|
platform_set_drvdata(pdev, mtx);
|
||||||
|
|
||||||
@@ -665,6 +814,8 @@ static const struct of_device_id mutex_driver_dt_match[] = {
|
|||||||
.data = &mt8192_mutex_driver_data},
|
.data = &mt8192_mutex_driver_data},
|
||||||
{ .compatible = "mediatek,mt8195-disp-mutex",
|
{ .compatible = "mediatek,mt8195-disp-mutex",
|
||||||
.data = &mt8195_mutex_driver_data},
|
.data = &mt8195_mutex_driver_data},
|
||||||
|
{ .compatible = "mediatek,mt8365-disp-mutex",
|
||||||
|
.data = &mt8365_mutex_driver_data},
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, mutex_driver_dt_match);
|
MODULE_DEVICE_TABLE(of, mutex_driver_dt_match);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/soc/mediatek/infracfg.h>
|
#include <linux/soc/mediatek/infracfg.h>
|
||||||
|
|
||||||
|
#include "mt6795-pm-domains.h"
|
||||||
#include "mt8167-pm-domains.h"
|
#include "mt8167-pm-domains.h"
|
||||||
#include "mt8173-pm-domains.h"
|
#include "mt8173-pm-domains.h"
|
||||||
#include "mt8183-pm-domains.h"
|
#include "mt8183-pm-domains.h"
|
||||||
@@ -428,6 +429,9 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
|
|||||||
dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret);
|
dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret);
|
||||||
goto err_put_subsys_clocks;
|
goto err_put_subsys_clocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (MTK_SCPD_CAPS(pd, MTK_SCPD_ALWAYS_ON))
|
||||||
|
pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scpsys->domains[id]) {
|
if (scpsys->domains[id]) {
|
||||||
@@ -555,6 +559,10 @@ static void scpsys_domain_cleanup(struct scpsys *scpsys)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id scpsys_of_match[] = {
|
static const struct of_device_id scpsys_of_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "mediatek,mt6795-power-controller",
|
||||||
|
.data = &mt6795_scpsys_data,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.compatible = "mediatek,mt8167-power-controller",
|
.compatible = "mediatek,mt8167-power-controller",
|
||||||
.data = &mt8167_scpsys_data,
|
.data = &mt8167_scpsys_data,
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#define MTK_SCPD_SRAM_ISO BIT(2)
|
#define MTK_SCPD_SRAM_ISO BIT(2)
|
||||||
#define MTK_SCPD_KEEP_DEFAULT_OFF BIT(3)
|
#define MTK_SCPD_KEEP_DEFAULT_OFF BIT(3)
|
||||||
#define MTK_SCPD_DOMAIN_SUPPLY BIT(4)
|
#define MTK_SCPD_DOMAIN_SUPPLY BIT(4)
|
||||||
|
/* can't set MTK_SCPD_KEEP_DEFAULT_OFF at the same time */
|
||||||
|
#define MTK_SCPD_ALWAYS_ON BIT(5)
|
||||||
#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x))
|
#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x))
|
||||||
|
|
||||||
#define SPM_VDE_PWR_CON 0x0210
|
#define SPM_VDE_PWR_CON 0x0210
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/reset.h>
|
#include <linux/reset.h>
|
||||||
|
|
||||||
|
#define PWRAP_POLL_DELAY_US 10
|
||||||
|
#define PWRAP_POLL_TIMEOUT_US 10000
|
||||||
|
|
||||||
#define PWRAP_MT8135_BRIDGE_IORD_ARB_EN 0x4
|
#define PWRAP_MT8135_BRIDGE_IORD_ARB_EN 0x4
|
||||||
#define PWRAP_MT8135_BRIDGE_WACS3_EN 0x10
|
#define PWRAP_MT8135_BRIDGE_WACS3_EN 0x10
|
||||||
#define PWRAP_MT8135_BRIDGE_INIT_DONE3 0x14
|
#define PWRAP_MT8135_BRIDGE_INIT_DONE3 0x14
|
||||||
@@ -1140,12 +1143,9 @@ enum pwrap_type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct pmic_wrapper;
|
struct pmic_wrapper;
|
||||||
struct pwrap_slv_type {
|
|
||||||
const u32 *dew_regs;
|
struct pwrap_slv_regops {
|
||||||
enum pmic_type type;
|
|
||||||
const struct regmap_config *regmap;
|
const struct regmap_config *regmap;
|
||||||
/* Flags indicating the capability for the target slave */
|
|
||||||
u32 caps;
|
|
||||||
/*
|
/*
|
||||||
* pwrap operations are highly associated with the PMIC types,
|
* pwrap operations are highly associated with the PMIC types,
|
||||||
* so the pointers added increases flexibility allowing determination
|
* so the pointers added increases flexibility allowing determination
|
||||||
@@ -1155,6 +1155,14 @@ struct pwrap_slv_type {
|
|||||||
int (*pwrap_write)(struct pmic_wrapper *wrp, u32 adr, u32 wdata);
|
int (*pwrap_write)(struct pmic_wrapper *wrp, u32 adr, u32 wdata);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct pwrap_slv_type {
|
||||||
|
const u32 *dew_regs;
|
||||||
|
enum pmic_type type;
|
||||||
|
const struct pwrap_slv_regops *regops;
|
||||||
|
/* Flags indicating the capability for the target slave */
|
||||||
|
u32 caps;
|
||||||
|
};
|
||||||
|
|
||||||
struct pmic_wrapper {
|
struct pmic_wrapper {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
@@ -1241,27 +1249,14 @@ static bool pwrap_is_fsm_idle_and_sync_idle(struct pmic_wrapper *wrp)
|
|||||||
(val & PWRAP_STATE_SYNC_IDLE0);
|
(val & PWRAP_STATE_SYNC_IDLE0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pwrap_wait_for_state(struct pmic_wrapper *wrp,
|
|
||||||
bool (*fp)(struct pmic_wrapper *))
|
|
||||||
{
|
|
||||||
unsigned long timeout;
|
|
||||||
|
|
||||||
timeout = jiffies + usecs_to_jiffies(10000);
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (time_after(jiffies, timeout))
|
|
||||||
return fp(wrp) ? 0 : -ETIMEDOUT;
|
|
||||||
if (fp(wrp))
|
|
||||||
return 0;
|
|
||||||
} while (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pwrap_read16(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
|
static int pwrap_read16(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
|
||||||
{
|
{
|
||||||
|
bool tmp;
|
||||||
int ret;
|
int ret;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
|
ret = readx_poll_timeout(pwrap_is_fsm_idle, wrp, tmp, tmp,
|
||||||
|
PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pwrap_leave_fsm_vldclr(wrp);
|
pwrap_leave_fsm_vldclr(wrp);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1273,7 +1268,8 @@ static int pwrap_read16(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
|
|||||||
val = (adr >> 1) << 16;
|
val = (adr >> 1) << 16;
|
||||||
pwrap_writel(wrp, val, PWRAP_WACS2_CMD);
|
pwrap_writel(wrp, val, PWRAP_WACS2_CMD);
|
||||||
|
|
||||||
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_vldclr);
|
ret = readx_poll_timeout(pwrap_is_fsm_vldclr, wrp, tmp, tmp,
|
||||||
|
PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -1290,11 +1286,14 @@ static int pwrap_read16(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
|
|||||||
|
|
||||||
static int pwrap_read32(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
|
static int pwrap_read32(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
|
||||||
{
|
{
|
||||||
|
bool tmp;
|
||||||
int ret, msb;
|
int ret, msb;
|
||||||
|
|
||||||
*rdata = 0;
|
*rdata = 0;
|
||||||
for (msb = 0; msb < 2; msb++) {
|
for (msb = 0; msb < 2; msb++) {
|
||||||
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
|
ret = readx_poll_timeout(pwrap_is_fsm_idle, wrp, tmp, tmp,
|
||||||
|
PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pwrap_leave_fsm_vldclr(wrp);
|
pwrap_leave_fsm_vldclr(wrp);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1303,7 +1302,8 @@ static int pwrap_read32(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
|
|||||||
pwrap_writel(wrp, ((msb << 30) | (adr << 16)),
|
pwrap_writel(wrp, ((msb << 30) | (adr << 16)),
|
||||||
PWRAP_WACS2_CMD);
|
PWRAP_WACS2_CMD);
|
||||||
|
|
||||||
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_vldclr);
|
ret = readx_poll_timeout(pwrap_is_fsm_vldclr, wrp, tmp, tmp,
|
||||||
|
PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -1318,14 +1318,16 @@ static int pwrap_read32(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
|
|||||||
|
|
||||||
static int pwrap_read(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
|
static int pwrap_read(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
|
||||||
{
|
{
|
||||||
return wrp->slave->pwrap_read(wrp, adr, rdata);
|
return wrp->slave->regops->pwrap_read(wrp, adr, rdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pwrap_write16(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
|
static int pwrap_write16(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
|
||||||
{
|
{
|
||||||
|
bool tmp;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
|
ret = readx_poll_timeout(pwrap_is_fsm_idle, wrp, tmp, tmp,
|
||||||
|
PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pwrap_leave_fsm_vldclr(wrp);
|
pwrap_leave_fsm_vldclr(wrp);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1344,10 +1346,12 @@ static int pwrap_write16(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
|
|||||||
|
|
||||||
static int pwrap_write32(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
|
static int pwrap_write32(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
|
||||||
{
|
{
|
||||||
|
bool tmp;
|
||||||
int ret, msb, rdata;
|
int ret, msb, rdata;
|
||||||
|
|
||||||
for (msb = 0; msb < 2; msb++) {
|
for (msb = 0; msb < 2; msb++) {
|
||||||
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
|
ret = readx_poll_timeout(pwrap_is_fsm_idle, wrp, tmp, tmp,
|
||||||
|
PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pwrap_leave_fsm_vldclr(wrp);
|
pwrap_leave_fsm_vldclr(wrp);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1373,7 +1377,7 @@ static int pwrap_write32(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
|
|||||||
|
|
||||||
static int pwrap_write(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
|
static int pwrap_write(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
|
||||||
{
|
{
|
||||||
return wrp->slave->pwrap_write(wrp, adr, wdata);
|
return wrp->slave->regops->pwrap_write(wrp, adr, wdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pwrap_regmap_read(void *context, u32 adr, u32 *rdata)
|
static int pwrap_regmap_read(void *context, u32 adr, u32 *rdata)
|
||||||
@@ -1388,6 +1392,7 @@ static int pwrap_regmap_write(void *context, u32 adr, u32 wdata)
|
|||||||
|
|
||||||
static int pwrap_reset_spislave(struct pmic_wrapper *wrp)
|
static int pwrap_reset_spislave(struct pmic_wrapper *wrp)
|
||||||
{
|
{
|
||||||
|
bool tmp;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
pwrap_writel(wrp, 0, PWRAP_HIPRIO_ARB_EN);
|
pwrap_writel(wrp, 0, PWRAP_HIPRIO_ARB_EN);
|
||||||
@@ -1407,7 +1412,8 @@ static int pwrap_reset_spislave(struct pmic_wrapper *wrp)
|
|||||||
pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_OUTS,
|
pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_OUTS,
|
||||||
PWRAP_MAN_CMD);
|
PWRAP_MAN_CMD);
|
||||||
|
|
||||||
ret = pwrap_wait_for_state(wrp, pwrap_is_sync_idle);
|
ret = readx_poll_timeout(pwrap_is_sync_idle, wrp, tmp, tmp,
|
||||||
|
PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(wrp->dev, "%s fail, ret=%d\n", __func__, ret);
|
dev_err(wrp->dev, "%s fail, ret=%d\n", __func__, ret);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1458,14 +1464,15 @@ static int pwrap_init_sidly(struct pmic_wrapper *wrp)
|
|||||||
static int pwrap_init_dual_io(struct pmic_wrapper *wrp)
|
static int pwrap_init_dual_io(struct pmic_wrapper *wrp)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
bool tmp;
|
||||||
u32 rdata;
|
u32 rdata;
|
||||||
|
|
||||||
/* Enable dual IO mode */
|
/* Enable dual IO mode */
|
||||||
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_DIO_EN], 1);
|
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_DIO_EN], 1);
|
||||||
|
|
||||||
/* Check IDLE & INIT_DONE in advance */
|
/* Check IDLE & INIT_DONE in advance */
|
||||||
ret = pwrap_wait_for_state(wrp,
|
ret = readx_poll_timeout(pwrap_is_fsm_idle_and_sync_idle, wrp, tmp, tmp,
|
||||||
pwrap_is_fsm_idle_and_sync_idle);
|
PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(wrp->dev, "%s fail, ret=%d\n", __func__, ret);
|
dev_err(wrp->dev, "%s fail, ret=%d\n", __func__, ret);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1570,6 +1577,7 @@ static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp)
|
|||||||
static int pwrap_init_cipher(struct pmic_wrapper *wrp)
|
static int pwrap_init_cipher(struct pmic_wrapper *wrp)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
bool tmp;
|
||||||
u32 rdata = 0;
|
u32 rdata = 0;
|
||||||
|
|
||||||
pwrap_writel(wrp, 0x1, PWRAP_CIPHER_SWRST);
|
pwrap_writel(wrp, 0x1, PWRAP_CIPHER_SWRST);
|
||||||
@@ -1624,14 +1632,16 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* wait for cipher data ready@AP */
|
/* wait for cipher data ready@AP */
|
||||||
ret = pwrap_wait_for_state(wrp, pwrap_is_cipher_ready);
|
ret = readx_poll_timeout(pwrap_is_cipher_ready, wrp, tmp, tmp,
|
||||||
|
PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(wrp->dev, "cipher data ready@AP fail, ret=%d\n", ret);
|
dev_err(wrp->dev, "cipher data ready@AP fail, ret=%d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* wait for cipher data ready@PMIC */
|
/* wait for cipher data ready@PMIC */
|
||||||
ret = pwrap_wait_for_state(wrp, pwrap_is_pmic_cipher_ready);
|
ret = readx_poll_timeout(pwrap_is_pmic_cipher_ready, wrp, tmp, tmp,
|
||||||
|
PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(wrp->dev,
|
dev_err(wrp->dev,
|
||||||
"timeout waiting for cipher data ready@PMIC\n");
|
"timeout waiting for cipher data ready@PMIC\n");
|
||||||
@@ -1640,7 +1650,8 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
|
|||||||
|
|
||||||
/* wait for cipher mode idle */
|
/* wait for cipher mode idle */
|
||||||
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_MODE], 0x1);
|
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_MODE], 0x1);
|
||||||
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle_and_sync_idle);
|
ret = readx_poll_timeout(pwrap_is_fsm_idle_and_sync_idle, wrp, tmp, tmp,
|
||||||
|
PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(wrp->dev, "cipher mode idle fail, ret=%d\n", ret);
|
dev_err(wrp->dev, "cipher mode idle fail, ret=%d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1885,99 +1896,82 @@ static const struct regmap_config pwrap_regmap_config32 = {
|
|||||||
.max_register = 0xffff,
|
.max_register = 0xffff,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct pwrap_slv_regops pwrap_regops16 = {
|
||||||
|
.pwrap_read = pwrap_read16,
|
||||||
|
.pwrap_write = pwrap_write16,
|
||||||
|
.regmap = &pwrap_regmap_config16,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pwrap_slv_regops pwrap_regops32 = {
|
||||||
|
.pwrap_read = pwrap_read32,
|
||||||
|
.pwrap_write = pwrap_write32,
|
||||||
|
.regmap = &pwrap_regmap_config32,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct pwrap_slv_type pmic_mt6323 = {
|
static const struct pwrap_slv_type pmic_mt6323 = {
|
||||||
.dew_regs = mt6323_regs,
|
.dew_regs = mt6323_regs,
|
||||||
.type = PMIC_MT6323,
|
.type = PMIC_MT6323,
|
||||||
.regmap = &pwrap_regmap_config16,
|
.regops = &pwrap_regops16,
|
||||||
.caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO |
|
.caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO |
|
||||||
PWRAP_SLV_CAP_SECURITY,
|
PWRAP_SLV_CAP_SECURITY,
|
||||||
.pwrap_read = pwrap_read16,
|
|
||||||
.pwrap_write = pwrap_write16,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct pwrap_slv_type pmic_mt6351 = {
|
static const struct pwrap_slv_type pmic_mt6351 = {
|
||||||
.dew_regs = mt6351_regs,
|
.dew_regs = mt6351_regs,
|
||||||
.type = PMIC_MT6351,
|
.type = PMIC_MT6351,
|
||||||
.regmap = &pwrap_regmap_config16,
|
.regops = &pwrap_regops16,
|
||||||
.caps = 0,
|
.caps = 0,
|
||||||
.pwrap_read = pwrap_read16,
|
|
||||||
.pwrap_write = pwrap_write16,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct pwrap_slv_type pmic_mt6357 = {
|
static const struct pwrap_slv_type pmic_mt6357 = {
|
||||||
.dew_regs = mt6357_regs,
|
.dew_regs = mt6357_regs,
|
||||||
.type = PMIC_MT6357,
|
.type = PMIC_MT6357,
|
||||||
.regmap = &pwrap_regmap_config16,
|
.regops = &pwrap_regops16,
|
||||||
.caps = 0,
|
.caps = 0,
|
||||||
.pwrap_read = pwrap_read16,
|
|
||||||
.pwrap_write = pwrap_write16,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct pwrap_slv_type pmic_mt6358 = {
|
static const struct pwrap_slv_type pmic_mt6358 = {
|
||||||
.dew_regs = mt6358_regs,
|
.dew_regs = mt6358_regs,
|
||||||
.type = PMIC_MT6358,
|
.type = PMIC_MT6358,
|
||||||
.regmap = &pwrap_regmap_config16,
|
.regops = &pwrap_regops16,
|
||||||
.caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO,
|
.caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO,
|
||||||
.pwrap_read = pwrap_read16,
|
|
||||||
.pwrap_write = pwrap_write16,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct pwrap_slv_type pmic_mt6359 = {
|
static const struct pwrap_slv_type pmic_mt6359 = {
|
||||||
.dew_regs = mt6359_regs,
|
.dew_regs = mt6359_regs,
|
||||||
.type = PMIC_MT6359,
|
.type = PMIC_MT6359,
|
||||||
.regmap = &pwrap_regmap_config16,
|
.regops = &pwrap_regops16,
|
||||||
.caps = PWRAP_SLV_CAP_DUALIO,
|
.caps = PWRAP_SLV_CAP_DUALIO,
|
||||||
.pwrap_read = pwrap_read16,
|
|
||||||
.pwrap_write = pwrap_write16,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct pwrap_slv_type pmic_mt6380 = {
|
static const struct pwrap_slv_type pmic_mt6380 = {
|
||||||
.dew_regs = NULL,
|
.dew_regs = NULL,
|
||||||
.type = PMIC_MT6380,
|
.type = PMIC_MT6380,
|
||||||
.regmap = &pwrap_regmap_config32,
|
.regops = &pwrap_regops32,
|
||||||
.caps = 0,
|
.caps = 0,
|
||||||
.pwrap_read = pwrap_read32,
|
|
||||||
.pwrap_write = pwrap_write32,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct pwrap_slv_type pmic_mt6397 = {
|
static const struct pwrap_slv_type pmic_mt6397 = {
|
||||||
.dew_regs = mt6397_regs,
|
.dew_regs = mt6397_regs,
|
||||||
.type = PMIC_MT6397,
|
.type = PMIC_MT6397,
|
||||||
.regmap = &pwrap_regmap_config16,
|
.regops = &pwrap_regops16,
|
||||||
.caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO |
|
.caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO |
|
||||||
PWRAP_SLV_CAP_SECURITY,
|
PWRAP_SLV_CAP_SECURITY,
|
||||||
.pwrap_read = pwrap_read16,
|
|
||||||
.pwrap_write = pwrap_write16,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id of_slave_match_tbl[] = {
|
static const struct of_device_id of_slave_match_tbl[] = {
|
||||||
{
|
{ .compatible = "mediatek,mt6323", .data = &pmic_mt6323 },
|
||||||
.compatible = "mediatek,mt6323",
|
{ .compatible = "mediatek,mt6351", .data = &pmic_mt6351 },
|
||||||
.data = &pmic_mt6323,
|
{ .compatible = "mediatek,mt6357", .data = &pmic_mt6357 },
|
||||||
}, {
|
{ .compatible = "mediatek,mt6358", .data = &pmic_mt6358 },
|
||||||
.compatible = "mediatek,mt6351",
|
{ .compatible = "mediatek,mt6359", .data = &pmic_mt6359 },
|
||||||
.data = &pmic_mt6351,
|
|
||||||
}, {
|
/* The MT6380 PMIC only implements a regulator, so we bind it
|
||||||
.compatible = "mediatek,mt6357",
|
* directly instead of using a MFD.
|
||||||
.data = &pmic_mt6357,
|
*/
|
||||||
}, {
|
{ .compatible = "mediatek,mt6380-regulator", .data = &pmic_mt6380 },
|
||||||
.compatible = "mediatek,mt6358",
|
{ .compatible = "mediatek,mt6397", .data = &pmic_mt6397 },
|
||||||
.data = &pmic_mt6358,
|
{ /* sentinel */ }
|
||||||
}, {
|
|
||||||
.compatible = "mediatek,mt6359",
|
|
||||||
.data = &pmic_mt6359,
|
|
||||||
}, {
|
|
||||||
/* The MT6380 PMIC only implements a regulator, so we bind it
|
|
||||||
* directly instead of using a MFD.
|
|
||||||
*/
|
|
||||||
.compatible = "mediatek,mt6380-regulator",
|
|
||||||
.data = &pmic_mt6380,
|
|
||||||
}, {
|
|
||||||
.compatible = "mediatek,mt6397",
|
|
||||||
.data = &pmic_mt6397,
|
|
||||||
}, {
|
|
||||||
/* sentinel */
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, of_slave_match_tbl);
|
MODULE_DEVICE_TABLE(of, of_slave_match_tbl);
|
||||||
|
|
||||||
@@ -2136,45 +2130,19 @@ static struct pmic_wrapper_type pwrap_mt8186 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id of_pwrap_match_tbl[] = {
|
static const struct of_device_id of_pwrap_match_tbl[] = {
|
||||||
{
|
{ .compatible = "mediatek,mt2701-pwrap", .data = &pwrap_mt2701 },
|
||||||
.compatible = "mediatek,mt2701-pwrap",
|
{ .compatible = "mediatek,mt6765-pwrap", .data = &pwrap_mt6765 },
|
||||||
.data = &pwrap_mt2701,
|
{ .compatible = "mediatek,mt6779-pwrap", .data = &pwrap_mt6779 },
|
||||||
}, {
|
{ .compatible = "mediatek,mt6797-pwrap", .data = &pwrap_mt6797 },
|
||||||
.compatible = "mediatek,mt6765-pwrap",
|
{ .compatible = "mediatek,mt6873-pwrap", .data = &pwrap_mt6873 },
|
||||||
.data = &pwrap_mt6765,
|
{ .compatible = "mediatek,mt7622-pwrap", .data = &pwrap_mt7622 },
|
||||||
}, {
|
{ .compatible = "mediatek,mt8135-pwrap", .data = &pwrap_mt8135 },
|
||||||
.compatible = "mediatek,mt6779-pwrap",
|
{ .compatible = "mediatek,mt8173-pwrap", .data = &pwrap_mt8173 },
|
||||||
.data = &pwrap_mt6779,
|
{ .compatible = "mediatek,mt8183-pwrap", .data = &pwrap_mt8183 },
|
||||||
}, {
|
{ .compatible = "mediatek,mt8186-pwrap", .data = &pwrap_mt8186 },
|
||||||
.compatible = "mediatek,mt6797-pwrap",
|
{ .compatible = "mediatek,mt8195-pwrap", .data = &pwrap_mt8195 },
|
||||||
.data = &pwrap_mt6797,
|
{ .compatible = "mediatek,mt8516-pwrap", .data = &pwrap_mt8516 },
|
||||||
}, {
|
{ /* sentinel */ }
|
||||||
.compatible = "mediatek,mt6873-pwrap",
|
|
||||||
.data = &pwrap_mt6873,
|
|
||||||
}, {
|
|
||||||
.compatible = "mediatek,mt7622-pwrap",
|
|
||||||
.data = &pwrap_mt7622,
|
|
||||||
}, {
|
|
||||||
.compatible = "mediatek,mt8135-pwrap",
|
|
||||||
.data = &pwrap_mt8135,
|
|
||||||
}, {
|
|
||||||
.compatible = "mediatek,mt8173-pwrap",
|
|
||||||
.data = &pwrap_mt8173,
|
|
||||||
}, {
|
|
||||||
.compatible = "mediatek,mt8183-pwrap",
|
|
||||||
.data = &pwrap_mt8183,
|
|
||||||
}, {
|
|
||||||
.compatible = "mediatek,mt8186-pwrap",
|
|
||||||
.data = &pwrap_mt8186,
|
|
||||||
}, {
|
|
||||||
.compatible = "mediatek,mt8195-pwrap",
|
|
||||||
.data = &pwrap_mt8195,
|
|
||||||
}, {
|
|
||||||
.compatible = "mediatek,mt8516-pwrap",
|
|
||||||
.data = &pwrap_mt8516,
|
|
||||||
}, {
|
|
||||||
/* sentinel */
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl);
|
MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl);
|
||||||
|
|
||||||
@@ -2185,7 +2153,6 @@ static int pwrap_probe(struct platform_device *pdev)
|
|||||||
struct pmic_wrapper *wrp;
|
struct pmic_wrapper *wrp;
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
const struct of_device_id *of_slave_id = NULL;
|
const struct of_device_id *of_slave_id = NULL;
|
||||||
struct resource *res;
|
|
||||||
|
|
||||||
if (np->child)
|
if (np->child)
|
||||||
of_slave_id = of_match_node(of_slave_match_tbl, np->child);
|
of_slave_id = of_match_node(of_slave_match_tbl, np->child);
|
||||||
@@ -2205,8 +2172,7 @@ static int pwrap_probe(struct platform_device *pdev)
|
|||||||
wrp->slave = of_slave_id->data;
|
wrp->slave = of_slave_id->data;
|
||||||
wrp->dev = &pdev->dev;
|
wrp->dev = &pdev->dev;
|
||||||
|
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrap");
|
wrp->base = devm_platform_ioremap_resource_byname(pdev, "pwrap");
|
||||||
wrp->base = devm_ioremap_resource(wrp->dev, res);
|
|
||||||
if (IS_ERR(wrp->base))
|
if (IS_ERR(wrp->base))
|
||||||
return PTR_ERR(wrp->base);
|
return PTR_ERR(wrp->base);
|
||||||
|
|
||||||
@@ -2220,9 +2186,7 @@ static int pwrap_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_CAP(wrp->master->caps, PWRAP_CAP_BRIDGE)) {
|
if (HAS_CAP(wrp->master->caps, PWRAP_CAP_BRIDGE)) {
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
wrp->bridge_base = devm_platform_ioremap_resource_byname(pdev, "pwrap-bridge");
|
||||||
"pwrap-bridge");
|
|
||||||
wrp->bridge_base = devm_ioremap_resource(wrp->dev, res);
|
|
||||||
if (IS_ERR(wrp->bridge_base))
|
if (IS_ERR(wrp->bridge_base))
|
||||||
return PTR_ERR(wrp->bridge_base);
|
return PTR_ERR(wrp->bridge_base);
|
||||||
|
|
||||||
@@ -2315,13 +2279,18 @@ static int pwrap_probe(struct platform_device *pdev)
|
|||||||
pwrap_writel(wrp, wrp->master->int1_en_all, PWRAP_INT1_EN);
|
pwrap_writel(wrp, wrp->master->int1_en_all, PWRAP_INT1_EN);
|
||||||
|
|
||||||
irq = platform_get_irq(pdev, 0);
|
irq = platform_get_irq(pdev, 0);
|
||||||
|
if (irq < 0) {
|
||||||
|
ret = irq;
|
||||||
|
goto err_out2;
|
||||||
|
}
|
||||||
|
|
||||||
ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt,
|
ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt,
|
||||||
IRQF_TRIGGER_HIGH,
|
IRQF_TRIGGER_HIGH,
|
||||||
"mt-pmic-pwrap", wrp);
|
"mt-pmic-pwrap", wrp);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_out2;
|
goto err_out2;
|
||||||
|
|
||||||
wrp->regmap = devm_regmap_init(wrp->dev, NULL, wrp, wrp->slave->regmap);
|
wrp->regmap = devm_regmap_init(wrp->dev, NULL, wrp, wrp->slave->regops->regmap);
|
||||||
if (IS_ERR(wrp->regmap)) {
|
if (IS_ERR(wrp->regmap)) {
|
||||||
ret = PTR_ERR(wrp->regmap);
|
ret = PTR_ERR(wrp->regmap);
|
||||||
goto err_out2;
|
goto err_out2;
|
||||||
|
|||||||
2403
drivers/soc/mediatek/mtk-svs.c
Normal file
2403
drivers/soc/mediatek/mtk-svs.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -129,7 +129,10 @@ config QCOM_RPMHPD
|
|||||||
|
|
||||||
config QCOM_RPMPD
|
config QCOM_RPMPD
|
||||||
tristate "Qualcomm RPM Power domain driver"
|
tristate "Qualcomm RPM Power domain driver"
|
||||||
|
depends on PM
|
||||||
depends on QCOM_SMD_RPM
|
depends on QCOM_SMD_RPM
|
||||||
|
select PM_GENERIC_DOMAINS
|
||||||
|
select PM_GENERIC_DOMAINS_OF
|
||||||
help
|
help
|
||||||
QCOM RPM Power domain driver to support power-domains with
|
QCOM RPM Power domain driver to support power-domains with
|
||||||
performance states. The driver communicates a performance state
|
performance states. The driver communicates a performance state
|
||||||
@@ -228,4 +231,19 @@ config QCOM_APR
|
|||||||
application processor and QDSP6. APR is
|
application processor and QDSP6. APR is
|
||||||
used by audio driver to configure QDSP6
|
used by audio driver to configure QDSP6
|
||||||
ASM, ADM and AFE modules.
|
ASM, ADM and AFE modules.
|
||||||
|
|
||||||
|
config QCOM_ICC_BWMON
|
||||||
|
tristate "QCOM Interconnect Bandwidth Monitor driver"
|
||||||
|
depends on ARCH_QCOM || COMPILE_TEST
|
||||||
|
select PM_OPP
|
||||||
|
help
|
||||||
|
Sets up driver monitoring bandwidth on various interconnects and
|
||||||
|
based on that voting for interconnect bandwidth, adjusting their
|
||||||
|
speed to current demand.
|
||||||
|
Current implementation brings support for BWMON v4, used for example
|
||||||
|
on SDM845 to measure bandwidth between CPU (gladiator_noc) and Last
|
||||||
|
Level Cache (memnoc). Usage of this BWMON allows to remove some of
|
||||||
|
the fixed bandwidth votes from cpufreq (CPU nodes) thus achieve high
|
||||||
|
memory throughput even with lower CPU frequencies.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|||||||
@@ -28,3 +28,4 @@ obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
|
|||||||
obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
|
obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
|
||||||
obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
|
obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
|
||||||
obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o
|
obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o
|
||||||
|
obj-$(CONFIG_QCOM_ICC_BWMON) += icc-bwmon.o
|
||||||
|
|||||||
@@ -377,17 +377,14 @@ static int apr_device_probe(struct device *dev)
|
|||||||
static void apr_device_remove(struct device *dev)
|
static void apr_device_remove(struct device *dev)
|
||||||
{
|
{
|
||||||
struct apr_device *adev = to_apr_device(dev);
|
struct apr_device *adev = to_apr_device(dev);
|
||||||
struct apr_driver *adrv;
|
struct apr_driver *adrv = to_apr_driver(dev->driver);
|
||||||
struct packet_router *apr = dev_get_drvdata(adev->dev.parent);
|
struct packet_router *apr = dev_get_drvdata(adev->dev.parent);
|
||||||
|
|
||||||
if (dev->driver) {
|
if (adrv->remove)
|
||||||
adrv = to_apr_driver(dev->driver);
|
adrv->remove(adev);
|
||||||
if (adrv->remove)
|
spin_lock(&apr->svcs_lock);
|
||||||
adrv->remove(adev);
|
idr_remove(&apr->svcs_idr, adev->svc.id);
|
||||||
spin_lock(&apr->svcs_lock);
|
spin_unlock(&apr->svcs_lock);
|
||||||
idr_remove(&apr->svcs_idr, adev->svc.id);
|
|
||||||
spin_unlock(&apr->svcs_lock);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apr_uevent(struct device *dev, struct kobj_uevent_env *env)
|
static int apr_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||||
|
|||||||
@@ -141,13 +141,17 @@ static int cmd_db_get_header(const char *id, const struct entry_header **eh,
|
|||||||
const struct rsc_hdr *rsc_hdr;
|
const struct rsc_hdr *rsc_hdr;
|
||||||
const struct entry_header *ent;
|
const struct entry_header *ent;
|
||||||
int ret, i, j;
|
int ret, i, j;
|
||||||
u8 query[8];
|
u8 query[sizeof(ent->id)] __nonstring;
|
||||||
|
|
||||||
ret = cmd_db_ready();
|
ret = cmd_db_ready();
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Pad out query string to same length as in DB */
|
/*
|
||||||
|
* Pad out query string to same length as in DB. NOTE: the output
|
||||||
|
* query string is not necessarily '\0' terminated if it bumps up
|
||||||
|
* against the max size. That's OK and expected.
|
||||||
|
*/
|
||||||
strncpy(query, id, sizeof(query));
|
strncpy(query, id, sizeof(query));
|
||||||
|
|
||||||
for (i = 0; i < MAX_SLV_ID; i++) {
|
for (i = 0; i < MAX_SLV_ID; i++) {
|
||||||
|
|||||||
419
drivers/soc/qcom/icc-bwmon.c
Normal file
419
drivers/soc/qcom/icc-bwmon.c
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
|
||||||
|
* Copyright (C) 2021-2022 Linaro Ltd
|
||||||
|
* Author: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>, based on
|
||||||
|
* previous work of Thara Gopinath and msm-4.9 downstream sources.
|
||||||
|
*/
|
||||||
|
#include <linux/interconnect.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm_opp.h>
|
||||||
|
#include <linux/sizes.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The BWMON samples data throughput within 'sample_ms' time. With three
|
||||||
|
* configurable thresholds (Low, Medium and High) gives four windows (called
|
||||||
|
* zones) of current bandwidth:
|
||||||
|
*
|
||||||
|
* Zone 0: byte count < THRES_LO
|
||||||
|
* Zone 1: THRES_LO < byte count < THRES_MED
|
||||||
|
* Zone 2: THRES_MED < byte count < THRES_HIGH
|
||||||
|
* Zone 3: THRES_HIGH < byte count
|
||||||
|
*
|
||||||
|
* Zones 0 and 2 are not used by this driver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Internal sampling clock frequency */
|
||||||
|
#define HW_TIMER_HZ 19200000
|
||||||
|
|
||||||
|
#define BWMON_GLOBAL_IRQ_STATUS 0x0
|
||||||
|
#define BWMON_GLOBAL_IRQ_CLEAR 0x8
|
||||||
|
#define BWMON_GLOBAL_IRQ_ENABLE 0xc
|
||||||
|
#define BWMON_GLOBAL_IRQ_ENABLE_ENABLE BIT(0)
|
||||||
|
|
||||||
|
#define BWMON_IRQ_STATUS 0x100
|
||||||
|
#define BWMON_IRQ_STATUS_ZONE_SHIFT 4
|
||||||
|
#define BWMON_IRQ_CLEAR 0x108
|
||||||
|
#define BWMON_IRQ_ENABLE 0x10c
|
||||||
|
#define BWMON_IRQ_ENABLE_ZONE1_SHIFT 5
|
||||||
|
#define BWMON_IRQ_ENABLE_ZONE2_SHIFT 6
|
||||||
|
#define BWMON_IRQ_ENABLE_ZONE3_SHIFT 7
|
||||||
|
#define BWMON_IRQ_ENABLE_MASK (BIT(BWMON_IRQ_ENABLE_ZONE1_SHIFT) | \
|
||||||
|
BIT(BWMON_IRQ_ENABLE_ZONE3_SHIFT))
|
||||||
|
|
||||||
|
#define BWMON_ENABLE 0x2a0
|
||||||
|
#define BWMON_ENABLE_ENABLE BIT(0)
|
||||||
|
|
||||||
|
#define BWMON_CLEAR 0x2a4
|
||||||
|
#define BWMON_CLEAR_CLEAR BIT(0)
|
||||||
|
|
||||||
|
#define BWMON_SAMPLE_WINDOW 0x2a8
|
||||||
|
#define BWMON_THRESHOLD_HIGH 0x2ac
|
||||||
|
#define BWMON_THRESHOLD_MED 0x2b0
|
||||||
|
#define BWMON_THRESHOLD_LOW 0x2b4
|
||||||
|
|
||||||
|
#define BWMON_ZONE_ACTIONS 0x2b8
|
||||||
|
/*
|
||||||
|
* Actions to perform on some zone 'z' when current zone hits the threshold:
|
||||||
|
* Increment counter of zone 'z'
|
||||||
|
*/
|
||||||
|
#define BWMON_ZONE_ACTIONS_INCREMENT(z) (0x2 << ((z) * 2))
|
||||||
|
/* Clear counter of zone 'z' */
|
||||||
|
#define BWMON_ZONE_ACTIONS_CLEAR(z) (0x1 << ((z) * 2))
|
||||||
|
|
||||||
|
/* Zone 0 threshold hit: Clear zone count */
|
||||||
|
#define BWMON_ZONE_ACTIONS_ZONE0 (BWMON_ZONE_ACTIONS_CLEAR(0))
|
||||||
|
|
||||||
|
/* Zone 1 threshold hit: Increment zone count & clear lower zones */
|
||||||
|
#define BWMON_ZONE_ACTIONS_ZONE1 (BWMON_ZONE_ACTIONS_INCREMENT(1) | \
|
||||||
|
BWMON_ZONE_ACTIONS_CLEAR(0))
|
||||||
|
|
||||||
|
/* Zone 2 threshold hit: Increment zone count & clear lower zones */
|
||||||
|
#define BWMON_ZONE_ACTIONS_ZONE2 (BWMON_ZONE_ACTIONS_INCREMENT(2) | \
|
||||||
|
BWMON_ZONE_ACTIONS_CLEAR(1) | \
|
||||||
|
BWMON_ZONE_ACTIONS_CLEAR(0))
|
||||||
|
|
||||||
|
/* Zone 3 threshold hit: Increment zone count & clear lower zones */
|
||||||
|
#define BWMON_ZONE_ACTIONS_ZONE3 (BWMON_ZONE_ACTIONS_INCREMENT(3) | \
|
||||||
|
BWMON_ZONE_ACTIONS_CLEAR(2) | \
|
||||||
|
BWMON_ZONE_ACTIONS_CLEAR(1) | \
|
||||||
|
BWMON_ZONE_ACTIONS_CLEAR(0))
|
||||||
|
/* Value for BWMON_ZONE_ACTIONS */
|
||||||
|
#define BWMON_ZONE_ACTIONS_DEFAULT (BWMON_ZONE_ACTIONS_ZONE0 | \
|
||||||
|
BWMON_ZONE_ACTIONS_ZONE1 << 8 | \
|
||||||
|
BWMON_ZONE_ACTIONS_ZONE2 << 16 | \
|
||||||
|
BWMON_ZONE_ACTIONS_ZONE3 << 24)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There is no clear documentation/explanation of BWMON_THRESHOLD_COUNT
|
||||||
|
* register. Based on observations, this is number of times one threshold has to
|
||||||
|
* be reached, to trigger interrupt in given zone.
|
||||||
|
*
|
||||||
|
* 0xff are maximum values meant to ignore the zones 0 and 2.
|
||||||
|
*/
|
||||||
|
#define BWMON_THRESHOLD_COUNT 0x2bc
|
||||||
|
#define BWMON_THRESHOLD_COUNT_ZONE1_SHIFT 8
|
||||||
|
#define BWMON_THRESHOLD_COUNT_ZONE2_SHIFT 16
|
||||||
|
#define BWMON_THRESHOLD_COUNT_ZONE3_SHIFT 24
|
||||||
|
#define BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT 0xff
|
||||||
|
#define BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT 0xff
|
||||||
|
|
||||||
|
/* BWMONv4 count registers use count unit of 64 kB */
|
||||||
|
#define BWMON_COUNT_UNIT_KB 64
|
||||||
|
#define BWMON_ZONE_COUNT 0x2d8
|
||||||
|
#define BWMON_ZONE_MAX(zone) (0x2e0 + 4 * (zone))
|
||||||
|
|
||||||
|
struct icc_bwmon_data {
|
||||||
|
unsigned int sample_ms;
|
||||||
|
unsigned int default_highbw_kbps;
|
||||||
|
unsigned int default_medbw_kbps;
|
||||||
|
unsigned int default_lowbw_kbps;
|
||||||
|
u8 zone1_thres_count;
|
||||||
|
u8 zone3_thres_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct icc_bwmon {
|
||||||
|
struct device *dev;
|
||||||
|
void __iomem *base;
|
||||||
|
int irq;
|
||||||
|
|
||||||
|
unsigned int default_lowbw_kbps;
|
||||||
|
unsigned int sample_ms;
|
||||||
|
unsigned int max_bw_kbps;
|
||||||
|
unsigned int min_bw_kbps;
|
||||||
|
unsigned int target_kbps;
|
||||||
|
unsigned int current_kbps;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void bwmon_clear_counters(struct icc_bwmon *bwmon)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Clear counters. The order and barriers are
|
||||||
|
* important. Quoting downstream Qualcomm msm-4.9 tree:
|
||||||
|
*
|
||||||
|
* The counter clear and IRQ clear bits are not in the same 4KB
|
||||||
|
* region. So, we need to make sure the counter clear is completed
|
||||||
|
* before we try to clear the IRQ or do any other counter operations.
|
||||||
|
*/
|
||||||
|
writel(BWMON_CLEAR_CLEAR, bwmon->base + BWMON_CLEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bwmon_clear_irq(struct icc_bwmon *bwmon)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Clear zone and global interrupts. The order and barriers are
|
||||||
|
* important. Quoting downstream Qualcomm msm-4.9 tree:
|
||||||
|
*
|
||||||
|
* Synchronize the local interrupt clear in mon_irq_clear()
|
||||||
|
* with the global interrupt clear here. Otherwise, the CPU
|
||||||
|
* may reorder the two writes and clear the global interrupt
|
||||||
|
* before the local interrupt, causing the global interrupt
|
||||||
|
* to be retriggered by the local interrupt still being high.
|
||||||
|
*
|
||||||
|
* Similarly, because the global registers are in a different
|
||||||
|
* region than the local registers, we need to ensure any register
|
||||||
|
* writes to enable the monitor after this call are ordered with the
|
||||||
|
* clearing here so that local writes don't happen before the
|
||||||
|
* interrupt is cleared.
|
||||||
|
*/
|
||||||
|
writel(BWMON_IRQ_ENABLE_MASK, bwmon->base + BWMON_IRQ_CLEAR);
|
||||||
|
writel(BIT(0), bwmon->base + BWMON_GLOBAL_IRQ_CLEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bwmon_disable(struct icc_bwmon *bwmon)
|
||||||
|
{
|
||||||
|
/* Disable interrupts. Strict ordering, see bwmon_clear_irq(). */
|
||||||
|
writel(0x0, bwmon->base + BWMON_GLOBAL_IRQ_ENABLE);
|
||||||
|
writel(0x0, bwmon->base + BWMON_IRQ_ENABLE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable bwmon. Must happen before bwmon_clear_irq() to avoid spurious
|
||||||
|
* IRQ.
|
||||||
|
*/
|
||||||
|
writel(0x0, bwmon->base + BWMON_ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bwmon_enable(struct icc_bwmon *bwmon, unsigned int irq_enable)
|
||||||
|
{
|
||||||
|
/* Enable interrupts */
|
||||||
|
writel(BWMON_GLOBAL_IRQ_ENABLE_ENABLE,
|
||||||
|
bwmon->base + BWMON_GLOBAL_IRQ_ENABLE);
|
||||||
|
writel(irq_enable, bwmon->base + BWMON_IRQ_ENABLE);
|
||||||
|
|
||||||
|
/* Enable bwmon */
|
||||||
|
writel(BWMON_ENABLE_ENABLE, bwmon->base + BWMON_ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int bwmon_kbps_to_count(unsigned int kbps)
|
||||||
|
{
|
||||||
|
return kbps / BWMON_COUNT_UNIT_KB;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bwmon_set_threshold(struct icc_bwmon *bwmon, unsigned int reg,
|
||||||
|
unsigned int kbps)
|
||||||
|
{
|
||||||
|
unsigned int thres;
|
||||||
|
|
||||||
|
thres = mult_frac(bwmon_kbps_to_count(kbps), bwmon->sample_ms,
|
||||||
|
MSEC_PER_SEC);
|
||||||
|
writel_relaxed(thres, bwmon->base + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bwmon_start(struct icc_bwmon *bwmon,
|
||||||
|
const struct icc_bwmon_data *data)
|
||||||
|
{
|
||||||
|
unsigned int thres_count;
|
||||||
|
int window;
|
||||||
|
|
||||||
|
bwmon_clear_counters(bwmon);
|
||||||
|
|
||||||
|
window = mult_frac(bwmon->sample_ms, HW_TIMER_HZ, MSEC_PER_SEC);
|
||||||
|
/* Maximum sampling window: 0xfffff */
|
||||||
|
writel_relaxed(window, bwmon->base + BWMON_SAMPLE_WINDOW);
|
||||||
|
|
||||||
|
bwmon_set_threshold(bwmon, BWMON_THRESHOLD_HIGH,
|
||||||
|
data->default_highbw_kbps);
|
||||||
|
bwmon_set_threshold(bwmon, BWMON_THRESHOLD_MED,
|
||||||
|
data->default_medbw_kbps);
|
||||||
|
bwmon_set_threshold(bwmon, BWMON_THRESHOLD_LOW,
|
||||||
|
data->default_lowbw_kbps);
|
||||||
|
|
||||||
|
thres_count = data->zone3_thres_count << BWMON_THRESHOLD_COUNT_ZONE3_SHIFT |
|
||||||
|
BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT << BWMON_THRESHOLD_COUNT_ZONE2_SHIFT |
|
||||||
|
data->zone1_thres_count << BWMON_THRESHOLD_COUNT_ZONE1_SHIFT |
|
||||||
|
BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT;
|
||||||
|
writel_relaxed(thres_count, bwmon->base + BWMON_THRESHOLD_COUNT);
|
||||||
|
writel_relaxed(BWMON_ZONE_ACTIONS_DEFAULT,
|
||||||
|
bwmon->base + BWMON_ZONE_ACTIONS);
|
||||||
|
/* Write barriers in bwmon_clear_irq() */
|
||||||
|
|
||||||
|
bwmon_clear_irq(bwmon);
|
||||||
|
bwmon_enable(bwmon, BWMON_IRQ_ENABLE_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t bwmon_intr(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct icc_bwmon *bwmon = dev_id;
|
||||||
|
unsigned int status, max;
|
||||||
|
int zone;
|
||||||
|
|
||||||
|
status = readl(bwmon->base + BWMON_IRQ_STATUS);
|
||||||
|
status &= BWMON_IRQ_ENABLE_MASK;
|
||||||
|
if (!status) {
|
||||||
|
/*
|
||||||
|
* Only zone 1 and zone 3 interrupts are enabled but zone 2
|
||||||
|
* threshold could be hit and trigger interrupt even if not
|
||||||
|
* enabled.
|
||||||
|
* Such spurious interrupt might come with valuable max count or
|
||||||
|
* not, so solution would be to always check all
|
||||||
|
* BWMON_ZONE_MAX() registers to find the highest value.
|
||||||
|
* Such case is currently ignored.
|
||||||
|
*/
|
||||||
|
return IRQ_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bwmon_disable(bwmon);
|
||||||
|
|
||||||
|
zone = get_bitmask_order(status >> BWMON_IRQ_STATUS_ZONE_SHIFT) - 1;
|
||||||
|
/*
|
||||||
|
* Zone max bytes count register returns count units within sampling
|
||||||
|
* window. Downstream kernel for BWMONv4 (called BWMON type 2 in
|
||||||
|
* downstream) always increments the max bytes count by one.
|
||||||
|
*/
|
||||||
|
max = readl(bwmon->base + BWMON_ZONE_MAX(zone)) + 1;
|
||||||
|
max *= BWMON_COUNT_UNIT_KB;
|
||||||
|
bwmon->target_kbps = mult_frac(max, MSEC_PER_SEC, bwmon->sample_ms);
|
||||||
|
|
||||||
|
return IRQ_WAKE_THREAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t bwmon_intr_thread(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct icc_bwmon *bwmon = dev_id;
|
||||||
|
unsigned int irq_enable = 0;
|
||||||
|
struct dev_pm_opp *opp, *target_opp;
|
||||||
|
unsigned int bw_kbps, up_kbps, down_kbps;
|
||||||
|
|
||||||
|
bw_kbps = bwmon->target_kbps;
|
||||||
|
|
||||||
|
target_opp = dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_kbps, 0);
|
||||||
|
if (IS_ERR(target_opp) && PTR_ERR(target_opp) == -ERANGE)
|
||||||
|
target_opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0);
|
||||||
|
|
||||||
|
bwmon->target_kbps = bw_kbps;
|
||||||
|
|
||||||
|
bw_kbps--;
|
||||||
|
opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0);
|
||||||
|
if (IS_ERR(opp) && PTR_ERR(opp) == -ERANGE)
|
||||||
|
down_kbps = bwmon->target_kbps;
|
||||||
|
else
|
||||||
|
down_kbps = bw_kbps;
|
||||||
|
|
||||||
|
up_kbps = bwmon->target_kbps + 1;
|
||||||
|
|
||||||
|
if (bwmon->target_kbps >= bwmon->max_bw_kbps)
|
||||||
|
irq_enable = BIT(BWMON_IRQ_ENABLE_ZONE1_SHIFT);
|
||||||
|
else if (bwmon->target_kbps <= bwmon->min_bw_kbps)
|
||||||
|
irq_enable = BIT(BWMON_IRQ_ENABLE_ZONE3_SHIFT);
|
||||||
|
else
|
||||||
|
irq_enable = BWMON_IRQ_ENABLE_MASK;
|
||||||
|
|
||||||
|
bwmon_set_threshold(bwmon, BWMON_THRESHOLD_HIGH, up_kbps);
|
||||||
|
bwmon_set_threshold(bwmon, BWMON_THRESHOLD_MED, down_kbps);
|
||||||
|
/* Write barriers in bwmon_clear_counters() */
|
||||||
|
bwmon_clear_counters(bwmon);
|
||||||
|
bwmon_clear_irq(bwmon);
|
||||||
|
bwmon_enable(bwmon, irq_enable);
|
||||||
|
|
||||||
|
if (bwmon->target_kbps == bwmon->current_kbps)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
dev_pm_opp_set_opp(bwmon->dev, target_opp);
|
||||||
|
bwmon->current_kbps = bwmon->target_kbps;
|
||||||
|
|
||||||
|
out:
|
||||||
|
dev_pm_opp_put(target_opp);
|
||||||
|
if (!IS_ERR(opp))
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bwmon_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct dev_pm_opp *opp;
|
||||||
|
struct icc_bwmon *bwmon;
|
||||||
|
const struct icc_bwmon_data *data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
bwmon = devm_kzalloc(dev, sizeof(*bwmon), GFP_KERNEL);
|
||||||
|
if (!bwmon)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
data = of_device_get_match_data(dev);
|
||||||
|
|
||||||
|
bwmon->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
if (IS_ERR(bwmon->base)) {
|
||||||
|
dev_err(dev, "failed to map bwmon registers\n");
|
||||||
|
return PTR_ERR(bwmon->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
bwmon->irq = platform_get_irq(pdev, 0);
|
||||||
|
if (bwmon->irq < 0)
|
||||||
|
return bwmon->irq;
|
||||||
|
|
||||||
|
ret = devm_pm_opp_of_add_table(dev);
|
||||||
|
if (ret)
|
||||||
|
return dev_err_probe(dev, ret, "failed to add OPP table\n");
|
||||||
|
|
||||||
|
bwmon->max_bw_kbps = UINT_MAX;
|
||||||
|
opp = dev_pm_opp_find_bw_floor(dev, &bwmon->max_bw_kbps, 0);
|
||||||
|
if (IS_ERR(opp))
|
||||||
|
return dev_err_probe(dev, ret, "failed to find max peak bandwidth\n");
|
||||||
|
|
||||||
|
bwmon->min_bw_kbps = 0;
|
||||||
|
opp = dev_pm_opp_find_bw_ceil(dev, &bwmon->min_bw_kbps, 0);
|
||||||
|
if (IS_ERR(opp))
|
||||||
|
return dev_err_probe(dev, ret, "failed to find min peak bandwidth\n");
|
||||||
|
|
||||||
|
bwmon->sample_ms = data->sample_ms;
|
||||||
|
bwmon->default_lowbw_kbps = data->default_lowbw_kbps;
|
||||||
|
bwmon->dev = dev;
|
||||||
|
|
||||||
|
bwmon_disable(bwmon);
|
||||||
|
ret = devm_request_threaded_irq(dev, bwmon->irq, bwmon_intr,
|
||||||
|
bwmon_intr_thread,
|
||||||
|
IRQF_ONESHOT, dev_name(dev), bwmon);
|
||||||
|
if (ret)
|
||||||
|
return dev_err_probe(dev, ret, "failed to request IRQ\n");
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, bwmon);
|
||||||
|
bwmon_start(bwmon, data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bwmon_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct icc_bwmon *bwmon = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
bwmon_disable(bwmon);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BWMON v4 */
|
||||||
|
static const struct icc_bwmon_data msm8998_bwmon_data = {
|
||||||
|
.sample_ms = 4,
|
||||||
|
.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,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id bwmon_of_match[] = {
|
||||||
|
{ .compatible = "qcom,msm8998-bwmon", .data = &msm8998_bwmon_data },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, bwmon_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver bwmon_driver = {
|
||||||
|
.probe = bwmon_probe,
|
||||||
|
.remove = bwmon_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "qcom-bwmon",
|
||||||
|
.of_match_table = bwmon_of_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(bwmon_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>");
|
||||||
|
MODULE_DESCRIPTION("QCOM BWMON driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
@@ -382,7 +382,7 @@ static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
|
|||||||
* llcc_slice_getd - get llcc slice descriptor
|
* llcc_slice_getd - get llcc slice descriptor
|
||||||
* @uid: usecase_id for the client
|
* @uid: usecase_id for the client
|
||||||
*
|
*
|
||||||
* A pointer to llcc slice descriptor will be returned on success and
|
* A pointer to llcc slice descriptor will be returned on success
|
||||||
* and error pointer is returned on failure
|
* and error pointer is returned on failure
|
||||||
*/
|
*/
|
||||||
struct llcc_slice_desc *llcc_slice_getd(u32 uid)
|
struct llcc_slice_desc *llcc_slice_getd(u32 uid)
|
||||||
|
|||||||
@@ -108,6 +108,8 @@ EXPORT_SYMBOL_GPL(qcom_mdt_get_size);
|
|||||||
* qcom_mdt_read_metadata() - read header and metadata from mdt or mbn
|
* qcom_mdt_read_metadata() - read header and metadata from mdt or mbn
|
||||||
* @fw: firmware of mdt header or mbn
|
* @fw: firmware of mdt header or mbn
|
||||||
* @data_len: length of the read metadata blob
|
* @data_len: length of the read metadata blob
|
||||||
|
* @fw_name: name of the firmware, for construction of segment file names
|
||||||
|
* @dev: device handle to associate resources with
|
||||||
*
|
*
|
||||||
* The mechanism that performs the authentication of the loading firmware
|
* The mechanism that performs the authentication of the loading firmware
|
||||||
* expects an ELF header directly followed by the segment of hashes, with no
|
* expects an ELF header directly followed by the segment of hashes, with no
|
||||||
@@ -192,7 +194,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
|
|||||||
* qcom_mdt_pas_init() - initialize PAS region for firmware loading
|
* qcom_mdt_pas_init() - initialize PAS region for firmware loading
|
||||||
* @dev: device handle to associate resources with
|
* @dev: device handle to associate resources with
|
||||||
* @fw: firmware object for the mdt file
|
* @fw: firmware object for the mdt file
|
||||||
* @firmware: name of the firmware, for construction of segment file names
|
* @fw_name: name of the firmware, for construction of segment file names
|
||||||
* @pas_id: PAS identifier
|
* @pas_id: PAS identifier
|
||||||
* @mem_phys: physical address of allocated memory region
|
* @mem_phys: physical address of allocated memory region
|
||||||
* @ctx: PAS metadata context, to be released by caller
|
* @ctx: PAS metadata context, to be released by caller
|
||||||
|
|||||||
@@ -194,14 +194,17 @@ struct ocmem *of_get_ocmem(struct device *dev)
|
|||||||
devnode = of_parse_phandle(dev->of_node, "sram", 0);
|
devnode = of_parse_phandle(dev->of_node, "sram", 0);
|
||||||
if (!devnode || !devnode->parent) {
|
if (!devnode || !devnode->parent) {
|
||||||
dev_err(dev, "Cannot look up sram phandle\n");
|
dev_err(dev, "Cannot look up sram phandle\n");
|
||||||
|
of_node_put(devnode);
|
||||||
return ERR_PTR(-ENODEV);
|
return ERR_PTR(-ENODEV);
|
||||||
}
|
}
|
||||||
|
|
||||||
pdev = of_find_device_by_node(devnode->parent);
|
pdev = of_find_device_by_node(devnode->parent);
|
||||||
if (!pdev) {
|
if (!pdev) {
|
||||||
dev_err(dev, "Cannot find device node %s\n", devnode->name);
|
dev_err(dev, "Cannot find device node %s\n", devnode->name);
|
||||||
|
of_node_put(devnode);
|
||||||
return ERR_PTR(-EPROBE_DEFER);
|
return ERR_PTR(-EPROBE_DEFER);
|
||||||
}
|
}
|
||||||
|
of_node_put(devnode);
|
||||||
|
|
||||||
ocmem = platform_get_drvdata(pdev);
|
ocmem = platform_get_drvdata(pdev);
|
||||||
if (!ocmem) {
|
if (!ocmem) {
|
||||||
|
|||||||
@@ -399,8 +399,10 @@ static int qmp_cooling_devices_register(struct qmp *qmp)
|
|||||||
continue;
|
continue;
|
||||||
ret = qmp_cooling_device_add(qmp, &qmp->cooling_devs[count++],
|
ret = qmp_cooling_device_add(qmp, &qmp->cooling_devs[count++],
|
||||||
child);
|
child);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
of_node_put(child);
|
||||||
goto unroll;
|
goto unroll;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!count)
|
if (!count)
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
/**
|
/**
|
||||||
* struct rpmhpd - top level RPMh power domain resource data structure
|
* struct rpmhpd - top level RPMh power domain resource data structure
|
||||||
* @dev: rpmh power domain controller device
|
* @dev: rpmh power domain controller device
|
||||||
* @pd: generic_pm_domain corrresponding to the power domain
|
* @pd: generic_pm_domain corresponding to the power domain
|
||||||
* @parent: generic_pm_domain corrresponding to the parent's power domain
|
* @parent: generic_pm_domain corresponding to the parent's power domain
|
||||||
* @peer: A peer power domain in case Active only Voting is
|
* @peer: A peer power domain in case Active only Voting is
|
||||||
* supported
|
* supported
|
||||||
* @active_only: True if it represents an Active only peer
|
* @active_only: True if it represents an Active only peer
|
||||||
|
|||||||
@@ -453,6 +453,7 @@ static const struct rpmpd_desc qcm2290_desc = {
|
|||||||
static const struct of_device_id rpmpd_match_table[] = {
|
static const struct of_device_id rpmpd_match_table[] = {
|
||||||
{ .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc },
|
{ .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc },
|
||||||
{ .compatible = "qcom,msm8226-rpmpd", .data = &msm8226_desc },
|
{ .compatible = "qcom,msm8226-rpmpd", .data = &msm8226_desc },
|
||||||
|
{ .compatible = "qcom,msm8909-rpmpd", .data = &msm8916_desc },
|
||||||
{ .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc },
|
{ .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc },
|
||||||
{ .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc },
|
{ .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc },
|
||||||
{ .compatible = "qcom,msm8953-rpmpd", .data = &msm8953_desc },
|
{ .compatible = "qcom,msm8953-rpmpd", .data = &msm8953_desc },
|
||||||
|
|||||||
@@ -234,6 +234,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = {
|
|||||||
{ .compatible = "qcom,rpm-apq8084" },
|
{ .compatible = "qcom,rpm-apq8084" },
|
||||||
{ .compatible = "qcom,rpm-ipq6018" },
|
{ .compatible = "qcom,rpm-ipq6018" },
|
||||||
{ .compatible = "qcom,rpm-msm8226" },
|
{ .compatible = "qcom,rpm-msm8226" },
|
||||||
|
{ .compatible = "qcom,rpm-msm8909" },
|
||||||
{ .compatible = "qcom,rpm-msm8916" },
|
{ .compatible = "qcom,rpm-msm8916" },
|
||||||
{ .compatible = "qcom,rpm-msm8936" },
|
{ .compatible = "qcom,rpm-msm8936" },
|
||||||
{ .compatible = "qcom,rpm-msm8953" },
|
{ .compatible = "qcom,rpm-msm8953" },
|
||||||
|
|||||||
@@ -119,6 +119,9 @@ struct smp2p_entry {
|
|||||||
* @out: pointer to the outbound smem item
|
* @out: pointer to the outbound smem item
|
||||||
* @smem_items: ids of the two smem items
|
* @smem_items: ids of the two smem items
|
||||||
* @valid_entries: already scanned inbound entries
|
* @valid_entries: already scanned inbound entries
|
||||||
|
* @ssr_ack_enabled: SMP2P_FEATURE_SSR_ACK feature is supported and was enabled
|
||||||
|
* @ssr_ack: current cached state of the local ack bit
|
||||||
|
* @negotiation_done: whether negotiating finished
|
||||||
* @local_pid: processor id of the inbound edge
|
* @local_pid: processor id of the inbound edge
|
||||||
* @remote_pid: processor id of the outbound edge
|
* @remote_pid: processor id of the outbound edge
|
||||||
* @ipc_regmap: regmap for the outbound ipc
|
* @ipc_regmap: regmap for the outbound ipc
|
||||||
|
|||||||
@@ -328,10 +328,12 @@ static const struct soc_id soc_id[] = {
|
|||||||
{ 455, "QRB5165" },
|
{ 455, "QRB5165" },
|
||||||
{ 457, "SM8450" },
|
{ 457, "SM8450" },
|
||||||
{ 459, "SM7225" },
|
{ 459, "SM7225" },
|
||||||
{ 460, "SA8540P" },
|
{ 460, "SA8295P" },
|
||||||
|
{ 461, "SA8540P" },
|
||||||
{ 480, "SM8450" },
|
{ 480, "SM8450" },
|
||||||
{ 482, "SM8450" },
|
{ 482, "SM8450" },
|
||||||
{ 487, "SC7280" },
|
{ 487, "SC7280" },
|
||||||
|
{ 495, "SC7180P" },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *socinfo_machine(struct device *dev, unsigned int id)
|
static const char *socinfo_machine(struct device *dev, unsigned int id)
|
||||||
|
|||||||
@@ -74,6 +74,18 @@ static const u16 spm_reg_offset_v3_0[SPM_REG_NR] = {
|
|||||||
[SPM_REG_SEQ_ENTRY] = 0x400,
|
[SPM_REG_SEQ_ENTRY] = 0x400,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* SPM register data for 8909 */
|
||||||
|
static const struct spm_reg_data spm_reg_8909_cpu = {
|
||||||
|
.reg_offset = spm_reg_offset_v3_0,
|
||||||
|
.spm_cfg = 0x1,
|
||||||
|
.spm_dly = 0x3C102800,
|
||||||
|
.seq = { 0x60, 0x03, 0x60, 0x0B, 0x0F, 0x20, 0x10, 0x80, 0x30, 0x90,
|
||||||
|
0x5B, 0x60, 0x03, 0x60, 0x76, 0x76, 0x0B, 0x94, 0x5B, 0x80,
|
||||||
|
0x10, 0x26, 0x30, 0x0F },
|
||||||
|
.start_index[PM_SLEEP_MODE_STBY] = 0,
|
||||||
|
.start_index[PM_SLEEP_MODE_SPC] = 5,
|
||||||
|
};
|
||||||
|
|
||||||
/* SPM register data for 8916 */
|
/* SPM register data for 8916 */
|
||||||
static const struct spm_reg_data spm_reg_8916_cpu = {
|
static const struct spm_reg_data spm_reg_8916_cpu = {
|
||||||
.reg_offset = spm_reg_offset_v3_0,
|
.reg_offset = spm_reg_offset_v3_0,
|
||||||
@@ -195,6 +207,8 @@ static const struct of_device_id spm_match_table[] = {
|
|||||||
.data = &spm_reg_660_silver_l2 },
|
.data = &spm_reg_660_silver_l2 },
|
||||||
{ .compatible = "qcom,msm8226-saw2-v2.1-cpu",
|
{ .compatible = "qcom,msm8226-saw2-v2.1-cpu",
|
||||||
.data = &spm_reg_8226_cpu },
|
.data = &spm_reg_8226_cpu },
|
||||||
|
{ .compatible = "qcom,msm8909-saw2-v3.0-cpu",
|
||||||
|
.data = &spm_reg_8909_cpu },
|
||||||
{ .compatible = "qcom,msm8916-saw2-v3.0-cpu",
|
{ .compatible = "qcom,msm8916-saw2-v3.0-cpu",
|
||||||
.data = &spm_reg_8916_cpu },
|
.data = &spm_reg_8916_cpu },
|
||||||
{ .compatible = "qcom,msm8974-saw2-v2.1-cpu",
|
{ .compatible = "qcom,msm8974-saw2-v2.1-cpu",
|
||||||
|
|||||||
@@ -57,11 +57,11 @@ static struct rcar_gen4_sysc_area r8a779a0_areas[] __initdata = {
|
|||||||
{ "a2cv6", R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR },
|
{ "a2cv6", R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR },
|
||||||
{ "a2cn2", R8A779A0_PD_A2CN2, R8A779A0_PD_A3IR },
|
{ "a2cn2", R8A779A0_PD_A2CN2, R8A779A0_PD_A3IR },
|
||||||
{ "a2imp23", R8A779A0_PD_A2IMP23, R8A779A0_PD_A3IR },
|
{ "a2imp23", R8A779A0_PD_A2IMP23, R8A779A0_PD_A3IR },
|
||||||
{ "a2dp1", R8A779A0_PD_A2DP0, R8A779A0_PD_A3IR },
|
{ "a2dp1", R8A779A0_PD_A2DP1, R8A779A0_PD_A3IR },
|
||||||
{ "a2cv2", R8A779A0_PD_A2CV0, R8A779A0_PD_A3IR },
|
{ "a2cv2", R8A779A0_PD_A2CV2, R8A779A0_PD_A3IR },
|
||||||
{ "a2cv3", R8A779A0_PD_A2CV1, R8A779A0_PD_A3IR },
|
{ "a2cv3", R8A779A0_PD_A2CV3, R8A779A0_PD_A3IR },
|
||||||
{ "a2cv5", R8A779A0_PD_A2CV4, R8A779A0_PD_A3IR },
|
{ "a2cv5", R8A779A0_PD_A2CV5, R8A779A0_PD_A3IR },
|
||||||
{ "a2cv7", R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR },
|
{ "a2cv7", R8A779A0_PD_A2CV7, R8A779A0_PD_A3IR },
|
||||||
{ "a2cn1", R8A779A0_PD_A2CN1, R8A779A0_PD_A3IR },
|
{ "a2cn1", R8A779A0_PD_A2CN1, R8A779A0_PD_A3IR },
|
||||||
{ "a1cnn0", R8A779A0_PD_A1CNN0, R8A779A0_PD_A2CN0 },
|
{ "a1cnn0", R8A779A0_PD_A1CNN0, R8A779A0_PD_A2CN0 },
|
||||||
{ "a1cnn2", R8A779A0_PD_A1CNN2, R8A779A0_PD_A2CN2 },
|
{ "a1cnn2", R8A779A0_PD_A1CNN2, R8A779A0_PD_A2CN2 },
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
struct rcar_gen4_sysc_area {
|
struct rcar_gen4_sysc_area {
|
||||||
const char *name;
|
const char *name;
|
||||||
u8 pdr; /* PDRn */
|
u8 pdr; /* PDRn */
|
||||||
int parent; /* -1 if none */
|
s8 parent; /* -1 if none */
|
||||||
unsigned int flags; /* See PD_* */
|
u8 flags; /* See PD_* */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ struct rcar_sysc_area {
|
|||||||
u16 chan_offs; /* Offset of PWRSR register for this area */
|
u16 chan_offs; /* Offset of PWRSR register for this area */
|
||||||
u8 chan_bit; /* Bit in PWR* (except for PWRUP in PWRSR) */
|
u8 chan_bit; /* Bit in PWR* (except for PWRUP in PWRSR) */
|
||||||
u8 isr_bit; /* Bit in SYSCI*R */
|
u8 isr_bit; /* Bit in SYSCI*R */
|
||||||
int parent; /* -1 if none */
|
s8 parent; /* -1 if none */
|
||||||
unsigned int flags; /* See PD_* */
|
u8 flags; /* See PD_* */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
config SUNXI_MBUS
|
config SUNXI_MBUS
|
||||||
bool
|
bool
|
||||||
default ARCH_SUNXI
|
default ARCH_SUNXI
|
||||||
|
depends on ARM || ARM64
|
||||||
help
|
help
|
||||||
Say y to enable the fixups needed to support the Allwinner
|
Say y to enable the fixups needed to support the Allwinner
|
||||||
MBUS DMA quirks.
|
MBUS DMA quirks.
|
||||||
|
|||||||
@@ -338,6 +338,7 @@ static const struct of_device_id pruss_of_match[] = {
|
|||||||
{ .compatible = "ti,am654-icssg", .data = &am65x_j721e_pruss_data, },
|
{ .compatible = "ti,am654-icssg", .data = &am65x_j721e_pruss_data, },
|
||||||
{ .compatible = "ti,j721e-icssg", .data = &am65x_j721e_pruss_data, },
|
{ .compatible = "ti,j721e-icssg", .data = &am65x_j721e_pruss_data, },
|
||||||
{ .compatible = "ti,am642-icssg", .data = &am65x_j721e_pruss_data, },
|
{ .compatible = "ti,am642-icssg", .data = &am65x_j721e_pruss_data, },
|
||||||
|
{ .compatible = "ti,am625-pruss", .data = &am65x_j721e_pruss_data, },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, pruss_of_match);
|
MODULE_DEVICE_TABLE(of, pruss_of_match);
|
||||||
|
|||||||
@@ -688,7 +688,7 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev)
|
|||||||
&m3_ipc->sd_fw_name);
|
&m3_ipc->sd_fw_name);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_dbg(dev, "Voltage scaling data blob not provided from DT.\n");
|
dev_dbg(dev, "Voltage scaling data blob not provided from DT.\n");
|
||||||
};
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait for firmware loading completion in a thread so we
|
* Wait for firmware loading completion in a thread so we
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ config SPI_BCM63XX
|
|||||||
|
|
||||||
config SPI_BCM63XX_HSSPI
|
config SPI_BCM63XX_HSSPI
|
||||||
tristate "Broadcom BCM63XX HS SPI controller driver"
|
tristate "Broadcom BCM63XX HS SPI controller driver"
|
||||||
depends on BCM63XX || BMIPS_GENERIC || ARCH_BCM_63XX || COMPILE_TEST
|
depends on BCM63XX || BMIPS_GENERIC || ARCH_BCMBCA || COMPILE_TEST
|
||||||
help
|
help
|
||||||
This enables support for the High Speed SPI controller present on
|
This enables support for the High Speed SPI controller present on
|
||||||
newer Broadcom BCM63XX SoCs.
|
newer Broadcom BCM63XX SoCs.
|
||||||
|
|||||||
@@ -1099,8 +1099,8 @@ config SERIAL_TIMBERDALE
|
|||||||
config SERIAL_BCM63XX
|
config SERIAL_BCM63XX
|
||||||
tristate "Broadcom BCM63xx/BCM33xx UART support"
|
tristate "Broadcom BCM63xx/BCM33xx UART support"
|
||||||
select SERIAL_CORE
|
select SERIAL_CORE
|
||||||
depends on ARCH_BCM4908 || ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC || COMPILE_TEST
|
depends on ARCH_BCM4908 || ARCH_BCMBCA || BCM63XX || BMIPS_GENERIC || COMPILE_TEST
|
||||||
default ARCH_BCM4908 || ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC
|
default ARCH_BCM4908 || ARCH_BCMBCA || BCM63XX || BMIPS_GENERIC
|
||||||
help
|
help
|
||||||
This enables the driver for the onchip UART core found on
|
This enables the driver for the onchip UART core found on
|
||||||
the following chipsets:
|
the following chipsets:
|
||||||
|
|||||||
@@ -164,10 +164,111 @@
|
|||||||
#define TEGRA234_CLK_PEX1_C5_CORE 225U
|
#define TEGRA234_CLK_PEX1_C5_CORE 225U
|
||||||
/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLC4_BASE */
|
/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLC4_BASE */
|
||||||
#define TEGRA234_CLK_PLLC4 237U
|
#define TEGRA234_CLK_PLLC4 237U
|
||||||
|
/** @brief RX clock recovered from MGBE0 lane input */
|
||||||
|
#define TEGRA234_CLK_MGBE0_RX_INPUT 248U
|
||||||
|
/** @brief RX clock recovered from MGBE1 lane input */
|
||||||
|
#define TEGRA234_CLK_MGBE1_RX_INPUT 249U
|
||||||
|
/** @brief RX clock recovered from MGBE2 lane input */
|
||||||
|
#define TEGRA234_CLK_MGBE2_RX_INPUT 250U
|
||||||
|
/** @brief RX clock recovered from MGBE3 lane input */
|
||||||
|
#define TEGRA234_CLK_MGBE3_RX_INPUT 251U
|
||||||
/** @brief 32K input clock provided by PMIC */
|
/** @brief 32K input clock provided by PMIC */
|
||||||
#define TEGRA234_CLK_CLK_32K 289U
|
#define TEGRA234_CLK_CLK_32K 289U
|
||||||
|
/** @brief Monitored branch of MBGE0 RX input clock */
|
||||||
|
#define TEGRA234_CLK_MGBE0_RX_INPUT_M 357U
|
||||||
|
/** @brief Monitored branch of MBGE1 RX input clock */
|
||||||
|
#define TEGRA234_CLK_MGBE1_RX_INPUT_M 358U
|
||||||
|
/** @brief Monitored branch of MBGE2 RX input clock */
|
||||||
|
#define TEGRA234_CLK_MGBE2_RX_INPUT_M 359U
|
||||||
|
/** @brief Monitored branch of MBGE3 RX input clock */
|
||||||
|
#define TEGRA234_CLK_MGBE3_RX_INPUT_M 360U
|
||||||
|
/** @brief Monitored branch of MGBE0 RX PCS mux output */
|
||||||
|
#define TEGRA234_CLK_MGBE0_RX_PCS_M 361U
|
||||||
|
/** @brief Monitored branch of MGBE1 RX PCS mux output */
|
||||||
|
#define TEGRA234_CLK_MGBE1_RX_PCS_M 362U
|
||||||
|
/** @brief Monitored branch of MGBE2 RX PCS mux output */
|
||||||
|
#define TEGRA234_CLK_MGBE2_RX_PCS_M 363U
|
||||||
|
/** @brief Monitored branch of MGBE3 RX PCS mux output */
|
||||||
|
#define TEGRA234_CLK_MGBE3_RX_PCS_M 364U
|
||||||
|
/** @brief RX PCS clock recovered from MGBE0 lane input */
|
||||||
|
#define TEGRA234_CLK_MGBE0_RX_PCS_INPUT 369U
|
||||||
|
/** @brief RX PCS clock recovered from MGBE1 lane input */
|
||||||
|
#define TEGRA234_CLK_MGBE1_RX_PCS_INPUT 370U
|
||||||
|
/** @brief RX PCS clock recovered from MGBE2 lane input */
|
||||||
|
#define TEGRA234_CLK_MGBE2_RX_PCS_INPUT 371U
|
||||||
|
/** @brief RX PCS clock recovered from MGBE3 lane input */
|
||||||
|
#define TEGRA234_CLK_MGBE3_RX_PCS_INPUT 372U
|
||||||
|
/** @brief output of mux controlled by GBE_UPHY_MGBE0_RX_PCS_CLK_SRC_SEL */
|
||||||
|
#define TEGRA234_CLK_MGBE0_RX_PCS 373U
|
||||||
|
/** @brief GBE_UPHY_MGBE0_TX_CLK divider gated output */
|
||||||
|
#define TEGRA234_CLK_MGBE0_TX 374U
|
||||||
|
/** @brief GBE_UPHY_MGBE0_TX_PCS_CLK divider gated output */
|
||||||
|
#define TEGRA234_CLK_MGBE0_TX_PCS 375U
|
||||||
|
/** @brief GBE_UPHY_MGBE0_MAC_CLK divider output */
|
||||||
|
#define TEGRA234_CLK_MGBE0_MAC_DIVIDER 376U
|
||||||
|
/** @brief GBE_UPHY_MGBE0_MAC_CLK gate output */
|
||||||
|
#define TEGRA234_CLK_MGBE0_MAC 377U
|
||||||
|
/** @brief GBE_UPHY_MGBE0_MACSEC_CLK gate output */
|
||||||
|
#define TEGRA234_CLK_MGBE0_MACSEC 378U
|
||||||
|
/** @brief GBE_UPHY_MGBE0_EEE_PCS_CLK gate output */
|
||||||
|
#define TEGRA234_CLK_MGBE0_EEE_PCS 379U
|
||||||
|
/** @brief GBE_UPHY_MGBE0_APP_CLK gate output */
|
||||||
|
#define TEGRA234_CLK_MGBE0_APP 380U
|
||||||
|
/** @brief GBE_UPHY_MGBE0_PTP_REF_CLK divider gated output */
|
||||||
|
#define TEGRA234_CLK_MGBE0_PTP_REF 381U
|
||||||
|
/** @brief output of mux controlled by GBE_UPHY_MGBE1_RX_PCS_CLK_SRC_SEL */
|
||||||
|
#define TEGRA234_CLK_MGBE1_RX_PCS 382U
|
||||||
|
/** @brief GBE_UPHY_MGBE1_TX_CLK divider gated output */
|
||||||
|
#define TEGRA234_CLK_MGBE1_TX 383U
|
||||||
|
/** @brief GBE_UPHY_MGBE1_TX_PCS_CLK divider gated output */
|
||||||
|
#define TEGRA234_CLK_MGBE1_TX_PCS 384U
|
||||||
|
/** @brief GBE_UPHY_MGBE1_MAC_CLK divider output */
|
||||||
|
#define TEGRA234_CLK_MGBE1_MAC_DIVIDER 385U
|
||||||
|
/** @brief GBE_UPHY_MGBE1_MAC_CLK gate output */
|
||||||
|
#define TEGRA234_CLK_MGBE1_MAC 386U
|
||||||
|
/** @brief GBE_UPHY_MGBE1_EEE_PCS_CLK gate output */
|
||||||
|
#define TEGRA234_CLK_MGBE1_EEE_PCS 388U
|
||||||
|
/** @brief GBE_UPHY_MGBE1_APP_CLK gate output */
|
||||||
|
#define TEGRA234_CLK_MGBE1_APP 389U
|
||||||
|
/** @brief GBE_UPHY_MGBE1_PTP_REF_CLK divider gated output */
|
||||||
|
#define TEGRA234_CLK_MGBE1_PTP_REF 390U
|
||||||
|
/** @brief output of mux controlled by GBE_UPHY_MGBE2_RX_PCS_CLK_SRC_SEL */
|
||||||
|
#define TEGRA234_CLK_MGBE2_RX_PCS 391U
|
||||||
|
/** @brief GBE_UPHY_MGBE2_TX_CLK divider gated output */
|
||||||
|
#define TEGRA234_CLK_MGBE2_TX 392U
|
||||||
|
/** @brief GBE_UPHY_MGBE2_TX_PCS_CLK divider gated output */
|
||||||
|
#define TEGRA234_CLK_MGBE2_TX_PCS 393U
|
||||||
|
/** @brief GBE_UPHY_MGBE2_MAC_CLK divider output */
|
||||||
|
#define TEGRA234_CLK_MGBE2_MAC_DIVIDER 394U
|
||||||
|
/** @brief GBE_UPHY_MGBE2_MAC_CLK gate output */
|
||||||
|
#define TEGRA234_CLK_MGBE2_MAC 395U
|
||||||
|
/** @brief GBE_UPHY_MGBE2_EEE_PCS_CLK gate output */
|
||||||
|
#define TEGRA234_CLK_MGBE2_EEE_PCS 397U
|
||||||
|
/** @brief GBE_UPHY_MGBE2_APP_CLK gate output */
|
||||||
|
#define TEGRA234_CLK_MGBE2_APP 398U
|
||||||
|
/** @brief GBE_UPHY_MGBE2_PTP_REF_CLK divider gated output */
|
||||||
|
#define TEGRA234_CLK_MGBE2_PTP_REF 399U
|
||||||
|
/** @brief output of mux controlled by GBE_UPHY_MGBE3_RX_PCS_CLK_SRC_SEL */
|
||||||
|
#define TEGRA234_CLK_MGBE3_RX_PCS 400U
|
||||||
|
/** @brief GBE_UPHY_MGBE3_TX_CLK divider gated output */
|
||||||
|
#define TEGRA234_CLK_MGBE3_TX 401U
|
||||||
|
/** @brief GBE_UPHY_MGBE3_TX_PCS_CLK divider gated output */
|
||||||
|
#define TEGRA234_CLK_MGBE3_TX_PCS 402U
|
||||||
|
/** @brief GBE_UPHY_MGBE3_MAC_CLK divider output */
|
||||||
|
#define TEGRA234_CLK_MGBE3_MAC_DIVIDER 403U
|
||||||
|
/** @brief GBE_UPHY_MGBE3_MAC_CLK gate output */
|
||||||
|
#define TEGRA234_CLK_MGBE3_MAC 404U
|
||||||
|
/** @brief GBE_UPHY_MGBE3_MACSEC_CLK gate output */
|
||||||
|
#define TEGRA234_CLK_MGBE3_MACSEC 405U
|
||||||
|
/** @brief GBE_UPHY_MGBE3_EEE_PCS_CLK gate output */
|
||||||
|
#define TEGRA234_CLK_MGBE3_EEE_PCS 406U
|
||||||
|
/** @brief GBE_UPHY_MGBE3_APP_CLK gate output */
|
||||||
|
#define TEGRA234_CLK_MGBE3_APP 407U
|
||||||
|
/** @brief GBE_UPHY_MGBE3_PTP_REF_CLK divider gated output */
|
||||||
|
#define TEGRA234_CLK_MGBE3_PTP_REF 408U
|
||||||
/** @brief CLK_RST_CONTROLLER_AZA2XBITCLK_OUT_SWITCH_DIVIDER switch divider output (aza_2xbitclk) */
|
/** @brief CLK_RST_CONTROLLER_AZA2XBITCLK_OUT_SWITCH_DIVIDER switch divider output (aza_2xbitclk) */
|
||||||
#define TEGRA234_CLK_AZA_2XBIT 457U
|
#define TEGRA234_CLK_AZA_2XBIT 457U
|
||||||
/** @brief aza_2xbitclk / 2 (aza_bitclk) */
|
/** @brief aza_2xbitclk / 2 (aza_bitclk) */
|
||||||
#define TEGRA234_CLK_AZA_BIT 458U
|
#define TEGRA234_CLK_AZA_BIT 458U
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -11,11 +11,16 @@
|
|||||||
/* NISO0 stream IDs */
|
/* NISO0 stream IDs */
|
||||||
#define TEGRA234_SID_APE 0x02
|
#define TEGRA234_SID_APE 0x02
|
||||||
#define TEGRA234_SID_HDA 0x03
|
#define TEGRA234_SID_HDA 0x03
|
||||||
|
#define TEGRA234_SID_GPCDMA 0x04
|
||||||
|
#define TEGRA234_SID_MGBE 0x06
|
||||||
#define TEGRA234_SID_PCIE0 0x12
|
#define TEGRA234_SID_PCIE0 0x12
|
||||||
#define TEGRA234_SID_PCIE4 0x13
|
#define TEGRA234_SID_PCIE4 0x13
|
||||||
#define TEGRA234_SID_PCIE5 0x14
|
#define TEGRA234_SID_PCIE5 0x14
|
||||||
#define TEGRA234_SID_PCIE6 0x15
|
#define TEGRA234_SID_PCIE6 0x15
|
||||||
#define TEGRA234_SID_PCIE9 0x1f
|
#define TEGRA234_SID_PCIE9 0x1f
|
||||||
|
#define TEGRA234_SID_MGBE_VF1 0x49
|
||||||
|
#define TEGRA234_SID_MGBE_VF2 0x4a
|
||||||
|
#define TEGRA234_SID_MGBE_VF3 0x4b
|
||||||
|
|
||||||
/* NISO1 stream IDs */
|
/* NISO1 stream IDs */
|
||||||
#define TEGRA234_SID_SDMMC4 0x02
|
#define TEGRA234_SID_SDMMC4 0x02
|
||||||
@@ -61,8 +66,24 @@
|
|||||||
#define TEGRA234_MEMORY_CLIENT_PCIE10AR1 0x48
|
#define TEGRA234_MEMORY_CLIENT_PCIE10AR1 0x48
|
||||||
/* PCIE7r1 read clients */
|
/* PCIE7r1 read clients */
|
||||||
#define TEGRA234_MEMORY_CLIENT_PCIE7AR1 0x49
|
#define TEGRA234_MEMORY_CLIENT_PCIE7AR1 0x49
|
||||||
|
/* MGBE0 read client */
|
||||||
|
#define TEGRA234_MEMORY_CLIENT_MGBEARD 0x58
|
||||||
|
/* MGBEB read client */
|
||||||
|
#define TEGRA234_MEMORY_CLIENT_MGBEBRD 0x59
|
||||||
|
/* MGBEC read client */
|
||||||
|
#define TEGRA234_MEMORY_CLIENT_MGBECRD 0x5a
|
||||||
|
/* MGBED read client */
|
||||||
|
#define TEGRA234_MEMORY_CLIENT_MGBEDRD 0x5b
|
||||||
|
/* MGBE0 write client */
|
||||||
|
#define TEGRA234_MEMORY_CLIENT_MGBEAWR 0x5c
|
||||||
|
/* MGBEB write client */
|
||||||
|
#define TEGRA234_MEMORY_CLIENT_MGBEBWR 0x5f
|
||||||
|
/* MGBEC write client */
|
||||||
|
#define TEGRA234_MEMORY_CLIENT_MGBECWR 0x61
|
||||||
/* sdmmcd memory read client */
|
/* sdmmcd memory read client */
|
||||||
#define TEGRA234_MEMORY_CLIENT_SDMMCRAB 0x63
|
#define TEGRA234_MEMORY_CLIENT_SDMMCRAB 0x63
|
||||||
|
/* MGBED write client */
|
||||||
|
#define TEGRA234_MEMORY_CLIENT_MGBEDWR 0x65
|
||||||
/* sdmmcd memory write client */
|
/* sdmmcd memory write client */
|
||||||
#define TEGRA234_MEMORY_CLIENT_SDMMCWAB 0x67
|
#define TEGRA234_MEMORY_CLIENT_SDMMCWAB 0x67
|
||||||
/* BPMP read client */
|
/* BPMP read client */
|
||||||
|
|||||||
16
include/dt-bindings/power/mt6795-power.h
Normal file
16
include/dt-bindings/power/mt6795-power.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
|
||||||
|
#ifndef _DT_BINDINGS_POWER_MT6795_POWER_H
|
||||||
|
#define _DT_BINDINGS_POWER_MT6795_POWER_H
|
||||||
|
|
||||||
|
#define MT6795_POWER_DOMAIN_MM 0
|
||||||
|
#define MT6795_POWER_DOMAIN_VDEC 1
|
||||||
|
#define MT6795_POWER_DOMAIN_VENC 2
|
||||||
|
#define MT6795_POWER_DOMAIN_ISP 3
|
||||||
|
#define MT6795_POWER_DOMAIN_MJC 4
|
||||||
|
#define MT6795_POWER_DOMAIN_AUDIO 5
|
||||||
|
#define MT6795_POWER_DOMAIN_MFG_ASYNC 6
|
||||||
|
#define MT6795_POWER_DOMAIN_MFG_2D 7
|
||||||
|
#define MT6795_POWER_DOMAIN_MFG 8
|
||||||
|
#define MT6795_POWER_DOMAIN_MODEM 9
|
||||||
|
|
||||||
|
#endif /* _DT_BINDINGS_POWER_MT6795_POWER_H */
|
||||||
@@ -187,6 +187,13 @@
|
|||||||
#define MSM8916_VDDMX 3
|
#define MSM8916_VDDMX 3
|
||||||
#define MSM8916_VDDMX_AO 4
|
#define MSM8916_VDDMX_AO 4
|
||||||
|
|
||||||
|
/* MSM8909 Power Domain Indexes */
|
||||||
|
#define MSM8909_VDDCX MSM8916_VDDCX
|
||||||
|
#define MSM8909_VDDCX_AO MSM8916_VDDCX_AO
|
||||||
|
#define MSM8909_VDDCX_VFC MSM8916_VDDCX_VFC
|
||||||
|
#define MSM8909_VDDMX MSM8916_VDDMX
|
||||||
|
#define MSM8909_VDDMX_AO MSM8916_VDDMX_AO
|
||||||
|
|
||||||
/* MSM8953 Power Domain Indexes */
|
/* MSM8953 Power Domain Indexes */
|
||||||
#define MSM8953_VDDMD 0
|
#define MSM8953_VDDMD 0
|
||||||
#define MSM8953_VDDMD_AO 1
|
#define MSM8953_VDDMD_AO 1
|
||||||
|
|||||||
@@ -18,5 +18,6 @@
|
|||||||
#define TEGRA234_POWER_DOMAIN_MGBEA 17U
|
#define TEGRA234_POWER_DOMAIN_MGBEA 17U
|
||||||
#define TEGRA234_POWER_DOMAIN_MGBEB 18U
|
#define TEGRA234_POWER_DOMAIN_MGBEB 18U
|
||||||
#define TEGRA234_POWER_DOMAIN_MGBEC 19U
|
#define TEGRA234_POWER_DOMAIN_MGBEC 19U
|
||||||
|
#define TEGRA234_POWER_DOMAIN_MGBED 20U
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user