// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2016 MediaTek Inc.
 * Author: Kevin Ren <kevin.ren@mediatek.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/version.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/types.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/videodev2.h>

#include <media/v4l2-mem2mem.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-vmalloc.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>

#include "mtk_pq.h"
#include "mtk_pq_dv.h"
#include "hwreg_common.h"
#include "hwreg_pq_display_scmi.h"
#include "hwreg_pq_display_ucm.h"
#include "hwreg_pq_display_mdw.h"

#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define PQ_SCMI_BUF_MAX (15)
#define PQ_SCMI_GAME_BUF_MIN       (3)
#define PQU_BIT_WIDTH_IDK          (36)
#define IOMMU_DMA_MASK             (34)
#define TS_EXTRA_DELAY             (1)

#define UCM_FOMAT_420	 (0)
#define UCM_FOMAT_420_EN (1)
#define UCM_FHD_WIDTH	 (1920)
#define UCM_FHD_HEIGHT	 (1088)
#define UCM_0_BITS	(0)
#define UCM_3_BITS	(3)
#define UCM_4_BITS	(4)
#define UCM_6_BITS	(6)
#define UCM_8_BITS	(8)
#define IS_UCM_REFINE_FORMAT(ucm_format, ucm_ch0_bit, ucm_ch1_bit, ucm_ch2_bit) \
			((ucm_format == UCM_FOMAT_420) \
			&& (ucm_ch0_bit == UCM_6_BITS) \
			&& (ucm_ch1_bit == UCM_3_BITS) \
			&& (ucm_ch2_bit == UCM_0_BITS))

enum {
	IN_FPS_15 = 0,
	IN_FPS_20,
	IN_FPS_24,
	IN_FPS_25,
	IN_FPS_30,
	IN_FPS_48,
	IN_FPS_50,
	IN_FPS_60,
	IN_FPS_96,
	IN_FPS_100,
	IN_FPS_120,
	IN_FPS_144,
	IN_FPS_192,
	IN_FPS_200,
	IN_FPS_240,
	IN_FPS_288,
	IN_FPS_MAX
};

/* frc table lite */
static const struct frc_table {
	int low;
	int high;
} table_lite[] = {
	[IN_FPS_15] = {
		.low = 14500,
		.high = 15500,
	},
	[IN_FPS_20] = {
		.low = 19500,
		.high = 20500
	},
	[IN_FPS_24] = {
		.low = 23500,
		.high = 24500
	},
	[IN_FPS_25] = {
		.low = 24500,
		.high = 25500
	},
	[IN_FPS_30] = {
		.low = 29500,
		.high = 30500
	},
	[IN_FPS_48] = {
		.low = 47500,
		.high = 48500
	},
	[IN_FPS_50] = {
		.low = 49500,
		.high = 50500
	},
	[IN_FPS_60] = {
		.low = 59500,
		.high = 60500
	},
	[IN_FPS_96] = {
		.low = 95500,
		.high = 96500
	},
	[IN_FPS_100] = {
		.low = 99500,
		.high = 100500
	},
	[IN_FPS_120] = {
		.low = 119500,
		.high = 120500
	},
	[IN_FPS_144] = {
		.low = 143500,
		.high = 144500
	},
	[IN_FPS_192] = {
		.low = 191500,
		.high = 192500
	},
	[IN_FPS_200] = {
		.low = 199500,
		.high = 200500
	},
	[IN_FPS_240] = {
		.low = 239500,
		.high = 240500
	},
	[IN_FPS_288] = {
		.low = 287500,
		.high = 288500
	},
};

static void _mtk_pq_mapping_scmi_format(hwmap_swbit *swbit, __u8 u8Idx)
{
	if (swbit) {
		if (u8Idx < SCMIFormatNum) {
			swbit->scmi_ch0_bit  = SCMI_Format_MappingTBL[u8Idx].ch0;
			swbit->scmi_ch1_bit  = SCMI_Format_MappingTBL[u8Idx].ch1;
			swbit->scmi_ch2_bit  = SCMI_Format_MappingTBL[u8Idx].ch2;
			swbit->scmi_comp_bit = SCMI_Format_MappingTBL[u8Idx].comp;
			swbit->scmi_format   = SCMI_Format_MappingTBL[u8Idx].format;
		}
	}
}

static void _mtk_pq_mapping_ucm_format(hwmap_swbit *swbit, __u8 u8Idx)
{
	if (swbit) {
		if (u8Idx < UCMFormatNum) {
			swbit->ucm_ch0_bit = UCM_Format_MappingTBL[u8Idx].ch0;
			swbit->ucm_ch1_bit = UCM_Format_MappingTBL[u8Idx].ch1;
			swbit->ucm_ch2_bit = UCM_Format_MappingTBL[u8Idx].ch2;
			swbit->ucm_format  = UCM_Format_MappingTBL[u8Idx].format;
		}
	}
}

static int _mtk_pq_cal_buf_size(struct pq_buffer *ppq_buf, enum pqu_buffer_type buf_type,
			struct meta_pq_stream_info stream, struct mtk_pq_platform_device *ppq_dev)
{
	uint16_t ctur_mode = 1, ctur2_mode = 1;
	int ret = 0;

	if (ppq_buf == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	switch (buf_type) {
	case PQU_BUF_SCMI:
	case PQU_BUF_UCM:
		ppq_buf->size_ch[PQU_BUF_CH_0] =
			(((ppq_buf->width + (ADDRESS_ALIGN - 1)) / ADDRESS_ALIGN)
			* ADDRESS_ALIGN * ppq_buf->height * ppq_buf->frame_num
			* ppq_buf->bit[PQU_BUF_CH_0]) / BIT_PER_BYTE;
		ppq_buf->size_ch[PQU_BUF_CH_1] =
			(((ppq_buf->width + (ADDRESS_ALIGN - 1)) / ADDRESS_ALIGN)
			* ADDRESS_ALIGN * ppq_buf->height * ppq_buf->frame_num
			* ppq_buf->bit[PQU_BUF_CH_1]) / BIT_PER_BYTE;
		ppq_buf->size_ch[PQU_BUF_CH_2] =
			(((ppq_buf->width + (ADDRESS_ALIGN - 1)) / ADDRESS_ALIGN)
			* ADDRESS_ALIGN * ppq_buf->height * ppq_buf->frame_num
			* ppq_buf->bit[PQU_BUF_CH_2]) / BIT_PER_BYTE;
		break;
	case PQU_BUF_ZNR:
		ppq_buf->size_ch[PQU_BUF_CH_0] =
			((((ppq_buf->width + ZNR_BLK_SIZE_CH_0 - 1) / ZNR_BLK_SIZE_CH_0
			+ (ADDRESS_ALIGN - 1)) / ADDRESS_ALIGN) * ADDRESS_ALIGN
			* ((ppq_buf->height + ZNR_BLK_SIZE_CH_0 - 1) / ZNR_BLK_SIZE_CH_0)
			* ppq_buf->frame_num * ppq_buf->bit[PQU_BUF_CH_0] + BIT_PER_BYTE - 1)
			/ BIT_PER_BYTE;
		ppq_buf->size_ch[PQU_BUF_CH_1] =
			((((ppq_buf->width + ZNR_BLK_SIZE_CH_1 - 1) / ZNR_BLK_SIZE_CH_1
			+ (ADDRESS_ALIGN - 1)) / ADDRESS_ALIGN) * ADDRESS_ALIGN
			* ((ppq_buf->height + ZNR_BLK_SIZE_CH_1 - 1) / ZNR_BLK_SIZE_CH_1)
			* ppq_buf->frame_num * ppq_buf->bit[PQU_BUF_CH_1] + BIT_PER_BYTE - 1)
			/ BIT_PER_BYTE;
		ppq_buf->size_ch[PQU_BUF_CH_2] = 0;

		ret = drv_hwreg_pq_display_znr_set_stub(stream.stub);
		ret = drv_hwreg_pq_display_znr_buffer(ppq_buf->size_ch,
				ppq_buf->frame_num, ppq_buf->bit);
		break;
	case PQU_BUF_ABF:
		mtk_display_abf_blk_mode(ppq_buf->width, ppq_buf->height, &ctur_mode, &ctur2_mode);

		ppq_buf->size_ch[PQU_BUF_CH_0] =
				(ppq_buf->width / ctur_mode) * (ppq_buf->height / ctur_mode) *
				((ppq_buf->bit[PQU_BUF_CH_0] + BIT_PER_BYTE - 1) / BIT_PER_BYTE)
				* ppq_buf->frame_num;
		ppq_buf->size_ch[PQU_BUF_CH_1] =
				(ppq_buf->width / ctur2_mode) *
				(ppq_buf->height / ctur2_mode) *
				((ppq_buf->bit[PQU_BUF_CH_1] + BIT_PER_BYTE - 1) / BIT_PER_BYTE)
				* ppq_buf->frame_num;
		ppq_buf->size_ch[PQU_BUF_CH_2] =
				((ppq_buf->width / ctur2_mode) + PQ_CTUR2_EXT_BIT) *
				((ppq_buf->height / ctur2_mode) + PQ_CTUR2_EXT_BIT) *
				((ppq_buf->bit[PQU_BUF_CH_2] + BIT_PER_BYTE - 1) / BIT_PER_BYTE)
				* ppq_buf->frame_num;
		break;
	case PQU_BUF_MCDI:
		ppq_buf->size_ch[PQU_BUF_CH_0] = ppq_dev->pqcaps.u32MCDI_ME1_Size;
		ppq_buf->size_ch[PQU_BUF_CH_1] = ppq_dev->pqcaps.u32MCDI_ME2_Size;
		ppq_buf->size_ch[PQU_BUF_CH_2] = 0;
		break;
	case PQU_BUF_DIPDI:
		ppq_buf->size_ch[PQU_BUF_CH_0] = DIPDI_BUFFER_SIZE;
		ppq_buf->size_ch[PQU_BUF_CH_1] = 0;
		ppq_buf->size_ch[PQU_BUF_CH_2] = 0;
		break;
	case PQU_BUF_VGSYNC:
		ppq_buf->size_ch[PQU_BUF_CH_0] = VGSYNC_BUFFER_SIZE;
		ppq_buf->size_ch[PQU_BUF_CH_1] = 0;
		ppq_buf->size_ch[PQU_BUF_CH_2] = 0;
		break;
	default:
		break;
	}

	return 0;
}

static int _mtk_pq_cut_reserved_memory(struct mtk_pq_platform_device *pqdev)
{
	enum pqu_buffer_type buf_idx = PQU_BUF_SCMI;
	int iommu_idx = 0, win = 0, buf_win_size = 0;
	uint32_t mmap_size = 0;
	uint64_t mmap_addr = 0;
	struct pq_buffer **ppResBuf = NULL;

	if (pqdev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	ppResBuf = pqdev->display_dev.pReserveBufTbl;

	if (ppResBuf == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	for (buf_idx = PQU_BUF_SCMI; buf_idx < PQU_BUF_MAX; buf_idx++) {
		iommu_idx = mtk_pq_buf_get_iommu_idx(pqdev, buf_idx);

		if (iommu_idx == 0) {
			switch (buf_idx) {
			case PQU_BUF_ZNR:
				mtk_pq_get_dedicate_memory_info(pqdev->dev, MMAP_ZNR_INDEX,
				&mmap_addr, &mmap_size);

				 mmap_addr -= pqdev->miu0_base;
				break;
			case PQU_BUF_ABF:
				mtk_pq_get_dedicate_memory_info(pqdev->dev, MMAP_ABF_INDEX,
				&mmap_addr, &mmap_size);

				 mmap_addr -= pqdev->miu0_base;
				break;
			case PQU_BUF_MCDI:
				mtk_pq_get_dedicate_memory_info(pqdev->dev, MMAP_MCDI_INDEX,
				&mmap_addr, &mmap_size);

				mmap_addr -= pqdev->miu0_base;
				break;
			case PQU_BUF_VGSYNC:
				if (pqdev->pqcaps.u8Perfect_vsync_support == true) {
					mtk_pq_get_dedicate_memory_info(pqdev->dev,
					MMAP_VGSYNC_SHM_INDEX,
					&mmap_addr, &mmap_size);

					mmap_addr -= pqdev->miu0_base;
				}
				break;
			default:
				break;
			}

			buf_win_size = mmap_size / pqdev->xc_win_num;
			if (buf_idx == PQU_BUF_VGSYNC) {
				if (pqdev->pqcaps.u8Perfect_vsync_support) {
					for (win = 0; win < pqdev->xc_win_num; win++) {
						ppResBuf[win][buf_idx].size = mmap_size;
						ppResBuf[win][buf_idx].addr = mmap_addr;
						ppResBuf[win][buf_idx].valid = true;
						ppResBuf[win][buf_idx].used_dev = -1;
						STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
							"VGSYNC ppResBuf[%d][%d].size : %u\n",
							win, buf_idx, ppResBuf[win][buf_idx].size);
					}
				}
			} else {
				for (win = 0; win < pqdev->xc_win_num; win++) {
					if (ppResBuf[win] == NULL) {
						STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
						"revserve table[%d] is not initialized\n", win);
						return -EPERM;
					}

					ppResBuf[win][buf_idx].size = buf_win_size;
					ppResBuf[win][buf_idx].addr =
						mmap_addr + (win * (uint64_t)buf_win_size);
					ppResBuf[win][buf_idx].valid = true;
					ppResBuf[win][buf_idx].used_dev = -1;
					STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
						"ppResBuf[%d][%d].size : %u\n",
						win, buf_idx, ppResBuf[win][buf_idx].size);

					STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
						"ppResBuf[%d][%d].addr : 0x%llx\n",
						win, buf_idx, ppResBuf[win][buf_idx].addr);
				}
			}
		}
	}

	return 0;
}

static int _mtk_pq_get_reserved_memory(struct mtk_pq_device *pq_dev,
		enum pqu_buffer_type buf_type, unsigned long long *iova, uint32_t size,
		unsigned long long *va, unsigned long long *pa)
{
	int ret = 0, win = 0;
	struct mtk_pq_platform_device *pqdev = NULL;
	struct pq_buffer **ppResBuf = NULL;

	if (iova == NULL || va == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	if (pq_dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	win = pq_dev->dev_indx;
	pqdev = dev_get_drvdata(pq_dev->dev);

	if (pqdev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	ppResBuf = pqdev->display_dev.pReserveBufTbl;

	if (ppResBuf == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}
	//only one xc buffer
	if (pqdev->pqcaps.u32Support_TS == 0)
		win = 0;

	STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
		"win:%d, dev_indx:%d\n", win, pq_dev->dev_indx);

	if (ppResBuf[win] == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	if (ppResBuf[win][buf_type].size < size) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
		"mmap buf isn't enough : %u < %u\n",
		ppResBuf[win][buf_type].size, size);
		return -EPERM;
	}

	if (ppResBuf[win][buf_type].valid == false) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
		"mmap buf isn't in mmap : %d\n", buf_type);
		return -EPERM;
	}

	if (ppResBuf[win][buf_type].used_dev != -1) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
		"mmap buf:%d, used_dev:%d\n",
			buf_type, ppResBuf[win][buf_type].used_dev);
		return -EPERM;
	}

	*iova = ppResBuf[win][buf_type].addr;
	*va = ppResBuf[win][buf_type].va;
	*pa = ppResBuf[win][buf_type].pa;
	ppResBuf[win][buf_type].used_dev = pq_dev->dev_indx;
	return ret;
}

static int _mtk_pq_put_reserved_memory(struct mtk_pq_device *pq_dev,
		enum pqu_buffer_type buf_type)
{
	int ret = 0, win = 0;
	struct mtk_pq_platform_device *pqdev = NULL;
	struct pq_buffer **ppResBuf = NULL;

	if (pq_dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	win = pq_dev->dev_indx;
	pqdev = dev_get_drvdata(pq_dev->dev);

	if (pqdev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	ppResBuf = pqdev->display_dev.pReserveBufTbl;

	if (ppResBuf == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	//only one xc buffer
	if (pqdev->pqcaps.u32Support_TS == 0)
		win = 0;

	STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
		"win:%d, dev_indx:%d\n", win, pq_dev->dev_indx);

	if (ppResBuf[win] == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	if (ppResBuf[win][buf_type].valid == false) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
		"mmap buf isn't in mmap : %d\n", buf_type);
		return -EPERM;
	}

	if (ppResBuf[win][buf_type].used_dev != pq_dev->dev_indx) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
		"no need release by dev_indx:%d, mmap buf:%d, used_dev:%d\n",
			pq_dev->dev_indx, buf_type, ppResBuf[win][buf_type].used_dev);
		return ret;
	}

	ppResBuf[win][buf_type].used_dev = -1;
	return ret;
}

static int _mtk_pq_get_dipdi_frame_num(void)
{
	struct device_node *np;
	int ret = 0;
	uint32_t useDINR = 0;

	np = of_find_compatible_node(NULL, NULL, "mediatek,tvpqu");
	if (np != NULL) {
		ret = of_property_read_u32(np, "DipUseDINR", &useDINR);
		if (ret != 0) {
			STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER, "Read DTS table failed, name = %s\n",
				"DipUseDINR");
		}
	}
	if (useDINR == 1)
		ret = DIPDI_FRAME;
	else
		ret = 0;
	return ret;
}

static int _mtk_pq_get_hwmap_info(struct pq_buffer *ppq_buf, enum pqu_buffer_type buf_type,
		hwmap_swbit *swbit, struct meta_pq_stream_info *stream_info,
		struct mtk_pq_caps *pqcaps)
{
	struct mtk_pq_dv_status dv_status;

	if (ppq_buf == NULL || swbit == NULL || stream_info == NULL || pqcaps == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	memset(&dv_status, 0, sizeof(struct mtk_pq_dv_status));

	switch (buf_type) {
	case PQU_BUF_SCMI:
		mtk_pq_dv_get_status(&dv_status);
		if (dv_status.idk_enable == TRUE) {
			STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "PQU 36 bit mode due to IDK dump\n");
			ppq_buf->bit[PQU_BUF_CH_0] = PQU_BIT_WIDTH_IDK;
			ppq_buf->bit[PQU_BUF_CH_1] = 0;
			ppq_buf->bit[PQU_BUF_CH_2] = 0;
		} else {
			ppq_buf->bit[PQU_BUF_CH_0] = swbit->scmi_ch0_bit;
			ppq_buf->bit[PQU_BUF_CH_1] = swbit->scmi_ch1_bit;
			ppq_buf->bit[PQU_BUF_CH_2] = swbit->scmi_ch2_bit;
		}
#ifndef NOT_SUPPORT_A2DP
		if (stream_info->pq_mode == meta_pq_mode_legacy
			&& stream_info->pq_source != meta_pq_source_b2r
			&& pqcaps->u8A2DP_support == true)
			if (u8IsBypassA2DP == false)
				ppq_buf->frame_num = PQ_SCMI_BUF_MAX;
			else
				ppq_buf->frame_num = swbit->scmi_frame + u8A2DP_Dbframe;
		else
			ppq_buf->frame_num = swbit->scmi_frame;
#else
		ppq_buf->frame_num = swbit->scmi_frame;
#endif
		ppq_buf->frame_diff = swbit->scmi_delay; // scmi frame diff is same as frame delay
		ppq_buf->frame_delay = swbit->scmi_delay;
		ppq_buf->frame_format = swbit->scmi_format;

		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
			"[SCMI] %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u\n",
			"bit[0]", ppq_buf->bit[PQU_BUF_CH_0],
			"bit[1]", ppq_buf->bit[PQU_BUF_CH_1],
			"bit[2]", ppq_buf->bit[PQU_BUF_CH_2],
			"frame_num", ppq_buf->frame_num,
			"frame_diff", ppq_buf->frame_diff,
			"frame_delay", ppq_buf->frame_delay);
		break;
	case PQU_BUF_ZNR:
		ppq_buf->bit[PQU_BUF_CH_0] = swbit->znr_ch0_bit;
		ppq_buf->bit[PQU_BUF_CH_1] = swbit->znr_ch1_bit;
		ppq_buf->bit[PQU_BUF_CH_2] = 0;
		ppq_buf->frame_num = swbit->znr_frame;
		ppq_buf->frame_diff = 0;
		ppq_buf->frame_delay = 0;

		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
			"[ZNR] %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u\n",
			"bit[0]", ppq_buf->bit[PQU_BUF_CH_0],
			"bit[1]", ppq_buf->bit[PQU_BUF_CH_1],
			"bit[2]", ppq_buf->bit[PQU_BUF_CH_2],
			"frame_num", ppq_buf->frame_num,
			"frame_diff", ppq_buf->frame_diff,
			"frame_delay", ppq_buf->frame_delay);
		break;
	case PQU_BUF_UCM:
		ppq_buf->bit[PQU_BUF_CH_0] = swbit->ucm_ch0_bit;
		ppq_buf->bit[PQU_BUF_CH_1] = swbit->ucm_ch1_bit;
		ppq_buf->bit[PQU_BUF_CH_2] = swbit->ucm_ch2_bit;
		ppq_buf->frame_num = swbit->ucm_frame;
		ppq_buf->frame_diff = swbit->ucm_delay; // ucm frame diff is same as frame delay
		ppq_buf->frame_delay = swbit->ucm_delay;
		ppq_buf->frame_format = swbit->ucm_format;

		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
			"[UCM] %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u\n",
			"bit[0]", ppq_buf->bit[PQU_BUF_CH_0],
			"bit[1]", ppq_buf->bit[PQU_BUF_CH_1],
			"bit[2]", ppq_buf->bit[PQU_BUF_CH_2],
			"frame_num", ppq_buf->frame_num,
			"frame_diff", ppq_buf->frame_diff,
			"frame_delay", ppq_buf->frame_delay);
		break;
	case PQU_BUF_ABF:
		ppq_buf->bit[PQU_BUF_CH_0] = swbit->abf_ch0_bit;
		ppq_buf->bit[PQU_BUF_CH_1] = swbit->abf_ch1_bit;
		ppq_buf->bit[PQU_BUF_CH_2] = swbit->abf_ch2_bit;
		ppq_buf->frame_num = swbit->abf_frame;
		ppq_buf->frame_diff = 0;
		ppq_buf->frame_delay = 0;

		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
			"[ABF] %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u\n",
			"bit[0]", ppq_buf->bit[PQU_BUF_CH_0],
			"bit[1]", ppq_buf->bit[PQU_BUF_CH_1],
			"bit[2]", ppq_buf->bit[PQU_BUF_CH_2],
			"frame_num", ppq_buf->frame_num,
			"frame_diff", ppq_buf->frame_diff,
			"frame_delay", ppq_buf->frame_delay);
		break;
	case PQU_BUF_MCDI:
		ppq_buf->bit[PQU_BUF_CH_0] = 0;
		ppq_buf->bit[PQU_BUF_CH_1] = 0;
		ppq_buf->bit[PQU_BUF_CH_2] = 0;
		ppq_buf->frame_num = swbit->mcdi_frame;
		ppq_buf->frame_diff = 0;
		ppq_buf->frame_delay = 0;

		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
			"[MCDI] %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u\n",
			"bit[0]", ppq_buf->bit[PQU_BUF_CH_0],
			"bit[1]", ppq_buf->bit[PQU_BUF_CH_1],
			"bit[2]", ppq_buf->bit[PQU_BUF_CH_2],
			"frame_num", ppq_buf->frame_num,
			"frame_diff", ppq_buf->frame_diff,
			"frame_delay", ppq_buf->frame_delay);
		break;
	case PQU_BUF_DIPDI:
		ppq_buf->bit[PQU_BUF_CH_0] = 0;
		ppq_buf->bit[PQU_BUF_CH_1] = 0;
		ppq_buf->bit[PQU_BUF_CH_2] = 0;
		ppq_buf->frame_num = _mtk_pq_get_dipdi_frame_num();
		ppq_buf->frame_diff = 0;

		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
			"[DIPDI] %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u\n",
			"bit[0]", ppq_buf->bit[PQU_BUF_CH_0],
			"bit[1]", ppq_buf->bit[PQU_BUF_CH_1],
			"bit[2]", ppq_buf->bit[PQU_BUF_CH_2],
			"frame_num", ppq_buf->frame_num,
			"frame_diff", ppq_buf->frame_diff,
			"frame_delay", ppq_buf->frame_delay);
		break;
	case PQU_BUF_VGSYNC:
		ppq_buf->bit[PQU_BUF_CH_0] = 0;
		ppq_buf->bit[PQU_BUF_CH_1] = 0;
		ppq_buf->bit[PQU_BUF_CH_2] = 0;
		ppq_buf->frame_num = 1;
		ppq_buf->frame_diff = 0;

		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
			"[VGSYNC] %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u\n",
			"bit[0]", ppq_buf->bit[PQU_BUF_CH_0],
			"bit[1]", ppq_buf->bit[PQU_BUF_CH_1],
			"bit[2]", ppq_buf->bit[PQU_BUF_CH_2],
			"frame_num", ppq_buf->frame_num,
			"frame_diff", ppq_buf->frame_diff,
			"frame_delay", ppq_buf->frame_delay);
		break;
	default:
		break;
	}

	return 0;
}

