Char/Misc and other Driver changes for 6.8-rc1

Here is the big set of char/misc and other driver subsystem changes for
 6.8-rc1.  Lots of stuff in here, but first off, you will get a merge
 conflict in drivers/android/binder_alloc.c when merging this tree due to
 changing coming in through the -mm tree.
 
 The resolution of the merge issue can be found here:
 	https://lore.kernel.org/r/20231207134213.25631ae9@canb.auug.org.au
 or in a simpler patch form in that thread:
 	https://lore.kernel.org/r/ZXHzooF07LfQQYiE@google.com
 
 If there are issues with the merge of this file, please let me know.
 
 Other than lots of binder driver changes (as you can see by the merge
 conflicts) included in here are:
  - lots of iio driver updates and additions
  - spmi driver updates
  - eeprom driver updates
  - firmware driver updates
  - ocxl driver updates
  - mhi driver updates
  - w1 driver updates
  - nvmem driver updates
  - coresight driver updates
  - platform driver remove callback api changes
  - tags.sh script updates
  - bus_type constant marking cleanups
  - lots of other small driver updates
 
 All of these have been in linux-next for a while with no reported issues
 (other than the binder merge conflict.)
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZaeMMQ8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ynWNgCfQ/Yz7QO6EMLDwHO5LRsb3YMhjL4AoNVdanjP
 YoI7f1I4GBcC0GKNfK6s
 =+Kyv
 -----END PGP SIGNATURE-----

Merge tag 'char-misc-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc

Pull char/misc and other driver updates from Greg KH:
 "Here is the big set of char/misc and other driver subsystem changes
  for 6.8-rc1.

  Other than lots of binder driver changes (as you can see by the merge
  conflicts) included in here are:

   - lots of iio driver updates and additions

   - spmi driver updates

   - eeprom driver updates

   - firmware driver updates

   - ocxl driver updates

   - mhi driver updates

   - w1 driver updates

   - nvmem driver updates

   - coresight driver updates

   - platform driver remove callback api changes

   - tags.sh script updates

   - bus_type constant marking cleanups

   - lots of other small driver updates

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'char-misc-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (341 commits)
  android: removed duplicate linux/errno
  uio: Fix use-after-free in uio_open
  drivers: soc: xilinx: add check for platform
  firmware: xilinx: Export function to use in other module
  scripts/tags.sh: remove find_sources
  scripts/tags.sh: use -n to test archinclude
  scripts/tags.sh: add local annotation
  scripts/tags.sh: use more portable -path instead of -wholename
  scripts/tags.sh: Update comment (addition of gtags)
  firmware: zynqmp: Convert to platform remove callback returning void
  firmware: turris-mox-rwtm: Convert to platform remove callback returning void
  firmware: stratix10-svc: Convert to platform remove callback returning void
  firmware: stratix10-rsu: Convert to platform remove callback returning void
  firmware: raspberrypi: Convert to platform remove callback returning void
  firmware: qemu_fw_cfg: Convert to platform remove callback returning void
  firmware: mtk-adsp-ipc: Convert to platform remove callback returning void
  firmware: imx-dsp: Convert to platform remove callback returning void
  firmware: coreboot_table: Convert to platform remove callback returning void
  firmware: arm_scpi: Convert to platform remove callback returning void
  firmware: arm_scmi: Convert to platform remove callback returning void
  ...
This commit is contained in:
Linus Torvalds 2024-01-17 16:47:17 -08:00
commit 296455ade1
303 changed files with 24551 additions and 3028 deletions

View File

@ -390,9 +390,10 @@ Matthias Fuchs <socketcan@esd.eu> <matthias.fuchs@esd.eu>
Matthieu Baerts <matttbe@kernel.org> <matthieu.baerts@tessares.net>
Matthieu CASTET <castet.matthieu@free.fr>
Matti Vaittinen <mazziesaccount@gmail.com> <matti.vaittinen@fi.rohmeurope.com>
Matt Ranostay <matt.ranostay@konsulko.com> <matt@ranostay.consulting>
Matt Ranostay <mranostay@gmail.com> Matthew Ranostay <mranostay@embeddedalley.com>
Matt Ranostay <mranostay@gmail.com> <matt.ranostay@intel.com>
Matt Ranostay <matt@ranostay.sg> <matt.ranostay@konsulko.com>
Matt Ranostay <matt@ranostay.sg> <matt@ranostay.consulting>
Matt Ranostay <matt@ranostay.sg> Matthew Ranostay <mranostay@embeddedalley.com>
Matt Ranostay <matt@ranostay.sg> <matt.ranostay@intel.com>
Matt Redfearn <matt.redfearn@mips.com> <matt.redfearn@imgtec.com>
Maulik Shah <quic_mkshah@quicinc.com> <mkshah@codeaurora.org>
Mauro Carvalho Chehab <mchehab@kernel.org> <maurochehab@gmail.com>

View File

@ -98,6 +98,13 @@ Description:
# echo 1 > /sys/bus/cdx/devices/.../remove
What: /sys/bus/cdx/devices/.../resource<N>
Date: July 2023
Contact: puneet.gupta@amd.com
Description:
The resource binary file contains the content of the memory
regions. These files can be m'maped from userspace.
What: /sys/bus/cdx/devices/.../modalias
Date: July 2023
Contact: nipun.gupta@amd.com

View File

@ -91,3 +91,19 @@ Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Size of the trace buffer for TMC-ETR when used in SYSFS
mode. Writable only for TMC-ETR configurations. The value
should be aligned to the kernel pagesize.
What: /sys/bus/coresight/devices/<memory_map>.tmc/buf_modes_available
Date: August 2023
KernelVersion: 6.7
Contact: Anshuman Khandual <anshuman.khandual@arm.com>
Description: (Read) Shows all supported Coresight TMC-ETR buffer modes available
for the users to configure explicitly. This file is avaialble only
for TMC ETR devices.
What: /sys/bus/coresight/devices/<memory_map>.tmc/buf_mode_preferred
Date: August 2023
KernelVersion: 6.7
Contact: Anshuman Khandual <anshuman.khandual@arm.com>
Description: (RW) Current Coresight TMC-ETR buffer mode selected. But user could
only provide a mode which is supported for a given ETR device. This
file is available only for TMC ETR devices.

View File

@ -11,3 +11,162 @@ Description:
Accepts only one of the 2 values - 1 or 2.
1 : Generate 64 bits data
2 : Generate 32 bits data
What: /sys/bus/coresight/devices/<tpdm-name>/reset_dataset
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
(Write) Reset the dataset of the tpdm.
Accepts only one value - 1.
1 : Reset the dataset of the tpdm
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_trig_type
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
(RW) Set/Get the trigger type of the DSB for tpdm.
Accepts only one of the 2 values - 0 or 1.
0 : Set the DSB trigger type to false
1 : Set the DSB trigger type to true
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_trig_ts
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
(RW) Set/Get the trigger timestamp of the DSB for tpdm.
Accepts only one of the 2 values - 0 or 1.
0 : Set the DSB trigger type to false
1 : Set the DSB trigger type to true
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_mode
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
(RW) Set/Get the programming mode of the DSB for tpdm.
Accepts the value needs to be greater than 0. What data
bits do is listed below.
Bit[0:1] : Test mode control bit for choosing the inputs.
Bit[3] : Set to 0 for low performance mode. Set to 1 for high
performance mode.
Bit[4:8] : Select byte lane for high performance mode.
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/ctrl_idx
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
(RW) Set/Get the index number of the edge detection for the DSB
subunit TPDM. Since there are at most 256 edge detections, this
value ranges from 0 to 255.
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/ctrl_val
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
Write a data to control the edge detection corresponding to
the index number. Before writing data to this sysfs file,
"ctrl_idx" should be written first to configure the index
number of the edge detection which needs to be controlled.
Accepts only one of the following values.
0 - Rising edge detection
1 - Falling edge detection
2 - Rising and falling edge detection (toggle detection)
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/ctrl_mask
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
Write a data to mask the edge detection corresponding to the index
number. Before writing data to this sysfs file, "ctrl_idx" should
be written first to configure the index number of the edge detection
which needs to be masked.
Accepts only one of the 2 values - 0 or 1.
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/edcr[0:15]
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
Read a set of the edge control value of the DSB in TPDM.
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/edcmr[0:7]
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
Read a set of the edge control mask of the DSB in TPDM.
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_trig_patt/xpr[0:7]
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
(RW) Set/Get the value of the trigger pattern for the DSB
subunit TPDM.
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_trig_patt/xpmr[0:7]
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
(RW) Set/Get the mask of the trigger pattern for the DSB
subunit TPDM.
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/tpr[0:7]
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
(RW) Set/Get the value of the pattern for the DSB subunit TPDM.
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/tpmr[0:7]
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
(RW) Set/Get the mask of the pattern for the DSB subunit TPDM.
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/enable_ts
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
(Write) Set the pattern timestamp of DSB tpdm. Read
the pattern timestamp of DSB tpdm.
Accepts only one of the 2 values - 0 or 1.
0 : Disable DSB pattern timestamp.
1 : Enable DSB pattern timestamp.
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/set_type
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
(Write) Set the pattern type of DSB tpdm. Read
the pattern type of DSB tpdm.
Accepts only one of the 2 values - 0 or 1.
0 : Set the DSB pattern type to value.
1 : Set the DSB pattern type to toggle.
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_msr/msr[0:31]
Date: March 2023
KernelVersion 6.7
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
Description:
(RW) Set/Get the MSR(mux select register) for the DSB subunit
TPDM.

View File

@ -362,10 +362,21 @@ Description:
What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_peak_raw
What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_peak_raw
What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_peak_raw
What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_peak_raw
What: /sys/bus/iio/devices/iio:deviceX/in_temp_peak_raw
KernelVersion: 2.6.36
Contact: linux-iio@vger.kernel.org
Description:
Highest value since some reset condition. These
Highest value since some reset condition. These
attributes allow access to this and are otherwise
the direct equivalent of the <type>Y[_name]_raw attributes.
What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_trough_raw
What: /sys/bus/iio/devices/iio:deviceX/in_temp_trough_raw
KernelVersion: 6.7
Contact: linux-iio@vger.kernel.org
Description:
Lowest value since some reset condition. These
attributes allow access to this and are otherwise
the direct equivalent of the <type>Y[_name]_raw attributes.
@ -618,7 +629,9 @@ KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
If a discrete set of scale values is available, they
are listed in this attribute.
are listed in this attribute. Unlike illumination,
multiplying intensity by intensity_scale does not
yield value with any standardized unit.
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_hardwaregain
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_hardwaregain
@ -1574,6 +1587,8 @@ What: /sys/.../iio:deviceX/in_intensityY_raw
What: /sys/.../iio:deviceX/in_intensityY_ir_raw
What: /sys/.../iio:deviceX/in_intensityY_both_raw
What: /sys/.../iio:deviceX/in_intensityY_uv_raw
What: /sys/.../iio:deviceX/in_intensityY_uva_raw
What: /sys/.../iio:deviceX/in_intensityY_uvb_raw
What: /sys/.../iio:deviceX/in_intensityY_duv_raw
KernelVersion: 3.4
Contact: linux-iio@vger.kernel.org
@ -1582,8 +1597,9 @@ Description:
that measurements contain visible and infrared light
components or just infrared light, respectively. Modifier
uv indicates that measurements contain ultraviolet light
components. Modifier duv indicates that measurements
contain deep ultraviolet light components.
components. Modifiers uva, uvb and duv indicate that
measurements contain A, B or deep (C) ultraviolet light
components respectively.
What: /sys/.../iio:deviceX/in_uvindex_input
KernelVersion: 4.6
@ -2254,3 +2270,21 @@ Description:
If a label is defined for this event add that to the event
specific attributes. This is useful for userspace to be able to
better identify an individual event.
What: /sys/.../events/in_accel_gesture_tap_wait_timeout
KernelVersion: 6.7
Contact: linux-iio@vger.kernel.org
Description:
Enable tap gesture confirmation with timeout.
What: /sys/.../events/in_accel_gesture_tap_wait_dur
KernelVersion: 6.7
Contact: linux-iio@vger.kernel.org
Description:
Timeout value in seconds for tap gesture confirmation.
What: /sys/.../events/in_accel_gesture_tap_wait_dur_available
KernelVersion: 6.7
Contact: linux-iio@vger.kernel.org
Description:
List of available timeout value for tap gesture confirmation.

View File

@ -0,0 +1,21 @@
What: /sys/bus/nvmem/devices/.../cells/<cell-name>
Date: May 2023
KernelVersion: 6.5
Contact: Miquel Raynal <miquel.raynal@bootlin.com>
Description:
The "cells" folder contains one file per cell exposed by the
NVMEM device. The name of the file is: <name>@<where>, with
<name> being the cell name and <where> its location in the NVMEM
device, in hexadecimal (without the '0x' prefix, to mimic device
tree node names). The length of the file is the size of the cell
(when known). The content of the file is the binary content of
the cell (may sometimes be ASCII, likely without trailing
character).
Note: This file is only present if CONFIG_NVMEM_SYSFS
is enabled.
Example::
hexdump -C /sys/bus/nvmem/devices/1-00563/cells/product-name@d
00000000 54 4e 34 38 4d 2d 50 2d 44 4e |TN48M-P-DN|
0000000a

View File

@ -117,6 +117,10 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A76 | #1463225 | ARM64_ERRATUM_1463225 |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A76 | #1490853 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A77 | #1491015 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A77 | #1508412 | ARM64_ERRATUM_1508412 |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A710 | #2119858 | ARM64_ERRATUM_2119858 |
@ -127,6 +131,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A715 | #2645198 | ARM64_ERRATUM_2645198 |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-X1 | #1502854 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-X2 | #2119858 | ARM64_ERRATUM_2119858 |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-X2 | #2224489 | ARM64_ERRATUM_2224489 |
@ -135,6 +141,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Neoverse-N1 | #1349291 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Neoverse-N1 | #1490853 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Neoverse-N1 | #1542419 | ARM64_ERRATUM_1542419 |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Neoverse-N2 | #2139208 | ARM64_ERRATUM_2139208 |
@ -143,6 +151,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Neoverse-N2 | #2253138 | ARM64_ERRATUM_2253138 |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Neoverse-V1 | #1619801 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | MMU-500 | #841119,826419 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | MMU-600 | #1076982,1209401| N/A |

View File

@ -44,6 +44,23 @@ properties:
minItems: 1
maxItems: 2
qcom,dsb-element-size:
description:
Specifies the DSB(Discrete Single Bit) element size supported by
the monitor. The associated aggregator will read this size before it
is enabled. DSB element size currently only supports 32-bit and 64-bit.
$ref: /schemas/types.yaml#/definitions/uint8
enum: [32, 64]
qcom,dsb-msrs-num:
description:
Specifies the number of DSB(Discrete Single Bit) MSR(mux select register)
registers supported by the monitor. If this property is not configured
or set to 0, it means this DSB TPDM doesn't support MSR.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 32
clocks:
maxItems: 1
@ -77,6 +94,9 @@ examples:
compatible = "qcom,coresight-tpdm", "arm,primecell";
reg = <0x0684c000 0x1000>;
qcom,dsb-element-size = /bits/ 8 <32>;
qcom,dsb-msrs-num = <16>;
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";

View File

@ -4,36 +4,92 @@
$id: http://devicetree.org/schemas/iio/adc/adi,ad7091r5.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices AD7091R5 4-Channel 12-Bit ADC
title: Analog Devices AD7091R-2/-4/-5/-8 Multi-Channel 12-Bit ADCs
maintainers:
- Michael Hennerich <michael.hennerich@analog.com>
- Marcelo Schmitt <marcelo.schmitt@analog.com>
description: |
Analog Devices AD7091R5 4-Channel 12-Bit ADC
Analog Devices AD7091R5 4-Channel 12-Bit ADC supporting I2C interface
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf
Analog Devices AD7091R-2/AD7091R-4/AD7091R-8 2-/4-/8-Channel 12-Bit ADCs
supporting SPI interface
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7091R-2_7091R-4_7091R-8.pdf
properties:
compatible:
enum:
- adi,ad7091r2
- adi,ad7091r4
- adi,ad7091r5
- adi,ad7091r8
reg:
maxItems: 1
vdd-supply:
description:
Provide VDD power to the sensor (VDD range is from 2.7V to 5.25V).
vdrive-supply:
description:
Determines the voltage level at which the interface logic will operate.
The V_drive voltage range is from 1.8V to 5.25V and must not exceed VDD by
more than 0.3V.
vref-supply:
description:
Phandle to the vref power supply
interrupts:
convst-gpios:
description:
GPIO connected to the CONVST pin.
This logic input is used to initiate conversions on the analog
input channels.
maxItems: 1
reset-gpios:
maxItems: 1
interrupts:
description:
Interrupt for signaling when conversion results exceed the high limit for
ADC readings or fall below the low limit for them. Interrupt source must
be attached to ALERT/BUSY/GPO0 pin.
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
# AD7091R-2 does not have ALERT/BUSY/GPO pin
- if:
properties:
compatible:
contains:
enum:
- adi,ad7091r2
then:
properties:
interrupts: false
- if:
properties:
compatible:
contains:
enum:
- adi,ad7091r2
- adi,ad7091r4
- adi,ad7091r8
then:
required:
- convst-gpios
unevaluatedProperties: false
examples:
- |
@ -51,4 +107,22 @@ examples:
interrupt-parent = <&gpio>;
};
};
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "adi,ad7091r8";
reg = <0x0>;
spi-max-frequency = <1000000>;
vref-supply = <&adc_vref>;
convst-gpios = <&gpio 25 GPIO_ACTIVE_LOW>;
reset-gpios = <&gpio 27 GPIO_ACTIVE_LOW>;
interrupts = <22 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio>;
};
};
...

View File

@ -0,0 +1,139 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/maxim,max34408.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim MAX34408/MAX34409 current monitors with overcurrent control
maintainers:
- Ivan Mikhaylov <fr0st61te@gmail.com>
description: |
The MAX34408/MAX34409 are two- and four-channel current monitors that are
configured and monitored with a standard I2C/SMBus serial interface. Each
unidirectional current sensor offers precision high-side operation with a
low full-scale sense voltage. The devices automatically sequence through
two or four channels and collect the current-sense samples and average them
to reduce the effect of impulse noise. The raw ADC samples are compared to
user-programmable digital thresholds to indicate overcurrent conditions.
Overcurrent conditions trigger a hardware output to provide an immediate
indication to shut down any necessary external circuitry.
Specifications about the devices can be found at:
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX34408-MAX34409.pdf
properties:
compatible:
enum:
- maxim,max34408
- maxim,max34409
"#address-cells":
const: 1
"#size-cells":
const: 0
reg:
maxItems: 1
interrupts:
maxItems: 1
powerdown-gpios:
description:
Shutdown Output. Open-drain output. This output transitions to high impedance
when any of the digital comparator thresholds are exceeded as long as the ENA
pin is high.
maxItems: 1
powerdown-status-gpios:
description:
SHTDN Enable Input. CMOS digital input. Connect to GND to clear the latch and
unconditionally deassert (force low) the SHTDN output and reset the shutdown
delay. Connect to VDD to enable normal latch operation of the SHTDN output.
maxItems: 1
vdd-supply: true
patternProperties:
"^channel@[0-3]$":
$ref: adc.yaml
type: object
description:
Represents the internal channels of the ADC.
properties:
reg:
items:
- minimum: 0
maximum: 3
maxim,rsense-val-micro-ohms:
description:
Adjust the Rsense value to monitor higher or lower current levels for
input.
enum: [250, 500, 1000, 5000, 10000, 50000, 100000, 200000, 500000]
default: 1000
required:
- reg
- maxim,rsense-val-micro-ohms
unevaluatedProperties: false
required:
- compatible
- reg
allOf:
- if:
properties:
compatible:
contains:
const: maxim,max34408
then:
patternProperties:
"^channel@[2-3]$": false
"^channel@[0-1]$":
properties:
reg:
maximum: 1
else:
patternProperties:
"^channel@[0-3]$":
properties:
reg:
maximum: 3
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
adc@1e {
compatible = "maxim,max34409";
reg = <0x1e>;
powerdown-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
powerdown-status-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0x0>;
maxim,rsense-val-micro-ohms = <5000>;
};
channel@1 {
reg = <0x1>;
maxim,rsense-val-micro-ohms = <10000>;
};
};
};

View File

@ -25,7 +25,7 @@ properties:
- const: qcom,spmi-iadc
reg:
description: IADC base address and length in the SPMI PMIC register map
description: IADC base address in the SPMI PMIC register map
maxItems: 1
qcom,external-resistor-micro-ohms:
@ -50,10 +50,12 @@ additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
spmi {
pmic {
#address-cells = <1>;
#size-cells = <0>;
pmic_iadc: adc@3600 {
adc@3600 {
compatible = "qcom,pm8941-iadc", "qcom,spmi-iadc";
reg = <0x3600>;
interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>;

View File

@ -43,7 +43,7 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
pmic_rradc: adc@4500 {
adc@4500 {
compatible = "qcom,pmi8998-rradc";
reg = <0x4500>;
#io-channel-cells = <1>;

View File

@ -236,11 +236,11 @@ additionalProperties: false
examples:
- |
spmi {
pmic {
#address-cells = <1>;
#size-cells = <0>;
/* VADC node */
pmic_vadc: adc@3100 {
adc@3100 {
compatible = "qcom,spmi-vadc";
reg = <0x3100>;
interrupts = <0x0 0x31 0x0 0x1>;
@ -281,9 +281,10 @@ examples:
#include <dt-bindings/iio/qcom,spmi-adc7-pm8350.h>
#include <dt-bindings/interrupt-controller/irq.h>
spmi {
pmic {
#address-cells = <1>;
#size-cells = <0>;
adc@3100 {
reg = <0x3100>;
compatible = "qcom,spmi-adc7";

View File

@ -67,19 +67,4 @@ required:
- compatible
- "#io-channel-cells"
examples:
- |
#include <dt-bindings/clock/mt8183-clk.h>
pmic {
compatible = "ti,twl6035-pmic", "ti,palmas-pmic";
adc {
compatible = "ti,palmas-gpadc";
interrupts = <18 0>,
<16 0>,
<17 0>;
#io-channel-cells = <1>;
ti,channel0-current-microamp = <5>;
ti,channel3-current-microamp = <10>;
};
};
...

View File

@ -12,6 +12,9 @@ maintainers:
description: |
Digital Step Attenuator IIO devices with gpio interface.
Offer various frequency and attenuation ranges.
ADRF5750 2 dB LSB, 4-Bit, Silicon Digital Attenuator, 10 MHz to 60 GHz
https://www.analog.com/media/en/technical-documentation/data-sheets/adrf5740.pdf
HMC425A 0.5 dB LSB GaAs MMIC 6-BIT DIGITAL POSITIVE CONTROL ATTENUATOR, 2.2 - 8.0 GHz
https://www.analog.com/media/en/technical-documentation/data-sheets/hmc425A.pdf
@ -22,6 +25,7 @@ description: |
properties:
compatible:
enum:
- adi,adrf5740
- adi,hmc425a
- adi,hmc540s

View File

@ -0,0 +1,47 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/chemical/aosong,ags02ma.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Aosong AGS02MA VOC Sensor
description: |
AGS02MA is an TVOC (Total Volatile Organic Compounds) i2c sensor with default
address of 0x1a.
Datasheet:
https://asairsensors.com/wp-content/uploads/2021/09/AGS02MA.pdf
maintainers:
- Anshul Dalal <anshulusr@gmail.com>
properties:
compatible:
enum:
- aosong,ags02ma
reg:
maxItems: 1
vdd-supply: true
required:
- compatible
- reg
- vdd-supply
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
voc-sensor@1a {
compatible = "aosong,ags02ma";
reg = <0x1a>;
vdd-supply = <&vdd_regulator>;
};
};

View File

@ -26,6 +26,11 @@ properties:
vdd-supply: true
vss-supply: true
adi,rbuf-gain2-en:
description: Specify to allow an external amplifier to be connected in a
gain of two configuration.
type: boolean
required:
- compatible
- reg

View File

@ -0,0 +1,86 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/dac/microchip,mcp4821.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip MCP4821 and similar DACs
description: |
Supports MCP48x1 (single channel) and MCP48x2 (dual channel) series of DACs.
Device supports simplex communication over SPI in Mode 0 and Mode 3.
+---------+--------------+-------------+
| Device | Resolution | Channels |
|---------|--------------|-------------|
| MCP4801 | 8-bit | 1 |
| MCP4802 | 8-bit | 2 |
| MCP4811 | 10-bit | 1 |
| MCP4812 | 10-bit | 2 |
| MCP4821 | 12-bit | 1 |
| MCP4822 | 12-bit | 2 |
+---------+--------------+-------------+
Datasheet:
MCP48x1: https://ww1.microchip.com/downloads/en/DeviceDoc/22244B.pdf
MCP48x2: https://ww1.microchip.com/downloads/en/DeviceDoc/20002249B.pdf
maintainers:
- Anshul Dalal <anshulusr@gmail.com>
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
properties:
compatible:
enum:
- microchip,mcp4801
- microchip,mcp4802
- microchip,mcp4811
- microchip,mcp4812
- microchip,mcp4821
- microchip,mcp4822
reg:
maxItems: 1
vdd-supply: true
ldac-gpios:
description: |
Active Low LDAC (Latch DAC Input) pin used to update the DAC output.
maxItems: 1
powerdown-gpios:
description: |
Active Low SHDN pin used to enter the shutdown mode.
maxItems: 1
spi-cpha: true
spi-cpol: true
required:
- compatible
- reg
- vdd-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
dac@0 {
compatible = "microchip,mcp4821";
reg = <0>;
vdd-supply = <&vdd_regulator>;
ldac-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
powerdown-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
spi-cpha;
spi-cpol;
};
};

View File

@ -0,0 +1,55 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/humidity/ti,hdc3020.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: HDC3020/HDC3021/HDC3022 humidity and temperature iio sensors
maintainers:
- Li peiyu <579lpy@gmail.com>
- Javier Carrasco <javier.carrasco.cruz@gmail.com>
description:
https://www.ti.com/lit/ds/symlink/hdc3020.pdf
The HDC302x is an integrated capacitive based relative humidity (RH)
and temperature sensor.
properties:
compatible:
oneOf:
- items:
- enum:
- ti,hdc3021
- ti,hdc3022
- const: ti,hdc3020
- const: ti,hdc3020
interrupts:
maxItems: 1
vdd-supply: true
reg:
maxItems: 1
required:
- compatible
- reg
- vdd-supply
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
humidity-sensor@47 {
compatible = "ti,hdc3021", "ti,hdc3020";
reg = <0x47>;
vdd-supply = <&vcc_3v3>;
};
};

View File

@ -25,6 +25,10 @@ properties:
spi-cpol: true
spi-cs-inactive-delay-ns:
minimum: 16000
default: 16000
interrupts:
maxItems: 1

View File

@ -47,6 +47,10 @@ properties:
spi-max-frequency:
maximum: 2000000
spi-cs-inactive-delay-ns:
minimum: 16000
default: 16000
interrupts:
maxItems: 1

View File

@ -0,0 +1,77 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/imu/bosch,bmi323.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Bosch BMI323 6-Axis IMU
maintainers:
- Jagath Jog J <jagathjog1996@gmail.com>
description:
BMI323 is a 6-axis inertial measurement unit that supports acceleration and
gyroscopic measurements with hardware fifo buffering. Sensor also provides
events information such as motion, steps, orientation, single and double
tap detection.
properties:
compatible:
const: bosch,bmi323
reg:
maxItems: 1
vdd-supply: true
vddio-supply: true
interrupts:
minItems: 1
maxItems: 2
interrupt-names:
minItems: 1
maxItems: 2
items:
enum:
- INT1
- INT2
drive-open-drain:
description:
set if the specified interrupt pin should be configured as
open drain. If not set, defaults to push-pull.
mount-matrix:
description:
an optional 3x3 mounting rotation matrix.
required:
- compatible
- reg
- vdd-supply
- vddio-supply
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
unevaluatedProperties: false
examples:
- |
// Example for I2C
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
imu@68 {
compatible = "bosch,bmi323";
reg = <0x68>;
vddio-supply = <&vddio>;
vdd-supply = <&vdd>;
interrupt-parent = <&gpio1>;
interrupts = <29 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT1";
};
};

View File

@ -0,0 +1,56 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/light/liteon,ltr390.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Lite-On LTR390 ALS and UV Sensor
description: |
The Lite-On LTR390 is an ALS (Ambient Light Sensor) and a UV sensor in a
single package with i2c address of 0x53.
Datasheet:
https://optoelectronics.liteon.com/upload/download/DS86-2015-0004/LTR-390UV_Final_%20DS_V1%201.pdf
maintainers:
- Anshul Dalal <anshulusr@gmail.com>
properties:
compatible:
enum:
- liteon,ltr390
reg:
maxItems: 1
interrupts:
maxItems: 1
description: |
Level interrupt pin with open drain output.
The sensor pulls this pin low when the measured reading is greater than
some configured threshold.
vdd-supply: true
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
light-sensor@53 {
compatible = "liteon,ltr390";
reg = <0x53>;
interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
vdd-supply = <&vdd_regulator>;
};
};

View File

@ -0,0 +1,39 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/light/vishay,veml6075.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Vishay VEML6075 UVA and UVB sensor
maintainers:
- Javier Carrasco <javier.carrasco.cruz@gmail.com>
properties:
compatible:
const: vishay,veml6075
reg:
maxItems: 1
vdd-supply: true
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
uv-sensor@10 {
compatible = "vishay,veml6075";
reg = <0x10>;
vdd-supply = <&vdd_reg>;
};
};
...

View File

@ -0,0 +1,142 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/pressure/honeywell,hsc030pa.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Honeywell TruStability HSC and SSC pressure sensor series
description: |
support for Honeywell TruStability HSC and SSC digital pressure sensor
series.
These sensors have either an I2C, an SPI or an analog interface. Only the
digital versions are supported by this driver.
There are 118 models with different pressure ranges available in each family.
The vendor calls them "HSC series" and "SSC series". All of them have an
identical programming model but differ in pressure range, unit and transfer
function.
To support different models one needs to specify the pressure range as well
as the transfer function. Pressure range can either be provided via
pressure-triplet (directly extracted from the part number) or in case it's
a custom chip via numerical range limits converted to pascals.
The transfer function defines the ranges of raw conversion values delivered
by the sensor. pmin-pascal and pmax-pascal corespond to the minimum and
maximum pressure that can be measured.
Please note that in case of an SPI-based sensor, the clock signal should not
exceed 800kHz and the MOSI signal is not required.
Specifications about the devices can be found at:
https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf
https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-ssc-series/documents/sps-siot-trustability-ssc-series-standard-accuracy-board-mount-pressure-sensors-50099533-a-en-ciid-151134.pdf
maintainers:
- Petre Rodan <petre.rodan@subdimension.ro>
properties:
compatible:
const: honeywell,hsc030pa
reg:
maxItems: 1
honeywell,transfer-function:
description: |
Transfer function which defines the range of valid values delivered by
the sensor.
0 - A, 10% to 90% of 2^14
1 - B, 5% to 95% of 2^14
2 - C, 5% to 85% of 2^14
3 - F, 4% to 94% of 2^14
enum: [0, 1, 2, 3]
$ref: /schemas/types.yaml#/definitions/uint32
honeywell,pressure-triplet:
description: |
Case-sensitive five character string that defines pressure range, unit
and type as part of the device nomenclature. In the unlikely case of a
custom chip, set to "NA" and provide pmin-pascal and pmax-pascal.
enum: [001BA, 1.6BA, 2.5BA, 004BA, 006BA, 010BA, 1.6MD, 2.5MD, 004MD,
006MD, 010MD, 016MD, 025MD, 040MD, 060MD, 100MD, 160MD, 250MD,
400MD, 600MD, 001BD, 1.6BD, 2.5BD, 004BD, 2.5MG, 004MG, 006MG,
010MG, 016MG, 025MG, 040MG, 060MG, 100MG, 160MG, 250MG, 400MG,
600MG, 001BG, 1.6BG, 2.5BG, 004BG, 006BG, 010BG, 100KA, 160KA,
250KA, 400KA, 600KA, 001GA, 160LD, 250LD, 400LD, 600LD, 001KD,
1.6KD, 2.5KD, 004KD, 006KD, 010KD, 016KD, 025KD, 040KD, 060KD,
100KD, 160KD, 250KD, 400KD, 250LG, 400LG, 600LG, 001KG, 1.6KG,
2.5KG, 004KG, 006KG, 010KG, 016KG, 025KG, 040KG, 060KG, 100KG,
160KG, 250KG, 400KG, 600KG, 001GG, 015PA, 030PA, 060PA, 100PA,
150PA, 0.5ND, 001ND, 002ND, 004ND, 005ND, 010ND, 020ND, 030ND,
001PD, 005PD, 015PD, 030PD, 060PD, 001NG, 002NG, 004NG, 005NG,
010NG, 020NG, 030NG, 001PG, 005PG, 015PG, 030PG, 060PG, 100PG,
150PG, NA]
$ref: /schemas/types.yaml#/definitions/string
honeywell,pmin-pascal:
description: |
Minimum pressure value the sensor can measure in pascal.
To be specified only if honeywell,pressure-triplet is set to "NA".
honeywell,pmax-pascal:
description: |
Maximum pressure value the sensor can measure in pascal.
To be specified only if honeywell,pressure-triplet is set to "NA".
vdd-supply:
description:
Provide VDD power to the sensor (either 3.3V or 5V depending on the chip)
spi-max-frequency:
maximum: 800000
required:
- compatible
- reg
- honeywell,transfer-function
- honeywell,pressure-triplet
additionalProperties: false
dependentSchemas:
honeywell,pmin-pascal:
properties:
honeywell,pressure-triplet:
const: NA
honeywell,pmax-pascal:
properties:
honeywell,pressure-triplet:
const: NA
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
pressure@28 {
compatible = "honeywell,hsc030pa";
reg = <0x28>;
honeywell,transfer-function = <0>;
honeywell,pressure-triplet = "030PA";
};
};
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
pressure@0 {
compatible = "honeywell,hsc030pa";
reg = <0>;
spi-max-frequency = <800000>;
honeywell,transfer-function = <0>;
honeywell,pressure-triplet = "NA";
honeywell,pmin-pascal = <0>;
honeywell,pmax-pascal = <200000>;
};
};
...

View File

@ -53,12 +53,10 @@ properties:
honeywell,pmin-pascal:
description:
Minimum pressure value the sensor can measure in pascal.
$ref: /schemas/types.yaml#/definitions/uint32
honeywell,pmax-pascal:
description:
Maximum pressure value the sensor can measure in pascal.
$ref: /schemas/types.yaml#/definitions/uint32
honeywell,transfer-function:
description: |

View File

@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/iio/temperature/melexis,mlx90632.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Melexis MLX90632 contactless Infra Red temperature sensor
title: Melexis MLX90632 and MLX90635 contactless Infra Red temperature sensor
maintainers:
- Crt Mori <cmo@melexis.com>
@ -27,9 +27,24 @@ description: |
Since measured object emissivity effects Infra Red energy emitted,
emissivity should be set before requesting the object temperature.
https://www.melexis.com/en/documents/documentation/datasheets/datasheet-mlx90635
MLX90635 is most suitable for consumer applications where
measured object temperature is in range between -20 to 100 degrees
Celsius with relative error of measurement 2 degree Celsius in
object temperature range for industrial applications, while just 0.2
degree Celsius for human body measurement applications. Since it can
operate and measure ambient temperature in range of -20 to 85 degrees
Celsius it is suitable also for outdoor use.
Since measured object emissivity effects Infra Red energy emitted,
emissivity should be set before requesting the object temperature.
properties:
compatible:
const: melexis,mlx90632
enum:
- melexis,mlx90632
- melexis,mlx90635
reg:
maxItems: 1

View File

@ -0,0 +1,70 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/temperature/microchip,mcp9600.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip MCP9600 thermocouple EMF converter
maintainers:
- Andrew Hepp <andrew.hepp@ahepp.dev>
description:
https://ww1.microchip.com/downloads/en/DeviceDoc/MCP960X-Data-Sheet-20005426.pdf
properties:
compatible:
const: microchip,mcp9600
reg:
maxItems: 1
interrupts:
minItems: 1
maxItems: 6
interrupt-names:
minItems: 1
maxItems: 6
items:
enum:
- open-circuit
- short-circuit
- alert1
- alert2
- alert3
- alert4
thermocouple-type:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Type of thermocouple (THERMOCOUPLE_TYPE_K if omitted).
Use defines in dt-bindings/iio/temperature/thermocouple.h.
Supported types are B, E, J, K, N, R, S, T.
vdd-supply: true
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/iio/temperature/thermocouple.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
temperature-sensor@60 {
compatible = "microchip,mcp9600";
reg = <0x60>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "open-circuit";
thermocouple-type = <THERMOCOUPLE_TYPE_K>;
vdd-supply = <&vdd>;
};
};

View File

@ -25,13 +25,16 @@ properties:
- const: qcom,msm8998-bwmon # BWMON v4
- items:
- enum:
- qcom,qcm2290-cpu-bwmon
- qcom,sc7180-cpu-bwmon
- qcom,sc7280-cpu-bwmon
- qcom,sc8280xp-cpu-bwmon
- qcom,sdm845-cpu-bwmon
- qcom,sm6115-cpu-bwmon
- qcom,sm6350-llcc-bwmon
- qcom,sm8250-cpu-bwmon
- qcom,sm8550-cpu-bwmon
- qcom,sm8650-cpu-bwmon
- const: qcom,sdm845-bwmon # BWMON v4, unified register space
- items:
- enum:
@ -40,6 +43,7 @@ properties:
- qcom,sm6350-cpu-bwmon
- qcom,sm8250-llcc-bwmon
- qcom,sm8550-llcc-bwmon
- qcom,sm8650-llcc-bwmon
- const: qcom,sc7280-llcc-bwmon
- const: qcom,sc7280-llcc-bwmon # BWMON v5
- const: qcom,sdm845-llcc-bwmon # BWMON v5

View File

@ -24,6 +24,7 @@ properties:
- st,stm32f4-otp
- st,stm32mp13-bsec
- st,stm32mp15-bsec
- st,stm32mp25-bsec
reg:
maxItems: 1

View File

@ -177,6 +177,8 @@ properties:
- isil,isl29030
# Intersil ISL68137 Digital Output Configurable PWM Controller
- isil,isl68137
# Intersil ISL76682 Ambient Light Sensor
- isil,isl76682
# Linear Technology LTC2488
- lineartechnology,ltc2488
# 5 Bit Programmable, Pulse-Width Modulator

View File

@ -121,6 +121,8 @@ patternProperties:
description: Andes Technology Corporation
"^anvo,.*":
description: Anvo-Systems Dresden GmbH
"^aosong,.*":
description: Guangzhou Aosong Electronic Co., Ltd.
"^apm,.*":
description: Applied Micro Circuits Corporation (APM)
"^apple,.*":

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/w1/amd,axi-1wire-host.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: AMD AXI 1-wire bus host for programmable logic
maintainers:
- Kris Chaplin <kris.chaplin@amd.com>
properties:
compatible:
const: amd,axi-1wire-host
reg:
maxItems: 1
clocks:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
- clocks
- interrupts
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
onewire@a0000000 {
compatible = "amd,axi-1wire-host";
reg = <0xa0000000 0x10000>;
clocks = <&zynqmp_clk 0x47>;
interrupts = <GIC_SPI 0x59 IRQ_TYPE_LEVEL_HIGH>;
};
...

View File

@ -624,6 +624,10 @@ They are also listed in the folder /sys/bus/event_source/devices/cs_etm/format/
* - timestamp
- Session local version of the system wide setting: :ref:`ETMv4_MODE_TIMESTAMP
<coresight-timestamp>`
* - cc_threshold
- Cycle count threshold value. If nothing is provided here or the provided value is 0, then the
default value i.e 0x100 will be used. If provided value is less than minimum cycles threshold
value, as indicated via TRCIDR3.CCITMIN, then the minimum value will be used instead.
How to use the STM module
-------------------------

View File

@ -890,6 +890,14 @@ Q: https://patchwork.kernel.org/project/linux-rdma/list/
F: drivers/infiniband/hw/efa/
F: include/uapi/rdma/efa-abi.h
AMD AXI W1 DRIVER
M: Kris Chaplin <kris.chaplin@amd.com>
R: Thomas Delev <thomas.delev@amd.com>
R: Michal Simek <michal.simek@amd.com>
S: Maintained
F: Documentation/devicetree/bindings/w1/amd,axi-1wire-host.yaml
F: drivers/w1/masters/amd_axi_w1.c
AMD CDX BUS DRIVER
M: Nipun Gupta <nipun.gupta@amd.com>
M: Nikhil Agarwal <nikhil.agarwal@amd.com>
@ -1123,6 +1131,14 @@ F: Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130
F: Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml
F: drivers/iio/adc/ad4130.c
ANALOG DEVICES INC AD7091R DRIVER
M: Marcelo Schmitt <marcelo.schmitt@analog.com>
L: linux-iio@vger.kernel.org
S: Supported
W: http://ez.analog.com/community/linux-device-drivers
F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r*
F: drivers/iio/adc/drivers/iio/adc/ad7091r*
ANALOG DEVICES INC AD7192 DRIVER
M: Alexandru Tachici <alexandru.tachici@analog.com>
L: linux-iio@vger.kernel.org
@ -2048,7 +2064,6 @@ ARM/CORESIGHT FRAMEWORK AND DRIVERS
M: Suzuki K Poulose <suzuki.poulose@arm.com>
R: Mike Leach <mike.leach@linaro.org>
R: James Clark <james.clark@arm.com>
R: Leo Yan <leo.yan@linaro.org>
L: coresight@lists.linaro.org (moderated for non-subscribers)
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
@ -3044,6 +3059,13 @@ S: Supported
W: http://www.akm.com/
F: drivers/iio/magnetometer/ak8974.c
AOSONG AGS02MA TVOC SENSOR DRIVER
M: Anshul Dalal <anshulusr@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/chemical/aosong,ags02ma.yaml
F: drivers/iio/chemical/ags02ma.c
ASC7621 HARDWARE MONITOR DRIVER
M: George Joseph <george.joseph@fairview5.com>
L: linux-hwmon@vger.kernel.org
@ -3643,6 +3665,13 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml
F: drivers/iio/accel/bma400*
BOSCH SENSORTEC BMI323 IMU IIO DRIVER
M: Jagath Jog J <jagathjog1996@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml
F: drivers/iio/imu/bmi323/
BPF JIT for ARM
M: Russell King <linux@armlinux.org.uk>
M: Puranjay Mohan <puranjay12@gmail.com>
@ -5384,6 +5413,12 @@ F: include/linux/counter.h
F: include/uapi/linux/counter.h
F: tools/counter/
COUNTER WATCH EVENTS TOOL
M: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: tools/counter/counter_watch_events.c
CP2615 I2C DRIVER
M: Bence Csókás <bence98@sch.bme.hu>
S: Maintained
@ -9731,6 +9766,13 @@ F: lib/test_hmm*
F: mm/hmm*
F: tools/testing/selftests/mm/*hmm*
HONEYWELL HSC030PA PRESSURE SENSOR SERIES IIO DRIVER
M: Petre Rodan <petre.rodan@subdimension.ro>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml
F: drivers/iio/pressure/hsc030pa*
HONEYWELL MPRLS0025PA PRESSURE SENSOR SERIES IIO DRIVER
M: Andreas Klinger <ak@it-klinger.de>
L: linux-iio@vger.kernel.org
@ -10346,8 +10388,8 @@ IIO LIGHT SENSOR GAIN-TIME-SCALE HELPERS
M: Matti Vaittinen <mazziesaccount@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/light/gain-time-scale-helper.c
F: drivers/iio/light/gain-time-scale-helper.h
F: drivers/iio/industrialio-gts-helper.c
F: include/linux/iio/iio-gts-helper.h
IIO MULTIPLEXER
M: Peter Rosin <peda@axentia.se>
@ -12734,6 +12776,13 @@ S: Maintained
W: http://linux-test-project.github.io/
T: git https://github.com/linux-test-project/ltp.git
LTR390 AMBIENT/UV LIGHT SENSOR DRIVER
M: Anshul Dalal <anshulusr@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/light/liteon,ltr390.yaml
F: drivers/iio/light/ltr390.c
LYNX 28G SERDES PHY DRIVER
M: Ioana Ciornei <ioana.ciornei@nxp.com>
L: netdev@vger.kernel.org
@ -13278,6 +13327,13 @@ F: Documentation/ABI/testing/sysfs-bus-iio-potentiometer-mcp4531
F: drivers/iio/potentiometer/mcp4018.c
F: drivers/iio/potentiometer/mcp4531.c
MCP4821 DAC DRIVER
M: Anshul Dalal <anshulusr@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/dac/microchip,mcp4821.yaml
F: drivers/iio/dac/mcp4821.c
MCR20A IEEE-802.15.4 RADIO DRIVER
M: Stefan Schmidt <stefan@datenfreihafen.org>
L: linux-wpan@vger.kernel.org
@ -13805,6 +13861,13 @@ S: Supported
W: http://www.melexis.com
F: drivers/iio/temperature/mlx90632.c
MELEXIS MLX90635 DRIVER
M: Crt Mori <cmo@melexis.com>
L: linux-iio@vger.kernel.org
S: Supported
W: http://www.melexis.com
F: drivers/iio/temperature/mlx90635.c
MELFAS MIP4 TOUCHSCREEN DRIVER
M: Sangwon Jee <jeesw@melfas.com>
S: Supported
@ -14275,11 +14338,12 @@ F: Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt
F: drivers/regulator/mcp16502.c
MICROCHIP MCP3564 ADC DRIVER
M: Marius Cristea <marius.cristea@microchip.com>
L: linux-iio@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/iio/adc/microchip,mcp3564.yaml
F: drivers/iio/adc/mcp3564.c
M: Marius Cristea <marius.cristea@microchip.com>
L: linux-iio@vger.kernel.org
S: Supported
F: Documentation/ABI/testing/sysfs-bus-iio-adc-mcp3564
F: Documentation/devicetree/bindings/iio/adc/microchip,mcp3564.yaml
F: drivers/iio/adc/mcp3564.c
MICROCHIP MCP3911 ADC DRIVER
M: Marcus Folkesson <marcus.folkesson@gmail.com>
@ -15374,6 +15438,15 @@ F: include/linux/nitro_enclaves.h
F: include/uapi/linux/nitro_enclaves.h
F: samples/nitro_enclaves/
NITRO SECURE MODULE (NSM)
M: Alexander Graf <graf@amazon.com>
L: linux-kernel@vger.kernel.org
L: The AWS Nitro Enclaves Team <aws-nitro-enclaves-devel@amazon.com>
S: Supported
W: https://aws.amazon.com/ec2/nitro/nitro-enclaves/
F: drivers/misc/nsm.c
F: include/uapi/linux/nsm.h
NOHZ, DYNTICKS SUPPORT
M: Frederic Weisbecker <frederic@kernel.org>
M: Thomas Gleixner <tglx@linutronix.de>
@ -23288,6 +23361,12 @@ S: Maintained
F: drivers/input/serio/userio.c
F: include/uapi/linux/userio.h
VISHAY VEML6075 UVA AND UVB LIGHT SENSOR DRIVER
M: Javier Carrasco <javier.carrasco.cruz@gmail.com>
S: Maintained
F: Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml
F: drivers/iio/light/veml6075.c
VISL VIRTUAL STATELESS DECODER DRIVER
M: Daniel Almeida <daniel.almeida@collabora.com>
L: linux-media@vger.kernel.org

View File

@ -68,6 +68,8 @@ struct locomo {
#endif
};
static const struct bus_type locomo_bus_type;
struct locomo_dev_info {
unsigned long offset;
unsigned long length;
@ -842,7 +844,7 @@ static void locomo_bus_remove(struct device *dev)
drv->remove(ldev);
}
struct bus_type locomo_bus_type = {
static const struct bus_type locomo_bus_type = {
.name = "locomo-bus",
.match = locomo_match,
.probe = locomo_bus_probe,

View File

@ -158,8 +158,6 @@
#define LOCOMO_LPT_TOH(TOH) ((TOH & 0x7) << 4)
#define LOCOMO_LPT_TOL(TOL) ((TOL & 0x7))
extern struct bus_type locomo_bus_type;
#define LOCOMO_DEVID_KEYBOARD 0
#define LOCOMO_DEVID_FRONTLIGHT 1
#define LOCOMO_DEVID_BACKLIGHT 2

View File

@ -2077,9 +2077,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
* Convert the address to an offset relative to
* the base of the transaction buffer.
*/
fda_offset =
(parent->buffer - (uintptr_t)buffer->user_data) +
fda->parent_offset;
fda_offset = parent->buffer - buffer->user_data +
fda->parent_offset;
for (fd_index = 0; fd_index < fda->num_fds;
fd_index++) {
u32 fd;
@ -2597,7 +2596,7 @@ static int binder_translate_fd_array(struct list_head *pf_head,
* Convert the address to an offset relative to
* the base of the transaction buffer.
*/
fda_offset = (parent->buffer - (uintptr_t)t->buffer->user_data) +
fda_offset = parent->buffer - t->buffer->user_data +
fda->parent_offset;
sender_ufda_base = (void __user *)(uintptr_t)sender_uparent->buffer +
fda->parent_offset;
@ -2672,8 +2671,9 @@ static int binder_fixup_parent(struct list_head *pf_head,
proc->pid, thread->pid);
return -EINVAL;
}
buffer_offset = bp->parent_offset +
(uintptr_t)parent->buffer - (uintptr_t)b->user_data;
buffer_offset = bp->parent_offset + parent->buffer - b->user_data;
return binder_add_fixup(pf_head, buffer_offset, bp->buffer, 0);
}
@ -3225,7 +3225,7 @@ static void binder_transaction(struct binder_proc *proc,
t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
tr->offsets_size, extra_buffers_size,
!reply && (t->flags & TF_ONE_WAY), current->tgid);
!reply && (t->flags & TF_ONE_WAY));
if (IS_ERR(t->buffer)) {
char *s;
@ -3250,7 +3250,7 @@ static void binder_transaction(struct binder_proc *proc,
ALIGN(extra_buffers_size, sizeof(void *)) -
ALIGN(secctx_sz, sizeof(u64));
t->security_ctx = (uintptr_t)t->buffer->user_data + buf_offset;
t->security_ctx = t->buffer->user_data + buf_offset;
err = binder_alloc_copy_to_buffer(&target_proc->alloc,
t->buffer, buf_offset,
secctx, secctx_sz);
@ -3527,8 +3527,7 @@ static void binder_transaction(struct binder_proc *proc,
goto err_translate_failed;
}
/* Fixup buffer pointer to target proc address space */
bp->buffer = (uintptr_t)
t->buffer->user_data + sg_buf_offset;
bp->buffer = t->buffer->user_data + sg_buf_offset;
sg_buf_offset += ALIGN(bp->length, sizeof(u64));
num_valid = (buffer_offset - off_start_offset) /
@ -4698,7 +4697,7 @@ retry:
}
trd->data_size = t->buffer->data_size;
trd->offsets_size = t->buffer->offsets_size;
trd->data.ptr.buffer = (uintptr_t)t->buffer->user_data;
trd->data.ptr.buffer = t->buffer->user_data;
trd->data.ptr.offsets = trd->data.ptr.buffer +
ALIGN(t->buffer->data_size,
sizeof(void *));
@ -5030,7 +5029,7 @@ static __poll_t binder_poll(struct file *filp,
thread = binder_get_thread(proc);
if (!thread)
return POLLERR;
return EPOLLERR;
binder_inner_proc_lock(thread->proc);
thread->looper |= BINDER_LOOPER_STATE_POLL;
@ -5981,9 +5980,9 @@ static void print_binder_transaction_ilocked(struct seq_file *m,
}
if (buffer->target_node)
seq_printf(m, " node %d", buffer->target_node->debug_id);
seq_printf(m, " size %zd:%zd data %pK\n",
seq_printf(m, " size %zd:%zd offset %lx\n",
buffer->data_size, buffer->offsets_size,
buffer->user_data);
proc->alloc.buffer - buffer->user_data);
}
static void print_binder_work_ilocked(struct seq_file *m,

File diff suppressed because it is too large Load Diff

View File

@ -9,13 +9,13 @@
#include <linux/rbtree.h>
#include <linux/list.h>
#include <linux/mm.h>
#include <linux/rtmutex.h>
#include <linux/spinlock.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/list_lru.h>
#include <uapi/linux/android/binder.h>
extern struct list_lru binder_alloc_lru;
extern struct list_lru binder_freelist;
struct binder_transaction;
/**
@ -49,21 +49,19 @@ struct binder_buffer {
unsigned async_transaction:1;
unsigned oneway_spam_suspect:1;
unsigned debug_id:27;
struct binder_transaction *transaction;
struct binder_node *target_node;
size_t data_size;
size_t offsets_size;
size_t extra_buffers_size;
void __user *user_data;
int pid;
unsigned long user_data;
int pid;
};
/**
* struct binder_lru_page - page object used for binder shrinker
* @page_ptr: pointer to physical page in mmap'd space
* @lru: entry in binder_alloc_lru
* @lru: entry in binder_freelist
* @alloc: binder_alloc for a proc
*/
struct binder_lru_page {
@ -74,7 +72,7 @@ struct binder_lru_page {
/**
* struct binder_alloc - per-binder proc state for binder allocator
* @mutex: protects binder_alloc fields
* @lock: protects binder_alloc fields
* @vma: vm_area_struct passed to mmap_handler
* (invariant after mmap)
* @mm: copy of task->mm (invariant after open)
@ -98,10 +96,10 @@ struct binder_lru_page {
* struct binder_buffer objects used to track the user buffers
*/
struct binder_alloc {
struct mutex mutex;
spinlock_t lock;
struct vm_area_struct *vma;
struct mm_struct *mm;
void __user *buffer;
unsigned long buffer;
struct list_head buffers;
struct rb_root free_buffers;
struct rb_root allocated_buffers;
@ -121,27 +119,26 @@ static inline void binder_selftest_alloc(struct binder_alloc *alloc) {}
enum lru_status binder_alloc_free_page(struct list_head *item,
struct list_lru_one *lru,
spinlock_t *lock, void *cb_arg);
extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
size_t data_size,
size_t offsets_size,
size_t extra_buffers_size,
int is_async,
int pid);
extern void binder_alloc_init(struct binder_alloc *alloc);
extern int binder_alloc_shrinker_init(void);
extern void binder_alloc_shrinker_exit(void);
extern void binder_alloc_vma_close(struct binder_alloc *alloc);
extern struct binder_buffer *
struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
size_t data_size,
size_t offsets_size,
size_t extra_buffers_size,
int is_async);
void binder_alloc_init(struct binder_alloc *alloc);
int binder_alloc_shrinker_init(void);
void binder_alloc_shrinker_exit(void);
void binder_alloc_vma_close(struct binder_alloc *alloc);
struct binder_buffer *
binder_alloc_prepare_to_free(struct binder_alloc *alloc,
uintptr_t user_ptr);
extern void binder_alloc_free_buf(struct binder_alloc *alloc,
struct binder_buffer *buffer);
extern int binder_alloc_mmap_handler(struct binder_alloc *alloc,
struct vm_area_struct *vma);
extern void binder_alloc_deferred_release(struct binder_alloc *alloc);
extern int binder_alloc_get_allocated_count(struct binder_alloc *alloc);
extern void binder_alloc_print_allocated(struct seq_file *m,
struct binder_alloc *alloc);
unsigned long user_ptr);
void binder_alloc_free_buf(struct binder_alloc *alloc,
struct binder_buffer *buffer);
int binder_alloc_mmap_handler(struct binder_alloc *alloc,
struct vm_area_struct *vma);
void binder_alloc_deferred_release(struct binder_alloc *alloc);
int binder_alloc_get_allocated_count(struct binder_alloc *alloc);
void binder_alloc_print_allocated(struct seq_file *m,
struct binder_alloc *alloc);
void binder_alloc_print_pages(struct seq_file *m,
struct binder_alloc *alloc);
@ -156,9 +153,9 @@ binder_alloc_get_free_async_space(struct binder_alloc *alloc)
{
size_t free_async_space;
mutex_lock(&alloc->mutex);
spin_lock(&alloc->lock);
free_async_space = alloc->free_async_space;
mutex_unlock(&alloc->mutex);
spin_unlock(&alloc->lock);
return free_async_space;
}

View File

@ -72,6 +72,10 @@ enum buf_end_align_type {
* buf1 ]|[ buf2 | buf2 | buf2 ][ ...
*/
NEXT_NEXT_UNALIGNED,
/**
* @LOOP_END: The number of enum values in &buf_end_align_type.
* It is used for controlling loop termination.
*/
LOOP_END,
};
@ -93,11 +97,11 @@ static bool check_buffer_pages_allocated(struct binder_alloc *alloc,
struct binder_buffer *buffer,
size_t size)
{
void __user *page_addr;
void __user *end;
unsigned long page_addr;
unsigned long end;
int page_index;
end = (void __user *)PAGE_ALIGN((uintptr_t)buffer->user_data + size);
end = PAGE_ALIGN(buffer->user_data + size);
page_addr = buffer->user_data;
for (; page_addr < end; page_addr += PAGE_SIZE) {
page_index = (page_addr - alloc->buffer) / PAGE_SIZE;
@ -119,7 +123,7 @@ static void binder_selftest_alloc_buf(struct binder_alloc *alloc,
int i;
for (i = 0; i < BUFFER_NUM; i++) {
buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0, 0);
buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0);
if (IS_ERR(buffers[i]) ||
!check_buffer_pages_allocated(alloc, buffers[i],
sizes[i])) {
@ -158,8 +162,8 @@ static void binder_selftest_free_page(struct binder_alloc *alloc)
int i;
unsigned long count;
while ((count = list_lru_count(&binder_alloc_lru))) {
list_lru_walk(&binder_alloc_lru, binder_alloc_free_page,
while ((count = list_lru_count(&binder_freelist))) {
list_lru_walk(&binder_freelist, binder_alloc_free_page,
NULL, count);
}
@ -183,7 +187,7 @@ static void binder_selftest_alloc_free(struct binder_alloc *alloc,
/* Allocate from lru. */
binder_selftest_alloc_buf(alloc, buffers, sizes, seq);
if (list_lru_count(&binder_alloc_lru))
if (list_lru_count(&binder_freelist))
pr_err("lru list should be empty but is not\n");
binder_selftest_free_buf(alloc, buffers, sizes, seq, end);

View File

@ -317,7 +317,7 @@ DEFINE_EVENT(binder_buffer_class, binder_transaction_update_buffer_release,
TRACE_EVENT(binder_update_page_range,
TP_PROTO(struct binder_alloc *alloc, bool allocate,
void __user *start, void __user *end),
unsigned long start, unsigned long end),
TP_ARGS(alloc, allocate, start, end),
TP_STRUCT__entry(
__field(int, proc)

View File

@ -29,7 +29,6 @@
#include <linux/uaccess.h>
#include <linux/user_namespace.h>
#include <linux/xarray.h>
#include <uapi/asm-generic/errno-base.h>
#include <uapi/linux/android/binder.h>
#include <uapi/linux/android/binderfs.h>

View File

@ -473,7 +473,7 @@ int fwnode_property_match_string(const struct fwnode_handle *fwnode,
const char **values;
int nval, ret;
nval = fwnode_property_read_string_array(fwnode, propname, NULL, 0);
nval = fwnode_property_string_array_count(fwnode, propname);
if (nval < 0)
return nval;
@ -498,6 +498,41 @@ out_free:
}
EXPORT_SYMBOL_GPL(fwnode_property_match_string);
/**
* fwnode_property_match_property_string - find a property string value in an array and return index
* @fwnode: Firmware node to get the property of
* @propname: Name of the property holding the string value
* @array: String array to search in
* @n: Size of the @array
*
* Find a property string value in a given @array and if it is found return
* the index back.
*
* Return: index, starting from %0, if the string value was found in the @array (success),
* %-ENOENT when the string value was not found in the @array,
* %-EINVAL if given arguments are not valid,
* %-ENODATA if the property does not have a value,
* %-EPROTO or %-EILSEQ if the property is not a string,
* %-ENXIO if no suitable firmware interface is present.
*/
int fwnode_property_match_property_string(const struct fwnode_handle *fwnode,
const char *propname, const char * const *array, size_t n)
{
const char *string;
int ret;
ret = fwnode_property_read_string(fwnode, propname, &string);
if (ret)
return ret;
ret = match_string(array, n, string);
if (ret < 0)
ret = -ENOENT;
return ret;
}
EXPORT_SYMBOL_GPL(fwnode_property_match_property_string);
/**
* fwnode_property_get_reference_args() - Find a reference with arguments
* @fwnode: Firmware node where to look for the reference

View File

@ -126,6 +126,7 @@ struct mhi_ep_ring {
union mhi_ep_ring_ctx *ring_ctx;
struct mhi_ring_element *ring_cache;
enum mhi_ep_ring_type type;
struct delayed_work intmodt_work;
u64 rbase;
size_t rd_offset;
size_t wr_offset;
@ -135,7 +136,9 @@ struct mhi_ep_ring {
u32 ch_id;
u32 er_index;
u32 irq_vector;
u32 intmodt;
bool started;
bool irq_pending;
};
struct mhi_ep_cmd {
@ -159,6 +162,7 @@ struct mhi_ep_chan {
void (*xfer_cb)(struct mhi_ep_device *mhi_dev, struct mhi_result *result);
enum mhi_ch_state state;
enum dma_data_direction dir;
size_t rd_offset;
u64 tre_loc;
u32 tre_size;
u32 tre_bytes_left;

View File

@ -54,11 +54,27 @@ static int mhi_ep_send_event(struct mhi_ep_cntrl *mhi_cntrl, u32 ring_idx,
mutex_unlock(&mhi_cntrl->event_lock);
/*
* Raise IRQ to host only if the BEI flag is not set in TRE. Host might
* set this flag for interrupt moderation as per MHI protocol.
* As per the MHI specification, section 4.3, Interrupt moderation:
*
* 1. If BEI flag is not set, cancel any pending intmodt work if started
* for the event ring and raise IRQ immediately.
*
* 2. If both BEI and intmodt are set, and if no IRQ is pending for the
* same event ring, start the IRQ delayed work as per the value of
* intmodt. If previous IRQ is pending, then do nothing as the pending
* IRQ is enough for the host to process the current event ring element.
*
* 3. If BEI is set and intmodt is not set, no need to raise IRQ.
*/
if (!bei)
if (!bei) {
if (READ_ONCE(ring->irq_pending))
cancel_delayed_work(&ring->intmodt_work);
mhi_cntrl->raise_irq(mhi_cntrl, ring->irq_vector);
} else if (ring->intmodt && !READ_ONCE(ring->irq_pending)) {
WRITE_ONCE(ring->irq_pending, true);
schedule_delayed_work(&ring->intmodt_work, msecs_to_jiffies(ring->intmodt));
}
return 0;
@ -71,45 +87,77 @@ err_unlock:
static int mhi_ep_send_completion_event(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring,
struct mhi_ring_element *tre, u32 len, enum mhi_ev_ccs code)
{
struct mhi_ring_element event = {};
struct mhi_ring_element *event;
int ret;
event.ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(*tre));
event.dword[0] = MHI_TRE_EV_DWORD0(code, len);
event.dword[1] = MHI_TRE_EV_DWORD1(ring->ch_id, MHI_PKT_TYPE_TX_EVENT);
event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA);
if (!event)
return -ENOMEM;
return mhi_ep_send_event(mhi_cntrl, ring->er_index, &event, MHI_TRE_DATA_GET_BEI(tre));
event->ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(*tre));
event->dword[0] = MHI_TRE_EV_DWORD0(code, len);
event->dword[1] = MHI_TRE_EV_DWORD1(ring->ch_id, MHI_PKT_TYPE_TX_EVENT);
ret = mhi_ep_send_event(mhi_cntrl, ring->er_index, event, MHI_TRE_DATA_GET_BEI(tre));
kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event);
return ret;
}
int mhi_ep_send_state_change_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_state state)
{
struct mhi_ring_element event = {};
struct mhi_ring_element *event;
int ret;
event.dword[0] = MHI_SC_EV_DWORD0(state);
event.dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_STATE_CHANGE_EVENT);
event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA);
if (!event)
return -ENOMEM;
return mhi_ep_send_event(mhi_cntrl, 0, &event, 0);
event->dword[0] = MHI_SC_EV_DWORD0(state);
event->dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_STATE_CHANGE_EVENT);
ret = mhi_ep_send_event(mhi_cntrl, 0, event, 0);
kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event);
return ret;
}
int mhi_ep_send_ee_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_ee_type exec_env)
{
struct mhi_ring_element event = {};
struct mhi_ring_element *event;
int ret;
event.dword[0] = MHI_EE_EV_DWORD0(exec_env);
event.dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_EE_EVENT);
event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA);
if (!event)
return -ENOMEM;
return mhi_ep_send_event(mhi_cntrl, 0, &event, 0);
event->dword[0] = MHI_EE_EV_DWORD0(exec_env);
event->dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_EE_EVENT);
ret = mhi_ep_send_event(mhi_cntrl, 0, event, 0);
kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event);
return ret;
}
static int mhi_ep_send_cmd_comp_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_ev_ccs code)
{
struct mhi_ep_ring *ring = &mhi_cntrl->mhi_cmd->ring;
struct mhi_ring_element event = {};
struct mhi_ring_element *event;
int ret;
event.ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(struct mhi_ring_element));
event.dword[0] = MHI_CC_EV_DWORD0(code);
event.dword[1] = MHI_CC_EV_DWORD1(MHI_PKT_TYPE_CMD_COMPLETION_EVENT);
event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA);
if (!event)
return -ENOMEM;
return mhi_ep_send_event(mhi_cntrl, 0, &event, 0);
event->ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(struct mhi_ring_element));
event->dword[0] = MHI_CC_EV_DWORD0(code);
event->dword[1] = MHI_CC_EV_DWORD1(MHI_PKT_TYPE_CMD_COMPLETION_EVENT);
ret = mhi_ep_send_event(mhi_cntrl, 0, event, 0);
kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event);
return ret;
}
static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_element *el)
@ -151,6 +199,8 @@ static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_ele
goto err_unlock;
}
mhi_chan->rd_offset = ch_ring->rd_offset;
}
/* Set channel state to RUNNING */
@ -280,22 +330,85 @@ bool mhi_ep_queue_is_empty(struct mhi_ep_device *mhi_dev, enum dma_data_directio
struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl;
struct mhi_ep_ring *ring = &mhi_cntrl->mhi_chan[mhi_chan->chan].ring;
return !!(ring->rd_offset == ring->wr_offset);
return !!(mhi_chan->rd_offset == ring->wr_offset);
}
EXPORT_SYMBOL_GPL(mhi_ep_queue_is_empty);
static void mhi_ep_read_completion(struct mhi_ep_buf_info *buf_info)
{
struct mhi_ep_device *mhi_dev = buf_info->mhi_dev;
struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl;
struct mhi_ep_chan *mhi_chan = mhi_dev->ul_chan;
struct mhi_ep_ring *ring = &mhi_cntrl->mhi_chan[mhi_chan->chan].ring;
struct mhi_ring_element *el = &ring->ring_cache[ring->rd_offset];
struct mhi_result result = {};
int ret;
if (mhi_chan->xfer_cb) {
result.buf_addr = buf_info->cb_buf;
result.dir = mhi_chan->dir;
result.bytes_xferd = buf_info->size;
mhi_chan->xfer_cb(mhi_dev, &result);
}
/*
* The host will split the data packet into multiple TREs if it can't fit
* the packet in a single TRE. In that case, CHAIN flag will be set by the
* host for all TREs except the last one.
*/
if (buf_info->code != MHI_EV_CC_OVERFLOW) {
if (MHI_TRE_DATA_GET_CHAIN(el)) {
/*
* IEOB (Interrupt on End of Block) flag will be set by the host if
* it expects the completion event for all TREs of a TD.
*/
if (MHI_TRE_DATA_GET_IEOB(el)) {
ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el,
MHI_TRE_DATA_GET_LEN(el),
MHI_EV_CC_EOB);
if (ret < 0) {
dev_err(&mhi_chan->mhi_dev->dev,
"Error sending transfer compl. event\n");
goto err_free_tre_buf;
}
}
} else {
/*
* IEOT (Interrupt on End of Transfer) flag will be set by the host
* for the last TRE of the TD and expects the completion event for
* the same.
*/
if (MHI_TRE_DATA_GET_IEOT(el)) {
ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el,
MHI_TRE_DATA_GET_LEN(el),
MHI_EV_CC_EOT);
if (ret < 0) {
dev_err(&mhi_chan->mhi_dev->dev,
"Error sending transfer compl. event\n");
goto err_free_tre_buf;
}
}
}
}
mhi_ep_ring_inc_index(ring);
err_free_tre_buf:
kmem_cache_free(mhi_cntrl->tre_buf_cache, buf_info->cb_buf);
}
static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
struct mhi_ep_ring *ring,
struct mhi_result *result,
u32 len)
struct mhi_ep_ring *ring)
{
struct mhi_ep_chan *mhi_chan = &mhi_cntrl->mhi_chan[ring->ch_id];
struct device *dev = &mhi_cntrl->mhi_dev->dev;
size_t tr_len, read_offset, write_offset;
struct mhi_ep_buf_info buf_info = {};
u32 len = MHI_EP_DEFAULT_MTU;
struct mhi_ring_element *el;
bool tr_done = false;
void *write_addr;
u64 read_addr;
void *buf_addr;
u32 buf_left;
int ret;
@ -308,7 +421,7 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
return -ENODEV;
}
el = &ring->ring_cache[ring->rd_offset];
el = &ring->ring_cache[mhi_chan->rd_offset];
/* Check if there is data pending to be read from previous read operation */
if (mhi_chan->tre_bytes_left) {
@ -324,81 +437,51 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
read_offset = mhi_chan->tre_size - mhi_chan->tre_bytes_left;
write_offset = len - buf_left;
read_addr = mhi_chan->tre_loc + read_offset;
write_addr = result->buf_addr + write_offset;
buf_addr = kmem_cache_zalloc(mhi_cntrl->tre_buf_cache, GFP_KERNEL | GFP_DMA);
if (!buf_addr)
return -ENOMEM;
buf_info.host_addr = mhi_chan->tre_loc + read_offset;
buf_info.dev_addr = buf_addr + write_offset;
buf_info.size = tr_len;
buf_info.cb = mhi_ep_read_completion;
buf_info.cb_buf = buf_addr;
buf_info.mhi_dev = mhi_chan->mhi_dev;
if (mhi_chan->tre_bytes_left - tr_len)
buf_info.code = MHI_EV_CC_OVERFLOW;
dev_dbg(dev, "Reading %zd bytes from channel (%u)\n", tr_len, ring->ch_id);
ret = mhi_cntrl->read_from_host(mhi_cntrl, read_addr, write_addr, tr_len);
ret = mhi_cntrl->read_async(mhi_cntrl, &buf_info);
if (ret < 0) {
dev_err(&mhi_chan->mhi_dev->dev, "Error reading from channel\n");
return ret;
goto err_free_buf_addr;
}
buf_left -= tr_len;
mhi_chan->tre_bytes_left -= tr_len;
/*
* Once the TRE (Transfer Ring Element) of a TD (Transfer Descriptor) has been
* read completely:
*
* 1. Send completion event to the host based on the flags set in TRE.
* 2. Increment the local read offset of the transfer ring.
*/
if (!mhi_chan->tre_bytes_left) {
/*
* The host will split the data packet into multiple TREs if it can't fit
* the packet in a single TRE. In that case, CHAIN flag will be set by the
* host for all TREs except the last one.
*/
if (MHI_TRE_DATA_GET_CHAIN(el)) {
/*
* IEOB (Interrupt on End of Block) flag will be set by the host if
* it expects the completion event for all TREs of a TD.
*/
if (MHI_TRE_DATA_GET_IEOB(el)) {
ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el,
MHI_TRE_DATA_GET_LEN(el),
MHI_EV_CC_EOB);
if (ret < 0) {
dev_err(&mhi_chan->mhi_dev->dev,
"Error sending transfer compl. event\n");
return ret;
}
}
} else {
/*
* IEOT (Interrupt on End of Transfer) flag will be set by the host
* for the last TRE of the TD and expects the completion event for
* the same.
*/
if (MHI_TRE_DATA_GET_IEOT(el)) {
ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el,
MHI_TRE_DATA_GET_LEN(el),
MHI_EV_CC_EOT);
if (ret < 0) {
dev_err(&mhi_chan->mhi_dev->dev,
"Error sending transfer compl. event\n");
return ret;
}
}
if (MHI_TRE_DATA_GET_IEOT(el))
tr_done = true;
}
mhi_ep_ring_inc_index(ring);
mhi_chan->rd_offset = (mhi_chan->rd_offset + 1) % ring->ring_size;
}
result->bytes_xferd += tr_len;
} while (buf_left && !tr_done);
return 0;
err_free_buf_addr:
kmem_cache_free(mhi_cntrl->tre_buf_cache, buf_addr);
return ret;
}
static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring, struct mhi_ring_element *el)
static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring)
{
struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
struct mhi_result result = {};
u32 len = MHI_EP_DEFAULT_MTU;
struct mhi_ep_chan *mhi_chan;
int ret;
@ -419,44 +502,59 @@ static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring, struct mhi_ring_elem
mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
} else {
/* UL channel */
result.buf_addr = kzalloc(len, GFP_KERNEL);
if (!result.buf_addr)
return -ENOMEM;
do {
ret = mhi_ep_read_channel(mhi_cntrl, ring, &result, len);
ret = mhi_ep_read_channel(mhi_cntrl, ring);
if (ret < 0) {
dev_err(&mhi_chan->mhi_dev->dev, "Failed to read channel\n");
kfree(result.buf_addr);
return ret;
}
result.dir = mhi_chan->dir;
mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
result.bytes_xferd = 0;
memset(result.buf_addr, 0, len);
/* Read until the ring becomes empty */
} while (!mhi_ep_queue_is_empty(mhi_chan->mhi_dev, DMA_TO_DEVICE));
kfree(result.buf_addr);
}
return 0;
}
static void mhi_ep_skb_completion(struct mhi_ep_buf_info *buf_info)
{
struct mhi_ep_device *mhi_dev = buf_info->mhi_dev;
struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl;
struct mhi_ep_chan *mhi_chan = mhi_dev->dl_chan;
struct mhi_ep_ring *ring = &mhi_cntrl->mhi_chan[mhi_chan->chan].ring;
struct mhi_ring_element *el = &ring->ring_cache[ring->rd_offset];
struct device *dev = &mhi_dev->dev;
struct mhi_result result = {};
int ret;
if (mhi_chan->xfer_cb) {
result.buf_addr = buf_info->cb_buf;
result.dir = mhi_chan->dir;
result.bytes_xferd = buf_info->size;
mhi_chan->xfer_cb(mhi_dev, &result);
}
ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, buf_info->size,
buf_info->code);
if (ret) {
dev_err(dev, "Error sending transfer completion event\n");
return;
}
mhi_ep_ring_inc_index(ring);
}
/* TODO: Handle partially formed TDs */
int mhi_ep_queue_skb(struct mhi_ep_device *mhi_dev, struct sk_buff *skb)
{
struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl;
struct mhi_ep_chan *mhi_chan = mhi_dev->dl_chan;
struct device *dev = &mhi_chan->mhi_dev->dev;
struct mhi_ep_buf_info buf_info = {};
struct mhi_ring_element *el;
u32 buf_left, read_offset;
struct mhi_ep_ring *ring;
enum mhi_ev_ccs code;
void *read_addr;
u64 write_addr;
size_t tr_len;
u32 tre_len;
int ret;
@ -480,40 +578,44 @@ int mhi_ep_queue_skb(struct mhi_ep_device *mhi_dev, struct sk_buff *skb)
goto err_exit;
}
el = &ring->ring_cache[ring->rd_offset];
el = &ring->ring_cache[mhi_chan->rd_offset];
tre_len = MHI_TRE_DATA_GET_LEN(el);
tr_len = min(buf_left, tre_len);
read_offset = skb->len - buf_left;
read_addr = skb->data + read_offset;
write_addr = MHI_TRE_DATA_GET_PTR(el);
dev_dbg(dev, "Writing %zd bytes to channel (%u)\n", tr_len, ring->ch_id);
ret = mhi_cntrl->write_to_host(mhi_cntrl, read_addr, write_addr, tr_len);
if (ret < 0) {
dev_err(dev, "Error writing to the channel\n");
goto err_exit;
}
buf_info.dev_addr = skb->data + read_offset;
buf_info.host_addr = MHI_TRE_DATA_GET_PTR(el);
buf_info.size = tr_len;
buf_info.cb = mhi_ep_skb_completion;
buf_info.cb_buf = skb;
buf_info.mhi_dev = mhi_dev;
buf_left -= tr_len;
/*
* For all TREs queued by the host for DL channel, only the EOT flag will be set.
* If the packet doesn't fit into a single TRE, send the OVERFLOW event to
* the host so that the host can adjust the packet boundary to next TREs. Else send
* the EOT event to the host indicating the packet boundary.
*/
if (buf_left)
code = MHI_EV_CC_OVERFLOW;
if (buf_left - tr_len)
buf_info.code = MHI_EV_CC_OVERFLOW;
else
code = MHI_EV_CC_EOT;
buf_info.code = MHI_EV_CC_EOT;
ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, tr_len, code);
if (ret) {
dev_err(dev, "Error sending transfer completion event\n");
dev_dbg(dev, "Writing %zd bytes to channel (%u)\n", tr_len, ring->ch_id);
ret = mhi_cntrl->write_async(mhi_cntrl, &buf_info);
if (ret < 0) {
dev_err(dev, "Error writing to the channel\n");
goto err_exit;
}
mhi_ep_ring_inc_index(ring);
buf_left -= tr_len;
/*
* Update the read offset cached in mhi_chan. Actual read offset
* will be updated by the completion handler.
*/
mhi_chan->rd_offset = (mhi_chan->rd_offset + 1) % ring->ring_size;
} while (buf_left);
mutex_unlock(&mhi_chan->lock);
@ -714,7 +816,6 @@ static void mhi_ep_ch_ring_worker(struct work_struct *work)
struct mhi_ep_cntrl *mhi_cntrl = container_of(work, struct mhi_ep_cntrl, ch_ring_work);
struct device *dev = &mhi_cntrl->mhi_dev->dev;
struct mhi_ep_ring_item *itr, *tmp;
struct mhi_ring_element *el;
struct mhi_ep_ring *ring;
struct mhi_ep_chan *chan;
unsigned long flags;
@ -748,31 +849,29 @@ static void mhi_ep_ch_ring_worker(struct work_struct *work)
if (ret) {
dev_err(dev, "Error updating write offset for ring\n");
mutex_unlock(&chan->lock);
kfree(itr);
kmem_cache_free(mhi_cntrl->ring_item_cache, itr);
continue;
}
/* Sanity check to make sure there are elements in the ring */
if (ring->rd_offset == ring->wr_offset) {
if (chan->rd_offset == ring->wr_offset) {
mutex_unlock(&chan->lock);
kfree(itr);
kmem_cache_free(mhi_cntrl->ring_item_cache, itr);
continue;
}
el = &ring->ring_cache[ring->rd_offset];
dev_dbg(dev, "Processing the ring for channel (%u)\n", ring->ch_id);
ret = mhi_ep_process_ch_ring(ring, el);
ret = mhi_ep_process_ch_ring(ring);
if (ret) {
dev_err(dev, "Error processing ring for channel (%u): %d\n",
ring->ch_id, ret);
mutex_unlock(&chan->lock);
kfree(itr);
kmem_cache_free(mhi_cntrl->ring_item_cache, itr);
continue;
}
mutex_unlock(&chan->lock);
kfree(itr);
kmem_cache_free(mhi_cntrl->ring_item_cache, itr);
}
}
@ -828,7 +927,7 @@ static void mhi_ep_queue_channel_db(struct mhi_ep_cntrl *mhi_cntrl, unsigned lon
u32 ch_id = ch_idx + i;
ring = &mhi_cntrl->mhi_chan[ch_id].ring;
item = kzalloc(sizeof(*item), GFP_ATOMIC);
item = kmem_cache_zalloc(mhi_cntrl->ring_item_cache, GFP_ATOMIC);
if (!item)
return;
@ -1365,6 +1464,10 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl,
if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->mmio || !mhi_cntrl->irq)
return -EINVAL;
if (!mhi_cntrl->read_sync || !mhi_cntrl->write_sync ||
!mhi_cntrl->read_async || !mhi_cntrl->write_async)
return -EINVAL;
ret = mhi_ep_chan_init(mhi_cntrl, config);
if (ret)
return ret;
@ -1375,6 +1478,29 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl,
goto err_free_ch;
}
mhi_cntrl->ev_ring_el_cache = kmem_cache_create("mhi_ep_event_ring_el",
sizeof(struct mhi_ring_element), 0,
SLAB_CACHE_DMA, NULL);
if (!mhi_cntrl->ev_ring_el_cache) {
ret = -ENOMEM;
goto err_free_cmd;
}
mhi_cntrl->tre_buf_cache = kmem_cache_create("mhi_ep_tre_buf", MHI_EP_DEFAULT_MTU, 0,
SLAB_CACHE_DMA, NULL);
if (!mhi_cntrl->tre_buf_cache) {
ret = -ENOMEM;
goto err_destroy_ev_ring_el_cache;
}
mhi_cntrl->ring_item_cache = kmem_cache_create("mhi_ep_ring_item",
sizeof(struct mhi_ep_ring_item), 0,
0, NULL);
if (!mhi_cntrl->ev_ring_el_cache) {
ret = -ENOMEM;
goto err_destroy_tre_buf_cache;
}
INIT_WORK(&mhi_cntrl->state_work, mhi_ep_state_worker);
INIT_WORK(&mhi_cntrl->reset_work, mhi_ep_reset_worker);
INIT_WORK(&mhi_cntrl->cmd_ring_work, mhi_ep_cmd_ring_worker);
@ -1383,7 +1509,7 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl,
mhi_cntrl->wq = alloc_workqueue("mhi_ep_wq", 0, 0);
if (!mhi_cntrl->wq) {
ret = -ENOMEM;
goto err_free_cmd;
goto err_destroy_ring_item_cache;
}
INIT_LIST_HEAD(&mhi_cntrl->st_transition_list);
@ -1442,6 +1568,12 @@ err_ida_free:
ida_free(&mhi_ep_cntrl_ida, mhi_cntrl->index);
err_destroy_wq:
destroy_workqueue(mhi_cntrl->wq);
err_destroy_ring_item_cache:
kmem_cache_destroy(mhi_cntrl->ring_item_cache);
err_destroy_ev_ring_el_cache:
kmem_cache_destroy(mhi_cntrl->ev_ring_el_cache);
err_destroy_tre_buf_cache:
kmem_cache_destroy(mhi_cntrl->tre_buf_cache);
err_free_cmd:
kfree(mhi_cntrl->mhi_cmd);
err_free_ch:
@ -1463,6 +1595,9 @@ void mhi_ep_unregister_controller(struct mhi_ep_cntrl *mhi_cntrl)
free_irq(mhi_cntrl->irq, mhi_cntrl);
kmem_cache_destroy(mhi_cntrl->tre_buf_cache);
kmem_cache_destroy(mhi_cntrl->ev_ring_el_cache);
kmem_cache_destroy(mhi_cntrl->ring_item_cache);
kfree(mhi_cntrl->mhi_cmd);
kfree(mhi_cntrl->mhi_chan);

View File

@ -30,7 +30,8 @@ static int __mhi_ep_cache_ring(struct mhi_ep_ring *ring, size_t end)
{
struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
size_t start, copy_size;
struct mhi_ep_buf_info buf_info = {};
size_t start;
int ret;
/* Don't proceed in the case of event ring. This happens during mhi_ep_ring_start(). */
@ -43,30 +44,34 @@ static int __mhi_ep_cache_ring(struct mhi_ep_ring *ring, size_t end)
start = ring->wr_offset;
if (start < end) {
copy_size = (end - start) * sizeof(struct mhi_ring_element);
ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase +
(start * sizeof(struct mhi_ring_element)),
&ring->ring_cache[start], copy_size);
buf_info.size = (end - start) * sizeof(struct mhi_ring_element);
buf_info.host_addr = ring->rbase + (start * sizeof(struct mhi_ring_element));
buf_info.dev_addr = &ring->ring_cache[start];
ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info);
if (ret < 0)
return ret;
} else {
copy_size = (ring->ring_size - start) * sizeof(struct mhi_ring_element);
ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase +
(start * sizeof(struct mhi_ring_element)),
&ring->ring_cache[start], copy_size);
buf_info.size = (ring->ring_size - start) * sizeof(struct mhi_ring_element);
buf_info.host_addr = ring->rbase + (start * sizeof(struct mhi_ring_element));
buf_info.dev_addr = &ring->ring_cache[start];
ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info);
if (ret < 0)
return ret;
if (end) {
ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase,
&ring->ring_cache[0],
end * sizeof(struct mhi_ring_element));
buf_info.host_addr = ring->rbase;
buf_info.dev_addr = &ring->ring_cache[0];
buf_info.size = end * sizeof(struct mhi_ring_element);
ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info);
if (ret < 0)
return ret;
}
}
dev_dbg(dev, "Cached ring: start %zu end %zu size %zu\n", start, end, copy_size);
dev_dbg(dev, "Cached ring: start %zu end %zu size %zu\n", start, end, buf_info.size);
return 0;
}
@ -102,6 +107,7 @@ int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *e
{
struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
struct mhi_ep_buf_info buf_info = {};
size_t old_offset = 0;
u32 num_free_elem;
__le64 rp;
@ -133,12 +139,11 @@ int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *e
rp = cpu_to_le64(ring->rd_offset * sizeof(*el) + ring->rbase);
memcpy_toio((void __iomem *) &ring->ring_ctx->generic.rp, &rp, sizeof(u64));
ret = mhi_cntrl->write_to_host(mhi_cntrl, el, ring->rbase + (old_offset * sizeof(*el)),
sizeof(*el));
if (ret < 0)
return ret;
buf_info.host_addr = ring->rbase + (old_offset * sizeof(*el));
buf_info.dev_addr = el;
buf_info.size = sizeof(*el);
return 0;
return mhi_cntrl->write_sync(mhi_cntrl, &buf_info);
}
void mhi_ep_ring_init(struct mhi_ep_ring *ring, enum mhi_ep_ring_type type, u32 id)
@ -157,6 +162,15 @@ void mhi_ep_ring_init(struct mhi_ep_ring *ring, enum mhi_ep_ring_type type, u32
}
}
static void mhi_ep_raise_irq(struct work_struct *work)
{
struct mhi_ep_ring *ring = container_of(work, struct mhi_ep_ring, intmodt_work.work);
struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
mhi_cntrl->raise_irq(mhi_cntrl, ring->irq_vector);
WRITE_ONCE(ring->irq_pending, false);
}
int mhi_ep_ring_start(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring,
union mhi_ep_ring_ctx *ctx)
{
@ -173,8 +187,13 @@ int mhi_ep_ring_start(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring,
if (ring->type == RING_TYPE_CH)
ring->er_index = le32_to_cpu(ring->ring_ctx->ch.erindex);
if (ring->type == RING_TYPE_ER)
if (ring->type == RING_TYPE_ER) {
ring->irq_vector = le32_to_cpu(ring->ring_ctx->ev.msivec);
ring->intmodt = FIELD_GET(EV_CTX_INTMODT_MASK,
le32_to_cpu(ring->ring_ctx->ev.intmod));
INIT_DELAYED_WORK(&ring->intmodt_work, mhi_ep_raise_irq);
}
/* During ring init, both rp and wp are equal */
memcpy_fromio(&val, (void __iomem *) &ring->ring_ctx->generic.rp, sizeof(u64));
@ -201,6 +220,9 @@ int mhi_ep_ring_start(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring,
void mhi_ep_ring_reset(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring)
{
if (ring->type == RING_TYPE_ER)
cancel_delayed_work_sync(&ring->intmodt_work);
ring->started = false;
kfree(ring->ring_cache);
ring->ring_cache = NULL;

View File

@ -881,6 +881,7 @@ static int parse_config(struct mhi_controller *mhi_cntrl,
if (!mhi_cntrl->timeout_ms)
mhi_cntrl->timeout_ms = MHI_TIMEOUT_MS;
mhi_cntrl->ready_timeout_ms = config->ready_timeout_ms;
mhi_cntrl->bounce_buf = config->use_bounce_buf;
mhi_cntrl->buffer_len = config->buf_len;
if (!mhi_cntrl->buffer_len)

View File

@ -321,7 +321,7 @@ int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl,
u32 *out);
int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl,
void __iomem *base, u32 offset, u32 mask,
u32 val, u32 delayus);
u32 val, u32 delayus, u32 timeout_ms);
void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base,
u32 offset, u32 val);
int __must_check mhi_write_reg_field(struct mhi_controller *mhi_cntrl,

View File

@ -40,10 +40,11 @@ int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl,
int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl,
void __iomem *base, u32 offset,
u32 mask, u32 val, u32 delayus)
u32 mask, u32 val, u32 delayus,
u32 timeout_ms)
{
int ret;
u32 out, retry = (mhi_cntrl->timeout_ms * 1000) / delayus;
u32 out, retry = (timeout_ms * 1000) / delayus;
while (retry--) {
ret = mhi_read_reg_field(mhi_cntrl, base, offset, mask, &out);
@ -268,7 +269,8 @@ static void mhi_del_ring_element(struct mhi_controller *mhi_cntrl,
static bool is_valid_ring_ptr(struct mhi_ring *ring, dma_addr_t addr)
{
return addr >= ring->iommu_base && addr < ring->iommu_base + ring->len;
return addr >= ring->iommu_base && addr < ring->iommu_base + ring->len &&
!(addr & (sizeof(struct mhi_ring_element) - 1));
}
int mhi_destroy_device(struct device *dev, void *data)
@ -642,6 +644,8 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
mhi_del_ring_element(mhi_cntrl, tre_ring);
local_rp = tre_ring->rp;
read_unlock_bh(&mhi_chan->lock);
/* notify client */
mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
@ -667,6 +671,8 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
kfree(buf_info->cb_buf);
}
}
read_lock_bh(&mhi_chan->lock);
}
break;
} /* CC_EOT */
@ -1122,17 +1128,15 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info,
if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)))
return -EIO;
read_lock_irqsave(&mhi_cntrl->pm_lock, flags);
ret = mhi_is_ring_full(mhi_cntrl, tre_ring);
if (unlikely(ret)) {
ret = -EAGAIN;
goto exit_unlock;
}
if (unlikely(ret))
return -EAGAIN;
ret = mhi_gen_tre(mhi_cntrl, mhi_chan, buf_info, mflags);
if (unlikely(ret))
goto exit_unlock;
return ret;
read_lock_irqsave(&mhi_cntrl->pm_lock, flags);
/* Packet is queued, take a usage ref to exit M3 if necessary
* for host->device buffer, balanced put is done on buffer completion
@ -1152,7 +1156,6 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info,
if (dir == DMA_FROM_DEVICE)
mhi_cntrl->runtime_put(mhi_cntrl);
exit_unlock:
read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags);
return ret;
@ -1204,6 +1207,9 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
int eot, eob, chain, bei;
int ret;
/* Protect accesses for reading and incrementing WP */
write_lock_bh(&mhi_chan->lock);
buf_ring = &mhi_chan->buf_ring;
tre_ring = &mhi_chan->tre_ring;
@ -1221,8 +1227,10 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
if (!info->pre_mapped) {
ret = mhi_cntrl->map_single(mhi_cntrl, buf_info);
if (ret)
if (ret) {
write_unlock_bh(&mhi_chan->lock);
return ret;
}
}
eob = !!(flags & MHI_EOB);
@ -1239,6 +1247,8 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
mhi_add_ring_element(mhi_cntrl, tre_ring);
mhi_add_ring_element(mhi_cntrl, buf_ring);
write_unlock_bh(&mhi_chan->lock);
return 0;
}

View File

@ -269,6 +269,16 @@ static struct mhi_event_config modem_qcom_v1_mhi_events[] = {
MHI_EVENT_CONFIG_HW_DATA(5, 2048, 101)
};
static const struct mhi_controller_config modem_qcom_v2_mhiv_config = {
.max_channels = 128,
.timeout_ms = 8000,
.ready_timeout_ms = 50000,
.num_channels = ARRAY_SIZE(modem_qcom_v1_mhi_channels),
.ch_cfg = modem_qcom_v1_mhi_channels,
.num_events = ARRAY_SIZE(modem_qcom_v1_mhi_events),
.event_cfg = modem_qcom_v1_mhi_events,
};
static const struct mhi_controller_config modem_qcom_v1_mhiv_config = {
.max_channels = 128,
.timeout_ms = 8000,
@ -278,6 +288,16 @@ static const struct mhi_controller_config modem_qcom_v1_mhiv_config = {
.event_cfg = modem_qcom_v1_mhi_events,
};
static const struct mhi_pci_dev_info mhi_qcom_sdx75_info = {
.name = "qcom-sdx75m",
.fw = "qcom/sdx75m/xbl.elf",
.edl = "qcom/sdx75m/edl.mbn",
.config = &modem_qcom_v2_mhiv_config,
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
.dma_data_width = 32,
.sideband_wake = false,
};
static const struct mhi_pci_dev_info mhi_qcom_sdx65_info = {
.name = "qcom-sdx65m",
.fw = "qcom/sdx65m/xbl.elf",
@ -600,6 +620,8 @@ static const struct pci_device_id mhi_pci_id_table[] = {
.driver_data = (kernel_ulong_t) &mhi_telit_fn990_info },
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308),
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info },
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0309),
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx75_info },
{ PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1001), /* EM120R-GL (sdx24) */
.driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info },
{ PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1002), /* EM160R-GL (sdx24) */

View File

@ -163,6 +163,7 @@ int mhi_ready_state_transition(struct mhi_controller *mhi_cntrl)
enum mhi_pm_state cur_state;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
u32 interval_us = 25000; /* poll register field every 25 milliseconds */
u32 timeout_ms;
int ret, i;
/* Check if device entered error state */
@ -173,14 +174,18 @@ int mhi_ready_state_transition(struct mhi_controller *mhi_cntrl)
/* Wait for RESET to be cleared and READY bit to be set by the device */
ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
MHICTRL_RESET_MASK, 0, interval_us);
MHICTRL_RESET_MASK, 0, interval_us,
mhi_cntrl->timeout_ms);
if (ret) {
dev_err(dev, "Device failed to clear MHI Reset\n");
return ret;
}
timeout_ms = mhi_cntrl->ready_timeout_ms ?
mhi_cntrl->ready_timeout_ms : mhi_cntrl->timeout_ms;
ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHISTATUS,
MHISTATUS_READY_MASK, 1, interval_us);
MHISTATUS_READY_MASK, 1, interval_us,
timeout_ms);
if (ret) {
dev_err(dev, "Device failed to enter MHI Ready\n");
return ret;
@ -479,7 +484,7 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl)
/* Wait for the reset bit to be cleared by the device */
ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
MHICTRL_RESET_MASK, 0, 25000);
MHICTRL_RESET_MASK, 0, 25000, mhi_cntrl->timeout_ms);
if (ret)
dev_err(dev, "Device failed to clear MHI Reset\n");
@ -492,8 +497,8 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl)
if (!MHI_IN_PBL(mhi_get_exec_env(mhi_cntrl))) {
/* wait for ready to be set */
ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs,
MHISTATUS,
MHISTATUS_READY_MASK, 1, 25000);
MHISTATUS, MHISTATUS_READY_MASK,
1, 25000, mhi_cntrl->timeout_ms);
if (ret)
dev_err(dev, "Device failed to enter READY state\n");
}
@ -1111,7 +1116,8 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl)
if (state == MHI_STATE_SYS_ERR) {
mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET);
ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
MHICTRL_RESET_MASK, 0, interval_us);
MHICTRL_RESET_MASK, 0, interval_us,
mhi_cntrl->timeout_ms);
if (ret) {
dev_info(dev, "Failed to reset MHI due to syserr state\n");
goto error_exit;
@ -1202,14 +1208,18 @@ EXPORT_SYMBOL_GPL(mhi_power_down);
int mhi_sync_power_up(struct mhi_controller *mhi_cntrl)
{
int ret = mhi_async_power_up(mhi_cntrl);
u32 timeout_ms;
if (ret)
return ret;
/* Some devices need more time to set ready during power up */
timeout_ms = mhi_cntrl->ready_timeout_ms ?
mhi_cntrl->ready_timeout_ms : mhi_cntrl->timeout_ms;
wait_event_timeout(mhi_cntrl->state_event,
MHI_IN_MISSION_MODE(mhi_cntrl->ee) ||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
msecs_to_jiffies(mhi_cntrl->timeout_ms));
msecs_to_jiffies(timeout_ms));
ret = (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -ETIMEDOUT;
if (ret)

View File

@ -102,7 +102,7 @@ static int moxtet_match(struct device *dev, struct device_driver *drv)
return 0;
}
static struct bus_type moxtet_bus_type = {
static const struct bus_type moxtet_bus_type = {
.name = "moxtet",
.dev_groups = moxtet_dev_groups,
.match = moxtet_match,

View File

@ -57,13 +57,17 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/idr.h>
#include <linux/cdx/cdx_bus.h>
#include <linux/iommu.h>
#include <linux/dma-map-ops.h>
#include <linux/debugfs.h>
#include "cdx.h"
/* Default DMA mask for devices on a CDX bus */
@ -74,9 +78,13 @@
static DEFINE_IDA(cdx_controller_ida);
/* Lock to protect controller ops */
static DEFINE_MUTEX(cdx_controller_lock);
/* Debugfs dir for cdx bus */
static struct dentry *cdx_debugfs_dir;
static char *compat_node_name = "xlnx,versal-net-cdx";
static void cdx_destroy_res_attr(struct cdx_device *cdx_dev, int num);
/**
* cdx_dev_reset - Reset a CDX device
* @dev: CDX device
@ -145,6 +153,8 @@ static int cdx_unregister_device(struct device *dev,
if (cdx_dev->enabled && cdx->ops->bus_disable)
cdx->ops->bus_disable(cdx, cdx_dev->bus_num);
} else {
cdx_destroy_res_attr(cdx_dev, MAX_CDX_DEV_RESOURCES);
debugfs_remove_recursive(cdx_dev->debugfs_dir);
kfree(cdx_dev->driver_override);
cdx_dev->driver_override = NULL;
}
@ -548,6 +558,31 @@ static const struct attribute_group *cdx_dev_groups[] = {
NULL,
};
static int cdx_debug_resource_show(struct seq_file *s, void *data)
{
struct cdx_device *cdx_dev = s->private;
int i;
for (i = 0; i < MAX_CDX_DEV_RESOURCES; i++) {
struct resource *res = &cdx_dev->res[i];
seq_printf(s, "%pr\n", res);
}
return 0;
}
DEFINE_SHOW_ATTRIBUTE(cdx_debug_resource);
static void cdx_device_debugfs_init(struct cdx_device *cdx_dev)
{
cdx_dev->debugfs_dir = debugfs_create_dir(dev_name(&cdx_dev->dev), cdx_debugfs_dir);
if (IS_ERR(cdx_dev->debugfs_dir))
return;
debugfs_create_file("resource", 0444, cdx_dev->debugfs_dir, cdx_dev,
&cdx_debug_resource_fops);
}
static ssize_t rescan_store(const struct bus_type *bus,
const char *buf, size_t count)
{
@ -569,12 +604,12 @@ static ssize_t rescan_store(const struct bus_type *bus,
/* Rescan all the devices */
for_each_compatible_node(np, NULL, compat_node_name) {
if (!np)
return -EINVAL;
pd = of_find_device_by_node(np);
if (!pd)
return -EINVAL;
if (!pd) {
of_node_put(np);
count = -EINVAL;
goto unlock;
}
cdx = platform_get_drvdata(pd);
if (cdx && cdx->controller_registered && cdx->ops->scan)
@ -583,6 +618,7 @@ static ssize_t rescan_store(const struct bus_type *bus,
put_device(&pd->dev);
}
unlock:
mutex_unlock(&cdx_controller_lock);
return count;
@ -640,11 +676,105 @@ static void cdx_device_release(struct device *dev)
kfree(cdx_dev);
}
static const struct vm_operations_struct cdx_phys_vm_ops = {
#ifdef CONFIG_HAVE_IOREMAP_PROT
.access = generic_access_phys,
#endif
};
/**
* cdx_mmap_resource - map a CDX resource into user memory space
* @fp: File pointer. Not used in this function, but required where
* this API is registered as a callback.
* @kobj: kobject for mapping
* @attr: struct bin_attribute for the file being mapped
* @vma: struct vm_area_struct passed into the mmap
*
* Use the regular CDX mapping routines to map a CDX resource into userspace.
*
* Return: true on success, false otherwise.
*/
static int cdx_mmap_resource(struct file *fp, struct kobject *kobj,
struct bin_attribute *attr,
struct vm_area_struct *vma)
{
struct cdx_device *cdx_dev = to_cdx_device(kobj_to_dev(kobj));
int num = (unsigned long)attr->private;
struct resource *res;
unsigned long size;
res = &cdx_dev->res[num];
if (iomem_is_exclusive(res->start))
return -EINVAL;
/* Make sure the caller is mapping a valid resource for this device */
size = ((cdx_resource_len(cdx_dev, num) - 1) >> PAGE_SHIFT) + 1;
if (vma->vm_pgoff + vma_pages(vma) > size)
return -EINVAL;
/*
* Map memory region and vm->vm_pgoff is expected to be an
* offset within that region.
*/
vma->vm_page_prot = pgprot_device(vma->vm_page_prot);
vma->vm_pgoff += (cdx_resource_start(cdx_dev, num) >> PAGE_SHIFT);
vma->vm_ops = &cdx_phys_vm_ops;
return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
}
static void cdx_destroy_res_attr(struct cdx_device *cdx_dev, int num)
{
int i;
/* removing the bin attributes */
for (i = 0; i < num; i++) {
struct bin_attribute *res_attr;
res_attr = cdx_dev->res_attr[i];
if (res_attr) {
sysfs_remove_bin_file(&cdx_dev->dev.kobj, res_attr);
kfree(res_attr);
}
}
}
#define CDX_RES_ATTR_NAME_LEN 10
static int cdx_create_res_attr(struct cdx_device *cdx_dev, int num)
{
struct bin_attribute *res_attr;
char *res_attr_name;
int ret;
res_attr = kzalloc(sizeof(*res_attr) + CDX_RES_ATTR_NAME_LEN, GFP_ATOMIC);
if (!res_attr)
return -ENOMEM;
res_attr_name = (char *)(res_attr + 1);
sysfs_bin_attr_init(res_attr);
cdx_dev->res_attr[num] = res_attr;
sprintf(res_attr_name, "resource%d", num);
res_attr->mmap = cdx_mmap_resource;
res_attr->attr.name = res_attr_name;
res_attr->attr.mode = 0600;
res_attr->size = cdx_resource_len(cdx_dev, num);
res_attr->private = (void *)(unsigned long)num;
ret = sysfs_create_bin_file(&cdx_dev->dev.kobj, res_attr);
if (ret)
kfree(res_attr);
return ret;
}
int cdx_device_add(struct cdx_dev_params *dev_params)
{
struct cdx_controller *cdx = dev_params->cdx;
struct cdx_device *cdx_dev;
int ret;
int ret, i;
cdx_dev = kzalloc(sizeof(*cdx_dev), GFP_KERNEL);
if (!cdx_dev)
@ -687,7 +817,28 @@ int cdx_device_add(struct cdx_dev_params *dev_params)
goto fail;
}
/* Create resource<N> attributes */
for (i = 0; i < MAX_CDX_DEV_RESOURCES; i++) {
if (cdx_resource_flags(cdx_dev, i) & IORESOURCE_MEM) {
/* skip empty resources */
if (!cdx_resource_len(cdx_dev, i))
continue;
ret = cdx_create_res_attr(cdx_dev, i);
if (ret != 0) {
dev_err(&cdx_dev->dev,
"cdx device resource<%d> file creation failed: %d", i, ret);
goto resource_create_fail;
}
}
}
cdx_device_debugfs_init(cdx_dev);
return 0;
resource_create_fail:
cdx_destroy_res_attr(cdx_dev, i);
device_del(&cdx_dev->dev);
fail:
/*
* Do not free cdx_dev here as it would be freed in
@ -788,6 +939,12 @@ EXPORT_SYMBOL_NS_GPL(cdx_unregister_controller, CDX_BUS_CONTROLLER);
static int __init cdx_bus_init(void)
{
return bus_register(&cdx_bus_type);
int ret;
ret = bus_register(&cdx_bus_type);
if (!ret)
cdx_debugfs_dir = debugfs_create_dir(cdx_bus_type.name, NULL);
return ret;
}
postcore_initcall(cdx_bus_init);

View File

@ -299,7 +299,7 @@ static int register_device(int minor, struct pp_struct *pp)
goto err;
}
index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL);
index = ida_alloc(&ida_index, GFP_KERNEL);
memset(&ppdev_cb, 0, sizeof(ppdev_cb));
ppdev_cb.irq_func = pp_irq;
ppdev_cb.flags = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
@ -310,7 +310,7 @@ static int register_device(int minor, struct pp_struct *pp)
if (!pdev) {
pr_warn("%s: failed to register device!\n", name);
rc = -ENXIO;
ida_simple_remove(&ida_index, index);
ida_free(&ida_index, index);
goto err;
}
@ -750,7 +750,7 @@ static int pp_release(struct inode *inode, struct file *file)
if (pp->pdev) {
parport_unregister_device(pp->pdev);
ida_simple_remove(&ida_index, pp->index);
ida_free(&ida_index, pp->index);
pp->pdev = NULL;
pr_debug(CHRDEV "%x: unregistered pardevice\n", minor);
}

View File

@ -1714,8 +1714,8 @@ static int __comedi_get_user_chanlist(struct comedi_device *dev,
lockdep_assert_held(&dev->mutex);
cmd->chanlist = NULL;
chanlist = memdup_user(user_chanlist,
cmd->chanlist_len * sizeof(unsigned int));
chanlist = memdup_array_user(user_chanlist,
cmd->chanlist_len, sizeof(unsigned int));
if (IS_ERR(chanlist))
return PTR_ERR(chanlist);

View File

@ -1005,7 +1005,7 @@ static int mc_probe(struct platform_device *pdev)
goto free_edac_mc;
}
rc = xlnx_register_event(PM_NOTIFY_CB, EVENT_ERROR_PMC_ERR1,
rc = xlnx_register_event(PM_NOTIFY_CB, VERSAL_EVENT_ERROR_PMC_ERR1,
XPM_EVENT_ERROR_MASK_DDRMC_CR | XPM_EVENT_ERROR_MASK_DDRMC_NCR |
XPM_EVENT_ERROR_MASK_NOC_CR | XPM_EVENT_ERROR_MASK_NOC_NCR,
false, err_callback, mci);
@ -1042,7 +1042,7 @@ static int mc_remove(struct platform_device *pdev)
debugfs_remove_recursive(priv->debugfs);
#endif
xlnx_unregister_event(PM_NOTIFY_CB, EVENT_ERROR_PMC_ERR1,
xlnx_unregister_event(PM_NOTIFY_CB, VERSAL_EVENT_ERROR_PMC_ERR1,
XPM_EVENT_ERROR_MASK_DDRMC_CR |
XPM_EVENT_ERROR_MASK_NOC_CR |
XPM_EVENT_ERROR_MASK_NOC_NCR |

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
/*
* extcon-qcom-spmi-misc.c - Qualcomm USB extcon driver to support USB ID
* and VBUS detection based on extcon-usb-gpio.c.
*

View File

@ -17,6 +17,7 @@
#include <linux/usb/typec.h>
#include <linux/usb/typec_altmode.h>
#include <linux/usb/role.h>
#include <linux/irq.h>
#define TUSB320_REG8 0x8
#define TUSB320_REG8_CURRENT_MODE_ADVERTISE GENMASK(7, 6)
@ -515,6 +516,8 @@ static int tusb320_probe(struct i2c_client *client)
const void *match_data;
unsigned int revision;
int ret;
u32 irq_trigger_type = IRQF_TRIGGER_FALLING;
struct irq_data *irq_d;
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@ -568,9 +571,13 @@ static int tusb320_probe(struct i2c_client *client)
*/
tusb320_state_update_handler(priv, true);
irq_d = irq_get_irq_data(client->irq);
if (irq_d)
irq_trigger_type = irqd_get_trigger_type(irq_d);
ret = devm_request_threaded_irq(priv->dev, client->irq, NULL,
tusb320_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
IRQF_ONESHOT | irq_trigger_type,
client->name, priv);
if (ret)
tusb320_typec_remove(priv);

View File

@ -1280,8 +1280,6 @@ int extcon_dev_register(struct extcon_dev *edev)
edev->id = ret;
dev_set_name(&edev->dev, "extcon%d", edev->id);
ret = extcon_alloc_cables(edev);
if (ret < 0)
goto err_alloc_cables;
@ -1310,6 +1308,7 @@ int extcon_dev_register(struct extcon_dev *edev)
RAW_INIT_NOTIFIER_HEAD(&edev->nh_all);
dev_set_drvdata(&edev->dev, edev);
dev_set_name(&edev->dev, "extcon%d", edev->id);
edev->state = 0;
ret = device_register(&edev->dev);

View File

@ -2834,7 +2834,7 @@ clear_ida:
return ret;
}
static int scmi_remove(struct platform_device *pdev)
static void scmi_remove(struct platform_device *pdev)
{
int id;
struct scmi_info *info = platform_get_drvdata(pdev);
@ -2868,8 +2868,6 @@ static int scmi_remove(struct platform_device *pdev)
scmi_cleanup_txrx_channels(info);
ida_free(&scmi_id, info->id);
return 0;
}
static ssize_t protocol_version_show(struct device *dev,
@ -2947,7 +2945,7 @@ static struct platform_driver scmi_driver = {
.dev_groups = versions_groups,
},
.probe = scmi_probe,
.remove = scmi_remove,
.remove_new = scmi_remove,
};
/**

View File

@ -863,7 +863,7 @@ static void scpi_free_channels(void *data)
mbox_free_channel(info->channels[i].chan);
}
static int scpi_remove(struct platform_device *pdev)
static void scpi_remove(struct platform_device *pdev)
{
int i;
struct scpi_drvinfo *info = platform_get_drvdata(pdev);
@ -874,8 +874,6 @@ static int scpi_remove(struct platform_device *pdev)
kfree(info->dvfs[i]->opps);
kfree(info->dvfs[i]);
}
return 0;
}
#define MAX_SCPI_XFERS 10
@ -1048,7 +1046,7 @@ static struct platform_driver scpi_driver = {
.dev_groups = versions_groups,
},
.probe = scpi_probe,
.remove = scpi_remove,
.remove_new = scpi_remove,
};
module_platform_driver(scpi_driver);

View File

@ -160,7 +160,7 @@ static int imx_dsp_probe(struct platform_device *pdev)
return 0;
}
static int imx_dsp_remove(struct platform_device *pdev)
static void imx_dsp_remove(struct platform_device *pdev)
{
struct imx_dsp_chan *dsp_chan;
struct imx_dsp_ipc *dsp_ipc;
@ -173,8 +173,6 @@ static int imx_dsp_remove(struct platform_device *pdev)
mbox_free_channel(dsp_chan->ch);
kfree(dsp_chan->name);
}
return 0;
}
static struct platform_driver imx_dsp_driver = {
@ -182,7 +180,7 @@ static struct platform_driver imx_dsp_driver = {
.name = "imx-dsp",
},
.probe = imx_dsp_probe,
.remove = imx_dsp_remove,
.remove_new = imx_dsp_remove,
};
builtin_platform_driver(imx_dsp_driver);

View File

@ -116,7 +116,7 @@ static int mtk_adsp_ipc_probe(struct platform_device *pdev)
return 0;
}
static int mtk_adsp_ipc_remove(struct platform_device *pdev)
static void mtk_adsp_ipc_remove(struct platform_device *pdev)
{
struct mtk_adsp_ipc *adsp_ipc = dev_get_drvdata(&pdev->dev);
struct mtk_adsp_chan *adsp_chan;
@ -126,8 +126,6 @@ static int mtk_adsp_ipc_remove(struct platform_device *pdev)
adsp_chan = &adsp_ipc->chans[i];
mbox_free_channel(adsp_chan->ch);
}
return 0;
}
static struct platform_driver mtk_adsp_ipc_driver = {
@ -135,7 +133,7 @@ static struct platform_driver mtk_adsp_ipc_driver = {
.name = "mtk-adsp-ipc",
},
.probe = mtk_adsp_ipc_probe,
.remove = mtk_adsp_ipc_remove,
.remove_new = mtk_adsp_ipc_remove,
};
builtin_platform_driver(mtk_adsp_ipc_driver);

View File

@ -731,7 +731,7 @@ err_sel:
return err;
}
static int fw_cfg_sysfs_remove(struct platform_device *pdev)
static void fw_cfg_sysfs_remove(struct platform_device *pdev)
{
pr_debug("fw_cfg: unloading.\n");
fw_cfg_sysfs_cache_cleanup();
@ -739,7 +739,6 @@ static int fw_cfg_sysfs_remove(struct platform_device *pdev)
fw_cfg_io_cleanup();
fw_cfg_kset_unregister_recursive(fw_cfg_fname_kset);
fw_cfg_kobj_cleanup(fw_cfg_sel_ko);
return 0;
}
static const struct of_device_id fw_cfg_sysfs_mmio_match[] = {
@ -758,7 +757,7 @@ MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match);
static struct platform_driver fw_cfg_sysfs_driver = {
.probe = fw_cfg_sysfs_probe,
.remove = fw_cfg_sysfs_remove,
.remove_new = fw_cfg_sysfs_remove,
.driver = {
.name = "fw_cfg",
.of_match_table = fw_cfg_sysfs_mmio_match,

View File

@ -317,7 +317,7 @@ static void rpi_firmware_shutdown(struct platform_device *pdev)
rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_REBOOT, NULL, 0);
}
static int rpi_firmware_remove(struct platform_device *pdev)
static void rpi_firmware_remove(struct platform_device *pdev)
{
struct rpi_firmware *fw = platform_get_drvdata(pdev);
@ -327,8 +327,6 @@ static int rpi_firmware_remove(struct platform_device *pdev)
rpi_clk = NULL;
rpi_firmware_put(fw);
return 0;
}
static const struct of_device_id rpi_firmware_of_match[] = {
@ -406,7 +404,7 @@ static struct platform_driver rpi_firmware_driver = {
},
.probe = rpi_firmware_probe,
.shutdown = rpi_firmware_shutdown,
.remove = rpi_firmware_remove,
.remove_new = rpi_firmware_remove,
};
module_platform_driver(rpi_firmware_driver);

View File

@ -793,17 +793,16 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
return ret;
}
static int stratix10_rsu_remove(struct platform_device *pdev)
static void stratix10_rsu_remove(struct platform_device *pdev)
{
struct stratix10_rsu_priv *priv = platform_get_drvdata(pdev);
stratix10_svc_free_channel(priv->chan);
return 0;
}
static struct platform_driver stratix10_rsu_driver = {
.probe = stratix10_rsu_probe,
.remove = stratix10_rsu_remove,
.remove_new = stratix10_rsu_remove,
.driver = {
.name = "stratix10-rsu",
.dev_groups = rsu_groups,

View File

@ -1251,7 +1251,7 @@ err_destroy_pool:
return ret;
}
static int stratix10_svc_drv_remove(struct platform_device *pdev)
static void stratix10_svc_drv_remove(struct platform_device *pdev)
{
struct stratix10_svc *svc = dev_get_drvdata(&pdev->dev);
struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev);
@ -1267,13 +1267,11 @@ static int stratix10_svc_drv_remove(struct platform_device *pdev)
if (ctrl->genpool)
gen_pool_destroy(ctrl->genpool);
list_del(&ctrl->node);
return 0;
}
static struct platform_driver stratix10_svc_driver = {
.probe = stratix10_svc_drv_probe,
.remove = stratix10_svc_drv_remove,
.remove_new = stratix10_svc_drv_remove,
.driver = {
.name = "stratix10-svc",
.of_match_table = stratix10_svc_drv_match,

View File

@ -554,7 +554,7 @@ put_kobj:
return ret;
}
static int turris_mox_rwtm_remove(struct platform_device *pdev)
static void turris_mox_rwtm_remove(struct platform_device *pdev)
{
struct mox_rwtm *rwtm = platform_get_drvdata(pdev);
@ -562,8 +562,6 @@ static int turris_mox_rwtm_remove(struct platform_device *pdev)
sysfs_remove_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs);
kobject_put(rwtm_to_kobj(rwtm));
mbox_free_channel(rwtm->mbox);
return 0;
}
static const struct of_device_id turris_mox_rwtm_match[] = {
@ -576,7 +574,7 @@ MODULE_DEVICE_TABLE(of, turris_mox_rwtm_match);
static struct platform_driver turris_mox_rwtm_driver = {
.probe = turris_mox_rwtm_probe,
.remove = turris_mox_rwtm_remove,
.remove_new = turris_mox_rwtm_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = turris_mox_rwtm_match,

View File

@ -92,6 +92,8 @@ static int zynqmp_pm_ret_code(u32 ret_status)
return 0;
case XST_PM_NO_FEATURE:
return -ENOTSUPP;
case XST_PM_INVALID_VERSION:
return -EOPNOTSUPP;
case XST_PM_NO_ACCESS:
return -EACCES;
case XST_PM_ABORT_SUSPEND:
@ -101,13 +103,13 @@ static int zynqmp_pm_ret_code(u32 ret_status)
case XST_PM_INTERNAL:
case XST_PM_CONFLICT:
case XST_PM_INVALID_NODE:
case XST_PM_INVALID_CRC:
default:
return -EINVAL;
}
}
static noinline int do_fw_call_fail(u64 arg0, u64 arg1, u64 arg2,
u32 *ret_payload)
static noinline int do_fw_call_fail(u32 *ret_payload, u32 num_args, ...)
{
return -ENODEV;
}
@ -116,25 +118,35 @@ static noinline int do_fw_call_fail(u64 arg0, u64 arg1, u64 arg2,
* PM function call wrapper
* Invoke do_fw_call_smc or do_fw_call_hvc, depending on the configuration
*/
static int (*do_fw_call)(u64, u64, u64, u32 *ret_payload) = do_fw_call_fail;
static int (*do_fw_call)(u32 *ret_payload, u32, ...) = do_fw_call_fail;
/**
* do_fw_call_smc() - Call system-level platform management layer (SMC)
* @arg0: Argument 0 to SMC call
* @arg1: Argument 1 to SMC call
* @arg2: Argument 2 to SMC call
* @num_args: Number of variable arguments should be <= 8
* @ret_payload: Returned value array
*
* Invoke platform management function via SMC call (no hypervisor present).
*
* Return: Returns status, either success or error+reason
*/
static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2,
u32 *ret_payload)
static noinline int do_fw_call_smc(u32 *ret_payload, u32 num_args, ...)
{
struct arm_smccc_res res;
u64 args[8] = {0};
va_list arg_list;
u8 i;
arm_smccc_smc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
if (num_args > 8)
return -EINVAL;
va_start(arg_list, num_args);
for (i = 0; i < num_args; i++)
args[i] = va_arg(arg_list, u64);
va_end(arg_list);
arm_smccc_smc(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], &res);
if (ret_payload) {
ret_payload[0] = lower_32_bits(res.a0);
@ -148,9 +160,7 @@ static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2,
/**
* do_fw_call_hvc() - Call system-level platform management layer (HVC)
* @arg0: Argument 0 to HVC call
* @arg1: Argument 1 to HVC call
* @arg2: Argument 2 to HVC call
* @num_args: Number of variable arguments should be <= 8
* @ret_payload: Returned value array
*
* Invoke platform management function via HVC
@ -159,12 +169,24 @@ static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2,
*
* Return: Returns status, either success or error+reason
*/
static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2,
u32 *ret_payload)
static noinline int do_fw_call_hvc(u32 *ret_payload, u32 num_args, ...)
{
struct arm_smccc_res res;
u64 args[8] = {0};
va_list arg_list;
u8 i;
arm_smccc_hvc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
if (num_args > 8)
return -EINVAL;
va_start(arg_list, num_args);
for (i = 0; i < num_args; i++)
args[i] = va_arg(arg_list, u64);
va_end(arg_list);
arm_smccc_hvc(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], &res);
if (ret_payload) {
ret_payload[0] = lower_32_bits(res.a0);
@ -180,11 +202,31 @@ static int __do_feature_check_call(const u32 api_id, u32 *ret_payload)
{
int ret;
u64 smc_arg[2];
u32 module_id;
u32 feature_check_api_id;
smc_arg[0] = PM_SIP_SVC | PM_FEATURE_CHECK;
smc_arg[1] = api_id;
module_id = FIELD_GET(MODULE_ID_MASK, api_id);
ret = do_fw_call(smc_arg[0], smc_arg[1], 0, ret_payload);
/*
* Feature check of APIs belonging to PM, XSEM, and TF-A are handled by calling
* PM_FEATURE_CHECK API. For other modules, call PM_API_FEATURES API.
*/
if (module_id == PM_MODULE_ID || module_id == XSEM_MODULE_ID || module_id == TF_A_MODULE_ID)
feature_check_api_id = PM_FEATURE_CHECK;
else
feature_check_api_id = PM_API_FEATURES;
/*
* Feature check of TF-A APIs is done in the TF-A layer and it expects for
* MODULE_ID_MASK bits of SMC's arg[0] to be the same as PM_MODULE_ID.
*/
if (module_id == TF_A_MODULE_ID)
module_id = PM_MODULE_ID;
smc_arg[0] = PM_SIP_SVC | FIELD_PREP(MODULE_ID_MASK, module_id) | feature_check_api_id;
smc_arg[1] = (api_id & API_ID_MASK);
ret = do_fw_call(ret_payload, 2, smc_arg[0], smc_arg[1]);
if (ret)
ret = -EOPNOTSUPP;
else
@ -295,11 +337,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_is_function_supported);
* zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer
* caller function depending on the configuration
* @pm_api_id: Requested PM-API call
* @arg0: Argument 0 to requested PM-API call
* @arg1: Argument 1 to requested PM-API call
* @arg2: Argument 2 to requested PM-API call
* @arg3: Argument 3 to requested PM-API call
* @ret_payload: Returned value array
* @num_args: Number of arguments to requested PM-API call
*
* Invoke platform management function for SMC or HVC call, depending on
* configuration.
@ -316,26 +355,38 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_is_function_supported);
*
* Return: Returns status, either success or error+reason
*/
int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1,
u32 arg2, u32 arg3, u32 *ret_payload)
int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 *ret_payload, u32 num_args, ...)
{
/*
* Added SIP service call Function Identifier
* Make sure to stay in x0 register
*/
u64 smc_arg[4];
int ret;
u64 smc_arg[8];
int ret, i;
va_list arg_list;
u32 args[14] = {0};
if (num_args > 14)
return -EINVAL;
va_start(arg_list, num_args);
/* Check if feature is supported or not */
ret = zynqmp_pm_feature(pm_api_id);
if (ret < 0)
return ret;
smc_arg[0] = PM_SIP_SVC | pm_api_id;
smc_arg[1] = ((u64)arg1 << 32) | arg0;
smc_arg[2] = ((u64)arg3 << 32) | arg2;
for (i = 0; i < num_args; i++)
args[i] = va_arg(arg_list, u32);
return do_fw_call(smc_arg[0], smc_arg[1], smc_arg[2], ret_payload);
va_end(arg_list);
smc_arg[0] = PM_SIP_SVC | pm_api_id;
for (i = 0; i < 7; i++)
smc_arg[i + 1] = ((u64)args[(i * 2) + 1] << 32) | args[i * 2];
return do_fw_call(ret_payload, 8, smc_arg[0], smc_arg[1], smc_arg[2], smc_arg[3],
smc_arg[4], smc_arg[5], smc_arg[6], smc_arg[7]);
}
static u32 pm_api_version;
@ -347,14 +398,12 @@ int zynqmp_pm_register_sgi(u32 sgi_num, u32 reset)
{
int ret;
ret = zynqmp_pm_invoke_fn(TF_A_PM_REGISTER_SGI, sgi_num, reset, 0, 0,
NULL);
if (!ret)
ret = zynqmp_pm_invoke_fn(TF_A_PM_REGISTER_SGI, NULL, 2, sgi_num, reset);
if (ret != -EOPNOTSUPP && !ret)
return ret;
/* try old implementation as fallback strategy if above fails */
return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_REGISTER_SGI, sgi_num,
reset, NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, IOCTL_REGISTER_SGI, sgi_num, reset);
}
/**
@ -376,7 +425,7 @@ int zynqmp_pm_get_api_version(u32 *version)
*version = pm_api_version;
return 0;
}
ret = zynqmp_pm_invoke_fn(PM_GET_API_VERSION, 0, 0, 0, 0, ret_payload);
ret = zynqmp_pm_invoke_fn(PM_GET_API_VERSION, ret_payload, 0);
*version = ret_payload[1];
return ret;
@ -399,7 +448,7 @@ int zynqmp_pm_get_chipid(u32 *idcode, u32 *version)
if (!idcode || !version)
return -EINVAL;
ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload);
ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, ret_payload, 0);
*idcode = ret_payload[1];
*version = ret_payload[2];
@ -414,7 +463,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_get_chipid);
*
* Return: Returns status, either success or error+reason
*/
static int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily)
int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily)
{
u32 ret_payload[PAYLOAD_ARG_CNT];
u32 idcode;
@ -427,7 +476,7 @@ static int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily)
return 0;
}
ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload);
ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, ret_payload, 0);
if (ret < 0)
return ret;
@ -439,6 +488,7 @@ static int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily)
return 0;
}
EXPORT_SYMBOL_GPL(zynqmp_pm_get_family_info);
/**
* zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version
@ -459,8 +509,7 @@ static int zynqmp_pm_get_trustzone_version(u32 *version)
*version = pm_tz_version;
return 0;
}
ret = zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION, 0, 0,
0, 0, ret_payload);
ret = zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION, ret_payload, 0);
*version = ret_payload[1];
return ret;
@ -507,8 +556,8 @@ int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out)
{
int ret;
ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, qdata.qid, qdata.arg1,
qdata.arg2, qdata.arg3, out);
ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, out, 4, qdata.qid, qdata.arg1, qdata.arg2,
qdata.arg3);
/*
* For clock name query, all bytes in SMC response are clock name
@ -530,7 +579,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_query_data);
*/
int zynqmp_pm_clock_enable(u32 clock_id)
{
return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, clock_id, 0, 0, 0, NULL);
return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, NULL, 1, clock_id);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_clock_enable);
@ -545,7 +594,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_clock_enable);
*/
int zynqmp_pm_clock_disable(u32 clock_id)
{
return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, clock_id, 0, 0, 0, NULL);
return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, NULL, 1, clock_id);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_clock_disable);
@ -564,8 +613,7 @@ int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state)
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, clock_id, 0,
0, 0, ret_payload);
ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, ret_payload, 1, clock_id);
*state = ret_payload[1];
return ret;
@ -584,8 +632,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getstate);
*/
int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider)
{
return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, clock_id, divider,
0, 0, NULL);
return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, NULL, 2, clock_id, divider);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_clock_setdivider);
@ -604,55 +651,13 @@ int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider)
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, clock_id, 0,
0, 0, ret_payload);
ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, ret_payload, 1, clock_id);
*divider = ret_payload[1];
return ret;
}
EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getdivider);
/**
* zynqmp_pm_clock_setrate() - Set the clock rate for given id
* @clock_id: ID of the clock
* @rate: rate value in hz
*
* This function is used by master to set rate for any clock.
*
* Return: Returns status, either success or error+reason
*/
int zynqmp_pm_clock_setrate(u32 clock_id, u64 rate)
{
return zynqmp_pm_invoke_fn(PM_CLOCK_SETRATE, clock_id,
lower_32_bits(rate),
upper_32_bits(rate),
0, NULL);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_clock_setrate);
/**
* zynqmp_pm_clock_getrate() - Get the clock rate for given id
* @clock_id: ID of the clock
* @rate: rate value in hz
*
* This function is used by master to get rate
* for any clock.
*
* Return: Returns status, either success or error+reason
*/
int zynqmp_pm_clock_getrate(u32 clock_id, u64 *rate)
{
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETRATE, clock_id, 0,
0, 0, ret_payload);
*rate = ((u64)ret_payload[2] << 32) | ret_payload[1];
return ret;
}
EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getrate);
/**
* zynqmp_pm_clock_setparent() - Set the clock parent for given id
* @clock_id: ID of the clock
@ -664,8 +669,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getrate);
*/
int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id)
{
return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, clock_id,
parent_id, 0, 0, NULL);
return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, NULL, 2, clock_id, parent_id);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_clock_setparent);
@ -684,8 +688,7 @@ int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id)
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, clock_id, 0,
0, 0, ret_payload);
ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, ret_payload, 1, clock_id);
*parent_id = ret_payload[1];
return ret;
@ -704,8 +707,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getparent);
*/
int zynqmp_pm_set_pll_frac_mode(u32 clk_id, u32 mode)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_PLL_FRAC_MODE,
clk_id, mode, NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_PLL_FRAC_MODE, clk_id, mode);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_mode);
@ -721,8 +723,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_mode);
*/
int zynqmp_pm_get_pll_frac_mode(u32 clk_id, u32 *mode)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_MODE,
clk_id, 0, mode);
return zynqmp_pm_invoke_fn(PM_IOCTL, mode, 3, 0, IOCTL_GET_PLL_FRAC_MODE, clk_id);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_mode);
@ -739,8 +740,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_mode);
*/
int zynqmp_pm_set_pll_frac_data(u32 clk_id, u32 data)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_PLL_FRAC_DATA,
clk_id, data, NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_PLL_FRAC_DATA, clk_id, data);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_data);
@ -756,8 +756,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_data);
*/
int zynqmp_pm_get_pll_frac_data(u32 clk_id, u32 *data)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_DATA,
clk_id, 0, data);
return zynqmp_pm_invoke_fn(PM_IOCTL, data, 3, 0, IOCTL_GET_PLL_FRAC_DATA, clk_id);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_data);
@ -778,9 +777,8 @@ int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value)
u32 mask = (node_id == NODE_SD_0) ? GENMASK(15, 0) : GENMASK(31, 16);
if (value) {
return zynqmp_pm_invoke_fn(PM_IOCTL, node_id,
IOCTL_SET_SD_TAPDELAY,
type, value, NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, node_id, IOCTL_SET_SD_TAPDELAY, type,
value);
}
/*
@ -798,7 +796,7 @@ int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value)
* Use PM_MMIO_READ/PM_MMIO_WRITE to re-implement the missing counter
* part of IOCTL_SET_SD_TAPDELAY which clears SDx_ITAPDLYENA bits.
*/
return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, reg, mask, 0, 0, NULL);
return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, NULL, 2, reg, mask);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay);
@ -814,8 +812,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay);
*/
int zynqmp_pm_sd_dll_reset(u32 node_id, u32 type)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, IOCTL_SD_DLL_RESET,
type, 0, NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, node_id, IOCTL_SD_DLL_RESET, type);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_sd_dll_reset);
@ -831,8 +828,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_sd_dll_reset);
*/
int zynqmp_pm_ospi_mux_select(u32 dev_id, u32 select)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, dev_id, IOCTL_OSPI_MUX_SELECT,
select, 0, NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, dev_id, IOCTL_OSPI_MUX_SELECT, select);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_ospi_mux_select);
@ -847,8 +843,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_ospi_mux_select);
*/
int zynqmp_pm_write_ggs(u32 index, u32 value)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_GGS,
index, value, NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_WRITE_GGS, index, value);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs);
@ -863,8 +858,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs);
*/
int zynqmp_pm_read_ggs(u32 index, u32 *value)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_GGS,
index, 0, value);
return zynqmp_pm_invoke_fn(PM_IOCTL, value, 3, 0, IOCTL_READ_GGS, index);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_read_ggs);
@ -880,8 +874,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_read_ggs);
*/
int zynqmp_pm_write_pggs(u32 index, u32 value)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_PGGS, index, value,
NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_WRITE_PGGS, index, value);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs);
@ -897,15 +890,13 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs);
*/
int zynqmp_pm_read_pggs(u32 index, u32 *value)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_PGGS, index, 0,
value);
return zynqmp_pm_invoke_fn(PM_IOCTL, value, 3, 0, IOCTL_READ_PGGS, index);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_read_pggs);
int zynqmp_pm_set_tapdelay_bypass(u32 index, u32 value)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_TAPDELAY_BYPASS,
index, value, NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_TAPDELAY_BYPASS, index, value);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_tapdelay_bypass);
@ -920,8 +911,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_tapdelay_bypass);
*/
int zynqmp_pm_set_boot_health_status(u32 value)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_BOOT_HEALTH_STATUS,
value, 0, NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, 0, IOCTL_SET_BOOT_HEALTH_STATUS, value);
}
/**
@ -935,8 +925,7 @@ int zynqmp_pm_set_boot_health_status(u32 value)
int zynqmp_pm_reset_assert(const enum zynqmp_pm_reset reset,
const enum zynqmp_pm_reset_action assert_flag)
{
return zynqmp_pm_invoke_fn(PM_RESET_ASSERT, reset, assert_flag,
0, 0, NULL);
return zynqmp_pm_invoke_fn(PM_RESET_ASSERT, NULL, 2, reset, assert_flag);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_reset_assert);
@ -955,8 +944,7 @@ int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset, u32 *status)
if (!status)
return -EINVAL;
ret = zynqmp_pm_invoke_fn(PM_RESET_GET_STATUS, reset, 0,
0, 0, ret_payload);
ret = zynqmp_pm_invoke_fn(PM_RESET_GET_STATUS, ret_payload, 1, reset);
*status = ret_payload[1];
return ret;
@ -981,9 +969,8 @@ int zynqmp_pm_fpga_load(const u64 address, const u32 size, const u32 flags)
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
ret = zynqmp_pm_invoke_fn(PM_FPGA_LOAD, lower_32_bits(address),
upper_32_bits(address), size, flags,
ret_payload);
ret = zynqmp_pm_invoke_fn(PM_FPGA_LOAD, ret_payload, 4, lower_32_bits(address),
upper_32_bits(address), size, flags);
if (ret_payload[0])
return -ret_payload[0];
@ -1008,7 +995,7 @@ int zynqmp_pm_fpga_get_status(u32 *value)
if (!value)
return -EINVAL;
ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload);
ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, ret_payload, 0);
*value = ret_payload[1];
return ret;
@ -1036,11 +1023,9 @@ int zynqmp_pm_fpga_get_config_status(u32 *value)
lower_addr = lower_32_bits((u64)&buf);
upper_addr = upper_32_bits((u64)&buf);
ret = zynqmp_pm_invoke_fn(PM_FPGA_READ,
XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET,
lower_addr, upper_addr,
XILINX_ZYNQMP_PM_FPGA_READ_CONFIG_REG,
ret_payload);
ret = zynqmp_pm_invoke_fn(PM_FPGA_READ, ret_payload, 4,
XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET, lower_addr, upper_addr,
XILINX_ZYNQMP_PM_FPGA_READ_CONFIG_REG);
*value = ret_payload[1];
@ -1058,7 +1043,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_fpga_get_config_status);
*/
int zynqmp_pm_pinctrl_request(const u32 pin)
{
return zynqmp_pm_invoke_fn(PM_PINCTRL_REQUEST, pin, 0, 0, 0, NULL);
return zynqmp_pm_invoke_fn(PM_PINCTRL_REQUEST, NULL, 1, pin);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_request);
@ -1072,35 +1057,10 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_request);
*/
int zynqmp_pm_pinctrl_release(const u32 pin)
{
return zynqmp_pm_invoke_fn(PM_PINCTRL_RELEASE, pin, 0, 0, 0, NULL);
return zynqmp_pm_invoke_fn(PM_PINCTRL_RELEASE, NULL, 1, pin);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_release);
/**
* zynqmp_pm_pinctrl_get_function - Read function id set for the given pin
* @pin: Pin number
* @id: Buffer to store function ID
*
* This function provides the function currently set for the given pin.
*
* Return: Returns status, either success or error+reason
*/
int zynqmp_pm_pinctrl_get_function(const u32 pin, u32 *id)
{
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
if (!id)
return -EINVAL;
ret = zynqmp_pm_invoke_fn(PM_PINCTRL_GET_FUNCTION, pin, 0,
0, 0, ret_payload);
*id = ret_payload[1];
return ret;
}
EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_get_function);
/**
* zynqmp_pm_pinctrl_set_function - Set requested function for the pin
* @pin: Pin number
@ -1112,8 +1072,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_get_function);
*/
int zynqmp_pm_pinctrl_set_function(const u32 pin, const u32 id)
{
return zynqmp_pm_invoke_fn(PM_PINCTRL_SET_FUNCTION, pin, id,
0, 0, NULL);
return zynqmp_pm_invoke_fn(PM_PINCTRL_SET_FUNCTION, NULL, 2, pin, id);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_set_function);
@ -1136,8 +1095,7 @@ int zynqmp_pm_pinctrl_get_config(const u32 pin, const u32 param,
if (!value)
return -EINVAL;
ret = zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_GET, pin, param,
0, 0, ret_payload);
ret = zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_GET, ret_payload, 2, pin, param);
*value = ret_payload[1];
return ret;
@ -1166,8 +1124,7 @@ int zynqmp_pm_pinctrl_set_config(const u32 pin, const u32 param,
return -EOPNOTSUPP;
}
return zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_SET, pin,
param, value, 0, NULL);
return zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_SET, NULL, 3, pin, param, value);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_set_config);
@ -1185,8 +1142,7 @@ unsigned int zynqmp_pm_bootmode_read(u32 *ps_mode)
unsigned int ret;
u32 ret_payload[PAYLOAD_ARG_CNT];
ret = zynqmp_pm_invoke_fn(PM_MMIO_READ, CRL_APB_BOOT_PIN_CTRL, 0,
0, 0, ret_payload);
ret = zynqmp_pm_invoke_fn(PM_MMIO_READ, ret_payload, 1, CRL_APB_BOOT_PIN_CTRL);
*ps_mode = ret_payload[1];
@ -1205,8 +1161,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_read);
*/
int zynqmp_pm_bootmode_write(u32 ps_mode)
{
return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, CRL_APB_BOOT_PIN_CTRL,
CRL_APB_BOOTPIN_CTRL_MASK, ps_mode, 0, NULL);
return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, NULL, 3, CRL_APB_BOOT_PIN_CTRL,
CRL_APB_BOOTPIN_CTRL_MASK, ps_mode);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_write);
@ -1221,7 +1177,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_write);
*/
int zynqmp_pm_init_finalize(void)
{
return zynqmp_pm_invoke_fn(PM_PM_INIT_FINALIZE, 0, 0, 0, 0, NULL);
return zynqmp_pm_invoke_fn(PM_PM_INIT_FINALIZE, NULL, 0);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_init_finalize);
@ -1235,7 +1191,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_init_finalize);
*/
int zynqmp_pm_set_suspend_mode(u32 mode)
{
return zynqmp_pm_invoke_fn(PM_SET_SUSPEND_MODE, mode, 0, 0, 0, NULL);
return zynqmp_pm_invoke_fn(PM_SET_SUSPEND_MODE, NULL, 1, mode);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_suspend_mode);
@ -1254,8 +1210,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_suspend_mode);
int zynqmp_pm_request_node(const u32 node, const u32 capabilities,
const u32 qos, const enum zynqmp_pm_request_ack ack)
{
return zynqmp_pm_invoke_fn(PM_REQUEST_NODE, node, capabilities,
qos, ack, NULL);
return zynqmp_pm_invoke_fn(PM_REQUEST_NODE, NULL, 4, node, capabilities, qos, ack);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_request_node);
@ -1271,7 +1226,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_request_node);
*/
int zynqmp_pm_release_node(const u32 node)
{
return zynqmp_pm_invoke_fn(PM_RELEASE_NODE, node, 0, 0, 0, NULL);
return zynqmp_pm_invoke_fn(PM_RELEASE_NODE, NULL, 1, node);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_release_node);
@ -1290,8 +1245,7 @@ int zynqmp_pm_get_rpu_mode(u32 node_id, enum rpu_oper_mode *rpu_mode)
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
ret = zynqmp_pm_invoke_fn(PM_IOCTL, node_id,
IOCTL_GET_RPU_OPER_MODE, 0, 0, ret_payload);
ret = zynqmp_pm_invoke_fn(PM_IOCTL, ret_payload, 2, node_id, IOCTL_GET_RPU_OPER_MODE);
/* only set rpu_mode if no error */
if (ret == XST_PM_SUCCESS)
@ -1313,9 +1267,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_get_rpu_mode);
*/
int zynqmp_pm_set_rpu_mode(u32 node_id, enum rpu_oper_mode rpu_mode)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, node_id,
IOCTL_SET_RPU_OPER_MODE, (u32)rpu_mode,
0, NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, node_id, IOCTL_SET_RPU_OPER_MODE,
(u32)rpu_mode);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_rpu_mode);
@ -1331,9 +1284,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_rpu_mode);
*/
int zynqmp_pm_set_tcm_config(u32 node_id, enum rpu_tcm_comb tcm_mode)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, node_id,
IOCTL_TCM_COMB_CONFIG, (u32)tcm_mode, 0,
NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, node_id, IOCTL_TCM_COMB_CONFIG,
(u32)tcm_mode);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_tcm_config);
@ -1348,7 +1300,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_tcm_config);
int zynqmp_pm_force_pwrdwn(const u32 node,
const enum zynqmp_pm_request_ack ack)
{
return zynqmp_pm_invoke_fn(PM_FORCE_POWERDOWN, node, ack, 0, 0, NULL);
return zynqmp_pm_invoke_fn(PM_FORCE_POWERDOWN, NULL, 2, node, ack);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_force_pwrdwn);
@ -1367,8 +1319,8 @@ int zynqmp_pm_request_wake(const u32 node,
const enum zynqmp_pm_request_ack ack)
{
/* set_addr flag is encoded into 1st bit of address */
return zynqmp_pm_invoke_fn(PM_REQUEST_WAKEUP, node, address | set_addr,
address >> 32, ack, NULL);
return zynqmp_pm_invoke_fn(PM_REQUEST_WAKEUP, NULL, 4, node, address | set_addr,
address >> 32, ack);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_request_wake);
@ -1388,15 +1340,14 @@ int zynqmp_pm_set_requirement(const u32 node, const u32 capabilities,
const u32 qos,
const enum zynqmp_pm_request_ack ack)
{
return zynqmp_pm_invoke_fn(PM_SET_REQUIREMENT, node, capabilities,
qos, ack, NULL);
return zynqmp_pm_invoke_fn(PM_SET_REQUIREMENT, NULL, 4, node, capabilities, qos, ack);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_requirement);
/**
* zynqmp_pm_load_pdi - Load and process PDI
* @src: Source device where PDI is located
* @address: PDI src address
* @src: Source device where PDI is located
* @address: PDI src address
*
* This function provides support to load PDI from linux
*
@ -1404,9 +1355,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_requirement);
*/
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);
return zynqmp_pm_invoke_fn(PM_LOAD_PDI, NULL, 3, src, lower_32_bits(address),
upper_32_bits(address));
}
EXPORT_SYMBOL_GPL(zynqmp_pm_load_pdi);
@ -1426,9 +1376,8 @@ int zynqmp_pm_aes_engine(const u64 address, u32 *out)
if (!out)
return -EINVAL;
ret = zynqmp_pm_invoke_fn(PM_SECURE_AES, upper_32_bits(address),
lower_32_bits(address),
0, 0, ret_payload);
ret = zynqmp_pm_invoke_fn(PM_SECURE_AES, ret_payload, 2, upper_32_bits(address),
lower_32_bits(address));
*out = ret_payload[1];
return ret;
@ -1456,8 +1405,7 @@ int zynqmp_pm_sha_hash(const u64 address, const u32 size, const u32 flags)
u32 lower_addr = lower_32_bits(address);
u32 upper_addr = upper_32_bits(address);
return zynqmp_pm_invoke_fn(PM_SECURE_SHA, upper_addr, lower_addr,
size, flags, NULL);
return zynqmp_pm_invoke_fn(PM_SECURE_SHA, NULL, 4, upper_addr, lower_addr, size, flags);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_sha_hash);
@ -1479,8 +1427,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_sha_hash);
int zynqmp_pm_register_notifier(const u32 node, const u32 event,
const u32 wake, const u32 enable)
{
return zynqmp_pm_invoke_fn(PM_REGISTER_NOTIFIER, node, event,
wake, enable, NULL);
return zynqmp_pm_invoke_fn(PM_REGISTER_NOTIFIER, NULL, 4, node, event, wake, enable);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_register_notifier);
@ -1493,8 +1440,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_register_notifier);
*/
int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype)
{
return zynqmp_pm_invoke_fn(PM_SYSTEM_SHUTDOWN, type, subtype,
0, 0, NULL);
return zynqmp_pm_invoke_fn(PM_SYSTEM_SHUTDOWN, NULL, 2, type, subtype);
}
/**
@ -1506,8 +1452,7 @@ int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype)
*/
int zynqmp_pm_set_feature_config(enum pm_feature_config_id id, u32 value)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_FEATURE_CONFIG,
id, value, NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_FEATURE_CONFIG, id, value);
}
/**
@ -1520,8 +1465,7 @@ int zynqmp_pm_set_feature_config(enum pm_feature_config_id id, u32 value)
int zynqmp_pm_get_feature_config(enum pm_feature_config_id id,
u32 *payload)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_GET_FEATURE_CONFIG,
id, 0, payload);
return zynqmp_pm_invoke_fn(PM_IOCTL, payload, 3, 0, IOCTL_GET_FEATURE_CONFIG, id);
}
/**
@ -1534,8 +1478,7 @@ int zynqmp_pm_get_feature_config(enum pm_feature_config_id id,
*/
int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, node, IOCTL_SET_SD_CONFIG,
config, value, NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, node, IOCTL_SET_SD_CONFIG, config, value);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_config);
@ -1550,8 +1493,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_config);
int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config,
u32 value)
{
return zynqmp_pm_invoke_fn(PM_IOCTL, node, IOCTL_SET_GEM_CONFIG,
config, value, NULL);
return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, node, IOCTL_SET_GEM_CONFIG, config, value);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_gem_config);
@ -1916,7 +1858,6 @@ ATTRIBUTE_GROUPS(zynqmp_firmware);
static int zynqmp_firmware_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np;
struct zynqmp_devinfo *devinfo;
int ret;
@ -1924,22 +1865,9 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
if (ret)
return ret;
np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
if (!np) {
np = of_find_compatible_node(NULL, NULL, "xlnx,versal");
if (!np)
return 0;
ret = do_feature_check_call(PM_FEATURE_CHECK);
if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_1))
feature_check_enabled = true;
}
if (!feature_check_enabled) {
ret = do_feature_check_call(PM_FEATURE_CHECK);
if (ret >= 0)
feature_check_enabled = true;
}
of_node_put(np);
devinfo = devm_kzalloc(dev, sizeof(*devinfo), GFP_KERNEL);
if (!devinfo)
@ -1992,19 +1920,17 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
zynqmp_pm_api_debugfs_init();
np = of_find_compatible_node(NULL, NULL, "xlnx,versal");
if (np) {
if (pm_family_code == VERSAL_FAMILY_CODE) {
em_dev = platform_device_register_data(&pdev->dev, "xlnx_event_manager",
-1, NULL, 0);
if (IS_ERR(em_dev))
dev_err_probe(&pdev->dev, PTR_ERR(em_dev), "EM register fail with error\n");
}
of_node_put(np);
return of_platform_populate(dev->of_node, NULL, NULL, dev);
}
static int zynqmp_firmware_remove(struct platform_device *pdev)
static void zynqmp_firmware_remove(struct platform_device *pdev)
{
struct pm_api_feature_data *feature_data;
struct hlist_node *tmp;
@ -2019,8 +1945,6 @@ static int zynqmp_firmware_remove(struct platform_device *pdev)
}
platform_device_unregister(em_dev);
return 0;
}
static const struct of_device_id zynqmp_firmware_of_match[] = {
@ -2037,6 +1961,6 @@ static struct platform_driver zynqmp_firmware_driver = {
.dev_groups = zynqmp_firmware_groups,
},
.probe = zynqmp_firmware_probe,
.remove = zynqmp_firmware_remove,
.remove_new = zynqmp_firmware_remove,
};
module_platform_driver(zynqmp_firmware_driver);

