From: "Murugasen Krishnan, Kuhanh" <kuhanh.murugasen.krish...@intel.com>

Hantro VC8000D allows 4K decoding with a minimal silicon single-core solution 
that
supports HEVC and H.264 video formats, key features:
* HEVC Main10 and Main Profiles up to Level 5.2
* HEVC Main Still Profile
* H.264 Main and High Profiles up to Level 5.2
* HEVC, H.264 and JPEG decoding up to 4K@60fps
* 8 channels 1080p@30fps decoding

Signed-off-by: Murugasen Krishnan, Kuhanh <kuhanh.murugasen.krish...@intel.com>
---
 drivers/gpu/drm/hantro/hantro_dec.c      | 1441 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/hantro/hantro_dec.h      |   59 ++
 drivers/gpu/drm/hantro/hantro_dwl_defs.h |  101 +++
 3 files changed, 1601 insertions(+)
 create mode 100644 drivers/gpu/drm/hantro/hantro_dec.c
 create mode 100644 drivers/gpu/drm/hantro/hantro_dec.h
 create mode 100644 drivers/gpu/drm/hantro/hantro_dwl_defs.h

diff --git a/drivers/gpu/drm/hantro/hantro_dec.c 
b/drivers/gpu/drm/hantro/hantro_dec.c
new file mode 100644
index 0000000..ac501f3
--- /dev/null
+++ b/drivers/gpu/drm/hantro/hantro_dec.c
@@ -0,0 +1,1441 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *    Hantro decoder hardware driver.
+ *
+ *    Copyright (c) 2017 - 2020, VeriSilicon Inc.
+ *    Copyright (c) 2020 Intel Corporation
+ */
+
+#include "hantro_dec.h"
+#include "hantro_dwl_defs.h"
+#include <linux/io.h>
+#include <linux/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>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+
+static const int dec_hwid[] = {
+       0x8001 /* VDEC */
+};
+
+ulong multicorebase[HXDEC_MAX_CORES] = {
+       SOCLE_LOGIC_0_BASE,
+       SOCLE_LOGIC_1_BASE
+};
+
+int irq[HXDEC_MAX_CORES] = {
+       DEC_IRQ_0,
+       DEC_IRQ_1
+};
+
+unsigned int iosize[HXDEC_MAX_CORES] = {
+       DEC_IO_SIZE_0,
+       DEC_IO_SIZE_1
+};
+
+/* KMB page lookup table */
+static unsigned long page_lut_read = KMB_VC8000D_PAGE_LUT;
+static u8 *page_lut_regs_read;
+
+/*
+ * Because one core may contain multi-pipeline,
+ * so multicore base may be changed
+ */
+unsigned long multicorebase_actual[HXDEC_MAX_CORES];
+int elements = 2;
+static struct device *parent_dev;
+
+struct hantrodec_t {
+       char *buffer;
+       unsigned int iosize[HXDEC_MAX_CORES];
+       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;
+};
+
+struct core_cfg {
+       /* indicate the supported format */
+       u32 cfg[HXDEC_MAX_CORES];
+       /* back up of cfg */
+       u32 cfg_backup[HXDEC_MAX_CORES];
+       /* indicate if main core exist */
+       int its_main_core_id[HXDEC_MAX_CORES];
+       /* indicate if aux core exist */
+       int its_aux_core_id[HXDEC_MAX_CORES];
+};
+
+static struct hantrodec_t hantrodec_data;
+static int reserve_io(void);
+static void release_io(void);
+static void reset_asic(struct hantrodec_t *dev);
+
+#ifdef HANTRODEC_DEBUG
+static void dump_regs(struct hantrodec_t *dev);
+#endif
+
+/* IRQ handler */
+static irqreturn_t hantrodec_isr(int irq, void *dev_id);
+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;
+static int pp_irq;
+
+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];
+static int core_has_format(const u32 *cfg, int core, u32 format);
+
+static DEFINE_SPINLOCK(owner_lock);
+static DECLARE_WAIT_QUEUE_HEAD(dec_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(pp_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(hw_queue);
+
+static struct core_cfg config;
+static u32 timeout;
+
+static struct clk *hantro_clk_xin_vdec;
+static struct clk *hantro_clk_vdec;
+
+static int hantro_clk_enable(void)
+{
+       clk_prepare_enable(hantro_clk_xin_vdec);
+       clk_prepare_enable(hantro_clk_vdec);
+
+       return 0;
+}
+
+static int hantro_clk_disable(void)
+{
+       if (hantro_clk_xin_vdec)
+               clk_disable_unprepare(hantro_clk_xin_vdec);
+
+       if (hantro_clk_vdec)
+               clk_disable_unprepare(hantro_clk_vdec);
+
+       return 0;
+}
+
+u32 hantrodec_readbandwidth(int is_read_bw)
+{
+       int i;
+       u32 bandwidth = 0;
+       struct hantrodec_t *dev = &hantrodec_data;
+
+       for (i = 0; i < hantrodec_data.cores; i++) {
+               if (is_read_bw)
+                       bandwidth +=
+                               ioread32((void *)(dev->hwregs[i] +
+                                                 HANTRO_VC8KD_REG_BWREAD * 4));
+               else
+                       bandwidth += ioread32
+                               ((void *)(dev->hwregs[i] +
+                                        HANTRO_VC8KD_REG_BWWRITE * 4));
+       }
+
+       return bandwidth * VC8KD_BURSTWIDTH;
+}
+
+static void read_core_config(struct hantrodec_t *dev)
+{
+       int c;
+       u32 reg, tmp, mask;
+
+       memset(config.cfg, 0, sizeof(config.cfg));
+
+       for (c = 0; c < dev->cores; c++) {
+               /* Decoder configuration */
+               if ((IS_VC8000D(dev->hw_id[c])) &&
+                   config.its_main_core_id[c] < 0) {
+                       reg = ioread32((void *)(dev->hwregs[c] +
+                                               HANTRODEC_SYNTH_CFG * 4));
+
+                       tmp = (reg >> DWL_H264_E) & 0x3U;
+                       if (tmp)
+                               pr_info("hantrodec: core[%d] has H264\n", c);
+                       config.cfg[c] |=
+                               tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+                       tmp = (reg >> DWL_JPEG_E) & 0x01U;
+                       if (tmp)
+                               pr_info("hantrodec: core[%d] has JPEG\n", c);
+                       config.cfg[c] |=
+                               tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+
+                       tmp = (reg >> DWL_MPEG4_E) & 0x3U;
+                       if (tmp)
+                               pr_info("hantrodec: core[%d] has MPEG4\n", c);
+                       config.cfg[c] |=
+                               tmp ? 1 << DWL_CLIENT_TYPE_MPEG4_DEC : 0;
+
+                       tmp = (reg >> DWL_VC1_E) & 0x3U;
+                       if (tmp)
+                               pr_info("hantrodec: core[%d] has VC1\n", c);
+                       config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VC1_DEC : 0;
+
+                       tmp = (reg >> DWL_MPEG2_E) & 0x01U;
+                       if (tmp)
+                               pr_info("hantrodec: core[%d] has MPEG2\n", c);
+                       config.cfg[c] |=
+                               tmp ? 1 << DWL_CLIENT_TYPE_MPEG2_DEC : 0;
+
+                       tmp = (reg >> DWL_VP6_E) & 0x01U;
+                       if (tmp)
+                               pr_info("hantrodec: core[%d] has VP6\n", c);
+                       config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP6_DEC : 0;
+
+                       reg = ioread32((void *)(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))
+                               pr_info("hantrodec: core[%d] has VP8\n", c);
+                       if (tmp & (1 << DWL_VP7_E))
+                               pr_info("hantrodec: core[%d] has VP7\n", c);
+                       if (tmp & (1 << DWL_WEBP_E))
+                               pr_info("hantrodec: core[%d] has WebP\n", c);
+                       config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP8_DEC : 0;
+
+                       tmp = (reg >> DWL_AVS_E) & 0x01U;
+                       if (tmp)
+                               pr_info("hantrodec: core[%d] has AVS\n", c);
+                       config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_AVS_DEC : 0;
+
+                       tmp = (reg >> DWL_RV_E) & 0x03U;
+                       if (tmp)
+                               pr_info("hantrodec: core[%d] has RV\n", c);
+                       config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_RV_DEC : 0;
+
+                       reg = ioread32((void *)(dev->hwregs[c] +
+                                               HANTRODEC_SYNTH_CFG_3 * 4));
+
+                       tmp = (reg >> DWL_HEVC_E) & 0x07U;
+                       if (tmp)
+                               pr_info("hantrodec: core[%d] has HEVC\n", c);
+                       config.cfg[c] |=
+                               tmp ? 1 << DWL_CLIENT_TYPE_HEVC_DEC : 0;
+
+                       tmp = (reg >> DWL_VP9_E) & 0x07U;
+                       if (tmp)
+                               pr_info("hantrodec: core[%d] has VP9\n", c);
+                       config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP9_DEC : 0;
+
+                       /* Post-processor configuration */
+                       reg = ioread32((void *)(dev->hwregs[c] +
+                                               HANTRODECPP_CFG_STAT * 4));
+
+                       tmp = (reg >> DWL_PP_E) & 0x01U;
+                       if (tmp)
+                               pr_info("hantrodec: core[%d] has PP\n", c);
+                       config.cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_PP : 0;
+
+                       if (config.its_aux_core_id[c] >= 0) {
+                               /* set main_core_id and aux_core_id */
+                               reg = ioread32
+                                       ((void *)(dev->hwregs[c] +
+                                                HANTRODEC_SYNTH_CFG_2 * 4));
+
+                               tmp = (reg >> DWL_H264_PIPELINE_E) & 0x01U;
+                               if (tmp)
+                                       pr_info("hantrodec: core[%d] has 
pipeline H264\n",
+                                               c);
+                               config.cfg[config.its_aux_core_id[c]] |=
+                                       tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+                               tmp = (reg >> DWL_JPEG_PIPELINE_E) & 0x01U;
+                               if (tmp)
+                                       pr_info("hantrodec: core[%d] has 
pipeline JPEG\n",
+                                               c);
+                               config.cfg[config.its_aux_core_id[c]] |=
+                                       tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+                       }
+               }
+       }
+       memcpy(config.cfg_backup, config.cfg, sizeof(config.cfg));
+}
+
+static int core_has_format(const u32 *cfg, int core, u32 format)
+{
+       return (cfg[core] & (1 << format)) ? 1 : 0;
+}
+
+static int get_dec_core(long core, struct hantrodec_t *dev, struct file *filp,
+                       unsigned long format)
+{
+       int success = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&owner_lock, flags);
+       if (core_has_format(config.cfg, core, format) &&
+           !dec_owner[core]) {
+               dec_owner[core] = filp;
+               success = 1;
+               /*
+                * If one main core takes one format which doesn't supported
+                * by aux core, set aux core's cfg to none video format support
+                */
+               if (config.its_aux_core_id[core] >= 0) {
+                       if (!core_has_format(config.cfg,
+                                            config.its_aux_core_id[core],
+                                            format))
+                               config.cfg[config.its_aux_core_id[core]] = 0;
+                       else
+                               config.cfg[config.its_aux_core_id[core]] =
+                                       (1 << format);
+               }
+               /*
+                * If one aux core takes one format,
+                * set main core's cfg to aux core supported video format
+                */
+               else if (config.its_main_core_id[core] >= 0)
+                       config.cfg[config.its_main_core_id[core]] =
+                               (1 << format);
+       }
+
+       spin_unlock_irqrestore(&owner_lock, flags);
+
+       return success;
+}
+
+static int get_dec_core_any(long *core, struct 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 (get_dec_core(c, dev, filp, format)) {
+                       success = 1;
+                       *core = c;
+                       break;
+               }
+       }
+
+       return success;
+}
+
+static int get_dec_coreid(struct hantrodec_t *dev, struct file *filp,
+                         unsigned long format)
+{
+       long c;
+       unsigned long flags;
+
+       int core_id = -1;
+
+       for (c = 0; c < dev->cores; c++) {
+               /* a core that has format */
+               spin_lock_irqsave(&owner_lock, flags);
+               if (core_has_format(config.cfg_backup, c, format)) {
+                       core_id = c;
+                       spin_unlock_irqrestore(&owner_lock, flags);
+                       break;
+               }
+               spin_unlock_irqrestore(&owner_lock, flags);
+       }
+
+       return core_id;
+}
+
+static long reserve_decoder(struct 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, get_dec_core_any(&core, dev, 
filp,
+                                                               format) != 0))
+               return -ERESTARTSYS;
+       PDEBUG("reserve core %ld:%lx", core, (unsigned long)filp);
+
+       return core;
+}
+
+static void release_decoder(struct hantrodec_t *dev, long core)
+{
+       u32 status;
+       unsigned long flags;
+
+       status = ioread32
+                       ((void *)(dev->hwregs[core] +
+                                 HANTRODEC_IRQ_STAT_DEC_OFF));
+
+       /* make sure HW is disabled */
+       if (status & HANTRODEC_DEC_E) {
+               PDEBUG("hantrodec: DEC[%li] still enabled -> reset\n", core);
+               /* abort decoder */
+               status |= HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+               iowrite32(status, (void *)(dev->hwregs[core] +
+                                          HANTRODEC_IRQ_STAT_DEC_OFF));
+       }
+
+       spin_lock_irqsave(&owner_lock, flags);
+       /* If aux core released, revert main core's config back */
+       if (config.its_main_core_id[core] >= 0)
+               config.cfg[config.its_main_core_id[core]] =
+                       config.cfg_backup[config.its_main_core_id[core]];
+
+       /* If main core released, revert aux core's config back */
+       if (config.its_aux_core_id[core] >= 0)
+               config.cfg[config.its_aux_core_id[core]] =
+                       config.cfg_backup[config.its_aux_core_id[core]];
+
+       dec_owner[core] = NULL;
+       spin_unlock_irqrestore(&owner_lock, flags);
+       up(&dec_core_sem);
+       wake_up_interruptible_all(&hw_queue);
+}
+
+static long reserve_post_processor(struct 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;
+}
+
+static void release_post_processor(struct hantrodec_t *dev, long core)
+{
+       unsigned long flags;
+
+       u32 status =
+               ioread32((void *)(dev->hwregs[core] + HANTRO_IRQ_STAT_PP_OFF));
+
+       /* make sure HW is disabled */
+       if (status & HANTRO_PP_E) {
+               PDEBUG("hantrodec: PP[%li] still enabled -> reset\n", core);
+               /* disable IRQ */
+               status |= HANTRO_PP_IRQ_DISABLE;
+               /* disable postprocessor */
+               status &= (~HANTRO_PP_E);
+               iowrite32(0x10,
+                         (void *)(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 reserve_dec_pp(struct 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 (!core_has_format(config.cfg, core, format))
+               return -EFAULT;
+
+       /* check that core has PP */
+       if (!core_has_format(config.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, get_dec_core(core, dev, filp,
+                                                           format) != 0)) {
+               up(&dec_core_sem);
+               return -ERESTARTSYS;
+       }
+
+       if (down_interruptible(&pp_core_sem)) {
+               release_decoder(dev, core);
+               return -ERESTARTSYS;
+       }
+
+       spin_lock_irqsave(&owner_lock, flags);
+       pp_owner[core] = filp;
+       spin_unlock_irqrestore(&owner_lock, flags);
+
+       return core;
+}
+
+static long dec_flush_regs(struct hantrodec_t *dev, struct core_desc *core)
+{
+       long ret = 0, i;
+
+       u32 id = core->id;
+
+       ret = copy_from_user(dec_regs[id], core->regs, HANTRO_VC8000D_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_VC8000D_LAST_REG; i++)
+               iowrite32(dec_regs[id][i], (void *)(dev->hwregs[id] + i * 4));
+       /* write the status register, which may start the decoder */
+       iowrite32(dec_regs[id][1], (void *)(dev->hwregs[id] + 4));
+
+       PDEBUG("flushed registers on core %d\n", id);
+
+       return 0;
+}
+
+static long dec_refresh_regs(struct hantrodec_t *dev, struct core_desc *core)
+{
+       long ret, i;
+       u32 id = core->id;
+
+       for (i = 0; i <= HANTRO_VC8000D_LAST_REG; i++)
+               dec_regs[id][i] = ioread32((void *)(dev->hwregs[id] + i * 4));
+
+       ret = copy_to_user(core->regs, dec_regs[id],
+                          HANTRO_VC8000D_LAST_REG * 4);
+       if (ret) {
+               PDEBUG("copy_to_user failed, returned %li\n", ret);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+static int check_dec_irq(struct 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;
+}
+
+static long wait_dec_ready_and_refresh_regs(struct hantrodec_t *dev,
+                                           struct core_desc *core)
+{
+       u32 id = core->id;
+       long ret;
+
+       PDEBUG("wait_event_interruptible DEC[%d]\n", id);
+       ret = wait_event_interruptible_timeout
+               (dec_wait_queue, check_dec_irq(dev, id), msecs_to_jiffies(10));
+       if (ret == -ERESTARTSYS) {
+               pr_err("DEC[%d]  failed to wait_event_interruptible 
interrupted\n",
+                      id);
+               return -ERESTARTSYS;
+       } else if (ret == 0) {
+               pr_err("DEC[%d]  wait_event_interruptible timeout\n", id);
+               timeout = 1;
+               return -EBUSY;
+       }
+       atomic_inc(&irq_tx);
+
+       /* refresh registers */
+       return dec_refresh_regs(dev, core);
+}
+
+static long dec_write_regs(struct hantrodec_t *dev, struct core_desc *core)
+{
+       long ret = 0, i;
+       u32 id = core->id;
+
+       i = core->reg_id;
+       ret = copy_from_user(dec_regs[id] + core->reg_id,
+                            core->regs + core->reg_id, 4);
+       if (ret) {
+               PDEBUG("copy_from_user failed, returned %li\n", ret);
+               return -EFAULT;
+       }
+       iowrite32(dec_regs[id][i], (void *)dev->hwregs[id] + i * 4);
+
+       return 0;
+}
+
+u32 *hantrodec_get_reg_addr(u32 coreid, u32 regid)
+{
+       if (coreid >= hantrodec_data.cores)
+               return NULL;
+       if (regid * 4 >= hantrodec_data.iosize[coreid])
+               return NULL;
+
+       return (u32 *)(hantrodec_data.hwregs[coreid] + regid * 4);
+}
+
+static long dec_read_regs(struct hantrodec_t *dev, struct core_desc *core)
+{
+       long ret, i;
+       u32 id = core->id;
+
+       i = core->reg_id;
+
+       /* read specific registers from hardware */
+       i = core->reg_id;
+       dec_regs[id][i] = ioread32((void *)dev->hwregs[id] + i * 4);
+       /* put registers to user space*/
+       ret = copy_to_user(core->regs + core->reg_id,
+                          dec_regs[id] + core->reg_id, 4);
+       if (ret) {
+               PDEBUG("copy_to_user failed, returned %li\n", ret);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+static long pp_flush_regs(struct hantrodec_t *dev, struct core_desc *core)
+{
+       long ret = 0;
+       u32 id = core->id;
+       u32 i;
+
+       /* copy original dec regs to kernel 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);
+       if (ret) {
+               pr_err("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], (void *)dev->hwregs[id] + i * 4);
+       /* write the stat reg, which may start the PP */
+       iowrite32(dec_regs[id][HANTRO_PP_ORG_FIRST_REG],
+                 (void *)dev->hwregs[id] + HANTRO_PP_ORG_FIRST_REG * 4);
+
+       return 0;
+}
+
+static long pp_refresh_regs(struct hantrodec_t *dev, struct core_desc *core)
+{
+       long i, ret;
+       u32 id = core->id;
+       /* user has to know exactly what they are asking for */
+       if (core->size != (HANTRO_PP_ORG_REGS * 4))
+               return -EFAULT;
+       /* 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((void *)dev->hwregs[id] + i * 4);
+       /* 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);
+       if (ret) {
+               pr_err("copy_to_user failed, returned %li\n", ret);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+static int check_pp_irq(struct 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;
+}
+
+static long wait_pp_ready_and_refresh_regs(struct 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, check_pp_irq(dev, id))) {
+               pr_err("PP[%d]  failed to wait_event_interruptible 
interrupted\n",
+                      id);
+               return -ERESTARTSYS;
+       }
+
+       atomic_inc(&irq_tx);
+
+       /* refresh registers */
+       return pp_refresh_regs(dev, core);
+}
+
+static int check_core_irq(struct 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) {
+                       PDEBUG("%s get irq for core %d:%lx", __func__, n,
+                              (unsigned long)filp);
+                       if (*id == n) {
+                               /* 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]) {
+                               /* zombie IRQ */
+                               PDEBUG("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;
+}
+
+static long wait_core_ready(struct hantrodec_t *dev, const struct file *filp,
+                           int *id)
+{
+       PDEBUG("wait_event_interruptible CORE\n");
+
+       if (wait_event_interruptible(dec_wait_queue,
+                                    check_core_irq(dev, filp, id))) {
+               pr_err("CORE  failed to 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
+ *-------------------------------------------------------------------------
+ */
+long hantrodec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       int err = 0;
+       u32 id;
+       long tmp;
+       struct core_desc core;
+
+       switch (_IOC_NR(cmd)) {
+       case _IOC_NR(HANTRODEC_IOC_CLI): {
+               id = arg;
+               if (id >= hantrodec_data.cores)
+                       return -EFAULT;
+               disable_irq(hantrodec_data.irq[id]);
+               break;
+       }
+       case _IOC_NR(HANTRODEC_IOC_STI): {
+               id = arg;
+               if (id >= hantrodec_data.cores)
+                       return -EFAULT;
+               enable_irq(hantrodec_data.irq[id]);
+               break;
+       }
+       case _IOC_NR(HANTRODEC_IOCGHWOFFSET): {
+               __get_user(id, (__u32 *)arg);
+               if (id >= hantrodec_data.cores)
+                       return -EFAULT;
+
+               __put_user(multicorebase_actual[id], (unsigned long *)arg);
+               break;
+       }
+       case _IOC_NR(HANTRODEC_IOCGHWIOSIZE): {
+               __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 _IOC_NR(HANTRODEC_IOC_MC_OFFSETS): {
+               tmp = copy_to_user((unsigned long *)arg, multicorebase_actual,
+                                  sizeof(multicorebase_actual));
+               if (err) {
+                       pr_err("copy_to_user failed, returned %li\n", tmp);
+                       return -EFAULT;
+               }
+               break;
+       }
+       case _IOC_NR(HANTRODEC_IOC_MC_CORES):
+               __put_user(hantrodec_data.cores, (unsigned int *)arg);
+               PDEBUG("hantrodec_data.cores=%d\n", hantrodec_data.cores);
+               break;
+       case _IOC_NR(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) {
+                       pr_err("copy_from_user failed, returned %li\n", tmp);
+                       return -EFAULT;
+               }
+
+               dec_flush_regs(&hantrodec_data, &core);
+               break;
+       }
+
+       case _IOC_NR(HANTRODEC_IOCS_DEC_WRITE_REG): {
+               /* 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;
+               }
+
+               dec_write_regs(&hantrodec_data, &core);
+               break;
+       }
+       case _IOC_NR(HANTRODEC_IOCS_PP_PUSH_REG): {
+               /* get registers from user space */
+               tmp = copy_from_user(&core, (void *)arg,
+                                    sizeof(struct core_desc));
+               if (tmp) {
+                       pr_err("copy_from_user failed, returned %li\n", tmp);
+                       return -EFAULT;
+               }
+
+               pp_flush_regs(&hantrodec_data, &core);
+               break;
+       }
+       case _IOC_NR(HANTRODEC_IOCS_DEC_PULL_REG): {
+               tmp = copy_from_user(&core, (void *)arg,
+                                    sizeof(struct core_desc));
+               if (tmp) {
+                       pr_err("copy_from_user failed, returned %li\n", tmp);
+                       return -EFAULT;
+               }
+
+               return dec_refresh_regs(&hantrodec_data, &core);
+       }
+       case _IOC_NR(HANTRODEC_IOCS_DEC_READ_REG): {
+               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 dec_read_regs(&hantrodec_data, &core);
+       }
+       case _IOC_NR(HANTRODEC_IOCS_PP_PULL_REG): {
+               tmp = copy_from_user(&core, (void *)arg,
+                                    sizeof(struct core_desc));
+               if (tmp) {
+                       pr_err("copy_from_user failed, returned %li\n", tmp);
+                       return -EFAULT;
+               }
+
+               return pp_refresh_regs(&hantrodec_data, &core);
+       }
+       case _IOC_NR(HANTRODEC_IOCH_DEC_RESERVE): {
+               PDEBUG("Reserve DEC core, format = %li\n", arg);
+               return reserve_decoder(&hantrodec_data, filp, arg);
+       }
+       case _IOC_NR(HANTRODEC_IOCT_DEC_RELEASE): {
+               if (arg >= hantrodec_data.cores || dec_owner[arg] != filp) {
+                       pr_err("bogus DEC release, core = %li\n", arg);
+                       return -EFAULT;
+               }
+
+               PDEBUG("Release DEC, core = %li\n", arg);
+
+               release_decoder(&hantrodec_data, arg);
+
+               break;
+       }
+       case _IOC_NR(HANTRODEC_IOCQ_PP_RESERVE):
+               return reserve_post_processor(&hantrodec_data, filp);
+       case _IOC_NR(HANTRODEC_IOCT_PP_RELEASE): {
+               if (arg != 0 || pp_owner[arg] != filp) {
+                       pr_err("bogus PP release %li\n", arg);
+                       return -EFAULT;
+               }
+
+               release_post_processor(&hantrodec_data, arg);
+
+               break;
+       }
+       case _IOC_NR(HANTRODEC_IOCX_DEC_WAIT): {
+               tmp = copy_from_user(&core, (void *)arg,
+                                    sizeof(struct core_desc));
+               if (tmp) {
+                       pr_err("copy_from_user failed, returned %li\n", tmp);
+                       return -EFAULT;
+               }
+
+               return wait_dec_ready_and_refresh_regs(&hantrodec_data, &core);
+       }
+       case _IOC_NR(HANTRODEC_IOCX_PP_WAIT): {
+               tmp = copy_from_user(&core, (void *)arg,
+                                    sizeof(struct core_desc));
+               if (tmp) {
+                       pr_err("copy_from_user failed, returned %li\n", tmp);
+                       return -EFAULT;
+               }
+
+               return wait_pp_ready_and_refresh_regs(&hantrodec_data, &core);
+       }
+       case _IOC_NR(HANTRODEC_IOCG_CORE_WAIT): {
+               int id;
+
+               __get_user(id, (int *)arg);
+               tmp = wait_core_ready(&hantrodec_data, filp, &id);
+               __put_user(id, (int *)arg);
+               return tmp;
+       }
+       case _IOC_NR(HANTRODEC_IOX_ASIC_ID): {
+               __get_user(id, (u32 *)arg);
+               if (id >= hantrodec_data.cores)
+                       return -EFAULT;
+               id = ioread32((void *)hantrodec_data.hwregs[id]);
+               __put_user(id, (u32 *)arg);
+               return 0;
+       }
+       case _IOC_NR(HANTRODEC_IOCG_CORE_ID): {
+               PDEBUG("Get DEC core_id, format = %li\n", arg);
+               tmp = get_dec_coreid(&hantrodec_data, filp, arg);
+               return tmp;
+       }
+       case _IOC_NR(HANTRODEC_DEBUG_STATUS): {
+               PDEBUG("hantrodec: dec_irq     = 0x%08x\n", dec_irq);
+               PDEBUG("hantrodec: pp_irq      = 0x%08x\n", pp_irq);
+
+               PDEBUG("hantrodec: IRQs received/sent2user = %d / %d\n",
+                      atomic_read(&irq_rx), atomic_read(&irq_tx));
+
+               for (tmp = 0; tmp < hantrodec_data.cores; tmp++) {
+                       PDEBUG("hantrodec: dec_core[%li] %s\n", tmp,
+                              !dec_owner[tmp] ? "FREE" : "RESERVED");
+                       PDEBUG("hantrodec: pp_core[%li]  %s\n", tmp,
+                              !pp_owner[tmp]  ? "FREE" : "RESERVED");
+               }
+               break;
+       }
+       default:
+               return -ENOTTY;
+       }
+
+       return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : hantrodec_release
+ *Description     : Release driver
+ *
+ *Return type     : int
+ *----------------------------------------------------------------------------
+ */
+int hantrodec_release(struct file *filp)
+{
+       int n;
+       struct hantrodec_t *dev = &hantrodec_data;
+
+       for (n = 0; n < dev->cores; n++) {
+               if (dec_owner[n] == filp) {
+                       PDEBUG("releasing dec core %i lock\n", n);
+                       release_decoder(dev, n);
+               }
+       }
+
+       for (n = 0; n < 1; n++) {
+               if (pp_owner[n] == filp) {
+                       PDEBUG("releasing pp core %i lock\n", n);
+                       release_post_processor(dev, n);
+               }
+       }
+
+       return 0;
+}
+
+int hantrodec_open(struct inode *inode, struct file *filp)
+{
+       return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : hantrodec_init
+ *Description     : Initialize the driver
+ *
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+int hantrodec_init(struct platform_device *pdev)
+{
+       int result = 0;
+       int irq_0;
+       int i;
+
+       dec_irq = 0;
+       pp_irq = 0;
+       parent_dev = &pdev->dev;
+       pr_info("hantrodec: Init multi core[0] at 0x%16lx\n"
+               "core[1] at 0x%16lx\n",
+               multicorebase[0], multicorebase[1]);
+
+       hantrodec_data.cores = 0;
+       hantrodec_data.iosize[0] = DEC_IO_SIZE_0;
+       hantrodec_data.irq[0] = -1;
+       hantrodec_data.iosize[1] = DEC_IO_SIZE_1;
+       hantrodec_data.irq[1] = -1;
+
+       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;
+       /* Enable and set the VDEC clks */
+       hantro_clk_xin_vdec = clk_get(&pdev->dev, "clk_xin_vdec");
+       hantro_clk_vdec = clk_get(&pdev->dev, "clk_vdec");
+       hantro_clk_enable();
+       /* Set KMB CLK to 700 Mhz VDEC */
+       pr_info("hantrodec: Before setting any clocks: clk_xin_vdec: %ld | 
clk_vdec %ld\n",
+               clk_get_rate(hantro_clk_xin_vdec),
+               clk_get_rate(hantro_clk_vdec));
+       clk_set_rate(hantro_clk_xin_vdec, 700000000);
+       pr_info("hantrodec: Set clocks to 700Mhz: clk_xin_vdec: %ld | clk_vdec 
%ld\n",
+               clk_get_rate(hantro_clk_xin_vdec),
+               clk_get_rate(hantro_clk_vdec));
+
+       result = reserve_io();
+
+       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);
+       sema_init(&pp_core_sem, 1);
+
+       /* read configuration for all cores */
+       read_core_config(&hantrodec_data);
+       /* reset hardware */
+       reset_asic(&hantrodec_data);
+
+       /* Dynamic AXI ID and Page LUT routines */
+       /* Register and set the page lookup table for read */
+       if (!request_mem_region(page_lut_read, hantrodec_data.iosize[0],
+                               "hantrodec_pagelut_read")) {
+               pr_info("hantrodec: failed to reserve page lookup table 
registers\n");
+               return -EBUSY;
+       }
+       page_lut_regs_read =
+               (u8 *)ioremap(page_lut_read, hantrodec_data.iosize[0]);
+       if (!page_lut_regs_read)
+               pr_info("hantrodec: failed to ioremap page lookup table 
registers\n");
+
+       /* Set VDEC RD Page LUT AXI ID 0-15 to 0x4 */
+       iowrite32(0x04040404, (void *)page_lut_regs_read);
+       pr_info("hantrodec: RD AXI ID 3:0 = %x\n",
+               ioread32((void *)page_lut_regs_read));
+       iowrite32(0x04040404, (void *)page_lut_regs_read + 0x4);
+       pr_info("hantrodec: RD AXI ID 7:4 = %x\n",
+               ioread32((void *)page_lut_regs_read + 0x4));
+       iowrite32(0x04040404, (void *)page_lut_regs_read + 0x8);
+       pr_info("hantrodec: RD AXI ID 11:8 = %x\n",
+               ioread32((void *)page_lut_regs_read + 0x8));
+       iowrite32(0x04040404, (void *)page_lut_regs_read + 0xc);
+       pr_info("hantrodec: RD AXI ID 15:12 = %x\n",
+               ioread32((void *)page_lut_regs_read + 0xc));
+
+       /* dynamic WR AXI ID */
+       /* Set sw_dec_axi_wr_id_e to 1 */
+       iowrite32(1 << 13, (void *)hantrodec_data.hwregs[0] + 0xE8);
+       pr_info("hantrodec: sw_dec_axi_wr_id_e  = %x\n",
+               ioread32((void *)hantrodec_data.hwregs[0] + 0xE8));
+       /*
+        * Set WR Page LUT AXI ID 0-3, 6-15 to 0x4 and
+        * WR Page LUT AXI ID 4,5 to 0x0
+        */
+       iowrite32(0x04040404, (void *)page_lut_regs_read + 0x10);
+       pr_info("hantrodec: page_lut_regs WR AXI ID 3:0= %x\n",
+               ioread32((void *)page_lut_regs_read + 0x10));
+       iowrite32(0x04040000, (void *)page_lut_regs_read + 0x14);
+       pr_info("hantrodec: page_lut_regs WR AXI ID 7:4= %x\n",
+               ioread32((void *)page_lut_regs_read + 0x14));
+       iowrite32(0x04040404, (void *)page_lut_regs_read + 0x18);
+       pr_info("hantrodec: page_lut_regs WR AXI ID 11:8= %x\n",
+               ioread32((void *)page_lut_regs_read + 0x18));
+       iowrite32(0x04040404, (void *)page_lut_regs_read + 0x1c);
+       pr_info("hantrodec: page_lut_regs WR AXI ID 15:12= %x\n",
+               ioread32((void *)page_lut_regs_read + 0x1c));
+
+       /* register irq for each core */
+       irq_0 = irq[0];
+       if (irq_0 > 0) {
+               PDEBUG("irq_0 platform_get_irq\n");
+               irq_0 = platform_get_irq_byname(pdev, "irq_hantro_decoder");
+               result = request_irq(irq_0, hantrodec_isr, IRQF_SHARED,
+                                    "irq_hantro_decoder",
+                                    (void *)&hantrodec_data);
+               if (result != 0) {
+                       PDEBUG("can't reserve irq0\n");
+                       goto err0;
+               }
+               PDEBUG("reserve irq0 success with irq0 = %d\n", irq_0);
+               hantrodec_data.irq[0] = irq_0;
+       } else {
+               PDEBUG("can't get irq0 and irq0 value = %d\n", irq_0);
+               result = -EINVAL;
+               goto err0;
+       }
+
+       pr_info("hantrodec: module inserted.\n");
+
+       return 0;
+err0:
+       release_io();
+
+err:
+       return result;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : hantrodec_cleanup
+ *Description     : clean up
+ *
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+void hantrodec_cleanup(void)
+{
+       struct hantrodec_t *dev = &hantrodec_data;
+       int n = 0;
+       /* reset hardware */
+       reset_asic(dev);
+
+       /* free the IRQ */
+       for (n = 0; n < dev->cores; n++) {
+               if (dev->irq[n] != -1)
+                       free_irq(dev->irq[n], (void *)dev);
+       }
+
+       release_io();
+       hantro_clk_disable();
+       pr_info("hantrodec: module removed\n");
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : check_hw_id
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+static int check_hw_id(struct hantrodec_t *dev)
+{
+       long hwid;
+       int i;
+       size_t num_hw = sizeof(dec_hwid) / sizeof(*dec_hwid);
+
+       int found = 0;
+
+       for (i = 0; i < dev->cores; i++) {
+               if (dev->hwregs[i]) {
+                       hwid = readl(dev->hwregs[i]);
+                       PDEBUG("hantrodec: core %d HW ID=0x%16lx\n", i, hwid);
+                       hwid = (hwid >> 16) & 0xFFFF;
+
+                       while (num_hw--) {
+                               if (hwid == dec_hwid[num_hw]) {
+                                       PDEBUG("hantrodec: Supported HW found 
at 0x%16lx\n",
+                                              multicorebase_actual[i]);
+                                       found++;
+                                       dev->hw_id[i] = hwid;
+                                       break;
+                               }
+                       }
+                       if (!found) {
+                               PDEBUG("hantrodec: Unknown HW found at 
0x%16lx\n",
+                                      multicorebase_actual[i]);
+                               return 0;
+                       }
+                       found = 0;
+                       num_hw = sizeof(dec_hwid) / sizeof(*dec_hwid);
+               }
+       }
+
+       return 1;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : reserve_io
+ *Description     : IO reserve
+ *
+ *Return type     : int
+ *---------------------------------------------------------------------------
+ */
+static int reserve_io(void)
+{
+       int i;
+       long hwid;
+       u32 reg;
+
+       memcpy(multicorebase_actual, multicorebase,
+              HXDEC_MAX_CORES * sizeof(unsigned long));
+       memcpy((unsigned int *)(hantrodec_data.iosize), iosize,
+              HXDEC_MAX_CORES * sizeof(unsigned int));
+       memcpy((unsigned int *)hantrodec_data.irq, irq,
+              HXDEC_MAX_CORES * sizeof(int));
+
+       for (i = 0; i < HXDEC_MAX_CORES; i++) {
+               if (multicorebase_actual[i] != -1) {
+                       if (!request_mem_region(multicorebase_actual[i],
+                                               hantrodec_data.iosize[i],
+                                               "hantrodec0")) {
+                               PDEBUG("hantrodec: failed to reserve HW 
regs\n");
+                               return -EBUSY;
+                       }
+
+                       hantrodec_data.hwregs[i] =
+                               (u8 *)ioremap(multicorebase_actual[i],
+                                                     hantrodec_data.iosize[i]);
+
+                       if (!hantrodec_data.hwregs[i]) {
+                               PDEBUG("hantrodec: failed to ioremap HW 
regs\n");
+                               release_io();
+                               return -EBUSY;
+                       }
+
+                       hantrodec_data.cores++;
+                       config.its_main_core_id[i] = -1;
+                       config.its_aux_core_id[i] = -1;
+                       hwid = ((readl(hantrodec_data.hwregs[i])) >> 16) &
+                              0xFFFF;
+
+                       if (IS_VC8000D(hwid)) {
+                               reg = readl(hantrodec_data.hwregs[i] +
+                                           HANTRODEC_SYNTH_CFG_2_OFF);
+                               if (((reg >> DWL_H264_PIPELINE_E) & 0x01U) ||
+                                   ((reg >> DWL_JPEG_PIPELINE_E) & 0x01U)) {
+                                       i++;
+                                       config.its_aux_core_id[i - 1] = i;
+                                       config.its_main_core_id[i] = i - 1;
+                                       config.its_aux_core_id[i] = -1;
+                                       multicorebase_actual[i] =
+                                               multicorebase_actual[i - 1] +
+                                               0x800;
+                                       hantrodec_data.iosize[i] =
+                                               hantrodec_data.iosize[i - 1];
+                                       memcpy(multicorebase_actual + i + 1,
+                                              multicorebase + i,
+                                              (HXDEC_MAX_CORES - i - 1) *
+                                                      sizeof(unsigned long));
+                                       memcpy((unsigned int *)(hantrodec_data
+                                                                       .iosize 
+
+                                                               i + 1),
+                                              iosize + i,
+                                              (HXDEC_MAX_CORES - i - 1) *
+                                                      sizeof(unsigned int));
+                                       if (!request_mem_region
+                                           (multicorebase_actual[i],
+                                            hantrodec_data.iosize[i],
+                                                   "hantrodec0")) {
+                                               PDEBUG("hantrodec: failed to 
reserve HW regs\n");
+                                               return -EBUSY;
+                                       }
+
+                                       hantrodec_data.hwregs[i] =
+                                               (u8 *)ioremap
+                                                       
(multicorebase_actual[i],
+                                                        hantrodec_data
+                                                               .iosize[i]);
+
+                                       if (!hantrodec_data.hwregs[i]) {
+                                               PDEBUG("hantrodec: failed to 
ioremap HW regs\n");
+                                               release_io();
+                                               return -EBUSY;
+                                       }
+                                       hantrodec_data.cores++;
+                               }
+                       }
+               }
+       }
+
+       /* check for correct HW */
+       if (!check_hw_id(&hantrodec_data)) {
+               release_io();
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : release_io
+ *Description     : release
+ *
+ *Return type     : void
+ *---------------------------------------------------------------------------
+ */
+static void release_io(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_actual[i],
+                                  hantrodec_data.iosize[i]);
+       }
+
+       iounmap((void *)page_lut_regs_read);
+       release_mem_region(page_lut_read, hantrodec_data.iosize[0]);
+}
+
+/*---------------------------------------------------------------------------
+ *Function name   : hantrodec_isr
+ *Description     : interrupt handler
+ *
+ *Return type     : irqreturn_t
+ *---------------------------------------------------------------------------
+ */
+static irqreturn_t hantrodec_isr(int irq, void *dev_id)
+{
+       unsigned long flags;
+       unsigned int handled = 0;
+       int i;
+
+       u8 *hwregs;
+       struct hantrodec_t *dev;
+       u32 irq_status_dec;
+
+       dev = (struct hantrodec_t *)dev_id;
+       spin_lock_irqsave(&owner_lock, flags);
+
+       for (i = 0; i < dev->cores; i++) {
+               u8 *hwregs = dev->hwregs[i];
+
+               /* interrupt status register read */
+               irq_status_dec =
+                       ioread32((void *)hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+               PDEBUG("%d core irq = %x\n", i, irq_status_dec);
+               if (irq_status_dec & HANTRODEC_DEC_IRQ) {
+                       /* clear dec IRQ */
+                       irq_status_dec &= (~HANTRODEC_DEC_IRQ);
+                       iowrite32(irq_status_dec,
+                                 (void *)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   : reset_asic
+ *Description     : reset asic
+ *
+ *Return type     :
+ *---------------------------------------------------------------------------
+ */
+static void reset_asic(struct hantrodec_t *dev)
+{
+       int i, j;
+       u32 status;
+
+       for (j = 0; j < dev->cores; j++) {
+               status = ioread32((void *)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, (void *)dev->hwregs[j] +
+                                                 HANTRODEC_IRQ_STAT_DEC_OFF);
+               }
+
+               for (i = 4; i < dev->iosize[j]; i += 4)
+                       iowrite32(0, (void *)dev->hwregs[j] + i);
+       }
+}
diff --git a/drivers/gpu/drm/hantro/hantro_dec.h 
b/drivers/gpu/drm/hantro/hantro_dec.h
new file mode 100644
index 0000000..c0f7573
--- /dev/null
+++ b/drivers/gpu/drm/hantro/hantro_dec.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *    Hantro decoder hardware driver header file.
+ *
+ *    Copyright (c) 2017 - 2020, VeriSilicon Inc.
+ *    Copyright (c) 2020 Intel Corporation
+ */
+
+#ifndef _HANTRODEC_H_
+#define _HANTRODEC_H_
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include "hantro_drm.h"
+
+#undef PDEBUG
+#ifdef HANTRODEC_DEBUG
+#ifdef __KERNEL__
+#define PDEBUG(fmt, args...) pr_info("hantrodec: " fmt, ##args)
+#else
+#define PDEBUG(fmt, args...) fprintf(stderr, fmt, ##args)
+#endif
+#else
+#define PDEBUG(fmt, args...)
+#endif
+
+/* hantro PP regs */
+#define HANTRO_PP_ORG_REGS              41
+#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 VC8000D reg config */
+#define HANTRO_VC8000D_REGS             342 /* VC8000D total regs */
+#define HANTRO_VC8000D_FIRST_REG        0
+#define HANTRO_VC8000D_LAST_REG         (HANTRO_VC8000D_REGS - 1)
+#define HANTRO_VC8KD_REG_BWREAD         300
+#define HANTRO_VC8KD_REG_BWWRITE        301
+#define VC8KD_BURSTWIDTH                16
+#define DEC_IO_SIZE_MAX                 (HANTRO_VC8000D_REGS * 4)
+#define HXDEC_MAX_CORES                 2
+
+/* Logic module base address */
+#define SOCLE_LOGIC_0_BASE              0x20888000
+#define SOCLE_LOGIC_1_BASE              0x20888800
+#define DEC_IO_SIZE_0                   DEC_IO_SIZE_MAX /* bytes */
+#define DEC_IO_SIZE_1                   DEC_IO_SIZE_MAX /* bytes */
+#define DEC_IRQ_0                       138
+#define DEC_IRQ_1                       138
+#define KMB_VC8000D_PAGE_LUT            0x20889000
+#define IS_VC8000D(hw_id)               (((hw_id) == 0x8001) ? 1 : 0)
+
+int hantrodec_init(struct platform_device *pdev);
+void hantrodec_cleanup(void);
+long hantrodec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+u32 *hantrodec_get_reg_addr(u32 coreid, u32 regid);
+int hantrodec_open(struct inode *inode, struct file *filp);
+u32 hantrodec_readbandwidth(int is_read_bw);
+#endif /* !_HANTRODEC_H_ */
diff --git a/drivers/gpu/drm/hantro/hantro_dwl_defs.h 
b/drivers/gpu/drm/hantro/hantro_dwl_defs.h
new file mode 100644
index 0000000..4411c62
--- /dev/null
+++ b/drivers/gpu/drm/hantro/hantro_dwl_defs.h
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *    Hantro driver hardware register definition.
+ *
+ *    Copyright (c) 2017 - 2020, VeriSilicon Inc.
+ *    Copyright (c) 2020 Intel Corporation
+ */
+
+#ifndef SOFTWARE_LINUX_DWL_DWL_DEFS_H_
+#define SOFTWARE_LINUX_DWL_DWL_DEFS_H_
+
+#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
+
+#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  */
+#define DWL_G1_PP_E                    16 /* 1 bit  */
+#define DWL_G2_PP_E                    31 /* 1 bit  */
+#define DWL_PP_E                       31 /* 1 bit  */
+#define DWL_HEVC_E                     26 /* 3 bits */
+#define DWL_VP9_E                      29 /* 3 bits */
+
+#define DWL_H264_PIPELINE_E            31 /* 1 bit */
+#define DWL_JPEG_PIPELINE_E            30 /* 1 bit */
+
+#define DWL_G2_HEVC_E                  0 /* 1 bits */
+#define DWL_G2_VP9_E                   1 /* 1 bits */
+#define DWL_G2_RFC_E                   2 /* 1 bits */
+#define DWL_RFC_E                      17 /* 2 bits */
+#define DWL_G2_DS_E                    3 /* 1 bits */
+#define DWL_DS_E                       28 /* 3 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 HANTRODECPP_CFG_STAT           260
+#define HANTRODECPP_CFG_STAT_OFF       (HANTRODECPP_CFG_STAT * 4)
+/* VC8000D HW build id */
+#define HANTRODEC_HW_BUILD_ID          309
+#define HANTRODEC_HW_BUILD_ID_OFF      (HANTRODEC_HW_BUILD_ID * 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_ */
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to