Char / Misc driver changes for 5.15-rc1
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 habanna labs 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. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYS+Kyw8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymlpACg0JM+hSeo8T5GtwZksZ1QXXQfh8sAoK6Dt6xF e62OQuuMFT0Un0qOflZk =emH+ -----END PGP SIGNATURE----- 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:
commit
ba1dc7f273
|
@ -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
|
||||
instance unusable. The ``binder-control`` device will be deleted when the
|
||||
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";
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -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:
|
||||
enum:
|
||||
- qcom,sc7180-osm-l3
|
||||
- qcom,sc8180x-osm-l3
|
||||
- qcom,sdm845-osm-l3
|
||||
- qcom,sm8150-osm-l3
|
||||
- qcom,sm8250-epss-l3
|
||||
|
|
|
@ -49,6 +49,17 @@ properties:
|
|||
- qcom,sc7280-mmss-noc
|
||||
- qcom,sc7280-nsp-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-aggre2-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>;
|
||||
};
|
|
@ -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>;
|
||||
};
|
||||
};
|
|
@ -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:
|
||||
description: Our power supply.
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
# Needed if any child nodes are present.
|
||||
"#address-cells":
|
||||
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)
|
||||
%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#
|
||||
|
||||
title: Intel Keem Bay USB PHY bindings
|
|
@ -15,7 +15,7 @@ description: |
|
|||
controllers on MediaTek SoCs, includes USB2.0, USB3.0, PCIe and SATA.
|
||||
|
||||
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:
|
||||
port offset bank
|
||||
|
@ -34,7 +34,7 @@ description: |
|
|||
u2 port2 0x1800 U2PHY_COM
|
||||
...
|
||||
|
||||
Version 2:
|
||||
Version 2/3:
|
||||
port offset bank
|
||||
u2 port0 0x0000 MISC
|
||||
0x0100 FMREG
|
||||
|
@ -59,7 +59,8 @@ description: |
|
|||
|
||||
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
|
||||
added on V2.
|
||||
added on V2; the FMREG bank for slew rate calibration is not used anymore
|
||||
and reserved on V3;
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
|
@ -79,8 +80,11 @@ properties:
|
|||
- mediatek,mt2712-tphy
|
||||
- mediatek,mt7629-tphy
|
||||
- mediatek,mt8183-tphy
|
||||
- mediatek,mt8195-tphy
|
||||
- const: mediatek,generic-tphy-v2
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8195-tphy
|
||||
- const: mediatek,generic-tphy-v3
|
||||
- const: mediatek,mt2701-u3phy
|
||||
deprecated: true
|
||||
- const: mediatek,mt2712-u3phy
|
||||
|
@ -91,7 +95,7 @@ properties:
|
|||
description:
|
||||
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
|
||||
T-PHY V2, such as mt2712.
|
||||
T-PHY V2/V3, such as mt2712.
|
||||
maxItems: 1
|
||||
|
||||
"#address-cells":
|
||||
|
@ -197,6 +201,22 @@ patternProperties:
|
|||
Specify the flag to enable BC1.2 if support it
|
||||
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:
|
||||
- reg
|
||||
- "#phy-cells"
|
||||
|
|
|
@ -18,6 +18,7 @@ properties:
|
|||
compatible:
|
||||
enum:
|
||||
- qcom,ipq6018-qmp-pcie-phy
|
||||
- qcom,ipq6018-qmp-usb3-phy
|
||||
- qcom,ipq8074-qmp-pcie-phy
|
||||
- qcom,ipq8074-qmp-usb3-phy
|
||||
- qcom,msm8996-qmp-pcie-phy
|
||||
|
@ -27,6 +28,7 @@ properties:
|
|||
- qcom,msm8998-qmp-ufs-phy
|
||||
- qcom,msm8998-qmp-usb3-phy
|
||||
- qcom,sc7180-qmp-usb3-phy
|
||||
- qcom,sc8180x-qmp-pcie-phy
|
||||
- qcom,sc8180x-qmp-ufs-phy
|
||||
- qcom,sc8180x-qmp-usb3-phy
|
||||
- qcom,sdm845-qhp-pcie-phy
|
||||
|
@ -34,6 +36,7 @@ properties:
|
|||
- qcom,sdm845-qmp-ufs-phy
|
||||
- qcom,sdm845-qmp-usb3-phy
|
||||
- qcom,sdm845-qmp-usb3-uni-phy
|
||||
- qcom,sm6115-qmp-ufs-phy
|
||||
- qcom,sm8150-qmp-ufs-phy
|
||||
- qcom,sm8150-qmp-usb3-phy
|
||||
- qcom,sm8150-qmp-usb3-uni-phy
|
||||
|
@ -326,6 +329,7 @@ allOf:
|
|||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sc8180x-qmp-pcie-phy
|
||||
- qcom,sdm845-qhp-pcie-phy
|
||||
- qcom,sdm845-qmp-pcie-phy
|
||||
- qcom,sdx55-qmp-pcie-phy
|
||||
|
|
|
@ -14,6 +14,7 @@ properties:
|
|||
compatible:
|
||||
enum:
|
||||
- qcom,sc7180-qmp-usb3-dp-phy
|
||||
- qcom,sc8180x-qmp-usb3-dp-phy
|
||||
- qcom,sdm845-qmp-usb3-dp-phy
|
||||
- qcom,sm8250-qmp-usb3-dp-phy
|
||||
reg:
|
||||
|
|
|
@ -30,6 +30,11 @@ properties:
|
|||
- renesas,usb2-phy-r8a77995 # R-Car D3
|
||||
- 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:
|
||||
maxItems: 1
|
||||
|
||||
|
@ -91,6 +96,16 @@ required:
|
|||
- clocks
|
||||
- '#phy-cells'
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,rzg2l-usb2-phy
|
||||
then:
|
||||
required:
|
||||
- resets
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
@ -16,6 +16,7 @@ properties:
|
|||
compatible:
|
||||
enum:
|
||||
- samsung,exynos7-ufs-phy
|
||||
- samsung,exynosautov9-ufs-phy
|
||||
|
||||
reg:
|
||||
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";
|
||||
};
|
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* struct fpga_bridge — The FPGA Bridge structure
|
||||
* struct fpga_bridge_ops — Low level Bridge driver ops
|
||||
* devm_fpga_bridge_create() — Allocate and init a bridge struct
|
||||
* fpga_bridge_register() — Register a bridge
|
||||
* fpga_bridge_unregister() — Unregister a bridge
|
||||
* struct fpga_bridge - The FPGA Bridge structure
|
||||
* struct fpga_bridge_ops - Low level Bridge driver ops
|
||||
* devm_fpga_bridge_create() - Allocate and init a bridge struct
|
||||
* fpga_bridge_register() - Register a bridge
|
||||
* fpga_bridge_unregister() - Unregister a bridge
|
||||
|
||||
.. kernel-doc:: include/linux/fpga/fpga-bridge.h
|
||||
:functions: fpga_bridge
|
||||
|
|
|
@ -101,12 +101,12 @@ in state.
|
|||
API for implementing a new FPGA Manager driver
|
||||
----------------------------------------------
|
||||
|
||||
* ``fpga_mgr_states`` — Values for :c:expr:`fpga_manager->state`.
|
||||
* struct fpga_manager — the FPGA manager struct
|
||||
* struct fpga_manager_ops — Low level FPGA manager driver ops
|
||||
* devm_fpga_mgr_create() — Allocate and init a manager struct
|
||||
* fpga_mgr_register() — Register an FPGA manager
|
||||
* fpga_mgr_unregister() — Unregister an FPGA manager
|
||||
* ``fpga_mgr_states`` - Values for :c:expr:`fpga_manager->state`.
|
||||
* struct fpga_manager - the FPGA manager struct
|
||||
* struct fpga_manager_ops - Low level FPGA manager driver ops
|
||||
* devm_fpga_mgr_create() - Allocate and init a manager struct
|
||||
* fpga_mgr_register() - Register an FPGA manager
|
||||
* fpga_mgr_unregister() - Unregister an FPGA manager
|
||||
|
||||
.. kernel-doc:: include/linux/fpga/fpga-mgr.h
|
||||
: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
|
||||
---------------------------
|
||||
|
||||
* fpga_region_program_fpga() — Program an FPGA
|
||||
* fpga_image_info() — Specifies what FPGA image to program
|
||||
* fpga_image_info_alloc() — Allocate an FPGA image info struct
|
||||
* fpga_image_info_free() — Free an FPGA image info struct
|
||||
* fpga_region_program_fpga() - Program an FPGA
|
||||
* fpga_image_info() - Specifies what FPGA image to program
|
||||
* fpga_image_info_alloc() - Allocate an FPGA image info struct
|
||||
* fpga_image_info_free() - Free an FPGA image info struct
|
||||
|
||||
.. kernel-doc:: drivers/fpga/fpga-region.c
|
||||
: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
|
||||
----------------------------
|
||||
|
||||
* struct fpga_region — The FPGA region struct
|
||||
* devm_fpga_region_create() — Allocate and init a region struct
|
||||
* fpga_region_register() — Register an FPGA region
|
||||
* fpga_region_unregister() — Unregister an FPGA region
|
||||
* struct fpga_region - The FPGA region struct
|
||||
* devm_fpga_region_create() - Allocate and init a region struct
|
||||
* fpga_region_register() - Register 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
|
||||
Manager it will be using to do the programming. This usually would happen
|
||||
during the region's probe function.
|
||||
|
||||
* 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,
|
||||
* 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.
|
||||
* 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. 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
|
||||
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
|
||||
* 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
|
||||
* 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
|
||||
:functions: fpga_region
|
||||
|
|
|
@ -29,8 +29,7 @@ recur_count
|
|||
cpoint_name
|
||||
Where in the kernel to trigger the action. It can be
|
||||
one of INT_HARDWARE_ENTRY, INT_HW_IRQ_EN, INT_TASKLET_ENTRY,
|
||||
FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_DISPATCH_CMD,
|
||||
IDE_CORE_CP, or DIRECT
|
||||
FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_QUEUE_RQ, or DIRECT.
|
||||
|
||||
cpoint_type
|
||||
Indicates the action to be taken on hitting the crash point.
|
||||
|
|
|
@ -10,7 +10,7 @@ Authors:
|
|||
- Xu Yilun <yilun.xu@intel.com>
|
||||
|
||||
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
|
||||
configure, enumerate, open and access FPGA accelerators on platforms which
|
||||
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
|
||||
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
|
||||
created by the system. This driver plays an infrastructural role in the
|
||||
driver architecture. It locates the DFLs in the device memory, handles them
|
||||
|
|
|
@ -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.
|
||||
(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
|
||||
|
||||
|
@ -628,3 +641,5 @@ A separate documentation file is provided to explain the use of these devices.
|
|||
.. [#third] https://github.com/Linaro/perf-opencsd
|
||||
|
||||
.. [#fourth] Documentation/trace/coresight/coresight-ect.rst
|
||||
|
||||
.. [#fifth] Documentation/trace/coresight/coresight-config.rst
|
||||
|
|
|
@ -70,6 +70,12 @@
|
|||
clock-frequency = <11289600>;
|
||||
};
|
||||
|
||||
achc_24M: achc-clock {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <24000000>;
|
||||
};
|
||||
|
||||
sgtlsound: sound {
|
||||
compatible = "fsl,imx53-cpuvo-sgtl5000",
|
||||
"fsl,imx-audio-sgtl5000";
|
||||
|
@ -314,16 +320,13 @@
|
|||
&gpio4 12 GPIO_ACTIVE_LOW>;
|
||||
status = "okay";
|
||||
|
||||
spidev0: spi@0 {
|
||||
compatible = "ge,achc";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
};
|
||||
|
||||
spidev1: spi@1 {
|
||||
compatible = "ge,achc";
|
||||
reg = <1>;
|
||||
spi-max-frequency = <1000000>;
|
||||
spidev0: spi@1 {
|
||||
compatible = "ge,achc", "nxp,kinetis-k20";
|
||||
reg = <1>, <0>;
|
||||
vdd-supply = <®_3v3>;
|
||||
vdda-supply = <®_3v3>;
|
||||
clocks = <&achc_24M>;
|
||||
reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
gpioxra0: gpio@2 {
|
||||
|
|
|
@ -90,13 +90,13 @@ static char *speakup_default_msgs[MSG_LAST_INDEX] = {
|
|||
[MSG_COLOR_YELLOW] = "yellow",
|
||||
[MSG_COLOR_WHITE] = "white",
|
||||
[MSG_COLOR_GREY] = "grey",
|
||||
[MSG_COLOR_BRIGHTBLUE] "bright blue",
|
||||
[MSG_COLOR_BRIGHTGREEN] "bright green",
|
||||
[MSG_COLOR_BRIGHTCYAN] "bright cyan",
|
||||
[MSG_COLOR_BRIGHTRED] "bright red",
|
||||
[MSG_COLOR_BRIGHTMAGENTA] "bright magenta",
|
||||
[MSG_COLOR_BRIGHTYELLOW] "bright yellow",
|
||||
[MSG_COLOR_BRIGHTWHITE] "bright white",
|
||||
[MSG_COLOR_BRIGHTBLUE] = "bright blue",
|
||||
[MSG_COLOR_BRIGHTGREEN] = "bright green",
|
||||
[MSG_COLOR_BRIGHTCYAN] = "bright cyan",
|
||||
[MSG_COLOR_BRIGHTRED] = "bright red",
|
||||
[MSG_COLOR_BRIGHTMAGENTA] = "bright magenta",
|
||||
[MSG_COLOR_BRIGHTYELLOW] = "bright yellow",
|
||||
[MSG_COLOR_BRIGHTWHITE] = "bright white",
|
||||
|
||||
/* Names of key states. */
|
||||
[MSG_STATE_DOUBLE] = "double",
|
||||
|
|
|
@ -153,18 +153,25 @@ static char *get_initstring(void)
|
|||
static char buf[40];
|
||||
char *cp;
|
||||
struct var_t *var;
|
||||
size_t len;
|
||||
size_t n;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
cp = buf;
|
||||
len = sizeof(buf);
|
||||
|
||||
var = synth_soft.vars;
|
||||
while (var->var_id != MAXVARS) {
|
||||
if (var->var_id != CAPS_START && var->var_id != CAPS_STOP &&
|
||||
var->var_id != PAUSE && var->var_id != DIRECT)
|
||||
cp = cp + sprintf(cp, var->u.n.synth_fmt,
|
||||
var->u.n.value);
|
||||
var->var_id != PAUSE && var->var_id != DIRECT) {
|
||||
n = scnprintf(cp, len, var->u.n.synth_fmt,
|
||||
var->u.n.value);
|
||||
cp = cp + n;
|
||||
len = len - n;
|
||||
}
|
||||
var++;
|
||||
}
|
||||
cp = cp + sprintf(cp, "\n");
|
||||
cp = cp + scnprintf(cp, len, "\n");
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
|
|
@ -2547,8 +2547,8 @@ static void binder_transaction(struct binder_proc *proc,
|
|||
ref->node, &target_proc,
|
||||
&return_error);
|
||||
} else {
|
||||
binder_user_error("%d:%d got transaction to invalid handle\n",
|
||||
proc->pid, thread->pid);
|
||||
binder_user_error("%d:%d got transaction to invalid handle, %u\n",
|
||||
proc->pid, thread->pid, tr->target.handle);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
}
|
||||
binder_proc_unlock(proc);
|
||||
|
|
|
@ -58,6 +58,10 @@ enum binderfs_stats_mode {
|
|||
binderfs_stats_mode_global,
|
||||
};
|
||||
|
||||
struct binder_features {
|
||||
bool oneway_spam_detection;
|
||||
};
|
||||
|
||||
static const struct constant_table binderfs_param_stats[] = {
|
||||
{ "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)
|
||||
{
|
||||
return sb->s_fs_info;
|
||||
|
@ -583,6 +591,33 @@ out:
|
|||
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)
|
||||
{
|
||||
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++;
|
||||
}
|
||||
|
||||
ret = init_binder_features(sb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (info->mount_opts.stats_mode == binderfs_stats_mode_global)
|
||||
return init_binder_logs(sb);
|
||||
|
||||
|
|
|
@ -63,11 +63,14 @@ struct fsl_mc_addr_translation_range {
|
|||
|
||||
#define FSL_MC_GCR1 0x0
|
||||
#define GCR1_P1_STOP BIT(31)
|
||||
#define GCR1_P2_STOP BIT(30)
|
||||
|
||||
#define FSL_MC_FAPR 0x28
|
||||
#define MC_FAPR_PL BIT(18)
|
||||
#define MC_FAPR_BMT BIT(17)
|
||||
|
||||
static phys_addr_t mc_portal_base_phys_addr;
|
||||
|
||||
/**
|
||||
* fsl_mc_bus_match - device to driver matching callback
|
||||
* @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_bus = to_fsl_mc_bus(root_mc_dev);
|
||||
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);
|
||||
|
||||
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
|
||||
* revert to old mechanism
|
||||
*/
|
||||
if (region_desc.base_address)
|
||||
if (region_desc.base_address) {
|
||||
regions[i].start = region_desc.base_address +
|
||||
region_desc.base_offset;
|
||||
else
|
||||
} else {
|
||||
error = translate_mc_addr(mc_dev, mc_region_type,
|
||||
region_desc.base_offset,
|
||||
®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) {
|
||||
dev_err(parent_dev,
|
||||
"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);
|
||||
|
||||
static struct notifier_block fsl_mc_nb;
|
||||
|
||||
/**
|
||||
* fsl_mc_device_remove - Remove an fsl-mc device from being visible to
|
||||
* 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
|
||||
* interrogating the firmware. This is the case when the device was not
|
||||
* 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)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
|
@ -1091,17 +1130,6 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
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)) {
|
||||
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,
|
||||
DEV_DMA_COHERENT,
|
||||
&mc_stream_id);
|
||||
if (error == -EPROBE_DEFER)
|
||||
return error;
|
||||
if (error)
|
||||
dev_warn(&pdev->dev,
|
||||
"failed to configure dma: %d.\n",
|
||||
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);
|
||||
mc_portal_phys_addr = plat_res->start;
|
||||
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,
|
||||
mc_portal_size, NULL,
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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[] = {
|
||||
{.compatible = "fsl,qoriq-mc",},
|
||||
{},
|
||||
|
@ -1226,6 +1287,45 @@ static struct platform_driver fsl_mc_bus_driver = {
|
|||
},
|
||||
.probe = fsl_mc_bus_probe,
|
||||
.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)
|
||||
|
@ -1252,7 +1352,7 @@ static int __init fsl_mc_bus_driver_init(void)
|
|||
if (error < 0)
|
||||
goto error_cleanup_dprc_driver;
|
||||
|
||||
return 0;
|
||||
return bus_register_notifier(&platform_bus_type, &fsl_mc_nb);
|
||||
|
||||
error_cleanup_dprc_driver:
|
||||
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;
|
||||
|
||||
for (i = 0; i < image_info->entries; i++, mhi_buf++)
|
||||
mhi_free_coherent(mhi_cntrl, mhi_buf->len, mhi_buf->buf,
|
||||
mhi_buf->dma_addr);
|
||||
dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len,
|
||||
mhi_buf->buf, mhi_buf->dma_addr);
|
||||
|
||||
kfree(image_info->mhi_buf);
|
||||
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;
|
||||
|
||||
mhi_buf->len = vec_size;
|
||||
mhi_buf->buf = mhi_alloc_coherent(mhi_cntrl, vec_size,
|
||||
&mhi_buf->dma_addr,
|
||||
mhi_buf->buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev,
|
||||
vec_size, &mhi_buf->dma_addr,
|
||||
GFP_KERNEL);
|
||||
if (!mhi_buf->buf)
|
||||
goto error_alloc_segment;
|
||||
|
@ -354,8 +354,8 @@ int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl,
|
|||
|
||||
error_alloc_segment:
|
||||
for (--i, --mhi_buf; i >= 0; i--, mhi_buf--)
|
||||
mhi_free_coherent(mhi_cntrl, mhi_buf->len, mhi_buf->buf,
|
||||
mhi_buf->dma_addr);
|
||||
dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len,
|
||||
mhi_buf->buf, mhi_buf->dma_addr);
|
||||
|
||||
error_alloc_mhi_buf:
|
||||
kfree(img_info);
|
||||
|
@ -442,7 +442,8 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
|
|||
if (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) {
|
||||
release_firmware(firmware);
|
||||
goto error_fw_load;
|
||||
|
@ -451,7 +452,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
|
|||
/* Download image using BHI */
|
||||
memcpy(buf, firmware->data, 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 */
|
||||
if (ret) {
|
||||
|
|
|
@ -129,7 +129,7 @@ static int mhi_alloc_aligned_ring(struct mhi_controller *mhi_cntrl,
|
|||
u64 len)
|
||||
{
|
||||
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);
|
||||
if (!ring->pre_aligned)
|
||||
return -ENOMEM;
|
||||
|
@ -221,13 +221,13 @@ void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
|||
mhi_cmd = mhi_cntrl->mhi_cmd;
|
||||
for (i = 0; i < NR_OF_CMD_RINGS; i++, mhi_cmd++) {
|
||||
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->base = NULL;
|
||||
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,
|
||||
mhi_ctxt->cmd_ctxt, mhi_ctxt->cmd_ctxt_addr);
|
||||
|
||||
|
@ -237,17 +237,17 @@ void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
|||
continue;
|
||||
|
||||
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->base = NULL;
|
||||
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_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_ctxt->chan_ctxt_addr);
|
||||
|
||||
|
@ -275,7 +275,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
|||
return -ENOMEM;
|
||||
|
||||
/* 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) *
|
||||
mhi_cntrl->max_chan,
|
||||
&mhi_ctxt->chan_ctxt_addr,
|
||||
|
@ -307,7 +307,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
|||
}
|
||||
|
||||
/* 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) *
|
||||
mhi_cntrl->total_ev_rings,
|
||||
&mhi_ctxt->er_ctxt_addr,
|
||||
|
@ -354,7 +354,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
|||
|
||||
/* Setup cmd context */
|
||||
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) *
|
||||
NR_OF_CMD_RINGS,
|
||||
&mhi_ctxt->cmd_ctxt_addr,
|
||||
|
@ -389,10 +389,10 @@ error_alloc_cmd:
|
|||
for (--i, --mhi_cmd; i >= 0; i--, mhi_cmd--) {
|
||||
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);
|
||||
}
|
||||
mhi_free_coherent(mhi_cntrl,
|
||||
dma_free_coherent(mhi_cntrl->cntrl_dev,
|
||||
sizeof(*mhi_ctxt->cmd_ctxt) * NR_OF_CMD_RINGS,
|
||||
mhi_ctxt->cmd_ctxt, mhi_ctxt->cmd_ctxt_addr);
|
||||
i = mhi_cntrl->total_ev_rings;
|
||||
|
@ -405,15 +405,15 @@ error_alloc_er:
|
|||
if (mhi_event->offload_ev)
|
||||
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);
|
||||
}
|
||||
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_ctxt->er_ctxt_addr);
|
||||
|
||||
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_ctxt->chan_ctxt_addr);
|
||||
|
||||
|
@ -567,7 +567,7 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl,
|
|||
if (!chan_ctxt->rbase) /* Already uninitialized */
|
||||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
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 ||
|
||||
!mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put ||
|
||||
!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;
|
||||
|
||||
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)
|
||||
{
|
||||
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
||||
u32 bhie_off;
|
||||
u32 bhi_off, bhie_off;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&mhi_cntrl->pm_mutex);
|
||||
|
@ -1072,29 +1073,51 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl)
|
|||
if (ret)
|
||||
goto error_dev_ctxt;
|
||||
|
||||
/*
|
||||
* Allocate RDDM table if specified, this table is for debugging purpose
|
||||
*/
|
||||
if (mhi_cntrl->rddm_size) {
|
||||
mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->rddm_image,
|
||||
mhi_cntrl->rddm_size);
|
||||
ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIOFF, &bhi_off);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error getting BHI offset\n");
|
||||
goto error_reg_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* This controller supports RDDM, so we need to manually clear
|
||||
* BHIE RX registers since POR values are undefined.
|
||||
*/
|
||||
if (bhi_off >= mhi_cntrl->reg_len) {
|
||||
dev_err(dev, "BHI offset: 0x%x is out of range: 0x%zx\n",
|
||||
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,
|
||||
&bhie_off);
|
||||
if (ret) {
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
0, BHIE_RXVECSTATUS_OFFS - BHIE_RXVECADDR_LOW_OFFS +
|
||||
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)
|
||||
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;
|
||||
|
||||
bhie_error:
|
||||
if (mhi_cntrl->rddm_image) {
|
||||
mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->rddm_image);
|
||||
mhi_cntrl->rddm_image = NULL;
|
||||
}
|
||||
error_reg_offset:
|
||||
mhi_deinit_dev_ctxt(mhi_cntrl);
|
||||
|
||||
error_dev_ctxt:
|
||||
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->bhi = NULL;
|
||||
mhi_cntrl->bhie = NULL;
|
||||
|
||||
mhi_deinit_dev_ctxt(mhi_cntrl);
|
||||
}
|
||||
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,
|
||||
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 */
|
||||
void mhi_ctrl_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,
|
||||
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);
|
||||
|
||||
if (!buf)
|
||||
|
@ -220,8 +220,8 @@ void mhi_unmap_single_use_bb(struct mhi_controller *mhi_cntrl,
|
|||
if (buf_info->dir == DMA_FROM_DEVICE)
|
||||
memcpy(buf_info->v_addr, buf_info->bb_addr, buf_info->len);
|
||||
|
||||
mhi_free_coherent(mhi_cntrl, buf_info->len, buf_info->bb_addr,
|
||||
buf_info->p_addr);
|
||||
dma_free_coherent(mhi_cntrl->cntrl_dev, buf_info->len,
|
||||
buf_info->bb_addr, buf_info->p_addr);
|
||||
}
|
||||
|
||||
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)
|
||||
goto error_setup_irq;
|
||||
|
||||
/* Setup BHI offset & INTVEC */
|
||||
/* Setup BHI INTVEC */
|
||||
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_cntrl->pm_state = MHI_PM_POR;
|
||||
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 */
|
||||
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;
|
||||
goto error_bhi_offset;
|
||||
goto error_async_power_up;
|
||||
}
|
||||
|
||||
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) {
|
||||
mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET);
|
||||
ret = wait_event_timeout(mhi_cntrl->state_event,
|
||||
|
@ -1110,7 +1094,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl)
|
|||
if (!ret) {
|
||||
ret = -EIO;
|
||||
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;
|
||||
|
||||
error_bhi_offset:
|
||||
error_async_power_up:
|
||||
mhi_deinit_free_irq(mhi_cntrl);
|
||||
|
||||
error_setup_irq:
|
||||
|
|
|
@ -369,6 +369,40 @@ static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = {
|
|||
.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[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0306),
|
||||
.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 */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0b1),
|
||||
.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);
|
||||
|
@ -490,6 +527,7 @@ static int mhi_pci_claim(struct mhi_controller *mhi_cntrl,
|
|||
return err;
|
||||
}
|
||||
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);
|
||||
if (err) {
|
||||
|
|
|
@ -427,8 +427,6 @@ config ADI
|
|||
and SSM (Silicon Secured Memory). Intended consumers of this
|
||||
driver include crash and makedumpfile.
|
||||
|
||||
endmenu
|
||||
|
||||
config RANDOM_TRUST_CPU
|
||||
bool "Trust the CPU manufacturer to initialize Linux's CRNG"
|
||||
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
|
||||
pool. Otherwise, say N here so it will be regarded as device input that
|
||||
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 retval = 0;
|
||||
|
||||
PRINTK_2(TRACE_TP3780I,
|
||||
"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,
|
||||
"tp3780i::tp3780I_QueryAbilities exit retval=SUCCESSFUL\n");
|
||||
|
||||
return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 */
|
||||
dev = kzalloc(sizeof(struct dio_dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return 0;
|
||||
return -ENOMEM;
|
||||
|
||||
dev->bus = &dio_bus;
|
||||
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);
|
||||
if (!fw)
|
||||
return NULL;
|
||||
goto err_put_device;
|
||||
|
||||
if (!kref_get_unless_zero(&fw->consumers))
|
||||
return NULL;
|
||||
goto err_put_device;
|
||||
|
||||
put_device(&pdev->dev);
|
||||
|
||||
return fw;
|
||||
|
||||
err_put_device:
|
||||
put_device(&pdev->dev);
|
||||
return NULL;
|
||||
}
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* zynqmp_pm_write_pggs() - PM API for reading persistent global general
|
||||
* zynqmp_pm_read_pggs() - PM API for reading persistent global general
|
||||
* storage (pggs)
|
||||
* @index: PGGS register index
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @address: Address of the AesParams structure.
|
||||
* @out: Returned output value
|
||||
|
|
|
@ -119,7 +119,7 @@ config XILINX_PR_DECOUPLER
|
|||
depends on HAS_IOMEM
|
||||
help
|
||||
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
|
||||
region of the FPGA from the busses while that region is
|
||||
being reprogrammed during partial reconfig.
|
||||
|
@ -234,4 +234,13 @@ config FPGA_MGR_ZYNQMP_FPGA
|
|||
to configure the programmable logic(PL) through PS
|
||||
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
|
||||
|
|
|
@ -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_ZYNQ_FPGA) += zynq-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_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) {
|
||||
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);
|
||||
if (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,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id altera_freeze_br_of_match[] = {
|
||||
{ .compatible = "altr,freeze-bridge-controller", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, altera_freeze_br_of_match);
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 = fme_mgr_write,
|
||||
.write_complete = fme_mgr_write_complete,
|
||||
.state = fme_mgr_state,
|
||||
.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
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* 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
|
||||
* 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_INTEL_PAC_N3000 0x0B30
|
||||
#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 */
|
||||
#define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF
|
||||
#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_D5005),},
|
||||
{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,}
|
||||
};
|
||||
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->feature_id = feature->id;
|
||||
ddev->revision = feature->revision;
|
||||
ddev->cdev = pdata->dfl_cdev;
|
||||
|
||||
/* add mmio resource */
|
||||
|
@ -717,6 +718,7 @@ struct build_feature_devs_info {
|
|||
*/
|
||||
struct dfl_feature_info {
|
||||
u16 fid;
|
||||
u8 revision;
|
||||
struct resource mmio_res;
|
||||
void __iomem *ioaddr;
|
||||
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 */
|
||||
feature->dev = fdev;
|
||||
feature->id = finfo->fid;
|
||||
feature->revision = finfo->revision;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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, v);
|
||||
u32 ofst = FIELD_GET(DFH_NEXT_HDR_OFST, value);
|
||||
/* workaround for private features with invalid size, use 4K instead */
|
||||
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, v);
|
||||
u8 type = FIELD_GET(DFH_TYPE, v);
|
||||
u16 id = FIELD_GET(DFH_ID, value);
|
||||
u8 type = FIELD_GET(DFH_TYPE, value);
|
||||
|
||||
if (type == DFH_TYPE_FIU)
|
||||
return FEATURE_ID_FIU_HEADER;
|
||||
|
@ -1021,10 +1022,15 @@ create_feature_instance(struct build_feature_devs_info *binfo,
|
|||
unsigned int irq_base, nr_irqs;
|
||||
struct dfl_feature_info *finfo;
|
||||
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 */
|
||||
size = size ? size : feature_size(binfo->ioaddr + ofst);
|
||||
fid = fid ? fid : feature_id(binfo->ioaddr + ofst);
|
||||
size = size ? size : feature_size(v);
|
||||
fid = fid ? fid : feature_id(v);
|
||||
|
||||
if (binfo->len - ofst < size)
|
||||
return -EINVAL;
|
||||
|
@ -1038,6 +1044,7 @@ create_feature_instance(struct build_feature_devs_info *binfo,
|
|||
return -ENOMEM;
|
||||
|
||||
finfo->fid = fid;
|
||||
finfo->revision = revision;
|
||||
finfo->mmio_res.start = binfo->start + ofst;
|
||||
finfo->mmio_res.end = finfo->mmio_res.start + size - 1;
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -232,7 +232,7 @@ struct dfl_feature_irq_ctx {
|
|||
* @id: sub feature id.
|
||||
* @resource_index: each sub feature has one mmio resource for its registers.
|
||||
* 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.
|
||||
* @irq_ctx: interrupt context list.
|
||||
* @nr_irqs: number of interrupt contexts.
|
||||
|
@ -243,6 +243,7 @@ struct dfl_feature_irq_ctx {
|
|||
struct dfl_feature {
|
||||
struct platform_device *dev;
|
||||
u16 id;
|
||||
u8 revision;
|
||||
int resource_index;
|
||||
void __iomem *ioaddr;
|
||||
struct dfl_feature_irq_ctx *irq_ctx;
|
||||
|
|
|
@ -228,9 +228,9 @@ EXPORT_SYMBOL_GPL(fpga_bridges_put);
|
|||
* @info: fpga image specific information
|
||||
* @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,
|
||||
struct fpga_image_info *info,
|
||||
|
@ -258,9 +258,9 @@ EXPORT_SYMBOL_GPL(of_fpga_bridge_get_to_list);
|
|||
* @info: fpga image specific information
|
||||
* @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,
|
||||
struct fpga_image_info *info,
|
||||
|
|
|
@ -25,6 +25,72 @@ struct fpga_mgr_devres {
|
|||
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
|
||||
* @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;
|
||||
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
|
||||
ret = mgr->mops->write_init(
|
||||
ret = fpga_mgr_write_init(
|
||||
mgr, info, buf, min(mgr->mops->initial_header_size, count));
|
||||
|
||||
if (ret) {
|
||||
|
@ -137,27 +203,6 @@ static int fpga_mgr_write_init_sg(struct fpga_manager *mgr,
|
|||
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
|
||||
* @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. */
|
||||
mgr->state = FPGA_MGR_STATE_WRITE;
|
||||
if (mgr->mops->write_sg) {
|
||||
ret = mgr->mops->write_sg(mgr, sgt);
|
||||
ret = fpga_mgr_write_sg(mgr, sgt);
|
||||
} else {
|
||||
struct sg_mapping_iter miter;
|
||||
|
||||
sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG);
|
||||
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)
|
||||
break;
|
||||
}
|
||||
|
@ -224,7 +269,7 @@ static int fpga_mgr_buf_load_mapped(struct fpga_manager *mgr,
|
|||
* Write the FPGA image to the FPGA.
|
||||
*/
|
||||
mgr->state = FPGA_MGR_STATE_WRITE;
|
||||
ret = mgr->mops->write(mgr, buf, count);
|
||||
ret = fpga_mgr_write(mgr, buf, count);
|
||||
if (ret) {
|
||||
dev_err(&mgr->dev, "Error while writing image data to FPGA\n");
|
||||
mgr->state = FPGA_MGR_STATE_WRITE_ERR;
|
||||
|
@ -417,10 +462,7 @@ static ssize_t status_show(struct device *dev,
|
|||
u64 status;
|
||||
int len = 0;
|
||||
|
||||
if (!mgr->mops->status)
|
||||
return -ENOENT;
|
||||
|
||||
status = mgr->mops->status(mgr);
|
||||
status = fpga_mgr_status(mgr);
|
||||
|
||||
if (status & FPGA_MGR_STATUS_OPERATION_ERR)
|
||||
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;
|
||||
int id, ret;
|
||||
|
||||
if (!mops || !mops->write_complete || !mops->state ||
|
||||
!mops->write_init || (!mops->write && !mops->write_sg) ||
|
||||
(mops->write && mops->write_sg)) {
|
||||
if (!mops) {
|
||||
dev_err(parent, "Attempt to register without fpga_manager_ops\n");
|
||||
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
|
||||
* by bootloader or EEPROM.
|
||||
*/
|
||||
mgr->state = mgr->mops->state(mgr);
|
||||
mgr->state = fpga_mgr_state(mgr);
|
||||
|
||||
ret = device_add(&mgr->dev);
|
||||
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
|
||||
* a desired state upon unregister, do it.
|
||||
*/
|
||||
if (mgr->mops->fpga_remove)
|
||||
mgr->mops->fpga_remove(mgr);
|
||||
fpga_mgr_fpga_remove(mgr);
|
||||
|
||||
device_unregister(&mgr->dev);
|
||||
}
|
||||
|
|
|
@ -388,13 +388,7 @@ static int s10_ops_write_complete(struct fpga_manager *mgr,
|
|||
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 = {
|
||||
.state = s10_ops_state,
|
||||
.write_init = s10_ops_write_init,
|
||||
.write = s10_ops_write,
|
||||
.write_complete = s10_ops_write_complete,
|
||||
|
|
|
@ -32,11 +32,6 @@ struct ts73xx_fpga_priv {
|
|||
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,
|
||||
struct fpga_image_info *info,
|
||||
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 = {
|
||||
.state = ts73xx_fpga_state,
|
||||
.write_init = ts73xx_fpga_write_init,
|
||||
.write = ts73xx_fpga_write,
|
||||
.write_complete = ts73xx_fpga_write_complete,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct xlnx_config_data decoupler_config = {
|
||||
.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);
|
||||
#endif
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id xlnx_spi_of_match[] = {
|
||||
{ .compatible = "xlnx,fpga-slave-serial", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, xlnx_spi_of_match);
|
||||
#endif
|
||||
|
||||
static struct spi_driver xilinx_slave_spi_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
|
||||
* 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 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);
|
||||
if (!(ctrl & CTRL_SEC_EN_MASK)) {
|
||||
dev_err(&mgr->dev,
|
||||
"System not secure, can't use crypted bitstreams\n");
|
||||
"System not secure, can't use encrypted bitstreams\n");
|
||||
err = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
|
@ -344,7 +344,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr,
|
|||
|
||||
/* set configuration register with following options:
|
||||
* - 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
|
||||
*/
|
||||
ctrl = zynq_fpga_read(priv, CTRL_OFFSET);
|
||||
|
|
|
@ -66,12 +66,6 @@ static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
|
|||
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)
|
||||
{
|
||||
u32 status = 0;
|
||||
|
@ -87,7 +81,6 @@ static const struct fpga_manager_ops zynqmp_fpga_ops = {
|
|||
.state = zynqmp_fpga_ops_state,
|
||||
.write_init = zynqmp_fpga_ops_write_init,
|
||||
.write = zynqmp_fpga_ops_write,
|
||||
.write_complete = zynqmp_fpga_ops_write_complete,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id zynqmp_fpga_of_match[] = {
|
||||
{ .compatible = "xlnx,zynqmp-pcap-fpga", },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver zynqmp_fpga_driver = {
|
||||
.probe = zynqmp_fpga_probe,
|
||||
|
|
|
@ -8,6 +8,7 @@ menuconfig CORESIGHT
|
|||
depends on OF || ACPI
|
||||
select ARM_AMBA
|
||||
select PERF_EVENTS
|
||||
select CONFIGFS_FS
|
||||
help
|
||||
This framework provides a kernel interface for the CoreSight debug
|
||||
and trace drivers to register themselves with. It's intended to build
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
#
|
||||
obj-$(CONFIG_CORESIGHT) += coresight.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
|
||||
coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.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-sysfs.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_CPU_DEBUG) += coresight-cpu-debug.o
|
||||
obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o
|
||||
|
|
|
@ -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) */
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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-priv.h"
|
||||
#include "coresight-syscfg.h"
|
||||
|
||||
static DEFINE_MUTEX(coresight_mutex);
|
||||
static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
|
||||
|
@ -1763,13 +1764,22 @@ static int __init coresight_init(void)
|
|||
|
||||
ret = etm_perf_init();
|
||||
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;
|
||||
}
|
||||
|
||||
static void __exit coresight_exit(void)
|
||||
{
|
||||
cscfg_exit();
|
||||
etm_perf_exit();
|
||||
bus_unregister(&coresight_bustype);
|
||||
}
|
||||
|
|
|
@ -588,11 +588,11 @@ static int debug_probe(struct amba_device *adev, const struct amba_id *id)
|
|||
|
||||
drvdata->base = base;
|
||||
|
||||
get_online_cpus();
|
||||
cpus_read_lock();
|
||||
per_cpu(debug_drvdata, drvdata->cpu) = drvdata;
|
||||
ret = smp_call_function_single(drvdata->cpu, debug_init_arch_data,
|
||||
drvdata, 1);
|
||||
put_online_cpus();
|
||||
cpus_read_unlock();
|
||||
|
||||
if (ret) {
|
||||
dev_err(dev, "CPU%d debug arch init failed\n", drvdata->cpu);
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "coresight-config.h"
|
||||
#include "coresight-etm-perf.h"
|
||||
#include "coresight-priv.h"
|
||||
#include "coresight-syscfg.h"
|
||||
|
||||
static struct pmu etm_pmu;
|
||||
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(timestamp, "config:" __stringify(ETM_OPT_TS));
|
||||
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 */
|
||||
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
|
||||
|
@ -88,6 +95,8 @@ static struct attribute *etm_config_formats_attr[] = {
|
|||
&format_attr_timestamp.attr,
|
||||
&format_attr_retstack.attr,
|
||||
&format_attr_sinkid.attr,
|
||||
&format_attr_preset.attr,
|
||||
&format_attr_configid.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -105,9 +114,19 @@ static const struct attribute_group etm_pmu_sinks_group = {
|
|||
.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[] = {
|
||||
&etm_pmu_format_group,
|
||||
&etm_pmu_sinks_group,
|
||||
&etm_pmu_events_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -196,6 +215,10 @@ static void free_event_data(struct work_struct *work)
|
|||
/* Free the sink buffers, if there are any */
|
||||
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) {
|
||||
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,
|
||||
int nr_pages, bool overwrite)
|
||||
{
|
||||
u32 id;
|
||||
u32 id, cfg_hash;
|
||||
int cpu = event->cpu;
|
||||
cpumask_t *mask;
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
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;
|
||||
|
||||
/*
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
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 ret;
|
||||
unsigned long hash;
|
||||
const char *name;
|
||||
struct device *pmu_dev = etm_pmu.dev;
|
||||
struct device *dev = &csdev->dev;
|
||||
struct dev_ext_attribute *ea;
|
||||
int err = 0;
|
||||
|
||||
if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
|
||||
csdev->type != CORESIGHT_DEV_TYPE_LINKSINK)
|
||||
|
@ -674,52 +739,77 @@ int etm_perf_add_symlink_sink(struct coresight_device *csdev)
|
|||
if (csdev->ea != NULL)
|
||||
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);
|
||||
/* See function coresight_get_sink_by_id() to know where this is used */
|
||||
hash = hashlen_hash(hashlen_string(NULL, name));
|
||||
csdev->ea = etm_perf_add_symlink_group(dev, name, "sinks");
|
||||
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);
|
||||
ea->attr.attr.name = devm_kstrdup(dev, name, GFP_KERNEL);
|
||||
if (!ea->attr.attr.name)
|
||||
return -ENOMEM;
|
||||
return err;
|
||||
}
|
||||
|
||||
ea->attr.attr.mode = 0444;
|
||||
ea->attr.show = etm_perf_sink_name_show;
|
||||
ea->var = (unsigned long *)hash;
|
||||
static void etm_perf_del_symlink_group(struct dev_ext_attribute *ea, const char *group_name)
|
||||
{
|
||||
struct device *pmu_dev = etm_pmu.dev;
|
||||
|
||||
ret = sysfs_add_file_to_group(&pmu_dev->kobj,
|
||||
&ea->attr.attr, "sinks");
|
||||
|
||||
if (!ret)
|
||||
csdev->ea = ea;
|
||||
|
||||
return ret;
|
||||
sysfs_remove_file_from_group(&pmu_dev->kobj,
|
||||
&ea->attr.attr, group_name);
|
||||
}
|
||||
|
||||
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 &&
|
||||
csdev->type != CORESIGHT_DEV_TYPE_LINKSINK)
|
||||
return;
|
||||
|
||||
if (!ea)
|
||||
if (!csdev->ea)
|
||||
return;
|
||||
|
||||
sysfs_remove_file_from_group(&pmu_dev->kobj,
|
||||
&ea->attr.attr, "sinks");
|
||||
etm_perf_del_symlink_group(csdev->ea, "sinks");
|
||||
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 ret;
|
||||
|
@ -748,7 +838,7 @@ int __init etm_perf_init(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void __exit etm_perf_exit(void)
|
||||
void etm_perf_exit(void)
|
||||
{
|
||||
perf_pmu_unregister(&etm_pmu);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "coresight-priv.h"
|
||||
|
||||
struct coresight_device;
|
||||
struct cscfg_config_desc;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* @mask: Hold the CPU(s) this event was set for.
|
||||
* @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.
|
||||
*/
|
||||
struct etm_event_data {
|
||||
struct work_struct work;
|
||||
cpumask_t mask;
|
||||
void *snk_config;
|
||||
u32 cfg_hash;
|
||||
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 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
|
||||
static inline int etm_perf_symlink(struct coresight_device *csdev, bool link)
|
||||
{ return -EINVAL; }
|
||||
|
@ -79,10 +85,14 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle)
|
|||
{
|
||||
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 */
|
||||
|
||||
int __init etm_perf_init(void);
|
||||
void __exit etm_perf_exit(void);
|
||||
void etm_perf_exit(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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-etm-perf.h"
|
||||
#include "coresight-etm4x-cfg.h"
|
||||
#include "coresight-syscfg.h"
|
||||
|
||||
static int boot_enable;
|
||||
module_param(boot_enable, int, 0444);
|
||||
|
@ -561,12 +563,15 @@ out:
|
|||
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)
|
||||
{
|
||||
int ret = 0;
|
||||
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
struct etmv4_config *config = &drvdata->config;
|
||||
struct perf_event_attr *attr = &event->attr;
|
||||
unsigned long cfg_hash;
|
||||
int preset;
|
||||
|
||||
/* Clear configuration from previous run */
|
||||
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 */
|
||||
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:
|
||||
return ret;
|
||||
}
|
||||
|
@ -648,7 +667,7 @@ static int etm4_enable_perf(struct coresight_device *csdev,
|
|||
}
|
||||
|
||||
/* 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)
|
||||
goto out;
|
||||
/* And enable it */
|
||||
|
@ -794,11 +813,18 @@ static int etm4_disable_perf(struct coresight_device *csdev,
|
|||
u32 control;
|
||||
struct etm_filters *filters = event->hw.addr_filters;
|
||||
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()))
|
||||
return -EINVAL;
|
||||
|
||||
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.
|
||||
|
@ -1939,6 +1965,13 @@ static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid)
|
|||
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;
|
||||
|
||||
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();
|
||||
|
||||
cscfg_unregister_csdev(drvdata->csdev);
|
||||
coresight_unregister(drvdata->csdev);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/sysfs.h>
|
||||
#include "coresight-etm4x.h"
|
||||
#include "coresight-priv.h"
|
||||
#include "coresight-syscfg.h"
|
||||
|
||||
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);
|
||||
|
||||
cscfg_csdev_reset_feats(to_coresight_device(dev));
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_WO(reset);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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();
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
if (WARN_ON(node->provider))
|
||||
return;
|
||||
|
||||
mutex_lock(&icc_lock);
|
||||
|
||||
node->provider = provider;
|
||||
|
|
|
@ -83,6 +83,15 @@ config INTERCONNECT_QCOM_SC7280
|
|||
This is a driver for the Qualcomm Network-on-Chip on sc7280-based
|
||||
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
|
||||
tristate "Qualcomm SDM660 interconnect driver"
|
||||
depends on INTERCONNECT_QCOM
|
||||
|
|
|
@ -9,6 +9,7 @@ qnoc-qcs404-objs := qcs404.o
|
|||
icc-rpmh-obj := icc-rpmh.o
|
||||
qnoc-sc7180-objs := sc7180.o
|
||||
qnoc-sc7280-objs := sc7280.o
|
||||
qnoc-sc8180x-objs := sc8180x.o
|
||||
qnoc-sdm660-objs := sdm660.o
|
||||
qnoc-sdm845-objs := sdm845.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_SC7180) += qnoc-sc7180.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_SDM845) += qnoc-sdm845.o
|
||||
obj-$(CONFIG_INTERCONNECT_QCOM_SDX55) += qnoc-sdx55.o
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/interconnect-provider.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.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);
|
||||
|
||||
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");
|
||||
|
|
|
@ -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);
|
||||
int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev);
|
||||
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
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <dt-bindings/interconnect/qcom,osm-l3.h>
|
||||
|
||||
#include "sc7180.h"
|
||||
#include "sc8180x.h"
|
||||
#include "sdm845.h"
|
||||
#include "sm8150.h"
|
||||
#include "sm8250.h"
|
||||
|
@ -37,7 +38,7 @@
|
|||
|
||||
#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)
|
||||
|
||||
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
|
||||
* @links: an array of nodes where we can go next while traversing
|
||||
* @id: a unique node identifier
|
||||
* @num_links: the total number of @links
|
||||
* @buswidth: width of the interconnect between a node and the bus
|
||||
*/
|
||||
struct qcom_icc_node {
|
||||
struct qcom_osm_l3_node {
|
||||
const char *name;
|
||||
u16 links[OSM_L3_MAX_LINKS];
|
||||
u16 id;
|
||||
|
@ -64,8 +65,8 @@ struct qcom_icc_node {
|
|||
u16 buswidth;
|
||||
};
|
||||
|
||||
struct qcom_icc_desc {
|
||||
const struct qcom_icc_node **nodes;
|
||||
struct qcom_osm_l3_desc {
|
||||
const struct qcom_osm_l3_node **nodes;
|
||||
size_t num_nodes;
|
||||
unsigned int lut_row_size;
|
||||
unsigned int reg_freq_lut;
|
||||
|
@ -73,7 +74,7 @@ struct qcom_icc_desc {
|
|||
};
|
||||
|
||||
#define DEFINE_QNODE(_name, _id, _buswidth, ...) \
|
||||
static const struct qcom_icc_node _name = { \
|
||||
static const struct qcom_osm_l3_node _name = { \
|
||||
.name = #_name, \
|
||||
.id = _id, \
|
||||
.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_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,
|
||||
[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,
|
||||
.num_nodes = ARRAY_SIZE(sdm845_osm_l3_nodes),
|
||||
.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_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,
|
||||
[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,
|
||||
.num_nodes = ARRAY_SIZE(sc7180_osm_l3_nodes),
|
||||
.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,
|
||||
};
|
||||
|
||||
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_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,
|
||||
[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,
|
||||
.num_nodes = ARRAY_SIZE(sm8150_osm_l3_nodes),
|
||||
.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_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,
|
||||
[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,
|
||||
.num_nodes = ARRAY_SIZE(sm8250_epss_l3_nodes),
|
||||
.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,
|
||||
};
|
||||
|
||||
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 icc_provider *provider;
|
||||
const struct qcom_icc_node *qn;
|
||||
const struct qcom_osm_l3_node *qn;
|
||||
struct icc_node *n;
|
||||
unsigned int index;
|
||||
u32 agg_peak = 0;
|
||||
|
@ -158,7 +175,7 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
|
|||
|
||||
qn = src->data;
|
||||
provider = src->provider;
|
||||
qp = to_qcom_provider(provider);
|
||||
qp = to_osm_l3_provider(provider);
|
||||
|
||||
list_for_each_entry(n, &provider->nodes, node_list)
|
||||
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;
|
||||
static unsigned long hw_rate, xo_rate;
|
||||
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_provider *provider;
|
||||
const struct qcom_icc_node **qnodes;
|
||||
const struct qcom_osm_l3_node **qnodes;
|
||||
struct icc_node *node;
|
||||
size_t num_nodes;
|
||||
struct clk *clk;
|
||||
|
@ -264,7 +281,7 @@ static int qcom_osm_l3_probe(struct platform_device *pdev)
|
|||
|
||||
provider = &qp->provider;
|
||||
provider->dev = &pdev->dev;
|
||||
provider->set = qcom_icc_set;
|
||||
provider->set = qcom_osm_l3_set;
|
||||
provider->aggregate = icc_std_aggregate;
|
||||
provider->xlate = of_icc_xlate_onecell;
|
||||
INIT_LIST_HEAD(&provider->nodes);
|
||||
|
@ -286,7 +303,7 @@ static int qcom_osm_l3_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
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];
|
||||
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,sdm845-osm-l3", .data = &sdm845_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 },
|
||||
{ }
|
||||
};
|
||||
|
|
|
@ -504,98 +504,6 @@ static struct qcom_icc_desc sc7180_system_noc = {
|
|||
.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[] = {
|
||||
{ .compatible = "qcom,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);
|
||||
|
||||
static struct platform_driver qnoc_driver = {
|
||||
.probe = qnoc_probe,
|
||||
.remove = qnoc_remove,
|
||||
.probe = qcom_icc_rpmh_probe,
|
||||
.remove = qcom_icc_rpmh_remove,
|
||||
.driver = {
|
||||
.name = "qnoc-sc7180",
|
||||
.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),
|
||||
};
|
||||
|
||||
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[] = {
|
||||
{ .compatible = "qcom,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);
|
||||
|
||||
static struct platform_driver qnoc_driver = {
|
||||
.probe = qnoc_probe,
|
||||
.remove = qnoc_remove,
|
||||
.probe = qcom_icc_rpmh_probe,
|
||||
.remove = qcom_icc_rpmh_remove,
|
||||
.driver = {
|
||||
.name = "qnoc-sc7280",
|
||||
.of_match_table = qnoc_of_match,
|
||||
|
|
|
@ -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");
|
|
@ -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),
|
||||
};
|
||||
|
||||
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[] = {
|
||||
{ .compatible = "qcom,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);
|
||||
|
||||
static struct platform_driver qnoc_driver = {
|
||||
.probe = qnoc_probe,
|
||||
.remove = qnoc_remove,
|
||||
.probe = qcom_icc_rpmh_probe,
|
||||
.remove = qcom_icc_rpmh_remove,
|
||||
.driver = {
|
||||
.name = "qnoc-sdm845",
|
||||
.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),
|
||||
};
|
||||
|
||||
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,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);
|
||||
|
||||
static struct platform_driver qnoc_driver = {
|
||||
.probe = qnoc_probe,
|
||||
.remove = qnoc_remove,
|
||||
.probe = qcom_icc_rpmh_probe,
|
||||
.remove = qcom_icc_rpmh_remove,
|
||||
.driver = {
|
||||
.name = "qnoc-sdx55",
|
||||
.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),
|
||||
};
|
||||
|
||||
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,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);
|
||||
|
||||
static struct platform_driver qnoc_driver = {
|
||||
.probe = qnoc_probe,
|
||||
.remove = qnoc_remove,
|
||||
.probe = qcom_icc_rpmh_probe,
|
||||
.remove = qcom_icc_rpmh_remove,
|
||||
.driver = {
|
||||
.name = "qnoc-sm8150",
|
||||
.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),
|
||||
};
|
||||
|
||||
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,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);
|
||||
|
||||
static struct platform_driver qnoc_driver = {
|
||||
.probe = qnoc_probe,
|
||||
.remove = qnoc_remove,
|
||||
.probe = qcom_icc_rpmh_probe,
|
||||
.remove = qcom_icc_rpmh_remove,
|
||||
.driver = {
|
||||
.name = "qnoc-sm8250",
|
||||
.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),
|
||||
};
|
||||
|
||||
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[] = {
|
||||
{ .compatible = "qcom,sm8350-aggre1-noc", .data = &sm8350_aggre1_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);
|
||||
|
||||
static struct platform_driver qnoc_driver = {
|
||||
.probe = qnoc_probe,
|
||||
.remove = qnoc_remove,
|
||||
.probe = qcom_icc_rpmh_probe,
|
||||
.remove = qcom_icc_rpmh_remove,
|
||||
.driver = {
|
||||
.name = "qnoc-sm8350",
|
||||
.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
|
||||
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
|
||||
tristate "Channel interface driver for the HP iLO processor"
|
||||
depends on PCI
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue