mirror of
git://nv-tegra.nvidia.com/linux-hwpm.git
synced 2025-12-23 09:46:59 +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
245 lines
5.7 KiB
C
245 lines
5.7 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/mm.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/module.h>
|
|
#include <linux/io.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/reset.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/dma-buf.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>
|
|
#include <tegra_hwpm_common.h>
|
|
#include <hal/t234/t234_hwpm_init.h>
|
|
|
|
int tegra_hwpm_init_chip_info(struct tegra_soc_hwpm *hwpm)
|
|
{
|
|
int err = -EINVAL;
|
|
|
|
tegra_hwpm_fn(hwpm, " ");
|
|
|
|
hwpm->device_info.chip = tegra_get_chip_id();
|
|
hwpm->device_info.chip_revision = tegra_get_major_rev();
|
|
hwpm->device_info.revision = tegra_chip_get_revision();
|
|
hwpm->device_info.platform = tegra_get_platform();
|
|
|
|
hwpm->dbg_mask = TEGRA_HWPM_DEFAULT_DBG_MASK;
|
|
|
|
switch (hwpm->device_info.chip) {
|
|
case 0x23:
|
|
switch (hwpm->device_info.chip_revision) {
|
|
case 0x4:
|
|
err = t234_hwpm_init_chip_info(hwpm);
|
|
break;
|
|
default:
|
|
tegra_hwpm_err(hwpm, "Chip 0x%x rev 0x%x not supported",
|
|
hwpm->device_info.chip,
|
|
hwpm->device_info.chip_revision);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
tegra_hwpm_err(hwpm, "Chip 0x%x not supported",
|
|
hwpm->device_info.chip);
|
|
break;
|
|
}
|
|
|
|
if (err != 0) {
|
|
tegra_hwpm_err(hwpm, "init_chip_info failed");
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
int tegra_hwpm_setup_sw(struct tegra_soc_hwpm *hwpm)
|
|
{
|
|
int ret = 0;
|
|
|
|
tegra_hwpm_fn(hwpm, " ");
|
|
|
|
if (hwpm->active_chip->finalize_chip_info == NULL) {
|
|
tegra_hwpm_err(hwpm, "finalize_chip_info uninitialized");
|
|
goto enodev;
|
|
}
|
|
ret = hwpm->active_chip->finalize_chip_info(hwpm);
|
|
if (ret < 0) {
|
|
tegra_hwpm_err(hwpm, "Unable to initialize chip fs_info");
|
|
goto fail;
|
|
}
|
|
|
|
/* Initialize SW state */
|
|
hwpm->bind_completed = false;
|
|
hwpm->full_alist_size = 0;
|
|
|
|
return 0;
|
|
enodev:
|
|
ret = -ENODEV;
|
|
fail:
|
|
return ret;
|
|
}
|
|
|
|
int tegra_hwpm_setup_hw(struct tegra_soc_hwpm *hwpm)
|
|
{
|
|
int ret = 0;
|
|
|
|
tegra_hwpm_fn(hwpm, " ");
|
|
|
|
/*
|
|
* Map PMA and RTR apertures
|
|
* PMA and RTR are hwpm apertures which include hwpm config registers.
|
|
* Map/reserve these apertures to get MMIO address required for hwpm
|
|
* configuration (following steps).
|
|
*/
|
|
if (hwpm->active_chip->reserve_pma == NULL) {
|
|
tegra_hwpm_err(hwpm, "reserve_pma uninitialized");
|
|
goto enodev;
|
|
}
|
|
ret = hwpm->active_chip->reserve_pma(hwpm);
|
|
if (ret < 0) {
|
|
tegra_hwpm_err(hwpm, "Unable to reserve PMA aperture");
|
|
goto fail;
|
|
}
|
|
|
|
if (hwpm->active_chip->reserve_rtr == NULL) {
|
|
tegra_hwpm_err(hwpm, "reserve_rtr uninitialized");
|
|
goto enodev;
|
|
}
|
|
ret = hwpm->active_chip->reserve_rtr(hwpm);
|
|
if (ret < 0) {
|
|
tegra_hwpm_err(hwpm, "Unable to reserve RTR aperture");
|
|
goto fail;
|
|
}
|
|
|
|
/* Disable SLCG */
|
|
if (hwpm->active_chip->disable_slcg == NULL) {
|
|
tegra_hwpm_err(hwpm, "disable_slcg uninitialized");
|
|
goto enodev;
|
|
}
|
|
ret = hwpm->active_chip->disable_slcg(hwpm);
|
|
if (ret < 0) {
|
|
tegra_hwpm_err(hwpm, "Unable to disable SLCG");
|
|
goto fail;
|
|
}
|
|
|
|
/* Program PROD values */
|
|
if (hwpm->active_chip->init_prod_values == NULL) {
|
|
tegra_hwpm_err(hwpm, "init_prod_values uninitialized");
|
|
goto enodev;
|
|
}
|
|
ret = hwpm->active_chip->init_prod_values(hwpm);
|
|
if (ret < 0) {
|
|
tegra_hwpm_err(hwpm, "Unable to set PROD values");
|
|
goto fail;
|
|
}
|
|
|
|
return 0;
|
|
enodev:
|
|
ret = -ENODEV;
|
|
fail:
|
|
return ret;
|
|
}
|
|
|
|
int tegra_hwpm_disable_triggers(struct tegra_soc_hwpm *hwpm)
|
|
{
|
|
tegra_hwpm_fn(hwpm, " ");
|
|
|
|
if (hwpm->active_chip->disable_triggers == NULL) {
|
|
tegra_hwpm_err(hwpm, "disable_triggers uninitialized");
|
|
return -ENODEV;
|
|
}
|
|
return hwpm->active_chip->disable_triggers(hwpm);
|
|
}
|
|
|
|
int tegra_hwpm_release_hw(struct tegra_soc_hwpm *hwpm)
|
|
{
|
|
int ret = 0;
|
|
|
|
tegra_hwpm_fn(hwpm, " ");
|
|
|
|
/* Enable SLCG */
|
|
if (hwpm->active_chip->enable_slcg == NULL) {
|
|
tegra_hwpm_err(hwpm, "enable_slcg uninitialized");
|
|
goto enodev;
|
|
}
|
|
ret = hwpm->active_chip->enable_slcg(hwpm);
|
|
if (ret < 0) {
|
|
tegra_hwpm_err(hwpm, "Unable to enable SLCG");
|
|
goto fail;
|
|
}
|
|
|
|
/*
|
|
* Unmap PMA and RTR apertures
|
|
* Since, PMA and RTR hwpm apertures consist of hwpm config registers,
|
|
* these aperture mappings are required to reset hwpm config.
|
|
* Hence, explicitly unmap/release these apertures as a last step.
|
|
*/
|
|
if (hwpm->active_chip->release_rtr == NULL) {
|
|
tegra_hwpm_err(hwpm, "release_rtr uninitialized");
|
|
goto enodev;
|
|
}
|
|
ret = hwpm->active_chip->release_rtr(hwpm);
|
|
if (ret < 0) {
|
|
tegra_hwpm_err(hwpm, "Unable to release RTR aperture");
|
|
goto fail;
|
|
}
|
|
|
|
if (hwpm->active_chip->release_pma == NULL) {
|
|
tegra_hwpm_err(hwpm, "release_pma uninitialized");
|
|
goto enodev;
|
|
}
|
|
ret = hwpm->active_chip->release_pma(hwpm);
|
|
if (ret < 0) {
|
|
tegra_hwpm_err(hwpm, "Unable to release PMA aperture");
|
|
goto fail;
|
|
}
|
|
|
|
return 0;
|
|
enodev:
|
|
ret = -ENODEV;
|
|
fail:
|
|
return ret;
|
|
}
|
|
|
|
void tegra_hwpm_release_sw_components(struct tegra_soc_hwpm *hwpm)
|
|
{
|
|
struct hwpm_ip_register_list *node = ip_register_list_head;
|
|
struct hwpm_ip_register_list *tmp_node = NULL;
|
|
|
|
tegra_hwpm_fn(hwpm, " ");
|
|
|
|
if (hwpm->active_chip->release_sw_setup == NULL) {
|
|
tegra_hwpm_err(hwpm, "release_sw_setup uninitialized");
|
|
} else {
|
|
hwpm->active_chip->release_sw_setup(hwpm);
|
|
}
|
|
|
|
while (node != NULL) {
|
|
tmp_node = node;
|
|
node = tmp_node->next;
|
|
kfree(tmp_node);
|
|
}
|
|
|
|
kfree(hwpm->active_chip->chip_ips);
|
|
kfree(hwpm);
|
|
tegra_soc_hwpm_pdev = NULL;
|
|
}
|