Browse Source

Linux_SDK_V0.9.5

thead_admin 1 year ago
commit
f9a685e835

+ 29 - 0
.gitignore

@@ -0,0 +1,29 @@
+/.auto.deps
+/.config.cmd
+/.config.old
+/..config.tmp
+/.config
+/.vscode
+*.tmp
+*.depend
+*.o
+*.a
+*.o.d
+*.o.cmd
+*.a.cmd
+*.ko.cmd
+*.ko
+*.mod
+*.mod.c
+*.mod.cmd
+*.order
+*.orig
+*.symvers.cmd
+*.order.cmd
+test/ivs_test
+user_mode/libivs.so
+Module.symvers
+out/
+output/
+obj/
+dependencies/

+ 120 - 0
Makefile

@@ -0,0 +1,120 @@
+##
+ # Copyright (C) 2020 Alibaba Group Holding Limited
+##
+ifneq ($(wildcard ../.param),)
+  include ../.param
+endif
+
+#CONFIG_DEBUG_MODE=1
+CONFIG_OUT_ENV=hwlinux
+
+CONFIG_BUILD_DRV_EXTRA_PARAM:=""    	
+CONFIG_BUILD_LIB_EXTRA_PARAM:=""
+CONFIG_BUILD_TST_EXTRA_PARAM:=""	
+
+DIR_TARGET_BASE=bsp/ivs		
+DIR_TARGET_LIB =bsp/ivs/lib
+DIR_TARGET_KO  =bsp/ivs/ko
+DIR_TARGET_TEST=bsp/ivs/test
+
+MODULE_NAME=IVS
+BUILD_LOG_START="\033[47;30m>>> $(MODULE_NAME) $@ begin\033[0m"
+BUILD_LOG_END  ="\033[47;30m<<< $(MODULE_NAME) $@ end\033[0m"
+
+#
+# Do a parallel build with multiple jobs, based on the number of CPUs online
+# in this system: 'make -j8' on a 8-CPU system, etc.
+#
+# (To override it, run 'make JOBS=1' and similar.)
+#
+
+ifeq ($(JOBS),)
+  JOBS := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null)
+  ifeq ($(JOBS),)
+    JOBS := 1
+  endif
+endif
+
+all:    info driver lib test install_local_output install_rootfs
+.PHONY: info driver lib test install_local_output install_rootfs \
+        install_prepare install_addons clean_driver clean_lib clean_test clean_output clean
+
+info:
+	@echo $(BUILD_LOG_START)
+	@echo "  ====== Build Info from repo project ======"
+	@echo "    BUILDROOT_DIR="$(BUILDROOT_DIR)
+	@echo "    CROSS_COMPILE="$(CROSS_COMPILE)
+	@echo "    LINUX_DIR="$(LINUX_DIR)
+	@echo "    ARCH="$(ARCH)
+	@echo "    BOARD_NAME="$(BOARD_NAME)
+	@echo "    KERNEL_ID="$(KERNELVERSION)
+	@echo "    KERNEL_DIR="$(LINUX_DIR)
+	@echo "    INSTALL_DIR_ROOTFS="$(INSTALL_DIR_ROOTFS)
+	@echo "    INSTALL_DIR_SDK="$(INSTALL_DIR_SDK)
+	@echo "  ====== Build configuration by settings ======"
+#	@echo "    CONFIG_DEBUG_MODE="$(CONFIG_DEBUG_MODE)
+	@echo "    CONFIG_OUT_ENV="$(CONFIG_OUT_ENV)
+	@echo "    JOBS="$(JOBS)
+	@echo $(BUILD_LOG_END)
+
+driver:
+	@echo $(BUILD_LOG_START)
+	make -C $(LINUX_DIR) M=$(PWD)/kernel_mode ARCH=$(ARCH) modules
+	@echo $(BUILD_LOG_END)
+
+clean_driver:
+	@echo $(BUILD_LOG_START)
+	make -C kernel_mode KDIR=$(LINUX_DIR) clean
+	@echo $(BUILD_LOG_END)
+
+lib:
+	@echo $(BUILD_LOG_START)
+	make -w -C user_mode hwlinux
+	@echo $(BUILD_LOG_END)
+
+clean_lib:
+	@echo $(BUILD_LOG_START)
+	make clean -C user_mode
+	@echo $(BUILD_LOG_END)
+
+test: lib driver
+	@echo $(BUILD_LOG_START)
+	make -w -C test hwlinux
+	@echo $(BUILD_LOG_END)
+
+clean_test:
+	@echo $(BUILD_LOG_START)
+	make clean -C test
+	@echo $(BUILD_LOG_END)
+
+install_prepare:
+	mkdir -p ./output/rootfs/$(DIR_TARGET_KO)
+	mkdir -p ./output/rootfs/$(DIR_TARGET_LIB)
+	mkdir -p ./output/rootfs/$(DIR_TARGET_TEST)
+
+install_addons: install_prepare
+	@echo $(BUILD_LOG_START)
+	@echo $(BUILD_LOG_END)
+
+install_local_output: driver lib test install_addons
+	@echo $(BUILD_LOG_START)
+	find ./kernel_mode -name "*.ko" | xargs -i cp -f {} ./output/rootfs/$(DIR_TARGET_KO)
+	find ./user_mode -name "*.so" | xargs -i cp -f {} ./output/rootfs/$(DIR_TARGET_LIB)
+	find ./user_mode -name "*.a" | xargs -i cp -f {} ./output/rootfs/$(DIR_TARGET_LIB)
+	cp -f ./test/ivs_test ./output/rootfs/$(DIR_TARGET_TEST)
+	@if [ `command -v tree` != "" ]; then \
+	    tree ./output/rootfs;             \
+	fi
+	@echo $(BUILD_LOG_END)
+
+install_rootfs: install_local_output
+	@echo $(BUILD_LOG_START)
+	@echo $(BUILD_LOG_END)
+
+clean_output:
+	@echo $(BUILD_LOG_START)
+	rm -rf ./output
+	@echo $(BUILD_LOG_END)
+
+clean: clean_output clean_driver clean_lib clean_test
+