View File

@ -147,20 +147,18 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev)
return ret;
}
static int alt_fpga_bridge_remove(struct platform_device *pdev)
static void alt_fpga_bridge_remove(struct platform_device *pdev)
{
struct fpga_bridge *br = platform_get_drvdata(pdev);
fpga_bridge_unregister(br);
return 0;
}
MODULE_DEVICE_TABLE(of, altera_fpga_of_match);
static struct platform_driver altera_fpga_driver = {
.probe = alt_fpga_bridge_probe,
.remove = alt_fpga_bridge_remove,
.remove_new = alt_fpga_bridge_remove,
.driver = {
.name = "altera_fpga2sdram_bridge",
.of_match_table = of_match_ptr(altera_fpga_of_match),

View File

@ -253,18 +253,16 @@ static int altera_freeze_br_probe(struct platform_device *pdev)
return 0;
}
static int altera_freeze_br_remove(struct platform_device *pdev)
static void altera_freeze_br_remove(struct platform_device *pdev)
{
struct fpga_bridge *br = platform_get_drvdata(pdev);
fpga_bridge_unregister(br);
return 0;
}
static struct platform_driver altera_freeze_br_driver = {
.probe = altera_freeze_br_probe,
.remove = altera_freeze_br_remove,
.remove_new = altera_freeze_br_remove,
.driver = {
.name = "altera_freeze_br",
.of_match_table = altera_freeze_br_of_match,

View File

@ -191,7 +191,7 @@ err:
return ret;
}
static int alt_fpga_bridge_remove(struct platform_device *pdev)
static void alt_fpga_bridge_remove(struct platform_device *pdev)
{
struct fpga_bridge *bridge = platform_get_drvdata(pdev);
struct altera_hps2fpga_data *priv = bridge->priv;
@ -199,15 +199,13 @@ static int alt_fpga_bridge_remove(struct platform_device *pdev)
fpga_bridge_unregister(bridge);
clk_disable_unprepare(priv->clk);
return 0;
}
MODULE_DEVICE_TABLE(of, altera_fpga_of_match);
static struct platform_driver alt_fpga_bridge_driver = {
.probe = alt_fpga_bridge_probe,
.remove = alt_fpga_bridge_remove,
.remove_new = alt_fpga_bridge_remove,
.driver = {
.name = "altera_hps2fpga_bridge",
.of_match_table = of_match_ptr(altera_fpga_of_match),

View File

@ -932,15 +932,13 @@ exit:
return ret;
}
static int afu_remove(struct platform_device *pdev)
static void afu_remove(struct platform_device *pdev)
{
dev_dbg(&pdev->dev, "%s\n", __func__);
dfl_fpga_dev_ops_unregister(pdev);
dfl_fpga_dev_feature_uinit(pdev);
afu_dev_destroy(pdev);
return 0;
}
static const struct attribute_group *afu_dev_groups[] = {
@ -956,7 +954,7 @@ static struct platform_driver afu_driver = {
.dev_groups = afu_dev_groups,
},
.probe = afu_probe,
.remove = afu_remove,
.remove_new = afu_remove,
};
static int __init afu_init(void)

View File

@ -78,7 +78,7 @@ static int fme_br_probe(struct platform_device *pdev)
return 0;
}
static int fme_br_remove(struct platform_device *pdev)
static void fme_br_remove(struct platform_device *pdev)
{
struct fpga_bridge *br = platform_get_drvdata(pdev);
struct fme_br_priv *priv = br->priv;
@ -89,8 +89,6 @@ static int fme_br_remove(struct platform_device *pdev)
put_device(&priv->port_pdev->dev);
if (priv->port_ops)
dfl_fpga_port_ops_put(priv->port_ops);
return 0;
}
static struct platform_driver fme_br_driver = {
@ -98,7 +96,7 @@ static struct platform_driver fme_br_driver = {
.name = DFL_FPGA_FME_BRIDGE,
},
.probe = fme_br_probe,
.remove = fme_br_remove,
.remove_new = fme_br_remove,
};
module_platform_driver(fme_br_driver);

View File

@ -730,13 +730,11 @@ exit:
return ret;
}
static int fme_remove(struct platform_device *pdev)
static void fme_remove(struct platform_device *pdev)
{
dfl_fpga_dev_ops_unregister(pdev);
dfl_fpga_dev_feature_uinit(pdev);
fme_dev_destroy(pdev);
return 0;
}
static const struct attribute_group *fme_dev_groups[] = {
@ -751,7 +749,7 @@ static struct platform_driver fme_driver = {
.dev_groups = fme_dev_groups,
},
.probe = fme_probe,
.remove = fme_remove,
.remove_new = fme_remove,
};
module_platform_driver(fme_driver);

View File

@ -61,15 +61,13 @@ eprobe_mgr_put:
return ret;
}
static int fme_region_remove(struct platform_device *pdev)
static void fme_region_remove(struct platform_device *pdev)
{
struct fpga_region *region = platform_get_drvdata(pdev);
struct fpga_manager *mgr = region->mgr;
fpga_region_unregister(region);
fpga_mgr_put(mgr);
return 0;
}
static struct platform_driver fme_region_driver = {
@ -77,7 +75,7 @@ static struct platform_driver fme_region_driver = {
.name = DFL_FPGA_FME_REGION,
},
.probe = fme_region_probe,
.remove = fme_region_remove,
.remove_new = fme_region_remove,
};
module_platform_driver(fme_region_driver);

View File

@ -2008,8 +2008,8 @@ long dfl_feature_ioctl_set_irq(struct platform_device *pdev,
(hdr.start + hdr.count < hdr.start))
return -EINVAL;
fds = memdup_user((void __user *)(arg + sizeof(hdr)),
array_size(hdr.count, sizeof(s32)));
fds = memdup_array_user((void __user *)(arg + sizeof(hdr)),
hdr.count, sizeof(s32));
if (IS_ERR(fds))
return PTR_ERR(fds);

View File

