ARM: SoC-related driver updates
Various driver updates for platforms: - A larger set of work on Tegra 2/3 around memory controller and regulator features, some fuse cleanups, etc.. - MMP platform drivers, in particular for USB PHY, and other smaller additions. - Samsung Exynos 5422 driver for DMC (dynamic memory configuration), and ASV (adaptive voltage), allowing the platform to run at more optimal operating points. - Misc refactorings and support for RZ/G2N and R8A774B1 from Renesas - Clock/reset control driver for TI/OMAP - Meson-A1 reset controller support - Qualcomm sdm845 and sda845 SoC IDs for socinfo -----BEGIN PGP SIGNATURE----- iQJDBAABCAAtFiEElf+HevZ4QCAJmMQ+jBrnPN6EHHcFAl3pORkPHG9sb2ZAbGl4 b20ubmV0AAoJEIwa5zzehBx3FK0P/0EG4lK+il7nE3pd9yIGUjlcYuumIjoxvyC9 9ef202POJLIO3yMlsNyGFR+aOknFO/GtGvDkDFhTtlsGCL40tVzVsyo7ZQo+8mXD abr+H74NmRXImc+SISYR8X1CD6vEi3oi/no1y5dRzknlBikfsdSLKXJSMYBJ2A6t DNLwu0h1IZhPk7XQQsxaElG/a9HN8eueMdP20J1IlhOh0GiOwm+rbsLSZNbA/W9m 53XhFs3Ag39SDE0BfXsS+XOWTE7FheZsZk2XQrOwYm9PnxjpIWH7FE2sYsk6uUIc Pa1b6wB5zlRnxvVHP0m3GXhbTUJDYDK3oybHffI4Mzd0cyZQHC92LhUXFrlTxkaf 6kyhJOTdd5KMlZ2LS7jkwLqb30ieXBPKAREjdbRt6hpvu5P6G+bZQphTEeNAZC61 XnX8mQ/XeoHdoGY5MvS8ht6a1qDF29ebA0/02seicThGK6tS9Qsju6Zo0sg9H1NH weK6jDuzLq5jpv/LB1apigrDSx+zddRzrwkwy85hR5aWOQhG0xjOoFBProbTS0to wR46zCEkbGZv4uc0gRuIdp0NR/lguqgDWPeoLluoTqmcpKS6N3RyxD0bWzlvgDFA fpYxVNKavHneWjfZ7U5RbYXD6jycJcuLaCOs16nrtUbMgJ9pqclLIaZXn7ZTRIuT RW6NgfZV =dk7w -----END PGP SIGNATURE----- Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc Pull ARM SoC driver updates from Olof Johansson: "Various driver updates for platforms: - A larger set of work on Tegra 2/3 around memory controller and regulator features, some fuse cleanups, etc.. - MMP platform drivers, in particular for USB PHY, and other smaller additions. - Samsung Exynos 5422 driver for DMC (dynamic memory configuration), and ASV (adaptive voltage), allowing the platform to run at more optimal operating points. - Misc refactorings and support for RZ/G2N and R8A774B1 from Renesas - Clock/reset control driver for TI/OMAP - Meson-A1 reset controller support - Qualcomm sdm845 and sda845 SoC IDs for socinfo" * tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (150 commits) firmware: arm_scmi: Fix doorbell ring logic for !CONFIG_64BIT soc: fsl: add RCPM driver dt-bindings: fsl: rcpm: Add 'little-endian' and update Chassis definition memory: tegra: Consolidate registers definition into common header memory: tegra: Ensure timing control debug features are disabled memory: tegra: Introduce Tegra30 EMC driver memory: tegra: Do not handle error from wait_for_completion_timeout() memory: tegra: Increase handshake timeout on Tegra20 memory: tegra: Print a brief info message about EMC timings memory: tegra: Pre-configure debug register on Tegra20 memory: tegra: Include io.h instead of iopoll.h memory: tegra: Adapt for Tegra20 clock driver changes memory: tegra: Don't set EMC rate to maximum on probe for Tegra20 memory: tegra: Add gr2d and gr3d to DRM IOMMU group memory: tegra: Set DMA mask based on supported address bits soc: at91: Add Atmel SFR SN (Serial Number) support memory: atmel-ebi: switch to SPDX license identifiers memory: atmel-ebi: move NUM_CS definition inside EBI driver soc: mediatek: Refactor bus protection control soc: mediatek: Refactor sram control ...
This commit is contained in:
Коммит
ec939e4c94
|
@ -103,7 +103,7 @@ the Microchip website: http://www.microchip.com.
|
|||
|
||||
* Datasheet
|
||||
|
||||
http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11121-32-bit-Cortex-A5-Microcontroller-SAMA5D3_Datasheet.pdf
|
||||
http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11121-32-bit-Cortex-A5-Microcontroller-SAMA5D3_Datasheet_B.pdf
|
||||
|
||||
* ARM Cortex-A5 + NEON based SoCs
|
||||
- sama5d4 family
|
||||
|
@ -167,7 +167,7 @@ the Microchip website: http://www.microchip.com.
|
|||
|
||||
* Datasheet
|
||||
|
||||
http://ww1.microchip.com/downloads/en/DeviceDoc/60001527A.pdf
|
||||
http://ww1.microchip.com/downloads/en/DeviceDoc/SAM-E70-S70-V70-V71-Family-Data-Sheet-DS60001527D.pdf
|
||||
|
||||
|
||||
Linux kernel information
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
== Introduction==
|
||||
|
||||
LLCC (Last Level Cache Controller) provides last level of cache memory in SOC,
|
||||
that can be shared by multiple clients. Clients here are different cores in the
|
||||
SOC, the idea is to minimize the local caches at the clients and migrate to
|
||||
common pool of memory. Cache memory is divided into partitions called slices
|
||||
which are assigned to clients. Clients can query the slice details, activate
|
||||
and deactivate them.
|
||||
|
||||
Properties:
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: must be "qcom,sdm845-llcc"
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
Value Type: <prop-encoded-array>
|
||||
Definition: The first element specifies the llcc base start address and
|
||||
the size of the register region. The second element specifies
|
||||
the llcc broadcast base address and size of the register region.
|
||||
|
||||
- reg-names:
|
||||
Usage: required
|
||||
Value Type: <stringlist>
|
||||
Definition: Register region names. Must be "llcc_base", "llcc_broadcast_base".
|
||||
|
||||
- interrupts:
|
||||
Usage: required
|
||||
Definition: The interrupt is associated with the llcc edac device.
|
||||
It's used for llcc cache single and double bit error detection
|
||||
and reporting.
|
||||
|
||||
Example:
|
||||
|
||||
cache-controller@1100000 {
|
||||
compatible = "qcom,sdm845-llcc";
|
||||
reg = <0x1100000 0x200000>, <0x1300000 0x50000> ;
|
||||
reg-names = "llcc_base", "llcc_broadcast_base";
|
||||
interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
|
@ -0,0 +1,55 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/arm/msm/qcom,llcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Last Level Cache Controller
|
||||
|
||||
maintainers:
|
||||
- Rishabh Bhatnagar <rishabhb@codeaurora.org>
|
||||
- Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
|
||||
|
||||
description: |
|
||||
LLCC (Last Level Cache Controller) provides last level of cache memory in SoC,
|
||||
that can be shared by multiple clients. Clients here are different cores in the
|
||||
SoC, the idea is to minimize the local caches at the clients and migrate to
|
||||
common pool of memory. Cache memory is divided into partitions called slices
|
||||
which are assigned to clients. Clients can query the slice details, activate
|
||||
and deactivate them.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sc7180-llcc
|
||||
- qcom,sdm845-llcc
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: LLCC base register region
|
||||
- description: LLCC broadcast base register region
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: llcc_base
|
||||
- const: llcc_broadcast_base
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
cache-controller@1100000 {
|
||||
compatible = "qcom,sdm845-llcc";
|
||||
reg = <0x1100000 0x200000>, <0x1300000 0x50000> ;
|
||||
reg-names = "llcc_base", "llcc_broadcast_base";
|
||||
interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
OMAP PRM instance bindings
|
||||
|
||||
Power and Reset Manager is an IP block on OMAP family of devices which
|
||||
handle the power domains and their current state, and provide reset
|
||||
handling for the domains and/or separate IP blocks under the power domain
|
||||
hierarchy.
|
||||
|
||||
Required properties:
|
||||
- compatible: Must contain one of the following:
|
||||
"ti,am3-prm-inst"
|
||||
"ti,am4-prm-inst"
|
||||
"ti,omap4-prm-inst"
|
||||
"ti,omap5-prm-inst"
|
||||
"ti,dra7-prm-inst"
|
||||
and additionally must contain:
|
||||
"ti,omap-prm-inst"
|
||||
- reg: Contains PRM instance register address range
|
||||
(base address and length)
|
||||
|
||||
Optional properties:
|
||||
- #reset-cells: Should be 1 if the PRM instance in question supports resets.
|
||||
|
||||
Example:
|
||||
|
||||
prm_dsp2: prm@1b00 {
|
||||
compatible = "ti,dra7-prm-inst", "ti,omap-prm-inst";
|
||||
reg = <0x1b00 0x40>;
|
||||
#reset-cells = <1>;
|
||||
};
|
|
@ -11,7 +11,9 @@ power management service, FPGA service and other platform management
|
|||
services.
|
||||
|
||||
Required properties:
|
||||
- compatible: Must contain: "xlnx,zynqmp-firmware"
|
||||
- compatible: Must contain any of below:
|
||||
"xlnx,zynqmp-firmware" for Zynq Ultrascale+ MPSoC
|
||||
"xlnx,versal-firmware" for Versal
|
||||
- method: The method of calling the PM-API firmware layer.
|
||||
Permitted values are:
|
||||
- "smc" : SMC #0, following the SMCCC
|
||||
|
@ -21,6 +23,8 @@ Required properties:
|
|||
Example
|
||||
-------
|
||||
|
||||
Zynq Ultrascale+ MPSoC
|
||||
----------------------
|
||||
firmware {
|
||||
zynqmp_firmware: zynqmp-firmware {
|
||||
compatible = "xlnx,zynqmp-firmware";
|
||||
|
@ -28,3 +32,13 @@ firmware {
|
|||
...
|
||||
};
|
||||
};
|
||||
|
||||
Versal
|
||||
------
|
||||
firmware {
|
||||
versal_firmware: versal-firmware {
|
||||
compatible = "xlnx,versal-firmware";
|
||||
method = "smc";
|
||||
...
|
||||
};
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@ Required properties:
|
|||
- compatible: should be "amlogic,meson-gxbb-efuse"
|
||||
- clocks: phandle to the efuse peripheral clock provided by the
|
||||
clock controller.
|
||||
- secure-monitor: phandle to the secure-monitor node
|
||||
|
||||
= Data cells =
|
||||
Are child nodes of eFuse, bindings of which as described in
|
||||
|
@ -16,6 +17,7 @@ Example:
|
|||
clocks = <&clkc CLKID_EFUSE>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
secure-monitor = <&sm>;
|
||||
|
||||
sn: sn@14 {
|
||||
reg = <0x14 0x10>;
|
||||
|
@ -30,6 +32,10 @@ Example:
|
|||
};
|
||||
};
|
||||
|
||||
sm: secure-monitor {
|
||||
compatible = "amlogic,meson-gxbb-sm";
|
||||
};
|
||||
|
||||
= Data consumers =
|
||||
Are device nodes which consume nvmem data cells.
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ which then translates it into a corresponding voltage on a rail
|
|||
|
||||
Required Properties:
|
||||
- compatible: Should be one of the following
|
||||
* qcom,msm8976-rpmpd: RPM Power domain for the msm8976 family of SoC
|
||||
* qcom,msm8996-rpmpd: RPM Power domain for the msm8996 family of SoC
|
||||
* qcom,msm8998-rpmpd: RPM Power domain for the msm8998 family of SoC
|
||||
* qcom,qcs404-rpmpd: RPM Power domain for the qcs404 family of SoC
|
||||
|
|
|
@ -4,7 +4,8 @@ The Amlogic Audio ARB is a simple device which enables or
|
|||
disables the access of Audio FIFOs to DDR on AXG based SoC.
|
||||
|
||||
Required properties:
|
||||
- compatible: 'amlogic,meson-axg-audio-arb'
|
||||
- compatible: 'amlogic,meson-axg-audio-arb' or
|
||||
'amlogic,meson-sm1-audio-arb'
|
||||
- reg: physical base address of the controller and length of memory
|
||||
mapped region.
|
||||
- clocks: phandle to the fifo peripheral clock provided by the audio
|
||||
|
|
|
@ -16,6 +16,7 @@ properties:
|
|||
- amlogic,meson8b-reset # Reset Controller on Meson8b and compatible SoCs
|
||||
- amlogic,meson-gxbb-reset # Reset Controller on GXBB and compatible SoCs
|
||||
- amlogic,meson-axg-reset # Reset Controller on AXG and compatible SoCs
|
||||
- amlogic,meson-a1-reset # Reset Controller on A1 and compatible SoCs
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
Qualcomm AOSS Reset Controller
|
||||
======================================
|
||||
|
||||
This binding describes a reset-controller found on AOSS-CC (always on subsystem)
|
||||
for Qualcomm SDM845 SoCs.
|
||||
|
||||
Required properties:
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: must be:
|
||||
"qcom,sdm845-aoss-cc"
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: must specify the base address and size of the register
|
||||
space.
|
||||
|
||||
- #reset-cells:
|
||||
Usage: required
|
||||
Value type: <uint>
|
||||
Definition: must be 1; cell entry represents the reset index.
|
||||
|
||||
Example:
|
||||
|
||||
aoss_reset: reset-controller@c2a0000 {
|
||||
compatible = "qcom,sdm845-aoss-cc";
|
||||
reg = <0xc2a0000 0x31000>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
Specifying reset lines connected to IP modules
|
||||
==============================================
|
||||
|
||||
Device nodes that need access to reset lines should
|
||||
specify them as a reset phandle in their corresponding node as
|
||||
specified in reset.txt.
|
||||
|
||||
For list of all valid reset indicies see
|
||||
<dt-bindings/reset/qcom,sdm845-aoss.h>
|
||||
|
||||
Example:
|
||||
|
||||
modem-pil@4080000 {
|
||||
...
|
||||
|
||||
resets = <&aoss_reset AOSS_CC_MSS_RESTART>;
|
||||
reset-names = "mss_restart";
|
||||
|
||||
...
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/reset/qcom,aoss-reset.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm AOSS Reset Controller
|
||||
|
||||
maintainers:
|
||||
- Sibi Sankar <sibis@codeaurora.org>
|
||||
|
||||
description:
|
||||
The bindings describe the reset-controller found on AOSS-CC (always on
|
||||
subsystem) for Qualcomm Technologies Inc SoCs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- description: on SC7180 SoCs the following compatibles must be specified
|
||||
items:
|
||||
- const: "qcom,sc7180-aoss-cc"
|
||||
- const: "qcom,sdm845-aoss-cc"
|
||||
|
||||
- description: on SDM845 SoCs the following compatibles must be specified
|
||||
items:
|
||||
- const: "qcom,sdm845-aoss-cc"
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#reset-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
aoss_reset: reset-controller@c2a0000 {
|
||||
compatible = "qcom,sdm845-aoss-cc";
|
||||
reg = <0xc2a0000 0x31000>;
|
||||
#reset-cells = <1>;
|
||||
};
|
|
@ -1,52 +0,0 @@
|
|||
PDC Global
|
||||
======================================
|
||||
|
||||
This binding describes a reset-controller found on PDC-Global (Power Domain
|
||||
Controller) block for Qualcomm Technologies Inc SDM845 SoCs.
|
||||
|
||||
Required properties:
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: must be:
|
||||
"qcom,sdm845-pdc-global"
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: must specify the base address and size of the register
|
||||
space.
|
||||
|
||||
- #reset-cells:
|
||||
Usage: required
|
||||
Value type: <uint>
|
||||
Definition: must be 1; cell entry represents the reset index.
|
||||
|
||||
Example:
|
||||
|
||||
pdc_reset: reset-controller@b2e0000 {
|
||||
compatible = "qcom,sdm845-pdc-global";
|
||||
reg = <0xb2e0000 0x20000>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
PDC reset clients
|
||||
======================================
|
||||
|
||||
Device nodes that need access to reset lines should
|
||||
specify them as a reset phandle in their corresponding node as
|
||||
specified in reset.txt.
|
||||
|
||||
For a list of all valid reset indices see
|
||||
<dt-bindings/reset/qcom,sdm845-pdc.h>
|
||||
|
||||
Example:
|
||||
|
||||
modem-pil@4080000 {
|
||||
...
|
||||
|
||||
resets = <&pdc_reset PDC_MODEM_SYNC_RESET>;
|
||||
reset-names = "pdc_reset";
|
||||
|
||||
...
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/reset/qcom,pdc-global.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm PDC Global
|
||||
|
||||
maintainers:
|
||||
- Sibi Sankar <sibis@codeaurora.org>
|
||||
|
||||
description:
|
||||
The bindings describes the reset-controller found on PDC-Global (Power Domain
|
||||
Controller) block for Qualcomm Technologies Inc SoCs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- description: on SC7180 SoCs the following compatibles must be specified
|
||||
items:
|
||||
- const: "qcom,sc7180-pdc-global"
|
||||
- const: "qcom,sdm845-pdc-global"
|
||||
|
||||
- description: on SDM845 SoCs the following compatibles must be specified
|
||||
items:
|
||||
- const: "qcom,sdm845-pdc-global"
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#reset-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
pdc_reset: reset-controller@b2e0000 {
|
||||
compatible = "qcom,sdm845-pdc-global";
|
||||
reg = <0xb2e0000 0x20000>;
|
||||
#reset-cells = <1>;
|
||||
};
|
|
@ -130,6 +130,7 @@ this layer. These clocks and resets should be described in each property.
|
|||
Required properties:
|
||||
- compatible: Should be
|
||||
"socionext,uniphier-pro4-usb3-reset" - for Pro4 SoC USB3
|
||||
"socionext,uniphier-pro5-usb3-reset" - for Pro5 SoC USB3
|
||||
"socionext,uniphier-pxs2-usb3-reset" - for PXs2 SoC USB3
|
||||
"socionext,uniphier-ld20-usb3-reset" - for LD20 SoC USB3
|
||||
"socionext,uniphier-pxs3-usb3-reset" - for PXs3 SoC USB3
|
||||
|
@ -141,12 +142,12 @@ Required properties:
|
|||
- clocks: A list of phandles to the clock gate for the glue layer.
|
||||
According to the clock-names, appropriate clocks are required.
|
||||
- clock-names: Should contain
|
||||
"gio", "link" - for Pro4 SoC
|
||||
"gio", "link" - for Pro4 and Pro5 SoCs
|
||||
"link" - for others
|
||||
- resets: A list of phandles to the reset control for the glue layer.
|
||||
According to the reset-names, appropriate resets are required.
|
||||
- reset-names: Should contain
|
||||
"gio", "link" - for Pro4 SoC
|
||||
"gio", "link" - for Pro4 and Pro5 SoCs
|
||||
"link" - for others
|
||||
|
||||
Example:
|
||||
|
|
|
@ -5,7 +5,7 @@ and power management.
|
|||
|
||||
Required properites:
|
||||
- reg : Offset and length of the register set of the RCPM block.
|
||||
- fsl,#rcpm-wakeup-cells : The number of IPPDEXPCR register cells in the
|
||||
- #fsl,rcpm-wakeup-cells : The number of IPPDEXPCR register cells in the
|
||||
fsl,rcpm-wakeup property.
|
||||
- compatible : Must contain a chip-specific RCPM block compatible string
|
||||
and (if applicable) may contain a chassis-version RCPM compatible
|
||||
|
@ -20,6 +20,7 @@ Required properites:
|
|||
* "fsl,qoriq-rcpm-1.0": for chassis 1.0 rcpm
|
||||
* "fsl,qoriq-rcpm-2.0": for chassis 2.0 rcpm
|
||||
* "fsl,qoriq-rcpm-2.1": for chassis 2.1 rcpm
|
||||
* "fsl,qoriq-rcpm-2.1+": for chassis 2.1+ rcpm
|
||||
|
||||
All references to "1.0" and "2.0" refer to the QorIQ chassis version to
|
||||
which the chip complies.
|
||||
|
@ -27,14 +28,19 @@ Chassis Version Example Chips
|
|||
--------------- -------------------------------
|
||||
1.0 p4080, p5020, p5040, p2041, p3041
|
||||
2.0 t4240, b4860, b4420
|
||||
2.1 t1040, ls1021
|
||||
2.1 t1040,
|
||||
2.1+ ls1021a, ls1012a, ls1043a, ls1046a
|
||||
|
||||
Optional properties:
|
||||
- little-endian : RCPM register block is Little Endian. Without it RCPM
|
||||
will be Big Endian (default case).
|
||||
|
||||
Example:
|
||||
The RCPM node for T4240:
|
||||
rcpm: global-utilities@e2000 {
|
||||
compatible = "fsl,t4240-rcpm", "fsl,qoriq-rcpm-2.0";
|
||||
reg = <0xe2000 0x1000>;
|
||||
fsl,#rcpm-wakeup-cells = <2>;
|
||||
#fsl,rcpm-wakeup-cells = <2>;
|
||||
};
|
||||
|
||||
* Freescale RCPM Wakeup Source Device Tree Bindings
|
||||
|
@ -44,7 +50,7 @@ can be used as a wakeup source.
|
|||
|
||||
- fsl,rcpm-wakeup: Consists of a phandle to the rcpm node and the IPPDEXPCR
|
||||
register cells. The number of IPPDEXPCR register cells is defined in
|
||||
"fsl,#rcpm-wakeup-cells" in the rcpm node. The first register cell is
|
||||
"#fsl,rcpm-wakeup-cells" in the rcpm node. The first register cell is
|
||||
the bit mask that should be set in IPPDEXPCR0, and the second register
|
||||
cell is for IPPDEXPCR1, and so on.
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ resources.
|
|||
"qcom,rpm-apq8084"
|
||||
"qcom,rpm-msm8916"
|
||||
"qcom,rpm-msm8974"
|
||||
"qcom,rpm-msm8976"
|
||||
"qcom,rpm-msm8998"
|
||||
"qcom,rpm-sdm660"
|
||||
"qcom,rpm-qcs404"
|
||||
|
|
17
MAINTAINERS
17
MAINTAINERS
|
@ -2140,6 +2140,7 @@ S: Maintained
|
|||
|
||||
ARM/QUALCOMM SUPPORT
|
||||
M: Andy Gross <agross@kernel.org>
|
||||
M: Bjorn Andersson <bjorn.andersson@linaro.org>
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/soc/qcom/
|
||||
|
@ -5001,6 +5002,14 @@ F: include/linux/dma-direct.h
|
|||
F: include/linux/dma-mapping.h
|
||||
F: include/linux/dma-noncoherent.h
|
||||
|
||||
DMC FREQUENCY DRIVER FOR SAMSUNG EXYNOS5422
|
||||
M: Lukasz Luba <l.luba@partner.samsung.com>
|
||||
L: linux-pm@vger.kernel.org
|
||||
L: linux-samsung-soc@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/memory/samsung/exynos5422-dmc.c
|
||||
F: Documentation/devicetree/bindings/memory-controllers/exynos5422-dmc.txt
|
||||
|
||||
DME1737 HARDWARE MONITOR DRIVER
|
||||
M: Juerg Haefliger <juergh@gmail.com>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
|
@ -11066,6 +11075,13 @@ F: arch/arm/boot/dts/mmp*
|
|||
F: arch/arm/mach-mmp/
|
||||
F: linux/soc/mmp/
|
||||
|
||||
MMP USB PHY DRIVERS
|
||||
R: Lubomir Rintel <lkundrak@v3.sk>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: drivers/phy/marvell/phy-mmp3-usb.c
|
||||
F: drivers/phy/marvell/phy-pxa-usb.c
|
||||
|
||||
MMU GATHER AND TLB INVALIDATION
|
||||
M: Will Deacon <will@kernel.org>
|
||||
M: "Aneesh Kumar K.V" <aneesh.kumar@linux.ibm.com>
|
||||
|
@ -14033,6 +14049,7 @@ F: include/dt-bindings/reset/
|
|||
F: include/linux/reset.h
|
||||
F: include/linux/reset/
|
||||
F: include/linux/reset-controller.h
|
||||
K: \b(?:devm_|of_)?reset_control(?:ler_[a-z]+|_[a-z_]+)?\b
|
||||
|
||||
RESTARTABLE SEQUENCES SUPPORT
|
||||
M: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
||||
|
|
|
@ -109,6 +109,7 @@ config ARCH_OMAP2PLUS
|
|||
select TI_SYSC
|
||||
select OMAP_IRQCHIP
|
||||
select CLKSRC_TI_32K
|
||||
select ARCH_HAS_RESET_CONTROLLER
|
||||
help
|
||||
Systems based on OMAP2, OMAP3, OMAP4 or OMAP5
|
||||
|
||||
|
|
|
@ -247,6 +247,60 @@ void wakeup_source_unregister(struct wakeup_source *ws)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(wakeup_source_unregister);
|
||||
|
||||
/**
|
||||
* wakeup_sources_read_lock - Lock wakeup source list for read.
|
||||
*
|
||||
* Returns an index of srcu lock for struct wakeup_srcu.
|
||||
* This index must be passed to the matching wakeup_sources_read_unlock().
|
||||
*/
|
||||
int wakeup_sources_read_lock(void)
|
||||
{
|
||||
return srcu_read_lock(&wakeup_srcu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wakeup_sources_read_lock);
|
||||
|
||||
/**
|
||||
* wakeup_sources_read_unlock - Unlock wakeup source list.
|
||||
* @idx: return value from corresponding wakeup_sources_read_lock()
|
||||
*/
|
||||
void wakeup_sources_read_unlock(int idx)
|
||||
{
|
||||
srcu_read_unlock(&wakeup_srcu, idx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wakeup_sources_read_unlock);
|
||||
|
||||
/**
|
||||
* wakeup_sources_walk_start - Begin a walk on wakeup source list
|
||||
*
|
||||
* Returns first object of the list of wakeup sources.
|
||||
*
|
||||
* Note that to be safe, wakeup sources list needs to be locked by calling
|
||||
* wakeup_source_read_lock() for this.
|
||||
*/
|
||||
struct wakeup_source *wakeup_sources_walk_start(void)
|
||||
{
|
||||
struct list_head *ws_head = &wakeup_sources;
|
||||
|
||||
return list_entry_rcu(ws_head->next, struct wakeup_source, entry);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wakeup_sources_walk_start);
|
||||
|
||||
/**
|
||||
* wakeup_sources_walk_next - Get next wakeup source from the list
|
||||
* @ws: Previous wakeup source object
|
||||
*
|
||||
* Note that to be safe, wakeup sources list needs to be locked by calling
|
||||
* wakeup_source_read_lock() for this.
|
||||
*/
|
||||
struct wakeup_source *wakeup_sources_walk_next(struct wakeup_source *ws)
|
||||
{
|
||||
struct list_head *ws_head = &wakeup_sources;
|
||||
|
||||
return list_next_or_null_rcu(ws_head, &ws->entry,
|
||||
struct wakeup_source, entry);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wakeup_sources_walk_next);
|
||||
|
||||
/**
|
||||
* device_wakeup_attach - Attach a wakeup source object to a device object.
|
||||
* @dev: Device to handle.
|
||||
|
|
|
@ -41,8 +41,9 @@ config MOXTET
|
|||
|
||||
config HISILICON_LPC
|
||||
bool "Support for ISA I/O space on HiSilicon Hip06/7"
|
||||
depends on ARM64 && (ARCH_HISI || COMPILE_TEST)
|
||||
select INDIRECT_PIO
|
||||
depends on (ARM64 && ARCH_HISI) || (COMPILE_TEST && !ALPHA && !HEXAGON && !PARISC && !C6X)
|
||||
depends on HAS_IOMEM
|
||||
select INDIRECT_PIO if ARM64
|
||||
help
|
||||
Driver to enable I/O access to devices attached to the Low Pin
|
||||
Count bus on the HiSilicon Hip06/7 SoC.
|
||||
|
|
|
@ -74,7 +74,7 @@ struct hisi_lpc_dev {
|
|||
/* About 10us. This is specific for single IO operations, such as inb */
|
||||
#define LPC_PEROP_WAITCNT 100
|
||||
|
||||
static int wait_lpc_idle(unsigned char *mbase, unsigned int waitcnt)
|
||||
static int wait_lpc_idle(void __iomem *mbase, unsigned int waitcnt)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
|
@ -209,7 +209,7 @@ static u32 hisi_lpc_comm_in(void *hostdata, unsigned long pio, size_t dwidth)
|
|||
struct hisi_lpc_dev *lpcdev = hostdata;
|
||||
struct lpc_cycle_para iopara;
|
||||
unsigned long addr;
|
||||
u32 rd_data = 0;
|
||||
__le32 rd_data = 0;
|
||||
int ret;
|
||||
|
||||
if (!lpcdev || !dwidth || dwidth > LPC_MAX_DWIDTH)
|
||||
|
@ -244,13 +244,12 @@ static void hisi_lpc_comm_out(void *hostdata, unsigned long pio,
|
|||
struct lpc_cycle_para iopara;
|
||||
const unsigned char *buf;
|
||||
unsigned long addr;
|
||||
__le32 _val = cpu_to_le32(val);
|
||||
|
||||
if (!lpcdev || !dwidth || dwidth > LPC_MAX_DWIDTH)
|
||||
return;
|
||||
|
||||
val = cpu_to_le32(val);
|
||||
|
||||
buf = (const unsigned char *)&val;
|
||||
buf = (const unsigned char *)&_val;
|
||||
addr = hisi_lpc_pio_to_addr(lpcdev, pio);
|
||||
|
||||
iopara.opflags = FG_INCRADDR_LPC;
|
||||
|
|
|
@ -917,6 +917,9 @@ set_midle:
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
|
||||
best_mode = SYSC_IDLE_NO;
|
||||
|
||||
reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
|
||||
reg |= best_mode << regbits->midle_shift;
|
||||
sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
|
||||
|
@ -978,6 +981,9 @@ static int sysc_disable_module(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
|
||||
best_mode = SYSC_IDLE_FORCE;
|
||||
|
||||
reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
|
||||
reg |= best_mode << regbits->midle_shift;
|
||||
sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
|
||||
|
@ -1037,8 +1043,6 @@ static int __maybe_unused sysc_runtime_resume_legacy(struct device *dev,
|
|||
struct ti_sysc_platform_data *pdata;
|
||||
int error;
|
||||
|
||||
reset_control_deassert(ddata->rsts);
|
||||
|
||||
pdata = dev_get_platdata(ddata->dev);
|
||||
if (!pdata)
|
||||
return 0;
|
||||
|
@ -1051,6 +1055,8 @@ static int __maybe_unused sysc_runtime_resume_legacy(struct device *dev,
|
|||
dev_err(dev, "%s: could not enable: %i\n",
|
||||
__func__, error);
|
||||
|
||||
reset_control_deassert(ddata->rsts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1104,8 +1110,6 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev)
|
|||
|
||||
sysc_clkdm_deny_idle(ddata);
|
||||
|
||||
reset_control_deassert(ddata->rsts);
|
||||
|
||||
if (sysc_opt_clks_needed(ddata)) {
|
||||
error = sysc_enable_opt_clocks(ddata);
|
||||
if (error)
|
||||
|
@ -1116,6 +1120,8 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev)
|
|||
if (error)
|
||||
goto err_opt_clocks;
|
||||
|
||||
reset_control_deassert(ddata->rsts);
|
||||
|
||||
if (ddata->legacy_mode) {
|
||||
error = sysc_runtime_resume_legacy(dev, ddata);
|
||||
if (error)
|
||||
|
@ -1251,6 +1257,10 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
|
|||
SYSC_QUIRK("gpu", 0x50000000, 0x14, -1, -1, 0x00010201, 0xffffffff, 0),
|
||||
SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -1, 0x40000000 , 0xffffffff,
|
||||
SYSC_MODULE_QUIRK_SGX),
|
||||
SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
|
||||
0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
|
||||
SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -1, 0x4ea2080d, 0xffffffff,
|
||||
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
|
||||
SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0,
|
||||
SYSC_MODULE_QUIRK_WDT),
|
||||
/* Watchdog on am3 and am4 */
|
||||
|
@ -1309,8 +1319,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
|
|||
SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000008, 0xffffffff, 0),
|
||||
SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0),
|
||||
SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -1, 0x50700101, 0xffffffff, 0),
|
||||
SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
|
||||
0xffffffff, 0),
|
||||
SYSC_QUIRK("vfpe", 0, 0, 0x104, -1, 0x4d001200, 0xffffffff, 0),
|
||||
#endif
|
||||
};
|
||||
|
@ -1532,37 +1540,6 @@ static int sysc_legacy_init(struct sysc *ddata)
|
|||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysc_rstctrl_reset_deassert - deassert rstctrl reset
|
||||
* @ddata: device driver data
|
||||
* @reset: reset before deassert
|
||||
*
|
||||
* A module can have both OCP softreset control and external rstctrl.
|
||||
* If more complicated rstctrl resets are needed, please handle these
|
||||
* directly from the child device driver and map only the module reset
|
||||
* for the parent interconnect target module device.
|
||||
*
|
||||
* Automatic reset of the module on init can be skipped with the
|
||||
* "ti,no-reset-on-init" device tree property.
|
||||
*/
|
||||
static int sysc_rstctrl_reset_deassert(struct sysc *ddata, bool reset)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!ddata->rsts)
|
||||
return 0;
|
||||
|
||||
if (reset) {
|
||||
error = reset_control_assert(ddata->rsts);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
reset_control_deassert(ddata->rsts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that the caller must ensure the interconnect target module is enabled
|
||||
* before calling reset. Otherwise reset will not complete.
|
||||
|
@ -1625,15 +1602,6 @@ static int sysc_reset(struct sysc *ddata)
|
|||
static int sysc_init_module(struct sysc *ddata)
|
||||
{
|
||||
int error = 0;
|
||||
bool manage_clocks = true;
|
||||
|
||||
error = sysc_rstctrl_reset_deassert(ddata, false);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (ddata->cfg.quirks &
|
||||
(SYSC_QUIRK_NO_IDLE | SYSC_QUIRK_NO_IDLE_ON_INIT))
|
||||
manage_clocks = false;
|
||||
|
||||
error = sysc_clockdomain_init(ddata);
|
||||
if (error)
|
||||
|
@ -1654,7 +1622,7 @@ static int sysc_init_module(struct sysc *ddata)
|
|||
goto err_opt_clocks;
|
||||
|
||||
if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)) {
|
||||
error = sysc_rstctrl_reset_deassert(ddata, true);
|
||||
error = reset_control_deassert(ddata->rsts);
|
||||
if (error)
|
||||
goto err_main_clocks;
|
||||
}
|
||||
|
@ -1666,28 +1634,32 @@ static int sysc_init_module(struct sysc *ddata)
|
|||
if (ddata->legacy_mode) {
|
||||
error = sysc_legacy_init(ddata);
|
||||
if (error)
|
||||
goto err_main_clocks;
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
if (!ddata->legacy_mode) {
|
||||
error = sysc_enable_module(ddata->dev);
|
||||
if (error)
|
||||
goto err_main_clocks;
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
error = sysc_reset(ddata);
|
||||
if (error)
|
||||
dev_err(ddata->dev, "Reset failed with %d\n", error);
|
||||
|
||||
if (!ddata->legacy_mode && manage_clocks)
|
||||
if (error && !ddata->legacy_mode)
|
||||
sysc_disable_module(ddata->dev);
|
||||
|
||||
err_reset:
|
||||
if (error && !(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT))
|
||||
reset_control_assert(ddata->rsts);
|
||||
|
||||
err_main_clocks:
|
||||
if (manage_clocks)
|
||||
if (error)
|
||||
sysc_disable_main_clocks(ddata);
|
||||
err_opt_clocks:
|
||||
/* No re-enable of clockdomain autoidle to prevent module autoidle */
|
||||
if (manage_clocks) {
|
||||
if (error) {
|
||||
sysc_disable_opt_clocks(ddata);
|
||||
sysc_clkdm_allow_idle(ddata);
|
||||
}
|
||||
|
@ -2460,10 +2432,17 @@ static int sysc_probe(struct platform_device *pdev)
|
|||
goto unprepare;
|
||||
}
|
||||
|
||||
/* Balance reset counts */
|
||||
if (ddata->rsts)
|
||||
/* Balance use counts as PM runtime should have enabled these all */
|
||||
if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT))
|
||||
reset_control_assert(ddata->rsts);
|
||||
|
||||
if (!(ddata->cfg.quirks &
|
||||
(SYSC_QUIRK_NO_IDLE | SYSC_QUIRK_NO_IDLE_ON_INIT))) {
|
||||
sysc_disable_main_clocks(ddata);
|
||||
sysc_disable_opt_clocks(ddata);
|
||||
sysc_clkdm_allow_idle(ddata);
|
||||
}
|
||||
|
||||
sysc_show_registers(ddata);
|
||||
|
||||
ddata->dev->type = &sysc_device_type;
|
||||
|
|
|
@ -323,7 +323,7 @@ static void scmi_perf_fc_ring_db(struct scmi_fc_db_info *db)
|
|||
|
||||
if (db->mask)
|
||||
val = ioread64_hi_lo(db->addr) & db->mask;
|
||||
iowrite64_hi_lo(db->set, db->addr);
|
||||
iowrite64_hi_lo(db->set | val, db->addr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ static int imx_dsp_probe(struct platform_device *pdev)
|
|||
|
||||
dev_info(dev, "NXP i.MX DSP IPC initialized\n");
|
||||
|
||||
return devm_of_platform_populate(dev);
|
||||
return 0;
|
||||
out:
|
||||
kfree(chan_name);
|
||||
for (j = 0; j < i; j++) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <dt-bindings/firmware/imx/rsrc.h>
|
||||
#include <linux/firmware/imx/ipc.h>
|
||||
#include <linux/firmware/imx/sci.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
|
||||
#define IMX_SC_IRQ_FUNC_ENABLE 1
|
||||
|
|
|
@ -107,6 +107,12 @@ static void imx_scu_rx_callback(struct mbox_client *c, void *msg)
|
|||
struct imx_sc_rpc_msg *hdr;
|
||||
u32 *data = msg;
|
||||
|
||||
if (!sc_ipc->msg) {
|
||||
dev_warn(sc_ipc->dev, "unexpected rx idx %d 0x%08x, ignore!\n",
|
||||
sc_chan->idx, *data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sc_chan->idx == 0) {
|
||||
hdr = msg;
|
||||
sc_ipc->rx_size = hdr->size;
|
||||
|
@ -156,6 +162,7 @@ static int imx_scu_ipc_write(struct imx_sc_ipc *sc_ipc, void *msg)
|
|||
*/
|
||||
int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp)
|
||||
{
|
||||
uint8_t saved_svc, saved_func;
|
||||
struct imx_sc_rpc_msg *hdr;
|
||||
int ret;
|
||||
|
||||
|
@ -165,7 +172,11 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp)
|
|||
mutex_lock(&sc_ipc->lock);
|
||||
reinit_completion(&sc_ipc->done);
|
||||
|
||||
sc_ipc->msg = msg;
|
||||
if (have_resp) {
|
||||
sc_ipc->msg = msg;
|
||||
saved_svc = ((struct imx_sc_rpc_msg *)msg)->svc;
|
||||
saved_func = ((struct imx_sc_rpc_msg *)msg)->func;
|
||||
}
|
||||
sc_ipc->count = 0;
|
||||
ret = imx_scu_ipc_write(sc_ipc, msg);
|
||||
if (ret < 0) {
|
||||
|
@ -184,9 +195,20 @@ int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp)
|
|||
/* response status is stored in hdr->func field */
|
||||
hdr = msg;
|
||||
ret = hdr->func;
|
||||
/*
|
||||
* Some special SCU firmware APIs do NOT have return value
|
||||
* in hdr->func, but they do have response data, those special
|
||||
* APIs are defined as void function in SCU firmware, so they
|
||||
* should be treated as return success always.
|
||||
*/
|
||||
if ((saved_svc == IMX_SC_RPC_SVC_MISC) &&
|
||||
(saved_func == IMX_SC_MISC_FUNC_UNIQUE_ID ||
|
||||
saved_func == IMX_SC_MISC_FUNC_GET_BUTTON_STATUS))
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
sc_ipc->msg = NULL;
|
||||
mutex_unlock(&sc_ipc->lock);
|
||||
|
||||
dev_dbg(sc_ipc->dev, "RPC SVC done\n");
|
||||
|
|
|
@ -35,7 +35,7 @@ struct meson_sm_chip {
|
|||
struct meson_sm_cmd cmd[];
|
||||
};
|
||||
|
||||
struct meson_sm_chip gxbb_chip = {
|
||||
static const struct meson_sm_chip gxbb_chip = {
|
||||
.shmem_size = SZ_4K,
|
||||
.cmd_shmem_in_base = 0x82000020,
|
||||
.cmd_shmem_out_base = 0x82000021,
|
||||
|
@ -54,8 +54,6 @@ struct meson_sm_firmware {
|
|||
void __iomem *sm_shmem_out_base;
|
||||
};
|
||||
|
||||
static struct meson_sm_firmware fw;
|
||||
|
||||
static u32 meson_sm_get_cmd(const struct meson_sm_chip *chip,
|
||||
unsigned int cmd_index)
|
||||
{
|
||||
|
@ -90,6 +88,7 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size)
|
|||
/**
|
||||
* meson_sm_call - generic SMC32 call to the secure-monitor
|
||||
*
|
||||
* @fw: Pointer to secure-monitor firmware
|
||||
* @cmd_index: Index of the SMC32 function ID
|
||||
* @ret: Returned value
|
||||
* @arg0: SMC32 Argument 0
|
||||
|
@ -100,15 +99,15 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size)
|
|||
*
|
||||
* Return: 0 on success, a negative value on error
|
||||
*/
|
||||
int meson_sm_call(unsigned int cmd_index, u32 *ret, u32 arg0,
|
||||
u32 arg1, u32 arg2, u32 arg3, u32 arg4)
|
||||
int meson_sm_call(struct meson_sm_firmware *fw, unsigned int cmd_index,
|
||||
u32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
|
||||
{
|
||||
u32 cmd, lret;
|
||||
|
||||
if (!fw.chip)
|
||||
if (!fw->chip)
|
||||
return -ENOENT;
|
||||
|
||||
cmd = meson_sm_get_cmd(fw.chip, cmd_index);
|
||||
cmd = meson_sm_get_cmd(fw->chip, cmd_index);
|
||||
if (!cmd)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -124,6 +123,7 @@ EXPORT_SYMBOL(meson_sm_call);
|
|||
/**
|
||||
* meson_sm_call_read - retrieve data from secure-monitor
|
||||
*
|
||||
* @fw: Pointer to secure-monitor firmware
|
||||
* @buffer: Buffer to store the retrieved data
|
||||
* @bsize: Size of the buffer
|
||||
* @cmd_index: Index of the SMC32 function ID
|
||||
|
@ -137,22 +137,23 @@ EXPORT_SYMBOL(meson_sm_call);
|
|||
* When 0 is returned there is no guarantee about the amount of
|
||||
* data read and bsize bytes are copied in buffer.
|
||||
*/
|
||||
int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index,
|
||||
u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
|
||||
int meson_sm_call_read(struct meson_sm_firmware *fw, void *buffer,
|
||||
unsigned int bsize, unsigned int cmd_index, u32 arg0,
|
||||
u32 arg1, u32 arg2, u32 arg3, u32 arg4)
|
||||
{
|
||||
u32 size;
|
||||
int ret;
|
||||
|
||||
if (!fw.chip)
|
||||
if (!fw->chip)
|
||||
return -ENOENT;
|
||||
|
||||
if (!fw.chip->cmd_shmem_out_base)
|
||||
if (!fw->chip->cmd_shmem_out_base)
|
||||
return -EINVAL;
|
||||
|
||||
if (bsize > fw.chip->shmem_size)
|
||||
if (bsize > fw->chip->shmem_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (meson_sm_call(cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0)
|
||||
if (meson_sm_call(fw, cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (size > bsize)
|
||||
|
@ -164,7 +165,7 @@ int meson_sm_call_read(void *buffer, unsigned int bsize, unsigned int cmd_index,
|
|||
size = bsize;
|
||||
|
||||
if (buffer)
|
||||
memcpy(buffer, fw.sm_shmem_out_base, size);
|
||||
memcpy(buffer, fw->sm_shmem_out_base, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -173,6 +174,7 @@ EXPORT_SYMBOL(meson_sm_call_read);
|
|||
/**
|
||||
* meson_sm_call_write - send data to secure-monitor
|
||||
*
|
||||
* @fw: Pointer to secure-monitor firmware
|
||||
* @buffer: Buffer containing data to send
|
||||
* @size: Size of the data to send
|
||||
* @cmd_index: Index of the SMC32 function ID
|
||||
|
@ -184,23 +186,24 @@ EXPORT_SYMBOL(meson_sm_call_read);
|
|||
*
|
||||
* Return: size of sent data on success, a negative value on error
|
||||
*/
|
||||
int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index,
|
||||
u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
|
||||
int meson_sm_call_write(struct meson_sm_firmware *fw, void *buffer,
|
||||
unsigned int size, unsigned int cmd_index, u32 arg0,
|
||||
u32 arg1, u32 arg2, u32 arg3, u32 arg4)
|
||||
{
|
||||
u32 written;
|
||||
|
||||
if (!fw.chip)
|
||||
if (!fw->chip)
|
||||
return -ENOENT;
|
||||
|
||||
if (size > fw.chip->shmem_size)
|
||||
if (size > fw->chip->shmem_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (!fw.chip->cmd_shmem_in_base)
|
||||
if (!fw->chip->cmd_shmem_in_base)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(fw.sm_shmem_in_base, buffer, size);
|
||||
memcpy(fw->sm_shmem_in_base, buffer, size);
|
||||
|
||||
if (meson_sm_call(cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0)
|
||||
if (meson_sm_call(fw, cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!written)
|
||||
|
@ -210,6 +213,24 @@ int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index,
|
|||
}
|
||||
EXPORT_SYMBOL(meson_sm_call_write);
|
||||
|
||||
/**
|
||||
* meson_sm_get - get pointer to meson_sm_firmware structure.
|
||||
*
|
||||
* @sm_node: Pointer to the secure-monitor Device Tree node.
|
||||
*
|
||||
* Return: NULL is the secure-monitor device is not ready.
|
||||
*/
|
||||
struct meson_sm_firmware *meson_sm_get(struct device_node *sm_node)
|
||||
{
|
||||
struct platform_device *pdev = of_find_device_by_node(sm_node);
|
||||
|
||||
if (!pdev)
|
||||
return NULL;
|
||||
|
||||
return platform_get_drvdata(pdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(meson_sm_get);
|
||||
|
||||
#define SM_CHIP_ID_LENGTH 119
|
||||
#define SM_CHIP_ID_OFFSET 4
|
||||
#define SM_CHIP_ID_SIZE 12
|
||||
|
@ -217,33 +238,25 @@ EXPORT_SYMBOL(meson_sm_call_write);
|
|||
static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct meson_sm_firmware *fw;
|
||||
uint8_t *id_buf;
|
||||
int ret;
|
||||
|
||||
fw = platform_get_drvdata(pdev);
|
||||
|
||||
id_buf = kmalloc(SM_CHIP_ID_LENGTH, GFP_KERNEL);
|
||||
if (!id_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = meson_sm_call_read(id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID,
|
||||
ret = meson_sm_call_read(fw, id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID,
|
||||
0, 0, 0, 0, 0);
|
||||
if (ret < 0) {
|
||||
kfree(id_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sprintf(buf, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
id_buf[SM_CHIP_ID_OFFSET + 0],
|
||||
id_buf[SM_CHIP_ID_OFFSET + 1],
|
||||
id_buf[SM_CHIP_ID_OFFSET + 2],
|
||||
id_buf[SM_CHIP_ID_OFFSET + 3],
|
||||
id_buf[SM_CHIP_ID_OFFSET + 4],
|
||||
id_buf[SM_CHIP_ID_OFFSET + 5],
|
||||
id_buf[SM_CHIP_ID_OFFSET + 6],
|
||||
id_buf[SM_CHIP_ID_OFFSET + 7],
|
||||
id_buf[SM_CHIP_ID_OFFSET + 8],
|
||||
id_buf[SM_CHIP_ID_OFFSET + 9],
|
||||
id_buf[SM_CHIP_ID_OFFSET + 10],
|
||||
id_buf[SM_CHIP_ID_OFFSET + 11]);
|
||||
ret = sprintf(buf, "%12phN\n", &id_buf[SM_CHIP_ID_OFFSET]);
|
||||
|
||||
kfree(id_buf);
|
||||
|
||||
|
@ -268,25 +281,34 @@ static const struct of_device_id meson_sm_ids[] = {
|
|||
|
||||
static int __init meson_sm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct meson_sm_chip *chip;
|
||||
struct meson_sm_firmware *fw;
|
||||
|
||||
chip = of_match_device(meson_sm_ids, &pdev->dev)->data;
|
||||
fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL);
|
||||
if (!fw)
|
||||
return -ENOMEM;
|
||||
|
||||
chip = of_match_device(meson_sm_ids, dev)->data;
|
||||
|
||||
if (chip->cmd_shmem_in_base) {
|
||||
fw.sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base,
|
||||
chip->shmem_size);
|
||||
if (WARN_ON(!fw.sm_shmem_in_base))
|
||||
fw->sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base,
|
||||
chip->shmem_size);
|
||||
if (WARN_ON(!fw->sm_shmem_in_base))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (chip->cmd_shmem_out_base) {
|
||||
fw.sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base,
|
||||
chip->shmem_size);
|
||||
if (WARN_ON(!fw.sm_shmem_out_base))
|
||||
fw->sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base,
|
||||
chip->shmem_size);
|
||||
if (WARN_ON(!fw->sm_shmem_out_base))
|
||||
goto out_in_base;
|
||||
}
|
||||
|
||||
fw.chip = chip;
|
||||
fw->chip = chip;
|
||||
|
||||
platform_set_drvdata(pdev, fw);
|
||||
|
||||
pr_info("secure-monitor enabled\n");
|
||||
|
||||
if (sysfs_create_group(&pdev->dev.kobj, &meson_sm_sysfs_attr_group))
|
||||
|
@ -295,7 +317,7 @@ static int __init meson_sm_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
out_in_base:
|
||||
iounmap(fw.sm_shmem_in_base);
|
||||
iounmap(fw->sm_shmem_in_base);
|
||||
out:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -804,7 +804,7 @@ static int __maybe_unused tegra_bpmp_resume(struct device *dev)
|
|||
}
|
||||
|
||||
static const struct dev_pm_ops tegra_bpmp_pm_ops = {
|
||||
.resume_early = tegra_bpmp_resume,
|
||||
.resume_noirq = tegra_bpmp_resume,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \
|
||||
|
|
|
@ -711,8 +711,11 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
|
|||
int ret;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
|
||||
if (!np)
|
||||
return 0;
|
||||
if (!np) {
|
||||
np = of_find_compatible_node(NULL, NULL, "xlnx,versal");
|
||||
if (!np)
|
||||
return 0;
|
||||
}
|
||||
of_node_put(np);
|
||||
|
||||
ret = get_set_conduit_method(dev->of_node);
|
||||
|
@ -770,6 +773,7 @@ static int zynqmp_firmware_remove(struct platform_device *pdev)
|
|||
|
||||
static const struct of_device_id zynqmp_firmware_of_match[] = {
|
||||
{.compatible = "xlnx,zynqmp-firmware"},
|
||||
{.compatible = "xlnx,versal-firmware"},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, zynqmp_firmware_of_match);
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* EBI driver for Atmel chips
|
||||
* inspired by the fsl weim bus driver
|
||||
*
|
||||
* Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
@ -19,6 +16,8 @@
|
|||
#include <linux/regmap.h>
|
||||
#include <soc/at91/atmel-sfr.h>
|
||||
|
||||
#define AT91_EBI_NUM_CS 8
|
||||
|
||||
struct atmel_ebi_dev_config {
|
||||
int cs;
|
||||
struct atmel_smc_cs_conf smcconf;
|
||||
|
@ -314,7 +313,7 @@ static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cs >= AT91_MATRIX_EBI_NUM_CS ||
|
||||
if (cs >= AT91_EBI_NUM_CS ||
|
||||
!(ebi->caps->available_cs & BIT(cs))) {
|
||||
dev_err(dev, "invalid reg property in %pOF\n", np);
|
||||
return -EINVAL;
|
||||
|
@ -344,7 +343,7 @@ static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np,
|
|||
apply = true;
|
||||
|
||||
i = 0;
|
||||
for_each_set_bit(cs, &cslines, AT91_MATRIX_EBI_NUM_CS) {
|
||||
for_each_set_bit(cs, &cslines, AT91_EBI_NUM_CS) {
|
||||
ebid->configs[i].cs = cs;
|
||||
|
||||
if (apply) {
|
||||
|
|
|
@ -127,7 +127,6 @@ enum dpfe_msg_fields {
|
|||
MSG_COMMAND,
|
||||
MSG_ARG_COUNT,
|
||||
MSG_ARG0,
|
||||
MSG_CHKSUM,
|
||||
MSG_FIELD_MAX = 16 /* Max number of arguments */
|
||||
};
|
||||
|
||||
|
@ -180,7 +179,7 @@ struct dpfe_api {
|
|||
};
|
||||
|
||||
/* Things we need for as long as we are active. */
|
||||
struct private_data {
|
||||
struct brcmstb_dpfe_priv {
|
||||
void __iomem *regs;
|
||||
void __iomem *dmem;
|
||||
void __iomem *imem;
|
||||
|
@ -232,9 +231,13 @@ static struct attribute *dpfe_v3_attrs[] = {
|
|||
};
|
||||
ATTRIBUTE_GROUPS(dpfe_v3);
|
||||
|
||||
/* API v2 firmware commands */
|
||||
static const struct dpfe_api dpfe_api_v2 = {
|
||||
.version = 2,
|
||||
/*
|
||||
* Old API v2 firmware commands, as defined in the rev 0.61 specification, we
|
||||
* use a version set to 1 to denote that it is not compatible with the new API
|
||||
* v2 and onwards.
|
||||
*/
|
||||
static const struct dpfe_api dpfe_api_old_v2 = {
|
||||
.version = 1,
|
||||
.fw_name = "dpfe.bin",
|
||||
.sysfs_attrs = dpfe_v2_groups,
|
||||
.command = {
|
||||
|
@ -243,21 +246,42 @@ static const struct dpfe_api dpfe_api_v2 = {
|
|||
[MSG_COMMAND] = 1,
|
||||
[MSG_ARG_COUNT] = 1,
|
||||
[MSG_ARG0] = 1,
|
||||
[MSG_CHKSUM] = 4,
|
||||
},
|
||||
[DPFE_CMD_GET_REFRESH] = {
|
||||
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
|
||||
[MSG_COMMAND] = 2,
|
||||
[MSG_ARG_COUNT] = 1,
|
||||
[MSG_ARG0] = 1,
|
||||
[MSG_CHKSUM] = 5,
|
||||
},
|
||||
[DPFE_CMD_GET_VENDOR] = {
|
||||
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
|
||||
[MSG_COMMAND] = 2,
|
||||
[MSG_ARG_COUNT] = 1,
|
||||
[MSG_ARG0] = 2,
|
||||
[MSG_CHKSUM] = 6,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* API v2 firmware commands, as defined in the rev 0.8 specification, named new
|
||||
* v2 here
|
||||
*/
|
||||
static const struct dpfe_api dpfe_api_new_v2 = {
|
||||
.version = 2,
|
||||
.fw_name = NULL, /* We expect the firmware to have been downloaded! */
|
||||
.sysfs_attrs = dpfe_v2_groups,
|
||||
.command = {
|
||||
[DPFE_CMD_GET_INFO] = {
|
||||
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
|
||||
[MSG_COMMAND] = 0x101,
|
||||
},
|
||||
[DPFE_CMD_GET_REFRESH] = {
|
||||
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
|
||||
[MSG_COMMAND] = 0x201,
|
||||
},
|
||||
[DPFE_CMD_GET_VENDOR] = {
|
||||
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
|
||||
[MSG_COMMAND] = 0x202,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
@ -273,49 +297,51 @@ static const struct dpfe_api dpfe_api_v3 = {
|
|||
[MSG_COMMAND] = 0x0101,
|
||||
[MSG_ARG_COUNT] = 1,
|
||||
[MSG_ARG0] = 1,
|
||||
[MSG_CHKSUM] = 0x104,
|
||||
},
|
||||
[DPFE_CMD_GET_REFRESH] = {
|
||||
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
|
||||
[MSG_COMMAND] = 0x0202,
|
||||
[MSG_ARG_COUNT] = 0,
|
||||
/*
|
||||
* This is a bit ugly. Without arguments, the checksum
|
||||
* follows right after the argument count and not at
|
||||
* offset MSG_CHKSUM.
|
||||
*/
|
||||
[MSG_ARG0] = 0x203,
|
||||
},
|
||||
/* There's no GET_VENDOR command in API v3. */
|
||||
},
|
||||
};
|
||||
|
||||
static bool is_dcpu_enabled(void __iomem *regs)
|
||||
static bool is_dcpu_enabled(struct brcmstb_dpfe_priv *priv)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(regs + REG_DCPU_RESET);
|
||||
mutex_lock(&priv->lock);
|
||||
val = readl_relaxed(priv->regs + REG_DCPU_RESET);
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
return !(val & DCPU_RESET_MASK);
|
||||
}
|
||||
|
||||
static void __disable_dcpu(void __iomem *regs)
|
||||
static void __disable_dcpu(struct brcmstb_dpfe_priv *priv)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (!is_dcpu_enabled(regs))
|
||||
if (!is_dcpu_enabled(priv))
|
||||
return;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
/* Put DCPU in reset if it's running. */
|
||||
val = readl_relaxed(regs + REG_DCPU_RESET);
|
||||
val = readl_relaxed(priv->regs + REG_DCPU_RESET);
|
||||
val |= (1 << DCPU_RESET_SHIFT);
|
||||
writel_relaxed(val, regs + REG_DCPU_RESET);
|
||||
writel_relaxed(val, priv->regs + REG_DCPU_RESET);
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
}
|
||||
|
||||
static void __enable_dcpu(void __iomem *regs)
|
||||
static void __enable_dcpu(struct brcmstb_dpfe_priv *priv)
|
||||
{
|
||||
void __iomem *regs = priv->regs;
|
||||
u32 val;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
/* Clear mailbox registers. */
|
||||
writel_relaxed(0, regs + REG_TO_DCPU_MBOX);
|
||||
writel_relaxed(0, regs + REG_TO_HOST_MBOX);
|
||||
|
@ -329,6 +355,8 @@ static void __enable_dcpu(void __iomem *regs)
|
|||
val = readl_relaxed(regs + REG_DCPU_RESET);
|
||||
val &= ~(1 << DCPU_RESET_SHIFT);
|
||||
writel_relaxed(val, regs + REG_DCPU_RESET);
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
}
|
||||
|
||||
static unsigned int get_msg_chksum(const u32 msg[], unsigned int max)
|
||||
|
@ -343,7 +371,7 @@ static unsigned int get_msg_chksum(const u32 msg[], unsigned int max)
|
|||
return sum;
|
||||
}
|
||||
|
||||
static void __iomem *get_msg_ptr(struct private_data *priv, u32 response,
|
||||
static void __iomem *get_msg_ptr(struct brcmstb_dpfe_priv *priv, u32 response,
|
||||
char *buf, ssize_t *size)
|
||||
{
|
||||
unsigned int msg_type;
|
||||
|
@ -382,7 +410,7 @@ static void __iomem *get_msg_ptr(struct private_data *priv, u32 response,
|
|||
return ptr;
|
||||
}
|
||||
|
||||
static void __finalize_command(struct private_data *priv)
|
||||
static void __finalize_command(struct brcmstb_dpfe_priv *priv)
|
||||
{
|
||||
unsigned int release_mbox;
|
||||
|
||||
|
@ -390,12 +418,12 @@ static void __finalize_command(struct private_data *priv)
|
|||
* It depends on the API version which MBOX register we have to write to
|
||||
* to signal we are done.
|
||||
*/
|
||||
release_mbox = (priv->dpfe_api->version < 3)
|
||||
release_mbox = (priv->dpfe_api->version < 2)
|
||||
? REG_TO_HOST_MBOX : REG_TO_DCPU_MBOX;
|
||||
writel_relaxed(0, priv->regs + release_mbox);
|
||||
}
|
||||
|
||||
static int __send_command(struct private_data *priv, unsigned int cmd,
|
||||
static int __send_command(struct brcmstb_dpfe_priv *priv, unsigned int cmd,
|
||||
u32 result[])
|
||||
{
|
||||
const u32 *msg = priv->dpfe_api->command[cmd];
|
||||
|
@ -421,9 +449,17 @@ static int __send_command(struct private_data *priv, unsigned int cmd,
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Compute checksum over the message */
|
||||
chksum_idx = msg[MSG_ARG_COUNT] + MSG_ARG_COUNT + 1;
|
||||
chksum = get_msg_chksum(msg, chksum_idx);
|
||||
|
||||
/* Write command and arguments to message area */
|
||||
for (i = 0; i < MSG_FIELD_MAX; i++)
|
||||
writel_relaxed(msg[i], regs + DCPU_MSG_RAM(i));
|
||||
for (i = 0; i < MSG_FIELD_MAX; i++) {
|
||||
if (i == chksum_idx)
|
||||
writel_relaxed(chksum, regs + DCPU_MSG_RAM(i));
|
||||
else
|
||||
writel_relaxed(msg[i], regs + DCPU_MSG_RAM(i));
|
||||
}
|
||||
|
||||
/* Tell DCPU there is a command waiting */
|
||||
writel_relaxed(1, regs + REG_TO_DCPU_MBOX);
|
||||
|
@ -517,7 +553,7 @@ static int __verify_firmware(struct init_data *init,
|
|||
|
||||
/* Verify checksum by reading back the firmware from co-processor RAM. */
|
||||
static int __verify_fw_checksum(struct init_data *init,
|
||||
struct private_data *priv,
|
||||
struct brcmstb_dpfe_priv *priv,
|
||||
const struct dpfe_firmware_header *header,
|
||||
u32 checksum)
|
||||
{
|
||||
|
@ -571,26 +607,23 @@ static int __write_firmware(u32 __iomem *mem, const u32 *fw,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int brcmstb_dpfe_download_firmware(struct platform_device *pdev,
|
||||
struct init_data *init)
|
||||
static int brcmstb_dpfe_download_firmware(struct brcmstb_dpfe_priv *priv)
|
||||
{
|
||||
const struct dpfe_firmware_header *header;
|
||||
unsigned int dmem_size, imem_size;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device *dev = priv->dev;
|
||||
bool is_big_endian = false;
|
||||
struct private_data *priv;
|
||||
const struct firmware *fw;
|
||||
const u32 *dmem, *imem;
|
||||
struct init_data init;
|
||||
const void *fw_blob;
|
||||
int ret;
|
||||
|
||||
priv = platform_get_drvdata(pdev);
|
||||
|
||||
/*
|
||||
* Skip downloading the firmware if the DCPU is already running and
|
||||
* responding to commands.
|
||||
*/
|
||||
if (is_dcpu_enabled(priv->regs)) {
|
||||
if (is_dcpu_enabled(priv)) {
|
||||
u32 response[MSG_FIELD_MAX];
|
||||
|
||||
ret = __send_command(priv, DPFE_CMD_GET_INFO, response);
|
||||
|
@ -606,20 +639,23 @@ static int brcmstb_dpfe_download_firmware(struct platform_device *pdev,
|
|||
if (!priv->dpfe_api->fw_name)
|
||||
return -ENODEV;
|
||||
|
||||
ret = request_firmware(&fw, priv->dpfe_api->fw_name, dev);
|
||||
/* request_firmware() prints its own error messages. */
|
||||
ret = firmware_request_nowarn(&fw, priv->dpfe_api->fw_name, dev);
|
||||
/*
|
||||
* Defer the firmware download if the firmware file couldn't be found.
|
||||
* The root file system may not be available yet.
|
||||
*/
|
||||
if (ret)
|
||||
return ret;
|
||||
return (ret == -ENOENT) ? -EPROBE_DEFER : ret;
|
||||
|
||||
ret = __verify_firmware(init, fw);
|
||||
ret = __verify_firmware(&init, fw);
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
|
||||
__disable_dcpu(priv->regs);
|
||||
__disable_dcpu(priv);
|
||||
|
||||
is_big_endian = init->is_big_endian;
|
||||
dmem_size = init->dmem_len;
|
||||
imem_size = init->imem_len;
|
||||
is_big_endian = init.is_big_endian;
|
||||
dmem_size = init.dmem_len;
|
||||
imem_size = init.imem_len;
|
||||
|
||||
/* At the beginning of the firmware blob is a header. */
|
||||
header = (struct dpfe_firmware_header *)fw->data;
|
||||
|
@ -637,17 +673,17 @@ static int brcmstb_dpfe_download_firmware(struct platform_device *pdev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = __verify_fw_checksum(init, priv, header, init->chksum);
|
||||
ret = __verify_fw_checksum(&init, priv, header, init.chksum);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
__enable_dcpu(priv->regs);
|
||||
__enable_dcpu(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t generic_show(unsigned int command, u32 response[],
|
||||
struct private_data *priv, char *buf)
|
||||
struct brcmstb_dpfe_priv *priv, char *buf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -665,7 +701,7 @@ static ssize_t show_info(struct device *dev, struct device_attribute *devattr,
|
|||
char *buf)
|
||||
{
|
||||
u32 response[MSG_FIELD_MAX];
|
||||
struct private_data *priv;
|
||||
struct brcmstb_dpfe_priv *priv;
|
||||
unsigned int info;
|
||||
ssize_t ret;
|
||||
|
||||
|
@ -688,7 +724,7 @@ static ssize_t show_refresh(struct device *dev,
|
|||
{
|
||||
u32 response[MSG_FIELD_MAX];
|
||||
void __iomem *info;
|
||||
struct private_data *priv;
|
||||
struct brcmstb_dpfe_priv *priv;
|
||||
u8 refresh, sr_abort, ppre, thermal_offs, tuf;
|
||||
u32 mr4;
|
||||
ssize_t ret;
|
||||
|
@ -721,7 +757,7 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
u32 response[MSG_FIELD_MAX];
|
||||
struct private_data *priv;
|
||||
struct brcmstb_dpfe_priv *priv;
|
||||
void __iomem *info;
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
@ -747,7 +783,7 @@ static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr,
|
|||
char *buf)
|
||||
{
|
||||
u32 response[MSG_FIELD_MAX];
|
||||
struct private_data *priv;
|
||||
struct brcmstb_dpfe_priv *priv;
|
||||
void __iomem *info;
|
||||
ssize_t ret;
|
||||
u32 mr5, mr6, mr7, mr8, err;
|
||||
|
@ -778,7 +814,7 @@ static ssize_t show_dram(struct device *dev, struct device_attribute *devattr,
|
|||
char *buf)
|
||||
{
|
||||
u32 response[MSG_FIELD_MAX];
|
||||
struct private_data *priv;
|
||||
struct brcmstb_dpfe_priv *priv;
|
||||
ssize_t ret;
|
||||
u32 mr4, mr5, mr6, mr7, mr8, err;
|
||||
|
||||
|
@ -800,16 +836,15 @@ static ssize_t show_dram(struct device *dev, struct device_attribute *devattr,
|
|||
|
||||
static int brcmstb_dpfe_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct init_data init;
|
||||
struct brcmstb_dpfe_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
return brcmstb_dpfe_download_firmware(pdev, &init);
|
||||
return brcmstb_dpfe_download_firmware(priv);
|
||||
}
|
||||
|
||||
static int brcmstb_dpfe_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct private_data *priv;
|
||||
struct init_data init;
|
||||
struct brcmstb_dpfe_priv *priv;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
|
@ -817,6 +852,8 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
|
|||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->dev = dev;
|
||||
|
||||
mutex_init(&priv->lock);
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
|
@ -851,9 +888,10 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = brcmstb_dpfe_download_firmware(pdev, &init);
|
||||
ret = brcmstb_dpfe_download_firmware(priv);
|
||||
if (ret) {
|
||||
dev_err(dev, "Couldn't download firmware -- %d\n", ret);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Couldn't download firmware -- %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -867,7 +905,7 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
|
|||
|
||||
static int brcmstb_dpfe_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct private_data *priv = dev_get_drvdata(&pdev->dev);
|
||||
struct brcmstb_dpfe_priv *priv = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
sysfs_remove_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs);
|
||||
|
||||
|
@ -876,10 +914,10 @@ static int brcmstb_dpfe_remove(struct platform_device *pdev)
|
|||
|
||||
static const struct of_device_id brcmstb_dpfe_of_match[] = {
|
||||
/* Use legacy API v2 for a select number of chips */
|
||||
{ .compatible = "brcm,bcm7268-dpfe-cpu", .data = &dpfe_api_v2 },
|
||||
{ .compatible = "brcm,bcm7271-dpfe-cpu", .data = &dpfe_api_v2 },
|
||||
{ .compatible = "brcm,bcm7278-dpfe-cpu", .data = &dpfe_api_v2 },
|
||||
{ .compatible = "brcm,bcm7211-dpfe-cpu", .data = &dpfe_api_v2 },
|
||||
{ .compatible = "brcm,bcm7268-dpfe-cpu", .data = &dpfe_api_old_v2 },
|
||||
{ .compatible = "brcm,bcm7271-dpfe-cpu", .data = &dpfe_api_old_v2 },
|
||||
{ .compatible = "brcm,bcm7278-dpfe-cpu", .data = &dpfe_api_old_v2 },
|
||||
{ .compatible = "brcm,bcm7211-dpfe-cpu", .data = &dpfe_api_new_v2 },
|
||||
/* API v3 is the default going forward */
|
||||
{ .compatible = "brcm,dpfe-cpu", .data = &dpfe_api_v3 },
|
||||
{}
|
||||
|
|
|
@ -1613,7 +1613,7 @@ static void emif_shutdown(struct platform_device *pdev)
|
|||
static int get_emif_reg_values(struct emif_data *emif, u32 freq,
|
||||
struct emif_regs *regs)
|
||||
{
|
||||
u32 cs1_used, ip_rev, phy_type;
|
||||
u32 ip_rev, phy_type;
|
||||
u32 cl, type;
|
||||
const struct lpddr2_timings *timings;
|
||||
const struct lpddr2_min_tck *min_tck;
|
||||
|
@ -1621,7 +1621,6 @@ static int get_emif_reg_values(struct emif_data *emif, u32 freq,
|
|||
const struct lpddr2_addressing *addressing;
|
||||
struct emif_data *emif_for_calc;
|
||||
struct device *dev;
|
||||
const struct emif_custom_configs *custom_configs;
|
||||
|
||||
dev = emif->dev;
|
||||
/*
|
||||
|
@ -1639,12 +1638,10 @@ static int get_emif_reg_values(struct emif_data *emif, u32 freq,
|
|||
|
||||
device_info = emif_for_calc->plat_data->device_info;
|
||||
type = device_info->type;
|
||||
cs1_used = device_info->cs1_used;
|
||||
ip_rev = emif_for_calc->plat_data->ip_rev;
|
||||
phy_type = emif_for_calc->plat_data->phy_type;
|
||||
|
||||
min_tck = emif_for_calc->plat_data->min_tck;
|
||||
custom_configs = emif_for_calc->plat_data->custom_configs;
|
||||
|
||||
set_ddr_clk_period(freq);
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#define DDR_TYPE_LPDDR2_S4 3
|
||||
#define DDR_TYPE_LPDDR2_S2 4
|
||||
#define DDR_TYPE_LPDDR2_NVM 5
|
||||
#define DDR_TYPE_LPDDR3 6
|
||||
|
||||
/* DDR IO width */
|
||||
#define DDR_IO_WIDTH_4 1
|
||||
|
@ -169,4 +170,64 @@ extern const struct lpddr2_timings
|
|||
lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES];
|
||||
extern const struct lpddr2_min_tck lpddr2_jedec_min_tck;
|
||||
|
||||
/*
|
||||
* Structure for timings for LPDDR3 based on LPDDR2 plus additional fields.
|
||||
* All parameters are in pico seconds(ps) excluding max_freq, min_freq which
|
||||
* are in Hz.
|
||||
*/
|
||||
struct lpddr3_timings {
|
||||
u32 max_freq;
|
||||
u32 min_freq;
|
||||
u32 tRFC;
|
||||
u32 tRRD;
|
||||
u32 tRPab;
|
||||
u32 tRPpb;
|
||||
u32 tRCD;
|
||||
u32 tRC;
|
||||
u32 tRAS;
|
||||
u32 tWTR;
|
||||
u32 tWR;
|
||||
u32 tRTP;
|
||||
u32 tW2W_C2C;
|
||||
u32 tR2R_C2C;
|
||||
u32 tWL;
|
||||
u32 tDQSCK;
|
||||
u32 tRL;
|
||||
u32 tFAW;
|
||||
u32 tXSR;
|
||||
u32 tXP;
|
||||
u32 tCKE;
|
||||
u32 tCKESR;
|
||||
u32 tMRD;
|
||||
};
|
||||
|
||||
/*
|
||||
* Min value for some parameters in terms of number of tCK cycles(nCK)
|
||||
* Please set to zero parameters that are not valid for a given memory
|
||||
* type
|
||||
*/
|
||||
struct lpddr3_min_tck {
|
||||
u32 tRFC;
|
||||
u32 tRRD;
|
||||
u32 tRPab;
|
||||
u32 tRPpb;
|
||||
u32 tRCD;
|
||||
u32 tRC;
|
||||
u32 tRAS;
|
||||
u32 tWTR;
|
||||
u32 tWR;
|
||||
u32 tRTP;
|
||||
u32 tW2W_C2C;
|
||||
u32 tR2R_C2C;
|
||||
u32 tWL;
|
||||
u32 tDQSCK;
|
||||
u32 tRL;
|
||||
u32 tFAW;
|
||||
u32 tXSR;
|
||||
u32 tXP;
|
||||
u32 tCKE;
|
||||
u32 tCKESR;
|
||||
u32 tMRD;
|
||||
};
|
||||
|
||||
#endif /* __JEDEC_DDR_H */
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* OpenFirmware helpers for memory drivers
|
||||
*
|
||||
* Copyright (C) 2012 Texas Instruments, Inc.
|
||||
* Copyright (C) 2019 Samsung Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
|
@ -149,3 +150,151 @@ default_timings:
|
|||
return lpddr2_jedec_timings;
|
||||
}
|
||||
EXPORT_SYMBOL(of_get_ddr_timings);
|
||||
|
||||
/**
|
||||
* of_lpddr3_get_min_tck() - extract min timing values for lpddr3
|
||||
* @np: pointer to ddr device tree node
|
||||
* @device: device requesting for min timing values
|
||||
*
|
||||
* Populates the lpddr3_min_tck structure by extracting data
|
||||
* from device tree node. Returns a pointer to the populated
|
||||
* structure. If any error in populating the structure, returns NULL.
|
||||
*/
|
||||
const struct lpddr3_min_tck *of_lpddr3_get_min_tck(struct device_node *np,
|
||||
struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct lpddr3_min_tck *min;
|
||||
|
||||
min = devm_kzalloc(dev, sizeof(*min), GFP_KERNEL);
|
||||
if (!min)
|
||||
goto default_min_tck;
|
||||
|
||||
ret |= of_property_read_u32(np, "tRFC-min-tck", &min->tRFC);
|
||||
ret |= of_property_read_u32(np, "tRRD-min-tck", &min->tRRD);
|
||||
ret |= of_property_read_u32(np, "tRPab-min-tck", &min->tRPab);
|
||||
ret |= of_property_read_u32(np, "tRPpb-min-tck", &min->tRPpb);
|
||||
ret |= of_property_read_u32(np, "tRCD-min-tck", &min->tRCD);
|
||||
ret |= of_property_read_u32(np, "tRC-min-tck", &min->tRC);
|
||||
ret |= of_property_read_u32(np, "tRAS-min-tck", &min->tRAS);
|
||||
ret |= of_property_read_u32(np, "tWTR-min-tck", &min->tWTR);
|
||||
ret |= of_property_read_u32(np, "tWR-min-tck", &min->tWR);
|
||||
ret |= of_property_read_u32(np, "tRTP-min-tck", &min->tRTP);
|
||||
ret |= of_property_read_u32(np, "tW2W-C2C-min-tck", &min->tW2W_C2C);
|
||||
ret |= of_property_read_u32(np, "tR2R-C2C-min-tck", &min->tR2R_C2C);
|
||||
ret |= of_property_read_u32(np, "tWL-min-tck", &min->tWL);
|
||||
ret |= of_property_read_u32(np, "tDQSCK-min-tck", &min->tDQSCK);
|
||||
ret |= of_property_read_u32(np, "tRL-min-tck", &min->tRL);
|
||||
ret |= of_property_read_u32(np, "tFAW-min-tck", &min->tFAW);
|
||||
ret |= of_property_read_u32(np, "tXSR-min-tck", &min->tXSR);
|
||||
ret |= of_property_read_u32(np, "tXP-min-tck", &min->tXP);
|
||||
ret |= of_property_read_u32(np, "tCKE-min-tck", &min->tCKE);
|
||||
ret |= of_property_read_u32(np, "tCKESR-min-tck", &min->tCKESR);
|
||||
ret |= of_property_read_u32(np, "tMRD-min-tck", &min->tMRD);
|
||||
|
||||
if (ret) {
|
||||
dev_warn(dev, "%s: errors while parsing min-tck values\n",
|
||||
__func__);
|
||||
devm_kfree(dev, min);
|
||||
goto default_min_tck;
|
||||
}
|
||||
|
||||
return min;
|
||||
|
||||
default_min_tck:
|
||||
dev_warn(dev, "%s: using default min-tck values\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(of_lpddr3_get_min_tck);
|
||||
|
||||
static int of_lpddr3_do_get_timings(struct device_node *np,
|
||||
struct lpddr3_timings *tim)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* The 'reg' param required since DT has changed, used as 'max-freq' */
|
||||
ret = of_property_read_u32(np, "reg", &tim->max_freq);
|
||||
ret |= of_property_read_u32(np, "min-freq", &tim->min_freq);
|
||||
ret |= of_property_read_u32(np, "tRFC", &tim->tRFC);
|
||||
ret |= of_property_read_u32(np, "tRRD", &tim->tRRD);
|
||||
ret |= of_property_read_u32(np, "tRPab", &tim->tRPab);
|
||||
ret |= of_property_read_u32(np, "tRPpb", &tim->tRPpb);
|
||||
ret |= of_property_read_u32(np, "tRCD", &tim->tRCD);
|
||||
ret |= of_property_read_u32(np, "tRC", &tim->tRC);
|
||||
ret |= of_property_read_u32(np, "tRAS", &tim->tRAS);
|
||||
ret |= of_property_read_u32(np, "tWTR", &tim->tWTR);
|
||||
ret |= of_property_read_u32(np, "tWR", &tim->tWR);
|
||||
ret |= of_property_read_u32(np, "tRTP", &tim->tRTP);
|
||||
ret |= of_property_read_u32(np, "tW2W-C2C", &tim->tW2W_C2C);
|
||||
ret |= of_property_read_u32(np, "tR2R-C2C", &tim->tR2R_C2C);
|
||||
ret |= of_property_read_u32(np, "tFAW", &tim->tFAW);
|
||||
ret |= of_property_read_u32(np, "tXSR", &tim->tXSR);
|
||||
ret |= of_property_read_u32(np, "tXP", &tim->tXP);
|
||||
ret |= of_property_read_u32(np, "tCKE", &tim->tCKE);
|
||||
ret |= of_property_read_u32(np, "tCKESR", &tim->tCKESR);
|
||||
ret |= of_property_read_u32(np, "tMRD", &tim->tMRD);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_lpddr3_get_ddr_timings() - extracts the lpddr3 timings and updates no of
|
||||
* frequencies available.
|
||||
* @np_ddr: Pointer to ddr device tree node
|
||||
* @dev: Device requesting for ddr timings
|
||||
* @device_type: Type of ddr
|
||||
* @nr_frequencies: No of frequencies available for ddr
|
||||
* (updated by this function)
|
||||
*
|
||||
* Populates lpddr3_timings structure by extracting data from device
|
||||
* tree node. Returns pointer to populated structure. If any error
|
||||
* while populating, returns NULL.
|
||||
*/
|
||||
const struct lpddr3_timings
|
||||
*of_lpddr3_get_ddr_timings(struct device_node *np_ddr, struct device *dev,
|
||||
u32 device_type, u32 *nr_frequencies)
|
||||
{
|
||||
struct lpddr3_timings *timings = NULL;
|
||||
u32 arr_sz = 0, i = 0;
|
||||
struct device_node *np_tim;
|
||||
char *tim_compat = NULL;
|
||||
|
||||
switch (device_type) {
|
||||
case DDR_TYPE_LPDDR3:
|
||||
tim_compat = "jedec,lpddr3-timings";
|
||||
break;
|
||||
default:
|
||||
dev_warn(dev, "%s: un-supported memory type\n", __func__);
|
||||
}
|
||||
|
||||
for_each_child_of_node(np_ddr, np_tim)
|
||||
if (of_device_is_compatible(np_tim, tim_compat))
|
||||
arr_sz++;
|
||||
|
||||
if (arr_sz)
|
||||
timings = devm_kcalloc(dev, arr_sz, sizeof(*timings),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!timings)
|
||||
goto default_timings;
|
||||
|
||||
for_each_child_of_node(np_ddr, np_tim) {
|
||||
if (of_device_is_compatible(np_tim, tim_compat)) {
|
||||
if (of_lpddr3_do_get_timings(np_tim, &timings[i])) {
|
||||
devm_kfree(dev, timings);
|
||||
goto default_timings;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
*nr_frequencies = arr_sz;
|
||||
|
||||
return timings;
|
||||
|
||||
default_timings:
|
||||
dev_warn(dev, "%s: failed to get timings\n", __func__);
|
||||
*nr_frequencies = 0;
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(of_lpddr3_get_ddr_timings);
|
||||
|
|
|
@ -14,6 +14,11 @@ extern const struct lpddr2_min_tck *of_get_min_tck(struct device_node *np,
|
|||
extern const struct lpddr2_timings
|
||||
*of_get_ddr_timings(struct device_node *np_ddr, struct device *dev,
|
||||
u32 device_type, u32 *nr_frequencies);
|
||||
extern const struct lpddr3_min_tck
|
||||
*of_lpddr3_get_min_tck(struct device_node *np, struct device *dev);
|
||||
extern const struct lpddr3_timings
|
||||
*of_lpddr3_get_ddr_timings(struct device_node *np_ddr,
|
||||
struct device *dev, u32 device_type, u32 *nr_frequencies);
|
||||
#else
|
||||
static inline const struct lpddr2_min_tck
|
||||
*of_get_min_tck(struct device_node *np, struct device *dev)
|
||||
|
@ -27,6 +32,19 @@ static inline const struct lpddr2_timings
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline const struct lpddr3_min_tck
|
||||
*of_lpddr3_get_min_tck(struct device_node *np, struct device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline const struct lpddr3_timings
|
||||
*of_lpddr3_get_ddr_timings(struct device_node *np_ddr,
|
||||
struct device *dev, u32 device_type, u32 *nr_frequencies)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_OF && CONFIG_DDR */
|
||||
|
||||
#endif /* __LINUX_MEMORY_OF_REG_ */
|
||||
|
|
|
@ -7,6 +7,19 @@ config SAMSUNG_MC
|
|||
|
||||
if SAMSUNG_MC
|
||||
|
||||
config EXYNOS5422_DMC
|
||||
tristate "EXYNOS5422 Dynamic Memory Controller driver"
|
||||
depends on ARCH_EXYNOS || (COMPILE_TEST && HAS_IOMEM)
|
||||
select DDR
|
||||
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.
|
||||
|
||||
config EXYNOS_SROM
|
||||
bool "Exynos SROM controller driver" if COMPILE_TEST
|
||||
depends on (ARM && ARCH_EXYNOS) || (COMPILE_TEST && HAS_IOMEM)
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_EXYNOS5422_DMC) += exynos5422-dmc.o
|
||||
obj-$(CONFIG_EXYNOS_SROM) += exynos-srom.o
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -17,6 +17,16 @@ config TEGRA20_EMC
|
|||
This driver is required to change memory timings / clock rate for
|
||||
external memory.
|
||||
|
||||
config TEGRA30_EMC
|
||||
bool "NVIDIA Tegra30 External Memory Controller driver"
|
||||
default y
|
||||
depends on TEGRA_MC && ARCH_TEGRA_3x_SOC
|
||||
help
|
||||
This driver is for the External Memory Controller (EMC) found on
|
||||
Tegra30 chips. The EMC controls the external DRAM on the board.
|
||||
This driver is required to change memory timings / clock rate for
|
||||
external memory.
|
||||
|
||||
config TEGRA124_EMC
|
||||
bool "NVIDIA Tegra124 External Memory Controller driver"
|
||||
default y
|
||||
|
|
|
@ -11,5 +11,6 @@ tegra-mc-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
|
|||
obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
|
||||
|
||||
obj-$(CONFIG_TEGRA20_EMC) += tegra20-emc.o
|
||||
obj-$(CONFIG_TEGRA30_EMC) += tegra30-emc.o
|
||||
obj-$(CONFIG_TEGRA124_EMC) += tegra124-emc.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -18,39 +19,6 @@
|
|||
|
||||
#include "mc.h"
|
||||
|
||||
#define MC_INTSTATUS 0x000
|
||||
|
||||
#define MC_INTMASK 0x004
|
||||
|
||||
#define MC_ERR_STATUS 0x08
|
||||
#define MC_ERR_STATUS_TYPE_SHIFT 28
|
||||
#define MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE (6 << MC_ERR_STATUS_TYPE_SHIFT)
|
||||
#define MC_ERR_STATUS_TYPE_MASK (0x7 << MC_ERR_STATUS_TYPE_SHIFT)
|
||||
#define MC_ERR_STATUS_READABLE (1 << 27)
|
||||
#define MC_ERR_STATUS_WRITABLE (1 << 26)
|
||||
#define MC_ERR_STATUS_NONSECURE (1 << 25)
|
||||
#define MC_ERR_STATUS_ADR_HI_SHIFT 20
|
||||
#define MC_ERR_STATUS_ADR_HI_MASK 0x3
|
||||
#define MC_ERR_STATUS_SECURITY (1 << 17)
|
||||
#define MC_ERR_STATUS_RW (1 << 16)
|
||||
|
||||
#define MC_ERR_ADR 0x0c
|
||||
|
||||
#define MC_GART_ERROR_REQ 0x30
|
||||
#define MC_DECERR_EMEM_OTHERS_STATUS 0x58
|
||||
#define MC_SECURITY_VIOLATION_STATUS 0x74
|
||||
|
||||
#define MC_EMEM_ARB_CFG 0x90
|
||||
#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) (((x) & 0x1ff) << 0)
|
||||
#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff
|
||||
#define MC_EMEM_ARB_MISC0 0xd8
|
||||
|
||||
#define MC_EMEM_ADR_CFG 0x54
|
||||
#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0)
|
||||
|
||||
#define MC_TIMING_CONTROL 0xfc
|
||||
#define MC_TIMING_UPDATE BIT(0)
|
||||
|
||||
static const struct of_device_id tegra_mc_of_match[] = {
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
{ .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc },
|
||||
|
@ -307,7 +275,7 @@ static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate)
|
||||
int tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate)
|
||||
{
|
||||
unsigned int i;
|
||||
struct tegra_mc_timing *timing = NULL;
|
||||
|
@ -322,11 +290,13 @@ void tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate)
|
|||
if (!timing) {
|
||||
dev_err(mc->dev, "no memory timing registered for rate %lu\n",
|
||||
rate);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < mc->soc->num_emem_regs; ++i)
|
||||
mc_writel(mc, timing->emem_data[i], mc->soc->emem_regs[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc)
|
||||
|
@ -626,6 +596,7 @@ static int tegra_mc_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
struct tegra_mc *mc;
|
||||
void *isr;
|
||||
u64 mask;
|
||||
int err;
|
||||
|
||||
mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
|
||||
|
@ -637,6 +608,14 @@ static int tegra_mc_probe(struct platform_device *pdev)
|
|||
mc->soc = of_device_get_match_data(&pdev->dev);
|
||||
mc->dev = &pdev->dev;
|
||||
|
||||
mask = DMA_BIT_MASK(mc->soc->num_address_bits);
|
||||
|
||||
err = dma_coerce_mask_and_coherent(&pdev->dev, mask);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* length of MC tick in nanoseconds */
|
||||
mc->tick = 30;
|
||||
|
||||
|
@ -658,6 +637,9 @@ static int tegra_mc_probe(struct platform_device *pdev)
|
|||
} else
|
||||
#endif
|
||||
{
|
||||
/* ensure that debug features are disabled */
|
||||
mc_writel(mc, 0x00000000, MC_TIMING_CONTROL_DBG);
|
||||
|
||||
err = tegra_mc_setup_latency_allowance(mc);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
|
|
|
@ -6,20 +6,76 @@
|
|||
#ifndef MEMORY_TEGRA_MC_H
|
||||
#define MEMORY_TEGRA_MC_H
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <soc/tegra/mc.h>
|
||||
|
||||
#define MC_INT_DECERR_MTS (1 << 16)
|
||||
#define MC_INT_SECERR_SEC (1 << 13)
|
||||
#define MC_INT_DECERR_VPR (1 << 12)
|
||||
#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11)
|
||||
#define MC_INT_INVALID_SMMU_PAGE (1 << 10)
|
||||
#define MC_INT_ARBITRATION_EMEM (1 << 9)
|
||||
#define MC_INT_SECURITY_VIOLATION (1 << 8)
|
||||
#define MC_INT_INVALID_GART_PAGE (1 << 7)
|
||||
#define MC_INT_DECERR_EMEM (1 << 6)
|
||||
#define MC_INTSTATUS 0x00
|
||||
#define MC_INTMASK 0x04
|
||||
#define MC_ERR_STATUS 0x08
|
||||
#define MC_ERR_ADR 0x0c
|
||||
#define MC_GART_ERROR_REQ 0x30
|
||||
#define MC_EMEM_ADR_CFG 0x54
|
||||
#define MC_DECERR_EMEM_OTHERS_STATUS 0x58
|
||||
#define MC_SECURITY_VIOLATION_STATUS 0x74
|
||||
#define MC_EMEM_ARB_CFG 0x90
|
||||
#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
|
||||
#define MC_EMEM_ARB_TIMING_RCD 0x98
|
||||
#define MC_EMEM_ARB_TIMING_RP 0x9c
|
||||
#define MC_EMEM_ARB_TIMING_RC 0xa0
|
||||
#define MC_EMEM_ARB_TIMING_RAS 0xa4
|
||||
#define MC_EMEM_ARB_TIMING_FAW 0xa8
|
||||
#define MC_EMEM_ARB_TIMING_RRD 0xac
|
||||
#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0
|
||||
#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4
|
||||
#define MC_EMEM_ARB_TIMING_R2R 0xb8
|
||||
#define MC_EMEM_ARB_TIMING_W2W 0xbc
|
||||
#define MC_EMEM_ARB_TIMING_R2W 0xc0
|
||||
#define MC_EMEM_ARB_TIMING_W2R 0xc4
|
||||
#define MC_EMEM_ARB_DA_TURNS 0xd0
|
||||
#define MC_EMEM_ARB_DA_COVERS 0xd4
|
||||
#define MC_EMEM_ARB_MISC0 0xd8
|
||||
#define MC_EMEM_ARB_MISC1 0xdc
|
||||
#define MC_EMEM_ARB_RING1_THROTTLE 0xe0
|
||||
#define MC_EMEM_ARB_OVERRIDE 0xe8
|
||||
#define MC_TIMING_CONTROL_DBG 0xf8
|
||||
#define MC_TIMING_CONTROL 0xfc
|
||||
|
||||
#define MC_INT_DECERR_MTS BIT(16)
|
||||
#define MC_INT_SECERR_SEC BIT(13)
|
||||
#define MC_INT_DECERR_VPR BIT(12)
|
||||
#define MC_INT_INVALID_APB_ASID_UPDATE BIT(11)
|
||||
#define MC_INT_INVALID_SMMU_PAGE BIT(10)
|
||||
#define MC_INT_ARBITRATION_EMEM BIT(9)
|
||||
#define MC_INT_SECURITY_VIOLATION BIT(8)
|
||||
#define MC_INT_INVALID_GART_PAGE BIT(7)
|
||||
#define MC_INT_DECERR_EMEM BIT(6)
|
||||
|
||||
#define MC_ERR_STATUS_TYPE_SHIFT 28
|
||||
#define MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE (0x6 << 28)
|
||||
#define MC_ERR_STATUS_TYPE_MASK (0x7 << 28)
|
||||
#define MC_ERR_STATUS_READABLE BIT(27)
|
||||
#define MC_ERR_STATUS_WRITABLE BIT(26)
|
||||
#define MC_ERR_STATUS_NONSECURE BIT(25)
|
||||
#define MC_ERR_STATUS_ADR_HI_SHIFT 20
|
||||
#define MC_ERR_STATUS_ADR_HI_MASK 0x3
|
||||
#define MC_ERR_STATUS_SECURITY BIT(17)
|
||||
#define MC_ERR_STATUS_RW BIT(16)
|
||||
|
||||
#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0)
|
||||
|
||||
#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) ((x) & 0x1ff)
|
||||
#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff
|
||||
|
||||
#define MC_EMEM_ARB_OUTSTANDING_REQ_MAX_MASK 0x1ff
|
||||
#define MC_EMEM_ARB_OUTSTANDING_REQ_HOLDOFF_OVERRIDE BIT(30)
|
||||
#define MC_EMEM_ARB_OUTSTANDING_REQ_LIMIT_ENABLE BIT(31)
|
||||
|
||||
#define MC_EMEM_ARB_OVERRIDE_EACK_MASK 0x3
|
||||
|
||||
#define MC_TIMING_UPDATE BIT(0)
|
||||
|
||||
static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset)
|
||||
{
|
||||
|
|
|
@ -909,16 +909,18 @@ static const struct tegra_smmu_swgroup tegra114_swgroups[] = {
|
|||
{ .name = "tsec", .swgroup = TEGRA_SWGROUP_TSEC, .reg = 0x294 },
|
||||
};
|
||||
|
||||
static const unsigned int tegra114_group_display[] = {
|
||||
static const unsigned int tegra114_group_drm[] = {
|
||||
TEGRA_SWGROUP_DC,
|
||||
TEGRA_SWGROUP_DCB,
|
||||
TEGRA_SWGROUP_G2,
|
||||
TEGRA_SWGROUP_NV,
|
||||
};
|
||||
|
||||
static const struct tegra_smmu_group_soc tegra114_groups[] = {
|
||||
{
|
||||
.name = "display",
|
||||
.swgroups = tegra114_group_display,
|
||||
.num_swgroups = ARRAY_SIZE(tegra114_group_display),
|
||||
.name = "drm",
|
||||
.swgroups = tegra114_group_drm,
|
||||
.num_swgroups = ARRAY_SIZE(tegra114_group_drm),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -10,26 +10,6 @@
|
|||
|
||||
#include "mc.h"
|
||||
|
||||
#define MC_EMEM_ARB_CFG 0x90
|
||||
#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
|
||||
#define MC_EMEM_ARB_TIMING_RCD 0x98
|
||||
#define MC_EMEM_ARB_TIMING_RP 0x9c
|
||||
#define MC_EMEM_ARB_TIMING_RC 0xa0
|
||||
#define MC_EMEM_ARB_TIMING_RAS 0xa4
|
||||
#define MC_EMEM_ARB_TIMING_FAW 0xa8
|
||||
#define MC_EMEM_ARB_TIMING_RRD 0xac
|
||||
#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0
|
||||
#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4
|
||||
#define MC_EMEM_ARB_TIMING_R2R 0xb8
|
||||
#define MC_EMEM_ARB_TIMING_W2W 0xbc
|
||||
#define MC_EMEM_ARB_TIMING_R2W 0xc0
|
||||
#define MC_EMEM_ARB_TIMING_W2R 0xc4
|
||||
#define MC_EMEM_ARB_DA_TURNS 0xd0
|
||||
#define MC_EMEM_ARB_DA_COVERS 0xd4
|
||||
#define MC_EMEM_ARB_MISC0 0xd8
|
||||
#define MC_EMEM_ARB_MISC1 0xdc
|
||||
#define MC_EMEM_ARB_RING1_THROTTLE 0xe0
|
||||
|
||||
static const struct tegra_mc_client tegra124_mc_clients[] = {
|
||||
{
|
||||
.id = 0x00,
|
||||
|
@ -974,16 +954,18 @@ static const struct tegra_smmu_swgroup tegra124_swgroups[] = {
|
|||
{ .name = "vi", .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 },
|
||||
};
|
||||
|
||||
static const unsigned int tegra124_group_display[] = {
|
||||
static const unsigned int tegra124_group_drm[] = {
|
||||
TEGRA_SWGROUP_DC,
|
||||
TEGRA_SWGROUP_DCB,
|
||||
TEGRA_SWGROUP_GPU,
|
||||
TEGRA_SWGROUP_VIC,
|
||||
};
|
||||
|
||||
static const struct tegra_smmu_group_soc tegra124_groups[] = {
|
||||
{
|
||||
.name = "display",
|
||||
.swgroups = tegra124_group_display,
|
||||
.num_swgroups = ARRAY_SIZE(tegra124_group_display),
|
||||
.name = "drm",
|
||||
.swgroups = tegra124_group_drm,
|
||||
.num_swgroups = ARRAY_SIZE(tegra124_group_drm),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -6,10 +6,11 @@
|
|||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
|
@ -21,6 +22,7 @@
|
|||
|
||||
#define EMC_INTSTATUS 0x000
|
||||
#define EMC_INTMASK 0x004
|
||||
#define EMC_DBG 0x008
|
||||
#define EMC_TIMING_CONTROL 0x028
|
||||
#define EMC_RC 0x02c
|
||||
#define EMC_RFC 0x030
|
||||
|
@ -79,6 +81,12 @@
|
|||
#define EMC_REFRESH_OVERFLOW_INT BIT(3)
|
||||
#define EMC_CLKCHANGE_COMPLETE_INT BIT(4)
|
||||
|
||||
#define EMC_DBG_READ_MUX_ASSEMBLY BIT(0)
|
||||
#define EMC_DBG_WRITE_MUX_ACTIVE BIT(1)
|
||||
#define EMC_DBG_FORCE_UPDATE BIT(2)
|
||||
#define EMC_DBG_READ_DQM_CTRL BIT(9)
|
||||
#define EMC_DBG_CFG_PRIORITY BIT(24)
|
||||
|
||||
static const u16 emc_timing_registers[] = {
|
||||
EMC_RC,
|
||||
EMC_RFC,
|
||||
|
@ -137,9 +145,6 @@ struct tegra_emc {
|
|||
struct device *dev;
|
||||
struct completion clk_handshake_complete;
|
||||
struct notifier_block clk_nb;
|
||||
struct clk *backup_clk;
|
||||
struct clk *emc_mux;
|
||||
struct clk *pll_m;
|
||||
struct clk *clk;
|
||||
void __iomem *regs;
|
||||
|
||||
|
@ -219,7 +224,7 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate)
|
|||
|
||||
static int emc_complete_timing_change(struct tegra_emc *emc, bool flush)
|
||||
{
|
||||
long timeout;
|
||||
unsigned long timeout;
|
||||
|
||||
dev_dbg(emc->dev, "%s: flush %d\n", __func__, flush);
|
||||
|
||||
|
@ -231,14 +236,10 @@ static int emc_complete_timing_change(struct tegra_emc *emc, bool flush)
|
|||
}
|
||||
|
||||
timeout = wait_for_completion_timeout(&emc->clk_handshake_complete,
|
||||
usecs_to_jiffies(100));
|
||||
msecs_to_jiffies(100));
|
||||
if (timeout == 0) {
|
||||
dev_err(emc->dev, "EMC-CAR handshake failed\n");
|
||||
return -EIO;
|
||||
} else if (timeout < 0) {
|
||||
dev_err(emc->dev, "failed to wait for EMC-CAR handshake: %ld\n",
|
||||
timeout);
|
||||
return timeout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -363,6 +364,13 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
|
|||
sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings,
|
||||
NULL);
|
||||
|
||||
dev_info(emc->dev,
|
||||
"got %u timings for RAM code %u (min %luMHz max %luMHz)\n",
|
||||
emc->num_timings,
|
||||
tegra_read_ram_code(),
|
||||
emc->timings[0].rate / 1000000,
|
||||
emc->timings[emc->num_timings - 1].rate / 1000000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -398,7 +406,7 @@ tegra_emc_find_node_by_ram_code(struct device *dev)
|
|||
static int emc_setup_hw(struct tegra_emc *emc)
|
||||
{
|
||||
u32 intmask = EMC_REFRESH_OVERFLOW_INT | EMC_CLKCHANGE_COMPLETE_INT;
|
||||
u32 emc_cfg;
|
||||
u32 emc_cfg, emc_dbg;
|
||||
|
||||
emc_cfg = readl_relaxed(emc->regs + EMC_CFG_2);
|
||||
|
||||
|
@ -421,42 +429,53 @@ static int emc_setup_hw(struct tegra_emc *emc)
|
|||
writel_relaxed(intmask, emc->regs + EMC_INTMASK);
|
||||
writel_relaxed(intmask, emc->regs + EMC_INTSTATUS);
|
||||
|
||||
/* ensure that unwanted debug features are disabled */
|
||||
emc_dbg = readl_relaxed(emc->regs + EMC_DBG);
|
||||
emc_dbg |= EMC_DBG_CFG_PRIORITY;
|
||||
emc_dbg &= ~EMC_DBG_READ_MUX_ASSEMBLY;
|
||||
emc_dbg &= ~EMC_DBG_WRITE_MUX_ACTIVE;
|
||||
emc_dbg &= ~EMC_DBG_FORCE_UPDATE;
|
||||
writel_relaxed(emc_dbg, emc->regs + EMC_DBG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emc_init(struct tegra_emc *emc, unsigned long rate)
|
||||
static long emc_round_rate(unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
void *arg)
|
||||
{
|
||||
int err;
|
||||
struct emc_timing *timing = NULL;
|
||||
struct tegra_emc *emc = arg;
|
||||
unsigned int i;
|
||||
|
||||
err = clk_set_parent(emc->emc_mux, emc->backup_clk);
|
||||
if (err) {
|
||||
dev_err(emc->dev,
|
||||
"failed to reparent to backup source: %d\n", err);
|
||||
return err;
|
||||
min_rate = min(min_rate, emc->timings[emc->num_timings - 1].rate);
|
||||
|
||||
for (i = 0; i < emc->num_timings; i++) {
|
||||
if (emc->timings[i].rate < rate && i != emc->num_timings - 1)
|
||||
continue;
|
||||
|
||||
if (emc->timings[i].rate > max_rate) {
|
||||
i = max(i, 1u) - 1;
|
||||
|
||||
if (emc->timings[i].rate < min_rate)
|
||||
break;
|
||||
}
|
||||
|
||||
if (emc->timings[i].rate < min_rate)
|
||||
continue;
|
||||
|
||||
timing = &emc->timings[i];
|
||||
break;
|
||||
}
|
||||
|
||||
err = clk_set_rate(emc->pll_m, rate);
|
||||
if (err) {
|
||||
dev_err(emc->dev,
|
||||
"failed to change pll_m rate: %d\n", err);
|
||||
return err;
|
||||
if (!timing) {
|
||||
dev_err(emc->dev, "no timing for rate %lu min %lu max %lu\n",
|
||||
rate, min_rate, max_rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = clk_set_parent(emc->emc_mux, emc->pll_m);
|
||||
if (err) {
|
||||
dev_err(emc->dev,
|
||||
"failed to reparent to pll_m: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_set_rate(emc->clk, rate);
|
||||
if (err) {
|
||||
dev_err(emc->dev,
|
||||
"failed to change emc rate: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return timing->rate;
|
||||
}
|
||||
|
||||
static int tegra_emc_probe(struct platform_device *pdev)
|
||||
|
@ -515,57 +534,26 @@ static int tegra_emc_probe(struct platform_device *pdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
tegra20_clk_set_emc_round_callback(emc_round_rate, emc);
|
||||
|
||||
emc->clk = devm_clk_get(&pdev->dev, "emc");
|
||||
if (IS_ERR(emc->clk)) {
|
||||
err = PTR_ERR(emc->clk);
|
||||
dev_err(&pdev->dev, "failed to get emc clock: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
emc->pll_m = clk_get_sys(NULL, "pll_m");
|
||||
if (IS_ERR(emc->pll_m)) {
|
||||
err = PTR_ERR(emc->pll_m);
|
||||
dev_err(&pdev->dev, "failed to get pll_m clock: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
emc->backup_clk = clk_get_sys(NULL, "pll_p");
|
||||
if (IS_ERR(emc->backup_clk)) {
|
||||
err = PTR_ERR(emc->backup_clk);
|
||||
dev_err(&pdev->dev, "failed to get pll_p clock: %d\n", err);
|
||||
goto put_pll_m;
|
||||
}
|
||||
|
||||
emc->emc_mux = clk_get_parent(emc->clk);
|
||||
if (IS_ERR(emc->emc_mux)) {
|
||||
err = PTR_ERR(emc->emc_mux);
|
||||
dev_err(&pdev->dev, "failed to get emc_mux clock: %d\n", err);
|
||||
goto put_backup;
|
||||
goto unset_cb;
|
||||
}
|
||||
|
||||
err = clk_notifier_register(emc->clk, &emc->clk_nb);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to register clk notifier: %d\n",
|
||||
err);
|
||||
goto put_backup;
|
||||
}
|
||||
|
||||
/* set DRAM clock rate to maximum */
|
||||
err = emc_init(emc, emc->timings[emc->num_timings - 1].rate);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to initialize EMC clock rate: %d\n",
|
||||
err);
|
||||
goto unreg_notifier;
|
||||
goto unset_cb;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unreg_notifier:
|
||||
clk_notifier_unregister(emc->clk, &emc->clk_nb);
|
||||
put_backup:
|
||||
clk_put(emc->backup_clk);
|
||||
put_pll_m:
|
||||
clk_put(emc->pll_m);
|
||||
unset_cb:
|
||||
tegra20_clk_set_emc_round_callback(NULL, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -10,6 +10,27 @@
|
|||
|
||||
#include "mc.h"
|
||||
|
||||
static const unsigned long tegra30_mc_emem_regs[] = {
|
||||
MC_EMEM_ARB_CFG,
|
||||
MC_EMEM_ARB_OUTSTANDING_REQ,
|
||||
MC_EMEM_ARB_TIMING_RCD,
|
||||
MC_EMEM_ARB_TIMING_RP,
|
||||
MC_EMEM_ARB_TIMING_RC,
|
||||
MC_EMEM_ARB_TIMING_RAS,
|
||||
MC_EMEM_ARB_TIMING_FAW,
|
||||
MC_EMEM_ARB_TIMING_RRD,
|
||||
MC_EMEM_ARB_TIMING_RAP2PRE,
|
||||
MC_EMEM_ARB_TIMING_WAP2PRE,
|
||||
MC_EMEM_ARB_TIMING_R2R,
|
||||
MC_EMEM_ARB_TIMING_W2W,
|
||||
MC_EMEM_ARB_TIMING_R2W,
|
||||
MC_EMEM_ARB_TIMING_W2R,
|
||||
MC_EMEM_ARB_DA_TURNS,
|
||||
MC_EMEM_ARB_DA_COVERS,
|
||||
MC_EMEM_ARB_MISC0,
|
||||
MC_EMEM_ARB_RING1_THROTTLE,
|
||||
};
|
||||
|
||||
static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||
{
|
||||
.id = 0x00,
|
||||
|
@ -931,16 +952,19 @@ static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
|
|||
{ .name = "isp", .swgroup = TEGRA_SWGROUP_ISP, .reg = 0x258 },
|
||||
};
|
||||
|
||||
static const unsigned int tegra30_group_display[] = {
|
||||
static const unsigned int tegra30_group_drm[] = {
|
||||
TEGRA_SWGROUP_DC,
|
||||
TEGRA_SWGROUP_DCB,
|
||||
TEGRA_SWGROUP_G2,
|
||||
TEGRA_SWGROUP_NV,
|
||||
TEGRA_SWGROUP_NV2,
|
||||
};
|
||||
|
||||
static const struct tegra_smmu_group_soc tegra30_groups[] = {
|
||||
{
|
||||
.name = "display",
|
||||
.swgroups = tegra30_group_display,
|
||||
.num_swgroups = ARRAY_SIZE(tegra30_group_display),
|
||||
.name = "drm",
|
||||
.swgroups = tegra30_group_drm,
|
||||
.num_swgroups = ARRAY_SIZE(tegra30_group_drm),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -994,6 +1018,8 @@ const struct tegra_mc_soc tegra30_mc_soc = {
|
|||
.atom_size = 16,
|
||||
.client_id_mask = 0x7f,
|
||||
.smmu = &tegra30_smmu_soc,
|
||||
.emem_regs = tegra30_mc_emem_regs,
|
||||
.num_emem_regs = ARRAY_SIZE(tegra30_mc_emem_regs),
|
||||
.intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
|
||||
MC_INT_DECERR_EMEM,
|
||||
.reset_ops = &tegra_mc_reset_ops_common,
|
||||
|
|
|
@ -17,14 +17,18 @@
|
|||
static int meson_efuse_read(void *context, unsigned int offset,
|
||||
void *val, size_t bytes)
|
||||
{
|
||||
return meson_sm_call_read((u8 *)val, bytes, SM_EFUSE_READ, offset,
|
||||
struct meson_sm_firmware *fw = context;
|
||||
|
||||
return meson_sm_call_read(fw, (u8 *)val, bytes, SM_EFUSE_READ, offset,
|
||||
bytes, 0, 0, 0);
|
||||
}
|
||||
|
||||
static int meson_efuse_write(void *context, unsigned int offset,
|
||||
void *val, size_t bytes)
|
||||
{
|
||||
return meson_sm_call_write((u8 *)val, bytes, SM_EFUSE_WRITE, offset,
|
||||
struct meson_sm_firmware *fw = context;
|
||||
|
||||
return meson_sm_call_write(fw, (u8 *)val, bytes, SM_EFUSE_WRITE, offset,
|
||||
bytes, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
@ -37,12 +41,25 @@ MODULE_DEVICE_TABLE(of, meson_efuse_match);
|
|||
static int meson_efuse_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct meson_sm_firmware *fw;
|
||||
struct device_node *sm_np;
|
||||
struct nvmem_device *nvmem;
|
||||
struct nvmem_config *econfig;
|
||||
struct clk *clk;
|
||||
unsigned int size;
|
||||
int ret;
|
||||
|
||||
sm_np = of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0);
|
||||
if (!sm_np) {
|
||||
dev_err(&pdev->dev, "no secure-monitor node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
fw = meson_sm_get(sm_np);
|
||||
of_node_put(sm_np);
|
||||
if (!fw)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
|
@ -65,7 +82,7 @@ static int meson_efuse_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (meson_sm_call(SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) {
|
||||
if (meson_sm_call(fw, SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) {
|
||||
dev_err(dev, "failed to get max user");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -81,6 +98,7 @@ static int meson_efuse_probe(struct platform_device *pdev)
|
|||
econfig->reg_read = meson_efuse_read;
|
||||
econfig->reg_write = meson_efuse_write;
|
||||
econfig->size = size;
|
||||
econfig->priv = fw;
|
||||
|
||||
nvmem = devm_nvmem_register(&pdev->dev, econfig);
|
||||
|
||||
|
|
|
@ -103,3 +103,14 @@ config PHY_PXA_USB
|
|||
The PHY driver will be used by Marvell udc/ehci/otg driver.
|
||||
|
||||
To compile this driver as a module, choose M here.
|
||||
|
||||
config PHY_MMP3_USB
|
||||
tristate "Marvell MMP3 USB PHY Driver"
|
||||
depends on MACH_MMP3_DT || COMPILE_TEST
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support Marvell MMP3 USB PHY driver for Marvell
|
||||
SoC. This driver will do the PHY initialization and shutdown.
|
||||
The PHY driver will be used by Marvell udc/ehci/otg driver.
|
||||
|
||||
To compile this driver as a module, choose M here.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o
|
||||
obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o
|
||||
obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o
|
||||
obj-$(CONFIG_PHY_MMP3_USB) += phy-mmp3-usb.o
|
||||
obj-$(CONFIG_PHY_MVEBU_A3700_COMPHY) += phy-mvebu-a3700-comphy.o
|
||||
obj-$(CONFIG_PHY_MVEBU_A3700_UTMI) += phy-mvebu-a3700-utmi.o
|
||||
obj-$(CONFIG_PHY_MVEBU_A38X_COMPHY) += phy-armada38x-comphy.o
|
||||
|
|
|
@ -0,0 +1,291 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2011 Marvell International Ltd. All rights reserved.
|
||||
* Copyright (C) 2018,2019 Lubomir Rintel <lkundrak@v3.sk>
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/soc/mmp/cputype.h>
|
||||
|
||||
#define USB2_PLL_REG0 0x4
|
||||
#define USB2_PLL_REG1 0x8
|
||||
#define USB2_TX_REG0 0x10
|
||||
#define USB2_TX_REG1 0x14
|
||||
#define USB2_TX_REG2 0x18
|
||||
#define USB2_RX_REG0 0x20
|
||||
#define USB2_RX_REG1 0x24
|
||||
#define USB2_RX_REG2 0x28
|
||||
#define USB2_ANA_REG0 0x30
|
||||
#define USB2_ANA_REG1 0x34
|
||||
#define USB2_ANA_REG2 0x38
|
||||
#define USB2_DIG_REG0 0x3C
|
||||
#define USB2_DIG_REG1 0x40
|
||||
#define USB2_DIG_REG2 0x44
|
||||
#define USB2_DIG_REG3 0x48
|
||||
#define USB2_TEST_REG0 0x4C
|
||||
#define USB2_TEST_REG1 0x50
|
||||
#define USB2_TEST_REG2 0x54
|
||||
#define USB2_CHARGER_REG0 0x58
|
||||
#define USB2_OTG_REG0 0x5C
|
||||
#define USB2_PHY_MON0 0x60
|
||||
#define USB2_RESETVE_REG0 0x64
|
||||
#define USB2_ICID_REG0 0x78
|
||||
#define USB2_ICID_REG1 0x7C
|
||||
|
||||
/* USB2_PLL_REG0 */
|
||||
|
||||
/* This is for Ax stepping */
|
||||
#define USB2_PLL_FBDIV_SHIFT_MMP3 0
|
||||
#define USB2_PLL_FBDIV_MASK_MMP3 (0xFF << 0)
|
||||
|
||||
#define USB2_PLL_REFDIV_SHIFT_MMP3 8
|
||||
#define USB2_PLL_REFDIV_MASK_MMP3 (0xF << 8)
|
||||
|
||||
#define USB2_PLL_VDD12_SHIFT_MMP3 12
|
||||
#define USB2_PLL_VDD18_SHIFT_MMP3 14
|
||||
|
||||
/* This is for B0 stepping */
|
||||
#define USB2_PLL_FBDIV_SHIFT_MMP3_B0 0
|
||||
#define USB2_PLL_REFDIV_SHIFT_MMP3_B0 9
|
||||
#define USB2_PLL_VDD18_SHIFT_MMP3_B0 14
|
||||
#define USB2_PLL_FBDIV_MASK_MMP3_B0 0x01FF
|
||||
#define USB2_PLL_REFDIV_MASK_MMP3_B0 0x3E00
|
||||
|
||||
#define USB2_PLL_CAL12_SHIFT_MMP3 0
|
||||
#define USB2_PLL_CALI12_MASK_MMP3 (0x3 << 0)
|
||||
|
||||
#define USB2_PLL_VCOCAL_START_SHIFT_MMP3 2
|
||||
|
||||
#define USB2_PLL_KVCO_SHIFT_MMP3 4
|
||||
#define USB2_PLL_KVCO_MASK_MMP3 (0x7<<4)
|
||||
|
||||
#define USB2_PLL_ICP_SHIFT_MMP3 8
|
||||
#define USB2_PLL_ICP_MASK_MMP3 (0x7<<8)
|
||||
|
||||
#define USB2_PLL_LOCK_BYPASS_SHIFT_MMP3 12
|
||||
|
||||
#define USB2_PLL_PU_PLL_SHIFT_MMP3 13
|
||||
#define USB2_PLL_PU_PLL_MASK (0x1 << 13)
|
||||
|
||||
#define USB2_PLL_READY_MASK_MMP3 (0x1 << 15)
|
||||
|
||||
/* USB2_TX_REG0 */
|
||||
#define USB2_TX_IMPCAL_VTH_SHIFT_MMP3 8
|
||||
#define USB2_TX_IMPCAL_VTH_MASK_MMP3 (0x7 << 8)
|
||||
|
||||
#define USB2_TX_RCAL_START_SHIFT_MMP3 13
|
||||
|
||||
/* USB2_TX_REG1 */
|
||||
#define USB2_TX_CK60_PHSEL_SHIFT_MMP3 0
|
||||
#define USB2_TX_CK60_PHSEL_MASK_MMP3 (0xf << 0)
|
||||
|
||||
#define USB2_TX_AMP_SHIFT_MMP3 4
|
||||
#define USB2_TX_AMP_MASK_MMP3 (0x7 << 4)
|
||||
|
||||
#define USB2_TX_VDD12_SHIFT_MMP3 8
|
||||
#define USB2_TX_VDD12_MASK_MMP3 (0x3 << 8)
|
||||
|
||||
/* USB2_TX_REG2 */
|
||||
#define USB2_TX_DRV_SLEWRATE_SHIFT 10
|
||||
|
||||
/* USB2_RX_REG0 */
|
||||
#define USB2_RX_SQ_THRESH_SHIFT_MMP3 4
|
||||
#define USB2_RX_SQ_THRESH_MASK_MMP3 (0xf << 4)
|
||||
|
||||
#define USB2_RX_SQ_LENGTH_SHIFT_MMP3 10
|
||||
#define USB2_RX_SQ_LENGTH_MASK_MMP3 (0x3 << 10)
|
||||
|
||||
/* USB2_ANA_REG1*/
|
||||
#define USB2_ANA_PU_ANA_SHIFT_MMP3 14
|
||||
|
||||
/* USB2_OTG_REG0 */
|
||||
#define USB2_OTG_PU_OTG_SHIFT_MMP3 3
|
||||
|
||||
struct mmp3_usb_phy {
|
||||
struct phy *phy;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
static unsigned int u2o_get(void __iomem *base, unsigned int offset)
|
||||
{
|
||||
return readl_relaxed(base + offset);
|
||||
}
|
||||
|
||||
static void u2o_set(void __iomem *base, unsigned int offset,
|
||||
unsigned int value)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = readl_relaxed(base + offset);
|
||||
reg |= value;
|
||||
writel_relaxed(reg, base + offset);
|
||||
readl_relaxed(base + offset);
|
||||
}
|
||||
|
||||
static void u2o_clear(void __iomem *base, unsigned int offset,
|
||||
unsigned int value)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = readl_relaxed(base + offset);
|
||||
reg &= ~value;
|
||||
writel_relaxed(reg, base + offset);
|
||||
readl_relaxed(base + offset);
|
||||
}
|
||||
|
||||
static int mmp3_usb_phy_init(struct phy *phy)
|
||||
{
|
||||
struct mmp3_usb_phy *mmp3_usb_phy = phy_get_drvdata(phy);
|
||||
void __iomem *base = mmp3_usb_phy->base;
|
||||
|
||||
if (cpu_is_mmp3_a0()) {
|
||||
u2o_clear(base, USB2_PLL_REG0, (USB2_PLL_FBDIV_MASK_MMP3
|
||||
| USB2_PLL_REFDIV_MASK_MMP3));
|
||||
u2o_set(base, USB2_PLL_REG0,
|
||||
0xd << USB2_PLL_REFDIV_SHIFT_MMP3
|
||||
| 0xf0 << USB2_PLL_FBDIV_SHIFT_MMP3);
|
||||
} else if (cpu_is_mmp3_b0()) {
|
||||
u2o_clear(base, USB2_PLL_REG0, USB2_PLL_REFDIV_MASK_MMP3_B0
|
||||
| USB2_PLL_FBDIV_MASK_MMP3_B0);
|
||||
u2o_set(base, USB2_PLL_REG0,
|
||||
0xd << USB2_PLL_REFDIV_SHIFT_MMP3_B0
|
||||
| 0xf0 << USB2_PLL_FBDIV_SHIFT_MMP3_B0);
|
||||
} else {
|
||||
dev_err(&phy->dev, "unsupported silicon revision\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
u2o_clear(base, USB2_PLL_REG1, USB2_PLL_PU_PLL_MASK
|
||||
| USB2_PLL_ICP_MASK_MMP3
|
||||
| USB2_PLL_KVCO_MASK_MMP3
|
||||
| USB2_PLL_CALI12_MASK_MMP3);
|
||||
u2o_set(base, USB2_PLL_REG1, 1 << USB2_PLL_PU_PLL_SHIFT_MMP3
|
||||
| 1 << USB2_PLL_LOCK_BYPASS_SHIFT_MMP3
|
||||
| 3 << USB2_PLL_ICP_SHIFT_MMP3
|
||||
| 3 << USB2_PLL_KVCO_SHIFT_MMP3
|
||||
| 3 << USB2_PLL_CAL12_SHIFT_MMP3);
|
||||
|
||||
u2o_clear(base, USB2_TX_REG0, USB2_TX_IMPCAL_VTH_MASK_MMP3);
|
||||
u2o_set(base, USB2_TX_REG0, 2 << USB2_TX_IMPCAL_VTH_SHIFT_MMP3);
|
||||
|
||||
u2o_clear(base, USB2_TX_REG1, USB2_TX_VDD12_MASK_MMP3
|
||||
| USB2_TX_AMP_MASK_MMP3
|
||||
| USB2_TX_CK60_PHSEL_MASK_MMP3);
|
||||
u2o_set(base, USB2_TX_REG1, 3 << USB2_TX_VDD12_SHIFT_MMP3
|
||||
| 4 << USB2_TX_AMP_SHIFT_MMP3
|
||||
| 4 << USB2_TX_CK60_PHSEL_SHIFT_MMP3);
|
||||
|
||||
u2o_clear(base, USB2_TX_REG2, 3 << USB2_TX_DRV_SLEWRATE_SHIFT);
|
||||
u2o_set(base, USB2_TX_REG2, 2 << USB2_TX_DRV_SLEWRATE_SHIFT);
|
||||
|
||||
u2o_clear(base, USB2_RX_REG0, USB2_RX_SQ_THRESH_MASK_MMP3);
|
||||
u2o_set(base, USB2_RX_REG0, 0xa << USB2_RX_SQ_THRESH_SHIFT_MMP3);
|
||||
|
||||
u2o_set(base, USB2_ANA_REG1, 0x1 << USB2_ANA_PU_ANA_SHIFT_MMP3);
|
||||
|
||||
u2o_set(base, USB2_OTG_REG0, 0x1 << USB2_OTG_PU_OTG_SHIFT_MMP3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmp3_usb_phy_calibrate(struct phy *phy)
|
||||
{
|
||||
struct mmp3_usb_phy *mmp3_usb_phy = phy_get_drvdata(phy);
|
||||
void __iomem *base = mmp3_usb_phy->base;
|
||||
int loops;
|
||||
|
||||
/*
|
||||
* PLL VCO and TX Impedance Calibration Timing:
|
||||
*
|
||||
* _____________________________________
|
||||
* PU __________|
|
||||
* _____________________________
|
||||
* VCOCAL START _________|
|
||||
* ___
|
||||
* REG_RCAL_START ________________| |________|_______
|
||||
* | 200us | 400us | 40| 400us | USB PHY READY
|
||||
*/
|
||||
|
||||
udelay(200);
|
||||
u2o_set(base, USB2_PLL_REG1, 1 << USB2_PLL_VCOCAL_START_SHIFT_MMP3);
|
||||
udelay(400);
|
||||
u2o_set(base, USB2_TX_REG0, 1 << USB2_TX_RCAL_START_SHIFT_MMP3);
|
||||
udelay(40);
|
||||
u2o_clear(base, USB2_TX_REG0, 1 << USB2_TX_RCAL_START_SHIFT_MMP3);
|
||||
udelay(400);
|
||||
|
||||
loops = 0;
|
||||
while ((u2o_get(base, USB2_PLL_REG1) & USB2_PLL_READY_MASK_MMP3) == 0) {
|
||||
mdelay(1);
|
||||
loops++;
|
||||
if (loops > 100) {
|
||||
dev_err(&phy->dev, "PLL_READY not set after 100mS.\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops mmp3_usb_phy_ops = {
|
||||
.init = mmp3_usb_phy_init,
|
||||
.calibrate = mmp3_usb_phy_calibrate,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id mmp3_usb_phy_of_match[] = {
|
||||
{ .compatible = "marvell,mmp3-usb-phy", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mmp3_usb_phy_of_match);
|
||||
|
||||
static int mmp3_usb_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *resource;
|
||||
struct mmp3_usb_phy *mmp3_usb_phy;
|
||||
struct phy_provider *provider;
|
||||
|
||||
mmp3_usb_phy = devm_kzalloc(dev, sizeof(*mmp3_usb_phy), GFP_KERNEL);
|
||||
if (!mmp3_usb_phy)
|
||||
return -ENOMEM;
|
||||
|
||||
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
mmp3_usb_phy->base = devm_ioremap_resource(dev, resource);
|
||||
if (IS_ERR(mmp3_usb_phy->base)) {
|
||||
dev_err(dev, "failed to remap PHY regs\n");
|
||||
return PTR_ERR(mmp3_usb_phy->base);
|
||||
}
|
||||
|
||||
mmp3_usb_phy->phy = devm_phy_create(dev, NULL, &mmp3_usb_phy_ops);
|
||||
if (IS_ERR(mmp3_usb_phy->phy)) {
|
||||
dev_err(dev, "failed to create PHY\n");
|
||||
return PTR_ERR(mmp3_usb_phy->phy);
|
||||
}
|
||||
|
||||
phy_set_drvdata(mmp3_usb_phy->phy, mmp3_usb_phy);
|
||||
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(provider)) {
|
||||
dev_err(dev, "failed to register PHY provider\n");
|
||||
return PTR_ERR(provider);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mmp3_usb_phy_driver = {
|
||||
.probe = mmp3_usb_phy_probe,
|
||||
.driver = {
|
||||
.name = "mmp3-usb-phy",
|
||||
.of_match_table = mmp3_usb_phy_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(mmp3_usb_phy_driver);
|
||||
|
||||
MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
|
||||
MODULE_DESCRIPTION("Marvell MMP3 USB PHY Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -129,7 +129,7 @@ config RESET_SCMI
|
|||
|
||||
config RESET_SIMPLE
|
||||
bool "Simple Reset Controller Driver" if COMPILE_TEST
|
||||
default ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED || ARCH_BITMAIN || ARC
|
||||
default ARCH_AGILEX || ARCH_ASPEED || ARCH_BITMAIN || ARCH_REALTEK || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARC
|
||||
help
|
||||
This enables a simple reset controller driver for reset lines that
|
||||
that can be asserted and deasserted by toggling bits in a contiguous,
|
||||
|
@ -138,10 +138,11 @@ config RESET_SIMPLE
|
|||
Currently this driver supports:
|
||||
- Altera SoCFPGAs
|
||||
- ASPEED BMC SoCs
|
||||
- Bitmain BM1880 SoC
|
||||
- Realtek SoCs
|
||||
- RCC reset controller in STM32 MCUs
|
||||
- Allwinner SoCs
|
||||
- ZTE's zx2967 family
|
||||
- Bitmain BM1880 SoC
|
||||
|
||||
config RESET_STM32MP157
|
||||
bool "STM32MP157 Reset Driver" if COMPILE_TEST
|
||||
|
|
|
@ -77,8 +77,10 @@ static const char *rcdev_name(struct reset_controller_dev *rcdev)
|
|||
* @rcdev: a pointer to the reset controller device
|
||||
* @reset_spec: reset line specifier as found in the device tree
|
||||
*
|
||||
* This simple translation function should be used for reset controllers
|
||||
* with 1:1 mapping, where reset lines can be indexed by number without gaps.
|
||||
* This static translation function is used by default if of_xlate in
|
||||
* :c:type:`reset_controller_dev` is not set. It is useful for all reset
|
||||
* controllers with 1:1 mapping, where reset lines can be indexed by number
|
||||
* without gaps.
|
||||
*/
|
||||
static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
|
||||
const struct of_phandle_args *reset_spec)
|
||||
|
@ -333,7 +335,6 @@ EXPORT_SYMBOL_GPL(reset_control_reset);
|
|||
* internal state to be reset, but must be prepared for this to happen.
|
||||
* Consumers must not use reset_control_reset on shared reset lines when
|
||||
* reset_control_(de)assert has been used.
|
||||
* return 0.
|
||||
*
|
||||
* If rstc is NULL it is an optional reset and the function will just
|
||||
* return 0.
|
||||
|
@ -392,7 +393,6 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
|
|||
* After calling this function, the reset is guaranteed to be deasserted.
|
||||
* Consumers must not use reset_control_reset on shared reset lines when
|
||||
* reset_control_(de)assert has been used.
|
||||
* return 0.
|
||||
*
|
||||
* If rstc is NULL it is an optional reset and the function will just
|
||||
* return 0.
|
||||
|
|
|
@ -56,7 +56,7 @@ static int hi3660_reset_dev(struct reset_controller_dev *rcdev,
|
|||
return hi3660_reset_deassert(rcdev, idx);
|
||||
}
|
||||
|
||||
static struct reset_control_ops hi3660_reset_ops = {
|
||||
static const struct reset_control_ops hi3660_reset_ops = {
|
||||
.reset = hi3660_reset_dev,
|
||||
.assert = hi3660_reset_assert,
|
||||
.deassert = hi3660_reset_deassert,
|
||||
|
|
|
@ -19,6 +19,11 @@ struct meson_audio_arb_data {
|
|||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct meson_audio_arb_match_data {
|
||||
const unsigned int *reset_bits;
|
||||
unsigned int reset_num;
|
||||
};
|
||||
|
||||
#define ARB_GENERAL_BIT 31
|
||||
|
||||
static const unsigned int axg_audio_arb_reset_bits[] = {
|
||||
|
@ -30,6 +35,27 @@ static const unsigned int axg_audio_arb_reset_bits[] = {
|
|||
[AXG_ARB_FRDDR_C] = 6,
|
||||
};
|
||||
|
||||
static const struct meson_audio_arb_match_data axg_audio_arb_match = {
|
||||
.reset_bits = axg_audio_arb_reset_bits,
|
||||
.reset_num = ARRAY_SIZE(axg_audio_arb_reset_bits),
|
||||
};
|
||||
|
||||
static const unsigned int sm1_audio_arb_reset_bits[] = {
|
||||
[AXG_ARB_TODDR_A] = 0,
|
||||
[AXG_ARB_TODDR_B] = 1,
|
||||
[AXG_ARB_TODDR_C] = 2,
|
||||
[AXG_ARB_FRDDR_A] = 4,
|
||||
[AXG_ARB_FRDDR_B] = 5,
|
||||
[AXG_ARB_FRDDR_C] = 6,
|
||||
[AXG_ARB_TODDR_D] = 3,
|
||||
[AXG_ARB_FRDDR_D] = 7,
|
||||
};
|
||||
|
||||
static const struct meson_audio_arb_match_data sm1_audio_arb_match = {
|
||||
.reset_bits = sm1_audio_arb_reset_bits,
|
||||
.reset_num = ARRAY_SIZE(sm1_audio_arb_reset_bits),
|
||||
};
|
||||
|
||||
static int meson_audio_arb_update(struct reset_controller_dev *rcdev,
|
||||
unsigned long id, bool assert)
|
||||
{
|
||||
|
@ -82,7 +108,13 @@ static const struct reset_control_ops meson_audio_arb_rstc_ops = {
|
|||
};
|
||||
|
||||
static const struct of_device_id meson_audio_arb_of_match[] = {
|
||||
{ .compatible = "amlogic,meson-axg-audio-arb", },
|
||||
{
|
||||
.compatible = "amlogic,meson-axg-audio-arb",
|
||||
.data = &axg_audio_arb_match,
|
||||
}, {
|
||||
.compatible = "amlogic,meson-sm1-audio-arb",
|
||||
.data = &sm1_audio_arb_match,
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_audio_arb_of_match);
|
||||
|
@ -104,10 +136,15 @@ static int meson_audio_arb_remove(struct platform_device *pdev)
|
|||
static int meson_audio_arb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct meson_audio_arb_match_data *data;
|
||||
struct meson_audio_arb_data *arb;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
data = of_device_get_match_data(dev);
|
||||
if (!data)
|
||||
return -EINVAL;
|
||||
|
||||
arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL);
|
||||
if (!arb)
|
||||
return -ENOMEM;
|
||||
|
@ -126,8 +163,8 @@ static int meson_audio_arb_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(arb->regs);
|
||||
|
||||
spin_lock_init(&arb->lock);
|
||||
arb->reset_bits = axg_audio_arb_reset_bits;
|
||||
arb->rstc.nr_resets = ARRAY_SIZE(axg_audio_arb_reset_bits);
|
||||
arb->reset_bits = data->reset_bits;
|
||||
arb->rstc.nr_resets = data->reset_num;
|
||||
arb->rstc.ops = &meson_audio_arb_rstc_ops;
|
||||
arb->rstc.of_node = dev->of_node;
|
||||
arb->rstc.owner = THIS_MODULE;
|
||||
|
|
|
@ -15,12 +15,16 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#define REG_COUNT 8
|
||||
#define BITS_PER_REG 32
|
||||
#define LEVEL_OFFSET 0x7c
|
||||
|
||||
struct meson_reset_param {
|
||||
int reg_count;
|
||||
int level_offset;
|
||||
};
|
||||
|
||||
struct meson_reset {
|
||||
void __iomem *reg_base;
|
||||
const struct meson_reset_param *param;
|
||||
struct reset_controller_dev rcdev;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
@ -46,10 +50,12 @@ static int meson_reset_level(struct reset_controller_dev *rcdev,
|
|||
container_of(rcdev, struct meson_reset, rcdev);
|
||||
unsigned int bank = id / BITS_PER_REG;
|
||||
unsigned int offset = id % BITS_PER_REG;
|
||||
void __iomem *reg_addr = data->reg_base + LEVEL_OFFSET + (bank << 2);
|
||||
void __iomem *reg_addr;
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
reg_addr = data->reg_base + data->param->level_offset + (bank << 2);
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
reg = readl(reg_addr);
|
||||
|
@ -81,10 +87,21 @@ static const struct reset_control_ops meson_reset_ops = {
|
|||
.deassert = meson_reset_deassert,
|
||||
};
|
||||
|
||||
static const struct meson_reset_param meson8b_param = {
|
||||
.reg_count = 8,
|
||||
.level_offset = 0x7c,
|
||||
};
|
||||
|
||||
static const struct meson_reset_param meson_a1_param = {
|
||||
.reg_count = 3,
|
||||
.level_offset = 0x40,
|
||||
};
|
||||
|
||||
static const struct of_device_id meson_reset_dt_ids[] = {
|
||||
{ .compatible = "amlogic,meson8b-reset" },
|
||||
{ .compatible = "amlogic,meson-gxbb-reset" },
|
||||
{ .compatible = "amlogic,meson-axg-reset" },
|
||||
{ .compatible = "amlogic,meson8b-reset", .data = &meson8b_param},
|
||||
{ .compatible = "amlogic,meson-gxbb-reset", .data = &meson8b_param},
|
||||
{ .compatible = "amlogic,meson-axg-reset", .data = &meson8b_param},
|
||||
{ .compatible = "amlogic,meson-a1-reset", .data = &meson_a1_param},
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
|
@ -102,12 +119,16 @@ static int meson_reset_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(data->reg_base))
|
||||
return PTR_ERR(data->reg_base);
|
||||
|
||||
data->param = of_device_get_match_data(&pdev->dev);
|
||||
if (!data->param)
|
||||
return -ENODEV;
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
spin_lock_init(&data->lock);
|
||||
|
||||
data->rcdev.owner = THIS_MODULE;
|
||||
data->rcdev.nr_resets = REG_COUNT * BITS_PER_REG;
|
||||
data->rcdev.nr_resets = data->param->reg_count * BITS_PER_REG;
|
||||
data->rcdev.ops = &meson_reset_ops;
|
||||
data->rcdev.of_node = pdev->dev.of_node;
|
||||
|
||||
|
|
|
@ -140,6 +140,10 @@ static const struct of_device_id uniphier_glue_reset_match[] = {
|
|||
.compatible = "socionext,uniphier-pro4-usb3-reset",
|
||||
.data = &uniphier_pro4_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-pro5-usb3-reset",
|
||||
.data = &uniphier_pro4_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-pxs2-usb3-reset",
|
||||
.data = &uniphier_pxs2_data,
|
||||
|
|
|
@ -64,7 +64,7 @@ static int zynqmp_reset_reset(struct reset_controller_dev *rcdev,
|
|||
PM_RESET_ACTION_PULSE);
|
||||
}
|
||||
|
||||
static struct reset_control_ops zynqmp_reset_ops = {
|
||||
static const struct reset_control_ops zynqmp_reset_ops = {
|
||||
.reset = zynqmp_reset_reset,
|
||||
.assert = zynqmp_reset_assert,
|
||||
.deassert = zynqmp_reset_deassert,
|
||||
|
|
|
@ -40,6 +40,7 @@ static const struct meson_gx_soc_id {
|
|||
{ "G12A", 0x28 },
|
||||
{ "G12B", 0x29 },
|
||||
{ "SM1", 0x2b },
|
||||
{ "A1", 0x2c },
|
||||
};
|
||||
|
||||
static const struct meson_gx_package_id {
|
||||
|
@ -68,6 +69,8 @@ static const struct meson_gx_package_id {
|
|||
{ "S922X", 0x29, 0x40, 0xf0 },
|
||||
{ "A311D", 0x29, 0x10, 0xf0 },
|
||||
{ "S905X3", 0x2b, 0x5, 0xf },
|
||||
{ "S905D3", 0x2b, 0xb0, 0xf0 },
|
||||
{ "A113L", 0x2c, 0x0, 0xf8 },
|
||||
};
|
||||
|
||||
static inline unsigned int socinfo_to_major(u32 socinfo)
|
||||
|
|
|
@ -5,3 +5,14 @@ config AT91_SOC_ID
|
|||
default ARCH_AT91
|
||||
help
|
||||
Include support for the SoC bus on the Atmel ARM SoCs.
|
||||
|
||||
config AT91_SOC_SFR
|
||||
tristate "Special Function Registers support"
|
||||
depends on ARCH_AT91 || COMPILE_TEST
|
||||
help
|
||||
This is a driver for the Special Function Registers available on
|
||||
Atmel SAMA5Dx SoCs, providing access to specific aspects of the
|
||||
integrated memory, bridge implementations, processor etc.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called sfr.
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_AT91_SOC_ID) += soc.o
|
||||
obj-$(CONFIG_AT91_SOC_SFR) += sfr.o
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* sfr.c - driver for special function registers
|
||||
*
|
||||
* Copyright (C) 2019 Bootlin.
|
||||
*
|
||||
*/
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-provider.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define SFR_SN0 0x4c
|
||||
#define SFR_SN_SIZE 8
|
||||
|
||||
struct atmel_sfr_priv {
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static int atmel_sfr_read(void *context, unsigned int offset,
|
||||
void *buf, size_t bytes)
|
||||
{
|
||||
struct atmel_sfr_priv *priv = context;
|
||||
|
||||
return regmap_bulk_read(priv->regmap, SFR_SN0 + offset,
|
||||
buf, bytes / 4);
|
||||
}
|
||||
|
||||
static struct nvmem_config atmel_sfr_nvmem_config = {
|
||||
.name = "atmel-sfr",
|
||||
.read_only = true,
|
||||
.word_size = 4,
|
||||
.stride = 4,
|
||||
.size = SFR_SN_SIZE,
|
||||
.reg_read = atmel_sfr_read,
|
||||
};
|
||||
|
||||
static int atmel_sfr_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct nvmem_device *nvmem;
|
||||
struct atmel_sfr_priv *priv;
|
||||
u8 sn[SFR_SN_SIZE];
|
||||
int ret;
|
||||
|
||||
priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->regmap = syscon_node_to_regmap(np);
|
||||
if (IS_ERR(priv->regmap)) {
|
||||
dev_err(dev, "cannot get parent's regmap\n");
|
||||
return PTR_ERR(priv->regmap);
|
||||
}
|
||||
|
||||
atmel_sfr_nvmem_config.dev = dev;
|
||||
atmel_sfr_nvmem_config.priv = priv;
|
||||
|
||||
nvmem = devm_nvmem_register(dev, &atmel_sfr_nvmem_config);
|
||||
if (IS_ERR(nvmem)) {
|
||||
dev_err(dev, "error registering nvmem config\n");
|
||||
return PTR_ERR(nvmem);
|
||||
}
|
||||
|
||||
ret = atmel_sfr_read(priv, 0, sn, SFR_SN_SIZE);
|
||||
if (ret == 0)
|
||||
add_device_randomness(sn, SFR_SN_SIZE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id atmel_sfr_dt_ids[] = {
|
||||
{
|
||||
.compatible = "atmel,sama5d2-sfr",
|
||||
}, {
|
||||
.compatible = "atmel,sama5d4-sfr",
|
||||
}, {
|
||||
/* sentinel */
|
||||
},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, atmel_sfr_dt_ids);
|
||||
|
||||
static struct platform_driver atmel_sfr_driver = {
|
||||
.probe = atmel_sfr_probe,
|
||||
.driver = {
|
||||
.name = "atmel-sfr",
|
||||
.of_match_table = atmel_sfr_dt_ids,
|
||||
},
|
||||
};
|
||||
module_platform_driver(atmel_sfr_driver);
|
||||
|
||||
MODULE_AUTHOR("Kamel Bouhara <kamel.bouhara@bootlin.com>");
|
||||
MODULE_DESCRIPTION("Atmel SFR SN driver for SAMA5D2/4 SoC family");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -40,4 +40,14 @@ config DPAA2_CONSOLE
|
|||
/dev/dpaa2_mc_console and /dev/dpaa2_aiop_console,
|
||||
which can be used to dump the Management Complex and AIOP
|
||||
firmware logs.
|
||||
|
||||
config FSL_RCPM
|
||||
bool "Freescale RCPM support"
|
||||
depends on PM_SLEEP && (ARM || ARM64)
|
||||
help
|
||||
The NXP QorIQ Processors based on ARM Core have RCPM module
|
||||
(Run Control and Power Management), which performs all device-level
|
||||
tasks associated with power management, such as wakeup source control.
|
||||
Note that currently this driver will not support PowerPC based
|
||||
QorIQ processor.
|
||||
endmenu
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
obj-$(CONFIG_FSL_DPAA) += qbman/
|
||||
obj-$(CONFIG_QUICC_ENGINE) += qe/
|
||||
obj-$(CONFIG_CPM) += qe/
|
||||
obj-$(CONFIG_FSL_RCPM) += rcpm.o
|
||||
obj-$(CONFIG_FSL_GUTS) += guts.o
|
||||
obj-$(CONFIG_FSL_MC_DPIO) += dpio/
|
||||
obj-$(CONFIG_DPAA2_CONSOLE) += dpaa2-console.o
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// rcpm.c - Freescale QorIQ RCPM driver
|
||||
//
|
||||
// Copyright 2019 NXP
|
||||
//
|
||||
// Author: Ran Wang <ran.wang_1@nxp.com>
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#define RCPM_WAKEUP_CELL_MAX_SIZE 7
|
||||
|
||||
struct rcpm {
|
||||
unsigned int wakeup_cells;
|
||||
void __iomem *ippdexpcr_base;
|
||||
bool little_endian;
|
||||
};
|
||||
|
||||
/**
|
||||
* rcpm_pm_prepare - performs device-level tasks associated with power
|
||||
* management, such as programming related to the wakeup source control.
|
||||
* @dev: Device to handle.
|
||||
*
|
||||
*/
|
||||
static int rcpm_pm_prepare(struct device *dev)
|
||||
{
|
||||
int i, ret, idx;
|
||||
void __iomem *base;
|
||||
struct wakeup_source *ws;
|
||||
struct rcpm *rcpm;
|
||||
struct device_node *np = dev->of_node;
|
||||
u32 value[RCPM_WAKEUP_CELL_MAX_SIZE + 1];
|
||||
u32 setting[RCPM_WAKEUP_CELL_MAX_SIZE] = {0};
|
||||
|
||||
rcpm = dev_get_drvdata(dev);
|
||||
if (!rcpm)
|
||||
return -EINVAL;
|
||||
|
||||
base = rcpm->ippdexpcr_base;
|
||||
idx = wakeup_sources_read_lock();
|
||||
|
||||
/* Begin with first registered wakeup source */
|
||||
for_each_wakeup_source(ws) {
|
||||
|
||||
/* skip object which is not attached to device */
|
||||
if (!ws->dev || !ws->dev->parent)
|
||||
continue;
|
||||
|
||||
ret = device_property_read_u32_array(ws->dev->parent,
|
||||
"fsl,rcpm-wakeup", value,
|
||||
rcpm->wakeup_cells + 1);
|
||||
|
||||
/* Wakeup source should refer to current rcpm device */
|
||||
if (ret || (np->phandle != value[0]))
|
||||
continue;
|
||||
|
||||
/* Property "#fsl,rcpm-wakeup-cells" of rcpm node defines the
|
||||
* number of IPPDEXPCR register cells, and "fsl,rcpm-wakeup"
|
||||
* of wakeup source IP contains an integer array: <phandle to
|
||||
* RCPM node, IPPDEXPCR0 setting, IPPDEXPCR1 setting,
|
||||
* IPPDEXPCR2 setting, etc>.
|
||||
*
|
||||
* So we will go thought them to collect setting data.
|
||||
*/
|
||||
for (i = 0; i < rcpm->wakeup_cells; i++)
|
||||
setting[i] |= value[i + 1];
|
||||
}
|
||||
|
||||
wakeup_sources_read_unlock(idx);
|
||||
|
||||
/* Program all IPPDEXPCRn once */
|
||||
for (i = 0; i < rcpm->wakeup_cells; i++) {
|
||||
u32 tmp = setting[i];
|
||||
void __iomem *address = base + i * 4;
|
||||
|
||||
if (!tmp)
|
||||
continue;
|
||||
|
||||
/* We can only OR related bits */
|
||||
if (rcpm->little_endian) {
|
||||
tmp |= ioread32(address);
|
||||
iowrite32(tmp, address);
|
||||
} else {
|
||||
tmp |= ioread32be(address);
|
||||
iowrite32be(tmp, address);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops rcpm_pm_ops = {
|
||||
.prepare = rcpm_pm_prepare,
|
||||
};
|
||||
|
||||
static int rcpm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *r;
|
||||
struct rcpm *rcpm;
|
||||
int ret;
|
||||
|
||||
rcpm = devm_kzalloc(dev, sizeof(*rcpm), GFP_KERNEL);
|
||||
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);
|
||||
if (IS_ERR(rcpm->ippdexpcr_base)) {
|
||||
ret = PTR_ERR(rcpm->ippdexpcr_base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rcpm->little_endian = device_property_read_bool(
|
||||
&pdev->dev, "little-endian");
|
||||
|
||||
ret = device_property_read_u32(&pdev->dev,
|
||||
"#fsl,rcpm-wakeup-cells", &rcpm->wakeup_cells);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, rcpm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id rcpm_of_match[] = {
|
||||
{ .compatible = "fsl,qoriq-rcpm-2.1+", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rcpm_of_match);
|
||||
|
||||
static struct platform_driver rcpm_driver = {
|
||||
.driver = {
|
||||
.name = "rcpm",
|
||||
.of_match_table = rcpm_of_match,
|
||||
.pm = &rcpm_pm_ops,
|
||||
},
|
||||
.probe = rcpm_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(rcpm_driver);
|
|
@ -33,12 +33,10 @@ struct imx_sc_msg_misc_get_soc_uid {
|
|||
u32 uid_high;
|
||||
} __packed;
|
||||
|
||||
static ssize_t soc_uid_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static int imx_scu_soc_uid(u64 *soc_uid)
|
||||
{
|
||||
struct imx_sc_msg_misc_get_soc_uid msg;
|
||||
struct imx_sc_rpc_msg *hdr = &msg.hdr;
|
||||
u64 soc_uid;
|
||||
int ret;
|
||||
|
||||
hdr->ver = IMX_SC_RPC_VERSION;
|
||||
|
@ -52,15 +50,13 @@ static ssize_t soc_uid_show(struct device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
soc_uid = msg.uid_high;
|
||||
soc_uid <<= 32;
|
||||
soc_uid |= msg.uid_low;
|
||||
*soc_uid = msg.uid_high;
|
||||
*soc_uid <<= 32;
|
||||
*soc_uid |= msg.uid_low;
|
||||
|
||||
return sprintf(buf, "%016llX\n", soc_uid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(soc_uid);
|
||||
|
||||
static int imx_scu_soc_id(void)
|
||||
{
|
||||
struct imx_sc_msg_misc_get_soc_id msg;
|
||||
|
@ -89,6 +85,7 @@ static int imx_scu_soc_probe(struct platform_device *pdev)
|
|||
struct soc_device_attribute *soc_dev_attr;
|
||||
struct soc_device *soc_dev;
|
||||
int id, ret;
|
||||
u64 uid = 0;
|
||||
u32 val;
|
||||
|
||||
ret = imx_scu_get_handle(&soc_ipc_handle);
|
||||
|
@ -112,6 +109,10 @@ static int imx_scu_soc_probe(struct platform_device *pdev)
|
|||
if (id < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = imx_scu_soc_uid(&uid);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* format soc_id value passed from SCU firmware */
|
||||
val = id & 0x1f;
|
||||
soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "0x%x", val);
|
||||
|
@ -130,19 +131,22 @@ static int imx_scu_soc_probe(struct platform_device *pdev)
|
|||
goto free_soc_id;
|
||||
}
|
||||
|
||||
soc_dev = soc_device_register(soc_dev_attr);
|
||||
if (IS_ERR(soc_dev)) {
|
||||
ret = PTR_ERR(soc_dev);
|
||||
soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", uid);
|
||||
if (!soc_dev_attr->serial_number) {
|
||||
ret = -ENOMEM;
|
||||
goto free_revision;
|
||||
}
|
||||
|
||||
ret = device_create_file(soc_device_to_device(soc_dev),
|
||||
&dev_attr_soc_uid);
|
||||
if (ret)
|
||||
goto free_revision;
|
||||
soc_dev = soc_device_register(soc_dev_attr);
|
||||
if (IS_ERR(soc_dev)) {
|
||||
ret = PTR_ERR(soc_dev);
|
||||
goto free_serial_number;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_serial_number:
|
||||
kfree(soc_dev_attr->serial_number);
|
||||
free_revision:
|
||||
kfree(soc_dev_attr->revision);
|
||||
free_soc_id:
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define REV_B1 0x21
|
||||
|
@ -16,6 +17,8 @@
|
|||
#define IMX8MQ_SW_INFO_B1 0x40
|
||||
#define IMX8MQ_SW_MAGIC_B1 0xff0055aa
|
||||
|
||||
#define IMX_SIP_GET_SOC_INFO 0xc2000006
|
||||
|
||||
#define OCOTP_UID_LOW 0x410
|
||||
#define OCOTP_UID_HIGH 0x420
|
||||
|
||||
|
@ -29,13 +32,21 @@ struct imx8_soc_data {
|
|||
|
||||
static u64 soc_uid;
|
||||
|
||||
static ssize_t soc_uid_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
#ifdef CONFIG_HAVE_ARM_SMCCC
|
||||
static u32 imx8mq_soc_revision_from_atf(void)
|
||||
{
|
||||
return sprintf(buf, "%016llX\n", soc_uid);
|
||||
}
|
||||
struct arm_smccc_res res;
|
||||
|
||||
static DEVICE_ATTR_RO(soc_uid);
|
||||
arm_smccc_smc(IMX_SIP_GET_SOC_INFO, 0, 0, 0, 0, 0, 0, 0, &res);
|
||||
|
||||
if (res.a0 == SMCCC_RET_NOT_SUPPORTED)
|
||||
return 0;
|
||||
else
|
||||
return res.a0 & 0xff;
|
||||
}
|
||||
#else
|
||||
static inline u32 imx8mq_soc_revision_from_atf(void) { return 0; };
|
||||
#endif
|
||||
|
||||
static u32 __init imx8mq_soc_revision(void)
|
||||
{
|
||||
|
@ -51,9 +62,16 @@ static u32 __init imx8mq_soc_revision(void)
|
|||
ocotp_base = of_iomap(np, 0);
|
||||
WARN_ON(!ocotp_base);
|
||||
|
||||
magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1);
|
||||
if (magic == IMX8MQ_SW_MAGIC_B1)
|
||||
rev = REV_B1;
|
||||
/*
|
||||
* SOC revision on older imx8mq is not available in fuses so query
|
||||
* the value from ATF instead.
|
||||
*/
|
||||
rev = imx8mq_soc_revision_from_atf();
|
||||
if (!rev) {
|
||||
magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1);
|
||||
if (magic == IMX8MQ_SW_MAGIC_B1)
|
||||
rev = REV_B1;
|
||||
}
|
||||
|
||||
soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH);
|
||||
soc_uid <<= 32;
|
||||
|
@ -174,22 +192,25 @@ static int __init imx8_soc_init(void)
|
|||
goto free_soc;
|
||||
}
|
||||
|
||||
soc_dev = soc_device_register(soc_dev_attr);
|
||||
if (IS_ERR(soc_dev)) {
|
||||
ret = PTR_ERR(soc_dev);
|
||||
soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid);
|
||||
if (!soc_dev_attr->serial_number) {
|
||||
ret = -ENOMEM;
|
||||
goto free_rev;
|
||||
}
|
||||
|
||||
ret = device_create_file(soc_device_to_device(soc_dev),
|
||||
&dev_attr_soc_uid);
|
||||
if (ret)
|
||||
goto free_rev;
|
||||
soc_dev = soc_device_register(soc_dev_attr);
|
||||
if (IS_ERR(soc_dev)) {
|
||||
ret = PTR_ERR(soc_dev);
|
||||
goto free_serial_number;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
|
||||
platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
free_serial_number:
|
||||
kfree(soc_dev_attr->serial_number);
|
||||
free_rev:
|
||||
if (strcmp(soc_dev_attr->revision, "unknown"))
|
||||
kfree(soc_dev_attr->revision);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <dt-bindings/power/mt8173-power.h>
|
||||
|
||||
#define MTK_POLL_DELAY_US 10
|
||||
#define MTK_POLL_TIMEOUT (jiffies_to_usecs(HZ))
|
||||
#define MTK_POLL_TIMEOUT USEC_PER_SEC
|
||||
|
||||
#define MTK_SCPD_ACTIVE_WAKEUP BIT(0)
|
||||
#define MTK_SCPD_FWAIT_SRAM BIT(1)
|
||||
|
@ -108,6 +108,17 @@ static const char * const clk_names[] = {
|
|||
|
||||
#define MAX_CLKS 3
|
||||
|
||||
/**
|
||||
* struct scp_domain_data - scp domain data for power on/off flow
|
||||
* @name: The domain name.
|
||||
* @sta_mask: The mask for power on/off status bit.
|
||||
* @ctl_offs: The offset for main power control register.
|
||||
* @sram_pdn_bits: The mask for sram power control bits.
|
||||
* @sram_pdn_ack_bits: The mask for sram power control acked bits.
|
||||
* @bus_prot_mask: The mask for single step bus protection.
|
||||
* @clk_id: The basic clocks required by this power domain.
|
||||
* @caps: The flag for active wake-up action.
|
||||
*/
|
||||
struct scp_domain_data {
|
||||
const char *name;
|
||||
u32 sta_mask;
|
||||
|
@ -180,32 +191,132 @@ static int scpsys_domain_is_on(struct scp_domain *scpd)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int scpsys_regulator_enable(struct scp_domain *scpd)
|
||||
{
|
||||
if (!scpd->supply)
|
||||
return 0;
|
||||
|
||||
return regulator_enable(scpd->supply);
|
||||
}
|
||||
|
||||
static int scpsys_regulator_disable(struct scp_domain *scpd)
|
||||
{
|
||||
if (!scpd->supply)
|
||||
return 0;
|
||||
|
||||
return regulator_disable(scpd->supply);
|
||||
}
|
||||
|
||||
static void scpsys_clk_disable(struct clk *clk[], int max_num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = max_num - 1; i >= 0; i--)
|
||||
clk_disable_unprepare(clk[i]);
|
||||
}
|
||||
|
||||
static int scpsys_clk_enable(struct clk *clk[], int max_num)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < max_num && clk[i]; i++) {
|
||||
ret = clk_prepare_enable(clk[i]);
|
||||
if (ret) {
|
||||
scpsys_clk_disable(clk, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scpsys_sram_enable(struct scp_domain *scpd, void __iomem *ctl_addr)
|
||||
{
|
||||
u32 val;
|
||||
u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
|
||||
int tmp;
|
||||
|
||||
val = readl(ctl_addr);
|
||||
val &= ~scpd->data->sram_pdn_bits;
|
||||
writel(val, ctl_addr);
|
||||
|
||||
/* Either wait until SRAM_PDN_ACK all 0 or have a force wait */
|
||||
if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) {
|
||||
/*
|
||||
* Currently, MTK_SCPD_FWAIT_SRAM is necessary only for
|
||||
* MT7622_POWER_DOMAIN_WB and thus just a trivial setup
|
||||
* is applied here.
|
||||
*/
|
||||
usleep_range(12000, 12100);
|
||||
} else {
|
||||
/* Either wait until SRAM_PDN_ACK all 1 or 0 */
|
||||
int ret = readl_poll_timeout(ctl_addr, tmp,
|
||||
(tmp & pdn_ack) == 0,
|
||||
MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scpsys_sram_disable(struct scp_domain *scpd, void __iomem *ctl_addr)
|
||||
{
|
||||
u32 val;
|
||||
u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
|
||||
int tmp;
|
||||
|
||||
val = readl(ctl_addr);
|
||||
val |= scpd->data->sram_pdn_bits;
|
||||
writel(val, ctl_addr);
|
||||
|
||||
/* Either wait until SRAM_PDN_ACK all 1 or 0 */
|
||||
return readl_poll_timeout(ctl_addr, tmp,
|
||||
(tmp & pdn_ack) == pdn_ack,
|
||||
MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
|
||||
}
|
||||
|
||||
static int scpsys_bus_protect_enable(struct scp_domain *scpd)
|
||||
{
|
||||
struct scp *scp = scpd->scp;
|
||||
|
||||
if (!scpd->data->bus_prot_mask)
|
||||
return 0;
|
||||
|
||||
return mtk_infracfg_set_bus_protection(scp->infracfg,
|
||||
scpd->data->bus_prot_mask,
|
||||
scp->bus_prot_reg_update);
|
||||
}
|
||||
|
||||
static int scpsys_bus_protect_disable(struct scp_domain *scpd)
|
||||
{
|
||||
struct scp *scp = scpd->scp;
|
||||
|
||||
if (!scpd->data->bus_prot_mask)
|
||||
return 0;
|
||||
|
||||
return mtk_infracfg_clear_bus_protection(scp->infracfg,
|
||||
scpd->data->bus_prot_mask,
|
||||
scp->bus_prot_reg_update);
|
||||
}
|
||||
|
||||
static int scpsys_power_on(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
|
||||
struct scp *scp = scpd->scp;
|
||||
void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
|
||||
u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
|
||||
u32 val;
|
||||
int ret, tmp;
|
||||
int i;
|
||||
|
||||
if (scpd->supply) {
|
||||
ret = regulator_enable(scpd->supply);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = scpsys_regulator_enable(scpd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) {
|
||||
ret = clk_prepare_enable(scpd->clk[i]);
|
||||
if (ret) {
|
||||
for (--i; i >= 0; i--)
|
||||
clk_disable_unprepare(scpd->clk[i]);
|
||||
|
||||
goto err_clk;
|
||||
}
|
||||
}
|
||||
ret = scpsys_clk_enable(scpd->clk, MAX_CLKS);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
||||
/* subsys power on */
|
||||
val = readl(ctl_addr);
|
||||
val |= PWR_ON_BIT;
|
||||
writel(val, ctl_addr);
|
||||
|
@ -227,43 +338,20 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
|
|||
val |= PWR_RST_B_BIT;
|
||||
writel(val, ctl_addr);
|
||||
|
||||
val &= ~scpd->data->sram_pdn_bits;
|
||||
writel(val, ctl_addr);
|
||||
ret = scpsys_sram_enable(scpd, ctl_addr);
|
||||
if (ret < 0)
|
||||
goto err_pwr_ack;
|
||||
|
||||
/* Either wait until SRAM_PDN_ACK all 0 or have a force wait */
|
||||
if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) {
|
||||
/*
|
||||
* Currently, MTK_SCPD_FWAIT_SRAM is necessary only for
|
||||
* MT7622_POWER_DOMAIN_WB and thus just a trivial setup is
|
||||
* applied here.
|
||||
*/
|
||||
usleep_range(12000, 12100);
|
||||
|
||||
} else {
|
||||
ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == 0,
|
||||
MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
|
||||
if (ret < 0)
|
||||
goto err_pwr_ack;
|
||||
}
|
||||
|
||||
if (scpd->data->bus_prot_mask) {
|
||||
ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
|
||||
scpd->data->bus_prot_mask,
|
||||
scp->bus_prot_reg_update);
|
||||
if (ret)
|
||||
goto err_pwr_ack;
|
||||
}
|
||||
ret = scpsys_bus_protect_disable(scpd);
|
||||
if (ret < 0)
|
||||
goto err_pwr_ack;
|
||||
|
||||
return 0;
|
||||
|
||||
err_pwr_ack:
|
||||
for (i = MAX_CLKS - 1; i >= 0; i--) {
|
||||
if (scpd->clk[i])
|
||||
clk_disable_unprepare(scpd->clk[i]);
|
||||
}
|
||||
scpsys_clk_disable(scpd->clk, MAX_CLKS);
|
||||
err_clk:
|
||||
if (scpd->supply)
|
||||
regulator_disable(scpd->supply);
|
||||
scpsys_regulator_disable(scpd);
|
||||
|
||||
dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name);
|
||||
|
||||
|
@ -275,29 +363,19 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
|
|||
struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
|
||||
struct scp *scp = scpd->scp;
|
||||
void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
|
||||
u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
|
||||
u32 val;
|
||||
int ret, tmp;
|
||||
int i;
|
||||
|
||||
if (scpd->data->bus_prot_mask) {
|
||||
ret = mtk_infracfg_set_bus_protection(scp->infracfg,
|
||||
scpd->data->bus_prot_mask,
|
||||
scp->bus_prot_reg_update);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
val = readl(ctl_addr);
|
||||
val |= scpd->data->sram_pdn_bits;
|
||||
writel(val, ctl_addr);
|
||||
|
||||
/* wait until SRAM_PDN_ACK all 1 */
|
||||
ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == pdn_ack,
|
||||
MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
|
||||
ret = scpsys_bus_protect_enable(scpd);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = scpsys_sram_disable(scpd, ctl_addr);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* subsys power off */
|
||||
val = readl(ctl_addr);
|
||||
val |= PWR_ISO_BIT;
|
||||
writel(val, ctl_addr);
|
||||
|
||||
|
@ -319,11 +397,11 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++)
|
||||
clk_disable_unprepare(scpd->clk[i]);
|
||||
scpsys_clk_disable(scpd->clk, MAX_CLKS);
|
||||
|
||||
if (scpd->supply)
|
||||
regulator_disable(scpd->supply);
|
||||
ret = scpsys_regulator_disable(scpd);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -58,17 +58,9 @@ config QCOM_LLCC
|
|||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
help
|
||||
Qualcomm Technologies, Inc. platform specific
|
||||
Last Level Cache Controller(LLCC) driver. This provides interfaces
|
||||
to clients that use the LLCC. Say yes here to enable LLCC slice
|
||||
driver.
|
||||
|
||||
config QCOM_SDM845_LLCC
|
||||
tristate "Qualcomm Technologies, Inc. SDM845 LLCC driver"
|
||||
depends on QCOM_LLCC
|
||||
help
|
||||
Say yes here to enable the LLCC driver for SDM845. This provides
|
||||
data required to configure LLCC so that clients can start using the
|
||||
LLCC slices.
|
||||
Last Level Cache Controller(LLCC) driver for platforms such as,
|
||||
SDM845. This provides interfaces to clients that use the LLCC.
|
||||
Say yes here to enable LLCC slice driver.
|
||||
|
||||
config QCOM_MDT_LOADER
|
||||
tristate
|
||||
|
|
|
@ -21,7 +21,6 @@ obj-$(CONFIG_QCOM_SMSM) += smsm.o
|
|||
obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o
|
||||
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
|
||||
obj-$(CONFIG_QCOM_APR) += apr.o
|
||||
obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o
|
||||
obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o
|
||||
obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
|
||||
obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
|
||||
obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/sizes.h>
|
||||
|
@ -46,15 +47,90 @@
|
|||
|
||||
#define BANK_OFFSET_STRIDE 0x80000
|
||||
|
||||
static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
|
||||
|
||||
static const struct regmap_config llcc_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.fast_io = true,
|
||||
/**
|
||||
* llcc_slice_config - Data associated with the llcc slice
|
||||
* @usecase_id: Unique id for the client's use case
|
||||
* @slice_id: llcc slice id for each client
|
||||
* @max_cap: The maximum capacity of the cache slice provided in KB
|
||||
* @priority: Priority of the client used to select victim line for replacement
|
||||
* @fixed_size: Boolean indicating if the slice has a fixed capacity
|
||||
* @bonus_ways: Bonus ways are additional ways to be used for any slice,
|
||||
* if client ends up using more than reserved cache ways. Bonus
|
||||
* ways are allocated only if they are not reserved for some
|
||||
* other client.
|
||||
* @res_ways: Reserved ways for the cache slice, the reserved ways cannot
|
||||
* be used by any other client than the one its assigned to.
|
||||
* @cache_mode: Each slice operates as a cache, this controls the mode of the
|
||||
* slice: normal or TCM(Tightly Coupled Memory)
|
||||
* @probe_target_ways: Determines what ways to probe for access hit. When
|
||||
* configured to 1 only bonus and reserved ways are probed.
|
||||
* When configured to 0 all ways in llcc are probed.
|
||||
* @dis_cap_alloc: Disable capacity based allocation for a client
|
||||
* @retain_on_pc: If this bit is set and client has maintained active vote
|
||||
* then the ways assigned to this client are not flushed on power
|
||||
* collapse.
|
||||
* @activate_on_init: Activate the slice immediately after it is programmed
|
||||
*/
|
||||
struct llcc_slice_config {
|
||||
u32 usecase_id;
|
||||
u32 slice_id;
|
||||
u32 max_cap;
|
||||
u32 priority;
|
||||
bool fixed_size;
|
||||
u32 bonus_ways;
|
||||
u32 res_ways;
|
||||
u32 cache_mode;
|
||||
u32 probe_target_ways;
|
||||
bool dis_cap_alloc;
|
||||
bool retain_on_pc;
|
||||
bool activate_on_init;
|
||||
};
|
||||
|
||||
struct qcom_llcc_config {
|
||||
const struct llcc_slice_config *sct_data;
|
||||
int size;
|
||||
};
|
||||
|
||||
static const struct llcc_slice_config sc7180_data[] = {
|
||||
{ LLCC_CPUSS, 1, 256, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 1 },
|
||||
{ LLCC_MDM, 8, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 },
|
||||
{ LLCC_GPUHTW, 11, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 },
|
||||
{ LLCC_GPU, 12, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 },
|
||||
};
|
||||
|
||||
static const struct llcc_slice_config sdm845_data[] = {
|
||||
{ LLCC_CPUSS, 1, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 1 },
|
||||
{ LLCC_VIDSC0, 2, 512, 2, 1, 0x0, 0x0f0, 0, 0, 1, 1, 0 },
|
||||
{ LLCC_VIDSC1, 3, 512, 2, 1, 0x0, 0x0f0, 0, 0, 1, 1, 0 },
|
||||
{ LLCC_ROTATOR, 4, 563, 2, 1, 0x0, 0x00e, 2, 0, 1, 1, 0 },
|
||||
{ LLCC_VOICE, 5, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 },
|
||||
{ LLCC_AUDIO, 6, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 },
|
||||
{ LLCC_MDMHPGRW, 7, 1024, 2, 0, 0xfc, 0xf00, 0, 0, 1, 1, 0 },
|
||||
{ LLCC_MDM, 8, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 },
|
||||
{ LLCC_CMPT, 10, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 },
|
||||
{ LLCC_GPUHTW, 11, 512, 1, 1, 0xc, 0x0, 0, 0, 1, 1, 0 },
|
||||
{ LLCC_GPU, 12, 2304, 1, 0, 0xff0, 0x2, 0, 0, 1, 1, 0 },
|
||||
{ LLCC_MMUHWT, 13, 256, 2, 0, 0x0, 0x1, 0, 0, 1, 0, 1 },
|
||||
{ LLCC_CMPTDMA, 15, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 },
|
||||
{ LLCC_DISP, 16, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 },
|
||||
{ LLCC_VIDFW, 17, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 },
|
||||
{ LLCC_MDMHPFX, 20, 1024, 2, 1, 0x0, 0xf00, 0, 0, 1, 1, 0 },
|
||||
{ LLCC_MDMPNG, 21, 1024, 0, 1, 0x1e, 0x0, 0, 0, 1, 1, 0 },
|
||||
{ LLCC_AUDHW, 22, 1024, 1, 1, 0xffc, 0x2, 0, 0, 1, 1, 0 },
|
||||
};
|
||||
|
||||
static const struct qcom_llcc_config sc7180_cfg = {
|
||||
.sct_data = sc7180_data,
|
||||
.size = ARRAY_SIZE(sc7180_data),
|
||||
};
|
||||
|
||||
static const struct qcom_llcc_config sdm845_cfg = {
|
||||
.sct_data = sdm845_data,
|
||||
.size = ARRAY_SIZE(sdm845_data),
|
||||
};
|
||||
|
||||
static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
|
||||
|
||||
/**
|
||||
* llcc_slice_getd - get llcc slice descriptor
|
||||
* @uid: usecase_id for the client
|
||||
|
@ -301,19 +377,24 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int qcom_llcc_remove(struct platform_device *pdev)
|
||||
static int qcom_llcc_remove(struct platform_device *pdev)
|
||||
{
|
||||
/* Set the global pointer to a error code to avoid referencing it */
|
||||
drv_data = ERR_PTR(-ENODEV);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_llcc_remove);
|
||||
|
||||
static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev,
|
||||
const char *name)
|
||||
{
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
struct regmap_config llcc_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
|
||||
if (!res)
|
||||
|
@ -323,16 +404,19 @@ static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev,
|
|||
if (IS_ERR(base))
|
||||
return ERR_CAST(base);
|
||||
|
||||
llcc_regmap_config.name = name;
|
||||
return devm_regmap_init_mmio(&pdev->dev, base, &llcc_regmap_config);
|
||||
}
|
||||
|
||||
int qcom_llcc_probe(struct platform_device *pdev,
|
||||
const struct llcc_slice_config *llcc_cfg, u32 sz)
|
||||
static int qcom_llcc_probe(struct platform_device *pdev)
|
||||
{
|
||||
u32 num_banks;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret, i;
|
||||
struct platform_device *llcc_edac;
|
||||
const struct qcom_llcc_config *cfg;
|
||||
const struct llcc_slice_config *llcc_cfg;
|
||||
u32 sz;
|
||||
|
||||
drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
|
||||
if (!drv_data) {
|
||||
|
@ -362,6 +446,10 @@ int qcom_llcc_probe(struct platform_device *pdev,
|
|||
num_banks >>= LLCC_LB_CNT_SHIFT;
|
||||
drv_data->num_banks = num_banks;
|
||||
|
||||
cfg = of_device_get_match_data(&pdev->dev);
|
||||
llcc_cfg = cfg->sct_data;
|
||||
sz = cfg->size;
|
||||
|
||||
for (i = 0; i < sz; i++)
|
||||
if (llcc_cfg[i].slice_id > drv_data->max_slices)
|
||||
drv_data->max_slices = llcc_cfg[i].slice_id;
|
||||
|
@ -407,6 +495,22 @@ err:
|
|||
drv_data = ERR_PTR(-ENODEV);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_llcc_probe);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static const struct of_device_id qcom_llcc_of_match[] = {
|
||||
{ .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfg },
|
||||
{ .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfg },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver qcom_llcc_driver = {
|
||||
.driver = {
|
||||
.name = "qcom-llcc",
|
||||
.of_match_table = qcom_llcc_of_match,
|
||||
},
|
||||
.probe = qcom_llcc_probe,
|
||||
.remove = qcom_llcc_remove,
|
||||
};
|
||||
module_platform_driver(qcom_llcc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm Last Level Cache Controller");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -1,100 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/soc/qcom/llcc-qcom.h>
|
||||
|
||||
/*
|
||||
* SCT(System Cache Table) entry contains of the following members:
|
||||
* usecase_id: Unique id for the client's use case
|
||||
* slice_id: llcc slice id for each client
|
||||
* max_cap: The maximum capacity of the cache slice provided in KB
|
||||
* priority: Priority of the client used to select victim line for replacement
|
||||
* fixed_size: Boolean indicating if the slice has a fixed capacity
|
||||
* bonus_ways: Bonus ways are additional ways to be used for any slice,
|
||||
* if client ends up using more than reserved cache ways. Bonus
|
||||
* ways are allocated only if they are not reserved for some
|
||||
* other client.
|
||||
* res_ways: Reserved ways for the cache slice, the reserved ways cannot
|
||||
* be used by any other client than the one its assigned to.
|
||||
* cache_mode: Each slice operates as a cache, this controls the mode of the
|
||||
* slice: normal or TCM(Tightly Coupled Memory)
|
||||
* probe_target_ways: Determines what ways to probe for access hit. When
|
||||
* configured to 1 only bonus and reserved ways are probed.
|
||||
* When configured to 0 all ways in llcc are probed.
|
||||
* dis_cap_alloc: Disable capacity based allocation for a client
|
||||
* retain_on_pc: If this bit is set and client has maintained active vote
|
||||
* then the ways assigned to this client are not flushed on power
|
||||
* collapse.
|
||||
* activate_on_init: Activate the slice immediately after the SCT is programmed
|
||||
*/
|
||||
#define SCT_ENTRY(uid, sid, mc, p, fs, bway, rway, cmod, ptw, dca, rp, a) \
|
||||
{ \
|
||||
.usecase_id = uid, \
|
||||
.slice_id = sid, \
|
||||
.max_cap = mc, \
|
||||
.priority = p, \
|
||||
.fixed_size = fs, \
|
||||
.bonus_ways = bway, \
|
||||
.res_ways = rway, \
|
||||
.cache_mode = cmod, \
|
||||
.probe_target_ways = ptw, \
|
||||
.dis_cap_alloc = dca, \
|
||||
.retain_on_pc = rp, \
|
||||
.activate_on_init = a, \
|
||||
}
|
||||
|
||||
static struct llcc_slice_config sdm845_data[] = {
|
||||
SCT_ENTRY(LLCC_CPUSS, 1, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 1),
|
||||
SCT_ENTRY(LLCC_VIDSC0, 2, 512, 2, 1, 0x0, 0x0f0, 0, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_VIDSC1, 3, 512, 2, 1, 0x0, 0x0f0, 0, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_ROTATOR, 4, 563, 2, 1, 0x0, 0x00e, 2, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_VOICE, 5, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_AUDIO, 6, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_MDMHPGRW, 7, 1024, 2, 0, 0xfc, 0xf00, 0, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_MDM, 8, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_CMPT, 10, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_GPUHTW, 11, 512, 1, 1, 0xc, 0x0, 0, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_GPU, 12, 2304, 1, 0, 0xff0, 0x2, 0, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_MMUHWT, 13, 256, 2, 0, 0x0, 0x1, 0, 0, 1, 0, 1),
|
||||
SCT_ENTRY(LLCC_CMPTDMA, 15, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_DISP, 16, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_VIDFW, 17, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_MDMHPFX, 20, 1024, 2, 1, 0x0, 0xf00, 0, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_MDMPNG, 21, 1024, 0, 1, 0x1e, 0x0, 0, 0, 1, 1, 0),
|
||||
SCT_ENTRY(LLCC_AUDHW, 22, 1024, 1, 1, 0xffc, 0x2, 0, 0, 1, 1, 0),
|
||||
};
|
||||
|
||||
static int sdm845_qcom_llcc_remove(struct platform_device *pdev)
|
||||
{
|
||||
return qcom_llcc_remove(pdev);
|
||||
}
|
||||
|
||||
static int sdm845_qcom_llcc_probe(struct platform_device *pdev)
|
||||
{
|
||||
return qcom_llcc_probe(pdev, sdm845_data, ARRAY_SIZE(sdm845_data));
|
||||
}
|
||||
|
||||
static const struct of_device_id sdm845_qcom_llcc_of_match[] = {
|
||||
{ .compatible = "qcom,sdm845-llcc", },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver sdm845_qcom_llcc_driver = {
|
||||
.driver = {
|
||||
.name = "sdm845-llcc",
|
||||
.of_match_table = sdm845_qcom_llcc_of_match,
|
||||
},
|
||||
.probe = sdm845_qcom_llcc_probe,
|
||||
.remove = sdm845_qcom_llcc_remove,
|
||||
};
|
||||
module_platform_driver(sdm845_qcom_llcc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("QCOM sdm845 LLCC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -115,6 +115,28 @@ struct rpmpd_desc {
|
|||
|
||||
static DEFINE_MUTEX(rpmpd_lock);
|
||||
|
||||
/* msm8976 RPM Power Domains */
|
||||
DEFINE_RPMPD_PAIR(msm8976, vddcx, vddcx_ao, SMPA, LEVEL, 2);
|
||||
DEFINE_RPMPD_PAIR(msm8976, vddmx, vddmx_ao, SMPA, LEVEL, 6);
|
||||
|
||||
DEFINE_RPMPD_VFL(msm8976, vddcx_vfl, RWSC, 2);
|
||||
DEFINE_RPMPD_VFL(msm8976, vddmx_vfl, RWSM, 6);
|
||||
|
||||
static struct rpmpd *msm8976_rpmpds[] = {
|
||||
[MSM8976_VDDCX] = &msm8976_vddcx,
|
||||
[MSM8976_VDDCX_AO] = &msm8976_vddcx_ao,
|
||||
[MSM8976_VDDCX_VFL] = &msm8976_vddcx_vfl,
|
||||
[MSM8976_VDDMX] = &msm8976_vddmx,
|
||||
[MSM8976_VDDMX_AO] = &msm8976_vddmx_ao,
|
||||
[MSM8976_VDDMX_VFL] = &msm8976_vddmx_vfl,
|
||||
};
|
||||
|
||||
static const struct rpmpd_desc msm8976_desc = {
|
||||
.rpmpds = msm8976_rpmpds,
|
||||
.num_pds = ARRAY_SIZE(msm8976_rpmpds),
|
||||
.max_state = RPM_SMD_LEVEL_TURBO_HIGH,
|
||||
};
|
||||
|
||||
/* msm8996 RPM Power domains */
|
||||
DEFINE_RPMPD_PAIR(msm8996, vddcx, vddcx_ao, SMPA, CORNER, 1);
|
||||
DEFINE_RPMPD_PAIR(msm8996, vddmx, vddmx_ao, SMPA, CORNER, 2);
|
||||
|
@ -198,6 +220,7 @@ static const struct rpmpd_desc qcs404_desc = {
|
|||
};
|
||||
|
||||
static const struct of_device_id rpmpd_match_table[] = {
|
||||
{ .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc },
|
||||
{ .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc },
|
||||
{ .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc },
|
||||
{ .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc },
|
||||
|
|
|
@ -19,12 +19,14 @@
|
|||
/**
|
||||
* struct qcom_smd_rpm - state of the rpm device driver
|
||||
* @rpm_channel: reference to the smd channel
|
||||
* @icc: interconnect proxy device
|
||||
* @ack: completion for acks
|
||||
* @lock: mutual exclusion around the send/complete pair
|
||||
* @ack_status: result of the rpm request
|
||||
*/
|
||||
struct qcom_smd_rpm {
|
||||
struct rpmsg_endpoint *rpm_channel;
|
||||
struct platform_device *icc;
|
||||
struct device *dev;
|
||||
|
||||
struct completion ack;
|
||||
|
@ -193,6 +195,7 @@ static int qcom_smd_rpm_callback(struct rpmsg_device *rpdev,
|
|||
static int qcom_smd_rpm_probe(struct rpmsg_device *rpdev)
|
||||
{
|
||||
struct qcom_smd_rpm *rpm;
|
||||
int ret;
|
||||
|
||||
rpm = devm_kzalloc(&rpdev->dev, sizeof(*rpm), GFP_KERNEL);
|
||||
if (!rpm)
|
||||
|
@ -205,11 +208,23 @@ static int qcom_smd_rpm_probe(struct rpmsg_device *rpdev)
|
|||
rpm->rpm_channel = rpdev->ept;
|
||||
dev_set_drvdata(&rpdev->dev, rpm);
|
||||
|
||||
return of_platform_populate(rpdev->dev.of_node, NULL, NULL, &rpdev->dev);
|
||||
rpm->icc = platform_device_register_data(&rpdev->dev, "icc_smd_rpm", -1,
|
||||
NULL, 0);
|
||||
if (IS_ERR(rpm->icc))
|
||||
return PTR_ERR(rpm->icc);
|
||||
|
||||
ret = of_platform_populate(rpdev->dev.of_node, NULL, NULL, &rpdev->dev);
|
||||
if (ret)
|
||||
platform_device_unregister(rpm->icc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qcom_smd_rpm_remove(struct rpmsg_device *rpdev)
|
||||
{
|
||||
struct qcom_smd_rpm *rpm = dev_get_drvdata(&rpdev->dev);
|
||||
|
||||
platform_device_unregister(rpm->icc);
|
||||
of_platform_depopulate(&rpdev->dev);
|
||||
}
|
||||
|
||||
|
@ -217,6 +232,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = {
|
|||
{ .compatible = "qcom,rpm-apq8084" },
|
||||
{ .compatible = "qcom,rpm-msm8916" },
|
||||
{ .compatible = "qcom,rpm-msm8974" },
|
||||
{ .compatible = "qcom,rpm-msm8976" },
|
||||
{ .compatible = "qcom,rpm-msm8996" },
|
||||
{ .compatible = "qcom,rpm-msm8998" },
|
||||
{ .compatible = "qcom,rpm-sdm660" },
|
||||
|
|
|
@ -198,6 +198,8 @@ static const struct soc_id soc_id[] = {
|
|||
{ 310, "MSM8996AU" },
|
||||
{ 311, "APQ8096AU" },
|
||||
{ 312, "APQ8096SG" },
|
||||
{ 321, "SDM845" },
|
||||
{ 341, "SDA845" },
|
||||
};
|
||||
|
||||
static const char *socinfo_machine(struct device *dev, unsigned int id)
|
||||
|
|
|
@ -178,6 +178,13 @@ config ARCH_R8A774A1
|
|||
help
|
||||
This enables support for the Renesas RZ/G2M SoC.
|
||||
|
||||
config ARCH_R8A774B1
|
||||
bool "Renesas RZ/G2N SoC Platform"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A774B1
|
||||
help
|
||||
This enables support for the Renesas RZ/G2N SoC.
|
||||
|
||||
config ARCH_R8A774C0
|
||||
bool "Renesas RZ/G2E SoC Platform"
|
||||
select ARCH_RCAR_GEN3
|
||||
|
@ -192,13 +199,24 @@ config ARCH_R8A7795
|
|||
help
|
||||
This enables support for the Renesas R-Car H3 SoC.
|
||||
|
||||
config ARCH_R8A77960
|
||||
bool
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A77960
|
||||
|
||||
config ARCH_R8A7796
|
||||
bool "Renesas R-Car M3-W SoC Platform"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A7796
|
||||
select ARCH_R8A77960
|
||||
help
|
||||
This enables support for the Renesas R-Car M3-W SoC.
|
||||
|
||||
config ARCH_R8A77961
|
||||
bool "Renesas R-Car M3-W+ SoC Platform"
|
||||
select ARCH_RCAR_GEN3
|
||||
select SYSC_R8A77961
|
||||
help
|
||||
This enables support for the Renesas R-Car M3-W+ SoC.
|
||||
|
||||
config ARCH_R8A77965
|
||||
bool "Renesas R-Car M3-N SoC Platform"
|
||||
select ARCH_RCAR_GEN3
|
||||
|
@ -253,6 +271,10 @@ config SYSC_R8A774A1
|
|||
bool "RZ/G2M System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A774B1
|
||||
bool "RZ/G2N System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A774C0
|
||||
bool "RZ/G2E System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
@ -281,10 +303,14 @@ config SYSC_R8A7795
|
|||
bool "R-Car H3 System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A7796
|
||||
config SYSC_R8A77960
|
||||
bool "R-Car M3-W System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77961
|
||||
bool "R-Car M3-W+ System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
||||
config SYSC_R8A77965
|
||||
bool "R-Car M3-N System Controller support" if COMPILE_TEST
|
||||
select SYSC_RCAR
|
||||
|
|
|
@ -7,6 +7,7 @@ obj-$(CONFIG_SYSC_R8A7743) += r8a7743-sysc.o
|
|||
obj-$(CONFIG_SYSC_R8A7745) += r8a7745-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A77470) += r8a77470-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A774A1) += r8a774a1-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A774B1) += r8a774b1-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A774C0) += r8a774c0-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A7779) += r8a7779-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A7790) += r8a7790-sysc.o
|
||||
|
@ -14,7 +15,8 @@ obj-$(CONFIG_SYSC_R8A7791) += r8a7791-sysc.o
|
|||
obj-$(CONFIG_SYSC_R8A7792) += r8a7792-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A7794) += r8a7794-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A7795) += r8a7795-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A7796) += r8a7796-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A77960) += r8a7796-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A77961) += r8a7796-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A77965) += r8a77965-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A77970) += r8a77970-sysc.o
|
||||
obj-$(CONFIG_SYSC_R8A77980) += r8a77980-sysc.o
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* Copyright (C) 2016 Cogent Embedded Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <dt-bindings/power/r8a7743-sysc.h>
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* Copyright (C) 2016 Cogent Embedded Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <dt-bindings/power/r8a7745-sysc.h>
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* Copyright (C) 2018 Renesas Electronics Corp.
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <dt-bindings/power/r8a77470-sysc.h>
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
* Copyright (C) 2016 Glider bvba
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <dt-bindings/power/r8a774a1-sysc.h>
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Renesas RZ/G2N System Controller
|
||||
* Copyright (C) 2019 Renesas Electronics Corp.
|
||||
*
|
||||
* Based on Renesas R-Car M3-W System Controller
|
||||
* Copyright (C) 2016 Glider bvba
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <dt-bindings/power/r8a774b1-sysc.h>
|
||||
|
||||
#include "rcar-sysc.h"
|
||||
|
||||
static const struct rcar_sysc_area r8a774b1_areas[] __initconst = {
|
||||
{ "always-on", 0, 0, R8A774B1_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
|
||||
{ "ca57-scu", 0x1c0, 0, R8A774B1_PD_CA57_SCU, R8A774B1_PD_ALWAYS_ON,
|
||||
PD_SCU },
|
||||
{ "ca57-cpu0", 0x80, 0, R8A774B1_PD_CA57_CPU0, R8A774B1_PD_CA57_SCU,
|
||||
PD_CPU_NOCR },
|
||||
{ "ca57-cpu1", 0x80, 1, R8A774B1_PD_CA57_CPU1, R8A774B1_PD_CA57_SCU,
|
||||
PD_CPU_NOCR },
|
||||
{ "a3vc", 0x380, 0, R8A774B1_PD_A3VC, R8A774B1_PD_ALWAYS_ON },
|
||||
{ "a3vp", 0x340, 0, R8A774B1_PD_A3VP, R8A774B1_PD_ALWAYS_ON },
|
||||
{ "a2vc1", 0x3c0, 1, R8A774B1_PD_A2VC1, R8A774B1_PD_A3VC },
|
||||
{ "3dg-a", 0x100, 0, R8A774B1_PD_3DG_A, R8A774B1_PD_ALWAYS_ON },
|
||||
{ "3dg-b", 0x100, 1, R8A774B1_PD_3DG_B, R8A774B1_PD_3DG_A },
|
||||
};
|
||||
|
||||
const struct rcar_sysc_info r8a774b1_sysc_info __initconst = {
|
||||
.areas = r8a774b1_areas,
|
||||
.num_areas = ARRAY_SIZE(r8a774b1_areas),
|
||||
.extmask_offs = 0x2f8,
|
||||
.extmask_val = BIT(0),
|
||||
};
|
|
@ -6,7 +6,7 @@
|
|||
* Based on Renesas R-Car E3 System Controller
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sys_soc.h>
|
||||
|
||||
|
@ -50,4 +50,6 @@ const struct rcar_sysc_info r8a774c0_sysc_info __initconst = {
|
|||
.init = r8a774c0_sysc_init,
|
||||
.areas = r8a774c0_areas,
|
||||
.num_areas = ARRAY_SIZE(r8a774c0_areas),
|
||||
.extmask_offs = 0x2f8,
|
||||
.extmask_val = BIT(0),
|
||||
};
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* Copyright (C) 2016 Glider bvba
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <dt-bindings/power/r8a7779-sysc.h>
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* Copyright (C) 2016 Glider bvba
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <dt-bindings/power/r8a7790-sysc.h>
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* Copyright (C) 2016 Glider bvba
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <dt-bindings/power/r8a7791-sysc.h>
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* Copyright (C) 2016 Cogent Embedded Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* Copyright (C) 2016 Glider bvba
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <dt-bindings/power/r8a7794-sysc.h>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Copyright (C) 2016-2017 Glider bvba
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sys_soc.h>
|
||||
|
||||
|
@ -51,25 +51,46 @@ static struct rcar_sysc_area r8a7795_areas[] __initdata = {
|
|||
|
||||
|
||||
/*
|
||||
* Fixups for R-Car H3 revisions after ES1.x
|
||||
* Fixups for R-Car H3 revisions
|
||||
*/
|
||||
|
||||
static const struct soc_device_attribute r8a7795es1[] __initconst = {
|
||||
{ .soc_id = "r8a7795", .revision = "ES1.*" },
|
||||
#define HAS_A2VC0 BIT(0) /* Power domain A2VC0 is present */
|
||||
#define NO_EXTMASK BIT(1) /* Missing SYSCEXTMASK register */
|
||||
|
||||
static const struct soc_device_attribute r8a7795_quirks_match[] __initconst = {
|
||||
{
|
||||
.soc_id = "r8a7795", .revision = "ES1.*",
|
||||
.data = (void *)(HAS_A2VC0 | NO_EXTMASK),
|
||||
}, {
|
||||
.soc_id = "r8a7795", .revision = "ES2.*",
|
||||
.data = (void *)(NO_EXTMASK),
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static int __init r8a7795_sysc_init(void)
|
||||
{
|
||||
if (!soc_device_match(r8a7795es1))
|
||||
const struct soc_device_attribute *attr;
|
||||
u32 quirks = 0;
|
||||
|
||||
attr = soc_device_match(r8a7795_quirks_match);
|
||||
if (attr)
|
||||
quirks = (uintptr_t)attr->data;
|
||||
|
||||
if (!(quirks & HAS_A2VC0))
|
||||
rcar_sysc_nullify(r8a7795_areas, ARRAY_SIZE(r8a7795_areas),
|
||||
R8A7795_PD_A2VC0);
|
||||
|
||||
if (quirks & NO_EXTMASK)
|
||||
r8a7795_sysc_info.extmask_val = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct rcar_sysc_info r8a7795_sysc_info __initconst = {
|
||||
struct rcar_sysc_info r8a7795_sysc_info __initdata = {
|
||||
.init = r8a7795_sysc_init,
|
||||
.areas = r8a7795_areas,
|
||||
.num_areas = ARRAY_SIZE(r8a7795_areas),
|
||||
.extmask_offs = 0x2f8,
|
||||
.extmask_val = BIT(0),
|
||||
};
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Renesas R-Car M3-W System Controller
|
||||
* Renesas R-Car M3-W/W+ System Controller
|
||||
*
|
||||
* Copyright (C) 2016 Glider bvba
|
||||
* Copyright (C) 2018-2019 Renesas Electronics Corporation
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <dt-bindings/power/r8a7796-sysc.h>
|
||||
|
||||
#include "rcar-sysc.h"
|
||||
|
||||
static const struct rcar_sysc_area r8a7796_areas[] __initconst = {
|
||||
static struct rcar_sysc_area r8a7796_areas[] __initdata = {
|
||||
{ "always-on", 0, 0, R8A7796_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
|
||||
{ "ca57-scu", 0x1c0, 0, R8A7796_PD_CA57_SCU, R8A7796_PD_ALWAYS_ON,
|
||||
PD_SCU },
|
||||
|
@ -39,7 +40,28 @@ static const struct rcar_sysc_area r8a7796_areas[] __initconst = {
|
|||
{ "a3ir", 0x180, 0, R8A7796_PD_A3IR, R8A7796_PD_ALWAYS_ON },
|
||||
};
|
||||
|
||||
const struct rcar_sysc_info r8a7796_sysc_info __initconst = {
|
||||
|
||||
#ifdef CONFIG_SYSC_R8A77960
|
||||
const struct rcar_sysc_info r8a77960_sysc_info __initconst = {
|
||||
.areas = r8a7796_areas,
|
||||
.num_areas = ARRAY_SIZE(r8a7796_areas),
|
||||
};
|
||||
#endif /* CONFIG_SYSC_R8A77960 */
|
||||
|
||||
#ifdef CONFIG_SYSC_R8A77961
|
||||
static int __init r8a77961_sysc_init(void)
|
||||
{
|
||||
rcar_sysc_nullify(r8a7796_areas, ARRAY_SIZE(r8a7796_areas),
|
||||
R8A7796_PD_A2VC0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct rcar_sysc_info r8a77961_sysc_info __initconst = {
|
||||
.init = r8a77961_sysc_init,
|
||||
.areas = r8a7796_areas,
|
||||
.num_areas = ARRAY_SIZE(r8a7796_areas),
|
||||
.extmask_offs = 0x2f8,
|
||||
.extmask_val = BIT(0),
|
||||
};
|
||||
#endif /* CONFIG_SYSC_R8A77961 */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Copyright (C) 2016 Glider bvba
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <dt-bindings/power/r8a77965-sysc.h>
|
||||
|
@ -33,4 +33,6 @@ static const struct rcar_sysc_area r8a77965_areas[] __initconst = {
|
|||
const struct rcar_sysc_info r8a77965_sysc_info __initconst = {
|
||||
.areas = r8a77965_areas,
|
||||
.num_areas = ARRAY_SIZE(r8a77965_areas),
|
||||
.extmask_offs = 0x2f8,
|
||||
.extmask_val = BIT(0),
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Copyright (C) 2017 Cogent Embedded Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <dt-bindings/power/r8a77970-sysc.h>
|
||||
|
@ -32,4 +32,6 @@ static const struct rcar_sysc_area r8a77970_areas[] __initconst = {
|
|||
const struct rcar_sysc_info r8a77970_sysc_info __initconst = {
|
||||
.areas = r8a77970_areas,
|
||||
.num_areas = ARRAY_SIZE(r8a77970_areas),
|
||||
.extmask_offs = 0x1b0,
|
||||
.extmask_val = BIT(0),
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Copyright (C) 2018 Cogent Embedded, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <dt-bindings/power/r8a77980-sysc.h>
|
||||
|
@ -49,4 +49,6 @@ static const struct rcar_sysc_area r8a77980_areas[] __initconst = {
|
|||
const struct rcar_sysc_info r8a77980_sysc_info __initconst = {
|
||||
.areas = r8a77980_areas,
|
||||
.num_areas = ARRAY_SIZE(r8a77980_areas),
|
||||
.extmask_offs = 0x138,
|
||||
.extmask_val = BIT(0),
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Copyright (C) 2018 Renesas Electronics Corp.
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sys_soc.h>
|
||||
|
||||
|
@ -50,4 +50,6 @@ const struct rcar_sysc_info r8a77990_sysc_info __initconst = {
|
|||
.init = r8a77990_sysc_init,
|
||||
.areas = r8a77990_areas,
|
||||
.num_areas = ARRAY_SIZE(r8a77990_areas),
|
||||
.extmask_offs = 0x2f8,
|
||||
.extmask_val = BIT(0),
|
||||
};
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* Copyright (C) 2017 Glider bvba
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <dt-bindings/power/r8a77995-sysc.h>
|
||||
|
|
|
@ -45,6 +45,7 @@ static const struct of_device_id rcar_rst_matches[] __initconst = {
|
|||
{ .compatible = "renesas,r8a77470-rst", .data = &rcar_rst_gen2 },
|
||||
/* RZ/G2 is handled like R-Car Gen3 */
|
||||
{ .compatible = "renesas,r8a774a1-rst", .data = &rcar_rst_gen3 },
|
||||
{ .compatible = "renesas,r8a774b1-rst", .data = &rcar_rst_gen3 },
|
||||
{ .compatible = "renesas,r8a774c0-rst", .data = &rcar_rst_gen3 },
|
||||
/* R-Car Gen1 */
|
||||
{ .compatible = "renesas,r8a7778-reset-wdt", .data = &rcar_rst_gen1 },
|
||||
|
@ -58,6 +59,7 @@ static const struct of_device_id rcar_rst_matches[] __initconst = {
|
|||
/* R-Car Gen3 */
|
||||
{ .compatible = "renesas,r8a7795-rst", .data = &rcar_rst_gen3 },
|
||||
{ .compatible = "renesas,r8a7796-rst", .data = &rcar_rst_gen3 },
|
||||
{ .compatible = "renesas,r8a77961-rst", .data = &rcar_rst_gen3 },
|
||||
{ .compatible = "renesas,r8a77965-rst", .data = &rcar_rst_gen3 },
|
||||
{ .compatible = "renesas,r8a77970-rst", .data = &rcar_rst_gen3 },
|
||||
{ .compatible = "renesas,r8a77980-rst", .data = &rcar_rst_gen3 },
|
||||
|
|
|
@ -63,6 +63,7 @@ struct rcar_sysc_ch {
|
|||
|
||||
static void __iomem *rcar_sysc_base;
|
||||
static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */
|
||||
static u32 rcar_sysc_extmask_offs, rcar_sysc_extmask_val;
|
||||
|
||||
static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on)
|
||||
{
|
||||
|
@ -105,6 +106,14 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on)
|
|||
|
||||
spin_lock_irqsave(&rcar_sysc_lock, flags);
|
||||
|
||||
/*
|
||||
* Mask external power requests for CPU or 3DG domains
|
||||
*/
|
||||
if (rcar_sysc_extmask_val) {
|
||||
iowrite32(rcar_sysc_extmask_val,
|
||||
rcar_sysc_base + rcar_sysc_extmask_offs);
|
||||
}
|
||||
|
||||
/*
|
||||
* The interrupt source needs to be enabled, but masked, to prevent the
|
||||
* CPU from receiving it.
|
||||
|
@ -148,6 +157,9 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on)
|
|||
iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
|
||||
|
||||
out:
|
||||
if (rcar_sysc_extmask_val)
|
||||
iowrite32(0, rcar_sysc_base + rcar_sysc_extmask_offs);
|
||||
|
||||
spin_unlock_irqrestore(&rcar_sysc_lock, flags);
|
||||
|
||||
pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off",
|
||||
|
@ -275,6 +287,9 @@ static const struct of_device_id rcar_sysc_matches[] __initconst = {
|
|||
#ifdef CONFIG_SYSC_R8A774A1
|
||||
{ .compatible = "renesas,r8a774a1-sysc", .data = &r8a774a1_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_SYSC_R8A774B1
|
||||
{ .compatible = "renesas,r8a774b1-sysc", .data = &r8a774b1_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_SYSC_R8A774C0
|
||||
{ .compatible = "renesas,r8a774c0-sysc", .data = &r8a774c0_sysc_info },
|
||||
#endif
|
||||
|
@ -298,8 +313,11 @@ static const struct of_device_id rcar_sysc_matches[] __initconst = {
|
|||
#ifdef CONFIG_SYSC_R8A7795
|
||||
{ .compatible = "renesas,r8a7795-sysc", .data = &r8a7795_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_SYSC_R8A7796
|
||||
{ .compatible = "renesas,r8a7796-sysc", .data = &r8a7796_sysc_info },
|
||||
#ifdef CONFIG_SYSC_R8A77960
|
||||
{ .compatible = "renesas,r8a7796-sysc", .data = &r8a77960_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_SYSC_R8A77961
|
||||
{ .compatible = "renesas,r8a77961-sysc", .data = &r8a77961_sysc_info },
|
||||
#endif
|
||||
#ifdef CONFIG_SYSC_R8A77965
|
||||
{ .compatible = "renesas,r8a77965-sysc", .data = &r8a77965_sysc_info },
|
||||
|
@ -360,6 +378,10 @@ static int __init rcar_sysc_pd_init(void)
|
|||
|
||||
rcar_sysc_base = base;
|
||||
|
||||
/* Optional External Request Mask Register */
|
||||
rcar_sysc_extmask_offs = info->extmask_offs;
|
||||
rcar_sysc_extmask_val = info->extmask_val;
|
||||
|
||||
domains = kzalloc(sizeof(*domains), GFP_KERNEL);
|
||||
if (!domains) {
|
||||
error = -ENOMEM;
|
||||
|
|
|
@ -44,20 +44,25 @@ struct rcar_sysc_info {
|
|||
int (*init)(void); /* Optional */
|
||||
const struct rcar_sysc_area *areas;
|
||||
unsigned int num_areas;
|
||||
/* Optional External Request Mask Register */
|
||||
u32 extmask_offs; /* SYSCEXTMASK register offset */
|
||||
u32 extmask_val; /* SYSCEXTMASK register mask value */
|
||||
};
|
||||
|
||||
extern const struct rcar_sysc_info r8a7743_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a7745_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a77470_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a774a1_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a774b1_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a774c0_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a7779_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a7790_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a7791_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a7792_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a7794_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a7795_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a7796_sysc_info;
|
||||
extern struct rcar_sysc_info r8a7795_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a77960_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a77961_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a77965_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a77970_sysc_info;
|
||||
extern const struct rcar_sysc_info r8a77980_sysc_info;
|
||||
|
|
|
@ -116,6 +116,11 @@ static const struct renesas_soc soc_rz_g2m __initconst __maybe_unused = {
|
|||
.id = 0x52,
|
||||
};
|
||||
|
||||
static const struct renesas_soc soc_rz_g2n __initconst __maybe_unused = {
|
||||
.family = &fam_rzg2,
|
||||
.id = 0x55,
|
||||
};
|
||||
|
||||
static const struct renesas_soc soc_rz_g2e __initconst __maybe_unused = {
|
||||
.family = &fam_rzg2,
|
||||
.id = 0x57,
|
||||
|
@ -227,6 +232,9 @@ static const struct of_device_id renesas_socs[] __initconst = {
|
|||
#ifdef CONFIG_ARCH_R8A774A1
|
||||
{ .compatible = "renesas,r8a774a1", .data = &soc_rz_g2m },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A774B1
|
||||
{ .compatible = "renesas,r8a774b1", .data = &soc_rz_g2n },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A774C0
|
||||
{ .compatible = "renesas,r8a774c0", .data = &soc_rz_g2e },
|
||||
#endif
|
||||
|
@ -254,9 +262,12 @@ static const struct of_device_id renesas_socs[] __initconst = {
|
|||
#ifdef CONFIG_ARCH_R8A7795
|
||||
{ .compatible = "renesas,r8a7795", .data = &soc_rcar_h3 },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A7796
|
||||
#ifdef CONFIG_ARCH_R8A77960
|
||||
{ .compatible = "renesas,r8a7796", .data = &soc_rcar_m3_w },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A77961
|
||||
{ .compatible = "renesas,r8a77961", .data = &soc_rcar_m3_w },
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_R8A77965
|
||||
{ .compatible = "renesas,r8a77965", .data = &soc_rcar_m3_n },
|
||||
#endif
|
||||
|
@ -326,7 +337,7 @@ static int __init renesas_soc_init(void)
|
|||
if (np) {
|
||||
chipid = of_iomap(np, 0);
|
||||
of_node_put(np);
|
||||
} else if (soc->id) {
|
||||
} else if (soc->id && family->reg) {
|
||||
chipid = ioremap(family->reg, 4);
|
||||
}
|
||||
if (chipid) {
|
||||
|
|
|
@ -7,6 +7,16 @@ menuconfig SOC_SAMSUNG
|
|||
|
||||
if SOC_SAMSUNG
|
||||
|
||||
config EXYNOS_ASV
|
||||
bool "Exynos Adaptive Supply Voltage support" if COMPILE_TEST
|
||||
depends on (ARCH_EXYNOS && EXYNOS_CHIPID) || COMPILE_TEST
|
||||
select EXYNOS_ASV_ARM if ARM && ARCH_EXYNOS
|
||||
|
||||
# There is no need to enable these drivers for ARMv8
|
||||
config EXYNOS_ASV_ARM
|
||||
bool "Exynos ASV ARMv7-specific driver extensions" if COMPILE_TEST
|
||||
depends on EXYNOS_ASV
|
||||
|
||||
config EXYNOS_CHIPID
|
||||
bool "Exynos Chipid controller driver" if COMPILE_TEST
|
||||
depends on ARCH_EXYNOS || COMPILE_TEST
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче