All of lore.kernel.org
 help / color / mirror / Atom feed
From: kuhanh.murugasen.krishnan@intel.com
To: dri-devel@lists.freedesktop.org
Subject: [PATCH v1 2/4] drm: hantro: Keem Bay VPU DRM encoder
Date: Fri,  9 Oct 2020 19:57:53 +0800	[thread overview]
Message-ID: <1602244675-8785-3-git-send-email-kuhanh.murugasen.krishnan@intel.com> (raw)
In-Reply-To: <1602244675-8785-1-git-send-email-kuhanh.murugasen.krishnan@intel.com>

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

Hantro VC8000E allows 4K encoding with a minimal silicon single-core solution that
supports HEVC and H.264 video formats, key features:
* HEVC Main10, Main and Main Still Profile, level 5.1
* H.264 Baseline, Main and High, High10 level 5.2
* JPEG encoder 16Kx16K max resolution
* HEVC/H264 Support up to 4K@60fps performance single-core
* 8 channels 1080p@30fps encoding
* B-frame support for higher compression rates
* Reference Frame Compression

Signed-off-by: Murugasen Krishnan, Kuhanh <kuhanh.murugasen.krishnan@intel.com>
---
 drivers/gpu/drm/hantro/hantro_enc.c | 738 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/hantro/hantro_enc.h |  66 ++++
 2 files changed, 804 insertions(+)
 create mode 100644 drivers/gpu/drm/hantro/hantro_enc.c
 create mode 100644 drivers/gpu/drm/hantro/hantro_enc.h

