nvdla: Replace deprecated nvhost_module* APIs

Remove dependencies on the following deprecated
nvhost API functions by implementing their functionality
directly in the NVDLA driver:

1. nvhost_module_init:
   Replaced with direct implementation in nvdla_module_init:
   - Get clock resources and set clock rates
   - Initialize reset control
   - Set up power management runtime
   - Create debugfs entries

2. nvhost_module_deinit:
   Replaced with direct implementation in nvdla_module_deinit:
   - Disable power management runtime
   - Free falcon firmware if present
   - Clean up debugfs entries

3. nvhost_module_reset:
   Replaced with direct implementation in nvdla_module_reset:
   - Handle prepare_poweroff callback
   - Acquire and release reset control
   - Load clock gating registers
   - Handle finalize_poweron callback

4. nvhost_module_busy:
   Replaced with direct implementation in nvdla_module_busy:
   - Get PM runtime sync
   - Handle PM runtime errors

5. nvhost_module_idle and nvhost_module_idle_mult:
   Replaced with direct implementations:
   - Mark last busy for PM runtime
   - Handle autosuspend or regular PM runtime put

6. nvhost_module_pm_ops:
  Replaced with custom nvdla_pm_ops structure:
   - Implement nvdla_runtime_suspend and nvdla_runtime_resume
   - Implement nvdla_suspend and nvdla_resume
   - Configure SET_RUNTIME_PM_OPS and SET_SYSTEM_SLEEP_PM_OPS

7. nvhost_module_load_regs:
   Replaced with nvdla_module_load_regs:
   - Implement register manipulation with direct memory mapped I/O
   - Use writel instead of host1x_writel

Bug 4921620

Jira HOSTX-5963

Change-Id: I3006a92a05966da138da31730e97f74f786c9d0c
Signed-off-by: Mainak Sen <msen@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3321246
Reviewed-by: Arvind M <am@nvidia.com>
Reviewed-by: Mitch Harwell <mharwell@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
Mainak Sen
2025-03-18 04:38:05 +00:00
committed by Jon Hunter
parent 0f991be9e7
commit cdf96fa81b
3 changed files with 258 additions and 84 deletions

View File

