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:
Linus Torvalds 2021-09-01 08:35:06 -07:00
commit ba1dc7f273
180 changed files with 9175 additions and 2747 deletions

View File

@ -0,0 +1,15 @@
What: /sys/bus/spi/<dev>/update_firmware
Date: Jul 2021
Contact: sebastian.reichel@collabora.com
Description: Write 1 to this file to update the ACHC microcontroller
firmware via the EzPort interface. For this the kernel
will load "achc.bin" via the firmware API (so usually
from /lib/firmware). The write will block until the FW
has either been flashed successfully or an error occured.
What: /sys/bus/spi/<dev>/reset
Date: Jul 2021
Contact: sebastian.reichel@collabora.com
Description: This file represents the microcontroller's reset line.
1 means the reset line is asserted, 0 means it's not
asserted. The file is read and writable.

View File

@ -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

View File

@ -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";
...
};
};

View File

@ -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";
};
};
...

View File

@ -0,0 +1,33 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/fpga/xlnx,versal-fpga.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Xilinx Versal FPGA driver.
maintainers:
- Nava kishore Manne <nava.manne@xilinx.com>
description: |
Device Tree Versal FPGA bindings for the Versal SoC, controlled
using firmware interface.
properties:
compatible:
items:
- enum:
- xlnx,versal-fpga
required:
- compatible
additionalProperties: false
examples:
- |
versal_fpga: versal_fpga {
compatible = "xlnx,versal-fpga";
};
...

View File

@ -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

View File

@ -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

View File

@ -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>;
};

View File

@ -0,0 +1,65 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
# Copyright (C) 2021 GE Inc.
# Copyright (C) 2021 Collabora Ltd.
%YAML 1.2
---
$id: http://devicetree.org/schemas/misc/ge-achc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: GE Healthcare USB Management Controller
description: |
A device which handles data acquisition from compatible USB based peripherals.
SPI is used for device management.
Note: This device does not expose the peripherals as USB devices.
maintainers:
- Sebastian Reichel <sre@kernel.org>
properties:
compatible:
items:
- const: ge,achc
- const: nxp,kinetis-k20
clocks:
maxItems: 1
vdd-supply:
description: Digital power supply regulator on VDD pin
vdda-supply:
description: Analog power supply regulator on VDDA pin
reg:
items:
- description: Control interface
- description: Firmware programming interface
reset-gpios:
description: GPIO used for hardware reset.
maxItems: 1
required:
- compatible
- clocks
- reg
- reset-gpios
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
spi@1 {
compatible = "ge,achc", "nxp,kinetis-k20";
reg = <1>, <0>;
clocks = <&achc_24M>;
reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
};
};

View File

@ -0,0 +1,44 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/nvmem/nintendo-otp.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Nintendo Wii and Wii U OTP Device Tree Bindings
description: |
This binding represents the OTP memory as found on a Nintendo Wii or Wii U,
which contains common and per-console keys, signatures and related data
required to access peripherals.
See https://wiiubrew.org/wiki/Hardware/OTP
maintainers:
- Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
allOf:
- $ref: "nvmem.yaml#"
properties:
compatible:
enum:
- nintendo,hollywood-otp
- nintendo,latte-otp
reg:
maxItems: 1
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
otp@d8001ec {
compatible = "nintendo,latte-otp";
reg = <0x0d8001ec 0x8>;
};
...

View File

@ -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

View File

@ -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>;
};

View File

@ -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>;
};

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -16,6 +16,7 @@ properties:
compatible:
enum:
- samsung,exynos7-ufs-phy
- samsung,exynosautov9-ufs-phy
reg:
maxItems: 1

View File

@ -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";
};

View File

@ -0,0 +1,103 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/ti,phy-am654-serdes.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI AM654 SERDES binding
description:
This binding describes the TI AM654 SERDES. AM654 SERDES can be configured
to be used with either PCIe or USB or SGMII.
maintainers:
- Kishon Vijay Abraham I <kishon@ti.com>
properties:
compatible:
enum:
- ti,phy-am654-serdes
reg:
maxItems: 1
reg-names:
items:
- const: serdes
power-domains:
maxItems: 1
clocks:
maxItems: 3
description:
Three input clocks referring to left input reference clock, refclk and right input reference
clock.
assigned-clocks:
$ref: "/schemas/types.yaml#/definitions/phandle-array"
assigned-clock-parents:
$ref: "/schemas/types.yaml#/definitions/phandle-array"
'#phy-cells':
const: 2
description:
The 1st cell corresponds to the phy type (should be one of the types specified in
include/dt-bindings/phy/phy.h) and the 2nd cell should be the serdes lane function.
ti,serdes-clk:
description: Phandle to the SYSCON entry required for configuring SERDES clock selection.
$ref: /schemas/types.yaml#/definitions/phandle
'#clock-cells':
const: 1
mux-controls:
maxItems: 1
description: Phandle to the SYSCON entry required for configuring SERDES lane function.
clock-output-names:
oneOf:
- description: Clock output names for SERDES 0
items:
- const: serdes0_cmu_refclk
- const: serdes0_lo_refclk
- const: serdes0_ro_refclk
- description: Clock output names for SERDES 1
items:
- const: serdes1_cmu_refclk
- const: serdes1_lo_refclk
- const: serdes1_ro_refclk
required:
- compatible
- reg
- power-domains
- clocks
- assigned-clocks
- assigned-clock-parents
- ti,serdes-clk
- mux-controls
- clock-output-names
additionalProperties: false
examples:
- |
#include <dt-bindings/phy/phy-am654-serdes.h>
serdes0: serdes@900000 {
compatible = "ti,phy-am654-serdes";
reg = <0x900000 0x2000>;
reg-names = "serdes";
#phy-cells = <2>;
power-domains = <&k3_pds 153>;
clocks = <&k3_clks 153 4>, <&k3_clks 153 1>,
<&serdes1 AM654_SERDES_LO_REFCLK>;
clock-output-names = "serdes0_cmu_refclk", "serdes0_lo_refclk", "serdes0_ro_refclk";
assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>;
assigned-clock-parents = <&k3_clks 153 8>, <&k3_clks 153 4>;
ti,serdes-clk = <&serdes0_clk>;
mux-controls = <&serdes_mux 0>;
#clock-cells = <1>;
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -0,0 +1,244 @@
.. SPDX-License-Identifier: GPL-2.0
======================================
CoreSight System Configuration Manager
======================================
:Author: Mike Leach <mike.leach@linaro.org>
:Date: October 2020
Introduction
============
The CoreSight System Configuration manager is an API that allows the
programming of the CoreSight system with pre-defined configurations that
can then be easily enabled from sysfs or perf.
Many CoreSight components can be programmed in complex ways - especially ETMs.
In addition, components can interact across the CoreSight system, often via
the cross trigger components such as CTI and CTM. These system settings can
be defined and enabled as named configurations.
Basic Concepts
==============
This section introduces the basic concepts of a CoreSight system configuration.
Features
--------
A feature is a named set of programming for a CoreSight device. The programming
is device dependent, and can be defined in terms of absolute register values,
resource usage and parameter values.
The feature is defined using a descriptor. This descriptor is used to load onto
a matching device, either when the feature is loaded into the system, or when the
CoreSight device is registered with the configuration manager.
The load process involves interpreting the descriptor into a set of register
accesses in the driver - the resource usage and parameter descriptions
translated into appropriate register accesses. This interpretation makes it easy
and efficient for the feature to be programmed onto the device when required.
The feature will not be active on the device until the feature is enabled, and
the device itself is enabled. When the device is enabled then enabled features
will be programmed into the device hardware.
A feature is enabled as part of a configuration being enabled on the system.
Parameter Value
~~~~~~~~~~~~~~~
A parameter value is a named value that may be set by the user prior to the
feature being enabled that can adjust the behaviour of the operation programmed
by the feature.
For example, this could be a count value in a programmed operation that repeats
at a given rate. When the feature is enabled then the current value of the
parameter is used in programming the device.
The feature descriptor defines a default value for a parameter, which is used
if the user does not supply a new value.
Users can update parameter values using the configfs API for the CoreSight
system - which is described below.
The current value of the parameter is loaded into the device when the feature
is enabled on that device.
Configurations
--------------
A configuration defines a set of features that are to be used in a trace
session where the configuration is selected. For any trace session only one
configuration may be selected.
The features defined may be on any type of device that is registered
to support system configuration. A configuration may select features to be
enabled on a class of devices - i.e. any ETMv4, or specific devices, e.g. a
specific CTI on the system.
As with the feature, a descriptor is used to define the configuration.
This will define the features that must be enabled as part of the configuration
as well as any preset values that can be used to override default parameter
values.
Preset Values
~~~~~~~~~~~~~
Preset values are easily selectable sets of parameter values for the features
that the configuration uses. The number of values in a single preset set, equals
the sum of parameter values in the features used by the configuration.
e.g. a configuration consists of 3 features, one has 2 parameters, one has
a single parameter, and another has no parameters. A single preset set will
therefore have 3 values.
Presets are optionally defined by the configuration, up to 15 can be defined.
If no preset is selected, then the parameter values defined in the feature
are used as normal.
Operation
~~~~~~~~~
The following steps take place in the operation of a configuration.
1) In this example, the configuration is 'autofdo', which has an
associated feature 'strobing' that works on ETMv4 CoreSight Devices.
2) The configuration is enabled. For example 'perf' may select the
configuration as part of its command line::
perf record -e cs_etm/autofdo/ myapp
which will enable the 'autofdo' configuration.
3) perf starts tracing on the system. As each ETMv4 that perf uses for
trace is enabled, the configuration manager will check if the ETMv4
has a feature that relates to the currently active configuration.
In this case 'strobing' is enabled & programmed into the ETMv4.
4) When the ETMv4 is disabled, any registers marked as needing to be
saved will be read back.
5) At the end of the perf session, the configuration will be disabled.
Viewing Configurations and Features
===================================
The set of configurations and features that are currently loaded into the
system can be viewed using the configfs API.
Mount configfs as normal and the 'cs-syscfg' subsystem will appear::
$ ls /config
cs-syscfg stp-policy
This has two sub-directories::
$ cd cs-syscfg/
$ ls
configurations features
The system has the configuration 'autofdo' built in. It may be examined as
follows::
$ cd configurations/
$ ls
autofdo
$ cd autofdo/
$ ls
description preset1 preset3 preset5 preset7 preset9
feature_refs preset2 preset4 preset6 preset8
$ cat description
Setup ETMs with strobing for autofdo
$ cat feature_refs
strobing
Each preset declared has a preset<n> subdirectory declared. The values for
the preset can be examined::
$ cat preset1/values
strobing.window = 0x1388 strobing.period = 0x2
$ cat preset2/values
strobing.window = 0x1388 strobing.period = 0x4
The features referenced by the configuration can be examined in the features
directory::
$ cd ../../features/strobing/
$ ls
description matches nr_params params
$ cat description
Generate periodic trace capture windows.
parameter 'window': a number of CPU cycles (W)
parameter 'period': trace enabled for W cycles every period x W cycles
$ cat matches
SRC_ETMV4
$ cat nr_params
2
Move to the params directory to examine and adjust parameters::
cd params
$ ls
period window
$ cd period
$ ls
value
$ cat value
0x2710
# echo 15000 > value
# cat value
0x3a98
Parameters adjusted in this way are reflected in all device instances that have
loaded the feature.
Using Configurations in perf
============================
The configurations loaded into the CoreSight configuration management are
also declared in the perf 'cs_etm' event infrastructure so that they can
be selected when running trace under perf::
$ ls /sys/devices/cs_etm
configurations format perf_event_mux_interval_ms sinks type
events nr_addr_filters power
Key directories here are 'configurations' - which lists the loaded
configurations, and 'events' - a generic perf directory which allows
selection on the perf command line.::
$ ls configurations/
autofdo
$ cat configurations/autofdo
0xa7c3dddd
As with the sinks entries, this provides a hash of the configuration name.
The entry in the 'events' directory uses perfs built in syntax generator
to substitute the syntax for the name when evaluating the command::
$ ls events/
autofdo
$ cat events/autofdo
configid=0xa7c3dddd
The 'autofdo' configuration may be selected on the perf command line::
$ perf record -e cs_etm/autofdo/u --per-thread <application>
A preset to override the current parameter values can also be selected::
$ perf record -e cs_etm/autofdo,preset=1/u --per-thread <application>
When configurations are selected in this way, then the trace sink used is
automatically selected.

View File

@ -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

View File

@ -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 = <&reg_3v3>;
vdda-supply = <&reg_3v3>;
clocks = <&achc_24M>;
reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
};
gpioxra0: gpio@2 {

View File

@ -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",

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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,
&regions[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();

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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:

View File

@ -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) {

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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)
{

View File

@ -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,
};

View File

@ -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)

View File

@ -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.
*/

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View File

@ -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);
}

View File

@ -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,

View File

@ -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,

View File

@ -0,0 +1,83 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019-2021 Xilinx, Inc.
*/
#include <linux/dma-mapping.h>
#include <linux/fpga/fpga-mgr.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/string.h>
#include <linux/firmware/xlnx-zynqmp.h>
static int versal_fpga_ops_write_init(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *buf, size_t size)
{
return 0;
}
static int versal_fpga_ops_write(struct fpga_manager *mgr,
const char *buf, size_t size)
{
dma_addr_t dma_addr = 0;
char *kbuf;
int ret;
kbuf = dma_alloc_coherent(mgr->dev.parent, size, &dma_addr, GFP_KERNEL);
if (!kbuf)
return -ENOMEM;
memcpy(kbuf, buf, size);
ret = zynqmp_pm_load_pdi(PDI_SRC_DDR, dma_addr);
dma_free_coherent(mgr->dev.parent, size, kbuf, dma_addr);
return ret;
}
static const struct fpga_manager_ops versal_fpga_ops = {
.write_init = versal_fpga_ops_write_init,
.write = versal_fpga_ops_write,
};
static int versal_fpga_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct fpga_manager *mgr;
int ret;
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (ret < 0) {
dev_err(dev, "no usable DMA configuration\n");
return ret;
}
mgr = devm_fpga_mgr_create(dev, "Xilinx Versal FPGA Manager",
&versal_fpga_ops, NULL);
if (!mgr)
return -ENOMEM;
return devm_fpga_mgr_register(dev, mgr);
}
static const struct of_device_id versal_fpga_of_match[] = {
{ .compatible = "xlnx,versal-fpga", },
{},
};
MODULE_DEVICE_TABLE(of, versal_fpga_of_match);
static struct platform_driver versal_fpga_driver = {
.probe = versal_fpga_probe,
.driver = {
.name = "versal_fpga_manager",
.of_match_table = of_match_ptr(versal_fpga_of_match),
},
};
module_platform_driver(versal_fpga_driver);
MODULE_AUTHOR("Nava kishore Manne <nava.manne@xilinx.com>");
MODULE_AUTHOR("Appana Durga Kedareswara rao <appanad.durga.rao@xilinx.com>");
MODULE_DESCRIPTION("Xilinx Versal FPGA Manager");
MODULE_LICENSE("GPL");

View File

@ -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)
{

View File

@ -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 = {

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,153 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright(C) 2020 Linaro Limited. All rights reserved.
* Author: Mike Leach <mike.leach@linaro.org>
*/
#include "coresight-config.h"
/* ETMv4 includes and features */
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
#include "coresight-etm4x-cfg.h"
/* preload configurations and features */
/* preload in features for ETMv4 */
/* strobe feature */
static struct cscfg_parameter_desc strobe_params[] = {
{
.name = "window",
.value = 5000,
},
{
.name = "period",
.value = 10000,
},
};
static struct cscfg_regval_desc strobe_regs[] = {
/* resource selectors */
{
.type = CS_CFG_REG_TYPE_RESOURCE,
.offset = TRCRSCTLRn(2),
.hw_info = ETM4_CFG_RES_SEL,
.val32 = 0x20001,
},
{
.type = CS_CFG_REG_TYPE_RESOURCE,
.offset = TRCRSCTLRn(3),
.hw_info = ETM4_CFG_RES_SEQ,
.val32 = 0x20002,
},
/* strobe window counter 0 - reload from param 0 */
{
.type = CS_CFG_REG_TYPE_RESOURCE | CS_CFG_REG_TYPE_VAL_SAVE,
.offset = TRCCNTVRn(0),
.hw_info = ETM4_CFG_RES_CTR,
},
{
.type = CS_CFG_REG_TYPE_RESOURCE | CS_CFG_REG_TYPE_VAL_PARAM,
.offset = TRCCNTRLDVRn(0),
.hw_info = ETM4_CFG_RES_CTR,
.val32 = 0,
},
{
.type = CS_CFG_REG_TYPE_RESOURCE,
.offset = TRCCNTCTLRn(0),
.hw_info = ETM4_CFG_RES_CTR,
.val32 = 0x10001,
},
/* strobe period counter 1 - reload from param 1 */
{
.type = CS_CFG_REG_TYPE_RESOURCE | CS_CFG_REG_TYPE_VAL_SAVE,
.offset = TRCCNTVRn(1),
.hw_info = ETM4_CFG_RES_CTR,
},
{
.type = CS_CFG_REG_TYPE_RESOURCE | CS_CFG_REG_TYPE_VAL_PARAM,
.offset = TRCCNTRLDVRn(1),
.hw_info = ETM4_CFG_RES_CTR,
.val32 = 1,
},
{
.type = CS_CFG_REG_TYPE_RESOURCE,
.offset = TRCCNTCTLRn(1),
.hw_info = ETM4_CFG_RES_CTR,
.val32 = 0x8102,
},
/* sequencer */
{
.type = CS_CFG_REG_TYPE_RESOURCE,
.offset = TRCSEQEVRn(0),
.hw_info = ETM4_CFG_RES_SEQ,
.val32 = 0x0081,
},
{
.type = CS_CFG_REG_TYPE_RESOURCE,
.offset = TRCSEQEVRn(1),
.hw_info = ETM4_CFG_RES_SEQ,
.val32 = 0x0000,
},
/* view-inst */
{
.type = CS_CFG_REG_TYPE_STD | CS_CFG_REG_TYPE_VAL_MASK,
.offset = TRCVICTLR,
.val32 = 0x0003,
.mask32 = 0x0003,
},
/* end of regs */
};
struct cscfg_feature_desc strobe_etm4x = {
.name = "strobing",
.description = "Generate periodic trace capture windows.\n"
"parameter \'window\': a number of CPU cycles (W)\n"
"parameter \'period\': trace enabled for W cycles every period x W cycles\n",
.match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4,
.nr_params = ARRAY_SIZE(strobe_params),
.params_desc = strobe_params,
.nr_regs = ARRAY_SIZE(strobe_regs),
.regs_desc = strobe_regs,
};
/* create an autofdo configuration */
/* we will provide 9 sets of preset parameter values */
#define AFDO_NR_PRESETS 9
/* the total number of parameters in used features */
#define AFDO_NR_PARAMS ARRAY_SIZE(strobe_params)
static const char *afdo_ref_names[] = {
"strobing",
};
/*
* set of presets leaves strobing window constant while varying period to allow
* experimentation with mark / space ratios for various workloads
*/
static u64 afdo_presets[AFDO_NR_PRESETS][AFDO_NR_PARAMS] = {
{ 5000, 2 },
{ 5000, 4 },
{ 5000, 8 },
{ 5000, 16 },
{ 5000, 64 },
{ 5000, 128 },
{ 5000, 512 },
{ 5000, 1024 },
{ 5000, 4096 },
};
struct cscfg_config_desc afdo_etm4x = {
.name = "autofdo",
.description = "Setup ETMs with strobing for autofdo\n"
"Supplied presets allow experimentation with mark-space ratio for various loads\n",
.nr_feat_refs = ARRAY_SIZE(afdo_ref_names),
.feat_ref_names = afdo_ref_names,
.nr_presets = AFDO_NR_PRESETS,
.nr_total_params = AFDO_NR_PARAMS,
.presets = &afdo_presets[0][0],
};
/* end of ETM4x configurations */
#endif /* IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) */

View File

@ -0,0 +1,31 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright(C) 2020 Linaro Limited. All rights reserved.
* Author: Mike Leach <mike.leach@linaro.org>
*/
#include "coresight-cfg-preload.h"
#include "coresight-config.h"
#include "coresight-syscfg.h"
/* Basic features and configurations pre-loaded on initialisation */
static struct cscfg_feature_desc *preload_feats[] = {
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
&strobe_etm4x,
#endif
NULL
};
static struct cscfg_config_desc *preload_cfgs[] = {
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
&afdo_etm4x,
#endif
NULL
};
/* preload called on initialisation */
int cscfg_preload(void)
{
return cscfg_load_config_sets(preload_cfgs, preload_feats);
}

View File

@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright(C) 2020 Linaro Limited. All rights reserved.
* Author: Mike Leach <mike.leach@linaro.org>
*/
/* declare preloaded configurations and features */
/* from coresight-cfg-afdo.c - etm 4x features */
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
extern struct cscfg_feature_desc strobe_etm4x;
extern struct cscfg_config_desc afdo_etm4x;
#endif

View File

@ -0,0 +1,272 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright(C) 2020 Linaro Limited. All rights reserved.
* Author: Mike Leach <mike.leach@linaro.org>
*/
#include <linux/sysfs.h>
#include "coresight-config.h"
#include "coresight-priv.h"
/*
* This provides a set of generic functions that operate on configurations
* and features to manage the handling of parameters, the programming and
* saving of registers used by features on devices.
*/
/*
* Write the value held in the register structure into the driver internal memory
* location.
*/
static void cscfg_set_reg(struct cscfg_regval_csdev *reg_csdev)
{
u32 *p_val32 = (u32 *)reg_csdev->driver_regval;
u32 tmp32 = reg_csdev->reg_desc.val32;
if (reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_64BIT) {
*((u64 *)reg_csdev->driver_regval) = reg_csdev->reg_desc.val64;
return;
}
if (reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_MASK) {
tmp32 = *p_val32;
tmp32 &= ~reg_csdev->reg_desc.mask32;
tmp32 |= reg_csdev->reg_desc.val32 & reg_csdev->reg_desc.mask32;
}
*p_val32 = tmp32;
}
/*
* Read the driver value into the reg if this is marked as one we want to save.
*/
static void cscfg_save_reg(struct cscfg_regval_csdev *reg_csdev)
{
if (!(reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_SAVE))
return;
if (reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_64BIT)
reg_csdev->reg_desc.val64 = *(u64 *)(reg_csdev->driver_regval);
else
reg_csdev->reg_desc.val32 = *(u32 *)(reg_csdev->driver_regval);
}
/*
* Some register values are set from parameters. Initialise these registers
* from the current parameter values.
*/
static void cscfg_init_reg_param(struct cscfg_feature_csdev *feat_csdev,
struct cscfg_regval_desc *reg_desc,
struct cscfg_regval_csdev *reg_csdev)
{
struct cscfg_parameter_csdev *param_csdev;
/* for param, load routines have validated the index */
param_csdev = &feat_csdev->params_csdev[reg_desc->param_idx];
param_csdev->reg_csdev = reg_csdev;
param_csdev->val64 = reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_64BIT;
if (param_csdev->val64)
reg_csdev->reg_desc.val64 = param_csdev->current_value;
else
reg_csdev->reg_desc.val32 = (u32)param_csdev->current_value;
}
/* set values into the driver locations referenced in cscfg_reg_csdev */
static int cscfg_set_on_enable(struct cscfg_feature_csdev *feat_csdev)
{
unsigned long flags;
int i;
spin_lock_irqsave(feat_csdev->drv_spinlock, flags);
for (i = 0; i < feat_csdev->nr_regs; i++)
cscfg_set_reg(&feat_csdev->regs_csdev[i]);
spin_unlock_irqrestore(feat_csdev->drv_spinlock, flags);
dev_dbg(&feat_csdev->csdev->dev, "Feature %s: %s",
feat_csdev->feat_desc->name, "set on enable");
return 0;
}
/* copy back values from the driver locations referenced in cscfg_reg_csdev */
static void cscfg_save_on_disable(struct cscfg_feature_csdev *feat_csdev)
{
unsigned long flags;
int i;
spin_lock_irqsave(feat_csdev->drv_spinlock, flags);
for (i = 0; i < feat_csdev->nr_regs; i++)
cscfg_save_reg(&feat_csdev->regs_csdev[i]);
spin_unlock_irqrestore(feat_csdev->drv_spinlock, flags);
dev_dbg(&feat_csdev->csdev->dev, "Feature %s: %s",
feat_csdev->feat_desc->name, "save on disable");
}
/* default reset - restore default values */
void cscfg_reset_feat(struct cscfg_feature_csdev *feat_csdev)
{
struct cscfg_regval_desc *reg_desc;
struct cscfg_regval_csdev *reg_csdev;
int i;
/*
* set the default values for all parameters and regs from the
* relevant static descriptors.
*/
for (i = 0; i < feat_csdev->nr_params; i++)
feat_csdev->params_csdev[i].current_value =
feat_csdev->feat_desc->params_desc[i].value;
for (i = 0; i < feat_csdev->nr_regs; i++) {
reg_desc = &feat_csdev->feat_desc->regs_desc[i];
reg_csdev = &feat_csdev->regs_csdev[i];
reg_csdev->reg_desc.type = reg_desc->type;
/* check if reg set from a parameter otherwise desc default */
if (reg_desc->type & CS_CFG_REG_TYPE_VAL_PARAM)
cscfg_init_reg_param(feat_csdev, reg_desc, reg_csdev);
else
/*
* for normal values the union between val64 & val32 + mask32
* allows us to init using the 64 bit value
*/
reg_csdev->reg_desc.val64 = reg_desc->val64;
}
}
/*
* For the selected presets, we set the register associated with the parameter, to
* the value of the preset index associated with the parameter.
*/
static int cscfg_update_presets(struct cscfg_config_csdev *config_csdev, int preset)
{
int i, j, val_idx = 0, nr_cfg_params;
struct cscfg_parameter_csdev *param_csdev;
struct cscfg_feature_csdev *feat_csdev;
const struct cscfg_config_desc *config_desc = config_csdev->config_desc;
const char *name;
const u64 *preset_base;
u64 val;
/* preset in range 1 to nr_presets */
if (preset < 1 || preset > config_desc->nr_presets)
return -EINVAL;
/*
* Go through the array of features, assigning preset values to
* feature parameters in the order they appear.
* There should be precisely the same number of preset values as the
* sum of number of parameters over all the features - but we will
* ensure there is no overrun.
*/
nr_cfg_params = config_desc->nr_total_params;
preset_base = &config_desc->presets[(preset - 1) * nr_cfg_params];
for (i = 0; i < config_csdev->nr_feat; i++) {
feat_csdev = config_csdev->feats_csdev[i];
if (!feat_csdev->nr_params)
continue;
for (j = 0; j < feat_csdev->nr_params; j++) {
param_csdev = &feat_csdev->params_csdev[j];
name = feat_csdev->feat_desc->params_desc[j].name;
val = preset_base[val_idx++];
if (param_csdev->val64) {
dev_dbg(&config_csdev->csdev->dev,
"set param %s (%lld)", name, val);
param_csdev->reg_csdev->reg_desc.val64 = val;
} else {
param_csdev->reg_csdev->reg_desc.val32 = (u32)val;
dev_dbg(&config_csdev->csdev->dev,
"set param %s (%d)", name, (u32)val);
}
}
/* exit early if all params filled */
if (val_idx >= nr_cfg_params)
break;
}
return 0;
}
/*
* if we are not using a preset, then need to update the feature params
* with current values. This sets the register associated with the parameter
* with the current value of that parameter.
*/
static int cscfg_update_curr_params(struct cscfg_config_csdev *config_csdev)
{
int i, j;
struct cscfg_feature_csdev *feat_csdev;
struct cscfg_parameter_csdev *param_csdev;
const char *name;
u64 val;
for (i = 0; i < config_csdev->nr_feat; i++) {
feat_csdev = config_csdev->feats_csdev[i];
if (!feat_csdev->nr_params)
continue;
for (j = 0; j < feat_csdev->nr_params; j++) {
param_csdev = &feat_csdev->params_csdev[j];
name = feat_csdev->feat_desc->params_desc[j].name;
val = param_csdev->current_value;
if (param_csdev->val64) {
dev_dbg(&config_csdev->csdev->dev,
"set param %s (%lld)", name, val);
param_csdev->reg_csdev->reg_desc.val64 = val;
} else {
param_csdev->reg_csdev->reg_desc.val32 = (u32)val;
dev_dbg(&config_csdev->csdev->dev,
"set param %s (%d)", name, (u32)val);
}
}
}
return 0;
}
/*
* Configuration values will be programmed into the driver locations if enabling, or read
* from relevant locations on disable.
*/
static int cscfg_prog_config(struct cscfg_config_csdev *config_csdev, bool enable)
{
int i, err = 0;
struct cscfg_feature_csdev *feat_csdev;
struct coresight_device *csdev;
for (i = 0; i < config_csdev->nr_feat; i++) {
feat_csdev = config_csdev->feats_csdev[i];
csdev = feat_csdev->csdev;
dev_dbg(&csdev->dev, "cfg %s; %s feature:%s", config_csdev->config_desc->name,
enable ? "enable" : "disable", feat_csdev->feat_desc->name);
if (enable)
err = cscfg_set_on_enable(feat_csdev);
else
cscfg_save_on_disable(feat_csdev);
if (err)
break;
}
return err;
}
/*
* Enable configuration for the device. Will result in the internal driver data
* being updated ready for programming into the device.
*
* @config_csdev: config_csdev to set.
* @preset: preset values to use - 0 for default.
*/
int cscfg_csdev_enable_config(struct cscfg_config_csdev *config_csdev, int preset)
{
int err = 0;
if (preset)
err = cscfg_update_presets(config_csdev, preset);
else
err = cscfg_update_curr_params(config_csdev);
if (!err)
err = cscfg_prog_config(config_csdev, true);
return err;
}
void cscfg_csdev_disable_config(struct cscfg_config_csdev *config_csdev)
{
cscfg_prog_config(config_csdev, false);
}

View File

@ -0,0 +1,253 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 Linaro Limited, All rights reserved.
* Author: Mike Leach <mike.leach@linaro.org>
*/
#ifndef _CORESIGHT_CORESIGHT_CONFIG_H
#define _CORESIGHT_CORESIGHT_CONFIG_H
#include <linux/coresight.h>
#include <linux/types.h>
/* CoreSight Configuration Management - component and system wide configuration */
/*
* Register type flags for register value descriptor:
* describe how the value is interpreted, and handled.
*/
#define CS_CFG_REG_TYPE_STD 0x80 /* reg is standard reg */
#define CS_CFG_REG_TYPE_RESOURCE 0x40 /* reg is a resource */
#define CS_CFG_REG_TYPE_VAL_PARAM 0x08 /* reg value uses param */
#define CS_CFG_REG_TYPE_VAL_MASK 0x04 /* reg value bit masked */
#define CS_CFG_REG_TYPE_VAL_64BIT 0x02 /* reg value 64 bit */
#define CS_CFG_REG_TYPE_VAL_SAVE 0x01 /* reg value save on disable */
/*
* flags defining what device class a feature will match to when processing a
* system configuration - used by config data and devices.
*/
#define CS_CFG_MATCH_CLASS_SRC_ALL 0x0001 /* match any source */
#define CS_CFG_MATCH_CLASS_SRC_ETM4 0x0002 /* match any ETMv4 device */
/* flags defining device instance matching - used in config match desc data. */
#define CS_CFG_MATCH_INST_ANY 0x80000000 /* any instance of a class */
/*
* Limit number of presets in a configuration
* This is related to the number of bits (4) we use to select the preset on
* the perf command line. Preset 0 is always none selected.
* See PMU_FORMAT_ATTR(preset, "config:0-3") in coresight-etm-perf.c
*/
#define CS_CFG_CONFIG_PRESET_MAX 15
/**
* Parameter descriptor for a device feature.
*
* @name: Name of parameter.
* @value: Initial or default value.
*/
struct cscfg_parameter_desc {
const char *name;
u64 value;
};
/**
* Representation of register value and a descriptor of register usage.
*
* Used as a descriptor in the feature descriptors.
* Used as a value in when in a feature loading into a csdev.
*
* Supports full 64 bit register value, or 32 bit value with optional mask
* value.
*
* @type: define register usage and interpretation.
* @offset: the address offset for register in the hardware device (per device specification).
* @hw_info: optional hardware device type specific information. (ETM / CTI specific etc)
* @val64: 64 bit value.
* @val32: 32 bit value.
* @mask32: 32 bit mask when using 32 bit value to access device register - if mask type.
* @param_idx: parameter index value into parameter array if param type.
*/
struct cscfg_regval_desc {
struct {
u32 type:8;
u32 offset:12;
u32 hw_info:12;
};
union {
u64 val64;
struct {
u32 val32;
u32 mask32;
};
u32 param_idx;
};
};
/**
* Device feature descriptor - combination of registers and parameters to
* program a device to implement a specific complex function.
*
* @name: feature name.
* @description: brief description of the feature.
* @item: List entry.
* @match_flags: matching information if loading into a device
* @nr_params: number of parameters used.
* @params_desc: array of parameters used.
* @nr_regs: number of registers used.
* @regs_desc: array of registers used.
*/
struct cscfg_feature_desc {
const char *name;
const char *description;
struct list_head item;
u32 match_flags;
int nr_params;
struct cscfg_parameter_desc *params_desc;
int nr_regs;
struct cscfg_regval_desc *regs_desc;
};
/**
* Configuration descriptor - describes selectable system configuration.
*
* A configuration describes device features in use, and may provide preset
* values for the parameters in those features.
*
* A single set of presets is the sum of the parameters declared by
* all the features in use - this value is @nr_total_params.
*
* @name: name of the configuration - used for selection.
* @description: description of the purpose of the configuration.
* @item: list entry.
* @nr_feat_refs: Number of features used in this configuration.
* @feat_ref_names: references to features used in this configuration.
* @nr_presets: Number of sets of presets supplied by this configuration.
* @nr_total_params: Sum of all parameters declared by used features
* @presets: Array of preset values.
* @event_ea: Extended attribute for perf event value
* @active_cnt: ref count for activate on this configuration.
*
*/
struct cscfg_config_desc {
const char *name;
const char *description;
struct list_head item;
int nr_feat_refs;
const char **feat_ref_names;
int nr_presets;
int nr_total_params;
const u64 *presets; /* nr_presets * nr_total_params */
struct dev_ext_attribute *event_ea;
atomic_t active_cnt;
};
/**
* config register instance - part of a loaded feature.
* maps register values to csdev driver structures
*
* @reg_desc: value to use when setting feature on device / store for
* readback of volatile values.
* @driver_regval: pointer to internal driver element used to set the value
* in hardware.
*/
struct cscfg_regval_csdev {
struct cscfg_regval_desc reg_desc;
void *driver_regval;
};
/**
* config parameter instance - part of a loaded feature.
*
* @feat_csdev: parent feature
* @reg_csdev: register value updated by this parameter.
* @current_value: current value of parameter - may be set by user via
* sysfs, or modified during device operation.
* @val64: true if 64 bit value
*/
struct cscfg_parameter_csdev {
struct cscfg_feature_csdev *feat_csdev;
struct cscfg_regval_csdev *reg_csdev;
u64 current_value;
bool val64;
};
/**
* Feature instance loaded into a CoreSight device.
*
* When a feature is loaded into a specific device, then this structure holds
* the connections between the register / parameter values used and the
* internal data structures that are written when the feature is enabled.
*
* Since applying a feature modifies internal data structures in the device,
* then we have a reference to the device spinlock to protect access to these
* structures (@drv_spinlock).
*
* @feat_desc: pointer to the static descriptor for this feature.
* @csdev: parent CoreSight device instance.
* @node: list entry into feature list for this device.
* @drv_spinlock: device spinlock for access to driver register data.
* @nr_params: number of parameters.
* @params_csdev: current parameter values on this device
* @nr_regs: number of registers to be programmed.
* @regs_csdev: Programming details for the registers
*/
struct cscfg_feature_csdev {
const struct cscfg_feature_desc *feat_desc;
struct coresight_device *csdev;
struct list_head node;
spinlock_t *drv_spinlock;
int nr_params;
struct cscfg_parameter_csdev *params_csdev;
int nr_regs;
struct cscfg_regval_csdev *regs_csdev;
};
/**
* Configuration instance when loaded into a CoreSight device.
*
* The instance contains references to loaded features on this device that are
* used by the configuration.
*
* @config_desc:reference to the descriptor for this configuration
* @csdev: parent coresight device for this configuration instance.
* @enabled: true if configuration is enabled on this device.
* @node: list entry within the coresight device
* @nr_feat: Number of features on this device that are used in the
* configuration.
* @feats_csdev:references to the device features to enable.
*/
struct cscfg_config_csdev {
const struct cscfg_config_desc *config_desc;
struct coresight_device *csdev;
bool enabled;
struct list_head node;
int nr_feat;
struct cscfg_feature_csdev *feats_csdev[0];
};
/**
* Coresight device operations.
*
* Registered coresight devices provide these operations to manage feature
* instances compatible with the device hardware and drivers
*
* @load_feat: Pass a feature descriptor into the device and create the
* loaded feature instance (struct cscfg_feature_csdev).
*/
struct cscfg_csdev_feat_ops {
int (*load_feat)(struct coresight_device *csdev,
struct cscfg_feature_csdev *feat_csdev);
};
/* coresight config helper functions*/
/* enable / disable config on a device - called with appropriate locks set.*/
int cscfg_csdev_enable_config(struct cscfg_config_csdev *config_csdev, int preset);
void cscfg_csdev_disable_config(struct cscfg_config_csdev *config_csdev);
/* reset a feature to default values */
void cscfg_reset_feat(struct cscfg_feature_csdev *feat_csdev);
#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -0,0 +1,182 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright(C) 2020 Linaro Limited. All rights reserved.
* Author: Mike Leach <mike.leach@linaro.org>
*/
#include "coresight-etm4x.h"
#include "coresight-etm4x-cfg.h"
#include "coresight-priv.h"
#include "coresight-syscfg.h"
/* defines to associate register IDs with driver data locations */
#define CHECKREG(cval, elem) \
{ \
if (offset == cval) { \
reg_csdev->driver_regval = &drvcfg->elem; \
err = 0; \
break; \
} \
}
#define CHECKREGIDX(cval, elem, off_idx, mask) \
{ \
if (mask == cval) { \
reg_csdev->driver_regval = &drvcfg->elem[off_idx]; \
err = 0; \
break; \
} \
}
/**
* etm4_cfg_map_reg_offset - validate and map the register offset into a
* location in the driver config struct.
*
* Limits the number of registers that can be accessed and programmed in
* features, to those which are used to control the trace capture parameters.
*
* Omits or limits access to those which the driver must use exclusively.
*
* Invalid offsets will result in fail code return and feature load failure.
*
* @drvdata: driver data to map into.
* @reg: register to map.
* @offset: device offset for the register
*/
static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
struct cscfg_regval_csdev *reg_csdev, u32 offset)
{
int err = -EINVAL, idx;
struct etmv4_config *drvcfg = &drvdata->config;
u32 off_mask;
if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) ||
((offset >= TRCSEQRSTEVR) && (offset <= TRCEXTINSELR)) ||
((offset >= TRCCIDCCTLR0) && (offset <= TRCVMIDCCTLR1))) {
do {
CHECKREG(TRCEVENTCTL0R, eventctrl0);
CHECKREG(TRCEVENTCTL1R, eventctrl1);
CHECKREG(TRCSTALLCTLR, stall_ctrl);
CHECKREG(TRCTSCTLR, ts_ctrl);
CHECKREG(TRCSYNCPR, syncfreq);
CHECKREG(TRCCCCTLR, ccctlr);
CHECKREG(TRCBBCTLR, bb_ctrl);
CHECKREG(TRCVICTLR, vinst_ctrl);
CHECKREG(TRCVIIECTLR, viiectlr);
CHECKREG(TRCVISSCTLR, vissctlr);
CHECKREG(TRCVIPCSSCTLR, vipcssctlr);
CHECKREG(TRCSEQRSTEVR, seq_rst);
CHECKREG(TRCSEQSTR, seq_state);
CHECKREG(TRCEXTINSELR, ext_inp);
CHECKREG(TRCCIDCCTLR0, ctxid_mask0);
CHECKREG(TRCCIDCCTLR1, ctxid_mask1);
CHECKREG(TRCVMIDCCTLR0, vmid_mask0);
CHECKREG(TRCVMIDCCTLR1, vmid_mask1);
} while (0);
} else if ((offset & GENMASK(11, 4)) == TRCSEQEVRn(0)) {
/* sequencer state control registers */
idx = (offset & GENMASK(3, 0)) / 4;
if (idx < ETM_MAX_SEQ_STATES) {
reg_csdev->driver_regval = &drvcfg->seq_ctrl[idx];
err = 0;
}
} else if ((offset >= TRCSSCCRn(0)) && (offset <= TRCSSPCICRn(7))) {
/* 32 bit, 8 off indexed register sets */
idx = (offset & GENMASK(4, 0)) / 4;
off_mask = (offset & GENMASK(11, 5));
do {
CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx, off_mask);
CHECKREGIDX(TRCSSCSRn(0), ss_status, idx, off_mask);
CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx, off_mask);
} while (0);
} else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
/* 64 bit, 8 off indexed register sets */
idx = (offset & GENMASK(5, 0)) / 8;
off_mask = (offset & GENMASK(11, 6));
do {
CHECKREGIDX(TRCCIDCVRn(0), ctxid_pid, idx, off_mask);
CHECKREGIDX(TRCVMIDCVRn(0), vmid_val, idx, off_mask);
} while (0);
} else if ((offset >= TRCRSCTLRn(2)) &&
(offset <= TRCRSCTLRn((ETM_MAX_RES_SEL - 1)))) {
/* 32 bit resource selection regs, 32 off, skip fixed 0,1 */
idx = (offset & GENMASK(6, 0)) / 4;
if (idx < ETM_MAX_RES_SEL) {
reg_csdev->driver_regval = &drvcfg->res_ctrl[idx];
err = 0;
}
} else if ((offset >= TRCACVRn(0)) &&
(offset <= TRCACATRn((ETM_MAX_SINGLE_ADDR_CMP - 1)))) {
/* 64 bit addr cmp regs, 16 off */
idx = (offset & GENMASK(6, 0)) / 8;
off_mask = offset & GENMASK(11, 7);
do {
CHECKREGIDX(TRCACVRn(0), addr_val, idx, off_mask);
CHECKREGIDX(TRCACATRn(0), addr_acc, idx, off_mask);
} while (0);
} else if ((offset >= TRCCNTRLDVRn(0)) &&
(offset <= TRCCNTVRn((ETMv4_MAX_CNTR - 1)))) {
/* 32 bit counter regs, 4 off (ETMv4_MAX_CNTR - 1) */
idx = (offset & GENMASK(3, 0)) / 4;
off_mask = offset & GENMASK(11, 4);
do {
CHECKREGIDX(TRCCNTRLDVRn(0), cntrldvr, idx, off_mask);
CHECKREGIDX(TRCCNTCTLRn(0), cntr_ctrl, idx, off_mask);
CHECKREGIDX(TRCCNTVRn(0), cntr_val, idx, off_mask);
} while (0);
}
return err;
}
/**
* etm4_cfg_load_feature - load a feature into a device instance.
*
* @csdev: An ETMv4 CoreSight device.
* @feat: The feature to be loaded.
*
* The function will load a feature instance into the device, checking that
* the register definitions are valid for the device.
*
* Parameter and register definitions will be converted into internal
* structures that are used to set the values in the driver when the
* feature is enabled for the device.
*
* The feature spinlock pointer is initialised to the same spinlock
* that the driver uses to protect the internal register values.
*/
static int etm4_cfg_load_feature(struct coresight_device *csdev,
struct cscfg_feature_csdev *feat_csdev)
{
struct device *dev = csdev->dev.parent;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
const struct cscfg_feature_desc *feat_desc = feat_csdev->feat_desc;
u32 offset;
int i = 0, err = 0;
/*
* essential we set the device spinlock - this is used in the generic
* programming routines when copying values into the drvdata structures
* via the pointers setup in etm4_cfg_map_reg_offset().
*/
feat_csdev->drv_spinlock = &drvdata->spinlock;
/* process the register descriptions */
for (i = 0; i < feat_csdev->nr_regs && !err; i++) {
offset = feat_desc->regs_desc[i].offset;
err = etm4_cfg_map_reg_offset(drvdata, &feat_csdev->regs_csdev[i], offset);
}
return err;
}
/* match information when loading configurations */
#define CS_CFG_ETM4_MATCH_FLAGS (CS_CFG_MATCH_CLASS_SRC_ALL | \
CS_CFG_MATCH_CLASS_SRC_ETM4)
int etm4_cscfg_register(struct coresight_device *csdev)
{
struct cscfg_csdev_feat_ops ops;
ops.load_feat = &etm4_cfg_load_feature;
return cscfg_register_csdev(csdev, CS_CFG_ETM4_MATCH_FLAGS, &ops);
}

View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _CORESIGHT_ETM4X_CFG_H
#define _CORESIGHT_ETM4X_CFG_H
#include "coresight-config.h"
#include "coresight-etm4x.h"
/* ETMv4 specific config defines */
/* resource IDs */
#define ETM4_CFG_RES_CTR 0x001
#define ETM4_CFG_RES_CMP 0x002
#define ETM4_CFG_RES_CMP_PAIR0 0x003
#define ETM4_CFG_RES_CMP_PAIR1 0x004
#define ETM4_CFG_RES_SEL 0x005
#define ETM4_CFG_RES_SEL_PAIR0 0x006
#define ETM4_CFG_RES_SEL_PAIR1 0x007
#define ETM4_CFG_RES_SEQ 0x008
#define ETM4_CFG_RES_TS 0x009
#define ETM4_CFG_RES_MASK 0x00F
/* ETMv4 specific config functions */
int etm4_cscfg_register(struct coresight_device *csdev);
#endif /* CORESIGHT_ETM4X_CFG_H */

View File

@ -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;

View File

@ -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);

View File

@ -0,0 +1,396 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020 Linaro Limited, All rights reserved.
* Author: Mike Leach <mike.leach@linaro.org>
*/
#include <linux/configfs.h>
#include "coresight-syscfg-configfs.h"
/* create a default ci_type. */
static inline struct config_item_type *cscfg_create_ci_type(void)
{
struct config_item_type *ci_type;
ci_type = devm_kzalloc(cscfg_device(), sizeof(*ci_type), GFP_KERNEL);
if (ci_type)
ci_type->ct_owner = THIS_MODULE;
return ci_type;
}
/* configurations sub-group */
/* attributes for the config view group */
static ssize_t cscfg_cfg_description_show(struct config_item *item, char *page)
{
struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
struct cscfg_fs_config, group);
return scnprintf(page, PAGE_SIZE, "%s", fs_config->config_desc->description);
}
CONFIGFS_ATTR_RO(cscfg_cfg_, description);
static ssize_t cscfg_cfg_feature_refs_show(struct config_item *item, char *page)
{
struct cscfg_fs_config *fs_config = container_of(to_config_group(item),
struct cscfg_fs_config, group);
const struct cscfg_config_desc *config_desc = fs_config->config_desc;
ssize_t ch_used = 0;
int i;
for (i = 0; i < config_desc->nr_feat_refs; i++)
ch_used += scnprintf(page + ch_used, PAGE_SIZE - ch_used,
"%s\n", config_desc->feat_ref_names[i]);
return ch_used;
}
CONFIGFS_ATTR_RO(cscfg_cfg_, feature_refs);
/* list preset values in order of features and params */
static ssize_t cscfg_cfg_values_show(struct config_item *item, char *page)
{
const struct cscfg_feature_desc *feat_desc;
const struct cscfg_config_desc *config_desc;
struct cscfg_fs_preset *fs_preset;
int i, j, val_idx, preset_idx;
ssize_t used = 0;
fs_preset = container_of(to_config_group(item), struct cscfg_fs_preset, group);
config_desc = fs_preset->config_desc;
if (!config_desc->nr_presets)
return 0;
preset_idx = fs_preset->preset_num - 1;
/* start index on the correct array line */
val_idx = config_desc->nr_total_params * preset_idx;
/*
* A set of presets is the sum of all params in used features,
* in order of declaration of features and params in the features
*/
for (i = 0; i < config_desc->nr_feat_refs; i++) {
feat_desc = cscfg_get_named_feat_desc(config_desc->feat_ref_names[i]);
for (j = 0; j < feat_desc->nr_params; j++) {
used += scnprintf(page + used, PAGE_SIZE - used,
"%s.%s = 0x%llx ",
feat_desc->name,
feat_desc->params_desc[j].name,
config_desc->presets[val_idx++]);
}
}
used += scnprintf(page + used, PAGE_SIZE - used, "\n");
return used;
}
CONFIGFS_ATTR_RO(cscfg_cfg_, values);
static struct configfs_attribute *cscfg_config_view_attrs[] = {
&cscfg_cfg_attr_description,
&cscfg_cfg_attr_feature_refs,
NULL,
};
static struct config_item_type cscfg_config_view_type = {
.ct_owner = THIS_MODULE,
.ct_attrs = cscfg_config_view_attrs,
};
static struct configfs_attribute *cscfg_config_preset_attrs[] = {
&cscfg_cfg_attr_values,
NULL,
};
static struct config_item_type cscfg_config_preset_type = {
.ct_owner = THIS_MODULE,
.ct_attrs = cscfg_config_preset_attrs,
};
static int cscfg_add_preset_groups(struct cscfg_fs_config *cfg_view)
{
int preset_num;
struct cscfg_fs_preset *cfg_fs_preset;
struct cscfg_config_desc *config_desc = cfg_view->config_desc;
char name[CONFIGFS_ITEM_NAME_LEN];
if (!config_desc->nr_presets)
return 0;
for (preset_num = 1; preset_num <= config_desc->nr_presets; preset_num++) {
cfg_fs_preset = devm_kzalloc(cscfg_device(),
sizeof(struct cscfg_fs_preset), GFP_KERNEL);
if (!cfg_fs_preset)
return -ENOMEM;
snprintf(name, CONFIGFS_ITEM_NAME_LEN, "preset%d", preset_num);
cfg_fs_preset->preset_num = preset_num;
cfg_fs_preset->config_desc = cfg_view->config_desc;
config_group_init_type_name(&cfg_fs_preset->group, name,
&cscfg_config_preset_type);
configfs_add_default_group(&cfg_fs_preset->group, &cfg_view->group);
}
return 0;
}
static struct config_group *cscfg_create_config_group(struct cscfg_config_desc *config_desc)
{
struct cscfg_fs_config *cfg_view;
struct device *dev = cscfg_device();
int err;
if (!dev)
return ERR_PTR(-EINVAL);
cfg_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_config), GFP_KERNEL);
if (!cfg_view)
return ERR_PTR(-ENOMEM);
cfg_view->config_desc = config_desc;
config_group_init_type_name(&cfg_view->group, config_desc->name, &cscfg_config_view_type);
/* add in a preset<n> dir for each preset */
err = cscfg_add_preset_groups(cfg_view);
if (err)
return ERR_PTR(err);
return &cfg_view->group;
}
/* attributes for features view */
static ssize_t cscfg_feat_description_show(struct config_item *item, char *page)
{
struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item),
struct cscfg_fs_feature, group);
return scnprintf(page, PAGE_SIZE, "%s", fs_feat->feat_desc->description);
}
CONFIGFS_ATTR_RO(cscfg_feat_, description);
static ssize_t cscfg_feat_matches_show(struct config_item *item, char *page)
{
struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item),
struct cscfg_fs_feature, group);
u32 match_flags = fs_feat->feat_desc->match_flags;
int used = 0;
if (match_flags & CS_CFG_MATCH_CLASS_SRC_ALL)
used = scnprintf(page, PAGE_SIZE, "SRC_ALL ");
if (match_flags & CS_CFG_MATCH_CLASS_SRC_ETM4)
used += scnprintf(page + used, PAGE_SIZE - used, "SRC_ETMV4 ");
used += scnprintf(page + used, PAGE_SIZE - used, "\n");
return used;
}
CONFIGFS_ATTR_RO(cscfg_feat_, matches);
static ssize_t cscfg_feat_nr_params_show(struct config_item *item, char *page)
{
struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item),
struct cscfg_fs_feature, group);
return scnprintf(page, PAGE_SIZE, "%d\n", fs_feat->feat_desc->nr_params);
}
CONFIGFS_ATTR_RO(cscfg_feat_, nr_params);
/* base feature desc attrib structures */
static struct configfs_attribute *cscfg_feature_view_attrs[] = {
&cscfg_feat_attr_description,
&cscfg_feat_attr_matches,
&cscfg_feat_attr_nr_params,
NULL,
};
static struct config_item_type cscfg_feature_view_type = {
.ct_owner = THIS_MODULE,
.ct_attrs = cscfg_feature_view_attrs,
};
static ssize_t cscfg_param_value_show(struct config_item *item, char *page)
{
struct cscfg_fs_param *param_item = container_of(to_config_group(item),
struct cscfg_fs_param, group);
u64 value = param_item->feat_desc->params_desc[param_item->param_idx].value;
return scnprintf(page, PAGE_SIZE, "0x%llx\n", value);
}
static ssize_t cscfg_param_value_store(struct config_item *item,
const char *page, size_t size)
{
struct cscfg_fs_param *param_item = container_of(to_config_group(item),
struct cscfg_fs_param, group);
struct cscfg_feature_desc *feat_desc = param_item->feat_desc;
int param_idx = param_item->param_idx;
u64 value;
int err;
err = kstrtoull(page, 0, &value);
if (!err)
err = cscfg_update_feat_param_val(feat_desc, param_idx, value);
return err ? err : size;
}
CONFIGFS_ATTR(cscfg_param_, value);
static struct configfs_attribute *cscfg_param_view_attrs[] = {
&cscfg_param_attr_value,
NULL,
};
static struct config_item_type cscfg_param_view_type = {
.ct_owner = THIS_MODULE,
.ct_attrs = cscfg_param_view_attrs,
};
/*
* configfs has far less functionality provided to add attributes dynamically than sysfs,
* and the show and store fns pass the enclosing config_item so the actual attribute cannot
* be determined. Therefore we add each item as a group directory, with a value attribute.
*/
static int cscfg_create_params_group_items(struct cscfg_feature_desc *feat_desc,
struct config_group *params_group)
{
struct device *dev = cscfg_device();
struct cscfg_fs_param *param_item;
int i;
/* parameter items - as groups with default_value attribute */
for (i = 0; i < feat_desc->nr_params; i++) {
param_item = devm_kzalloc(dev, sizeof(struct cscfg_fs_param), GFP_KERNEL);
if (!param_item)
return -ENOMEM;
param_item->feat_desc = feat_desc;
param_item->param_idx = i;
config_group_init_type_name(&param_item->group,
feat_desc->params_desc[i].name,
&cscfg_param_view_type);
configfs_add_default_group(&param_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);
}

View File

@ -0,0 +1,45 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Coresight system configuration driver - support for configfs.
*/
#ifndef CORESIGHT_SYSCFG_CONFIGFS_H
#define CORESIGHT_SYSCFG_CONFIGFS_H
#include <linux/configfs.h>
#include "coresight-syscfg.h"
#define CSCFG_FS_SUBSYS_NAME "cs-syscfg"
/* container for configuration view */
struct cscfg_fs_config {
struct cscfg_config_desc *config_desc;
struct config_group group;
};
/* container for feature view */
struct cscfg_fs_feature {
struct cscfg_feature_desc *feat_desc;
struct config_group group;
};
/* container for parameter view */
struct cscfg_fs_param {
int param_idx;
struct cscfg_feature_desc *feat_desc;
struct config_group group;
};
/* container for preset view */
struct cscfg_fs_preset {
int preset_num;
struct cscfg_config_desc *config_desc;
struct config_group group;
};
int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr);
void cscfg_configfs_release(struct cscfg_manager *cscfg_mgr);
int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc);
int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc);
#endif /* CORESIGHT_SYSCFG_CONFIGFS_H */

View File

@ -0,0 +1,847 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020 Linaro Limited, All rights reserved.
* Author: Mike Leach <mike.leach@linaro.org>
*/
#include <linux/platform_device.h>
#include "coresight-config.h"
#include "coresight-etm-perf.h"
#include "coresight-syscfg.h"
#include "coresight-syscfg-configfs.h"
/*
* cscfg_ API manages configurations and features for the entire coresight
* infrastructure.
*
* It allows the loading of configurations and features, and loads these into
* coresight devices as appropriate.
*/
/* protect the cscsg_data and device */
static DEFINE_MUTEX(cscfg_mutex);
/* only one of these */
static struct cscfg_manager *cscfg_mgr;
/* load features and configuations into the lists */
/* get name feature instance from a coresight device list of features */
static struct cscfg_feature_csdev *
cscfg_get_feat_csdev(struct coresight_device *csdev, const char *name)
{
struct cscfg_feature_csdev *feat_csdev = NULL;
list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) {
if (strcmp(feat_csdev->feat_desc->name, name) == 0)
return feat_csdev;
}
return NULL;
}
/* allocate the device config instance - with max number of used features */
static struct cscfg_config_csdev *
cscfg_alloc_csdev_cfg(struct coresight_device *csdev, int nr_feats)
{
struct cscfg_config_csdev *config_csdev = NULL;
struct device *dev = csdev->dev.parent;
/* this is being allocated using the devm for the coresight device */
config_csdev = devm_kzalloc(dev,
offsetof(struct cscfg_config_csdev, feats_csdev[nr_feats]),
GFP_KERNEL);
if (!config_csdev)
return NULL;
config_csdev->csdev = csdev;
return config_csdev;
}
/* Load a config into a device if there are any feature matches between config and device */
static int cscfg_add_csdev_cfg(struct coresight_device *csdev,
struct cscfg_config_desc *config_desc)
{
struct cscfg_config_csdev *config_csdev = NULL;
struct cscfg_feature_csdev *feat_csdev;
unsigned long flags;
int i;
/* look at each required feature and see if it matches any feature on the device */
for (i = 0; i < config_desc->nr_feat_refs; i++) {
/* look for a matching name */
feat_csdev = cscfg_get_feat_csdev(csdev, config_desc->feat_ref_names[i]);
if (feat_csdev) {
/*
* At least one feature on this device matches the config
* add a config instance to the device and a reference to the feature.
*/
if (!config_csdev) {
config_csdev = cscfg_alloc_csdev_cfg(csdev,
config_desc->nr_feat_refs);
if (!config_csdev)
return -ENOMEM;
config_csdev->config_desc = config_desc;
}
config_csdev->feats_csdev[config_csdev->nr_feat++] = feat_csdev;
}
}
/* if matched features, add config to device.*/
if (config_csdev) {
spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
list_add(&config_csdev->node, &csdev->config_csdev_list);
spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
}
return 0;
}
/*
* Add the config to the set of registered devices - call with mutex locked.
* Iterates through devices - any device that matches one or more of the
* configuration features will load it, the others will ignore it.
*/
static int cscfg_add_cfg_to_csdevs(struct cscfg_config_desc *config_desc)
{
struct cscfg_registered_csdev *csdev_item;
int err;
list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
err = cscfg_add_csdev_cfg(csdev_item->csdev, config_desc);
if (err)
return err;
}
return 0;
}
/*
* Allocate a feature object for load into a csdev.
* memory allocated using the csdev->dev object using devm managed allocator.
*/
static struct cscfg_feature_csdev *
cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc *feat_desc)
{
struct cscfg_feature_csdev *feat_csdev = NULL;
struct device *dev = csdev->dev.parent;
int i;
feat_csdev = devm_kzalloc(dev, sizeof(struct cscfg_feature_csdev), GFP_KERNEL);
if (!feat_csdev)
return NULL;
/* parameters are optional - could be 0 */
feat_csdev->nr_params = feat_desc->nr_params;
/*
* if we need parameters, zero alloc the space here, the load routine in
* the csdev device driver will fill out some information according to
* feature descriptor.
*/
if (feat_csdev->nr_params) {
feat_csdev->params_csdev = devm_kcalloc(dev, feat_csdev->nr_params,
sizeof(struct cscfg_parameter_csdev),
GFP_KERNEL);
if (!feat_csdev->params_csdev)
return NULL;
/*
* fill in the feature reference in the param - other fields
* handled by loader in csdev.
*/
for (i = 0; i < feat_csdev->nr_params; i++)
feat_csdev->params_csdev[i].feat_csdev = feat_csdev;
}
/*
* Always have registers to program - again the load routine in csdev device
* will fill out according to feature descriptor and device requirements.
*/
feat_csdev->nr_regs = feat_desc->nr_regs;
feat_csdev->regs_csdev = devm_kcalloc(dev, feat_csdev->nr_regs,
sizeof(struct cscfg_regval_csdev),
GFP_KERNEL);
if (!feat_csdev->regs_csdev)
return NULL;
/* load the feature default values */
feat_csdev->feat_desc = feat_desc;
feat_csdev->csdev = csdev;
return feat_csdev;
}
/* load one feature into one coresight device */
static int cscfg_load_feat_csdev(struct coresight_device *csdev,
struct cscfg_feature_desc *feat_desc,
struct cscfg_csdev_feat_ops *ops)
{
struct cscfg_feature_csdev *feat_csdev;
unsigned long flags;
int err;
if (!ops->load_feat)
return -EINVAL;
feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc);
if (!feat_csdev)
return -ENOMEM;
/* load the feature into the device */
err = ops->load_feat(csdev, feat_csdev);
if (err)
return err;
/* add to internal csdev feature list & initialise using reset call */
cscfg_reset_feat(feat_csdev);
spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
list_add(&feat_csdev->node, &csdev->feature_csdev_list);
spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
return 0;
}
/*
* Add feature to any matching devices - call with mutex locked.
* Iterates through devices - any device that matches the feature will be
* called to load it.
*/
static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc)
{
struct cscfg_registered_csdev *csdev_item;
int err;
list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
if (csdev_item->match_flags & feat_desc->match_flags) {
err = cscfg_load_feat_csdev(csdev_item->csdev, feat_desc, &csdev_item->ops);
if (err)
return err;
}
}
return 0;
}
/* check feature list for a named feature - call with mutex locked. */
static bool cscfg_match_list_feat(const char *name)
{
struct cscfg_feature_desc *feat_desc;
list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
if (strcmp(feat_desc->name, name) == 0)
return true;
}
return false;
}
/* check all feat needed for cfg are in the list - call with mutex locked. */
static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *config_desc)
{
int i;
for (i = 0; i < config_desc->nr_feat_refs; i++)
if (!cscfg_match_list_feat(config_desc->feat_ref_names[i]))
return -EINVAL;
return 0;
}
/*
* load feature - add to feature list.
*/
static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc)
{
int err;
/* add feature to any matching registered devices */
err = cscfg_add_feat_to_csdevs(feat_desc);
if (err)
return err;
list_add(&feat_desc->item, &cscfg_mgr->feat_desc_list);
return 0;
}
/*
* load config into the system - validate used features exist then add to
* config list.
*/
static int cscfg_load_config(struct cscfg_config_desc *config_desc)
{
int err;
/* validate features are present */
err = cscfg_check_feat_for_cfg(config_desc);
if (err)
return err;
/* add config to any matching registered device */
err = cscfg_add_cfg_to_csdevs(config_desc);
if (err)
return err;
/* add config to perf fs to allow selection */
err = etm_perf_add_symlink_cscfg(cscfg_device(), config_desc);
if (err)
return err;
list_add(&config_desc->item, &cscfg_mgr->config_desc_list);
atomic_set(&config_desc->active_cnt, 0);
return 0;
}
/* get a feature descriptor by name */
const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name)
{
const struct cscfg_feature_desc *feat_desc = NULL, *feat_desc_item;
mutex_lock(&cscfg_mutex);
list_for_each_entry(feat_desc_item, &cscfg_mgr->feat_desc_list, item) {
if (strcmp(feat_desc_item->name, name) == 0) {
feat_desc = feat_desc_item;
break;
}
}
mutex_unlock(&cscfg_mutex);
return feat_desc;
}
/* called with cscfg_mutex held */
static struct cscfg_feature_csdev *
cscfg_csdev_get_feat_from_desc(struct coresight_device *csdev,
struct cscfg_feature_desc *feat_desc)
{
struct cscfg_feature_csdev *feat_csdev;
list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) {
if (feat_csdev->feat_desc == feat_desc)
return feat_csdev;
}
return NULL;
}
int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
int param_idx, u64 value)
{
int err = 0;
struct cscfg_feature_csdev *feat_csdev;
struct cscfg_registered_csdev *csdev_item;
mutex_lock(&cscfg_mutex);
/* check if any config active & return busy */
if (atomic_read(&cscfg_mgr->sys_active_cnt)) {
err = -EBUSY;
goto unlock_exit;
}
/* set the value */
if ((param_idx < 0) || (param_idx >= feat_desc->nr_params)) {
err = -EINVAL;
goto unlock_exit;
}
feat_desc->params_desc[param_idx].value = value;
/* update loaded instances.*/
list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) {
feat_csdev = cscfg_csdev_get_feat_from_desc(csdev_item->csdev, feat_desc);
if (feat_csdev)
feat_csdev->params_csdev[param_idx].current_value = value;
}
unlock_exit:
mutex_unlock(&cscfg_mutex);
return err;
}
/**
* cscfg_load_config_sets - API function to load feature and config sets.
*
* Take a 0 terminated array of feature descriptors and/or configuration
* descriptors and load into the system.
* Features are loaded first to ensure configuration dependencies can be met.
*
* @config_descs: 0 terminated array of configuration descriptors.
* @feat_descs: 0 terminated array of feature descriptors.
*/
int cscfg_load_config_sets(struct cscfg_config_desc **config_descs,
struct cscfg_feature_desc **feat_descs)
{
int err, i = 0;
mutex_lock(&cscfg_mutex);
/* load features first */
if (feat_descs) {
while (feat_descs[i]) {
err = cscfg_load_feat(feat_descs[i]);
if (!err)
err = cscfg_configfs_add_feature(feat_descs[i]);
if (err) {
pr_err("coresight-syscfg: Failed to load feature %s\n",
feat_descs[i]->name);
goto exit_unlock;
}
i++;
}
}
/* next any configurations to check feature dependencies */
i = 0;
if (config_descs) {
while (config_descs[i]) {
err = cscfg_load_config(config_descs[i]);
if (!err)
err = cscfg_configfs_add_config(config_descs[i]);
if (err) {
pr_err("coresight-syscfg: Failed to load configuration %s\n",
config_descs[i]->name);
goto exit_unlock;
}
i++;
}
}
exit_unlock:
mutex_unlock(&cscfg_mutex);
return err;
}
EXPORT_SYMBOL_GPL(cscfg_load_config_sets);
/* Handle coresight device registration and add configs and features to devices */
/* iterate through config lists and load matching configs to device */
static int cscfg_add_cfgs_csdev(struct coresight_device *csdev)
{
struct cscfg_config_desc *config_desc;
int err = 0;
list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
err = cscfg_add_csdev_cfg(csdev, config_desc);
if (err)
break;
}
return err;
}
/* iterate through feature lists and load matching features to device */
static int cscfg_add_feats_csdev(struct coresight_device *csdev,
u32 match_flags,
struct cscfg_csdev_feat_ops *ops)
{
struct cscfg_feature_desc *feat_desc;
int err = 0;
if (!ops->load_feat)
return -EINVAL;
list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) {
if (feat_desc->match_flags & match_flags) {
err = cscfg_load_feat_csdev(csdev, feat_desc, ops);
if (err)
break;
}
}
return err;
}
/* Add coresight device to list and copy its matching info */
static int cscfg_list_add_csdev(struct coresight_device *csdev,
u32 match_flags,
struct cscfg_csdev_feat_ops *ops)
{
struct cscfg_registered_csdev *csdev_item;
/* allocate the list entry structure */
csdev_item = kzalloc(sizeof(struct cscfg_registered_csdev), GFP_KERNEL);
if (!csdev_item)
return -ENOMEM;
csdev_item->csdev = csdev;
csdev_item->match_flags = match_flags;
csdev_item->ops.load_feat = ops->load_feat;
list_add(&csdev_item->item, &cscfg_mgr->csdev_desc_list);
INIT_LIST_HEAD(&csdev->feature_csdev_list);
INIT_LIST_HEAD(&csdev->config_csdev_list);
spin_lock_init(&csdev->cscfg_csdev_lock);
return 0;
}
/* remove a coresight device from the list and free data */
static void cscfg_list_remove_csdev(struct coresight_device *csdev)
{
struct cscfg_registered_csdev *csdev_item, *tmp;
list_for_each_entry_safe(csdev_item, tmp, &cscfg_mgr->csdev_desc_list, item) {
if (csdev_item->csdev == csdev) {
list_del(&csdev_item->item);
kfree(csdev_item);
break;
}
}
}
/**
* cscfg_register_csdev - register a coresight device with the syscfg manager.
*
* Registers the coresight device with the system. @match_flags used to check
* if the device is a match for registered features. Any currently registered
* configurations and features that match the device will be loaded onto it.
*
* @csdev: The coresight device to register.
* @match_flags: Matching information to load features.
* @ops: Standard operations supported by the device.
*/
int cscfg_register_csdev(struct coresight_device *csdev,
u32 match_flags,
struct cscfg_csdev_feat_ops *ops)
{
int ret = 0;
mutex_lock(&cscfg_mutex);
/* add device to list of registered devices */
ret = cscfg_list_add_csdev(csdev, match_flags, ops);
if (ret)
goto reg_csdev_unlock;
/* now load any registered features and configs matching the device. */
ret = cscfg_add_feats_csdev(csdev, match_flags, ops);
if (ret) {
cscfg_list_remove_csdev(csdev);
goto reg_csdev_unlock;
}
ret = cscfg_add_cfgs_csdev(csdev);
if (ret) {
cscfg_list_remove_csdev(csdev);
goto reg_csdev_unlock;
}
pr_info("CSCFG registered %s", dev_name(&csdev->dev));
reg_csdev_unlock:
mutex_unlock(&cscfg_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(cscfg_register_csdev);
/**
* cscfg_unregister_csdev - remove coresight device from syscfg manager.
*
* @csdev: Device to remove.
*/
void cscfg_unregister_csdev(struct coresight_device *csdev)
{
mutex_lock(&cscfg_mutex);
cscfg_list_remove_csdev(csdev);
mutex_unlock(&cscfg_mutex);
}
EXPORT_SYMBOL_GPL(cscfg_unregister_csdev);
/**
* cscfg_csdev_reset_feats - reset features for a CoreSight device.
*
* Resets all parameters and register values for any features loaded
* into @csdev to their default values.
*
* @csdev: The CoreSight device.
*/
void cscfg_csdev_reset_feats(struct coresight_device *csdev)
{
struct cscfg_feature_csdev *feat_csdev;
unsigned long flags;
spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
if (list_empty(&csdev->feature_csdev_list))
goto unlock_exit;
list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node)
cscfg_reset_feat(feat_csdev);
unlock_exit:
spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
}
EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);
/**
* cscfg_activate_config - Mark a configuration descriptor as active.
*
* This will be seen when csdev devices are enabled in the system.
* Only activated configurations can be enabled on individual devices.
* Activation protects the configuration from alteration or removal while
* active.
*
* Selection by hash value - generated from the configuration name when it
* was loaded and added to the cs_etm/configurations file system for selection
* by perf.
*
* Increments the configuration descriptor active count and the global active
* count.
*
* @cfg_hash: Hash value of the selected configuration name.
*/
int cscfg_activate_config(unsigned long cfg_hash)
{
struct cscfg_config_desc *config_desc;
int err = -EINVAL;
mutex_lock(&cscfg_mutex);
list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
/*
* increment the global active count - control changes to
* active configurations
*/
atomic_inc(&cscfg_mgr->sys_active_cnt);
/*
* mark the descriptor as active so enable config on a
* device instance will use it
*/
atomic_inc(&config_desc->active_cnt);
err = 0;
dev_dbg(cscfg_device(), "Activate config %s.\n", config_desc->name);
break;
}
}
mutex_unlock(&cscfg_mutex);
return err;
}
EXPORT_SYMBOL_GPL(cscfg_activate_config);
/**
* cscfg_deactivate_config - Mark a config descriptor as inactive.
*
* Decrement the configuration and global active counts.
*
* @cfg_hash: Hash value of the selected configuration name.
*/
void cscfg_deactivate_config(unsigned long cfg_hash)
{
struct cscfg_config_desc *config_desc;
mutex_lock(&cscfg_mutex);
list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
atomic_dec(&config_desc->active_cnt);
atomic_dec(&cscfg_mgr->sys_active_cnt);
dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name);
break;
}
}
mutex_unlock(&cscfg_mutex);
}
EXPORT_SYMBOL_GPL(cscfg_deactivate_config);
/**
* cscfg_csdev_enable_active_config - Enable matching active configuration for device.
*
* Enables the configuration selected by @cfg_hash if the configuration is supported
* on the device and has been activated.
*
* If active and supported the CoreSight device @csdev will be programmed with the
* configuration, using @preset parameters.
*
* Should be called before driver hardware enable for the requested device, prior to
* programming and enabling the physical hardware.
*
* @csdev: CoreSight device to program.
* @cfg_hash: Selector for the configuration.
* @preset: Preset parameter values to use, 0 for current / default values.
*/
int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
unsigned long cfg_hash, int preset)
{
struct cscfg_config_csdev *config_csdev_active = NULL, *config_csdev_item;
const struct cscfg_config_desc *config_desc;
unsigned long flags;
int err = 0;
/* quickly check global count */
if (!atomic_read(&cscfg_mgr->sys_active_cnt))
return 0;
/*
* Look for matching configuration - set the active configuration
* context if found.
*/
spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {
config_desc = config_csdev_item->config_desc;
if ((atomic_read(&config_desc->active_cnt)) &&
((unsigned long)config_desc->event_ea->var == cfg_hash)) {
config_csdev_active = config_csdev_item;
csdev->active_cscfg_ctxt = (void *)config_csdev_active;
break;
}
}
spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
/*
* If found, attempt to enable
*/
if (config_csdev_active) {
/*
* Call the generic routine that will program up the internal
* driver structures prior to programming up the hardware.
* This routine takes the driver spinlock saved in the configs.
*/
err = cscfg_csdev_enable_config(config_csdev_active, preset);
if (!err) {
/*
* Successful programming. Check the active_cscfg_ctxt
* pointer to ensure no pre-emption disabled it via
* cscfg_csdev_disable_active_config() before
* we could start.
*
* Set enabled if OK, err if not.
*/
spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
if (csdev->active_cscfg_ctxt)
config_csdev_active->enabled = true;
else
err = -EBUSY;
spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
}
}
return err;
}
EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
/**
* cscfg_csdev_disable_active_config - disable an active config on the device.
*
* Disables the active configuration on the CoreSight device @csdev.
* Disable will save the values of any registers marked in the configurations
* as save on disable.
*
* Should be called after driver hardware disable for the requested device,
* after disabling the physical hardware and reading back registers.
*
* @csdev: The CoreSight device.
*/
void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
{
struct cscfg_config_csdev *config_csdev;
unsigned long flags;
/*
* Check if we have an active config, and that it was successfully enabled.
* If it was not enabled, we have no work to do, otherwise mark as disabled.
* Clear the active config pointer.
*/
spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
config_csdev = (struct cscfg_config_csdev *)csdev->active_cscfg_ctxt;
if (config_csdev) {
if (!config_csdev->enabled)
config_csdev = NULL;
else
config_csdev->enabled = false;
}
csdev->active_cscfg_ctxt = NULL;
spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
/* true if there was an enabled active config */
if (config_csdev)
cscfg_csdev_disable_config(config_csdev);
}
EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config);
/* Initialise system configuration management device. */
struct device *cscfg_device(void)
{
return cscfg_mgr ? &cscfg_mgr->dev : NULL;
}
/* Must have a release function or the kernel will complain on module unload */
static void cscfg_dev_release(struct device *dev)
{
kfree(cscfg_mgr);
cscfg_mgr = NULL;
}
/* a device is needed to "own" some kernel elements such as sysfs entries. */
static int cscfg_create_device(void)
{
struct device *dev;
int err = -ENOMEM;
mutex_lock(&cscfg_mutex);
if (cscfg_mgr) {
err = -EINVAL;
goto create_dev_exit_unlock;
}
cscfg_mgr = kzalloc(sizeof(struct cscfg_manager), GFP_KERNEL);
if (!cscfg_mgr)
goto create_dev_exit_unlock;
/* setup the device */
dev = cscfg_device();
dev->release = cscfg_dev_release;
dev->init_name = "cs_system_cfg";
err = device_register(dev);
if (err)
cscfg_dev_release(dev);
create_dev_exit_unlock:
mutex_unlock(&cscfg_mutex);
return err;
}
static void cscfg_clear_device(void)
{
struct cscfg_config_desc *cfg_desc;
mutex_lock(&cscfg_mutex);
list_for_each_entry(cfg_desc, &cscfg_mgr->config_desc_list, item) {
etm_perf_del_symlink_cscfg(cfg_desc);
}
cscfg_configfs_release(cscfg_mgr);
device_unregister(cscfg_device());
mutex_unlock(&cscfg_mutex);
}
/* Initialise system config management API device */
int __init cscfg_init(void)
{
int err = 0;
err = cscfg_create_device();
if (err)
return err;
err = cscfg_configfs_init(cscfg_mgr);
if (err)
goto exit_err;
INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list);
INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list);
INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
atomic_set(&cscfg_mgr->sys_active_cnt, 0);
/* preload built-in configurations */
err = cscfg_preload();
if (err)
goto exit_err;
dev_info(cscfg_device(), "CoreSight Configuration manager initialised");
return 0;
exit_err:
cscfg_clear_device();
return err;
}
void cscfg_exit(void)
{
cscfg_clear_device();
}

View File

@ -0,0 +1,81 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Coresight system configuration driver.
*/
#ifndef CORESIGHT_SYSCFG_H
#define CORESIGHT_SYSCFG_H
#include <linux/configfs.h>
#include <linux/coresight.h>
#include <linux/device.h>
#include "coresight-config.h"
/**
* System configuration manager device.
*
* Contains lists of the loaded configurations and features, plus a list of CoreSight devices
* registered with the system as supporting configuration management.
*
* Need a device to 'own' some coresight system wide sysfs entries in
* perf events, configfs etc.
*
* @dev: The device.
* @csdev_desc_list: List of coresight devices registered with the configuration manager.
* @feat_desc_list: List of feature descriptors to load into registered devices.
* @config_desc_list: List of system configuration descriptors to load into registered devices.
* @sys_active_cnt: Total number of active config descriptor references.
* @cfgfs_subsys: configfs subsystem used to manage configurations.
*/
struct cscfg_manager {
struct device dev;
struct list_head csdev_desc_list;
struct list_head feat_desc_list;
struct list_head config_desc_list;
atomic_t sys_active_cnt;
struct configfs_subsystem cfgfs_subsys;
};
/* get reference to dev in cscfg_manager */
struct device *cscfg_device(void);
/**
* List entry for Coresight devices that are registered as supporting complex
* config operations.
*
* @csdev: The registered device.
* @match_flags: The matching type information for adding features.
* @ops: Operations supported by the registered device.
* @item: list entry.
*/
struct cscfg_registered_csdev {
struct coresight_device *csdev;
u32 match_flags;
struct cscfg_csdev_feat_ops ops;
struct list_head item;
};
/* internal core operations for cscfg */
int __init cscfg_init(void);
void cscfg_exit(void);
int cscfg_preload(void);
const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name);
int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc,
int param_idx, u64 value);
/* syscfg manager external API */
int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs,
struct cscfg_feature_desc **feat_descs);
int cscfg_register_csdev(struct coresight_device *csdev, u32 match_flags,
struct cscfg_csdev_feat_ops *ops);
void cscfg_unregister_csdev(struct coresight_device *csdev);
int cscfg_activate_config(unsigned long cfg_hash);
void cscfg_deactivate_config(unsigned long cfg_hash);
void cscfg_csdev_reset_feats(struct coresight_device *csdev);
int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
unsigned long cfg_hash, int preset);
void cscfg_csdev_disable_active_config(struct coresight_device *csdev);
#endif /* CORESIGHT_SYSCFG_H */

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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");

View File

@ -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

View File

@ -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 },
{ }
};

View File

@ -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,

View File

@ -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,

View File

@ -0,0 +1,626 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2021, Linaro Ltd.
*/
#include <linux/device.h>
#include <linux/interconnect-provider.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <dt-bindings/interconnect/qcom,sc8180x.h>
#include "bcm-voter.h"
#include "icc-rpmh.h"
#include "sc8180x.h"
DEFINE_QNODE(mas_qhm_a1noc_cfg, SC8180X_MASTER_A1NOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_A1NOC);
DEFINE_QNODE(mas_xm_ufs_card, SC8180X_MASTER_UFS_CARD, 1, 8, SC8180X_A1NOC_SNOC_SLV);
DEFINE_QNODE(mas_xm_ufs_g4, SC8180X_MASTER_UFS_GEN4, 1, 8, SC8180X_A1NOC_SNOC_SLV);
DEFINE_QNODE(mas_xm_ufs_mem, SC8180X_MASTER_UFS_MEM, 1, 8, SC8180X_A1NOC_SNOC_SLV);
DEFINE_QNODE(mas_xm_usb3_0, SC8180X_MASTER_USB3, 1, 8, SC8180X_A1NOC_SNOC_SLV);
DEFINE_QNODE(mas_xm_usb3_1, SC8180X_MASTER_USB3_1, 1, 8, SC8180X_A1NOC_SNOC_SLV);
DEFINE_QNODE(mas_xm_usb3_2, SC8180X_MASTER_USB3_2, 1, 16, SC8180X_A1NOC_SNOC_SLV);
DEFINE_QNODE(mas_qhm_a2noc_cfg, SC8180X_MASTER_A2NOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_A2NOC);
DEFINE_QNODE(mas_qhm_qdss_bam, SC8180X_MASTER_QDSS_BAM, 1, 4, SC8180X_A2NOC_SNOC_SLV);
DEFINE_QNODE(mas_qhm_qspi, SC8180X_MASTER_QSPI_0, 1, 4, SC8180X_A2NOC_SNOC_SLV);
DEFINE_QNODE(mas_qhm_qspi1, SC8180X_MASTER_QSPI_1, 1, 4, SC8180X_A2NOC_SNOC_SLV);
DEFINE_QNODE(mas_qhm_qup0, SC8180X_MASTER_QUP_0, 1, 4, SC8180X_A2NOC_SNOC_SLV);
DEFINE_QNODE(mas_qhm_qup1, SC8180X_MASTER_QUP_1, 1, 4, SC8180X_A2NOC_SNOC_SLV);
DEFINE_QNODE(mas_qhm_qup2, SC8180X_MASTER_QUP_2, 1, 4, SC8180X_A2NOC_SNOC_SLV);
DEFINE_QNODE(mas_qhm_sensorss_ahb, SC8180X_MASTER_SENSORS_AHB, 1, 4, SC8180X_A2NOC_SNOC_SLV);
DEFINE_QNODE(mas_qxm_crypto, SC8180X_MASTER_CRYPTO_CORE_0, 1, 8, SC8180X_A2NOC_SNOC_SLV);
DEFINE_QNODE(mas_qxm_ipa, SC8180X_MASTER_IPA, 1, 8, SC8180X_A2NOC_SNOC_SLV);
DEFINE_QNODE(mas_xm_emac, SC8180X_MASTER_EMAC, 1, 8, SC8180X_A2NOC_SNOC_SLV);
DEFINE_QNODE(mas_xm_pcie3_0, SC8180X_MASTER_PCIE, 1, 8, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC);
DEFINE_QNODE(mas_xm_pcie3_1, SC8180X_MASTER_PCIE_1, 1, 16, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC);
DEFINE_QNODE(mas_xm_pcie3_2, SC8180X_MASTER_PCIE_2, 1, 8, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC);
DEFINE_QNODE(mas_xm_pcie3_3, SC8180X_MASTER_PCIE_3, 1, 16, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC);
DEFINE_QNODE(mas_xm_qdss_etr, SC8180X_MASTER_QDSS_ETR, 1, 8, SC8180X_A2NOC_SNOC_SLV);
DEFINE_QNODE(mas_xm_sdc2, SC8180X_MASTER_SDCC_2, 1, 8, SC8180X_A2NOC_SNOC_SLV);
DEFINE_QNODE(mas_xm_sdc4, SC8180X_MASTER_SDCC_4, 1, 8, SC8180X_A2NOC_SNOC_SLV);
DEFINE_QNODE(mas_qxm_camnoc_hf0_uncomp, SC8180X_MASTER_CAMNOC_HF0_UNCOMP, 1, 32, SC8180X_SLAVE_CAMNOC_UNCOMP);
DEFINE_QNODE(mas_qxm_camnoc_hf1_uncomp, SC8180X_MASTER_CAMNOC_HF1_UNCOMP, 1, 32, SC8180X_SLAVE_CAMNOC_UNCOMP);
DEFINE_QNODE(mas_qxm_camnoc_sf_uncomp, SC8180X_MASTER_CAMNOC_SF_UNCOMP, 1, 32, SC8180X_SLAVE_CAMNOC_UNCOMP);
DEFINE_QNODE(mas_qnm_npu, SC8180X_MASTER_NPU, 1, 32, SC8180X_SLAVE_CDSP_MEM_NOC);
DEFINE_QNODE(mas_qnm_snoc, SC8180X_SNOC_CNOC_MAS, 1, 8, SC8180X_SLAVE_TLMM_SOUTH, SC8180X_SLAVE_CDSP_CFG, SC8180X_SLAVE_SPSS_CFG, SC8180X_SLAVE_CAMERA_CFG, SC8180X_SLAVE_SDCC_4, SC8180X_SLAVE_AHB2PHY_CENTER, SC8180X_SLAVE_SDCC_2, SC8180X_SLAVE_PCIE_2_CFG, SC8180X_SLAVE_CNOC_MNOC_CFG, SC8180X_SLAVE_EMAC_CFG, SC8180X_SLAVE_QSPI_0, SC8180X_SLAVE_QSPI_1, SC8180X_SLAVE_TLMM_EAST, SC8180X_SLAVE_SNOC_CFG, SC8180X_SLAVE_AHB2PHY_EAST, SC8180X_SLAVE_GLM, SC8180X_SLAVE_PDM, SC8180X_SLAVE_PCIE_1_CFG, SC8180X_SLAVE_A2NOC_CFG, SC8180X_SLAVE_QDSS_CFG, SC8180X_SLAVE_DISPLAY_CFG, SC8180X_SLAVE_TCSR, SC8180X_SLAVE_UFS_MEM_0_CFG, SC8180X_SLAVE_CNOC_DDRSS, SC8180X_SLAVE_PCIE_0_CFG, SC8180X_SLAVE_QUP_1, SC8180X_SLAVE_QUP_2, SC8180X_SLAVE_NPU_CFG, SC8180X_SLAVE_CRYPTO_0_CFG, SC8180X_SLAVE_GRAPHICS_3D_CFG, SC8180X_SLAVE_VENUS_CFG, SC8180X_SLAVE_TSIF, SC8180X_SLAVE_IPA_CFG, SC8180X_SLAVE_CLK_CTL, SC8180X_SLAVE_SECURITY, SC8180X_SLAVE_AOP, SC8180X_SLAVE_AHB2PHY_WEST, SC8180X_SLAVE_AHB2PHY_SOUTH, SC8180X_SLAVE_SERVICE_CNOC, SC8180X_SLAVE_UFS_CARD_CFG, SC8180X_SLAVE_USB3_1, SC8180X_SLAVE_USB3_2, SC8180X_SLAVE_PCIE_3_CFG, SC8180X_SLAVE_RBCPR_CX_CFG, SC8180X_SLAVE_TLMM_WEST, SC8180X_SLAVE_A1NOC_CFG, SC8180X_SLAVE_AOSS, SC8180X_SLAVE_PRNG, SC8180X_SLAVE_VSENSE_CTRL_CFG, SC8180X_SLAVE_QUP_0, SC8180X_SLAVE_USB3, SC8180X_SLAVE_RBCPR_MMCX_CFG, SC8180X_SLAVE_PIMEM_CFG, SC8180X_SLAVE_UFS_MEM_1_CFG, SC8180X_SLAVE_RBCPR_MX_CFG, SC8180X_SLAVE_IMEM_CFG);
DEFINE_QNODE(mas_qhm_cnoc_dc_noc, SC8180X_MASTER_CNOC_DC_NOC, 1, 4, SC8180X_SLAVE_LLCC_CFG, SC8180X_SLAVE_GEM_NOC_CFG);
DEFINE_QNODE(mas_acm_apps, SC8180X_MASTER_AMPSS_M0, 4, 64, SC8180X_SLAVE_ECC, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC);
DEFINE_QNODE(mas_acm_gpu_tcu, SC8180X_MASTER_GPU_TCU, 1, 8, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC);
DEFINE_QNODE(mas_acm_sys_tcu, SC8180X_MASTER_SYS_TCU, 1, 8, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC);
DEFINE_QNODE(mas_qhm_gemnoc_cfg, SC8180X_MASTER_GEM_NOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_GEM_NOC_1, SC8180X_SLAVE_SERVICE_GEM_NOC, SC8180X_SLAVE_MSS_PROC_MS_MPU_CFG);
DEFINE_QNODE(mas_qnm_cmpnoc, SC8180X_MASTER_COMPUTE_NOC, 2, 32, SC8180X_SLAVE_ECC, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC);
DEFINE_QNODE(mas_qnm_gpu, SC8180X_MASTER_GRAPHICS_3D, 4, 32, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC);
DEFINE_QNODE(mas_qnm_mnoc_hf, SC8180X_MASTER_MNOC_HF_MEM_NOC, 2, 32, SC8180X_SLAVE_LLCC);
DEFINE_QNODE(mas_qnm_mnoc_sf, SC8180X_MASTER_MNOC_SF_MEM_NOC, 1, 32, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC);
DEFINE_QNODE(mas_qnm_pcie, SC8180X_MASTER_GEM_NOC_PCIE_SNOC, 1, 32, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC);
DEFINE_QNODE(mas_qnm_snoc_gc, SC8180X_MASTER_SNOC_GC_MEM_NOC, 1, 8, SC8180X_SLAVE_LLCC);
DEFINE_QNODE(mas_qnm_snoc_sf, SC8180X_MASTER_SNOC_SF_MEM_NOC, 1, 32, SC8180X_SLAVE_LLCC);
DEFINE_QNODE(mas_qxm_ecc, SC8180X_MASTER_ECC, 2, 32, SC8180X_SLAVE_LLCC);
DEFINE_QNODE(mas_ipa_core_master, SC8180X_MASTER_IPA_CORE, 1, 8, SC8180X_SLAVE_IPA_CORE);
DEFINE_QNODE(mas_llcc_mc, SC8180X_MASTER_LLCC, 8, 4, SC8180X_SLAVE_EBI_CH0);
DEFINE_QNODE(mas_qhm_mnoc_cfg, SC8180X_MASTER_CNOC_MNOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_MNOC);
DEFINE_QNODE(mas_qxm_camnoc_hf0, SC8180X_MASTER_CAMNOC_HF0, 1, 32, SC8180X_SLAVE_MNOC_HF_MEM_NOC);
DEFINE_QNODE(mas_qxm_camnoc_hf1, SC8180X_MASTER_CAMNOC_HF1, 1, 32, SC8180X_SLAVE_MNOC_HF_MEM_NOC);
DEFINE_QNODE(mas_qxm_camnoc_sf, SC8180X_MASTER_CAMNOC_SF, 1, 32, SC8180X_SLAVE_MNOC_SF_MEM_NOC);
DEFINE_QNODE(mas_qxm_mdp0, SC8180X_MASTER_MDP_PORT0, 1, 32, SC8180X_SLAVE_MNOC_HF_MEM_NOC);
DEFINE_QNODE(mas_qxm_mdp1, SC8180X_MASTER_MDP_PORT1, 1, 32, SC8180X_SLAVE_MNOC_HF_MEM_NOC);
DEFINE_QNODE(mas_qxm_rot, SC8180X_MASTER_ROTATOR, 1, 32, SC8180X_SLAVE_MNOC_SF_MEM_NOC);
DEFINE_QNODE(mas_qxm_venus0, SC8180X_MASTER_VIDEO_P0, 1, 32, SC8180X_SLAVE_MNOC_SF_MEM_NOC);
DEFINE_QNODE(mas_qxm_venus1, SC8180X_MASTER_VIDEO_P1, 1, 32, SC8180X_SLAVE_MNOC_SF_MEM_NOC);
DEFINE_QNODE(mas_qxm_venus_arm9, SC8180X_MASTER_VIDEO_PROC, 1, 8, SC8180X_SLAVE_MNOC_SF_MEM_NOC);
DEFINE_QNODE(mas_qhm_snoc_cfg, SC8180X_MASTER_SNOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_SNOC);
DEFINE_QNODE(mas_qnm_aggre1_noc, SC8180X_A1NOC_SNOC_MAS, 1, 32, SC8180X_SLAVE_SNOC_GEM_NOC_SF, SC8180X_SLAVE_PIMEM, SC8180X_SLAVE_OCIMEM, SC8180X_SLAVE_APPSS, SC8180X_SNOC_CNOC_SLV, SC8180X_SLAVE_QDSS_STM);
DEFINE_QNODE(mas_qnm_aggre2_noc, SC8180X_A2NOC_SNOC_MAS, 1, 16, SC8180X_SLAVE_SNOC_GEM_NOC_SF, SC8180X_SLAVE_PIMEM, SC8180X_SLAVE_PCIE_3, SC8180X_SLAVE_OCIMEM, SC8180X_SLAVE_APPSS, SC8180X_SLAVE_PCIE_2, SC8180X_SNOC_CNOC_SLV, SC8180X_SLAVE_PCIE_0, SC8180X_SLAVE_PCIE_1, SC8180X_SLAVE_TCU, SC8180X_SLAVE_QDSS_STM);
DEFINE_QNODE(mas_qnm_gemnoc, SC8180X_MASTER_GEM_NOC_SNOC, 1, 8, SC8180X_SLAVE_PIMEM, SC8180X_SLAVE_OCIMEM, SC8180X_SLAVE_APPSS, SC8180X_SNOC_CNOC_SLV, SC8180X_SLAVE_TCU, SC8180X_SLAVE_QDSS_STM);
DEFINE_QNODE(mas_qxm_pimem, SC8180X_MASTER_PIMEM, 1, 8, SC8180X_SLAVE_SNOC_GEM_NOC_GC, SC8180X_SLAVE_OCIMEM);
DEFINE_QNODE(mas_xm_gic, SC8180X_MASTER_GIC, 1, 8, SC8180X_SLAVE_SNOC_GEM_NOC_GC, SC8180X_SLAVE_OCIMEM);
DEFINE_QNODE(slv_qns_a1noc_snoc, SC8180X_A1NOC_SNOC_SLV, 1, 32, SC8180X_A1NOC_SNOC_MAS);
DEFINE_QNODE(slv_srvc_aggre1_noc, SC8180X_SLAVE_SERVICE_A1NOC, 1, 4);
DEFINE_QNODE(slv_qns_a2noc_snoc, SC8180X_A2NOC_SNOC_SLV, 1, 16, SC8180X_A2NOC_SNOC_MAS);
DEFINE_QNODE(slv_qns_pcie_mem_noc, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC, 1, 32, SC8180X_MASTER_GEM_NOC_PCIE_SNOC);
DEFINE_QNODE(slv_srvc_aggre2_noc, SC8180X_SLAVE_SERVICE_A2NOC, 1, 4);
DEFINE_QNODE(slv_qns_camnoc_uncomp, SC8180X_SLAVE_CAMNOC_UNCOMP, 1, 32);
DEFINE_QNODE(slv_qns_cdsp_mem_noc, SC8180X_SLAVE_CDSP_MEM_NOC, 2, 32, SC8180X_MASTER_COMPUTE_NOC);
DEFINE_QNODE(slv_qhs_a1_noc_cfg, SC8180X_SLAVE_A1NOC_CFG, 1, 4, SC8180X_MASTER_A1NOC_CFG);
DEFINE_QNODE(slv_qhs_a2_noc_cfg, SC8180X_SLAVE_A2NOC_CFG, 1, 4, SC8180X_MASTER_A2NOC_CFG);
DEFINE_QNODE(slv_qhs_ahb2phy_refgen_center, SC8180X_SLAVE_AHB2PHY_CENTER, 1, 4);
DEFINE_QNODE(slv_qhs_ahb2phy_refgen_east, SC8180X_SLAVE_AHB2PHY_EAST, 1, 4);
DEFINE_QNODE(slv_qhs_ahb2phy_refgen_west, SC8180X_SLAVE_AHB2PHY_WEST, 1, 4);
DEFINE_QNODE(slv_qhs_ahb2phy_south, SC8180X_SLAVE_AHB2PHY_SOUTH, 1, 4);
DEFINE_QNODE(slv_qhs_aop, SC8180X_SLAVE_AOP, 1, 4);
DEFINE_QNODE(slv_qhs_aoss, SC8180X_SLAVE_AOSS, 1, 4);
DEFINE_QNODE(slv_qhs_camera_cfg, SC8180X_SLAVE_CAMERA_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_clk_ctl, SC8180X_SLAVE_CLK_CTL, 1, 4);
DEFINE_QNODE(slv_qhs_compute_dsp, SC8180X_SLAVE_CDSP_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_cpr_cx, SC8180X_SLAVE_RBCPR_CX_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_cpr_mmcx, SC8180X_SLAVE_RBCPR_MMCX_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_cpr_mx, SC8180X_SLAVE_RBCPR_MX_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_crypto0_cfg, SC8180X_SLAVE_CRYPTO_0_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_ddrss_cfg, SC8180X_SLAVE_CNOC_DDRSS, 1, 4, SC8180X_MASTER_CNOC_DC_NOC);
DEFINE_QNODE(slv_qhs_display_cfg, SC8180X_SLAVE_DISPLAY_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_emac_cfg, SC8180X_SLAVE_EMAC_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_glm, SC8180X_SLAVE_GLM, 1, 4);
DEFINE_QNODE(slv_qhs_gpuss_cfg, SC8180X_SLAVE_GRAPHICS_3D_CFG, 1, 8);
DEFINE_QNODE(slv_qhs_imem_cfg, SC8180X_SLAVE_IMEM_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_ipa, SC8180X_SLAVE_IPA_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_mnoc_cfg, SC8180X_SLAVE_CNOC_MNOC_CFG, 1, 4, SC8180X_MASTER_CNOC_MNOC_CFG);
DEFINE_QNODE(slv_qhs_npu_cfg, SC8180X_SLAVE_NPU_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_pcie0_cfg, SC8180X_SLAVE_PCIE_0_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_pcie1_cfg, SC8180X_SLAVE_PCIE_1_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_pcie2_cfg, SC8180X_SLAVE_PCIE_2_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_pcie3_cfg, SC8180X_SLAVE_PCIE_3_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_pdm, SC8180X_SLAVE_PDM, 1, 4);
DEFINE_QNODE(slv_qhs_pimem_cfg, SC8180X_SLAVE_PIMEM_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_prng, SC8180X_SLAVE_PRNG, 1, 4);
DEFINE_QNODE(slv_qhs_qdss_cfg, SC8180X_SLAVE_QDSS_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_qspi_0, SC8180X_SLAVE_QSPI_0, 1, 4);
DEFINE_QNODE(slv_qhs_qspi_1, SC8180X_SLAVE_QSPI_1, 1, 4);
DEFINE_QNODE(slv_qhs_qupv3_east0, SC8180X_SLAVE_QUP_1, 1, 4);
DEFINE_QNODE(slv_qhs_qupv3_east1, SC8180X_SLAVE_QUP_2, 1, 4);
DEFINE_QNODE(slv_qhs_qupv3_west, SC8180X_SLAVE_QUP_0, 1, 4);
DEFINE_QNODE(slv_qhs_sdc2, SC8180X_SLAVE_SDCC_2, 1, 4);
DEFINE_QNODE(slv_qhs_sdc4, SC8180X_SLAVE_SDCC_4, 1, 4);
DEFINE_QNODE(slv_qhs_security, SC8180X_SLAVE_SECURITY, 1, 4);
DEFINE_QNODE(slv_qhs_snoc_cfg, SC8180X_SLAVE_SNOC_CFG, 1, 4, SC8180X_MASTER_SNOC_CFG);
DEFINE_QNODE(slv_qhs_spss_cfg, SC8180X_SLAVE_SPSS_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_tcsr, SC8180X_SLAVE_TCSR, 1, 4);
DEFINE_QNODE(slv_qhs_tlmm_east, SC8180X_SLAVE_TLMM_EAST, 1, 4);
DEFINE_QNODE(slv_qhs_tlmm_south, SC8180X_SLAVE_TLMM_SOUTH, 1, 4);
DEFINE_QNODE(slv_qhs_tlmm_west, SC8180X_SLAVE_TLMM_WEST, 1, 4);
DEFINE_QNODE(slv_qhs_tsif, SC8180X_SLAVE_TSIF, 1, 4);
DEFINE_QNODE(slv_qhs_ufs_card_cfg, SC8180X_SLAVE_UFS_CARD_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_ufs_mem0_cfg, SC8180X_SLAVE_UFS_MEM_0_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_ufs_mem1_cfg, SC8180X_SLAVE_UFS_MEM_1_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_usb3_0, SC8180X_SLAVE_USB3, 1, 4);
DEFINE_QNODE(slv_qhs_usb3_1, SC8180X_SLAVE_USB3_1, 1, 4);
DEFINE_QNODE(slv_qhs_usb3_2, SC8180X_SLAVE_USB3_2, 1, 4);
DEFINE_QNODE(slv_qhs_venus_cfg, SC8180X_SLAVE_VENUS_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_vsense_ctrl_cfg, SC8180X_SLAVE_VSENSE_CTRL_CFG, 1, 4);
DEFINE_QNODE(slv_srvc_cnoc, SC8180X_SLAVE_SERVICE_CNOC, 1, 4);
DEFINE_QNODE(slv_qhs_gemnoc, SC8180X_SLAVE_GEM_NOC_CFG, 1, 4, SC8180X_MASTER_GEM_NOC_CFG);
DEFINE_QNODE(slv_qhs_llcc, SC8180X_SLAVE_LLCC_CFG, 1, 4);
DEFINE_QNODE(slv_qhs_mdsp_ms_mpu_cfg, SC8180X_SLAVE_MSS_PROC_MS_MPU_CFG, 1, 4);
DEFINE_QNODE(slv_qns_ecc, SC8180X_SLAVE_ECC, 1, 32);
DEFINE_QNODE(slv_qns_gem_noc_snoc, SC8180X_SLAVE_GEM_NOC_SNOC, 1, 8, SC8180X_MASTER_GEM_NOC_SNOC);
DEFINE_QNODE(slv_qns_llcc, SC8180X_SLAVE_LLCC, 8, 16, SC8180X_MASTER_LLCC);
DEFINE_QNODE(slv_srvc_gemnoc, SC8180X_SLAVE_SERVICE_GEM_NOC, 1, 4);
DEFINE_QNODE(slv_srvc_gemnoc1, SC8180X_SLAVE_SERVICE_GEM_NOC_1, 1, 4);
DEFINE_QNODE(slv_ipa_core_slave, SC8180X_SLAVE_IPA_CORE, 1, 8);
DEFINE_QNODE(slv_ebi, SC8180X_SLAVE_EBI_CH0, 8, 4);
DEFINE_QNODE(slv_qns2_mem_noc, SC8180X_SLAVE_MNOC_SF_MEM_NOC, 1, 32, SC8180X_MASTER_MNOC_SF_MEM_NOC);
DEFINE_QNODE(slv_qns_mem_noc_hf, SC8180X_SLAVE_MNOC_HF_MEM_NOC, 2, 32, SC8180X_MASTER_MNOC_HF_MEM_NOC);
DEFINE_QNODE(slv_srvc_mnoc, SC8180X_SLAVE_SERVICE_MNOC, 1, 4);
DEFINE_QNODE(slv_qhs_apss, SC8180X_SLAVE_APPSS, 1, 8);
DEFINE_QNODE(slv_qns_cnoc, SC8180X_SNOC_CNOC_SLV, 1, 8, SC8180X_SNOC_CNOC_MAS);
DEFINE_QNODE(slv_qns_gemnoc_gc, SC8180X_SLAVE_SNOC_GEM_NOC_GC, 1, 8, SC8180X_MASTER_SNOC_GC_MEM_NOC);
DEFINE_QNODE(slv_qns_gemnoc_sf, SC8180X_SLAVE_SNOC_GEM_NOC_SF, 1, 32, SC8180X_MASTER_SNOC_SF_MEM_NOC);
DEFINE_QNODE(slv_qxs_imem, SC8180X_SLAVE_OCIMEM, 1, 8);
DEFINE_QNODE(slv_qxs_pimem, SC8180X_SLAVE_PIMEM, 1, 8);
DEFINE_QNODE(slv_srvc_snoc, SC8180X_SLAVE_SERVICE_SNOC, 1, 4);
DEFINE_QNODE(slv_xs_pcie_0, SC8180X_SLAVE_PCIE_0, 1, 8);
DEFINE_QNODE(slv_xs_pcie_1, SC8180X_SLAVE_PCIE_1, 1, 8);
DEFINE_QNODE(slv_xs_pcie_2, SC8180X_SLAVE_PCIE_2, 1, 8);
DEFINE_QNODE(slv_xs_pcie_3, SC8180X_SLAVE_PCIE_3, 1, 8);
DEFINE_QNODE(slv_xs_qdss_stm, SC8180X_SLAVE_QDSS_STM, 1, 4);
DEFINE_QNODE(slv_xs_sys_tcu_cfg, SC8180X_SLAVE_TCU, 1, 8);
DEFINE_QBCM(bcm_acv, "ACV", false, &slv_ebi);
DEFINE_QBCM(bcm_mc0, "MC0", false, &slv_ebi);
DEFINE_QBCM(bcm_sh0, "SH0", false, &slv_qns_llcc);
DEFINE_QBCM(bcm_mm0, "MM0", false, &slv_qns_mem_noc_hf);
DEFINE_QBCM(bcm_co0, "CO0", false, &slv_qns_cdsp_mem_noc);
DEFINE_QBCM(bcm_ce0, "CE0", false, &mas_qxm_crypto);
DEFINE_QBCM(bcm_cn0, "CN0", false, &mas_qnm_snoc, &slv_qhs_a1_noc_cfg, &slv_qhs_a2_noc_cfg, &slv_qhs_ahb2phy_refgen_center, &slv_qhs_ahb2phy_refgen_east, &slv_qhs_ahb2phy_refgen_west, &slv_qhs_ahb2phy_south, &slv_qhs_aop, &slv_qhs_aoss, &slv_qhs_camera_cfg, &slv_qhs_clk_ctl, &slv_qhs_compute_dsp, &slv_qhs_cpr_cx, &slv_qhs_cpr_mmcx, &slv_qhs_cpr_mx, &slv_qhs_crypto0_cfg, &slv_qhs_ddrss_cfg, &slv_qhs_display_cfg, &slv_qhs_emac_cfg, &slv_qhs_glm, &slv_qhs_gpuss_cfg, &slv_qhs_imem_cfg, &slv_qhs_ipa, &slv_qhs_mnoc_cfg, &slv_qhs_npu_cfg, &slv_qhs_pcie0_cfg, &slv_qhs_pcie1_cfg, &slv_qhs_pcie2_cfg, &slv_qhs_pcie3_cfg, &slv_qhs_pdm, &slv_qhs_pimem_cfg, &slv_qhs_prng, &slv_qhs_qdss_cfg, &slv_qhs_qspi_0, &slv_qhs_qspi_1, &slv_qhs_qupv3_east0, &slv_qhs_qupv3_east1, &slv_qhs_qupv3_west, &slv_qhs_sdc2, &slv_qhs_sdc4, &slv_qhs_security, &slv_qhs_snoc_cfg, &slv_qhs_spss_cfg, &slv_qhs_tcsr, &slv_qhs_tlmm_east, &slv_qhs_tlmm_south, &slv_qhs_tlmm_west, &slv_qhs_tsif, &slv_qhs_ufs_card_cfg, &slv_qhs_ufs_mem0_cfg, &slv_qhs_ufs_mem1_cfg, &slv_qhs_usb3_0, &slv_qhs_usb3_1, &slv_qhs_usb3_2, &slv_qhs_venus_cfg, &slv_qhs_vsense_ctrl_cfg, &slv_srvc_cnoc);
DEFINE_QBCM(bcm_mm1, "MM1", false, &mas_qxm_camnoc_hf0_uncomp, &mas_qxm_camnoc_hf1_uncomp, &mas_qxm_camnoc_sf_uncomp, &mas_qxm_camnoc_hf0, &mas_qxm_camnoc_hf1, &mas_qxm_mdp0, &mas_qxm_mdp1);
DEFINE_QBCM(bcm_qup0, "QUP0", false, &mas_qhm_qup0, &mas_qhm_qup1, &mas_qhm_qup2);
DEFINE_QBCM(bcm_sh2, "SH2", false, &slv_qns_gem_noc_snoc);
DEFINE_QBCM(bcm_mm2, "MM2", false, &mas_qxm_camnoc_sf, &mas_qxm_rot, &mas_qxm_venus0, &mas_qxm_venus1, &mas_qxm_venus_arm9, &slv_qns2_mem_noc);
DEFINE_QBCM(bcm_sh3, "SH3", false, &mas_acm_apps);
DEFINE_QBCM(bcm_sn0, "SN0", false, &slv_qns_gemnoc_sf);
DEFINE_QBCM(bcm_sn1, "SN1", false, &slv_qxs_imem);
DEFINE_QBCM(bcm_sn2, "SN2", false, &slv_qns_gemnoc_gc);
DEFINE_QBCM(bcm_co2, "CO2", false, &mas_qnm_npu);
DEFINE_QBCM(bcm_ip0, "IP0", false, &slv_ipa_core_slave);
DEFINE_QBCM(bcm_sn3, "SN3", false, &slv_srvc_aggre1_noc, &slv_qns_cnoc);
DEFINE_QBCM(bcm_sn4, "SN4", false, &slv_qxs_pimem);
DEFINE_QBCM(bcm_sn8, "SN8", false, &slv_xs_pcie_0, &slv_xs_pcie_1, &slv_xs_pcie_2, &slv_xs_pcie_3);
DEFINE_QBCM(bcm_sn9, "SN9", false, &mas_qnm_aggre1_noc);
DEFINE_QBCM(bcm_sn11, "SN11", false, &mas_qnm_aggre2_noc);
DEFINE_QBCM(bcm_sn14, "SN14", false, &slv_qns_pcie_mem_noc);
DEFINE_QBCM(bcm_sn15, "SN15", false, &mas_qnm_gemnoc);
static struct qcom_icc_bcm *aggre1_noc_bcms[] = {
&bcm_sn3,
&bcm_ce0,
&bcm_qup0,
};
static struct qcom_icc_bcm *aggre2_noc_bcms[] = {
&bcm_sn14,
&bcm_ce0,
&bcm_qup0,
};
static struct qcom_icc_bcm *camnoc_virt_bcms[] = {
&bcm_mm1,
};
static struct qcom_icc_bcm *compute_noc_bcms[] = {
&bcm_co0,
&bcm_co2,
};
static struct qcom_icc_bcm *config_noc_bcms[] = {
&bcm_cn0,
};
static struct qcom_icc_bcm *gem_noc_bcms[] = {
&bcm_sh0,
&bcm_sh2,
&bcm_sh3,
};
static struct qcom_icc_bcm *ipa_virt_bcms[] = {
&bcm_ip0,
};
static struct qcom_icc_bcm *mc_virt_bcms[] = {
&bcm_mc0,
&bcm_acv,
};
static struct qcom_icc_bcm *mmss_noc_bcms[] = {
&bcm_mm0,
&bcm_mm1,
&bcm_mm2,
};
static struct qcom_icc_bcm *system_noc_bcms[] = {
&bcm_sn0,
&bcm_sn1,
&bcm_sn2,
&bcm_sn3,
&bcm_sn4,
&bcm_sn8,
&bcm_sn9,
&bcm_sn11,
&bcm_sn15,
};
static struct qcom_icc_node *aggre1_noc_nodes[] = {
[MASTER_A1NOC_CFG] = &mas_qhm_a1noc_cfg,
[MASTER_UFS_CARD] = &mas_xm_ufs_card,
[MASTER_UFS_GEN4] = &mas_xm_ufs_g4,
[MASTER_UFS_MEM] = &mas_xm_ufs_mem,
[MASTER_USB3] = &mas_xm_usb3_0,
[MASTER_USB3_1] = &mas_xm_usb3_1,
[MASTER_USB3_2] = &mas_xm_usb3_2,
[A1NOC_SNOC_SLV] = &slv_qns_a1noc_snoc,
[SLAVE_SERVICE_A1NOC] = &slv_srvc_aggre1_noc,
};
static struct qcom_icc_node *aggre2_noc_nodes[] = {
[MASTER_A2NOC_CFG] = &mas_qhm_a2noc_cfg,
[MASTER_QDSS_BAM] = &mas_qhm_qdss_bam,
[MASTER_QSPI_0] = &mas_qhm_qspi,
[MASTER_QSPI_1] = &mas_qhm_qspi1,
[MASTER_QUP_0] = &mas_qhm_qup0,
[MASTER_QUP_1] = &mas_qhm_qup1,
[MASTER_QUP_2] = &mas_qhm_qup2,
[MASTER_SENSORS_AHB] = &mas_qhm_sensorss_ahb,
[MASTER_CRYPTO_CORE_0] = &mas_qxm_crypto,
[MASTER_IPA] = &mas_qxm_ipa,
[MASTER_EMAC] = &mas_xm_emac,
[MASTER_PCIE] = &mas_xm_pcie3_0,
[MASTER_PCIE_1] = &mas_xm_pcie3_1,
[MASTER_PCIE_2] = &mas_xm_pcie3_2,
[MASTER_PCIE_3] = &mas_xm_pcie3_3,
[MASTER_QDSS_ETR] = &mas_xm_qdss_etr,
[MASTER_SDCC_2] = &mas_xm_sdc2,
[MASTER_SDCC_4] = &mas_xm_sdc4,
[A2NOC_SNOC_SLV] = &slv_qns_a2noc_snoc,
[SLAVE_ANOC_PCIE_GEM_NOC] = &slv_qns_pcie_mem_noc,
[SLAVE_SERVICE_A2NOC] = &slv_srvc_aggre2_noc,
};
static struct qcom_icc_node *camnoc_virt_nodes[] = {
[MASTER_CAMNOC_HF0_UNCOMP] = &mas_qxm_camnoc_hf0_uncomp,
[MASTER_CAMNOC_HF1_UNCOMP] = &mas_qxm_camnoc_hf1_uncomp,
[MASTER_CAMNOC_SF_UNCOMP] = &mas_qxm_camnoc_sf_uncomp,
[SLAVE_CAMNOC_UNCOMP] = &slv_qns_camnoc_uncomp,
};
static struct qcom_icc_node *compute_noc_nodes[] = {
[MASTER_NPU] = &mas_qnm_npu,
[SLAVE_CDSP_MEM_NOC] = &slv_qns_cdsp_mem_noc,
};
static struct qcom_icc_node *config_noc_nodes[] = {
[SNOC_CNOC_MAS] = &mas_qnm_snoc,
[SLAVE_A1NOC_CFG] = &slv_qhs_a1_noc_cfg,
[SLAVE_A2NOC_CFG] = &slv_qhs_a2_noc_cfg,
[SLAVE_AHB2PHY_CENTER] = &slv_qhs_ahb2phy_refgen_center,
[SLAVE_AHB2PHY_EAST] = &slv_qhs_ahb2phy_refgen_east,
[SLAVE_AHB2PHY_WEST] = &slv_qhs_ahb2phy_refgen_west,
[SLAVE_AHB2PHY_SOUTH] = &slv_qhs_ahb2phy_south,
[SLAVE_AOP] = &slv_qhs_aop,
[SLAVE_AOSS] = &slv_qhs_aoss,
[SLAVE_CAMERA_CFG] = &slv_qhs_camera_cfg,
[SLAVE_CLK_CTL] = &slv_qhs_clk_ctl,
[SLAVE_CDSP_CFG] = &slv_qhs_compute_dsp,
[SLAVE_RBCPR_CX_CFG] = &slv_qhs_cpr_cx,
[SLAVE_RBCPR_MMCX_CFG] = &slv_qhs_cpr_mmcx,
[SLAVE_RBCPR_MX_CFG] = &slv_qhs_cpr_mx,
[SLAVE_CRYPTO_0_CFG] = &slv_qhs_crypto0_cfg,
[SLAVE_CNOC_DDRSS] = &slv_qhs_ddrss_cfg,
[SLAVE_DISPLAY_CFG] = &slv_qhs_display_cfg,
[SLAVE_EMAC_CFG] = &slv_qhs_emac_cfg,
[SLAVE_GLM] = &slv_qhs_glm,
[SLAVE_GRAPHICS_3D_CFG] = &slv_qhs_gpuss_cfg,
[SLAVE_IMEM_CFG] = &slv_qhs_imem_cfg,
[SLAVE_IPA_CFG] = &slv_qhs_ipa,
[SLAVE_CNOC_MNOC_CFG] = &slv_qhs_mnoc_cfg,
[SLAVE_NPU_CFG] = &slv_qhs_npu_cfg,
[SLAVE_PCIE_0_CFG] = &slv_qhs_pcie0_cfg,
[SLAVE_PCIE_1_CFG] = &slv_qhs_pcie1_cfg,
[SLAVE_PCIE_2_CFG] = &slv_qhs_pcie2_cfg,
[SLAVE_PCIE_3_CFG] = &slv_qhs_pcie3_cfg,
[SLAVE_PDM] = &slv_qhs_pdm,
[SLAVE_PIMEM_CFG] = &slv_qhs_pimem_cfg,
[SLAVE_PRNG] = &slv_qhs_prng,
[SLAVE_QDSS_CFG] = &slv_qhs_qdss_cfg,
[SLAVE_QSPI_0] = &slv_qhs_qspi_0,
[SLAVE_QSPI_1] = &slv_qhs_qspi_1,
[SLAVE_QUP_1] = &slv_qhs_qupv3_east0,
[SLAVE_QUP_2] = &slv_qhs_qupv3_east1,
[SLAVE_QUP_0] = &slv_qhs_qupv3_west,
[SLAVE_SDCC_2] = &slv_qhs_sdc2,
[SLAVE_SDCC_4] = &slv_qhs_sdc4,
[SLAVE_SECURITY] = &slv_qhs_security,
[SLAVE_SNOC_CFG] = &slv_qhs_snoc_cfg,
[SLAVE_SPSS_CFG] = &slv_qhs_spss_cfg,
[SLAVE_TCSR] = &slv_qhs_tcsr,
[SLAVE_TLMM_EAST] = &slv_qhs_tlmm_east,
[SLAVE_TLMM_SOUTH] = &slv_qhs_tlmm_south,
[SLAVE_TLMM_WEST] = &slv_qhs_tlmm_west,
[SLAVE_TSIF] = &slv_qhs_tsif,
[SLAVE_UFS_CARD_CFG] = &slv_qhs_ufs_card_cfg,
[SLAVE_UFS_MEM_0_CFG] = &slv_qhs_ufs_mem0_cfg,
[SLAVE_UFS_MEM_1_CFG] = &slv_qhs_ufs_mem1_cfg,
[SLAVE_USB3] = &slv_qhs_usb3_0,
[SLAVE_USB3_1] = &slv_qhs_usb3_1,
[SLAVE_USB3_2] = &slv_qhs_usb3_2,
[SLAVE_VENUS_CFG] = &slv_qhs_venus_cfg,
[SLAVE_VSENSE_CTRL_CFG] = &slv_qhs_vsense_ctrl_cfg,
[SLAVE_SERVICE_CNOC] = &slv_srvc_cnoc,
};
static struct qcom_icc_node *dc_noc_nodes[] = {
[MASTER_CNOC_DC_NOC] = &mas_qhm_cnoc_dc_noc,
[SLAVE_GEM_NOC_CFG] = &slv_qhs_gemnoc,
[SLAVE_LLCC_CFG] = &slv_qhs_llcc,
};
static struct qcom_icc_node *gem_noc_nodes[] = {
[MASTER_AMPSS_M0] = &mas_acm_apps,
[MASTER_GPU_TCU] = &mas_acm_gpu_tcu,
[MASTER_SYS_TCU] = &mas_acm_sys_tcu,
[MASTER_GEM_NOC_CFG] = &mas_qhm_gemnoc_cfg,
[MASTER_COMPUTE_NOC] = &mas_qnm_cmpnoc,
[MASTER_GRAPHICS_3D] = &mas_qnm_gpu,
[MASTER_MNOC_HF_MEM_NOC] = &mas_qnm_mnoc_hf,
[MASTER_MNOC_SF_MEM_NOC] = &mas_qnm_mnoc_sf,
[MASTER_GEM_NOC_PCIE_SNOC] = &mas_qnm_pcie,
[MASTER_SNOC_GC_MEM_NOC] = &mas_qnm_snoc_gc,
[MASTER_SNOC_SF_MEM_NOC] = &mas_qnm_snoc_sf,
[MASTER_ECC] = &mas_qxm_ecc,
[SLAVE_MSS_PROC_MS_MPU_CFG] = &slv_qhs_mdsp_ms_mpu_cfg,
[SLAVE_ECC] = &slv_qns_ecc,
[SLAVE_GEM_NOC_SNOC] = &slv_qns_gem_noc_snoc,
[SLAVE_LLCC] = &slv_qns_llcc,
[SLAVE_SERVICE_GEM_NOC] = &slv_srvc_gemnoc,
[SLAVE_SERVICE_GEM_NOC_1] = &slv_srvc_gemnoc1,
};
static struct qcom_icc_node *ipa_virt_nodes[] = {
[MASTER_IPA_CORE] = &mas_ipa_core_master,
[SLAVE_IPA_CORE] = &slv_ipa_core_slave,
};
static struct qcom_icc_node *mc_virt_nodes[] = {
[MASTER_LLCC] = &mas_llcc_mc,
[SLAVE_EBI_CH0] = &slv_ebi,
};
static struct qcom_icc_node *mmss_noc_nodes[] = {
[MASTER_CNOC_MNOC_CFG] = &mas_qhm_mnoc_cfg,
[MASTER_CAMNOC_HF0] = &mas_qxm_camnoc_hf0,
[MASTER_CAMNOC_HF1] = &mas_qxm_camnoc_hf1,
[MASTER_CAMNOC_SF] = &mas_qxm_camnoc_sf,
[MASTER_MDP_PORT0] = &mas_qxm_mdp0,
[MASTER_MDP_PORT1] = &mas_qxm_mdp1,
[MASTER_ROTATOR] = &mas_qxm_rot,
[MASTER_VIDEO_P0] = &mas_qxm_venus0,
[MASTER_VIDEO_P1] = &mas_qxm_venus1,
[MASTER_VIDEO_PROC] = &mas_qxm_venus_arm9,
[SLAVE_MNOC_SF_MEM_NOC] = &slv_qns2_mem_noc,
[SLAVE_MNOC_HF_MEM_NOC] = &slv_qns_mem_noc_hf,
[SLAVE_SERVICE_MNOC] = &slv_srvc_mnoc,
};
static struct qcom_icc_node *system_noc_nodes[] = {
[MASTER_SNOC_CFG] = &mas_qhm_snoc_cfg,
[A1NOC_SNOC_MAS] = &mas_qnm_aggre1_noc,
[A2NOC_SNOC_MAS] = &mas_qnm_aggre2_noc,
[MASTER_GEM_NOC_SNOC] = &mas_qnm_gemnoc,
[MASTER_PIMEM] = &mas_qxm_pimem,
[MASTER_GIC] = &mas_xm_gic,
[SLAVE_APPSS] = &slv_qhs_apss,
[SNOC_CNOC_SLV] = &slv_qns_cnoc,
[SLAVE_SNOC_GEM_NOC_GC] = &slv_qns_gemnoc_gc,
[SLAVE_SNOC_GEM_NOC_SF] = &slv_qns_gemnoc_sf,
[SLAVE_OCIMEM] = &slv_qxs_imem,
[SLAVE_PIMEM] = &slv_qxs_pimem,
[SLAVE_SERVICE_SNOC] = &slv_srvc_snoc,
[SLAVE_QDSS_STM] = &slv_xs_qdss_stm,
[SLAVE_TCU] = &slv_xs_sys_tcu_cfg,
};
static const struct qcom_icc_desc sc8180x_aggre1_noc = {
.nodes = aggre1_noc_nodes,
.num_nodes = ARRAY_SIZE(aggre1_noc_nodes),
.bcms = aggre1_noc_bcms,
.num_bcms = ARRAY_SIZE(aggre1_noc_bcms),
};
static const struct qcom_icc_desc sc8180x_aggre2_noc = {
.nodes = aggre2_noc_nodes,
.num_nodes = ARRAY_SIZE(aggre2_noc_nodes),
.bcms = aggre2_noc_bcms,
.num_bcms = ARRAY_SIZE(aggre2_noc_bcms),
};
static const struct qcom_icc_desc sc8180x_camnoc_virt = {
.nodes = camnoc_virt_nodes,
.num_nodes = ARRAY_SIZE(camnoc_virt_nodes),
.bcms = camnoc_virt_bcms,
.num_bcms = ARRAY_SIZE(camnoc_virt_bcms),
};
static const struct qcom_icc_desc sc8180x_compute_noc = {
.nodes = compute_noc_nodes,
.num_nodes = ARRAY_SIZE(compute_noc_nodes),
.bcms = compute_noc_bcms,
.num_bcms = ARRAY_SIZE(compute_noc_bcms),
};
static const struct qcom_icc_desc sc8180x_config_noc = {
.nodes = config_noc_nodes,
.num_nodes = ARRAY_SIZE(config_noc_nodes),
.bcms = config_noc_bcms,
.num_bcms = ARRAY_SIZE(config_noc_bcms),
};
static const struct qcom_icc_desc sc8180x_dc_noc = {
.nodes = dc_noc_nodes,
.num_nodes = ARRAY_SIZE(dc_noc_nodes),
};
static const struct qcom_icc_desc sc8180x_gem_noc = {
.nodes = gem_noc_nodes,
.num_nodes = ARRAY_SIZE(gem_noc_nodes),
.bcms = gem_noc_bcms,
.num_bcms = ARRAY_SIZE(gem_noc_bcms),
};
static const struct qcom_icc_desc sc8180x_ipa_virt = {
.nodes = ipa_virt_nodes,
.num_nodes = ARRAY_SIZE(ipa_virt_nodes),
.bcms = ipa_virt_bcms,
.num_bcms = ARRAY_SIZE(ipa_virt_bcms),
};
static const struct qcom_icc_desc sc8180x_mc_virt = {
.nodes = mc_virt_nodes,
.num_nodes = ARRAY_SIZE(mc_virt_nodes),
.bcms = mc_virt_bcms,
.num_bcms = ARRAY_SIZE(mc_virt_bcms),
};
static const struct qcom_icc_desc sc8180x_mmss_noc = {
.nodes = mmss_noc_nodes,
.num_nodes = ARRAY_SIZE(mmss_noc_nodes),
.bcms = mmss_noc_bcms,
.num_bcms = ARRAY_SIZE(mmss_noc_bcms),
};
static const struct qcom_icc_desc sc8180x_system_noc = {
.nodes = system_noc_nodes,
.num_nodes = ARRAY_SIZE(system_noc_nodes),
.bcms = system_noc_bcms,
.num_bcms = ARRAY_SIZE(system_noc_bcms),
};
static int qnoc_probe(struct platform_device *pdev)
{
const struct qcom_icc_desc *desc;
struct icc_onecell_data *data;
struct icc_provider *provider;
struct qcom_icc_node **qnodes;
struct qcom_icc_provider *qp;
struct icc_node *node;
size_t num_nodes, i;
int ret;
desc = device_get_match_data(&pdev->dev);
if (!desc)
return -EINVAL;
qnodes = desc->nodes;
num_nodes = desc->num_nodes;
qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
if (!qp)
return -ENOMEM;
data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL);
if (!data)
return -ENOMEM;
provider = &qp->provider;
provider->dev = &pdev->dev;
provider->set = qcom_icc_set;
provider->pre_aggregate = qcom_icc_pre_aggregate;
provider->aggregate = qcom_icc_aggregate;
provider->xlate = of_icc_xlate_onecell;
INIT_LIST_HEAD(&provider->nodes);
provider->data = data;
qp->dev = &pdev->dev;
qp->bcms = desc->bcms;
qp->num_bcms = desc->num_bcms;
qp->voter = of_bcm_voter_get(qp->dev, NULL);
if (IS_ERR(qp->voter))
return PTR_ERR(qp->voter);
ret = icc_provider_add(provider);
if (ret) {
dev_err(&pdev->dev, "error adding interconnect provider\n");
return ret;
}
for (i = 0; i < qp->num_bcms; i++)
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
for (i = 0; i < num_nodes; i++) {
size_t j;
if (!qnodes[i])
continue;
node = icc_node_create(qnodes[i]->id);
if (IS_ERR(node)) {
ret = PTR_ERR(node);
goto err;
}
node->name = qnodes[i]->name;
node->data = qnodes[i];
icc_node_add(node, provider);
for (j = 0; j < qnodes[i]->num_links; j++)
icc_link_create(node, qnodes[i]->links[j]);
data->nodes[i] = node;
}
data->num_nodes = num_nodes;
platform_set_drvdata(pdev, qp);
return 0;
err:
icc_nodes_remove(provider);
icc_provider_del(provider);
return ret;
}
static int qnoc_remove(struct platform_device *pdev)
{
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
icc_nodes_remove(&qp->provider);
return icc_provider_del(&qp->provider);
}
static const struct of_device_id qnoc_of_match[] = {
{ .compatible = "qcom,sc8180x-aggre1-noc", .data = &sc8180x_aggre1_noc },
{ .compatible = "qcom,sc8180x-aggre2-noc", .data = &sc8180x_aggre2_noc },
{ .compatible = "qcom,sc8180x-camnoc-virt", .data = &sc8180x_camnoc_virt },
{ .compatible = "qcom,sc8180x-compute-noc", .data = &sc8180x_compute_noc, },
{ .compatible = "qcom,sc8180x-config-noc", .data = &sc8180x_config_noc },
{ .compatible = "qcom,sc8180x-dc-noc", .data = &sc8180x_dc_noc },
{ .compatible = "qcom,sc8180x-gem-noc", .data = &sc8180x_gem_noc },
{ .compatible = "qcom,sc8180x-ipa-virt", .data = &sc8180x_ipa_virt },
{ .compatible = "qcom,sc8180x-mc-virt", .data = &sc8180x_mc_virt },
{ .compatible = "qcom,sc8180x-mmss-noc", .data = &sc8180x_mmss_noc },
{ .compatible = "qcom,sc8180x-system-noc", .data = &sc8180x_system_noc },
{ }
};
MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qnoc_probe,
.remove = qnoc_remove,
.driver = {
.name = "qnoc-sc8180x",
.of_match_table = qnoc_of_match,
.sync_state = icc_sync_state,
},
};
module_platform_driver(qnoc_driver);
MODULE_DESCRIPTION("Qualcomm sc8180x NoC driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,174 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Qualcomm #define SC8180X interconnect IDs
*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#ifndef __DRIVERS_INTERCONNECT_QCOM_SC8180X_H
#define __DRIVERS_INTERCONNECT_QCOM_SC8180X_H
#define SC8180X_MASTER_A1NOC_CFG 1
#define SC8180X_MASTER_UFS_CARD 2
#define SC8180X_MASTER_UFS_GEN4 3
#define SC8180X_MASTER_UFS_MEM 4
#define SC8180X_MASTER_USB3 5
#define SC8180X_MASTER_USB3_1 6
#define SC8180X_MASTER_USB3_2 7
#define SC8180X_MASTER_A2NOC_CFG 8
#define SC8180X_MASTER_QDSS_BAM 9
#define SC8180X_MASTER_QSPI_0 10
#define SC8180X_MASTER_QSPI_1 11
#define SC8180X_MASTER_QUP_0 12
#define SC8180X_MASTER_QUP_1 13
#define SC8180X_MASTER_QUP_2 14
#define SC8180X_MASTER_SENSORS_AHB 15
#define SC8180X_MASTER_CRYPTO_CORE_0 16
#define SC8180X_MASTER_IPA 17
#define SC8180X_MASTER_EMAC 18
#define SC8180X_MASTER_PCIE 19
#define SC8180X_MASTER_PCIE_1 20
#define SC8180X_MASTER_PCIE_2 21
#define SC8180X_MASTER_PCIE_3 22
#define SC8180X_MASTER_QDSS_ETR 23
#define SC8180X_MASTER_SDCC_2 24
#define SC8180X_MASTER_SDCC_4 25
#define SC8180X_MASTER_CAMNOC_HF0_UNCOMP 26
#define SC8180X_MASTER_CAMNOC_HF1_UNCOMP 27
#define SC8180X_MASTER_CAMNOC_SF_UNCOMP 28
#define SC8180X_MASTER_NPU 29
#define SC8180X_SNOC_CNOC_MAS 30
#define SC8180X_MASTER_CNOC_DC_NOC 31
#define SC8180X_MASTER_AMPSS_M0 32
#define SC8180X_MASTER_GPU_TCU 33
#define SC8180X_MASTER_SYS_TCU 34
#define SC8180X_MASTER_GEM_NOC_CFG 35
#define SC8180X_MASTER_COMPUTE_NOC 36
#define SC8180X_MASTER_GRAPHICS_3D 37
#define SC8180X_MASTER_MNOC_HF_MEM_NOC 38
#define SC8180X_MASTER_MNOC_SF_MEM_NOC 39
#define SC8180X_MASTER_GEM_NOC_PCIE_SNOC 40
#define SC8180X_MASTER_SNOC_GC_MEM_NOC 41
#define SC8180X_MASTER_SNOC_SF_MEM_NOC 42
#define SC8180X_MASTER_ECC 43
#define SC8180X_MASTER_IPA_CORE 44
#define SC8180X_MASTER_LLCC 45
#define SC8180X_MASTER_CNOC_MNOC_CFG 46
#define SC8180X_MASTER_CAMNOC_HF0 47
#define SC8180X_MASTER_CAMNOC_HF1 48
#define SC8180X_MASTER_CAMNOC_SF 49
#define SC8180X_MASTER_MDP_PORT0 50
#define SC8180X_MASTER_MDP_PORT1 51
#define SC8180X_MASTER_ROTATOR 52
#define SC8180X_MASTER_VIDEO_P0 53
#define SC8180X_MASTER_VIDEO_P1 54
#define SC8180X_MASTER_VIDEO_PROC 55
#define SC8180X_MASTER_SNOC_CFG 56
#define SC8180X_A1NOC_SNOC_MAS 57
#define SC8180X_A2NOC_SNOC_MAS 58
#define SC8180X_MASTER_GEM_NOC_SNOC 59
#define SC8180X_MASTER_PIMEM 60
#define SC8180X_MASTER_GIC 61
#define SC8180X_MASTER_MNOC_HF_MEM_NOC_DISPLAY 62
#define SC8180X_MASTER_MNOC_SF_MEM_NOC_DISPLAY 63
#define SC8180X_MASTER_LLCC_DISPLAY 64
#define SC8180X_MASTER_MDP_PORT0_DISPLAY 65
#define SC8180X_MASTER_MDP_PORT1_DISPLAY 66
#define SC8180X_MASTER_ROTATOR_DISPLAY 67
#define SC8180X_A1NOC_SNOC_SLV 68
#define SC8180X_SLAVE_SERVICE_A1NOC 69
#define SC8180X_A2NOC_SNOC_SLV 70
#define SC8180X_SLAVE_ANOC_PCIE_GEM_NOC 71
#define SC8180X_SLAVE_SERVICE_A2NOC 72
#define SC8180X_SLAVE_CAMNOC_UNCOMP 73
#define SC8180X_SLAVE_CDSP_MEM_NOC 74
#define SC8180X_SLAVE_A1NOC_CFG 75
#define SC8180X_SLAVE_A2NOC_CFG 76
#define SC8180X_SLAVE_AHB2PHY_CENTER 77
#define SC8180X_SLAVE_AHB2PHY_EAST 78
#define SC8180X_SLAVE_AHB2PHY_WEST 79
#define SC8180X_SLAVE_AHB2PHY_SOUTH 80
#define SC8180X_SLAVE_AOP 81
#define SC8180X_SLAVE_AOSS 82
#define SC8180X_SLAVE_CAMERA_CFG 83
#define SC8180X_SLAVE_CLK_CTL 84
#define SC8180X_SLAVE_CDSP_CFG 85
#define SC8180X_SLAVE_RBCPR_CX_CFG 86
#define SC8180X_SLAVE_RBCPR_MMCX_CFG 87
#define SC8180X_SLAVE_RBCPR_MX_CFG 88
#define SC8180X_SLAVE_CRYPTO_0_CFG 89
#define SC8180X_SLAVE_CNOC_DDRSS 90
#define SC8180X_SLAVE_DISPLAY_CFG 91
#define SC8180X_SLAVE_EMAC_CFG 92
#define SC8180X_SLAVE_GLM 93
#define SC8180X_SLAVE_GRAPHICS_3D_CFG 94
#define SC8180X_SLAVE_IMEM_CFG 95
#define SC8180X_SLAVE_IPA_CFG 96
#define SC8180X_SLAVE_CNOC_MNOC_CFG 97
#define SC8180X_SLAVE_NPU_CFG 98
#define SC8180X_SLAVE_PCIE_0_CFG 99
#define SC8180X_SLAVE_PCIE_1_CFG 100
#define SC8180X_SLAVE_PCIE_2_CFG 101
#define SC8180X_SLAVE_PCIE_3_CFG 102
#define SC8180X_SLAVE_PDM 103
#define SC8180X_SLAVE_PIMEM_CFG 104
#define SC8180X_SLAVE_PRNG 105
#define SC8180X_SLAVE_QDSS_CFG 106
#define SC8180X_SLAVE_QSPI_0 107
#define SC8180X_SLAVE_QSPI_1 108
#define SC8180X_SLAVE_QUP_1 109
#define SC8180X_SLAVE_QUP_2 110
#define SC8180X_SLAVE_QUP_0 111
#define SC8180X_SLAVE_SDCC_2 112
#define SC8180X_SLAVE_SDCC_4 113
#define SC8180X_SLAVE_SECURITY 114
#define SC8180X_SLAVE_SNOC_CFG 115
#define SC8180X_SLAVE_SPSS_CFG 116
#define SC8180X_SLAVE_TCSR 117
#define SC8180X_SLAVE_TLMM_EAST 118
#define SC8180X_SLAVE_TLMM_SOUTH 119
#define SC8180X_SLAVE_TLMM_WEST 120
#define SC8180X_SLAVE_TSIF 121
#define SC8180X_SLAVE_UFS_CARD_CFG 122
#define SC8180X_SLAVE_UFS_MEM_0_CFG 123
#define SC8180X_SLAVE_UFS_MEM_1_CFG 124
#define SC8180X_SLAVE_USB3 125
#define SC8180X_SLAVE_USB3_1 126
#define SC8180X_SLAVE_USB3_2 127
#define SC8180X_SLAVE_VENUS_CFG 128
#define SC8180X_SLAVE_VSENSE_CTRL_CFG 129
#define SC8180X_SLAVE_SERVICE_CNOC 130
#define SC8180X_SLAVE_GEM_NOC_CFG 131
#define SC8180X_SLAVE_LLCC_CFG 132
#define SC8180X_SLAVE_MSS_PROC_MS_MPU_CFG 133
#define SC8180X_SLAVE_ECC 134
#define SC8180X_SLAVE_GEM_NOC_SNOC 135
#define SC8180X_SLAVE_LLCC 136
#define SC8180X_SLAVE_SERVICE_GEM_NOC 137
#define SC8180X_SLAVE_SERVICE_GEM_NOC_1 138
#define SC8180X_SLAVE_IPA_CORE 139
#define SC8180X_SLAVE_EBI_CH0 140
#define SC8180X_SLAVE_MNOC_SF_MEM_NOC 141
#define SC8180X_SLAVE_MNOC_HF_MEM_NOC 142
#define SC8180X_SLAVE_SERVICE_MNOC 143
#define SC8180X_SLAVE_APPSS 144
#define SC8180X_SNOC_CNOC_SLV 145
#define SC8180X_SLAVE_SNOC_GEM_NOC_GC 146
#define SC8180X_SLAVE_SNOC_GEM_NOC_SF 147
#define SC8180X_SLAVE_OCIMEM 148
#define SC8180X_SLAVE_PIMEM 149
#define SC8180X_SLAVE_SERVICE_SNOC 150
#define SC8180X_SLAVE_PCIE_0 151
#define SC8180X_SLAVE_PCIE_1 152
#define SC8180X_SLAVE_PCIE_2 153
#define SC8180X_SLAVE_PCIE_3 154
#define SC8180X_SLAVE_QDSS_STM 155
#define SC8180X_SLAVE_TCU 156
#define SC8180X_SLAVE_LLCC_DISPLAY 157
#define SC8180X_SLAVE_EBI_CH0_DISPLAY 158
#define SC8180X_SLAVE_MNOC_SF_MEM_NOC_DISPLAY 159
#define SC8180X_SLAVE_MNOC_HF_MEM_NOC_DISPLAY 160
#define SC8180X_MASTER_OSM_L3_APPS 161
#define SC8180X_SLAVE_OSM_L3 162
#endif

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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