/* Allocate firmware */
int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
{
#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
	int err;
	struct cma_info mem_info_f, mem_info_a, mem_info_b;
#endif
	unsigned int base_align;
	unsigned int firmware_size;
	void *alloc_ctx;

	mfc_debug_enter();

	if (!dev) {
		mfc_err("no mfc device to run\n");
		return -EINVAL;
	}

	base_align = dev->variant->buf_align->mfc_base_align;
	firmware_size = dev->variant->buf_size->firmware_code;
	alloc_ctx = dev->alloc_ctx[MFC_CMA_FW_ALLOC_CTX];

#if !defined(CONFIG_VIDEOBUF2_ION)
	if (s5p_mfc_bitproc_buf) {
		mfc_err("Attempting to allocate firmware when it seems that it is already loaded.\n");
		return -ENOMEM;
	}
#else
	if (s5p_mfc_bitproc_buf)
		return 0;
#endif

	/* Get memory region information and check if it is correct */
#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
	err = cma_info(&mem_info_f, dev->v4l2_dev.dev, MFC_CMA_FW);
	mfc_debug(3, "Area \"%s\" is from %08x to %08x and has size %08x", "f",
				mem_info_f.lower_bound, mem_info_f.upper_bound,
							mem_info_f.total_size);
	if (err) {
		mfc_err("Couldn't get memory information from CMA.\n");
		return -EINVAL;
	}
	err = cma_info(&mem_info_a, dev->v4l2_dev.dev, MFC_CMA_BANK1);
	mfc_debug(3, "Area \"%s\" is from %08x to %08x and has size %08x", "a",
			mem_info_a.lower_bound, mem_info_a.upper_bound,
						mem_info_a.total_size);
	if (err) {
		mfc_err("Couldn't get memory information from CMA.\n");
		return -EINVAL;
	}

	if (mem_info_f.upper_bound > mem_info_a.lower_bound) {
			mfc_err("Firmware has to be "
			"allocated before  memory for buffers (bank A).\n");
		return -EINVAL;
	}
#endif
	mfc_debug(2, "Allocating memory for firmware.\n");

#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
	if (dev->num_drm_inst)
		alloc_ctx = dev->alloc_ctx_fw;
#endif

	s5p_mfc_bitproc_buf = s5p_mfc_mem_alloc_priv(alloc_ctx, firmware_size);
	if (IS_ERR(s5p_mfc_bitproc_buf)) {
		s5p_mfc_bitproc_buf = 0;
		printk(KERN_ERR "Allocating bitprocessor buffer failed\n");
		return -ENOMEM;
	}

	s5p_mfc_bitproc_phys = s5p_mfc_mem_daddr_priv(s5p_mfc_bitproc_buf);
	if (s5p_mfc_bitproc_phys & ((1 << base_align) - 1)) {
		mfc_err("The base memory is not aligned to %dBytes.\n",
				(1 << base_align));
		s5p_mfc_mem_free_priv(s5p_mfc_bitproc_buf);
		s5p_mfc_bitproc_phys = 0;
		s5p_mfc_bitproc_buf = 0;
		return -EIO;
	}

	if (!dev->num_drm_inst) {
		s5p_mfc_bitproc_virt =
				s5p_mfc_mem_vaddr_priv(s5p_mfc_bitproc_buf);
		mfc_debug(2, "Virtual address for FW: %08lx\n",
				(long unsigned int)s5p_mfc_bitproc_virt);
		if (!s5p_mfc_bitproc_virt) {
			mfc_err("Bitprocessor memory remap failed\n");
			s5p_mfc_mem_free_priv(s5p_mfc_bitproc_buf);
			s5p_mfc_bitproc_phys = 0;
			s5p_mfc_bitproc_buf = 0;
			return -EIO;
		}
	}

	dev->port_a = s5p_mfc_bitproc_phys;

#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
	if (IS_TWOPORT(dev)) {
		err = cma_info(&mem_info_b, dev->v4l2_dev.dev, MFC_CMA_BANK2);
		mfc_debug(3, "Area \"%s\" is from %08x to %08x and has size %08x", "b",
				mem_info_b.lower_bound, mem_info_b.upper_bound,
				mem_info_b.total_size);
		if (err) {
			mfc_err("Couldn't get memory information from CMA.\n");
			return -EINVAL;
		}
		dev->port_b = mem_info_b.lower_bound;
		mfc_debug(2, "Port A: %08x Port B: %08x (FW: %08x size: %08x)\n",
				dev->port_a, dev->port_b, s5p_mfc_bitproc_phys,
							firmware_size);
	} else {
		mfc_debug(2, "Port : %08x (FW: %08x size: %08x)\n",
				dev->port_a, s5p_mfc_bitproc_phys,
						firmware_size);
	}
#elif defined(CONFIG_VIDEOBUF2_ION) || defined(CONFIG_VIDEOBUF2_DMA_CMA)
	dev->port_b = s5p_mfc_bitproc_phys;

	mfc_debug(2, "Port A: %08x Port B: %08x (FW: %08x size: %08x)\n",
			dev->port_a, dev->port_b,
			s5p_mfc_bitproc_phys,
			firmware_size);
#endif
	mfc_debug_leave();

	return 0;
}
/* Allocate firmware */
int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
{
	unsigned int base_align;
	size_t firmware_size;
	void *alloc_ctx;
	struct s5p_mfc_buf_size_v6 *buf_size;

	mfc_debug_enter();

	if (!dev) {
		mfc_err("no mfc device to run\n");
		return -EINVAL;
	}

	buf_size = dev->variant->buf_size->buf;
	base_align = dev->variant->buf_align->mfc_base_align;
	firmware_size = dev->variant->buf_size->firmware_code;
	alloc_ctx = dev->alloc_ctx[MFC_FW_ALLOC_CTX];

	if (dev->fw_info.alloc)
		return 0;

	mfc_debug(2, "Allocating memory for firmware.\n");

	alloc_ctx = dev->alloc_ctx_fw;
	dev->fw_info.alloc = s5p_mfc_mem_alloc_priv(alloc_ctx,
					firmware_size + buf_size->dev_ctx);
	if (IS_ERR(dev->fw_info.alloc)) {
		dev->fw_info.alloc = 0;
		printk(KERN_ERR "Allocating bitprocessor buffer failed\n");
		return -ENOMEM;
	}

	dev->fw_info.ofs = s5p_mfc_mem_daddr_priv(dev->fw_info.alloc);
	if (dev->fw_info.ofs & ((1 << base_align) - 1)) {
		mfc_err_dev("The base memory is not aligned to %dBytes.\n",
				(1 << base_align));
		s5p_mfc_mem_free_priv(dev->fw_info.alloc);
		dev->fw_info.ofs = 0;
		dev->fw_info.alloc = 0;
		return -EIO;
	}

	dev->fw_info.virt =
		s5p_mfc_mem_vaddr_priv(dev->fw_info.alloc);
	mfc_debug(2, "Virtual address for FW: %08lx\n",
			(long unsigned int)dev->fw_info.virt);
	if (!dev->fw_info.virt) {
		mfc_err_dev("Bitprocessor memory remap failed\n");
		s5p_mfc_mem_free_priv(dev->fw_info.alloc);
		dev->fw_info.ofs = 0;
		dev->fw_info.alloc = 0;
		return -EIO;
	}

	dev->port_a = dev->fw_info.ofs;
	dev->port_b = dev->fw_info.ofs;

	mfc_debug(2, "Port A: %08zu Port B: %08zu (FW: %08lx size: %08zu)\n",
			dev->port_a, dev->port_b,
			dev->fw_info.ofs,
			firmware_size);
#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
	alloc_ctx = dev->alloc_ctx_drm_fw;

	dev->drm_fw_info.alloc = s5p_mfc_mem_alloc_priv(alloc_ctx,
					firmware_size + buf_size->dev_ctx);
	if (IS_ERR(dev->drm_fw_info.alloc)) {
		/* Release normal F/W buffer */
		s5p_mfc_mem_free_priv(dev->fw_info.alloc);
		dev->fw_info.ofs = 0;
		dev->fw_info.alloc = 0;
		printk(KERN_ERR "Allocating bitprocessor buffer failed\n");
		return -ENOMEM;
	}

	dev->drm_fw_info.ofs = s5p_mfc_mem_daddr_priv(dev->drm_fw_info.alloc);
	if (dev->drm_fw_info.ofs & ((1 << base_align) - 1)) {
		mfc_err_dev("The base memory is not aligned to %dBytes.\n",
				(1 << base_align));
		s5p_mfc_mem_free_priv(dev->drm_fw_info.alloc);
		/* Release normal F/W buffer */
		s5p_mfc_mem_free_priv(dev->fw_info.alloc);
		dev->fw_info.ofs = 0;
		dev->fw_info.alloc = 0;
		return -EIO;
	}

	mfc_info_dev("Port for DRM F/W : 0x%lx\n", dev->drm_fw_info.ofs);
#endif

	mfc_debug_leave();

	return 0;
}