tegra: hwpm: add wrapper linux os structure

Currently, HWPM parent structure contains linux specific device
variables. In an effort to make HWPM driver OS agnostic, create Linux
specific wrapper HWPM structure tegra_hwpm_os_linux. Move linux specific
variables from tegra_soc_hwpm structure to tegra_hwpm_os_linux
structure.

Jira THWPM-60

Change-Id: I189cde92c5b83b327ccb467c72dee5756f16481d
Signed-off-by: Vedashree Vidwans <vvidwans@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2729700
Reviewed-by: Seema Khowala <seemaj@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
Vedashree Vidwans
2022-06-15 23:41:07 -07:00
committed by mobile promotions
parent 2dd64aec0b
commit 738361e0e2
14 changed files with 292 additions and 212 deletions

View File

@@ -24,32 +24,33 @@
#include <tegra_hwpm_next_init.h>
#endif
static int tegra_hwpm_init_chip_ip_structures(struct tegra_soc_hwpm *hwpm)
static int tegra_hwpm_init_chip_ip_structures(struct tegra_soc_hwpm *hwpm,
u32 chip_id, u32 chip_id_rev)
{
int err = -EINVAL;
tegra_hwpm_fn(hwpm, " ");
switch (hwpm->device_info.chip) {
switch (chip_id) {
case 0x23:
switch (hwpm->device_info.chip_revision) {
switch (chip_id_rev) {
case 0x4:
err = t234_hwpm_init_chip_info(hwpm);
break;
default:
#ifdef CONFIG_TEGRA_NEXT1_HWPM
err = tegra_hwpm_next1_init_chip_info(hwpm);
err = tegra_hwpm_next1_init_chip_info(hwpm,
chip_id, chip_id_rev);
#else
tegra_hwpm_err(hwpm, "Chip 0x%x rev 0x%x not supported",
hwpm->device_info.chip,
hwpm->device_info.chip_revision);
chip_id, chip_id_rev);
#endif
break;
}
break;
default:
tegra_hwpm_err(hwpm, "Chip 0x%x not supported",
hwpm->device_info.chip);
tegra_hwpm_err(hwpm, "Chip 0x%x not supported", chip_id);
break;
}
@@ -67,13 +68,16 @@ static int tegra_hwpm_init_chip_ip_structures(struct tegra_soc_hwpm *hwpm)
return err;
}
int tegra_hwpm_init_sw_components(struct tegra_soc_hwpm *hwpm)
int tegra_hwpm_init_sw_components(struct tegra_soc_hwpm *hwpm,
u32 chip_id, u32 chip_id_rev)
{
int err = 0;
tegra_hwpm_fn(hwpm, " ");
err = tegra_hwpm_init_chip_ip_structures(hwpm);
hwpm->dbg_mask = TEGRA_HWPM_DEFAULT_DBG_MASK;
err = tegra_hwpm_init_chip_ip_structures(hwpm, chip_id, chip_id_rev);
if (err != 0) {
tegra_hwpm_err(hwpm, "IP structure init failed");
return err;
@@ -88,17 +92,6 @@ int tegra_hwpm_init_sw_components(struct tegra_soc_hwpm *hwpm)
return 0;
}
void tegra_hwpm_release_sw_components(struct tegra_soc_hwpm *hwpm)
{
tegra_hwpm_fn(hwpm, " ");
hwpm->active_chip->release_sw_setup(hwpm);
tegra_hwpm_kfree(hwpm, hwpm->active_chip->chip_ips);
tegra_hwpm_kfree(hwpm, hwpm);
tegra_soc_hwpm_pdev = NULL;
}
int tegra_hwpm_setup_sw(struct tegra_soc_hwpm *hwpm)
{
int ret = 0;
@@ -211,5 +204,7 @@ void tegra_hwpm_release_sw_setup(struct tegra_soc_hwpm *hwpm)
return;
}
tegra_hwpm_kfree(hwpm, hwpm->active_chip->chip_ips);
return;
}

View File

@@ -59,8 +59,6 @@ static struct tegra_soc_hwpm_chip t234_chip_info = {
.zero_alist_regs = t234_hwpm_zero_alist_regs,
.copy_alist = t234_hwpm_copy_alist,
.check_alist = t234_hwpm_check_alist,
.release_sw_setup = tegra_hwpm_release_sw_setup,
};
static bool t234_hwpm_validate_hals(struct tegra_soc_hwpm *hwpm)
@@ -215,11 +213,6 @@ static bool t234_hwpm_validate_hals(struct tegra_soc_hwpm *hwpm)
return false;
}
if (hwpm->active_chip->release_sw_setup == NULL) {
tegra_hwpm_err(hwpm, "release_sw_setup uninitialized");
return false;
}
return true;
}

View File

