Char / Misc / Other smaller driver subsystem updates for 5.19-rc1
Here is the large set of char, misc, and other driver subsystem updates for 5.19-rc1. The merge request for this has been delayed as I wanted to get lots of linux-next testing due to some late arrivals of changes for the habannalabs driver. Highlights of this merge are: - habanalabs driver updates for new hardware types and fixes and other updates - IIO driver tree merge which includes loads of new IIO drivers and cleanups and additions - PHY driver tree merge with new drivers and small updates to existing ones - interconnect driver tree merge with fixes and updates - soundwire driver tree merge with some small fixes - coresight driver tree merge with small fixes and updates - mhi bus driver tree merge with lots of updates and new device support - firmware driver updates - fpga driver updates - lkdtm driver updates (with a merge conflict, more on that below) - extcon driver tree merge with small updates - lots of other tiny driver updates and fixes and cleanups, full details in the shortlog. All of these have been in linux-next for almost 2 weeks with no reported problems. Note, there are 3 merge conflicts when merging this with your tree: - MAINTAINERS, should be easy to resolve - drivers/slimbus/qcom-ctrl.c, should be straightforward resolution - drivers/misc/lkdtm/stackleak.c, not an easy resolution. This has been noted in the linux-next tree for a while, and resolved there, here's a link to the resolution that Stephen came up with and that Kees says is correct: https://lore.kernel.org/r/20220509185344.3fe1a354@canb.auug.org.au I will be glad to provide a merge point that contains these resolutions if that makes things any easier for you. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYpnkbA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ylOrgCggbbAFwESBY9o2YfpG+2VOLpc0GAAoJgY1XN8 P/gumbLEpFvoBZ5xLIW8 =KCgk -----END PGP SIGNATURE----- Merge tag 'char-misc-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc Pull char / misc / other smaller driver subsystem updates from Greg KH: "Here is the large set of char, misc, and other driver subsystem updates for 5.19-rc1. The merge request for this has been delayed as I wanted to get lots of linux-next testing due to some late arrivals of changes for the habannalabs driver. Highlights of this merge are: - habanalabs driver updates for new hardware types and fixes and other updates - IIO driver tree merge which includes loads of new IIO drivers and cleanups and additions - PHY driver tree merge with new drivers and small updates to existing ones - interconnect driver tree merge with fixes and updates - soundwire driver tree merge with some small fixes - coresight driver tree merge with small fixes and updates - mhi bus driver tree merge with lots of updates and new device support - firmware driver updates - fpga driver updates - lkdtm driver updates (with a merge conflict, more on that below) - extcon driver tree merge with small updates - lots of other tiny driver updates and fixes and cleanups, full details in the shortlog. All of these have been in linux-next for almost 2 weeks with no reported problems" * tag 'char-misc-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (387 commits) habanalabs: use separate structure info for each error collect data habanalabs: fix missing handle shift during mmap habanalabs: remove hdev from hl_ctx_get args habanalabs: do MMU prefetch as deferred work habanalabs: order memory manager messages habanalabs: return -EFAULT on copy_to_user error habanalabs: use NULL for eventfd habanalabs: update firmware header habanalabs: add support for notification via eventfd habanalabs: add topic to memory manager buffer habanalabs: handle race in driver fini habanalabs: add device memory scrub ability through debugfs habanalabs: use unified memory manager for CB flow habanalabs: unified memory manager new code for CB flow habanalabs/gaudi: set arbitration timeout to a high value habanalabs: add put by handle method to memory manager habanalabs: hide memory manager page shift habanalabs: Add separate poll interval value for protocol habanalabs: use get_task_pid() to take PID habanalabs: add prefetch flag to the MAP operation ...
This commit is contained in:
commit
6f9b5ed8ca
@ -19,3 +19,13 @@ Description: The file holds the OEM PK Hash value of the endpoint device
|
||||
read without having the device power on at least once, the file
|
||||
will read all 0's.
|
||||
Users: Any userspace application or clients interested in device info.
|
||||
|
||||
What: /sys/bus/mhi/devices/.../soc_reset
|
||||
Date: April 2022
|
||||
KernelVersion: 5.19
|
||||
Contact: mhi@lists.linux.dev
|
||||
Description: Initiates a SoC reset on the MHI controller. A SoC reset is
|
||||
a reset of last resort, and will require a complete re-init.
|
||||
This can be useful as a method of recovery if the device is
|
||||
non-responsive, or as a means of loading new firmware as a
|
||||
system administration task.
|
||||
|
@ -170,6 +170,20 @@ KernelVersion: 5.1
|
||||
Contact: ogabbay@kernel.org
|
||||
Description: Sets the state of the third S/W led on the device
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/memory_scrub
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Contact: dhirschfeld@habana.ai
|
||||
Description: Allows the root user to scrub the dram memory. The scrubbing
|
||||
value can be set using the debugfs file memory_scrub_val.
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/memory_scrub_val
|
||||
Date: May 2022
|
||||
KernelVersion: 5.19
|
||||
Contact: dhirschfeld@habana.ai
|
||||
Description: The value to which the dram will be set to when the user
|
||||
scrubs the dram using 'memory_scrub' debugfs file
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/mmu
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
@ -190,6 +204,30 @@ Description: Check and display page fault or access violation mmu errors for
|
||||
echo "0x200" > /sys/kernel/debug/habanalabs/hl0/mmu_error
|
||||
cat /sys/kernel/debug/habanalabs/hl0/mmu_error
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/monitor_dump
|
||||
Date: Mar 2022
|
||||
KernelVersion: 5.19
|
||||
Contact: osharabi@habana.ai
|
||||
Description: Allows the root user to dump monitors status from the device's
|
||||
protected config space.
|
||||
This property is a binary blob that contains the result of the
|
||||
monitors registers dump.
|
||||
This custom interface is needed (instead of using the generic
|
||||
Linux user-space PCI mapping) because this space is protected
|
||||
and cannot be accessed using PCI read.
|
||||
This interface doesn't support concurrency in the same device.
|
||||
Only supported on GAUDI.
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/monitor_dump_trig
|
||||
Date: Mar 2022
|
||||
KernelVersion: 5.19
|
||||
Contact: osharabi@habana.ai
|
||||
Description: Triggers dump of monitor data. The value to trigger the operation
|
||||
must be 1. Triggering the monitor dump operation initiates dump of
|
||||
current registers values of all monitors.
|
||||
When the write is finished, the user can read the "monitor_dump"
|
||||
blob
|
||||
|
||||
What: /sys/kernel/debug/habanalabs/hl<n>/set_power_state
|
||||
Date: Jan 2019
|
||||
KernelVersion: 5.1
|
||||
|
@ -20,11 +20,12 @@ properties:
|
||||
enum:
|
||||
- siliconmitus,sm5502-muic
|
||||
- siliconmitus,sm5504-muic
|
||||
- siliconmitus,sm5703-muic
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: I2C slave address of the device. Usually 0x25 for SM5502,
|
||||
0x14 for SM5504.
|
||||
description: I2C slave address of the device. Usually 0x25 for SM5502
|
||||
and SM5703, 0x14 for SM5504.
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
@ -19,7 +19,8 @@ properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- renesas,r9a07g044-adc # RZ/G2{L,LC}
|
||||
- renesas,r9a07g044-adc # RZ/G2L
|
||||
- renesas,r9a07g054-adc # RZ/V2L
|
||||
- const: renesas,rzg2l-adc
|
||||
|
||||
reg:
|
||||
|
@ -20,6 +20,7 @@ properties:
|
||||
- sprd,sc2723-adc
|
||||
- sprd,sc2730-adc
|
||||
- sprd,sc2731-adc
|
||||
- sprd,ump9620-adc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@ -33,13 +34,39 @@ properties:
|
||||
hwlocks:
|
||||
maxItems: 1
|
||||
|
||||
nvmem-cells:
|
||||
maxItems: 2
|
||||
nvmem-cells: true
|
||||
|
||||
nvmem-cell-names:
|
||||
items:
|
||||
- const: big_scale_calib
|
||||
- const: small_scale_calib
|
||||
nvmem-cell-names: true
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
not:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- sprd,ump9620-adc
|
||||
then:
|
||||
properties:
|
||||
nvmem-cells:
|
||||
maxItems: 2
|
||||
nvmem-cell-names:
|
||||
items:
|
||||
- const: big_scale_calib
|
||||
- const: small_scale_calib
|
||||
|
||||
else:
|
||||
properties:
|
||||
nvmem-cells:
|
||||
maxItems: 6
|
||||
nvmem-cell-names:
|
||||
items:
|
||||
- const: big_scale_calib1
|
||||
- const: big_scale_calib2
|
||||
- const: small_scale_calib1
|
||||
- const: small_scale_calib2
|
||||
- const: vbat_det_cal1
|
||||
- const: vbat_det_cal2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
@ -69,4 +96,25 @@ examples:
|
||||
nvmem-cell-names = "big_scale_calib", "small_scale_calib";
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
pmic {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
adc@504 {
|
||||
compatible = "sprd,ump9620-adc";
|
||||
reg = <0x504>;
|
||||
interrupt-parent = <&ump9620_pmic>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#io-channel-cells = <1>;
|
||||
hwlocks = <&hwlock 4>;
|
||||
nvmem-cells = <&adc_bcal1>, <&adc_bcal2>,
|
||||
<&adc_scal1>, <&adc_scal2>,
|
||||
<&vbat_det_cal1>, <&vbat_det_cal2>;
|
||||
nvmem-cell-names = "big_scale_calib1", "big_scale_calib2",
|
||||
"small_scale_calib1", "small_scale_calib2",
|
||||
"vbat_det_cal1", "vbat_det_cal2";
|
||||
};
|
||||
};
|
||||
...
|
||||
|
@ -4,7 +4,7 @@
|
||||
$id: http://devicetree.org/schemas/iio/adc/ti,ads1015.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: TI ADS1015 4 channel I2C analog to digital converter
|
||||
title: TI ADS1015/ADS1115 4 channel I2C analog to digital converter
|
||||
|
||||
maintainers:
|
||||
- Daniel Baluta <daniel.baluta@nxp.com>
|
||||
@ -15,7 +15,10 @@ description: |
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: ti,ads1015
|
||||
enum:
|
||||
- ti,ads1015
|
||||
- ti,ads1115
|
||||
- ti,tla2024
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Analog Devices AD2552R DAC device driver
|
||||
|
||||
maintainers:
|
||||
- Mihail Chindris <mihail.chindris@analog.com>
|
||||
- Nuno Sá <nuno.sa@analog.com>
|
||||
|
||||
description: |
|
||||
Bindings for the Analog Devices AD3552R DAC device and similar.
|
||||
|
@ -68,7 +68,7 @@ examples:
|
||||
#size-cells = <0>;
|
||||
|
||||
dac@0 {
|
||||
compatible = "lltc,ltc2632";
|
||||
compatible = "lltc,ltc2632-l12";
|
||||
reg = <0>; /* CS0 */
|
||||
spi-max-frequency = <1000000>;
|
||||
vref-supply = <&vref>;
|
||||
|
@ -14,21 +14,25 @@ description: |
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- invensense,iam20680
|
||||
- invensense,icm20608
|
||||
- invensense,icm20609
|
||||
- invensense,icm20689
|
||||
- invensense,icm20602
|
||||
- invensense,icm20690
|
||||
- invensense,mpu6000
|
||||
- invensense,mpu6050
|
||||
- invensense,mpu6500
|
||||
- invensense,mpu6515
|
||||
- invensense,mpu6880
|
||||
- invensense,mpu9150
|
||||
- invensense,mpu9250
|
||||
- invensense,mpu9255
|
||||
oneOf:
|
||||
- enum:
|
||||
- invensense,iam20680
|
||||
- invensense,icm20608
|
||||
- invensense,icm20609
|
||||
- invensense,icm20689
|
||||
- invensense,icm20602
|
||||
- invensense,icm20690
|
||||
- invensense,mpu6000
|
||||
- invensense,mpu6050
|
||||
- invensense,mpu6500
|
||||
- invensense,mpu6515
|
||||
- invensense,mpu6880
|
||||
- invensense,mpu9150
|
||||
- invensense,mpu9250
|
||||
- invensense,mpu9255
|
||||
- items:
|
||||
- const: invensense,icm20608d
|
||||
- const: invensense,icm20608
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -14,23 +14,27 @@ description:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- st,lsm6ds3
|
||||
- st,lsm6ds3h
|
||||
- st,lsm6dsl
|
||||
- st,lsm6dsm
|
||||
- st,ism330dlc
|
||||
- st,lsm6dso
|
||||
- st,asm330lhh
|
||||
- st,lsm6dsox
|
||||
- st,lsm6dsr
|
||||
- st,lsm6ds3tr-c
|
||||
- st,ism330dhcx
|
||||
- st,lsm9ds1-imu
|
||||
- st,lsm6ds0
|
||||
- st,lsm6dsrx
|
||||
- st,lsm6dst
|
||||
- st,lsm6dsop
|
||||
oneOf:
|
||||
- enum:
|
||||
- st,lsm6ds3
|
||||
- st,lsm6ds3h
|
||||
- st,lsm6dsl
|
||||
- st,lsm6dsm
|
||||
- st,ism330dlc
|
||||
- st,lsm6dso
|
||||
- st,asm330lhh
|
||||
- st,lsm6dsox
|
||||
- st,lsm6dsr
|
||||
- st,lsm6ds3tr-c
|
||||
- st,ism330dhcx
|
||||
- st,lsm9ds1-imu
|
||||
- st,lsm6ds0
|
||||
- st,lsm6dsrx
|
||||
- st,lsm6dst
|
||||
- st,lsm6dsop
|
||||
- items:
|
||||
- const: st,asm330lhhx
|
||||
- const: st,lsm6dsr
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -13,6 +13,9 @@ maintainers:
|
||||
description: |
|
||||
Ambient light and proximity sensor over an i2c interface.
|
||||
|
||||
allOf:
|
||||
- $ref: ../common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
@ -26,6 +29,8 @@ properties:
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
proximity-near-level: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@ -44,6 +49,7 @@ examples:
|
||||
stk3310@48 {
|
||||
compatible = "sensortek,stk3310";
|
||||
reg = <0x48>;
|
||||
proximity-near-level = <25>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
|
||||
};
|
||||
|
@ -95,7 +95,7 @@ examples:
|
||||
#size-cells = <0>;
|
||||
|
||||
potentiometer@0 {
|
||||
compatible = "mcp4131-502";
|
||||
compatible = "microchip,mcp4131-502";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <500000>;
|
||||
};
|
||||
|
@ -29,6 +29,7 @@ properties:
|
||||
- st,lis2dw12
|
||||
- st,lis2hh12
|
||||
- st,lis2dh12-accel
|
||||
- st,lis302dl
|
||||
- st,lis331dl-accel
|
||||
- st,lis331dlh-accel
|
||||
- st,lis3de
|
||||
|
@ -31,7 +31,6 @@ properties:
|
||||
- qcom,sc7180-config-noc
|
||||
- qcom,sc7180-dc-noc
|
||||
- qcom,sc7180-gem-noc
|
||||
- qcom,sc7180-ipa-virt
|
||||
- qcom,sc7180-mc-virt
|
||||
- qcom,sc7180-mmss-noc
|
||||
- qcom,sc7180-npu-noc
|
||||
@ -59,7 +58,20 @@ properties:
|
||||
- qcom,sc8180x-ipa-virt
|
||||
- qcom,sc8180x-mc-virt
|
||||
- qcom,sc8180x-mmss-noc
|
||||
- qcom,sc8180x-qup-virt
|
||||
- qcom,sc8180x-system-noc
|
||||
- qcom,sc8280xp-aggre1-noc
|
||||
- qcom,sc8280xp-aggre2-noc
|
||||
- qcom,sc8280xp-clk-virt
|
||||
- qcom,sc8280xp-config-noc
|
||||
- qcom,sc8280xp-dc-noc
|
||||
- qcom,sc8280xp-gem-noc
|
||||
- qcom,sc8280xp-lpass-ag-noc
|
||||
- qcom,sc8280xp-mc-virt
|
||||
- qcom,sc8280xp-mmss-noc
|
||||
- qcom,sc8280xp-nspa-noc
|
||||
- qcom,sc8280xp-nspb-noc
|
||||
- qcom,sc8280xp-system-noc
|
||||
- qcom,sdm845-aggre1-noc
|
||||
- qcom,sdm845-aggre2-noc
|
||||
- qcom,sdm845-config-noc
|
||||
@ -68,10 +80,12 @@ properties:
|
||||
- qcom,sdm845-mem-noc
|
||||
- qcom,sdm845-mmss-noc
|
||||
- qcom,sdm845-system-noc
|
||||
- qcom,sdx55-ipa-virt
|
||||
- qcom,sdx55-mc-virt
|
||||
- qcom,sdx55-mem-noc
|
||||
- qcom,sdx55-system-noc
|
||||
- qcom,sdx65-mc-virt
|
||||
- qcom,sdx65-mem-noc
|
||||
- qcom,sdx65-system-noc
|
||||
- qcom,sm8150-aggre1-noc
|
||||
- qcom,sm8150-aggre2-noc
|
||||
- qcom,sm8150-camnoc-noc
|
||||
|
50
Documentation/devicetree/bindings/nvmem/apple,efuses.yaml
Normal file
50
Documentation/devicetree/bindings/nvmem/apple,efuses.yaml
Normal file
@ -0,0 +1,50 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/nvmem/apple,efuses.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Apple SoC eFuse-based NVMEM
|
||||
|
||||
description: |
|
||||
Apple SoCs such as the M1 contain factory-programmed eFuses used to e.g. store
|
||||
calibration data for the PCIe and the Type-C PHY or unique chip identifiers
|
||||
such as the ECID.
|
||||
|
||||
maintainers:
|
||||
- Sven Peter <sven@svenpeter.dev>
|
||||
|
||||
allOf:
|
||||
- $ref: "nvmem.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- apple,t8103-efuses
|
||||
- apple,t6000-efuses
|
||||
- const: apple,efuses
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
efuse@3d2bc000 {
|
||||
compatible = "apple,t8103-efuses", "apple,efuses";
|
||||
reg = <0x3d2bc000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
ecid: efuse@500 {
|
||||
reg = <0x500 0x8>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Michael Walle <michael@walle.cc>
|
||||
|
||||
description: |
|
||||
SFP is the security fuse processor which among other things provide a
|
||||
SFP is the security fuse processor which among other things provides a
|
||||
unique identifier per part.
|
||||
|
||||
allOf:
|
||||
@ -18,21 +18,45 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,ls1028a-sfp
|
||||
oneOf:
|
||||
- description: Trust architecture 2.1 SFP
|
||||
items:
|
||||
- const: fsl,ls1021a-sfp
|
||||
- description: Trust architecture 3.0 SFP
|
||||
items:
|
||||
- const: fsl,ls1028a-sfp
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description:
|
||||
The SFP clock. Typically, this is the platform clock divided by 4.
|
||||
|
||||
clock-names:
|
||||
const: sfp
|
||||
|
||||
ta-prog-sfp-supply:
|
||||
description:
|
||||
The regulator for the TA_PROG_SFP pin. It will be enabled for programming
|
||||
and disabled for reading.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/fsl,qoriq-clockgen.h>
|
||||
efuse@1e80000 {
|
||||
compatible = "fsl,ls1028a-sfp";
|
||||
reg = <0x1e80000 0x8000>;
|
||||
clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
|
||||
QORIQ_CLK_PLL_DIV(4)>;
|
||||
clock-names = "sfp";
|
||||
};
|
||||
|
@ -37,6 +37,18 @@ properties:
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
allwinner,direction:
|
||||
$ref: '/schemas/types.yaml#/definitions/string'
|
||||
description: |
|
||||
Direction of the D-PHY:
|
||||
- "rx" for receiving (e.g. when used with MIPI CSI-2);
|
||||
- "tx" for transmitting (e.g. when used with MIPI DSI).
|
||||
|
||||
enum:
|
||||
- tx
|
||||
- rx
|
||||
default: tx
|
||||
|
||||
required:
|
||||
- "#phy-cells"
|
||||
- compatible
|
||||
|
@ -45,7 +45,7 @@ additionalProperties: false
|
||||
examples:
|
||||
- |
|
||||
usb2_utmi_host_phy: phy@5f000 {
|
||||
compatible = "marvell,armada-3700-utmi-host-phy";
|
||||
compatible = "marvell,a3700-utmi-host-phy";
|
||||
reg = <0x5f000 0x800>;
|
||||
marvell,usb-misc-reg = <&usb2_syscon>;
|
||||
#phy-cells = <0>;
|
||||
|
@ -1,29 +0,0 @@
|
||||
Mixel DSI PHY for i.MX8
|
||||
|
||||
The Mixel MIPI-DSI PHY IP block is e.g. found on i.MX8 platforms (along the
|
||||
MIPI-DSI IP from Northwest Logic). It represents the physical layer for the
|
||||
electrical signals for DSI.
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be:
|
||||
- "fsl,imx8mq-mipi-dphy"
|
||||
- clocks: Must contain an entry for each entry in clock-names.
|
||||
- clock-names: Must contain the following entries:
|
||||
- "phy_ref": phandle and specifier referring to the DPHY ref clock
|
||||
- reg: the register range of the PHY controller
|
||||
- #phy-cells: number of cells in PHY, as defined in
|
||||
Documentation/devicetree/bindings/phy/phy-bindings.txt
|
||||
this must be <0>
|
||||
|
||||
Optional properties:
|
||||
- power-domains: phandle to power domain
|
||||
|
||||
Example:
|
||||
dphy: dphy@30a0030 {
|
||||
compatible = "fsl,imx8mq-mipi-dphy";
|
||||
clocks = <&clk IMX8MQ_CLK_DSI_PHY_REF>;
|
||||
clock-names = "phy_ref";
|
||||
reg = <0x30a00300 0x100>;
|
||||
power-domains = <&pd_mipi0>;
|
||||
#phy-cells = <0>;
|
||||
};
|
107
Documentation/devicetree/bindings/phy/mixel,mipi-dsi-phy.yaml
Normal file
107
Documentation/devicetree/bindings/phy/mixel,mipi-dsi-phy.yaml
Normal file
@ -0,0 +1,107 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/mixel,mipi-dsi-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mixel DSI PHY for i.MX8
|
||||
|
||||
maintainers:
|
||||
- Guido Günther <agx@sigxcpu.org>
|
||||
|
||||
description: |
|
||||
The Mixel MIPI-DSI PHY IP block is e.g. found on i.MX8 platforms (along the
|
||||
MIPI-DSI IP from Northwest Logic). It represents the physical layer for the
|
||||
electrical signals for DSI.
|
||||
|
||||
The Mixel PHY IP block found on i.MX8qxp is a combo PHY that can work
|
||||
in either MIPI-DSI PHY mode or LVDS PHY mode.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx8mq-mipi-dphy
|
||||
- fsl,imx8qxp-mipi-dphy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: phy_ref
|
||||
|
||||
assigned-clocks:
|
||||
maxItems: 1
|
||||
|
||||
assigned-clock-parents:
|
||||
maxItems: 1
|
||||
|
||||
assigned-clock-rates:
|
||||
maxItems: 1
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
fsl,syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: |
|
||||
A phandle which points to Control and Status Registers(CSR) module.
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- "#phy-cells"
|
||||
- power-domains
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: fsl,imx8mq-mipi-dphy
|
||||
then:
|
||||
properties:
|
||||
fsl,syscon: false
|
||||
|
||||
required:
|
||||
- assigned-clocks
|
||||
- assigned-clock-parents
|
||||
- assigned-clock-rates
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: fsl,imx8qxp-mipi-dphy
|
||||
then:
|
||||
properties:
|
||||
assigned-clocks: false
|
||||
assigned-clock-parents: false
|
||||
assigned-clock-rates: false
|
||||
|
||||
required:
|
||||
- fsl,syscon
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/imx8mq-clock.h>
|
||||
dphy: dphy@30a0030 {
|
||||
compatible = "fsl,imx8mq-mipi-dphy";
|
||||
reg = <0x30a00300 0x100>;
|
||||
clocks = <&clk IMX8MQ_CLK_DSI_PHY_REF>;
|
||||
clock-names = "phy_ref";
|
||||
assigned-clocks = <&clk IMX8MQ_CLK_DSI_PHY_REF>;
|
||||
assigned-clock-parents = <&clk IMX8MQ_VIDEO_PLL1_OUT>;
|
||||
assigned-clock-rates = <24000000>;
|
||||
#phy-cells = <0>;
|
||||
power-domains = <&pgc_mipi>;
|
||||
};
|
@ -39,6 +39,7 @@ properties:
|
||||
- qcom,sdm845-qmp-usb3-phy
|
||||
- qcom,sdm845-qmp-usb3-uni-phy
|
||||
- qcom,sm6115-qmp-ufs-phy
|
||||
- qcom,sm6350-qmp-ufs-phy
|
||||
- qcom,sm8150-qmp-ufs-phy
|
||||
- qcom,sm8150-qmp-usb3-phy
|
||||
- qcom,sm8150-qmp-usb3-uni-phy
|
||||
@ -57,6 +58,7 @@ properties:
|
||||
- qcom,sm8450-qmp-usb3-phy
|
||||
- qcom,sdx55-qmp-pcie-phy
|
||||
- qcom,sdx55-qmp-usb3-uni-phy
|
||||
- qcom,sdx65-qmp-usb3-uni-phy
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
@ -163,6 +165,7 @@ allOf:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sdx55-qmp-usb3-uni-phy
|
||||
- qcom,sdx65-qmp-usb3-uni-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
@ -279,6 +282,7 @@ allOf:
|
||||
enum:
|
||||
- qcom,msm8998-qmp-ufs-phy
|
||||
- qcom,sdm845-qmp-ufs-phy
|
||||
- qcom,sm6350-qmp-ufs-phy
|
||||
- qcom,sm8150-qmp-ufs-phy
|
||||
- qcom,sm8250-qmp-ufs-phy
|
||||
- qcom,sc8180x-qmp-ufs-phy
|
||||
|
@ -32,6 +32,7 @@ properties:
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,usb2-phy-r9a07g043 # RZ/G2UL
|
||||
- renesas,usb2-phy-r9a07g044 # RZ/G2{L,LC}
|
||||
- renesas,usb2-phy-r9a07g054 # RZ/V2L
|
||||
- const: renesas,rzg2l-usb2-phy
|
||||
|
@ -30,32 +30,79 @@ properties:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
oneOf:
|
||||
- items: # for PXs2
|
||||
- const: link
|
||||
- items: # for Pro4
|
||||
- const: link
|
||||
- const: gio
|
||||
- items: # for others
|
||||
- const: link
|
||||
- const: phy
|
||||
clock-names: true
|
||||
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
maxItems: 6
|
||||
|
||||
reset-names:
|
||||
oneOf:
|
||||
- items: # for Pro4
|
||||
- const: link
|
||||
- const: gio
|
||||
- const: pm
|
||||
- const: tx
|
||||
- const: rx
|
||||
- items: # for others
|
||||
- const: link
|
||||
- const: phy
|
||||
reset-names: true
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: socionext,uniphier-pro4-ahci-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: gio
|
||||
resets:
|
||||
minItems: 6
|
||||
maxItems: 6
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: gio
|
||||
- const: phy
|
||||
- const: pm
|
||||
- const: tx
|
||||
- const: rx
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: socionext,uniphier-pxs2-ahci-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 1
|
||||
clock-names:
|
||||
const: link
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: socionext,uniphier-pxs3-ahci-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
@ -31,28 +31,51 @@ properties:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
oneOf:
|
||||
- items: # for Pro5
|
||||
- const: gio
|
||||
- const: link
|
||||
- const: link # for others
|
||||
clock-names: true
|
||||
|
||||
resets:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
oneOf:
|
||||
- items: # for Pro5
|
||||
- const: gio
|
||||
- const: link
|
||||
- const: link # for others
|
||||
reset-names: true
|
||||
|
||||
socionext,syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: A phandle to system control to set configurations for phy
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: socionext,uniphier-pro5-pcie-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: gio
|
||||
- const: link
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: gio
|
||||
- const: link
|
||||
else:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 1
|
||||
clock-names:
|
||||
const: link
|
||||
resets:
|
||||
maxItems: 1
|
||||
reset-names:
|
||||
const: link
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -43,6 +43,9 @@ patternProperties:
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
vbus-supply:
|
||||
description: A phandle to the regulator for USB VBUS, only for USB host
|
||||
|
||||
required:
|
||||
- reg
|
||||
- "#phy-cells"
|
||||
|
@ -31,27 +31,15 @@ properties:
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
oneOf:
|
||||
- const: link # for PXs2
|
||||
- items: # for PXs3 with phy-ext
|
||||
- const: link
|
||||
- const: phy
|
||||
- const: phy-ext
|
||||
- items: # for others
|
||||
- const: link
|
||||
- const: phy
|
||||
clock-names: true
|
||||
|
||||
resets:
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
reset-names: true
|
||||
|
||||
vbus-supply:
|
||||
description: A phandle to the regulator for USB VBUS
|
||||
@ -74,6 +62,77 @@ properties:
|
||||
required for each port, if any one is omitted, the trimming data
|
||||
of the port will not be set at all.
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: socionext,uniphier-pro5-usb3-hsphy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: gio
|
||||
- const: link
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: gio
|
||||
- const: link
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- socionext,uniphier-pxs2-usb3-hsphy
|
||||
- socionext,uniphier-ld20-usb3-hsphy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- socionext,uniphier-pxs3-usb3-hsphy
|
||||
- socionext,uniphier-nx1-usb3-hsphy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
- const: phy-ext
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -35,33 +35,88 @@ properties:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
oneOf:
|
||||
- items: # for Pro4, Pro5
|
||||
- const: gio
|
||||
- const: link
|
||||
- items: # for PXs3 with phy-ext
|
||||
- const: link
|
||||
- const: phy
|
||||
- const: phy-ext
|
||||
- items: # for others
|
||||
- const: link
|
||||
- const: phy
|
||||
clock-names: true
|
||||
|
||||
resets:
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
oneOf:
|
||||
- items: # for Pro4,Pro5
|
||||
- const: gio
|
||||
- const: link
|
||||
- items: # for others
|
||||
- const: link
|
||||
- const: phy
|
||||
reset-names: true
|
||||
|
||||
vbus-supply:
|
||||
description: A phandle to the regulator for USB VBUS
|
||||
description: A phandle to the regulator for USB VBUS, only for USB host
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- socionext,uniphier-pro4-usb3-ssphy
|
||||
- socionext,uniphier-pro5-usb3-ssphy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: gio
|
||||
- const: link
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: gio
|
||||
- const: link
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- socionext,uniphier-pxs2-usb3-ssphy
|
||||
- socionext,uniphier-ld20-usb3-ssphy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- socionext,uniphier-pxs3-usb3-ssphy
|
||||
- socionext,uniphier-nx1-usb3-ssphy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
- const: phy-ext
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
|
||||
required:
|
||||
- compatible
|
||||
@ -71,7 +126,6 @@ required:
|
||||
- clock-names
|
||||
- resets
|
||||
- reset-names
|
||||
- vbus-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
|
@ -162,6 +162,18 @@ board specific bus parameters.
|
||||
or applicable for the respective data port.
|
||||
More info in MIPI Alliance SoundWire 1.0 Specifications.
|
||||
|
||||
- reset:
|
||||
Usage: optional
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: Should specify the SoundWire audio CSR reset controller interface,
|
||||
which is required for SoundWire version 1.6.0 and above.
|
||||
|
||||
- reset-names:
|
||||
Usage: optional
|
||||
Value type: <stringlist>
|
||||
Definition: should be "swr_audio_cgcr" for SoundWire audio CSR reset
|
||||
controller interface.
|
||||
|
||||
Note:
|
||||
More Information on detail of encoding of these fields can be
|
||||
found in MIPI Alliance SoundWire 1.0 Specifications.
|
||||
@ -180,6 +192,8 @@ soundwire: soundwire@c85 {
|
||||
interrupts = <20 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&wcc>;
|
||||
clock-names = "iface";
|
||||
resets = <&lpass_audiocc LPASS_AUDIO_SWR_TX_CGCR>;
|
||||
reset-names = "swr_audio_cgcr";
|
||||
#sound-dai-cells = <1>;
|
||||
qcom,dports-type = <0>;
|
||||
qcom,dout-ports = <6>;
|
||||
|
@ -502,6 +502,11 @@ Developer only needs to provide a sub feature driver with matched feature id.
|
||||
FME Partial Reconfiguration Sub Feature driver (see drivers/fpga/dfl-fme-pr.c)
|
||||
could be a reference.
|
||||
|
||||
Please refer to below link to existing feature id table and guide for new feature
|
||||
ids application.
|
||||
https://github.com/OPAE/dfl-feature-id
|
||||
|
||||
|
||||
Location of DFLs on a PCI Device
|
||||
================================
|
||||
The original method for finding a DFL on a PCI device assumed the start of the
|
||||
|
18
MAINTAINERS
18
MAINTAINERS
@ -1090,6 +1090,14 @@ W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml
|
||||
F: drivers/iio/adc/ad7292.c
|
||||
|
||||
ANALOG DEVICES INC AD3552R DRIVER
|
||||
M: Nuno Sá <nuno.sa@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
|
||||
F: drivers/iio/dac/ad3552r.c
|
||||
|
||||
ANALOG DEVICES INC AD7293 DRIVER
|
||||
M: Antoniu Miclaus <antoniu.miclaus@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
@ -1830,6 +1838,7 @@ F: Documentation/devicetree/bindings/iommu/apple,dart.yaml
|
||||
F: Documentation/devicetree/bindings/iommu/apple,sart.yaml
|
||||
F: Documentation/devicetree/bindings/mailbox/apple,mailbox.yaml
|
||||
F: Documentation/devicetree/bindings/nvme/apple,nvme-ans.yaml
|
||||
F: Documentation/devicetree/bindings/nvmem/apple,efuses.yaml
|
||||
F: Documentation/devicetree/bindings/pci/apple,pcie.yaml
|
||||
F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml
|
||||
F: Documentation/devicetree/bindings/power/apple*
|
||||
@ -1842,6 +1851,7 @@ F: drivers/iommu/apple-dart.c
|
||||
F: drivers/irqchip/irq-apple-aic.c
|
||||
F: drivers/mailbox/apple-mailbox.c
|
||||
F: drivers/nvme/host/apple.c
|
||||
F: drivers/nvmem/apple-efuses.c
|
||||
F: drivers/pinctrl/pinctrl-apple-gpio.c
|
||||
F: drivers/soc/apple/*
|
||||
F: drivers/watchdog/apple_wdt.c
|
||||
@ -7785,7 +7795,7 @@ R: Tom Rix <trix@redhat.com>
|
||||
L: linux-fpga@vger.kernel.org
|
||||
S: Maintained
|
||||
Q: http://patchwork.kernel.org/project/linux-fpga/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mdf/linux-fpga.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/fpga/linux-fpga.git
|
||||
F: Documentation/devicetree/bindings/fpga/
|
||||
F: Documentation/driver-api/fpga/
|
||||
F: Documentation/fpga/
|
||||
@ -9063,7 +9073,7 @@ S: Maintained
|
||||
F: drivers/input/touchscreen/htcpen.c
|
||||
|
||||
HTS221 TEMPERATURE-HUMIDITY IIO DRIVER
|
||||
M: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
|
||||
M: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
W: http://www.st.com/
|
||||
@ -12902,7 +12912,7 @@ F: arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
|
||||
|
||||
MHI BUS
|
||||
M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
R: Hemant Kumar <hemantk@codeaurora.org>
|
||||
R: Hemant Kumar <quic_hemantk@quicinc.com>
|
||||
L: mhi@lists.linux.dev
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
S: Maintained
|
||||
@ -18794,7 +18804,7 @@ S: Maintained
|
||||
F: arch/alpha/kernel/srm_env.c
|
||||
|
||||
ST LSM6DSx IMU IIO DRIVER
|
||||
M: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
|
||||
M: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
W: http://www.st.com/
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* fakekey.c
|
||||
* Functions for simulating keypresses.
|
||||
* Functions for simulating key presses.
|
||||
*
|
||||
* Copyright (C) 2010 the Speakup Team
|
||||
*/
|
||||
@ -78,7 +78,7 @@ void speakup_fake_down_arrow(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Are we handling a simulated keypress on the current CPU?
|
||||
* Are we handling a simulated key press on the current CPU?
|
||||
* Returns a boolean.
|
||||
*/
|
||||
bool speakup_fake_key_pressed(void)
|
||||
|
@ -59,7 +59,7 @@ const struct old_serial_port *spk_serial_init(int index)
|
||||
}
|
||||
ser = rs_table + index;
|
||||
|
||||
/* Divisor, bytesize and parity */
|
||||
/* Divisor, byte size and parity */
|
||||
quot = ser->baud_base / baud;
|
||||
cval = cflag & (CSIZE | CSTOPB);
|
||||
#if defined(__powerpc__) || defined(__alpha__)
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright (C) 1998-99 Kirk Reiser.
|
||||
* Copyright (C) 2003 David Borowski.
|
||||
*
|
||||
* this code is specificly written as a driver for the speakup screenreview
|
||||
* this code is specifically written as a driver for the speakup screenreview
|
||||
* package and is not a general device driver.
|
||||
* This driver is for the Aicom Acent PC internal synthesizer.
|
||||
*/
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright (C) 1998-99 Kirk Reiser.
|
||||
* Copyright (C) 2003 David Borowski.
|
||||
*
|
||||
* this code is specificly written as a driver for the speakup screenreview
|
||||
* this code is specifically written as a driver for the speakup screenreview
|
||||
* package and is not a general device driver.
|
||||
*/
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright (C) 1998-99 Kirk Reiser.
|
||||
* Copyright (C) 2003 David Borowski.
|
||||
*
|
||||
* this code is specificly written as a driver for the speakup screenreview
|
||||
* this code is specifically written as a driver for the speakup screenreview
|
||||
* package and is not a general device driver.
|
||||
*/
|
||||
#include <linux/jiffies.h>
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright (C) 1998-99 Kirk Reiser.
|
||||
* Copyright (C) 2003 David Borowski.
|
||||
*
|
||||
* specificly written as a driver for the speakup screenreview
|
||||
* specifically written as a driver for the speakup screenreview
|
||||
* s not a general device driver.
|
||||
*/
|
||||
#include "spk_priv.h"
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright (C) 1998-99 Kirk Reiser.
|
||||
* Copyright (C) 2003 David Borowski.
|
||||
*
|
||||
* this code is specificly written as a driver for the speakup screenreview
|
||||
* this code is specifically written as a driver for the speakup screenreview
|
||||
* package and is not a general device driver.
|
||||
*/
|
||||
#include "spk_priv.h"
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright (C) 1998-99 Kirk Reiser.
|
||||
* Copyright (C) 2003 David Borowski.
|
||||
*
|
||||
* specificly written as a driver for the speakup screenreview
|
||||
* specifically written as a driver for the speakup screenreview
|
||||
* s not a general device driver.
|
||||
*/
|
||||
#include <linux/jiffies.h>
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright (C) 1998-99 Kirk Reiser.
|
||||
* Copyright (C) 2003 David Borowski.
|
||||
*
|
||||
* specificly written as a driver for the speakup screenreview
|
||||
* specifically written as a driver for the speakup screenreview
|
||||
* s not a general device driver.
|
||||
*/
|
||||
#include <linux/unistd.h>
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright (C) 1998-99 Kirk Reiser.
|
||||
* Copyright (C) 2003 David Borowski.
|
||||
*
|
||||
* specificly written as a driver for the speakup screenreview
|
||||
* specifically written as a driver for the speakup screenreview
|
||||
* package it's not a general device driver.
|
||||
* This driver is for the RC Systems DoubleTalk PC internal synthesizer.
|
||||
*/
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Copyright (C) 2003 David Borowski.
|
||||
* Copyright (C) 2007 Samuel Thibault.
|
||||
*
|
||||
* specificly written as a driver for the speakup screenreview
|
||||
* specifically written as a driver for the speakup screenreview
|
||||
* s not a general device driver.
|
||||
*/
|
||||
#include "spk_priv.h"
|
||||
|
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Copyright (C) 2003 David Borowski.
|
||||
*
|
||||
* specificly written as a driver for the speakup screenreview
|
||||
* specifically written as a driver for the speakup screenreview
|
||||
* package it's not a general device driver.
|
||||
* This driver is for the Keynote Gold internal synthesizer.
|
||||
*/
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright (C) 1998-99 Kirk Reiser.
|
||||
* Copyright (C) 2003 David Borowski.
|
||||
*
|
||||
* specificly written as a driver for the speakup screenreview
|
||||
* specifically written as a driver for the speakup screenreview
|
||||
* s not a general device driver.
|
||||
*/
|
||||
#include "speakup.h"
|
||||
|
@ -5,7 +5,7 @@
|
||||
*
|
||||
* Copyright (C) 2003 Kirk Reiser.
|
||||
*
|
||||
* this code is specificly written as a driver for the speakup screenreview
|
||||
* this code is specifically written as a driver for the speakup screenreview
|
||||
* package and is not a general device driver.
|
||||
*/
|
||||
|
||||
@ -397,6 +397,7 @@ static int softsynth_probe(struct spk_synth *synth)
|
||||
synthu_device.name = "softsynthu";
|
||||
synthu_device.fops = &softsynthu_fops;
|
||||
if (misc_register(&synthu_device)) {
|
||||
misc_deregister(&synth_device);
|
||||
pr_warn("Couldn't initialize miscdevice /dev/softsynthu.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright (C) 1998-99 Kirk Reiser.
|
||||
* Copyright (C) 2003 David Borowski.
|
||||
*
|
||||
* specificly written as a driver for the speakup screenreview
|
||||
* specifically written as a driver for the speakup screenreview
|
||||
* s not a general device driver.
|
||||
*/
|
||||
#include "spk_priv.h"
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright (C) 1998-99 Kirk Reiser.
|
||||
* Copyright (C) 2003 David Borowski.
|
||||
*
|
||||
* specificly written as a driver for the speakup screenreview
|
||||
* specifically written as a driver for the speakup screenreview
|
||||
* s not a general device driver.
|
||||
*/
|
||||
#include "spk_priv.h"
|
||||
|
@ -133,18 +133,45 @@ static int binder_set_stop_on_user_error(const char *val,
|
||||
module_param_call(stop_on_user_error, binder_set_stop_on_user_error,
|
||||
param_get_int, &binder_stop_on_user_error, 0644);
|
||||
|
||||
#define binder_debug(mask, x...) \
|
||||
do { \
|
||||
if (binder_debug_mask & mask) \
|
||||
pr_info_ratelimited(x); \
|
||||
} while (0)
|
||||
static __printf(2, 3) void binder_debug(int mask, const char *format, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
|
||||
#define binder_user_error(x...) \
|
||||
if (binder_debug_mask & mask) {
|
||||
va_start(args, format);
|
||||
vaf.va = &args;
|
||||
vaf.fmt = format;
|
||||
pr_info_ratelimited("%pV", &vaf);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
#define binder_txn_error(x...) \
|
||||
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, x)
|
||||
|
||||
static __printf(1, 2) void binder_user_error(const char *format, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
|
||||
if (binder_debug_mask & BINDER_DEBUG_USER_ERROR) {
|
||||
va_start(args, format);
|
||||
vaf.va = &args;
|
||||
vaf.fmt = format;
|
||||
pr_info_ratelimited("%pV", &vaf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
if (binder_stop_on_user_error)
|
||||
binder_stop_on_user_error = 2;
|
||||
}
|
||||
|
||||
#define binder_set_extended_error(ee, _id, _command, _param) \
|
||||
do { \
|
||||
if (binder_debug_mask & BINDER_DEBUG_USER_ERROR) \
|
||||
pr_info_ratelimited(x); \
|
||||
if (binder_stop_on_user_error) \
|
||||
binder_stop_on_user_error = 2; \
|
||||
(ee)->id = _id; \
|
||||
(ee)->command = _command; \
|
||||
(ee)->param = _param; \
|
||||
} while (0)
|
||||
|
||||
#define to_flat_binder_object(hdr) \
|
||||
@ -1481,6 +1508,8 @@ static void binder_free_txn_fixups(struct binder_transaction *t)
|
||||
|
||||
list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) {
|
||||
fput(fixup->file);
|
||||
if (fixup->target_fd >= 0)
|
||||
put_unused_fd(fixup->target_fd);
|
||||
list_del(&fixup->fixup_entry);
|
||||
kfree(fixup);
|
||||
}
|
||||
@ -2220,6 +2249,7 @@ static int binder_translate_fd(u32 fd, binder_size_t fd_offset,
|
||||
}
|
||||
fixup->file = file;
|
||||
fixup->offset = fd_offset;
|
||||
fixup->target_fd = -1;
|
||||
trace_binder_transaction_fd_send(t, fd, fixup->offset);
|
||||
list_add_tail(&fixup->fixup_entry, &t->fd_fixups);
|
||||
|
||||
@ -2705,6 +2735,24 @@ static struct binder_node *binder_get_node_refs_for_txn(
|
||||
return target_node;
|
||||
}
|
||||
|
||||
static void binder_set_txn_from_error(struct binder_transaction *t, int id,
|
||||
uint32_t command, int32_t param)
|
||||
{
|
||||
struct binder_thread *from = binder_get_txn_from_and_acq_inner(t);
|
||||
|
||||
if (!from) {
|
||||
/* annotation for sparse */
|
||||
__release(&from->proc->inner_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* don't override existing errors */
|
||||
if (from->ee.command == BR_OK)
|
||||
binder_set_extended_error(&from->ee, id, command, param);
|
||||
binder_inner_proc_unlock(from->proc);
|
||||
binder_thread_dec_tmpref(from);
|
||||
}
|
||||
|
||||
static void binder_transaction(struct binder_proc *proc,
|
||||
struct binder_thread *thread,
|
||||
struct binder_transaction_data *tr, int reply,
|
||||
@ -2750,6 +2798,10 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
e->offsets_size = tr->offsets_size;
|
||||
strscpy(e->context_name, proc->context->name, BINDERFS_MAX_NAME);
|
||||
|
||||
binder_inner_proc_lock(proc);
|
||||
binder_set_extended_error(&thread->ee, t_debug_id, BR_OK, 0);
|
||||
binder_inner_proc_unlock(proc);
|
||||
|
||||
if (reply) {
|
||||
binder_inner_proc_lock(proc);
|
||||
in_reply_to = thread->transaction_stack;
|
||||
@ -2785,6 +2837,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
if (target_thread == NULL) {
|
||||
/* annotation for sparse */
|
||||
__release(&target_thread->proc->inner_lock);
|
||||
binder_txn_error("%d:%d reply target not found\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error = BR_DEAD_REPLY;
|
||||
return_error_line = __LINE__;
|
||||
goto err_dead_binder;
|
||||
@ -2850,6 +2904,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
}
|
||||
}
|
||||
if (!target_node) {
|
||||
binder_txn_error("%d:%d cannot find target node\n",
|
||||
thread->pid, proc->pid);
|
||||
/*
|
||||
* return_error is set above
|
||||
*/
|
||||
@ -2859,6 +2915,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
}
|
||||
e->to_node = target_node->debug_id;
|
||||
if (WARN_ON(proc == target_proc)) {
|
||||
binder_txn_error("%d:%d self transactions not allowed\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = -EINVAL;
|
||||
return_error_line = __LINE__;
|
||||
@ -2866,6 +2924,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
}
|
||||
if (security_binder_transaction(proc->cred,
|
||||
target_proc->cred) < 0) {
|
||||
binder_txn_error("%d:%d transaction credentials failed\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = -EPERM;
|
||||
return_error_line = __LINE__;
|
||||
@ -2937,6 +2997,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
/* TODO: reuse incoming transaction for reply */
|
||||
t = kzalloc(sizeof(*t), GFP_KERNEL);
|
||||
if (t == NULL) {
|
||||
binder_txn_error("%d:%d cannot allocate transaction\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = -ENOMEM;
|
||||
return_error_line = __LINE__;
|
||||
@ -2948,6 +3010,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
|
||||
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
|
||||
if (tcomplete == NULL) {
|
||||
binder_txn_error("%d:%d cannot allocate work for transaction\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = -ENOMEM;
|
||||
return_error_line = __LINE__;
|
||||
@ -2994,6 +3058,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
security_cred_getsecid(proc->cred, &secid);
|
||||
ret = security_secid_to_secctx(secid, &secctx, &secctx_sz);
|
||||
if (ret) {
|
||||
binder_txn_error("%d:%d failed to get security context\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = ret;
|
||||
return_error_line = __LINE__;
|
||||
@ -3002,7 +3068,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
added_size = ALIGN(secctx_sz, sizeof(u64));
|
||||
extra_buffers_size += added_size;
|
||||
if (extra_buffers_size < added_size) {
|
||||
/* integer overflow of extra_buffers_size */
|
||||
binder_txn_error("%d:%d integer overflow of extra_buffers_size\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = -EINVAL;
|
||||
return_error_line = __LINE__;
|
||||
@ -3016,9 +3083,15 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
tr->offsets_size, extra_buffers_size,
|
||||
!reply && (t->flags & TF_ONE_WAY), current->tgid);
|
||||
if (IS_ERR(t->buffer)) {
|
||||
/*
|
||||
* -ESRCH indicates VMA cleared. The target is dying.
|
||||
*/
|
||||
char *s;
|
||||
|
||||
ret = PTR_ERR(t->buffer);
|
||||
s = (ret == -ESRCH) ? ": vma cleared, target dead or dying"
|
||||
: (ret == -ENOSPC) ? ": no space left"
|
||||
: (ret == -ENOMEM) ? ": memory allocation failed"
|
||||
: "";
|
||||
binder_txn_error("cannot allocate buffer%s", s);
|
||||
|
||||
return_error_param = PTR_ERR(t->buffer);
|
||||
return_error = return_error_param == -ESRCH ?
|
||||
BR_DEAD_REPLY : BR_FAILED_REPLY;
|
||||
@ -3101,6 +3174,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
t->buffer,
|
||||
buffer_offset,
|
||||
sizeof(object_offset))) {
|
||||
binder_txn_error("%d:%d copy offset from buffer failed\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = -EINVAL;
|
||||
return_error_line = __LINE__;
|
||||
@ -3159,6 +3234,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
t->buffer,
|
||||
object_offset,
|
||||
fp, sizeof(*fp))) {
|
||||
binder_txn_error("%d:%d translate binder failed\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = ret;
|
||||
return_error_line = __LINE__;
|
||||
@ -3176,6 +3253,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
t->buffer,
|
||||
object_offset,
|
||||
fp, sizeof(*fp))) {
|
||||
binder_txn_error("%d:%d translate handle failed\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = ret;
|
||||
return_error_line = __LINE__;
|
||||
@ -3196,6 +3275,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
t->buffer,
|
||||
object_offset,
|
||||
fp, sizeof(*fp))) {
|
||||
binder_txn_error("%d:%d translate fd failed\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = ret;
|
||||
return_error_line = __LINE__;
|
||||
@ -3265,6 +3346,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
object_offset,
|
||||
fda, sizeof(*fda));
|
||||
if (ret) {
|
||||
binder_txn_error("%d:%d translate fd array failed\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = ret > 0 ? -EINVAL : ret;
|
||||
return_error_line = __LINE__;
|
||||
@ -3292,6 +3375,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
(const void __user *)(uintptr_t)bp->buffer,
|
||||
bp->length);
|
||||
if (ret) {
|
||||
binder_txn_error("%d:%d deferred copy failed\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = ret;
|
||||
return_error_line = __LINE__;
|
||||
@ -3315,6 +3400,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
t->buffer,
|
||||
object_offset,
|
||||
bp, sizeof(*bp))) {
|
||||
binder_txn_error("%d:%d failed to fixup parent\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = ret;
|
||||
return_error_line = __LINE__;
|
||||
@ -3422,6 +3509,8 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
return;
|
||||
|
||||
err_dead_proc_or_thread:
|
||||
binder_txn_error("%d:%d dead process or thread\n",
|
||||
thread->pid, proc->pid);
|
||||
return_error_line = __LINE__;
|
||||
binder_dequeue_work(proc, tcomplete);
|
||||
err_translate_failed:
|
||||
@ -3457,21 +3546,26 @@ err_bad_call_stack:
|
||||
err_empty_call_stack:
|
||||
err_dead_binder:
|
||||
err_invalid_target_handle:
|
||||
if (target_thread)
|
||||
binder_thread_dec_tmpref(target_thread);
|
||||
if (target_proc)
|
||||
binder_proc_dec_tmpref(target_proc);
|
||||
if (target_node) {
|
||||
binder_dec_node(target_node, 1, 0);
|
||||
binder_dec_node_tmpref(target_node);
|
||||
}
|
||||
|
||||
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
|
||||
"%d:%d transaction failed %d/%d, size %lld-%lld line %d\n",
|
||||
proc->pid, thread->pid, return_error, return_error_param,
|
||||
"%d:%d transaction %s to %d:%d failed %d/%d/%d, size %lld-%lld line %d\n",
|
||||
proc->pid, thread->pid, reply ? "reply" :
|
||||
(tr->flags & TF_ONE_WAY ? "async" : "call"),
|
||||
target_proc ? target_proc->pid : 0,
|
||||
target_thread ? target_thread->pid : 0,
|
||||
t_debug_id, return_error, return_error_param,
|
||||
(u64)tr->data_size, (u64)tr->offsets_size,
|
||||
return_error_line);
|
||||
|
||||
if (target_thread)
|
||||
binder_thread_dec_tmpref(target_thread);
|
||||
if (target_proc)
|
||||
binder_proc_dec_tmpref(target_proc);
|
||||
|
||||
{
|
||||
struct binder_transaction_log_entry *fe;
|
||||
|
||||
@ -3491,10 +3585,16 @@ err_invalid_target_handle:
|
||||
|
||||
BUG_ON(thread->return_error.cmd != BR_OK);
|
||||
if (in_reply_to) {
|
||||
binder_set_txn_from_error(in_reply_to, t_debug_id,
|
||||
return_error, return_error_param);
|
||||
thread->return_error.cmd = BR_TRANSACTION_COMPLETE;
|
||||
binder_enqueue_thread_work(thread, &thread->return_error.work);
|
||||
binder_send_failed_reply(in_reply_to, return_error);
|
||||
} else {
|
||||
binder_inner_proc_lock(proc);
|
||||
binder_set_extended_error(&thread->ee, t_debug_id,
|
||||
return_error, return_error_param);
|
||||
binder_inner_proc_unlock(proc);
|
||||
thread->return_error.cmd = return_error;
|
||||
binder_enqueue_thread_work(thread, &thread->return_error.work);
|
||||
}
|
||||
@ -3984,7 +4084,7 @@ static int binder_thread_write(struct binder_proc *proc,
|
||||
} break;
|
||||
|
||||
default:
|
||||
pr_err("%d:%d unknown command %d\n",
|
||||
pr_err("%d:%d unknown command %u\n",
|
||||
proc->pid, thread->pid, cmd);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -4075,10 +4175,9 @@ static int binder_wait_for_work(struct binder_thread *thread,
|
||||
* Now that we are in the context of the transaction target
|
||||
* process, we can allocate and install fds. Process the
|
||||
* list of fds to translate and fixup the buffer with the
|
||||
* new fds.
|
||||
* new fds first and only then install the files.
|
||||
*
|
||||
* If we fail to allocate an fd, then free the resources by
|
||||
* fput'ing files that have not been processed and ksys_close'ing
|
||||
* If we fail to allocate an fd, skip the install and release
|
||||
* any fds that have already been allocated.
|
||||
*/
|
||||
static int binder_apply_fd_fixups(struct binder_proc *proc,
|
||||
@ -4095,41 +4194,31 @@ static int binder_apply_fd_fixups(struct binder_proc *proc,
|
||||
"failed fd fixup txn %d fd %d\n",
|
||||
t->debug_id, fd);
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
goto err;
|
||||
}
|
||||
binder_debug(BINDER_DEBUG_TRANSACTION,
|
||||
"fd fixup txn %d fd %d\n",
|
||||
t->debug_id, fd);
|
||||
trace_binder_transaction_fd_recv(t, fd, fixup->offset);
|
||||
fd_install(fd, fixup->file);
|
||||
fixup->file = NULL;
|
||||
fixup->target_fd = fd;
|
||||
if (binder_alloc_copy_to_buffer(&proc->alloc, t->buffer,
|
||||
fixup->offset, &fd,
|
||||
sizeof(u32))) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) {
|
||||
if (fixup->file) {
|
||||
fput(fixup->file);
|
||||
} else if (ret) {
|
||||
u32 fd;
|
||||
int err;
|
||||
|
||||
err = binder_alloc_copy_from_buffer(&proc->alloc, &fd,
|
||||
t->buffer,
|
||||
fixup->offset,
|
||||
sizeof(fd));
|
||||
WARN_ON(err);
|
||||
if (!err)
|
||||
binder_deferred_fd_close(fd);
|
||||
}
|
||||
fd_install(fixup->target_fd, fixup->file);
|
||||
list_del(&fixup->fixup_entry);
|
||||
kfree(fixup);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
binder_free_txn_fixups(t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int binder_thread_read(struct binder_proc *proc,
|
||||
@ -4490,7 +4579,7 @@ retry:
|
||||
trace_binder_transaction_received(t);
|
||||
binder_stat_br(proc, thread, cmd);
|
||||
binder_debug(BINDER_DEBUG_TRANSACTION,
|
||||
"%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n",
|
||||
"%d:%d %s %d %d:%d, cmd %u size %zd-%zd ptr %016llx-%016llx\n",
|
||||
proc->pid, thread->pid,
|
||||
(cmd == BR_TRANSACTION) ? "BR_TRANSACTION" :
|
||||
(cmd == BR_TRANSACTION_SEC_CTX) ?
|
||||
@ -4632,6 +4721,7 @@ static struct binder_thread *binder_get_thread_ilocked(
|
||||
thread->return_error.cmd = BR_OK;
|
||||
thread->reply_error.work.type = BINDER_WORK_RETURN_ERROR;
|
||||
thread->reply_error.cmd = BR_OK;
|
||||
thread->ee.command = BR_OK;
|
||||
INIT_LIST_HEAD(&new_thread->waiting_thread_node);
|
||||
return thread;
|
||||
}
|
||||
@ -5070,6 +5160,22 @@ static int binder_ioctl_get_freezer_info(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int binder_ioctl_get_extended_error(struct binder_thread *thread,
|
||||
void __user *ubuf)
|
||||
{
|
||||
struct binder_extended_error ee;
|
||||
|
||||
binder_inner_proc_lock(thread->proc);
|
||||
ee = thread->ee;
|
||||
binder_set_extended_error(&thread->ee, 0, BR_OK, 0);
|
||||
binder_inner_proc_unlock(thread->proc);
|
||||
|
||||
if (copy_to_user(ubuf, &ee, sizeof(ee)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int ret;
|
||||
@ -5278,6 +5384,11 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
binder_inner_proc_unlock(proc);
|
||||
break;
|
||||
}
|
||||
case BINDER_GET_EXTENDED_ERROR:
|
||||
ret = binder_ioctl_get_extended_error(thread, ubuf);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
|
@ -1175,14 +1175,11 @@ static void binder_alloc_clear_buf(struct binder_alloc *alloc,
|
||||
unsigned long size;
|
||||
struct page *page;
|
||||
pgoff_t pgoff;
|
||||
void *kptr;
|
||||
|
||||
page = binder_alloc_get_page(alloc, buffer,
|
||||
buffer_offset, &pgoff);
|
||||
size = min_t(size_t, bytes, PAGE_SIZE - pgoff);
|
||||
kptr = kmap(page) + pgoff;
|
||||
memset(kptr, 0, size);
|
||||
kunmap(page);
|
||||
memset_page(page, pgoff, 0, size);
|
||||
bytes -= size;
|
||||
buffer_offset += size;
|
||||
}
|
||||
@ -1220,9 +1217,9 @@ binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc,
|
||||
page = binder_alloc_get_page(alloc, buffer,
|
||||
buffer_offset, &pgoff);
|
||||
size = min_t(size_t, bytes, PAGE_SIZE - pgoff);
|
||||
kptr = kmap(page) + pgoff;
|
||||
kptr = kmap_local_page(page) + pgoff;
|
||||
ret = copy_from_user(kptr, from, size);
|
||||
kunmap(page);
|
||||
kunmap_local(kptr);
|
||||
if (ret)
|
||||
return bytes - size + ret;
|
||||
bytes -= size;
|
||||
@ -1247,23 +1244,14 @@ static int binder_alloc_do_buffer_copy(struct binder_alloc *alloc,
|
||||
unsigned long size;
|
||||
struct page *page;
|
||||
pgoff_t pgoff;
|
||||
void *tmpptr;
|
||||
void *base_ptr;
|
||||
|
||||
page = binder_alloc_get_page(alloc, buffer,
|
||||
buffer_offset, &pgoff);
|
||||
size = min_t(size_t, bytes, PAGE_SIZE - pgoff);
|
||||
base_ptr = kmap_atomic(page);
|
||||
tmpptr = base_ptr + pgoff;
|
||||
if (to_buffer)
|
||||
memcpy(tmpptr, ptr, size);
|
||||
memcpy_to_page(page, pgoff, ptr, size);
|
||||
else
|
||||
memcpy(ptr, tmpptr, size);
|
||||
/*
|
||||
* kunmap_atomic() takes care of flushing the cache
|
||||
* if this device has VIVT cache arch
|
||||
*/
|
||||
kunmap_atomic(base_ptr);
|
||||
memcpy_from_page(ptr, page, pgoff, size);
|
||||
bytes -= size;
|
||||
pgoff = 0;
|
||||
ptr = ptr + size;
|
||||
|
@ -480,6 +480,8 @@ struct binder_proc {
|
||||
* (only accessed by this thread)
|
||||
* @reply_error: transaction errors reported by target thread
|
||||
* (protected by @proc->inner_lock)
|
||||
* @ee: extended error information from this thread
|
||||
* (protected by @proc->inner_lock)
|
||||
* @wait: wait queue for thread work
|
||||
* @stats: per-thread statistics
|
||||
* (atomics, no lock needed)
|
||||
@ -504,6 +506,7 @@ struct binder_thread {
|
||||
bool process_todo;
|
||||
struct binder_error return_error;
|
||||
struct binder_error reply_error;
|
||||
struct binder_extended_error ee;
|
||||
wait_queue_head_t wait;
|
||||
struct binder_stats stats;
|
||||
atomic_t tmp_ref;
|
||||
@ -515,6 +518,7 @@ struct binder_thread {
|
||||
* @fixup_entry: list entry
|
||||
* @file: struct file to be associated with new fd
|
||||
* @offset: offset in buffer data to this fixup
|
||||
* @target_fd: fd to use by the target to install @file
|
||||
*
|
||||
* List element for fd fixups in a transaction. Since file
|
||||
* descriptors need to be allocated in the context of the
|
||||
@ -525,6 +529,7 @@ struct binder_txn_fd_fixup {
|
||||
struct list_head fixup_entry;
|
||||
struct file *file;
|
||||
size_t offset;
|
||||
int target_fd;
|
||||
};
|
||||
|
||||
struct binder_transaction {
|
||||
|
@ -60,6 +60,7 @@ enum binderfs_stats_mode {
|
||||
|
||||
struct binder_features {
|
||||
bool oneway_spam_detection;
|
||||
bool extended_error;
|
||||
};
|
||||
|
||||
static const struct constant_table binderfs_param_stats[] = {
|
||||
@ -75,6 +76,7 @@ static const struct fs_parameter_spec binderfs_fs_parameters[] = {
|
||||
|
||||
static struct binder_features binder_features = {
|
||||
.oneway_spam_detection = true,
|
||||
.extended_error = true,
|
||||
};
|
||||
|
||||
static inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb)
|
||||
@ -615,6 +617,12 @@ static int init_binder_features(struct super_block *sb)
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
dentry = binderfs_create_file(dir, "extended_error",
|
||||
&binder_features_fops,
|
||||
&binder_features.extended_error);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -6,3 +6,4 @@
|
||||
#
|
||||
|
||||
source "drivers/bus/mhi/host/Kconfig"
|
||||
source "drivers/bus/mhi/ep/Kconfig"
|
||||
|
@ -1,2 +1,5 @@
|
||||
# Host MHI stack
|
||||
obj-y += host/
|
||||
|
||||
# Endpoint MHI stack
|
||||
obj-y += ep/
|
||||
|
@ -165,6 +165,22 @@
|
||||
#define MHI_TRE_GET_EV_LINKSPEED(tre) FIELD_GET(GENMASK(31, 24), (MHI_TRE_GET_DWORD(tre, 1)))
|
||||
#define MHI_TRE_GET_EV_LINKWIDTH(tre) FIELD_GET(GENMASK(7, 0), (MHI_TRE_GET_DWORD(tre, 0)))
|
||||
|
||||
/* State change event */
|
||||
#define MHI_SC_EV_PTR 0
|
||||
#define MHI_SC_EV_DWORD0(state) cpu_to_le32(FIELD_PREP(GENMASK(31, 24), state))
|
||||
#define MHI_SC_EV_DWORD1(type) cpu_to_le32(FIELD_PREP(GENMASK(23, 16), type))
|
||||
|
||||
/* EE event */
|
||||
#define MHI_EE_EV_PTR 0
|
||||
#define MHI_EE_EV_DWORD0(ee) cpu_to_le32(FIELD_PREP(GENMASK(31, 24), ee))
|
||||
#define MHI_EE_EV_DWORD1(type) cpu_to_le32(FIELD_PREP(GENMASK(23, 16), type))
|
||||
|
||||
|
||||
/* Command Completion event */
|
||||
#define MHI_CC_EV_PTR(ptr) cpu_to_le64(ptr)
|
||||
#define MHI_CC_EV_DWORD0(code) cpu_to_le32(FIELD_PREP(GENMASK(31, 24), code))
|
||||
#define MHI_CC_EV_DWORD1(type) cpu_to_le32(FIELD_PREP(GENMASK(23, 16), type))
|
||||
|
||||
/* Transfer descriptor macros */
|
||||
#define MHI_TRE_DATA_PTR(ptr) cpu_to_le64(ptr)
|
||||
#define MHI_TRE_DATA_DWORD0(len) cpu_to_le32(FIELD_PREP(GENMASK(15, 0), len))
|
||||
@ -175,6 +191,12 @@
|
||||
FIELD_PREP(BIT(9), ieot) | \
|
||||
FIELD_PREP(BIT(8), ieob) | \
|
||||
FIELD_PREP(BIT(0), chain))
|
||||
#define MHI_TRE_DATA_GET_PTR(tre) le64_to_cpu((tre)->ptr)
|
||||
#define MHI_TRE_DATA_GET_LEN(tre) FIELD_GET(GENMASK(15, 0), MHI_TRE_GET_DWORD(tre, 0))
|
||||
#define MHI_TRE_DATA_GET_CHAIN(tre) (!!(FIELD_GET(BIT(0), MHI_TRE_GET_DWORD(tre, 1))))
|
||||
#define MHI_TRE_DATA_GET_IEOB(tre) (!!(FIELD_GET(BIT(8), MHI_TRE_GET_DWORD(tre, 1))))
|
||||
#define MHI_TRE_DATA_GET_IEOT(tre) (!!(FIELD_GET(BIT(9), MHI_TRE_GET_DWORD(tre, 1))))
|
||||
#define MHI_TRE_DATA_GET_BEI(tre) (!!(FIELD_GET(BIT(10), MHI_TRE_GET_DWORD(tre, 1))))
|
||||
|
||||
/* RSC transfer descriptor macros */
|
||||
#define MHI_RSCTRE_DATA_PTR(ptr, len) cpu_to_le64(FIELD_PREP(GENMASK(64, 48), len) | ptr)
|
||||
|
10
drivers/bus/mhi/ep/Kconfig
Normal file
10
drivers/bus/mhi/ep/Kconfig
Normal file
@ -0,0 +1,10 @@
|
||||
config MHI_BUS_EP
|
||||
tristate "Modem Host Interface (MHI) bus Endpoint implementation"
|
||||
help
|
||||
Bus driver for MHI protocol. Modem Host Interface (MHI) is a
|
||||
communication protocol used by a host processor to control
|
||||
and communicate a modem device over a high speed peripheral
|
||||
bus or shared memory.
|
||||
|
||||
MHI_BUS_EP implements the MHI protocol for the endpoint devices,
|
||||
such as SDX55 modem connected to the host machine over PCIe.
|
2
drivers/bus/mhi/ep/Makefile
Normal file
2
drivers/bus/mhi/ep/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_MHI_BUS_EP) += mhi_ep.o
|
||||
mhi_ep-y := main.o mmio.o ring.o sm.o
|
218
drivers/bus/mhi/ep/internal.h
Normal file
218
drivers/bus/mhi/ep/internal.h
Normal file
@ -0,0 +1,218 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2022, Linaro Ltd.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MHI_EP_INTERNAL_
|
||||
#define _MHI_EP_INTERNAL_
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
extern struct bus_type mhi_ep_bus_type;
|
||||
|
||||
#define MHI_REG_OFFSET 0x100
|
||||
#define BHI_REG_OFFSET 0x200
|
||||
|
||||
/* MHI registers */
|
||||
#define EP_MHIREGLEN (MHI_REG_OFFSET + MHIREGLEN)
|
||||
#define EP_MHIVER (MHI_REG_OFFSET + MHIVER)
|
||||
#define EP_MHICFG (MHI_REG_OFFSET + MHICFG)
|
||||
#define EP_CHDBOFF (MHI_REG_OFFSET + CHDBOFF)
|
||||
#define EP_ERDBOFF (MHI_REG_OFFSET + ERDBOFF)
|
||||
#define EP_BHIOFF (MHI_REG_OFFSET + BHIOFF)
|
||||
#define EP_BHIEOFF (MHI_REG_OFFSET + BHIEOFF)
|
||||
#define EP_DEBUGOFF (MHI_REG_OFFSET + DEBUGOFF)
|
||||
#define EP_MHICTRL (MHI_REG_OFFSET + MHICTRL)
|
||||
#define EP_MHISTATUS (MHI_REG_OFFSET + MHISTATUS)
|
||||
#define EP_CCABAP_LOWER (MHI_REG_OFFSET + CCABAP_LOWER)
|
||||
#define EP_CCABAP_HIGHER (MHI_REG_OFFSET + CCABAP_HIGHER)
|
||||
#define EP_ECABAP_LOWER (MHI_REG_OFFSET + ECABAP_LOWER)
|
||||
#define EP_ECABAP_HIGHER (MHI_REG_OFFSET + ECABAP_HIGHER)
|
||||
#define EP_CRCBAP_LOWER (MHI_REG_OFFSET + CRCBAP_LOWER)
|
||||
#define EP_CRCBAP_HIGHER (MHI_REG_OFFSET + CRCBAP_HIGHER)
|
||||
#define EP_CRDB_LOWER (MHI_REG_OFFSET + CRDB_LOWER)
|
||||
#define EP_CRDB_HIGHER (MHI_REG_OFFSET + CRDB_HIGHER)
|
||||
#define EP_MHICTRLBASE_LOWER (MHI_REG_OFFSET + MHICTRLBASE_LOWER)
|
||||
#define EP_MHICTRLBASE_HIGHER (MHI_REG_OFFSET + MHICTRLBASE_HIGHER)
|
||||
#define EP_MHICTRLLIMIT_LOWER (MHI_REG_OFFSET + MHICTRLLIMIT_LOWER)
|
||||
#define EP_MHICTRLLIMIT_HIGHER (MHI_REG_OFFSET + MHICTRLLIMIT_HIGHER)
|
||||
#define EP_MHIDATABASE_LOWER (MHI_REG_OFFSET + MHIDATABASE_LOWER)
|
||||
#define EP_MHIDATABASE_HIGHER (MHI_REG_OFFSET + MHIDATABASE_HIGHER)
|
||||
#define EP_MHIDATALIMIT_LOWER (MHI_REG_OFFSET + MHIDATALIMIT_LOWER)
|
||||
#define EP_MHIDATALIMIT_HIGHER (MHI_REG_OFFSET + MHIDATALIMIT_HIGHER)
|
||||
|
||||
/* MHI BHI registers */
|
||||
#define EP_BHI_INTVEC (BHI_REG_OFFSET + BHI_INTVEC)
|
||||
#define EP_BHI_EXECENV (BHI_REG_OFFSET + BHI_EXECENV)
|
||||
|
||||
/* MHI Doorbell registers */
|
||||
#define CHDB_LOWER_n(n) (0x400 + 0x8 * (n))
|
||||
#define CHDB_HIGHER_n(n) (0x404 + 0x8 * (n))
|
||||
#define ERDB_LOWER_n(n) (0x800 + 0x8 * (n))
|
||||
#define ERDB_HIGHER_n(n) (0x804 + 0x8 * (n))
|
||||
|
||||
#define MHI_CTRL_INT_STATUS 0x4
|
||||
#define MHI_CTRL_INT_STATUS_MSK BIT(0)
|
||||
#define MHI_CTRL_INT_STATUS_CRDB_MSK BIT(1)
|
||||
#define MHI_CHDB_INT_STATUS_n(n) (0x28 + 0x4 * (n))
|
||||
#define MHI_ERDB_INT_STATUS_n(n) (0x38 + 0x4 * (n))
|
||||
|
||||
#define MHI_CTRL_INT_CLEAR 0x4c
|
||||
#define MHI_CTRL_INT_MMIO_WR_CLEAR BIT(2)
|
||||
#define MHI_CTRL_INT_CRDB_CLEAR BIT(1)
|
||||
#define MHI_CTRL_INT_CRDB_MHICTRL_CLEAR BIT(0)
|
||||
|
||||
#define MHI_CHDB_INT_CLEAR_n(n) (0x70 + 0x4 * (n))
|
||||
#define MHI_CHDB_INT_CLEAR_n_CLEAR_ALL GENMASK(31, 0)
|
||||
#define MHI_ERDB_INT_CLEAR_n(n) (0x80 + 0x4 * (n))
|
||||
#define MHI_ERDB_INT_CLEAR_n_CLEAR_ALL GENMASK(31, 0)
|
||||
|
||||
/*
|
||||
* Unlike the usual "masking" convention, writing "1" to a bit in this register
|
||||
* enables the interrupt and writing "0" will disable it..
|
||||
*/
|
||||
#define MHI_CTRL_INT_MASK 0x94
|
||||
#define MHI_CTRL_INT_MASK_MASK GENMASK(1, 0)
|
||||
#define MHI_CTRL_MHICTRL_MASK BIT(0)
|
||||
#define MHI_CTRL_CRDB_MASK BIT(1)
|
||||
|
||||
#define MHI_CHDB_INT_MASK_n(n) (0xb8 + 0x4 * (n))
|
||||
#define MHI_CHDB_INT_MASK_n_EN_ALL GENMASK(31, 0)
|
||||
#define MHI_ERDB_INT_MASK_n(n) (0xc8 + 0x4 * (n))
|
||||
#define MHI_ERDB_INT_MASK_n_EN_ALL GENMASK(31, 0)
|
||||
|
||||
#define NR_OF_CMD_RINGS 1
|
||||
#define MHI_MASK_ROWS_CH_DB 4
|
||||
#define MHI_MASK_ROWS_EV_DB 4
|
||||
#define MHI_MASK_CH_LEN 32
|
||||
#define MHI_MASK_EV_LEN 32
|
||||
|
||||
/* Generic context */
|
||||
struct mhi_generic_ctx {
|
||||
__le32 reserved0;
|
||||
__le32 reserved1;
|
||||
__le32 reserved2;
|
||||
|
||||
__le64 rbase __packed __aligned(4);
|
||||
__le64 rlen __packed __aligned(4);
|
||||
__le64 rp __packed __aligned(4);
|
||||
__le64 wp __packed __aligned(4);
|
||||
};
|
||||
|
||||
enum mhi_ep_ring_type {
|
||||
RING_TYPE_CMD,
|
||||
RING_TYPE_ER,
|
||||
RING_TYPE_CH,
|
||||
};
|
||||
|
||||
/* Ring element */
|
||||
union mhi_ep_ring_ctx {
|
||||
struct mhi_cmd_ctxt cmd;
|
||||
struct mhi_event_ctxt ev;
|
||||
struct mhi_chan_ctxt ch;
|
||||
struct mhi_generic_ctx generic;
|
||||
};
|
||||
|
||||
struct mhi_ep_ring_item {
|
||||
struct list_head node;
|
||||
struct mhi_ep_ring *ring;
|
||||
};
|
||||
|
||||
struct mhi_ep_ring {
|
||||
struct mhi_ep_cntrl *mhi_cntrl;
|
||||
union mhi_ep_ring_ctx *ring_ctx;
|
||||
struct mhi_ring_element *ring_cache;
|
||||
enum mhi_ep_ring_type type;
|
||||
u64 rbase;
|
||||
size_t rd_offset;
|
||||
size_t wr_offset;
|
||||
size_t ring_size;
|
||||
u32 db_offset_h;
|
||||
u32 db_offset_l;
|
||||
u32 ch_id;
|
||||
u32 er_index;
|
||||
u32 irq_vector;
|
||||
bool started;
|
||||
};
|
||||
|
||||
struct mhi_ep_cmd {
|
||||
struct mhi_ep_ring ring;
|
||||
};
|
||||
|
||||
struct mhi_ep_event {
|
||||
struct mhi_ep_ring ring;
|
||||
};
|
||||
|
||||
struct mhi_ep_state_transition {
|
||||
struct list_head node;
|
||||
enum mhi_state state;
|
||||
};
|
||||
|
||||
struct mhi_ep_chan {
|
||||
char *name;
|
||||
struct mhi_ep_device *mhi_dev;
|
||||
struct mhi_ep_ring ring;
|
||||
struct mutex lock;
|
||||
void (*xfer_cb)(struct mhi_ep_device *mhi_dev, struct mhi_result *result);
|
||||
enum mhi_ch_state state;
|
||||
enum dma_data_direction dir;
|
||||
u64 tre_loc;
|
||||
u32 tre_size;
|
||||
u32 tre_bytes_left;
|
||||
u32 chan;
|
||||
bool skip_td;
|
||||
};
|
||||
|
||||
/* MHI Ring related functions */
|
||||
void mhi_ep_ring_init(struct mhi_ep_ring *ring, enum mhi_ep_ring_type type, u32 id);
|
||||
void mhi_ep_ring_reset(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring);
|
||||
int mhi_ep_ring_start(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring,
|
||||
union mhi_ep_ring_ctx *ctx);
|
||||
size_t mhi_ep_ring_addr2offset(struct mhi_ep_ring *ring, u64 ptr);
|
||||
int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *element);
|
||||
void mhi_ep_ring_inc_index(struct mhi_ep_ring *ring);
|
||||
int mhi_ep_update_wr_offset(struct mhi_ep_ring *ring);
|
||||
|
||||
/* MMIO related functions */
|
||||
u32 mhi_ep_mmio_read(struct mhi_ep_cntrl *mhi_cntrl, u32 offset);
|
||||
void mhi_ep_mmio_write(struct mhi_ep_cntrl *mhi_cntrl, u32 offset, u32 val);
|
||||
void mhi_ep_mmio_masked_write(struct mhi_ep_cntrl *mhi_cntrl, u32 offset, u32 mask, u32 val);
|
||||
u32 mhi_ep_mmio_masked_read(struct mhi_ep_cntrl *dev, u32 offset, u32 mask);
|
||||
void mhi_ep_mmio_enable_ctrl_interrupt(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
void mhi_ep_mmio_disable_ctrl_interrupt(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
void mhi_ep_mmio_enable_cmdb_interrupt(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
void mhi_ep_mmio_disable_cmdb_interrupt(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
void mhi_ep_mmio_enable_chdb(struct mhi_ep_cntrl *mhi_cntrl, u32 ch_id);
|
||||
void mhi_ep_mmio_disable_chdb(struct mhi_ep_cntrl *mhi_cntrl, u32 ch_id);
|
||||
void mhi_ep_mmio_enable_chdb_interrupts(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
bool mhi_ep_mmio_read_chdb_status_interrupts(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
void mhi_ep_mmio_mask_interrupts(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
void mhi_ep_mmio_get_chc_base(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
void mhi_ep_mmio_get_erc_base(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
void mhi_ep_mmio_get_crc_base(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
u64 mhi_ep_mmio_get_db(struct mhi_ep_ring *ring);
|
||||
void mhi_ep_mmio_set_env(struct mhi_ep_cntrl *mhi_cntrl, u32 value);
|
||||
void mhi_ep_mmio_clear_reset(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
void mhi_ep_mmio_reset(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
void mhi_ep_mmio_get_mhi_state(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_state *state,
|
||||
bool *mhi_reset);
|
||||
void mhi_ep_mmio_init(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
void mhi_ep_mmio_update_ner(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
|
||||
/* MHI EP core functions */
|
||||
int mhi_ep_send_state_change_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_state state);
|
||||
int mhi_ep_send_ee_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_ee_type exec_env);
|
||||
bool mhi_ep_check_mhi_state(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_state cur_mhi_state,
|
||||
enum mhi_state mhi_state);
|
||||
int mhi_ep_set_mhi_state(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_state mhi_state);
|
||||
int mhi_ep_set_m0_state(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
int mhi_ep_set_m3_state(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
int mhi_ep_set_ready_state(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
void mhi_ep_handle_syserr(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
void mhi_ep_resume_channels(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
void mhi_ep_suspend_channels(struct mhi_ep_cntrl *mhi_cntrl);
|
||||
|
||||
#endif
|
1591
drivers/bus/mhi/ep/main.c
Normal file
1591
drivers/bus/mhi/ep/main.c
Normal file
File diff suppressed because it is too large
Load Diff
273
drivers/bus/mhi/ep/mmio.c
Normal file
273
drivers/bus/mhi/ep/mmio.c
Normal file
@ -0,0 +1,273 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2022 Linaro Ltd.
|
||||
* Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mhi_ep.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
u32 mhi_ep_mmio_read(struct mhi_ep_cntrl *mhi_cntrl, u32 offset)
|
||||
{
|
||||
return readl(mhi_cntrl->mmio + offset);
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_write(struct mhi_ep_cntrl *mhi_cntrl, u32 offset, u32 val)
|
||||
{
|
||||
writel(val, mhi_cntrl->mmio + offset);
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_masked_write(struct mhi_ep_cntrl *mhi_cntrl, u32 offset, u32 mask, u32 val)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
regval = mhi_ep_mmio_read(mhi_cntrl, offset);
|
||||
regval &= ~mask;
|
||||
regval |= (val << __ffs(mask)) & mask;
|
||||
mhi_ep_mmio_write(mhi_cntrl, offset, regval);
|
||||
}
|
||||
|
||||
u32 mhi_ep_mmio_masked_read(struct mhi_ep_cntrl *dev, u32 offset, u32 mask)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
regval = mhi_ep_mmio_read(dev, offset);
|
||||
regval &= mask;
|
||||
regval >>= __ffs(mask);
|
||||
|
||||
return regval;
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_get_mhi_state(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_state *state,
|
||||
bool *mhi_reset)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
regval = mhi_ep_mmio_read(mhi_cntrl, EP_MHICTRL);
|
||||
*state = FIELD_GET(MHICTRL_MHISTATE_MASK, regval);
|
||||
*mhi_reset = !!FIELD_GET(MHICTRL_RESET_MASK, regval);
|
||||
}
|
||||
|
||||
static void mhi_ep_mmio_set_chdb(struct mhi_ep_cntrl *mhi_cntrl, u32 ch_id, bool enable)
|
||||
{
|
||||
u32 chid_mask, chid_shift, chdb_idx, val;
|
||||
|
||||
chid_shift = ch_id % 32;
|
||||
chid_mask = BIT(chid_shift);
|
||||
chdb_idx = ch_id / 32;
|
||||
|
||||
val = enable ? 1 : 0;
|
||||
|
||||
mhi_ep_mmio_masked_write(mhi_cntrl, MHI_CHDB_INT_MASK_n(chdb_idx), chid_mask, val);
|
||||
|
||||
/* Update the local copy of the channel mask */
|
||||
mhi_cntrl->chdb[chdb_idx].mask &= ~chid_mask;
|
||||
mhi_cntrl->chdb[chdb_idx].mask |= val << chid_shift;
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_enable_chdb(struct mhi_ep_cntrl *mhi_cntrl, u32 ch_id)
|
||||
{
|
||||
mhi_ep_mmio_set_chdb(mhi_cntrl, ch_id, true);
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_disable_chdb(struct mhi_ep_cntrl *mhi_cntrl, u32 ch_id)
|
||||
{
|
||||
mhi_ep_mmio_set_chdb(mhi_cntrl, ch_id, false);
|
||||
}
|
||||
|
||||
static void mhi_ep_mmio_set_chdb_interrupts(struct mhi_ep_cntrl *mhi_cntrl, bool enable)
|
||||
{
|
||||
u32 val, i;
|
||||
|
||||
val = enable ? MHI_CHDB_INT_MASK_n_EN_ALL : 0;
|
||||
|
||||
for (i = 0; i < MHI_MASK_ROWS_CH_DB; i++) {
|
||||
mhi_ep_mmio_write(mhi_cntrl, MHI_CHDB_INT_MASK_n(i), val);
|
||||
mhi_cntrl->chdb[i].mask = val;
|
||||
}
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_enable_chdb_interrupts(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
mhi_ep_mmio_set_chdb_interrupts(mhi_cntrl, true);
|
||||
}
|
||||
|
||||
static void mhi_ep_mmio_mask_chdb_interrupts(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
mhi_ep_mmio_set_chdb_interrupts(mhi_cntrl, false);
|
||||
}
|
||||
|
||||
bool mhi_ep_mmio_read_chdb_status_interrupts(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
bool chdb = false;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < MHI_MASK_ROWS_CH_DB; i++) {
|
||||
mhi_cntrl->chdb[i].status = mhi_ep_mmio_read(mhi_cntrl, MHI_CHDB_INT_STATUS_n(i));
|
||||
if (mhi_cntrl->chdb[i].status)
|
||||
chdb = true;
|
||||
}
|
||||
|
||||
/* Return whether a channel doorbell interrupt occurred or not */
|
||||
return chdb;
|
||||
}
|
||||
|
||||
static void mhi_ep_mmio_set_erdb_interrupts(struct mhi_ep_cntrl *mhi_cntrl, bool enable)
|
||||
{
|
||||
u32 val, i;
|
||||
|
||||
val = enable ? MHI_ERDB_INT_MASK_n_EN_ALL : 0;
|
||||
|
||||
for (i = 0; i < MHI_MASK_ROWS_EV_DB; i++)
|
||||
mhi_ep_mmio_write(mhi_cntrl, MHI_ERDB_INT_MASK_n(i), val);
|
||||
}
|
||||
|
||||
static void mhi_ep_mmio_mask_erdb_interrupts(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
mhi_ep_mmio_set_erdb_interrupts(mhi_cntrl, false);
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_enable_ctrl_interrupt(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
mhi_ep_mmio_masked_write(mhi_cntrl, MHI_CTRL_INT_MASK,
|
||||
MHI_CTRL_MHICTRL_MASK, 1);
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_disable_ctrl_interrupt(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
mhi_ep_mmio_masked_write(mhi_cntrl, MHI_CTRL_INT_MASK,
|
||||
MHI_CTRL_MHICTRL_MASK, 0);
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_enable_cmdb_interrupt(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
mhi_ep_mmio_masked_write(mhi_cntrl, MHI_CTRL_INT_MASK,
|
||||
MHI_CTRL_CRDB_MASK, 1);
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_disable_cmdb_interrupt(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
mhi_ep_mmio_masked_write(mhi_cntrl, MHI_CTRL_INT_MASK,
|
||||
MHI_CTRL_CRDB_MASK, 0);
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_mask_interrupts(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
mhi_ep_mmio_disable_ctrl_interrupt(mhi_cntrl);
|
||||
mhi_ep_mmio_disable_cmdb_interrupt(mhi_cntrl);
|
||||
mhi_ep_mmio_mask_chdb_interrupts(mhi_cntrl);
|
||||
mhi_ep_mmio_mask_erdb_interrupts(mhi_cntrl);
|
||||
}
|
||||
|
||||
static void mhi_ep_mmio_clear_interrupts(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < MHI_MASK_ROWS_CH_DB; i++)
|
||||
mhi_ep_mmio_write(mhi_cntrl, MHI_CHDB_INT_CLEAR_n(i),
|
||||
MHI_CHDB_INT_CLEAR_n_CLEAR_ALL);
|
||||
|
||||
for (i = 0; i < MHI_MASK_ROWS_EV_DB; i++)
|
||||
mhi_ep_mmio_write(mhi_cntrl, MHI_ERDB_INT_CLEAR_n(i),
|
||||
MHI_ERDB_INT_CLEAR_n_CLEAR_ALL);
|
||||
|
||||
mhi_ep_mmio_write(mhi_cntrl, MHI_CTRL_INT_CLEAR,
|
||||
MHI_CTRL_INT_MMIO_WR_CLEAR |
|
||||
MHI_CTRL_INT_CRDB_CLEAR |
|
||||
MHI_CTRL_INT_CRDB_MHICTRL_CLEAR);
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_get_chc_base(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
regval = mhi_ep_mmio_read(mhi_cntrl, EP_CCABAP_HIGHER);
|
||||
mhi_cntrl->ch_ctx_host_pa = regval;
|
||||
mhi_cntrl->ch_ctx_host_pa <<= 32;
|
||||
|
||||
regval = mhi_ep_mmio_read(mhi_cntrl, EP_CCABAP_LOWER);
|
||||
mhi_cntrl->ch_ctx_host_pa |= regval;
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_get_erc_base(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
regval = mhi_ep_mmio_read(mhi_cntrl, EP_ECABAP_HIGHER);
|
||||
mhi_cntrl->ev_ctx_host_pa = regval;
|
||||
mhi_cntrl->ev_ctx_host_pa <<= 32;
|
||||
|
||||
regval = mhi_ep_mmio_read(mhi_cntrl, EP_ECABAP_LOWER);
|
||||
mhi_cntrl->ev_ctx_host_pa |= regval;
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_get_crc_base(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
regval = mhi_ep_mmio_read(mhi_cntrl, EP_CRCBAP_HIGHER);
|
||||
mhi_cntrl->cmd_ctx_host_pa = regval;
|
||||
mhi_cntrl->cmd_ctx_host_pa <<= 32;
|
||||
|
||||
regval = mhi_ep_mmio_read(mhi_cntrl, EP_CRCBAP_LOWER);
|
||||
mhi_cntrl->cmd_ctx_host_pa |= regval;
|
||||
}
|
||||
|
||||
u64 mhi_ep_mmio_get_db(struct mhi_ep_ring *ring)
|
||||
{
|
||||
struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
|
||||
u64 db_offset;
|
||||
u32 regval;
|
||||
|
||||
regval = mhi_ep_mmio_read(mhi_cntrl, ring->db_offset_h);
|
||||
db_offset = regval;
|
||||
db_offset <<= 32;
|
||||
|
||||
regval = mhi_ep_mmio_read(mhi_cntrl, ring->db_offset_l);
|
||||
db_offset |= regval;
|
||||
|
||||
return db_offset;
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_set_env(struct mhi_ep_cntrl *mhi_cntrl, u32 value)
|
||||
{
|
||||
mhi_ep_mmio_write(mhi_cntrl, EP_BHI_EXECENV, value);
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_clear_reset(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
mhi_ep_mmio_masked_write(mhi_cntrl, EP_MHICTRL, MHICTRL_RESET_MASK, 0);
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_reset(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
mhi_ep_mmio_write(mhi_cntrl, EP_MHICTRL, 0);
|
||||
mhi_ep_mmio_write(mhi_cntrl, EP_MHISTATUS, 0);
|
||||
mhi_ep_mmio_clear_interrupts(mhi_cntrl);
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_init(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
mhi_cntrl->chdb_offset = mhi_ep_mmio_read(mhi_cntrl, EP_CHDBOFF);
|
||||
mhi_cntrl->erdb_offset = mhi_ep_mmio_read(mhi_cntrl, EP_ERDBOFF);
|
||||
|
||||
regval = mhi_ep_mmio_read(mhi_cntrl, EP_MHICFG);
|
||||
mhi_cntrl->event_rings = FIELD_GET(MHICFG_NER_MASK, regval);
|
||||
mhi_cntrl->hw_event_rings = FIELD_GET(MHICFG_NHWER_MASK, regval);
|
||||
|
||||
mhi_ep_mmio_reset(mhi_cntrl);
|
||||
}
|
||||
|
||||
void mhi_ep_mmio_update_ner(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
regval = mhi_ep_mmio_read(mhi_cntrl, EP_MHICFG);
|
||||
mhi_cntrl->event_rings = FIELD_GET(MHICFG_NER_MASK, regval);
|
||||
mhi_cntrl->hw_event_rings = FIELD_GET(MHICFG_NHWER_MASK, regval);
|
||||
}
|
207
drivers/bus/mhi/ep/ring.c
Normal file
207
drivers/bus/mhi/ep/ring.c
Normal file
@ -0,0 +1,207 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2022 Linaro Ltd.
|
||||
* Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
*/
|
||||
|
||||
#include <linux/mhi_ep.h>
|
||||
#include "internal.h"
|
||||
|
||||
size_t mhi_ep_ring_addr2offset(struct mhi_ep_ring *ring, u64 ptr)
|
||||
{
|
||||
return (ptr - ring->rbase) / sizeof(struct mhi_ring_element);
|
||||
}
|
||||
|
||||
static u32 mhi_ep_ring_num_elems(struct mhi_ep_ring *ring)
|
||||
{
|
||||
__le64 rlen;
|
||||
|
||||
memcpy_fromio(&rlen, (void __iomem *) &ring->ring_ctx->generic.rlen, sizeof(u64));
|
||||
|
||||
return le64_to_cpu(rlen) / sizeof(struct mhi_ring_element);
|
||||
}
|
||||
|
||||
void mhi_ep_ring_inc_index(struct mhi_ep_ring *ring)
|
||||
{
|
||||
ring->rd_offset = (ring->rd_offset + 1) % ring->ring_size;
|
||||
}
|
||||
|
||||
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;
|
||||
int ret;
|
||||
|
||||
/* Don't proceed in the case of event ring. This happens during mhi_ep_ring_start(). */
|
||||
if (ring->type == RING_TYPE_ER)
|
||||
return 0;
|
||||
|
||||
/* No need to cache the ring if write pointer is unmodified */
|
||||
if (ring->wr_offset == end)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
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);
|
||||
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));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(dev, "Cached ring: start %zu end %zu size %zu\n", start, end, copy_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mhi_ep_cache_ring(struct mhi_ep_ring *ring, u64 wr_ptr)
|
||||
{
|
||||
size_t wr_offset;
|
||||
int ret;
|
||||
|
||||
wr_offset = mhi_ep_ring_addr2offset(ring, wr_ptr);
|
||||
|
||||
/* Cache the host ring till write offset */
|
||||
ret = __mhi_ep_cache_ring(ring, wr_offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ring->wr_offset = wr_offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mhi_ep_update_wr_offset(struct mhi_ep_ring *ring)
|
||||
{
|
||||
u64 wr_ptr;
|
||||
|
||||
wr_ptr = mhi_ep_mmio_get_db(ring);
|
||||
|
||||
return mhi_ep_cache_ring(ring, wr_ptr);
|
||||
}
|
||||
|
||||
/* TODO: Support for adding multiple ring elements to the ring */
|
||||
int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *el)
|
||||
{
|
||||
struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
|
||||
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
||||
size_t old_offset = 0;
|
||||
u32 num_free_elem;
|
||||
__le64 rp;
|
||||
int ret;
|
||||
|
||||
ret = mhi_ep_update_wr_offset(ring);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error updating write pointer\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ring->rd_offset < ring->wr_offset)
|
||||
num_free_elem = (ring->wr_offset - ring->rd_offset) - 1;
|
||||
else
|
||||
num_free_elem = ((ring->ring_size - ring->rd_offset) + ring->wr_offset) - 1;
|
||||
|
||||
/* Check if there is space in ring for adding at least an element */
|
||||
if (!num_free_elem) {
|
||||
dev_err(dev, "No space left in the ring\n");
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
old_offset = ring->rd_offset;
|
||||
mhi_ep_ring_inc_index(ring);
|
||||
|
||||
dev_dbg(dev, "Adding an element to ring at offset (%zu)\n", ring->rd_offset);
|
||||
|
||||
/* Update rp in ring context */
|
||||
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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mhi_ep_ring_init(struct mhi_ep_ring *ring, enum mhi_ep_ring_type type, u32 id)
|
||||
{
|
||||
ring->type = type;
|
||||
if (ring->type == RING_TYPE_CMD) {
|
||||
ring->db_offset_h = EP_CRDB_HIGHER;
|
||||
ring->db_offset_l = EP_CRDB_LOWER;
|
||||
} else if (ring->type == RING_TYPE_CH) {
|
||||
ring->db_offset_h = CHDB_HIGHER_n(id);
|
||||
ring->db_offset_l = CHDB_LOWER_n(id);
|
||||
ring->ch_id = id;
|
||||
} else {
|
||||
ring->db_offset_h = ERDB_HIGHER_n(id);
|
||||
ring->db_offset_l = ERDB_LOWER_n(id);
|
||||
}
|
||||
}
|
||||
|
||||
int mhi_ep_ring_start(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring,
|
||||
union mhi_ep_ring_ctx *ctx)
|
||||
{
|
||||
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
||||
__le64 val;
|
||||
int ret;
|
||||
|
||||
ring->mhi_cntrl = mhi_cntrl;
|
||||
ring->ring_ctx = ctx;
|
||||
ring->ring_size = mhi_ep_ring_num_elems(ring);
|
||||
memcpy_fromio(&val, (void __iomem *) &ring->ring_ctx->generic.rbase, sizeof(u64));
|
||||
ring->rbase = le64_to_cpu(val);
|
||||
|
||||
if (ring->type == RING_TYPE_CH)
|
||||
ring->er_index = le32_to_cpu(ring->ring_ctx->ch.erindex);
|
||||
|
||||
if (ring->type == RING_TYPE_ER)
|
||||
ring->irq_vector = le32_to_cpu(ring->ring_ctx->ev.msivec);
|
||||
|
||||
/* During ring init, both rp and wp are equal */
|
||||
memcpy_fromio(&val, (void __iomem *) &ring->ring_ctx->generic.rp, sizeof(u64));
|
||||
ring->rd_offset = mhi_ep_ring_addr2offset(ring, le64_to_cpu(val));
|
||||
ring->wr_offset = mhi_ep_ring_addr2offset(ring, le64_to_cpu(val));
|
||||
|
||||
/* Allocate ring cache memory for holding the copy of host ring */
|
||||
ring->ring_cache = kcalloc(ring->ring_size, sizeof(struct mhi_ring_element), GFP_KERNEL);
|
||||
if (!ring->ring_cache)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy_fromio(&val, (void __iomem *) &ring->ring_ctx->generic.wp, sizeof(u64));
|
||||
ret = mhi_ep_cache_ring(ring, le64_to_cpu(val));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to cache ring\n");
|
||||
kfree(ring->ring_cache);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ring->started = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mhi_ep_ring_reset(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring)
|
||||
{
|
||||
ring->started = false;
|
||||
kfree(ring->ring_cache);
|
||||
ring->ring_cache = NULL;
|
||||
}
|
148
drivers/bus/mhi/ep/sm.c
Normal file
148
drivers/bus/mhi/ep/sm.c
Normal file
@ -0,0 +1,148 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2022 Linaro Ltd.
|
||||
* Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mhi_ep.h>
|
||||
#include "internal.h"
|
||||
|
||||
bool __must_check mhi_ep_check_mhi_state(struct mhi_ep_cntrl *mhi_cntrl,
|
||||
enum mhi_state cur_mhi_state,
|
||||
enum mhi_state mhi_state)
|
||||
{
|
||||
if (mhi_state == MHI_STATE_SYS_ERR)
|
||||
return true; /* Allowed in any state */
|
||||
|
||||
if (mhi_state == MHI_STATE_READY)
|
||||
return cur_mhi_state == MHI_STATE_RESET;
|
||||
|
||||
if (mhi_state == MHI_STATE_M0)
|
||||
return cur_mhi_state == MHI_STATE_M3 || cur_mhi_state == MHI_STATE_READY;
|
||||
|
||||
if (mhi_state == MHI_STATE_M3)
|
||||
return cur_mhi_state == MHI_STATE_M0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int mhi_ep_set_mhi_state(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_state mhi_state)
|
||||
{
|
||||
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
||||
|
||||
if (!mhi_ep_check_mhi_state(mhi_cntrl, mhi_cntrl->mhi_state, mhi_state)) {
|
||||
dev_err(dev, "MHI state change to %s from %s is not allowed!\n",
|
||||
mhi_state_str(mhi_state),
|
||||
mhi_state_str(mhi_cntrl->mhi_state));
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
/* TODO: Add support for M1 and M2 states */
|
||||
if (mhi_state == MHI_STATE_M1 || mhi_state == MHI_STATE_M2) {
|
||||
dev_err(dev, "MHI state (%s) not supported\n", mhi_state_str(mhi_state));
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
mhi_ep_mmio_masked_write(mhi_cntrl, EP_MHISTATUS, MHISTATUS_MHISTATE_MASK, mhi_state);
|
||||
mhi_cntrl->mhi_state = mhi_state;
|
||||
|
||||
if (mhi_state == MHI_STATE_READY)
|
||||
mhi_ep_mmio_masked_write(mhi_cntrl, EP_MHISTATUS, MHISTATUS_READY_MASK, 1);
|
||||
|
||||
if (mhi_state == MHI_STATE_SYS_ERR)
|
||||
mhi_ep_mmio_masked_write(mhi_cntrl, EP_MHISTATUS, MHISTATUS_SYSERR_MASK, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mhi_ep_set_m0_state(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
||||
enum mhi_state old_state;
|
||||
int ret;
|
||||
|
||||
/* If MHI is in M3, resume suspended channels */
|
||||
spin_lock_bh(&mhi_cntrl->state_lock);
|
||||
old_state = mhi_cntrl->mhi_state;
|
||||
if (old_state == MHI_STATE_M3)
|
||||
mhi_ep_resume_channels(mhi_cntrl);
|
||||
|
||||
ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_M0);
|
||||
spin_unlock_bh(&mhi_cntrl->state_lock);
|
||||
|
||||
if (ret) {
|
||||
mhi_ep_handle_syserr(mhi_cntrl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Signal host that the device moved to M0 */
|
||||
ret = mhi_ep_send_state_change_event(mhi_cntrl, MHI_STATE_M0);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed sending M0 state change event\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (old_state == MHI_STATE_READY) {
|
||||
/* Send AMSS EE event to host */
|
||||
ret = mhi_ep_send_ee_event(mhi_cntrl, MHI_EE_AMSS);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed sending AMSS EE event\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mhi_ep_set_m3_state(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&mhi_cntrl->state_lock);
|
||||
ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_M3);
|
||||
spin_unlock_bh(&mhi_cntrl->state_lock);
|
||||
|
||||
if (ret) {
|
||||
mhi_ep_handle_syserr(mhi_cntrl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mhi_ep_suspend_channels(mhi_cntrl);
|
||||
|
||||
/* Signal host that the device moved to M3 */
|
||||
ret = mhi_ep_send_state_change_event(mhi_cntrl, MHI_STATE_M3);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed sending M3 state change event\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mhi_ep_set_ready_state(struct mhi_ep_cntrl *mhi_cntrl)
|
||||
{
|
||||
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
||||
enum mhi_state mhi_state;
|
||||
int ret, is_ready;
|
||||
|
||||
spin_lock_bh(&mhi_cntrl->state_lock);
|
||||
/* Ensure that the MHISTATUS is set to RESET by host */
|
||||
mhi_state = mhi_ep_mmio_masked_read(mhi_cntrl, EP_MHISTATUS, MHISTATUS_MHISTATE_MASK);
|
||||
is_ready = mhi_ep_mmio_masked_read(mhi_cntrl, EP_MHISTATUS, MHISTATUS_READY_MASK);
|
||||
|
||||
if (mhi_state != MHI_STATE_RESET || is_ready) {
|
||||
dev_err(dev, "READY state transition failed. MHI host not in RESET state\n");
|
||||
spin_unlock_bh(&mhi_cntrl->state_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_READY);
|
||||
spin_unlock_bh(&mhi_cntrl->state_lock);
|
||||
|
||||
if (ret)
|
||||
mhi_ep_handle_syserr(mhi_cntrl);
|
||||
|
||||
return ret;
|
||||
}
|
@ -19,8 +19,8 @@
|
||||
#include "internal.h"
|
||||
|
||||
/* Setup RDDM vector table for RDDM transfer and program RXVEC */
|
||||
void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl,
|
||||
struct image_info *img_info)
|
||||
int mhi_rddm_prepare(struct mhi_controller *mhi_cntrl,
|
||||
struct image_info *img_info)
|
||||
{
|
||||
struct mhi_buf *mhi_buf = img_info->mhi_buf;
|
||||
struct bhi_vec_entry *bhi_vec = img_info->bhi_vec;
|
||||
@ -28,6 +28,7 @@ void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl,
|
||||
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
||||
u32 sequence_id;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < img_info->entries - 1; i++, mhi_buf++, bhi_vec++) {
|
||||
bhi_vec->dma_addr = mhi_buf->dma_addr;
|
||||
@ -45,11 +46,17 @@ void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl,
|
||||
mhi_write_reg(mhi_cntrl, base, BHIE_RXVECSIZE_OFFS, mhi_buf->len);
|
||||
sequence_id = MHI_RANDOM_U32_NONZERO(BHIE_RXVECSTATUS_SEQNUM_BMSK);
|
||||
|
||||
mhi_write_reg_field(mhi_cntrl, base, BHIE_RXVECDB_OFFS,
|
||||
BHIE_RXVECDB_SEQNUM_BMSK, sequence_id);
|
||||
ret = mhi_write_reg_field(mhi_cntrl, base, BHIE_RXVECDB_OFFS,
|
||||
BHIE_RXVECDB_SEQNUM_BMSK, sequence_id);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to write sequence ID for BHIE_RXVECDB\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "Address: %p and len: 0x%zx sequence: %u\n",
|
||||
&mhi_buf->dma_addr, mhi_buf->len, sequence_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Collect RDDM buffer during kernel panic */
|
||||
@ -198,10 +205,13 @@ static int mhi_fw_load_bhie(struct mhi_controller *mhi_cntrl,
|
||||
|
||||
mhi_write_reg(mhi_cntrl, base, BHIE_TXVECSIZE_OFFS, mhi_buf->len);
|
||||
|
||||
mhi_write_reg_field(mhi_cntrl, base, BHIE_TXVECDB_OFFS,
|
||||
BHIE_TXVECDB_SEQNUM_BMSK, sequence_id);
|
||||
ret = mhi_write_reg_field(mhi_cntrl, base, BHIE_TXVECDB_OFFS,
|
||||
BHIE_TXVECDB_SEQNUM_BMSK, sequence_id);
|
||||
read_unlock_bh(pm_lock);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Wait for the image download to complete */
|
||||
ret = wait_event_timeout(mhi_cntrl->state_event,
|
||||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) ||
|
||||
|
@ -86,7 +86,7 @@ static ssize_t serial_number_show(struct device *dev,
|
||||
struct mhi_device *mhi_dev = to_mhi_device(dev);
|
||||
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "Serial Number: %u\n",
|
||||
return sysfs_emit(buf, "Serial Number: %u\n",
|
||||
mhi_cntrl->serial_number);
|
||||
}
|
||||
static DEVICE_ATTR_RO(serial_number);
|
||||
@ -100,17 +100,30 @@ static ssize_t oem_pk_hash_show(struct device *dev,
|
||||
int i, cnt = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mhi_cntrl->oem_pk_hash); i++)
|
||||
cnt += snprintf(buf + cnt, PAGE_SIZE - cnt,
|
||||
"OEMPKHASH[%d]: 0x%x\n", i,
|
||||
mhi_cntrl->oem_pk_hash[i]);
|
||||
cnt += sysfs_emit_at(buf, cnt, "OEMPKHASH[%d]: 0x%x\n",
|
||||
i, mhi_cntrl->oem_pk_hash[i]);
|
||||
|
||||
return cnt;
|
||||
}
|
||||
static DEVICE_ATTR_RO(oem_pk_hash);
|
||||
|
||||
static ssize_t soc_reset_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct mhi_device *mhi_dev = to_mhi_device(dev);
|
||||
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
|
||||
|
||||
mhi_soc_reset(mhi_cntrl);
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_WO(soc_reset);
|
||||
|
||||
static struct attribute *mhi_dev_attrs[] = {
|
||||
&dev_attr_serial_number.attr,
|
||||
&dev_attr_oem_pk_hash.attr,
|
||||
&dev_attr_soc_reset.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(mhi_dev);
|
||||
@ -425,74 +438,65 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
|
||||
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
||||
struct {
|
||||
u32 offset;
|
||||
u32 mask;
|
||||
u32 val;
|
||||
} reg_info[] = {
|
||||
{
|
||||
CCABAP_HIGHER, U32_MAX,
|
||||
CCABAP_HIGHER,
|
||||
upper_32_bits(mhi_cntrl->mhi_ctxt->chan_ctxt_addr),
|
||||
},
|
||||
{
|
||||
CCABAP_LOWER, U32_MAX,
|
||||
CCABAP_LOWER,
|
||||
lower_32_bits(mhi_cntrl->mhi_ctxt->chan_ctxt_addr),
|
||||
},
|
||||
{
|
||||
ECABAP_HIGHER, U32_MAX,
|
||||
ECABAP_HIGHER,
|
||||
upper_32_bits(mhi_cntrl->mhi_ctxt->er_ctxt_addr),
|
||||
},
|
||||
{
|
||||
ECABAP_LOWER, U32_MAX,
|
||||
ECABAP_LOWER,
|
||||
lower_32_bits(mhi_cntrl->mhi_ctxt->er_ctxt_addr),
|
||||
},
|
||||
{
|
||||
CRCBAP_HIGHER, U32_MAX,
|
||||
CRCBAP_HIGHER,
|
||||
upper_32_bits(mhi_cntrl->mhi_ctxt->cmd_ctxt_addr),
|
||||
},
|
||||
{
|
||||
CRCBAP_LOWER, U32_MAX,
|
||||
CRCBAP_LOWER,
|
||||
lower_32_bits(mhi_cntrl->mhi_ctxt->cmd_ctxt_addr),
|
||||
},
|
||||
{
|
||||
MHICFG, MHICFG_NER_MASK,
|
||||
mhi_cntrl->total_ev_rings,
|
||||
},
|
||||
{
|
||||
MHICFG, MHICFG_NHWER_MASK,
|
||||
mhi_cntrl->hw_ev_rings,
|
||||
},
|
||||
{
|
||||
MHICTRLBASE_HIGHER, U32_MAX,
|
||||
MHICTRLBASE_HIGHER,
|
||||
upper_32_bits(mhi_cntrl->iova_start),
|
||||
},
|
||||
{
|
||||
MHICTRLBASE_LOWER, U32_MAX,
|
||||
MHICTRLBASE_LOWER,
|
||||
lower_32_bits(mhi_cntrl->iova_start),
|
||||
},
|
||||
{
|
||||
MHIDATABASE_HIGHER, U32_MAX,
|
||||
MHIDATABASE_HIGHER,
|
||||
upper_32_bits(mhi_cntrl->iova_start),
|
||||
},
|
||||
{
|
||||
MHIDATABASE_LOWER, U32_MAX,
|
||||
MHIDATABASE_LOWER,
|
||||
lower_32_bits(mhi_cntrl->iova_start),
|
||||
},
|
||||
{
|
||||
MHICTRLLIMIT_HIGHER, U32_MAX,
|
||||
MHICTRLLIMIT_HIGHER,
|
||||
upper_32_bits(mhi_cntrl->iova_stop),
|
||||
},
|
||||
{
|
||||
MHICTRLLIMIT_LOWER, U32_MAX,
|
||||
MHICTRLLIMIT_LOWER,
|
||||
lower_32_bits(mhi_cntrl->iova_stop),
|
||||
},
|
||||
{
|
||||
MHIDATALIMIT_HIGHER, U32_MAX,
|
||||
MHIDATALIMIT_HIGHER,
|
||||
upper_32_bits(mhi_cntrl->iova_stop),
|
||||
},
|
||||
{
|
||||
MHIDATALIMIT_LOWER, U32_MAX,
|
||||
MHIDATALIMIT_LOWER,
|
||||
lower_32_bits(mhi_cntrl->iova_stop),
|
||||
},
|
||||
{ 0, 0, 0 }
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
dev_dbg(dev, "Initializing MHI registers\n");
|
||||
@ -534,8 +538,22 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
|
||||
|
||||
/* Write to MMIO registers */
|
||||
for (i = 0; reg_info[i].offset; i++)
|
||||
mhi_write_reg_field(mhi_cntrl, base, reg_info[i].offset,
|
||||
reg_info[i].mask, reg_info[i].val);
|
||||
mhi_write_reg(mhi_cntrl, base, reg_info[i].offset,
|
||||
reg_info[i].val);
|
||||
|
||||
ret = mhi_write_reg_field(mhi_cntrl, base, MHICFG, MHICFG_NER_MASK,
|
||||
mhi_cntrl->total_ev_rings);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to write MHICFG register\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mhi_write_reg_field(mhi_cntrl, base, MHICFG, MHICFG_NHWER_MASK,
|
||||
mhi_cntrl->hw_ev_rings);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to write MHICFG register\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1103,8 +1121,15 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl)
|
||||
*/
|
||||
mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->rddm_image,
|
||||
mhi_cntrl->rddm_size);
|
||||
if (mhi_cntrl->rddm_image)
|
||||
mhi_rddm_prepare(mhi_cntrl, mhi_cntrl->rddm_image);
|
||||
if (mhi_cntrl->rddm_image) {
|
||||
ret = mhi_rddm_prepare(mhi_cntrl,
|
||||
mhi_cntrl->rddm_image);
|
||||
if (ret) {
|
||||
mhi_free_bhie_table(mhi_cntrl,
|
||||
mhi_cntrl->rddm_image);
|
||||
goto error_reg_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&mhi_cntrl->pm_mutex);
|
||||
|
@ -324,8 +324,9 @@ int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl,
|
||||
u32 val, u32 delayus);
|
||||
void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base,
|
||||
u32 offset, u32 val);
|
||||
void mhi_write_reg_field(struct mhi_controller *mhi_cntrl, void __iomem *base,
|
||||
u32 offset, u32 mask, u32 val);
|
||||
int __must_check mhi_write_reg_field(struct mhi_controller *mhi_cntrl,
|
||||
void __iomem *base, u32 offset, u32 mask,
|
||||
u32 val);
|
||||
void mhi_ring_er_db(struct mhi_event *mhi_event);
|
||||
void mhi_write_db(struct mhi_controller *mhi_cntrl, void __iomem *db_addr,
|
||||
dma_addr_t db_val);
|
||||
@ -339,7 +340,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl);
|
||||
void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl);
|
||||
int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl);
|
||||
void mhi_deinit_free_irq(struct mhi_controller *mhi_cntrl);
|
||||
void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl,
|
||||
int mhi_rddm_prepare(struct mhi_controller *mhi_cntrl,
|
||||
struct image_info *img_info);
|
||||
void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl);
|
||||
|
||||
|
@ -65,19 +65,22 @@ void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base,
|
||||
mhi_cntrl->write_reg(mhi_cntrl, base + offset, val);
|
||||
}
|
||||
|
||||
void mhi_write_reg_field(struct mhi_controller *mhi_cntrl, void __iomem *base,
|
||||
u32 offset, u32 mask, u32 val)
|
||||
int __must_check mhi_write_reg_field(struct mhi_controller *mhi_cntrl,
|
||||
void __iomem *base, u32 offset, u32 mask,
|
||||
u32 val)
|
||||
{
|
||||
int ret;
|
||||
u32 tmp;
|
||||
|
||||
ret = mhi_read_reg(mhi_cntrl, base, offset, &tmp);
|
||||
if (ret)
|
||||
return;
|
||||
return ret;
|
||||
|
||||
tmp &= ~mask;
|
||||
tmp |= (val << __ffs(mask));
|
||||
mhi_write_reg(mhi_cntrl, base, offset, tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mhi_write_db(struct mhi_controller *mhi_cntrl, void __iomem *db_addr,
|
||||
@ -531,18 +534,13 @@ irqreturn_t mhi_intvec_handler(int irq_number, void *dev)
|
||||
static void mhi_recycle_ev_ring_element(struct mhi_controller *mhi_cntrl,
|
||||
struct mhi_ring *ring)
|
||||
{
|
||||
dma_addr_t ctxt_wp;
|
||||
|
||||
/* Update the WP */
|
||||
ring->wp += ring->el_size;
|
||||
ctxt_wp = le64_to_cpu(*ring->ctxt_wp) + ring->el_size;
|
||||
|
||||
if (ring->wp >= (ring->base + ring->len)) {
|
||||
if (ring->wp >= (ring->base + ring->len))
|
||||
ring->wp = ring->base;
|
||||
ctxt_wp = ring->iommu_base;
|
||||
}
|
||||
|
||||
*ring->ctxt_wp = cpu_to_le64(ctxt_wp);
|
||||
*ring->ctxt_wp = cpu_to_le64(ring->iommu_base + (ring->wp - ring->base));
|
||||
|
||||
/* Update the RP */
|
||||
ring->rp += ring->el_size;
|
||||
|
@ -371,7 +371,16 @@ static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = {
|
||||
.sideband_wake = false,
|
||||
};
|
||||
|
||||
static const struct mhi_channel_config mhi_mv31_channels[] = {
|
||||
static const struct mhi_pci_dev_info mhi_foxconn_sdx65_info = {
|
||||
.name = "foxconn-sdx65",
|
||||
.config = &modem_foxconn_sdx55_config,
|
||||
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
|
||||
.dma_data_width = 32,
|
||||
.mru_default = 32768,
|
||||
.sideband_wake = false,
|
||||
};
|
||||
|
||||
static const struct mhi_channel_config mhi_mv3x_channels[] = {
|
||||
MHI_CHANNEL_CONFIG_UL(0, "LOOPBACK", 64, 0),
|
||||
MHI_CHANNEL_CONFIG_DL(1, "LOOPBACK", 64, 0),
|
||||
/* MBIM Control Channel */
|
||||
@ -382,25 +391,33 @@ static const struct mhi_channel_config mhi_mv31_channels[] = {
|
||||
MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 512, 3),
|
||||
};
|
||||
|
||||
static struct mhi_event_config mhi_mv31_events[] = {
|
||||
static struct mhi_event_config mhi_mv3x_events[] = {
|
||||
MHI_EVENT_CONFIG_CTRL(0, 256),
|
||||
MHI_EVENT_CONFIG_DATA(1, 256),
|
||||
MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100),
|
||||
MHI_EVENT_CONFIG_HW_DATA(3, 1024, 101),
|
||||
};
|
||||
|
||||
static const struct mhi_controller_config modem_mv31_config = {
|
||||
static const struct mhi_controller_config modem_mv3x_config = {
|
||||
.max_channels = 128,
|
||||
.timeout_ms = 20000,
|
||||
.num_channels = ARRAY_SIZE(mhi_mv31_channels),
|
||||
.ch_cfg = mhi_mv31_channels,
|
||||
.num_events = ARRAY_SIZE(mhi_mv31_events),
|
||||
.event_cfg = mhi_mv31_events,
|
||||
.num_channels = ARRAY_SIZE(mhi_mv3x_channels),
|
||||
.ch_cfg = mhi_mv3x_channels,
|
||||
.num_events = ARRAY_SIZE(mhi_mv3x_events),
|
||||
.event_cfg = mhi_mv3x_events,
|
||||
};
|
||||
|
||||
static const struct mhi_pci_dev_info mhi_mv31_info = {
|
||||
.name = "cinterion-mv31",
|
||||
.config = &modem_mv31_config,
|
||||
.config = &modem_mv3x_config,
|
||||
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
|
||||
.dma_data_width = 32,
|
||||
.mru_default = 32768,
|
||||
};
|
||||
|
||||
static const struct mhi_pci_dev_info mhi_mv32_info = {
|
||||
.name = "cinterion-mv32",
|
||||
.config = &modem_mv3x_config,
|
||||
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
|
||||
.dma_data_width = 32,
|
||||
.mru_default = 32768,
|
||||
@ -446,20 +463,100 @@ static const struct mhi_pci_dev_info mhi_sierra_em919x_info = {
|
||||
.sideband_wake = false,
|
||||
};
|
||||
|
||||
static const struct mhi_channel_config mhi_telit_fn980_hw_v1_channels[] = {
|
||||
MHI_CHANNEL_CONFIG_UL(14, "QMI", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_DL(15, "QMI", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_UL(20, "IPCR", 16, 0),
|
||||
MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(21, "IPCR", 16, 0),
|
||||
MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 1),
|
||||
MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 2),
|
||||
};
|
||||
|
||||
static struct mhi_event_config mhi_telit_fn980_hw_v1_events[] = {
|
||||
MHI_EVENT_CONFIG_CTRL(0, 128),
|
||||
MHI_EVENT_CONFIG_HW_DATA(1, 1024, 100),
|
||||
MHI_EVENT_CONFIG_HW_DATA(2, 2048, 101)
|
||||
};
|
||||
|
||||
static struct mhi_controller_config modem_telit_fn980_hw_v1_config = {
|
||||
.max_channels = 128,
|
||||
.timeout_ms = 20000,
|
||||
.num_channels = ARRAY_SIZE(mhi_telit_fn980_hw_v1_channels),
|
||||
.ch_cfg = mhi_telit_fn980_hw_v1_channels,
|
||||
.num_events = ARRAY_SIZE(mhi_telit_fn980_hw_v1_events),
|
||||
.event_cfg = mhi_telit_fn980_hw_v1_events,
|
||||
};
|
||||
|
||||
static const struct mhi_pci_dev_info mhi_telit_fn980_hw_v1_info = {
|
||||
.name = "telit-fn980-hwv1",
|
||||
.fw = "qcom/sdx55m/sbl1.mbn",
|
||||
.edl = "qcom/sdx55m/edl.mbn",
|
||||
.config = &modem_telit_fn980_hw_v1_config,
|
||||
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
|
||||
.dma_data_width = 32,
|
||||
.mru_default = 32768,
|
||||
.sideband_wake = false,
|
||||
};
|
||||
|
||||
static const struct mhi_channel_config mhi_telit_fn990_channels[] = {
|
||||
MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_UL(4, "DIAG", 64, 1),
|
||||
MHI_CHANNEL_CONFIG_DL(5, "DIAG", 64, 1),
|
||||
MHI_CHANNEL_CONFIG_UL(12, "MBIM", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_DL(13, "MBIM", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2),
|
||||
MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3),
|
||||
};
|
||||
|
||||
static struct mhi_event_config mhi_telit_fn990_events[] = {
|
||||
MHI_EVENT_CONFIG_CTRL(0, 128),
|
||||
MHI_EVENT_CONFIG_DATA(1, 128),
|
||||
MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100),
|
||||
MHI_EVENT_CONFIG_HW_DATA(3, 2048, 101)
|
||||
};
|
||||
|
||||
static const struct mhi_controller_config modem_telit_fn990_config = {
|
||||
.max_channels = 128,
|
||||
.timeout_ms = 20000,
|
||||
.num_channels = ARRAY_SIZE(mhi_telit_fn990_channels),
|
||||
.ch_cfg = mhi_telit_fn990_channels,
|
||||
.num_events = ARRAY_SIZE(mhi_telit_fn990_events),
|
||||
.event_cfg = mhi_telit_fn990_events,
|
||||
};
|
||||
|
||||
static const struct mhi_pci_dev_info mhi_telit_fn990_info = {
|
||||
.name = "telit-fn990",
|
||||
.config = &modem_telit_fn990_config,
|
||||
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
|
||||
.dma_data_width = 32,
|
||||
.sideband_wake = false,
|
||||
.mru_default = 32768,
|
||||
};
|
||||
|
||||
/* Keep the list sorted based on the PID. New VID should be added as the last entry */
|
||||
static const struct pci_device_id mhi_pci_id_table[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304),
|
||||
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx24_info },
|
||||
/* EM919x (sdx55), use the same vid:pid as qcom-sdx55m */
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, 0x18d7, 0x0200),
|
||||
.driver_data = (kernel_ulong_t) &mhi_sierra_em919x_info },
|
||||
/* Telit FN980 hardware revision v1 */
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, 0x1C5D, 0x2000),
|
||||
.driver_data = (kernel_ulong_t) &mhi_telit_fn980_hw_v1_info },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0306),
|
||||
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx55_info },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304),
|
||||
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx24_info },
|
||||
/* Telit FN990 */
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, 0x1c5d, 0x2010),
|
||||
.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(0x1eac, 0x1001), /* EM120R-GL (sdx24) */
|
||||
.driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info },
|
||||
{ PCI_DEVICE(0x1eac, 0x1002), /* EM160R-GL (sdx24) */
|
||||
.driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308),
|
||||
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info },
|
||||
/* T99W175 (sdx55), Both for eSIM and Non-eSIM */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0ab),
|
||||
.driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info },
|
||||
@ -472,9 +569,21 @@ static const struct pci_device_id mhi_pci_id_table[] = {
|
||||
/* T99W175 (sdx55), Based on Qualcomm new baseline */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0bf),
|
||||
.driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info },
|
||||
/* T99W368 (sdx65) */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0d8),
|
||||
.driver_data = (kernel_ulong_t) &mhi_foxconn_sdx65_info },
|
||||
/* T99W373 (sdx62) */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0d9),
|
||||
.driver_data = (kernel_ulong_t) &mhi_foxconn_sdx65_info },
|
||||
/* MV31-W (Cinterion) */
|
||||
{ PCI_DEVICE(0x1269, 0x00b3),
|
||||
.driver_data = (kernel_ulong_t) &mhi_mv31_info },
|
||||
/* MV32-WA (Cinterion) */
|
||||
{ PCI_DEVICE(0x1269, 0x00ba),
|
||||
.driver_data = (kernel_ulong_t) &mhi_mv32_info },
|
||||
/* MV32-WB (Cinterion) */
|
||||
{ PCI_DEVICE(0x1269, 0x00bb),
|
||||
.driver_data = (kernel_ulong_t) &mhi_mv32_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, mhi_pci_id_table);
|
||||
|
@ -129,13 +129,20 @@ enum mhi_pm_state __must_check mhi_tryset_pm_state(struct mhi_controller *mhi_cn
|
||||
|
||||
void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, enum mhi_state state)
|
||||
{
|
||||
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
||||
int ret;
|
||||
|
||||
if (state == MHI_STATE_RESET) {
|
||||
mhi_write_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
|
||||
MHICTRL_RESET_MASK, 1);
|
||||
ret = mhi_write_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
|
||||
MHICTRL_RESET_MASK, 1);
|
||||
} else {
|
||||
mhi_write_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
|
||||
MHICTRL_MHISTATE_MASK, state);
|
||||
ret = mhi_write_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
|
||||
MHICTRL_MHISTATE_MASK, state);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to set MHI state to: %s\n",
|
||||
mhi_state_str(state));
|
||||
}
|
||||
|
||||
/* NOP for backward compatibility, host allowed to ring DB in M2 state */
|
||||
@ -476,6 +483,15 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl)
|
||||
* hence re-program it
|
||||
*/
|
||||
mhi_write_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_INTVEC, 0);
|
||||
|
||||
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);
|
||||
if (ret)
|
||||
dev_err(dev, "Device failed to enter READY state\n");
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(dev,
|
||||
|
@ -3395,7 +3395,9 @@ static int sysc_remove(struct platform_device *pdev)
|
||||
struct sysc *ddata = platform_get_drvdata(pdev);
|
||||
int error;
|
||||
|
||||
cancel_delayed_work_sync(&ddata->idle_work);
|
||||
/* Device can still be enabled, see deferred idle quirk in probe */
|
||||
if (cancel_delayed_work_sync(&ddata->idle_work))
|
||||
ti_sysc_idle(&ddata->idle_work.work);
|
||||
|
||||
error = pm_runtime_resume_and_get(ddata->dev);
|
||||
if (error < 0) {
|
||||
|
@ -101,7 +101,7 @@ static inline bool should_stop_iteration(void)
|
||||
{
|
||||
if (need_resched())
|
||||
cond_resched();
|
||||
return fatal_signal_pending(current);
|
||||
return signal_pending(current);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -100,17 +100,18 @@ static const struct seq_operations misc_seq_ops = {
|
||||
static int misc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
int minor = iminor(inode);
|
||||
struct miscdevice *c;
|
||||
struct miscdevice *c = NULL, *iter;
|
||||
int err = -ENODEV;
|
||||
const struct file_operations *new_fops = NULL;
|
||||
|
||||
mutex_lock(&misc_mtx);
|
||||
|
||||
list_for_each_entry(c, &misc_list, list) {
|
||||
if (c->minor == minor) {
|
||||
new_fops = fops_get(c->fops);
|
||||
break;
|
||||
}
|
||||
list_for_each_entry(iter, &misc_list, list) {
|
||||
if (iter->minor != minor)
|
||||
continue;
|
||||
c = iter;
|
||||
new_fops = fops_get(iter->fops);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!new_fops) {
|
||||
@ -118,11 +119,12 @@ static int misc_open(struct inode *inode, struct file *file)
|
||||
request_module("char-major-%d-%d", MISC_MAJOR, minor);
|
||||
mutex_lock(&misc_mtx);
|
||||
|
||||
list_for_each_entry(c, &misc_list, list) {
|
||||
if (c->minor == minor) {
|
||||
new_fops = fops_get(c->fops);
|
||||
break;
|
||||
}
|
||||
list_for_each_entry(iter, &misc_list, list) {
|
||||
if (iter->minor != minor)
|
||||
continue;
|
||||
c = iter;
|
||||
new_fops = fops_get(iter->fops);
|
||||
break;
|
||||
}
|
||||
if (!new_fops)
|
||||
goto fail;
|
||||
|
@ -922,7 +922,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd)
|
||||
// BIT7:parity error
|
||||
// BIT6:framing error
|
||||
|
||||
if (status & (BIT7 + BIT6)) {
|
||||
if (status & (BIT7 | BIT6)) {
|
||||
if (status & BIT7)
|
||||
icount->parity++;
|
||||
else
|
||||
|
@ -174,18 +174,17 @@ void xillybus_cleanup_chrdev(void *private_data,
|
||||
struct device *dev)
|
||||
{
|
||||
int minor;
|
||||
struct xilly_unit *unit;
|
||||
bool found = false;
|
||||
struct xilly_unit *unit = NULL, *iter;
|
||||
|
||||
mutex_lock(&unit_mutex);
|
||||
|
||||
list_for_each_entry(unit, &unit_list, list_entry)
|
||||
if (unit->private_data == private_data) {
|
||||
found = true;
|
||||
list_for_each_entry(iter, &unit_list, list_entry)
|
||||
if (iter->private_data == private_data) {
|
||||
unit = iter;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (!unit) {
|
||||
dev_err(dev, "Weird bug: Failed to find unit\n");
|
||||
mutex_unlock(&unit_mutex);
|
||||
return;
|
||||
@ -216,22 +215,21 @@ int xillybus_find_inode(struct inode *inode,
|
||||
{
|
||||
int minor = iminor(inode);
|
||||
int major = imajor(inode);
|
||||
struct xilly_unit *unit;
|
||||
bool found = false;
|
||||
struct xilly_unit *unit = NULL, *iter;
|
||||
|
||||
mutex_lock(&unit_mutex);
|
||||
|
||||
list_for_each_entry(unit, &unit_list, list_entry)
|
||||
if (unit->major == major &&
|
||||
minor >= unit->lowest_minor &&
|
||||
minor < (unit->lowest_minor + unit->num_nodes)) {
|
||||
found = true;
|
||||
list_for_each_entry(iter, &unit_list, list_entry)
|
||||
if (iter->major == major &&
|
||||
minor >= iter->lowest_minor &&
|
||||
minor < (iter->lowest_minor + iter->num_nodes)) {
|
||||
unit = iter;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&unit_mutex);
|
||||
|
||||
if (!found)
|
||||
if (!unit)
|
||||
return -ENODEV;
|
||||
|
||||
*private_data = unit->private_data;
|
||||
|
@ -549,6 +549,7 @@ static void cleanup_dev(struct kref *kref)
|
||||
if (xdev->workq)
|
||||
destroy_workqueue(xdev->workq);
|
||||
|
||||
usb_put_dev(xdev->udev);
|
||||
kfree(xdev->channels); /* Argument may be NULL, and that's fine */
|
||||
kfree(xdev);
|
||||
}
|
||||
|
@ -854,7 +854,7 @@ int comedi_load_firmware(struct comedi_device *dev,
|
||||
release_firmware(fw);
|
||||
}
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
return min(ret, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_load_firmware);
|
||||
|
||||
|
@ -216,8 +216,11 @@ static int __init dio_init(void)
|
||||
|
||||
/* Found a board, allocate it an entry in the list */
|
||||
dev = kzalloc(sizeof(struct dio_dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
if (!dev) {
|
||||
if (scode >= DIOII_SCBASE)
|
||||
iounmap(va);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev->bus = &dio_bus;
|
||||
dev->dev.parent = &dio_bus.dev;
|
||||
|
@ -131,6 +131,7 @@ config EXTCON_PALMAS
|
||||
config EXTCON_PTN5150
|
||||
tristate "NXP PTN5150 CC LOGIC USB EXTCON support"
|
||||
depends on I2C && (GPIOLIB || COMPILE_TEST)
|
||||
depends on USB_ROLE_SWITCH || !USB_ROLE_SWITCH
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say Y here to enable support for USB peripheral and USB host
|
||||
@ -156,7 +157,7 @@ config EXTCON_RT8973A
|
||||
from abnormal high input voltage (up to 28V).
|
||||
|
||||
config EXTCON_SM5502
|
||||
tristate "Silicon Mitus SM5502/SM5504 EXTCON support"
|
||||
tristate "Silicon Mitus SM5502/SM5504/SM5703 EXTCON support"
|
||||
depends on I2C
|
||||
select IRQ_DOMAIN
|
||||
select REGMAP_I2C
|
||||
|
@ -394,8 +394,8 @@ static int axp288_extcon_probe(struct platform_device *pdev)
|
||||
if (adev) {
|
||||
info->id_extcon = extcon_get_extcon_dev(acpi_dev_name(adev));
|
||||
put_device(&adev->dev);
|
||||
if (!info->id_extcon)
|
||||
return -EPROBE_DEFER;
|
||||
if (IS_ERR(info->id_extcon))
|
||||
return PTR_ERR(info->id_extcon);
|
||||
|
||||
dev_info(dev, "controlling USB role\n");
|
||||
} else {
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#define INT3496_GPIO_USB_ID 0
|
||||
#define INT3496_GPIO_VBUS_EN 1
|
||||
@ -30,7 +31,9 @@ struct int3496_data {
|
||||
struct gpio_desc *gpio_usb_id;
|
||||
struct gpio_desc *gpio_vbus_en;
|
||||
struct gpio_desc *gpio_usb_mux;
|
||||
struct regulator *vbus_boost;
|
||||
int usb_id_irq;
|
||||
bool vbus_boost_enabled;
|
||||
};
|
||||
|
||||
static const unsigned int int3496_cable[] = {
|
||||
@ -53,6 +56,27 @@ static const struct acpi_gpio_mapping acpi_int3496_default_gpios[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
static void int3496_set_vbus_boost(struct int3496_data *data, bool enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(data->vbus_boost))
|
||||
return;
|
||||
|
||||
if (data->vbus_boost_enabled == enable)
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
ret = regulator_enable(data->vbus_boost);
|
||||
else
|
||||
ret = regulator_disable(data->vbus_boost);
|
||||
|
||||
if (ret == 0)
|
||||
data->vbus_boost_enabled = enable;
|
||||
else
|
||||
dev_err(data->dev, "Error updating Vbus boost regulator: %d\n", ret);
|
||||
}
|
||||
|
||||
static void int3496_do_usb_id(struct work_struct *work)
|
||||
{
|
||||
struct int3496_data *data =
|
||||
@ -71,6 +95,8 @@ static void int3496_do_usb_id(struct work_struct *work)
|
||||
|
||||
if (!IS_ERR(data->gpio_vbus_en))
|
||||
gpiod_direction_output(data->gpio_vbus_en, !id);
|
||||
else
|
||||
int3496_set_vbus_boost(data, !id);
|
||||
|
||||
extcon_set_state_sync(data->edev, EXTCON_USB_HOST, !id);
|
||||
}
|
||||
@ -91,10 +117,12 @@ static int int3496_probe(struct platform_device *pdev)
|
||||
struct int3496_data *data;
|
||||
int ret;
|
||||
|
||||
ret = devm_acpi_dev_add_driver_gpios(dev, acpi_int3496_default_gpios);
|
||||
if (ret) {
|
||||
dev_err(dev, "can't add GPIO ACPI mapping\n");
|
||||
return ret;
|
||||
if (has_acpi_companion(dev)) {
|
||||
ret = devm_acpi_dev_add_driver_gpios(dev, acpi_int3496_default_gpios);
|
||||
if (ret) {
|
||||
dev_err(dev, "can't add GPIO ACPI mapping\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
@ -106,7 +134,8 @@ static int int3496_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->gpio_usb_id = devm_gpiod_get(dev, "id", GPIOD_IN);
|
||||
data->gpio_usb_id =
|
||||
devm_gpiod_get(dev, "id", GPIOD_IN | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
|
||||
if (IS_ERR(data->gpio_usb_id)) {
|
||||
ret = PTR_ERR(data->gpio_usb_id);
|
||||
dev_err(dev, "can't request USB ID GPIO: %d\n", ret);
|
||||
@ -120,12 +149,14 @@ static int int3496_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
data->gpio_vbus_en = devm_gpiod_get(dev, "vbus", GPIOD_ASIS);
|
||||
if (IS_ERR(data->gpio_vbus_en))
|
||||
dev_info(dev, "can't request VBUS EN GPIO\n");
|
||||
if (IS_ERR(data->gpio_vbus_en)) {
|
||||
dev_dbg(dev, "can't request VBUS EN GPIO\n");
|
||||
data->vbus_boost = devm_regulator_get_optional(dev, "vbus");
|
||||
}
|
||||
|
||||
data->gpio_usb_mux = devm_gpiod_get(dev, "mux", GPIOD_ASIS);
|
||||
if (IS_ERR(data->gpio_usb_mux))
|
||||
dev_info(dev, "can't request USB MUX GPIO\n");
|
||||
dev_dbg(dev, "can't request USB MUX GPIO\n");
|
||||
|
||||
/* register extcon device */
|
||||
data->edev = devm_extcon_dev_allocate(dev, int3496_cable);
|
||||
@ -164,12 +195,19 @@ static const struct acpi_device_id int3496_acpi_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, int3496_acpi_match);
|
||||
|
||||
static const struct platform_device_id int3496_ids[] = {
|
||||
{ .name = "intel-int3496" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, int3496_ids);
|
||||
|
||||
static struct platform_driver int3496_driver = {
|
||||
.driver = {
|
||||
.name = "intel-int3496",
|
||||
.acpi_match_table = int3496_acpi_match,
|
||||
},
|
||||
.probe = int3496_probe,
|
||||
.id_table = int3496_ids,
|
||||
};
|
||||
|
||||
module_platform_driver(int3496_driver);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/extcon-provider.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/usb/role.h>
|
||||
|
||||
/* PTN5150 registers */
|
||||
#define PTN5150_REG_DEVICE_ID 0x01
|
||||
@ -52,6 +53,7 @@ struct ptn5150_info {
|
||||
int irq;
|
||||
struct work_struct irq_work;
|
||||
struct mutex mutex;
|
||||
struct usb_role_switch *role_sw;
|
||||
};
|
||||
|
||||
/* List of detectable cables */
|
||||
@ -70,6 +72,7 @@ static const struct regmap_config ptn5150_regmap_config = {
|
||||
static void ptn5150_check_state(struct ptn5150_info *info)
|
||||
{
|
||||
unsigned int port_status, reg_data, vbus;
|
||||
enum usb_role usb_role = USB_ROLE_NONE;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(info->regmap, PTN5150_REG_CC_STATUS, ®_data);
|
||||
@ -85,6 +88,7 @@ static void ptn5150_check_state(struct ptn5150_info *info)
|
||||
extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false);
|
||||
gpiod_set_value_cansleep(info->vbus_gpiod, 0);
|
||||
extcon_set_state_sync(info->edev, EXTCON_USB, true);
|
||||
usb_role = USB_ROLE_DEVICE;
|
||||
break;
|
||||
case PTN5150_UFP_ATTACHED:
|
||||
extcon_set_state_sync(info->edev, EXTCON_USB, false);
|
||||
@ -95,10 +99,18 @@ static void ptn5150_check_state(struct ptn5150_info *info)
|
||||
gpiod_set_value_cansleep(info->vbus_gpiod, 1);
|
||||
|
||||
extcon_set_state_sync(info->edev, EXTCON_USB_HOST, true);
|
||||
usb_role = USB_ROLE_HOST;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (usb_role) {
|
||||
ret = usb_role_switch_set_role(info->role_sw, usb_role);
|
||||
if (ret)
|
||||
dev_err(info->dev, "failed to set %s role: %d\n",
|
||||
usb_role_string(usb_role), ret);
|
||||
}
|
||||
}
|
||||
|
||||
static void ptn5150_irq_work(struct work_struct *work)
|
||||
@ -133,6 +145,13 @@ static void ptn5150_irq_work(struct work_struct *work)
|
||||
extcon_set_state_sync(info->edev,
|
||||
EXTCON_USB, false);
|
||||
gpiod_set_value_cansleep(info->vbus_gpiod, 0);
|
||||
|
||||
ret = usb_role_switch_set_role(info->role_sw,
|
||||
USB_ROLE_NONE);
|
||||
if (ret)
|
||||
dev_err(info->dev,
|
||||
"failed to set none role: %d\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,6 +213,14 @@ static int ptn5150_init_dev_type(struct ptn5150_info *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ptn5150_work_sync_and_put(void *data)
|
||||
{
|
||||
struct ptn5150_info *info = data;
|
||||
|
||||
cancel_work_sync(&info->irq_work);
|
||||
usb_role_switch_put(info->role_sw);
|
||||
}
|
||||
|
||||
static int ptn5150_i2c_probe(struct i2c_client *i2c)
|
||||
{
|
||||
struct device *dev = &i2c->dev;
|
||||
@ -284,6 +311,15 @@ static int ptn5150_i2c_probe(struct i2c_client *i2c)
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
info->role_sw = usb_role_switch_get(info->dev);
|
||||
if (IS_ERR(info->role_sw))
|
||||
return dev_err_probe(info->dev, PTR_ERR(info->role_sw),
|
||||
"failed to get role switch\n");
|
||||
|
||||
ret = devm_add_action_or_reset(dev, ptn5150_work_sync_and_put, info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Update current extcon state if for example OTG connection was there
|
||||
* before the probe
|
||||
|
@ -798,6 +798,7 @@ static const struct sm5502_type sm5504_data = {
|
||||
static const struct of_device_id sm5502_dt_match[] = {
|
||||
{ .compatible = "siliconmitus,sm5502-muic", .data = &sm5502_data },
|
||||
{ .compatible = "siliconmitus,sm5504-muic", .data = &sm5504_data },
|
||||
{ .compatible = "siliconmitus,sm5703-muic", .data = &sm5502_data },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sm5502_dt_match);
|
||||
@ -830,6 +831,7 @@ static SIMPLE_DEV_PM_OPS(sm5502_muic_pm_ops,
|
||||
static const struct i2c_device_id sm5502_i2c_id[] = {
|
||||
{ "sm5502", (kernel_ulong_t)&sm5502_data },
|
||||
{ "sm5504", (kernel_ulong_t)&sm5504_data },
|
||||
{ "sm5703-muic", (kernel_ulong_t)&sm5502_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, sm5502_i2c_id);
|
||||
|
@ -226,16 +226,6 @@ static int usb_extcon_suspend(struct device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't want to process any IRQs after this point
|
||||
* as GPIOs used behind I2C subsystem might not be
|
||||
* accessible until resume completes. So disable IRQ.
|
||||
*/
|
||||
if (info->id_gpiod)
|
||||
disable_irq(info->id_irq);
|
||||
if (info->vbus_gpiod)
|
||||
disable_irq(info->vbus_irq);
|
||||
|
||||
if (!device_may_wakeup(dev))
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
|
||||
@ -267,11 +257,6 @@ static int usb_extcon_resume(struct device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
if (info->id_gpiod)
|
||||
enable_irq(info->id_irq);
|
||||
if (info->vbus_gpiod)
|
||||
enable_irq(info->vbus_irq);
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
&info->wq_detcable, 0);
|
||||
|
||||
|
@ -68,7 +68,7 @@ static int cros_ec_pd_command(struct cros_ec_extcon_info *info,
|
||||
struct cros_ec_command *msg;
|
||||
int ret;
|
||||
|
||||
msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL);
|
||||
msg = kzalloc(struct_size(msg, data, max(outsize, insize)), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -399,6 +399,7 @@ static ssize_t cable_state_show(struct device *dev,
|
||||
/**
|
||||
* extcon_sync() - Synchronize the state for an external connector.
|
||||
* @edev: the extcon device
|
||||
* @id: the unique id indicating an external connector
|
||||
*
|
||||
* Note that this function send a notification in order to synchronize
|
||||
* the state and property of an external connector.
|
||||
@ -736,6 +737,9 @@ EXPORT_SYMBOL_GPL(extcon_set_property);
|
||||
|
||||
/**
|
||||
* extcon_set_property_sync() - Set property of an external connector with sync.
|
||||
* @edev: the extcon device
|
||||
* @id: the unique id indicating an external connector
|
||||
* @prop: the property id indicating an extcon property
|
||||
* @prop_val: the pointer including the new value of extcon property
|
||||
*
|
||||
* Note that when setting the property value of external connector,
|
||||
@ -851,6 +855,8 @@ EXPORT_SYMBOL_GPL(extcon_set_property_capability);
|
||||
* @extcon_name: the extcon name provided with extcon_dev_register()
|
||||
*
|
||||
* Return the pointer of extcon device if success or ERR_PTR(err) if fail.
|
||||
* NOTE: This function returns -EPROBE_DEFER so it may only be called from
|
||||
* probe() functions.
|
||||
*/
|
||||
struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
|
||||
{
|
||||
@ -864,7 +870,7 @@ struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
|
||||
if (!strcmp(sd->name, extcon_name))
|
||||
goto out;
|
||||
}
|
||||
sd = NULL;
|
||||
sd = ERR_PTR(-EPROBE_DEFER);
|
||||
out:
|
||||
mutex_unlock(&extcon_dev_list_lock);
|
||||
return sd;
|
||||
@ -1218,19 +1224,14 @@ int extcon_dev_register(struct extcon_dev *edev)
|
||||
edev->dev.type = &edev->extcon_dev_type;
|
||||
}
|
||||
|
||||
ret = device_register(&edev->dev);
|
||||
if (ret) {
|
||||
put_device(&edev->dev);
|
||||
goto err_dev;
|
||||
}
|
||||
|
||||
spin_lock_init(&edev->lock);
|
||||
edev->nh = devm_kcalloc(&edev->dev, edev->max_supported,
|
||||
sizeof(*edev->nh), GFP_KERNEL);
|
||||
if (!edev->nh) {
|
||||
ret = -ENOMEM;
|
||||
device_unregister(&edev->dev);
|
||||
goto err_dev;
|
||||
if (edev->max_supported) {
|
||||
edev->nh = kcalloc(edev->max_supported, sizeof(*edev->nh),
|
||||
GFP_KERNEL);
|
||||
if (!edev->nh) {
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc_nh;
|
||||
}
|
||||
}
|
||||
|
||||
for (index = 0; index < edev->max_supported; index++)
|
||||
@ -1241,6 +1242,12 @@ int extcon_dev_register(struct extcon_dev *edev)
|
||||
dev_set_drvdata(&edev->dev, edev);
|
||||
edev->state = 0;
|
||||
|
||||
ret = device_register(&edev->dev);
|
||||
if (ret) {
|
||||
put_device(&edev->dev);
|
||||
goto err_dev;
|
||||
}
|
||||
|
||||
mutex_lock(&extcon_dev_list_lock);
|
||||
list_add(&edev->entry, &extcon_dev_list);
|
||||
mutex_unlock(&extcon_dev_list_lock);
|
||||
@ -1248,6 +1255,9 @@ int extcon_dev_register(struct extcon_dev *edev)
|
||||
return 0;
|
||||
|
||||
err_dev:
|
||||
if (edev->max_supported)
|
||||
kfree(edev->nh);
|
||||
err_alloc_nh:
|
||||
if (edev->max_supported)
|
||||
kfree(edev->extcon_dev_type.groups);
|
||||
err_alloc_groups:
|
||||
@ -1308,6 +1318,7 @@ void extcon_dev_unregister(struct extcon_dev *edev)
|
||||
if (edev->max_supported) {
|
||||
kfree(edev->extcon_dev_type.groups);
|
||||
kfree(edev->cables);
|
||||
kfree(edev->nh);
|
||||
}
|
||||
|
||||
put_device(&edev->dev);
|
||||
|
@ -604,7 +604,7 @@ static void __init dmi_sysfs_register_handle(const struct dmi_header *dh,
|
||||
"%d-%d", dh->type, entry->instance);
|
||||
|
||||
if (*ret) {
|
||||
kfree(entry);
|
||||
kobject_put(&entry->kobj);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -685,8 +685,7 @@ static void edd_populate_dir(struct edd_device * edev)
|
||||
int i;
|
||||
|
||||
for (i = 0; (attr = edd_attrs[i]) && !error; i++) {
|
||||
if (!attr->test ||
|
||||
(attr->test && attr->test(edev)))
|
||||
if (!attr->test || attr->test(edev))
|
||||
error = sysfs_create_file(&edev->kobj,&attr->attr);
|
||||
}
|
||||
|
||||
|
@ -948,17 +948,17 @@ EXPORT_SYMBOL_GPL(stratix10_svc_allocate_memory);
|
||||
void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
|
||||
{
|
||||
struct stratix10_svc_data_mem *pmem;
|
||||
size_t size = 0;
|
||||
|
||||
list_for_each_entry(pmem, &svc_data_mem, node)
|
||||
if (pmem->vaddr == kaddr) {
|
||||
size = pmem->size;
|
||||
break;
|
||||
gen_pool_free(chan->ctrl->genpool,
|
||||
(unsigned long)kaddr, pmem->size);
|
||||
pmem->vaddr = NULL;
|
||||
list_del(&pmem->node);
|
||||
return;
|
||||
}
|
||||
|
||||
gen_pool_free(chan->ctrl->genpool, (unsigned long)kaddr, size);
|
||||
pmem->vaddr = NULL;
|
||||
list_del(&pmem->node);
|
||||
list_del(&svc_data_mem);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(stratix10_svc_free_memory);
|
||||
|
||||
|
@ -36,8 +36,16 @@
|
||||
/* BOOT_PIN_CTRL_MASK- out_val[11:8], out_en[3:0] */
|
||||
#define CRL_APB_BOOTPIN_CTRL_MASK 0xF0FU
|
||||
|
||||
/* IOCTL/QUERY feature payload size */
|
||||
#define FEATURE_PAYLOAD_SIZE 2
|
||||
|
||||
/* Firmware feature check version mask */
|
||||
#define FIRMWARE_VERSION_MASK GENMASK(15, 0)
|
||||
|
||||
static bool feature_check_enabled;
|
||||
static DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER);
|
||||
static u32 ioctl_features[FEATURE_PAYLOAD_SIZE];
|
||||
static u32 query_features[FEATURE_PAYLOAD_SIZE];
|
||||
|
||||
static struct platform_device *em_dev;
|
||||
|
||||
@ -167,22 +175,29 @@ static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2,
|
||||
return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_feature() - Check weather given feature is supported or not
|
||||
* @api_id: API ID to check
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
int zynqmp_pm_feature(const u32 api_id)
|
||||
static int __do_feature_check_call(const u32 api_id, u32 *ret_payload)
|
||||
{
|
||||
int ret;
|
||||
u64 smc_arg[2];
|
||||
|
||||
smc_arg[0] = PM_SIP_SVC | PM_FEATURE_CHECK;
|
||||
smc_arg[1] = api_id;
|
||||
|
||||
ret = do_fw_call(smc_arg[0], smc_arg[1], 0, ret_payload);
|
||||
if (ret)
|
||||
ret = -EOPNOTSUPP;
|
||||
else
|
||||
ret = ret_payload[1];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_feature_check_call(const u32 api_id)
|
||||
{
|
||||
int ret;
|
||||
u32 ret_payload[PAYLOAD_ARG_CNT];
|
||||
u64 smc_arg[2];
|
||||
struct pm_api_feature_data *feature_data;
|
||||
|
||||
if (!feature_check_enabled)
|
||||
return 0;
|
||||
|
||||
/* Check for existing entry in hash table for given api */
|
||||
hash_for_each_possible(pm_api_features_map, feature_data, hentry,
|
||||
api_id) {
|
||||
@ -196,22 +211,85 @@ int zynqmp_pm_feature(const u32 api_id)
|
||||
return -ENOMEM;
|
||||
|
||||
feature_data->pm_api_id = api_id;
|
||||
smc_arg[0] = PM_SIP_SVC | PM_FEATURE_CHECK;
|
||||
smc_arg[1] = api_id;
|
||||
|
||||
ret = do_fw_call(smc_arg[0], smc_arg[1], 0, ret_payload);
|
||||
if (ret)
|
||||
ret = -EOPNOTSUPP;
|
||||
else
|
||||
ret = ret_payload[1];
|
||||
ret = __do_feature_check_call(api_id, ret_payload);
|
||||
|
||||
feature_data->feature_status = ret;
|
||||
hash_add(pm_api_features_map, &feature_data->hentry, api_id);
|
||||
|
||||
if (api_id == PM_IOCTL)
|
||||
/* Store supported IOCTL IDs mask */
|
||||
memcpy(ioctl_features, &ret_payload[2], FEATURE_PAYLOAD_SIZE * 4);
|
||||
else if (api_id == PM_QUERY_DATA)
|
||||
/* Store supported QUERY IDs mask */
|
||||
memcpy(query_features, &ret_payload[2], FEATURE_PAYLOAD_SIZE * 4);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(zynqmp_pm_feature);
|
||||
|
||||
/**
|
||||
* zynqmp_pm_feature() - Check whether given feature is supported or not and
|
||||
* store supported IOCTL/QUERY ID mask
|
||||
* @api_id: API ID to check
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
int zynqmp_pm_feature(const u32 api_id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!feature_check_enabled)
|
||||
return 0;
|
||||
|
||||
ret = do_feature_check_call(api_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_is_function_supported() - Check whether given IOCTL/QUERY function
|
||||
* is supported or not
|
||||
* @api_id: PM_IOCTL or PM_QUERY_DATA
|
||||
* @id: IOCTL or QUERY function IDs
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id)
|
||||
{
|
||||
int ret;
|
||||
u32 *bit_mask;
|
||||
|
||||
/* Input arguments validation */
|
||||
if (id >= 64 || (api_id != PM_IOCTL && api_id != PM_QUERY_DATA))
|
||||
return -EINVAL;
|
||||
|
||||
/* Check feature check API version */
|
||||
ret = do_feature_check_call(PM_FEATURE_CHECK);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Check if feature check version 2 is supported or not */
|
||||
if ((ret & FIRMWARE_VERSION_MASK) == PM_API_VERSION_2) {
|
||||
/*
|
||||
* Call feature check for IOCTL/QUERY API to get IOCTL ID or
|
||||
* QUERY ID feature status.
|
||||
*/
|
||||
ret = do_feature_check_call(api_id);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
bit_mask = (api_id == PM_IOCTL) ? ioctl_features : query_features;
|
||||
|
||||
if ((bit_mask[(id / 32)] & BIT((id % 32))) == 0U)
|
||||
return -EOPNOTSUPP;
|
||||
} else {
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
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
|
||||
@ -1584,6 +1662,10 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
|
||||
struct zynqmp_devinfo *devinfo;
|
||||
int ret;
|
||||
|
||||
ret = get_set_conduit_method(dev->of_node);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
|
||||
if (!np) {
|
||||
np = of_find_compatible_node(NULL, NULL, "xlnx,versal");
|
||||
@ -1592,11 +1674,14 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
|
||||
|
||||
feature_check_enabled = true;
|
||||
}
|
||||
of_node_put(np);
|
||||
|
||||
ret = get_set_conduit_method(dev->of_node);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!feature_check_enabled) {
|
||||
ret = do_feature_check_call(PM_FEATURE_CHECK);
|
||||
if (ret >= 0)
|
||||
feature_check_enabled = true;
|
||||
}
|
||||
|
||||
of_node_put(np);
|
||||
|
||||
devinfo = devm_kzalloc(dev, sizeof(*devinfo), GFP_KERNEL);
|
||||
if (!devinfo)
|
||||
|
@ -18,9 +18,9 @@ obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o
|
||||
obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o
|
||||
obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o
|
||||
obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA) += zynqmp-fpga.o
|
||||
obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA) += versal-fpga.o
|
||||
obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o
|
||||
obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o
|
||||
obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA) += versal-fpga.o
|
||||
obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o
|
||||
obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o
|
||||
|
||||
# FPGA Bridge Drivers
|
||||
obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o
|
||||
|
@ -259,6 +259,15 @@ static int find_dfls_by_default(struct pci_dev *pcidev,
|
||||
*/
|
||||
bar = FIELD_GET(FME_PORT_OFST_BAR_ID, v);
|
||||
offset = FIELD_GET(FME_PORT_OFST_DFH_OFST, v);
|
||||
if (bar == FME_PORT_OFST_BAR_SKIP) {
|
||||
continue;
|
||||
} else if (bar >= PCI_STD_NUM_BARS) {
|
||||
dev_err(&pcidev->dev, "bad BAR %d for port %d\n",
|
||||
bar, i);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
start = pci_resource_start(pcidev, bar) + offset;
|
||||
len = pci_resource_len(pcidev, bar) - offset;
|
||||
|
||||
|
@ -940,9 +940,12 @@ static int parse_feature_irqs(struct build_feature_devs_info *binfo,
|
||||
{
|
||||
void __iomem *base = binfo->ioaddr + ofst;
|
||||
unsigned int i, ibase, inr = 0;
|
||||
enum dfl_id_type type;
|
||||
int virq;
|
||||
u64 v;
|
||||
|
||||
type = feature_dev_id_type(binfo->feature_dev);
|
||||
|
||||
/*
|
||||
* Ideally DFL framework should only read info from DFL header, but
|
||||
* current version DFL only provides mmio resources information for
|
||||
@ -957,22 +960,25 @@ static int parse_feature_irqs(struct build_feature_devs_info *binfo,
|
||||
* code will be added. But in order to be compatible to old version
|
||||
* DFL, the driver may still fall back to these quirks.
|
||||
*/
|
||||
switch (fid) {
|
||||
case PORT_FEATURE_ID_UINT:
|
||||
v = readq(base + PORT_UINT_CAP);
|
||||
ibase = FIELD_GET(PORT_UINT_CAP_FST_VECT, v);
|
||||
inr = FIELD_GET(PORT_UINT_CAP_INT_NUM, v);
|
||||
break;
|
||||
case PORT_FEATURE_ID_ERROR:
|
||||
v = readq(base + PORT_ERROR_CAP);
|
||||
ibase = FIELD_GET(PORT_ERROR_CAP_INT_VECT, v);
|
||||
inr = FIELD_GET(PORT_ERROR_CAP_SUPP_INT, v);
|
||||
break;
|
||||
case FME_FEATURE_ID_GLOBAL_ERR:
|
||||
v = readq(base + FME_ERROR_CAP);
|
||||
ibase = FIELD_GET(FME_ERROR_CAP_INT_VECT, v);
|
||||
inr = FIELD_GET(FME_ERROR_CAP_SUPP_INT, v);
|
||||
break;
|
||||
if (type == PORT_ID) {
|
||||
switch (fid) {
|
||||
case PORT_FEATURE_ID_UINT:
|
||||
v = readq(base + PORT_UINT_CAP);
|
||||
ibase = FIELD_GET(PORT_UINT_CAP_FST_VECT, v);
|
||||
inr = FIELD_GET(PORT_UINT_CAP_INT_NUM, v);
|
||||
break;
|
||||
case PORT_FEATURE_ID_ERROR:
|
||||
v = readq(base + PORT_ERROR_CAP);
|
||||
ibase = FIELD_GET(PORT_ERROR_CAP_INT_VECT, v);
|
||||
inr = FIELD_GET(PORT_ERROR_CAP_SUPP_INT, v);
|
||||
break;
|
||||
}
|
||||
} else if (type == FME_ID) {
|
||||
if (fid == FME_FEATURE_ID_GLOBAL_ERR) {
|
||||
v = readq(base + FME_ERROR_CAP);
|
||||
ibase = FIELD_GET(FME_ERROR_CAP_INT_VECT, v);
|
||||
inr = FIELD_GET(FME_ERROR_CAP_SUPP_INT, v);
|
||||
}
|
||||
}
|
||||
|
||||
if (!inr) {
|
||||
|
@ -89,6 +89,7 @@
|
||||
#define FME_HDR_NEXT_AFU NEXT_AFU
|
||||
#define FME_HDR_CAP 0x30
|
||||
#define FME_HDR_PORT_OFST(n) (0x38 + ((n) * 0x8))
|
||||
#define FME_PORT_OFST_BAR_SKIP 7
|
||||
#define FME_HDR_BITSTREAM_ID 0x60
|
||||
#define FME_HDR_BITSTREAM_MD 0x68
|
||||
|
||||
|
@ -148,11 +148,12 @@ static int fpga_mgr_write_init_buf(struct fpga_manager *mgr,
|
||||
int ret;
|
||||
|
||||
mgr->state = FPGA_MGR_STATE_WRITE_INIT;
|
||||
if (!mgr->mops->initial_header_size)
|
||||
if (!mgr->mops->initial_header_size) {
|
||||
ret = fpga_mgr_write_init(mgr, info, NULL, 0);
|
||||
else
|
||||
ret = fpga_mgr_write_init(
|
||||
mgr, info, buf, min(mgr->mops->initial_header_size, count));
|
||||
} else {
|
||||
count = min(mgr->mops->initial_header_size, count);
|
||||
ret = fpga_mgr_write_init(mgr, info, buf, count);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
dev_err(&mgr->dev, "Error preparing FPGA for writing\n");
|
||||
@ -730,6 +731,8 @@ static void devm_fpga_mgr_unregister(struct device *dev, void *res)
|
||||
* @parent: fpga manager device from pdev
|
||||
* @info: parameters for fpga manager
|
||||
*
|
||||
* Return: fpga manager pointer on success, negative error code otherwise.
|
||||
*
|
||||
* This is the devres variant of fpga_mgr_register_full() for which the unregister
|
||||
* function will be called automatically when the managing device is detached.
|
||||
*/
|
||||
@ -763,6 +766,8 @@ EXPORT_SYMBOL_GPL(devm_fpga_mgr_register_full);
|
||||
* @mops: pointer to structure of fpga manager ops
|
||||
* @priv: fpga manager private data
|
||||
*
|
||||
* Return: fpga manager pointer on success, negative error code otherwise.
|
||||
*
|
||||
* This is the devres variant of fpga_mgr_register() for which the
|
||||
* unregister function will be called automatically when the managing
|
||||
* device is detached.
|
||||
|
@ -18,9 +18,9 @@
|
||||
static DEFINE_IDA(fpga_region_ida);
|
||||
static struct class *fpga_region_class;
|
||||
|
||||
struct fpga_region *fpga_region_class_find(
|
||||
struct device *start, const void *data,
|
||||
int (*match)(struct device *, const void *))
|
||||
struct fpga_region *
|
||||
fpga_region_class_find(struct device *start, const void *data,
|
||||
int (*match)(struct device *, const void *))
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
|
@ -28,7 +28,7 @@ MODULE_DEVICE_TABLE(of, fpga_region_of_match);
|
||||
*
|
||||
* Caller will need to put_device(®ion->dev) when done.
|
||||
*
|
||||
* Returns FPGA Region struct or NULL
|
||||
* Return: FPGA Region struct or NULL
|
||||
*/
|
||||
static struct fpga_region *of_fpga_region_find(struct device_node *np)
|
||||
{
|
||||
@ -80,7 +80,7 @@ static struct fpga_manager *of_fpga_region_get_mgr(struct device_node *np)
|
||||
* Caller should call fpga_bridges_put(®ion->bridge_list) when
|
||||
* done with the bridges.
|
||||
*
|
||||
* Return 0 for success (even if there are no bridges specified)
|
||||
* Return: 0 for success (even if there are no bridges specified)
|
||||
* or -EBUSY if any of the bridges are in use.
|
||||
*/
|
||||
static int of_fpga_region_get_bridges(struct fpga_region *region)
|
||||
@ -139,13 +139,13 @@ static int of_fpga_region_get_bridges(struct fpga_region *region)
|
||||
}
|
||||
|
||||
/**
|
||||
* child_regions_with_firmware
|
||||
* child_regions_with_firmware - Used to check the child region info.
|
||||
* @overlay: device node of the overlay
|
||||
*
|
||||
* If the overlay adds child FPGA regions, they are not allowed to have
|
||||
* firmware-name property.
|
||||
*
|
||||
* Return 0 for OK or -EINVAL if child FPGA region adds firmware-name.
|
||||
* Return: 0 for OK or -EINVAL if child FPGA region adds firmware-name.
|
||||
*/
|
||||
static int child_regions_with_firmware(struct device_node *overlay)
|
||||
{
|
||||
@ -184,14 +184,14 @@ static int child_regions_with_firmware(struct device_node *overlay)
|
||||
* Given an overlay applied to an FPGA region, parse the FPGA image specific
|
||||
* info in the overlay and do some checking.
|
||||
*
|
||||
* Returns:
|
||||
* Return:
|
||||
* NULL if overlay doesn't direct us to program the FPGA.
|
||||
* fpga_image_info struct if there is an image to program.
|
||||
* error code for invalid overlay.
|
||||
*/
|
||||
static struct fpga_image_info *of_fpga_region_parse_ov(
|
||||
struct fpga_region *region,
|
||||
struct device_node *overlay)
|
||||
static struct fpga_image_info *
|
||||
of_fpga_region_parse_ov(struct fpga_region *region,
|
||||
struct device_node *overlay)
|
||||
{
|
||||
struct device *dev = ®ion->dev;
|
||||
struct fpga_image_info *info;
|
||||
@ -279,7 +279,7 @@ ret_no_info:
|
||||
* If the checks fail, overlay is rejected and does not get added to the
|
||||
* live tree.
|
||||
*
|
||||
* Returns 0 for success or negative error code for failure.
|
||||
* Return: 0 for success or negative error code for failure.
|
||||
*/
|
||||
static int of_fpga_region_notify_pre_apply(struct fpga_region *region,
|
||||
struct of_overlay_notify_data *nd)
|
||||
@ -339,7 +339,7 @@ static void of_fpga_region_notify_post_remove(struct fpga_region *region,
|
||||
* This notifier handles programming an FPGA when a "firmware-name" property is
|
||||
* added to an fpga-region.
|
||||
*
|
||||
* Returns NOTIFY_OK or error if FPGA programming fails.
|
||||
* Return: NOTIFY_OK or error if FPGA programming fails.
|
||||
*/
|
||||
static int of_fpga_region_notify(struct notifier_block *nb,
|
||||
unsigned long action, void *arg)
|
||||
@ -446,6 +446,8 @@ static struct platform_driver of_fpga_region_driver = {
|
||||
/**
|
||||
* of_fpga_region_init - init function for fpga_region class
|
||||
* Creates the fpga_region class and registers a reconfig notifier.
|
||||
*
|
||||
* Return: 0 on success, negative error code otherwise.
|
||||
*/
|
||||
static int __init of_fpga_region_init(void)
|
||||
{
|
||||
|
@ -1379,7 +1379,7 @@ static int coresight_fixup_device_conns(struct coresight_device *csdev)
|
||||
continue;
|
||||
conn->child_dev =
|
||||
coresight_find_csdev_by_fwnode(conn->child_fwnode);
|
||||
if (conn->child_dev) {
|
||||
if (conn->child_dev && conn->child_dev->has_conns_grp) {
|
||||
ret = coresight_make_links(csdev, conn,
|
||||
conn->child_dev);
|
||||
if (ret)
|
||||
@ -1571,6 +1571,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
|
||||
int nr_refcnts = 1;
|
||||
atomic_t *refcnts = NULL;
|
||||
struct coresight_device *csdev;
|
||||
bool registered = false;
|
||||
|
||||
csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
|
||||
if (!csdev) {
|
||||
@ -1591,7 +1592,8 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
|
||||
refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL);
|
||||
if (!refcnts) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_csdev;
|
||||
kfree(csdev);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
csdev->refcnt = refcnts;
|
||||
@ -1616,6 +1618,13 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
|
||||
csdev->dev.fwnode = fwnode_handle_get(dev_fwnode(desc->dev));
|
||||
dev_set_name(&csdev->dev, "%s", desc->name);
|
||||
|
||||
/*
|
||||
* Make sure the device registration and the connection fixup
|
||||
* are synchronised, so that we don't see uninitialised devices
|
||||
* on the coresight bus while trying to resolve the connections.
|
||||
*/
|
||||
mutex_lock(&coresight_mutex);
|
||||
|
||||
ret = device_register(&csdev->dev);
|
||||
if (ret) {
|
||||
put_device(&csdev->dev);
|
||||
@ -1623,7 +1632,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
|
||||
* All resources are free'd explicitly via
|
||||
* coresight_device_release(), triggered from put_device().
|
||||
*/
|
||||
goto err_out;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (csdev->type == CORESIGHT_DEV_TYPE_SINK ||
|
||||
@ -1638,11 +1647,11 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
|
||||
* from put_device(), which is in turn called from
|
||||
* function device_unregister().
|
||||
*/
|
||||
goto err_out;
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&coresight_mutex);
|
||||
/* Device is now registered */
|
||||
registered = true;
|
||||
|
||||
ret = coresight_create_conns_sysfs_group(csdev);
|
||||
if (!ret)
|
||||
@ -1652,16 +1661,18 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
|
||||
if (!ret && cti_assoc_ops && cti_assoc_ops->add)
|
||||
cti_assoc_ops->add(csdev);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&coresight_mutex);
|
||||
if (ret) {
|
||||
/* Success */
|
||||
if (!ret)
|
||||
return csdev;
|
||||
|
||||
/* Unregister the device if needed */
|
||||
if (registered) {
|
||||
coresight_unregister(csdev);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return csdev;
|
||||
|
||||
err_free_csdev:
|
||||
kfree(csdev);
|
||||
err_out:
|
||||
/* Cleanup the connection information */
|
||||
coresight_release_platform_data(NULL, desc->pdata);
|
||||
|
@ -380,9 +380,10 @@ static int debug_notifier_call(struct notifier_block *self,
|
||||
int cpu;
|
||||
struct debug_drvdata *drvdata;
|
||||
|
||||
mutex_lock(&debug_lock);
|
||||
/* Bail out if we can't acquire the mutex or the functionality is off */
|
||||
if (!mutex_trylock(&debug_lock))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
/* Bail out if the functionality is disabled */
|
||||
if (!debug_enable)
|
||||
goto skip_dump;
|
||||
|
||||
@ -401,7 +402,7 @@ static int debug_notifier_call(struct notifier_block *self,
|
||||
|
||||
skip_dump:
|
||||
mutex_unlock(&debug_lock);
|
||||
return 0;
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block debug_notifier = {
|
||||
|
@ -204,7 +204,7 @@ void etm_set_default(struct etm_config *config)
|
||||
* set all bits in register 0x007, the ETMTECR2, to 0
|
||||
* set register 0x008, the ETMTEEVR, to 0x6F (TRUE).
|
||||
*/
|
||||
config->enable_ctrl1 = BIT(24);
|
||||
config->enable_ctrl1 = ETMTECR1_INC_EXC;
|
||||
config->enable_ctrl2 = 0x0;
|
||||
config->enable_event = ETM_HARD_WIRE_RES_A;
|
||||
|
||||
|
@ -474,7 +474,7 @@ static ssize_t addr_start_store(struct device *dev,
|
||||
config->addr_val[idx] = val;
|
||||
config->addr_type[idx] = ETM_ADDR_TYPE_START;
|
||||
config->startstop_ctrl |= (1 << idx);
|
||||
config->enable_ctrl1 |= BIT(25);
|
||||
config->enable_ctrl1 |= ETMTECR1_START_STOP;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
return size;
|
||||
|
@ -443,7 +443,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
|
||||
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
|
||||
/* always clear status bit on restart if using single-shot */
|
||||
if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
|
||||
config->ss_status[i] &= ~BIT(31);
|
||||
config->ss_status[i] &= ~TRCSSCSRn_STATUS;
|
||||
etm4x_relaxed_write32(csa, config->ss_ctrl[i], TRCSSCCRn(i));
|
||||
etm4x_relaxed_write32(csa, config->ss_status[i], TRCSSCSRn(i));
|
||||
if (etm4x_sspcicrn_present(drvdata, i))
|
||||
@ -633,7 +633,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
|
||||
|
||||
/* Go from generic option to ETMv4 specifics */
|
||||
if (attr->config & BIT(ETM_OPT_CYCACC)) {
|
||||
config->cfg |= BIT(4);
|
||||
config->cfg |= TRCCONFIGR_CCI;
|
||||
/* TRM: Must program this for cycacc to work */
|
||||
config->ccctlr = ETM_CYC_THRESHOLD_DEFAULT;
|
||||
}
|
||||
@ -653,14 +653,14 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
|
||||
goto out;
|
||||
|
||||
/* bit[11], Global timestamp tracing bit */
|
||||
config->cfg |= BIT(11);
|
||||
config->cfg |= TRCCONFIGR_TS;
|
||||
}
|
||||
|
||||
/* Only trace contextID when runs in root PID namespace */
|
||||
if ((attr->config & BIT(ETM_OPT_CTXTID)) &&
|
||||
task_is_in_init_pid_ns(current))
|
||||
/* bit[6], Context ID tracing bit */
|
||||
config->cfg |= BIT(ETM4_CFG_BIT_CTXTID);
|
||||
config->cfg |= TRCCONFIGR_CID;
|
||||
|
||||
/*
|
||||
* If set bit ETM_OPT_CTXTID2 in perf config, this asks to trace VMID
|
||||
@ -672,17 +672,15 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Only trace virtual contextID when runs in root PID namespace */
|
||||
if (task_is_in_init_pid_ns(current))
|
||||
config->cfg |= BIT(ETM4_CFG_BIT_VMID) |
|
||||
BIT(ETM4_CFG_BIT_VMID_OPT);
|
||||
config->cfg |= TRCCONFIGR_VMID | TRCCONFIGR_VMIDOPT;
|
||||
}
|
||||
|
||||
/* return stack - enable if selected and supported */
|
||||
if ((attr->config & BIT(ETM_OPT_RETSTK)) && drvdata->retstack)
|
||||
/* bit[12], Return stack enable bit */
|
||||
config->cfg |= BIT(12);
|
||||
config->cfg |= TRCCONFIGR_RS;
|
||||
|
||||
/*
|
||||
* Set any selected configuration and preset.
|
||||
@ -1097,107 +1095,67 @@ static void etm4_init_arch_data(void *info)
|
||||
etmidr0 = etm4x_relaxed_read32(csa, TRCIDR0);
|
||||
|
||||
/* INSTP0, bits[2:1] P0 tracing support field */
|
||||
if (BMVAL(etmidr0, 1, 2) == 0b11)
|
||||
drvdata->instrp0 = true;
|
||||
else
|
||||
drvdata->instrp0 = false;
|
||||
|
||||
drvdata->instrp0 = !!(FIELD_GET(TRCIDR0_INSTP0_MASK, etmidr0) == 0b11);
|
||||
/* TRCBB, bit[5] Branch broadcast tracing support bit */
|
||||
if (BMVAL(etmidr0, 5, 5))
|
||||
drvdata->trcbb = true;
|
||||
else
|
||||
drvdata->trcbb = false;
|
||||
|
||||
drvdata->trcbb = !!(etmidr0 & TRCIDR0_TRCBB);
|
||||
/* TRCCOND, bit[6] Conditional instruction tracing support bit */
|
||||
if (BMVAL(etmidr0, 6, 6))
|
||||
drvdata->trccond = true;
|
||||
else
|
||||
drvdata->trccond = false;
|
||||
|
||||
drvdata->trccond = !!(etmidr0 & TRCIDR0_TRCCOND);
|
||||
/* TRCCCI, bit[7] Cycle counting instruction bit */
|
||||
if (BMVAL(etmidr0, 7, 7))
|
||||
drvdata->trccci = true;
|
||||
else
|
||||
drvdata->trccci = false;
|
||||
|
||||
drvdata->trccci = !!(etmidr0 & TRCIDR0_TRCCCI);
|
||||
/* RETSTACK, bit[9] Return stack bit */
|
||||
if (BMVAL(etmidr0, 9, 9))
|
||||
drvdata->retstack = true;
|
||||
else
|
||||
drvdata->retstack = false;
|
||||
|
||||
drvdata->retstack = !!(etmidr0 & TRCIDR0_RETSTACK);
|
||||
/* NUMEVENT, bits[11:10] Number of events field */
|
||||
drvdata->nr_event = BMVAL(etmidr0, 10, 11);
|
||||
drvdata->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0);
|
||||
/* QSUPP, bits[16:15] Q element support field */
|
||||
drvdata->q_support = BMVAL(etmidr0, 15, 16);
|
||||
drvdata->q_support = FIELD_GET(TRCIDR0_QSUPP_MASK, etmidr0);
|
||||
/* TSSIZE, bits[28:24] Global timestamp size field */
|
||||
drvdata->ts_size = BMVAL(etmidr0, 24, 28);
|
||||
drvdata->ts_size = FIELD_GET(TRCIDR0_TSSIZE_MASK, etmidr0);
|
||||
|
||||
/* maximum size of resources */
|
||||
etmidr2 = etm4x_relaxed_read32(csa, TRCIDR2);
|
||||
/* CIDSIZE, bits[9:5] Indicates the Context ID size */
|
||||
drvdata->ctxid_size = BMVAL(etmidr2, 5, 9);
|
||||
drvdata->ctxid_size = FIELD_GET(TRCIDR2_CIDSIZE_MASK, etmidr2);
|
||||
/* VMIDSIZE, bits[14:10] Indicates the VMID size */
|
||||
drvdata->vmid_size = BMVAL(etmidr2, 10, 14);
|
||||
drvdata->vmid_size = FIELD_GET(TRCIDR2_VMIDSIZE_MASK, etmidr2);
|
||||
/* CCSIZE, bits[28:25] size of the cycle counter in bits minus 12 */
|
||||
drvdata->ccsize = BMVAL(etmidr2, 25, 28);
|
||||
drvdata->ccsize = FIELD_GET(TRCIDR2_CCSIZE_MASK, etmidr2);
|
||||
|
||||
etmidr3 = etm4x_relaxed_read32(csa, TRCIDR3);
|
||||
/* CCITMIN, bits[11:0] minimum threshold value that can be programmed */
|
||||
drvdata->ccitmin = BMVAL(etmidr3, 0, 11);
|
||||
drvdata->ccitmin = FIELD_GET(TRCIDR3_CCITMIN_MASK, etmidr3);
|
||||
/* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
|
||||
drvdata->s_ex_level = BMVAL(etmidr3, 16, 19);
|
||||
drvdata->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
|
||||
drvdata->config.s_ex_level = drvdata->s_ex_level;
|
||||
/* EXLEVEL_NS, bits[23:20] Non-secure state instruction tracing */
|
||||
drvdata->ns_ex_level = BMVAL(etmidr3, 20, 23);
|
||||
|
||||
drvdata->ns_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_NS_MASK, etmidr3);
|
||||
/*
|
||||
* TRCERR, bit[24] whether a trace unit can trace a
|
||||
* system error exception.
|
||||
*/
|
||||
if (BMVAL(etmidr3, 24, 24))
|
||||
drvdata->trc_error = true;
|
||||
else
|
||||
drvdata->trc_error = false;
|
||||
|
||||
drvdata->trc_error = !!(etmidr3 & TRCIDR3_TRCERR);
|
||||
/* SYNCPR, bit[25] implementation has a fixed synchronization period? */
|
||||
if (BMVAL(etmidr3, 25, 25))
|
||||
drvdata->syncpr = true;
|
||||
else
|
||||
drvdata->syncpr = false;
|
||||
|
||||
drvdata->syncpr = !!(etmidr3 & TRCIDR3_SYNCPR);
|
||||
/* STALLCTL, bit[26] is stall control implemented? */
|
||||
if (BMVAL(etmidr3, 26, 26))
|
||||
drvdata->stallctl = true;
|
||||
else
|
||||
drvdata->stallctl = false;
|
||||
|
||||
drvdata->stallctl = !!(etmidr3 & TRCIDR3_STALLCTL);
|
||||
/* SYSSTALL, bit[27] implementation can support stall control? */
|
||||
if (BMVAL(etmidr3, 27, 27))
|
||||
drvdata->sysstall = true;
|
||||
else
|
||||
drvdata->sysstall = false;
|
||||
|
||||
drvdata->sysstall = !!(etmidr3 & TRCIDR3_SYSSTALL);
|
||||
/*
|
||||
* NUMPROC - the number of PEs available for tracing, 5bits
|
||||
* = TRCIDR3.bits[13:12]bits[30:28]
|
||||
* bits[4:3] = TRCIDR3.bits[13:12] (since etm-v4.2, otherwise RES0)
|
||||
* bits[3:0] = TRCIDR3.bits[30:28]
|
||||
*/
|
||||
drvdata->nr_pe = (BMVAL(etmidr3, 12, 13) << 3) | BMVAL(etmidr3, 28, 30);
|
||||
|
||||
drvdata->nr_pe = (FIELD_GET(TRCIDR3_NUMPROC_HI_MASK, etmidr3) << 3) |
|
||||
FIELD_GET(TRCIDR3_NUMPROC_LO_MASK, etmidr3);
|
||||
/* NOOVERFLOW, bit[31] is trace overflow prevention supported */
|
||||
if (BMVAL(etmidr3, 31, 31))
|
||||
drvdata->nooverflow = true;
|
||||
else
|
||||
drvdata->nooverflow = false;
|
||||
drvdata->nooverflow = !!(etmidr3 & TRCIDR3_NOOVERFLOW);
|
||||
|
||||
/* number of resources trace unit supports */
|
||||
etmidr4 = etm4x_relaxed_read32(csa, TRCIDR4);
|
||||
/* NUMACPAIRS, bits[0:3] number of addr comparator pairs for tracing */
|
||||
drvdata->nr_addr_cmp = BMVAL(etmidr4, 0, 3);
|
||||
drvdata->nr_addr_cmp = FIELD_GET(TRCIDR4_NUMACPAIRS_MASK, etmidr4);
|
||||
/* NUMPC, bits[15:12] number of PE comparator inputs for tracing */
|
||||
drvdata->nr_pe_cmp = BMVAL(etmidr4, 12, 15);
|
||||
drvdata->nr_pe_cmp = FIELD_GET(TRCIDR4_NUMPC_MASK, etmidr4);
|
||||
/*
|
||||
* NUMRSPAIR, bits[19:16]
|
||||
* The number of resource pairs conveyed by the HW starts at 0, i.e a
|
||||
@ -1208,7 +1166,7 @@ static void etm4_init_arch_data(void *info)
|
||||
* the default TRUE and FALSE resource selectors are omitted.
|
||||
* Otherwise for values 0x1 and above the number is N + 1 as per v4.2.
|
||||
*/
|
||||
drvdata->nr_resource = BMVAL(etmidr4, 16, 19);
|
||||
drvdata->nr_resource = FIELD_GET(TRCIDR4_NUMRSPAIR_MASK, etmidr4);
|
||||
if ((drvdata->arch < ETM_ARCH_V4_3) || (drvdata->nr_resource > 0))
|
||||
drvdata->nr_resource += 1;
|
||||
/*
|
||||
@ -1216,45 +1174,39 @@ static void etm4_init_arch_data(void *info)
|
||||
* comparator control for tracing. Read any status regs as these
|
||||
* also contain RO capability data.
|
||||
*/
|
||||
drvdata->nr_ss_cmp = BMVAL(etmidr4, 20, 23);
|
||||
drvdata->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
|
||||
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
|
||||
drvdata->config.ss_status[i] =
|
||||
etm4x_relaxed_read32(csa, TRCSSCSRn(i));
|
||||
}
|
||||
/* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
|
||||
drvdata->numcidc = BMVAL(etmidr4, 24, 27);
|
||||
drvdata->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
|
||||
/* NUMVMIDC, bits[31:28] number of VMID comparators for tracing */
|
||||
drvdata->numvmidc = BMVAL(etmidr4, 28, 31);
|
||||
drvdata->numvmidc = FIELD_GET(TRCIDR4_NUMVMIDC_MASK, etmidr4);
|
||||
|
||||
etmidr5 = etm4x_relaxed_read32(csa, TRCIDR5);
|
||||
/* NUMEXTIN, bits[8:0] number of external inputs implemented */
|
||||
drvdata->nr_ext_inp = BMVAL(etmidr5, 0, 8);
|
||||
drvdata->nr_ext_inp = FIELD_GET(TRCIDR5_NUMEXTIN_MASK, etmidr5);
|
||||
/* TRACEIDSIZE, bits[21:16] indicates the trace ID width */
|
||||
drvdata->trcid_size = BMVAL(etmidr5, 16, 21);
|
||||
drvdata->trcid_size = FIELD_GET(TRCIDR5_TRACEIDSIZE_MASK, etmidr5);
|
||||
/* ATBTRIG, bit[22] implementation can support ATB triggers? */
|
||||
if (BMVAL(etmidr5, 22, 22))
|
||||
drvdata->atbtrig = true;
|
||||
else
|
||||
drvdata->atbtrig = false;
|
||||
drvdata->atbtrig = !!(etmidr5 & TRCIDR5_ATBTRIG);
|
||||
/*
|
||||
* LPOVERRIDE, bit[23] implementation supports
|
||||
* low-power state override
|
||||
*/
|
||||
if (BMVAL(etmidr5, 23, 23) && (!drvdata->skip_power_up))
|
||||
drvdata->lpoverride = true;
|
||||
else
|
||||
drvdata->lpoverride = false;
|
||||
drvdata->lpoverride = (etmidr5 & TRCIDR5_LPOVERRIDE) && (!drvdata->skip_power_up);
|
||||
/* NUMSEQSTATE, bits[27:25] number of sequencer states implemented */
|
||||
drvdata->nrseqstate = BMVAL(etmidr5, 25, 27);
|
||||
drvdata->nrseqstate = FIELD_GET(TRCIDR5_NUMSEQSTATE_MASK, etmidr5);
|
||||
/* NUMCNTR, bits[30:28] number of counters available for tracing */
|
||||
drvdata->nr_cntr = BMVAL(etmidr5, 28, 30);
|
||||
drvdata->nr_cntr = FIELD_GET(TRCIDR5_NUMCNTR_MASK, etmidr5);
|
||||
etm4_cs_lock(drvdata, csa);
|
||||
cpu_detect_trace_filtering(drvdata);
|
||||
}
|
||||
|
||||
static inline u32 etm4_get_victlr_access_type(struct etmv4_config *config)
|
||||
{
|
||||
return etm4_get_access_type(config) << TRCVICTLR_EXLEVEL_SHIFT;
|
||||
return etm4_get_access_type(config) << __bf_shf(TRCVICTLR_EXLEVEL_MASK);
|
||||
}
|
||||
|
||||
/* Set ELx trace filter access in the TRCVICTLR register */
|
||||
@ -1280,7 +1232,7 @@ static void etm4_set_default_config(struct etmv4_config *config)
|
||||
config->ts_ctrl = 0x0;
|
||||
|
||||
/* TRCVICTLR::EVENT = 0x01, select the always on logic */
|
||||
config->vinst_ctrl = BIT(0);
|
||||
config->vinst_ctrl = FIELD_PREP(TRCVICTLR_EVENT_MASK, 0x01);
|
||||
|
||||
/* TRCVICTLR::EXLEVEL_NS:EXLEVELS: Set kernel / user filtering */
|
||||
etm4_set_victlr_access(config);
|
||||
@ -1389,7 +1341,7 @@ static void etm4_set_default_filter(struct etmv4_config *config)
|
||||
* TRCVICTLR::SSSTATUS == 1, the start-stop logic is
|
||||
* in the started state
|
||||
*/
|
||||
config->vinst_ctrl |= BIT(9);
|
||||
config->vinst_ctrl |= TRCVICTLR_SSSTATUS;
|
||||
config->mode |= ETM_MODE_VIEWINST_STARTSTOP;
|
||||
|
||||
/* No start-stop filtering for ViewInst */
|
||||
@ -1493,7 +1445,7 @@ static int etm4_set_event_filters(struct etmv4_drvdata *drvdata,
|
||||
* TRCVICTLR::SSSTATUS == 1, the start-stop logic is
|
||||
* in the started state
|
||||
*/
|
||||
config->vinst_ctrl |= BIT(9);
|
||||
config->vinst_ctrl |= TRCVICTLR_SSSTATUS;
|
||||
|
||||
/* No start-stop filtering for ViewInst */
|
||||
config->vissctlr = 0x0;
|
||||
@ -1521,7 +1473,7 @@ static int etm4_set_event_filters(struct etmv4_drvdata *drvdata,
|
||||
* etm4_disable_perf().
|
||||
*/
|
||||
if (filters->ssstatus)
|
||||
config->vinst_ctrl |= BIT(9);
|
||||
config->vinst_ctrl |= TRCVICTLR_SSSTATUS;
|
||||
|
||||
/* No include/exclude filtering for ViewInst */
|
||||
config->viiectlr = 0x0;
|
||||
|
@ -22,7 +22,7 @@ static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude)
|
||||
* TRCACATRn.TYPE bit[1:0]: type of comparison
|
||||
* the trace unit performs
|
||||
*/
|
||||
if (BMVAL(config->addr_acc[idx], 0, 1) == ETM_INSTR_ADDR) {
|
||||
if (FIELD_GET(TRCACATRn_TYPE_MASK, config->addr_acc[idx]) == TRCACATRn_TYPE_ADDR) {
|
||||
if (idx % 2 != 0)
|
||||
return -EINVAL;
|
||||
|
||||
@ -180,12 +180,12 @@ static ssize_t reset_store(struct device *dev,
|
||||
|
||||
/* Disable data tracing: do not trace load and store data transfers */
|
||||
config->mode &= ~(ETM_MODE_LOAD | ETM_MODE_STORE);
|
||||
config->cfg &= ~(BIT(1) | BIT(2));
|
||||
config->cfg &= ~(TRCCONFIGR_INSTP0_LOAD | TRCCONFIGR_INSTP0_STORE);
|
||||
|
||||
/* Disable data value and data address tracing */
|
||||
config->mode &= ~(ETM_MODE_DATA_TRACE_ADDR |
|
||||
ETM_MODE_DATA_TRACE_VAL);
|
||||
config->cfg &= ~(BIT(16) | BIT(17));
|
||||
config->cfg &= ~(TRCCONFIGR_DA | TRCCONFIGR_DV);
|
||||
|
||||
/* Disable all events tracing */
|
||||
config->eventctrl0 = 0x0;
|
||||
@ -206,11 +206,11 @@ static ssize_t reset_store(struct device *dev,
|
||||
* started state. ARM recommends start-stop logic is set before
|
||||
* each trace run.
|
||||
*/
|
||||
config->vinst_ctrl = BIT(0);
|
||||
config->vinst_ctrl = FIELD_PREP(TRCVICTLR_EVENT_MASK, 0x01);
|
||||
if (drvdata->nr_addr_cmp > 0) {
|
||||
config->mode |= ETM_MODE_VIEWINST_STARTSTOP;
|
||||
/* SSSTATUS, bit[9] */
|
||||
config->vinst_ctrl |= BIT(9);
|
||||
config->vinst_ctrl |= TRCVICTLR_SSSTATUS;
|
||||
}
|
||||
|
||||
/* No address range filtering for ViewInst */
|
||||
@ -304,134 +304,134 @@ static ssize_t mode_store(struct device *dev,
|
||||
|
||||
if (drvdata->instrp0 == true) {
|
||||
/* start by clearing instruction P0 field */
|
||||
config->cfg &= ~(BIT(1) | BIT(2));
|
||||
config->cfg &= ~TRCCONFIGR_INSTP0_LOAD_STORE;
|
||||
if (config->mode & ETM_MODE_LOAD)
|
||||
/* 0b01 Trace load instructions as P0 instructions */
|
||||
config->cfg |= BIT(1);
|
||||
config->cfg |= TRCCONFIGR_INSTP0_LOAD;
|
||||
if (config->mode & ETM_MODE_STORE)
|
||||
/* 0b10 Trace store instructions as P0 instructions */
|
||||
config->cfg |= BIT(2);
|
||||
config->cfg |= TRCCONFIGR_INSTP0_STORE;
|
||||
if (config->mode & ETM_MODE_LOAD_STORE)
|
||||
/*
|
||||
* 0b11 Trace load and store instructions
|
||||
* as P0 instructions
|
||||
*/
|
||||
config->cfg |= BIT(1) | BIT(2);
|
||||
config->cfg |= TRCCONFIGR_INSTP0_LOAD_STORE;
|
||||
}
|
||||
|
||||
/* bit[3], Branch broadcast mode */
|
||||
if ((config->mode & ETM_MODE_BB) && (drvdata->trcbb == true))
|
||||
config->cfg |= BIT(3);
|
||||
config->cfg |= TRCCONFIGR_BB;
|
||||
else
|
||||
config->cfg &= ~BIT(3);
|
||||
config->cfg &= ~TRCCONFIGR_BB;
|
||||
|
||||
/* bit[4], Cycle counting instruction trace bit */
|
||||
if ((config->mode & ETMv4_MODE_CYCACC) &&
|
||||
(drvdata->trccci == true))
|
||||
config->cfg |= BIT(4);
|
||||
config->cfg |= TRCCONFIGR_CCI;
|
||||
else
|
||||
config->cfg &= ~BIT(4);
|
||||
config->cfg &= ~TRCCONFIGR_CCI;
|
||||
|
||||
/* bit[6], Context ID tracing bit */
|
||||
if ((config->mode & ETMv4_MODE_CTXID) && (drvdata->ctxid_size))
|
||||
config->cfg |= BIT(6);
|
||||
config->cfg |= TRCCONFIGR_CID;
|
||||
else
|
||||
config->cfg &= ~BIT(6);
|
||||
config->cfg &= ~TRCCONFIGR_CID;
|
||||
|
||||
if ((config->mode & ETM_MODE_VMID) && (drvdata->vmid_size))
|
||||
config->cfg |= BIT(7);
|
||||
config->cfg |= TRCCONFIGR_VMID;
|
||||
else
|
||||
config->cfg &= ~BIT(7);
|
||||
config->cfg &= ~TRCCONFIGR_VMID;
|
||||
|
||||
/* bits[10:8], Conditional instruction tracing bit */
|
||||
mode = ETM_MODE_COND(config->mode);
|
||||
if (drvdata->trccond == true) {
|
||||
config->cfg &= ~(BIT(8) | BIT(9) | BIT(10));
|
||||
config->cfg |= mode << 8;
|
||||
config->cfg &= ~TRCCONFIGR_COND_MASK;
|
||||
config->cfg |= mode << __bf_shf(TRCCONFIGR_COND_MASK);
|
||||
}
|
||||
|
||||
/* bit[11], Global timestamp tracing bit */
|
||||
if ((config->mode & ETMv4_MODE_TIMESTAMP) && (drvdata->ts_size))
|
||||
config->cfg |= BIT(11);
|
||||
config->cfg |= TRCCONFIGR_TS;
|
||||
else
|
||||
config->cfg &= ~BIT(11);
|
||||
config->cfg &= ~TRCCONFIGR_TS;
|
||||
|
||||
/* bit[12], Return stack enable bit */
|
||||
if ((config->mode & ETM_MODE_RETURNSTACK) &&
|
||||
(drvdata->retstack == true))
|
||||
config->cfg |= BIT(12);
|
||||
config->cfg |= TRCCONFIGR_RS;
|
||||
else
|
||||
config->cfg &= ~BIT(12);
|
||||
config->cfg &= ~TRCCONFIGR_RS;
|
||||
|
||||
/* bits[14:13], Q element enable field */
|
||||
mode = ETM_MODE_QELEM(config->mode);
|
||||
/* start by clearing QE bits */
|
||||
config->cfg &= ~(BIT(13) | BIT(14));
|
||||
config->cfg &= ~(TRCCONFIGR_QE_W_COUNTS | TRCCONFIGR_QE_WO_COUNTS);
|
||||
/*
|
||||
* if supported, Q elements with instruction counts are enabled.
|
||||
* Always set the low bit for any requested mode. Valid combos are
|
||||
* 0b00, 0b01 and 0b11.
|
||||
*/
|
||||
if (mode && drvdata->q_support)
|
||||
config->cfg |= BIT(13);
|
||||
config->cfg |= TRCCONFIGR_QE_W_COUNTS;
|
||||
/*
|
||||
* if supported, Q elements with and without instruction
|
||||
* counts are enabled
|
||||
*/
|
||||
if ((mode & BIT(1)) && (drvdata->q_support & BIT(1)))
|
||||
config->cfg |= BIT(14);
|
||||
config->cfg |= TRCCONFIGR_QE_WO_COUNTS;
|
||||
|
||||
/* bit[11], AMBA Trace Bus (ATB) trigger enable bit */
|
||||
if ((config->mode & ETM_MODE_ATB_TRIGGER) &&
|
||||
(drvdata->atbtrig == true))
|
||||
config->eventctrl1 |= BIT(11);
|
||||
config->eventctrl1 |= TRCEVENTCTL1R_ATB;
|
||||
else
|
||||
config->eventctrl1 &= ~BIT(11);
|
||||
config->eventctrl1 &= ~TRCEVENTCTL1R_ATB;
|
||||
|
||||
/* bit[12], Low-power state behavior override bit */
|
||||
if ((config->mode & ETM_MODE_LPOVERRIDE) &&
|
||||
(drvdata->lpoverride == true))
|
||||
config->eventctrl1 |= BIT(12);
|
||||
config->eventctrl1 |= TRCEVENTCTL1R_LPOVERRIDE;
|
||||
else
|
||||
config->eventctrl1 &= ~BIT(12);
|
||||
config->eventctrl1 &= ~TRCEVENTCTL1R_LPOVERRIDE;
|
||||
|
||||
/* bit[8], Instruction stall bit */
|
||||
if ((config->mode & ETM_MODE_ISTALL_EN) && (drvdata->stallctl == true))
|
||||
config->stall_ctrl |= BIT(8);
|
||||
config->stall_ctrl |= TRCSTALLCTLR_ISTALL;
|
||||
else
|
||||
config->stall_ctrl &= ~BIT(8);
|
||||
config->stall_ctrl &= ~TRCSTALLCTLR_ISTALL;
|
||||
|
||||
/* bit[10], Prioritize instruction trace bit */
|
||||
if (config->mode & ETM_MODE_INSTPRIO)
|
||||
config->stall_ctrl |= BIT(10);
|
||||
config->stall_ctrl |= TRCSTALLCTLR_INSTPRIORITY;
|
||||
else
|
||||
config->stall_ctrl &= ~BIT(10);
|
||||
config->stall_ctrl &= ~TRCSTALLCTLR_INSTPRIORITY;
|
||||
|
||||
/* bit[13], Trace overflow prevention bit */
|
||||
if ((config->mode & ETM_MODE_NOOVERFLOW) &&
|
||||
(drvdata->nooverflow == true))
|
||||
config->stall_ctrl |= BIT(13);
|
||||
config->stall_ctrl |= TRCSTALLCTLR_NOOVERFLOW;
|
||||
else
|
||||
config->stall_ctrl &= ~BIT(13);
|
||||
config->stall_ctrl &= ~TRCSTALLCTLR_NOOVERFLOW;
|
||||
|
||||
/* bit[9] Start/stop logic control bit */
|
||||
if (config->mode & ETM_MODE_VIEWINST_STARTSTOP)
|
||||
config->vinst_ctrl |= BIT(9);
|
||||
config->vinst_ctrl |= TRCVICTLR_SSSTATUS;
|
||||
else
|
||||
config->vinst_ctrl &= ~BIT(9);
|
||||
config->vinst_ctrl &= ~TRCVICTLR_SSSTATUS;
|
||||
|
||||
/* bit[10], Whether a trace unit must trace a Reset exception */
|
||||
if (config->mode & ETM_MODE_TRACE_RESET)
|
||||
config->vinst_ctrl |= BIT(10);
|
||||
config->vinst_ctrl |= TRCVICTLR_TRCRESET;
|
||||
else
|
||||
config->vinst_ctrl &= ~BIT(10);
|
||||
config->vinst_ctrl &= ~TRCVICTLR_TRCRESET;
|
||||
|
||||
/* bit[11], Whether a trace unit must trace a system error exception */
|
||||
if ((config->mode & ETM_MODE_TRACE_ERR) &&
|
||||
(drvdata->trc_error == true))
|
||||
config->vinst_ctrl |= BIT(11);
|
||||
config->vinst_ctrl |= TRCVICTLR_TRCERR;
|
||||
else
|
||||
config->vinst_ctrl &= ~BIT(11);
|
||||
config->vinst_ctrl &= ~TRCVICTLR_TRCERR;
|
||||
|
||||
if (config->mode & (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER))
|
||||
etm4_config_trace_mode(config);
|
||||
@ -534,7 +534,7 @@ static ssize_t event_instren_show(struct device *dev,
|
||||
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
struct etmv4_config *config = &drvdata->config;
|
||||
|
||||
val = BMVAL(config->eventctrl1, 0, 3);
|
||||
val = FIELD_GET(TRCEVENTCTL1R_INSTEN_MASK, config->eventctrl1);
|
||||
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
|
||||
}
|
||||
|
||||
@ -551,23 +551,28 @@ static ssize_t event_instren_store(struct device *dev,
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
/* start by clearing all instruction event enable bits */
|
||||
config->eventctrl1 &= ~(BIT(0) | BIT(1) | BIT(2) | BIT(3));
|
||||
config->eventctrl1 &= ~TRCEVENTCTL1R_INSTEN_MASK;
|
||||
switch (drvdata->nr_event) {
|
||||
case 0x0:
|
||||
/* generate Event element for event 1 */
|
||||
config->eventctrl1 |= val & BIT(1);
|
||||
config->eventctrl1 |= val & TRCEVENTCTL1R_INSTEN_1;
|
||||
break;
|
||||
case 0x1:
|
||||
/* generate Event element for event 1 and 2 */
|
||||
config->eventctrl1 |= val & (BIT(0) | BIT(1));
|
||||
config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 | TRCEVENTCTL1R_INSTEN_1);
|
||||
break;
|
||||
case 0x2:
|
||||
/* generate Event element for event 1, 2 and 3 */
|
||||
config->eventctrl1 |= val & (BIT(0) | BIT(1) | BIT(2));
|
||||
config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 |
|
||||
TRCEVENTCTL1R_INSTEN_1 |
|
||||
TRCEVENTCTL1R_INSTEN_2);
|
||||
break;
|
||||
case 0x3:
|
||||
/* generate Event element for all 4 events */
|
||||
config->eventctrl1 |= val & 0xF;
|
||||
config->eventctrl1 |= val & (TRCEVENTCTL1R_INSTEN_0 |
|
||||
TRCEVENTCTL1R_INSTEN_1 |
|
||||
TRCEVENTCTL1R_INSTEN_2 |
|
||||
TRCEVENTCTL1R_INSTEN_3);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -702,10 +707,10 @@ static ssize_t bb_ctrl_store(struct device *dev,
|
||||
* individual range comparators. If include then at least 1
|
||||
* range must be selected.
|
||||
*/
|
||||
if ((val & BIT(8)) && (BMVAL(val, 0, 7) == 0))
|
||||
if ((val & TRCBBCTLR_MODE) && (FIELD_GET(TRCBBCTLR_RANGE_MASK, val) == 0))
|
||||
return -EINVAL;
|
||||
|
||||
config->bb_ctrl = val & GENMASK(8, 0);
|
||||
config->bb_ctrl = val & (TRCBBCTLR_MODE | TRCBBCTLR_RANGE_MASK);
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(bb_ctrl);
|
||||
@ -718,7 +723,7 @@ static ssize_t event_vinst_show(struct device *dev,
|
||||
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
struct etmv4_config *config = &drvdata->config;
|
||||
|
||||
val = config->vinst_ctrl & ETMv4_EVENT_MASK;
|
||||
val = FIELD_GET(TRCVICTLR_EVENT_MASK, config->vinst_ctrl);
|
||||
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
|
||||
}
|
||||
|
||||
@ -734,9 +739,9 @@ static ssize_t event_vinst_store(struct device *dev,
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
val &= ETMv4_EVENT_MASK;
|
||||
config->vinst_ctrl &= ~ETMv4_EVENT_MASK;
|
||||
config->vinst_ctrl |= val;
|
||||
val &= TRCVICTLR_EVENT_MASK >> __bf_shf(TRCVICTLR_EVENT_MASK);
|
||||
config->vinst_ctrl &= ~TRCVICTLR_EVENT_MASK;
|
||||
config->vinst_ctrl |= FIELD_PREP(TRCVICTLR_EVENT_MASK, val);
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
}
|
||||
@ -750,7 +755,7 @@ static ssize_t s_exlevel_vinst_show(struct device *dev,
|
||||
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
struct etmv4_config *config = &drvdata->config;
|
||||
|
||||
val = (config->vinst_ctrl & TRCVICTLR_EXLEVEL_S_MASK) >> TRCVICTLR_EXLEVEL_S_SHIFT;
|
||||
val = FIELD_GET(TRCVICTLR_EXLEVEL_S_MASK, config->vinst_ctrl);
|
||||
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
|
||||
}
|
||||
|
||||
@ -767,10 +772,10 @@ static ssize_t s_exlevel_vinst_store(struct device *dev,
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
/* clear all EXLEVEL_S bits */
|
||||
config->vinst_ctrl &= ~(TRCVICTLR_EXLEVEL_S_MASK);
|
||||
config->vinst_ctrl &= ~TRCVICTLR_EXLEVEL_S_MASK;
|
||||
/* enable instruction tracing for corresponding exception level */
|
||||
val &= drvdata->s_ex_level;
|
||||
config->vinst_ctrl |= (val << TRCVICTLR_EXLEVEL_S_SHIFT);
|
||||
config->vinst_ctrl |= val << __bf_shf(TRCVICTLR_EXLEVEL_S_MASK);
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
}
|
||||
@ -785,7 +790,7 @@ static ssize_t ns_exlevel_vinst_show(struct device *dev,
|
||||
struct etmv4_config *config = &drvdata->config;
|
||||
|
||||
/* EXLEVEL_NS, bits[23:20] */
|
||||
val = (config->vinst_ctrl & TRCVICTLR_EXLEVEL_NS_MASK) >> TRCVICTLR_EXLEVEL_NS_SHIFT;
|
||||
val = FIELD_GET(TRCVICTLR_EXLEVEL_NS_MASK, config->vinst_ctrl);
|
||||
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
|
||||
}
|
||||
|
||||
@ -802,10 +807,10 @@ static ssize_t ns_exlevel_vinst_store(struct device *dev,
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
/* clear EXLEVEL_NS bits */
|
||||
config->vinst_ctrl &= ~(TRCVICTLR_EXLEVEL_NS_MASK);
|
||||
config->vinst_ctrl &= ~TRCVICTLR_EXLEVEL_NS_MASK;
|
||||
/* enable instruction tracing for corresponding exception level */
|
||||
val &= drvdata->ns_ex_level;
|
||||
config->vinst_ctrl |= (val << TRCVICTLR_EXLEVEL_NS_SHIFT);
|
||||
config->vinst_ctrl |= val << __bf_shf(TRCVICTLR_EXLEVEL_NS_MASK);
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
}
|
||||
@ -858,11 +863,11 @@ static ssize_t addr_instdatatype_show(struct device *dev,
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
idx = config->addr_idx;
|
||||
val = BMVAL(config->addr_acc[idx], 0, 1);
|
||||
val = FIELD_GET(TRCACATRn_TYPE_MASK, config->addr_acc[idx]);
|
||||
len = scnprintf(buf, PAGE_SIZE, "%s\n",
|
||||
val == ETM_INSTR_ADDR ? "instr" :
|
||||
(val == ETM_DATA_LOAD_ADDR ? "data_load" :
|
||||
(val == ETM_DATA_STORE_ADDR ? "data_store" :
|
||||
val == TRCACATRn_TYPE_ADDR ? "instr" :
|
||||
(val == TRCACATRn_TYPE_DATA_LOAD_ADDR ? "data_load" :
|
||||
(val == TRCACATRn_TYPE_DATA_STORE_ADDR ? "data_store" :
|
||||
"data_load_store")));
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return len;
|
||||
@ -886,7 +891,7 @@ static ssize_t addr_instdatatype_store(struct device *dev,
|
||||
idx = config->addr_idx;
|
||||
if (!strcmp(str, "instr"))
|
||||
/* TYPE, bits[1:0] */
|
||||
config->addr_acc[idx] &= ~(BIT(0) | BIT(1));
|
||||
config->addr_acc[idx] &= ~TRCACATRn_TYPE_MASK;
|
||||
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
@ -1144,7 +1149,7 @@ static ssize_t addr_ctxtype_show(struct device *dev,
|
||||
spin_lock(&drvdata->spinlock);
|
||||
idx = config->addr_idx;
|
||||
/* CONTEXTTYPE, bits[3:2] */
|
||||
val = BMVAL(config->addr_acc[idx], 2, 3);
|
||||
val = FIELD_GET(TRCACATRn_CONTEXTTYPE_MASK, config->addr_acc[idx]);
|
||||
len = scnprintf(buf, PAGE_SIZE, "%s\n", val == ETM_CTX_NONE ? "none" :
|
||||
(val == ETM_CTX_CTXID ? "ctxid" :
|
||||
(val == ETM_CTX_VMID ? "vmid" : "all")));
|
||||
@ -1170,18 +1175,18 @@ static ssize_t addr_ctxtype_store(struct device *dev,
|
||||
idx = config->addr_idx;
|
||||
if (!strcmp(str, "none"))
|
||||
/* start by clearing context type bits */
|
||||
config->addr_acc[idx] &= ~(BIT(2) | BIT(3));
|
||||
config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_MASK;
|
||||
else if (!strcmp(str, "ctxid")) {
|
||||
/* 0b01 The trace unit performs a Context ID */
|
||||
if (drvdata->numcidc) {
|
||||
config->addr_acc[idx] |= BIT(2);
|
||||
config->addr_acc[idx] &= ~BIT(3);
|
||||
config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_CTXID;
|
||||
config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_VMID;
|
||||
}
|
||||
} else if (!strcmp(str, "vmid")) {
|
||||
/* 0b10 The trace unit performs a VMID */
|
||||
if (drvdata->numvmidc) {
|
||||
config->addr_acc[idx] &= ~BIT(2);
|
||||
config->addr_acc[idx] |= BIT(3);
|
||||
config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_CTXID;
|
||||
config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_VMID;
|
||||
}
|
||||
} else if (!strcmp(str, "all")) {
|
||||
/*
|
||||
@ -1189,9 +1194,9 @@ static ssize_t addr_ctxtype_store(struct device *dev,
|
||||
* comparison and a VMID
|
||||
*/
|
||||
if (drvdata->numcidc)
|
||||
config->addr_acc[idx] |= BIT(2);
|
||||
config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_CTXID;
|
||||
if (drvdata->numvmidc)
|
||||
config->addr_acc[idx] |= BIT(3);
|
||||
config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_VMID;
|
||||
}
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
@ -1210,7 +1215,7 @@ static ssize_t addr_context_show(struct device *dev,
|
||||
spin_lock(&drvdata->spinlock);
|
||||
idx = config->addr_idx;
|
||||
/* context ID comparator bits[6:4] */
|
||||
val = BMVAL(config->addr_acc[idx], 4, 6);
|
||||
val = FIELD_GET(TRCACATRn_CONTEXT_MASK, config->addr_acc[idx]);
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
|
||||
}
|
||||
@ -1235,8 +1240,8 @@ static ssize_t addr_context_store(struct device *dev,
|
||||
spin_lock(&drvdata->spinlock);
|
||||
idx = config->addr_idx;
|
||||
/* clear context ID comparator bits[6:4] */
|
||||
config->addr_acc[idx] &= ~(BIT(4) | BIT(5) | BIT(6));
|
||||
config->addr_acc[idx] |= (val << 4);
|
||||
config->addr_acc[idx] &= ~TRCACATRn_CONTEXT_MASK;
|
||||
config->addr_acc[idx] |= val << __bf_shf(TRCACATRn_CONTEXT_MASK);
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
}
|
||||
@ -1253,7 +1258,7 @@ static ssize_t addr_exlevel_s_ns_show(struct device *dev,
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
idx = config->addr_idx;
|
||||
val = BMVAL(config->addr_acc[idx], 8, 14);
|
||||
val = FIELD_GET(TRCACATRn_EXLEVEL_MASK, config->addr_acc[idx]);
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
|
||||
}
|
||||
@ -1270,14 +1275,14 @@ static ssize_t addr_exlevel_s_ns_store(struct device *dev,
|
||||
if (kstrtoul(buf, 0, &val))
|
||||
return -EINVAL;
|
||||
|
||||
if (val & ~((GENMASK(14, 8) >> 8)))
|
||||
if (val & ~(TRCACATRn_EXLEVEL_MASK >> __bf_shf(TRCACATRn_EXLEVEL_MASK)))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
idx = config->addr_idx;
|
||||
/* clear Exlevel_ns & Exlevel_s bits[14:12, 11:8], bit[15] is res0 */
|
||||
config->addr_acc[idx] &= ~(GENMASK(14, 8));
|
||||
config->addr_acc[idx] |= (val << 8);
|
||||
config->addr_acc[idx] &= ~TRCACATRn_EXLEVEL_MASK;
|
||||
config->addr_acc[idx] |= val << __bf_shf(TRCACATRn_EXLEVEL_MASK);
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
}
|
||||
@ -1721,8 +1726,11 @@ static ssize_t res_ctrl_store(struct device *dev,
|
||||
/* For odd idx pair inversal bit is RES0 */
|
||||
if (idx % 2 != 0)
|
||||
/* PAIRINV, bit[21] */
|
||||
val &= ~BIT(21);
|
||||
config->res_ctrl[idx] = val & GENMASK(21, 0);
|
||||
val &= ~TRCRSCTLRn_PAIRINV;
|
||||
config->res_ctrl[idx] = val & (TRCRSCTLRn_PAIRINV |
|
||||
TRCRSCTLRn_INV |
|
||||
TRCRSCTLRn_GROUP_MASK |
|
||||
TRCRSCTLRn_SELECT_MASK);
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
}
|
||||
@ -1787,9 +1795,9 @@ static ssize_t sshot_ctrl_store(struct device *dev,
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
idx = config->ss_idx;
|
||||
config->ss_ctrl[idx] = val & GENMASK(24, 0);
|
||||
config->ss_ctrl[idx] = FIELD_PREP(TRCSSCCRn_SAC_ARC_RST_MASK, val);
|
||||
/* must clear bit 31 in related status register on programming */
|
||||
config->ss_status[idx] &= ~BIT(31);
|
||||
config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
}
|
||||
@ -1837,9 +1845,9 @@ static ssize_t sshot_pe_ctrl_store(struct device *dev,
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
idx = config->ss_idx;
|
||||
config->ss_pe_cmp[idx] = val & GENMASK(7, 0);
|
||||
config->ss_pe_cmp[idx] = FIELD_PREP(TRCSSPCICRn_PC_MASK, val);
|
||||
/* must clear bit 31 in related status register on programming */
|
||||
config->ss_status[idx] &= ~BIT(31);
|
||||
config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
}
|
||||
|
@ -130,6 +130,104 @@
|
||||
|
||||
#define TRCRSR_TA BIT(12)
|
||||
|
||||
/*
|
||||
* Bit positions of registers that are defined above, in the sysreg.h style
|
||||
* of _MASK for multi bit fields and BIT() for single bits.
|
||||
*/
|
||||
#define TRCIDR0_INSTP0_MASK GENMASK(2, 1)
|
||||
#define TRCIDR0_TRCBB BIT(5)
|
||||
#define TRCIDR0_TRCCOND BIT(6)
|
||||
#define TRCIDR0_TRCCCI BIT(7)
|
||||
#define TRCIDR0_RETSTACK BIT(9)
|
||||
#define TRCIDR0_NUMEVENT_MASK GENMASK(11, 10)
|
||||
#define TRCIDR0_QSUPP_MASK GENMASK(16, 15)
|
||||
#define TRCIDR0_TSSIZE_MASK GENMASK(28, 24)
|
||||
|
||||
#define TRCIDR2_CIDSIZE_MASK GENMASK(9, 5)
|
||||
#define TRCIDR2_VMIDSIZE_MASK GENMASK(14, 10)
|
||||
#define TRCIDR2_CCSIZE_MASK GENMASK(28, 25)
|
||||
|
||||
#define TRCIDR3_CCITMIN_MASK GENMASK(11, 0)
|
||||
#define TRCIDR3_EXLEVEL_S_MASK GENMASK(19, 16)
|
||||
#define TRCIDR3_EXLEVEL_NS_MASK GENMASK(23, 20)
|
||||
#define TRCIDR3_TRCERR BIT(24)
|
||||
#define TRCIDR3_SYNCPR BIT(25)
|
||||
#define TRCIDR3_STALLCTL BIT(26)
|
||||
#define TRCIDR3_SYSSTALL BIT(27)
|
||||
#define TRCIDR3_NUMPROC_LO_MASK GENMASK(30, 28)
|
||||
#define TRCIDR3_NUMPROC_HI_MASK GENMASK(13, 12)
|
||||
#define TRCIDR3_NOOVERFLOW BIT(31)
|
||||
|
||||
#define TRCIDR4_NUMACPAIRS_MASK GENMASK(3, 0)
|
||||
#define TRCIDR4_NUMPC_MASK GENMASK(15, 12)
|
||||
#define TRCIDR4_NUMRSPAIR_MASK GENMASK(19, 16)
|
||||
#define TRCIDR4_NUMSSCC_MASK GENMASK(23, 20)
|
||||
#define TRCIDR4_NUMCIDC_MASK GENMASK(27, 24)
|
||||
#define TRCIDR4_NUMVMIDC_MASK GENMASK(31, 28)
|
||||
|
||||
#define TRCIDR5_NUMEXTIN_MASK GENMASK(8, 0)
|
||||
#define TRCIDR5_TRACEIDSIZE_MASK GENMASK(21, 16)
|
||||
#define TRCIDR5_ATBTRIG BIT(22)
|
||||
#define TRCIDR5_LPOVERRIDE BIT(23)
|
||||
#define TRCIDR5_NUMSEQSTATE_MASK GENMASK(27, 25)
|
||||
#define TRCIDR5_NUMCNTR_MASK GENMASK(30, 28)
|
||||
|
||||
#define TRCCONFIGR_INSTP0_LOAD BIT(1)
|
||||
#define TRCCONFIGR_INSTP0_STORE BIT(2)
|
||||
#define TRCCONFIGR_INSTP0_LOAD_STORE (TRCCONFIGR_INSTP0_LOAD | TRCCONFIGR_INSTP0_STORE)
|
||||
#define TRCCONFIGR_BB BIT(3)
|
||||
#define TRCCONFIGR_CCI BIT(4)
|
||||
#define TRCCONFIGR_CID BIT(6)
|
||||
#define TRCCONFIGR_VMID BIT(7)
|
||||
#define TRCCONFIGR_COND_MASK GENMASK(10, 8)
|
||||
#define TRCCONFIGR_TS BIT(11)
|
||||
#define TRCCONFIGR_RS BIT(12)
|
||||
#define TRCCONFIGR_QE_W_COUNTS BIT(13)
|
||||
#define TRCCONFIGR_QE_WO_COUNTS BIT(14)
|
||||
#define TRCCONFIGR_VMIDOPT BIT(15)
|
||||
#define TRCCONFIGR_DA BIT(16)
|
||||
#define TRCCONFIGR_DV BIT(17)
|
||||
|
||||
#define TRCEVENTCTL1R_INSTEN_MASK GENMASK(3, 0)
|
||||
#define TRCEVENTCTL1R_INSTEN_0 BIT(0)
|
||||
#define TRCEVENTCTL1R_INSTEN_1 BIT(1)
|
||||
#define TRCEVENTCTL1R_INSTEN_2 BIT(2)
|
||||
#define TRCEVENTCTL1R_INSTEN_3 BIT(3)
|
||||
#define TRCEVENTCTL1R_ATB BIT(11)
|
||||
#define TRCEVENTCTL1R_LPOVERRIDE BIT(12)
|
||||
|
||||
#define TRCSTALLCTLR_ISTALL BIT(8)
|
||||
#define TRCSTALLCTLR_INSTPRIORITY BIT(10)
|
||||
#define TRCSTALLCTLR_NOOVERFLOW BIT(13)
|
||||
|
||||
#define TRCVICTLR_EVENT_MASK GENMASK(7, 0)
|
||||
#define TRCVICTLR_SSSTATUS BIT(9)
|
||||
#define TRCVICTLR_TRCRESET BIT(10)
|
||||
#define TRCVICTLR_TRCERR BIT(11)
|
||||
#define TRCVICTLR_EXLEVEL_MASK GENMASK(22, 16)
|
||||
#define TRCVICTLR_EXLEVEL_S_MASK GENMASK(19, 16)
|
||||
#define TRCVICTLR_EXLEVEL_NS_MASK GENMASK(22, 20)
|
||||
|
||||
#define TRCACATRn_TYPE_MASK GENMASK(1, 0)
|
||||
#define TRCACATRn_CONTEXTTYPE_MASK GENMASK(3, 2)
|
||||
#define TRCACATRn_CONTEXTTYPE_CTXID BIT(2)
|
||||
#define TRCACATRn_CONTEXTTYPE_VMID BIT(3)
|
||||
#define TRCACATRn_CONTEXT_MASK GENMASK(6, 4)
|
||||
#define TRCACATRn_EXLEVEL_MASK GENMASK(14, 8)
|
||||
|
||||
#define TRCSSCSRn_STATUS BIT(31)
|
||||
#define TRCSSCCRn_SAC_ARC_RST_MASK GENMASK(24, 0)
|
||||
|
||||
#define TRCSSPCICRn_PC_MASK GENMASK(7, 0)
|
||||
|
||||
#define TRCBBCTLR_MODE BIT(8)
|
||||
#define TRCBBCTLR_RANGE_MASK GENMASK(7, 0)
|
||||
|
||||
#define TRCRSCTLRn_PAIRINV BIT(21)
|
||||
#define TRCRSCTLRn_INV BIT(20)
|
||||
#define TRCRSCTLRn_GROUP_MASK GENMASK(19, 16)
|
||||
#define TRCRSCTLRn_SELECT_MASK GENMASK(15, 0)
|
||||
|
||||
/*
|
||||
* System instructions to access ETM registers.
|
||||
* See ETMv4.4 spec ARM IHI0064F section 4.3.6 System instructions
|
||||
@ -630,23 +728,9 @@
|
||||
#define ETM_EXLEVEL_NS_OS BIT(5) /* NonSecure EL1 */
|
||||
#define ETM_EXLEVEL_NS_HYP BIT(6) /* NonSecure EL2 */
|
||||
|
||||
#define ETM_EXLEVEL_MASK (GENMASK(6, 0))
|
||||
#define ETM_EXLEVEL_S_MASK (GENMASK(3, 0))
|
||||
#define ETM_EXLEVEL_NS_MASK (GENMASK(6, 4))
|
||||
|
||||
/* access level controls in TRCACATRn */
|
||||
#define TRCACATR_EXLEVEL_SHIFT 8
|
||||
|
||||
/* access level control in TRCVICTLR */
|
||||
#define TRCVICTLR_EXLEVEL_SHIFT 16
|
||||
#define TRCVICTLR_EXLEVEL_S_SHIFT 16
|
||||
#define TRCVICTLR_EXLEVEL_NS_SHIFT 20
|
||||
|
||||
/* secure / non secure masks - TRCVICTLR, IDR3 */
|
||||
#define TRCVICTLR_EXLEVEL_MASK (ETM_EXLEVEL_MASK << TRCVICTLR_EXLEVEL_SHIFT)
|
||||
#define TRCVICTLR_EXLEVEL_S_MASK (ETM_EXLEVEL_S_MASK << TRCVICTLR_EXLEVEL_SHIFT)
|
||||
#define TRCVICTLR_EXLEVEL_NS_MASK (ETM_EXLEVEL_NS_MASK << TRCVICTLR_EXLEVEL_SHIFT)
|
||||
|
||||
#define ETM_TRCIDR1_ARCH_MAJOR_SHIFT 8
|
||||
#define ETM_TRCIDR1_ARCH_MAJOR_MASK (0xfU << ETM_TRCIDR1_ARCH_MAJOR_SHIFT)
|
||||
#define ETM_TRCIDR1_ARCH_MAJOR(x) \
|
||||
@ -986,10 +1070,10 @@ struct etmv4_drvdata {
|
||||
|
||||
/* Address comparator access types */
|
||||
enum etm_addr_acctype {
|
||||
ETM_INSTR_ADDR,
|
||||
ETM_DATA_LOAD_ADDR,
|
||||
ETM_DATA_STORE_ADDR,
|
||||
ETM_DATA_LOAD_STORE_ADDR,
|
||||
TRCACATRn_TYPE_ADDR,
|
||||
TRCACATRn_TYPE_DATA_LOAD_ADDR,
|
||||
TRCACATRn_TYPE_DATA_STORE_ADDR,
|
||||
TRCACATRn_TYPE_DATA_LOAD_STORE_ADDR,
|
||||
};
|
||||
|
||||
/* Address comparator context types */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user