media: rockchip: add aiisp driver

Signed-off-by: Hu Kejun <william.hu@rock-chips.com>
Change-Id: I11459fd2862411528c1fce4eb6fdd174c42325d8
This commit is contained in:
Hu Kejun
2024-12-18 09:31:18 +08:00
committed by Tao Huang
parent 39d1fb94fa
commit d7466155ba
12 changed files with 2937 additions and 0 deletions

View File

@@ -2,6 +2,7 @@
comment "Rockchip media platform drivers"
source "drivers/media/platform/rockchip/aiisp/Kconfig"
source "drivers/media/platform/rockchip/cif/Kconfig"
source "drivers/media/platform/rockchip/fec/Kconfig"
source "drivers/media/platform/rockchip/flexbus_cif/Kconfig"

View File

@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-y += aiisp/
obj-y += cif/
obj-y += fec/
obj-y += flexbus_cif/

View File

@@ -0,0 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
config VIDEO_ROCKCHIP_AIISP
tristate "Rockchip AIISP driver"
depends on V4L_PLATFORM_DRIVERS
depends on VIDEO_DEV
depends on ARCH_ROCKCHIP || COMPILE_TEST
select VIDEOBUF2_CMA_SG
select V4L2_FWNODE
default n
help
Support for AIISP on the rockchip SoC.

View File

@@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_VIDEO_ROCKCHIP_AIISP) += video_rkaiisp.o
video_rkaiisp-objs += hw.o dev.o aiisp.o

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,179 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2025 Rockchip Electronics Co., Ltd. */
#ifndef _RKAIISP_DEV_H
#define _RKAIISP_DEV_H
#include <linux/clk.h>
#include <linux/media.h>
#include <linux/mutex.h>
#include <linux/rk-video-format.h>
#include <linux/rk-aiisp-config.h>
#include <linux/slab.h>
#include <linux/kfifo.h>
#include <media/media-device.h>
#include <media/media-entity.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mc.h>
#include <media/videobuf2-dma-sg.h>
#include <media/videobuf2-v4l2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-core.h>
#include <media/v4l2-event.h>
#include "hw.h"
#define DRIVER_NAME "rkaiisp"
#define RKAIISP_SUBDEV_NAME DRIVER_NAME "-subdev"
#define RKAIISP_V4L2_EVENT_ELEMS 4
#define RKAIISP_MAX_CHANNEL 7
#define RKAIISP_TMP_BUF_CNT 2
#define RKAIISP_DEFAULT_MAXRUNCNT 8
#define RKAIISP_DEFAULT_PARASIZE (16 * 1024)
#define RKAIISP_SW_REG_SIZE 0x3000
#define RKAIISP_SW_MAX_SIZE (RKAIISP_SW_REG_SIZE * 2)
enum rkaiisp_irqhdl_ret {
NOT_WREND = (0 << 0),
CONTINUE_RUN = (1 << 0),
RUN_COMPLETE = (2 << 0)
};
enum rkaiisp_hwstate {
HW_STOP,
HW_RUNNING
};
struct rkaiisp_vdev_node {
struct vb2_queue buf_queue;
struct video_device vdev;
struct media_pad pad;
};
struct rkaiisp_buffer {
struct vb2_v4l2_buffer vb;
struct list_head queue;
u32 buff_addr[VIDEO_MAX_PLANES];
void *vaddr[VIDEO_MAX_PLANES];
};
struct rkaiisp_dummy_buffer {
struct vb2_buffer vb;
struct vb2_queue vb2_queue;
s32 dma_fd;
struct dma_buf *dmabuf;
struct dma_buf_attachment *dba;
struct sg_table *sgt;
dma_addr_t dma_addr;
void *vaddr;
u32 size;
void *mem_priv;
};
struct rkaiisp_buffer_size {
u32 height;
u32 width;
u32 channel;
u32 stride;
};
struct rkaiiisp_subdev {
struct v4l2_subdev sd;
bool is_subs_evt;
};
struct rkaiisp_device {
char name[128];
void *sw_base_addr;
struct v4l2_device v4l2_dev;
struct media_device media_dev;
struct device *dev;
const struct vb2_mem_ops *mem_ops;
spinlock_t config_lock;
struct mutex apilock;
wait_queue_head_t sync_onoff;
struct rkaiisp_hw_dev *hw_dev;
bool is_hw_link;
int dev_id;
struct rkaiiisp_subdev subdev;
struct rkaiisp_ispbuf_info ispbuf;
struct rkaiisp_dummy_buffer iirbuf[RKISP_BUFFER_MAX];
struct rkaiisp_dummy_buffer aiprebuf[RKISP_BUFFER_MAX];
struct rkaiisp_dummy_buffer vpslbuf[RKISP_BUFFER_MAX];
struct rkaiisp_dummy_buffer aiispbuf[RKISP_BUFFER_MAX];
struct rkaiisp_dummy_buffer temp_buf[RKAIISP_TMP_BUF_CNT];
u32 outbuf_idx;
struct kfifo idxbuf_kfifo;
struct rkisp_aiisp_st curr_idxbuf;
struct rkaiisp_vdev_node vnode;
struct list_head params;
struct rkaiisp_buffer *cur_params;
struct v4l2_format vdev_fmt;
struct rkaiisp_buffer_size outbuf_size[RKAIISP_MAX_RUNCNT];
struct rkaiisp_buffer_size chn_size[RKAIISP_MAX_CHANNEL];
enum rkaiisp_exemode exemode;
enum rkaiisp_model_mode model_mode;
enum rkaiisp_hwstate hwstate;
u32 para_size;
u32 max_runcnt;
u32 model_runcnt;
u32 run_idx;
u32 frame_id;
bool streamon;
bool showreg;
};
extern int rkaiisp_debug;
extern int rkaiisp_showreg;
static inline struct rkaiisp_buffer *to_rkaiisp_buffer(struct vb2_v4l2_buffer *vb)
{
return container_of(vb, struct rkaiisp_buffer, vb);
}
static inline void rkaiisp_write(struct rkaiisp_device *aidev, u32 reg, u32 val, bool is_direct)
{
u32 *mem = aidev->sw_base_addr + reg;
u32 *flag = aidev->sw_base_addr + reg + RKAIISP_SW_REG_SIZE;
*mem = val;
*flag = SW_REG_CACHE;
if (aidev->hw_dev->is_single || is_direct) {
*flag = SW_REG_CACHE_SYNC;
writel(val, aidev->hw_dev->base_addr + reg);
}
}
static inline u32 rkaiisp_read(struct rkaiisp_device *aidev, u32 reg, bool is_direct)
{
u32 val;
if (aidev->hw_dev->is_single || is_direct)
val = readl(aidev->hw_dev->base_addr + reg);
else
val = *(u32 *)(aidev->sw_base_addr + reg);
return val;
}
extern struct platform_driver rkaiisp_plat_drv;
int rkaiisp_queue_ispbuf(struct rkaiisp_device *aidev, struct rkisp_aiisp_st *idxbuf);
void rkaiisp_update_list_reg(struct rkaiisp_device *aidev);
void rkaiisp_trigger(struct rkaiisp_device *aidev);
int rkaiisp_get_idxbuf_len(struct rkaiisp_device *aidev);
enum rkaiisp_irqhdl_ret rkaiisp_irq_hdl(struct rkaiisp_device *aidev, u32 mi_mis);
int rkaiisp_register_vdev(struct rkaiisp_device *aidev, struct v4l2_device *v4l2_dev);
void rkaiisp_unregister_vdev(struct rkaiisp_device *aidev);
#endif

View File

@@ -0,0 +1,236 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2025 Rockchip Electronics Co., Ltd. */
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/of_reserved_mem.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
#include <linux/regmap.h>
#include <linux/nospec.h>
#include "regs.h"
#include "hw.h"
#include "aiisp.h"
#include "version.h"
#define RKAIISP_VERNO_LEN 10
int rkaiisp_debug;
module_param_named(debug, rkaiisp_debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
int rkaiisp_showreg;
module_param_named(showreg, rkaiisp_showreg, int, 0644);
MODULE_PARM_DESC(showreg, "show register (0-1)");
static char rkaiisp_version[RKAIISP_VERNO_LEN];
module_param_string(version, rkaiisp_version, RKAIISP_VERNO_LEN, 0444);
MODULE_PARM_DESC(version, "version number");
/***************************** platform deive *******************************/
static int rkaiisp_attach_hw(struct rkaiisp_device *aidev)
{
struct device_node *np;
struct platform_device *pdev;
struct rkaiisp_hw_dev *hw_dev;
const char *name;
int ret, dev_id = -1;
of_property_read_string(aidev->dev->of_node, "name", &name);
if (name) {
ret = sscanf(name, "rkaiisp-vir%d", &dev_id);
if ((dev_id >= RKAIISP_DEV_MAX) || ret != 1) {
dev_err(aidev->dev, "dev_id %d, failed attach aidev hw, max dev:%d\n",
dev_id, RKAIISP_DEV_MAX);
return -EINVAL;
}
}
np = of_parse_phandle(aidev->dev->of_node, "rockchip,hw", 0);
if (!np || !of_device_is_available(np)) {
dev_err(aidev->dev, "failed to get isp hw node\n");
return -ENODEV;
}
pdev = of_find_device_by_node(np);
of_node_put(np);
if (!pdev) {
dev_err(aidev->dev, "failed to get aidev hw from node\n");
return -ENODEV;
}
hw_dev = platform_get_drvdata(pdev);
if (!hw_dev) {
dev_err(aidev->dev, "failed attach aidev hw\n");
return -EINVAL;
}
mutex_lock(&hw_dev->dev_mutex);
if (hw_dev->dev_num >= RKAIISP_DEV_MAX) {
dev_err(aidev->dev, "failed attach aidev hw, max dev:%d\n", RKAIISP_DEV_MAX);
mutex_unlock(&hw_dev->dev_mutex);
return -EINVAL;
}
if (dev_id == -1)
dev_id = hw_dev->dev_num;
if (dev_id >= 0 && dev_id < RKAIISP_DEV_MAX) {
dev_id = array_index_nospec(dev_id, RKAIISP_DEV_MAX);
dev_info(aidev->dev, "dev_id %d\n", dev_id);
aidev->dev_id = dev_id;
hw_dev->aidev[dev_id] = aidev;
hw_dev->dev_num++;
aidev->hw_dev = hw_dev;
aidev->is_hw_link = true;
}
hw_dev->is_single = (hw_dev->dev_num > 1) ? false : true;
mutex_unlock(&hw_dev->dev_mutex);
return 0;
}
static int rkaiisp_plat_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct v4l2_device *v4l2_dev;
struct rkaiisp_device *aidev;
int ret;
snprintf(rkaiisp_version, sizeof(rkaiisp_version),
"v%02x.%02x.%02x",
RKAIISP_DRIVER_VERSION >> 16,
(RKAIISP_DRIVER_VERSION & 0xff00) >> 8,
RKAIISP_DRIVER_VERSION & 0x00ff);
dev_info(dev, "rkaiisp driver version: %s\n", rkaiisp_version);
aidev = devm_kzalloc(dev, sizeof(*aidev), GFP_KERNEL);
if (!aidev)
return -ENOMEM;
dev_set_drvdata(dev, aidev);
aidev->dev = dev;
ret = rkaiisp_attach_hw(aidev);
if (ret)
return ret;
aidev->sw_base_addr = devm_kzalloc(dev, RKAIISP_SW_MAX_SIZE, GFP_KERNEL);
if (!aidev->sw_base_addr)
return -ENOMEM;
snprintf(aidev->media_dev.model, sizeof(aidev->media_dev.model),
"%s%d", DRIVER_NAME, aidev->dev_id);
strscpy(aidev->name, dev_name(dev), sizeof(aidev->name));
strscpy(aidev->media_dev.driver_name, aidev->name,
sizeof(aidev->media_dev.driver_name));
mutex_init(&aidev->apilock);
aidev->media_dev.dev = dev;
v4l2_dev = &aidev->v4l2_dev;
v4l2_dev->mdev = &aidev->media_dev;
strscpy(v4l2_dev->name, aidev->name, sizeof(v4l2_dev->name));
ret = v4l2_device_register(aidev->dev, &aidev->v4l2_dev);
if (ret < 0) {
v4l2_err(v4l2_dev, "Failed to register v4l2 device:%d\n", ret);
return ret;
}
media_device_init(&aidev->media_dev);
ret = media_device_register(&aidev->media_dev);
if (ret < 0) {
v4l2_err(v4l2_dev, "Failed to register media device:%d\n", ret);
goto err_unreg_v4l2_dev;
}
pm_runtime_enable(dev);
ret = rkaiisp_register_vdev(aidev, &aidev->v4l2_dev);
if (ret < 0) {
v4l2_err(v4l2_dev, "Failed to register platform subdevs:%d\n", ret);
goto err_unreg_media_dev;
}
v4l2_info(v4l2_dev, "probe end.\n");
return 0;
err_unreg_media_dev:
media_device_unregister(&aidev->media_dev);
err_unreg_v4l2_dev:
v4l2_device_unregister(&aidev->v4l2_dev);
return ret;
}
static int rkaiisp_plat_remove(struct platform_device *pdev)
{
struct rkaiisp_device *aidev = platform_get_drvdata(pdev);
aidev->is_hw_link = false;
aidev->hw_dev->aidev[aidev->dev_id] = NULL;
pm_runtime_disable(&pdev->dev);
media_device_unregister(&aidev->media_dev);
v4l2_device_unregister(&aidev->v4l2_dev);
rkaiisp_unregister_vdev(aidev);
media_device_cleanup(&aidev->media_dev);
return 0;
}
static int __maybe_unused rkaiisp_runtime_suspend(struct device *dev)
{
struct rkaiisp_device *aidev = dev_get_drvdata(dev);
int ret;
mutex_lock(&aidev->hw_dev->dev_mutex);
ret = pm_runtime_put_sync(aidev->hw_dev->dev);
mutex_unlock(&aidev->hw_dev->dev_mutex);
return (ret > 0) ? 0 : ret;
}
static int __maybe_unused rkaiisp_runtime_resume(struct device *dev)
{
struct rkaiisp_device *aidev = dev_get_drvdata(dev);
int ret;
mutex_lock(&aidev->hw_dev->dev_mutex);
ret = pm_runtime_get_sync(aidev->hw_dev->dev);
mutex_unlock(&aidev->hw_dev->dev_mutex);
return (ret > 0) ? 0 : ret;
}
static const struct dev_pm_ops rkaiisp_plat_pm_ops = {
SET_RUNTIME_PM_OPS(rkaiisp_runtime_suspend, rkaiisp_runtime_resume, NULL)
};
static const struct of_device_id rkaiisp_plat_of_match[] = {
{
.compatible = "rockchip,rkaiisp-vir",
},
{},
};
struct platform_driver rkaiisp_plat_drv = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(rkaiisp_plat_of_match),
.pm = &rkaiisp_plat_pm_ops,
},
.probe = rkaiisp_plat_probe,
.remove = rkaiisp_plat_remove,
};
MODULE_AUTHOR("Rockchip Camera/ISP team");
MODULE_DESCRIPTION("Rockchip ISP platform driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_IMPORT_NS(DMA_BUF);
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);

View File

@@ -0,0 +1,446 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2025 Rockchip Electronics Co., Ltd. */
#define pr_fmt(fmt) "rkaiisp: %s:%d " fmt, __func__, __LINE__
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iommu.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/of_reserved_mem.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <media/videobuf2-cma-sg.h>
#include <media/videobuf2-dma-sg.h>
#include <soc/rockchip/rockchip_iommu.h>
#include "regs.h"
#include "hw.h"
#include "aiisp.h"
static struct rkaiisp_hw_dev *rkaiisp_hwdev;
/*
* rkaiisp_hw share hardware resource with rkaiisp virtual device
* rkaiisp_device rkaiisp_device rkaiisp_device rkaiisp_device
* | | | |
* \ | | /
* --------------------------------------
* |
* rkaiisp_hw
*/
static irqreturn_t hw_irq_hdl(int irq, void *ctx)
{
struct device *dev = ctx;
struct rkaiisp_hw_dev *hw_dev = dev_get_drvdata(dev);
struct rkaiisp_device *aidev = hw_dev->aidev[hw_dev->cur_dev_id];
void __iomem *base = hw_dev->base_addr;
int i, max = 0, id = 0;
int len[RKAIISP_DEV_MAX] = { 0 };
enum rkaiisp_irqhdl_ret irq_hdl_ret;
u32 mis_val;
mis_val = readl(base + AIISP_MI_MIS);
if (mis_val) {
irq_hdl_ret = rkaiisp_irq_hdl(aidev, mis_val);
if (irq_hdl_ret == RUN_COMPLETE) {
spin_lock(&hw_dev->hw_lock);
for (i = 0; i < RKAIISP_DEV_MAX; i++) {
aidev = hw_dev->aidev[i];
if (!aidev)
continue;
if (!aidev->streamon)
continue;
len[i] = rkaiisp_get_idxbuf_len(aidev);
if (max < len[i]) {
max = len[i];
id = i;
}
}
spin_unlock(&hw_dev->hw_lock);
if (max > 0) {
spin_lock(&hw_dev->hw_lock);
hw_dev->is_idle = false;
hw_dev->cur_dev_id = id;
aidev = hw_dev->aidev[hw_dev->cur_dev_id];
spin_unlock(&hw_dev->hw_lock);
v4l2_dbg(1, rkaiisp_debug, &aidev->v4l2_dev,
"trigger aidev: %d, idxbuf len: %d\n",
hw_dev->cur_dev_id, max);
rkaiisp_trigger(aidev);
} else {
spin_lock(&hw_dev->hw_lock);
hw_dev->is_idle = true;
spin_unlock(&hw_dev->hw_lock);
}
}
}
return IRQ_HANDLED;
}
static int rkaiisp_register_irq(struct rkaiisp_hw_dev *hw_dev)
{
const struct aiisp_match_data *match_data = hw_dev->match_data;
struct platform_device *pdev = hw_dev->pdev;
struct device *dev = &pdev->dev;
int ret, irq;
irq = platform_get_irq_byname(pdev, "irq");
if (irq < 0) {
dev_err(dev, "no irq %s in dts\n",
match_data->irqs[0].name);
return irq;
}
ret = devm_request_irq(dev, irq,
match_data->irqs[0].irq_hdl,
0,
dev_driver_string(dev),
dev);
if (ret < 0) {
dev_err(dev, "request %s failed: %d\n",
match_data->irqs[0].name, ret);
return ret;
}
return 0;
}
int rkaiisp_ispidx_queue(int dev_id, struct rkisp_aiisp_st *idxbuf)
{
struct rkaiisp_hw_dev *hw_dev = rkaiisp_hwdev;
struct rkaiisp_device *aidev = NULL;
int i;
if (!hw_dev) {
pr_err("Can not find hwdev!");
return -EINVAL;
}
for (i = 0; i < hw_dev->dev_num; i++) {
if (hw_dev->aidev[i]) {
if ((hw_dev->aidev[i]->is_hw_link) && hw_dev->aidev[i]->dev_id == dev_id) {
aidev = hw_dev->aidev[i];
break;
}
}
}
if (!aidev) {
pr_err("Can not find aidev for dev_id %d!", dev_id);
return -EINVAL;
}
if (aidev->exemode != BOTHEVENT_TO_AIQ) {
pr_err("aidev %d exemode(%d) is not right!", dev_id, aidev->exemode);
return -EINVAL;
}
return rkaiisp_queue_ispbuf(aidev, idxbuf);
}
EXPORT_SYMBOL(rkaiisp_ispidx_queue);
static const char * const rv1126b_clks[] = {
"clk_aiisp_core",
"aclk_aiisp",
"hclk_aiisp",
};
static const struct aiisp_clk_info rv1126b_clk_rate[] = {
{
.clk_rate = 400,
.refer_data = 1920, //width
}, {
.clk_rate = 400,
.refer_data = 2688,
}, {
.clk_rate = 500,
.refer_data = 3072,
}, {
.clk_rate = 600,
.refer_data = 3840,
}, {
.clk_rate = 702,
.refer_data = 4672,
}
};
static struct aiisp_irqs_data rv1126b_irqs[] = {
{"irq", hw_irq_hdl},
};
static const struct aiisp_match_data rv1126b_match_data = {
.clks = rv1126b_clks,
.num_clks = ARRAY_SIZE(rv1126b_clks),
.clk_rate_tbl = rv1126b_clk_rate,
.num_clk_rate_tbl = ARRAY_SIZE(rv1126b_clk_rate),
.irqs = rv1126b_irqs,
.num_irqs = ARRAY_SIZE(rv1126b_irqs),
};
static const struct of_device_id rkaiisp_hw_of_match[] = {
{
.compatible = "rockchip,rv1126b-rkaiisp",
.data = &rv1126b_match_data,
},
{},
};
static inline bool is_iommu_enable(struct device *dev)
{
struct device_node *iommu;
iommu = of_parse_phandle(dev->of_node, "iommus", 0);
if (!iommu) {
dev_info(dev, "no iommu attached, using non-iommu buffers\n");
return false;
} else if (!of_device_is_available(iommu)) {
dev_info(dev, "iommu is disabled, using iommu buffers\n");
of_node_put(iommu);
return false;
}
of_node_put(iommu);
return true;
}
static void rkaiisp_soft_reset(struct rkaiisp_hw_dev *dev, bool is_secure)
{
void __iomem *base = dev->base_addr;
if (is_secure) {
/* if aidev working, cru reset isn't secure.
* aidev soft reset first to protect aidev reset.
*/
writel(0x1, base + AIISP_CORE_SOFT_RST);
udelay(10);
}
if (dev->reset) {
reset_control_assert(dev->reset);
udelay(10);
reset_control_deassert(dev->reset);
udelay(10);
}
/* refresh iommu after reset */
if (dev->is_mmu) {
rockchip_iommu_disable(dev->dev);
rockchip_iommu_enable(dev->dev);
}
}
static void disable_sys_clk(struct rkaiisp_hw_dev *dev)
{
int i;
for (i = dev->num_clks - 1; i >= 0; i--)
if (!IS_ERR(dev->clks[i]))
clk_disable_unprepare(dev->clks[i]);
}
static int enable_sys_clk(struct rkaiisp_hw_dev *dev)
{
int i, ret = -EINVAL;
for (i = 0; i < dev->num_clks; i++) {
if (!IS_ERR(dev->clks[i])) {
ret = clk_prepare_enable(dev->clks[i]);
if (ret < 0)
goto err;
}
}
rkaiisp_soft_reset(dev, false);
return 0;
err:
for (--i; i >= 0; --i)
if (!IS_ERR(dev->clks[i]))
clk_disable_unprepare(dev->clks[i]);
return ret;
}
static int rkaiisp_hw_probe(struct platform_device *pdev)
{
const struct aiisp_match_data *match_data;
struct device_node *node = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct rkaiisp_hw_dev *hw_dev;
struct resource *res;
int i, ret;
bool is_mem_reserved = true;
match_data = of_device_get_match_data(dev);
hw_dev = devm_kzalloc(dev, sizeof(*hw_dev), GFP_KERNEL);
if (!hw_dev)
return -ENOMEM;
dev_set_drvdata(dev, hw_dev);
hw_dev->dev = dev;
hw_dev->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf");
if (IS_ERR(hw_dev->grf))
dev_warn(dev, "Missing rockchip,grf property\n");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "get resource failed\n");
ret = -EINVAL;
goto err;
}
hw_dev->base_addr = devm_ioremap_resource(dev, res);
if (PTR_ERR(hw_dev->base_addr) == -EBUSY) {
resource_size_t offset = res->start;
resource_size_t size = resource_size(res);
hw_dev->base_addr = devm_ioremap(dev, offset, size);
}
if (IS_ERR(hw_dev->base_addr)) {
dev_err(dev, "ioremap failed\n");
ret = PTR_ERR(hw_dev->base_addr);
goto err;
}
hw_dev->pdev = pdev;
hw_dev->match_data = match_data;
for (i = 0; i < match_data->num_clks; i++) {
struct clk *clk = devm_clk_get(dev, match_data->clks[i]);
if (IS_ERR(clk)) {
dev_err(dev, "failed to get %s\n", match_data->clks[i]);
ret = PTR_ERR(clk);
goto err;
}
hw_dev->clks[i] = clk;
}
hw_dev->num_clks = match_data->num_clks;
hw_dev->clk_rate_tbl = match_data->clk_rate_tbl;
hw_dev->num_clk_rate_tbl = match_data->num_clk_rate_tbl;
hw_dev->reset = devm_reset_control_array_get(dev, false, false);
if (IS_ERR(hw_dev->reset)) {
dev_dbg(dev, "failed to get reset\n");
hw_dev->reset = NULL;
}
hw_dev->dev_num = 0;
hw_dev->cur_dev_id = 0;
mutex_init(&hw_dev->dev_mutex);
spin_lock_init(&hw_dev->hw_lock);
atomic_set(&hw_dev->refcnt, 0);
hw_dev->is_idle = true;
hw_dev->is_single = true;
hw_dev->is_dma_contig = true;
hw_dev->is_dma_sg_ops = true;
hw_dev->is_shutdown = false;
hw_dev->is_mmu = is_iommu_enable(dev);
ret = of_reserved_mem_device_init(dev);
if (ret) {
is_mem_reserved = false;
if (!hw_dev->is_mmu)
dev_info(dev, "No reserved memory region. default cma area!\n");
}
if (hw_dev->is_mmu && !is_mem_reserved)
hw_dev->is_dma_contig = false;
hw_dev->mem_ops = &vb2_cma_sg_memops;
rkaiisp_hwdev = hw_dev;
rkaiisp_register_irq(hw_dev);
pm_runtime_enable(dev);
dev_info(dev, "probe end.\n");
return 0;
err:
return ret;
}
static int rkaiisp_hw_remove(struct platform_device *pdev)
{
struct rkaiisp_hw_dev *hw_dev = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev);
mutex_destroy(&hw_dev->dev_mutex);
rkaiisp_hwdev = NULL;
return 0;
}
static void rkaiisp_hw_shutdown(struct platform_device *pdev)
{
struct rkaiisp_hw_dev *hw_dev = platform_get_drvdata(pdev);
hw_dev->is_shutdown = true;
}
static int __maybe_unused rkaiisp_runtime_suspend(struct device *dev)
{
struct rkaiisp_hw_dev *hw_dev = dev_get_drvdata(dev);
hw_dev->is_idle = true;
disable_sys_clk(hw_dev);
return pinctrl_pm_select_sleep_state(dev);
}
static int __maybe_unused rkaiisp_runtime_resume(struct device *dev)
{
struct rkaiisp_hw_dev *hw_dev = dev_get_drvdata(dev);
int ret;
ret = pinctrl_pm_select_default_state(dev);
if (ret < 0)
return ret;
enable_sys_clk(hw_dev);
return 0;
}
static const struct dev_pm_ops rkaiisp_hw_pm_ops = {
SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(rkaiisp_runtime_suspend, rkaiisp_runtime_resume, NULL)
};
static struct platform_driver rkaiisp_hw_drv = {
.driver = {
.name = "rkaiisp_hw",
.of_match_table = of_match_ptr(rkaiisp_hw_of_match),
.pm = &rkaiisp_hw_pm_ops,
},
.probe = rkaiisp_hw_probe,
.remove = rkaiisp_hw_remove,
.shutdown = rkaiisp_hw_shutdown,
};
static int __init rkaiisp_hw_drv_init(void)
{
int ret = 0;
ret = platform_driver_register(&rkaiisp_hw_drv);
if (!ret)
ret = platform_driver_register(&rkaiisp_plat_drv);
return ret;
}
static void __exit rkaiisp_hw_drv_exit(void)
{
platform_driver_unregister(&rkaiisp_plat_drv);
platform_driver_unregister(&rkaiisp_hw_drv);
}
module_init(rkaiisp_hw_drv_init);
module_exit(rkaiisp_hw_drv_exit);

View File

@@ -0,0 +1,80 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2025 Rockchip Electronics Co., Ltd. */
#ifndef _RKAIISP_HW_H
#define _RKAIISP_HW_H
#include <linux/interrupt.h>
#include <linux/rk-aiisp-config.h>
#define RKAIISP_MAX_BUS_CLK 10
enum rkaiisp_dev {
RKAIISP_DEV_ID0 = 0,
RKAIISP_DEV_ID1,
RKAIISP_DEV_ID2,
RKAIISP_DEV_ID3,
RKAIISP_DEV_ID4,
RKAIISP_DEV_ID5,
RKAIISP_DEV_ID6,
RKAIISP_DEV_ID7,
RKAIISP_DEV_MAX,
};
enum rkaiisp_sw_reg {
SW_REG_CACHE = 0xffffffff,
SW_REG_CACHE_SYNC = 0xeeeeeeee,
};
struct aiisp_irqs_data {
const char *name;
irqreturn_t (*irq_hdl)(int irq, void *ctx);
};
struct aiisp_clk_info {
u32 clk_rate;
u32 refer_data;
};
struct aiisp_match_data {
const char * const *clks;
int num_clks;
const struct aiisp_clk_info *clk_rate_tbl;
int num_clk_rate_tbl;
struct aiisp_irqs_data *irqs;
int num_irqs;
};
struct rkaiisp_hw_dev {
const struct aiisp_match_data *match_data;
struct platform_device *pdev;
struct device *dev;
struct regmap *grf;
void __iomem *base_addr;
struct clk *clks[RKAIISP_MAX_BUS_CLK];
int num_clks;
const struct aiisp_clk_info *clk_rate_tbl;
int num_clk_rate_tbl;
struct reset_control *reset;
struct rkaiisp_device *aidev[RKAIISP_DEV_MAX];
int dev_num;
int cur_dev_id;
/* lock for multi dev */
struct mutex dev_mutex;
spinlock_t hw_lock;
atomic_t refcnt;
const struct vb2_mem_ops *mem_ops;
bool is_dma_contig;
bool is_dma_sg_ops;
bool is_mmu;
bool is_idle;
bool is_single;
bool is_shutdown;
};
int rkaiisp_ispidx_queue(int dev_id, struct rkisp_aiisp_st *idxbuf);
#endif

View File

@@ -0,0 +1,136 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2025 Rockchip Electronics Co., Ltd. */
#ifndef _RKAIISP_REGS_H
#define _RKAIISP_REGS_H
#define AIISP_CORE_BASE 0x00000000
#define AIISP_CORE_CTRL (AIISP_CORE_BASE + 0x00000)
#define AIISP_CORE_SOFT_RST (AIISP_CORE_BASE + 0x00008)
#define AIISP_CORE_LEVEL_CTRL0 (AIISP_CORE_BASE + 0x00020)
#define AIISP_CORE_LEVEL_CTRL1 (AIISP_CORE_BASE + 0x00024)
#define AIISP_CORE_LEVEL_CTRL2 (AIISP_CORE_BASE + 0x00028)
#define AIISP_CORE_LEVEL_CTRL3 (AIISP_CORE_BASE + 0x0002c)
#define AIISP_CORE_OUT_CTRL (AIISP_CORE_BASE + 0x00040)
#define AIISP_CORE_NOISE_LMT (AIISP_CORE_BASE + 0x00044)
#define AIISP_CORE_COMP0 (AIISP_CORE_BASE + 0x00200)
#define AIISP_CORE_COMP1 (AIISP_CORE_BASE + 0x00204)
#define AIISP_CORE_COMP2 (AIISP_CORE_BASE + 0x00208)
#define AIISP_CORE_COMP3 (AIISP_CORE_BASE + 0x0020c)
#define AIISP_CORE_COMP4 (AIISP_CORE_BASE + 0x00210)
#define AIISP_CORE_COMP5 (AIISP_CORE_BASE + 0x00214)
#define AIISP_CORE_COMP6 (AIISP_CORE_BASE + 0x00218)
#define AIISP_CORE_COMP7 (AIISP_CORE_BASE + 0x0021c)
#define AIISP_CORE_COMP8 (AIISP_CORE_BASE + 0x00220)
#define AIISP_CORE_COMP9 (AIISP_CORE_BASE + 0x00224)
#define AIISP_CORE_COMP10 (AIISP_CORE_BASE + 0x00228)
#define AIISP_CORE_COMP11 (AIISP_CORE_BASE + 0x0022c)
#define AIISP_CORE_COMP12 (AIISP_CORE_BASE + 0x00230)
#define AIISP_CORE_COMP13 (AIISP_CORE_BASE + 0x00234)
#define AIISP_CORE_COMP14 (AIISP_CORE_BASE + 0x00238)
#define AIISP_CORE_COMP15 (AIISP_CORE_BASE + 0x0023c)
#define AIISP_CORE_COMP16 (AIISP_CORE_BASE + 0x00240)
#define AIISP_CORE_DECOMP0 (AIISP_CORE_BASE + 0x00280)
#define AIISP_CORE_DECOMP1 (AIISP_CORE_BASE + 0x00284)
#define AIISP_CORE_DECOMP2 (AIISP_CORE_BASE + 0x00288)
#define AIISP_CORE_DECOMP3 (AIISP_CORE_BASE + 0x0028c)
#define AIISP_CORE_DECOMP4 (AIISP_CORE_BASE + 0x00290)
#define AIISP_CORE_DECOMP5 (AIISP_CORE_BASE + 0x00294)
#define AIISP_CORE_DECOMP6 (AIISP_CORE_BASE + 0x00298)
#define AIISP_CORE_DECOMP7 (AIISP_CORE_BASE + 0x0029c)
#define AIISP_CORE_DECOMP8 (AIISP_CORE_BASE + 0x002a0)
#define AIISP_CORE_DECOMP9 (AIISP_CORE_BASE + 0x002a4)
#define AIISP_CORE_DECOMP10 (AIISP_CORE_BASE + 0x002a8)
#define AIISP_CORE_DECOMP11 (AIISP_CORE_BASE + 0x002ac)
#define AIISP_CORE_DECOMP12 (AIISP_CORE_BASE + 0x002b0)
#define AIISP_CORE_DECOMP13 (AIISP_CORE_BASE + 0x002b4)
#define AIISP_CORE_DECOMP14 (AIISP_CORE_BASE + 0x002b8)
#define AIISP_CORE_DECOMP15 (AIISP_CORE_BASE + 0x002bc)
#define AIISP_CORE_DECOMP16 (AIISP_CORE_BASE + 0x002c0)
#define AIISP_MI_BASE 0x00002000
#define AIISP_MI_HURRY_CTRL (AIISP_MI_BASE + 0x00040)
#define AIISP_MI_ARQOS_CTRL (AIISP_MI_BASE + 0x00044)
#define AIISP_MI_AWQOS_CTRL (AIISP_MI_BASE + 0x00048)
#define AIISP_MI_IMSC (AIISP_MI_BASE + 0x00050)
#define AIISP_MI_RIS (AIISP_MI_BASE + 0x00054)
#define AIISP_MI_MIS (AIISP_MI_BASE + 0x00058)
#define AIISP_MI_ICR (AIISP_MI_BASE + 0x0005c)
#define AIISP_MI_ISR (AIISP_MI_BASE + 0x00060)
#define AIISP_MI_RD_START (AIISP_MI_BASE + 0x00100)
#define AIISP_MI_CTRL (AIISP_MI_BASE + 0x00104)
#define AIISP_MI_SLICE_CTRL (AIISP_MI_BASE + 0x00180)
#define AIISP_MI_MANUAL_CTRL (AIISP_MI_BASE + 0x00184)
#define AIISP_MI_CORE_WIDTH (AIISP_MI_BASE + 0x001a0)
#define AIISP_MI_CORE_HEIGHT (AIISP_MI_BASE + 0x001a4)
#define AIISP_MI_RD_CH0_CTRL (AIISP_MI_BASE + 0x00200)
#define AIISP_MI_RD_CH0_BASE (AIISP_MI_BASE + 0x00204)
#define AIISP_MI_RD_CH0_HEIGHT (AIISP_MI_BASE + 0x0020c)
#define AIISP_MI_RD_CH0_STRIDE (AIISP_MI_BASE + 0x00210)
#define AIISP_MI_RD_CH1_CTRL (AIISP_MI_BASE + 0x00300)
#define AIISP_MI_RD_CH1_BASE (AIISP_MI_BASE + 0x00304)
#define AIISP_MI_RD_CH1_HEIGHT (AIISP_MI_BASE + 0x0030c)
#define AIISP_MI_RD_CH1_STRIDE (AIISP_MI_BASE + 0x00310)
#define AIISP_MI_RD_CH2_CTRL (AIISP_MI_BASE + 0x00400)
#define AIISP_MI_RD_CH2_BASE (AIISP_MI_BASE + 0x00404)
#define AIISP_MI_RD_CH2_HEIGHT (AIISP_MI_BASE + 0x0040c)
#define AIISP_MI_RD_CH2_STRIDE (AIISP_MI_BASE + 0x00410)
#define AIISP_MI_RD_CH3_CTRL (AIISP_MI_BASE + 0x00500)
#define AIISP_MI_RD_CH3_BASE (AIISP_MI_BASE + 0x00504)
#define AIISP_MI_RD_CH3_HEIGHT (AIISP_MI_BASE + 0x0050c)
#define AIISP_MI_RD_CH3_STRIDE (AIISP_MI_BASE + 0x00510)
#define AIISP_MI_RD_CH4_CTRL (AIISP_MI_BASE + 0x00600)
#define AIISP_MI_RD_CH4_BASE (AIISP_MI_BASE + 0x00604)
#define AIISP_MI_RD_CH4_HEIGHT (AIISP_MI_BASE + 0x0060c)
#define AIISP_MI_RD_CH4_STRIDE (AIISP_MI_BASE + 0x00610)
#define AIISP_MI_RD_CH5_CTRL (AIISP_MI_BASE + 0x00700)
#define AIISP_MI_RD_CH5_BASE (AIISP_MI_BASE + 0x00704)
#define AIISP_MI_RD_CH5_HEIGHT (AIISP_MI_BASE + 0x0070c)
#define AIISP_MI_RD_CH5_STRIDE (AIISP_MI_BASE + 0x00710)
#define AIISP_MI_RD_CH6_CTRL (AIISP_MI_BASE + 0x00800)
#define AIISP_MI_RD_CH6_BASE (AIISP_MI_BASE + 0x00804)
#define AIISP_MI_RD_CH6_HEIGHT (AIISP_MI_BASE + 0x0080c)
#define AIISP_MI_RD_CH6_STRIDE (AIISP_MI_BASE + 0x00810)
#define AIISP_MI_RD_KWT_CTRL (AIISP_MI_BASE + 0x00900)
#define AIISP_MI_RD_KWT_BASE (AIISP_MI_BASE + 0x00904)
#define AIISP_MI_RD_KWT_WIDTH (AIISP_MI_BASE + 0x00908)
#define AIISP_MI_RD_KWT_HEIGHT (AIISP_MI_BASE + 0x0090c)
#define AIISP_MI_RD_KWT_STRIDE (AIISP_MI_BASE + 0x00910)
#define AIISP_MI_WR_CTRL (AIISP_MI_BASE + 0x00a00)
#define AIISP_MI_WR_INIT (AIISP_MI_BASE + 0x00a04)
#define AIISP_MI_CHN0_WR_CRTL (AIISP_MI_BASE + 0x00a08)
#define AIISP_MI_CHN0_WR_BASE (AIISP_MI_BASE + 0x00a10)
#define AIISP_MI_CHN0_WR_SIZE (AIISP_MI_BASE + 0x00a24)
#define AIISP_MI_CHN0_WR_STRIDE (AIISP_MI_BASE + 0x00a28)
#define AIISP_MI_ISR_BUSERR BIT(0)
#define AIISP_MI_ISR_WREND BIT(3)
#define AIISP_MI_ISR_ALL (AIISP_MI_ISR_BUSERR | AIISP_MI_ISR_WREND)
#define AIISP_MI_RD_START_EN BIT(0)
#define AIISP_MI_RD_KWT_EN BIT(0)
#define AIISP_MI_RD_CH_EN BIT(0)
#define AIISP_MI_RD_CH0_GROUP_MODE 2
#define AIISP_MI_RD_CH1_GROUP_MODE 2
#define AIISP_MI_RD_CH2_GROUP_MODE 2
#define AIISP_MI_RD_CH3_GROUP_MODE 0
#define AIISP_MI_RD_CH4_GROUP_MODE 0
#define AIISP_MI_RD_CH5_GROUP_MODE 0
#define AIISP_MI_RD_CH6_GROUP_MODE 0
#define AIISP_MI_RD_KWT_GROUP_MODE 0
#define AIISP_MI_WR_GROUP_MODE 2
#define AIISP_MI_WR_INIT_BASE_EN BIT(4)
#define AIISP_MI_WR_INIT_OFFSET_EN BIT(5)
#define AIISP_MI_CHN0_WR_EN BIT(0)
#define AIISP_MI_CHN0_WR_AUTOUPD BIT(1)
#define AIISP_MI_CHN0SELF_FORCE_UPD BIT(4)
#define AIISP_MI_RD_ALWAYS_ON BIT(0)
#define AIISP_MI_WR_ALWAYS_ON BIT(4)
#endif /* _RKAIISP_REGS_H */

View File

@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2025 Rockchip Electronics Co., Ltd. */
#ifndef _RKAIISP_VERSION_H
#define _RKAIISP_VERSION_H
#include <linux/version.h>
/*
*RKAIISP DRIVER VERSION NOTE
*
*v0.1.1:
*1. First version;
*
*/
#define RKAIISP_DRIVER_VERSION KERNEL_VERSION(0, 1, 0x1)
#endif

View File

@@ -0,0 +1,140 @@
/* SPDX-License-Identifier: (GPL-2.0+ WITH Linux-syscall-note) OR MIT
*
* Rockchip AIISP
* Copyright (C) 2025 Rockchip Electronics Co., Ltd.
*/
#ifndef _UAPI_RK_AIISP_CONFIG_H
#define _UAPI_RK_AIISP_CONFIG_H
#include <linux/rk-isp2-config.h>
#define RKAIISP_PYRAMID_LAYER_NUM 4
#define RKAIISP_MAX_RUNCNT 8
#define RKAIISP_MAX_ISPBUF 8
#define RKAIISP_MODEL_UPDATE 0x01
#define RKAIISP_OTHER_UPDATE 0x02
#define RKAIISP_CMD_SET_PARAM_INFO \
_IOW('V', BASE_VIDIOC_PRIVATE + 0, struct rkaiisp_param_info)
#define RKAIISP_CMD_INIT_BUFPOOL \
_IOW('V', BASE_VIDIOC_PRIVATE + 1, struct rkaiisp_ispbuf_info)
#define RKAIISP_CMD_FREE_BUFPOOL \
_IO('V', BASE_VIDIOC_PRIVATE + 2)
#define RKAIISP_CMD_QUEUE_BUF \
_IOW('V', BASE_VIDIOC_PRIVATE + 3, struct rkisp_aiisp_st)
/**********************EVENT_PRIVATE***************************/
#define RKAIISP_V4L2_EVENT_AIISP_DONE (V4L2_EVENT_PRIVATE_START + 1)
enum rkaiisp_chn_src {
ISP_IIR,
VPSL_YRAW_CHN0,
VPSL_YRAW_CHN1,
VPSL_YRAW_CHN2,
VPSL_YRAW_CHN3,
VPSL_YRAW_CHN4,
VPSL_YRAW_CHN5,
VPSL_SIG_CHN0,
VPSL_SIG_CHN1,
VPSL_SIG_CHN2,
VPSL_SIG_CHN3,
VPSL_SIG_CHN4,
ISP_AIPRE_NARMAP,
AIISP_LAST_OUT
};
enum rkaiisp_model_mode {
SINGLE_MODE,
COMBO_MODE,
SINGLEX2_MODE
};
enum rkaiisp_exemode {
BOTHEVENT_TO_AIQ,
ISPEVENT_IN_KERNEL,
BOTHEVENT_IN_KERNEL
};
struct rkaiisp_param_info {
enum rkaiisp_exemode exemode;
__u32 para_size;
__u32 max_runcnt;
} __attribute__ ((packed));
struct rkaiisp_ispbuf_info {
struct rkisp_bnr_buf_info bnr_buf;
__u32 iir_width;
__u32 iir_height;
__u32 raw_width[6];
__u32 raw_height[6];
__u32 sig_width[5];
__u32 sig_height[5];
__u32 narmap_width;
__u32 narmap_height;
} __attribute__ ((packed));
struct rkaiisp_other_cfg {
__u16 sw_neg_noiselimit;
__u16 sw_pos_noiselimit;
__u16 sw_prev_blacklvl;
__u16 sw_post_blacklvl;
__u16 sw_in_comp_y[33];
__u16 sw_out_decomp_y[33];
} __attribute__ ((packed));
struct rkaiisp_model_cfg {
enum rkaiisp_chn_src mi_chn_src[7];
__u32 sw_aiisp_mode;
__u32 sw_aiisp_level_num;
__u32 sw_aiisp_l1_level_num;
__u32 sw_aiisp_op_mode;
__u32 sw_aiisp_drop_en;
__u32 sw_aiisp_lv_active[16];
__u32 sw_aiisp_lv_mode[16];
__u32 sw_mi_chn_en[7];
__u32 sw_mi_chn_mode[7];
__u32 sw_mi_chn_num[7];
__u32 sw_mi_chn_data_mode[7];
__u32 sw_mi_chn1_sel;
__u32 sw_mi_chn3_sel;
__u32 sw_out_d2s_en;
__u32 sw_out_mode;
__u32 sw_lastlvlm1_clip8bit;
} __attribute__ ((packed));
struct rkaiisp_kwt_cfg {
__u32 kwt_offet[RKAIISP_MAX_RUNCNT];
__u32 kwt_size[RKAIISP_MAX_RUNCNT];
__u32 kwt_pad_size[RKAIISP_MAX_RUNCNT];
} __attribute__ ((packed));
struct rkaiisp_params {
__u32 frame_id;
__u32 module_update;
__u32 model_runcnt;
enum rkaiisp_model_mode model_mode;
struct rkaiisp_other_cfg other_cfg;
struct rkaiisp_model_cfg model_cfg[RKAIISP_MAX_RUNCNT];
struct rkaiisp_kwt_cfg kwt_cfg;
__u8 reserved[36];
} __attribute__ ((packed));
struct rkaiisp_model_info {
__u32 checksum;
__u32 model_runcnt;
float model_qr;
enum rkaiisp_model_mode model_mode;
struct rkaiisp_model_cfg model_cfg[RKAIISP_MAX_RUNCNT];
struct rkaiisp_kwt_cfg kwt_cfg;
__u8 reserved[48];
} __attribute__ ((packed));
#endif /* _UAPI_RK_AIISP_CONFIG_H */