@@ -10,6 +10,7 @@
#include "../../dla_queue.h" #include "../../dla_queue.h"
#include "../../nvdla_debug.h" #include "../../nvdla_debug.h"
#include "../fw/nvdla_falcon.h"
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
@@ -19,6 +20,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/reset.h>
uint32_t nvdla_device_register_read(struct platform_device *pdev, uint32_t nvdla_device_register_read(struct platform_device *pdev,
uint32_t reg) uint32_t reg)
@@ -126,6 +128,7 @@ int32_t nvdla_module_init(struct platform_device *pdev)
int32_t err; int32_t err;
struct nvhost_device_data *pdata = platform_get_drvdata(pdev); struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
int i; int i;
unsigned int num_clks;
pdata->host1x = dev_get_drvdata(pdev->dev.parent); pdata->host1x = dev_get_drvdata(pdev->dev.parent);
if (!pdata->host1x) { if (!pdata->host1x) {
@@ -153,16 +156,62 @@ int32_t nvdla_module_init(struct platform_device *pdev)
pdata->aperture[i] = regs; pdata->aperture[i] = regs;
} }
err = nvhost_module_init(pdev); err = devm_clk_bulk_get_all(&pdev->dev, &pdata->clks);
if (err) { if (err < 0) {
nvdla_dbg_err(pdev, "Failed to init module (err: %x)", err); dev_err(&pdev->dev, "failed to get clocks %d\n", err);
return err; return err;
} }
pdata->num_clks = err;
num_clks = err;
for (i = 0; i < num_clks; i++) {
err = clk_set_rate(pdata->clks[i].clk, ULONG_MAX);
if (err < 0) {
dev_err(&pdev->dev, "failed to set clock rate!\n");
return err;
}
}
pdata->reset_control = devm_reset_control_get_exclusive_released(&pdev->dev, NULL);
if (IS_ERR(pdata->reset_control)) {
dev_err(&pdev->dev, "failed to get reset\n");
return PTR_ERR(pdata->reset_control);
}
err = reset_control_acquire(pdata->reset_control);
if (err < 0) {
dev_err(&pdev->dev, "failed to acquire reset: %d\n", err);
return err;
}
err = clk_bulk_prepare_enable(num_clks, pdata->clks);
if (err < 0) {
reset_control_release(pdata->reset_control);
dev_err(&pdev->dev, "failed to enabled clocks: %d\n", err);
return err;
}
reset_control_reset(pdata->reset_control);
clk_bulk_disable_unprepare(num_clks, pdata->clks);
reset_control_release(pdata->reset_control);
if (pdata->autosuspend_delay) {
pm_runtime_set_autosuspend_delay(&pdev->dev, pdata->autosuspend_delay);
pm_runtime_use_autosuspend(&pdev->dev);
}
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev))
return -EOPNOTSUPP;
pdata->debugfs = debugfs_create_dir(pdev->dev.of_node->name, NULL);
err = nvdla_client_device_init(pdev); err = nvdla_client_device_init(pdev);
if (err) { if (err) {
nvdla_dbg_err(pdev, "Failed to client device (err: %x)", err); nvdla_dbg_err(pdev, "Failed to client device (err: %x)", err);
nvhost_module_deinit(pdev); /* Clean up in case of error */
pm_runtime_disable(&pdev->dev);
debugfs_remove_recursive(pdata->debugfs);
return err; return err;
} }
@@ -171,8 +220,19 @@ int32_t nvdla_module_init(struct platform_device *pdev)
void nvdla_module_deinit(struct platform_device *pdev) void nvdla_module_deinit(struct platform_device *pdev)
{ {
struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
struct falcon *falcon = pdata->falcon_data;
nvdla_client_device_release(pdev); nvdla_client_device_release(pdev);
nvhost_module_deinit(pdev); pm_runtime_disable(&pdev->dev);
if (falcon) {
dma_free_coherent(&pdev->dev, falcon->firmware.size,
falcon->firmware.virt, falcon->firmware.iova);
falcon_exit(falcon);
}
debugfs_remove_recursive(pdata->debugfs);
} }
int32_t nvdla_module_client_register(struct platform_device *pdev, int32_t nvdla_module_client_register(struct platform_device *pdev,
@@ -189,47 +249,182 @@ void nvdla_module_client_unregister(struct platform_device *pdev,
int32_t nvdla_module_busy(struct platform_device *pdev) int32_t nvdla_module_busy(struct platform_device *pdev)
{ {
return nvhost_module_busy(pdev); int err;
err = pm_runtime_get_sync(&pdev->dev);
if (err < 0) {
pm_runtime_put_noidle(&pdev->dev);
return err;
}
return 0;
} }
void nvdla_module_idle(struct platform_device *pdev) void nvdla_module_idle(struct platform_device *pdev)
{ {
nvhost_module_idle(pdev); nvdla_module_idle_mult(pdev, 1);
} }
void nvdla_module_idle_mult(struct platform_device *pdev, int32_t refs) void nvdla_module_idle_mult(struct platform_device *pdev, int32_t refs)
{ {
nvhost_module_idle_mult(pdev, refs); struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
while (refs--) {
pm_runtime_mark_last_busy(&pdev->dev);
if (pdata->autosuspend_delay)
pm_runtime_put_autosuspend(&pdev->dev);
else
pm_runtime_put(&pdev->dev);
}
}
static void nvdla_module_load_regs(struct platform_device *pdev, bool prod)
{
struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
struct nvhost_gating_register *regs = pdata->engine_cg_regs;
if (!regs)
return;
while (regs->addr) {
if (prod) {
void __iomem *addr = pdata->aperture[0] + regs->addr;
writel(regs->prod, addr);
} else {
void __iomem *addr = pdata->aperture[0] + regs->addr;
writel(regs->disable, addr);
}
regs++;
}
} }
void nvdla_module_reset(struct platform_device *pdev, bool reboot) void nvdla_module_reset(struct platform_device *pdev, bool reboot)
{ {
nvhost_module_reset(pdev, reboot); struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
int err;
if (reboot)
if (pdata->prepare_poweroff)
pdata->prepare_poweroff(pdev);
mutex_lock(&pdata->lock);
err = reset_control_acquire(pdata->reset_control);
if (err < 0) {
dev_err(&pdev->dev, "failed to acquire reset: %d\n", err);
} else {
reset_control_reset(pdata->reset_control);
reset_control_release(pdata->reset_control);
}
mutex_unlock(&pdata->lock);
if (reboot) {
/* Load clockgating registers */
nvdla_module_load_regs(pdev, pdata->engine_can_cg);
/* ..and execute engine specific operations (i.e. boot) */
if (pdata->finalize_poweron)
pdata->finalize_poweron(pdev);
}
} }
/* Define our own runtime_suspend function for nvdla */
static int nvdla_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct nvhost_device_data *pdata = dev_get_drvdata(dev);
int err;
if (pdata->prepare_poweroff) {
err = pdata->prepare_poweroff(pdev);
if (err)
return err;
}
clk_bulk_disable_unprepare(pdata->num_clks, pdata->clks);
return 0;
}
/* Define our own runtime_resume function for nvdla */
static int nvdla_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct nvhost_device_data *pdata = dev_get_drvdata(dev);
int err;
err = clk_bulk_prepare_enable(pdata->num_clks, pdata->clks);
if (err < 0) {
dev_err(&pdev->dev, "failed to enabled clocks: %d\n", err);
return err;
}
if (pdata->poweron_reset)
nvdla_module_reset(pdev, false);
/* Load clockgating registers */
nvdla_module_load_regs(pdev, pdata->engine_can_cg);
if (pdata->finalize_poweron)
err = pdata->finalize_poweron(pdev);
return err;
}
/* Define our own suspend function for nvdla */
static int nvdla_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct nvhost_device_data *pdata = dev_get_drvdata(dev);
int err = 0;
if (pdata->prepare_poweroff) {
err = pdata->prepare_poweroff(pdev);
if (err)
return err;
}
clk_bulk_disable_unprepare(pdata->num_clks, pdata->clks);
return 0;
}
/* Define our own resume function for nvdla */
static int nvdla_resume(struct device *dev)
{
return nvdla_runtime_resume(dev);
}
/* Create our own PM operations structure */
static const struct dev_pm_ops nvdla_pm_ops = {
.runtime_suspend = nvdla_runtime_suspend,
.runtime_resume = nvdla_runtime_resume,
.suspend = nvdla_suspend,
.resume = nvdla_resume,
};
/* Module runtime suspend implementation */
int nvdla_module_runtime_suspend(struct device *dev) int nvdla_module_runtime_suspend(struct device *dev)
{ {
struct nvhost_device_data *pdata = dev_get_drvdata(dev); struct nvhost_device_data *pdata = dev_get_drvdata(dev);
struct nvdla_device *nvdla = pdata->private_data; struct nvdla_device *nvdla = pdata->private_data;
int err; int err;
if (nvhost_module_pm_ops.runtime_suspend != NULL) { /* Call directly to our own runtime_suspend */
err = nvhost_module_pm_ops.runtime_suspend(dev); err = nvdla_runtime_suspend(dev);
if (!err && nvdla->icc_write) { if (!err && nvdla->icc_write) {
err = icc_set_bw(nvdla->icc_write, 0, 0); err = icc_set_bw(nvdla->icc_write, 0, 0);
if (err) if (err)
dev_warn(&nvdla->pdev->dev, dev_warn(&nvdla->pdev->dev,
"failed to set icc_write bw: %d\n", "failed to set icc_write bw: %d\n",
err); err);
return 0;
}
return err;
} }
return -EOPNOTSUPP; return err;
} }
/* Module runtime resume implementation */
int nvdla_module_runtime_resume(struct device *dev) int nvdla_module_runtime_resume(struct device *dev)
{ {
struct nvhost_device_data *pdata = dev_get_drvdata(dev); struct nvhost_device_data *pdata = dev_get_drvdata(dev);
@@ -239,24 +434,20 @@ int nvdla_module_runtime_resume(struct device *dev)
u32 emc_kbps; u32 emc_kbps;
int err; int err;
if (nvhost_module_pm_ops.runtime_resume != NULL) { /* Call directly to our own runtime_resume */
err = nvhost_module_pm_ops.runtime_resume(dev); err = nvdla_runtime_resume(dev);
if (!err && nvdla->icc_write) { if (!err && nvdla->icc_write) {
rate = clk_get_rate(clk); rate = clk_get_rate(clk);
emc_kbps = rate * NVDLA_AXI_DBB_BW_BPC / 1024; emc_kbps = rate * NVDLA_AXI_DBB_BW_BPC / 1024;
err = icc_set_bw(nvdla->icc_write, kbps_to_icc(emc_kbps), err = icc_set_bw(nvdla->icc_write, kbps_to_icc(emc_kbps),
0); 0);
if (err) if (err)
dev_warn(&nvdla->pdev->dev, dev_warn(&nvdla->pdev->dev,
"failed to set icc_write bw: %d\n", "failed to set icc_write bw: %d\n",
err); err);
return 0;
}
return err;
} }
return -EOPNOTSUPP; return err;
} }
int nvdla_module_suspend(struct device *dev) int nvdla_module_suspend(struct device *dev)
@@ -265,18 +456,11 @@ int nvdla_module_suspend(struct device *dev)
struct nvdla_device *nvdla_dev = pdata->private_data; struct nvdla_device *nvdla_dev = pdata->private_data;
int err = 0; int err = 0;
if (nvhost_module_pm_ops.suspend != NULL) { /* Call directly to our own suspend */
err = nvhost_module_pm_ops.suspend(dev); err = nvdla_suspend(dev);
if (err != 0) { if (err != 0) {
dev_err(dev, "(FAIL) NvHost suspend\n"); dev_err(dev, "(FAIL) NVDLA suspend\n");
goto fail_nvhost_module_suspend; goto fail_nvhost_module_suspend;
}
} else {
err = pm_runtime_force_suspend(dev);
if (err != 0) {
dev_err(dev, "(FAIL) PM suspend\n");
goto fail_nvhost_module_suspend;
}
} }
if (nvdla_dev->icc_write) { if (nvdla_dev->icc_write) {
@@ -305,18 +489,11 @@ int nvdla_module_resume(struct device *dev)
goto fail_not_in_suspend; goto fail_not_in_suspend;
} }
if (nvhost_module_pm_ops.resume != NULL) { /* Call directly to our own resume */
err = nvhost_module_pm_ops.resume(dev); err = nvdla_resume(dev);
if (err != 0) { if (err != 0) {
dev_err(dev, "(FAIL) NvHost resume\n"); dev_err(dev, "(FAIL) NVDLA resume\n");
goto fail_nvhost_module_resume; goto fail_nvhost_module_resume;
}
} else {
err = pm_runtime_force_resume(dev);
if (err != 0) {
dev_err(dev, "(FAIL) PM resume\n");
goto fail_nvhost_module_resume;
}
} }
return 0; return 0;
@@ -345,25 +522,11 @@ int nvdla_module_prepare_suspend(struct device *dev)
goto fail_nvdla_queue_pool_prepare_suspend; goto fail_nvdla_queue_pool_prepare_suspend;
} }
/* NvHost prepare suspend - callback */ /* Drop runtime reference */
if (nvhost_module_pm_ops.prepare != NULL) { pm_runtime_put_sync(dev);
err = nvhost_module_pm_ops.prepare(dev);
if (err != 0) {
dev_err(dev, "(FAIL) NvHost prepare suspend\n");
goto fail_nvhost_module_prepare_suspend;
}
} else {
/* If we took an extra reference, drop it now to prevent
* the device from automatically resuming upon system
* resume.
*/
pm_runtime_put_sync(dev);
}
return 0; return 0;
fail_nvhost_module_prepare_suspend:
fail_nvdla_queue_pool_prepare_suspend: fail_nvdla_queue_pool_prepare_suspend:
fail_already_in_suspend: fail_already_in_suspend:
return err; return err;
@@ -374,12 +537,8 @@ void nvdla_module_complete_resume(struct device *dev)
struct nvhost_device_data *pdata = dev_get_drvdata(dev); struct nvhost_device_data *pdata = dev_get_drvdata(dev);
struct nvdla_device *nvdla_dev = pdata->private_data; struct nvdla_device *nvdla_dev = pdata->private_data;
if (nvhost_module_pm_ops.complete != NULL) { /* Retake reference dropped in prepare */
nvhost_module_pm_ops.complete(dev); pm_runtime_get_noresume(dev);
} else {
/* Retake reference dropped above */
pm_runtime_get_noresume(dev);
}
/* Module is no longer in suspend and has resumed successfully */ /* Module is no longer in suspend and has resumed successfully */
nvdla_dev->is_suspended = false; nvdla_dev->is_suspended = false;
@@ -388,6 +547,7 @@ void nvdla_module_complete_resume(struct device *dev)
static struct host1x_driver host1x_nvdla_driver = { static struct host1x_driver host1x_nvdla_driver = {
.driver = { .driver = {
.name = "host1x-nvdla", .name = "host1x-nvdla",
.pm = &nvdla_pm_ops,
}, },
}; };

