mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-03-16 12:04:08 +00:00
ARM driver updates for 5.18
There are a few separately maintained driver subsystems that we merge through the SoC tree, notable changes are: - Memory controller updates, mainly for Tegra and Mediatek SoCs, and clarifications for the memory controller DT bindings - SCMI firmware interface updates, in particular a new transport based on OPTEE and support for atomic operations. - Cleanups to the TEE subsystem, refactoring its memory management For SoC specific drivers without a separate subsystem, changes include - Smaller updates and fixes for TI, AT91/SAMA5, Qualcomm and NXP Layerscape SoCs. - Driver support for Microchip SAMA5D29, Tesla FSD, Renesas RZ/G2L, and Qualcomm SM8450. - Better power management on Mediatek MT81xx, NXP i.MX8MQ and older NVIDIA Tegra chips -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmI4nOUACgkQmmx57+YA GNlNNhAApPQw+FKQ6yVj2EZYcaAgik8PJAJoNQWYED52iQfm5uXgjt3aQewvrPNW nkKx5Mx+fPUfaKx5mkVOFMhME5Bw9tYbXHm2/RpRp+n8jOdUlQpAhzIPOyWPHOJS QX6qu4t+agrQzjbOCGouAJXgyxhTJFUMviM2EgVHbQHXPtdF8i2kyanfCP7Rw8cx sVtLwpvhbLm849+deYRXuv2Xw9I3M1Np7018s5QciimI2eLLEb+lJ/C5XWz5pMYn M1nZ7uwCLKPCewpMETTuhKOv0ioOXyY9C1ghyiGZFhHQfoCYTu94Hrx9t8x5gQmL qWDinXWXVk8LBegyrs8Bp4wcjtmvMMLnfWtsGSfT5uq24JOGg22OmtUNhNJbS9+p VjEvBgkXYD7UEl5npI9v9/KQWr3/UDir0zvkuV40gJyeBWNEZ/PB8olXAxgL7wZv cXRYSaUYYt3DKQf1k5I4GUyQtkP/4RaBy6AqvH5Sx0lCwuY6G6ISK+kCPaaSRKnX WR+nFw84dKCu7miehmW9qSzMQ4kiSCKIDqk7ilHcwv0J2oXDrlqVPKGGGTzZjUc8 +feqM/eSoYvDDEDemuXNSnl3hc1Zlvm7Apd5AN6kdTaNgoACDYdyvGuJ3CvzcA+K 1gBHUBvGS/ODA25KnYabr7wCMgxYqf7dXfkyKIBwFHwxOnRHtgs= =Cfbk -----END PGP SIGNATURE----- Merge tag 'arm-drivers-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc Pull ARM driver updates from Arnd Bergmann: "There are a few separately maintained driver subsystems that we merge through the SoC tree, notable changes are: - Memory controller updates, mainly for Tegra and Mediatek SoCs, and clarifications for the memory controller DT bindings - SCMI firmware interface updates, in particular a new transport based on OPTEE and support for atomic operations. - Cleanups to the TEE subsystem, refactoring its memory management For SoC specific drivers without a separate subsystem, changes include - Smaller updates and fixes for TI, AT91/SAMA5, Qualcomm and NXP Layerscape SoCs. - Driver support for Microchip SAMA5D29, Tesla FSD, Renesas RZ/G2L, and Qualcomm SM8450. - Better power management on Mediatek MT81xx, NXP i.MX8MQ and older NVIDIA Tegra chips" * tag 'arm-drivers-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (154 commits) ARM: spear: fix typos in comments soc/microchip: fix invalid free in mpfs_sys_controller_delete soc: s4: Add support for power domains controller dt-bindings: power: add Amlogic s4 power domains bindings ARM: at91: add support in soc driver for new SAMA5D29 soc: mediatek: mmsys: add sw0_rst_offset in mmsys driver data dt-bindings: memory: renesas,rpc-if: Document RZ/V2L SoC memory: emif: check the pointer temp in get_device_details() memory: emif: Add check for setup_interrupts dt-bindings: arm: mediatek: mmsys: add support for MT8186 dt-bindings: mediatek: add compatible for MT8186 pwrap soc: mediatek: pwrap: add pwrap driver for MT8186 SoC soc: mediatek: mmsys: add mmsys reset control for MT8186 soc: mediatek: mtk-infracfg: Disable ACP on MT8192 soc: ti: k3-socinfo: Add AM62x JTAG ID soc: mediatek: add MTK mutex support for MT8186 soc: mediatek: mmsys: add mt8186 mmsys routing table soc: mediatek: pm-domains: Add support for mt8186 dt-bindings: power: Add MT8186 power domains soc: mediatek: pm-domains: Add support for mt8195 ...
This commit is contained in:
commit
b4bc93bd76
124 changed files with 7644 additions and 1435 deletions
|
@ -29,6 +29,7 @@ properties:
|
|||
- mediatek,mt8167-mmsys
|
||||
- mediatek,mt8173-mmsys
|
||||
- mediatek,mt8183-mmsys
|
||||
- mediatek,mt8186-mmsys
|
||||
- mediatek,mt8192-mmsys
|
||||
- mediatek,mt8365-mmsys
|
||||
- const: syscon
|
||||
|
|
|
@ -27,6 +27,8 @@ properties:
|
|||
- qcom,sm6350-llcc
|
||||
- qcom,sm8150-llcc
|
||||
- qcom,sm8250-llcc
|
||||
- qcom,sm8350-llcc
|
||||
- qcom,sm8450-llcc
|
||||
|
||||
reg:
|
||||
items:
|
||||
|
|
198
Documentation/devicetree/bindings/clock/tesla,fsd-clock.yaml
Normal file
198
Documentation/devicetree/bindings/clock/tesla,fsd-clock.yaml
Normal file
|
@ -0,0 +1,198 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/tesla,fsd-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Tesla FSD (Full Self-Driving) SoC clock controller
|
||||
|
||||
maintainers:
|
||||
- Alim Akhtar <alim.akhtar@samsung.com>
|
||||
- linux-fsd@tesla.com
|
||||
|
||||
description: |
|
||||
FSD clock controller consist of several clock management unit
|
||||
(CMU), which generates clocks for various inteernal SoC blocks.
|
||||
The root clock comes from external OSC clock (24 MHz).
|
||||
|
||||
All available clocks are defined as preprocessor macros in
|
||||
'dt-bindings/clock/fsd-clk.h' header.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- tesla,fsd-clock-cmu
|
||||
- tesla,fsd-clock-imem
|
||||
- tesla,fsd-clock-peric
|
||||
- tesla,fsd-clock-fsys0
|
||||
- tesla,fsd-clock-fsys1
|
||||
- tesla,fsd-clock-mfc
|
||||
- tesla,fsd-clock-cam_csi
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 6
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 6
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: tesla,fsd-clock-cmu
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: External reference clock (24 MHz)
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: tesla,fsd-clock-imem
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: External reference clock (24 MHz)
|
||||
- description: IMEM TCU clock (from CMU_CMU)
|
||||
- description: IMEM bus clock (from CMU_CMU)
|
||||
- description: IMEM DMA clock (from CMU_CMU)
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: dout_cmu_imem_tcuclk
|
||||
- const: dout_cmu_imem_aclk
|
||||
- const: dout_cmu_imem_dmaclk
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: tesla,fsd-clock-peric
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: External reference clock (24 MHz)
|
||||
- description: Shared0 PLL div4 clock (from CMU_CMU)
|
||||
- description: PERIC shared1 div36 clock (from CMU_CMU)
|
||||
- description: PERIC shared0 div3 TBU clock (from CMU_CMU)
|
||||
- description: PERIC shared0 div20 clock (from CMU_CMU)
|
||||
- description: PERIC shared1 div4 DMAclock (from CMU_CMU)
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: dout_cmu_pll_shared0_div4
|
||||
- const: dout_cmu_peric_shared1div36
|
||||
- const: dout_cmu_peric_shared0div3_tbuclk
|
||||
- const: dout_cmu_peric_shared0div20
|
||||
- const: dout_cmu_peric_shared1div4_dmaclk
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: tesla,fsd-clock-fsys0
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: External reference clock (24 MHz)
|
||||
- description: Shared0 PLL div6 clock (from CMU_CMU)
|
||||
- description: FSYS0 shared1 div4 clock (from CMU_CMU)
|
||||
- description: FSYS0 shared0 div4 clock (from CMU_CMU)
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: dout_cmu_pll_shared0_div6
|
||||
- const: dout_cmu_fsys0_shared1div4
|
||||
- const: dout_cmu_fsys0_shared0div4
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: tesla,fsd-clock-fsys1
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: External reference clock (24 MHz)
|
||||
- description: FSYS1 shared0 div8 clock (from CMU_CMU)
|
||||
- description: FSYS1 shared0 div4 clock (from CMU_CMU)
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: dout_cmu_fsys1_shared0div8
|
||||
- const: dout_cmu_fsys1_shared0div4
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: tesla,fsd-clock-mfc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: External reference clock (24 MHz)
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: tesla,fsd-clock-cam_csi
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: External reference clock (24 MHz)
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#clock-cells"
|
||||
- clocks
|
||||
- clock-names
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
# Clock controller node for CMU_FSYS1
|
||||
- |
|
||||
#include <dt-bindings/clock/fsd-clk.h>
|
||||
|
||||
clock_fsys1: clock-controller@16810000 {
|
||||
compatible = "tesla,fsd-clock-fsys1";
|
||||
reg = <0x16810000 0x3000>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clocks = <&fin_pll>,
|
||||
<&clock_cmu DOUT_CMU_FSYS1_SHARED0DIV8>,
|
||||
<&clock_cmu DOUT_CMU_FSYS1_SHARED0DIV4>;
|
||||
clock-names = "fin_pll",
|
||||
"dout_cmu_fsys1_shared0div8",
|
||||
"dout_cmu_fsys1_shared0div4";
|
||||
};
|
||||
|
||||
...
|
|
@ -38,6 +38,9 @@ properties:
|
|||
The virtio transport only supports a single device.
|
||||
items:
|
||||
- const: arm,scmi-virtio
|
||||
- description: SCMI compliant firmware with OP-TEE transport
|
||||
items:
|
||||
- const: linaro,scmi-optee
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
|
@ -78,11 +81,24 @@ properties:
|
|||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
atomic-threshold-us:
|
||||
description:
|
||||
An optional time value, expressed in microseconds, representing, on this
|
||||
platform, the threshold above which any SCMI command, advertised to have
|
||||
an higher-than-threshold execution latency, should not be considered for
|
||||
atomic mode of operation, even if requested.
|
||||
default: 0
|
||||
|
||||
arm,smc-id:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
SMC id required when using smc or hvc transports
|
||||
|
||||
linaro,optee-channel-id:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Channel specifier required when using OP-TEE transport.
|
||||
|
||||
protocol@11:
|
||||
type: object
|
||||
properties:
|
||||
|
@ -195,6 +211,12 @@ patternProperties:
|
|||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
linaro,optee-channel-id:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Channel specifier required when using OP-TEE transport and
|
||||
protocol has a dedicated communication channel.
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
|
@ -226,6 +248,16 @@ else:
|
|||
- arm,smc-id
|
||||
- shmem
|
||||
|
||||
else:
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: linaro,scmi-optee
|
||||
then:
|
||||
required:
|
||||
- linaro,optee-channel-id
|
||||
|
||||
examples:
|
||||
- |
|
||||
firmware {
|
||||
|
@ -240,6 +272,8 @@ examples:
|
|||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
atomic-threshold-us = <10000>;
|
||||
|
||||
scmi_devpd: protocol@11 {
|
||||
reg = <0x11>;
|
||||
#power-domain-cells = <1>;
|
||||
|
@ -340,7 +374,48 @@ examples:
|
|||
reg = <0x11>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
firmware {
|
||||
scmi {
|
||||
compatible = "linaro,scmi-optee";
|
||||
linaro,optee-channel-id = <0>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
scmi_dvfs1: protocol@13 {
|
||||
reg = <0x13>;
|
||||
linaro,optee-channel-id = <1>;
|
||||
shmem = <&cpu_optee_lpri0>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
scmi_clk0: protocol@14 {
|
||||
reg = <0x14>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
sram@51000000 {
|
||||
compatible = "mmio-sram";
|
||||
reg = <0x0 0x51000000 0x0 0x10000>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0 0x0 0x51000000 0x10000>;
|
||||
|
||||
cpu_optee_lpri0: optee-sram-section@0 {
|
||||
compatible = "arm,scmi-shmem";
|
||||
reg = <0x0 0x80>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,lpddr2-timings.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: LPDDR2 SDRAM AC timing parameters for a given speed-bin
|
||||
|
||||
maintainers:
|
||||
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: jedec,lpddr2-timings
|
||||
|
||||
max-freq:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Maximum DDR clock frequency for the speed-bin, in Hz.
|
||||
|
||||
min-freq:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Minimum DDR clock frequency for the speed-bin, in Hz.
|
||||
|
||||
tCKESR:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
CKE minimum pulse width during SELF REFRESH (low pulse width during
|
||||
SELF REFRESH) in pico seconds.
|
||||
|
||||
tDQSCK-max:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
DQS output data access time from CK_t/CK_c in pico seconds.
|
||||
|
||||
tDQSCK-max-derated:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
DQS output data access time from CK_t/CK_c, temperature de-rated, in pico
|
||||
seconds.
|
||||
|
||||
tFAW:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Four-bank activate window in pico seconds.
|
||||
|
||||
tRAS-max-ns:
|
||||
description: |
|
||||
Row active time in nano seconds.
|
||||
|
||||
tRAS-min:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Row active time in pico seconds.
|
||||
|
||||
tRCD:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
RAS-to-CAS delay in pico seconds.
|
||||
|
||||
tRPab:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Row precharge time (all banks) in pico seconds.
|
||||
|
||||
tRRD:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Active bank A to active bank B in pico seconds.
|
||||
|
||||
tRTP:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Internal READ to PRECHARGE command delay in pico seconds.
|
||||
|
||||
tWR:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
WRITE recovery time in pico seconds.
|
||||
|
||||
tWTR:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Internal WRITE-to-READ command delay in pico seconds.
|
||||
|
||||
tXP:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Exit power-down to next valid command delay in pico seconds.
|
||||
|
||||
tZQCL:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Long calibration time in pico seconds.
|
||||
|
||||
tZQCS:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Short calibration time in pico seconds.
|
||||
|
||||
tZQinit:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Initialization calibration time in pico seconds.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- min-freq
|
||||
- max-freq
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
timings {
|
||||
compatible = "jedec,lpddr2-timings";
|
||||
min-freq = <10000000>;
|
||||
max-freq = <400000000>;
|
||||
tCKESR = <15000>;
|
||||
tDQSCK-max = <5500>;
|
||||
tFAW = <50000>;
|
||||
tRAS-max-ns = <70000>;
|
||||
tRAS-min = <42000>;
|
||||
tRPab = <21000>;
|
||||
tRCD = <18000>;
|
||||
tRRD = <10000>;
|
||||
tRTP = <7500>;
|
||||
tWR = <15000>;
|
||||
tWTR = <7500>;
|
||||
tXP = <7500>;
|
||||
tZQCL = <360000>;
|
||||
tZQCS = <90000>;
|
||||
tZQinit = <1000000>;
|
||||
};
|
|
@ -30,12 +30,26 @@ properties:
|
|||
maximum: 255
|
||||
description: |
|
||||
Revision 1 value of SDRAM chip. Obtained from device datasheet.
|
||||
Property is deprecated, use revision-id instead.
|
||||
deprecated: true
|
||||
|
||||
revision-id2:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 255
|
||||
description: |
|
||||
Revision 2 value of SDRAM chip. Obtained from device datasheet.
|
||||
Property is deprecated, use revision-id instead.
|
||||
deprecated: true
|
||||
|
||||
revision-id:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description: |
|
||||
Revision IDs read from Mode Register 6 and 7. One byte per uint32 cell (i.e. <MR6 MR7>).
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
items:
|
||||
minimum: 0
|
||||
maximum: 255
|
||||
|
||||
density:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
@ -142,14 +156,12 @@ properties:
|
|||
|
||||
patternProperties:
|
||||
"^lpddr2-timings":
|
||||
type: object
|
||||
$ref: jedec,lpddr2-timings.yaml
|
||||
description: |
|
||||
The lpddr2 node may have one or more child nodes of type "lpddr2-timings".
|
||||
"lpddr2-timings" provides AC timing parameters of the device for
|
||||
a given speed-bin. The user may provide the timings for as many
|
||||
speed-bins as is required. Please see Documentation/devicetree/
|
||||
bindings/memory-controllers/ddr/lpddr2-timings.txt for more information
|
||||
on "lpddr2-timings".
|
||||
speed-bins as is required.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
@ -164,8 +176,7 @@ examples:
|
|||
compatible = "elpida,ECB240ABACN", "jedec,lpddr2-s4";
|
||||
density = <2048>;
|
||||
io-width = <32>;
|
||||
revision-id1 = <1>;
|
||||
revision-id2 = <0>;
|
||||
revision-id = <1 0>;
|
||||
|
||||
tRPab-min-tck = <3>;
|
||||
tRCD-min-tck = <3>;
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,lpddr3-timings.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: LPDDR3 SDRAM AC timing parameters for a given speed-bin
|
||||
|
||||
maintainers:
|
||||
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: jedec,lpddr3-timings
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: |
|
||||
Maximum DDR clock frequency for the speed-bin, in Hz.
|
||||
Property is deprecated, use max-freq.
|
||||
deprecated: true
|
||||
|
||||
max-freq:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Maximum DDR clock frequency for the speed-bin, in Hz.
|
||||
|
||||
min-freq:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Minimum DDR clock frequency for the speed-bin, in Hz.
|
||||
|
||||
tCKE:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
CKE minimum pulse width (HIGH and LOW pulse width) in pico seconds.
|
||||
|
||||
tCKESR:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
CKE minimum pulse width during SELF REFRESH (low pulse width during
|
||||
SELF REFRESH) in pico seconds.
|
||||
|
||||
tFAW:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Four-bank activate window in pico seconds.
|
||||
|
||||
tMRD:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Mode register set command delay in pico seconds.
|
||||
|
||||
tR2R-C2C:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Additional READ-to-READ delay in chip-to-chip cases in pico seconds.
|
||||
|
||||
tRAS:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Row active time in pico seconds.
|
||||
|
||||
tRC:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
ACTIVATE-to-ACTIVATE command period in pico seconds.
|
||||
|
||||
tRCD:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
RAS-to-CAS delay in pico seconds.
|
||||
|
||||
tRFC:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Refresh Cycle time in pico seconds.
|
||||
|
||||
tRPab:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Row precharge time (all banks) in pico seconds.
|
||||
|
||||
tRPpb:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Row precharge time (single banks) in pico seconds.
|
||||
|
||||
tRRD:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Active bank A to active bank B in pico seconds.
|
||||
|
||||
tRTP:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Internal READ to PRECHARGE command delay in pico seconds.
|
||||
|
||||
tW2W-C2C:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Additional WRITE-to-WRITE delay in chip-to-chip cases in pico seconds.
|
||||
|
||||
tWR:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
WRITE recovery time in pico seconds.
|
||||
|
||||
tWTR:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Internal WRITE-to-READ command delay in pico seconds.
|
||||
|
||||
tXP:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Exit power-down to next valid command delay in pico seconds.
|
||||
|
||||
tXSR:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
SELF REFRESH exit to next valid command delay in pico seconds.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- min-freq
|
||||
- max-freq
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
lpddr3 {
|
||||
timings {
|
||||
compatible = "jedec,lpddr3-timings";
|
||||
max-freq = <800000000>;
|
||||
min-freq = <100000000>;
|
||||
tCKE = <3750>;
|
||||
tCKESR = <3750>;
|
||||
tFAW = <25000>;
|
||||
tMRD = <7000>;
|
||||
tR2R-C2C = <0>;
|
||||
tRAS = <23000>;
|
||||
tRC = <33750>;
|
||||
tRCD = <10000>;
|
||||
tRFC = <65000>;
|
||||
tRPab = <12000>;
|
||||
tRPpb = <12000>;
|
||||
tRRD = <6000>;
|
||||
tRTP = <3750>;
|
||||
tW2W-C2C = <0>;
|
||||
tWR = <7500>;
|
||||
tWTR = <3750>;
|
||||
tXP = <3750>;
|
||||
tXSR = <70000>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,263 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,lpddr3.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: LPDDR3 SDRAM compliant to JEDEC JESD209-3
|
||||
|
||||
maintainers:
|
||||
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- samsung,K3QF2F20DB
|
||||
- const: jedec,lpddr3
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
deprecated: true
|
||||
|
||||
density:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Density in megabits of SDRAM chip.
|
||||
enum:
|
||||
- 4096
|
||||
- 8192
|
||||
- 16384
|
||||
- 32768
|
||||
|
||||
io-width:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
IO bus width in bits of SDRAM chip.
|
||||
enum:
|
||||
- 32
|
||||
- 16
|
||||
|
||||
manufacturer-id:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Manufacturer ID value read from Mode Register 5. The property is
|
||||
deprecated, manufacturer should be derived from the compatible.
|
||||
deprecated: true
|
||||
|
||||
revision-id:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
items:
|
||||
maximum: 255
|
||||
description: |
|
||||
Revision value of SDRAM chip read from Mode Registers 6 and 7.
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
deprecated: true
|
||||
|
||||
tCKE-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 15
|
||||
description: |
|
||||
CKE minimum pulse width (HIGH and LOW pulse width) in terms of number
|
||||
of clock cycles.
|
||||
|
||||
tCKESR-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 15
|
||||
description: |
|
||||
CKE minimum pulse width during SELF REFRESH (low pulse width during
|
||||
SELF REFRESH) in terms of number of clock cycles.
|
||||
|
||||
tDQSCK-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 15
|
||||
description: |
|
||||
DQS output data access time from CK_t/CK_c in terms of number of clock
|
||||
cycles.
|
||||
|
||||
tFAW-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 63
|
||||
description: |
|
||||
Four-bank activate window in terms of number of clock cycles.
|
||||
|
||||
tMRD-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 15
|
||||
description: |
|
||||
Mode register set command delay in terms of number of clock cycles.
|
||||
|
||||
tR2R-C2C-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1]
|
||||
description: |
|
||||
Additional READ-to-READ delay in chip-to-chip cases in terms of number
|
||||
of clock cycles.
|
||||
|
||||
tRAS-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 63
|
||||
description: |
|
||||
Row active time in terms of number of clock cycles.
|
||||
|
||||
tRC-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 63
|
||||
description: |
|
||||
ACTIVATE-to-ACTIVATE command period in terms of number of clock cycles.
|
||||
|
||||
tRCD-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 15
|
||||
description: |
|
||||
RAS-to-CAS delay in terms of number of clock cycles.
|
||||
|
||||
tRFC-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 255
|
||||
description: |
|
||||
Refresh Cycle time in terms of number of clock cycles.
|
||||
|
||||
tRL-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 15
|
||||
description: |
|
||||
READ data latency in terms of number of clock cycles.
|
||||
|
||||
tRPab-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 15
|
||||
description: |
|
||||
Row precharge time (all banks) in terms of number of clock cycles.
|
||||
|
||||
tRPpb-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 15
|
||||
description: |
|
||||
Row precharge time (single banks) in terms of number of clock cycles.
|
||||
|
||||
tRRD-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 15
|
||||
description: |
|
||||
Active bank A to active bank B in terms of number of clock cycles.
|
||||
|
||||
tRTP-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 15
|
||||
description: |
|
||||
Internal READ to PRECHARGE command delay in terms of number of clock
|
||||
cycles.
|
||||
|
||||
tW2W-C2C-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1]
|
||||
description: |
|
||||
Additional WRITE-to-WRITE delay in chip-to-chip cases in terms of number
|
||||
of clock cycles.
|
||||
|
||||
tWL-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 15
|
||||
description: |
|
||||
WRITE data latency in terms of number of clock cycles.
|
||||
|
||||
tWR-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 15
|
||||
description: |
|
||||
WRITE recovery time in terms of number of clock cycles.
|
||||
|
||||
tWTR-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 15
|
||||
description: |
|
||||
Internal WRITE-to-READ command delay in terms of number of clock cycles.
|
||||
|
||||
tXP-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 255
|
||||
description: |
|
||||
Exit power-down to next valid command delay in terms of number of clock
|
||||
cycles.
|
||||
|
||||
tXSR-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 1023
|
||||
description: |
|
||||
SELF REFRESH exit to next valid command delay in terms of number of clock
|
||||
cycles.
|
||||
|
||||
patternProperties:
|
||||
"^timings((-[0-9])+|(@[0-9a-f]+))?$":
|
||||
$ref: jedec,lpddr3-timings.yaml
|
||||
description: |
|
||||
The lpddr3 node may have one or more child nodes with timings.
|
||||
Each timing node provides AC timing parameters of the device for a given
|
||||
speed-bin. The user may provide the timings for as many speed-bins as is
|
||||
required.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- density
|
||||
- io-width
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
lpddr3 {
|
||||
compatible = "samsung,K3QF2F20DB", "jedec,lpddr3";
|
||||
density = <16384>;
|
||||
io-width = <32>;
|
||||
|
||||
tCKE-min-tck = <2>;
|
||||
tCKESR-min-tck = <2>;
|
||||
tDQSCK-min-tck = <5>;
|
||||
tFAW-min-tck = <5>;
|
||||
tMRD-min-tck = <5>;
|
||||
tR2R-C2C-min-tck = <0>;
|
||||
tRAS-min-tck = <5>;
|
||||
tRC-min-tck = <6>;
|
||||
tRCD-min-tck = <3>;
|
||||
tRFC-min-tck = <17>;
|
||||
tRL-min-tck = <14>;
|
||||
tRPab-min-tck = <2>;
|
||||
tRPpb-min-tck = <2>;
|
||||
tRRD-min-tck = <2>;
|
||||
tRTP-min-tck = <2>;
|
||||
tW2W-C2C-min-tck = <0>;
|
||||
tWL-min-tck = <8>;
|
||||
tWR-min-tck = <7>;
|
||||
tWTR-min-tck = <2>;
|
||||
tXP-min-tck = <2>;
|
||||
tXSR-min-tck = <12>;
|
||||
|
||||
timings {
|
||||
compatible = "jedec,lpddr3-timings";
|
||||
max-freq = <800000000>;
|
||||
min-freq = <100000000>;
|
||||
tCKE = <3750>;
|
||||
tCKESR = <3750>;
|
||||
tFAW = <25000>;
|
||||
tMRD = <7000>;
|
||||
tR2R-C2C = <0>;
|
||||
tRAS = <23000>;
|
||||
tRC = <33750>;
|
||||
tRCD = <10000>;
|
||||
tRFC = <65000>;
|
||||
tRPab = <12000>;
|
||||
tRPpb = <12000>;
|
||||
tRRD = <6000>;
|
||||
tRTP = <3750>;
|
||||
tW2W-C2C = <0>;
|
||||
tWR = <7500>;
|
||||
tWTR = <3750>;
|
||||
tXP = <3750>;
|
||||
tXSR = <70000>;
|
||||
};
|
||||
};
|
|
@ -1,52 +0,0 @@
|
|||
* AC timing parameters of LPDDR2(JESD209-2) memories for a given speed-bin
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "jedec,lpddr2-timings"
|
||||
- min-freq : minimum DDR clock frequency for the speed-bin. Type is <u32>
|
||||
- max-freq : maximum DDR clock frequency for the speed-bin. Type is <u32>
|
||||
|
||||
Optional properties:
|
||||
|
||||
The following properties represent AC timing parameters from the memory
|
||||
data-sheet of the device for a given speed-bin. All these properties are
|
||||
of type <u32> and the default unit is ps (pico seconds). Parameters with
|
||||
a different unit have a suffix indicating the unit such as 'tRAS-max-ns'
|
||||
- tRCD
|
||||
- tWR
|
||||
- tRAS-min
|
||||
- tRRD
|
||||
- tWTR
|
||||
- tXP
|
||||
- tRTP
|
||||
- tDQSCK-max
|
||||
- tFAW
|
||||
- tZQCS
|
||||
- tZQinit
|
||||
- tRPab
|
||||
- tZQCL
|
||||
- tCKESR
|
||||
- tRAS-max-ns
|
||||
- tDQSCK-max-derated
|
||||
|
||||
Example:
|
||||
|
||||
timings_elpida_ECB240ABACN_400mhz: lpddr2-timings@0 {
|
||||
compatible = "jedec,lpddr2-timings";
|
||||
min-freq = <10000000>;
|
||||
max-freq = <400000000>;
|
||||
tRPab = <21000>;
|
||||
tRCD = <18000>;
|
||||
tWR = <15000>;
|
||||
tRAS-min = <42000>;
|
||||
tRRD = <10000>;
|
||||
tWTR = <7500>;
|
||||
tXP = <7500>;
|
||||
tRTP = <7500>;
|
||||
tCKESR = <15000>;
|
||||
tDQSCK-max = <5500>;
|
||||
tFAW = <50000>;
|
||||
tZQCS = <90000>;
|
||||
tZQCL = <360000>;
|
||||
tZQinit = <1000000>;
|
||||
tRAS-max-ns = <70000>;
|
||||
};
|
|
@ -1,58 +0,0 @@
|
|||
* AC timing parameters of LPDDR3 memories for a given speed-bin.
|
||||
|
||||
The structures are based on LPDDR2 and extended where needed.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "jedec,lpddr3-timings"
|
||||
- min-freq : minimum DDR clock frequency for the speed-bin. Type is <u32>
|
||||
- reg : maximum DDR clock frequency for the speed-bin. Type is <u32>
|
||||
|
||||
Optional properties:
|
||||
|
||||
The following properties represent AC timing parameters from the memory
|
||||
data-sheet of the device for a given speed-bin. All these properties are
|
||||
of type <u32> and the default unit is ps (pico seconds).
|
||||
- tRFC
|
||||
- tRRD
|
||||
- tRPab
|
||||
- tRPpb
|
||||
- tRCD
|
||||
- tRC
|
||||
- tRAS
|
||||
- tWTR
|
||||
- tWR
|
||||
- tRTP
|
||||
- tW2W-C2C
|
||||
- tR2R-C2C
|
||||
- tFAW
|
||||
- tXSR
|
||||
- tXP
|
||||
- tCKE
|
||||
- tCKESR
|
||||
- tMRD
|
||||
|
||||
Example:
|
||||
|
||||
timings_samsung_K3QF2F20DB_800mhz: lpddr3-timings@800000000 {
|
||||
compatible = "jedec,lpddr3-timings";
|
||||
reg = <800000000>; /* workaround: it shows max-freq */
|
||||
min-freq = <100000000>;
|
||||
tRFC = <65000>;
|
||||
tRRD = <6000>;
|
||||
tRPab = <12000>;
|
||||
tRPpb = <12000>;
|
||||
tRCD = <10000>;
|
||||
tRC = <33750>;
|
||||
tRAS = <23000>;
|
||||
tWTR = <3750>;
|
||||
tWR = <7500>;
|
||||
tRTP = <3750>;
|
||||
tW2W-C2C = <0>;
|
||||
tR2R-C2C = <0>;
|
||||
tFAW = <25000>;
|
||||
tXSR = <70000>;
|
||||
tXP = <3750>;
|
||||
tCKE = <3750>;
|
||||
tCKESR = <3750>;
|
||||
tMRD = <7000>;
|
||||
};
|
|
@ -1,107 +0,0 @@
|
|||
* LPDDR3 SDRAM memories compliant to JEDEC JESD209-3C
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "<vendor>,<type>", and generic value "jedec,lpddr3".
|
||||
Example "<vendor>,<type>" values:
|
||||
"samsung,K3QF2F20DB"
|
||||
|
||||
- density : <u32> representing density in Mb (Mega bits)
|
||||
- io-width : <u32> representing bus width. Possible values are 8, 16, 32, 64
|
||||
- #address-cells: Must be set to 1
|
||||
- #size-cells: Must be set to 0
|
||||
|
||||
Optional properties:
|
||||
|
||||
- manufacturer-id : <u32> Manufacturer ID value read from Mode Register 5
|
||||
- revision-id : <u32 u32> Revision IDs read from Mode Registers 6 and 7
|
||||
|
||||
The following optional properties represent the minimum value of some AC
|
||||
timing parameters of the DDR device in terms of number of clock cycles.
|
||||
These values shall be obtained from the device data-sheet.
|
||||
- tRFC-min-tck
|
||||
- tRRD-min-tck
|
||||
- tRPab-min-tck
|
||||
- tRPpb-min-tck
|
||||
- tRCD-min-tck
|
||||
- tRC-min-tck
|
||||
- tRAS-min-tck
|
||||
- tWTR-min-tck
|
||||
- tWR-min-tck
|
||||
- tRTP-min-tck
|
||||
- tW2W-C2C-min-tck
|
||||
- tR2R-C2C-min-tck
|
||||
- tWL-min-tck
|
||||
- tDQSCK-min-tck
|
||||
- tRL-min-tck
|
||||
- tFAW-min-tck
|
||||
- tXSR-min-tck
|
||||
- tXP-min-tck
|
||||
- tCKE-min-tck
|
||||
- tCKESR-min-tck
|
||||
- tMRD-min-tck
|
||||
|
||||
Child nodes:
|
||||
- The lpddr3 node may have one or more child nodes of type "lpddr3-timings".
|
||||
"lpddr3-timings" provides AC timing parameters of the device for
|
||||
a given speed-bin. Please see
|
||||
Documentation/devicetree/bindings/memory-controllers/ddr/lpddr3-timings.txt
|
||||
for more information on "lpddr3-timings"
|
||||
|
||||
Example:
|
||||
|
||||
samsung_K3QF2F20DB: lpddr3 {
|
||||
compatible = "samsung,K3QF2F20DB", "jedec,lpddr3";
|
||||
density = <16384>;
|
||||
io-width = <32>;
|
||||
manufacturer-id = <1>;
|
||||
revision-id = <123 234>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
tRFC-min-tck = <17>;
|
||||
tRRD-min-tck = <2>;
|
||||
tRPab-min-tck = <2>;
|
||||
tRPpb-min-tck = <2>;
|
||||
tRCD-min-tck = <3>;
|
||||
tRC-min-tck = <6>;
|
||||
tRAS-min-tck = <5>;
|
||||
tWTR-min-tck = <2>;
|
||||
tWR-min-tck = <7>;
|
||||
tRTP-min-tck = <2>;
|
||||
tW2W-C2C-min-tck = <0>;
|
||||
tR2R-C2C-min-tck = <0>;
|
||||
tWL-min-tck = <8>;
|
||||
tDQSCK-min-tck = <5>;
|
||||
tRL-min-tck = <14>;
|
||||
tFAW-min-tck = <5>;
|
||||
tXSR-min-tck = <12>;
|
||||
tXP-min-tck = <2>;
|
||||
tCKE-min-tck = <2>;
|
||||
tCKESR-min-tck = <2>;
|
||||
tMRD-min-tck = <5>;
|
||||
|
||||
timings_samsung_K3QF2F20DB_800mhz: lpddr3-timings@800000000 {
|
||||
compatible = "jedec,lpddr3-timings";
|
||||
/* workaround: 'reg' shows max-freq */
|
||||
reg = <800000000>;
|
||||
min-freq = <100000000>;
|
||||
tRFC = <65000>;
|
||||
tRRD = <6000>;
|
||||
tRPab = <12000>;
|
||||
tRPpb = <12000>;
|
||||
tRCD = <10000>;
|
||||
tRC = <33750>;
|
||||
tRAS = <23000>;
|
||||
tWTR = <3750>;
|
||||
tWR = <7500>;
|
||||
tRTP = <3750>;
|
||||
tW2W-C2C = <0>;
|
||||
tR2R-C2C = <0>;
|
||||
tFAW = <25000>;
|
||||
tXSR = <70000>;
|
||||
tXP = <3750>;
|
||||
tCKE = <3750>;
|
||||
tCKESR = <3750>;
|
||||
tMRD = <7000>;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/memory-controllers/fsl/fsl,ifc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: FSL/NXP Integrated Flash Controller
|
||||
|
||||
maintainers:
|
||||
- Li Yang <leoyang.li@nxp.com>
|
||||
|
||||
description: |
|
||||
NXP's integrated flash controller (IFC) is an advanced version of the
|
||||
enhanced local bus controller which includes similar programming and signal
|
||||
interfaces with an extended feature set. The IFC provides access to multiple
|
||||
external memory types, such as NAND flash (SLC and MLC), NOR flash, EPROM,
|
||||
SRAM and other memories where address and data are shared on a bus.
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^memory-controller@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
const: fsl,ifc
|
||||
|
||||
"#address-cells":
|
||||
enum: [2, 3]
|
||||
description: |
|
||||
Should be either two or three. The first cell is the chipselect
|
||||
number, and the remaining cells are the offset into the chipselect.
|
||||
|
||||
"#size-cells":
|
||||
enum: [1, 2]
|
||||
description: |
|
||||
Either one or two, depending on how large each chipselect can be.
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
description: |
|
||||
IFC may have one or two interrupts. If two interrupt specifiers are
|
||||
present, the first is the "common" interrupt (CM_EVTER_STAT), and the
|
||||
second is the NAND interrupt (NAND_EVTER_STAT). If there is only one,
|
||||
that interrupt reports both types of event.
|
||||
|
||||
little-endian:
|
||||
type: boolean
|
||||
description: |
|
||||
If this property is absent, the big-endian mode will be in use as default
|
||||
for registers.
|
||||
|
||||
ranges:
|
||||
description: |
|
||||
Each range corresponds to a single chipselect, and covers the entire
|
||||
access window as configured.
|
||||
|
||||
patternProperties:
|
||||
"^.*@[a-f0-9]+(,[a-f0-9]+)+$":
|
||||
type: object
|
||||
description: |
|
||||
Child device nodes describe the devices connected to IFC such as NOR (e.g.
|
||||
cfi-flash) and NAND (fsl,ifc-nand). There might be board specific devices
|
||||
like FPGAs, CPLDs, etc.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
memory-controller@ffe1e000 {
|
||||
compatible = "fsl,ifc";
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
reg = <0x0 0xffe1e000 0 0x2000>;
|
||||
interrupts = <16 2 19 2>;
|
||||
little-endian;
|
||||
|
||||
/* NOR, NAND Flashes and CPLD on board */
|
||||
ranges = <0x0 0x0 0x0 0xee000000 0x02000000>,
|
||||
<0x1 0x0 0x0 0xffa00000 0x00010000>,
|
||||
<0x3 0x0 0x0 0xffb00000 0x00020000>;
|
||||
|
||||
flash@0,0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "cfi-flash";
|
||||
reg = <0x0 0x0 0x2000000>;
|
||||
bank-width = <2>;
|
||||
device-width = <1>;
|
||||
|
||||
partition@0 {
|
||||
/* 32MB for user data */
|
||||
reg = <0x0 0x02000000>;
|
||||
label = "NOR Data";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -1,82 +0,0 @@
|
|||
Integrated Flash Controller
|
||||
|
||||
Properties:
|
||||
- name : Should be ifc
|
||||
- compatible : should contain "fsl,ifc". The version of the integrated
|
||||
flash controller can be found in the IFC_REV register at
|
||||
offset zero.
|
||||
|
||||
- #address-cells : Should be either two or three. The first cell is the
|
||||
chipselect number, and the remaining cells are the
|
||||
offset into the chipselect.
|
||||
- #size-cells : Either one or two, depending on how large each chipselect
|
||||
can be.
|
||||
- reg : Offset and length of the register set for the device
|
||||
- interrupts: IFC may have one or two interrupts. If two interrupt
|
||||
specifiers are present, the first is the "common"
|
||||
interrupt (CM_EVTER_STAT), and the second is the NAND
|
||||
interrupt (NAND_EVTER_STAT). If there is only one,
|
||||
that interrupt reports both types of event.
|
||||
|
||||
- little-endian : If this property is absent, the big-endian mode will
|
||||
be in use as default for registers.
|
||||
|
||||
- ranges : Each range corresponds to a single chipselect, and covers
|
||||
the entire access window as configured.
|
||||
|
||||
Child device nodes describe the devices connected to IFC such as NOR (e.g.
|
||||
cfi-flash) and NAND (fsl,ifc-nand). There might be board specific devices
|
||||
like FPGAs, CPLDs, etc.
|
||||
|
||||
Example:
|
||||
|
||||
ifc@ffe1e000 {
|
||||
compatible = "fsl,ifc", "simple-bus";
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
reg = <0x0 0xffe1e000 0 0x2000>;
|
||||
interrupts = <16 2 19 2>;
|
||||
little-endian;
|
||||
|
||||
/* NOR, NAND Flashes and CPLD on board */
|
||||
ranges = <0x0 0x0 0x0 0xee000000 0x02000000
|
||||
0x1 0x0 0x0 0xffa00000 0x00010000
|
||||
0x3 0x0 0x0 0xffb00000 0x00020000>;
|
||||
|
||||
flash@0,0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "cfi-flash";
|
||||
reg = <0x0 0x0 0x2000000>;
|
||||
bank-width = <2>;
|
||||
device-width = <1>;
|
||||
|
||||
partition@0 {
|
||||
/* 32MB for user data */
|
||||
reg = <0x0 0x02000000>;
|
||||
label = "NOR Data";
|
||||
};
|
||||
};
|
||||
|
||||
flash@1,0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "fsl,ifc-nand";
|
||||
reg = <0x1 0x0 0x10000>;
|
||||
|
||||
partition@0 {
|
||||
/* This location must not be altered */
|
||||
/* 1MB for u-boot Bootloader Image */
|
||||
reg = <0x0 0x00100000>;
|
||||
label = "NAND U-Boot Image";
|
||||
read-only;
|
||||
};
|
||||
};
|
||||
|
||||
cpld@3,0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "fsl,p1010rdb-cpld";
|
||||
reg = <0x3 0x0 0x000001f>;
|
||||
};
|
||||
};
|
|
@ -16,7 +16,7 @@ description: |
|
|||
MediaTek SMI have two generations of HW architecture, here is the list
|
||||
which generation the SoCs use:
|
||||
generation 1: mt2701 and mt7623.
|
||||
generation 2: mt2712, mt6779, mt8167, mt8173, mt8183, mt8192 and mt8195.
|
||||
generation 2: mt2712, mt6779, mt8167, mt8173, mt8183, mt8186, mt8192 and mt8195.
|
||||
|
||||
There's slight differences between the two SMI, for generation 2, the
|
||||
register which control the iommu port is at each larb's register base. But
|
||||
|
@ -35,6 +35,7 @@ properties:
|
|||
- mediatek,mt8167-smi-common
|
||||
- mediatek,mt8173-smi-common
|
||||
- mediatek,mt8183-smi-common
|
||||
- mediatek,mt8186-smi-common
|
||||
- mediatek,mt8192-smi-common
|
||||
- mediatek,mt8195-smi-common-vdo
|
||||
- mediatek,mt8195-smi-common-vpp
|
||||
|
@ -88,10 +89,9 @@ allOf:
|
|||
- mediatek,mt2701-smi-common
|
||||
then:
|
||||
properties:
|
||||
clock:
|
||||
items:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
items:
|
||||
- const: apb
|
||||
|
@ -108,10 +108,9 @@ allOf:
|
|||
required:
|
||||
- mediatek,smi
|
||||
properties:
|
||||
clock:
|
||||
items:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
items:
|
||||
- const: apb
|
||||
|
@ -127,16 +126,16 @@ allOf:
|
|||
enum:
|
||||
- mediatek,mt6779-smi-common
|
||||
- mediatek,mt8183-smi-common
|
||||
- mediatek,mt8186-smi-common
|
||||
- mediatek,mt8192-smi-common
|
||||
- mediatek,mt8195-smi-common-vdo
|
||||
- mediatek,mt8195-smi-common-vpp
|
||||
|
||||
then:
|
||||
properties:
|
||||
clock:
|
||||
items:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
clocks:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
clock-names:
|
||||
items:
|
||||
- const: apb
|
||||
|
@ -146,10 +145,9 @@ allOf:
|
|||
|
||||
else: # for gen2 HW that don't have gals
|
||||
properties:
|
||||
clock:
|
||||
items:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: apb
|
||||
|
|
|
@ -23,6 +23,7 @@ properties:
|
|||
- mediatek,mt8167-smi-larb
|
||||
- mediatek,mt8173-smi-larb
|
||||
- mediatek,mt8183-smi-larb
|
||||
- mediatek,mt8186-smi-larb
|
||||
- mediatek,mt8192-smi-larb
|
||||
- mediatek,mt8195-smi-larb
|
||||
|
||||
|
@ -75,15 +76,16 @@ allOf:
|
|||
compatible:
|
||||
enum:
|
||||
- mediatek,mt8183-smi-larb
|
||||
- mediatek,mt8186-smi-larb
|
||||
- mediatek,mt8195-smi-larb
|
||||
|
||||
then:
|
||||
properties:
|
||||
clock:
|
||||
items:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: apb
|
||||
- const: smi
|
||||
|
@ -91,10 +93,9 @@ allOf:
|
|||
|
||||
else:
|
||||
properties:
|
||||
clock:
|
||||
items:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: apb
|
||||
|
@ -108,7 +109,7 @@ allOf:
|
|||
- mediatek,mt2701-smi-larb
|
||||
- mediatek,mt2712-smi-larb
|
||||
- mediatek,mt6779-smi-larb
|
||||
- mediatek,mt8167-smi-larb
|
||||
- mediatek,mt8186-smi-larb
|
||||
- mediatek,mt8192-smi-larb
|
||||
- mediatek,mt8195-smi-larb
|
||||
|
||||
|
|
|
@ -40,7 +40,8 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- renesas,r9a07g044-rpc-if # RZ/G2{L,LC}
|
||||
- const: renesas,rzg2l-rpc-if # RZ/G2L family
|
||||
- renesas,r9a07g054-rpc-if # RZ/V2L
|
||||
- const: renesas,rzg2l-rpc-if
|
||||
|
||||
reg:
|
||||
items:
|
||||
|
|
|
@ -51,8 +51,7 @@ properties:
|
|||
$ref: '/schemas/types.yaml#/definitions/phandle'
|
||||
description: |
|
||||
phandle of the connected DRAM memory device. For more information please
|
||||
refer to documentation file:
|
||||
Documentation/devicetree/bindings/memory-controllers/ddr/lpddr3.txt
|
||||
refer to jedec,lpddr3.yaml.
|
||||
|
||||
operating-points-v2: true
|
||||
|
||||
|
|
|
@ -12,13 +12,14 @@ maintainers:
|
|||
- Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
|
||||
description: |+
|
||||
Secure Power Domains used in Meson A1/C1 SoCs, and should be the child node
|
||||
Secure Power Domains used in Meson A1/C1/S4 SoCs, and should be the child node
|
||||
of secure-monitor.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- amlogic,meson-a1-pwrc
|
||||
- amlogic,meson-s4-pwrc
|
||||
|
||||
"#power-domain-cells":
|
||||
const: 1
|
||||
|
|
|
@ -26,7 +26,9 @@ properties:
|
|||
- mediatek,mt8167-power-controller
|
||||
- mediatek,mt8173-power-controller
|
||||
- mediatek,mt8183-power-controller
|
||||
- mediatek,mt8186-power-controller
|
||||
- mediatek,mt8192-power-controller
|
||||
- mediatek,mt8195-power-controller
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
@ -64,6 +66,7 @@ patternProperties:
|
|||
"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/mt8192-power.h" - for MT8192 type power domain.
|
||||
"include/dt-bindings/power/mt8195-power.h" - for MT8195 type power domain.
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
|
|
|
@ -17,6 +17,7 @@ properties:
|
|||
compatible:
|
||||
enum:
|
||||
- qcom,mdm9607-rpmpd
|
||||
- qcom,msm8226-rpmpd
|
||||
- qcom,msm8916-rpmpd
|
||||
- qcom,msm8939-rpmpd
|
||||
- qcom,msm8953-rpmpd
|
||||
|
|
|
@ -47,6 +47,10 @@ properties:
|
|||
- qcom,sm8350-cdsp-pas
|
||||
- qcom,sm8350-slpi-pas
|
||||
- qcom,sm8350-mpss-pas
|
||||
- qcom,sm8450-adsp-pas
|
||||
- qcom,sm8450-cdsp-pas
|
||||
- qcom,sm8450-mpss-pas
|
||||
- qcom,sm8450-slpi-pas
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -175,6 +179,10 @@ allOf:
|
|||
- qcom,sm8350-cdsp-pas
|
||||
- qcom,sm8350-slpi-pas
|
||||
- qcom,sm8350-mpss-pas
|
||||
- qcom,sm8450-adsp-pas
|
||||
- qcom,sm8450-cdsp-pas
|
||||
- qcom,sm8450-slpi-pas
|
||||
- qcom,sm8450-mpss-pas
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
|
@ -283,6 +291,9 @@ allOf:
|
|||
- qcom,sm8350-adsp-pas
|
||||
- qcom,sm8350-cdsp-pas
|
||||
- qcom,sm8350-slpi-pas
|
||||
- qcom,sm8450-adsp-pas
|
||||
- qcom,sm8450-cdsp-pas
|
||||
- qcom,sm8450-slpi-pas
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
|
@ -312,6 +323,7 @@ allOf:
|
|||
- qcom,sm6350-mpss-pas
|
||||
- qcom,sm8150-mpss-pas
|
||||
- qcom,sm8350-mpss-pas
|
||||
- qcom,sm8450-mpss-pas
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
|
@ -434,6 +446,7 @@ allOf:
|
|||
- qcom,sm6350-mpss-pas
|
||||
- qcom,sm8150-mpss-pas
|
||||
- qcom,sm8350-mpss-pas
|
||||
- qcom,sm8450-mpss-pas
|
||||
then:
|
||||
properties:
|
||||
power-domains:
|
||||
|
@ -458,6 +471,8 @@ allOf:
|
|||
- qcom,sm8250-slpi-pas
|
||||
- qcom,sm8350-adsp-pas
|
||||
- qcom,sm8350-slpi-pas
|
||||
- qcom,sm8450-adsp-pas
|
||||
- qcom,sm8450-slpi-pas
|
||||
then:
|
||||
properties:
|
||||
power-domains:
|
||||
|
@ -475,6 +490,7 @@ allOf:
|
|||
contains:
|
||||
enum:
|
||||
- qcom,sm8350-cdsp-pas
|
||||
- qcom,sm8450-cdsp-pas
|
||||
then:
|
||||
properties:
|
||||
power-domains:
|
||||
|
|
|
@ -27,6 +27,7 @@ Required properties in pwrap device node.
|
|||
"mediatek,mt8135-pwrap" for MT8135 SoCs
|
||||
"mediatek,mt8173-pwrap" for MT8173 SoCs
|
||||
"mediatek,mt8183-pwrap" for MT8183 SoCs
|
||||
"mediatek,mt8186-pwrap" for MT8186 SoCs
|
||||
"mediatek,mt8195-pwrap" for MT8195 SoCs
|
||||
"mediatek,mt8516-pwrap" for MT8516 SoCs
|
||||
- interrupts: IRQ for pwrap in SOC
|
||||
|
|
|
@ -357,8 +357,7 @@ static void __init qcom_smp_prepare_cpus(unsigned int max_cpus)
|
|||
{
|
||||
int cpu;
|
||||
|
||||
if (qcom_scm_set_cold_boot_addr(secondary_startup_arm,
|
||||
cpu_present_mask)) {
|
||||
if (qcom_scm_set_cold_boot_addr(secondary_startup_arm)) {
|
||||
for_each_present_cpu(cpu) {
|
||||
if (cpu == smp_processor_id())
|
||||
continue;
|
||||
|
|
|
@ -29,7 +29,7 @@ void __init spear13xx_l2x0_init(void)
|
|||
/*
|
||||
* 512KB (64KB/way), 8-way associativity, parity supported
|
||||
*
|
||||
* FIXME: 9th bit, of Auxillary Controller register must be set
|
||||
* FIXME: 9th bit, of Auxiliary Controller register must be set
|
||||
* for some spear13xx devices for stable L2 operation.
|
||||
*
|
||||
* Enable Early BRESP, L2 prefetch for Instruction and Data,
|
||||
|
|
|
@ -64,6 +64,11 @@ struct cs_timing_state {
|
|||
struct cs_timing cs[MAX_CS_COUNT];
|
||||
};
|
||||
|
||||
struct weim_priv {
|
||||
void __iomem *base;
|
||||
struct cs_timing_state timing_state;
|
||||
};
|
||||
|
||||
static const struct of_device_id weim_id_table[] = {
|
||||
/* i.MX1/21 */
|
||||
{ .compatible = "fsl,imx1-weim", .data = &imx1_weim_devtype, },
|
||||
|
@ -128,21 +133,26 @@ err:
|
|||
}
|
||||
|
||||
/* Parse and set the timing for this device. */
|
||||
static int weim_timing_setup(struct device *dev,
|
||||
struct device_node *np, void __iomem *base,
|
||||
const struct imx_weim_devtype *devtype,
|
||||
struct cs_timing_state *ts)
|
||||
static int weim_timing_setup(struct device *dev, struct device_node *np,
|
||||
const struct imx_weim_devtype *devtype)
|
||||
{
|
||||
u32 cs_idx, value[MAX_CS_REGS_COUNT];
|
||||
int i, ret;
|
||||
int reg_idx, num_regs;
|
||||
struct cs_timing *cst;
|
||||
struct weim_priv *priv;
|
||||
struct cs_timing_state *ts;
|
||||
void __iomem *base;
|
||||
|
||||
if (WARN_ON(devtype->cs_regs_count > MAX_CS_REGS_COUNT))
|
||||
return -EINVAL;
|
||||
if (WARN_ON(devtype->cs_count > MAX_CS_COUNT))
|
||||
return -EINVAL;
|
||||
|
||||
priv = dev_get_drvdata(dev);
|
||||
base = priv->base;
|
||||
ts = &priv->timing_state;
|
||||
|
||||
ret = of_property_read_u32_array(np, "fsl,weim-cs-timing",
|
||||
value, devtype->cs_regs_count);
|
||||
if (ret)
|
||||
|
@ -189,14 +199,15 @@ static int weim_timing_setup(struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int weim_parse_dt(struct platform_device *pdev, void __iomem *base)
|
||||
static int weim_parse_dt(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id = of_match_device(weim_id_table,
|
||||
&pdev->dev);
|
||||
const struct imx_weim_devtype *devtype = of_id->data;
|
||||
struct device_node *child;
|
||||
int ret, have_child = 0;
|
||||
struct cs_timing_state ts = {};
|
||||
struct weim_priv *priv;
|
||||
void __iomem *base;
|
||||
u32 reg;
|
||||
|
||||
if (devtype == &imx50_weim_devtype) {
|
||||
|
@ -205,6 +216,9 @@ static int weim_parse_dt(struct platform_device *pdev, void __iomem *base)
|
|||
return ret;
|
||||
}
|
||||
|
||||
priv = dev_get_drvdata(&pdev->dev);
|
||||
base = priv->base;
|
||||
|
||||
if (of_property_read_bool(pdev->dev.of_node, "fsl,burst-clk-enable")) {
|
||||
if (devtype->wcr_bcm) {
|
||||
reg = readl(base + devtype->wcr_offset);
|
||||
|
@ -229,7 +243,7 @@ static int weim_parse_dt(struct platform_device *pdev, void __iomem *base)
|
|||
}
|
||||
|
||||
for_each_available_child_of_node(pdev->dev.of_node, child) {
|
||||
ret = weim_timing_setup(&pdev->dev, child, base, devtype, &ts);
|
||||
ret = weim_timing_setup(&pdev->dev, child, devtype);
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "%pOF set timing failed.\n",
|
||||
child);
|
||||
|
@ -248,17 +262,25 @@ static int weim_parse_dt(struct platform_device *pdev, void __iomem *base)
|
|||
|
||||
static int weim_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct weim_priv *priv;
|
||||
struct resource *res;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
/* get the resource */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
priv->base = base;
|
||||
dev_set_drvdata(&pdev->dev, priv);
|
||||
|
||||
/* get the clock */
|
||||
clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(clk))
|
||||
|
@ -269,7 +291,7 @@ static int weim_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
|
||||
/* parse the device node */
|
||||
ret = weim_parse_dt(pdev, base);
|
||||
ret = weim_parse_dt(pdev);
|
||||
if (ret)
|
||||
clk_disable_unprepare(clk);
|
||||
else
|
||||
|
@ -278,6 +300,81 @@ static int weim_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF_DYNAMIC)
|
||||
static int of_weim_notify(struct notifier_block *nb, unsigned long action,
|
||||
void *arg)
|
||||
{
|
||||
const struct imx_weim_devtype *devtype;
|
||||
struct of_reconfig_data *rd = arg;
|
||||
const struct of_device_id *of_id;
|
||||
struct platform_device *pdev;
|
||||
int ret = NOTIFY_OK;
|
||||
|
||||
switch (of_reconfig_get_state_change(action, rd)) {
|
||||
case OF_RECONFIG_CHANGE_ADD:
|
||||
of_id = of_match_node(weim_id_table, rd->dn->parent);
|
||||
if (!of_id)
|
||||
return NOTIFY_OK; /* not for us */
|
||||
|
||||
devtype = of_id->data;
|
||||
|
||||
pdev = of_find_device_by_node(rd->dn->parent);
|
||||
if (!pdev) {
|
||||
pr_err("%s: could not find platform device for '%pOF'\n",
|
||||
__func__, rd->dn->parent);
|
||||
|
||||
return notifier_from_errno(-EINVAL);
|
||||
}
|
||||
|
||||
if (weim_timing_setup(&pdev->dev, rd->dn, devtype))
|
||||
dev_warn(&pdev->dev,
|
||||
"Failed to setup timing for '%pOF'\n", rd->dn);
|
||||
|
||||
if (!of_node_check_flag(rd->dn, OF_POPULATED)) {
|
||||
if (!of_platform_device_create(rd->dn, NULL, &pdev->dev)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to create child device '%pOF'\n",
|
||||
rd->dn);
|
||||
ret = notifier_from_errno(-EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
platform_device_put(pdev);
|
||||
|
||||
break;
|
||||
case OF_RECONFIG_CHANGE_REMOVE:
|
||||
if (!of_node_check_flag(rd->dn, OF_POPULATED))
|
||||
return NOTIFY_OK; /* device already destroyed */
|
||||
|
||||
of_id = of_match_node(weim_id_table, rd->dn->parent);
|
||||
if (!of_id)
|
||||
return NOTIFY_OK; /* not for us */
|
||||
|
||||
pdev = of_find_device_by_node(rd->dn);
|
||||
if (!pdev) {
|
||||
dev_err(&pdev->dev,
|
||||
"Could not find platform device for '%pOF'\n",
|
||||
rd->dn);
|
||||
|
||||
ret = notifier_from_errno(-EINVAL);
|
||||
} else {
|
||||
of_platform_device_destroy(&pdev->dev, NULL);
|
||||
platform_device_put(pdev);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct notifier_block weim_of_notifier = {
|
||||
.notifier_call = of_weim_notify,
|
||||
};
|
||||
#endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */
|
||||
|
||||
static struct platform_driver weim_driver = {
|
||||
.driver = {
|
||||
.name = "imx-weim",
|
||||
|
@ -285,7 +382,27 @@ static struct platform_driver weim_driver = {
|
|||
},
|
||||
.probe = weim_probe,
|
||||
};
|
||||
module_platform_driver(weim_driver);
|
||||
|
||||
static int __init weim_init(void)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_OF_DYNAMIC)
|
||||
WARN_ON(of_reconfig_notifier_register(&weim_of_notifier));
|
||||
#endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */
|
||||
|
||||
return platform_driver_register(&weim_driver);
|
||||
}
|
||||
module_init(weim_init);
|
||||
|
||||
static void __exit weim_exit(void)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_OF_DYNAMIC)
|
||||
of_reconfig_notifier_unregister(&weim_of_notifier);
|
||||
#endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */
|
||||
|
||||
return platform_driver_unregister(&weim_driver);
|
||||
|
||||
}
|
||||
module_exit(weim_exit);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor Inc.");
|
||||
MODULE_DESCRIPTION("i.MX EIM Controller Driver");
|
||||
|
|
|
@ -145,10 +145,10 @@ static int optee_rng_init(struct hwrng *rng)
|
|||
struct optee_rng_private *pvt_data = to_optee_rng_private(rng);
|
||||
struct tee_shm *entropy_shm_pool = NULL;
|
||||
|
||||
entropy_shm_pool = tee_shm_alloc(pvt_data->ctx, MAX_ENTROPY_REQ_SZ,
|
||||
TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
|
||||
entropy_shm_pool = tee_shm_alloc_kernel_buf(pvt_data->ctx,
|
||||
MAX_ENTROPY_REQ_SZ);
|
||||
if (IS_ERR(entropy_shm_pool)) {
|
||||
dev_err(pvt_data->dev, "tee_shm_alloc failed\n");
|
||||
dev_err(pvt_data->dev, "tee_shm_alloc_kernel_buf failed\n");
|
||||
return PTR_ERR(entropy_shm_pool);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* System Control and Power Interface (SCMI) Protocol based clock driver
|
||||
*
|
||||
* Copyright (C) 2018-2021 ARM Ltd.
|
||||
* Copyright (C) 2018-2022 ARM Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
|
@ -88,21 +88,51 @@ static void scmi_clk_disable(struct clk_hw *hw)
|
|||
scmi_proto_clk_ops->disable(clk->ph, clk->id);
|
||||
}
|
||||
|
||||
static int scmi_clk_atomic_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct scmi_clk *clk = to_scmi_clk(hw);
|
||||
|
||||
return scmi_proto_clk_ops->enable_atomic(clk->ph, clk->id);
|
||||
}
|
||||
|
||||
static void scmi_clk_atomic_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct scmi_clk *clk = to_scmi_clk(hw);
|
||||
|
||||
scmi_proto_clk_ops->disable_atomic(clk->ph, clk->id);
|
||||
}
|
||||
|
||||
/*
|
||||
* We can provide enable/disable atomic callbacks only if the underlying SCMI
|
||||
* transport for an SCMI instance is configured to handle SCMI commands in an
|
||||
* atomic manner.
|
||||
*
|
||||
* When no SCMI atomic transport support is available we instead provide only
|
||||
* the prepare/unprepare API, as allowed by the clock framework when atomic
|
||||
* calls are not available.
|
||||
*
|
||||
* Two distinct sets of clk_ops are provided since we could have multiple SCMI
|
||||
* instances with different underlying transport quality, so they cannot be
|
||||
* shared.
|
||||
*/
|
||||
static const struct clk_ops scmi_clk_ops = {
|
||||
.recalc_rate = scmi_clk_recalc_rate,
|
||||
.round_rate = scmi_clk_round_rate,
|
||||
.set_rate = scmi_clk_set_rate,
|
||||
/*
|
||||
* We can't provide enable/disable callback as we can't perform the same
|
||||
* in atomic context. Since the clock framework provides standard API
|
||||
* clk_prepare_enable that helps cases using clk_enable in non-atomic
|
||||
* context, it should be fine providing prepare/unprepare.
|
||||
*/
|
||||
.prepare = scmi_clk_enable,
|
||||
.unprepare = scmi_clk_disable,
|
||||
};
|
||||
|
||||
static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk)
|
||||
static const struct clk_ops scmi_atomic_clk_ops = {
|
||||
.recalc_rate = scmi_clk_recalc_rate,
|
||||
.round_rate = scmi_clk_round_rate,
|
||||
.set_rate = scmi_clk_set_rate,
|
||||
.enable = scmi_clk_atomic_enable,
|
||||
.disable = scmi_clk_atomic_disable,
|
||||
};
|
||||
|
||||
static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk,
|
||||
const struct clk_ops *scmi_ops)
|
||||
{
|
||||
int ret;
|
||||
unsigned long min_rate, max_rate;
|
||||
|
@ -110,7 +140,7 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk)
|
|||
struct clk_init_data init = {
|
||||
.flags = CLK_GET_RATE_NOCACHE,
|
||||
.num_parents = 0,
|
||||
.ops = &scmi_clk_ops,
|
||||
.ops = scmi_ops,
|
||||
.name = sclk->info->name,
|
||||
};
|
||||
|
||||
|
@ -139,6 +169,8 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk)
|
|||
static int scmi_clocks_probe(struct scmi_device *sdev)
|
||||
{
|
||||
int idx, count, err;
|
||||
unsigned int atomic_threshold;
|
||||
bool is_atomic;
|
||||
struct clk_hw **hws;
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
struct device *dev = &sdev->dev;
|
||||
|
@ -168,8 +200,11 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
|
|||
clk_data->num = count;
|
||||
hws = clk_data->hws;
|
||||
|
||||
is_atomic = handle->is_transport_atomic(handle, &atomic_threshold);
|
||||
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
struct scmi_clk *sclk;
|
||||
const struct clk_ops *scmi_ops;
|
||||
|
||||
sclk = devm_kzalloc(dev, sizeof(*sclk), GFP_KERNEL);
|
||||
if (!sclk)
|
||||
|
@ -184,13 +219,27 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
|
|||
sclk->id = idx;
|
||||
sclk->ph = ph;
|
||||
|
||||
err = scmi_clk_ops_init(dev, sclk);
|
||||
/*
|
||||
* Note that when transport is atomic but SCMI protocol did not
|
||||
* specify (or support) an enable_latency associated with a
|
||||
* clock, we default to use atomic operations mode.
|
||||
*/
|
||||
if (is_atomic &&
|
||||
sclk->info->enable_latency <= atomic_threshold)
|
||||
scmi_ops = &scmi_atomic_clk_ops;
|
||||
else
|
||||
scmi_ops = &scmi_clk_ops;
|
||||
|
||||
err = scmi_clk_ops_init(dev, sclk, scmi_ops);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to register clock %d\n", idx);
|
||||
devm_kfree(dev, sclk);
|
||||
hws[idx] = NULL;
|
||||
} else {
|
||||
dev_dbg(dev, "Registered clock:%s\n", sclk->info->name);
|
||||
dev_dbg(dev, "Registered clock:%s%s\n",
|
||||
sclk->info->name,
|
||||
scmi_ops == &scmi_atomic_clk_ops ?
|
||||
" (atomic ops)" : "");
|
||||
hws[idx] = &sclk->hw;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ config COMMON_CLK_SAMSUNG
|
|||
select EXYNOS_5410_COMMON_CLK if ARM && SOC_EXYNOS5410
|
||||
select EXYNOS_5420_COMMON_CLK if ARM && SOC_EXYNOS5420
|
||||
select EXYNOS_ARM64_COMMON_CLK if ARM64 && ARCH_EXYNOS
|
||||
select TESLA_FSD_COMMON_CLK if ARM64 && ARCH_TESLA_FSD
|
||||
|
||||
config S3C64XX_COMMON_CLK
|
||||
bool "Samsung S3C64xx clock controller support" if COMPILE_TEST
|
||||
|
@ -124,3 +125,11 @@ config S3C2443_COMMON_CLK
|
|||
help
|
||||
Support for the clock controller present on the Samsung
|
||||
S3C2416/S3C2443 SoCs. Choose Y here only if you build for this SoC.
|
||||
|
||||
config TESLA_FSD_COMMON_CLK
|
||||
bool "Tesla FSD clock controller support" if COMPILE_TEST
|
||||
depends on COMMON_CLK_SAMSUNG
|
||||
depends on EXYNOS_ARM64_COMMON_CLK
|
||||
help
|
||||
Support for the clock controller present on the Tesla FSD SoC.
|
||||
Choose Y here only if you build for this SoC.
|
||||
|
|
|
@ -26,3 +26,4 @@ obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o
|
|||
obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o
|
||||
obj-$(CONFIG_S3C64XX_COMMON_CLK) += clk-s3c64xx.o
|
||||
obj-$(CONFIG_S5PV210_COMMON_CLK) += clk-s5pv210.o clk-s5pv210-audss.o
|
||||
obj-$(CONFIG_TESLA_FSD_COMMON_CLK) += clk-fsd.o
|
||||
|
|
1803
drivers/clk/samsung/clk-fsd.c
Normal file
1803
drivers/clk/samsung/clk-fsd.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1469,6 +1469,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
|
|||
case pll_1450x:
|
||||
case pll_1451x:
|
||||
case pll_1452x:
|
||||
case pll_142xx:
|
||||
pll->enable_offs = PLL35XX_ENABLE_SHIFT;
|
||||
pll->lock_offs = PLL35XX_LOCK_STAT_SHIFT;
|
||||
if (!pll->rate_table)
|
||||
|
|
|
@ -39,6 +39,7 @@ enum samsung_pll_type {
|
|||
pll_1460x,
|
||||
pll_0822x,
|
||||
pll_0831x,
|
||||
pll_142xx,
|
||||
};
|
||||
|
||||
#define PLL_RATE(_fin, _m, _p, _s, _k, _ks) \
|
||||
|
|
|
@ -122,10 +122,6 @@ static int spm_cpuidle_register(struct device *cpuidle_dev, int cpu)
|
|||
if (ret <= 0)
|
||||
return ret ? : -ENODEV;
|
||||
|
||||
ret = qcom_scm_set_warm_boot_addr(cpu_resume_arm, cpumask_of(cpu));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return cpuidle_register(&data->cpuidle_driver, NULL);
|
||||
}
|
||||
|
||||
|
@ -136,6 +132,10 @@ static int spm_cpuidle_drv_probe(struct platform_device *pdev)
|
|||
if (!qcom_scm_is_available())
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
ret = qcom_scm_set_warm_boot_addr(cpu_resume_arm);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "set warm boot addr failed");
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
ret = spm_cpuidle_register(&pdev->dev, cpu);
|
||||
if (ret && ret != -ENODEV) {
|
||||
|
@ -155,6 +155,22 @@ static struct platform_driver spm_cpuidle_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static bool __init qcom_spm_find_any_cpu(void)
|
||||
{
|
||||
struct device_node *cpu_node, *saw_node;
|
||||
|
||||
for_each_of_cpu_node(cpu_node) {
|
||||
saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0);
|
||||
if (of_device_is_available(saw_node)) {
|
||||
of_node_put(saw_node);
|
||||
of_node_put(cpu_node);
|
||||
return true;
|
||||
}
|
||||
of_node_put(saw_node);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __init qcom_spm_cpuidle_init(void)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
|
@ -164,6 +180,10 @@ static int __init qcom_spm_cpuidle_init(void)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Make sure there is actually any CPU managed by the SPM */
|
||||
if (!qcom_spm_find_any_cpu())
|
||||
return 0;
|
||||
|
||||
pdev = platform_device_register_simple("qcom-spm-cpuidle",
|
||||
-1, NULL, 0);
|
||||
if (IS_ERR(pdev)) {
|
||||
|
|
|
@ -54,6 +54,18 @@ config ARM_SCMI_TRANSPORT_MAILBOX
|
|||
If you want the ARM SCMI PROTOCOL stack to include support for a
|
||||
transport based on mailboxes, answer Y.
|
||||
|
||||
config ARM_SCMI_TRANSPORT_OPTEE
|
||||
bool "SCMI transport based on OP-TEE service"
|
||||
depends on OPTEE=y || OPTEE=ARM_SCMI_PROTOCOL
|
||||
select ARM_SCMI_HAVE_TRANSPORT
|
||||
select ARM_SCMI_HAVE_SHMEM
|
||||
default y
|
||||
help
|
||||
This enables the OP-TEE service based transport for SCMI.
|
||||
|
||||
If you want the ARM SCMI PROTOCOL stack to include support for a
|
||||
transport based on OP-TEE SCMI service, answer Y.
|
||||
|
||||
config ARM_SCMI_TRANSPORT_SMC
|
||||
bool "SCMI transport based on SMC"
|
||||
depends on HAVE_ARM_SMCCC_DISCOVERY
|
||||
|
@ -66,6 +78,20 @@ config ARM_SCMI_TRANSPORT_SMC
|
|||
If you want the ARM SCMI PROTOCOL stack to include support for a
|
||||
transport based on SMC, answer Y.
|
||||
|
||||
config ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE
|
||||
bool "Enable atomic mode support for SCMI SMC transport"
|
||||
depends on ARM_SCMI_TRANSPORT_SMC
|
||||
help
|
||||
Enable support of atomic operation for SCMI SMC based transport.
|
||||
|
||||
If you want the SCMI SMC based transport to operate in atomic
|
||||
mode, avoiding any kind of sleeping behaviour for selected
|
||||
transactions on the TX path, answer Y.
|
||||
Enabling atomic mode operations allows any SCMI driver using this
|
||||
transport to optionally ask for atomic SCMI transactions and operate
|
||||
in atomic context too, at the price of using a number of busy-waiting
|
||||
primitives all over instead. If unsure say N.
|
||||
|
||||
config ARM_SCMI_TRANSPORT_VIRTIO
|
||||
bool "SCMI transport based on VirtIO"
|
||||
depends on VIRTIO=y || VIRTIO=ARM_SCMI_PROTOCOL
|
||||
|
@ -77,6 +103,36 @@ config ARM_SCMI_TRANSPORT_VIRTIO
|
|||
If you want the ARM SCMI PROTOCOL stack to include support for a
|
||||
transport based on VirtIO, answer Y.
|
||||
|
||||
config ARM_SCMI_TRANSPORT_VIRTIO_VERSION1_COMPLIANCE
|
||||
bool "SCMI VirtIO transport Version 1 compliance"
|
||||
depends on ARM_SCMI_TRANSPORT_VIRTIO
|
||||
default y
|
||||
help
|
||||
This enforces strict compliance with VirtIO Version 1 specification.
|
||||
|
||||
If you want the ARM SCMI VirtIO transport layer to refuse to work
|
||||
with Legacy VirtIO backends and instead support only VirtIO Version 1
|
||||
devices (or above), answer Y.
|
||||
|
||||
If you want instead to support also old Legacy VirtIO backends (like
|
||||
the ones implemented by kvmtool) and let the core Kernel VirtIO layer
|
||||
take care of the needed conversions, say N.
|
||||
|
||||
config ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE
|
||||
bool "Enable atomic mode for SCMI VirtIO transport"
|
||||
depends on ARM_SCMI_TRANSPORT_VIRTIO
|
||||
help
|
||||
Enable support of atomic operation for SCMI VirtIO based transport.
|
||||
|
||||
If you want the SCMI VirtIO based transport to operate in atomic
|
||||
mode, avoiding any kind of sleeping behaviour for selected
|
||||
transactions on the TX path, answer Y.
|
||||
|
||||
Enabling atomic mode operations allows any SCMI driver using this
|
||||
transport to optionally ask for atomic SCMI transactions and operate
|
||||
in atomic context too, at the price of using a number of busy-waiting
|
||||
primitives all over instead. If unsure say N.
|
||||
|
||||
endif #ARM_SCMI_PROTOCOL
|
||||
|
||||
config ARM_SCMI_POWER_DOMAIN
|
||||
|
|
|
@ -6,8 +6,16 @@ scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) += mailbox.o
|
|||
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += smc.o
|
||||
scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.o
|
||||
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += virtio.o
|
||||
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += optee.o
|
||||
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o
|
||||
scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \
|
||||
$(scmi-transport-y)
|
||||
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o
|
||||
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
|
||||
|
||||
ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy)
|
||||
# The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame
|
||||
# pointer in Thumb2 mode, which is forcibly enabled by Clang when profiling
|
||||
# hooks are inserted via the -pg switch.
|
||||
CFLAGS_REMOVE_smc.o += $(CC_FLAGS_FTRACE)
|
||||
endif
|
||||
|
|
|
@ -27,7 +27,8 @@ struct scmi_msg_resp_clock_protocol_attributes {
|
|||
struct scmi_msg_resp_clock_attributes {
|
||||
__le32 attributes;
|
||||
#define CLOCK_ENABLE BIT(0)
|
||||
u8 name[SCMI_MAX_STR_SIZE];
|
||||
u8 name[SCMI_MAX_STR_SIZE];
|
||||
__le32 clock_enable_latency;
|
||||
};
|
||||
|
||||
struct scmi_clock_set_config {
|
||||
|
@ -116,10 +117,15 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
|
|||
attr = t->rx.buf;
|
||||
|
||||
ret = ph->xops->do_xfer(ph, t);
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
strlcpy(clk->name, attr->name, SCMI_MAX_STR_SIZE);
|
||||
else
|
||||
/* Is optional field clock_enable_latency provided ? */
|
||||
if (t->rx.len == sizeof(*attr))
|
||||
clk->enable_latency =
|
||||
le32_to_cpu(attr->clock_enable_latency);
|
||||
} else {
|
||||
clk->name[0] = '\0';
|
||||
}
|
||||
|
||||
ph->xops->xfer_put(ph, t);
|
||||
return ret;
|
||||
|
@ -273,7 +279,7 @@ static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph,
|
|||
|
||||
static int
|
||||
scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id,
|
||||
u32 config)
|
||||
u32 config, bool atomic)
|
||||
{
|
||||
int ret;
|
||||
struct scmi_xfer *t;
|
||||
|
@ -284,6 +290,8 @@ scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
t->hdr.poll_completion = atomic;
|
||||
|
||||
cfg = t->tx.buf;
|
||||
cfg->id = cpu_to_le32(clk_id);
|
||||
cfg->attributes = cpu_to_le32(config);
|
||||
|
@ -296,12 +304,24 @@ scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id,
|
|||
|
||||
static int scmi_clock_enable(const struct scmi_protocol_handle *ph, u32 clk_id)
|
||||
{
|
||||
return scmi_clock_config_set(ph, clk_id, CLOCK_ENABLE);
|
||||
return scmi_clock_config_set(ph, clk_id, CLOCK_ENABLE, false);
|
||||
}
|
||||
|
||||
static int scmi_clock_disable(const struct scmi_protocol_handle *ph, u32 clk_id)
|
||||
{
|
||||
return scmi_clock_config_set(ph, clk_id, 0);
|
||||
return scmi_clock_config_set(ph, clk_id, 0, false);
|
||||
}
|
||||
|
||||
static int scmi_clock_enable_atomic(const struct scmi_protocol_handle *ph,
|
||||
u32 clk_id)
|
||||
{
|
||||
return scmi_clock_config_set(ph, clk_id, CLOCK_ENABLE, true);
|
||||
}
|
||||
|
||||
static int scmi_clock_disable_atomic(const struct scmi_protocol_handle *ph,
|
||||
u32 clk_id)
|
||||
{
|
||||
return scmi_clock_config_set(ph, clk_id, 0, true);
|
||||
}
|
||||
|
||||
static int scmi_clock_count_get(const struct scmi_protocol_handle *ph)
|
||||
|
@ -330,6 +350,8 @@ static const struct scmi_clk_proto_ops clk_proto_ops = {
|
|||
.rate_set = scmi_clock_rate_set,
|
||||
.enable = scmi_clock_enable,
|
||||
.disable = scmi_clock_disable,
|
||||
.enable_atomic = scmi_clock_enable_atomic,
|
||||
.disable_atomic = scmi_clock_disable_atomic,
|
||||
};
|
||||
|
||||
static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
|
||||
|
|
|
@ -339,11 +339,16 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
|
|||
* @dev: Reference to device in the SCMI hierarchy corresponding to this
|
||||
* channel
|
||||
* @handle: Pointer to SCMI entity handle
|
||||
* @no_completion_irq: Flag to indicate that this channel has no completion
|
||||
* interrupt mechanism for synchronous commands.
|
||||
* This can be dynamically set by transports at run-time
|
||||
* inside their provided .chan_setup().
|
||||
* @transport_info: Transport layer related information
|
||||
*/
|
||||
struct scmi_chan_info {
|
||||
struct device *dev;
|
||||
struct scmi_handle *handle;
|
||||
bool no_completion_irq;
|
||||
void *transport_info;
|
||||
};
|
||||
|
||||
|
@ -373,7 +378,8 @@ struct scmi_transport_ops {
|
|||
unsigned int (*get_max_msg)(struct scmi_chan_info *base_cinfo);
|
||||
int (*send_message)(struct scmi_chan_info *cinfo,
|
||||
struct scmi_xfer *xfer);
|
||||
void (*mark_txdone)(struct scmi_chan_info *cinfo, int ret);
|
||||
void (*mark_txdone)(struct scmi_chan_info *cinfo, int ret,
|
||||
struct scmi_xfer *xfer);
|
||||
void (*fetch_response)(struct scmi_chan_info *cinfo,
|
||||
struct scmi_xfer *xfer);
|
||||
void (*fetch_notification)(struct scmi_chan_info *cinfo,
|
||||
|
@ -402,6 +408,18 @@ struct scmi_device *scmi_child_dev_find(struct device *parent,
|
|||
* be pending simultaneously in the system. May be overridden by the
|
||||
* get_max_msg op.
|
||||
* @max_msg_size: Maximum size of data per message that can be handled.
|
||||
* @force_polling: Flag to force this whole transport to use SCMI core polling
|
||||
* mechanism instead of completion interrupts even if available.
|
||||
* @sync_cmds_completed_on_ret: Flag to indicate that the transport assures
|
||||
* synchronous-command messages are atomically
|
||||
* completed on .send_message: no need to poll
|
||||
* actively waiting for a response.
|
||||
* Used by core internally only when polling is
|
||||
* selected as a waiting for reply method: i.e.
|
||||
* if a completion irq was found use that anyway.
|
||||
* @atomic_enabled: Flag to indicate that this transport, which is assured not
|
||||
* to sleep anywhere on the TX path, can be used in atomic mode
|
||||
* when requested.
|
||||
*/
|
||||
struct scmi_desc {
|
||||
int (*transport_init)(void);
|
||||
|
@ -410,6 +428,9 @@ struct scmi_desc {
|
|||
int max_rx_timeout_ms;
|
||||
int max_msg;
|
||||
int max_msg_size;
|
||||
const bool force_polling;
|
||||
const bool sync_cmds_completed_on_ret;
|
||||
const bool atomic_enabled;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARM_SCMI_TRANSPORT_MAILBOX
|
||||
|
@ -421,6 +442,9 @@ extern const struct scmi_desc scmi_smc_desc;
|
|||
#ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
|
||||
extern const struct scmi_desc scmi_virtio_desc;
|
||||
#endif
|
||||
#ifdef CONFIG_ARM_SCMI_TRANSPORT_OPTEE
|
||||
extern const struct scmi_desc scmi_optee_desc;
|
||||
#endif
|
||||
|
||||
void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv);
|
||||
void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id);
|
||||
|
|
|
@ -131,6 +131,12 @@ struct scmi_protocol_instance {
|
|||
* MAX_PROTOCOLS_IMP elements allocated by the base protocol
|
||||
* @active_protocols: IDR storing device_nodes for protocols actually defined
|
||||
* in the DT and confirmed as implemented by fw.
|
||||
* @atomic_threshold: Optional system wide DT-configured threshold, expressed
|
||||
* in microseconds, for atomic operations.
|
||||
* Only SCMI synchronous commands reported by the platform
|
||||
* to have an execution latency lesser-equal to the threshold
|
||||
* should be considered for atomic mode operation: such
|
||||
* decision is finally left up to the SCMI drivers.
|
||||
* @notify_priv: Pointer to private data structure specific to notifications.
|
||||
* @node: List head
|
||||
* @users: Number of users of this instance
|
||||
|
@ -149,6 +155,7 @@ struct scmi_info {
|
|||
struct mutex protocols_mtx;
|
||||
u8 *protocols_imp;
|
||||
struct idr active_protocols;
|
||||
unsigned int atomic_threshold;
|
||||
void *notify_priv;
|
||||
struct list_head node;
|
||||
int users;
|
||||
|
@ -609,6 +616,25 @@ static inline void scmi_clear_channel(struct scmi_info *info,
|
|||
info->desc->ops->clear_channel(cinfo);
|
||||
}
|
||||
|
||||
static inline bool is_polling_required(struct scmi_chan_info *cinfo,
|
||||
struct scmi_info *info)
|
||||
{
|
||||
return cinfo->no_completion_irq || info->desc->force_polling;
|
||||
}
|
||||
|
||||
static inline bool is_transport_polling_capable(struct scmi_info *info)
|
||||
{
|
||||
return info->desc->ops->poll_done ||
|
||||
info->desc->sync_cmds_completed_on_ret;
|
||||
}
|
||||
|
||||
static inline bool is_polling_enabled(struct scmi_chan_info *cinfo,
|
||||
struct scmi_info *info)
|
||||
{
|
||||
return is_polling_required(cinfo, info) &&
|
||||
is_transport_polling_capable(info);
|
||||
}
|
||||
|
||||
static void scmi_handle_notification(struct scmi_chan_info *cinfo,
|
||||
u32 msg_hdr, void *priv)
|
||||
{
|
||||
|
@ -629,7 +655,8 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo,
|
|||
|
||||
unpack_scmi_header(msg_hdr, &xfer->hdr);
|
||||
if (priv)
|
||||
xfer->priv = priv;
|
||||
/* Ensure order between xfer->priv store and following ops */
|
||||
smp_store_mb(xfer->priv, priv);
|
||||
info->desc->ops->fetch_notification(cinfo, info->desc->max_msg_size,
|
||||
xfer);
|
||||
scmi_notify(cinfo->handle, xfer->hdr.protocol_id,
|
||||
|
@ -661,7 +688,8 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo,
|
|||
xfer->rx.len = info->desc->max_msg_size;
|
||||
|
||||
if (priv)
|
||||
xfer->priv = priv;
|
||||
/* Ensure order between xfer->priv store and following ops */
|
||||
smp_store_mb(xfer->priv, priv);
|
||||
info->desc->ops->fetch_response(cinfo, xfer);
|
||||
|
||||
trace_scmi_rx_done(xfer->transfer_id, xfer->hdr.id,
|
||||
|
@ -724,8 +752,6 @@ static void xfer_put(const struct scmi_protocol_handle *ph,
|
|||
__scmi_xfer_put(&info->tx_minfo, xfer);
|
||||
}
|
||||
|
||||
#define SCMI_MAX_POLL_TO_NS (100 * NSEC_PER_USEC)
|
||||
|
||||
static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo,
|
||||
struct scmi_xfer *xfer, ktime_t stop)
|
||||
{
|
||||
|
@ -740,6 +766,79 @@ static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo,
|
|||
ktime_after(ktime_get(), stop);
|
||||
}
|
||||
|
||||
/**
|
||||
* scmi_wait_for_message_response - An helper to group all the possible ways of
|
||||
* waiting for a synchronous message response.
|
||||
*
|
||||
* @cinfo: SCMI channel info
|
||||
* @xfer: Reference to the transfer being waited for.
|
||||
*
|
||||
* Chooses waiting strategy (sleep-waiting vs busy-waiting) depending on
|
||||
* configuration flags like xfer->hdr.poll_completion.
|
||||
*
|
||||
* Return: 0 on Success, error otherwise.
|
||||
*/
|
||||
static int scmi_wait_for_message_response(struct scmi_chan_info *cinfo,
|
||||
struct scmi_xfer *xfer)
|
||||
{
|
||||
struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
|
||||
struct device *dev = info->dev;
|
||||
int ret = 0, timeout_ms = info->desc->max_rx_timeout_ms;
|
||||
|
||||
trace_scmi_xfer_response_wait(xfer->transfer_id, xfer->hdr.id,
|
||||
xfer->hdr.protocol_id, xfer->hdr.seq,
|
||||
timeout_ms,
|
||||
xfer->hdr.poll_completion);
|
||||
|
||||
if (xfer->hdr.poll_completion) {
|
||||
/*
|
||||
* Real polling is needed only if transport has NOT declared
|
||||
* itself to support synchronous commands replies.
|
||||
*/
|
||||
if (!info->desc->sync_cmds_completed_on_ret) {
|
||||
/*
|
||||
* Poll on xfer using transport provided .poll_done();
|
||||
* assumes no completion interrupt was available.
|
||||
*/
|
||||
ktime_t stop = ktime_add_ms(ktime_get(), timeout_ms);
|
||||
|
||||
spin_until_cond(scmi_xfer_done_no_timeout(cinfo,
|
||||
xfer, stop));
|
||||
if (ktime_after(ktime_get(), stop)) {
|
||||
dev_err(dev,
|
||||
"timed out in resp(caller: %pS) - polling\n",
|
||||
(void *)_RET_IP_);
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Do not fetch_response if an out-of-order delayed
|
||||
* response is being processed.
|
||||
*/
|
||||
spin_lock_irqsave(&xfer->lock, flags);
|
||||
if (xfer->state == SCMI_XFER_SENT_OK) {
|
||||
info->desc->ops->fetch_response(cinfo, xfer);
|
||||
xfer->state = SCMI_XFER_RESP_OK;
|
||||
}
|
||||
spin_unlock_irqrestore(&xfer->lock, flags);
|
||||
}
|
||||
} else {
|
||||
/* And we wait for the response. */
|
||||
if (!wait_for_completion_timeout(&xfer->done,
|
||||
msecs_to_jiffies(timeout_ms))) {
|
||||
dev_err(dev, "timed out in resp(caller: %pS)\n",
|
||||
(void *)_RET_IP_);
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_xfer() - Do one transfer
|
||||
*
|
||||
|
@ -754,18 +853,26 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
|
|||
struct scmi_xfer *xfer)
|
||||
{
|
||||
int ret;
|
||||
int timeout;
|
||||
const struct scmi_protocol_instance *pi = ph_to_pi(ph);
|
||||
struct scmi_info *info = handle_to_scmi_info(pi->handle);
|
||||
struct device *dev = info->dev;
|
||||
struct scmi_chan_info *cinfo;
|
||||
|
||||
if (xfer->hdr.poll_completion && !info->desc->ops->poll_done) {
|
||||
/* Check for polling request on custom command xfers at first */
|
||||
if (xfer->hdr.poll_completion && !is_transport_polling_capable(info)) {
|
||||
dev_warn_once(dev,
|
||||
"Polling mode is not supported by transport.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cinfo = idr_find(&info->tx_idr, pi->proto->id);
|
||||
if (unlikely(!cinfo))
|
||||
return -EINVAL;
|
||||
|
||||
/* True ONLY if also supported by transport. */
|
||||
if (is_polling_enabled(cinfo, info))
|
||||
xfer->hdr.poll_completion = true;
|
||||
|
||||
/*
|
||||
* Initialise protocol id now from protocol handle to avoid it being
|
||||
* overridden by mistake (or malice) by the protocol code mangling with
|
||||
|
@ -774,10 +881,6 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
|
|||
xfer->hdr.protocol_id = pi->proto->id;
|
||||
reinit_completion(&xfer->done);
|
||||
|
||||
cinfo = idr_find(&info->tx_idr, xfer->hdr.protocol_id);
|
||||
if (unlikely(!cinfo))
|
||||
return -EINVAL;
|
||||
|
||||
trace_scmi_xfer_begin(xfer->transfer_id, xfer->hdr.id,
|
||||
xfer->hdr.protocol_id, xfer->hdr.seq,
|
||||
xfer->hdr.poll_completion);
|
||||
|
@ -798,41 +901,12 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (xfer->hdr.poll_completion) {
|
||||
ktime_t stop = ktime_add_ns(ktime_get(), SCMI_MAX_POLL_TO_NS);
|
||||
|
||||
spin_until_cond(scmi_xfer_done_no_timeout(cinfo, xfer, stop));
|
||||
if (ktime_before(ktime_get(), stop)) {
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Do not fetch_response if an out-of-order delayed
|
||||
* response is being processed.
|
||||
*/
|
||||
spin_lock_irqsave(&xfer->lock, flags);
|
||||
if (xfer->state == SCMI_XFER_SENT_OK) {
|
||||
info->desc->ops->fetch_response(cinfo, xfer);
|
||||
xfer->state = SCMI_XFER_RESP_OK;
|
||||
}
|
||||
spin_unlock_irqrestore(&xfer->lock, flags);
|
||||
} else {
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
/* And we wait for the response. */
|
||||
timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms);
|
||||
if (!wait_for_completion_timeout(&xfer->done, timeout)) {
|
||||
dev_err(dev, "timed out in resp(caller: %pS)\n",
|
||||
(void *)_RET_IP_);
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
ret = scmi_wait_for_message_response(cinfo, xfer);
|
||||
if (!ret && xfer->hdr.status)
|
||||
ret = scmi_to_linux_errno(xfer->hdr.status);
|
||||
|
||||
if (info->desc->ops->mark_txdone)
|
||||
info->desc->ops->mark_txdone(cinfo, ret);
|
||||
info->desc->ops->mark_txdone(cinfo, ret, xfer);
|
||||
|
||||
trace_scmi_xfer_end(xfer->transfer_id, xfer->hdr.id,
|
||||
xfer->hdr.protocol_id, xfer->hdr.seq, ret);
|
||||
|
@ -858,6 +932,20 @@ static void reset_rx_to_maxsz(const struct scmi_protocol_handle *ph,
|
|||
* @ph: Pointer to SCMI protocol handle
|
||||
* @xfer: Transfer to initiate and wait for response
|
||||
*
|
||||
* Using asynchronous commands in atomic/polling mode should be avoided since
|
||||
* it could cause long busy-waiting here, so ignore polling for the delayed
|
||||
* response and WARN if it was requested for this command transaction since
|
||||
* upper layers should refrain from issuing such kind of requests.
|
||||
*
|
||||
* The only other option would have been to refrain from using any asynchronous
|
||||
* command even if made available, when an atomic transport is detected, and
|
||||
* instead forcibly use the synchronous version (thing that can be easily
|
||||
* attained at the protocol layer), but this would also have led to longer
|
||||
* stalls of the channel for synchronous commands and possibly timeouts.
|
||||
* (in other words there is usually a good reason if a platform provides an
|
||||
* asynchronous version of a command and we should prefer to use it...just not
|
||||
* when using atomic/polling mode)
|
||||
*
|
||||
* Return: -ETIMEDOUT in case of no delayed response, if transmit error,
|
||||
* return corresponding error, else if all goes well, return 0.
|
||||
*/
|
||||
|
@ -869,12 +957,24 @@ static int do_xfer_with_response(const struct scmi_protocol_handle *ph,
|
|||
|
||||
xfer->async_done = &async_response;
|
||||
|
||||
/*
|
||||
* Delayed responses should not be polled, so an async command should
|
||||
* not have been used when requiring an atomic/poll context; WARN and
|
||||
* perform instead a sleeping wait.
|
||||
* (Note Async + IgnoreDelayedResponses are sent via do_xfer)
|
||||
*/
|
||||
WARN_ON_ONCE(xfer->hdr.poll_completion);
|
||||
|
||||
ret = do_xfer(ph, xfer);
|
||||
if (!ret) {
|
||||
if (!wait_for_completion_timeout(xfer->async_done, timeout))
|
||||
if (!wait_for_completion_timeout(xfer->async_done, timeout)) {
|
||||
dev_err(ph->dev,
|
||||
"timed out in delayed resp(caller: %pS)\n",
|
||||
(void *)_RET_IP_);
|
||||
ret = -ETIMEDOUT;
|
||||
else if (xfer->hdr.status)
|
||||
} else if (xfer->hdr.status) {
|
||||
ret = scmi_to_linux_errno(xfer->hdr.status);
|
||||
}
|
||||
}
|
||||
|
||||
xfer->async_done = NULL;
|
||||
|
@ -1308,6 +1408,29 @@ static void scmi_devm_protocol_put(struct scmi_device *sdev, u8 protocol_id)
|
|||
WARN_ON(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* scmi_is_transport_atomic - Method to check if underlying transport for an
|
||||
* SCMI instance is configured as atomic.
|
||||
*
|
||||
* @handle: A reference to the SCMI platform instance.
|
||||
* @atomic_threshold: An optional return value for the system wide currently
|
||||
* configured threshold for atomic operations.
|
||||
*
|
||||
* Return: True if transport is configured as atomic
|
||||
*/
|
||||
static bool scmi_is_transport_atomic(const struct scmi_handle *handle,
|
||||
unsigned int *atomic_threshold)
|
||||
{
|
||||
bool ret;
|
||||
struct scmi_info *info = handle_to_scmi_info(handle);
|
||||
|
||||
ret = info->desc->atomic_enabled && is_transport_polling_capable(info);
|
||||
if (ret && atomic_threshold)
|
||||
*atomic_threshold = info->atomic_threshold;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct scmi_handle *scmi_handle_get_from_info_unlocked(struct scmi_info *info)
|
||||
{
|
||||
|
@ -1499,6 +1622,16 @@ static int scmi_chan_setup(struct scmi_info *info, struct device *dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tx && is_polling_required(cinfo, info)) {
|
||||
if (is_transport_polling_capable(info))
|
||||
dev_info(dev,
|
||||
"Enabled polling mode TX channel - prot_id:%d\n",
|
||||
prot_id);
|
||||
else
|
||||
dev_warn(dev,
|
||||
"Polling mode NOT supported by transport.\n");
|
||||
}
|
||||
|
||||
idr_alloc:
|
||||
ret = idr_alloc(idr, cinfo, prot_id, prot_id + 1, GFP_KERNEL);
|
||||
if (ret != prot_id) {
|
||||
|
@ -1836,6 +1969,14 @@ static int scmi_probe(struct platform_device *pdev)
|
|||
handle->devm_protocol_get = scmi_devm_protocol_get;
|
||||
handle->devm_protocol_put = scmi_devm_protocol_put;
|
||||
|
||||
/* System wide atomic threshold for atomic ops .. if any */
|
||||
if (!of_property_read_u32(np, "atomic-threshold-us",
|
||||
&info->atomic_threshold))
|
||||
dev_info(dev,
|
||||
"SCMI System wide atomic threshold set to %d us\n",
|
||||
info->atomic_threshold);
|
||||
handle->is_transport_atomic = scmi_is_transport_atomic;
|
||||
|
||||
if (desc->ops->link_supplier) {
|
||||
ret = desc->ops->link_supplier(dev);
|
||||
if (ret)
|
||||
|
@ -1853,6 +1994,10 @@ static int scmi_probe(struct platform_device *pdev)
|
|||
if (scmi_notification_init(handle))
|
||||
dev_err(dev, "SCMI Notifications NOT available.\n");
|
||||
|
||||
if (info->desc->atomic_enabled && !is_transport_polling_capable(info))
|
||||
dev_err(dev,
|
||||
"Transport is not polling capable. Atomic mode not supported.\n");
|
||||
|
||||
/*
|
||||
* Trigger SCMI Base protocol initialization.
|
||||
* It's mandatory and won't be ever released/deinit until the
|
||||
|
@ -1994,6 +2139,9 @@ static const struct of_device_id scmi_of_match[] = {
|
|||
#ifdef CONFIG_ARM_SCMI_TRANSPORT_MAILBOX
|
||||
{ .compatible = "arm,scmi", .data = &scmi_mailbox_desc },
|
||||
#endif
|
||||
#ifdef CONFIG_ARM_SCMI_TRANSPORT_OPTEE
|
||||
{ .compatible = "linaro,scmi-optee", .data = &scmi_optee_desc },
|
||||
#endif
|
||||
#ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
|
||||
{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
|
||||
#endif
|
||||
|
|
|
@ -140,7 +140,8 @@ static int mailbox_send_message(struct scmi_chan_info *cinfo,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void mailbox_mark_txdone(struct scmi_chan_info *cinfo, int ret)
|
||||
static void mailbox_mark_txdone(struct scmi_chan_info *cinfo, int ret,
|
||||
struct scmi_xfer *__unused)
|
||||
{
|
||||
struct scmi_mailbox *smbox = cinfo->transport_info;
|
||||
|
||||
|
|
567
drivers/firmware/arm_scmi/optee.c
Normal file
567
drivers/firmware/arm_scmi/optee.c
Normal file
|
@ -0,0 +1,567 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2019-2021 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tee_drv.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <uapi/linux/tee.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define SCMI_OPTEE_MAX_MSG_SIZE 128
|
||||
|
||||
enum scmi_optee_pta_cmd {
|
||||
/*
|
||||
* PTA_SCMI_CMD_CAPABILITIES - Get channel capabilities
|
||||
*
|
||||
* [out] value[0].a: Capability bit mask (enum pta_scmi_caps)
|
||||
* [out] value[0].b: Extended capabilities or 0
|
||||
*/
|
||||
PTA_SCMI_CMD_CAPABILITIES = 0,
|
||||
|
||||
/*
|
||||
* PTA_SCMI_CMD_PROCESS_SMT_CHANNEL - Process SCMI message in SMT buffer
|
||||
*
|
||||
* [in] value[0].a: Channel handle
|
||||
*
|
||||
* Shared memory used for SCMI message/response exhange is expected
|
||||
* already identified and bound to channel handle in both SCMI agent
|
||||
* and SCMI server (OP-TEE) parts.
|
||||
* The memory uses SMT header to carry SCMI meta-data (protocol ID and
|
||||
* protocol message ID).
|
||||
*/
|
||||
PTA_SCMI_CMD_PROCESS_SMT_CHANNEL = 1,
|
||||
|
||||
/*
|
||||
* PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE - Process SMT/SCMI message
|
||||
*
|
||||
* [in] value[0].a: Channel handle
|
||||
* [in/out] memref[1]: Message/response buffer (SMT and SCMI payload)
|
||||
*
|
||||
* Shared memory used for SCMI message/response is a SMT buffer
|
||||
* referenced by param[1]. It shall be 128 bytes large to fit response
|
||||
* payload whatever message playload size.
|
||||
* The memory uses SMT header to carry SCMI meta-data (protocol ID and
|
||||
* protocol message ID).
|
||||
*/
|
||||
PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE = 2,
|
||||
|
||||
/*
|
||||
* PTA_SCMI_CMD_GET_CHANNEL - Get channel handle
|
||||
*
|
||||
* SCMI shm information are 0 if agent expects to use OP-TEE regular SHM
|
||||
*
|
||||
* [in] value[0].a: Channel identifier
|
||||
* [out] value[0].a: Returned channel handle
|
||||
* [in] value[0].b: Requested capabilities mask (enum pta_scmi_caps)
|
||||
*/
|
||||
PTA_SCMI_CMD_GET_CHANNEL = 3,
|
||||
};
|
||||
|
||||
/*
|
||||
* OP-TEE SCMI service capabilities bit flags (32bit)
|
||||
*
|
||||
* PTA_SCMI_CAPS_SMT_HEADER
|
||||
* When set, OP-TEE supports command using SMT header protocol (SCMI shmem) in
|
||||
* shared memory buffers to carry SCMI protocol synchronisation information.
|
||||
*/
|
||||
#define PTA_SCMI_CAPS_NONE 0
|
||||
#define PTA_SCMI_CAPS_SMT_HEADER BIT(0)
|
||||
|
||||
/**
|
||||
* struct scmi_optee_channel - Description of an OP-TEE SCMI channel
|
||||
*
|
||||
* @channel_id: OP-TEE channel ID used for this transport
|
||||
* @tee_session: TEE session identifier
|
||||
* @caps: OP-TEE SCMI channel capabilities
|
||||
* @mu: Mutex protection on channel access
|
||||
* @cinfo: SCMI channel information
|
||||
* @shmem: Virtual base address of the shared memory
|
||||
* @tee_shm: Reference to TEE shared memory or NULL if using static shmem
|
||||
* @link: Reference in agent's channel list
|
||||
*/
|
||||
struct scmi_optee_channel {
|
||||
u32 channel_id;
|
||||
u32 tee_session;
|
||||
u32 caps;
|
||||
struct mutex mu;
|
||||
struct scmi_chan_info *cinfo;
|
||||
struct scmi_shared_mem __iomem *shmem;
|
||||
struct tee_shm *tee_shm;
|
||||
struct list_head link;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scmi_optee_agent - OP-TEE transport private data
|
||||
*
|
||||
* @dev: Device used for communication with TEE
|
||||
* @tee_ctx: TEE context used for communication
|
||||
* @caps: Supported channel capabilities
|
||||
* @mu: Mutex for protection of @channel_list
|
||||
* @channel_list: List of all created channels for the agent
|
||||
*/
|
||||
struct scmi_optee_agent {
|
||||
struct device *dev;
|
||||
struct tee_context *tee_ctx;
|
||||
u32 caps;
|
||||
struct mutex mu;
|
||||
struct list_head channel_list;
|
||||
};
|
||||
|
||||
/* There can be only 1 SCMI service in OP-TEE we connect to */
|
||||
static struct scmi_optee_agent *scmi_optee_private;
|
||||
|
||||
/* Forward reference to scmi_optee transport initialization */
|
||||
static int scmi_optee_init(void);
|
||||
|
||||
/* Open a session toward SCMI OP-TEE service with REE_KERNEL identity */
|
||||
static int open_session(struct scmi_optee_agent *agent, u32 *tee_session)
|
||||
{
|
||||
struct device *dev = agent->dev;
|
||||
struct tee_client_device *scmi_pta = to_tee_client_device(dev);
|
||||
struct tee_ioctl_open_session_arg arg = { };
|
||||
int ret;
|
||||
|
||||
memcpy(arg.uuid, scmi_pta->id.uuid.b, TEE_IOCTL_UUID_LEN);
|
||||
arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
|
||||
|
||||
ret = tee_client_open_session(agent->tee_ctx, &arg, NULL);
|
||||
if (ret < 0 || arg.ret) {
|
||||
dev_err(dev, "Can't open tee session: %d / %#x\n", ret, arg.ret);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
*tee_session = arg.session;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void close_session(struct scmi_optee_agent *agent, u32 tee_session)
|
||||
{
|
||||
tee_client_close_session(agent->tee_ctx, tee_session);
|
||||
}
|
||||
|
||||
static int get_capabilities(struct scmi_optee_agent *agent)
|
||||
{
|
||||
struct tee_ioctl_invoke_arg arg = { };
|
||||
struct tee_param param[1] = { };
|
||||
u32 caps;
|
||||
u32 tee_session;
|
||||
int ret;
|
||||
|
||||
ret = open_session(agent, &tee_session);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
arg.func = PTA_SCMI_CMD_CAPABILITIES;
|
||||
arg.session = tee_session;
|
||||
arg.num_params = 1;
|
||||
|
||||
param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
|
||||
|
||||
ret = tee_client_invoke_func(agent->tee_ctx, &arg, param);
|
||||
|
||||
close_session(agent, tee_session);
|
||||
|
||||
if (ret < 0 || arg.ret) {
|
||||
dev_err(agent->dev, "Can't get capabilities: %d / %#x\n", ret, arg.ret);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
caps = param[0].u.value.a;
|
||||
|
||||
if (!(caps & PTA_SCMI_CAPS_SMT_HEADER)) {
|
||||
dev_err(agent->dev, "OP-TEE SCMI PTA doesn't support SMT\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
agent->caps = caps;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_channel(struct scmi_optee_channel *channel)
|
||||
{
|
||||
struct device *dev = scmi_optee_private->dev;
|
||||
struct tee_ioctl_invoke_arg arg = { };
|
||||
struct tee_param param[1] = { };
|
||||
unsigned int caps = PTA_SCMI_CAPS_SMT_HEADER;
|
||||
int ret;
|
||||
|
||||
arg.func = PTA_SCMI_CMD_GET_CHANNEL;
|
||||
arg.session = channel->tee_session;
|
||||
arg.num_params = 1;
|
||||
|
||||
param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
|
||||
param[0].u.value.a = channel->channel_id;
|
||||
param[0].u.value.b = caps;
|
||||
|
||||
ret = tee_client_invoke_func(scmi_optee_private->tee_ctx, &arg, param);
|
||||
|
||||
if (ret || arg.ret) {
|
||||
dev_err(dev, "Can't get channel with caps %#x: %d / %#x\n", caps, ret, arg.ret);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* From now on use channel identifer provided by OP-TEE SCMI service */
|
||||
channel->channel_id = param[0].u.value.a;
|
||||
channel->caps = caps;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int invoke_process_smt_channel(struct scmi_optee_channel *channel)
|
||||
{
|
||||
struct tee_ioctl_invoke_arg arg = { };
|
||||
struct tee_param param[2] = { };
|
||||
int ret;
|
||||
|
||||
arg.session = channel->tee_session;
|
||||
param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
|
||||
param[0].u.value.a = channel->channel_id;
|
||||
|
||||
if (channel->tee_shm) {
|
||||
param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
|
||||
param[1].u.memref.shm = channel->tee_shm;
|
||||
param[1].u.memref.size = SCMI_OPTEE_MAX_MSG_SIZE;
|
||||
arg.num_params = 2;
|
||||
arg.func = PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE;
|
||||
} else {
|
||||
arg.num_params = 1;
|
||||
arg.func = PTA_SCMI_CMD_PROCESS_SMT_CHANNEL;
|
||||
}
|
||||
|
||||
ret = tee_client_invoke_func(scmi_optee_private->tee_ctx, &arg, param);
|
||||
if (ret < 0 || arg.ret) {
|
||||
dev_err(scmi_optee_private->dev, "Can't invoke channel %u: %d / %#x\n",
|
||||
channel->channel_id, ret, arg.ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scmi_optee_link_supplier(struct device *dev)
|
||||
{
|
||||
if (!scmi_optee_private) {
|
||||
if (scmi_optee_init())
|
||||
dev_dbg(dev, "Optee bus not yet ready\n");
|
||||
|
||||
/* Wait for optee bus */
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
if (!device_link_add(dev, scmi_optee_private->dev, DL_FLAG_AUTOREMOVE_CONSUMER)) {
|
||||
dev_err(dev, "Adding link to supplier optee device failed\n");
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool scmi_optee_chan_available(struct device *dev, int idx)
|
||||
{
|
||||
u32 channel_id;
|
||||
|
||||
return !of_property_read_u32_index(dev->of_node, "linaro,optee-channel-id",
|
||||
idx, &channel_id);
|
||||
}
|
||||
|
||||
static void scmi_optee_clear_channel(struct scmi_chan_info *cinfo)
|
||||
{
|
||||
struct scmi_optee_channel *channel = cinfo->transport_info;
|
||||
|
||||
shmem_clear_channel(channel->shmem);
|
||||
}
|
||||
|
||||
static int setup_static_shmem(struct device *dev, struct scmi_chan_info *cinfo,
|
||||
struct scmi_optee_channel *channel)
|
||||
{
|
||||
struct device_node *np;
|
||||
resource_size_t size;
|
||||
struct resource res;
|
||||
int ret;
|
||||
|
||||
np = of_parse_phandle(cinfo->dev->of_node, "shmem", 0);
|
||||
if (!of_device_is_compatible(np, "arm,scmi-shmem")) {
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = of_address_to_resource(np, 0, &res);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to get SCMI Tx shared memory\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
size = resource_size(&res);
|
||||
|
||||
channel->shmem = devm_ioremap(dev, res.start, size);
|
||||
if (!channel->shmem) {
|
||||
dev_err(dev, "Failed to ioremap SCMI Tx shared memory\n");
|
||||
ret = -EADDRNOTAVAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
of_node_put(np);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int setup_shmem(struct device *dev, struct scmi_chan_info *cinfo,
|
||||
struct scmi_optee_channel *channel)
|
||||
{
|
||||
if (of_find_property(cinfo->dev->of_node, "shmem", NULL))
|
||||
return setup_static_shmem(dev, cinfo, channel);
|
||||
else
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int scmi_optee_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, bool tx)
|
||||
{
|
||||
struct scmi_optee_channel *channel;
|
||||
uint32_t channel_id;
|
||||
int ret;
|
||||
|
||||
if (!tx)
|
||||
return -ENODEV;
|
||||
|
||||
channel = devm_kzalloc(dev, sizeof(*channel), GFP_KERNEL);
|
||||
if (!channel)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_property_read_u32_index(cinfo->dev->of_node, "linaro,optee-channel-id",
|
||||
0, &channel_id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cinfo->transport_info = channel;
|
||||
channel->cinfo = cinfo;
|
||||
channel->channel_id = channel_id;
|
||||
mutex_init(&channel->mu);
|
||||
|
||||
ret = setup_shmem(dev, cinfo, channel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = open_session(scmi_optee_private, &channel->tee_session);
|
||||
if (ret)
|
||||
goto err_free_shm;
|
||||
|
||||
ret = get_channel(channel);
|
||||
if (ret)
|
||||
goto err_close_sess;
|
||||
|
||||
/* Enable polling */
|
||||
cinfo->no_completion_irq = true;
|
||||
|
||||
mutex_lock(&scmi_optee_private->mu);
|
||||
list_add(&channel->link, &scmi_optee_private->channel_list);
|
||||
mutex_unlock(&scmi_optee_private->mu);
|
||||
|
||||
return 0;
|
||||
|
||||
err_close_sess:
|
||||
close_session(scmi_optee_private, channel->tee_session);
|
||||
err_free_shm:
|
||||
if (channel->tee_shm)
|
||||
tee_shm_free(channel->tee_shm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_optee_chan_free(int id, void *p, void *data)
|
||||
{
|
||||
struct scmi_chan_info *cinfo = p;
|
||||
struct scmi_optee_channel *channel = cinfo->transport_info;
|
||||
|
||||
mutex_lock(&scmi_optee_private->mu);
|
||||
list_del(&channel->link);
|
||||
mutex_unlock(&scmi_optee_private->mu);
|
||||
|
||||
close_session(scmi_optee_private, channel->tee_session);
|
||||
|
||||
if (channel->tee_shm) {
|
||||
tee_shm_free(channel->tee_shm);
|
||||
channel->tee_shm = NULL;
|
||||
}
|
||||
|
||||
cinfo->transport_info = NULL;
|
||||
channel->cinfo = NULL;
|
||||
|
||||
scmi_free_channel(cinfo, data, id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct scmi_shared_mem *get_channel_shm(struct scmi_optee_channel *chan,
|
||||
struct scmi_xfer *xfer)
|
||||
{
|
||||
if (!chan)
|
||||
return NULL;
|
||||
|
||||
return chan->shmem;
|
||||
}
|
||||
|
||||
|
||||
static int scmi_optee_send_message(struct scmi_chan_info *cinfo,
|
||||
struct scmi_xfer *xfer)
|
||||
{
|
||||
struct scmi_optee_channel *channel = cinfo->transport_info;
|
||||
struct scmi_shared_mem *shmem = get_channel_shm(channel, xfer);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&channel->mu);
|
||||
shmem_tx_prepare(shmem, xfer);
|
||||
|
||||
ret = invoke_process_smt_channel(channel);
|
||||
if (ret)
|
||||
mutex_unlock(&channel->mu);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void scmi_optee_fetch_response(struct scmi_chan_info *cinfo,
|
||||
struct scmi_xfer *xfer)
|
||||
{
|
||||
struct scmi_optee_channel *channel = cinfo->transport_info;
|
||||
struct scmi_shared_mem *shmem = get_channel_shm(channel, xfer);
|
||||
|
||||
shmem_fetch_response(shmem, xfer);
|
||||
}
|
||||
|
||||
static void scmi_optee_mark_txdone(struct scmi_chan_info *cinfo, int ret,
|
||||
struct scmi_xfer *__unused)
|
||||
{
|
||||
struct scmi_optee_channel *channel = cinfo->transport_info;
|
||||
|
||||
mutex_unlock(&channel->mu);
|
||||
}
|
||||
|
||||
static struct scmi_transport_ops scmi_optee_ops = {
|
||||
.link_supplier = scmi_optee_link_supplier,
|
||||
.chan_available = scmi_optee_chan_available,
|
||||
.chan_setup = scmi_optee_chan_setup,
|
||||
.chan_free = scmi_optee_chan_free,
|
||||
.send_message = scmi_optee_send_message,
|
||||
.mark_txdone = scmi_optee_mark_txdone,
|
||||
.fetch_response = scmi_optee_fetch_response,
|
||||
.clear_channel = scmi_optee_clear_channel,
|
||||
};
|
||||
|
||||
static int scmi_optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
|
||||
{
|
||||
return ver->impl_id == TEE_IMPL_ID_OPTEE;
|
||||
}
|
||||
|
||||
static int scmi_optee_service_probe(struct device *dev)
|
||||
{
|
||||
struct scmi_optee_agent *agent;
|
||||
struct tee_context *tee_ctx;
|
||||
int ret;
|
||||
|
||||
/* Only one SCMI OP-TEE device allowed */
|
||||
if (scmi_optee_private) {
|
||||
dev_err(dev, "An SCMI OP-TEE device was already initialized: only one allowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
tee_ctx = tee_client_open_context(NULL, scmi_optee_ctx_match, NULL, NULL);
|
||||
if (IS_ERR(tee_ctx))
|
||||
return -ENODEV;
|
||||
|
||||
agent = devm_kzalloc(dev, sizeof(*agent), GFP_KERNEL);
|
||||
if (!agent) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
agent->dev = dev;
|
||||
agent->tee_ctx = tee_ctx;
|
||||
INIT_LIST_HEAD(&agent->channel_list);
|
||||
mutex_init(&agent->mu);
|
||||
|
||||
ret = get_capabilities(agent);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* Ensure agent resources are all visible before scmi_optee_private is */
|
||||
smp_mb();
|
||||
scmi_optee_private = agent;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
tee_client_close_context(tee_ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scmi_optee_service_remove(struct device *dev)
|
||||
{
|
||||
struct scmi_optee_agent *agent = scmi_optee_private;
|
||||
|
||||
if (!scmi_optee_private)
|
||||
return -EINVAL;
|
||||
|
||||
if (!list_empty(&scmi_optee_private->channel_list))
|
||||
return -EBUSY;
|
||||
|
||||
/* Ensure cleared reference is visible before resources are released */
|
||||
smp_store_mb(scmi_optee_private, NULL);
|
||||
|
||||
tee_client_close_context(agent->tee_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct tee_client_device_id scmi_optee_service_id[] = {
|
||||
{
|
||||
UUID_INIT(0xa8cfe406, 0xd4f5, 0x4a2e,
|
||||
0x9f, 0x8d, 0xa2, 0x5d, 0xc7, 0x54, 0xc0, 0x99)
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(tee, scmi_optee_service_id);
|
||||
|
||||
static struct tee_client_driver scmi_optee_driver = {
|
||||
.id_table = scmi_optee_service_id,
|
||||
.driver = {
|
||||
.name = "scmi-optee",
|
||||
.bus = &tee_bus_type,
|
||||
.probe = scmi_optee_service_probe,
|
||||
.remove = scmi_optee_service_remove,
|
||||
},
|
||||
};
|
||||
|
||||
static int scmi_optee_init(void)
|
||||
{
|
||||
return driver_register(&scmi_optee_driver.driver);
|
||||
}
|
||||
|
||||
static void scmi_optee_exit(void)
|
||||
{
|
||||
if (scmi_optee_private)
|
||||
driver_unregister(&scmi_optee_driver.driver);
|
||||
}
|
||||
|
||||
const struct scmi_desc scmi_optee_desc = {
|
||||
.transport_exit = scmi_optee_exit,
|
||||
.ops = &scmi_optee_ops,
|
||||
.max_rx_timeout_ms = 30,
|
||||
.max_msg = 20,
|
||||
.max_msg_size = SCMI_OPTEE_MAX_MSG_SIZE,
|
||||
.sync_cmds_completed_on_ret = true,
|
||||
};
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
@ -14,6 +15,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/processor.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "common.h"
|
||||
|
@ -23,26 +25,29 @@
|
|||
*
|
||||
* @cinfo: SCMI channel info
|
||||
* @shmem: Transmit/Receive shared memory area
|
||||
* @shmem_lock: Lock to protect access to Tx/Rx shared memory area
|
||||
* @shmem_lock: Lock to protect access to Tx/Rx shared memory area.
|
||||
* Used when NOT operating in atomic mode.
|
||||
* @inflight: Atomic flag to protect access to Tx/Rx shared memory area.
|
||||
* Used when operating in atomic mode.
|
||||
* @func_id: smc/hvc call function id
|
||||
* @irq: Optional; employed when platforms indicates msg completion by intr.
|
||||
* @tx_complete: Optional, employed only when irq is valid.
|
||||
*/
|
||||
|
||||
struct scmi_smc {
|
||||
struct scmi_chan_info *cinfo;
|
||||
struct scmi_shared_mem __iomem *shmem;
|
||||
/* Protect access to shmem area */
|
||||
struct mutex shmem_lock;
|
||||
#define INFLIGHT_NONE MSG_TOKEN_MAX
|
||||
atomic_t inflight;
|
||||
u32 func_id;
|
||||
int irq;
|
||||
struct completion tx_complete;
|
||||
};
|
||||
|
||||
static irqreturn_t smc_msg_done_isr(int irq, void *data)
|
||||
{
|
||||
struct scmi_smc *scmi_info = data;
|
||||
|
||||
complete(&scmi_info->tx_complete);
|
||||
scmi_rx_callback(scmi_info->cinfo,
|
||||
shmem_read_header(scmi_info->shmem), NULL);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -57,6 +62,41 @@ static bool smc_chan_available(struct device *dev, int idx)
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline void smc_channel_lock_init(struct scmi_smc *scmi_info)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE))
|
||||
atomic_set(&scmi_info->inflight, INFLIGHT_NONE);
|
||||
else
|
||||
mutex_init(&scmi_info->shmem_lock);
|
||||
}
|
||||
|
||||
static bool smc_xfer_inflight(struct scmi_xfer *xfer, atomic_t *inflight)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = atomic_cmpxchg(inflight, INFLIGHT_NONE, xfer->hdr.seq);
|
||||
|
||||
return ret == INFLIGHT_NONE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
smc_channel_lock_acquire(struct scmi_smc *scmi_info,
|
||||
struct scmi_xfer *xfer __maybe_unused)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE))
|
||||
spin_until_cond(smc_xfer_inflight(xfer, &scmi_info->inflight));
|
||||
else
|
||||
mutex_lock(&scmi_info->shmem_lock);
|
||||
}
|
||||
|
||||
static inline void smc_channel_lock_release(struct scmi_smc *scmi_info)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE))
|
||||
atomic_set(&scmi_info->inflight, INFLIGHT_NONE);
|
||||
else
|
||||
mutex_unlock(&scmi_info->shmem_lock);
|
||||
}
|
||||
|
||||
static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
|
||||
bool tx)
|
||||
{
|
||||
|
@ -111,13 +151,13 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
|
|||
dev_err(dev, "failed to setup SCMI smc irq\n");
|
||||
return ret;
|
||||
}
|
||||
init_completion(&scmi_info->tx_complete);
|
||||
scmi_info->irq = irq;
|
||||
} else {
|
||||
cinfo->no_completion_irq = true;
|
||||
}
|
||||
|
||||
scmi_info->func_id = func_id;
|
||||
scmi_info->cinfo = cinfo;
|
||||
mutex_init(&scmi_info->shmem_lock);
|
||||
smc_channel_lock_init(scmi_info);
|
||||
cinfo->transport_info = scmi_info;
|
||||
|
||||
return 0;
|
||||
|
@ -142,26 +182,22 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
|
|||
struct scmi_smc *scmi_info = cinfo->transport_info;
|
||||
struct arm_smccc_res res;
|
||||
|
||||
mutex_lock(&scmi_info->shmem_lock);
|
||||
/*
|
||||
* Channel will be released only once response has been
|
||||
* surely fully retrieved, so after .mark_txdone()
|
||||
*/
|
||||
smc_channel_lock_acquire(scmi_info, xfer);
|
||||
|
||||
shmem_tx_prepare(scmi_info->shmem, xfer);
|
||||
|
||||
if (scmi_info->irq)
|
||||
reinit_completion(&scmi_info->tx_complete);
|
||||
|
||||
arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res);
|
||||
|
||||
if (scmi_info->irq)
|
||||
wait_for_completion(&scmi_info->tx_complete);
|
||||
|
||||
scmi_rx_callback(scmi_info->cinfo,
|
||||
shmem_read_header(scmi_info->shmem), NULL);
|
||||
|
||||
mutex_unlock(&scmi_info->shmem_lock);
|
||||
|
||||
/* Only SMCCC_RET_NOT_SUPPORTED is valid error code */
|
||||
if (res.a0)
|
||||
if (res.a0) {
|
||||
smc_channel_lock_release(scmi_info);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -173,12 +209,12 @@ static void smc_fetch_response(struct scmi_chan_info *cinfo,
|
|||
shmem_fetch_response(scmi_info->shmem, xfer);
|
||||
}
|
||||
|
||||
static bool
|
||||
smc_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
|
||||
static void smc_mark_txdone(struct scmi_chan_info *cinfo, int ret,
|
||||
struct scmi_xfer *__unused)
|
||||
{
|
||||
struct scmi_smc *scmi_info = cinfo->transport_info;
|
||||
|
||||
return shmem_poll_done(scmi_info->shmem, xfer);
|
||||
smc_channel_lock_release(scmi_info);
|
||||
}
|
||||
|
||||
static const struct scmi_transport_ops scmi_smc_ops = {
|
||||
|
@ -186,8 +222,8 @@ static const struct scmi_transport_ops scmi_smc_ops = {
|
|||
.chan_setup = smc_chan_setup,
|
||||
.chan_free = smc_chan_free,
|
||||
.send_message = smc_send_message,
|
||||
.mark_txdone = smc_mark_txdone,
|
||||
.fetch_response = smc_fetch_response,
|
||||
.poll_done = smc_poll_done,
|
||||
};
|
||||
|
||||
const struct scmi_desc scmi_smc_desc = {
|
||||
|
@ -195,4 +231,14 @@ const struct scmi_desc scmi_smc_desc = {
|
|||
.max_rx_timeout_ms = 30,
|
||||
.max_msg = 20,
|
||||
.max_msg_size = 128,
|
||||
/*
|
||||
* Setting .sync_cmds_atomic_replies to true for SMC assumes that,
|
||||
* once the SMC instruction has completed successfully, the issued
|
||||
* SCMI command would have been already fully processed by the SCMI
|
||||
* platform firmware and so any possible response value expected
|
||||
* for the issued command will be immmediately ready to be fetched
|
||||
* from the shared memory area.
|
||||
*/
|
||||
.sync_cmds_completed_on_ret = true,
|
||||
.atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE),
|
||||
};
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
* Virtio Transport driver for Arm System Control and Management Interface
|
||||
* (SCMI).
|
||||
*
|
||||
* Copyright (C) 2020-2021 OpenSynergy.
|
||||
* Copyright (C) 2021 ARM Ltd.
|
||||
* Copyright (C) 2020-2022 OpenSynergy.
|
||||
* Copyright (C) 2021-2022 ARM Ltd.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -17,7 +17,9 @@
|
|||
* virtqueue. Access to each virtqueue is protected by spinlocks.
|
||||
*/
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/virtio.h>
|
||||
#include <linux/virtio_config.h>
|
||||
|
@ -27,6 +29,7 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
#define VIRTIO_MAX_RX_TIMEOUT_MS 60000
|
||||
#define VIRTIO_SCMI_MAX_MSG_SIZE 128 /* Value may be increased. */
|
||||
#define VIRTIO_SCMI_MAX_PDU_SIZE \
|
||||
(VIRTIO_SCMI_MAX_MSG_SIZE + SCMI_MSG_MAX_PROT_OVERHEAD)
|
||||
|
@ -37,25 +40,46 @@
|
|||
*
|
||||
* @vqueue: Associated virtqueue
|
||||
* @cinfo: SCMI Tx or Rx channel
|
||||
* @free_lock: Protects access to the @free_list.
|
||||
* @free_list: List of unused scmi_vio_msg, maintained for Tx channels only
|
||||
* @deferred_tx_work: Worker for TX deferred replies processing
|
||||
* @deferred_tx_wq: Workqueue for TX deferred replies
|
||||
* @pending_lock: Protects access to the @pending_cmds_list.
|
||||
* @pending_cmds_list: List of pre-fetched commands queueud for later processing
|
||||
* @is_rx: Whether channel is an Rx channel
|
||||
* @ready: Whether transport user is ready to hear about channel
|
||||
* @max_msg: Maximum number of pending messages for this channel.
|
||||
* @lock: Protects access to all members except ready.
|
||||
* @ready_lock: Protects access to ready. If required, it must be taken before
|
||||
* lock.
|
||||
* @lock: Protects access to all members except users, free_list and
|
||||
* pending_cmds_list.
|
||||
* @shutdown_done: A reference to a completion used when freeing this channel.
|
||||
* @users: A reference count to currently active users of this channel.
|
||||
*/
|
||||
struct scmi_vio_channel {
|
||||
struct virtqueue *vqueue;
|
||||
struct scmi_chan_info *cinfo;
|
||||
/* lock to protect access to the free list. */
|
||||
spinlock_t free_lock;
|
||||
struct list_head free_list;
|
||||
/* lock to protect access to the pending list. */
|
||||
spinlock_t pending_lock;
|
||||
struct list_head pending_cmds_list;
|
||||
struct work_struct deferred_tx_work;
|
||||
struct workqueue_struct *deferred_tx_wq;
|
||||
bool is_rx;
|
||||
bool ready;
|
||||
unsigned int max_msg;
|
||||
/* lock to protect access to all members except ready. */
|
||||
/*
|
||||
* Lock to protect access to all members except users, free_list and
|
||||
* pending_cmds_list
|
||||
*/
|
||||
spinlock_t lock;
|
||||
/* lock to rotects access to ready flag. */
|
||||
spinlock_t ready_lock;
|
||||
struct completion *shutdown_done;
|
||||
refcount_t users;
|
||||
};
|
||||
|
||||
enum poll_states {
|
||||
VIO_MSG_NOT_POLLED,
|
||||
VIO_MSG_POLL_TIMEOUT,
|
||||
VIO_MSG_POLLING,
|
||||
VIO_MSG_POLL_DONE,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -65,29 +89,154 @@ struct scmi_vio_channel {
|
|||
* @input: SDU used for (delayed) responses and notifications
|
||||
* @list: List which scmi_vio_msg may be part of
|
||||
* @rx_len: Input SDU size in bytes, once input has been received
|
||||
* @poll_idx: Last used index registered for polling purposes if this message
|
||||
* transaction reply was configured for polling.
|
||||
* @poll_status: Polling state for this message.
|
||||
* @poll_lock: A lock to protect @poll_status
|
||||
* @users: A reference count to track this message users and avoid premature
|
||||
* freeing (and reuse) when polling and IRQ execution paths interleave.
|
||||
*/
|
||||
struct scmi_vio_msg {
|
||||
struct scmi_msg_payld *request;
|
||||
struct scmi_msg_payld *input;
|
||||
struct list_head list;
|
||||
unsigned int rx_len;
|
||||
unsigned int poll_idx;
|
||||
enum poll_states poll_status;
|
||||
/* Lock to protect access to poll_status */
|
||||
spinlock_t poll_lock;
|
||||
refcount_t users;
|
||||
};
|
||||
|
||||
/* Only one SCMI VirtIO device can possibly exist */
|
||||
static struct virtio_device *scmi_vdev;
|
||||
|
||||
static void scmi_vio_channel_ready(struct scmi_vio_channel *vioch,
|
||||
struct scmi_chan_info *cinfo)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&vioch->lock, flags);
|
||||
cinfo->transport_info = vioch;
|
||||
/* Indirectly setting channel not available any more */
|
||||
vioch->cinfo = cinfo;
|
||||
spin_unlock_irqrestore(&vioch->lock, flags);
|
||||
|
||||
refcount_set(&vioch->users, 1);
|
||||
}
|
||||
|
||||
static inline bool scmi_vio_channel_acquire(struct scmi_vio_channel *vioch)
|
||||
{
|
||||
return refcount_inc_not_zero(&vioch->users);
|
||||
}
|
||||
|
||||
static inline void scmi_vio_channel_release(struct scmi_vio_channel *vioch)
|
||||
{
|
||||
if (refcount_dec_and_test(&vioch->users)) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&vioch->lock, flags);
|
||||
if (vioch->shutdown_done) {
|
||||
vioch->cinfo = NULL;
|
||||
complete(vioch->shutdown_done);
|
||||
}
|
||||
spin_unlock_irqrestore(&vioch->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void scmi_vio_channel_cleanup_sync(struct scmi_vio_channel *vioch)
|
||||
{
|
||||
unsigned long flags;
|
||||
DECLARE_COMPLETION_ONSTACK(vioch_shutdown_done);
|
||||
void *deferred_wq = NULL;
|
||||
|
||||
/*
|
||||
* Prepare to wait for the last release if not already released
|
||||
* or in progress.
|
||||
*/
|
||||
spin_lock_irqsave(&vioch->lock, flags);
|
||||
if (!vioch->cinfo || vioch->shutdown_done) {
|
||||
spin_unlock_irqrestore(&vioch->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
vioch->shutdown_done = &vioch_shutdown_done;
|
||||
virtio_break_device(vioch->vqueue->vdev);
|
||||
if (!vioch->is_rx && vioch->deferred_tx_wq) {
|
||||
deferred_wq = vioch->deferred_tx_wq;
|
||||
/* Cannot be kicked anymore after this...*/
|
||||
vioch->deferred_tx_wq = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&vioch->lock, flags);
|
||||
|
||||
if (deferred_wq)
|
||||
destroy_workqueue(deferred_wq);
|
||||
|
||||
scmi_vio_channel_release(vioch);
|
||||
|
||||
/* Let any possibly concurrent RX path release the channel */
|
||||
wait_for_completion(vioch->shutdown_done);
|
||||
}
|
||||
|
||||
/* Assumes to be called with vio channel acquired already */
|
||||
static struct scmi_vio_msg *
|
||||
scmi_virtio_get_free_msg(struct scmi_vio_channel *vioch)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct scmi_vio_msg *msg;
|
||||
|
||||
spin_lock_irqsave(&vioch->free_lock, flags);
|
||||
if (list_empty(&vioch->free_list)) {
|
||||
spin_unlock_irqrestore(&vioch->free_lock, flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
msg = list_first_entry(&vioch->free_list, typeof(*msg), list);
|
||||
list_del_init(&msg->list);
|
||||
spin_unlock_irqrestore(&vioch->free_lock, flags);
|
||||
|
||||
/* Still no users, no need to acquire poll_lock */
|
||||
msg->poll_status = VIO_MSG_NOT_POLLED;
|
||||
refcount_set(&msg->users, 1);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
static inline bool scmi_vio_msg_acquire(struct scmi_vio_msg *msg)
|
||||
{
|
||||
return refcount_inc_not_zero(&msg->users);
|
||||
}
|
||||
|
||||
/* Assumes to be called with vio channel acquired already */
|
||||
static inline bool scmi_vio_msg_release(struct scmi_vio_channel *vioch,
|
||||
struct scmi_vio_msg *msg)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
ret = refcount_dec_and_test(&msg->users);
|
||||
if (ret) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&vioch->free_lock, flags);
|
||||
list_add_tail(&msg->list, &vioch->free_list);
|
||||
spin_unlock_irqrestore(&vioch->free_lock, flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool scmi_vio_have_vq_rx(struct virtio_device *vdev)
|
||||
{
|
||||
return virtio_has_feature(vdev, VIRTIO_SCMI_F_P2A_CHANNELS);
|
||||
}
|
||||
|
||||
static int scmi_vio_feed_vq_rx(struct scmi_vio_channel *vioch,
|
||||
struct scmi_vio_msg *msg,
|
||||
struct device *dev)
|
||||
struct scmi_vio_msg *msg)
|
||||
{
|
||||
struct scatterlist sg_in;
|
||||
int rc;
|
||||
unsigned long flags;
|
||||
struct device *dev = &vioch->vqueue->vdev->dev;
|
||||
|
||||
sg_init_one(&sg_in, msg->input, VIRTIO_SCMI_MAX_PDU_SIZE);
|
||||
|
||||
|
@ -95,7 +244,7 @@ static int scmi_vio_feed_vq_rx(struct scmi_vio_channel *vioch,
|
|||
|
||||
rc = virtqueue_add_inbuf(vioch->vqueue, &sg_in, 1, msg, GFP_ATOMIC);
|
||||
if (rc)
|
||||
dev_err_once(dev, "failed to add to virtqueue (%d)\n", rc);
|
||||
dev_err(dev, "failed to add to RX virtqueue (%d)\n", rc);
|
||||
else
|
||||
virtqueue_kick(vioch->vqueue);
|
||||
|
||||
|
@ -104,22 +253,22 @@ static int scmi_vio_feed_vq_rx(struct scmi_vio_channel *vioch,
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assume to be called with channel already acquired or not ready at all;
|
||||
* vioch->lock MUST NOT have been already acquired.
|
||||
*/
|
||||
static void scmi_finalize_message(struct scmi_vio_channel *vioch,
|
||||
struct scmi_vio_msg *msg)
|
||||
{
|
||||
if (vioch->is_rx) {
|
||||
scmi_vio_feed_vq_rx(vioch, msg, vioch->cinfo->dev);
|
||||
} else {
|
||||
/* Here IRQs are assumed to be already disabled by the caller */
|
||||
spin_lock(&vioch->lock);
|
||||
list_add(&msg->list, &vioch->free_list);
|
||||
spin_unlock(&vioch->lock);
|
||||
}
|
||||
if (vioch->is_rx)
|
||||
scmi_vio_feed_vq_rx(vioch, msg);
|
||||
else
|
||||
scmi_vio_msg_release(vioch, msg);
|
||||
}
|
||||
|
||||
static void scmi_vio_complete_cb(struct virtqueue *vqueue)
|
||||
{
|
||||
unsigned long ready_flags;
|
||||
unsigned long flags;
|
||||
unsigned int length;
|
||||
struct scmi_vio_channel *vioch;
|
||||
struct scmi_vio_msg *msg;
|
||||
|
@ -130,27 +279,25 @@ static void scmi_vio_complete_cb(struct virtqueue *vqueue)
|
|||
vioch = &((struct scmi_vio_channel *)vqueue->vdev->priv)[vqueue->index];
|
||||
|
||||
for (;;) {
|
||||
spin_lock_irqsave(&vioch->ready_lock, ready_flags);
|
||||
if (!scmi_vio_channel_acquire(vioch))
|
||||
return;
|
||||
|
||||
if (!vioch->ready) {
|
||||
if (!cb_enabled)
|
||||
(void)virtqueue_enable_cb(vqueue);
|
||||
goto unlock_ready_out;
|
||||
}
|
||||
|
||||
/* IRQs already disabled here no need to irqsave */
|
||||
spin_lock(&vioch->lock);
|
||||
spin_lock_irqsave(&vioch->lock, flags);
|
||||
if (cb_enabled) {
|
||||
virtqueue_disable_cb(vqueue);
|
||||
cb_enabled = false;
|
||||
}
|
||||
|
||||
msg = virtqueue_get_buf(vqueue, &length);
|
||||
if (!msg) {
|
||||
if (virtqueue_enable_cb(vqueue))
|
||||
goto unlock_out;
|
||||
if (virtqueue_enable_cb(vqueue)) {
|
||||
spin_unlock_irqrestore(&vioch->lock, flags);
|
||||
scmi_vio_channel_release(vioch);
|
||||
return;
|
||||
}
|
||||
cb_enabled = true;
|
||||
}
|
||||
spin_unlock(&vioch->lock);
|
||||
spin_unlock_irqrestore(&vioch->lock, flags);
|
||||
|
||||
if (msg) {
|
||||
msg->rx_len = length;
|
||||
|
@ -161,19 +308,57 @@ static void scmi_vio_complete_cb(struct virtqueue *vqueue)
|
|||
}
|
||||
|
||||
/*
|
||||
* Release ready_lock and re-enable IRQs between loop iterations
|
||||
* to allow virtio_chan_free() to possibly kick in and set the
|
||||
* flag vioch->ready to false even in between processing of
|
||||
* messages, so as to force outstanding messages to be ignored
|
||||
* when system is shutting down.
|
||||
* Release vio channel between loop iterations to allow
|
||||
* virtio_chan_free() to eventually fully release it when
|
||||
* shutting down; in such a case, any outstanding message will
|
||||
* be ignored since this loop will bail out at the next
|
||||
* iteration.
|
||||
*/
|
||||
spin_unlock_irqrestore(&vioch->ready_lock, ready_flags);
|
||||
scmi_vio_channel_release(vioch);
|
||||
}
|
||||
}
|
||||
|
||||
static void scmi_vio_deferred_tx_worker(struct work_struct *work)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct scmi_vio_channel *vioch;
|
||||
struct scmi_vio_msg *msg, *tmp;
|
||||
|
||||
vioch = container_of(work, struct scmi_vio_channel, deferred_tx_work);
|
||||
|
||||
if (!scmi_vio_channel_acquire(vioch))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Process pre-fetched messages: these could be non-polled messages or
|
||||
* late timed-out replies to polled messages dequeued by chance while
|
||||
* polling for some other messages: this worker is in charge to process
|
||||
* the valid non-expired messages and anyway finally free all of them.
|
||||
*/
|
||||
spin_lock_irqsave(&vioch->pending_lock, flags);
|
||||
|
||||
/* Scan the list of possibly pre-fetched messages during polling. */
|
||||
list_for_each_entry_safe(msg, tmp, &vioch->pending_cmds_list, list) {
|
||||
list_del(&msg->list);
|
||||
|
||||
/*
|
||||
* Channel is acquired here (cannot vanish) and this message
|
||||
* is no more processed elsewhere so no poll_lock needed.
|
||||
*/
|
||||
if (msg->poll_status == VIO_MSG_NOT_POLLED)
|
||||
scmi_rx_callback(vioch->cinfo,
|
||||
msg_read_header(msg->input), msg);
|
||||
|
||||
/* Free the processed message once done */
|
||||
scmi_vio_msg_release(vioch, msg);
|
||||
}
|
||||
|
||||
unlock_out:
|
||||
spin_unlock(&vioch->lock);
|
||||
unlock_ready_out:
|
||||
spin_unlock_irqrestore(&vioch->ready_lock, ready_flags);
|
||||
spin_unlock_irqrestore(&vioch->pending_lock, flags);
|
||||
|
||||
/* Process possibly still pending messages */
|
||||
scmi_vio_complete_cb(vioch->vqueue);
|
||||
|
||||
scmi_vio_channel_release(vioch);
|
||||
}
|
||||
|
||||
static const char *const scmi_vio_vqueue_names[] = { "tx", "rx" };
|
||||
|
@ -193,8 +378,8 @@ static unsigned int virtio_get_max_msg(struct scmi_chan_info *base_cinfo)
|
|||
static int virtio_link_supplier(struct device *dev)
|
||||
{
|
||||
if (!scmi_vdev) {
|
||||
dev_notice_once(dev,
|
||||
"Deferring probe after not finding a bound scmi-virtio device\n");
|
||||
dev_notice(dev,
|
||||
"Deferring probe after not finding a bound scmi-virtio device\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
|
@ -234,7 +419,6 @@ static bool virtio_chan_available(struct device *dev, int idx)
|
|||
static int virtio_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
|
||||
bool tx)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct scmi_vio_channel *vioch;
|
||||
int index = tx ? VIRTIO_SCMI_VQ_TX : VIRTIO_SCMI_VQ_RX;
|
||||
int i;
|
||||
|
@ -244,6 +428,19 @@ static int virtio_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
|
|||
|
||||
vioch = &((struct scmi_vio_channel *)scmi_vdev->priv)[index];
|
||||
|
||||
/* Setup a deferred worker for polling. */
|
||||
if (tx && !vioch->deferred_tx_wq) {
|
||||
vioch->deferred_tx_wq =
|
||||
alloc_workqueue(dev_name(&scmi_vdev->dev),
|
||||
WQ_UNBOUND | WQ_FREEZABLE | WQ_SYSFS,
|
||||
0);
|
||||
if (!vioch->deferred_tx_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_WORK(&vioch->deferred_tx_work,
|
||||
scmi_vio_deferred_tx_worker);
|
||||
}
|
||||
|
||||
for (i = 0; i < vioch->max_msg; i++) {
|
||||
struct scmi_vio_msg *msg;
|
||||
|
||||
|
@ -257,6 +454,8 @@ static int virtio_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
|
|||
GFP_KERNEL);
|
||||
if (!msg->request)
|
||||
return -ENOMEM;
|
||||
spin_lock_init(&msg->poll_lock);
|
||||
refcount_set(&msg->users, 1);
|
||||
}
|
||||
|
||||
msg->input = devm_kzalloc(cinfo->dev, VIRTIO_SCMI_MAX_PDU_SIZE,
|
||||
|
@ -264,44 +463,23 @@ static int virtio_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
|
|||
if (!msg->input)
|
||||
return -ENOMEM;
|
||||
|
||||
if (tx) {
|
||||
spin_lock_irqsave(&vioch->lock, flags);
|
||||
list_add_tail(&msg->list, &vioch->free_list);
|
||||
spin_unlock_irqrestore(&vioch->lock, flags);
|
||||
} else {
|
||||
scmi_vio_feed_vq_rx(vioch, msg, cinfo->dev);
|
||||
}
|
||||
scmi_finalize_message(vioch, msg);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&vioch->lock, flags);
|
||||
cinfo->transport_info = vioch;
|
||||
/* Indirectly setting channel not available any more */
|
||||
vioch->cinfo = cinfo;
|
||||
spin_unlock_irqrestore(&vioch->lock, flags);
|
||||
|
||||
spin_lock_irqsave(&vioch->ready_lock, flags);
|
||||
vioch->ready = true;
|
||||
spin_unlock_irqrestore(&vioch->ready_lock, flags);
|
||||
scmi_vio_channel_ready(vioch, cinfo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_chan_free(int id, void *p, void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct scmi_chan_info *cinfo = p;
|
||||
struct scmi_vio_channel *vioch = cinfo->transport_info;
|
||||
|
||||
spin_lock_irqsave(&vioch->ready_lock, flags);
|
||||
vioch->ready = false;
|
||||
spin_unlock_irqrestore(&vioch->ready_lock, flags);
|
||||
scmi_vio_channel_cleanup_sync(vioch);
|
||||
|
||||
scmi_free_channel(cinfo, data, id);
|
||||
|
||||
spin_lock_irqsave(&vioch->lock, flags);
|
||||
vioch->cinfo = NULL;
|
||||
spin_unlock_irqrestore(&vioch->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -316,33 +494,56 @@ static int virtio_send_message(struct scmi_chan_info *cinfo,
|
|||
int rc;
|
||||
struct scmi_vio_msg *msg;
|
||||
|
||||
spin_lock_irqsave(&vioch->lock, flags);
|
||||
if (!scmi_vio_channel_acquire(vioch))
|
||||
return -EINVAL;
|
||||
|
||||
if (list_empty(&vioch->free_list)) {
|
||||
spin_unlock_irqrestore(&vioch->lock, flags);
|
||||
msg = scmi_virtio_get_free_msg(vioch);
|
||||
if (!msg) {
|
||||
scmi_vio_channel_release(vioch);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
msg = list_first_entry(&vioch->free_list, typeof(*msg), list);
|
||||
list_del(&msg->list);
|
||||
|
||||
msg_tx_prepare(msg->request, xfer);
|
||||
|
||||
sg_init_one(&sg_out, msg->request, msg_command_size(xfer));
|
||||
sg_init_one(&sg_in, msg->input, msg_response_size(xfer));
|
||||
|
||||
rc = virtqueue_add_sgs(vioch->vqueue, sgs, 1, 1, msg, GFP_ATOMIC);
|
||||
if (rc) {
|
||||
list_add(&msg->list, &vioch->free_list);
|
||||
dev_err_once(vioch->cinfo->dev,
|
||||
"%s() failed to add to virtqueue (%d)\n", __func__,
|
||||
rc);
|
||||
} else {
|
||||
virtqueue_kick(vioch->vqueue);
|
||||
spin_lock_irqsave(&vioch->lock, flags);
|
||||
|
||||
/*
|
||||
* If polling was requested for this transaction:
|
||||
* - retrieve last used index (will be used as polling reference)
|
||||
* - bind the polled message to the xfer via .priv
|
||||
* - grab an additional msg refcount for the poll-path
|
||||
*/
|
||||
if (xfer->hdr.poll_completion) {
|
||||
msg->poll_idx = virtqueue_enable_cb_prepare(vioch->vqueue);
|
||||
/* Still no users, no need to acquire poll_lock */
|
||||
msg->poll_status = VIO_MSG_POLLING;
|
||||
scmi_vio_msg_acquire(msg);
|
||||
/* Ensure initialized msg is visibly bound to xfer */
|
||||
smp_store_mb(xfer->priv, msg);
|
||||
}
|
||||
|
||||
rc = virtqueue_add_sgs(vioch->vqueue, sgs, 1, 1, msg, GFP_ATOMIC);
|
||||
if (rc)
|
||||
dev_err(vioch->cinfo->dev,
|
||||
"failed to add to TX virtqueue (%d)\n", rc);
|
||||
else
|
||||
virtqueue_kick(vioch->vqueue);
|
||||
|
||||
spin_unlock_irqrestore(&vioch->lock, flags);
|
||||
|
||||
if (rc) {
|
||||
/* Ensure order between xfer->priv clear and vq feeding */
|
||||
smp_store_mb(xfer->priv, NULL);
|
||||
if (xfer->hdr.poll_completion)
|
||||
scmi_vio_msg_release(vioch, msg);
|
||||
scmi_vio_msg_release(vioch, msg);
|
||||
}
|
||||
|
||||
scmi_vio_channel_release(vioch);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -351,10 +552,8 @@ static void virtio_fetch_response(struct scmi_chan_info *cinfo,
|
|||
{
|
||||
struct scmi_vio_msg *msg = xfer->priv;
|
||||
|
||||
if (msg) {
|
||||
if (msg)
|
||||
msg_fetch_response(msg->input, msg->rx_len, xfer);
|
||||
xfer->priv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_fetch_notification(struct scmi_chan_info *cinfo,
|
||||
|
@ -362,10 +561,225 @@ static void virtio_fetch_notification(struct scmi_chan_info *cinfo,
|
|||
{
|
||||
struct scmi_vio_msg *msg = xfer->priv;
|
||||
|
||||
if (msg) {
|
||||
if (msg)
|
||||
msg_fetch_notification(msg->input, msg->rx_len, max_len, xfer);
|
||||
xfer->priv = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* virtio_mark_txdone - Mark transmission done
|
||||
*
|
||||
* Free only completed polling transfer messages.
|
||||
*
|
||||
* Note that in the SCMI VirtIO transport we never explicitly release still
|
||||
* outstanding but timed-out messages by forcibly re-adding them to the
|
||||
* free-list inside the TX code path; we instead let IRQ/RX callbacks, or the
|
||||
* TX deferred worker, eventually clean up such messages once, finally, a late
|
||||
* reply is received and discarded (if ever).
|
||||
*
|
||||
* This approach was deemed preferable since those pending timed-out buffers are
|
||||
* still effectively owned by the SCMI platform VirtIO device even after timeout
|
||||
* expiration: forcibly freeing and reusing them before they had been returned
|
||||
* explicitly by the SCMI platform could lead to subtle bugs due to message
|
||||
* corruption.
|
||||
* An SCMI platform VirtIO device which never returns message buffers is
|
||||
* anyway broken and it will quickly lead to exhaustion of available messages.
|
||||
*
|
||||
* For this same reason, here, we take care to free only the polled messages
|
||||
* that had been somehow replied (only if not by chance already processed on the
|
||||
* IRQ path - the initial scmi_vio_msg_release() takes care of this) and also
|
||||
* any timed-out polled message if that indeed appears to have been at least
|
||||
* dequeued from the virtqueues (VIO_MSG_POLL_DONE): this is needed since such
|
||||
* messages won't be freed elsewhere. Any other polled message is marked as
|
||||
* VIO_MSG_POLL_TIMEOUT.
|
||||
*
|
||||
* Possible late replies to timed-out polled messages will be eventually freed
|
||||
* by RX callbacks if delivered on the IRQ path or by the deferred TX worker if
|
||||
* dequeued on some other polling path.
|
||||
*
|
||||
* @cinfo: SCMI channel info
|
||||
* @ret: Transmission return code
|
||||
* @xfer: Transfer descriptor
|
||||
*/
|
||||
static void virtio_mark_txdone(struct scmi_chan_info *cinfo, int ret,
|
||||
struct scmi_xfer *xfer)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct scmi_vio_channel *vioch = cinfo->transport_info;
|
||||
struct scmi_vio_msg *msg = xfer->priv;
|
||||
|
||||
if (!msg || !scmi_vio_channel_acquire(vioch))
|
||||
return;
|
||||
|
||||
/* Ensure msg is unbound from xfer anyway at this point */
|
||||
smp_store_mb(xfer->priv, NULL);
|
||||
|
||||
/* Must be a polled xfer and not already freed on the IRQ path */
|
||||
if (!xfer->hdr.poll_completion || scmi_vio_msg_release(vioch, msg)) {
|
||||
scmi_vio_channel_release(vioch);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&msg->poll_lock, flags);
|
||||
/* Do not free timedout polled messages only if still inflight */
|
||||
if (ret != -ETIMEDOUT || msg->poll_status == VIO_MSG_POLL_DONE)
|
||||
scmi_vio_msg_release(vioch, msg);
|
||||
else if (msg->poll_status == VIO_MSG_POLLING)
|
||||
msg->poll_status = VIO_MSG_POLL_TIMEOUT;
|
||||
spin_unlock_irqrestore(&msg->poll_lock, flags);
|
||||
|
||||
scmi_vio_channel_release(vioch);
|
||||
}
|
||||
|
||||
/**
|
||||
* virtio_poll_done - Provide polling support for VirtIO transport
|
||||
*
|
||||
* @cinfo: SCMI channel info
|
||||
* @xfer: Reference to the transfer being poll for.
|
||||
*
|
||||
* VirtIO core provides a polling mechanism based only on last used indexes:
|
||||
* this means that it is possible to poll the virtqueues waiting for something
|
||||
* new to arrive from the host side, but the only way to check if the freshly
|
||||
* arrived buffer was indeed what we were waiting for is to compare the newly
|
||||
* arrived message descriptor with the one we are polling on.
|
||||
*
|
||||
* As a consequence it can happen to dequeue something different from the buffer
|
||||
* we were poll-waiting for: if that is the case such early fetched buffers are
|
||||
* then added to a the @pending_cmds_list list for later processing by a
|
||||
* dedicated deferred worker.
|
||||
*
|
||||
* So, basically, once something new is spotted we proceed to de-queue all the
|
||||
* freshly received used buffers until we found the one we were polling on, or,
|
||||
* we have 'seemingly' emptied the virtqueue; if some buffers are still pending
|
||||
* in the vqueue at the end of the polling loop (possible due to inherent races
|
||||
* in virtqueues handling mechanisms), we similarly kick the deferred worker
|
||||
* and let it process those, to avoid indefinitely looping in the .poll_done
|
||||
* busy-waiting helper.
|
||||
*
|
||||
* Finally, we delegate to the deferred worker also the final free of any timed
|
||||
* out reply to a polled message that we should dequeue.
|
||||
*
|
||||
* Note that, since we do NOT have per-message suppress notification mechanism,
|
||||
* the message we are polling for could be alternatively delivered via usual
|
||||
* IRQs callbacks on another core which happened to have IRQs enabled while we
|
||||
* are actively polling for it here: in such a case it will be handled as such
|
||||
* by scmi_rx_callback() and the polling loop in the SCMI Core TX path will be
|
||||
* transparently terminated anyway.
|
||||
*
|
||||
* Return: True once polling has successfully completed.
|
||||
*/
|
||||
static bool virtio_poll_done(struct scmi_chan_info *cinfo,
|
||||
struct scmi_xfer *xfer)
|
||||
{
|
||||
bool pending, found = false;
|
||||
unsigned int length, any_prefetched = 0;
|
||||
unsigned long flags;
|
||||
struct scmi_vio_msg *next_msg, *msg = xfer->priv;
|
||||
struct scmi_vio_channel *vioch = cinfo->transport_info;
|
||||
|
||||
if (!msg)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Processed already by other polling loop on another CPU ?
|
||||
*
|
||||
* Note that this message is acquired on the poll path so cannot vanish
|
||||
* while inside this loop iteration even if concurrently processed on
|
||||
* the IRQ path.
|
||||
*
|
||||
* Avoid to acquire poll_lock since polled_status can be changed
|
||||
* in a relevant manner only later in this same thread of execution:
|
||||
* any other possible changes made concurrently by other polling loops
|
||||
* or by a reply delivered on the IRQ path have no meaningful impact on
|
||||
* this loop iteration: in other words it is harmless to allow this
|
||||
* possible race but let has avoid spinlocking with irqs off in this
|
||||
* initial part of the polling loop.
|
||||
*/
|
||||
if (msg->poll_status == VIO_MSG_POLL_DONE)
|
||||
return true;
|
||||
|
||||
if (!scmi_vio_channel_acquire(vioch))
|
||||
return true;
|
||||
|
||||
/* Has cmdq index moved at all ? */
|
||||
pending = virtqueue_poll(vioch->vqueue, msg->poll_idx);
|
||||
if (!pending) {
|
||||
scmi_vio_channel_release(vioch);
|
||||
return false;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&vioch->lock, flags);
|
||||
virtqueue_disable_cb(vioch->vqueue);
|
||||
|
||||
/*
|
||||
* Process all new messages till the polled-for message is found OR
|
||||
* the vqueue is empty.
|
||||
*/
|
||||
while ((next_msg = virtqueue_get_buf(vioch->vqueue, &length))) {
|
||||
bool next_msg_done = false;
|
||||
|
||||
/*
|
||||
* Mark any dequeued buffer message as VIO_MSG_POLL_DONE so
|
||||
* that can be properly freed even on timeout in mark_txdone.
|
||||
*/
|
||||
spin_lock(&next_msg->poll_lock);
|
||||
if (next_msg->poll_status == VIO_MSG_POLLING) {
|
||||
next_msg->poll_status = VIO_MSG_POLL_DONE;
|
||||
next_msg_done = true;
|
||||
}
|
||||
spin_unlock(&next_msg->poll_lock);
|
||||
|
||||
next_msg->rx_len = length;
|
||||
/* Is the message we were polling for ? */
|
||||
if (next_msg == msg) {
|
||||
found = true;
|
||||
break;
|
||||
} else if (next_msg_done) {
|
||||
/* Skip the rest if this was another polled msg */
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enqueue for later processing any non-polled message and any
|
||||
* timed-out polled one that we happen to have dequeued.
|
||||
*/
|
||||
spin_lock(&next_msg->poll_lock);
|
||||
if (next_msg->poll_status == VIO_MSG_NOT_POLLED ||
|
||||
next_msg->poll_status == VIO_MSG_POLL_TIMEOUT) {
|
||||
spin_unlock(&next_msg->poll_lock);
|
||||
|
||||
any_prefetched++;
|
||||
spin_lock(&vioch->pending_lock);
|
||||
list_add_tail(&next_msg->list,
|
||||
&vioch->pending_cmds_list);
|
||||
spin_unlock(&vioch->pending_lock);
|
||||
} else {
|
||||
spin_unlock(&next_msg->poll_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When the polling loop has successfully terminated if something
|
||||
* else was queued in the meantime, it will be served by a deferred
|
||||
* worker OR by the normal IRQ/callback OR by other poll loops.
|
||||
*
|
||||
* If we are still looking for the polled reply, the polling index has
|
||||
* to be updated to the current vqueue last used index.
|
||||
*/
|
||||
if (found) {
|
||||
pending = !virtqueue_enable_cb(vioch->vqueue);
|
||||
} else {
|
||||
msg->poll_idx = virtqueue_enable_cb_prepare(vioch->vqueue);
|
||||
pending = virtqueue_poll(vioch->vqueue, msg->poll_idx);
|
||||
}
|
||||
|
||||
if (vioch->deferred_tx_wq && (any_prefetched || pending))
|
||||
queue_work(vioch->deferred_tx_wq, &vioch->deferred_tx_work);
|
||||
|
||||
spin_unlock_irqrestore(&vioch->lock, flags);
|
||||
|
||||
scmi_vio_channel_release(vioch);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static const struct scmi_transport_ops scmi_virtio_ops = {
|
||||
|
@ -377,6 +791,8 @@ static const struct scmi_transport_ops scmi_virtio_ops = {
|
|||
.send_message = virtio_send_message,
|
||||
.fetch_response = virtio_fetch_response,
|
||||
.fetch_notification = virtio_fetch_notification,
|
||||
.mark_txdone = virtio_mark_txdone,
|
||||
.poll_done = virtio_poll_done,
|
||||
};
|
||||
|
||||
static int scmi_vio_probe(struct virtio_device *vdev)
|
||||
|
@ -417,8 +833,10 @@ static int scmi_vio_probe(struct virtio_device *vdev)
|
|||
unsigned int sz;
|
||||
|
||||
spin_lock_init(&channels[i].lock);
|
||||
spin_lock_init(&channels[i].ready_lock);
|
||||
spin_lock_init(&channels[i].free_lock);
|
||||
INIT_LIST_HEAD(&channels[i].free_list);
|
||||
spin_lock_init(&channels[i].pending_lock);
|
||||
INIT_LIST_HEAD(&channels[i].pending_cmds_list);
|
||||
channels[i].vqueue = vqs[i];
|
||||
|
||||
sz = virtqueue_get_vring_size(channels[i].vqueue);
|
||||
|
@ -427,10 +845,10 @@ static int scmi_vio_probe(struct virtio_device *vdev)
|
|||
sz /= DESCRIPTORS_PER_TX_MSG;
|
||||
|
||||
if (sz > MSG_TOKEN_MAX) {
|
||||
dev_info_once(dev,
|
||||
"%s virtqueue could hold %d messages. Only %ld allowed to be pending.\n",
|
||||
channels[i].is_rx ? "rx" : "tx",
|
||||
sz, MSG_TOKEN_MAX);
|
||||
dev_info(dev,
|
||||
"%s virtqueue could hold %d messages. Only %ld allowed to be pending.\n",
|
||||
channels[i].is_rx ? "rx" : "tx",
|
||||
sz, MSG_TOKEN_MAX);
|
||||
sz = MSG_TOKEN_MAX;
|
||||
}
|
||||
channels[i].max_msg = sz;
|
||||
|
@ -460,12 +878,13 @@ static void scmi_vio_remove(struct virtio_device *vdev)
|
|||
|
||||
static int scmi_vio_validate(struct virtio_device *vdev)
|
||||
{
|
||||
#ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO_VERSION1_COMPLIANCE
|
||||
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
|
||||
dev_err(&vdev->dev,
|
||||
"device does not comply with spec version 1.x\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -503,7 +922,9 @@ const struct scmi_desc scmi_virtio_desc = {
|
|||
.transport_init = virtio_scmi_init,
|
||||
.transport_exit = virtio_scmi_exit,
|
||||
.ops = &scmi_virtio_ops,
|
||||
.max_rx_timeout_ms = 60000, /* for non-realtime virtio devices */
|
||||
/* for non-realtime virtio devices */
|
||||
.max_rx_timeout_ms = VIRTIO_MAX_RX_TIMEOUT_MS,
|
||||
.max_msg = 0, /* overridden by virtio_get_max_msg() */
|
||||
.max_msg_size = VIRTIO_SCMI_MAX_MSG_SIZE,
|
||||
.atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE),
|
||||
};
|
||||
|
|
|
@ -43,3 +43,48 @@ bool imx_sc_rm_is_resource_owned(struct imx_sc_ipc *ipc, u16 resource)
|
|||
return hdr->func;
|
||||
}
|
||||
EXPORT_SYMBOL(imx_sc_rm_is_resource_owned);
|
||||
|
||||
struct imx_sc_msg_rm_get_resource_owner {
|
||||
struct imx_sc_rpc_msg hdr;
|
||||
union {
|
||||
struct {
|
||||
u16 resource;
|
||||
} req;
|
||||
struct {
|
||||
u8 val;
|
||||
} resp;
|
||||
} data;
|
||||
} __packed __aligned(4);
|
||||
|
||||
/*
|
||||
* This function get @resource partition number
|
||||
*
|
||||
* @param[in] ipc IPC handle
|
||||
* @param[in] resource resource the control is associated with
|
||||
* @param[out] pt pointer to return the partition number
|
||||
*
|
||||
* @return Returns 0 for success and < 0 for errors.
|
||||
*/
|
||||
int imx_sc_rm_get_resource_owner(struct imx_sc_ipc *ipc, u16 resource, u8 *pt)
|
||||
{
|
||||
struct imx_sc_msg_rm_get_resource_owner msg;
|
||||
struct imx_sc_rpc_msg *hdr = &msg.hdr;
|
||||
int ret;
|
||||
|
||||
hdr->ver = IMX_SC_RPC_VERSION;
|
||||
hdr->svc = IMX_SC_RPC_SVC_RM;
|
||||
hdr->func = IMX_SC_RM_FUNC_GET_RESOURCE_OWNER;
|
||||
hdr->size = 2;
|
||||
|
||||
msg.data.req.resource = resource;
|
||||
|
||||
ret = imx_scu_call_rpc(ipc, &msg, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pt)
|
||||
*pt = msg.data.resp.val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(imx_sc_rm_get_resource_owner);
|
||||
|
|
|
@ -155,6 +155,10 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
|
|||
{ "vpu-pid", IMX_SC_R_VPU_PID0, 8, true, 0 },
|
||||
{ "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, false, 0 },
|
||||
{ "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, false, 0 },
|
||||
{ "vpu-enc1", IMX_SC_R_VPU_ENC_1, 1, false, 0 },
|
||||
{ "vpu-mu0", IMX_SC_R_VPU_MU_0, 1, false, 0 },
|
||||
{ "vpu-mu1", IMX_SC_R_VPU_MU_1, 1, false, 0 },
|
||||
{ "vpu-mu2", IMX_SC_R_VPU_MU_2, 1, false, 0 },
|
||||
|
||||
/* GPU SS */
|
||||
{ "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, true, 0 },
|
||||
|
|
|
@ -49,26 +49,12 @@ struct qcom_scm_mem_map_info {
|
|||
__le64 mem_size;
|
||||
};
|
||||
|
||||
#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00
|
||||
#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01
|
||||
#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
|
||||
#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
|
||||
|
||||
#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
|
||||
#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
|
||||
#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
|
||||
#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
|
||||
|
||||
struct qcom_scm_wb_entry {
|
||||
int flag;
|
||||
void *entry;
|
||||
/* Each bit configures cold/warm boot address for one of the 4 CPUs */
|
||||
static const u8 qcom_scm_cpu_cold_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
|
||||
0, BIT(0), BIT(3), BIT(5)
|
||||
};
|
||||
|
||||
static struct qcom_scm_wb_entry qcom_scm_wb[] = {
|
||||
{ .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
|
||||
{ .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
|
||||
{ .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
|
||||
{ .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
|
||||
static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
|
||||
BIT(2), BIT(1), BIT(4), BIT(6)
|
||||
};
|
||||
|
||||
static const char * const qcom_scm_convention_names[] = {
|
||||
|
@ -179,9 +165,8 @@ found:
|
|||
/**
|
||||
* qcom_scm_call() - Invoke a syscall in the secure world
|
||||
* @dev: device
|
||||
* @svc_id: service identifier
|
||||
* @cmd_id: command identifier
|
||||
* @desc: Descriptor structure containing arguments and return values
|
||||
* @res: Structure containing results from SMC/HVC call
|
||||
*
|
||||
* Sends a command to the SCM and waits for the command to finish processing.
|
||||
* This should *only* be called in pre-emptible context.
|
||||
|
@ -205,8 +190,6 @@ static int qcom_scm_call(struct device *dev, const struct qcom_scm_desc *desc,
|
|||
/**
|
||||
* qcom_scm_call_atomic() - atomic variation of qcom_scm_call()
|
||||
* @dev: device
|
||||
* @svc_id: service identifier
|
||||
* @cmd_id: command identifier
|
||||
* @desc: Descriptor structure containing arguments and return values
|
||||
* @res: Structure containing results from SMC/HVC call
|
||||
*
|
||||
|
@ -260,70 +243,10 @@ static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
|
|||
return ret ? false : !!res.result[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
|
||||
* @entry: Entry point function for the cpus
|
||||
* @cpus: The cpumask of cpus that will use the entry point
|
||||
*
|
||||
* Set the Linux entry point for the SCM to transfer control to when coming
|
||||
* out of a power down. CPU power down may be executed on cpuidle or hotplug.
|
||||
*/
|
||||
int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
|
||||
static int qcom_scm_set_boot_addr(void *entry, const u8 *cpu_bits)
|
||||
{
|
||||
int ret;
|
||||
int flags = 0;
|
||||
int cpu;
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_BOOT,
|
||||
.cmd = QCOM_SCM_BOOT_SET_ADDR,
|
||||
.arginfo = QCOM_SCM_ARGS(2),
|
||||
};
|
||||
|
||||
/*
|
||||
* Reassign only if we are switching from hotplug entry point
|
||||
* to cpuidle entry point or vice versa.
|
||||
*/
|
||||
for_each_cpu(cpu, cpus) {
|
||||
if (entry == qcom_scm_wb[cpu].entry)
|
||||
continue;
|
||||
flags |= qcom_scm_wb[cpu].flag;
|
||||
}
|
||||
|
||||
/* No change in entry function */
|
||||
if (!flags)
|
||||
return 0;
|
||||
|
||||
desc.args[0] = flags;
|
||||
desc.args[1] = virt_to_phys(entry);
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, NULL);
|
||||
if (!ret) {
|
||||
for_each_cpu(cpu, cpus)
|
||||
qcom_scm_wb[cpu].entry = entry;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
|
||||
|
||||
/**
|
||||
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
|
||||
* @entry: Entry point function for the cpus
|
||||
* @cpus: The cpumask of cpus that will use the entry point
|
||||
*
|
||||
* Set the cold boot address of the cpus. Any cpu outside the supported
|
||||
* range would be removed from the cpu present mask.
|
||||
*/
|
||||
int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
|
||||
{
|
||||
int flags = 0;
|
||||
int cpu;
|
||||
int scm_cb_flags[] = {
|
||||
QCOM_SCM_FLAG_COLDBOOT_CPU0,
|
||||
QCOM_SCM_FLAG_COLDBOOT_CPU1,
|
||||
QCOM_SCM_FLAG_COLDBOOT_CPU2,
|
||||
QCOM_SCM_FLAG_COLDBOOT_CPU3,
|
||||
};
|
||||
unsigned int flags = 0;
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_BOOT,
|
||||
.cmd = QCOM_SCM_BOOT_SET_ADDR,
|
||||
|
@ -331,14 +254,10 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
|
|||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
};
|
||||
|
||||
if (!cpus || cpumask_empty(cpus))
|
||||
return -EINVAL;
|
||||
|
||||
for_each_cpu(cpu, cpus) {
|
||||
if (cpu < ARRAY_SIZE(scm_cb_flags))
|
||||
flags |= scm_cb_flags[cpu];
|
||||
else
|
||||
set_cpu_present(cpu, false);
|
||||
for_each_present_cpu(cpu) {
|
||||
if (cpu >= QCOM_SCM_BOOT_MAX_CPUS)
|
||||
return -EINVAL;
|
||||
flags |= cpu_bits[cpu];
|
||||
}
|
||||
|
||||
desc.args[0] = flags;
|
||||
|
@ -346,11 +265,61 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
|
|||
|
||||
return qcom_scm_call_atomic(__scm ? __scm->dev : NULL, &desc, NULL);
|
||||
}
|
||||
|
||||
static int qcom_scm_set_boot_addr_mc(void *entry, unsigned int flags)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_BOOT,
|
||||
.cmd = QCOM_SCM_BOOT_SET_ADDR_MC,
|
||||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
.arginfo = QCOM_SCM_ARGS(6),
|
||||
.args = {
|
||||
virt_to_phys(entry),
|
||||
/* Apply to all CPUs in all affinity levels */
|
||||
~0ULL, ~0ULL, ~0ULL, ~0ULL,
|
||||
flags,
|
||||
},
|
||||
};
|
||||
|
||||
/* Need a device for DMA of the additional arguments */
|
||||
if (!__scm || __get_convention() == SMC_CONVENTION_LEGACY)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return qcom_scm_call(__scm->dev, &desc, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* qcom_scm_set_warm_boot_addr() - Set the warm boot address for all cpus
|
||||
* @entry: Entry point function for the cpus
|
||||
*
|
||||
* Set the Linux entry point for the SCM to transfer control to when coming
|
||||
* out of a power down. CPU power down may be executed on cpuidle or hotplug.
|
||||
*/
|
||||
int qcom_scm_set_warm_boot_addr(void *entry)
|
||||
{
|
||||
if (qcom_scm_set_boot_addr_mc(entry, QCOM_SCM_BOOT_MC_FLAG_WARMBOOT))
|
||||
/* Fallback to old SCM call */
|
||||
return qcom_scm_set_boot_addr(entry, qcom_scm_cpu_warm_bits);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
|
||||
|
||||
/**
|
||||
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for all cpus
|
||||
* @entry: Entry point function for the cpus
|
||||
*/
|
||||
int qcom_scm_set_cold_boot_addr(void *entry)
|
||||
{
|
||||
if (qcom_scm_set_boot_addr_mc(entry, QCOM_SCM_BOOT_MC_FLAG_COLDBOOT))
|
||||
/* Fallback to old SCM call */
|
||||
return qcom_scm_set_boot_addr(entry, qcom_scm_cpu_cold_bits);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr);
|
||||
|
||||
/**
|
||||
* qcom_scm_cpu_power_down() - Power down the cpu
|
||||
* @flags - Flags to flush cache
|
||||
* @flags: Flags to flush cache
|
||||
*
|
||||
* This is an end point to power down cpu. If there was a pending interrupt,
|
||||
* the control would return from this function, otherwise, the cpu jumps to the
|
||||
|
@ -435,10 +404,16 @@ static void qcom_scm_set_download_mode(bool enable)
|
|||
* and optional blob of data used for authenticating the metadata
|
||||
* and the rest of the firmware
|
||||
* @size: size of the metadata
|
||||
* @ctx: optional metadata context
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Return: 0 on success.
|
||||
*
|
||||
* Upon successful return, the PAS metadata context (@ctx) will be used to
|
||||
* track the metadata allocation, this needs to be released by invoking
|
||||
* qcom_scm_pas_metadata_release() by the caller.
|
||||
*/
|
||||
int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size)
|
||||
int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size,
|
||||
struct qcom_scm_pas_metadata *ctx)
|
||||
{
|
||||
dma_addr_t mdata_phys;
|
||||
void *mdata_buf;
|
||||
|
@ -467,7 +442,7 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size)
|
|||
|
||||
ret = qcom_scm_clk_enable();
|
||||
if (ret)
|
||||
goto free_metadata;
|
||||
goto out;
|
||||
|
||||
desc.args[1] = mdata_phys;
|
||||
|
||||
|
@ -475,13 +450,36 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size)
|
|||
|
||||
qcom_scm_clk_disable();
|
||||
|
||||
free_metadata:
|
||||
dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
|
||||
out:
|
||||
if (ret < 0 || !ctx) {
|
||||
dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
|
||||
} else if (ctx) {
|
||||
ctx->ptr = mdata_buf;
|
||||
ctx->phys = mdata_phys;
|
||||
ctx->size = size;
|
||||
}
|
||||
|
||||
return ret ? : res.result[0];
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_scm_pas_init_image);
|
||||
|
||||
/**
|
||||
* qcom_scm_pas_metadata_release() - release metadata context
|
||||
* @ctx: metadata context
|
||||
*/
|
||||
void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx)
|
||||
{
|
||||
if (!ctx->ptr)
|
||||
return;
|
||||
|
||||
dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys);
|
||||
|
||||
ctx->ptr = NULL;
|
||||
ctx->phys = 0;
|
||||
ctx->size = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_scm_pas_metadata_release);
|
||||
|
||||
/**
|
||||
* qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral
|
||||
* for firmware loading
|
||||
|
@ -749,12 +747,6 @@ int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
|
|||
};
|
||||
int ret;
|
||||
|
||||
desc.args[0] = addr;
|
||||
desc.args[1] = size;
|
||||
desc.args[2] = spare;
|
||||
desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL,
|
||||
QCOM_SCM_VAL);
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, NULL);
|
||||
|
||||
/* the pg table has been initialized already, ignore the error */
|
||||
|
@ -765,6 +757,21 @@ int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
|
|||
}
|
||||
EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);
|
||||
|
||||
int qcom_scm_iommu_set_cp_pool_size(u32 spare, u32 size)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_MP,
|
||||
.cmd = QCOM_SCM_MP_IOMMU_SET_CP_POOL_SIZE,
|
||||
.arginfo = QCOM_SCM_ARGS(2),
|
||||
.args[0] = size,
|
||||
.args[1] = spare,
|
||||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
};
|
||||
|
||||
return qcom_scm_call(__scm->dev, &desc, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_scm_iommu_set_cp_pool_size);
|
||||
|
||||
int qcom_scm_mem_protect_video_var(u32 cp_start, u32 cp_size,
|
||||
u32 cp_nonpixel_start,
|
||||
u32 cp_nonpixel_size)
|
||||
|
@ -1131,6 +1138,22 @@ int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
|
|||
}
|
||||
EXPORT_SYMBOL(qcom_scm_hdcp_req);
|
||||
|
||||
int qcom_scm_iommu_set_pt_format(u32 sec_id, u32 ctx_num, u32 pt_fmt)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_SMMU_PROGRAM,
|
||||
.cmd = QCOM_SCM_SMMU_PT_FORMAT,
|
||||
.arginfo = QCOM_SCM_ARGS(3),
|
||||
.args[0] = sec_id,
|
||||
.args[1] = ctx_num,
|
||||
.args[2] = pt_fmt, /* 0: LPAE AArch32 - 1: AArch64 */
|
||||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
};
|
||||
|
||||
return qcom_scm_call(__scm->dev, &desc, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_scm_iommu_set_pt_format);
|
||||
|
||||
int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
|
|
|
@ -78,8 +78,13 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
|
|||
#define QCOM_SCM_BOOT_SET_ADDR 0x01
|
||||
#define QCOM_SCM_BOOT_TERMINATE_PC 0x02
|
||||
#define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10
|
||||
#define QCOM_SCM_BOOT_SET_ADDR_MC 0x11
|
||||
#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a
|
||||
#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
|
||||
#define QCOM_SCM_BOOT_MAX_CPUS 4
|
||||
#define QCOM_SCM_BOOT_MC_FLAG_AARCH64 BIT(0)
|
||||
#define QCOM_SCM_BOOT_MC_FLAG_COLDBOOT BIT(1)
|
||||
#define QCOM_SCM_BOOT_MC_FLAG_WARMBOOT BIT(2)
|
||||
|
||||
#define QCOM_SCM_SVC_PIL 0x02
|
||||
#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x01
|
||||
|
@ -100,6 +105,7 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
|
|||
#define QCOM_SCM_MP_RESTORE_SEC_CFG 0x02
|
||||
#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE 0x03
|
||||
#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT 0x04
|
||||
#define QCOM_SCM_MP_IOMMU_SET_CP_POOL_SIZE 0x05
|
||||
#define QCOM_SCM_MP_VIDEO_VAR 0x08
|
||||
#define QCOM_SCM_MP_ASSIGN 0x16
|
||||
|
||||
|
@ -119,6 +125,7 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
|
|||
#define QCOM_SCM_LMH_LIMIT_DCVSH 0x10
|
||||
|
||||
#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
|
||||
#define QCOM_SCM_SMMU_PT_FORMAT 0x01
|
||||
#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x03
|
||||
#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x02
|
||||
|
||||
|
|
|
@ -3412,7 +3412,7 @@ static int ti_sci_probe(struct platform_device *pdev)
|
|||
ret = register_restart_handler(&info->nb);
|
||||
if (ret) {
|
||||
dev_err(dev, "reboot registration fail(%d)\n", ret);
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -424,7 +424,7 @@ static void __finalize_command(struct brcmstb_dpfe_priv *priv)
|
|||
|
||||
/*
|
||||
* It depends on the API version which MBOX register we have to write to
|
||||
* to signal we are done.
|
||||
* signal we are done.
|
||||
*/
|
||||
release_mbox = (priv->dpfe_api->version < 2)
|
||||
? REG_TO_HOST_MBOX : REG_TO_DCPU_MBOX;
|
||||
|
|
|
@ -1025,7 +1025,7 @@ static struct emif_data *__init_or_module get_device_details(
|
|||
temp = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
|
||||
dev_info = devm_kzalloc(dev, sizeof(*dev_info), GFP_KERNEL);
|
||||
|
||||
if (!emif || !pd || !dev_info) {
|
||||
if (!emif || !temp || !dev_info) {
|
||||
dev_err(dev, "%s:%d: allocation error\n", __func__, __LINE__);
|
||||
goto error;
|
||||
}
|
||||
|
@ -1117,7 +1117,7 @@ static int __init_or_module emif_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct emif_data *emif;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int irq, ret;
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
emif = of_get_memory_device_details(pdev->dev.of_node, &pdev->dev);
|
||||
|
@ -1147,7 +1147,9 @@ static int __init_or_module emif_probe(struct platform_device *pdev)
|
|||
emif_onetime_settings(emif);
|
||||
emif_debugfs_init(emif);
|
||||
disable_and_clear_all_interrupts(emif);
|
||||
setup_interrupts(emif, irq);
|
||||
ret = setup_interrupts(emif, irq);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
/* One-time actions taken on probing the first device */
|
||||
if (!emif1) {
|
||||
|
|
|
@ -88,6 +88,7 @@ static int fsl_ifc_ctrl_remove(struct platform_device *dev)
|
|||
{
|
||||
struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(&dev->dev);
|
||||
|
||||
of_platform_depopulate(&dev->dev);
|
||||
free_irq(ctrl->nand_irq, ctrl);
|
||||
free_irq(ctrl->irq, ctrl);
|
||||
|
||||
|
@ -285,8 +286,16 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
/* legacy dts may still use "simple-bus" compatible */
|
||||
ret = of_platform_populate(dev->dev.of_node, NULL, NULL,
|
||||
&dev->dev);
|
||||
if (ret)
|
||||
goto err_free_nandirq;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_nandirq:
|
||||
free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev);
|
||||
err_free_irq:
|
||||
free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
|
||||
err_unmap_nandirq:
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
@ -32,6 +33,10 @@
|
|||
#define SMI_DUMMY 0x444
|
||||
|
||||
/* SMI LARB */
|
||||
#define SMI_LARB_SLP_CON 0xc
|
||||
#define SLP_PROT_EN BIT(0)
|
||||
#define SLP_PROT_RDY BIT(16)
|
||||
|
||||
#define SMI_LARB_CMD_THRT_CON 0x24
|
||||
#define SMI_LARB_THRT_RD_NU_LMT_MSK GENMASK(7, 4)
|
||||
#define SMI_LARB_THRT_RD_NU_LMT (5 << 4)
|
||||
|
@ -81,6 +86,7 @@
|
|||
|
||||
#define MTK_SMI_FLAG_THRT_UPDATE BIT(0)
|
||||
#define MTK_SMI_FLAG_SW_FLAG BIT(1)
|
||||
#define MTK_SMI_FLAG_SLEEP_CTL BIT(2)
|
||||
#define MTK_SMI_CAPS(flags, _x) (!!((flags) & (_x)))
|
||||
|
||||
struct mtk_smi_reg_pair {
|
||||
|
@ -94,8 +100,6 @@ enum mtk_smi_type {
|
|||
MTK_SMI_GEN2_SUB_COMM, /* gen2 smi sub common */
|
||||
};
|
||||
|
||||
#define MTK_SMI_CLK_NR_MAX 4
|
||||
|
||||
/* larbs: Require apb/smi clocks while gals is optional. */
|
||||
static const char * const mtk_smi_larb_clks[] = {"apb", "smi", "gals"};
|
||||
#define MTK_SMI_LARB_REQ_CLK_NR 2
|
||||
|
@ -106,6 +110,7 @@ static const char * const mtk_smi_larb_clks[] = {"apb", "smi", "gals"};
|
|||
* sub common: Require apb/smi/gals0 clocks in has_gals case. Otherwise, only apb/smi are required.
|
||||
*/
|
||||
static const char * const mtk_smi_common_clks[] = {"apb", "smi", "gals0", "gals1"};
|
||||
#define MTK_SMI_CLK_NR_MAX ARRAY_SIZE(mtk_smi_common_clks)
|
||||
#define MTK_SMI_COM_REQ_CLK_NR 2
|
||||
#define MTK_SMI_COM_GALS_REQ_CLK_NR MTK_SMI_CLK_NR_MAX
|
||||
#define MTK_SMI_SUB_COM_GALS_REQ_CLK_NR 3
|
||||
|
@ -335,13 +340,19 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = {
|
|||
/* IPU0 | IPU1 | CCU */
|
||||
};
|
||||
|
||||
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8186 = {
|
||||
.config_port = mtk_smi_larb_config_port_gen2_general,
|
||||
.flags_general = MTK_SMI_FLAG_SLEEP_CTL,
|
||||
};
|
||||
|
||||
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8192 = {
|
||||
.config_port = mtk_smi_larb_config_port_gen2_general,
|
||||
};
|
||||
|
||||
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8195 = {
|
||||
.config_port = mtk_smi_larb_config_port_gen2_general,
|
||||
.flags_general = MTK_SMI_FLAG_THRT_UPDATE | MTK_SMI_FLAG_SW_FLAG,
|
||||
.flags_general = MTK_SMI_FLAG_THRT_UPDATE | MTK_SMI_FLAG_SW_FLAG |
|
||||
MTK_SMI_FLAG_SLEEP_CTL,
|
||||
.ostd = mtk_smi_larb_mt8195_ostd,
|
||||
};
|
||||
|
||||
|
@ -352,11 +363,32 @@ static const struct of_device_id mtk_smi_larb_of_ids[] = {
|
|||
{.compatible = "mediatek,mt8167-smi-larb", .data = &mtk_smi_larb_mt8167},
|
||||
{.compatible = "mediatek,mt8173-smi-larb", .data = &mtk_smi_larb_mt8173},
|
||||
{.compatible = "mediatek,mt8183-smi-larb", .data = &mtk_smi_larb_mt8183},
|
||||
{.compatible = "mediatek,mt8186-smi-larb", .data = &mtk_smi_larb_mt8186},
|
||||
{.compatible = "mediatek,mt8192-smi-larb", .data = &mtk_smi_larb_mt8192},
|
||||
{.compatible = "mediatek,mt8195-smi-larb", .data = &mtk_smi_larb_mt8195},
|
||||
{}
|
||||
};
|
||||
|
||||
static int mtk_smi_larb_sleep_ctrl_enable(struct mtk_smi_larb *larb)
|
||||
{
|
||||
int ret;
|
||||
u32 tmp;
|
||||
|
||||
writel_relaxed(SLP_PROT_EN, larb->base + SMI_LARB_SLP_CON);
|
||||
ret = readl_poll_timeout_atomic(larb->base + SMI_LARB_SLP_CON,
|
||||
tmp, !!(tmp & SLP_PROT_RDY), 10, 1000);
|
||||
if (ret) {
|
||||
/* TODO: Reset this larb if it fails here. */
|
||||
dev_err(larb->smi.dev, "sleep ctrl is not ready(0x%x).\n", tmp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mtk_smi_larb_sleep_ctrl_disable(struct mtk_smi_larb *larb)
|
||||
{
|
||||
writel_relaxed(0, larb->base + SMI_LARB_SLP_CON);
|
||||
}
|
||||
|
||||
static int mtk_smi_device_link_common(struct device *dev, struct device **com_dev)
|
||||
{
|
||||
struct platform_device *smi_com_pdev;
|
||||
|
@ -466,9 +498,12 @@ static int __maybe_unused mtk_smi_larb_resume(struct device *dev)
|
|||
int ret;
|
||||
|
||||
ret = clk_bulk_prepare_enable(larb->smi.clk_num, larb->smi.clks);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (MTK_SMI_CAPS(larb->larb_gen->flags_general, MTK_SMI_FLAG_SLEEP_CTL))
|
||||
mtk_smi_larb_sleep_ctrl_disable(larb);
|
||||
|
||||
/* Configure the basic setting for this larb */
|
||||
larb_gen->config_port(dev);
|
||||
|
||||
|
@ -478,6 +513,13 @@ static int __maybe_unused mtk_smi_larb_resume(struct device *dev)
|
|||
static int __maybe_unused mtk_smi_larb_suspend(struct device *dev)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (MTK_SMI_CAPS(larb->larb_gen->flags_general, MTK_SMI_FLAG_SLEEP_CTL)) {
|
||||
ret = mtk_smi_larb_sleep_ctrl_enable(larb);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk_bulk_disable_unprepare(larb->smi.clk_num, larb->smi.clks);
|
||||
return 0;
|
||||
|
@ -530,6 +572,12 @@ static const struct mtk_smi_common_plat mtk_smi_common_mt8183 = {
|
|||
F_MMU1_LARB(7),
|
||||
};
|
||||
|
||||
static const struct mtk_smi_common_plat mtk_smi_common_mt8186 = {
|
||||
.type = MTK_SMI_GEN2,
|
||||
.has_gals = true,
|
||||
.bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(4) | F_MMU1_LARB(7),
|
||||
};
|
||||
|
||||
static const struct mtk_smi_common_plat mtk_smi_common_mt8192 = {
|
||||
.type = MTK_SMI_GEN2,
|
||||
.has_gals = true,
|
||||
|
@ -564,6 +612,7 @@ static const struct of_device_id mtk_smi_common_of_ids[] = {
|
|||
{.compatible = "mediatek,mt8167-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,mt8186-smi-common", .data = &mtk_smi_common_mt8186},
|
||||
{.compatible = "mediatek,mt8192-smi-common", .data = &mtk_smi_common_mt8192},
|
||||
{.compatible = "mediatek,mt8195-smi-common-vdo", .data = &mtk_smi_common_mt8195_vdo},
|
||||
{.compatible = "mediatek,mt8195-smi-common-vpp", .data = &mtk_smi_common_mt8195_vpp},
|
||||
|
|
|
@ -212,8 +212,10 @@ static int of_lpddr3_do_get_timings(struct device_node *np,
|
|||
{
|
||||
int ret;
|
||||
|
||||
/* The 'reg' param required since DT has changed, used as 'max-freq' */
|
||||
ret = of_property_read_u32(np, "reg", &tim->max_freq);
|
||||
ret = of_property_read_u32(np, "max-freq", &tim->max_freq);
|
||||
if (ret)
|
||||
/* Deprecated way of passing max-freq as 'reg' */
|
||||
ret = of_property_read_u32(np, "reg", &tim->max_freq);
|
||||
ret |= of_property_read_u32(np, "min-freq", &tim->min_freq);
|
||||
ret |= of_property_read_u32(np, "tRFC", &tim->tRFC);
|
||||
ret |= of_property_read_u32(np, "tRRD", &tim->tRRD);
|
||||
|
@ -316,14 +318,21 @@ const struct lpddr2_info
|
|||
struct property *prop;
|
||||
const char *cp;
|
||||
int err;
|
||||
u32 revision_id[2];
|
||||
|
||||
err = of_property_read_u32(np, "revision-id1", &info.revision_id1);
|
||||
if (err)
|
||||
info.revision_id1 = -ENOENT;
|
||||
err = of_property_read_u32_array(np, "revision-id", revision_id, 2);
|
||||
if (!err) {
|
||||
info.revision_id1 = revision_id[0];
|
||||
info.revision_id2 = revision_id[1];
|
||||
} else {
|
||||
err = of_property_read_u32(np, "revision-id1", &info.revision_id1);
|
||||
if (err)
|
||||
info.revision_id1 = -ENOENT;
|
||||
|
||||
err = of_property_read_u32(np, "revision-id2", &info.revision_id2);
|
||||
if (err)
|
||||
info.revision_id2 = -ENOENT;
|
||||
err = of_property_read_u32(np, "revision-id2", &info.revision_id2);
|
||||
if (err)
|
||||
info.revision_id2 = -ENOENT;
|
||||
}
|
||||
|
||||
err = of_property_read_u32(np, "io-width", &info.io_width);
|
||||
if (err)
|
||||
|
|
|
@ -28,6 +28,7 @@ config TEGRA30_EMC
|
|||
default y
|
||||
depends on ARCH_TEGRA_3x_SOC || COMPILE_TEST
|
||||
select PM_OPP
|
||||
select DDR
|
||||
help
|
||||
This driver is for the External Memory Controller (EMC) found on
|
||||
Tegra30 chips. The EMC controls the external DRAM on the board.
|
||||
|
|
|
@ -540,7 +540,7 @@ static int emc_read_lpddr_mode_register(struct tegra_emc *emc,
|
|||
unsigned int register_addr,
|
||||
unsigned int *register_data)
|
||||
{
|
||||
u32 memory_dev = emem_dev + 1;
|
||||
u32 memory_dev = emem_dev ? 1 : 2;
|
||||
u32 val, mr_mask = 0xff;
|
||||
int err;
|
||||
|
||||
|
|
|
@ -711,7 +711,7 @@ static int tegra210_emc_cd_set_state(struct thermal_cooling_device *cd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_cooling_device_ops tegra210_emc_cd_ops = {
|
||||
static const struct thermal_cooling_device_ops tegra210_emc_cd_ops = {
|
||||
.get_max_state = tegra210_emc_cd_max_state,
|
||||
.get_cur_state = tegra210_emc_cd_get_state,
|
||||
.set_cur_state = tegra210_emc_cd_set_state,
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
* Copyright (C) 2019 GRATE-DRIVER project
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
@ -31,11 +32,15 @@
|
|||
#include <soc/tegra/common.h>
|
||||
#include <soc/tegra/fuse.h>
|
||||
|
||||
#include "../jedec_ddr.h"
|
||||
#include "../of_memory.h"
|
||||
|
||||
#include "mc.h"
|
||||
|
||||
#define EMC_INTSTATUS 0x000
|
||||
#define EMC_INTMASK 0x004
|
||||
#define EMC_DBG 0x008
|
||||
#define EMC_ADR_CFG 0x010
|
||||
#define EMC_CFG 0x00c
|
||||
#define EMC_REFCTRL 0x020
|
||||
#define EMC_TIMING_CONTROL 0x028
|
||||
|
@ -81,6 +86,7 @@
|
|||
#define EMC_EMRS 0x0d0
|
||||
#define EMC_SELF_REF 0x0e0
|
||||
#define EMC_MRW 0x0e8
|
||||
#define EMC_MRR 0x0ec
|
||||
#define EMC_XM2DQSPADCTRL3 0x0f8
|
||||
#define EMC_FBIO_SPARE 0x100
|
||||
#define EMC_FBIO_CFG5 0x104
|
||||
|
@ -208,6 +214,13 @@
|
|||
|
||||
#define EMC_REFRESH_OVERFLOW_INT BIT(3)
|
||||
#define EMC_CLKCHANGE_COMPLETE_INT BIT(4)
|
||||
#define EMC_MRR_DIVLD_INT BIT(5)
|
||||
|
||||
#define EMC_MRR_DEV_SELECTN GENMASK(31, 30)
|
||||
#define EMC_MRR_MRR_MA GENMASK(23, 16)
|
||||
#define EMC_MRR_MRR_DATA GENMASK(15, 0)
|
||||
|
||||
#define EMC_ADR_CFG_EMEM_NUMDEV BIT(0)
|
||||
|
||||
enum emc_dram_type {
|
||||
DRAM_TYPE_DDR3,
|
||||
|
@ -378,6 +391,8 @@ struct tegra_emc {
|
|||
|
||||
/* protect shared rate-change code path */
|
||||
struct mutex rate_lock;
|
||||
|
||||
bool mrr_error;
|
||||
};
|
||||
|
||||
static int emc_seq_update_timing(struct tegra_emc *emc)
|
||||
|
@ -1008,12 +1023,18 @@ static int emc_load_timings_from_dt(struct tegra_emc *emc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct device_node *emc_find_node_by_ram_code(struct device *dev)
|
||||
static struct device_node *emc_find_node_by_ram_code(struct tegra_emc *emc)
|
||||
{
|
||||
struct device *dev = emc->dev;
|
||||
struct device_node *np;
|
||||
u32 value, ram_code;
|
||||
int err;
|
||||
|
||||
if (emc->mrr_error) {
|
||||
dev_warn(dev, "memory timings skipped due to MRR error\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (of_get_child_count(dev->of_node) == 0) {
|
||||
dev_info_once(dev, "device-tree doesn't have memory timings\n");
|
||||
return NULL;
|
||||
|
@ -1035,11 +1056,73 @@ static struct device_node *emc_find_node_by_ram_code(struct device *dev)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int emc_read_lpddr_mode_register(struct tegra_emc *emc,
|
||||
unsigned int emem_dev,
|
||||
unsigned int register_addr,
|
||||
unsigned int *register_data)
|
||||
{
|
||||
u32 memory_dev = emem_dev ? 1 : 2;
|
||||
u32 val, mr_mask = 0xff;
|
||||
int err;
|
||||
|
||||
/* clear data-valid interrupt status */
|
||||
writel_relaxed(EMC_MRR_DIVLD_INT, emc->regs + EMC_INTSTATUS);
|
||||
|
||||
/* issue mode register read request */
|
||||
val = FIELD_PREP(EMC_MRR_DEV_SELECTN, memory_dev);
|
||||
val |= FIELD_PREP(EMC_MRR_MRR_MA, register_addr);
|
||||
|
||||
writel_relaxed(val, emc->regs + EMC_MRR);
|
||||
|
||||
/* wait for the LPDDR2 data-valid interrupt */
|
||||
err = readl_relaxed_poll_timeout_atomic(emc->regs + EMC_INTSTATUS, val,
|
||||
val & EMC_MRR_DIVLD_INT,
|
||||
1, 100);
|
||||
if (err) {
|
||||
dev_err(emc->dev, "mode register %u read failed: %d\n",
|
||||
register_addr, err);
|
||||
emc->mrr_error = true;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* read out mode register data */
|
||||
val = readl_relaxed(emc->regs + EMC_MRR);
|
||||
*register_data = FIELD_GET(EMC_MRR_MRR_DATA, val) & mr_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void emc_read_lpddr_sdram_info(struct tegra_emc *emc,
|
||||
unsigned int emem_dev)
|
||||
{
|
||||
union lpddr2_basic_config4 basic_conf4;
|
||||
unsigned int manufacturer_id;
|
||||
unsigned int revision_id1;
|
||||
unsigned int revision_id2;
|
||||
|
||||
/* these registers are standard for all LPDDR JEDEC memory chips */
|
||||
emc_read_lpddr_mode_register(emc, emem_dev, 5, &manufacturer_id);
|
||||
emc_read_lpddr_mode_register(emc, emem_dev, 6, &revision_id1);
|
||||
emc_read_lpddr_mode_register(emc, emem_dev, 7, &revision_id2);
|
||||
emc_read_lpddr_mode_register(emc, emem_dev, 8, &basic_conf4.value);
|
||||
|
||||
dev_info(emc->dev, "SDRAM[dev%u]: manufacturer: 0x%x (%s) rev1: 0x%x rev2: 0x%x prefetch: S%u density: %uMbit iowidth: %ubit\n",
|
||||
emem_dev, manufacturer_id,
|
||||
lpddr2_jedec_manufacturer(manufacturer_id),
|
||||
revision_id1, revision_id2,
|
||||
4 >> basic_conf4.arch_type,
|
||||
64 << basic_conf4.density,
|
||||
32 >> basic_conf4.io_width);
|
||||
}
|
||||
|
||||
static int emc_setup_hw(struct tegra_emc *emc)
|
||||
{
|
||||
u32 fbio_cfg5, emc_cfg, emc_dbg, emc_adr_cfg;
|
||||
u32 intmask = EMC_REFRESH_OVERFLOW_INT;
|
||||
u32 fbio_cfg5, emc_cfg, emc_dbg;
|
||||
static bool print_sdram_info_once;
|
||||
enum emc_dram_type dram_type;
|
||||
const char *dram_type_str;
|
||||
unsigned int emem_numdev;
|
||||
|
||||
fbio_cfg5 = readl_relaxed(emc->regs + EMC_FBIO_CFG5);
|
||||
dram_type = fbio_cfg5 & EMC_FBIO_CFG5_DRAM_TYPE_MASK;
|
||||
|
@ -1076,6 +1159,34 @@ static int emc_setup_hw(struct tegra_emc *emc)
|
|||
emc_dbg &= ~EMC_DBG_FORCE_UPDATE;
|
||||
writel_relaxed(emc_dbg, emc->regs + EMC_DBG);
|
||||
|
||||
switch (dram_type) {
|
||||
case DRAM_TYPE_DDR1:
|
||||
dram_type_str = "DDR1";
|
||||
break;
|
||||
case DRAM_TYPE_LPDDR2:
|
||||
dram_type_str = "LPDDR2";
|
||||
break;
|
||||
case DRAM_TYPE_DDR2:
|
||||
dram_type_str = "DDR2";
|
||||
break;
|
||||
case DRAM_TYPE_DDR3:
|
||||
dram_type_str = "DDR3";
|
||||
break;
|
||||
}
|
||||
|
||||
emc_adr_cfg = readl_relaxed(emc->regs + EMC_ADR_CFG);
|
||||
emem_numdev = FIELD_GET(EMC_ADR_CFG_EMEM_NUMDEV, emc_adr_cfg) + 1;
|
||||
|
||||
dev_info_once(emc->dev, "%u %s %s attached\n", emem_numdev,
|
||||
dram_type_str, emem_numdev == 2 ? "devices" : "device");
|
||||
|
||||
if (dram_type == DRAM_TYPE_LPDDR2 && !print_sdram_info_once) {
|
||||
while (emem_numdev--)
|
||||
emc_read_lpddr_sdram_info(emc, emem_numdev);
|
||||
|
||||
print_sdram_info_once = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1538,14 +1649,6 @@ static int tegra_emc_probe(struct platform_device *pdev)
|
|||
emc->clk_nb.notifier_call = emc_clk_change_notify;
|
||||
emc->dev = &pdev->dev;
|
||||
|
||||
np = emc_find_node_by_ram_code(&pdev->dev);
|
||||
if (np) {
|
||||
err = emc_load_timings_from_dt(emc, np);
|
||||
of_node_put(np);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
emc->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(emc->regs))
|
||||
return PTR_ERR(emc->regs);
|
||||
|
@ -1554,6 +1657,14 @@ static int tegra_emc_probe(struct platform_device *pdev)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
np = emc_find_node_by_ram_code(emc);
|
||||
if (np) {
|
||||
err = emc_load_timings_from_dt(emc, np);
|
||||
of_node_put(np);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = platform_get_irq(pdev, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
|
|
@ -928,7 +928,8 @@ static void q6v5proc_halt_axi_port(struct q6v5 *qproc,
|
|||
regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
|
||||
}
|
||||
|
||||
static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
|
||||
static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw,
|
||||
const char *fw_name)
|
||||
{
|
||||
unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
|
||||
dma_addr_t phys;
|
||||
|
@ -939,7 +940,7 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
|
|||
void *ptr;
|
||||
int ret;
|
||||
|
||||
metadata = qcom_mdt_read_metadata(fw, &size);
|
||||
metadata = qcom_mdt_read_metadata(fw, &size, fw_name, qproc->dev);
|
||||
if (IS_ERR(metadata))
|
||||
return PTR_ERR(metadata);
|
||||
|
||||
|
@ -1289,7 +1290,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
|
|||
/* Initialize the RMB validator */
|
||||
writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
|
||||
|
||||
ret = q6v5_mpss_init_image(qproc, fw);
|
||||
ret = q6v5_mpss_init_image(qproc, fw, qproc->hexagon_mdt_image);
|
||||
if (ret)
|
||||
goto release_firmware;
|
||||
|
||||
|
|
|
@ -79,6 +79,8 @@ struct qcom_adsp {
|
|||
struct qcom_rproc_subdev smd_subdev;
|
||||
struct qcom_rproc_ssr ssr_subdev;
|
||||
struct qcom_sysmon *sysmon;
|
||||
|
||||
struct qcom_scm_pas_metadata pas_metadata;
|
||||
};
|
||||
|
||||
static void adsp_minidump(struct rproc *rproc)
|
||||
|
@ -126,14 +128,34 @@ static void adsp_pds_disable(struct qcom_adsp *adsp, struct device **pds,
|
|||
}
|
||||
}
|
||||
|
||||
static int adsp_unprepare(struct rproc *rproc)
|
||||
{
|
||||
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
|
||||
|
||||
/*
|
||||
* adsp_load() did pass pas_metadata to the SCM driver for storing
|
||||
* metadata context. It might have been released already if
|
||||
* auth_and_reset() was successful, but in other cases clean it up
|
||||
* here.
|
||||
*/
|
||||
qcom_scm_pas_metadata_release(&adsp->pas_metadata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adsp_load(struct rproc *rproc, const struct firmware *fw)
|
||||
{
|
||||
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
|
||||
int ret;
|
||||
|
||||
ret = qcom_mdt_load(adsp->dev, fw, rproc->firmware, adsp->pas_id,
|
||||
adsp->mem_region, adsp->mem_phys, adsp->mem_size,
|
||||
&adsp->mem_reloc);
|
||||
ret = qcom_mdt_pas_init(adsp->dev, fw, rproc->firmware, adsp->pas_id,
|
||||
adsp->mem_phys, &adsp->pas_metadata);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, adsp->pas_id,
|
||||
adsp->mem_region, adsp->mem_phys, adsp->mem_size,
|
||||
&adsp->mem_reloc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -185,6 +207,8 @@ static int adsp_start(struct rproc *rproc)
|
|||
goto disable_px_supply;
|
||||
}
|
||||
|
||||
qcom_scm_pas_metadata_release(&adsp->pas_metadata);
|
||||
|
||||
return 0;
|
||||
|
||||
disable_px_supply:
|
||||
|
@ -255,6 +279,7 @@ static unsigned long adsp_panic(struct rproc *rproc)
|
|||
}
|
||||
|
||||
static const struct rproc_ops adsp_ops = {
|
||||
.unprepare = adsp_unprepare,
|
||||
.start = adsp_start,
|
||||
.stop = adsp_stop,
|
||||
.da_to_va = adsp_da_to_va,
|
||||
|
@ -264,6 +289,7 @@ static const struct rproc_ops adsp_ops = {
|
|||
};
|
||||
|
||||
static const struct rproc_ops adsp_minidump_ops = {
|
||||
.unprepare = adsp_unprepare,
|
||||
.start = adsp_start,
|
||||
.stop = adsp_stop,
|
||||
.da_to_va = adsp_da_to_va,
|
||||
|
@ -853,6 +879,10 @@ static const struct of_device_id adsp_of_match[] = {
|
|||
{ .compatible = "qcom,sm8350-cdsp-pas", .data = &sm8350_cdsp_resource},
|
||||
{ .compatible = "qcom,sm8350-slpi-pas", .data = &sm8350_slpi_resource},
|
||||
{ .compatible = "qcom,sm8350-mpss-pas", .data = &mpss_resource_init},
|
||||
{ .compatible = "qcom,sm8450-adsp-pas", .data = &sm8350_adsp_resource},
|
||||
{ .compatible = "qcom,sm8450-cdsp-pas", .data = &sm8350_cdsp_resource},
|
||||
{ .compatible = "qcom,sm8450-slpi-pas", .data = &sm8350_slpi_resource},
|
||||
{ .compatible = "qcom,sm8450-mpss-pas", .data = &mpss_resource_init},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adsp_of_match);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <dt-bindings/power/meson-a1-power.h>
|
||||
#include <dt-bindings/power/meson-s4-power.h>
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/firmware/meson/meson_sm.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -119,6 +120,18 @@ static struct meson_secure_pwrc_domain_desc a1_pwrc_domains[] = {
|
|||
SEC_PD(RSA, 0),
|
||||
};
|
||||
|
||||
static struct meson_secure_pwrc_domain_desc s4_pwrc_domains[] = {
|
||||
SEC_PD(S4_DOS_HEVC, 0),
|
||||
SEC_PD(S4_DOS_VDEC, 0),
|
||||
SEC_PD(S4_VPU_HDMI, 0),
|
||||
SEC_PD(S4_USB_COMB, 0),
|
||||
SEC_PD(S4_GE2D, 0),
|
||||
/* ETH is for ethernet online wakeup, and should be always on */
|
||||
SEC_PD(S4_ETH, GENPD_FLAG_ALWAYS_ON),
|
||||
SEC_PD(S4_DEMOD, 0),
|
||||
SEC_PD(S4_AUDIO, 0),
|
||||
};
|
||||
|
||||
static int meson_secure_pwrc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
|
@ -187,11 +200,20 @@ static struct meson_secure_pwrc_domain_data meson_secure_a1_pwrc_data = {
|
|||
.count = ARRAY_SIZE(a1_pwrc_domains),
|
||||
};
|
||||
|
||||
static struct meson_secure_pwrc_domain_data meson_secure_s4_pwrc_data = {
|
||||
.domains = s4_pwrc_domains,
|
||||
.count = ARRAY_SIZE(s4_pwrc_domains),
|
||||
};
|
||||
|
||||
static const struct of_device_id meson_secure_pwrc_match_table[] = {
|
||||
{
|
||||
.compatible = "amlogic,meson-a1-pwrc",
|
||||
.data = &meson_secure_a1_pwrc_data,
|
||||
},
|
||||
{
|
||||
.compatible = "amlogic,meson-s4-pwrc",
|
||||
.data = &meson_secure_s4_pwrc_data,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_secure_pwrc_match_table);
|
||||
|
|
|
@ -156,6 +156,9 @@ static const struct at91_soc socs[] __initconst = {
|
|||
AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
|
||||
AT91_CIDR_VERSION_MASK, SAMA5D28C_LD2G_EXID_MATCH,
|
||||
"sama5d28c 256MiB LPDDR2 SiP", "sama5d2"),
|
||||
AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
|
||||
AT91_CIDR_VERSION_MASK, SAMA5D29CN_EXID_MATCH,
|
||||
"sama5d29", "sama5d2"),
|
||||
AT91_SOC(SAMA5D3_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
|
||||
AT91_CIDR_VERSION_MASK, SAMA5D31_EXID_MATCH,
|
||||
"sama5d31", "sama5d3"),
|
||||
|
|
|
@ -95,6 +95,7 @@ at91_soc_init(const struct at91_soc *socs);
|
|||
#define SAMA5D28C_LD2G_EXID_MATCH 0x00000072
|
||||
#define SAMA5D28CU_EXID_MATCH 0x00000010
|
||||
#define SAMA5D28CN_EXID_MATCH 0x00000020
|
||||
#define SAMA5D29CN_EXID_MATCH 0x00000023
|
||||
|
||||
#define SAMA5D3_CIDR_MATCH 0x0a5c07c0
|
||||
#define SAMA5D31_EXID_MATCH 0x00444300
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <dt-bindings/power/imx8mm-power.h>
|
||||
#include <dt-bindings/power/imx8mn-power.h>
|
||||
#include <dt-bindings/power/imx8mq-power.h>
|
||||
|
||||
#define BLK_SFT_RSTN 0x0
|
||||
#define BLK_CLK_EN 0x4
|
||||
|
@ -589,6 +590,68 @@ static const struct imx8m_blk_ctrl_data imx8mn_disp_blk_ctl_dev_data = {
|
|||
.num_domains = ARRAY_SIZE(imx8mn_disp_blk_ctl_domain_data),
|
||||
};
|
||||
|
||||
static int imx8mq_vpu_power_notifier(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
|
||||
power_nb);
|
||||
|
||||
if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF)
|
||||
return NOTIFY_OK;
|
||||
|
||||
/*
|
||||
* The ADB in the VPUMIX domain has no separate reset and clock
|
||||
* enable bits, but is ungated and reset together with the VPUs. The
|
||||
* reset and clock enable inputs to the ADB is a logical OR of the
|
||||
* VPU bits. In order to set the G2 fuse bits, the G2 clock must
|
||||
* also be enabled.
|
||||
*/
|
||||
regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(0) | BIT(1));
|
||||
regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(0) | BIT(1));
|
||||
|
||||
if (action == GENPD_NOTIFY_ON) {
|
||||
/*
|
||||
* On power up we have no software backchannel to the GPC to
|
||||
* wait for the ADB handshake to happen, so we just delay for a
|
||||
* bit. On power down the GPC driver waits for the handshake.
|
||||
*/
|
||||
udelay(5);
|
||||
|
||||
/* set "fuse" bits to enable the VPUs */
|
||||
regmap_set_bits(bc->regmap, 0x8, 0xffffffff);
|
||||
regmap_set_bits(bc->regmap, 0xc, 0xffffffff);
|
||||
regmap_set_bits(bc->regmap, 0x10, 0xffffffff);
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static const struct imx8m_blk_ctrl_domain_data imx8mq_vpu_blk_ctl_domain_data[] = {
|
||||
[IMX8MQ_VPUBLK_PD_G1] = {
|
||||
.name = "vpublk-g1",
|
||||
.clk_names = (const char *[]){ "g1", },
|
||||
.num_clks = 1,
|
||||
.gpc_name = "g1",
|
||||
.rst_mask = BIT(1),
|
||||
.clk_mask = BIT(1),
|
||||
},
|
||||
[IMX8MQ_VPUBLK_PD_G2] = {
|
||||
.name = "vpublk-g2",
|
||||
.clk_names = (const char *[]){ "g2", },
|
||||
.num_clks = 1,
|
||||
.gpc_name = "g2",
|
||||
.rst_mask = BIT(0),
|
||||
.clk_mask = BIT(0),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct imx8m_blk_ctrl_data imx8mq_vpu_blk_ctl_dev_data = {
|
||||
.max_reg = 0x14,
|
||||
.power_notifier_fn = imx8mq_vpu_power_notifier,
|
||||
.domains = imx8mq_vpu_blk_ctl_domain_data,
|
||||
.num_domains = ARRAY_SIZE(imx8mq_vpu_blk_ctl_domain_data),
|
||||
};
|
||||
|
||||
static const struct of_device_id imx8m_blk_ctrl_of_match[] = {
|
||||
{
|
||||
.compatible = "fsl,imx8mm-vpu-blk-ctrl",
|
||||
|
@ -599,6 +662,9 @@ static const struct of_device_id imx8m_blk_ctrl_of_match[] = {
|
|||
}, {
|
||||
.compatible = "fsl,imx8mn-disp-blk-ctrl",
|
||||
.data = &imx8mn_disp_blk_ctl_dev_data
|
||||
}, {
|
||||
.compatible = "fsl,imx8mq-vpu-blk-ctrl",
|
||||
.data = &imx8mq_vpu_blk_ctl_dev_data
|
||||
}, {
|
||||
/* Sentinel */
|
||||
}
|
||||
|
|
|
@ -40,9 +40,6 @@ static int __init imx_soc_device_init(void)
|
|||
if (!__mxc_cpu_type)
|
||||
return 0;
|
||||
|
||||
if (of_machine_is_compatible("fsl,ls1021a"))
|
||||
return 0;
|
||||
|
||||
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
|
||||
if (!soc_dev_attr)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -18,6 +18,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = {
|
|||
.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 = {
|
||||
|
@ -30,6 +32,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = {
|
|||
.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(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.caps = MTK_SCPD_ACTIVE_WAKEUP,
|
||||
|
@ -38,6 +42,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = {
|
|||
.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),
|
||||
.caps = MTK_SCPD_ACTIVE_WAKEUP,
|
||||
|
@ -46,6 +52,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = {
|
|||
.name = "mfg_async",
|
||||
.sta_mask = MT8167_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 = 0,
|
||||
.sram_pdn_ack_bits = 0,
|
||||
.bp_infracfg = {
|
||||
|
@ -57,6 +65,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = {
|
|||
.name = "mfg_2d",
|
||||
.sta_mask = MT8167_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(15, 12),
|
||||
},
|
||||
|
@ -64,6 +74,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = {
|
|||
.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(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(15, 12),
|
||||
},
|
||||
|
@ -71,6 +83,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = {
|
|||
.name = "conn",
|
||||
.sta_mask = PWR_STATUS_CONN,
|
||||
.ctl_offs = SPM_CONN_PWR_CON,
|
||||
.pwr_sta_offs = SPM_PWR_STATUS,
|
||||
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = 0,
|
||||
.caps = MTK_SCPD_ACTIVE_WAKEUP,
|
||||
|
@ -85,8 +99,6 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = {
|
|||
static const struct scpsys_soc_data mt8167_scpsys_data = {
|
||||
.domains_data = scpsys_domain_data_mt8167,
|
||||
.num_domains = ARRAY_SIZE(scpsys_domain_data_mt8167),
|
||||
.pwr_sta_offs = SPM_PWR_STATUS,
|
||||
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
|
||||
};
|
||||
|
||||
#endif /* __SOC_MEDIATEK_MT8167_PM_DOMAINS_H */
|
||||
|
|
|
@ -15,6 +15,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = {
|
|||
.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),
|
||||
},
|
||||
|
@ -22,6 +24,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = {
|
|||
.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),
|
||||
},
|
||||
|
@ -29,6 +33,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = {
|
|||
.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),
|
||||
},
|
||||
|
@ -36,6 +42,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = {
|
|||
.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 = {
|
||||
|
@ -47,6 +55,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = {
|
|||
.name = "venc_lt",
|
||||
.sta_mask = PWR_STATUS_VENC_LT,
|
||||
.ctl_offs = SPM_VEN2_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),
|
||||
},
|
||||
|
@ -54,6 +64,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = {
|
|||
.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),
|
||||
},
|
||||
|
@ -61,6 +73,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = {
|
|||
.name = "usb",
|
||||
.sta_mask = PWR_STATUS_USB,
|
||||
.ctl_offs = SPM_USB_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),
|
||||
.caps = MTK_SCPD_ACTIVE_WAKEUP,
|
||||
|
@ -69,6 +83,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = {
|
|||
.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,
|
||||
.caps = MTK_SCPD_DOMAIN_SUPPLY,
|
||||
|
@ -77,6 +93,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = {
|
|||
.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),
|
||||
},
|
||||
|
@ -84,6 +102,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = {
|
|||
.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 = {
|
||||
|
@ -98,8 +118,6 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = {
|
|||
static const struct scpsys_soc_data mt8173_scpsys_data = {
|
||||
.domains_data = scpsys_domain_data_mt8173,
|
||||
.num_domains = ARRAY_SIZE(scpsys_domain_data_mt8173),
|
||||
.pwr_sta_offs = SPM_PWR_STATUS,
|
||||
.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
|
||||
};
|
||||
|
||||
#endif /* __SOC_MEDIATEK_MT8173_PM_DOMAINS_H */
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#define MT8183_RDMA0_SOUT_COLOR0 0x1
|
||||
#define MT8183_RDMA1_SOUT_DSI0 0x1
|
||||
|
||||
#define MT8183_MMSYS_SW0_RST_B 0x140
|
||||
|
||||
static const struct mtk_mmsys_routes mmsys_mt8183_routing_table[] = {
|
||||
{
|
||||
DDP_COMPONENT_OVL0, DDP_COMPONENT_OVL_2L0,
|
||||
|
|
|
@ -15,6 +15,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "audio",
|
||||
.sta_mask = PWR_STATUS_AUDIO,
|
||||
.ctl_offs = 0x0314,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(15, 12),
|
||||
},
|
||||
|
@ -22,6 +24,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "conn",
|
||||
.sta_mask = PWR_STATUS_CONN,
|
||||
.ctl_offs = 0x032c,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = 0,
|
||||
.sram_pdn_ack_bits = 0,
|
||||
.bp_infracfg = {
|
||||
|
@ -33,6 +37,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "mfg_async",
|
||||
.sta_mask = PWR_STATUS_MFG_ASYNC,
|
||||
.ctl_offs = 0x0334,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = 0,
|
||||
.sram_pdn_ack_bits = 0,
|
||||
},
|
||||
|
@ -40,6 +46,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "mfg",
|
||||
.sta_mask = PWR_STATUS_MFG,
|
||||
.ctl_offs = 0x0338,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.caps = MTK_SCPD_DOMAIN_SUPPLY,
|
||||
|
@ -48,6 +56,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "mfg_core0",
|
||||
.sta_mask = BIT(7),
|
||||
.ctl_offs = 0x034c,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
},
|
||||
|
@ -55,6 +65,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "mfg_core1",
|
||||
.sta_mask = BIT(20),
|
||||
.ctl_offs = 0x0310,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
},
|
||||
|
@ -62,6 +74,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "mfg_2d",
|
||||
.sta_mask = PWR_STATUS_MFG_2D,
|
||||
.ctl_offs = 0x0348,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -75,6 +89,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "disp",
|
||||
.sta_mask = PWR_STATUS_DISP,
|
||||
.ctl_offs = 0x030c,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -94,6 +110,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "cam",
|
||||
.sta_mask = BIT(25),
|
||||
.ctl_offs = 0x0344,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = GENMASK(9, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(13, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -117,6 +135,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "isp",
|
||||
.sta_mask = PWR_STATUS_ISP,
|
||||
.ctl_offs = 0x0308,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = GENMASK(9, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(13, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -140,6 +160,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "vdec",
|
||||
.sta_mask = BIT(31),
|
||||
.ctl_offs = 0x0300,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_smi = {
|
||||
|
@ -153,6 +175,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "venc",
|
||||
.sta_mask = PWR_STATUS_VENC,
|
||||
.ctl_offs = 0x0304,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(15, 12),
|
||||
.bp_smi = {
|
||||
|
@ -166,6 +190,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "vpu_top",
|
||||
.sta_mask = BIT(26),
|
||||
.ctl_offs = 0x0324,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -193,6 +219,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "vpu_core0",
|
||||
.sta_mask = BIT(27),
|
||||
.ctl_offs = 0x33c,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(13, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -211,6 +239,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
.name = "vpu_core1",
|
||||
.sta_mask = BIT(28),
|
||||
.ctl_offs = 0x0340,
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184,
|
||||
.sram_pdn_bits = GENMASK(11, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(13, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -230,8 +260,6 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
|
|||
static const struct scpsys_soc_data mt8183_scpsys_data = {
|
||||
.domains_data = scpsys_domain_data_mt8183,
|
||||
.num_domains = ARRAY_SIZE(scpsys_domain_data_mt8183),
|
||||
.pwr_sta_offs = 0x0180,
|
||||
.pwr_sta2nd_offs = 0x0184
|
||||
};
|
||||
|
||||
#endif /* __SOC_MEDIATEK_MT8183_PM_DOMAINS_H */
|
||||
|
|
115
drivers/soc/mediatek/mt8186-mmsys.h
Normal file
115
drivers/soc/mediatek/mt8186-mmsys.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef __SOC_MEDIATEK_MT8186_MMSYS_H
|
||||
#define __SOC_MEDIATEK_MT8186_MMSYS_H
|
||||
|
||||
#define MT8186_MMSYS_OVL_CON 0xF04
|
||||
#define MT8186_MMSYS_OVL0_CON_MASK 0x3
|
||||
#define MT8186_MMSYS_OVL0_2L_CON_MASK 0xC
|
||||
#define MT8186_OVL0_GO_BLEND BIT(0)
|
||||
#define MT8186_OVL0_GO_BG BIT(1)
|
||||
#define MT8186_OVL0_2L_GO_BLEND BIT(2)
|
||||
#define MT8186_OVL0_2L_GO_BG BIT(3)
|
||||
#define MT8186_DISP_RDMA0_SOUT_SEL 0xF0C
|
||||
#define MT8186_RDMA0_SOUT_SEL_MASK 0xF
|
||||
#define MT8186_RDMA0_SOUT_TO_DSI0 (0)
|
||||
#define MT8186_RDMA0_SOUT_TO_COLOR0 (1)
|
||||
#define MT8186_RDMA0_SOUT_TO_DPI0 (2)
|
||||
#define MT8186_DISP_OVL0_2L_MOUT_EN 0xF14
|
||||
#define MT8186_OVL0_2L_MOUT_EN_MASK 0xF
|
||||
#define MT8186_OVL0_2L_MOUT_TO_RDMA0 BIT(0)
|
||||
#define MT8186_OVL0_2L_MOUT_TO_RDMA1 BIT(3)
|
||||
#define MT8186_DISP_OVL0_MOUT_EN 0xF18
|
||||
#define MT8186_OVL0_MOUT_EN_MASK 0xF
|
||||
#define MT8186_OVL0_MOUT_TO_RDMA0 BIT(0)
|
||||
#define MT8186_OVL0_MOUT_TO_RDMA1 BIT(3)
|
||||
#define MT8186_DISP_DITHER0_MOUT_EN 0xF20
|
||||
#define MT8186_DITHER0_MOUT_EN_MASK 0xF
|
||||
#define MT8186_DITHER0_MOUT_TO_DSI0 BIT(0)
|
||||
#define MT8186_DITHER0_MOUT_TO_RDMA1 BIT(2)
|
||||
#define MT8186_DITHER0_MOUT_TO_DPI0 BIT(3)
|
||||
#define MT8186_DISP_RDMA0_SEL_IN 0xF28
|
||||
#define MT8186_RDMA0_SEL_IN_MASK 0xF
|
||||
#define MT8186_RDMA0_FROM_OVL0 0
|
||||
#define MT8186_RDMA0_FROM_OVL0_2L 2
|
||||
#define MT8186_DISP_DSI0_SEL_IN 0xF30
|
||||
#define MT8186_DSI0_SEL_IN_MASK 0xF
|
||||
#define MT8186_DSI0_FROM_RDMA0 0
|
||||
#define MT8186_DSI0_FROM_DITHER0 1
|
||||
#define MT8186_DSI0_FROM_RDMA1 2
|
||||
#define MT8186_DISP_RDMA1_MOUT_EN 0xF3C
|
||||
#define MT8186_RDMA1_MOUT_EN_MASK 0xF
|
||||
#define MT8186_RDMA1_MOUT_TO_DPI0_SEL BIT(0)
|
||||
#define MT8186_RDMA1_MOUT_TO_DSI0_SEL BIT(2)
|
||||
#define MT8186_DISP_RDMA1_SEL_IN 0xF40
|
||||
#define MT8186_RDMA1_SEL_IN_MASK 0xF
|
||||
#define MT8186_RDMA1_FROM_OVL0 0
|
||||
#define MT8186_RDMA1_FROM_OVL0_2L 2
|
||||
#define MT8186_RDMA1_FROM_DITHER0 3
|
||||
#define MT8186_DISP_DPI0_SEL_IN 0xF44
|
||||
#define MT8186_DPI0_SEL_IN_MASK 0xF
|
||||
#define MT8186_DPI0_FROM_RDMA1 0
|
||||
#define MT8186_DPI0_FROM_DITHER0 1
|
||||
#define MT8186_DPI0_FROM_RDMA0 2
|
||||
|
||||
#define MT8186_MMSYS_SW0_RST_B 0x160
|
||||
|
||||
static const struct mtk_mmsys_routes mmsys_mt8186_routing_table[] = {
|
||||
{
|
||||
DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
|
||||
MT8186_DISP_OVL0_MOUT_EN, MT8186_OVL0_MOUT_EN_MASK,
|
||||
MT8186_OVL0_MOUT_TO_RDMA0
|
||||
},
|
||||
{
|
||||
DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
|
||||
MT8186_DISP_RDMA0_SEL_IN, MT8186_RDMA0_SEL_IN_MASK,
|
||||
MT8186_RDMA0_FROM_OVL0
|
||||
},
|
||||
{
|
||||
DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
|
||||
MT8186_MMSYS_OVL_CON, MT8186_MMSYS_OVL0_CON_MASK,
|
||||
MT8186_OVL0_GO_BLEND
|
||||
},
|
||||
{
|
||||
DDP_COMPONENT_RDMA0, DDP_COMPONENT_COLOR0,
|
||||
MT8186_DISP_RDMA0_SOUT_SEL, MT8186_RDMA0_SOUT_SEL_MASK,
|
||||
MT8186_RDMA0_SOUT_TO_COLOR0
|
||||
},
|
||||
{
|
||||
DDP_COMPONENT_DITHER, DDP_COMPONENT_DSI0,
|
||||
MT8186_DISP_DITHER0_MOUT_EN, MT8186_DITHER0_MOUT_EN_MASK,
|
||||
MT8186_DITHER0_MOUT_TO_DSI0,
|
||||
},
|
||||
{
|
||||
DDP_COMPONENT_DITHER, DDP_COMPONENT_DSI0,
|
||||
MT8186_DISP_DSI0_SEL_IN, MT8186_DSI0_SEL_IN_MASK,
|
||||
MT8186_DSI0_FROM_DITHER0
|
||||
},
|
||||
{
|
||||
DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA1,
|
||||
MT8186_DISP_OVL0_2L_MOUT_EN, MT8186_OVL0_2L_MOUT_EN_MASK,
|
||||
MT8186_OVL0_2L_MOUT_TO_RDMA1
|
||||
},
|
||||
{
|
||||
DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA1,
|
||||
MT8186_DISP_RDMA1_SEL_IN, MT8186_RDMA1_SEL_IN_MASK,
|
||||
MT8186_RDMA1_FROM_OVL0_2L
|
||||
},
|
||||
{
|
||||
DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA1,
|
||||
MT8186_MMSYS_OVL_CON, MT8186_MMSYS_OVL0_2L_CON_MASK,
|
||||
MT8186_OVL0_2L_GO_BLEND
|
||||
},
|
||||
{
|
||||
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
|
||||
MT8186_DISP_RDMA1_MOUT_EN, MT8186_RDMA1_MOUT_EN_MASK,
|
||||
MT8186_RDMA1_MOUT_TO_DPI0_SEL
|
||||
},
|
||||
{
|
||||
DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
|
||||
MT8186_DISP_DPI0_SEL_IN, MT8186_DPI0_SEL_IN_MASK,
|
||||
MT8186_DPI0_FROM_RDMA1
|
||||
},
|
||||
};
|
||||
|
||||
#endif /* __SOC_MEDIATEK_MT8186_MMSYS_H */
|
344
drivers/soc/mediatek/mt8186-pm-domains.h
Normal file
344
drivers/soc/mediatek/mt8186-pm-domains.h
Normal file
|
@ -0,0 +1,344 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022 MediaTek Inc.
|
||||
* Author: Chun-Jie Chen <chun-jie.chen@mediatek.com>
|
||||
*/
|
||||
|
||||
#ifndef __SOC_MEDIATEK_MT8186_PM_DOMAINS_H
|
||||
#define __SOC_MEDIATEK_MT8186_PM_DOMAINS_H
|
||||
|
||||
#include "mtk-pm-domains.h"
|
||||
#include <dt-bindings/power/mt8186-power.h>
|
||||
|
||||
/*
|
||||
* MT8186 power domain support
|
||||
*/
|
||||
|
||||
static const struct scpsys_domain_data scpsys_domain_data_mt8186[] = {
|
||||
[MT8186_POWER_DOMAIN_MFG0] = {
|
||||
.name = "mfg0",
|
||||
.sta_mask = BIT(2),
|
||||
.ctl_offs = 0x308,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_MFG1] = {
|
||||
.name = "mfg1",
|
||||
.sta_mask = BIT(3),
|
||||
.ctl_offs = 0x30c,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_MFG1_STEP1,
|
||||
MT8186_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_MFG1_STEP2,
|
||||
MT8186_TOP_AXI_PROT_EN_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_STA),
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_MFG1_STEP3,
|
||||
MT8186_TOP_AXI_PROT_EN_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_STA),
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_MFG1_STEP4,
|
||||
MT8186_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_MFG2] = {
|
||||
.name = "mfg2",
|
||||
.sta_mask = BIT(4),
|
||||
.ctl_offs = 0x310,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_MFG3] = {
|
||||
.name = "mfg3",
|
||||
.sta_mask = BIT(5),
|
||||
.ctl_offs = 0x314,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_SSUSB] = {
|
||||
.name = "ssusb",
|
||||
.sta_mask = BIT(20),
|
||||
.ctl_offs = 0x9F0,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.caps = MTK_SCPD_ACTIVE_WAKEUP,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_SSUSB_P1] = {
|
||||
.name = "ssusb_p1",
|
||||
.sta_mask = BIT(19),
|
||||
.ctl_offs = 0x9F4,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.caps = MTK_SCPD_ACTIVE_WAKEUP,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_DIS] = {
|
||||
.name = "dis",
|
||||
.sta_mask = BIT(21),
|
||||
.ctl_offs = 0x354,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_DIS_STEP1,
|
||||
MT8186_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_DIS_STEP2,
|
||||
MT8186_TOP_AXI_PROT_EN_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_STA),
|
||||
},
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_IMG] = {
|
||||
.name = "img",
|
||||
.sta_mask = BIT(13),
|
||||
.ctl_offs = 0x334,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_IMG_STEP1,
|
||||
MT8186_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_IMG_STEP2,
|
||||
MT8186_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_IMG2] = {
|
||||
.name = "img2",
|
||||
.sta_mask = BIT(14),
|
||||
.ctl_offs = 0x338,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_IPE] = {
|
||||
.name = "ipe",
|
||||
.sta_mask = BIT(15),
|
||||
.ctl_offs = 0x33C,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_IPE_STEP1,
|
||||
MT8186_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_IPE_STEP2,
|
||||
MT8186_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_CAM] = {
|
||||
.name = "cam",
|
||||
.sta_mask = BIT(23),
|
||||
.ctl_offs = 0x35C,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_CAM_STEP1,
|
||||
MT8186_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_CAM_STEP2,
|
||||
MT8186_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_CAM_RAWA] = {
|
||||
.name = "cam_rawa",
|
||||
.sta_mask = BIT(24),
|
||||
.ctl_offs = 0x360,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_CAM_RAWB] = {
|
||||
.name = "cam_rawb",
|
||||
.sta_mask = BIT(25),
|
||||
.ctl_offs = 0x364,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_VENC] = {
|
||||
.name = "venc",
|
||||
.sta_mask = BIT(18),
|
||||
.ctl_offs = 0x348,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_VENC_STEP1,
|
||||
MT8186_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_VENC_STEP2,
|
||||
MT8186_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_VDEC] = {
|
||||
.name = "vdec",
|
||||
.sta_mask = BIT(16),
|
||||
.ctl_offs = 0x340,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_VDEC_STEP1,
|
||||
MT8186_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_VDEC_STEP2,
|
||||
MT8186_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_WPE] = {
|
||||
.name = "wpe",
|
||||
.sta_mask = BIT(0),
|
||||
.ctl_offs = 0x3F8,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_2_WPE_STEP1,
|
||||
MT8186_TOP_AXI_PROT_EN_2_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_2_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_2_STA),
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_2_WPE_STEP2,
|
||||
MT8186_TOP_AXI_PROT_EN_2_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_2_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_2_STA),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_CONN_ON] = {
|
||||
.name = "conn_on",
|
||||
.sta_mask = BIT(1),
|
||||
.ctl_offs = 0x304,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_CONN_ON_STEP1,
|
||||
MT8186_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_1_STA),
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_CONN_ON_STEP2,
|
||||
MT8186_TOP_AXI_PROT_EN_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_STA),
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_CONN_ON_STEP3,
|
||||
MT8186_TOP_AXI_PROT_EN_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_STA),
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_CONN_ON_STEP4,
|
||||
MT8186_TOP_AXI_PROT_EN_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_STA),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_ACTIVE_WAKEUP,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_CSIRX_TOP] = {
|
||||
.name = "csirx_top",
|
||||
.sta_mask = BIT(6),
|
||||
.ctl_offs = 0x318,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_ADSP_AO] = {
|
||||
.name = "adsp_ao",
|
||||
.sta_mask = BIT(17),
|
||||
.ctl_offs = 0x9FC,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_ADSP_INFRA] = {
|
||||
.name = "adsp_infra",
|
||||
.sta_mask = BIT(10),
|
||||
.ctl_offs = 0x9F8,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8186_POWER_DOMAIN_ADSP_TOP] = {
|
||||
.name = "adsp_top",
|
||||
.sta_mask = BIT(31),
|
||||
.ctl_offs = 0x3E4,
|
||||
.pwr_sta_offs = 0x16C,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = BIT(8),
|
||||
.sram_pdn_ack_bits = BIT(12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_3_ADSP_TOP_STEP1,
|
||||
MT8186_TOP_AXI_PROT_EN_3_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_3_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_3_STA),
|
||||
BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_3_ADSP_TOP_STEP2,
|
||||
MT8186_TOP_AXI_PROT_EN_3_SET,
|
||||
MT8186_TOP_AXI_PROT_EN_3_CLR,
|
||||
MT8186_TOP_AXI_PROT_EN_3_STA),
|
||||
},
|
||||
.caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_ACTIVE_WAKEUP,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct scpsys_soc_data mt8186_scpsys_data = {
|
||||
.domains_data = scpsys_domain_data_mt8186,
|
||||
.num_domains = ARRAY_SIZE(scpsys_domain_data_mt8186),
|
||||
};
|
||||
|
||||
#endif /* __SOC_MEDIATEK_MT8186_PM_DOMAINS_H */
|
|
@ -15,6 +15,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "audio",
|
||||
.sta_mask = BIT(21),
|
||||
.ctl_offs = 0x0354,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -28,6 +30,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "conn",
|
||||
.sta_mask = PWR_STATUS_CONN,
|
||||
.ctl_offs = 0x0304,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = 0,
|
||||
.sram_pdn_ack_bits = 0,
|
||||
.bp_infracfg = {
|
||||
|
@ -50,6 +54,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "mfg0",
|
||||
.sta_mask = BIT(2),
|
||||
.ctl_offs = 0x0308,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
},
|
||||
|
@ -57,6 +63,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "mfg1",
|
||||
.sta_mask = BIT(3),
|
||||
.ctl_offs = 0x030c,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -82,6 +90,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "mfg2",
|
||||
.sta_mask = BIT(4),
|
||||
.ctl_offs = 0x0310,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
},
|
||||
|
@ -89,6 +99,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "mfg3",
|
||||
.sta_mask = BIT(5),
|
||||
.ctl_offs = 0x0314,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
},
|
||||
|
@ -96,6 +108,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "mfg4",
|
||||
.sta_mask = BIT(6),
|
||||
.ctl_offs = 0x0318,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
},
|
||||
|
@ -103,6 +117,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "mfg5",
|
||||
.sta_mask = BIT(7),
|
||||
.ctl_offs = 0x031c,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
},
|
||||
|
@ -110,6 +126,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "mfg6",
|
||||
.sta_mask = BIT(8),
|
||||
.ctl_offs = 0x0320,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
},
|
||||
|
@ -117,6 +135,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "disp",
|
||||
.sta_mask = BIT(20),
|
||||
.ctl_offs = 0x0350,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -146,6 +166,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "ipe",
|
||||
.sta_mask = BIT(14),
|
||||
.ctl_offs = 0x0338,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -163,6 +185,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "isp",
|
||||
.sta_mask = BIT(12),
|
||||
.ctl_offs = 0x0330,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -180,6 +204,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "isp2",
|
||||
.sta_mask = BIT(13),
|
||||
.ctl_offs = 0x0334,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -197,6 +223,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "mdp",
|
||||
.sta_mask = BIT(19),
|
||||
.ctl_offs = 0x034c,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -214,6 +242,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "venc",
|
||||
.sta_mask = BIT(17),
|
||||
.ctl_offs = 0x0344,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -231,6 +261,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "vdec",
|
||||
.sta_mask = BIT(15),
|
||||
.ctl_offs = 0x033c,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -248,6 +280,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "vdec2",
|
||||
.sta_mask = BIT(16),
|
||||
.ctl_offs = 0x0340,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
},
|
||||
|
@ -255,6 +289,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "cam",
|
||||
.sta_mask = BIT(23),
|
||||
.ctl_offs = 0x035c,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
|
@ -284,6 +320,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "cam_rawa",
|
||||
.sta_mask = BIT(24),
|
||||
.ctl_offs = 0x0360,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
},
|
||||
|
@ -291,6 +329,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "cam_rawb",
|
||||
.sta_mask = BIT(25),
|
||||
.ctl_offs = 0x0364,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
},
|
||||
|
@ -298,6 +338,8 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
.name = "cam_rawc",
|
||||
.sta_mask = BIT(26),
|
||||
.ctl_offs = 0x0368,
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
},
|
||||
|
@ -306,8 +348,6 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
|
|||
static const struct scpsys_soc_data mt8192_scpsys_data = {
|
||||
.domains_data = scpsys_domain_data_mt8192,
|
||||
.num_domains = ARRAY_SIZE(scpsys_domain_data_mt8192),
|
||||
.pwr_sta_offs = 0x016c,
|
||||
.pwr_sta2nd_offs = 0x0170,
|
||||
};
|
||||
|
||||
#endif /* __SOC_MEDIATEK_MT8192_PM_DOMAINS_H */
|
||||
|
|
613
drivers/soc/mediatek/mt8195-pm-domains.h
Normal file
613
drivers/soc/mediatek/mt8195-pm-domains.h
Normal file
|
@ -0,0 +1,613 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2021 MediaTek Inc.
|
||||
* Author: Chun-Jie Chen <chun-jie.chen@mediatek.com>
|
||||
*/
|
||||
|
||||
#ifndef __SOC_MEDIATEK_MT8195_PM_DOMAINS_H
|
||||
#define __SOC_MEDIATEK_MT8195_PM_DOMAINS_H
|
||||
|
||||
#include "mtk-pm-domains.h"
|
||||
#include <dt-bindings/power/mt8195-power.h>
|
||||
|
||||
/*
|
||||
* MT8195 power domain support
|
||||
*/
|
||||
|
||||
static const struct scpsys_domain_data scpsys_domain_data_mt8195[] = {
|
||||
[MT8195_POWER_DOMAIN_PCIE_MAC_P0] = {
|
||||
.name = "pcie_mac_p0",
|
||||
.sta_mask = BIT(11),
|
||||
.ctl_offs = 0x328,
|
||||
.pwr_sta_offs = 0x174,
|
||||
.pwr_sta2nd_offs = 0x178,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_PCIE_MAC_P0,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_1_PCIE_MAC_P0,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_1_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_1_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_1_STA1),
|
||||
},
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_PCIE_MAC_P1] = {
|
||||
.name = "pcie_mac_p1",
|
||||
.sta_mask = BIT(12),
|
||||
.ctl_offs = 0x32C,
|
||||
.pwr_sta_offs = 0x174,
|
||||
.pwr_sta2nd_offs = 0x178,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_PCIE_MAC_P1,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_1_PCIE_MAC_P1,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_1_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_1_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_1_STA1),
|
||||
},
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_PCIE_PHY] = {
|
||||
.name = "pcie_phy",
|
||||
.sta_mask = BIT(13),
|
||||
.ctl_offs = 0x330,
|
||||
.pwr_sta_offs = 0x174,
|
||||
.pwr_sta2nd_offs = 0x178,
|
||||
.caps = MTK_SCPD_ACTIVE_WAKEUP,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_SSUSB_PCIE_PHY] = {
|
||||
.name = "ssusb_pcie_phy",
|
||||
.sta_mask = BIT(14),
|
||||
.ctl_offs = 0x334,
|
||||
.pwr_sta_offs = 0x174,
|
||||
.pwr_sta2nd_offs = 0x178,
|
||||
.caps = MTK_SCPD_ACTIVE_WAKEUP,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_CSI_RX_TOP] = {
|
||||
.name = "csi_rx_top",
|
||||
.sta_mask = BIT(18),
|
||||
.ctl_offs = 0x3C4,
|
||||
.pwr_sta_offs = 0x174,
|
||||
.pwr_sta2nd_offs = 0x178,
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_ETHER] = {
|
||||
.name = "ether",
|
||||
.sta_mask = BIT(3),
|
||||
.ctl_offs = 0x344,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.caps = MTK_SCPD_ACTIVE_WAKEUP,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_ADSP] = {
|
||||
.name = "adsp",
|
||||
.sta_mask = BIT(10),
|
||||
.ctl_offs = 0x360,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_ADSP,
|
||||
MT8195_TOP_AXI_PROT_EN_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_2_STA1),
|
||||
},
|
||||
.caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_ACTIVE_WAKEUP,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_AUDIO] = {
|
||||
.name = "audio",
|
||||
.sta_mask = BIT(8),
|
||||
.ctl_offs = 0x358,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_AUDIO,
|
||||
MT8195_TOP_AXI_PROT_EN_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_2_STA1),
|
||||
},
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_MFG0] = {
|
||||
.name = "mfg0",
|
||||
.sta_mask = BIT(1),
|
||||
.ctl_offs = 0x300,
|
||||
.pwr_sta_offs = 0x174,
|
||||
.pwr_sta2nd_offs = 0x178,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_MFG1] = {
|
||||
.name = "mfg1",
|
||||
.sta_mask = BIT(2),
|
||||
.ctl_offs = 0x304,
|
||||
.pwr_sta_offs = 0x174,
|
||||
.pwr_sta2nd_offs = 0x178,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MFG1,
|
||||
MT8195_TOP_AXI_PROT_EN_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_MFG1,
|
||||
MT8195_TOP_AXI_PROT_EN_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_2_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_1_MFG1,
|
||||
MT8195_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_1_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_MFG1_2ND,
|
||||
MT8195_TOP_AXI_PROT_EN_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_2_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MFG1_2ND,
|
||||
MT8195_TOP_AXI_PROT_EN_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_MFG1,
|
||||
MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_MFG2] = {
|
||||
.name = "mfg2",
|
||||
.sta_mask = BIT(3),
|
||||
.ctl_offs = 0x308,
|
||||
.pwr_sta_offs = 0x174,
|
||||
.pwr_sta2nd_offs = 0x178,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_MFG3] = {
|
||||
.name = "mfg3",
|
||||
.sta_mask = BIT(4),
|
||||
.ctl_offs = 0x30C,
|
||||
.pwr_sta_offs = 0x174,
|
||||
.pwr_sta2nd_offs = 0x178,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_MFG4] = {
|
||||
.name = "mfg4",
|
||||
.sta_mask = BIT(5),
|
||||
.ctl_offs = 0x310,
|
||||
.pwr_sta_offs = 0x174,
|
||||
.pwr_sta2nd_offs = 0x178,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_MFG5] = {
|
||||
.name = "mfg5",
|
||||
.sta_mask = BIT(6),
|
||||
.ctl_offs = 0x314,
|
||||
.pwr_sta_offs = 0x174,
|
||||
.pwr_sta2nd_offs = 0x178,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_MFG6] = {
|
||||
.name = "mfg6",
|
||||
.sta_mask = BIT(7),
|
||||
.ctl_offs = 0x318,
|
||||
.pwr_sta_offs = 0x174,
|
||||
.pwr_sta2nd_offs = 0x178,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_VPPSYS0] = {
|
||||
.name = "vppsys0",
|
||||
.sta_mask = BIT(11),
|
||||
.ctl_offs = 0x364,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VPPSYS0,
|
||||
MT8195_TOP_AXI_PROT_EN_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VPPSYS0,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VPPSYS0_2ND,
|
||||
MT8195_TOP_AXI_PROT_EN_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VPPSYS0_2ND,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_VPPSYS0,
|
||||
MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
|
||||
},
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_VDOSYS0] = {
|
||||
.name = "vdosys0",
|
||||
.sta_mask = BIT(13),
|
||||
.ctl_offs = 0x36C,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDOSYS0,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDOSYS0,
|
||||
MT8195_TOP_AXI_PROT_EN_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_VDOSYS0,
|
||||
MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
|
||||
},
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_VPPSYS1] = {
|
||||
.name = "vppsys1",
|
||||
.sta_mask = BIT(12),
|
||||
.ctl_offs = 0x368,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VPPSYS1,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VPPSYS1_2ND,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VPPSYS1,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
|
||||
},
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_VDOSYS1] = {
|
||||
.name = "vdosys1",
|
||||
.sta_mask = BIT(14),
|
||||
.ctl_offs = 0x370,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDOSYS1,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDOSYS1_2ND,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDOSYS1,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
|
||||
},
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_DP_TX] = {
|
||||
.name = "dp_tx",
|
||||
.sta_mask = BIT(16),
|
||||
.ctl_offs = 0x378,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_1_DP_TX,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_1_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_1_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_1_STA1),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_EPD_TX] = {
|
||||
.name = "epd_tx",
|
||||
.sta_mask = BIT(17),
|
||||
.ctl_offs = 0x37C,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_1_EPD_TX,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_1_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_1_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_VDNR_1_STA1),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_HDMI_TX] = {
|
||||
.name = "hdmi_tx",
|
||||
.sta_mask = BIT(18),
|
||||
.ctl_offs = 0x380,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_ACTIVE_WAKEUP,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_WPESYS] = {
|
||||
.name = "wpesys",
|
||||
.sta_mask = BIT(15),
|
||||
.ctl_offs = 0x374,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_WPESYS,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_WPESYS,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_WPESYS_2ND,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
|
||||
},
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_VDEC0] = {
|
||||
.name = "vdec0",
|
||||
.sta_mask = BIT(20),
|
||||
.ctl_offs = 0x388,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDEC0,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDEC0,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDEC0_2ND,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDEC0_2ND,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_VDEC1] = {
|
||||
.name = "vdec1",
|
||||
.sta_mask = BIT(21),
|
||||
.ctl_offs = 0x38C,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDEC1,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDEC1_2ND,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_VDEC2] = {
|
||||
.name = "vdec2",
|
||||
.sta_mask = BIT(22),
|
||||
.ctl_offs = 0x390,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDEC2,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDEC2_2ND,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_VENC] = {
|
||||
.name = "venc",
|
||||
.sta_mask = BIT(23),
|
||||
.ctl_offs = 0x394,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VENC,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VENC_2ND,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VENC,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_VENC_CORE1] = {
|
||||
.name = "venc_core1",
|
||||
.sta_mask = BIT(24),
|
||||
.ctl_offs = 0x398,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VENC_CORE1,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VENC_CORE1,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_IMG] = {
|
||||
.name = "img",
|
||||
.sta_mask = BIT(29),
|
||||
.ctl_offs = 0x3AC,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_IMG,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_IMG_2ND,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_DIP] = {
|
||||
.name = "dip",
|
||||
.sta_mask = BIT(30),
|
||||
.ctl_offs = 0x3B0,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_IPE] = {
|
||||
.name = "ipe",
|
||||
.sta_mask = BIT(31),
|
||||
.ctl_offs = 0x3B4,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_IPE,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_IPE,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_CAM] = {
|
||||
.name = "cam",
|
||||
.sta_mask = BIT(25),
|
||||
.ctl_offs = 0x39C,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.bp_infracfg = {
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_CAM,
|
||||
MT8195_TOP_AXI_PROT_EN_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_2_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_CAM,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_1_CAM,
|
||||
MT8195_TOP_AXI_PROT_EN_1_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_1_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_1_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_CAM_2ND,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_STA1),
|
||||
BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_CAM,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_SET,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
|
||||
MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
|
||||
},
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_CAM_RAWA] = {
|
||||
.name = "cam_rawa",
|
||||
.sta_mask = BIT(26),
|
||||
.ctl_offs = 0x3A0,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_CAM_RAWB] = {
|
||||
.name = "cam_rawb",
|
||||
.sta_mask = BIT(27),
|
||||
.ctl_offs = 0x3A4,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
[MT8195_POWER_DOMAIN_CAM_MRAW] = {
|
||||
.name = "cam_mraw",
|
||||
.sta_mask = BIT(28),
|
||||
.ctl_offs = 0x3A8,
|
||||
.pwr_sta_offs = 0x16c,
|
||||
.pwr_sta2nd_offs = 0x170,
|
||||
.sram_pdn_bits = GENMASK(8, 8),
|
||||
.sram_pdn_ack_bits = GENMASK(12, 12),
|
||||
.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct scpsys_soc_data mt8195_scpsys_data = {
|
||||
.domains_data = scpsys_domain_data_mt8195,
|
||||
.num_domains = ARRAY_SIZE(scpsys_domain_data_mt8195),
|
||||
};
|
||||
|
||||
#endif /* __SOC_MEDIATEK_MT8195_PM_DOMAINS_H */
|
|
@ -6,6 +6,7 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/soc/mediatek/infracfg.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
|
@ -72,3 +73,21 @@ int mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask,
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init mtk_infracfg_init(void)
|
||||
{
|
||||
struct regmap *infracfg;
|
||||
|
||||
/*
|
||||
* MT8192 has an experimental path to route GPU traffic to the DSU's
|
||||
* Accelerator Coherency Port, which is inadvertently enabled by
|
||||
* default. It turns out not to work, so disable it to prevent spurious
|
||||
* GPU faults.
|
||||
*/
|
||||
infracfg = syscon_regmap_lookup_by_compatible("mediatek,mt8192-infracfg");
|
||||
if (!IS_ERR(infracfg))
|
||||
regmap_set_bits(infracfg, MT8192_INFRA_CTRL,
|
||||
MT8192_INFRA_CTRL_DISABLE_MFG2ACP);
|
||||
return 0;
|
||||
}
|
||||
postcore_initcall(mtk_infracfg_init);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "mtk-mmsys.h"
|
||||
#include "mt8167-mmsys.h"
|
||||
#include "mt8183-mmsys.h"
|
||||
#include "mt8186-mmsys.h"
|
||||
#include "mt8192-mmsys.h"
|
||||
#include "mt8365-mmsys.h"
|
||||
|
||||
|
@ -48,12 +49,21 @@ static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
|
|||
.clk_driver = "clk-mt8173-mm",
|
||||
.routes = mmsys_default_routing_table,
|
||||
.num_routes = ARRAY_SIZE(mmsys_default_routing_table),
|
||||
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
|
||||
};
|
||||
|
||||
static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
|
||||
.clk_driver = "clk-mt8183-mm",
|
||||
.routes = mmsys_mt8183_routing_table,
|
||||
.num_routes = ARRAY_SIZE(mmsys_mt8183_routing_table),
|
||||
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
|
||||
};
|
||||
|
||||
static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = {
|
||||
.clk_driver = "clk-mt8186-mm",
|
||||
.routes = mmsys_mt8186_routing_table,
|
||||
.num_routes = ARRAY_SIZE(mmsys_mt8186_routing_table),
|
||||
.sw0_rst_offset = MT8186_MMSYS_SW0_RST_B,
|
||||
};
|
||||
|
||||
static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
|
||||
|
@ -121,14 +131,14 @@ static int mtk_mmsys_reset_update(struct reset_controller_dev *rcdev, unsigned l
|
|||
|
||||
spin_lock_irqsave(&mmsys->lock, flags);
|
||||
|
||||
reg = readl_relaxed(mmsys->regs + MMSYS_SW0_RST_B);
|
||||
reg = readl_relaxed(mmsys->regs + mmsys->data->sw0_rst_offset);
|
||||
|
||||
if (assert)
|
||||
reg &= ~BIT(id);
|
||||
else
|
||||
reg |= BIT(id);
|
||||
|
||||
writel_relaxed(reg, mmsys->regs + MMSYS_SW0_RST_B);
|
||||
writel_relaxed(reg, mmsys->regs + mmsys->data->sw0_rst_offset);
|
||||
|
||||
spin_unlock_irqrestore(&mmsys->lock, flags);
|
||||
|
||||
|
@ -242,6 +252,10 @@ static const struct of_device_id of_match_mtk_mmsys[] = {
|
|||
.compatible = "mediatek,mt8183-mmsys",
|
||||
.data = &mt8183_mmsys_driver_data,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8186-mmsys",
|
||||
.data = &mt8186_mmsys_driver_data,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8192-mmsys",
|
||||
.data = &mt8192_mmsys_driver_data,
|
||||
|
|
|
@ -78,8 +78,6 @@
|
|||
#define DSI_SEL_IN_RDMA 0x1
|
||||
#define DSI_SEL_IN_MASK 0x1
|
||||
|
||||
#define MMSYS_SW0_RST_B 0x140
|
||||
|
||||
struct mtk_mmsys_routes {
|
||||
u32 from_comp;
|
||||
u32 to_comp;
|
||||
|
@ -92,6 +90,7 @@ struct mtk_mmsys_driver_data {
|
|||
const char *clk_driver;
|
||||
const struct mtk_mmsys_routes *routes;
|
||||
const unsigned int num_routes;
|
||||
const u16 sw0_rst_offset;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -26,6 +26,23 @@
|
|||
|
||||
#define INT_MUTEX BIT(1)
|
||||
|
||||
#define MT8186_MUTEX_MOD_DISP_OVL0 0
|
||||
#define MT8186_MUTEX_MOD_DISP_OVL0_2L 1
|
||||
#define MT8186_MUTEX_MOD_DISP_RDMA0 2
|
||||
#define MT8186_MUTEX_MOD_DISP_COLOR0 4
|
||||
#define MT8186_MUTEX_MOD_DISP_CCORR0 5
|
||||
#define MT8186_MUTEX_MOD_DISP_AAL0 7
|
||||
#define MT8186_MUTEX_MOD_DISP_GAMMA0 8
|
||||
#define MT8186_MUTEX_MOD_DISP_POSTMASK0 9
|
||||
#define MT8186_MUTEX_MOD_DISP_DITHER0 10
|
||||
#define MT8186_MUTEX_MOD_DISP_RDMA1 17
|
||||
|
||||
#define MT8186_MUTEX_SOF_SINGLE_MODE 0
|
||||
#define MT8186_MUTEX_SOF_DSI0 1
|
||||
#define MT8186_MUTEX_SOF_DPI0 2
|
||||
#define MT8186_MUTEX_EOF_DSI0 (MT8186_MUTEX_SOF_DSI0 << 6)
|
||||
#define MT8186_MUTEX_EOF_DPI0 (MT8186_MUTEX_SOF_DPI0 << 6)
|
||||
|
||||
#define MT8167_MUTEX_MOD_DISP_PWM 1
|
||||
#define MT8167_MUTEX_MOD_DISP_OVL0 6
|
||||
#define MT8167_MUTEX_MOD_DISP_OVL1 7
|
||||
|
@ -226,6 +243,19 @@ static const unsigned int mt8183_mutex_mod[DDP_COMPONENT_ID_MAX] = {
|
|||
[DDP_COMPONENT_WDMA0] = MT8183_MUTEX_MOD_DISP_WDMA0,
|
||||
};
|
||||
|
||||
static const unsigned int mt8186_mutex_mod[DDP_COMPONENT_ID_MAX] = {
|
||||
[DDP_COMPONENT_AAL0] = MT8186_MUTEX_MOD_DISP_AAL0,
|
||||
[DDP_COMPONENT_CCORR] = MT8186_MUTEX_MOD_DISP_CCORR0,
|
||||
[DDP_COMPONENT_COLOR0] = MT8186_MUTEX_MOD_DISP_COLOR0,
|
||||
[DDP_COMPONENT_DITHER] = MT8186_MUTEX_MOD_DISP_DITHER0,
|
||||
[DDP_COMPONENT_GAMMA] = MT8186_MUTEX_MOD_DISP_GAMMA0,
|
||||
[DDP_COMPONENT_OVL0] = MT8186_MUTEX_MOD_DISP_OVL0,
|
||||
[DDP_COMPONENT_OVL_2L0] = MT8186_MUTEX_MOD_DISP_OVL0_2L,
|
||||
[DDP_COMPONENT_POSTMASK0] = MT8186_MUTEX_MOD_DISP_POSTMASK0,
|
||||
[DDP_COMPONENT_RDMA0] = MT8186_MUTEX_MOD_DISP_RDMA0,
|
||||
[DDP_COMPONENT_RDMA1] = MT8186_MUTEX_MOD_DISP_RDMA1,
|
||||
};
|
||||
|
||||
static const unsigned int mt8192_mutex_mod[DDP_COMPONENT_ID_MAX] = {
|
||||
[DDP_COMPONENT_AAL0] = MT8192_MUTEX_MOD_DISP_AAL0,
|
||||
[DDP_COMPONENT_CCORR] = MT8192_MUTEX_MOD_DISP_CCORR0,
|
||||
|
@ -264,6 +294,12 @@ static const unsigned int mt8183_mutex_sof[MUTEX_SOF_DSI3 + 1] = {
|
|||
[MUTEX_SOF_DPI0] = MT8183_MUTEX_SOF_DPI0 | MT8183_MUTEX_EOF_DPI0,
|
||||
};
|
||||
|
||||
static const unsigned int mt8186_mutex_sof[MUTEX_SOF_DSI3 + 1] = {
|
||||
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
|
||||
[MUTEX_SOF_DSI0] = MT8186_MUTEX_SOF_DSI0 | MT8186_MUTEX_EOF_DSI0,
|
||||
[MUTEX_SOF_DPI0] = MT8186_MUTEX_SOF_DPI0 | MT8186_MUTEX_EOF_DPI0,
|
||||
};
|
||||
|
||||
static const struct mtk_mutex_data mt2701_mutex_driver_data = {
|
||||
.mutex_mod = mt2701_mutex_mod,
|
||||
.mutex_sof = mt2712_mutex_sof,
|
||||
|
@ -301,6 +337,13 @@ static const struct mtk_mutex_data mt8183_mutex_driver_data = {
|
|||
.no_clk = true,
|
||||
};
|
||||
|
||||
static const struct mtk_mutex_data mt8186_mutex_driver_data = {
|
||||
.mutex_mod = mt8186_mutex_mod,
|
||||
.mutex_sof = mt8186_mutex_sof,
|
||||
.mutex_mod_reg = MT8183_MUTEX0_MOD0,
|
||||
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
|
||||
};
|
||||
|
||||
static const struct mtk_mutex_data mt8192_mutex_driver_data = {
|
||||
.mutex_mod = mt8192_mutex_mod,
|
||||
.mutex_sof = mt8183_mutex_sof,
|
||||
|
@ -540,6 +583,8 @@ static const struct of_device_id mutex_driver_dt_match[] = {
|
|||
.data = &mt8173_mutex_driver_data},
|
||||
{ .compatible = "mediatek,mt8183-disp-mutex",
|
||||
.data = &mt8183_mutex_driver_data},
|
||||
{ .compatible = "mediatek,mt8186-disp-mutex",
|
||||
.data = &mt8186_mutex_driver_data},
|
||||
{ .compatible = "mediatek,mt8192-disp-mutex",
|
||||
.data = &mt8192_mutex_driver_data},
|
||||
{},
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
#include "mt8167-pm-domains.h"
|
||||
#include "mt8173-pm-domains.h"
|
||||
#include "mt8183-pm-domains.h"
|
||||
#include "mt8186-pm-domains.h"
|
||||
#include "mt8192-pm-domains.h"
|
||||
#include "mt8195-pm-domains.h"
|
||||
|
||||
#define MTK_POLL_DELAY_US 10
|
||||
#define MTK_POLL_TIMEOUT USEC_PER_SEC
|
||||
|
@ -60,10 +62,10 @@ static bool scpsys_domain_is_on(struct scpsys_domain *pd)
|
|||
struct scpsys *scpsys = pd->scpsys;
|
||||
u32 status, status2;
|
||||
|
||||
regmap_read(scpsys->base, scpsys->soc_data->pwr_sta_offs, &status);
|
||||
regmap_read(scpsys->base, pd->data->pwr_sta_offs, &status);
|
||||
status &= pd->data->sta_mask;
|
||||
|
||||
regmap_read(scpsys->base, scpsys->soc_data->pwr_sta2nd_offs, &status2);
|
||||
regmap_read(scpsys->base, pd->data->pwr_sta2nd_offs, &status2);
|
||||
status2 &= pd->data->sta_mask;
|
||||
|
||||
/* A domain is on when both status bits are set. */
|
||||
|
@ -443,6 +445,9 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
|
|||
pd->genpd.power_off = scpsys_power_off;
|
||||
pd->genpd.power_on = scpsys_power_on;
|
||||
|
||||
if (MTK_SCPD_CAPS(pd, MTK_SCPD_ACTIVE_WAKEUP))
|
||||
pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
|
||||
|
||||
if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF))
|
||||
pm_genpd_init(&pd->genpd, NULL, true);
|
||||
else
|
||||
|
@ -562,10 +567,18 @@ static const struct of_device_id scpsys_of_match[] = {
|
|||
.compatible = "mediatek,mt8183-power-controller",
|
||||
.data = &mt8183_scpsys_data,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8186-power-controller",
|
||||
.data = &mt8186_scpsys_data,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8192-power-controller",
|
||||
.data = &mt8192_scpsys_data,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8195-power-controller",
|
||||
.data = &mt8195_scpsys_data,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#define PWR_STATUS_AUDIO BIT(24)
|
||||
#define PWR_STATUS_USB BIT(25)
|
||||
|
||||
#define SPM_MAX_BUS_PROT_DATA 5
|
||||
#define SPM_MAX_BUS_PROT_DATA 6
|
||||
|
||||
#define _BUS_PROT(_mask, _set, _clr, _sta, _update, _ignore) { \
|
||||
.bus_prot_mask = (_mask), \
|
||||
|
@ -72,8 +72,6 @@ struct scpsys_bus_prot_data {
|
|||
bool ignore_clr_ack;
|
||||
};
|
||||
|
||||
#define MAX_SUBSYS_CLKS 10
|
||||
|
||||
/**
|
||||
* struct scpsys_domain_data - scp domain data for power on/off flow
|
||||
* @name: The name of the power domain.
|
||||
|
@ -94,13 +92,13 @@ struct scpsys_domain_data {
|
|||
u8 caps;
|
||||
const struct scpsys_bus_prot_data bp_infracfg[SPM_MAX_BUS_PROT_DATA];
|
||||
const struct scpsys_bus_prot_data bp_smi[SPM_MAX_BUS_PROT_DATA];
|
||||
int pwr_sta_offs;
|
||||
int pwr_sta2nd_offs;
|
||||
};
|
||||
|
||||
struct scpsys_soc_data {
|
||||
const struct scpsys_domain_data *domains_data;
|
||||
int num_domains;
|
||||
int pwr_sta_offs;
|
||||
int pwr_sta2nd_offs;
|
||||
};
|
||||
|
||||
#endif /* __SOC_MEDIATEK_MTK_PM_DOMAINS_H */
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#define PWRAP_GET_WACS_REQ(x) (((x) >> 19) & 0x00000001)
|
||||
#define PWRAP_STATE_SYNC_IDLE0 BIT(20)
|
||||
#define PWRAP_STATE_INIT_DONE0 BIT(21)
|
||||
#define PWRAP_STATE_INIT_DONE0_MT8186 BIT(22)
|
||||
#define PWRAP_STATE_INIT_DONE1 BIT(15)
|
||||
|
||||
/* macro for WACS FSM */
|
||||
|
@ -77,6 +78,7 @@
|
|||
#define PWRAP_CAP_INT1_EN BIT(3)
|
||||
#define PWRAP_CAP_WDT_SRC1 BIT(4)
|
||||
#define PWRAP_CAP_ARB BIT(5)
|
||||
#define PWRAP_CAP_ARB_MT8186 BIT(8)
|
||||
|
||||
/* defines for slave device wrapper registers */
|
||||
enum dew_regs {
|
||||
|
@ -1063,6 +1065,55 @@ static int mt8516_regs[] = {
|
|||
[PWRAP_MSB_FIRST] = 0x170,
|
||||
};
|
||||
|
||||
static int mt8186_regs[] = {
|
||||
[PWRAP_MUX_SEL] = 0x0,
|
||||
[PWRAP_WRAP_EN] = 0x4,
|
||||
[PWRAP_DIO_EN] = 0x8,
|
||||
[PWRAP_RDDMY] = 0x20,
|
||||
[PWRAP_CSHEXT_WRITE] = 0x24,
|
||||
[PWRAP_CSHEXT_READ] = 0x28,
|
||||
[PWRAP_CSLEXT_WRITE] = 0x2C,
|
||||
[PWRAP_CSLEXT_READ] = 0x30,
|
||||
[PWRAP_EXT_CK_WRITE] = 0x34,
|
||||
[PWRAP_STAUPD_CTRL] = 0x3C,
|
||||
[PWRAP_STAUPD_GRPEN] = 0x40,
|
||||
[PWRAP_EINT_STA0_ADR] = 0x44,
|
||||
[PWRAP_EINT_STA1_ADR] = 0x48,
|
||||
[PWRAP_INT_CLR] = 0xC8,
|
||||
[PWRAP_INT_FLG] = 0xC4,
|
||||
[PWRAP_MAN_EN] = 0x7C,
|
||||
[PWRAP_MAN_CMD] = 0x80,
|
||||
[PWRAP_WACS0_EN] = 0x8C,
|
||||
[PWRAP_WACS1_EN] = 0x94,
|
||||
[PWRAP_WACS2_EN] = 0x9C,
|
||||
[PWRAP_INIT_DONE0] = 0x90,
|
||||
[PWRAP_INIT_DONE1] = 0x98,
|
||||
[PWRAP_INIT_DONE2] = 0xA0,
|
||||
[PWRAP_INT_EN] = 0xBC,
|
||||
[PWRAP_INT1_EN] = 0xCC,
|
||||
[PWRAP_INT1_FLG] = 0xD4,
|
||||
[PWRAP_INT1_CLR] = 0xD8,
|
||||
[PWRAP_TIMER_EN] = 0xF0,
|
||||
[PWRAP_WDT_UNIT] = 0xF8,
|
||||
[PWRAP_WDT_SRC_EN] = 0xFC,
|
||||
[PWRAP_WDT_SRC_EN_1] = 0x100,
|
||||
[PWRAP_WDT_FLG] = 0x104,
|
||||
[PWRAP_SPMINF_STA] = 0x1B4,
|
||||
[PWRAP_DCM_EN] = 0x1EC,
|
||||
[PWRAP_DCM_DBC_PRD] = 0x1F0,
|
||||
[PWRAP_GPSINF_0_STA] = 0x204,
|
||||
[PWRAP_GPSINF_1_STA] = 0x208,
|
||||
[PWRAP_WACS0_CMD] = 0xC00,
|
||||
[PWRAP_WACS0_RDATA] = 0xC04,
|
||||
[PWRAP_WACS0_VLDCLR] = 0xC08,
|
||||
[PWRAP_WACS1_CMD] = 0xC10,
|
||||
[PWRAP_WACS1_RDATA] = 0xC14,
|
||||
[PWRAP_WACS1_VLDCLR] = 0xC18,
|
||||
[PWRAP_WACS2_CMD] = 0xC20,
|
||||
[PWRAP_WACS2_RDATA] = 0xC24,
|
||||
[PWRAP_WACS2_VLDCLR] = 0xC28,
|
||||
};
|
||||
|
||||
enum pmic_type {
|
||||
PMIC_MT6323,
|
||||
PMIC_MT6351,
|
||||
|
@ -1083,6 +1134,7 @@ enum pwrap_type {
|
|||
PWRAP_MT8135,
|
||||
PWRAP_MT8173,
|
||||
PWRAP_MT8183,
|
||||
PWRAP_MT8186,
|
||||
PWRAP_MT8195,
|
||||
PWRAP_MT8516,
|
||||
};
|
||||
|
@ -1535,6 +1587,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
|
|||
case PWRAP_MT6779:
|
||||
case PWRAP_MT6797:
|
||||
case PWRAP_MT8173:
|
||||
case PWRAP_MT8186:
|
||||
case PWRAP_MT8516:
|
||||
pwrap_writel(wrp, 1, PWRAP_CIPHER_EN);
|
||||
break;
|
||||
|
@ -2069,6 +2122,19 @@ static struct pmic_wrapper_type pwrap_mt8516 = {
|
|||
.init_soc_specific = NULL,
|
||||
};
|
||||
|
||||
static struct pmic_wrapper_type pwrap_mt8186 = {
|
||||
.regs = mt8186_regs,
|
||||
.type = PWRAP_MT8186,
|
||||
.arb_en_all = 0xfb27f,
|
||||
.int_en_all = 0xfffffffe, /* disable WatchDog Timeout for bit 1 */
|
||||
.int1_en_all = 0x000017ff, /* disable Matching interrupt for bit 13 */
|
||||
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
|
||||
.wdt_src = PWRAP_WDT_SRC_MASK_ALL,
|
||||
.caps = PWRAP_CAP_INT1_EN | PWRAP_CAP_ARB_MT8186,
|
||||
.init_reg_clock = pwrap_common_init_reg_clock,
|
||||
.init_soc_specific = NULL,
|
||||
};
|
||||
|
||||
static const struct of_device_id of_pwrap_match_tbl[] = {
|
||||
{
|
||||
.compatible = "mediatek,mt2701-pwrap",
|
||||
|
@ -2097,6 +2163,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = {
|
|||
}, {
|
||||
.compatible = "mediatek,mt8183-pwrap",
|
||||
.data = &pwrap_mt8183,
|
||||
}, {
|
||||
.compatible = "mediatek,mt8186-pwrap",
|
||||
.data = &pwrap_mt8186,
|
||||
}, {
|
||||
.compatible = "mediatek,mt8195-pwrap",
|
||||
.data = &pwrap_mt8195,
|
||||
|
@ -2209,6 +2278,8 @@ static int pwrap_probe(struct platform_device *pdev)
|
|||
|
||||
if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB))
|
||||
mask_done = PWRAP_STATE_INIT_DONE1;
|
||||
else if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB_MT8186))
|
||||
mask_done = PWRAP_STATE_INIT_DONE0_MT8186;
|
||||
else
|
||||
mask_done = PWRAP_STATE_INIT_DONE0;
|
||||
|
||||
|
|
|
@ -95,9 +95,9 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mpfs_sys_controller *sys_controller;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
sys_controller = devm_kzalloc(dev, sizeof(*sys_controller), GFP_KERNEL);
|
||||
sys_controller = kzalloc(sizeof(*sys_controller), GFP_KERNEL);
|
||||
if (!sys_controller)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -106,9 +106,12 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev)
|
|||
sys_controller->client.tx_block = 1U;
|
||||
|
||||
sys_controller->chan = mbox_request_channel(&sys_controller->client, 0);
|
||||
if (IS_ERR(sys_controller->chan))
|
||||
return dev_err_probe(dev, PTR_ERR(sys_controller->chan),
|
||||
"Failed to get mbox channel\n");
|
||||
if (IS_ERR(sys_controller->chan)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(sys_controller->chan),
|
||||
"Failed to get mbox channel\n");
|
||||
kfree(sys_controller);
|
||||
return ret;
|
||||
}
|
||||
|
||||
init_completion(&sys_controller->c);
|
||||
kref_init(&sys_controller->consumers);
|
||||
|
|
|
@ -653,7 +653,6 @@ static void apr_remove(struct rpmsg_device *rpdev)
|
|||
|
||||
pdr_handle_release(apr->pdr);
|
||||
device_for_each_child(&rpdev->dev, NULL, apr_remove_device);
|
||||
flush_workqueue(apr->rxwq);
|
||||
destroy_workqueue(apr->rxwq);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,17 +29,13 @@
|
|||
#define ATTR1_FIXED_SIZE_SHIFT 0x03
|
||||
#define ATTR1_PRIORITY_SHIFT 0x04
|
||||
#define ATTR1_MAX_CAP_SHIFT 0x10
|
||||
#define ATTR0_RES_WAYS_MASK GENMASK(11, 0)
|
||||
#define ATTR0_BONUS_WAYS_MASK GENMASK(27, 16)
|
||||
#define ATTR0_RES_WAYS_MASK GENMASK(15, 0)
|
||||
#define ATTR0_BONUS_WAYS_MASK GENMASK(31, 16)
|
||||
#define ATTR0_BONUS_WAYS_SHIFT 0x10
|
||||
#define LLCC_STATUS_READ_DELAY 100
|
||||
|
||||
#define CACHE_LINE_SIZE_SHIFT 6
|
||||
|
||||
#define LLCC_COMMON_HW_INFO 0x00030000
|
||||
#define LLCC_MAJOR_VERSION_MASK GENMASK(31, 24)
|
||||
|
||||
#define LLCC_COMMON_STATUS0 0x0003000c
|
||||
#define LLCC_LB_CNT_MASK GENMASK(31, 28)
|
||||
#define LLCC_LB_CNT_SHIFT 28
|
||||
|
||||
|
@ -52,9 +48,13 @@
|
|||
#define LLCC_TRP_SCID_DIS_CAP_ALLOC 0x21f00
|
||||
#define LLCC_TRP_PCB_ACT 0x21f04
|
||||
#define LLCC_TRP_WRSC_EN 0x21f20
|
||||
#define LLCC_TRP_WRSC_CACHEABLE_EN 0x21f2c
|
||||
|
||||
#define BANK_OFFSET_STRIDE 0x80000
|
||||
|
||||
#define LLCC_VERSION_2_0_0_0 0x02000000
|
||||
#define LLCC_VERSION_2_1_0_0 0x02010000
|
||||
|
||||
/**
|
||||
* struct llcc_slice_config - Data associated with the llcc slice
|
||||
* @usecase_id: Unique id for the client's use case
|
||||
|
@ -79,6 +79,8 @@
|
|||
* collapse.
|
||||
* @activate_on_init: Activate the slice immediately after it is programmed
|
||||
* @write_scid_en: Bit enables write cache support for a given scid.
|
||||
* @write_scid_cacheable_en: Enables write cache cacheable support for a
|
||||
* given scid (not supported on v2 or older hardware).
|
||||
*/
|
||||
struct llcc_slice_config {
|
||||
u32 usecase_id;
|
||||
|
@ -94,12 +96,19 @@ struct llcc_slice_config {
|
|||
bool retain_on_pc;
|
||||
bool activate_on_init;
|
||||
bool write_scid_en;
|
||||
bool write_scid_cacheable_en;
|
||||
};
|
||||
|
||||
struct qcom_llcc_config {
|
||||
const struct llcc_slice_config *sct_data;
|
||||
int size;
|
||||
bool need_llcc_cfg;
|
||||
const u32 *reg_offset;
|
||||
};
|
||||
|
||||
enum llcc_reg_offset {
|
||||
LLCC_COMMON_HW_INFO,
|
||||
LLCC_COMMON_STATUS0,
|
||||
};
|
||||
|
||||
static const struct llcc_slice_config sc7180_data[] = {
|
||||
|
@ -217,42 +226,96 @@ static const struct llcc_slice_config sm8350_data[] = {
|
|||
{ LLCC_CPUHWT, 5, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 1 },
|
||||
};
|
||||
|
||||
static const struct llcc_slice_config sm8450_data[] = {
|
||||
{LLCC_CPUSS, 1, 3072, 1, 0, 0xFFFF, 0x0, 0, 0, 0, 1, 1, 0, 0 },
|
||||
{LLCC_VIDSC0, 2, 512, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{LLCC_AUDIO, 6, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{LLCC_MDMHPGRW, 7, 1024, 3, 0, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{LLCC_MODHW, 9, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{LLCC_CMPT, 10, 4096, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{LLCC_GPUHTW, 11, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{LLCC_GPU, 12, 2048, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 1, 0 },
|
||||
{LLCC_MMUHWT, 13, 768, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0 },
|
||||
{LLCC_DISP, 16, 4096, 2, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{LLCC_MDMPNG, 21, 1024, 1, 1, 0xF000, 0x0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{LLCC_AUDHW, 22, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{LLCC_CVP, 28, 256, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{LLCC_MODPE, 29, 64, 1, 1, 0xF000, 0x0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0xF0, 1, 0, 0, 1, 0, 0, 0 },
|
||||
{LLCC_WRCACHE, 31, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0 },
|
||||
{LLCC_CVPFW, 17, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{LLCC_CPUSS1, 3, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{LLCC_CAMEXP0, 4, 256, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{LLCC_CPUMTE, 23, 256, 1, 1, 0x0FFF, 0x0, 0, 0, 0, 0, 1, 0, 0 },
|
||||
{LLCC_CPUHWT, 5, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 1, 0, 0 },
|
||||
{LLCC_CAMEXP1, 27, 256, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
|
||||
{LLCC_AENPU, 8, 2048, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static const u32 llcc_v1_2_reg_offset[] = {
|
||||
[LLCC_COMMON_HW_INFO] = 0x00030000,
|
||||
[LLCC_COMMON_STATUS0] = 0x0003000c,
|
||||
};
|
||||
|
||||
static const u32 llcc_v21_reg_offset[] = {
|
||||
[LLCC_COMMON_HW_INFO] = 0x00034000,
|
||||
[LLCC_COMMON_STATUS0] = 0x0003400c,
|
||||
};
|
||||
|
||||
static const struct qcom_llcc_config sc7180_cfg = {
|
||||
.sct_data = sc7180_data,
|
||||
.size = ARRAY_SIZE(sc7180_data),
|
||||
.need_llcc_cfg = true,
|
||||
.reg_offset = llcc_v1_2_reg_offset,
|
||||
};
|
||||
|
||||
static const struct qcom_llcc_config sc7280_cfg = {
|
||||
.sct_data = sc7280_data,
|
||||
.size = ARRAY_SIZE(sc7280_data),
|
||||
.need_llcc_cfg = true,
|
||||
.reg_offset = llcc_v1_2_reg_offset,
|
||||
};
|
||||
|
||||
static const struct qcom_llcc_config sdm845_cfg = {
|
||||
.sct_data = sdm845_data,
|
||||
.size = ARRAY_SIZE(sdm845_data),
|
||||
.need_llcc_cfg = false,
|
||||
.reg_offset = llcc_v1_2_reg_offset,
|
||||
};
|
||||
|
||||
static const struct qcom_llcc_config sm6350_cfg = {
|
||||
.sct_data = sm6350_data,
|
||||
.size = ARRAY_SIZE(sm6350_data),
|
||||
.need_llcc_cfg = true,
|
||||
.reg_offset = llcc_v1_2_reg_offset,
|
||||
};
|
||||
|
||||
static const struct qcom_llcc_config sm8150_cfg = {
|
||||
.sct_data = sm8150_data,
|
||||
.size = ARRAY_SIZE(sm8150_data),
|
||||
.need_llcc_cfg = true,
|
||||
.reg_offset = llcc_v1_2_reg_offset,
|
||||
};
|
||||
|
||||
static const struct qcom_llcc_config sm8250_cfg = {
|
||||
.sct_data = sm8250_data,
|
||||
.size = ARRAY_SIZE(sm8250_data),
|
||||
.need_llcc_cfg = true,
|
||||
.reg_offset = llcc_v1_2_reg_offset,
|
||||
};
|
||||
|
||||
static const struct qcom_llcc_config sm8350_cfg = {
|
||||
.sct_data = sm8350_data,
|
||||
.size = ARRAY_SIZE(sm8350_data),
|
||||
.need_llcc_cfg = true,
|
||||
.reg_offset = llcc_v1_2_reg_offset,
|
||||
};
|
||||
|
||||
static const struct qcom_llcc_config sm8450_cfg = {
|
||||
.sct_data = sm8450_data,
|
||||
.size = ARRAY_SIZE(sm8450_data),
|
||||
.need_llcc_cfg = true,
|
||||
.reg_offset = llcc_v21_reg_offset,
|
||||
};
|
||||
|
||||
static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
|
||||
|
@ -504,7 +567,7 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (drv_data->major_version == 2) {
|
||||
if (drv_data->version >= LLCC_VERSION_2_0_0_0) {
|
||||
u32 wren;
|
||||
|
||||
wren = config->write_scid_en << config->slice_id;
|
||||
|
@ -514,6 +577,16 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (drv_data->version >= LLCC_VERSION_2_1_0_0) {
|
||||
u32 wr_cache_en;
|
||||
|
||||
wr_cache_en = config->write_scid_cacheable_en << config->slice_id;
|
||||
ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_WRSC_CACHEABLE_EN,
|
||||
BIT(config->slice_id), wr_cache_en);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (config->activate_on_init) {
|
||||
desc.slice_id = config->slice_id;
|
||||
ret = llcc_slice_activate(&desc);
|
||||
|
@ -598,15 +671,18 @@ static int qcom_llcc_probe(struct platform_device *pdev)
|
|||
goto err;
|
||||
}
|
||||
|
||||
/* Extract major version of the IP */
|
||||
ret = regmap_read(drv_data->bcast_regmap, LLCC_COMMON_HW_INFO, &version);
|
||||
cfg = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
/* Extract version of the IP */
|
||||
ret = regmap_read(drv_data->bcast_regmap, cfg->reg_offset[LLCC_COMMON_HW_INFO],
|
||||
&version);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
drv_data->major_version = FIELD_GET(LLCC_MAJOR_VERSION_MASK, version);
|
||||
drv_data->version = version;
|
||||
|
||||
ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0,
|
||||
&num_banks);
|
||||
ret = regmap_read(drv_data->regmap, cfg->reg_offset[LLCC_COMMON_STATUS0],
|
||||
&num_banks);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
|
@ -614,7 +690,6 @@ static int qcom_llcc_probe(struct platform_device *pdev)
|
|||
num_banks >>= LLCC_LB_CNT_SHIFT;
|
||||
drv_data->num_banks = num_banks;
|
||||
|
||||
cfg = of_device_get_match_data(&pdev->dev);
|
||||
llcc_cfg = cfg->sct_data;
|
||||
sz = cfg->size;
|
||||
|
||||
|
@ -632,9 +707,8 @@ static int qcom_llcc_probe(struct platform_device *pdev)
|
|||
for (i = 0; i < num_banks; i++)
|
||||
drv_data->offsets[i] = i * BANK_OFFSET_STRIDE;
|
||||
|
||||
drv_data->bitmap = devm_kcalloc(dev,
|
||||
BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long),
|
||||
GFP_KERNEL);
|
||||
drv_data->bitmap = devm_bitmap_zalloc(dev, drv_data->max_slices,
|
||||
GFP_KERNEL);
|
||||
if (!drv_data->bitmap) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
|
@ -672,6 +746,7 @@ static const struct of_device_id qcom_llcc_of_match[] = {
|
|||
{ .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfg },
|
||||
{ .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg },
|
||||
{ .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfg },
|
||||
{ .compatible = "qcom,sm8450-llcc", .data = &sm8450_cfg },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -31,6 +31,44 @@ static bool mdt_phdr_valid(const struct elf32_phdr *phdr)
|
|||
return true;
|
||||
}
|
||||
|
||||
static ssize_t mdt_load_split_segment(void *ptr, const struct elf32_phdr *phdrs,
|
||||
unsigned int segment, const char *fw_name,
|
||||
struct device *dev)
|
||||
{
|
||||
const struct elf32_phdr *phdr = &phdrs[segment];
|
||||
const struct firmware *seg_fw;
|
||||
char *seg_name;
|
||||
ssize_t ret;
|
||||
|
||||
if (strlen(fw_name) < 4)
|
||||
return -EINVAL;
|
||||
|
||||
seg_name = kstrdup(fw_name, GFP_KERNEL);
|
||||
if (!seg_name)
|
||||
return -ENOMEM;
|
||||
|
||||
sprintf(seg_name + strlen(fw_name) - 3, "b%02d", segment);
|
||||
ret = request_firmware_into_buf(&seg_fw, seg_name, dev,
|
||||
ptr, phdr->p_filesz);
|
||||
if (ret) {
|
||||
dev_err(dev, "error %zd loading %s\n", ret, seg_name);
|
||||
kfree(seg_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (seg_fw->size != phdr->p_filesz) {
|
||||
dev_err(dev,
|
||||
"failed to load segment %d from truncated file %s\n",
|
||||
segment, seg_name);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
release_firmware(seg_fw);
|
||||
kfree(seg_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* qcom_mdt_get_size() - acquire size of the memory region needed to load mdt
|
||||
* @fw: firmware object for the mdt file
|
||||
|
@ -83,13 +121,17 @@ EXPORT_SYMBOL_GPL(qcom_mdt_get_size);
|
|||
*
|
||||
* Return: pointer to data, or ERR_PTR()
|
||||
*/
|
||||
void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len)
|
||||
void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len,
|
||||
const char *fw_name, struct device *dev)
|
||||
{
|
||||
const struct elf32_phdr *phdrs;
|
||||
const struct elf32_hdr *ehdr;
|
||||
unsigned int hash_segment = 0;
|
||||
size_t hash_offset;
|
||||
size_t hash_size;
|
||||
size_t ehdr_size;
|
||||
unsigned int i;
|
||||
ssize_t ret;
|
||||
void *data;
|
||||
|
||||
ehdr = (struct elf32_hdr *)fw->data;
|
||||
|
@ -101,24 +143,44 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len)
|
|||
if (phdrs[0].p_type == PT_LOAD)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if ((phdrs[1].p_flags & QCOM_MDT_TYPE_MASK) != QCOM_MDT_TYPE_HASH)
|
||||
for (i = 1; i < ehdr->e_phnum; i++) {
|
||||
if ((phdrs[i].p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) {
|
||||
hash_segment = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hash_segment) {
|
||||
dev_err(dev, "no hash segment found in %s\n", fw_name);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
ehdr_size = phdrs[0].p_filesz;
|
||||
hash_size = phdrs[1].p_filesz;
|
||||
hash_size = phdrs[hash_segment].p_filesz;
|
||||
|
||||
data = kmalloc(ehdr_size + hash_size, GFP_KERNEL);
|
||||
if (!data)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* Is the header and hash already packed */
|
||||
if (ehdr_size + hash_size == fw->size)
|
||||
hash_offset = phdrs[0].p_filesz;
|
||||
else
|
||||
hash_offset = phdrs[1].p_offset;
|
||||
|
||||
/* Copy ELF header */
|
||||
memcpy(data, fw->data, ehdr_size);
|
||||
memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
|
||||
|
||||
if (ehdr_size + hash_size == fw->size) {
|
||||
/* Firmware is split and hash is packed following the ELF header */
|
||||
hash_offset = phdrs[0].p_filesz;
|
||||
memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
|
||||
} else if (phdrs[hash_segment].p_offset + hash_size <= fw->size) {
|
||||
/* Hash is in its own segment, but within the loaded file */
|
||||
hash_offset = phdrs[hash_segment].p_offset;
|
||||
memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
|
||||
} else {
|
||||
/* Hash is in its own segment, beyond the loaded file */
|
||||
ret = mdt_load_split_segment(data + ehdr_size, phdrs, hash_segment, fw_name, dev);
|
||||
if (ret) {
|
||||
kfree(data);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
|
||||
*data_len = ehdr_size + hash_size;
|
||||
|
||||
|
@ -126,23 +188,85 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
|
||||
|
||||
/**
|
||||
* qcom_mdt_pas_init() - initialize PAS region for firmware loading
|
||||
* @dev: device handle to associate resources with
|
||||
* @fw: firmware object for the mdt file
|
||||
* @firmware: name of the firmware, for construction of segment file names
|
||||
* @pas_id: PAS identifier
|
||||
* @mem_phys: physical address of allocated memory region
|
||||
* @ctx: PAS metadata context, to be released by caller
|
||||
*
|
||||
* Returns 0 on success, negative errno otherwise.
|
||||
*/
|
||||
int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
|
||||
const char *fw_name, int pas_id, phys_addr_t mem_phys,
|
||||
struct qcom_scm_pas_metadata *ctx)
|
||||
{
|
||||
const struct elf32_phdr *phdrs;
|
||||
const struct elf32_phdr *phdr;
|
||||
const struct elf32_hdr *ehdr;
|
||||
phys_addr_t min_addr = PHYS_ADDR_MAX;
|
||||
phys_addr_t max_addr = 0;
|
||||
size_t metadata_len;
|
||||
void *metadata;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ehdr = (struct elf32_hdr *)fw->data;
|
||||
phdrs = (struct elf32_phdr *)(ehdr + 1);
|
||||
|
||||
for (i = 0; i < ehdr->e_phnum; i++) {
|
||||
phdr = &phdrs[i];
|
||||
|
||||
if (!mdt_phdr_valid(phdr))
|
||||
continue;
|
||||
|
||||
if (phdr->p_paddr < min_addr)
|
||||
min_addr = phdr->p_paddr;
|
||||
|
||||
if (phdr->p_paddr + phdr->p_memsz > max_addr)
|
||||
max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
|
||||
}
|
||||
|
||||
metadata = qcom_mdt_read_metadata(fw, &metadata_len, fw_name, dev);
|
||||
if (IS_ERR(metadata)) {
|
||||
ret = PTR_ERR(metadata);
|
||||
dev_err(dev, "error %d reading firmware %s metadata\n", ret, fw_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = qcom_scm_pas_init_image(pas_id, metadata, metadata_len, ctx);
|
||||
kfree(metadata);
|
||||
if (ret) {
|
||||
/* Invalid firmware metadata */
|
||||
dev_err(dev, "error %d initializing firmware %s\n", ret, fw_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
|
||||
if (ret) {
|
||||
/* Unable to set up relocation */
|
||||
dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_mdt_pas_init);
|
||||
|
||||
static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
|
||||
const char *firmware, int pas_id, void *mem_region,
|
||||
const char *fw_name, int pas_id, void *mem_region,
|
||||
phys_addr_t mem_phys, size_t mem_size,
|
||||
phys_addr_t *reloc_base, bool pas_init)
|
||||
{
|
||||
const struct elf32_phdr *phdrs;
|
||||
const struct elf32_phdr *phdr;
|
||||
const struct elf32_hdr *ehdr;
|
||||
const struct firmware *seg_fw;
|
||||
phys_addr_t mem_reloc;
|
||||
phys_addr_t min_addr = PHYS_ADDR_MAX;
|
||||
phys_addr_t max_addr = 0;
|
||||
size_t metadata_len;
|
||||
size_t fw_name_len;
|
||||
ssize_t offset;
|
||||
void *metadata;
|
||||
char *fw_name;
|
||||
bool relocate = false;
|
||||
void *ptr;
|
||||
int ret = 0;
|
||||
|
@ -154,34 +278,6 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
|
|||
ehdr = (struct elf32_hdr *)fw->data;
|
||||
phdrs = (struct elf32_phdr *)(ehdr + 1);
|
||||
|
||||
fw_name_len = strlen(firmware);
|
||||
if (fw_name_len <= 4)
|
||||
return -EINVAL;
|
||||
|
||||
fw_name = kstrdup(firmware, GFP_KERNEL);
|
||||
if (!fw_name)
|
||||
return -ENOMEM;
|
||||
|
||||
if (pas_init) {
|
||||
metadata = qcom_mdt_read_metadata(fw, &metadata_len);
|
||||
if (IS_ERR(metadata)) {
|
||||
ret = PTR_ERR(metadata);
|
||||
dev_err(dev, "error %d reading firmware %s metadata\n",
|
||||
ret, fw_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = qcom_scm_pas_init_image(pas_id, metadata, metadata_len);
|
||||
|
||||
kfree(metadata);
|
||||
if (ret) {
|
||||
/* Invalid firmware metadata */
|
||||
dev_err(dev, "error %d initializing firmware %s\n",
|
||||
ret, fw_name);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ehdr->e_phnum; i++) {
|
||||
phdr = &phdrs[i];
|
||||
|
||||
|
@ -193,23 +289,9 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
|
|||
|
||||
if (phdr->p_paddr < min_addr)
|
||||
min_addr = phdr->p_paddr;
|
||||
|
||||
if (phdr->p_paddr + phdr->p_memsz > max_addr)
|
||||
max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
|
||||
}
|
||||
|
||||
if (relocate) {
|
||||
if (pas_init) {
|
||||
ret = qcom_scm_pas_mem_setup(pas_id, mem_phys,
|
||||
max_addr - min_addr);
|
||||
if (ret) {
|
||||
/* Unable to set up relocation */
|
||||
dev_err(dev, "error %d setting up firmware %s\n",
|
||||
ret, fw_name);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The image is relocatable, so offset each segment based on
|
||||
* the lowest segment address.
|
||||
|
@ -246,7 +328,8 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
|
|||
|
||||
ptr = mem_region + offset;
|
||||
|
||||
if (phdr->p_filesz && phdr->p_offset < fw->size) {
|
||||
if (phdr->p_filesz && phdr->p_offset < fw->size &&
|
||||
phdr->p_offset + phdr->p_filesz <= fw->size) {
|
||||
/* Firmware is large enough to be non-split */
|
||||
if (phdr->p_offset + phdr->p_filesz > fw->size) {
|
||||
dev_err(dev, "file %s segment %d would be truncated\n",
|
||||
|
@ -258,25 +341,9 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
|
|||
memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
|
||||
} else if (phdr->p_filesz) {
|
||||
/* Firmware not large enough, load split-out segments */
|
||||
sprintf(fw_name + fw_name_len - 3, "b%02d", i);
|
||||
ret = request_firmware_into_buf(&seg_fw, fw_name, dev,
|
||||
ptr, phdr->p_filesz);
|
||||
if (ret) {
|
||||
dev_err(dev, "error %d loading %s\n",
|
||||
ret, fw_name);
|
||||
ret = mdt_load_split_segment(ptr, phdrs, i, fw_name, dev);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
if (seg_fw->size != phdr->p_filesz) {
|
||||
dev_err(dev,
|
||||
"failed to load segment %d from truncated file %s\n",
|
||||
i, fw_name);
|
||||
release_firmware(seg_fw);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
release_firmware(seg_fw);
|
||||
}
|
||||
|
||||
if (phdr->p_memsz > phdr->p_filesz)
|
||||
|
@ -286,9 +353,6 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
|
|||
if (reloc_base)
|
||||
*reloc_base = mem_reloc;
|
||||
|
||||
out:
|
||||
kfree(fw_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -310,6 +374,12 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw,
|
|||
phys_addr_t mem_phys, size_t mem_size,
|
||||
phys_addr_t *reloc_base)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = qcom_mdt_pas_init(dev, fw, firmware, pas_id, mem_phys, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys,
|
||||
mem_size, reloc_base, true);
|
||||
}
|
||||
|
|
|
@ -206,6 +206,7 @@ struct ocmem *of_get_ocmem(struct device *dev)
|
|||
ocmem = platform_get_drvdata(pdev);
|
||||
if (!ocmem) {
|
||||
dev_err(dev, "Cannot get ocmem\n");
|
||||
put_device(&pdev->dev);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
return ocmem;
|
||||
|
|
|
@ -451,7 +451,11 @@ struct qmp *qmp_get(struct device *dev)
|
|||
|
||||
qmp = platform_get_drvdata(pdev);
|
||||
|
||||
return qmp ? qmp : ERR_PTR(-EPROBE_DEFER);
|
||||
if (!qmp) {
|
||||
put_device(&pdev->dev);
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
return qmp;
|
||||
}
|
||||
EXPORT_SYMBOL(qmp_get);
|
||||
|
||||
|
@ -497,7 +501,7 @@ static int qmp_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
ret = devm_request_irq(&pdev->dev, irq, qmp_intr, IRQF_ONESHOT,
|
||||
ret = devm_request_irq(&pdev->dev, irq, qmp_intr, 0,
|
||||
"aoss-qmp", qmp);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to request interrupt\n");
|
||||
|
|
|
@ -138,6 +138,22 @@ static const struct rpmpd_desc mdm9607_desc = {
|
|||
.max_state = RPM_SMD_LEVEL_TURBO,
|
||||
};
|
||||
|
||||
/* msm8226 RPM Power Domains */
|
||||
DEFINE_RPMPD_PAIR(msm8226, vddcx, vddcx_ao, SMPA, CORNER, 1);
|
||||
DEFINE_RPMPD_VFC(msm8226, vddcx_vfc, SMPA, 1);
|
||||
|
||||
static struct rpmpd *msm8226_rpmpds[] = {
|
||||
[MSM8226_VDDCX] = &msm8226_vddcx,
|
||||
[MSM8226_VDDCX_AO] = &msm8226_vddcx_ao,
|
||||
[MSM8226_VDDCX_VFC] = &msm8226_vddcx_vfc,
|
||||
};
|
||||
|
||||
static const struct rpmpd_desc msm8226_desc = {
|
||||
.rpmpds = msm8226_rpmpds,
|
||||
.num_pds = ARRAY_SIZE(msm8226_rpmpds),
|
||||
.max_state = MAX_CORNER_RPMPD_STATE,
|
||||
};
|
||||
|
||||
/* msm8939 RPM Power Domains */
|
||||
DEFINE_RPMPD_PAIR(msm8939, vddmd, vddmd_ao, SMPA, CORNER, 1);
|
||||
DEFINE_RPMPD_VFC(msm8939, vddmd_vfc, SMPA, 1);
|
||||
|
@ -436,6 +452,7 @@ static const struct rpmpd_desc qcm2290_desc = {
|
|||
|
||||
static const struct of_device_id rpmpd_match_table[] = {
|
||||
{ .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc },
|
||||
{ .compatible = "qcom,msm8226-rpmpd", .data = &msm8226_desc },
|
||||
{ .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc },
|
||||
{ .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc },
|
||||
{ .compatible = "qcom,msm8953-rpmpd", .data = &msm8953_desc },
|
||||
|
@ -610,6 +627,9 @@ static int rpmpd_probe(struct platform_device *pdev)
|
|||
|
||||
data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains),
|
||||
GFP_KERNEL);
|
||||
if (!data->domains)
|
||||
return -ENOMEM;
|
||||
|
||||
data->num_domains = num;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
|
|
|
@ -104,6 +104,14 @@ static const char *const pmic_models[] = {
|
|||
[36] = "PM8009",
|
||||
[38] = "PM8150C",
|
||||
[41] = "SMB2351",
|
||||
[47] = "PMK8350",
|
||||
[48] = "PM8350",
|
||||
[49] = "PM8350C",
|
||||
[50] = "PM8350B",
|
||||
[51] = "PMR735A",
|
||||
[52] = "PMR735B",
|
||||
[58] = "PM8450",
|
||||
[65] = "PM8010",
|
||||
};
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
|
@ -314,10 +322,14 @@ static const struct soc_id soc_id[] = {
|
|||
{ 422, "IPQ6010" },
|
||||
{ 425, "SC7180" },
|
||||
{ 434, "SM6350" },
|
||||
{ 439, "SM8350" },
|
||||
{ 449, "SC8280XP" },
|
||||
{ 453, "IPQ6005" },
|
||||
{ 455, "QRB5165" },
|
||||
{ 457, "SM8450" },
|
||||
{ 459, "SM7225" },
|
||||
{ 460, "SA8540P" },
|
||||
{ 480, "SM8450" },
|
||||
};
|
||||
|
||||
static const char *socinfo_machine(struct device *dev, unsigned int id)
|
||||
|
|
|
@ -40,6 +40,11 @@ config ARCH_RMOBILE
|
|||
select SYS_SUPPORTS_SH_TMU
|
||||
select SYSC_RMOBILE
|
||||
|
||||
config ARCH_RZG2L
|
||||
bool
|
||||
select PM
|
||||
select PM_GENERIC_DOMAINS
|
||||
|
||||
config ARCH_RZN1
|
||||
bool
|
||||
select ARM_AMBA
|
||||
|
@ -293,9 +298,16 @@ config ARCH_R8A774B1
|
|||
|
||||
config ARCH_R9A07G044
|
||||
bool "ARM64 Platform support for RZ/G2L"
|
||||
select ARCH_RZG2L
|
||||
help
|
||||
This enables support for the Renesas RZ/G2L SoC variants.
|
||||
|
||||
config ARCH_R9A07G054
|
||||
bool "ARM64 Platform support for RZ/V2L"
|
||||
select ARCH_RZG2L
|
||||
help
|
||||
This enables support for the Renesas RZ/V2L SoC variants.
|
||||
|
||||
endif # ARM64
|
||||
|
||||
config RST_RCAR
|
||||
|
|
|
@ -64,6 +64,10 @@ static const struct renesas_family fam_rzg2l __initconst __maybe_unused = {
|
|||
.name = "RZ/G2L",
|
||||
};
|
||||
|
||||
static const struct renesas_family fam_rzv2l __initconst __maybe_unused = {
|
||||
.name = "RZ/V2L",
|
||||
};
|
||||
|
||||
static const struct renesas_family fam_shmobile __initconst __maybe_unused = {
|
||||
.name = "SH-Mobile",
|
||||
.reg = 0xe600101c, /* CCCR (Common Chip Code Register) */
|
||||
|
@ -144,6 +148,11 @@ static const struct renesas_soc soc_rz_g2l __initconst __maybe_unused = {
|
|||
.id = 0x841c447,
|
||||
};
|
||||
|
||||
static const struct renesas_soc soc_rz_v2l __initconst __maybe_unused = {
|
||||
.family = &fam_rzv2l,
|
||||
.id = 0x8447447,
|
||||
};
|
||||
|
||||
static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = {
|
||||
.family = &fam_rcar_gen1,
|
||||
};
|
||||
|
@ -334,6 +343,9 @@ static const struct of_device_id renesas_socs[] __initconst = {
|
|||
#if defined(CONFIG_ARCH_R9A07G044)
|
||||
{ .compatible = "renesas,r9a07g044", .data = &soc_rz_g2l },
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_R9A07G054)
|
||||
{ .compatible = "renesas,r9a07g054", .data = &soc_rz_v2l },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_SH73A0
|
||||
{ .compatible = "renesas,sh73a0", .data = &soc_shmobile_ag5 },
|
||||
#endif
|
||||
|
@ -367,6 +379,7 @@ static const struct renesas_id id_prr __initconst = {
|
|||
static const struct of_device_id renesas_ids[] __initconst = {
|
||||
{ .compatible = "renesas,bsid", .data = &id_bsid },
|
||||
{ .compatible = "renesas,r9a07g044-sysc", .data = &id_rzg2l },
|
||||
{ .compatible = "renesas,r9a07g054-sysc", .data = &id_rzg2l },
|
||||
{ .compatible = "renesas,prr", .data = &id_prr },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
@ -380,9 +393,11 @@ static int __init renesas_soc_init(void)
|
|||
const struct renesas_soc *soc;
|
||||
const struct renesas_id *id;
|
||||
void __iomem *chipid = NULL;
|
||||
const char *rev_prefix = "";
|
||||
struct soc_device *soc_dev;
|
||||
struct device_node *np;
|
||||
const char *soc_id;
|
||||
int ret;
|
||||
|
||||
match = of_match_node(renesas_socs, of_root);
|
||||
if (!match)
|
||||
|
@ -403,6 +418,17 @@ static int __init renesas_soc_init(void)
|
|||
chipid = ioremap(family->reg, 4);
|
||||
}
|
||||
|
||||
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
|
||||
if (!soc_dev_attr)
|
||||
return -ENOMEM;
|
||||
|
||||
np = of_find_node_by_path("/");
|
||||
of_property_read_string(np, "model", &soc_dev_attr->machine);
|
||||
of_node_put(np);
|
||||
|
||||
soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL);
|
||||
soc_dev_attr->soc_id = kstrdup_const(soc_id, GFP_KERNEL);
|
||||
|
||||
if (chipid) {
|
||||
product = readl(chipid + id->offset);
|
||||
iounmap(chipid);
|
||||
|
@ -417,41 +443,39 @@ static int __init renesas_soc_init(void)
|
|||
|
||||
eshi = ((product >> 4) & 0x0f) + 1;
|
||||
eslo = product & 0xf;
|
||||
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u",
|
||||
eshi, eslo);
|
||||
} else if (id == &id_rzg2l) {
|
||||
eshi = ((product >> 28) & 0x0f);
|
||||
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u",
|
||||
eshi);
|
||||
rev_prefix = "Rev ";
|
||||
}
|
||||
|
||||
if (soc->id &&
|
||||
((product & id->mask) >> __ffs(id->mask)) != soc->id) {
|
||||
pr_warn("SoC mismatch (product = 0x%x)\n", product);
|
||||
return -ENODEV;
|
||||
ret = -ENODEV;
|
||||
goto free_soc_dev_attr;
|
||||
}
|
||||
}
|
||||
|
||||
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
|
||||
if (!soc_dev_attr)
|
||||
return -ENOMEM;
|
||||
|
||||
np = of_find_node_by_path("/");
|
||||
of_property_read_string(np, "model", &soc_dev_attr->machine);
|
||||
of_node_put(np);
|
||||
|
||||
soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL);
|
||||
soc_dev_attr->soc_id = kstrdup_const(soc_id, GFP_KERNEL);
|
||||
if (eshi)
|
||||
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u", eshi,
|
||||
eslo);
|
||||
|
||||
pr_info("Detected Renesas %s %s %s\n", soc_dev_attr->family,
|
||||
soc_dev_attr->soc_id, soc_dev_attr->revision ?: "");
|
||||
pr_info("Detected Renesas %s %s %s%s\n", soc_dev_attr->family,
|
||||
soc_dev_attr->soc_id, rev_prefix, soc_dev_attr->revision ?: "");
|
||||
|
||||
soc_dev = soc_device_register(soc_dev_attr);
|
||||
if (IS_ERR(soc_dev)) {
|
||||
kfree(soc_dev_attr->revision);
|
||||
kfree_const(soc_dev_attr->soc_id);
|
||||
kfree_const(soc_dev_attr->family);
|
||||
kfree(soc_dev_attr);
|
||||
return PTR_ERR(soc_dev);
|
||||
ret = PTR_ERR(soc_dev);
|
||||
goto free_soc_dev_attr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_soc_dev_attr:
|
||||
kfree(soc_dev_attr->revision);
|
||||
kfree_const(soc_dev_attr->soc_id);
|
||||
kfree_const(soc_dev_attr->family);
|
||||
kfree(soc_dev_attr);
|
||||
return ret;
|
||||
}
|
||||
early_initcall(renesas_soc_init);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2013-2021, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
@ -161,6 +161,12 @@ static const struct nvmem_cell_info tegra_fuse_cells[] = {
|
|||
.bytes = 4,
|
||||
.bit_offset = 0,
|
||||
.nbits = 32,
|
||||
}, {
|
||||
.name = "gcplex-config-fuse",
|
||||
.offset = 0x1c8,
|
||||
.bytes = 4,
|
||||
.bit_offset = 0,
|
||||
.nbits = 32,
|
||||
}, {
|
||||
.name = "tsensor-realignment",
|
||||
.offset = 0x1fc,
|
||||
|
@ -179,13 +185,25 @@ static const struct nvmem_cell_info tegra_fuse_cells[] = {
|
|||
.bytes = 4,
|
||||
.bit_offset = 0,
|
||||
.nbits = 32,
|
||||
}, {
|
||||
.name = "pdi0",
|
||||
.offset = 0x300,
|
||||
.bytes = 4,
|
||||
.bit_offset = 0,
|
||||
.nbits = 32,
|
||||
}, {
|
||||
.name = "pdi1",
|
||||
.offset = 0x304,
|
||||
.bytes = 4,
|
||||
.bit_offset = 0,
|
||||
.nbits = 32,
|
||||
},
|
||||
};
|
||||
|
||||
static void tegra_fuse_restore(void *base)
|
||||
{
|
||||
fuse->base = (void __iomem *)base;
|
||||
fuse->clk = NULL;
|
||||
fuse->base = base;
|
||||
}
|
||||
|
||||
static int tegra_fuse_probe(struct platform_device *pdev)
|
||||
|
@ -195,7 +213,7 @@ static int tegra_fuse_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
int err;
|
||||
|
||||
err = devm_add_action(&pdev->dev, tegra_fuse_restore, base);
|
||||
err = devm_add_action(&pdev->dev, tegra_fuse_restore, (void __force *)base);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* drivers/soc/tegra/pmc.c
|
||||
*
|
||||
* Copyright (c) 2010 Google, Inc
|
||||
* Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@google.com>
|
||||
|
@ -54,6 +54,7 @@
|
|||
#include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
|
||||
#include <dt-bindings/gpio/tegra186-gpio.h>
|
||||
#include <dt-bindings/gpio/tegra194-gpio.h>
|
||||
#include <dt-bindings/gpio/tegra234-gpio.h>
|
||||
#include <dt-bindings/soc/tegra-pmc.h>
|
||||
|
||||
#define PMC_CNTRL 0x0
|
||||
|
@ -3066,7 +3067,7 @@ static void tegra20_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
|
|||
}
|
||||
|
||||
static const struct tegra_pmc_soc tegra20_pmc_soc = {
|
||||
.supports_core_domain = false,
|
||||
.supports_core_domain = true,
|
||||
.num_powergates = ARRAY_SIZE(tegra20_powergates),
|
||||
.powergates = tegra20_powergates,
|
||||
.num_cpu_powergates = 0,
|
||||
|
@ -3127,7 +3128,7 @@ static const char * const tegra30_reset_sources[] = {
|
|||
};
|
||||
|
||||
static const struct tegra_pmc_soc tegra30_pmc_soc = {
|
||||
.supports_core_domain = false,
|
||||
.supports_core_domain = true,
|
||||
.num_powergates = ARRAY_SIZE(tegra30_powergates),
|
||||
.powergates = tegra30_powergates,
|
||||
.num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates),
|
||||
|
@ -3788,6 +3789,11 @@ static const char * const tegra234_reset_sources[] = {
|
|||
"FUSECRC",
|
||||
};
|
||||
|
||||
static const struct tegra_wake_event tegra234_wake_events[] = {
|
||||
TEGRA_WAKE_GPIO("power", 29, 1, TEGRA234_AON_GPIO(EE, 4)),
|
||||
TEGRA_WAKE_IRQ("rtc", 73, 10),
|
||||
};
|
||||
|
||||
static const struct tegra_pmc_soc tegra234_pmc_soc = {
|
||||
.supports_core_domain = false,
|
||||
.num_powergates = 0,
|
||||
|
@ -3812,8 +3818,8 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = {
|
|||
.num_reset_sources = ARRAY_SIZE(tegra234_reset_sources),
|
||||
.reset_levels = tegra186_reset_levels,
|
||||
.num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
|
||||
.num_wake_events = 0,
|
||||
.wake_events = NULL,
|
||||
.num_wake_events = ARRAY_SIZE(tegra234_wake_events),
|
||||
.wake_events = tegra234_wake_events,
|
||||
.pmc_clks_data = NULL,
|
||||
.num_pmc_clks = 0,
|
||||
.has_blink_output = false,
|
||||
|
|
|
@ -1402,12 +1402,10 @@ static int k3_ringacc_init(struct platform_device *pdev,
|
|||
sizeof(*ringacc->rings) *
|
||||
ringacc->num_rings,
|
||||
GFP_KERNEL);
|
||||
ringacc->rings_inuse = devm_kcalloc(dev,
|
||||
BITS_TO_LONGS(ringacc->num_rings),
|
||||
sizeof(unsigned long), GFP_KERNEL);
|
||||
ringacc->proxy_inuse = devm_kcalloc(dev,
|
||||
BITS_TO_LONGS(ringacc->num_proxies),
|
||||
sizeof(unsigned long), GFP_KERNEL);
|
||||
ringacc->rings_inuse = devm_bitmap_zalloc(dev, ringacc->num_rings,
|
||||
GFP_KERNEL);
|
||||
ringacc->proxy_inuse = devm_bitmap_zalloc(dev, ringacc->num_proxies,
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!ringacc->rings || !ringacc->rings_inuse || !ringacc->proxy_inuse)
|
||||
return -ENOMEM;
|
||||
|
@ -1483,9 +1481,8 @@ struct k3_ringacc *k3_ringacc_dmarings_init(struct platform_device *pdev,
|
|||
sizeof(*ringacc->rings) *
|
||||
ringacc->num_rings * 2,
|
||||
GFP_KERNEL);
|
||||
ringacc->rings_inuse = devm_kcalloc(dev,
|
||||
BITS_TO_LONGS(ringacc->num_rings),
|
||||
sizeof(unsigned long), GFP_KERNEL);
|
||||
ringacc->rings_inuse = devm_bitmap_zalloc(dev, ringacc->num_rings,
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!ringacc->rings || !ringacc->rings_inuse)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
|
|
@ -42,6 +42,7 @@ static const struct k3_soc_id {
|
|||
{ 0xBB6D, "J7200" },
|
||||
{ 0xBB38, "AM64X" },
|
||||
{ 0xBB75, "J721S2"},
|
||||
{ 0xBB7E, "AM62X" },
|
||||
};
|
||||
|
||||
static int
|
||||
|
|
|
@ -819,7 +819,7 @@ static int omap_sr_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct omap_sr *sr_info;
|
||||
struct omap_sr_data *pdata = pdev->dev.platform_data;
|
||||
struct resource *mem, *irq;
|
||||
struct resource *mem;
|
||||
struct dentry *nvalue_dir;
|
||||
int i, ret = 0;
|
||||
|
||||
|
@ -844,7 +844,11 @@ static int omap_sr_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(sr_info->base))
|
||||
return PTR_ERR(sr_info->base);
|
||||
|
||||
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
ret = platform_get_irq_optional(pdev, 0);
|
||||
if (ret < 0 && ret != -ENXIO)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to get IRQ resource\n");
|
||||
if (ret > 0)
|
||||
sr_info->irq = ret;
|
||||
|
||||
sr_info->fck = devm_clk_get(pdev->dev.parent, "fck");
|
||||
if (IS_ERR(sr_info->fck))
|
||||
|
@ -870,9 +874,6 @@ static int omap_sr_probe(struct platform_device *pdev)
|
|||
sr_info->autocomp_active = false;
|
||||
sr_info->ip_type = pdata->ip_type;
|
||||
|
||||
if (irq)
|
||||
sr_info->irq = irq->start;
|
||||
|
||||
sr_set_clk_length(sr_info);
|
||||
|
||||
list_add(&sr_info->node, &sr_list);
|
||||
|
@ -926,7 +927,7 @@ static int omap_sr_probe(struct platform_device *pdev)
|
|||
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
|
||||
err_debugfs:
|
||||
debugfs_remove_recursive(sr_info->dbg_dir);
|
||||
|
|
|
@ -450,9 +450,9 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(m3_ipc->ipc_mem_base);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (!irq) {
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq resource\n");
|
||||
return -ENXIO;
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, irq, wkup_m3_txev_handler,
|
||||
|
|
|
@ -122,7 +122,7 @@ static int amd_params_to_tee_params(struct tee_param *tee, u32 count,
|
|||
}
|
||||
|
||||
static DEFINE_MUTEX(ta_refcount_mutex);
|
||||
static struct list_head ta_list = LIST_HEAD_INIT(ta_list);
|
||||
static LIST_HEAD(ta_list);
|
||||
|
||||
static u32 get_ta_refcount(u32 ta_handle)
|
||||
{
|
||||
|
|
|
@ -8,13 +8,17 @@
|
|||
#include <linux/psp-sev.h>
|
||||
#include "amdtee_private.h"
|
||||
|
||||
static int pool_op_alloc(struct tee_shm_pool_mgr *poolm, struct tee_shm *shm,
|
||||
size_t size)
|
||||
static int pool_op_alloc(struct tee_shm_pool *pool, struct tee_shm *shm,
|
||||
size_t size, size_t align)
|
||||
{
|
||||
unsigned int order = get_order(size);
|
||||
unsigned long va;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Ignore alignment since this is already going to be page aligned
|
||||
* and there's no need for any larger alignment.
|
||||
*/
|
||||
va = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
|
||||
if (!va)
|
||||
return -ENOMEM;
|
||||
|
@ -34,7 +38,7 @@ static int pool_op_alloc(struct tee_shm_pool_mgr *poolm, struct tee_shm *shm,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void pool_op_free(struct tee_shm_pool_mgr *poolm, struct tee_shm *shm)
|
||||
static void pool_op_free(struct tee_shm_pool *pool, struct tee_shm *shm)
|
||||
{
|
||||
/* Unmap the shared memory from TEE */
|
||||
amdtee_unmap_shmem(shm);
|
||||
|
@ -42,52 +46,25 @@ static void pool_op_free(struct tee_shm_pool_mgr *poolm, struct tee_shm *shm)
|
|||
shm->kaddr = NULL;
|
||||
}
|
||||
|
||||
static void pool_op_destroy_poolmgr(struct tee_shm_pool_mgr *poolm)
|
||||
static void pool_op_destroy_pool(struct tee_shm_pool *pool)
|
||||
{
|
||||
kfree(poolm);
|
||||
kfree(pool);
|
||||
}
|
||||
|
||||
static const struct tee_shm_pool_mgr_ops pool_ops = {
|
||||
static const struct tee_shm_pool_ops pool_ops = {
|
||||
.alloc = pool_op_alloc,
|
||||
.free = pool_op_free,
|
||||
.destroy_poolmgr = pool_op_destroy_poolmgr,
|
||||
.destroy_pool = pool_op_destroy_pool,
|
||||
};
|
||||
|
||||
static struct tee_shm_pool_mgr *pool_mem_mgr_alloc(void)
|
||||
{
|
||||
struct tee_shm_pool_mgr *mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
|
||||
|
||||
if (!mgr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mgr->ops = &pool_ops;
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
struct tee_shm_pool *amdtee_config_shm(void)
|
||||
{
|
||||
struct tee_shm_pool_mgr *priv_mgr;
|
||||
struct tee_shm_pool_mgr *dmabuf_mgr;
|
||||
void *rc;
|
||||
struct tee_shm_pool *pool = kzalloc(sizeof(*pool), GFP_KERNEL);
|
||||
|
||||
rc = pool_mem_mgr_alloc();
|
||||
if (IS_ERR(rc))
|
||||
return rc;
|
||||
priv_mgr = rc;
|
||||
if (!pool)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
rc = pool_mem_mgr_alloc();
|
||||
if (IS_ERR(rc)) {
|
||||
tee_shm_pool_mgr_destroy(priv_mgr);
|
||||
return rc;
|
||||
}
|
||||
dmabuf_mgr = rc;
|
||||
pool->ops = &pool_ops;
|
||||
|
||||
rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
|
||||
if (IS_ERR(rc)) {
|
||||
tee_shm_pool_mgr_destroy(priv_mgr);
|
||||
tee_shm_pool_mgr_destroy(dmabuf_mgr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
return pool;
|
||||
}
|
||||
|
|
|
@ -7,11 +7,3 @@ config OPTEE
|
|||
help
|
||||
This implements the OP-TEE Trusted Execution Environment (TEE)
|
||||
driver.
|
||||
|
||||
config OPTEE_SHM_NUM_PRIV_PAGES
|
||||
int "Private Shared Memory Pages"
|
||||
default 1
|
||||
depends on OPTEE
|
||||
help
|
||||
This sets the number of private shared memory pages to be
|
||||
used by OP-TEE TEE driver.
|
||||
|
|
|
@ -120,7 +120,7 @@ struct tee_shm *optee_get_msg_arg(struct tee_context *ctx, size_t num_params,
|
|||
if (optee->rpc_arg_count)
|
||||
sz += OPTEE_MSG_GET_ARG_SIZE(optee->rpc_arg_count);
|
||||
|
||||
shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED | TEE_SHM_PRIV);
|
||||
shm = tee_shm_alloc_priv_buf(ctx, sz);
|
||||
if (IS_ERR(shm))
|
||||
return shm;
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include <linux/workqueue.h>
|
||||
#include "optee_private.h"
|
||||
|
||||
int optee_pool_op_alloc_helper(struct tee_shm_pool_mgr *poolm,
|
||||
struct tee_shm *shm, size_t size,
|
||||
int optee_pool_op_alloc_helper(struct tee_shm_pool *pool, struct tee_shm *shm,
|
||||
size_t size, size_t align,
|
||||
int (*shm_register)(struct tee_context *ctx,
|
||||
struct tee_shm *shm,
|
||||
struct page **pages,
|
||||
|
@ -30,6 +30,10 @@ int optee_pool_op_alloc_helper(struct tee_shm_pool_mgr *poolm,
|
|||
struct page *page;
|
||||
int rc = 0;
|
||||
|
||||
/*
|
||||
* Ignore alignment since this is already going to be page aligned
|
||||
* and there's no need for any larger alignment.
|
||||
*/
|
||||
page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
@ -51,7 +55,6 @@ int optee_pool_op_alloc_helper(struct tee_shm_pool_mgr *poolm,
|
|||
for (i = 0; i < nr_pages; i++)
|
||||
pages[i] = page + i;
|
||||
|
||||
shm->flags |= TEE_SHM_REGISTER;
|
||||
rc = shm_register(shm->ctx, shm, pages, nr_pages,
|
||||
(unsigned long)shm->kaddr);
|
||||
kfree(pages);
|
||||
|
@ -62,10 +65,20 @@ int optee_pool_op_alloc_helper(struct tee_shm_pool_mgr *poolm,
|
|||
return 0;
|
||||
|
||||
err:
|
||||
__free_pages(page, order);
|
||||
free_pages((unsigned long)shm->kaddr, order);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void optee_pool_op_free_helper(struct tee_shm_pool *pool, struct tee_shm *shm,
|
||||
int (*shm_unregister)(struct tee_context *ctx,
|
||||
struct tee_shm *shm))
|
||||
{
|
||||
if (shm_unregister)
|
||||
shm_unregister(shm->ctx, shm);
|
||||
free_pages((unsigned long)shm->kaddr, get_order(shm->size));
|
||||
shm->kaddr = NULL;
|
||||
}
|
||||
|
||||
static void optee_bus_scan(struct work_struct *work)
|
||||
{
|
||||
WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
|
||||
|
|
|
@ -121,10 +121,9 @@ static int __optee_enumerate_devices(u32 func)
|
|||
if (rc < 0 || !shm_size)
|
||||
goto out_sess;
|
||||
|
||||
device_shm = tee_shm_alloc(ctx, shm_size,
|
||||
TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
|
||||
device_shm = tee_shm_alloc_kernel_buf(ctx, shm_size);
|
||||
if (IS_ERR(device_shm)) {
|
||||
pr_err("tee_shm_alloc failed\n");
|
||||
pr_err("tee_shm_alloc_kernel_buf failed\n");
|
||||
rc = PTR_ERR(device_shm);
|
||||
goto out_sess;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue