diff --git a/drivers/rknpu/include/rknpu_drv.h b/drivers/rknpu/include/rknpu_drv.h index 0e17b86d018e..eea0cc64fd4c 100644 --- a/drivers/rknpu/include/rknpu_drv.h +++ b/drivers/rknpu/include/rknpu_drv.h @@ -83,6 +83,10 @@ struct rknpu_device { unsigned long current_volt; int bypass_irq_handler; int bypass_soft_reset; + struct device *genpd_dev_npu0; + struct device *genpd_dev_npu1; + struct device *genpd_dev_npu2; + bool multiple_domains; }; #endif /* __LINUX_RKNPU_DRV_H_ */ diff --git a/drivers/rknpu/rknpu_drv.c b/drivers/rknpu/rknpu_drv.c index 22550ba58dff..2b826271fb1f 100644 --- a/drivers/rknpu/rknpu_drv.c +++ b/drivers/rknpu/rknpu_drv.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -364,6 +365,41 @@ static int rknpu_power_on(struct rknpu_device *rknpu_dev) return ret; } + if (rknpu_dev->multiple_domains) { + if (rknpu_dev->genpd_dev_npu0) { + ret = pm_runtime_resume_and_get( + rknpu_dev->genpd_dev_npu0); + if (ret < 0) { + LOG_DEV_ERROR( + dev, + "failed to get pm runtime for npu0, ret = %d\n", + ret); + return ret; + } + } + if (rknpu_dev->genpd_dev_npu1) { + ret = pm_runtime_resume_and_get( + rknpu_dev->genpd_dev_npu1); + if (ret < 0) { + LOG_DEV_ERROR( + dev, + "failed to get pm runtime for npu1, ret = %d\n", + ret); + return ret; + } + } + if (rknpu_dev->genpd_dev_npu2) { + ret = pm_runtime_resume_and_get( + rknpu_dev->genpd_dev_npu2); + if (ret < 0) { + LOG_DEV_ERROR( + dev, + "failed to get pm runtime for npu2, ret = %d\n", + ret); + return ret; + } + } + } ret = pm_runtime_get_sync(dev); if (ret < 0) { LOG_DEV_ERROR(dev, @@ -381,6 +417,15 @@ static int rknpu_power_off(struct rknpu_device *rknpu_dev) pm_runtime_put_sync(dev); + if (rknpu_dev->multiple_domains) { + if (rknpu_dev->genpd_dev_npu2) + pm_runtime_put_sync(rknpu_dev->genpd_dev_npu2); + if (rknpu_dev->genpd_dev_npu1) + pm_runtime_put_sync(rknpu_dev->genpd_dev_npu1); + if (rknpu_dev->genpd_dev_npu0) + pm_runtime_put_sync(rknpu_dev->genpd_dev_npu0); + } + clk_bulk_disable_unprepare(rknpu_dev->num_clks, rknpu_dev->clks); regulator_disable(rknpu_dev->vdd); @@ -638,6 +683,7 @@ static int rknpu_probe(struct platform_device *pdev) struct resource *res = NULL; struct rknpu_device *rknpu_dev = NULL; struct device *dev = &pdev->dev; + struct device *virt_dev = NULL; const struct of_device_id *match = NULL; const struct rknpu_config *config = NULL; int ret = -EINVAL; @@ -770,6 +816,20 @@ static int rknpu_probe(struct platform_device *pdev) pm_runtime_enable(dev); + if (of_count_phandle_with_args(dev->of_node, "power-domains", + "#power-domain-cells") > 1) { + virt_dev = dev_pm_domain_attach_by_name(dev, "npu0"); + if (!IS_ERR(virt_dev)) + rknpu_dev->genpd_dev_npu0 = virt_dev; + virt_dev = dev_pm_domain_attach_by_name(dev, "npu1"); + if (!IS_ERR(virt_dev)) + rknpu_dev->genpd_dev_npu1 = virt_dev; + virt_dev = dev_pm_domain_attach_by_name(dev, "npu2"); + if (!IS_ERR(virt_dev)) + rknpu_dev->genpd_dev_npu2 = virt_dev; + rknpu_dev->multiple_domains = true; + } + ret = rknpu_power_on(rknpu_dev); if (ret) goto err_free_fence_context; @@ -797,6 +857,15 @@ static int rknpu_remove(struct platform_device *pdev) rknpu_power_off(rknpu_dev); + if (rknpu_dev->multiple_domains) { + if (rknpu_dev->genpd_dev_npu0) + dev_pm_domain_detach(rknpu_dev->genpd_dev_npu0, true); + if (rknpu_dev->genpd_dev_npu1) + dev_pm_domain_detach(rknpu_dev->genpd_dev_npu1, true); + if (rknpu_dev->genpd_dev_npu2) + dev_pm_domain_detach(rknpu_dev->genpd_dev_npu2, true); + } + pm_runtime_disable(&pdev->dev); return 0;