Commit 822ef14e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'arm-drivers-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc

Pull ARM SoC driver updates from Arnd Bergmann:
 "A couple of subsystems have their own subsystem maintainers but choose
  to have the code merged through the soc tree as upstream, as the code
  tends to be used across multiple SoCs or has SoC specific drivers
  itself:

   - memory controllers:

     Krzysztof Kozlowski takes ownership of the drivers/memory subsystem
     and its drivers, starting out with a set of cleanup patches.

     A larger driver for the Tegra memory controller that was
     accidentally missed for v5.8 is now added.

   - reset controllers:

     Only minor updates to drivers/reset this time

   - firmware:

     The "turris mox" firmware driver gains support for signed firmware
     blobs The tegra firmware driver gets extended to export some debug
     information Various updates to i.MX firmware drivers, mostly
     cosmetic

   - ARM SCMI/SCPI:

     A new mechanism for platform notifications is added, among a number
     of minor changes.

   - optee:

     Probing of the TEE bus is rewritten to better support detection of
     devices that depend on the tee-supplicant user space. A new
     firmware based trusted platform module (fTPM) driver is added based
     on OP-TEE

   - SoC attributes:

     A new driver is added to provide a generic soc_device for
     identifying a machine through the SMCCC ARCH_SOC_ID firmware
     interface rather than by probing SoC family specific registers.

     The series also contains some cleanups to the common soc_device
     code.

  There are also a number of updates to SoC specific drivers, the main
  ones are:

   - Mediatek cmdq driver gains a few in-kernel interfaces

   - Minor updates to Qualcomm RPMh, socinfo, rpm drivers, mostly adding
     support for additional SoC variants

   - The Qualcomm GENI core code gains interconnect path voting and
     performance level support, and integrating this into a number of
     device drivers.

   - A new driver for Samsung Exynos5800 voltage coupler for

   - Renesas RZ/G2H (R8A774E1) SoC support gets added to a couple of SoC
     specific device drivers

   - Updates to the TI K3 Ring Accelerator driver"

* tag 'arm-drivers-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (164 commits)
  soc: qcom: geni: Fix unused label warning
  soc: qcom: smd-rpm: Fix kerneldoc
  memory: jz4780_nemc: Only request IO memory the driver will use
  soc: qcom: pdr: Reorder the PD state indication ack
  MAINTAINERS: Add Git repository for memory controller drivers
  memory: brcmstb_dpfe: Fix language typo
  memory: samsung: exynos5422-dmc: Correct white space issues
  memory: samsung: exynos-srom: Correct alignment
  memory: pl172: Enclose macro argument usage in parenthesis
  memory: of: Correct kerneldoc
  memory: omap-gpmc: Fix language typo
  memory: omap-gpmc: Correct white space issues
  memory: omap-gpmc: Use 'unsigned int' for consistency
  memory: omap-gpmc: Enclose macro argument usage in parenthesis
  memory: omap-gpmc: Correct kerneldoc
  memory: mvebu-devbus: Align with open parenthesis
  memory: mvebu-devbus: Add missing braces to all arms of if statement
  memory: bt1-l2-ctl: Add blank lines after declarations
  soc: TI knav_qmss: make symbol 'knav_acc_range_ops' static
  firmware: ti_sci: Replace HTTP links with HTTPS ones
  ...
