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:
7
.mailmap
7
.mailmap
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -362,6 +362,8 @@ 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:
|
||||
@ -369,6 +371,15 @@ Description:
|
||||
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.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_xyz_squared_peak_raw
|
||||
KernelVersion: 2.6.36
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
@ -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.
|
||||
|
21
Documentation/ABI/testing/sysfs-nvmem-cells
Normal file
21
Documentation/ABI/testing/sysfs-nvmem-cells
Normal 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
|
@ -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 |
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
139
Documentation/devicetree/bindings/iio/adc/maxim,max34408.yaml
Normal file
139
Documentation/devicetree/bindings/iio/adc/maxim,max34408.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
@ -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>;
|
||||
|
@ -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>;
|
||||
|
@ -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";
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
};
|
@ -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>;
|
||||
};
|
||||
};
|
@ -25,6 +25,10 @@ properties:
|
||||
|
||||
spi-cpol: true
|
||||
|
||||
spi-cs-inactive-delay-ns:
|
||||
minimum: 16000
|
||||
default: 16000
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
|
@ -47,6 +47,10 @@ properties:
|
||||
spi-max-frequency:
|
||||
maximum: 2000000
|
||||
|
||||
spi-cs-inactive-delay-ns:
|
||||
minimum: 16000
|
||||
default: 16000
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
|
77
Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml
Normal file
77
Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml
Normal 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";
|
||||
};
|
||||
};
|
@ -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>;
|
||||
};
|
||||
};
|
@ -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>;
|
||||
};
|
||||
};
|
||||
...
|
@ -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>;
|
||||
};
|
||||
};
|
||||
...
|
@ -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: |
|
||||
|
@ -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
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
@ -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
|
||||
|
@ -24,6 +24,7 @@ properties:
|
||||
- st,stm32f4-otp
|
||||
- st,stm32mp13-bsec
|
||||
- st,stm32mp15-bsec
|
||||
- st,stm32mp25-bsec
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -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
|
||||
|
@ -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,.*":
|
||||
|
44
Documentation/devicetree/bindings/w1/amd,axi-1wire-host.yaml
Normal file
44
Documentation/devicetree/bindings/w1/amd,axi-1wire-host.yaml
Normal file
@ -0,0 +1,44 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/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>;
|
||||
};
|
||||
|
||||
...
|
@ -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
|
||||
-------------------------
|
||||
|
85
MAINTAINERS
85
MAINTAINERS
@ -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
|
||||
@ -14278,6 +14341,7 @@ MICROCHIP MCP3564 ADC DRIVER
|
||||
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
|
||||
|
||||
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -2077,8 +2077,7 @@ 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_offset = parent->buffer - buffer->user_data +
|
||||
fda->parent_offset;
|
||||
for (fd_index = 0; fd_index < fda->num_fds;
|
||||
fd_index++) {
|
||||
@ -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
@ -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;
|
||||
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,26 +119,25 @@ 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,
|
||||
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 *
|
||||
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,
|
||||
unsigned long user_ptr);
|
||||
void binder_alloc_free_buf(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffer);
|
||||
extern int binder_alloc_mmap_handler(struct binder_alloc *alloc,
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,76 +330,34 @@ 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 int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
|
||||
struct mhi_ep_ring *ring,
|
||||
struct mhi_result *result,
|
||||
u32 len)
|
||||
static void mhi_ep_read_completion(struct mhi_ep_buf_info *buf_info)
|
||||
{
|
||||
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_ring_element *el;
|
||||
bool tr_done = false;
|
||||
void *write_addr;
|
||||
u64 read_addr;
|
||||
u32 buf_left;
|
||||
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;
|
||||
|
||||
buf_left = len;
|
||||
if (mhi_chan->xfer_cb) {
|
||||
result.buf_addr = buf_info->cb_buf;
|
||||
result.dir = mhi_chan->dir;
|
||||
result.bytes_xferd = buf_info->size;
|
||||
|
||||
do {
|
||||
/* Don't process the transfer ring if the channel is not in RUNNING state */
|
||||
if (mhi_chan->state != MHI_CH_STATE_RUNNING) {
|
||||
dev_err(dev, "Channel not available\n");
|
||||
return -ENODEV;
|
||||
mhi_chan->xfer_cb(mhi_dev, &result);
|
||||
}
|
||||
|
||||
el = &ring->ring_cache[ring->rd_offset];
|
||||
|
||||
/* Check if there is data pending to be read from previous read operation */
|
||||
if (mhi_chan->tre_bytes_left) {
|
||||
dev_dbg(dev, "TRE bytes remaining: %u\n", mhi_chan->tre_bytes_left);
|
||||
tr_len = min(buf_left, mhi_chan->tre_bytes_left);
|
||||
} else {
|
||||
mhi_chan->tre_loc = MHI_TRE_DATA_GET_PTR(el);
|
||||
mhi_chan->tre_size = MHI_TRE_DATA_GET_LEN(el);
|
||||
mhi_chan->tre_bytes_left = mhi_chan->tre_size;
|
||||
|
||||
tr_len = min(buf_left, mhi_chan->tre_size);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
if (ret < 0) {
|
||||
dev_err(&mhi_chan->mhi_dev->dev, "Error reading from channel\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 (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
|
||||
@ -362,7 +370,7 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
|
||||
if (ret < 0) {
|
||||
dev_err(&mhi_chan->mhi_dev->dev,
|
||||
"Error sending transfer compl. event\n");
|
||||
return ret;
|
||||
goto err_free_tre_buf;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -378,27 +386,102 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
|
||||
if (ret < 0) {
|
||||
dev_err(&mhi_chan->mhi_dev->dev,
|
||||
"Error sending transfer compl. event\n");
|
||||
return ret;
|
||||
goto err_free_tre_buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tr_done = true;
|
||||
}
|
||||
|
||||
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_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 *buf_addr;
|
||||
u32 buf_left;
|
||||
int ret;
|
||||
|
||||
buf_left = len;
|
||||
|
||||
do {
|
||||
/* Don't process the transfer ring if the channel is not in RUNNING state */
|
||||
if (mhi_chan->state != MHI_CH_STATE_RUNNING) {
|
||||
dev_err(dev, "Channel not available\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
result->bytes_xferd += tr_len;
|
||||
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) {
|
||||
dev_dbg(dev, "TRE bytes remaining: %u\n", mhi_chan->tre_bytes_left);
|
||||
tr_len = min(buf_left, mhi_chan->tre_bytes_left);
|
||||
} else {
|
||||
mhi_chan->tre_loc = MHI_TRE_DATA_GET_PTR(el);
|
||||
mhi_chan->tre_size = MHI_TRE_DATA_GET_LEN(el);
|
||||
mhi_chan->tre_bytes_left = mhi_chan->tre_size;
|
||||
|
||||
tr_len = min(buf_left, mhi_chan->tre_size);
|
||||
}
|
||||
|
||||
read_offset = mhi_chan->tre_size - mhi_chan->tre_bytes_left;
|
||||
write_offset = len - buf_left;
|
||||
|
||||
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_async(mhi_cntrl, &buf_info);
|
||||
if (ret < 0) {
|
||||
dev_err(&mhi_chan->mhi_dev->dev, "Error reading from channel\n");
|
||||
goto err_free_buf_addr;
|
||||
}
|
||||
|
||||
buf_left -= tr_len;
|
||||
mhi_chan->tre_bytes_left -= tr_len;
|
||||
|
||||
if (!mhi_chan->tre_bytes_left) {
|
||||
if (MHI_TRE_DATA_GET_IEOT(el))
|
||||
tr_done = true;
|
||||
|
||||
mhi_chan->rd_offset = (mhi_chan->rd_offset + 1) % ring->ring_size;
|
||||
}
|
||||
} 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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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,9 +1227,11 @@ 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);
|
||||
eot = !!(flags & MHI_EOT);
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) */
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 |
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,8 +1340,7 @@ 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);
|
||||
|
||||
@ -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;
|
||||
|
||||
feature_check_enabled = true;
|
||||
}
|
||||
|
||||
if (!feature_check_enabled) {
|
||||
ret = do_feature_check_call(PM_FEATURE_CHECK);
|
||||
if (ret >= 0)
|
||||
if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_1))
|
||||
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);
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
|
@ -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. */
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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() */
|
||||
|
@ -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() */
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __tpda_disable(struct tpda_drvdata *drvdata, int port)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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
Reference in New Issue
Block a user