diff --git a/Makefile b/Makefile
index d53ef26..64b4679 100644
--- a/Makefile
+++ b/Makefile
@@ -8,4 +8,5 @@ obj-y += tegra-soc-hwpm.o
obj-y += tegra-soc-hwpm-io.o
obj-y += tegra-soc-hwpm-ioctl.o
obj-y += tegra-soc-hwpm-log.o
+obj-y += tegra-soc-hwpm-ip.o
obj-$(CONFIG_DEBUG_FS) += tegra-soc-hwpm-debugfs.o
diff --git a/tegra-soc-hwpm-ioctl.c b/tegra-soc-hwpm-ioctl.c
index 05ac81c..22b1596 100644
--- a/tegra-soc-hwpm-ioctl.c
+++ b/tegra-soc-hwpm-ioctl.c
@@ -351,6 +351,8 @@ static int reserve_resource_ioctl(struct tegra_soc_hwpm *hwpm,
u32 resource = reserve_resource->resource;
struct hwpm_resource_aperture *aperture = NULL;
int aprt_idx = 0;
+ struct tegra_soc_hwpm_ip_ops *ip_ops;
+ int err;
if (hwpm->bind_completed) {
tegra_soc_hwpm_err("The RESERVE_RESOURCE IOCTL can only be"
@@ -390,7 +392,20 @@ static int reserve_resource_ioctl(struct tegra_soc_hwpm *hwpm,
tegra_soc_hwpm_dbg("Found PERFMON(0x%llx - 0x%llx)",
aperture->start_pa, aperture->end_pa);
-
+ ip_ops = &hwpm->ip_info[aperture->dt_aperture];
+ if (ip_ops && (*ip_ops->hwpm_ip_pm)) {
+ err = (*ip_ops->hwpm_ip_pm)
+ (ip_ops->ip_dev, true);
+ if (err) {
+ tegra_soc_hwpm_err(
+ "Disable Runtime PM(%d) Failed",
+ aperture->dt_aperture);
+ }
+ } else {
+ tegra_soc_hwpm_dbg(
+ "No Runtime PM(%d) for IP",
+ aperture->dt_aperture);
+ }
hwpm->dt_apertures[aperture->dt_aperture] =
of_iomap(hwpm->np, aperture->dt_aperture);
if (!hwpm->dt_apertures[aperture->dt_aperture]) {
@@ -1441,6 +1456,7 @@ static int tegra_soc_hwpm_release(struct inode *inode, struct file *filp)
u32 *mem_bytes_kernel_u32 = NULL;
struct tegra_soc_hwpm *hwpm = NULL;
struct hwpm_resource_aperture *aperture = NULL;
+ struct tegra_soc_hwpm_ip_ops *ip_ops;
#define RELEASE_FAIL(msg, ...) \
do { \
if (err < 0) { \
@@ -1541,6 +1557,20 @@ static int tegra_soc_hwpm_release(struct inode *inode, struct file *filp)
aperture->start_pa,
aperture->end_pa);
}
+ ip_ops = &hwpm->ip_info[aperture->dt_aperture];
+ if (ip_ops && (*ip_ops->hwpm_ip_pm)) {
+ err = (*ip_ops->hwpm_ip_pm)
+ (ip_ops->ip_dev, false);
+ if (err) {
+ tegra_soc_hwpm_err(
+ "Enable Runtime PM(%d) Failed",
+ aperture->dt_aperture);
+ }
+ } else {
+ tegra_soc_hwpm_dbg(
+ "No Runtime PM(%d) for IP",
+ aperture->dt_aperture);
+ }
}
}
diff --git a/tegra-soc-hwpm-ip.c b/tegra-soc-hwpm-ip.c
new file mode 100644
index 0000000..e8daf27
--- /dev/null
+++ b/tegra-soc-hwpm-ip.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * tegra-soc-hwpm-ip.c:
+ * This file contains functions for SOC HWPM <-> IPC communication.
+ */
+
+
+#include
+#include "tegra-soc-hwpm.h"
+
+struct platform_device *tegra_soc_hwpm_pdev;
+
+static enum tegra_soc_hwpm_dt_aperture tegra_soc_hwpm_get_apeture(
+ struct tegra_soc_hwpm *hwpm, u64 ip_base_address)
+{
+ enum tegra_soc_hwpm_dt_aperture aperture =
+ TEGRA_SOC_HWPM_NUM_DT_APERTURES;
+
+ /* TODO chip speciifc implementation for finding aperture */
+ if (ip_base_address == addr_map_vic_base_r()) {
+ aperture = TEGRA_SOC_HWPM_VICA0_PERFMON_DT;
+ } else if (ip_base_address == addr_map_nvenc_base_r()) {
+ aperture = TEGRA_SOC_HWPM_NVENCA0_PERFMON_DT;
+ } else if (ip_base_address == addr_map_ofa_base_r()) {
+ aperture = TEGRA_SOC_HWPM_OFAA0_PERFMON_DT;
+ }
+
+ return aperture;
+}
+
+void tegra_soc_hwpm_ip_register(struct tegra_soc_hwpm_ip_ops *hwpm_ip_ops)
+{
+ struct tegra_soc_hwpm *hwpm = NULL;
+ enum tegra_soc_hwpm_dt_aperture dt_aperture;
+
+ tegra_soc_hwpm_dbg("HWPM Registered IP 0x%llx",
+ hwpm_ip_ops->ip_base_address);
+
+ if (tegra_soc_hwpm_pdev == NULL) {
+ tegra_soc_hwpm_err(
+ "IP trying to register before SOC HWPM 0x%llx",
+ hwpm_ip_ops->ip_base_address);
+ } else {
+ hwpm = platform_get_drvdata(tegra_soc_hwpm_pdev);
+ dt_aperture = tegra_soc_hwpm_get_apeture(hwpm,
+ hwpm_ip_ops->ip_base_address);
+ if (dt_aperture != TEGRA_SOC_HWPM_NUM_DT_APERTURES) {
+ memcpy(&hwpm->ip_info[dt_aperture], hwpm_ip_ops,
+ sizeof(struct tegra_soc_hwpm_ip_ops));
+ } else {
+ tegra_soc_hwpm_err(
+ "SOC HWPM has no support for 0x%llx",
+ hwpm_ip_ops->ip_base_address);
+ }
+ }
+
+}
+
+void tegra_soc_hwpm_ip_unregister(struct tegra_soc_hwpm_ip_ops *hwpm_ip_ops)
+{
+ struct tegra_soc_hwpm *hwpm = NULL;
+ enum tegra_soc_hwpm_dt_aperture dt_aperture;
+
+ if (tegra_soc_hwpm_pdev == NULL) {
+ tegra_soc_hwpm_err("IP unregister before SOC HWPM 0x%llx",
+ hwpm_ip_ops->ip_base_address);
+ } else {
+ hwpm = platform_get_drvdata(tegra_soc_hwpm_pdev);
+ dt_aperture = tegra_soc_hwpm_get_apeture(hwpm,
+ hwpm_ip_ops->ip_base_address);
+ if (dt_aperture != TEGRA_SOC_HWPM_NUM_DT_APERTURES) {
+ memset(&hwpm->ip_info[dt_aperture], 0,
+ sizeof(struct tegra_soc_hwpm_ip_ops));
+ }
+ }
+}
diff --git a/tegra-soc-hwpm.c b/tegra-soc-hwpm.c
index c1af523..a91ecc9 100644
--- a/tegra-soc-hwpm.c
+++ b/tegra-soc-hwpm.c
@@ -129,6 +129,7 @@ static int tegra_soc_hwpm_probe(struct platform_device *pdev)
hwpm->fake_registers_enabled = false;
platform_set_drvdata(pdev, hwpm);
+ tegra_soc_hwpm_pdev = pdev;
tegra_soc_hwpm_dbg("Probe successful!");
goto success;
@@ -189,6 +190,7 @@ static int tegra_soc_hwpm_remove(struct platform_device *pdev)
class_unregister(&hwpm->class);
kfree(hwpm);
+ tegra_soc_hwpm_pdev = NULL;
return 0;
}
diff --git a/tegra-soc-hwpm.h b/tegra-soc-hwpm.h
index 6d8d54e..ebfd7a4 100644
--- a/tegra-soc-hwpm.h
+++ b/tegra-soc-hwpm.h
@@ -73,6 +73,8 @@ struct tegra_soc_hwpm {
struct reset_control *la_rst;
struct reset_control *hwpm_rst;
+ struct tegra_soc_hwpm_ip_ops ip_info[TEGRA_SOC_HWPM_NUM_DT_APERTURES];
+
/* Memory Management */
struct dma_buf *stream_dma_buf;
struct dma_buf_attachment *stream_attach;
@@ -93,6 +95,7 @@ struct tegra_soc_hwpm {
bool fake_registers_enabled;
};
+extern struct platform_device *tegra_soc_hwpm_pdev;
extern const struct file_operations tegra_soc_hwpm_ops;
#ifdef CONFIG_DEBUG_FS