forked from Minki/linux
ARM: SoC drivers for 5.16
These are all the driver updates for SoC specific drivers. There are a couple of subsystems with individual maintainers picking up their patches here: - The reset controller subsystem add support for a few new SoC variants to existing drivers, along with other minor improvements - The OP-TEE subsystem gets a driver for the ARM FF-A transport - The memory controller subsystem has improvements for Tegra, Mediatek, Renesas, Freescale and Broadcom specific drivers. - The tegra cpuidle driver changes get merged through this tree this time. There are only minor changes, but they depend on other tegra driver updates here. - The ep93xx platform finally moves to using the drivers/clk/ subsystem, moving the code out of arch/arm in the process. This depends on a small sound driver change that is included here as well. - There are some minor updates for Qualcomm and Tegra specific firmware drivers. The other driver updates are mainly for drivers/soc, which contains a mixture of vendor specific drivers that don't really fit elsewhere: - Mediatek drivers gain more support for MT8192, with new support for hw-mutex and mmsys routing, plus support for reset lines in the mmsys driver. - Qualcomm gains a new "sleep stats" driver, and support for the "Generic Packet Router" in the APR driver. - There is a new user interface for routing the UARTS on ASpeed BMCs, something that apparently nobody else has needed so far. - More drivers can now be built as loadable modules, in particular for Broadcom and Samsung platforms. - Lots of improvements to the TI sysc driver for better suspend/resume support Finally, there are lots of minor cleanups and new device IDs for amlogic, renesas, tegra, qualcomm, mediateka, samsung, imx, layerscape, allwinner, broadcom, and omap. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmGCvKgACgkQmmx57+YA GNnNfw/8DDTfMUycVvtaNslYlWri0/2O0nSqhNIIbTAcVuD/x5qo/McDhKuv+ldM BoTDMjRYZfQkrNXSEj3MaxB9E0o6Srva5SM8y4+Koe0VVtvEVovjYkXOhXqSEWWl aqVIe0S6Y1rF/KxJlvAfGxYHb5d+6aYqzdmhjURpXNGxqpSHb9/hqisY97Q9TpnD 6lQZOz9d1JNDq0eOh1qjcfuMjg1EHZHDZJyioCvyX38KIl2q7p3ll2z/eqrrDhQZ TrvL/YVosTXqBcAfi47Oz+n/CX2i0MrjVO8nfPSGOq5UL4Al3SZD4XYY96IOIQrH +XGFigGGAkV2LfKSEPNJWaq7g+SiQUr2jc3p8b4Zxde8/+5M127/gotiPddyG2LX 1OnFRnPskgRApGqHjGEcEzzJUTag7Hc+YVH82TMEHZhSDMq6i30k9UnyfXsziZDV 8CrkOpjuSg+YxFv/83bfa1pIoYtFfjGr16mq4muajodnX7+b7My9iv+2Oo2iQM9y DwRUKj7+eap23SEUpi4et6HlNpoF6yJMbt5Ae1k+gTK2DvQ4Cx6n4QJz/I7WC1Wp BdVhvSH8XVppVLtQqODud+VWvLgLerRxUpGRdbS8r5VsnNUJTvaS4YGMpm9616G7 TrgUSSvsyu1lLqbWMh+pOCk4l3r64vSUn581hrIw6jtioNGvMdE= =tUuj -----END PGP SIGNATURE----- Merge tag 'drivers-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc Pull ARM SoC driver updates from Arnd Bergmann: "These are all the driver updates for SoC specific drivers. There are a couple of subsystems with individual maintainers picking up their patches here: - The reset controller subsystem add support for a few new SoC variants to existing drivers, along with other minor improvements - The OP-TEE subsystem gets a driver for the ARM FF-A transport - The memory controller subsystem has improvements for Tegra, Mediatek, Renesas, Freescale and Broadcom specific drivers. - The tegra cpuidle driver changes get merged through this tree this time. There are only minor changes, but they depend on other tegra driver updates here. - The ep93xx platform finally moves to using the drivers/clk/ subsystem, moving the code out of arch/arm in the process. This depends on a small sound driver change that is included here as well. - There are some minor updates for Qualcomm and Tegra specific firmware drivers. The other driver updates are mainly for drivers/soc, which contains a mixture of vendor specific drivers that don't really fit elsewhere: - Mediatek drivers gain more support for MT8192, with new support for hw-mutex and mmsys routing, plus support for reset lines in the mmsys driver. - Qualcomm gains a new "sleep stats" driver, and support for the "Generic Packet Router" in the APR driver. - There is a new user interface for routing the UARTS on ASpeed BMCs, something that apparently nobody else has needed so far. - More drivers can now be built as loadable modules, in particular for Broadcom and Samsung platforms. - Lots of improvements to the TI sysc driver for better suspend/resume support" Finally, there are lots of minor cleanups and new device IDs for amlogic, renesas, tegra, qualcomm, mediateka, samsung, imx, layerscape, allwinner, broadcom, and omap" * tag 'drivers-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (179 commits) optee: Fix spelling mistake "reclain" -> "reclaim" Revert "firmware: qcom: scm: Add support for MC boot address API" qcom: spm: allow compile-testing firmware: arm_ffa: Remove unused 'compat_version' variable soc: samsung: exynos-chipid: add exynosautov9 SoC support firmware: qcom: scm: Don't break compile test on non-ARM platforms soc: qcom: smp2p: Add of_node_put() before goto soc: qcom: apr: Add of_node_put() before return soc: qcom: qcom_stats: Fix client votes offset soc: qcom: rpmhpd: fix sm8350_mxc's peer domain dt-bindings: arm: cpus: Document qcom,msm8916-smp enable-method ARM: qcom: Add qcom,msm8916-smp enable-method identical to MSM8226 firmware: qcom: scm: Add support for MC boot address API soc: qcom: spm: Add 8916 SPM register data dt-bindings: soc: qcom: spm: Document qcom,msm8916-saw2-v3.0-cpu soc: qcom: socinfo: Add PM8150C and SMB2351 models firmware: qcom_scm: Fix error retval in __qcom_scm_is_call_available() soc: aspeed: Add UART routing support soc: fsl: dpio: rename the enqueue descriptor variable soc: fsl: dpio: use an explicit NULL instead of 0 ...
This commit is contained in:
commit
d461e96cd2
27
Documentation/ABI/testing/sysfs-driver-aspeed-uart-routing
Normal file
27
Documentation/ABI/testing/sysfs-driver-aspeed-uart-routing
Normal file
@ -0,0 +1,27 @@
|
||||
What: /sys/bus/platform/drivers/aspeed-uart-routing/*/uart*
|
||||
Date: September 2021
|
||||
Contact: Oskar Senft <osk@google.com>
|
||||
Chia-Wei Wang <chiawei_wang@aspeedtech.com>
|
||||
Description: Selects the RX source of the UARTx device.
|
||||
|
||||
When read, each file shows the list of available options with currently
|
||||
selected option marked by brackets "[]". The list of available options
|
||||
depends on the selected file.
|
||||
|
||||
e.g.
|
||||
cat /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1
|
||||
[io1] io2 io3 io4 uart2 uart3 uart4 io6
|
||||
|
||||
In this case, UART1 gets its input from IO1 (physical serial port 1).
|
||||
|
||||
Users: OpenBMC. Proposed changes should be mailed to
|
||||
openbmc@lists.ozlabs.org
|
||||
|
||||
What: /sys/bus/platform/drivers/aspeed-uart-routing/*/io*
|
||||
Date: September 2021
|
||||
Contact: Oskar Senft <osk@google.com>
|
||||
Chia-Wei Wang <chiawei_wang@aspeedtech.com>
|
||||
Description: Selects the RX source of IOx serial port. The current selection
|
||||
will be marked by brackets "[]".
|
||||
Users: OpenBMC. Proposed changes should be mailed to
|
||||
openbmc@lists.ozlabs.org
|
@ -211,6 +211,9 @@ properties:
|
||||
- qcom,gcc-msm8660
|
||||
- qcom,kpss-acc-v1
|
||||
- qcom,kpss-acc-v2
|
||||
- qcom,msm8226-smp
|
||||
# Only valid on ARM 32-bit, see above for ARM v8 64-bit
|
||||
- qcom,msm8916-smp
|
||||
- renesas,apmu
|
||||
- renesas,r9a06g032-smp
|
||||
- rockchip,rk3036-smp
|
||||
@ -297,7 +300,8 @@ properties:
|
||||
Specifies the ACC* node associated with this CPU.
|
||||
|
||||
Required for systems that have an "enable-method" property
|
||||
value of "qcom,kpss-acc-v1" or "qcom,kpss-acc-v2"
|
||||
value of "qcom,kpss-acc-v1", "qcom,kpss-acc-v2", "qcom,msm8226-smp" or
|
||||
"qcom,msm8916-smp".
|
||||
|
||||
* arm/msm/qcom,kpss-acc.txt
|
||||
|
||||
|
@ -11,8 +11,9 @@ maintainers:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: samsung,exynos4210-chipid
|
||||
enum:
|
||||
- samsung,exynos4210-chipid
|
||||
- samsung,exynos850-chipid
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -1,102 +0,0 @@
|
||||
* LPDDR2 SDRAM memories compliant to JEDEC JESD209-2
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be one of - "jedec,lpddr2-nvm", "jedec,lpddr2-s2",
|
||||
"jedec,lpddr2-s4"
|
||||
|
||||
"ti,jedec-lpddr2-s2" should be listed if the memory part is LPDDR2-S2 type
|
||||
|
||||
"ti,jedec-lpddr2-s4" should be listed if the memory part is LPDDR2-S4 type
|
||||
|
||||
"ti,jedec-lpddr2-nvm" should be listed if the memory part is LPDDR2-NVM type
|
||||
|
||||
- density : <u32> representing density in Mb (Mega bits)
|
||||
|
||||
- io-width : <u32> representing bus width. Possible values are 8, 16, and 32
|
||||
|
||||
Optional properties:
|
||||
|
||||
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.
|
||||
- tRRD-min-tck
|
||||
- tWTR-min-tck
|
||||
- tXP-min-tck
|
||||
- tRTP-min-tck
|
||||
- tCKE-min-tck
|
||||
- tRPab-min-tck
|
||||
- tRCD-min-tck
|
||||
- tWR-min-tck
|
||||
- tRASmin-min-tck
|
||||
- tCKESR-min-tck
|
||||
- tFAW-min-tck
|
||||
|
||||
Child nodes:
|
||||
- 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/ddr/lpddr2-timings.txt for more information on "lpddr2-timings"
|
||||
|
||||
Example:
|
||||
|
||||
elpida_ECB240ABACN : lpddr2 {
|
||||
compatible = "Elpida,ECB240ABACN","jedec,lpddr2-s4";
|
||||
density = <2048>;
|
||||
io-width = <32>;
|
||||
|
||||
tRPab-min-tck = <3>;
|
||||
tRCD-min-tck = <3>;
|
||||
tWR-min-tck = <3>;
|
||||
tRASmin-min-tck = <3>;
|
||||
tRRD-min-tck = <2>;
|
||||
tWTR-min-tck = <2>;
|
||||
tXP-min-tck = <2>;
|
||||
tRTP-min-tck = <2>;
|
||||
tCKE-min-tck = <3>;
|
||||
tCKESR-min-tck = <3>;
|
||||
tFAW-min-tck = <8>;
|
||||
|
||||
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>;
|
||||
};
|
||||
|
||||
timings_elpida_ECB240ABACN_200mhz: lpddr2-timings@1 {
|
||||
compatible = "jedec,lpddr2-timings";
|
||||
min-freq = <10000000>;
|
||||
max-freq = <200000000>;
|
||||
tRPab = <21000>;
|
||||
tRCD = <18000>;
|
||||
tWR = <15000>;
|
||||
tRAS-min = <42000>;
|
||||
tRRD = <10000>;
|
||||
tWTR = <10000>;
|
||||
tXP = <7500>;
|
||||
tRTP = <7500>;
|
||||
tCKESR = <15000>;
|
||||
tDQSCK-max = <5500>;
|
||||
tFAW = <50000>;
|
||||
tZQCS = <90000>;
|
||||
tZQCL = <360000>;
|
||||
tZQinit = <1000000>;
|
||||
tRAS-max-ns = <70000>;
|
||||
};
|
||||
|
||||
}
|
@ -102,7 +102,6 @@ examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/qcom,dispcc-sc7180.h>
|
||||
#include <dt-bindings/power/qcom-aoss-qmp.h>
|
||||
#include <dt-bindings/power/qcom-rpmpd.h>
|
||||
|
||||
displayport-controller@ae90000 {
|
||||
|
@ -13,8 +13,10 @@ Required properties:
|
||||
* "qcom,scm-ipq806x"
|
||||
* "qcom,scm-ipq8074"
|
||||
* "qcom,scm-mdm9607"
|
||||
* "qcom,scm-msm8226"
|
||||
* "qcom,scm-msm8660"
|
||||
* "qcom,scm-msm8916"
|
||||
* "qcom,scm-msm8953"
|
||||
* "qcom,scm-msm8960"
|
||||
* "qcom,scm-msm8974"
|
||||
* "qcom,scm-msm8994"
|
||||
@ -33,7 +35,7 @@ Required properties:
|
||||
* core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660" and
|
||||
"qcom,scm-msm8960"
|
||||
* core, iface and bus clocks required for "qcom,scm-apq8084",
|
||||
"qcom,scm-msm8916" and "qcom,scm-msm8974"
|
||||
"qcom,scm-msm8916", "qcom,scm-msm8953" and "qcom,scm-msm8974"
|
||||
- clock-names: Must contain "core" for the core clock, "iface" for the interface
|
||||
clock and "bus" for the bus clock per the requirements of the compatible.
|
||||
- qcom,dload-mode: phandle to the TCSR hardware block and offset of the
|
||||
|
@ -0,0 +1,223 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,lpddr2.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: LPDDR2 SDRAM compliant to JEDEC JESD209-2
|
||||
|
||||
maintainers:
|
||||
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- elpida,ECB240ABACN
|
||||
- elpida,B8132B2PB-6D-F
|
||||
- enum:
|
||||
- jedec,lpddr2-s4
|
||||
- items:
|
||||
- enum:
|
||||
- jedec,lpddr2-s2
|
||||
- items:
|
||||
- enum:
|
||||
- jedec,lpddr2-nvm
|
||||
|
||||
revision-id1:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 255
|
||||
description: |
|
||||
Revision 1 value of SDRAM chip. Obtained from device datasheet.
|
||||
|
||||
revision-id2:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 255
|
||||
description: |
|
||||
Revision 2 value of SDRAM chip. Obtained from device datasheet.
|
||||
|
||||
density:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
Density in megabits of SDRAM chip. Obtained from device datasheet.
|
||||
enum:
|
||||
- 64
|
||||
- 128
|
||||
- 256
|
||||
- 512
|
||||
- 1024
|
||||
- 2048
|
||||
- 4096
|
||||
- 8192
|
||||
- 16384
|
||||
- 32768
|
||||
|
||||
io-width:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
IO bus width in bits of SDRAM chip. Obtained from device datasheet.
|
||||
enum:
|
||||
- 32
|
||||
- 16
|
||||
- 8
|
||||
|
||||
tRRD-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 16
|
||||
description: |
|
||||
Active bank a to active bank b in terms of number of clock cycles.
|
||||
Obtained from device datasheet.
|
||||
|
||||
tWTR-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 16
|
||||
description: |
|
||||
Internal WRITE-to-READ command delay in terms of number of clock cycles.
|
||||
Obtained from device datasheet.
|
||||
|
||||
tXP-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 16
|
||||
description: |
|
||||
Exit power-down to next valid command delay in terms of number of clock
|
||||
cycles. Obtained from device datasheet.
|
||||
|
||||
tRTP-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 16
|
||||
description: |
|
||||
Internal READ to PRECHARGE command delay in terms of number of clock
|
||||
cycles. Obtained from device datasheet.
|
||||
|
||||
tCKE-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 16
|
||||
description: |
|
||||
CKE minimum pulse width (HIGH and LOW pulse width) in terms of number
|
||||
of clock cycles. Obtained from device datasheet.
|
||||
|
||||
tRPab-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 16
|
||||
description: |
|
||||
Row precharge time (all banks) in terms of number of clock cycles.
|
||||
Obtained from device datasheet.
|
||||
|
||||
tRCD-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 16
|
||||
description: |
|
||||
RAS-to-CAS delay in terms of number of clock cycles. Obtained from
|
||||
device datasheet.
|
||||
|
||||
tWR-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 16
|
||||
description: |
|
||||
WRITE recovery time in terms of number of clock cycles. Obtained from
|
||||
device datasheet.
|
||||
|
||||
tRASmin-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 16
|
||||
description: |
|
||||
Row active time in terms of number of clock cycles. Obtained from device
|
||||
datasheet.
|
||||
|
||||
tCKESR-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 16
|
||||
description: |
|
||||
CKE minimum pulse width during SELF REFRESH (low pulse width during
|
||||
SELF REFRESH) in terms of number of clock cycles. Obtained from device
|
||||
datasheet.
|
||||
|
||||
tFAW-min-tck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
maximum: 16
|
||||
description: |
|
||||
Four-bank activate window in terms of number of clock cycles. Obtained
|
||||
from device datasheet.
|
||||
|
||||
patternProperties:
|
||||
"^lpddr2-timings":
|
||||
type: object
|
||||
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".
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- density
|
||||
- io-width
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
elpida_ECB240ABACN: lpddr2 {
|
||||
compatible = "elpida,ECB240ABACN", "jedec,lpddr2-s4";
|
||||
density = <2048>;
|
||||
io-width = <32>;
|
||||
revision-id1 = <1>;
|
||||
revision-id2 = <0>;
|
||||
|
||||
tRPab-min-tck = <3>;
|
||||
tRCD-min-tck = <3>;
|
||||
tWR-min-tck = <3>;
|
||||
tRASmin-min-tck = <3>;
|
||||
tRRD-min-tck = <2>;
|
||||
tWTR-min-tck = <2>;
|
||||
tXP-min-tck = <2>;
|
||||
tRTP-min-tck = <2>;
|
||||
tCKE-min-tck = <3>;
|
||||
tCKESR-min-tck = <3>;
|
||||
tFAW-min-tck = <8>;
|
||||
|
||||
timings_elpida_ECB240ABACN_400mhz: lpddr2-timings0 {
|
||||
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>;
|
||||
};
|
||||
|
||||
timings_elpida_ECB240ABACN_200mhz: lpddr2-timings1 {
|
||||
compatible = "jedec,lpddr2-timings";
|
||||
min-freq = <10000000>;
|
||||
max-freq = <200000000>;
|
||||
tRPab = <21000>;
|
||||
tRCD = <18000>;
|
||||
tWR = <15000>;
|
||||
tRAS-min = <42000>;
|
||||
tRRD = <10000>;
|
||||
tWTR = <10000>;
|
||||
tXP = <7500>;
|
||||
tRTP = <7500>;
|
||||
tCKESR = <15000>;
|
||||
tDQSCK-max = <5500>;
|
||||
tFAW = <50000>;
|
||||
tZQCS = <90000>;
|
||||
tZQCL = <360000>;
|
||||
tZQinit = <1000000>;
|
||||
tRAS-max-ns = <70000>;
|
||||
};
|
||||
};
|
@ -43,8 +43,9 @@ These values shall be obtained from the device data-sheet.
|
||||
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/ddr/lpddr3-timings.txt for more information on "lpddr3-timings"
|
||||
a given speed-bin. Please see
|
||||
Documentation/devicetree/bindings/memory-controllers/ddr/lpddr3-timings.txt
|
||||
for more information on "lpddr3-timings"
|
||||
|
||||
Example:
|
||||
|
@ -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 and mt8192.
|
||||
generation 2: mt2712, mt6779, mt8167, mt8173, mt8183, 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
|
||||
@ -36,6 +36,9 @@ properties:
|
||||
- mediatek,mt8173-smi-common
|
||||
- mediatek,mt8183-smi-common
|
||||
- mediatek,mt8192-smi-common
|
||||
- mediatek,mt8195-smi-common-vdo
|
||||
- mediatek,mt8195-smi-common-vpp
|
||||
- mediatek,mt8195-smi-sub-common
|
||||
|
||||
- description: for mt7623
|
||||
items:
|
||||
@ -65,6 +68,10 @@ properties:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
|
||||
mediatek,smi:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: a phandle to the smi-common node above. Only for sub-common.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@ -91,6 +98,29 @@ allOf:
|
||||
- const: smi
|
||||
- const: async
|
||||
|
||||
- if: # only for sub common
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- mediatek,mt8195-smi-sub-common
|
||||
then:
|
||||
required:
|
||||
- mediatek,smi
|
||||
properties:
|
||||
clock:
|
||||
items:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
items:
|
||||
- const: apb
|
||||
- const: smi
|
||||
- const: gals0
|
||||
else:
|
||||
properties:
|
||||
mediatek,smi: false
|
||||
|
||||
- if: # for gen2 HW that have gals
|
||||
properties:
|
||||
compatible:
|
||||
@ -98,6 +128,8 @@ allOf:
|
||||
- mediatek,mt6779-smi-common
|
||||
- mediatek,mt8183-smi-common
|
||||
- mediatek,mt8192-smi-common
|
||||
- mediatek,mt8195-smi-common-vdo
|
||||
- mediatek,mt8195-smi-common-vpp
|
||||
|
||||
then:
|
||||
properties:
|
||||
|
@ -24,6 +24,7 @@ properties:
|
||||
- mediatek,mt8173-smi-larb
|
||||
- mediatek,mt8183-smi-larb
|
||||
- mediatek,mt8192-smi-larb
|
||||
- mediatek,mt8195-smi-larb
|
||||
|
||||
- description: for mt7623
|
||||
items:
|
||||
@ -74,6 +75,7 @@ allOf:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt8183-smi-larb
|
||||
- mediatek,mt8195-smi-larb
|
||||
|
||||
then:
|
||||
properties:
|
||||
@ -108,6 +110,7 @@ allOf:
|
||||
- mediatek,mt6779-smi-larb
|
||||
- mediatek,mt8167-smi-larb
|
||||
- mediatek,mt8192-smi-larb
|
||||
- mediatek,mt8195-smi-larb
|
||||
|
||||
then:
|
||||
required:
|
||||
|
@ -164,12 +164,20 @@ patternProperties:
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
lpddr2:
|
||||
$ref: "ddr/jedec,lpddr2.yaml#"
|
||||
type: object
|
||||
|
||||
patternProperties:
|
||||
"^emc-table@[0-9]+$":
|
||||
$ref: "#/$defs/emc-table"
|
||||
|
||||
required:
|
||||
- nvidia,ram-code
|
||||
oneOf:
|
||||
- required:
|
||||
- nvidia,ram-code
|
||||
|
||||
- required:
|
||||
- lpddr2
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
@ -227,4 +235,15 @@ examples:
|
||||
0x00000000 0x00000000 0x00000000 0x00000000>;
|
||||
};
|
||||
};
|
||||
|
||||
emc-tables@1 {
|
||||
reg = <1>;
|
||||
|
||||
lpddr2 {
|
||||
compatible = "elpida,B8132B2PB-6D-F", "jedec,lpddr2-s4";
|
||||
revision-id1 = <1>;
|
||||
density = <2048>;
|
||||
io-width = <16>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -33,6 +33,7 @@ properties:
|
||||
- renesas,r8a77970-rpc-if # R-Car V3M
|
||||
- renesas,r8a77980-rpc-if # R-Car V3H
|
||||
- renesas,r8a77995-rpc-if # R-Car D3
|
||||
- renesas,r8a779a0-rpc-if # R-Car V3U
|
||||
- const: renesas,rcar-gen3-rpc-if # a generic R-Car gen3 or RZ/G2 device
|
||||
|
||||
reg:
|
||||
|
@ -51,7 +51,8 @@ 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/ddr/lpddr3.txt
|
||||
refer to documentation file:
|
||||
Documentation/devicetree/bindings/memory-controllers/ddr/lpddr3.txt
|
||||
|
||||
operating-points-v2: true
|
||||
|
||||
|
@ -19,6 +19,7 @@ properties:
|
||||
- qcom,mdm9607-rpmpd
|
||||
- qcom,msm8916-rpmpd
|
||||
- qcom,msm8939-rpmpd
|
||||
- qcom,msm8953-rpmpd
|
||||
- qcom,msm8976-rpmpd
|
||||
- qcom,msm8994-rpmpd
|
||||
- qcom,msm8996-rpmpd
|
||||
@ -31,6 +32,7 @@ properties:
|
||||
- qcom,sdm845-rpmhpd
|
||||
- qcom,sdx55-rpmhpd
|
||||
- qcom,sm6115-rpmpd
|
||||
- qcom,sm6350-rpmhpd
|
||||
- qcom,sm8150-rpmhpd
|
||||
- qcom,sm8250-rpmhpd
|
||||
- qcom,sm8350-rpmhpd
|
||||
|
@ -20,7 +20,9 @@ properties:
|
||||
pattern: "^reset-controller@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
const: microchip,sparx5-switch-reset
|
||||
enum:
|
||||
- microchip,sparx5-switch-reset
|
||||
- microchip,lan966x-switch-reset
|
||||
|
||||
reg:
|
||||
items:
|
||||
|
@ -23,6 +23,7 @@ properties:
|
||||
- socionext,uniphier-pxs2-usb3-reset
|
||||
- socionext,uniphier-ld20-usb3-reset
|
||||
- socionext,uniphier-pxs3-usb3-reset
|
||||
- socionext,uniphier-nx1-usb3-reset
|
||||
- socionext,uniphier-pro4-ahci-reset
|
||||
- socionext,uniphier-pxs2-ahci-reset
|
||||
- socionext,uniphier-pxs3-ahci-reset
|
||||
|
@ -23,6 +23,7 @@ properties:
|
||||
- socionext,uniphier-ld11-reset
|
||||
- socionext,uniphier-ld20-reset
|
||||
- socionext,uniphier-pxs3-reset
|
||||
- socionext,uniphier-nx1-reset
|
||||
- description: Media I/O (MIO) reset, SD reset
|
||||
enum:
|
||||
- socionext,uniphier-ld4-mio-reset
|
||||
@ -34,6 +35,7 @@ properties:
|
||||
- socionext,uniphier-ld11-sd-reset
|
||||
- socionext,uniphier-ld20-sd-reset
|
||||
- socionext,uniphier-pxs3-sd-reset
|
||||
- socionext,uniphier-nx1-sd-reset
|
||||
- description: Peripheral reset
|
||||
enum:
|
||||
- socionext,uniphier-ld4-peri-reset
|
||||
@ -44,6 +46,7 @@ properties:
|
||||
- socionext,uniphier-ld11-peri-reset
|
||||
- socionext,uniphier-ld20-peri-reset
|
||||
- socionext,uniphier-pxs3-peri-reset
|
||||
- socionext,uniphier-nx1-peri-reset
|
||||
- description: Analog signal amplifier reset
|
||||
enum:
|
||||
- socionext,uniphier-ld11-adamv-reset
|
||||
|
@ -19,8 +19,7 @@ description:
|
||||
|
||||
The AOSS side channel exposes control over a set of resources, used to control
|
||||
a set of debug related clocks and to affect the low power state of resources
|
||||
related to the secondary subsystems. These resources are exposed as a set of
|
||||
power-domains.
|
||||
related to the secondary subsystems.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -30,6 +29,7 @@ properties:
|
||||
- qcom,sc7280-aoss-qmp
|
||||
- qcom,sc8180x-aoss-qmp
|
||||
- qcom,sdm845-aoss-qmp
|
||||
- qcom,sm6350-aoss-qmp
|
||||
- qcom,sm8150-aoss-qmp
|
||||
- qcom,sm8250-aoss-qmp
|
||||
- qcom,sm8350-aoss-qmp
|
||||
@ -57,13 +57,6 @@ properties:
|
||||
description:
|
||||
The single clock represents the QDSS clock.
|
||||
|
||||
"#power-domain-cells":
|
||||
const: 1
|
||||
description: |
|
||||
The provided power-domains are:
|
||||
CDSP state (0), LPASS state (1), modem state (2), SLPI
|
||||
state (3), SPSS state (4) and Venus state (5).
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@ -101,7 +94,6 @@ examples:
|
||||
mboxes = <&apss_shared 0>;
|
||||
|
||||
#clock-cells = <0>;
|
||||
#power-domain-cells = <1>;
|
||||
|
||||
cx_cdev: cx {
|
||||
#cooling-cells = <2>;
|
||||
|
@ -34,6 +34,7 @@ properties:
|
||||
- qcom,rpm-ipq6018
|
||||
- qcom,rpm-msm8226
|
||||
- qcom,rpm-msm8916
|
||||
- qcom,rpm-msm8953
|
||||
- qcom,rpm-msm8974
|
||||
- qcom,rpm-msm8976
|
||||
- qcom,rpm-msm8996
|
||||
@ -41,6 +42,7 @@ properties:
|
||||
- qcom,rpm-sdm660
|
||||
- qcom,rpm-sm6115
|
||||
- qcom,rpm-sm6125
|
||||
- qcom,rpm-qcm2290
|
||||
- qcom,rpm-qcs404
|
||||
|
||||
qcom,smd-channels:
|
||||
@ -57,6 +59,7 @@ if:
|
||||
- qcom,rpm-apq8084
|
||||
- qcom,rpm-msm8916
|
||||
- qcom,rpm-msm8974
|
||||
- qcom,rpm-msm8953
|
||||
then:
|
||||
required:
|
||||
- qcom,smd-channels
|
||||
|
@ -10,14 +10,18 @@ maintainers:
|
||||
- Andy Gross <agross@kernel.org>
|
||||
- Bjorn Andersson <bjorn.andersson@linaro.org>
|
||||
|
||||
description: |
|
||||
This binding describes the Qualcomm Shared Memory Manager, used to share data
|
||||
between various subsystems and OSes in Qualcomm platforms.
|
||||
description:
|
||||
This binding describes the Qualcomm Shared Memory Manager, a region of
|
||||
reserved-memory used to share data between various subsystems and OSes in
|
||||
Qualcomm platforms.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,smem
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
memory-region:
|
||||
maxItems: 1
|
||||
description: handle to memory reservation for main SMEM memory region.
|
||||
@ -29,11 +33,19 @@ properties:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: handle to RPM message memory resource
|
||||
|
||||
no-map: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- memory-region
|
||||
- hwlocks
|
||||
|
||||
oneOf:
|
||||
- required:
|
||||
- reg
|
||||
- no-map
|
||||
- required:
|
||||
- memory-region
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
@ -43,6 +55,20 @@ examples:
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
smem@fa00000 {
|
||||
compatible = "qcom,smem";
|
||||
reg = <0xfa00000 0x200000>;
|
||||
no-map;
|
||||
|
||||
hwlocks = <&tcsr_mutex 3>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
reserved-memory {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
smem_region: smem@fa00000 {
|
||||
reg = <0xfa00000 0x200000>;
|
||||
no-map;
|
||||
|
81
Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml
Normal file
81
Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml
Normal file
@ -0,0 +1,81 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/soc/qcom/qcom,spm.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Qualcomm Subsystem Power Manager binding
|
||||
|
||||
maintainers:
|
||||
- Andy Gross <agross@kernel.org>
|
||||
- Bjorn Andersson <bjorn.andersson@linaro.org>
|
||||
|
||||
description: |
|
||||
This binding describes the Qualcomm Subsystem Power Manager, used to control
|
||||
the peripheral logic surrounding the application cores in Qualcomm platforms.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- qcom,sdm660-gold-saw2-v4.1-l2
|
||||
- qcom,sdm660-silver-saw2-v4.1-l2
|
||||
- qcom,msm8998-gold-saw2-v4.1-l2
|
||||
- qcom,msm8998-silver-saw2-v4.1-l2
|
||||
- qcom,msm8916-saw2-v3.0-cpu
|
||||
- qcom,msm8226-saw2-v2.1-cpu
|
||||
- qcom,msm8974-saw2-v2.1-cpu
|
||||
- qcom,apq8084-saw2-v2.1-cpu
|
||||
- qcom,apq8064-saw2-v1.1-cpu
|
||||
- const: qcom,saw2
|
||||
|
||||
reg:
|
||||
description: Base address and size of the SPM register region
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
/* Example 1: SoC using SAW2 and kpss-acc-v2 CPUIdle */
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cpu@0 {
|
||||
compatible = "qcom,kryo";
|
||||
device_type = "cpu";
|
||||
enable-method = "qcom,kpss-acc-v2";
|
||||
qcom,saw = <&saw0>;
|
||||
reg = <0x0>;
|
||||
operating-points-v2 = <&cpu_opp_table>;
|
||||
};
|
||||
};
|
||||
|
||||
saw0: power-manager@f9089000 {
|
||||
compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2";
|
||||
reg = <0xf9089000 0x1000>;
|
||||
};
|
||||
|
||||
- |
|
||||
|
||||
/*
|
||||
* Example 2: New-gen multi cluster SoC using SAW only for L2;
|
||||
* This does not require any cpuidle driver, nor any cpu phandle.
|
||||
*/
|
||||
power-manager@17812000 {
|
||||
compatible = "qcom,msm8998-gold-saw2-v4.1-l2", "qcom,saw2";
|
||||
reg = <0x17812000 0x1000>;
|
||||
};
|
||||
|
||||
power-manager@17912000 {
|
||||
compatible = "qcom,msm8998-silver-saw2-v4.1-l2", "qcom,saw2";
|
||||
reg = <0x17912000 0x1000>;
|
||||
};
|
||||
|
||||
...
|
47
Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml
Normal file
47
Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml
Normal file
@ -0,0 +1,47 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/soc/qcom/qcom-stats.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Technologies, Inc. (QTI) Stats bindings
|
||||
|
||||
maintainers:
|
||||
- Maulik Shah <mkshah@codeaurora.org>
|
||||
|
||||
description:
|
||||
Always On Processor/Resource Power Manager maintains statistics of the SoC
|
||||
sleep modes involving powering down of the rails and oscillator clock.
|
||||
|
||||
Statistics includes SoC sleep mode type, number of times low power mode were
|
||||
entered, time of last entry, time of last exit and accumulated sleep duration.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,rpmh-stats
|
||||
- qcom,rpm-stats
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
# Example of rpmh sleep stats
|
||||
- |
|
||||
sram@c3f0000 {
|
||||
compatible = "qcom,rpmh-stats";
|
||||
reg = <0x0c3f0000 0x400>;
|
||||
};
|
||||
# Example of rpm sleep stats
|
||||
- |
|
||||
sram@4690000 {
|
||||
compatible = "qcom,rpm-stats";
|
||||
reg = <0x04690000 0x10000>;
|
||||
};
|
||||
...
|
@ -31,6 +31,7 @@ properties:
|
||||
- amlogic,meson-gxbb-sram
|
||||
- arm,juno-sram-ns
|
||||
- atmel,sama5d2-securam
|
||||
- qcom,rpm-msg-ram
|
||||
- rockchip,rk3288-pmu-sram
|
||||
|
||||
reg:
|
||||
@ -135,7 +136,9 @@ if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: rockchip,rk3288-pmu-sram
|
||||
enum:
|
||||
- qcom,rpm-msg-ram
|
||||
- rockchip,rk3288-pmu-sram
|
||||
|
||||
else:
|
||||
required:
|
||||
|
@ -359,6 +359,8 @@ patternProperties:
|
||||
description: Shenzhen Elida Technology Co., Ltd.
|
||||
"^elimo,.*":
|
||||
description: Elimo Engineering Ltd.
|
||||
"^elpida,.*":
|
||||
description: Elpida Memory, Inc.
|
||||
"^embest,.*":
|
||||
description: Shenzhen Embest Technology Co., Ltd.
|
||||
"^emlid,.*":
|
||||
|
@ -11992,6 +11992,14 @@ M: Sean Wang <sean.wang@mediatek.com>
|
||||
S: Maintained
|
||||
F: drivers/char/hw_random/mtk-rng.c
|
||||
|
||||
MEDIATEK SMI DRIVER
|
||||
M: Yong Wu <yong.wu@mediatek.com>
|
||||
L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/memory-controllers/mediatek,smi*
|
||||
F: drivers/memory/mtk-smi.c
|
||||
F: include/soc/mediatek/smi.h
|
||||
|
||||
MEDIATEK SWITCH DRIVER
|
||||
M: Sean Wang <sean.wang@mediatek.com>
|
||||
M: Landen Chao <Landen.Chao@mediatek.com>
|
||||
|
@ -351,7 +351,7 @@ config ARCH_EP93XX
|
||||
select CLKSRC_MMIO
|
||||
select CPU_ARM920T
|
||||
select GPIOLIB
|
||||
select HAVE_LEGACY_CLK
|
||||
select COMMON_CLK
|
||||
help
|
||||
This enables support for the Cirrus EP93xx series of CPUs.
|
||||
|
||||
@ -480,7 +480,6 @@ config ARCH_S3C24XX
|
||||
select GPIOLIB
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
select HAVE_S3C2410_I2C if I2C
|
||||
select HAVE_S3C_RTC if RTC_CLASS
|
||||
select NEED_MACH_IO_H
|
||||
select S3C2410_WATCHDOG
|
||||
select SAMSUNG_ATAGS
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -214,7 +214,7 @@ static int ep93xx_ohci_power_on(struct platform_device *pdev)
|
||||
return PTR_ERR(ep93xx_ohci_host_clock);
|
||||
}
|
||||
|
||||
return clk_enable(ep93xx_ohci_host_clock);
|
||||
return clk_prepare_enable(ep93xx_ohci_host_clock);
|
||||
}
|
||||
|
||||
static void ep93xx_ohci_power_off(struct platform_device *pdev)
|
||||
|
@ -111,19 +111,19 @@
|
||||
#define EP93XX_SYSCON_PWRCNT EP93XX_SYSCON_REG(0x04)
|
||||
#define EP93XX_SYSCON_PWRCNT_FIR_EN (1<<31)
|
||||
#define EP93XX_SYSCON_PWRCNT_UARTBAUD (1<<29)
|
||||
#define EP93XX_SYSCON_PWRCNT_USH_EN (1<<28)
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2M1 (1<<27)
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2M0 (1<<26)
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P8 (1<<25)
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P9 (1<<24)
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P6 (1<<23)
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P7 (1<<22)
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P4 (1<<21)
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P5 (1<<20)
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P2 (1<<19)
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P3 (1<<18)
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P0 (1<<17)
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 (1<<16)
|
||||
#define EP93XX_SYSCON_PWRCNT_USH_EN 28
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2M1 27
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2M0 26
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P8 25
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P9 24
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P6 23
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P7 22
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P4 21
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P5 20
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P2 19
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P3 18
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P0 17
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 16
|
||||
#define EP93XX_SYSCON_HALT EP93XX_SYSCON_REG(0x08)
|
||||
#define EP93XX_SYSCON_STANDBY EP93XX_SYSCON_REG(0x0c)
|
||||
#define EP93XX_SYSCON_CLKSET1 EP93XX_SYSCON_REG(0x20)
|
||||
@ -139,13 +139,13 @@
|
||||
#define EP93XX_SYSCON_DEVCFG_GONK (1<<27)
|
||||
#define EP93XX_SYSCON_DEVCFG_TONG (1<<26)
|
||||
#define EP93XX_SYSCON_DEVCFG_MONG (1<<25)
|
||||
#define EP93XX_SYSCON_DEVCFG_U3EN (1<<24)
|
||||
#define EP93XX_SYSCON_DEVCFG_U3EN 24
|
||||
#define EP93XX_SYSCON_DEVCFG_CPENA (1<<23)
|
||||
#define EP93XX_SYSCON_DEVCFG_A2ONG (1<<22)
|
||||
#define EP93XX_SYSCON_DEVCFG_A1ONG (1<<21)
|
||||
#define EP93XX_SYSCON_DEVCFG_U2EN (1<<20)
|
||||
#define EP93XX_SYSCON_DEVCFG_U2EN 20
|
||||
#define EP93XX_SYSCON_DEVCFG_EXVC (1<<19)
|
||||
#define EP93XX_SYSCON_DEVCFG_U1EN (1<<18)
|
||||
#define EP93XX_SYSCON_DEVCFG_U1EN 18
|
||||
#define EP93XX_SYSCON_DEVCFG_TIN (1<<17)
|
||||
#define EP93XX_SYSCON_DEVCFG_HC3IN (1<<15)
|
||||
#define EP93XX_SYSCON_DEVCFG_HC3EN (1<<14)
|
||||
@ -163,12 +163,12 @@
|
||||
#define EP93XX_SYSCON_DEVCFG_KEYS (1<<1)
|
||||
#define EP93XX_SYSCON_DEVCFG_SHENA (1<<0)
|
||||
#define EP93XX_SYSCON_VIDCLKDIV EP93XX_SYSCON_REG(0x84)
|
||||
#define EP93XX_SYSCON_CLKDIV_ENABLE (1<<15)
|
||||
#define EP93XX_SYSCON_CLKDIV_ENABLE 15
|
||||
#define EP93XX_SYSCON_CLKDIV_ESEL (1<<14)
|
||||
#define EP93XX_SYSCON_CLKDIV_PSEL (1<<13)
|
||||
#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8
|
||||
#define EP93XX_SYSCON_I2SCLKDIV EP93XX_SYSCON_REG(0x8c)
|
||||
#define EP93XX_SYSCON_I2SCLKDIV_SENA (1<<31)
|
||||
#define EP93XX_SYSCON_I2SCLKDIV_SENA 31
|
||||
#define EP93XX_SYSCON_I2SCLKDIV_ORIDE (1<<29)
|
||||
#define EP93XX_SYSCON_I2SCLKDIV_SPOL (1<<19)
|
||||
#define EP93XX_I2SCLKDIV_SDIV (1 << 16)
|
||||
@ -177,9 +177,9 @@
|
||||
#define EP93XX_I2SCLKDIV_LRDIV128 (2 << 17)
|
||||
#define EP93XX_I2SCLKDIV_LRDIV_MASK (3 << 17)
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV EP93XX_SYSCON_REG(0x90)
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN (1<<31)
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV (1<<16)
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN (1<<15)
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN 31
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV 16
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN 15
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV (1<<0)
|
||||
#define EP93XX_SYSCON_SYSCFG EP93XX_SYSCON_REG(0x9c)
|
||||
#define EP93XX_SYSCON_SYSCFG_REV_MASK (0xf0000000)
|
||||
|
@ -13,7 +13,6 @@ menuconfig ARCH_EXYNOS
|
||||
select ARM_GIC
|
||||
select EXYNOS_IRQ_COMBINER
|
||||
select COMMON_CLK_SAMSUNG
|
||||
select EXYNOS_CHIPID
|
||||
select EXYNOS_THERMAL
|
||||
select EXYNOS_PMU
|
||||
select EXYNOS_SROM
|
||||
@ -22,7 +21,6 @@ menuconfig ARCH_EXYNOS
|
||||
select HAVE_ARM_ARCH_TIMER if ARCH_EXYNOS5
|
||||
select HAVE_ARM_SCU if SMP
|
||||
select HAVE_S3C2410_I2C if I2C
|
||||
select HAVE_S3C_RTC if RTC_CLASS
|
||||
select PINCTRL
|
||||
select PINCTRL_EXYNOS
|
||||
select PM_GENERIC_DOMAINS if PM
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define COREPOR_RST BIT(5)
|
||||
#define CORE_RST BIT(4)
|
||||
#define L2DT_SLP BIT(3)
|
||||
#define CORE_MEM_CLAMP BIT(1)
|
||||
#define CLAMP BIT(0)
|
||||
|
||||
#define APC_PWR_GATE_CTL 0x14
|
||||
@ -75,6 +76,62 @@ static int scss_release_secondary(unsigned int cpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cortex_a7_release_secondary(unsigned int cpu)
|
||||
{
|
||||
int ret = 0;
|
||||
void __iomem *reg;
|
||||
struct device_node *cpu_node, *acc_node;
|
||||
u32 reg_val;
|
||||
|
||||
cpu_node = of_get_cpu_node(cpu, NULL);
|
||||
if (!cpu_node)
|
||||
return -ENODEV;
|
||||
|
||||
acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
|
||||
if (!acc_node) {
|
||||
ret = -ENODEV;
|
||||
goto out_acc;
|
||||
}
|
||||
|
||||
reg = of_iomap(acc_node, 0);
|
||||
if (!reg) {
|
||||
ret = -ENOMEM;
|
||||
goto out_acc_map;
|
||||
}
|
||||
|
||||
/* Put the CPU into reset. */
|
||||
reg_val = CORE_RST | COREPOR_RST | CLAMP | CORE_MEM_CLAMP;
|
||||
writel(reg_val, reg + APCS_CPU_PWR_CTL);
|
||||
|
||||
/* Turn on the BHS and set the BHS_CNT to 16 XO clock cycles */
|
||||
writel(BHS_EN | (0x10 << BHS_CNT_SHIFT), reg + APC_PWR_GATE_CTL);
|
||||
/* Wait for the BHS to settle */
|
||||
udelay(2);
|
||||
|
||||
reg_val &= ~CORE_MEM_CLAMP;
|
||||
writel(reg_val, reg + APCS_CPU_PWR_CTL);
|
||||
reg_val |= L2DT_SLP;
|
||||
writel(reg_val, reg + APCS_CPU_PWR_CTL);
|
||||
udelay(2);
|
||||
|
||||
reg_val = (reg_val | BIT(17)) & ~CLAMP;
|
||||
writel(reg_val, reg + APCS_CPU_PWR_CTL);
|
||||
udelay(2);
|
||||
|
||||
/* Release CPU out of reset and bring it to life. */
|
||||
reg_val &= ~(CORE_RST | COREPOR_RST);
|
||||
writel(reg_val, reg + APCS_CPU_PWR_CTL);
|
||||
reg_val |= CORE_PWRD_UP;
|
||||
writel(reg_val, reg + APCS_CPU_PWR_CTL);
|
||||
|
||||
iounmap(reg);
|
||||
out_acc_map:
|
||||
of_node_put(acc_node);
|
||||
out_acc:
|
||||
of_node_put(cpu_node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kpssv1_release_secondary(unsigned int cpu)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -281,6 +338,11 @@ static int msm8660_boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
return qcom_boot_secondary(cpu, scss_release_secondary);
|
||||
}
|
||||
|
||||
static int cortex_a7_boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
{
|
||||
return qcom_boot_secondary(cpu, cortex_a7_release_secondary);
|
||||
}
|
||||
|
||||
static int kpssv1_boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
{
|
||||
return qcom_boot_secondary(cpu, kpssv1_release_secondary);
|
||||
@ -315,6 +377,16 @@ static const struct smp_operations smp_msm8660_ops __initconst = {
|
||||
};
|
||||
CPU_METHOD_OF_DECLARE(qcom_smp, "qcom,gcc-msm8660", &smp_msm8660_ops);
|
||||
|
||||
static const struct smp_operations qcom_smp_cortex_a7_ops __initconst = {
|
||||
.smp_prepare_cpus = qcom_smp_prepare_cpus,
|
||||
.smp_boot_secondary = cortex_a7_boot_secondary,
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
.cpu_die = qcom_cpu_die,
|
||||
#endif
|
||||
};
|
||||
CPU_METHOD_OF_DECLARE(qcom_smp_msm8226, "qcom,msm8226-smp", &qcom_smp_cortex_a7_ops);
|
||||
CPU_METHOD_OF_DECLARE(qcom_smp_msm8916, "qcom,msm8916-smp", &qcom_smp_cortex_a7_ops);
|
||||
|
||||
static const struct smp_operations qcom_smp_kpssv1_ops __initconst = {
|
||||
.smp_prepare_cpus = qcom_smp_prepare_cpus,
|
||||
.smp_boot_secondary = kpssv1_boot_secondary,
|
||||
|
@ -13,7 +13,6 @@ config ARCH_S5PV210
|
||||
select COMMON_CLK_SAMSUNG
|
||||
select GPIOLIB
|
||||
select HAVE_S3C2410_I2C if I2C
|
||||
select HAVE_S3C_RTC if RTC_CLASS
|
||||
select PINCTRL
|
||||
select PINCTRL_EXYNOS
|
||||
select SOC_SAMSUNG
|
||||
|
@ -89,10 +89,8 @@ config ARCH_BRCMSTB
|
||||
config ARCH_EXYNOS
|
||||
bool "ARMv8 based Samsung Exynos SoC family"
|
||||
select COMMON_CLK_SAMSUNG
|
||||
select EXYNOS_CHIPID
|
||||
select EXYNOS_PM_DOMAINS if PM_GENERIC_DOMAINS
|
||||
select EXYNOS_PMU
|
||||
select HAVE_S3C_RTC if RTC_CLASS
|
||||
select PINCTRL
|
||||
select PINCTRL_EXYNOS
|
||||
select PM_GENERIC_DOMAINS if PM
|
||||
|
@ -30,7 +30,7 @@ config ARM_INTEGRATOR_LM
|
||||
found on the ARM Integrator AP (Application Platform)
|
||||
|
||||
config BRCMSTB_GISB_ARB
|
||||
bool "Broadcom STB GISB bus arbiter"
|
||||
tristate "Broadcom STB GISB bus arbiter"
|
||||
depends on ARM || ARM64 || MIPS
|
||||
default ARCH_BRCMSTB || BMIPS_GENERIC
|
||||
help
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Broadcom
|
||||
* Copyright (C) 2014-2021 Broadcom
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
@ -536,6 +536,7 @@ static struct platform_driver brcmstb_gisb_arb_driver = {
|
||||
.name = "brcm-gisb-arb",
|
||||
.of_match_table = brcmstb_gisb_arb_of_match,
|
||||
.pm = &brcmstb_gisb_arb_pm_ops,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -546,3 +547,7 @@ static int __init brcm_gisb_driver_init(void)
|
||||
}
|
||||
|
||||
module_init(brcm_gisb_driver_init);
|
||||
|
||||
MODULE_AUTHOR("Broadcom");
|
||||
MODULE_DESCRIPTION("Broadcom STB GISB arbiter driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -15,10 +15,9 @@ static int sun50i_de2_bus_probe(struct platform_device *pdev)
|
||||
int ret;
|
||||
|
||||
ret = sunxi_sram_claim(&pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Error couldn't map SRAM to device\n");
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"Couldn't map SRAM to device\n");
|
||||
|
||||
of_platform_populate(np, NULL, NULL, &pdev->dev);
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
@ -17,6 +18,7 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/timekeeping.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#include <linux/platform_data/ti-sysc.h>
|
||||
@ -51,11 +53,18 @@ struct sysc_address {
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
struct sysc_module {
|
||||
struct sysc *ddata;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
struct sysc_soc_info {
|
||||
unsigned long general_purpose:1;
|
||||
enum sysc_soc soc;
|
||||
struct mutex list_lock; /* disabled modules list lock */
|
||||
struct mutex list_lock; /* disabled and restored modules list lock */
|
||||
struct list_head disabled_modules;
|
||||
struct list_head restored_modules;
|
||||
struct notifier_block nb;
|
||||
};
|
||||
|
||||
enum sysc_clocks {
|
||||
@ -131,6 +140,7 @@ struct sysc {
|
||||
struct ti_sysc_cookie cookie;
|
||||
const char *name;
|
||||
u32 revision;
|
||||
u32 sysconfig;
|
||||
unsigned int reserved:1;
|
||||
unsigned int enabled:1;
|
||||
unsigned int needs_resume:1;
|
||||
@ -147,6 +157,7 @@ struct sysc {
|
||||
|
||||
static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
|
||||
bool is_child);
|
||||
static int sysc_reset(struct sysc *ddata);
|
||||
|
||||
static void sysc_write(struct sysc *ddata, int offset, u32 value)
|
||||
{
|
||||
@ -223,37 +234,77 @@ static u32 sysc_read_sysstatus(struct sysc *ddata)
|
||||
return sysc_read(ddata, offset);
|
||||
}
|
||||
|
||||
/* Poll on reset status */
|
||||
static int sysc_wait_softreset(struct sysc *ddata)
|
||||
static int sysc_poll_reset_sysstatus(struct sysc *ddata)
|
||||
{
|
||||
u32 sysc_mask, syss_done, rstval;
|
||||
int syss_offset, error = 0;
|
||||
|
||||
if (ddata->cap->regbits->srst_shift < 0)
|
||||
return 0;
|
||||
|
||||
syss_offset = ddata->offsets[SYSC_SYSSTATUS];
|
||||
sysc_mask = BIT(ddata->cap->regbits->srst_shift);
|
||||
int error, retries;
|
||||
u32 syss_done, rstval;
|
||||
|
||||
if (ddata->cfg.quirks & SYSS_QUIRK_RESETDONE_INVERTED)
|
||||
syss_done = 0;
|
||||
else
|
||||
syss_done = ddata->cfg.syss_mask;
|
||||
|
||||
if (syss_offset >= 0) {
|
||||
if (likely(!timekeeping_suspended)) {
|
||||
error = readx_poll_timeout_atomic(sysc_read_sysstatus, ddata,
|
||||
rstval, (rstval & ddata->cfg.syss_mask) ==
|
||||
syss_done, 100, MAX_MODULE_SOFTRESET_WAIT);
|
||||
} else {
|
||||
retries = MAX_MODULE_SOFTRESET_WAIT;
|
||||
while (retries--) {
|
||||
rstval = sysc_read_sysstatus(ddata);
|
||||
if ((rstval & ddata->cfg.syss_mask) == syss_done)
|
||||
return 0;
|
||||
udelay(2); /* Account for udelay flakeyness */
|
||||
}
|
||||
error = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
} else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS) {
|
||||
return error;
|
||||
}
|
||||
|
||||
static int sysc_poll_reset_sysconfig(struct sysc *ddata)
|
||||
{
|
||||
int error, retries;
|
||||
u32 sysc_mask, rstval;
|
||||
|
||||
sysc_mask = BIT(ddata->cap->regbits->srst_shift);
|
||||
|
||||
if (likely(!timekeeping_suspended)) {
|
||||
error = readx_poll_timeout_atomic(sysc_read_sysconfig, ddata,
|
||||
rstval, !(rstval & sysc_mask),
|
||||
100, MAX_MODULE_SOFTRESET_WAIT);
|
||||
} else {
|
||||
retries = MAX_MODULE_SOFTRESET_WAIT;
|
||||
while (retries--) {
|
||||
rstval = sysc_read_sysconfig(ddata);
|
||||
if (!(rstval & sysc_mask))
|
||||
return 0;
|
||||
udelay(2); /* Account for udelay flakeyness */
|
||||
}
|
||||
error = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Poll on reset status */
|
||||
static int sysc_wait_softreset(struct sysc *ddata)
|
||||
{
|
||||
int syss_offset, error = 0;
|
||||
|
||||
if (ddata->cap->regbits->srst_shift < 0)
|
||||
return 0;
|
||||
|
||||
syss_offset = ddata->offsets[SYSC_SYSSTATUS];
|
||||
|
||||
if (syss_offset >= 0)
|
||||
error = sysc_poll_reset_sysstatus(ddata);
|
||||
else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS)
|
||||
error = sysc_poll_reset_sysconfig(ddata);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int sysc_add_named_clock_from_child(struct sysc *ddata,
|
||||
const char *name,
|
||||
const char *optfck_name)
|
||||
@ -1094,7 +1145,8 @@ set_midle:
|
||||
best_mode = fls(ddata->cfg.midlemodes) - 1;
|
||||
if (best_mode > SYSC_IDLE_MASK) {
|
||||
dev_err(dev, "%s: invalid midlemode\n", __func__);
|
||||
return -EINVAL;
|
||||
error = -EINVAL;
|
||||
goto save_context;
|
||||
}
|
||||
|
||||
if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
|
||||
@ -1112,13 +1164,16 @@ set_autoidle:
|
||||
sysc_write_sysconfig(ddata, reg);
|
||||
}
|
||||
|
||||
/* Flush posted write */
|
||||
sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
|
||||
error = 0;
|
||||
|
||||
save_context:
|
||||
/* Save context and flush posted write */
|
||||
ddata->sysconfig = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
|
||||
|
||||
if (ddata->module_enable_quirk)
|
||||
ddata->module_enable_quirk(ddata);
|
||||
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
static int sysc_best_idle_mode(u32 idlemodes, u32 *best_mode)
|
||||
@ -1175,8 +1230,10 @@ static int sysc_disable_module(struct device *dev)
|
||||
set_sidle:
|
||||
/* Set SIDLE mode */
|
||||
idlemodes = ddata->cfg.sidlemodes;
|
||||
if (!idlemodes || regbits->sidle_shift < 0)
|
||||
return 0;
|
||||
if (!idlemodes || regbits->sidle_shift < 0) {
|
||||
ret = 0;
|
||||
goto save_context;
|
||||
}
|
||||
|
||||
if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_SIDLE) {
|
||||
best_mode = SYSC_IDLE_FORCE;
|
||||
@ -1184,7 +1241,8 @@ set_sidle:
|
||||
ret = sysc_best_idle_mode(idlemodes, &best_mode);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: invalid sidlemode\n", __func__);
|
||||
return ret;
|
||||
ret = -EINVAL;
|
||||
goto save_context;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1195,10 +1253,13 @@ set_sidle:
|
||||
reg |= 1 << regbits->autoidle_shift;
|
||||
sysc_write_sysconfig(ddata, reg);
|
||||
|
||||
/* Flush posted write */
|
||||
sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
|
||||
ret = 0;
|
||||
|
||||
return 0;
|
||||
save_context:
|
||||
/* Save context and flush posted write */
|
||||
ddata->sysconfig = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused sysc_runtime_suspend_legacy(struct device *dev,
|
||||
@ -1336,13 +1397,40 @@ err_allow_idle:
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if device context was lost. Assumes the sysconfig register value
|
||||
* after lost context is different from the configured value. Only works for
|
||||
* enabled devices.
|
||||
*
|
||||
* Eventually we may want to also add support to using the context lost
|
||||
* registers that some SoCs have.
|
||||
*/
|
||||
static int sysc_check_context(struct sysc *ddata)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
if (!ddata->enabled)
|
||||
return -ENODATA;
|
||||
|
||||
reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
|
||||
if (reg == ddata->sysconfig)
|
||||
return 0;
|
||||
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
static int sysc_reinit_module(struct sysc *ddata, bool leave_enabled)
|
||||
{
|
||||
struct device *dev = ddata->dev;
|
||||
int error;
|
||||
|
||||
/* Disable target module if it is enabled */
|
||||
if (ddata->enabled) {
|
||||
/* Nothing to do if enabled and context not lost */
|
||||
error = sysc_check_context(ddata);
|
||||
if (!error)
|
||||
return 0;
|
||||
|
||||
/* Disable target module if it is enabled */
|
||||
error = sysc_runtime_suspend(dev);
|
||||
if (error)
|
||||
dev_warn(dev, "reinit suspend failed: %i\n", error);
|
||||
@ -1353,6 +1441,15 @@ static int sysc_reinit_module(struct sysc *ddata, bool leave_enabled)
|
||||
if (error)
|
||||
dev_warn(dev, "reinit resume failed: %i\n", error);
|
||||
|
||||
/* Some modules like am335x gpmc need reset and restore of sysconfig */
|
||||
if (ddata->cfg.quirks & SYSC_QUIRK_RESET_ON_CTX_LOST) {
|
||||
error = sysc_reset(ddata);
|
||||
if (error)
|
||||
dev_warn(dev, "reinit reset failed: %i\n", error);
|
||||
|
||||
sysc_write_sysconfig(ddata, ddata->sysconfig);
|
||||
}
|
||||
|
||||
if (leave_enabled)
|
||||
return error;
|
||||
|
||||
@ -1442,10 +1539,6 @@ struct sysc_revision_quirk {
|
||||
|
||||
static const struct sysc_revision_quirk sysc_revision_quirks[] = {
|
||||
/* These drivers need to be fixed to not use pm_runtime_irq_safe() */
|
||||
SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffff00ff,
|
||||
SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET),
|
||||
SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff,
|
||||
SYSC_QUIRK_LEGACY_IDLE),
|
||||
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff,
|
||||
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
|
||||
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
|
||||
@ -1479,7 +1572,10 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
|
||||
SYSC_QUIRK_CLKDM_NOAUTO),
|
||||
SYSC_QUIRK("dwc3", 0x488c0000, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff,
|
||||
SYSC_QUIRK_CLKDM_NOAUTO),
|
||||
SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffff00ff,
|
||||
SYSC_QUIRK_OPT_CLKS_IN_RESET),
|
||||
SYSC_QUIRK("gpmc", 0, 0, 0x10, 0x14, 0x00000060, 0xffffffff,
|
||||
SYSC_QUIRK_REINIT_ON_CTX_LOST | SYSC_QUIRK_RESET_ON_CTX_LOST |
|
||||
SYSC_QUIRK_GPMC_DEBUG),
|
||||
SYSC_QUIRK("hdmi", 0, 0, 0x10, -ENODEV, 0x50030200, 0xffffffff,
|
||||
SYSC_QUIRK_OPT_CLKS_NEEDED),
|
||||
@ -1515,10 +1611,11 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
|
||||
SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -ENODEV, 0x50700101, 0xffffffff,
|
||||
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
|
||||
SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
|
||||
0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
|
||||
0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY |
|
||||
SYSC_MODULE_QUIRK_OTG),
|
||||
SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -ENODEV, 0x4ea2080d, 0xffffffff,
|
||||
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY |
|
||||
SYSC_QUIRK_REINIT_ON_RESUME),
|
||||
SYSC_QUIRK_REINIT_ON_CTX_LOST),
|
||||
SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0,
|
||||
SYSC_MODULE_QUIRK_WDT),
|
||||
/* PRUSS on am3, am4 and am5 */
|
||||
@ -1583,6 +1680,7 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
|
||||
SYSC_QUIRK("sdio", 0, 0, 0x10, -ENODEV, 0x40202301, 0xffff0ff0, 0),
|
||||
SYSC_QUIRK("sdio", 0, 0x2fc, 0x110, 0x114, 0x31010000, 0xffffffff, 0),
|
||||
SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff, 0),
|
||||
SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff, 0),
|
||||
SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40000902, 0xffffffff, 0),
|
||||
SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40002903, 0xffffffff, 0),
|
||||
SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x24, -ENODEV, 0x00000000, 0xffffffff, 0),
|
||||
@ -1874,6 +1972,22 @@ static void sysc_module_lock_quirk_rtc(struct sysc *ddata)
|
||||
sysc_quirk_rtc(ddata, true);
|
||||
}
|
||||
|
||||
/* OTG omap2430 glue layer up to omap4 needs OTG_FORCESTDBY configured */
|
||||
static void sysc_module_enable_quirk_otg(struct sysc *ddata)
|
||||
{
|
||||
int offset = 0x414; /* OTG_FORCESTDBY */
|
||||
|
||||
sysc_write(ddata, offset, 0);
|
||||
}
|
||||
|
||||
static void sysc_module_disable_quirk_otg(struct sysc *ddata)
|
||||
{
|
||||
int offset = 0x414; /* OTG_FORCESTDBY */
|
||||
u32 val = BIT(0); /* ENABLEFORCE */
|
||||
|
||||
sysc_write(ddata, offset, val);
|
||||
}
|
||||
|
||||
/* 36xx SGX needs a quirk for to bypass OCP IPG interrupt logic */
|
||||
static void sysc_module_enable_quirk_sgx(struct sysc *ddata)
|
||||
{
|
||||
@ -1956,6 +2070,11 @@ static void sysc_init_module_quirks(struct sysc *ddata)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_OTG) {
|
||||
ddata->module_enable_quirk = sysc_module_enable_quirk_otg;
|
||||
ddata->module_disable_quirk = sysc_module_disable_quirk_otg;
|
||||
}
|
||||
|
||||
if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_SGX)
|
||||
ddata->module_enable_quirk = sysc_module_enable_quirk_sgx;
|
||||
|
||||
@ -2401,6 +2520,78 @@ static struct dev_pm_domain sysc_child_pm_domain = {
|
||||
}
|
||||
};
|
||||
|
||||
/* Caller needs to take list_lock if ever used outside of cpu_pm */
|
||||
static void sysc_reinit_modules(struct sysc_soc_info *soc)
|
||||
{
|
||||
struct sysc_module *module;
|
||||
struct list_head *pos;
|
||||
struct sysc *ddata;
|
||||
|
||||
list_for_each(pos, &sysc_soc->restored_modules) {
|
||||
module = list_entry(pos, struct sysc_module, node);
|
||||
ddata = module->ddata;
|
||||
sysc_reinit_module(ddata, ddata->enabled);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sysc_context_notifier - optionally reset and restore module after idle
|
||||
* @nb: notifier block
|
||||
* @cmd: unused
|
||||
* @v: unused
|
||||
*
|
||||
* Some interconnect target modules need to be restored, or reset and restored
|
||||
* on CPU_PM CPU_PM_CLUSTER_EXIT notifier. This is needed at least for am335x
|
||||
* OTG and GPMC target modules even if the modules are unused.
|
||||
*/
|
||||
static int sysc_context_notifier(struct notifier_block *nb, unsigned long cmd,
|
||||
void *v)
|
||||
{
|
||||
struct sysc_soc_info *soc;
|
||||
|
||||
soc = container_of(nb, struct sysc_soc_info, nb);
|
||||
|
||||
switch (cmd) {
|
||||
case CPU_CLUSTER_PM_ENTER:
|
||||
break;
|
||||
case CPU_CLUSTER_PM_ENTER_FAILED: /* No need to restore context */
|
||||
break;
|
||||
case CPU_CLUSTER_PM_EXIT:
|
||||
sysc_reinit_modules(soc);
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysc_add_restored - optionally add reset and restore quirk hanlling
|
||||
* @ddata: device data
|
||||
*/
|
||||
static void sysc_add_restored(struct sysc *ddata)
|
||||
{
|
||||
struct sysc_module *restored_module;
|
||||
|
||||
restored_module = kzalloc(sizeof(*restored_module), GFP_KERNEL);
|
||||
if (!restored_module)
|
||||
return;
|
||||
|
||||
restored_module->ddata = ddata;
|
||||
|
||||
mutex_lock(&sysc_soc->list_lock);
|
||||
|
||||
list_add(&restored_module->node, &sysc_soc->restored_modules);
|
||||
|
||||
if (sysc_soc->nb.notifier_call)
|
||||
goto out_unlock;
|
||||
|
||||
sysc_soc->nb.notifier_call = sysc_context_notifier;
|
||||
cpu_pm_register_notifier(&sysc_soc->nb);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&sysc_soc->list_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysc_legacy_idle_quirk - handle children in omap_device compatible way
|
||||
* @ddata: device driver data
|
||||
@ -2900,12 +3091,14 @@ static int sysc_add_disabled(unsigned long base)
|
||||
}
|
||||
|
||||
/*
|
||||
* One time init to detect the booted SoC and disable unavailable features.
|
||||
* One time init to detect the booted SoC, disable unavailable features
|
||||
* and initialize list for optional cpu_pm notifier.
|
||||
*
|
||||
* Note that we initialize static data shared across all ti-sysc instances
|
||||
* so ddata is only used for SoC type. This can be called from module_init
|
||||
* once we no longer need to rely on platform data.
|
||||
*/
|
||||
static int sysc_init_soc(struct sysc *ddata)
|
||||
static int sysc_init_static_data(struct sysc *ddata)
|
||||
{
|
||||
const struct soc_device_attribute *match;
|
||||
struct ti_sysc_platform_data *pdata;
|
||||
@ -2921,6 +3114,7 @@ static int sysc_init_soc(struct sysc *ddata)
|
||||
|
||||
mutex_init(&sysc_soc->list_lock);
|
||||
INIT_LIST_HEAD(&sysc_soc->disabled_modules);
|
||||
INIT_LIST_HEAD(&sysc_soc->restored_modules);
|
||||
sysc_soc->general_purpose = true;
|
||||
|
||||
pdata = dev_get_platdata(ddata->dev);
|
||||
@ -2985,15 +3179,24 @@ static int sysc_init_soc(struct sysc *ddata)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sysc_cleanup_soc(void)
|
||||
static void sysc_cleanup_static_data(void)
|
||||
{
|
||||
struct sysc_module *restored_module;
|
||||
struct sysc_address *disabled_module;
|
||||
struct list_head *pos, *tmp;
|
||||
|
||||
if (!sysc_soc)
|
||||
return;
|
||||
|
||||
if (sysc_soc->nb.notifier_call)
|
||||
cpu_pm_unregister_notifier(&sysc_soc->nb);
|
||||
|
||||
mutex_lock(&sysc_soc->list_lock);
|
||||
list_for_each_safe(pos, tmp, &sysc_soc->restored_modules) {
|
||||
restored_module = list_entry(pos, struct sysc_module, node);
|
||||
list_del(pos);
|
||||
kfree(restored_module);
|
||||
}
|
||||
list_for_each_safe(pos, tmp, &sysc_soc->disabled_modules) {
|
||||
disabled_module = list_entry(pos, struct sysc_address, node);
|
||||
list_del(pos);
|
||||
@ -3061,7 +3264,7 @@ static int sysc_probe(struct platform_device *pdev)
|
||||
ddata->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
error = sysc_init_soc(ddata);
|
||||
error = sysc_init_static_data(ddata);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@ -3159,6 +3362,9 @@ static int sysc_probe(struct platform_device *pdev)
|
||||
pm_runtime_put(&pdev->dev);
|
||||
}
|
||||
|
||||
if (ddata->cfg.quirks & SYSC_QUIRK_REINIT_ON_CTX_LOST)
|
||||
sysc_add_restored(ddata);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
@ -3240,7 +3446,7 @@ static void __exit sysc_exit(void)
|
||||
{
|
||||
bus_unregister_notifier(&platform_bus_type, &sysc_nb);
|
||||
platform_driver_unregister(&sysc_driver);
|
||||
sysc_cleanup_soc();
|
||||
sysc_cleanup_static_data();
|
||||
}
|
||||
module_exit(sysc_exit);
|
||||
|
||||
|
@ -99,7 +99,7 @@ config ARM_MVEBU_V7_CPUIDLE
|
||||
|
||||
config ARM_TEGRA_CPUIDLE
|
||||
bool "CPU Idle Driver for NVIDIA Tegra SoCs"
|
||||
depends on ARCH_TEGRA && !ARM64
|
||||
depends on (ARCH_TEGRA || COMPILE_TEST) && !ARM64 && MMU
|
||||
select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
|
||||
select ARM_CPU_SUSPEND
|
||||
help
|
||||
@ -112,6 +112,7 @@ config ARM_QCOM_SPM_CPUIDLE
|
||||
select CPU_IDLE_MULTIPLE_DRIVERS
|
||||
select DT_IDLE_STATES
|
||||
select QCOM_SCM
|
||||
select QCOM_SPM
|
||||
help
|
||||
Select this to enable cpuidle for Qualcomm processors.
|
||||
The Subsystem Power Manager (SPM) controls low power modes for the
|
||||
|
@ -18,158 +18,18 @@
|
||||
#include <linux/cpuidle.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/qcom_scm.h>
|
||||
#include <soc/qcom/spm.h>
|
||||
|
||||
#include <asm/proc-fns.h>
|
||||
#include <asm/suspend.h>
|
||||
|
||||
#include "dt_idle_states.h"
|
||||
|
||||
#define MAX_PMIC_DATA 2
|
||||
#define MAX_SEQ_DATA 64
|
||||
#define SPM_CTL_INDEX 0x7f
|
||||
#define SPM_CTL_INDEX_SHIFT 4
|
||||
#define SPM_CTL_EN BIT(0)
|
||||
|
||||
enum pm_sleep_mode {
|
||||
PM_SLEEP_MODE_STBY,
|
||||
PM_SLEEP_MODE_RET,
|
||||
PM_SLEEP_MODE_SPC,
|
||||
PM_SLEEP_MODE_PC,
|
||||
PM_SLEEP_MODE_NR,
|
||||
};
|
||||
|
||||
enum spm_reg {
|
||||
SPM_REG_CFG,
|
||||
SPM_REG_SPM_CTL,
|
||||
SPM_REG_DLY,
|
||||
SPM_REG_PMIC_DLY,
|
||||
SPM_REG_PMIC_DATA_0,
|
||||
SPM_REG_PMIC_DATA_1,
|
||||
SPM_REG_VCTL,
|
||||
SPM_REG_SEQ_ENTRY,
|
||||
SPM_REG_SPM_STS,
|
||||
SPM_REG_PMIC_STS,
|
||||
SPM_REG_NR,
|
||||
};
|
||||
|
||||
struct spm_reg_data {
|
||||
const u8 *reg_offset;
|
||||
u32 spm_cfg;
|
||||
u32 spm_dly;
|
||||
u32 pmic_dly;
|
||||
u32 pmic_data[MAX_PMIC_DATA];
|
||||
u8 seq[MAX_SEQ_DATA];
|
||||
u8 start_index[PM_SLEEP_MODE_NR];
|
||||
};
|
||||
|
||||
struct spm_driver_data {
|
||||
struct cpuidle_qcom_spm_data {
|
||||
struct cpuidle_driver cpuidle_driver;
|
||||
void __iomem *reg_base;
|
||||
const struct spm_reg_data *reg_data;
|
||||
struct spm_driver_data *spm;
|
||||
};
|
||||
|
||||
static const u8 spm_reg_offset_v2_1[SPM_REG_NR] = {
|
||||
[SPM_REG_CFG] = 0x08,
|
||||
[SPM_REG_SPM_CTL] = 0x30,
|
||||
[SPM_REG_DLY] = 0x34,
|
||||
[SPM_REG_SEQ_ENTRY] = 0x80,
|
||||
};
|
||||
|
||||
/* SPM register data for 8974, 8084 */
|
||||
static const struct spm_reg_data spm_reg_8974_8084_cpu = {
|
||||
.reg_offset = spm_reg_offset_v2_1,
|
||||
.spm_cfg = 0x1,
|
||||
.spm_dly = 0x3C102800,
|
||||
.seq = { 0x03, 0x0B, 0x0F, 0x00, 0x20, 0x80, 0x10, 0xE8, 0x5B, 0x03,
|
||||
0x3B, 0xE8, 0x5B, 0x82, 0x10, 0x0B, 0x30, 0x06, 0x26, 0x30,
|
||||
0x0F },
|
||||
.start_index[PM_SLEEP_MODE_STBY] = 0,
|
||||
.start_index[PM_SLEEP_MODE_SPC] = 3,
|
||||
};
|
||||
|
||||
/* SPM register data for 8226 */
|
||||
static const struct spm_reg_data spm_reg_8226_cpu = {
|
||||
.reg_offset = spm_reg_offset_v2_1,
|
||||
.spm_cfg = 0x0,
|
||||
.spm_dly = 0x3C102800,
|
||||
.seq = { 0x60, 0x03, 0x60, 0x0B, 0x0F, 0x20, 0x10, 0x80, 0x30, 0x90,
|
||||
0x5B, 0x60, 0x03, 0x60, 0x3B, 0x76, 0x76, 0x0B, 0x94, 0x5B,
|
||||
0x80, 0x10, 0x26, 0x30, 0x0F },
|
||||
.start_index[PM_SLEEP_MODE_STBY] = 0,
|
||||
.start_index[PM_SLEEP_MODE_SPC] = 5,
|
||||
};
|
||||
|
||||
static const u8 spm_reg_offset_v1_1[SPM_REG_NR] = {
|
||||
[SPM_REG_CFG] = 0x08,
|
||||
[SPM_REG_SPM_CTL] = 0x20,
|
||||
[SPM_REG_PMIC_DLY] = 0x24,
|
||||
[SPM_REG_PMIC_DATA_0] = 0x28,
|
||||
[SPM_REG_PMIC_DATA_1] = 0x2C,
|
||||
[SPM_REG_SEQ_ENTRY] = 0x80,
|
||||
};
|
||||
|
||||
/* SPM register data for 8064 */
|
||||
static const struct spm_reg_data spm_reg_8064_cpu = {
|
||||
.reg_offset = spm_reg_offset_v1_1,
|
||||
.spm_cfg = 0x1F,
|
||||
.pmic_dly = 0x02020004,
|
||||
.pmic_data[0] = 0x0084009C,
|
||||
.pmic_data[1] = 0x00A4001C,
|
||||
.seq = { 0x03, 0x0F, 0x00, 0x24, 0x54, 0x10, 0x09, 0x03, 0x01,
|
||||
0x10, 0x54, 0x30, 0x0C, 0x24, 0x30, 0x0F },
|
||||
.start_index[PM_SLEEP_MODE_STBY] = 0,
|
||||
.start_index[PM_SLEEP_MODE_SPC] = 2,
|
||||
};
|
||||
|
||||
static inline void spm_register_write(struct spm_driver_data *drv,
|
||||
enum spm_reg reg, u32 val)
|
||||
{
|
||||
if (drv->reg_data->reg_offset[reg])
|
||||
writel_relaxed(val, drv->reg_base +
|
||||
drv->reg_data->reg_offset[reg]);
|
||||
}
|
||||
|
||||
/* Ensure a guaranteed write, before return */
|
||||
static inline void spm_register_write_sync(struct spm_driver_data *drv,
|
||||
enum spm_reg reg, u32 val)
|
||||
{
|
||||
u32 ret;
|
||||
|
||||
if (!drv->reg_data->reg_offset[reg])
|
||||
return;
|
||||
|
||||
do {
|
||||
writel_relaxed(val, drv->reg_base +
|
||||
drv->reg_data->reg_offset[reg]);
|
||||
ret = readl_relaxed(drv->reg_base +
|
||||
drv->reg_data->reg_offset[reg]);
|
||||
if (ret == val)
|
||||
break;
|
||||
cpu_relax();
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static inline u32 spm_register_read(struct spm_driver_data *drv,
|
||||
enum spm_reg reg)
|
||||
{
|
||||
return readl_relaxed(drv->reg_base + drv->reg_data->reg_offset[reg]);
|
||||
}
|
||||
|
||||
static void spm_set_low_power_mode(struct spm_driver_data *drv,
|
||||
enum pm_sleep_mode mode)
|
||||
{
|
||||
u32 start_index;
|
||||
u32 ctl_val;
|
||||
|
||||
start_index = drv->reg_data->start_index[mode];
|
||||
|
||||
ctl_val = spm_register_read(drv, SPM_REG_SPM_CTL);
|
||||
ctl_val &= ~(SPM_CTL_INDEX << SPM_CTL_INDEX_SHIFT);
|
||||
ctl_val |= start_index << SPM_CTL_INDEX_SHIFT;
|
||||
ctl_val |= SPM_CTL_EN;
|
||||
spm_register_write_sync(drv, SPM_REG_SPM_CTL, ctl_val);
|
||||
}
|
||||
|
||||
static int qcom_pm_collapse(unsigned long int unused)
|
||||
{
|
||||
qcom_scm_cpu_power_down(QCOM_SCM_CPU_PWR_DOWN_L2_ON);
|
||||
@ -201,10 +61,10 @@ static int qcom_cpu_spc(struct spm_driver_data *drv)
|
||||
static int spm_enter_idle_state(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv, int idx)
|
||||
{
|
||||
struct spm_driver_data *data = container_of(drv, struct spm_driver_data,
|
||||
cpuidle_driver);
|
||||
struct cpuidle_qcom_spm_data *data = container_of(drv, struct cpuidle_qcom_spm_data,
|
||||
cpuidle_driver);
|
||||
|
||||
return CPU_PM_CPU_IDLE_ENTER_PARAM(qcom_cpu_spc, idx, data);
|
||||
return CPU_PM_CPU_IDLE_ENTER_PARAM(qcom_cpu_spc, idx, data->spm);
|
||||
}
|
||||
|
||||
static struct cpuidle_driver qcom_spm_idle_driver = {
|
||||
@ -225,134 +85,92 @@ static const struct of_device_id qcom_idle_state_match[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
static int spm_cpuidle_init(struct cpuidle_driver *drv, int cpu)
|
||||
static int spm_cpuidle_register(struct device *cpuidle_dev, int cpu)
|
||||
{
|
||||
struct platform_device *pdev = NULL;
|
||||
struct device_node *cpu_node, *saw_node;
|
||||
struct cpuidle_qcom_spm_data *data = NULL;
|
||||
int ret;
|
||||
|
||||
memcpy(drv, &qcom_spm_idle_driver, sizeof(*drv));
|
||||
drv->cpumask = (struct cpumask *)cpumask_of(cpu);
|
||||
cpu_node = of_cpu_device_node_get(cpu);
|
||||
if (!cpu_node)
|
||||
return -ENODEV;
|
||||
|
||||
/* Parse idle states from device tree */
|
||||
ret = dt_init_idle_driver(drv, qcom_idle_state_match, 1);
|
||||
saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0);
|
||||
if (!saw_node)
|
||||
return -ENODEV;
|
||||
|
||||
pdev = of_find_device_by_node(saw_node);
|
||||
of_node_put(saw_node);
|
||||
of_node_put(cpu_node);
|
||||
if (!pdev)
|
||||
return -ENODEV;
|
||||
|
||||
data = devm_kzalloc(cpuidle_dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->spm = dev_get_drvdata(&pdev->dev);
|
||||
if (!data->spm)
|
||||
return -EINVAL;
|
||||
|
||||
data->cpuidle_driver = qcom_spm_idle_driver;
|
||||
data->cpuidle_driver.cpumask = (struct cpumask *)cpumask_of(cpu);
|
||||
|
||||
ret = dt_init_idle_driver(&data->cpuidle_driver,
|
||||
qcom_idle_state_match, 1);
|
||||
if (ret <= 0)
|
||||
return ret ? : -ENODEV;
|
||||
|
||||
/* We have atleast one power down mode */
|
||||
return qcom_scm_set_warm_boot_addr(cpu_resume_arm, drv->cpumask);
|
||||
ret = qcom_scm_set_warm_boot_addr(cpu_resume_arm, cpumask_of(cpu));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return cpuidle_register(&data->cpuidle_driver, NULL);
|
||||
}
|
||||
|
||||
static struct spm_driver_data *spm_get_drv(struct platform_device *pdev,
|
||||
int *spm_cpu)
|
||||
static int spm_cpuidle_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spm_driver_data *drv = NULL;
|
||||
struct device_node *cpu_node, *saw_node;
|
||||
int cpu;
|
||||
bool found = 0;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
cpu_node = of_cpu_device_node_get(cpu);
|
||||
if (!cpu_node)
|
||||
continue;
|
||||
saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0);
|
||||
found = (saw_node == pdev->dev.of_node);
|
||||
of_node_put(saw_node);
|
||||
of_node_put(cpu_node);
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
|
||||
if (drv)
|
||||
*spm_cpu = cpu;
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
static const struct of_device_id spm_match_table[] = {
|
||||
{ .compatible = "qcom,msm8226-saw2-v2.1-cpu",
|
||||
.data = &spm_reg_8226_cpu },
|
||||
{ .compatible = "qcom,msm8974-saw2-v2.1-cpu",
|
||||
.data = &spm_reg_8974_8084_cpu },
|
||||
{ .compatible = "qcom,apq8084-saw2-v2.1-cpu",
|
||||
.data = &spm_reg_8974_8084_cpu },
|
||||
{ .compatible = "qcom,apq8064-saw2-v1.1-cpu",
|
||||
.data = &spm_reg_8064_cpu },
|
||||
{ },
|
||||
};
|
||||
|
||||
static int spm_dev_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spm_driver_data *drv;
|
||||
struct resource *res;
|
||||
const struct of_device_id *match_id;
|
||||
void __iomem *addr;
|
||||
int cpu, ret;
|
||||
|
||||
if (!qcom_scm_is_available())
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
drv = spm_get_drv(pdev, &cpu);
|
||||
if (!drv)
|
||||
return -EINVAL;
|
||||
platform_set_drvdata(pdev, drv);
|
||||
for_each_possible_cpu(cpu) {
|
||||
ret = spm_cpuidle_register(&pdev->dev, cpu);
|
||||
if (ret && ret != -ENODEV) {
|
||||
dev_err(&pdev->dev,
|
||||
"Cannot register for CPU%d: %d\n", cpu, ret);
|
||||
}
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
drv->reg_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(drv->reg_base))
|
||||
return PTR_ERR(drv->reg_base);
|
||||
|
||||
match_id = of_match_node(spm_match_table, pdev->dev.of_node);
|
||||
if (!match_id)
|
||||
return -ENODEV;
|
||||
|
||||
drv->reg_data = match_id->data;
|
||||
|
||||
ret = spm_cpuidle_init(&drv->cpuidle_driver, cpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Write the SPM sequences first.. */
|
||||
addr = drv->reg_base + drv->reg_data->reg_offset[SPM_REG_SEQ_ENTRY];
|
||||
__iowrite32_copy(addr, drv->reg_data->seq,
|
||||
ARRAY_SIZE(drv->reg_data->seq) / 4);
|
||||
|
||||
/*
|
||||
* ..and then the control registers.
|
||||
* On some SoC if the control registers are written first and if the
|
||||
* CPU was held in reset, the reset signal could trigger the SPM state
|
||||
* machine, before the sequences are completely written.
|
||||
*/
|
||||
spm_register_write(drv, SPM_REG_CFG, drv->reg_data->spm_cfg);
|
||||
spm_register_write(drv, SPM_REG_DLY, drv->reg_data->spm_dly);
|
||||
spm_register_write(drv, SPM_REG_PMIC_DLY, drv->reg_data->pmic_dly);
|
||||
spm_register_write(drv, SPM_REG_PMIC_DATA_0,
|
||||
drv->reg_data->pmic_data[0]);
|
||||
spm_register_write(drv, SPM_REG_PMIC_DATA_1,
|
||||
drv->reg_data->pmic_data[1]);
|
||||
|
||||
/* Set up Standby as the default low power mode */
|
||||
spm_set_low_power_mode(drv, PM_SLEEP_MODE_STBY);
|
||||
|
||||
return cpuidle_register(&drv->cpuidle_driver, NULL);
|
||||
}
|
||||
|
||||
static int spm_dev_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spm_driver_data *drv = platform_get_drvdata(pdev);
|
||||
|
||||
cpuidle_unregister(&drv->cpuidle_driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver spm_driver = {
|
||||
.probe = spm_dev_probe,
|
||||
.remove = spm_dev_remove,
|
||||
static struct platform_driver spm_cpuidle_driver = {
|
||||
.probe = spm_cpuidle_drv_probe,
|
||||
.driver = {
|
||||
.name = "saw",
|
||||
.of_match_table = spm_match_table,
|
||||
.name = "qcom-spm-cpuidle",
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
builtin_platform_driver(spm_driver);
|
||||
static int __init qcom_spm_cpuidle_init(void)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&spm_cpuidle_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pdev = platform_device_register_simple("qcom-spm-cpuidle",
|
||||
-1, NULL, 0);
|
||||
if (IS_ERR(pdev)) {
|
||||
platform_driver_unregister(&spm_cpuidle_driver);
|
||||
return PTR_ERR(pdev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
device_initcall(qcom_spm_cpuidle_init);
|
||||
|
@ -337,6 +337,9 @@ static void tegra_cpuidle_setup_tegra114_c7_state(void)
|
||||
|
||||
static int tegra_cpuidle_probe(struct platform_device *pdev)
|
||||
{
|
||||
if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NOT_READY)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
/* LP2 could be disabled in device-tree */
|
||||
if (tegra_pmc_get_suspend_mode() < TEGRA_SUSPEND_LP2)
|
||||
tegra_cpuidle_disable_state(TEGRA_CC6);
|
||||
|
@ -167,6 +167,27 @@ struct ffa_drv_info {
|
||||
|
||||
static struct ffa_drv_info *drv_info;
|
||||
|
||||
/*
|
||||
* The driver must be able to support all the versions from the earliest
|
||||
* supported FFA_MIN_VERSION to the latest supported FFA_DRIVER_VERSION.
|
||||
* The specification states that if firmware supports a FFA implementation
|
||||
* that is incompatible with and at a greater version number than specified
|
||||
* by the caller(FFA_DRIVER_VERSION passed as parameter to FFA_VERSION),
|
||||
* it must return the NOT_SUPPORTED error code.
|
||||
*/
|
||||
static u32 ffa_compatible_version_find(u32 version)
|
||||
{
|
||||
u16 major = MAJOR_VERSION(version), minor = MINOR_VERSION(version);
|
||||
u16 drv_major = MAJOR_VERSION(FFA_DRIVER_VERSION);
|
||||
u16 drv_minor = MINOR_VERSION(FFA_DRIVER_VERSION);
|
||||
|
||||
if ((major < drv_major) || (major == drv_major && minor <= drv_minor))
|
||||
return version;
|
||||
|
||||
pr_info("Firmware version higher than driver version, downgrading\n");
|
||||
return FFA_DRIVER_VERSION;
|
||||
}
|
||||
|
||||
static int ffa_version_check(u32 *version)
|
||||
{
|
||||
ffa_value_t ver;
|
||||
@ -180,15 +201,20 @@ static int ffa_version_check(u32 *version)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (ver.a0 < FFA_MIN_VERSION || ver.a0 > FFA_DRIVER_VERSION) {
|
||||
pr_err("Incompatible version %d.%d found\n",
|
||||
MAJOR_VERSION(ver.a0), MINOR_VERSION(ver.a0));
|
||||
if (ver.a0 < FFA_MIN_VERSION) {
|
||||
pr_err("Incompatible v%d.%d! Earliest supported v%d.%d\n",
|
||||
MAJOR_VERSION(ver.a0), MINOR_VERSION(ver.a0),
|
||||
MAJOR_VERSION(FFA_MIN_VERSION),
|
||||
MINOR_VERSION(FFA_MIN_VERSION));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*version = ver.a0;
|
||||
pr_info("Version %d.%d found\n", MAJOR_VERSION(ver.a0),
|
||||
pr_info("Driver version %d.%d\n", MAJOR_VERSION(FFA_DRIVER_VERSION),
|
||||
MINOR_VERSION(FFA_DRIVER_VERSION));
|
||||
pr_info("Firmware version %d.%d found\n", MAJOR_VERSION(ver.a0),
|
||||
MINOR_VERSION(ver.a0));
|
||||
*version = ffa_compatible_version_find(ver.a0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -586,6 +612,22 @@ ffa_memory_share(struct ffa_device *dev, struct ffa_mem_ops_args *args)
|
||||
return ffa_memory_ops(FFA_FN_NATIVE(MEM_SHARE), args);
|
||||
}
|
||||
|
||||
static int
|
||||
ffa_memory_lend(struct ffa_device *dev, struct ffa_mem_ops_args *args)
|
||||
{
|
||||
/* Note that upon a successful MEM_LEND request the caller
|
||||
* must ensure that the memory region specified is not accessed
|
||||
* until a successful MEM_RECALIM call has been made.
|
||||
* On systems with a hypervisor present this will been enforced,
|
||||
* however on systems without a hypervisor the responsibility
|
||||
* falls to the calling kernel driver to prevent access.
|
||||
*/
|
||||
if (dev->mode_32bit)
|
||||
return ffa_memory_ops(FFA_MEM_LEND, args);
|
||||
|
||||
return ffa_memory_ops(FFA_FN_NATIVE(MEM_LEND), args);
|
||||
}
|
||||
|
||||
static const struct ffa_dev_ops ffa_ops = {
|
||||
.api_version_get = ffa_api_version_get,
|
||||
.partition_info_get = ffa_partition_info_get,
|
||||
@ -593,6 +635,7 @@ static const struct ffa_dev_ops ffa_ops = {
|
||||
.sync_send_receive = ffa_sync_send_receive,
|
||||
.memory_reclaim = ffa_memory_reclaim,
|
||||
.memory_share = ffa_memory_share,
|
||||
.memory_lend = ffa_memory_lend,
|
||||
};
|
||||
|
||||
const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev)
|
||||
|
@ -252,7 +252,7 @@ static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown SMC convention being used\n");
|
||||
return -EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = qcom_scm_call(dev, &desc, &res);
|
||||
@ -1348,6 +1348,10 @@ static const struct of_device_id qcom_scm_dt_match[] = {
|
||||
SCM_HAS_IFACE_CLK |
|
||||
SCM_HAS_BUS_CLK)
|
||||
},
|
||||
{ .compatible = "qcom,scm-msm8953", .data = (void *)(SCM_HAS_CORE_CLK |
|
||||
SCM_HAS_IFACE_CLK |
|
||||
SCM_HAS_BUS_CLK)
|
||||
},
|
||||
{ .compatible = "qcom,scm-msm8974", .data = (void *)(SCM_HAS_CORE_CLK |
|
||||
SCM_HAS_IFACE_CLK |
|
||||
SCM_HAS_BUS_CLK)
|
||||
|
@ -74,28 +74,36 @@ static void seqbuf_seek(struct seqbuf *seqbuf, ssize_t offset)
|
||||
static const char *get_filename(struct tegra_bpmp *bpmp,
|
||||
const struct file *file, char *buf, int size)
|
||||
{
|
||||
char root_path_buf[512];
|
||||
const char *root_path;
|
||||
const char *filename;
|
||||
const char *root_path, *filename = NULL;
|
||||
char *root_path_buf;
|
||||
size_t root_len;
|
||||
|
||||
root_path_buf = kzalloc(512, GFP_KERNEL);
|
||||
if (!root_path_buf)
|
||||
goto out;
|
||||
|
||||
root_path = dentry_path(bpmp->debugfs_mirror, root_path_buf,
|
||||
sizeof(root_path_buf));
|
||||
if (IS_ERR(root_path))
|
||||
return NULL;
|
||||
goto out;
|
||||
|
||||
root_len = strlen(root_path);
|
||||
|
||||
filename = dentry_path(file->f_path.dentry, buf, size);
|
||||
if (IS_ERR(filename))
|
||||
return NULL;
|
||||
if (IS_ERR(filename)) {
|
||||
filename = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strlen(filename) < root_len ||
|
||||
strncmp(filename, root_path, root_len))
|
||||
return NULL;
|
||||
if (strlen(filename) < root_len || strncmp(filename, root_path, root_len)) {
|
||||
filename = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
filename += root_len;
|
||||
|
||||
out:
|
||||
kfree(root_path_buf);
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
@ -162,7 +162,6 @@ static int tegra210_bpmp_init(struct tegra_bpmp *bpmp)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(bpmp->dev);
|
||||
struct tegra210_bpmp *priv;
|
||||
struct resource *res;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
@ -172,13 +171,11 @@ static int tegra210_bpmp_init(struct tegra_bpmp *bpmp)
|
||||
|
||||
bpmp->priv = priv;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->atomics = devm_ioremap_resource(&pdev->dev, res);
|
||||
priv->atomics = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->atomics))
|
||||
return PTR_ERR(priv->atomics);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
priv->arb_sema = devm_ioremap_resource(&pdev->dev, res);
|
||||
priv->arb_sema = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(priv->arb_sema))
|
||||
return PTR_ERR(priv->arb_sema);
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include <video/mipi_display.h>
|
||||
#include <video/videomode.h>
|
||||
@ -980,8 +981,10 @@ static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
|
||||
struct mtk_dsi *dsi = dev_get_drvdata(dev);
|
||||
|
||||
ret = mtk_dsi_encoder_init(drm, dsi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
return device_reset_optional(dev);
|
||||
}
|
||||
|
||||
static void mtk_dsi_unbind(struct device *dev, struct device *master,
|
||||
|
@ -55,8 +55,8 @@ config ATMEL_EBI
|
||||
SRAMs, ATA devices, etc.
|
||||
|
||||
config BRCMSTB_DPFE
|
||||
bool "Broadcom STB DPFE driver" if COMPILE_TEST
|
||||
default y if ARCH_BRCMSTB
|
||||
tristate "Broadcom STB DPFE driver"
|
||||
default ARCH_BRCMSTB
|
||||
depends on ARCH_BRCMSTB || COMPILE_TEST
|
||||
help
|
||||
This driver provides access to the DPFE interface of Broadcom
|
||||
@ -210,6 +210,7 @@ config RENESAS_RPCIF
|
||||
tristate "Renesas RPC-IF driver"
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
select REGMAP_MMIO
|
||||
select RESET_CONTROLLER
|
||||
help
|
||||
This supports Renesas R-Car Gen3 or RZ/G2 RPC-IF which provides
|
||||
either SPI host or HyperFlash. You'll have to select individual
|
||||
|
@ -263,7 +263,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
|
||||
|
||||
ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
goto err_unmap_nandirq;
|
||||
|
||||
init_waitqueue_head(&fsl_ifc_ctrl_dev->nand_wait);
|
||||
|
||||
@ -272,7 +272,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
|
||||
if (ret != 0) {
|
||||
dev_err(&dev->dev, "failed to install irq (%d)\n",
|
||||
fsl_ifc_ctrl_dev->irq);
|
||||
goto err_irq;
|
||||
goto err_unmap_nandirq;
|
||||
}
|
||||
|
||||
if (fsl_ifc_ctrl_dev->nand_irq) {
|
||||
@ -281,17 +281,16 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
|
||||
if (ret != 0) {
|
||||
dev_err(&dev->dev, "failed to install irq (%d)\n",
|
||||
fsl_ifc_ctrl_dev->nand_irq);
|
||||
goto err_nandirq;
|
||||
goto err_free_irq;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_nandirq:
|
||||
free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev);
|
||||
irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
|
||||
err_irq:
|
||||
err_free_irq:
|
||||
free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
|
||||
err_unmap_nandirq:
|
||||
irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
|
||||
irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
|
||||
err:
|
||||
iounmap(fsl_ifc_ctrl_dev->gregs);
|
||||
|
@ -112,6 +112,26 @@
|
||||
#define NUM_DDR_ADDR_TABLE_ENTRIES 11
|
||||
#define NUM_DDR_TIMING_TABLE_ENTRIES 4
|
||||
|
||||
#define LPDDR2_MANID_SAMSUNG 1
|
||||
#define LPDDR2_MANID_QIMONDA 2
|
||||
#define LPDDR2_MANID_ELPIDA 3
|
||||
#define LPDDR2_MANID_ETRON 4
|
||||
#define LPDDR2_MANID_NANYA 5
|
||||
#define LPDDR2_MANID_HYNIX 6
|
||||
#define LPDDR2_MANID_MOSEL 7
|
||||
#define LPDDR2_MANID_WINBOND 8
|
||||
#define LPDDR2_MANID_ESMT 9
|
||||
#define LPDDR2_MANID_SPANSION 11
|
||||
#define LPDDR2_MANID_SST 12
|
||||
#define LPDDR2_MANID_ZMOS 13
|
||||
#define LPDDR2_MANID_INTEL 14
|
||||
#define LPDDR2_MANID_NUMONYX 254
|
||||
#define LPDDR2_MANID_MICRON 255
|
||||
|
||||
#define LPDDR2_TYPE_S4 0
|
||||
#define LPDDR2_TYPE_S2 1
|
||||
#define LPDDR2_TYPE_NVM 2
|
||||
|
||||
/* Structure for DDR addressing info from the JEDEC spec */
|
||||
struct lpddr2_addressing {
|
||||
u32 num_banks;
|
||||
@ -170,6 +190,33 @@ extern const struct lpddr2_timings
|
||||
lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES];
|
||||
extern const struct lpddr2_min_tck lpddr2_jedec_min_tck;
|
||||
|
||||
/* Structure of MR8 */
|
||||
union lpddr2_basic_config4 {
|
||||
u32 value;
|
||||
|
||||
struct {
|
||||
unsigned int arch_type : 2;
|
||||
unsigned int density : 4;
|
||||
unsigned int io_width : 2;
|
||||
} __packed;
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure for information about LPDDR2 chip. All parameters are
|
||||
* matching raw values of standard mode register bitfields or set to
|
||||
* -ENOENT if info unavailable.
|
||||
*/
|
||||
struct lpddr2_info {
|
||||
int arch_type;
|
||||
int density;
|
||||
int io_width;
|
||||
int manufacturer_id;
|
||||
int revision_id1;
|
||||
int revision_id2;
|
||||
};
|
||||
|
||||
const char *lpddr2_jedec_manufacturer(unsigned int manufacturer_id);
|
||||
|
||||
/*
|
||||
* Structure for timings for LPDDR3 based on LPDDR2 plus additional fields.
|
||||
* All parameters are in pico seconds(ps) excluding max_freq, min_freq which
|
||||
|
@ -131,3 +131,44 @@ const struct lpddr2_min_tck lpddr2_jedec_min_tck = {
|
||||
.tFAW = 8
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(lpddr2_jedec_min_tck);
|
||||
|
||||
const char *lpddr2_jedec_manufacturer(unsigned int manufacturer_id)
|
||||
{
|
||||
switch (manufacturer_id) {
|
||||
case LPDDR2_MANID_SAMSUNG:
|
||||
return "Samsung";
|
||||
case LPDDR2_MANID_QIMONDA:
|
||||
return "Qimonda";
|
||||
case LPDDR2_MANID_ELPIDA:
|
||||
return "Elpida";
|
||||
case LPDDR2_MANID_ETRON:
|
||||
return "Etron";
|
||||
case LPDDR2_MANID_NANYA:
|
||||
return "Nanya";
|
||||
case LPDDR2_MANID_HYNIX:
|
||||
return "Hynix";
|
||||
case LPDDR2_MANID_MOSEL:
|
||||
return "Mosel";
|
||||
case LPDDR2_MANID_WINBOND:
|
||||
return "Winbond";
|
||||
case LPDDR2_MANID_ESMT:
|
||||
return "ESMT";
|
||||
case LPDDR2_MANID_SPANSION:
|
||||
return "Spansion";
|
||||
case LPDDR2_MANID_SST:
|
||||
return "SST";
|
||||
case LPDDR2_MANID_ZMOS:
|
||||
return "ZMOS";
|
||||
case LPDDR2_MANID_INTEL:
|
||||
return "Intel";
|
||||
case LPDDR2_MANID_NUMONYX:
|
||||
return "Numonyx";
|
||||
case LPDDR2_MANID_MICRON:
|
||||
return "Micron";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "invalid";
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lpddr2_jedec_manufacturer);
|
||||
|
@ -17,13 +17,33 @@
|
||||
#include <dt-bindings/memory/mt2701-larb-port.h>
|
||||
#include <dt-bindings/memory/mtk-memory-port.h>
|
||||
|
||||
/* mt8173 */
|
||||
#define SMI_LARB_MMU_EN 0xf00
|
||||
/* SMI COMMON */
|
||||
#define SMI_L1LEN 0x100
|
||||
|
||||
/* mt8167 */
|
||||
#define MT8167_SMI_LARB_MMU_EN 0xfc0
|
||||
#define SMI_BUS_SEL 0x220
|
||||
#define SMI_BUS_LARB_SHIFT(larbid) ((larbid) << 1)
|
||||
/* All are MMU0 defaultly. Only specialize mmu1 here. */
|
||||
#define F_MMU1_LARB(larbid) (0x1 << SMI_BUS_LARB_SHIFT(larbid))
|
||||
|
||||
/* mt2701 */
|
||||
#define SMI_M4U_TH 0x234
|
||||
#define SMI_FIFO_TH1 0x238
|
||||
#define SMI_FIFO_TH2 0x23c
|
||||
#define SMI_DCM 0x300
|
||||
#define SMI_DUMMY 0x444
|
||||
|
||||
/* SMI LARB */
|
||||
#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)
|
||||
|
||||
#define SMI_LARB_SW_FLAG 0x40
|
||||
#define SMI_LARB_SW_FLAG_1 0x1
|
||||
|
||||
#define SMI_LARB_OSTDL_PORT 0x200
|
||||
#define SMI_LARB_OSTDL_PORTx(id) (SMI_LARB_OSTDL_PORT + (((id) & 0x1f) << 2))
|
||||
|
||||
/* Below are about mmu enable registers, they are different in SoCs */
|
||||
/* gen1: mt2701 */
|
||||
#define REG_SMI_SECUR_CON_BASE 0x5c0
|
||||
|
||||
/* every register control 8 port, register offset 0x4 */
|
||||
@ -41,99 +61,94 @@
|
||||
/* mt2701 domain should be set to 3 */
|
||||
#define SMI_SECUR_CON_VAL_DOMAIN(id) (0x3 << ((((id) & 0x7) << 2) + 1))
|
||||
|
||||
/* mt2712 */
|
||||
#define SMI_LARB_NONSEC_CON(id) (0x380 + ((id) * 4))
|
||||
#define F_MMU_EN BIT(0)
|
||||
#define BANK_SEL(id) ({ \
|
||||
/* gen2: */
|
||||
/* mt8167 */
|
||||
#define MT8167_SMI_LARB_MMU_EN 0xfc0
|
||||
|
||||
/* mt8173 */
|
||||
#define MT8173_SMI_LARB_MMU_EN 0xf00
|
||||
|
||||
/* general */
|
||||
#define SMI_LARB_NONSEC_CON(id) (0x380 + ((id) * 4))
|
||||
#define F_MMU_EN BIT(0)
|
||||
#define BANK_SEL(id) ({ \
|
||||
u32 _id = (id) & 0x3; \
|
||||
(_id << 8 | _id << 10 | _id << 12 | _id << 14); \
|
||||
})
|
||||
|
||||
/* SMI COMMON */
|
||||
#define SMI_BUS_SEL 0x220
|
||||
#define SMI_BUS_LARB_SHIFT(larbid) ((larbid) << 1)
|
||||
/* All are MMU0 defaultly. Only specialize mmu1 here. */
|
||||
#define F_MMU1_LARB(larbid) (0x1 << SMI_BUS_LARB_SHIFT(larbid))
|
||||
#define SMI_COMMON_INIT_REGS_NR 6
|
||||
#define SMI_LARB_PORT_NR_MAX 32
|
||||
|
||||
enum mtk_smi_gen {
|
||||
MTK_SMI_GEN1,
|
||||
MTK_SMI_GEN2
|
||||
#define MTK_SMI_FLAG_THRT_UPDATE BIT(0)
|
||||
#define MTK_SMI_FLAG_SW_FLAG BIT(1)
|
||||
#define MTK_SMI_CAPS(flags, _x) (!!((flags) & (_x)))
|
||||
|
||||
struct mtk_smi_reg_pair {
|
||||
unsigned int offset;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
enum mtk_smi_type {
|
||||
MTK_SMI_GEN1,
|
||||
MTK_SMI_GEN2, /* gen2 smi common */
|
||||
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
|
||||
#define MTK_SMI_LARB_OPT_CLK_NR 1
|
||||
|
||||
/*
|
||||
* common: Require these four clocks in has_gals case. Otherwise, only apb/smi are required.
|
||||
* 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_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
|
||||
|
||||
struct mtk_smi_common_plat {
|
||||
enum mtk_smi_gen gen;
|
||||
bool has_gals;
|
||||
u32 bus_sel; /* Balance some larbs to enter mmu0 or mmu1 */
|
||||
enum mtk_smi_type type;
|
||||
bool has_gals;
|
||||
u32 bus_sel; /* Balance some larbs to enter mmu0 or mmu1 */
|
||||
|
||||
const struct mtk_smi_reg_pair *init;
|
||||
};
|
||||
|
||||
struct mtk_smi_larb_gen {
|
||||
int port_in_larb[MTK_LARB_NR_MAX + 1];
|
||||
void (*config_port)(struct device *dev);
|
||||
unsigned int larb_direct_to_common_mask;
|
||||
bool has_gals;
|
||||
unsigned int flags_general;
|
||||
const u8 (*ostd)[SMI_LARB_PORT_NR_MAX];
|
||||
};
|
||||
|
||||
struct mtk_smi {
|
||||
struct device *dev;
|
||||
struct clk *clk_apb, *clk_smi;
|
||||
struct clk *clk_gals0, *clk_gals1;
|
||||
unsigned int clk_num;
|
||||
struct clk_bulk_data clks[MTK_SMI_CLK_NR_MAX];
|
||||
struct clk *clk_async; /*only needed by mt2701*/
|
||||
union {
|
||||
void __iomem *smi_ao_base; /* only for gen1 */
|
||||
void __iomem *base; /* only for gen2 */
|
||||
};
|
||||
struct device *smi_common_dev; /* for sub common */
|
||||
const struct mtk_smi_common_plat *plat;
|
||||
};
|
||||
|
||||
struct mtk_smi_larb { /* larb: local arbiter */
|
||||
struct mtk_smi smi;
|
||||
void __iomem *base;
|
||||
struct device *smi_common_dev;
|
||||
struct device *smi_common_dev; /* common or sub-common dev */
|
||||
const struct mtk_smi_larb_gen *larb_gen;
|
||||
int larbid;
|
||||
u32 *mmu;
|
||||
unsigned char *bank;
|
||||
};
|
||||
|
||||
static int mtk_smi_clk_enable(const struct mtk_smi *smi)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(smi->clk_apb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(smi->clk_smi);
|
||||
if (ret)
|
||||
goto err_disable_apb;
|
||||
|
||||
ret = clk_prepare_enable(smi->clk_gals0);
|
||||
if (ret)
|
||||
goto err_disable_smi;
|
||||
|
||||
ret = clk_prepare_enable(smi->clk_gals1);
|
||||
if (ret)
|
||||
goto err_disable_gals0;
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable_gals0:
|
||||
clk_disable_unprepare(smi->clk_gals0);
|
||||
err_disable_smi:
|
||||
clk_disable_unprepare(smi->clk_smi);
|
||||
err_disable_apb:
|
||||
clk_disable_unprepare(smi->clk_apb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mtk_smi_clk_disable(const struct mtk_smi *smi)
|
||||
{
|
||||
clk_disable_unprepare(smi->clk_gals1);
|
||||
clk_disable_unprepare(smi->clk_gals0);
|
||||
clk_disable_unprepare(smi->clk_smi);
|
||||
clk_disable_unprepare(smi->clk_apb);
|
||||
}
|
||||
|
||||
int mtk_smi_larb_get(struct device *larbdev)
|
||||
{
|
||||
int ret = pm_runtime_resume_and_get(larbdev);
|
||||
@ -166,36 +181,16 @@ mtk_smi_larb_bind(struct device *dev, struct device *master, void *data)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void mtk_smi_larb_config_port_gen2_general(struct device *dev)
|
||||
static void
|
||||
mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
|
||||
u32 reg;
|
||||
int i;
|
||||
|
||||
if (BIT(larb->larbid) & larb->larb_gen->larb_direct_to_common_mask)
|
||||
return;
|
||||
|
||||
for_each_set_bit(i, (unsigned long *)larb->mmu, 32) {
|
||||
reg = readl_relaxed(larb->base + SMI_LARB_NONSEC_CON(i));
|
||||
reg |= F_MMU_EN;
|
||||
reg |= BANK_SEL(larb->bank[i]);
|
||||
writel(reg, larb->base + SMI_LARB_NONSEC_CON(i));
|
||||
}
|
||||
/* Do nothing as the iommu is always enabled. */
|
||||
}
|
||||
|
||||
static void mtk_smi_larb_config_port_mt8173(struct device *dev)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
|
||||
|
||||
writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN);
|
||||
}
|
||||
|
||||
static void mtk_smi_larb_config_port_mt8167(struct device *dev)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
|
||||
|
||||
writel(*larb->mmu, larb->base + MT8167_SMI_LARB_MMU_EN);
|
||||
}
|
||||
static const struct component_ops mtk_smi_larb_component_ops = {
|
||||
.bind = mtk_smi_larb_bind,
|
||||
.unbind = mtk_smi_larb_unbind,
|
||||
};
|
||||
|
||||
static void mtk_smi_larb_config_port_gen1(struct device *dev)
|
||||
{
|
||||
@ -228,25 +223,94 @@ static void mtk_smi_larb_config_port_gen1(struct device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data)
|
||||
static void mtk_smi_larb_config_port_mt8167(struct device *dev)
|
||||
{
|
||||
/* Do nothing as the iommu is always enabled. */
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
|
||||
|
||||
writel(*larb->mmu, larb->base + MT8167_SMI_LARB_MMU_EN);
|
||||
}
|
||||
|
||||
static const struct component_ops mtk_smi_larb_component_ops = {
|
||||
.bind = mtk_smi_larb_bind,
|
||||
.unbind = mtk_smi_larb_unbind,
|
||||
};
|
||||
static void mtk_smi_larb_config_port_mt8173(struct device *dev)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
|
||||
|
||||
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = {
|
||||
/* mt8173 do not need the port in larb */
|
||||
.config_port = mtk_smi_larb_config_port_mt8173,
|
||||
};
|
||||
writel(*larb->mmu, larb->base + MT8173_SMI_LARB_MMU_EN);
|
||||
}
|
||||
|
||||
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8167 = {
|
||||
/* mt8167 do not need the port in larb */
|
||||
.config_port = mtk_smi_larb_config_port_mt8167,
|
||||
static void mtk_smi_larb_config_port_gen2_general(struct device *dev)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
|
||||
u32 reg, flags_general = larb->larb_gen->flags_general;
|
||||
const u8 *larbostd = larb->larb_gen->ostd[larb->larbid];
|
||||
int i;
|
||||
|
||||
if (BIT(larb->larbid) & larb->larb_gen->larb_direct_to_common_mask)
|
||||
return;
|
||||
|
||||
if (MTK_SMI_CAPS(flags_general, MTK_SMI_FLAG_THRT_UPDATE)) {
|
||||
reg = readl_relaxed(larb->base + SMI_LARB_CMD_THRT_CON);
|
||||
reg &= ~SMI_LARB_THRT_RD_NU_LMT_MSK;
|
||||
reg |= SMI_LARB_THRT_RD_NU_LMT;
|
||||
writel_relaxed(reg, larb->base + SMI_LARB_CMD_THRT_CON);
|
||||
}
|
||||
|
||||
if (MTK_SMI_CAPS(flags_general, MTK_SMI_FLAG_SW_FLAG))
|
||||
writel_relaxed(SMI_LARB_SW_FLAG_1, larb->base + SMI_LARB_SW_FLAG);
|
||||
|
||||
for (i = 0; i < SMI_LARB_PORT_NR_MAX && larbostd && !!larbostd[i]; i++)
|
||||
writel_relaxed(larbostd[i], larb->base + SMI_LARB_OSTDL_PORTx(i));
|
||||
|
||||
for_each_set_bit(i, (unsigned long *)larb->mmu, 32) {
|
||||
reg = readl_relaxed(larb->base + SMI_LARB_NONSEC_CON(i));
|
||||
reg |= F_MMU_EN;
|
||||
reg |= BANK_SEL(larb->bank[i]);
|
||||
writel(reg, larb->base + SMI_LARB_NONSEC_CON(i));
|
||||
}
|
||||
}
|
||||
|
||||
static const u8 mtk_smi_larb_mt8195_ostd[][SMI_LARB_PORT_NR_MAX] = {
|
||||
[0] = {0x0a, 0xc, 0x22, 0x22, 0x01, 0x0a,}, /* larb0 */
|
||||
[1] = {0x0a, 0xc, 0x22, 0x22, 0x01, 0x0a,}, /* larb1 */
|
||||
[2] = {0x12, 0x12, 0x12, 0x12, 0x0a,}, /* ... */
|
||||
[3] = {0x12, 0x12, 0x12, 0x12, 0x28, 0x28, 0x0a,},
|
||||
[4] = {0x06, 0x01, 0x17, 0x06, 0x0a,},
|
||||
[5] = {0x06, 0x01, 0x17, 0x06, 0x06, 0x01, 0x06, 0x0a,},
|
||||
[6] = {0x06, 0x01, 0x06, 0x0a,},
|
||||
[7] = {0x0c, 0x0c, 0x12,},
|
||||
[8] = {0x0c, 0x0c, 0x12,},
|
||||
[9] = {0x0a, 0x08, 0x04, 0x06, 0x01, 0x01, 0x10, 0x18, 0x11, 0x0a,
|
||||
0x08, 0x04, 0x11, 0x06, 0x02, 0x06, 0x01, 0x11, 0x11, 0x06,},
|
||||
[10] = {0x18, 0x08, 0x01, 0x01, 0x20, 0x12, 0x18, 0x06, 0x05, 0x10,
|
||||
0x08, 0x08, 0x10, 0x08, 0x08, 0x18, 0x0c, 0x09, 0x0b, 0x0d,
|
||||
0x0d, 0x06, 0x10, 0x10,},
|
||||
[11] = {0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x01, 0x01, 0x01, 0x01,},
|
||||
[12] = {0x09, 0x09, 0x05, 0x05, 0x0c, 0x18, 0x02, 0x02, 0x04, 0x02,},
|
||||
[13] = {0x02, 0x02, 0x12, 0x12, 0x02, 0x02, 0x02, 0x02, 0x08, 0x01,},
|
||||
[14] = {0x12, 0x12, 0x02, 0x02, 0x02, 0x02, 0x16, 0x01, 0x16, 0x01,
|
||||
0x01, 0x02, 0x02, 0x08, 0x02,},
|
||||
[15] = {},
|
||||
[16] = {0x28, 0x02, 0x02, 0x12, 0x02, 0x12, 0x10, 0x02, 0x02, 0x0a,
|
||||
0x12, 0x02, 0x0a, 0x16, 0x02, 0x04,},
|
||||
[17] = {0x1a, 0x0e, 0x0a, 0x0a, 0x0c, 0x0e, 0x10,},
|
||||
[18] = {0x12, 0x06, 0x12, 0x06,},
|
||||
[19] = {0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01,
|
||||
0x01, 0x01, 0x04, 0x0a, 0x06, 0x01, 0x01, 0x01, 0x0a, 0x06,
|
||||
0x01, 0x01, 0x05, 0x03, 0x03, 0x04, 0x01,},
|
||||
[20] = {0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01,
|
||||
0x01, 0x01, 0x04, 0x0a, 0x06, 0x01, 0x01, 0x01, 0x0a, 0x06,
|
||||
0x01, 0x01, 0x05, 0x03, 0x03, 0x04, 0x01,},
|
||||
[21] = {0x28, 0x19, 0x0c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,},
|
||||
[22] = {0x28, 0x19, 0x0c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,},
|
||||
[23] = {0x18, 0x01,},
|
||||
[24] = {0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01,
|
||||
0x01, 0x01,},
|
||||
[25] = {0x02, 0x02, 0x02, 0x28, 0x16, 0x02, 0x02, 0x02, 0x12, 0x16,
|
||||
0x02, 0x01,},
|
||||
[26] = {0x02, 0x02, 0x02, 0x28, 0x16, 0x02, 0x02, 0x02, 0x12, 0x16,
|
||||
0x02, 0x01,},
|
||||
[27] = {0x02, 0x02, 0x02, 0x28, 0x16, 0x02, 0x02, 0x02, 0x12, 0x16,
|
||||
0x02, 0x01,},
|
||||
[28] = {0x1a, 0x0e, 0x0a, 0x0a, 0x0c, 0x0e, 0x10,},
|
||||
};
|
||||
|
||||
static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = {
|
||||
@ -269,8 +333,17 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt6779 = {
|
||||
/* DUMMY | IPU0 | IPU1 | CCU | MDLA */
|
||||
};
|
||||
|
||||
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8167 = {
|
||||
/* mt8167 do not need the port in larb */
|
||||
.config_port = mtk_smi_larb_config_port_mt8167,
|
||||
};
|
||||
|
||||
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = {
|
||||
/* mt8173 do not need the port in larb */
|
||||
.config_port = mtk_smi_larb_config_port_mt8173,
|
||||
};
|
||||
|
||||
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = {
|
||||
.has_gals = true,
|
||||
.config_port = mtk_smi_larb_config_port_gen2_general,
|
||||
.larb_direct_to_common_mask = BIT(2) | BIT(3) | BIT(7),
|
||||
/* IPU0 | IPU1 | CCU */
|
||||
@ -280,99 +353,114 @@ 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,
|
||||
.ostd = mtk_smi_larb_mt8195_ostd,
|
||||
};
|
||||
|
||||
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,mt2701-smi-larb",
|
||||
.data = &mtk_smi_larb_mt2701
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt2712-smi-larb",
|
||||
.data = &mtk_smi_larb_mt2712
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt6779-smi-larb",
|
||||
.data = &mtk_smi_larb_mt6779
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8183-smi-larb",
|
||||
.data = &mtk_smi_larb_mt8183
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8192-smi-larb",
|
||||
.data = &mtk_smi_larb_mt8192
|
||||
},
|
||||
{.compatible = "mediatek,mt2701-smi-larb", .data = &mtk_smi_larb_mt2701},
|
||||
{.compatible = "mediatek,mt2712-smi-larb", .data = &mtk_smi_larb_mt2712},
|
||||
{.compatible = "mediatek,mt6779-smi-larb", .data = &mtk_smi_larb_mt6779},
|
||||
{.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,mt8192-smi-larb", .data = &mtk_smi_larb_mt8192},
|
||||
{.compatible = "mediatek,mt8195-smi-larb", .data = &mtk_smi_larb_mt8195},
|
||||
{}
|
||||
};
|
||||
|
||||
static int mtk_smi_device_link_common(struct device *dev, struct device **com_dev)
|
||||
{
|
||||
struct platform_device *smi_com_pdev;
|
||||
struct device_node *smi_com_node;
|
||||
struct device *smi_com_dev;
|
||||
struct device_link *link;
|
||||
|
||||
smi_com_node = of_parse_phandle(dev->of_node, "mediatek,smi", 0);
|
||||
if (!smi_com_node)
|
||||
return -EINVAL;
|
||||
|
||||
smi_com_pdev = of_find_device_by_node(smi_com_node);
|
||||
of_node_put(smi_com_node);
|
||||
if (smi_com_pdev) {
|
||||
/* smi common is the supplier, Make sure it is ready before */
|
||||
if (!platform_get_drvdata(smi_com_pdev))
|
||||
return -EPROBE_DEFER;
|
||||
smi_com_dev = &smi_com_pdev->dev;
|
||||
link = device_link_add(dev, smi_com_dev,
|
||||
DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS);
|
||||
if (!link) {
|
||||
dev_err(dev, "Unable to link smi-common dev\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
*com_dev = smi_com_dev;
|
||||
} else {
|
||||
dev_err(dev, "Failed to get the smi_common device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_smi_dts_clk_init(struct device *dev, struct mtk_smi *smi,
|
||||
const char * const clks[],
|
||||
unsigned int clk_nr_required,
|
||||
unsigned int clk_nr_optional)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < clk_nr_required; i++)
|
||||
smi->clks[i].id = clks[i];
|
||||
ret = devm_clk_bulk_get(dev, clk_nr_required, smi->clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = clk_nr_required; i < clk_nr_required + clk_nr_optional; i++)
|
||||
smi->clks[i].id = clks[i];
|
||||
ret = devm_clk_bulk_get_optional(dev, clk_nr_optional,
|
||||
smi->clks + clk_nr_required);
|
||||
smi->clk_num = clk_nr_required + clk_nr_optional;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mtk_smi_larb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mtk_smi_larb *larb;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *smi_node;
|
||||
struct platform_device *smi_pdev;
|
||||
struct device_link *link;
|
||||
int ret;
|
||||
|
||||
larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL);
|
||||
if (!larb)
|
||||
return -ENOMEM;
|
||||
|
||||
larb->larb_gen = of_device_get_match_data(dev);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
larb->base = devm_ioremap_resource(dev, res);
|
||||
larb->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(larb->base))
|
||||
return PTR_ERR(larb->base);
|
||||
|
||||
larb->smi.clk_apb = devm_clk_get(dev, "apb");
|
||||
if (IS_ERR(larb->smi.clk_apb))
|
||||
return PTR_ERR(larb->smi.clk_apb);
|
||||
ret = mtk_smi_dts_clk_init(dev, &larb->smi, mtk_smi_larb_clks,
|
||||
MTK_SMI_LARB_REQ_CLK_NR, MTK_SMI_LARB_OPT_CLK_NR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
larb->smi.clk_smi = devm_clk_get(dev, "smi");
|
||||
if (IS_ERR(larb->smi.clk_smi))
|
||||
return PTR_ERR(larb->smi.clk_smi);
|
||||
|
||||
if (larb->larb_gen->has_gals) {
|
||||
/* The larbs may still haven't gals even if the SoC support.*/
|
||||
larb->smi.clk_gals0 = devm_clk_get(dev, "gals");
|
||||
if (PTR_ERR(larb->smi.clk_gals0) == -ENOENT)
|
||||
larb->smi.clk_gals0 = NULL;
|
||||
else if (IS_ERR(larb->smi.clk_gals0))
|
||||
return PTR_ERR(larb->smi.clk_gals0);
|
||||
}
|
||||
larb->smi.dev = dev;
|
||||
|
||||
smi_node = of_parse_phandle(dev->of_node, "mediatek,smi", 0);
|
||||
if (!smi_node)
|
||||
return -EINVAL;
|
||||
|
||||
smi_pdev = of_find_device_by_node(smi_node);
|
||||
of_node_put(smi_node);
|
||||
if (smi_pdev) {
|
||||
if (!platform_get_drvdata(smi_pdev))
|
||||
return -EPROBE_DEFER;
|
||||
larb->smi_common_dev = &smi_pdev->dev;
|
||||
link = device_link_add(dev, larb->smi_common_dev,
|
||||
DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS);
|
||||
if (!link) {
|
||||
dev_err(dev, "Unable to link smi-common dev\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
} else {
|
||||
dev_err(dev, "Failed to get the smi_common device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = mtk_smi_device_link_common(dev, &larb->smi_common_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
platform_set_drvdata(pdev, larb);
|
||||
return component_add(dev, &mtk_smi_larb_component_ops);
|
||||
ret = component_add(dev, &mtk_smi_larb_component_ops);
|
||||
if (ret)
|
||||
goto err_pm_disable;
|
||||
return 0;
|
||||
|
||||
err_pm_disable:
|
||||
pm_runtime_disable(dev);
|
||||
device_link_remove(dev, larb->smi_common_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mtk_smi_larb_remove(struct platform_device *pdev)
|
||||
@ -391,11 +479,9 @@ static int __maybe_unused mtk_smi_larb_resume(struct device *dev)
|
||||
const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
|
||||
int ret;
|
||||
|
||||
ret = mtk_smi_clk_enable(&larb->smi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to enable clock(%d).\n", ret);
|
||||
ret = clk_bulk_prepare_enable(larb->smi.clk_num, larb->smi.clks);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure the basic setting for this larb */
|
||||
larb_gen->config_port(dev);
|
||||
@ -407,7 +493,7 @@ static int __maybe_unused mtk_smi_larb_suspend(struct device *dev)
|
||||
{
|
||||
struct mtk_smi_larb *larb = dev_get_drvdata(dev);
|
||||
|
||||
mtk_smi_clk_disable(&larb->smi);
|
||||
clk_bulk_disable_unprepare(larb->smi.clk_num, larb->smi.clks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -427,64 +513,75 @@ static struct platform_driver mtk_smi_larb_driver = {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct mtk_smi_reg_pair mtk_smi_common_mt8195_init[SMI_COMMON_INIT_REGS_NR] = {
|
||||
{SMI_L1LEN, 0xb},
|
||||
{SMI_M4U_TH, 0xe100e10},
|
||||
{SMI_FIFO_TH1, 0x506090a},
|
||||
{SMI_FIFO_TH2, 0x506090a},
|
||||
{SMI_DCM, 0x4f1},
|
||||
{SMI_DUMMY, 0x1},
|
||||
};
|
||||
|
||||
static const struct mtk_smi_common_plat mtk_smi_common_gen1 = {
|
||||
.gen = MTK_SMI_GEN1,
|
||||
.type = MTK_SMI_GEN1,
|
||||
};
|
||||
|
||||
static const struct mtk_smi_common_plat mtk_smi_common_gen2 = {
|
||||
.gen = MTK_SMI_GEN2,
|
||||
.type = MTK_SMI_GEN2,
|
||||
};
|
||||
|
||||
static const struct mtk_smi_common_plat mtk_smi_common_mt6779 = {
|
||||
.gen = MTK_SMI_GEN2,
|
||||
.has_gals = true,
|
||||
.bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(4) |
|
||||
F_MMU1_LARB(5) | F_MMU1_LARB(6) | F_MMU1_LARB(7),
|
||||
.type = MTK_SMI_GEN2,
|
||||
.has_gals = true,
|
||||
.bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(4) |
|
||||
F_MMU1_LARB(5) | F_MMU1_LARB(6) | F_MMU1_LARB(7),
|
||||
};
|
||||
|
||||
static const struct mtk_smi_common_plat mtk_smi_common_mt8183 = {
|
||||
.gen = MTK_SMI_GEN2,
|
||||
.type = MTK_SMI_GEN2,
|
||||
.has_gals = true,
|
||||
.bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(5) |
|
||||
F_MMU1_LARB(7),
|
||||
};
|
||||
|
||||
static const struct mtk_smi_common_plat mtk_smi_common_mt8192 = {
|
||||
.gen = MTK_SMI_GEN2,
|
||||
.type = MTK_SMI_GEN2,
|
||||
.has_gals = true,
|
||||
.bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(5) |
|
||||
F_MMU1_LARB(6),
|
||||
};
|
||||
|
||||
static const struct mtk_smi_common_plat mtk_smi_common_mt8195_vdo = {
|
||||
.type = MTK_SMI_GEN2,
|
||||
.has_gals = true,
|
||||
.bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(3) | F_MMU1_LARB(5) |
|
||||
F_MMU1_LARB(7),
|
||||
.init = mtk_smi_common_mt8195_init,
|
||||
};
|
||||
|
||||
static const struct mtk_smi_common_plat mtk_smi_common_mt8195_vpp = {
|
||||
.type = MTK_SMI_GEN2,
|
||||
.has_gals = true,
|
||||
.bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(7),
|
||||
.init = mtk_smi_common_mt8195_init,
|
||||
};
|
||||
|
||||
static const struct mtk_smi_common_plat mtk_smi_sub_common_mt8195 = {
|
||||
.type = MTK_SMI_GEN2_SUB_COMM,
|
||||
.has_gals = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id mtk_smi_common_of_ids[] = {
|
||||
{
|
||||
.compatible = "mediatek,mt8173-smi-common",
|
||||
.data = &mtk_smi_common_gen2,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8167-smi-common",
|
||||
.data = &mtk_smi_common_gen2,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt2701-smi-common",
|
||||
.data = &mtk_smi_common_gen1,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt2712-smi-common",
|
||||
.data = &mtk_smi_common_gen2,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt6779-smi-common",
|
||||
.data = &mtk_smi_common_mt6779,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8183-smi-common",
|
||||
.data = &mtk_smi_common_mt8183,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8192-smi-common",
|
||||
.data = &mtk_smi_common_mt8192,
|
||||
},
|
||||
{.compatible = "mediatek,mt2701-smi-common", .data = &mtk_smi_common_gen1},
|
||||
{.compatible = "mediatek,mt2712-smi-common", .data = &mtk_smi_common_gen2},
|
||||
{.compatible = "mediatek,mt6779-smi-common", .data = &mtk_smi_common_mt6779},
|
||||
{.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,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},
|
||||
{.compatible = "mediatek,mt8195-smi-sub-common", .data = &mtk_smi_sub_common_mt8195},
|
||||
{}
|
||||
};
|
||||
|
||||
@ -492,8 +589,7 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mtk_smi *common;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
int ret, clk_required = MTK_SMI_COM_REQ_CLK_NR;
|
||||
|
||||
common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
|
||||
if (!common)
|
||||
@ -501,23 +597,15 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
|
||||
common->dev = dev;
|
||||
common->plat = of_device_get_match_data(dev);
|
||||
|
||||
common->clk_apb = devm_clk_get(dev, "apb");
|
||||
if (IS_ERR(common->clk_apb))
|
||||
return PTR_ERR(common->clk_apb);
|
||||
|
||||
common->clk_smi = devm_clk_get(dev, "smi");
|
||||
if (IS_ERR(common->clk_smi))
|
||||
return PTR_ERR(common->clk_smi);
|
||||
|
||||
if (common->plat->has_gals) {
|
||||
common->clk_gals0 = devm_clk_get(dev, "gals0");
|
||||
if (IS_ERR(common->clk_gals0))
|
||||
return PTR_ERR(common->clk_gals0);
|
||||
|
||||
common->clk_gals1 = devm_clk_get(dev, "gals1");
|
||||
if (IS_ERR(common->clk_gals1))
|
||||
return PTR_ERR(common->clk_gals1);
|
||||
if (common->plat->type == MTK_SMI_GEN2)
|
||||
clk_required = MTK_SMI_COM_GALS_REQ_CLK_NR;
|
||||
else if (common->plat->type == MTK_SMI_GEN2_SUB_COMM)
|
||||
clk_required = MTK_SMI_SUB_COM_GALS_REQ_CLK_NR;
|
||||
}
|
||||
ret = mtk_smi_dts_clk_init(dev, common, mtk_smi_common_clks, clk_required, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* for mtk smi gen 1, we need to get the ao(always on) base to config
|
||||
@ -525,9 +613,8 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
|
||||
* clock into emi clock domain, but for mtk smi gen2, there's no smi ao
|
||||
* base.
|
||||
*/
|
||||
if (common->plat->gen == MTK_SMI_GEN1) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
common->smi_ao_base = devm_ioremap_resource(dev, res);
|
||||
if (common->plat->type == MTK_SMI_GEN1) {
|
||||
common->smi_ao_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(common->smi_ao_base))
|
||||
return PTR_ERR(common->smi_ao_base);
|
||||
|
||||
@ -539,11 +626,18 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
common->base = devm_ioremap_resource(dev, res);
|
||||
common->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(common->base))
|
||||
return PTR_ERR(common->base);
|
||||
}
|
||||
|
||||
/* link its smi-common if this is smi-sub-common */
|
||||
if (common->plat->type == MTK_SMI_GEN2_SUB_COMM) {
|
||||
ret = mtk_smi_device_link_common(dev, &common->smi_common_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
platform_set_drvdata(pdev, common);
|
||||
return 0;
|
||||
@ -551,6 +645,10 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
|
||||
|
||||
static int mtk_smi_common_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mtk_smi *common = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
if (common->plat->type == MTK_SMI_GEN2_SUB_COMM)
|
||||
device_link_remove(&pdev->dev, common->smi_common_dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
@ -558,17 +656,21 @@ static int mtk_smi_common_remove(struct platform_device *pdev)
|
||||
static int __maybe_unused mtk_smi_common_resume(struct device *dev)
|
||||
{
|
||||
struct mtk_smi *common = dev_get_drvdata(dev);
|
||||
u32 bus_sel = common->plat->bus_sel;
|
||||
int ret;
|
||||
const struct mtk_smi_reg_pair *init = common->plat->init;
|
||||
u32 bus_sel = common->plat->bus_sel; /* default is 0 */
|
||||
int ret, i;
|
||||
|
||||
ret = mtk_smi_clk_enable(common);
|
||||
if (ret) {
|
||||
dev_err(common->dev, "Failed to enable clock(%d).\n", ret);
|
||||
ret = clk_bulk_prepare_enable(common->clk_num, common->clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (common->plat->gen == MTK_SMI_GEN2 && bus_sel)
|
||||
writel(bus_sel, common->base + SMI_BUS_SEL);
|
||||
if (common->plat->type != MTK_SMI_GEN2)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < SMI_COMMON_INIT_REGS_NR && init && init[i].offset; i++)
|
||||
writel_relaxed(init[i].value, common->base + init[i].offset);
|
||||
|
||||
writel(bus_sel, common->base + SMI_BUS_SEL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -576,7 +678,7 @@ static int __maybe_unused mtk_smi_common_suspend(struct device *dev)
|
||||
{
|
||||
struct mtk_smi *common = dev_get_drvdata(dev);
|
||||
|
||||
mtk_smi_clk_disable(common);
|
||||
clk_bulk_disable_unprepare(common->clk_num, common->clks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -298,3 +298,90 @@ default_timings:
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(of_lpddr3_get_ddr_timings);
|
||||
|
||||
/**
|
||||
* of_lpddr2_get_info() - extracts information about the lpddr2 chip.
|
||||
* @np: Pointer to device tree node containing lpddr2 info
|
||||
* @dev: Device requesting info
|
||||
*
|
||||
* Populates lpddr2_info structure by extracting data from device
|
||||
* tree node. Returns pointer to populated structure. If error
|
||||
* happened while populating, returns NULL. If property is missing
|
||||
* in a device-tree, then the corresponding value is set to -ENOENT.
|
||||
*/
|
||||
const struct lpddr2_info
|
||||
*of_lpddr2_get_info(struct device_node *np, struct device *dev)
|
||||
{
|
||||
struct lpddr2_info *ret_info, info = {};
|
||||
struct property *prop;
|
||||
const char *cp;
|
||||
int err;
|
||||
|
||||
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, "io-width", &info.io_width);
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
info.io_width = 32 / info.io_width - 1;
|
||||
|
||||
err = of_property_read_u32(np, "density", &info.density);
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
info.density = ffs(info.density) - 7;
|
||||
|
||||
if (of_device_is_compatible(np, "jedec,lpddr2-s4"))
|
||||
info.arch_type = LPDDR2_TYPE_S4;
|
||||
else if (of_device_is_compatible(np, "jedec,lpddr2-s2"))
|
||||
info.arch_type = LPDDR2_TYPE_S2;
|
||||
else if (of_device_is_compatible(np, "jedec,lpddr2-nvm"))
|
||||
info.arch_type = LPDDR2_TYPE_NVM;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
prop = of_find_property(np, "compatible", NULL);
|
||||
for (cp = of_prop_next_string(prop, NULL); cp;
|
||||
cp = of_prop_next_string(prop, cp)) {
|
||||
|
||||
#define OF_LPDDR2_VENDOR_CMP(compat, ID) \
|
||||
if (!of_compat_cmp(cp, compat ",", strlen(compat ","))) { \
|
||||
info.manufacturer_id = LPDDR2_MANID_##ID; \
|
||||
break; \
|
||||
}
|
||||
|
||||
OF_LPDDR2_VENDOR_CMP("samsung", SAMSUNG)
|
||||
OF_LPDDR2_VENDOR_CMP("qimonda", QIMONDA)
|
||||
OF_LPDDR2_VENDOR_CMP("elpida", ELPIDA)
|
||||
OF_LPDDR2_VENDOR_CMP("etron", ETRON)
|
||||
OF_LPDDR2_VENDOR_CMP("nanya", NANYA)
|
||||
OF_LPDDR2_VENDOR_CMP("hynix", HYNIX)
|
||||
OF_LPDDR2_VENDOR_CMP("mosel", MOSEL)
|
||||
OF_LPDDR2_VENDOR_CMP("winbond", WINBOND)
|
||||
OF_LPDDR2_VENDOR_CMP("esmt", ESMT)
|
||||
OF_LPDDR2_VENDOR_CMP("spansion", SPANSION)
|
||||
OF_LPDDR2_VENDOR_CMP("sst", SST)
|
||||
OF_LPDDR2_VENDOR_CMP("zmos", ZMOS)
|
||||
OF_LPDDR2_VENDOR_CMP("intel", INTEL)
|
||||
OF_LPDDR2_VENDOR_CMP("numonyx", NUMONYX)
|
||||
OF_LPDDR2_VENDOR_CMP("micron", MICRON)
|
||||
|
||||
#undef OF_LPDDR2_VENDOR_CMP
|
||||
}
|
||||
|
||||
if (!info.manufacturer_id)
|
||||
info.manufacturer_id = -ENOENT;
|
||||
|
||||
ret_info = devm_kzalloc(dev, sizeof(*ret_info), GFP_KERNEL);
|
||||
if (ret_info)
|
||||
*ret_info = info;
|
||||
|
||||
return ret_info;
|
||||
}
|
||||
EXPORT_SYMBOL(of_lpddr2_get_info);
|
||||
|
@ -20,6 +20,9 @@ const struct lpddr3_min_tck *of_lpddr3_get_min_tck(struct device_node *np,
|
||||
const struct lpddr3_timings *
|
||||
of_lpddr3_get_ddr_timings(struct device_node *np_ddr,
|
||||
struct device *dev, u32 device_type, u32 *nr_frequencies);
|
||||
|
||||
const struct lpddr2_info *of_lpddr2_get_info(struct device_node *np,
|
||||
struct device *dev);
|
||||
#else
|
||||
static inline const struct lpddr2_min_tck
|
||||
*of_get_min_tck(struct device_node *np, struct device *dev)
|
||||
@ -46,6 +49,12 @@ static inline const struct lpddr3_timings
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline const struct lpddr2_info
|
||||
*of_lpddr2_get_info(struct device_node *np, struct device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_OF && CONFIG_DDR */
|
||||
|
||||
#endif /* __LINUX_MEMORY_OF_REG_ */
|
||||
|
@ -160,10 +160,61 @@ static const struct regmap_access_table rpcif_volatile_table = {
|
||||
.n_yes_ranges = ARRAY_SIZE(rpcif_volatile_ranges),
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Custom accessor functions to ensure SMRDR0 and SMWDR0 are always accessed
|
||||
* with proper width. Requires SMENR_SPIDE to be correctly set before!
|
||||
*/
|
||||
static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct rpcif *rpc = context;
|
||||
|
||||
if (reg == RPCIF_SMRDR0 || reg == RPCIF_SMWDR0) {
|
||||
u32 spide = readl(rpc->base + RPCIF_SMENR) & RPCIF_SMENR_SPIDE(0xF);
|
||||
|
||||
if (spide == 0x8) {
|
||||
*val = readb(rpc->base + reg);
|
||||
return 0;
|
||||
} else if (spide == 0xC) {
|
||||
*val = readw(rpc->base + reg);
|
||||
return 0;
|
||||
} else if (spide != 0xF) {
|
||||
return -EILSEQ;
|
||||
}
|
||||
}
|
||||
|
||||
*val = readl(rpc->base + reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpcif_reg_write(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct rpcif *rpc = context;
|
||||
|
||||
if (reg == RPCIF_SMRDR0 || reg == RPCIF_SMWDR0) {
|
||||
u32 spide = readl(rpc->base + RPCIF_SMENR) & RPCIF_SMENR_SPIDE(0xF);
|
||||
|
||||
if (spide == 0x8) {
|
||||
writeb(val, rpc->base + reg);
|
||||
return 0;
|
||||
} else if (spide == 0xC) {
|
||||
writew(val, rpc->base + reg);
|
||||
return 0;
|
||||
} else if (spide != 0xF) {
|
||||
return -EILSEQ;
|
||||
}
|
||||
}
|
||||
|
||||
writel(val, rpc->base + reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config rpcif_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.reg_read = rpcif_reg_read,
|
||||
.reg_write = rpcif_reg_write,
|
||||
.fast_io = true,
|
||||
.max_register = RPCIF_PHYINT,
|
||||
.volatile_table = &rpcif_volatile_table,
|
||||
@ -173,17 +224,15 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
|
||||
rpc->dev = dev;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
rpc->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(rpc->base))
|
||||
return PTR_ERR(rpc->base);
|
||||
|
||||
rpc->regmap = devm_regmap_init_mmio(&pdev->dev, base,
|
||||
&rpcif_regmap_config);
|
||||
rpc->regmap = devm_regmap_init(&pdev->dev, NULL, rpc, &rpcif_regmap_config);
|
||||
if (IS_ERR(rpc->regmap)) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to init regmap for rpcif, error %ld\n",
|
||||
@ -354,20 +403,16 @@ void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs,
|
||||
nbytes = op->data.nbytes;
|
||||
rpc->xferlen = nbytes;
|
||||
|
||||
rpc->enable |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes)) |
|
||||
RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth));
|
||||
rpc->enable |= RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth));
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(rpcif_prepare);
|
||||
|
||||
int rpcif_manual_xfer(struct rpcif *rpc)
|
||||
{
|
||||
u32 smenr, smcr, pos = 0, max = 4;
|
||||
u32 smenr, smcr, pos = 0, max = rpc->bus_size == 2 ? 8 : 4;
|
||||
int ret = 0;
|
||||
|
||||
if (rpc->bus_size == 2)
|
||||
max = 8;
|
||||
|
||||
pm_runtime_get_sync(rpc->dev);
|
||||
|
||||
regmap_update_bits(rpc->regmap, RPCIF_PHYCNT,
|
||||
@ -378,37 +423,36 @@ int rpcif_manual_xfer(struct rpcif *rpc)
|
||||
regmap_write(rpc->regmap, RPCIF_SMOPR, rpc->option);
|
||||
regmap_write(rpc->regmap, RPCIF_SMDMCR, rpc->dummy);
|
||||
regmap_write(rpc->regmap, RPCIF_SMDRENR, rpc->ddr);
|
||||
regmap_write(rpc->regmap, RPCIF_SMADR, rpc->smadr);
|
||||
smenr = rpc->enable;
|
||||
|
||||
switch (rpc->dir) {
|
||||
case RPCIF_DATA_OUT:
|
||||
while (pos < rpc->xferlen) {
|
||||
u32 nbytes = rpc->xferlen - pos;
|
||||
u32 data[2];
|
||||
u32 bytes_left = rpc->xferlen - pos;
|
||||
u32 nbytes, data[2];
|
||||
|
||||
smcr = rpc->smcr | RPCIF_SMCR_SPIE;
|
||||
if (nbytes > max) {
|
||||
nbytes = max;
|
||||
|
||||
/* nbytes may only be 1, 2, 4, or 8 */
|
||||
nbytes = bytes_left >= max ? max : (1 << ilog2(bytes_left));
|
||||
if (bytes_left > nbytes)
|
||||
smcr |= RPCIF_SMCR_SSLKP;
|
||||
}
|
||||
|
||||
smenr |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes));
|
||||
regmap_write(rpc->regmap, RPCIF_SMENR, smenr);
|
||||
|
||||
memcpy(data, rpc->buffer + pos, nbytes);
|
||||
if (nbytes > 4) {
|
||||
if (nbytes == 8) {
|
||||
regmap_write(rpc->regmap, RPCIF_SMWDR1,
|
||||
data[0]);
|
||||
regmap_write(rpc->regmap, RPCIF_SMWDR0,
|
||||
data[1]);
|
||||
} else if (nbytes > 2) {
|
||||
} else {
|
||||
regmap_write(rpc->regmap, RPCIF_SMWDR0,
|
||||
data[0]);
|
||||
} else {
|
||||
regmap_write(rpc->regmap, RPCIF_SMWDR0,
|
||||
data[0] << 16);
|
||||
}
|
||||
|
||||
regmap_write(rpc->regmap, RPCIF_SMADR,
|
||||
rpc->smadr + pos);
|
||||
regmap_write(rpc->regmap, RPCIF_SMENR, smenr);
|
||||
regmap_write(rpc->regmap, RPCIF_SMCR, smcr);
|
||||
ret = wait_msg_xfer_end(rpc);
|
||||
if (ret)
|
||||
@ -448,14 +492,16 @@ int rpcif_manual_xfer(struct rpcif *rpc)
|
||||
break;
|
||||
}
|
||||
while (pos < rpc->xferlen) {
|
||||
u32 nbytes = rpc->xferlen - pos;
|
||||
u32 data[2];
|
||||
u32 bytes_left = rpc->xferlen - pos;
|
||||
u32 nbytes, data[2];
|
||||
|
||||
if (nbytes > max)
|
||||
nbytes = max;
|
||||
/* nbytes may only be 1, 2, 4, or 8 */
|
||||
nbytes = bytes_left >= max ? max : (1 << ilog2(bytes_left));
|
||||
|
||||
regmap_write(rpc->regmap, RPCIF_SMADR,
|
||||
rpc->smadr + pos);
|
||||
smenr &= ~RPCIF_SMENR_SPIDE(0xF);
|
||||
smenr |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes));
|
||||
regmap_write(rpc->regmap, RPCIF_SMENR, smenr);
|
||||
regmap_write(rpc->regmap, RPCIF_SMCR,
|
||||
rpc->smcr | RPCIF_SMCR_SPIE);
|
||||
@ -463,18 +509,14 @@ int rpcif_manual_xfer(struct rpcif *rpc)
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
if (nbytes > 4) {
|
||||
if (nbytes == 8) {
|
||||
regmap_read(rpc->regmap, RPCIF_SMRDR1,
|
||||
&data[0]);
|
||||
regmap_read(rpc->regmap, RPCIF_SMRDR0,
|
||||
&data[1]);
|
||||
} else if (nbytes > 2) {
|
||||
} else {
|
||||
regmap_read(rpc->regmap, RPCIF_SMRDR0,
|
||||
&data[0]);
|
||||
} else {
|
||||
regmap_read(rpc->regmap, RPCIF_SMRDR0,
|
||||
&data[0]);
|
||||
data[0] >>= 16;
|
||||
}
|
||||
memcpy(rpc->buffer + pos, data, nbytes);
|
||||
|
||||
@ -502,6 +544,48 @@ err_out:
|
||||
}
|
||||
EXPORT_SYMBOL(rpcif_manual_xfer);
|
||||
|
||||
static void memcpy_fromio_readw(void *to,
|
||||
const void __iomem *from,
|
||||
size_t count)
|
||||
{
|
||||
const int maxw = (IS_ENABLED(CONFIG_64BIT)) ? 8 : 4;
|
||||
u8 buf[2];
|
||||
|
||||
if (count && ((unsigned long)from & 1)) {
|
||||
*(u16 *)buf = __raw_readw((void __iomem *)((unsigned long)from & ~1));
|
||||
*(u8 *)to = buf[1];
|
||||
from++;
|
||||
to++;
|
||||
count--;
|
||||
}
|
||||
while (count >= 2 && !IS_ALIGNED((unsigned long)from, maxw)) {
|
||||
*(u16 *)to = __raw_readw(from);
|
||||
from += 2;
|
||||
to += 2;
|
||||
count -= 2;
|
||||
}
|
||||
while (count >= maxw) {
|
||||
#ifdef CONFIG_64BIT
|
||||
*(u64 *)to = __raw_readq(from);
|
||||
#else
|
||||
*(u32 *)to = __raw_readl(from);
|
||||
#endif
|
||||
from += maxw;
|
||||
to += maxw;
|
||||
count -= maxw;
|
||||
}
|
||||
while (count >= 2) {
|
||||
*(u16 *)to = __raw_readw(from);
|
||||
from += 2;
|
||||
to += 2;
|
||||
count -= 2;
|
||||
}
|
||||
if (count) {
|
||||
*(u16 *)buf = __raw_readw(from);
|
||||
*(u8 *)to = buf[0];
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf)
|
||||
{
|
||||
loff_t from = offs & (RPCIF_DIRMAP_SIZE - 1);
|
||||
@ -523,7 +607,10 @@ ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf)
|
||||
regmap_write(rpc->regmap, RPCIF_DRDMCR, rpc->dummy);
|
||||
regmap_write(rpc->regmap, RPCIF_DRDRENR, rpc->ddr);
|
||||
|
||||
memcpy_fromio(buf, rpc->dirmap + from, len);
|
||||
if (rpc->bus_size == 2)
|
||||
memcpy_fromio_readw(buf, rpc->dirmap + from, len);
|
||||
else
|
||||
memcpy_fromio(buf, rpc->dirmap + from, len);
|
||||
|
||||
pm_runtime_put(rpc->dev);
|
||||
|
||||
|
@ -14,11 +14,12 @@ config EXYNOS5422_DMC
|
||||
depends on DEVFREQ_GOV_SIMPLE_ONDEMAND
|
||||
depends on (PM_DEVFREQ && PM_DEVFREQ_EVENT)
|
||||
help
|
||||
This adds driver for Exynos5422 DMC (Dynamic Memory Controller).
|
||||
The driver provides support for Dynamic Voltage and Frequency Scaling in
|
||||
DMC and DRAM. It also supports changing timings of DRAM running with
|
||||
different frequency. The timings are calculated based on DT memory
|
||||
information.
|
||||
This adds driver for Samsung Exynos5422 SoC DMC (Dynamic Memory
|
||||
Controller). The driver provides support for Dynamic Voltage and
|
||||
Frequency Scaling in DMC and DRAM. It also supports changing timings
|
||||
of DRAM running with different frequency. The timings are calculated
|
||||
based on DT memory information.
|
||||
If unsure, say Y on devices with Samsung Exynos SoCs.
|
||||
|
||||
config EXYNOS_SROM
|
||||
bool "Exynos SROM controller driver" if COMPILE_TEST
|
||||
@ -29,6 +30,6 @@ config EXYNOS_SROM
|
||||
during suspend. If however appropriate device tree configuration
|
||||
is provided, the driver enables support for external memory
|
||||
or external devices.
|
||||
If unsure, say Y on devices with Samsung Exynos SocS.
|
||||
If unsure, say Y on devices with Samsung Exynos SoCs.
|
||||
|
||||
endif
|
||||
|
@ -16,6 +16,7 @@ config TEGRA20_EMC
|
||||
depends on ARCH_TEGRA_2x_SOC || COMPILE_TEST
|
||||
select DEVFREQ_GOV_SIMPLE_ONDEMAND
|
||||
select PM_DEVFREQ
|
||||
select DDR
|
||||
help
|
||||
This driver is for the External Memory Controller (EMC) found on
|
||||
Tegra20 chips. The EMC controls the external DRAM on the board.
|
||||
|
@ -87,11 +87,9 @@ struct tegra_mc *devm_tegra_memory_controller_get(struct device *dev)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
err = devm_add_action(dev, tegra_mc_devm_action_put_device, mc);
|
||||
if (err) {
|
||||
put_device(mc->dev);
|
||||
err = devm_add_action_or_reset(dev, tegra_mc_devm_action_put_device, mc);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
return mc;
|
||||
}
|
||||
@ -706,15 +704,6 @@ static int tegra_mc_interconnect_setup(struct tegra_mc *mc)
|
||||
goto remove_nodes;
|
||||
}
|
||||
|
||||
/*
|
||||
* MC driver is registered too early, so early that generic driver
|
||||
* syncing doesn't work for the MC. But it doesn't really matter
|
||||
* since syncing works for the EMC drivers, hence we can sync the
|
||||
* MC driver by ourselves and then EMC will complete syncing of
|
||||
* the whole ICC state.
|
||||
*/
|
||||
icc_sync_state(mc->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
remove_nodes:
|
||||
@ -835,6 +824,15 @@ static int __maybe_unused tegra_mc_resume(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_mc_sync_state(struct device *dev)
|
||||
{
|
||||
struct tegra_mc *mc = dev_get_drvdata(dev);
|
||||
|
||||
/* check whether ICC provider is registered */
|
||||
if (mc->provider.dev == dev)
|
||||
icc_sync_state(dev);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops tegra_mc_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(tegra_mc_suspend, tegra_mc_resume)
|
||||
};
|
||||
@ -845,6 +843,7 @@ static struct platform_driver tegra_mc_driver = {
|
||||
.of_match_table = tegra_mc_of_match,
|
||||
.pm = &tegra_mc_pm_ops,
|
||||
.suppress_bind_attrs = true,
|
||||
.sync_state = tegra_mc_sync_state,
|
||||
},
|
||||
.prevent_deferred_probe = true,
|
||||
.probe = tegra_mc_probe,
|
||||
|
@ -197,6 +197,11 @@ static int tegra186_emc_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "failed to EMC DVFS pairs: %d\n", err);
|
||||
goto put_bpmp;
|
||||
}
|
||||
if (msg.rx.ret < 0) {
|
||||
err = -EINVAL;
|
||||
dev_err(&pdev->dev, "EMC DVFS MRQ failed: %d (BPMP error code)\n", msg.rx.ret);
|
||||
goto put_bpmp;
|
||||
}
|
||||
|
||||
emc->debugfs.min_rate = ULONG_MAX;
|
||||
emc->debugfs.max_rate = 0;
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Author: Dmitry Osipenko <digetx@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
#include <linux/debugfs.h>
|
||||
@ -27,11 +28,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_0 0x010
|
||||
#define EMC_TIMING_CONTROL 0x028
|
||||
#define EMC_RC 0x02c
|
||||
#define EMC_RFC 0x030
|
||||
@ -68,6 +73,7 @@
|
||||
#define EMC_QUSE_EXTRA 0x0ac
|
||||
#define EMC_ODT_WRITE 0x0b0
|
||||
#define EMC_ODT_READ 0x0b4
|
||||
#define EMC_MRR 0x0ec
|
||||
#define EMC_FBIO_CFG5 0x104
|
||||
#define EMC_FBIO_CFG6 0x114
|
||||
#define EMC_STAT_CONTROL 0x160
|
||||
@ -94,6 +100,7 @@
|
||||
|
||||
#define EMC_REFRESH_OVERFLOW_INT BIT(3)
|
||||
#define EMC_CLKCHANGE_COMPLETE_INT BIT(4)
|
||||
#define EMC_MRR_DIVLD_INT BIT(5)
|
||||
|
||||
#define EMC_DBG_READ_MUX_ASSEMBLY BIT(0)
|
||||
#define EMC_DBG_WRITE_MUX_ACTIVE BIT(1)
|
||||
@ -102,11 +109,25 @@
|
||||
#define EMC_DBG_CFG_PRIORITY BIT(24)
|
||||
|
||||
#define EMC_FBIO_CFG5_DRAM_WIDTH_X16 BIT(4)
|
||||
#define EMC_FBIO_CFG5_DRAM_TYPE GENMASK(1, 0)
|
||||
|
||||
#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_0_EMEM_NUMDEV GENMASK(25, 24)
|
||||
|
||||
#define EMC_PWR_GATHER_CLEAR (1 << 8)
|
||||
#define EMC_PWR_GATHER_DISABLE (2 << 8)
|
||||
#define EMC_PWR_GATHER_ENABLE (3 << 8)
|
||||
|
||||
enum emc_dram_type {
|
||||
DRAM_TYPE_RESERVED,
|
||||
DRAM_TYPE_DDR1,
|
||||
DRAM_TYPE_LPDDR2,
|
||||
DRAM_TYPE_DDR2,
|
||||
};
|
||||
|
||||
static const u16 emc_timing_registers[] = {
|
||||
EMC_RC,
|
||||
EMC_RFC,
|
||||
@ -201,6 +222,14 @@ struct tegra_emc {
|
||||
struct mutex rate_lock;
|
||||
|
||||
struct devfreq_simple_ondemand_data ondemand_data;
|
||||
|
||||
/* memory chip identity information */
|
||||
union lpddr2_basic_config4 basic_conf4;
|
||||
unsigned int manufacturer_id;
|
||||
unsigned int revision_id1;
|
||||
unsigned int revision_id2;
|
||||
|
||||
bool mrr_error;
|
||||
};
|
||||
|
||||
static irqreturn_t tegra_emc_isr(int irq, void *data)
|
||||
@ -397,15 +426,19 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
|
||||
if (!emc->timings)
|
||||
return -ENOMEM;
|
||||
|
||||
emc->num_timings = child_count;
|
||||
timing = emc->timings;
|
||||
|
||||
for_each_child_of_node(node, child) {
|
||||
if (of_node_name_eq(child, "lpddr2"))
|
||||
continue;
|
||||
|
||||
err = load_one_timing_from_dt(emc, timing++, child);
|
||||
if (err) {
|
||||
of_node_put(child);
|
||||
return err;
|
||||
}
|
||||
|
||||
emc->num_timings++;
|
||||
}
|
||||
|
||||
sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings,
|
||||
@ -422,12 +455,18 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
|
||||
}
|
||||
|
||||
static struct device_node *
|
||||
tegra_emc_find_node_by_ram_code(struct device *dev)
|
||||
tegra_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;
|
||||
@ -442,8 +481,49 @@ tegra_emc_find_node_by_ram_code(struct device *dev)
|
||||
np = of_find_node_by_name(np, "emc-tables")) {
|
||||
err = of_property_read_u32(np, "nvidia,ram-code", &value);
|
||||
if (err || value != ram_code) {
|
||||
of_node_put(np);
|
||||
continue;
|
||||
struct device_node *lpddr2_np;
|
||||
bool cfg_mismatches = false;
|
||||
|
||||
lpddr2_np = of_find_node_by_name(np, "lpddr2");
|
||||
if (lpddr2_np) {
|
||||
const struct lpddr2_info *info;
|
||||
|
||||
info = of_lpddr2_get_info(lpddr2_np, dev);
|
||||
if (info) {
|
||||
if (info->manufacturer_id >= 0 &&
|
||||
info->manufacturer_id != emc->manufacturer_id)
|
||||
cfg_mismatches = true;
|
||||
|
||||
if (info->revision_id1 >= 0 &&
|
||||
info->revision_id1 != emc->revision_id1)
|
||||
cfg_mismatches = true;
|
||||
|
||||
if (info->revision_id2 >= 0 &&
|
||||
info->revision_id2 != emc->revision_id2)
|
||||
cfg_mismatches = true;
|
||||
|
||||
if (info->density != emc->basic_conf4.density)
|
||||
cfg_mismatches = true;
|
||||
|
||||
if (info->io_width != emc->basic_conf4.io_width)
|
||||
cfg_mismatches = true;
|
||||
|
||||
if (info->arch_type != emc->basic_conf4.arch_type)
|
||||
cfg_mismatches = true;
|
||||
} else {
|
||||
dev_err(dev, "failed to parse %pOF\n", lpddr2_np);
|
||||
cfg_mismatches = true;
|
||||
}
|
||||
|
||||
of_node_put(lpddr2_np);
|
||||
} else {
|
||||
cfg_mismatches = true;
|
||||
}
|
||||
|
||||
if (cfg_mismatches) {
|
||||
of_node_put(np);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return np;
|
||||
@ -455,10 +535,72 @@ tegra_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;
|
||||
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,
|
||||
bool print_out)
|
||||
{
|
||||
/* these registers are standard for all LPDDR JEDEC memory chips */
|
||||
emc_read_lpddr_mode_register(emc, emem_dev, 5, &emc->manufacturer_id);
|
||||
emc_read_lpddr_mode_register(emc, emem_dev, 6, &emc->revision_id1);
|
||||
emc_read_lpddr_mode_register(emc, emem_dev, 7, &emc->revision_id2);
|
||||
emc_read_lpddr_mode_register(emc, emem_dev, 8, &emc->basic_conf4.value);
|
||||
|
||||
if (!print_out)
|
||||
return;
|
||||
|
||||
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, emc->manufacturer_id,
|
||||
lpddr2_jedec_manufacturer(emc->manufacturer_id),
|
||||
emc->revision_id1, emc->revision_id2,
|
||||
4 >> emc->basic_conf4.arch_type,
|
||||
64 << emc->basic_conf4.density,
|
||||
32 >> emc->basic_conf4.io_width);
|
||||
}
|
||||
|
||||
static int emc_setup_hw(struct tegra_emc *emc)
|
||||
{
|
||||
u32 emc_cfg, emc_dbg, emc_fbio, emc_adr_cfg;
|
||||
u32 intmask = EMC_REFRESH_OVERFLOW_INT;
|
||||
u32 emc_cfg, emc_dbg, emc_fbio;
|
||||
static bool print_sdram_info_once;
|
||||
enum emc_dram_type dram_type;
|
||||
const char *dram_type_str;
|
||||
unsigned int emem_numdev;
|
||||
|
||||
emc_cfg = readl_relaxed(emc->regs + EMC_CFG_2);
|
||||
|
||||
@ -496,7 +638,36 @@ static int emc_setup_hw(struct tegra_emc *emc)
|
||||
else
|
||||
emc->dram_bus_width = 32;
|
||||
|
||||
dev_info_once(emc->dev, "%ubit DRAM bus\n", emc->dram_bus_width);
|
||||
dram_type = FIELD_GET(EMC_FBIO_CFG5_DRAM_TYPE, emc_fbio);
|
||||
|
||||
switch (dram_type) {
|
||||
case DRAM_TYPE_RESERVED:
|
||||
dram_type_str = "INVALID";
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
emc_adr_cfg = readl_relaxed(emc->regs + EMC_ADR_CFG_0);
|
||||
emem_numdev = FIELD_GET(EMC_ADR_CFG_0_EMEM_NUMDEV, emc_adr_cfg) + 1;
|
||||
|
||||
dev_info_once(emc->dev, "%ubit DRAM bus, %u %s %s attached\n",
|
||||
emc->dram_bus_width, emem_numdev, dram_type_str,
|
||||
emem_numdev == 2 ? "devices" : "device");
|
||||
|
||||
if (dram_type == DRAM_TYPE_LPDDR2) {
|
||||
while (emem_numdev--)
|
||||
emc_read_lpddr_sdram_info(emc, emem_numdev,
|
||||
!print_sdram_info_once);
|
||||
print_sdram_info_once = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1049,14 +1220,6 @@ static int tegra_emc_probe(struct platform_device *pdev)
|
||||
emc->clk_nb.notifier_call = tegra_emc_clk_change_notify;
|
||||
emc->dev = &pdev->dev;
|
||||
|
||||
np = tegra_emc_find_node_by_ram_code(&pdev->dev);
|
||||
if (np) {
|
||||
err = tegra_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);
|
||||
@ -1065,6 +1228,14 @@ static int tegra_emc_probe(struct platform_device *pdev)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
np = tegra_emc_find_node_by_ram_code(emc);
|
||||
if (np) {
|
||||
err = tegra_emc_load_timings_from_dt(emc, np);
|
||||
of_node_put(np);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = devm_request_irq(&pdev->dev, irq, tegra_emc_isr, 0,
|
||||
dev_name(&pdev->dev), emc);
|
||||
if (err) {
|
||||
@ -1117,4 +1288,5 @@ module_platform_driver(tegra_emc_driver);
|
||||
|
||||
MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
|
||||
MODULE_DESCRIPTION("NVIDIA Tegra20 EMC driver");
|
||||
MODULE_SOFTDEP("pre: governor_simpleondemand");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -478,7 +478,7 @@ static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type,
|
||||
static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc)
|
||||
{
|
||||
u32 emc_cfg, emc_cfg_o, emc_cfg_update, del, value;
|
||||
u32 list[] = {
|
||||
static const u32 list[] = {
|
||||
EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0,
|
||||
EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1,
|
||||
EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2,
|
||||
|
@ -1662,7 +1662,7 @@ static int tegra210_emc_debug_min_rate_set(void *data, u64 rate)
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(tegra210_emc_debug_min_rate_fops,
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(tegra210_emc_debug_min_rate_fops,
|
||||
tegra210_emc_debug_min_rate_get,
|
||||
tegra210_emc_debug_min_rate_set, "%llu\n");
|
||||
|
||||
@ -1692,7 +1692,7 @@ static int tegra210_emc_debug_max_rate_set(void *data, u64 rate)
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(tegra210_emc_debug_max_rate_fops,
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(tegra210_emc_debug_max_rate_fops,
|
||||
tegra210_emc_debug_max_rate_get,
|
||||
tegra210_emc_debug_max_rate_set, "%llu\n");
|
||||
|
||||
@ -1723,7 +1723,7 @@ static int tegra210_emc_debug_temperature_set(void *data, u64 temperature)
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(tegra210_emc_debug_temperature_fops,
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(tegra210_emc_debug_temperature_fops,
|
||||
tegra210_emc_debug_temperature_get,
|
||||
tegra210_emc_debug_temperature_set, "%llu\n");
|
||||
|
||||
|
@ -1289,7 +1289,7 @@ static int tegra_emc_debug_min_rate_set(void *data, u64 rate)
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(tegra_emc_debug_min_rate_fops,
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(tegra_emc_debug_min_rate_fops,
|
||||
tegra_emc_debug_min_rate_get,
|
||||
tegra_emc_debug_min_rate_set, "%llu\n");
|
||||
|
||||
@ -1319,7 +1319,7 @@ static int tegra_emc_debug_max_rate_set(void *data, u64 rate)
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(tegra_emc_debug_max_rate_fops,
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(tegra_emc_debug_max_rate_fops,
|
||||
tegra_emc_debug_max_rate_get,
|
||||
tegra_emc_debug_max_rate_set, "%llu\n");
|
||||
|
||||
|
@ -505,6 +505,7 @@ EXPORT_SYMBOL_GPL(of_platform_default_populate);
|
||||
static const struct of_device_id reserved_mem_matches[] = {
|
||||
{ .compatible = "qcom,rmtfs-mem" },
|
||||
{ .compatible = "qcom,cmd-db" },
|
||||
{ .compatible = "qcom,smem" },
|
||||
{ .compatible = "ramoops" },
|
||||
{ .compatible = "nvmem-rmem" },
|
||||
{}
|
||||
|
@ -58,7 +58,7 @@ config RESET_BRCMSTB
|
||||
a SUN_TOP_CTRL_SW_INIT style controller.
|
||||
|
||||
config RESET_BRCMSTB_RESCAL
|
||||
bool "Broadcom STB RESCAL reset controller"
|
||||
tristate "Broadcom STB RESCAL reset controller"
|
||||
depends on HAS_IOMEM
|
||||
depends on ARCH_BRCMSTB || COMPILE_TEST
|
||||
default ARCH_BRCMSTB
|
||||
@ -116,7 +116,7 @@ config RESET_LPC18XX
|
||||
|
||||
config RESET_MCHP_SPARX5
|
||||
bool "Microchip Sparx5 reset driver"
|
||||
depends on ARCH_SPARX5 || COMPILE_TEST
|
||||
depends on ARCH_SPARX5 || SOC_LAN966 || COMPILE_TEST
|
||||
default y if SPARX5_SWITCH
|
||||
select MFD_SYSCON
|
||||
help
|
||||
|
@ -13,15 +13,18 @@
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset-controller.h>
|
||||
|
||||
#define PROTECT_REG 0x84
|
||||
#define PROTECT_BIT BIT(10)
|
||||
#define SOFT_RESET_REG 0x00
|
||||
#define SOFT_RESET_BIT BIT(1)
|
||||
struct reset_props {
|
||||
u32 protect_reg;
|
||||
u32 protect_bit;
|
||||
u32 reset_reg;
|
||||
u32 reset_bit;
|
||||
};
|
||||
|
||||
struct mchp_reset_context {
|
||||
struct regmap *cpu_ctrl;
|
||||
struct regmap *gcb_ctrl;
|
||||
struct reset_controller_dev rcdev;
|
||||
const struct reset_props *props;
|
||||
};
|
||||
|
||||
static struct regmap_config sparx5_reset_regmap_config = {
|
||||
@ -38,14 +41,16 @@ static int sparx5_switch_reset(struct reset_controller_dev *rcdev,
|
||||
u32 val;
|
||||
|
||||
/* Make sure the core is PROTECTED from reset */
|
||||
regmap_update_bits(ctx->cpu_ctrl, PROTECT_REG, PROTECT_BIT, PROTECT_BIT);
|
||||
regmap_update_bits(ctx->cpu_ctrl, ctx->props->protect_reg,
|
||||
ctx->props->protect_bit, ctx->props->protect_bit);
|
||||
|
||||
/* Start soft reset */
|
||||
regmap_write(ctx->gcb_ctrl, SOFT_RESET_REG, SOFT_RESET_BIT);
|
||||
regmap_write(ctx->gcb_ctrl, ctx->props->reset_reg,
|
||||
ctx->props->reset_bit);
|
||||
|
||||
/* Wait for soft reset done */
|
||||
return regmap_read_poll_timeout(ctx->gcb_ctrl, SOFT_RESET_REG, val,
|
||||
(val & SOFT_RESET_BIT) == 0,
|
||||
return regmap_read_poll_timeout(ctx->gcb_ctrl, ctx->props->reset_reg, val,
|
||||
(val & ctx->props->reset_bit) == 0,
|
||||
1, 100);
|
||||
}
|
||||
|
||||
@ -115,13 +120,32 @@ static int mchp_sparx5_reset_probe(struct platform_device *pdev)
|
||||
ctx->rcdev.nr_resets = 1;
|
||||
ctx->rcdev.ops = &sparx5_reset_ops;
|
||||
ctx->rcdev.of_node = dn;
|
||||
ctx->props = device_get_match_data(&pdev->dev);
|
||||
|
||||
return devm_reset_controller_register(&pdev->dev, &ctx->rcdev);
|
||||
}
|
||||
|
||||
static const struct reset_props reset_props_sparx5 = {
|
||||
.protect_reg = 0x84,
|
||||
.protect_bit = BIT(10),
|
||||
.reset_reg = 0x0,
|
||||
.reset_bit = BIT(1),
|
||||
};
|
||||
|
||||
static const struct reset_props reset_props_lan966x = {
|
||||
.protect_reg = 0x88,
|
||||
.protect_bit = BIT(5),
|
||||
.reset_reg = 0x0,
|
||||
.reset_bit = BIT(1),
|
||||
};
|
||||
|
||||
static const struct of_device_id mchp_sparx5_reset_of_match[] = {
|
||||
{
|
||||
.compatible = "microchip,sparx5-switch-reset",
|
||||
.data = &reset_props_sparx5,
|
||||
}, {
|
||||
.compatible = "microchip,lan966x-switch-reset",
|
||||
.data = &reset_props_lan966x,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
@ -155,6 +155,10 @@ static const struct of_device_id uniphier_glue_reset_match[] = {
|
||||
.compatible = "socionext,uniphier-pxs3-usb3-reset",
|
||||
.data = &uniphier_pxs2_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-nx1-usb3-reset",
|
||||
.data = &uniphier_pxs2_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-pro4-ahci-reset",
|
||||
.data = &uniphier_pro4_data,
|
||||
|
@ -136,6 +136,21 @@ static const struct uniphier_reset_data uniphier_pxs3_sys_reset_data[] = {
|
||||
UNIPHIER_RESETX(28, 0x200c, 7), /* SATA0 */
|
||||
UNIPHIER_RESETX(29, 0x200c, 8), /* SATA1 */
|
||||
UNIPHIER_RESETX(30, 0x200c, 21), /* SATA-PHY */
|
||||
UNIPHIER_RESETX(40, 0x2008, 0), /* AIO */
|
||||
UNIPHIER_RESETX(42, 0x2010, 2), /* EXIV */
|
||||
UNIPHIER_RESET_END,
|
||||
};
|
||||
|
||||
static const struct uniphier_reset_data uniphier_nx1_sys_reset_data[] = {
|
||||
UNIPHIER_RESETX(4, 0x2008, 8), /* eMMC */
|
||||
UNIPHIER_RESETX(6, 0x200c, 0), /* Ether */
|
||||
UNIPHIER_RESETX(12, 0x200c, 16), /* USB30 link */
|
||||
UNIPHIER_RESETX(16, 0x200c, 24), /* USB30-PHY0 */
|
||||
UNIPHIER_RESETX(17, 0x200c, 25), /* USB30-PHY1 */
|
||||
UNIPHIER_RESETX(18, 0x200c, 26), /* USB30-PHY2 */
|
||||
UNIPHIER_RESETX(24, 0x200c, 8), /* PCIe */
|
||||
UNIPHIER_RESETX(52, 0x2010, 0), /* VOC */
|
||||
UNIPHIER_RESETX(58, 0x2010, 8), /* HDMI-Tx */
|
||||
UNIPHIER_RESET_END,
|
||||
};
|
||||
|
||||
@ -400,6 +415,10 @@ static const struct of_device_id uniphier_reset_match[] = {
|
||||
.compatible = "socionext,uniphier-pxs3-reset",
|
||||
.data = uniphier_pxs3_sys_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-nx1-reset",
|
||||
.data = uniphier_nx1_sys_reset_data,
|
||||
},
|
||||
/* Media I/O reset, SD reset */
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld4-mio-reset",
|
||||
@ -437,6 +456,10 @@ static const struct of_device_id uniphier_reset_match[] = {
|
||||
.compatible = "socionext,uniphier-pxs3-sd-reset",
|
||||
.data = uniphier_pro5_sd_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-nx1-sd-reset",
|
||||
.data = uniphier_pro5_sd_reset_data,
|
||||
},
|
||||
/* Peripheral reset */
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld4-peri-reset",
|
||||
@ -470,6 +493,10 @@ static const struct of_device_id uniphier_reset_match[] = {
|
||||
.compatible = "socionext,uniphier-pxs3-peri-reset",
|
||||
.data = uniphier_pro4_peri_reset_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-nx1-peri-reset",
|
||||
.data = uniphier_pro4_peri_reset_data,
|
||||
},
|
||||
/* Analog signal amplifiers reset */
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld11-adamv-reset",
|
||||
|
@ -1404,16 +1404,10 @@ config RTC_DRV_OMAP
|
||||
This driver can also be built as a module, if so, module
|
||||
will be called rtc-omap.
|
||||
|
||||
config HAVE_S3C_RTC
|
||||
bool
|
||||
help
|
||||
This will include RTC support for Samsung SoCs. If
|
||||
you want to include RTC support for any machine, kindly
|
||||
select this in the respective mach-XXXX/Kconfig file.
|
||||
|
||||
config RTC_DRV_S3C
|
||||
tristate "Samsung S3C series SoC RTC"
|
||||
depends on ARCH_S3C64XX || HAVE_S3C_RTC || COMPILE_TEST
|
||||
depends on ARCH_EXYNOS || ARCH_S3C64XX || ARCH_S3C24XX || ARCH_S5PV210 || \
|
||||
COMPILE_TEST
|
||||
help
|
||||
RTC (Realtime Clock) driver for the clock inbuilt into the
|
||||
Samsung S3C24XX series of SoCs. This can provide periodic
|
||||
|
@ -168,7 +168,6 @@ EXPORT_SYMBOL_GPL(meson_canvas_free);
|
||||
|
||||
static int meson_canvas_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct meson_canvas *canvas;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
@ -176,8 +175,7 @@ static int meson_canvas_probe(struct platform_device *pdev)
|
||||
if (!canvas)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
canvas->reg_base = devm_ioremap_resource(dev, res);
|
||||
canvas->reg_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(canvas->reg_base))
|
||||
return PTR_ERR(canvas->reg_base);
|
||||
|
||||
|
@ -606,7 +606,6 @@ static int meson_msr_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct meson_msr_id *match_data;
|
||||
struct meson_msr *priv;
|
||||
struct resource *res;
|
||||
struct dentry *root, *clks;
|
||||
void __iomem *base;
|
||||
int i;
|
||||
@ -624,8 +623,7 @@ static int meson_msr_probe(struct platform_device *pdev)
|
||||
|
||||
memcpy(priv->msr_table, match_data, sizeof(priv->msr_table));
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
@ -65,6 +65,7 @@ static const struct meson_gx_package_id {
|
||||
{ "A113X", 0x25, 0x37, 0xff },
|
||||
{ "A113D", 0x25, 0x22, 0xff },
|
||||
{ "S905D2", 0x28, 0x10, 0xf0 },
|
||||
{ "S905Y2", 0x28, 0x30, 0xf0 },
|
||||
{ "S905X2", 0x28, 0x40, 0xf0 },
|
||||
{ "A311D", 0x29, 0x10, 0xf0 },
|
||||
{ "S922X", 0x29, 0x40, 0xf0 },
|
||||
|
@ -24,6 +24,16 @@ config ASPEED_LPC_SNOOP
|
||||
allows the BMC to listen on and save the data written by
|
||||
the host to an arbitrary LPC I/O port.
|
||||
|
||||
config ASPEED_UART_ROUTING
|
||||
tristate "ASPEED uart routing control"
|
||||
select REGMAP
|
||||
select MFD_SYSCON
|
||||
default ARCH_ASPEED
|
||||
help
|
||||
Provides a driver to control the UART routing paths, allowing
|
||||
users to perform runtime configuration of the RX muxes among
|
||||
the UART controllers and I/O pins.
|
||||
|
||||
config ASPEED_P2A_CTRL
|
||||
tristate "ASPEED P2A (VGA MMIO to BMC) bridge control"
|
||||
select REGMAP
|
||||
|
@ -1,5 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
|
||||
obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
|
||||
obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
|
||||
obj-$(CONFIG_ASPEED_SOCINFO) += aspeed-socinfo.o
|
||||
obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
|
||||
obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
|
||||
obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o
|
||||
obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
|
||||
obj-$(CONFIG_ASPEED_SOCINFO) += aspeed-socinfo.o
|
||||
|
603
drivers/soc/aspeed/aspeed-uart-routing.c
Normal file
603
drivers/soc/aspeed/aspeed-uart-routing.c
Normal file
@ -0,0 +1,603 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2018 Google LLC
|
||||
* Copyright (c) 2021 Aspeed Technology Inc.
|
||||
*/
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/* register offsets */
|
||||
#define HICR9 0x98
|
||||
#define HICRA 0x9c
|
||||
|
||||
/* attributes options */
|
||||
#define UART_ROUTING_IO1 "io1"
|
||||
#define UART_ROUTING_IO2 "io2"
|
||||
#define UART_ROUTING_IO3 "io3"
|
||||
#define UART_ROUTING_IO4 "io4"
|
||||
#define UART_ROUTING_IO5 "io5"
|
||||
#define UART_ROUTING_IO6 "io6"
|
||||
#define UART_ROUTING_IO10 "io10"
|
||||
#define UART_ROUTING_UART1 "uart1"
|
||||
#define UART_ROUTING_UART2 "uart2"
|
||||
#define UART_ROUTING_UART3 "uart3"
|
||||
#define UART_ROUTING_UART4 "uart4"
|
||||
#define UART_ROUTING_UART5 "uart5"
|
||||
#define UART_ROUTING_UART6 "uart6"
|
||||
#define UART_ROUTING_UART10 "uart10"
|
||||
#define UART_ROUTING_RES "reserved"
|
||||
|
||||
struct aspeed_uart_routing {
|
||||
struct regmap *map;
|
||||
struct attribute_group const *attr_grp;
|
||||
};
|
||||
|
||||
struct aspeed_uart_routing_selector {
|
||||
struct device_attribute dev_attr;
|
||||
uint8_t reg;
|
||||
uint8_t mask;
|
||||
uint8_t shift;
|
||||
const char *const options[];
|
||||
};
|
||||
|
||||
#define to_routing_selector(_dev_attr) \
|
||||
container_of(_dev_attr, struct aspeed_uart_routing_selector, dev_attr)
|
||||
|
||||
static ssize_t aspeed_uart_routing_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf);
|
||||
|
||||
static ssize_t aspeed_uart_routing_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
|
||||
#define ROUTING_ATTR(_name) { \
|
||||
.attr = {.name = _name, \
|
||||
.mode = VERIFY_OCTAL_PERMISSIONS(0644) }, \
|
||||
.show = aspeed_uart_routing_show, \
|
||||
.store = aspeed_uart_routing_store, \
|
||||
}
|
||||
|
||||
/* routing selector for AST25xx */
|
||||
static struct aspeed_uart_routing_selector ast2500_io6_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_IO6),
|
||||
.reg = HICR9,
|
||||
.shift = 8,
|
||||
.mask = 0xf,
|
||||
.options = {
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_UART5,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_IO5,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2500_uart5_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_UART5),
|
||||
.reg = HICRA,
|
||||
.shift = 28,
|
||||
.mask = 0xf,
|
||||
.options = {
|
||||
UART_ROUTING_IO5,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_IO6,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2500_uart4_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_UART4),
|
||||
.reg = HICRA,
|
||||
.shift = 25,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_IO6,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2500_uart3_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_UART3),
|
||||
.reg = HICRA,
|
||||
.shift = 22,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_IO6,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2500_uart2_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_UART2),
|
||||
.reg = HICRA,
|
||||
.shift = 19,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_IO6,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2500_uart1_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_UART1),
|
||||
.reg = HICRA,
|
||||
.shift = 16,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_IO6,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2500_io5_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_IO5),
|
||||
.reg = HICRA,
|
||||
.shift = 12,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_UART5,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO6,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2500_io4_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_IO4),
|
||||
.reg = HICRA,
|
||||
.shift = 9,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_UART5,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_IO6,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2500_io3_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_IO3),
|
||||
.reg = HICRA,
|
||||
.shift = 6,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_UART5,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_IO6,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2500_io2_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_IO2),
|
||||
.reg = HICRA,
|
||||
.shift = 3,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_UART5,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_IO6,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2500_io1_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_IO1),
|
||||
.reg = HICRA,
|
||||
.shift = 0,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_UART5,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_IO6,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct attribute *ast2500_uart_routing_attrs[] = {
|
||||
&ast2500_io6_sel.dev_attr.attr,
|
||||
&ast2500_uart5_sel.dev_attr.attr,
|
||||
&ast2500_uart4_sel.dev_attr.attr,
|
||||
&ast2500_uart3_sel.dev_attr.attr,
|
||||
&ast2500_uart2_sel.dev_attr.attr,
|
||||
&ast2500_uart1_sel.dev_attr.attr,
|
||||
&ast2500_io5_sel.dev_attr.attr,
|
||||
&ast2500_io4_sel.dev_attr.attr,
|
||||
&ast2500_io3_sel.dev_attr.attr,
|
||||
&ast2500_io2_sel.dev_attr.attr,
|
||||
&ast2500_io1_sel.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group ast2500_uart_routing_attr_group = {
|
||||
.attrs = ast2500_uart_routing_attrs,
|
||||
};
|
||||
|
||||
/* routing selector for AST26xx */
|
||||
static struct aspeed_uart_routing_selector ast2600_uart10_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_UART10),
|
||||
.reg = HICR9,
|
||||
.shift = 12,
|
||||
.mask = 0xf,
|
||||
.options = {
|
||||
UART_ROUTING_IO10,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_RES,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2600_io10_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_IO10),
|
||||
.reg = HICR9,
|
||||
.shift = 8,
|
||||
.mask = 0xf,
|
||||
.options = {
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_RES,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_RES,
|
||||
UART_ROUTING_UART10,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2600_uart4_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_UART4),
|
||||
.reg = HICRA,
|
||||
.shift = 25,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_IO10,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2600_uart3_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_UART3),
|
||||
.reg = HICRA,
|
||||
.shift = 22,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_IO10,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2600_uart2_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_UART2),
|
||||
.reg = HICRA,
|
||||
.shift = 19,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_IO10,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2600_uart1_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_UART1),
|
||||
.reg = HICRA,
|
||||
.shift = 16,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_IO10,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2600_io4_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_IO4),
|
||||
.reg = HICRA,
|
||||
.shift = 9,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_UART10,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_IO10,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2600_io3_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_IO3),
|
||||
.reg = HICRA,
|
||||
.shift = 6,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_UART10,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_IO1,
|
||||
UART_ROUTING_IO2,
|
||||
UART_ROUTING_IO10,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2600_io2_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_IO2),
|
||||
.reg = HICRA,
|
||||
.shift = 3,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_UART10,
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_IO10,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct aspeed_uart_routing_selector ast2600_io1_sel = {
|
||||
.dev_attr = ROUTING_ATTR(UART_ROUTING_IO1),
|
||||
.reg = HICRA,
|
||||
.shift = 0,
|
||||
.mask = 0x7,
|
||||
.options = {
|
||||
UART_ROUTING_UART1,
|
||||
UART_ROUTING_UART2,
|
||||
UART_ROUTING_UART3,
|
||||
UART_ROUTING_UART4,
|
||||
UART_ROUTING_UART10,
|
||||
UART_ROUTING_IO3,
|
||||
UART_ROUTING_IO4,
|
||||
UART_ROUTING_IO10,
|
||||
NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct attribute *ast2600_uart_routing_attrs[] = {
|
||||
&ast2600_uart10_sel.dev_attr.attr,
|
||||
&ast2600_io10_sel.dev_attr.attr,
|
||||
&ast2600_uart4_sel.dev_attr.attr,
|
||||
&ast2600_uart3_sel.dev_attr.attr,
|
||||
&ast2600_uart2_sel.dev_attr.attr,
|
||||
&ast2600_uart1_sel.dev_attr.attr,
|
||||
&ast2600_io4_sel.dev_attr.attr,
|
||||
&ast2600_io3_sel.dev_attr.attr,
|
||||
&ast2600_io2_sel.dev_attr.attr,
|
||||
&ast2600_io1_sel.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group ast2600_uart_routing_attr_group = {
|
||||
.attrs = ast2600_uart_routing_attrs,
|
||||
};
|
||||
|
||||
static ssize_t aspeed_uart_routing_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct aspeed_uart_routing *uart_routing = dev_get_drvdata(dev);
|
||||
struct aspeed_uart_routing_selector *sel = to_routing_selector(attr);
|
||||
int val, pos, len;
|
||||
|
||||
regmap_read(uart_routing->map, sel->reg, &val);
|
||||
val = (val >> sel->shift) & sel->mask;
|
||||
|
||||
len = 0;
|
||||
for (pos = 0; sel->options[pos] != NULL; ++pos) {
|
||||
if (pos == val)
|
||||
len += sysfs_emit_at(buf, len, "[%s] ", sel->options[pos]);
|
||||
else
|
||||
len += sysfs_emit_at(buf, len, "%s ", sel->options[pos]);
|
||||
}
|
||||
|
||||
if (val >= pos)
|
||||
len += sysfs_emit_at(buf, len, "[unknown(%d)]", val);
|
||||
|
||||
len += sysfs_emit_at(buf, len, "\n");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t aspeed_uart_routing_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct aspeed_uart_routing *uart_routing = dev_get_drvdata(dev);
|
||||
struct aspeed_uart_routing_selector *sel = to_routing_selector(attr);
|
||||
int val;
|
||||
|
||||
val = match_string(sel->options, -1, buf);
|
||||
if (val < 0) {
|
||||
dev_err(dev, "invalid value \"%s\"\n", buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(uart_routing->map, sel->reg,
|
||||
(sel->mask << sel->shift),
|
||||
(val & sel->mask) << sel->shift);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int aspeed_uart_routing_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct aspeed_uart_routing *uart_routing;
|
||||
|
||||
uart_routing = devm_kzalloc(&pdev->dev, sizeof(*uart_routing), GFP_KERNEL);
|
||||
if (!uart_routing)
|
||||
return -ENOMEM;
|
||||
|
||||
uart_routing->map = syscon_node_to_regmap(dev->parent->of_node);
|
||||
if (IS_ERR(uart_routing->map)) {
|
||||
dev_err(dev, "cannot get regmap\n");
|
||||
return PTR_ERR(uart_routing->map);
|
||||
}
|
||||
|
||||
uart_routing->attr_grp = of_device_get_match_data(dev);
|
||||
|
||||
rc = sysfs_create_group(&dev->kobj, uart_routing->attr_grp);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
dev_set_drvdata(dev, uart_routing);
|
||||
|
||||
dev_info(dev, "module loaded\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aspeed_uart_routing_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct aspeed_uart_routing *uart_routing = platform_get_drvdata(pdev);
|
||||
|
||||
sysfs_remove_group(&dev->kobj, uart_routing->attr_grp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id aspeed_uart_routing_table[] = {
|
||||
{ .compatible = "aspeed,ast2400-uart-routing",
|
||||
.data = &ast2500_uart_routing_attr_group },
|
||||
{ .compatible = "aspeed,ast2500-uart-routing",
|
||||
.data = &ast2500_uart_routing_attr_group },
|
||||
{ .compatible = "aspeed,ast2600-uart-routing",
|
||||
.data = &ast2600_uart_routing_attr_group },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver aspeed_uart_routing_driver = {
|
||||
.driver = {
|
||||
.name = "aspeed-uart-routing",
|
||||
.of_match_table = aspeed_uart_routing_table,
|
||||
},
|
||||
.probe = aspeed_uart_routing_probe,
|
||||
.remove = aspeed_uart_routing_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(aspeed_uart_routing_driver);
|
||||
|
||||
MODULE_AUTHOR("Oskar Senft <osk@google.com>");
|
||||
MODULE_AUTHOR("Chia-Wei Wang <chiawei_wang@aspeedtech.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Driver to configure Aspeed UART routing");
|
@ -276,7 +276,6 @@ static int bcm_pmb_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct bcm_pmb_pd_data *table;
|
||||
const struct bcm_pmb_pd_data *e;
|
||||
struct resource *res;
|
||||
struct bcm_pmb *pmb;
|
||||
int max_id;
|
||||
int err;
|
||||
@ -287,8 +286,7 @@ static int bcm_pmb_probe(struct platform_device *pdev)
|
||||
|
||||
pmb->dev = dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pmb->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
pmb->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pmb->base))
|
||||
return PTR_ERR(pmb->base);
|
||||
|
||||
|
@ -91,7 +91,6 @@ static int bcm63xx_power_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct resource *res;
|
||||
const struct bcm63xx_power_data *entry, *table;
|
||||
struct bcm63xx_power *power;
|
||||
unsigned int ndom;
|
||||
@ -102,8 +101,7 @@ static int bcm63xx_power_probe(struct platform_device *pdev)
|
||||
if (!power)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
power->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
power->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(power->base))
|
||||
return PTR_ERR(power->base);
|
||||
|
||||
|
@ -136,6 +136,8 @@ static int __init mcp_write_pairing_set(void)
|
||||
|
||||
static const u32 a72_b53_mach_compat[] = {
|
||||
0x7211,
|
||||
0x72113,
|
||||
0x72116,
|
||||
0x7216,
|
||||
0x72164,
|
||||
0x72165,
|
||||
|
@ -500,7 +500,7 @@ int dpaa2_io_service_enqueue_multiple_fq(struct dpaa2_io *d,
|
||||
qbman_eq_desc_set_no_orp(&ed, 0);
|
||||
qbman_eq_desc_set_fq(&ed, fqid);
|
||||
|
||||
return qbman_swp_enqueue_multiple(d->swp, &ed, fd, 0, nb);
|
||||
return qbman_swp_enqueue_multiple(d->swp, &ed, fd, NULL, nb);
|
||||
}
|
||||
EXPORT_SYMBOL(dpaa2_io_service_enqueue_multiple_fq);
|
||||
|
||||
|
@ -693,9 +693,9 @@ int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s,
|
||||
p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
|
||||
p[0] = cl[0] | s->eqcr.pi_vb;
|
||||
if (flags && (flags[i] & QBMAN_ENQUEUE_FLAG_DCA)) {
|
||||
struct qbman_eq_desc *d = (struct qbman_eq_desc *)p;
|
||||
struct qbman_eq_desc *eq_desc = (struct qbman_eq_desc *)p;
|
||||
|
||||
d->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) |
|
||||
eq_desc->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) |
|
||||
((flags[i]) & QBMAN_EQCR_DCA_IDXMASK);
|
||||
}
|
||||
eqcr_pi++;
|
||||
@ -775,9 +775,9 @@ int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s,
|
||||
p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
|
||||
p[0] = cl[0] | s->eqcr.pi_vb;
|
||||
if (flags && (flags[i] & QBMAN_ENQUEUE_FLAG_DCA)) {
|
||||
struct qbman_eq_desc *d = (struct qbman_eq_desc *)p;
|
||||
struct qbman_eq_desc *eq_desc = (struct qbman_eq_desc *)p;
|
||||
|
||||
d->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) |
|
||||
eq_desc->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) |
|
||||
((flags[i]) & QBMAN_EQCR_DCA_IDXMASK);
|
||||
}
|
||||
eqcr_pi++;
|
||||
|
@ -140,7 +140,6 @@ static int fsl_guts_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
const struct fsl_soc_die_attr *soc_die;
|
||||
const char *machine;
|
||||
u32 svr;
|
||||
@ -152,8 +151,7 @@ static int fsl_guts_probe(struct platform_device *pdev)
|
||||
|
||||
guts->little_endian = of_property_read_bool(np, "little-endian");
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
guts->regs = devm_ioremap_resource(dev, res);
|
||||
guts->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(guts->regs))
|
||||
return PTR_ERR(guts->regs);
|
||||
|
||||
|
@ -146,7 +146,6 @@ static const struct dev_pm_ops rcpm_pm_ops = {
|
||||
static int rcpm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *r;
|
||||
struct rcpm *rcpm;
|
||||
int ret;
|
||||
|
||||
@ -154,11 +153,7 @@ static int rcpm_probe(struct platform_device *pdev)
|
||||
if (!rcpm)
|
||||
return -ENOMEM;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!r)
|
||||
return -ENODEV;
|
||||
|
||||
rcpm->ippdexpcr_base = devm_ioremap_resource(&pdev->dev, r);
|
||||
rcpm->ippdexpcr_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(rcpm->ippdexpcr_base)) {
|
||||
ret = PTR_ERR(rcpm->ippdexpcr_base);
|
||||
return ret;
|
||||
|
@ -6,6 +6,7 @@ config IMX_GPCV2_PM_DOMAINS
|
||||
depends on ARCH_MXC || (COMPILE_TEST && OF)
|
||||
depends on PM
|
||||
select PM_GENERIC_DOMAINS
|
||||
select REGMAP_MMIO
|
||||
default y if SOC_IMX7D
|
||||
|
||||
config SOC_IMX8M
|
||||
|
@ -5,3 +5,4 @@ endif
|
||||
obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
|
||||
obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
|
||||
obj-$(CONFIG_SOC_IMX8M) += soc-imx8m.o
|
||||
obj-$(CONFIG_SOC_IMX8M) += imx8m-blk-ctrl.o
|
||||
|
@ -192,7 +192,7 @@ struct imx_pgc_domain {
|
||||
struct clk_bulk_data *clks;
|
||||
int num_clks;
|
||||
|
||||
unsigned int pgc;
|
||||
unsigned long pgc;
|
||||
|
||||
const struct {
|
||||
u32 pxx;
|
||||
@ -202,6 +202,7 @@ struct imx_pgc_domain {
|
||||
} bits;
|
||||
|
||||
const int voltage;
|
||||
const bool keep_clocks;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
@ -220,7 +221,7 @@ to_imx_pgc_domain(struct generic_pm_domain *genpd)
|
||||
static int imx_pgc_power_up(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd);
|
||||
u32 reg_val;
|
||||
u32 reg_val, pgc;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(domain->dev);
|
||||
@ -244,6 +245,8 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
|
||||
goto out_regulator_disable;
|
||||
}
|
||||
|
||||
reset_control_assert(domain->reset);
|
||||
|
||||
if (domain->bits.pxx) {
|
||||
/* request the domain to power up */
|
||||
regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PUP_REQ,
|
||||
@ -262,12 +265,12 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
|
||||
}
|
||||
|
||||
/* disable power control */
|
||||
regmap_clear_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc),
|
||||
GPC_PGC_CTRL_PCR);
|
||||
for_each_set_bit(pgc, &domain->pgc, 32) {
|
||||
regmap_clear_bits(domain->regmap, GPC_PGC_CTRL(pgc),
|
||||
GPC_PGC_CTRL_PCR);
|
||||
}
|
||||
}
|
||||
|
||||
reset_control_assert(domain->reset);
|
||||
|
||||
/* delay for reset to propagate */
|
||||
udelay(5);
|
||||
|
||||
@ -293,7 +296,8 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
|
||||
}
|
||||
|
||||
/* Disable reset clocks for all devices in the domain */
|
||||
clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
|
||||
if (!domain->keep_clocks)
|
||||
clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -311,14 +315,16 @@ out_put_pm:
|
||||
static int imx_pgc_power_down(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd);
|
||||
u32 reg_val;
|
||||
u32 reg_val, pgc;
|
||||
int ret;
|
||||
|
||||
/* Enable reset clocks for all devices in the domain */
|
||||
ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
|
||||
if (ret) {
|
||||
dev_err(domain->dev, "failed to enable reset clocks\n");
|
||||
return ret;
|
||||
if (!domain->keep_clocks) {
|
||||
ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
|
||||
if (ret) {
|
||||
dev_err(domain->dev, "failed to enable reset clocks\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* request the ADB400 to power down */
|
||||
@ -338,8 +344,10 @@ static int imx_pgc_power_down(struct generic_pm_domain *genpd)
|
||||
|
||||
if (domain->bits.pxx) {
|
||||
/* enable power control */
|
||||
regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc),
|
||||
GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR);
|
||||
for_each_set_bit(pgc, &domain->pgc, 32) {
|
||||
regmap_update_bits(domain->regmap, GPC_PGC_CTRL(pgc),
|
||||
GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR);
|
||||
}
|
||||
|
||||
/* request the domain to power down */
|
||||
regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PDN_REQ,
|
||||
@ -389,7 +397,7 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = {
|
||||
.map = IMX7_MIPI_PHY_A_CORE_DOMAIN,
|
||||
},
|
||||
.voltage = 1000000,
|
||||
.pgc = IMX7_PGC_MIPI,
|
||||
.pgc = BIT(IMX7_PGC_MIPI),
|
||||
},
|
||||
|
||||
[IMX7_POWER_DOMAIN_PCIE_PHY] = {
|
||||
@ -401,7 +409,7 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = {
|
||||
.map = IMX7_PCIE_PHY_A_CORE_DOMAIN,
|
||||
},
|
||||
.voltage = 1000000,
|
||||
.pgc = IMX7_PGC_PCIE,
|
||||
.pgc = BIT(IMX7_PGC_PCIE),
|
||||
},
|
||||
|
||||
[IMX7_POWER_DOMAIN_USB_HSIC_PHY] = {
|
||||
@ -413,7 +421,7 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = {
|
||||
.map = IMX7_USB_HSIC_PHY_A_CORE_DOMAIN,
|
||||
},
|
||||
.voltage = 1200000,
|
||||
.pgc = IMX7_PGC_USB_HSIC,
|
||||
.pgc = BIT(IMX7_PGC_USB_HSIC),
|
||||
},
|
||||
};
|
||||
|
||||
@ -448,7 +456,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
|
||||
.pxx = IMX8M_MIPI_SW_Pxx_REQ,
|
||||
.map = IMX8M_MIPI_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_MIPI,
|
||||
.pgc = BIT(IMX8M_PGC_MIPI),
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_PCIE1] = {
|
||||
@ -459,7 +467,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
|
||||
.pxx = IMX8M_PCIE1_SW_Pxx_REQ,
|
||||
.map = IMX8M_PCIE1_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_PCIE1,
|
||||
.pgc = BIT(IMX8M_PGC_PCIE1),
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_USB_OTG1] = {
|
||||
@ -470,7 +478,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
|
||||
.pxx = IMX8M_OTG1_SW_Pxx_REQ,
|
||||
.map = IMX8M_OTG1_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_OTG1,
|
||||
.pgc = BIT(IMX8M_PGC_OTG1),
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_USB_OTG2] = {
|
||||
@ -481,7 +489,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
|
||||
.pxx = IMX8M_OTG2_SW_Pxx_REQ,
|
||||
.map = IMX8M_OTG2_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_OTG2,
|
||||
.pgc = BIT(IMX8M_PGC_OTG2),
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_DDR1] = {
|
||||
@ -492,7 +500,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
|
||||
.pxx = IMX8M_DDR1_SW_Pxx_REQ,
|
||||
.map = IMX8M_DDR2_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_DDR1,
|
||||
.pgc = BIT(IMX8M_PGC_DDR1),
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_GPU] = {
|
||||
@ -505,7 +513,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
|
||||
.hskreq = IMX8M_GPU_HSK_PWRDNREQN,
|
||||
.hskack = IMX8M_GPU_HSK_PWRDNACKN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_GPU,
|
||||
.pgc = BIT(IMX8M_PGC_GPU),
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_VPU] = {
|
||||
@ -518,7 +526,8 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
|
||||
.hskreq = IMX8M_VPU_HSK_PWRDNREQN,
|
||||
.hskack = IMX8M_VPU_HSK_PWRDNACKN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_VPU,
|
||||
.pgc = BIT(IMX8M_PGC_VPU),
|
||||
.keep_clocks = true,
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_DISP] = {
|
||||
@ -531,7 +540,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
|
||||
.hskreq = IMX8M_DISP_HSK_PWRDNREQN,
|
||||
.hskack = IMX8M_DISP_HSK_PWRDNACKN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_DISP,
|
||||
.pgc = BIT(IMX8M_PGC_DISP),
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_MIPI_CSI1] = {
|
||||
@ -542,7 +551,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
|
||||
.pxx = IMX8M_MIPI_CSI1_SW_Pxx_REQ,
|
||||
.map = IMX8M_MIPI_CSI1_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_MIPI_CSI1,
|
||||
.pgc = BIT(IMX8M_PGC_MIPI_CSI1),
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_MIPI_CSI2] = {
|
||||
@ -553,7 +562,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
|
||||
.pxx = IMX8M_MIPI_CSI2_SW_Pxx_REQ,
|
||||
.map = IMX8M_MIPI_CSI2_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_MIPI_CSI2,
|
||||
.pgc = BIT(IMX8M_PGC_MIPI_CSI2),
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_PCIE2] = {
|
||||
@ -564,7 +573,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
|
||||
.pxx = IMX8M_PCIE2_SW_Pxx_REQ,
|
||||
.map = IMX8M_PCIE2_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_PCIE2,
|
||||
.pgc = BIT(IMX8M_PGC_PCIE2),
|
||||
},
|
||||
};
|
||||
|
||||
@ -617,6 +626,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
|
||||
.hskreq = IMX8MM_HSIO_HSK_PWRDNREQN,
|
||||
.hskack = IMX8MM_HSIO_HSK_PWRDNACKN,
|
||||
},
|
||||
.keep_clocks = true,
|
||||
},
|
||||
|
||||
[IMX8MM_POWER_DOMAIN_PCIE] = {
|
||||
@ -627,7 +637,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
|
||||
.pxx = IMX8MM_PCIE_SW_Pxx_REQ,
|
||||
.map = IMX8MM_PCIE_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8MM_PGC_PCIE,
|
||||
.pgc = BIT(IMX8MM_PGC_PCIE),
|
||||
},
|
||||
|
||||
[IMX8MM_POWER_DOMAIN_OTG1] = {
|
||||
@ -638,7 +648,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
|
||||
.pxx = IMX8MM_OTG1_SW_Pxx_REQ,
|
||||
.map = IMX8MM_OTG1_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8MM_PGC_OTG1,
|
||||
.pgc = BIT(IMX8MM_PGC_OTG1),
|
||||
},
|
||||
|
||||
[IMX8MM_POWER_DOMAIN_OTG2] = {
|
||||
@ -649,7 +659,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
|
||||
.pxx = IMX8MM_OTG2_SW_Pxx_REQ,
|
||||
.map = IMX8MM_OTG2_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8MM_PGC_OTG2,
|
||||
.pgc = BIT(IMX8MM_PGC_OTG2),
|
||||
},
|
||||
|
||||
[IMX8MM_POWER_DOMAIN_GPUMIX] = {
|
||||
@ -662,7 +672,8 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
|
||||
.hskreq = IMX8MM_GPUMIX_HSK_PWRDNREQN,
|
||||
.hskack = IMX8MM_GPUMIX_HSK_PWRDNACKN,
|
||||
},
|
||||
.pgc = IMX8MM_PGC_GPUMIX,
|
||||
.pgc = BIT(IMX8MM_PGC_GPUMIX),
|
||||
.keep_clocks = true,
|
||||
},
|
||||
|
||||
[IMX8MM_POWER_DOMAIN_GPU] = {
|
||||
@ -675,7 +686,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
|
||||
.hskreq = IMX8MM_GPU_HSK_PWRDNREQN,
|
||||
.hskack = IMX8MM_GPU_HSK_PWRDNACKN,
|
||||
},
|
||||
.pgc = IMX8MM_PGC_GPU2D,
|
||||
.pgc = BIT(IMX8MM_PGC_GPU2D) | BIT(IMX8MM_PGC_GPU3D),
|
||||
},
|
||||
|
||||
[IMX8MM_POWER_DOMAIN_VPUMIX] = {
|
||||
@ -688,7 +699,8 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
|
||||
.hskreq = IMX8MM_VPUMIX_HSK_PWRDNREQN,
|
||||
.hskack = IMX8MM_VPUMIX_HSK_PWRDNACKN,
|
||||
},
|
||||
.pgc = IMX8MM_PGC_VPUMIX,
|
||||
.pgc = BIT(IMX8MM_PGC_VPUMIX),
|
||||
.keep_clocks = true,
|
||||
},
|
||||
|
||||
[IMX8MM_POWER_DOMAIN_VPUG1] = {
|
||||
@ -699,7 +711,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
|
||||
.pxx = IMX8MM_VPUG1_SW_Pxx_REQ,
|
||||
.map = IMX8MM_VPUG1_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8MM_PGC_VPUG1,
|
||||
.pgc = BIT(IMX8MM_PGC_VPUG1),
|
||||
},
|
||||
|
||||
[IMX8MM_POWER_DOMAIN_VPUG2] = {
|
||||
@ -710,7 +722,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
|
||||
.pxx = IMX8MM_VPUG2_SW_Pxx_REQ,
|
||||
.map = IMX8MM_VPUG2_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8MM_PGC_VPUG2,
|
||||
.pgc = BIT(IMX8MM_PGC_VPUG2),
|
||||
},
|
||||
|
||||
[IMX8MM_POWER_DOMAIN_VPUH1] = {
|
||||
@ -721,7 +733,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
|
||||
.pxx = IMX8MM_VPUH1_SW_Pxx_REQ,
|
||||
.map = IMX8MM_VPUH1_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8MM_PGC_VPUH1,
|
||||
.pgc = BIT(IMX8MM_PGC_VPUH1),
|
||||
},
|
||||
|
||||
[IMX8MM_POWER_DOMAIN_DISPMIX] = {
|
||||
@ -734,7 +746,8 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
|
||||
.hskreq = IMX8MM_DISPMIX_HSK_PWRDNREQN,
|
||||
.hskack = IMX8MM_DISPMIX_HSK_PWRDNACKN,
|
||||
},
|
||||
.pgc = IMX8MM_PGC_DISPMIX,
|
||||
.pgc = BIT(IMX8MM_PGC_DISPMIX),
|
||||
.keep_clocks = true,
|
||||
},
|
||||
|
||||
[IMX8MM_POWER_DOMAIN_MIPI] = {
|
||||
@ -745,7 +758,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
|
||||
.pxx = IMX8MM_MIPI_SW_Pxx_REQ,
|
||||
.map = IMX8MM_MIPI_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8MM_PGC_MIPI,
|
||||
.pgc = BIT(IMX8MM_PGC_MIPI),
|
||||
},
|
||||
};
|
||||
|
||||
@ -802,6 +815,7 @@ static const struct imx_pgc_domain imx8mn_pgc_domains[] = {
|
||||
.hskreq = IMX8MN_HSIO_HSK_PWRDNREQN,
|
||||
.hskack = IMX8MN_HSIO_HSK_PWRDNACKN,
|
||||
},
|
||||
.keep_clocks = true,
|
||||
},
|
||||
|
||||
[IMX8MN_POWER_DOMAIN_OTG1] = {
|
||||
@ -812,7 +826,7 @@ static const struct imx_pgc_domain imx8mn_pgc_domains[] = {
|
||||
.pxx = IMX8MN_OTG1_SW_Pxx_REQ,
|
||||
.map = IMX8MN_OTG1_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8MN_PGC_OTG1,
|
||||
.pgc = BIT(IMX8MN_PGC_OTG1),
|
||||
},
|
||||
|
||||
[IMX8MN_POWER_DOMAIN_GPUMIX] = {
|
||||
@ -825,7 +839,7 @@ static const struct imx_pgc_domain imx8mn_pgc_domains[] = {
|
||||
.hskreq = IMX8MN_GPUMIX_HSK_PWRDNREQN,
|
||||
.hskack = IMX8MN_GPUMIX_HSK_PWRDNACKN,
|
||||
},
|
||||
.pgc = IMX8MN_PGC_GPUMIX,
|
||||
.pgc = BIT(IMX8MN_PGC_GPUMIX),
|
||||
},
|
||||
};
|
||||
|
||||
@ -894,6 +908,10 @@ static int imx_pgc_domain_probe(struct platform_device *pdev)
|
||||
goto out_domain_unmap;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_LOCKDEP) &&
|
||||
of_property_read_bool(domain->dev->of_node, "power-domains"))
|
||||
lockdep_set_subclass(&domain->genpd.mlock, 1);
|
||||
|
||||
ret = of_genpd_add_provider_simple(domain->dev->of_node,
|
||||
&domain->genpd);
|
||||
if (ret) {
|
||||
@ -930,6 +948,36 @@ static int imx_pgc_domain_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int imx_pgc_domain_suspend(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* This may look strange, but is done so the generic PM_SLEEP code
|
||||
* can power down our domain and more importantly power it up again
|
||||
* after resume, without tripping over our usage of runtime PM to
|
||||
* power up/down the nested domains.
|
||||
*/
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_pgc_domain_resume(struct device *dev)
|
||||
{
|
||||
return pm_runtime_put(dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops imx_pgc_domain_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(imx_pgc_domain_suspend, imx_pgc_domain_resume)
|
||||
};
|
||||
|
||||
static const struct platform_device_id imx_pgc_domain_id[] = {
|
||||
{ "imx-pgc-domain", },
|
||||
{ },
|
||||
@ -938,6 +986,7 @@ static const struct platform_device_id imx_pgc_domain_id[] = {
|
||||
static struct platform_driver imx_pgc_domain_driver = {
|
||||
.driver = {
|
||||
.name = "imx-pgc",
|
||||
.pm = &imx_pgc_domain_pm_ops,
|
||||
},
|
||||
.probe = imx_pgc_domain_probe,
|
||||
.remove = imx_pgc_domain_remove,
|
||||
@ -986,6 +1035,9 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
|
||||
struct imx_pgc_domain *domain;
|
||||
u32 domain_index;
|
||||
|
||||
if (!of_device_is_available(np))
|
||||
continue;
|
||||
|
||||
ret = of_property_read_u32(np, "reg", &domain_index);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read 'reg' property\n");
|
||||
|
523
drivers/soc/imx/imx8m-blk-ctrl.c
Normal file
523
drivers/soc/imx/imx8m-blk-ctrl.c
Normal file
@ -0,0 +1,523 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/*
|
||||
* Copyright 2021 Pengutronix, Lucas Stach <kernel@pengutronix.de>
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <dt-bindings/power/imx8mm-power.h>
|
||||
|
||||
#define BLK_SFT_RSTN 0x0
|
||||
#define BLK_CLK_EN 0x4
|
||||
|
||||
struct imx8m_blk_ctrl_domain;
|
||||
|
||||
struct imx8m_blk_ctrl {
|
||||
struct device *dev;
|
||||
struct notifier_block power_nb;
|
||||
struct device *bus_power_dev;
|
||||
struct regmap *regmap;
|
||||
struct imx8m_blk_ctrl_domain *domains;
|
||||
struct genpd_onecell_data onecell_data;
|
||||
};
|
||||
|
||||
struct imx8m_blk_ctrl_domain_data {
|
||||
const char *name;
|
||||
const char * const *clk_names;
|
||||
int num_clks;
|
||||
const char *gpc_name;
|
||||
u32 rst_mask;
|
||||
u32 clk_mask;
|
||||
};
|
||||
|
||||
#define DOMAIN_MAX_CLKS 3
|
||||
|
||||
struct imx8m_blk_ctrl_domain {
|
||||
struct generic_pm_domain genpd;
|
||||
const struct imx8m_blk_ctrl_domain_data *data;
|
||||
struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
|
||||
struct device *power_dev;
|
||||
struct imx8m_blk_ctrl *bc;
|
||||
};
|
||||
|
||||
struct imx8m_blk_ctrl_data {
|
||||
int max_reg;
|
||||
notifier_fn_t power_notifier_fn;
|
||||
const struct imx8m_blk_ctrl_domain_data *domains;
|
||||
int num_domains;
|
||||
};
|
||||
|
||||
static inline struct imx8m_blk_ctrl_domain *
|
||||
to_imx8m_blk_ctrl_domain(struct generic_pm_domain *genpd)
|
||||
{
|
||||
return container_of(genpd, struct imx8m_blk_ctrl_domain, genpd);
|
||||
}
|
||||
|
||||
static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct imx8m_blk_ctrl_domain *domain = to_imx8m_blk_ctrl_domain(genpd);
|
||||
const struct imx8m_blk_ctrl_domain_data *data = domain->data;
|
||||
struct imx8m_blk_ctrl *bc = domain->bc;
|
||||
int ret;
|
||||
|
||||
/* make sure bus domain is awake */
|
||||
ret = pm_runtime_get_sync(bc->bus_power_dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(bc->bus_power_dev);
|
||||
dev_err(bc->dev, "failed to power up bus domain\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* put devices into reset */
|
||||
regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
|
||||
|
||||
/* enable upstream and blk-ctrl clocks to allow reset to propagate */
|
||||
ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
|
||||
if (ret) {
|
||||
dev_err(bc->dev, "failed to enable clocks\n");
|
||||
goto bus_put;
|
||||
}
|
||||
regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
|
||||
|
||||
/* power up upstream GPC domain */
|
||||
ret = pm_runtime_get_sync(domain->power_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(bc->dev, "failed to power up peripheral domain\n");
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
/* wait for reset to propagate */
|
||||
udelay(5);
|
||||
|
||||
/* release reset */
|
||||
regmap_set_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
|
||||
|
||||
/* disable upstream clocks */
|
||||
clk_bulk_disable_unprepare(data->num_clks, domain->clks);
|
||||
|
||||
return 0;
|
||||
|
||||
clk_disable:
|
||||
clk_bulk_disable_unprepare(data->num_clks, domain->clks);
|
||||
bus_put:
|
||||
pm_runtime_put(bc->bus_power_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx8m_blk_ctrl_power_off(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct imx8m_blk_ctrl_domain *domain = to_imx8m_blk_ctrl_domain(genpd);
|
||||
const struct imx8m_blk_ctrl_domain_data *data = domain->data;
|
||||
struct imx8m_blk_ctrl *bc = domain->bc;
|
||||
|
||||
/* put devices into reset and disable clocks */
|
||||
regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
|
||||
regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
|
||||
|
||||
/* power down upstream GPC domain */
|
||||
pm_runtime_put(domain->power_dev);
|
||||
|
||||
/* allow bus domain to suspend */
|
||||
pm_runtime_put(bc->bus_power_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct generic_pm_domain *
|
||||
imx8m_blk_ctrl_xlate(struct of_phandle_args *args, void *data)
|
||||
{
|
||||
struct genpd_onecell_data *onecell_data = data;
|
||||
unsigned int index = args->args[0];
|
||||
|
||||
if (args->args_count != 1 ||
|
||||
index >= onecell_data->num_domains)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return onecell_data->domains[index];
|
||||
}
|
||||
|
||||
static struct lock_class_key blk_ctrl_genpd_lock_class;
|
||||
|
||||
static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct imx8m_blk_ctrl_data *bc_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct imx8m_blk_ctrl *bc;
|
||||
void __iomem *base;
|
||||
int i, ret;
|
||||
|
||||
struct regmap_config regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
};
|
||||
|
||||
bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL);
|
||||
if (!bc)
|
||||
return -ENOMEM;
|
||||
|
||||
bc->dev = dev;
|
||||
|
||||
bc_data = of_device_get_match_data(dev);
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
regmap_config.max_register = bc_data->max_reg;
|
||||
bc->regmap = devm_regmap_init_mmio(dev, base, ®map_config);
|
||||
if (IS_ERR(bc->regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(bc->regmap),
|
||||
"failed to init regmap\n");
|
||||
|
||||
bc->domains = devm_kcalloc(dev, bc_data->num_domains,
|
||||
sizeof(struct imx8m_blk_ctrl_domain),
|
||||
GFP_KERNEL);
|
||||
if (!bc->domains)
|
||||
return -ENOMEM;
|
||||
|
||||
bc->onecell_data.num_domains = bc_data->num_domains;
|
||||
bc->onecell_data.xlate = imx8m_blk_ctrl_xlate;
|
||||
bc->onecell_data.domains =
|
||||
devm_kcalloc(dev, bc_data->num_domains,
|
||||
sizeof(struct generic_pm_domain *), GFP_KERNEL);
|
||||
if (!bc->onecell_data.domains)
|
||||
return -ENOMEM;
|
||||
|
||||
bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
|
||||
if (IS_ERR(bc->bus_power_dev))
|
||||
return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
|
||||
"failed to attach power domain\n");
|
||||
|
||||
for (i = 0; i < bc_data->num_domains; i++) {
|
||||
const struct imx8m_blk_ctrl_domain_data *data = &bc_data->domains[i];
|
||||
struct imx8m_blk_ctrl_domain *domain = &bc->domains[i];
|
||||
int j;
|
||||
|
||||
domain->data = data;
|
||||
|
||||
for (j = 0; j < data->num_clks; j++)
|
||||
domain->clks[j].id = data->clk_names[j];
|
||||
|
||||
ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret, "failed to get clock\n");
|
||||
goto cleanup_pds;
|
||||
}
|
||||
|
||||
domain->power_dev =
|
||||
dev_pm_domain_attach_by_name(dev, data->gpc_name);
|
||||
if (IS_ERR(domain->power_dev)) {
|
||||
dev_err_probe(dev, PTR_ERR(domain->power_dev),
|
||||
"failed to attach power domain\n");
|
||||
ret = PTR_ERR(domain->power_dev);
|
||||
goto cleanup_pds;
|
||||
}
|
||||
|
||||
domain->genpd.name = data->name;
|
||||
domain->genpd.power_on = imx8m_blk_ctrl_power_on;
|
||||
domain->genpd.power_off = imx8m_blk_ctrl_power_off;
|
||||
domain->bc = bc;
|
||||
|
||||
ret = pm_genpd_init(&domain->genpd, NULL, true);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret, "failed to init power domain\n");
|
||||
dev_pm_domain_detach(domain->power_dev, true);
|
||||
goto cleanup_pds;
|
||||
}
|
||||
|
||||
/*
|
||||
* We use runtime PM to trigger power on/off of the upstream GPC
|
||||
* domain, as a strict hierarchical parent/child power domain
|
||||
* setup doesn't allow us to meet the sequencing requirements.
|
||||
* This means we have nested locking of genpd locks, without the
|
||||
* nesting being visible at the genpd level, so we need a
|
||||
* separate lock class to make lockdep aware of the fact that
|
||||
* this are separate domain locks that can be nested without a
|
||||
* self-deadlock.
|
||||
*/
|
||||
lockdep_set_class(&domain->genpd.mlock,
|
||||
&blk_ctrl_genpd_lock_class);
|
||||
|
||||
bc->onecell_data.domains[i] = &domain->genpd;
|
||||
}
|
||||
|
||||
ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret, "failed to add power domain provider\n");
|
||||
goto cleanup_pds;
|
||||
}
|
||||
|
||||
bc->power_nb.notifier_call = bc_data->power_notifier_fn;
|
||||
ret = dev_pm_genpd_add_notifier(bc->bus_power_dev, &bc->power_nb);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret, "failed to add power notifier\n");
|
||||
goto cleanup_provider;
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, bc);
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_provider:
|
||||
of_genpd_del_provider(dev->of_node);
|
||||
cleanup_pds:
|
||||
for (i--; i >= 0; i--) {
|
||||
pm_genpd_remove(&bc->domains[i].genpd);
|
||||
dev_pm_domain_detach(bc->domains[i].power_dev, true);
|
||||
}
|
||||
|
||||
dev_pm_domain_detach(bc->bus_power_dev, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx8m_blk_ctrl_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct imx8m_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
|
||||
int i;
|
||||
|
||||
of_genpd_del_provider(pdev->dev.of_node);
|
||||
|
||||
for (i = 0; bc->onecell_data.num_domains; i++) {
|
||||
struct imx8m_blk_ctrl_domain *domain = &bc->domains[i];
|
||||
|
||||
pm_genpd_remove(&domain->genpd);
|
||||
dev_pm_domain_detach(domain->power_dev, true);
|
||||
}
|
||||
|
||||
dev_pm_genpd_remove_notifier(bc->bus_power_dev);
|
||||
|
||||
dev_pm_domain_detach(bc->bus_power_dev, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int imx8m_blk_ctrl_suspend(struct device *dev)
|
||||
{
|
||||
struct imx8m_blk_ctrl *bc = dev_get_drvdata(dev);
|
||||
int ret, i;
|
||||
|
||||
/*
|
||||
* This may look strange, but is done so the generic PM_SLEEP code
|
||||
* can power down our domains and more importantly power them up again
|
||||
* after resume, without tripping over our usage of runtime PM to
|
||||
* control the upstream GPC domains. Things happen in the right order
|
||||
* in the system suspend/resume paths due to the device parent/child
|
||||
* hierarchy.
|
||||
*/
|
||||
ret = pm_runtime_get_sync(bc->bus_power_dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(bc->bus_power_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < bc->onecell_data.num_domains; i++) {
|
||||
struct imx8m_blk_ctrl_domain *domain = &bc->domains[i];
|
||||
|
||||
ret = pm_runtime_get_sync(domain->power_dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(domain->power_dev);
|
||||
goto out_fail;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_fail:
|
||||
for (i--; i >= 0; i--)
|
||||
pm_runtime_put(bc->domains[i].power_dev);
|
||||
|
||||
pm_runtime_put(bc->bus_power_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx8m_blk_ctrl_resume(struct device *dev)
|
||||
{
|
||||
struct imx8m_blk_ctrl *bc = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < bc->onecell_data.num_domains; i++)
|
||||
pm_runtime_put(bc->domains[i].power_dev);
|
||||
|
||||
pm_runtime_put(bc->bus_power_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops imx8m_blk_ctrl_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(imx8m_blk_ctrl_suspend, imx8m_blk_ctrl_resume)
|
||||
};
|
||||
|
||||
static int imx8mm_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 together with the VPU clocks. To
|
||||
* allow the handshake with the GPC to progress we put the VPUs
|
||||
* in reset and ungate the clocks.
|
||||
*/
|
||||
regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, BIT(0) | BIT(1) | BIT(2));
|
||||
regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(0) | BIT(1) | BIT(2));
|
||||
|
||||
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);
|
||||
regmap_set_bits(bc->regmap, 0x14, 0xffffffff);
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static const struct imx8m_blk_ctrl_domain_data imx8mm_vpu_blk_ctl_domain_data[] = {
|
||||
[IMX8MM_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),
|
||||
},
|
||||
[IMX8MM_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),
|
||||
},
|
||||
[IMX8MM_VPUBLK_PD_H1] = {
|
||||
.name = "vpublk-h1",
|
||||
.clk_names = (const char *[]){ "h1", },
|
||||
.num_clks = 1,
|
||||
.gpc_name = "h1",
|
||||
.rst_mask = BIT(2),
|
||||
.clk_mask = BIT(2),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct imx8m_blk_ctrl_data imx8mm_vpu_blk_ctl_dev_data = {
|
||||
.max_reg = 0x18,
|
||||
.power_notifier_fn = imx8mm_vpu_power_notifier,
|
||||
.domains = imx8mm_vpu_blk_ctl_domain_data,
|
||||
.num_domains = ARRAY_SIZE(imx8mm_vpu_blk_ctl_domain_data),
|
||||
};
|
||||
|
||||
static int imx8mm_disp_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;
|
||||
|
||||
/* Enable bus clock and deassert bus reset */
|
||||
regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(12));
|
||||
regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(6));
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (action == GENPD_NOTIFY_ON)
|
||||
udelay(5);
|
||||
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static const struct imx8m_blk_ctrl_domain_data imx8mm_disp_blk_ctl_domain_data[] = {
|
||||
[IMX8MM_DISPBLK_PD_CSI_BRIDGE] = {
|
||||
.name = "dispblk-csi-bridge",
|
||||
.clk_names = (const char *[]){ "csi-bridge-axi", "csi-bridge-apb",
|
||||
"csi-bridge-core", },
|
||||
.num_clks = 3,
|
||||
.gpc_name = "csi-bridge",
|
||||
.rst_mask = BIT(0) | BIT(1) | BIT(2),
|
||||
.clk_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5),
|
||||
},
|
||||
[IMX8MM_DISPBLK_PD_LCDIF] = {
|
||||
.name = "dispblk-lcdif",
|
||||
.clk_names = (const char *[]){ "lcdif-axi", "lcdif-apb", "lcdif-pix", },
|
||||
.num_clks = 3,
|
||||
.gpc_name = "lcdif",
|
||||
.clk_mask = BIT(6) | BIT(7),
|
||||
},
|
||||
[IMX8MM_DISPBLK_PD_MIPI_DSI] = {
|
||||
.name = "dispblk-mipi-dsi",
|
||||
.clk_names = (const char *[]){ "dsi-pclk", "dsi-ref", },
|
||||
.num_clks = 2,
|
||||
.gpc_name = "mipi-dsi",
|
||||
.rst_mask = BIT(5),
|
||||
.clk_mask = BIT(8) | BIT(9),
|
||||
},
|
||||
[IMX8MM_DISPBLK_PD_MIPI_CSI] = {
|
||||
.name = "dispblk-mipi-csi",
|
||||
.clk_names = (const char *[]){ "csi-aclk", "csi-pclk" },
|
||||
.num_clks = 2,
|
||||
.gpc_name = "mipi-csi",
|
||||
.rst_mask = BIT(3) | BIT(4),
|
||||
.clk_mask = BIT(10) | BIT(11),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct imx8m_blk_ctrl_data imx8mm_disp_blk_ctl_dev_data = {
|
||||
.max_reg = 0x2c,
|
||||
.power_notifier_fn = imx8mm_disp_power_notifier,
|
||||
.domains = imx8mm_disp_blk_ctl_domain_data,
|
||||
.num_domains = ARRAY_SIZE(imx8mm_disp_blk_ctl_domain_data),
|
||||
};
|
||||
|
||||
static const struct of_device_id imx8m_blk_ctrl_of_match[] = {
|
||||
{
|
||||
.compatible = "fsl,imx8mm-vpu-blk-ctrl",
|
||||
.data = &imx8mm_vpu_blk_ctl_dev_data
|
||||
}, {
|
||||
.compatible = "fsl,imx8mm-disp-blk-ctrl",
|
||||
.data = &imx8mm_disp_blk_ctl_dev_data
|
||||
} ,{
|
||||
/* Sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx8m_blk_ctrl_of_match);
|
||||
|
||||
static struct platform_driver imx8m_blk_ctrl_driver = {
|
||||
.probe = imx8m_blk_ctrl_probe,
|
||||
.remove = imx8m_blk_ctrl_remove,
|
||||
.driver = {
|
||||
.name = "imx8m-blk-ctrl",
|
||||
.pm = &imx8m_blk_ctrl_pm_ops,
|
||||
.of_match_table = imx8m_blk_ctrl_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(imx8m_blk_ctrl_driver);
|
76
drivers/soc/mediatek/mt8192-mmsys.h
Normal file
76
drivers/soc/mediatek/mt8192-mmsys.h
Normal file
@ -0,0 +1,76 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef __SOC_MEDIATEK_MT8192_MMSYS_H
|
||||
#define __SOC_MEDIATEK_MT8192_MMSYS_H
|
||||
|
||||
#define MT8192_MMSYS_OVL_MOUT_EN 0xf04
|
||||
#define MT8192_DISP_OVL1_2L_MOUT_EN 0xf08
|
||||
#define MT8192_DISP_OVL0_2L_MOUT_EN 0xf18
|
||||
#define MT8192_DISP_OVL0_MOUT_EN 0xf1c
|
||||
#define MT8192_DISP_RDMA0_SEL_IN 0xf2c
|
||||
#define MT8192_DISP_RDMA0_SOUT_SEL 0xf30
|
||||
#define MT8192_DISP_CCORR0_SOUT_SEL 0xf34
|
||||
#define MT8192_DISP_AAL0_SEL_IN 0xf38
|
||||
#define MT8192_DISP_DITHER0_MOUT_EN 0xf3c
|
||||
#define MT8192_DISP_DSI0_SEL_IN 0xf40
|
||||
#define MT8192_DISP_OVL2_2L_MOUT_EN 0xf4c
|
||||
|
||||
#define MT8192_DISP_OVL0_GO_BLEND BIT(0)
|
||||
#define MT8192_DITHER0_MOUT_IN_DSI0 BIT(0)
|
||||
#define MT8192_OVL0_MOUT_EN_DISP_RDMA0 BIT(0)
|
||||
#define MT8192_OVL2_2L_MOUT_EN_RDMA4 BIT(0)
|
||||
#define MT8192_DISP_OVL0_GO_BG BIT(1)
|
||||
#define MT8192_DISP_OVL0_2L_GO_BLEND BIT(2)
|
||||
#define MT8192_DISP_OVL0_2L_GO_BG BIT(3)
|
||||
#define MT8192_OVL1_2L_MOUT_EN_RDMA1 BIT(4)
|
||||
#define MT8192_OVL0_MOUT_EN_OVL0_2L BIT(4)
|
||||
#define MT8192_RDMA0_SEL_IN_OVL0_2L 0x3
|
||||
#define MT8192_RDMA0_SOUT_COLOR0 0x1
|
||||
#define MT8192_CCORR0_SOUT_AAL0 0x1
|
||||
#define MT8192_AAL0_SEL_IN_CCORR0 0x1
|
||||
#define MT8192_DSI0_SEL_IN_DITHER0 0x1
|
||||
|
||||
static const struct mtk_mmsys_routes mmsys_mt8192_routing_table[] = {
|
||||
{
|
||||
DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0,
|
||||
MT8192_DISP_OVL0_2L_MOUT_EN, MT8192_OVL0_MOUT_EN_DISP_RDMA0,
|
||||
MT8192_OVL0_MOUT_EN_DISP_RDMA0
|
||||
}, {
|
||||
DDP_COMPONENT_OVL_2L2, DDP_COMPONENT_RDMA4,
|
||||
MT8192_DISP_OVL2_2L_MOUT_EN, MT8192_OVL2_2L_MOUT_EN_RDMA4,
|
||||
MT8192_OVL2_2L_MOUT_EN_RDMA4
|
||||
}, {
|
||||
DDP_COMPONENT_DITHER, DDP_COMPONENT_DSI0,
|
||||
MT8192_DISP_DITHER0_MOUT_EN, MT8192_DITHER0_MOUT_IN_DSI0,
|
||||
MT8192_DITHER0_MOUT_IN_DSI0
|
||||
}, {
|
||||
DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0,
|
||||
MT8192_DISP_RDMA0_SEL_IN, MT8192_RDMA0_SEL_IN_OVL0_2L,
|
||||
MT8192_RDMA0_SEL_IN_OVL0_2L
|
||||
}, {
|
||||
DDP_COMPONENT_CCORR, DDP_COMPONENT_AAL0,
|
||||
MT8192_DISP_AAL0_SEL_IN, MT8192_AAL0_SEL_IN_CCORR0,
|
||||
MT8192_AAL0_SEL_IN_CCORR0
|
||||
}, {
|
||||
DDP_COMPONENT_DITHER, DDP_COMPONENT_DSI0,
|
||||
MT8192_DISP_DSI0_SEL_IN, MT8192_DSI0_SEL_IN_DITHER0
|
||||
}, {
|
||||
DDP_COMPONENT_RDMA0, DDP_COMPONENT_COLOR0,
|
||||
MT8192_DISP_RDMA0_SOUT_SEL, MT8192_RDMA0_SOUT_COLOR0,
|
||||
MT8192_RDMA0_SOUT_COLOR0
|
||||
}, {
|
||||
DDP_COMPONENT_CCORR, DDP_COMPONENT_AAL0,
|
||||
MT8192_DISP_CCORR0_SOUT_SEL, MT8192_CCORR0_SOUT_AAL0,
|
||||
MT8192_CCORR0_SOUT_AAL0
|
||||
}, {
|
||||
DDP_COMPONENT_OVL0, DDP_COMPONENT_OVL_2L0,
|
||||
MT8192_MMSYS_OVL_MOUT_EN, MT8192_DISP_OVL0_GO_BG,
|
||||
MT8192_DISP_OVL0_GO_BG
|
||||
}, {
|
||||
DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0,
|
||||
MT8192_MMSYS_OVL_MOUT_EN, MT8192_DISP_OVL0_2L_GO_BLEND,
|
||||
MT8192_DISP_OVL0_2L_GO_BLEND
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* __SOC_MEDIATEK_MT8192_MMSYS_H */
|
@ -4,15 +4,18 @@
|
||||
* Author: James Liao <jamesjj.liao@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/soc/mediatek/mtk-mmsys.h>
|
||||
|
||||
#include "mtk-mmsys.h"
|
||||
#include "mt8167-mmsys.h"
|
||||
#include "mt8183-mmsys.h"
|
||||
#include "mt8192-mmsys.h"
|
||||
#include "mt8365-mmsys.h"
|
||||
|
||||
static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
|
||||
@ -53,6 +56,12 @@ static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
|
||||
.num_routes = ARRAY_SIZE(mmsys_mt8183_routing_table),
|
||||
};
|
||||
|
||||
static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
|
||||
.clk_driver = "clk-mt8192-mm",
|
||||
.routes = mmsys_mt8192_routing_table,
|
||||
.num_routes = ARRAY_SIZE(mmsys_mt8192_routing_table),
|
||||
};
|
||||
|
||||
static const struct mtk_mmsys_driver_data mt8365_mmsys_driver_data = {
|
||||
.clk_driver = "clk-mt8365-mm",
|
||||
.routes = mt8365_mmsys_routing_table,
|
||||
@ -62,6 +71,8 @@ static const struct mtk_mmsys_driver_data mt8365_mmsys_driver_data = {
|
||||
struct mtk_mmsys {
|
||||
void __iomem *regs;
|
||||
const struct mtk_mmsys_driver_data *data;
|
||||
spinlock_t lock; /* protects mmsys_sw_rst_b reg */
|
||||
struct reset_controller_dev rcdev;
|
||||
};
|
||||
|
||||
void mtk_mmsys_ddp_connect(struct device *dev,
|
||||
@ -101,6 +112,58 @@ void mtk_mmsys_ddp_disconnect(struct device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_disconnect);
|
||||
|
||||
static int mtk_mmsys_reset_update(struct reset_controller_dev *rcdev, unsigned long id,
|
||||
bool assert)
|
||||
{
|
||||
struct mtk_mmsys *mmsys = container_of(rcdev, struct mtk_mmsys, rcdev);
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
spin_lock_irqsave(&mmsys->lock, flags);
|
||||
|
||||
reg = readl_relaxed(mmsys->regs + MMSYS_SW0_RST_B);
|
||||
|
||||
if (assert)
|
||||
reg &= ~BIT(id);
|
||||
else
|
||||
reg |= BIT(id);
|
||||
|
||||
writel_relaxed(reg, mmsys->regs + MMSYS_SW0_RST_B);
|
||||
|
||||
spin_unlock_irqrestore(&mmsys->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_mmsys_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
|
||||
{
|
||||
return mtk_mmsys_reset_update(rcdev, id, true);
|
||||
}
|
||||
|
||||
static int mtk_mmsys_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
|
||||
{
|
||||
return mtk_mmsys_reset_update(rcdev, id, false);
|
||||
}
|
||||
|
||||
static int mtk_mmsys_reset(struct reset_controller_dev *rcdev, unsigned long id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mtk_mmsys_reset_assert(rcdev, id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
usleep_range(1000, 1100);
|
||||
|
||||
return mtk_mmsys_reset_deassert(rcdev, id);
|
||||
}
|
||||
|
||||
static const struct reset_control_ops mtk_mmsys_reset_ops = {
|
||||
.assert = mtk_mmsys_reset_assert,
|
||||
.deassert = mtk_mmsys_reset_deassert,
|
||||
.reset = mtk_mmsys_reset,
|
||||
};
|
||||
|
||||
static int mtk_mmsys_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -120,6 +183,18 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
spin_lock_init(&mmsys->lock);
|
||||
|
||||
mmsys->rcdev.owner = THIS_MODULE;
|
||||
mmsys->rcdev.nr_resets = 32;
|
||||
mmsys->rcdev.ops = &mtk_mmsys_reset_ops;
|
||||
mmsys->rcdev.of_node = pdev->dev.of_node;
|
||||
ret = devm_reset_controller_register(&pdev->dev, &mmsys->rcdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Couldn't register mmsys reset controller: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mmsys->data = of_device_get_match_data(&pdev->dev);
|
||||
platform_set_drvdata(pdev, mmsys);
|
||||
|
||||
@ -167,6 +242,10 @@ static const struct of_device_id of_match_mtk_mmsys[] = {
|
||||
.compatible = "mediatek,mt8183-mmsys",
|
||||
.data = &mt8183_mmsys_driver_data,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8192-mmsys",
|
||||
.data = &mt8192_mmsys_driver_data,
|
||||
},
|
||||
{
|
||||
.compatible = "mediatek,mt8365-mmsys",
|
||||
.data = &mt8365_mmsys_driver_data,
|
||||
|
@ -78,6 +78,8 @@
|
||||
#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;
|
||||
|
@ -39,6 +39,18 @@
|
||||
#define MT8167_MUTEX_MOD_DISP_DITHER 15
|
||||
#define MT8167_MUTEX_MOD_DISP_UFOE 16
|
||||
|
||||
#define MT8192_MUTEX_MOD_DISP_OVL0 0
|
||||
#define MT8192_MUTEX_MOD_DISP_OVL0_2L 1
|
||||
#define MT8192_MUTEX_MOD_DISP_RDMA0 2
|
||||
#define MT8192_MUTEX_MOD_DISP_COLOR0 4
|
||||
#define MT8192_MUTEX_MOD_DISP_CCORR0 5
|
||||
#define MT8192_MUTEX_MOD_DISP_AAL0 6
|
||||
#define MT8192_MUTEX_MOD_DISP_GAMMA0 7
|
||||
#define MT8192_MUTEX_MOD_DISP_POSTMASK0 8
|
||||
#define MT8192_MUTEX_MOD_DISP_DITHER0 9
|
||||
#define MT8192_MUTEX_MOD_DISP_OVL2_2L 16
|
||||
#define MT8192_MUTEX_MOD_DISP_RDMA4 17
|
||||
|
||||
#define MT8183_MUTEX_MOD_DISP_RDMA0 0
|
||||
#define MT8183_MUTEX_MOD_DISP_RDMA1 1
|
||||
#define MT8183_MUTEX_MOD_DISP_OVL0 9
|
||||
@ -214,6 +226,20 @@ static const unsigned int mt8183_mutex_mod[DDP_COMPONENT_ID_MAX] = {
|
||||
[DDP_COMPONENT_WDMA0] = MT8183_MUTEX_MOD_DISP_WDMA0,
|
||||
};
|
||||
|
||||
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,
|
||||
[DDP_COMPONENT_COLOR0] = MT8192_MUTEX_MOD_DISP_COLOR0,
|
||||
[DDP_COMPONENT_DITHER] = MT8192_MUTEX_MOD_DISP_DITHER0,
|
||||
[DDP_COMPONENT_GAMMA] = MT8192_MUTEX_MOD_DISP_GAMMA0,
|
||||
[DDP_COMPONENT_POSTMASK0] = MT8192_MUTEX_MOD_DISP_POSTMASK0,
|
||||
[DDP_COMPONENT_OVL0] = MT8192_MUTEX_MOD_DISP_OVL0,
|
||||
[DDP_COMPONENT_OVL_2L0] = MT8192_MUTEX_MOD_DISP_OVL0_2L,
|
||||
[DDP_COMPONENT_OVL_2L2] = MT8192_MUTEX_MOD_DISP_OVL2_2L,
|
||||
[DDP_COMPONENT_RDMA0] = MT8192_MUTEX_MOD_DISP_RDMA0,
|
||||
[DDP_COMPONENT_RDMA4] = MT8192_MUTEX_MOD_DISP_RDMA4,
|
||||
};
|
||||
|
||||
static const unsigned int mt2712_mutex_sof[MUTEX_SOF_DSI3 + 1] = {
|
||||
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
|
||||
[MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
|
||||
@ -275,6 +301,13 @@ static const struct mtk_mutex_data mt8183_mutex_driver_data = {
|
||||
.no_clk = true,
|
||||
};
|
||||
|
||||
static const struct mtk_mutex_data mt8192_mutex_driver_data = {
|
||||
.mutex_mod = mt8192_mutex_mod,
|
||||
.mutex_sof = mt8183_mutex_sof,
|
||||
.mutex_mod_reg = MT8183_MUTEX0_MOD0,
|
||||
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
|
||||
};
|
||||
|
||||
struct mtk_mutex *mtk_mutex_get(struct device *dev)
|
||||
{
|
||||
struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev);
|
||||
@ -507,6 +540,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,mt8192-disp-mutex",
|
||||
.data = &mt8192_mutex_driver_data},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mutex_driver_dt_match);
|
||||
|
@ -190,6 +190,25 @@ config QCOM_SOCINFO
|
||||
Say yes here to support the Qualcomm socinfo driver, providing
|
||||
information about the SoC to user space.
|
||||
|
||||
config QCOM_SPM
|
||||
tristate "Qualcomm Subsystem Power Manager (SPM)"
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
select QCOM_SCM
|
||||
help
|
||||
Enable the support for the Qualcomm Subsystem Power Manager, used
|
||||
to manage cores, L2 low power modes and to configure the internal
|
||||
Adaptive Voltage Scaler parameters, where supported.
|
||||
|
||||
config QCOM_STATS
|
||||
tristate "Qualcomm Technologies, Inc. (QTI) Sleep stats driver"
|
||||
depends on (ARCH_QCOM && DEBUG_FS) || COMPILE_TEST
|
||||
depends on QCOM_SMEM
|
||||
help
|
||||
Qualcomm Technologies, Inc. (QTI) Sleep stats driver to read
|
||||
the shared memory exported by the remote processor related to
|
||||
various SoC level low power modes statistics and export to debugfs
|
||||
interface.
|
||||
|
||||
config QCOM_WCNSS_CTRL
|
||||
tristate "Qualcomm WCNSS control driver"
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
|
@ -20,6 +20,8 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
|
||||
obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
|
||||
obj-$(CONFIG_QCOM_SMSM) += smsm.o
|
||||
obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o
|
||||
obj-$(CONFIG_QCOM_SPM) += spm.o
|
||||
obj-$(CONFIG_QCOM_STATS) += qcom_stats.o
|
||||
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
|
||||
obj-$(CONFIG_QCOM_APR) += apr.o
|
||||
obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
|
||||
|
@ -492,12 +492,14 @@ static int of_apr_add_pd_lookups(struct device *dev)
|
||||
1, &service_path);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "pdr service path missing: %d\n", ret);
|
||||
of_node_put(node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pds = pdr_add_lookup(apr->pdr, service_name, service_path);
|
||||
if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) {
|
||||
dev_err(dev, "pdr add lookup failed: %ld\n", PTR_ERR(pds));
|
||||
of_node_put(node);
|
||||
return PTR_ERR(pds);
|
||||
}
|
||||
}
|
||||
|
@ -1614,7 +1614,6 @@ static void cpr_debugfs_init(struct cpr_drv *drv)
|
||||
|
||||
static int cpr_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cpr_drv *drv;
|
||||
int irq, ret;
|
||||
@ -1648,8 +1647,7 @@ static int cpr_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(drv->tcsr))
|
||||
return PTR_ERR(drv->tcsr);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
drv->base = devm_ioremap_resource(dev, res);
|
||||
drv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(drv->base))
|
||||
return PTR_ERR(drv->base);
|
||||
|
||||
|
@ -115,7 +115,7 @@ static const struct llcc_slice_config sc7280_data[] = {
|
||||
{ LLCC_CMPT, 10, 768, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
|
||||
{ LLCC_GPUHTW, 11, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
|
||||
{ LLCC_GPU, 12, 512, 1, 0, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
|
||||
{ LLCC_MMUHWT, 13, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 1, 0},
|
||||
{ LLCC_MMUHWT, 13, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 0, 1, 0},
|
||||
{ LLCC_MDMPNG, 21, 768, 0, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
|
||||
{ LLCC_WLHW, 24, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
|
||||
{ LLCC_MODPE, 29, 64, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
|
||||
@ -142,6 +142,16 @@ static const struct llcc_slice_config sdm845_data[] = {
|
||||
{ LLCC_AUDHW, 22, 1024, 1, 1, 0xffc, 0x2, 0, 0, 1, 1, 0 },
|
||||
};
|
||||
|
||||
static const struct llcc_slice_config sm6350_data[] = {
|
||||
{ LLCC_CPUSS, 1, 768, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 1 },
|
||||
{ LLCC_MDM, 8, 512, 2, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
|
||||
{ LLCC_GPUHTW, 11, 256, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
|
||||
{ LLCC_GPU, 12, 512, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
|
||||
{ LLCC_MDMPNG, 21, 768, 0, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
|
||||
{ LLCC_NPU, 23, 768, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
|
||||
{ LLCC_MODPE, 29, 64, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
|
||||
};
|
||||
|
||||
static const struct llcc_slice_config sm8150_data[] = {
|
||||
{ LLCC_CPUSS, 1, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 1 },
|
||||
{ LLCC_VIDSC0, 2, 512, 2, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 },
|
||||
@ -203,6 +213,11 @@ static const struct qcom_llcc_config sdm845_cfg = {
|
||||
.need_llcc_cfg = false,
|
||||
};
|
||||
|
||||
static const struct qcom_llcc_config sm6350_cfg = {
|
||||
.sct_data = sm6350_data,
|
||||
.size = ARRAY_SIZE(sm6350_data),
|
||||
};
|
||||
|
||||
static const struct qcom_llcc_config sm8150_cfg = {
|
||||
.sct_data = sm8150_data,
|
||||
.size = ARRAY_SIZE(sm8150_data),
|
||||
@ -626,6 +641,7 @@ static const struct of_device_id qcom_llcc_of_match[] = {
|
||||
{ .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfg },
|
||||
{ .compatible = "qcom,sc7280-llcc", .data = &sc7280_cfg },
|
||||
{ .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfg },
|
||||
{ .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfg },
|
||||
{ .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfg },
|
||||
{ .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg },
|
||||
{ }
|
||||
|
@ -300,7 +300,6 @@ static int ocmem_dev_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
unsigned long reg, region_size;
|
||||
int i, j, ret, num_banks;
|
||||
struct resource *res;
|
||||
struct ocmem *ocmem;
|
||||
|
||||
if (!qcom_scm_is_available())
|
||||
@ -321,8 +320,7 @@ static int ocmem_dev_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl");
|
||||
ocmem->mmio = devm_ioremap_resource(&pdev->dev, res);
|
||||
ocmem->mmio = devm_platform_ioremap_resource_byname(pdev, "ctrl");
|
||||
if (IS_ERR(ocmem->mmio)) {
|
||||
dev_err(&pdev->dev, "Failed to ioremap ocmem_ctrl resource\n");
|
||||
return PTR_ERR(ocmem->mmio);
|
||||
|
@ -131,7 +131,7 @@ static int pdr_register_listener(struct pdr_handle *pdr,
|
||||
return ret;
|
||||
|
||||
req.enable = enable;
|
||||
strcpy(req.service_path, pds->service_path);
|
||||
strscpy(req.service_path, pds->service_path, sizeof(req.service_path));
|
||||
|
||||
ret = qmi_send_request(&pdr->notifier_hdl, &pds->addr,
|
||||
&txn, SERVREG_REGISTER_LISTENER_REQ,
|
||||
@ -257,7 +257,7 @@ static int pdr_send_indack_msg(struct pdr_handle *pdr, struct pdr_service *pds,
|
||||
return ret;
|
||||
|
||||
req.transaction_id = tid;
|
||||
strcpy(req.service_path, pds->service_path);
|
||||
strscpy(req.service_path, pds->service_path, sizeof(req.service_path));
|
||||
|
||||
ret = qmi_send_request(&pdr->notifier_hdl, &pds->addr,
|
||||
&txn, SERVREG_SET_ACK_REQ,
|
||||
@ -406,7 +406,7 @@ static int pdr_locate_service(struct pdr_handle *pdr, struct pdr_service *pds)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Prepare req message */
|
||||
strcpy(req.service_name, pds->service_name);
|
||||
strscpy(req.service_name, pds->service_name, sizeof(req.service_name));
|
||||
req.domain_offset_valid = true;
|
||||
req.domain_offset = 0;
|
||||
|
||||
@ -531,8 +531,8 @@ struct pdr_service *pdr_add_lookup(struct pdr_handle *pdr,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pds->service = SERVREG_NOTIFIER_SERVICE;
|
||||
strcpy(pds->service_name, service_name);
|
||||
strcpy(pds->service_path, service_path);
|
||||
strscpy(pds->service_name, service_name, sizeof(pds->service_name));
|
||||
strscpy(pds->service_path, service_path, sizeof(pds->service_path));
|
||||
pds->need_locator_lookup = true;
|
||||
|
||||
mutex_lock(&pdr->list_lock);
|
||||
@ -587,7 +587,7 @@ int pdr_restart_pd(struct pdr_handle *pdr, struct pdr_service *pds)
|
||||
break;
|
||||
|
||||
/* Prepare req message */
|
||||
strcpy(req.service_path, pds->service_path);
|
||||
strscpy(req.service_path, pds->service_path, sizeof(req.service_path));
|
||||
addr = pds->addr;
|
||||
break;
|
||||
}
|
||||
|
@ -871,7 +871,6 @@ EXPORT_SYMBOL(geni_icc_disable);
|
||||
static int geni_se_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
struct geni_wrapper *wrapper;
|
||||
int ret;
|
||||
|
||||
@ -880,8 +879,7 @@ static int geni_se_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
wrapper->dev = dev;
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
wrapper->base = devm_ioremap_resource(dev, res);
|
||||
wrapper->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(wrapper->base))
|
||||
return PTR_ERR(wrapper->base);
|
||||
|
||||
|
@ -2,16 +2,16 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Linaro Ltd
|
||||
*/
|
||||
#include <dt-bindings/power/qcom-aoss-qmp.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/soc/qcom/qcom_aoss.h>
|
||||
|
||||
#define QMP_DESC_MAGIC 0x0
|
||||
#define QMP_DESC_VERSION 0x4
|
||||
@ -64,7 +64,6 @@ struct qmp_cooling_device {
|
||||
* @event: wait_queue for synchronization with the IRQ
|
||||
* @tx_lock: provides synchronization between multiple callers of qmp_send()
|
||||
* @qdss_clk: QDSS clock hw struct
|
||||
* @pd_data: genpd data
|
||||
* @cooling_devs: thermal cooling devices
|
||||
*/
|
||||
struct qmp {
|
||||
@ -82,17 +81,9 @@ struct qmp {
|
||||
struct mutex tx_lock;
|
||||
|
||||
struct clk_hw qdss_clk;
|
||||
struct genpd_onecell_data pd_data;
|
||||
struct qmp_cooling_device *cooling_devs;
|
||||
};
|
||||
|
||||
struct qmp_pd {
|
||||
struct qmp *qmp;
|
||||
struct generic_pm_domain pd;
|
||||
};
|
||||
|
||||
#define to_qmp_pd_resource(res) container_of(res, struct qmp_pd, pd)
|
||||
|
||||
static void qmp_kick(struct qmp *qmp)
|
||||
{
|
||||
mbox_send_message(qmp->mbox_chan, NULL);
|
||||
@ -223,11 +214,14 @@ static bool qmp_message_empty(struct qmp *qmp)
|
||||
*
|
||||
* Return: 0 on success, negative errno on failure
|
||||
*/
|
||||
static int qmp_send(struct qmp *qmp, const void *data, size_t len)
|
||||
int qmp_send(struct qmp *qmp, const void *data, size_t len)
|
||||
{
|
||||
long time_left;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(IS_ERR_OR_NULL(qmp) || !data))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON(len + sizeof(u32) > qmp->size))
|
||||
return -EINVAL;
|
||||
|
||||
@ -261,6 +255,7 @@ static int qmp_send(struct qmp *qmp, const void *data, size_t len)
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(qmp_send);
|
||||
|
||||
static int qmp_qdss_clk_prepare(struct clk_hw *hw)
|
||||
{
|
||||
@ -314,95 +309,6 @@ static void qmp_qdss_clk_remove(struct qmp *qmp)
|
||||
clk_hw_unregister(&qmp->qdss_clk);
|
||||
}
|
||||
|
||||
static int qmp_pd_power_toggle(struct qmp_pd *res, bool enable)
|
||||
{
|
||||
char buf[QMP_MSG_LEN] = {};
|
||||
|
||||
snprintf(buf, sizeof(buf),
|
||||
"{class: image, res: load_state, name: %s, val: %s}",
|
||||
res->pd.name, enable ? "on" : "off");
|
||||
return qmp_send(res->qmp, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static int qmp_pd_power_on(struct generic_pm_domain *domain)
|
||||
{
|
||||
return qmp_pd_power_toggle(to_qmp_pd_resource(domain), true);
|
||||
}
|
||||
|
||||
static int qmp_pd_power_off(struct generic_pm_domain *domain)
|
||||
{
|
||||
return qmp_pd_power_toggle(to_qmp_pd_resource(domain), false);
|
||||
}
|
||||
|
||||
static const char * const sdm845_resources[] = {
|
||||
[AOSS_QMP_LS_CDSP] = "cdsp",
|
||||
[AOSS_QMP_LS_LPASS] = "adsp",
|
||||
[AOSS_QMP_LS_MODEM] = "modem",
|
||||
[AOSS_QMP_LS_SLPI] = "slpi",
|
||||
[AOSS_QMP_LS_SPSS] = "spss",
|
||||
[AOSS_QMP_LS_VENUS] = "venus",
|
||||
};
|
||||
|
||||
static int qmp_pd_add(struct qmp *qmp)
|
||||
{
|
||||
struct genpd_onecell_data *data = &qmp->pd_data;
|
||||
struct device *dev = qmp->dev;
|
||||
struct qmp_pd *res;
|
||||
size_t num = ARRAY_SIZE(sdm845_resources);
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
res = devm_kcalloc(dev, num, sizeof(*res), GFP_KERNEL);
|
||||
if (!res)
|
||||
return -ENOMEM;
|
||||
|
||||
data->domains = devm_kcalloc(dev, num, sizeof(*data->domains),
|
||||
GFP_KERNEL);
|
||||
if (!data->domains)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
res[i].qmp = qmp;
|
||||
res[i].pd.name = sdm845_resources[i];
|
||||
res[i].pd.power_on = qmp_pd_power_on;
|
||||
res[i].pd.power_off = qmp_pd_power_off;
|
||||
|
||||
ret = pm_genpd_init(&res[i].pd, NULL, true);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to init genpd\n");
|
||||
goto unroll_genpds;
|
||||
}
|
||||
|
||||
data->domains[i] = &res[i].pd;
|
||||
}
|
||||
|
||||
data->num_domains = i;
|
||||
|
||||
ret = of_genpd_add_provider_onecell(dev->of_node, data);
|
||||
if (ret < 0)
|
||||
goto unroll_genpds;
|
||||
|
||||
return 0;
|
||||
|
||||
unroll_genpds:
|
||||
for (i--; i >= 0; i--)
|
||||
pm_genpd_remove(data->domains[i]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qmp_pd_remove(struct qmp *qmp)
|
||||
{
|
||||
struct genpd_onecell_data *data = &qmp->pd_data;
|
||||
struct device *dev = qmp->dev;
|
||||
int i;
|
||||
|
||||
of_genpd_del_provider(dev->of_node);
|
||||
|
||||
for (i = 0; i < data->num_domains; i++)
|
||||
pm_genpd_remove(data->domains[i]);
|
||||
}
|
||||
|
||||
static int qmp_cdev_get_max_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
@ -519,9 +425,53 @@ static void qmp_cooling_devices_remove(struct qmp *qmp)
|
||||
thermal_cooling_device_unregister(qmp->cooling_devs[i].cdev);
|
||||
}
|
||||
|
||||
/**
|
||||
* qmp_get() - get a qmp handle from a device
|
||||
* @dev: client device pointer
|
||||
*
|
||||
* Return: handle to qmp device on success, ERR_PTR() on failure
|
||||
*/
|
||||
struct qmp *qmp_get(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct device_node *np;
|
||||
struct qmp *qmp;
|
||||
|
||||
if (!dev || !dev->of_node)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
np = of_parse_phandle(dev->of_node, "qcom,qmp", 0);
|
||||
if (!np)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
pdev = of_find_device_by_node(np);
|
||||
of_node_put(np);
|
||||
if (!pdev)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
qmp = platform_get_drvdata(pdev);
|
||||
|
||||
return qmp ? qmp : ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
EXPORT_SYMBOL(qmp_get);
|
||||
|
||||
/**
|
||||
* qmp_put() - release a qmp handle
|
||||
* @qmp: qmp handle obtained from qmp_get()
|
||||
*/
|
||||
void qmp_put(struct qmp *qmp)
|
||||
{
|
||||
/*
|
||||
* Match get_device() inside of_find_device_by_node() in
|
||||
* qmp_get()
|
||||
*/
|
||||
if (!IS_ERR_OR_NULL(qmp))
|
||||
put_device(qmp->dev);
|
||||
}
|
||||
EXPORT_SYMBOL(qmp_put);
|
||||
|
||||
static int qmp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct qmp *qmp;
|
||||
int irq;
|
||||
int ret;
|
||||
@ -534,8 +484,7 @@ static int qmp_probe(struct platform_device *pdev)
|
||||
init_waitqueue_head(&qmp->event);
|
||||
mutex_init(&qmp->tx_lock);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
qmp->msgram = devm_ioremap_resource(&pdev->dev, res);
|
||||
qmp->msgram = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(qmp->msgram))
|
||||
return PTR_ERR(qmp->msgram);
|
||||
|
||||
@ -563,10 +512,6 @@ static int qmp_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto err_close_qmp;
|
||||
|
||||
ret = qmp_pd_add(qmp);
|
||||
if (ret)
|
||||
goto err_remove_qdss_clk;
|
||||
|
||||
ret = qmp_cooling_devices_register(qmp);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "failed to register aoss cooling devices\n");
|
||||
@ -575,8 +520,6 @@ static int qmp_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_qdss_clk:
|
||||
qmp_qdss_clk_remove(qmp);
|
||||
err_close_qmp:
|
||||
qmp_close(qmp);
|
||||
err_free_mbox:
|
||||
@ -590,7 +533,6 @@ static int qmp_remove(struct platform_device *pdev)
|
||||
struct qmp *qmp = platform_get_drvdata(pdev);
|
||||
|
||||
qmp_qdss_clk_remove(qmp);
|
||||
qmp_pd_remove(qmp);
|
||||
qmp_cooling_devices_remove(qmp);
|
||||
|
||||
qmp_close(qmp);
|
||||
@ -615,6 +557,7 @@ static struct platform_driver qmp_driver = {
|
||||
.driver = {
|
||||
.name = "qcom_aoss_qmp",
|
||||
.of_match_table = qmp_dt_match,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = qmp_probe,
|
||||
.remove = qmp_remove,
|
||||
|
@ -127,7 +127,6 @@ static int gsbi_probe(struct platform_device *pdev)
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct device_node *tcsr_node;
|
||||
const struct of_device_id *match;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
struct gsbi_info *gsbi;
|
||||
int i, ret;
|
||||
@ -139,8 +138,7 @@ static int gsbi_probe(struct platform_device *pdev)
|
||||
if (!gsbi)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user