parents 6ce076f4 d76cfc7c
What: /sys/kernel/debug/turris-mox-rwtm/do_sign
Date: Jun 2020
KernelVersion: 5.8
Contact: Marek Behún <marek.behun@nic.cz>
Description: (W) Message to sign with the ECDSA private key stored in
device's OTP. The message must be exactly 64 bytes (since
this is intended for SHA-512 hashes).
(R) The resulting signature, 136 bytes. This contains the R and
S values of the ECDSA signature, both in big-endian format.
What: /sys/bus/tee/devices/optee-ta-<uuid>/
Date: May 2020
KernelVersion 5.8
Contact: op-tee@lists.trustedfirmware.org
Description:
OP-TEE bus provides reference to registered drivers under this directory. The <uuid>
matches Trusted Application (TA) driver and corresponding TA in secure OS. Drivers
are free to create needed API under optee-ta-<uuid> directory.
...@@ -26,6 +26,30 @@ Description: ...@@ -26,6 +26,30 @@ Description:
Read-only attribute common to all SoCs. Contains SoC family name Read-only attribute common to all SoCs. Contains SoC family name
(e.g. DB8500). (e.g. DB8500).
On many of ARM based silicon with SMCCC v1.2+ compliant firmware
this will contain the JEDEC JEP106 manufacturer’s identification
code. The format is "jep106:XXYY" where XX is identity code and
YY is continuation code.
This manufacturer’s identification code is defined by one
or more eight (8) bit fields, each consisting of seven (7)
data bits plus one (1) odd parity bit. It is a single field,
limiting the possible number of vendors to 126. To expand
the maximum number of identification codes, a continuation
scheme has been defined.
The specified mechanism is that an identity code of 0x7F
represents the "continuation code" and implies the presence
of an additional identity code field, and this mechanism
may be extended to multiple continuation codes followed
by the manufacturer's identity code.
For example, ARM has identity code 0x7F 0x7F 0x7F 0x7F 0x3B,
which is code 0x3B on the fifth 'page'. This is shortened
as JEP106 identity code of 0x3B and a continuation code of
0x4 to represent the four continuation codes preceding the
identity code.
What: /sys/devices/socX/serial_number What: /sys/devices/socX/serial_number
Date: January 2019 Date: January 2019
contact: Bjorn Andersson <bjorn.andersson@linaro.org> contact: Bjorn Andersson <bjorn.andersson@linaro.org>
...@@ -40,6 +64,12 @@ Description: ...@@ -40,6 +64,12 @@ Description:
Read-only attribute supported by most SoCs. In the case of Read-only attribute supported by most SoCs. In the case of
ST-Ericsson's chips this contains the SoC serial number. ST-Ericsson's chips this contains the SoC serial number.
On many of ARM based silicon with SMCCC v1.2+ compliant firmware
this will contain the SOC ID appended to the family attribute
to ensure there is no conflict in this namespace across various
vendors. The format is "jep106:XXYY:ZZZZ" where XX is identity
code, YY is continuation code and ZZZZ is the SOC ID.
What: /sys/devices/socX/revision What: /sys/devices/socX/revision
Date: January 2012 Date: January 2012
contact: Lee Jones <lee.jones@linaro.org> contact: Lee Jones <lee.jones@linaro.org>
......
...@@ -11,10 +11,12 @@ Required properties: ...@@ -11,10 +11,12 @@ Required properties:
* "qcom,scm-apq8084" * "qcom,scm-apq8084"
* "qcom,scm-ipq4019" * "qcom,scm-ipq4019"
* "qcom,scm-ipq806x" * "qcom,scm-ipq806x"
* "qcom,scm-ipq8074"
* "qcom,scm-msm8660" * "qcom,scm-msm8660"
* "qcom,scm-msm8916" * "qcom,scm-msm8916"
* "qcom,scm-msm8960" * "qcom,scm-msm8960"
* "qcom,scm-msm8974" * "qcom,scm-msm8974"
* "qcom,scm-msm8994"
* "qcom,scm-msm8996" * "qcom,scm-msm8996"
* "qcom,scm-msm8998" * "qcom,scm-msm8998"
* "qcom,scm-sc7180" * "qcom,scm-sc7180"
......
...@@ -55,7 +55,7 @@ Required Properties: ...@@ -55,7 +55,7 @@ Required Properties:
corresponds to a range of host irqs. corresponds to a range of host irqs.
For more details on TISCI IRQ resource management refer: For more details on TISCI IRQ resource management refer:
http://downloads.ti.com/tisci/esd/latest/2_tisci_msgs/rm/rm_irq.html https://downloads.ti.com/tisci/esd/latest/2_tisci_msgs/rm/rm_irq.html
Example: Example:
-------- --------
......
Freescale i.MX System Reset Controller
======================================
Please also refer to reset.txt in this directory for common reset
controller binding usage.
Required properties:
- compatible: Should be "fsl,<chip>-src"
- reg: should be register base and length as documented in the
datasheet
- interrupts: Should contain SRC interrupt and CPU WDOG interrupt,
in this order.
- #reset-cells: 1, see below
example:
src: src@20d8000 {
compatible = "fsl,imx6q-src";
reg = <0x020d8000 0x4000>;
interrupts = <0 91 0x04 0 96 0x04>;
#reset-cells = <1>;
};
Specifying reset lines connected to IP modules
==============================================
The system reset controller can be used to reset the GPU, VPU,
IPU, and OpenVG IP modules on i.MX5 and i.MX6 ICs. Those device
nodes should specify the reset line on the SRC in their resets
property, containing a phandle to the SRC device node and a
RESET_INDEX specifying which module to reset, as described in
reset.txt
example:
ipu1: ipu@2400000 {
resets = <&src 2>;
};
ipu2: ipu@2800000 {
resets = <&src 4>;
};
The following RESET_INDEX values are valid for i.MX5:
GPU_RESET 0
VPU_RESET 1
IPU1_RESET 2
OPEN_VG_RESET 3
The following additional RESET_INDEX value is valid for i.MX6:
IPU2_RESET 4
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/reset/fsl,imx-src.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX System Reset Controller
maintainers:
- Philipp Zabel <p.zabel@pengutronix.de>
description: |
The system reset controller can be used to reset the GPU, VPU,
IPU, and OpenVG IP modules on i.MX5 and i.MX6 ICs. Those device
nodes should specify the reset line on the SRC in their resets
property, containing a phandle to the SRC device node and a
RESET_INDEX specifying which module to reset, as described in
reset.txt
The following RESET_INDEX values are valid for i.MX5:
GPU_RESET 0
VPU_RESET 1
IPU1_RESET 2
OPEN_VG_RESET 3
The following additional RESET_INDEX value is valid for i.MX6:
IPU2_RESET 4
properties:
compatible:
oneOf:
- const: "fsl,imx51-src"
- items:
- const: "fsl,imx50-src"
- const: "fsl,imx51-src"
- items:
- const: "fsl,imx53-src"
- const: "fsl,imx51-src"
- items:
- const: "fsl,imx6q-src"
- const: "fsl,imx51-src"
- items:
- const: "fsl,imx6sx-src"
- const: "fsl,imx51-src"
- items:
- const: "fsl,imx6sl-src"
- const: "fsl,imx51-src"
- items:
- const: "fsl,imx6ul-src"
- const: "fsl,imx51-src"
- items:
- const: "fsl,imx6sll-src"
- const: "fsl,imx51-src"
reg:
maxItems: 1
interrupts:
items:
- description: SRC interrupt
- description: CPU WDOG interrupts out of SRC
minItems: 1
maxItems: 2
'#reset-cells':
const: 1
required:
- compatible
- reg
- interrupts
- '#reset-cells'
additionalProperties: false
examples:
- |
reset-controller@73fd0000 {
compatible = "fsl,imx51-src";
reg = <0x73fd0000 0x4000>;
interrupts = <75>;
#reset-cells = <1>;
};
Freescale i.MX7 System Reset Controller
======================================
Please also refer to reset.txt in this directory for common reset
controller binding usage.
Required properties:
- compatible:
- For i.MX7 SoCs should be "fsl,imx7d-src", "syscon"
- For i.MX8MQ SoCs should be "fsl,imx8mq-src", "syscon"
- For i.MX8MM SoCs should be "fsl,imx8mm-src", "fsl,imx8mq-src", "syscon"
- For i.MX8MN SoCs should be "fsl,imx8mn-src", "fsl,imx8mq-src", "syscon"
- For i.MX8MP SoCs should be "fsl,imx8mp-src", "syscon"
- reg: should be register base and length as documented in the
datasheet
- interrupts: Should contain SRC interrupt
- #reset-cells: 1, see below
example:
src: reset-controller@30390000 {
compatible = "fsl,imx7d-src", "syscon";
reg = <0x30390000 0x2000>;
interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
#reset-cells = <1>;
};
Specifying reset lines connected to IP modules
==============================================
The system reset controller can be used to reset various set of
peripherals. Device nodes that need access to reset lines should
specify them as a reset phandle in their corresponding node as
specified in reset.txt.
Example:
pcie: pcie@33800000 {
...
resets = <&src IMX7_RESET_PCIEPHY>,
<&src IMX7_RESET_PCIE_CTRL_APPS_EN>;
reset-names = "pciephy", "apps";
...
};
For list of all valid reset indices see
<dt-bindings/reset/imx7-reset.h> for i.MX7,
<dt-bindings/reset/imx8mq-reset.h> for i.MX8MQ and
<dt-bindings/reset/imx8mq-reset.h> for i.MX8MM and
<dt-bindings/reset/imx8mq-reset.h> for i.MX8MN and
<dt-bindings/reset/imx8mp-reset.h> for i.MX8MP
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/reset/fsl,imx7-src.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX7 System Reset Controller
maintainers:
- Andrey Smirnov <andrew.smirnov@gmail.com>
description: |
The system reset controller can be used to reset various set of
peripherals. 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 indices see
<dt-bindings/reset/imx7-reset.h> for i.MX7,
<dt-bindings/reset/imx8mq-reset.h> for i.MX8MQ, i.MX8MM and i.MX8MN,
<dt-bindings/reset/imx8mp-reset.h> for i.MX8MP.
properties:
compatible:
items:
- enum:
- fsl,imx7d-src
- fsl,imx8mq-src
- fsl,imx8mp-src
- const: syscon
reg:
maxItems: 1
interrupts:
maxItems: 1
'#reset-cells':
const: 1
required:
- compatible
- reg
- interrupts
- '#reset-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
reset-controller@30390000 {
compatible = "fsl,imx7d-src", "syscon";
reg = <0x30390000 0x2000>;
interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
#reset-cells = <1>;
};
Qualcomm Resource Power Manager (RPM) over SMD
This driver is used to interface with the Resource Power Manager (RPM) found in
various Qualcomm platforms. The RPM allows each component in the system to vote
for state of the system resources, such as clocks, regulators and bus
frequencies.
The SMD information for the RPM edge should be filled out. See qcom,smd.txt for
the required edge properties. All SMD related properties will reside within the
RPM node itself.
= SUBDEVICES
The RPM exposes resources to its subnodes. The rpm_requests node must be
present and this subnode may contain children that designate regulator
resources.
- compatible:
Usage: required
Value type: <string>
Definition: must be one of:
"qcom,rpm-apq8084"
"qcom,rpm-msm8916"
"qcom,rpm-msm8974"
"qcom,rpm-msm8976"
"qcom,rpm-msm8998"
"qcom,rpm-sdm660"
"qcom,rpm-qcs404"
- qcom,smd-channels:
Usage: required
Value type: <string>
Definition: must be "rpm_requests"
Refer to Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
for information on the regulator subnodes that can exist under the rpm_requests.
Example:
soc {
apcs: syscon@f9011000 {
compatible = "syscon";
reg = <0xf9011000 0x1000>;
};
};
smd {
compatible = "qcom,smd";
rpm {
interrupts = <0 168 1>;
qcom,ipc = <&apcs 8 0>;
qcom,smd-edge = <15>;
rpm_requests {
compatible = "qcom,rpm-msm8974";
qcom,smd-channels = "rpm_requests";
...
};
};
};
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/soc/qcom/qcom,smd-rpm.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Qualcomm Resource Power Manager (RPM) over SMD
description: |
This driver is used to interface with the Resource Power Manager (RPM) found
in various Qualcomm platforms. The RPM allows each component in the system
to vote for state of the system resources, such as clocks, regulators and bus
frequencies.
The SMD information for the RPM edge should be filled out. See qcom,smd.txt
for the required edge properties. All SMD related properties will reside
within the RPM node itself.
The RPM exposes resources to its subnodes. The rpm_requests node must be
present and this subnode may contain children that designate regulator
resources.
Refer to Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
for information on the regulator subnodes that can exist under the
rpm_requests.
maintainers:
- Kathiravan T <kathirav@codeaurora.org>
properties:
compatible:
enum:
- qcom,rpm-apq8084
- qcom,rpm-ipq6018
- qcom,rpm-msm8916
- qcom,rpm-msm8974
- qcom,rpm-msm8976
- qcom,rpm-msm8996
- qcom,rpm-msm8998
- qcom,rpm-sdm660
- qcom,rpm-qcs404
qcom,smd-channels:
$ref: /schemas/types.yaml#/definitions/string-array
description: Channel name used for the RPM communication
items:
- const: rpm_requests
if:
properties:
compatible:
contains:
enum:
- qcom,rpm-apq8084
- qcom,rpm-msm8916
- qcom,rpm-msm8974
then:
required:
- qcom,smd-channels
required:
- compatible
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
smd {
compatible = "qcom,smd";
rpm {
interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>;
qcom,ipc = <&apcs 8 0>;
qcom,smd-edge = <15>;
rpm_requests {
compatible = "qcom,rpm-msm8974";
qcom,smd-channels = "rpm_requests";
/* Regulator nodes to follow */
};
};
};
...
* Texas Instruments K3 NavigatorSS Ring Accelerator
The Ring Accelerator (RA) is a machine which converts read/write accesses
from/to a constant address into corresponding read/write accesses from/to a
circular data structure in memory. The RA eliminates the need for each DMA
controller which needs to access ring elements from having to know the current
state of the ring (base address, current offset). The DMA controller
performs a read or write access to a specific address range (which maps to the
source interface on the RA) and the RA replaces the address for the transaction
with a new address which corresponds to the head or tail element of the ring
(head for reads, tail for writes).
The Ring Accelerator is a hardware module that is responsible for accelerating
management of the packet queues. The K3 SoCs can have more than one RA instances
Required properties:
- compatible : Must be "ti,am654-navss-ringacc";
- reg : Should contain register location and length of the following
named register regions.
- reg-names : should be
"rt" - The RA Ring Real-time Control/Status Registers
"fifos" - The RA Queues Registers
"proxy_gcfg" - The RA Proxy Global Config Registers
"proxy_target" - The RA Proxy Datapath Registers
- ti,num-rings : Number of rings supported by RA
- ti,sci-rm-range-gp-rings : TI-SCI RM subtype for GP ring range
- ti,sci : phandle on TI-SCI compatible System controller node
- ti,sci-dev-id : TI-SCI device id of the ring accelerator
- msi-parent : phandle for "ti,sci-inta" interrupt controller
Optional properties:
-- ti,dma-ring-reset-quirk : enable ringacc / udma ring state interoperability
issue software w/a
Example:
ringacc: ringacc@3c000000 {
compatible = "ti,am654-navss-ringacc";
reg = <0x0 0x3c000000 0x0 0x400000>,
<0x0 0x38000000 0x0 0x400000>,
<0x0 0x31120000 0x0 0x100>,
<0x0 0x33000000 0x0 0x40000>;
reg-names = "rt", "fifos",
"proxy_gcfg", "proxy_target";
ti,num-rings = <818>;
ti,sci-rm-range-gp-rings = <0x2>; /* GP ring range */
ti,dma-ring-reset-quirk;
ti,sci = <&dmsc>;
ti,sci-dev-id = <187>;
msi-parent = <&inta_main_udmass>;
};
client:
dma_ipx: dma_ipx@<addr> {
...
ti,ringacc = <&ringacc>;
...
}
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
%YAML 1.2
---
$id: "http://devicetree.org/schemas/soc/ti/k3-ringacc.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Texas Instruments K3 NavigatorSS Ring Accelerator
maintainers:
- Santosh Shilimkar <ssantosh@kernel.org>
- Grygorii Strashko <grygorii.strashko@ti.com>
description: |
The Ring Accelerator (RA) is a machine which converts read/write accesses
from/to a constant address into corresponding read/write accesses from/to a
circular data structure in memory. The RA eliminates the need for each DMA
controller which needs to access ring elements from having to know the current
state of the ring (base address, current offset). The DMA controller
performs a read or write access to a specific address range (which maps to the
source interface on the RA) and the RA replaces the address for the transaction
with a new address which corresponds to the head or tail element of the ring
(head for reads, tail for writes).
The Ring Accelerator is a hardware module that is responsible for accelerating
management of the packet queues. The K3 SoCs can have more than one RA instances
properties:
compatible:
items:
- const: ti,am654-navss-ringacc
reg:
items:
- description: real time registers regions
- description: fifos registers regions
- description: proxy gcfg registers regions
- description: proxy target registers regions
reg-names:
items:
- const: rt
- const: fifos
- const: proxy_gcfg
- const: proxy_target
msi-parent: true
ti,num-rings:
$ref: /schemas/types.yaml#/definitions/uint32
description: Number of rings supported by RA
ti,sci-rm-range-gp-rings:
$ref: /schemas/types.yaml#/definitions/uint32
description: TI-SCI RM subtype for GP ring range
ti,sci:
$ref: /schemas/types.yaml#definitions/phandle-array
description: phandle on TI-SCI compatible System controller node
ti,sci-dev-id:
$ref: /schemas/types.yaml#/definitions/uint32
description: TI-SCI device id of the ring accelerator
ti,dma-ring-reset-quirk:
$ref: /schemas/types.yaml#definitions/flag
description: |
enable ringacc/udma ring state interoperability issue software w/a
required:
- compatible
- reg
- reg-names
- msi-parent
- ti,num-rings
- ti,sci-rm-range-gp-rings
- ti,sci
- ti,sci-dev-id
additionalProperties: false
examples:
- |
bus {
#address-cells = <2>;
#size-cells = <2>;
ringacc: ringacc@3c000000 {
compatible = "ti,am654-navss-ringacc";
reg = <0x0 0x3c000000 0x0 0x400000>,
<0x0 0x38000000 0x0 0x400000>,
<0x0 0x31120000 0x0 0x100>,
<0x0 0x33000000 0x0 0x40000>;
reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target";
ti,num-rings = <818>;
ti,sci-rm-range-gp-rings = <0x2>; /* GP ring range */
ti,dma-ring-reset-quirk;
ti,sci = <&dmsc>;
ti,sci-dev-id = <187>;
msi-parent = <&inta_main_udmass>;
};
};
...@@ -11117,6 +11117,14 @@ F: Documentation/core-api/boot-time-mm.rst ...@@ -11117,6 +11117,14 @@ F: Documentation/core-api/boot-time-mm.rst
F: include/linux/memblock.h F: include/linux/memblock.h
F: mm/memblock.c F: mm/memblock.c
MEMORY CONTROLLER DRIVERS
M: Krzysztof Kozlowski <krzk@kernel.org>
L: linux-kernel@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl.git
F: Documentation/devicetree/bindings/memory-controllers/
F: drivers/memory/
MEMORY MANAGEMENT MEMORY MANAGEMENT
M: Andrew Morton <akpm@linux-foundation.org> M: Andrew Morton <akpm@linux-foundation.org>
L: linux-mm@kvack.org L: linux-mm@kvack.org
...@@ -12729,6 +12737,7 @@ OP-TEE DRIVER ...@@ -12729,6 +12737,7 @@ OP-TEE DRIVER
M: Jens Wiklander <jens.wiklander@linaro.org> M: Jens Wiklander <jens.wiklander@linaro.org>
L: op-tee@lists.trustedfirmware.org L: op-tee@lists.trustedfirmware.org
S: Maintained S: Maintained
F: Documentation/ABI/testing/sysfs-bus-optee-devices
F: drivers/tee/optee/ F: drivers/tee/optee/
OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER
......
...@@ -118,6 +118,7 @@ config SOC_EXYNOS5800 ...@@ -118,6 +118,7 @@ config SOC_EXYNOS5800
bool "Samsung EXYNOS5800" bool "Samsung EXYNOS5800"
default y default y
depends on SOC_EXYNOS5420 depends on SOC_EXYNOS5420
select EXYNOS_REGULATOR_COUPLER
config EXYNOS_MCPM config EXYNOS_MCPM
bool bool
......
...@@ -775,19 +775,23 @@ static const char * __init omap_get_family(void) ...@@ -775,19 +775,23 @@ static const char * __init omap_get_family(void)
return kasprintf(GFP_KERNEL, "Unknown"); return kasprintf(GFP_KERNEL, "Unknown");
} }
static ssize_t omap_get_type(struct device *dev, static ssize_t
struct device_attribute *attr, type_show(struct device *dev, struct device_attribute *attr, char *buf)
char *buf)
{ {
return sprintf(buf, "%s\n", omap_types[omap_type()]); return sprintf(buf, "%s\n", omap_types[omap_type()]);
} }
static struct device_attribute omap_soc_attr = static DEVICE_ATTR_RO(type);
__ATTR(type, S_IRUGO, omap_get_type, NULL);
static struct attribute *omap_soc_attrs[] = {
&dev_attr_type.attr,
NULL
};
ATTRIBUTE_GROUPS(omap_soc);
void __init omap_soc_device_init(void) void __init omap_soc_device_init(void)
{ {
struct device *parent;
struct soc_device *soc_dev; struct soc_device *soc_dev;
struct soc_device_attribute *soc_dev_attr; struct soc_device_attribute *soc_dev_attr;
...@@ -798,14 +802,12 @@ void __init omap_soc_device_init(void) ...@@ -798,14 +802,12 @@ void __init omap_soc_device_init(void)
soc_dev_attr->machine = soc_name; soc_dev_attr->machine = soc_name;
soc_dev_attr->family = omap_get_family(); soc_dev_attr->family = omap_get_family();
soc_dev_attr->revision = soc_rev; soc_dev_attr->revision = soc_rev;
soc_dev_attr->custom_attr_group = omap_soc_groups[0];
soc_dev = soc_device_register(soc_dev_attr); soc_dev = soc_device_register(soc_dev_attr);
if (IS_ERR(soc_dev)) { if (IS_ERR(soc_dev)) {
kfree(soc_dev_attr); kfree(soc_dev_attr);
return; return;
} }
parent = soc_device_to_device(soc_dev);
device_create_file(parent, &omap_soc_attr);
} }
#endif /* CONFIG_SOC_BUS */ #endif /* CONFIG_SOC_BUS */
...@@ -881,7 +881,6 @@ CONFIG_OWL_PM_DOMAINS=y ...@@ -881,7 +881,6 @@ CONFIG_OWL_PM_DOMAINS=y
CONFIG_RASPBERRYPI_POWER=y CONFIG_RASPBERRYPI_POWER=y
CONFIG_FSL_DPAA=y CONFIG_FSL_DPAA=y
CONFIG_FSL_MC_DPIO=y CONFIG_FSL_MC_DPIO=y
CONFIG_IMX_SCU_SOC=y
CONFIG_QCOM_AOSS_QMP=y CONFIG_QCOM_AOSS_QMP=y
CONFIG_QCOM_GENI_SE=y CONFIG_QCOM_GENI_SE=y
CONFIG_QCOM_RMTFS_MEM=m CONFIG_QCOM_RMTFS_MEM=m
......
...@@ -214,11 +214,10 @@ static int ftpm_tee_match(struct tee_ioctl_version_data *ver, const void *data) ...@@ -214,11 +214,10 @@ static int ftpm_tee_match(struct tee_ioctl_version_data *ver, const void *data)
* Return: * Return:
* On success, 0. On failure, -errno. * On success, 0. On failure, -errno.
*/ */
static int ftpm_tee_probe(struct platform_device *pdev) static int ftpm_tee_probe(struct device *dev)
{ {
int rc; int rc;
struct tpm_chip *chip; struct tpm_chip *chip;
struct device *dev = &pdev->dev;
struct ftpm_tee_private *pvt_data = NULL; struct ftpm_tee_private *pvt_data = NULL;
struct tee_ioctl_open_session_arg sess_arg; struct tee_ioctl_open_session_arg sess_arg;
...@@ -297,6 +296,13 @@ static int ftpm_tee_probe(struct platform_device *pdev) ...@@ -297,6 +296,13 @@ static int ftpm_tee_probe(struct platform_device *pdev)
return rc; return rc;
} }
static int ftpm_plat_tee_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
return ftpm_tee_probe(dev);
}
/** /**
* ftpm_tee_remove() - remove the TPM device * ftpm_tee_remove() - remove the TPM device
* @pdev: the platform_device description. * @pdev: the platform_device description.
...@@ -304,9 +310,9 @@ static int ftpm_tee_probe(struct platform_device *pdev) ...@@ -304,9 +310,9 @@ static int ftpm_tee_probe(struct platform_device *pdev)
* Return: * Return:
* 0 always. * 0 always.
*/ */
static int ftpm_tee_remove(struct platform_device *pdev) static int ftpm_tee_remove(struct device *dev)
{ {
struct ftpm_tee_private *pvt_data = dev_get_drvdata(&pdev->dev); struct ftpm_tee_private *pvt_data = dev_get_drvdata(dev);
/* Release the chip */ /* Release the chip */
tpm_chip_unregister(pvt_data->chip); tpm_chip_unregister(pvt_data->chip);
...@@ -328,11 +334,18 @@ static int ftpm_tee_remove(struct platform_device *pdev) ...@@ -328,11 +334,18 @@ static int ftpm_tee_remove(struct platform_device *pdev)
return 0; return 0;
} }
static int ftpm_plat_tee_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
return ftpm_tee_remove(dev);
}
/** /**
* ftpm_tee_shutdown() - shutdown the TPM device * ftpm_tee_shutdown() - shutdown the TPM device
* @pdev: the platform_device description. * @pdev: the platform_device description.
*/ */
static void ftpm_tee_shutdown(struct platform_device *pdev) static void ftpm_plat_tee_shutdown(struct platform_device *pdev)
{ {
struct ftpm_tee_private *pvt_data = dev_get_drvdata(&pdev->dev); struct ftpm_tee_private *pvt_data = dev_get_drvdata(&pdev->dev);
...@@ -347,17 +360,54 @@ static const struct of_device_id of_ftpm_tee_ids[] = { ...@@ -347,17 +360,54 @@ static const struct of_device_id of_ftpm_tee_ids[] = {
}; };
MODULE_DEVICE_TABLE(of, of_ftpm_tee_ids); MODULE_DEVICE_TABLE(of, of_ftpm_tee_ids);
static struct platform_driver ftpm_tee_driver = { static struct platform_driver ftpm_tee_plat_driver = {
.driver = { .driver = {
.name = "ftpm-tee", .name = "ftpm-tee",
.of_match_table = of_match_ptr(of_ftpm_tee_ids), .of_match_table = of_match_ptr(of_ftpm_tee_ids),
}, },
.probe = ftpm_tee_probe, .shutdown = ftpm_plat_tee_shutdown,
.remove = ftpm_tee_remove, .probe = ftpm_plat_tee_probe,
.shutdown = ftpm_tee_shutdown, .remove = ftpm_plat_tee_remove,
};
/* UUID of the fTPM TA */
static const struct tee_client_device_id optee_ftpm_id_table[] = {
{UUID_INIT(0xbc50d971, 0xd4c9, 0x42c4,
0x82, 0xcb, 0x34, 0x3f, 0xb7, 0xf3, 0x78, 0x96)},
{}
}; };
module_platform_driver(ftpm_tee_driver); MODULE_DEVICE_TABLE(tee, optee_ftpm_id_table);
static struct tee_client_driver ftpm_tee_driver = {
.id_table = optee_ftpm_id_table,
.driver = {
.name = "optee-ftpm",
.bus = &tee_bus_type,
.probe = ftpm_tee_probe,
.remove = ftpm_tee_remove,
},
};
static int __init ftpm_mod_init(void)
{
int rc;
rc = platform_driver_register(&ftpm_tee_plat_driver);
if (rc)
return rc;
return driver_register(&ftpm_tee_driver.driver);
}
static void __exit ftpm_mod_exit(void)
{
platform_driver_unregister(&ftpm_tee_plat_driver);
driver_unregister(&ftpm_tee_driver.driver);
}
module_init(ftpm_mod_init);
module_exit(ftpm_mod_exit);
MODULE_AUTHOR("Thirupathaiah Annapureddy <thiruan@microsoft.com>"); MODULE_AUTHOR("Thirupathaiah Annapureddy <thiruan@microsoft.com>");
MODULE_DESCRIPTION("TPM Driver for fTPM TA in TEE"); MODULE_DESCRIPTION("TPM Driver for fTPM TA in TEE");
......
...@@ -103,6 +103,8 @@ static const struct clk_ops scmi_clk_ops = { ...@@ -103,6 +103,8 @@ static const struct clk_ops scmi_clk_ops = {
static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk) static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk)
{ {
int ret; int ret;
unsigned long min_rate, max_rate;
struct clk_init_data init = { struct clk_init_data init = {
.flags = CLK_GET_RATE_NOCACHE, .flags = CLK_GET_RATE_NOCACHE,
.num_parents = 0, .num_parents = 0,
...@@ -112,9 +114,23 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk) ...@@ -112,9 +114,23 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk)
sclk->hw.init = &init; sclk->hw.init = &init;
ret = devm_clk_hw_register(dev, &sclk->hw); ret = devm_clk_hw_register(dev, &sclk->hw);
if (!ret) if (ret)
clk_hw_set_rate_range(&sclk->hw, sclk->info->range.min_rate, return ret;
sclk->info->range.max_rate);
if (sclk->info->rate_discrete) {
int num_rates = sclk->info->list.num_rates;
if (num_rates <= 0)
return -EINVAL;
min_rate = sclk->info->list.rates[0];
max_rate = sclk->info->list.rates[num_rates - 1];
} else {
min_rate = sclk->info->range.min_rate;
max_rate = sclk->info->range.max_rate;
}
clk_hw_set_rate_range(&sclk->hw, min_rate, max_rate);
return ret; return ret;
} }
......
...@@ -198,7 +198,8 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) ...@@ -198,7 +198,8 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = latency; policy->cpuinfo.transition_latency = latency;
policy->fast_switch_possible = true; policy->fast_switch_possible =
handle->perf_ops->fast_switch_possible(handle, cpu_dev);
em_register_perf_domain(policy->cpus, nr_opp, &em_cb); em_register_perf_domain(policy->cpus, nr_opp, &em_cb);
......
...@@ -271,20 +271,12 @@ struct k3_udma_glue_tx_channel *k3_udma_glue_request_tx_chn(struct device *dev, ...@@ -271,20 +271,12 @@ struct k3_udma_glue_tx_channel *k3_udma_glue_request_tx_chn(struct device *dev,
atomic_set(&tx_chn->free_pkts, cfg->txcq_cfg.size); atomic_set(&tx_chn->free_pkts, cfg->txcq_cfg.size);
/* request and cfg rings */ /* request and cfg rings */
tx_chn->ringtx = k3_ringacc_request_ring(tx_chn->common.ringacc, ret = k3_ringacc_request_rings_pair(tx_chn->common.ringacc,
tx_chn->udma_tchan_id, 0); tx_chn->udma_tchan_id, -1,
if (!tx_chn->ringtx) { &tx_chn->ringtx,
ret = -ENODEV; &tx_chn->ringtxcq);
dev_err(dev, "Failed to get TX ring %u\n", if (ret) {
tx_chn->udma_tchan_id); dev_err(dev, "Failed to get TX/TXCQ rings %d\n", ret);
goto err;
}
tx_chn->ringtxcq = k3_ringacc_request_ring(tx_chn->common.ringacc,
-1, 0);
if (!tx_chn->ringtxcq) {
ret = -ENODEV;
dev_err(dev, "Failed to get TXCQ ring\n");
goto err; goto err;
} }
...@@ -587,22 +579,16 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn, ...@@ -587,22 +579,16 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn,
} }
/* request and cfg rings */ /* request and cfg rings */
flow->ringrx = k3_ringacc_request_ring(rx_chn->common.ringacc, ret = k3_ringacc_request_rings_pair(rx_chn->common.ringacc,
flow_cfg->ring_rxq_id, 0); flow_cfg->ring_rxq_id,
if (!flow->ringrx) { flow_cfg->ring_rxfdq0_id,
ret = -ENODEV; &flow->ringrxfdq,
dev_err(dev, "Failed to get RX ring\n"); &flow->ringrx);
if (ret) {
dev_err(dev, "Failed to get RX/RXFDQ rings %d\n", ret);
goto err_rflow_put; goto err_rflow_put;
} }
flow->ringrxfdq = k3_ringacc_request_ring(rx_chn->common.ringacc,
flow_cfg->ring_rxfdq0_id, 0);
if (!flow->ringrxfdq) {
ret = -ENODEV;
dev_err(dev, "Failed to get RXFDQ ring\n");
goto err_ringrx_free;
}
ret = k3_ringacc_ring_cfg(flow->ringrx, &flow_cfg->rx_cfg); ret = k3_ringacc_ring_cfg(flow->ringrx, &flow_cfg->rx_cfg);
if (ret) { if (ret) {
dev_err(dev, "Failed to cfg ringrx %d\n", ret); dev_err(dev, "Failed to cfg ringrx %d\n", ret);
...@@ -673,8 +659,6 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn, ...@@ -673,8 +659,6 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn,
err_ringrxfdq_free: err_ringrxfdq_free:
k3_ringacc_ring_free(flow->ringrxfdq); k3_ringacc_ring_free(flow->ringrxfdq);
err_ringrx_free:
k3_ringacc_ring_free(flow->ringrx); k3_ringacc_ring_free(flow->ringrx);
err_rflow_put: err_rflow_put:
......
...@@ -1418,17 +1418,12 @@ static int udma_alloc_tx_resources(struct udma_chan *uc) ...@@ -1418,17 +1418,12 @@ static int udma_alloc_tx_resources(struct udma_chan *uc)
if (ret) if (ret)
return ret; return ret;
uc->tchan->t_ring = k3_ringacc_request_ring(ud->ringacc, ret = k3_ringacc_request_rings_pair(ud->ringacc, uc->tchan->id, -1,
uc->tchan->id, 0); &uc->tchan->t_ring,
if (!uc->tchan->t_ring) { &uc->tchan->tc_ring);
ret = -EBUSY; if (ret) {
goto err_tx_ring;
}
uc->tchan->tc_ring = k3_ringacc_request_ring(ud->ringacc, -1, 0);
if (!uc->tchan->tc_ring) {
ret = -EBUSY; ret = -EBUSY;
goto err_txc_ring; goto err_ring;
} }
memset(&ring_cfg, 0, sizeof(ring_cfg)); memset(&ring_cfg, 0, sizeof(ring_cfg));
...@@ -1447,10 +1442,9 @@ static int udma_alloc_tx_resources(struct udma_chan *uc) ...@@ -1447,10 +1442,9 @@ static int udma_alloc_tx_resources(struct udma_chan *uc)
err_ringcfg: err_ringcfg:
k3_ringacc_ring_free(uc->tchan->tc_ring); k3_ringacc_ring_free(uc->tchan->tc_ring);
uc->tchan->tc_ring = NULL; uc->tchan->tc_ring = NULL;
err_txc_ring:
k3_ringacc_ring_free(uc->tchan->t_ring); k3_ringacc_ring_free(uc->tchan->t_ring);
uc->tchan->t_ring = NULL; uc->tchan->t_ring = NULL;
err_tx_ring: err_ring:
udma_put_tchan(uc); udma_put_tchan(uc);
return ret; return ret;
...@@ -1499,16 +1493,11 @@ static int udma_alloc_rx_resources(struct udma_chan *uc) ...@@ -1499,16 +1493,11 @@ static int udma_alloc_rx_resources(struct udma_chan *uc)
rflow = uc->rflow; rflow = uc->rflow;
fd_ring_id = ud->tchan_cnt + ud->echan_cnt + uc->rchan->id; fd_ring_id = ud->tchan_cnt + ud->echan_cnt + uc->rchan->id;
rflow->fd_ring = k3_ringacc_request_ring(ud->ringacc, fd_ring_id, 0); ret = k3_ringacc_request_rings_pair(ud->ringacc, fd_ring_id, -1,
if (!rflow->fd_ring) { &rflow->fd_ring, &rflow->r_ring);
ret = -EBUSY; if (ret) {
goto err_rx_ring;
}
rflow->r_ring = k3_ringacc_request_ring(ud->ringacc, -1, 0);
if (!rflow->r_ring) {
ret = -EBUSY; ret = -EBUSY;
goto err_rxc_ring; goto err_ring;
} }
memset(&ring_cfg, 0, sizeof(ring_cfg)); memset(&ring_cfg, 0, sizeof(ring_cfg));
...@@ -1533,10 +1522,9 @@ static int udma_alloc_rx_resources(struct udma_chan *uc) ...@@ -1533,10 +1522,9 @@ static int udma_alloc_rx_resources(struct udma_chan *uc)
err_ringcfg: err_ringcfg:
k3_ringacc_ring_free(rflow->r_ring); k3_ringacc_ring_free(rflow->r_ring);
rflow->r_ring = NULL; rflow->r_ring = NULL;
err_rxc_ring:
k3_ringacc_ring_free(rflow->fd_ring); k3_ringacc_ring_free(rflow->fd_ring);
rflow->fd_ring = NULL; rflow->fd_ring = NULL;
err_rx_ring: err_ring:
udma_put_rflow(uc); udma_put_rflow(uc);
err_rflow: err_rflow:
udma_put_rchan(uc); udma_put_rchan(uc);
......
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o
scmi-bus-y = bus.o scmi-bus-y = bus.o
scmi-driver-y = driver.o scmi-driver-y = driver.o notify.o
scmi-transport-y = shmem.o scmi-transport-y = shmem.o
scmi-transport-$(CONFIG_MAILBOX) += mailbox.o scmi-transport-$(CONFIG_MAILBOX) += mailbox.o
scmi-transport-$(CONFIG_ARM_PSCI_FW) += smc.o scmi-transport-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smc.o
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
...@@ -5,7 +5,15 @@ ...@@ -5,7 +5,15 @@
* Copyright (C) 2018 ARM Ltd. * Copyright (C) 2018 ARM Ltd.
*/ */
#define pr_fmt(fmt) "SCMI Notifications BASE - " fmt
#include <linux/scmi_protocol.h>
#include "common.h" #include "common.h"
#include "notify.h"
#define SCMI_BASE_NUM_SOURCES 1
#define SCMI_BASE_MAX_CMD_ERR_COUNT 1024
enum scmi_base_protocol_cmd { enum scmi_base_protocol_cmd {
BASE_DISCOVER_VENDOR = 0x3, BASE_DISCOVER_VENDOR = 0x3,
...@@ -19,16 +27,25 @@ enum scmi_base_protocol_cmd { ...@@ -19,16 +27,25 @@ enum scmi_base_protocol_cmd {
BASE_RESET_AGENT_CONFIGURATION = 0xb, BASE_RESET_AGENT_CONFIGURATION = 0xb,
}; };
enum scmi_base_protocol_notify {
BASE_ERROR_EVENT = 0x0,
};
struct scmi_msg_resp_base_attributes { struct scmi_msg_resp_base_attributes {
u8 num_protocols; u8 num_protocols;
u8 num_agents; u8 num_agents;
__le16 reserved; __le16 reserved;
}; };
struct scmi_msg_base_error_notify {
__le32 event_control;
#define BASE_TP_NOTIFY_ALL BIT(0)
};
struct scmi_base_error_notify_payld {
__le32 agent_id;
__le32 error_status;
#define IS_FATAL_ERROR(x) ((x) & BIT(31))
#define ERROR_CMD_COUNT(x) FIELD_GET(GENMASK(9, 0), (x))
__le64 msg_reports[SCMI_BASE_MAX_CMD_ERR_COUNT];
};
/** /**
* scmi_base_attributes_get() - gets the implementation details * scmi_base_attributes_get() - gets the implementation details
* that are associated with the base protocol. * that are associated with the base protocol.
...@@ -222,6 +239,83 @@ static int scmi_base_discover_agent_get(const struct scmi_handle *handle, ...@@ -222,6 +239,83 @@ static int scmi_base_discover_agent_get(const struct scmi_handle *handle,
return ret; return ret;
} }
static int scmi_base_error_notify(const struct scmi_handle *handle, bool enable)
{
int ret;
u32 evt_cntl = enable ? BASE_TP_NOTIFY_ALL : 0;
struct scmi_xfer *t;
struct scmi_msg_base_error_notify *cfg;
ret = scmi_xfer_get_init(handle, BASE_NOTIFY_ERRORS,
SCMI_PROTOCOL_BASE, sizeof(*cfg), 0, &t);
if (ret)
return ret;
cfg = t->tx.buf;
cfg->event_control = cpu_to_le32(evt_cntl);
ret = scmi_do_xfer(handle, t);
scmi_xfer_put(handle, t);
return ret;
}
static int scmi_base_set_notify_enabled(const struct scmi_handle *handle,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
ret = scmi_base_error_notify(handle, enable);
if (ret)
pr_debug("FAIL_ENABLED - evt[%X] ret:%d\n", evt_id, ret);
return ret;
}
static void *scmi_base_fill_custom_report(const struct scmi_handle *handle,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
{
int i;
const struct scmi_base_error_notify_payld *p = payld;
struct scmi_base_error_report *r = report;
/*
* BaseError notification payload is variable in size but
* up to a maximum length determined by the struct ponted by p.
* Instead payld_sz is the effective length of this notification
* payload so cannot be greater of the maximum allowed size as
* pointed by p.
*/
if (evt_id != SCMI_EVENT_BASE_ERROR_EVENT || sizeof(*p) < payld_sz)
return NULL;
r->timestamp = timestamp;
r->agent_id = le32_to_cpu(p->agent_id);
r->fatal = IS_FATAL_ERROR(le32_to_cpu(p->error_status));
r->cmd_count = ERROR_CMD_COUNT(le32_to_cpu(p->error_status));
for (i = 0; i < r->cmd_count; i++)
r->reports[i] = le64_to_cpu(p->msg_reports[i]);
*src_id = 0;
return r;
}
static const struct scmi_event base_events[] = {
{
.id = SCMI_EVENT_BASE_ERROR_EVENT,
.max_payld_sz = sizeof(struct scmi_base_error_notify_payld),
.max_report_sz = sizeof(struct scmi_base_error_report) +
SCMI_BASE_MAX_CMD_ERR_COUNT * sizeof(u64),
},
};
static const struct scmi_event_ops base_event_ops = {
.set_notify_enabled = scmi_base_set_notify_enabled,
.fill_custom_report = scmi_base_fill_custom_report,
};
int scmi_base_protocol_init(struct scmi_handle *h) int scmi_base_protocol_init(struct scmi_handle *h)
{ {
int id, ret; int id, ret;
...@@ -256,6 +350,12 @@ int scmi_base_protocol_init(struct scmi_handle *h) ...@@ -256,6 +350,12 @@ int scmi_base_protocol_init(struct scmi_handle *h)
dev_dbg(dev, "Found %d protocol(s) %d agent(s)\n", rev->num_protocols, dev_dbg(dev, "Found %d protocol(s) %d agent(s)\n", rev->num_protocols,
rev->num_agents); rev->num_agents);
scmi_register_protocol_events(handle, SCMI_PROTOCOL_BASE,
(4 * SCMI_PROTO_QUEUE_SZ),
&base_event_ops, base_events,
ARRAY_SIZE(base_events),
SCMI_BASE_NUM_SOURCES);
for (id = 0; id < rev->num_agents; id++) { for (id = 0; id < rev->num_agents; id++) {
scmi_base_discover_agent_get(handle, id, name); scmi_base_discover_agent_get(handle, id, name);
dev_dbg(dev, "Agent %d: %s\n", id, name); dev_dbg(dev, "Agent %d: %s\n", id, name);
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
* Copyright (C) 2018 ARM Ltd. * Copyright (C) 2018 ARM Ltd.
*/ */
#include <linux/sort.h>
#include "common.h" #include "common.h"
enum scmi_clock_protocol_cmd { enum scmi_clock_protocol_cmd {
...@@ -121,11 +123,23 @@ static int scmi_clock_attributes_get(const struct scmi_handle *handle, ...@@ -121,11 +123,23 @@ static int scmi_clock_attributes_get(const struct scmi_handle *handle,
return ret; return ret;
} }
static int rate_cmp_func(const void *_r1, const void *_r2)
{
const u64 *r1 = _r1, *r2 = _r2;
if (*r1 < *r2)
return -1;
else if (*r1 == *r2)
return 0;
else
return 1;
}
static int static int
scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
struct scmi_clock_info *clk) struct scmi_clock_info *clk)
{ {
u64 *rate; u64 *rate = NULL;
int ret, cnt; int ret, cnt;
bool rate_discrete = false; bool rate_discrete = false;
u32 tot_rate_cnt = 0, rates_flag; u32 tot_rate_cnt = 0, rates_flag;
...@@ -184,8 +198,10 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, ...@@ -184,8 +198,10 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
*/ */
} while (num_returned && num_remaining); } while (num_returned && num_remaining);
if (rate_discrete) if (rate_discrete && rate) {
clk->list.num_rates = tot_rate_cnt; clk->list.num_rates = tot_rate_cnt;
sort(rate, tot_rate_cnt, sizeof(*rate), rate_cmp_func, NULL);
}
clk->rate_discrete = rate_discrete; clk->rate_discrete = rate_discrete;
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
* *
* Copyright (C) 2018 ARM Ltd. * Copyright (C) 2018 ARM Ltd.
*/ */
#ifndef _SCMI_COMMON_H
#define _SCMI_COMMON_H
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/completion.h> #include <linux/completion.h>
...@@ -235,3 +237,5 @@ void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, ...@@ -235,3 +237,5 @@ void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem,
void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem); void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem);
bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
struct scmi_xfer *xfer); struct scmi_xfer *xfer);
#endif /* _SCMI_COMMON_H */
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include "common.h" #include "common.h"
#include "notify.h"
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/scmi.h> #include <trace/events/scmi.h>
...@@ -208,7 +209,9 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo, u32 msg_hdr) ...@@ -208,7 +209,9 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo, u32 msg_hdr)
struct device *dev = cinfo->dev; struct device *dev = cinfo->dev;
struct scmi_info *info = handle_to_scmi_info(cinfo->handle); struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
struct scmi_xfers_info *minfo = &info->rx_minfo; struct scmi_xfers_info *minfo = &info->rx_minfo;
ktime_t ts;
ts = ktime_get_boottime();
xfer = scmi_xfer_get(cinfo->handle, minfo); xfer = scmi_xfer_get(cinfo->handle, minfo);
if (IS_ERR(xfer)) { if (IS_ERR(xfer)) {
dev_err(dev, "failed to get free message slot (%ld)\n", dev_err(dev, "failed to get free message slot (%ld)\n",
...@@ -221,6 +224,8 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo, u32 msg_hdr) ...@@ -221,6 +224,8 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo, u32 msg_hdr)
scmi_dump_header_dbg(dev, &xfer->hdr); scmi_dump_header_dbg(dev, &xfer->hdr);
info->desc->ops->fetch_notification(cinfo, info->desc->max_msg_size, info->desc->ops->fetch_notification(cinfo, info->desc->max_msg_size,
xfer); xfer);
scmi_notify(cinfo->handle, xfer->hdr.protocol_id,
xfer->hdr.id, xfer->rx.buf, xfer->rx.len, ts);
trace_scmi_rx_done(xfer->transfer_id, xfer->hdr.id, trace_scmi_rx_done(xfer->transfer_id, xfer->hdr.id,
xfer->hdr.protocol_id, xfer->hdr.seq, xfer->hdr.protocol_id, xfer->hdr.seq,
...@@ -392,8 +397,7 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) ...@@ -392,8 +397,7 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer)
info->desc->ops->mark_txdone(cinfo, ret); info->desc->ops->mark_txdone(cinfo, ret);
trace_scmi_xfer_end(xfer->transfer_id, xfer->hdr.id, trace_scmi_xfer_end(xfer->transfer_id, xfer->hdr.id,
xfer->hdr.protocol_id, xfer->hdr.seq, xfer->hdr.protocol_id, xfer->hdr.seq, ret);
xfer->hdr.status);
return ret; return ret;
} }
...@@ -789,6 +793,9 @@ static int scmi_probe(struct platform_device *pdev) ...@@ -789,6 +793,9 @@ static int scmi_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
if (scmi_notification_init(handle))
dev_err(dev, "SCMI Notifications NOT available.\n");
ret = scmi_base_protocol_init(handle); ret = scmi_base_protocol_init(handle);
if (ret) { if (ret) {
dev_err(dev, "unable to communicate with SCMI(%d)\n", ret); dev_err(dev, "unable to communicate with SCMI(%d)\n", ret);
...@@ -831,6 +838,8 @@ static int scmi_remove(struct platform_device *pdev) ...@@ -831,6 +838,8 @@ static int scmi_remove(struct platform_device *pdev)
struct scmi_info *info = platform_get_drvdata(pdev); struct scmi_info *info = platform_get_drvdata(pdev);
struct idr *idr = &info->tx_idr; struct idr *idr = &info->tx_idr;
scmi_notification_exit(&info->handle);
mutex_lock(&scmi_list_mutex); mutex_lock(&scmi_list_mutex);
if (info->users) if (info->users)
ret = -EBUSY; ret = -EBUSY;
...@@ -901,7 +910,7 @@ ATTRIBUTE_GROUPS(versions); ...@@ -901,7 +910,7 @@ ATTRIBUTE_GROUPS(versions);
/* Each compatible listed below must have descriptor associated with it */ /* Each compatible listed below must have descriptor associated with it */
static const struct of_device_id scmi_of_match[] = { static const struct of_device_id scmi_of_match[] = {
{ .compatible = "arm,scmi", .data = &scmi_mailbox_desc }, { .compatible = "arm,scmi", .data = &scmi_mailbox_desc },
#ifdef CONFIG_ARM_PSCI_FW #ifdef CONFIG_HAVE_ARM_SMCCC_DISCOVERY
{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc}, { .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
#endif #endif
{ /* Sentinel */ }, { /* Sentinel */ },
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* System Control and Management Interface (SCMI) Message Protocol
* notification header file containing some definitions, structures
* and function prototypes related to SCMI Notification handling.
*
* Copyright (C) 2020 ARM Ltd.
*/
#ifndef _SCMI_NOTIFY_H
#define _SCMI_NOTIFY_H
#include <linux/device.h>
#include <linux/ktime.h>
#include <linux/types.h>
#define SCMI_PROTO_QUEUE_SZ 4096
/**
* struct scmi_event - Describes an event to be supported
* @id: Event ID
* @max_payld_sz: Max possible size for the payload of a notification message
* @max_report_sz: Max possible size for the report of a notification message
*
* Each SCMI protocol, during its initialization phase, can describe the events
* it wishes to support in a few struct scmi_event and pass them to the core
* using scmi_register_protocol_events().
*/
struct scmi_event {
u8 id;
size_t max_payld_sz;
size_t max_report_sz;
};
/**
* struct scmi_event_ops - Protocol helpers called by the notification core.
* @set_notify_enabled: Enable/disable the required evt_id/src_id notifications
* using the proper custom protocol commands.
* Return 0 on Success
* @fill_custom_report: fills a custom event report from the provided
* event message payld identifying the event
* specific src_id.
* Return NULL on failure otherwise @report now fully
* populated
*
* Context: Helpers described in &struct scmi_event_ops are called only in
* process context.
*/
struct scmi_event_ops {
int (*set_notify_enabled)(const struct scmi_handle *handle,
u8 evt_id, u32 src_id, bool enabled);
void *(*fill_custom_report)(const struct scmi_handle *handle,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id);
};
int scmi_notification_init(struct scmi_handle *handle);
void scmi_notification_exit(struct scmi_handle *handle);
int scmi_register_protocol_events(const struct scmi_handle *handle,
u8 proto_id, size_t queue_sz,
const struct scmi_event_ops *ops,
const struct scmi_event *evt, int num_events,
int num_sources);
int scmi_notify(const struct scmi_handle *handle, u8 proto_id, u8 evt_id,
const void *buf, size_t len, ktime_t ts);
#endif /* _SCMI_NOTIFY_H */
...@@ -5,15 +5,19 @@ ...@@ -5,15 +5,19 @@
* Copyright (C) 2018 ARM Ltd. * Copyright (C) 2018 ARM Ltd.
*/ */
#define pr_fmt(fmt) "SCMI Notifications PERF - " fmt
#include <linux/bits.h> #include <linux/bits.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/io-64-nonatomic-hi-lo.h> #include <linux/io-64-nonatomic-hi-lo.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_opp.h> #include <linux/pm_opp.h>
#include <linux/scmi_protocol.h>
#include <linux/sort.h> #include <linux/sort.h>
#include "common.h" #include "common.h"
#include "notify.h"
enum scmi_performance_protocol_cmd { enum scmi_performance_protocol_cmd {
PERF_DOMAIN_ATTRIBUTES = 0x3, PERF_DOMAIN_ATTRIBUTES = 0x3,
...@@ -27,11 +31,6 @@ enum scmi_performance_protocol_cmd { ...@@ -27,11 +31,6 @@ enum scmi_performance_protocol_cmd {
PERF_DESCRIBE_FASTCHANNEL = 0xb, PERF_DESCRIBE_FASTCHANNEL = 0xb,
}; };
enum scmi_performance_protocol_notify {
PERFORMANCE_LIMITS_CHANGED = 0x0,
PERFORMANCE_LEVEL_CHANGED = 0x1,
};
struct scmi_opp { struct scmi_opp {
u32 perf; u32 perf;
u32 power; u32 power;
...@@ -86,6 +85,19 @@ struct scmi_perf_notify_level_or_limits { ...@@ -86,6 +85,19 @@ struct scmi_perf_notify_level_or_limits {
__le32 notify_enable; __le32 notify_enable;
}; };
struct scmi_perf_limits_notify_payld {
__le32 agent_id;
__le32 domain_id;
__le32 range_max;
__le32 range_min;
};
struct scmi_perf_level_notify_payld {
__le32 agent_id;
__le32 domain_id;
__le32 performance_level;
};
struct scmi_msg_resp_perf_describe_levels { struct scmi_msg_resp_perf_describe_levels {
__le16 num_returned; __le16 num_returned;
__le16 num_remaining; __le16 num_remaining;
...@@ -158,6 +170,11 @@ struct scmi_perf_info { ...@@ -158,6 +170,11 @@ struct scmi_perf_info {
struct perf_dom_info *dom_info; struct perf_dom_info *dom_info;
}; };
static enum scmi_performance_protocol_cmd evt_2_cmd[] = {
PERF_NOTIFY_LIMITS,
PERF_NOTIFY_LEVEL,
};
static int scmi_perf_attributes_get(const struct scmi_handle *handle, static int scmi_perf_attributes_get(const struct scmi_handle *handle,
struct scmi_perf_info *pi) struct scmi_perf_info *pi)
{ {
...@@ -488,6 +505,29 @@ static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain, ...@@ -488,6 +505,29 @@ static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain,
return scmi_perf_mb_level_get(handle, domain, level, poll); return scmi_perf_mb_level_get(handle, domain, level, poll);
} }
static int scmi_perf_level_limits_notify(const struct scmi_handle *handle,
u32 domain, int message_id,
bool enable)
{
int ret;
struct scmi_xfer *t;
struct scmi_perf_notify_level_or_limits *notify;
ret = scmi_xfer_get_init(handle, message_id, SCMI_PROTOCOL_PERF,
sizeof(*notify), 0, &t);
if (ret)
return ret;
notify = t->tx.buf;
notify->domain = cpu_to_le32(domain);
notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0;
ret = scmi_do_xfer(handle, t);
scmi_xfer_put(handle, t);
return ret;
}
static bool scmi_perf_fc_size_is_valid(u32 msg, u32 size) static bool scmi_perf_fc_size_is_valid(u32 msg, u32 size)
{ {
if ((msg == PERF_LEVEL_GET || msg == PERF_LEVEL_SET) && size == 4) if ((msg == PERF_LEVEL_GET || msg == PERF_LEVEL_SET) && size == 4)
...@@ -697,6 +737,17 @@ static int scmi_dvfs_est_power_get(const struct scmi_handle *handle, u32 domain, ...@@ -697,6 +737,17 @@ static int scmi_dvfs_est_power_get(const struct scmi_handle *handle, u32 domain,
return ret; return ret;
} }
static bool scmi_fast_switch_possible(const struct scmi_handle *handle,
struct device *dev)
{
struct perf_dom_info *dom;
struct scmi_perf_info *pi = handle->perf_priv;
dom = pi->dom_info + scmi_dev_domain_id(dev);
return dom->fc_info && dom->fc_info->level_set_addr;
}
static struct scmi_perf_ops perf_ops = { static struct scmi_perf_ops perf_ops = {
.limits_set = scmi_perf_limits_set, .limits_set = scmi_perf_limits_set,
.limits_get = scmi_perf_limits_get, .limits_get = scmi_perf_limits_get,
...@@ -708,6 +759,90 @@ static struct scmi_perf_ops perf_ops = { ...@@ -708,6 +759,90 @@ static struct scmi_perf_ops perf_ops = {
.freq_set = scmi_dvfs_freq_set, .freq_set = scmi_dvfs_freq_set,
.freq_get = scmi_dvfs_freq_get, .freq_get = scmi_dvfs_freq_get,
.est_power_get = scmi_dvfs_est_power_get, .est_power_get = scmi_dvfs_est_power_get,
.fast_switch_possible = scmi_fast_switch_possible,
};
static int scmi_perf_set_notify_enabled(const struct scmi_handle *handle,
u8 evt_id, u32 src_id, bool enable)
{
int ret, cmd_id;
if (evt_id >= ARRAY_SIZE(evt_2_cmd))
return -EINVAL;
cmd_id = evt_2_cmd[evt_id];
ret = scmi_perf_level_limits_notify(handle, src_id, cmd_id, enable);
if (ret)
pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
evt_id, src_id, ret);
return ret;
}
static void *scmi_perf_fill_custom_report(const struct scmi_handle *handle,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
{
void *rep = NULL;
switch (evt_id) {
case SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED:
{
const struct scmi_perf_limits_notify_payld *p = payld;
struct scmi_perf_limits_report *r = report;
if (sizeof(*p) != payld_sz)
break;
r->timestamp = timestamp;
r->agent_id = le32_to_cpu(p->agent_id);
r->domain_id = le32_to_cpu(p->domain_id);
r->range_max = le32_to_cpu(p->range_max);
r->range_min = le32_to_cpu(p->range_min);
*src_id = r->domain_id;
rep = r;
break;
}
case SCMI_EVENT_PERFORMANCE_LEVEL_CHANGED:
{
const struct scmi_perf_level_notify_payld *p = payld;
struct scmi_perf_level_report *r = report;
if (sizeof(*p) != payld_sz)
break;
r->timestamp = timestamp;
r->agent_id = le32_to_cpu(p->agent_id);
r->domain_id = le32_to_cpu(p->domain_id);
r->performance_level = le32_to_cpu(p->performance_level);
*src_id = r->domain_id;
rep = r;
break;
}
default:
break;
}
return rep;
}
static const struct scmi_event perf_events[] = {
{
.id = SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED,
.max_payld_sz = sizeof(struct scmi_perf_limits_notify_payld),
.max_report_sz = sizeof(struct scmi_perf_limits_report),
},
{
.id = SCMI_EVENT_PERFORMANCE_LEVEL_CHANGED,
.max_payld_sz = sizeof(struct scmi_perf_level_notify_payld),
.max_report_sz = sizeof(struct scmi_perf_level_report),
},
};
static const struct scmi_event_ops perf_event_ops = {
.set_notify_enabled = scmi_perf_set_notify_enabled,
.fill_custom_report = scmi_perf_fill_custom_report,
}; };
static int scmi_perf_protocol_init(struct scmi_handle *handle) static int scmi_perf_protocol_init(struct scmi_handle *handle)
...@@ -742,6 +877,12 @@ static int scmi_perf_protocol_init(struct scmi_handle *handle) ...@@ -742,6 +877,12 @@ static int scmi_perf_protocol_init(struct scmi_handle *handle)
scmi_perf_domain_init_fc(handle, domain, &dom->fc_info); scmi_perf_domain_init_fc(handle, domain, &dom->fc_info);
} }
scmi_register_protocol_events(handle,
SCMI_PROTOCOL_PERF, SCMI_PROTO_QUEUE_SZ,
&perf_event_ops, perf_events,
ARRAY_SIZE(perf_events),
pinfo->num_domains);
pinfo->version = version; pinfo->version = version;
handle->perf_ops = &perf_ops; handle->perf_ops = &perf_ops;
handle->perf_priv = pinfo; handle->perf_priv = pinfo;
......
...@@ -5,19 +5,18 @@ ...@@ -5,19 +5,18 @@
* Copyright (C) 2018 ARM Ltd. * Copyright (C) 2018 ARM Ltd.
*/ */
#define pr_fmt(fmt) "SCMI Notifications POWER - " fmt
#include <linux/scmi_protocol.h>
#include "common.h" #include "common.h"
#include "notify.h"
enum scmi_power_protocol_cmd { enum scmi_power_protocol_cmd {
POWER_DOMAIN_ATTRIBUTES = 0x3, POWER_DOMAIN_ATTRIBUTES = 0x3,
POWER_STATE_SET = 0x4, POWER_STATE_SET = 0x4,
POWER_STATE_GET = 0x5, POWER_STATE_GET = 0x5,
POWER_STATE_NOTIFY = 0x6, POWER_STATE_NOTIFY = 0x6,
POWER_STATE_CHANGE_REQUESTED_NOTIFY = 0x7,
};
enum scmi_power_protocol_notify {
POWER_STATE_CHANGED = 0x0,
POWER_STATE_CHANGE_REQUESTED = 0x1,
}; };
struct scmi_msg_resp_power_attributes { struct scmi_msg_resp_power_attributes {
...@@ -48,6 +47,12 @@ struct scmi_power_state_notify { ...@@ -48,6 +47,12 @@ struct scmi_power_state_notify {
__le32 notify_enable; __le32 notify_enable;
}; };
struct scmi_power_state_notify_payld {
__le32 agent_id;
__le32 domain_id;
__le32 power_state;
};
struct power_dom_info { struct power_dom_info {
bool state_set_sync; bool state_set_sync;
bool state_set_async; bool state_set_async;
...@@ -186,6 +191,75 @@ static struct scmi_power_ops power_ops = { ...@@ -186,6 +191,75 @@ static struct scmi_power_ops power_ops = {
.state_get = scmi_power_state_get, .state_get = scmi_power_state_get,
}; };
static int scmi_power_request_notify(const struct scmi_handle *handle,
u32 domain, bool enable)
{
int ret;
struct scmi_xfer *t;
struct scmi_power_state_notify *notify;
ret = scmi_xfer_get_init(handle, POWER_STATE_NOTIFY,
SCMI_PROTOCOL_POWER, sizeof(*notify), 0, &t);
if (ret)
return ret;
notify = t->tx.buf;
notify->domain = cpu_to_le32(domain);
notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0;
ret = scmi_do_xfer(handle, t);
scmi_xfer_put(handle, t);
return ret;
}
static int scmi_power_set_notify_enabled(const struct scmi_handle *handle,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
ret = scmi_power_request_notify(handle, src_id, enable);
if (ret)
pr_debug("FAIL_ENABLE - evt[%X] dom[%d] - ret:%d\n",
evt_id, src_id, ret);
return ret;
}
static void *scmi_power_fill_custom_report(const struct scmi_handle *handle,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
{
const struct scmi_power_state_notify_payld *p = payld;
struct scmi_power_state_changed_report *r = report;
if (evt_id != SCMI_EVENT_POWER_STATE_CHANGED || sizeof(*p) != payld_sz)
return NULL;
r->timestamp = timestamp;
r->agent_id = le32_to_cpu(p->agent_id);
r->domain_id = le32_to_cpu(p->domain_id);
r->power_state = le32_to_cpu(p->power_state);
*src_id = r->domain_id;
return r;
}
static const struct scmi_event power_events[] = {
{
.id = SCMI_EVENT_POWER_STATE_CHANGED,
.max_payld_sz = sizeof(struct scmi_power_state_notify_payld),
.max_report_sz =
sizeof(struct scmi_power_state_changed_report),
},
};
static const struct scmi_event_ops power_event_ops = {
.set_notify_enabled = scmi_power_set_notify_enabled,
.fill_custom_report = scmi_power_fill_custom_report,
};
static int scmi_power_protocol_init(struct scmi_handle *handle) static int scmi_power_protocol_init(struct scmi_handle *handle)
{ {
int domain; int domain;
...@@ -214,6 +288,12 @@ static int scmi_power_protocol_init(struct scmi_handle *handle) ...@@ -214,6 +288,12 @@ static int scmi_power_protocol_init(struct scmi_handle *handle)
scmi_power_domain_attributes_get(handle, domain, dom); scmi_power_domain_attributes_get(handle, domain, dom);
} }
scmi_register_protocol_events(handle,
SCMI_PROTOCOL_POWER, SCMI_PROTO_QUEUE_SZ,
&power_event_ops, power_events,
ARRAY_SIZE(power_events),
pinfo->num_domains);
pinfo->version = version; pinfo->version = version;
handle->power_ops = &power_ops; handle->power_ops = &power_ops;
handle->power_priv = pinfo; handle->power_priv = pinfo;
......
...@@ -5,7 +5,12 @@ ...@@ -5,7 +5,12 @@
* Copyright (C) 2019 ARM Ltd. * Copyright (C) 2019 ARM Ltd.
*/ */
#define pr_fmt(fmt) "SCMI Notifications RESET - " fmt
#include <linux/scmi_protocol.h>
#include "common.h" #include "common.h"
#include "notify.h"
enum scmi_reset_protocol_cmd { enum scmi_reset_protocol_cmd {
RESET_DOMAIN_ATTRIBUTES = 0x3, RESET_DOMAIN_ATTRIBUTES = 0x3,
...@@ -13,10 +18,6 @@ enum scmi_reset_protocol_cmd { ...@@ -13,10 +18,6 @@ enum scmi_reset_protocol_cmd {
RESET_NOTIFY = 0x5, RESET_NOTIFY = 0x5,
}; };
enum scmi_reset_protocol_notify {
RESET_ISSUED = 0x0,
};
#define NUM_RESET_DOMAIN_MASK 0xffff #define NUM_RESET_DOMAIN_MASK 0xffff
#define RESET_NOTIFY_ENABLE BIT(0) #define RESET_NOTIFY_ENABLE BIT(0)
...@@ -40,6 +41,18 @@ struct scmi_msg_reset_domain_reset { ...@@ -40,6 +41,18 @@ struct scmi_msg_reset_domain_reset {
#define ARCH_COLD_RESET (ARCH_RESET_TYPE | COLD_RESET_STATE) #define ARCH_COLD_RESET (ARCH_RESET_TYPE | COLD_RESET_STATE)
}; };
struct scmi_msg_reset_notify {
__le32 id;
__le32 event_control;
#define RESET_TP_NOTIFY_ALL BIT(0)
};
struct scmi_reset_issued_notify_payld {
__le32 agent_id;
__le32 domain_id;
__le32 reset_state;
};
struct reset_dom_info { struct reset_dom_info {
bool async_reset; bool async_reset;
bool reset_notify; bool reset_notify;
...@@ -190,6 +203,75 @@ static struct scmi_reset_ops reset_ops = { ...@@ -190,6 +203,75 @@ static struct scmi_reset_ops reset_ops = {
.deassert = scmi_reset_domain_deassert, .deassert = scmi_reset_domain_deassert,
}; };
static int scmi_reset_notify(const struct scmi_handle *handle, u32 domain_id,
bool enable)
{
int ret;
u32 evt_cntl = enable ? RESET_TP_NOTIFY_ALL : 0;
struct scmi_xfer *t;
struct scmi_msg_reset_notify *cfg;
ret = scmi_xfer_get_init(handle, RESET_NOTIFY,
SCMI_PROTOCOL_RESET, sizeof(*cfg), 0, &t);
if (ret)
return ret;
cfg = t->tx.buf;
cfg->id = cpu_to_le32(domain_id);
cfg->event_control = cpu_to_le32(evt_cntl);
ret = scmi_do_xfer(handle, t);
scmi_xfer_put(handle, t);
return ret;
}
static int scmi_reset_set_notify_enabled(const struct scmi_handle *handle,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
ret = scmi_reset_notify(handle, src_id, enable);
if (ret)
pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
evt_id, src_id, ret);
return ret;
}
static void *scmi_reset_fill_custom_report(const struct scmi_handle *handle,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
{
const struct scmi_reset_issued_notify_payld *p = payld;
struct scmi_reset_issued_report *r = report;
if (evt_id != SCMI_EVENT_RESET_ISSUED || sizeof(*p) != payld_sz)
return NULL;
r->timestamp = timestamp;
r->agent_id = le32_to_cpu(p->agent_id);
r->domain_id = le32_to_cpu(p->domain_id);
r->reset_state = le32_to_cpu(p->reset_state);
*src_id = r->domain_id;
return r;
}
static const struct scmi_event reset_events[] = {
{
.id = SCMI_EVENT_RESET_ISSUED,
.max_payld_sz = sizeof(struct scmi_reset_issued_notify_payld),
.max_report_sz = sizeof(struct scmi_reset_issued_report),
},
};
static const struct scmi_event_ops reset_event_ops = {
.set_notify_enabled = scmi_reset_set_notify_enabled,
.fill_custom_report = scmi_reset_fill_custom_report,
};
static int scmi_reset_protocol_init(struct scmi_handle *handle) static int scmi_reset_protocol_init(struct scmi_handle *handle)
{ {
int domain; int domain;
...@@ -218,6 +300,12 @@ static int scmi_reset_protocol_init(struct scmi_handle *handle) ...@@ -218,6 +300,12 @@ static int scmi_reset_protocol_init(struct scmi_handle *handle)
scmi_reset_domain_attributes_get(handle, domain, dom); scmi_reset_domain_attributes_get(handle, domain, dom);
} }
scmi_register_protocol_events(handle,
SCMI_PROTOCOL_RESET, SCMI_PROTO_QUEUE_SZ,
&reset_event_ops, reset_events,
ARRAY_SIZE(reset_events),
pinfo->num_domains);
pinfo->version = version; pinfo->version = version;
handle->reset_ops = &reset_ops; handle->reset_ops = &reset_ops;
handle->reset_priv = pinfo; handle->reset_priv = pinfo;
......
...@@ -85,7 +85,10 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev) ...@@ -85,7 +85,10 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
for (i = 0; i < num_domains; i++, scmi_pd++) { for (i = 0; i < num_domains; i++, scmi_pd++) {
u32 state; u32 state;
domains[i] = &scmi_pd->genpd; if (handle->power_ops->state_get(handle, i, &state)) {
dev_warn(dev, "failed to get state for domain %d\n", i);
continue;
}
scmi_pd->domain = i; scmi_pd->domain = i;
scmi_pd->handle = handle; scmi_pd->handle = handle;
...@@ -94,13 +97,10 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev) ...@@ -94,13 +97,10 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
scmi_pd->genpd.power_off = scmi_pd_power_off; scmi_pd->genpd.power_off = scmi_pd_power_off;
scmi_pd->genpd.power_on = scmi_pd_power_on; scmi_pd->genpd.power_on = scmi_pd_power_on;
if (handle->power_ops->state_get(handle, i, &state)) {
dev_warn(dev, "failed to get state for domain %d\n", i);
continue;
}
pm_genpd_init(&scmi_pd->genpd, NULL, pm_genpd_init(&scmi_pd->genpd, NULL,
state == SCMI_POWER_STATE_GENERIC_OFF); state == SCMI_POWER_STATE_GENERIC_OFF);
domains[i] = &scmi_pd->genpd;
} }
scmi_pd_data->domains = domains; scmi_pd_data->domains = domains;
......
...@@ -5,7 +5,12 @@ ...@@ -5,7 +5,12 @@
* Copyright (C) 2018 ARM Ltd. * Copyright (C) 2018 ARM Ltd.
*/ */
#define pr_fmt(fmt) "SCMI Notifications SENSOR - " fmt
#include <linux/scmi_protocol.h>
#include "common.h" #include "common.h"
#include "notify.h"
enum scmi_sensor_protocol_cmd { enum scmi_sensor_protocol_cmd {
SENSOR_DESCRIPTION_GET = 0x3, SENSOR_DESCRIPTION_GET = 0x3,
...@@ -14,10 +19,6 @@ enum scmi_sensor_protocol_cmd { ...@@ -14,10 +19,6 @@ enum scmi_sensor_protocol_cmd {
SENSOR_READING_GET = 0x6, SENSOR_READING_GET = 0x6,
}; };
enum scmi_sensor_protocol_notify {
SENSOR_TRIP_POINT_EVENT = 0x0,
};
struct scmi_msg_resp_sensor_attributes { struct scmi_msg_resp_sensor_attributes {
__le16 num_sensors; __le16 num_sensors;
u8 max_requests; u8 max_requests;
...@@ -71,6 +72,12 @@ struct scmi_msg_sensor_reading_get { ...@@ -71,6 +72,12 @@ struct scmi_msg_sensor_reading_get {
#define SENSOR_READ_ASYNC BIT(0) #define SENSOR_READ_ASYNC BIT(0)
}; };
struct scmi_sensor_trip_notify_payld {
__le32 agent_id;
__le32 sensor_id;
__le32 trip_point_desc;
};
struct sensors_info { struct sensors_info {
u32 version; u32 version;
int num_sensors; int num_sensors;
...@@ -271,11 +278,57 @@ static int scmi_sensor_count_get(const struct scmi_handle *handle) ...@@ -271,11 +278,57 @@ static int scmi_sensor_count_get(const struct scmi_handle *handle)
static struct scmi_sensor_ops sensor_ops = { static struct scmi_sensor_ops sensor_ops = {
.count_get = scmi_sensor_count_get, .count_get = scmi_sensor_count_get,
.info_get = scmi_sensor_info_get, .info_get = scmi_sensor_info_get,
.trip_point_notify = scmi_sensor_trip_point_notify,
.trip_point_config = scmi_sensor_trip_point_config, .trip_point_config = scmi_sensor_trip_point_config,
.reading_get = scmi_sensor_reading_get, .reading_get = scmi_sensor_reading_get,
}; };
static int scmi_sensor_set_notify_enabled(const struct scmi_handle *handle,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
ret = scmi_sensor_trip_point_notify(handle, src_id, enable);
if (ret)
pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
evt_id, src_id, ret);
return ret;
}
static void *scmi_sensor_fill_custom_report(const struct scmi_handle *handle,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
{
const struct scmi_sensor_trip_notify_payld *p = payld;
struct scmi_sensor_trip_point_report *r = report;
if (evt_id != SCMI_EVENT_SENSOR_TRIP_POINT_EVENT ||
sizeof(*p) != payld_sz)
return NULL;
r->timestamp = timestamp;
r->agent_id = le32_to_cpu(p->agent_id);
r->sensor_id = le32_to_cpu(p->sensor_id);
r->trip_point_desc = le32_to_cpu(p->trip_point_desc);
*src_id = r->sensor_id;
return r;
}
static const struct scmi_event sensor_events[] = {
{
.id = SCMI_EVENT_SENSOR_TRIP_POINT_EVENT,
.max_payld_sz = sizeof(struct scmi_sensor_trip_notify_payld),
.max_report_sz = sizeof(struct scmi_sensor_trip_point_report),
},
};
static const struct scmi_event_ops sensor_event_ops = {
.set_notify_enabled = scmi_sensor_set_notify_enabled,
.fill_custom_report = scmi_sensor_fill_custom_report,
};
static int scmi_sensors_protocol_init(struct scmi_handle *handle) static int scmi_sensors_protocol_init(struct scmi_handle *handle)
{ {
u32 version; u32 version;
...@@ -299,6 +352,12 @@ static int scmi_sensors_protocol_init(struct scmi_handle *handle) ...@@ -299,6 +352,12 @@ static int scmi_sensors_protocol_init(struct scmi_handle *handle)
scmi_sensor_description_get(handle, sinfo); scmi_sensor_description_get(handle, sinfo);
scmi_register_protocol_events(handle,
SCMI_PROTOCOL_SENSOR, SCMI_PROTO_QUEUE_SZ,
&sensor_event_ops, sensor_events,
ARRAY_SIZE(sensor_events),
sinfo->num_sensors);
sinfo->version = version; sinfo->version = version;
handle->sensor_ops = &sensor_ops; handle->sensor_ops = &sensor_ops;
handle->sensor_priv = sinfo; handle->sensor_priv = sinfo;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
* *
* @cinfo: SCMI channel info * @cinfo: SCMI channel info
* @shmem: Transmit/Receive shared memory area * @shmem: Transmit/Receive shared memory area
* @shmem_lock: Lock to protect access to Tx/Rx shared memory area
* @func_id: smc/hvc call function id * @func_id: smc/hvc call function id
*/ */
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_IMX_DSP) += imx-dsp.o obj-$(CONFIG_IMX_DSP) += imx-dsp.o
obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o
obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/firmware/imx/ipc.h> #include <linux/firmware/imx/ipc.h>
#include <linux/firmware/imx/sci.h> #include <linux/firmware/imx/sci.h>
#include <linux/mailbox_client.h> #include <linux/mailbox_client.h>
#include <linux/suspend.h>
#define IMX_SC_IRQ_FUNC_ENABLE 1 #define IMX_SC_IRQ_FUNC_ENABLE 1
#define IMX_SC_IRQ_FUNC_STATUS 2 #define IMX_SC_IRQ_FUNC_STATUS 2
...@@ -91,6 +92,7 @@ static void imx_scu_irq_work_handler(struct work_struct *work) ...@@ -91,6 +92,7 @@ static void imx_scu_irq_work_handler(struct work_struct *work)
if (!irq_status) if (!irq_status)
continue; continue;
pm_system_wakeup();
imx_scu_irq_notifier_call_chain(irq_status, &i); imx_scu_irq_notifier_call_chain(irq_status, &i);
} }
} }
......
...@@ -10,9 +10,7 @@ ...@@ -10,9 +10,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of.h> #include <linux/of.h>
#define IMX_SCU_SOC_DRIVER_NAME "imx-scu-soc" static struct imx_sc_ipc *imx_sc_soc_ipc_handle;
static struct imx_sc_ipc *soc_ipc_handle;
struct imx_sc_msg_misc_get_soc_id { struct imx_sc_msg_misc_get_soc_id {
struct imx_sc_rpc_msg hdr; struct imx_sc_rpc_msg hdr;
...@@ -44,7 +42,7 @@ static int imx_scu_soc_uid(u64 *soc_uid) ...@@ -44,7 +42,7 @@ static int imx_scu_soc_uid(u64 *soc_uid)
hdr->func = IMX_SC_MISC_FUNC_UNIQUE_ID; hdr->func = IMX_SC_MISC_FUNC_UNIQUE_ID;
hdr->size = 1; hdr->size = 1;
ret = imx_scu_call_rpc(soc_ipc_handle, &msg, true); ret = imx_scu_call_rpc(imx_sc_soc_ipc_handle, &msg, true);
if (ret) { if (ret) {
pr_err("%s: get soc uid failed, ret %d\n", __func__, ret); pr_err("%s: get soc uid failed, ret %d\n", __func__, ret);
return ret; return ret;
...@@ -71,7 +69,7 @@ static int imx_scu_soc_id(void) ...@@ -71,7 +69,7 @@ static int imx_scu_soc_id(void)
msg.data.req.control = IMX_SC_C_ID; msg.data.req.control = IMX_SC_C_ID;
msg.data.req.resource = IMX_SC_R_SYSTEM; msg.data.req.resource = IMX_SC_R_SYSTEM;
ret = imx_scu_call_rpc(soc_ipc_handle, &msg, true); ret = imx_scu_call_rpc(imx_sc_soc_ipc_handle, &msg, true);
if (ret) { if (ret) {
pr_err("%s: get soc info failed, ret %d\n", __func__, ret); pr_err("%s: get soc info failed, ret %d\n", __func__, ret);
return ret; return ret;
...@@ -80,7 +78,7 @@ static int imx_scu_soc_id(void) ...@@ -80,7 +78,7 @@ static int imx_scu_soc_id(void)
return msg.data.resp.id; return msg.data.resp.id;
} }
static int imx_scu_soc_probe(struct platform_device *pdev) int imx_scu_soc_init(struct device *dev)
{ {
struct soc_device_attribute *soc_dev_attr; struct soc_device_attribute *soc_dev_attr;
struct soc_device *soc_dev; struct soc_device *soc_dev;
...@@ -88,11 +86,11 @@ static int imx_scu_soc_probe(struct platform_device *pdev) ...@@ -88,11 +86,11 @@ static int imx_scu_soc_probe(struct platform_device *pdev)
u64 uid = 0; u64 uid = 0;
u32 val; u32 val;
ret = imx_scu_get_handle(&soc_ipc_handle); ret = imx_scu_get_handle(&imx_sc_soc_ipc_handle);
if (ret) if (ret)
return ret; return ret;
soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr), soc_dev_attr = devm_kzalloc(dev, sizeof(*soc_dev_attr),
GFP_KERNEL); GFP_KERNEL);
if (!soc_dev_attr) if (!soc_dev_attr)
return -ENOMEM; return -ENOMEM;
...@@ -115,73 +113,26 @@ static int imx_scu_soc_probe(struct platform_device *pdev) ...@@ -115,73 +113,26 @@ static int imx_scu_soc_probe(struct platform_device *pdev)
/* format soc_id value passed from SCU firmware */ /* format soc_id value passed from SCU firmware */
val = id & 0x1f; val = id & 0x1f;
soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "0x%x", val); soc_dev_attr->soc_id = devm_kasprintf(dev, GFP_KERNEL, "0x%x", val);
if (!soc_dev_attr->soc_id) if (!soc_dev_attr->soc_id)
return -ENOMEM; return -ENOMEM;
/* format revision value passed from SCU firmware */ /* format revision value passed from SCU firmware */
val = (id >> 5) & 0xf; val = (id >> 5) & 0xf;
val = (((val >> 2) + 1) << 4) | (val & 0x3); val = (((val >> 2) + 1) << 4) | (val & 0x3);
soc_dev_attr->revision = kasprintf(GFP_KERNEL, soc_dev_attr->revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d",
"%d.%d", (val >> 4) & 0xf, val & 0xf);
(val >> 4) & 0xf, if (!soc_dev_attr->revision)
val & 0xf); return -ENOMEM;
if (!soc_dev_attr->revision) {
ret = -ENOMEM;
goto free_soc_id;
}
soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", uid); soc_dev_attr->serial_number = devm_kasprintf(dev, GFP_KERNEL,
if (!soc_dev_attr->serial_number) { "%016llX", uid);
ret = -ENOMEM; if (!soc_dev_attr->serial_number)
goto free_revision; return -ENOMEM;
}
soc_dev = soc_device_register(soc_dev_attr); soc_dev = soc_device_register(soc_dev_attr);
if (IS_ERR(soc_dev)) { if (IS_ERR(soc_dev))
ret = PTR_ERR(soc_dev); return PTR_ERR(soc_dev);
goto free_serial_number;
}
return 0; return 0;
free_serial_number:
kfree(soc_dev_attr->serial_number);
free_revision:
kfree(soc_dev_attr->revision);
free_soc_id:
kfree(soc_dev_attr->soc_id);
return ret;
}
static struct platform_driver imx_scu_soc_driver = {
.driver = {
.name = IMX_SCU_SOC_DRIVER_NAME,
},
.probe = imx_scu_soc_probe,
};
static int __init imx_scu_soc_init(void)
{
struct platform_device *pdev;
struct device_node *np;
int ret;
np = of_find_compatible_node(NULL, NULL, "fsl,imx-scu");
if (!np)
return -ENODEV;
of_node_put(np);
ret = platform_driver_register(&imx_scu_soc_driver);
if (ret)
return ret;
pdev = platform_device_register_simple(IMX_SCU_SOC_DRIVER_NAME,
-1, NULL, 0);
if (IS_ERR(pdev))
platform_driver_unregister(&imx_scu_soc_driver);
return PTR_ERR_OR_ZERO(pdev);
} }
device_initcall(imx_scu_soc_init);
...@@ -328,6 +328,10 @@ static int imx_scu_probe(struct platform_device *pdev) ...@@ -328,6 +328,10 @@ static int imx_scu_probe(struct platform_device *pdev)
imx_sc_ipc_handle = sc_ipc; imx_sc_ipc_handle = sc_ipc;
ret = imx_scu_soc_init(dev);
if (ret)
dev_warn(dev, "failed to initialize SoC info: %d\n", ret);
ret = imx_scu_enable_general_irq_channel(dev); ret = imx_scu_enable_general_irq_channel(dev);
if (ret) if (ret)
dev_warn(dev, dev_warn(dev,
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2020 NXP
*
* File containing client-side RPC functions for the RM service. These
* function are ported to clients that communicate to the SC.
*/
#include <linux/firmware/imx/svc/rm.h>
struct imx_sc_msg_rm_rsrc_owned {
struct imx_sc_rpc_msg hdr;
u16 resource;
} __packed __aligned(4);
/*
* This function check @resource is owned by current partition or not
*
* @param[in] ipc IPC handle
* @param[in] resource resource the control is associated with
*
* @return Returns 0 for not owned and 1 for owned.
*/
bool imx_sc_rm_is_resource_owned(struct imx_sc_ipc *ipc, u16 resource)
{
struct imx_sc_msg_rm_rsrc_owned msg;
struct imx_sc_rpc_msg *hdr = &msg.hdr;
hdr->ver = IMX_SC_RPC_VERSION;
hdr->svc = IMX_SC_RPC_SVC_RM;
hdr->func = IMX_SC_RM_FUNC_IS_RESOURCE_OWNED;
hdr->size = 2;
msg.resource = resource;
/*
* SCU firmware only returns value 0 or 1
* for resource owned check which means not owned or owned.
* So it is always successful.
*/
imx_scu_call_rpc(ipc, &msg, true);
return hdr->func;
}
EXPORT_SYMBOL(imx_sc_rm_is_resource_owned);
...@@ -167,8 +167,18 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { ...@@ -167,8 +167,18 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
{ "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 }, { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 },
/* CM40 SS */ /* CM40 SS */
{ "cm40_i2c", IMX_SC_R_M4_0_I2C, 1, 0 }, { "cm40-i2c", IMX_SC_R_M4_0_I2C, 1, false, 0 },
{ "cm40_intmux", IMX_SC_R_M4_0_INTMUX, 1, 0 }, { "cm40-intmux", IMX_SC_R_M4_0_INTMUX, 1, false, 0 },
{ "cm40-pid", IMX_SC_R_M4_0_PID0, 5, true, 0},
{ "cm40-mu-a1", IMX_SC_R_M4_0_MU_1A, 1, false, 0},
{ "cm40-lpuart", IMX_SC_R_M4_0_UART, 1, false, 0},
/* CM41 SS */
{ "cm41-i2c", IMX_SC_R_M4_1_I2C, 1, false, 0 },
{ "cm41-intmux", IMX_SC_R_M4_1_INTMUX, 1, false, 0 },
{ "cm41-pid", IMX_SC_R_M4_1_PID0, 5, true, 0},
{ "cm41-mu-a1", IMX_SC_R_M4_1_MU_1A, 1, false, 0},
{ "cm41-lpuart", IMX_SC_R_M4_1_UART, 1, false, 0},
}; };
static const struct imx_sc_pd_soc imx8qxp_scu_pd = { static const struct imx_sc_pd_soc imx8qxp_scu_pd = {
......
...@@ -391,7 +391,7 @@ static int __qcom_scm_set_dload_mode(struct device *dev, bool enable) ...@@ -391,7 +391,7 @@ static int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0; desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0;
return qcom_scm_call(__scm->dev, &desc, NULL); return qcom_scm_call_atomic(__scm->dev, &desc, NULL);
} }
static void qcom_scm_set_download_mode(bool enable) static void qcom_scm_set_download_mode(bool enable)
...@@ -650,7 +650,7 @@ int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) ...@@ -650,7 +650,7 @@ int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val)
int ret; int ret;
ret = qcom_scm_call(__scm->dev, &desc, &res); ret = qcom_scm_call_atomic(__scm->dev, &desc, &res);
if (ret >= 0) if (ret >= 0)
*val = res.result[0]; *val = res.result[0];
...@@ -669,8 +669,7 @@ int qcom_scm_io_writel(phys_addr_t addr, unsigned int val) ...@@ -669,8 +669,7 @@ int qcom_scm_io_writel(phys_addr_t addr, unsigned int val)
.owner = ARM_SMCCC_OWNER_SIP, .owner = ARM_SMCCC_OWNER_SIP,
}; };
return qcom_scm_call_atomic(__scm->dev, &desc, NULL);
return qcom_scm_call(__scm->dev, &desc, NULL);
} }
EXPORT_SYMBOL(qcom_scm_io_writel); EXPORT_SYMBOL(qcom_scm_io_writel);
...@@ -1151,6 +1150,7 @@ static const struct of_device_id qcom_scm_dt_match[] = { ...@@ -1151,6 +1150,7 @@ static const struct of_device_id qcom_scm_dt_match[] = {
SCM_HAS_IFACE_CLK | SCM_HAS_IFACE_CLK |
SCM_HAS_BUS_CLK) SCM_HAS_BUS_CLK)
}, },
{ .compatible = "qcom,scm-msm8994" },
{ .compatible = "qcom,scm-msm8996" }, { .compatible = "qcom,scm-msm8996" },
{ .compatible = "qcom,scm" }, { .compatible = "qcom,scm" },
{} {}
......
...@@ -14,3 +14,12 @@ config HAVE_ARM_SMCCC_DISCOVERY ...@@ -14,3 +14,12 @@ config HAVE_ARM_SMCCC_DISCOVERY
to add SMCCC discovery mechanism though the PSCI firmware to add SMCCC discovery mechanism though the PSCI firmware
implementation of PSCI_FEATURES(SMCCC_VERSION) which returns implementation of PSCI_FEATURES(SMCCC_VERSION) which returns
success on firmware compliant to SMCCC v1.1 and above. success on firmware compliant to SMCCC v1.1 and above.
config ARM_SMCCC_SOC_ID
bool "SoC bus device for the ARM SMCCC SOC_ID"
depends on HAVE_ARM_SMCCC_DISCOVERY
default y
select SOC_BUS
help
Include support for the SoC bus on the ARM SMCCC firmware based
platforms providing some sysfs information about the SoC variant.
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
# #
obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smccc.o obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smccc.o
obj-$(CONFIG_ARM_SMCCC_SOC_ID) += soc_id.o
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2020 Arm Limited
*/
#define pr_fmt(fmt) "SMCCC: SOC_ID: " fmt
#include <linux/arm-smccc.h>
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sys_soc.h>
#define SMCCC_SOC_ID_JEP106_BANK_IDX_MASK GENMASK(30, 24)
/*
* As per the SMC Calling Convention specification v1.2 (ARM DEN 0028C)
* Section 7.4 SMCCC_ARCH_SOC_ID bits[23:16] are JEP-106 identification
* code with parity bit for the SiP. We can drop the parity bit.
*/
#define SMCCC_SOC_ID_JEP106_ID_CODE_MASK GENMASK(22, 16)
#define SMCCC_SOC_ID_IMP_DEF_SOC_ID_MASK GENMASK(15, 0)
#define JEP106_BANK_CONT_CODE(x) \
(u8)(FIELD_GET(SMCCC_SOC_ID_JEP106_BANK_IDX_MASK, (x)))
#define JEP106_ID_CODE(x) \
(u8)(FIELD_GET(SMCCC_SOC_ID_JEP106_ID_CODE_MASK, (x)))
#define IMP_DEF_SOC_ID(x) \
(u16)(FIELD_GET(SMCCC_SOC_ID_IMP_DEF_SOC_ID_MASK, (x)))
static struct soc_device *soc_dev;
static struct soc_device_attribute *soc_dev_attr;
static int __init smccc_soc_init(void)
{
struct arm_smccc_res res;
int soc_id_rev, soc_id_version;
static char soc_id_str[20], soc_id_rev_str[12];
static char soc_id_jep106_id_str[12];
if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
return 0;
if (arm_smccc_1_1_get_conduit() == SMCCC_CONDUIT_NONE) {
pr_err("%s: invalid SMCCC conduit\n", __func__);
return -EOPNOTSUPP;
}
arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
ARM_SMCCC_ARCH_SOC_ID, &res);
if (res.a0 == SMCCC_RET_NOT_SUPPORTED) {
pr_info("ARCH_SOC_ID not implemented, skipping ....\n");
return 0;
}
if ((int)res.a0 < 0) {
pr_info("ARCH_FEATURES(ARCH_SOC_ID) returned error: %lx\n",
res.a0);
return -EINVAL;
}
arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 0, &res);
if ((int)res.a0 < 0) {
pr_err("ARCH_SOC_ID(0) returned error: %lx\n", res.a0);
return -EINVAL;
}
soc_id_version = res.a0;
arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 1, &res);
if ((int)res.a0 < 0) {
pr_err("ARCH_SOC_ID(1) returned error: %lx\n", res.a0);
return -EINVAL;
}
soc_id_rev = res.a0;
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
if (!soc_dev_attr)
return -ENOMEM;
sprintf(soc_id_rev_str, "0x%08x", soc_id_rev);
sprintf(soc_id_jep106_id_str, "jep106:%02x%02x",
JEP106_BANK_CONT_CODE(soc_id_version),
JEP106_ID_CODE(soc_id_version));
sprintf(soc_id_str, "%s:%04x", soc_id_jep106_id_str,
IMP_DEF_SOC_ID(soc_id_version));
soc_dev_attr->soc_id = soc_id_str;
soc_dev_attr->revision = soc_id_rev_str;
soc_dev_attr->family = soc_id_jep106_id_str;
soc_dev = soc_device_register(soc_dev_attr);
if (IS_ERR(soc_dev)) {
kfree(soc_dev_attr);
return PTR_ERR(soc_dev);
}
pr_info("ID = %s Revision = %s\n", soc_dev_attr->soc_id,
soc_dev_attr->revision);
return 0;
}
module_init(smccc_soc_init);
static void __exit smccc_soc_exit(void)
{
if (soc_dev)
soc_device_unregister(soc_dev);
kfree(soc_dev_attr);
}
module_exit(smccc_soc_exit);
This diff is collapsed.
...@@ -515,10 +515,10 @@ bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq) ...@@ -515,10 +515,10 @@ bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq)
.size = sizeof(resp), .size = sizeof(resp),
}, },
}; };
int ret; int err;
ret = tegra_bpmp_transfer(bpmp, &msg); err = tegra_bpmp_transfer(bpmp, &msg);
if (ret || msg.rx.ret) if (err || msg.rx.ret)
return false; return false;
return resp.status == 0; return resp.status == 0;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* Texas Instruments System Control Interface Protocol Driver * Texas Instruments System Control Interface Protocol Driver
* *
* Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/
* Nishanth Menon * Nishanth Menon
*/ */
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* The system works in a message response protocol * The system works in a message response protocol
* See: http://processors.wiki.ti.com/index.php/TISCI for details * See: http://processors.wiki.ti.com/index.php/TISCI for details
* *
* Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/
*/ */
#ifndef __TI_SCI_H #ifndef __TI_SCI_H
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/armada-37xx-rwtm-mailbox.h> #include <linux/armada-37xx-rwtm-mailbox.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/hw_random.h> #include <linux/hw_random.h>
#include <linux/mailbox_client.h> #include <linux/mailbox_client.h>
...@@ -69,6 +70,18 @@ struct mox_rwtm { ...@@ -69,6 +70,18 @@ struct mox_rwtm {
/* public key burned in eFuse */ /* public key burned in eFuse */
int has_pubkey; int has_pubkey;
u8 pubkey[135]; u8 pubkey[135];
#ifdef CONFIG_DEBUG_FS
/*
* Signature process. This is currently done via debugfs, because it
* does not conform to the sysfs standard "one file per attribute".
* It should be rewritten via crypto API once akcipher API is available
* from userspace.
*/
struct dentry *debugfs_root;
u32 last_sig[34];
int last_sig_done;
#endif
}; };
struct mox_kobject { struct mox_kobject {
...@@ -279,6 +292,152 @@ static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) ...@@ -279,6 +292,152 @@ static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
return ret; return ret;
} }
#ifdef CONFIG_DEBUG_FS
static int rwtm_debug_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return nonseekable_open(inode, file);
}
static ssize_t do_sign_read(struct file *file, char __user *buf, size_t len,
loff_t *ppos)
{
struct mox_rwtm *rwtm = file->private_data;
ssize_t ret;
/* only allow one read, of 136 bytes, from position 0 */
if (*ppos != 0)
return 0;
if (len < 136)
return -EINVAL;
if (!rwtm->last_sig_done)
return -ENODATA;
/* 2 arrays of 17 32-bit words are 136 bytes */
ret = simple_read_from_buffer(buf, len, ppos, rwtm->last_sig, 136);
rwtm->last_sig_done = 0;
return ret;
}
static ssize_t do_sign_write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
{
struct mox_rwtm *rwtm = file->private_data;
struct armada_37xx_rwtm_rx_msg *reply = &rwtm->reply;
struct armada_37xx_rwtm_tx_msg msg;
loff_t dummy = 0;
ssize_t ret;
/* the input is a SHA-512 hash, so exactly 64 bytes have to be read */
if (len != 64)
return -EINVAL;
/* if last result is not zero user has not read that information yet */
if (rwtm->last_sig_done)
return -EBUSY;
if (!mutex_trylock(&rwtm->busy))
return -EBUSY;
/*
* Here we have to send:
* 1. Address of the input to sign.
* The input is an array of 17 32-bit words, the first (most
* significat) is 0, the rest 16 words are copied from the SHA-512
* hash given by the user and converted from BE to LE.
* 2. Address of the buffer where ECDSA signature value R shall be
* stored by the rWTM firmware.
* 3. Address of the buffer where ECDSA signature value S shall be
* stored by the rWTM firmware.
*/
memset(rwtm->buf, 0, 4);
ret = simple_write_to_buffer(rwtm->buf + 4, 64, &dummy, buf, len);
if (ret < 0)
goto unlock_mutex;
be32_to_cpu_array(rwtm->buf, rwtm->buf, 17);
msg.command = MBOX_CMD_SIGN;
msg.args[0] = 1;
msg.args[1] = rwtm->buf_phys;
msg.args[2] = rwtm->buf_phys + 68;
msg.args[3] = rwtm->buf_phys + 2 * 68;
ret = mbox_send_message(rwtm->mbox, &msg);
if (ret < 0)
goto unlock_mutex;
ret = wait_for_completion_interruptible(&rwtm->cmd_done);
if (ret < 0)
goto unlock_mutex;
ret = MBOX_STS_VALUE(reply->retval);
if (MBOX_STS_ERROR(reply->retval) != MBOX_STS_SUCCESS)
goto unlock_mutex;
/*
* Here we read the R and S values of the ECDSA signature
* computed by the rWTM firmware and convert their words from
* LE to BE.
*/
memcpy(rwtm->last_sig, rwtm->buf + 68, 136);
cpu_to_be32_array(rwtm->last_sig, rwtm->last_sig, 34);
rwtm->last_sig_done = 1;
mutex_unlock(&rwtm->busy);
return len;
unlock_mutex:
mutex_unlock(&rwtm->busy);
return ret;
}
static const struct file_operations do_sign_fops = {
.owner = THIS_MODULE,
.open = rwtm_debug_open,
.read = do_sign_read,
.write = do_sign_write,
.llseek = no_llseek,
};
static int rwtm_register_debugfs(struct mox_rwtm *rwtm)
{
struct dentry *root, *entry;
root = debugfs_create_dir("turris-mox-rwtm", NULL);
if (IS_ERR(root))
return PTR_ERR(root);
entry = debugfs_create_file_unsafe("do_sign", 0600, root, rwtm,
&do_sign_fops);
if (IS_ERR(entry))
goto err_remove;
rwtm->debugfs_root = root;
return 0;
err_remove:
debugfs_remove_recursive(root);
return PTR_ERR(entry);
}
static void rwtm_unregister_debugfs(struct mox_rwtm *rwtm)
{
debugfs_remove_recursive(rwtm->debugfs_root);
}
#else
static inline int rwtm_register_debugfs(struct mox_rwtm *rwtm)
{
return 0;
}
static inline void rwtm_unregister_debugfs(struct mox_rwtm *rwtm)
{
}
#endif
static int turris_mox_rwtm_probe(struct platform_device *pdev) static int turris_mox_rwtm_probe(struct platform_device *pdev)
{ {
struct mox_rwtm *rwtm; struct mox_rwtm *rwtm;
...@@ -340,6 +499,12 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) ...@@ -340,6 +499,12 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev)
goto free_channel; goto free_channel;
} }
ret = rwtm_register_debugfs(rwtm);
if (ret < 0) {
dev_err(dev, "Failed creating debugfs entries: %i\n", ret);
goto free_channel;
}
return 0; return 0;
free_channel: free_channel:
...@@ -355,6 +520,7 @@ static int turris_mox_rwtm_remove(struct platform_device *pdev) ...@@ -355,6 +520,7 @@ static int turris_mox_rwtm_remove(struct platform_device *pdev)
{ {
struct mox_rwtm *rwtm = platform_get_drvdata(pdev); struct mox_rwtm *rwtm = platform_get_drvdata(pdev);
rwtm_unregister_debugfs(rwtm);
sysfs_remove_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs); sysfs_remove_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs);
kobject_put(rwtm_to_kobj(rwtm)); kobject_put(rwtm_to_kobj(rwtm));
mbox_free_channel(rwtm->mbox); mbox_free_channel(rwtm->mbox);
......
...@@ -487,6 +487,7 @@ static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc) ...@@ -487,6 +487,7 @@ static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc)
cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event); cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event);
cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event); cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event);
mtk_crtc_ddp_config(crtc, cmdq_handle); mtk_crtc_ddp_config(crtc, cmdq_handle);
cmdq_pkt_finalize(cmdq_handle);
cmdq_pkt_flush_async(cmdq_handle, ddp_cmdq_cb, cmdq_handle); cmdq_pkt_flush_async(cmdq_handle, ddp_cmdq_cb, cmdq_handle);
} }
#endif #endif
......
...@@ -559,6 +559,22 @@ static int geni_i2c_probe(struct platform_device *pdev) ...@@ -559,6 +559,22 @@ static int geni_i2c_probe(struct platform_device *pdev)
gi2c->adap.dev.of_node = dev->of_node; gi2c->adap.dev.of_node = dev->of_node;
strlcpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name)); strlcpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name));
ret = geni_icc_get(&gi2c->se, "qup-memory");
if (ret)
return ret;
/*
* Set the bus quota for core and cpu to a reasonable value for
* register access.
* Set quota for DDR based on bus speed.
*/
gi2c->se.icc_paths[GENI_TO_CORE].avg_bw = GENI_DEFAULT_BW;
gi2c->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW;
gi2c->se.icc_paths[GENI_TO_DDR].avg_bw = Bps_to_icc(gi2c->clk_freq_out);
ret = geni_icc_set_bw(&gi2c->se);
if (ret)
return ret;
ret = geni_se_resources_on(&gi2c->se); ret = geni_se_resources_on(&gi2c->se);
if (ret) { if (ret) {
dev_err(dev, "Error turning on resources %d\n", ret); dev_err(dev, "Error turning on resources %d\n", ret);
...@@ -581,6 +597,10 @@ static int geni_i2c_probe(struct platform_device *pdev) ...@@ -581,6 +597,10 @@ static int geni_i2c_probe(struct platform_device *pdev)
return ret; return ret;
} }
ret = geni_icc_disable(&gi2c->se);
if (ret)
return ret;
dev_dbg(dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth); dev_dbg(dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
gi2c->suspended = 1; gi2c->suspended = 1;
...@@ -625,7 +645,7 @@ static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev) ...@@ -625,7 +645,7 @@ static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev)
gi2c->suspended = 1; gi2c->suspended = 1;
} }
return 0; return geni_icc_disable(&gi2c->se);
} }
static int __maybe_unused geni_i2c_runtime_resume(struct device *dev) static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
...@@ -633,6 +653,10 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev) ...@@ -633,6 +653,10 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
int ret; int ret;
struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
ret = geni_icc_enable(&gi2c->se);
if (ret)
return ret;
ret = geni_se_resources_on(&gi2c->se); ret = geni_se_resources_on(&gi2c->se);
if (ret) if (ret)
return ret; return ret;
......
...@@ -266,11 +266,7 @@ int qcom_icc_bcm_voter_commit(struct bcm_voter *voter) ...@@ -266,11 +266,7 @@ int qcom_icc_bcm_voter_commit(struct bcm_voter *voter)
if (!commit_idx[0]) if (!commit_idx[0])
goto out; goto out;
ret = rpmh_invalidate(voter->dev); rpmh_invalidate(voter->dev);
if (ret) {
pr_err("Error invalidating RPMH client (%d)\n", ret);
goto out;
}
ret = rpmh_write_batch(voter->dev, RPMH_ACTIVE_ONLY_STATE, ret = rpmh_write_batch(voter->dev, RPMH_ACTIVE_ONLY_STATE,
cmds, commit_idx); cmds, commit_idx);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* Texas Instruments' K3 Interrupt Aggregator irqchip driver * Texas Instruments' K3 Interrupt Aggregator irqchip driver
* *
* Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2018-2019 Texas Instruments Incorporated - https://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com> * Lokesh Vutla <lokeshvutla@ti.com>
*/ */
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* Texas Instruments' K3 Interrupt Router irqchip driver * Texas Instruments' K3 Interrupt Router irqchip driver
* *
* Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2018-2019 Texas Instruments Incorporated - https://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com> * Lokesh Vutla <lokeshvutla@ti.com>
*/ */
......
...@@ -5,6 +5,12 @@ ...@@ -5,6 +5,12 @@
menuconfig MEMORY menuconfig MEMORY
bool "Memory Controller drivers" bool "Memory Controller drivers"
help
This option allows to enable specific memory controller drivers,
useful mostly on embedded systems. These could be controllers
for DRAM (SDR, DDR), ROM, SRAM and others. The drivers features
vary from memory tuning and frequency scaling to enabling
access to attached peripherals through memory bus.
if MEMORY if MEMORY
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
* - BE kernel + LE firmware image * - BE kernel + LE firmware image
* - BE kernel + BE firmware image * - BE kernel + BE firmware image
* *
* The DPCU always runs in big endian mode. The firwmare image, however, can * The DPCU always runs in big endian mode. The firmware image, however, can
* be in either format. Also, communication between host CPU and DCPU is * be in either format. Also, communication between host CPU and DCPU is
* always in little endian. * always in little endian.
*/ */
...@@ -188,7 +188,7 @@ struct brcmstb_dpfe_priv { ...@@ -188,7 +188,7 @@ struct brcmstb_dpfe_priv {
struct mutex lock; struct mutex lock;
}; };
static const char *error_text[] = { static const char * const error_text[] = {
"Success", "Header code incorrect", "Unknown command or argument", "Success", "Header code incorrect", "Unknown command or argument",
"Incorrect checksum", "Malformed command", "Timed out", "Incorrect checksum", "Malformed command", "Timed out",
}; };
...@@ -379,9 +379,8 @@ static void __iomem *get_msg_ptr(struct brcmstb_dpfe_priv *priv, u32 response, ...@@ -379,9 +379,8 @@ static void __iomem *get_msg_ptr(struct brcmstb_dpfe_priv *priv, u32 response,
void __iomem *ptr = NULL; void __iomem *ptr = NULL;
/* There is no need to use this function for API v3 or later. */ /* There is no need to use this function for API v3 or later. */
if (unlikely(priv->dpfe_api->version >= 3)) { if (unlikely(priv->dpfe_api->version >= 3))
return NULL; return NULL;
}
msg_type = (response >> DRAM_MSG_TYPE_OFFSET) & DRAM_MSG_TYPE_MASK; msg_type = (response >> DRAM_MSG_TYPE_OFFSET) & DRAM_MSG_TYPE_MASK;
offset = (response >> DRAM_MSG_ADDR_OFFSET) & DRAM_MSG_ADDR_MASK; offset = (response >> DRAM_MSG_ADDR_OFFSET) & DRAM_MSG_ADDR_MASK;
......
...@@ -66,6 +66,7 @@ struct l2_ctl_device_attribute { ...@@ -66,6 +66,7 @@ struct l2_ctl_device_attribute {
struct device_attribute dev_attr; struct device_attribute dev_attr;
enum l2_ctl_stall id; enum l2_ctl_stall id;
}; };
#define to_l2_ctl_dev_attr(_dev_attr) \ #define to_l2_ctl_dev_attr(_dev_attr) \
container_of(_dev_attr, struct l2_ctl_device_attribute, dev_attr) container_of(_dev_attr, struct l2_ctl_device_attribute, dev_attr)
...@@ -242,6 +243,7 @@ static ssize_t l2_ctl_latency_store(struct device *dev, ...@@ -242,6 +243,7 @@ static ssize_t l2_ctl_latency_store(struct device *dev,
return count; return count;
} }
static L2_CTL_ATTR_RW(l2_ws_latency, l2_ctl_latency, L2_WS_STALL); static L2_CTL_ATTR_RW(l2_ws_latency, l2_ctl_latency, L2_WS_STALL);
static L2_CTL_ATTR_RW(l2_tag_latency, l2_ctl_latency, L2_TAG_STALL); static L2_CTL_ATTR_RW(l2_tag_latency, l2_ctl_latency, L2_TAG_STALL);
static L2_CTL_ATTR_RW(l2_data_latency, l2_ctl_latency, L2_DATA_STALL); static L2_CTL_ATTR_RW(l2_data_latency, l2_ctl_latency, L2_DATA_STALL);
......
...@@ -102,14 +102,12 @@ static int da8xx_ddrctl_probe(struct platform_device *pdev) ...@@ -102,14 +102,12 @@ static int da8xx_ddrctl_probe(struct platform_device *pdev)
{ {
const struct da8xx_ddrctl_config_knob *knob; const struct da8xx_ddrctl_config_knob *knob;
const struct da8xx_ddrctl_setting *setting; const struct da8xx_ddrctl_setting *setting;
struct device_node *node;
struct resource *res; struct resource *res;
void __iomem *ddrctl; void __iomem *ddrctl;
struct device *dev; struct device *dev;
u32 reg; u32 reg;
dev = &pdev->dev; dev = &pdev->dev;
node = dev->of_node;
setting = da8xx_ddrctl_get_board_settings(); setting = da8xx_ddrctl_get_board_settings();
if (!setting) { if (!setting) {
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* TI AM33XX EMIF PM Assembly Offsets * TI AM33XX EMIF PM Assembly Offsets
* *
* Copyright (C) 2016-2017 Texas Instruments Inc. * Copyright (C) 2016-2017 Texas Instruments Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <linux/ti-emif-sram.h> #include <linux/ti-emif-sram.h>
......
...@@ -282,10 +282,9 @@ static void set_lpmode(struct emif_data *emif, u8 lpmode) ...@@ -282,10 +282,9 @@ static void set_lpmode(struct emif_data *emif, u8 lpmode)
* the EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE bit field to 0x4. * the EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE bit field to 0x4.
*/ */
if ((emif->plat_data->ip_rev == EMIF_4D) && if ((emif->plat_data->ip_rev == EMIF_4D) &&
(EMIF_LP_MODE_PWR_DN == lpmode)) { (lpmode == EMIF_LP_MODE_PWR_DN)) {
WARN_ONCE(1, WARN_ONCE(1,
"REG_LP_MODE = LP_MODE_PWR_DN(4) is prohibited by" "REG_LP_MODE = LP_MODE_PWR_DN(4) is prohibited by erratum i743 switch to LP_MODE_SELF_REFRESH(2)\n");
"erratum i743 switch to LP_MODE_SELF_REFRESH(2)\n");
/* rollback LP_MODE to Self-refresh mode */ /* rollback LP_MODE to Self-refresh mode */
lpmode = EMIF_LP_MODE_SELF_REFRESH; lpmode = EMIF_LP_MODE_SELF_REFRESH;
} }
...@@ -714,7 +713,7 @@ static u32 get_ext_phy_ctrl_2_intelliphy_4d5(void) ...@@ -714,7 +713,7 @@ static u32 get_ext_phy_ctrl_2_intelliphy_4d5(void)
u32 fifo_we_slave_ratio; u32 fifo_we_slave_ratio;
fifo_we_slave_ratio = DIV_ROUND_CLOSEST( fifo_we_slave_ratio = DIV_ROUND_CLOSEST(
EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck); EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256, t_ck);
return fifo_we_slave_ratio | fifo_we_slave_ratio << 11 | return fifo_we_slave_ratio | fifo_we_slave_ratio << 11 |
fifo_we_slave_ratio << 22; fifo_we_slave_ratio << 22;
...@@ -725,7 +724,7 @@ static u32 get_ext_phy_ctrl_3_intelliphy_4d5(void) ...@@ -725,7 +724,7 @@ static u32 get_ext_phy_ctrl_3_intelliphy_4d5(void)
u32 fifo_we_slave_ratio; u32 fifo_we_slave_ratio;
fifo_we_slave_ratio = DIV_ROUND_CLOSEST( fifo_we_slave_ratio = DIV_ROUND_CLOSEST(
EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck); EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256, t_ck);
return fifo_we_slave_ratio >> 10 | fifo_we_slave_ratio << 1 | return fifo_we_slave_ratio >> 10 | fifo_we_slave_ratio << 1 |
fifo_we_slave_ratio << 12 | fifo_we_slave_ratio << 23; fifo_we_slave_ratio << 12 | fifo_we_slave_ratio << 23;
...@@ -736,7 +735,7 @@ static u32 get_ext_phy_ctrl_4_intelliphy_4d5(void) ...@@ -736,7 +735,7 @@ static u32 get_ext_phy_ctrl_4_intelliphy_4d5(void)
u32 fifo_we_slave_ratio; u32 fifo_we_slave_ratio;
fifo_we_slave_ratio = DIV_ROUND_CLOSEST( fifo_we_slave_ratio = DIV_ROUND_CLOSEST(
EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck); EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256, t_ck);
return fifo_we_slave_ratio >> 9 | fifo_we_slave_ratio << 2 | return fifo_we_slave_ratio >> 9 | fifo_we_slave_ratio << 2 |
fifo_we_slave_ratio << 13; fifo_we_slave_ratio << 13;
...@@ -975,8 +974,7 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif) ...@@ -975,8 +974,7 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART)) { EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART)) {
if (emif->temperature_level >= SDRAM_TEMP_HIGH_DERATE_REFRESH) { if (emif->temperature_level >= SDRAM_TEMP_HIGH_DERATE_REFRESH) {
dev_err(emif->dev, dev_err(emif->dev,
"%s:NOT Extended temperature capable memory." "%s:NOT Extended temperature capable memory. Converting MR4=0x%02x as shutdown event\n",
"Converting MR4=0x%02x as shutdown event\n",
__func__, emif->temperature_level); __func__, emif->temperature_level);
/* /*
* Temperature far too high - do kernel_power_off() * Temperature far too high - do kernel_power_off()
...@@ -1318,9 +1316,9 @@ static void __init_or_module of_get_ddr_info(struct device_node *np_emif, ...@@ -1318,9 +1316,9 @@ static void __init_or_module of_get_ddr_info(struct device_node *np_emif,
if (of_find_property(np_emif, "cal-resistor-per-cs", &len)) if (of_find_property(np_emif, "cal-resistor-per-cs", &len))
dev_info->cal_resistors_per_cs = true; dev_info->cal_resistors_per_cs = true;
if (of_device_is_compatible(np_ddr , "jedec,lpddr2-s4")) if (of_device_is_compatible(np_ddr, "jedec,lpddr2-s4"))
dev_info->type = DDR_TYPE_LPDDR2_S4; dev_info->type = DDR_TYPE_LPDDR2_S4;
else if (of_device_is_compatible(np_ddr , "jedec,lpddr2-s2")) else if (of_device_is_compatible(np_ddr, "jedec,lpddr2-s2"))
dev_info->type = DDR_TYPE_LPDDR2_S2; dev_info->type = DDR_TYPE_LPDDR2_S2;
of_property_read_u32(np_ddr, "density", &density); of_property_read_u32(np_ddr, "density", &density);
...@@ -1563,11 +1561,8 @@ static int __init_or_module emif_probe(struct platform_device *pdev) ...@@ -1563,11 +1561,8 @@ static int __init_or_module emif_probe(struct platform_device *pdev)
goto error; goto error;
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0)
dev_err(emif->dev, "%s: error getting IRQ resource - %d\n",
__func__, irq);
goto error; goto error;
}
emif_onetime_settings(emif); emif_onetime_settings(emif);
emif_debugfs_init(emif); emif_debugfs_init(emif);
......
...@@ -53,6 +53,7 @@ int fsl_ifc_find(phys_addr_t addr_base) ...@@ -53,6 +53,7 @@ int fsl_ifc_find(phys_addr_t addr_base)
for (i = 0; i < fsl_ifc_ctrl_dev->banks; i++) { for (i = 0; i < fsl_ifc_ctrl_dev->banks; i++) {
u32 cspr = ifc_in32(&fsl_ifc_ctrl_dev->gregs->cspr_cs[i].cspr); u32 cspr = ifc_in32(&fsl_ifc_ctrl_dev->gregs->cspr_cs[i].cspr);
if (cspr & CSPR_V && (cspr & CSPR_BA) == if (cspr & CSPR_V && (cspr & CSPR_BA) ==
convert_ifc_address(addr_base)) convert_ifc_address(addr_base))
return i; return i;
...@@ -153,8 +154,8 @@ static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data) ...@@ -153,8 +154,8 @@ static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
/* read for chip select error */ /* read for chip select error */
cs_err = ifc_in32(&ifc->cm_evter_stat); cs_err = ifc_in32(&ifc->cm_evter_stat);
if (cs_err) { if (cs_err) {
dev_err(ctrl->dev, "transaction sent to IFC is not mapped to" dev_err(ctrl->dev, "transaction sent to IFC is not mapped to any memory bank 0x%08X\n",
"any memory bank 0x%08X\n", cs_err); cs_err);
/* clear the chip select error */ /* clear the chip select error */
ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat); ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat);
...@@ -163,24 +164,24 @@ static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data) ...@@ -163,24 +164,24 @@ static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
err_addr = ifc_in32(&ifc->cm_erattr1); err_addr = ifc_in32(&ifc->cm_erattr1);
if (status & IFC_CM_ERATTR0_ERTYP_READ) if (status & IFC_CM_ERATTR0_ERTYP_READ)
dev_err(ctrl->dev, "Read transaction error" dev_err(ctrl->dev, "Read transaction error CM_ERATTR0 0x%08X\n",
"CM_ERATTR0 0x%08X\n", status); status);
else else
dev_err(ctrl->dev, "Write transaction error" dev_err(ctrl->dev, "Write transaction error CM_ERATTR0 0x%08X\n",
"CM_ERATTR0 0x%08X\n", status); status);
err_axiid = (status & IFC_CM_ERATTR0_ERAID) >> err_axiid = (status & IFC_CM_ERATTR0_ERAID) >>
IFC_CM_ERATTR0_ERAID_SHIFT; IFC_CM_ERATTR0_ERAID_SHIFT;
dev_err(ctrl->dev, "AXI ID of the error" dev_err(ctrl->dev, "AXI ID of the error transaction 0x%08X\n",
"transaction 0x%08X\n", err_axiid); err_axiid);
err_srcid = (status & IFC_CM_ERATTR0_ESRCID) >> err_srcid = (status & IFC_CM_ERATTR0_ESRCID) >>
IFC_CM_ERATTR0_ESRCID_SHIFT; IFC_CM_ERATTR0_ESRCID_SHIFT;
dev_err(ctrl->dev, "SRC ID of the error" dev_err(ctrl->dev, "SRC ID of the error transaction 0x%08X\n",
"transaction 0x%08X\n", err_srcid); err_srcid);
dev_err(ctrl->dev, "Transaction Address corresponding to error" dev_err(ctrl->dev, "Transaction Address corresponding to error ERADDR 0x%08X\n",
"ERADDR 0x%08X\n", err_addr); err_addr);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
} }
...@@ -199,7 +200,7 @@ static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data) ...@@ -199,7 +200,7 @@ static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
* the resources needed for the controller only. The * the resources needed for the controller only. The
* resources for the NAND banks themselves are allocated * resources for the NAND banks themselves are allocated
* in the chip probe function. * in the chip probe function.
*/ */
static int fsl_ifc_ctrl_probe(struct platform_device *dev) static int fsl_ifc_ctrl_probe(struct platform_device *dev)
{ {
int ret = 0; int ret = 0;
...@@ -250,8 +251,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev) ...@@ -250,8 +251,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
/* get the Controller level irq */ /* get the Controller level irq */
fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0); fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
if (fsl_ifc_ctrl_dev->irq == 0) { if (fsl_ifc_ctrl_dev->irq == 0) {
dev_err(&dev->dev, "failed to get irq resource " dev_err(&dev->dev, "failed to get irq resource for IFC\n");
"for IFC\n");
ret = -ENODEV; ret = -ENODEV;
goto err; goto err;
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h>
#include <linux/math64.h> #include <linux/math64.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
...@@ -22,6 +23,8 @@ ...@@ -22,6 +23,8 @@
#define NEMC_SMCRn(n) (0x14 + (((n) - 1) * 4)) #define NEMC_SMCRn(n) (0x14 + (((n) - 1) * 4))
#define NEMC_NFCSR 0x50 #define NEMC_NFCSR 0x50
#define NEMC_REG_LEN 0x54
#define NEMC_SMCR_SMT BIT(0) #define NEMC_SMCR_SMT BIT(0)
#define NEMC_SMCR_BW_SHIFT 6 #define NEMC_SMCR_BW_SHIFT 6
#define NEMC_SMCR_BW_MASK (0x3 << NEMC_SMCR_BW_SHIFT) #define NEMC_SMCR_BW_MASK (0x3 << NEMC_SMCR_BW_SHIFT)
...@@ -288,7 +291,19 @@ static int jz4780_nemc_probe(struct platform_device *pdev) ...@@ -288,7 +291,19 @@ static int jz4780_nemc_probe(struct platform_device *pdev)
nemc->dev = dev; nemc->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nemc->base = devm_ioremap_resource(dev, res);
/*
* The driver currently only uses the registers up to offset
* NEMC_REG_LEN. Since the EFUSE registers are in the middle of the
* NEMC registers, we only request the registers we will use for now;
* that way the EFUSE driver can probe too.
*/
if (!devm_request_mem_region(dev, res->start, NEMC_REG_LEN, dev_name(dev))) {
dev_err(dev, "unable to request I/O memory region\n");
return -EBUSY;
}
nemc->base = devm_ioremap(dev, res->start, NEMC_REG_LEN);
if (IS_ERR(nemc->base)) { if (IS_ERR(nemc->base)) {
dev_err(dev, "failed to get I/O memory\n"); dev_err(dev, "failed to get I/O memory\n");
return PTR_ERR(nemc->base); return PTR_ERR(nemc->base);
......
...@@ -60,7 +60,7 @@ struct mtk_smi_common_plat { ...@@ -60,7 +60,7 @@ struct mtk_smi_common_plat {
struct mtk_smi_larb_gen { struct mtk_smi_larb_gen {
int port_in_larb[MTK_LARB_NR_MAX + 1]; int port_in_larb[MTK_LARB_NR_MAX + 1];
void (*config_port)(struct device *); void (*config_port)(struct device *dev);
unsigned int larb_direct_to_common_mask; unsigned int larb_direct_to_common_mask;
bool has_gals; bool has_gals;
}; };
......
This diff is collapsed.
This diff is collapsed.
...@@ -3,22 +3,23 @@ ...@@ -3,22 +3,23 @@
* OpenFirmware helpers for memory drivers * OpenFirmware helpers for memory drivers
* *
* Copyright (C) 2012 Texas Instruments, Inc. * Copyright (C) 2012 Texas Instruments, Inc.
* Copyright (C) 2020 Krzysztof Kozlowski <krzk@kernel.org>
*/ */
#ifndef __LINUX_MEMORY_OF_REG_H #ifndef __LINUX_MEMORY_OF_REG_H
#define __LINUX_MEMORY_OF_REG_H #define __LINUX_MEMORY_OF_REG_H
#if defined(CONFIG_OF) && defined(CONFIG_DDR) #if defined(CONFIG_OF) && defined(CONFIG_DDR)
extern const struct lpddr2_min_tck *of_get_min_tck(struct device_node *np, const struct lpddr2_min_tck *of_get_min_tck(struct device_node *np,
struct device *dev); struct device *dev);
extern const struct lpddr2_timings const struct lpddr2_timings *of_get_ddr_timings(struct device_node *np_ddr,
*of_get_ddr_timings(struct device_node *np_ddr, struct device *dev, struct device *dev,
u32 device_type, u32 *nr_frequencies); u32 device_type, u32 *nr_frequencies);
extern const struct lpddr3_min_tck const struct lpddr3_min_tck *of_lpddr3_get_min_tck(struct device_node *np,
*of_lpddr3_get_min_tck(struct device_node *np, struct device *dev); struct device *dev);
extern const struct lpddr3_timings const struct lpddr3_timings *
*of_lpddr3_get_ddr_timings(struct device_node *np_ddr, of_lpddr3_get_ddr_timings(struct device_node *np_ddr,
struct device *dev, u32 device_type, u32 *nr_frequencies); struct device *dev, u32 device_type, u32 *nr_frequencies);
#else #else
static inline const struct lpddr2_min_tck static inline const struct lpddr2_min_tck
*of_get_min_tck(struct device_node *np, struct device *dev) *of_get_min_tck(struct device_node *np, struct device *dev)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#define MC_EMEM_ARB_TIMING_W2W 0xbc #define MC_EMEM_ARB_TIMING_W2W 0xbc
#define MC_EMEM_ARB_TIMING_R2W 0xc0 #define MC_EMEM_ARB_TIMING_R2W 0xc0
#define MC_EMEM_ARB_TIMING_W2R 0xc4 #define MC_EMEM_ARB_TIMING_W2R 0xc4
#define MC_EMEM_ARB_MISC2 0xc8
#define MC_EMEM_ARB_DA_TURNS 0xd0 #define MC_EMEM_ARB_DA_TURNS 0xd0
#define MC_EMEM_ARB_DA_COVERS 0xd4 #define MC_EMEM_ARB_DA_COVERS 0xd4
#define MC_EMEM_ARB_MISC0 0xd8 #define MC_EMEM_ARB_MISC0 0xd8
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment