From 579bc23ee66b845b22e795423303436f0a0efd89 Mon Sep 17 00:00:00 2001 From: Seshendra Gadagottu Date: Thu, 7 Oct 2021 09:28:49 -0700 Subject: [PATCH] tegra: hwpm: add support for SOC HWPM <-> IP interface Add support for IP registering mechanism for runtime callback and perfmux read/writes. void tegra_soc_hwpm_ip_register(struct tegra_soc_hwpm_ip_ops *hwpm_ip_ops); IP's callback are called to disable and enable IP runtime pm. At this moment, only VIC/NVENC/OFA driver registration is supported. Also will take-up perfmux register read/write in follow-up patch. Bug 3333031 Bug 3333042 Change-Id: If559cae73be1edbdb7139b4183ce3e1dc0943053 Signed-off-by: Seshendra Gadagottu Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2607267 Reviewed-by: svc_kernel_abi Reviewed-by: Seema Khowala Reviewed-by: mobile promotions Tested-by: mobile promotions GVS: Gerrit_Virtual_Submit --- Makefile | 1 + tegra-soc-hwpm-ioctl.c | 32 ++++++++++++++- tegra-soc-hwpm-ip.c | 89 ++++++++++++++++++++++++++++++++++++++++++ tegra-soc-hwpm.c | 2 + tegra-soc-hwpm.h | 3 ++ 5 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 tegra-soc-hwpm-ip.c 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