@@ -14,13 +14,6 @@
#ifndef TEGRA_HWPM_H
#define TEGRA_HWPM_H
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <uapi/linux/tegra-soc-hwpm-uapi.h>
#include <tegra_hwpm_types.h>
#define TEGRA_SOC_HWPM_IP_INACTIVE ~(0U)
@@ -431,54 +424,21 @@ struct tegra_soc_hwpm_chip {
u64 *full_alist_idx);
bool (*check_alist)(struct tegra_soc_hwpm *hwpm,
struct hwpm_ip_aperture *aperture, u64 phys_addr);
void (*release_sw_setup)(struct tegra_soc_hwpm *hwpm);
};
extern struct platform_device *tegra_soc_hwpm_pdev;
extern const struct file_operations tegra_soc_hwpm_ops;
struct allowlist;
struct tegra_hwpm_mem_mgmt;
struct tegra_hwpm_allowlist_map;
/* Driver struct */
struct tegra_soc_hwpm {
/* Device */
struct platform_device *pdev;
struct device *dev;
struct device_node *np;
struct class class;
dev_t dev_t;
struct cdev cdev;
/* Device info */
struct tegra_soc_hwpm_device_info device_info;
/* Active chip info */
struct tegra_soc_hwpm_chip *active_chip;
/* Clocks and resets */
struct clk *la_clk;
struct clk *la_parent_clk;
struct reset_control *la_rst;
struct reset_control *hwpm_rst;
/* Memory Management */
struct tegra_hwpm_mem_mgmt *mem_mgmt;
struct tegra_hwpm_allowlist_map *alist_map;
/* SW State */
u32 dbg_mask;
bool bind_completed;
bool device_opened;
atomic_t hwpm_in_use;
u32 dbg_mask;
/* Debugging */
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
#endif
bool fake_registers_enabled;
};

View File