diff --git a/drivers/gpu/drm/hantro/hantro_enc.c b/drivers/gpu/drm/hantro/hantro_enc.c
new file mode 100644
index 0000000..35d1153
--- /dev/null
+++ b/drivers/gpu/drm/hantro/hantro_enc.c
@@ -0,0 +1,738 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *    Hantro encoder hardware driver.
+ *
+ *    Copyright (c) 2017 - 2020, VeriSilicon Inc.
+ *    Copyright (c) 2020 Intel Corporation
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/uaccess.h>
+#include <linux/ioport.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/timer.h>
+#include "hantro_enc.h"
+#include <linux/irq.h>
+#include <linux/clk.h>
+
+struct semaphore enc_core_sem;
+static DECLARE_WAIT_QUEUE_HEAD(enc_hw_queue);
+static DEFINE_SPINLOCK(enc_owner_lock);
+static DECLARE_WAIT_QUEUE_HEAD(enc_wait_queue);
+
+/* for all cores, the core info should be listed here for subsequent use */
+/* base_addr, iosize, irq, resource_shared */
+struct enc_core enc_core_array[] = {
+	{ CORE_0_IO_ADDR, CORE_0_IO_SIZE, INT_PIN_CORE_0,
+	  RESOURCE_SHARED_INTER_CORES }, /* core_0, hevc and avc */
+	{ CORE_1_IO_ADDR, CORE_1_IO_SIZE, INT_PIN_CORE_1,
+	  RESOURCE_SHARED_INTER_CORES } /* core_1, jpeg */
+};
+
+/* Interrupt Pin Name */
+const char *core_irq_names[] = {
+	"irq_hantro_videoencoder",   /* core_0, hevc and avc */
+	"irq_hantro_jpegencoder"    /* core_1, jpeg */
+};
+
+/* KMB VC8000E page lookup table */
+static unsigned long page_lut_read = KMB_VC8000E_PAGE_LUT;
+static u8 *page_lut_regs_read;
+
+static struct clk *hantro_clk_xin_venc;
+static struct clk *hantro_clk_xin_jpeg;
+static struct clk *hantro_clk_venc;
+static struct clk *hantro_clk_jpeg;
+
+static int hantro_clk_enable(void)
+{
+	clk_prepare_enable(hantro_clk_xin_venc);
+	clk_prepare_enable(hantro_clk_xin_jpeg);
+	clk_prepare_enable(hantro_clk_venc);
+	clk_prepare_enable(hantro_clk_jpeg);
+
+	return 0;
+}
+
+static int hantro_clk_disable(void)
+{
+	if (hantro_clk_xin_venc)
+		clk_disable_unprepare(hantro_clk_xin_venc);
+
+	if (hantro_clk_venc)
+		clk_disable_unprepare(hantro_clk_venc);
+
+	if (hantro_clk_xin_jpeg)
+		clk_disable_unprepare(hantro_clk_xin_jpeg);
+
+	if (hantro_clk_jpeg)
+		clk_disable_unprepare(hantro_clk_jpeg);
+
+	return 0;
+}
+
+/***************************TYPE AND FUNCTION DECLARATION****************/
+struct hantroenc_t {
+	struct enc_core core_cfg;	//config of each core,such as base addr, irq,etc
+	u32 hw_id;		//hw id to indicate project
+	u32 core_id;		//core id for driver and sw internal use
+	u32 is_valid;		//indicate this core is hantro's core or not
+	u32 is_reserved;	//indicate this core is occupied by user or not
+	int pid;		//indicate which process is occupying the core
+	u32 irq_received;	//indicate this core receives irq
+	u32 irq_status;
+	char *buffer;
+	unsigned int buffsize;
+	u8 *hwregs;
+	struct fasync_struct *async_queue;
+};
+
+static int reserve_io(void);
+static void release_io(void);
+static void reset_asic(struct hantroenc_t *dev);
+static int check_core_occupation(struct hantroenc_t *dev);
+static void release_encoder(struct hantroenc_t *dev, u32 *core_info);
+
+#ifdef hantroenc_DEBUG
+static void dump_regs(unsigned long data);
+#endif
+
+/* IRQ handler */
+static irqreturn_t hantroenc_isr(int irq, void *dev_id);
+
+/*********************local variable declaration*****************/
+unsigned long sram_base;
+unsigned int sram_size;
+/* and this is our MAJOR; use 0 for dynamic allocation (recommended) */
+static int hantroenc_major;
+static int total_core_num;
+/* dynamic allocation */
+static struct hantroenc_t *hantroenc_data;
+
+/******************************************************************************/
+static int check_enc_irq(struct hantroenc_t *dev, u32 *core_info, u32 *irq_status)
+{
+	unsigned long flags;
+	int rdy = 0;
+	u32 i = 0;
+	u8 core_mapping = 0;
+
+	core_mapping = (u8)(*core_info & 0xFF);
+
+	while (core_mapping) {
+		if (core_mapping & 0x1) {
+			if (i > total_core_num - 1)
+				break;
+
+			spin_lock_irqsave(&enc_owner_lock, flags);
+
+			if (dev[i].irq_received) {
+				/* reset the wait condition(s) */
+				PDEBUG("check %d irq ready\n", i);
+				dev[i].irq_received = 0;
+				rdy = 1;
+				*core_info = i;
+				*irq_status = dev[i].irq_status;
+			}
+
+			spin_unlock_irqrestore(&enc_owner_lock, flags);
+			break;
+		}
+		core_mapping = core_mapping >> 1;
+		i++;
+	}
+
+	return rdy;
+}
+
+static unsigned int wait_enc_ready(struct hantroenc_t *dev, u32 *core_info,
+				   u32 *irq_status)
+{
+	if (wait_event_interruptible(enc_wait_queue,
+				     check_enc_irq(dev, core_info, irq_status))) {
+		PDEBUG("ENC wait_event_interruptible interrupted\n");
+		release_encoder(dev, core_info);
+		return -ERESTARTSYS;
+	}
+
+	return 0;
+}
+
+u32 hantroenc_readbandwidth(int is_read_bw)
+{
+	int i;
+	u32 bandwidth = 0;
+
+	for (i = 0; i < total_core_num; i++) {
+		if (hantroenc_data[i].is_valid == 0)
+			continue;
+
+		if (is_read_bw)
+			bandwidth +=
+				ioread32((void *)(hantroenc_data[i].hwregs +
+						  HANTRO_VC8KE_REG_BWREAD * 4));
+		else
+			bandwidth +=
+				ioread32((void *)(hantroenc_data[i].hwregs +
+					 HANTRO_VC8KE_REG_BWWRITE * 4));
+	}
+
+	return bandwidth * VC8KE_BURSTWIDTH;
+}
+
+static int check_core_occupation(struct hantroenc_t *dev)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&enc_owner_lock, flags);
+	if (!dev->is_reserved) {
+		dev->is_reserved = 1;
+		dev->pid = current->pid;
+		ret = 1;
+		PDEBUG("%s pid=%d\n", __func__, dev->pid);
+	}
+
+	spin_unlock_irqrestore(&enc_owner_lock, flags);
+
+	return ret;
+}
+
+static int get_workable_core(struct hantroenc_t *dev, u32 *core_info,
+			     u32 *core_info_tmp)
+{
+	int ret = 0;
+	u32 i = 0;
+	u32 cores;
+	u32 core_id = 0;
+	u8 core_mapping = 0;
+	u32 required_num = 0;
+
+	cores = *core_info;
+	required_num = ((cores >> CORE_INFO_AMOUNT_OFFSET) & 0x7) + 1;
+	core_mapping = (u8)(cores & 0xFF);
+
+	if (*core_info_tmp == 0)
+		*core_info_tmp = required_num << 8;
+	else
+		required_num = ((*core_info_tmp & 0xF00) >> 8);
+
+	PDEBUG("%s:required_num=%d,core_info=%x\n", __func__, required_num,
+	       *core_info);
+
+	if (required_num) {
+		/* a valid free Core that has specified core id */
+		while (core_mapping) {
+			if (core_mapping & 0x1) {
+				if (i > total_core_num - 1)
+					break;
+				core_id = i;
+				if (dev[core_id].is_valid &&
+				    check_core_occupation(&dev[core_id])) {
+					*core_info_tmp =
+						((((*core_info_tmp & 0xF00) >>
+						   8) -
+						  1)
+						 << 8) |
+						(*core_info_tmp & 0x0FF);
+					*core_info_tmp =
+						*core_info_tmp | (1 << core_id);
+					if (((*core_info_tmp & 0xF00) >> 8) ==
+					    0) {
+						ret = 1;
+						*core_info =
+							(*core_info &
+							 0xFFFFFF00) |
+							(*core_info_tmp & 0xFF);
+						*core_info_tmp = 0;
+						required_num = 0;
+						break;
+					}
+				}
+			}
+			core_mapping = core_mapping >> 1;
+			i++;
+		}
+	} else {
+		ret = 1;
+	}
+
+	return ret;
+}
+
+static long reserve_encoder(struct hantroenc_t *dev, u32 *core_info)
+{
+	u32 core_info_tmp = 0;
+	/*
+	 * If HW resources are shared inter cores
+	 * just make sure only one is using the HW
+	 */
+	if (dev[0].core_cfg.resource_shared) {
+		if (down_interruptible(&enc_core_sem))
+			return -ERESTARTSYS;
+	}
+
+	/* lock a core that has specified core id */
+	if (wait_event_interruptible(enc_hw_queue,
+				     get_workable_core(dev, core_info,
+						       &core_info_tmp) != 0))
+		return -ERESTARTSYS;
+
+	return 0;
+}
+
+static void release_encoder(struct hantroenc_t *dev, u32 *core_info)
+{
+	unsigned long flags;
+	u32 core_num = 0;
+	u32 i = 0, core_id;
+	u8 core_mapping = 0;
+
+	core_num = ((*core_info >> CORE_INFO_AMOUNT_OFFSET) & 0x7) + 1;
+
+	core_mapping = (u8)(*core_info & 0xFF);
+
+	PDEBUG("%s:core_num=%d,core_mapping=%x\n", __func__, core_num,
+	       core_mapping);
+	/* release specified core id */
+	while (core_mapping) {
+		if (core_mapping & 0x1) {
+			core_id = i;
+			spin_lock_irqsave(&enc_owner_lock, flags);
+			PDEBUG("dev[core_id].pid=%d,current->pid=%d\n",
+			       dev[core_id].pid, current->pid);
+			if (dev[core_id].is_reserved &&
+			    dev[core_id].pid == current->pid) {
+				dev[core_id].pid = -1;
+				dev[core_id].is_reserved = 0;
+			}
+
+			dev[core_id].irq_received = 0;
+			dev[core_id].irq_status = 0;
+			spin_unlock_irqrestore(&enc_owner_lock, flags);
+		}
+		core_mapping = core_mapping >> 1;
+		i++;
+	}
+
+	wake_up_interruptible_all(&enc_hw_queue);
+	if (dev->core_cfg.resource_shared)
+		up(&enc_core_sem);
+}
+
+long hantroenc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	unsigned int tmp;
+
+	if (!hantroenc_data)
+		return -ENXIO;
+	switch (cmd) {
+	case HX280ENC_IOCGHWOFFSET: {
+		u32 id;
+
+		__get_user(id, (u32 *)arg);
+
+		if (id >= total_core_num || hantroenc_data[id].is_valid == 0)
+			return -EFAULT;
+
+		__put_user(hantroenc_data[id].core_cfg.base_addr,
+			   (unsigned long *)arg);
+		break;
+	}
+
+	case HX280ENC_IOCGHWIOSIZE: {
+		u32 id;
+		u32 io_size;
+
+		__get_user(id, (u32 *)arg);
+
+		if (id >= total_core_num || hantroenc_data[id].is_valid == 0)
+			return -EFAULT;
+
+		io_size = hantroenc_data[id].core_cfg.iosize;
+		__put_user(io_size, (u32 *)arg);
+
+		return 0;
+	}
+	case HX280ENC_IOCGSRAMOFFSET:
+		__put_user(sram_base, (unsigned long *)arg);
+		break;
+	case HX280ENC_IOCGSRAMEIOSIZE:
+		__put_user(sram_size, (unsigned int *)arg);
+		break;
+	case HX280ENC_IOCG_CORE_NUM:
+		__put_user(total_core_num, (unsigned int *)arg);
+		PDEBUG("enc core num = %d", total_core_num);
+		break;
+	case HX280ENC_IOCH_ENC_RESERVE: {
+		u32 core_info;
+		int ret;
+
+		PDEBUG("Reserve ENC Cores\n");
+		__get_user(core_info, (u32 *)arg);
+		ret = reserve_encoder(hantroenc_data, &core_info);
+		if (ret == 0)
+			__put_user(core_info, (u32 *)arg);
+		return ret;
+	}
+	case HX280ENC_IOCH_ENC_RELEASE: {
+		u32 core_info;
+
+		__get_user(core_info, (u32 *)arg);
+
+		PDEBUG("Release ENC Core\n");
+
+		release_encoder(hantroenc_data, &core_info);
+
+		break;
+	}
+
+	case HX280ENC_IOCG_CORE_WAIT: {
+		u32 core_info;
+		u32 irq_status;
+
+		__get_user(core_info, (u32 *)arg);
+
+		tmp = wait_enc_ready(hantroenc_data, &core_info, &irq_status);
+		if (tmp == 0) {
+			__put_user(irq_status, (unsigned int *)arg);
+			return core_info; //return core_id
+		}
+		__put_user(0, (unsigned int *)arg);
+		return -1;
+
+		break;
+	}
+	}
+
+	return 0;
+}
+
+int hantroenc_init(struct platform_device *pdev)
+{
+	int result = 0;
+	int i;
+
+	sram_base = 0;
+	sram_size = 0;
+	hantroenc_major = 0;
+	total_core_num = 0;
+	hantroenc_data = NULL;
+
+	total_core_num = sizeof(enc_core_array) / sizeof(struct enc_core);
+	for (i = 0; i < total_core_num; i++) {
+		pr_info("hantroenc: module init - core[%d] addr = %lx\n", i,
+			(size_t)enc_core_array[i].base_addr);
+	}
+
+	hantroenc_data = vmalloc(sizeof(*hantroenc_data) * total_core_num);
+	if (!hantroenc_data)
+		goto err;
+	memset(hantroenc_data, 0, sizeof(*hantroenc_data) * total_core_num);
+
+	for (i = 0; i < total_core_num; i++) {
+		hantroenc_data[i].core_cfg = enc_core_array[i];
+		hantroenc_data[i].async_queue = NULL;
+		hantroenc_data[i].hwregs = NULL;
+		hantroenc_data[i].core_id = i;
+	}
+
+	hantroenc_data[0].core_cfg.irq =
+		platform_get_irq_byname(pdev, "irq_hantro_videoencoder");
+	hantroenc_data[1].core_cfg.irq =
+		platform_get_irq_byname(pdev, "irq_hantro_jpgencoder");
+
+	hantro_clk_xin_venc = clk_get(&pdev->dev, "clk_xin_venc");
+	hantro_clk_venc = clk_get(&pdev->dev, "clk_venc");
+	hantro_clk_xin_jpeg = clk_get(&pdev->dev, "clk_xin_jpeg");
+	hantro_clk_jpeg = clk_get(&pdev->dev, "clk_jpeg");
+	hantro_clk_enable();
+
+	/* Set KMB VENC CLK to max 700Mhz VENC */
+	pr_info("hx280enc venc: Before setting any clocks: clk_xin_venc: %ld | clk_venc %ld\n",
+		clk_get_rate(hantro_clk_xin_venc),
+		clk_get_rate(hantro_clk_venc));
+	clk_set_rate(hantro_clk_xin_venc, 700000000);
+	pr_info("hx280enc venc: Set clocks to 700Mhz: clk_xin_venc: %ld | clk_venc %ld\n",
+		clk_get_rate(hantro_clk_xin_venc),
+		clk_get_rate(hantro_clk_venc));
+
+	/* Set KMB JPEGENC CLK to max 700Mhz JPEGENC */
+	pr_info("hx280enc jpegenc: Before setting any clocks: clk_xin_jpeg: %ld | clk_jpeg %ld\n",
+		clk_get_rate(hantro_clk_xin_jpeg),
+		clk_get_rate(hantro_clk_jpeg));
+	clk_set_rate(hantro_clk_xin_jpeg, 700000000);
+	pr_info("hx280enc jpegenc: Set clocks to 700Mhz: clk_xin_jpeg: %ld | clk_jpeg %ld\n",
+		clk_get_rate(hantro_clk_xin_jpeg),
+		clk_get_rate(hantro_clk_jpeg));
+
+	result = reserve_io();
+	if (result < 0)
+		goto err;
+
+	reset_asic(hantroenc_data); /* reset hardware */
+
+	sema_init(&enc_core_sem, 1);
+
+	/* Dynamic AXI ID and Page LUT routines */
+	/* Register and set the page lookup table for encoder */
+	if (!request_mem_region(page_lut_read,
+				hantroenc_data[0].core_cfg.iosize,
+				"hantroenc_pagelut_read")) {
+		pr_info("hantroenc: failed to reserve page lookup table regs\n");
+		return -EBUSY;
+	}
+	page_lut_regs_read = (u8 *)ioremap
+		(page_lut_read, hantroenc_data[0].core_cfg.iosize);
+	if (!page_lut_regs_read)
+		pr_info("hantroenc: failed to ioremap page lookup table regs\n");
+
+	/* Set write page LUT AXI ID 1-8 to 0x4 */
+	iowrite32(0x04040400, (void *)page_lut_regs_read + 0x10);
+	pr_info("hx280enc: Page LUT WR AXI ID 3:0 = %x\n",
+		ioread32((void *)page_lut_regs_read + 0x10));
+	iowrite32(0x04040404, (void *)page_lut_regs_read + 0x14);
+	pr_info("hx280enc: Page LUT WR AXI ID 7:4 = %x\n",
+		ioread32((void *)page_lut_regs_read + 0x14));
+	iowrite32(0x4, (void *)page_lut_regs_read + 0x18);
+	pr_info("hx280enc: Page LUT WR AXI ID 8 = %x\n",
+		ioread32((void *)page_lut_regs_read + 0x18));
+
+	/* Set VENC sw_enc_axi_rd_id_e = 1 */
+	iowrite32(1 << 16, (void *)hantroenc_data[0].hwregs + 0x8);
+	pr_info("hx280enc: sw_enc_axi_rd_id_e  = %x\n",
+		ioread32((void *)hantroenc_data[0].hwregs + 0x8));
+	/* Set RD Page LUT AXI ID 0.1 to 0x0 and the rest AXI ID 2-8 to 0x4 */
+	iowrite32(0x04040000, (void *)page_lut_regs_read);
+	pr_info("hx280enc: RD AXI 3:0 = %x\n",
+		ioread32((void *)page_lut_regs_read));
+	iowrite32(0x04040404, (void *)page_lut_regs_read + 0x4);
+	pr_info("hx280enc: RD AXI 7:4  = %x\n",
+		ioread32((void *)page_lut_regs_read + 0x4));
+	iowrite32(0x00000004, (void *)page_lut_regs_read + 0x8);
+	pr_info("hx280enc: RD AXI 8 = %x\n",
+		ioread32((void *)page_lut_regs_read + 0x8));
+
+	/* get the IRQ line */
+	for (i = 0; i < total_core_num; i++) {
+		if (hantroenc_data[i].is_valid == 0)
+			continue;
+		if (hantroenc_data[i].core_cfg.irq > 0) {
+			PDEBUG("hx280enc: Trying to request_irq = %d\n",
+			       hantroenc_data[i].core_cfg.irq);
+
+			result = request_irq(hantroenc_data[i].core_cfg.irq,
+					     hantroenc_isr, IRQF_SHARED,
+					     core_irq_names[i],
+					     (void *)&hantroenc_data[i]);
+
+			if (result == -EINVAL) {
+				PDEBUG("hx280enc: Bad irq number or handler\n");
+				release_io();
+				goto err;
+			} else if (result == -EBUSY) {
+				PDEBUG("hx280enc: IRQ <%d> busy, change config\n",
+				       hantroenc_data[i].core_cfg.irq);
+				release_io();
+				goto err;
+			}
+		}
+	}
+
+	pr_info("hantroenc: module inserted.\n");
+
+	return 0;
+err:
+	pr_info("hantroenc: module not inserted\n");
+	return result;
+}
+
+void hantroenc_cleanup(void)
+{
+	int i = 0;
+
+	for (i = 0; i < total_core_num; i++) {
+		u32 hwid = hantroenc_data[i].hw_id;
+		u32 major_id = (hwid & 0x0000FF00) >> 8;
+		u32 wclr = (major_id >= 0x61) ? (0x1FD) : (0);
+
+		if (hantroenc_data[i].is_valid == 0)
+			continue;
+		iowrite32(0, (void *)(hantroenc_data[i].hwregs +
+				      0x14)); /* disable HW */
+		iowrite32(wclr, (void *)(hantroenc_data[i].hwregs +
+					 0x04)); /* clear enc IRQ */
+
+		/* free the encoder IRQ */
+		if (hantroenc_data[i].core_cfg.irq > 0)
+			free_irq(hantroenc_data[i].core_cfg.irq,
+				 (void *)&hantroenc_data[i]);
+	}
+
+	release_io();
+	vfree(hantroenc_data);
+	hantro_clk_disable();
+	pr_info("hantroenc: module removed\n");
+}
+
+static int reserve_io(void)
+{
+	u32 hwid;
+	int i;
+	u32 found_hw = 0;
+
+	for (i = 0; i < total_core_num; i++) {
+		if (!request_mem_region(hantroenc_data[i].core_cfg.base_addr,
+					hantroenc_data[i].core_cfg.iosize,
+					"hx280enc")) {
+			PDEBUG("hantroenc: failed to reserve HW regs\n");
+			continue;
+		}
+
+		hantroenc_data[i].hwregs =
+			(u8 *)ioremap(hantroenc_data[i].core_cfg.base_addr,
+			hantroenc_data[i].core_cfg.iosize);
+
+		if (!hantroenc_data[i].hwregs) {
+			PDEBUG("hantroenc: failed to ioremap HW regs\n");
+			release_io();
+			continue;
+		}
+
+		/* read hwid and check validness and store it */
+		hwid = (u32)ioread32((void *)hantroenc_data[i].hwregs);
+		PDEBUG("hwid=0x%08x\n", hwid);
+
+		/* check for encoder HW ID */
+		if (((((hwid >> 16) & 0xFFFF) !=
+		      ((ENC_HW_ID1 >> 16) & 0xFFFF))) &&
+		    ((((hwid >> 16) & 0xFFFF) !=
+		      ((ENC_HW_ID2 >> 16) & 0xFFFF)))) {
+			PDEBUG("hantroenc: HW not found at %lx\n",
+			       hantroenc_data[i].core_cfg.base_addr);
+#ifdef hantroenc_DEBUG
+			dump_regs((unsigned long)&hantroenc_data);
+#endif
+			release_io();
+			hantroenc_data[i].is_valid = 0;
+			continue;
+		}
+		hantroenc_data[i].hw_id = hwid;
+		hantroenc_data[i].is_valid = 1;
+		found_hw = 1;
+
+		PDEBUG("hantroenc: HW at base <%lx> with ID <0x%08x>\n",
+		       hantroenc_data[i].core_cfg.base_addr, hwid);
+	}
+
+	if (found_hw == 0) {
+		PDEBUG("hantroenc: NO ANY HW found!!\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void release_io(void)
+{
+	u32 i;
+
+	for (i = 0; i < total_core_num; i++) {
+		if (hantroenc_data[i].is_valid == 0)
+			continue;
+		if (hantroenc_data[i].hwregs)
+			iounmap((void *)hantroenc_data[i].hwregs);
+		release_mem_region(hantroenc_data[i].core_cfg.base_addr,
+				   hantroenc_data[i].core_cfg.iosize);
+	}
+
+	iounmap((void *)page_lut_regs_read);
+	release_mem_region(page_lut_read, hantroenc_data[0].core_cfg.iosize);
+}
+
+static irqreturn_t hantroenc_isr(int irq, void *dev_id)
+{
+	unsigned int handled = 0;
+	struct hantroenc_t *dev = (struct hantroenc_t *)dev_id;
+	u32 irq_status;
+	unsigned long flags;
+
+	/*
+	 * If core is not reserved by any user,
+	 * but irq is received, just ignore it
+	 */
+	spin_lock_irqsave(&enc_owner_lock, flags);
+	if (!dev->is_reserved) {
+		PDEBUG("%s:received IRQ but core is not reserved!\n", __func__);
+		irq_status = (u32)ioread32((void *)(dev->hwregs + 0x04));
+		if (irq_status & 0x01) {
+			/*
+			 * clear all IRQ bits by writing value 1
+			 * (hwid >= 0x80006100) means IRQ is cleared
+			 */
+			u32 hwid = ioread32((void *)dev->hwregs);
+			u32 major_id = (hwid & 0x0000FF00) >> 8;
+			u32 wclr = (major_id >= 0x61) ? irq_status :
+						       (irq_status & (~0x1FD));
+
+			iowrite32(wclr, (void *)(dev->hwregs + 0x04));
+		}
+		spin_unlock_irqrestore(&enc_owner_lock, flags);
+		return IRQ_HANDLED;
+	}
+	spin_unlock_irqrestore(&enc_owner_lock, flags);
+
+	PDEBUG("%s:received IRQ!\n", __func__);
+	irq_status = (u32)ioread32((void *)(dev->hwregs + 0x04));
+	PDEBUG("hx280enc: irq_status of %d is:%x\n", dev->core_id, irq_status);
+	if (irq_status & 0x01) {
+		/*
+		 * clear all IRQ bits by writing value 1
+		 * (hwid >= 0x80006100) means IRQ is cleared
+		 */
+		u32 hwid = ioread32((void *)dev->hwregs);
+		u32 major_id = (hwid & 0x0000FF00) >> 8;
+		u32 wclr = (major_id >= 0x61) ? irq_status :
+					       (irq_status & (~0x1FD));
+
+		iowrite32(wclr, (void *)(dev->hwregs + 0x04));
+		spin_lock_irqsave(&enc_owner_lock, flags);
+		dev->irq_received = 1;
+		dev->irq_status = irq_status & (~0x01);
+		spin_unlock_irqrestore(&enc_owner_lock, flags);
+
+		wake_up_interruptible_all(&enc_wait_queue);
+		handled++;
+	}
+	if (!handled)
+		PDEBUG("IRQ received, but not hantro's!\n");
+
+	return IRQ_HANDLED;
+}
+
+static void reset_asic(struct hantroenc_t *dev)
+{
+	int i, n;
+
+	for (n = 0; n < total_core_num; n++) {
+		if (dev[n].is_valid == 0)
+			continue;
+		iowrite32(0, (void *)(dev[n].hwregs + 0x14));
+		for (i = 4; i < dev[n].core_cfg.iosize; i += 4)
+			iowrite32(0, (void *)(dev[n].hwregs + i));
+	}
+}
diff --git a/drivers/gpu/drm/hantro/hantro_enc.h b/drivers/gpu/drm/hantro/hantro_enc.h
new file mode 100644
index 0000000..711de74
--- /dev/null
+++ b/drivers/gpu/drm/hantro/hantro_enc.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *    Hantro encoder hardware driver header file.
+ *
+ *    Copyright (c) 2017 - 2020, VeriSilicon Inc.
+ *    Copyright (c) 2020 Intel Corporation
+ */
+
+#ifndef _HX280ENC_H_
+#define _HX280ENC_H_
+
+#include "hantro_drm.h"
+
+/*
+ * Macros to help debugging
+ */
+#undef PDEBUG
+#ifdef HX280ENC_DEBUG
+#ifdef __KERNEL__
+/* This one if debugging is on, and kernel space */
+#define PDEBUG(fmt, args...) pr_info("hmp4e: " fmt, ##args)
+#else
+/* This one for user space */
+#define PDEBUG(fmt, args...) printf(__FILE__ ":%d: " fmt, __LINE__, ##args)
+#endif
+#else
+#define PDEBUG(fmt, args...) /* not debugging: nothing */
+#endif
+
+/*------------------------------------------------------------------------
+ *****************************PORTING LAYER********************************
+ *-------------------------------------------------------------------------
+ */
+/*0:no resource sharing inter cores 1: existing resource sharing*/
+#define RESOURCE_SHARED_INTER_CORES     0
+#define CORE_0_IO_ADDR                  0x20884000 //Video
+#define CORE_1_IO_ADDR                  0x208a0000 //JPEG
+
+#define CORE_0_IO_SIZE                  (250 * 4) /* bytes */
+#define CORE_1_IO_SIZE                  (250 * 4) /* bytes */
+
+#define INT_PIN_CORE_0                  137
+#define INT_PIN_CORE_1                  64
+
+#define HANTRO_VC8KE_REG_BWREAD         216
+#define HANTRO_VC8KE_REG_BWWRITE        220
+#define VC8KE_BURSTWIDTH                16
+#define KMB_VC8000E_PAGE_LUT            0x20885000
+
+#define ENC_HW_ID1			0x48320100
+#define ENC_HW_ID2			0x80006000
+#define CORE_INFO_MODE_OFFSET		31
+#define CORE_INFO_AMOUNT_OFFSET		28
+
+struct enc_core {
+	unsigned long base_addr;
+	u32 iosize;
+	int irq;
+	u32 resource_shared;
+};
+
+long hantroenc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+int hantroenc_init(struct platform_device *pdev);
+void hantroenc_cleanup(void);
+u32 hantroenc_readbandwidth(int is_read_bw);
+#endif /* !_HX280ENC_H_ */
-- 
1.9.1

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

  parent reply	other threads:[~2020-10-09 18:12 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-09 11:57 [PATCH v1 0/4] Add support for Keem Bay VPU DRM driver kuhanh.murugasen.krishnan
2020-10-09 11:57 ` [PATCH v1 1/4] drm: Add Keem Bay VPU codec DRM kuhanh.murugasen.krishnan
2020-10-09 22:15   ` Daniel Vetter
2020-10-10  8:20     ` Ezequiel Garcia
2020-10-10  8:20       ` Ezequiel Garcia
2020-10-09 11:57 ` kuhanh.murugasen.krishnan [this message]
2020-10-09 11:57 ` [PATCH v1 3/4] drm: hantro: Keem Bay VPU DRM decoder kuhanh.murugasen.krishnan
2020-10-09 11:57 ` [PATCH v1 4/4] drm: hantro: Keem Bay VPU DRM build files kuhanh.murugasen.krishnan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1602244675-8785-3-git-send-email-kuhanh.murugasen.krishnan@intel.com \
    --to=kuhanh.murugasen.krishnan@intel.com \
    --cc=dri-devel@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.