mirror of
https://github.com/DrHo1y/ezrknn-llm.git
synced 2026-10-01 23:58:50 +07:00
Uncompressed rknpu-driver
This commit is contained in:
60
rknpu-driver/driver-0.9.6/Kconfig
Normal file
60
rknpu-driver/driver-0.9.6/Kconfig
Normal file
@@ -0,0 +1,60 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
menu "RKNPU"
|
||||
depends on ARCH_ROCKCHIP
|
||||
|
||||
config ROCKCHIP_RKNPU
|
||||
tristate "ROCKCHIP_RKNPU"
|
||||
depends on DRM || DMABUF_HEAPS_ROCKCHIP_CMA_HEAP
|
||||
help
|
||||
rknpu module.
|
||||
|
||||
if ROCKCHIP_RKNPU
|
||||
|
||||
config ROCKCHIP_RKNPU_DEBUG_FS
|
||||
bool "RKNPU debugfs"
|
||||
depends on DEBUG_FS
|
||||
default y
|
||||
help
|
||||
Enable debugfs to debug RKNPU usage.
|
||||
|
||||
config ROCKCHIP_RKNPU_PROC_FS
|
||||
bool "RKNPU procfs"
|
||||
depends on PROC_FS
|
||||
help
|
||||
Enable procfs to debug RKNPU usage.
|
||||
|
||||
config ROCKCHIP_RKNPU_FENCE
|
||||
bool "RKNPU fence"
|
||||
depends on SYNC_FILE
|
||||
help
|
||||
Enable fence support for RKNPU.
|
||||
|
||||
config ROCKCHIP_RKNPU_SRAM
|
||||
bool "RKNPU SRAM"
|
||||
depends on NO_GKI
|
||||
help
|
||||
Enable RKNPU SRAM support
|
||||
|
||||
choice
|
||||
prompt "RKNPU memory manager"
|
||||
default ROCKCHIP_RKNPU_DRM_GEM
|
||||
help
|
||||
Select RKNPU memory manager
|
||||
|
||||
config ROCKCHIP_RKNPU_DRM_GEM
|
||||
bool "RKNPU DRM GEM"
|
||||
depends on DRM
|
||||
help
|
||||
Enable RKNPU memory manager by DRM GEM.
|
||||
|
||||
config ROCKCHIP_RKNPU_DMA_HEAP
|
||||
bool "RKNPU DMA heap"
|
||||
depends on DMABUF_HEAPS_ROCKCHIP_CMA_HEAP
|
||||
help
|
||||
Enable RKNPU memory manager by DMA Heap.
|
||||
|
||||
endchoice
|
||||
|
||||
endif
|
||||
|
||||
endmenu
|
||||
17
rknpu-driver/driver-0.9.6/Makefile
Normal file
17
rknpu-driver/driver-0.9.6/Makefile
Normal file
@@ -0,0 +1,17 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_ROCKCHIP_RKNPU) += rknpu.o
|
||||
|
||||
ccflags-y += -I$(srctree)/$(src)/include
|
||||
ccflags-y += -I$(src)/include
|
||||
ccflags-y += -Werror
|
||||
|
||||
rknpu-y += rknpu_drv.o
|
||||
rknpu-y += rknpu_reset.o
|
||||
rknpu-y += rknpu_job.o
|
||||
rknpu-y += rknpu_debugger.o
|
||||
rknpu-y += rknpu_iommu.o
|
||||
rknpu-$(CONFIG_PM_DEVFREQ) += rknpu_devfreq.o
|
||||
rknpu-$(CONFIG_ROCKCHIP_RKNPU_SRAM) += rknpu_mm.o
|
||||
rknpu-$(CONFIG_ROCKCHIP_RKNPU_FENCE) += rknpu_fence.o
|
||||
rknpu-$(CONFIG_ROCKCHIP_RKNPU_DRM_GEM) += rknpu_gem.o
|
||||
rknpu-$(CONFIG_ROCKCHIP_RKNPU_DMA_HEAP) += rknpu_mem.o
|
||||
88
rknpu-driver/driver-0.9.6/include/rknpu_debugger.h
Normal file
88
rknpu-driver/driver-0.9.6/include/rknpu_debugger.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RKNPU_DEBUGGER_H_
|
||||
#define __LINUX_RKNPU_DEBUGGER_H_
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
/*
|
||||
* struct rknpu_debugger - rknpu debugger information
|
||||
*
|
||||
* This structure represents a debugger to be created by the rknpu driver
|
||||
* or core.
|
||||
*/
|
||||
struct rknpu_debugger {
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DEBUG_FS
|
||||
/* Directory of debugfs file */
|
||||
struct dentry *debugfs_dir;
|
||||
struct list_head debugfs_entry_list;
|
||||
struct mutex debugfs_lock;
|
||||
#endif
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_PROC_FS
|
||||
/* Directory of procfs file */
|
||||
struct proc_dir_entry *procfs_dir;
|
||||
struct list_head procfs_entry_list;
|
||||
struct mutex procfs_lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* struct rknpu_debugger_list - debugfs/procfs info list entry
|
||||
*
|
||||
* This structure represents a debugfs/procfs file to be created by the npu
|
||||
* driver or core.
|
||||
*/
|
||||
struct rknpu_debugger_list {
|
||||
/* File name */
|
||||
const char *name;
|
||||
/*
|
||||
* Show callback. &seq_file->private will be set to the &struct
|
||||
* rknpu_debugger_node corresponding to the instance of this info
|
||||
* on a given &struct rknpu_debugger.
|
||||
*/
|
||||
int (*show)(struct seq_file *seq, void *data);
|
||||
/*
|
||||
* Write callback. &seq_file->private will be set to the &struct
|
||||
* rknpu_debugger_node corresponding to the instance of this info
|
||||
* on a given &struct rknpu_debugger.
|
||||
*/
|
||||
ssize_t (*write)(struct file *file, const char __user *ubuf, size_t len,
|
||||
loff_t *offp);
|
||||
/* Procfs/Debugfs private data. */
|
||||
void *data;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct rknpu_debugger_node - Nodes for debugfs/procfs
|
||||
*
|
||||
* This structure represents each instance of procfs/debugfs created from the
|
||||
* template.
|
||||
*/
|
||||
struct rknpu_debugger_node {
|
||||
struct rknpu_debugger *debugger;
|
||||
|
||||
/* template for this node. */
|
||||
const struct rknpu_debugger_list *info_ent;
|
||||
|
||||
/* Each Procfs/Debugfs file. */
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DEBUG_FS
|
||||
struct dentry *dent;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_PROC_FS
|
||||
struct proc_dir_entry *pent;
|
||||
#endif
|
||||
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct rknpu_device;
|
||||
|
||||
int rknpu_debugger_init(struct rknpu_device *rknpu_dev);
|
||||
int rknpu_debugger_remove(struct rknpu_device *rknpu_dev);
|
||||
|
||||
#endif /* __LINUX_RKNPU_FENCE_H_ */
|
||||
46
rknpu-driver/driver-0.9.6/include/rknpu_devfreq.h
Normal file
46
rknpu-driver/driver-0.9.6/include/rknpu_devfreq.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Finley Xiao <finley.xiao@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RKNPU_DEVFREQ_H
|
||||
#define __LINUX_RKNPU_DEVFREQ_H
|
||||
|
||||
#ifdef CONFIG_PM_DEVFREQ
|
||||
void rknpu_devfreq_lock(struct rknpu_device *rknpu_dev);
|
||||
void rknpu_devfreq_unlock(struct rknpu_device *rknpu_dev);
|
||||
int rknpu_devfreq_init(struct rknpu_device *rknpu_dev);
|
||||
void rknpu_devfreq_remove(struct rknpu_device *rknpu_dev);
|
||||
int rknpu_devfreq_runtime_suspend(struct device *dev);
|
||||
int rknpu_devfreq_runtime_resume(struct device *dev);
|
||||
#else
|
||||
static inline int rknpu_devfreq_init(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void rknpu_devfreq_remove(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rknpu_devfreq_lock(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rknpu_devfreq_unlock(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int rknpu_devfreq_runtime_suspend(struct device *dev)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int rknpu_devfreq_runtime_resume(struct device *dev)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif /* CONFIG_PM_DEVFREQ */
|
||||
|
||||
#endif /* __LINUX_RKNPU_DEVFREQ_H_ */
|
||||
183
rknpu-driver/driver-0.9.6/include/rknpu_drv.h
Normal file
183
rknpu-driver/driver-0.9.6/include/rknpu_drv.h
Normal file
@@ -0,0 +1,183 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RKNPU_DRV_H_
|
||||
#define __LINUX_RKNPU_DRV_H_
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/miscdevice.h>
|
||||
|
||||
#include <soc/rockchip/rockchip_opp_select.h>
|
||||
#include <soc/rockchip/rockchip_system_monitor.h>
|
||||
#include <soc/rockchip/rockchip_ipa.h>
|
||||
|
||||
#include "rknpu_job.h"
|
||||
#include "rknpu_fence.h"
|
||||
#include "rknpu_debugger.h"
|
||||
#include "rknpu_mm.h"
|
||||
|
||||
#define DRIVER_NAME "rknpu"
|
||||
#define DRIVER_DESC "RKNPU driver"
|
||||
#define DRIVER_DATE "20240322"
|
||||
#define DRIVER_MAJOR 0
|
||||
#define DRIVER_MINOR 9
|
||||
#define DRIVER_PATCHLEVEL 6
|
||||
|
||||
#define LOG_TAG "RKNPU"
|
||||
|
||||
/* sample interval: 1000ms */
|
||||
#define RKNPU_LOAD_INTERVAL 1000000000
|
||||
|
||||
#define LOG_INFO(fmt, args...) pr_info(LOG_TAG ": " fmt, ##args)
|
||||
#if KERNEL_VERSION(5, 5, 0) <= LINUX_VERSION_CODE
|
||||
#define LOG_WARN(fmt, args...) pr_warn(LOG_TAG ": " fmt, ##args)
|
||||
#else
|
||||
#define LOG_WARN(fmt, args...) pr_warning(LOG_TAG ": " fmt, ##args)
|
||||
#endif
|
||||
#define LOG_DEBUG(fmt, args...) pr_devel(LOG_TAG ": " fmt, ##args)
|
||||
#define LOG_ERROR(fmt, args...) pr_err(LOG_TAG ": " fmt, ##args)
|
||||
|
||||
#define LOG_DEV_INFO(dev, fmt, args...) dev_info(dev, LOG_TAG ": " fmt, ##args)
|
||||
#define LOG_DEV_WARN(dev, fmt, args...) dev_warn(dev, LOG_TAG ": " fmt, ##args)
|
||||
#define LOG_DEV_DEBUG(dev, fmt, args...) dev_dbg(dev, LOG_TAG ": " fmt, ##args)
|
||||
#define LOG_DEV_ERROR(dev, fmt, args...) dev_err(dev, LOG_TAG ": " fmt, ##args)
|
||||
|
||||
#define RKNPU_MAX_IOMMU_DOMAIN_NUM 16
|
||||
|
||||
struct rknpu_irqs_data {
|
||||
const char *name;
|
||||
irqreturn_t (*irq_hdl)(int irq, void *ctx);
|
||||
};
|
||||
|
||||
struct rknpu_amount_data {
|
||||
uint16_t offset_clr_all;
|
||||
uint16_t offset_dt_wr;
|
||||
uint16_t offset_dt_rd;
|
||||
uint16_t offset_wt_rd;
|
||||
};
|
||||
|
||||
struct rknpu_config {
|
||||
__u32 bw_priority_addr;
|
||||
__u32 bw_priority_length;
|
||||
__u64 dma_mask;
|
||||
__u32 pc_data_amount_scale;
|
||||
__u32 pc_task_number_bits;
|
||||
__u32 pc_task_number_mask;
|
||||
__u32 pc_task_status_offset;
|
||||
__u32 pc_dma_ctrl;
|
||||
const struct rknpu_irqs_data *irqs;
|
||||
int num_irqs;
|
||||
__u64 nbuf_phyaddr;
|
||||
__u64 nbuf_size;
|
||||
__u64 max_submit_number;
|
||||
__u32 core_mask;
|
||||
const struct rknpu_amount_data *amount_top;
|
||||
const struct rknpu_amount_data *amount_core;
|
||||
};
|
||||
|
||||
struct rknpu_timer {
|
||||
ktime_t busy_time;
|
||||
ktime_t total_busy_time;
|
||||
};
|
||||
|
||||
struct rknpu_subcore_data {
|
||||
struct list_head todo_list;
|
||||
wait_queue_head_t job_done_wq;
|
||||
struct rknpu_job *job;
|
||||
int64_t task_num;
|
||||
struct rknpu_timer timer;
|
||||
};
|
||||
|
||||
/**
|
||||
* RKNPU device
|
||||
*
|
||||
* @base: IO mapped base address for device
|
||||
* @dev: Device instance
|
||||
* @drm_dev: DRM device instance
|
||||
*/
|
||||
struct rknpu_device {
|
||||
void __iomem *base[RKNPU_MAX_CORES];
|
||||
struct device *dev;
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM
|
||||
struct device *fake_dev;
|
||||
struct drm_device *drm_dev;
|
||||
#endif
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP
|
||||
struct miscdevice miscdev;
|
||||
struct rk_dma_heap *heap;
|
||||
#endif
|
||||
atomic_t sequence;
|
||||
spinlock_t lock;
|
||||
spinlock_t irq_lock;
|
||||
struct mutex power_lock;
|
||||
struct mutex reset_lock;
|
||||
struct mutex domain_lock;
|
||||
struct rknpu_subcore_data subcore_datas[RKNPU_MAX_CORES];
|
||||
const struct rknpu_config *config;
|
||||
void __iomem *bw_priority_base;
|
||||
struct rknpu_fence_context *fence_ctx;
|
||||
bool iommu_en;
|
||||
struct reset_control **srsts;
|
||||
int num_srsts;
|
||||
struct clk_bulk_data *clks;
|
||||
int num_clks;
|
||||
struct regulator *vdd;
|
||||
struct regulator *mem;
|
||||
struct monitor_dev_info *mdev_info;
|
||||
struct ipa_power_model_data *model_data;
|
||||
struct thermal_cooling_device *devfreq_cooling;
|
||||
struct devfreq *devfreq;
|
||||
unsigned long ondemand_freq;
|
||||
struct rockchip_opp_info opp_info;
|
||||
unsigned long current_freq;
|
||||
unsigned long current_volt;
|
||||
int bypass_irq_handler;
|
||||
int bypass_soft_reset;
|
||||
bool soft_reseting;
|
||||
struct device *genpd_dev_npu0;
|
||||
struct device *genpd_dev_npu1;
|
||||
struct device *genpd_dev_npu2;
|
||||
bool multiple_domains;
|
||||
atomic_t power_refcount;
|
||||
atomic_t cmdline_power_refcount;
|
||||
struct delayed_work power_off_work;
|
||||
struct workqueue_struct *power_off_wq;
|
||||
struct rknpu_debugger debugger;
|
||||
struct hrtimer timer;
|
||||
ktime_t kt;
|
||||
phys_addr_t sram_start;
|
||||
phys_addr_t sram_end;
|
||||
phys_addr_t nbuf_start;
|
||||
phys_addr_t nbuf_end;
|
||||
uint32_t sram_size;
|
||||
uint32_t nbuf_size;
|
||||
void __iomem *sram_base_io;
|
||||
void __iomem *nbuf_base_io;
|
||||
struct rknpu_mm *sram_mm;
|
||||
unsigned long power_put_delay;
|
||||
struct iommu_group *iommu_group;
|
||||
int iommu_domain_num;
|
||||
int iommu_domain_id;
|
||||
struct iommu_domain *iommu_domains[RKNPU_MAX_IOMMU_DOMAIN_NUM];
|
||||
};
|
||||
|
||||
struct rknpu_session {
|
||||
struct rknpu_device *rknpu_dev;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
int rknpu_power_get(struct rknpu_device *rknpu_dev);
|
||||
int rknpu_power_put(struct rknpu_device *rknpu_dev);
|
||||
|
||||
#endif /* __LINUX_RKNPU_DRV_H_ */
|
||||
24
rknpu-driver/driver-0.9.6/include/rknpu_fence.h
Normal file
24
rknpu-driver/driver-0.9.6/include/rknpu_fence.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RKNPU_FENCE_H_
|
||||
#define __LINUX_RKNPU_FENCE_H_
|
||||
|
||||
#include "rknpu_job.h"
|
||||
|
||||
struct rknpu_fence_context {
|
||||
unsigned int context;
|
||||
unsigned int seqno;
|
||||
spinlock_t spinlock;
|
||||
};
|
||||
|
||||
int rknpu_fence_context_alloc(struct rknpu_device *rknpu_dev);
|
||||
|
||||
int rknpu_fence_alloc(struct rknpu_job *job);
|
||||
|
||||
int rknpu_fence_get_fd(struct rknpu_job *job);
|
||||
|
||||
#endif /* __LINUX_RKNPU_FENCE_H_ */
|
||||
215
rknpu-driver/driver-0.9.6/include/rknpu_gem.h
Normal file
215
rknpu-driver/driver-0.9.6/include/rknpu_gem.h
Normal file
@@ -0,0 +1,215 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RKNPU_GEM_H
|
||||
#define __LINUX_RKNPU_GEM_H
|
||||
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_vma_manager.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_mode.h>
|
||||
|
||||
#if KERNEL_VERSION(4, 14, 0) > LINUX_VERSION_CODE
|
||||
#include <drm/drm_mem_util.h>
|
||||
#endif
|
||||
|
||||
#include "rknpu_mm.h"
|
||||
|
||||
#define to_rknpu_obj(x) container_of(x, struct rknpu_gem_object, base)
|
||||
|
||||
/*
|
||||
* rknpu drm buffer structure.
|
||||
*
|
||||
* @base: a gem object.
|
||||
* - a new handle to this gem object would be created
|
||||
* by drm_gem_handle_create().
|
||||
* @flags: indicate memory type to allocated buffer and cache attribute.
|
||||
* @size: size requested from user, in bytes and this size is aligned
|
||||
* in page unit.
|
||||
* @cookie: cookie returned by dma_alloc_attrs
|
||||
* @kv_addr: kernel virtual address to allocated memory region.
|
||||
* @dma_addr: bus address(accessed by dma) to allocated memory region.
|
||||
* - this address could be physical address without IOMMU and
|
||||
* device address with IOMMU.
|
||||
* @pages: Array of backing pages.
|
||||
* @sgt: Imported sg_table.
|
||||
*
|
||||
* P.S. this object would be transferred to user as kms_bo.handle so
|
||||
* user can access the buffer through kms_bo.handle.
|
||||
*/
|
||||
struct rknpu_gem_object {
|
||||
struct drm_gem_object base;
|
||||
unsigned int flags;
|
||||
unsigned long size;
|
||||
unsigned long sram_size;
|
||||
unsigned long nbuf_size;
|
||||
struct rknpu_mm_obj *sram_obj;
|
||||
dma_addr_t iova_start;
|
||||
unsigned long iova_size;
|
||||
void *cookie;
|
||||
void __iomem *kv_addr;
|
||||
dma_addr_t dma_addr;
|
||||
unsigned long dma_attrs;
|
||||
unsigned long num_pages;
|
||||
struct page **pages;
|
||||
struct sg_table *sgt;
|
||||
struct drm_mm_node mm_node;
|
||||
int iommu_domain_id;
|
||||
};
|
||||
|
||||
enum rknpu_cache_type {
|
||||
RKNPU_CACHE_SRAM = 1 << 0,
|
||||
RKNPU_CACHE_NBUF = 1 << 1,
|
||||
};
|
||||
|
||||
/* create a new buffer with gem object */
|
||||
struct rknpu_gem_object *rknpu_gem_object_create(struct drm_device *dev,
|
||||
unsigned int flags,
|
||||
unsigned long size,
|
||||
unsigned long sram_size,
|
||||
int iommu_domain_id);
|
||||
|
||||
/* destroy a buffer with gem object */
|
||||
void rknpu_gem_object_destroy(struct rknpu_gem_object *rknpu_obj);
|
||||
|
||||
/* request gem object creation and buffer allocation as the size */
|
||||
int rknpu_gem_create_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
/* get fake-offset of gem object that can be used with mmap. */
|
||||
int rknpu_gem_map_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
int rknpu_gem_destroy_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
/*
|
||||
* get rknpu drm object,
|
||||
* gem object reference count would be increased.
|
||||
*/
|
||||
static inline void rknpu_gem_object_get(struct drm_gem_object *obj)
|
||||
{
|
||||
#if KERNEL_VERSION(4, 13, 0) < LINUX_VERSION_CODE
|
||||
drm_gem_object_get(obj);
|
||||
#else
|
||||
drm_gem_object_reference(obj);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* put rknpu drm object acquired from rknpu_gem_object_find() or rknpu_gem_object_get(),
|
||||
* gem object reference count would be decreased.
|
||||
*/
|
||||
static inline void rknpu_gem_object_put(struct drm_gem_object *obj)
|
||||
{
|
||||
#if KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE
|
||||
drm_gem_object_put(obj);
|
||||
#elif KERNEL_VERSION(4, 13, 0) < LINUX_VERSION_CODE
|
||||
drm_gem_object_put_unlocked(obj);
|
||||
#else
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* get rknpu drm object from gem handle, this function could be used for
|
||||
* other drivers such as 2d/3d acceleration drivers.
|
||||
* with this function call, gem object reference count would be increased.
|
||||
*/
|
||||
static inline struct rknpu_gem_object *
|
||||
rknpu_gem_object_find(struct drm_file *filp, unsigned int handle)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
obj = drm_gem_object_lookup(filp, handle);
|
||||
if (!obj) {
|
||||
// DRM_ERROR("failed to lookup gem object.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rknpu_gem_object_put(obj);
|
||||
|
||||
return to_rknpu_obj(obj);
|
||||
}
|
||||
|
||||
/* get buffer information to memory region allocated by gem. */
|
||||
int rknpu_gem_get_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
/* free gem object. */
|
||||
void rknpu_gem_free_object(struct drm_gem_object *obj);
|
||||
|
||||
/* create memory region for drm framebuffer. */
|
||||
int rknpu_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
|
||||
struct drm_mode_create_dumb *args);
|
||||
|
||||
#if KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE
|
||||
/* map memory region for drm framebuffer to user space. */
|
||||
int rknpu_gem_dumb_map_offset(struct drm_file *file_priv,
|
||||
struct drm_device *dev, uint32_t handle,
|
||||
uint64_t *offset);
|
||||
#endif
|
||||
|
||||
/* page fault handler and mmap fault address(virtual) to physical memory. */
|
||||
#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE
|
||||
vm_fault_t rknpu_gem_fault(struct vm_fault *vmf);
|
||||
#elif KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE
|
||||
int rknpu_gem_fault(struct vm_fault *vmf);
|
||||
#else
|
||||
int rknpu_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
|
||||
#endif
|
||||
|
||||
int rknpu_gem_mmap_obj(struct drm_gem_object *obj, struct vm_area_struct *vma);
|
||||
|
||||
/* set vm_flags and we can change the vm attribute to other one at here. */
|
||||
int rknpu_gem_mmap(struct file *filp, struct vm_area_struct *vma);
|
||||
|
||||
/* low-level interface prime helpers */
|
||||
#if KERNEL_VERSION(4, 13, 0) <= LINUX_VERSION_CODE
|
||||
struct drm_gem_object *rknpu_gem_prime_import(struct drm_device *dev,
|
||||
struct dma_buf *dma_buf);
|
||||
#endif
|
||||
struct sg_table *rknpu_gem_prime_get_sg_table(struct drm_gem_object *obj);
|
||||
struct drm_gem_object *
|
||||
rknpu_gem_prime_import_sg_table(struct drm_device *dev,
|
||||
struct dma_buf_attachment *attach,
|
||||
struct sg_table *sgt);
|
||||
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
|
||||
void *rknpu_gem_prime_vmap(struct drm_gem_object *obj);
|
||||
void rknpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
|
||||
#else
|
||||
int rknpu_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map);
|
||||
void rknpu_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map);
|
||||
#endif
|
||||
int rknpu_gem_prime_mmap(struct drm_gem_object *obj,
|
||||
struct vm_area_struct *vma);
|
||||
|
||||
int rknpu_gem_sync_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
static inline void *rknpu_gem_alloc_page(size_t nr_pages)
|
||||
{
|
||||
#if KERNEL_VERSION(4, 13, 0) <= LINUX_VERSION_CODE
|
||||
return kvmalloc_array(nr_pages, sizeof(struct page *),
|
||||
GFP_KERNEL | __GFP_ZERO);
|
||||
#else
|
||||
return drm_calloc_large(nr_pages, sizeof(struct page *));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void rknpu_gem_free_page(void *pages)
|
||||
{
|
||||
#if KERNEL_VERSION(4, 13, 0) <= LINUX_VERSION_CODE
|
||||
kvfree(pages);
|
||||
#else
|
||||
drm_free_large(pages);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
327
rknpu-driver/driver-0.9.6/include/rknpu_ioctl.h
Normal file
327
rknpu-driver/driver-0.9.6/include/rknpu_ioctl.h
Normal file
@@ -0,0 +1,327 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RKNPU_IOCTL_H
|
||||
#define __LINUX_RKNPU_IOCTL_H
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
#define __user
|
||||
#endif
|
||||
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((packed))
|
||||
#endif
|
||||
|
||||
#define RKNPU_OFFSET_VERSION 0x0
|
||||
#define RKNPU_OFFSET_VERSION_NUM 0x4
|
||||
#define RKNPU_OFFSET_PC_OP_EN 0x8
|
||||
#define RKNPU_OFFSET_PC_DATA_ADDR 0x10
|
||||
#define RKNPU_OFFSET_PC_DATA_AMOUNT 0x14
|
||||
#define RKNPU_OFFSET_PC_TASK_CONTROL 0x30
|
||||
#define RKNPU_OFFSET_PC_DMA_BASE_ADDR 0x34
|
||||
|
||||
#define RKNPU_OFFSET_INT_MASK 0x20
|
||||
#define RKNPU_OFFSET_INT_CLEAR 0x24
|
||||
#define RKNPU_OFFSET_INT_STATUS 0x28
|
||||
#define RKNPU_OFFSET_INT_RAW_STATUS 0x2c
|
||||
|
||||
#define RKNPU_OFFSET_ENABLE_MASK 0xf008
|
||||
|
||||
#define RKNPU_INT_CLEAR 0x1ffff
|
||||
|
||||
#define RKNPU_PC_DATA_EXTRA_AMOUNT 4
|
||||
|
||||
#define RKNPU_STR_HELPER(x) #x
|
||||
|
||||
#define RKNPU_GET_DRV_VERSION_STRING(MAJOR, MINOR, PATCHLEVEL) \
|
||||
RKNPU_STR_HELPER(MAJOR) \
|
||||
"." RKNPU_STR_HELPER(MINOR) "." RKNPU_STR_HELPER(PATCHLEVEL)
|
||||
#define RKNPU_GET_DRV_VERSION_CODE(MAJOR, MINOR, PATCHLEVEL) \
|
||||
(MAJOR * 10000 + MINOR * 100 + PATCHLEVEL)
|
||||
#define RKNPU_GET_DRV_VERSION_MAJOR(CODE) (CODE / 10000)
|
||||
#define RKNPU_GET_DRV_VERSION_MINOR(CODE) ((CODE % 10000) / 100)
|
||||
#define RKNPU_GET_DRV_VERSION_PATCHLEVEL(CODE) (CODE % 100)
|
||||
|
||||
/* memory type definitions. */
|
||||
enum e_rknpu_mem_type {
|
||||
/* physically continuous memory and used as default. */
|
||||
RKNPU_MEM_CONTIGUOUS = 0 << 0,
|
||||
/* physically non-continuous memory. */
|
||||
RKNPU_MEM_NON_CONTIGUOUS = 1 << 0,
|
||||
/* non-cacheable mapping and used as default. */
|
||||
RKNPU_MEM_NON_CACHEABLE = 0 << 1,
|
||||
/* cacheable mapping. */
|
||||
RKNPU_MEM_CACHEABLE = 1 << 1,
|
||||
/* write-combine mapping. */
|
||||
RKNPU_MEM_WRITE_COMBINE = 1 << 2,
|
||||
/* dma attr kernel mapping */
|
||||
RKNPU_MEM_KERNEL_MAPPING = 1 << 3,
|
||||
/* iommu mapping */
|
||||
RKNPU_MEM_IOMMU = 1 << 4,
|
||||
/* zero mapping */
|
||||
RKNPU_MEM_ZEROING = 1 << 5,
|
||||
/* allocate secure buffer */
|
||||
RKNPU_MEM_SECURE = 1 << 6,
|
||||
/* allocate from dma32 zone */
|
||||
RKNPU_MEM_DMA32 = 1 << 7,
|
||||
/* request SRAM */
|
||||
RKNPU_MEM_TRY_ALLOC_SRAM = 1 << 8,
|
||||
/* request NBUF */
|
||||
RKNPU_MEM_TRY_ALLOC_NBUF = 1 << 9,
|
||||
RKNPU_MEM_MASK = RKNPU_MEM_NON_CONTIGUOUS | RKNPU_MEM_CACHEABLE |
|
||||
RKNPU_MEM_WRITE_COMBINE | RKNPU_MEM_KERNEL_MAPPING |
|
||||
RKNPU_MEM_IOMMU | RKNPU_MEM_ZEROING |
|
||||
RKNPU_MEM_SECURE | RKNPU_MEM_DMA32 |
|
||||
RKNPU_MEM_TRY_ALLOC_SRAM | RKNPU_MEM_TRY_ALLOC_NBUF
|
||||
};
|
||||
|
||||
/* sync mode definitions. */
|
||||
enum e_rknpu_mem_sync_mode {
|
||||
RKNPU_MEM_SYNC_TO_DEVICE = 1 << 0,
|
||||
RKNPU_MEM_SYNC_FROM_DEVICE = 1 << 1,
|
||||
RKNPU_MEM_SYNC_MASK =
|
||||
RKNPU_MEM_SYNC_TO_DEVICE | RKNPU_MEM_SYNC_FROM_DEVICE
|
||||
};
|
||||
|
||||
/* job mode definitions. */
|
||||
enum e_rknpu_job_mode {
|
||||
RKNPU_JOB_SLAVE = 0 << 0,
|
||||
RKNPU_JOB_PC = 1 << 0,
|
||||
RKNPU_JOB_BLOCK = 0 << 1,
|
||||
RKNPU_JOB_NONBLOCK = 1 << 1,
|
||||
RKNPU_JOB_PINGPONG = 1 << 2,
|
||||
RKNPU_JOB_FENCE_IN = 1 << 3,
|
||||
RKNPU_JOB_FENCE_OUT = 1 << 4,
|
||||
RKNPU_JOB_MASK = RKNPU_JOB_PC | RKNPU_JOB_NONBLOCK |
|
||||
RKNPU_JOB_PINGPONG | RKNPU_JOB_FENCE_IN |
|
||||
RKNPU_JOB_FENCE_OUT
|
||||
};
|
||||
|
||||
/* action definitions */
|
||||
enum e_rknpu_action {
|
||||
RKNPU_GET_HW_VERSION = 0,
|
||||
RKNPU_GET_DRV_VERSION = 1,
|
||||
RKNPU_GET_FREQ = 2,
|
||||
RKNPU_SET_FREQ = 3,
|
||||
RKNPU_GET_VOLT = 4,
|
||||
RKNPU_SET_VOLT = 5,
|
||||
RKNPU_ACT_RESET = 6,
|
||||
RKNPU_GET_BW_PRIORITY = 7,
|
||||
RKNPU_SET_BW_PRIORITY = 8,
|
||||
RKNPU_GET_BW_EXPECT = 9,
|
||||
RKNPU_SET_BW_EXPECT = 10,
|
||||
RKNPU_GET_BW_TW = 11,
|
||||
RKNPU_SET_BW_TW = 12,
|
||||
RKNPU_ACT_CLR_TOTAL_RW_AMOUNT = 13,
|
||||
RKNPU_GET_DT_WR_AMOUNT = 14,
|
||||
RKNPU_GET_DT_RD_AMOUNT = 15,
|
||||
RKNPU_GET_WT_RD_AMOUNT = 16,
|
||||
RKNPU_GET_TOTAL_RW_AMOUNT = 17,
|
||||
RKNPU_GET_IOMMU_EN = 18,
|
||||
RKNPU_SET_PROC_NICE = 19,
|
||||
RKNPU_POWER_ON = 20,
|
||||
RKNPU_POWER_OFF = 21,
|
||||
RKNPU_GET_TOTAL_SRAM_SIZE = 22,
|
||||
RKNPU_GET_FREE_SRAM_SIZE = 23,
|
||||
RKNPU_GET_IOMMU_DOMAIN_ID = 24,
|
||||
RKNPU_SET_IOMMU_DOMAIN_ID = 25,
|
||||
};
|
||||
|
||||
/**
|
||||
* User-desired buffer creation information structure.
|
||||
*
|
||||
* @handle: The handle of the created GEM object.
|
||||
* @flags: user request for setting memory type or cache attributes.
|
||||
* @size: user-desired memory allocation size.
|
||||
* - this size value would be page-aligned internally.
|
||||
* @obj_addr: address of RKNPU memory object.
|
||||
* @dma_addr: dma address that access by rknpu.
|
||||
* @sram_size: user-desired sram memory allocation size.
|
||||
* - this size value would be page-aligned internally.
|
||||
* @iommu_domain_id: iommu domain id
|
||||
* @reserved: just padding to be 64-bit aligned.
|
||||
*/
|
||||
struct rknpu_mem_create {
|
||||
__u32 handle;
|
||||
__u32 flags;
|
||||
__u64 size;
|
||||
__u64 obj_addr;
|
||||
__u64 dma_addr;
|
||||
__u64 sram_size;
|
||||
__s32 iommu_domain_id;
|
||||
__u32 reserved;
|
||||
};
|
||||
|
||||
/**
|
||||
* A structure for getting a fake-offset that can be used with mmap.
|
||||
*
|
||||
* @handle: handle of gem object.
|
||||
* @reserved: just padding to be 64-bit aligned.
|
||||
* @offset: a fake-offset of gem object.
|
||||
*/
|
||||
struct rknpu_mem_map {
|
||||
__u32 handle;
|
||||
__u32 reserved;
|
||||
__u64 offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* For destroying DMA buffer
|
||||
*
|
||||
* @handle: handle of the buffer.
|
||||
* @reserved: reserved for padding.
|
||||
* @obj_addr: rknpu_mem_object addr.
|
||||
*/
|
||||
struct rknpu_mem_destroy {
|
||||
__u32 handle;
|
||||
__u32 reserved;
|
||||
__u64 obj_addr;
|
||||
};
|
||||
|
||||
/**
|
||||
* For synchronizing DMA buffer
|
||||
*
|
||||
* @flags: user request for setting memory type or cache attributes.
|
||||
* @reserved: reserved for padding.
|
||||
* @obj_addr: address of RKNPU memory object.
|
||||
* @offset: offset in bytes from start address of buffer.
|
||||
* @size: size of memory region.
|
||||
*
|
||||
*/
|
||||
struct rknpu_mem_sync {
|
||||
__u32 flags;
|
||||
__u32 reserved;
|
||||
__u64 obj_addr;
|
||||
__u64 offset;
|
||||
__u64 size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rknpu_task structure for task information
|
||||
*
|
||||
* @flags: flags for task
|
||||
* @op_idx: operator index
|
||||
* @enable_mask: enable mask
|
||||
* @int_mask: interrupt mask
|
||||
* @int_clear: interrupt clear
|
||||
* @int_status: interrupt status
|
||||
* @regcfg_amount: register config number
|
||||
* @regcfg_offset: offset for register config
|
||||
* @regcmd_addr: address for register command
|
||||
*
|
||||
*/
|
||||
struct rknpu_task {
|
||||
__u32 flags;
|
||||
__u32 op_idx;
|
||||
__u32 enable_mask;
|
||||
__u32 int_mask;
|
||||
__u32 int_clear;
|
||||
__u32 int_status;
|
||||
__u32 regcfg_amount;
|
||||
__u32 regcfg_offset;
|
||||
__u64 regcmd_addr;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct rknpu_subcore_task structure for subcore task index
|
||||
*
|
||||
* @task_start: task start index
|
||||
* @task_number: task number
|
||||
*
|
||||
*/
|
||||
struct rknpu_subcore_task {
|
||||
__u32 task_start;
|
||||
__u32 task_number;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rknpu_submit structure for job submit
|
||||
*
|
||||
* @flags: flags for job submit
|
||||
* @timeout: submit timeout
|
||||
* @task_start: task start index
|
||||
* @task_number: task number
|
||||
* @task_counter: task counter
|
||||
* @priority: submit priority
|
||||
* @task_obj_addr: address of task object
|
||||
* @iommu_domain_id: iommu domain id
|
||||
* @reserved: just padding to be 64-bit aligned.
|
||||
* @task_base_addr: task base address
|
||||
* @hw_elapse_time: hardware elapse time
|
||||
* @core_mask: core mask of rknpu
|
||||
* @fence_fd: dma fence fd
|
||||
* @subcore_task: subcore task
|
||||
*
|
||||
*/
|
||||
struct rknpu_submit {
|
||||
__u32 flags;
|
||||
__u32 timeout;
|
||||
__u32 task_start;
|
||||
__u32 task_number;
|
||||
__u32 task_counter;
|
||||
__s32 priority;
|
||||
__u64 task_obj_addr;
|
||||
__u32 iommu_domain_id;
|
||||
__u32 reserved;
|
||||
__u64 task_base_addr;
|
||||
__s64 hw_elapse_time;
|
||||
__u32 core_mask;
|
||||
__s32 fence_fd;
|
||||
struct rknpu_subcore_task subcore_task[5];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rknpu_task structure for action (GET, SET or ACT)
|
||||
*
|
||||
* @flags: flags for action
|
||||
* @value: GET or SET value
|
||||
*
|
||||
*/
|
||||
struct rknpu_action {
|
||||
__u32 flags;
|
||||
__u32 value;
|
||||
};
|
||||
|
||||
#define RKNPU_ACTION 0x00
|
||||
#define RKNPU_SUBMIT 0x01
|
||||
#define RKNPU_MEM_CREATE 0x02
|
||||
#define RKNPU_MEM_MAP 0x03
|
||||
#define RKNPU_MEM_DESTROY 0x04
|
||||
#define RKNPU_MEM_SYNC 0x05
|
||||
|
||||
#define RKNPU_IOC_MAGIC 'r'
|
||||
#define RKNPU_IOW(nr, type) _IOW(RKNPU_IOC_MAGIC, nr, type)
|
||||
#define RKNPU_IOR(nr, type) _IOR(RKNPU_IOC_MAGIC, nr, type)
|
||||
#define RKNPU_IOWR(nr, type) _IOWR(RKNPU_IOC_MAGIC, nr, type)
|
||||
|
||||
#include <drm/drm.h>
|
||||
|
||||
#define DRM_IOCTL_RKNPU_ACTION \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + RKNPU_ACTION, struct rknpu_action)
|
||||
#define DRM_IOCTL_RKNPU_SUBMIT \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + RKNPU_SUBMIT, struct rknpu_submit)
|
||||
#define DRM_IOCTL_RKNPU_MEM_CREATE \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + RKNPU_MEM_CREATE, struct rknpu_mem_create)
|
||||
#define DRM_IOCTL_RKNPU_MEM_MAP \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + RKNPU_MEM_MAP, struct rknpu_mem_map)
|
||||
#define DRM_IOCTL_RKNPU_MEM_DESTROY \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + RKNPU_MEM_DESTROY, struct rknpu_mem_destroy)
|
||||
#define DRM_IOCTL_RKNPU_MEM_SYNC \
|
||||
DRM_IOWR(DRM_COMMAND_BASE + RKNPU_MEM_SYNC, struct rknpu_mem_sync)
|
||||
|
||||
#define IOCTL_RKNPU_ACTION RKNPU_IOWR(RKNPU_ACTION, struct rknpu_action)
|
||||
#define IOCTL_RKNPU_SUBMIT RKNPU_IOWR(RKNPU_SUBMIT, struct rknpu_submit)
|
||||
#define IOCTL_RKNPU_MEM_CREATE \
|
||||
RKNPU_IOWR(RKNPU_MEM_CREATE, struct rknpu_mem_create)
|
||||
#define IOCTL_RKNPU_MEM_MAP RKNPU_IOWR(RKNPU_MEM_MAP, struct rknpu_mem_map)
|
||||
#define IOCTL_RKNPU_MEM_DESTROY \
|
||||
RKNPU_IOWR(RKNPU_MEM_DESTROY, struct rknpu_mem_destroy)
|
||||
#define IOCTL_RKNPU_MEM_SYNC RKNPU_IOWR(RKNPU_MEM_SYNC, struct rknpu_mem_sync)
|
||||
|
||||
#endif
|
||||
48
rknpu-driver/driver-0.9.6/include/rknpu_iommu.h
Normal file
48
rknpu-driver/driver-0.9.6/include/rknpu_iommu.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RKNPU_IOMMU_H
|
||||
#define __LINUX_RKNPU_IOMMU_H
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/iova.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
|
||||
#include <linux/dma-iommu.h>
|
||||
#endif
|
||||
|
||||
#include "rknpu_drv.h"
|
||||
|
||||
enum iommu_dma_cookie_type {
|
||||
IOMMU_DMA_IOVA_COOKIE,
|
||||
IOMMU_DMA_MSI_COOKIE,
|
||||
};
|
||||
|
||||
struct rknpu_iommu_dma_cookie {
|
||||
enum iommu_dma_cookie_type type;
|
||||
|
||||
/* Full allocator for IOMMU_DMA_IOVA_COOKIE */
|
||||
struct iova_domain iovad;
|
||||
};
|
||||
|
||||
dma_addr_t rknpu_iommu_dma_alloc_iova(struct iommu_domain *domain, size_t size,
|
||||
u64 dma_limit, struct device *dev);
|
||||
|
||||
void rknpu_iommu_dma_free_iova(struct rknpu_iommu_dma_cookie *cookie,
|
||||
dma_addr_t iova, size_t size);
|
||||
|
||||
int rknpu_iommu_init_domain(struct rknpu_device *rknpu_dev);
|
||||
int rknpu_iommu_switch_domain(struct rknpu_device *rknpu_dev, int domain_id);
|
||||
void rknpu_iommu_free_domains(struct rknpu_device *rknpu_dev);
|
||||
|
||||
#if KERNEL_VERSION(5, 10, 0) < LINUX_VERSION_CODE
|
||||
int iommu_get_dma_cookie(struct iommu_domain *domain);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
81
rknpu-driver/driver-0.9.6/include/rknpu_job.h
Normal file
81
rknpu-driver/driver-0.9.6/include/rknpu_job.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RKNPU_JOB_H_
|
||||
#define __LINUX_RKNPU_JOB_H_
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/dma-fence.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <drm/drm_device.h>
|
||||
|
||||
#include "rknpu_ioctl.h"
|
||||
|
||||
#define RKNPU_MAX_CORES 3
|
||||
|
||||
#define RKNPU_JOB_DONE (1 << 0)
|
||||
#define RKNPU_JOB_ASYNC (1 << 1)
|
||||
#define RKNPU_JOB_DETACHED (1 << 2)
|
||||
|
||||
#define RKNPU_CORE_AUTO_MASK 0x00
|
||||
#define RKNPU_CORE0_MASK 0x01
|
||||
#define RKNPU_CORE1_MASK 0x02
|
||||
#define RKNPU_CORE2_MASK 0x04
|
||||
|
||||
struct rknpu_job {
|
||||
struct rknpu_device *rknpu_dev;
|
||||
struct list_head head[RKNPU_MAX_CORES];
|
||||
struct work_struct cleanup_work;
|
||||
bool irq_entry[RKNPU_MAX_CORES];
|
||||
unsigned int flags;
|
||||
int ret;
|
||||
struct rknpu_submit *args;
|
||||
bool args_owner;
|
||||
struct rknpu_task *first_task;
|
||||
struct rknpu_task *last_task;
|
||||
uint32_t int_mask[RKNPU_MAX_CORES];
|
||||
uint32_t int_status[RKNPU_MAX_CORES];
|
||||
struct dma_fence *fence;
|
||||
ktime_t timestamp;
|
||||
uint32_t use_core_num;
|
||||
atomic_t run_count;
|
||||
atomic_t interrupt_count;
|
||||
ktime_t hw_commit_time;
|
||||
ktime_t hw_recoder_time;
|
||||
ktime_t hw_elapse_time;
|
||||
atomic_t submit_count[RKNPU_MAX_CORES];
|
||||
int iommu_domain_id;
|
||||
};
|
||||
|
||||
irqreturn_t rknpu_core0_irq_handler(int irq, void *data);
|
||||
irqreturn_t rknpu_core1_irq_handler(int irq, void *data);
|
||||
irqreturn_t rknpu_core2_irq_handler(int irq, void *data);
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM
|
||||
int rknpu_submit_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
#endif
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP
|
||||
int rknpu_submit_ioctl(struct rknpu_device *rknpu_dev, unsigned long data);
|
||||
#endif
|
||||
|
||||
int rknpu_get_hw_version(struct rknpu_device *rknpu_dev, uint32_t *version);
|
||||
|
||||
int rknpu_get_bw_priority(struct rknpu_device *rknpu_dev, uint32_t *priority,
|
||||
uint32_t *expect, uint32_t *tw);
|
||||
|
||||
int rknpu_set_bw_priority(struct rknpu_device *rknpu_dev, uint32_t priority,
|
||||
uint32_t expect, uint32_t tw);
|
||||
|
||||
int rknpu_clear_rw_amount(struct rknpu_device *rknpu_dev);
|
||||
|
||||
int rknpu_get_rw_amount(struct rknpu_device *rknpu_dev, uint32_t *dt_wr,
|
||||
uint32_t *dt_rd, uint32_t *wd_rd);
|
||||
|
||||
int rknpu_get_total_rw_amount(struct rknpu_device *rknpu_dev, uint32_t *amount);
|
||||
|
||||
#endif /* __LINUX_RKNPU_JOB_H_ */
|
||||
46
rknpu-driver/driver-0.9.6/include/rknpu_mem.h
Normal file
46
rknpu-driver/driver-0.9.6/include/rknpu_mem.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RKNPU_MEM_H
|
||||
#define __LINUX_RKNPU_MEM_H
|
||||
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
/*
|
||||
* rknpu DMA buffer structure.
|
||||
*
|
||||
* @flags: indicate memory type to allocated buffer and cache attribute.
|
||||
* @size: size requested from user, in bytes and this size is aligned
|
||||
* in page unit.
|
||||
* @kv_addr: kernel virtual address to allocated memory region.
|
||||
* @dma_addr: bus address(accessed by dma) to allocated memory region.
|
||||
* - this address could be physical address without IOMMU and
|
||||
* device address with IOMMU.
|
||||
* @pages: Array of backing pages.
|
||||
* @sgt: Imported sg_table.
|
||||
* @dmabuf: buffer for this attachment.
|
||||
* @owner: Is this memory internally allocated.
|
||||
*/
|
||||
struct rknpu_mem_object {
|
||||
unsigned long flags;
|
||||
unsigned long size;
|
||||
void __iomem *kv_addr;
|
||||
dma_addr_t dma_addr;
|
||||
struct page **pages;
|
||||
struct sg_table *sgt;
|
||||
struct dma_buf *dmabuf;
|
||||
struct list_head head;
|
||||
unsigned int owner;
|
||||
};
|
||||
|
||||
int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, struct file *file,
|
||||
unsigned int cmd, unsigned long data);
|
||||
int rknpu_mem_destroy_ioctl(struct rknpu_device *rknpu_dev, struct file *file,
|
||||
unsigned long data);
|
||||
int rknpu_mem_sync_ioctl(struct rknpu_device *rknpu_dev, unsigned long data);
|
||||
|
||||
#endif
|
||||
42
rknpu-driver/driver-0.9.6/include/rknpu_mm.h
Normal file
42
rknpu-driver/driver-0.9.6/include/rknpu_mm.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RKNPU_MM_H
|
||||
#define __LINUX_RKNPU_MM_H
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/iova.h>
|
||||
|
||||
#include "rknpu_drv.h"
|
||||
|
||||
struct rknpu_mm {
|
||||
void *bitmap;
|
||||
struct mutex lock;
|
||||
unsigned int chunk_size;
|
||||
unsigned int total_chunks;
|
||||
unsigned int free_chunks;
|
||||
};
|
||||
|
||||
struct rknpu_mm_obj {
|
||||
uint32_t range_start;
|
||||
uint32_t range_end;
|
||||
};
|
||||
|
||||
int rknpu_mm_create(unsigned int mem_size, unsigned int chunk_size,
|
||||
struct rknpu_mm **mm);
|
||||
|
||||
void rknpu_mm_destroy(struct rknpu_mm *mm);
|
||||
|
||||
int rknpu_mm_alloc(struct rknpu_mm *mm, unsigned int size,
|
||||
struct rknpu_mm_obj **mm_obj);
|
||||
|
||||
int rknpu_mm_free(struct rknpu_mm *mm, struct rknpu_mm_obj *mm_obj);
|
||||
|
||||
int rknpu_mm_dump(struct seq_file *m, void *data);
|
||||
|
||||
#endif
|
||||
18
rknpu-driver/driver-0.9.6/include/rknpu_reset.h
Normal file
18
rknpu-driver/driver-0.9.6/include/rknpu_reset.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RKNPU_RESET_H
|
||||
#define __LINUX_RKNPU_RESET_H
|
||||
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "rknpu_drv.h"
|
||||
|
||||
int rknpu_reset_get(struct rknpu_device *rknpu_dev);
|
||||
|
||||
int rknpu_soft_reset(struct rknpu_device *rknpu_dev);
|
||||
|
||||
#endif
|
||||
31
rknpu-driver/driver-0.9.6/rknpu.mod.c
Normal file
31
rknpu-driver/driver-0.9.6/rknpu.mod.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <linux/module.h>
|
||||
#define INCLUDE_VERMAGIC
|
||||
#include <linux/build-salt.h>
|
||||
#include <linux/vermagic.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
BUILD_SALT;
|
||||
|
||||
MODULE_INFO(vermagic, VERMAGIC_STRING);
|
||||
MODULE_INFO(name, KBUILD_MODNAME);
|
||||
|
||||
__visible struct module __this_module
|
||||
__section(".gnu.linkonce.this_module") = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.init = init_module,
|
||||
#ifdef CONFIG_MODULE_UNLOAD
|
||||
.exit = cleanup_module,
|
||||
#endif
|
||||
.arch = MODULE_ARCH_INIT,
|
||||
};
|
||||
|
||||
MODULE_INFO(intree, "Y");
|
||||
|
||||
#ifdef CONFIG_RETPOLINE
|
||||
MODULE_INFO(retpoline, "Y");
|
||||
#endif
|
||||
|
||||
MODULE_INFO(depends, "");
|
||||
|
||||
|
||||
MODULE_INFO(srcversion, "3F8407365EF7935915D4CC3");
|
||||
605
rknpu-driver/driver-0.9.6/rknpu_debugger.c
Normal file
605
rknpu-driver/driver-0.9.6/rknpu_debugger.c
Normal file
@@ -0,0 +1,605 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#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
|
||||
#ifdef CONFIG_PM_DEVFREQ
|
||||
#include <../drivers/devfreq/governor.h>
|
||||
#endif
|
||||
#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,
|
||||
DRIVER_MINOR, DRIVER_PATCHLEVEL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rknpu_load_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);
|
||||
struct rknpu_subcore_data *subcore_data = NULL;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
int load;
|
||||
uint64_t total_busy_time, div_value;
|
||||
|
||||
seq_puts(m, "NPU load: ");
|
||||
for (i = 0; i < rknpu_dev->config->num_irqs; i++) {
|
||||
subcore_data = &rknpu_dev->subcore_datas[i];
|
||||
|
||||
if (rknpu_dev->config->num_irqs > 1)
|
||||
seq_printf(m, " Core%d: ", i);
|
||||
|
||||
spin_lock_irqsave(&rknpu_dev->irq_lock, flags);
|
||||
|
||||
total_busy_time = subcore_data->timer.total_busy_time;
|
||||
|
||||
spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags);
|
||||
|
||||
div_value = (RKNPU_LOAD_INTERVAL / 100);
|
||||
do_div(total_busy_time, div_value);
|
||||
load = total_busy_time > 100 ? 100 : total_busy_time;
|
||||
|
||||
if (rknpu_dev->config->num_irqs > 1)
|
||||
seq_printf(m, "%2.d%%,", load);
|
||||
else
|
||||
seq_printf(m, "%2.d%%", load);
|
||||
}
|
||||
seq_puts(m, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rknpu_power_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);
|
||||
|
||||
if (atomic_read(&rknpu_dev->power_refcount) > 0)
|
||||
seq_puts(m, "on\n");
|
||||
else
|
||||
seq_puts(m, "off\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t rknpu_power_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[8];
|
||||
|
||||
if (len > sizeof(buf) - 1)
|
||||
return -EINVAL;
|
||||
if (copy_from_user(buf, ubuf, len))
|
||||
return -EFAULT;
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
if (strcmp(buf, "on") == 0) {
|
||||
atomic_inc(&rknpu_dev->cmdline_power_refcount);
|
||||
rknpu_power_get(rknpu_dev);
|
||||
LOG_INFO("rknpu power is on!");
|
||||
} else if (strcmp(buf, "off") == 0) {
|
||||
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);
|
||||
rknpu_power_put(rknpu_dev);
|
||||
}
|
||||
if (atomic_read(&rknpu_dev->power_refcount) <= 0)
|
||||
LOG_INFO("rknpu power is off!");
|
||||
} else {
|
||||
LOG_ERROR("rknpu power node params is invalid!");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_DEVFREQ
|
||||
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;
|
||||
}
|
||||
#else
|
||||
static ssize_t rknpu_freq_set(struct file *file, const char __user *ubuf,
|
||||
size_t len, loff_t *offp)
|
||||
{
|
||||
return -EFAULT;
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
struct rknpu_debugger *debugger = node->debugger;
|
||||
struct rknpu_device *rknpu_dev =
|
||||
container_of(debugger, struct rknpu_device, debugger);
|
||||
|
||||
if (!rknpu_dev->bypass_soft_reset)
|
||||
seq_puts(m, "on\n");
|
||||
else
|
||||
seq_puts(m, "off\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t rknpu_reset_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[8];
|
||||
|
||||
if (len > sizeof(buf) - 1)
|
||||
return -EINVAL;
|
||||
if (copy_from_user(buf, ubuf, len))
|
||||
return -EFAULT;
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
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;
|
||||
else if (strcmp(buf, "off") == 0)
|
||||
rknpu_dev->bypass_soft_reset = 1;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
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 },
|
||||
#endif
|
||||
};
|
||||
|
||||
static ssize_t rknpu_debugger_write(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;
|
||||
|
||||
if (node->info_ent->write)
|
||||
return node->info_ent->write(file, ubuf, len, offp);
|
||||
else
|
||||
return len;
|
||||
}
|
||||
|
||||
static int rknpu_debugfs_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct rknpu_debugger_node *node = inode->i_private;
|
||||
|
||||
return single_open(file, node->info_ent->show, node);
|
||||
}
|
||||
|
||||
static const struct file_operations rknpu_debugfs_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = rknpu_debugfs_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.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)
|
||||
{
|
||||
struct rknpu_debugger_node *pos, *q;
|
||||
struct list_head *entry_list;
|
||||
|
||||
mutex_lock(&debugger->debugfs_lock);
|
||||
|
||||
/* Delete debugfs entry list */
|
||||
entry_list = &debugger->debugfs_entry_list;
|
||||
list_for_each_entry_safe(pos, q, entry_list, list) {
|
||||
if (pos->dent == NULL)
|
||||
continue;
|
||||
list_del(&pos->list);
|
||||
kfree(pos);
|
||||
pos = NULL;
|
||||
}
|
||||
|
||||
/* Delete all debugfs node in this directory */
|
||||
debugfs_remove_recursive(debugger->debugfs_dir);
|
||||
debugger->debugfs_dir = NULL;
|
||||
|
||||
mutex_unlock(&debugger->debugfs_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rknpu_debugfs_create_files(const struct rknpu_debugger_list *files,
|
||||
int count, struct dentry *root,
|
||||
struct rknpu_debugger *debugger)
|
||||
{
|
||||
int i;
|
||||
struct dentry *ent;
|
||||
struct rknpu_debugger_node *tmp;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
tmp = kmalloc(sizeof(struct rknpu_debugger_node), GFP_KERNEL);
|
||||
if (tmp == NULL) {
|
||||
LOG_ERROR(
|
||||
"Cannot alloc node path /sys/kernel/debug/%pd/%s\n",
|
||||
root, files[i].name);
|
||||
goto MALLOC_FAIL;
|
||||
}
|
||||
|
||||
tmp->info_ent = &files[i];
|
||||
tmp->debugger = debugger;
|
||||
|
||||
ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
|
||||
root, tmp, &rknpu_debugfs_fops);
|
||||
if (!ent) {
|
||||
LOG_ERROR("Cannot create /sys/kernel/debug/%pd/%s\n",
|
||||
root, files[i].name);
|
||||
goto CREATE_FAIL;
|
||||
}
|
||||
|
||||
tmp->dent = ent;
|
||||
|
||||
mutex_lock(&debugger->debugfs_lock);
|
||||
list_add_tail(&tmp->list, &debugger->debugfs_entry_list);
|
||||
mutex_unlock(&debugger->debugfs_lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
CREATE_FAIL:
|
||||
kfree(tmp);
|
||||
MALLOC_FAIL:
|
||||
rknpu_debugfs_remove_files(debugger);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int rknpu_debugfs_remove(struct rknpu_debugger *debugger)
|
||||
{
|
||||
rknpu_debugfs_remove_files(debugger);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rknpu_debugfs_init(struct rknpu_debugger *debugger)
|
||||
{
|
||||
int ret;
|
||||
|
||||
debugger->debugfs_dir =
|
||||
debugfs_create_dir(RKNPU_DEBUGGER_ROOT_NAME, NULL);
|
||||
if (IS_ERR_OR_NULL(debugger->debugfs_dir)) {
|
||||
LOG_ERROR("failed on mkdir /sys/kernel/debug/%s\n",
|
||||
RKNPU_DEBUGGER_ROOT_NAME);
|
||||
debugger->debugfs_dir = NULL;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = rknpu_debugfs_create_files(rknpu_debugger_root_list,
|
||||
ARRAY_SIZE(rknpu_debugger_root_list),
|
||||
debugger->debugfs_dir, debugger);
|
||||
if (ret) {
|
||||
LOG_ERROR(
|
||||
"Could not install rknpu_debugger_root_list debugfs\n");
|
||||
goto CREATE_FAIL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
CREATE_FAIL:
|
||||
rknpu_debugfs_remove(debugger);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* #ifdef CONFIG_ROCKCHIP_RKNPU_DEBUG_FS */
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_PROC_FS
|
||||
static int rknpu_procfs_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
|
||||
struct rknpu_debugger_node *node = PDE_DATA(inode);
|
||||
#else
|
||||
struct rknpu_debugger_node *node = pde_data(inode);
|
||||
#endif
|
||||
|
||||
return single_open(file, node->info_ent->show, node);
|
||||
}
|
||||
|
||||
static const struct proc_ops rknpu_procfs_fops = {
|
||||
.proc_open = rknpu_procfs_open,
|
||||
.proc_read = seq_read,
|
||||
.proc_lseek = seq_lseek,
|
||||
.proc_release = single_release,
|
||||
.proc_write = rknpu_debugger_write,
|
||||
};
|
||||
|
||||
static int rknpu_procfs_remove_files(struct rknpu_debugger *debugger)
|
||||
{
|
||||
struct rknpu_debugger_node *pos, *q;
|
||||
struct list_head *entry_list;
|
||||
|
||||
mutex_lock(&debugger->procfs_lock);
|
||||
|
||||
/* Delete procfs entry list */
|
||||
entry_list = &debugger->procfs_entry_list;
|
||||
list_for_each_entry_safe(pos, q, entry_list, list) {
|
||||
if (pos->pent == NULL)
|
||||
continue;
|
||||
list_del(&pos->list);
|
||||
kfree(pos);
|
||||
pos = NULL;
|
||||
}
|
||||
|
||||
/* Delete all procfs node in this directory */
|
||||
proc_remove(debugger->procfs_dir);
|
||||
debugger->procfs_dir = NULL;
|
||||
|
||||
mutex_unlock(&debugger->procfs_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rknpu_procfs_create_files(const struct rknpu_debugger_list *files,
|
||||
int count, struct proc_dir_entry *root,
|
||||
struct rknpu_debugger *debugger)
|
||||
{
|
||||
int i;
|
||||
struct proc_dir_entry *ent;
|
||||
struct rknpu_debugger_node *tmp;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
tmp = kmalloc(sizeof(struct rknpu_debugger_node), GFP_KERNEL);
|
||||
if (tmp == NULL) {
|
||||
LOG_ERROR("Cannot alloc node path for /proc/%s/%s\n",
|
||||
RKNPU_DEBUGGER_ROOT_NAME, files[i].name);
|
||||
goto MALLOC_FAIL;
|
||||
}
|
||||
|
||||
tmp->info_ent = &files[i];
|
||||
tmp->debugger = debugger;
|
||||
|
||||
ent = proc_create_data(files[i].name, S_IFREG | S_IRUGO, root,
|
||||
&rknpu_procfs_fops, tmp);
|
||||
if (!ent) {
|
||||
LOG_ERROR("Cannot create /proc/%s/%s\n",
|
||||
RKNPU_DEBUGGER_ROOT_NAME, files[i].name);
|
||||
goto CREATE_FAIL;
|
||||
}
|
||||
|
||||
tmp->pent = ent;
|
||||
|
||||
mutex_lock(&debugger->procfs_lock);
|
||||
list_add_tail(&tmp->list, &debugger->procfs_entry_list);
|
||||
mutex_unlock(&debugger->procfs_lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
CREATE_FAIL:
|
||||
kfree(tmp);
|
||||
MALLOC_FAIL:
|
||||
rknpu_procfs_remove_files(debugger);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int rknpu_procfs_remove(struct rknpu_debugger *debugger)
|
||||
{
|
||||
rknpu_procfs_remove_files(debugger);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rknpu_procfs_init(struct rknpu_debugger *debugger)
|
||||
{
|
||||
int ret;
|
||||
|
||||
debugger->procfs_dir = proc_mkdir(RKNPU_DEBUGGER_ROOT_NAME, NULL);
|
||||
if (IS_ERR_OR_NULL(debugger->procfs_dir)) {
|
||||
pr_err("failed on mkdir /proc/%s\n", RKNPU_DEBUGGER_ROOT_NAME);
|
||||
debugger->procfs_dir = NULL;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = rknpu_procfs_create_files(rknpu_debugger_root_list,
|
||||
ARRAY_SIZE(rknpu_debugger_root_list),
|
||||
debugger->procfs_dir, debugger);
|
||||
if (ret) {
|
||||
pr_err("Could not install rknpu_debugger_root_list procfs\n");
|
||||
goto CREATE_FAIL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
CREATE_FAIL:
|
||||
rknpu_procfs_remove(debugger);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* #ifdef CONFIG_ROCKCHIP_RKNPU_PROC_FS */
|
||||
|
||||
int rknpu_debugger_init(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DEBUG_FS
|
||||
mutex_init(&rknpu_dev->debugger.debugfs_lock);
|
||||
INIT_LIST_HEAD(&rknpu_dev->debugger.debugfs_entry_list);
|
||||
rknpu_debugfs_init(&rknpu_dev->debugger);
|
||||
#endif
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_PROC_FS
|
||||
mutex_init(&rknpu_dev->debugger.procfs_lock);
|
||||
INIT_LIST_HEAD(&rknpu_dev->debugger.procfs_entry_list);
|
||||
rknpu_procfs_init(&rknpu_dev->debugger);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rknpu_debugger_remove(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DEBUG_FS
|
||||
rknpu_debugfs_remove(&rknpu_dev->debugger);
|
||||
#endif
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_PROC_FS
|
||||
rknpu_procfs_remove(&rknpu_dev->debugger);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
795
rknpu-driver/driver-0.9.6/rknpu_devfreq.c
Normal file
795
rknpu-driver/driver-0.9.6/rknpu_devfreq.c
Normal file
@@ -0,0 +1,795 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Finley Xiao <finley.xiao@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/devfreq_cooling.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <../drivers/devfreq/governor.h>
|
||||
#include "rknpu_drv.h"
|
||||
#include "rknpu_devfreq.h"
|
||||
|
||||
#define POWER_DOWN_FREQ 200000000
|
||||
|
||||
static int npu_devfreq_target(struct device *dev, unsigned long *freq,
|
||||
u32 flags);
|
||||
|
||||
static struct monitor_dev_profile npu_mdevp = {
|
||||
.type = MONITOR_TYPE_DEV,
|
||||
.low_temp_adjust = rockchip_monitor_dev_low_temp_adjust,
|
||||
.high_temp_adjust = rockchip_monitor_dev_high_temp_adjust,
|
||||
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
|
||||
.check_rate_volt = rockchip_monitor_check_rate_volt,
|
||||
#else
|
||||
.update_volt = rockchip_monitor_check_rate_volt,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int npu_devfreq_get_dev_status(struct device *dev,
|
||||
struct devfreq_dev_status *stat)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int npu_devfreq_get_cur_freq(struct device *dev, unsigned long *freq)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev);
|
||||
|
||||
*freq = rknpu_dev->current_freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct devfreq_dev_profile npu_devfreq_profile = {
|
||||
.polling_ms = 50,
|
||||
.target = npu_devfreq_target,
|
||||
.get_dev_status = npu_devfreq_get_dev_status,
|
||||
.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 && rknpu_dev->ondemand_freq)
|
||||
*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 int rk3576_npu_set_read_margin(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
u32 rm)
|
||||
{
|
||||
if (!opp_info->grf || !opp_info->volt_rm_tbl)
|
||||
return 0;
|
||||
|
||||
if (rm == opp_info->current_rm || rm == UINT_MAX)
|
||||
return 0;
|
||||
|
||||
LOG_DEV_DEBUG(dev, "set rm to %d\n", rm);
|
||||
|
||||
regmap_write(opp_info->grf, 0x08, 0x001c0000 | (rm << 2));
|
||||
regmap_write(opp_info->grf, 0x0c, 0x003c0000 | (rm << 2));
|
||||
regmap_write(opp_info->grf, 0x10, 0x001c0000 | (rm << 2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk3588_npu_get_soc_info(struct device *dev, struct device_node *np,
|
||||
int *bin, int *process)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 value = 0;
|
||||
|
||||
if (!bin)
|
||||
return 0;
|
||||
|
||||
if (of_property_match_string(np, "nvmem-cell-names",
|
||||
"specification_serial_number") >= 0) {
|
||||
ret = rockchip_nvmem_cell_read_u8(
|
||||
np, "specification_serial_number", &value);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(
|
||||
dev,
|
||||
"Failed to get specification_serial_number\n");
|
||||
return ret;
|
||||
}
|
||||
/* RK3588M */
|
||||
if (value == 0xd)
|
||||
*bin = 1;
|
||||
/* RK3588J */
|
||||
else if (value == 0xa)
|
||||
*bin = 2;
|
||||
}
|
||||
if (*bin < 0)
|
||||
*bin = 0;
|
||||
LOG_DEV_INFO(dev, "bin=%d\n", *bin);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
|
||||
static int rk3588_npu_set_soc_info(struct device *dev, struct device_node *np,
|
||||
struct rockchip_opp_info *opp_info)
|
||||
{
|
||||
int bin = opp_info->bin;
|
||||
|
||||
if (opp_info->volt_sel < 0)
|
||||
return 0;
|
||||
if (bin < 0)
|
||||
bin = 0;
|
||||
|
||||
if (!of_property_read_bool(np, "rockchip,supported-hw"))
|
||||
return 0;
|
||||
|
||||
/* SoC Version */
|
||||
opp_info->supported_hw[0] = BIT(bin);
|
||||
/* Speed Grade */
|
||||
opp_info->supported_hw[1] = BIT(opp_info->volt_sel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int rk3588_npu_set_soc_info(struct device *dev, struct device_node *np,
|
||||
int bin, int process, int volt_sel)
|
||||
{
|
||||
struct opp_table *opp_table;
|
||||
u32 supported_hw[2];
|
||||
|
||||
if (volt_sel < 0)
|
||||
return 0;
|
||||
if (bin < 0)
|
||||
bin = 0;
|
||||
|
||||
if (!of_property_read_bool(np, "rockchip,supported-hw"))
|
||||
return 0;
|
||||
|
||||
/* SoC Version */
|
||||
supported_hw[0] = BIT(bin);
|
||||
/* Speed Grade */
|
||||
supported_hw[1] = BIT(volt_sel);
|
||||
opp_table = dev_pm_opp_set_supported_hw(dev, supported_hw, 2);
|
||||
if (IS_ERR(opp_table)) {
|
||||
LOG_DEV_ERROR(dev, "failed to set supported opp\n");
|
||||
return PTR_ERR(opp_table);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rk3588_npu_set_read_margin(struct device *dev,
|
||||
struct rockchip_opp_info *opp_info,
|
||||
u32 rm)
|
||||
{
|
||||
u32 offset = 0, val = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
if (!opp_info->grf || !opp_info->volt_rm_tbl)
|
||||
return 0;
|
||||
|
||||
if (rm == opp_info->current_rm || rm == UINT_MAX)
|
||||
return 0;
|
||||
|
||||
LOG_DEV_DEBUG(dev, "set rm to %d\n", rm);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
ret = regmap_read(opp_info->grf, offset, &val);
|
||||
if (ret < 0) {
|
||||
LOG_DEV_ERROR(dev, "failed to get rm from 0x%x\n",
|
||||
offset);
|
||||
return ret;
|
||||
}
|
||||
val &= ~0x1c;
|
||||
regmap_write(opp_info->grf, offset, val | (rm << 2));
|
||||
offset += 4;
|
||||
}
|
||||
opp_info->current_rm = rm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
|
||||
static int npu_opp_config_regulators(struct device *dev,
|
||||
struct dev_pm_opp *old_opp,
|
||||
struct dev_pm_opp *new_opp,
|
||||
struct regulator **regulators,
|
||||
unsigned int count)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev);
|
||||
|
||||
return rockchip_opp_config_regulators(dev, old_opp, new_opp, regulators,
|
||||
count, &rknpu_dev->opp_info);
|
||||
}
|
||||
|
||||
static int npu_opp_config_clks(struct device *dev, struct opp_table *opp_table,
|
||||
struct dev_pm_opp *opp, void *data,
|
||||
bool scaling_down)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev);
|
||||
|
||||
return rockchip_opp_config_clks(dev, opp_table, opp, data, scaling_down,
|
||||
&rknpu_dev->opp_info);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct rockchip_opp_data rk3576_npu_opp_data = {
|
||||
.set_read_margin = rk3576_npu_set_read_margin,
|
||||
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
|
||||
.config_regulators = npu_opp_config_regulators,
|
||||
.config_clks = npu_opp_config_clks,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct rockchip_opp_data rk3588_npu_opp_data = {
|
||||
.get_soc_info = rk3588_npu_get_soc_info,
|
||||
.set_soc_info = rk3588_npu_set_soc_info,
|
||||
.set_read_margin = rk3588_npu_set_read_margin,
|
||||
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
|
||||
.config_regulators = npu_opp_config_regulators,
|
||||
.config_clks = npu_opp_config_clks,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct of_device_id rockchip_npu_of_match[] = {
|
||||
{
|
||||
.compatible = "rockchip,rk3576",
|
||||
.data = (void *)&rk3576_npu_opp_data,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3588",
|
||||
.data = (void *)&rk3588_npu_opp_data,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
|
||||
void rknpu_devfreq_lock(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
if (rknpu_dev->devfreq)
|
||||
rockchip_opp_dvfs_lock(&rknpu_dev->opp_info);
|
||||
}
|
||||
EXPORT_SYMBOL(rknpu_devfreq_lock);
|
||||
|
||||
void rknpu_devfreq_unlock(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
if (rknpu_dev->devfreq)
|
||||
rockchip_opp_dvfs_unlock(&rknpu_dev->opp_info);
|
||||
}
|
||||
EXPORT_SYMBOL(rknpu_devfreq_unlock);
|
||||
|
||||
static int npu_devfreq_target(struct device *dev, unsigned long *freq,
|
||||
u32 flags)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev);
|
||||
struct rockchip_opp_info *opp_info = &rknpu_dev->opp_info;
|
||||
struct dev_pm_opp *opp;
|
||||
unsigned long opp_volt;
|
||||
int ret = 0;
|
||||
|
||||
if (!opp_info->is_rate_volt_checked)
|
||||
return -EINVAL;
|
||||
|
||||
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);
|
||||
|
||||
if (*freq == rknpu_dev->current_freq)
|
||||
return 0;
|
||||
|
||||
rockchip_opp_dvfs_lock(opp_info);
|
||||
if (pm_runtime_active(dev))
|
||||
opp_info->is_runtime_active = true;
|
||||
else
|
||||
opp_info->is_runtime_active = false;
|
||||
ret = dev_pm_opp_set_rate(dev, *freq);
|
||||
if (!ret) {
|
||||
rknpu_dev->current_freq = *freq;
|
||||
if (rknpu_dev->devfreq)
|
||||
rknpu_dev->devfreq->last_status.current_frequency =
|
||||
*freq;
|
||||
rknpu_dev->current_volt = opp_volt;
|
||||
LOG_DEV_DEBUG(dev, "set rknpu freq: %lu, volt: %lu\n",
|
||||
rknpu_dev->current_freq, rknpu_dev->current_volt);
|
||||
}
|
||||
rockchip_opp_dvfs_unlock(opp_info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct rockchip_opp_data rockchip_npu_opp_data = {
|
||||
.config_clks = npu_opp_config_clks,
|
||||
};
|
||||
|
||||
int rknpu_devfreq_init(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
struct rockchip_opp_info *info = &rknpu_dev->opp_info;
|
||||
struct device *dev = rknpu_dev->dev;
|
||||
struct devfreq_dev_profile *dp;
|
||||
struct dev_pm_opp *opp;
|
||||
unsigned int dyn_power_coeff = 0;
|
||||
int ret = 0;
|
||||
|
||||
info->data = &rockchip_npu_opp_data;
|
||||
rockchip_get_opp_data(rockchip_npu_of_match, info);
|
||||
ret = rockchip_init_opp_table(dev, info, "clk_npu", "rknpu");
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(dev, "failed to init_opp_table\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rknpu_dev->current_freq = clk_get_rate(rknpu_dev->clks[0].clk);
|
||||
opp = devfreq_recommended_opp(dev, &rknpu_dev->current_freq, 0);
|
||||
if (IS_ERR(opp)) {
|
||||
ret = PTR_ERR(opp);
|
||||
goto err_uinit_table;
|
||||
}
|
||||
dev_pm_opp_put(opp);
|
||||
|
||||
dp = &npu_devfreq_profile;
|
||||
dp->initial_freq = rknpu_dev->current_freq;
|
||||
of_property_read_u32(dev->of_node, "dynamic-power-coefficient",
|
||||
&dyn_power_coeff);
|
||||
if (dyn_power_coeff)
|
||||
dp->is_cooling_device = true;
|
||||
|
||||
ret = devfreq_add_governor(&devfreq_rknpu_ondemand);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(dev, "failed to add rknpu_ondemand governor\n");
|
||||
goto err_uinit_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");
|
||||
ret = PTR_ERR(rknpu_dev->devfreq);
|
||||
rknpu_dev->devfreq = NULL;
|
||||
goto err_remove_governor;
|
||||
}
|
||||
|
||||
npu_mdevp.data = rknpu_dev->devfreq;
|
||||
npu_mdevp.opp_info = &rknpu_dev->opp_info;
|
||||
rknpu_dev->mdev_info =
|
||||
rockchip_system_monitor_register(dev, &npu_mdevp);
|
||||
if (IS_ERR(rknpu_dev->mdev_info)) {
|
||||
dev_dbg(dev, "without system monitor\n");
|
||||
rknpu_dev->mdev_info = NULL;
|
||||
}
|
||||
|
||||
rknpu_dev->current_freq = clk_get_rate(rknpu_dev->clks[0].clk);
|
||||
rknpu_dev->ondemand_freq = rknpu_dev->current_freq;
|
||||
rknpu_dev->current_volt = regulator_get_voltage(rknpu_dev->vdd);
|
||||
|
||||
rknpu_dev->devfreq->previous_freq = rknpu_dev->current_freq;
|
||||
if (rknpu_dev->devfreq->suspend_freq)
|
||||
rknpu_dev->devfreq->resume_freq = rknpu_dev->current_freq;
|
||||
rknpu_dev->devfreq->last_status.current_frequency =
|
||||
rknpu_dev->current_freq;
|
||||
rknpu_dev->devfreq->last_status.total_time = 1;
|
||||
rknpu_dev->devfreq->last_status.busy_time = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_governor:
|
||||
devfreq_remove_governor(&devfreq_rknpu_ondemand);
|
||||
err_uinit_table:
|
||||
rockchip_uninit_opp_table(dev, info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(rknpu_devfreq_init);
|
||||
|
||||
int rknpu_devfreq_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev);
|
||||
struct rockchip_opp_info *opp_info = &rknpu_dev->opp_info;
|
||||
|
||||
if (opp_info->is_scmi_clk) {
|
||||
if (clk_set_rate(opp_info->clk, POWER_DOWN_FREQ))
|
||||
LOG_DEV_ERROR(dev, "failed to restore clk rate\n");
|
||||
}
|
||||
opp_info->current_rm = UINT_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rknpu_devfreq_runtime_suspend);
|
||||
|
||||
int rknpu_devfreq_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->nclocks, opp_info->clocks);
|
||||
if (ret) {
|
||||
LOG_DEV_INFO(dev, "failed to enable opp clks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (opp_info->data && opp_info->data->set_read_margin)
|
||||
opp_info->data->set_read_margin(dev, opp_info,
|
||||
opp_info->target_rm);
|
||||
if (opp_info->is_scmi_clk) {
|
||||
if (clk_set_rate(opp_info->clk, rknpu_dev->current_freq))
|
||||
LOG_DEV_ERROR(dev, "failed to set power down rate\n");
|
||||
}
|
||||
|
||||
clk_bulk_disable_unprepare(opp_info->nclocks, opp_info->clocks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(rknpu_devfreq_runtime_resume);
|
||||
#else
|
||||
void rknpu_devfreq_lock(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
rockchip_monitor_volt_adjust_lock(rknpu_dev->mdev_info);
|
||||
}
|
||||
EXPORT_SYMBOL(rknpu_devfreq_lock);
|
||||
|
||||
void rknpu_devfreq_unlock(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
rockchip_monitor_volt_adjust_unlock(rknpu_dev->mdev_info);
|
||||
}
|
||||
EXPORT_SYMBOL(rknpu_devfreq_unlock);
|
||||
|
||||
static int npu_opp_helper(struct dev_pm_set_opp_data *data)
|
||||
{
|
||||
struct device *dev = data->dev;
|
||||
struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0];
|
||||
struct dev_pm_opp_supply *old_supply_mem = &data->old_opp.supplies[1];
|
||||
struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0];
|
||||
struct dev_pm_opp_supply *new_supply_mem = &data->new_opp.supplies[1];
|
||||
struct regulator *vdd_reg = data->regulators[0];
|
||||
struct regulator *mem_reg = data->regulators[1];
|
||||
struct clk *clk = data->clk;
|
||||
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev);
|
||||
struct rockchip_opp_info *opp_info = &rknpu_dev->opp_info;
|
||||
unsigned long old_freq = data->old_opp.rate;
|
||||
unsigned long new_freq = data->new_opp.rate;
|
||||
bool is_set_rm = true;
|
||||
bool is_set_clk = true;
|
||||
u32 target_rm = UINT_MAX;
|
||||
int ret = 0;
|
||||
|
||||
if (!pm_runtime_active(dev)) {
|
||||
is_set_rm = false;
|
||||
if (opp_info->scmi_clk)
|
||||
is_set_clk = false;
|
||||
}
|
||||
|
||||
ret = clk_bulk_prepare_enable(opp_info->num_clks, opp_info->clks);
|
||||
if (ret < 0) {
|
||||
LOG_DEV_ERROR(dev, "failed to enable opp clks\n");
|
||||
return ret;
|
||||
}
|
||||
rockchip_get_read_margin(dev, opp_info, new_supply_vdd->u_volt,
|
||||
&target_rm);
|
||||
|
||||
/* Change frequency */
|
||||
LOG_DEV_DEBUG(dev, "switching OPP: %lu Hz --> %lu Hz\n", old_freq,
|
||||
new_freq);
|
||||
/* Scaling up? Scale voltage before frequency */
|
||||
if (new_freq >= old_freq) {
|
||||
rockchip_set_intermediate_rate(dev, opp_info, clk, old_freq,
|
||||
new_freq, true, is_set_clk);
|
||||
ret = regulator_set_voltage(mem_reg, new_supply_mem->u_volt,
|
||||
INT_MAX);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(dev,
|
||||
"failed to set volt %lu uV for mem reg\n",
|
||||
new_supply_mem->u_volt);
|
||||
goto restore_voltage;
|
||||
}
|
||||
ret = regulator_set_voltage(vdd_reg, new_supply_vdd->u_volt,
|
||||
INT_MAX);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(dev,
|
||||
"failed to set volt %lu uV for vdd reg\n",
|
||||
new_supply_vdd->u_volt);
|
||||
goto restore_voltage;
|
||||
}
|
||||
rockchip_set_read_margin(dev, opp_info, target_rm, is_set_rm);
|
||||
if (is_set_clk && clk_set_rate(clk, new_freq)) {
|
||||
ret = -EINVAL;
|
||||
LOG_DEV_ERROR(dev, "failed to set clk rate: %d\n", ret);
|
||||
goto restore_rm;
|
||||
}
|
||||
/* Scaling down? Scale voltage after frequency */
|
||||
} else {
|
||||
rockchip_set_intermediate_rate(dev, opp_info, clk, old_freq,
|
||||
new_freq, false, is_set_clk);
|
||||
rockchip_set_read_margin(dev, opp_info, target_rm, is_set_rm);
|
||||
if (is_set_clk && clk_set_rate(clk, new_freq)) {
|
||||
ret = -EINVAL;
|
||||
LOG_DEV_ERROR(dev, "failed to set clk rate: %d\n", ret);
|
||||
goto restore_rm;
|
||||
}
|
||||
ret = regulator_set_voltage(vdd_reg, new_supply_vdd->u_volt,
|
||||
INT_MAX);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(dev,
|
||||
"failed to set volt %lu uV for vdd reg\n",
|
||||
new_supply_vdd->u_volt);
|
||||
goto restore_freq;
|
||||
}
|
||||
ret = regulator_set_voltage(mem_reg, new_supply_mem->u_volt,
|
||||
INT_MAX);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(dev,
|
||||
"failed to set volt %lu uV for mem reg\n",
|
||||
new_supply_mem->u_volt);
|
||||
goto restore_freq;
|
||||
}
|
||||
}
|
||||
|
||||
clk_bulk_disable_unprepare(opp_info->num_clks, opp_info->clks);
|
||||
|
||||
return 0;
|
||||
|
||||
restore_freq:
|
||||
if (is_set_clk && clk_set_rate(clk, old_freq))
|
||||
LOG_DEV_ERROR(dev, "failed to restore old-freq %lu Hz\n",
|
||||
old_freq);
|
||||
restore_rm:
|
||||
rockchip_get_read_margin(dev, opp_info, old_supply_vdd->u_volt,
|
||||
&target_rm);
|
||||
rockchip_set_read_margin(dev, opp_info, opp_info->current_rm,
|
||||
is_set_rm);
|
||||
restore_voltage:
|
||||
regulator_set_voltage(mem_reg, old_supply_mem->u_volt, INT_MAX);
|
||||
regulator_set_voltage(vdd_reg, old_supply_vdd->u_volt, INT_MAX);
|
||||
clk_bulk_disable_unprepare(opp_info->num_clks, opp_info->clks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int npu_devfreq_target(struct device *dev, unsigned long *freq,
|
||||
u32 flags)
|
||||
{
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
||||
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);
|
||||
|
||||
ret = dev_pm_opp_set_rate(dev, *freq);
|
||||
if (!ret) {
|
||||
rknpu_dev->current_freq = *freq;
|
||||
if (rknpu_dev->devfreq)
|
||||
rknpu_dev->devfreq->last_status.current_frequency =
|
||||
*freq;
|
||||
rknpu_dev->current_volt = opp_volt;
|
||||
LOG_DEV_DEBUG(dev, "set rknpu freq: %lu, volt: %lu\n",
|
||||
rknpu_dev->current_freq, rknpu_dev->current_volt);
|
||||
}
|
||||
|
||||
rockchip_monitor_volt_adjust_unlock(rknpu_dev->mdev_info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned long npu_get_static_power(struct devfreq *devfreq,
|
||||
unsigned long voltage)
|
||||
{
|
||||
struct device *dev = devfreq->dev.parent;
|
||||
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev);
|
||||
|
||||
if (!rknpu_dev->model_data)
|
||||
return 0;
|
||||
|
||||
return rockchip_ipa_get_static_power(rknpu_dev->model_data, voltage);
|
||||
}
|
||||
|
||||
static struct devfreq_cooling_power npu_cooling_power = {
|
||||
.get_static_power = &npu_get_static_power,
|
||||
};
|
||||
|
||||
int rknpu_devfreq_init(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
struct device *dev = rknpu_dev->dev;
|
||||
struct devfreq_dev_profile *dp = &npu_devfreq_profile;
|
||||
struct dev_pm_opp *opp;
|
||||
struct opp_table *reg_table = NULL;
|
||||
struct opp_table *opp_table = NULL;
|
||||
const char *const reg_names[] = { "rknpu", "mem" };
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (strstr(__clk_get_name(rknpu_dev->clks[0].clk), "scmi"))
|
||||
rknpu_dev->opp_info.scmi_clk = rknpu_dev->clks[0].clk;
|
||||
|
||||
if (of_find_property(dev->of_node, "rknpu-supply", NULL) &&
|
||||
of_find_property(dev->of_node, "mem-supply", NULL)) {
|
||||
reg_table = dev_pm_opp_set_regulators(dev, reg_names, 2);
|
||||
if (IS_ERR(reg_table))
|
||||
return PTR_ERR(reg_table);
|
||||
opp_table =
|
||||
dev_pm_opp_register_set_opp_helper(dev, npu_opp_helper);
|
||||
if (IS_ERR(opp_table)) {
|
||||
dev_pm_opp_put_regulators(reg_table);
|
||||
return PTR_ERR(opp_table);
|
||||
}
|
||||
} else {
|
||||
reg_table = dev_pm_opp_set_regulators(dev, reg_names, 1);
|
||||
if (IS_ERR(reg_table))
|
||||
return PTR_ERR(reg_table);
|
||||
}
|
||||
|
||||
rockchip_get_opp_data(rockchip_npu_of_match, &rknpu_dev->opp_info);
|
||||
ret = rockchip_init_opp_table(dev, &rknpu_dev->opp_info, "npu_leakage",
|
||||
"rknpu");
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(dev, "failed to init_opp_table\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
rknpu_dev->current_freq = clk_get_rate(rknpu_dev->clks[0].clk);
|
||||
|
||||
opp = devfreq_recommended_opp(dev, &rknpu_dev->current_freq, 0);
|
||||
if (IS_ERR(opp)) {
|
||||
ret = PTR_ERR(opp);
|
||||
goto err_remove_table;
|
||||
}
|
||||
dev_pm_opp_put(opp);
|
||||
dp->initial_freq = rknpu_dev->current_freq;
|
||||
|
||||
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");
|
||||
ret = PTR_ERR(rknpu_dev->devfreq);
|
||||
goto err_remove_governor;
|
||||
}
|
||||
|
||||
npu_mdevp.data = rknpu_dev->devfreq;
|
||||
npu_mdevp.opp_info = &rknpu_dev->opp_info;
|
||||
rknpu_dev->mdev_info =
|
||||
rockchip_system_monitor_register(dev, &npu_mdevp);
|
||||
if (IS_ERR(rknpu_dev->mdev_info)) {
|
||||
LOG_DEV_DEBUG(dev, "without system monitor\n");
|
||||
rknpu_dev->mdev_info = NULL;
|
||||
npu_mdevp.is_checked = true;
|
||||
}
|
||||
rknpu_dev->current_freq = clk_get_rate(rknpu_dev->clks[0].clk);
|
||||
rknpu_dev->ondemand_freq = rknpu_dev->current_freq;
|
||||
rknpu_dev->current_volt = regulator_get_voltage(rknpu_dev->vdd);
|
||||
|
||||
rknpu_dev->devfreq->previous_freq = rknpu_dev->current_freq;
|
||||
if (rknpu_dev->devfreq->suspend_freq)
|
||||
rknpu_dev->devfreq->resume_freq = rknpu_dev->current_freq;
|
||||
rknpu_dev->devfreq->last_status.current_frequency =
|
||||
rknpu_dev->current_freq;
|
||||
rknpu_dev->devfreq->last_status.total_time = 1;
|
||||
rknpu_dev->devfreq->last_status.busy_time = 1;
|
||||
|
||||
of_property_read_u32(dev->of_node, "dynamic-power-coefficient",
|
||||
(u32 *)&npu_cooling_power.dyn_power_coeff);
|
||||
rknpu_dev->model_data =
|
||||
rockchip_ipa_power_model_init(dev, "npu_leakage");
|
||||
if (IS_ERR_OR_NULL(rknpu_dev->model_data)) {
|
||||
rknpu_dev->model_data = NULL;
|
||||
LOG_DEV_ERROR(dev, "failed to initialize power model\n");
|
||||
} else if (rknpu_dev->model_data->dynamic_coefficient) {
|
||||
npu_cooling_power.dyn_power_coeff =
|
||||
rknpu_dev->model_data->dynamic_coefficient;
|
||||
}
|
||||
if (!npu_cooling_power.dyn_power_coeff) {
|
||||
LOG_DEV_ERROR(dev, "failed to get dynamic-coefficient\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rknpu_dev->devfreq_cooling = of_devfreq_cooling_register_power(
|
||||
dev->of_node, rknpu_dev->devfreq, &npu_cooling_power);
|
||||
if (IS_ERR_OR_NULL(rknpu_dev->devfreq_cooling))
|
||||
LOG_DEV_ERROR(dev, "failed to register cooling device\n");
|
||||
|
||||
out:
|
||||
return 0;
|
||||
|
||||
err_remove_governor:
|
||||
devfreq_remove_governor(&devfreq_rknpu_ondemand);
|
||||
err_remove_table:
|
||||
rockchip_uninit_opp_table(dev, &rknpu_dev->opp_info);
|
||||
|
||||
rknpu_dev->devfreq = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(rknpu_devfreq_init);
|
||||
|
||||
int rknpu_devfreq_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct rknpu_device *rknpu_dev = dev_get_drvdata(dev);
|
||||
struct rockchip_opp_info *opp_info = &rknpu_dev->opp_info;
|
||||
|
||||
if (opp_info->scmi_clk) {
|
||||
if (clk_set_rate(opp_info->scmi_clk, POWER_DOWN_FREQ))
|
||||
LOG_DEV_ERROR(dev, "failed to restore clk rate\n");
|
||||
}
|
||||
opp_info->current_rm = UINT_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rknpu_devfreq_runtime_suspend);
|
||||
|
||||
int rknpu_devfreq_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_INFO(dev, "failed to enable opp clks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (opp_info->data && opp_info->data->set_read_margin)
|
||||
opp_info->data->set_read_margin(dev, opp_info,
|
||||
opp_info->target_rm);
|
||||
if (opp_info->scmi_clk) {
|
||||
if (clk_set_rate(opp_info->scmi_clk, rknpu_dev->current_freq))
|
||||
LOG_DEV_ERROR(dev, "failed to set power down rate\n");
|
||||
}
|
||||
|
||||
clk_bulk_disable_unprepare(opp_info->num_clks, opp_info->clks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(rknpu_devfreq_runtime_resume);
|
||||
#endif
|
||||
|
||||
void rknpu_devfreq_remove(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
if (rknpu_dev->mdev_info) {
|
||||
rockchip_system_monitor_unregister(rknpu_dev->mdev_info);
|
||||
rknpu_dev->mdev_info = NULL;
|
||||
}
|
||||
if (rknpu_dev->devfreq)
|
||||
devfreq_remove_governor(&devfreq_rknpu_ondemand);
|
||||
rockchip_uninit_opp_table(rknpu_dev->dev, &rknpu_dev->opp_info);
|
||||
}
|
||||
EXPORT_SYMBOL(rknpu_devfreq_remove);
|
||||
1549
rknpu-driver/driver-0.9.6/rknpu_drv.c
Normal file
1549
rknpu-driver/driver-0.9.6/rknpu_drv.c
Normal file
File diff suppressed because it is too large
Load Diff
80
rknpu-driver/driver-0.9.6/rknpu_fence.c
Normal file
80
rknpu-driver/driver-0.9.6/rknpu_fence.c
Normal file
@@ -0,0 +1,80 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/dma-fence.h>
|
||||
#include <linux/sync_file.h>
|
||||
|
||||
#include "rknpu_drv.h"
|
||||
#include "rknpu_job.h"
|
||||
|
||||
#include "rknpu_fence.h"
|
||||
|
||||
static const char *rknpu_fence_get_name(struct dma_fence *fence)
|
||||
{
|
||||
return DRIVER_NAME;
|
||||
}
|
||||
|
||||
static const struct dma_fence_ops rknpu_fence_ops = {
|
||||
.get_driver_name = rknpu_fence_get_name,
|
||||
.get_timeline_name = rknpu_fence_get_name,
|
||||
};
|
||||
|
||||
int rknpu_fence_context_alloc(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
struct rknpu_fence_context *fence_ctx = NULL;
|
||||
|
||||
fence_ctx =
|
||||
devm_kzalloc(rknpu_dev->dev, sizeof(*fence_ctx), GFP_KERNEL);
|
||||
if (!fence_ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
fence_ctx->context = dma_fence_context_alloc(1);
|
||||
spin_lock_init(&fence_ctx->spinlock);
|
||||
|
||||
rknpu_dev->fence_ctx = fence_ctx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rknpu_fence_alloc(struct rknpu_job *job)
|
||||
{
|
||||
struct rknpu_fence_context *fence_ctx = job->rknpu_dev->fence_ctx;
|
||||
struct dma_fence *fence = NULL;
|
||||
|
||||
fence = kzalloc(sizeof(*fence), GFP_KERNEL);
|
||||
if (!fence)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_fence_init(fence, &rknpu_fence_ops, &fence_ctx->spinlock,
|
||||
fence_ctx->context, ++fence_ctx->seqno);
|
||||
|
||||
job->fence = fence;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rknpu_fence_get_fd(struct rknpu_job *job)
|
||||
{
|
||||
struct sync_file *sync_file = NULL;
|
||||
int fence_fd = -1;
|
||||
|
||||
if (!job->fence)
|
||||
return -EINVAL;
|
||||
|
||||
fence_fd = get_unused_fd_flags(O_CLOEXEC);
|
||||
if (fence_fd < 0)
|
||||
return fence_fd;
|
||||
|
||||
sync_file = sync_file_create(job->fence);
|
||||
if (!sync_file)
|
||||
return -ENOMEM;
|
||||
|
||||
fd_install(fence_fd, sync_file->file);
|
||||
|
||||
return fence_fd;
|
||||
}
|
||||
1504
rknpu-driver/driver-0.9.6/rknpu_gem.c
Normal file
1504
rknpu-driver/driver-0.9.6/rknpu_gem.c
Normal file
File diff suppressed because it is too large
Load Diff
254
rknpu-driver/driver-0.9.6/rknpu_iommu.c
Normal file
254
rknpu-driver/driver-0.9.6/rknpu_iommu.c
Normal file
@@ -0,0 +1,254 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include "rknpu_iommu.h"
|
||||
|
||||
dma_addr_t rknpu_iommu_dma_alloc_iova(struct iommu_domain *domain, size_t size,
|
||||
u64 dma_limit, struct device *dev)
|
||||
{
|
||||
struct rknpu_iommu_dma_cookie *cookie = (void *)domain->iova_cookie;
|
||||
struct iova_domain *iovad = &cookie->iovad;
|
||||
unsigned long shift, iova_len, iova = 0;
|
||||
#if (KERNEL_VERSION(5, 4, 0) > LINUX_VERSION_CODE)
|
||||
dma_addr_t limit;
|
||||
#endif
|
||||
|
||||
shift = iova_shift(iovad);
|
||||
iova_len = size >> shift;
|
||||
|
||||
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
|
||||
/*
|
||||
* Freeing non-power-of-two-sized allocations back into the IOVA caches
|
||||
* will come back to bite us badly, so we have to waste a bit of space
|
||||
* rounding up anything cacheable to make sure that can't happen. The
|
||||
* order of the unadjusted size will still match upon freeing.
|
||||
*/
|
||||
if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1)))
|
||||
iova_len = roundup_pow_of_two(iova_len);
|
||||
#endif
|
||||
|
||||
#if (KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE)
|
||||
dma_limit = min_not_zero(dma_limit, dev->bus_dma_limit);
|
||||
#else
|
||||
if (dev->bus_dma_mask)
|
||||
dma_limit &= dev->bus_dma_mask;
|
||||
#endif
|
||||
|
||||
if (domain->geometry.force_aperture)
|
||||
dma_limit =
|
||||
min_t(u64, dma_limit, domain->geometry.aperture_end);
|
||||
|
||||
#if (KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE)
|
||||
iova = alloc_iova_fast(iovad, iova_len, dma_limit >> shift, true);
|
||||
#else
|
||||
limit = min_t(dma_addr_t, dma_limit >> shift, iovad->end_pfn);
|
||||
|
||||
iova = alloc_iova_fast(iovad, iova_len, limit, true);
|
||||
#endif
|
||||
|
||||
return (dma_addr_t)iova << shift;
|
||||
}
|
||||
|
||||
void rknpu_iommu_dma_free_iova(struct rknpu_iommu_dma_cookie *cookie,
|
||||
dma_addr_t iova, size_t size)
|
||||
{
|
||||
struct iova_domain *iovad = &cookie->iovad;
|
||||
|
||||
free_iova_fast(iovad, iova_pfn(iovad, iova), size >> iova_shift(iovad));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IOMMU_API) && defined(CONFIG_NO_GKI)
|
||||
|
||||
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
|
||||
struct iommu_group {
|
||||
struct kobject kobj;
|
||||
struct kobject *devices_kobj;
|
||||
struct list_head devices;
|
||||
#ifdef __ANDROID_COMMON_KERNEL__
|
||||
struct xarray pasid_array;
|
||||
#endif
|
||||
struct mutex mutex;
|
||||
void *iommu_data;
|
||||
void (*iommu_data_release)(void *iommu_data);
|
||||
char *name;
|
||||
int id;
|
||||
struct iommu_domain *default_domain;
|
||||
struct iommu_domain *blocking_domain;
|
||||
struct iommu_domain *domain;
|
||||
struct list_head entry;
|
||||
unsigned int owner_cnt;
|
||||
void *owner;
|
||||
};
|
||||
#else
|
||||
struct iommu_group {
|
||||
struct kobject kobj;
|
||||
struct kobject *devices_kobj;
|
||||
struct list_head devices;
|
||||
struct mutex mutex;
|
||||
struct blocking_notifier_head notifier;
|
||||
void *iommu_data;
|
||||
void (*iommu_data_release)(void *iommu_data);
|
||||
char *name;
|
||||
int id;
|
||||
struct iommu_domain *default_domain;
|
||||
struct iommu_domain *domain;
|
||||
struct list_head entry;
|
||||
};
|
||||
#endif
|
||||
|
||||
int rknpu_iommu_init_domain(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
// init domain 0
|
||||
if (!rknpu_dev->iommu_domains[0]) {
|
||||
rknpu_dev->iommu_domain_id = 0;
|
||||
rknpu_dev->iommu_domains[rknpu_dev->iommu_domain_id] =
|
||||
iommu_get_domain_for_dev(rknpu_dev->dev);
|
||||
rknpu_dev->iommu_domain_num = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rknpu_iommu_switch_domain(struct rknpu_device *rknpu_dev, int domain_id)
|
||||
{
|
||||
struct iommu_domain *src_domain = NULL;
|
||||
struct iommu_domain *dst_domain = NULL;
|
||||
struct bus_type *bus = NULL;
|
||||
int src_domain_id = 0;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!rknpu_dev->iommu_en)
|
||||
return -EINVAL;
|
||||
|
||||
if (domain_id < 0 || domain_id > (RKNPU_MAX_IOMMU_DOMAIN_NUM - 1)) {
|
||||
LOG_DEV_ERROR(
|
||||
rknpu_dev->dev,
|
||||
"invalid iommu domain id: %d, reuse domain id: %d\n",
|
||||
domain_id, rknpu_dev->iommu_domain_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bus = rknpu_dev->dev->bus;
|
||||
if (!bus)
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&rknpu_dev->domain_lock);
|
||||
|
||||
src_domain_id = rknpu_dev->iommu_domain_id;
|
||||
if (domain_id == src_domain_id) {
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
src_domain = iommu_get_domain_for_dev(rknpu_dev->dev);
|
||||
if (src_domain != rknpu_dev->iommu_domains[src_domain_id]) {
|
||||
LOG_DEV_ERROR(
|
||||
rknpu_dev->dev,
|
||||
"mismatch domain get from iommu_get_domain_for_dev\n");
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dst_domain = rknpu_dev->iommu_domains[domain_id];
|
||||
if (dst_domain != NULL) {
|
||||
iommu_detach_device(src_domain, rknpu_dev->dev);
|
||||
ret = iommu_attach_device(dst_domain, rknpu_dev->dev);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(
|
||||
rknpu_dev->dev,
|
||||
"failed to attach dst iommu domain, id: %d, ret: %d\n",
|
||||
domain_id, ret);
|
||||
if (iommu_attach_device(src_domain, rknpu_dev->dev)) {
|
||||
LOG_DEV_ERROR(
|
||||
rknpu_dev->dev,
|
||||
"failed to reattach src iommu domain, id: %d\n",
|
||||
src_domain_id);
|
||||
}
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
return ret;
|
||||
}
|
||||
rknpu_dev->iommu_domain_id = domain_id;
|
||||
} else {
|
||||
uint64_t dma_limit = 1ULL << 32;
|
||||
|
||||
dst_domain = iommu_domain_alloc(bus);
|
||||
if (!dst_domain) {
|
||||
LOG_DEV_ERROR(rknpu_dev->dev,
|
||||
"failed to allocate iommu domain\n");
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
return -EIO;
|
||||
}
|
||||
// init domain iova_cookie
|
||||
iommu_get_dma_cookie(dst_domain);
|
||||
|
||||
iommu_detach_device(src_domain, rknpu_dev->dev);
|
||||
ret = iommu_attach_device(dst_domain, rknpu_dev->dev);
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(
|
||||
rknpu_dev->dev,
|
||||
"failed to attach iommu domain, id: %d, ret: %d\n",
|
||||
domain_id, ret);
|
||||
iommu_domain_free(dst_domain);
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// set domain type to dma domain
|
||||
dst_domain->type |= __IOMMU_DOMAIN_DMA_API;
|
||||
// iommu dma init domain
|
||||
iommu_setup_dma_ops(rknpu_dev->dev, 0, dma_limit);
|
||||
|
||||
rknpu_dev->iommu_domain_id = domain_id;
|
||||
rknpu_dev->iommu_domains[domain_id] = dst_domain;
|
||||
rknpu_dev->iommu_domain_num++;
|
||||
}
|
||||
|
||||
// reset default iommu domain
|
||||
rknpu_dev->iommu_group->default_domain = dst_domain;
|
||||
|
||||
mutex_unlock(&rknpu_dev->domain_lock);
|
||||
|
||||
LOG_INFO("switch iommu domain from %d to %d\n", src_domain_id,
|
||||
domain_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rknpu_iommu_free_domains(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
rknpu_iommu_switch_domain(rknpu_dev, 0);
|
||||
|
||||
for (i = 1; i < RKNPU_MAX_IOMMU_DOMAIN_NUM; i++) {
|
||||
struct iommu_domain *domain = rknpu_dev->iommu_domains[i];
|
||||
|
||||
if (domain == NULL)
|
||||
continue;
|
||||
|
||||
iommu_detach_device(domain, rknpu_dev->dev);
|
||||
iommu_domain_free(domain);
|
||||
|
||||
rknpu_dev->iommu_domains[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int rknpu_iommu_init_domain(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rknpu_iommu_switch_domain(struct rknpu_device *rknpu_dev, int domain_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rknpu_iommu_free_domains(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
1049
rknpu-driver/driver-0.9.6/rknpu_job.c
Normal file
1049
rknpu-driver/driver-0.9.6/rknpu_job.c
Normal file
File diff suppressed because it is too large
Load Diff
353
rknpu-driver/driver-0.9.6/rknpu_mem.c
Normal file
353
rknpu-driver/driver-0.9.6/rknpu_mem.c
Normal file
@@ -0,0 +1,353 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/rk-dma-heap.h>
|
||||
|
||||
#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE
|
||||
#include <linux/dma-map-ops.h>
|
||||
#endif
|
||||
|
||||
#include "rknpu_drv.h"
|
||||
#include "rknpu_ioctl.h"
|
||||
#include "rknpu_mem.h"
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP
|
||||
|
||||
int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, struct file *file,
|
||||
unsigned int cmd, unsigned long data)
|
||||
{
|
||||
struct rknpu_mem_create args;
|
||||
int ret = -EINVAL;
|
||||
struct dma_buf_attachment *attachment;
|
||||
struct sg_table *table;
|
||||
struct scatterlist *sgl;
|
||||
dma_addr_t phys;
|
||||
struct dma_buf *dmabuf;
|
||||
struct page **pages;
|
||||
struct page *page;
|
||||
struct rknpu_mem_object *rknpu_obj = NULL;
|
||||
struct rknpu_session *session = NULL;
|
||||
int i, fd;
|
||||
unsigned int length, page_count;
|
||||
unsigned int in_size = _IOC_SIZE(cmd);
|
||||
unsigned int k_size = sizeof(struct rknpu_mem_create);
|
||||
char *k_data = (char *)&args;
|
||||
|
||||
if (unlikely(copy_from_user(&args, (struct rknpu_mem_create *)data,
|
||||
in_size))) {
|
||||
LOG_ERROR("%s: copy_from_user failed\n", __func__);
|
||||
ret = -EFAULT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (k_size > in_size)
|
||||
memset(k_data + in_size, 0, k_size - in_size);
|
||||
|
||||
if (args.flags & RKNPU_MEM_NON_CONTIGUOUS) {
|
||||
LOG_ERROR("%s: malloc iommu memory unsupported in current!\n",
|
||||
__func__);
|
||||
ret = -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
rknpu_obj = kzalloc(sizeof(*rknpu_obj), GFP_KERNEL);
|
||||
if (!rknpu_obj)
|
||||
return -ENOMEM;
|
||||
|
||||
if (args.handle > 0) {
|
||||
fd = args.handle;
|
||||
|
||||
dmabuf = dma_buf_get(fd);
|
||||
if (IS_ERR(dmabuf)) {
|
||||
ret = PTR_ERR(dmabuf);
|
||||
goto err_free_obj;
|
||||
}
|
||||
|
||||
rknpu_obj->dmabuf = dmabuf;
|
||||
rknpu_obj->owner = 0;
|
||||
} else {
|
||||
/* Start test kernel alloc/free dma buf */
|
||||
dmabuf = rk_dma_heap_buffer_alloc(rknpu_dev->heap, args.size,
|
||||
O_CLOEXEC | O_RDWR, 0x0,
|
||||
dev_name(rknpu_dev->dev));
|
||||
if (IS_ERR(dmabuf)) {
|
||||
LOG_ERROR("dmabuf alloc failed, args.size = %llu\n",
|
||||
args.size);
|
||||
ret = PTR_ERR(dmabuf);
|
||||
goto err_free_obj;
|
||||
}
|
||||
|
||||
rknpu_obj->dmabuf = dmabuf;
|
||||
rknpu_obj->owner = 1;
|
||||
|
||||
fd = dma_buf_fd(dmabuf, O_CLOEXEC | O_RDWR);
|
||||
if (fd < 0) {
|
||||
LOG_ERROR("dmabuf fd get failed\n");
|
||||
ret = -EFAULT;
|
||||
goto err_free_dma_buf;
|
||||
}
|
||||
}
|
||||
|
||||
attachment = dma_buf_attach(dmabuf, rknpu_dev->dev);
|
||||
if (IS_ERR(attachment)) {
|
||||
LOG_ERROR("dma_buf_attach failed\n");
|
||||
ret = PTR_ERR(attachment);
|
||||
goto err_free_dma_buf;
|
||||
}
|
||||
|
||||
table = dma_buf_map_attachment(attachment, DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR(table)) {
|
||||
LOG_ERROR("dma_buf_attach failed\n");
|
||||
dma_buf_detach(dmabuf, attachment);
|
||||
ret = PTR_ERR(table);
|
||||
goto err_free_dma_buf;
|
||||
}
|
||||
|
||||
for_each_sgtable_sg(table, sgl, i) {
|
||||
phys = sg_dma_address(sgl);
|
||||
page = sg_page(sgl);
|
||||
length = sg_dma_len(sgl);
|
||||
LOG_DEBUG("%s, %d, phys: %pad, length: %u\n", __func__,
|
||||
__LINE__, &phys, length);
|
||||
}
|
||||
|
||||
if (args.flags & RKNPU_MEM_KERNEL_MAPPING) {
|
||||
page_count = length >> PAGE_SHIFT;
|
||||
pages = vmalloc(page_count * sizeof(struct page));
|
||||
if (!pages) {
|
||||
LOG_ERROR("alloc pages failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_detach_dma_buf;
|
||||
}
|
||||
|
||||
for (i = 0; i < page_count; i++)
|
||||
pages[i] = &page[i];
|
||||
|
||||
rknpu_obj->kv_addr =
|
||||
vmap(pages, page_count, VM_MAP, PAGE_KERNEL);
|
||||
if (!rknpu_obj->kv_addr) {
|
||||
LOG_ERROR("vmap pages addr failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_pages;
|
||||
}
|
||||
vfree(pages);
|
||||
pages = NULL;
|
||||
}
|
||||
|
||||
rknpu_obj->size = PAGE_ALIGN(args.size);
|
||||
rknpu_obj->dma_addr = phys;
|
||||
rknpu_obj->sgt = table;
|
||||
|
||||
args.size = rknpu_obj->size;
|
||||
args.obj_addr = (__u64)(uintptr_t)rknpu_obj;
|
||||
args.dma_addr = rknpu_obj->dma_addr;
|
||||
args.handle = fd;
|
||||
|
||||
LOG_DEBUG(
|
||||
"args.handle: %d, args.size: %lld, rknpu_obj: %#llx, rknpu_obj->dma_addr: %#llx\n",
|
||||
args.handle, args.size, (__u64)(uintptr_t)rknpu_obj,
|
||||
(__u64)rknpu_obj->dma_addr);
|
||||
|
||||
if (unlikely(copy_to_user((struct rknpu_mem_create *)data, &args,
|
||||
in_size))) {
|
||||
LOG_ERROR("%s: copy_to_user failed\n", __func__);
|
||||
ret = -EFAULT;
|
||||
goto err_unmap_kv_addr;
|
||||
}
|
||||
|
||||
dma_buf_unmap_attachment(attachment, table, DMA_BIDIRECTIONAL);
|
||||
dma_buf_detach(dmabuf, attachment);
|
||||
|
||||
spin_lock(&rknpu_dev->lock);
|
||||
|
||||
session = file->private_data;
|
||||
if (!session) {
|
||||
spin_unlock(&rknpu_dev->lock);
|
||||
ret = -EFAULT;
|
||||
goto err_unmap_kv_addr;
|
||||
}
|
||||
list_add_tail(&rknpu_obj->head, &session->list);
|
||||
|
||||
spin_unlock(&rknpu_dev->lock);
|
||||
|
||||
return 0;
|
||||
|
||||
err_unmap_kv_addr:
|
||||
vunmap(rknpu_obj->kv_addr);
|
||||
rknpu_obj->kv_addr = NULL;
|
||||
|
||||
err_free_pages:
|
||||
vfree(pages);
|
||||
pages = NULL;
|
||||
|
||||
err_detach_dma_buf:
|
||||
dma_buf_unmap_attachment(attachment, table, DMA_BIDIRECTIONAL);
|
||||
dma_buf_detach(dmabuf, attachment);
|
||||
|
||||
err_free_dma_buf:
|
||||
if (rknpu_obj->owner)
|
||||
rk_dma_heap_buffer_free(dmabuf);
|
||||
else
|
||||
dma_buf_put(dmabuf);
|
||||
|
||||
err_free_obj:
|
||||
kfree(rknpu_obj);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rknpu_mem_destroy_ioctl(struct rknpu_device *rknpu_dev, struct file *file,
|
||||
unsigned long data)
|
||||
{
|
||||
struct rknpu_mem_object *rknpu_obj, *entry, *q;
|
||||
struct rknpu_session *session = NULL;
|
||||
struct rknpu_mem_destroy args;
|
||||
int ret = -EFAULT;
|
||||
|
||||
if (unlikely(copy_from_user(&args, (struct rknpu_mem_destroy *)data,
|
||||
sizeof(struct rknpu_mem_destroy)))) {
|
||||
LOG_ERROR("%s: copy_from_user failed\n", __func__);
|
||||
ret = -EFAULT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!kern_addr_valid(args.obj_addr)) {
|
||||
LOG_ERROR("%s: invalid obj_addr: %#llx\n", __func__,
|
||||
(__u64)(uintptr_t)args.obj_addr);
|
||||
ret = -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
rknpu_obj = (struct rknpu_mem_object *)(uintptr_t)args.obj_addr;
|
||||
LOG_DEBUG(
|
||||
"free args.handle: %d, rknpu_obj: %#llx, rknpu_obj->dma_addr: %#llx\n",
|
||||
args.handle, (__u64)(uintptr_t)rknpu_obj,
|
||||
(__u64)rknpu_obj->dma_addr);
|
||||
|
||||
spin_lock(&rknpu_dev->lock);
|
||||
session = file->private_data;
|
||||
if (!session) {
|
||||
spin_unlock(&rknpu_dev->lock);
|
||||
ret = -EFAULT;
|
||||
return ret;
|
||||
}
|
||||
list_for_each_entry_safe(entry, q, &session->list, head) {
|
||||
if (entry == rknpu_obj) {
|
||||
list_del(&entry->head);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&rknpu_dev->lock);
|
||||
|
||||
if (rknpu_obj == entry) {
|
||||
vunmap(rknpu_obj->kv_addr);
|
||||
rknpu_obj->kv_addr = NULL;
|
||||
|
||||
if (!rknpu_obj->owner)
|
||||
dma_buf_put(rknpu_obj->dmabuf);
|
||||
|
||||
kfree(rknpu_obj);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* begin cpu access => for_cpu = true
|
||||
* end cpu access => for_cpu = false
|
||||
*/
|
||||
static void __maybe_unused rknpu_dma_buf_sync(
|
||||
struct rknpu_device *rknpu_dev, struct rknpu_mem_object *rknpu_obj,
|
||||
u32 offset, u32 length, enum dma_data_direction dir, bool for_cpu)
|
||||
{
|
||||
struct device *dev = rknpu_dev->dev;
|
||||
struct sg_table *sgt = rknpu_obj->sgt;
|
||||
struct scatterlist *sg = sgt->sgl;
|
||||
dma_addr_t sg_dma_addr = sg_dma_address(sg);
|
||||
unsigned int len = 0;
|
||||
int i;
|
||||
|
||||
for_each_sgtable_sg(sgt, sg, i) {
|
||||
unsigned int sg_offset, sg_left, size = 0;
|
||||
|
||||
len += sg->length;
|
||||
if (len <= offset) {
|
||||
sg_dma_addr += sg->length;
|
||||
continue;
|
||||
}
|
||||
|
||||
sg_left = len - offset;
|
||||
sg_offset = sg->length - sg_left;
|
||||
|
||||
size = (length < sg_left) ? length : sg_left;
|
||||
|
||||
if (for_cpu)
|
||||
dma_sync_single_range_for_cpu(dev, sg_dma_addr,
|
||||
sg_offset, size, dir);
|
||||
else
|
||||
dma_sync_single_range_for_device(dev, sg_dma_addr,
|
||||
sg_offset, size, dir);
|
||||
|
||||
offset += size;
|
||||
length -= size;
|
||||
sg_dma_addr += sg->length;
|
||||
|
||||
if (length == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int rknpu_mem_sync_ioctl(struct rknpu_device *rknpu_dev, unsigned long data)
|
||||
{
|
||||
struct rknpu_mem_object *rknpu_obj = NULL;
|
||||
struct rknpu_mem_sync args;
|
||||
#ifdef CONFIG_DMABUF_PARTIAL
|
||||
struct dma_buf *dmabuf;
|
||||
#endif
|
||||
int ret = -EFAULT;
|
||||
|
||||
if (unlikely(copy_from_user(&args, (struct rknpu_mem_sync *)data,
|
||||
sizeof(struct rknpu_mem_sync)))) {
|
||||
LOG_ERROR("%s: copy_from_user failed\n", __func__);
|
||||
ret = -EFAULT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!kern_addr_valid(args.obj_addr)) {
|
||||
LOG_ERROR("%s: invalid obj_addr: %#llx\n", __func__,
|
||||
(__u64)(uintptr_t)args.obj_addr);
|
||||
ret = -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
rknpu_obj = (struct rknpu_mem_object *)(uintptr_t)args.obj_addr;
|
||||
|
||||
#ifndef CONFIG_DMABUF_PARTIAL
|
||||
if (args.flags & RKNPU_MEM_SYNC_TO_DEVICE) {
|
||||
rknpu_dma_buf_sync(rknpu_dev, rknpu_obj, args.offset, args.size,
|
||||
DMA_TO_DEVICE, false);
|
||||
}
|
||||
if (args.flags & RKNPU_MEM_SYNC_FROM_DEVICE) {
|
||||
rknpu_dma_buf_sync(rknpu_dev, rknpu_obj, args.offset, args.size,
|
||||
DMA_FROM_DEVICE, true);
|
||||
}
|
||||
#else
|
||||
dmabuf = rknpu_obj->dmabuf;
|
||||
if (args.flags & RKNPU_MEM_SYNC_TO_DEVICE) {
|
||||
dmabuf->ops->end_cpu_access_partial(dmabuf, DMA_TO_DEVICE,
|
||||
args.offset, args.size);
|
||||
}
|
||||
if (args.flags & RKNPU_MEM_SYNC_FROM_DEVICE) {
|
||||
dmabuf->ops->begin_cpu_access_partial(dmabuf, DMA_FROM_DEVICE,
|
||||
args.offset, args.size);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
238
rknpu-driver/driver-0.9.6/rknpu_mm.c
Normal file
238
rknpu-driver/driver-0.9.6/rknpu_mm.c
Normal file
@@ -0,0 +1,238 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include "rknpu_debugger.h"
|
||||
#include "rknpu_mm.h"
|
||||
|
||||
int rknpu_mm_create(unsigned int mem_size, unsigned int chunk_size,
|
||||
struct rknpu_mm **mm)
|
||||
{
|
||||
unsigned int num_of_longs;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (WARN_ON(mem_size < chunk_size))
|
||||
return -EINVAL;
|
||||
if (WARN_ON(mem_size == 0))
|
||||
return -EINVAL;
|
||||
if (WARN_ON(chunk_size == 0))
|
||||
return -EINVAL;
|
||||
|
||||
*mm = kzalloc(sizeof(struct rknpu_mm), GFP_KERNEL);
|
||||
if (!(*mm))
|
||||
return -ENOMEM;
|
||||
|
||||
(*mm)->chunk_size = chunk_size;
|
||||
(*mm)->total_chunks = mem_size / chunk_size;
|
||||
(*mm)->free_chunks = (*mm)->total_chunks;
|
||||
|
||||
num_of_longs =
|
||||
((*mm)->total_chunks + BITS_PER_LONG - 1) / BITS_PER_LONG;
|
||||
|
||||
(*mm)->bitmap = kcalloc(num_of_longs, sizeof(long), GFP_KERNEL);
|
||||
if (!(*mm)->bitmap) {
|
||||
ret = -ENOMEM;
|
||||
goto free_mm;
|
||||
}
|
||||
|
||||
mutex_init(&(*mm)->lock);
|
||||
|
||||
LOG_DEBUG("total_chunks: %d, bitmap: %p\n", (*mm)->total_chunks,
|
||||
(*mm)->bitmap);
|
||||
|
||||
return 0;
|
||||
|
||||
free_mm:
|
||||
kfree(mm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rknpu_mm_destroy(struct rknpu_mm *mm)
|
||||
{
|
||||
if (mm != NULL) {
|
||||
mutex_destroy(&mm->lock);
|
||||
kfree(mm->bitmap);
|
||||
kfree(mm);
|
||||
}
|
||||
}
|
||||
|
||||
int rknpu_mm_alloc(struct rknpu_mm *mm, unsigned int size,
|
||||
struct rknpu_mm_obj **mm_obj)
|
||||
{
|
||||
unsigned int found, start_search, cur_size;
|
||||
|
||||
if (size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (size > mm->total_chunks * mm->chunk_size)
|
||||
return -ENOMEM;
|
||||
|
||||
*mm_obj = kzalloc(sizeof(struct rknpu_mm_obj), GFP_KERNEL);
|
||||
if (!(*mm_obj))
|
||||
return -ENOMEM;
|
||||
|
||||
start_search = 0;
|
||||
|
||||
mutex_lock(&mm->lock);
|
||||
|
||||
mm_restart_search:
|
||||
/* Find the first chunk that is free */
|
||||
found = find_next_zero_bit(mm->bitmap, mm->total_chunks, start_search);
|
||||
|
||||
/* If there wasn't any free chunk, bail out */
|
||||
if (found == mm->total_chunks)
|
||||
goto mm_no_free_chunk;
|
||||
|
||||
/* Update fields of mm_obj */
|
||||
(*mm_obj)->range_start = found;
|
||||
(*mm_obj)->range_end = found;
|
||||
|
||||
/* If we need only one chunk, mark it as allocated and get out */
|
||||
if (size <= mm->chunk_size) {
|
||||
set_bit(found, mm->bitmap);
|
||||
goto mm_out;
|
||||
}
|
||||
|
||||
/* Otherwise, try to see if we have enough contiguous chunks */
|
||||
cur_size = size - mm->chunk_size;
|
||||
do {
|
||||
(*mm_obj)->range_end = find_next_zero_bit(
|
||||
mm->bitmap, mm->total_chunks, ++found);
|
||||
/*
|
||||
* If next free chunk is not contiguous than we need to
|
||||
* restart our search from the last free chunk we found (which
|
||||
* wasn't contiguous to the previous ones
|
||||
*/
|
||||
if ((*mm_obj)->range_end != found) {
|
||||
start_search = found;
|
||||
goto mm_restart_search;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we reached end of buffer, bail out with error
|
||||
*/
|
||||
if (found == mm->total_chunks)
|
||||
goto mm_no_free_chunk;
|
||||
|
||||
/* Check if we don't need another chunk */
|
||||
if (cur_size <= mm->chunk_size)
|
||||
cur_size = 0;
|
||||
else
|
||||
cur_size -= mm->chunk_size;
|
||||
|
||||
} while (cur_size > 0);
|
||||
|
||||
/* Mark the chunks as allocated */
|
||||
for (found = (*mm_obj)->range_start; found <= (*mm_obj)->range_end;
|
||||
found++)
|
||||
set_bit(found, mm->bitmap);
|
||||
|
||||
mm_out:
|
||||
mm->free_chunks -= ((*mm_obj)->range_end - (*mm_obj)->range_start + 1);
|
||||
mutex_unlock(&mm->lock);
|
||||
|
||||
LOG_DEBUG("mm allocate, mm_obj: %p, range_start: %d, range_end: %d\n",
|
||||
*mm_obj, (*mm_obj)->range_start, (*mm_obj)->range_end);
|
||||
|
||||
return 0;
|
||||
|
||||
mm_no_free_chunk:
|
||||
mutex_unlock(&mm->lock);
|
||||
kfree(*mm_obj);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int rknpu_mm_free(struct rknpu_mm *mm, struct rknpu_mm_obj *mm_obj)
|
||||
{
|
||||
unsigned int bit;
|
||||
|
||||
/* Act like kfree when trying to free a NULL object */
|
||||
if (!mm_obj)
|
||||
return 0;
|
||||
|
||||
LOG_DEBUG("mm free, mem_obj: %p, range_start: %d, range_end: %d\n",
|
||||
mm_obj, mm_obj->range_start, mm_obj->range_end);
|
||||
|
||||
mutex_lock(&mm->lock);
|
||||
|
||||
/* Mark the chunks as free */
|
||||
for (bit = mm_obj->range_start; bit <= mm_obj->range_end; bit++)
|
||||
clear_bit(bit, mm->bitmap);
|
||||
|
||||
mm->free_chunks += (mm_obj->range_end - mm_obj->range_start + 1);
|
||||
|
||||
mutex_unlock(&mm->lock);
|
||||
|
||||
kfree(mm_obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rknpu_mm_dump(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);
|
||||
struct rknpu_mm *mm = NULL;
|
||||
int cur = 0, rbot = 0, rtop = 0;
|
||||
size_t ret = 0;
|
||||
char buf[64];
|
||||
size_t size = sizeof(buf);
|
||||
int seg_chunks = 32, seg_id = 0;
|
||||
int free_size = 0;
|
||||
int i = 0;
|
||||
|
||||
mm = rknpu_dev->sram_mm;
|
||||
if (mm == NULL)
|
||||
return 0;
|
||||
|
||||
seq_printf(m, "SRAM bitmap: \"*\" - used, \".\" - free (1bit = %dKB)\n",
|
||||
mm->chunk_size / 1024);
|
||||
|
||||
rbot = cur = find_first_bit(mm->bitmap, mm->total_chunks);
|
||||
for (i = 0; i < cur; ++i) {
|
||||
ret += scnprintf(buf + ret, size - ret, ".");
|
||||
if (ret >= seg_chunks) {
|
||||
seq_printf(m, "[%03d] [%s]\n", seg_id++, buf);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
while (cur < mm->total_chunks) {
|
||||
rtop = cur;
|
||||
cur = find_next_bit(mm->bitmap, mm->total_chunks, cur + 1);
|
||||
if (cur < mm->total_chunks && cur <= rtop + 1)
|
||||
continue;
|
||||
|
||||
for (i = rbot; i <= rtop; ++i) {
|
||||
ret += scnprintf(buf + ret, size - ret, "*");
|
||||
if (ret >= seg_chunks) {
|
||||
seq_printf(m, "[%03d] [%s]\n", seg_id++, buf);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = rtop + 1; i < cur; ++i) {
|
||||
ret += scnprintf(buf + ret, size - ret, ".");
|
||||
if (ret >= seg_chunks) {
|
||||
seq_printf(m, "[%03d] [%s]\n", seg_id++, buf);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
rbot = cur;
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
seq_printf(m, "[%03d] [%s]\n", seg_id++, buf);
|
||||
|
||||
free_size = mm->free_chunks * mm->chunk_size;
|
||||
seq_printf(m, "SRAM total size: %d, used: %d, free: %d\n",
|
||||
rknpu_dev->sram_size, rknpu_dev->sram_size - free_size,
|
||||
free_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
155
rknpu-driver/driver-0.9.6/rknpu_reset.c
Normal file
155
rknpu-driver/driver-0.9.6/rknpu_reset.c
Normal file
@@ -0,0 +1,155 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co.Ltd
|
||||
* Author: Felix Zeng <felix.zeng@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iommu.h>
|
||||
|
||||
#include "rknpu_reset.h"
|
||||
|
||||
#ifndef FPGA_PLATFORM
|
||||
static inline struct reset_control *rknpu_reset_control_get(struct device *dev,
|
||||
const char *name)
|
||||
{
|
||||
struct reset_control *rst = NULL;
|
||||
|
||||
rst = devm_reset_control_get(dev, name);
|
||||
if (IS_ERR(rst))
|
||||
LOG_DEV_ERROR(dev,
|
||||
"failed to get rknpu reset control: %s, %ld\n",
|
||||
name, PTR_ERR(rst));
|
||||
|
||||
return rst;
|
||||
}
|
||||
#endif
|
||||
|
||||
int rknpu_reset_get(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
#ifndef FPGA_PLATFORM
|
||||
int i = 0;
|
||||
int num_srsts = 0;
|
||||
|
||||
num_srsts = of_count_phandle_with_args(rknpu_dev->dev->of_node,
|
||||
"resets", "#reset-cells");
|
||||
if (num_srsts <= 0) {
|
||||
LOG_DEV_ERROR(rknpu_dev->dev,
|
||||
"failed to get rknpu resets from dtb\n");
|
||||
return num_srsts;
|
||||
}
|
||||
|
||||
rknpu_dev->srsts = devm_kcalloc(rknpu_dev->dev, num_srsts,
|
||||
sizeof(*rknpu_dev->srsts), GFP_KERNEL);
|
||||
if (!rknpu_dev->srsts)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num_srsts; ++i) {
|
||||
rknpu_dev->srsts[i] = devm_reset_control_get_exclusive_by_index(
|
||||
rknpu_dev->dev, i);
|
||||
if (IS_ERR(rknpu_dev->srsts[i])) {
|
||||
rknpu_dev->num_srsts = i;
|
||||
return PTR_ERR(rknpu_dev->srsts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
rknpu_dev->num_srsts = num_srsts;
|
||||
|
||||
return num_srsts;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef FPGA_PLATFORM
|
||||
static int rknpu_reset_assert(struct reset_control *rst)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!rst)
|
||||
return -EINVAL;
|
||||
|
||||
ret = reset_control_assert(rst);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("failed to assert rknpu reset: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rknpu_reset_deassert(struct reset_control *rst)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!rst)
|
||||
return -EINVAL;
|
||||
|
||||
ret = reset_control_deassert(rst);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("failed to deassert rknpu reset: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int rknpu_soft_reset(struct rknpu_device *rknpu_dev)
|
||||
{
|
||||
#ifndef FPGA_PLATFORM
|
||||
struct iommu_domain *domain = NULL;
|
||||
struct rknpu_subcore_data *subcore_data = NULL;
|
||||
int ret = 0, i = 0;
|
||||
|
||||
if (rknpu_dev->bypass_soft_reset) {
|
||||
LOG_WARN("bypass soft reset\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!mutex_trylock(&rknpu_dev->reset_lock))
|
||||
return 0;
|
||||
|
||||
rknpu_dev->soft_reseting = true;
|
||||
|
||||
msleep(100);
|
||||
|
||||
for (i = 0; i < rknpu_dev->config->num_irqs; ++i) {
|
||||
subcore_data = &rknpu_dev->subcore_datas[i];
|
||||
wake_up(&subcore_data->job_done_wq);
|
||||
}
|
||||
|
||||
LOG_INFO("soft reset, num: %d\n", rknpu_dev->num_srsts);
|
||||
|
||||
for (i = 0; i < rknpu_dev->num_srsts; ++i)
|
||||
ret |= rknpu_reset_assert(rknpu_dev->srsts[i]);
|
||||
|
||||
udelay(10);
|
||||
|
||||
for (i = 0; i < rknpu_dev->num_srsts; ++i)
|
||||
ret |= rknpu_reset_deassert(rknpu_dev->srsts[i]);
|
||||
|
||||
udelay(10);
|
||||
|
||||
if (ret) {
|
||||
LOG_DEV_ERROR(rknpu_dev->dev,
|
||||
"failed to soft reset for rknpu: %d\n", ret);
|
||||
mutex_unlock(&rknpu_dev->reset_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (rknpu_dev->iommu_en)
|
||||
domain = iommu_get_domain_for_dev(rknpu_dev->dev);
|
||||
|
||||
if (domain) {
|
||||
iommu_detach_device(domain, rknpu_dev->dev);
|
||||
iommu_attach_device(domain, rknpu_dev->dev);
|
||||
}
|
||||
|
||||
rknpu_dev->soft_reseting = false;
|
||||
|
||||
mutex_unlock(&rknpu_dev->reset_lock);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user