View File

@@ -152,6 +152,19 @@ static int falcon_init(struct falcon *falcon)
return 0; return 0;
} }
/**
* falcon_exit() - Release resources used by falcon
*
* @falcon: Pointer to falcon structure
*
* This function releases firmware resources for falcon
*/
void falcon_exit(struct falcon *falcon)
{
if (falcon->firmware.firmware)
release_firmware(falcon->firmware.firmware);
}
static int falcon_boot(struct falcon *falcon) static int falcon_boot(struct falcon *falcon)
{ {
unsigned long offset; unsigned long offset;

View File

@@ -116,5 +116,6 @@ int nvdla_flcn_intr_init(struct platform_device *pdev);
int nvdla_flcn_reload_fw(struct platform_device *pdev); int nvdla_flcn_reload_fw(struct platform_device *pdev);
int nvdla_flcn_prepare_poweroff(struct platform_device *pdev); int nvdla_flcn_prepare_poweroff(struct platform_device *pdev);
int nvdla_flcn_finalize_poweron(struct platform_device *pdev); int nvdla_flcn_finalize_poweron(struct platform_device *pdev);
void falcon_exit(struct falcon *falcon);
#endif /* _NVDLA_PORT_FW_FALCON_H_ */ #endif /* _NVDLA_PORT_FW_FALCON_H_ */