summaryrefslogtreecommitdiff
path: root/drivers/mxc/hantro
diff options
context:
space:
mode:
authorZhou Peng-B04994 <eagle.zhou@nxp.com>2017-06-21 14:57:33 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:41:33 +0300
commit77802b0a58ac4ab83ede7e210a37adca7437bf51 (patch)
tree571673dae7a5c95d2dd92f7dce466b6567edfba4 /drivers/mxc/hantro
parentfd2261731a523bce300f197c4a9a74ae7a6fa3b1 (diff)
MLK-15132-1: Enable Hantro decoder on i.MX8MQ
Added hantro driver code Signed-off-by: Zhou Peng-B04994 <eagle.zhou@nxp.com>
Diffstat (limited to 'drivers/mxc/hantro')
-rwxr-xr-xdrivers/mxc/hantro/Kconfig14
-rwxr-xr-xdrivers/mxc/hantro/Makefile10
-rwxr-xr-xdrivers/mxc/hantro/dwl_defs.h95
-rwxr-xr-xdrivers/mxc/hantro/hantrodec.c2074
-rwxr-xr-xdrivers/mxc/hantro/hantrodec.h93
5 files changed, 2286 insertions, 0 deletions
diff --git a/drivers/mxc/hantro/Kconfig b/drivers/mxc/hantro/Kconfig
new file mode 100755
index 000000000000..55ea8ee722b9
--- /dev/null
+++ b/drivers/mxc/hantro/Kconfig
@@ -0,0 +1,14 @@
+#
+# Codec configuration
+#
+
+menu "MXC HANTRO(Video Processing Unit) support"
+ depends on ARCH_FSL_IMX8MQ
+
+config MXC_HANTRO
+ tristate "Support for MXC HANTRO(Video Processing Unit)"
+ default y
+ ---help---
+ VPU codec device.
+
+endmenu
diff --git a/drivers/mxc/hantro/Makefile b/drivers/mxc/hantro/Makefile
new file mode 100755
index 000000000000..617c232816d1
--- /dev/null
+++ b/drivers/mxc/hantro/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the VPU drivers.
+#
+
+EXTRA_CFLAGS += -I$(PWD)/./dwl
+#EXTRA_CFLAGS += -DUSE_64BIT_ENV
+
+obj-$(CONFIG_MXC_HANTRO) += hantrodec.o
+
+
diff --git a/drivers/mxc/hantro/dwl_defs.h b/drivers/mxc/hantro/dwl_defs.h
new file mode 100755
index 000000000000..3018d39c8e7f
--- /dev/null
+++ b/drivers/mxc/hantro/dwl_defs.h
@@ -0,0 +1,95 @@
+/*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (c) 2015-2017, VeriSilicon Inc.
+* Copyright (c) 2011-2014, Google Inc.
+*
+* 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 SOFTWARE_LINUX_DWL_DWL_DEFS_H_
+#define SOFTWARE_LINUX_DWL_DWL_DEFS_H_
+
+#define DWL_MPEG2_E 31 /* 1 bit */
+#define DWL_VC1_E 29 /* 2 bits */
+#define DWL_JPEG_E 28 /* 1 bit */
+#define DWL_MPEG4_E 26 /* 2 bits */
+#define DWL_H264_E 24 /* 2 bits */
+#define DWL_VP6_E 23 /* 1 bit */
+#define DWL_RV_E 26 /* 2 bits */
+#define DWL_VP8_E 23 /* 1 bit */
+#define DWL_VP7_E 24 /* 1 bit */
+#define DWL_WEBP_E 19 /* 1 bit */
+#define DWL_AVS_E 22 /* 1 bit */
+#if 0
+#define DWL_PP_E 16 /* 1 bit */
+#endif
+#define DWL_PP_E 31 /* 1 bit */
+#define DWL_HEVC_E 5 /* 2 bits */
+#define DWL_VP9_E 3 /* 2 bits */
+
+#define DWL_HEVC_ENA 0 /* 1 bits */
+#define DWL_VP9_ENA 1 /* 1 bits */
+#define DWL_RFC_E 2 /* 1 bits */
+#define DWL_DS_E 3 /* 1 bits */
+#define DWL_HEVC_VER 8 /* 4 bits */
+#define DWL_VP9_PROFILE 12 /* 3 bits */
+#define DWL_RING_E 16 /* 1 bits */
+
+#define HANTRODEC_IRQ_STAT_DEC 1
+#define HANTRODEC_IRQ_STAT_DEC_OFF (HANTRODEC_IRQ_STAT_DEC * 4)
+
+#define HANTRODECPP_SYNTH_CFG 60
+#define HANTRODECPP_SYNTH_CFG_OFF (HANTRODECPP_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG 50
+#define HANTRODEC_SYNTH_CFG_OFF (HANTRODEC_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG_2 54
+#define HANTRODEC_SYNTH_CFG_2_OFF (HANTRODEC_SYNTH_CFG_2 * 4)
+#define HANTRODEC_SYNTH_CFG_3 56
+#define HANTRODEC_SYNTH_CFG_3_OFF (HANTRODEC_SYNTH_CFG_3 * 4)
+#define HANTRODEC_CFG_STAT 23
+#define HANTRODEC_CFG_STAT_OFF (HANTRODEC_CFG_STAT * 4)
+
+
+#define HANTRODEC_DEC_E 0x01
+#define HANTRODEC_PP_E 0x01
+#define HANTRODEC_DEC_ABORT 0x20
+#define HANTRODEC_DEC_IRQ_DISABLE 0x10
+#define HANTRODEC_DEC_IRQ 0x100
+
+/* Legacy from G1 */
+#define HANTRO_IRQ_STAT_DEC 1
+#define HANTRO_IRQ_STAT_DEC_OFF (HANTRO_IRQ_STAT_DEC * 4)
+#define HANTRO_IRQ_STAT_PP 60
+#define HANTRO_IRQ_STAT_PP_OFF (HANTRO_IRQ_STAT_PP * 4)
+
+#define HANTROPP_SYNTH_CFG 100
+#define HANTROPP_SYNTH_CFG_OFF (HANTROPP_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG 50
+#define HANTRODEC_SYNTH_CFG_OFF (HANTRODEC_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG_2 54
+#define HANTRODEC_SYNTH_CFG_2_OFF (HANTRODEC_SYNTH_CFG_2 * 4)
+
+#define HANTRO_DEC_E 0x01
+#define HANTRO_PP_E 0x01
+#define HANTRO_DEC_ABORT 0x20
+#define HANTRO_DEC_IRQ_DISABLE 0x10
+#define HANTRO_PP_IRQ_DISABLE 0x10
+#define HANTRO_DEC_IRQ 0x100
+#define HANTRO_PP_IRQ 0x100
+
+#endif /* SOFTWARE_LINUX_DWL_DWL_DEFS_H_ */
diff --git a/drivers/mxc/hantro/hantrodec.c b/drivers/mxc/hantro/hantrodec.c
new file mode 100755
index 000000000000..2b454b98d88b
--- /dev/null
+++ b/drivers/mxc/hantro/hantrodec.c
@@ -0,0 +1,2074 @@
+/*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (c) 2015-2017, VeriSilicon Inc.
+* Copyright (c) 2011-2014, Google Inc.
+*
+* 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 "hantrodec.h"
+#include "dwl_defs.h"
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+
+/*hantro G1 regs config including dec and pp*/
+#define HANTRO_DEC_ORG_REGS 60
+#define HANTRO_PP_ORG_REGS 41
+
+#define HANTRO_DEC_EXT_REGS 27
+#define HANTRO_PP_EXT_REGS 9
+
+#define HANTRO_G1_DEC_TOTAL_REGS (HANTRO_DEC_ORG_REGS + HANTRO_DEC_EXT_REGS)
+#define HANTRO_PP_TOTAL_REGS (HANTRO_PP_ORG_REGS + HANTRO_PP_EXT_REGS)
+#define HANTRO_G1_TOTAL_REGS 155 /*G1 total regs*/
+
+#define HANTRO_DEC_ORG_FIRST_REG 0
+#define HANTRO_DEC_ORG_LAST_REG 59
+#define HANTRO_DEC_EXT_FIRST_REG 119
+#define HANTRO_DEC_EXT_LAST_REG 145
+
+#define HANTRO_PP_ORG_FIRST_REG 60
+#define HANTRO_PP_ORG_LAST_REG 100
+#define HANTRO_PP_EXT_FIRST_REG 146
+#define HANTRO_PP_EXT_LAST_REG 154
+
+/*hantro G2 reg config*/
+#define HANTRO_G2_DEC_REGS 265 /*G2 total regs*/
+
+#define HANTRO_G2_DEC_FIRST_REG 0
+#define HANTRO_G2_DEC_LAST_REG HANTRO_G2_DEC_REGS-1
+
+/* Logic module IRQs */
+#define HXDEC_NO_IRQ -1
+
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#define DEC_IO_SIZE_MAX (MAX(HANTRO_G2_DEC_REGS, HANTRO_G1_TOTAL_REGS)* 4)
+
+/********************************************************************
+* PORTING SEGMENT
+* NOTES: customer should modify these configuration if do porting to own platform.
+* Please guarantee the base_addr, io_size,dec_irq belong to same core.
+********************************************************************/
+
+#define HXDEC_MAX_CORES 4
+#define MULTI_CORE /*this macro defines single core or multicore*/
+//#define CLK_CFG /*this macro defines use kernel clk cfg or not*/
+#ifdef CLK_CFG
+#define CLK_ID "hantrodec_clk" /*this id should conform with platform define*/
+#endif
+
+/* Logic module base address */
+#define SOCLE_LOGIC_0_BASE 0x38300000
+#define SOCLE_LOGIC_1_BASE 0x38310000
+
+#define VEXPRESS_LOGIC_0_BASE 0xFC010000
+#define VEXPRESS_LOGIC_1_BASE 0xFC020000
+
+#ifdef USE_64BIT_ENV
+#define DEC_IO_SIZE_0 ((HANTRO_G2_DEC_REGS) * 4) /* bytes */
+#else
+#define DEC_IO_SIZE_0 ((HANTRO_G2_DEC_REGS) * 4) /* bytes */
+#endif
+#ifdef MULTI_CORE
+#ifdef USE_64BIT_ENV
+#define DEC_IO_SIZE_1 ((HANTRO_G2_DEC_REGS) * 4) /* bytes */
+#else
+#define DEC_IO_SIZE_1 ((HANTRO_G2_DEC_REGS) * 4) /* bytes */
+#endif
+
+#endif
+#define DEC_IRQ_0 7
+#ifdef MULTI_CORE
+#define DEC_IRQ_1 8
+#endif
+
+/***********************************************************************/
+
+#define IS_G1(hw_id) ((hw_id == 0x6731)? 1:0)
+
+static const int DecHwId[] = {
+ 0x8190, /* Legacy HW */
+ 0x8170,
+ 0x9170,
+ 0x9190,
+ 0x6731, /* G1 */
+ 0x6732 /* G2 */
+};
+
+unsigned long base_port = -1; /*for single core and set when module init*/
+volatile unsigned char *reg = NULL;
+
+ulong multicorebase[HXDEC_MAX_CORES] = {
+ SOCLE_LOGIC_0_BASE,
+ SOCLE_LOGIC_1_BASE,
+ -1,
+ -1
+};
+
+int irq_0 = DEC_IRQ_0;
+#ifndef MULTI_CORE
+int elements = 1;
+#else
+int irq_1 = DEC_IRQ_1;
+int elements = 2;
+#endif
+
+#ifdef CLK_CFG
+ struct clk *clk_cfg;
+ int is_clk_on;
+ struct timer_list timer;
+#endif
+
+#ifndef VSI //1NXP
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+//#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+
+static struct class *hantro_class;
+#define DEVICE_NAME "mxc_hantro"
+
+static struct device *hantro_dev;
+static struct clk *hantro_clk_g1;
+static struct clk *hantro_clk_g2;
+static struct clk * hantro_clk_bus;
+
+int irq_g1=0;
+int irq_g2=0;
+static irqreturn_t hantrodec_isr_g1(int irq, void *dev_id);
+
+static int hantro_dbg=0;
+module_param(hantro_dbg, int, 0644);
+MODULE_PARM_DESC(hantro_dbg, "Debug level (0-1)");
+#undef PDEBUG
+#define PDEBUG(fmt, arg...) \
+ do { \
+ if (hantro_dbg > 0){printk(KERN_DEBUG fmt ,## arg);} \
+ } while (0)
+
+#endif
+
+/* module_param(name, type, perm) */
+module_param(base_port, ulong, 0);
+module_param(irq_0, int, 0);
+module_param_array(multicorebase, ulong, &elements, 0644);
+
+static int hantrodec_major = 0; /* dynamic allocation */
+static const struct of_device_id mmp_timer_dt_ids_0[] = {
+ { .compatible = "nxp,imx8dv-g1", },
+ {}
+};
+#ifdef MULTI_CORE
+static const struct of_device_id mmp_timer_dt_ids_1[] = {
+ { .compatible = "nxp,imx8dv-g2", },
+ {}
+};
+#endif
+
+
+/* here's all the must remember stuff */
+typedef struct {
+ char *buffer;
+ unsigned int iosize[HXDEC_MAX_CORES];
+ volatile u8 *hwregs[HXDEC_MAX_CORES];
+ int irq[HXDEC_MAX_CORES];
+ int hw_id[HXDEC_MAX_CORES];
+ int cores;
+ struct fasync_struct *async_queue_dec;
+ struct fasync_struct *async_queue_pp;
+} hantrodec_t;
+
+static hantrodec_t hantrodec_data; /* dynamic allocation? */
+
+static int ReserveIO(void);
+static void ReleaseIO(void);
+
+static void ResetAsic(hantrodec_t * dev);
+
+#ifdef HANTRODEC_DEBUG
+static void dump_regs(hantrodec_t *dev);
+#endif
+
+/* IRQ handler */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+static irqreturn_t hantrodec_isr(int irq, void *dev_id, struct pt_regs *regs);
+#else
+static irqreturn_t hantrodec_isr(int irq, void *dev_id);
+#endif
+
+
+static u32 dec_regs[HXDEC_MAX_CORES][DEC_IO_SIZE_MAX/4];
+struct semaphore dec_core_sem;
+struct semaphore pp_core_sem;
+
+static int dec_irq = 0;
+static int pp_irq = 0;
+
+atomic_t irq_rx = ATOMIC_INIT(0);
+atomic_t irq_tx = ATOMIC_INIT(0);
+
+static struct file* dec_owner[HXDEC_MAX_CORES];
+static struct file* pp_owner[HXDEC_MAX_CORES];
+
+/* spinlock_t owner_lock = SPIN_LOCK_UNLOCKED; */
+DEFINE_SPINLOCK(owner_lock);
+
+DECLARE_WAIT_QUEUE_HEAD(dec_wait_queue);
+DECLARE_WAIT_QUEUE_HEAD(pp_wait_queue);
+
+DECLARE_WAIT_QUEUE_HEAD(hw_queue);
+#ifdef CLK_CFG
+DEFINE_SPINLOCK(clk_lock);
+#endif
+
+#define DWL_CLIENT_TYPE_H264_DEC 1U
+#define DWL_CLIENT_TYPE_MPEG4_DEC 2U
+#define DWL_CLIENT_TYPE_JPEG_DEC 3U
+#define DWL_CLIENT_TYPE_PP 4U
+#define DWL_CLIENT_TYPE_VC1_DEC 5U
+#define DWL_CLIENT_TYPE_MPEG2_DEC 6U
+#define DWL_CLIENT_TYPE_VP6_DEC 7U
+#define DWL_CLIENT_TYPE_AVS_DEC 8U
+#define DWL_CLIENT_TYPE_RV_DEC 9U
+#define DWL_CLIENT_TYPE_VP8_DEC 10U
+#define DWL_CLIENT_TYPE_VP9_DEC 11U
+#define DWL_CLIENT_TYPE_HEVC_DEC 12U
+
+static u32 cfg[HXDEC_MAX_CORES];
+
+static void ReadCoreConfig(hantrodec_t *dev) {
+ int c;
+ u32 reg, tmp, mask;
+
+ memset(cfg, 0, sizeof(cfg));
+
+ for(c = 0; c < dev->cores; c++) {
+ /* Decoder configuration */
+ if (IS_G1(dev->hw_id[c])) {
+ reg = ioread32(dev->hwregs[c] + HANTRODEC_SYNTH_CFG * 4);
+
+ tmp = (reg >> DWL_H264_E) & 0x3U;
+ if(tmp) printk(KERN_INFO "hantrodec: Core[%d] has H264\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+ tmp = (reg >> DWL_JPEG_E) & 0x01U;
+ if(tmp) printk(KERN_INFO "hantrodec: Core[%d] has JPEG\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+
+ tmp = (reg >> DWL_MPEG4_E) & 0x3U;
+ if(tmp) printk(KERN_INFO "hantrodec: Core[%d] has MPEG4\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG4_DEC : 0;
+
+ tmp = (reg >> DWL_VC1_E) & 0x3U;
+ if(tmp) printk(KERN_INFO "hantrodec: Core[%d] has VC1\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VC1_DEC: 0;
+
+ tmp = (reg >> DWL_MPEG2_E) & 0x01U;
+ if(tmp) printk(KERN_INFO "hantrodec: Core[%d] has MPEG2\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG2_DEC : 0;
+
+ tmp = (reg >> DWL_VP6_E) & 0x01U;
+ if(tmp) printk(KERN_INFO "hantrodec: Core[%d] has VP6\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP6_DEC : 0;
+
+ reg = ioread32(dev->hwregs[c] + HANTRODEC_SYNTH_CFG_2 * 4);
+
+ /* VP7 and WEBP is part of VP8 */
+ mask = (1 << DWL_VP8_E) | (1 << DWL_VP7_E) | (1 << DWL_WEBP_E);
+ tmp = (reg & mask);
+ if(tmp & (1 << DWL_VP8_E))
+ printk(KERN_INFO "hantrodec: Core[%d] has VP8\n", c);
+ if(tmp & (1 << DWL_VP7_E))
+ printk(KERN_INFO "hantrodec: Core[%d] has VP7\n", c);
+ if(tmp & (1 << DWL_WEBP_E))
+ printk(KERN_INFO "hantrodec: Core[%d] has WebP\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP8_DEC : 0;
+
+ tmp = (reg >> DWL_AVS_E) & 0x01U;
+ if(tmp) printk(KERN_INFO "hantrodec: Core[%d] has AVS\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_AVS_DEC: 0;
+
+ tmp = (reg >> DWL_RV_E) & 0x03U;
+ if(tmp) printk(KERN_INFO "hantrodec: Core[%d] has RV\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_RV_DEC : 0;
+
+ /* Post-processor configuration */
+ reg = ioread32(dev->hwregs[c] + HANTROPP_SYNTH_CFG * 4);
+ }else {
+ reg = ioread32(dev->hwregs[c] + HANTRODEC_SYNTH_CFG_2 * 4);
+
+ tmp = (reg >> DWL_HEVC_E) & 0x3U;
+ if(tmp) printk(KERN_INFO "hantrodec: Core[%d] has HEVC\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_HEVC_DEC : 0;
+
+ tmp = (reg >> DWL_VP9_E) & 0x03U;
+ if(tmp) printk(KERN_INFO "hantrodec: Core[%d] has VP9\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP9_DEC : 0;
+ }
+
+ /* Post-processor configuration */
+ reg = ioread32(dev->hwregs[c] + HANTRODECPP_SYNTH_CFG * 4);
+
+ tmp = (reg >> DWL_PP_E) & 0x01U;
+ if(tmp) printk(KERN_INFO "hantrodec: Core[%d] has PP\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_PP : 0;
+ }
+}
+
+static int CoreHasFormat(const u32 *cfg, int Core, u32 format) {
+ return (cfg[Core] & (1 << format)) ? 1 : 0;
+}
+
+int GetDecCore(long Core, hantrodec_t *dev, struct file* filp) {
+ int success = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&owner_lock, flags);
+ if(dec_owner[Core] == NULL ) {
+ dec_owner[Core] = filp;
+ success = 1;
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return success;
+}
+
+int GetDecCoreAny(long *Core, hantrodec_t *dev, struct file* filp,
+ unsigned long format) {
+ int success = 0;
+ long c;
+
+ *Core = -1;
+
+ for(c = 0; c < dev->cores; c++) {
+ /* a free Core that has format */
+ if(CoreHasFormat(cfg, c, format) && GetDecCore(c, dev, filp)) {
+ success = 1;
+ *Core = c;
+ break;
+ }
+ }
+
+ return success;
+}
+int GetDecCoreID(hantrodec_t *dev, struct file* filp,
+ unsigned long format) {
+ long c;
+
+ int core_id = -1;
+
+ for(c = 0; c < dev->cores; c++) {
+ /* a Core that has format */
+ if(CoreHasFormat(cfg, c, format)) {
+ core_id = c;
+ break;
+ }
+ }
+ printk("GetDecCoreID=%d\n",core_id);
+ return core_id;
+}
+
+static int hantrodec_choose_core(int is_g1) {
+ volatile unsigned char *reg = NULL;
+ unsigned int blk_base = 0x38320000;
+
+ PDEBUG("hantrodec_choose_core\n");
+ if (!request_mem_region(blk_base, 0x1000, "blk_ctl"))
+ {
+ printk(KERN_INFO "blk_ctl: failed to reserve HW regs\n");
+ return -EBUSY;
+ }
+
+ reg = (volatile u8 *) ioremap_nocache(blk_base, 0x1000);
+
+ if (reg == NULL )
+ {
+ printk(KERN_INFO "blk_ctl: failed to ioremap HW regs\n");
+ if (reg)
+ iounmap((void *)reg);
+ release_mem_region(blk_base, 0x1000);
+ return -EBUSY;
+ }
+
+ // G1 use, set to 1; G2 use, set to 0, choose the one you are using
+ if (is_g1)
+ iowrite32(0x1, reg + 0x14); // VPUMIX only use G1, user should modify the reg according to platform design
+ else
+ iowrite32(0x0, reg + 0x14); // VPUMIX only use G2, user should modify the reg according to platform design
+
+ if (reg)
+ iounmap((void *)reg);
+ release_mem_region(blk_base, 0x1000);
+ PDEBUG("hantrodec_choose_core OK!\n");
+ return 0;
+}
+
+
+long ReserveDecoder(hantrodec_t *dev, struct file* filp, unsigned long format) {
+ long Core = -1;
+
+ /* reserve a Core */
+ if (down_interruptible(&dec_core_sem))
+ return -ERESTARTSYS;
+
+ /* lock a Core that has specific format*/
+ if(wait_event_interruptible(hw_queue,
+ GetDecCoreAny(&Core, dev, filp, format) != 0 ))
+ return -ERESTARTSYS;
+#if 1
+ if(IS_G1(dev->hw_id[Core]))
+ {
+ if (0 == hantrodec_choose_core(1))
+ printk("G1 is reserved\n");
+ else
+ return -1;
+ }
+ else
+ {
+ if (0 == hantrodec_choose_core(0))
+ printk("G2 is reserved\n");
+ else
+ return -1;
+ }
+#endif
+
+ return Core;
+}
+
+void ReleaseDecoder(hantrodec_t *dev, long Core) {
+ u32 status;
+ unsigned long flags;
+
+ status = ioread32(dev->hwregs[Core] + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+ /* make sure HW is disabled */
+ if(status & HANTRODEC_DEC_E) {
+ printk(KERN_INFO "hantrodec: DEC[%li] still enabled -> reset\n", Core);
+
+ /* abort decoder */
+ status |= HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+ iowrite32(status, dev->hwregs[Core] + HANTRODEC_IRQ_STAT_DEC_OFF);
+ }
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ dec_owner[Core] = NULL;
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ up(&dec_core_sem);
+
+ wake_up_interruptible_all(&hw_queue);
+
+}
+
+long ReservePostProcessor(hantrodec_t *dev, struct file* filp) {
+ unsigned long flags;
+
+ long Core = 0;
+
+ /* single Core PP only */
+ if (down_interruptible(&pp_core_sem))
+ return -ERESTARTSYS;
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ pp_owner[Core] = filp;
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return Core;
+}
+
+void ReleasePostProcessor(hantrodec_t *dev, long Core) {
+ unsigned long flags;
+
+ u32 status = ioread32(dev->hwregs[Core] + HANTRO_IRQ_STAT_PP_OFF);
+
+ /* make sure HW is disabled */
+ if(status & HANTRO_PP_E) {
+ printk(KERN_INFO "hantrodec: PP[%li] still enabled -> reset\n", Core);
+
+ /* disable IRQ */
+ status |= HANTRO_PP_IRQ_DISABLE;
+
+ /* disable postprocessor */
+ status &= (~HANTRO_PP_E);
+ iowrite32(0x10, dev->hwregs[Core] + HANTRO_IRQ_STAT_PP_OFF);
+ }
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ pp_owner[Core] = NULL;
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ up(&pp_core_sem);
+}
+
+long ReserveDecPp(hantrodec_t *dev, struct file* filp, unsigned long format) {
+ /* reserve Core 0, DEC+PP for pipeline */
+ unsigned long flags;
+
+ long Core = 0;
+
+ /* check that Core has the requested dec format */
+ if(!CoreHasFormat(cfg, Core, format))
+ return -EFAULT;
+
+ /* check that Core has PP */
+ if(!CoreHasFormat(cfg, Core, DWL_CLIENT_TYPE_PP))
+ return -EFAULT;
+
+ /* reserve a Core */
+ if (down_interruptible(&dec_core_sem))
+ return -ERESTARTSYS;
+
+ /* wait until the Core is available */
+ if(wait_event_interruptible(hw_queue,
+ GetDecCore(Core, dev, filp) != 0)) {
+ up(&dec_core_sem);
+ return -ERESTARTSYS;
+ }
+
+ if (down_interruptible(&pp_core_sem)) {
+ ReleaseDecoder(dev, Core);
+ return -ERESTARTSYS;
+ }
+
+ spin_lock_irqsave(&owner_lock, flags);
+ pp_owner[Core] = filp;
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return Core;
+}
+
+long DecFlushRegs(hantrodec_t *dev, struct core_desc *Core) {
+ long ret = 0, i;
+
+ u32 id = Core->id;
+
+ if (IS_G1(dev->hw_id[id])) {
+ /* copy original dec regs to kernal space*/
+ ret = copy_from_user(dec_regs[id], Core->regs, HANTRO_DEC_ORG_REGS*4);
+ if (ret) {
+ PDEBUG("copy_from_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+#ifdef USE_64BIT_ENV
+ /* copy extended dec regs to kernal space*/
+ ret = copy_from_user(dec_regs[id] + HANTRO_DEC_EXT_FIRST_REG,
+ Core->regs + HANTRO_DEC_EXT_FIRST_REG,
+ HANTRO_DEC_EXT_REGS*4);
+#endif
+ if (ret) {
+ PDEBUG("copy_from_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+
+ /* write dec regs but the status reg[1] to hardware */
+ /* both original and extended regs need to be written */
+ for(i = 2; i <= HANTRO_DEC_ORG_LAST_REG; i++)
+ {
+ iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+ }
+#ifdef USE_64BIT_ENV
+ for(i = HANTRO_DEC_EXT_FIRST_REG; i <= HANTRO_DEC_EXT_LAST_REG; i++)
+ iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+#endif
+ } else {
+ ret = copy_from_user(dec_regs[id], Core->regs, HANTRO_G2_DEC_REGS*4);
+ if (ret) {
+ PDEBUG("copy_from_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+
+ /* write all regs but the status reg[1] to hardware */
+ for(i = 2; i <= HANTRO_G2_DEC_LAST_REG; i++)
+ {
+ #if 0
+ if(i==2)
+ //dec_regs[id][i] = 0x78777777;
+ //dec_regs[id][i] = 0x78778787;
+ //c_regs[id][i] = 0x78888888; //64bit
+ {
+ printk("reg2=%08x\n",dec_regs[id][i]);
+ //dec_regs[id][i] = 0xF0F00000;//128bit 0xF0F0F000
+ }
+ //dec_regs[id][i] = 0xF0F0000F;//128bit 0xF0F00000 for big endian
+ if(i==58)
+ {
+ printk("reg58=%08x\n",dec_regs[id][i]);
+ //dec_regs[id][i]= 0x210;//128bit
+ //dec_regs[id][i]= 0x110;//64bit
+ }
+ if(i==3)
+ {
+ printk("reg3=%08x\n",dec_regs[id][i]);
+ //dec_regs[id][i] |= 0x00F00000;//128bit
+ //dec_regs[id][i]= 0x110;//64bit
+ }
+ #endif
+ iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+
+ }
+ }
+
+ /* write the status register, which may start the decoder */
+ iowrite32(dec_regs[id][1], dev->hwregs[id] + 4);
+
+ PDEBUG("flushed registers on Core %d\n", id);
+
+ return 0;
+}
+
+long DecRefreshRegs(hantrodec_t *dev, struct core_desc *Core) {
+ long ret, i;
+ u32 id = Core->id;
+
+ if (IS_G1(dev->hw_id[id])) {
+#ifdef USE_64BIT_ENV
+ /* user has to know exactly what they are asking for */
+#if 1 //eagle for compiler
+ PDEBUG("DecRefreshRegs: size: %d \n", Core->size);
+#else
+ if(Core->size != (HANTRO_DEC_TOTAL_REGS * 4))
+ return -EFAULT;
+#endif
+#else
+ /* user has to know exactly what they are asking for */
+ //if(Core->size != (HANTRO_DEC_ORG_REGS * 4))
+ // return -EFAULT;
+#endif
+ /* read all registers from hardware */
+ /* both original and extended regs need to be read */
+ for(i = 0; i <= HANTRO_DEC_ORG_LAST_REG; i++)
+ dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+#ifdef USE_64BIT_ENV
+ for(i = HANTRO_DEC_EXT_FIRST_REG; i <= HANTRO_DEC_EXT_LAST_REG; i++)
+ dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+#endif
+ /* put registers to user space*/
+ /* put original registers to user space*/
+ ret = copy_to_user(Core->regs, dec_regs[id], HANTRO_DEC_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+ /*put extended registers to user space*/
+ ret = copy_to_user(Core->regs + HANTRO_DEC_EXT_FIRST_REG,
+ dec_regs[id] + HANTRO_DEC_EXT_FIRST_REG,
+ HANTRO_DEC_EXT_REGS * 4);
+#endif
+ if (ret) {
+ PDEBUG("copy_to_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+ } else {
+ /* user has to know exactly what they are asking for */
+ if(Core->size != (HANTRO_G2_DEC_REGS * 4))
+ return -EFAULT;
+
+ /* read all registers from hardware */
+ for(i = 0; i <= HANTRO_G2_DEC_LAST_REG; i++)
+ dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+
+ /* put registers to user space*/
+ ret = copy_to_user(Core->regs, dec_regs[id], HANTRO_G2_DEC_REGS*4);
+ if (ret) {
+ PDEBUG("copy_to_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+ }
+ return 0;
+}
+
+static int CheckDecIrq(hantrodec_t *dev, int id) {
+ unsigned long flags;
+ int rdy = 0;
+
+ const u32 irq_mask = (1 << id);
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ if(dec_irq & irq_mask) {
+ /* reset the wait condition(s) */
+ dec_irq &= ~irq_mask;
+ rdy = 1;
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return rdy;
+}
+
+long WaitDecReadyAndRefreshRegs(hantrodec_t *dev, struct core_desc *Core) {
+ u32 id = Core->id;
+
+ PDEBUG("wait_event_interruptible DEC[%d]\n", id);
+
+ if(wait_event_interruptible(dec_wait_queue, CheckDecIrq(dev, id))) {
+ PDEBUG("DEC[%d] wait_event_interruptible interrupted\n", id);
+ return -ERESTARTSYS;
+ }
+
+ atomic_inc(&irq_tx);
+
+ /* refresh registers */
+ return DecRefreshRegs(dev, Core);
+}
+
+long PPFlushRegs(hantrodec_t *dev, struct core_desc *Core) {
+ long ret = 0;
+ u32 id = Core->id;
+ u32 i;
+
+ /* copy original dec regs to kernal space*/
+ ret = copy_from_user(dec_regs[id] + HANTRO_PP_ORG_FIRST_REG,
+ Core->regs + HANTRO_PP_ORG_FIRST_REG,
+ HANTRO_PP_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+ /* copy extended dec regs to kernal space*/
+ ret = copy_from_user(dec_regs[id] + HANTRO_PP_EXT_FIRST_REG,
+ Core->regs + HANTRO_PP_EXT_FIRST_REG,
+ HANTRO_PP_EXT_REGS*4);
+#endif
+ if (ret) {
+ PDEBUG("copy_from_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+
+ /* write all regs but the status reg[1] to hardware */
+ /* both original and extended regs need to be written */
+ for(i = HANTRO_PP_ORG_FIRST_REG + 1; i <= HANTRO_PP_ORG_LAST_REG; i++)
+ iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+#ifdef USE_64BIT_ENV
+ for(i = HANTRO_PP_EXT_FIRST_REG; i <= HANTRO_PP_EXT_LAST_REG; i++)
+ iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+#endif
+ /* write the stat reg, which may start the PP */
+ iowrite32(dec_regs[id][HANTRO_PP_ORG_FIRST_REG],
+ dev->hwregs[id] + HANTRO_PP_ORG_FIRST_REG * 4);
+
+ return 0;
+}
+
+long PPRefreshRegs(hantrodec_t *dev, struct core_desc *Core) {
+ long i, ret;
+ u32 id = Core->id;
+#ifdef USE_64BIT_ENV
+ /* user has to know exactly what they are asking for */
+ if(Core->size != (HANTRO_PP_TOTAL_REGS * 4))
+ return -EFAULT;
+#else
+ /* user has to know exactly what they are asking for */
+ if(Core->size != (HANTRO_PP_ORG_REGS * 4))
+ return -EFAULT;
+#endif
+
+ /* read all registers from hardware */
+ /* both original and extended regs need to be read */
+ for(i = HANTRO_PP_ORG_FIRST_REG; i <= HANTRO_PP_ORG_LAST_REG; i++)
+ dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+#ifdef USE_64BIT_ENV
+ for(i = HANTRO_PP_EXT_FIRST_REG; i <= HANTRO_PP_EXT_LAST_REG; i++)
+ dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+#endif
+ /* put registers to user space*/
+ /* put original registers to user space*/
+ ret = copy_to_user(Core->regs + HANTRO_PP_ORG_FIRST_REG,
+ dec_regs[id] + HANTRO_PP_ORG_FIRST_REG,
+ HANTRO_PP_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+ /* put extended registers to user space*/
+ ret = copy_to_user(Core->regs + HANTRO_PP_EXT_FIRST_REG,
+ dec_regs[id] + HANTRO_PP_EXT_FIRST_REG,
+ HANTRO_PP_EXT_REGS * 4);
+#endif
+ if (ret) {
+ PDEBUG("copy_to_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int CheckPPIrq(hantrodec_t *dev, int id) {
+ unsigned long flags;
+ int rdy = 0;
+
+ const u32 irq_mask = (1 << id);
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ if(pp_irq & irq_mask) {
+ /* reset the wait condition(s) */
+ pp_irq &= ~irq_mask;
+ rdy = 1;
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return rdy;
+}
+
+long WaitPPReadyAndRefreshRegs(hantrodec_t *dev, struct core_desc *Core) {
+ u32 id = Core->id;
+
+ PDEBUG("wait_event_interruptible PP[%d]\n", id);
+
+ if(wait_event_interruptible(pp_wait_queue, CheckPPIrq(dev, id))) {
+ PDEBUG("PP[%d] wait_event_interruptible interrupted\n", id);
+ return -ERESTARTSYS;
+ }
+
+ atomic_inc(&irq_tx);
+
+ /* refresh registers */
+ return PPRefreshRegs(dev, Core);
+}
+
+static int CheckCoreIrq(hantrodec_t *dev, const struct file *filp, int *id) {
+ unsigned long flags;
+ int rdy = 0, n = 0;
+
+ do {
+ u32 irq_mask = (1 << n);
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ if(dec_irq & irq_mask) {
+ if (dec_owner[n] == filp) {
+ /* we have an IRQ for our client */
+
+ /* reset the wait condition(s) */
+ dec_irq &= ~irq_mask;
+
+ /* signal ready Core no. for our client */
+ *id = n;
+
+ rdy = 1;
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+ break;
+ } else if(dec_owner[n] == NULL) {
+ /* zombie IRQ */
+ printk(KERN_INFO "IRQ on Core[%d], but no owner!!!\n", n);
+
+ /* reset the wait condition(s) */
+ dec_irq &= ~irq_mask;
+ }
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ n++; /* next Core */
+ } while(n < dev->cores);
+
+ return rdy;
+}
+
+long WaitCoreReady(hantrodec_t *dev, const struct file *filp, int *id) {
+ PDEBUG("wait_event_interruptible CORE\n");
+
+ if(wait_event_interruptible(dec_wait_queue, CheckCoreIrq(dev, filp, id))) {
+ PDEBUG("CORE wait_event_interruptible interrupted\n");
+ return -ERESTARTSYS;
+ }
+
+ atomic_inc(&irq_tx);
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------------
+ Function name : hantrodec_ioctl
+ Description : communication method to/from the user space
+
+ Return type : long
+------------------------------------------------------------------------------*/
+
+static long hantrodec_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg) {
+ int err = 0;
+ long tmp;
+#ifdef CLK_CFG
+ unsigned long flags;
+#endif
+
+#ifdef HW_PERFORMANCE
+ struct timeval *end_time_arg;
+#endif
+
+ PDEBUG("ioctl cmd 0x%08x\n", cmd);
+ /*
+ * extract the type and number bitfields, and don't decode
+ * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+ */
+ if (_IOC_TYPE(cmd) != HANTRODEC_IOC_MAGIC)
+ return -ENOTTY;
+ if (_IOC_NR(cmd) > HANTRODEC_IOC_MAXNR)
+ return -ENOTTY;
+
+ /*
+ * the direction is a bitmask, and VERIFY_WRITE catches R/W
+ * transfers. `Type' is user-oriented, while
+ * access_ok is kernel-oriented, so the concept of "read" and
+ * "write" is reversed
+ */
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE, (void *) arg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ, (void *) arg, _IOC_SIZE(cmd));
+
+ if (err)
+ return -EFAULT;
+
+#ifdef CLK_CFG
+ spin_lock_irqsave(&clk_lock, flags);
+ if (clk_cfg!=NULL && !IS_ERR(clk_cfg)&&(is_clk_on==0))
+ {
+ printk("turn on clock by user\n");
+ if (clk_enable(clk_cfg))
+ {
+ spin_unlock_irqrestore(&clk_lock, flags);
+ return -EFAULT;
+ }
+ else
+ is_clk_on=1;
+ }
+ spin_unlock_irqrestore(&clk_lock, flags);
+ mod_timer(&timer, jiffies + 10*HZ); /*the interval is 10s*/
+#endif
+
+ switch (cmd) {
+ case HANTRODEC_IOC_CLI:
+ {
+ __u32 id;
+ __get_user(id, (__u32*)arg);
+
+ if(id >= hantrodec_data.cores) {
+ return -EFAULT;
+ }
+ disable_irq(hantrodec_data.irq[id]);
+ break;
+ }
+ case HANTRODEC_IOC_STI:
+ {
+ __u32 id;
+ __get_user(id, (__u32*)arg);
+
+ if(id >= hantrodec_data.cores) {
+ return -EFAULT;
+ }
+ enable_irq(hantrodec_data.irq[id]);
+ break;
+ }
+ case HANTRODEC_IOCGHWOFFSET:
+ {
+ __u32 id;
+ __get_user(id, (__u32*)arg);
+
+ if(id >= hantrodec_data.cores) {
+ return -EFAULT;
+ }
+
+ __put_user(multicorebase[id], (unsigned long *) arg);
+ break;
+ }
+ case HANTRODEC_IOCGHWIOSIZE:
+ {
+ __u32 id;
+ __u32 io_size;
+ __get_user(id, (__u32*)arg);
+
+ if(id >= hantrodec_data.cores) {
+ return -EFAULT;
+ }
+ io_size = hantrodec_data.iosize[id];
+ __put_user(io_size, (u32 *) arg);
+
+ return 0;
+ }
+ case HANTRODEC_IOC_MC_OFFSETS: {
+ tmp = copy_to_user((u64 *) arg, multicorebase, sizeof(multicorebase));
+ if (err) {
+ PDEBUG("copy_to_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+ break;
+ }
+ case HANTRODEC_IOC_MC_CORES:
+ __put_user(hantrodec_data.cores, (unsigned int *) arg);
+ PDEBUG("hantrodec_data.cores=%d\n", hantrodec_data.cores);
+ break;
+ case HANTRODEC_IOCS_DEC_PUSH_REG: {
+ struct core_desc Core;
+
+ /* get registers from user space*/
+ tmp = copy_from_user(&Core, (void*)arg, sizeof(struct core_desc));
+ if (tmp) {
+ PDEBUG("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ DecFlushRegs(&hantrodec_data, &Core);
+ break;
+ }
+ case HANTRODEC_IOCS_PP_PUSH_REG: {
+ struct core_desc Core;
+
+ /* get registers from user space*/
+ tmp = copy_from_user(&Core, (void*)arg, sizeof(struct core_desc));
+ if (tmp) {
+ PDEBUG("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ PPFlushRegs(&hantrodec_data, &Core);
+ break;
+ }
+ case HANTRODEC_IOCS_DEC_PULL_REG: {
+ struct core_desc Core;
+
+ /* get registers from user space*/
+ tmp = copy_from_user(&Core, (void*)arg, sizeof(struct core_desc));
+ if (tmp) {
+ PDEBUG("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ return DecRefreshRegs(&hantrodec_data, &Core);
+ }
+ case HANTRODEC_IOCS_PP_PULL_REG: {
+ struct core_desc Core;
+
+ /* get registers from user space*/
+ tmp = copy_from_user(&Core, (void*)arg, sizeof(struct core_desc));
+ if (tmp) {
+ PDEBUG("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ return PPRefreshRegs(&hantrodec_data, &Core);
+ }
+ case HANTRODEC_IOCH_DEC_RESERVE: {
+ PDEBUG("Reserve DEC Core, format = %li\n", arg);
+ return ReserveDecoder(&hantrodec_data, filp, arg);
+ }
+ case HANTRODEC_IOCT_DEC_RELEASE: {
+ if(arg >= hantrodec_data.cores || dec_owner[arg] != filp) {
+ PDEBUG("bogus DEC release, Core = %li\n", arg);
+ return -EFAULT;
+ }
+
+ PDEBUG("Release DEC, Core = %li\n", arg);
+
+ ReleaseDecoder(&hantrodec_data, arg);
+
+ break;
+ }
+ case HANTRODEC_IOCQ_PP_RESERVE:
+ return ReservePostProcessor(&hantrodec_data, filp);
+ case HANTRODEC_IOCT_PP_RELEASE: {
+ if(arg != 0 || pp_owner[arg] != filp) {
+ PDEBUG("bogus PP release %li\n", arg);
+ return -EFAULT;
+ }
+
+ ReleasePostProcessor(&hantrodec_data, arg);
+
+ break;
+ }
+ case HANTRODEC_IOCX_DEC_WAIT: {
+ struct core_desc Core;
+
+ /* get registers from user space */
+ tmp = copy_from_user(&Core, (void*)arg, sizeof(struct core_desc));
+ if (tmp) {
+ PDEBUG("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ return WaitDecReadyAndRefreshRegs(&hantrodec_data, &Core);
+ }
+ case HANTRODEC_IOCX_PP_WAIT: {
+ struct core_desc Core;
+
+ /* get registers from user space */
+ tmp = copy_from_user(&Core, (void*)arg, sizeof(struct core_desc));
+ if (tmp) {
+ PDEBUG("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ return WaitPPReadyAndRefreshRegs(&hantrodec_data, &Core);
+ }
+ case HANTRODEC_IOCG_CORE_WAIT: {
+ int id;
+ tmp = WaitCoreReady(&hantrodec_data, filp, &id);
+ __put_user(id, (int *) arg);
+ return tmp;
+ }
+ case HANTRODEC_IOX_ASIC_ID: {
+ u32 id;
+ __get_user(id, (u32*)arg);
+
+ if(id >= hantrodec_data.cores) {
+ return -EFAULT;
+ }
+ id = ioread32(hantrodec_data.hwregs[id]);
+ __put_user(id, (u32 *) arg);
+ return 0;
+ }
+ case HANTRODEC_IOCG_CORE_ID: {
+ PDEBUG("Get DEC Core_id, format = %li\n", arg);
+ return GetDecCoreID(&hantrodec_data, filp, arg);
+ }
+ case HANTRODEC_DEBUG_STATUS: {
+ printk(KERN_INFO "hantrodec: dec_irq = 0x%08x \n", dec_irq);
+ printk(KERN_INFO "hantrodec: pp_irq = 0x%08x \n", pp_irq);
+
+ printk(KERN_INFO "hantrodec: IRQs received/sent2user = %d / %d \n",
+ atomic_read(&irq_rx), atomic_read(&irq_tx));
+
+ for (tmp = 0; tmp < hantrodec_data.cores; tmp++) {
+ printk(KERN_INFO "hantrodec: dec_core[%li] %s\n",
+ tmp, dec_owner[tmp] == NULL ? "FREE" : "RESERVED");
+ printk(KERN_INFO "hantrodec: pp_core[%li] %s\n",
+ tmp, pp_owner[tmp] == NULL ? "FREE" : "RESERVED");
+ }
+ }
+ default:
+ return -ENOTTY;
+ }
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------------
+ Function name : hantrodec_open
+ Description : open method
+
+ Return type : int
+------------------------------------------------------------------------------*/
+
+static int hantrodec_open(struct inode *inode, struct file *filp) {
+ PDEBUG("dev opened\n");
+#ifndef VSI //1 NXP
+ pm_runtime_get_sync(hantro_dev);
+#endif
+ return 0;
+}
+
+/*------------------------------------------------------------------------------
+ Function name : hantrodec_release
+ Description : Release driver
+
+ Return type : int
+------------------------------------------------------------------------------*/
+
+static int hantrodec_release(struct inode *inode, struct file *filp) {
+ int n;
+ hantrodec_t *dev = &hantrodec_data;
+
+ PDEBUG("closing ...\n");
+
+ for(n = 0; n < dev->cores; n++) {
+ if(dec_owner[n] == filp) {
+ PDEBUG("releasing dec Core %i lock\n", n);
+ ReleaseDecoder(dev, n);
+ }
+ }
+
+ for(n = 0; n < 1; n++) {
+ if(pp_owner[n] == filp) {
+ PDEBUG("releasing pp Core %i lock\n", n);
+ ReleasePostProcessor(dev, n);
+ }
+ }
+#ifndef VSI //1 NXP
+ pm_runtime_put_sync_suspend(hantro_dev);
+#endif
+ PDEBUG("closed\n");
+ return 0;
+}
+
+#ifdef CLK_CFG
+void hantrodec_disable_clk(unsigned long value)
+{
+ unsigned long flags;
+ /*entering this function means decoder is idle over expiry.So disable clk*/
+ if (clk_cfg!=NULL && !IS_ERR(clk_cfg))
+ {
+ spin_lock_irqsave(&clk_lock, flags);
+ if (is_clk_on==1)
+ {
+ clk_disable(clk_cfg);
+ is_clk_on = 0;
+ printk("turned off hantrodec clk\n");
+ }
+ spin_unlock_irqrestore(&clk_lock, flags);
+ }
+}
+#endif
+
+/* VFS methods */
+static struct file_operations hantrodec_fops = {
+ .owner = THIS_MODULE,
+ .open = hantrodec_open,
+ .release = hantrodec_release,
+ .unlocked_ioctl = hantrodec_ioctl,
+ .fasync = NULL
+};
+
+/*------------------------------------------------------------------------------
+ Function name : hantrodec_init
+ Description : Initialize the driver
+
+ Return type : int
+------------------------------------------------------------------------------*/
+
+int __init hantrodec_init(void) {
+ int result, i;
+
+ PDEBUG("module init\n");
+
+ printk(KERN_INFO "hantrodec: dec/pp kernel module. \n");
+#ifdef VSI //1NXP
+/*This segment is related with customer platform CFG and should be modified for specified use*/
+/*---------------------------------------------------------------------------*/
+{
+ //map PGC_CPU_MAPPING
+ unsigned long pgc_base = 0x303A0000;
+ //volatile unsigned char *reg = NULL;
+ unsigned int val = 0;
+ if (!request_mem_region(pgc_base, 0x1000, "pgc_cpu_mapping"))
+ {
+ printk(KERN_INFO "pgc_cpu_mapping: failed to reserve HW regs\n");
+ return -EBUSY;
+ }
+
+ reg = (volatile u8 *) ioremap_nocache(pgc_base, 0x1000);
+
+ if (reg == NULL )
+ {
+ printk(KERN_INFO "pgc_cpu_mapping: failed to ioremap HW regs\n");
+ if (reg)
+ iounmap((void *)reg);
+ release_mem_region(pgc_base, 0x1000);
+ return -EBUSY;
+ }
+ val = ioread32(reg + 0xEC);
+ printk(KERN_INFO" the initial val = 0x%x\n", val);
+ iowrite32(0x0000ffffl, reg+0xEC);
+ val = ioread32(reg + 0xEC);
+ printk(KERN_INFO" the changed val = 0x%x\n", val);
+
+ val = ioread32(reg + 0xF8);
+ printk(KERN_INFO" the initial val = 0x%x\n", val);
+ val |= 0x100;
+ iowrite32(val, reg+0xF8);
+ val = ioread32(reg + 0xF8);
+ printk(KERN_INFO" the changed val = 0x%x\n", val);
+
+ if (reg)
+ iounmap((void *)reg);
+ release_mem_region(pgc_base, 0x1000);
+}
+#if 1
+{
+ //BLK_CTL
+ unsigned int blk_base = 0x38320000;
+ volatile unsigned char *reg = NULL;
+
+ if (!request_mem_region(blk_base, 0x1000, "blk_ctl"))
+ {
+ printk(KERN_INFO "blk_ctl: failed to reserve HW regs\n");
+ return -EBUSY;
+ }
+
+ reg = (volatile u8 *) ioremap_nocache(blk_base, 0x1000);
+
+ if (reg == NULL )
+ {
+ printk(KERN_INFO "blk_ctl: failed to ioremap HW regs\n");
+ if (reg)
+ iounmap((void *)reg);
+ release_mem_region(blk_base, 0x1000);
+ return -EBUSY;
+ }
+
+ iowrite32(0x3, reg + 0x0); // release all soft reset
+ iowrite32(0x3, reg + 0x4); // enable all clock
+ iowrite32(0xFFFFFFFF, reg + 0x8); // all G1 fuse dec enable
+ iowrite32(0xFFFFFFFF, reg + 0xC); // all G1 fuse pp enable
+ iowrite32(0xFFFFFFFF, reg + 0x10); // all G2 fuse dec enable
+ // G1 use, set to 1; G2 use, set to 0, choose the one you are using
+ //iowrite32(0x1, reg + 0x14); // VPUMIX only use G1
+ //iowrite32(0x0, reg + 0x14); // VPUMIX only use G2
+
+ if (reg)
+ iounmap((void *)reg);
+ release_mem_region(blk_base, 0x1000);
+}
+#endif
+/*------------------------------------------------------------*/
+#endif
+ /* If base_port is set at load, use that for single Core legacy mode */
+ if(base_port != -1) {
+ multicorebase[0] = base_port;
+ elements = 1;
+ printk(KERN_INFO "hantrodec: Init single Core at 0x%16lx IRQ=%i\n",
+ multicorebase[0], irq_0);
+ } else {
+ printk(KERN_INFO "hantrodec: Init multi Core[0] at 0x%16lx\n"
+ " Core[1] at 0x%16lx\n"
+ " Core[2] at 0x%16lx\n"
+ " Core[3] at 0x%16lx\n"
+ " IRQ_0=%i\n"
+ " IRQ_1=%i\n",
+ multicorebase[0], multicorebase[1],
+ multicorebase[2], multicorebase[3],
+ irq_0,irq_1);
+ }
+
+ hantrodec_data.cores = 0;
+
+ hantrodec_data.iosize[0] = DEC_IO_SIZE_0;
+ hantrodec_data.irq[0] = irq_0;
+#ifdef MULTI_CORE
+ hantrodec_data.iosize[1] = DEC_IO_SIZE_1;
+ hantrodec_data.irq[1] = irq_1;
+#endif
+
+ for(i=0; i< HXDEC_MAX_CORES; i++) {
+ hantrodec_data.hwregs[i] = 0;
+ /* If user gave less Core bases that we have by default,
+ * invalidate default bases
+ */
+ if(elements && i>=elements) {
+ multicorebase[i] = -1;
+ }
+ }
+
+ hantrodec_data.async_queue_dec = NULL;
+ hantrodec_data.async_queue_pp = NULL;
+
+ result = register_chrdev(hantrodec_major, "hantrodec", &hantrodec_fops);
+ if(result < 0) {
+ printk(KERN_INFO "hantrodec: unable to get major %d\n", hantrodec_major);
+ goto err;
+ } else if(result != 0) { /* this is for dynamic major */
+ hantrodec_major = result;
+ }
+
+#ifdef CLK_CFG
+ clk_cfg = clk_get(NULL, CLK_ID); /*first get clk instance pointer*/
+ if (!clk_cfg||IS_ERR(clk_cfg))
+ {
+ printk("get handrodec clk failed!\n");
+ goto err;
+ }
+ if(clk_prepare_enable(clk_cfg)) /*prepare and enable clk*/
+ {
+ printk("try to enable handrodec clk failed!\n");
+ goto err;
+ }
+ is_clk_on =1;
+ /*init a timer to disable clk*/
+ init_timer(&timer);
+ timer.function = &hantrodec_disable_clk;
+ timer.expires = jiffies + 100*HZ; //the expires time is 100s
+ add_timer(&timer);
+#endif
+
+ result = ReserveIO();
+ if(result < 0) {
+ goto err;
+ }
+
+ memset(dec_owner, 0, sizeof(dec_owner));
+ memset(pp_owner, 0, sizeof(pp_owner));
+
+ sema_init(&dec_core_sem, hantrodec_data.cores-1);
+ sema_init(&pp_core_sem, 1);
+
+ /* read configuration fo all cores */
+ ReadCoreConfig(&hantrodec_data);
+
+ /* reset hardware */
+ ResetAsic(&hantrodec_data);
+
+ /* register irq for each core*/
+ if(irq_0 > 0)
+ {
+#ifdef VSI //1NXP
+ struct device_node *np;
+ //memset(&irq_g2,0,sizeof(struct irq_test_type));
+ np = of_find_matching_node(NULL, mmp_timer_dt_ids_0);
+ if (!np) {
+ result = -ENODEV;
+ printk("errno 1 = %d\n", result);
+ goto err;
+ }
+ irq_0 = irq_of_parse_and_map(np, 0);
+ if (!irq_0) {
+ result = -EINVAL;
+ printk("errno 2 = %d\n", result);
+ goto err;
+ }
+#endif
+ //printk("irq = %d\n", irq_0);
+ hantrodec_data.irq[0] = irq_0;
+ //printk(KERN_INFO "init the irq function !!\n");
+ result = request_irq(irq_0, hantrodec_isr,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+ SA_INTERRUPT | SA_SHIRQ,
+#else
+ IRQF_SHARED,
+#endif
+ "hantrodec", (void *) &hantrodec_data);
+
+ if(result != 0)
+ {
+ if(result == -EINVAL)
+ {
+ printk(KERN_ERR "hantrodec: Bad irq number or handler\n");
+ }
+ else if(result == -EBUSY)
+ {
+ printk(KERN_ERR "hantrodec: IRQ <%d> busy, change your config\n",
+ hantrodec_data.irq[0]);
+ }
+
+ ReleaseIO();
+ goto err;
+ }
+ }
+ else
+ {
+ printk(KERN_INFO "hantrodec: IRQ not in use!\n");
+ }
+
+#ifdef MULTI_CORE
+ if(irq_1 > 0)
+ {
+#ifdef VSI //1NXP
+ struct device_node *np;
+ //memset(&irq_g2,0,sizeof(struct irq_test_type));
+ np = of_find_matching_node(NULL, mmp_timer_dt_ids_1);
+ if (!np) {
+ result = -ENODEV;
+ printk("errno 1 = %d\n", result);
+ goto err;
+ }
+ irq_1 = irq_of_parse_and_map(np, 0);
+ if (!irq_1) {
+ result = -EINVAL;
+ printk("errno 2 = %d\n", result);
+ goto err;
+ }
+#endif
+ //printk("irq = %d\n", irq_1);
+ hantrodec_data.irq[1] = irq_1;
+ //printk(KERN_INFO "init the irq function !!\n");
+ result = request_irq(irq_1, hantrodec_isr,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+ SA_INTERRUPT | SA_SHIRQ,
+#else
+ IRQF_SHARED,
+#endif
+ "hantrodec", (void *) &hantrodec_data);
+
+ if(result != 0)
+ {
+ if(result == -EINVAL)
+ {
+ printk(KERN_ERR "hantrodec: Bad irq number or handler\n");
+ }
+ else if(result == -EBUSY)
+ {
+ printk(KERN_ERR "hantrodec: IRQ <%d> busy, change your config\n",
+ hantrodec_data.irq[1]);
+ }
+
+ ReleaseIO();
+ goto err;
+ }
+ }
+ else
+ {
+ printk(KERN_INFO "hantrodec: IRQ not in use!\n");
+ }
+#endif
+
+ printk(KERN_INFO "hantrodec: module inserted. Major = %d\n", hantrodec_major);
+
+ return 0;
+
+err:
+ printk(KERN_INFO "hantrodec: module not inserted\n");
+ unregister_chrdev(hantrodec_major, "hantrodec");
+ return result;
+}
+
+/*------------------------------------------------------------------------------
+ Function name : hantrodec_cleanup
+ Description : clean up
+
+ Return type : int
+------------------------------------------------------------------------------*/
+
+void __exit hantrodec_cleanup(void) {
+ hantrodec_t *dev = &hantrodec_data;
+ int n =0;
+ /* reset hardware */
+ ResetAsic(dev);
+
+ /* free the IRQ */
+ for (n = 0; n < dev->cores; n++)
+ {
+ if(dev->irq[n] != -1) {
+ free_irq(dev->irq[n], (void *) dev);
+ }
+ }
+
+ ReleaseIO();
+
+#ifdef CLK_CFG
+ if (clk_cfg!=NULL && !IS_ERR(clk_cfg))
+ {
+ clk_disable_unprepare(clk_cfg);
+ is_clk_on = 0;
+ printk("turned off hantrodec clk\n");
+ }
+
+ /*delete timer*/
+ del_timer(&timer);
+#endif
+
+ unregister_chrdev(hantrodec_major, "hantrodec");
+
+ printk(KERN_INFO "hantrodec: module removed\n");
+ return;
+}
+
+/*------------------------------------------------------------------------------
+ Function name : CheckHwId
+ Return type : int
+------------------------------------------------------------------------------*/
+static int CheckHwId(hantrodec_t * dev) {
+ long int hwid;
+ int i;
+ size_t num_hw = sizeof(DecHwId) / sizeof(*DecHwId);
+
+ int found = 0;
+
+ for (i = 0; i < dev->cores; i++) {
+ if (dev->hwregs[i] != NULL ) {
+ hwid = readl(dev->hwregs[i]);
+ printk(KERN_INFO "hantrodec: Core %d HW ID=0x%16lx\n", i, hwid);
+ hwid = (hwid >> 16) & 0xFFFF; /* product version only */
+
+ while (num_hw--) {
+ if (hwid == DecHwId[num_hw]) {
+ printk(KERN_INFO "hantrodec: Supported HW found at 0x%16lx\n",
+ multicorebase[i]);
+ found++;
+ dev->hw_id[i] = hwid;
+ break;
+ }
+ }
+ if (!found) {
+ printk(KERN_INFO "hantrodec: Unknown HW found at 0x%16lx\n",
+ multicorebase[i]);
+ return 0;
+ }
+ found = 0;
+ num_hw = sizeof(DecHwId) / sizeof(*DecHwId);
+ }
+ }
+
+ return 1;
+}
+
+/*------------------------------------------------------------------------------
+ Function name : ReserveIO
+ Description : IO reserve
+
+ Return type : int
+------------------------------------------------------------------------------*/
+static int ReserveIO(void) {
+ int i;
+
+ for (i = 0; i < HXDEC_MAX_CORES; i++) {
+ if (multicorebase[i] != -1) {
+ if (!request_mem_region(multicorebase[i], hantrodec_data.iosize[i],
+ "hantrodec0")) {
+ printk("hantrodec: failed to reserve HW regs\n");
+ return -EBUSY;
+ }
+
+ hantrodec_data.hwregs[i] = (volatile u8 *) ioremap_nocache(multicorebase[i],
+ hantrodec_data.iosize[i]);
+
+ if (hantrodec_data.hwregs[i] == NULL ) {
+ printk("hantrodec: failed to ioremap HW regs\n");
+ ReleaseIO();
+ return -EBUSY;
+ }
+ hantrodec_data.cores++;
+ }
+ }
+
+ /* check for correct HW */
+ if (!CheckHwId(&hantrodec_data)) {
+ ReleaseIO();
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------------
+ Function name : releaseIO
+ Description : release
+
+ Return type : void
+------------------------------------------------------------------------------*/
+
+static void ReleaseIO(void) {
+ int i;
+ for (i = 0; i < hantrodec_data.cores; i++) {
+ if (hantrodec_data.hwregs[i])
+ iounmap((void *) hantrodec_data.hwregs[i]);
+ release_mem_region(multicorebase[i], hantrodec_data.iosize[i]);
+ }
+}
+
+/*------------------------------------------------------------------------------
+ Function name : hantrodec_isr
+ Description : interrupt handler
+
+ Return type : irqreturn_t
+------------------------------------------------------------------------------*/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+irqreturn_t hantrodec_isr(int irq, void *dev_id, struct pt_regs *regs)
+#else
+irqreturn_t hantrodec_isr(int irq, void *dev_id)
+#endif
+{
+ unsigned long flags;
+ unsigned int handled = 0;
+ int i;
+ volatile u8 *hwregs;
+
+ hantrodec_t *dev = (hantrodec_t *) dev_id;
+ u32 irq_status_dec;
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ for(i=0; i<dev->cores; i++) {
+ volatile u8 *hwregs = dev->hwregs[i];
+
+ /* interrupt status register read */
+ irq_status_dec = ioread32(hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+ if(irq_status_dec & HANTRODEC_DEC_IRQ) {
+ /* clear dec IRQ */
+ irq_status_dec &= (~HANTRODEC_DEC_IRQ);
+ iowrite32(irq_status_dec, hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+ PDEBUG("decoder IRQ received! Core %d\n", i);
+
+ atomic_inc(&irq_rx);
+
+ dec_irq |= (1 << i);
+
+ wake_up_interruptible_all(&dec_wait_queue);
+ handled++;
+ }
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ if(!handled) {
+ PDEBUG("IRQ received, but not hantrodec's!\n");
+ }
+
+ (void)hwregs;
+ return IRQ_RETVAL(handled);
+}
+
+/*------------------------------------------------------------------------------
+ Function name : ResetAsic
+ Description : reset asic
+
+ Return type :
+------------------------------------------------------------------------------*/
+void ResetAsic(hantrodec_t * dev) {
+ int i, j;
+ u32 status;
+
+ for (j = 0; j < dev->cores; j++) {
+ status = ioread32(dev->hwregs[j] + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+ if( status & HANTRODEC_DEC_E) {
+ /* abort with IRQ disabled */
+ status = HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+ iowrite32(status, dev->hwregs[j] + HANTRODEC_IRQ_STAT_DEC_OFF);
+ }
+
+ if (IS_G1(dev->hw_id[j]))
+ /* reset PP */
+ iowrite32(0, dev->hwregs[j] + HANTRO_IRQ_STAT_PP_OFF);
+
+ for (i = 4; i < dev->iosize[j]; i += 4) {
+ iowrite32(0, dev->hwregs[j] + i);
+ }
+ }
+}
+
+/*------------------------------------------------------------------------------
+ Function name : dump_regs
+ Description : Dump registers
+
+ Return type :
+------------------------------------------------------------------------------*/
+#ifdef HANTRODEC_DEBUG
+void dump_regs(hantrodec_t *dev) {
+ int i,c;
+
+ PDEBUG("Reg Dump Start\n");
+ for(c = 0; c < dev->cores; c++) {
+ for(i = 0; i < dev->iosize[c]; i += 4*4) {
+ PDEBUG("\toffset %04X: %08X %08X %08X %08X\n", i,
+ ioread32(dev->hwregs[c] + i),
+ ioread32(dev->hwregs[c] + i + 4),
+ ioread32(dev->hwregs[c] + i + 8),
+ ioread32(dev->hwregs[c] + i + 12));
+ }
+ }
+ PDEBUG("Reg Dump End\n");
+}
+#endif
+
+#ifdef VSI
+module_init( hantrodec_init);
+module_exit( hantrodec_cleanup);
+#else //1 for NXP
+
+static irqreturn_t hantrodec_isr_g1(int irq, void *dev_id)
+{
+ PDEBUG("g1 interrupt \n");
+ return IRQ_RETVAL(1);
+}
+
+static int hantro_dev_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ struct device *temp_class;
+ struct resource *res;
+ unsigned long reg_base;
+
+ hantro_dev=&pdev->dev;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs_hantro");
+ if (!res) {
+ dev_err(hantro_dev, "hantro: unable to get vpu base addr\n");
+ return -ENODEV;
+ }
+ reg_base = res->start;
+
+ irq_g2 = platform_get_irq_byname(pdev, "irq_hantro_g2");
+ if (irq_g2 < 0) {
+ dev_err(hantro_dev, "hantro: unable to get hantro g2 interrupt\n");
+ err = -ENXIO;
+ goto error;
+ }
+
+ irq_g1 = platform_get_irq_byname(pdev, "irq_hantro_g1");
+ if (irq_g1 < 0) {
+ dev_err(hantro_dev, "hantro: unable to get hantro g1 interrupt\n");
+ err = -ENXIO;
+ goto error;
+ }
+
+ hantro_clk_g1 = clk_get(&pdev->dev, "clk_hantro_g1");
+ if (IS_ERR(hantro_clk_g1)) {
+ err = -ENOENT;
+ goto error;
+ }
+ hantro_clk_g2 = clk_get(&pdev->dev, "clk_hantro_g2");
+ if (IS_ERR(hantro_clk_g2)) {
+ err = -ENOENT;
+ goto error;
+ }
+ hantro_clk_bus = clk_get(&pdev->dev, "clk_hantro_bus");
+ if (IS_ERR(hantro_clk_bus)) {
+ err = -ENOENT;
+ goto error;
+ }
+#if 1 //1 eagle : temporary code for zebu
+{
+ //#define CLK_RATE (600000000) //600MHZ
+#define CLKG1_RATE (600000000) //600MHZ
+#define CLKG2_RATE (300000000) //300MHZ
+ int ret;
+ volatile u8* iobase;
+
+ /*
+ mw 0x303a00f8 0x100
+ mw 0x38320000 0x3 // BLK_SFT_RSTN_CSR 0x00 VPUMIX G1/G2 block soft reset control
+ mw 0x38320004 0x3 // BLK_CLK_EN_CSR 0x04 VPUMIX G1/G2 block clock enable control
+ */
+#if 0 //only needed by zebu
+ printk("will set 0x303a00f8 and 0x303a00EC \r\n");
+ iobase = (volatile u8 *) ioremap_nocache(0x303a0000,0x10000);
+ iowrite32(0x100,iobase+0xf8);
+ //iobase[0xf8]=0x100;
+ iowrite32(0x0000ffffl, iobase+0xEC);
+ iounmap(iobase);
+#endif
+ //printk("will set 0x3832000X, reset g1 and g2 \r\n");
+ iobase = (volatile u8 *) ioremap_nocache(0x38320000,0x10000);
+ //iobase[0]=0x3;
+ //iobase[0x4]=0x3;
+ iowrite32(0x3,iobase);
+ iowrite32(0x3,iobase+4);
+ {
+ unsigned int val=0;
+ iowrite32(0xFFFFFFFF, iobase + 0x8); // all G1 fuse dec enable
+ iowrite32(0xFFFFFFFF, iobase + 0xC); // all G1 fuse pp enable
+
+ val=ioread32(iobase + 0x10);
+ //printk("g2 fuse before set: 0x%X \n",val);
+ iowrite32(0xFFFFFFFF, iobase + 0x10); // all G2 fuse dec enable
+ val=ioread32(iobase + 0x10);
+ //printk("g2 fuse after set : 0x%X \n",val);
+ // G1 use, set to 1; G2 use, set to 0, choose the one you are using
+
+#if 0
+ //iowrite32(0x1, iobase + 0x14); // VPUMIX only use G1
+ val=ioread32(iobase + 0x14);
+ printk("vpumix before set: 0x%X \n",val);
+ iowrite32(0x0, iobase + 0x14); // VPUMIX only use G2
+ val=ioread32(iobase + 0x14);
+ printk("vpumix after set: 0x%X \n",val);
+#endif
+ }
+ iounmap(iobase);
+ //printk("enable hantro power \r\n");
+ // pm_runtime_enable(hantro_dev);
+ // ret=pm_runtime_get_sync(hantro_dev);
+ // printk("turn power ret: %d \r\n",ret);
+
+#if 0
+ clk_prepare(hantro_clk_g1);
+ ret=clk_set_rate(hantro_clk_g1,CLKG1_RATE);
+ printk("set g1 rate: %d , ret: %d \r\n",CLKG1_RATE,ret);
+ clk_unprepare(hantro_clk_g1);
+
+ clk_prepare(hantro_clk_g2);
+ ret=clk_set_rate(hantro_clk_g2,CLKG2_RATE);
+ printk("set g2 rate: %d , ret: %d \r\n",CLKG2_RATE,ret);
+ clk_unprepare(hantro_clk_g2);
+#endif
+
+ //printk("enable g1 and g2 clock \r\n");
+ ret=clk_prepare(hantro_clk_g1);
+ //printk("prepare g1 ret: %d \r\n",ret);
+ ret=clk_enable(hantro_clk_g1);
+ //printk("enable g1 ret: %d \r\n",ret);
+ ret=clk_prepare(hantro_clk_g2);
+ //printk("prepare g2 ret: %d \r\n",ret);
+ ret=clk_enable(hantro_clk_g2);
+ //printk("enable g2 ret: %d \r\n",ret);
+ ret=clk_prepare(hantro_clk_bus);
+ //printk("prepare hantro bus ret: %d \r\n",ret);
+ ret=clk_enable(hantro_clk_bus);
+ //printk("enable hantro bus ret: %d \r\n",ret);
+ //printk("g1 clk: get rate: %d \r\n",(int)clk_get_rate(hantro_clk_g1));
+ //printk("g2 clk: get rate: %d \r\n",(int)clk_get_rate(hantro_clk_g2));
+ //printk("hantro bus clk: get rate: %d \r\n",(int)clk_get_rate(hantro_clk_bus));
+
+#if 0
+ printk("set g1 rate: %d , ret: %d \r\n",CLKG1_RATE,ret);
+ ret=clk_set_rate(hantro_clk_g1,CLKG1_RATE);
+ printk("set g2 rate: %d , ret: %d \r\n",CLKG2_RATE,ret);
+ ret=clk_set_rate(hantro_clk_g2,CLKG2_RATE);
+ printk("g1 clk: get rate: %d \r\n",(int)clk_get_rate(hantro_clk_g1));
+ printk("g2 clk: get rate: %d \r\n",(int)clk_get_rate(hantro_clk_g2));
+#endif
+
+}
+
+ if((ulong)reg_base!=multicorebase[0]){
+ printk(KERN_ERR "hantrodec: regbase(0x%lX) not equal to expected value(0x%lX)\n",reg_base,multicorebase[0]);
+ err=-ENODEV;
+ goto error;
+ }
+
+ PDEBUG("base port: 0x%lX , g1 irq: %d, g2 irq: %d \n",reg_base,irq_g1,irq_g2);
+
+ irq_0=irq_g1;
+ irq_1=irq_g2;
+ if(0){ // register g1 irq
+ int result;
+ result = request_irq(irq_g1, hantrodec_isr_g1,IRQF_SHARED, "hantrodec", (void *) &hantrodec_data);
+ if(result != 0) {
+ printk(KERN_ERR "hantrodec: can't request irq g1\n");
+ }
+ }
+#endif
+
+ err=hantrodec_init();
+ if(0!=err){
+ dev_err(hantro_dev, "hantro: hantrodec_init failed\n");
+ goto error;
+ }
+
+ hantro_class = class_create(THIS_MODULE, "mxc_hantro");
+ if (IS_ERR(hantro_class)) {
+ err = PTR_ERR(hantro_class);
+ goto error;
+ }
+ temp_class = device_create(hantro_class, NULL, MKDEV(hantrodec_major, 0), NULL, DEVICE_NAME);
+ if (IS_ERR(temp_class)) {
+ err = PTR_ERR(temp_class);
+ goto err_out_class;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+ goto out;
+
+err_out_class:
+ device_destroy(hantro_class, MKDEV(hantrodec_major, 0));
+ class_destroy(hantro_class);
+error:
+ //iounmap(hantro_base);
+out:
+ return err;
+}
+
+static int hantro_dev_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+ if (hantrodec_major > 0) {
+ device_destroy(hantro_class, MKDEV(hantrodec_major, 0));
+ class_destroy(hantro_class);
+ hantrodec_cleanup();
+ hantrodec_major = 0;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int hantro_suspend(struct device *dev)
+{
+ pm_runtime_put_sync_suspend(dev); //power off
+ return 0;
+}
+static int hantro_resume(struct device *dev)
+{
+ pm_runtime_get_sync(dev); //power on
+ return 0;
+}
+static int hantro_runtime_suspend(struct device *dev)
+{
+ //release_bus_freq(BUS_FREQ_HIGH);
+ return 0;
+}
+
+static int hantro_runtime_resume(struct device *dev)
+{
+ //request_bus_freq(BUS_FREQ_HIGH);
+ return 0;
+}
+
+static const struct dev_pm_ops hantro_pm_ops = {
+ SET_RUNTIME_PM_OPS(hantro_runtime_suspend, hantro_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(hantro_suspend, hantro_resume)
+};
+#endif
+
+static const struct of_device_id hantro_of_match[] = {
+ { .compatible = "nxp,imx8mq-hantro", },
+ {/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, vpu_of_match);
+
+
+static struct platform_driver mxchantro_driver = {
+ .driver = {
+ .name = "mxc_hantro",
+ .of_match_table = hantro_of_match,
+#ifdef CONFIG_PM
+ .pm = &hantro_pm_ops,
+#endif
+ },
+ .probe = hantro_dev_probe,
+ .remove = hantro_dev_remove,
+};
+
+static int __init hantro_init(void)
+{
+ int ret = platform_driver_register(&mxchantro_driver);
+
+ return ret;
+}
+
+static void __exit hantro_exit(void)
+{
+ //1 clk_put(hantro_clk);
+ platform_driver_unregister(&mxchantro_driver);
+ return;
+}
+
+module_init( hantro_init);
+module_exit( hantro_exit);
+
+#endif
+
+/* module description */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Google Finland Oy");
+MODULE_DESCRIPTION("Driver module for Hantro Decoder/Post-Processor");
+
diff --git a/drivers/mxc/hantro/hantrodec.h b/drivers/mxc/hantro/hantrodec.h
new file mode 100755
index 000000000000..fdb55a00aba7
--- /dev/null
+++ b/drivers/mxc/hantro/hantrodec.h
@@ -0,0 +1,93 @@
+/*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (c) 2015-2017, VeriSilicon Inc.
+* Copyright (c) 2011-2014, Google Inc.
+*
+* 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 _HANTRODEC_H_
+#define _HANTRODEC_H_
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#undef PDEBUG
+#ifdef HANTRODEC_DEBUG
+# ifdef __KERNEL__
+# define PDEBUG(fmt, args...) printk( KERN_INFO "hantrodec: " fmt, ## args)
+# else
+# define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
+# endif
+#else
+# define PDEBUG(fmt, args...)
+#endif
+
+struct core_desc {
+ __u32 id; /* id of the Core */
+ __u32 *regs; /* pointer to user registers */
+ __u32 size; /* size of register space */
+};
+
+/* Use 'k' as magic number */
+#define HANTRODEC_IOC_MAGIC 'k'
+
+/*
+ * S means "Set" through a ptr,
+ * T means "Tell" directly with the argument value
+ * G means "Get": reply by setting through a pointer
+ * Q means "Query": response is on the return value
+ * X means "eXchange": G and S atomically
+ * H means "sHift": T and Q atomically
+ */
+
+#define HANTRODEC_PP_INSTANCE _IO(HANTRODEC_IOC_MAGIC, 1)
+#define HANTRODEC_HW_PERFORMANCE _IO(HANTRODEC_IOC_MAGIC, 2)
+#define HANTRODEC_IOCGHWOFFSET _IOR(HANTRODEC_IOC_MAGIC, 3, unsigned long *)
+#define HANTRODEC_IOCGHWIOSIZE _IOR(HANTRODEC_IOC_MAGIC, 4, unsigned int *)
+
+#define HANTRODEC_IOC_CLI _IO(HANTRODEC_IOC_MAGIC, 5)
+#define HANTRODEC_IOC_STI _IO(HANTRODEC_IOC_MAGIC, 6)
+#define HANTRODEC_IOC_MC_OFFSETS _IOR(HANTRODEC_IOC_MAGIC, 7, unsigned long *)
+#define HANTRODEC_IOC_MC_CORES _IOR(HANTRODEC_IOC_MAGIC, 8, unsigned int *)
+
+
+#define HANTRODEC_IOCS_DEC_PUSH_REG _IOW(HANTRODEC_IOC_MAGIC, 9, struct core_desc *)
+#define HANTRODEC_IOCS_PP_PUSH_REG _IOW(HANTRODEC_IOC_MAGIC, 10, struct core_desc *)
+
+#define HANTRODEC_IOCH_DEC_RESERVE _IO(HANTRODEC_IOC_MAGIC, 11)
+#define HANTRODEC_IOCT_DEC_RELEASE _IO(HANTRODEC_IOC_MAGIC, 12)
+#define HANTRODEC_IOCQ_PP_RESERVE _IO(HANTRODEC_IOC_MAGIC, 13)
+#define HANTRODEC_IOCT_PP_RELEASE _IO(HANTRODEC_IOC_MAGIC, 14)
+
+#define HANTRODEC_IOCX_DEC_WAIT _IOWR(HANTRODEC_IOC_MAGIC, 15, struct core_desc *)
+#define HANTRODEC_IOCX_PP_WAIT _IOWR(HANTRODEC_IOC_MAGIC, 16, struct core_desc *)
+
+#define HANTRODEC_IOCS_DEC_PULL_REG _IOWR(HANTRODEC_IOC_MAGIC, 17, struct core_desc *)
+#define HANTRODEC_IOCS_PP_PULL_REG _IOWR(HANTRODEC_IOC_MAGIC, 18, struct core_desc *)
+
+#define HANTRODEC_IOCG_CORE_WAIT _IOR(HANTRODEC_IOC_MAGIC, 19, int *)
+
+#define HANTRODEC_IOX_ASIC_ID _IOWR(HANTRODEC_IOC_MAGIC, 20, __u32 *)
+
+#define HANTRODEC_IOCG_CORE_ID _IOR(HANTRODEC_IOC_MAGIC, 21, int *)
+
+#define HANTRODEC_DEBUG_STATUS _IO(HANTRODEC_IOC_MAGIC, 29)
+
+#define HANTRODEC_IOC_MAXNR 29
+
+#endif /* !_HANTRODEC_H_ */