static int _mtk_pq_allocate_buf(struct mtk_pq_device *pq_dev, enum pqu_buffer_type buf_type,
			struct pq_buffer *ppq_buf, struct meta_pq_stream_info stream_pq)
{
	struct mtk_pq_platform_device *pqdev = NULL;
	unsigned int buf_iommu_idx = 0;
	unsigned long iommu_attrs = 0;
	unsigned long long iova = 0, va = 0, pa = 0;
	int ret = 0;
	uint32_t size = 0;
	struct device *dev = NULL;

	if (pq_dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	if (ppq_buf == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	dev = pq_dev->dev;
	pqdev = dev_get_drvdata(pq_dev->dev);
	buf_iommu_idx = mtk_pq_buf_get_iommu_idx(pqdev, buf_type);

	if (dma_get_mask(dev) < DMA_BIT_MASK(34)) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER, "IOMMU isn't registered\n");
		return -1;
	}

#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0)
	if (!dma_supported(dev, 0)) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
			"IOMMU is not supported\n");
		return -1;
	}
#endif

	if (buf_type == PQU_BUF_VGSYNC) {
		if (pqdev->pqcaps.u8Perfect_vsync_support) {
			ret = _mtk_pq_cal_buf_size(ppq_buf, buf_type, stream_pq, pqdev);
			if (ret) {
				STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
					"_mtk_pq_cal_buf_size Failed, ret = %d\n", ret);
				return ret;
			}
		}
	} else {
		ret = _mtk_pq_cal_buf_size(ppq_buf, buf_type, stream_pq, pqdev);
		if (ret) {
			STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
				"_mtk_pq_cal_buf_size Failed, ret = %d\n", ret);
			return ret;
		}
	}
	STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
		"%s%x, %s%u, %s%u, %s%u\n",
		"buf_type : ", buf_type,
		"size_ch[PQU_BUF_CH_0] : ", ppq_buf->size_ch[PQU_BUF_CH_0],
		"size_ch[PQU_BUF_CH_1] : ", ppq_buf->size_ch[PQU_BUF_CH_1],
		"size_ch[PQU_BUF_CH_2] : ", ppq_buf->size_ch[PQU_BUF_CH_2]);

	size = ppq_buf->size_ch[PQU_BUF_CH_0] + ppq_buf->size_ch[PQU_BUF_CH_1]
							+ ppq_buf->size_ch[PQU_BUF_CH_2];

	if (size > 0) {
		if (buf_iommu_idx != 0) {
			// According to iommu requires the size to align 4K.
			size = PAGE_ALIGN(size);

			// set buf tag
			iommu_attrs |= buf_iommu_idx;

			// if mapping uncache
			iommu_attrs |= DMA_ATTR_WRITE_COMBINE | DMA_ATTR_NO_KERNEL_MAPPING;

			if (size == 0) {
				STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
					"PQ buffer alloc size = 0\n");
				return -1;
			}

			STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
				"buf_type : %d, buf_iommu_idx : %x, size = %u\n",
				buf_type, buf_iommu_idx, size);

			va = (unsigned long long)dma_alloc_attrs(dev,
					size,
					&iova,
					GFP_KERNEL,
					iommu_attrs);
			ret = dma_mapping_error(dev, iova);
			if (ret) {
				STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
					"dma_alloc_attrs fail\n");
				return ret;
			}
		} else {
			ret = _mtk_pq_get_reserved_memory(pq_dev, buf_type, &iova, size, &va, &pa);
			if (ret) {
				STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
					"_mtk_pq_get_reserved_memory Failed, ret = %d\n", ret);
				return ret;
			}
		}

		ppq_buf->valid = true;

		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
			"buf = {va : %llx, addr : %llx, size = %u}\n", va, iova, size);
	}

	ppq_buf->va = va;
	ppq_buf->pa = pa;
	ppq_buf->addr = iova;
	ppq_buf->size = size;

	return 0;
}

static int _mtk_pq_release_buf(struct mtk_pq_device *pq_dev,
	enum pqu_buffer_type buf_type, struct pq_buffer *ppq_buf)
{
	struct device *dev = NULL;
	struct mtk_pq_platform_device *pqdev = NULL;
	unsigned int buf_iommu_idx = 0;

	if (pq_dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	if (ppq_buf == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	dev = pq_dev->dev;
	pqdev = dev_get_drvdata(pq_dev->dev);
	buf_iommu_idx = mtk_pq_buf_get_iommu_idx(pqdev, buf_type);

	/* clear valid flag first to avoid racing condition */
	ppq_buf->valid = false;

	STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
		"buf_type : %d, buf_iommu_idx  %u, size : %u\n",
		buf_type, buf_iommu_idx, ppq_buf->size);

	if (buf_iommu_idx != 0) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
			"va : %llx, addr : %llx\n", ppq_buf->va, ppq_buf->addr);

		dma_free_attrs(dev, ppq_buf->size, (void *)ppq_buf->va,
			ppq_buf->addr, buf_iommu_idx);
	} else {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
			"buf_type:%d, release used reserved memory\n", buf_type);
		_mtk_pq_put_reserved_memory(pq_dev, buf_type);
	}

	return 0;
}

static int _mtk_pq_allocate_frc_pq_buf(struct mtk_frc_device *frc_dev,
	struct pq_buffer_frc_pq *ppq_buf)
{
	struct mtk_pq_platform_device *pqdev = NULL;
	unsigned int frc_pq_buf_iommu_idx = 0;
	unsigned long iommu_attrs = 0;
	unsigned long long iova = 0, va = 0;
	struct device *dev = NULL;
	uint32_t size = 0x0;
	int ret = 0;

	if (frc_dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	if (ppq_buf == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	dev = frc_dev->dev;

	if (dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	pqdev = dev_get_drvdata(frc_dev->dev);

	frc_pq_buf_iommu_idx = (pqdev->display_dev.frc_dev.frc_iommu_idx_frc_pq <<
		pqdev->display_dev.frc_dev.frc_buf_iommu_offset);
	size = (pqdev->display_dev.frc_dev.frc_iommu_frc_pq_size);

	if (dma_get_mask(dev) < DMA_BIT_MASK(IOMMU_DMA_MASK)) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER, "IOMMU isn't registered\n");
		return -1;
	}

#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0)
	if (!dma_supported(dev, 0)) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
			"IOMMU is not supported\n");
		return -1;
	}
#endif

	if (size > 0) {
		if (frc_pq_buf_iommu_idx != 0) {
			// According to iommu requires the size to align 4K.
			size = PAGE_ALIGN(size);

			// set buf tag
			iommu_attrs |= frc_pq_buf_iommu_idx;

			// if mapping uncache
			iommu_attrs |= DMA_ATTR_WRITE_COMBINE | DMA_ATTR_NO_KERNEL_MAPPING;

			if (size == 0) {
				STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
					"FRC PQ buffer alloc size = 0\n");
				return -1;
			}

			STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
				" frc_pq_buf_iommu_idx : %x, size = %u\n",
				frc_pq_buf_iommu_idx, size);

			va = (unsigned long long)dma_alloc_attrs(dev,
					size,
					&iova,
					GFP_KERNEL,
					iommu_attrs);

			ret = dma_mapping_error(dev, iova);
			if (ret) {
				STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
					"dma_alloc_attrs fail\n");
				return ret;
			}
		}

		ppq_buf->valid = true;
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
			"buf = {va : %llx, addr : %llx, size = %u}\n", va, iova, size);
		pqdev->display_dev.frc_dev.frc_iommu_frc_pq_adr = (uint64_t)iova;
	}

	ppq_buf->va = va;
	ppq_buf->addr = iova;
	ppq_buf->size = size;

	return 0;
}

static int _mtk_pq_release_frc_pq_buf(struct mtk_frc_device *frc_dev,
		struct pq_buffer_frc_pq *ppq_buf)
{
	struct device *dev = NULL;
	struct mtk_pq_platform_device *pqdev = NULL;
	unsigned int frc_pq_buf_iommu_idx = 0;

	if (frc_dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	if (ppq_buf == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	dev = frc_dev->dev;

	if (dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	pqdev = dev_get_drvdata(frc_dev->dev);
	frc_pq_buf_iommu_idx = (pqdev->display_dev.frc_dev.frc_iommu_idx_frc_pq	<<
		pqdev->display_dev.frc_dev.frc_buf_iommu_offset);

	ppq_buf->valid = false;

	STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
		"frc_pq_buf_iommu_idx  %u, size : %u\n",
		 frc_pq_buf_iommu_idx, ppq_buf->size);

	if (frc_pq_buf_iommu_idx != 0) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
			"va : %llx, addr : %llx\n", ppq_buf->va, ppq_buf->addr);

		dma_free_attrs(dev, ppq_buf->size, (void *)ppq_buf->va,
			ppq_buf->addr, frc_pq_buf_iommu_idx);
	}

	return 0;
}

static int _mtk_pq_buffer_debug_swbit(struct mtk_pq_device *pq_dev,
	hwmap_swbit *swbit)
{
	/*fill debug info*/
	pq_dev->pq_debug.swbit.scmi_ch0_bit = swbit->scmi_ch0_bit;
	pq_dev->pq_debug.swbit.scmi_ch1_bit = swbit->scmi_ch1_bit;
	pq_dev->pq_debug.swbit.scmi_ch2_bit = swbit->scmi_ch2_bit;
	pq_dev->pq_debug.swbit.scmi_comp_bit = swbit->scmi_comp_bit;
	pq_dev->pq_debug.swbit.scmi_format = swbit->scmi_format;
	pq_dev->pq_debug.swbit.scmi_frame = swbit->scmi_frame;
	pq_dev->pq_debug.swbit.scmi_delay = swbit->scmi_delay;

	pq_dev->pq_debug.swbit.ucm_ch0_bit = swbit->ucm_ch0_bit;
	pq_dev->pq_debug.swbit.ucm_ch1_bit = swbit->ucm_ch1_bit;
	pq_dev->pq_debug.swbit.ucm_ch2_bit = swbit->ucm_ch2_bit;
	pq_dev->pq_debug.swbit.ucm_format = swbit->ucm_format;
	pq_dev->pq_debug.swbit.ucm_frame = swbit->ucm_frame;
	pq_dev->pq_debug.swbit.ucm_delay = swbit->ucm_delay;
	pq_dev->pq_debug.swbit.ucm_diff = swbit->ucm_diff;

	pq_dev->pq_debug.swbit.znr_aul_en = swbit->znr_aul_en;
	pq_dev->pq_debug.swbit.znr_frame = swbit->znr_frame;
	pq_dev->pq_debug.swbit.znr_ch0_bit = swbit->znr_ch0_bit;
	pq_dev->pq_debug.swbit.znr_ch1_bit = swbit->znr_ch1_bit;

	pq_dev->pq_debug.swbit.spf_aul_en = swbit->spf_aul_en;

	pq_dev->pq_debug.swbit.abf_frame = swbit->abf_frame;
	pq_dev->pq_debug.swbit.abf_ch0_bit = swbit->abf_ch0_bit;
	pq_dev->pq_debug.swbit.abf_ch1_bit = swbit->abf_ch1_bit;
	pq_dev->pq_debug.swbit.abf_ch2_bit = swbit->abf_ch2_bit;

	pq_dev->pq_debug.swbit.mcdi_frame = swbit->mcdi_frame;

	pq_dev->pq_debug.swbit.dnr_func_on = swbit->dnr_func_on;
	pq_dev->pq_debug.swbit.dnr_motion_on = swbit->dnr_motion_on;
	pq_dev->pq_debug.swbit.znr_func_on = swbit->znr_func_on;
	pq_dev->pq_debug.swbit.pnr_motion_on = swbit->pnr_motion_on;
	pq_dev->pq_debug.swbit.di_func_on = swbit->di_func_on;
	pq_dev->pq_debug.swbit.di_mode = swbit->di_mode;
	pq_dev->pq_debug.swbit.spf_func_on = swbit->spf_func_on;
	pq_dev->pq_debug.swbit.abf_func_on = swbit->abf_func_on;

	return 0;
}

int mtk_pq_get_dedicate_memory_info(struct device *dev, int pool_index,
	__u64 *pbus_address, __u32 *pbus_size)
{
	struct of_mmap_info_data of_mmap_info;

	if (dev == NULL || pbus_address == NULL || pbus_size == NULL) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "NULL pointer\n");
		return -EINVAL;
	}

	memset(&of_mmap_info, 0, sizeof(struct of_mmap_info_data));
	of_mtk_get_reserved_memory_info_by_idx(dev->of_node, pool_index, &of_mmap_info);
	*pbus_address = of_mmap_info.start_bus_address;
	*pbus_size = of_mmap_info.buffer_size;

	if (*pbus_address == 0 || *pbus_size == 0) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "Invalid bus address\n");
		return -EINVAL;
	}
	return 0;
}

int mtk_pq_get_dedicate_memory_cacheable(int pool_index, bool *pcacheable)
{
	if (pcacheable == NULL) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "NULL pointer\n");
		return -EINVAL;
	}

	switch (pool_index) {
	case MMAP_MCDI_INDEX:
	case MMAP_ABF_INDEX:
	case MMAP_ZNR_INDEX:
	case MMAP_PQMAP_INDEX:
	case MMAP_CONTROLMAP_INDEX:
	case MMAP_DV_PYR_INDEX:
	case MMAP_DV_CONFIG_INDEX:
	case MMAP_STREAM_METADATA_INDEX:
	case MMAP_METADATA_INDEX:
	case MMAP_CFD_BUF_INDEX:
	case MMAP_VGSYNC_SHM_INDEX:
		*pcacheable = true;
		break;
	case MMAP_PQPARAM_INDEX:
	case MMAP_HISTOGRAM_INDEX:
		*pcacheable = false;
		break;
	default:
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "Invalid pool_index %d\n", pool_index);
		return -EINVAL;
	}

	return 0;
}

int mtk_pq_buf_get_iommu_idx(struct mtk_pq_platform_device *pqdev, enum pqu_buffer_type buf_type)
{
	int idx = 0;

	if (pqdev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	switch (buf_type) {
	case PQU_BUF_SCMI:
		idx = pqdev->display_dev.pq_iommu_idx_scmi;
		break;
	case PQU_BUF_UCM:
		idx = pqdev->display_dev.pq_iommu_idx_ucm;
		break;
	case PQU_BUF_DIPDI:
		idx = pqdev->display_dev.pq_iommu_idx_dip;
		break;
	default:
		/* buffer type does not support iommu */
		break;
	}

	return (idx << pqdev->display_dev.buf_iommu_offset);
}

int mtk_pq_buffer_reserve_buf_init(struct mtk_pq_platform_device *pqdev)
{
	uint8_t idx = 0;
	struct pq_buffer **ppResBuf = NULL;

	if (pqdev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	if (pqdev->display_dev.pReserveBufTbl != NULL)
		mtk_pq_buffer_reserve_buf_exit(pqdev);

	pqdev->display_dev.pReserveBufTbl
		= (struct pq_buffer **)malloc(pqdev->xc_win_num * sizeof(struct pq_buffer *));

	ppResBuf = pqdev->display_dev.pReserveBufTbl;

	if (ppResBuf != NULL) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
			"pq reserve buffer allocate succeesful : %llx\n", (uint64_t)ppResBuf);

		memset(ppResBuf, 0, pqdev->xc_win_num * sizeof(struct pq_buffer *));

		for (idx = 0; idx < pqdev->xc_win_num; idx++) {
			ppResBuf[idx] =
				(struct pq_buffer *)malloc(PQU_BUF_MAX * sizeof(struct pq_buffer));

			STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
				"pq[%d] reserve buffer allocate succeesful : %llx\n",
				idx, (uint64_t)ppResBuf[idx]);

			if (ppResBuf[idx] == NULL) {
				mtk_pq_buffer_reserve_buf_exit(pqdev);

				STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
					"pq[%d] reserve buffer allocate failed!\n", idx);
				return -EPERM;
			}
		}

		_mtk_pq_cut_reserved_memory(pqdev);

	} else {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
			"pq reserve buffer allocate failed!\n");
		return -EPERM;
	}

	return 0;
}