@ -730,15 +730,13 @@ fw_name_fail:
return ret;
}
static int m10bmc_sec_remove(struct platform_device *pdev)
static void m10bmc_sec_remove(struct platform_device *pdev)
{
struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev);
firmware_upload_unregister(sec->fwl);
kfree(sec->fw_name);
xa_erase(&fw_upload_xa, sec->fw_name_id);
return 0;
}
static const struct platform_device_id intel_m10bmc_sec_ids[] = {
@ -760,7 +758,7 @@ MODULE_DEVICE_TABLE(platform, intel_m10bmc_sec_ids);
static struct platform_driver intel_m10bmc_sec_driver = {
.probe = m10bmc_sec_probe,
.remove = m10bmc_sec_remove,
.remove_new = m10bmc_sec_remove,
.driver = {
.name = "intel-m10bmc-sec-update",
.dev_groups = m10bmc_sec_attr_groups,

View File

@ -425,20 +425,18 @@ eprobe_mgr_put:
return ret;
}
static int of_fpga_region_remove(struct platform_device *pdev)
static void of_fpga_region_remove(struct platform_device *pdev)
{
struct fpga_region *region = platform_get_drvdata(pdev);
struct fpga_manager *mgr = region->mgr;
fpga_region_unregister(region);
fpga_mgr_put(mgr);
return 0;
}
static struct platform_driver of_fpga_region_driver = {
.probe = of_fpga_region_probe,
.remove = of_fpga_region_remove,
.remove_new = of_fpga_region_remove,
.driver = {
.name = "of-fpga-region",
.of_match_table = of_match_ptr(fpga_region_of_match),

View File

@ -517,15 +517,13 @@ static int socfpga_a10_fpga_probe(struct platform_device *pdev)
return 0;
}
static int socfpga_a10_fpga_remove(struct platform_device *pdev)
static void socfpga_a10_fpga_remove(struct platform_device *pdev)
{
struct fpga_manager *mgr = platform_get_drvdata(pdev);
struct a10_fpga_priv *priv = mgr->priv;
fpga_mgr_unregister(mgr);
clk_disable_unprepare(priv->clk);
return 0;
}
static const struct of_device_id socfpga_a10_fpga_of_match[] = {
@ -537,7 +535,7 @@ MODULE_DEVICE_TABLE(of, socfpga_a10_fpga_of_match);
static struct platform_driver socfpga_a10_fpga_driver = {
.probe = socfpga_a10_fpga_probe,
.remove = socfpga_a10_fpga_remove,
.remove_new = socfpga_a10_fpga_remove,
.driver = {
.name = "socfpga_a10_fpga_manager",
.of_match_table = socfpga_a10_fpga_of_match,

View File

@ -436,15 +436,13 @@ probe_err:
return ret;
}
static int s10_remove(struct platform_device *pdev)
static void s10_remove(struct platform_device *pdev)
{
struct fpga_manager *mgr = platform_get_drvdata(pdev);
struct s10_priv *priv = mgr->priv;
fpga_mgr_unregister(mgr);
stratix10_svc_free_channel(priv->chan);
return 0;
}
static const struct of_device_id s10_of_match[] = {
@ -457,7 +455,7 @@ MODULE_DEVICE_TABLE(of, s10_of_match);
static struct platform_driver s10_driver = {
.probe = s10_probe,
.remove = s10_remove,
.remove_new = s10_remove,
.driver = {
.name = "Stratix10 SoC FPGA manager",
.of_match_table = of_match_ptr(s10_of_match),

View File

@ -150,7 +150,7 @@ err_clk:
return err;
}
static int xlnx_pr_decoupler_remove(struct platform_device *pdev)
static void xlnx_pr_decoupler_remove(struct platform_device *pdev)
{
struct fpga_bridge *bridge = platform_get_drvdata(pdev);
struct xlnx_pr_decoupler_data *p = bridge->priv;
@ -158,13 +158,11 @@ static int xlnx_pr_decoupler_remove(struct platform_device *pdev)
fpga_bridge_unregister(bridge);
clk_unprepare(p->clk);
return 0;
}
static struct platform_driver xlnx_pr_decoupler_driver = {
.probe = xlnx_pr_decoupler_probe,
.remove = xlnx_pr_decoupler_remove,
.remove_new = xlnx_pr_decoupler_remove,
.driver = {
.name = "xlnx_pr_decoupler",
.of_match_table = xlnx_pr_decoupler_of_match,

View File

@ -618,7 +618,7 @@ static int zynq_fpga_probe(struct platform_device *pdev)
return 0;
}
static int zynq_fpga_remove(struct platform_device *pdev)
static void zynq_fpga_remove(struct platform_device *pdev)
{
struct zynq_fpga_priv *priv;
struct fpga_manager *mgr;
@ -629,8 +629,6 @@ static int zynq_fpga_remove(struct platform_device *pdev)
fpga_mgr_unregister(mgr);
clk_unprepare(priv->clk);
return 0;
}
#ifdef CONFIG_OF
@ -644,7 +642,7 @@ MODULE_DEVICE_TABLE(of, zynq_fpga_of_match);
static struct platform_driver zynq_fpga_driver = {
.probe = zynq_fpga_probe,
.remove = zynq_fpga_remove,
.remove_new = zynq_fpga_remove,
.driver = {
.name = "zynq_fpga_manager",
.of_match_table = of_match_ptr(zynq_fpga_of_match),

View File

@ -85,17 +85,31 @@ struct hdlc_payload {
void *buf;
};
/**
* struct hdlc_greybus_frame - Structure to represent greybus HDLC frame payload
*
* @cport: cport id
* @hdr: greybus operation header
* @payload: greybus message payload
*
* The HDLC payload sent over UART for greybus address has cport preappended to greybus message
*/
struct hdlc_greybus_frame {
__le16 cport;
struct gb_operation_msg_hdr hdr;
u8 payload[];
} __packed;
static void hdlc_rx_greybus_frame(struct gb_beagleplay *bg, u8 *buf, u16 len)
{
u16 cport_id;
struct gb_operation_msg_hdr *hdr = (struct gb_operation_msg_hdr *)buf;
memcpy(&cport_id, hdr->pad, sizeof(cport_id));
struct hdlc_greybus_frame *gb_frame = (struct hdlc_greybus_frame *)buf;
u16 cport_id = le16_to_cpu(gb_frame->cport);
u16 gb_msg_len = le16_to_cpu(gb_frame->hdr.size);
dev_dbg(&bg->sd->dev, "Greybus Operation %u type %X cport %u status %u received",
hdr->operation_id, hdr->type, cport_id, hdr->result);
gb_frame->hdr.operation_id, gb_frame->hdr.type, cport_id, gb_frame->hdr.result);
greybus_data_rcvd(bg->gb_hd, cport_id, buf, len);
greybus_data_rcvd(bg->gb_hd, cport_id, (u8 *)&gb_frame->hdr, gb_msg_len);
}
static void hdlc_rx_dbg_frame(const struct gb_beagleplay *bg, const char *buf, u16 len)
@ -336,25 +350,39 @@ static struct serdev_device_ops gb_beagleplay_ops = {
.write_wakeup = gb_tty_wakeup,
};
/**
* gb_message_send() - Send greybus message using HDLC over UART
*
* @hd: pointer to greybus host device
* @cport: AP cport where message originates
* @msg: greybus message to send
* @mask: gfp mask
*
* Greybus HDLC frame has the following payload:
* 1. le16 cport
* 2. gb_operation_msg_hdr msg_header
* 3. u8 *msg_payload
*/
static int gb_message_send(struct gb_host_device *hd, u16 cport, struct gb_message *msg, gfp_t mask)
{
struct gb_beagleplay *bg = dev_get_drvdata(&hd->dev);
struct hdlc_payload payloads[2];
struct hdlc_payload payloads[3];
__le16 cport_id = cpu_to_le16(cport);
dev_dbg(&hd->dev, "Sending greybus message with Operation %u, Type: %X on Cport %u",
msg->header->operation_id, msg->header->type, cport);
if (msg->header->size > RX_HDLC_PAYLOAD)
if (le16_to_cpu(msg->header->size) > RX_HDLC_PAYLOAD)
return dev_err_probe(&hd->dev, -E2BIG, "Greybus message too big");
memcpy(msg->header->pad, &cport, sizeof(cport));
payloads[0].buf = &cport_id;
payloads[0].len = sizeof(cport_id);
payloads[1].buf = msg->header;
payloads[1].len = sizeof(*msg->header);
payloads[2].buf = msg->payload;
payloads[2].len = msg->payload_size;
payloads[0].buf = msg->header;
payloads[0].len = sizeof(*msg->header);
payloads[1].buf = msg->payload;
payloads[1].len = msg->payload_size;
hdlc_tx_frames(bg, ADDRESS_GREYBUS, 0x03, payloads, 2);
hdlc_tx_frames(bg, ADDRESS_GREYBUS, 0x03, payloads, 3);
greybus_message_sent(bg->gb_hd, msg, 0);
return 0;

View File

@ -1093,6 +1093,7 @@ static int coresight_validate_source(struct coresight_device *csdev,
if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC &&
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE &&
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM &&
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) {
dev_err(&csdev->dev, "wrong device subtype in %s\n", function);
return -EINVAL;
@ -1162,6 +1163,7 @@ int coresight_enable(struct coresight_device *csdev)
per_cpu(tracer_path, cpu) = path;
break;
case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
/*
* Use the hash of source's device name as ID
@ -1212,6 +1214,7 @@ void coresight_disable(struct coresight_device *csdev)
per_cpu(tracer_path, cpu) = NULL;
break;
case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
/* Find the path by the hash. */

View File

@ -122,14 +122,13 @@ static int dummy_probe(struct platform_device *pdev)
return 0;
}
static int dummy_remove(struct platform_device *pdev)
static void dummy_remove(struct platform_device *pdev)
{
struct dummy_drvdata *drvdata = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
pm_runtime_disable(dev);
coresight_unregister(drvdata->csdev);
return 0;
}
static const struct of_device_id dummy_match[] = {
@ -140,7 +139,7 @@ static const struct of_device_id dummy_match[] = {
static struct platform_driver dummy_driver = {
.probe = dummy_probe,
.remove = dummy_remove,
.remove_new = dummy_remove,
.driver = {
.name = "coresight-dummy",
.of_match_table = dummy_match,

View File

@ -68,6 +68,7 @@ PMU_FORMAT_ATTR(preset, "config:0-3");
PMU_FORMAT_ATTR(sinkid, "config2:0-31");
/* config ID - set if a system configuration is selected */
PMU_FORMAT_ATTR(configid, "config2:32-63");
PMU_FORMAT_ATTR(cc_threshold, "config3:0-11");
/*
@ -101,6 +102,7 @@ static struct attribute *etm_config_formats_attr[] = {
&format_attr_preset.attr,
&format_attr_configid.attr,
&format_attr_branch_broadcast.attr,
&format_attr_cc_threshold.attr,
NULL,
};

View File

@ -644,7 +644,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
struct etmv4_config *config = &drvdata->config;
struct perf_event_attr *attr = &event->attr;
unsigned long cfg_hash;
int preset;
int preset, cc_threshold;
/* Clear configuration from previous run */
memset(config, 0, sizeof(struct etmv4_config));
@ -667,7 +667,12 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
if (attr->config & BIT(ETM_OPT_CYCACC)) {
config->cfg |= TRCCONFIGR_CCI;
/* TRM: Must program this for cycacc to work */
config->ccctlr = ETM_CYC_THRESHOLD_DEFAULT;
cc_threshold = attr->config3 & ETM_CYC_THRESHOLD_MASK;
if (!cc_threshold)
cc_threshold = ETM_CYC_THRESHOLD_DEFAULT;
if (cc_threshold < drvdata->ccitmin)
cc_threshold = drvdata->ccitmin;
config->ccctlr = cc_threshold;
}
if (attr->config & BIT(ETM_OPT_TS)) {
/*
@ -1150,6 +1155,41 @@ static void cpu_detect_trace_filtering(struct etmv4_drvdata *drvdata)
drvdata->trfcr = trfcr;
}
/*
* The following errata on applicable cpu ranges, affect the CCITMIN filed
* in TCRIDR3 register. Software read for the field returns 0x100 limiting
* the cycle threshold granularity, whereas the right value should have
* been 0x4, which is well supported in the hardware.
*/
static struct midr_range etm_wrong_ccitmin_cpus[] = {
/* Erratum #1490853 - Cortex-A76 */
MIDR_RANGE(MIDR_CORTEX_A76, 0, 0, 4, 0),
/* Erratum #1490853 - Neoverse-N1 */
MIDR_RANGE(MIDR_NEOVERSE_N1, 0, 0, 4, 0),
/* Erratum #1491015 - Cortex-A77 */
MIDR_RANGE(MIDR_CORTEX_A77, 0, 0, 1, 0),
/* Erratum #1502854 - Cortex-X1 */
MIDR_REV(MIDR_CORTEX_X1, 0, 0),
/* Erratum #1619801 - Neoverse-V1 */
MIDR_REV(MIDR_NEOVERSE_V1, 0, 0),
{},
};
static void etm4_fixup_wrong_ccitmin(struct etmv4_drvdata *drvdata)
{
/*
* Erratum affected cpus will read 256 as the minimum
* instruction trace cycle counting threshold whereas
* the correct value should be 4 instead. Override the
* recorded value for 'drvdata->ccitmin' to workaround
* this problem.
*/
if (is_midr_in_range_list(read_cpuid_id(), etm_wrong_ccitmin_cpus)) {
if (drvdata->ccitmin == 256)
drvdata->ccitmin = 4;
}
}
static void etm4_init_arch_data(void *info)
{
u32 etmidr0;
@ -1214,6 +1254,8 @@ static void etm4_init_arch_data(void *info)
etmidr3 = etm4x_relaxed_read32(csa, TRCIDR3);
/* CCITMIN, bits[11:0] minimum threshold value that can be programmed */
drvdata->ccitmin = FIELD_GET(TRCIDR3_CCITMIN_MASK, etmidr3);
etm4_fixup_wrong_ccitmin(drvdata);
/* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
drvdata->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
drvdata->config.s_ex_level = drvdata->s_ex_level;
@ -2261,7 +2303,7 @@ static void etm4_remove_amba(struct amba_device *adev)
etm4_remove_dev(drvdata);
}
static int etm4_remove_platform_dev(struct platform_device *pdev)
static void etm4_remove_platform_dev(struct platform_device *pdev)
{
struct etmv4_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
@ -2271,8 +2313,6 @@ static int etm4_remove_platform_dev(struct platform_device *pdev)
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
clk_put(drvdata->pclk);
return 0;
}
static const struct amba_id etm4_ids[] = {
@ -2358,7 +2398,7 @@ MODULE_DEVICE_TABLE(acpi, etm4x_acpi_ids);
static struct platform_driver etm4_platform_driver = {
.probe = etm4_probe_platform_dev,
.remove = etm4_remove_platform_dev,
.remove_new = etm4_remove_platform_dev,
.driver = {
.name = "coresight-etm4x",
.of_match_table = etm4_sysreg_match,

View File

@ -1036,7 +1036,7 @@ struct etmv4_drvdata {
u8 ctxid_size;
u8 vmid_size;
u8 ccsize;
u8 ccitmin;
u16 ccitmin;
u8 s_ex_level;
u8 ns_ex_level;
u8 q_support;

View File

@ -335,11 +335,10 @@ static int static_funnel_probe(struct platform_device *pdev)
return ret;
}
static int static_funnel_remove(struct platform_device *pdev)
static void static_funnel_remove(struct platform_device *pdev)
{
funnel_remove(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
}
static const struct of_device_id static_funnel_match[] = {
@ -360,7 +359,7 @@ MODULE_DEVICE_TABLE(acpi, static_funnel_ids);
static struct platform_driver static_funnel_driver = {
.probe = static_funnel_probe,
.remove = static_funnel_remove,
.remove_new = static_funnel_remove,
.driver = {
.name = "coresight-static-funnel",
/* THIS_MODULE is taken care of by platform_driver_register() */

View File

@ -320,11 +320,10 @@ static int static_replicator_probe(struct platform_device *pdev)
return ret;
}
static int static_replicator_remove(struct platform_device *pdev)
static void static_replicator_remove(struct platform_device *pdev)
{
replicator_remove(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
}
#ifdef CONFIG_PM
@ -373,7 +372,7 @@ MODULE_DEVICE_TABLE(acpi, static_replicator_acpi_ids);
static struct platform_driver static_replicator_driver = {
.probe = static_replicator_probe,
.remove = static_replicator_remove,
.remove_new = static_replicator_remove,
.driver = {
.name = "coresight-static-replicator",
/* THIS_MODULE is taken care of by platform_driver_register() */

View File

@ -10,6 +10,7 @@
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/io.h>
#include <linux/iommu.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
@ -344,7 +345,14 @@ static const struct attribute_group coresight_tmc_mgmt_group = {
.name = "mgmt",
};
static const struct attribute_group *coresight_tmc_groups[] = {
static const struct attribute_group *coresight_etf_groups[] = {
&coresight_tmc_group,
&coresight_tmc_mgmt_group,
NULL,
};
static const struct attribute_group *coresight_etr_groups[] = {
&coresight_etr_group,
&coresight_tmc_group,
&coresight_tmc_mgmt_group,
NULL,
@ -465,6 +473,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
drvdata->memwidth = tmc_get_memwidth(devid);
/* This device is not associated with a session */
drvdata->pid = -1;
drvdata->etr_mode = ETR_MODE_AUTO;
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
drvdata->size = tmc_etr_get_default_buffer_size(dev);
@ -474,16 +483,17 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
}
desc.dev = dev;
desc.groups = coresight_tmc_groups;
switch (drvdata->config_type) {
case TMC_CONFIG_TYPE_ETB:
desc.groups = coresight_etf_groups;
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc.ops = &tmc_etb_cs_ops;
dev_list = &etb_devs;
break;
case TMC_CONFIG_TYPE_ETR:
desc.groups = coresight_etr_groups;
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM;
desc.ops = &tmc_etr_cs_ops;
@ -496,6 +506,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
dev_list = &etr_devs;
break;
case TMC_CONFIG_TYPE_ETF:
desc.groups = coresight_etf_groups;
desc.type = CORESIGHT_DEV_TYPE_LINKSINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;

View File

@ -26,6 +26,12 @@ struct etr_flat_buf {
size_t size;
};
struct etr_buf_hw {
bool has_iommu;
bool has_etr_sg;
bool has_catu;
};
/*
* etr_perf_buffer - Perf buffer used for ETR
* @drvdata - The ETR drvdaga this buffer has been allocated for.
@ -830,6 +836,22 @@ static inline int tmc_etr_mode_alloc_buf(int mode,
}
}
static void get_etr_buf_hw(struct device *dev, struct etr_buf_hw *buf_hw)
{
struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
buf_hw->has_iommu = iommu_get_domain_for_dev(dev->parent);
buf_hw->has_etr_sg = tmc_etr_has_cap(drvdata, TMC_ETR_SG);
buf_hw->has_catu = !!tmc_etr_get_catu_device(drvdata);
}
static bool etr_can_use_flat_mode(struct etr_buf_hw *buf_hw, ssize_t etr_buf_size)
{
bool has_sg = buf_hw->has_catu || buf_hw->has_etr_sg;
return !has_sg || buf_hw->has_iommu || etr_buf_size < SZ_1M;
}
/*
* tmc_alloc_etr_buf: Allocate a buffer use by ETR.
* @drvdata : ETR device details.
@ -843,23 +865,22 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata,
int node, void **pages)
{
int rc = -ENOMEM;
bool has_etr_sg, has_iommu;
bool has_sg, has_catu;
struct etr_buf *etr_buf;
struct etr_buf_hw buf_hw;
struct device *dev = &drvdata->csdev->dev;
has_etr_sg = tmc_etr_has_cap(drvdata, TMC_ETR_SG);
has_iommu = iommu_get_domain_for_dev(dev->parent);
has_catu = !!tmc_etr_get_catu_device(drvdata);
has_sg = has_catu || has_etr_sg;
get_etr_buf_hw(dev, &buf_hw);
etr_buf = kzalloc(sizeof(*etr_buf), GFP_KERNEL);
if (!etr_buf)
return ERR_PTR(-ENOMEM);
etr_buf->size = size;
/* If there is user directive for buffer mode, try that first */
if (drvdata->etr_mode != ETR_MODE_AUTO)
rc = tmc_etr_mode_alloc_buf(drvdata->etr_mode, drvdata,
etr_buf, node, pages);
/*
* If we have to use an existing list of pages, we cannot reliably
* use a contiguous DMA memory (even if we have an IOMMU). Otherwise,
@ -872,14 +893,13 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata,
* Fallback to available mechanisms.
*
*/
if (!pages &&
(!has_sg || has_iommu || size < SZ_1M))
if (rc && !pages && etr_can_use_flat_mode(&buf_hw, size))
rc = tmc_etr_mode_alloc_buf(ETR_MODE_FLAT, drvdata,
etr_buf, node, pages);
if (rc && has_etr_sg)
if (rc && buf_hw.has_etr_sg)
rc = tmc_etr_mode_alloc_buf(ETR_MODE_ETR_SG, drvdata,
etr_buf, node, pages);
if (rc && has_catu)
if (rc && buf_hw.has_catu)
rc = tmc_etr_mode_alloc_buf(ETR_MODE_CATU, drvdata,
etr_buf, node, pages);
if (rc) {
@ -1804,3 +1824,70 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
return 0;
}
static const char *const buf_modes_str[] = {
[ETR_MODE_FLAT] = "flat",
[ETR_MODE_ETR_SG] = "tmc-sg",
[ETR_MODE_CATU] = "catu",
[ETR_MODE_AUTO] = "auto",
};
static ssize_t buf_modes_available_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct etr_buf_hw buf_hw;
ssize_t size = 0;
get_etr_buf_hw(dev, &buf_hw);
size += sysfs_emit(buf, "%s ", buf_modes_str[ETR_MODE_AUTO]);
size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_FLAT]);
if (buf_hw.has_etr_sg)
size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_ETR_SG]);
if (buf_hw.has_catu)
size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_CATU]);
size += sysfs_emit_at(buf, size, "\n");
return size;
}
static DEVICE_ATTR_RO(buf_modes_available);
static ssize_t buf_mode_preferred_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
return sysfs_emit(buf, "%s\n", buf_modes_str[drvdata->etr_mode]);
}
static ssize_t buf_mode_preferred_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etr_buf_hw buf_hw;
get_etr_buf_hw(dev, &buf_hw);
if (sysfs_streq(buf, buf_modes_str[ETR_MODE_FLAT]))
drvdata->etr_mode = ETR_MODE_FLAT;
else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_ETR_SG]) && buf_hw.has_etr_sg)
drvdata->etr_mode = ETR_MODE_ETR_SG;
else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_CATU]) && buf_hw.has_catu)
drvdata->etr_mode = ETR_MODE_CATU;
else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_AUTO]))
drvdata->etr_mode = ETR_MODE_AUTO;
else
return -EINVAL;
return size;
}
static DEVICE_ATTR_RW(buf_mode_preferred);
static struct attribute *coresight_etr_attrs[] = {
&dev_attr_buf_modes_available.attr,
&dev_attr_buf_mode_preferred.attr,
NULL,
};
const struct attribute_group coresight_etr_group = {
.attrs = coresight_etr_attrs,
};

View File

@ -135,6 +135,7 @@ enum etr_mode {
ETR_MODE_FLAT, /* Uses contiguous flat buffer */
ETR_MODE_ETR_SG, /* Uses in-built TMC ETR SG mechanism */
ETR_MODE_CATU, /* Use SG mechanism in CATU */
ETR_MODE_AUTO, /* Use the default mechanism */
};
struct etr_buf_operations;
@ -207,6 +208,7 @@ struct tmc_drvdata {
enum tmc_mem_intf_width memwidth;
u32 trigger_cntr;
u32 etr_caps;
enum etr_mode etr_mode;
struct idr idr;
struct mutex idr_mutex;
struct etr_buf *sysfs_buf;
@ -334,5 +336,6 @@ void tmc_etr_set_catu_ops(const struct etr_buf_operations *catu);
void tmc_etr_remove_catu_ops(void);
struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
enum cs_mode mode, void *data);
extern const struct attribute_group coresight_etr_group;
#endif

View File

@ -21,6 +21,80 @@
DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda");
static bool coresight_device_is_tpdm(struct coresight_device *csdev)
{
return (csdev->type == CORESIGHT_DEV_TYPE_SOURCE) &&
(csdev->subtype.source_subtype ==
CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM);
}
/*
* Read the DSB element size from the TPDM device
* Returns
* The dsb element size read from the devicetree if available.
* 0 - Otherwise, with a warning once.
*/
static int tpdm_read_dsb_element_size(struct coresight_device *csdev)
{
int rc = 0;
u8 size = 0;
rc = fwnode_property_read_u8(dev_fwnode(csdev->dev.parent),
"qcom,dsb-element-size", &size);
if (rc)
dev_warn_once(&csdev->dev,
"Failed to read TPDM DSB Element size: %d\n", rc);
return size;
}
/*
* Search and read element data size from the TPDM node in
* the devicetree. Each input port of TPDA is connected to
* a TPDM. Different TPDM supports different types of dataset,
* and some may support more than one type of dataset.
* Parameter "inport" is used to pass in the input port number
* of TPDA, and it is set to -1 in the recursize call.
*/
static int tpda_get_element_size(struct coresight_device *csdev,
int inport)
{
int dsb_size = -ENOENT;
int i, size;
struct coresight_device *in;
for (i = 0; i < csdev->pdata->nr_inconns; i++) {
in = csdev->pdata->in_conns[i]->src_dev;
if (!in)
continue;
/* Ignore the paths that do not match port */
if (inport > 0 &&
csdev->pdata->in_conns[i]->dest_port != inport)
continue;
if (coresight_device_is_tpdm(in)) {
size = tpdm_read_dsb_element_size(in);
} else {
/* Recurse down the path */
size = tpda_get_element_size(in, -1);
}
if (size < 0)
return size;
if (dsb_size < 0) {
/* Found a size, save it. */
dsb_size = size;
} else {
/* Found duplicate TPDMs */
return -EEXIST;
}
}
return dsb_size;
}
/* Settings pre enabling port control register */
static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
{
@ -32,26 +106,55 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
writel_relaxed(val, drvdata->base + TPDA_CR);
}
static void tpda_enable_port(struct tpda_drvdata *drvdata, int port)
static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
{
u32 val;
int size;
val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port));
/*
* Configure aggregator port n DSB data set element size
* Set the bit to 0 if the size is 32
* Set the bit to 1 if the size is 64
*/
size = tpda_get_element_size(drvdata->csdev, port);
switch (size) {
case 32:
val &= ~TPDA_Pn_CR_DSBSIZE;
break;
case 64:
val |= TPDA_Pn_CR_DSBSIZE;
break;
case 0:
return -EEXIST;
case -EEXIST:
dev_warn_once(&drvdata->csdev->dev,
"Detected multiple TPDMs on port %d", -EEXIST);
return -EEXIST;
default:
return -EINVAL;
}
/* Enable the port */
val |= TPDA_Pn_CR_ENA;
writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port));
return 0;
}
static void __tpda_enable(struct tpda_drvdata *drvdata, int port)
static int __tpda_enable(struct tpda_drvdata *drvdata, int port)
{
int ret;
CS_UNLOCK(drvdata->base);
if (!drvdata->csdev->enable)
tpda_enable_pre_port(drvdata);
tpda_enable_port(drvdata, port);
ret = tpda_enable_port(drvdata, port);
CS_LOCK(drvdata->base);
return ret;
}
static int tpda_enable(struct coresight_device *csdev,
@ -59,16 +162,19 @@ static int tpda_enable(struct coresight_device *csdev,
struct coresight_connection *out)
{
struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
int ret = 0;
spin_lock(&drvdata->spinlock);
if (atomic_read(&in->dest_refcnt) == 0)
__tpda_enable(drvdata, in->dest_port);
if (atomic_read(&in->dest_refcnt) == 0) {
ret = __tpda_enable(drvdata, in->dest_port);
if (!ret) {
atomic_inc(&in->dest_refcnt);
dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
}
}
atomic_inc(&in->dest_refcnt);
spin_unlock(&drvdata->spinlock);
dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
return 0;
return ret;
}
static void __tpda_disable(struct tpda_drvdata *drvdata, int port)

View File

@ -10,6 +10,8 @@
#define TPDA_Pn_CR(n) (0x004 + (n * 4))
/* Aggregator port enable bit */
#define TPDA_Pn_CR_ENA BIT(0)
/* Aggregator port DSB data set element size bit */
#define TPDA_Pn_CR_DSBSIZE BIT(8)
#define TPDA_MAX_INPORTS 32

View File

@ -4,6 +4,7 @@
*/
#include <linux/amba/bus.h>
#include <linux/bitfield.h>
#include <linux/bitmap.h>
#include <linux/coresight.h>
#include <linux/coresight-pmu.h>
@ -20,23 +21,265 @@
DEFINE_CORESIGHT_DEVLIST(tpdm_devs, "tpdm");
static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
/* Read dataset array member with the index number */
static ssize_t tpdm_simple_dataset_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct tpdm_dataset_attribute *tpdm_attr =
container_of(attr, struct tpdm_dataset_attribute, attr);
switch (tpdm_attr->mem) {
case DSB_EDGE_CTRL:
if (tpdm_attr->idx >= TPDM_DSB_MAX_EDCR)
return -EINVAL;
return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->edge_ctrl[tpdm_attr->idx]);
case DSB_EDGE_CTRL_MASK:
if (tpdm_attr->idx >= TPDM_DSB_MAX_EDCMR)
return -EINVAL;
return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->edge_ctrl_mask[tpdm_attr->idx]);
case DSB_TRIG_PATT:
if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)
return -EINVAL;
return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->trig_patt[tpdm_attr->idx]);
case DSB_TRIG_PATT_MASK:
if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)
return -EINVAL;
return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->trig_patt_mask[tpdm_attr->idx]);
case DSB_PATT:
if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)
return -EINVAL;
return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->patt_val[tpdm_attr->idx]);
case DSB_PATT_MASK:
if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)
return -EINVAL;
return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->patt_mask[tpdm_attr->idx]);
case DSB_MSR:
if (tpdm_attr->idx >= drvdata->dsb_msr_num)
return -EINVAL;
return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->msr[tpdm_attr->idx]);
}
return -EINVAL;
}
/* Write dataset array member with the index number */
static ssize_t tpdm_simple_dataset_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t size)
{
unsigned long val;
ssize_t ret = size;
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct tpdm_dataset_attribute *tpdm_attr =
container_of(attr, struct tpdm_dataset_attribute, attr);
if (kstrtoul(buf, 0, &val))
return -EINVAL;
spin_lock(&drvdata->spinlock);
switch (tpdm_attr->mem) {
case DSB_TRIG_PATT:
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
drvdata->dsb->trig_patt[tpdm_attr->idx] = val;
else
ret = -EINVAL;
break;
case DSB_TRIG_PATT_MASK:
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
drvdata->dsb->trig_patt_mask[tpdm_attr->idx] = val;
else
ret = -EINVAL;
break;
case DSB_PATT:
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
drvdata->dsb->patt_val[tpdm_attr->idx] = val;
else
ret = -EINVAL;
break;
case DSB_PATT_MASK:
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
drvdata->dsb->patt_mask[tpdm_attr->idx] = val;
else
ret = -EINVAL;
break;
case DSB_MSR:
if (tpdm_attr->idx < drvdata->dsb_msr_num)
drvdata->dsb->msr[tpdm_attr->idx] = val;
else
ret = -EINVAL;
break;
default:
ret = -EINVAL;
}
spin_unlock(&drvdata->spinlock);
return ret;
}
static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata)
{
return (drvdata->datasets & TPDM_PIDR0_DS_DSB);
}
static umode_t tpdm_dsb_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
struct device *dev = kobj_to_dev(kobj);
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
if (drvdata && tpdm_has_dsb_dataset(drvdata))
return attr->mode;
return 0;
}
static umode_t tpdm_dsb_msr_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
struct device *dev = kobj_to_dev(kobj);
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct device_attribute *dev_attr =
container_of(attr, struct device_attribute, attr);
struct tpdm_dataset_attribute *tpdm_attr =
container_of(dev_attr, struct tpdm_dataset_attribute, attr);
if (tpdm_attr->idx < drvdata->dsb_msr_num)
return attr->mode;
return 0;
}
static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata)
{
if (tpdm_has_dsb_dataset(drvdata)) {
memset(drvdata->dsb, 0, sizeof(struct dsb_dataset));
drvdata->dsb->trig_ts = true;
drvdata->dsb->trig_type = false;
}
}
static void set_dsb_mode(struct tpdm_drvdata *drvdata, u32 *val)
{
u32 mode;
/* Set the test accurate mode */
mode = TPDM_DSB_MODE_TEST(drvdata->dsb->mode);
*val &= ~TPDM_DSB_CR_TEST_MODE;
*val |= FIELD_PREP(TPDM_DSB_CR_TEST_MODE, mode);
/* Set the byte lane for high-performance mode */
mode = TPDM_DSB_MODE_HPBYTESEL(drvdata->dsb->mode);
*val &= ~TPDM_DSB_CR_HPSEL;
*val |= FIELD_PREP(TPDM_DSB_CR_HPSEL, mode);
/* Set the performance mode */
if (drvdata->dsb->mode & TPDM_DSB_MODE_PERF)
*val |= TPDM_DSB_CR_MODE;
else
*val &= ~TPDM_DSB_CR_MODE;
}
static void set_dsb_tier(struct tpdm_drvdata *drvdata)
{
u32 val;
/* Set the enable bit of DSB control register to 1 */
val = readl_relaxed(drvdata->base + TPDM_DSB_TIER);
/* Clear all relevant fields */
val &= ~(TPDM_DSB_TIER_PATT_TSENAB | TPDM_DSB_TIER_PATT_TYPE |
TPDM_DSB_TIER_XTRIG_TSENAB);
/* Set pattern timestamp type and enablement */
if (drvdata->dsb->patt_ts) {
val |= TPDM_DSB_TIER_PATT_TSENAB;
if (drvdata->dsb->patt_type)
val |= TPDM_DSB_TIER_PATT_TYPE;
else
val &= ~TPDM_DSB_TIER_PATT_TYPE;
} else {
val &= ~TPDM_DSB_TIER_PATT_TSENAB;
}
/* Set trigger timestamp */
if (drvdata->dsb->trig_ts)
val |= TPDM_DSB_TIER_XTRIG_TSENAB;
else
val &= ~TPDM_DSB_TIER_XTRIG_TSENAB;
writel_relaxed(val, drvdata->base + TPDM_DSB_TIER);
}
static void set_dsb_msr(struct tpdm_drvdata *drvdata)
{
int i;
for (i = 0; i < drvdata->dsb_msr_num; i++)
writel_relaxed(drvdata->dsb->msr[i],
drvdata->base + TPDM_DSB_MSR(i));
}
static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
{
u32 val, i;
for (i = 0; i < TPDM_DSB_MAX_EDCR; i++)
writel_relaxed(drvdata->dsb->edge_ctrl[i],
drvdata->base + TPDM_DSB_EDCR(i));
for (i = 0; i < TPDM_DSB_MAX_EDCMR; i++)
writel_relaxed(drvdata->dsb->edge_ctrl_mask[i],
drvdata->base + TPDM_DSB_EDCMR(i));
for (i = 0; i < TPDM_DSB_MAX_PATT; i++) {
writel_relaxed(drvdata->dsb->patt_val[i],
drvdata->base + TPDM_DSB_TPR(i));
writel_relaxed(drvdata->dsb->patt_mask[i],
drvdata->base + TPDM_DSB_TPMR(i));
writel_relaxed(drvdata->dsb->trig_patt[i],
drvdata->base + TPDM_DSB_XPR(i));
writel_relaxed(drvdata->dsb->trig_patt_mask[i],
drvdata->base + TPDM_DSB_XPMR(i));
}
set_dsb_tier(drvdata);
set_dsb_msr(drvdata);
val = readl_relaxed(drvdata->base + TPDM_DSB_CR);
/* Set the mode of DSB dataset */
set_dsb_mode(drvdata, &val);
/* Set trigger type */
if (drvdata->dsb->trig_type)
val |= TPDM_DSB_CR_TRIG_TYPE;
else
val &= ~TPDM_DSB_CR_TRIG_TYPE;
/* Set the enable bit of DSB control register to 1 */
val |= TPDM_DSB_CR_ENA;
writel_relaxed(val, drvdata->base + TPDM_DSB_CR);
}
/* TPDM enable operations */
/*
* TPDM enable operations
* The TPDM or Monitor serves as data collection component for various
* dataset types. It covers Basic Counts(BC), Tenure Counts(TC),
* Continuous Multi-Bit(CMB), Multi-lane CMB(MCMB) and Discrete Single
* Bit(DSB). This function will initialize the configuration according
* to the dataset type supported by the TPDM.
*/
static void __tpdm_enable(struct tpdm_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
/* Check if DSB datasets is present for TPDM. */
if (drvdata->datasets & TPDM_PIDR0_DS_DSB)
if (tpdm_has_dsb_dataset(drvdata))
tpdm_enable_dsb(drvdata);
CS_LOCK(drvdata->base);
@ -76,8 +319,7 @@ static void __tpdm_disable(struct tpdm_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
/* Check if DSB datasets is present for TPDM. */
if (drvdata->datasets & TPDM_PIDR0_DS_DSB)
if (tpdm_has_dsb_dataset(drvdata))
tpdm_disable_dsb(drvdata);
CS_LOCK(drvdata->base);
@ -110,17 +352,46 @@ static const struct coresight_ops tpdm_cs_ops = {
.source_ops = &tpdm_source_ops,
};
static void tpdm_init_default_data(struct tpdm_drvdata *drvdata)
static int tpdm_datasets_setup(struct tpdm_drvdata *drvdata)
{
u32 pidr;
CS_UNLOCK(drvdata->base);
/* Get the datasets present on the TPDM. */
pidr = readl_relaxed(drvdata->base + CORESIGHT_PERIPHIDR0);
drvdata->datasets |= pidr & GENMASK(TPDM_DATASETS - 1, 0);
CS_LOCK(drvdata->base);
if (tpdm_has_dsb_dataset(drvdata) && (!drvdata->dsb)) {
drvdata->dsb = devm_kzalloc(drvdata->dev,
sizeof(*drvdata->dsb), GFP_KERNEL);
if (!drvdata->dsb)
return -ENOMEM;
}
tpdm_reset_datasets(drvdata);
return 0;
}
static ssize_t reset_dataset_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t size)
{
int ret = 0;
unsigned long val;
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
ret = kstrtoul(buf, 0, &val);
if (ret || val != 1)
return -EINVAL;
spin_lock(&drvdata->spinlock);
tpdm_reset_datasets(drvdata);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_WO(reset_dataset);
/*
* value 1: 64 bits test data
* value 2: 32 bits test data
@ -161,6 +432,7 @@ static ssize_t integration_test_store(struct device *dev,
static DEVICE_ATTR_WO(integration_test);
static struct attribute *tpdm_attrs[] = {
&dev_attr_reset_dataset.attr,
&dev_attr_integration_test.attr,
NULL,
};
@ -169,8 +441,421 @@ static struct attribute_group tpdm_attr_grp = {
.attrs = tpdm_attrs,
};
static ssize_t dsb_mode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
return sysfs_emit(buf, "%x\n", drvdata->dsb->mode);
}
static ssize_t dsb_mode_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t size)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
if ((kstrtoul(buf, 0, &val)) || (val < 0) ||
(val & ~TPDM_DSB_MODE_MASK))
return -EINVAL;
spin_lock(&drvdata->spinlock);
drvdata->dsb->mode = val & TPDM_DSB_MODE_MASK;
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(dsb_mode);
static ssize_t ctrl_idx_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
return sysfs_emit(buf, "%u\n",
(unsigned int)drvdata->dsb->edge_ctrl_idx);
}
/*
* The EDCR registers can include up to 16 32-bit registers, and each
* one can be configured to control up to 16 edge detections(2 bits
* control one edge detection). So a total 256 edge detections can be
* configured. This function provides a way to set the index number of
* the edge detection which needs to be configured.
*/
static ssize_t ctrl_idx_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t size)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
if ((kstrtoul(buf, 0, &val)) || (val >= TPDM_DSB_MAX_LINES))
return -EINVAL;
spin_lock(&drvdata->spinlock);
drvdata->dsb->edge_ctrl_idx = val;
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(ctrl_idx);
/*
* This function is used to control the edge detection according
* to the index number that has been set.
* "edge_ctrl" should be one of the following values.
* 0 - Rising edge detection
* 1 - Falling edge detection
* 2 - Rising and falling edge detection (toggle detection)
*/
static ssize_t ctrl_val_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t size)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val, edge_ctrl;
int reg;
if ((kstrtoul(buf, 0, &edge_ctrl)) || (edge_ctrl > 0x2))
return -EINVAL;
spin_lock(&drvdata->spinlock);
/*
* There are 2 bit per DSB Edge Control line.
* Thus we have 16 lines in a 32bit word.
*/
reg = EDCR_TO_WORD_IDX(drvdata->dsb->edge_ctrl_idx);
val = drvdata->dsb->edge_ctrl[reg];
val &= ~EDCR_TO_WORD_MASK(drvdata->dsb->edge_ctrl_idx);
val |= EDCR_TO_WORD_VAL(edge_ctrl, drvdata->dsb->edge_ctrl_idx);
drvdata->dsb->edge_ctrl[reg] = val;
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_WO(ctrl_val);
static ssize_t ctrl_mask_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t size)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
u32 set;
int reg;
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
return -EINVAL;
spin_lock(&drvdata->spinlock);
/*
* There is 1 bit per DSB Edge Control Mark line.
* Thus we have 32 lines in a 32bit word.
*/
reg = EDCMR_TO_WORD_IDX(drvdata->dsb->edge_ctrl_idx);
set = drvdata->dsb->edge_ctrl_mask[reg];
if (val)
set |= BIT(EDCMR_TO_WORD_SHIFT(drvdata->dsb->edge_ctrl_idx));
else
set &= ~BIT(EDCMR_TO_WORD_SHIFT(drvdata->dsb->edge_ctrl_idx));
drvdata->dsb->edge_ctrl_mask[reg] = set;
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_WO(ctrl_mask);
static ssize_t enable_ts_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
return sysfs_emit(buf, "%u\n",
(unsigned int)drvdata->dsb->patt_ts);
}
/*
* value 1: Enable/Disable DSB pattern timestamp
*/
static ssize_t enable_ts_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t size)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
return -EINVAL;
spin_lock(&drvdata->spinlock);
drvdata->dsb->patt_ts = !!val;
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(enable_ts);
static ssize_t set_type_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
return sysfs_emit(buf, "%u\n",
(unsigned int)drvdata->dsb->patt_type);
}
/*
* value 1: Set DSB pattern type
*/
static ssize_t set_type_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
return -EINVAL;
spin_lock(&drvdata->spinlock);
drvdata->dsb->patt_type = val;
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(set_type);
static ssize_t dsb_trig_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
return sysfs_emit(buf, "%u\n",
(unsigned int)drvdata->dsb->trig_type);
}
/*
* Trigger type (boolean):
* false - Disable trigger type.
* true - Enable trigger type.
*/
static ssize_t dsb_trig_type_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t size)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
return -EINVAL;
spin_lock(&drvdata->spinlock);
if (val)
drvdata->dsb->trig_type = true;
else
drvdata->dsb->trig_type = false;
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(dsb_trig_type);
static ssize_t dsb_trig_ts_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
return sysfs_emit(buf, "%u\n",
(unsigned int)drvdata->dsb->trig_ts);
}
/*
* Trigger timestamp (boolean):
* false - Disable trigger timestamp.
* true - Enable trigger timestamp.
*/
static ssize_t dsb_trig_ts_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t size)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
return -EINVAL;
spin_lock(&drvdata->spinlock);
if (val)
drvdata->dsb->trig_ts = true;
else
drvdata->dsb->trig_ts = false;
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(dsb_trig_ts);
static struct attribute *tpdm_dsb_edge_attrs[] = {
&dev_attr_ctrl_idx.attr,
&dev_attr_ctrl_val.attr,
&dev_attr_ctrl_mask.attr,
DSB_EDGE_CTRL_ATTR(0),
DSB_EDGE_CTRL_ATTR(1),
DSB_EDGE_CTRL_ATTR(2),
DSB_EDGE_CTRL_ATTR(3),
DSB_EDGE_CTRL_ATTR(4),
DSB_EDGE_CTRL_ATTR(5),
DSB_EDGE_CTRL_ATTR(6),
DSB_EDGE_CTRL_ATTR(7),
DSB_EDGE_CTRL_ATTR(8),
DSB_EDGE_CTRL_ATTR(9),
DSB_EDGE_CTRL_ATTR(10),
DSB_EDGE_CTRL_ATTR(11),
DSB_EDGE_CTRL_ATTR(12),
DSB_EDGE_CTRL_ATTR(13),
DSB_EDGE_CTRL_ATTR(14),
DSB_EDGE_CTRL_ATTR(15),
DSB_EDGE_CTRL_MASK_ATTR(0),
DSB_EDGE_CTRL_MASK_ATTR(1),
DSB_EDGE_CTRL_MASK_ATTR(2),
DSB_EDGE_CTRL_MASK_ATTR(3),
DSB_EDGE_CTRL_MASK_ATTR(4),
DSB_EDGE_CTRL_MASK_ATTR(5),
DSB_EDGE_CTRL_MASK_ATTR(6),
DSB_EDGE_CTRL_MASK_ATTR(7),
NULL,
};
static struct attribute *tpdm_dsb_trig_patt_attrs[] = {
DSB_TRIG_PATT_ATTR(0),
DSB_TRIG_PATT_ATTR(1),
DSB_TRIG_PATT_ATTR(2),
DSB_TRIG_PATT_ATTR(3),
DSB_TRIG_PATT_ATTR(4),
DSB_TRIG_PATT_ATTR(5),
DSB_TRIG_PATT_ATTR(6),
DSB_TRIG_PATT_ATTR(7),
DSB_TRIG_PATT_MASK_ATTR(0),
DSB_TRIG_PATT_MASK_ATTR(1),
DSB_TRIG_PATT_MASK_ATTR(2),
DSB_TRIG_PATT_MASK_ATTR(3),
DSB_TRIG_PATT_MASK_ATTR(4),
DSB_TRIG_PATT_MASK_ATTR(5),
DSB_TRIG_PATT_MASK_ATTR(6),
DSB_TRIG_PATT_MASK_ATTR(7),
NULL,
};
static struct attribute *tpdm_dsb_patt_attrs[] = {
DSB_PATT_ATTR(0),
DSB_PATT_ATTR(1),
DSB_PATT_ATTR(2),
DSB_PATT_ATTR(3),
DSB_PATT_ATTR(4),
DSB_PATT_ATTR(5),
DSB_PATT_ATTR(6),
DSB_PATT_ATTR(7),
DSB_PATT_MASK_ATTR(0),
DSB_PATT_MASK_ATTR(1),
DSB_PATT_MASK_ATTR(2),
DSB_PATT_MASK_ATTR(3),
DSB_PATT_MASK_ATTR(4),
DSB_PATT_MASK_ATTR(5),
DSB_PATT_MASK_ATTR(6),
DSB_PATT_MASK_ATTR(7),
&dev_attr_enable_ts.attr,
&dev_attr_set_type.attr,
NULL,
};
static struct attribute *tpdm_dsb_msr_attrs[] = {
DSB_MSR_ATTR(0),
DSB_MSR_ATTR(1),
DSB_MSR_ATTR(2),
DSB_MSR_ATTR(3),
DSB_MSR_ATTR(4),
DSB_MSR_ATTR(5),
DSB_MSR_ATTR(6),
DSB_MSR_ATTR(7),
DSB_MSR_ATTR(8),
DSB_MSR_ATTR(9),
DSB_MSR_ATTR(10),
DSB_MSR_ATTR(11),
DSB_MSR_ATTR(12),
DSB_MSR_ATTR(13),
DSB_MSR_ATTR(14),
DSB_MSR_ATTR(15),
DSB_MSR_ATTR(16),
DSB_MSR_ATTR(17),
DSB_MSR_ATTR(18),
DSB_MSR_ATTR(19),
DSB_MSR_ATTR(20),
DSB_MSR_ATTR(21),
DSB_MSR_ATTR(22),
DSB_MSR_ATTR(23),
DSB_MSR_ATTR(24),
DSB_MSR_ATTR(25),
DSB_MSR_ATTR(26),
DSB_MSR_ATTR(27),
DSB_MSR_ATTR(28),
DSB_MSR_ATTR(29),
DSB_MSR_ATTR(30),
DSB_MSR_ATTR(31),
NULL,
};
static struct attribute *tpdm_dsb_attrs[] = {
&dev_attr_dsb_mode.attr,
&dev_attr_dsb_trig_ts.attr,
&dev_attr_dsb_trig_type.attr,
NULL,
};
static struct attribute_group tpdm_dsb_attr_grp = {
.attrs = tpdm_dsb_attrs,
.is_visible = tpdm_dsb_is_visible,
};
static struct attribute_group tpdm_dsb_edge_grp = {
.attrs = tpdm_dsb_edge_attrs,
.is_visible = tpdm_dsb_is_visible,
.name = "dsb_edge",
};
static struct attribute_group tpdm_dsb_trig_patt_grp = {
.attrs = tpdm_dsb_trig_patt_attrs,
.is_visible = tpdm_dsb_is_visible,
.name = "dsb_trig_patt",
};
static struct attribute_group tpdm_dsb_patt_grp = {
.attrs = tpdm_dsb_patt_attrs,
.is_visible = tpdm_dsb_is_visible,
.name = "dsb_patt",
};
static struct attribute_group tpdm_dsb_msr_grp = {
.attrs = tpdm_dsb_msr_attrs,
.is_visible = tpdm_dsb_msr_is_visible,
.name = "dsb_msr",
};
static const struct attribute_group *tpdm_attr_grps[] = {
&tpdm_attr_grp,
&tpdm_dsb_attr_grp,
&tpdm_dsb_edge_grp,
&tpdm_dsb_trig_patt_grp,
&tpdm_dsb_patt_grp,
&tpdm_dsb_msr_grp,
NULL,
};
@ -181,6 +866,7 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
struct coresight_platform_data *pdata;
struct tpdm_drvdata *drvdata;
struct coresight_desc desc = { 0 };
int ret;
pdata = coresight_get_platform_data(dev);
if (IS_ERR(pdata))
@ -200,12 +886,20 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
drvdata->base = base;
ret = tpdm_datasets_setup(drvdata);
if (ret)
return ret;
if (drvdata && tpdm_has_dsb_dataset(drvdata))
of_property_read_u32(drvdata->dev->of_node,
"qcom,dsb-msrs-num", &drvdata->dsb_msr_num);
/* Set up coresight component description */
desc.name = coresight_alloc_device_name(&tpdm_devs, dev);
if (!desc.name)
return -ENOMEM;
desc.type = CORESIGHT_DEV_TYPE_SOURCE;
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS;
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM;
desc.ops = &tpdm_cs_ops;
desc.pdata = adev->dev.platform_data;
desc.dev = &adev->dev;
@ -216,7 +910,7 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
return PTR_ERR(drvdata->csdev);
spin_lock_init(&drvdata->spinlock);
tpdm_init_default_data(drvdata);
/* Decrease pm refcount when probe is done.*/
pm_runtime_put(&adev->dev);

