Merge tag 'char-misc-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char / misc driver updates from Greg KH: "Here is the big set of char/misc driver changes for 5.15-rc1. Lots of different driver subsystems are being updated in here, notably: - mhi subsystem update - fpga subsystem update - coresight/hwtracing subsystem update - interconnect subsystem update - nvmem subsystem update - parport drivers update - phy subsystem update - soundwire subsystem update and there are some other char/misc drivers being updated as well: - binder driver additions - new misc drivers - lkdtm driver updates - mei driver updates - sram driver updates - other minor driver updates. Note, there are no habanalabs driver updates in this pull request, that will probably come later before -rc1 is out in a different request. All of these have been in linux-next for a while with no reported problems" * tag 'char-misc-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (169 commits) Revert "bus: mhi: Add inbound buffers allocation flag" misc/pvpanic: fix set driver data VMCI: fix NULL pointer dereference when unmapping queue pair char: mware: fix returnvar.cocci warnings parport: remove non-zero check on count soundwire: cadence: do not extend reset delay soundwire: intel: conditionally exit clock stop mode on system suspend soundwire: intel: skip suspend/resume/wake when link was not started soundwire: intel: fix potential race condition during power down phy: qcom-qmp: Add support for SM6115 UFS phy dt-bindings: phy: qcom,qmp: Add SM6115 UFS PHY bindings phy: qmp: Provide unique clock names for DP clocks lkdtm: remove IDE_CORE_CP crashpoint lkdtm: replace SCSI_DISPATCH_CMD with SCSI_QUEUE_RQ coresight: Replace deprecated CPU-hotplug functions. Documentation: coresight: Add documentation for CoreSight config coresight: syscfg: Add initial configfs support coresight: config: Add preloaded configurations coresight: etm4x: Add complex configuration handlers to etmv4 coresight: etm-perf: Update to activate selected configuration ...
This commit is contained in:
15
Documentation/ABI/testing/sysfs-driver-ge-achc
Normal file
15
Documentation/ABI/testing/sysfs-driver-ge-achc
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
What: /sys/bus/spi/<dev>/update_firmware
|
||||||
|
Date: Jul 2021
|
||||||
|
Contact: sebastian.reichel@collabora.com
|
||||||
|
Description: Write 1 to this file to update the ACHC microcontroller
|
||||||
|
firmware via the EzPort interface. For this the kernel
|
||||||
|
will load "achc.bin" via the firmware API (so usually
|
||||||
|
from /lib/firmware). The write will block until the FW
|
||||||
|
has either been flashed successfully or an error occured.
|
||||||
|
|
||||||
|
What: /sys/bus/spi/<dev>/reset
|
||||||
|
Date: Jul 2021
|
||||||
|
Contact: sebastian.reichel@collabora.com
|
||||||
|
Description: This file represents the microcontroller's reset line.
|
||||||
|
1 means the reset line is asserted, 0 means it's not
|
||||||
|
asserted. The file is read and writable.
|
||||||
@@ -72,3 +72,16 @@ that the `rm() <rm_>`_ tool can be used to delete them. Note that the
|
|||||||
``binder-control`` device cannot be deleted since this would make the binderfs
|
``binder-control`` device cannot be deleted since this would make the binderfs
|
||||||
instance unusable. The ``binder-control`` device will be deleted when the
|
instance unusable. The ``binder-control`` device will be deleted when the
|
||||||
binderfs instance is unmounted and all references to it have been dropped.
|
binderfs instance is unmounted and all references to it have been dropped.
|
||||||
|
|
||||||
|
Binder features
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Assuming an instance of binderfs has been mounted at ``/dev/binderfs``, the
|
||||||
|
features supported by the binder driver can be located under
|
||||||
|
``/dev/binderfs/features/``. The presence of individual files can be tested
|
||||||
|
to determine whether a particular feature is supported by the driver.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
cat /dev/binderfs/features/oneway_spam_detection
|
||||||
|
1
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
-----------------------------------------------------------------
|
|
||||||
Device Tree Bindings for the Xilinx Zynq MPSoC Firmware Interface
|
|
||||||
-----------------------------------------------------------------
|
|
||||||
|
|
||||||
The zynqmp-firmware node describes the interface to platform firmware.
|
|
||||||
ZynqMP has an interface to communicate with secure firmware. Firmware
|
|
||||||
driver provides an interface to firmware APIs. Interface APIs can be
|
|
||||||
used by any driver to communicate to PMUFW(Platform Management Unit).
|
|
||||||
These requests include clock management, pin control, device control,
|
|
||||||
power management service, FPGA service and other platform management
|
|
||||||
services.
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: Must contain any of below:
|
|
||||||
"xlnx,zynqmp-firmware" for Zynq Ultrascale+ MPSoC
|
|
||||||
"xlnx,versal-firmware" for Versal
|
|
||||||
- method: The method of calling the PM-API firmware layer.
|
|
||||||
Permitted values are:
|
|
||||||
- "smc" : SMC #0, following the SMCCC
|
|
||||||
- "hvc" : HVC #0, following the SMCCC
|
|
||||||
|
|
||||||
-------
|
|
||||||
Example
|
|
||||||
-------
|
|
||||||
|
|
||||||
Zynq Ultrascale+ MPSoC
|
|
||||||
----------------------
|
|
||||||
firmware {
|
|
||||||
zynqmp_firmware: zynqmp-firmware {
|
|
||||||
compatible = "xlnx,zynqmp-firmware";
|
|
||||||
method = "smc";
|
|
||||||
...
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
Versal
|
|
||||||
------
|
|
||||||
firmware {
|
|
||||||
versal_firmware: versal-firmware {
|
|
||||||
compatible = "xlnx,versal-firmware";
|
|
||||||
method = "smc";
|
|
||||||
...
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/firmware/xilinx/xlnx,zynqmp-firmware.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Xilinx firmware driver
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Nava kishore Manne <nava.manne@xilinx.com>
|
||||||
|
|
||||||
|
description: The zynqmp-firmware node describes the interface to platform
|
||||||
|
firmware. ZynqMP has an interface to communicate with secure firmware.
|
||||||
|
Firmware driver provides an interface to firmware APIs. Interface APIs
|
||||||
|
can be used by any driver to communicate to PMUFW(Platform Management Unit).
|
||||||
|
These requests include clock management, pin control, device control,
|
||||||
|
power management service, FPGA service and other platform management
|
||||||
|
services.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
- description: For implementations complying for Zynq Ultrascale+ MPSoC.
|
||||||
|
const: xlnx,zynqmp-firmware
|
||||||
|
|
||||||
|
- description: For implementations complying for Versal.
|
||||||
|
const: xlnx,versal-firmware
|
||||||
|
|
||||||
|
method:
|
||||||
|
description: |
|
||||||
|
The method of calling the PM-API firmware layer.
|
||||||
|
Permitted values are.
|
||||||
|
- "smc" : SMC #0, following the SMCCC
|
||||||
|
- "hvc" : HVC #0, following the SMCCC
|
||||||
|
|
||||||
|
$ref: /schemas/types.yaml#/definitions/string-array
|
||||||
|
enum:
|
||||||
|
- smc
|
||||||
|
- hvc
|
||||||
|
|
||||||
|
versal_fpga:
|
||||||
|
$ref: /schemas/fpga/xlnx,versal-fpga.yaml#
|
||||||
|
description: Compatible of the FPGA device.
|
||||||
|
type: object
|
||||||
|
|
||||||
|
zynqmp-aes:
|
||||||
|
$ref: /schemas/crypto/xlnx,zynqmp-aes.yaml#
|
||||||
|
description: The ZynqMP AES-GCM hardened cryptographic accelerator is
|
||||||
|
used to encrypt or decrypt the data with provided key and initialization
|
||||||
|
vector.
|
||||||
|
type: object
|
||||||
|
|
||||||
|
clock-controller:
|
||||||
|
$ref: /schemas/clock/xlnx,versal-clk.yaml#
|
||||||
|
description: The clock controller is a hardware block of Xilinx versal
|
||||||
|
clock tree. It reads required input clock frequencies from the devicetree
|
||||||
|
and acts as clock provider for all clock consumers of PS clocks.list of
|
||||||
|
clock specifiers which are external input clocks to the given clock
|
||||||
|
controller.
|
||||||
|
type: object
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
versal-firmware {
|
||||||
|
compatible = "xlnx,versal-firmware";
|
||||||
|
method = "smc";
|
||||||
|
|
||||||
|
versal_fpga: versal_fpga {
|
||||||
|
compatible = "xlnx,versal-fpga";
|
||||||
|
};
|
||||||
|
|
||||||
|
xlnx_aes: zynqmp-aes {
|
||||||
|
compatible = "xlnx,zynqmp-aes";
|
||||||
|
};
|
||||||
|
|
||||||
|
versal_clk: clock-controller {
|
||||||
|
#clock-cells = <1>;
|
||||||
|
compatible = "xlnx,versal-clk";
|
||||||
|
clocks = <&ref>, <&alt_ref>, <&pl_alt_ref>;
|
||||||
|
clock-names = "ref", "alt_ref", "pl_alt_ref";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
||||||
33
Documentation/devicetree/bindings/fpga/xlnx,versal-fpga.yaml
Normal file
33
Documentation/devicetree/bindings/fpga/xlnx,versal-fpga.yaml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/fpga/xlnx,versal-fpga.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Xilinx Versal FPGA driver.
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Nava kishore Manne <nava.manne@xilinx.com>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
Device Tree Versal FPGA bindings for the Versal SoC, controlled
|
||||||
|
using firmware interface.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
items:
|
||||||
|
- enum:
|
||||||
|
- xlnx,versal-fpga
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
versal_fpga: versal_fpga {
|
||||||
|
compatible = "xlnx,versal-fpga";
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
||||||
@@ -18,6 +18,7 @@ properties:
|
|||||||
compatible:
|
compatible:
|
||||||
enum:
|
enum:
|
||||||
- qcom,sc7180-osm-l3
|
- qcom,sc7180-osm-l3
|
||||||
|
- qcom,sc8180x-osm-l3
|
||||||
- qcom,sdm845-osm-l3
|
- qcom,sdm845-osm-l3
|
||||||
- qcom,sm8150-osm-l3
|
- qcom,sm8150-osm-l3
|
||||||
- qcom,sm8250-epss-l3
|
- qcom,sm8250-epss-l3
|
||||||
|
|||||||
@@ -49,6 +49,17 @@ properties:
|
|||||||
- qcom,sc7280-mmss-noc
|
- qcom,sc7280-mmss-noc
|
||||||
- qcom,sc7280-nsp-noc
|
- qcom,sc7280-nsp-noc
|
||||||
- qcom,sc7280-system-noc
|
- qcom,sc7280-system-noc
|
||||||
|
- qcom,sc8180x-aggre1-noc
|
||||||
|
- qcom,sc8180x-aggre2-noc
|
||||||
|
- qcom,sc8180x-camnoc-virt
|
||||||
|
- qcom,sc8180x-compute-noc
|
||||||
|
- qcom,sc8180x-config-noc
|
||||||
|
- qcom,sc8180x-dc-noc
|
||||||
|
- qcom,sc8180x-gem-noc
|
||||||
|
- qcom,sc8180x-ipa-virt
|
||||||
|
- qcom,sc8180x-mc-virt
|
||||||
|
- qcom,sc8180x-mmss-noc
|
||||||
|
- qcom,sc8180x-system-noc
|
||||||
- qcom,sdm845-aggre1-noc
|
- qcom,sdm845-aggre1-noc
|
||||||
- qcom,sdm845-aggre2-noc
|
- qcom,sdm845-aggre2-noc
|
||||||
- qcom,sdm845-config-noc
|
- qcom,sdm845-config-noc
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
* GE Healthcare USB Management Controller
|
|
||||||
|
|
||||||
A device which handles data aquisition from compatible USB based peripherals.
|
|
||||||
SPI is used for device management.
|
|
||||||
|
|
||||||
Note: This device does not expose the peripherals as USB devices.
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
|
|
||||||
- compatible : Should be "ge,achc"
|
|
||||||
|
|
||||||
Required SPI properties:
|
|
||||||
|
|
||||||
- reg : Should be address of the device chip select within
|
|
||||||
the controller.
|
|
||||||
|
|
||||||
- spi-max-frequency : Maximum SPI clocking speed of device in Hz, should be
|
|
||||||
1MHz for the GE ACHC.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
spidev0: spi@0 {
|
|
||||||
compatible = "ge,achc";
|
|
||||||
reg = <0>;
|
|
||||||
spi-max-frequency = <1000000>;
|
|
||||||
};
|
|
||||||
65
Documentation/devicetree/bindings/misc/ge-achc.yaml
Normal file
65
Documentation/devicetree/bindings/misc/ge-achc.yaml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
|
||||||
|
# Copyright (C) 2021 GE Inc.
|
||||||
|
# Copyright (C) 2021 Collabora Ltd.
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/misc/ge-achc.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: GE Healthcare USB Management Controller
|
||||||
|
|
||||||
|
description: |
|
||||||
|
A device which handles data acquisition from compatible USB based peripherals.
|
||||||
|
SPI is used for device management.
|
||||||
|
|
||||||
|
Note: This device does not expose the peripherals as USB devices.
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Sebastian Reichel <sre@kernel.org>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
items:
|
||||||
|
- const: ge,achc
|
||||||
|
- const: nxp,kinetis-k20
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
vdd-supply:
|
||||||
|
description: Digital power supply regulator on VDD pin
|
||||||
|
|
||||||
|
vdda-supply:
|
||||||
|
description: Analog power supply regulator on VDDA pin
|
||||||
|
|
||||||
|
reg:
|
||||||
|
items:
|
||||||
|
- description: Control interface
|
||||||
|
- description: Firmware programming interface
|
||||||
|
|
||||||
|
reset-gpios:
|
||||||
|
description: GPIO used for hardware reset.
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- clocks
|
||||||
|
- reg
|
||||||
|
- reset-gpios
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/gpio/gpio.h>
|
||||||
|
spi {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
spi@1 {
|
||||||
|
compatible = "ge,achc", "nxp,kinetis-k20";
|
||||||
|
reg = <1>, <0>;
|
||||||
|
clocks = <&achc_24M>;
|
||||||
|
reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
|
||||||
|
};
|
||||||
|
};
|
||||||
44
Documentation/devicetree/bindings/nvmem/nintendo-otp.yaml
Normal file
44
Documentation/devicetree/bindings/nvmem/nintendo-otp.yaml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/nvmem/nintendo-otp.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Nintendo Wii and Wii U OTP Device Tree Bindings
|
||||||
|
|
||||||
|
description: |
|
||||||
|
This binding represents the OTP memory as found on a Nintendo Wii or Wii U,
|
||||||
|
which contains common and per-console keys, signatures and related data
|
||||||
|
required to access peripherals.
|
||||||
|
|
||||||
|
See https://wiiubrew.org/wiki/Hardware/OTP
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: "nvmem.yaml#"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- nintendo,hollywood-otp
|
||||||
|
- nintendo,latte-otp
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
|
||||||
|
unevaluatedProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
otp@d8001ec {
|
||||||
|
compatible = "nintendo,latte-otp";
|
||||||
|
reg = <0x0d8001ec 0x8>;
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
||||||
@@ -51,6 +51,9 @@ properties:
|
|||||||
vcc-supply:
|
vcc-supply:
|
||||||
description: Our power supply.
|
description: Our power supply.
|
||||||
|
|
||||||
|
power-domains:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
# Needed if any child nodes are present.
|
# Needed if any child nodes are present.
|
||||||
"#address-cells":
|
"#address-cells":
|
||||||
const: 1
|
const: 1
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
* Freescale i.MX8MQ USB3 PHY binding
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: Should be "fsl,imx8mq-usb-phy" or "fsl,imx8mp-usb-phy"
|
|
||||||
- #phys-cells: must be 0 (see phy-bindings.txt in this directory)
|
|
||||||
- reg: The base address and length of the registers
|
|
||||||
- clocks: phandles to the clocks for each clock listed in clock-names
|
|
||||||
- clock-names: must contain "phy"
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- vbus-supply: A phandle to the regulator for USB VBUS.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
usb3_phy0: phy@381f0040 {
|
|
||||||
compatible = "fsl,imx8mq-usb-phy";
|
|
||||||
reg = <0x381f0040 0x40>;
|
|
||||||
clocks = <&clk IMX8MQ_CLK_USB1_PHY_ROOT>;
|
|
||||||
clock-names = "phy";
|
|
||||||
#phy-cells = <0>;
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/phy/fsl,imx8mq-usb-phy.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Freescale i.MX8MQ USB3 PHY binding
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Li Jun <jun.li@nxp.com>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- fsl,imx8mq-usb-phy
|
||||||
|
- fsl,imx8mp-usb-phy
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
"#phy-cells":
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
items:
|
||||||
|
- const: phy
|
||||||
|
|
||||||
|
vbus-supply:
|
||||||
|
description:
|
||||||
|
A phandle to the regulator for USB VBUS.
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- "#phy-cells"
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/clock/imx8mq-clock.h>
|
||||||
|
usb3_phy0: phy@381f0040 {
|
||||||
|
compatible = "fsl,imx8mq-usb-phy";
|
||||||
|
reg = <0x381f0040 0x40>;
|
||||||
|
clocks = <&clk IMX8MQ_CLK_USB1_PHY_ROOT>;
|
||||||
|
clock-names = "phy";
|
||||||
|
#phy-cells = <0>;
|
||||||
|
};
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
%YAML 1.2
|
%YAML 1.2
|
||||||
---
|
---
|
||||||
$id: http://devicetree.org/schemas/phy/intel,phy-keembay-usb.yaml#
|
$id: http://devicetree.org/schemas/phy/intel,keembay-phy-usb.yaml#
|
||||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
title: Intel Keem Bay USB PHY bindings
|
title: Intel Keem Bay USB PHY bindings
|
||||||
@@ -15,7 +15,7 @@ description: |
|
|||||||
controllers on MediaTek SoCs, includes USB2.0, USB3.0, PCIe and SATA.
|
controllers on MediaTek SoCs, includes USB2.0, USB3.0, PCIe and SATA.
|
||||||
|
|
||||||
Layout differences of banks between T-PHY V1 (mt8173/mt2701) and
|
Layout differences of banks between T-PHY V1 (mt8173/mt2701) and
|
||||||
T-PHY V2 (mt2712) when works on USB mode:
|
T-PHY V2 (mt2712) / V3 (mt8195) when works on USB mode:
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
Version 1:
|
Version 1:
|
||||||
port offset bank
|
port offset bank
|
||||||
@@ -34,7 +34,7 @@ description: |
|
|||||||
u2 port2 0x1800 U2PHY_COM
|
u2 port2 0x1800 U2PHY_COM
|
||||||
...
|
...
|
||||||
|
|
||||||
Version 2:
|
Version 2/3:
|
||||||
port offset bank
|
port offset bank
|
||||||
u2 port0 0x0000 MISC
|
u2 port0 0x0000 MISC
|
||||||
0x0100 FMREG
|
0x0100 FMREG
|
||||||
@@ -59,7 +59,8 @@ description: |
|
|||||||
|
|
||||||
SPLLC shared by u3 ports and FMREG shared by u2 ports on V1 are put back
|
SPLLC shared by u3 ports and FMREG shared by u2 ports on V1 are put back
|
||||||
into each port; a new bank MISC for u2 ports and CHIP for u3 ports are
|
into each port; a new bank MISC for u2 ports and CHIP for u3 ports are
|
||||||
added on V2.
|
added on V2; the FMREG bank for slew rate calibration is not used anymore
|
||||||
|
and reserved on V3;
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
$nodename:
|
$nodename:
|
||||||
@@ -79,8 +80,11 @@ properties:
|
|||||||
- mediatek,mt2712-tphy
|
- mediatek,mt2712-tphy
|
||||||
- mediatek,mt7629-tphy
|
- mediatek,mt7629-tphy
|
||||||
- mediatek,mt8183-tphy
|
- mediatek,mt8183-tphy
|
||||||
- mediatek,mt8195-tphy
|
|
||||||
- const: mediatek,generic-tphy-v2
|
- const: mediatek,generic-tphy-v2
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- mediatek,mt8195-tphy
|
||||||
|
- const: mediatek,generic-tphy-v3
|
||||||
- const: mediatek,mt2701-u3phy
|
- const: mediatek,mt2701-u3phy
|
||||||
deprecated: true
|
deprecated: true
|
||||||
- const: mediatek,mt2712-u3phy
|
- const: mediatek,mt2712-u3phy
|
||||||
@@ -91,7 +95,7 @@ properties:
|
|||||||
description:
|
description:
|
||||||
Register shared by multiple ports, exclude port's private register.
|
Register shared by multiple ports, exclude port's private register.
|
||||||
It is needed for T-PHY V1, such as mt2701 and mt8173, but not for
|
It is needed for T-PHY V1, such as mt2701 and mt8173, but not for
|
||||||
T-PHY V2, such as mt2712.
|
T-PHY V2/V3, such as mt2712.
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
"#address-cells":
|
"#address-cells":
|
||||||
@@ -197,6 +201,22 @@ patternProperties:
|
|||||||
Specify the flag to enable BC1.2 if support it
|
Specify the flag to enable BC1.2 if support it
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|
||||||
|
mediatek,syscon-type:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||||
|
maxItems: 1
|
||||||
|
description:
|
||||||
|
A phandle to syscon used to access the register of type switch,
|
||||||
|
the field should always be 3 cells long.
|
||||||
|
items:
|
||||||
|
items:
|
||||||
|
- description:
|
||||||
|
The first cell represents a phandle to syscon
|
||||||
|
- description:
|
||||||
|
The second cell represents the register offset
|
||||||
|
- description:
|
||||||
|
The third cell represents the index of config segment
|
||||||
|
enum: [0, 1, 2, 3]
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- reg
|
- reg
|
||||||
- "#phy-cells"
|
- "#phy-cells"
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ properties:
|
|||||||
compatible:
|
compatible:
|
||||||
enum:
|
enum:
|
||||||
- qcom,ipq6018-qmp-pcie-phy
|
- qcom,ipq6018-qmp-pcie-phy
|
||||||
|
- qcom,ipq6018-qmp-usb3-phy
|
||||||
- qcom,ipq8074-qmp-pcie-phy
|
- qcom,ipq8074-qmp-pcie-phy
|
||||||
- qcom,ipq8074-qmp-usb3-phy
|
- qcom,ipq8074-qmp-usb3-phy
|
||||||
- qcom,msm8996-qmp-pcie-phy
|
- qcom,msm8996-qmp-pcie-phy
|
||||||
@@ -27,6 +28,7 @@ properties:
|
|||||||
- qcom,msm8998-qmp-ufs-phy
|
- qcom,msm8998-qmp-ufs-phy
|
||||||
- qcom,msm8998-qmp-usb3-phy
|
- qcom,msm8998-qmp-usb3-phy
|
||||||
- qcom,sc7180-qmp-usb3-phy
|
- qcom,sc7180-qmp-usb3-phy
|
||||||
|
- qcom,sc8180x-qmp-pcie-phy
|
||||||
- qcom,sc8180x-qmp-ufs-phy
|
- qcom,sc8180x-qmp-ufs-phy
|
||||||
- qcom,sc8180x-qmp-usb3-phy
|
- qcom,sc8180x-qmp-usb3-phy
|
||||||
- qcom,sdm845-qhp-pcie-phy
|
- qcom,sdm845-qhp-pcie-phy
|
||||||
@@ -34,6 +36,7 @@ properties:
|
|||||||
- qcom,sdm845-qmp-ufs-phy
|
- qcom,sdm845-qmp-ufs-phy
|
||||||
- qcom,sdm845-qmp-usb3-phy
|
- qcom,sdm845-qmp-usb3-phy
|
||||||
- qcom,sdm845-qmp-usb3-uni-phy
|
- qcom,sdm845-qmp-usb3-uni-phy
|
||||||
|
- qcom,sm6115-qmp-ufs-phy
|
||||||
- qcom,sm8150-qmp-ufs-phy
|
- qcom,sm8150-qmp-ufs-phy
|
||||||
- qcom,sm8150-qmp-usb3-phy
|
- qcom,sm8150-qmp-usb3-phy
|
||||||
- qcom,sm8150-qmp-usb3-uni-phy
|
- qcom,sm8150-qmp-usb3-uni-phy
|
||||||
@@ -326,6 +329,7 @@ allOf:
|
|||||||
compatible:
|
compatible:
|
||||||
contains:
|
contains:
|
||||||
enum:
|
enum:
|
||||||
|
- qcom,sc8180x-qmp-pcie-phy
|
||||||
- qcom,sdm845-qhp-pcie-phy
|
- qcom,sdm845-qhp-pcie-phy
|
||||||
- qcom,sdm845-qmp-pcie-phy
|
- qcom,sdm845-qmp-pcie-phy
|
||||||
- qcom,sdx55-qmp-pcie-phy
|
- qcom,sdx55-qmp-pcie-phy
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ properties:
|
|||||||
compatible:
|
compatible:
|
||||||
enum:
|
enum:
|
||||||
- qcom,sc7180-qmp-usb3-dp-phy
|
- qcom,sc7180-qmp-usb3-dp-phy
|
||||||
|
- qcom,sc8180x-qmp-usb3-dp-phy
|
||||||
- qcom,sdm845-qmp-usb3-dp-phy
|
- qcom,sdm845-qmp-usb3-dp-phy
|
||||||
- qcom,sm8250-qmp-usb3-dp-phy
|
- qcom,sm8250-qmp-usb3-dp-phy
|
||||||
reg:
|
reg:
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ properties:
|
|||||||
- renesas,usb2-phy-r8a77995 # R-Car D3
|
- renesas,usb2-phy-r8a77995 # R-Car D3
|
||||||
- const: renesas,rcar-gen3-usb2-phy
|
- const: renesas,rcar-gen3-usb2-phy
|
||||||
|
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- renesas,usb2-phy-r9a07g044 # RZ/G2{L,LC}
|
||||||
|
- const: renesas,rzg2l-usb2-phy # RZ/G2L family
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
@@ -91,6 +96,16 @@ required:
|
|||||||
- clocks
|
- clocks
|
||||||
- '#phy-cells'
|
- '#phy-cells'
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
const: renesas,rzg2l-usb2-phy
|
||||||
|
then:
|
||||||
|
required:
|
||||||
|
- resets
|
||||||
|
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ properties:
|
|||||||
compatible:
|
compatible:
|
||||||
enum:
|
enum:
|
||||||
- samsung,exynos7-ufs-phy
|
- samsung,exynos7-ufs-phy
|
||||||
|
- samsung,exynosautov9-ufs-phy
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
TI AM654 SERDES
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: Should be "ti,phy-am654-serdes"
|
|
||||||
- reg : Address and length of the register set for the device.
|
|
||||||
- #phy-cells: determine the number of cells that should be given in the
|
|
||||||
phandle while referencing this phy. Should be "2". The 1st cell
|
|
||||||
corresponds to the phy type (should be one of the types specified in
|
|
||||||
include/dt-bindings/phy/phy.h) and the 2nd cell should be the serdes
|
|
||||||
lane function.
|
|
||||||
If SERDES0 is referenced 2nd cell should be:
|
|
||||||
0 - USB3
|
|
||||||
1 - PCIe0 Lane0
|
|
||||||
2 - ICSS2 SGMII Lane0
|
|
||||||
If SERDES1 is referenced 2nd cell should be:
|
|
||||||
0 - PCIe1 Lane0
|
|
||||||
1 - PCIe0 Lane1
|
|
||||||
2 - ICSS2 SGMII Lane1
|
|
||||||
- power-domains: As documented by the generic PM domain bindings in
|
|
||||||
Documentation/devicetree/bindings/power/power_domain.txt.
|
|
||||||
- clocks: List of clock-specifiers representing the input to the SERDES.
|
|
||||||
Should have 3 items representing the left input clock, external
|
|
||||||
reference clock and right input clock in that order.
|
|
||||||
- clock-output-names: List of clock names for each of the clock outputs of
|
|
||||||
SERDES. Should have 3 items for CMU reference clock,
|
|
||||||
left output clock and right output clock in that order.
|
|
||||||
- assigned-clocks: As defined in
|
|
||||||
Documentation/devicetree/bindings/clock/clock-bindings.txt
|
|
||||||
- assigned-clock-parents: As defined in
|
|
||||||
Documentation/devicetree/bindings/clock/clock-bindings.txt
|
|
||||||
- #clock-cells: Should be <1> to choose between the 3 output clocks.
|
|
||||||
Defined in Documentation/devicetree/bindings/clock/clock-bindings.txt
|
|
||||||
|
|
||||||
The following macros are defined in dt-bindings/phy/phy-am654-serdes.h
|
|
||||||
for selecting the correct reference clock. This can be used while
|
|
||||||
specifying the clocks created by SERDES.
|
|
||||||
=> AM654_SERDES_CMU_REFCLK
|
|
||||||
=> AM654_SERDES_LO_REFCLK
|
|
||||||
=> AM654_SERDES_RO_REFCLK
|
|
||||||
|
|
||||||
- mux-controls: Phandle to the multiplexer that is used to select the lane
|
|
||||||
function. See #phy-cells above to see the multiplex values.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
Example for SERDES0 is given below. It has 3 clock inputs;
|
|
||||||
left input reference clock as indicated by <&k3_clks 153 4>, external
|
|
||||||
reference clock as indicated by <&k3_clks 153 1> and right input
|
|
||||||
reference clock as indicated by <&serdes1 AM654_SERDES_LO_REFCLK>. (The
|
|
||||||
right input of SERDES0 is connected to the left output of SERDES1).
|
|
||||||
|
|
||||||
SERDES0 registers 3 clock outputs as indicated in clock-output-names. The
|
|
||||||
first refers to the CMU reference clock, second refers to the left output
|
|
||||||
reference clock and the third refers to the right output reference clock.
|
|
||||||
|
|
||||||
The assigned-clocks and assigned-clock-parents is used here to set the
|
|
||||||
parent of left input reference clock to MAINHSDIV_CLKOUT4 and parent of
|
|
||||||
CMU reference clock to left input reference clock.
|
|
||||||
|
|
||||||
serdes0: serdes@900000 {
|
|
||||||
compatible = "ti,phy-am654-serdes";
|
|
||||||
reg = <0x0 0x900000 0x0 0x2000>;
|
|
||||||
reg-names = "serdes";
|
|
||||||
#phy-cells = <2>;
|
|
||||||
power-domains = <&k3_pds 153>;
|
|
||||||
clocks = <&k3_clks 153 4>, <&k3_clks 153 1>,
|
|
||||||
<&serdes1 AM654_SERDES_LO_REFCLK>;
|
|
||||||
clock-output-names = "serdes0_cmu_refclk", "serdes0_lo_refclk",
|
|
||||||
"serdes0_ro_refclk";
|
|
||||||
assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>;
|
|
||||||
assigned-clock-parents = <&k3_clks 153 8>, <&k3_clks 153 4>;
|
|
||||||
ti,serdes-clk = <&serdes0_clk>;
|
|
||||||
mux-controls = <&serdes_mux 0>;
|
|
||||||
#clock-cells = <1>;
|
|
||||||
};
|
|
||||||
|
|
||||||
Example for PCIe consumer node using the SERDES PHY specifier is given below.
|
|
||||||
&pcie0_rc {
|
|
||||||
num-lanes = <2>;
|
|
||||||
phys = <&serdes0 PHY_TYPE_PCIE 1>, <&serdes1 PHY_TYPE_PCIE 1>;
|
|
||||||
phy-names = "pcie-phy0", "pcie-phy1";
|
|
||||||
};
|
|
||||||
103
Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml
Normal file
103
Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/phy/ti,phy-am654-serdes.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: TI AM654 SERDES binding
|
||||||
|
|
||||||
|
description:
|
||||||
|
This binding describes the TI AM654 SERDES. AM654 SERDES can be configured
|
||||||
|
to be used with either PCIe or USB or SGMII.
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Kishon Vijay Abraham I <kishon@ti.com>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- ti,phy-am654-serdes
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
reg-names:
|
||||||
|
items:
|
||||||
|
- const: serdes
|
||||||
|
|
||||||
|
power-domains:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 3
|
||||||
|
description:
|
||||||
|
Three input clocks referring to left input reference clock, refclk and right input reference
|
||||||
|
clock.
|
||||||
|
|
||||||
|
assigned-clocks:
|
||||||
|
$ref: "/schemas/types.yaml#/definitions/phandle-array"
|
||||||
|
assigned-clock-parents:
|
||||||
|
$ref: "/schemas/types.yaml#/definitions/phandle-array"
|
||||||
|
|
||||||
|
'#phy-cells':
|
||||||
|
const: 2
|
||||||
|
description:
|
||||||
|
The 1st cell corresponds to the phy type (should be one of the types specified in
|
||||||
|
include/dt-bindings/phy/phy.h) and the 2nd cell should be the serdes lane function.
|
||||||
|
|
||||||
|
ti,serdes-clk:
|
||||||
|
description: Phandle to the SYSCON entry required for configuring SERDES clock selection.
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
|
||||||
|
'#clock-cells':
|
||||||
|
const: 1
|
||||||
|
|
||||||
|
mux-controls:
|
||||||
|
maxItems: 1
|
||||||
|
description: Phandle to the SYSCON entry required for configuring SERDES lane function.
|
||||||
|
|
||||||
|
clock-output-names:
|
||||||
|
oneOf:
|
||||||
|
- description: Clock output names for SERDES 0
|
||||||
|
items:
|
||||||
|
- const: serdes0_cmu_refclk
|
||||||
|
- const: serdes0_lo_refclk
|
||||||
|
- const: serdes0_ro_refclk
|
||||||
|
- description: Clock output names for SERDES 1
|
||||||
|
items:
|
||||||
|
- const: serdes1_cmu_refclk
|
||||||
|
- const: serdes1_lo_refclk
|
||||||
|
- const: serdes1_ro_refclk
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- power-domains
|
||||||
|
- clocks
|
||||||
|
- assigned-clocks
|
||||||
|
- assigned-clock-parents
|
||||||
|
- ti,serdes-clk
|
||||||
|
- mux-controls
|
||||||
|
- clock-output-names
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/phy/phy-am654-serdes.h>
|
||||||
|
|
||||||
|
serdes0: serdes@900000 {
|
||||||
|
compatible = "ti,phy-am654-serdes";
|
||||||
|
reg = <0x900000 0x2000>;
|
||||||
|
reg-names = "serdes";
|
||||||
|
#phy-cells = <2>;
|
||||||
|
power-domains = <&k3_pds 153>;
|
||||||
|
clocks = <&k3_clks 153 4>, <&k3_clks 153 1>,
|
||||||
|
<&serdes1 AM654_SERDES_LO_REFCLK>;
|
||||||
|
clock-output-names = "serdes0_cmu_refclk", "serdes0_lo_refclk", "serdes0_ro_refclk";
|
||||||
|
assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>;
|
||||||
|
assigned-clock-parents = <&k3_clks 153 8>, <&k3_clks 153 4>;
|
||||||
|
ti,serdes-clk = <&serdes0_clk>;
|
||||||
|
mux-controls = <&serdes_mux 0>;
|
||||||
|
#clock-cells = <1>;
|
||||||
|
};
|
||||||
@@ -4,11 +4,11 @@ FPGA Bridge
|
|||||||
API to implement a new FPGA bridge
|
API to implement a new FPGA bridge
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
* struct fpga_bridge — The FPGA Bridge structure
|
* struct fpga_bridge - The FPGA Bridge structure
|
||||||
* struct fpga_bridge_ops — Low level Bridge driver ops
|
* struct fpga_bridge_ops - Low level Bridge driver ops
|
||||||
* devm_fpga_bridge_create() — Allocate and init a bridge struct
|
* devm_fpga_bridge_create() - Allocate and init a bridge struct
|
||||||
* fpga_bridge_register() — Register a bridge
|
* fpga_bridge_register() - Register a bridge
|
||||||
* fpga_bridge_unregister() — Unregister a bridge
|
* fpga_bridge_unregister() - Unregister a bridge
|
||||||
|
|
||||||
.. kernel-doc:: include/linux/fpga/fpga-bridge.h
|
.. kernel-doc:: include/linux/fpga/fpga-bridge.h
|
||||||
:functions: fpga_bridge
|
:functions: fpga_bridge
|
||||||
|
|||||||
@@ -101,12 +101,12 @@ in state.
|
|||||||
API for implementing a new FPGA Manager driver
|
API for implementing a new FPGA Manager driver
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
* ``fpga_mgr_states`` — Values for :c:expr:`fpga_manager->state`.
|
* ``fpga_mgr_states`` - Values for :c:expr:`fpga_manager->state`.
|
||||||
* struct fpga_manager — the FPGA manager struct
|
* struct fpga_manager - the FPGA manager struct
|
||||||
* struct fpga_manager_ops — Low level FPGA manager driver ops
|
* struct fpga_manager_ops - Low level FPGA manager driver ops
|
||||||
* devm_fpga_mgr_create() — Allocate and init a manager struct
|
* devm_fpga_mgr_create() - Allocate and init a manager struct
|
||||||
* fpga_mgr_register() — Register an FPGA manager
|
* fpga_mgr_register() - Register an FPGA manager
|
||||||
* fpga_mgr_unregister() — Unregister an FPGA manager
|
* fpga_mgr_unregister() - Unregister an FPGA manager
|
||||||
|
|
||||||
.. kernel-doc:: include/linux/fpga/fpga-mgr.h
|
.. kernel-doc:: include/linux/fpga/fpga-mgr.h
|
||||||
:functions: fpga_mgr_states
|
:functions: fpga_mgr_states
|
||||||
|
|||||||
@@ -84,10 +84,10 @@ will generate that list. Here's some sample code of what to do next::
|
|||||||
API for programming an FPGA
|
API for programming an FPGA
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
* fpga_region_program_fpga() — Program an FPGA
|
* fpga_region_program_fpga() - Program an FPGA
|
||||||
* fpga_image_info() — Specifies what FPGA image to program
|
* fpga_image_info() - Specifies what FPGA image to program
|
||||||
* fpga_image_info_alloc() — Allocate an FPGA image info struct
|
* fpga_image_info_alloc() - Allocate an FPGA image info struct
|
||||||
* fpga_image_info_free() — Free an FPGA image info struct
|
* fpga_image_info_free() - Free an FPGA image info struct
|
||||||
|
|
||||||
.. kernel-doc:: drivers/fpga/fpga-region.c
|
.. kernel-doc:: drivers/fpga/fpga-region.c
|
||||||
:functions: fpga_region_program_fpga
|
:functions: fpga_region_program_fpga
|
||||||
|
|||||||
@@ -45,19 +45,19 @@ An example of usage can be seen in the probe function of [#f2]_.
|
|||||||
API to add a new FPGA region
|
API to add a new FPGA region
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
* struct fpga_region — The FPGA region struct
|
* struct fpga_region - The FPGA region struct
|
||||||
* devm_fpga_region_create() — Allocate and init a region struct
|
* devm_fpga_region_create() - Allocate and init a region struct
|
||||||
* fpga_region_register() — Register an FPGA region
|
* fpga_region_register() - Register an FPGA region
|
||||||
* fpga_region_unregister() — Unregister an FPGA region
|
* fpga_region_unregister() - Unregister an FPGA region
|
||||||
|
|
||||||
The FPGA region's probe function will need to get a reference to the FPGA
|
The FPGA region's probe function will need to get a reference to the FPGA
|
||||||
Manager it will be using to do the programming. This usually would happen
|
Manager it will be using to do the programming. This usually would happen
|
||||||
during the region's probe function.
|
during the region's probe function.
|
||||||
|
|
||||||
* fpga_mgr_get() — Get a reference to an FPGA manager, raise ref count
|
* fpga_mgr_get() - Get a reference to an FPGA manager, raise ref count
|
||||||
* of_fpga_mgr_get() — Get a reference to an FPGA manager, raise ref count,
|
* of_fpga_mgr_get() - Get a reference to an FPGA manager, raise ref count,
|
||||||
given a device node.
|
given a device node.
|
||||||
* fpga_mgr_put() — Put an FPGA manager
|
* fpga_mgr_put() - Put an FPGA manager
|
||||||
|
|
||||||
The FPGA region will need to specify which bridges to control while programming
|
The FPGA region will need to specify which bridges to control while programming
|
||||||
the FPGA. The region driver can build a list of bridges during probe time
|
the FPGA. The region driver can build a list of bridges during probe time
|
||||||
@@ -66,11 +66,11 @@ the list of bridges to program just before programming
|
|||||||
(:c:expr:`fpga_region->get_bridges`). The FPGA bridge framework supplies the
|
(:c:expr:`fpga_region->get_bridges`). The FPGA bridge framework supplies the
|
||||||
following APIs to handle building or tearing down that list.
|
following APIs to handle building or tearing down that list.
|
||||||
|
|
||||||
* fpga_bridge_get_to_list() — Get a ref of an FPGA bridge, add it to a
|
* fpga_bridge_get_to_list() - Get a ref of an FPGA bridge, add it to a
|
||||||
list
|
list
|
||||||
* of_fpga_bridge_get_to_list() — Get a ref of an FPGA bridge, add it to a
|
* of_fpga_bridge_get_to_list() - Get a ref of an FPGA bridge, add it to a
|
||||||
list, given a device node
|
list, given a device node
|
||||||
* fpga_bridges_put() — Given a list of bridges, put them
|
* fpga_bridges_put() - Given a list of bridges, put them
|
||||||
|
|
||||||
.. kernel-doc:: include/linux/fpga/fpga-region.h
|
.. kernel-doc:: include/linux/fpga/fpga-region.h
|
||||||
:functions: fpga_region
|
:functions: fpga_region
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ recur_count
|
|||||||
cpoint_name
|
cpoint_name
|
||||||
Where in the kernel to trigger the action. It can be
|
Where in the kernel to trigger the action. It can be
|
||||||
one of INT_HARDWARE_ENTRY, INT_HW_IRQ_EN, INT_TASKLET_ENTRY,
|
one of INT_HARDWARE_ENTRY, INT_HW_IRQ_EN, INT_TASKLET_ENTRY,
|
||||||
FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_DISPATCH_CMD,
|
FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_QUEUE_RQ, or DIRECT.
|
||||||
IDE_CORE_CP, or DIRECT
|
|
||||||
|
|
||||||
cpoint_type
|
cpoint_type
|
||||||
Indicates the action to be taken on hitting the crash point.
|
Indicates the action to be taken on hitting the crash point.
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Authors:
|
|||||||
- Xu Yilun <yilun.xu@intel.com>
|
- Xu Yilun <yilun.xu@intel.com>
|
||||||
|
|
||||||
The Device Feature List (DFL) FPGA framework (and drivers according to
|
The Device Feature List (DFL) FPGA framework (and drivers according to
|
||||||
this framework) hides the very details of low layer hardwares and provides
|
this framework) hides the very details of low layer hardware and provides
|
||||||
unified interfaces to userspace. Applications could use these interfaces to
|
unified interfaces to userspace. Applications could use these interfaces to
|
||||||
configure, enumerate, open and access FPGA accelerators on platforms which
|
configure, enumerate, open and access FPGA accelerators on platforms which
|
||||||
implement the DFL in the device memory. Besides this, the DFL framework
|
implement the DFL in the device memory. Besides this, the DFL framework
|
||||||
@@ -205,7 +205,7 @@ given Device Feature Lists and create platform devices for feature devices
|
|||||||
also abstracts operations for the private features and exposes common ops to
|
also abstracts operations for the private features and exposes common ops to
|
||||||
feature device drivers.
|
feature device drivers.
|
||||||
|
|
||||||
The FPGA DFL Device could be different hardwares, e.g. PCIe device, platform
|
The FPGA DFL Device could be different hardware, e.g. PCIe device, platform
|
||||||
device and etc. Its driver module is always loaded first once the device is
|
device and etc. Its driver module is always loaded first once the device is
|
||||||
created by the system. This driver plays an infrastructural role in the
|
created by the system. This driver plays an infrastructural role in the
|
||||||
driver architecture. It locates the DFLs in the device memory, handles them
|
driver architecture. It locates the DFLs in the device memory, handles them
|
||||||
|
|||||||
244
Documentation/trace/coresight/coresight-config.rst
Normal file
244
Documentation/trace/coresight/coresight-config.rst
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
======================================
|
||||||
|
CoreSight System Configuration Manager
|
||||||
|
======================================
|
||||||
|
|
||||||
|
:Author: Mike Leach <mike.leach@linaro.org>
|
||||||
|
:Date: October 2020
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
The CoreSight System Configuration manager is an API that allows the
|
||||||
|
programming of the CoreSight system with pre-defined configurations that
|
||||||
|
can then be easily enabled from sysfs or perf.
|
||||||
|
|
||||||
|
Many CoreSight components can be programmed in complex ways - especially ETMs.
|
||||||
|
In addition, components can interact across the CoreSight system, often via
|
||||||
|
the cross trigger components such as CTI and CTM. These system settings can
|
||||||
|
be defined and enabled as named configurations.
|
||||||
|
|
||||||
|
|
||||||
|
Basic Concepts
|
||||||
|
==============
|
||||||
|
|
||||||
|
This section introduces the basic concepts of a CoreSight system configuration.
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
A feature is a named set of programming for a CoreSight device. The programming
|
||||||
|
is device dependent, and can be defined in terms of absolute register values,
|
||||||
|
resource usage and parameter values.
|
||||||
|
|
||||||
|
The feature is defined using a descriptor. This descriptor is used to load onto
|
||||||
|
a matching device, either when the feature is loaded into the system, or when the
|
||||||
|
CoreSight device is registered with the configuration manager.
|
||||||
|
|
||||||
|
The load process involves interpreting the descriptor into a set of register
|
||||||
|
accesses in the driver - the resource usage and parameter descriptions
|
||||||
|
translated into appropriate register accesses. This interpretation makes it easy
|
||||||
|
and efficient for the feature to be programmed onto the device when required.
|
||||||
|
|
||||||
|
The feature will not be active on the device until the feature is enabled, and
|
||||||
|
the device itself is enabled. When the device is enabled then enabled features
|
||||||
|
will be programmed into the device hardware.
|
||||||
|
|
||||||
|
A feature is enabled as part of a configuration being enabled on the system.
|
||||||
|
|
||||||
|
|
||||||
|
Parameter Value
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
A parameter value is a named value that may be set by the user prior to the
|
||||||
|
feature being enabled that can adjust the behaviour of the operation programmed
|
||||||
|
by the feature.
|
||||||
|
|
||||||
|
For example, this could be a count value in a programmed operation that repeats
|
||||||
|
at a given rate. When the feature is enabled then the current value of the
|
||||||
|
parameter is used in programming the device.
|
||||||
|
|
||||||
|
The feature descriptor defines a default value for a parameter, which is used
|
||||||
|
if the user does not supply a new value.
|
||||||
|
|
||||||
|
Users can update parameter values using the configfs API for the CoreSight
|
||||||
|
system - which is described below.
|
||||||
|
|
||||||
|
The current value of the parameter is loaded into the device when the feature
|
||||||
|
is enabled on that device.
|
||||||
|
|
||||||
|
|
||||||
|
Configurations
|
||||||
|
--------------
|
||||||
|
|
||||||
|
A configuration defines a set of features that are to be used in a trace
|
||||||
|
session where the configuration is selected. For any trace session only one
|
||||||
|
configuration may be selected.
|
||||||
|
|
||||||
|
The features defined may be on any type of device that is registered
|
||||||
|
to support system configuration. A configuration may select features to be
|
||||||
|
enabled on a class of devices - i.e. any ETMv4, or specific devices, e.g. a
|
||||||
|
specific CTI on the system.
|
||||||
|
|
||||||
|
As with the feature, a descriptor is used to define the configuration.
|
||||||
|
This will define the features that must be enabled as part of the configuration
|
||||||
|
as well as any preset values that can be used to override default parameter
|
||||||
|
values.
|
||||||
|
|
||||||
|
|
||||||
|
Preset Values
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Preset values are easily selectable sets of parameter values for the features
|
||||||
|
that the configuration uses. The number of values in a single preset set, equals
|
||||||
|
the sum of parameter values in the features used by the configuration.
|
||||||
|
|
||||||
|
e.g. a configuration consists of 3 features, one has 2 parameters, one has
|
||||||
|
a single parameter, and another has no parameters. A single preset set will
|
||||||
|
therefore have 3 values.
|
||||||
|
|
||||||
|
Presets are optionally defined by the configuration, up to 15 can be defined.
|
||||||
|
If no preset is selected, then the parameter values defined in the feature
|
||||||
|
are used as normal.
|
||||||
|
|
||||||
|
|
||||||
|
Operation
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
The following steps take place in the operation of a configuration.
|
||||||
|
|
||||||
|
1) In this example, the configuration is 'autofdo', which has an
|
||||||
|
associated feature 'strobing' that works on ETMv4 CoreSight Devices.
|
||||||
|
|
||||||
|
2) The configuration is enabled. For example 'perf' may select the
|
||||||
|
configuration as part of its command line::
|
||||||
|
|
||||||
|
perf record -e cs_etm/autofdo/ myapp
|
||||||
|
|
||||||
|
which will enable the 'autofdo' configuration.
|
||||||
|
|
||||||
|
3) perf starts tracing on the system. As each ETMv4 that perf uses for
|
||||||
|
trace is enabled, the configuration manager will check if the ETMv4
|
||||||
|
has a feature that relates to the currently active configuration.
|
||||||
|
In this case 'strobing' is enabled & programmed into the ETMv4.
|
||||||
|
|
||||||
|
4) When the ETMv4 is disabled, any registers marked as needing to be
|
||||||
|
saved will be read back.
|
||||||
|
|
||||||
|
5) At the end of the perf session, the configuration will be disabled.
|
||||||
|
|
||||||
|
|
||||||
|
Viewing Configurations and Features
|
||||||
|
===================================
|
||||||
|
|
||||||
|
The set of configurations and features that are currently loaded into the
|
||||||
|
system can be viewed using the configfs API.
|
||||||
|
|
||||||
|
Mount configfs as normal and the 'cs-syscfg' subsystem will appear::
|
||||||
|
|
||||||
|
$ ls /config
|
||||||
|
cs-syscfg stp-policy
|
||||||
|
|
||||||
|
This has two sub-directories::
|
||||||
|
|
||||||
|
$ cd cs-syscfg/
|
||||||
|
$ ls
|
||||||
|
configurations features
|
||||||
|
|
||||||
|
The system has the configuration 'autofdo' built in. It may be examined as
|
||||||
|
follows::
|
||||||
|
|
||||||
|
$ cd configurations/
|
||||||
|
$ ls
|
||||||
|
autofdo
|
||||||
|
$ cd autofdo/
|
||||||
|
$ ls
|
||||||
|
description preset1 preset3 preset5 preset7 preset9
|
||||||
|
feature_refs preset2 preset4 preset6 preset8
|
||||||
|
$ cat description
|
||||||
|
Setup ETMs with strobing for autofdo
|
||||||
|
$ cat feature_refs
|
||||||
|
strobing
|
||||||
|
|
||||||
|
Each preset declared has a preset<n> subdirectory declared. The values for
|
||||||
|
the preset can be examined::
|
||||||
|
|
||||||
|
$ cat preset1/values
|
||||||
|
strobing.window = 0x1388 strobing.period = 0x2
|
||||||
|
$ cat preset2/values
|
||||||
|
strobing.window = 0x1388 strobing.period = 0x4
|
||||||
|
|
||||||
|
The features referenced by the configuration can be examined in the features
|
||||||
|
directory::
|
||||||
|
|
||||||
|
$ cd ../../features/strobing/
|
||||||
|
$ ls
|
||||||
|
description matches nr_params params
|
||||||
|
$ cat description
|
||||||
|
Generate periodic trace capture windows.
|
||||||
|
parameter 'window': a number of CPU cycles (W)
|
||||||
|
parameter 'period': trace enabled for W cycles every period x W cycles
|
||||||
|
$ cat matches
|
||||||
|
SRC_ETMV4
|
||||||
|
$ cat nr_params
|
||||||
|
2
|
||||||
|
|
||||||
|
Move to the params directory to examine and adjust parameters::
|
||||||
|
|
||||||
|
cd params
|
||||||
|
$ ls
|
||||||
|
period window
|
||||||
|
$ cd period
|
||||||
|
$ ls
|
||||||
|
value
|
||||||
|
$ cat value
|
||||||
|
0x2710
|
||||||
|
# echo 15000 > value
|
||||||
|
# cat value
|
||||||
|
0x3a98
|
||||||
|
|
||||||
|
Parameters adjusted in this way are reflected in all device instances that have
|
||||||
|
loaded the feature.
|
||||||
|
|
||||||
|
|
||||||
|
Using Configurations in perf
|
||||||
|
============================
|
||||||
|
|
||||||
|
The configurations loaded into the CoreSight configuration management are
|
||||||
|
also declared in the perf 'cs_etm' event infrastructure so that they can
|
||||||
|
be selected when running trace under perf::
|
||||||
|
|
||||||
|
$ ls /sys/devices/cs_etm
|
||||||
|
configurations format perf_event_mux_interval_ms sinks type
|
||||||
|
events nr_addr_filters power
|
||||||
|
|
||||||
|
Key directories here are 'configurations' - which lists the loaded
|
||||||
|
configurations, and 'events' - a generic perf directory which allows
|
||||||
|
selection on the perf command line.::
|
||||||
|
|
||||||
|
$ ls configurations/
|
||||||
|
autofdo
|
||||||
|
$ cat configurations/autofdo
|
||||||
|
0xa7c3dddd
|
||||||
|
|
||||||
|
As with the sinks entries, this provides a hash of the configuration name.
|
||||||
|
The entry in the 'events' directory uses perfs built in syntax generator
|
||||||
|
to substitute the syntax for the name when evaluating the command::
|
||||||
|
|
||||||
|
$ ls events/
|
||||||
|
autofdo
|
||||||
|
$ cat events/autofdo
|
||||||
|
configid=0xa7c3dddd
|
||||||
|
|
||||||
|
The 'autofdo' configuration may be selected on the perf command line::
|
||||||
|
|
||||||
|
$ perf record -e cs_etm/autofdo/u --per-thread <application>
|
||||||
|
|
||||||
|
A preset to override the current parameter values can also be selected::
|
||||||
|
|
||||||
|
$ perf record -e cs_etm/autofdo,preset=1/u --per-thread <application>
|
||||||
|
|
||||||
|
When configurations are selected in this way, then the trace sink used is
|
||||||
|
automatically selected.
|
||||||
@@ -620,6 +620,19 @@ channels on the CTM (Cross Trigger Matrix).
|
|||||||
A separate documentation file is provided to explain the use of these devices.
|
A separate documentation file is provided to explain the use of these devices.
|
||||||
(Documentation/trace/coresight/coresight-ect.rst) [#fourth]_.
|
(Documentation/trace/coresight/coresight-ect.rst) [#fourth]_.
|
||||||
|
|
||||||
|
CoreSight System Configuration
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
CoreSight components can be complex devices with many programming options.
|
||||||
|
Furthermore, components can be programmed to interact with each other across the
|
||||||
|
complete system.
|
||||||
|
|
||||||
|
A CoreSight System Configuration manager is provided to allow these complex programming
|
||||||
|
configurations to be selected and used easily from perf and sysfs.
|
||||||
|
|
||||||
|
See the separate document for further information.
|
||||||
|
(Documentation/trace/coresight/coresight-config.rst) [#fifth]_.
|
||||||
|
|
||||||
|
|
||||||
.. [#first] Documentation/ABI/testing/sysfs-bus-coresight-devices-stm
|
.. [#first] Documentation/ABI/testing/sysfs-bus-coresight-devices-stm
|
||||||
|
|
||||||
@@ -628,3 +641,5 @@ A separate documentation file is provided to explain the use of these devices.
|
|||||||
.. [#third] https://github.com/Linaro/perf-opencsd
|
.. [#third] https://github.com/Linaro/perf-opencsd
|
||||||
|
|
||||||
.. [#fourth] Documentation/trace/coresight/coresight-ect.rst
|
.. [#fourth] Documentation/trace/coresight/coresight-ect.rst
|
||||||
|
|
||||||
|
.. [#fifth] Documentation/trace/coresight/coresight-config.rst
|
||||||
|
|||||||
@@ -70,6 +70,12 @@
|
|||||||
clock-frequency = <11289600>;
|
clock-frequency = <11289600>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
achc_24M: achc-clock {
|
||||||
|
compatible = "fixed-clock";
|
||||||
|
#clock-cells = <0>;
|
||||||
|
clock-frequency = <24000000>;
|
||||||
|
};
|
||||||
|
|
||||||
sgtlsound: sound {
|
sgtlsound: sound {
|
||||||
compatible = "fsl,imx53-cpuvo-sgtl5000",
|
compatible = "fsl,imx53-cpuvo-sgtl5000",
|
||||||
"fsl,imx-audio-sgtl5000";
|
"fsl,imx-audio-sgtl5000";
|
||||||
@@ -314,16 +320,13 @@
|
|||||||
&gpio4 12 GPIO_ACTIVE_LOW>;
|
&gpio4 12 GPIO_ACTIVE_LOW>;
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
|
||||||
spidev0: spi@0 {
|
spidev0: spi@1 {
|
||||||
compatible = "ge,achc";
|
compatible = "ge,achc", "nxp,kinetis-k20";
|
||||||
reg = <0>;
|
reg = <1>, <0>;
|
||||||
spi-max-frequency = <1000000>;
|
vdd-supply = <®_3v3>;
|
||||||
};
|
vdda-supply = <®_3v3>;
|
||||||
|
clocks = <&achc_24M>;
|
||||||
spidev1: spi@1 {
|
reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
|
||||||
compatible = "ge,achc";
|
|
||||||
reg = <1>;
|
|
||||||
spi-max-frequency = <1000000>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
gpioxra0: gpio@2 {
|
gpioxra0: gpio@2 {
|
||||||
|
|||||||
@@ -90,13 +90,13 @@ static char *speakup_default_msgs[MSG_LAST_INDEX] = {
|
|||||||
[MSG_COLOR_YELLOW] = "yellow",
|
[MSG_COLOR_YELLOW] = "yellow",
|
||||||
[MSG_COLOR_WHITE] = "white",
|
[MSG_COLOR_WHITE] = "white",
|
||||||
[MSG_COLOR_GREY] = "grey",
|
[MSG_COLOR_GREY] = "grey",
|
||||||
[MSG_COLOR_BRIGHTBLUE] "bright blue",
|
[MSG_COLOR_BRIGHTBLUE] = "bright blue",
|
||||||
[MSG_COLOR_BRIGHTGREEN] "bright green",
|
[MSG_COLOR_BRIGHTGREEN] = "bright green",
|
||||||
[MSG_COLOR_BRIGHTCYAN] "bright cyan",
|
[MSG_COLOR_BRIGHTCYAN] = "bright cyan",
|
||||||
[MSG_COLOR_BRIGHTRED] "bright red",
|
[MSG_COLOR_BRIGHTRED] = "bright red",
|
||||||
[MSG_COLOR_BRIGHTMAGENTA] "bright magenta",
|
[MSG_COLOR_BRIGHTMAGENTA] = "bright magenta",
|
||||||
[MSG_COLOR_BRIGHTYELLOW] "bright yellow",
|
[MSG_COLOR_BRIGHTYELLOW] = "bright yellow",
|
||||||
[MSG_COLOR_BRIGHTWHITE] "bright white",
|
[MSG_COLOR_BRIGHTWHITE] = "bright white",
|
||||||
|
|
||||||
/* Names of key states. */
|
/* Names of key states. */
|
||||||
[MSG_STATE_DOUBLE] = "double",
|
[MSG_STATE_DOUBLE] = "double",
|
||||||
|
|||||||
@@ -153,18 +153,25 @@ static char *get_initstring(void)
|
|||||||
static char buf[40];
|
static char buf[40];
|
||||||
char *cp;
|
char *cp;
|
||||||
struct var_t *var;
|
struct var_t *var;
|
||||||
|
size_t len;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
cp = buf;
|
cp = buf;
|
||||||
|
len = sizeof(buf);
|
||||||
|
|
||||||
var = synth_soft.vars;
|
var = synth_soft.vars;
|
||||||
while (var->var_id != MAXVARS) {
|
while (var->var_id != MAXVARS) {
|
||||||
if (var->var_id != CAPS_START && var->var_id != CAPS_STOP &&
|
if (var->var_id != CAPS_START && var->var_id != CAPS_STOP &&
|
||||||
var->var_id != PAUSE && var->var_id != DIRECT)
|
var->var_id != PAUSE && var->var_id != DIRECT) {
|
||||||
cp = cp + sprintf(cp, var->u.n.synth_fmt,
|
n = scnprintf(cp, len, var->u.n.synth_fmt,
|
||||||
var->u.n.value);
|
var->u.n.value);
|
||||||
|
cp = cp + n;
|
||||||
|
len = len - n;
|
||||||
|
}
|
||||||
var++;
|
var++;
|
||||||
}
|
}
|
||||||
cp = cp + sprintf(cp, "\n");
|
cp = cp + scnprintf(cp, len, "\n");
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2547,8 +2547,8 @@ static void binder_transaction(struct binder_proc *proc,
|
|||||||
ref->node, &target_proc,
|
ref->node, &target_proc,
|
||||||
&return_error);
|
&return_error);
|
||||||
} else {
|
} else {
|
||||||
binder_user_error("%d:%d got transaction to invalid handle\n",
|
binder_user_error("%d:%d got transaction to invalid handle, %u\n",
|
||||||
proc->pid, thread->pid);
|
proc->pid, thread->pid, tr->target.handle);
|
||||||
return_error = BR_FAILED_REPLY;
|
return_error = BR_FAILED_REPLY;
|
||||||
}
|
}
|
||||||
binder_proc_unlock(proc);
|
binder_proc_unlock(proc);
|
||||||
|
|||||||
@@ -58,6 +58,10 @@ enum binderfs_stats_mode {
|
|||||||
binderfs_stats_mode_global,
|
binderfs_stats_mode_global,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct binder_features {
|
||||||
|
bool oneway_spam_detection;
|
||||||
|
};
|
||||||
|
|
||||||
static const struct constant_table binderfs_param_stats[] = {
|
static const struct constant_table binderfs_param_stats[] = {
|
||||||
{ "global", binderfs_stats_mode_global },
|
{ "global", binderfs_stats_mode_global },
|
||||||
{}
|
{}
|
||||||
@@ -69,6 +73,10 @@ static const struct fs_parameter_spec binderfs_fs_parameters[] = {
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct binder_features binder_features = {
|
||||||
|
.oneway_spam_detection = true,
|
||||||
|
};
|
||||||
|
|
||||||
static inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb)
|
static inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb)
|
||||||
{
|
{
|
||||||
return sb->s_fs_info;
|
return sb->s_fs_info;
|
||||||
@@ -583,6 +591,33 @@ out:
|
|||||||
return dentry;
|
return dentry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int binder_features_show(struct seq_file *m, void *unused)
|
||||||
|
{
|
||||||
|
bool *feature = m->private;
|
||||||
|
|
||||||
|
seq_printf(m, "%d\n", *feature);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DEFINE_SHOW_ATTRIBUTE(binder_features);
|
||||||
|
|
||||||
|
static int init_binder_features(struct super_block *sb)
|
||||||
|
{
|
||||||
|
struct dentry *dentry, *dir;
|
||||||
|
|
||||||
|
dir = binderfs_create_dir(sb->s_root, "features");
|
||||||
|
if (IS_ERR(dir))
|
||||||
|
return PTR_ERR(dir);
|
||||||
|
|
||||||
|
dentry = binderfs_create_file(dir, "oneway_spam_detection",
|
||||||
|
&binder_features_fops,
|
||||||
|
&binder_features.oneway_spam_detection);
|
||||||
|
if (IS_ERR(dentry))
|
||||||
|
return PTR_ERR(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int init_binder_logs(struct super_block *sb)
|
static int init_binder_logs(struct super_block *sb)
|
||||||
{
|
{
|
||||||
struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir;
|
struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir;
|
||||||
@@ -723,6 +758,10 @@ static int binderfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
|||||||
name++;
|
name++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = init_binder_features(sb);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (info->mount_opts.stats_mode == binderfs_stats_mode_global)
|
if (info->mount_opts.stats_mode == binderfs_stats_mode_global)
|
||||||
return init_binder_logs(sb);
|
return init_binder_logs(sb);
|
||||||
|
|
||||||
|
|||||||
@@ -63,11 +63,14 @@ struct fsl_mc_addr_translation_range {
|
|||||||
|
|
||||||
#define FSL_MC_GCR1 0x0
|
#define FSL_MC_GCR1 0x0
|
||||||
#define GCR1_P1_STOP BIT(31)
|
#define GCR1_P1_STOP BIT(31)
|
||||||
|
#define GCR1_P2_STOP BIT(30)
|
||||||
|
|
||||||
#define FSL_MC_FAPR 0x28
|
#define FSL_MC_FAPR 0x28
|
||||||
#define MC_FAPR_PL BIT(18)
|
#define MC_FAPR_PL BIT(18)
|
||||||
#define MC_FAPR_BMT BIT(17)
|
#define MC_FAPR_BMT BIT(17)
|
||||||
|
|
||||||
|
static phys_addr_t mc_portal_base_phys_addr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fsl_mc_bus_match - device to driver matching callback
|
* fsl_mc_bus_match - device to driver matching callback
|
||||||
* @dev: the fsl-mc device to match against
|
* @dev: the fsl-mc device to match against
|
||||||
@@ -220,7 +223,7 @@ static int scan_fsl_mc_bus(struct device *dev, void *data)
|
|||||||
root_mc_dev = to_fsl_mc_device(dev);
|
root_mc_dev = to_fsl_mc_device(dev);
|
||||||
root_mc_bus = to_fsl_mc_bus(root_mc_dev);
|
root_mc_bus = to_fsl_mc_bus(root_mc_dev);
|
||||||
mutex_lock(&root_mc_bus->scan_mutex);
|
mutex_lock(&root_mc_bus->scan_mutex);
|
||||||
dprc_scan_objects(root_mc_dev, NULL);
|
dprc_scan_objects(root_mc_dev, false);
|
||||||
mutex_unlock(&root_mc_bus->scan_mutex);
|
mutex_unlock(&root_mc_bus->scan_mutex);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
@@ -703,14 +706,30 @@ static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev,
|
|||||||
* If base address is in the region_desc use it otherwise
|
* If base address is in the region_desc use it otherwise
|
||||||
* revert to old mechanism
|
* revert to old mechanism
|
||||||
*/
|
*/
|
||||||
if (region_desc.base_address)
|
if (region_desc.base_address) {
|
||||||
regions[i].start = region_desc.base_address +
|
regions[i].start = region_desc.base_address +
|
||||||
region_desc.base_offset;
|
region_desc.base_offset;
|
||||||
else
|
} else {
|
||||||
error = translate_mc_addr(mc_dev, mc_region_type,
|
error = translate_mc_addr(mc_dev, mc_region_type,
|
||||||
region_desc.base_offset,
|
region_desc.base_offset,
|
||||||
®ions[i].start);
|
®ions[i].start);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some versions of the MC firmware wrongly report
|
||||||
|
* 0 for register base address of the DPMCP associated
|
||||||
|
* with child DPRC objects thus rendering them unusable.
|
||||||
|
* This is particularly troublesome in ACPI boot
|
||||||
|
* scenarios where the legacy way of extracting this
|
||||||
|
* base address from the device tree does not apply.
|
||||||
|
* Given that DPMCPs share the same base address,
|
||||||
|
* workaround this by using the base address extracted
|
||||||
|
* from the root DPRC container.
|
||||||
|
*/
|
||||||
|
if (is_fsl_mc_bus_dprc(mc_dev) &&
|
||||||
|
regions[i].start == region_desc.base_offset)
|
||||||
|
regions[i].start += mc_portal_base_phys_addr;
|
||||||
|
}
|
||||||
|
|
||||||
if (error < 0) {
|
if (error < 0) {
|
||||||
dev_err(parent_dev,
|
dev_err(parent_dev,
|
||||||
"Invalid MC offset: %#x (for %s.%d\'s region %d)\n",
|
"Invalid MC offset: %#x (for %s.%d\'s region %d)\n",
|
||||||
@@ -895,6 +914,8 @@ error_cleanup_dev:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(fsl_mc_device_add);
|
EXPORT_SYMBOL_GPL(fsl_mc_device_add);
|
||||||
|
|
||||||
|
static struct notifier_block fsl_mc_nb;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fsl_mc_device_remove - Remove an fsl-mc device from being visible to
|
* fsl_mc_device_remove - Remove an fsl-mc device from being visible to
|
||||||
* Linux
|
* Linux
|
||||||
@@ -949,10 +970,28 @@ struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev,
|
|||||||
* We know that the device has an endpoint because we verified by
|
* We know that the device has an endpoint because we verified by
|
||||||
* interrogating the firmware. This is the case when the device was not
|
* interrogating the firmware. This is the case when the device was not
|
||||||
* yet discovered by the fsl-mc bus, thus the lookup returned NULL.
|
* yet discovered by the fsl-mc bus, thus the lookup returned NULL.
|
||||||
* Differentiate this case by returning EPROBE_DEFER.
|
* Force a rescan of the devices in this container and retry the lookup.
|
||||||
|
*/
|
||||||
|
if (!endpoint) {
|
||||||
|
struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
|
||||||
|
|
||||||
|
if (mutex_trylock(&mc_bus->scan_mutex)) {
|
||||||
|
err = dprc_scan_objects(mc_bus_dev, true);
|
||||||
|
mutex_unlock(&mc_bus->scan_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err < 0)
|
||||||
|
return ERR_PTR(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint = fsl_mc_device_lookup(&endpoint_desc, mc_bus_dev);
|
||||||
|
/*
|
||||||
|
* This means that the endpoint might reside in a different isolation
|
||||||
|
* context (DPRC/container). Not much to do, so return a permssion
|
||||||
|
* error.
|
||||||
*/
|
*/
|
||||||
if (!endpoint)
|
if (!endpoint)
|
||||||
return ERR_PTR(-EPROBE_DEFER);
|
return ERR_PTR(-EPERM);
|
||||||
|
|
||||||
return endpoint;
|
return endpoint;
|
||||||
}
|
}
|
||||||
@@ -1091,17 +1130,6 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mc->fsl_mc_regs) {
|
if (mc->fsl_mc_regs) {
|
||||||
/*
|
|
||||||
* Some bootloaders pause the MC firmware before booting the
|
|
||||||
* kernel so that MC will not cause faults as soon as the
|
|
||||||
* SMMU probes due to the fact that there's no configuration
|
|
||||||
* in place for MC.
|
|
||||||
* At this point MC should have all its SMMU setup done so make
|
|
||||||
* sure it is resumed.
|
|
||||||
*/
|
|
||||||
writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) & (~GCR1_P1_STOP),
|
|
||||||
mc->fsl_mc_regs + FSL_MC_GCR1);
|
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_ACPI) && !dev_of_node(&pdev->dev)) {
|
if (IS_ENABLED(CONFIG_ACPI) && !dev_of_node(&pdev->dev)) {
|
||||||
mc_stream_id = readl(mc->fsl_mc_regs + FSL_MC_FAPR);
|
mc_stream_id = readl(mc->fsl_mc_regs + FSL_MC_FAPR);
|
||||||
/*
|
/*
|
||||||
@@ -1115,11 +1143,25 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
|
|||||||
error = acpi_dma_configure_id(&pdev->dev,
|
error = acpi_dma_configure_id(&pdev->dev,
|
||||||
DEV_DMA_COHERENT,
|
DEV_DMA_COHERENT,
|
||||||
&mc_stream_id);
|
&mc_stream_id);
|
||||||
|
if (error == -EPROBE_DEFER)
|
||||||
|
return error;
|
||||||
if (error)
|
if (error)
|
||||||
dev_warn(&pdev->dev,
|
dev_warn(&pdev->dev,
|
||||||
"failed to configure dma: %d.\n",
|
"failed to configure dma: %d.\n",
|
||||||
error);
|
error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some bootloaders pause the MC firmware before booting the
|
||||||
|
* kernel so that MC will not cause faults as soon as the
|
||||||
|
* SMMU probes due to the fact that there's no configuration
|
||||||
|
* in place for MC.
|
||||||
|
* At this point MC should have all its SMMU setup done so make
|
||||||
|
* sure it is resumed.
|
||||||
|
*/
|
||||||
|
writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) &
|
||||||
|
(~(GCR1_P1_STOP | GCR1_P2_STOP)),
|
||||||
|
mc->fsl_mc_regs + FSL_MC_GCR1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1128,6 +1170,8 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
|
|||||||
plat_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
plat_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
mc_portal_phys_addr = plat_res->start;
|
mc_portal_phys_addr = plat_res->start;
|
||||||
mc_portal_size = resource_size(plat_res);
|
mc_portal_size = resource_size(plat_res);
|
||||||
|
mc_portal_base_phys_addr = mc_portal_phys_addr & ~0x3ffffff;
|
||||||
|
|
||||||
error = fsl_create_mc_io(&pdev->dev, mc_portal_phys_addr,
|
error = fsl_create_mc_io(&pdev->dev, mc_portal_phys_addr,
|
||||||
mc_portal_size, NULL,
|
mc_portal_size, NULL,
|
||||||
FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, &mc_io);
|
FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, &mc_io);
|
||||||
@@ -1201,9 +1245,26 @@ static int fsl_mc_bus_remove(struct platform_device *pdev)
|
|||||||
fsl_destroy_mc_io(mc->root_mc_bus_dev->mc_io);
|
fsl_destroy_mc_io(mc->root_mc_bus_dev->mc_io);
|
||||||
mc->root_mc_bus_dev->mc_io = NULL;
|
mc->root_mc_bus_dev->mc_io = NULL;
|
||||||
|
|
||||||
|
bus_unregister_notifier(&fsl_mc_bus_type, &fsl_mc_nb);
|
||||||
|
|
||||||
|
if (mc->fsl_mc_regs) {
|
||||||
|
/*
|
||||||
|
* Pause the MC firmware so that it doesn't crash in certain
|
||||||
|
* scenarios, such as kexec.
|
||||||
|
*/
|
||||||
|
writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) |
|
||||||
|
(GCR1_P1_STOP | GCR1_P2_STOP),
|
||||||
|
mc->fsl_mc_regs + FSL_MC_GCR1);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fsl_mc_bus_shutdown(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
fsl_mc_bus_remove(pdev);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct of_device_id fsl_mc_bus_match_table[] = {
|
static const struct of_device_id fsl_mc_bus_match_table[] = {
|
||||||
{.compatible = "fsl,qoriq-mc",},
|
{.compatible = "fsl,qoriq-mc",},
|
||||||
{},
|
{},
|
||||||
@@ -1226,6 +1287,45 @@ static struct platform_driver fsl_mc_bus_driver = {
|
|||||||
},
|
},
|
||||||
.probe = fsl_mc_bus_probe,
|
.probe = fsl_mc_bus_probe,
|
||||||
.remove = fsl_mc_bus_remove,
|
.remove = fsl_mc_bus_remove,
|
||||||
|
.shutdown = fsl_mc_bus_shutdown,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int fsl_mc_bus_notifier(struct notifier_block *nb,
|
||||||
|
unsigned long action, void *data)
|
||||||
|
{
|
||||||
|
struct device *dev = data;
|
||||||
|
struct resource *res;
|
||||||
|
void __iomem *fsl_mc_regs;
|
||||||
|
|
||||||
|
if (action != BUS_NOTIFY_ADD_DEVICE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!of_match_device(fsl_mc_bus_match_table, dev) &&
|
||||||
|
!acpi_match_device(fsl_mc_bus_acpi_match_table, dev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 1);
|
||||||
|
if (!res)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fsl_mc_regs = ioremap(res->start, resource_size(res));
|
||||||
|
if (!fsl_mc_regs)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure that the MC firmware is paused before the IOMMU setup for
|
||||||
|
* it is done or otherwise the firmware will crash right after the SMMU
|
||||||
|
* gets probed and enabled.
|
||||||
|
*/
|
||||||
|
writel(readl(fsl_mc_regs + FSL_MC_GCR1) | (GCR1_P1_STOP | GCR1_P2_STOP),
|
||||||
|
fsl_mc_regs + FSL_MC_GCR1);
|
||||||
|
iounmap(fsl_mc_regs);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block fsl_mc_nb = {
|
||||||
|
.notifier_call = fsl_mc_bus_notifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init fsl_mc_bus_driver_init(void)
|
static int __init fsl_mc_bus_driver_init(void)
|
||||||
@@ -1252,7 +1352,7 @@ static int __init fsl_mc_bus_driver_init(void)
|
|||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto error_cleanup_dprc_driver;
|
goto error_cleanup_dprc_driver;
|
||||||
|
|
||||||
return 0;
|
return bus_register_notifier(&platform_bus_type, &fsl_mc_nb);
|
||||||
|
|
||||||
error_cleanup_dprc_driver:
|
error_cleanup_dprc_driver:
|
||||||
dprc_driver_exit();
|
dprc_driver_exit();
|
||||||
|
|||||||
@@ -302,8 +302,8 @@ void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl,
|
|||||||
struct mhi_buf *mhi_buf = image_info->mhi_buf;
|
struct mhi_buf *mhi_buf = image_info->mhi_buf;
|
||||||
|
|
||||||
for (i = 0; i < image_info->entries; i++, mhi_buf++)
|
for (i = 0; i < image_info->entries; i++, mhi_buf++)
|
||||||
mhi_free_coherent(mhi_cntrl, mhi_buf->len, mhi_buf->buf,
|
dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len,
|
||||||
mhi_buf->dma_addr);
|
mhi_buf->buf, mhi_buf->dma_addr);
|
||||||
|
|
||||||
kfree(image_info->mhi_buf);
|
kfree(image_info->mhi_buf);
|
||||||
kfree(image_info);
|
kfree(image_info);
|
||||||
@@ -339,8 +339,8 @@ int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl,
|
|||||||
vec_size = sizeof(struct bhi_vec_entry) * i;
|
vec_size = sizeof(struct bhi_vec_entry) * i;
|
||||||
|
|
||||||
mhi_buf->len = vec_size;
|
mhi_buf->len = vec_size;
|
||||||
mhi_buf->buf = mhi_alloc_coherent(mhi_cntrl, vec_size,
|
mhi_buf->buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev,
|
||||||
&mhi_buf->dma_addr,
|
vec_size, &mhi_buf->dma_addr,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!mhi_buf->buf)
|
if (!mhi_buf->buf)
|
||||||
goto error_alloc_segment;
|
goto error_alloc_segment;
|
||||||
@@ -354,8 +354,8 @@ int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl,
|
|||||||
|
|
||||||
error_alloc_segment:
|
error_alloc_segment:
|
||||||
for (--i, --mhi_buf; i >= 0; i--, mhi_buf--)
|
for (--i, --mhi_buf; i >= 0; i--, mhi_buf--)
|
||||||
mhi_free_coherent(mhi_cntrl, mhi_buf->len, mhi_buf->buf,
|
dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len,
|
||||||
mhi_buf->dma_addr);
|
mhi_buf->buf, mhi_buf->dma_addr);
|
||||||
|
|
||||||
error_alloc_mhi_buf:
|
error_alloc_mhi_buf:
|
||||||
kfree(img_info);
|
kfree(img_info);
|
||||||
@@ -442,7 +442,8 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
|
|||||||
if (size > firmware->size)
|
if (size > firmware->size)
|
||||||
size = firmware->size;
|
size = firmware->size;
|
||||||
|
|
||||||
buf = mhi_alloc_coherent(mhi_cntrl, size, &dma_addr, GFP_KERNEL);
|
buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, size, &dma_addr,
|
||||||
|
GFP_KERNEL);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
release_firmware(firmware);
|
release_firmware(firmware);
|
||||||
goto error_fw_load;
|
goto error_fw_load;
|
||||||
@@ -451,7 +452,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
|
|||||||
/* Download image using BHI */
|
/* Download image using BHI */
|
||||||
memcpy(buf, firmware->data, size);
|
memcpy(buf, firmware->data, size);
|
||||||
ret = mhi_fw_load_bhi(mhi_cntrl, dma_addr, size);
|
ret = mhi_fw_load_bhi(mhi_cntrl, dma_addr, size);
|
||||||
mhi_free_coherent(mhi_cntrl, size, buf, dma_addr);
|
dma_free_coherent(mhi_cntrl->cntrl_dev, size, buf, dma_addr);
|
||||||
|
|
||||||
/* Error or in EDL mode, we're done */
|
/* Error or in EDL mode, we're done */
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ static int mhi_alloc_aligned_ring(struct mhi_controller *mhi_cntrl,
|
|||||||
u64 len)
|
u64 len)
|
||||||
{
|
{
|
||||||
ring->alloc_size = len + (len - 1);
|
ring->alloc_size = len + (len - 1);
|
||||||
ring->pre_aligned = mhi_alloc_coherent(mhi_cntrl, ring->alloc_size,
|
ring->pre_aligned = dma_alloc_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size,
|
||||||
&ring->dma_handle, GFP_KERNEL);
|
&ring->dma_handle, GFP_KERNEL);
|
||||||
if (!ring->pre_aligned)
|
if (!ring->pre_aligned)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -221,13 +221,13 @@ void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
|||||||
mhi_cmd = mhi_cntrl->mhi_cmd;
|
mhi_cmd = mhi_cntrl->mhi_cmd;
|
||||||
for (i = 0; i < NR_OF_CMD_RINGS; i++, mhi_cmd++) {
|
for (i = 0; i < NR_OF_CMD_RINGS; i++, mhi_cmd++) {
|
||||||
ring = &mhi_cmd->ring;
|
ring = &mhi_cmd->ring;
|
||||||
mhi_free_coherent(mhi_cntrl, ring->alloc_size,
|
dma_free_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size,
|
||||||
ring->pre_aligned, ring->dma_handle);
|
ring->pre_aligned, ring->dma_handle);
|
||||||
ring->base = NULL;
|
ring->base = NULL;
|
||||||
ring->iommu_base = 0;
|
ring->iommu_base = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mhi_free_coherent(mhi_cntrl,
|
dma_free_coherent(mhi_cntrl->cntrl_dev,
|
||||||
sizeof(*mhi_ctxt->cmd_ctxt) * NR_OF_CMD_RINGS,
|
sizeof(*mhi_ctxt->cmd_ctxt) * NR_OF_CMD_RINGS,
|
||||||
mhi_ctxt->cmd_ctxt, mhi_ctxt->cmd_ctxt_addr);
|
mhi_ctxt->cmd_ctxt, mhi_ctxt->cmd_ctxt_addr);
|
||||||
|
|
||||||
@@ -237,17 +237,17 @@ void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
ring = &mhi_event->ring;
|
ring = &mhi_event->ring;
|
||||||
mhi_free_coherent(mhi_cntrl, ring->alloc_size,
|
dma_free_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size,
|
||||||
ring->pre_aligned, ring->dma_handle);
|
ring->pre_aligned, ring->dma_handle);
|
||||||
ring->base = NULL;
|
ring->base = NULL;
|
||||||
ring->iommu_base = 0;
|
ring->iommu_base = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mhi_free_coherent(mhi_cntrl, sizeof(*mhi_ctxt->er_ctxt) *
|
dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->er_ctxt) *
|
||||||
mhi_cntrl->total_ev_rings, mhi_ctxt->er_ctxt,
|
mhi_cntrl->total_ev_rings, mhi_ctxt->er_ctxt,
|
||||||
mhi_ctxt->er_ctxt_addr);
|
mhi_ctxt->er_ctxt_addr);
|
||||||
|
|
||||||
mhi_free_coherent(mhi_cntrl, sizeof(*mhi_ctxt->chan_ctxt) *
|
dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->chan_ctxt) *
|
||||||
mhi_cntrl->max_chan, mhi_ctxt->chan_ctxt,
|
mhi_cntrl->max_chan, mhi_ctxt->chan_ctxt,
|
||||||
mhi_ctxt->chan_ctxt_addr);
|
mhi_ctxt->chan_ctxt_addr);
|
||||||
|
|
||||||
@@ -275,7 +275,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Setup channel ctxt */
|
/* Setup channel ctxt */
|
||||||
mhi_ctxt->chan_ctxt = mhi_alloc_coherent(mhi_cntrl,
|
mhi_ctxt->chan_ctxt = dma_alloc_coherent(mhi_cntrl->cntrl_dev,
|
||||||
sizeof(*mhi_ctxt->chan_ctxt) *
|
sizeof(*mhi_ctxt->chan_ctxt) *
|
||||||
mhi_cntrl->max_chan,
|
mhi_cntrl->max_chan,
|
||||||
&mhi_ctxt->chan_ctxt_addr,
|
&mhi_ctxt->chan_ctxt_addr,
|
||||||
@@ -307,7 +307,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Setup event context */
|
/* Setup event context */
|
||||||
mhi_ctxt->er_ctxt = mhi_alloc_coherent(mhi_cntrl,
|
mhi_ctxt->er_ctxt = dma_alloc_coherent(mhi_cntrl->cntrl_dev,
|
||||||
sizeof(*mhi_ctxt->er_ctxt) *
|
sizeof(*mhi_ctxt->er_ctxt) *
|
||||||
mhi_cntrl->total_ev_rings,
|
mhi_cntrl->total_ev_rings,
|
||||||
&mhi_ctxt->er_ctxt_addr,
|
&mhi_ctxt->er_ctxt_addr,
|
||||||
@@ -354,7 +354,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
|||||||
|
|
||||||
/* Setup cmd context */
|
/* Setup cmd context */
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
mhi_ctxt->cmd_ctxt = mhi_alloc_coherent(mhi_cntrl,
|
mhi_ctxt->cmd_ctxt = dma_alloc_coherent(mhi_cntrl->cntrl_dev,
|
||||||
sizeof(*mhi_ctxt->cmd_ctxt) *
|
sizeof(*mhi_ctxt->cmd_ctxt) *
|
||||||
NR_OF_CMD_RINGS,
|
NR_OF_CMD_RINGS,
|
||||||
&mhi_ctxt->cmd_ctxt_addr,
|
&mhi_ctxt->cmd_ctxt_addr,
|
||||||
@@ -389,10 +389,10 @@ error_alloc_cmd:
|
|||||||
for (--i, --mhi_cmd; i >= 0; i--, mhi_cmd--) {
|
for (--i, --mhi_cmd; i >= 0; i--, mhi_cmd--) {
|
||||||
struct mhi_ring *ring = &mhi_cmd->ring;
|
struct mhi_ring *ring = &mhi_cmd->ring;
|
||||||
|
|
||||||
mhi_free_coherent(mhi_cntrl, ring->alloc_size,
|
dma_free_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size,
|
||||||
ring->pre_aligned, ring->dma_handle);
|
ring->pre_aligned, ring->dma_handle);
|
||||||
}
|
}
|
||||||
mhi_free_coherent(mhi_cntrl,
|
dma_free_coherent(mhi_cntrl->cntrl_dev,
|
||||||
sizeof(*mhi_ctxt->cmd_ctxt) * NR_OF_CMD_RINGS,
|
sizeof(*mhi_ctxt->cmd_ctxt) * NR_OF_CMD_RINGS,
|
||||||
mhi_ctxt->cmd_ctxt, mhi_ctxt->cmd_ctxt_addr);
|
mhi_ctxt->cmd_ctxt, mhi_ctxt->cmd_ctxt_addr);
|
||||||
i = mhi_cntrl->total_ev_rings;
|
i = mhi_cntrl->total_ev_rings;
|
||||||
@@ -405,15 +405,15 @@ error_alloc_er:
|
|||||||
if (mhi_event->offload_ev)
|
if (mhi_event->offload_ev)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
mhi_free_coherent(mhi_cntrl, ring->alloc_size,
|
dma_free_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size,
|
||||||
ring->pre_aligned, ring->dma_handle);
|
ring->pre_aligned, ring->dma_handle);
|
||||||
}
|
}
|
||||||
mhi_free_coherent(mhi_cntrl, sizeof(*mhi_ctxt->er_ctxt) *
|
dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->er_ctxt) *
|
||||||
mhi_cntrl->total_ev_rings, mhi_ctxt->er_ctxt,
|
mhi_cntrl->total_ev_rings, mhi_ctxt->er_ctxt,
|
||||||
mhi_ctxt->er_ctxt_addr);
|
mhi_ctxt->er_ctxt_addr);
|
||||||
|
|
||||||
error_alloc_er_ctxt:
|
error_alloc_er_ctxt:
|
||||||
mhi_free_coherent(mhi_cntrl, sizeof(*mhi_ctxt->chan_ctxt) *
|
dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->chan_ctxt) *
|
||||||
mhi_cntrl->max_chan, mhi_ctxt->chan_ctxt,
|
mhi_cntrl->max_chan, mhi_ctxt->chan_ctxt,
|
||||||
mhi_ctxt->chan_ctxt_addr);
|
mhi_ctxt->chan_ctxt_addr);
|
||||||
|
|
||||||
@@ -567,7 +567,7 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl,
|
|||||||
if (!chan_ctxt->rbase) /* Already uninitialized */
|
if (!chan_ctxt->rbase) /* Already uninitialized */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mhi_free_coherent(mhi_cntrl, tre_ring->alloc_size,
|
dma_free_coherent(mhi_cntrl->cntrl_dev, tre_ring->alloc_size,
|
||||||
tre_ring->pre_aligned, tre_ring->dma_handle);
|
tre_ring->pre_aligned, tre_ring->dma_handle);
|
||||||
vfree(buf_ring->base);
|
vfree(buf_ring->base);
|
||||||
|
|
||||||
@@ -610,7 +610,7 @@ int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl,
|
|||||||
buf_ring->base = vzalloc(buf_ring->len);
|
buf_ring->base = vzalloc(buf_ring->len);
|
||||||
|
|
||||||
if (!buf_ring->base) {
|
if (!buf_ring->base) {
|
||||||
mhi_free_coherent(mhi_cntrl, tre_ring->alloc_size,
|
dma_free_coherent(mhi_cntrl->cntrl_dev, tre_ring->alloc_size,
|
||||||
tre_ring->pre_aligned, tre_ring->dma_handle);
|
tre_ring->pre_aligned, tre_ring->dma_handle);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
@@ -885,7 +885,8 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
|
|||||||
if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs ||
|
if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs ||
|
||||||
!mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put ||
|
!mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put ||
|
||||||
!mhi_cntrl->status_cb || !mhi_cntrl->read_reg ||
|
!mhi_cntrl->status_cb || !mhi_cntrl->read_reg ||
|
||||||
!mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs || !mhi_cntrl->irq)
|
!mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs ||
|
||||||
|
!mhi_cntrl->irq || !mhi_cntrl->reg_len)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ret = parse_config(mhi_cntrl, config);
|
ret = parse_config(mhi_cntrl, config);
|
||||||
@@ -1063,7 +1064,7 @@ EXPORT_SYMBOL_GPL(mhi_free_controller);
|
|||||||
int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl)
|
int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl)
|
||||||
{
|
{
|
||||||
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
||||||
u32 bhie_off;
|
u32 bhi_off, bhie_off;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
mutex_lock(&mhi_cntrl->pm_mutex);
|
mutex_lock(&mhi_cntrl->pm_mutex);
|
||||||
@@ -1072,29 +1073,51 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto error_dev_ctxt;
|
goto error_dev_ctxt;
|
||||||
|
|
||||||
/*
|
ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIOFF, &bhi_off);
|
||||||
* Allocate RDDM table if specified, this table is for debugging purpose
|
if (ret) {
|
||||||
*/
|
dev_err(dev, "Error getting BHI offset\n");
|
||||||
if (mhi_cntrl->rddm_size) {
|
goto error_reg_offset;
|
||||||
mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->rddm_image,
|
}
|
||||||
mhi_cntrl->rddm_size);
|
|
||||||
|
|
||||||
/*
|
if (bhi_off >= mhi_cntrl->reg_len) {
|
||||||
* This controller supports RDDM, so we need to manually clear
|
dev_err(dev, "BHI offset: 0x%x is out of range: 0x%zx\n",
|
||||||
* BHIE RX registers since POR values are undefined.
|
bhi_off, mhi_cntrl->reg_len);
|
||||||
*/
|
ret = -EINVAL;
|
||||||
|
goto error_reg_offset;
|
||||||
|
}
|
||||||
|
mhi_cntrl->bhi = mhi_cntrl->regs + bhi_off;
|
||||||
|
|
||||||
|
if (mhi_cntrl->fbc_download || mhi_cntrl->rddm_size) {
|
||||||
ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIEOFF,
|
ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIEOFF,
|
||||||
&bhie_off);
|
&bhie_off);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "Error getting BHIE offset\n");
|
dev_err(dev, "Error getting BHIE offset\n");
|
||||||
goto bhie_error;
|
goto error_reg_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bhie_off >= mhi_cntrl->reg_len) {
|
||||||
|
dev_err(dev,
|
||||||
|
"BHIe offset: 0x%x is out of range: 0x%zx\n",
|
||||||
|
bhie_off, mhi_cntrl->reg_len);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto error_reg_offset;
|
||||||
|
}
|
||||||
mhi_cntrl->bhie = mhi_cntrl->regs + bhie_off;
|
mhi_cntrl->bhie = mhi_cntrl->regs + bhie_off;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mhi_cntrl->rddm_size) {
|
||||||
|
/*
|
||||||
|
* This controller supports RDDM, so we need to manually clear
|
||||||
|
* BHIE RX registers since POR values are undefined.
|
||||||
|
*/
|
||||||
memset_io(mhi_cntrl->bhie + BHIE_RXVECADDR_LOW_OFFS,
|
memset_io(mhi_cntrl->bhie + BHIE_RXVECADDR_LOW_OFFS,
|
||||||
0, BHIE_RXVECSTATUS_OFFS - BHIE_RXVECADDR_LOW_OFFS +
|
0, BHIE_RXVECSTATUS_OFFS - BHIE_RXVECADDR_LOW_OFFS +
|
||||||
4);
|
4);
|
||||||
|
/*
|
||||||
|
* Allocate RDDM table for debugging purpose if specified
|
||||||
|
*/
|
||||||
|
mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->rddm_image,
|
||||||
|
mhi_cntrl->rddm_size);
|
||||||
if (mhi_cntrl->rddm_image)
|
if (mhi_cntrl->rddm_image)
|
||||||
mhi_rddm_prepare(mhi_cntrl, mhi_cntrl->rddm_image);
|
mhi_rddm_prepare(mhi_cntrl, mhi_cntrl->rddm_image);
|
||||||
}
|
}
|
||||||
@@ -1103,11 +1126,8 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bhie_error:
|
error_reg_offset:
|
||||||
if (mhi_cntrl->rddm_image) {
|
mhi_deinit_dev_ctxt(mhi_cntrl);
|
||||||
mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->rddm_image);
|
|
||||||
mhi_cntrl->rddm_image = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
error_dev_ctxt:
|
error_dev_ctxt:
|
||||||
mutex_unlock(&mhi_cntrl->pm_mutex);
|
mutex_unlock(&mhi_cntrl->pm_mutex);
|
||||||
@@ -1128,6 +1148,9 @@ void mhi_unprepare_after_power_down(struct mhi_controller *mhi_cntrl)
|
|||||||
mhi_cntrl->rddm_image = NULL;
|
mhi_cntrl->rddm_image = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mhi_cntrl->bhi = NULL;
|
||||||
|
mhi_cntrl->bhie = NULL;
|
||||||
|
|
||||||
mhi_deinit_dev_ctxt(mhi_cntrl);
|
mhi_deinit_dev_ctxt(mhi_cntrl);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mhi_unprepare_after_power_down);
|
EXPORT_SYMBOL_GPL(mhi_unprepare_after_power_down);
|
||||||
|
|||||||
@@ -690,26 +690,6 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl,
|
|||||||
void mhi_reset_chan(struct mhi_controller *mhi_cntrl,
|
void mhi_reset_chan(struct mhi_controller *mhi_cntrl,
|
||||||
struct mhi_chan *mhi_chan);
|
struct mhi_chan *mhi_chan);
|
||||||
|
|
||||||
/* Memory allocation methods */
|
|
||||||
static inline void *mhi_alloc_coherent(struct mhi_controller *mhi_cntrl,
|
|
||||||
size_t size,
|
|
||||||
dma_addr_t *dma_handle,
|
|
||||||
gfp_t gfp)
|
|
||||||
{
|
|
||||||
void *buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, size, dma_handle,
|
|
||||||
gfp);
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mhi_free_coherent(struct mhi_controller *mhi_cntrl,
|
|
||||||
size_t size,
|
|
||||||
void *vaddr,
|
|
||||||
dma_addr_t dma_handle)
|
|
||||||
{
|
|
||||||
dma_free_coherent(mhi_cntrl->cntrl_dev, size, vaddr, dma_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Event processing methods */
|
/* Event processing methods */
|
||||||
void mhi_ctrl_ev_task(unsigned long data);
|
void mhi_ctrl_ev_task(unsigned long data);
|
||||||
void mhi_ev_task(unsigned long data);
|
void mhi_ev_task(unsigned long data);
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ int mhi_map_single_no_bb(struct mhi_controller *mhi_cntrl,
|
|||||||
int mhi_map_single_use_bb(struct mhi_controller *mhi_cntrl,
|
int mhi_map_single_use_bb(struct mhi_controller *mhi_cntrl,
|
||||||
struct mhi_buf_info *buf_info)
|
struct mhi_buf_info *buf_info)
|
||||||
{
|
{
|
||||||
void *buf = mhi_alloc_coherent(mhi_cntrl, buf_info->len,
|
void *buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, buf_info->len,
|
||||||
&buf_info->p_addr, GFP_ATOMIC);
|
&buf_info->p_addr, GFP_ATOMIC);
|
||||||
|
|
||||||
if (!buf)
|
if (!buf)
|
||||||
@@ -220,8 +220,8 @@ void mhi_unmap_single_use_bb(struct mhi_controller *mhi_cntrl,
|
|||||||
if (buf_info->dir == DMA_FROM_DEVICE)
|
if (buf_info->dir == DMA_FROM_DEVICE)
|
||||||
memcpy(buf_info->v_addr, buf_info->bb_addr, buf_info->len);
|
memcpy(buf_info->v_addr, buf_info->bb_addr, buf_info->len);
|
||||||
|
|
||||||
mhi_free_coherent(mhi_cntrl, buf_info->len, buf_info->bb_addr,
|
dma_free_coherent(mhi_cntrl->cntrl_dev, buf_info->len,
|
||||||
buf_info->p_addr);
|
buf_info->bb_addr, buf_info->p_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_nr_avail_ring_elements(struct mhi_controller *mhi_cntrl,
|
static int get_nr_avail_ring_elements(struct mhi_controller *mhi_cntrl,
|
||||||
|
|||||||
@@ -1059,28 +1059,8 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto error_setup_irq;
|
goto error_setup_irq;
|
||||||
|
|
||||||
/* Setup BHI offset & INTVEC */
|
/* Setup BHI INTVEC */
|
||||||
write_lock_irq(&mhi_cntrl->pm_lock);
|
write_lock_irq(&mhi_cntrl->pm_lock);
|
||||||
ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIOFF, &val);
|
|
||||||
if (ret) {
|
|
||||||
write_unlock_irq(&mhi_cntrl->pm_lock);
|
|
||||||
goto error_bhi_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
mhi_cntrl->bhi = mhi_cntrl->regs + val;
|
|
||||||
|
|
||||||
/* Setup BHIE offset */
|
|
||||||
if (mhi_cntrl->fbc_download) {
|
|
||||||
ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIEOFF, &val);
|
|
||||||
if (ret) {
|
|
||||||
write_unlock_irq(&mhi_cntrl->pm_lock);
|
|
||||||
dev_err(dev, "Error reading BHIE offset\n");
|
|
||||||
goto error_bhi_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
mhi_cntrl->bhie = mhi_cntrl->regs + val;
|
|
||||||
}
|
|
||||||
|
|
||||||
mhi_write_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_INTVEC, 0);
|
mhi_write_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_INTVEC, 0);
|
||||||
mhi_cntrl->pm_state = MHI_PM_POR;
|
mhi_cntrl->pm_state = MHI_PM_POR;
|
||||||
mhi_cntrl->ee = MHI_EE_MAX;
|
mhi_cntrl->ee = MHI_EE_MAX;
|
||||||
@@ -1089,12 +1069,16 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl)
|
|||||||
|
|
||||||
/* Confirm that the device is in valid exec env */
|
/* Confirm that the device is in valid exec env */
|
||||||
if (!MHI_IN_PBL(current_ee) && current_ee != MHI_EE_AMSS) {
|
if (!MHI_IN_PBL(current_ee) && current_ee != MHI_EE_AMSS) {
|
||||||
dev_err(dev, "Not a valid EE for power on\n");
|
dev_err(dev, "%s is not a valid EE for power on\n",
|
||||||
|
TO_MHI_EXEC_STR(current_ee));
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto error_bhi_offset;
|
goto error_async_power_up;
|
||||||
}
|
}
|
||||||
|
|
||||||
state = mhi_get_mhi_state(mhi_cntrl);
|
state = mhi_get_mhi_state(mhi_cntrl);
|
||||||
|
dev_dbg(dev, "Attempting power on with EE: %s, state: %s\n",
|
||||||
|
TO_MHI_EXEC_STR(current_ee), TO_MHI_STATE_STR(state));
|
||||||
|
|
||||||
if (state == MHI_STATE_SYS_ERR) {
|
if (state == MHI_STATE_SYS_ERR) {
|
||||||
mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET);
|
mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET);
|
||||||
ret = wait_event_timeout(mhi_cntrl->state_event,
|
ret = wait_event_timeout(mhi_cntrl->state_event,
|
||||||
@@ -1110,7 +1094,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl)
|
|||||||
if (!ret) {
|
if (!ret) {
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
dev_info(dev, "Failed to reset MHI due to syserr state\n");
|
dev_info(dev, "Failed to reset MHI due to syserr state\n");
|
||||||
goto error_bhi_offset;
|
goto error_async_power_up;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1132,7 +1116,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error_bhi_offset:
|
error_async_power_up:
|
||||||
mhi_deinit_free_irq(mhi_cntrl);
|
mhi_deinit_free_irq(mhi_cntrl);
|
||||||
|
|
||||||
error_setup_irq:
|
error_setup_irq:
|
||||||
|
|||||||
@@ -369,6 +369,40 @@ static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = {
|
|||||||
.sideband_wake = false,
|
.sideband_wake = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct mhi_channel_config mhi_mv31_channels[] = {
|
||||||
|
MHI_CHANNEL_CONFIG_UL(0, "LOOPBACK", 64, 0),
|
||||||
|
MHI_CHANNEL_CONFIG_DL(1, "LOOPBACK", 64, 0),
|
||||||
|
/* MBIM Control Channel */
|
||||||
|
MHI_CHANNEL_CONFIG_UL(12, "MBIM", 64, 0),
|
||||||
|
MHI_CHANNEL_CONFIG_DL(13, "MBIM", 64, 0),
|
||||||
|
/* MBIM Data Channel */
|
||||||
|
MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 512, 2),
|
||||||
|
MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 512, 3),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mhi_event_config mhi_mv31_events[] = {
|
||||||
|
MHI_EVENT_CONFIG_CTRL(0, 256),
|
||||||
|
MHI_EVENT_CONFIG_DATA(1, 256),
|
||||||
|
MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100),
|
||||||
|
MHI_EVENT_CONFIG_HW_DATA(3, 1024, 101),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mhi_controller_config modem_mv31_config = {
|
||||||
|
.max_channels = 128,
|
||||||
|
.timeout_ms = 20000,
|
||||||
|
.num_channels = ARRAY_SIZE(mhi_mv31_channels),
|
||||||
|
.ch_cfg = mhi_mv31_channels,
|
||||||
|
.num_events = ARRAY_SIZE(mhi_mv31_events),
|
||||||
|
.event_cfg = mhi_mv31_events,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mhi_pci_dev_info mhi_mv31_info = {
|
||||||
|
.name = "cinterion-mv31",
|
||||||
|
.config = &modem_mv31_config,
|
||||||
|
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
|
||||||
|
.dma_data_width = 32,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct pci_device_id mhi_pci_id_table[] = {
|
static const struct pci_device_id mhi_pci_id_table[] = {
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0306),
|
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0306),
|
||||||
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx55_info },
|
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx55_info },
|
||||||
@@ -389,6 +423,9 @@ static const struct pci_device_id mhi_pci_id_table[] = {
|
|||||||
/* DW5930e (sdx55), Non-eSIM, It's also T99W175 */
|
/* DW5930e (sdx55), Non-eSIM, It's also T99W175 */
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0b1),
|
{ PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0b1),
|
||||||
.driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info },
|
.driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info },
|
||||||
|
/* MV31-W (Cinterion) */
|
||||||
|
{ PCI_DEVICE(0x1269, 0x00b3),
|
||||||
|
.driver_data = (kernel_ulong_t) &mhi_mv31_info },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(pci, mhi_pci_id_table);
|
MODULE_DEVICE_TABLE(pci, mhi_pci_id_table);
|
||||||
@@ -490,6 +527,7 @@ static int mhi_pci_claim(struct mhi_controller *mhi_cntrl,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
mhi_cntrl->regs = pcim_iomap_table(pdev)[bar_num];
|
mhi_cntrl->regs = pcim_iomap_table(pdev)[bar_num];
|
||||||
|
mhi_cntrl->reg_len = pci_resource_len(pdev, bar_num);
|
||||||
|
|
||||||
err = pci_set_dma_mask(pdev, dma_mask);
|
err = pci_set_dma_mask(pdev, dma_mask);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
@@ -427,8 +427,6 @@ config ADI
|
|||||||
and SSM (Silicon Secured Memory). Intended consumers of this
|
and SSM (Silicon Secured Memory). Intended consumers of this
|
||||||
driver include crash and makedumpfile.
|
driver include crash and makedumpfile.
|
||||||
|
|
||||||
endmenu
|
|
||||||
|
|
||||||
config RANDOM_TRUST_CPU
|
config RANDOM_TRUST_CPU
|
||||||
bool "Trust the CPU manufacturer to initialize Linux's CRNG"
|
bool "Trust the CPU manufacturer to initialize Linux's CRNG"
|
||||||
depends on ARCH_RANDOM
|
depends on ARCH_RANDOM
|
||||||
@@ -452,3 +450,5 @@ config RANDOM_TRUST_BOOTLOADER
|
|||||||
booloader is trustworthy so it will be added to the kernel's entropy
|
booloader is trustworthy so it will be added to the kernel's entropy
|
||||||
pool. Otherwise, say N here so it will be regarded as device input that
|
pool. Otherwise, say N here so it will be regarded as device input that
|
||||||
only mixes the entropy pool.
|
only mixes the entropy pool.
|
||||||
|
|
||||||
|
endmenu
|
||||||
|
|||||||
@@ -470,8 +470,6 @@ int tp3780I_StartDSP(THINKPAD_BD_DATA * pBDData)
|
|||||||
|
|
||||||
int tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData, MW_ABILITIES * pAbilities)
|
int tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData, MW_ABILITIES * pAbilities)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
PRINTK_2(TRACE_TP3780I,
|
PRINTK_2(TRACE_TP3780I,
|
||||||
"tp3780i::tp3780I_QueryAbilities entry pBDData %p\n", pBDData);
|
"tp3780i::tp3780I_QueryAbilities entry pBDData %p\n", pBDData);
|
||||||
|
|
||||||
@@ -502,7 +500,7 @@ int tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData, MW_ABILITIES * pAbilities
|
|||||||
PRINTK_1(TRACE_TP3780I,
|
PRINTK_1(TRACE_TP3780I,
|
||||||
"tp3780i::tp3780I_QueryAbilities exit retval=SUCCESSFUL\n");
|
"tp3780i::tp3780I_QueryAbilities exit retval=SUCCESSFUL\n");
|
||||||
|
|
||||||
return retval;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
|
int tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ static int __init dio_init(void)
|
|||||||
/* Found a board, allocate it an entry in the list */
|
/* Found a board, allocate it an entry in the list */
|
||||||
dev = kzalloc(sizeof(struct dio_dev), GFP_KERNEL);
|
dev = kzalloc(sizeof(struct dio_dev), GFP_KERNEL);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return 0;
|
return -ENOMEM;
|
||||||
|
|
||||||
dev->bus = &dio_bus;
|
dev->bus = &dio_bus;
|
||||||
dev->dev.parent = &dio_bus.dev;
|
dev->dev.parent = &dio_bus.dev;
|
||||||
|
|||||||
@@ -329,12 +329,18 @@ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node)
|
|||||||
|
|
||||||
fw = platform_get_drvdata(pdev);
|
fw = platform_get_drvdata(pdev);
|
||||||
if (!fw)
|
if (!fw)
|
||||||
return NULL;
|
goto err_put_device;
|
||||||
|
|
||||||
if (!kref_get_unless_zero(&fw->consumers))
|
if (!kref_get_unless_zero(&fw->consumers))
|
||||||
return NULL;
|
goto err_put_device;
|
||||||
|
|
||||||
|
put_device(&pdev->dev);
|
||||||
|
|
||||||
return fw;
|
return fw;
|
||||||
|
|
||||||
|
err_put_device:
|
||||||
|
put_device(&pdev->dev);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rpi_firmware_get);
|
EXPORT_SYMBOL_GPL(rpi_firmware_get);
|
||||||
|
|
||||||
|
|||||||
@@ -664,7 +664,7 @@ int zynqmp_pm_write_ggs(u32 index, u32 value)
|
|||||||
EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs);
|
EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zynqmp_pm_write_ggs() - PM API for reading global general storage (ggs)
|
* zynqmp_pm_read_ggs() - PM API for reading global general storage (ggs)
|
||||||
* @index: GGS register index
|
* @index: GGS register index
|
||||||
* @value: Register value to be written
|
* @value: Register value to be written
|
||||||
*
|
*
|
||||||
@@ -697,7 +697,7 @@ int zynqmp_pm_write_pggs(u32 index, u32 value)
|
|||||||
EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs);
|
EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zynqmp_pm_write_pggs() - PM API for reading persistent global general
|
* zynqmp_pm_read_pggs() - PM API for reading persistent global general
|
||||||
* storage (pggs)
|
* storage (pggs)
|
||||||
* @index: PGGS register index
|
* @index: PGGS register index
|
||||||
* @value: Register value to be written
|
* @value: Register value to be written
|
||||||
@@ -1012,7 +1012,24 @@ int zynqmp_pm_set_requirement(const u32 node, const u32 capabilities,
|
|||||||
EXPORT_SYMBOL_GPL(zynqmp_pm_set_requirement);
|
EXPORT_SYMBOL_GPL(zynqmp_pm_set_requirement);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zynqmp_pm_aes - Access AES hardware to encrypt/decrypt the data using
|
* zynqmp_pm_load_pdi - Load and process PDI
|
||||||
|
* @src: Source device where PDI is located
|
||||||
|
* @address: PDI src address
|
||||||
|
*
|
||||||
|
* This function provides support to load PDI from linux
|
||||||
|
*
|
||||||
|
* Return: Returns status, either success or error+reason
|
||||||
|
*/
|
||||||
|
int zynqmp_pm_load_pdi(const u32 src, const u64 address)
|
||||||
|
{
|
||||||
|
return zynqmp_pm_invoke_fn(PM_LOAD_PDI, src,
|
||||||
|
lower_32_bits(address),
|
||||||
|
upper_32_bits(address), 0, NULL);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(zynqmp_pm_load_pdi);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zynqmp_pm_aes_engine - Access AES hardware to encrypt/decrypt the data using
|
||||||
* AES-GCM core.
|
* AES-GCM core.
|
||||||
* @address: Address of the AesParams structure.
|
* @address: Address of the AesParams structure.
|
||||||
* @out: Returned output value
|
* @out: Returned output value
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ config XILINX_PR_DECOUPLER
|
|||||||
depends on HAS_IOMEM
|
depends on HAS_IOMEM
|
||||||
help
|
help
|
||||||
Say Y to enable drivers for Xilinx LogiCORE PR Decoupler
|
Say Y to enable drivers for Xilinx LogiCORE PR Decoupler
|
||||||
or Xilinx Dynamic Function eXchnage AIX Shutdown Manager.
|
or Xilinx Dynamic Function eXchange AIX Shutdown Manager.
|
||||||
The PR Decoupler exists in the FPGA fabric to isolate one
|
The PR Decoupler exists in the FPGA fabric to isolate one
|
||||||
region of the FPGA from the busses while that region is
|
region of the FPGA from the busses while that region is
|
||||||
being reprogrammed during partial reconfig.
|
being reprogrammed during partial reconfig.
|
||||||
@@ -234,4 +234,13 @@ config FPGA_MGR_ZYNQMP_FPGA
|
|||||||
to configure the programmable logic(PL) through PS
|
to configure the programmable logic(PL) through PS
|
||||||
on ZynqMP SoC.
|
on ZynqMP SoC.
|
||||||
|
|
||||||
|
config FPGA_MGR_VERSAL_FPGA
|
||||||
|
tristate "Xilinx Versal FPGA"
|
||||||
|
depends on ARCH_ZYNQMP || COMPILE_TEST
|
||||||
|
help
|
||||||
|
Select this option to enable FPGA manager driver support for
|
||||||
|
Xilinx Versal SoC. This driver uses the firmware interface to
|
||||||
|
configure the programmable logic(PL).
|
||||||
|
|
||||||
|
To compile this as a module, choose M here.
|
||||||
endif # FPGA
|
endif # FPGA
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o
|
|||||||
obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o
|
obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o
|
||||||
obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o
|
obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o
|
||||||
obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA) += zynqmp-fpga.o
|
obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA) += zynqmp-fpga.o
|
||||||
|
obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA) += versal-fpga.o
|
||||||
obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o
|
obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o
|
||||||
obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o
|
obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o
|
||||||
|
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ static int altera_cvp_write_init(struct fpga_manager *mgr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (val & VSE_CVP_STATUS_CFG_RDY) {
|
if (val & VSE_CVP_STATUS_CFG_RDY) {
|
||||||
dev_warn(&mgr->dev, "CvP already started, teardown first\n");
|
dev_warn(&mgr->dev, "CvP already started, tear down first\n");
|
||||||
ret = altera_cvp_teardown(mgr, info);
|
ret = altera_cvp_teardown(mgr, info);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -198,11 +198,13 @@ static const struct fpga_bridge_ops altera_freeze_br_br_ops = {
|
|||||||
.enable_show = altera_freeze_br_enable_show,
|
.enable_show = altera_freeze_br_enable_show,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
static const struct of_device_id altera_freeze_br_of_match[] = {
|
static const struct of_device_id altera_freeze_br_of_match[] = {
|
||||||
{ .compatible = "altr,freeze-bridge-controller", },
|
{ .compatible = "altr,freeze-bridge-controller", },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, altera_freeze_br_of_match);
|
MODULE_DEVICE_TABLE(of, altera_freeze_br_of_match);
|
||||||
|
#endif
|
||||||
|
|
||||||
static int altera_freeze_br_probe(struct platform_device *pdev)
|
static int altera_freeze_br_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -252,11 +252,6 @@ static int fme_mgr_write_complete(struct fpga_manager *mgr,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum fpga_mgr_states fme_mgr_state(struct fpga_manager *mgr)
|
|
||||||
{
|
|
||||||
return FPGA_MGR_STATE_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u64 fme_mgr_status(struct fpga_manager *mgr)
|
static u64 fme_mgr_status(struct fpga_manager *mgr)
|
||||||
{
|
{
|
||||||
struct fme_mgr_priv *priv = mgr->priv;
|
struct fme_mgr_priv *priv = mgr->priv;
|
||||||
@@ -268,7 +263,6 @@ static const struct fpga_manager_ops fme_mgr_ops = {
|
|||||||
.write_init = fme_mgr_write_init,
|
.write_init = fme_mgr_write_init,
|
||||||
.write = fme_mgr_write,
|
.write = fme_mgr_write,
|
||||||
.write_complete = fme_mgr_write_complete,
|
.write_complete = fme_mgr_write_complete,
|
||||||
.state = fme_mgr_state,
|
|
||||||
.status = fme_mgr_status,
|
.status = fme_mgr_status,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* it allows userspace to reset the PR region's logic by disabling and
|
* it allows userspace to reset the PR region's logic by disabling and
|
||||||
* reenabling the bridge to clear things out between accleration runs.
|
* reenabling the bridge to clear things out between acceleration runs.
|
||||||
* so no need to hold the bridges after partial reconfiguration.
|
* so no need to hold the bridges after partial reconfiguration.
|
||||||
*/
|
*/
|
||||||
if (region->get_bridges)
|
if (region->get_bridges)
|
||||||
|
|||||||
@@ -461,7 +461,7 @@ static int n3000_nios_poll_stat_timeout(void __iomem *base, u64 *v)
|
|||||||
* We don't use the time based timeout here for performance.
|
* We don't use the time based timeout here for performance.
|
||||||
*
|
*
|
||||||
* The regbus read/write is on the critical path of Intel PAC N3000
|
* The regbus read/write is on the critical path of Intel PAC N3000
|
||||||
* image programing. The time based timeout checking will add too much
|
* image programming. The time based timeout checking will add too much
|
||||||
* overhead on it. Usually the state changes in 1 or 2 loops on the
|
* overhead on it. Usually the state changes in 1 or 2 loops on the
|
||||||
* test server, and we set 10000 times loop here for safety.
|
* test server, and we set 10000 times loop here for safety.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -74,6 +74,9 @@ static void cci_pci_free_irq(struct pci_dev *pcidev)
|
|||||||
#define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4
|
#define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4
|
||||||
#define PCIE_DEVICE_ID_INTEL_PAC_N3000 0x0B30
|
#define PCIE_DEVICE_ID_INTEL_PAC_N3000 0x0B30
|
||||||
#define PCIE_DEVICE_ID_INTEL_PAC_D5005 0x0B2B
|
#define PCIE_DEVICE_ID_INTEL_PAC_D5005 0x0B2B
|
||||||
|
#define PCIE_DEVICE_ID_SILICOM_PAC_N5010 0x1000
|
||||||
|
#define PCIE_DEVICE_ID_SILICOM_PAC_N5011 0x1001
|
||||||
|
|
||||||
/* VF Device */
|
/* VF Device */
|
||||||
#define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF
|
#define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF
|
||||||
#define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1
|
#define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1
|
||||||
@@ -90,6 +93,8 @@ static struct pci_device_id cci_pcie_id_tbl[] = {
|
|||||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_N3000),},
|
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_N3000),},
|
||||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005),},
|
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005),},
|
||||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005_VF),},
|
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005_VF),},
|
||||||
|
{PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5010),},
|
||||||
|
{PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5011),},
|
||||||
{0,}
|
{0,}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl);
|
MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl);
|
||||||
|
|||||||
@@ -381,6 +381,7 @@ dfl_dev_add(struct dfl_feature_platform_data *pdata,
|
|||||||
|
|
||||||
ddev->type = feature_dev_id_type(pdev);
|
ddev->type = feature_dev_id_type(pdev);
|
||||||
ddev->feature_id = feature->id;
|
ddev->feature_id = feature->id;
|
||||||
|
ddev->revision = feature->revision;
|
||||||
ddev->cdev = pdata->dfl_cdev;
|
ddev->cdev = pdata->dfl_cdev;
|
||||||
|
|
||||||
/* add mmio resource */
|
/* add mmio resource */
|
||||||
@@ -717,6 +718,7 @@ struct build_feature_devs_info {
|
|||||||
*/
|
*/
|
||||||
struct dfl_feature_info {
|
struct dfl_feature_info {
|
||||||
u16 fid;
|
u16 fid;
|
||||||
|
u8 revision;
|
||||||
struct resource mmio_res;
|
struct resource mmio_res;
|
||||||
void __iomem *ioaddr;
|
void __iomem *ioaddr;
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
@@ -796,6 +798,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
|
|||||||
/* save resource information for each feature */
|
/* save resource information for each feature */
|
||||||
feature->dev = fdev;
|
feature->dev = fdev;
|
||||||
feature->id = finfo->fid;
|
feature->id = finfo->fid;
|
||||||
|
feature->revision = finfo->revision;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the FIU header feature has some fundamental functions (sriov
|
* the FIU header feature has some fundamental functions (sriov
|
||||||
@@ -910,19 +913,17 @@ static void build_info_free(struct build_feature_devs_info *binfo)
|
|||||||
devm_kfree(binfo->dev, binfo);
|
devm_kfree(binfo->dev, binfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 feature_size(void __iomem *start)
|
static inline u32 feature_size(u64 value)
|
||||||
{
|
{
|
||||||
u64 v = readq(start + DFH);
|
u32 ofst = FIELD_GET(DFH_NEXT_HDR_OFST, value);
|
||||||
u32 ofst = FIELD_GET(DFH_NEXT_HDR_OFST, v);
|
|
||||||
/* workaround for private features with invalid size, use 4K instead */
|
/* workaround for private features with invalid size, use 4K instead */
|
||||||
return ofst ? ofst : 4096;
|
return ofst ? ofst : 4096;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u16 feature_id(void __iomem *start)
|
static u16 feature_id(u64 value)
|
||||||
{
|
{
|
||||||
u64 v = readq(start + DFH);
|
u16 id = FIELD_GET(DFH_ID, value);
|
||||||
u16 id = FIELD_GET(DFH_ID, v);
|
u8 type = FIELD_GET(DFH_TYPE, value);
|
||||||
u8 type = FIELD_GET(DFH_TYPE, v);
|
|
||||||
|
|
||||||
if (type == DFH_TYPE_FIU)
|
if (type == DFH_TYPE_FIU)
|
||||||
return FEATURE_ID_FIU_HEADER;
|
return FEATURE_ID_FIU_HEADER;
|
||||||
@@ -1021,10 +1022,15 @@ create_feature_instance(struct build_feature_devs_info *binfo,
|
|||||||
unsigned int irq_base, nr_irqs;
|
unsigned int irq_base, nr_irqs;
|
||||||
struct dfl_feature_info *finfo;
|
struct dfl_feature_info *finfo;
|
||||||
int ret;
|
int ret;
|
||||||
|
u8 revision;
|
||||||
|
u64 v;
|
||||||
|
|
||||||
|
v = readq(binfo->ioaddr + ofst);
|
||||||
|
revision = FIELD_GET(DFH_REVISION, v);
|
||||||
|
|
||||||
/* read feature size and id if inputs are invalid */
|
/* read feature size and id if inputs are invalid */
|
||||||
size = size ? size : feature_size(binfo->ioaddr + ofst);
|
size = size ? size : feature_size(v);
|
||||||
fid = fid ? fid : feature_id(binfo->ioaddr + ofst);
|
fid = fid ? fid : feature_id(v);
|
||||||
|
|
||||||
if (binfo->len - ofst < size)
|
if (binfo->len - ofst < size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -1038,6 +1044,7 @@ create_feature_instance(struct build_feature_devs_info *binfo,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
finfo->fid = fid;
|
finfo->fid = fid;
|
||||||
|
finfo->revision = revision;
|
||||||
finfo->mmio_res.start = binfo->start + ofst;
|
finfo->mmio_res.start = binfo->start + ofst;
|
||||||
finfo->mmio_res.end = finfo->mmio_res.start + size - 1;
|
finfo->mmio_res.end = finfo->mmio_res.start + size - 1;
|
||||||
finfo->mmio_res.flags = IORESOURCE_MEM;
|
finfo->mmio_res.flags = IORESOURCE_MEM;
|
||||||
@@ -1166,7 +1173,7 @@ static int parse_feature_private(struct build_feature_devs_info *binfo,
|
|||||||
{
|
{
|
||||||
if (!is_feature_dev_detected(binfo)) {
|
if (!is_feature_dev_detected(binfo)) {
|
||||||
dev_err(binfo->dev, "the private feature 0x%x does not belong to any AFU.\n",
|
dev_err(binfo->dev, "the private feature 0x%x does not belong to any AFU.\n",
|
||||||
feature_id(binfo->ioaddr + ofst));
|
feature_id(readq(binfo->ioaddr + ofst)));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ struct dfl_feature_irq_ctx {
|
|||||||
* @id: sub feature id.
|
* @id: sub feature id.
|
||||||
* @resource_index: each sub feature has one mmio resource for its registers.
|
* @resource_index: each sub feature has one mmio resource for its registers.
|
||||||
* this index is used to find its mmio resource from the
|
* this index is used to find its mmio resource from the
|
||||||
* feature dev (platform device)'s reources.
|
* feature dev (platform device)'s resources.
|
||||||
* @ioaddr: mapped mmio resource address.
|
* @ioaddr: mapped mmio resource address.
|
||||||
* @irq_ctx: interrupt context list.
|
* @irq_ctx: interrupt context list.
|
||||||
* @nr_irqs: number of interrupt contexts.
|
* @nr_irqs: number of interrupt contexts.
|
||||||
@@ -243,6 +243,7 @@ struct dfl_feature_irq_ctx {
|
|||||||
struct dfl_feature {
|
struct dfl_feature {
|
||||||
struct platform_device *dev;
|
struct platform_device *dev;
|
||||||
u16 id;
|
u16 id;
|
||||||
|
u8 revision;
|
||||||
int resource_index;
|
int resource_index;
|
||||||
void __iomem *ioaddr;
|
void __iomem *ioaddr;
|
||||||
struct dfl_feature_irq_ctx *irq_ctx;
|
struct dfl_feature_irq_ctx *irq_ctx;
|
||||||
|
|||||||
@@ -228,9 +228,9 @@ EXPORT_SYMBOL_GPL(fpga_bridges_put);
|
|||||||
* @info: fpga image specific information
|
* @info: fpga image specific information
|
||||||
* @bridge_list: list of FPGA bridges
|
* @bridge_list: list of FPGA bridges
|
||||||
*
|
*
|
||||||
* Get an exclusive reference to the bridge and and it to the list.
|
* Get an exclusive reference to the bridge and it to the list.
|
||||||
*
|
*
|
||||||
* Return 0 for success, error code from of_fpga_bridge_get() othewise.
|
* Return 0 for success, error code from of_fpga_bridge_get() otherwise.
|
||||||
*/
|
*/
|
||||||
int of_fpga_bridge_get_to_list(struct device_node *np,
|
int of_fpga_bridge_get_to_list(struct device_node *np,
|
||||||
struct fpga_image_info *info,
|
struct fpga_image_info *info,
|
||||||
@@ -258,9 +258,9 @@ EXPORT_SYMBOL_GPL(of_fpga_bridge_get_to_list);
|
|||||||
* @info: fpga image specific information
|
* @info: fpga image specific information
|
||||||
* @bridge_list: list of FPGA bridges
|
* @bridge_list: list of FPGA bridges
|
||||||
*
|
*
|
||||||
* Get an exclusive reference to the bridge and and it to the list.
|
* Get an exclusive reference to the bridge and it to the list.
|
||||||
*
|
*
|
||||||
* Return 0 for success, error code from fpga_bridge_get() othewise.
|
* Return 0 for success, error code from fpga_bridge_get() otherwise.
|
||||||
*/
|
*/
|
||||||
int fpga_bridge_get_to_list(struct device *dev,
|
int fpga_bridge_get_to_list(struct device *dev,
|
||||||
struct fpga_image_info *info,
|
struct fpga_image_info *info,
|
||||||
|
|||||||
@@ -25,6 +25,72 @@ struct fpga_mgr_devres {
|
|||||||
struct fpga_manager *mgr;
|
struct fpga_manager *mgr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline void fpga_mgr_fpga_remove(struct fpga_manager *mgr)
|
||||||
|
{
|
||||||
|
if (mgr->mops->fpga_remove)
|
||||||
|
mgr->mops->fpga_remove(mgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline enum fpga_mgr_states fpga_mgr_state(struct fpga_manager *mgr)
|
||||||
|
{
|
||||||
|
if (mgr->mops->state)
|
||||||
|
return mgr->mops->state(mgr);
|
||||||
|
return FPGA_MGR_STATE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u64 fpga_mgr_status(struct fpga_manager *mgr)
|
||||||
|
{
|
||||||
|
if (mgr->mops->status)
|
||||||
|
return mgr->mops->status(mgr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int fpga_mgr_write(struct fpga_manager *mgr, const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
if (mgr->mops->write)
|
||||||
|
return mgr->mops->write(mgr, buf, count);
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After all the FPGA image has been written, do the device specific steps to
|
||||||
|
* finish and set the FPGA into operating mode.
|
||||||
|
*/
|
||||||
|
static inline int fpga_mgr_write_complete(struct fpga_manager *mgr,
|
||||||
|
struct fpga_image_info *info)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE;
|
||||||
|
if (mgr->mops->write_complete)
|
||||||
|
ret = mgr->mops->write_complete(mgr, info);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&mgr->dev, "Error after writing image data to FPGA\n");
|
||||||
|
mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
mgr->state = FPGA_MGR_STATE_OPERATING;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int fpga_mgr_write_init(struct fpga_manager *mgr,
|
||||||
|
struct fpga_image_info *info,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
if (mgr->mops->write_init)
|
||||||
|
return mgr->mops->write_init(mgr, info, buf, count);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int fpga_mgr_write_sg(struct fpga_manager *mgr,
|
||||||
|
struct sg_table *sgt)
|
||||||
|
{
|
||||||
|
if (mgr->mops->write_sg)
|
||||||
|
return mgr->mops->write_sg(mgr, sgt);
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpga_image_info_alloc - Allocate an FPGA image info struct
|
* fpga_image_info_alloc - Allocate an FPGA image info struct
|
||||||
* @dev: owning device
|
* @dev: owning device
|
||||||
@@ -83,9 +149,9 @@ static int fpga_mgr_write_init_buf(struct fpga_manager *mgr,
|
|||||||
|
|
||||||
mgr->state = FPGA_MGR_STATE_WRITE_INIT;
|
mgr->state = FPGA_MGR_STATE_WRITE_INIT;
|
||||||
if (!mgr->mops->initial_header_size)
|
if (!mgr->mops->initial_header_size)
|
||||||
ret = mgr->mops->write_init(mgr, info, NULL, 0);
|
ret = fpga_mgr_write_init(mgr, info, NULL, 0);
|
||||||
else
|
else
|
||||||
ret = mgr->mops->write_init(
|
ret = fpga_mgr_write_init(
|
||||||
mgr, info, buf, min(mgr->mops->initial_header_size, count));
|
mgr, info, buf, min(mgr->mops->initial_header_size, count));
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -137,27 +203,6 @@ static int fpga_mgr_write_init_sg(struct fpga_manager *mgr,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* After all the FPGA image has been written, do the device specific steps to
|
|
||||||
* finish and set the FPGA into operating mode.
|
|
||||||
*/
|
|
||||||
static int fpga_mgr_write_complete(struct fpga_manager *mgr,
|
|
||||||
struct fpga_image_info *info)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE;
|
|
||||||
ret = mgr->mops->write_complete(mgr, info);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&mgr->dev, "Error after writing image data to FPGA\n");
|
|
||||||
mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
mgr->state = FPGA_MGR_STATE_OPERATING;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fpga_mgr_buf_load_sg - load fpga from image in buffer from a scatter list
|
* fpga_mgr_buf_load_sg - load fpga from image in buffer from a scatter list
|
||||||
* @mgr: fpga manager
|
* @mgr: fpga manager
|
||||||
@@ -188,13 +233,13 @@ static int fpga_mgr_buf_load_sg(struct fpga_manager *mgr,
|
|||||||
/* Write the FPGA image to the FPGA. */
|
/* Write the FPGA image to the FPGA. */
|
||||||
mgr->state = FPGA_MGR_STATE_WRITE;
|
mgr->state = FPGA_MGR_STATE_WRITE;
|
||||||
if (mgr->mops->write_sg) {
|
if (mgr->mops->write_sg) {
|
||||||
ret = mgr->mops->write_sg(mgr, sgt);
|
ret = fpga_mgr_write_sg(mgr, sgt);
|
||||||
} else {
|
} else {
|
||||||
struct sg_mapping_iter miter;
|
struct sg_mapping_iter miter;
|
||||||
|
|
||||||
sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG);
|
sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG);
|
||||||
while (sg_miter_next(&miter)) {
|
while (sg_miter_next(&miter)) {
|
||||||
ret = mgr->mops->write(mgr, miter.addr, miter.length);
|
ret = fpga_mgr_write(mgr, miter.addr, miter.length);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -224,7 +269,7 @@ static int fpga_mgr_buf_load_mapped(struct fpga_manager *mgr,
|
|||||||
* Write the FPGA image to the FPGA.
|
* Write the FPGA image to the FPGA.
|
||||||
*/
|
*/
|
||||||
mgr->state = FPGA_MGR_STATE_WRITE;
|
mgr->state = FPGA_MGR_STATE_WRITE;
|
||||||
ret = mgr->mops->write(mgr, buf, count);
|
ret = fpga_mgr_write(mgr, buf, count);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&mgr->dev, "Error while writing image data to FPGA\n");
|
dev_err(&mgr->dev, "Error while writing image data to FPGA\n");
|
||||||
mgr->state = FPGA_MGR_STATE_WRITE_ERR;
|
mgr->state = FPGA_MGR_STATE_WRITE_ERR;
|
||||||
@@ -417,10 +462,7 @@ static ssize_t status_show(struct device *dev,
|
|||||||
u64 status;
|
u64 status;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
if (!mgr->mops->status)
|
status = fpga_mgr_status(mgr);
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
status = mgr->mops->status(mgr);
|
|
||||||
|
|
||||||
if (status & FPGA_MGR_STATUS_OPERATION_ERR)
|
if (status & FPGA_MGR_STATUS_OPERATION_ERR)
|
||||||
len += sprintf(buf + len, "reconfig operation error\n");
|
len += sprintf(buf + len, "reconfig operation error\n");
|
||||||
@@ -568,9 +610,7 @@ struct fpga_manager *fpga_mgr_create(struct device *parent, const char *name,
|
|||||||
struct fpga_manager *mgr;
|
struct fpga_manager *mgr;
|
||||||
int id, ret;
|
int id, ret;
|
||||||
|
|
||||||
if (!mops || !mops->write_complete || !mops->state ||
|
if (!mops) {
|
||||||
!mops->write_init || (!mops->write && !mops->write_sg) ||
|
|
||||||
(mops->write && mops->write_sg)) {
|
|
||||||
dev_err(parent, "Attempt to register without fpga_manager_ops\n");
|
dev_err(parent, "Attempt to register without fpga_manager_ops\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -688,7 +728,7 @@ int fpga_mgr_register(struct fpga_manager *mgr)
|
|||||||
* from device. FPGA may be in reset mode or may have been programmed
|
* from device. FPGA may be in reset mode or may have been programmed
|
||||||
* by bootloader or EEPROM.
|
* by bootloader or EEPROM.
|
||||||
*/
|
*/
|
||||||
mgr->state = mgr->mops->state(mgr);
|
mgr->state = fpga_mgr_state(mgr);
|
||||||
|
|
||||||
ret = device_add(&mgr->dev);
|
ret = device_add(&mgr->dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
@@ -719,8 +759,7 @@ void fpga_mgr_unregister(struct fpga_manager *mgr)
|
|||||||
* If the low level driver provides a method for putting fpga into
|
* If the low level driver provides a method for putting fpga into
|
||||||
* a desired state upon unregister, do it.
|
* a desired state upon unregister, do it.
|
||||||
*/
|
*/
|
||||||
if (mgr->mops->fpga_remove)
|
fpga_mgr_fpga_remove(mgr);
|
||||||
mgr->mops->fpga_remove(mgr);
|
|
||||||
|
|
||||||
device_unregister(&mgr->dev);
|
device_unregister(&mgr->dev);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -388,13 +388,7 @@ static int s10_ops_write_complete(struct fpga_manager *mgr,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum fpga_mgr_states s10_ops_state(struct fpga_manager *mgr)
|
|
||||||
{
|
|
||||||
return FPGA_MGR_STATE_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct fpga_manager_ops s10_ops = {
|
static const struct fpga_manager_ops s10_ops = {
|
||||||
.state = s10_ops_state,
|
|
||||||
.write_init = s10_ops_write_init,
|
.write_init = s10_ops_write_init,
|
||||||
.write = s10_ops_write,
|
.write = s10_ops_write,
|
||||||
.write_complete = s10_ops_write_complete,
|
.write_complete = s10_ops_write_complete,
|
||||||
|
|||||||
@@ -32,11 +32,6 @@ struct ts73xx_fpga_priv {
|
|||||||
struct device *dev;
|
struct device *dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum fpga_mgr_states ts73xx_fpga_state(struct fpga_manager *mgr)
|
|
||||||
{
|
|
||||||
return FPGA_MGR_STATE_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ts73xx_fpga_write_init(struct fpga_manager *mgr,
|
static int ts73xx_fpga_write_init(struct fpga_manager *mgr,
|
||||||
struct fpga_image_info *info,
|
struct fpga_image_info *info,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
@@ -98,7 +93,6 @@ static int ts73xx_fpga_write_complete(struct fpga_manager *mgr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct fpga_manager_ops ts73xx_fpga_ops = {
|
static const struct fpga_manager_ops ts73xx_fpga_ops = {
|
||||||
.state = ts73xx_fpga_state,
|
|
||||||
.write_init = ts73xx_fpga_write_init,
|
.write_init = ts73xx_fpga_write_init,
|
||||||
.write = ts73xx_fpga_write,
|
.write = ts73xx_fpga_write,
|
||||||
.write_complete = ts73xx_fpga_write_complete,
|
.write_complete = ts73xx_fpga_write_complete,
|
||||||
|
|||||||
83
drivers/fpga/versal-fpga.c
Normal file
83
drivers/fpga/versal-fpga.c
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019-2021 Xilinx, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/fpga/fpga-mgr.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/firmware/xlnx-zynqmp.h>
|
||||||
|
|
||||||
|
static int versal_fpga_ops_write_init(struct fpga_manager *mgr,
|
||||||
|
struct fpga_image_info *info,
|
||||||
|
const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int versal_fpga_ops_write(struct fpga_manager *mgr,
|
||||||
|
const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
dma_addr_t dma_addr = 0;
|
||||||
|
char *kbuf;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
kbuf = dma_alloc_coherent(mgr->dev.parent, size, &dma_addr, GFP_KERNEL);
|
||||||
|
if (!kbuf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
memcpy(kbuf, buf, size);
|
||||||
|
ret = zynqmp_pm_load_pdi(PDI_SRC_DDR, dma_addr);
|
||||||
|
dma_free_coherent(mgr->dev.parent, size, kbuf, dma_addr);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fpga_manager_ops versal_fpga_ops = {
|
||||||
|
.write_init = versal_fpga_ops_write_init,
|
||||||
|
.write = versal_fpga_ops_write,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int versal_fpga_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct fpga_manager *mgr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "no usable DMA configuration\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
mgr = devm_fpga_mgr_create(dev, "Xilinx Versal FPGA Manager",
|
||||||
|
&versal_fpga_ops, NULL);
|
||||||
|
if (!mgr)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
return devm_fpga_mgr_register(dev, mgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id versal_fpga_of_match[] = {
|
||||||
|
{ .compatible = "xlnx,versal-fpga", },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, versal_fpga_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver versal_fpga_driver = {
|
||||||
|
.probe = versal_fpga_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "versal_fpga_manager",
|
||||||
|
.of_match_table = of_match_ptr(versal_fpga_of_match),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(versal_fpga_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Nava kishore Manne <nava.manne@xilinx.com>");
|
||||||
|
MODULE_AUTHOR("Appana Durga Kedareswara rao <appanad.durga.rao@xilinx.com>");
|
||||||
|
MODULE_DESCRIPTION("Xilinx Versal FPGA Manager");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
@@ -81,6 +81,7 @@ static const struct fpga_bridge_ops xlnx_pr_decoupler_br_ops = {
|
|||||||
.enable_show = xlnx_pr_decoupler_enable_show,
|
.enable_show = xlnx_pr_decoupler_enable_show,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
static const struct xlnx_config_data decoupler_config = {
|
static const struct xlnx_config_data decoupler_config = {
|
||||||
.name = "Xilinx PR Decoupler",
|
.name = "Xilinx PR Decoupler",
|
||||||
};
|
};
|
||||||
@@ -99,6 +100,7 @@ static const struct of_device_id xlnx_pr_decoupler_of_match[] = {
|
|||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, xlnx_pr_decoupler_of_match);
|
MODULE_DEVICE_TABLE(of, xlnx_pr_decoupler_of_match);
|
||||||
|
#endif
|
||||||
|
|
||||||
static int xlnx_pr_decoupler_probe(struct platform_device *pdev)
|
static int xlnx_pr_decoupler_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -256,11 +256,13 @@ static int xilinx_spi_probe(struct spi_device *spi)
|
|||||||
return devm_fpga_mgr_register(&spi->dev, mgr);
|
return devm_fpga_mgr_register(&spi->dev, mgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
static const struct of_device_id xlnx_spi_of_match[] = {
|
static const struct of_device_id xlnx_spi_of_match[] = {
|
||||||
{ .compatible = "xlnx,fpga-slave-serial", },
|
{ .compatible = "xlnx,fpga-slave-serial", },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, xlnx_spi_of_match);
|
MODULE_DEVICE_TABLE(of, xlnx_spi_of_match);
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct spi_driver xilinx_slave_spi_driver = {
|
static struct spi_driver xilinx_slave_spi_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ static void zynq_step_dma(struct zynq_fpga_priv *priv)
|
|||||||
|
|
||||||
/* Once the first transfer is queued we can turn on the ISR, future
|
/* Once the first transfer is queued we can turn on the ISR, future
|
||||||
* calls to zynq_step_dma will happen from the ISR context. The
|
* calls to zynq_step_dma will happen from the ISR context. The
|
||||||
* dma_lock spinlock guarentees this handover is done coherently, the
|
* dma_lock spinlock guarantees this handover is done coherently, the
|
||||||
* ISR enable is put at the end to avoid another CPU spinning in the
|
* ISR enable is put at the end to avoid another CPU spinning in the
|
||||||
* ISR on this lock.
|
* ISR on this lock.
|
||||||
*/
|
*/
|
||||||
@@ -267,7 +267,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr,
|
|||||||
ctrl = zynq_fpga_read(priv, CTRL_OFFSET);
|
ctrl = zynq_fpga_read(priv, CTRL_OFFSET);
|
||||||
if (!(ctrl & CTRL_SEC_EN_MASK)) {
|
if (!(ctrl & CTRL_SEC_EN_MASK)) {
|
||||||
dev_err(&mgr->dev,
|
dev_err(&mgr->dev,
|
||||||
"System not secure, can't use crypted bitstreams\n");
|
"System not secure, can't use encrypted bitstreams\n");
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
@@ -344,7 +344,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr,
|
|||||||
|
|
||||||
/* set configuration register with following options:
|
/* set configuration register with following options:
|
||||||
* - enable PCAP interface
|
* - enable PCAP interface
|
||||||
* - set throughput for maximum speed (if bistream not crypted)
|
* - set throughput for maximum speed (if bistream not encrypted)
|
||||||
* - set CPU in user mode
|
* - set CPU in user mode
|
||||||
*/
|
*/
|
||||||
ctrl = zynq_fpga_read(priv, CTRL_OFFSET);
|
ctrl = zynq_fpga_read(priv, CTRL_OFFSET);
|
||||||
|
|||||||
@@ -66,12 +66,6 @@ static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int zynqmp_fpga_ops_write_complete(struct fpga_manager *mgr,
|
|
||||||
struct fpga_image_info *info)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr)
|
static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr)
|
||||||
{
|
{
|
||||||
u32 status = 0;
|
u32 status = 0;
|
||||||
@@ -87,7 +81,6 @@ static const struct fpga_manager_ops zynqmp_fpga_ops = {
|
|||||||
.state = zynqmp_fpga_ops_state,
|
.state = zynqmp_fpga_ops_state,
|
||||||
.write_init = zynqmp_fpga_ops_write_init,
|
.write_init = zynqmp_fpga_ops_write_init,
|
||||||
.write = zynqmp_fpga_ops_write,
|
.write = zynqmp_fpga_ops_write,
|
||||||
.write_complete = zynqmp_fpga_ops_write_complete,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int zynqmp_fpga_probe(struct platform_device *pdev)
|
static int zynqmp_fpga_probe(struct platform_device *pdev)
|
||||||
@@ -110,12 +103,13 @@ static int zynqmp_fpga_probe(struct platform_device *pdev)
|
|||||||
return devm_fpga_mgr_register(dev, mgr);
|
return devm_fpga_mgr_register(dev, mgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
static const struct of_device_id zynqmp_fpga_of_match[] = {
|
static const struct of_device_id zynqmp_fpga_of_match[] = {
|
||||||
{ .compatible = "xlnx,zynqmp-pcap-fpga", },
|
{ .compatible = "xlnx,zynqmp-pcap-fpga", },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match);
|
MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match);
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct platform_driver zynqmp_fpga_driver = {
|
static struct platform_driver zynqmp_fpga_driver = {
|
||||||
.probe = zynqmp_fpga_probe,
|
.probe = zynqmp_fpga_probe,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ menuconfig CORESIGHT
|
|||||||
depends on OF || ACPI
|
depends on OF || ACPI
|
||||||
select ARM_AMBA
|
select ARM_AMBA
|
||||||
select PERF_EVENTS
|
select PERF_EVENTS
|
||||||
|
select CONFIGFS_FS
|
||||||
help
|
help
|
||||||
This framework provides a kernel interface for the CoreSight debug
|
This framework provides a kernel interface for the CoreSight debug
|
||||||
and trace drivers to register themselves with. It's intended to build
|
and trace drivers to register themselves with. It's intended to build
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
#
|
#
|
||||||
obj-$(CONFIG_CORESIGHT) += coresight.o
|
obj-$(CONFIG_CORESIGHT) += coresight.o
|
||||||
coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
|
coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
|
||||||
coresight-sysfs.o
|
coresight-sysfs.o coresight-syscfg.o coresight-config.o \
|
||||||
|
coresight-cfg-preload.o coresight-cfg-afdo.o \
|
||||||
|
coresight-syscfg-configfs.o
|
||||||
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o
|
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o
|
||||||
coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \
|
coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \
|
||||||
coresight-tmc-etr.o
|
coresight-tmc-etr.o
|
||||||
@@ -16,7 +18,8 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o
|
|||||||
coresight-etm3x-y := coresight-etm3x-core.o coresight-etm-cp14.o \
|
coresight-etm3x-y := coresight-etm3x-core.o coresight-etm-cp14.o \
|
||||||
coresight-etm3x-sysfs.o
|
coresight-etm3x-sysfs.o
|
||||||
obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o
|
obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o
|
||||||
coresight-etm4x-y := coresight-etm4x-core.o coresight-etm4x-sysfs.o
|
coresight-etm4x-y := coresight-etm4x-core.o coresight-etm4x-sysfs.o \
|
||||||
|
coresight-etm4x-cfg.o
|
||||||
obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o
|
obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o
|
||||||
obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o
|
obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o
|
||||||
obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o
|
obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o
|
||||||
|
|||||||
153
drivers/hwtracing/coresight/coresight-cfg-afdo.c
Normal file
153
drivers/hwtracing/coresight/coresight-cfg-afdo.c
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright(C) 2020 Linaro Limited. All rights reserved.
|
||||||
|
* Author: Mike Leach <mike.leach@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "coresight-config.h"
|
||||||
|
|
||||||
|
/* ETMv4 includes and features */
|
||||||
|
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
|
||||||
|
#include "coresight-etm4x-cfg.h"
|
||||||
|
|
||||||
|
/* preload configurations and features */
|
||||||
|
|
||||||
|
/* preload in features for ETMv4 */
|
||||||
|
|
||||||
|
/* strobe feature */
|
||||||
|
static struct cscfg_parameter_desc strobe_params[] = {
|
||||||
|
{
|
||||||
|
.name = "window",
|
||||||
|
.value = 5000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "period",
|
||||||
|
.value = 10000,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct cscfg_regval_desc strobe_regs[] = {
|
||||||
|
/* resource selectors */
|
||||||
|
{
|
||||||
|
.type = CS_CFG_REG_TYPE_RESOURCE,
|
||||||
|
.offset = TRCRSCTLRn(2),
|
||||||
|
.hw_info = ETM4_CFG_RES_SEL,
|
||||||
|
.val32 = 0x20001,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = CS_CFG_REG_TYPE_RESOURCE,
|
||||||
|
.offset = TRCRSCTLRn(3),
|
||||||
|
.hw_info = ETM4_CFG_RES_SEQ,
|
||||||
|
.val32 = 0x20002,
|
||||||
|
},
|
||||||
|
/* strobe window counter 0 - reload from param 0 */
|
||||||
|
{
|
||||||
|
.type = CS_CFG_REG_TYPE_RESOURCE | CS_CFG_REG_TYPE_VAL_SAVE,
|
||||||
|
.offset = TRCCNTVRn(0),
|
||||||
|
.hw_info = ETM4_CFG_RES_CTR,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = CS_CFG_REG_TYPE_RESOURCE | CS_CFG_REG_TYPE_VAL_PARAM,
|
||||||
|
.offset = TRCCNTRLDVRn(0),
|
||||||
|
.hw_info = ETM4_CFG_RES_CTR,
|
||||||
|
.val32 = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = CS_CFG_REG_TYPE_RESOURCE,
|
||||||
|
.offset = TRCCNTCTLRn(0),
|
||||||
|
.hw_info = ETM4_CFG_RES_CTR,
|
||||||
|
.val32 = 0x10001,
|
||||||
|
},
|
||||||
|
/* strobe period counter 1 - reload from param 1 */
|
||||||
|
{
|
||||||
|
.type = CS_CFG_REG_TYPE_RESOURCE | CS_CFG_REG_TYPE_VAL_SAVE,
|
||||||
|
.offset = TRCCNTVRn(1),
|
||||||
|
.hw_info = ETM4_CFG_RES_CTR,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = CS_CFG_REG_TYPE_RESOURCE | CS_CFG_REG_TYPE_VAL_PARAM,
|
||||||
|
.offset = TRCCNTRLDVRn(1),
|
||||||
|
.hw_info = ETM4_CFG_RES_CTR,
|
||||||
|
.val32 = 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = CS_CFG_REG_TYPE_RESOURCE,
|
||||||
|
.offset = TRCCNTCTLRn(1),
|
||||||
|
.hw_info = ETM4_CFG_RES_CTR,
|
||||||
|
.val32 = 0x8102,
|
||||||
|
},
|
||||||
|
/* sequencer */
|
||||||
|
{
|
||||||
|
.type = CS_CFG_REG_TYPE_RESOURCE,
|
||||||
|
.offset = TRCSEQEVRn(0),
|
||||||
|
.hw_info = ETM4_CFG_RES_SEQ,
|
||||||
|
.val32 = 0x0081,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = CS_CFG_REG_TYPE_RESOURCE,
|
||||||
|
.offset = TRCSEQEVRn(1),
|
||||||
|
.hw_info = ETM4_CFG_RES_SEQ,
|
||||||
|
.val32 = 0x0000,
|
||||||
|
},
|
||||||
|
/* view-inst */
|
||||||
|
{
|
||||||
|
.type = CS_CFG_REG_TYPE_STD | CS_CFG_REG_TYPE_VAL_MASK,
|
||||||
|
.offset = TRCVICTLR,
|
||||||
|
.val32 = 0x0003,
|
||||||
|
.mask32 = 0x0003,
|
||||||
|
},
|
||||||
|
/* end of regs */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cscfg_feature_desc strobe_etm4x = {
|
||||||
|
.name = "strobing",
|
||||||
|
.description = "Generate periodic trace capture windows.\n"
|
||||||
|
"parameter \'window\': a number of CPU cycles (W)\n"
|
||||||
|
"parameter \'period\': trace enabled for W cycles every period x W cycles\n",
|
||||||
|
.match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4,
|
||||||
|
.nr_params = ARRAY_SIZE(strobe_params),
|
||||||
|
.params_desc = strobe_params,
|
||||||
|
.nr_regs = ARRAY_SIZE(strobe_regs),
|
||||||
|
.regs_desc = strobe_regs,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* create an autofdo configuration */
|
||||||
|
|
||||||
|
/* we will provide 9 sets of preset parameter values */
|
||||||
|
#define AFDO_NR_PRESETS 9
|
||||||
|
/* the total number of parameters in used features */
|
||||||
|
#define AFDO_NR_PARAMS ARRAY_SIZE(strobe_params)
|
||||||
|
|
||||||
|
static const char *afdo_ref_names[] = {
|
||||||
|
"strobing",
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set of presets leaves strobing window constant while varying period to allow
|
||||||
|
* experimentation with mark / space ratios for various workloads
|
||||||
|
*/
|
||||||
|
static u64 afdo_presets[AFDO_NR_PRESETS][AFDO_NR_PARAMS] = {
|
||||||
|
{ 5000, 2 },
|
||||||
|
{ 5000, 4 },
|
||||||
|
{ 5000, 8 },
|
||||||
|
{ 5000, 16 },
|
||||||
|
{ 5000, 64 },
|
||||||
|
{ 5000, 128 },
|
||||||
|
{ 5000, 512 },
|
||||||
|
{ 5000, 1024 },
|
||||||
|
{ 5000, 4096 },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cscfg_config_desc afdo_etm4x = {
|
||||||
|
.name = "autofdo",
|
||||||
|
.description = "Setup ETMs with strobing for autofdo\n"
|
||||||
|
"Supplied presets allow experimentation with mark-space ratio for various loads\n",
|
||||||
|
.nr_feat_refs = ARRAY_SIZE(afdo_ref_names),
|
||||||
|
.feat_ref_names = afdo_ref_names,
|
||||||
|
.nr_presets = AFDO_NR_PRESETS,
|
||||||
|
.nr_total_params = AFDO_NR_PARAMS,
|
||||||
|
.presets = &afdo_presets[0][0],
|
||||||
|
};
|
||||||
|
|
||||||
|
/* end of ETM4x configurations */
|
||||||
|
#endif /* IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) */
|
||||||
31
drivers/hwtracing/coresight/coresight-cfg-preload.c
Normal file
31
drivers/hwtracing/coresight/coresight-cfg-preload.c
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright(C) 2020 Linaro Limited. All rights reserved.
|
||||||
|
* Author: Mike Leach <mike.leach@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "coresight-cfg-preload.h"
|
||||||
|
#include "coresight-config.h"
|
||||||
|
#include "coresight-syscfg.h"
|
||||||
|
|
||||||
|
/* Basic features and configurations pre-loaded on initialisation */
|
||||||
|
|
||||||
|
static struct cscfg_feature_desc *preload_feats[] = {
|
||||||
|
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
|
||||||
|
&strobe_etm4x,
|
||||||
|
#endif
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct cscfg_config_desc *preload_cfgs[] = {
|
||||||
|
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
|
||||||
|
&afdo_etm4x,
|
||||||
|
#endif
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
/* preload called on initialisation */
|
||||||
|
int cscfg_preload(void)
|
||||||
|
{
|
||||||
|
return cscfg_load_config_sets(preload_cfgs, preload_feats);
|
||||||
|
}
|
||||||
13
drivers/hwtracing/coresight/coresight-cfg-preload.h
Normal file
13
drivers/hwtracing/coresight/coresight-cfg-preload.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright(C) 2020 Linaro Limited. All rights reserved.
|
||||||
|
* Author: Mike Leach <mike.leach@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* declare preloaded configurations and features */
|
||||||
|
|
||||||
|
/* from coresight-cfg-afdo.c - etm 4x features */
|
||||||
|
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
|
||||||
|
extern struct cscfg_feature_desc strobe_etm4x;
|
||||||
|
extern struct cscfg_config_desc afdo_etm4x;
|
||||||
|
#endif
|
||||||
272
drivers/hwtracing/coresight/coresight-config.c
Normal file
272
drivers/hwtracing/coresight/coresight-config.c
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright(C) 2020 Linaro Limited. All rights reserved.
|
||||||
|
* Author: Mike Leach <mike.leach@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/sysfs.h>
|
||||||
|
#include "coresight-config.h"
|
||||||
|
#include "coresight-priv.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This provides a set of generic functions that operate on configurations
|
||||||
|
* and features to manage the handling of parameters, the programming and
|
||||||
|
* saving of registers used by features on devices.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the value held in the register structure into the driver internal memory
|
||||||
|
* location.
|
||||||
|
*/
|
||||||
|
static void cscfg_set_reg(struct cscfg_regval_csdev *reg_csdev)
|
||||||
|
{
|
||||||
|
u32 *p_val32 = (u32 *)reg_csdev->driver_regval;
|
||||||
|
u32 tmp32 = reg_csdev->reg_desc.val32;
|
||||||
|
|
||||||
|
if (reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_64BIT) {
|
||||||
|
*((u64 *)reg_csdev->driver_regval) = reg_csdev->reg_desc.val64;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_MASK) {
|
||||||
|
tmp32 = *p_val32;
|
||||||
|
tmp32 &= ~reg_csdev->reg_desc.mask32;
|
||||||
|
tmp32 |= reg_csdev->reg_desc.val32 & reg_csdev->reg_desc.mask32;
|
||||||
|
}
|
||||||
|
*p_val32 = tmp32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the driver value into the reg if this is marked as one we want to save.
|
||||||
|
*/
|
||||||
|
static void cscfg_save_reg(struct cscfg_regval_csdev *reg_csdev)
|
||||||
|
{
|
||||||
|
if (!(reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_SAVE))
|
||||||
|
return;
|
||||||
|
if (reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_64BIT)
|
||||||
|
reg_csdev->reg_desc.val64 = *(u64 *)(reg_csdev->driver_regval);
|
||||||
|
else
|
||||||
|
reg_csdev->reg_desc.val32 = *(u32 *)(reg_csdev->driver_regval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some register values are set from parameters. Initialise these registers
|
||||||
|
* from the current parameter values.
|
||||||
|
*/
|
||||||
|
static void cscfg_init_reg_param(struct cscfg_feature_csdev *feat_csdev,
|
||||||
|
struct cscfg_regval_desc *reg_desc,
|
||||||
|
struct cscfg_regval_csdev *reg_csdev)
|
||||||
|
{
|
||||||
|
struct cscfg_parameter_csdev *param_csdev;
|
||||||
|
|
||||||
|
/* for param, load routines have validated the index */
|
||||||
|
param_csdev = &feat_csdev->params_csdev[reg_desc->param_idx];
|
||||||
|
param_csdev->reg_csdev = reg_csdev;
|
||||||
|
param_csdev->val64 = reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_64BIT;
|
||||||
|
|
||||||
|
if (param_csdev->val64)
|
||||||
|
reg_csdev->reg_desc.val64 = param_csdev->current_value;
|
||||||
|
else
|
||||||
|
reg_csdev->reg_desc.val32 = (u32)param_csdev->current_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set values into the driver locations referenced in cscfg_reg_csdev */
|
||||||
|
static int cscfg_set_on_enable(struct cscfg_feature_csdev *feat_csdev)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
spin_lock_irqsave(feat_csdev->drv_spinlock, flags);
|
||||||
|
for (i = 0; i < feat_csdev->nr_regs; i++)
|
||||||
|
cscfg_set_reg(&feat_csdev->regs_csdev[i]);
|
||||||
|
spin_unlock_irqrestore(feat_csdev->drv_spinlock, flags);
|
||||||
|
dev_dbg(&feat_csdev->csdev->dev, "Feature %s: %s",
|
||||||
|
feat_csdev->feat_desc->name, "set on enable");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy back values from the driver locations referenced in cscfg_reg_csdev */
|
||||||
|
static void cscfg_save_on_disable(struct cscfg_feature_csdev *feat_csdev)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
spin_lock_irqsave(feat_csdev->drv_spinlock, flags);
|
||||||
|
for (i = 0; i < feat_csdev->nr_regs; i++)
|
||||||
|
cscfg_save_reg(&feat_csdev->regs_csdev[i]);
|
||||||
|
spin_unlock_irqrestore(feat_csdev->drv_spinlock, flags);
|
||||||
|
dev_dbg(&feat_csdev->csdev->dev, "Feature %s: %s",
|
||||||
|
feat_csdev->feat_desc->name, "save on disable");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* default reset - restore default values */
|
||||||
|
void cscfg_reset_feat(struct cscfg_feature_csdev *feat_csdev)
|
||||||
|
{
|
||||||
|
struct cscfg_regval_desc *reg_desc;
|
||||||
|
struct cscfg_regval_csdev *reg_csdev;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set the default values for all parameters and regs from the
|
||||||
|
* relevant static descriptors.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < feat_csdev->nr_params; i++)
|
||||||
|
feat_csdev->params_csdev[i].current_value =
|
||||||
|
feat_csdev->feat_desc->params_desc[i].value;
|
||||||
|
|
||||||
|
for (i = 0; i < feat_csdev->nr_regs; i++) {
|
||||||
|
reg_desc = &feat_csdev->feat_desc->regs_desc[i];
|
||||||
|
reg_csdev = &feat_csdev->regs_csdev[i];
|
||||||
|
reg_csdev->reg_desc.type = reg_desc->type;
|
||||||
|
|
||||||
|
/* check if reg set from a parameter otherwise desc default */
|
||||||
|
if (reg_desc->type & CS_CFG_REG_TYPE_VAL_PARAM)
|
||||||
|
cscfg_init_reg_param(feat_csdev, reg_desc, reg_csdev);
|
||||||
|
else
|
||||||
|
/*
|
||||||
|
* for normal values the union between val64 & val32 + mask32
|
||||||
|
* allows us to init using the 64 bit value
|
||||||
|
*/
|
||||||
|
reg_csdev->reg_desc.val64 = reg_desc->val64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For the selected presets, we set the register associated with the parameter, to
|
||||||
|
* the value of the preset index associated with the parameter.
|
||||||
|
*/
|
||||||
|
static int cscfg_update_presets(struct cscfg_config_csdev *config_csdev, int preset)
|
||||||
|
{
|
||||||
|
int i, j, val_idx = 0, nr_cfg_params;
|
||||||
|
struct cscfg_parameter_csdev *param_csdev;
|
||||||
|
struct cscfg_feature_csdev *feat_csdev;
|
||||||
|
const struct cscfg_config_desc *config_desc = config_csdev->config_desc;
|
||||||
|
const char *name;
|
||||||
|
const u64 *preset_base;
|
||||||
|
u64 val;
|
||||||
|
|
||||||
|
/* preset in range 1 to nr_presets */
|
||||||
|
if (preset < 1 || preset > config_desc->nr_presets)
|
||||||
|
return -EINVAL;
|
||||||
|
/*
|
||||||
|
* Go through the array of features, assigning preset values to
|
||||||
|
* feature parameters in the order they appear.
|
||||||
|
* There should be precisely the same number of preset values as the
|
||||||
|
* sum of number of parameters over all the features - but we will
|
||||||
|
* ensure there is no overrun.
|
||||||
|
*/
|
||||||
|
nr_cfg_params = config_desc->nr_total_params;
|
||||||
|
preset_base = &config_desc->presets[(preset - 1) * nr_cfg_params];
|
||||||
|
for (i = 0; i < config_csdev->nr_feat; i++) {
|
||||||
|
feat_csdev = config_csdev->feats_csdev[i];
|
||||||
|
if (!feat_csdev->nr_params)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (j = 0; j < feat_csdev->nr_params; j++) {
|
||||||
|
param_csdev = &feat_csdev->params_csdev[j];
|
||||||
|
name = feat_csdev->feat_desc->params_desc[j].name;
|
||||||
|
val = preset_base[val_idx++];
|
||||||
|
if (param_csdev->val64) {
|
||||||
|
dev_dbg(&config_csdev->csdev->dev,
|
||||||
|
"set param %s (%lld)", name, val);
|
||||||
|
param_csdev->reg_csdev->reg_desc.val64 = val;
|
||||||
|
} else {
|
||||||
|
param_csdev->reg_csdev->reg_desc.val32 = (u32)val;
|
||||||
|
dev_dbg(&config_csdev->csdev->dev,
|
||||||
|
"set param %s (%d)", name, (u32)val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* exit early if all params filled */
|
||||||
|
if (val_idx >= nr_cfg_params)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if we are not using a preset, then need to update the feature params
|
||||||
|
* with current values. This sets the register associated with the parameter
|
||||||
|
* with the current value of that parameter.
|
||||||
|
*/
|
||||||
|
static int cscfg_update_curr_params(struct cscfg_config_csdev *config_csdev)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
struct cscfg_feature_csdev *feat_csdev;
|
||||||
|
struct cscfg_parameter_csdev *param_csdev;
|
||||||
|
const char *name;
|
||||||
|
u64 val;
|
||||||
|
|
||||||
|
for (i = 0; i < config_csdev->nr_feat; i++) {
|
||||||
|
feat_csdev = config_csdev->feats_csdev[i];
|
||||||
|
if (!feat_csdev->nr_params)
|
||||||
|
continue;
|
||||||
|
for (j = 0; j < feat_csdev->nr_params; j++) {
|
||||||
|
param_csdev = &feat_csdev->params_csdev[j];
|
||||||
|
name = feat_csdev->feat_desc->params_desc[j].name;
|
||||||
|
val = param_csdev->current_value;
|
||||||
|
if (param_csdev->val64) {
|
||||||
|
dev_dbg(&config_csdev->csdev->dev,
|
||||||
|
"set param %s (%lld)", name, val);
|
||||||
|
param_csdev->reg_csdev->reg_desc.val64 = val;
|
||||||
|
} else {
|
||||||
|
param_csdev->reg_csdev->reg_desc.val32 = (u32)val;
|
||||||
|
dev_dbg(&config_csdev->csdev->dev,
|
||||||
|
"set param %s (%d)", name, (u32)val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configuration values will be programmed into the driver locations if enabling, or read
|
||||||
|
* from relevant locations on disable.
|
||||||
|
*/
|
||||||
|
static int cscfg_prog_config(struct cscfg_config_csdev *config_csdev, bool enable)
|
||||||
|
{
|
||||||
|
int i, err = 0;
|
||||||
|
struct cscfg_feature_csdev *feat_csdev;
|
||||||
|
struct coresight_device *csdev;
|
||||||
|
|
||||||
|
for (i = 0; i < config_csdev->nr_feat; i++) {
|
||||||
|
feat_csdev = config_csdev->feats_csdev[i];
|
||||||
|
csdev = feat_csdev->csdev;
|
||||||
|
dev_dbg(&csdev->dev, "cfg %s; %s feature:%s", config_csdev->config_desc->name,
|
||||||
|
enable ? "enable" : "disable", feat_csdev->feat_desc->name);
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
err = cscfg_set_on_enable(feat_csdev);
|
||||||
|
else
|
||||||
|
cscfg_save_on_disable(feat_csdev);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable configuration for the device. Will result in the internal driver data
|
||||||
|
* being updated ready for programming into the device.
|
||||||
|
*
|
||||||
|
* @config_csdev: config_csdev to set.
|
||||||
|
* @preset: preset values to use - 0 for default.
|
||||||
|
*/
|
||||||
|
int cscfg_csdev_enable_config(struct cscfg_config_csdev *config_csdev, int preset)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (preset)
|
||||||
|
err = cscfg_update_presets(config_csdev, preset);
|
||||||
|
else
|
||||||
|
err = cscfg_update_curr_params(config_csdev);
|
||||||
|
if (!err)
|
||||||
|
err = cscfg_prog_config(config_csdev, true);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cscfg_csdev_disable_config(struct cscfg_config_csdev *config_csdev)
|
||||||
|
{
|
||||||
|
cscfg_prog_config(config_csdev, false);
|
||||||
|
}
|
||||||
253
drivers/hwtracing/coresight/coresight-config.h
Normal file
253
drivers/hwtracing/coresight/coresight-config.h
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Linaro Limited, All rights reserved.
|
||||||
|
* Author: Mike Leach <mike.leach@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CORESIGHT_CORESIGHT_CONFIG_H
|
||||||
|
#define _CORESIGHT_CORESIGHT_CONFIG_H
|
||||||
|
|
||||||
|
#include <linux/coresight.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
/* CoreSight Configuration Management - component and system wide configuration */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register type flags for register value descriptor:
|
||||||
|
* describe how the value is interpreted, and handled.
|
||||||
|
*/
|
||||||
|
#define CS_CFG_REG_TYPE_STD 0x80 /* reg is standard reg */
|
||||||
|
#define CS_CFG_REG_TYPE_RESOURCE 0x40 /* reg is a resource */
|
||||||
|
#define CS_CFG_REG_TYPE_VAL_PARAM 0x08 /* reg value uses param */
|
||||||
|
#define CS_CFG_REG_TYPE_VAL_MASK 0x04 /* reg value bit masked */
|
||||||
|
#define CS_CFG_REG_TYPE_VAL_64BIT 0x02 /* reg value 64 bit */
|
||||||
|
#define CS_CFG_REG_TYPE_VAL_SAVE 0x01 /* reg value save on disable */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* flags defining what device class a feature will match to when processing a
|
||||||
|
* system configuration - used by config data and devices.
|
||||||
|
*/
|
||||||
|
#define CS_CFG_MATCH_CLASS_SRC_ALL 0x0001 /* match any source */
|
||||||
|
#define CS_CFG_MATCH_CLASS_SRC_ETM4 0x0002 /* match any ETMv4 device */
|
||||||
|
|
||||||
|
/* flags defining device instance matching - used in config match desc data. */
|
||||||
|
#define CS_CFG_MATCH_INST_ANY 0x80000000 /* any instance of a class */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Limit number of presets in a configuration
|
||||||
|
* This is related to the number of bits (4) we use to select the preset on
|
||||||
|
* the perf command line. Preset 0 is always none selected.
|
||||||
|
* See PMU_FORMAT_ATTR(preset, "config:0-3") in coresight-etm-perf.c
|
||||||
|
*/
|
||||||
|
#define CS_CFG_CONFIG_PRESET_MAX 15
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameter descriptor for a device feature.
|
||||||
|
*
|
||||||
|
* @name: Name of parameter.
|
||||||
|
* @value: Initial or default value.
|
||||||
|
*/
|
||||||
|
struct cscfg_parameter_desc {
|
||||||
|
const char *name;
|
||||||
|
u64 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of register value and a descriptor of register usage.
|
||||||
|
*
|
||||||
|
* Used as a descriptor in the feature descriptors.
|
||||||
|
* Used as a value in when in a feature loading into a csdev.
|
||||||
|
*
|
||||||
|
* Supports full 64 bit register value, or 32 bit value with optional mask
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* @type: define register usage and interpretation.
|
||||||
|
* @offset: the address offset for register in the hardware device (per device specification).
|
||||||
|
* @hw_info: optional hardware device type specific information. (ETM / CTI specific etc)
|
||||||
|
* @val64: 64 bit value.
|
||||||
|
* @val32: 32 bit value.
|
||||||
|
* @mask32: 32 bit mask when using 32 bit value to access device register - if mask type.
|
||||||
|
* @param_idx: parameter index value into parameter array if param type.
|
||||||
|
*/
|
||||||
|
struct cscfg_regval_desc {
|
||||||
|
struct {
|
||||||
|
u32 type:8;
|
||||||
|
u32 offset:12;
|
||||||
|
u32 hw_info:12;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
u64 val64;
|
||||||
|
struct {
|
||||||
|
u32 val32;
|
||||||
|
u32 mask32;
|
||||||
|
};
|
||||||
|
u32 param_idx;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Device feature descriptor - combination of registers and parameters to
|
||||||
|
* program a device to implement a specific complex function.
|
||||||
|
*
|
||||||
|
* @name: feature name.
|
||||||
|
* @description: brief description of the feature.
|
||||||
|
* @item: List entry.
|
||||||
|
* @match_flags: matching information if loading into a device
|
||||||
|
* @nr_params: number of parameters used.
|
||||||
|
* @params_desc: array of parameters used.
|
||||||
|
* @nr_regs: number of registers used.
|
||||||
|
* @regs_desc: array of registers used.
|
||||||
|
*/
|
||||||
|
struct cscfg_feature_desc {
|
||||||
|
const char *name;
|
||||||
|
const char *description;
|
||||||
|
struct list_head item;
|
||||||
|
u32 match_flags;
|
||||||
|
int nr_params;
|
||||||
|
struct cscfg_parameter_desc *params_desc;
|
||||||
|
int nr_regs;
|
||||||
|
struct cscfg_regval_desc *regs_desc;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration descriptor - describes selectable system configuration.
|
||||||
|
*
|
||||||
|
* A configuration describes device features in use, and may provide preset
|
||||||
|
* values for the parameters in those features.
|
||||||
|
*
|
||||||
|
* A single set of presets is the sum of the parameters declared by
|
||||||
|
* all the features in use - this value is @nr_total_params.
|
||||||
|
*
|
||||||
|
* @name: name of the configuration - used for selection.
|
||||||
|
* @description: description of the purpose of the configuration.
|
||||||
|
* @item: list entry.
|
||||||
|
* @nr_feat_refs: Number of features used in this configuration.
|
||||||
|
* @feat_ref_names: references to features used in this configuration.
|
||||||
|
* @nr_presets: Number of sets of presets supplied by this configuration.
|
||||||
|
* @nr_total_params: Sum of all parameters declared by used features
|
||||||
|
* @presets: Array of preset values.
|
||||||
|
* @event_ea: Extended attribute for perf event value
|
||||||
|
* @active_cnt: ref count for activate on this configuration.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct cscfg_config_desc {
|
||||||
|
const char *name;
|
||||||
|
const char *description;
|
||||||
|
struct list_head item;
|
||||||
|
int nr_feat_refs;
|
||||||
|
const char **feat_ref_names;
|
||||||
|
int nr_presets;
|
||||||
|
int nr_total_params;
|
||||||
|
const u64 *presets; /* nr_presets * nr_total_params */
|
||||||
|
struct dev_ext_attribute *event_ea;
|
||||||
|
atomic_t active_cnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* config register instance - part of a loaded feature.
|
||||||
|
* maps register values to csdev driver structures
|
||||||
|
*
|
||||||
|
* @reg_desc: value to use when setting feature on device / store for
|
||||||
|
* readback of volatile values.
|
||||||
|
* @driver_regval: pointer to internal driver element used to set the value
|
||||||
|
* in hardware.
|
||||||
|
*/
|
||||||
|
struct cscfg_regval_csdev {
|
||||||
|
struct cscfg_regval_desc reg_desc;
|
||||||
|
void *driver_regval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* config parameter instance - part of a loaded feature.
|
||||||
|
*
|
||||||
|
* @feat_csdev: parent feature
|
||||||
|
* @reg_csdev: register value updated by this parameter.
|
||||||
|
* @current_value: current value of parameter - may be set by user via
|
||||||
|
* sysfs, or modified during device operation.
|
||||||
|
* @val64: true if 64 bit value
|
||||||
|
*/
|
||||||
|
struct cscfg_parameter_csdev {
|
||||||
|
struct cscfg_feature_csdev *feat_csdev;
|
||||||
|
struct cscfg_regval_csdev *reg_csdev;
|
||||||
|
u64 current_value;
|
||||||
|
bool val64;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feature instance loaded into a CoreSight device.
|
||||||
|
*
|
||||||
|
* When a feature is loaded into a specific device, then this structure holds
|
||||||
|
* the connections between the register / parameter values used and the
|
||||||
|
* internal data structures that are written when the feature is enabled.
|
||||||
|
*
|
||||||
|
* Since applying a feature modifies internal data structures in the device,
|
||||||
|
* then we have a reference to the device spinlock to protect access to these
|
||||||
|
* structures (@drv_spinlock).
|
||||||
|
*
|
||||||
|
* @feat_desc: pointer to the static descriptor for this feature.
|
||||||
|
* @csdev: parent CoreSight device instance.
|
||||||
|
* @node: list entry into feature list for this device.
|
||||||
|
* @drv_spinlock: device spinlock for access to driver register data.
|
||||||
|
* @nr_params: number of parameters.
|
||||||
|
* @params_csdev: current parameter values on this device
|
||||||
|
* @nr_regs: number of registers to be programmed.
|
||||||
|
* @regs_csdev: Programming details for the registers
|
||||||
|
*/
|
||||||
|
struct cscfg_feature_csdev {
|
||||||
|
const struct cscfg_feature_desc *feat_desc;
|
||||||
|
struct coresight_device *csdev;
|
||||||
|
struct list_head node;
|
||||||
|
spinlock_t *drv_spinlock;
|
||||||
|
int nr_params;
|
||||||
|
struct cscfg_parameter_csdev *params_csdev;
|
||||||
|
int nr_regs;
|
||||||
|
struct cscfg_regval_csdev *regs_csdev;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration instance when loaded into a CoreSight device.
|
||||||
|
*
|
||||||
|
* The instance contains references to loaded features on this device that are
|
||||||
|
* used by the configuration.
|
||||||
|
*
|
||||||
|
* @config_desc:reference to the descriptor for this configuration
|
||||||
|
* @csdev: parent coresight device for this configuration instance.
|
||||||
|
* @enabled: true if configuration is enabled on this device.
|
||||||
|
* @node: list entry within the coresight device
|
||||||
|
* @nr_feat: Number of features on this device that are used in the
|
||||||
|
* configuration.
|
||||||
|
* @feats_csdev:references to the device features to enable.
|
||||||
|
*/
|
||||||
|
struct cscfg_config_csdev {
|
||||||
|
const struct cscfg_config_desc *config_desc;
|
||||||
|
struct coresight_device *csdev;
|
||||||
|
bool enabled;
|
||||||
|
struct list_head node;
|
||||||
|
int nr_feat;
|
||||||
|
struct cscfg_feature_csdev *feats_csdev[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coresight device operations.
|
||||||
|
*
|
||||||
|
* Registered coresight devices provide these operations to manage feature
|
||||||
|
* instances compatible with the device hardware and drivers
|
||||||
|
*
|
||||||
|
* @load_feat: Pass a feature descriptor into the device and create the
|
||||||
|
* loaded feature instance (struct cscfg_feature_csdev).
|
||||||
|
*/
|
||||||
|
struct cscfg_csdev_feat_ops {
|
||||||
|
int (*load_feat)(struct coresight_device *csdev,
|
||||||
|
struct cscfg_feature_csdev *feat_csdev);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* coresight config helper functions*/
|
||||||
|
|
||||||
|
/* enable / disable config on a device - called with appropriate locks set.*/
|
||||||
|
int cscfg_csdev_enable_config(struct cscfg_config_csdev *config_csdev, int preset);
|
||||||
|
void cscfg_csdev_disable_config(struct cscfg_config_csdev *config_csdev);
|
||||||
|
|
||||||
|
/* reset a feature to default values */
|
||||||
|
void cscfg_reset_feat(struct cscfg_feature_csdev *feat_csdev);
|
||||||
|
|
||||||
|
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "coresight-etm-perf.h"
|
#include "coresight-etm-perf.h"
|
||||||
#include "coresight-priv.h"
|
#include "coresight-priv.h"
|
||||||
|
#include "coresight-syscfg.h"
|
||||||
|
|
||||||
static DEFINE_MUTEX(coresight_mutex);
|
static DEFINE_MUTEX(coresight_mutex);
|
||||||
static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
|
static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
|
||||||
@@ -1763,13 +1764,22 @@ static int __init coresight_init(void)
|
|||||||
|
|
||||||
ret = etm_perf_init();
|
ret = etm_perf_init();
|
||||||
if (ret)
|
if (ret)
|
||||||
bus_unregister(&coresight_bustype);
|
goto exit_bus_unregister;
|
||||||
|
|
||||||
|
/* initialise the coresight syscfg API */
|
||||||
|
ret = cscfg_init();
|
||||||
|
if (!ret)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
etm_perf_exit();
|
||||||
|
exit_bus_unregister:
|
||||||
|
bus_unregister(&coresight_bustype);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit coresight_exit(void)
|
static void __exit coresight_exit(void)
|
||||||
{
|
{
|
||||||
|
cscfg_exit();
|
||||||
etm_perf_exit();
|
etm_perf_exit();
|
||||||
bus_unregister(&coresight_bustype);
|
bus_unregister(&coresight_bustype);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -588,11 +588,11 @@ static int debug_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
|
|
||||||
drvdata->base = base;
|
drvdata->base = base;
|
||||||
|
|
||||||
get_online_cpus();
|
cpus_read_lock();
|
||||||
per_cpu(debug_drvdata, drvdata->cpu) = drvdata;
|
per_cpu(debug_drvdata, drvdata->cpu) = drvdata;
|
||||||
ret = smp_call_function_single(drvdata->cpu, debug_init_arch_data,
|
ret = smp_call_function_single(drvdata->cpu, debug_init_arch_data,
|
||||||
drvdata, 1);
|
drvdata, 1);
|
||||||
put_online_cpus();
|
cpus_read_unlock();
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "CPU%d debug arch init failed\n", drvdata->cpu);
|
dev_err(dev, "CPU%d debug arch init failed\n", drvdata->cpu);
|
||||||
|
|||||||
@@ -18,8 +18,10 @@
|
|||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
|
#include "coresight-config.h"
|
||||||
#include "coresight-etm-perf.h"
|
#include "coresight-etm-perf.h"
|
||||||
#include "coresight-priv.h"
|
#include "coresight-priv.h"
|
||||||
|
#include "coresight-syscfg.h"
|
||||||
|
|
||||||
static struct pmu etm_pmu;
|
static struct pmu etm_pmu;
|
||||||
static bool etm_perf_up;
|
static bool etm_perf_up;
|
||||||
@@ -57,8 +59,13 @@ PMU_FORMAT_ATTR(contextid1, "config:" __stringify(ETM_OPT_CTXTID));
|
|||||||
PMU_FORMAT_ATTR(contextid2, "config:" __stringify(ETM_OPT_CTXTID2));
|
PMU_FORMAT_ATTR(contextid2, "config:" __stringify(ETM_OPT_CTXTID2));
|
||||||
PMU_FORMAT_ATTR(timestamp, "config:" __stringify(ETM_OPT_TS));
|
PMU_FORMAT_ATTR(timestamp, "config:" __stringify(ETM_OPT_TS));
|
||||||
PMU_FORMAT_ATTR(retstack, "config:" __stringify(ETM_OPT_RETSTK));
|
PMU_FORMAT_ATTR(retstack, "config:" __stringify(ETM_OPT_RETSTK));
|
||||||
|
/* preset - if sink ID is used as a configuration selector */
|
||||||
|
PMU_FORMAT_ATTR(preset, "config:0-3");
|
||||||
/* Sink ID - same for all ETMs */
|
/* Sink ID - same for all ETMs */
|
||||||
PMU_FORMAT_ATTR(sinkid, "config2:0-31");
|
PMU_FORMAT_ATTR(sinkid, "config2:0-31");
|
||||||
|
/* config ID - set if a system configuration is selected */
|
||||||
|
PMU_FORMAT_ATTR(configid, "config2:32-63");
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* contextid always traces the "PID". The PID is in CONTEXTIDR_EL1
|
* contextid always traces the "PID". The PID is in CONTEXTIDR_EL1
|
||||||
@@ -88,6 +95,8 @@ static struct attribute *etm_config_formats_attr[] = {
|
|||||||
&format_attr_timestamp.attr,
|
&format_attr_timestamp.attr,
|
||||||
&format_attr_retstack.attr,
|
&format_attr_retstack.attr,
|
||||||
&format_attr_sinkid.attr,
|
&format_attr_sinkid.attr,
|
||||||
|
&format_attr_preset.attr,
|
||||||
|
&format_attr_configid.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -105,9 +114,19 @@ static const struct attribute_group etm_pmu_sinks_group = {
|
|||||||
.attrs = etm_config_sinks_attr,
|
.attrs = etm_config_sinks_attr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct attribute *etm_config_events_attr[] = {
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group etm_pmu_events_group = {
|
||||||
|
.name = "events",
|
||||||
|
.attrs = etm_config_events_attr,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct attribute_group *etm_pmu_attr_groups[] = {
|
static const struct attribute_group *etm_pmu_attr_groups[] = {
|
||||||
&etm_pmu_format_group,
|
&etm_pmu_format_group,
|
||||||
&etm_pmu_sinks_group,
|
&etm_pmu_sinks_group,
|
||||||
|
&etm_pmu_events_group,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -196,6 +215,10 @@ static void free_event_data(struct work_struct *work)
|
|||||||
/* Free the sink buffers, if there are any */
|
/* Free the sink buffers, if there are any */
|
||||||
free_sink_buffer(event_data);
|
free_sink_buffer(event_data);
|
||||||
|
|
||||||
|
/* clear any configuration we were using */
|
||||||
|
if (event_data->cfg_hash)
|
||||||
|
cscfg_deactivate_config(event_data->cfg_hash);
|
||||||
|
|
||||||
for_each_cpu(cpu, mask) {
|
for_each_cpu(cpu, mask) {
|
||||||
struct list_head **ppath;
|
struct list_head **ppath;
|
||||||
|
|
||||||
@@ -273,7 +296,7 @@ static bool sinks_compatible(struct coresight_device *a,
|
|||||||
static void *etm_setup_aux(struct perf_event *event, void **pages,
|
static void *etm_setup_aux(struct perf_event *event, void **pages,
|
||||||
int nr_pages, bool overwrite)
|
int nr_pages, bool overwrite)
|
||||||
{
|
{
|
||||||
u32 id;
|
u32 id, cfg_hash;
|
||||||
int cpu = event->cpu;
|
int cpu = event->cpu;
|
||||||
cpumask_t *mask;
|
cpumask_t *mask;
|
||||||
struct coresight_device *sink = NULL;
|
struct coresight_device *sink = NULL;
|
||||||
@@ -286,11 +309,19 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
|
|||||||
INIT_WORK(&event_data->work, free_event_data);
|
INIT_WORK(&event_data->work, free_event_data);
|
||||||
|
|
||||||
/* First get the selected sink from user space. */
|
/* First get the selected sink from user space. */
|
||||||
if (event->attr.config2) {
|
if (event->attr.config2 & GENMASK_ULL(31, 0)) {
|
||||||
id = (u32)event->attr.config2;
|
id = (u32)event->attr.config2;
|
||||||
sink = user_sink = coresight_get_sink_by_id(id);
|
sink = user_sink = coresight_get_sink_by_id(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check if user wants a coresight configuration selected */
|
||||||
|
cfg_hash = (u32)((event->attr.config2 & GENMASK_ULL(63, 32)) >> 32);
|
||||||
|
if (cfg_hash) {
|
||||||
|
if (cscfg_activate_config(cfg_hash))
|
||||||
|
goto err;
|
||||||
|
event_data->cfg_hash = cfg_hash;
|
||||||
|
}
|
||||||
|
|
||||||
mask = &event_data->mask;
|
mask = &event_data->mask;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -658,14 +689,48 @@ static ssize_t etm_perf_sink_name_show(struct device *dev,
|
|||||||
return scnprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)(ea->var));
|
return scnprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)(ea->var));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct dev_ext_attribute *
|
||||||
|
etm_perf_add_symlink_group(struct device *dev, const char *name, const char *group_name)
|
||||||
|
{
|
||||||
|
struct dev_ext_attribute *ea;
|
||||||
|
unsigned long hash;
|
||||||
|
int ret;
|
||||||
|
struct device *pmu_dev = etm_pmu.dev;
|
||||||
|
|
||||||
|
if (!etm_perf_up)
|
||||||
|
return ERR_PTR(-EPROBE_DEFER);
|
||||||
|
|
||||||
|
ea = devm_kzalloc(dev, sizeof(*ea), GFP_KERNEL);
|
||||||
|
if (!ea)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this function is called adding a sink then the hash is used for
|
||||||
|
* sink selection - see function coresight_get_sink_by_id().
|
||||||
|
* If adding a configuration then the hash is used for selection in
|
||||||
|
* cscfg_activate_config()
|
||||||
|
*/
|
||||||
|
hash = hashlen_hash(hashlen_string(NULL, name));
|
||||||
|
|
||||||
|
sysfs_attr_init(&ea->attr.attr);
|
||||||
|
ea->attr.attr.name = devm_kstrdup(dev, name, GFP_KERNEL);
|
||||||
|
if (!ea->attr.attr.name)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
ea->attr.attr.mode = 0444;
|
||||||
|
ea->var = (unsigned long *)hash;
|
||||||
|
|
||||||
|
ret = sysfs_add_file_to_group(&pmu_dev->kobj,
|
||||||
|
&ea->attr.attr, group_name);
|
||||||
|
|
||||||
|
return ret ? ERR_PTR(ret) : ea;
|
||||||
|
}
|
||||||
|
|
||||||
int etm_perf_add_symlink_sink(struct coresight_device *csdev)
|
int etm_perf_add_symlink_sink(struct coresight_device *csdev)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
unsigned long hash;
|
|
||||||
const char *name;
|
const char *name;
|
||||||
struct device *pmu_dev = etm_pmu.dev;
|
|
||||||
struct device *dev = &csdev->dev;
|
struct device *dev = &csdev->dev;
|
||||||
struct dev_ext_attribute *ea;
|
int err = 0;
|
||||||
|
|
||||||
if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
|
if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
|
||||||
csdev->type != CORESIGHT_DEV_TYPE_LINKSINK)
|
csdev->type != CORESIGHT_DEV_TYPE_LINKSINK)
|
||||||
@@ -674,52 +739,77 @@ int etm_perf_add_symlink_sink(struct coresight_device *csdev)
|
|||||||
if (csdev->ea != NULL)
|
if (csdev->ea != NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!etm_perf_up)
|
|
||||||
return -EPROBE_DEFER;
|
|
||||||
|
|
||||||
ea = devm_kzalloc(dev, sizeof(*ea), GFP_KERNEL);
|
|
||||||
if (!ea)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
name = dev_name(dev);
|
name = dev_name(dev);
|
||||||
/* See function coresight_get_sink_by_id() to know where this is used */
|
csdev->ea = etm_perf_add_symlink_group(dev, name, "sinks");
|
||||||
hash = hashlen_hash(hashlen_string(NULL, name));
|
if (IS_ERR(csdev->ea)) {
|
||||||
|
err = PTR_ERR(csdev->ea);
|
||||||
|
csdev->ea = NULL;
|
||||||
|
} else
|
||||||
|
csdev->ea->attr.show = etm_perf_sink_name_show;
|
||||||
|
|
||||||
sysfs_attr_init(&ea->attr.attr);
|
return err;
|
||||||
ea->attr.attr.name = devm_kstrdup(dev, name, GFP_KERNEL);
|
}
|
||||||
if (!ea->attr.attr.name)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
ea->attr.attr.mode = 0444;
|
static void etm_perf_del_symlink_group(struct dev_ext_attribute *ea, const char *group_name)
|
||||||
ea->attr.show = etm_perf_sink_name_show;
|
{
|
||||||
ea->var = (unsigned long *)hash;
|
struct device *pmu_dev = etm_pmu.dev;
|
||||||
|
|
||||||
ret = sysfs_add_file_to_group(&pmu_dev->kobj,
|
sysfs_remove_file_from_group(&pmu_dev->kobj,
|
||||||
&ea->attr.attr, "sinks");
|
&ea->attr.attr, group_name);
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
csdev->ea = ea;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void etm_perf_del_symlink_sink(struct coresight_device *csdev)
|
void etm_perf_del_symlink_sink(struct coresight_device *csdev)
|
||||||
{
|
{
|
||||||
struct device *pmu_dev = etm_pmu.dev;
|
|
||||||
struct dev_ext_attribute *ea = csdev->ea;
|
|
||||||
|
|
||||||
if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
|
if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
|
||||||
csdev->type != CORESIGHT_DEV_TYPE_LINKSINK)
|
csdev->type != CORESIGHT_DEV_TYPE_LINKSINK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!ea)
|
if (!csdev->ea)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sysfs_remove_file_from_group(&pmu_dev->kobj,
|
etm_perf_del_symlink_group(csdev->ea, "sinks");
|
||||||
&ea->attr.attr, "sinks");
|
|
||||||
csdev->ea = NULL;
|
csdev->ea = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t etm_perf_cscfg_event_show(struct device *dev,
|
||||||
|
struct device_attribute *dattr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct dev_ext_attribute *ea;
|
||||||
|
|
||||||
|
ea = container_of(dattr, struct dev_ext_attribute, attr);
|
||||||
|
return scnprintf(buf, PAGE_SIZE, "configid=0x%lx\n", (unsigned long)(ea->var));
|
||||||
|
}
|
||||||
|
|
||||||
|
int etm_perf_add_symlink_cscfg(struct device *dev, struct cscfg_config_desc *config_desc)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (config_desc->event_ea != NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
config_desc->event_ea = etm_perf_add_symlink_group(dev, config_desc->name, "events");
|
||||||
|
|
||||||
|
/* set the show function to the custom cscfg event */
|
||||||
|
if (!IS_ERR(config_desc->event_ea))
|
||||||
|
config_desc->event_ea->attr.show = etm_perf_cscfg_event_show;
|
||||||
|
else {
|
||||||
|
err = PTR_ERR(config_desc->event_ea);
|
||||||
|
config_desc->event_ea = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *config_desc)
|
||||||
|
{
|
||||||
|
if (!config_desc->event_ea)
|
||||||
|
return;
|
||||||
|
|
||||||
|
etm_perf_del_symlink_group(config_desc->event_ea, "events");
|
||||||
|
config_desc->event_ea = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int __init etm_perf_init(void)
|
int __init etm_perf_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@@ -748,7 +838,7 @@ int __init etm_perf_init(void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __exit etm_perf_exit(void)
|
void etm_perf_exit(void)
|
||||||
{
|
{
|
||||||
perf_pmu_unregister(&etm_pmu);
|
perf_pmu_unregister(&etm_pmu);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "coresight-priv.h"
|
#include "coresight-priv.h"
|
||||||
|
|
||||||
struct coresight_device;
|
struct coresight_device;
|
||||||
|
struct cscfg_config_desc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In both ETMv3 and v4 the maximum number of address comparator implentable
|
* In both ETMv3 and v4 the maximum number of address comparator implentable
|
||||||
@@ -48,12 +49,14 @@ struct etm_filters {
|
|||||||
* @work: Handle to free allocated memory outside IRQ context.
|
* @work: Handle to free allocated memory outside IRQ context.
|
||||||
* @mask: Hold the CPU(s) this event was set for.
|
* @mask: Hold the CPU(s) this event was set for.
|
||||||
* @snk_config: The sink configuration.
|
* @snk_config: The sink configuration.
|
||||||
|
* @cfg_hash: The hash id of any coresight config selected.
|
||||||
* @path: An array of path, each slot for one CPU.
|
* @path: An array of path, each slot for one CPU.
|
||||||
*/
|
*/
|
||||||
struct etm_event_data {
|
struct etm_event_data {
|
||||||
struct work_struct work;
|
struct work_struct work;
|
||||||
cpumask_t mask;
|
cpumask_t mask;
|
||||||
void *snk_config;
|
void *snk_config;
|
||||||
|
u32 cfg_hash;
|
||||||
struct list_head * __percpu *path;
|
struct list_head * __percpu *path;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -69,6 +72,9 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle)
|
|||||||
return data->snk_config;
|
return data->snk_config;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
int etm_perf_add_symlink_cscfg(struct device *dev,
|
||||||
|
struct cscfg_config_desc *config_desc);
|
||||||
|
void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *config_desc);
|
||||||
#else
|
#else
|
||||||
static inline int etm_perf_symlink(struct coresight_device *csdev, bool link)
|
static inline int etm_perf_symlink(struct coresight_device *csdev, bool link)
|
||||||
{ return -EINVAL; }
|
{ return -EINVAL; }
|
||||||
@@ -79,10 +85,14 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle)
|
|||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
int etm_perf_add_symlink_cscfg(struct device *dev,
|
||||||
|
struct cscfg_config_desc *config_desc)
|
||||||
|
{ return -EINVAL; }
|
||||||
|
void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *config_desc) {}
|
||||||
|
|
||||||
#endif /* CONFIG_CORESIGHT */
|
#endif /* CONFIG_CORESIGHT */
|
||||||
|
|
||||||
int __init etm_perf_init(void);
|
int __init etm_perf_init(void);
|
||||||
void __exit etm_perf_exit(void);
|
void etm_perf_exit(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
182
drivers/hwtracing/coresight/coresight-etm4x-cfg.c
Normal file
182
drivers/hwtracing/coresight/coresight-etm4x-cfg.c
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright(C) 2020 Linaro Limited. All rights reserved.
|
||||||
|
* Author: Mike Leach <mike.leach@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "coresight-etm4x.h"
|
||||||
|
#include "coresight-etm4x-cfg.h"
|
||||||
|
#include "coresight-priv.h"
|
||||||
|
#include "coresight-syscfg.h"
|
||||||
|
|
||||||
|
/* defines to associate register IDs with driver data locations */
|
||||||
|
#define CHECKREG(cval, elem) \
|
||||||
|
{ \
|
||||||
|
if (offset == cval) { \
|
||||||
|
reg_csdev->driver_regval = &drvcfg->elem; \
|
||||||
|
err = 0; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHECKREGIDX(cval, elem, off_idx, mask) \
|
||||||
|
{ \
|
||||||
|
if (mask == cval) { \
|
||||||
|
reg_csdev->driver_regval = &drvcfg->elem[off_idx]; \
|
||||||
|
err = 0; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* etm4_cfg_map_reg_offset - validate and map the register offset into a
|
||||||
|
* location in the driver config struct.
|
||||||
|
*
|
||||||
|
* Limits the number of registers that can be accessed and programmed in
|
||||||
|
* features, to those which are used to control the trace capture parameters.
|
||||||
|
*
|
||||||
|
* Omits or limits access to those which the driver must use exclusively.
|
||||||
|
*
|
||||||
|
* Invalid offsets will result in fail code return and feature load failure.
|
||||||
|
*
|
||||||
|
* @drvdata: driver data to map into.
|
||||||
|
* @reg: register to map.
|
||||||
|
* @offset: device offset for the register
|
||||||
|
*/
|
||||||
|
static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
|
||||||
|
struct cscfg_regval_csdev *reg_csdev, u32 offset)
|
||||||
|
{
|
||||||
|
int err = -EINVAL, idx;
|
||||||
|
struct etmv4_config *drvcfg = &drvdata->config;
|
||||||
|
u32 off_mask;
|
||||||
|
|
||||||
|
if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) ||
|
||||||
|
((offset >= TRCSEQRSTEVR) && (offset <= TRCEXTINSELR)) ||
|
||||||
|
((offset >= TRCCIDCCTLR0) && (offset <= TRCVMIDCCTLR1))) {
|
||||||
|
do {
|
||||||
|
CHECKREG(TRCEVENTCTL0R, eventctrl0);
|
||||||
|
CHECKREG(TRCEVENTCTL1R, eventctrl1);
|
||||||
|
CHECKREG(TRCSTALLCTLR, stall_ctrl);
|
||||||
|
CHECKREG(TRCTSCTLR, ts_ctrl);
|
||||||
|
CHECKREG(TRCSYNCPR, syncfreq);
|
||||||
|
CHECKREG(TRCCCCTLR, ccctlr);
|
||||||
|
CHECKREG(TRCBBCTLR, bb_ctrl);
|
||||||
|
CHECKREG(TRCVICTLR, vinst_ctrl);
|
||||||
|
CHECKREG(TRCVIIECTLR, viiectlr);
|
||||||
|
CHECKREG(TRCVISSCTLR, vissctlr);
|
||||||
|
CHECKREG(TRCVIPCSSCTLR, vipcssctlr);
|
||||||
|
CHECKREG(TRCSEQRSTEVR, seq_rst);
|
||||||
|
CHECKREG(TRCSEQSTR, seq_state);
|
||||||
|
CHECKREG(TRCEXTINSELR, ext_inp);
|
||||||
|
CHECKREG(TRCCIDCCTLR0, ctxid_mask0);
|
||||||
|
CHECKREG(TRCCIDCCTLR1, ctxid_mask1);
|
||||||
|
CHECKREG(TRCVMIDCCTLR0, vmid_mask0);
|
||||||
|
CHECKREG(TRCVMIDCCTLR1, vmid_mask1);
|
||||||
|
} while (0);
|
||||||
|
} else if ((offset & GENMASK(11, 4)) == TRCSEQEVRn(0)) {
|
||||||
|
/* sequencer state control registers */
|
||||||
|
idx = (offset & GENMASK(3, 0)) / 4;
|
||||||
|
if (idx < ETM_MAX_SEQ_STATES) {
|
||||||
|
reg_csdev->driver_regval = &drvcfg->seq_ctrl[idx];
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
} else if ((offset >= TRCSSCCRn(0)) && (offset <= TRCSSPCICRn(7))) {
|
||||||
|
/* 32 bit, 8 off indexed register sets */
|
||||||
|
idx = (offset & GENMASK(4, 0)) / 4;
|
||||||
|
off_mask = (offset & GENMASK(11, 5));
|
||||||
|
do {
|
||||||
|
CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx, off_mask);
|
||||||
|
CHECKREGIDX(TRCSSCSRn(0), ss_status, idx, off_mask);
|
||||||
|
CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx, off_mask);
|
||||||
|
} while (0);
|
||||||
|
} else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
|
||||||
|
/* 64 bit, 8 off indexed register sets */
|
||||||
|
idx = (offset & GENMASK(5, 0)) / 8;
|
||||||
|
off_mask = (offset & GENMASK(11, 6));
|
||||||
|
do {
|
||||||
|
CHECKREGIDX(TRCCIDCVRn(0), ctxid_pid, idx, off_mask);
|
||||||
|
CHECKREGIDX(TRCVMIDCVRn(0), vmid_val, idx, off_mask);
|
||||||
|
} while (0);
|
||||||
|
} else if ((offset >= TRCRSCTLRn(2)) &&
|
||||||
|
(offset <= TRCRSCTLRn((ETM_MAX_RES_SEL - 1)))) {
|
||||||
|
/* 32 bit resource selection regs, 32 off, skip fixed 0,1 */
|
||||||
|
idx = (offset & GENMASK(6, 0)) / 4;
|
||||||
|
if (idx < ETM_MAX_RES_SEL) {
|
||||||
|
reg_csdev->driver_regval = &drvcfg->res_ctrl[idx];
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
} else if ((offset >= TRCACVRn(0)) &&
|
||||||
|
(offset <= TRCACATRn((ETM_MAX_SINGLE_ADDR_CMP - 1)))) {
|
||||||
|
/* 64 bit addr cmp regs, 16 off */
|
||||||
|
idx = (offset & GENMASK(6, 0)) / 8;
|
||||||
|
off_mask = offset & GENMASK(11, 7);
|
||||||
|
do {
|
||||||
|
CHECKREGIDX(TRCACVRn(0), addr_val, idx, off_mask);
|
||||||
|
CHECKREGIDX(TRCACATRn(0), addr_acc, idx, off_mask);
|
||||||
|
} while (0);
|
||||||
|
} else if ((offset >= TRCCNTRLDVRn(0)) &&
|
||||||
|
(offset <= TRCCNTVRn((ETMv4_MAX_CNTR - 1)))) {
|
||||||
|
/* 32 bit counter regs, 4 off (ETMv4_MAX_CNTR - 1) */
|
||||||
|
idx = (offset & GENMASK(3, 0)) / 4;
|
||||||
|
off_mask = offset & GENMASK(11, 4);
|
||||||
|
do {
|
||||||
|
CHECKREGIDX(TRCCNTRLDVRn(0), cntrldvr, idx, off_mask);
|
||||||
|
CHECKREGIDX(TRCCNTCTLRn(0), cntr_ctrl, idx, off_mask);
|
||||||
|
CHECKREGIDX(TRCCNTVRn(0), cntr_val, idx, off_mask);
|
||||||
|
} while (0);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* etm4_cfg_load_feature - load a feature into a device instance.
|
||||||
|
*
|
||||||
|
* @csdev: An ETMv4 CoreSight device.
|
||||||
|
* @feat: The feature to be loaded.
|
||||||
|
*
|
||||||
|
* The function will load a feature instance into the device, checking that
|
||||||
|
* the register definitions are valid for the device.
|
||||||
|
*
|
||||||
|
* Parameter and register definitions will be converted into internal
|
||||||
|
* structures that are used to set the values in the driver when the
|
||||||
|
* feature is enabled for the device.
|
||||||
|
*
|
||||||
|
* The feature spinlock pointer is initialised to the same spinlock
|
||||||
|
* that the driver uses to protect the internal register values.
|
||||||
|
*/
|
||||||
|
static int etm4_cfg_load_feature(struct coresight_device *csdev,
|
||||||
|
struct cscfg_feature_csdev *feat_csdev)
|
||||||
|
{
|
||||||
|
struct device *dev = csdev->dev.parent;
|
||||||
|
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
|
const struct cscfg_feature_desc *feat_desc = feat_csdev->feat_desc;
|
||||||
|
u32 offset;
|
||||||
|
int i = 0, err = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* essential we set the device spinlock - this is used in the generic
|
||||||
|
* programming routines when copying values into the drvdata structures
|
||||||
|
* via the pointers setup in etm4_cfg_map_reg_offset().
|
||||||
|
*/
|
||||||
|
feat_csdev->drv_spinlock = &drvdata->spinlock;
|
||||||
|
|
||||||
|
/* process the register descriptions */
|
||||||
|
for (i = 0; i < feat_csdev->nr_regs && !err; i++) {
|
||||||
|
offset = feat_desc->regs_desc[i].offset;
|
||||||
|
err = etm4_cfg_map_reg_offset(drvdata, &feat_csdev->regs_csdev[i], offset);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* match information when loading configurations */
|
||||||
|
#define CS_CFG_ETM4_MATCH_FLAGS (CS_CFG_MATCH_CLASS_SRC_ALL | \
|
||||||
|
CS_CFG_MATCH_CLASS_SRC_ETM4)
|
||||||
|
|
||||||
|
int etm4_cscfg_register(struct coresight_device *csdev)
|
||||||
|
{
|
||||||
|
struct cscfg_csdev_feat_ops ops;
|
||||||
|
|
||||||
|
ops.load_feat = &etm4_cfg_load_feature;
|
||||||
|
|
||||||
|
return cscfg_register_csdev(csdev, CS_CFG_ETM4_MATCH_FLAGS, &ops);
|
||||||
|
}
|
||||||
30
drivers/hwtracing/coresight/coresight-etm4x-cfg.h
Normal file
30
drivers/hwtracing/coresight/coresight-etm4x-cfg.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CORESIGHT_ETM4X_CFG_H
|
||||||
|
#define _CORESIGHT_ETM4X_CFG_H
|
||||||
|
|
||||||
|
#include "coresight-config.h"
|
||||||
|
#include "coresight-etm4x.h"
|
||||||
|
|
||||||
|
/* ETMv4 specific config defines */
|
||||||
|
|
||||||
|
/* resource IDs */
|
||||||
|
|
||||||
|
#define ETM4_CFG_RES_CTR 0x001
|
||||||
|
#define ETM4_CFG_RES_CMP 0x002
|
||||||
|
#define ETM4_CFG_RES_CMP_PAIR0 0x003
|
||||||
|
#define ETM4_CFG_RES_CMP_PAIR1 0x004
|
||||||
|
#define ETM4_CFG_RES_SEL 0x005
|
||||||
|
#define ETM4_CFG_RES_SEL_PAIR0 0x006
|
||||||
|
#define ETM4_CFG_RES_SEL_PAIR1 0x007
|
||||||
|
#define ETM4_CFG_RES_SEQ 0x008
|
||||||
|
#define ETM4_CFG_RES_TS 0x009
|
||||||
|
#define ETM4_CFG_RES_MASK 0x00F
|
||||||
|
|
||||||
|
/* ETMv4 specific config functions */
|
||||||
|
int etm4_cscfg_register(struct coresight_device *csdev);
|
||||||
|
|
||||||
|
#endif /* CORESIGHT_ETM4X_CFG_H */
|
||||||
@@ -39,6 +39,8 @@
|
|||||||
|
|
||||||
#include "coresight-etm4x.h"
|
#include "coresight-etm4x.h"
|
||||||
#include "coresight-etm-perf.h"
|
#include "coresight-etm-perf.h"
|
||||||
|
#include "coresight-etm4x-cfg.h"
|
||||||
|
#include "coresight-syscfg.h"
|
||||||
|
|
||||||
static int boot_enable;
|
static int boot_enable;
|
||||||
module_param(boot_enable, int, 0444);
|
module_param(boot_enable, int, 0444);
|
||||||
@@ -561,12 +563,15 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int etm4_parse_event_config(struct etmv4_drvdata *drvdata,
|
static int etm4_parse_event_config(struct coresight_device *csdev,
|
||||||
struct perf_event *event)
|
struct perf_event *event)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||||
struct etmv4_config *config = &drvdata->config;
|
struct etmv4_config *config = &drvdata->config;
|
||||||
struct perf_event_attr *attr = &event->attr;
|
struct perf_event_attr *attr = &event->attr;
|
||||||
|
unsigned long cfg_hash;
|
||||||
|
int preset;
|
||||||
|
|
||||||
/* Clear configuration from previous run */
|
/* Clear configuration from previous run */
|
||||||
memset(config, 0, sizeof(struct etmv4_config));
|
memset(config, 0, sizeof(struct etmv4_config));
|
||||||
@@ -632,6 +637,20 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata,
|
|||||||
/* bit[12], Return stack enable bit */
|
/* bit[12], Return stack enable bit */
|
||||||
config->cfg |= BIT(12);
|
config->cfg |= BIT(12);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set any selected configuration and preset.
|
||||||
|
*
|
||||||
|
* This extracts the values of PMU_FORMAT_ATTR(configid) and PMU_FORMAT_ATTR(preset)
|
||||||
|
* in the perf attributes defined in coresight-etm-perf.c.
|
||||||
|
* configid uses bits 63:32 of attr->config2, preset uses bits 3:0 of attr->config.
|
||||||
|
* A zero configid means no configuration active, preset = 0 means no preset selected.
|
||||||
|
*/
|
||||||
|
if (attr->config2 & GENMASK_ULL(63, 32)) {
|
||||||
|
cfg_hash = (u32)(attr->config2 >> 32);
|
||||||
|
preset = attr->config & 0xF;
|
||||||
|
ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -648,7 +667,7 @@ static int etm4_enable_perf(struct coresight_device *csdev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Configure the tracer based on the session's specifics */
|
/* Configure the tracer based on the session's specifics */
|
||||||
ret = etm4_parse_event_config(drvdata, event);
|
ret = etm4_parse_event_config(csdev, event);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
/* And enable it */
|
/* And enable it */
|
||||||
@@ -794,11 +813,18 @@ static int etm4_disable_perf(struct coresight_device *csdev,
|
|||||||
u32 control;
|
u32 control;
|
||||||
struct etm_filters *filters = event->hw.addr_filters;
|
struct etm_filters *filters = event->hw.addr_filters;
|
||||||
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||||
|
struct perf_event_attr *attr = &event->attr;
|
||||||
|
|
||||||
if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id()))
|
if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id()))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
etm4_disable_hw(drvdata);
|
etm4_disable_hw(drvdata);
|
||||||
|
/*
|
||||||
|
* The config_id occupies bits 63:32 of the config2 perf event attr
|
||||||
|
* field. If this is non-zero then we will have enabled a config.
|
||||||
|
*/
|
||||||
|
if (attr->config2 & GENMASK_ULL(63, 32))
|
||||||
|
cscfg_csdev_disable_active_config(csdev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the start/stop logic was active when the unit was stopped.
|
* Check if the start/stop logic was active when the unit was stopped.
|
||||||
@@ -1939,6 +1965,13 @@ static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* register with config infrastructure & load any current features */
|
||||||
|
ret = etm4_cscfg_register(drvdata->csdev);
|
||||||
|
if (ret) {
|
||||||
|
coresight_unregister(drvdata->csdev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
etmdrvdata[drvdata->cpu] = drvdata;
|
etmdrvdata[drvdata->cpu] = drvdata;
|
||||||
|
|
||||||
dev_info(&drvdata->csdev->dev, "CPU%d: %s v%d.%d initialized\n",
|
dev_info(&drvdata->csdev->dev, "CPU%d: %s v%d.%d initialized\n",
|
||||||
@@ -2025,6 +2058,7 @@ static int __exit etm4_remove_dev(struct etmv4_drvdata *drvdata)
|
|||||||
|
|
||||||
cpus_read_unlock();
|
cpus_read_unlock();
|
||||||
|
|
||||||
|
cscfg_unregister_csdev(drvdata->csdev);
|
||||||
coresight_unregister(drvdata->csdev);
|
coresight_unregister(drvdata->csdev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <linux/sysfs.h>
|
#include <linux/sysfs.h>
|
||||||
#include "coresight-etm4x.h"
|
#include "coresight-etm4x.h"
|
||||||
#include "coresight-priv.h"
|
#include "coresight-priv.h"
|
||||||
|
#include "coresight-syscfg.h"
|
||||||
|
|
||||||
static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude)
|
static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude)
|
||||||
{
|
{
|
||||||
@@ -269,6 +270,8 @@ static ssize_t reset_store(struct device *dev,
|
|||||||
|
|
||||||
spin_unlock(&drvdata->spinlock);
|
spin_unlock(&drvdata->spinlock);
|
||||||
|
|
||||||
|
cscfg_csdev_reset_feats(to_coresight_device(dev));
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR_WO(reset);
|
static DEVICE_ATTR_WO(reset);
|
||||||
|
|||||||
396
drivers/hwtracing/coresight/coresight-syscfg-configfs.c
Normal file
396
drivers/hwtracing/coresight/coresight-syscfg-configfs.c
Normal file
@@ -0,0 +1,396 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Linaro Limited, All rights reserved.
|
||||||
|
* Author: Mike Leach <mike.leach@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/configfs.h>
|
||||||
|
|
||||||
|
#include "coresight-syscfg-configfs.h"
|
||||||
|
|
||||||
|
/* create a default ci_type. */
|
||||||
|
static inline struct config_item_type *cscfg_create_ci_type(void)
|
||||||
|
{
|
||||||
|
struct config_item_type *ci_type;
|
||||||
|
|
||||||
|
ci_type = devm_kzalloc(cscfg_device(), sizeof(*ci_type), GFP_KERNEL);
|
||||||
|
if (ci_type)
|
||||||
|
ci_type->ct_owner = THIS_MODULE;
|
||||||
|
|
||||||
|
return ci_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* configurations sub-group */
|
||||||
|
|
||||||
|
/* attributes for the config view group */
|
||||||
|
static ssize_t cscfg_cfg_description_show(struct config_item *item, char *page)
|
||||||
|
{
|
||||||
|
struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
|
||||||
|
struct cscfg_fs_config, group);
|
||||||
|
|
||||||
|
return scnprintf(page, PAGE_SIZE, "%s", fs_config->config_desc->description);
|
||||||
|
}
|
||||||
|
CONFIGFS_ATTR_RO(cscfg_cfg_, description);
|
||||||
|
|
||||||
|
static ssize_t cscfg_cfg_feature_refs_show(struct config_item *item, char *page)
|
||||||
|
{
|
||||||
|
struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
|
||||||
|
struct cscfg_fs_config, group);
|
||||||
|
const struct cscfg_config_desc *config_desc = fs_config->config_desc;
|
||||||
|
ssize_t ch_used = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < config_desc->nr_feat_refs; i++)
|
||||||
|
ch_used += scnprintf(page + ch_used, PAGE_SIZE - ch_used,
|
||||||
|
"%s\n", config_desc->feat_ref_names[i]);
|
||||||
|
return ch_used;
|
||||||
|
}
|
||||||
|
CONFIGFS_ATTR_RO(cscfg_cfg_, feature_refs);
|
||||||
|
|
||||||
|
/* list preset values in order of features and params */
|
||||||
|
static ssize_t cscfg_cfg_values_show(struct config_item *item, char *page)
|
||||||
|
{
|
||||||
|
const struct cscfg_feature_desc *feat_desc;
|
||||||
|
const struct cscfg_config_desc *config_desc;
|
||||||
|
struct cscfg_fs_preset *fs_preset;
|
||||||
|
int i, j, val_idx, preset_idx;
|
||||||
|
ssize_t used = 0;
|
||||||
|
|
||||||
|
fs_preset = container_of(to_config_group(item), struct cscfg_fs_preset, group);
|
||||||
|
config_desc = fs_preset->config_desc;
|
||||||
|
|
||||||
|
if (!config_desc->nr_presets)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
preset_idx = fs_preset->preset_num - 1;
|
||||||
|
|
||||||
|
/* start index on the correct array line */
|
||||||
|
val_idx = config_desc->nr_total_params * preset_idx;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A set of presets is the sum of all params in used features,
|
||||||
|
* in order of declaration of features and params in the features
|
||||||
|
*/
|
||||||
|
for (i = 0; i < config_desc->nr_feat_refs; i++) {
|
||||||
|
feat_desc = cscfg_get_named_feat_desc(config_desc->feat_ref_names[i]);
|
||||||
|
for (j = 0; j < feat_desc->nr_params; j++) {
|
||||||
|
used += scnprintf(page + used, PAGE_SIZE - used,
|
||||||
|
"%s.%s = 0x%llx ",
|
||||||
|
feat_desc->name,
|
||||||
|
feat_desc->params_desc[j].name,
|
||||||
|
config_desc->presets[val_idx++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
used += scnprintf(page + used, PAGE_SIZE - used, "\n");
|
||||||
|
|
||||||
|
return used;
|
||||||
|
}
|
||||||
|
CONFIGFS_ATTR_RO(cscfg_cfg_, values);
|
||||||
|
|
||||||
|
static struct configfs_attribute *cscfg_config_view_attrs[] = {
|
||||||
|
&cscfg_cfg_attr_description,
|
||||||
|
&cscfg_cfg_attr_feature_refs,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct config_item_type cscfg_config_view_type = {
|
||||||
|
.ct_owner = THIS_MODULE,
|
||||||
|
.ct_attrs = cscfg_config_view_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct configfs_attribute *cscfg_config_preset_attrs[] = {
|
||||||
|
&cscfg_cfg_attr_values,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct config_item_type cscfg_config_preset_type = {
|
||||||
|
.ct_owner = THIS_MODULE,
|
||||||
|
.ct_attrs = cscfg_config_preset_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int cscfg_add_preset_groups(struct cscfg_fs_config *cfg_view)
|
||||||
|
{
|
||||||
|
int preset_num;
|
||||||
|
struct cscfg_fs_preset *cfg_fs_preset;
|
||||||
|
struct cscfg_config_desc *config_desc = cfg_view->config_desc;
|
||||||
|
char name[CONFIGFS_ITEM_NAME_LEN];
|
||||||
|
|
||||||
|
if (!config_desc->nr_presets)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (preset_num = 1; preset_num <= config_desc->nr_presets; preset_num++) {
|
||||||
|
cfg_fs_preset = devm_kzalloc(cscfg_device(),
|
||||||
|
sizeof(struct cscfg_fs_preset), GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!cfg_fs_preset)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
snprintf(name, CONFIGFS_ITEM_NAME_LEN, "preset%d", preset_num);
|
||||||
|
cfg_fs_preset->preset_num = preset_num;
|
||||||
|
cfg_fs_preset->config_desc = cfg_view->config_desc;
|
||||||
|
config_group_init_type_name(&cfg_fs_preset->group, name,
|
||||||
|
&cscfg_config_preset_type);
|
||||||
|
configfs_add_default_group(&cfg_fs_preset->group, &cfg_view->group);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct config_group *cscfg_create_config_group(struct cscfg_config_desc *config_desc)
|
||||||
|
{
|
||||||
|
struct cscfg_fs_config *cfg_view;
|
||||||
|
struct device *dev = cscfg_device();
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!dev)
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
|
cfg_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_config), GFP_KERNEL);
|
||||||
|
if (!cfg_view)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
cfg_view->config_desc = config_desc;
|
||||||
|
config_group_init_type_name(&cfg_view->group, config_desc->name, &cscfg_config_view_type);
|
||||||
|
|
||||||
|
/* add in a preset<n> dir for each preset */
|
||||||
|
err = cscfg_add_preset_groups(cfg_view);
|
||||||
|
if (err)
|
||||||
|
return ERR_PTR(err);
|
||||||
|
|
||||||
|
return &cfg_view->group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* attributes for features view */
|
||||||
|
|
||||||
|
static ssize_t cscfg_feat_description_show(struct config_item *item, char *page)
|
||||||
|
{
|
||||||
|
struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item),
|
||||||
|
struct cscfg_fs_feature, group);
|
||||||
|
|
||||||
|
return scnprintf(page, PAGE_SIZE, "%s", fs_feat->feat_desc->description);
|
||||||
|
}
|
||||||
|
CONFIGFS_ATTR_RO(cscfg_feat_, description);
|
||||||
|
|
||||||
|
static ssize_t cscfg_feat_matches_show(struct config_item *item, char *page)
|
||||||
|
{
|
||||||
|
struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item),
|
||||||
|
struct cscfg_fs_feature, group);
|
||||||
|
u32 match_flags = fs_feat->feat_desc->match_flags;
|
||||||
|
int used = 0;
|
||||||
|
|
||||||
|
if (match_flags & CS_CFG_MATCH_CLASS_SRC_ALL)
|
||||||
|
used = scnprintf(page, PAGE_SIZE, "SRC_ALL ");
|
||||||
|
|
||||||
|
if (match_flags & CS_CFG_MATCH_CLASS_SRC_ETM4)
|
||||||
|
used += scnprintf(page + used, PAGE_SIZE - used, "SRC_ETMV4 ");
|
||||||
|
|
||||||
|
used += scnprintf(page + used, PAGE_SIZE - used, "\n");
|
||||||
|
return used;
|
||||||
|
}
|
||||||
|
CONFIGFS_ATTR_RO(cscfg_feat_, matches);
|
||||||
|
|
||||||
|
static ssize_t cscfg_feat_nr_params_show(struct config_item *item, char *page)
|
||||||
|
{
|
||||||
|
struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item),
|
||||||
|
struct cscfg_fs_feature, group);
|
||||||
|
|
||||||
|
return scnprintf(page, PAGE_SIZE, "%d\n", fs_feat->feat_desc->nr_params);
|
||||||
|
}
|
||||||
|
CONFIGFS_ATTR_RO(cscfg_feat_, nr_params);
|
||||||
|
|
||||||
|
/* base feature desc attrib structures */
|
||||||
|
static struct configfs_attribute *cscfg_feature_view_attrs[] = {
|
||||||
|
&cscfg_feat_attr_description,
|
||||||
|
&cscfg_feat_attr_matches,
|
||||||
|
&cscfg_feat_attr_nr_params,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct config_item_type cscfg_feature_view_type = {
|
||||||
|
.ct_owner = THIS_MODULE,
|
||||||
|
.ct_attrs = cscfg_feature_view_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t cscfg_param_value_show(struct config_item *item, char *page)
|
||||||
|
{
|
||||||
|
struct cscfg_fs_param *param_item = container_of(to_config_group(item),
|
||||||
|
struct cscfg_fs_param, group);
|
||||||
|
u64 value = param_item->feat_desc->params_desc[param_item->param_idx].value;
|
||||||
|
|
||||||
|
return scnprintf(page, PAGE_SIZE, "0x%llx\n", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t cscfg_param_value_store(struct config_item *item,
|
||||||
|
const char *page, size_t size)
|
||||||
|
{
|
||||||
|
struct cscfg_fs_param *param_item = container_of(to_config_group(item),
|
||||||
|
struct cscfg_fs_param, group);
|
||||||
|
struct cscfg_feature_desc *feat_desc = param_item->feat_desc;
|
||||||
|
int param_idx = param_item->param_idx;
|
||||||
|
u64 value;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = kstrtoull(page, 0, &value);
|
||||||
|
if (!err)
|
||||||
|
err = cscfg_update_feat_param_val(feat_desc, param_idx, value);
|
||||||
|
|
||||||
|
return err ? err : size;
|
||||||
|
}
|
||||||
|
CONFIGFS_ATTR(cscfg_param_, value);
|
||||||
|
|
||||||
|
static struct configfs_attribute *cscfg_param_view_attrs[] = {
|
||||||
|
&cscfg_param_attr_value,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct config_item_type cscfg_param_view_type = {
|
||||||
|
.ct_owner = THIS_MODULE,
|
||||||
|
.ct_attrs = cscfg_param_view_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* configfs has far less functionality provided to add attributes dynamically than sysfs,
|
||||||
|
* and the show and store fns pass the enclosing config_item so the actual attribute cannot
|
||||||
|
* be determined. Therefore we add each item as a group directory, with a value attribute.
|
||||||
|
*/
|
||||||
|
static int cscfg_create_params_group_items(struct cscfg_feature_desc *feat_desc,
|
||||||
|
struct config_group *params_group)
|
||||||
|
{
|
||||||
|
struct device *dev = cscfg_device();
|
||||||
|
struct cscfg_fs_param *param_item;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* parameter items - as groups with default_value attribute */
|
||||||
|
for (i = 0; i < feat_desc->nr_params; i++) {
|
||||||
|
param_item = devm_kzalloc(dev, sizeof(struct cscfg_fs_param), GFP_KERNEL);
|
||||||
|
if (!param_item)
|
||||||
|
return -ENOMEM;
|
||||||
|
param_item->feat_desc = feat_desc;
|
||||||
|
param_item->param_idx = i;
|
||||||
|
config_group_init_type_name(¶m_item->group,
|
||||||
|
feat_desc->params_desc[i].name,
|
||||||
|
&cscfg_param_view_type);
|
||||||
|
configfs_add_default_group(¶m_item->group, params_group);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct config_group *cscfg_create_feature_group(struct cscfg_feature_desc *feat_desc)
|
||||||
|
{
|
||||||
|
struct cscfg_fs_feature *feat_view;
|
||||||
|
struct config_item_type *params_group_type;
|
||||||
|
struct config_group *params_group = NULL;
|
||||||
|
struct device *dev = cscfg_device();
|
||||||
|
int item_err;
|
||||||
|
|
||||||
|
if (!dev)
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
|
feat_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_feature), GFP_KERNEL);
|
||||||
|
if (!feat_view)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
if (feat_desc->nr_params) {
|
||||||
|
params_group = devm_kzalloc(dev, sizeof(struct config_group), GFP_KERNEL);
|
||||||
|
if (!params_group)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
params_group_type = cscfg_create_ci_type();
|
||||||
|
if (!params_group_type)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
feat_view->feat_desc = feat_desc;
|
||||||
|
config_group_init_type_name(&feat_view->group,
|
||||||
|
feat_desc->name,
|
||||||
|
&cscfg_feature_view_type);
|
||||||
|
if (params_group) {
|
||||||
|
config_group_init_type_name(params_group, "params", params_group_type);
|
||||||
|
configfs_add_default_group(params_group, &feat_view->group);
|
||||||
|
item_err = cscfg_create_params_group_items(feat_desc, params_group);
|
||||||
|
if (item_err)
|
||||||
|
return ERR_PTR(item_err);
|
||||||
|
}
|
||||||
|
return &feat_view->group;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct config_item_type cscfg_configs_type = {
|
||||||
|
.ct_owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct config_group cscfg_configs_grp = {
|
||||||
|
.cg_item = {
|
||||||
|
.ci_namebuf = "configurations",
|
||||||
|
.ci_type = &cscfg_configs_type,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* add configuration to configurations group */
|
||||||
|
int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc)
|
||||||
|
{
|
||||||
|
struct config_group *new_group;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
new_group = cscfg_create_config_group(config_desc);
|
||||||
|
if (IS_ERR(new_group))
|
||||||
|
return PTR_ERR(new_group);
|
||||||
|
err = configfs_register_group(&cscfg_configs_grp, new_group);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct config_item_type cscfg_features_type = {
|
||||||
|
.ct_owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct config_group cscfg_features_grp = {
|
||||||
|
.cg_item = {
|
||||||
|
.ci_namebuf = "features",
|
||||||
|
.ci_type = &cscfg_features_type,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* add feature to features group */
|
||||||
|
int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc)
|
||||||
|
{
|
||||||
|
struct config_group *new_group;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
new_group = cscfg_create_feature_group(feat_desc);
|
||||||
|
if (IS_ERR(new_group))
|
||||||
|
return PTR_ERR(new_group);
|
||||||
|
err = configfs_register_group(&cscfg_features_grp, new_group);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr)
|
||||||
|
{
|
||||||
|
struct configfs_subsystem *subsys;
|
||||||
|
struct config_item_type *ci_type;
|
||||||
|
|
||||||
|
if (!cscfg_mgr)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ci_type = cscfg_create_ci_type();
|
||||||
|
if (!ci_type)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
subsys = &cscfg_mgr->cfgfs_subsys;
|
||||||
|
config_item_set_name(&subsys->su_group.cg_item, CSCFG_FS_SUBSYS_NAME);
|
||||||
|
subsys->su_group.cg_item.ci_type = ci_type;
|
||||||
|
|
||||||
|
config_group_init(&subsys->su_group);
|
||||||
|
mutex_init(&subsys->su_mutex);
|
||||||
|
|
||||||
|
/* Add default groups to subsystem */
|
||||||
|
config_group_init(&cscfg_configs_grp);
|
||||||
|
configfs_add_default_group(&cscfg_configs_grp, &subsys->su_group);
|
||||||
|
|
||||||
|
config_group_init(&cscfg_features_grp);
|
||||||
|
configfs_add_default_group(&cscfg_features_grp, &subsys->su_group);
|
||||||
|
|
||||||
|
return configfs_register_subsystem(subsys);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cscfg_configfs_release(struct cscfg_manager *cscfg_mgr)
|
||||||
|
{
|
||||||
|
configfs_unregister_subsystem(&cscfg_mgr->cfgfs_subsys);
|
||||||
|
}
|
||||||
45
drivers/hwtracing/coresight/coresight-syscfg-configfs.h
Normal file
45
drivers/hwtracing/coresight/coresight-syscfg-configfs.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
/*
|
||||||
|
* Coresight system configuration driver - support for configfs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CORESIGHT_SYSCFG_CONFIGFS_H
|
||||||
|
#define CORESIGHT_SYSCFG_CONFIGFS_H
|
||||||
|
|
||||||
|
#include <linux/configfs.h>
|
||||||
|
#include "coresight-syscfg.h"
|
||||||
|
|
||||||
|
#define CSCFG_FS_SUBSYS_NAME "cs-syscfg"
|
||||||
|
|
||||||
|
/* container for configuration view */
|
||||||
|
struct cscfg_fs_config {
|
||||||
|
struct cscfg_config_desc *config_desc;
|
||||||
|
struct config_group group;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* container for feature view */
|
||||||
|
struct cscfg_fs_feature {
|
||||||
|
struct cscfg_feature_desc *feat_desc;
|
||||||
|
struct config_group group;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* container for parameter view */
|
||||||
|
struct cscfg_fs_param {
|
||||||
|
int param_idx;
|
||||||
|
struct cscfg_feature_desc *feat_desc;
|
||||||
|
struct config_group group;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* container for preset view */
|
||||||
|
struct cscfg_fs_preset {
|
||||||
|
int preset_num;
|
||||||
|
struct cscfg_config_desc *config_desc;
|
||||||
|
struct config_group group;
|
||||||
|
};
|
||||||
|
|
||||||
|
int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr);
|
||||||
|
void cscfg_configfs_release(struct cscfg_manager *cscfg_mgr);
|
||||||
|
int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc);
|
||||||
|
int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc);
|
||||||
|
|
||||||
|
#endif /* CORESIGHT_SYSCFG_CONFIGFS_H */
|
||||||
847
drivers/hwtracing/coresight/coresight-syscfg.c
Normal file
847
drivers/hwtracing/coresight/coresight-syscfg.c
Normal file
@@ -0,0 +1,847 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Linaro Limited, All rights reserved.
|
||||||
|
* Author: Mike Leach <mike.leach@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#include "coresight-config.h"
|
||||||
|
#include "coresight-etm-perf.h"
|
||||||
|
#include "coresight-syscfg.h"
|
||||||
|
#include "coresight-syscfg-configfs.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cscfg_ API manages configurations and features for the entire coresight
|
||||||
|
* infrastructure.
|
||||||
|
*
|
||||||
|
* It allows the loading of configurations and features, and loads these into
|
||||||
|
* coresight devices as appropriate.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* protect the cscsg_data and device */
|
||||||
|
static DEFINE_MUTEX(cscfg_mutex);
|
||||||
|
|
||||||
|
/* only one of these */
|
||||||
|
static struct cscfg_manager *cscfg_mgr;
|
||||||
|
|
||||||
|
/* load features and configuations into the lists */
|
||||||
|
|
||||||
|
/* get name feature instance from a coresight device list of features */
|
||||||
|
static struct cscfg_feature_csdev *
|
||||||
|
cscfg_get_feat_csdev(struct coresight_device *csdev, const char *name)
|
||||||
|
{
|
||||||
|
struct cscfg_feature_csdev *feat_csdev = NULL;
|
||||||
|
|
||||||
|
list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) {
|
||||||
|
if (strcmp(feat_csdev->feat_desc->name, name) == 0)
|
||||||
|
return feat_csdev;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate the device config instance - with max number of used features */
|
||||||
|
static struct cscfg_config_csdev *
|
||||||
|
cscfg_alloc_csdev_cfg(struct coresight_device *csdev, int nr_feats)
|
||||||
|
{
|
||||||
|
struct cscfg_config_csdev *config_csdev = NULL;
|
||||||
|
struct device *dev = csdev->dev.parent;
|
||||||
|
|
||||||
|
/* this is being allocated using the devm for the coresight device */
|
||||||
|
config_csdev = devm_kzalloc(dev,
|
||||||
|
offsetof(struct cscfg_config_csdev, feats_csdev[nr_feats]),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!config_csdev)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
config_csdev->csdev = csdev;
|
||||||
|
return config_csdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load a config into a device if there are any feature matches between config and device */
|
||||||
|
static int cscfg_add_csdev_cfg(struct coresight_device *csdev,
|
||||||
|
struct cscfg_config_desc *config_desc)
|
||||||
|
{
|
||||||
|
struct cscfg_config_csdev *config_csdev = NULL;
|
||||||
|
struct cscfg_feature_csdev *feat_csdev;
|
||||||
|
unsigned long flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* look at each required feature and see if it matches any feature on the device */
|
||||||
|
for (i = 0; i < config_desc->nr_feat_refs; i++) {
|
||||||
|
/* look for a matching name */
|
||||||
|
feat_csdev = cscfg_get_feat_csdev(csdev, config_desc->feat_ref_names[i]);
|
||||||
|
if (feat_csdev) {
|
||||||
|
/*
|
||||||
|
* At least one feature on this device matches the config
|
||||||
|
* add a config instance to the device and a reference to the feature.
|
||||||
|
*/
|
||||||
|
if (!config_csdev) {
|
||||||
|
config_csdev = cscfg_alloc_csdev_cfg(csdev,
|
||||||
|
config_desc->nr_feat_refs);
|
||||||
|
if (!config_csdev)
|
||||||
|
return -ENOMEM;
|
||||||
|
config_csdev->config_desc = config_desc;
|
||||||
|
}
|
||||||
|
config_csdev->feats_csdev[config_csdev->nr_feat++] = feat_csdev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* if matched features, add config to device.*/
|
||||||
|
if (config_csdev) {
|
||||||
|
spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
|
||||||
|
list_add(&config_csdev->node, &csdev->config_csdev_list);
|
||||||
|
spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the config to the set of registered devices - call with mutex locked.
|
||||||
|
* Iterates through devices - any device that matches one or more of the
|
||||||
|
* configuration features will load it, the others will ignore it.
|
||||||
|
*/
|
||||||
|
static int cscfg_add_cfg_to_csdevs(struct cscfg_config_desc *config_desc)
|
||||||
|
{
|
||||||
|
struct cscfg_registered_csdev *csdev_item;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
|
||||||
|
err = cscfg_add_csdev_cfg(csdev_item->csdev, config_desc);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate a feature object for load into a csdev.
|
||||||
|
* memory allocated using the csdev->dev object using devm managed allocator.
|
||||||
|
*/
|
||||||
|
static struct cscfg_feature_csdev *
|
||||||
|
cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc *feat_desc)
|
||||||
|
{
|
||||||
|
struct cscfg_feature_csdev *feat_csdev = NULL;
|
||||||
|
struct device *dev = csdev->dev.parent;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
feat_csdev = devm_kzalloc(dev, sizeof(struct cscfg_feature_csdev), GFP_KERNEL);
|
||||||
|
if (!feat_csdev)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* parameters are optional - could be 0 */
|
||||||
|
feat_csdev->nr_params = feat_desc->nr_params;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if we need parameters, zero alloc the space here, the load routine in
|
||||||
|
* the csdev device driver will fill out some information according to
|
||||||
|
* feature descriptor.
|
||||||
|
*/
|
||||||
|
if (feat_csdev->nr_params) {
|
||||||
|
feat_csdev->params_csdev = devm_kcalloc(dev, feat_csdev->nr_params,
|
||||||
|
sizeof(struct cscfg_parameter_csdev),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!feat_csdev->params_csdev)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fill in the feature reference in the param - other fields
|
||||||
|
* handled by loader in csdev.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < feat_csdev->nr_params; i++)
|
||||||
|
feat_csdev->params_csdev[i].feat_csdev = feat_csdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Always have registers to program - again the load routine in csdev device
|
||||||
|
* will fill out according to feature descriptor and device requirements.
|
||||||
|
*/
|
||||||
|
feat_csdev->nr_regs = feat_desc->nr_regs;
|
||||||
|
feat_csdev->regs_csdev = devm_kcalloc(dev, feat_csdev->nr_regs,
|
||||||
|
sizeof(struct cscfg_regval_csdev),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!feat_csdev->regs_csdev)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* load the feature default values */
|
||||||
|
feat_csdev->feat_desc = feat_desc;
|
||||||
|
feat_csdev->csdev = csdev;
|
||||||
|
|
||||||
|
return feat_csdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* load one feature into one coresight device */
|
||||||
|
static int cscfg_load_feat_csdev(struct coresight_device *csdev,
|
||||||
|
struct cscfg_feature_desc *feat_desc,
|
||||||
|
struct cscfg_csdev_feat_ops *ops)
|
||||||
|
{
|
||||||
|
struct cscfg_feature_csdev *feat_csdev;
|
||||||
|
unsigned long flags;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!ops->load_feat)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);
|
||||||
|
if (!feat_csdev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* load the feature into the device */
|
||||||
|
err = ops->load_feat(csdev, feat_csdev);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* add to internal csdev feature list & initialise using reset call */
|
||||||
|
cscfg_reset_feat(feat_csdev);
|
||||||
|
spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
|
||||||
|
list_add(&feat_csdev->node, &csdev->feature_csdev_list);
|
||||||
|
spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add feature to any matching devices - call with mutex locked.
|
||||||
|
* Iterates through devices - any device that matches the feature will be
|
||||||
|
* called to load it.
|
||||||
|
*/
|
||||||
|
static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc)
|
||||||
|
{
|
||||||
|
struct cscfg_registered_csdev *csdev_item;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
|
||||||
|
if (csdev_item->match_flags & feat_desc->match_flags) {
|
||||||
|
err = cscfg_load_feat_csdev(csdev_item->csdev, feat_desc, &csdev_item->ops);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check feature list for a named feature - call with mutex locked. */
|
||||||
|
static bool cscfg_match_list_feat(const char *name)
|
||||||
|
{
|
||||||
|
struct cscfg_feature_desc *feat_desc;
|
||||||
|
|
||||||
|
list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
|
||||||
|
if (strcmp(feat_desc->name, name) == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check all feat needed for cfg are in the list - call with mutex locked. */
|
||||||
|
static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *config_desc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < config_desc->nr_feat_refs; i++)
|
||||||
|
if (!cscfg_match_list_feat(config_desc->feat_ref_names[i]))
|
||||||
|
return -EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* load feature - add to feature list.
|
||||||
|
*/
|
||||||
|
static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* add feature to any matching registered devices */
|
||||||
|
err = cscfg_add_feat_to_csdevs(feat_desc);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
list_add(&feat_desc->item, &cscfg_mgr->feat_desc_list);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* load config into the system - validate used features exist then add to
|
||||||
|
* config list.
|
||||||
|
*/
|
||||||
|
static int cscfg_load_config(struct cscfg_config_desc *config_desc)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* validate features are present */
|
||||||
|
err = cscfg_check_feat_for_cfg(config_desc);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* add config to any matching registered device */
|
||||||
|
err = cscfg_add_cfg_to_csdevs(config_desc);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* add config to perf fs to allow selection */
|
||||||
|
err = etm_perf_add_symlink_cscfg(cscfg_device(), config_desc);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
list_add(&config_desc->item, &cscfg_mgr->config_desc_list);
|
||||||
|
atomic_set(&config_desc->active_cnt, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get a feature descriptor by name */
|
||||||
|
const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name)
|
||||||
|
{
|
||||||
|
const struct cscfg_feature_desc *feat_desc = NULL, *feat_desc_item;
|
||||||
|
|
||||||
|
mutex_lock(&cscfg_mutex);
|
||||||
|
|
||||||
|
list_for_each_entry(feat_desc_item, &cscfg_mgr->feat_desc_list, item) {
|
||||||
|
if (strcmp(feat_desc_item->name, name) == 0) {
|
||||||
|
feat_desc = feat_desc_item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&cscfg_mutex);
|
||||||
|
return feat_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called with cscfg_mutex held */
|
||||||
|
static struct cscfg_feature_csdev *
|
||||||
|
cscfg_csdev_get_feat_from_desc(struct coresight_device *csdev,
|
||||||
|
struct cscfg_feature_desc *feat_desc)
|
||||||
|
{
|
||||||
|
struct cscfg_feature_csdev *feat_csdev;
|
||||||
|
|
||||||
|
list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) {
|
||||||
|
if (feat_csdev->feat_desc == feat_desc)
|
||||||
|
return feat_csdev;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
|
||||||
|
int param_idx, u64 value)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
struct cscfg_feature_csdev *feat_csdev;
|
||||||
|
struct cscfg_registered_csdev *csdev_item;
|
||||||
|
|
||||||
|
mutex_lock(&cscfg_mutex);
|
||||||
|
|
||||||
|
/* check if any config active & return busy */
|
||||||
|
if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
|
||||||
|
err = -EBUSY;
|
||||||
|
goto unlock_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set the value */
|
||||||
|
if ((param_idx < 0) || (param_idx >= feat_desc->nr_params)) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto unlock_exit;
|
||||||
|
}
|
||||||
|
feat_desc->params_desc[param_idx].value = value;
|
||||||
|
|
||||||
|
/* update loaded instances.*/
|
||||||
|
list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
|
||||||
|
feat_csdev = cscfg_csdev_get_feat_from_desc(csdev_item->csdev, feat_desc);
|
||||||
|
if (feat_csdev)
|
||||||
|
feat_csdev->params_csdev[param_idx].current_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock_exit:
|
||||||
|
mutex_unlock(&cscfg_mutex);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cscfg_load_config_sets - API function to load feature and config sets.
|
||||||
|
*
|
||||||
|
* Take a 0 terminated array of feature descriptors and/or configuration
|
||||||
|
* descriptors and load into the system.
|
||||||
|
* Features are loaded first to ensure configuration dependencies can be met.
|
||||||
|
*
|
||||||
|
* @config_descs: 0 terminated array of configuration descriptors.
|
||||||
|
* @feat_descs: 0 terminated array of feature descriptors.
|
||||||
|
*/
|
||||||
|
int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
|
||||||
|
struct cscfg_feature_desc **feat_descs)
|
||||||
|
{
|
||||||
|
int err, i = 0;
|
||||||
|
|
||||||
|
mutex_lock(&cscfg_mutex);
|
||||||
|
|
||||||
|
/* load features first */
|
||||||
|
if (feat_descs) {
|
||||||
|
while (feat_descs[i]) {
|
||||||
|
err = cscfg_load_feat(feat_descs[i]);
|
||||||
|
if (!err)
|
||||||
|
err = cscfg_configfs_add_feature(feat_descs[i]);
|
||||||
|
if (err) {
|
||||||
|
pr_err("coresight-syscfg: Failed to load feature %s\n",
|
||||||
|
feat_descs[i]->name);
|
||||||
|
goto exit_unlock;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* next any configurations to check feature dependencies */
|
||||||
|
i = 0;
|
||||||
|
if (config_descs) {
|
||||||
|
while (config_descs[i]) {
|
||||||
|
err = cscfg_load_config(config_descs[i]);
|
||||||
|
if (!err)
|
||||||
|
err = cscfg_configfs_add_config(config_descs[i]);
|
||||||
|
if (err) {
|
||||||
|
pr_err("coresight-syscfg: Failed to load configuration %s\n",
|
||||||
|
config_descs[i]->name);
|
||||||
|
goto exit_unlock;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit_unlock:
|
||||||
|
mutex_unlock(&cscfg_mutex);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
|
||||||
|
|
||||||
|
/* Handle coresight device registration and add configs and features to devices */
|
||||||
|
|
||||||
|
/* iterate through config lists and load matching configs to device */
|
||||||
|
static int cscfg_add_cfgs_csdev(struct coresight_device *csdev)
|
||||||
|
{
|
||||||
|
struct cscfg_config_desc *config_desc;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
|
||||||
|
err = cscfg_add_csdev_cfg(csdev, config_desc);
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* iterate through feature lists and load matching features to device */
|
||||||
|
static int cscfg_add_feats_csdev(struct coresight_device *csdev,
|
||||||
|
u32 match_flags,
|
||||||
|
struct cscfg_csdev_feat_ops *ops)
|
||||||
|
{
|
||||||
|
struct cscfg_feature_desc *feat_desc;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (!ops->load_feat)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
|
||||||
|
if (feat_desc->match_flags & match_flags) {
|
||||||
|
err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add coresight device to list and copy its matching info */
|
||||||
|
static int cscfg_list_add_csdev(struct coresight_device *csdev,
|
||||||
|
u32 match_flags,
|
||||||
|
struct cscfg_csdev_feat_ops *ops)
|
||||||
|
{
|
||||||
|
struct cscfg_registered_csdev *csdev_item;
|
||||||
|
|
||||||
|
/* allocate the list entry structure */
|
||||||
|
csdev_item = kzalloc(sizeof(struct cscfg_registered_csdev), GFP_KERNEL);
|
||||||
|
if (!csdev_item)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
csdev_item->csdev = csdev;
|
||||||
|
csdev_item->match_flags = match_flags;
|
||||||
|
csdev_item->ops.load_feat = ops->load_feat;
|
||||||
|
list_add(&csdev_item->item, &cscfg_mgr->csdev_desc_list);
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&csdev->feature_csdev_list);
|
||||||
|
INIT_LIST_HEAD(&csdev->config_csdev_list);
|
||||||
|
spin_lock_init(&csdev->cscfg_csdev_lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove a coresight device from the list and free data */
|
||||||
|
static void cscfg_list_remove_csdev(struct coresight_device *csdev)
|
||||||
|
{
|
||||||
|
struct cscfg_registered_csdev *csdev_item, *tmp;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(csdev_item, tmp, &cscfg_mgr->csdev_desc_list, item) {
|
||||||
|
if (csdev_item->csdev == csdev) {
|
||||||
|
list_del(&csdev_item->item);
|
||||||
|
kfree(csdev_item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cscfg_register_csdev - register a coresight device with the syscfg manager.
|
||||||
|
*
|
||||||
|
* Registers the coresight device with the system. @match_flags used to check
|
||||||
|
* if the device is a match for registered features. Any currently registered
|
||||||
|
* configurations and features that match the device will be loaded onto it.
|
||||||
|
*
|
||||||
|
* @csdev: The coresight device to register.
|
||||||
|
* @match_flags: Matching information to load features.
|
||||||
|
* @ops: Standard operations supported by the device.
|
||||||
|
*/
|
||||||
|
int cscfg_register_csdev(struct coresight_device *csdev,
|
||||||
|
u32 match_flags,
|
||||||
|
struct cscfg_csdev_feat_ops *ops)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
mutex_lock(&cscfg_mutex);
|
||||||
|
|
||||||
|
/* add device to list of registered devices */
|
||||||
|
ret = cscfg_list_add_csdev(csdev, match_flags, ops);
|
||||||
|
if (ret)
|
||||||
|
goto reg_csdev_unlock;
|
||||||
|
|
||||||
|
/* now load any registered features and configs matching the device. */
|
||||||
|
ret = cscfg_add_feats_csdev(csdev, match_flags, ops);
|
||||||
|
if (ret) {
|
||||||
|
cscfg_list_remove_csdev(csdev);
|
||||||
|
goto reg_csdev_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cscfg_add_cfgs_csdev(csdev);
|
||||||
|
if (ret) {
|
||||||
|
cscfg_list_remove_csdev(csdev);
|
||||||
|
goto reg_csdev_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("CSCFG registered %s", dev_name(&csdev->dev));
|
||||||
|
|
||||||
|
reg_csdev_unlock:
|
||||||
|
mutex_unlock(&cscfg_mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(cscfg_register_csdev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cscfg_unregister_csdev - remove coresight device from syscfg manager.
|
||||||
|
*
|
||||||
|
* @csdev: Device to remove.
|
||||||
|
*/
|
||||||
|
void cscfg_unregister_csdev(struct coresight_device *csdev)
|
||||||
|
{
|
||||||
|
mutex_lock(&cscfg_mutex);
|
||||||
|
cscfg_list_remove_csdev(csdev);
|
||||||
|
mutex_unlock(&cscfg_mutex);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(cscfg_unregister_csdev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cscfg_csdev_reset_feats - reset features for a CoreSight device.
|
||||||
|
*
|
||||||
|
* Resets all parameters and register values for any features loaded
|
||||||
|
* into @csdev to their default values.
|
||||||
|
*
|
||||||
|
* @csdev: The CoreSight device.
|
||||||
|
*/
|
||||||
|
void cscfg_csdev_reset_feats(struct coresight_device *csdev)
|
||||||
|
{
|
||||||
|
struct cscfg_feature_csdev *feat_csdev;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
|
||||||
|
if (list_empty(&csdev->feature_csdev_list))
|
||||||
|
goto unlock_exit;
|
||||||
|
|
||||||
|
list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node)
|
||||||
|
cscfg_reset_feat(feat_csdev);
|
||||||
|
|
||||||
|
unlock_exit:
|
||||||
|
spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cscfg_activate_config - Mark a configuration descriptor as active.
|
||||||
|
*
|
||||||
|
* This will be seen when csdev devices are enabled in the system.
|
||||||
|
* Only activated configurations can be enabled on individual devices.
|
||||||
|
* Activation protects the configuration from alteration or removal while
|
||||||
|
* active.
|
||||||
|
*
|
||||||
|
* Selection by hash value - generated from the configuration name when it
|
||||||
|
* was loaded and added to the cs_etm/configurations file system for selection
|
||||||
|
* by perf.
|
||||||
|
*
|
||||||
|
* Increments the configuration descriptor active count and the global active
|
||||||
|
* count.
|
||||||
|
*
|
||||||
|
* @cfg_hash: Hash value of the selected configuration name.
|
||||||
|
*/
|
||||||
|
int cscfg_activate_config(unsigned long cfg_hash)
|
||||||
|
{
|
||||||
|
struct cscfg_config_desc *config_desc;
|
||||||
|
int err = -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&cscfg_mutex);
|
||||||
|
|
||||||
|
list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
|
||||||
|
if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
|
||||||
|
/*
|
||||||
|
* increment the global active count - control changes to
|
||||||
|
* active configurations
|
||||||
|
*/
|
||||||
|
atomic_inc(&cscfg_mgr->sys_active_cnt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mark the descriptor as active so enable config on a
|
||||||
|
* device instance will use it
|
||||||
|
*/
|
||||||
|
atomic_inc(&config_desc->active_cnt);
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
dev_dbg(cscfg_device(), "Activate config %s.\n", config_desc->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex_unlock(&cscfg_mutex);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(cscfg_activate_config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cscfg_deactivate_config - Mark a config descriptor as inactive.
|
||||||
|
*
|
||||||
|
* Decrement the configuration and global active counts.
|
||||||
|
*
|
||||||
|
* @cfg_hash: Hash value of the selected configuration name.
|
||||||
|
*/
|
||||||
|
void cscfg_deactivate_config(unsigned long cfg_hash)
|
||||||
|
{
|
||||||
|
struct cscfg_config_desc *config_desc;
|
||||||
|
|
||||||
|
mutex_lock(&cscfg_mutex);
|
||||||
|
|
||||||
|
list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
|
||||||
|
if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
|
||||||
|
atomic_dec(&config_desc->active_cnt);
|
||||||
|
atomic_dec(&cscfg_mgr->sys_active_cnt);
|
||||||
|
dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex_unlock(&cscfg_mutex);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(cscfg_deactivate_config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cscfg_csdev_enable_active_config - Enable matching active configuration for device.
|
||||||
|
*
|
||||||
|
* Enables the configuration selected by @cfg_hash if the configuration is supported
|
||||||
|
* on the device and has been activated.
|
||||||
|
*
|
||||||
|
* If active and supported the CoreSight device @csdev will be programmed with the
|
||||||
|
* configuration, using @preset parameters.
|
||||||
|
*
|
||||||
|
* Should be called before driver hardware enable for the requested device, prior to
|
||||||
|
* programming and enabling the physical hardware.
|
||||||
|
*
|
||||||
|
* @csdev: CoreSight device to program.
|
||||||
|
* @cfg_hash: Selector for the configuration.
|
||||||
|
* @preset: Preset parameter values to use, 0 for current / default values.
|
||||||
|
*/
|
||||||
|
int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
|
||||||
|
unsigned long cfg_hash, int preset)
|
||||||
|
{
|
||||||
|
struct cscfg_config_csdev *config_csdev_active = NULL, *config_csdev_item;
|
||||||
|
const struct cscfg_config_desc *config_desc;
|
||||||
|
unsigned long flags;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
/* quickly check global count */
|
||||||
|
if (!atomic_read(&cscfg_mgr->sys_active_cnt))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for matching configuration - set the active configuration
|
||||||
|
* context if found.
|
||||||
|
*/
|
||||||
|
spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
|
||||||
|
list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {
|
||||||
|
config_desc = config_csdev_item->config_desc;
|
||||||
|
if ((atomic_read(&config_desc->active_cnt)) &&
|
||||||
|
((unsigned long)config_desc->event_ea->var == cfg_hash)) {
|
||||||
|
config_csdev_active = config_csdev_item;
|
||||||
|
csdev->active_cscfg_ctxt = (void *)config_csdev_active;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If found, attempt to enable
|
||||||
|
*/
|
||||||
|
if (config_csdev_active) {
|
||||||
|
/*
|
||||||
|
* Call the generic routine that will program up the internal
|
||||||
|
* driver structures prior to programming up the hardware.
|
||||||
|
* This routine takes the driver spinlock saved in the configs.
|
||||||
|
*/
|
||||||
|
err = cscfg_csdev_enable_config(config_csdev_active, preset);
|
||||||
|
if (!err) {
|
||||||
|
/*
|
||||||
|
* Successful programming. Check the active_cscfg_ctxt
|
||||||
|
* pointer to ensure no pre-emption disabled it via
|
||||||
|
* cscfg_csdev_disable_active_config() before
|
||||||
|
* we could start.
|
||||||
|
*
|
||||||
|
* Set enabled if OK, err if not.
|
||||||
|
*/
|
||||||
|
spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
|
||||||
|
if (csdev->active_cscfg_ctxt)
|
||||||
|
config_csdev_active->enabled = true;
|
||||||
|
else
|
||||||
|
err = -EBUSY;
|
||||||
|
spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cscfg_csdev_disable_active_config - disable an active config on the device.
|
||||||
|
*
|
||||||
|
* Disables the active configuration on the CoreSight device @csdev.
|
||||||
|
* Disable will save the values of any registers marked in the configurations
|
||||||
|
* as save on disable.
|
||||||
|
*
|
||||||
|
* Should be called after driver hardware disable for the requested device,
|
||||||
|
* after disabling the physical hardware and reading back registers.
|
||||||
|
*
|
||||||
|
* @csdev: The CoreSight device.
|
||||||
|
*/
|
||||||
|
void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
|
||||||
|
{
|
||||||
|
struct cscfg_config_csdev *config_csdev;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if we have an active config, and that it was successfully enabled.
|
||||||
|
* If it was not enabled, we have no work to do, otherwise mark as disabled.
|
||||||
|
* Clear the active config pointer.
|
||||||
|
*/
|
||||||
|
spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
|
||||||
|
config_csdev = (struct cscfg_config_csdev *)csdev->active_cscfg_ctxt;
|
||||||
|
if (config_csdev) {
|
||||||
|
if (!config_csdev->enabled)
|
||||||
|
config_csdev = NULL;
|
||||||
|
else
|
||||||
|
config_csdev->enabled = false;
|
||||||
|
}
|
||||||
|
csdev->active_cscfg_ctxt = NULL;
|
||||||
|
spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
|
||||||
|
|
||||||
|
/* true if there was an enabled active config */
|
||||||
|
if (config_csdev)
|
||||||
|
cscfg_csdev_disable_config(config_csdev);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config);
|
||||||
|
|
||||||
|
/* Initialise system configuration management device. */
|
||||||
|
|
||||||
|
struct device *cscfg_device(void)
|
||||||
|
{
|
||||||
|
return cscfg_mgr ? &cscfg_mgr->dev : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Must have a release function or the kernel will complain on module unload */
|
||||||
|
static void cscfg_dev_release(struct device *dev)
|
||||||
|
{
|
||||||
|
kfree(cscfg_mgr);
|
||||||
|
cscfg_mgr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a device is needed to "own" some kernel elements such as sysfs entries. */
|
||||||
|
static int cscfg_create_device(void)
|
||||||
|
{
|
||||||
|
struct device *dev;
|
||||||
|
int err = -ENOMEM;
|
||||||
|
|
||||||
|
mutex_lock(&cscfg_mutex);
|
||||||
|
if (cscfg_mgr) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto create_dev_exit_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
cscfg_mgr = kzalloc(sizeof(struct cscfg_manager), GFP_KERNEL);
|
||||||
|
if (!cscfg_mgr)
|
||||||
|
goto create_dev_exit_unlock;
|
||||||
|
|
||||||
|
/* setup the device */
|
||||||
|
dev = cscfg_device();
|
||||||
|
dev->release = cscfg_dev_release;
|
||||||
|
dev->init_name = "cs_system_cfg";
|
||||||
|
|
||||||
|
err = device_register(dev);
|
||||||
|
if (err)
|
||||||
|
cscfg_dev_release(dev);
|
||||||
|
|
||||||
|
create_dev_exit_unlock:
|
||||||
|
mutex_unlock(&cscfg_mutex);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cscfg_clear_device(void)
|
||||||
|
{
|
||||||
|
struct cscfg_config_desc *cfg_desc;
|
||||||
|
|
||||||
|
mutex_lock(&cscfg_mutex);
|
||||||
|
list_for_each_entry(cfg_desc, &cscfg_mgr->config_desc_list, item) {
|
||||||
|
etm_perf_del_symlink_cscfg(cfg_desc);
|
||||||
|
}
|
||||||
|
cscfg_configfs_release(cscfg_mgr);
|
||||||
|
device_unregister(cscfg_device());
|
||||||
|
mutex_unlock(&cscfg_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialise system config management API device */
|
||||||
|
int __init cscfg_init(void)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
err = cscfg_create_device();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = cscfg_configfs_init(cscfg_mgr);
|
||||||
|
if (err)
|
||||||
|
goto exit_err;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);
|
||||||
|
INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list);
|
||||||
|
INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
|
||||||
|
atomic_set(&cscfg_mgr->sys_active_cnt, 0);
|
||||||
|
|
||||||
|
/* preload built-in configurations */
|
||||||
|
err = cscfg_preload();
|
||||||
|
if (err)
|
||||||
|
goto exit_err;
|
||||||
|
|
||||||
|
dev_info(cscfg_device(), "CoreSight Configuration manager initialised");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
exit_err:
|
||||||
|
cscfg_clear_device();
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cscfg_exit(void)
|
||||||
|
{
|
||||||
|
cscfg_clear_device();
|
||||||
|
}
|
||||||
81
drivers/hwtracing/coresight/coresight-syscfg.h
Normal file
81
drivers/hwtracing/coresight/coresight-syscfg.h
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
/*
|
||||||
|
* Coresight system configuration driver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CORESIGHT_SYSCFG_H
|
||||||
|
#define CORESIGHT_SYSCFG_H
|
||||||
|
|
||||||
|
#include <linux/configfs.h>
|
||||||
|
#include <linux/coresight.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
|
||||||
|
#include "coresight-config.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* System configuration manager device.
|
||||||
|
*
|
||||||
|
* Contains lists of the loaded configurations and features, plus a list of CoreSight devices
|
||||||
|
* registered with the system as supporting configuration management.
|
||||||
|
*
|
||||||
|
* Need a device to 'own' some coresight system wide sysfs entries in
|
||||||
|
* perf events, configfs etc.
|
||||||
|
*
|
||||||
|
* @dev: The device.
|
||||||
|
* @csdev_desc_list: List of coresight devices registered with the configuration manager.
|
||||||
|
* @feat_desc_list: List of feature descriptors to load into registered devices.
|
||||||
|
* @config_desc_list: List of system configuration descriptors to load into registered devices.
|
||||||
|
* @sys_active_cnt: Total number of active config descriptor references.
|
||||||
|
* @cfgfs_subsys: configfs subsystem used to manage configurations.
|
||||||
|
*/
|
||||||
|
struct cscfg_manager {
|
||||||
|
struct device dev;
|
||||||
|
struct list_head csdev_desc_list;
|
||||||
|
struct list_head feat_desc_list;
|
||||||
|
struct list_head config_desc_list;
|
||||||
|
atomic_t sys_active_cnt;
|
||||||
|
struct configfs_subsystem cfgfs_subsys;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* get reference to dev in cscfg_manager */
|
||||||
|
struct device *cscfg_device(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List entry for Coresight devices that are registered as supporting complex
|
||||||
|
* config operations.
|
||||||
|
*
|
||||||
|
* @csdev: The registered device.
|
||||||
|
* @match_flags: The matching type information for adding features.
|
||||||
|
* @ops: Operations supported by the registered device.
|
||||||
|
* @item: list entry.
|
||||||
|
*/
|
||||||
|
struct cscfg_registered_csdev {
|
||||||
|
struct coresight_device *csdev;
|
||||||
|
u32 match_flags;
|
||||||
|
struct cscfg_csdev_feat_ops ops;
|
||||||
|
struct list_head item;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* internal core operations for cscfg */
|
||||||
|
int __init cscfg_init(void);
|
||||||
|
void cscfg_exit(void);
|
||||||
|
int cscfg_preload(void);
|
||||||
|
const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name);
|
||||||
|
int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
|
||||||
|
int param_idx, u64 value);
|
||||||
|
|
||||||
|
|
||||||
|
/* syscfg manager external API */
|
||||||
|
int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
|
||||||
|
struct cscfg_feature_desc **feat_descs);
|
||||||
|
int cscfg_register_csdev(struct coresight_device *csdev, u32 match_flags,
|
||||||
|
struct cscfg_csdev_feat_ops *ops);
|
||||||
|
void cscfg_unregister_csdev(struct coresight_device *csdev);
|
||||||
|
int cscfg_activate_config(unsigned long cfg_hash);
|
||||||
|
void cscfg_deactivate_config(unsigned long cfg_hash);
|
||||||
|
void cscfg_csdev_reset_feats(struct coresight_device *csdev);
|
||||||
|
int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
|
||||||
|
unsigned long cfg_hash, int preset);
|
||||||
|
void cscfg_csdev_disable_active_config(struct coresight_device *csdev);
|
||||||
|
|
||||||
|
#endif /* CORESIGHT_SYSCFG_H */
|
||||||
@@ -959,6 +959,9 @@ EXPORT_SYMBOL_GPL(icc_link_destroy);
|
|||||||
*/
|
*/
|
||||||
void icc_node_add(struct icc_node *node, struct icc_provider *provider)
|
void icc_node_add(struct icc_node *node, struct icc_provider *provider)
|
||||||
{
|
{
|
||||||
|
if (WARN_ON(node->provider))
|
||||||
|
return;
|
||||||
|
|
||||||
mutex_lock(&icc_lock);
|
mutex_lock(&icc_lock);
|
||||||
|
|
||||||
node->provider = provider;
|
node->provider = provider;
|
||||||
|
|||||||
@@ -83,6 +83,15 @@ config INTERCONNECT_QCOM_SC7280
|
|||||||
This is a driver for the Qualcomm Network-on-Chip on sc7280-based
|
This is a driver for the Qualcomm Network-on-Chip on sc7280-based
|
||||||
platforms.
|
platforms.
|
||||||
|
|
||||||
|
config INTERCONNECT_QCOM_SC8180X
|
||||||
|
tristate "Qualcomm SC8180X interconnect driver"
|
||||||
|
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
|
||||||
|
select INTERCONNECT_QCOM_RPMH
|
||||||
|
select INTERCONNECT_QCOM_BCM_VOTER
|
||||||
|
help
|
||||||
|
This is a driver for the Qualcomm Network-on-Chip on sc8180x-based
|
||||||
|
platforms.
|
||||||
|
|
||||||
config INTERCONNECT_QCOM_SDM660
|
config INTERCONNECT_QCOM_SDM660
|
||||||
tristate "Qualcomm SDM660 interconnect driver"
|
tristate "Qualcomm SDM660 interconnect driver"
|
||||||
depends on INTERCONNECT_QCOM
|
depends on INTERCONNECT_QCOM
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ qnoc-qcs404-objs := qcs404.o
|
|||||||
icc-rpmh-obj := icc-rpmh.o
|
icc-rpmh-obj := icc-rpmh.o
|
||||||
qnoc-sc7180-objs := sc7180.o
|
qnoc-sc7180-objs := sc7180.o
|
||||||
qnoc-sc7280-objs := sc7280.o
|
qnoc-sc7280-objs := sc7280.o
|
||||||
|
qnoc-sc8180x-objs := sc8180x.o
|
||||||
qnoc-sdm660-objs := sdm660.o
|
qnoc-sdm660-objs := sdm660.o
|
||||||
qnoc-sdm845-objs := sdm845.o
|
qnoc-sdm845-objs := sdm845.o
|
||||||
qnoc-sdx55-objs := sdx55.o
|
qnoc-sdx55-objs := sdx55.o
|
||||||
@@ -26,6 +27,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o
|
|||||||
obj-$(CONFIG_INTERCONNECT_QCOM_RPMH) += icc-rpmh.o
|
obj-$(CONFIG_INTERCONNECT_QCOM_RPMH) += icc-rpmh.o
|
||||||
obj-$(CONFIG_INTERCONNECT_QCOM_SC7180) += qnoc-sc7180.o
|
obj-$(CONFIG_INTERCONNECT_QCOM_SC7180) += qnoc-sc7180.o
|
||||||
obj-$(CONFIG_INTERCONNECT_QCOM_SC7280) += qnoc-sc7280.o
|
obj-$(CONFIG_INTERCONNECT_QCOM_SC7280) += qnoc-sc7280.o
|
||||||
|
obj-$(CONFIG_INTERCONNECT_QCOM_SC8180X) += qnoc-sc8180x.o
|
||||||
obj-$(CONFIG_INTERCONNECT_QCOM_SDM660) += qnoc-sdm660.o
|
obj-$(CONFIG_INTERCONNECT_QCOM_SDM660) += qnoc-sdm660.o
|
||||||
obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o
|
obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o
|
||||||
obj-$(CONFIG_INTERCONNECT_QCOM_SDX55) += qnoc-sdx55.o
|
obj-$(CONFIG_INTERCONNECT_QCOM_SDX55) += qnoc-sdx55.o
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <linux/interconnect-provider.h>
|
#include <linux/interconnect-provider.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "bcm-voter.h"
|
#include "bcm-voter.h"
|
||||||
@@ -182,4 +183,96 @@ int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(qcom_icc_bcm_init);
|
EXPORT_SYMBOL_GPL(qcom_icc_bcm_init);
|
||||||
|
|
||||||
|
int qcom_icc_rpmh_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
const struct qcom_icc_desc *desc;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct icc_onecell_data *data;
|
||||||
|
struct icc_provider *provider;
|
||||||
|
struct qcom_icc_node **qnodes, *qn;
|
||||||
|
struct qcom_icc_provider *qp;
|
||||||
|
struct icc_node *node;
|
||||||
|
size_t num_nodes, i, j;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
desc = of_device_get_match_data(dev);
|
||||||
|
if (!desc)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
qnodes = desc->nodes;
|
||||||
|
num_nodes = desc->num_nodes;
|
||||||
|
|
||||||
|
qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
|
||||||
|
if (!qp)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes), GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
provider = &qp->provider;
|
||||||
|
provider->dev = dev;
|
||||||
|
provider->set = qcom_icc_set;
|
||||||
|
provider->pre_aggregate = qcom_icc_pre_aggregate;
|
||||||
|
provider->aggregate = qcom_icc_aggregate;
|
||||||
|
provider->xlate_extended = qcom_icc_xlate_extended;
|
||||||
|
INIT_LIST_HEAD(&provider->nodes);
|
||||||
|
provider->data = data;
|
||||||
|
|
||||||
|
qp->dev = dev;
|
||||||
|
qp->bcms = desc->bcms;
|
||||||
|
qp->num_bcms = desc->num_bcms;
|
||||||
|
|
||||||
|
qp->voter = of_bcm_voter_get(qp->dev, NULL);
|
||||||
|
if (IS_ERR(qp->voter))
|
||||||
|
return PTR_ERR(qp->voter);
|
||||||
|
|
||||||
|
ret = icc_provider_add(provider);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (i = 0; i < qp->num_bcms; i++)
|
||||||
|
qcom_icc_bcm_init(qp->bcms[i], dev);
|
||||||
|
|
||||||
|
for (i = 0; i < num_nodes; i++) {
|
||||||
|
qn = qnodes[i];
|
||||||
|
if (!qn)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
node = icc_node_create(qn->id);
|
||||||
|
if (IS_ERR(node)) {
|
||||||
|
ret = PTR_ERR(node);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->name = qn->name;
|
||||||
|
node->data = qn;
|
||||||
|
icc_node_add(node, provider);
|
||||||
|
|
||||||
|
for (j = 0; j < qn->num_links; j++)
|
||||||
|
icc_link_create(node, qn->links[j]);
|
||||||
|
|
||||||
|
data->nodes[i] = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->num_nodes = num_nodes;
|
||||||
|
platform_set_drvdata(pdev, qp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
|
icc_nodes_remove(provider);
|
||||||
|
icc_provider_del(provider);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(qcom_icc_rpmh_probe);
|
||||||
|
|
||||||
|
int qcom_icc_rpmh_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
icc_nodes_remove(&qp->provider);
|
||||||
|
return icc_provider_del(&qp->provider);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(qcom_icc_rpmh_remove);
|
||||||
|
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|||||||
@@ -134,5 +134,7 @@ int qcom_icc_set(struct icc_node *src, struct icc_node *dst);
|
|||||||
struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data);
|
struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data);
|
||||||
int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev);
|
int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev);
|
||||||
void qcom_icc_pre_aggregate(struct icc_node *node);
|
void qcom_icc_pre_aggregate(struct icc_node *node);
|
||||||
|
int qcom_icc_rpmh_probe(struct platform_device *pdev);
|
||||||
|
int qcom_icc_rpmh_remove(struct platform_device *pdev);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <dt-bindings/interconnect/qcom,osm-l3.h>
|
#include <dt-bindings/interconnect/qcom,osm-l3.h>
|
||||||
|
|
||||||
#include "sc7180.h"
|
#include "sc7180.h"
|
||||||
|
#include "sc8180x.h"
|
||||||
#include "sdm845.h"
|
#include "sdm845.h"
|
||||||
#include "sm8150.h"
|
#include "sm8150.h"
|
||||||
#include "sm8250.h"
|
#include "sm8250.h"
|
||||||
@@ -37,7 +38,7 @@
|
|||||||
|
|
||||||
#define OSM_L3_MAX_LINKS 1
|
#define OSM_L3_MAX_LINKS 1
|
||||||
|
|
||||||
#define to_qcom_provider(_provider) \
|
#define to_osm_l3_provider(_provider) \
|
||||||
container_of(_provider, struct qcom_osm_l3_icc_provider, provider)
|
container_of(_provider, struct qcom_osm_l3_icc_provider, provider)
|
||||||
|
|
||||||
struct qcom_osm_l3_icc_provider {
|
struct qcom_osm_l3_icc_provider {
|
||||||
@@ -49,14 +50,14 @@ struct qcom_osm_l3_icc_provider {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct qcom_icc_node - Qualcomm specific interconnect nodes
|
* struct qcom_osm_l3_node - Qualcomm specific interconnect nodes
|
||||||
* @name: the node name used in debugfs
|
* @name: the node name used in debugfs
|
||||||
* @links: an array of nodes where we can go next while traversing
|
* @links: an array of nodes where we can go next while traversing
|
||||||
* @id: a unique node identifier
|
* @id: a unique node identifier
|
||||||
* @num_links: the total number of @links
|
* @num_links: the total number of @links
|
||||||
* @buswidth: width of the interconnect between a node and the bus
|
* @buswidth: width of the interconnect between a node and the bus
|
||||||
*/
|
*/
|
||||||
struct qcom_icc_node {
|
struct qcom_osm_l3_node {
|
||||||
const char *name;
|
const char *name;
|
||||||
u16 links[OSM_L3_MAX_LINKS];
|
u16 links[OSM_L3_MAX_LINKS];
|
||||||
u16 id;
|
u16 id;
|
||||||
@@ -64,8 +65,8 @@ struct qcom_icc_node {
|
|||||||
u16 buswidth;
|
u16 buswidth;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct qcom_icc_desc {
|
struct qcom_osm_l3_desc {
|
||||||
const struct qcom_icc_node **nodes;
|
const struct qcom_osm_l3_node **nodes;
|
||||||
size_t num_nodes;
|
size_t num_nodes;
|
||||||
unsigned int lut_row_size;
|
unsigned int lut_row_size;
|
||||||
unsigned int reg_freq_lut;
|
unsigned int reg_freq_lut;
|
||||||
@@ -73,7 +74,7 @@ struct qcom_icc_desc {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define DEFINE_QNODE(_name, _id, _buswidth, ...) \
|
#define DEFINE_QNODE(_name, _id, _buswidth, ...) \
|
||||||
static const struct qcom_icc_node _name = { \
|
static const struct qcom_osm_l3_node _name = { \
|
||||||
.name = #_name, \
|
.name = #_name, \
|
||||||
.id = _id, \
|
.id = _id, \
|
||||||
.buswidth = _buswidth, \
|
.buswidth = _buswidth, \
|
||||||
@@ -84,12 +85,12 @@ struct qcom_icc_desc {
|
|||||||
DEFINE_QNODE(sdm845_osm_apps_l3, SDM845_MASTER_OSM_L3_APPS, 16, SDM845_SLAVE_OSM_L3);
|
DEFINE_QNODE(sdm845_osm_apps_l3, SDM845_MASTER_OSM_L3_APPS, 16, SDM845_SLAVE_OSM_L3);
|
||||||
DEFINE_QNODE(sdm845_osm_l3, SDM845_SLAVE_OSM_L3, 16);
|
DEFINE_QNODE(sdm845_osm_l3, SDM845_SLAVE_OSM_L3, 16);
|
||||||
|
|
||||||
static const struct qcom_icc_node *sdm845_osm_l3_nodes[] = {
|
static const struct qcom_osm_l3_node *sdm845_osm_l3_nodes[] = {
|
||||||
[MASTER_OSM_L3_APPS] = &sdm845_osm_apps_l3,
|
[MASTER_OSM_L3_APPS] = &sdm845_osm_apps_l3,
|
||||||
[SLAVE_OSM_L3] = &sdm845_osm_l3,
|
[SLAVE_OSM_L3] = &sdm845_osm_l3,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct qcom_icc_desc sdm845_icc_osm_l3 = {
|
static const struct qcom_osm_l3_desc sdm845_icc_osm_l3 = {
|
||||||
.nodes = sdm845_osm_l3_nodes,
|
.nodes = sdm845_osm_l3_nodes,
|
||||||
.num_nodes = ARRAY_SIZE(sdm845_osm_l3_nodes),
|
.num_nodes = ARRAY_SIZE(sdm845_osm_l3_nodes),
|
||||||
.lut_row_size = OSM_LUT_ROW_SIZE,
|
.lut_row_size = OSM_LUT_ROW_SIZE,
|
||||||
@@ -100,12 +101,12 @@ static const struct qcom_icc_desc sdm845_icc_osm_l3 = {
|
|||||||
DEFINE_QNODE(sc7180_osm_apps_l3, SC7180_MASTER_OSM_L3_APPS, 16, SC7180_SLAVE_OSM_L3);
|
DEFINE_QNODE(sc7180_osm_apps_l3, SC7180_MASTER_OSM_L3_APPS, 16, SC7180_SLAVE_OSM_L3);
|
||||||
DEFINE_QNODE(sc7180_osm_l3, SC7180_SLAVE_OSM_L3, 16);
|
DEFINE_QNODE(sc7180_osm_l3, SC7180_SLAVE_OSM_L3, 16);
|
||||||
|
|
||||||
static const struct qcom_icc_node *sc7180_osm_l3_nodes[] = {
|
static const struct qcom_osm_l3_node *sc7180_osm_l3_nodes[] = {
|
||||||
[MASTER_OSM_L3_APPS] = &sc7180_osm_apps_l3,
|
[MASTER_OSM_L3_APPS] = &sc7180_osm_apps_l3,
|
||||||
[SLAVE_OSM_L3] = &sc7180_osm_l3,
|
[SLAVE_OSM_L3] = &sc7180_osm_l3,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct qcom_icc_desc sc7180_icc_osm_l3 = {
|
static const struct qcom_osm_l3_desc sc7180_icc_osm_l3 = {
|
||||||
.nodes = sc7180_osm_l3_nodes,
|
.nodes = sc7180_osm_l3_nodes,
|
||||||
.num_nodes = ARRAY_SIZE(sc7180_osm_l3_nodes),
|
.num_nodes = ARRAY_SIZE(sc7180_osm_l3_nodes),
|
||||||
.lut_row_size = OSM_LUT_ROW_SIZE,
|
.lut_row_size = OSM_LUT_ROW_SIZE,
|
||||||
@@ -113,15 +114,31 @@ static const struct qcom_icc_desc sc7180_icc_osm_l3 = {
|
|||||||
.reg_perf_state = OSM_REG_PERF_STATE,
|
.reg_perf_state = OSM_REG_PERF_STATE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DEFINE_QNODE(sc8180x_osm_apps_l3, SC8180X_MASTER_OSM_L3_APPS, 32, SC8180X_SLAVE_OSM_L3);
|
||||||
|
DEFINE_QNODE(sc8180x_osm_l3, SC8180X_SLAVE_OSM_L3, 32);
|
||||||
|
|
||||||
|
static const struct qcom_osm_l3_node *sc8180x_osm_l3_nodes[] = {
|
||||||
|
[MASTER_OSM_L3_APPS] = &sc8180x_osm_apps_l3,
|
||||||
|
[SLAVE_OSM_L3] = &sc8180x_osm_l3,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_osm_l3_desc sc8180x_icc_osm_l3 = {
|
||||||
|
.nodes = sc8180x_osm_l3_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(sc8180x_osm_l3_nodes),
|
||||||
|
.lut_row_size = OSM_LUT_ROW_SIZE,
|
||||||
|
.reg_freq_lut = OSM_REG_FREQ_LUT,
|
||||||
|
.reg_perf_state = OSM_REG_PERF_STATE,
|
||||||
|
};
|
||||||
|
|
||||||
DEFINE_QNODE(sm8150_osm_apps_l3, SM8150_MASTER_OSM_L3_APPS, 32, SM8150_SLAVE_OSM_L3);
|
DEFINE_QNODE(sm8150_osm_apps_l3, SM8150_MASTER_OSM_L3_APPS, 32, SM8150_SLAVE_OSM_L3);
|
||||||
DEFINE_QNODE(sm8150_osm_l3, SM8150_SLAVE_OSM_L3, 32);
|
DEFINE_QNODE(sm8150_osm_l3, SM8150_SLAVE_OSM_L3, 32);
|
||||||
|
|
||||||
static const struct qcom_icc_node *sm8150_osm_l3_nodes[] = {
|
static const struct qcom_osm_l3_node *sm8150_osm_l3_nodes[] = {
|
||||||
[MASTER_OSM_L3_APPS] = &sm8150_osm_apps_l3,
|
[MASTER_OSM_L3_APPS] = &sm8150_osm_apps_l3,
|
||||||
[SLAVE_OSM_L3] = &sm8150_osm_l3,
|
[SLAVE_OSM_L3] = &sm8150_osm_l3,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct qcom_icc_desc sm8150_icc_osm_l3 = {
|
static const struct qcom_osm_l3_desc sm8150_icc_osm_l3 = {
|
||||||
.nodes = sm8150_osm_l3_nodes,
|
.nodes = sm8150_osm_l3_nodes,
|
||||||
.num_nodes = ARRAY_SIZE(sm8150_osm_l3_nodes),
|
.num_nodes = ARRAY_SIZE(sm8150_osm_l3_nodes),
|
||||||
.lut_row_size = OSM_LUT_ROW_SIZE,
|
.lut_row_size = OSM_LUT_ROW_SIZE,
|
||||||
@@ -132,12 +149,12 @@ static const struct qcom_icc_desc sm8150_icc_osm_l3 = {
|
|||||||
DEFINE_QNODE(sm8250_epss_apps_l3, SM8250_MASTER_EPSS_L3_APPS, 32, SM8250_SLAVE_EPSS_L3);
|
DEFINE_QNODE(sm8250_epss_apps_l3, SM8250_MASTER_EPSS_L3_APPS, 32, SM8250_SLAVE_EPSS_L3);
|
||||||
DEFINE_QNODE(sm8250_epss_l3, SM8250_SLAVE_EPSS_L3, 32);
|
DEFINE_QNODE(sm8250_epss_l3, SM8250_SLAVE_EPSS_L3, 32);
|
||||||
|
|
||||||
static const struct qcom_icc_node *sm8250_epss_l3_nodes[] = {
|
static const struct qcom_osm_l3_node *sm8250_epss_l3_nodes[] = {
|
||||||
[MASTER_EPSS_L3_APPS] = &sm8250_epss_apps_l3,
|
[MASTER_EPSS_L3_APPS] = &sm8250_epss_apps_l3,
|
||||||
[SLAVE_EPSS_L3_SHARED] = &sm8250_epss_l3,
|
[SLAVE_EPSS_L3_SHARED] = &sm8250_epss_l3,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct qcom_icc_desc sm8250_icc_epss_l3 = {
|
static const struct qcom_osm_l3_desc sm8250_icc_epss_l3 = {
|
||||||
.nodes = sm8250_epss_l3_nodes,
|
.nodes = sm8250_epss_l3_nodes,
|
||||||
.num_nodes = ARRAY_SIZE(sm8250_epss_l3_nodes),
|
.num_nodes = ARRAY_SIZE(sm8250_epss_l3_nodes),
|
||||||
.lut_row_size = EPSS_LUT_ROW_SIZE,
|
.lut_row_size = EPSS_LUT_ROW_SIZE,
|
||||||
@@ -145,11 +162,11 @@ static const struct qcom_icc_desc sm8250_icc_epss_l3 = {
|
|||||||
.reg_perf_state = EPSS_REG_PERF_STATE,
|
.reg_perf_state = EPSS_REG_PERF_STATE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
|
static int qcom_osm_l3_set(struct icc_node *src, struct icc_node *dst)
|
||||||
{
|
{
|
||||||
struct qcom_osm_l3_icc_provider *qp;
|
struct qcom_osm_l3_icc_provider *qp;
|
||||||
struct icc_provider *provider;
|
struct icc_provider *provider;
|
||||||
const struct qcom_icc_node *qn;
|
const struct qcom_osm_l3_node *qn;
|
||||||
struct icc_node *n;
|
struct icc_node *n;
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
u32 agg_peak = 0;
|
u32 agg_peak = 0;
|
||||||
@@ -158,7 +175,7 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
|
|||||||
|
|
||||||
qn = src->data;
|
qn = src->data;
|
||||||
provider = src->provider;
|
provider = src->provider;
|
||||||
qp = to_qcom_provider(provider);
|
qp = to_osm_l3_provider(provider);
|
||||||
|
|
||||||
list_for_each_entry(n, &provider->nodes, node_list)
|
list_for_each_entry(n, &provider->nodes, node_list)
|
||||||
provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
|
provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
|
||||||
@@ -191,10 +208,10 @@ static int qcom_osm_l3_probe(struct platform_device *pdev)
|
|||||||
u32 info, src, lval, i, prev_freq = 0, freq;
|
u32 info, src, lval, i, prev_freq = 0, freq;
|
||||||
static unsigned long hw_rate, xo_rate;
|
static unsigned long hw_rate, xo_rate;
|
||||||
struct qcom_osm_l3_icc_provider *qp;
|
struct qcom_osm_l3_icc_provider *qp;
|
||||||
const struct qcom_icc_desc *desc;
|
const struct qcom_osm_l3_desc *desc;
|
||||||
struct icc_onecell_data *data;
|
struct icc_onecell_data *data;
|
||||||
struct icc_provider *provider;
|
struct icc_provider *provider;
|
||||||
const struct qcom_icc_node **qnodes;
|
const struct qcom_osm_l3_node **qnodes;
|
||||||
struct icc_node *node;
|
struct icc_node *node;
|
||||||
size_t num_nodes;
|
size_t num_nodes;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
@@ -264,7 +281,7 @@ static int qcom_osm_l3_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
provider = &qp->provider;
|
provider = &qp->provider;
|
||||||
provider->dev = &pdev->dev;
|
provider->dev = &pdev->dev;
|
||||||
provider->set = qcom_icc_set;
|
provider->set = qcom_osm_l3_set;
|
||||||
provider->aggregate = icc_std_aggregate;
|
provider->aggregate = icc_std_aggregate;
|
||||||
provider->xlate = of_icc_xlate_onecell;
|
provider->xlate = of_icc_xlate_onecell;
|
||||||
INIT_LIST_HEAD(&provider->nodes);
|
INIT_LIST_HEAD(&provider->nodes);
|
||||||
@@ -286,7 +303,7 @@ static int qcom_osm_l3_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
node->name = qnodes[i]->name;
|
node->name = qnodes[i]->name;
|
||||||
/* Cast away const and add it back in qcom_icc_set() */
|
/* Cast away const and add it back in qcom_osm_l3_set() */
|
||||||
node->data = (void *)qnodes[i];
|
node->data = (void *)qnodes[i];
|
||||||
icc_node_add(node, provider);
|
icc_node_add(node, provider);
|
||||||
|
|
||||||
@@ -311,6 +328,7 @@ static const struct of_device_id osm_l3_of_match[] = {
|
|||||||
{ .compatible = "qcom,sc7180-osm-l3", .data = &sc7180_icc_osm_l3 },
|
{ .compatible = "qcom,sc7180-osm-l3", .data = &sc7180_icc_osm_l3 },
|
||||||
{ .compatible = "qcom,sdm845-osm-l3", .data = &sdm845_icc_osm_l3 },
|
{ .compatible = "qcom,sdm845-osm-l3", .data = &sdm845_icc_osm_l3 },
|
||||||
{ .compatible = "qcom,sm8150-osm-l3", .data = &sm8150_icc_osm_l3 },
|
{ .compatible = "qcom,sm8150-osm-l3", .data = &sm8150_icc_osm_l3 },
|
||||||
|
{ .compatible = "qcom,sc8180x-osm-l3", .data = &sc8180x_icc_osm_l3 },
|
||||||
{ .compatible = "qcom,sm8250-epss-l3", .data = &sm8250_icc_epss_l3 },
|
{ .compatible = "qcom,sm8250-epss-l3", .data = &sm8250_icc_epss_l3 },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -504,98 +504,6 @@ static struct qcom_icc_desc sc7180_system_noc = {
|
|||||||
.num_bcms = ARRAY_SIZE(system_noc_bcms),
|
.num_bcms = ARRAY_SIZE(system_noc_bcms),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int qnoc_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
const struct qcom_icc_desc *desc;
|
|
||||||
struct icc_onecell_data *data;
|
|
||||||
struct icc_provider *provider;
|
|
||||||
struct qcom_icc_node **qnodes;
|
|
||||||
struct qcom_icc_provider *qp;
|
|
||||||
struct icc_node *node;
|
|
||||||
size_t num_nodes, i;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
desc = device_get_match_data(&pdev->dev);
|
|
||||||
if (!desc)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
qnodes = desc->nodes;
|
|
||||||
num_nodes = desc->num_nodes;
|
|
||||||
|
|
||||||
qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
|
|
||||||
if (!qp)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL);
|
|
||||||
if (!data)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
provider = &qp->provider;
|
|
||||||
provider->dev = &pdev->dev;
|
|
||||||
provider->set = qcom_icc_set;
|
|
||||||
provider->pre_aggregate = qcom_icc_pre_aggregate;
|
|
||||||
provider->aggregate = qcom_icc_aggregate;
|
|
||||||
provider->xlate_extended = qcom_icc_xlate_extended;
|
|
||||||
INIT_LIST_HEAD(&provider->nodes);
|
|
||||||
provider->data = data;
|
|
||||||
|
|
||||||
qp->dev = &pdev->dev;
|
|
||||||
qp->bcms = desc->bcms;
|
|
||||||
qp->num_bcms = desc->num_bcms;
|
|
||||||
|
|
||||||
qp->voter = of_bcm_voter_get(qp->dev, NULL);
|
|
||||||
if (IS_ERR(qp->voter))
|
|
||||||
return PTR_ERR(qp->voter);
|
|
||||||
|
|
||||||
ret = icc_provider_add(provider);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "error adding interconnect provider\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < qp->num_bcms; i++)
|
|
||||||
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
|
|
||||||
|
|
||||||
for (i = 0; i < num_nodes; i++) {
|
|
||||||
size_t j;
|
|
||||||
|
|
||||||
if (!qnodes[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
node = icc_node_create(qnodes[i]->id);
|
|
||||||
if (IS_ERR(node)) {
|
|
||||||
ret = PTR_ERR(node);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->name = qnodes[i]->name;
|
|
||||||
node->data = qnodes[i];
|
|
||||||
icc_node_add(node, provider);
|
|
||||||
|
|
||||||
for (j = 0; j < qnodes[i]->num_links; j++)
|
|
||||||
icc_link_create(node, qnodes[i]->links[j]);
|
|
||||||
|
|
||||||
data->nodes[i] = node;
|
|
||||||
}
|
|
||||||
data->num_nodes = num_nodes;
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, qp);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
err:
|
|
||||||
icc_nodes_remove(provider);
|
|
||||||
icc_provider_del(provider);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int qnoc_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
icc_nodes_remove(&qp->provider);
|
|
||||||
return icc_provider_del(&qp->provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct of_device_id qnoc_of_match[] = {
|
static const struct of_device_id qnoc_of_match[] = {
|
||||||
{ .compatible = "qcom,sc7180-aggre1-noc",
|
{ .compatible = "qcom,sc7180-aggre1-noc",
|
||||||
.data = &sc7180_aggre1_noc},
|
.data = &sc7180_aggre1_noc},
|
||||||
@@ -628,8 +536,8 @@ static const struct of_device_id qnoc_of_match[] = {
|
|||||||
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
||||||
|
|
||||||
static struct platform_driver qnoc_driver = {
|
static struct platform_driver qnoc_driver = {
|
||||||
.probe = qnoc_probe,
|
.probe = qcom_icc_rpmh_probe,
|
||||||
.remove = qnoc_remove,
|
.remove = qcom_icc_rpmh_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "qnoc-sc7180",
|
.name = "qnoc-sc7180",
|
||||||
.of_match_table = qnoc_of_match,
|
.of_match_table = qnoc_of_match,
|
||||||
|
|||||||
@@ -1802,98 +1802,6 @@ static struct qcom_icc_desc sc7280_system_noc = {
|
|||||||
.num_bcms = ARRAY_SIZE(system_noc_bcms),
|
.num_bcms = ARRAY_SIZE(system_noc_bcms),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int qnoc_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
const struct qcom_icc_desc *desc;
|
|
||||||
struct icc_onecell_data *data;
|
|
||||||
struct icc_provider *provider;
|
|
||||||
struct qcom_icc_node **qnodes;
|
|
||||||
struct qcom_icc_provider *qp;
|
|
||||||
struct icc_node *node;
|
|
||||||
size_t num_nodes, i;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
desc = device_get_match_data(&pdev->dev);
|
|
||||||
if (!desc)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
qnodes = desc->nodes;
|
|
||||||
num_nodes = desc->num_nodes;
|
|
||||||
|
|
||||||
qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
|
|
||||||
if (!qp)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL);
|
|
||||||
if (!data)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
provider = &qp->provider;
|
|
||||||
provider->dev = &pdev->dev;
|
|
||||||
provider->set = qcom_icc_set;
|
|
||||||
provider->pre_aggregate = qcom_icc_pre_aggregate;
|
|
||||||
provider->aggregate = qcom_icc_aggregate;
|
|
||||||
provider->xlate_extended = qcom_icc_xlate_extended;
|
|
||||||
INIT_LIST_HEAD(&provider->nodes);
|
|
||||||
provider->data = data;
|
|
||||||
|
|
||||||
qp->dev = &pdev->dev;
|
|
||||||
qp->bcms = desc->bcms;
|
|
||||||
qp->num_bcms = desc->num_bcms;
|
|
||||||
|
|
||||||
qp->voter = of_bcm_voter_get(qp->dev, NULL);
|
|
||||||
if (IS_ERR(qp->voter))
|
|
||||||
return PTR_ERR(qp->voter);
|
|
||||||
|
|
||||||
ret = icc_provider_add(provider);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "error adding interconnect provider\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < qp->num_bcms; i++)
|
|
||||||
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
|
|
||||||
|
|
||||||
for (i = 0; i < num_nodes; i++) {
|
|
||||||
size_t j;
|
|
||||||
|
|
||||||
if (!qnodes[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
node = icc_node_create(qnodes[i]->id);
|
|
||||||
if (IS_ERR(node)) {
|
|
||||||
ret = PTR_ERR(node);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->name = qnodes[i]->name;
|
|
||||||
node->data = qnodes[i];
|
|
||||||
icc_node_add(node, provider);
|
|
||||||
|
|
||||||
for (j = 0; j < qnodes[i]->num_links; j++)
|
|
||||||
icc_link_create(node, qnodes[i]->links[j]);
|
|
||||||
|
|
||||||
data->nodes[i] = node;
|
|
||||||
}
|
|
||||||
data->num_nodes = num_nodes;
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, qp);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
err:
|
|
||||||
icc_nodes_remove(provider);
|
|
||||||
icc_provider_del(provider);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int qnoc_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
icc_nodes_remove(&qp->provider);
|
|
||||||
return icc_provider_del(&qp->provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct of_device_id qnoc_of_match[] = {
|
static const struct of_device_id qnoc_of_match[] = {
|
||||||
{ .compatible = "qcom,sc7280-aggre1-noc",
|
{ .compatible = "qcom,sc7280-aggre1-noc",
|
||||||
.data = &sc7280_aggre1_noc},
|
.data = &sc7280_aggre1_noc},
|
||||||
@@ -1924,8 +1832,8 @@ static const struct of_device_id qnoc_of_match[] = {
|
|||||||
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
||||||
|
|
||||||
static struct platform_driver qnoc_driver = {
|
static struct platform_driver qnoc_driver = {
|
||||||
.probe = qnoc_probe,
|
.probe = qcom_icc_rpmh_probe,
|
||||||
.remove = qnoc_remove,
|
.remove = qcom_icc_rpmh_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "qnoc-sc7280",
|
.name = "qnoc-sc7280",
|
||||||
.of_match_table = qnoc_of_match,
|
.of_match_table = qnoc_of_match,
|
||||||
|
|||||||
626
drivers/interconnect/qcom/sc8180x.c
Normal file
626
drivers/interconnect/qcom/sc8180x.c
Normal file
@@ -0,0 +1,626 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||||
|
* Copyright (c) 2021, Linaro Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/interconnect-provider.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
|
||||||
|
#include <dt-bindings/interconnect/qcom,sc8180x.h>
|
||||||
|
|
||||||
|
#include "bcm-voter.h"
|
||||||
|
#include "icc-rpmh.h"
|
||||||
|
#include "sc8180x.h"
|
||||||
|
|
||||||
|
DEFINE_QNODE(mas_qhm_a1noc_cfg, SC8180X_MASTER_A1NOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_A1NOC);
|
||||||
|
DEFINE_QNODE(mas_xm_ufs_card, SC8180X_MASTER_UFS_CARD, 1, 8, SC8180X_A1NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_xm_ufs_g4, SC8180X_MASTER_UFS_GEN4, 1, 8, SC8180X_A1NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_xm_ufs_mem, SC8180X_MASTER_UFS_MEM, 1, 8, SC8180X_A1NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_xm_usb3_0, SC8180X_MASTER_USB3, 1, 8, SC8180X_A1NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_xm_usb3_1, SC8180X_MASTER_USB3_1, 1, 8, SC8180X_A1NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_xm_usb3_2, SC8180X_MASTER_USB3_2, 1, 16, SC8180X_A1NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_qhm_a2noc_cfg, SC8180X_MASTER_A2NOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_A2NOC);
|
||||||
|
DEFINE_QNODE(mas_qhm_qdss_bam, SC8180X_MASTER_QDSS_BAM, 1, 4, SC8180X_A2NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_qhm_qspi, SC8180X_MASTER_QSPI_0, 1, 4, SC8180X_A2NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_qhm_qspi1, SC8180X_MASTER_QSPI_1, 1, 4, SC8180X_A2NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_qhm_qup0, SC8180X_MASTER_QUP_0, 1, 4, SC8180X_A2NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_qhm_qup1, SC8180X_MASTER_QUP_1, 1, 4, SC8180X_A2NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_qhm_qup2, SC8180X_MASTER_QUP_2, 1, 4, SC8180X_A2NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_qhm_sensorss_ahb, SC8180X_MASTER_SENSORS_AHB, 1, 4, SC8180X_A2NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_qxm_crypto, SC8180X_MASTER_CRYPTO_CORE_0, 1, 8, SC8180X_A2NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_qxm_ipa, SC8180X_MASTER_IPA, 1, 8, SC8180X_A2NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_xm_emac, SC8180X_MASTER_EMAC, 1, 8, SC8180X_A2NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_xm_pcie3_0, SC8180X_MASTER_PCIE, 1, 8, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC);
|
||||||
|
DEFINE_QNODE(mas_xm_pcie3_1, SC8180X_MASTER_PCIE_1, 1, 16, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC);
|
||||||
|
DEFINE_QNODE(mas_xm_pcie3_2, SC8180X_MASTER_PCIE_2, 1, 8, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC);
|
||||||
|
DEFINE_QNODE(mas_xm_pcie3_3, SC8180X_MASTER_PCIE_3, 1, 16, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC);
|
||||||
|
DEFINE_QNODE(mas_xm_qdss_etr, SC8180X_MASTER_QDSS_ETR, 1, 8, SC8180X_A2NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_xm_sdc2, SC8180X_MASTER_SDCC_2, 1, 8, SC8180X_A2NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_xm_sdc4, SC8180X_MASTER_SDCC_4, 1, 8, SC8180X_A2NOC_SNOC_SLV);
|
||||||
|
DEFINE_QNODE(mas_qxm_camnoc_hf0_uncomp, SC8180X_MASTER_CAMNOC_HF0_UNCOMP, 1, 32, SC8180X_SLAVE_CAMNOC_UNCOMP);
|
||||||
|
DEFINE_QNODE(mas_qxm_camnoc_hf1_uncomp, SC8180X_MASTER_CAMNOC_HF1_UNCOMP, 1, 32, SC8180X_SLAVE_CAMNOC_UNCOMP);
|
||||||
|
DEFINE_QNODE(mas_qxm_camnoc_sf_uncomp, SC8180X_MASTER_CAMNOC_SF_UNCOMP, 1, 32, SC8180X_SLAVE_CAMNOC_UNCOMP);
|
||||||
|
DEFINE_QNODE(mas_qnm_npu, SC8180X_MASTER_NPU, 1, 32, SC8180X_SLAVE_CDSP_MEM_NOC);
|
||||||
|
DEFINE_QNODE(mas_qnm_snoc, SC8180X_SNOC_CNOC_MAS, 1, 8, SC8180X_SLAVE_TLMM_SOUTH, SC8180X_SLAVE_CDSP_CFG, SC8180X_SLAVE_SPSS_CFG, SC8180X_SLAVE_CAMERA_CFG, SC8180X_SLAVE_SDCC_4, SC8180X_SLAVE_AHB2PHY_CENTER, SC8180X_SLAVE_SDCC_2, SC8180X_SLAVE_PCIE_2_CFG, SC8180X_SLAVE_CNOC_MNOC_CFG, SC8180X_SLAVE_EMAC_CFG, SC8180X_SLAVE_QSPI_0, SC8180X_SLAVE_QSPI_1, SC8180X_SLAVE_TLMM_EAST, SC8180X_SLAVE_SNOC_CFG, SC8180X_SLAVE_AHB2PHY_EAST, SC8180X_SLAVE_GLM, SC8180X_SLAVE_PDM, SC8180X_SLAVE_PCIE_1_CFG, SC8180X_SLAVE_A2NOC_CFG, SC8180X_SLAVE_QDSS_CFG, SC8180X_SLAVE_DISPLAY_CFG, SC8180X_SLAVE_TCSR, SC8180X_SLAVE_UFS_MEM_0_CFG, SC8180X_SLAVE_CNOC_DDRSS, SC8180X_SLAVE_PCIE_0_CFG, SC8180X_SLAVE_QUP_1, SC8180X_SLAVE_QUP_2, SC8180X_SLAVE_NPU_CFG, SC8180X_SLAVE_CRYPTO_0_CFG, SC8180X_SLAVE_GRAPHICS_3D_CFG, SC8180X_SLAVE_VENUS_CFG, SC8180X_SLAVE_TSIF, SC8180X_SLAVE_IPA_CFG, SC8180X_SLAVE_CLK_CTL, SC8180X_SLAVE_SECURITY, SC8180X_SLAVE_AOP, SC8180X_SLAVE_AHB2PHY_WEST, SC8180X_SLAVE_AHB2PHY_SOUTH, SC8180X_SLAVE_SERVICE_CNOC, SC8180X_SLAVE_UFS_CARD_CFG, SC8180X_SLAVE_USB3_1, SC8180X_SLAVE_USB3_2, SC8180X_SLAVE_PCIE_3_CFG, SC8180X_SLAVE_RBCPR_CX_CFG, SC8180X_SLAVE_TLMM_WEST, SC8180X_SLAVE_A1NOC_CFG, SC8180X_SLAVE_AOSS, SC8180X_SLAVE_PRNG, SC8180X_SLAVE_VSENSE_CTRL_CFG, SC8180X_SLAVE_QUP_0, SC8180X_SLAVE_USB3, SC8180X_SLAVE_RBCPR_MMCX_CFG, SC8180X_SLAVE_PIMEM_CFG, SC8180X_SLAVE_UFS_MEM_1_CFG, SC8180X_SLAVE_RBCPR_MX_CFG, SC8180X_SLAVE_IMEM_CFG);
|
||||||
|
DEFINE_QNODE(mas_qhm_cnoc_dc_noc, SC8180X_MASTER_CNOC_DC_NOC, 1, 4, SC8180X_SLAVE_LLCC_CFG, SC8180X_SLAVE_GEM_NOC_CFG);
|
||||||
|
DEFINE_QNODE(mas_acm_apps, SC8180X_MASTER_AMPSS_M0, 4, 64, SC8180X_SLAVE_ECC, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC);
|
||||||
|
DEFINE_QNODE(mas_acm_gpu_tcu, SC8180X_MASTER_GPU_TCU, 1, 8, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC);
|
||||||
|
DEFINE_QNODE(mas_acm_sys_tcu, SC8180X_MASTER_SYS_TCU, 1, 8, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC);
|
||||||
|
DEFINE_QNODE(mas_qhm_gemnoc_cfg, SC8180X_MASTER_GEM_NOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_GEM_NOC_1, SC8180X_SLAVE_SERVICE_GEM_NOC, SC8180X_SLAVE_MSS_PROC_MS_MPU_CFG);
|
||||||
|
DEFINE_QNODE(mas_qnm_cmpnoc, SC8180X_MASTER_COMPUTE_NOC, 2, 32, SC8180X_SLAVE_ECC, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC);
|
||||||
|
DEFINE_QNODE(mas_qnm_gpu, SC8180X_MASTER_GRAPHICS_3D, 4, 32, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC);
|
||||||
|
DEFINE_QNODE(mas_qnm_mnoc_hf, SC8180X_MASTER_MNOC_HF_MEM_NOC, 2, 32, SC8180X_SLAVE_LLCC);
|
||||||
|
DEFINE_QNODE(mas_qnm_mnoc_sf, SC8180X_MASTER_MNOC_SF_MEM_NOC, 1, 32, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC);
|
||||||
|
DEFINE_QNODE(mas_qnm_pcie, SC8180X_MASTER_GEM_NOC_PCIE_SNOC, 1, 32, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC);
|
||||||
|
DEFINE_QNODE(mas_qnm_snoc_gc, SC8180X_MASTER_SNOC_GC_MEM_NOC, 1, 8, SC8180X_SLAVE_LLCC);
|
||||||
|
DEFINE_QNODE(mas_qnm_snoc_sf, SC8180X_MASTER_SNOC_SF_MEM_NOC, 1, 32, SC8180X_SLAVE_LLCC);
|
||||||
|
DEFINE_QNODE(mas_qxm_ecc, SC8180X_MASTER_ECC, 2, 32, SC8180X_SLAVE_LLCC);
|
||||||
|
DEFINE_QNODE(mas_ipa_core_master, SC8180X_MASTER_IPA_CORE, 1, 8, SC8180X_SLAVE_IPA_CORE);
|
||||||
|
DEFINE_QNODE(mas_llcc_mc, SC8180X_MASTER_LLCC, 8, 4, SC8180X_SLAVE_EBI_CH0);
|
||||||
|
DEFINE_QNODE(mas_qhm_mnoc_cfg, SC8180X_MASTER_CNOC_MNOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_MNOC);
|
||||||
|
DEFINE_QNODE(mas_qxm_camnoc_hf0, SC8180X_MASTER_CAMNOC_HF0, 1, 32, SC8180X_SLAVE_MNOC_HF_MEM_NOC);
|
||||||
|
DEFINE_QNODE(mas_qxm_camnoc_hf1, SC8180X_MASTER_CAMNOC_HF1, 1, 32, SC8180X_SLAVE_MNOC_HF_MEM_NOC);
|
||||||
|
DEFINE_QNODE(mas_qxm_camnoc_sf, SC8180X_MASTER_CAMNOC_SF, 1, 32, SC8180X_SLAVE_MNOC_SF_MEM_NOC);
|
||||||
|
DEFINE_QNODE(mas_qxm_mdp0, SC8180X_MASTER_MDP_PORT0, 1, 32, SC8180X_SLAVE_MNOC_HF_MEM_NOC);
|
||||||
|
DEFINE_QNODE(mas_qxm_mdp1, SC8180X_MASTER_MDP_PORT1, 1, 32, SC8180X_SLAVE_MNOC_HF_MEM_NOC);
|
||||||
|
DEFINE_QNODE(mas_qxm_rot, SC8180X_MASTER_ROTATOR, 1, 32, SC8180X_SLAVE_MNOC_SF_MEM_NOC);
|
||||||
|
DEFINE_QNODE(mas_qxm_venus0, SC8180X_MASTER_VIDEO_P0, 1, 32, SC8180X_SLAVE_MNOC_SF_MEM_NOC);
|
||||||
|
DEFINE_QNODE(mas_qxm_venus1, SC8180X_MASTER_VIDEO_P1, 1, 32, SC8180X_SLAVE_MNOC_SF_MEM_NOC);
|
||||||
|
DEFINE_QNODE(mas_qxm_venus_arm9, SC8180X_MASTER_VIDEO_PROC, 1, 8, SC8180X_SLAVE_MNOC_SF_MEM_NOC);
|
||||||
|
DEFINE_QNODE(mas_qhm_snoc_cfg, SC8180X_MASTER_SNOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_SNOC);
|
||||||
|
DEFINE_QNODE(mas_qnm_aggre1_noc, SC8180X_A1NOC_SNOC_MAS, 1, 32, SC8180X_SLAVE_SNOC_GEM_NOC_SF, SC8180X_SLAVE_PIMEM, SC8180X_SLAVE_OCIMEM, SC8180X_SLAVE_APPSS, SC8180X_SNOC_CNOC_SLV, SC8180X_SLAVE_QDSS_STM);
|
||||||
|
DEFINE_QNODE(mas_qnm_aggre2_noc, SC8180X_A2NOC_SNOC_MAS, 1, 16, SC8180X_SLAVE_SNOC_GEM_NOC_SF, SC8180X_SLAVE_PIMEM, SC8180X_SLAVE_PCIE_3, SC8180X_SLAVE_OCIMEM, SC8180X_SLAVE_APPSS, SC8180X_SLAVE_PCIE_2, SC8180X_SNOC_CNOC_SLV, SC8180X_SLAVE_PCIE_0, SC8180X_SLAVE_PCIE_1, SC8180X_SLAVE_TCU, SC8180X_SLAVE_QDSS_STM);
|
||||||
|
DEFINE_QNODE(mas_qnm_gemnoc, SC8180X_MASTER_GEM_NOC_SNOC, 1, 8, SC8180X_SLAVE_PIMEM, SC8180X_SLAVE_OCIMEM, SC8180X_SLAVE_APPSS, SC8180X_SNOC_CNOC_SLV, SC8180X_SLAVE_TCU, SC8180X_SLAVE_QDSS_STM);
|
||||||
|
DEFINE_QNODE(mas_qxm_pimem, SC8180X_MASTER_PIMEM, 1, 8, SC8180X_SLAVE_SNOC_GEM_NOC_GC, SC8180X_SLAVE_OCIMEM);
|
||||||
|
DEFINE_QNODE(mas_xm_gic, SC8180X_MASTER_GIC, 1, 8, SC8180X_SLAVE_SNOC_GEM_NOC_GC, SC8180X_SLAVE_OCIMEM);
|
||||||
|
DEFINE_QNODE(slv_qns_a1noc_snoc, SC8180X_A1NOC_SNOC_SLV, 1, 32, SC8180X_A1NOC_SNOC_MAS);
|
||||||
|
DEFINE_QNODE(slv_srvc_aggre1_noc, SC8180X_SLAVE_SERVICE_A1NOC, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qns_a2noc_snoc, SC8180X_A2NOC_SNOC_SLV, 1, 16, SC8180X_A2NOC_SNOC_MAS);
|
||||||
|
DEFINE_QNODE(slv_qns_pcie_mem_noc, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC, 1, 32, SC8180X_MASTER_GEM_NOC_PCIE_SNOC);
|
||||||
|
DEFINE_QNODE(slv_srvc_aggre2_noc, SC8180X_SLAVE_SERVICE_A2NOC, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qns_camnoc_uncomp, SC8180X_SLAVE_CAMNOC_UNCOMP, 1, 32);
|
||||||
|
DEFINE_QNODE(slv_qns_cdsp_mem_noc, SC8180X_SLAVE_CDSP_MEM_NOC, 2, 32, SC8180X_MASTER_COMPUTE_NOC);
|
||||||
|
DEFINE_QNODE(slv_qhs_a1_noc_cfg, SC8180X_SLAVE_A1NOC_CFG, 1, 4, SC8180X_MASTER_A1NOC_CFG);
|
||||||
|
DEFINE_QNODE(slv_qhs_a2_noc_cfg, SC8180X_SLAVE_A2NOC_CFG, 1, 4, SC8180X_MASTER_A2NOC_CFG);
|
||||||
|
DEFINE_QNODE(slv_qhs_ahb2phy_refgen_center, SC8180X_SLAVE_AHB2PHY_CENTER, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_ahb2phy_refgen_east, SC8180X_SLAVE_AHB2PHY_EAST, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_ahb2phy_refgen_west, SC8180X_SLAVE_AHB2PHY_WEST, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_ahb2phy_south, SC8180X_SLAVE_AHB2PHY_SOUTH, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_aop, SC8180X_SLAVE_AOP, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_aoss, SC8180X_SLAVE_AOSS, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_camera_cfg, SC8180X_SLAVE_CAMERA_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_clk_ctl, SC8180X_SLAVE_CLK_CTL, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_compute_dsp, SC8180X_SLAVE_CDSP_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_cpr_cx, SC8180X_SLAVE_RBCPR_CX_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_cpr_mmcx, SC8180X_SLAVE_RBCPR_MMCX_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_cpr_mx, SC8180X_SLAVE_RBCPR_MX_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_crypto0_cfg, SC8180X_SLAVE_CRYPTO_0_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_ddrss_cfg, SC8180X_SLAVE_CNOC_DDRSS, 1, 4, SC8180X_MASTER_CNOC_DC_NOC);
|
||||||
|
DEFINE_QNODE(slv_qhs_display_cfg, SC8180X_SLAVE_DISPLAY_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_emac_cfg, SC8180X_SLAVE_EMAC_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_glm, SC8180X_SLAVE_GLM, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_gpuss_cfg, SC8180X_SLAVE_GRAPHICS_3D_CFG, 1, 8);
|
||||||
|
DEFINE_QNODE(slv_qhs_imem_cfg, SC8180X_SLAVE_IMEM_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_ipa, SC8180X_SLAVE_IPA_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_mnoc_cfg, SC8180X_SLAVE_CNOC_MNOC_CFG, 1, 4, SC8180X_MASTER_CNOC_MNOC_CFG);
|
||||||
|
DEFINE_QNODE(slv_qhs_npu_cfg, SC8180X_SLAVE_NPU_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_pcie0_cfg, SC8180X_SLAVE_PCIE_0_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_pcie1_cfg, SC8180X_SLAVE_PCIE_1_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_pcie2_cfg, SC8180X_SLAVE_PCIE_2_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_pcie3_cfg, SC8180X_SLAVE_PCIE_3_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_pdm, SC8180X_SLAVE_PDM, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_pimem_cfg, SC8180X_SLAVE_PIMEM_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_prng, SC8180X_SLAVE_PRNG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_qdss_cfg, SC8180X_SLAVE_QDSS_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_qspi_0, SC8180X_SLAVE_QSPI_0, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_qspi_1, SC8180X_SLAVE_QSPI_1, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_qupv3_east0, SC8180X_SLAVE_QUP_1, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_qupv3_east1, SC8180X_SLAVE_QUP_2, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_qupv3_west, SC8180X_SLAVE_QUP_0, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_sdc2, SC8180X_SLAVE_SDCC_2, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_sdc4, SC8180X_SLAVE_SDCC_4, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_security, SC8180X_SLAVE_SECURITY, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_snoc_cfg, SC8180X_SLAVE_SNOC_CFG, 1, 4, SC8180X_MASTER_SNOC_CFG);
|
||||||
|
DEFINE_QNODE(slv_qhs_spss_cfg, SC8180X_SLAVE_SPSS_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_tcsr, SC8180X_SLAVE_TCSR, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_tlmm_east, SC8180X_SLAVE_TLMM_EAST, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_tlmm_south, SC8180X_SLAVE_TLMM_SOUTH, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_tlmm_west, SC8180X_SLAVE_TLMM_WEST, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_tsif, SC8180X_SLAVE_TSIF, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_ufs_card_cfg, SC8180X_SLAVE_UFS_CARD_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_ufs_mem0_cfg, SC8180X_SLAVE_UFS_MEM_0_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_ufs_mem1_cfg, SC8180X_SLAVE_UFS_MEM_1_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_usb3_0, SC8180X_SLAVE_USB3, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_usb3_1, SC8180X_SLAVE_USB3_1, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_usb3_2, SC8180X_SLAVE_USB3_2, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_venus_cfg, SC8180X_SLAVE_VENUS_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_vsense_ctrl_cfg, SC8180X_SLAVE_VSENSE_CTRL_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_srvc_cnoc, SC8180X_SLAVE_SERVICE_CNOC, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_gemnoc, SC8180X_SLAVE_GEM_NOC_CFG, 1, 4, SC8180X_MASTER_GEM_NOC_CFG);
|
||||||
|
DEFINE_QNODE(slv_qhs_llcc, SC8180X_SLAVE_LLCC_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_mdsp_ms_mpu_cfg, SC8180X_SLAVE_MSS_PROC_MS_MPU_CFG, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qns_ecc, SC8180X_SLAVE_ECC, 1, 32);
|
||||||
|
DEFINE_QNODE(slv_qns_gem_noc_snoc, SC8180X_SLAVE_GEM_NOC_SNOC, 1, 8, SC8180X_MASTER_GEM_NOC_SNOC);
|
||||||
|
DEFINE_QNODE(slv_qns_llcc, SC8180X_SLAVE_LLCC, 8, 16, SC8180X_MASTER_LLCC);
|
||||||
|
DEFINE_QNODE(slv_srvc_gemnoc, SC8180X_SLAVE_SERVICE_GEM_NOC, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_srvc_gemnoc1, SC8180X_SLAVE_SERVICE_GEM_NOC_1, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_ipa_core_slave, SC8180X_SLAVE_IPA_CORE, 1, 8);
|
||||||
|
DEFINE_QNODE(slv_ebi, SC8180X_SLAVE_EBI_CH0, 8, 4);
|
||||||
|
DEFINE_QNODE(slv_qns2_mem_noc, SC8180X_SLAVE_MNOC_SF_MEM_NOC, 1, 32, SC8180X_MASTER_MNOC_SF_MEM_NOC);
|
||||||
|
DEFINE_QNODE(slv_qns_mem_noc_hf, SC8180X_SLAVE_MNOC_HF_MEM_NOC, 2, 32, SC8180X_MASTER_MNOC_HF_MEM_NOC);
|
||||||
|
DEFINE_QNODE(slv_srvc_mnoc, SC8180X_SLAVE_SERVICE_MNOC, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_qhs_apss, SC8180X_SLAVE_APPSS, 1, 8);
|
||||||
|
DEFINE_QNODE(slv_qns_cnoc, SC8180X_SNOC_CNOC_SLV, 1, 8, SC8180X_SNOC_CNOC_MAS);
|
||||||
|
DEFINE_QNODE(slv_qns_gemnoc_gc, SC8180X_SLAVE_SNOC_GEM_NOC_GC, 1, 8, SC8180X_MASTER_SNOC_GC_MEM_NOC);
|
||||||
|
DEFINE_QNODE(slv_qns_gemnoc_sf, SC8180X_SLAVE_SNOC_GEM_NOC_SF, 1, 32, SC8180X_MASTER_SNOC_SF_MEM_NOC);
|
||||||
|
DEFINE_QNODE(slv_qxs_imem, SC8180X_SLAVE_OCIMEM, 1, 8);
|
||||||
|
DEFINE_QNODE(slv_qxs_pimem, SC8180X_SLAVE_PIMEM, 1, 8);
|
||||||
|
DEFINE_QNODE(slv_srvc_snoc, SC8180X_SLAVE_SERVICE_SNOC, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_xs_pcie_0, SC8180X_SLAVE_PCIE_0, 1, 8);
|
||||||
|
DEFINE_QNODE(slv_xs_pcie_1, SC8180X_SLAVE_PCIE_1, 1, 8);
|
||||||
|
DEFINE_QNODE(slv_xs_pcie_2, SC8180X_SLAVE_PCIE_2, 1, 8);
|
||||||
|
DEFINE_QNODE(slv_xs_pcie_3, SC8180X_SLAVE_PCIE_3, 1, 8);
|
||||||
|
DEFINE_QNODE(slv_xs_qdss_stm, SC8180X_SLAVE_QDSS_STM, 1, 4);
|
||||||
|
DEFINE_QNODE(slv_xs_sys_tcu_cfg, SC8180X_SLAVE_TCU, 1, 8);
|
||||||
|
|
||||||
|
DEFINE_QBCM(bcm_acv, "ACV", false, &slv_ebi);
|
||||||
|
DEFINE_QBCM(bcm_mc0, "MC0", false, &slv_ebi);
|
||||||
|
DEFINE_QBCM(bcm_sh0, "SH0", false, &slv_qns_llcc);
|
||||||
|
DEFINE_QBCM(bcm_mm0, "MM0", false, &slv_qns_mem_noc_hf);
|
||||||
|
DEFINE_QBCM(bcm_co0, "CO0", false, &slv_qns_cdsp_mem_noc);
|
||||||
|
DEFINE_QBCM(bcm_ce0, "CE0", false, &mas_qxm_crypto);
|
||||||
|
DEFINE_QBCM(bcm_cn0, "CN0", false, &mas_qnm_snoc, &slv_qhs_a1_noc_cfg, &slv_qhs_a2_noc_cfg, &slv_qhs_ahb2phy_refgen_center, &slv_qhs_ahb2phy_refgen_east, &slv_qhs_ahb2phy_refgen_west, &slv_qhs_ahb2phy_south, &slv_qhs_aop, &slv_qhs_aoss, &slv_qhs_camera_cfg, &slv_qhs_clk_ctl, &slv_qhs_compute_dsp, &slv_qhs_cpr_cx, &slv_qhs_cpr_mmcx, &slv_qhs_cpr_mx, &slv_qhs_crypto0_cfg, &slv_qhs_ddrss_cfg, &slv_qhs_display_cfg, &slv_qhs_emac_cfg, &slv_qhs_glm, &slv_qhs_gpuss_cfg, &slv_qhs_imem_cfg, &slv_qhs_ipa, &slv_qhs_mnoc_cfg, &slv_qhs_npu_cfg, &slv_qhs_pcie0_cfg, &slv_qhs_pcie1_cfg, &slv_qhs_pcie2_cfg, &slv_qhs_pcie3_cfg, &slv_qhs_pdm, &slv_qhs_pimem_cfg, &slv_qhs_prng, &slv_qhs_qdss_cfg, &slv_qhs_qspi_0, &slv_qhs_qspi_1, &slv_qhs_qupv3_east0, &slv_qhs_qupv3_east1, &slv_qhs_qupv3_west, &slv_qhs_sdc2, &slv_qhs_sdc4, &slv_qhs_security, &slv_qhs_snoc_cfg, &slv_qhs_spss_cfg, &slv_qhs_tcsr, &slv_qhs_tlmm_east, &slv_qhs_tlmm_south, &slv_qhs_tlmm_west, &slv_qhs_tsif, &slv_qhs_ufs_card_cfg, &slv_qhs_ufs_mem0_cfg, &slv_qhs_ufs_mem1_cfg, &slv_qhs_usb3_0, &slv_qhs_usb3_1, &slv_qhs_usb3_2, &slv_qhs_venus_cfg, &slv_qhs_vsense_ctrl_cfg, &slv_srvc_cnoc);
|
||||||
|
DEFINE_QBCM(bcm_mm1, "MM1", false, &mas_qxm_camnoc_hf0_uncomp, &mas_qxm_camnoc_hf1_uncomp, &mas_qxm_camnoc_sf_uncomp, &mas_qxm_camnoc_hf0, &mas_qxm_camnoc_hf1, &mas_qxm_mdp0, &mas_qxm_mdp1);
|
||||||
|
DEFINE_QBCM(bcm_qup0, "QUP0", false, &mas_qhm_qup0, &mas_qhm_qup1, &mas_qhm_qup2);
|
||||||
|
DEFINE_QBCM(bcm_sh2, "SH2", false, &slv_qns_gem_noc_snoc);
|
||||||
|
DEFINE_QBCM(bcm_mm2, "MM2", false, &mas_qxm_camnoc_sf, &mas_qxm_rot, &mas_qxm_venus0, &mas_qxm_venus1, &mas_qxm_venus_arm9, &slv_qns2_mem_noc);
|
||||||
|
DEFINE_QBCM(bcm_sh3, "SH3", false, &mas_acm_apps);
|
||||||
|
DEFINE_QBCM(bcm_sn0, "SN0", false, &slv_qns_gemnoc_sf);
|
||||||
|
DEFINE_QBCM(bcm_sn1, "SN1", false, &slv_qxs_imem);
|
||||||
|
DEFINE_QBCM(bcm_sn2, "SN2", false, &slv_qns_gemnoc_gc);
|
||||||
|
DEFINE_QBCM(bcm_co2, "CO2", false, &mas_qnm_npu);
|
||||||
|
DEFINE_QBCM(bcm_ip0, "IP0", false, &slv_ipa_core_slave);
|
||||||
|
DEFINE_QBCM(bcm_sn3, "SN3", false, &slv_srvc_aggre1_noc, &slv_qns_cnoc);
|
||||||
|
DEFINE_QBCM(bcm_sn4, "SN4", false, &slv_qxs_pimem);
|
||||||
|
DEFINE_QBCM(bcm_sn8, "SN8", false, &slv_xs_pcie_0, &slv_xs_pcie_1, &slv_xs_pcie_2, &slv_xs_pcie_3);
|
||||||
|
DEFINE_QBCM(bcm_sn9, "SN9", false, &mas_qnm_aggre1_noc);
|
||||||
|
DEFINE_QBCM(bcm_sn11, "SN11", false, &mas_qnm_aggre2_noc);
|
||||||
|
DEFINE_QBCM(bcm_sn14, "SN14", false, &slv_qns_pcie_mem_noc);
|
||||||
|
DEFINE_QBCM(bcm_sn15, "SN15", false, &mas_qnm_gemnoc);
|
||||||
|
|
||||||
|
static struct qcom_icc_bcm *aggre1_noc_bcms[] = {
|
||||||
|
&bcm_sn3,
|
||||||
|
&bcm_ce0,
|
||||||
|
&bcm_qup0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_bcm *aggre2_noc_bcms[] = {
|
||||||
|
&bcm_sn14,
|
||||||
|
&bcm_ce0,
|
||||||
|
&bcm_qup0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_bcm *camnoc_virt_bcms[] = {
|
||||||
|
&bcm_mm1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_bcm *compute_noc_bcms[] = {
|
||||||
|
&bcm_co0,
|
||||||
|
&bcm_co2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_bcm *config_noc_bcms[] = {
|
||||||
|
&bcm_cn0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_bcm *gem_noc_bcms[] = {
|
||||||
|
&bcm_sh0,
|
||||||
|
&bcm_sh2,
|
||||||
|
&bcm_sh3,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_bcm *ipa_virt_bcms[] = {
|
||||||
|
&bcm_ip0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_bcm *mc_virt_bcms[] = {
|
||||||
|
&bcm_mc0,
|
||||||
|
&bcm_acv,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_bcm *mmss_noc_bcms[] = {
|
||||||
|
&bcm_mm0,
|
||||||
|
&bcm_mm1,
|
||||||
|
&bcm_mm2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_bcm *system_noc_bcms[] = {
|
||||||
|
&bcm_sn0,
|
||||||
|
&bcm_sn1,
|
||||||
|
&bcm_sn2,
|
||||||
|
&bcm_sn3,
|
||||||
|
&bcm_sn4,
|
||||||
|
&bcm_sn8,
|
||||||
|
&bcm_sn9,
|
||||||
|
&bcm_sn11,
|
||||||
|
&bcm_sn15,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_node *aggre1_noc_nodes[] = {
|
||||||
|
[MASTER_A1NOC_CFG] = &mas_qhm_a1noc_cfg,
|
||||||
|
[MASTER_UFS_CARD] = &mas_xm_ufs_card,
|
||||||
|
[MASTER_UFS_GEN4] = &mas_xm_ufs_g4,
|
||||||
|
[MASTER_UFS_MEM] = &mas_xm_ufs_mem,
|
||||||
|
[MASTER_USB3] = &mas_xm_usb3_0,
|
||||||
|
[MASTER_USB3_1] = &mas_xm_usb3_1,
|
||||||
|
[MASTER_USB3_2] = &mas_xm_usb3_2,
|
||||||
|
[A1NOC_SNOC_SLV] = &slv_qns_a1noc_snoc,
|
||||||
|
[SLAVE_SERVICE_A1NOC] = &slv_srvc_aggre1_noc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_node *aggre2_noc_nodes[] = {
|
||||||
|
[MASTER_A2NOC_CFG] = &mas_qhm_a2noc_cfg,
|
||||||
|
[MASTER_QDSS_BAM] = &mas_qhm_qdss_bam,
|
||||||
|
[MASTER_QSPI_0] = &mas_qhm_qspi,
|
||||||
|
[MASTER_QSPI_1] = &mas_qhm_qspi1,
|
||||||
|
[MASTER_QUP_0] = &mas_qhm_qup0,
|
||||||
|
[MASTER_QUP_1] = &mas_qhm_qup1,
|
||||||
|
[MASTER_QUP_2] = &mas_qhm_qup2,
|
||||||
|
[MASTER_SENSORS_AHB] = &mas_qhm_sensorss_ahb,
|
||||||
|
[MASTER_CRYPTO_CORE_0] = &mas_qxm_crypto,
|
||||||
|
[MASTER_IPA] = &mas_qxm_ipa,
|
||||||
|
[MASTER_EMAC] = &mas_xm_emac,
|
||||||
|
[MASTER_PCIE] = &mas_xm_pcie3_0,
|
||||||
|
[MASTER_PCIE_1] = &mas_xm_pcie3_1,
|
||||||
|
[MASTER_PCIE_2] = &mas_xm_pcie3_2,
|
||||||
|
[MASTER_PCIE_3] = &mas_xm_pcie3_3,
|
||||||
|
[MASTER_QDSS_ETR] = &mas_xm_qdss_etr,
|
||||||
|
[MASTER_SDCC_2] = &mas_xm_sdc2,
|
||||||
|
[MASTER_SDCC_4] = &mas_xm_sdc4,
|
||||||
|
[A2NOC_SNOC_SLV] = &slv_qns_a2noc_snoc,
|
||||||
|
[SLAVE_ANOC_PCIE_GEM_NOC] = &slv_qns_pcie_mem_noc,
|
||||||
|
[SLAVE_SERVICE_A2NOC] = &slv_srvc_aggre2_noc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_node *camnoc_virt_nodes[] = {
|
||||||
|
[MASTER_CAMNOC_HF0_UNCOMP] = &mas_qxm_camnoc_hf0_uncomp,
|
||||||
|
[MASTER_CAMNOC_HF1_UNCOMP] = &mas_qxm_camnoc_hf1_uncomp,
|
||||||
|
[MASTER_CAMNOC_SF_UNCOMP] = &mas_qxm_camnoc_sf_uncomp,
|
||||||
|
[SLAVE_CAMNOC_UNCOMP] = &slv_qns_camnoc_uncomp,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_node *compute_noc_nodes[] = {
|
||||||
|
[MASTER_NPU] = &mas_qnm_npu,
|
||||||
|
[SLAVE_CDSP_MEM_NOC] = &slv_qns_cdsp_mem_noc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_node *config_noc_nodes[] = {
|
||||||
|
[SNOC_CNOC_MAS] = &mas_qnm_snoc,
|
||||||
|
[SLAVE_A1NOC_CFG] = &slv_qhs_a1_noc_cfg,
|
||||||
|
[SLAVE_A2NOC_CFG] = &slv_qhs_a2_noc_cfg,
|
||||||
|
[SLAVE_AHB2PHY_CENTER] = &slv_qhs_ahb2phy_refgen_center,
|
||||||
|
[SLAVE_AHB2PHY_EAST] = &slv_qhs_ahb2phy_refgen_east,
|
||||||
|
[SLAVE_AHB2PHY_WEST] = &slv_qhs_ahb2phy_refgen_west,
|
||||||
|
[SLAVE_AHB2PHY_SOUTH] = &slv_qhs_ahb2phy_south,
|
||||||
|
[SLAVE_AOP] = &slv_qhs_aop,
|
||||||
|
[SLAVE_AOSS] = &slv_qhs_aoss,
|
||||||
|
[SLAVE_CAMERA_CFG] = &slv_qhs_camera_cfg,
|
||||||
|
[SLAVE_CLK_CTL] = &slv_qhs_clk_ctl,
|
||||||
|
[SLAVE_CDSP_CFG] = &slv_qhs_compute_dsp,
|
||||||
|
[SLAVE_RBCPR_CX_CFG] = &slv_qhs_cpr_cx,
|
||||||
|
[SLAVE_RBCPR_MMCX_CFG] = &slv_qhs_cpr_mmcx,
|
||||||
|
[SLAVE_RBCPR_MX_CFG] = &slv_qhs_cpr_mx,
|
||||||
|
[SLAVE_CRYPTO_0_CFG] = &slv_qhs_crypto0_cfg,
|
||||||
|
[SLAVE_CNOC_DDRSS] = &slv_qhs_ddrss_cfg,
|
||||||
|
[SLAVE_DISPLAY_CFG] = &slv_qhs_display_cfg,
|
||||||
|
[SLAVE_EMAC_CFG] = &slv_qhs_emac_cfg,
|
||||||
|
[SLAVE_GLM] = &slv_qhs_glm,
|
||||||
|
[SLAVE_GRAPHICS_3D_CFG] = &slv_qhs_gpuss_cfg,
|
||||||
|
[SLAVE_IMEM_CFG] = &slv_qhs_imem_cfg,
|
||||||
|
[SLAVE_IPA_CFG] = &slv_qhs_ipa,
|
||||||
|
[SLAVE_CNOC_MNOC_CFG] = &slv_qhs_mnoc_cfg,
|
||||||
|
[SLAVE_NPU_CFG] = &slv_qhs_npu_cfg,
|
||||||
|
[SLAVE_PCIE_0_CFG] = &slv_qhs_pcie0_cfg,
|
||||||
|
[SLAVE_PCIE_1_CFG] = &slv_qhs_pcie1_cfg,
|
||||||
|
[SLAVE_PCIE_2_CFG] = &slv_qhs_pcie2_cfg,
|
||||||
|
[SLAVE_PCIE_3_CFG] = &slv_qhs_pcie3_cfg,
|
||||||
|
[SLAVE_PDM] = &slv_qhs_pdm,
|
||||||
|
[SLAVE_PIMEM_CFG] = &slv_qhs_pimem_cfg,
|
||||||
|
[SLAVE_PRNG] = &slv_qhs_prng,
|
||||||
|
[SLAVE_QDSS_CFG] = &slv_qhs_qdss_cfg,
|
||||||
|
[SLAVE_QSPI_0] = &slv_qhs_qspi_0,
|
||||||
|
[SLAVE_QSPI_1] = &slv_qhs_qspi_1,
|
||||||
|
[SLAVE_QUP_1] = &slv_qhs_qupv3_east0,
|
||||||
|
[SLAVE_QUP_2] = &slv_qhs_qupv3_east1,
|
||||||
|
[SLAVE_QUP_0] = &slv_qhs_qupv3_west,
|
||||||
|
[SLAVE_SDCC_2] = &slv_qhs_sdc2,
|
||||||
|
[SLAVE_SDCC_4] = &slv_qhs_sdc4,
|
||||||
|
[SLAVE_SECURITY] = &slv_qhs_security,
|
||||||
|
[SLAVE_SNOC_CFG] = &slv_qhs_snoc_cfg,
|
||||||
|
[SLAVE_SPSS_CFG] = &slv_qhs_spss_cfg,
|
||||||
|
[SLAVE_TCSR] = &slv_qhs_tcsr,
|
||||||
|
[SLAVE_TLMM_EAST] = &slv_qhs_tlmm_east,
|
||||||
|
[SLAVE_TLMM_SOUTH] = &slv_qhs_tlmm_south,
|
||||||
|
[SLAVE_TLMM_WEST] = &slv_qhs_tlmm_west,
|
||||||
|
[SLAVE_TSIF] = &slv_qhs_tsif,
|
||||||
|
[SLAVE_UFS_CARD_CFG] = &slv_qhs_ufs_card_cfg,
|
||||||
|
[SLAVE_UFS_MEM_0_CFG] = &slv_qhs_ufs_mem0_cfg,
|
||||||
|
[SLAVE_UFS_MEM_1_CFG] = &slv_qhs_ufs_mem1_cfg,
|
||||||
|
[SLAVE_USB3] = &slv_qhs_usb3_0,
|
||||||
|
[SLAVE_USB3_1] = &slv_qhs_usb3_1,
|
||||||
|
[SLAVE_USB3_2] = &slv_qhs_usb3_2,
|
||||||
|
[SLAVE_VENUS_CFG] = &slv_qhs_venus_cfg,
|
||||||
|
[SLAVE_VSENSE_CTRL_CFG] = &slv_qhs_vsense_ctrl_cfg,
|
||||||
|
[SLAVE_SERVICE_CNOC] = &slv_srvc_cnoc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_node *dc_noc_nodes[] = {
|
||||||
|
[MASTER_CNOC_DC_NOC] = &mas_qhm_cnoc_dc_noc,
|
||||||
|
[SLAVE_GEM_NOC_CFG] = &slv_qhs_gemnoc,
|
||||||
|
[SLAVE_LLCC_CFG] = &slv_qhs_llcc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_node *gem_noc_nodes[] = {
|
||||||
|
[MASTER_AMPSS_M0] = &mas_acm_apps,
|
||||||
|
[MASTER_GPU_TCU] = &mas_acm_gpu_tcu,
|
||||||
|
[MASTER_SYS_TCU] = &mas_acm_sys_tcu,
|
||||||
|
[MASTER_GEM_NOC_CFG] = &mas_qhm_gemnoc_cfg,
|
||||||
|
[MASTER_COMPUTE_NOC] = &mas_qnm_cmpnoc,
|
||||||
|
[MASTER_GRAPHICS_3D] = &mas_qnm_gpu,
|
||||||
|
[MASTER_MNOC_HF_MEM_NOC] = &mas_qnm_mnoc_hf,
|
||||||
|
[MASTER_MNOC_SF_MEM_NOC] = &mas_qnm_mnoc_sf,
|
||||||
|
[MASTER_GEM_NOC_PCIE_SNOC] = &mas_qnm_pcie,
|
||||||
|
[MASTER_SNOC_GC_MEM_NOC] = &mas_qnm_snoc_gc,
|
||||||
|
[MASTER_SNOC_SF_MEM_NOC] = &mas_qnm_snoc_sf,
|
||||||
|
[MASTER_ECC] = &mas_qxm_ecc,
|
||||||
|
[SLAVE_MSS_PROC_MS_MPU_CFG] = &slv_qhs_mdsp_ms_mpu_cfg,
|
||||||
|
[SLAVE_ECC] = &slv_qns_ecc,
|
||||||
|
[SLAVE_GEM_NOC_SNOC] = &slv_qns_gem_noc_snoc,
|
||||||
|
[SLAVE_LLCC] = &slv_qns_llcc,
|
||||||
|
[SLAVE_SERVICE_GEM_NOC] = &slv_srvc_gemnoc,
|
||||||
|
[SLAVE_SERVICE_GEM_NOC_1] = &slv_srvc_gemnoc1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_node *ipa_virt_nodes[] = {
|
||||||
|
[MASTER_IPA_CORE] = &mas_ipa_core_master,
|
||||||
|
[SLAVE_IPA_CORE] = &slv_ipa_core_slave,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_node *mc_virt_nodes[] = {
|
||||||
|
[MASTER_LLCC] = &mas_llcc_mc,
|
||||||
|
[SLAVE_EBI_CH0] = &slv_ebi,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_node *mmss_noc_nodes[] = {
|
||||||
|
[MASTER_CNOC_MNOC_CFG] = &mas_qhm_mnoc_cfg,
|
||||||
|
[MASTER_CAMNOC_HF0] = &mas_qxm_camnoc_hf0,
|
||||||
|
[MASTER_CAMNOC_HF1] = &mas_qxm_camnoc_hf1,
|
||||||
|
[MASTER_CAMNOC_SF] = &mas_qxm_camnoc_sf,
|
||||||
|
[MASTER_MDP_PORT0] = &mas_qxm_mdp0,
|
||||||
|
[MASTER_MDP_PORT1] = &mas_qxm_mdp1,
|
||||||
|
[MASTER_ROTATOR] = &mas_qxm_rot,
|
||||||
|
[MASTER_VIDEO_P0] = &mas_qxm_venus0,
|
||||||
|
[MASTER_VIDEO_P1] = &mas_qxm_venus1,
|
||||||
|
[MASTER_VIDEO_PROC] = &mas_qxm_venus_arm9,
|
||||||
|
[SLAVE_MNOC_SF_MEM_NOC] = &slv_qns2_mem_noc,
|
||||||
|
[SLAVE_MNOC_HF_MEM_NOC] = &slv_qns_mem_noc_hf,
|
||||||
|
[SLAVE_SERVICE_MNOC] = &slv_srvc_mnoc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct qcom_icc_node *system_noc_nodes[] = {
|
||||||
|
[MASTER_SNOC_CFG] = &mas_qhm_snoc_cfg,
|
||||||
|
[A1NOC_SNOC_MAS] = &mas_qnm_aggre1_noc,
|
||||||
|
[A2NOC_SNOC_MAS] = &mas_qnm_aggre2_noc,
|
||||||
|
[MASTER_GEM_NOC_SNOC] = &mas_qnm_gemnoc,
|
||||||
|
[MASTER_PIMEM] = &mas_qxm_pimem,
|
||||||
|
[MASTER_GIC] = &mas_xm_gic,
|
||||||
|
[SLAVE_APPSS] = &slv_qhs_apss,
|
||||||
|
[SNOC_CNOC_SLV] = &slv_qns_cnoc,
|
||||||
|
[SLAVE_SNOC_GEM_NOC_GC] = &slv_qns_gemnoc_gc,
|
||||||
|
[SLAVE_SNOC_GEM_NOC_SF] = &slv_qns_gemnoc_sf,
|
||||||
|
[SLAVE_OCIMEM] = &slv_qxs_imem,
|
||||||
|
[SLAVE_PIMEM] = &slv_qxs_pimem,
|
||||||
|
[SLAVE_SERVICE_SNOC] = &slv_srvc_snoc,
|
||||||
|
[SLAVE_QDSS_STM] = &slv_xs_qdss_stm,
|
||||||
|
[SLAVE_TCU] = &slv_xs_sys_tcu_cfg,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_icc_desc sc8180x_aggre1_noc = {
|
||||||
|
.nodes = aggre1_noc_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(aggre1_noc_nodes),
|
||||||
|
.bcms = aggre1_noc_bcms,
|
||||||
|
.num_bcms = ARRAY_SIZE(aggre1_noc_bcms),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_icc_desc sc8180x_aggre2_noc = {
|
||||||
|
.nodes = aggre2_noc_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(aggre2_noc_nodes),
|
||||||
|
.bcms = aggre2_noc_bcms,
|
||||||
|
.num_bcms = ARRAY_SIZE(aggre2_noc_bcms),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_icc_desc sc8180x_camnoc_virt = {
|
||||||
|
.nodes = camnoc_virt_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(camnoc_virt_nodes),
|
||||||
|
.bcms = camnoc_virt_bcms,
|
||||||
|
.num_bcms = ARRAY_SIZE(camnoc_virt_bcms),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_icc_desc sc8180x_compute_noc = {
|
||||||
|
.nodes = compute_noc_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(compute_noc_nodes),
|
||||||
|
.bcms = compute_noc_bcms,
|
||||||
|
.num_bcms = ARRAY_SIZE(compute_noc_bcms),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_icc_desc sc8180x_config_noc = {
|
||||||
|
.nodes = config_noc_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(config_noc_nodes),
|
||||||
|
.bcms = config_noc_bcms,
|
||||||
|
.num_bcms = ARRAY_SIZE(config_noc_bcms),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_icc_desc sc8180x_dc_noc = {
|
||||||
|
.nodes = dc_noc_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(dc_noc_nodes),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_icc_desc sc8180x_gem_noc = {
|
||||||
|
.nodes = gem_noc_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(gem_noc_nodes),
|
||||||
|
.bcms = gem_noc_bcms,
|
||||||
|
.num_bcms = ARRAY_SIZE(gem_noc_bcms),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_icc_desc sc8180x_ipa_virt = {
|
||||||
|
.nodes = ipa_virt_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(ipa_virt_nodes),
|
||||||
|
.bcms = ipa_virt_bcms,
|
||||||
|
.num_bcms = ARRAY_SIZE(ipa_virt_bcms),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_icc_desc sc8180x_mc_virt = {
|
||||||
|
.nodes = mc_virt_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(mc_virt_nodes),
|
||||||
|
.bcms = mc_virt_bcms,
|
||||||
|
.num_bcms = ARRAY_SIZE(mc_virt_bcms),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_icc_desc sc8180x_mmss_noc = {
|
||||||
|
.nodes = mmss_noc_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(mmss_noc_nodes),
|
||||||
|
.bcms = mmss_noc_bcms,
|
||||||
|
.num_bcms = ARRAY_SIZE(mmss_noc_bcms),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_icc_desc sc8180x_system_noc = {
|
||||||
|
.nodes = system_noc_nodes,
|
||||||
|
.num_nodes = ARRAY_SIZE(system_noc_nodes),
|
||||||
|
.bcms = system_noc_bcms,
|
||||||
|
.num_bcms = ARRAY_SIZE(system_noc_bcms),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int qnoc_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
const struct qcom_icc_desc *desc;
|
||||||
|
struct icc_onecell_data *data;
|
||||||
|
struct icc_provider *provider;
|
||||||
|
struct qcom_icc_node **qnodes;
|
||||||
|
struct qcom_icc_provider *qp;
|
||||||
|
struct icc_node *node;
|
||||||
|
size_t num_nodes, i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
desc = device_get_match_data(&pdev->dev);
|
||||||
|
if (!desc)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
qnodes = desc->nodes;
|
||||||
|
num_nodes = desc->num_nodes;
|
||||||
|
|
||||||
|
qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
|
||||||
|
if (!qp)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
provider = &qp->provider;
|
||||||
|
provider->dev = &pdev->dev;
|
||||||
|
provider->set = qcom_icc_set;
|
||||||
|
provider->pre_aggregate = qcom_icc_pre_aggregate;
|
||||||
|
provider->aggregate = qcom_icc_aggregate;
|
||||||
|
provider->xlate = of_icc_xlate_onecell;
|
||||||
|
INIT_LIST_HEAD(&provider->nodes);
|
||||||
|
provider->data = data;
|
||||||
|
|
||||||
|
qp->dev = &pdev->dev;
|
||||||
|
qp->bcms = desc->bcms;
|
||||||
|
qp->num_bcms = desc->num_bcms;
|
||||||
|
|
||||||
|
qp->voter = of_bcm_voter_get(qp->dev, NULL);
|
||||||
|
if (IS_ERR(qp->voter))
|
||||||
|
return PTR_ERR(qp->voter);
|
||||||
|
|
||||||
|
ret = icc_provider_add(provider);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "error adding interconnect provider\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < qp->num_bcms; i++)
|
||||||
|
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
|
||||||
|
|
||||||
|
for (i = 0; i < num_nodes; i++) {
|
||||||
|
size_t j;
|
||||||
|
|
||||||
|
if (!qnodes[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
node = icc_node_create(qnodes[i]->id);
|
||||||
|
if (IS_ERR(node)) {
|
||||||
|
ret = PTR_ERR(node);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->name = qnodes[i]->name;
|
||||||
|
node->data = qnodes[i];
|
||||||
|
icc_node_add(node, provider);
|
||||||
|
|
||||||
|
for (j = 0; j < qnodes[i]->num_links; j++)
|
||||||
|
icc_link_create(node, qnodes[i]->links[j]);
|
||||||
|
|
||||||
|
data->nodes[i] = node;
|
||||||
|
}
|
||||||
|
data->num_nodes = num_nodes;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, qp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
|
icc_nodes_remove(provider);
|
||||||
|
icc_provider_del(provider);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qnoc_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
icc_nodes_remove(&qp->provider);
|
||||||
|
return icc_provider_del(&qp->provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id qnoc_of_match[] = {
|
||||||
|
{ .compatible = "qcom,sc8180x-aggre1-noc", .data = &sc8180x_aggre1_noc },
|
||||||
|
{ .compatible = "qcom,sc8180x-aggre2-noc", .data = &sc8180x_aggre2_noc },
|
||||||
|
{ .compatible = "qcom,sc8180x-camnoc-virt", .data = &sc8180x_camnoc_virt },
|
||||||
|
{ .compatible = "qcom,sc8180x-compute-noc", .data = &sc8180x_compute_noc, },
|
||||||
|
{ .compatible = "qcom,sc8180x-config-noc", .data = &sc8180x_config_noc },
|
||||||
|
{ .compatible = "qcom,sc8180x-dc-noc", .data = &sc8180x_dc_noc },
|
||||||
|
{ .compatible = "qcom,sc8180x-gem-noc", .data = &sc8180x_gem_noc },
|
||||||
|
{ .compatible = "qcom,sc8180x-ipa-virt", .data = &sc8180x_ipa_virt },
|
||||||
|
{ .compatible = "qcom,sc8180x-mc-virt", .data = &sc8180x_mc_virt },
|
||||||
|
{ .compatible = "qcom,sc8180x-mmss-noc", .data = &sc8180x_mmss_noc },
|
||||||
|
{ .compatible = "qcom,sc8180x-system-noc", .data = &sc8180x_system_noc },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver qnoc_driver = {
|
||||||
|
.probe = qnoc_probe,
|
||||||
|
.remove = qnoc_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "qnoc-sc8180x",
|
||||||
|
.of_match_table = qnoc_of_match,
|
||||||
|
.sync_state = icc_sync_state,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(qnoc_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Qualcomm sc8180x NoC driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
174
drivers/interconnect/qcom/sc8180x.h
Normal file
174
drivers/interconnect/qcom/sc8180x.h
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Qualcomm #define SC8180X interconnect IDs
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DRIVERS_INTERCONNECT_QCOM_SC8180X_H
|
||||||
|
#define __DRIVERS_INTERCONNECT_QCOM_SC8180X_H
|
||||||
|
|
||||||
|
#define SC8180X_MASTER_A1NOC_CFG 1
|
||||||
|
#define SC8180X_MASTER_UFS_CARD 2
|
||||||
|
#define SC8180X_MASTER_UFS_GEN4 3
|
||||||
|
#define SC8180X_MASTER_UFS_MEM 4
|
||||||
|
#define SC8180X_MASTER_USB3 5
|
||||||
|
#define SC8180X_MASTER_USB3_1 6
|
||||||
|
#define SC8180X_MASTER_USB3_2 7
|
||||||
|
#define SC8180X_MASTER_A2NOC_CFG 8
|
||||||
|
#define SC8180X_MASTER_QDSS_BAM 9
|
||||||
|
#define SC8180X_MASTER_QSPI_0 10
|
||||||
|
#define SC8180X_MASTER_QSPI_1 11
|
||||||
|
#define SC8180X_MASTER_QUP_0 12
|
||||||
|
#define SC8180X_MASTER_QUP_1 13
|
||||||
|
#define SC8180X_MASTER_QUP_2 14
|
||||||
|
#define SC8180X_MASTER_SENSORS_AHB 15
|
||||||
|
#define SC8180X_MASTER_CRYPTO_CORE_0 16
|
||||||
|
#define SC8180X_MASTER_IPA 17
|
||||||
|
#define SC8180X_MASTER_EMAC 18
|
||||||
|
#define SC8180X_MASTER_PCIE 19
|
||||||
|
#define SC8180X_MASTER_PCIE_1 20
|
||||||
|
#define SC8180X_MASTER_PCIE_2 21
|
||||||
|
#define SC8180X_MASTER_PCIE_3 22
|
||||||
|
#define SC8180X_MASTER_QDSS_ETR 23
|
||||||
|
#define SC8180X_MASTER_SDCC_2 24
|
||||||
|
#define SC8180X_MASTER_SDCC_4 25
|
||||||
|
#define SC8180X_MASTER_CAMNOC_HF0_UNCOMP 26
|
||||||
|
#define SC8180X_MASTER_CAMNOC_HF1_UNCOMP 27
|
||||||
|
#define SC8180X_MASTER_CAMNOC_SF_UNCOMP 28
|
||||||
|
#define SC8180X_MASTER_NPU 29
|
||||||
|
#define SC8180X_SNOC_CNOC_MAS 30
|
||||||
|
#define SC8180X_MASTER_CNOC_DC_NOC 31
|
||||||
|
#define SC8180X_MASTER_AMPSS_M0 32
|
||||||
|
#define SC8180X_MASTER_GPU_TCU 33
|
||||||
|
#define SC8180X_MASTER_SYS_TCU 34
|
||||||
|
#define SC8180X_MASTER_GEM_NOC_CFG 35
|
||||||
|
#define SC8180X_MASTER_COMPUTE_NOC 36
|
||||||
|
#define SC8180X_MASTER_GRAPHICS_3D 37
|
||||||
|
#define SC8180X_MASTER_MNOC_HF_MEM_NOC 38
|
||||||
|
#define SC8180X_MASTER_MNOC_SF_MEM_NOC 39
|
||||||
|
#define SC8180X_MASTER_GEM_NOC_PCIE_SNOC 40
|
||||||
|
#define SC8180X_MASTER_SNOC_GC_MEM_NOC 41
|
||||||
|
#define SC8180X_MASTER_SNOC_SF_MEM_NOC 42
|
||||||
|
#define SC8180X_MASTER_ECC 43
|
||||||
|
#define SC8180X_MASTER_IPA_CORE 44
|
||||||
|
#define SC8180X_MASTER_LLCC 45
|
||||||
|
#define SC8180X_MASTER_CNOC_MNOC_CFG 46
|
||||||
|
#define SC8180X_MASTER_CAMNOC_HF0 47
|
||||||
|
#define SC8180X_MASTER_CAMNOC_HF1 48
|
||||||
|
#define SC8180X_MASTER_CAMNOC_SF 49
|
||||||
|
#define SC8180X_MASTER_MDP_PORT0 50
|
||||||
|
#define SC8180X_MASTER_MDP_PORT1 51
|
||||||
|
#define SC8180X_MASTER_ROTATOR 52
|
||||||
|
#define SC8180X_MASTER_VIDEO_P0 53
|
||||||
|
#define SC8180X_MASTER_VIDEO_P1 54
|
||||||
|
#define SC8180X_MASTER_VIDEO_PROC 55
|
||||||
|
#define SC8180X_MASTER_SNOC_CFG 56
|
||||||
|
#define SC8180X_A1NOC_SNOC_MAS 57
|
||||||
|
#define SC8180X_A2NOC_SNOC_MAS 58
|
||||||
|
#define SC8180X_MASTER_GEM_NOC_SNOC 59
|
||||||
|
#define SC8180X_MASTER_PIMEM 60
|
||||||
|
#define SC8180X_MASTER_GIC 61
|
||||||
|
#define SC8180X_MASTER_MNOC_HF_MEM_NOC_DISPLAY 62
|
||||||
|
#define SC8180X_MASTER_MNOC_SF_MEM_NOC_DISPLAY 63
|
||||||
|
#define SC8180X_MASTER_LLCC_DISPLAY 64
|
||||||
|
#define SC8180X_MASTER_MDP_PORT0_DISPLAY 65
|
||||||
|
#define SC8180X_MASTER_MDP_PORT1_DISPLAY 66
|
||||||
|
#define SC8180X_MASTER_ROTATOR_DISPLAY 67
|
||||||
|
#define SC8180X_A1NOC_SNOC_SLV 68
|
||||||
|
#define SC8180X_SLAVE_SERVICE_A1NOC 69
|
||||||
|
#define SC8180X_A2NOC_SNOC_SLV 70
|
||||||
|
#define SC8180X_SLAVE_ANOC_PCIE_GEM_NOC 71
|
||||||
|
#define SC8180X_SLAVE_SERVICE_A2NOC 72
|
||||||
|
#define SC8180X_SLAVE_CAMNOC_UNCOMP 73
|
||||||
|
#define SC8180X_SLAVE_CDSP_MEM_NOC 74
|
||||||
|
#define SC8180X_SLAVE_A1NOC_CFG 75
|
||||||
|
#define SC8180X_SLAVE_A2NOC_CFG 76
|
||||||
|
#define SC8180X_SLAVE_AHB2PHY_CENTER 77
|
||||||
|
#define SC8180X_SLAVE_AHB2PHY_EAST 78
|
||||||
|
#define SC8180X_SLAVE_AHB2PHY_WEST 79
|
||||||
|
#define SC8180X_SLAVE_AHB2PHY_SOUTH 80
|
||||||
|
#define SC8180X_SLAVE_AOP 81
|
||||||
|
#define SC8180X_SLAVE_AOSS 82
|
||||||
|
#define SC8180X_SLAVE_CAMERA_CFG 83
|
||||||
|
#define SC8180X_SLAVE_CLK_CTL 84
|
||||||
|
#define SC8180X_SLAVE_CDSP_CFG 85
|
||||||
|
#define SC8180X_SLAVE_RBCPR_CX_CFG 86
|
||||||
|
#define SC8180X_SLAVE_RBCPR_MMCX_CFG 87
|
||||||
|
#define SC8180X_SLAVE_RBCPR_MX_CFG 88
|
||||||
|
#define SC8180X_SLAVE_CRYPTO_0_CFG 89
|
||||||
|
#define SC8180X_SLAVE_CNOC_DDRSS 90
|
||||||
|
#define SC8180X_SLAVE_DISPLAY_CFG 91
|
||||||
|
#define SC8180X_SLAVE_EMAC_CFG 92
|
||||||
|
#define SC8180X_SLAVE_GLM 93
|
||||||
|
#define SC8180X_SLAVE_GRAPHICS_3D_CFG 94
|
||||||
|
#define SC8180X_SLAVE_IMEM_CFG 95
|
||||||
|
#define SC8180X_SLAVE_IPA_CFG 96
|
||||||
|
#define SC8180X_SLAVE_CNOC_MNOC_CFG 97
|
||||||
|
#define SC8180X_SLAVE_NPU_CFG 98
|
||||||
|
#define SC8180X_SLAVE_PCIE_0_CFG 99
|
||||||
|
#define SC8180X_SLAVE_PCIE_1_CFG 100
|
||||||
|
#define SC8180X_SLAVE_PCIE_2_CFG 101
|
||||||
|
#define SC8180X_SLAVE_PCIE_3_CFG 102
|
||||||
|
#define SC8180X_SLAVE_PDM 103
|
||||||
|
#define SC8180X_SLAVE_PIMEM_CFG 104
|
||||||
|
#define SC8180X_SLAVE_PRNG 105
|
||||||
|
#define SC8180X_SLAVE_QDSS_CFG 106
|
||||||
|
#define SC8180X_SLAVE_QSPI_0 107
|
||||||
|
#define SC8180X_SLAVE_QSPI_1 108
|
||||||
|
#define SC8180X_SLAVE_QUP_1 109
|
||||||
|
#define SC8180X_SLAVE_QUP_2 110
|
||||||
|
#define SC8180X_SLAVE_QUP_0 111
|
||||||
|
#define SC8180X_SLAVE_SDCC_2 112
|
||||||
|
#define SC8180X_SLAVE_SDCC_4 113
|
||||||
|
#define SC8180X_SLAVE_SECURITY 114
|
||||||
|
#define SC8180X_SLAVE_SNOC_CFG 115
|
||||||
|
#define SC8180X_SLAVE_SPSS_CFG 116
|
||||||
|
#define SC8180X_SLAVE_TCSR 117
|
||||||
|
#define SC8180X_SLAVE_TLMM_EAST 118
|
||||||
|
#define SC8180X_SLAVE_TLMM_SOUTH 119
|
||||||
|
#define SC8180X_SLAVE_TLMM_WEST 120
|
||||||
|
#define SC8180X_SLAVE_TSIF 121
|
||||||
|
#define SC8180X_SLAVE_UFS_CARD_CFG 122
|
||||||
|
#define SC8180X_SLAVE_UFS_MEM_0_CFG 123
|
||||||
|
#define SC8180X_SLAVE_UFS_MEM_1_CFG 124
|
||||||
|
#define SC8180X_SLAVE_USB3 125
|
||||||
|
#define SC8180X_SLAVE_USB3_1 126
|
||||||
|
#define SC8180X_SLAVE_USB3_2 127
|
||||||
|
#define SC8180X_SLAVE_VENUS_CFG 128
|
||||||
|
#define SC8180X_SLAVE_VSENSE_CTRL_CFG 129
|
||||||
|
#define SC8180X_SLAVE_SERVICE_CNOC 130
|
||||||
|
#define SC8180X_SLAVE_GEM_NOC_CFG 131
|
||||||
|
#define SC8180X_SLAVE_LLCC_CFG 132
|
||||||
|
#define SC8180X_SLAVE_MSS_PROC_MS_MPU_CFG 133
|
||||||
|
#define SC8180X_SLAVE_ECC 134
|
||||||
|
#define SC8180X_SLAVE_GEM_NOC_SNOC 135
|
||||||
|
#define SC8180X_SLAVE_LLCC 136
|
||||||
|
#define SC8180X_SLAVE_SERVICE_GEM_NOC 137
|
||||||
|
#define SC8180X_SLAVE_SERVICE_GEM_NOC_1 138
|
||||||
|
#define SC8180X_SLAVE_IPA_CORE 139
|
||||||
|
#define SC8180X_SLAVE_EBI_CH0 140
|
||||||
|
#define SC8180X_SLAVE_MNOC_SF_MEM_NOC 141
|
||||||
|
#define SC8180X_SLAVE_MNOC_HF_MEM_NOC 142
|
||||||
|
#define SC8180X_SLAVE_SERVICE_MNOC 143
|
||||||
|
#define SC8180X_SLAVE_APPSS 144
|
||||||
|
#define SC8180X_SNOC_CNOC_SLV 145
|
||||||
|
#define SC8180X_SLAVE_SNOC_GEM_NOC_GC 146
|
||||||
|
#define SC8180X_SLAVE_SNOC_GEM_NOC_SF 147
|
||||||
|
#define SC8180X_SLAVE_OCIMEM 148
|
||||||
|
#define SC8180X_SLAVE_PIMEM 149
|
||||||
|
#define SC8180X_SLAVE_SERVICE_SNOC 150
|
||||||
|
#define SC8180X_SLAVE_PCIE_0 151
|
||||||
|
#define SC8180X_SLAVE_PCIE_1 152
|
||||||
|
#define SC8180X_SLAVE_PCIE_2 153
|
||||||
|
#define SC8180X_SLAVE_PCIE_3 154
|
||||||
|
#define SC8180X_SLAVE_QDSS_STM 155
|
||||||
|
#define SC8180X_SLAVE_TCU 156
|
||||||
|
#define SC8180X_SLAVE_LLCC_DISPLAY 157
|
||||||
|
#define SC8180X_SLAVE_EBI_CH0_DISPLAY 158
|
||||||
|
#define SC8180X_SLAVE_MNOC_SF_MEM_NOC_DISPLAY 159
|
||||||
|
#define SC8180X_SLAVE_MNOC_HF_MEM_NOC_DISPLAY 160
|
||||||
|
#define SC8180X_MASTER_OSM_L3_APPS 161
|
||||||
|
#define SC8180X_SLAVE_OSM_L3 162
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -440,101 +440,6 @@ static const struct qcom_icc_desc sdm845_system_noc = {
|
|||||||
.num_bcms = ARRAY_SIZE(system_noc_bcms),
|
.num_bcms = ARRAY_SIZE(system_noc_bcms),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int qnoc_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
const struct qcom_icc_desc *desc;
|
|
||||||
struct icc_onecell_data *data;
|
|
||||||
struct icc_provider *provider;
|
|
||||||
struct qcom_icc_node **qnodes;
|
|
||||||
struct qcom_icc_provider *qp;
|
|
||||||
struct icc_node *node;
|
|
||||||
size_t num_nodes, i;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
desc = device_get_match_data(&pdev->dev);
|
|
||||||
if (!desc)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
qnodes = desc->nodes;
|
|
||||||
num_nodes = desc->num_nodes;
|
|
||||||
|
|
||||||
qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
|
|
||||||
if (!qp)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
data = devm_kzalloc(&pdev->dev, struct_size(data, nodes, num_nodes),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!data)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
provider = &qp->provider;
|
|
||||||
provider->dev = &pdev->dev;
|
|
||||||
provider->set = qcom_icc_set;
|
|
||||||
provider->pre_aggregate = qcom_icc_pre_aggregate;
|
|
||||||
provider->aggregate = qcom_icc_aggregate;
|
|
||||||
provider->xlate_extended = qcom_icc_xlate_extended;
|
|
||||||
INIT_LIST_HEAD(&provider->nodes);
|
|
||||||
provider->data = data;
|
|
||||||
|
|
||||||
qp->dev = &pdev->dev;
|
|
||||||
qp->bcms = desc->bcms;
|
|
||||||
qp->num_bcms = desc->num_bcms;
|
|
||||||
|
|
||||||
qp->voter = of_bcm_voter_get(qp->dev, NULL);
|
|
||||||
if (IS_ERR(qp->voter)) {
|
|
||||||
dev_err(&pdev->dev, "bcm_voter err:%ld\n", PTR_ERR(qp->voter));
|
|
||||||
return PTR_ERR(qp->voter);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = icc_provider_add(provider);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "error adding interconnect provider\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < qp->num_bcms; i++)
|
|
||||||
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
|
|
||||||
|
|
||||||
for (i = 0; i < num_nodes; i++) {
|
|
||||||
size_t j;
|
|
||||||
|
|
||||||
if (!qnodes[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
node = icc_node_create(qnodes[i]->id);
|
|
||||||
if (IS_ERR(node)) {
|
|
||||||
ret = PTR_ERR(node);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->name = qnodes[i]->name;
|
|
||||||
node->data = qnodes[i];
|
|
||||||
icc_node_add(node, provider);
|
|
||||||
|
|
||||||
for (j = 0; j < qnodes[i]->num_links; j++)
|
|
||||||
icc_link_create(node, qnodes[i]->links[j]);
|
|
||||||
|
|
||||||
data->nodes[i] = node;
|
|
||||||
}
|
|
||||||
data->num_nodes = num_nodes;
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, qp);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
err:
|
|
||||||
icc_nodes_remove(provider);
|
|
||||||
icc_provider_del(provider);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int qnoc_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
icc_nodes_remove(&qp->provider);
|
|
||||||
return icc_provider_del(&qp->provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct of_device_id qnoc_of_match[] = {
|
static const struct of_device_id qnoc_of_match[] = {
|
||||||
{ .compatible = "qcom,sdm845-aggre1-noc",
|
{ .compatible = "qcom,sdm845-aggre1-noc",
|
||||||
.data = &sdm845_aggre1_noc},
|
.data = &sdm845_aggre1_noc},
|
||||||
@@ -557,8 +462,8 @@ static const struct of_device_id qnoc_of_match[] = {
|
|||||||
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
||||||
|
|
||||||
static struct platform_driver qnoc_driver = {
|
static struct platform_driver qnoc_driver = {
|
||||||
.probe = qnoc_probe,
|
.probe = qcom_icc_rpmh_probe,
|
||||||
.remove = qnoc_remove,
|
.remove = qcom_icc_rpmh_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "qnoc-sdm845",
|
.name = "qnoc-sdm845",
|
||||||
.of_match_table = qnoc_of_match,
|
.of_match_table = qnoc_of_match,
|
||||||
|
|||||||
@@ -235,98 +235,6 @@ static const struct qcom_icc_desc sdx55_ipa_virt = {
|
|||||||
.num_bcms = ARRAY_SIZE(ipa_virt_bcms),
|
.num_bcms = ARRAY_SIZE(ipa_virt_bcms),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int qnoc_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
const struct qcom_icc_desc *desc;
|
|
||||||
struct icc_onecell_data *data;
|
|
||||||
struct icc_provider *provider;
|
|
||||||
struct qcom_icc_node **qnodes;
|
|
||||||
struct qcom_icc_provider *qp;
|
|
||||||
struct icc_node *node;
|
|
||||||
size_t num_nodes, i;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
desc = device_get_match_data(&pdev->dev);
|
|
||||||
if (!desc)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
qnodes = desc->nodes;
|
|
||||||
num_nodes = desc->num_nodes;
|
|
||||||
|
|
||||||
qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
|
|
||||||
if (!qp)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL);
|
|
||||||
if (!data)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
provider = &qp->provider;
|
|
||||||
provider->dev = &pdev->dev;
|
|
||||||
provider->set = qcom_icc_set;
|
|
||||||
provider->pre_aggregate = qcom_icc_pre_aggregate;
|
|
||||||
provider->aggregate = qcom_icc_aggregate;
|
|
||||||
provider->xlate = of_icc_xlate_onecell;
|
|
||||||
INIT_LIST_HEAD(&provider->nodes);
|
|
||||||
provider->data = data;
|
|
||||||
|
|
||||||
qp->dev = &pdev->dev;
|
|
||||||
qp->bcms = desc->bcms;
|
|
||||||
qp->num_bcms = desc->num_bcms;
|
|
||||||
|
|
||||||
qp->voter = of_bcm_voter_get(qp->dev, NULL);
|
|
||||||
if (IS_ERR(qp->voter))
|
|
||||||
return PTR_ERR(qp->voter);
|
|
||||||
|
|
||||||
ret = icc_provider_add(provider);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "error adding interconnect provider\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < qp->num_bcms; i++)
|
|
||||||
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
|
|
||||||
|
|
||||||
for (i = 0; i < num_nodes; i++) {
|
|
||||||
size_t j;
|
|
||||||
|
|
||||||
if (!qnodes[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
node = icc_node_create(qnodes[i]->id);
|
|
||||||
if (IS_ERR(node)) {
|
|
||||||
ret = PTR_ERR(node);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->name = qnodes[i]->name;
|
|
||||||
node->data = qnodes[i];
|
|
||||||
icc_node_add(node, provider);
|
|
||||||
|
|
||||||
for (j = 0; j < qnodes[i]->num_links; j++)
|
|
||||||
icc_link_create(node, qnodes[i]->links[j]);
|
|
||||||
|
|
||||||
data->nodes[i] = node;
|
|
||||||
}
|
|
||||||
data->num_nodes = num_nodes;
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, qp);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
err:
|
|
||||||
icc_nodes_remove(provider);
|
|
||||||
icc_provider_del(provider);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int qnoc_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
icc_nodes_remove(&qp->provider);
|
|
||||||
return icc_provider_del(&qp->provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct of_device_id qnoc_of_match[] = {
|
static const struct of_device_id qnoc_of_match[] = {
|
||||||
{ .compatible = "qcom,sdx55-mc-virt",
|
{ .compatible = "qcom,sdx55-mc-virt",
|
||||||
.data = &sdx55_mc_virt},
|
.data = &sdx55_mc_virt},
|
||||||
@@ -341,8 +249,8 @@ static const struct of_device_id qnoc_of_match[] = {
|
|||||||
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
||||||
|
|
||||||
static struct platform_driver qnoc_driver = {
|
static struct platform_driver qnoc_driver = {
|
||||||
.probe = qnoc_probe,
|
.probe = qcom_icc_rpmh_probe,
|
||||||
.remove = qnoc_remove,
|
.remove = qcom_icc_rpmh_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "qnoc-sdx55",
|
.name = "qnoc-sdx55",
|
||||||
.of_match_table = qnoc_of_match,
|
.of_match_table = qnoc_of_match,
|
||||||
|
|||||||
@@ -502,98 +502,6 @@ static struct qcom_icc_desc sm8150_system_noc = {
|
|||||||
.num_bcms = ARRAY_SIZE(system_noc_bcms),
|
.num_bcms = ARRAY_SIZE(system_noc_bcms),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int qnoc_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
const struct qcom_icc_desc *desc;
|
|
||||||
struct icc_onecell_data *data;
|
|
||||||
struct icc_provider *provider;
|
|
||||||
struct qcom_icc_node **qnodes;
|
|
||||||
struct qcom_icc_provider *qp;
|
|
||||||
struct icc_node *node;
|
|
||||||
size_t num_nodes, i;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
desc = device_get_match_data(&pdev->dev);
|
|
||||||
if (!desc)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
qnodes = desc->nodes;
|
|
||||||
num_nodes = desc->num_nodes;
|
|
||||||
|
|
||||||
qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
|
|
||||||
if (!qp)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL);
|
|
||||||
if (!data)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
provider = &qp->provider;
|
|
||||||
provider->dev = &pdev->dev;
|
|
||||||
provider->set = qcom_icc_set;
|
|
||||||
provider->pre_aggregate = qcom_icc_pre_aggregate;
|
|
||||||
provider->aggregate = qcom_icc_aggregate;
|
|
||||||
provider->xlate = of_icc_xlate_onecell;
|
|
||||||
INIT_LIST_HEAD(&provider->nodes);
|
|
||||||
provider->data = data;
|
|
||||||
|
|
||||||
qp->dev = &pdev->dev;
|
|
||||||
qp->bcms = desc->bcms;
|
|
||||||
qp->num_bcms = desc->num_bcms;
|
|
||||||
|
|
||||||
qp->voter = of_bcm_voter_get(qp->dev, NULL);
|
|
||||||
if (IS_ERR(qp->voter))
|
|
||||||
return PTR_ERR(qp->voter);
|
|
||||||
|
|
||||||
ret = icc_provider_add(provider);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "error adding interconnect provider\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < qp->num_bcms; i++)
|
|
||||||
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
|
|
||||||
|
|
||||||
for (i = 0; i < num_nodes; i++) {
|
|
||||||
size_t j;
|
|
||||||
|
|
||||||
if (!qnodes[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
node = icc_node_create(qnodes[i]->id);
|
|
||||||
if (IS_ERR(node)) {
|
|
||||||
ret = PTR_ERR(node);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->name = qnodes[i]->name;
|
|
||||||
node->data = qnodes[i];
|
|
||||||
icc_node_add(node, provider);
|
|
||||||
|
|
||||||
for (j = 0; j < qnodes[i]->num_links; j++)
|
|
||||||
icc_link_create(node, qnodes[i]->links[j]);
|
|
||||||
|
|
||||||
data->nodes[i] = node;
|
|
||||||
}
|
|
||||||
data->num_nodes = num_nodes;
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, qp);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
err:
|
|
||||||
icc_nodes_remove(provider);
|
|
||||||
icc_provider_del(provider);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int qnoc_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
icc_nodes_remove(&qp->provider);
|
|
||||||
return icc_provider_del(&qp->provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct of_device_id qnoc_of_match[] = {
|
static const struct of_device_id qnoc_of_match[] = {
|
||||||
{ .compatible = "qcom,sm8150-aggre1-noc",
|
{ .compatible = "qcom,sm8150-aggre1-noc",
|
||||||
.data = &sm8150_aggre1_noc},
|
.data = &sm8150_aggre1_noc},
|
||||||
@@ -622,8 +530,8 @@ static const struct of_device_id qnoc_of_match[] = {
|
|||||||
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
||||||
|
|
||||||
static struct platform_driver qnoc_driver = {
|
static struct platform_driver qnoc_driver = {
|
||||||
.probe = qnoc_probe,
|
.probe = qcom_icc_rpmh_probe,
|
||||||
.remove = qnoc_remove,
|
.remove = qcom_icc_rpmh_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "qnoc-sm8150",
|
.name = "qnoc-sm8150",
|
||||||
.of_match_table = qnoc_of_match,
|
.of_match_table = qnoc_of_match,
|
||||||
|
|||||||
@@ -518,98 +518,6 @@ static struct qcom_icc_desc sm8250_system_noc = {
|
|||||||
.num_bcms = ARRAY_SIZE(system_noc_bcms),
|
.num_bcms = ARRAY_SIZE(system_noc_bcms),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int qnoc_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
const struct qcom_icc_desc *desc;
|
|
||||||
struct icc_onecell_data *data;
|
|
||||||
struct icc_provider *provider;
|
|
||||||
struct qcom_icc_node **qnodes;
|
|
||||||
struct qcom_icc_provider *qp;
|
|
||||||
struct icc_node *node;
|
|
||||||
size_t num_nodes, i;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
desc = device_get_match_data(&pdev->dev);
|
|
||||||
if (!desc)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
qnodes = desc->nodes;
|
|
||||||
num_nodes = desc->num_nodes;
|
|
||||||
|
|
||||||
qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
|
|
||||||
if (!qp)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL);
|
|
||||||
if (!data)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
provider = &qp->provider;
|
|
||||||
provider->dev = &pdev->dev;
|
|
||||||
provider->set = qcom_icc_set;
|
|
||||||
provider->pre_aggregate = qcom_icc_pre_aggregate;
|
|
||||||
provider->aggregate = qcom_icc_aggregate;
|
|
||||||
provider->xlate = of_icc_xlate_onecell;
|
|
||||||
INIT_LIST_HEAD(&provider->nodes);
|
|
||||||
provider->data = data;
|
|
||||||
|
|
||||||
qp->dev = &pdev->dev;
|
|
||||||
qp->bcms = desc->bcms;
|
|
||||||
qp->num_bcms = desc->num_bcms;
|
|
||||||
|
|
||||||
qp->voter = of_bcm_voter_get(qp->dev, NULL);
|
|
||||||
if (IS_ERR(qp->voter))
|
|
||||||
return PTR_ERR(qp->voter);
|
|
||||||
|
|
||||||
ret = icc_provider_add(provider);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "error adding interconnect provider\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < qp->num_bcms; i++)
|
|
||||||
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
|
|
||||||
|
|
||||||
for (i = 0; i < num_nodes; i++) {
|
|
||||||
size_t j;
|
|
||||||
|
|
||||||
if (!qnodes[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
node = icc_node_create(qnodes[i]->id);
|
|
||||||
if (IS_ERR(node)) {
|
|
||||||
ret = PTR_ERR(node);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->name = qnodes[i]->name;
|
|
||||||
node->data = qnodes[i];
|
|
||||||
icc_node_add(node, provider);
|
|
||||||
|
|
||||||
for (j = 0; j < qnodes[i]->num_links; j++)
|
|
||||||
icc_link_create(node, qnodes[i]->links[j]);
|
|
||||||
|
|
||||||
data->nodes[i] = node;
|
|
||||||
}
|
|
||||||
data->num_nodes = num_nodes;
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, qp);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
err:
|
|
||||||
icc_nodes_remove(provider);
|
|
||||||
icc_provider_del(provider);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int qnoc_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
icc_nodes_remove(&qp->provider);
|
|
||||||
return icc_provider_del(&qp->provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct of_device_id qnoc_of_match[] = {
|
static const struct of_device_id qnoc_of_match[] = {
|
||||||
{ .compatible = "qcom,sm8250-aggre1-noc",
|
{ .compatible = "qcom,sm8250-aggre1-noc",
|
||||||
.data = &sm8250_aggre1_noc},
|
.data = &sm8250_aggre1_noc},
|
||||||
@@ -638,8 +546,8 @@ static const struct of_device_id qnoc_of_match[] = {
|
|||||||
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
||||||
|
|
||||||
static struct platform_driver qnoc_driver = {
|
static struct platform_driver qnoc_driver = {
|
||||||
.probe = qnoc_probe,
|
.probe = qcom_icc_rpmh_probe,
|
||||||
.remove = qnoc_remove,
|
.remove = qcom_icc_rpmh_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "qnoc-sm8250",
|
.name = "qnoc-sm8250",
|
||||||
.of_match_table = qnoc_of_match,
|
.of_match_table = qnoc_of_match,
|
||||||
|
|||||||
@@ -510,99 +510,6 @@ static struct qcom_icc_desc sm8350_system_noc = {
|
|||||||
.num_bcms = ARRAY_SIZE(system_noc_bcms),
|
.num_bcms = ARRAY_SIZE(system_noc_bcms),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int qnoc_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
const struct qcom_icc_desc *desc;
|
|
||||||
struct icc_onecell_data *data;
|
|
||||||
struct icc_provider *provider;
|
|
||||||
struct qcom_icc_node **qnodes;
|
|
||||||
struct qcom_icc_provider *qp;
|
|
||||||
struct icc_node *node;
|
|
||||||
size_t num_nodes, i;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
desc = of_device_get_match_data(&pdev->dev);
|
|
||||||
if (!desc)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
qnodes = desc->nodes;
|
|
||||||
num_nodes = desc->num_nodes;
|
|
||||||
|
|
||||||
qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
|
|
||||||
if (!qp)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL);
|
|
||||||
if (!data)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
provider = &qp->provider;
|
|
||||||
provider->dev = &pdev->dev;
|
|
||||||
provider->set = qcom_icc_set;
|
|
||||||
provider->pre_aggregate = qcom_icc_pre_aggregate;
|
|
||||||
provider->aggregate = qcom_icc_aggregate;
|
|
||||||
provider->xlate = of_icc_xlate_onecell;
|
|
||||||
INIT_LIST_HEAD(&provider->nodes);
|
|
||||||
provider->data = data;
|
|
||||||
|
|
||||||
qp->dev = &pdev->dev;
|
|
||||||
qp->bcms = desc->bcms;
|
|
||||||
qp->num_bcms = desc->num_bcms;
|
|
||||||
|
|
||||||
qp->voter = of_bcm_voter_get(qp->dev, NULL);
|
|
||||||
if (IS_ERR(qp->voter))
|
|
||||||
return PTR_ERR(qp->voter);
|
|
||||||
|
|
||||||
ret = icc_provider_add(provider);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "error adding interconnect provider\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < qp->num_bcms; i++)
|
|
||||||
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
|
|
||||||
|
|
||||||
for (i = 0; i < num_nodes; i++) {
|
|
||||||
size_t j;
|
|
||||||
|
|
||||||
if (!qnodes[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
node = icc_node_create(qnodes[i]->id);
|
|
||||||
if (IS_ERR(node)) {
|
|
||||||
ret = PTR_ERR(node);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->name = qnodes[i]->name;
|
|
||||||
node->data = qnodes[i];
|
|
||||||
icc_node_add(node, provider);
|
|
||||||
|
|
||||||
for (j = 0; j < qnodes[i]->num_links; j++)
|
|
||||||
icc_link_create(node, qnodes[i]->links[j]);
|
|
||||||
|
|
||||||
data->nodes[i] = node;
|
|
||||||
}
|
|
||||||
data->num_nodes = num_nodes;
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, qp);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
err:
|
|
||||||
icc_nodes_remove(provider);
|
|
||||||
icc_provider_del(provider);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int qnoc_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
icc_nodes_remove(&qp->provider);
|
|
||||||
return icc_provider_del(&qp->provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct of_device_id qnoc_of_match[] = {
|
static const struct of_device_id qnoc_of_match[] = {
|
||||||
{ .compatible = "qcom,sm8350-aggre1-noc", .data = &sm8350_aggre1_noc},
|
{ .compatible = "qcom,sm8350-aggre1-noc", .data = &sm8350_aggre1_noc},
|
||||||
{ .compatible = "qcom,sm8350-aggre2-noc", .data = &sm8350_aggre2_noc},
|
{ .compatible = "qcom,sm8350-aggre2-noc", .data = &sm8350_aggre2_noc},
|
||||||
@@ -619,8 +526,8 @@ static const struct of_device_id qnoc_of_match[] = {
|
|||||||
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
MODULE_DEVICE_TABLE(of, qnoc_of_match);
|
||||||
|
|
||||||
static struct platform_driver qnoc_driver = {
|
static struct platform_driver qnoc_driver = {
|
||||||
.probe = qnoc_probe,
|
.probe = qcom_icc_rpmh_probe,
|
||||||
.remove = qnoc_remove,
|
.remove = qcom_icc_rpmh_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "qnoc-sm8350",
|
.name = "qnoc-sm8350",
|
||||||
.of_match_table = qnoc_of_match,
|
.of_match_table = qnoc_of_match,
|
||||||
|
|||||||
@@ -208,6 +208,18 @@ config CS5535_CLOCK_EVENT_SRC
|
|||||||
MFGPTs have a better resolution and max interval than the
|
MFGPTs have a better resolution and max interval than the
|
||||||
generic PIT, and are suitable for use as high-res timers.
|
generic PIT, and are suitable for use as high-res timers.
|
||||||
|
|
||||||
|
config GEHC_ACHC
|
||||||
|
tristate "GEHC ACHC support"
|
||||||
|
depends on SPI && SYSFS
|
||||||
|
depends on SOC_IMX53 || COMPILE_TEST
|
||||||
|
select FW_LOADER
|
||||||
|
help
|
||||||
|
Support for GE ACHC microcontroller, that is part of the GE
|
||||||
|
PPD device.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called gehc-achc.
|
||||||
|
|
||||||
config HP_ILO
|
config HP_ILO
|
||||||
tristate "Channel interface driver for the HP iLO processor"
|
tristate "Channel interface driver for the HP iLO processor"
|
||||||
depends on PCI
|
depends on PCI
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user