int mtk_pq_buffer_reserve_buf_exit(struct mtk_pq_platform_device *pqdev)
{
	uint8_t idx = 0;
	struct pq_buffer **ppResBuf = NULL;

	if (pqdev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	ppResBuf = pqdev->display_dev.pReserveBufTbl;

	if (ppResBuf != NULL) {
		for (idx = 0; idx < pqdev->xc_win_num; idx++) {
			if (ppResBuf[idx] != NULL) {
				free(ppResBuf[idx]);
				ppResBuf[idx] = NULL;
			}
		}

		free(ppResBuf);
		ppResBuf = NULL;
	}

	return 0;
}

int mtk_pq_buffer_buf_init(struct mtk_pq_device *pq_dev)
{
	if (pq_dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	memset(pq_dev->display_info.BufferTable, 0,
			PQU_BUF_MAX*sizeof(struct pq_buffer));

	return 0;
}

int mtk_pq_buffer_buf_exit(struct mtk_pq_device *pq_dev)
{
	enum pqu_buffer_type idx = PQU_BUF_SCMI;
	struct pq_buffer *ppq_buf = NULL;

	if (pq_dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	for (idx = PQU_BUF_SCMI; idx < PQU_BUF_MAX; idx++) {
		ppq_buf = &(pq_dev->display_info.BufferTable[idx]);

		if (ppq_buf->valid == true)
			_mtk_pq_release_buf(pq_dev, idx, ppq_buf);
	}

	memset(&(pq_dev->display_info.BufferTable), 0, PQU_BUF_MAX*sizeof(struct pq_buffer));

	return 0;
}

static inline bool _check_is_framelock(uint32_t input_fps)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(table_lite); ++i) {
		if (input_fps >= table_lite[i].low &&
			input_fps <= table_lite[i].high)
			return true;
	}

	return false;
}

static inline bool _check_is_in_out_1on1(uint32_t input_fps, uint32_t output_fps)
{
#define FPS_60	61000
#define FPS_144	145000
	int st, end;

	/* check 1:1
	 * for 4k2k60, the possible 1:1 input fps case is 48~60
	 * for 4k2k120/144, the possible 1:1 input fps case is 96~144
	 * for 4k1k240/288, the possible 1:1 input fps case is 192~288
	 */
	if (output_fps <= FPS_60) {
		st = IN_FPS_48;
		end = IN_FPS_60;
	} else if (output_fps <= FPS_144) {
		st = IN_FPS_96;
		end = IN_FPS_144;
	} else {
		st = IN_FPS_192;
		end = IN_FPS_288;
	}

	for (; st <= end; ++st) {
		if (input_fps >= table_lite[st].low && input_fps <= table_lite[st].high)
			return true;
	}

	return false;
}

static inline bool _is_game_with_interlace(struct meta_pq_stream_info *stream_pq)
{
	return (stream_pq->interlace && stream_pq->pq_scene == meta_pq_scene_game);
}

static inline bool _is_hdmi_with_game_crop(struct meta_pq_stream_info *stream_pq)
{
	return (stream_pq->pq_source == meta_pq_source_ipdma &&
			(stream_pq->pq_scene == meta_pq_scene_game_crop ||
			stream_pq->pq_scene == meta_pq_scene_game_crop_with_memc));
}

static inline bool _is_hdmi_with_nonfull_disp(struct meta_pq_stream_info *stream_pq)
{
	return (stream_pq->pq_source == meta_pq_source_ipdma &&
			stream_pq->bIsFullDisp == false);
}

/*
 * following cases the scmi opm rwdiff
 * should be patched by SW
 */
static bool _hwmap_need_fixup(struct mtk_pq_device *pq_dev)
{
	uint32_t pqout_fps = 0;
	bool scene_game = false;
	struct meta_pq_stream_info *stream_pq = &(pq_dev->stream_meta);

	scene_game = (stream_pq->pq_scene == meta_pq_scene_game ||
		stream_pq->pq_scene == meta_pq_scene_game_with_pc ||
		stream_pq->pq_scene == meta_pq_scene_game_with_memc);

	/*
	 * FRC FB case
	 * 1. framelock free run
	 * 2. in:out is not 1:1
	 * 3. in:out is 1:1 and non-game mode
	 * 4. i-mode and game mode
	 */
	if (pq_dev->common_info.output_mode != MTK_PQ_OUTPUT_MODE_BYPASS) {
		/* pq trig select input, so that pq out = pq in */
		pqout_fps = stream_pq->input_fps;

		if (!_check_is_framelock(stream_pq->input_fps))
			return true;

		if (!_check_is_in_out_1on1(stream_pq->input_fps, pqout_fps))
			return true;

		if (_check_is_in_out_1on1(stream_pq->input_fps, pqout_fps) &&
				!scene_game)
			return true;

		if (_is_game_with_interlace(stream_pq))
			return true;
	} else {
		/*
		 * FRC FBL case
		 * 1. in:out is not 1:1
		 */

		/* pq trig select TGEN, so that pq out = render out */
		pqout_fps = stream_pq->output_fps;
		if (!_check_is_in_out_1on1(stream_pq->input_fps, pqout_fps))
			return true;
	}

	/*
	 * common case
	 * 1. hdmi game crop
	 * 2. hdmi + non fullscreen
	 */
	if (_is_hdmi_with_game_crop(stream_pq))
		return true;
	if (_is_hdmi_with_nonfull_disp(stream_pq))
		return true;

	/*
	 * mirror case
	 * r/w diff at least 1.
	 */
	if (pq_dev->common_info.v_flip)
		return true;

	return false;
}

static int mtk_pq_buffer_hwmap_fixup(struct mtk_pq_device *pq_dev, hwmap_swbit *swbit)
{
	struct meta_pq_stream_info *stream_pq;
	uint32_t buffer_mode;

	if (!pq_dev || !swbit) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	stream_pq = &(pq_dev->stream_meta);
	buffer_mode = drv_hwreg_common_config_get_buffer_mode((uint32_t)stream_pq->scenario_idx);
	pq_dev->scmi_opm_diff_fixup = false;

	/* it should be someting wrong if no in/out fps */
	if (stream_pq->input_fps == 0 || stream_pq->output_fps == 0)
		return -EINVAL;

	/* do nothing if froce P */
	if (stream_pq->pq_scene == meta_pq_scene_force_p || stream_pq->bForceP)
		return 0;

	/*
	 * pre condition: scmi should be FB && rwdiff = 0
	 * assume scmi_delay == scmi_frame
	 */
	if (buffer_mode != hwmap_buffer_mode_fb || swbit->scmi_delay != 0)
		return 0;

	STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
		"scenario_idx:%d, buf:%d, diff:%d, src:%d, in-fps:%d, out-fps:%d, interlace:%d, scene:%d, screen:%s, framelock:%d, frc:%s\n",
		(int)stream_pq->scenario_idx,
		(int)buffer_mode,
		(int)swbit->scmi_delay,
		(int)stream_pq->pq_source,
		stream_pq->input_fps,
		stream_pq->output_fps,
		(int)stream_pq->interlace,
		(int)stream_pq->pq_scene,
		stream_pq->bIsFullDisp ? "Full" : "nonFull",
		(int)_check_is_framelock(stream_pq->input_fps),
		pq_dev->common_info.output_mode == MTK_PQ_OUTPUT_MODE_BYPASS ? "FBL" : "FB");

	// check..
	if (_hwmap_need_fixup(pq_dev)) {
		pq_dev->scmi_opm_diff_fixup = true;	// to notify pqu
		swbit->scmi_delay = 1;
		if (swbit->scmi_frame < PQ_SCMI_GAME_BUF_MIN)
			swbit->scmi_frame = PQ_SCMI_GAME_BUF_MIN;

		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER, "fixup scmi opm diff, frame cnt=%u\n",
			swbit->scmi_frame);
	}

	return 0;
}

static int mtk_pq_buffer_hwmap_bitnum_fixup(struct mtk_pq_device *pq_dev, hwmap_swbit *swbit)
{
	struct meta_pq_stream_info *stream_pq;

	if (!pq_dev || !swbit) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	stream_pq = &(pq_dev->stream_meta);
	if (!stream_pq) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	// refine bit num
	if ((stream_pq->pq_source == meta_pq_source_b2r) &&
		IS_UCM_REFINE_FORMAT(swbit->ucm_format, swbit->ucm_ch0_bit,
			swbit->ucm_ch1_bit, swbit->ucm_ch2_bit)) {
		swbit->ucm_ch0_bit = ((stream_pq->height * swbit->ucm_ch0_bit)
			> (UCM_FHD_HEIGHT * UCM_8_BITS)) ? swbit->ucm_ch0_bit : UCM_8_BITS;
		swbit->ucm_ch1_bit = ((stream_pq->height * swbit->ucm_ch1_bit)
			> (UCM_FHD_HEIGHT * UCM_8_BITS)) ? swbit->ucm_ch1_bit : UCM_8_BITS;
		swbit->ucm_ch2_bit = UCM_0_BITS;
	}

	STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
		"ucm_ch0_bit:%d, ucm_ch1_bit:%d, ucm_ch2_bit:%d\n",
		swbit->ucm_ch0_bit, swbit->ucm_ch1_bit, swbit->ucm_ch2_bit);

	return 0;
}

int mtk_pq_buffer_get_hwmap_info(struct mtk_pq_device *pq_dev)
{
	int ret = 0;
	enum pqu_buffer_type buf_idx = PQU_BUF_SCMI;
	struct mtk_pq_platform_device *pqdev = NULL;
	struct pq_buffer *pBufferTable = NULL;
	struct meta_pq_stream_info *stream_pq = NULL;
	hwmap_swbit swbit, swbit_p, swbit_i;
	struct mtk_pq_caps *pqcaps;
	int boost_width = 0, boost_height = 0;

	if (pq_dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	pqdev = dev_get_drvdata(pq_dev->dev);
	pBufferTable = pq_dev->display_info.BufferTable;
	stream_pq = &(pq_dev->stream_meta);
	pqcaps = &pqdev->pqcaps;

	memset(&swbit, 0, sizeof(hwmap_swbit));
	memset(&swbit_p, 0, sizeof(hwmap_swbit));
	memset(&swbit_i, 0, sizeof(hwmap_swbit));

	STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
		"stream.width: %d, stream.height: %d, scenario_idx: %d\n",
		stream_pq->width, stream_pq->height, stream_pq->scenario_idx);

	drv_hwreg_common_config_load_tab_by_src(
		stream_pq->scenario_idx, PQ_BIN_IP_ALL, pqdev->config_info.u8Config_Version,
		false, NULL, NULL, NULL, &swbit, NULL, NULL);

	if (stream_pq->bFormatSelectEn) {
		_mtk_pq_mapping_scmi_format(&swbit, stream_pq->u8SCMIFormat);
		_mtk_pq_mapping_ucm_format(&swbit, stream_pq->u8UCMFormat);
	}

	if ((stream_pq->pq_scene == meta_pq_scene_force_p) && (stream_pq->bForceP == true)) {
		uint8_t p_idx = 0, i_idx = 0;

		p_idx = drv_hwreg_common_get_pi_idx(FORCEP_LEVEL_P_BEST);
		i_idx = drv_hwreg_common_get_pi_idx(FORCEP_LEVEL_I_BEST);

		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER, "p_idx:%d, i_idx:%d\n", p_idx, i_idx);

		drv_hwreg_common_config_load_tab_by_src(
			p_idx, PQ_BIN_IP_ALL, pqdev->config_info.u8Config_Version,
			false, NULL, NULL, NULL, &swbit_p, NULL, NULL);
		drv_hwreg_common_config_load_tab_by_src(
			i_idx, PQ_BIN_IP_ALL, pqdev->config_info.u8Config_Version,
			false, NULL, NULL, NULL, &swbit_i, NULL, NULL);

		swbit.scmi_ch0_bit = MAX(swbit_p.scmi_ch0_bit, swbit_i.scmi_ch0_bit);
		swbit.scmi_ch1_bit = MAX(swbit_p.scmi_ch1_bit, swbit_i.scmi_ch1_bit);
		swbit.scmi_ch2_bit = MAX(swbit_p.scmi_ch2_bit, swbit_i.scmi_ch2_bit);
		swbit.scmi_frame = MAX(swbit_p.scmi_frame, swbit_i.scmi_frame);

		swbit.ucm_ch0_bit = MAX(swbit_p.ucm_ch0_bit, swbit_i.ucm_ch0_bit);
		swbit.ucm_ch1_bit = MAX(swbit_p.ucm_ch1_bit, swbit_i.ucm_ch1_bit);
		swbit.ucm_ch2_bit = MAX(swbit_p.ucm_ch2_bit, swbit_i.ucm_ch2_bit);
		swbit.ucm_frame = MAX(swbit_p.ucm_frame, swbit_i.ucm_frame);

		swbit.znr_ch0_bit = MAX(swbit_p.znr_ch0_bit, swbit_i.znr_ch0_bit);
		swbit.znr_ch1_bit = MAX(swbit_p.znr_ch1_bit, swbit_i.znr_ch1_bit);
		swbit.znr_frame = MAX(swbit_p.znr_frame, swbit_i.znr_frame);

		swbit.abf_ch0_bit = MAX(swbit_p.abf_ch0_bit, swbit_i.abf_ch0_bit);
		swbit.abf_ch1_bit = MAX(swbit_p.abf_ch1_bit, swbit_i.abf_ch1_bit);
		swbit.abf_ch2_bit = MAX(swbit_p.abf_ch2_bit, swbit_i.abf_ch2_bit);
		swbit.abf_frame = MAX(swbit_p.abf_frame, swbit_i.abf_frame);

		swbit.mcdi_frame = MAX(swbit_p.mcdi_frame, swbit_i.mcdi_frame);
	} else if (pqcaps->u32HWMAP_Dynamic_Boost_Support) {
		struct hwmap_boost boost;
		hwmap_swbit swbit_boost;
		hwmap_buffer_mode buf_mode = hwmap_buffer_mode_max;

		memset(&boost, 0, sizeof(struct hwmap_boost));
		memset(&swbit_boost, 0, sizeof(hwmap_swbit));

		drv_hwreg_common_get_hwmap_boost(stream_pq->scenario_idx, &boost);

		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER, "%s:%d, %s:%d, %s:%d\n",
			"u32HWMAP_Dynamic_Boost_Support", pqcaps->u32HWMAP_Dynamic_Boost_Support,
			"scenario_idx", stream_pq->scenario_idx,
			"boost.scenario_idx", boost.scenario_idx);

		if (stream_pq->scenario_idx != boost.scenario_idx) {
			drv_hwreg_common_config_load_tab_by_src(
				boost.scenario_idx, PQ_BIN_IP_ALL,
				pqdev->config_info.u8Config_Version,
				false, NULL, NULL, NULL, &swbit_boost, NULL, NULL);

			buf_mode = drv_hwreg_common_config_get_buffer_mode(stream_pq->scenario_idx);
			if (buf_mode == hwmap_buffer_mode_fb) {
				boost_width = MAX(stream_pq->width, boost.width_thd);
				boost_height = MAX(stream_pq->height, boost.height_thd);
			} else {
				boost_width = boost.width_thd;
				boost_height = boost.height_thd;
			}

			swbit.scmi_ch0_bit = MAX(swbit.scmi_ch0_bit, swbit_boost.scmi_ch0_bit);
			swbit.scmi_ch1_bit = MAX(swbit.scmi_ch1_bit, swbit_boost.scmi_ch1_bit);
			swbit.scmi_ch2_bit = MAX(swbit.scmi_ch2_bit, swbit_boost.scmi_ch2_bit);
			swbit.scmi_frame = MAX(swbit.scmi_frame, swbit_boost.scmi_frame);

			swbit.ucm_ch0_bit = MAX(swbit.ucm_ch0_bit, swbit_boost.ucm_ch0_bit);
			swbit.ucm_ch1_bit = MAX(swbit.ucm_ch1_bit, swbit_boost.ucm_ch1_bit);
			swbit.ucm_ch2_bit = MAX(swbit.ucm_ch2_bit, swbit_boost.ucm_ch2_bit);
			swbit.ucm_frame = MAX(swbit.ucm_frame, swbit_boost.ucm_frame);

			swbit.znr_ch0_bit = MAX(swbit.znr_ch0_bit, swbit_boost.znr_ch0_bit);
			swbit.znr_ch1_bit = MAX(swbit.znr_ch1_bit, swbit_boost.znr_ch1_bit);
			swbit.znr_frame = MAX(swbit.znr_frame, swbit_boost.znr_frame);

			swbit.abf_ch0_bit = MAX(swbit.abf_ch0_bit, swbit_boost.abf_ch0_bit);
			swbit.abf_ch1_bit = MAX(swbit.abf_ch1_bit, swbit_boost.abf_ch1_bit);
			swbit.abf_ch2_bit = MAX(swbit.abf_ch2_bit, swbit_boost.abf_ch2_bit);
			swbit.abf_frame = MAX(swbit.abf_frame, swbit_boost.abf_frame);

			swbit.mcdi_frame = MAX(swbit.mcdi_frame, swbit_boost.mcdi_frame);
		}
	}

	/* only legacy mode need this */
	if (pqcaps->u32Support_TS == 0) {
		// frame num refine
		mtk_pq_buffer_hwmap_fixup(pq_dev, &swbit);

		// refine bit num
		mtk_pq_buffer_hwmap_bitnum_fixup(pq_dev, &swbit);
	}
	_mtk_pq_buffer_debug_swbit(pq_dev, &swbit);
	for (buf_idx = PQU_BUF_SCMI; buf_idx < PQU_BUF_MAX; buf_idx++) {
		struct pq_buffer *ppq_buf = &(pBufferTable[buf_idx]);

		ret = _mtk_pq_get_hwmap_info(ppq_buf, buf_idx, &swbit, &(pq_dev->stream_meta),
			pqcaps);
		if (ret) {
			STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
				"_mtk_pq_get_hwmap_info Failed, ret = %d\n", ret);
			return ret;
		}

		ppq_buf->width = stream_pq->width;
		ppq_buf->height = stream_pq->height;

		if ((stream_pq->pq_mode == meta_pq_mode_legacy) && (stream_pq->bForceP == true) &&
			(stream_pq->pq_scene == meta_pq_scene_force_p)) {
			if (buf_idx == PQU_BUF_SCMI) {
				ppq_buf->width = PQ_FHD_WIDTH;
				ppq_buf->height = PQ_FHD_HEIGHT;
			}
		} else if (pqcaps->u32HWMAP_Dynamic_Boost_Support) {
			if (buf_idx == PQU_BUF_SCMI) {
				if (boost_width != 0 && boost_height != 0) {
					ppq_buf->width = boost_width;
					ppq_buf->height = boost_height;
				}
			}
		}

		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER, "buf_idx = %d, width = %d, height = %d\n",
				buf_idx, ppq_buf->width, ppq_buf->height);
	}

	memcpy(&pq_dev->display_info.swbit, &swbit, sizeof(struct hwmap_swbit));

	return ret;
}

bool _mtk_pq_buf_skip_cond(enum v4l2_pq_path path, enum pqu_buffer_type buf_idx)
{
	bool ret = false;
	bool dip_path = false;
	bool dip_buf = false;

	if (path == V4L2_PQ_PATH_DIPW || path == V4L2_PQ_PATH_DIPWGE)
		dip_path = true;
	if (buf_idx == PQU_BUF_DIPDI)
		dip_buf = true;
	if ((dip_path && !dip_buf) ||
		(!dip_path && dip_buf))
		ret = true;
	return ret;
}

int mtk_pq_buffer_allocate(struct mtk_pq_device *pq_dev)
{
	enum pqu_buffer_type buf_idx = PQU_BUF_SCMI;
	enum pqu_buffer_channel ch_idx = PQU_BUF_CH_0;
	struct pq_buffer *pBufferTable = NULL;
	struct meta_pq_stream_info *stream_pq = NULL;
	bool bHwBuffer = false;
	int ret = 0;

	if (pq_dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	pBufferTable = pq_dev->display_info.BufferTable;
	stream_pq = &(pq_dev->stream_meta);
	bHwBuffer = ((pq_dev->display_info.mdw.output_path == PQ_OUTPUT_PATH_WITH_BUF_FRC) ||
		(pq_dev->common_info.output_mode != MTK_PQ_OUTPUT_MODE_SW));

	STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER, "stream.width: %d, stream.height: %d\n",
						stream_pq->width, stream_pq->height);

	for (buf_idx = PQU_BUF_SCMI; buf_idx < PQU_BUF_MAX; buf_idx++) {
		struct pq_buffer *ppq_buf = &(pBufferTable[buf_idx]);
		if (_mtk_pq_buf_skip_cond(pq_dev->path, buf_idx))
			continue;
		if (ppq_buf->frame_num != 0) {
			if (ppq_buf->valid == true)
				_mtk_pq_release_buf(pq_dev, buf_idx, ppq_buf);
			if (((buf_idx == PQU_BUF_VGSYNC)
				&& (bHwBuffer == true))
				|| (buf_idx != PQU_BUF_VGSYNC)) {
				ret = _mtk_pq_allocate_buf(pq_dev, buf_idx, ppq_buf, *stream_pq);
				if (ret) {
					STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
						"_mtk_pq_allocate_buf Failed, ret = %d\n", ret);
					return ret;
				}
			}
			for (ch_idx = PQU_BUF_CH_0; ch_idx < PQU_BUF_CH_MAX; ch_idx++) {
				if (ch_idx == PQU_BUF_CH_0)
					ppq_buf->addr_ch[ch_idx] = ppq_buf->addr;
				else
					ppq_buf->addr_ch[ch_idx] =
						ppq_buf->addr_ch[ch_idx-1] +
						ppq_buf->size_ch[ch_idx-1];
			}

			if ((buf_idx == PQU_BUF_SCMI) || (buf_idx == PQU_BUF_UCM))
				ppq_buf->sec_buf = true;

		} else {
			if (ppq_buf->valid == true)
				_mtk_pq_release_buf(pq_dev, buf_idx, ppq_buf);
		}
	}

	return ret;
}

int mtk_pq_buffer_release(struct mtk_pq_device *pq_dev)
{
	enum pqu_buffer_type buf_idx = PQU_BUF_SCMI;
	struct pq_buffer *pBufferTable = NULL;

	if (pq_dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	pBufferTable = pq_dev->display_info.BufferTable;

	for (buf_idx = PQU_BUF_SCMI; buf_idx < PQU_BUF_MAX; buf_idx++) {
		struct pq_buffer *ppq_buf = &(pBufferTable[buf_idx]);

		STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER, "buf_idx, %d\n", buf_idx);

		if (ppq_buf->valid == true) {
			if ((buf_idx == PQU_BUF_SCMI) || (buf_idx == PQU_BUF_UCM))
				ppq_buf->sec_buf = false;

			_mtk_pq_release_buf(pq_dev, buf_idx, ppq_buf);
		}
	}

	return 0;
}

int mtk_get_pq_buffer(struct mtk_pq_device *pq_dev, enum pqu_buffer_type buftype,
	struct pq_buffer *ppq_buf)
{
	int ret = 1;
	struct pq_buffer *pBufferTable = NULL;

	if (pq_dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	if (ppq_buf == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	pBufferTable = pq_dev->display_info.BufferTable;

	if (buftype >= PQU_BUF_MAX) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
			"buftype is not valid : %d\n", buftype);
		return -EPERM;
	}

