From f9a685e835d7c0ecb8c504e778bb90b8b36de709 Mon Sep 17 00:00:00 2001 From: thead_admin Date: Tue, 13 Sep 2022 10:33:13 +0800 Subject: [PATCH] Linux_SDK_V0.9.5 --- .gitignore | 29 ++ Makefile | 120 ++++++++ README.md | 12 + kernel_mode/Makefile | 6 + kernel_mode/isp_venc_shake_driver.c | 439 ++++++++++++++++++++++++++++ kernel_mode/isp_venc_shake_driver.h | 71 +++++ test/Makefile | 73 +++++ test/isp_venc_shake.c | 76 +++++ user_mode/Makefile | 75 +++++ user_mode/isp_venc_shake_hal.c | 160 ++++++++++ user_mode/isp_venc_shake_hal.h | 75 +++++ 11 files changed, 1136 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 kernel_mode/Makefile create mode 100644 kernel_mode/isp_venc_shake_driver.c create mode 100644 kernel_mode/isp_venc_shake_driver.h create mode 100755 test/Makefile create mode 100644 test/isp_venc_shake.c create mode 100755 user_mode/Makefile create mode 100644 user_mode/isp_venc_shake_hal.c create mode 100644 user_mode/isp_venc_shake_hal.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e0c3d40 --- /dev/null +++ b/.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/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ce40b43 --- /dev/null +++ b/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 + diff --git a/README.md b/README.md new file mode 100644 index 0000000..812cb57 --- /dev/null +++ b/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 diff --git a/kernel_mode/Makefile b/kernel_mode/Makefile new file mode 100644 index 0000000..b683436 --- /dev/null +++ b/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 diff --git a/kernel_mode/isp_venc_shake_driver.c b/kernel_mode/isp_venc_shake_driver.c new file mode 100644 index 0000000..e1289b3 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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(¶ms, (struct ivs_parameter*)arg, sizeof(struct ivs_parameter)); + config_ivs(filp, ¶ms); + 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"); + diff --git a/kernel_mode/isp_venc_shake_driver.h b/kernel_mode/isp_venc_shake_driver.h new file mode 100644 index 0000000..aa91a16 --- /dev/null +++ b/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 + +#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_ */ diff --git a/test/Makefile b/test/Makefile new file mode 100755 index 0000000..2c20831 --- /dev/null +++ b/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 diff --git a/test/isp_venc_shake.c b/test/isp_venc_shake.c new file mode 100644 index 0000000..6f4c126 --- /dev/null +++ b/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 +#include +#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); +} + diff --git a/user_mode/Makefile b/user_mode/Makefile new file mode 100755 index 0000000..fcd939f --- /dev/null +++ b/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 diff --git a/user_mode/isp_venc_shake_hal.c b/user_mode/isp_venc_shake_hal.c new file mode 100644 index 0000000..676f5f5 --- /dev/null +++ b/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 +#include +#include +#include +#include "isp_venc_shake_driver.h" +#include "isp_venc_shake_hal.h" +#include + +#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); +} + diff --git a/user_mode/isp_venc_shake_hal.h b/user_mode/isp_venc_shake_hal.h new file mode 100644 index 0000000..8d0b8cd --- /dev/null +++ b/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_ */