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:
Linus Torvalds 2022-03-23 18:23:13 -07:00
commit b4bc93bd76
124 changed files with 7644 additions and 1435 deletions

View file

@ -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

View file

@ -27,6 +27,8 @@ properties:
- qcom,sm6350-llcc
- qcom,sm8150-llcc
- qcom,sm8250-llcc
- qcom,sm8350-llcc
- qcom,sm8450-llcc
reg:
items:

View 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";
};
...

View file

@ -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>;
};
};
};

View file

@ -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>;
};

View file

@ -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>;

View file

@ -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>;
};
};

View file

@ -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>;
};
};

View file

@ -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>;
};

View file

@ -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>;
};

View file

@ -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>;
};
}

View file

@ -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";
};
};
};
};

View file

@ -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>;
};
};

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -17,6 +17,7 @@ properties:
compatible:
enum:
- qcom,mdm9607-rpmpd
- qcom,msm8226-rpmpd
- qcom,msm8916-rpmpd
- qcom,msm8939-rpmpd
- qcom,msm8953-rpmpd

View file

@ -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:

View file

@ -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

View file

@ -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;

View file

@ -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,

View file

@ -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 @@ static int imx_weim_gpr_setup(struct platform_device *pdev)
}
/* 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");

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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.

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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)

View file

@ -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) \

View file

@ -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)) {

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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);

View file

@ -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

View file

@ -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;

View 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,
};

View file

@ -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),
};

View file

@ -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),
};

View file

@ -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);

View file

@ -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 },

View file

@ -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 @@ static enum qcom_scm_convention __get_convention(void)
/**
* 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 = {

View file

@ -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

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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) {

View file

@ -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:

View file

@ -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},

View file

@ -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)

View file

@ -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.

View file

@ -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;

View file

@ -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,

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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"),

View file

@ -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

View file

@ -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 */
}

View file

@ -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;

View file

@ -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 */

View file

@ -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 */

View file

@ -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,

View file

@ -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 */

View 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 */

View 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 */

View file

@ -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 */

View 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 */

View file

@ -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);

View file

@ -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,

View file

@ -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;
};
/*

View file

@ -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},
{},

View file

@ -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,
},
{ }
};

View file

@ -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 */

View file

@ -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;

View file

@ -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);

View file

@ -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);
}

View file

@ -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 },
{ }
};

View file

@ -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);
}

View file

@ -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;

View file

@ -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");

View file

@ -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++) {

View file

@ -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)

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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,

View file

@ -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);

View file

@ -42,6 +42,7 @@ static const struct k3_soc_id {
{ 0xBB6D, "J7200" },
{ 0xBB38, "AM64X" },
{ 0xBB75, "J721S2"},
{ 0xBB7E, "AM62X" },
};
static int

View file

@ -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);

View file

@ -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,

View file

@ -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)
{

View file

@ -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;
}

View file

@ -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.

View file

@ -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;

View file

@ -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));

View file

@ -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