	ppq_buf->valid = pBufferTable[buftype].valid;
	ppq_buf->size = pBufferTable[buftype].size;
	ppq_buf->frame_num = pBufferTable[buftype].frame_num;
	ppq_buf->frame_format = pBufferTable[buftype].frame_format;
	ppq_buf->frame_diff = pBufferTable[buftype].frame_diff;
	ppq_buf->frame_delay = pBufferTable[buftype].frame_delay;
	ppq_buf->va = pBufferTable[buftype].va;
	ppq_buf->pa = pBufferTable[buftype].pa;
	ppq_buf->addr = pBufferTable[buftype].addr;
	ppq_buf->width = pBufferTable[buftype].width;
	ppq_buf->height = pBufferTable[buftype].height;
	memcpy(ppq_buf->addr_ch, pBufferTable[buftype].addr_ch, sizeof(__u64) * PQU_BUF_CH_MAX);
	memcpy(ppq_buf->size_ch, pBufferTable[buftype].size_ch, sizeof(__u32) * PQU_BUF_CH_MAX);
	memcpy(ppq_buf->bit, pBufferTable[buftype].bit, sizeof(__u8) * PQU_BUF_CH_MAX);
	if (pq_dev->log_cd == 0) {
		if (buftype == PQU_BUF_VGSYNC) {
			STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
				"valid : %d, size : %u va : %llx, addr : %llx\n",
				ppq_buf->valid, ppq_buf->size_ch[0],
				ppq_buf->va, ppq_buf->addr_ch[0]);
		} else {
			STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
				"valid : %d, size : %u va : %llx, addr : %llx\n",
				ppq_buf->valid, ppq_buf->size, ppq_buf->va, ppq_buf->addr);
		}
	}
	return ret;
}

int mtk_pq_get_cal_buffer_size(struct mtk_pq_device *pq_dev, enum pqu_buffer_type buf_type,
	struct pq_buffer *ppq_buf)
{
	int ret = 0;
	struct meta_pq_stream_info *stream_pq = NULL;
	struct mtk_pq_platform_device *pqdev = NULL;

	if (pq_dev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	if (ppq_buf == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	stream_pq = &(pq_dev->stream_meta);
	pqdev = dev_get_drvdata(pq_dev->dev);
	ret = _mtk_pq_cal_buf_size(ppq_buf, buf_type, *stream_pq, pqdev);
	if (ret) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
		"_mtk_pq_cal_buf_size Failed, ret = %d\n", ret);
		return ret;
	}

	STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER, "buf_type = %d, size = %u",
		buf_type, ppq_buf->size);

	return ret;
}

int mtk_pq_buffer_get_extra_frame(struct mtk_pq_device *pq_dev, uint8_t *extra_frame)
{
	struct mtk_pq_platform_device *pqdev = NULL;
	enum meta_pq_source pq_source = meta_pq_source_ipdma;
	enum meta_pq_mode pq_mode = meta_pq_mode_ts;
	bool interlace = false;
	bool low_latency = false;
	__u8 frame_delay = 0;
	__u8 tmp_extra = 0;
	__u8 vdec_extra = 0;
	__u8 dv_extra = 0;
	bool bvdec_statistic_en = false;
	enum EN_PQ_CFD_HDR_MODE hdr_mode = E_PQ_CFD_HDR_MODE_SDR;

	if (pq_dev == NULL || extra_frame == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	pqdev = dev_get_drvdata(pq_dev->dev);
	if (pqdev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	interlace = pq_dev->stream_meta.interlace;
	pq_source = pq_dev->stream_meta.pq_source;
	pq_mode = pq_dev->stream_meta.pq_mode;
	if (pq_source == meta_pq_source_b2r) {

		bvdec_statistic_en = pq_dev->stream_meta.bvdec_statistic_en;
		frame_delay =
			pq_dev->display_info.BufferTable[PQU_BUF_SCMI].frame_delay +
			pq_dev->display_info.BufferTable[PQU_BUF_UCM].frame_delay;

		if (bvdec_statistic_en == true) {
			switch (pq_dev->stream_meta.scan_type) {
			case meta_pq_scan_type_progressive:
				vdec_extra = pqdev->display_dev.extraframe_p;
				break;
			case meta_pq_scan_type_i_frame:
				vdec_extra = pqdev->display_dev.extraframe_i_frame;
				break;
			case meta_pq_scan_type_i_field:
				vdec_extra = pqdev->display_dev.extraframe_i_filed;
				break;
			default:
				vdec_extra = 0;
				STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "undefine scan_type\n")
					break;
			}

			if (pq_mode == meta_pq_mode_ts)
				vdec_extra += TS_EXTRA_DELAY;
		}

		low_latency = pq_dev->stream_meta.low_latency;
		if (low_latency == false) {
			if (frame_delay >= vdec_extra)
				tmp_extra = 0;
			else
				tmp_extra = vdec_extra - frame_delay;
		}
	}

	hdr_mode = (enum EN_PQ_CFD_HDR_MODE)pq_dev->hdr_type;
	if (hdr_mode == E_PQ_CFD_HDR_MODE_DOLBY) {
		dv_extra = mtk_pq_dv_get_extra_num(pqdev);
		if (tmp_extra < dv_extra)
			tmp_extra = dv_extra;
	}

	STI_PQ_LOG(STI_PQ_LOG_LEVEL_BUFFER,
		"%s%d, %s%d, %s%d, %s%d, %s%d, %s%d, %s%d, %s%d, %s%d, %s%d, %s%d, %s%d\n",
		"Window = ", pq_dev->dev_indx,
		"pq_source = ", pq_source,
		"low_latency = ", low_latency,
		"interlance = ", interlace,
		"bvdec_statistic_en = ", bvdec_statistic_en,
		"hdr_mode = ", hdr_mode,
		"frame_delay = ", frame_delay,
		"vdec_extra = ", vdec_extra,
		"dv_extra = ", dv_extra,
		"extra_frame = ", tmp_extra,
		"pq_mode = ", pq_mode,
		"scan_type = ", pq_dev->stream_meta.scan_type);

	*extra_frame = tmp_extra;

	return 0;
}

int mtk_pq_buffer_frc_pq_allocate(struct mtk_pq_platform_device *pqdev)
{
	int ret = 0;
	struct pq_buffer_frc_pq *pBuffer_frc_pq = NULL;

	if (pqdev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	pBuffer_frc_pq = &(pqdev->frc_dev.frc_pq_buffer);
	pqdev->frc_dev.dev = pqdev->dev;

	if (pBuffer_frc_pq->valid == true)
		return 0;

	ret = _mtk_pq_allocate_frc_pq_buf(&(pqdev->frc_dev), pBuffer_frc_pq);
	if (ret) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
			"_mtk_pq_allocate_frc_pq_buf Failed, ret = %d\n", ret);
		return ret;
	}

	return 0;
}

int mtk_pq_buffer_frc_pq_release(struct mtk_pq_platform_device *pqdev)
{
	int ret = 0;
	struct pq_buffer_frc_pq *pBuffer_frc_pq = NULL;

	if (pqdev == NULL) {
		PQ_CHECK_NULLPTR();
		return -EPERM;
	}

	pBuffer_frc_pq = &(pqdev->frc_dev.frc_pq_buffer);
	pqdev->frc_dev.dev = pqdev->dev;

	if (pBuffer_frc_pq->valid == true) {
		ret = _mtk_pq_release_frc_pq_buf(&(pqdev->frc_dev), pBuffer_frc_pq);
		if (ret) {
			STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR,
				"_mtk_pq_release_frc_pq_buf Failed, ret = %d\n", ret);
			return ret;
		}
	}
	return 0;
}

static void _mtk_pq_scmi_miup_debug_info(struct mtk_pq_device *pq_dev,
	struct mtk_pq_miup_client_table *pq_miup_id, uint32_t hit_cid)
{
	struct hwreg_scmi_hw_info scmi_hw_info;
	struct pq_buffer pq_buf[PQU_BUF_MAX];

	if (pq_dev == NULL) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "Pointer is NULL!\n");
		return;
	}

	if (pq_miup_id == NULL) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "Pointer is NULL!\n");
		return;
	}

	if (pq_dev->ref_count == 0) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "Window is not open!\n");
		return;
	}

	memset(&scmi_hw_info, 0, sizeof(struct hwreg_scmi_hw_info));
	pr_crit("[%s][%d]\n", __func__, __LINE__);

	//scmi info
	if ((hit_cid == pq_miup_id->u16ipm_w) || (hit_cid == pq_miup_id->u16ipm_w_1) ||
		(hit_cid == pq_miup_id->u16ipm_r) || (hit_cid == pq_miup_id->u16ipm_r_1)) {
		/* meta get pq buf info */
		mtk_get_pq_buffer(pq_dev, PQU_BUF_SCMI, &pq_buf[PQU_BUF_SCMI]);

		//get hw status
		drv_hwreg_pq_display_scmi_get_hw_info(&scmi_hw_info);
		pr_crit("@@============[SCMI]============@@\n");
		pr_crit("[Buffer Addr Info]:\n (addr_r, addr_g, addr_b) = (0x%llx, 0x%llx, 0x%llx)\n",
			pq_buf[PQU_BUF_SCMI].addr_ch[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_SCMI].addr_ch[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_SCMI].addr_ch[PQU_BUF_CH_2]);
		pr_crit("[Buffer Size Info]:\n (size_r, size_g, size_b) = (0x%x, 0x%x, 0x%x)\n",
			pq_buf[PQU_BUF_SCMI].size_ch[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_SCMI].size_ch[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_SCMI].size_ch[PQU_BUF_CH_2]);
		pr_crit("[Buffer Bit Info]:\n (size_r, size_g, size_b) = (0x%x, 0x%x, 0x%x)\n",
			pq_buf[PQU_BUF_SCMI].bit[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_SCMI].bit[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_SCMI].bit[PQU_BUF_CH_2]);
		pr_crit("[HW Addr Info]:\n (addr_r, addr_g, addr_b) = (0x%x, 0x%x, 0x%x)\n",
			scmi_hw_info.scmi_addr.base_addr_r, scmi_hw_info.scmi_addr.base_addr_g,
			scmi_hw_info.scmi_addr.base_addr_b);
		pr_crit("[HW Limit Addr Info]:\n");
		pr_crit("[IPM limit]:\n (enable, limit_start, limit_end) = (%d, 0x%x, 0x%x)\n",
			scmi_hw_info.scmi_limitaddr.limit_enable_ipm,
			scmi_hw_info.scmi_limitaddr.limit_addr_start_ipm,
			scmi_hw_info.scmi_limitaddr.limit_addr_end_ipm);
		pr_crit("[IPMR limit]:\n (enable, limit_start, limit_end) = (%d, 0x%x, 0x%x)\n",
			scmi_hw_info.scmi_limitaddr.limit_enable_ipmr,
			scmi_hw_info.scmi_limitaddr.limit_addr_start_ipmr,
			scmi_hw_info.scmi_limitaddr.limit_addr_end_ipmr);
		pr_crit("[OPM limit]:\n (enable, limit_start, limit_end) = (%d, 0x%x, 0x%x)\n",
			scmi_hw_info.scmi_limitaddr.limit_enable_opm,
			scmi_hw_info.scmi_limitaddr.limit_addr_start_opm,
			scmi_hw_info.scmi_limitaddr.limit_addr_end_opm);
		pr_crit("[OPW limit]:\n (enable, limit_start, limit_end) = (%d, 0x%x, 0x%x)\n",
			scmi_hw_info.scmi_limitaddr.limit_enable_opw,
			scmi_hw_info.scmi_limitaddr.limit_addr_start_opw,
			scmi_hw_info.scmi_limitaddr.limit_addr_end_opw);
	}
}

