coresight: Updates for Linux v6.8
Updates for the hwtracing subsystem includes : - Support for CoreSight TPDM DSB set - Support for tuning Cycle count Threshold for CoreSight ETM via perf - Support for TRBE on ACPI based systems - Support for choosing buffer mode in ETR for sysfs mode - Improvements to HiSilicon PTT driver - Cleanups to Ultrasoc SMB driver - Cleanup .remove callback for various Coresight platform drivers - Remove Leo Yan from Reviewers Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuFy0byloRoXZHaWBxcXRZPKyBqEFAmV4SmsACgkQxcXRZPKy BqHDHg//UvrXrMpTKXSfuFsb4/UtvT53sBh/pULgdV4hNNF3r3Kp2Ktko/n9ftXu OK8LmaKlQvchbc1NLD8mI7lW2xIRoK3Sax4WKyHFU0Wwh2a8cnAnEmip2z5YjuY1 7UlmY/+SIGTXgtx7P4YUJ0O2FoQwp/7yGAvc0n7xlwFpucuGIpawVsEkviA7OKWo fMEnkdYppqWEQE4r4eN9TTV8mVFPj669aWBmi5lTFX0C0eaX24eJ/yj+fNKcoqWZ HVxhrPK21KcUd9r9FRuavq5GPZXz1DscdkfwwCvNfUMMbkwf3dPLszN4aBF9cWjN mb0YJL2AgjzDawJtPow95tikCpn8jW+Bgd9djEtdw3KwT03K7wjk7clQ79oeobpF ry2bY40V+IMHmQoVK6vXPLQu6HPwn1wcOrAWNNQGVPS18I1FdHnt0wpIcl2uui+W E9vZ6u9WHxToj5TgL9Uobq8hL6HWChJ3Z8uT7wAN35q0JrpvqwvJaZro3g4knMzE YQttPzDKb+VpLh6ZwWNL4p2Y93K4MCITdYouZdGTmYquUKbQgixq7B8WI4qALJML RUlWfGfWTy1mqmQrnvSG23QWcfMqpQLaC/a/gDYjKgFvT84BXcKXYYIcpkbb7+/7 9SigQroz2uq+SgdRjdc2bU1QQ/4LN9XfpgKaLDzdChNLpH6DKO8= =7+gH -----END PGP SIGNATURE----- Merge tag 'coresight-next-v6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux into char-misc-next Suzuki writes: coresight: Updates for Linux v6.8 Updates for the hwtracing subsystem includes : - Support for CoreSight TPDM DSB set - Support for tuning Cycle count Threshold for CoreSight ETM via perf - Support for TRBE on ACPI based systems - Support for choosing buffer mode in ETR for sysfs mode - Improvements to HiSilicon PTT driver - Cleanups to Ultrasoc SMB driver - Cleanup .remove callback for various Coresight platform drivers - Remove Leo Yan from Reviewers Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> * tag 'coresight-next-v6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux: (32 commits) coresight: ultrasoc-smb: Use guards to cleanup coresight: ultrasoc-smb: Convert to platform remove callback returning void coresight: trbe: Convert to platform remove callback returning void coresight: replicator: Convert to platform remove callback returning void coresight: funnel: Convert to platform remove callback returning void coresight: etm4x: Convert to platform remove callback returning void coresight: dummy: Convert to platform remove callback returning void coresight: etm4x: Fix width of CCITMIN field coresight-tpdm: Correct the property name of MSR number hwtracing: hisi_ptt: Optimize the trace data committing hwtracing: hisi_ptt: Disable interrupt after trace end Documentation: ABI: coresight-tpdm: Fix Bit[3] description indentation coresight-tpdm: Add nodes for dsb msr support dt-bindings: arm: Add support for DSB MSR register coresight-tpdm: Add nodes for timestamp request coresight-tpdm: Add nodes to configure pattern match output coresight-tpdm: Add nodes for dsb edge control coresight-tpdm: Add node to set dsb programming mode coresight-tpdm: Add nodes to set trigger timestamp and type coresight-tpdm: Add reset node to TPDM node ...
This commit is contained in:
commit
e909abe885
@ -91,3 +91,19 @@ Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
|
||||
Description: (RW) Size of the trace buffer for TMC-ETR when used in SYSFS
|
||||
mode. Writable only for TMC-ETR configurations. The value
|
||||
should be aligned to the kernel pagesize.
|
||||
|
||||
What: /sys/bus/coresight/devices/<memory_map>.tmc/buf_modes_available
|
||||
Date: August 2023
|
||||
KernelVersion: 6.7
|
||||
Contact: Anshuman Khandual <anshuman.khandual@arm.com>
|
||||
Description: (Read) Shows all supported Coresight TMC-ETR buffer modes available
|
||||
for the users to configure explicitly. This file is avaialble only
|
||||
for TMC ETR devices.
|
||||
|
||||
What: /sys/bus/coresight/devices/<memory_map>.tmc/buf_mode_preferred
|
||||
Date: August 2023
|
||||
KernelVersion: 6.7
|
||||
Contact: Anshuman Khandual <anshuman.khandual@arm.com>
|
||||
Description: (RW) Current Coresight TMC-ETR buffer mode selected. But user could
|
||||
only provide a mode which is supported for a given ETR device. This
|
||||
file is available only for TMC ETR devices.
|
||||
|
@ -11,3 +11,162 @@ Description:
|
||||
Accepts only one of the 2 values - 1 or 2.
|
||||
1 : Generate 64 bits data
|
||||
2 : Generate 32 bits data
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/reset_dataset
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(Write) Reset the dataset of the tpdm.
|
||||
|
||||
Accepts only one value - 1.
|
||||
1 : Reset the dataset of the tpdm
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_trig_type
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the trigger type of the DSB for tpdm.
|
||||
|
||||
Accepts only one of the 2 values - 0 or 1.
|
||||
0 : Set the DSB trigger type to false
|
||||
1 : Set the DSB trigger type to true
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_trig_ts
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the trigger timestamp of the DSB for tpdm.
|
||||
|
||||
Accepts only one of the 2 values - 0 or 1.
|
||||
0 : Set the DSB trigger type to false
|
||||
1 : Set the DSB trigger type to true
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_mode
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the programming mode of the DSB for tpdm.
|
||||
|
||||
Accepts the value needs to be greater than 0. What data
|
||||
bits do is listed below.
|
||||
Bit[0:1] : Test mode control bit for choosing the inputs.
|
||||
Bit[3] : Set to 0 for low performance mode. Set to 1 for high
|
||||
performance mode.
|
||||
Bit[4:8] : Select byte lane for high performance mode.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/ctrl_idx
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the index number of the edge detection for the DSB
|
||||
subunit TPDM. Since there are at most 256 edge detections, this
|
||||
value ranges from 0 to 255.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/ctrl_val
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
Write a data to control the edge detection corresponding to
|
||||
the index number. Before writing data to this sysfs file,
|
||||
"ctrl_idx" should be written first to configure the index
|
||||
number of the edge detection which needs to be controlled.
|
||||
|
||||
Accepts only one of the following values.
|
||||
0 - Rising edge detection
|
||||
1 - Falling edge detection
|
||||
2 - Rising and falling edge detection (toggle detection)
|
||||
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/ctrl_mask
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
Write a data to mask the edge detection corresponding to the index
|
||||
number. Before writing data to this sysfs file, "ctrl_idx" should
|
||||
be written first to configure the index number of the edge detection
|
||||
which needs to be masked.
|
||||
|
||||
Accepts only one of the 2 values - 0 or 1.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/edcr[0:15]
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
Read a set of the edge control value of the DSB in TPDM.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/edcmr[0:7]
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
Read a set of the edge control mask of the DSB in TPDM.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_trig_patt/xpr[0:7]
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the value of the trigger pattern for the DSB
|
||||
subunit TPDM.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_trig_patt/xpmr[0:7]
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the mask of the trigger pattern for the DSB
|
||||
subunit TPDM.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/tpr[0:7]
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the value of the pattern for the DSB subunit TPDM.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/tpmr[0:7]
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the mask of the pattern for the DSB subunit TPDM.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/enable_ts
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(Write) Set the pattern timestamp of DSB tpdm. Read
|
||||
the pattern timestamp of DSB tpdm.
|
||||
|
||||
Accepts only one of the 2 values - 0 or 1.
|
||||
0 : Disable DSB pattern timestamp.
|
||||
1 : Enable DSB pattern timestamp.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/set_type
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(Write) Set the pattern type of DSB tpdm. Read
|
||||
the pattern type of DSB tpdm.
|
||||
|
||||
Accepts only one of the 2 values - 0 or 1.
|
||||
0 : Set the DSB pattern type to value.
|
||||
1 : Set the DSB pattern type to toggle.
|
||||
|
||||
What: /sys/bus/coresight/devices/<tpdm-name>/dsb_msr/msr[0:31]
|
||||
Date: March 2023
|
||||
KernelVersion 6.7
|
||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||
Description:
|
||||
(RW) Set/Get the MSR(mux select register) for the DSB subunit
|
||||
TPDM.
|
||||
|
@ -117,6 +117,10 @@ stable kernels.
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A76 | #1463225 | ARM64_ERRATUM_1463225 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A76 | #1490853 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A77 | #1491015 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A77 | #1508412 | ARM64_ERRATUM_1508412 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A710 | #2119858 | ARM64_ERRATUM_2119858 |
|
||||
@ -127,6 +131,8 @@ stable kernels.
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A715 | #2645198 | ARM64_ERRATUM_2645198 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X1 | #1502854 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X2 | #2119858 | ARM64_ERRATUM_2119858 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X2 | #2224489 | ARM64_ERRATUM_2224489 |
|
||||
@ -135,6 +141,8 @@ stable kernels.
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-N1 | #1349291 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-N1 | #1490853 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-N1 | #1542419 | ARM64_ERRATUM_1542419 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-N2 | #2139208 | ARM64_ERRATUM_2139208 |
|
||||
@ -143,6 +151,8 @@ stable kernels.
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-N2 | #2253138 | ARM64_ERRATUM_2253138 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-V1 | #1619801 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | MMU-500 | #841119,826419 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | MMU-600 | #1076982,1209401| N/A |
|
||||
|
@ -44,6 +44,23 @@ properties:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
qcom,dsb-element-size:
|
||||
description:
|
||||
Specifies the DSB(Discrete Single Bit) element size supported by
|
||||
the monitor. The associated aggregator will read this size before it
|
||||
is enabled. DSB element size currently only supports 32-bit and 64-bit.
|
||||
$ref: /schemas/types.yaml#/definitions/uint8
|
||||
enum: [32, 64]
|
||||
|
||||
qcom,dsb-msrs-num:
|
||||
description:
|
||||
Specifies the number of DSB(Discrete Single Bit) MSR(mux select register)
|
||||
registers supported by the monitor. If this property is not configured
|
||||
or set to 0, it means this DSB TPDM doesn't support MSR.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 32
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
@ -77,6 +94,9 @@ examples:
|
||||
compatible = "qcom,coresight-tpdm", "arm,primecell";
|
||||
reg = <0x0684c000 0x1000>;
|
||||
|
||||
qcom,dsb-element-size = /bits/ 8 <32>;
|
||||
qcom,dsb-msrs-num = <16>;
|
||||
|
||||
clocks = <&aoss_qmp>;
|
||||
clock-names = "apb_pclk";
|
||||
|
||||
|
@ -624,6 +624,10 @@ They are also listed in the folder /sys/bus/event_source/devices/cs_etm/format/
|
||||
* - timestamp
|
||||
- Session local version of the system wide setting: :ref:`ETMv4_MODE_TIMESTAMP
|
||||
<coresight-timestamp>`
|
||||
* - cc_threshold
|
||||
- Cycle count threshold value. If nothing is provided here or the provided value is 0, then the
|
||||
default value i.e 0x100 will be used. If provided value is less than minimum cycles threshold
|
||||
value, as indicated via TRCIDR3.CCITMIN, then the minimum value will be used instead.
|
||||
|
||||
How to use the STM module
|
||||
-------------------------
|
||||
|
@ -2051,7 +2051,6 @@ ARM/CORESIGHT FRAMEWORK AND DRIVERS
|
||||
M: Suzuki K Poulose <suzuki.poulose@arm.com>
|
||||
R: Mike Leach <mike.leach@linaro.org>
|
||||
R: James Clark <james.clark@arm.com>
|
||||
R: Leo Yan <leo.yan@linaro.org>
|
||||
L: coresight@lists.linaro.org (moderated for non-subscribers)
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
|
@ -1093,6 +1093,7 @@ static int coresight_validate_source(struct coresight_device *csdev,
|
||||
|
||||
if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC &&
|
||||
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE &&
|
||||
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM &&
|
||||
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) {
|
||||
dev_err(&csdev->dev, "wrong device subtype in %s\n", function);
|
||||
return -EINVAL;
|
||||
@ -1162,6 +1163,7 @@ int coresight_enable(struct coresight_device *csdev)
|
||||
per_cpu(tracer_path, cpu) = path;
|
||||
break;
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
|
||||
/*
|
||||
* Use the hash of source's device name as ID
|
||||
@ -1212,6 +1214,7 @@ void coresight_disable(struct coresight_device *csdev)
|
||||
per_cpu(tracer_path, cpu) = NULL;
|
||||
break;
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
|
||||
case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
|
||||
hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
|
||||
/* Find the path by the hash. */
|
||||
|
@ -122,14 +122,13 @@ static int dummy_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dummy_remove(struct platform_device *pdev)
|
||||
static void dummy_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dummy_drvdata *drvdata = platform_get_drvdata(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
coresight_unregister(drvdata->csdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id dummy_match[] = {
|
||||
@ -140,7 +139,7 @@ static const struct of_device_id dummy_match[] = {
|
||||
|
||||
static struct platform_driver dummy_driver = {
|
||||
.probe = dummy_probe,
|
||||
.remove = dummy_remove,
|
||||
.remove_new = dummy_remove,
|
||||
.driver = {
|
||||
.name = "coresight-dummy",
|
||||
.of_match_table = dummy_match,
|
||||
|
@ -68,6 +68,7 @@ PMU_FORMAT_ATTR(preset, "config:0-3");
|
||||
PMU_FORMAT_ATTR(sinkid, "config2:0-31");
|
||||
/* config ID - set if a system configuration is selected */
|
||||
PMU_FORMAT_ATTR(configid, "config2:32-63");
|
||||
PMU_FORMAT_ATTR(cc_threshold, "config3:0-11");
|
||||
|
||||
|
||||
/*
|
||||
@ -101,6 +102,7 @@ static struct attribute *etm_config_formats_attr[] = {
|
||||
&format_attr_preset.attr,
|
||||
&format_attr_configid.attr,
|
||||
&format_attr_branch_broadcast.attr,
|
||||
&format_attr_cc_threshold.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -644,7 +644,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
|
||||
struct etmv4_config *config = &drvdata->config;
|
||||
struct perf_event_attr *attr = &event->attr;
|
||||
unsigned long cfg_hash;
|
||||
int preset;
|
||||
int preset, cc_threshold;
|
||||
|
||||
/* Clear configuration from previous run */
|
||||
memset(config, 0, sizeof(struct etmv4_config));
|
||||
@ -667,7 +667,12 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
|
||||
if (attr->config & BIT(ETM_OPT_CYCACC)) {
|
||||
config->cfg |= TRCCONFIGR_CCI;
|
||||
/* TRM: Must program this for cycacc to work */
|
||||
config->ccctlr = ETM_CYC_THRESHOLD_DEFAULT;
|
||||
cc_threshold = attr->config3 & ETM_CYC_THRESHOLD_MASK;
|
||||
if (!cc_threshold)
|
||||
cc_threshold = ETM_CYC_THRESHOLD_DEFAULT;
|
||||
if (cc_threshold < drvdata->ccitmin)
|
||||
cc_threshold = drvdata->ccitmin;
|
||||
config->ccctlr = cc_threshold;
|
||||
}
|
||||
if (attr->config & BIT(ETM_OPT_TS)) {
|
||||
/*
|
||||
@ -1150,6 +1155,41 @@ static void cpu_detect_trace_filtering(struct etmv4_drvdata *drvdata)
|
||||
drvdata->trfcr = trfcr;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following errata on applicable cpu ranges, affect the CCITMIN filed
|
||||
* in TCRIDR3 register. Software read for the field returns 0x100 limiting
|
||||
* the cycle threshold granularity, whereas the right value should have
|
||||
* been 0x4, which is well supported in the hardware.
|
||||
*/
|
||||
static struct midr_range etm_wrong_ccitmin_cpus[] = {
|
||||
/* Erratum #1490853 - Cortex-A76 */
|
||||
MIDR_RANGE(MIDR_CORTEX_A76, 0, 0, 4, 0),
|
||||
/* Erratum #1490853 - Neoverse-N1 */
|
||||
MIDR_RANGE(MIDR_NEOVERSE_N1, 0, 0, 4, 0),
|
||||
/* Erratum #1491015 - Cortex-A77 */
|
||||
MIDR_RANGE(MIDR_CORTEX_A77, 0, 0, 1, 0),
|
||||
/* Erratum #1502854 - Cortex-X1 */
|
||||
MIDR_REV(MIDR_CORTEX_X1, 0, 0),
|
||||
/* Erratum #1619801 - Neoverse-V1 */
|
||||
MIDR_REV(MIDR_NEOVERSE_V1, 0, 0),
|
||||
{},
|
||||
};
|
||||
|
||||
static void etm4_fixup_wrong_ccitmin(struct etmv4_drvdata *drvdata)
|
||||
{
|
||||
/*
|
||||
* Erratum affected cpus will read 256 as the minimum
|
||||
* instruction trace cycle counting threshold whereas
|
||||
* the correct value should be 4 instead. Override the
|
||||
* recorded value for 'drvdata->ccitmin' to workaround
|
||||
* this problem.
|
||||
*/
|
||||
if (is_midr_in_range_list(read_cpuid_id(), etm_wrong_ccitmin_cpus)) {
|
||||
if (drvdata->ccitmin == 256)
|
||||
drvdata->ccitmin = 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void etm4_init_arch_data(void *info)
|
||||
{
|
||||
u32 etmidr0;
|
||||
@ -1214,6 +1254,8 @@ static void etm4_init_arch_data(void *info)
|
||||
etmidr3 = etm4x_relaxed_read32(csa, TRCIDR3);
|
||||
/* CCITMIN, bits[11:0] minimum threshold value that can be programmed */
|
||||
drvdata->ccitmin = FIELD_GET(TRCIDR3_CCITMIN_MASK, etmidr3);
|
||||
etm4_fixup_wrong_ccitmin(drvdata);
|
||||
|
||||
/* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
|
||||
drvdata->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
|
||||
drvdata->config.s_ex_level = drvdata->s_ex_level;
|
||||
@ -2261,7 +2303,7 @@ static void etm4_remove_amba(struct amba_device *adev)
|
||||
etm4_remove_dev(drvdata);
|
||||
}
|
||||
|
||||
static int etm4_remove_platform_dev(struct platform_device *pdev)
|
||||
static void etm4_remove_platform_dev(struct platform_device *pdev)
|
||||
{
|
||||
struct etmv4_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
@ -2271,8 +2313,6 @@ static int etm4_remove_platform_dev(struct platform_device *pdev)
|
||||
|
||||
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||
clk_put(drvdata->pclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct amba_id etm4_ids[] = {
|
||||
@ -2358,7 +2398,7 @@ MODULE_DEVICE_TABLE(acpi, etm4x_acpi_ids);
|
||||
|
||||
static struct platform_driver etm4_platform_driver = {
|
||||
.probe = etm4_probe_platform_dev,
|
||||
.remove = etm4_remove_platform_dev,
|
||||
.remove_new = etm4_remove_platform_dev,
|
||||
.driver = {
|
||||
.name = "coresight-etm4x",
|
||||
.of_match_table = etm4_sysreg_match,
|
||||
|
@ -1036,7 +1036,7 @@ struct etmv4_drvdata {
|
||||
u8 ctxid_size;
|
||||
u8 vmid_size;
|
||||
u8 ccsize;
|
||||
u8 ccitmin;
|
||||
u16 ccitmin;
|
||||
u8 s_ex_level;
|
||||
u8 ns_ex_level;
|
||||
u8 q_support;
|
||||
|
@ -335,11 +335,10 @@ static int static_funnel_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int static_funnel_remove(struct platform_device *pdev)
|
||||
static void static_funnel_remove(struct platform_device *pdev)
|
||||
{
|
||||
funnel_remove(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id static_funnel_match[] = {
|
||||
@ -360,7 +359,7 @@ MODULE_DEVICE_TABLE(acpi, static_funnel_ids);
|
||||
|
||||
static struct platform_driver static_funnel_driver = {
|
||||
.probe = static_funnel_probe,
|
||||
.remove = static_funnel_remove,
|
||||
.remove_new = static_funnel_remove,
|
||||
.driver = {
|
||||
.name = "coresight-static-funnel",
|
||||
/* THIS_MODULE is taken care of by platform_driver_register() */
|
||||
|
@ -320,11 +320,10 @@ static int static_replicator_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int static_replicator_remove(struct platform_device *pdev)
|
||||
static void static_replicator_remove(struct platform_device *pdev)
|
||||
{
|
||||
replicator_remove(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
@ -373,7 +372,7 @@ MODULE_DEVICE_TABLE(acpi, static_replicator_acpi_ids);
|
||||
|
||||
static struct platform_driver static_replicator_driver = {
|
||||
.probe = static_replicator_probe,
|
||||
.remove = static_replicator_remove,
|
||||
.remove_new = static_replicator_remove,
|
||||
.driver = {
|
||||
.name = "coresight-static-replicator",
|
||||
/* THIS_MODULE is taken care of by platform_driver_register() */
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
@ -344,7 +345,14 @@ static const struct attribute_group coresight_tmc_mgmt_group = {
|
||||
.name = "mgmt",
|
||||
};
|
||||
|
||||
static const struct attribute_group *coresight_tmc_groups[] = {
|
||||
static const struct attribute_group *coresight_etf_groups[] = {
|
||||
&coresight_tmc_group,
|
||||
&coresight_tmc_mgmt_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group *coresight_etr_groups[] = {
|
||||
&coresight_etr_group,
|
||||
&coresight_tmc_group,
|
||||
&coresight_tmc_mgmt_group,
|
||||
NULL,
|
||||
@ -465,6 +473,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
drvdata->memwidth = tmc_get_memwidth(devid);
|
||||
/* This device is not associated with a session */
|
||||
drvdata->pid = -1;
|
||||
drvdata->etr_mode = ETR_MODE_AUTO;
|
||||
|
||||
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
|
||||
drvdata->size = tmc_etr_get_default_buffer_size(dev);
|
||||
@ -474,16 +483,17 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
}
|
||||
|
||||
desc.dev = dev;
|
||||
desc.groups = coresight_tmc_groups;
|
||||
|
||||
switch (drvdata->config_type) {
|
||||
case TMC_CONFIG_TYPE_ETB:
|
||||
desc.groups = coresight_etf_groups;
|
||||
desc.type = CORESIGHT_DEV_TYPE_SINK;
|
||||
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
|
||||
desc.ops = &tmc_etb_cs_ops;
|
||||
dev_list = &etb_devs;
|
||||
break;
|
||||
case TMC_CONFIG_TYPE_ETR:
|
||||
desc.groups = coresight_etr_groups;
|
||||
desc.type = CORESIGHT_DEV_TYPE_SINK;
|
||||
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM;
|
||||
desc.ops = &tmc_etr_cs_ops;
|
||||
@ -496,6 +506,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
dev_list = &etr_devs;
|
||||
break;
|
||||
case TMC_CONFIG_TYPE_ETF:
|
||||
desc.groups = coresight_etf_groups;
|
||||
desc.type = CORESIGHT_DEV_TYPE_LINKSINK;
|
||||
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
|
||||
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
|
||||
|
@ -26,6 +26,12 @@ struct etr_flat_buf {
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct etr_buf_hw {
|
||||
bool has_iommu;
|
||||
bool has_etr_sg;
|
||||
bool has_catu;
|
||||
};
|
||||
|
||||
/*
|
||||
* etr_perf_buffer - Perf buffer used for ETR
|
||||
* @drvdata - The ETR drvdaga this buffer has been allocated for.
|
||||
@ -830,6 +836,22 @@ static inline int tmc_etr_mode_alloc_buf(int mode,
|
||||
}
|
||||
}
|
||||
|
||||
static void get_etr_buf_hw(struct device *dev, struct etr_buf_hw *buf_hw)
|
||||
{
|
||||
struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
buf_hw->has_iommu = iommu_get_domain_for_dev(dev->parent);
|
||||
buf_hw->has_etr_sg = tmc_etr_has_cap(drvdata, TMC_ETR_SG);
|
||||
buf_hw->has_catu = !!tmc_etr_get_catu_device(drvdata);
|
||||
}
|
||||
|
||||
static bool etr_can_use_flat_mode(struct etr_buf_hw *buf_hw, ssize_t etr_buf_size)
|
||||
{
|
||||
bool has_sg = buf_hw->has_catu || buf_hw->has_etr_sg;
|
||||
|
||||
return !has_sg || buf_hw->has_iommu || etr_buf_size < SZ_1M;
|
||||
}
|
||||
|
||||
/*
|
||||
* tmc_alloc_etr_buf: Allocate a buffer use by ETR.
|
||||
* @drvdata : ETR device details.
|
||||
@ -843,23 +865,22 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata,
|
||||
int node, void **pages)
|
||||
{
|
||||
int rc = -ENOMEM;
|
||||
bool has_etr_sg, has_iommu;
|
||||
bool has_sg, has_catu;
|
||||
struct etr_buf *etr_buf;
|
||||
struct etr_buf_hw buf_hw;
|
||||
struct device *dev = &drvdata->csdev->dev;
|
||||
|
||||
has_etr_sg = tmc_etr_has_cap(drvdata, TMC_ETR_SG);
|
||||
has_iommu = iommu_get_domain_for_dev(dev->parent);
|
||||
has_catu = !!tmc_etr_get_catu_device(drvdata);
|
||||
|
||||
has_sg = has_catu || has_etr_sg;
|
||||
|
||||
get_etr_buf_hw(dev, &buf_hw);
|
||||
etr_buf = kzalloc(sizeof(*etr_buf), GFP_KERNEL);
|
||||
if (!etr_buf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
etr_buf->size = size;
|
||||
|
||||
/* If there is user directive for buffer mode, try that first */
|
||||
if (drvdata->etr_mode != ETR_MODE_AUTO)
|
||||
rc = tmc_etr_mode_alloc_buf(drvdata->etr_mode, drvdata,
|
||||
etr_buf, node, pages);
|
||||
|
||||
/*
|
||||
* If we have to use an existing list of pages, we cannot reliably
|
||||
* use a contiguous DMA memory (even if we have an IOMMU). Otherwise,
|
||||
@ -872,14 +893,13 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata,
|
||||
* Fallback to available mechanisms.
|
||||
*
|
||||
*/
|
||||
if (!pages &&
|
||||
(!has_sg || has_iommu || size < SZ_1M))
|
||||
if (rc && !pages && etr_can_use_flat_mode(&buf_hw, size))
|
||||
rc = tmc_etr_mode_alloc_buf(ETR_MODE_FLAT, drvdata,
|
||||
etr_buf, node, pages);
|
||||
if (rc && has_etr_sg)
|
||||
if (rc && buf_hw.has_etr_sg)
|
||||
rc = tmc_etr_mode_alloc_buf(ETR_MODE_ETR_SG, drvdata,
|
||||
etr_buf, node, pages);
|
||||
if (rc && has_catu)
|
||||
if (rc && buf_hw.has_catu)
|
||||
rc = tmc_etr_mode_alloc_buf(ETR_MODE_CATU, drvdata,
|
||||
etr_buf, node, pages);
|
||||
if (rc) {
|
||||
@ -1804,3 +1824,70 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *const buf_modes_str[] = {
|
||||
[ETR_MODE_FLAT] = "flat",
|
||||
[ETR_MODE_ETR_SG] = "tmc-sg",
|
||||
[ETR_MODE_CATU] = "catu",
|
||||
[ETR_MODE_AUTO] = "auto",
|
||||
};
|
||||
|
||||
static ssize_t buf_modes_available_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct etr_buf_hw buf_hw;
|
||||
ssize_t size = 0;
|
||||
|
||||
get_etr_buf_hw(dev, &buf_hw);
|
||||
size += sysfs_emit(buf, "%s ", buf_modes_str[ETR_MODE_AUTO]);
|
||||
size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_FLAT]);
|
||||
if (buf_hw.has_etr_sg)
|
||||
size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_ETR_SG]);
|
||||
|
||||
if (buf_hw.has_catu)
|
||||
size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_CATU]);
|
||||
|
||||
size += sysfs_emit_at(buf, size, "\n");
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RO(buf_modes_available);
|
||||
|
||||
static ssize_t buf_mode_preferred_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
return sysfs_emit(buf, "%s\n", buf_modes_str[drvdata->etr_mode]);
|
||||
}
|
||||
|
||||
static ssize_t buf_mode_preferred_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
struct etr_buf_hw buf_hw;
|
||||
|
||||
get_etr_buf_hw(dev, &buf_hw);
|
||||
if (sysfs_streq(buf, buf_modes_str[ETR_MODE_FLAT]))
|
||||
drvdata->etr_mode = ETR_MODE_FLAT;
|
||||
else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_ETR_SG]) && buf_hw.has_etr_sg)
|
||||
drvdata->etr_mode = ETR_MODE_ETR_SG;
|
||||
else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_CATU]) && buf_hw.has_catu)
|
||||
drvdata->etr_mode = ETR_MODE_CATU;
|
||||
else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_AUTO]))
|
||||
drvdata->etr_mode = ETR_MODE_AUTO;
|
||||
else
|
||||
return -EINVAL;
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(buf_mode_preferred);
|
||||
|
||||
static struct attribute *coresight_etr_attrs[] = {
|
||||
&dev_attr_buf_modes_available.attr,
|
||||
&dev_attr_buf_mode_preferred.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
const struct attribute_group coresight_etr_group = {
|
||||
.attrs = coresight_etr_attrs,
|
||||
};
|
||||
|
@ -135,6 +135,7 @@ enum etr_mode {
|
||||
ETR_MODE_FLAT, /* Uses contiguous flat buffer */
|
||||
ETR_MODE_ETR_SG, /* Uses in-built TMC ETR SG mechanism */
|
||||
ETR_MODE_CATU, /* Use SG mechanism in CATU */
|
||||
ETR_MODE_AUTO, /* Use the default mechanism */
|
||||
};
|
||||
|
||||
struct etr_buf_operations;
|
||||
@ -207,6 +208,7 @@ struct tmc_drvdata {
|
||||
enum tmc_mem_intf_width memwidth;
|
||||
u32 trigger_cntr;
|
||||
u32 etr_caps;
|
||||
enum etr_mode etr_mode;
|
||||
struct idr idr;
|
||||
struct mutex idr_mutex;
|
||||
struct etr_buf *sysfs_buf;
|
||||
@ -334,5 +336,6 @@ void tmc_etr_set_catu_ops(const struct etr_buf_operations *catu);
|
||||
void tmc_etr_remove_catu_ops(void);
|
||||
struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
|
||||
enum cs_mode mode, void *data);
|
||||
extern const struct attribute_group coresight_etr_group;
|
||||
|
||||
#endif
|
||||
|
@ -21,6 +21,80 @@
|
||||
|
||||
DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda");
|
||||
|
||||
static bool coresight_device_is_tpdm(struct coresight_device *csdev)
|
||||
{
|
||||
return (csdev->type == CORESIGHT_DEV_TYPE_SOURCE) &&
|
||||
(csdev->subtype.source_subtype ==
|
||||
CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the DSB element size from the TPDM device
|
||||
* Returns
|
||||
* The dsb element size read from the devicetree if available.
|
||||
* 0 - Otherwise, with a warning once.
|
||||
*/
|
||||
static int tpdm_read_dsb_element_size(struct coresight_device *csdev)
|
||||
{
|
||||
int rc = 0;
|
||||
u8 size = 0;
|
||||
|
||||
rc = fwnode_property_read_u8(dev_fwnode(csdev->dev.parent),
|
||||
"qcom,dsb-element-size", &size);
|
||||
if (rc)
|
||||
dev_warn_once(&csdev->dev,
|
||||
"Failed to read TPDM DSB Element size: %d\n", rc);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search and read element data size from the TPDM node in
|
||||
* the devicetree. Each input port of TPDA is connected to
|
||||
* a TPDM. Different TPDM supports different types of dataset,
|
||||
* and some may support more than one type of dataset.
|
||||
* Parameter "inport" is used to pass in the input port number
|
||||
* of TPDA, and it is set to -1 in the recursize call.
|
||||
*/
|
||||
static int tpda_get_element_size(struct coresight_device *csdev,
|
||||
int inport)
|
||||
{
|
||||
int dsb_size = -ENOENT;
|
||||
int i, size;
|
||||
struct coresight_device *in;
|
||||
|
||||
for (i = 0; i < csdev->pdata->nr_inconns; i++) {
|
||||
in = csdev->pdata->in_conns[i]->src_dev;
|
||||
if (!in)
|
||||
continue;
|
||||
|
||||
/* Ignore the paths that do not match port */
|
||||
if (inport > 0 &&
|
||||
csdev->pdata->in_conns[i]->dest_port != inport)
|
||||
continue;
|
||||
|
||||
if (coresight_device_is_tpdm(in)) {
|
||||
size = tpdm_read_dsb_element_size(in);
|
||||
} else {
|
||||
/* Recurse down the path */
|
||||
size = tpda_get_element_size(in, -1);
|
||||
}
|
||||
|
||||
if (size < 0)
|
||||
return size;
|
||||
|
||||
if (dsb_size < 0) {
|
||||
/* Found a size, save it. */
|
||||
dsb_size = size;
|
||||
} else {
|
||||
/* Found duplicate TPDMs */
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
return dsb_size;
|
||||
}
|
||||
|
||||
/* Settings pre enabling port control register */
|
||||
static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
|
||||
{
|
||||
@ -32,26 +106,55 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
|
||||
writel_relaxed(val, drvdata->base + TPDA_CR);
|
||||
}
|
||||
|
||||
static void tpda_enable_port(struct tpda_drvdata *drvdata, int port)
|
||||
static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
|
||||
{
|
||||
u32 val;
|
||||
int size;
|
||||
|
||||
val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port));
|
||||
/*
|
||||
* Configure aggregator port n DSB data set element size
|
||||
* Set the bit to 0 if the size is 32
|
||||
* Set the bit to 1 if the size is 64
|
||||
*/
|
||||
size = tpda_get_element_size(drvdata->csdev, port);
|
||||
switch (size) {
|
||||
case 32:
|
||||
val &= ~TPDA_Pn_CR_DSBSIZE;
|
||||
break;
|
||||
case 64:
|
||||
val |= TPDA_Pn_CR_DSBSIZE;
|
||||
break;
|
||||
case 0:
|
||||
return -EEXIST;
|
||||
case -EEXIST:
|
||||
dev_warn_once(&drvdata->csdev->dev,
|
||||
"Detected multiple TPDMs on port %d", -EEXIST);
|
||||
return -EEXIST;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Enable the port */
|
||||
val |= TPDA_Pn_CR_ENA;
|
||||
writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __tpda_enable(struct tpda_drvdata *drvdata, int port)
|
||||
static int __tpda_enable(struct tpda_drvdata *drvdata, int port)
|
||||
{
|
||||
int ret;
|
||||
|
||||
CS_UNLOCK(drvdata->base);
|
||||
|
||||
if (!drvdata->csdev->enable)
|
||||
tpda_enable_pre_port(drvdata);
|
||||
|
||||
tpda_enable_port(drvdata, port);
|
||||
|
||||
ret = tpda_enable_port(drvdata, port);
|
||||
CS_LOCK(drvdata->base);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tpda_enable(struct coresight_device *csdev,
|
||||
@ -59,16 +162,19 @@ static int tpda_enable(struct coresight_device *csdev,
|
||||
struct coresight_connection *out)
|
||||
{
|
||||
struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
int ret = 0;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
if (atomic_read(&in->dest_refcnt) == 0)
|
||||
__tpda_enable(drvdata, in->dest_port);
|
||||
if (atomic_read(&in->dest_refcnt) == 0) {
|
||||
ret = __tpda_enable(drvdata, in->dest_port);
|
||||
if (!ret) {
|
||||
atomic_inc(&in->dest_refcnt);
|
||||
dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
|
||||
}
|
||||
}
|
||||
|
||||
atomic_inc(&in->dest_refcnt);
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __tpda_disable(struct tpda_drvdata *drvdata, int port)
|
||||
|
@ -10,6 +10,8 @@
|
||||
#define TPDA_Pn_CR(n) (0x004 + (n * 4))
|
||||
/* Aggregator port enable bit */
|
||||
#define TPDA_Pn_CR_ENA BIT(0)
|
||||
/* Aggregator port DSB data set element size bit */
|
||||
#define TPDA_Pn_CR_DSBSIZE BIT(8)
|
||||
|
||||
#define TPDA_MAX_INPORTS 32
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/amba/bus.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/coresight.h>
|
||||
#include <linux/coresight-pmu.h>
|
||||
@ -20,23 +21,265 @@
|
||||
|
||||
DEFINE_CORESIGHT_DEVLIST(tpdm_devs, "tpdm");
|
||||
|
||||
static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
|
||||
/* Read dataset array member with the index number */
|
||||
static ssize_t tpdm_simple_dataset_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
struct tpdm_dataset_attribute *tpdm_attr =
|
||||
container_of(attr, struct tpdm_dataset_attribute, attr);
|
||||
|
||||
switch (tpdm_attr->mem) {
|
||||
case DSB_EDGE_CTRL:
|
||||
if (tpdm_attr->idx >= TPDM_DSB_MAX_EDCR)
|
||||
return -EINVAL;
|
||||
return sysfs_emit(buf, "0x%x\n",
|
||||
drvdata->dsb->edge_ctrl[tpdm_attr->idx]);
|
||||
case DSB_EDGE_CTRL_MASK:
|
||||
if (tpdm_attr->idx >= TPDM_DSB_MAX_EDCMR)
|
||||
return -EINVAL;
|
||||
return sysfs_emit(buf, "0x%x\n",
|
||||
drvdata->dsb->edge_ctrl_mask[tpdm_attr->idx]);
|
||||
case DSB_TRIG_PATT:
|
||||
if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)
|
||||
return -EINVAL;
|
||||
return sysfs_emit(buf, "0x%x\n",
|
||||
drvdata->dsb->trig_patt[tpdm_attr->idx]);
|
||||
case DSB_TRIG_PATT_MASK:
|
||||
if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)
|
||||
return -EINVAL;
|
||||
return sysfs_emit(buf, "0x%x\n",
|
||||
drvdata->dsb->trig_patt_mask[tpdm_attr->idx]);
|
||||
case DSB_PATT:
|
||||
if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)
|
||||
return -EINVAL;
|
||||
return sysfs_emit(buf, "0x%x\n",
|
||||
drvdata->dsb->patt_val[tpdm_attr->idx]);
|
||||
case DSB_PATT_MASK:
|
||||
if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)
|
||||
return -EINVAL;
|
||||
return sysfs_emit(buf, "0x%x\n",
|
||||
drvdata->dsb->patt_mask[tpdm_attr->idx]);
|
||||
case DSB_MSR:
|
||||
if (tpdm_attr->idx >= drvdata->dsb_msr_num)
|
||||
return -EINVAL;
|
||||
return sysfs_emit(buf, "0x%x\n",
|
||||
drvdata->dsb->msr[tpdm_attr->idx]);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Write dataset array member with the index number */
|
||||
static ssize_t tpdm_simple_dataset_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
unsigned long val;
|
||||
ssize_t ret = size;
|
||||
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
struct tpdm_dataset_attribute *tpdm_attr =
|
||||
container_of(attr, struct tpdm_dataset_attribute, attr);
|
||||
|
||||
if (kstrtoul(buf, 0, &val))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
switch (tpdm_attr->mem) {
|
||||
case DSB_TRIG_PATT:
|
||||
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
|
||||
drvdata->dsb->trig_patt[tpdm_attr->idx] = val;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case DSB_TRIG_PATT_MASK:
|
||||
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
|
||||
drvdata->dsb->trig_patt_mask[tpdm_attr->idx] = val;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case DSB_PATT:
|
||||
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
|
||||
drvdata->dsb->patt_val[tpdm_attr->idx] = val;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case DSB_PATT_MASK:
|
||||
if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
|
||||
drvdata->dsb->patt_mask[tpdm_attr->idx] = val;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case DSB_MSR:
|
||||
if (tpdm_attr->idx < drvdata->dsb_msr_num)
|
||||
drvdata->dsb->msr[tpdm_attr->idx] = val;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
return (drvdata->datasets & TPDM_PIDR0_DS_DSB);
|
||||
}
|
||||
|
||||
static umode_t tpdm_dsb_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int n)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
if (drvdata && tpdm_has_dsb_dataset(drvdata))
|
||||
return attr->mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static umode_t tpdm_dsb_msr_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int n)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
struct device_attribute *dev_attr =
|
||||
container_of(attr, struct device_attribute, attr);
|
||||
struct tpdm_dataset_attribute *tpdm_attr =
|
||||
container_of(dev_attr, struct tpdm_dataset_attribute, attr);
|
||||
|
||||
if (tpdm_attr->idx < drvdata->dsb_msr_num)
|
||||
return attr->mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
if (tpdm_has_dsb_dataset(drvdata)) {
|
||||
memset(drvdata->dsb, 0, sizeof(struct dsb_dataset));
|
||||
|
||||
drvdata->dsb->trig_ts = true;
|
||||
drvdata->dsb->trig_type = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_dsb_mode(struct tpdm_drvdata *drvdata, u32 *val)
|
||||
{
|
||||
u32 mode;
|
||||
|
||||
/* Set the test accurate mode */
|
||||
mode = TPDM_DSB_MODE_TEST(drvdata->dsb->mode);
|
||||
*val &= ~TPDM_DSB_CR_TEST_MODE;
|
||||
*val |= FIELD_PREP(TPDM_DSB_CR_TEST_MODE, mode);
|
||||
|
||||
/* Set the byte lane for high-performance mode */
|
||||
mode = TPDM_DSB_MODE_HPBYTESEL(drvdata->dsb->mode);
|
||||
*val &= ~TPDM_DSB_CR_HPSEL;
|
||||
*val |= FIELD_PREP(TPDM_DSB_CR_HPSEL, mode);
|
||||
|
||||
/* Set the performance mode */
|
||||
if (drvdata->dsb->mode & TPDM_DSB_MODE_PERF)
|
||||
*val |= TPDM_DSB_CR_MODE;
|
||||
else
|
||||
*val &= ~TPDM_DSB_CR_MODE;
|
||||
}
|
||||
|
||||
static void set_dsb_tier(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* Set the enable bit of DSB control register to 1 */
|
||||
val = readl_relaxed(drvdata->base + TPDM_DSB_TIER);
|
||||
|
||||
/* Clear all relevant fields */
|
||||
val &= ~(TPDM_DSB_TIER_PATT_TSENAB | TPDM_DSB_TIER_PATT_TYPE |
|
||||
TPDM_DSB_TIER_XTRIG_TSENAB);
|
||||
|
||||
/* Set pattern timestamp type and enablement */
|
||||
if (drvdata->dsb->patt_ts) {
|
||||
val |= TPDM_DSB_TIER_PATT_TSENAB;
|
||||
if (drvdata->dsb->patt_type)
|
||||
val |= TPDM_DSB_TIER_PATT_TYPE;
|
||||
else
|
||||
val &= ~TPDM_DSB_TIER_PATT_TYPE;
|
||||
} else {
|
||||
val &= ~TPDM_DSB_TIER_PATT_TSENAB;
|
||||
}
|
||||
|
||||
/* Set trigger timestamp */
|
||||
if (drvdata->dsb->trig_ts)
|
||||
val |= TPDM_DSB_TIER_XTRIG_TSENAB;
|
||||
else
|
||||
val &= ~TPDM_DSB_TIER_XTRIG_TSENAB;
|
||||
|
||||
writel_relaxed(val, drvdata->base + TPDM_DSB_TIER);
|
||||
}
|
||||
|
||||
static void set_dsb_msr(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < drvdata->dsb_msr_num; i++)
|
||||
writel_relaxed(drvdata->dsb->msr[i],
|
||||
drvdata->base + TPDM_DSB_MSR(i));
|
||||
}
|
||||
|
||||
static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
u32 val, i;
|
||||
|
||||
for (i = 0; i < TPDM_DSB_MAX_EDCR; i++)
|
||||
writel_relaxed(drvdata->dsb->edge_ctrl[i],
|
||||
drvdata->base + TPDM_DSB_EDCR(i));
|
||||
for (i = 0; i < TPDM_DSB_MAX_EDCMR; i++)
|
||||
writel_relaxed(drvdata->dsb->edge_ctrl_mask[i],
|
||||
drvdata->base + TPDM_DSB_EDCMR(i));
|
||||
for (i = 0; i < TPDM_DSB_MAX_PATT; i++) {
|
||||
writel_relaxed(drvdata->dsb->patt_val[i],
|
||||
drvdata->base + TPDM_DSB_TPR(i));
|
||||
writel_relaxed(drvdata->dsb->patt_mask[i],
|
||||
drvdata->base + TPDM_DSB_TPMR(i));
|
||||
writel_relaxed(drvdata->dsb->trig_patt[i],
|
||||
drvdata->base + TPDM_DSB_XPR(i));
|
||||
writel_relaxed(drvdata->dsb->trig_patt_mask[i],
|
||||
drvdata->base + TPDM_DSB_XPMR(i));
|
||||
}
|
||||
|
||||
set_dsb_tier(drvdata);
|
||||
|
||||
set_dsb_msr(drvdata);
|
||||
|
||||
val = readl_relaxed(drvdata->base + TPDM_DSB_CR);
|
||||
/* Set the mode of DSB dataset */
|
||||
set_dsb_mode(drvdata, &val);
|
||||
/* Set trigger type */
|
||||
if (drvdata->dsb->trig_type)
|
||||
val |= TPDM_DSB_CR_TRIG_TYPE;
|
||||
else
|
||||
val &= ~TPDM_DSB_CR_TRIG_TYPE;
|
||||
/* Set the enable bit of DSB control register to 1 */
|
||||
val |= TPDM_DSB_CR_ENA;
|
||||
writel_relaxed(val, drvdata->base + TPDM_DSB_CR);
|
||||
}
|
||||
|
||||
/* TPDM enable operations */
|
||||
/*
|
||||
* TPDM enable operations
|
||||
* The TPDM or Monitor serves as data collection component for various
|
||||
* dataset types. It covers Basic Counts(BC), Tenure Counts(TC),
|
||||
* Continuous Multi-Bit(CMB), Multi-lane CMB(MCMB) and Discrete Single
|
||||
* Bit(DSB). This function will initialize the configuration according
|
||||
* to the dataset type supported by the TPDM.
|
||||
*/
|
||||
static void __tpdm_enable(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
CS_UNLOCK(drvdata->base);
|
||||
|
||||
/* Check if DSB datasets is present for TPDM. */
|
||||
if (drvdata->datasets & TPDM_PIDR0_DS_DSB)
|
||||
if (tpdm_has_dsb_dataset(drvdata))
|
||||
tpdm_enable_dsb(drvdata);
|
||||
|
||||
CS_LOCK(drvdata->base);
|
||||
@ -76,8 +319,7 @@ static void __tpdm_disable(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
CS_UNLOCK(drvdata->base);
|
||||
|
||||
/* Check if DSB datasets is present for TPDM. */
|
||||
if (drvdata->datasets & TPDM_PIDR0_DS_DSB)
|
||||
if (tpdm_has_dsb_dataset(drvdata))
|
||||
tpdm_disable_dsb(drvdata);
|
||||
|
||||
CS_LOCK(drvdata->base);
|
||||
@ -110,17 +352,46 @@ static const struct coresight_ops tpdm_cs_ops = {
|
||||
.source_ops = &tpdm_source_ops,
|
||||
};
|
||||
|
||||
static void tpdm_init_default_data(struct tpdm_drvdata *drvdata)
|
||||
static int tpdm_datasets_setup(struct tpdm_drvdata *drvdata)
|
||||
{
|
||||
u32 pidr;
|
||||
|
||||
CS_UNLOCK(drvdata->base);
|
||||
/* Get the datasets present on the TPDM. */
|
||||
pidr = readl_relaxed(drvdata->base + CORESIGHT_PERIPHIDR0);
|
||||
drvdata->datasets |= pidr & GENMASK(TPDM_DATASETS - 1, 0);
|
||||
CS_LOCK(drvdata->base);
|
||||
|
||||
if (tpdm_has_dsb_dataset(drvdata) && (!drvdata->dsb)) {
|
||||
drvdata->dsb = devm_kzalloc(drvdata->dev,
|
||||
sizeof(*drvdata->dsb), GFP_KERNEL);
|
||||
if (!drvdata->dsb)
|
||||
return -ENOMEM;
|
||||
}
|
||||
tpdm_reset_datasets(drvdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t reset_dataset_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long val;
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
ret = kstrtoul(buf, 0, &val);
|
||||
if (ret || val != 1)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
tpdm_reset_datasets(drvdata);
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_WO(reset_dataset);
|
||||
|
||||
/*
|
||||
* value 1: 64 bits test data
|
||||
* value 2: 32 bits test data
|
||||
@ -161,6 +432,7 @@ static ssize_t integration_test_store(struct device *dev,
|
||||
static DEVICE_ATTR_WO(integration_test);
|
||||
|
||||
static struct attribute *tpdm_attrs[] = {
|
||||
&dev_attr_reset_dataset.attr,
|
||||
&dev_attr_integration_test.attr,
|
||||
NULL,
|
||||
};
|
||||
@ -169,8 +441,421 @@ static struct attribute_group tpdm_attr_grp = {
|
||||
.attrs = tpdm_attrs,
|
||||
};
|
||||
|
||||
static ssize_t dsb_mode_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
return sysfs_emit(buf, "%x\n", drvdata->dsb->mode);
|
||||
}
|
||||
|
||||
static ssize_t dsb_mode_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long val;
|
||||
|
||||
if ((kstrtoul(buf, 0, &val)) || (val < 0) ||
|
||||
(val & ~TPDM_DSB_MODE_MASK))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
drvdata->dsb->mode = val & TPDM_DSB_MODE_MASK;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(dsb_mode);
|
||||
|
||||
static ssize_t ctrl_idx_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
(unsigned int)drvdata->dsb->edge_ctrl_idx);
|
||||
}
|
||||
|
||||
/*
|
||||
* The EDCR registers can include up to 16 32-bit registers, and each
|
||||
* one can be configured to control up to 16 edge detections(2 bits
|
||||
* control one edge detection). So a total 256 edge detections can be
|
||||
* configured. This function provides a way to set the index number of
|
||||
* the edge detection which needs to be configured.
|
||||
*/
|
||||
static ssize_t ctrl_idx_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long val;
|
||||
|
||||
if ((kstrtoul(buf, 0, &val)) || (val >= TPDM_DSB_MAX_LINES))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
drvdata->dsb->edge_ctrl_idx = val;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(ctrl_idx);
|
||||
|
||||
/*
|
||||
* This function is used to control the edge detection according
|
||||
* to the index number that has been set.
|
||||
* "edge_ctrl" should be one of the following values.
|
||||
* 0 - Rising edge detection
|
||||
* 1 - Falling edge detection
|
||||
* 2 - Rising and falling edge detection (toggle detection)
|
||||
*/
|
||||
static ssize_t ctrl_val_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long val, edge_ctrl;
|
||||
int reg;
|
||||
|
||||
if ((kstrtoul(buf, 0, &edge_ctrl)) || (edge_ctrl > 0x2))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
/*
|
||||
* There are 2 bit per DSB Edge Control line.
|
||||
* Thus we have 16 lines in a 32bit word.
|
||||
*/
|
||||
reg = EDCR_TO_WORD_IDX(drvdata->dsb->edge_ctrl_idx);
|
||||
val = drvdata->dsb->edge_ctrl[reg];
|
||||
val &= ~EDCR_TO_WORD_MASK(drvdata->dsb->edge_ctrl_idx);
|
||||
val |= EDCR_TO_WORD_VAL(edge_ctrl, drvdata->dsb->edge_ctrl_idx);
|
||||
drvdata->dsb->edge_ctrl[reg] = val;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_WO(ctrl_val);
|
||||
|
||||
static ssize_t ctrl_mask_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long val;
|
||||
u32 set;
|
||||
int reg;
|
||||
|
||||
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
/*
|
||||
* There is 1 bit per DSB Edge Control Mark line.
|
||||
* Thus we have 32 lines in a 32bit word.
|
||||
*/
|
||||
reg = EDCMR_TO_WORD_IDX(drvdata->dsb->edge_ctrl_idx);
|
||||
set = drvdata->dsb->edge_ctrl_mask[reg];
|
||||
if (val)
|
||||
set |= BIT(EDCMR_TO_WORD_SHIFT(drvdata->dsb->edge_ctrl_idx));
|
||||
else
|
||||
set &= ~BIT(EDCMR_TO_WORD_SHIFT(drvdata->dsb->edge_ctrl_idx));
|
||||
drvdata->dsb->edge_ctrl_mask[reg] = set;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_WO(ctrl_mask);
|
||||
|
||||
static ssize_t enable_ts_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
(unsigned int)drvdata->dsb->patt_ts);
|
||||
}
|
||||
|
||||
/*
|
||||
* value 1: Enable/Disable DSB pattern timestamp
|
||||
*/
|
||||
static ssize_t enable_ts_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long val;
|
||||
|
||||
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
drvdata->dsb->patt_ts = !!val;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(enable_ts);
|
||||
|
||||
static ssize_t set_type_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
(unsigned int)drvdata->dsb->patt_type);
|
||||
}
|
||||
|
||||
/*
|
||||
* value 1: Set DSB pattern type
|
||||
*/
|
||||
static ssize_t set_type_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long val;
|
||||
|
||||
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
drvdata->dsb->patt_type = val;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(set_type);
|
||||
|
||||
static ssize_t dsb_trig_type_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
(unsigned int)drvdata->dsb->trig_type);
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger type (boolean):
|
||||
* false - Disable trigger type.
|
||||
* true - Enable trigger type.
|
||||
*/
|
||||
static ssize_t dsb_trig_type_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long val;
|
||||
|
||||
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
if (val)
|
||||
drvdata->dsb->trig_type = true;
|
||||
else
|
||||
drvdata->dsb->trig_type = false;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(dsb_trig_type);
|
||||
|
||||
static ssize_t dsb_trig_ts_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
(unsigned int)drvdata->dsb->trig_ts);
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger timestamp (boolean):
|
||||
* false - Disable trigger timestamp.
|
||||
* true - Enable trigger timestamp.
|
||||
*/
|
||||
static ssize_t dsb_trig_ts_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
|
||||
unsigned long val;
|
||||
|
||||
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
if (val)
|
||||
drvdata->dsb->trig_ts = true;
|
||||
else
|
||||
drvdata->dsb->trig_ts = false;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
return size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(dsb_trig_ts);
|
||||
|
||||
static struct attribute *tpdm_dsb_edge_attrs[] = {
|
||||
&dev_attr_ctrl_idx.attr,
|
||||
&dev_attr_ctrl_val.attr,
|
||||
&dev_attr_ctrl_mask.attr,
|
||||
DSB_EDGE_CTRL_ATTR(0),
|
||||
DSB_EDGE_CTRL_ATTR(1),
|
||||
DSB_EDGE_CTRL_ATTR(2),
|
||||
DSB_EDGE_CTRL_ATTR(3),
|
||||
DSB_EDGE_CTRL_ATTR(4),
|
||||
DSB_EDGE_CTRL_ATTR(5),
|
||||
DSB_EDGE_CTRL_ATTR(6),
|
||||
DSB_EDGE_CTRL_ATTR(7),
|
||||
DSB_EDGE_CTRL_ATTR(8),
|
||||
DSB_EDGE_CTRL_ATTR(9),
|
||||
DSB_EDGE_CTRL_ATTR(10),
|
||||
DSB_EDGE_CTRL_ATTR(11),
|
||||
DSB_EDGE_CTRL_ATTR(12),
|
||||
DSB_EDGE_CTRL_ATTR(13),
|
||||
DSB_EDGE_CTRL_ATTR(14),
|
||||
DSB_EDGE_CTRL_ATTR(15),
|
||||
DSB_EDGE_CTRL_MASK_ATTR(0),
|
||||
DSB_EDGE_CTRL_MASK_ATTR(1),
|
||||
DSB_EDGE_CTRL_MASK_ATTR(2),
|
||||
DSB_EDGE_CTRL_MASK_ATTR(3),
|
||||
DSB_EDGE_CTRL_MASK_ATTR(4),
|
||||
DSB_EDGE_CTRL_MASK_ATTR(5),
|
||||
DSB_EDGE_CTRL_MASK_ATTR(6),
|
||||
DSB_EDGE_CTRL_MASK_ATTR(7),
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *tpdm_dsb_trig_patt_attrs[] = {
|
||||
DSB_TRIG_PATT_ATTR(0),
|
||||
DSB_TRIG_PATT_ATTR(1),
|
||||
DSB_TRIG_PATT_ATTR(2),
|
||||
DSB_TRIG_PATT_ATTR(3),
|
||||
DSB_TRIG_PATT_ATTR(4),
|
||||
DSB_TRIG_PATT_ATTR(5),
|
||||
DSB_TRIG_PATT_ATTR(6),
|
||||
DSB_TRIG_PATT_ATTR(7),
|
||||
DSB_TRIG_PATT_MASK_ATTR(0),
|
||||
DSB_TRIG_PATT_MASK_ATTR(1),
|
||||
DSB_TRIG_PATT_MASK_ATTR(2),
|
||||
DSB_TRIG_PATT_MASK_ATTR(3),
|
||||
DSB_TRIG_PATT_MASK_ATTR(4),
|
||||
DSB_TRIG_PATT_MASK_ATTR(5),
|
||||
DSB_TRIG_PATT_MASK_ATTR(6),
|
||||
DSB_TRIG_PATT_MASK_ATTR(7),
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *tpdm_dsb_patt_attrs[] = {
|
||||
DSB_PATT_ATTR(0),
|
||||
DSB_PATT_ATTR(1),
|
||||
DSB_PATT_ATTR(2),
|
||||
DSB_PATT_ATTR(3),
|
||||
DSB_PATT_ATTR(4),
|
||||
DSB_PATT_ATTR(5),
|
||||
DSB_PATT_ATTR(6),
|
||||
DSB_PATT_ATTR(7),
|
||||
DSB_PATT_MASK_ATTR(0),
|
||||
DSB_PATT_MASK_ATTR(1),
|
||||
DSB_PATT_MASK_ATTR(2),
|
||||
DSB_PATT_MASK_ATTR(3),
|
||||
DSB_PATT_MASK_ATTR(4),
|
||||
DSB_PATT_MASK_ATTR(5),
|
||||
DSB_PATT_MASK_ATTR(6),
|
||||
DSB_PATT_MASK_ATTR(7),
|
||||
&dev_attr_enable_ts.attr,
|
||||
&dev_attr_set_type.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *tpdm_dsb_msr_attrs[] = {
|
||||
DSB_MSR_ATTR(0),
|
||||
DSB_MSR_ATTR(1),
|
||||
DSB_MSR_ATTR(2),
|
||||
DSB_MSR_ATTR(3),
|
||||
DSB_MSR_ATTR(4),
|
||||
DSB_MSR_ATTR(5),
|
||||
DSB_MSR_ATTR(6),
|
||||
DSB_MSR_ATTR(7),
|
||||
DSB_MSR_ATTR(8),
|
||||
DSB_MSR_ATTR(9),
|
||||
DSB_MSR_ATTR(10),
|
||||
DSB_MSR_ATTR(11),
|
||||
DSB_MSR_ATTR(12),
|
||||
DSB_MSR_ATTR(13),
|
||||
DSB_MSR_ATTR(14),
|
||||
DSB_MSR_ATTR(15),
|
||||
DSB_MSR_ATTR(16),
|
||||
DSB_MSR_ATTR(17),
|
||||
DSB_MSR_ATTR(18),
|
||||
DSB_MSR_ATTR(19),
|
||||
DSB_MSR_ATTR(20),
|
||||
DSB_MSR_ATTR(21),
|
||||
DSB_MSR_ATTR(22),
|
||||
DSB_MSR_ATTR(23),
|
||||
DSB_MSR_ATTR(24),
|
||||
DSB_MSR_ATTR(25),
|
||||
DSB_MSR_ATTR(26),
|
||||
DSB_MSR_ATTR(27),
|
||||
DSB_MSR_ATTR(28),
|
||||
DSB_MSR_ATTR(29),
|
||||
DSB_MSR_ATTR(30),
|
||||
DSB_MSR_ATTR(31),
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *tpdm_dsb_attrs[] = {
|
||||
&dev_attr_dsb_mode.attr,
|
||||
&dev_attr_dsb_trig_ts.attr,
|
||||
&dev_attr_dsb_trig_type.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group tpdm_dsb_attr_grp = {
|
||||
.attrs = tpdm_dsb_attrs,
|
||||
.is_visible = tpdm_dsb_is_visible,
|
||||
};
|
||||
|
||||
static struct attribute_group tpdm_dsb_edge_grp = {
|
||||
.attrs = tpdm_dsb_edge_attrs,
|
||||
.is_visible = tpdm_dsb_is_visible,
|
||||
.name = "dsb_edge",
|
||||
};
|
||||
|
||||
static struct attribute_group tpdm_dsb_trig_patt_grp = {
|
||||
.attrs = tpdm_dsb_trig_patt_attrs,
|
||||
.is_visible = tpdm_dsb_is_visible,
|
||||
.name = "dsb_trig_patt",
|
||||
};
|
||||
|
||||
static struct attribute_group tpdm_dsb_patt_grp = {
|
||||
.attrs = tpdm_dsb_patt_attrs,
|
||||
.is_visible = tpdm_dsb_is_visible,
|
||||
.name = "dsb_patt",
|
||||
};
|
||||
|
||||
static struct attribute_group tpdm_dsb_msr_grp = {
|
||||
.attrs = tpdm_dsb_msr_attrs,
|
||||
.is_visible = tpdm_dsb_msr_is_visible,
|
||||
.name = "dsb_msr",
|
||||
};
|
||||
|
||||
static const struct attribute_group *tpdm_attr_grps[] = {
|
||||
&tpdm_attr_grp,
|
||||
&tpdm_dsb_attr_grp,
|
||||
&tpdm_dsb_edge_grp,
|
||||
&tpdm_dsb_trig_patt_grp,
|
||||
&tpdm_dsb_patt_grp,
|
||||
&tpdm_dsb_msr_grp,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -181,6 +866,7 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
struct coresight_platform_data *pdata;
|
||||
struct tpdm_drvdata *drvdata;
|
||||
struct coresight_desc desc = { 0 };
|
||||
int ret;
|
||||
|
||||
pdata = coresight_get_platform_data(dev);
|
||||
if (IS_ERR(pdata))
|
||||
@ -200,12 +886,20 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
|
||||
drvdata->base = base;
|
||||
|
||||
ret = tpdm_datasets_setup(drvdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (drvdata && tpdm_has_dsb_dataset(drvdata))
|
||||
of_property_read_u32(drvdata->dev->of_node,
|
||||
"qcom,dsb-msrs-num", &drvdata->dsb_msr_num);
|
||||
|
||||
/* Set up coresight component description */
|
||||
desc.name = coresight_alloc_device_name(&tpdm_devs, dev);
|
||||
if (!desc.name)
|
||||
return -ENOMEM;
|
||||
desc.type = CORESIGHT_DEV_TYPE_SOURCE;
|
||||
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS;
|
||||
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM;
|
||||
desc.ops = &tpdm_cs_ops;
|
||||
desc.pdata = adev->dev.platform_data;
|
||||
desc.dev = &adev->dev;
|
||||
@ -216,7 +910,7 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
return PTR_ERR(drvdata->csdev);
|
||||
|
||||
spin_lock_init(&drvdata->spinlock);
|
||||
tpdm_init_default_data(drvdata);
|
||||
|
||||
/* Decrease pm refcount when probe is done.*/
|
||||
pm_runtime_put(&adev->dev);
|
||||
|
||||
|
@ -11,8 +11,52 @@
|
||||
|
||||
/* DSB Subunit Registers */
|
||||
#define TPDM_DSB_CR (0x780)
|
||||
#define TPDM_DSB_TIER (0x784)
|
||||
#define TPDM_DSB_TPR(n) (0x788 + (n * 4))
|
||||
#define TPDM_DSB_TPMR(n) (0x7A8 + (n * 4))
|
||||
#define TPDM_DSB_XPR(n) (0x7C8 + (n * 4))
|
||||
#define TPDM_DSB_XPMR(n) (0x7E8 + (n * 4))
|
||||
#define TPDM_DSB_EDCR(n) (0x808 + (n * 4))
|
||||
#define TPDM_DSB_EDCMR(n) (0x848 + (n * 4))
|
||||
#define TPDM_DSB_MSR(n) (0x980 + (n * 4))
|
||||
|
||||
/* Enable bit for DSB subunit */
|
||||
#define TPDM_DSB_CR_ENA BIT(0)
|
||||
/* Enable bit for DSB subunit perfmance mode */
|
||||
#define TPDM_DSB_CR_MODE BIT(1)
|
||||
/* Enable bit for DSB subunit trigger type */
|
||||
#define TPDM_DSB_CR_TRIG_TYPE BIT(12)
|
||||
/* Data bits for DSB high performace mode */
|
||||
#define TPDM_DSB_CR_HPSEL GENMASK(6, 2)
|
||||
/* Data bits for DSB test mode */
|
||||
#define TPDM_DSB_CR_TEST_MODE GENMASK(10, 9)
|
||||
|
||||
/* Enable bit for DSB subunit pattern timestamp */
|
||||
#define TPDM_DSB_TIER_PATT_TSENAB BIT(0)
|
||||
/* Enable bit for DSB subunit trigger timestamp */
|
||||
#define TPDM_DSB_TIER_XTRIG_TSENAB BIT(1)
|
||||
/* Bit for DSB subunit pattern type */
|
||||
#define TPDM_DSB_TIER_PATT_TYPE BIT(2)
|
||||
|
||||
/* DSB programming modes */
|
||||
/* DSB mode bits mask */
|
||||
#define TPDM_DSB_MODE_MASK GENMASK(8, 0)
|
||||
/* Test mode control bit*/
|
||||
#define TPDM_DSB_MODE_TEST(val) (val & GENMASK(1, 0))
|
||||
/* Performance mode */
|
||||
#define TPDM_DSB_MODE_PERF BIT(3)
|
||||
/* High performance mode */
|
||||
#define TPDM_DSB_MODE_HPBYTESEL(val) (val & GENMASK(8, 4))
|
||||
|
||||
#define EDCRS_PER_WORD 16
|
||||
#define EDCR_TO_WORD_IDX(r) ((r) / EDCRS_PER_WORD)
|
||||
#define EDCR_TO_WORD_SHIFT(r) ((r % EDCRS_PER_WORD) * 2)
|
||||
#define EDCR_TO_WORD_VAL(val, r) (val << EDCR_TO_WORD_SHIFT(r))
|
||||
#define EDCR_TO_WORD_MASK(r) EDCR_TO_WORD_VAL(0x3, r)
|
||||
|
||||
#define EDCMRS_PER_WORD 32
|
||||
#define EDCMR_TO_WORD_IDX(r) ((r) / EDCMRS_PER_WORD)
|
||||
#define EDCMR_TO_WORD_SHIFT(r) ((r) % EDCMRS_PER_WORD)
|
||||
|
||||
/* TPDM integration test registers */
|
||||
#define TPDM_ITATBCNTRL (0xEF0)
|
||||
@ -40,6 +84,95 @@
|
||||
#define TPDM_PIDR0_DS_IMPDEF BIT(0)
|
||||
#define TPDM_PIDR0_DS_DSB BIT(1)
|
||||
|
||||
#define TPDM_DSB_MAX_LINES 256
|
||||
/* MAX number of EDCR registers */
|
||||
#define TPDM_DSB_MAX_EDCR 16
|
||||
/* MAX number of EDCMR registers */
|
||||
#define TPDM_DSB_MAX_EDCMR 8
|
||||
/* MAX number of DSB pattern */
|
||||
#define TPDM_DSB_MAX_PATT 8
|
||||
/* MAX number of DSB MSR */
|
||||
#define TPDM_DSB_MAX_MSR 32
|
||||
|
||||
#define tpdm_simple_dataset_ro(name, mem, idx) \
|
||||
(&((struct tpdm_dataset_attribute[]) { \
|
||||
{ \
|
||||
__ATTR(name, 0444, tpdm_simple_dataset_show, NULL), \
|
||||
mem, \
|
||||
idx, \
|
||||
} \
|
||||
})[0].attr.attr)
|
||||
|
||||
#define tpdm_simple_dataset_rw(name, mem, idx) \
|
||||
(&((struct tpdm_dataset_attribute[]) { \
|
||||
{ \
|
||||
__ATTR(name, 0644, tpdm_simple_dataset_show, \
|
||||
tpdm_simple_dataset_store), \
|
||||
mem, \
|
||||
idx, \
|
||||
} \
|
||||
})[0].attr.attr)
|
||||
|
||||
#define DSB_EDGE_CTRL_ATTR(nr) \
|
||||
tpdm_simple_dataset_ro(edcr##nr, \
|
||||
DSB_EDGE_CTRL, nr)
|
||||
|
||||
#define DSB_EDGE_CTRL_MASK_ATTR(nr) \
|
||||
tpdm_simple_dataset_ro(edcmr##nr, \
|
||||
DSB_EDGE_CTRL_MASK, nr)
|
||||
|
||||
#define DSB_TRIG_PATT_ATTR(nr) \
|
||||
tpdm_simple_dataset_rw(xpr##nr, \
|
||||
DSB_TRIG_PATT, nr)
|
||||
|
||||
#define DSB_TRIG_PATT_MASK_ATTR(nr) \
|
||||
tpdm_simple_dataset_rw(xpmr##nr, \
|
||||
DSB_TRIG_PATT_MASK, nr)
|
||||
|
||||
#define DSB_PATT_ATTR(nr) \
|
||||
tpdm_simple_dataset_rw(tpr##nr, \
|
||||
DSB_PATT, nr)
|
||||
|
||||
#define DSB_PATT_MASK_ATTR(nr) \
|
||||
tpdm_simple_dataset_rw(tpmr##nr, \
|
||||
DSB_PATT_MASK, nr)
|
||||
|
||||
#define DSB_MSR_ATTR(nr) \
|
||||
tpdm_simple_dataset_rw(msr##nr, \
|
||||
DSB_MSR, nr)
|
||||
|
||||
/**
|
||||
* struct dsb_dataset - specifics associated to dsb dataset
|
||||
* @mode: DSB programming mode
|
||||
* @edge_ctrl_idx Index number of the edge control
|
||||
* @edge_ctrl: Save value for edge control
|
||||
* @edge_ctrl_mask: Save value for edge control mask
|
||||
* @patt_val: Save value for pattern
|
||||
* @patt_mask: Save value for pattern mask
|
||||
* @trig_patt: Save value for trigger pattern
|
||||
* @trig_patt_mask: Save value for trigger pattern mask
|
||||
* @msr Save value for MSR
|
||||
* @patt_ts: Enable/Disable pattern timestamp
|
||||
* @patt_type: Set pattern type
|
||||
* @trig_ts: Enable/Disable trigger timestamp.
|
||||
* @trig_type: Enable/Disable trigger type.
|
||||
*/
|
||||
struct dsb_dataset {
|
||||
u32 mode;
|
||||
u32 edge_ctrl_idx;
|
||||
u32 edge_ctrl[TPDM_DSB_MAX_EDCR];
|
||||
u32 edge_ctrl_mask[TPDM_DSB_MAX_EDCMR];
|
||||
u32 patt_val[TPDM_DSB_MAX_PATT];
|
||||
u32 patt_mask[TPDM_DSB_MAX_PATT];
|
||||
u32 trig_patt[TPDM_DSB_MAX_PATT];
|
||||
u32 trig_patt_mask[TPDM_DSB_MAX_PATT];
|
||||
u32 msr[TPDM_DSB_MAX_MSR];
|
||||
bool patt_ts;
|
||||
bool patt_type;
|
||||
bool trig_ts;
|
||||
bool trig_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tpdm_drvdata - specifics associated to an TPDM component
|
||||
* @base: memory mapped base address for this component.
|
||||
@ -48,6 +181,8 @@
|
||||
* @spinlock: lock for the drvdata value.
|
||||
* @enable: enable status of the component.
|
||||
* @datasets: The datasets types present of the TPDM.
|
||||
* @dsb Specifics associated to TPDM DSB.
|
||||
* @dsb_msr_num Number of MSR supported by DSB TPDM
|
||||
*/
|
||||
|
||||
struct tpdm_drvdata {
|
||||
@ -57,6 +192,32 @@ struct tpdm_drvdata {
|
||||
spinlock_t spinlock;
|
||||
bool enable;
|
||||
unsigned long datasets;
|
||||
struct dsb_dataset *dsb;
|
||||
u32 dsb_msr_num;
|
||||
};
|
||||
|
||||
/* Enumerate members of various datasets */
|
||||
enum dataset_mem {
|
||||
DSB_EDGE_CTRL,
|
||||
DSB_EDGE_CTRL_MASK,
|
||||
DSB_TRIG_PATT,
|
||||
DSB_TRIG_PATT_MASK,
|
||||
DSB_PATT,
|
||||
DSB_PATT_MASK,
|
||||
DSB_MSR,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tpdm_dataset_attribute - Record the member variables and
|
||||
* index number of datasets that need to be operated by sysfs file
|
||||
* @attr: The device attribute
|
||||
* @mem: The member in the dataset data structure
|
||||
* @idx: The index number of the array data
|
||||
*/
|
||||
struct tpdm_dataset_attribute {
|
||||
struct device_attribute attr;
|
||||
enum dataset_mem mem;
|
||||
u32 idx;
|
||||
};
|
||||
|
||||
#endif /* _CORESIGHT_CORESIGHT_TPDM_H */
|
||||
|
@ -1253,8 +1253,18 @@ static void arm_trbe_register_coresight_cpu(struct trbe_drvdata *drvdata, int cp
|
||||
desc.name = devm_kasprintf(dev, GFP_KERNEL, "trbe%d", cpu);
|
||||
if (!desc.name)
|
||||
goto cpu_clear;
|
||||
|
||||
desc.pdata = coresight_get_platform_data(dev);
|
||||
/*
|
||||
* TRBE coresight devices do not need regular connections
|
||||
* information, as the paths get built between all percpu
|
||||
* source and their respective percpu sink devices. Though
|
||||
* coresight_register() expect device connections via the
|
||||
* platform_data, which TRBE devices do not have. As they
|
||||
* are not real ACPI devices, coresight_get_platform_data()
|
||||
* ends up failing. Instead let's allocate a dummy zeroed
|
||||
* coresight_platform_data structure and assign that back
|
||||
* into the device for that purpose.
|
||||
*/
|
||||
desc.pdata = devm_kzalloc(dev, sizeof(*desc.pdata), GFP_KERNEL);
|
||||
if (IS_ERR(desc.pdata))
|
||||
goto cpu_clear;
|
||||
|
||||
@ -1520,14 +1530,13 @@ probe_failed:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int arm_trbe_device_remove(struct platform_device *pdev)
|
||||
static void arm_trbe_device_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct trbe_drvdata *drvdata = platform_get_drvdata(pdev);
|
||||
|
||||
arm_trbe_remove_cpuhp(drvdata);
|
||||
arm_trbe_remove_coresight(drvdata);
|
||||
arm_trbe_remove_irq(drvdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id arm_trbe_of_match[] = {
|
||||
@ -1536,14 +1545,23 @@ static const struct of_device_id arm_trbe_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, arm_trbe_of_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct platform_device_id arm_trbe_acpi_match[] = {
|
||||
{ ARMV8_TRBE_PDEV_NAME, 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, arm_trbe_acpi_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver arm_trbe_driver = {
|
||||
.id_table = ACPI_PTR(arm_trbe_acpi_match),
|
||||
.driver = {
|
||||
.name = DRVNAME,
|
||||
.of_match_table = of_match_ptr(arm_trbe_of_match),
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = arm_trbe_device_probe,
|
||||
.remove = arm_trbe_device_remove,
|
||||
.remove_new = arm_trbe_device_remove,
|
||||
};
|
||||
|
||||
static int __init arm_trbe_init(void)
|
||||
|
@ -7,11 +7,13 @@
|
||||
*
|
||||
* Author: Anshuman Khandual <anshuman.khandual@arm.com>
|
||||
*/
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/coresight.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/perf/arm_pmu.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
|
@ -97,27 +97,19 @@ static int smb_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct smb_drv_data *drvdata = container_of(file->private_data,
|
||||
struct smb_drv_data, miscdev);
|
||||
int ret = 0;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
guard(spinlock)(&drvdata->spinlock);
|
||||
|
||||
if (drvdata->reading) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
if (drvdata->reading)
|
||||
return -EBUSY;
|
||||
|
||||
if (atomic_read(&drvdata->csdev->refcnt)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
if (atomic_read(&drvdata->csdev->refcnt))
|
||||
return -EBUSY;
|
||||
|
||||
smb_update_data_size(drvdata);
|
||||
|
||||
drvdata->reading = true;
|
||||
out:
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t smb_read(struct file *file, char __user *data, size_t len,
|
||||
@ -160,9 +152,8 @@ static int smb_release(struct inode *inode, struct file *file)
|
||||
struct smb_drv_data *drvdata = container_of(file->private_data,
|
||||
struct smb_drv_data, miscdev);
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
guard(spinlock)(&drvdata->spinlock);
|
||||
drvdata->reading = false;
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -255,19 +246,15 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
|
||||
struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
int ret = 0;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
guard(spinlock)(&drvdata->spinlock);
|
||||
|
||||
/* Do nothing, the trace data is reading by other interface now */
|
||||
if (drvdata->reading) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
if (drvdata->reading)
|
||||
return -EBUSY;
|
||||
|
||||
/* Do nothing, the SMB is already enabled as other mode */
|
||||
if (drvdata->mode != CS_MODE_DISABLED && drvdata->mode != mode) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
if (drvdata->mode != CS_MODE_DISABLED && drvdata->mode != mode)
|
||||
return -EBUSY;
|
||||
|
||||
switch (mode) {
|
||||
case CS_MODE_SYSFS:
|
||||
@ -281,13 +268,10 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
atomic_inc(&csdev->refcnt);
|
||||
|
||||
dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n");
|
||||
out:
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -295,19 +279,14 @@ out:
|
||||
static int smb_disable(struct coresight_device *csdev)
|
||||
{
|
||||
struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
int ret = 0;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
guard(spinlock)(&drvdata->spinlock);
|
||||
|
||||
if (drvdata->reading) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
if (drvdata->reading)
|
||||
return -EBUSY;
|
||||
|
||||
if (atomic_dec_return(&csdev->refcnt)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
if (atomic_dec_return(&csdev->refcnt))
|
||||
return -EBUSY;
|
||||
|
||||
/* Complain if we (somehow) got out of sync */
|
||||
WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
|
||||
@ -317,12 +296,9 @@ static int smb_disable(struct coresight_device *csdev)
|
||||
/* Dissociate from the target process. */
|
||||
drvdata->pid = -1;
|
||||
drvdata->mode = CS_MODE_DISABLED;
|
||||
|
||||
dev_dbg(&csdev->dev, "Ultrasoc SMB disabled\n");
|
||||
out:
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *smb_alloc_buffer(struct coresight_device *csdev,
|
||||
@ -395,17 +371,17 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev,
|
||||
struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
|
||||
struct smb_data_buffer *sdb = &drvdata->sdb;
|
||||
struct cs_buffers *buf = sink_config;
|
||||
unsigned long data_size = 0;
|
||||
unsigned long data_size;
|
||||
bool lost = false;
|
||||
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
spin_lock(&drvdata->spinlock);
|
||||
guard(spinlock)(&drvdata->spinlock);
|
||||
|
||||
/* Don't do anything if another tracer is using this sink. */
|
||||
if (atomic_read(&csdev->refcnt) != 1)
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
smb_disable_hw(drvdata);
|
||||
smb_update_data_size(drvdata);
|
||||
@ -424,8 +400,6 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev,
|
||||
smb_sync_perf_buffer(drvdata, buf, handle->head);
|
||||
if (!buf->snapshot && lost)
|
||||
perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
|
||||
out:
|
||||
spin_unlock(&drvdata->spinlock);
|
||||
|
||||
return data_size;
|
||||
}
|
||||
@ -601,15 +575,13 @@ static int smb_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smb_remove(struct platform_device *pdev)
|
||||
static void smb_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct smb_drv_data *drvdata = platform_get_drvdata(pdev);
|
||||
|
||||
smb_unregister_sink(drvdata);
|
||||
|
||||
smb_config_inport(&pdev->dev, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
@ -627,7 +599,7 @@ static struct platform_driver smb_driver = {
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = smb_probe,
|
||||
.remove = smb_remove,
|
||||
.remove_new = smb_remove,
|
||||
};
|
||||
module_platform_driver(smb_driver);
|
||||
|
||||
|
@ -183,6 +183,10 @@ static void hisi_ptt_wait_dma_reset_done(struct hisi_ptt *hisi_ptt)
|
||||
static void hisi_ptt_trace_end(struct hisi_ptt *hisi_ptt)
|
||||
{
|
||||
writel(0, hisi_ptt->iobase + HISI_PTT_TRACE_CTRL);
|
||||
|
||||
/* Mask the interrupt on the end */
|
||||
writel(HISI_PTT_TRACE_INT_MASK_ALL, hisi_ptt->iobase + HISI_PTT_TRACE_INT_MASK);
|
||||
|
||||
hisi_ptt->trace_ctrl.started = false;
|
||||
}
|
||||
|
||||
@ -270,15 +274,14 @@ static int hisi_ptt_update_aux(struct hisi_ptt *hisi_ptt, int index, bool stop)
|
||||
buf->pos += size;
|
||||
|
||||
/*
|
||||
* Just commit the traced data if we're going to stop. Otherwise if the
|
||||
* resident AUX buffer cannot contain the data of next trace buffer,
|
||||
* apply a new one.
|
||||
* Always commit the data to the AUX buffer in time to make sure
|
||||
* userspace got enough time to consume the data.
|
||||
*
|
||||
* If we're not going to stop, apply a new one and check whether
|
||||
* there's enough room for the next trace.
|
||||
*/
|
||||
if (stop) {
|
||||
perf_aux_output_end(handle, buf->pos);
|
||||
} else if (buf->length - buf->pos < HISI_PTT_TRACE_BUF_SIZE) {
|
||||
perf_aux_output_end(handle, buf->pos);
|
||||
|
||||
perf_aux_output_end(handle, size);
|
||||
if (!stop) {
|
||||
buf = perf_aux_output_begin(handle, event);
|
||||
if (!buf)
|
||||
return -EINVAL;
|
||||
|
@ -47,6 +47,7 @@
|
||||
#define HISI_PTT_TRACE_INT_STAT 0x0890
|
||||
#define HISI_PTT_TRACE_INT_STAT_MASK GENMASK(3, 0)
|
||||
#define HISI_PTT_TRACE_INT_MASK 0x0894
|
||||
#define HISI_PTT_TRACE_INT_MASK_ALL GENMASK(3, 0)
|
||||
#define HISI_PTT_TUNING_INT_STAT 0x0898
|
||||
#define HISI_PTT_TUNING_INT_STAT_MASK BIT(0)
|
||||
#define HISI_PTT_TRACE_WR_STS 0x08a0
|
||||
|
@ -64,6 +64,7 @@ enum coresight_dev_subtype_source {
|
||||
CORESIGHT_DEV_SUBTYPE_SOURCE_PROC,
|
||||
CORESIGHT_DEV_SUBTYPE_SOURCE_BUS,
|
||||
CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE,
|
||||
CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM,
|
||||
CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS,
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user