diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c index adf6d63509b49fe68e0dfac524823830996aa083..e90d765d3af5dd9a838405a9a8e0204e1da83998 100644 --- a/drivers/accel/rocket/rocket_core.c +++ b/drivers/accel/rocket/rocket_core.c @@ -1,12 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright 2024 Tomeu Vizoso <tomeu@tomeuvizoso.net> */ -#include <asm-generic/delay.h> #include <linux/err.h> #include <linux/clk.h> +#include <linux/delay.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/pm_domain.h> +#include <linux/pm_runtime.h> #include <linux/reset.h> #include "rocket_core.h" diff --git a/drivers/accel/rocket/rocket_core.h b/drivers/accel/rocket/rocket_core.h index b9557104a32bcf6279c0c87393a4a03e087d36de..b72f738d539a0fd14c25e8b01b1c3ae5c03f9138 100644 --- a/drivers/accel/rocket/rocket_core.h +++ b/drivers/accel/rocket/rocket_core.h @@ -17,6 +17,7 @@ struct rocket_core { struct device *dev; struct rocket_device *rdev; unsigned int index; + struct device_link *link; struct reset_control *a_reset; struct reset_control *h_reset; diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c index 4c273d4320923a9c742be5f5dac6aa3fc980e1b5..0b9d51765af3b469e125d65b9d0b1fbe5d410572 100644 --- a/drivers/accel/rocket/rocket_drv.c +++ b/drivers/accel/rocket/rocket_drv.c @@ -144,11 +144,11 @@ static int rocket_drm_bind(struct device *dev) if (err) goto err_drm_dev; - // pm_runtime_use_autosuspend(dev); - // pm_runtime_set_autosuspend_delay(dev, 50); /* ~3 frames */ - // pm_runtime_set_active(dev); - // pm_runtime_enable(dev); - // pm_runtime_mark_last_busy(dev); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_autosuspend_delay(dev, 50); /* ~3 frames */ + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_mark_last_busy(dev); /* * Register the DRM device with the core and the connectors with @@ -158,6 +158,8 @@ static int rocket_drm_bind(struct device *dev) if (err < 0) goto err_pm_runtime; + printk("*** %s: %d dev %s usage_count %d links_count %d\n", __func__, 99, dev_name(dev), atomic_read(&dev->power.usage_count), dev->power.links_count); + return 0; err_pm_runtime: @@ -180,9 +182,9 @@ static void rocket_drm_unbind(struct device *dev) component_unbind_all(dev, rdev); - // pm_runtime_disable(dev); + pm_runtime_disable(dev); rocket_device_fini(rdev); - // pm_runtime_set_suspended(dev); + pm_runtime_set_suspended(dev); drm_dev_put(ddev); @@ -200,9 +202,14 @@ static int rocket_core_bind(struct device *dev, struct device *master, void *dat unsigned int core = rdev->num_cores; int err; + platform_set_drvdata(to_platform_device(dev), rdev); + rdev->cores[core].rdev = rdev; rdev->cores[core].dev = dev; rdev->cores[core].index = core; + rdev->cores[core].link = device_link_add(dev, rdev->cores[0].dev, + DL_FLAG_STATELESS); + rdev->num_cores++; err = rocket_core_init(&rdev->cores[core]); @@ -211,6 +218,15 @@ static int rocket_core_bind(struct device *dev, struct device *master, void *dat return err; } + pm_runtime_use_autosuspend(dev); + pm_runtime_set_autosuspend_delay(dev, 50); /* ~3 frames */ + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_mark_last_busy(dev); + + printk("*** %s: %d dev %s usage_count %d links_count %d\n", __func__, 99, dev_name(dev), atomic_read(&dev->power.usage_count), dev->power.links_count); + + return 0; } @@ -220,13 +236,18 @@ static void rocket_core_unbind(struct device *dev, struct device *master, void * printk("*** %s: %d dev %p\n", __func__, 1, dev); + pm_runtime_disable(dev); + for (unsigned int core = 0; core < rdev->num_cores; core++) { if (rdev->cores[core].dev == dev) { rocket_core_fini(&rdev->cores[core]); + device_link_del(rdev->cores[core].link); break; } } + pm_runtime_set_suspended(dev); + printk("*** %s: %d\n", __func__, 99); } @@ -287,14 +308,20 @@ MODULE_DEVICE_TABLE(of, dt_match); static int rocket_device_runtime_resume(struct device *dev) { struct rocket_device *rdev = dev_get_drvdata(dev); - int core; - clk_prepare_enable(rdev->clk_npu); - clk_prepare_enable(rdev->pclk); + printk("*** %s: %d dev %s\n", __func__, 1, dev_name(dev)); - for (core = 0; core < rdev->num_cores; core++) { - clk_prepare_enable(rdev->cores[core].a_clk); - clk_prepare_enable(rdev->cores[core].h_clk); + for (unsigned int core = 0; core < rdev->num_cores; core++) { + if (rdev->cores[core].dev == dev) { + printk("*** %s: %d core %d\n", __func__, 2, core); + if (core == 0) { + clk_prepare_enable(rdev->clk_npu); + clk_prepare_enable(rdev->pclk); + } + clk_prepare_enable(rdev->cores[core].a_clk); + clk_prepare_enable(rdev->cores[core].h_clk); + break; + } } return 0; @@ -303,19 +330,26 @@ static int rocket_device_runtime_resume(struct device *dev) static int rocket_device_runtime_suspend(struct device *dev) { struct rocket_device *rdev = dev_get_drvdata(dev); - int core; - if (!rocket_job_is_idle(rdev)) - return -EBUSY; + printk("*** %s: %d dev %s\n", __func__, 1, dev_name(dev)); + WARN(1, ""); - for (core = 0; core < rdev->num_cores; core++) { - clk_disable_unprepare(rdev->cores[core].a_clk); - clk_disable_unprepare(rdev->cores[core].h_clk); + for (unsigned int core = 0; core < rdev->num_cores; core++) { + if (rdev->cores[core].dev == dev) { + printk("*** %s: %d core %d\n", __func__, 2, core); + if (!rocket_job_is_idle(&rdev->cores[core])) + return -EBUSY; + + clk_disable_unprepare(rdev->cores[core].a_clk); + clk_disable_unprepare(rdev->cores[core].h_clk); + if (core == 0) { + clk_disable_unprepare(rdev->pclk); + clk_disable_unprepare(rdev->clk_npu); + } + break; + } } - clk_disable_unprepare(rdev->pclk); - clk_disable_unprepare(rdev->clk_npu); - return 0; } @@ -329,7 +363,7 @@ static struct platform_driver rocket_driver = { .remove_new = rocket_remove, .driver = { .name = "rocket", - //.pm = pm_ptr(&rocket_pm_ops), + .pm = pm_ptr(&rocket_pm_ops), .of_match_table = dt_match, }, }; diff --git a/drivers/accel/rocket/rocket_job.c b/drivers/accel/rocket/rocket_job.c index 6671a637122f67b9fbed2a389a7d3ca03198aa39..b1157da18776c4f43f5b42ca2460ea9ce6a61b55 100644 --- a/drivers/accel/rocket/rocket_job.c +++ b/drivers/accel/rocket/rocket_job.c @@ -607,15 +607,11 @@ void rocket_job_close(struct rocket_file_priv *rocket_priv) drm_sched_entity_destroy(entity); } -int rocket_job_is_idle(struct rocket_device *rdev) +int rocket_job_is_idle(struct rocket_core *core) { - unsigned int core; - - for (core = 0; core < rdev->num_cores; core++) { - /* If there are any jobs in any HW queue, we're not idle */ - if (atomic_read(&rdev->cores[core].sched.credit_count)) - return false; - } + /* If there are any jobs in the HW queue, we're not idle */ + if (atomic_read(&core->sched.credit_count)) + return false; return true; } diff --git a/drivers/accel/rocket/rocket_job.h b/drivers/accel/rocket/rocket_job.h index 0c3c90e47d3918619edd972430ba7b65987c4115..2302d376f47619e31cc6caa142201df37c29332a 100644 --- a/drivers/accel/rocket/rocket_job.h +++ b/drivers/accel/rocket/rocket_job.h @@ -44,6 +44,6 @@ int rocket_job_init(struct rocket_core *core); void rocket_job_fini(struct rocket_core *core); int rocket_job_open(struct rocket_file_priv *rocket_priv); void rocket_job_close(struct rocket_file_priv *rocket_priv); -int rocket_job_is_idle(struct rocket_device *rdev); +int rocket_job_is_idle(struct rocket_core *core); #endif \ No newline at end of file