static void _mtk_pq_ucm_miup_debug_info(struct mtk_pq_device *pq_dev,
	struct mtk_pq_miup_client_table *pq_miup_id, uint32_t hit_cid)
{
	struct hwreg_ucm_hw_info ucm_hw_info;
	struct pq_buffer pq_buf[PQU_BUF_MAX];

	if (pq_dev == NULL) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "Pointer is NULL!\n");
		return;
	}

	if (pq_dev->ref_count == 0) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "Window is not open!\n");
		return;
	}

	memset(&ucm_hw_info, 0, sizeof(struct hwreg_ucm_hw_info));
	pr_crit("[%s][%d]\n", __func__, __LINE__);

	//znr, ucn info
	if ((hit_cid == pq_miup_id->u16ucm_w) || (hit_cid == pq_miup_id->u16ucm_w_1)
		|| (hit_cid == pq_miup_id->u16ucm_r)
		|| (hit_cid == pq_miup_id->u16ucm_r_1)
		|| (hit_cid == pq_miup_id->u16znr_r)) {
		/* meta get pq buf info */
		mtk_get_pq_buffer(pq_dev, PQU_BUF_UCM, &pq_buf[PQU_BUF_UCM]);

		//get hw status
		drv_hwreg_pq_display_ucm_get_hw_info(&ucm_hw_info);
		pr_crit("@@============[UCM]============@@\n");
		pr_crit("[Buffer Addr Info]:\n (addr_r, addr_g, addr_b) = (0x%llx, 0x%llx, 0x%llx)\n",
			pq_buf[PQU_BUF_UCM].addr_ch[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_UCM].addr_ch[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_UCM].addr_ch[PQU_BUF_CH_2]);
		pr_crit("[Buffer Size Info]:\n (size_r, size_g, size_b) = (0x%x, 0x%x, 0x%x)\n",
			pq_buf[PQU_BUF_UCM].size_ch[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_UCM].size_ch[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_UCM].size_ch[PQU_BUF_CH_2]);
		pr_crit("[Buffer Bit Info]:\n (size_r, size_g, size_b) = (0x%x, 0x%x, 0x%x)\n",
			pq_buf[PQU_BUF_UCM].bit[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_UCM].bit[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_UCM].bit[PQU_BUF_CH_2]);
		pr_crit("[HW Addr Info - UCM write]:\n (w_addr_r, w_addr_g, w_addr_b)"
			" = (0x%x, 0x%x, 0x%x)\n",
			ucm_hw_info.ucm_addr.write_base_addr_r,
			ucm_hw_info.ucm_addr.write_base_addr_g,
			ucm_hw_info.ucm_addr.write_base_addr_b);
		pr_crit("[HW Addr Info - UCM read]:\n (r_addr_r, r_addr_g, r_addr_b)"
			" = (0x%x, 0x%x, 0x%x)\n",
			ucm_hw_info.ucm_addr.read_base_addr_r,
			ucm_hw_info.ucm_addr.read_base_addr_g,
			ucm_hw_info.ucm_addr.read_base_addr_b);
		pr_crit("[HW Limit Addr Info]:\n");
		pr_crit("[UCM write limit]:\n (enable, limit_start, limit_end) = (%d, 0x%x, 0x%x)\n",
			ucm_hw_info.ucm_limitaddr.write_limit_enable,
			ucm_hw_info.ucm_limitaddr.write_limit_addr_start,
			ucm_hw_info.ucm_limitaddr.write_limit_addr_end);
		pr_crit("[UCM read limit]:\n (enable, limit_start, limit_end) = (%d, 0x%x, 0x%x)\n",
			ucm_hw_info.ucm_limitaddr.read_limit_enable,
			ucm_hw_info.ucm_limitaddr.read_limit_addr_start,
			ucm_hw_info.ucm_limitaddr.read_limit_addr_end);

		pr_crit("@@============[ZNR]============@@\n");
		pr_crit("[Buffer Addr Info]:\n (addr_r, addr_g, addr_b) = (0x%llx, 0x%llx, 0x%llx)\n",
			pq_buf[PQU_BUF_ZNR].addr_ch[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_ZNR].addr_ch[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_ZNR].addr_ch[PQU_BUF_CH_2]);
		pr_crit("[Buffer Size Info]:\n (size_r, size_g, size_b) = (0x%x, 0x%x, 0x%x)\n",
			pq_buf[PQU_BUF_ZNR].size_ch[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_ZNR].size_ch[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_ZNR].size_ch[PQU_BUF_CH_2]);
		pr_crit("[Buffer Bit Info]:\n (size_r, size_g, size_b) = (0x%x, 0x%x, 0x%x)\n",
			pq_buf[PQU_BUF_ZNR].bit[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_ZNR].bit[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_ZNR].bit[PQU_BUF_CH_2]);
		pr_crit("[HW Addr Info]:\n (w_pln0, w_pln0, r_pln0, r_pln0)"
			" = (0x%x, 0x%x, 0x%x, 0x%x)\n",
			ucm_hw_info.znr_addr.write_base_addr_pln0,
			ucm_hw_info.znr_addr.write_base_addr_pln1,
			ucm_hw_info.znr_addr.read_base_addr_pln0,
			ucm_hw_info.znr_addr.read_base_addr_pln1);
	}

	//mcdi info
	if ((hit_cid == pq_miup_id->u16mcdi_w) || (hit_cid == pq_miup_id->u16mcdi_r)) {
		/* meta get pq buf info */
		mtk_get_pq_buffer(pq_dev, PQU_BUF_MCDI, &pq_buf[PQU_BUF_MCDI]);

		pr_crit("@@============[MCDI]============@@\n");
		pr_crit("[Buffer Addr Info]:\n (addr_r, addr_g, addr_b) = (0x%llx, 0x%llx, 0x%llx)\n",
			pq_buf[PQU_BUF_MCDI].addr_ch[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_MCDI].addr_ch[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_MCDI].addr_ch[PQU_BUF_CH_2]);
		pr_crit("[Buffer Size Info]:\n (size_r, size_g, size_b) = (0x%x, 0x%x, 0x%x)\n",
			pq_buf[PQU_BUF_MCDI].size_ch[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_MCDI].size_ch[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_MCDI].size_ch[PQU_BUF_CH_2]);
		pr_crit("[Buffer Bit Info]:\n (size_r, size_g, size_b) = (0x%x, 0x%x, 0x%x)\n",
			pq_buf[PQU_BUF_MCDI].bit[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_MCDI].bit[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_MCDI].bit[PQU_BUF_CH_2]);
	}

	//abf info
	if ((hit_cid == pq_miup_id->u16abf_w) || (hit_cid == pq_miup_id->u16abf_r)) {
		/* meta get pq buf info */
		mtk_get_pq_buffer(pq_dev, PQU_BUF_ABF, &pq_buf[PQU_BUF_ABF]);
		pr_crit("@@============[ABF]============@@\n");
		pr_crit("[Buffer Addr Info]:\n (addr_r, addr_g, addr_b) = (0x%llx, 0x%llx, 0x%llx)\n",
			pq_buf[PQU_BUF_ABF].addr_ch[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_ABF].addr_ch[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_ABF].addr_ch[PQU_BUF_CH_2]);
		pr_crit("[Buffer Size Info]:\n (size_r, size_g, size_b) = (0x%x, 0x%x, 0x%x)\n",
			pq_buf[PQU_BUF_ABF].size_ch[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_ABF].size_ch[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_ABF].size_ch[PQU_BUF_CH_2]);
		pr_crit("[Buffer Bit Info]:\n (size_r, size_g, size_b) = (0x%x, 0x%x, 0x%x)\n",
			pq_buf[PQU_BUF_ABF].bit[PQU_BUF_CH_0],
			pq_buf[PQU_BUF_ABF].bit[PQU_BUF_CH_1],
			pq_buf[PQU_BUF_ABF].bit[PQU_BUF_CH_2]);
	}
}

static void _mtk_pq_mdw_miup_debug_info(struct mtk_pq_device *pq_dev,
	struct mtk_pq_miup_client_table *pq_miup_id, uint32_t hit_cid, uint8_t win_idx)
{
	struct hwreg_mdw_hw_info mdw_hw_info;

	if (pq_dev == NULL) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "Pointer is NULL!\n");
		return;
	}

	if (pq_dev->ref_count == 0) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "Window is not open!\n");
		return;
	}

	memset(&mdw_hw_info, 0, sizeof(struct hwreg_mdw_hw_info));
	pr_crit("[%s][%d]\n", __func__, __LINE__);

	//mdw info
	if ((hit_cid == pq_miup_id->u16mdw_w)
		|| (hit_cid == pq_miup_id->u16mdw_w_1)) {
		//get hw status
		drv_hwreg_pq_display_mdw_get_hw_info(&mdw_hw_info);
		pr_crit("@@============[MDW]============@@\n");
		pr_crit("[HW Addr Info]:\n (addr_r, addr_g, addr_b) = (0x%x, 0x%x, 0x%x)\n",
			mdw_hw_info.mdw_addr.base_addr_r, mdw_hw_info.mdw_addr.base_addr_g,
			mdw_hw_info.mdw_addr.base_addr_b);
		pr_crit("[HW Limit Addr Info]:\n");
		pr_crit("[MDW limit]:\n (enable, limit_start, limit_end) = (%d, 0x%x, 0x%x)\n",
			mdw_hw_info.mdw_limitaddr.limit_enable,
			mdw_hw_info.mdw_limitaddr.limit_addr_start,
			mdw_hw_info.mdw_limitaddr.limit_addr_end);
		pr_crit("[MDW buffer]:Buffer Info from displink\n");

		//pr_crit("(mdw_meta_buf_size, mdw_frame_buf_size) = (0x%llx, 0x%llx)\n",
		//	pqdev->pq_devs[win_idx]->pq_debug.mdw_meta_buf_size,
		//	pqdev->pq_devs[win_idx]->pq_debug.mdw_frame_buf_size);
	}
}

void mtk_pq_miup_debug_info(struct mtk_pq_device *pq_dev,
	struct mtk_pq_miup_client_table *pq_miup_id, uint32_t hit_cid, uint8_t win_idx)
{
	if (pq_dev == NULL) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "Pointer is NULL!\n");
		return;
	}

	if (pq_dev->ref_count == 0) {
		STI_PQ_LOG(STI_PQ_LOG_LEVEL_ERROR, "Window is not open!\n");
		return;
	}

	_mtk_pq_scmi_miup_debug_info(pq_dev, pq_miup_id, hit_cid);
	_mtk_pq_ucm_miup_debug_info(pq_dev, pq_miup_id, hit_cid);
	_mtk_pq_mdw_miup_debug_info(pq_dev, pq_miup_id, hit_cid, win_idx);
}