+ 12 - 0
README.md

@@ -0,0 +1,12 @@
+# How to build
+- Just run 'make' to build kernel mode driver, user mode driver and test application.
+
+Find all the binaries in following folders:
+- output/rootfs/bsp/ivs/ko: kernel mode driver
+- output/rootfs/bsp/ivs/lib: user mode driver static linked library and dynamic linked library
+- output/rootfs/bsp/ivs/test: test application
+
+# Description of each directories
+- kernel_mode: kernel mode driver source
+- user_mode: user mode driver source
+- test: test application source

+ 6 - 0
kernel_mode/Makefile

@@ -0,0 +1,6 @@
+shake-objs := isp_venc_shake_driver.o
+obj-m         += shake.o
+
+clean:
+	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.ur-safe .cache.mk
+	rm -rf modules.order Module.symvers

+ 439 - 0
kernel_mode/isp_venc_shake_driver.c

@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2021 - 2022  Alibaba Group. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <linux/cdev.h>
+#include <linux/pci.h>
+#include <linux/uaccess.h>
+#include <linux/ioport.h>
+#include <asm/irq.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include "isp_venc_shake_driver.h"
+
+#define IVS_SWREG_AMOUNT 27
+
+typedef struct _theadivs_dev
+{
+	struct cdev cdev;
+	dev_t devt;
+	struct class *class;
+    unsigned long base_addr;
+    u32 iosize;
+    volatile u8 *hwregs;
+    int irq;
+    int state;
+} theadivs_dev;
+
+static int theadivs_major = 0;  /* dynamic */
+static int theadivs_minor = 0;
+static theadivs_dev* theadivs_data = NULL;
+static unsigned int device_register_index = 0;
+struct class *theadivs_class;
+
+static irqreturn_t theadivs_isr(int irq, void *dev_id);
+
+static void print_registers(void)
+{
+    printk("pic_width = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x00)));
+    printk("pic_height = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x04)));
+    printk("encode_width = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x08)));
+    printk("encode_height = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x0c)));
+    printk("wid_y = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x10)));
+    printk("wid_uv = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x14)));
+    printk("sram_size = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x18)));
+    printk("encode_n = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x1c)));
+    printk("stride_y = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x20)));
+    printk("stride_uv = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x24)));
+    printk("encode_x = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x2c)));
+    printk("encode_y = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x30)));
+    printk("int_state = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x38)));
+    printk("int_mask = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x40)));
+}
+
+static int config_ivs(struct file *filp, struct ivs_parameter *params)
+{
+    iowrite32(params->pic_width, (void*)(theadivs_data->hwregs + 0x00));
+    iowrite32(params->pic_height, (void*)(theadivs_data->hwregs + 0x04));
+    iowrite32(params->encode_width, (void*)(theadivs_data->hwregs + 0x08));
+    iowrite32(params->encode_height, (void*)(theadivs_data->hwregs + 0x0c));
+    iowrite32(params->wid_y, (void*)(theadivs_data->hwregs + 0x10));
+    iowrite32(params->wid_uv, (void*)(theadivs_data->hwregs + 0x14));
+    iowrite32(params->sram_size, (void*)(theadivs_data->hwregs + 0x18));
+    iowrite32(params->encode_n, (void*)(theadivs_data->hwregs + 0x1c));
+    iowrite32(params->stride_y, (void*)(theadivs_data->hwregs + 0x20));
+    iowrite32(params->stride_uv, (void*)(theadivs_data->hwregs + 0x24));
+    iowrite32(1, (void*)(theadivs_data->hwregs + 0x28)); // CLEAR
+    iowrite32(params->encode_x, (void*)(theadivs_data->hwregs + 0x2c));
+    iowrite32(params->encode_y, (void*)(theadivs_data->hwregs + 0x30));
+    iowrite32(0, (void*)(theadivs_data->hwregs + 0x34)); // START
+    iowrite32(0, (void*)(theadivs_data->hwregs + 0x3c)); // INT_CLEAN
+    iowrite32(params->int_mask, (void*)(theadivs_data->hwregs + 0x40));
+
+    return 0;
+}
+
+static long theadivs_ioctl(struct file *filp,
+                          unsigned int cmd, unsigned long arg)
+{
+    int err = 0;
+
+    if (_IOC_TYPE(cmd) != THEAD_IOC_MAGIC)
+        return -ENOTTY;
+    else if (_IOC_NR(cmd) > THEAD_IOC_MAXNR)
+        return -ENOTTY;
+
+    if (_IOC_DIR(cmd) & _IOC_READ)
+        err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+    else if (_IOC_DIR(cmd) & _IOC_WRITE)
+        err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+    if (err)
+        return -EFAULT;
+
+    switch (cmd)
+    {
+    case THEAD_IOCH_CONFIG_IVS:
+    {
+        struct ivs_parameter params;
+        printk("%s: THEAD_IOCH_CONFIG_IVS\n", __func__);
+        err = copy_from_user(&params, (struct ivs_parameter*)arg, sizeof(struct ivs_parameter));
+        config_ivs(filp, &params);
+        print_registers();
+        theadivs_data->state = THEADIVS_READY;
+        break;
+    }
+    case THEAD_IOCH_START_IVS:
+    {
+        printk("%s: THEAD_IOCH_START_IVS\n", __func__);
+        iowrite32(1, theadivs_data->hwregs + 0x34); // START
+        print_registers();
+        theadivs_data->state = THEADIVS_RUNNING;
+        break;
+    }
+    case THEAD_IOCH_RESET_IVS:
+    {
+        printk("%s: THEAD_IOCH_RESET_IVS\n", __func__);
+        iowrite32(1, theadivs_data->hwregs + 0x40); // INT_MASK
+        iowrite32(1, theadivs_data->hwregs + 0x28); // CLEAR
+        iowrite32(0, theadivs_data->hwregs + 0x40); // INT_MASK
+        print_registers();
+        theadivs_data->state = THEADIVS_IDLE;
+        break;
+    }
+    case THEAD_IOCH_GET_STATE:
+    {
+        printk("%s: THEAD_IOCH_GET_STATE: %d\n", __func__, theadivs_data->state);
+        err = copy_to_user((int *)arg, &theadivs_data->state, sizeof(int));
+        break;
+    }
+    default:
+    {
+        printk("%s: undefined command: 0x%x\n", __func__, cmd);
+    }
+    }
+    return 0;
+}
+
+static int theadivs_open(struct inode *inode, struct file *filp)
+{
+    int result = 0;
+    //theadivs_dev *dev = theadivs_data;
+    //filp->private_data = (void *) dev;
+
+    return result;
+}
+static int theadivs_release(struct inode *inode, struct file *filp)
+{
+    //theadivs_dev *dev = (theadivs_dev *) filp->private_data;
+
+    return 0;
+}
+
+static struct file_operations theadivs_fops = {
+    .owner= THIS_MODULE,
+    .open = theadivs_open,
+    .release = theadivs_release,
+    .unlocked_ioctl = theadivs_ioctl,
+    .fasync = NULL,
+};
+
+static const struct of_device_id thead_of_match[] = {
+        { .compatible = "thead,light-ivs",  },
+        { /* sentinel */  },
+};
+
+static int theadivs_reserve_IO(void)
+{
+    if(!request_mem_region
+        (theadivs_data->base_addr, theadivs_data->iosize, "shake"))
+    {
+        printk(KERN_INFO "theadivs: failed to reserve HW regs\n");
+        printk(KERN_INFO "theadivs: base_addr = 0x%08lx, iosize = %d\n",
+                          theadivs_data->base_addr,
+                          theadivs_data->iosize);
+        return -1;
+    }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0))
+    theadivs_data->hwregs =
+        (volatile u8 *) ioremap_nocache(theadivs_data->base_addr,
+                                        theadivs_data->iosize);
+#else
+    theadivs_data->hwregs =
+        (volatile u8 *) ioremap(theadivs_data->base_addr,
+                                        theadivs_data->iosize);
+#endif
+
+    if (theadivs_data->hwregs == NULL)
+    {
+        printk(KERN_INFO "theadivs: failed to ioremap HW regs\n");
+        release_mem_region(theadivs_data->base_addr, theadivs_data->iosize);
+        return -1;
+    }
+
+    printk("theadivs: mapped from 0x%lx to %p with size %d\n", 
+        theadivs_data->base_addr, theadivs_data->hwregs, theadivs_data->iosize);
+
+    return 0;
+}
+
+static void theadivs_release_IO(void)
+{
+    if(theadivs_data->hwregs)
+    {
+        iounmap((void *) theadivs_data->hwregs);
+        release_mem_region(theadivs_data->base_addr, theadivs_data->iosize);
+        theadivs_data->hwregs = NULL;
+    }
+}
+
+int __init theadivs_probe(struct platform_device *pdev)
+{
+    int result = -1;
+    struct resource *mem;
+    printk("enter %s\n",__func__);
+
+    theadivs_data = (theadivs_dev *)vmalloc(sizeof(theadivs_dev));
+    if (theadivs_data == NULL)
+        return result;
+    memset(theadivs_data, 0, sizeof(theadivs_dev));
+
+    mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+    if(mem->start)
+        theadivs_data->base_addr = mem->start; 
+    theadivs_data->irq = platform_get_irq(pdev, 0);
+    printk("%s:get irq %d\n", __func__, theadivs_data->irq);
+    theadivs_data->iosize = IVS_SWREG_AMOUNT * 4;
+#if 1
+	if (device_register_index == 0)
+	{
+		if (theadivs_major == 0)
+		{
+			result = alloc_chrdev_region(&theadivs_data->devt, 0, 1, "shake");
+			if (result != 0)
+			{
+				printk("%s:alloc_chrdev_region error\n", __func__);
+				goto err1;
+			}
+			theadivs_major = MAJOR(theadivs_data->devt);
+			theadivs_minor = MINOR(theadivs_data->devt);
+		}
+		else
+		{
+			theadivs_data->devt = MKDEV(theadivs_major, theadivs_minor);
+			result = register_chrdev_region(theadivs_data->devt, 1, "shake");
+			if (result)
+			{
+				printk("%s:register_chrdev_region error\n", __func__);
+				goto err1;
+			}
+		}
+
+		theadivs_class = class_create(THIS_MODULE, "shake");
+		if (IS_ERR(theadivs_class))
+		{
+			printk("%s[%d]:class_create error!\n", __func__, __LINE__);
+			goto err;
+		}
+	}
+	theadivs_data->devt = MKDEV(theadivs_major, theadivs_minor + pdev->id);
+
+	cdev_init(&theadivs_data->cdev, &theadivs_fops);
+	result = cdev_add(&theadivs_data->cdev, theadivs_data->devt, 1);
+	if ( result )
+	{
+		printk("%s[%d]:cdev_add error!\n", __func__, __LINE__);
+		goto err;
+	}
+	theadivs_data->class = theadivs_class;
+	device_create(theadivs_data->class, NULL, theadivs_data->devt,
+			theadivs_data, "shake");
+
+	device_register_index++;
+#else
+    result = register_chrdev(theadivs_major, "shake", &theadivs_fops);
+    if (result < 0)
+    {
+        printk(KERN_INFO "theadivs_driver: unable to get major <%d>\n",
+              theadivs_major);
+        goto err1;
+    }
+    else if (result != 0)    /* this is for dynamic major */
+    {
+        theadivs_major = result;
+    }
+#endif
+
+    theadivs_reserve_IO();
+
+    /* get the IRQ line */
+    if (theadivs_data->irq!= -1)
+    {
+        result = request_irq(theadivs_data->irq, theadivs_isr,
+                              IRQF_SHARED,
+                              "shake", (void *)theadivs_data);
+        if (result == -EINVAL)
+        {
+            printk(KERN_ERR "theadivs_driver: Bad irq number or handler.\n");
+            theadivs_release_IO();
+            goto err;
+        }
+        else if (result == -EBUSY)
+        {
+            printk(KERN_ERR "theadivs_driver: IRQ <%d> busy, change your config.\n",
+                    theadivs_data->irq);
+            theadivs_release_IO();
+            goto err;
+        }
+    }
+    else
+    {
+        printk(KERN_INFO "theadivs_driver: IRQ not in use!\n");
+    }
+
+    printk(KERN_INFO "theadivs_driver: module inserted. Major <%d>\n", theadivs_major);
+
+    return 0;
+err:
+    //unregister_chrdev(theadivs_major, "shake");
+    unregister_chrdev_region(theadivs_data->devt, 1);
+err1:
+    if (theadivs_data != NULL)
+        vfree(theadivs_data);
+    printk(KERN_INFO "theadivs_driver: module not inserted\n");
+    return result;
+}
+
+static int theadivs_remove(struct platform_device *pdev)
+{
+    free_irq(theadivs_data->irq, theadivs_data);
+    theadivs_release_IO();
+    //unregister_chrdev(theadivs_major, "shake");
+    device_register_index--;
+	cdev_del(&theadivs_data->cdev);
+	device_destroy(theadivs_data->class, theadivs_data->devt);
+    unregister_chrdev_region(theadivs_data->devt, 1);
+	if (device_register_index == 0)
+	{
+		class_destroy(theadivs_data->class);
+	}
+    if (theadivs_data != NULL)
+        vfree(theadivs_data);
+
+    printk(KERN_INFO "theadivs_driver: module removed\n");
+    return 0;
+}
+
+
+static struct platform_driver theadivs_driver = {
+    .probe = theadivs_probe,
+    .remove = theadivs_remove,
+    .driver = {
+        .name = "shake",
+        .owner = THIS_MODULE,
+        .of_match_table = of_match_ptr(thead_of_match),
+    }
+};
+
+
+int __init theadivs_init(void)
+{
+    int ret = 0;
+    printk("enter %s\n",__func__);
+#if 1
+    ret = platform_driver_register(&theadivs_driver);
+    if (ret)
+    {
+        pr_err("register platform driver failed!\n");
+    }
+#endif
+    return ret;
+}
+
+void __exit theadivs_cleanup(void)
+{
+    printk("enter %s\n",__func__);
+    platform_driver_unregister(&theadivs_driver);
+    return;
+}
+
+static irqreturn_t theadivs_isr(int irq, void *dev_id)
+{
+    theadivs_dev *dev = (theadivs_dev *) dev_id;
+    u32 irq_status = 0;
+
+    printk( "theadivs_isr: received IRQ!\n");
+    irq_status = (u32)ioread32((void*)dev->hwregs + 0x38); // INT_STATE
+    printk( "INT_STATE of is: 0x%x\n", irq_status);
+    theadivs_data->state = THEADIVS_ERROR;
+
+    iowrite32(1, theadivs_data->hwregs + 0x40); // INT_MASK
+    iowrite32(1, theadivs_data->hwregs + 0x3c); // INT_CLEAN
+    iowrite32(1, theadivs_data->hwregs + 0x28); // CLEAR
+    iowrite32(0, theadivs_data->hwregs + 0x40); // INT_MASK
+
+    return IRQ_HANDLED;
+}
+
+
+module_init(theadivs_init);
+module_exit(theadivs_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("T-HEAD");
+MODULE_DESCRIPTION("T-HEAD ISP-VENC-SHAKE driver");
+

+ 71 - 0
kernel_mode/isp_venc_shake_driver.h

@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 - 2022  Alibaba Group. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _ISP_VENC_SHAKE_DRIVER_H_
+#define _ISP_VENC_SHAKE_DRIVER_H_
+#include <linux/ioctl.h>
+
+#define THEAD_IOC_MAGIC  't'
+
+#define THEAD_IOCH_CONFIG_IVS    _IOR(THEAD_IOC_MAGIC, 3, unsigned long *)
+#define THEAD_IOCH_START_IVS    _IOR(THEAD_IOC_MAGIC, 4, unsigned long *)
+#define THEAD_IOCH_RESET_IVS    _IOR(THEAD_IOC_MAGIC, 5, unsigned long *)
+#define THEAD_IOCH_GET_STATE    _IOR(THEAD_IOC_MAGIC, 6, int *)
+
+#define THEAD_IOC_MAXNR 6
+
+typedef int8_t    i8;
+typedef uint8_t   u8;
+typedef int16_t   i16;
+typedef uint16_t  u16;
+typedef int32_t   i32;
+typedef uint32_t  u32;
+typedef int64_t   i64;
+typedef uint64_t  u64;
+
+typedef enum _theadivs_state
+{
+    THEADIVS_IDLE,
+    THEADIVS_READY,
+    THEADIVS_RUNNING,
+    THEADIVS_ERROR
+} theadivs_state;
+
+struct ivs_parameter
+{
+  u32 pic_width;
+  u32 pic_height;
+  u32 encode_width;
+  u32 encode_height;
+  u32 wid_y;
+  u32 wid_uv;
+  u32 sram_size;
+  u32 encode_n;
+  u32 stride_y;
+  u32 stride_uv;
+  //u32 clear;
+  u32 encode_x;
+  u32 encode_y;
+  //u32 start;
+  //u32 int_state;
+  //u32 int_clean;
+  u32 int_mask;
+  //u32 signal_resv;
+};
+
+#endif /* !_ISP_VENC_SHAKE_DRIVER_H_ */

+ 73 - 0
test/Makefile

@@ -0,0 +1,73 @@
+
+CFLAGS = -Wall -D_GNU_SOURCE -D_REENTRANT -D_THREAD_SAFE -O2 -Werror -Wno-unused -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-strict-overflow -Wno-array-bounds -Wno-shift-negative-value -Wempty-body -Wtype-limits -Wno-unused-result -fPIC -Wmissing-field-initializers -std=gnu99
+
+INCLUDE += -I../user_mode
+
+SRCS = isp_venc_shake.c
+OBJS = $(SRCS:.c=.o)
+
+#source search path
+vpath %.c
+
+# name of the outputfile (library)
+IVSLIB = ../user_mode/libivs.a
+IVSSLIB = ../user_mode/libivs.so
+TARGET = ivs_test
+
+#Here are rules for building codes and generating object library.
+all:    tags
+	@echo ---------------------------------------
+	@echo "Usage: make [ system | testdata | versatile | integrator | android]"
+	@echo "system     - PC system model (== pclinux)"
+	@echo "testdata   - PC system model for test data creation"
+	@echo "eval       - PC system model for evaluation with frame limit"
+	@echo "versatile  - ARM versatile with FPGA HW"
+	@echo "integrator - ARM integrator with FPGA HW"
+	@echo "android    - ARM android"
+	@echo "NOTE! Make sure to do 'make clean'"
+	@echo "between compiling to different targets!"
+	@echo ---------------------------------------
+
+.PHONY: system_lib system testdata clean depend
+
+evaluation: eval
+eval: system
+
+system_static: testdata
+system: testdata
+
+# for libva
+system_lib: system
+
+testdata: .depend $(IVSLIB)
+
+
+.PHONY: hwlinux
+hwlinux:
+hwlinux: .depend $(TARGET)
+
+$(TARGET): $(OBJS)
+	$(CC) $(CFLAGS) $(OBJS) $(IVSLIB) -lm -lpthread -o $(TARGET)
+
+
+
+%.o: %.c
+	$(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@
+
+clean:
+	$(RM) $(TARGET)
+	$(RM) .depend
+	$(RM) *.o *.gcno *.gcda
+
+tags:
+	ctags ../kernel_mode/*h ./*[ch]
+
+depend .depend: $(SRCS)
+	@echo "[CC] $@"
+	@$(CC) -M $(DEBFLAGS) $(INCLUDE) $^ > .depend
+
+ifneq (clean, $(findstring clean, $(MAKECMDGOALS)))
+ifeq (.depend, $(wildcard .depend))
+include .depend
+endif
+endif

+ 76 - 0
test/isp_venc_shake.c

@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2021-2022 Alibaba Group. All rights reserved.
+ * License-Identifier: Apache-2.0
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include "isp_venc_shake_hal.h"
+
+#ifndef NULL
+#define NULL    ((void *)0)
+#endif
+
+
+int main(void)
+{
+    void *ivs = NULL;
+    IvsConfig config;
+    IvsStatus status = IVS_STATUS_OK;
+
+    do
+    {
+        status = createIspVencShake(&ivs);
+        if (status != IVS_STATUS_OK)
+            break;
+
+        status = resetIspVencShake(ivs);
+        
+        config.mode = IVS_BUFFER_MODE_FRAME;
+        config.encode = IVS_ENCODER_FORMAT_H264;
+        config.pic_width = 640;
+        config.pic_height = 480;
+        config.encode_width = 640;
+        config.encode_height = 480;
+        config.buffer_height = 240;
+        config.stride_y = 640;
+        config.stride_uv = 640;
+        config.encode_x = 0;
+        config.encode_y = 0;
+        status = configIspVencShake(ivs, &config);
+        if (status != IVS_STATUS_OK)
+            break;
+        
+        status = startIspVencShake(ivs);
+        if (status != IVS_STATUS_OK)
+            break;
+
+        sleep(90);
+
+        status = resetIspVencShake(ivs);
+        if (status != IVS_STATUS_OK)
+            break;
+    } while (0);
+    
+    destroyIspVencShake(ivs);
+
+    if (status != IVS_STATUS_OK)
+        printf("ERROR: ivs_test exit with error!\n");
+    else
+        printf("ivs_test done!\n");
+
+    return (status == IVS_STATUS_OK ? 0 : 1);
+}
+

+ 75 - 0
user_mode/Makefile

@@ -0,0 +1,75 @@
+
+CFLAGS = -Wall -D_GNU_SOURCE -D_REENTRANT -D_THREAD_SAFE -O2 -Werror -Wno-unused -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-strict-overflow -Wno-array-bounds -Wno-shift-negative-value -Wempty-body -Wtype-limits -Wno-unused-result -fPIC -Wmissing-field-initializers -std=gnu99
+
+INCLUDE += -I../kernel_mode
+
+SRCS = isp_venc_shake_hal.c
+OBJS = $(SRCS:.c=.o)
+
+#source search path
+vpath %.c
+
+# name of the outputfile (library)
+IVSLIB = libivs.a
+IVSSLIB = libivs.so
+
+#Here are rules for building codes and generating object library.
+all:    tags
+	@echo ---------------------------------------
+	@echo "Usage: make [ system | testdata | versatile | integrator | android]"
+	@echo "system     - PC system model (== pclinux)"
+	@echo "testdata   - PC system model for test data creation"
+	@echo "eval       - PC system model for evaluation with frame limit"
+	@echo "versatile  - ARM versatile with FPGA HW"
+	@echo "integrator - ARM integrator with FPGA HW"
+	@echo "android    - ARM android"
+	@echo "NOTE! Make sure to do 'make clean'"
+	@echo "between compiling to different targets!"
+	@echo ---------------------------------------
+
+.PHONY: system_lib system testdata clean depend
+
+evaluation: eval
+eval: system
+
+system_static: testdata
+system: testdata
+
+# for libva
+system_lib: system
+
+testdata: .depend $(IVSLIB)
+
+
+.PHONY: hwlinux
+hwlinux:
+hwlinux: .depend $(IVSLIB) $(IVSSLIB)
+
+$(IVSLIB): $(OBJS)
+	@echo "[AR] $@"
+	$(AR) rcs $(IVSLIB) $(OBJS)
+
+$(IVSSLIB): $(OBJS)
+	$(CC) -fPIC -Wl,-no-undefined -shared $(CFLAGS) $(OBJS) -lm -lpthread -o $(IVSSLIB)
+
+
+%.o: %.c
+	$(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@
+
+clean:
+	$(RM) $(IVSLIB) $(IVSSLIB)
+	$(RM) .depend
+	$(RM) *.o *.gcno *.gcda
+
+tags:
+	ctags ../kernel_mode/*h ./*[ch]
+
+depend .depend: $(SRCS)
+	@echo "[CC] $@"
+	@$(CC) -M $(DEBFLAGS) $(INCLUDE) $^ > .depend
+
+ifneq (clean, $(findstring clean, $(MAKECMDGOALS)))
+ifeq (.depend, $(wildcard .depend))
+include .depend
+endif
+endif

+ 160 - 0
user_mode/isp_venc_shake_hal.c

@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2021-2022 Alibaba Group. All rights reserved.
+ * License-Identifier: Apache-2.0
+ *
+ * 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.
+ */
+
+#include <stdint.h>
+#include <malloc.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "isp_venc_shake_driver.h"
+#include "isp_venc_shake_hal.h"
+#include <sys/ioctl.h>
+
+#ifndef NULL
+#define NULL    ((void *)0)
+#endif
+
+
+#ifndef IVS_MODULE_PATH
+#define IVS_MODULE_PATH             "/dev/shake"
+#endif
+
+typedef struct _IspVencShake
+{
+    unsigned int fd;
+    struct ivs_parameter params;
+} IspVencShake;
+
+IvsStatus createIspVencShake(void **ivs)
+{
+    IvsStatus status = IVS_STATUS_OK;
+    IspVencShake *shake = NULL;
+    unsigned int fd;
+    
+    shake = (IspVencShake *)malloc(sizeof(IspVencShake));
+    if (NULL == shake)
+        return IVS_STATUS_ERROR;
+
+    fd = open("/dev/shake", O_RDONLY);
+    if (fd == -1)
+    {
+        free(shake);
+        return IVS_STATUS_ERROR;
+    }
+
+    shake->fd = fd;
+    *ivs = shake;
+
+    return status;
+}
+
+IvsStatus configIspVencShake(void *ivs, IvsConfig *config)
+{
+    IvsStatus status = IVS_STATUS_OK;
+    IspVencShake *shake = (IspVencShake *)ivs;
+    struct ivs_parameter *params = NULL;
+    unsigned int buffer_height;
+
+    if (ivs == NULL || config == NULL)
+        return IVS_STATUS_ERROR;
+
+    params = &shake->params;
+    buffer_height = config->mode = IVS_BUFFER_MODE_SLICE ? 
+        config->buffer_height : config->pic_height * 3 / 2;
+
+    params->pic_width = config->pic_width;
+    params->pic_height = config->pic_height;
+    params->encode_width = config->encode_width;
+    params->encode_height = config->encode_height;
+    params->wid_y = 1;
+    params->wid_uv = 2;
+    params->sram_size = config->pic_width * buffer_height;
+    params->encode_n = config->encode == IVS_ENCODER_FORMAT_H264 ? 16 : 64;
+    params->stride_y = config->stride_y;
+    params->stride_uv = config->stride_uv;
+    params->encode_x = config->encode_x;
+    params->encode_y = config->encode_y;
+    params->int_mask = 0;
+
+    if (ioctl(shake->fd, THEAD_IOCH_CONFIG_IVS, params) == -1)
+    {
+        status = IVS_STATUS_ERROR;
+    }
+
+    return status;
+}
+
+IvsStatus startIspVencShake(void *ivs)
+{
+    IvsStatus status = IVS_STATUS_OK;
+    IspVencShake *shake = (IspVencShake *)ivs;
+
+    if (ivs == NULL)
+        return IVS_STATUS_ERROR;
+
+    if (ioctl(shake->fd, THEAD_IOCH_START_IVS, NULL) == -1)
+    {
+        status = IVS_STATUS_ERROR;
+    }
+
+    return status;
+}
+
+IvsStatus resetIspVencShake(void *ivs)
+{
+    IvsStatus status = IVS_STATUS_OK;
+    IspVencShake *shake = (IspVencShake *)ivs;
+
+    if (ivs == NULL)
+        return IVS_STATUS_ERROR;
+
+    if (ioctl(shake->fd, THEAD_IOCH_RESET_IVS, NULL) == -1)
+    {
+        status = IVS_STATUS_ERROR;
+    }
+
+    return status;
+}
+
+IvsStatus getIspVencShakeState(void *ivs, int *state)
+{
+    IvsStatus status = IVS_STATUS_OK;
+    IspVencShake *shake = (IspVencShake *)ivs;
+
+    if (ivs == NULL || state == NULL)
+        return IVS_STATUS_ERROR;
+
+    if (ioctl(shake->fd, THEAD_IOCH_GET_STATE, state) == -1)
+    {
+        status = IVS_STATUS_ERROR;
+    }
+
+    return status;
+}
+
+void destroyIspVencShake(void *ivs)
+{
+    IspVencShake *shake = (IspVencShake *)ivs;
+
+    if (NULL == ivs)
+        return;
+
+    if (shake->fd != -1)
+        close(shake->fd);
+
+    free(ivs);
+}
+

+ 75 - 0
user_mode/isp_venc_shake_hal.h

@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2021-2022 Alibaba Group. All rights reserved.
+ * License-Identifier: Apache-2.0
+ *
+ * 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.
+ */
+
+#ifndef _ISP_VENC_SHAKE_HAL_H_
+#define _ISP_VENC_SHAKE_HAL_H_
+
+#ifndef IVS_MODULE_PATH
+#define IVS_MODULE_PATH "/tmp/dev/theadivs"
+#endif
+
+typedef enum _IvsStatus
+{
+    IVS_STATUS_OK = 0,
+    IVS_STATUS_ERROR = -1,
+} IvsStatus;
+
+typedef enum _IvsState
+{
+    IVS_STATE_IDLE,
+    IVS_STATE_READY,
+    IVS_STATE_RUNNING,
+    IVS_STATE_ERROR
+} IvsState;
+
+typedef enum _IvsBufferMode
+{
+    IVS_BUFFER_MODE_FRAME = 0,
+    IVS_BUFFER_MODE_SLICE,
+    IVS_BUFFER_MODE_MAX
+} IvsBufferMode;
+
+typedef enum _IvsEncoderFormat
+{
+    IVS_ENCODER_FORMAT_H264 = 0,
+    IVS_ENCODER_FORMAT_H265,
+    IVS_ENCODER_FORMAT_MAX
+} IvsEncoderFormat;
+
+typedef struct _IvsConfig
+{
+    IvsBufferMode mode;
+    IvsEncoderFormat encode;
+    unsigned int pic_width;
+    unsigned int pic_height;
+    unsigned int encode_width;
+    unsigned int encode_height;
+    unsigned int buffer_height;   // valid in slice buffer mode only
+    unsigned int stride_y;
+    unsigned int stride_uv;
+    unsigned int encode_x;
+    unsigned int encode_y;
+} IvsConfig;
+
+IvsStatus createIspVencShake(void **ivs);
+IvsStatus configIspVencShake(void *ivs, IvsConfig *config);
+IvsStatus startIspVencShake(void *ivs);
+IvsStatus resetIspVencShake(void *ivs);
+IvsStatus getIspVencShakeState(void *ivs, int *state);
+void destroyIspVencShake(void *ivs);
+
+#endif /* !_ISP_VENC_SHAKE_HAL_H_ */