mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
driver: rknpu: Update rknpu driver, version: 0.8.2
* Add auto power on/off support for rknpu * Add freq/volt node to unify queries and settings Signed-off-by: Felix Zeng <felix.zeng@rock-chips.com> Change-Id: Ib55f7ccb7abff51bd36194449bd6c315fcec91b2
This commit is contained in:
@@ -30,10 +30,10 @@
|
||||
|
||||
#define DRIVER_NAME "rknpu"
|
||||
#define DRIVER_DESC "RKNPU driver"
|
||||
#define DRIVER_DATE "20220803"
|
||||
#define DRIVER_DATE "20220826"
|
||||
#define DRIVER_MAJOR 0
|
||||
#define DRIVER_MINOR 8
|
||||
#define DRIVER_PATCHLEVEL 0
|
||||
#define DRIVER_PATCHLEVEL 2
|
||||
|
||||
#define LOG_TAG "RKNPU"
|
||||
|
||||
@@ -123,6 +123,7 @@ struct rknpu_device {
|
||||
struct ipa_power_model_data *model_data;
|
||||
struct thermal_cooling_device *devfreq_cooling;
|
||||
struct devfreq *devfreq;
|
||||
unsigned long ondemand_freq;
|
||||
#ifndef FPGA_PLATFORM
|
||||
#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE
|
||||
struct rockchip_opp_info opp_info;
|
||||
@@ -141,7 +142,6 @@ struct rknpu_device {
|
||||
atomic_t cmdline_power_refcount;
|
||||
struct delayed_work power_off_work;
|
||||
struct workqueue_struct *power_off_wq;
|
||||
bool is_powered;
|
||||
struct rknpu_debugger debugger;
|
||||
struct hrtimer timer;
|
||||
ktime_t kt;
|
||||
@@ -150,8 +150,10 @@ struct rknpu_device {
|
||||
uint32_t sram_size;
|
||||
void __iomem *sram_base_io;
|
||||
struct rknpu_mm *sram_mm;
|
||||
unsigned long power_put_delay;
|
||||
};
|
||||
|
||||
int rknpu_action(struct rknpu_device *rknpu_dev, struct rknpu_action *args);
|
||||
int rknpu_power_get(struct rknpu_device *rknpu_dev);
|
||||
int rknpu_power_put(struct rknpu_device *rknpu_dev);
|
||||
|
||||
#endif /* __LINUX_RKNPU_DRV_H_ */
|
||||
|
||||
@@ -9,14 +9,23 @@
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/devfreq.h>
|
||||
#include <linux/clk.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#ifndef FPGA_PLATFORM
|
||||
#include <../drivers/devfreq/governor.h>
|
||||
#endif
|
||||
|
||||
#include "rknpu_drv.h"
|
||||
#include "rknpu_mm.h"
|
||||
#include "rknpu_reset.h"
|
||||
#include "rknpu_debugger.h"
|
||||
|
||||
#define RKNPU_DEBUGGER_ROOT_NAME "rknpu"
|
||||
|
||||
#if defined(CONFIG_ROCKCHIP_RKNPU_DEBUG_FS) || \
|
||||
defined(CONFIG_ROCKCHIP_RKNPU_PROC_FS)
|
||||
static int rknpu_version_show(struct seq_file *m, void *data)
|
||||
{
|
||||
seq_printf(m, "%s: v%d.%d.%d\n", DRIVER_DESC, DRIVER_MAJOR,
|
||||
@@ -71,7 +80,7 @@ static int rknpu_power_show(struct seq_file *m, void *data)
|
||||
struct rknpu_device *rknpu_dev =
|
||||
container_of(debugger, struct rknpu_device, debugger);
|
||||
|
||||
if (rknpu_dev->is_powered)
|
||||
if (atomic_read(&rknpu_dev->power_refcount) > 0)
|
||||
seq_puts(m, "on\n");
|
||||
else
|
||||
seq_puts(m, "off\n");
|
||||
@@ -87,7 +96,6 @@ static ssize_t rknpu_power_set(struct file *file, const char __user *ubuf,
|
||||
struct rknpu_debugger *debugger = node->debugger;
|
||||
struct rknpu_device *rknpu_dev =
|
||||
container_of(debugger, struct rknpu_device, debugger);
|
||||
struct rknpu_action args;
|
||||
char buf[8];
|
||||
|
||||
if (len > sizeof(buf) - 1)
|
||||
@@ -98,21 +106,19 @@ static ssize_t rknpu_power_set(struct file *file, const char __user *ubuf,
|
||||
|
||||
if (strcmp(buf, "on") == 0) {
|
||||
atomic_inc(&rknpu_dev->cmdline_power_refcount);
|
||||
args.flags = RKNPU_POWER_ON;
|
||||
rknpu_action(rknpu_dev, &args);
|
||||
rknpu_power_get(rknpu_dev);
|
||||
LOG_INFO("rknpu power is on!");
|
||||
} else if (strcmp(buf, "off") == 0) {
|
||||
if (rknpu_dev->is_powered &&
|
||||
if (atomic_read(&rknpu_dev->power_refcount) > 0 &&
|
||||
atomic_dec_if_positive(
|
||||
&rknpu_dev->cmdline_power_refcount) >= 0) {
|
||||
atomic_sub(
|
||||
atomic_read(&rknpu_dev->cmdline_power_refcount),
|
||||
&rknpu_dev->power_refcount);
|
||||
atomic_set(&rknpu_dev->cmdline_power_refcount, 0);
|
||||
args.flags = RKNPU_POWER_OFF;
|
||||
rknpu_action(rknpu_dev, &args);
|
||||
rknpu_power_put(rknpu_dev);
|
||||
}
|
||||
if (!rknpu_dev->is_powered)
|
||||
if (atomic_read(&rknpu_dev->power_refcount) <= 0)
|
||||
LOG_INFO("rknpu power is off!");
|
||||
} else {
|
||||
LOG_ERROR("rknpu power node params is invalid!");
|
||||
@@ -121,6 +127,128 @@ static ssize_t rknpu_power_set(struct file *file, const char __user *ubuf,
|
||||
return len;
|
||||
}
|
||||
|
||||
static int rknpu_power_put_delay_show(struct seq_file *m, void *data)
|
||||
{
|
||||
struct rknpu_debugger_node *node = m->private;
|
||||
struct rknpu_debugger *debugger = node->debugger;
|
||||
struct rknpu_device *rknpu_dev =
|
||||
container_of(debugger, struct rknpu_device, debugger);
|
||||
|
||||
seq_printf(m, "%lu\n", rknpu_dev->power_put_delay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t rknpu_power_put_delay_set(struct file *file,
|
||||
const char __user *ubuf, size_t len,
|
||||
loff_t *offp)
|
||||
{
|
||||
struct seq_file *priv = file->private_data;
|
||||
struct rknpu_debugger_node *node = priv->private;
|
||||
struct rknpu_debugger *debugger = node->debugger;
|
||||
struct rknpu_device *rknpu_dev =
|
||||
container_of(debugger, struct rknpu_device, debugger);
|
||||
char buf[16];
|
||||
unsigned long power_put_delay = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (len > sizeof(buf) - 1)
|
||||
return -EINVAL;
|
||||
if (copy_from_user(buf, ubuf, len))
|
||||
return -EFAULT;
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
ret = kstrtoul(buf, 10, &power_put_delay);
|
||||
if (ret) {
|
||||
LOG_ERROR("failed to parse power put delay string: %s\n", buf);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
rknpu_dev->power_put_delay = power_put_delay;
|
||||
|
||||
LOG_INFO("set rknpu power put delay time %lums\n",
|
||||
rknpu_dev->power_put_delay);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int rknpu_freq_show(struct seq_file *m, void *data)
|
||||
{
|
||||
struct rknpu_debugger_node *node = m->private;
|
||||
struct rknpu_debugger *debugger = node->debugger;
|
||||
struct rknpu_device *rknpu_dev =
|
||||
container_of(debugger, struct rknpu_device, debugger);
|
||||
unsigned long current_freq = 0;
|
||||
|
||||
rknpu_power_get(rknpu_dev);
|
||||
|
||||
current_freq = clk_get_rate(rknpu_dev->clks[0].clk);
|
||||
|
||||
rknpu_power_put(rknpu_dev);
|
||||
|
||||
seq_printf(m, "%lu\n", current_freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t rknpu_freq_set(struct file *file, const char __user *ubuf,
|
||||
size_t len, loff_t *offp)
|
||||
{
|
||||
struct seq_file *priv = file->private_data;
|
||||
struct rknpu_debugger_node *node = priv->private;
|
||||
struct rknpu_debugger *debugger = node->debugger;
|
||||
struct rknpu_device *rknpu_dev =
|
||||
container_of(debugger, struct rknpu_device, debugger);
|
||||
unsigned long current_freq = 0;
|
||||
char buf[16];
|
||||
unsigned long freq = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (len > sizeof(buf) - 1)
|
||||
return -EINVAL;
|
||||
if (copy_from_user(buf, ubuf, len))
|
||||
return -EFAULT;
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
ret = kstrtoul(buf, 10, &freq);
|
||||
if (ret) {
|
||||
LOG_ERROR("failed to parse freq string: %s\n", buf);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!rknpu_dev->devfreq)
|
||||
return -EFAULT;
|
||||
|
||||
rknpu_power_get(rknpu_dev);
|
||||
|
||||
current_freq = clk_get_rate(rknpu_dev->clks[0].clk);
|
||||
if (freq != current_freq) {
|
||||
rknpu_dev->ondemand_freq = freq;
|
||||
mutex_lock(&rknpu_dev->devfreq->lock);
|
||||
update_devfreq(rknpu_dev->devfreq);
|
||||
mutex_unlock(&rknpu_dev->devfreq->lock);
|
||||
}
|
||||
|
||||
rknpu_power_put(rknpu_dev);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int rknpu_volt_show(struct seq_file *m, void *data)
|
||||
{
|
||||
struct rknpu_debugger_node *node = m->private;
|
||||
struct rknpu_debugger *debugger = node->debugger;
|
||||
struct rknpu_device *rknpu_dev =
|
||||
container_of(debugger, struct rknpu_device, debugger);
|
||||
unsigned long current_volt = 0;
|
||||
|
||||
current_volt = regulator_get_voltage(rknpu_dev->vdd);
|
||||
|
||||
seq_printf(m, "%lu\n", current_volt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rknpu_reset_show(struct seq_file *m, void *data)
|
||||
{
|
||||
struct rknpu_debugger_node *node = m->private;
|
||||
@@ -152,7 +280,8 @@ static ssize_t rknpu_reset_set(struct file *file, const char __user *ubuf,
|
||||
return -EFAULT;
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
if (strcmp(buf, "1") == 0 && rknpu_dev->is_powered)
|
||||
if (strcmp(buf, "1") == 0 &&
|
||||
atomic_read(&rknpu_dev->power_refcount) > 0)
|
||||
rknpu_soft_reset(rknpu_dev);
|
||||
else if (strcmp(buf, "on") == 0)
|
||||
rknpu_dev->bypass_soft_reset = 0;
|
||||
@@ -166,6 +295,10 @@ static struct rknpu_debugger_list rknpu_debugger_root_list[] = {
|
||||
{ "version", rknpu_version_show, NULL, NULL },
|
||||
{ "load", rknpu_load_show, NULL, NULL },
|
||||
{ "power", rknpu_power_show, rknpu_power_set, NULL },
|
||||
{ "freq", rknpu_freq_show, rknpu_freq_set, NULL },
|
||||
{ "volt", rknpu_volt_show, NULL, NULL },
|
||||
{ "delayms", rknpu_power_put_delay_show, rknpu_power_put_delay_set,
|
||||
NULL },
|
||||
{ "reset", rknpu_reset_show, rknpu_reset_set, NULL },
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_SRAM
|
||||
{ "mm", rknpu_mm_dump, NULL, NULL },
|
||||
@@ -199,6 +332,7 @@ static const struct file_operations rknpu_debugfs_fops = {
|
||||
.release = single_release,
|
||||
.write = rknpu_debugger_write,
|
||||
};
|
||||
#endif /* #if defined(CONFIG_ROCKCHIP_RKNPU_DEBUG_FS) || defined(CONFIG_ROCKCHIP_RKNPU_PROC_FS) */
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DEBUG_FS
|
||||
static int rknpu_debugfs_remove_files(struct rknpu_debugger *debugger)
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <soc/rockchip/rockchip_opp_select.h>
|
||||
#include <soc/rockchip/rockchip_system_monitor.h>
|
||||
#include <soc/rockchip/rockchip_ipa.h>
|
||||
#include <../drivers/devfreq/governor.h>
|
||||
#endif
|
||||
|
||||
#include "rknpu_ioctl.h"
|
||||
@@ -186,46 +187,54 @@ static void rknpu_power_off_delay_work(struct work_struct *power_off_work)
|
||||
container_of(to_delayed_work(power_off_work),
|
||||
struct rknpu_device, power_off_work);
|
||||
mutex_lock(&rknpu_dev->power_lock);
|
||||
if (atomic_read(&rknpu_dev->power_refcount) == 0 &&
|
||||
rknpu_dev->is_powered) {
|
||||
rknpu_dev->is_powered = false;
|
||||
if (atomic_dec_if_positive(&rknpu_dev->power_refcount) == 0)
|
||||
rknpu_power_off(rknpu_dev);
|
||||
}
|
||||
mutex_unlock(&rknpu_dev->power_lock);
|
||||
}
|
||||
|
||||
int rknpu_action(struct rknpu_device *rknpu_dev, struct rknpu_action *args)
|
||||
int rknpu_power_get(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
cancel_delayed_work(&rknpu_dev->power_off_work);
|
||||
mutex_lock(&rknpu_dev->power_lock);
|
||||
if (atomic_inc_return(&rknpu_dev->power_refcount) == 1)
|
||||
ret = rknpu_power_on(rknpu_dev);
|
||||
mutex_unlock(&rknpu_dev->power_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rknpu_power_put(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&rknpu_dev->power_lock);
|
||||
if (atomic_dec_if_positive(&rknpu_dev->power_refcount) == 0)
|
||||
ret = rknpu_power_off(rknpu_dev);
|
||||
mutex_unlock(&rknpu_dev->power_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rknpu_power_put_delay(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
mutex_lock(&rknpu_dev->power_lock);
|
||||
if (atomic_read(&rknpu_dev->power_refcount) == 1)
|
||||
queue_delayed_work(
|
||||
rknpu_dev->power_off_wq, &rknpu_dev->power_off_work,
|
||||
msecs_to_jiffies(rknpu_dev->power_put_delay));
|
||||
else
|
||||
atomic_dec_if_positive(&rknpu_dev->power_refcount);
|
||||
mutex_unlock(&rknpu_dev->power_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rknpu_action(struct rknpu_device *rknpu_dev,
|
||||
struct rknpu_action *args)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
switch (args->flags) {
|
||||
case RKNPU_POWER_ON:
|
||||
atomic_inc(&rknpu_dev->power_refcount);
|
||||
mutex_lock(&rknpu_dev->power_lock);
|
||||
if (!rknpu_dev->is_powered) {
|
||||
rknpu_dev->is_powered = true;
|
||||
ret = rknpu_power_on(rknpu_dev);
|
||||
}
|
||||
mutex_unlock(&rknpu_dev->power_lock);
|
||||
break;
|
||||
case RKNPU_POWER_OFF:
|
||||
if (rknpu_dev->is_powered &&
|
||||
atomic_dec_if_positive(&rknpu_dev->power_refcount) == 0)
|
||||
queue_delayed_work(rknpu_dev->power_off_wq,
|
||||
&rknpu_dev->power_off_work,
|
||||
msecs_to_jiffies(1000));
|
||||
break;
|
||||
default:
|
||||
/* default open rknpu power to compatible with librknnrt.so version before 1.2.0 */
|
||||
mutex_lock(&rknpu_dev->power_lock);
|
||||
if (!rknpu_dev->is_powered) {
|
||||
atomic_inc(&rknpu_dev->power_refcount);
|
||||
rknpu_dev->is_powered = true;
|
||||
ret = rknpu_power_on(rknpu_dev);
|
||||
}
|
||||
mutex_unlock(&rknpu_dev->power_lock);
|
||||
}
|
||||
|
||||
switch (args->flags) {
|
||||
case RKNPU_GET_HW_VERSION:
|
||||
ret = rknpu_get_hw_version(rknpu_dev, &args->value);
|
||||
@@ -234,13 +243,13 @@ int rknpu_action(struct rknpu_device *rknpu_dev, struct rknpu_action *args)
|
||||
ret = rknpu_get_drv_version(&args->value);
|
||||
break;
|
||||
case RKNPU_GET_FREQ:
|
||||
args->value = rknpu_dev->current_freq;
|
||||
args->value = clk_get_rate(rknpu_dev->clks[0].clk);
|
||||
ret = 0;
|
||||
break;
|
||||
case RKNPU_SET_FREQ:
|
||||
break;
|
||||
case RKNPU_GET_VOLT:
|
||||
args->value = rknpu_dev->current_volt;
|
||||
args->value = regulator_get_voltage(rknpu_dev->vdd);
|
||||
ret = 0;
|
||||
break;
|
||||
case RKNPU_SET_VOLT:
|
||||
@@ -354,9 +363,12 @@ static int rknpu_action_ioctl(struct rknpu_device *rknpu_dev,
|
||||
|
||||
static long rknpu_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
|
||||
{
|
||||
long ret = 0;
|
||||
long ret = -EINVAL;
|
||||
struct rknpu_device *rknpu_dev =
|
||||
container_of(file->private_data, struct rknpu_device, miscdev);
|
||||
|
||||
rknpu_power_get(rknpu_dev);
|
||||
|
||||
switch (cmd) {
|
||||
case IOCTL_RKNPU_ACTION:
|
||||
ret = rknpu_action_ioctl(rknpu_dev, arg);
|
||||
@@ -378,6 +390,9 @@ static long rknpu_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
rknpu_power_put_delay(rknpu_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
const struct file_operations rknpu_fops = {
|
||||
@@ -399,17 +414,42 @@ static const struct vm_operations_struct rknpu_gem_vm_ops = {
|
||||
};
|
||||
|
||||
static int rknpu_action_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev->dev);
|
||||
|
||||
return rknpu_action(rknpu_dev, (struct rknpu_action *)data);
|
||||
}
|
||||
|
||||
#define RKNPU_IOCTL(func) \
|
||||
static int __##func(struct drm_device *dev, void *data, \
|
||||
struct drm_file *file_priv) \
|
||||
{ \
|
||||
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev->dev); \
|
||||
int ret = -EINVAL; \
|
||||
rknpu_power_get(rknpu_dev); \
|
||||
ret = func(dev, data, file_priv); \
|
||||
rknpu_power_put_delay(rknpu_dev); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
RKNPU_IOCTL(rknpu_action_ioctl);
|
||||
RKNPU_IOCTL(rknpu_submit_ioctl);
|
||||
RKNPU_IOCTL(rknpu_gem_create_ioctl);
|
||||
RKNPU_IOCTL(rknpu_gem_map_ioctl);
|
||||
RKNPU_IOCTL(rknpu_gem_destroy_ioctl);
|
||||
RKNPU_IOCTL(rknpu_gem_sync_ioctl);
|
||||
|
||||
static const struct drm_ioctl_desc rknpu_ioctls[] = {
|
||||
DRM_IOCTL_DEF_DRV(RKNPU_ACTION, rknpu_action_ioctl, DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(RKNPU_SUBMIT, rknpu_submit_ioctl, DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(RKNPU_MEM_CREATE, rknpu_gem_create_ioctl,
|
||||
DRM_IOCTL_DEF_DRV(RKNPU_ACTION, __rknpu_action_ioctl, DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(RKNPU_SUBMIT, __rknpu_submit_ioctl, DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(RKNPU_MEM_CREATE, __rknpu_gem_create_ioctl,
|
||||
DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(RKNPU_MEM_MAP, rknpu_gem_map_ioctl, DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(RKNPU_MEM_DESTROY, rknpu_gem_destroy_ioctl,
|
||||
DRM_IOCTL_DEF_DRV(RKNPU_MEM_MAP, __rknpu_gem_map_ioctl,
|
||||
DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(RKNPU_MEM_SYNC, rknpu_gem_sync_ioctl,
|
||||
DRM_IOCTL_DEF_DRV(RKNPU_MEM_DESTROY, __rknpu_gem_destroy_ioctl,
|
||||
DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(RKNPU_MEM_SYNC, __rknpu_gem_sync_ioctl,
|
||||
DRM_RENDER_ALLOW),
|
||||
};
|
||||
|
||||
@@ -466,14 +506,6 @@ static struct drm_driver rknpu_drm_driver = {
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
};
|
||||
|
||||
static int rknpu_action_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev->dev);
|
||||
|
||||
return rknpu_action(rknpu_dev, (struct rknpu_action *)data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer)
|
||||
@@ -915,6 +947,8 @@ static int npu_devfreq_target(struct device *dev, unsigned long *freq,
|
||||
rknpu_dev->devfreq->last_status.current_frequency =
|
||||
*freq;
|
||||
rknpu_dev->current_volt = opp_volt;
|
||||
LOG_DEV_INFO(dev, "set rknpu freq: %lu, volt: %lu\n",
|
||||
rknpu_dev->current_freq, rknpu_dev->current_volt);
|
||||
}
|
||||
#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE
|
||||
rockchip_monitor_volt_adjust_unlock(rknpu_dev->mdev_info);
|
||||
@@ -999,6 +1033,9 @@ static int npu_devfreq_target(struct device *dev, unsigned long *target_freq,
|
||||
}
|
||||
rknpu_dev->current_volt = volt;
|
||||
|
||||
LOG_DEV_INFO(dev, "set rknpu freq: %lu, volt: %lu\n",
|
||||
rknpu_dev->current_freq, rknpu_dev->current_volt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
@@ -1025,6 +1062,30 @@ static struct devfreq_dev_profile npu_devfreq_profile = {
|
||||
.get_cur_freq = npu_devfreq_get_cur_freq,
|
||||
};
|
||||
|
||||
static int devfreq_rknpu_ondemand_func(struct devfreq *df, unsigned long *freq)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = df->data;
|
||||
|
||||
if (rknpu_dev)
|
||||
*freq = rknpu_dev->ondemand_freq;
|
||||
else
|
||||
*freq = df->previous_freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int devfreq_rknpu_ondemand_handler(struct devfreq *devfreq,
|
||||
unsigned int event, void *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct devfreq_governor devfreq_rknpu_ondemand = {
|
||||
.name = "rknpu_ondemand",
|
||||
.get_target_freq = devfreq_rknpu_ondemand_func,
|
||||
.event_handler = devfreq_rknpu_ondemand_handler,
|
||||
};
|
||||
|
||||
static unsigned long npu_get_static_power(struct devfreq *devfreq,
|
||||
unsigned long voltage)
|
||||
{
|
||||
@@ -1130,11 +1191,18 @@ static int rknpu_devfreq_init(struct rknpu_device *rknpu_dev)
|
||||
dev_pm_opp_put(opp);
|
||||
dp->initial_freq = rknpu_dev->current_freq;
|
||||
|
||||
rknpu_dev->devfreq =
|
||||
devm_devfreq_add_device(dev, dp, "userspace", NULL);
|
||||
ret = devfreq_add_governor(&devfreq_rknpu_ondemand);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(dev, "failed to add rknpu_ondemand governor\n");
|
||||
goto err_remove_table;
|
||||
}
|
||||
|
||||
rknpu_dev->devfreq = devm_devfreq_add_device(dev, dp, "rknpu_ondemand",
|
||||
(void *)rknpu_dev);
|
||||
if (IS_ERR(rknpu_dev->devfreq)) {
|
||||
LOG_DEV_ERROR(dev, "failed to add devfreq\n");
|
||||
return PTR_ERR(rknpu_dev->devfreq);
|
||||
ret = PTR_ERR(rknpu_dev->devfreq);
|
||||
goto err_remove_governor;
|
||||
}
|
||||
devm_devfreq_register_opp_notifier(dev, rknpu_dev->devfreq);
|
||||
|
||||
@@ -1177,6 +1245,15 @@ static int rknpu_devfreq_init(struct rknpu_device *rknpu_dev)
|
||||
|
||||
out:
|
||||
return 0;
|
||||
|
||||
err_remove_governor:
|
||||
devfreq_remove_governor(&devfreq_rknpu_ondemand);
|
||||
err_remove_table:
|
||||
dev_pm_opp_of_remove_table(dev);
|
||||
|
||||
rknpu_dev->devfreq = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -1249,11 +1326,18 @@ static int rknpu_devfreq_init(struct rknpu_device *rknpu_dev)
|
||||
}
|
||||
dp->initial_freq = rknpu_dev->current_freq;
|
||||
|
||||
rknpu_dev->devfreq =
|
||||
devm_devfreq_add_device(dev, dp, "userspace", NULL);
|
||||
ret = devfreq_add_governor(&devfreq_rknpu_ondemand);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(dev, "failed to add rknpu_ondemand governor\n");
|
||||
goto err_remove_table;
|
||||
}
|
||||
|
||||
rknpu_dev->devfreq = devm_devfreq_add_device(dev, dp, "rknpu_ondemand",
|
||||
(void *)rknpu_dev);
|
||||
if (IS_ERR(rknpu_dev->devfreq)) {
|
||||
LOG_DEV_ERROR(dev, "failed to add devfreq\n");
|
||||
return PTR_ERR(rknpu_dev->devfreq);
|
||||
ret = PTR_ERR(rknpu_dev->devfreq);
|
||||
goto err_remove_governor;
|
||||
}
|
||||
devm_devfreq_register_opp_notifier(dev, rknpu_dev->devfreq);
|
||||
|
||||
@@ -1295,8 +1379,30 @@ static int rknpu_devfreq_init(struct rknpu_device *rknpu_dev)
|
||||
|
||||
out:
|
||||
return 0;
|
||||
|
||||
err_remove_governor:
|
||||
devfreq_remove_governor(&devfreq_rknpu_ondemand);
|
||||
err_remove_table:
|
||||
dev_pm_opp_of_remove_table(dev);
|
||||
|
||||
rknpu_dev->devfreq = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rknpu_devfreq_remove(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
if (rknpu_dev->devfreq) {
|
||||
devfreq_unregister_opp_notifier(rknpu_dev->dev,
|
||||
rknpu_dev->devfreq);
|
||||
dev_pm_opp_of_remove_table(rknpu_dev->dev);
|
||||
devfreq_remove_governor(&devfreq_rknpu_ondemand);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int rknpu_register_irq(struct platform_device *pdev,
|
||||
@@ -1573,12 +1679,7 @@ static int rknpu_probe(struct platform_device *pdev)
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(dev,
|
||||
"failed to allocate fence context for rknpu\n");
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM
|
||||
goto err_remove_drm;
|
||||
#endif
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP
|
||||
goto err_remove_misc;
|
||||
#endif
|
||||
goto err_remove_drv;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1601,25 +1702,23 @@ static int rknpu_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
ret = rknpu_power_on(rknpu_dev);
|
||||
if (ret) {
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM
|
||||
goto err_remove_drm;
|
||||
#endif
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP
|
||||
goto err_remove_misc;
|
||||
#endif
|
||||
}
|
||||
if (ret)
|
||||
goto err_remove_drv;
|
||||
|
||||
#ifndef FPGA_PLATFORM
|
||||
rknpu_devfreq_init(rknpu_dev);
|
||||
ret = rknpu_devfreq_init(rknpu_dev);
|
||||
if (ret)
|
||||
goto err_remove_drv;
|
||||
#endif
|
||||
|
||||
// set default power put delay to 3s
|
||||
rknpu_dev->power_put_delay = 3000;
|
||||
rknpu_dev->power_off_wq =
|
||||
create_freezable_workqueue("rknpu_power_off_wq");
|
||||
if (!rknpu_dev->power_off_wq) {
|
||||
LOG_DEV_ERROR(dev, "rknpu couldn't create power_off workqueue");
|
||||
ret = -ENOMEM;
|
||||
goto err_remove_wq;
|
||||
goto err_devfreq_remove;
|
||||
}
|
||||
INIT_DEFERRABLE_WORK(&rknpu_dev->power_off_work,
|
||||
rknpu_power_off_delay_work);
|
||||
@@ -1636,7 +1735,6 @@ static int rknpu_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
rknpu_power_off(rknpu_dev);
|
||||
rknpu_dev->is_powered = false;
|
||||
atomic_set(&rknpu_dev->power_refcount, 0);
|
||||
atomic_set(&rknpu_dev->cmdline_power_refcount, 0);
|
||||
|
||||
@@ -1645,16 +1743,22 @@ static int rknpu_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_wq:
|
||||
destroy_workqueue(rknpu_dev->power_off_wq);
|
||||
|
||||
err_devfreq_remove:
|
||||
#ifndef FPGA_PLATFORM
|
||||
rknpu_devfreq_remove(rknpu_dev);
|
||||
#endif
|
||||
|
||||
err_remove_drv:
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM
|
||||
err_remove_drm:
|
||||
rknpu_drm_remove(rknpu_dev);
|
||||
#endif
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP
|
||||
err_remove_misc:
|
||||
misc_deregister(&(rknpu_dev->miscdev));
|
||||
#endif
|
||||
err_remove_wq:
|
||||
destroy_workqueue(rknpu_dev->power_off_wq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1683,8 +1787,15 @@ static int rknpu_remove(struct platform_device *pdev)
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP
|
||||
misc_deregister(&(rknpu_dev->miscdev));
|
||||
#endif
|
||||
if (rknpu_dev->is_powered)
|
||||
|
||||
#ifndef FPGA_PLATFORM
|
||||
rknpu_devfreq_remove(rknpu_dev);
|
||||
#endif
|
||||
|
||||
mutex_lock(&rknpu_dev->power_lock);
|
||||
if (atomic_read(&rknpu_dev->power_refcount) > 0)
|
||||
rknpu_power_off(rknpu_dev);
|
||||
mutex_unlock(&rknpu_dev->power_lock);
|
||||
|
||||
if (rknpu_dev->multiple_domains) {
|
||||
if (rknpu_dev->genpd_dev_npu0)
|
||||
|
||||
Reference in New Issue
Block a user