View File

@ -11,8 +11,52 @@
/* DSB Subunit Registers */
#define TPDM_DSB_CR (0x780)
#define TPDM_DSB_TIER (0x784)
#define TPDM_DSB_TPR(n) (0x788 + (n * 4))
#define TPDM_DSB_TPMR(n) (0x7A8 + (n * 4))
#define TPDM_DSB_XPR(n) (0x7C8 + (n * 4))
#define TPDM_DSB_XPMR(n) (0x7E8 + (n * 4))
#define TPDM_DSB_EDCR(n) (0x808 + (n * 4))
#define TPDM_DSB_EDCMR(n) (0x848 + (n * 4))
#define TPDM_DSB_MSR(n) (0x980 + (n * 4))
/* Enable bit for DSB subunit */
#define TPDM_DSB_CR_ENA BIT(0)
/* Enable bit for DSB subunit perfmance mode */
#define TPDM_DSB_CR_MODE BIT(1)
/* Enable bit for DSB subunit trigger type */
#define TPDM_DSB_CR_TRIG_TYPE BIT(12)
/* Data bits for DSB high performace mode */
#define TPDM_DSB_CR_HPSEL GENMASK(6, 2)
/* Data bits for DSB test mode */
#define TPDM_DSB_CR_TEST_MODE GENMASK(10, 9)
/* Enable bit for DSB subunit pattern timestamp */
#define TPDM_DSB_TIER_PATT_TSENAB BIT(0)
/* Enable bit for DSB subunit trigger timestamp */
#define TPDM_DSB_TIER_XTRIG_TSENAB BIT(1)
/* Bit for DSB subunit pattern type */
#define TPDM_DSB_TIER_PATT_TYPE BIT(2)
/* DSB programming modes */
/* DSB mode bits mask */
#define TPDM_DSB_MODE_MASK GENMASK(8, 0)
/* Test mode control bit*/
#define TPDM_DSB_MODE_TEST(val) (val & GENMASK(1, 0))
/* Performance mode */
#define TPDM_DSB_MODE_PERF BIT(3)
/* High performance mode */
#define TPDM_DSB_MODE_HPBYTESEL(val) (val & GENMASK(8, 4))
#define EDCRS_PER_WORD 16
#define EDCR_TO_WORD_IDX(r) ((r) / EDCRS_PER_WORD)
#define EDCR_TO_WORD_SHIFT(r) ((r % EDCRS_PER_WORD) * 2)
#define EDCR_TO_WORD_VAL(val, r) (val << EDCR_TO_WORD_SHIFT(r))
#define EDCR_TO_WORD_MASK(r) EDCR_TO_WORD_VAL(0x3, r)
#define EDCMRS_PER_WORD 32
#define EDCMR_TO_WORD_IDX(r) ((r) / EDCMRS_PER_WORD)
#define EDCMR_TO_WORD_SHIFT(r) ((r) % EDCMRS_PER_WORD)
/* TPDM integration test registers */
#define TPDM_ITATBCNTRL (0xEF0)
@ -40,6 +84,95 @@
#define TPDM_PIDR0_DS_IMPDEF BIT(0)
#define TPDM_PIDR0_DS_DSB BIT(1)
#define TPDM_DSB_MAX_LINES 256
/* MAX number of EDCR registers */
#define TPDM_DSB_MAX_EDCR 16
/* MAX number of EDCMR registers */
#define TPDM_DSB_MAX_EDCMR 8
/* MAX number of DSB pattern */
#define TPDM_DSB_MAX_PATT 8
/* MAX number of DSB MSR */
#define TPDM_DSB_MAX_MSR 32
#define tpdm_simple_dataset_ro(name, mem, idx) \
(&((struct tpdm_dataset_attribute[]) { \
{ \
__ATTR(name, 0444, tpdm_simple_dataset_show, NULL), \
mem, \
idx, \
} \
})[0].attr.attr)
#define tpdm_simple_dataset_rw(name, mem, idx) \
(&((struct tpdm_dataset_attribute[]) { \
{ \
__ATTR(name, 0644, tpdm_simple_dataset_show, \
tpdm_simple_dataset_store), \
mem, \
idx, \
} \
})[0].attr.attr)
#define DSB_EDGE_CTRL_ATTR(nr) \
tpdm_simple_dataset_ro(edcr##nr, \
DSB_EDGE_CTRL, nr)
#define DSB_EDGE_CTRL_MASK_ATTR(nr) \
tpdm_simple_dataset_ro(edcmr##nr, \
DSB_EDGE_CTRL_MASK, nr)
#define DSB_TRIG_PATT_ATTR(nr) \
tpdm_simple_dataset_rw(xpr##nr, \
DSB_TRIG_PATT, nr)
#define DSB_TRIG_PATT_MASK_ATTR(nr) \
tpdm_simple_dataset_rw(xpmr##nr, \
DSB_TRIG_PATT_MASK, nr)
#define DSB_PATT_ATTR(nr) \
tpdm_simple_dataset_rw(tpr##nr, \
DSB_PATT, nr)
#define DSB_PATT_MASK_ATTR(nr) \
tpdm_simple_dataset_rw(tpmr##nr, \
DSB_PATT_MASK, nr)
#define DSB_MSR_ATTR(nr) \
tpdm_simple_dataset_rw(msr##nr, \
DSB_MSR, nr)
/**
* struct dsb_dataset - specifics associated to dsb dataset
* @mode: DSB programming mode
* @edge_ctrl_idx Index number of the edge control
* @edge_ctrl: Save value for edge control
* @edge_ctrl_mask: Save value for edge control mask
* @patt_val: Save value for pattern
* @patt_mask: Save value for pattern mask
* @trig_patt: Save value for trigger pattern
* @trig_patt_mask: Save value for trigger pattern mask
* @msr Save value for MSR
* @patt_ts: Enable/Disable pattern timestamp
* @patt_type: Set pattern type
* @trig_ts: Enable/Disable trigger timestamp.
* @trig_type: Enable/Disable trigger type.
*/
struct dsb_dataset {
u32 mode;
u32 edge_ctrl_idx;
u32 edge_ctrl[TPDM_DSB_MAX_EDCR];
u32 edge_ctrl_mask[TPDM_DSB_MAX_EDCMR];
u32 patt_val[TPDM_DSB_MAX_PATT];
u32 patt_mask[TPDM_DSB_MAX_PATT];
u32 trig_patt[TPDM_DSB_MAX_PATT];
u32 trig_patt_mask[TPDM_DSB_MAX_PATT];
u32 msr[TPDM_DSB_MAX_MSR];
bool patt_ts;
bool patt_type;
bool trig_ts;
bool trig_type;
};
/**
* struct tpdm_drvdata - specifics associated to an TPDM component
* @base: memory mapped base address for this component.
@ -48,6 +181,8 @@
* @spinlock: lock for the drvdata value.
* @enable: enable status of the component.
* @datasets: The datasets types present of the TPDM.
* @dsb Specifics associated to TPDM DSB.
* @dsb_msr_num Number of MSR supported by DSB TPDM
*/
struct tpdm_drvdata {
@ -57,6 +192,32 @@ struct tpdm_drvdata {
spinlock_t spinlock;
bool enable;
unsigned long datasets;
struct dsb_dataset *dsb;
u32 dsb_msr_num;
};
/* Enumerate members of various datasets */
enum dataset_mem {
DSB_EDGE_CTRL,
DSB_EDGE_CTRL_MASK,
DSB_TRIG_PATT,
DSB_TRIG_PATT_MASK,
DSB_PATT,
DSB_PATT_MASK,
DSB_MSR,
};
/**
* struct tpdm_dataset_attribute - Record the member variables and
* index number of datasets that need to be operated by sysfs file
* @attr: The device attribute
* @mem: The member in the dataset data structure
* @idx: The index number of the array data
*/
struct tpdm_dataset_attribute {
struct device_attribute attr;
enum dataset_mem mem;
u32 idx;
};
#endif /* _CORESIGHT_CORESIGHT_TPDM_H */

View File

@ -1253,8 +1253,18 @@ static void arm_trbe_register_coresight_cpu(struct trbe_drvdata *drvdata, int cp
desc.name = devm_kasprintf(dev, GFP_KERNEL, "trbe%d", cpu);
if (!desc.name)
goto cpu_clear;
desc.pdata = coresight_get_platform_data(dev);
/*
* TRBE coresight devices do not need regular connections
* information, as the paths get built between all percpu
* source and their respective percpu sink devices. Though
* coresight_register() expect device connections via the
* platform_data, which TRBE devices do not have. As they
* are not real ACPI devices, coresight_get_platform_data()
* ends up failing. Instead let's allocate a dummy zeroed
* coresight_platform_data structure and assign that back
* into the device for that purpose.
*/
desc.pdata = devm_kzalloc(dev, sizeof(*desc.pdata), GFP_KERNEL);
if (IS_ERR(desc.pdata))
goto cpu_clear;
@ -1520,14 +1530,13 @@ probe_failed:
return ret;
}
static int arm_trbe_device_remove(struct platform_device *pdev)
static void arm_trbe_device_remove(struct platform_device *pdev)
{
struct trbe_drvdata *drvdata = platform_get_drvdata(pdev);
arm_trbe_remove_cpuhp(drvdata);
arm_trbe_remove_coresight(drvdata);
arm_trbe_remove_irq(drvdata);
return 0;
}
static const struct of_device_id arm_trbe_of_match[] = {
@ -1536,14 +1545,23 @@ static const struct of_device_id arm_trbe_of_match[] = {
};
MODULE_DEVICE_TABLE(of, arm_trbe_of_match);
#ifdef CONFIG_ACPI
static const struct platform_device_id arm_trbe_acpi_match[] = {
{ ARMV8_TRBE_PDEV_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(platform, arm_trbe_acpi_match);
#endif
static struct platform_driver arm_trbe_driver = {
.id_table = ACPI_PTR(arm_trbe_acpi_match),
.driver = {
.name = DRVNAME,
.of_match_table = of_match_ptr(arm_trbe_of_match),
.suppress_bind_attrs = true,
},
.probe = arm_trbe_device_probe,
.remove = arm_trbe_device_remove,
.remove_new = arm_trbe_device_remove,
};
static int __init arm_trbe_init(void)

Some files were not shown because too many files have changed in this diff Show More