mirror of
git://nv-tegra.nvidia.com/linux-hwpm.git
synced 2025-12-23 01:35:10 +03:00
HWPM supports various IPs which initialize at different times in boot flow. Some IPs such as MSS, NVLINK initialize before HWPM device and some IPs (VIC, OFA, NVDEC, NVDLA) are initialized after HWPM device. Modify IP register function to store registration requests in a linked list for IPs initialized before HWPM device is probed. The linked list will be traversed to complete pending IP register requests after HWPM device is initialized. - Add struct tegra_hwpm_ip_ops internal to HWPM driver to include only required ip_ops details. - Replace init_fs_info HAL with finalize_chip_info to register ip_ops, force enable IPs (if any). Jira THWPM-41 Change-Id: I916b4fa50679e79025a941a9c1fc113bdfe92b41 Signed-off-by: Vedashree Vidwans <vvidwans@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2675472 Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com> Reviewed-by: Vasuki Shankar <vasukis@nvidia.com> Reviewed-by: Seema Khowala <seemaj@nvidia.com> GVS: Gerrit_Virtual_Submit
177 lines
4.5 KiB
C
177 lines
4.5 KiB
C
/*
|
|
* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. 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.
|
|
*/
|
|
|
|
#include <linux/slab.h>
|
|
#include <soc/tegra/fuse.h>
|
|
#include <uapi/linux/tegra-soc-hwpm-uapi.h>
|
|
|
|
#include <tegra_hwpm_log.h>
|
|
#include <tegra_hwpm_io.h>
|
|
#include <tegra_hwpm.h>
|
|
|
|
struct platform_device *tegra_soc_hwpm_pdev;
|
|
struct hwpm_ip_register_list *ip_register_list_head;
|
|
|
|
#define REGISTER_IP true
|
|
#define UNREGISTER_IP false
|
|
|
|
static int tegra_hwpm_alloc_ip_register_list_node(
|
|
struct tegra_soc_hwpm_ip_ops *hwpm_ip_ops,
|
|
struct hwpm_ip_register_list **node_ptr)
|
|
{
|
|
struct hwpm_ip_register_list *new_node = NULL;
|
|
|
|
new_node = kzalloc(sizeof(struct hwpm_ip_register_list), GFP_KERNEL);
|
|
if (new_node == NULL) {
|
|
tegra_hwpm_err(NULL,
|
|
"struct hwpm_ip_register_list node allocation failed");
|
|
return -ENOMEM;
|
|
}
|
|
new_node->next = NULL;
|
|
|
|
/* Copy given ip register details to node */
|
|
memcpy(&new_node->ip_ops, hwpm_ip_ops,
|
|
sizeof(struct tegra_soc_hwpm_ip_ops));
|
|
(*node_ptr) = new_node;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tegra_hwpm_note_ip_register(
|
|
struct tegra_soc_hwpm_ip_ops *hwpm_ip_ops)
|
|
{
|
|
int err = 0;
|
|
struct hwpm_ip_register_list *node;
|
|
|
|
if (ip_register_list_head == NULL) {
|
|
err = tegra_hwpm_alloc_ip_register_list_node(hwpm_ip_ops,
|
|
&ip_register_list_head);
|
|
if (err != 0) {
|
|
tegra_hwpm_err(NULL,
|
|
"failed to note ip registration");
|
|
return err;
|
|
}
|
|
} else {
|
|
node = ip_register_list_head;
|
|
while (node->next != NULL) {
|
|
node = node->next;
|
|
}
|
|
|
|
err = tegra_hwpm_alloc_ip_register_list_node(hwpm_ip_ops,
|
|
&node->next);
|
|
if (err != 0) {
|
|
tegra_hwpm_err(NULL,
|
|
"failed to note ip registration");
|
|
return err;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
void tegra_soc_hwpm_ip_register(struct tegra_soc_hwpm_ip_ops *hwpm_ip_ops)
|
|
{
|
|
struct tegra_soc_hwpm *hwpm = NULL;
|
|
int ret = 0;
|
|
|
|
if (tegra_soc_hwpm_pdev == NULL) {
|
|
ret = tegra_hwpm_note_ip_register(hwpm_ip_ops);
|
|
if (ret != 0) {
|
|
tegra_hwpm_err(NULL,
|
|
"Couldn't save IP register details");
|
|
}
|
|
} else {
|
|
if (hwpm_ip_ops->ip_dev == NULL) {
|
|
tegra_hwpm_err(hwpm, "IP dev to register is NULL");
|
|
return;
|
|
}
|
|
hwpm = platform_get_drvdata(tegra_soc_hwpm_pdev);
|
|
|
|
tegra_hwpm_dbg(hwpm, hwpm_info,
|
|
"Register IP 0x%llx", hwpm_ip_ops->ip_base_address);
|
|
|
|
if (hwpm->active_chip->extract_ip_ops == NULL) {
|
|
tegra_hwpm_err(hwpm, "extract_ip_ops uninitialized");
|
|
return;
|
|
}
|
|
ret = hwpm->active_chip->extract_ip_ops(hwpm,
|
|
hwpm_ip_ops, REGISTER_IP);
|
|
if (ret < 0) {
|
|
tegra_hwpm_err(hwpm, "Failed to set IP ops for IP %d",
|
|
hwpm_ip_ops->ip_index);
|
|
}
|
|
}
|
|
}
|
|
|
|
void tegra_soc_hwpm_ip_unregister(struct tegra_soc_hwpm_ip_ops *hwpm_ip_ops)
|
|
{
|
|
struct tegra_soc_hwpm *hwpm = NULL;
|
|
int ret = 0;
|
|
|
|
if (tegra_soc_hwpm_pdev == NULL) {
|
|
tegra_hwpm_dbg(hwpm, hwpm_info, "HWPM device not available");
|
|
} else {
|
|
if (hwpm_ip_ops->ip_dev == NULL) {
|
|
tegra_hwpm_err(hwpm, "IP dev to unregister is NULL");
|
|
return;
|
|
}
|
|
hwpm = platform_get_drvdata(tegra_soc_hwpm_pdev);
|
|
|
|
tegra_hwpm_dbg(hwpm, hwpm_info,
|
|
"Unregister IP 0x%llx", hwpm_ip_ops->ip_base_address);
|
|
|
|
if (hwpm->active_chip->extract_ip_ops == NULL) {
|
|
tegra_hwpm_err(hwpm, "extract_ip_ops uninitialized");
|
|
return;
|
|
}
|
|
ret = hwpm->active_chip->extract_ip_ops(hwpm,
|
|
hwpm_ip_ops, UNREGISTER_IP);
|
|
if (ret < 0) {
|
|
tegra_hwpm_err(hwpm, "Failed to reset IP ops for IP %d",
|
|
hwpm_ip_ops->ip_index);
|
|
}
|
|
}
|
|
}
|
|
|
|
int tegra_hwpm_get_floorsweep_info(struct tegra_soc_hwpm *hwpm,
|
|
struct tegra_soc_hwpm_ip_floorsweep_info *fs_info)
|
|
{
|
|
int ret = 0;
|
|
u32 i = 0U;
|
|
|
|
tegra_hwpm_fn(hwpm, " ");
|
|
|
|
if (hwpm->active_chip->get_fs_info == NULL) {
|
|
tegra_hwpm_err(hwpm, "get_fs_info uninitialized");
|
|
return -ENODEV;
|
|
}
|
|
|
|
for (i = 0U; i < fs_info->num_queries; i++) {
|
|
ret = hwpm->active_chip->get_fs_info(
|
|
hwpm, (u32)fs_info->ip_fsinfo[i].ip_type,
|
|
&fs_info->ip_fsinfo[i].ip_inst_mask,
|
|
&fs_info->ip_fsinfo[i].status);
|
|
if (ret < 0) {
|
|
/* Print error for debug purpose. */
|
|
tegra_hwpm_err(hwpm, "Failed to get fs_info");
|
|
}
|
|
|
|
tegra_hwpm_dbg(hwpm, hwpm_verbose,
|
|
"Query %d: ip_type %d: ip_status: %d inst_mask 0x%llx",
|
|
i, fs_info->ip_fsinfo[i].ip_type,
|
|
fs_info->ip_fsinfo[i].status,
|
|
fs_info->ip_fsinfo[i].ip_inst_mask);
|
|
}
|
|
return ret;
|
|
}
|