driver: rknpu: Add pm ops for npu

The configuration of pvtpll and memory read margin will lose if npu pd
power down, and if the source clock of npu comes from pvtpll it will
fail to power up npu pd. so change the source clock to normal pll before
power down, and restore source clock and read margin after power up.

Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
Change-Id: I4a558c51ad061fb99cad384f462065f96ac2f658
This commit is contained in:
Finley Xiao
2021-12-25 18:33:07 +08:00
committed by Tao Huang
parent 5226534d73
commit 301c7f8724
2 changed files with 58 additions and 0 deletions

View File

@@ -105,6 +105,7 @@ struct rknpu_device {
struct device *genpd_dev_npu0;
struct device *genpd_dev_npu1;
struct device *genpd_dev_npu2;
struct clk *scmi_clk;
bool multiple_domains;
};

View File

@@ -27,6 +27,7 @@
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/devfreq_cooling.h>
@@ -49,6 +50,8 @@
#include "rknpu_fence.h"
#include "rknpu_drv.h"
#define POWER_DOWN_FREQ 200000000
static int bypass_irq_handler;
module_param(bypass_irq_handler, int, 0644);
MODULE_PARM_DESC(bypass_irq_handler,
@@ -610,6 +613,7 @@ static int npu_devfreq_target(struct device *dev, unsigned long *freq,
{
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev);
struct dev_pm_opp *opp;
unsigned long opp_volt;
int ret = 0;
if (!npu_mdevp.is_checked)
@@ -618,6 +622,7 @@ static int npu_devfreq_target(struct device *dev, unsigned long *freq,
opp = devfreq_recommended_opp(dev, freq, flags);
if (IS_ERR(opp))
return PTR_ERR(opp);
opp_volt = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
rockchip_monitor_volt_adjust_lock(rknpu_dev->mdev_info);
@@ -627,6 +632,7 @@ static int npu_devfreq_target(struct device *dev, unsigned long *freq,
if (rknpu_dev->devfreq)
rknpu_dev->devfreq->last_status.current_frequency =
*freq;
rknpu_dev->current_volt = opp_volt;
}
rockchip_monitor_volt_adjust_unlock(rknpu_dev->mdev_info);
@@ -790,6 +796,7 @@ static int rknpu_devfreq_init(struct rknpu_device *rknpu_dev)
rknpu_dev->mdev_info = NULL;
npu_mdevp.is_checked = true;
}
rknpu_dev->current_volt = regulator_get_voltage(rknpu_dev->vdd);
of_property_read_u32(dev->of_node, "dynamic-power-coefficient",
(u32 *)&npu_cooling_power.dyn_power_coeff);
@@ -918,6 +925,8 @@ static int rknpu_probe(struct platform_device *pdev)
rknpu_reset_get(rknpu_dev);
rknpu_dev->num_clks = devm_clk_bulk_get_all(dev, &rknpu_dev->clks);
if (strstr(__clk_get_name(rknpu_dev->clks[0].clk), "scmi"))
rknpu_dev->scmi_clk = rknpu_dev->clks[0].clk;
#ifndef FPGA_PLATFORM
rknpu_dev->vdd = devm_regulator_get_optional(dev, "rknpu");
@@ -1064,12 +1073,60 @@ static int rknpu_remove(struct platform_device *pdev)
return 0;
}
static int rknpu_runtime_suspend(struct device *dev)
{
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev);
if (rknpu_dev->scmi_clk) {
if (clk_set_rate(rknpu_dev->scmi_clk, POWER_DOWN_FREQ))
LOG_DEV_ERROR(dev, "failed to restore clk rate\n");
}
return 0;
}
static int rknpu_runtime_resume(struct device *dev)
{
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev);
struct rockchip_opp_info *opp_info = &rknpu_dev->opp_info;
int ret = 0;
if (!rknpu_dev->current_freq || !rknpu_dev->current_volt)
return 0;
ret = clk_bulk_prepare_enable(opp_info->num_clks, opp_info->clks);
if (ret) {
LOG_DEV_ERROR(dev, "failed to enable opp clks\n");
return ret;
}
if (rknpu_dev->scmi_clk) {
if (clk_set_rate(rknpu_dev->scmi_clk, rknpu_dev->current_freq))
LOG_DEV_ERROR(dev, "failed to set power down rate\n");
}
if (opp_info->data->set_read_margin)
opp_info->data->set_read_margin(dev, opp_info,
rknpu_dev->current_volt);
clk_bulk_disable_unprepare(opp_info->num_clks, opp_info->clks);
return ret;
}
static const struct dev_pm_ops rknpu_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(rknpu_runtime_suspend, rknpu_runtime_resume, NULL)
};
static struct platform_driver rknpu_driver = {
.probe = rknpu_probe,
.remove = rknpu_remove,
.driver = {
.owner = THIS_MODULE,
.name = "RKNPU",
.pm = &rknpu_pm_ops,
.of_match_table = of_match_ptr(rknpu_of_match),
},
};