@@ -26,8 +26,8 @@ struct hwpm_ip;
struct hwpm_ip_inst;
struct hwpm_ip_aperture;
int tegra_hwpm_init_sw_components(struct tegra_soc_hwpm *hwpm);
void tegra_hwpm_release_sw_components(struct tegra_soc_hwpm *hwpm);
int tegra_hwpm_init_sw_components(struct tegra_soc_hwpm *hwpm,
u32 chip_id, u32 chip_id_rev);
int tegra_hwpm_func_all_ip(struct tegra_soc_hwpm *hwpm,
struct tegra_hwpm_func_args *func_args,

View File

@@ -14,8 +14,7 @@
#ifndef TEGRA_HWPM_STATIC_ANALYSIS_H
#define TEGRA_HWPM_STATIC_ANALYSIS_H
#include <linux/types.h>
#include <linux/bug.h>
#include <tegra_hwpm_types.h>
/**
* @brief Add two u32 values and check for overflow.

View File

@@ -16,6 +16,9 @@
#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/err.h>
#include <linux/bug.h>
#include <linux/bits.h>
#endif
#endif /* TEGRA_HWPM_TYPES_H */

View File

@@ -20,24 +20,32 @@
#include <tegra_hwpm_log.h>
#include <tegra_hwpm_io.h>
#include <tegra_hwpm.h>
#include <os/linux/driver.h>
int tegra_hwpm_perfmon_reserve_impl(struct tegra_soc_hwpm *hwpm,
struct hwpm_ip_inst *ip_inst, struct hwpm_ip_aperture *perfmon)
{
struct resource *res = NULL;
struct tegra_hwpm_os_linux *hwpm_linux = NULL;
tegra_hwpm_fn(hwpm, " ");
hwpm_linux = tegra_hwpm_os_linux_from_hwpm(hwpm);
if (!hwpm_linux) {
tegra_hwpm_err(NULL, "Invalid hwpm_linux struct");
return -ENODEV;
}
/* Reserve */
res = platform_get_resource_byname(hwpm->pdev,
IORESOURCE_MEM, perfmon->name);
res = platform_get_resource_byname(hwpm_linux->pdev,
IORESOURCE_MEM, perfmon->name);
if ((!res) || (res->start == 0) || (res->end == 0)) {
tegra_hwpm_err(hwpm, "Failed to get perfmon %s", perfmon->name);
return -ENOMEM;
}
perfmon->dt_mmio = devm_ioremap(hwpm->dev, res->start,
resource_size(res));
perfmon->dt_mmio = devm_ioremap(
hwpm_linux->dev, res->start, resource_size(res));
if (IS_ERR(perfmon->dt_mmio)) {
tegra_hwpm_err(hwpm, "Couldn't map perfmon %s", perfmon->name);
return PTR_ERR(perfmon->dt_mmio);
@@ -116,13 +124,21 @@ int tegra_hwpm_perfmux_reserve_impl(struct tegra_soc_hwpm *hwpm,
int tegra_hwpm_perfmon_release_impl(struct tegra_soc_hwpm *hwpm,
struct hwpm_ip_aperture *perfmon)
{
struct tegra_hwpm_os_linux *hwpm_linux = NULL;
tegra_hwpm_fn(hwpm, " ");
hwpm_linux = tegra_hwpm_os_linux_from_hwpm(hwpm);
if (!hwpm_linux) {
tegra_hwpm_err(NULL, "Invalid hwpm_linux struct");
return -ENODEV;
}
if (perfmon->dt_mmio == NULL) {
tegra_hwpm_err(hwpm, "Perfmon was not mapped");
return -EINVAL;
}
devm_iounmap(hwpm->dev, perfmon->dt_mmio);
devm_iounmap(hwpm_linux->dev, perfmon->dt_mmio);
perfmon->dt_mmio = NULL;
perfmon->start_pa = 0ULL;
perfmon->end_pa = 0ULL;

View File

@@ -18,39 +18,44 @@
#include <tegra_hwpm_io.h>
#include <tegra_hwpm.h>
#include <os/linux/debugfs.h>
#include <os/linux/driver.h>
void tegra_hwpm_debugfs_init(struct tegra_soc_hwpm *hwpm)
void tegra_hwpm_debugfs_init(struct tegra_hwpm_os_linux *hwpm_linux)
{
if (!hwpm) {
tegra_hwpm_err(hwpm, "Invalid hwpm struct");
struct tegra_soc_hwpm *hwpm = &hwpm_linux->hwpm;
if (!hwpm_linux) {
tegra_hwpm_err(hwpm, "Invalid hwpm_linux struct");
return;
}
hwpm->debugfs_root =
hwpm_linux->debugfs_root =
debugfs_create_dir(TEGRA_SOC_HWPM_MODULE_NAME, NULL);
if (!hwpm->debugfs_root) {
if (!hwpm_linux->debugfs_root) {
tegra_hwpm_err(hwpm, "Failed to create debugfs root directory");
goto fail;
}
/* Debug logs */
debugfs_create_u32("log_mask", S_IRUGO|S_IWUSR, hwpm->debugfs_root,
&hwpm->dbg_mask);
debugfs_create_u32("log_mask", S_IRUGO|S_IWUSR,
hwpm_linux->debugfs_root, &hwpm->dbg_mask);
return;
fail:
debugfs_remove_recursive(hwpm->debugfs_root);
hwpm->debugfs_root = NULL;
debugfs_remove_recursive(hwpm_linux->debugfs_root);
hwpm_linux->debugfs_root = NULL;
}
void tegra_hwpm_debugfs_deinit(struct tegra_soc_hwpm *hwpm)
void tegra_hwpm_debugfs_deinit(struct tegra_hwpm_os_linux *hwpm_linux)
{
if (!hwpm) {
struct tegra_soc_hwpm *hwpm = &hwpm_linux->hwpm;
if (!hwpm_linux) {
tegra_hwpm_err(hwpm, "Invalid hwpm struct");
return;
}
debugfs_remove_recursive(hwpm->debugfs_root);
hwpm->debugfs_root = NULL;
debugfs_remove_recursive(hwpm_linux->debugfs_root);
hwpm_linux->debugfs_root = NULL;
}

View File

@@ -15,13 +15,16 @@
#define TEGRA_HWPM_OS_LINUX_DEBUGFS_H
struct tegra_soc_hwpm;
struct tegra_hwpm_os_linux;
#ifdef CONFIG_DEBUG_FS
void tegra_hwpm_debugfs_init(struct tegra_soc_hwpm *hwpm);
void tegra_hwpm_debugfs_deinit(struct tegra_soc_hwpm *hwpm);
void tegra_hwpm_debugfs_init(struct tegra_hwpm_os_linux *hwpm_linux);
void tegra_hwpm_debugfs_deinit(struct tegra_hwpm_os_linux *hwpm_linux);
#else
static inline void tegra_hwpm_debugfs_init(struct tegra_soc_hwpm *hwpm) {}
static inline void tegra_hwpm_debugfs_deinit(struct tegra_soc_hwpm *hwpm) {}
static inline void tegra_hwpm_debugfs_init(
struct tegra_hwpm_os_linux *hwpm_linux) {}
static inline void tegra_hwpm_debugfs_deinit(
struct tegra_hwpm_os_linux *hwpm_linux) {}
#endif /* CONFIG_DEBUG_FS */
#endif /* TEGRA_HWPM_OS_LINUX_DEBUGFS_H */

View File

@@ -23,11 +23,13 @@
#include <soc/tegra/fuse.h>
#include <tegra_hwpm.h>
#include <tegra_hwpm_ip.h>
#include <tegra_hwpm_log.h>
#include <tegra_hwpm_soc.h>
#include <tegra_hwpm_kmem.h>
#include <tegra_hwpm_common.h>
#include <os/linux/debugfs.h>
#include <os/linux/ip_utils.h>
#include <os/linux/driver.h>
static const struct of_device_id tegra_soc_hwpm_of_match[] = {
{
@@ -64,16 +66,12 @@ static bool tegra_hwpm_read_support_soc_tools_prop(struct platform_device *pdev)
return allow_node;
}
static int tegra_hwpm_init_chip_info(struct tegra_soc_hwpm *hwpm)
int tegra_hwpm_init_chip_info(struct tegra_hwpm_os_linux *hwpm_linux)
{
tegra_hwpm_fn(hwpm, " ");
hwpm->dbg_mask = TEGRA_HWPM_DEFAULT_DBG_MASK;
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_linux->device_info.chip = tegra_get_chip_id();
hwpm_linux->device_info.chip_revision = tegra_get_major_rev();
hwpm_linux->device_info.revision = tegra_chip_get_revision();
hwpm_linux->device_info.platform = tegra_get_platform();
return 0;
}
@@ -82,6 +80,7 @@ static int tegra_hwpm_probe(struct platform_device *pdev)
{
int ret = 0;
struct device *dev = NULL;
struct tegra_hwpm_os_linux *hwpm_linux = NULL;
struct tegra_soc_hwpm *hwpm = NULL;
if (!pdev) {
@@ -96,94 +95,100 @@ static int tegra_hwpm_probe(struct platform_device *pdev)
goto fail;
}
hwpm = kzalloc(sizeof(struct tegra_soc_hwpm), GFP_KERNEL);
if (!hwpm) {
tegra_hwpm_err(hwpm, "Couldn't allocate memory for hwpm struct");
hwpm_linux = kzalloc(sizeof(struct tegra_hwpm_os_linux), GFP_KERNEL);
if (!hwpm_linux) {
tegra_hwpm_err(NULL,
"Couldn't allocate memory for linux hwpm struct");
ret = -ENOMEM;
goto fail;
}
hwpm->pdev = pdev;
hwpm->dev = &pdev->dev;
hwpm->np = pdev->dev.of_node;
hwpm->class.owner = THIS_MODULE;
hwpm->class.name = TEGRA_SOC_HWPM_MODULE_NAME;
hwpm_linux->pdev = pdev;
hwpm_linux->dev = &pdev->dev;
hwpm_linux->np = pdev->dev.of_node;
hwpm_linux->class.owner = THIS_MODULE;
hwpm_linux->class.name = TEGRA_SOC_HWPM_MODULE_NAME;
hwpm = &hwpm_linux->hwpm;
/* Create device node */
ret = class_register(&hwpm->class);
ret = class_register(&hwpm_linux->class);
if (ret) {
tegra_hwpm_err(hwpm, "Failed to register class");
goto class_register;
}
/* Set devnode to retrieve device permissions */
hwpm->class.devnode = tegra_hwpm_get_devnode;
hwpm_linux->class.devnode = tegra_hwpm_get_devnode;
ret = alloc_chrdev_region(&hwpm->dev_t, 0, 1, dev_name(hwpm->dev));
ret = alloc_chrdev_region(&hwpm_linux->dev_t, 0, 1,
dev_name(hwpm_linux->dev));
if (ret) {
tegra_hwpm_err(hwpm, "Failed to allocate device region");
goto alloc_chrdev_region;
}
cdev_init(&hwpm->cdev, &tegra_soc_hwpm_ops);
hwpm->cdev.owner = THIS_MODULE;
cdev_init(&hwpm_linux->cdev, &tegra_hwpm_ops);
hwpm_linux->cdev.owner = THIS_MODULE;
ret = cdev_add(&hwpm->cdev, hwpm->dev_t, 1);
ret = cdev_add(&hwpm_linux->cdev, hwpm_linux->dev_t, 1);
if (ret) {
tegra_hwpm_err(hwpm, "Failed to add cdev");
goto cdev_add;
}
dev = device_create(&hwpm->class,
NULL,
hwpm->dev_t,
NULL,
TEGRA_SOC_HWPM_MODULE_NAME);
dev = device_create(&hwpm_linux->class, NULL,
hwpm_linux->dev_t, NULL, TEGRA_SOC_HWPM_MODULE_NAME);
if (IS_ERR(dev)) {
tegra_hwpm_err(hwpm, "Failed to create device");
ret = PTR_ERR(dev);
goto device_create;
}
(void) dma_set_mask_and_coherent(hwpm->dev, DMA_BIT_MASK(39));
(void) dma_set_mask_and_coherent(hwpm_linux->dev, DMA_BIT_MASK(39));
if (tegra_hwpm_is_platform_silicon()) {
hwpm->la_clk = devm_clk_get(hwpm->dev, "la");
if (IS_ERR(hwpm->la_clk)) {
hwpm_linux->la_clk = devm_clk_get(hwpm_linux->dev, "la");
if (IS_ERR(hwpm_linux->la_clk)) {
tegra_hwpm_err(hwpm, "Missing la clock");
ret = PTR_ERR(hwpm->la_clk);
ret = PTR_ERR(hwpm_linux->la_clk);
goto clock_reset_fail;
}
hwpm->la_parent_clk = devm_clk_get(hwpm->dev, "parent");
if (IS_ERR(hwpm->la_parent_clk)) {
hwpm_linux->la_parent_clk =
devm_clk_get(hwpm_linux->dev, "parent");
if (IS_ERR(hwpm_linux->la_parent_clk)) {
tegra_hwpm_err(hwpm, "Missing la parent clk");
ret = PTR_ERR(hwpm->la_parent_clk);
ret = PTR_ERR(hwpm_linux->la_parent_clk);
goto clock_reset_fail;
}
hwpm->la_rst = devm_reset_control_get(hwpm->dev, "la");
if (IS_ERR(hwpm->la_rst)) {
hwpm_linux->la_rst =
devm_reset_control_get(hwpm_linux->dev, "la");
if (IS_ERR(hwpm_linux->la_rst)) {
tegra_hwpm_err(hwpm, "Missing la reset");
ret = PTR_ERR(hwpm->la_rst);
ret = PTR_ERR(hwpm_linux->la_rst);
goto clock_reset_fail;
}
hwpm->hwpm_rst = devm_reset_control_get(hwpm->dev, "hwpm");
if (IS_ERR(hwpm->hwpm_rst)) {
hwpm_linux->hwpm_rst =
devm_reset_control_get(hwpm_linux->dev, "hwpm");
if (IS_ERR(hwpm_linux->hwpm_rst)) {
tegra_hwpm_err(hwpm, "Missing hwpm reset");
ret = PTR_ERR(hwpm->hwpm_rst);
ret = PTR_ERR(hwpm_linux->hwpm_rst);
goto clock_reset_fail;
}
}
tegra_hwpm_debugfs_init(hwpm);
ret = tegra_hwpm_init_chip_info(hwpm);
tegra_hwpm_debugfs_init(hwpm_linux);
ret = tegra_hwpm_init_chip_info(hwpm_linux);
if (ret != 0) {
tegra_hwpm_err(hwpm, "Failed to initialize current chip info.");
tegra_hwpm_err(hwpm, "Failed to initialize current chip info");
goto init_chip_info_fail;
}
ret = tegra_hwpm_init_sw_components(hwpm);
ret = tegra_hwpm_init_sw_components(hwpm, hwpm_linux->device_info.chip,
hwpm_linux->device_info.chip_revision);
if (ret != 0) {
tegra_hwpm_err(hwpm, "Failed to init sw components");
goto init_sw_components_fail;
@@ -207,25 +212,26 @@ static int tegra_hwpm_probe(struct platform_device *pdev)
init_chip_info_fail:
init_sw_components_fail:
if (tegra_hwpm_is_platform_silicon()) {
if (hwpm->la_clk)
devm_clk_put(hwpm->dev, hwpm->la_clk);
if (hwpm->la_parent_clk)
devm_clk_put(hwpm->dev, hwpm->la_parent_clk);
if (hwpm->la_rst)
reset_control_assert(hwpm->la_rst);
if (hwpm->hwpm_rst)
reset_control_assert(hwpm->hwpm_rst);
if (hwpm_linux->la_clk)
devm_clk_put(hwpm_linux->dev, hwpm_linux->la_clk);
if (hwpm_linux->la_parent_clk)
devm_clk_put(hwpm_linux->dev,
hwpm_linux->la_parent_clk);
if (hwpm_linux->la_rst)
reset_control_assert(hwpm_linux->la_rst);
if (hwpm_linux->hwpm_rst)
reset_control_assert(hwpm_linux->hwpm_rst);
}
clock_reset_fail:
device_destroy(&hwpm->class, hwpm->dev_t);
device_destroy(&hwpm_linux->class, hwpm_linux->dev_t);
device_create:
cdev_del(&hwpm->cdev);
cdev_del(&hwpm_linux->cdev);
cdev_add:
unregister_chrdev_region(hwpm->dev_t, 1);
unregister_chrdev_region(hwpm_linux->dev_t, 1);
alloc_chrdev_region:
class_unregister(&hwpm->class);
class_unregister(&hwpm_linux->class);
class_register:
kfree(hwpm);
tegra_hwpm_kfree(NULL, hwpm_linux);
fail:
tegra_hwpm_err(NULL, "Probe failed!");
success:
@@ -234,6 +240,7 @@ success:
static int tegra_hwpm_remove(struct platform_device *pdev)
{
struct tegra_hwpm_os_linux *hwpm_linux = NULL;
struct tegra_soc_hwpm *hwpm = NULL;
if (!pdev) {
@@ -247,25 +254,34 @@ static int tegra_hwpm_remove(struct platform_device *pdev)
return -ENODEV;
}
if (tegra_hwpm_is_platform_silicon()) {
if (hwpm->la_clk)
devm_clk_put(hwpm->dev, hwpm->la_clk);
if (hwpm->la_parent_clk)
devm_clk_put(hwpm->dev, hwpm->la_parent_clk);
if (hwpm->la_rst)
reset_control_assert(hwpm->la_rst);
if (hwpm->hwpm_rst)
reset_control_assert(hwpm->hwpm_rst);
hwpm_linux = tegra_hwpm_os_linux_from_hwpm(hwpm);
if (!hwpm_linux) {
tegra_hwpm_err(NULL, "Invalid hwpm_linux struct");
return -ENODEV;
}
device_destroy(&hwpm->class, hwpm->dev_t);
cdev_del(&hwpm->cdev);
unregister_chrdev_region(hwpm->dev_t, 1);
class_unregister(&hwpm->class);
if (tegra_hwpm_is_platform_silicon()) {
if (hwpm_linux->la_clk)
devm_clk_put(hwpm_linux->dev, hwpm_linux->la_clk);
if (hwpm_linux->la_parent_clk)
devm_clk_put(hwpm_linux->dev, hwpm_linux->la_parent_clk);
if (hwpm_linux->la_rst)
reset_control_assert(hwpm_linux->la_rst);
if (hwpm_linux->hwpm_rst)
reset_control_assert(hwpm_linux->hwpm_rst);
}
tegra_hwpm_debugfs_deinit(hwpm);
tegra_hwpm_release_ip_register_node(hwpm);
tegra_hwpm_release_sw_components(hwpm);
tegra_hwpm_release_sw_setup(hwpm);
tegra_hwpm_debugfs_deinit(hwpm_linux);
device_destroy(&hwpm_linux->class, hwpm_linux->dev_t);
cdev_del(&hwpm_linux->cdev);
unregister_chrdev_region(hwpm_linux->dev_t, 1);
class_unregister(&hwpm_linux->class);
tegra_hwpm_kfree(NULL, hwpm_linux);
tegra_soc_hwpm_pdev = NULL;
return 0;
}

View File

@@ -14,10 +14,68 @@
#ifndef TEGRA_HWPM_OS_LINUX_DRIVER_H
#define TEGRA_HWPM_OS_LINUX_DRIVER_H
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <tegra_hwpm.h>
#include <uapi/linux/tegra-soc-hwpm-uapi.h>
#define TEGRA_SOC_HWPM_MODULE_NAME "tegra-soc-hwpm"
extern struct platform_device *tegra_soc_hwpm_pdev;
extern const struct file_operations tegra_hwpm_ops;
typedef struct tegra_hwpm_linux_atomic_t {
atomic_t var;
} tegra_hwpm_atomic_t;
struct hwpm_ip_register_list {
struct tegra_soc_hwpm_ip_ops ip_ops;
struct hwpm_ip_register_list *next;
};
extern struct hwpm_ip_register_list *ip_register_list_head;
struct tegra_hwpm_os_linux {
struct tegra_soc_hwpm hwpm;
/* Device */
struct platform_device *pdev;
struct device *dev;
struct device_node *np;
struct class class;
dev_t dev_t;
struct cdev cdev;
/* Clocks and resets */
struct clk *la_clk;
struct clk *la_parent_clk;
struct reset_control *la_rst;
struct reset_control *hwpm_rst;
/* Device info */
struct tegra_soc_hwpm_device_info device_info;
/* Reference count */
tegra_hwpm_atomic_t usage_count;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
#endif
};
static inline struct tegra_hwpm_os_linux *tegra_hwpm_os_linux_from_cdev(
struct cdev *cdev)
{
return container_of(cdev, struct tegra_hwpm_os_linux, cdev);
}
static inline struct tegra_hwpm_os_linux *tegra_hwpm_os_linux_from_hwpm(
struct tegra_soc_hwpm *hwpm)
{
return container_of(hwpm, struct tegra_hwpm_os_linux, hwpm);
}
#endif /* TEGRA_HWPM_OS_LINUX_DRIVER_H */

View File

@@ -29,8 +29,11 @@
#include <tegra_hwpm_ip.h>
#include <tegra_hwpm_log.h>
#include <tegra_hwpm_soc.h>
#include <tegra_hwpm_kmem.h>
#include <tegra_hwpm_common.h>
#include <tegra_hwpm_mem_mgmt.h>
#include <os/linux/driver.h>
#include <os/linux/regops_utils.h>
#define LA_CLK_RATE 625000000UL
@@ -38,12 +41,20 @@
static int tegra_hwpm_get_device_info_ioctl(struct tegra_soc_hwpm *hwpm,
struct tegra_soc_hwpm_device_info *device_info)
{
struct tegra_hwpm_os_linux *hwpm_linux = NULL;
tegra_hwpm_fn(hwpm, " ");
device_info->chip = hwpm->device_info.chip;
device_info->chip_revision = hwpm->device_info.chip_revision;
device_info->revision = hwpm->device_info.revision;
device_info->platform = hwpm->device_info.platform;
hwpm_linux = tegra_hwpm_os_linux_from_hwpm(hwpm);
if (!hwpm_linux) {
tegra_hwpm_err(NULL, "Invalid hwpm_linux struct");
return -ENODEV;
}
device_info->chip = hwpm_linux->device_info.chip;
device_info->chip_revision = hwpm_linux->device_info.chip_revision;
device_info->revision = hwpm_linux->device_info.revision;
device_info->platform = hwpm_linux->device_info.platform;
tegra_hwpm_dbg(hwpm, hwpm_info | hwpm_dbg_device_info,
"chip id 0x%x", device_info->chip);
@@ -227,11 +238,6 @@ static int tegra_hwpm_update_get_put_ioctl(struct tegra_soc_hwpm *hwpm,
" after the BIND IOCTL.");
return -EPERM;
}
if (!hwpm->mem_mgmt->mem_bytes_kernel) {
tegra_hwpm_err(hwpm,
"mem_bytes buffer is not mapped in the driver");
return -ENXIO;
}
return tegra_hwpm_update_mem_bytes(hwpm, update_get_put);
}
@@ -275,7 +281,7 @@ static long tegra_hwpm_ioctl(struct file *file,
}
if (!(_IOC_DIR(cmd) & _IOC_NONE)) {
buf = kzalloc(TEGRA_SOC_HWPM_MAX_ARG_SIZE, GFP_KERNEL);
buf = tegra_hwpm_kzalloc(hwpm, TEGRA_SOC_HWPM_MAX_ARG_SIZE);
if (!buf) {
tegra_hwpm_err(hwpm, "Kernel buf allocation failed");
ret = -ENOMEM;
@@ -343,7 +349,7 @@ static long tegra_hwpm_ioctl(struct file *file,
fail:
if (buf) {
kfree(buf);
tegra_hwpm_kfree(hwpm, buf);
}
if (ret < 0) {
@@ -360,51 +366,55 @@ static int tegra_hwpm_open(struct inode *inode, struct file *filp)
int ret = 0;
unsigned int minor;
struct tegra_soc_hwpm *hwpm = NULL;
struct tegra_hwpm_os_linux *hwpm_linux = NULL;
if (!inode) {
tegra_hwpm_err(hwpm, "Invalid inode");
tegra_hwpm_err(NULL, "Invalid inode");
return -EINVAL;
}
if (!filp) {
tegra_hwpm_err(hwpm, "Invalid file");
tegra_hwpm_err(NULL, "Invalid file");
return -EINVAL;
}
minor = iminor(inode);
if (minor > 0) {
tegra_hwpm_err(hwpm, "Incorrect minor number");
tegra_hwpm_err(NULL, "Incorrect minor number");
return -EBADFD;
}
hwpm = container_of(inode->i_cdev, struct tegra_soc_hwpm, cdev);
if (!hwpm) {
tegra_hwpm_err(hwpm, "Invalid hwpm struct");
hwpm_linux =
container_of(inode->i_cdev, struct tegra_hwpm_os_linux, cdev);
if (!hwpm_linux) {
tegra_hwpm_err(NULL, "Invalid hwpm_linux struct");
return -EINVAL;
}
hwpm = &hwpm_linux->hwpm;
filp->private_data = hwpm;
tegra_hwpm_fn(hwpm, " ");
/* Initialize driver on first open call only */
if (!atomic_add_unless(&hwpm->hwpm_in_use, 1U, 1U)) {
if (!atomic_add_unless(&hwpm_linux->usage_count.var, 1U, 1U)) {
return -EAGAIN;
}
if (tegra_hwpm_is_platform_silicon()) {
ret = reset_control_assert(hwpm->hwpm_rst);
ret = reset_control_assert(hwpm_linux->hwpm_rst);
if (ret < 0) {
tegra_hwpm_err(hwpm, "hwpm reset assert failed");
goto fail;
}
ret = reset_control_assert(hwpm->la_rst);
ret = reset_control_assert(hwpm_linux->la_rst);
if (ret < 0) {
tegra_hwpm_err(hwpm, "la reset assert failed");
goto fail;
}
/* Set required parent for la_clk */
if (hwpm->la_clk && hwpm->la_parent_clk) {
ret = clk_set_parent(hwpm->la_clk, hwpm->la_parent_clk);
if (hwpm_linux->la_clk && hwpm_linux->la_parent_clk) {
ret = clk_set_parent(
hwpm_linux->la_clk, hwpm_linux->la_parent_clk);
if (ret < 0) {
tegra_hwpm_err(hwpm,
"la clk set parent failed");
@@ -412,22 +422,22 @@ static int tegra_hwpm_open(struct inode *inode, struct file *filp)
}
}
/* set la_clk rate to 625 MHZ */
ret = clk_set_rate(hwpm->la_clk, LA_CLK_RATE);
ret = clk_set_rate(hwpm_linux->la_clk, LA_CLK_RATE);
if (ret < 0) {
tegra_hwpm_err(hwpm, "la clock set rate failed");
goto fail;
}
ret = clk_prepare_enable(hwpm->la_clk);
ret = clk_prepare_enable(hwpm_linux->la_clk);
if (ret < 0) {
tegra_hwpm_err(hwpm, "la clock enable failed");
goto fail;
}
ret = reset_control_deassert(hwpm->la_rst);
ret = reset_control_deassert(hwpm_linux->la_rst);
if (ret < 0) {
tegra_hwpm_err(hwpm, "la reset deassert failed");
goto fail;
}
ret = reset_control_deassert(hwpm->hwpm_rst);
ret = reset_control_deassert(hwpm_linux->hwpm_rst);
if (ret < 0) {
tegra_hwpm_err(hwpm, "hwpm reset deassert failed");
goto fail;
@@ -471,25 +481,33 @@ static ssize_t tegra_hwpm_read(struct file *file,
static int tegra_hwpm_release(struct inode *inode, struct file *filp)
{
int ret = 0, err = 0;
struct tegra_hwpm_os_linux *hwpm_linux = NULL;
struct tegra_soc_hwpm *hwpm = NULL;
if (!inode) {
tegra_hwpm_err(hwpm, "Invalid inode");
tegra_hwpm_err(NULL, "Invalid inode");
return -EINVAL;
}
if (!filp) {
tegra_hwpm_err(hwpm, "Invalid file");
tegra_hwpm_err(NULL, "Invalid file");
return -EINVAL;
}
hwpm = container_of(inode->i_cdev, struct tegra_soc_hwpm, cdev);
if (!hwpm) {
tegra_hwpm_err(hwpm, "Invalid hwpm struct");
hwpm_linux =
container_of(inode->i_cdev, struct tegra_hwpm_os_linux, cdev);
if (!hwpm_linux) {
tegra_hwpm_err(NULL, "Invalid hwpm_linux struct");
return -EINVAL;
}
hwpm = &hwpm_linux->hwpm;
tegra_hwpm_fn(hwpm, " ");
/* De-init driver on last close call only */
if (!atomic_dec_and_test(&hwpm_linux->usage_count.var)) {
return 0;
}
if (hwpm->device_opened == false) {
/* Device was not opened, do nothing */
return 0;
@@ -528,24 +546,19 @@ static int tegra_hwpm_release(struct inode *inode, struct file *filp)
}
if (tegra_hwpm_is_platform_silicon()) {
ret = reset_control_assert(hwpm->hwpm_rst);
ret = reset_control_assert(hwpm_linux->hwpm_rst);
if (ret < 0) {
tegra_hwpm_err(hwpm, "hwpm reset assert failed");
err = ret;
goto fail;
}
ret = reset_control_assert(hwpm->la_rst);
ret = reset_control_assert(hwpm_linux->la_rst);
if (ret < 0) {
tegra_hwpm_err(hwpm, "la reset assert failed");
err = ret;
goto fail;
}
clk_disable_unprepare(hwpm->la_clk);
}
/* De-init driver on last close call only */
if (!atomic_dec_and_test(&hwpm->hwpm_in_use)) {
return 0;
clk_disable_unprepare(hwpm_linux->la_clk);
}
hwpm->device_opened = false;
@@ -554,7 +567,7 @@ fail:
}
/* File ops for device node */
const struct file_operations tegra_soc_hwpm_ops = {
const struct file_operations tegra_hwpm_ops = {
.owner = THIS_MODULE,
.open = tegra_hwpm_open,
.read = tegra_hwpm_read,

View File

@@ -34,7 +34,8 @@ static int tegra_hwpm_alloc_ip_register_list_node(
{
struct hwpm_ip_register_list *new_node = NULL;
new_node = kzalloc(sizeof(struct hwpm_ip_register_list), GFP_KERNEL);
new_node = tegra_hwpm_kzalloc(NULL,
sizeof(struct hwpm_ip_register_list));
if (new_node == NULL) {
tegra_hwpm_err(NULL,
"struct hwpm_ip_register_list node allocation failed");

View File

@@ -31,11 +31,21 @@
#include <tegra_hwpm_mem_mgmt.h>
#include <tegra_hwpm_static_analysis.h>
#include <os/linux/driver.h>
static int tegra_hwpm_dma_map_stream_buffer(struct tegra_soc_hwpm *hwpm,
struct tegra_soc_hwpm_alloc_pma_stream *alloc_pma_stream)
{
struct tegra_hwpm_os_linux *hwpm_linux = NULL;
tegra_hwpm_fn(hwpm, " ");
hwpm_linux = tegra_hwpm_os_linux_from_hwpm(hwpm);
if (!hwpm_linux) {
tegra_hwpm_err(NULL, "Invalid hwpm_linux struct");
return -ENODEV;
}
hwpm->mem_mgmt->stream_buf_size = alloc_pma_stream->stream_buf_size;
hwpm->mem_mgmt->stream_dma_buf =
dma_buf_get(tegra_hwpm_safe_cast_u64_to_s32(
@@ -45,7 +55,7 @@ static int tegra_hwpm_dma_map_stream_buffer(struct tegra_soc_hwpm *hwpm,
return PTR_ERR(hwpm->mem_mgmt->stream_dma_buf);
}
hwpm->mem_mgmt->stream_attach =
dma_buf_attach(hwpm->mem_mgmt->stream_dma_buf, hwpm->dev);
dma_buf_attach(hwpm->mem_mgmt->stream_dma_buf, hwpm_linux->dev);
if (IS_ERR(hwpm->mem_mgmt->stream_attach)) {
tegra_hwpm_err(hwpm, "Unable to attach stream dma_buf");
return PTR_ERR(hwpm->mem_mgmt->stream_attach);
@@ -74,8 +84,16 @@ static int tegra_hwpm_dma_map_stream_buffer(struct tegra_soc_hwpm *hwpm,
static int tegra_hwpm_dma_map_mem_bytes_buffer(struct tegra_soc_hwpm *hwpm,
struct tegra_soc_hwpm_alloc_pma_stream *alloc_pma_stream)
{
struct tegra_hwpm_os_linux *hwpm_linux = NULL;
tegra_hwpm_fn(hwpm, " ");
hwpm_linux = tegra_hwpm_os_linux_from_hwpm(hwpm);
if (!hwpm_linux) {
tegra_hwpm_err(NULL, "Invalid hwpm_linux struct");
return -ENODEV;
}
hwpm->mem_mgmt->mem_bytes_dma_buf =
dma_buf_get(tegra_hwpm_safe_cast_u64_to_s32(
alloc_pma_stream->mem_bytes_buf_fd));
@@ -85,7 +103,7 @@ static int tegra_hwpm_dma_map_mem_bytes_buffer(struct tegra_soc_hwpm *hwpm,
}
hwpm->mem_mgmt->mem_bytes_attach = dma_buf_attach(
hwpm->mem_mgmt->mem_bytes_dma_buf, hwpm->dev);
hwpm->mem_mgmt->mem_bytes_dma_buf, hwpm_linux->dev);
if (IS_ERR(hwpm->mem_mgmt->mem_bytes_attach)) {
tegra_hwpm_err(hwpm, "Unable to attach mem bytes dma_buf");
return PTR_ERR(hwpm->mem_mgmt->mem_bytes_attach);