mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-16 10:17:32 +00:00
coresight: hwtracing subsystem updates for v6.10
CoreSight/hwtracing updates for the next release includes: - ACPI power management support for CoreSight legacy components, via migration from AMBA to platform device - Fixes for ETE register save/restore during CPU Idle. - ACPI support TMC for Scatter-Gather mode. - his_ptt driver update to set the parent device for PMU and documentation fixes - Qcomm Trace component DT binding fixes - Miscellaneous cleanups Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuFy0byloRoXZHaWBxcXRZPKyBqEFAmYzcecACgkQxcXRZPKy BqEyrw//fsxpXrjt9Uz1QSmpEH+5eV//RQIO8vOOibihLrQYYMl8ZrwHp1n0lS0B Cj9P6MIRs8XztOBh5f0w57NoUOD9eJJ4/BdPRpixDPyZsm3acV/7JFMh1TIYQG6z ETlRGr5GRlLlx6VXkytMVfxRCtNlPR3PA3/fy5QR5BQ74ux+AlxuiX5krk6pEvak j8Vf35eNofqIDjNvr8ffY59kxDP+ULtiv+JWfAW+hzjjlQd+RxyamLUSJHr5Mh1N AqFjt+bqCVoT7MdtZoCrLX1b4gcgi1W/55Ph3ODdvy9vwErj2MpaNAW4829I5m1l dK5WmXFSQ/vb6UGj5laIu4ssZ0sMShu4jzatiGBBSo4FwAazSg2Lk3F6gNhXHBE2 iyrU+Pr8mRnxh59FDtnldCD1ww0cUPZOQz29aNwNy1x52nkeEMOg2KYx3sXy/Sbx TK5qJ7Fv6DOEZ/fWDPxvZjKM8IbsvJI2XTL7WyyCt3hOT+bcdzQIwnlS8q+EdBL/ zk/HAdb6/IA1vyg3kgmTCejC0EXwklME01UTs591HQ6U0iG+YxlklFFXLL9sw4Ij v6FVAbrtsgC8ov9UtmECqvjUlkZ5pwXkFU0php51R0MKvOWEU7vSxhtIjzvTumhu /lxyAQA+V112RWQS3nlxmUq3FWbqXIiFZSo1zvTavhxOtMVg06s= =yu6I -----END PGP SIGNATURE----- Merge tag 'coresight-next-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux into char-misc-next Suzuki writes: coresight: hwtracing subsystem updates for v6.10 CoreSight/hwtracing updates for the next release includes: - ACPI power management support for CoreSight legacy components, via migration from AMBA to platform device - Fixes for ETE register save/restore during CPU Idle. - ACPI support TMC for Scatter-Gather mode. - his_ptt driver update to set the parent device for PMU and documentation fixes - Qcomm Trace component DT binding fixes - Miscellaneous cleanups Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> * tag 'coresight-next-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux: (28 commits) hwtracing: hisi_ptt: Assign parent for event_source device Documentation: ABI + trace: hisi_ptt: update paths to bus/event_source coresight: tmc: Enable SG capability on ACPI based SoC-400 TMC ETR devices coresight: Docs/ABI/testing/sysfs-bus-coresight-devices: Fix spelling errors coresight: tpiu: Convert to platform remove callback returning void coresight: tmc: Convert to platform remove callback returning void coresight: stm: Convert to platform remove callback returning void coresight: debug: Convert to platform remove callback returning void coresight: catu: Convert to platform remove callback returning void coresight: Remove duplicate linux/amba/bus.h header coresight: stm: Remove duplicate linux/acpi.h header coresight: etm4x: Fix access to resource selector registers coresight: etm4x: Safe access for TRCQCLTR coresight: etm4x: Do not save/restore Data trace control registers coresight: etm4x: Do not hardcode IOMEM access for register restore coresight: debug: Move ACPI support from AMBA driver to platform driver coresight: stm: Move ACPI support from AMBA driver to platform driver coresight: tmc: Move ACPI support from AMBA driver to platform driver coresight: tpiu: Move ACPI support from AMBA driver to platform driver coresight: catu: Move ACPI support from AMBA driver to platform driver ...
This commit is contained in:
commit
d629cfcfed
@ -22,7 +22,7 @@ Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
|
|||||||
Description: (RW) Used in conjunction with @addr_idx. Specifies
|
Description: (RW) Used in conjunction with @addr_idx. Specifies
|
||||||
characteristics about the address comparator being configure,
|
characteristics about the address comparator being configure,
|
||||||
for example the access type, the kind of instruction to trace,
|
for example the access type, the kind of instruction to trace,
|
||||||
processor contect ID to trigger on, etc. Individual fields in
|
processor context ID to trigger on, etc. Individual fields in
|
||||||
the access type register may vary on the version of the trace
|
the access type register may vary on the version of the trace
|
||||||
entity.
|
entity.
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ Date: August 2023
|
|||||||
KernelVersion: 6.7
|
KernelVersion: 6.7
|
||||||
Contact: Anshuman Khandual <anshuman.khandual@arm.com>
|
Contact: Anshuman Khandual <anshuman.khandual@arm.com>
|
||||||
Description: (Read) Shows all supported Coresight TMC-ETR buffer modes available
|
Description: (Read) Shows all supported Coresight TMC-ETR buffer modes available
|
||||||
for the users to configure explicitly. This file is avaialble only
|
for the users to configure explicitly. This file is available only
|
||||||
for TMC ETR devices.
|
for TMC ETR devices.
|
||||||
|
|
||||||
What: /sys/bus/coresight/devices/<memory_map>.tmc/buf_mode_preferred
|
What: /sys/bus/coresight/devices/<memory_map>.tmc/buf_mode_preferred
|
||||||
|
@ -244,7 +244,7 @@ KernelVersion 6.9
|
|||||||
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
Contact: Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
|
||||||
Description:
|
Description:
|
||||||
(RW) Read or write the status of timestamp upon all interface.
|
(RW) Read or write the status of timestamp upon all interface.
|
||||||
Only value 0 and 1 can be written to this node. Set this node to 1 to requeset
|
Only value 0 and 1 can be written to this node. Set this node to 1 to request
|
||||||
timestamp to all trace packet.
|
timestamp to all trace packet.
|
||||||
Accepts only one of the 2 values - 0 or 1.
|
Accepts only one of the 2 values - 0 or 1.
|
||||||
0 : Disable the timestamp of all trace packets.
|
0 : Disable the timestamp of all trace packets.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/tune
|
What: /sys/bus/event_source/devices/hisi_ptt<sicl_id>_<core_id>/tune
|
||||||
Date: October 2022
|
Date: October 2022
|
||||||
KernelVersion: 6.1
|
KernelVersion: 6.1
|
||||||
Contact: Yicong Yang <yangyicong@hisilicon.com>
|
Contact: Yicong Yang <yangyicong@hisilicon.com>
|
||||||
@ -8,7 +8,7 @@ Description: This directory contains files for tuning the PCIe link
|
|||||||
|
|
||||||
See Documentation/trace/hisi-ptt.rst for more information.
|
See Documentation/trace/hisi-ptt.rst for more information.
|
||||||
|
|
||||||
What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/tune/qos_tx_cpl
|
What: /sys/bus/event_source/devices/hisi_ptt<sicl_id>_<core_id>/tune/qos_tx_cpl
|
||||||
Date: October 2022
|
Date: October 2022
|
||||||
KernelVersion: 6.1
|
KernelVersion: 6.1
|
||||||
Contact: Yicong Yang <yangyicong@hisilicon.com>
|
Contact: Yicong Yang <yangyicong@hisilicon.com>
|
||||||
@ -18,7 +18,7 @@ Description: (RW) Controls the weight of Tx completion TLPs, which influence
|
|||||||
will return an error, and out of range values will be converted
|
will return an error, and out of range values will be converted
|
||||||
to 2. The value indicates a probable level of the event.
|
to 2. The value indicates a probable level of the event.
|
||||||
|
|
||||||
What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/tune/qos_tx_np
|
What: /sys/bus/event_source/devices/hisi_ptt<sicl_id>_<core_id>/tune/qos_tx_np
|
||||||
Date: October 2022
|
Date: October 2022
|
||||||
KernelVersion: 6.1
|
KernelVersion: 6.1
|
||||||
Contact: Yicong Yang <yangyicong@hisilicon.com>
|
Contact: Yicong Yang <yangyicong@hisilicon.com>
|
||||||
@ -28,7 +28,7 @@ Description: (RW) Controls the weight of Tx non-posted TLPs, which influence
|
|||||||
will return an error, and out of range values will be converted
|
will return an error, and out of range values will be converted
|
||||||
to 2. The value indicates a probable level of the event.
|
to 2. The value indicates a probable level of the event.
|
||||||
|
|
||||||
What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/tune/qos_tx_p
|
What: /sys/bus/event_source/devices/hisi_ptt<sicl_id>_<core_id>/tune/qos_tx_p
|
||||||
Date: October 2022
|
Date: October 2022
|
||||||
KernelVersion: 6.1
|
KernelVersion: 6.1
|
||||||
Contact: Yicong Yang <yangyicong@hisilicon.com>
|
Contact: Yicong Yang <yangyicong@hisilicon.com>
|
||||||
@ -38,7 +38,7 @@ Description: (RW) Controls the weight of Tx posted TLPs, which influence the
|
|||||||
will return an error, and out of range values will be converted
|
will return an error, and out of range values will be converted
|
||||||
to 2. The value indicates a probable level of the event.
|
to 2. The value indicates a probable level of the event.
|
||||||
|
|
||||||
What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/tune/rx_alloc_buf_level
|
What: /sys/bus/event_source/devices/hisi_ptt<sicl_id>_<core_id>/tune/rx_alloc_buf_level
|
||||||
Date: October 2022
|
Date: October 2022
|
||||||
KernelVersion: 6.1
|
KernelVersion: 6.1
|
||||||
Contact: Yicong Yang <yangyicong@hisilicon.com>
|
Contact: Yicong Yang <yangyicong@hisilicon.com>
|
||||||
@ -49,7 +49,7 @@ Description: (RW) Control the allocated buffer watermark for inbound packets.
|
|||||||
will return an error, and out of range values will be converted
|
will return an error, and out of range values will be converted
|
||||||
to 2. The value indicates a probable level of the event.
|
to 2. The value indicates a probable level of the event.
|
||||||
|
|
||||||
What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/tune/tx_alloc_buf_level
|
What: /sys/bus/event_source/devices/hisi_ptt<sicl_id>_<core_id>/tune/tx_alloc_buf_level
|
||||||
Date: October 2022
|
Date: October 2022
|
||||||
KernelVersion: 6.1
|
KernelVersion: 6.1
|
||||||
Contact: Yicong Yang <yangyicong@hisilicon.com>
|
Contact: Yicong Yang <yangyicong@hisilicon.com>
|
@ -66,13 +66,11 @@ properties:
|
|||||||
- const: apb_pclk
|
- const: apb_pclk
|
||||||
|
|
||||||
in-ports:
|
in-ports:
|
||||||
type: object
|
|
||||||
description: |
|
description: |
|
||||||
Input connections from TPDM to TPDA
|
Input connections from TPDM to TPDA
|
||||||
$ref: /schemas/graph.yaml#/properties/ports
|
$ref: /schemas/graph.yaml#/properties/ports
|
||||||
|
|
||||||
out-ports:
|
out-ports:
|
||||||
type: object
|
|
||||||
description: |
|
description: |
|
||||||
Output connections from the TPDA to legacy CoreSight trace bus.
|
Output connections from the TPDA to legacy CoreSight trace bus.
|
||||||
$ref: /schemas/graph.yaml#/properties/ports
|
$ref: /schemas/graph.yaml#/properties/ports
|
||||||
@ -97,33 +95,31 @@ examples:
|
|||||||
# minimum tpda definition.
|
# minimum tpda definition.
|
||||||
- |
|
- |
|
||||||
tpda@6004000 {
|
tpda@6004000 {
|
||||||
compatible = "qcom,coresight-tpda", "arm,primecell";
|
compatible = "qcom,coresight-tpda", "arm,primecell";
|
||||||
reg = <0x6004000 0x1000>;
|
reg = <0x6004000 0x1000>;
|
||||||
|
|
||||||
clocks = <&aoss_qmp>;
|
clocks = <&aoss_qmp>;
|
||||||
clock-names = "apb_pclk";
|
clock-names = "apb_pclk";
|
||||||
|
|
||||||
in-ports {
|
in-ports {
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
|
|
||||||
port@0 {
|
port@0 {
|
||||||
reg = <0>;
|
reg = <0>;
|
||||||
tpda_qdss_0_in_tpdm_dcc: endpoint {
|
tpda_qdss_0_in_tpdm_dcc: endpoint {
|
||||||
remote-endpoint =
|
remote-endpoint = <&tpdm_dcc_out_tpda_qdss_0>;
|
||||||
<&tpdm_dcc_out_tpda_qdss_0>;
|
};
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
out-ports {
|
out-ports {
|
||||||
port {
|
port {
|
||||||
tpda_qdss_out_funnel_in0: endpoint {
|
tpda_qdss_out_funnel_in0: endpoint {
|
||||||
remote-endpoint =
|
remote-endpoint = <&funnel_in0_in_tpda_qdss>;
|
||||||
<&funnel_in0_in_tpda_qdss>;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
...
|
...
|
||||||
|
@ -40,7 +40,7 @@ IO dies (SICL, Super I/O Cluster), where there's one PCIe Root
|
|||||||
Complex for each SICL.
|
Complex for each SICL.
|
||||||
::
|
::
|
||||||
|
|
||||||
/sys/devices/hisi_ptt<sicl_id>_<core_id>
|
/sys/bus/event_source/devices/hisi_ptt<sicl_id>_<core_id>
|
||||||
|
|
||||||
Tune
|
Tune
|
||||||
====
|
====
|
||||||
@ -53,7 +53,7 @@ Each event is presented as a file under $(PTT PMU dir)/tune, and
|
|||||||
a simple open/read/write/close cycle will be used to tune the event.
|
a simple open/read/write/close cycle will be used to tune the event.
|
||||||
::
|
::
|
||||||
|
|
||||||
$ cd /sys/devices/hisi_ptt<sicl_id>_<core_id>/tune
|
$ cd /sys/bus/event_source/devices/hisi_ptt<sicl_id>_<core_id>/tune
|
||||||
$ ls
|
$ ls
|
||||||
qos_tx_cpl qos_tx_np qos_tx_p
|
qos_tx_cpl qos_tx_np qos_tx_p
|
||||||
tx_path_rx_req_alloc_buf_level
|
tx_path_rx_req_alloc_buf_level
|
||||||
|
@ -9816,7 +9816,7 @@ M: Yicong Yang <yangyicong@hisilicon.com>
|
|||||||
M: Jonathan Cameron <jonathan.cameron@huawei.com>
|
M: Jonathan Cameron <jonathan.cameron@huawei.com>
|
||||||
L: linux-kernel@vger.kernel.org
|
L: linux-kernel@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/ABI/testing/sysfs-devices-hisi_ptt
|
F: Documentation/ABI/testing/sysfs-bus-event_source-devices-hisi_ptt
|
||||||
F: Documentation/trace/hisi-ptt.rst
|
F: Documentation/trace/hisi-ptt.rst
|
||||||
F: drivers/hwtracing/ptt/
|
F: drivers/hwtracing/ptt/
|
||||||
F: tools/perf/arch/arm64/util/hisi-ptt.c
|
F: tools/perf/arch/arm64/util/hisi-ptt.c
|
||||||
|
@ -22,14 +22,6 @@
|
|||||||
static const struct acpi_device_id amba_id_list[] = {
|
static const struct acpi_device_id amba_id_list[] = {
|
||||||
{"ARMH0061", 0}, /* PL061 GPIO Device */
|
{"ARMH0061", 0}, /* PL061 GPIO Device */
|
||||||
{"ARMH0330", 0}, /* ARM DMA Controller DMA-330 */
|
{"ARMH0330", 0}, /* ARM DMA Controller DMA-330 */
|
||||||
{"ARMHC501", 0}, /* ARM CoreSight ETR */
|
|
||||||
{"ARMHC502", 0}, /* ARM CoreSight STM */
|
|
||||||
{"ARMHC503", 0}, /* ARM CoreSight Debug */
|
|
||||||
{"ARMHC979", 0}, /* ARM CoreSight TPIU */
|
|
||||||
{"ARMHC97C", 0}, /* ARM CoreSight SoC-400 TMC, SoC-600 ETF/ETB */
|
|
||||||
{"ARMHC98D", 0}, /* ARM CoreSight Dynamic Replicator */
|
|
||||||
{"ARMHC9CA", 0}, /* ARM CoreSight CATU */
|
|
||||||
{"ARMHC9FF", 0}, /* ARM CoreSight Dynamic Funnel */
|
|
||||||
{"", 0},
|
{"", 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,11 +7,13 @@
|
|||||||
* Author: Suzuki K Poulose <suzuki.poulose@arm.com>
|
* Author: Suzuki K Poulose <suzuki.poulose@arm.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
||||||
#include <linux/amba/bus.h>
|
#include <linux/amba/bus.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "coresight-catu.h"
|
#include "coresight-catu.h"
|
||||||
@ -502,28 +504,20 @@ static const struct coresight_ops catu_ops = {
|
|||||||
.helper_ops = &catu_helper_ops,
|
.helper_ops = &catu_helper_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int catu_probe(struct amba_device *adev, const struct amba_id *id)
|
static int __catu_probe(struct device *dev, struct resource *res)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u32 dma_mask;
|
u32 dma_mask;
|
||||||
struct catu_drvdata *drvdata;
|
struct catu_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
struct coresight_desc catu_desc;
|
struct coresight_desc catu_desc;
|
||||||
struct coresight_platform_data *pdata = NULL;
|
struct coresight_platform_data *pdata = NULL;
|
||||||
struct device *dev = &adev->dev;
|
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
|
|
||||||
catu_desc.name = coresight_alloc_device_name(&catu_devs, dev);
|
catu_desc.name = coresight_alloc_device_name(&catu_devs, dev);
|
||||||
if (!catu_desc.name)
|
if (!catu_desc.name)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
|
base = devm_ioremap_resource(dev, res);
|
||||||
if (!drvdata) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_set_drvdata(dev, drvdata);
|
|
||||||
base = devm_ioremap_resource(dev, &adev->res);
|
|
||||||
if (IS_ERR(base)) {
|
if (IS_ERR(base)) {
|
||||||
ret = PTR_ERR(base);
|
ret = PTR_ERR(base);
|
||||||
goto out;
|
goto out;
|
||||||
@ -567,19 +561,39 @@ static int catu_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
drvdata->csdev = coresight_register(&catu_desc);
|
drvdata->csdev = coresight_register(&catu_desc);
|
||||||
if (IS_ERR(drvdata->csdev))
|
if (IS_ERR(drvdata->csdev))
|
||||||
ret = PTR_ERR(drvdata->csdev);
|
ret = PTR_ERR(drvdata->csdev);
|
||||||
else
|
|
||||||
pm_runtime_put(&adev->dev);
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void catu_remove(struct amba_device *adev)
|
static int catu_probe(struct amba_device *adev, const struct amba_id *id)
|
||||||
{
|
{
|
||||||
struct catu_drvdata *drvdata = dev_get_drvdata(&adev->dev);
|
struct catu_drvdata *drvdata;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
drvdata = devm_kzalloc(&adev->dev, sizeof(*drvdata), GFP_KERNEL);
|
||||||
|
if (!drvdata)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
amba_set_drvdata(adev, drvdata);
|
||||||
|
ret = __catu_probe(&adev->dev, &adev->res);
|
||||||
|
if (!ret)
|
||||||
|
pm_runtime_put(&adev->dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __catu_remove(struct device *dev)
|
||||||
|
{
|
||||||
|
struct catu_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
|
|
||||||
coresight_unregister(drvdata->csdev);
|
coresight_unregister(drvdata->csdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void catu_remove(struct amba_device *adev)
|
||||||
|
{
|
||||||
|
__catu_remove(&adev->dev);
|
||||||
|
}
|
||||||
|
|
||||||
static struct amba_id catu_ids[] = {
|
static struct amba_id catu_ids[] = {
|
||||||
CS_AMBA_ID(0x000bb9ee),
|
CS_AMBA_ID(0x000bb9ee),
|
||||||
{},
|
{},
|
||||||
@ -598,13 +612,98 @@ static struct amba_driver catu_driver = {
|
|||||||
.id_table = catu_ids,
|
.id_table = catu_ids,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int catu_platform_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
struct catu_drvdata *drvdata;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
|
||||||
|
if (!drvdata)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev);
|
||||||
|
if (IS_ERR(drvdata->pclk))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
pm_runtime_get_noresume(&pdev->dev);
|
||||||
|
pm_runtime_set_active(&pdev->dev);
|
||||||
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
|
||||||
|
dev_set_drvdata(&pdev->dev, drvdata);
|
||||||
|
ret = __catu_probe(&pdev->dev, res);
|
||||||
|
pm_runtime_put(&pdev->dev);
|
||||||
|
if (ret) {
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
if (!IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_put(drvdata->pclk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void catu_platform_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct catu_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
if (WARN_ON(!drvdata))
|
||||||
|
return;
|
||||||
|
|
||||||
|
__catu_remove(&pdev->dev);
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
if (!IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_put(drvdata->pclk);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static int catu_runtime_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct catu_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_disable_unprepare(drvdata->pclk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int catu_runtime_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct catu_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_prepare_enable(drvdata->pclk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const struct dev_pm_ops catu_dev_pm_ops = {
|
||||||
|
SET_RUNTIME_PM_OPS(catu_runtime_suspend, catu_runtime_resume, NULL)
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI
|
||||||
|
static const struct acpi_device_id catu_acpi_ids[] = {
|
||||||
|
{"ARMHC9CA", 0, 0, 0}, /* ARM CoreSight CATU */
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(acpi, catu_acpi_ids);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct platform_driver catu_platform_driver = {
|
||||||
|
.probe = catu_platform_probe,
|
||||||
|
.remove_new = catu_platform_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "coresight-catu-platform",
|
||||||
|
.acpi_match_table = ACPI_PTR(catu_acpi_ids),
|
||||||
|
.suppress_bind_attrs = true,
|
||||||
|
.pm = &catu_dev_pm_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static int __init catu_init(void)
|
static int __init catu_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = amba_driver_register(&catu_driver);
|
ret = coresight_init_driver("catu", &catu_driver, &catu_platform_driver);
|
||||||
if (ret)
|
|
||||||
pr_info("Error registering catu driver\n");
|
|
||||||
tmc_etr_set_catu_ops(&etr_catu_buf_ops);
|
tmc_etr_set_catu_ops(&etr_catu_buf_ops);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -612,7 +711,7 @@ static int __init catu_init(void)
|
|||||||
static void __exit catu_exit(void)
|
static void __exit catu_exit(void)
|
||||||
{
|
{
|
||||||
tmc_etr_remove_catu_ops();
|
tmc_etr_remove_catu_ops();
|
||||||
amba_driver_unregister(&catu_driver);
|
coresight_remove_driver(&catu_driver, &catu_platform_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(catu_init);
|
module_init(catu_init);
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
#define CATU_IRQEN_OFF 0x0
|
#define CATU_IRQEN_OFF 0x0
|
||||||
|
|
||||||
struct catu_drvdata {
|
struct catu_drvdata {
|
||||||
|
struct clk *pclk;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct coresight_device *csdev;
|
struct coresight_device *csdev;
|
||||||
int irq;
|
int irq;
|
||||||
|
@ -1398,6 +1398,35 @@ static void __exit coresight_exit(void)
|
|||||||
module_init(coresight_init);
|
module_init(coresight_init);
|
||||||
module_exit(coresight_exit);
|
module_exit(coresight_exit);
|
||||||
|
|
||||||
|
int coresight_init_driver(const char *drv, struct amba_driver *amba_drv,
|
||||||
|
struct platform_driver *pdev_drv)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = amba_driver_register(amba_drv);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: error registering AMBA driver\n", drv);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = platform_driver_register(pdev_drv);
|
||||||
|
if (!ret)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
pr_err("%s: error registering platform driver\n", drv);
|
||||||
|
amba_driver_unregister(amba_drv);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(coresight_init_driver);
|
||||||
|
|
||||||
|
void coresight_remove_driver(struct amba_driver *amba_drv,
|
||||||
|
struct platform_driver *pdev_drv)
|
||||||
|
{
|
||||||
|
amba_driver_unregister(amba_drv);
|
||||||
|
platform_driver_unregister(pdev_drv);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(coresight_remove_driver);
|
||||||
|
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");
|
MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");
|
||||||
MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>");
|
MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>");
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
*
|
*
|
||||||
* Author: Leo Yan <leo.yan@linaro.org>
|
* Author: Leo Yan <leo.yan@linaro.org>
|
||||||
*/
|
*/
|
||||||
|
#include <linux/acpi.h>
|
||||||
#include <linux/amba/bus.h>
|
#include <linux/amba/bus.h>
|
||||||
#include <linux/coresight.h>
|
#include <linux/coresight.h>
|
||||||
#include <linux/cpu.h>
|
#include <linux/cpu.h>
|
||||||
@ -18,6 +19,7 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/panic_notifier.h>
|
#include <linux/panic_notifier.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm_qos.h>
|
#include <linux/pm_qos.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
@ -84,6 +86,7 @@
|
|||||||
#define DEBUG_WAIT_TIMEOUT 32000
|
#define DEBUG_WAIT_TIMEOUT 32000
|
||||||
|
|
||||||
struct debug_drvdata {
|
struct debug_drvdata {
|
||||||
|
struct clk *pclk;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
int cpu;
|
int cpu;
|
||||||
@ -557,18 +560,12 @@ static void debug_func_exit(void)
|
|||||||
debugfs_remove_recursive(debug_debugfs_dir);
|
debugfs_remove_recursive(debug_debugfs_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int debug_probe(struct amba_device *adev, const struct amba_id *id)
|
static int __debug_probe(struct device *dev, struct resource *res)
|
||||||
{
|
{
|
||||||
|
struct debug_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct device *dev = &adev->dev;
|
|
||||||
struct debug_drvdata *drvdata;
|
|
||||||
struct resource *res = &adev->res;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
|
|
||||||
if (!drvdata)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
drvdata->cpu = coresight_get_cpu(dev);
|
drvdata->cpu = coresight_get_cpu(dev);
|
||||||
if (drvdata->cpu < 0)
|
if (drvdata->cpu < 0)
|
||||||
return drvdata->cpu;
|
return drvdata->cpu;
|
||||||
@ -579,10 +576,7 @@ static int debug_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
drvdata->dev = &adev->dev;
|
drvdata->dev = dev;
|
||||||
amba_set_drvdata(adev, drvdata);
|
|
||||||
|
|
||||||
/* Validity for the resource is already checked by the AMBA core */
|
|
||||||
base = devm_ioremap_resource(dev, res);
|
base = devm_ioremap_resource(dev, res);
|
||||||
if (IS_ERR(base))
|
if (IS_ERR(base))
|
||||||
return PTR_ERR(base);
|
return PTR_ERR(base);
|
||||||
@ -629,10 +623,21 @@ err:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void debug_remove(struct amba_device *adev)
|
static int debug_probe(struct amba_device *adev, const struct amba_id *id)
|
||||||
{
|
{
|
||||||
struct device *dev = &adev->dev;
|
struct debug_drvdata *drvdata;
|
||||||
struct debug_drvdata *drvdata = amba_get_drvdata(adev);
|
|
||||||
|
drvdata = devm_kzalloc(&adev->dev, sizeof(*drvdata), GFP_KERNEL);
|
||||||
|
if (!drvdata)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
amba_set_drvdata(adev, drvdata);
|
||||||
|
return __debug_probe(&adev->dev, &adev->res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __debug_remove(struct device *dev)
|
||||||
|
{
|
||||||
|
struct debug_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
|
|
||||||
per_cpu(debug_drvdata, drvdata->cpu) = NULL;
|
per_cpu(debug_drvdata, drvdata->cpu) = NULL;
|
||||||
|
|
||||||
@ -646,6 +651,11 @@ static void debug_remove(struct amba_device *adev)
|
|||||||
debug_func_exit();
|
debug_func_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void debug_remove(struct amba_device *adev)
|
||||||
|
{
|
||||||
|
__debug_remove(&adev->dev);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct amba_cs_uci_id uci_id_debug[] = {
|
static const struct amba_cs_uci_id uci_id_debug[] = {
|
||||||
{
|
{
|
||||||
/* CPU Debug UCI data */
|
/* CPU Debug UCI data */
|
||||||
@ -677,7 +687,102 @@ static struct amba_driver debug_driver = {
|
|||||||
.id_table = debug_ids,
|
.id_table = debug_ids,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_amba_driver(debug_driver);
|
static int debug_platform_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
struct debug_drvdata *drvdata;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
|
||||||
|
if (!drvdata)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev);
|
||||||
|
if (IS_ERR(drvdata->pclk))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
dev_set_drvdata(&pdev->dev, drvdata);
|
||||||
|
pm_runtime_get_noresume(&pdev->dev);
|
||||||
|
pm_runtime_set_active(&pdev->dev);
|
||||||
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
|
||||||
|
ret = __debug_probe(&pdev->dev, res);
|
||||||
|
if (ret) {
|
||||||
|
pm_runtime_put_noidle(&pdev->dev);
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
if (!IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_put(drvdata->pclk);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void debug_platform_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct debug_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
if (WARN_ON(!drvdata))
|
||||||
|
return;
|
||||||
|
|
||||||
|
__debug_remove(&pdev->dev);
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
if (!IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_put(drvdata->pclk);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI
|
||||||
|
static const struct acpi_device_id debug_platform_ids[] = {
|
||||||
|
{"ARMHC503", 0, 0, 0}, /* ARM CoreSight Debug */
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(acpi, debug_platform_ids);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static int debug_runtime_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct debug_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_disable_unprepare(drvdata->pclk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int debug_runtime_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct debug_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_prepare_enable(drvdata->pclk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const struct dev_pm_ops debug_dev_pm_ops = {
|
||||||
|
SET_RUNTIME_PM_OPS(debug_runtime_suspend, debug_runtime_resume, NULL)
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver debug_platform_driver = {
|
||||||
|
.probe = debug_platform_probe,
|
||||||
|
.remove_new = debug_platform_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "coresight-debug-platform",
|
||||||
|
.acpi_match_table = ACPI_PTR(debug_platform_ids),
|
||||||
|
.suppress_bind_attrs = true,
|
||||||
|
.pm = &debug_dev_pm_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init debug_init(void)
|
||||||
|
{
|
||||||
|
return coresight_init_driver("debug", &debug_driver, &debug_platform_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit debug_exit(void)
|
||||||
|
{
|
||||||
|
coresight_remove_driver(&debug_driver, &debug_platform_driver);
|
||||||
|
}
|
||||||
|
module_init(debug_init);
|
||||||
|
module_exit(debug_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
|
MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
|
||||||
MODULE_DESCRIPTION("ARM Coresight CPU Debug Driver");
|
MODULE_DESCRIPTION("ARM Coresight CPU Debug Driver");
|
||||||
|
@ -1240,6 +1240,8 @@ static void etm4_init_arch_data(void *info)
|
|||||||
drvdata->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0);
|
drvdata->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0);
|
||||||
/* QSUPP, bits[16:15] Q element support field */
|
/* QSUPP, bits[16:15] Q element support field */
|
||||||
drvdata->q_support = FIELD_GET(TRCIDR0_QSUPP_MASK, etmidr0);
|
drvdata->q_support = FIELD_GET(TRCIDR0_QSUPP_MASK, etmidr0);
|
||||||
|
if (drvdata->q_support)
|
||||||
|
drvdata->q_filt = !!(etmidr0 & TRCIDR0_QFILT);
|
||||||
/* TSSIZE, bits[28:24] Global timestamp size field */
|
/* TSSIZE, bits[28:24] Global timestamp size field */
|
||||||
drvdata->ts_size = FIELD_GET(TRCIDR0_TSSIZE_MASK, etmidr0);
|
drvdata->ts_size = FIELD_GET(TRCIDR0_TSSIZE_MASK, etmidr0);
|
||||||
|
|
||||||
@ -1732,16 +1734,14 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
|
|||||||
state->trcccctlr = etm4x_read32(csa, TRCCCCTLR);
|
state->trcccctlr = etm4x_read32(csa, TRCCCCTLR);
|
||||||
state->trcbbctlr = etm4x_read32(csa, TRCBBCTLR);
|
state->trcbbctlr = etm4x_read32(csa, TRCBBCTLR);
|
||||||
state->trctraceidr = etm4x_read32(csa, TRCTRACEIDR);
|
state->trctraceidr = etm4x_read32(csa, TRCTRACEIDR);
|
||||||
state->trcqctlr = etm4x_read32(csa, TRCQCTLR);
|
if (drvdata->q_filt)
|
||||||
|
state->trcqctlr = etm4x_read32(csa, TRCQCTLR);
|
||||||
|
|
||||||
state->trcvictlr = etm4x_read32(csa, TRCVICTLR);
|
state->trcvictlr = etm4x_read32(csa, TRCVICTLR);
|
||||||
state->trcviiectlr = etm4x_read32(csa, TRCVIIECTLR);
|
state->trcviiectlr = etm4x_read32(csa, TRCVIIECTLR);
|
||||||
state->trcvissctlr = etm4x_read32(csa, TRCVISSCTLR);
|
state->trcvissctlr = etm4x_read32(csa, TRCVISSCTLR);
|
||||||
if (drvdata->nr_pe_cmp)
|
if (drvdata->nr_pe_cmp)
|
||||||
state->trcvipcssctlr = etm4x_read32(csa, TRCVIPCSSCTLR);
|
state->trcvipcssctlr = etm4x_read32(csa, TRCVIPCSSCTLR);
|
||||||
state->trcvdctlr = etm4x_read32(csa, TRCVDCTLR);
|
|
||||||
state->trcvdsacctlr = etm4x_read32(csa, TRCVDSACCTLR);
|
|
||||||
state->trcvdarcctlr = etm4x_read32(csa, TRCVDARCCTLR);
|
|
||||||
|
|
||||||
for (i = 0; i < drvdata->nrseqstate - 1; i++)
|
for (i = 0; i < drvdata->nrseqstate - 1; i++)
|
||||||
state->trcseqevr[i] = etm4x_read32(csa, TRCSEQEVRn(i));
|
state->trcseqevr[i] = etm4x_read32(csa, TRCSEQEVRn(i));
|
||||||
@ -1758,7 +1758,8 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
|
|||||||
state->trccntvr[i] = etm4x_read32(csa, TRCCNTVRn(i));
|
state->trccntvr[i] = etm4x_read32(csa, TRCCNTVRn(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < drvdata->nr_resource * 2; i++)
|
/* Resource selector pair 0 is reserved */
|
||||||
|
for (i = 2; i < drvdata->nr_resource * 2; i++)
|
||||||
state->trcrsctlr[i] = etm4x_read32(csa, TRCRSCTLRn(i));
|
state->trcrsctlr[i] = etm4x_read32(csa, TRCRSCTLRn(i));
|
||||||
|
|
||||||
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
|
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
|
||||||
@ -1843,8 +1844,10 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct etmv4_save_state *state = drvdata->save_state;
|
struct etmv4_save_state *state = drvdata->save_state;
|
||||||
struct csdev_access tmp_csa = CSDEV_ACCESS_IOMEM(drvdata->base);
|
struct csdev_access *csa = &drvdata->csdev->access;
|
||||||
struct csdev_access *csa = &tmp_csa;
|
|
||||||
|
if (WARN_ON(!drvdata->csdev))
|
||||||
|
return;
|
||||||
|
|
||||||
etm4_cs_unlock(drvdata, csa);
|
etm4_cs_unlock(drvdata, csa);
|
||||||
etm4x_relaxed_write32(csa, state->trcclaimset, TRCCLAIMSET);
|
etm4x_relaxed_write32(csa, state->trcclaimset, TRCCLAIMSET);
|
||||||
@ -1863,16 +1866,14 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
|
|||||||
etm4x_relaxed_write32(csa, state->trcccctlr, TRCCCCTLR);
|
etm4x_relaxed_write32(csa, state->trcccctlr, TRCCCCTLR);
|
||||||
etm4x_relaxed_write32(csa, state->trcbbctlr, TRCBBCTLR);
|
etm4x_relaxed_write32(csa, state->trcbbctlr, TRCBBCTLR);
|
||||||
etm4x_relaxed_write32(csa, state->trctraceidr, TRCTRACEIDR);
|
etm4x_relaxed_write32(csa, state->trctraceidr, TRCTRACEIDR);
|
||||||
etm4x_relaxed_write32(csa, state->trcqctlr, TRCQCTLR);
|
if (drvdata->q_filt)
|
||||||
|
etm4x_relaxed_write32(csa, state->trcqctlr, TRCQCTLR);
|
||||||
|
|
||||||
etm4x_relaxed_write32(csa, state->trcvictlr, TRCVICTLR);
|
etm4x_relaxed_write32(csa, state->trcvictlr, TRCVICTLR);
|
||||||
etm4x_relaxed_write32(csa, state->trcviiectlr, TRCVIIECTLR);
|
etm4x_relaxed_write32(csa, state->trcviiectlr, TRCVIIECTLR);
|
||||||
etm4x_relaxed_write32(csa, state->trcvissctlr, TRCVISSCTLR);
|
etm4x_relaxed_write32(csa, state->trcvissctlr, TRCVISSCTLR);
|
||||||
if (drvdata->nr_pe_cmp)
|
if (drvdata->nr_pe_cmp)
|
||||||
etm4x_relaxed_write32(csa, state->trcvipcssctlr, TRCVIPCSSCTLR);
|
etm4x_relaxed_write32(csa, state->trcvipcssctlr, TRCVIPCSSCTLR);
|
||||||
etm4x_relaxed_write32(csa, state->trcvdctlr, TRCVDCTLR);
|
|
||||||
etm4x_relaxed_write32(csa, state->trcvdsacctlr, TRCVDSACCTLR);
|
|
||||||
etm4x_relaxed_write32(csa, state->trcvdarcctlr, TRCVDARCCTLR);
|
|
||||||
|
|
||||||
for (i = 0; i < drvdata->nrseqstate - 1; i++)
|
for (i = 0; i < drvdata->nrseqstate - 1; i++)
|
||||||
etm4x_relaxed_write32(csa, state->trcseqevr[i], TRCSEQEVRn(i));
|
etm4x_relaxed_write32(csa, state->trcseqevr[i], TRCSEQEVRn(i));
|
||||||
@ -1889,7 +1890,8 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
|
|||||||
etm4x_relaxed_write32(csa, state->trccntvr[i], TRCCNTVRn(i));
|
etm4x_relaxed_write32(csa, state->trccntvr[i], TRCCNTVRn(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < drvdata->nr_resource * 2; i++)
|
/* Resource selector pair 0 is reserved */
|
||||||
|
for (i = 2; i < drvdata->nr_resource * 2; i++)
|
||||||
etm4x_relaxed_write32(csa, state->trcrsctlr[i], TRCRSCTLRn(i));
|
etm4x_relaxed_write32(csa, state->trcrsctlr[i], TRCRSCTLRn(i));
|
||||||
|
|
||||||
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
|
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
|
||||||
@ -2213,6 +2215,9 @@ static int etm4_probe_platform_dev(struct platform_device *pdev)
|
|||||||
ret = etm4_probe(&pdev->dev);
|
ret = etm4_probe(&pdev->dev);
|
||||||
|
|
||||||
pm_runtime_put(&pdev->dev);
|
pm_runtime_put(&pdev->dev);
|
||||||
|
if (ret)
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,9 +43,6 @@
|
|||||||
#define TRCVIIECTLR 0x084
|
#define TRCVIIECTLR 0x084
|
||||||
#define TRCVISSCTLR 0x088
|
#define TRCVISSCTLR 0x088
|
||||||
#define TRCVIPCSSCTLR 0x08C
|
#define TRCVIPCSSCTLR 0x08C
|
||||||
#define TRCVDCTLR 0x0A0
|
|
||||||
#define TRCVDSACCTLR 0x0A4
|
|
||||||
#define TRCVDARCCTLR 0x0A8
|
|
||||||
/* Derived resources registers */
|
/* Derived resources registers */
|
||||||
#define TRCSEQEVRn(n) (0x100 + (n * 4)) /* n = 0-2 */
|
#define TRCSEQEVRn(n) (0x100 + (n * 4)) /* n = 0-2 */
|
||||||
#define TRCSEQRSTEVR 0x118
|
#define TRCSEQRSTEVR 0x118
|
||||||
@ -90,9 +87,6 @@
|
|||||||
/* Address Comparator registers n = 0-15 */
|
/* Address Comparator registers n = 0-15 */
|
||||||
#define TRCACVRn(n) (0x400 + (n * 8))
|
#define TRCACVRn(n) (0x400 + (n * 8))
|
||||||
#define TRCACATRn(n) (0x480 + (n * 8))
|
#define TRCACATRn(n) (0x480 + (n * 8))
|
||||||
/* Data Value Comparator Value registers, n = 0-7 */
|
|
||||||
#define TRCDVCVRn(n) (0x500 + (n * 16))
|
|
||||||
#define TRCDVCMRn(n) (0x580 + (n * 16))
|
|
||||||
/* ContextID/Virtual ContextID comparators, n = 0-7 */
|
/* ContextID/Virtual ContextID comparators, n = 0-7 */
|
||||||
#define TRCCIDCVRn(n) (0x600 + (n * 8))
|
#define TRCCIDCVRn(n) (0x600 + (n * 8))
|
||||||
#define TRCVMIDCVRn(n) (0x640 + (n * 8))
|
#define TRCVMIDCVRn(n) (0x640 + (n * 8))
|
||||||
@ -141,6 +135,7 @@
|
|||||||
#define TRCIDR0_TRCCCI BIT(7)
|
#define TRCIDR0_TRCCCI BIT(7)
|
||||||
#define TRCIDR0_RETSTACK BIT(9)
|
#define TRCIDR0_RETSTACK BIT(9)
|
||||||
#define TRCIDR0_NUMEVENT_MASK GENMASK(11, 10)
|
#define TRCIDR0_NUMEVENT_MASK GENMASK(11, 10)
|
||||||
|
#define TRCIDR0_QFILT BIT(14)
|
||||||
#define TRCIDR0_QSUPP_MASK GENMASK(16, 15)
|
#define TRCIDR0_QSUPP_MASK GENMASK(16, 15)
|
||||||
#define TRCIDR0_TSSIZE_MASK GENMASK(28, 24)
|
#define TRCIDR0_TSSIZE_MASK GENMASK(28, 24)
|
||||||
|
|
||||||
@ -272,9 +267,6 @@
|
|||||||
/* List of registers accessible via System instructions */
|
/* List of registers accessible via System instructions */
|
||||||
#define ETM4x_ONLY_SYSREG_LIST(op, val) \
|
#define ETM4x_ONLY_SYSREG_LIST(op, val) \
|
||||||
CASE_##op((val), TRCPROCSELR) \
|
CASE_##op((val), TRCPROCSELR) \
|
||||||
CASE_##op((val), TRCVDCTLR) \
|
|
||||||
CASE_##op((val), TRCVDSACCTLR) \
|
|
||||||
CASE_##op((val), TRCVDARCCTLR) \
|
|
||||||
CASE_##op((val), TRCOSLAR)
|
CASE_##op((val), TRCOSLAR)
|
||||||
|
|
||||||
#define ETM_COMMON_SYSREG_LIST(op, val) \
|
#define ETM_COMMON_SYSREG_LIST(op, val) \
|
||||||
@ -422,22 +414,6 @@
|
|||||||
CASE_##op((val), TRCACATRn(13)) \
|
CASE_##op((val), TRCACATRn(13)) \
|
||||||
CASE_##op((val), TRCACATRn(14)) \
|
CASE_##op((val), TRCACATRn(14)) \
|
||||||
CASE_##op((val), TRCACATRn(15)) \
|
CASE_##op((val), TRCACATRn(15)) \
|
||||||
CASE_##op((val), TRCDVCVRn(0)) \
|
|
||||||
CASE_##op((val), TRCDVCVRn(1)) \
|
|
||||||
CASE_##op((val), TRCDVCVRn(2)) \
|
|
||||||
CASE_##op((val), TRCDVCVRn(3)) \
|
|
||||||
CASE_##op((val), TRCDVCVRn(4)) \
|
|
||||||
CASE_##op((val), TRCDVCVRn(5)) \
|
|
||||||
CASE_##op((val), TRCDVCVRn(6)) \
|
|
||||||
CASE_##op((val), TRCDVCVRn(7)) \
|
|
||||||
CASE_##op((val), TRCDVCMRn(0)) \
|
|
||||||
CASE_##op((val), TRCDVCMRn(1)) \
|
|
||||||
CASE_##op((val), TRCDVCMRn(2)) \
|
|
||||||
CASE_##op((val), TRCDVCMRn(3)) \
|
|
||||||
CASE_##op((val), TRCDVCMRn(4)) \
|
|
||||||
CASE_##op((val), TRCDVCMRn(5)) \
|
|
||||||
CASE_##op((val), TRCDVCMRn(6)) \
|
|
||||||
CASE_##op((val), TRCDVCMRn(7)) \
|
|
||||||
CASE_##op((val), TRCCIDCVRn(0)) \
|
CASE_##op((val), TRCCIDCVRn(0)) \
|
||||||
CASE_##op((val), TRCCIDCVRn(1)) \
|
CASE_##op((val), TRCCIDCVRn(1)) \
|
||||||
CASE_##op((val), TRCCIDCVRn(2)) \
|
CASE_##op((val), TRCCIDCVRn(2)) \
|
||||||
@ -907,9 +883,6 @@ struct etmv4_save_state {
|
|||||||
u32 trcviiectlr;
|
u32 trcviiectlr;
|
||||||
u32 trcvissctlr;
|
u32 trcvissctlr;
|
||||||
u32 trcvipcssctlr;
|
u32 trcvipcssctlr;
|
||||||
u32 trcvdctlr;
|
|
||||||
u32 trcvdsacctlr;
|
|
||||||
u32 trcvdarcctlr;
|
|
||||||
|
|
||||||
u32 trcseqevr[ETM_MAX_SEQ_STATES];
|
u32 trcseqevr[ETM_MAX_SEQ_STATES];
|
||||||
u32 trcseqrstevr;
|
u32 trcseqrstevr;
|
||||||
@ -982,6 +955,7 @@ struct etmv4_save_state {
|
|||||||
* @os_unlock: True if access to management registers is allowed.
|
* @os_unlock: True if access to management registers is allowed.
|
||||||
* @instrp0: Tracing of load and store instructions
|
* @instrp0: Tracing of load and store instructions
|
||||||
* as P0 elements is supported.
|
* as P0 elements is supported.
|
||||||
|
* @q_filt: Q element filtering support, if Q elements are supported.
|
||||||
* @trcbb: Indicates if the trace unit supports branch broadcast tracing.
|
* @trcbb: Indicates if the trace unit supports branch broadcast tracing.
|
||||||
* @trccond: If the trace unit supports conditional
|
* @trccond: If the trace unit supports conditional
|
||||||
* instruction tracing.
|
* instruction tracing.
|
||||||
@ -1044,6 +1018,7 @@ struct etmv4_drvdata {
|
|||||||
bool boot_enable;
|
bool boot_enable;
|
||||||
bool os_unlock;
|
bool os_unlock;
|
||||||
bool instrp0;
|
bool instrp0;
|
||||||
|
bool q_filt;
|
||||||
bool trcbb;
|
bool trcbb;
|
||||||
bool trccond;
|
bool trccond;
|
||||||
bool retstack;
|
bool retstack;
|
||||||
|
@ -36,6 +36,7 @@ DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel");
|
|||||||
* struct funnel_drvdata - specifics associated to a funnel component
|
* struct funnel_drvdata - specifics associated to a funnel component
|
||||||
* @base: memory mapped base address for this component.
|
* @base: memory mapped base address for this component.
|
||||||
* @atclk: optional clock for the core parts of the funnel.
|
* @atclk: optional clock for the core parts of the funnel.
|
||||||
|
* @pclk: APB clock if present, otherwise NULL
|
||||||
* @csdev: component vitals needed by the framework.
|
* @csdev: component vitals needed by the framework.
|
||||||
* @priority: port selection order.
|
* @priority: port selection order.
|
||||||
* @spinlock: serialize enable/disable operations.
|
* @spinlock: serialize enable/disable operations.
|
||||||
@ -43,6 +44,7 @@ DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel");
|
|||||||
struct funnel_drvdata {
|
struct funnel_drvdata {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct clk *atclk;
|
struct clk *atclk;
|
||||||
|
struct clk *pclk;
|
||||||
struct coresight_device *csdev;
|
struct coresight_device *csdev;
|
||||||
unsigned long priority;
|
unsigned long priority;
|
||||||
spinlock_t spinlock;
|
spinlock_t spinlock;
|
||||||
@ -236,6 +238,10 @@ static int funnel_probe(struct device *dev, struct resource *res)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drvdata->pclk = coresight_get_enable_apb_pclk(dev);
|
||||||
|
if (IS_ERR(drvdata->pclk))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Map the device base for dynamic-funnel, which has been
|
* Map the device base for dynamic-funnel, which has been
|
||||||
* validated by AMBA core.
|
* validated by AMBA core.
|
||||||
@ -272,12 +278,13 @@ static int funnel_probe(struct device *dev, struct resource *res)
|
|||||||
goto out_disable_clk;
|
goto out_disable_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_runtime_put(dev);
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
out_disable_clk:
|
out_disable_clk:
|
||||||
if (ret && !IS_ERR_OR_NULL(drvdata->atclk))
|
if (ret && !IS_ERR_OR_NULL(drvdata->atclk))
|
||||||
clk_disable_unprepare(drvdata->atclk);
|
clk_disable_unprepare(drvdata->atclk);
|
||||||
|
if (ret && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_disable_unprepare(drvdata->pclk);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,6 +305,9 @@ static int funnel_runtime_suspend(struct device *dev)
|
|||||||
if (drvdata && !IS_ERR(drvdata->atclk))
|
if (drvdata && !IS_ERR(drvdata->atclk))
|
||||||
clk_disable_unprepare(drvdata->atclk);
|
clk_disable_unprepare(drvdata->atclk);
|
||||||
|
|
||||||
|
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_disable_unprepare(drvdata->pclk);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,6 +318,8 @@ static int funnel_runtime_resume(struct device *dev)
|
|||||||
if (drvdata && !IS_ERR(drvdata->atclk))
|
if (drvdata && !IS_ERR(drvdata->atclk))
|
||||||
clk_prepare_enable(drvdata->atclk);
|
clk_prepare_enable(drvdata->atclk);
|
||||||
|
|
||||||
|
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_prepare_enable(drvdata->pclk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -316,55 +328,61 @@ static const struct dev_pm_ops funnel_dev_pm_ops = {
|
|||||||
SET_RUNTIME_PM_OPS(funnel_runtime_suspend, funnel_runtime_resume, NULL)
|
SET_RUNTIME_PM_OPS(funnel_runtime_suspend, funnel_runtime_resume, NULL)
|
||||||
};
|
};
|
||||||
|
|
||||||
static int static_funnel_probe(struct platform_device *pdev)
|
static int funnel_platform_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pm_runtime_get_noresume(&pdev->dev);
|
pm_runtime_get_noresume(&pdev->dev);
|
||||||
pm_runtime_set_active(&pdev->dev);
|
pm_runtime_set_active(&pdev->dev);
|
||||||
pm_runtime_enable(&pdev->dev);
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
|
||||||
/* Static funnel do not have programming base */
|
ret = funnel_probe(&pdev->dev, res);
|
||||||
ret = funnel_probe(&pdev->dev, NULL);
|
pm_runtime_put(&pdev->dev);
|
||||||
|
if (ret)
|
||||||
if (ret) {
|
|
||||||
pm_runtime_put_noidle(&pdev->dev);
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void static_funnel_remove(struct platform_device *pdev)
|
static void funnel_platform_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
struct funnel_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
if (WARN_ON(!drvdata))
|
||||||
|
return;
|
||||||
|
|
||||||
funnel_remove(&pdev->dev);
|
funnel_remove(&pdev->dev);
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
if (!IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_put(drvdata->pclk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id static_funnel_match[] = {
|
static const struct of_device_id funnel_match[] = {
|
||||||
{.compatible = "arm,coresight-static-funnel"},
|
{.compatible = "arm,coresight-static-funnel"},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(of, static_funnel_match);
|
MODULE_DEVICE_TABLE(of, funnel_match);
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
static const struct acpi_device_id static_funnel_ids[] = {
|
static const struct acpi_device_id funnel_acpi_ids[] = {
|
||||||
{"ARMHC9FE", 0, 0, 0},
|
{"ARMHC9FE", 0, 0, 0}, /* ARM Coresight Static Funnel */
|
||||||
|
{"ARMHC9FF", 0, 0, 0}, /* ARM CoreSight Dynamic Funnel */
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(acpi, static_funnel_ids);
|
MODULE_DEVICE_TABLE(acpi, funnel_acpi_ids);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct platform_driver static_funnel_driver = {
|
static struct platform_driver funnel_driver = {
|
||||||
.probe = static_funnel_probe,
|
.probe = funnel_platform_probe,
|
||||||
.remove_new = static_funnel_remove,
|
.remove_new = funnel_platform_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "coresight-static-funnel",
|
.name = "coresight-funnel",
|
||||||
/* THIS_MODULE is taken care of by platform_driver_register() */
|
/* THIS_MODULE is taken care of by platform_driver_register() */
|
||||||
.of_match_table = static_funnel_match,
|
.of_match_table = funnel_match,
|
||||||
.acpi_match_table = ACPI_PTR(static_funnel_ids),
|
.acpi_match_table = ACPI_PTR(funnel_acpi_ids),
|
||||||
.pm = &funnel_dev_pm_ops,
|
.pm = &funnel_dev_pm_ops,
|
||||||
.suppress_bind_attrs = true,
|
.suppress_bind_attrs = true,
|
||||||
},
|
},
|
||||||
@ -373,7 +391,13 @@ static struct platform_driver static_funnel_driver = {
|
|||||||
static int dynamic_funnel_probe(struct amba_device *adev,
|
static int dynamic_funnel_probe(struct amba_device *adev,
|
||||||
const struct amba_id *id)
|
const struct amba_id *id)
|
||||||
{
|
{
|
||||||
return funnel_probe(&adev->dev, &adev->res);
|
int ret;
|
||||||
|
|
||||||
|
ret = funnel_probe(&adev->dev, &adev->res);
|
||||||
|
if (!ret)
|
||||||
|
pm_runtime_put(&adev->dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dynamic_funnel_remove(struct amba_device *adev)
|
static void dynamic_funnel_remove(struct amba_device *adev)
|
||||||
@ -410,27 +434,12 @@ static struct amba_driver dynamic_funnel_driver = {
|
|||||||
|
|
||||||
static int __init funnel_init(void)
|
static int __init funnel_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
return coresight_init_driver("funnel", &dynamic_funnel_driver, &funnel_driver);
|
||||||
|
|
||||||
ret = platform_driver_register(&static_funnel_driver);
|
|
||||||
if (ret) {
|
|
||||||
pr_info("Error registering platform driver\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = amba_driver_register(&dynamic_funnel_driver);
|
|
||||||
if (ret) {
|
|
||||||
pr_info("Error registering amba driver\n");
|
|
||||||
platform_driver_unregister(&static_funnel_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit funnel_exit(void)
|
static void __exit funnel_exit(void)
|
||||||
{
|
{
|
||||||
platform_driver_unregister(&static_funnel_driver);
|
coresight_remove_driver(&dynamic_funnel_driver, &funnel_driver);
|
||||||
amba_driver_unregister(&dynamic_funnel_driver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(funnel_init);
|
module_init(funnel_init);
|
||||||
|
@ -222,6 +222,16 @@ static inline void *coresight_get_uci_data(const struct amba_id *id)
|
|||||||
return uci_id->data;
|
return uci_id->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void *coresight_get_uci_data_from_amba(const struct amba_id *table, u32 pid)
|
||||||
|
{
|
||||||
|
while (table->mask) {
|
||||||
|
if ((pid & table->mask) == table->id)
|
||||||
|
return coresight_get_uci_data(table);
|
||||||
|
table++;
|
||||||
|
};
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void coresight_release_platform_data(struct coresight_device *csdev,
|
void coresight_release_platform_data(struct coresight_device *csdev,
|
||||||
struct device *dev,
|
struct device *dev,
|
||||||
struct coresight_platform_data *pdata);
|
struct coresight_platform_data *pdata);
|
||||||
|
@ -31,6 +31,7 @@ DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator");
|
|||||||
* @base: memory mapped base address for this component. Also indicates
|
* @base: memory mapped base address for this component. Also indicates
|
||||||
* whether this one is programmable or not.
|
* whether this one is programmable or not.
|
||||||
* @atclk: optional clock for the core parts of the replicator.
|
* @atclk: optional clock for the core parts of the replicator.
|
||||||
|
* @pclk: APB clock if present, otherwise NULL
|
||||||
* @csdev: component vitals needed by the framework
|
* @csdev: component vitals needed by the framework
|
||||||
* @spinlock: serialize enable/disable operations.
|
* @spinlock: serialize enable/disable operations.
|
||||||
* @check_idfilter_val: check if the context is lost upon clock removal.
|
* @check_idfilter_val: check if the context is lost upon clock removal.
|
||||||
@ -38,6 +39,7 @@ DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator");
|
|||||||
struct replicator_drvdata {
|
struct replicator_drvdata {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct clk *atclk;
|
struct clk *atclk;
|
||||||
|
struct clk *pclk;
|
||||||
struct coresight_device *csdev;
|
struct coresight_device *csdev;
|
||||||
spinlock_t spinlock;
|
spinlock_t spinlock;
|
||||||
bool check_idfilter_val;
|
bool check_idfilter_val;
|
||||||
@ -243,6 +245,10 @@ static int replicator_probe(struct device *dev, struct resource *res)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drvdata->pclk = coresight_get_enable_apb_pclk(dev);
|
||||||
|
if (IS_ERR(drvdata->pclk))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Map the device base for dynamic-replicator, which has been
|
* Map the device base for dynamic-replicator, which has been
|
||||||
* validated by AMBA core
|
* validated by AMBA core
|
||||||
@ -285,11 +291,12 @@ static int replicator_probe(struct device *dev, struct resource *res)
|
|||||||
}
|
}
|
||||||
|
|
||||||
replicator_reset(drvdata);
|
replicator_reset(drvdata);
|
||||||
pm_runtime_put(dev);
|
|
||||||
|
|
||||||
out_disable_clk:
|
out_disable_clk:
|
||||||
if (ret && !IS_ERR_OR_NULL(drvdata->atclk))
|
if (ret && !IS_ERR_OR_NULL(drvdata->atclk))
|
||||||
clk_disable_unprepare(drvdata->atclk);
|
clk_disable_unprepare(drvdata->atclk);
|
||||||
|
if (ret && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_disable_unprepare(drvdata->pclk);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,29 +308,34 @@ static int replicator_remove(struct device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int static_replicator_probe(struct platform_device *pdev)
|
static int replicator_platform_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pm_runtime_get_noresume(&pdev->dev);
|
pm_runtime_get_noresume(&pdev->dev);
|
||||||
pm_runtime_set_active(&pdev->dev);
|
pm_runtime_set_active(&pdev->dev);
|
||||||
pm_runtime_enable(&pdev->dev);
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
|
||||||
/* Static replicators do not have programming base */
|
ret = replicator_probe(&pdev->dev, res);
|
||||||
ret = replicator_probe(&pdev->dev, NULL);
|
pm_runtime_put(&pdev->dev);
|
||||||
|
if (ret)
|
||||||
if (ret) {
|
|
||||||
pm_runtime_put_noidle(&pdev->dev);
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void static_replicator_remove(struct platform_device *pdev)
|
static void replicator_platform_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
struct replicator_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
if (WARN_ON(!drvdata))
|
||||||
|
return;
|
||||||
|
|
||||||
replicator_remove(&pdev->dev);
|
replicator_remove(&pdev->dev);
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
if (!IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_put(drvdata->pclk);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
@ -334,6 +346,8 @@ static int replicator_runtime_suspend(struct device *dev)
|
|||||||
if (drvdata && !IS_ERR(drvdata->atclk))
|
if (drvdata && !IS_ERR(drvdata->atclk))
|
||||||
clk_disable_unprepare(drvdata->atclk);
|
clk_disable_unprepare(drvdata->atclk);
|
||||||
|
|
||||||
|
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_disable_unprepare(drvdata->pclk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,6 +358,8 @@ static int replicator_runtime_resume(struct device *dev)
|
|||||||
if (drvdata && !IS_ERR(drvdata->atclk))
|
if (drvdata && !IS_ERR(drvdata->atclk))
|
||||||
clk_prepare_enable(drvdata->atclk);
|
clk_prepare_enable(drvdata->atclk);
|
||||||
|
|
||||||
|
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_prepare_enable(drvdata->pclk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -353,31 +369,32 @@ static const struct dev_pm_ops replicator_dev_pm_ops = {
|
|||||||
replicator_runtime_resume, NULL)
|
replicator_runtime_resume, NULL)
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id static_replicator_match[] = {
|
static const struct of_device_id replicator_match[] = {
|
||||||
{.compatible = "arm,coresight-replicator"},
|
{.compatible = "arm,coresight-replicator"},
|
||||||
{.compatible = "arm,coresight-static-replicator"},
|
{.compatible = "arm,coresight-static-replicator"},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(of, static_replicator_match);
|
MODULE_DEVICE_TABLE(of, replicator_match);
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
static const struct acpi_device_id static_replicator_acpi_ids[] = {
|
static const struct acpi_device_id replicator_acpi_ids[] = {
|
||||||
{"ARMHC985", 0, 0, 0}, /* ARM CoreSight Static Replicator */
|
{"ARMHC985", 0, 0, 0}, /* ARM CoreSight Static Replicator */
|
||||||
|
{"ARMHC98D", 0, 0, 0}, /* ARM CoreSight Dynamic Replicator */
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(acpi, static_replicator_acpi_ids);
|
MODULE_DEVICE_TABLE(acpi, replicator_acpi_ids);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct platform_driver static_replicator_driver = {
|
static struct platform_driver replicator_driver = {
|
||||||
.probe = static_replicator_probe,
|
.probe = replicator_platform_probe,
|
||||||
.remove_new = static_replicator_remove,
|
.remove_new = replicator_platform_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "coresight-static-replicator",
|
.name = "coresight-replicator",
|
||||||
/* THIS_MODULE is taken care of by platform_driver_register() */
|
/* THIS_MODULE is taken care of by platform_driver_register() */
|
||||||
.of_match_table = of_match_ptr(static_replicator_match),
|
.of_match_table = of_match_ptr(replicator_match),
|
||||||
.acpi_match_table = ACPI_PTR(static_replicator_acpi_ids),
|
.acpi_match_table = ACPI_PTR(replicator_acpi_ids),
|
||||||
.pm = &replicator_dev_pm_ops,
|
.pm = &replicator_dev_pm_ops,
|
||||||
.suppress_bind_attrs = true,
|
.suppress_bind_attrs = true,
|
||||||
},
|
},
|
||||||
@ -386,7 +403,13 @@ static struct platform_driver static_replicator_driver = {
|
|||||||
static int dynamic_replicator_probe(struct amba_device *adev,
|
static int dynamic_replicator_probe(struct amba_device *adev,
|
||||||
const struct amba_id *id)
|
const struct amba_id *id)
|
||||||
{
|
{
|
||||||
return replicator_probe(&adev->dev, &adev->res);
|
int ret;
|
||||||
|
|
||||||
|
ret = replicator_probe(&adev->dev, &adev->res);
|
||||||
|
if (!ret)
|
||||||
|
pm_runtime_put(&adev->dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dynamic_replicator_remove(struct amba_device *adev)
|
static void dynamic_replicator_remove(struct amba_device *adev)
|
||||||
@ -416,27 +439,12 @@ static struct amba_driver dynamic_replicator_driver = {
|
|||||||
|
|
||||||
static int __init replicator_init(void)
|
static int __init replicator_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver);
|
||||||
|
|
||||||
ret = platform_driver_register(&static_replicator_driver);
|
|
||||||
if (ret) {
|
|
||||||
pr_info("Error registering platform driver\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = amba_driver_register(&dynamic_replicator_driver);
|
|
||||||
if (ret) {
|
|
||||||
pr_info("Error registering amba driver\n");
|
|
||||||
platform_driver_unregister(&static_replicator_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit replicator_exit(void)
|
static void __exit replicator_exit(void)
|
||||||
{
|
{
|
||||||
platform_driver_unregister(&static_replicator_driver);
|
coresight_remove_driver(&dynamic_replicator_driver, &replicator_driver);
|
||||||
amba_driver_unregister(&dynamic_replicator_driver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(replicator_init);
|
module_init(replicator_init);
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include <linux/perf_event.h>
|
#include <linux/perf_event.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/stm.h>
|
#include <linux/stm.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
#include "coresight-priv.h"
|
#include "coresight-priv.h"
|
||||||
#include "coresight-trace-id.h"
|
#include "coresight-trace-id.h"
|
||||||
@ -115,6 +116,7 @@ DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm");
|
|||||||
* struct stm_drvdata - specifics associated to an STM component
|
* struct stm_drvdata - specifics associated to an STM component
|
||||||
* @base: memory mapped base address for this component.
|
* @base: memory mapped base address for this component.
|
||||||
* @atclk: optional clock for the core parts of the STM.
|
* @atclk: optional clock for the core parts of the STM.
|
||||||
|
* @pclk: APB clock if present, otherwise NULL
|
||||||
* @csdev: component vitals needed by the framework.
|
* @csdev: component vitals needed by the framework.
|
||||||
* @spinlock: only one at a time pls.
|
* @spinlock: only one at a time pls.
|
||||||
* @chs: the channels accociated to this STM.
|
* @chs: the channels accociated to this STM.
|
||||||
@ -131,6 +133,7 @@ DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm");
|
|||||||
struct stm_drvdata {
|
struct stm_drvdata {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct clk *atclk;
|
struct clk *atclk;
|
||||||
|
struct clk *pclk;
|
||||||
struct coresight_device *csdev;
|
struct coresight_device *csdev;
|
||||||
spinlock_t spinlock;
|
spinlock_t spinlock;
|
||||||
struct channel_space chs;
|
struct channel_space chs;
|
||||||
@ -800,14 +803,22 @@ static void stm_init_generic_data(struct stm_drvdata *drvdata,
|
|||||||
drvdata->stm.set_options = stm_generic_set_options;
|
drvdata->stm.set_options = stm_generic_set_options;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stm_probe(struct amba_device *adev, const struct amba_id *id)
|
static const struct amba_id stm_ids[];
|
||||||
|
|
||||||
|
static char *stm_csdev_name(struct coresight_device *csdev)
|
||||||
|
{
|
||||||
|
u32 stm_pid = coresight_get_pid(&csdev->access);
|
||||||
|
void *uci_data = coresight_get_uci_data_from_amba(stm_ids, stm_pid);
|
||||||
|
|
||||||
|
return uci_data ? (char *)uci_data : "STM";
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __stm_probe(struct device *dev, struct resource *res)
|
||||||
{
|
{
|
||||||
int ret, trace_id;
|
int ret, trace_id;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct device *dev = &adev->dev;
|
|
||||||
struct coresight_platform_data *pdata = NULL;
|
struct coresight_platform_data *pdata = NULL;
|
||||||
struct stm_drvdata *drvdata;
|
struct stm_drvdata *drvdata;
|
||||||
struct resource *res = &adev->res;
|
|
||||||
struct resource ch_res;
|
struct resource ch_res;
|
||||||
struct coresight_desc desc = { 0 };
|
struct coresight_desc desc = { 0 };
|
||||||
|
|
||||||
@ -819,12 +830,16 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
if (!drvdata)
|
if (!drvdata)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
|
drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
|
||||||
if (!IS_ERR(drvdata->atclk)) {
|
if (!IS_ERR(drvdata->atclk)) {
|
||||||
ret = clk_prepare_enable(drvdata->atclk);
|
ret = clk_prepare_enable(drvdata->atclk);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drvdata->pclk = coresight_get_enable_apb_pclk(dev);
|
||||||
|
if (IS_ERR(drvdata->pclk))
|
||||||
|
return -ENODEV;
|
||||||
dev_set_drvdata(dev, drvdata);
|
dev_set_drvdata(dev, drvdata);
|
||||||
|
|
||||||
base = devm_ioremap_resource(dev, res);
|
base = devm_ioremap_resource(dev, res);
|
||||||
@ -872,7 +887,7 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
ret = PTR_ERR(pdata);
|
ret = PTR_ERR(pdata);
|
||||||
goto stm_unregister;
|
goto stm_unregister;
|
||||||
}
|
}
|
||||||
adev->dev.platform_data = pdata;
|
dev->platform_data = pdata;
|
||||||
|
|
||||||
desc.type = CORESIGHT_DEV_TYPE_SOURCE;
|
desc.type = CORESIGHT_DEV_TYPE_SOURCE;
|
||||||
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE;
|
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE;
|
||||||
@ -893,10 +908,8 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
}
|
}
|
||||||
drvdata->traceid = (u8)trace_id;
|
drvdata->traceid = (u8)trace_id;
|
||||||
|
|
||||||
pm_runtime_put(&adev->dev);
|
|
||||||
|
|
||||||
dev_info(&drvdata->csdev->dev, "%s initialized\n",
|
dev_info(&drvdata->csdev->dev, "%s initialized\n",
|
||||||
(char *)coresight_get_uci_data(id));
|
stm_csdev_name(drvdata->csdev));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cs_unregister:
|
cs_unregister:
|
||||||
@ -907,9 +920,20 @@ stm_unregister:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stm_remove(struct amba_device *adev)
|
static int stm_probe(struct amba_device *adev, const struct amba_id *id)
|
||||||
{
|
{
|
||||||
struct stm_drvdata *drvdata = dev_get_drvdata(&adev->dev);
|
int ret;
|
||||||
|
|
||||||
|
ret = __stm_probe(&adev->dev, &adev->res);
|
||||||
|
if (!ret)
|
||||||
|
pm_runtime_put(&adev->dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __stm_remove(struct device *dev)
|
||||||
|
{
|
||||||
|
struct stm_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
|
|
||||||
coresight_trace_id_put_system_id(drvdata->traceid);
|
coresight_trace_id_put_system_id(drvdata->traceid);
|
||||||
coresight_unregister(drvdata->csdev);
|
coresight_unregister(drvdata->csdev);
|
||||||
@ -917,6 +941,11 @@ static void stm_remove(struct amba_device *adev)
|
|||||||
stm_unregister_device(&drvdata->stm);
|
stm_unregister_device(&drvdata->stm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void stm_remove(struct amba_device *adev)
|
||||||
|
{
|
||||||
|
__stm_remove(&adev->dev);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
static int stm_runtime_suspend(struct device *dev)
|
static int stm_runtime_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
@ -925,6 +954,8 @@ static int stm_runtime_suspend(struct device *dev)
|
|||||||
if (drvdata && !IS_ERR(drvdata->atclk))
|
if (drvdata && !IS_ERR(drvdata->atclk))
|
||||||
clk_disable_unprepare(drvdata->atclk);
|
clk_disable_unprepare(drvdata->atclk);
|
||||||
|
|
||||||
|
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_disable_unprepare(drvdata->pclk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -935,6 +966,8 @@ static int stm_runtime_resume(struct device *dev)
|
|||||||
if (drvdata && !IS_ERR(drvdata->atclk))
|
if (drvdata && !IS_ERR(drvdata->atclk))
|
||||||
clk_prepare_enable(drvdata->atclk);
|
clk_prepare_enable(drvdata->atclk);
|
||||||
|
|
||||||
|
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_prepare_enable(drvdata->pclk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -963,7 +996,66 @@ static struct amba_driver stm_driver = {
|
|||||||
.id_table = stm_ids,
|
.id_table = stm_ids,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_amba_driver(stm_driver);
|
static int stm_platform_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
pm_runtime_get_noresume(&pdev->dev);
|
||||||
|
pm_runtime_set_active(&pdev->dev);
|
||||||
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
|
||||||
|
ret = __stm_probe(&pdev->dev, res);
|
||||||
|
pm_runtime_put(&pdev->dev);
|
||||||
|
if (ret)
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stm_platform_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct stm_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
if (WARN_ON(!drvdata))
|
||||||
|
return;
|
||||||
|
|
||||||
|
__stm_remove(&pdev->dev);
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
if (!IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_put(drvdata->pclk);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI
|
||||||
|
static const struct acpi_device_id stm_acpi_ids[] = {
|
||||||
|
{"ARMHC502", 0, 0, 0}, /* ARM CoreSight STM */
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(acpi, stm_acpi_ids);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct platform_driver stm_platform_driver = {
|
||||||
|
.probe = stm_platform_probe,
|
||||||
|
.remove_new = stm_platform_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "coresight-stm-platform",
|
||||||
|
.acpi_match_table = ACPI_PTR(stm_acpi_ids),
|
||||||
|
.suppress_bind_attrs = true,
|
||||||
|
.pm = &stm_dev_pm_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init stm_init(void)
|
||||||
|
{
|
||||||
|
return coresight_init_driver("stm", &stm_driver, &stm_platform_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit stm_exit(void)
|
||||||
|
{
|
||||||
|
coresight_remove_driver(&stm_driver, &stm_platform_driver);
|
||||||
|
}
|
||||||
|
module_init(stm_init);
|
||||||
|
module_exit(stm_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");
|
MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");
|
||||||
MODULE_DESCRIPTION("Arm CoreSight System Trace Macrocell driver");
|
MODULE_DESCRIPTION("Arm CoreSight System Trace Macrocell driver");
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
* Description: CoreSight Trace Memory Controller driver
|
* Description: CoreSight Trace Memory Controller driver
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
@ -24,6 +25,8 @@
|
|||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/coresight.h>
|
#include <linux/coresight.h>
|
||||||
#include <linux/amba/bus.h>
|
#include <linux/amba/bus.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/acpi.h>
|
||||||
|
|
||||||
#include "coresight-priv.h"
|
#include "coresight-priv.h"
|
||||||
#include "coresight-tmc.h"
|
#include "coresight-tmc.h"
|
||||||
@ -360,7 +363,32 @@ static const struct attribute_group *coresight_etr_groups[] = {
|
|||||||
|
|
||||||
static inline bool tmc_etr_can_use_sg(struct device *dev)
|
static inline bool tmc_etr_can_use_sg(struct device *dev)
|
||||||
{
|
{
|
||||||
return fwnode_property_present(dev->fwnode, "arm,scatter-gather");
|
int ret;
|
||||||
|
u8 val_u8;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Presence of the property 'arm,scatter-gather' is checked
|
||||||
|
* on the platform for the feature support, rather than its
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
|
if (is_of_node(dev->fwnode)) {
|
||||||
|
return fwnode_property_present(dev->fwnode, "arm,scatter-gather");
|
||||||
|
} else if (is_acpi_device_node(dev->fwnode)) {
|
||||||
|
/*
|
||||||
|
* TMC_DEVID_NOSCAT test in tmc_etr_setup_caps(), has already ensured
|
||||||
|
* this property is only checked for Coresight SoC 400 TMC configured
|
||||||
|
* as ETR.
|
||||||
|
*/
|
||||||
|
ret = fwnode_property_read_u8(dev->fwnode, "arm-armhc97c-sg-enable", &val_u8);
|
||||||
|
if (!ret)
|
||||||
|
return !!val_u8;
|
||||||
|
|
||||||
|
if (fwnode_property_present(dev->fwnode, "arm,scatter-gather")) {
|
||||||
|
pr_warn_once("Deprecated ACPI property - arm,scatter-gather\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool tmc_etr_has_non_secure_access(struct tmc_drvdata *drvdata)
|
static inline bool tmc_etr_has_non_secure_access(struct tmc_drvdata *drvdata)
|
||||||
@ -370,16 +398,23 @@ static inline bool tmc_etr_has_non_secure_access(struct tmc_drvdata *drvdata)
|
|||||||
return (auth & TMC_AUTH_NSID_MASK) == 0x3;
|
return (auth & TMC_AUTH_NSID_MASK) == 0x3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct amba_id tmc_ids[];
|
||||||
|
|
||||||
/* Detect and initialise the capabilities of a TMC ETR */
|
/* Detect and initialise the capabilities of a TMC ETR */
|
||||||
static int tmc_etr_setup_caps(struct device *parent, u32 devid, void *dev_caps)
|
static int tmc_etr_setup_caps(struct device *parent, u32 devid,
|
||||||
|
struct csdev_access *access)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
u32 dma_mask = 0;
|
u32 tmc_pid, dma_mask = 0;
|
||||||
struct tmc_drvdata *drvdata = dev_get_drvdata(parent);
|
struct tmc_drvdata *drvdata = dev_get_drvdata(parent);
|
||||||
|
void *dev_caps;
|
||||||
|
|
||||||
if (!tmc_etr_has_non_secure_access(drvdata))
|
if (!tmc_etr_has_non_secure_access(drvdata))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
|
tmc_pid = coresight_get_pid(access);
|
||||||
|
dev_caps = coresight_get_uci_data_from_amba(tmc_ids, tmc_pid);
|
||||||
|
|
||||||
/* Set the unadvertised capabilities */
|
/* Set the unadvertised capabilities */
|
||||||
tmc_etr_init_caps(drvdata, (u32)(unsigned long)dev_caps);
|
tmc_etr_init_caps(drvdata, (u32)(unsigned long)dev_caps);
|
||||||
|
|
||||||
@ -437,24 +472,17 @@ static u32 tmc_etr_get_max_burst_size(struct device *dev)
|
|||||||
return burst_size;
|
return burst_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
|
static int __tmc_probe(struct device *dev, struct resource *res)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u32 devid;
|
u32 devid;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct device *dev = &adev->dev;
|
|
||||||
struct coresight_platform_data *pdata = NULL;
|
struct coresight_platform_data *pdata = NULL;
|
||||||
struct tmc_drvdata *drvdata;
|
struct tmc_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
struct resource *res = &adev->res;
|
|
||||||
struct coresight_desc desc = { 0 };
|
struct coresight_desc desc = { 0 };
|
||||||
struct coresight_dev_list *dev_list = NULL;
|
struct coresight_dev_list *dev_list = NULL;
|
||||||
|
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
|
|
||||||
if (!drvdata)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
dev_set_drvdata(dev, drvdata);
|
|
||||||
|
|
||||||
/* Validity for the resource is already checked by the AMBA core */
|
/* Validity for the resource is already checked by the AMBA core */
|
||||||
base = devm_ioremap_resource(dev, res);
|
base = devm_ioremap_resource(dev, res);
|
||||||
@ -497,8 +525,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
desc.type = CORESIGHT_DEV_TYPE_SINK;
|
desc.type = CORESIGHT_DEV_TYPE_SINK;
|
||||||
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM;
|
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM;
|
||||||
desc.ops = &tmc_etr_cs_ops;
|
desc.ops = &tmc_etr_cs_ops;
|
||||||
ret = tmc_etr_setup_caps(dev, devid,
|
ret = tmc_etr_setup_caps(dev, devid, &desc.access);
|
||||||
coresight_get_uci_data(id));
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
idr_init(&drvdata->idr);
|
idr_init(&drvdata->idr);
|
||||||
@ -530,7 +557,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
ret = PTR_ERR(pdata);
|
ret = PTR_ERR(pdata);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
adev->dev.platform_data = pdata;
|
dev->platform_data = pdata;
|
||||||
desc.pdata = pdata;
|
desc.pdata = pdata;
|
||||||
|
|
||||||
drvdata->csdev = coresight_register(&desc);
|
drvdata->csdev = coresight_register(&desc);
|
||||||
@ -545,12 +572,27 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
ret = misc_register(&drvdata->miscdev);
|
ret = misc_register(&drvdata->miscdev);
|
||||||
if (ret)
|
if (ret)
|
||||||
coresight_unregister(drvdata->csdev);
|
coresight_unregister(drvdata->csdev);
|
||||||
else
|
|
||||||
pm_runtime_put(&adev->dev);
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
|
||||||
|
{
|
||||||
|
struct tmc_drvdata *drvdata;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
drvdata = devm_kzalloc(&adev->dev, sizeof(*drvdata), GFP_KERNEL);
|
||||||
|
if (!drvdata)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
amba_set_drvdata(adev, drvdata);
|
||||||
|
ret = __tmc_probe(&adev->dev, &adev->res);
|
||||||
|
if (!ret)
|
||||||
|
pm_runtime_put(&adev->dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void tmc_shutdown(struct amba_device *adev)
|
static void tmc_shutdown(struct amba_device *adev)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@ -573,9 +615,9 @@ out:
|
|||||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmc_remove(struct amba_device *adev)
|
static void __tmc_remove(struct device *dev)
|
||||||
{
|
{
|
||||||
struct tmc_drvdata *drvdata = dev_get_drvdata(&adev->dev);
|
struct tmc_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since misc_open() holds a refcount on the f_ops, which is
|
* Since misc_open() holds a refcount on the f_ops, which is
|
||||||
@ -586,6 +628,11 @@ static void tmc_remove(struct amba_device *adev)
|
|||||||
coresight_unregister(drvdata->csdev);
|
coresight_unregister(drvdata->csdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tmc_remove(struct amba_device *adev)
|
||||||
|
{
|
||||||
|
__tmc_remove(&adev->dev);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct amba_id tmc_ids[] = {
|
static const struct amba_id tmc_ids[] = {
|
||||||
CS_AMBA_ID(0x000bb961),
|
CS_AMBA_ID(0x000bb961),
|
||||||
/* Coresight SoC 600 TMC-ETR/ETS */
|
/* Coresight SoC 600 TMC-ETR/ETS */
|
||||||
@ -611,7 +658,101 @@ static struct amba_driver tmc_driver = {
|
|||||||
.id_table = tmc_ids,
|
.id_table = tmc_ids,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_amba_driver(tmc_driver);
|
static int tmc_platform_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
struct tmc_drvdata *drvdata;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
|
||||||
|
if (!drvdata)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev);
|
||||||
|
if (IS_ERR(drvdata->pclk))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
dev_set_drvdata(&pdev->dev, drvdata);
|
||||||
|
pm_runtime_get_noresume(&pdev->dev);
|
||||||
|
pm_runtime_set_active(&pdev->dev);
|
||||||
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
|
||||||
|
ret = __tmc_probe(&pdev->dev, res);
|
||||||
|
pm_runtime_put(&pdev->dev);
|
||||||
|
if (ret)
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tmc_platform_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct tmc_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
if (WARN_ON(!drvdata))
|
||||||
|
return;
|
||||||
|
|
||||||
|
__tmc_remove(&pdev->dev);
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
if (!IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_put(drvdata->pclk);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static int tmc_runtime_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct tmc_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_disable_unprepare(drvdata->pclk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tmc_runtime_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct tmc_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_prepare_enable(drvdata->pclk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const struct dev_pm_ops tmc_dev_pm_ops = {
|
||||||
|
SET_RUNTIME_PM_OPS(tmc_runtime_suspend, tmc_runtime_resume, NULL)
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI
|
||||||
|
static const struct acpi_device_id tmc_acpi_ids[] = {
|
||||||
|
{"ARMHC501", 0, 0, 0}, /* ARM CoreSight ETR */
|
||||||
|
{"ARMHC97C", 0, 0, 0}, /* ARM CoreSight SoC-400 TMC, SoC-600 ETF/ETB */
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(acpi, tmc_acpi_ids);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct platform_driver tmc_platform_driver = {
|
||||||
|
.probe = tmc_platform_probe,
|
||||||
|
.remove_new = tmc_platform_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "coresight-tmc-platform",
|
||||||
|
.acpi_match_table = ACPI_PTR(tmc_acpi_ids),
|
||||||
|
.suppress_bind_attrs = true,
|
||||||
|
.pm = &tmc_dev_pm_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init tmc_init(void)
|
||||||
|
{
|
||||||
|
return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit tmc_exit(void)
|
||||||
|
{
|
||||||
|
coresight_remove_driver(&tmc_driver, &tmc_platform_driver);
|
||||||
|
}
|
||||||
|
module_init(tmc_init);
|
||||||
|
module_exit(tmc_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");
|
MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");
|
||||||
MODULE_DESCRIPTION("Arm CoreSight Trace Memory Controller driver");
|
MODULE_DESCRIPTION("Arm CoreSight Trace Memory Controller driver");
|
||||||
|
@ -166,6 +166,7 @@ struct etr_buf {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* struct tmc_drvdata - specifics associated to an TMC component
|
* struct tmc_drvdata - specifics associated to an TMC component
|
||||||
|
* @pclk: APB clock if present, otherwise NULL
|
||||||
* @base: memory mapped base address for this component.
|
* @base: memory mapped base address for this component.
|
||||||
* @csdev: component vitals needed by the framework.
|
* @csdev: component vitals needed by the framework.
|
||||||
* @miscdev: specifics to handle "/dev/xyz.tmc" entry.
|
* @miscdev: specifics to handle "/dev/xyz.tmc" entry.
|
||||||
@ -189,6 +190,7 @@ struct etr_buf {
|
|||||||
* @perf_buf: PERF buffer for ETR.
|
* @perf_buf: PERF buffer for ETR.
|
||||||
*/
|
*/
|
||||||
struct tmc_drvdata {
|
struct tmc_drvdata {
|
||||||
|
struct clk *pclk;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct coresight_device *csdev;
|
struct coresight_device *csdev;
|
||||||
struct miscdevice miscdev;
|
struct miscdevice miscdev;
|
||||||
|
@ -5,17 +5,19 @@
|
|||||||
* Description: CoreSight Trace Port Interface Unit driver
|
* Description: CoreSight Trace Port Interface Unit driver
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/atomic.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/io.h>
|
|
||||||
#include <linux/err.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/pm_runtime.h>
|
|
||||||
#include <linux/coresight.h>
|
|
||||||
#include <linux/amba/bus.h>
|
#include <linux/amba/bus.h>
|
||||||
|
#include <linux/atomic.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/coresight.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "coresight-priv.h"
|
#include "coresight-priv.h"
|
||||||
|
|
||||||
@ -52,11 +54,13 @@ DEFINE_CORESIGHT_DEVLIST(tpiu_devs, "tpiu");
|
|||||||
/*
|
/*
|
||||||
* @base: memory mapped base address for this component.
|
* @base: memory mapped base address for this component.
|
||||||
* @atclk: optional clock for the core parts of the TPIU.
|
* @atclk: optional clock for the core parts of the TPIU.
|
||||||
|
* @pclk: APB clock if present, otherwise NULL
|
||||||
* @csdev: component vitals needed by the framework.
|
* @csdev: component vitals needed by the framework.
|
||||||
*/
|
*/
|
||||||
struct tpiu_drvdata {
|
struct tpiu_drvdata {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct clk *atclk;
|
struct clk *atclk;
|
||||||
|
struct clk *pclk;
|
||||||
struct coresight_device *csdev;
|
struct coresight_device *csdev;
|
||||||
spinlock_t spinlock;
|
spinlock_t spinlock;
|
||||||
};
|
};
|
||||||
@ -122,14 +126,12 @@ static const struct coresight_ops tpiu_cs_ops = {
|
|||||||
.sink_ops = &tpiu_sink_ops,
|
.sink_ops = &tpiu_sink_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
|
static int __tpiu_probe(struct device *dev, struct resource *res)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct device *dev = &adev->dev;
|
|
||||||
struct coresight_platform_data *pdata = NULL;
|
struct coresight_platform_data *pdata = NULL;
|
||||||
struct tpiu_drvdata *drvdata;
|
struct tpiu_drvdata *drvdata;
|
||||||
struct resource *res = &adev->res;
|
|
||||||
struct coresight_desc desc = { 0 };
|
struct coresight_desc desc = { 0 };
|
||||||
|
|
||||||
desc.name = coresight_alloc_device_name(&tpiu_devs, dev);
|
desc.name = coresight_alloc_device_name(&tpiu_devs, dev);
|
||||||
@ -142,12 +144,16 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
|
|
||||||
spin_lock_init(&drvdata->spinlock);
|
spin_lock_init(&drvdata->spinlock);
|
||||||
|
|
||||||
drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
|
drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
|
||||||
if (!IS_ERR(drvdata->atclk)) {
|
if (!IS_ERR(drvdata->atclk)) {
|
||||||
ret = clk_prepare_enable(drvdata->atclk);
|
ret = clk_prepare_enable(drvdata->atclk);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drvdata->pclk = coresight_get_enable_apb_pclk(dev);
|
||||||
|
if (IS_ERR(drvdata->pclk))
|
||||||
|
return -ENODEV;
|
||||||
dev_set_drvdata(dev, drvdata);
|
dev_set_drvdata(dev, drvdata);
|
||||||
|
|
||||||
/* Validity for the resource is already checked by the AMBA core */
|
/* Validity for the resource is already checked by the AMBA core */
|
||||||
@ -173,21 +179,34 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
desc.dev = dev;
|
desc.dev = dev;
|
||||||
drvdata->csdev = coresight_register(&desc);
|
drvdata->csdev = coresight_register(&desc);
|
||||||
|
|
||||||
if (!IS_ERR(drvdata->csdev)) {
|
if (!IS_ERR(drvdata->csdev))
|
||||||
pm_runtime_put(&adev->dev);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
return PTR_ERR(drvdata->csdev);
|
return PTR_ERR(drvdata->csdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tpiu_remove(struct amba_device *adev)
|
static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
|
||||||
{
|
{
|
||||||
struct tpiu_drvdata *drvdata = dev_get_drvdata(&adev->dev);
|
int ret;
|
||||||
|
|
||||||
|
ret = __tpiu_probe(&adev->dev, &adev->res);
|
||||||
|
if (!ret)
|
||||||
|
pm_runtime_put(&adev->dev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __tpiu_remove(struct device *dev)
|
||||||
|
{
|
||||||
|
struct tpiu_drvdata *drvdata = dev_get_drvdata(dev);
|
||||||
|
|
||||||
coresight_unregister(drvdata->csdev);
|
coresight_unregister(drvdata->csdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tpiu_remove(struct amba_device *adev)
|
||||||
|
{
|
||||||
|
__tpiu_remove(&adev->dev);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
static int tpiu_runtime_suspend(struct device *dev)
|
static int tpiu_runtime_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
@ -196,6 +215,8 @@ static int tpiu_runtime_suspend(struct device *dev)
|
|||||||
if (drvdata && !IS_ERR(drvdata->atclk))
|
if (drvdata && !IS_ERR(drvdata->atclk))
|
||||||
clk_disable_unprepare(drvdata->atclk);
|
clk_disable_unprepare(drvdata->atclk);
|
||||||
|
|
||||||
|
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_disable_unprepare(drvdata->pclk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,6 +227,8 @@ static int tpiu_runtime_resume(struct device *dev)
|
|||||||
if (drvdata && !IS_ERR(drvdata->atclk))
|
if (drvdata && !IS_ERR(drvdata->atclk))
|
||||||
clk_prepare_enable(drvdata->atclk);
|
clk_prepare_enable(drvdata->atclk);
|
||||||
|
|
||||||
|
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_prepare_enable(drvdata->pclk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -245,7 +268,66 @@ static struct amba_driver tpiu_driver = {
|
|||||||
.id_table = tpiu_ids,
|
.id_table = tpiu_ids,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_amba_driver(tpiu_driver);
|
static int tpiu_platform_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
pm_runtime_get_noresume(&pdev->dev);
|
||||||
|
pm_runtime_set_active(&pdev->dev);
|
||||||
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
|
||||||
|
ret = __tpiu_probe(&pdev->dev, res);
|
||||||
|
pm_runtime_put(&pdev->dev);
|
||||||
|
if (ret)
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tpiu_platform_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct tpiu_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
if (WARN_ON(!drvdata))
|
||||||
|
return;
|
||||||
|
|
||||||
|
__tpiu_remove(&pdev->dev);
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
if (!IS_ERR_OR_NULL(drvdata->pclk))
|
||||||
|
clk_put(drvdata->pclk);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI
|
||||||
|
static const struct acpi_device_id tpiu_acpi_ids[] = {
|
||||||
|
{"ARMHC979", 0, 0, 0}, /* ARM CoreSight TPIU */
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(acpi, tpiu_acpi_ids);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct platform_driver tpiu_platform_driver = {
|
||||||
|
.probe = tpiu_platform_probe,
|
||||||
|
.remove_new = tpiu_platform_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "coresight-tpiu-platform",
|
||||||
|
.acpi_match_table = ACPI_PTR(tpiu_acpi_ids),
|
||||||
|
.suppress_bind_attrs = true,
|
||||||
|
.pm = &tpiu_dev_pm_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init tpiu_init(void)
|
||||||
|
{
|
||||||
|
return coresight_init_driver("tpiu", &tpiu_driver, &tpiu_platform_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit tpiu_exit(void)
|
||||||
|
{
|
||||||
|
coresight_remove_driver(&tpiu_driver, &tpiu_platform_driver);
|
||||||
|
}
|
||||||
|
module_init(tpiu_init);
|
||||||
|
module_exit(tpiu_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");
|
MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");
|
||||||
MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>");
|
MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>");
|
||||||
|
@ -1221,6 +1221,7 @@ static int hisi_ptt_register_pmu(struct hisi_ptt *hisi_ptt)
|
|||||||
|
|
||||||
hisi_ptt->hisi_ptt_pmu = (struct pmu) {
|
hisi_ptt->hisi_ptt_pmu = (struct pmu) {
|
||||||
.module = THIS_MODULE,
|
.module = THIS_MODULE,
|
||||||
|
.parent = &hisi_ptt->pdev->dev,
|
||||||
.capabilities = PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_NO_EXCLUDE,
|
.capabilities = PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_NO_EXCLUDE,
|
||||||
.task_ctx_nr = perf_sw_context,
|
.task_ctx_nr = perf_sw_context,
|
||||||
.attr_groups = hisi_ptt_pmu_groups,
|
.attr_groups = hisi_ptt_pmu_groups,
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/perf_event.h>
|
#include <linux/perf_event.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
/* Peripheral id registers (0xFD0-0xFEC) */
|
/* Peripheral id registers (0xFD0-0xFEC) */
|
||||||
#define CORESIGHT_PERIPHIDR4 0xfd0
|
#define CORESIGHT_PERIPHIDR4 0xfd0
|
||||||
@ -658,4 +659,9 @@ coresight_find_output_type(struct coresight_platform_data *pdata,
|
|||||||
enum coresight_dev_type type,
|
enum coresight_dev_type type,
|
||||||
union coresight_dev_subtype subtype);
|
union coresight_dev_subtype subtype);
|
||||||
|
|
||||||
|
int coresight_init_driver(const char *drv, struct amba_driver *amba_drv,
|
||||||
|
struct platform_driver *pdev_drv);
|
||||||
|
|
||||||
|
void coresight_remove_driver(struct amba_driver *amba_drv,
|
||||||
|
struct platform_driver *pdev_drv);
|
||||||
#endif /* _LINUX_COREISGHT_H */
|
#endif /* _LINUX_COREISGHT_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user