Fixed ulimits and changed build permissions

Removed unneeded files
This commit is contained in:
Pelochus
2024-04-14 20:32:28 +00:00
parent a0d0490f61
commit 16aece7c01
25 changed files with 0 additions and 7940 deletions

View File

@@ -1,132 +0,0 @@
// Copyright (c) 2024 by Rockchip Electronics Co., Ltd. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Modified by Pelochus
#include <string.h>
#include <unistd.h>
#include <string>
#include "rkllm.h"
#include <fstream>
#include <iostream>
#include <csignal>
#include <vector>
#define PROMPT_TEXT_PREFIX "<|im_start|>system You are a helpful assistant. <|im_end|> <|im_start|>user"
#define PROMPT_TEXT_POSTFIX "<|im_end|><|im_start|>assistant"
using namespace std;
LLMHandle llmHandle = nullptr;
void exit_handler(int signal)
{
if (llmHandle != nullptr)
{
cout << "Catched exit signal. Exiting..." << endl;
LLMHandle _tmp = llmHandle;
llmHandle = nullptr;
rkllm_destroy(_tmp);
exit(signal);
}
}
void callback(const char *text, void *userdata, LLMCallState state)
{
if (state == LLM_RUN_FINISH)
{
printf("\n");
}
else if (state == LLM_RUN_ERROR)
{
printf("\\LLM run error\n");
}
else
{
printf("%s", text);
}
}
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: %s [rkllm_model_path]\n", argv[0]);
return -1;
}
signal(SIGINT, exit_handler);
string rkllm_model(argv[1]);
printf("RKLLM starting, please wait...\n");
RKLLMParam param = rkllm_createDefaultParam();
param.modelPath = rkllm_model.c_str();
param.target_platform = "rk3588";
param.num_npu_core = 2;
param.top_k = 1;
param.max_new_tokens = 256;
param.max_context_len = 512;
rkllm_init(&llmHandle, param, callback);
printf("RKLLM init success!\n");
vector<string> pre_input;
pre_input.push_back("Welcome to ezrkllm! This is an adaptation of Rockchip's rknn-llm repo (see github.com/airockchip/rknn-llm) for running LLMs on its SoCs' NPUs.\n");
pre_input.push_back("You are currently running the runtime for ");
pre_input.push_back(param.target_platform);
pre_input.push_back("\nTo exit the model, enter either exit or quit\n");
pre_input.push_back("\nMore information here: https://github.com/Pelochus/ezrknpu");
pre_input.push_back("\nDetailed information for devs here: https://github.com/Pelochus/ezrknn-llm");
cout << "\n*************************** Pelochus' ezrkllm runtime *************************\n" << endl;
for (int i = 0; i < (int)pre_input.size(); i++)
{
cout << pre_input[i];
}
cout << "\n*******************************************************************************\n" << endl;
string text;
while (true)
{
std::string input_str;
printf("\n");
printf("You: ");
std::getline(std::cin, input_str);
if (input_str == "exit" || input_str == "quit")
{
cout << "Quitting program..." << endl;
break;
}
for (int i = 0; i < (int)pre_input.size(); i++)
{
if (input_str == to_string(i))
{
input_str = pre_input[i];
cout << input_str << endl;
}
}
string text = PROMPT_TEXT_PREFIX + input_str + PROMPT_TEXT_POSTFIX;
printf("LLM: ");
rkllm_run(llmHandle, text.c_str(), NULL);
}
rkllm_destroy(llmHandle);
return 0;
}

View File

@@ -1,60 +0,0 @@
# 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

View File

@@ -1,17 +0,0 @@
# 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

View File

@@ -1,88 +0,0 @@
/* 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_ */

View File

@@ -1,46 +0,0 @@
/* 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_ */

View File

@@ -1,183 +0,0 @@
/* 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_ */

View File

@@ -1,24 +0,0 @@
/* 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_ */

View File

@@ -1,215 +0,0 @@
/* 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

View File

@@ -1,327 +0,0 @@
/* 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

View File

@@ -1,48 +0,0 @@
/* 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

View File

@@ -1,81 +0,0 @@
/* 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_ */

View File

@@ -1,46 +0,0 @@
/* 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

View File

@@ -1,42 +0,0 @@
/* 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

View File

@@ -1,18 +0,0 @@
/* 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

View File

@@ -1,31 +0,0 @@
#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");

View File

@@ -1,605 +0,0 @@
// 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;
}

View File

@@ -1,795 +0,0 @@
// 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);

File diff suppressed because it is too large Load Diff

View File

@@ -1,80 +0,0 @@
// 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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,254 +0,0 @@
// 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

File diff suppressed because it is too large Load Diff

View File

@@ -1,353 +0,0 @@
// 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

View File

@@ -1,238 +0,0 @@
// 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;
}

View File

@@ -1,155 +0,0 @@
// 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;
}