// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
 */

/* Linux Headers */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/irqreturn.h>
#include <linux/errno.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/fdtable.h>
#include <linux/file.h>
#include <linux/list.h>
#include <linux/kthread.h>
#include <linux/ktime.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/sysfs.h>
#include <linux/uaccess.h>
#include <uapi/linux/sched/types.h>
#include <asm/div64.h>
/* media module used media/registers/cpu_version.h since kernel 5.4 */
#include <linux/amlogic/media/registers/cpu_version.h>

/* Android Headers */

/* Amlogic Headers */
#include <linux/amlogic/media/vout/vinfo.h>
#include <linux/amlogic/media/vout/vout_notify.h>
#include <linux/amlogic/media/video_common.h>
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
#include <linux/amlogic/media/canvas/canvas.h>
#include <linux/amlogic/media/canvas/canvas_mgr.h>
#endif
#ifdef CONFIG_AMLOGIC_VPU
#include <linux/amlogic/media/vpu/vpu.h>
#endif
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM
#include <linux/amlogic/media/amvecm/ve.h>
#endif

#ifdef CONFIG_AMLOGIC_MEDIA_VIDEO
#include <linux/amlogic/media/video_sink/video.h>
#endif
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
#include <linux/amlogic/media/amdolbyvision/dolby_vision.h>
#endif
#ifdef CONFIG_AMLOGIC_MEDIA_SECURITY
#include <linux/amlogic/media/vpu_secure/vpu_secure.h>
#endif
#ifdef CONFIG_AMLOGIC_MEDIA_SW_SYNC
#include "../common/sw_sync/osd_sw_sync.h"
#endif

/* Local Headers */
#include "osd_canvas.h"
#include "osd_prot.h"
#include "osd_antiflicker.h"
#include "osd_clone.h"
#include "osd_log.h"
#include "osd_reg.h"
#include "osd_io.h"
#include "osd_backup.h"
#include "osd_hw.h"
#include "osd_hw_def.h"
#include "osd_fb.h"
#include "osd_rdma.h"

#ifdef CONFIG_AMLOGIC_VSYNC_FIQ_ENABLE
#define FIQ_VSYNC
#endif
#define VOUT_ENCI	1
#define VOUT_ENCP	2
#define VOUT_ENCT	3
#define OSD_TYPE_TOP_FIELD 0
#define OSD_TYPE_BOT_FIELD 1

#define OSD_DISP_DEBUG    1
#define OSD_OLD_HWC         (0x01 << 0)
#define OSD_OTHER_NEW_HWC   (0x01 << 1)
#define OSD_G12A_NEW_HWC    (0x01 << 2)

#define WAIT_AFBC_READY_COUNT 100
#define NEW_PPS_PHASE

#define osd_tprintk(...)

#define FREE_SCALE_MAX_WIDTH    1920
#define WAIT_CNT_MAX            20
#define SCALER_OVERLAP          32
#define SIZE_ALIG8              BYTE_8_ALIGNED

struct hw_para_s osd_hw;
struct osd_device_hw_s osd_dev_hw;

static DEFINE_MUTEX(osd_mutex);
static DECLARE_WAIT_QUEUE_HEAD(osd_vsync_wq);
static DECLARE_WAIT_QUEUE_HEAD(osd_vsync2_wq);
static DECLARE_WAIT_QUEUE_HEAD(osd_vsync3_wq);

static DECLARE_WAIT_QUEUE_HEAD(osd_rdma_vpp0_done_wq);
static DECLARE_WAIT_QUEUE_HEAD(osd_rdma_vpp1_done_wq);
static DECLARE_WAIT_QUEUE_HEAD(osd_rdma_vpp2_done_wq);

static bool vsync_hit[VIU_COUNT];
static bool osd_update_window_axis;
static int osd_afbc_dec_enable;
static int ext_canvas_id[HW_OSD_COUNT];
static int osd_extra_idx[HW_OSD_COUNT][2];
static bool suspend_flag;
static int osd_log_out;
static u32 rdma_dt_cnt;
static void set_vpp_osd2_rgb2yuv(bool on);
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
static bool update_to_dv;
#endif
static void osd_clone_pan(u32 index, u32 yoffset, int debug_flag);
static void osd_set_dummy_data(u32 index, u32 alpha);
static void osd_wait_vsync_hw_viux(u32 output_index);
static void osd_setting_default_hwc(void);
static void osd_setting_vout_blend(void);

struct hw_osd_reg_s hw_osd_reg_array[HW_OSD_COUNT];
struct hw_osd_blend_reg_s hw_osd_reg_blend;
struct hw_osd_slice2ppc_reg_s hw_osd_reg_slice2ppc;
struct hw_osd_slice2ppc_s osd_slice2ppc;

struct hw_osd_reg_s hw_osd_reg_array_g12a[HW_OSD_COUNT] = {
	{
		VIU_OSD1_CTRL_STAT,
		VIU_OSD1_CTRL_STAT2,
		VIU_OSD1_COLOR_ADDR,
		VIU_OSD1_COLOR,
		VIU_OSD1_TCOLOR_AG0,
		VIU_OSD1_TCOLOR_AG1,
		VIU_OSD1_TCOLOR_AG2,
		VIU_OSD1_TCOLOR_AG3,
		VIU_OSD1_BLK0_CFG_W0,
		VIU_OSD1_BLK0_CFG_W1,
		VIU_OSD1_BLK0_CFG_W2,
		VIU_OSD1_BLK0_CFG_W3,
		VIU_OSD1_BLK0_CFG_W4,
		VIU_OSD1_BLK1_CFG_W4,
		VIU_OSD1_BLK2_CFG_W4,
		VIU_OSD1_FIFO_CTRL_STAT,
		VIU_OSD1_TEST_RDDATA,
		VIU_OSD1_PROT_CTRL,
		VIU_OSD1_MALI_UNPACK_CTRL,
		VIU_OSD1_DIMM_CTRL,
		VPP_WRAP_OSD1_MATRIX_EN_CTRL,

		VPP_OSD_SCALE_COEF_IDX,
		VPP_OSD_SCALE_COEF,
		VPP_OSD_VSC_PHASE_STEP,
		VPP_OSD_VSC_INI_PHASE,
		VPP_OSD_VSC_CTRL0,
		VPP_OSD_HSC_PHASE_STEP,
		VPP_OSD_HSC_INI_PHASE,
		VPP_OSD_HSC_CTRL0,
		OSD_REG_UNSUPPORT,
		VPP_OSD_SC_DUMMY_DATA,
		VPP_OSD_SC_CTRL0,
		VPP_OSD_SCI_WH_M1,
		VPP_OSD_SCO_H_START_END,
		VPP_OSD_SCO_V_START_END,
		OSD_DB_FLT_CTRL,
		VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0,
		VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0,
		VPU_MAFBC_FORMAT_SPECIFIER_S0,
		VPU_MAFBC_BUFFER_WIDTH_S0,
		VPU_MAFBC_BUFFER_HEIGHT_S0,
		VPU_MAFBC_BOUNDING_BOX_X_START_S0,
		VPU_MAFBC_BOUNDING_BOX_X_END_S0,
		VPU_MAFBC_BOUNDING_BOX_Y_START_S0,
		VPU_MAFBC_BOUNDING_BOX_Y_END_S0,
		VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0,
		VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0,
		VPU_MAFBC_OUTPUT_BUF_STRIDE_S0,
		VPU_MAFBC_PREFETCH_CFG_S0,

		MALI_AFBCD_TOP_CTRL,
		VPU_MAFBC_IRQ_MASK,
		VPU_MAFBC_SURFACE_CFG,
		VPU_MAFBC_COMMAND,
		VPU_MAFBC_IRQ_RAW_STATUS,
		VPU_MAFBC_IRQ_CLEAR,

		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
	},
	{
		VIU_OSD2_CTRL_STAT,
		VIU_OSD2_CTRL_STAT2,
		VIU_OSD2_COLOR_ADDR,
		VIU_OSD2_COLOR,
		VIU_OSD2_TCOLOR_AG0,
		VIU_OSD2_TCOLOR_AG1,
		VIU_OSD2_TCOLOR_AG2,
		VIU_OSD2_TCOLOR_AG3,
		VIU_OSD2_BLK0_CFG_W0,
		VIU_OSD2_BLK0_CFG_W1,
		VIU_OSD2_BLK0_CFG_W2,
		VIU_OSD2_BLK0_CFG_W3,
		VIU_OSD2_BLK0_CFG_W4,
		VIU_OSD2_BLK1_CFG_W4,
		VIU_OSD2_BLK2_CFG_W4,
		VIU_OSD2_FIFO_CTRL_STAT,
		VIU_OSD2_TEST_RDDATA,
		VIU_OSD2_PROT_CTRL,
		VIU_OSD2_MALI_UNPACK_CTRL,
		VIU_OSD2_DIMM_CTRL,
		VPP_WRAP_OSD2_MATRIX_EN_CTRL,

		OSD2_SCALE_COEF_IDX,
		OSD2_SCALE_COEF,
		OSD2_VSC_PHASE_STEP,
		OSD2_VSC_INI_PHASE,
		OSD2_VSC_CTRL0,
		OSD2_HSC_PHASE_STEP,
		OSD2_HSC_INI_PHASE,
		OSD2_HSC_CTRL0,
		OSD_REG_UNSUPPORT,
		OSD2_SC_DUMMY_DATA,
		OSD2_SC_CTRL0,
		OSD2_SCI_WH_M1,
		OSD2_SCO_H_START_END,
		OSD2_SCO_V_START_END,
		OSD2_DB_FLT_CTRL,
		VPU_MAFBC_HEADER_BUF_ADDR_LOW_S1,
		VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S1,
		VPU_MAFBC_FORMAT_SPECIFIER_S1,
		VPU_MAFBC_BUFFER_WIDTH_S1,
		VPU_MAFBC_BUFFER_HEIGHT_S1,
		VPU_MAFBC_BOUNDING_BOX_X_START_S1,
		VPU_MAFBC_BOUNDING_BOX_X_END_S1,
		VPU_MAFBC_BOUNDING_BOX_Y_START_S1,
		VPU_MAFBC_BOUNDING_BOX_Y_END_S1,
		VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S1,
		VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S1,
		VPU_MAFBC_OUTPUT_BUF_STRIDE_S1,
		VPU_MAFBC_PREFETCH_CFG_S1,

		MALI_AFBCD_TOP_CTRL,
		VPU_MAFBC_IRQ_MASK,
		VPU_MAFBC_SURFACE_CFG,
		VPU_MAFBC_COMMAND,
		VPU_MAFBC_IRQ_RAW_STATUS,
		VPU_MAFBC_IRQ_CLEAR,

		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
	},
	{
		VIU_OSD3_CTRL_STAT,
		VIU_OSD3_CTRL_STAT2,
		VIU_OSD3_COLOR_ADDR,
		VIU_OSD3_COLOR,
		VIU_OSD3_TCOLOR_AG0,
		VIU_OSD3_TCOLOR_AG1,
		VIU_OSD3_TCOLOR_AG2,
		VIU_OSD3_TCOLOR_AG3,
		VIU_OSD3_BLK0_CFG_W0,
		VIU_OSD3_BLK0_CFG_W1,
		VIU_OSD3_BLK0_CFG_W2,
		VIU_OSD3_BLK0_CFG_W3,
		VIU_OSD3_BLK0_CFG_W4,
		VIU_OSD3_BLK1_CFG_W4,
		VIU_OSD3_BLK2_CFG_W4,
		VIU_OSD3_FIFO_CTRL_STAT,
		VIU_OSD3_TEST_RDDATA,
		VIU_OSD3_PROT_CTRL,
		VIU_OSD3_MALI_UNPACK_CTRL,
		VIU_OSD3_DIMM_CTRL,
		VPP_WRAP_OSD3_MATRIX_EN_CTRL,

		OSD34_SCALE_COEF_IDX,
		OSD34_SCALE_COEF,
		OSD34_VSC_PHASE_STEP,
		OSD34_VSC_INI_PHASE,
		OSD34_VSC_CTRL0,
		OSD34_HSC_PHASE_STEP,
		OSD34_HSC_INI_PHASE,
		OSD34_HSC_CTRL0,
		OSD_REG_UNSUPPORT,
		OSD34_SC_DUMMY_DATA,
		OSD34_SC_CTRL0,
		OSD34_SCI_WH_M1,
		OSD34_SCO_H_START_END,
		OSD34_SCO_V_START_END,
		OSD34_DB_FLT_CTRL,
		VPU_MAFBC_HEADER_BUF_ADDR_LOW_S2,
		VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S2,
		VPU_MAFBC_FORMAT_SPECIFIER_S2,
		VPU_MAFBC_BUFFER_WIDTH_S2,
		VPU_MAFBC_BUFFER_HEIGHT_S2,
		VPU_MAFBC_BOUNDING_BOX_X_START_S2,
		VPU_MAFBC_BOUNDING_BOX_X_END_S2,
		VPU_MAFBC_BOUNDING_BOX_Y_START_S2,
		VPU_MAFBC_BOUNDING_BOX_Y_END_S2,
		VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S2,
		VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S2,
		VPU_MAFBC_OUTPUT_BUF_STRIDE_S2,
		VPU_MAFBC_PREFETCH_CFG_S2,

		MALI_AFBCD_TOP_CTRL,
		VPU_MAFBC_IRQ_MASK,
		VPU_MAFBC_SURFACE_CFG,
		VPU_MAFBC_COMMAND,
		VPU_MAFBC_IRQ_RAW_STATUS,
		VPU_MAFBC_IRQ_CLEAR,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
	},
	{
		VIU2_OSD1_CTRL_STAT,
		VIU2_OSD1_CTRL_STAT2,
		VIU2_OSD1_COLOR_ADDR,
		VIU2_OSD1_COLOR,
		VIU2_OSD1_TCOLOR_AG0,
		VIU2_OSD1_TCOLOR_AG1,
		VIU2_OSD1_TCOLOR_AG2,
		VIU2_OSD1_TCOLOR_AG3,
		VIU2_OSD1_BLK0_CFG_W0,
		VIU2_OSD1_BLK0_CFG_W1,
		VIU2_OSD1_BLK0_CFG_W2,
		VIU2_OSD1_BLK0_CFG_W3,
		VIU2_OSD1_BLK0_CFG_W4,
		VIU2_OSD1_BLK1_CFG_W4,
		VIU2_OSD1_BLK2_CFG_W4,
		VIU2_OSD1_FIFO_CTRL_STAT,
		VIU2_OSD1_TEST_RDDATA,
		VIU2_OSD1_PROT_CTRL,
		VIU2_OSD1_MALI_UNPACK_CTRL,
		VIU2_OSD1_DIMM_CTRL,
		VIU2_OSD1_MATRIX_EN_CTRL,

		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,

		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		}
};

struct hw_osd_reg_s hw_osd_reg_array_tl1[HW_OSD_COUNT] = {
	{
		VIU_OSD1_CTRL_STAT,
		VIU_OSD1_CTRL_STAT2,
		VIU_OSD1_COLOR_ADDR,
		VIU_OSD1_COLOR,
		VIU_OSD1_TCOLOR_AG0,
		VIU_OSD1_TCOLOR_AG1,
		VIU_OSD1_TCOLOR_AG2,
		VIU_OSD1_TCOLOR_AG3,
		VIU_OSD1_BLK0_CFG_W0,
		VIU_OSD1_BLK0_CFG_W1,
		VIU_OSD1_BLK0_CFG_W2,
		VIU_OSD1_BLK0_CFG_W3,
		VIU_OSD1_BLK0_CFG_W4,
		VIU_OSD1_BLK1_CFG_W4,
		VIU_OSD1_BLK2_CFG_W4,
		VIU_OSD1_FIFO_CTRL_STAT,
		VIU_OSD1_TEST_RDDATA,
		VIU_OSD1_PROT_CTRL,
		VIU_OSD1_MALI_UNPACK_CTRL,
		VIU_OSD1_DIMM_CTRL,
		VPP_WRAP_OSD1_MATRIX_EN_CTRL,

		VPP_OSD_SCALE_COEF_IDX,
		VPP_OSD_SCALE_COEF,
		VPP_OSD_VSC_PHASE_STEP,
		VPP_OSD_VSC_INI_PHASE,
		VPP_OSD_VSC_CTRL0,
		VPP_OSD_HSC_PHASE_STEP,
		VPP_OSD_HSC_INI_PHASE,
		VPP_OSD_HSC_CTRL0,
		OSD_REG_UNSUPPORT,
		VPP_OSD_SC_DUMMY_DATA,
		VPP_OSD_SC_CTRL0,
		VPP_OSD_SCI_WH_M1,
		VPP_OSD_SCO_H_START_END,
		VPP_OSD_SCO_V_START_END,
		OSD_DB_FLT_CTRL,
		VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0,
		VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0,
		VPU_MAFBC_FORMAT_SPECIFIER_S0,
		VPU_MAFBC_BUFFER_WIDTH_S0,
		VPU_MAFBC_BUFFER_HEIGHT_S0,
		VPU_MAFBC_BOUNDING_BOX_X_START_S0,
		VPU_MAFBC_BOUNDING_BOX_X_END_S0,
		VPU_MAFBC_BOUNDING_BOX_Y_START_S0,
		VPU_MAFBC_BOUNDING_BOX_Y_END_S0,
		VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0,
		VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0,
		VPU_MAFBC_OUTPUT_BUF_STRIDE_S0,
		VPU_MAFBC_PREFETCH_CFG_S0,

		MALI_AFBCD_TOP_CTRL,
		VPU_MAFBC_IRQ_MASK,
		VPU_MAFBC_SURFACE_CFG,
		VPU_MAFBC_COMMAND,
		VPU_MAFBC_IRQ_RAW_STATUS,
		VPU_MAFBC_IRQ_CLEAR,

		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
	},
	{
		VIU_OSD2_CTRL_STAT,
		VIU_OSD2_CTRL_STAT2,
		VIU_OSD2_COLOR_ADDR,
		VIU_OSD2_COLOR,
		VIU_OSD2_TCOLOR_AG0,
		VIU_OSD2_TCOLOR_AG1,
		VIU_OSD2_TCOLOR_AG2,
		VIU_OSD2_TCOLOR_AG3,
		VIU_OSD2_BLK0_CFG_W0,
		VIU_OSD2_BLK0_CFG_W1,
		VIU_OSD2_BLK0_CFG_W2,
		VIU_OSD2_BLK0_CFG_W3,
		VIU_OSD2_BLK0_CFG_W4,
		VIU_OSD2_BLK1_CFG_W4,
		VIU_OSD2_BLK2_CFG_W4,
		VIU_OSD2_FIFO_CTRL_STAT,
		VIU_OSD2_TEST_RDDATA,
		VIU_OSD2_PROT_CTRL,
		VIU_OSD2_MALI_UNPACK_CTRL,
		VIU_OSD2_DIMM_CTRL,
		VPP_WRAP_OSD2_MATRIX_EN_CTRL,

		OSD2_SCALE_COEF_IDX,
		OSD2_SCALE_COEF,
		OSD2_VSC_PHASE_STEP,
		OSD2_VSC_INI_PHASE,
		OSD2_VSC_CTRL0,
		OSD2_HSC_PHASE_STEP,
		OSD2_HSC_INI_PHASE,
		OSD2_HSC_CTRL0,
		OSD_REG_UNSUPPORT,
		OSD2_SC_DUMMY_DATA,
		OSD2_SC_CTRL0,
		OSD2_SCI_WH_M1,
		OSD2_SCO_H_START_END,
		OSD2_SCO_V_START_END,
		OSD2_DB_FLT_CTRL,
		VPU_MAFBC_HEADER_BUF_ADDR_LOW_S1,
		VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S1,
		VPU_MAFBC_FORMAT_SPECIFIER_S1,
		VPU_MAFBC_BUFFER_WIDTH_S1,
		VPU_MAFBC_BUFFER_HEIGHT_S1,
		VPU_MAFBC_BOUNDING_BOX_X_START_S1,
		VPU_MAFBC_BOUNDING_BOX_X_END_S1,
		VPU_MAFBC_BOUNDING_BOX_Y_START_S1,
		VPU_MAFBC_BOUNDING_BOX_Y_END_S1,
		VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S1,
		VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S1,
		VPU_MAFBC_OUTPUT_BUF_STRIDE_S1,
		VPU_MAFBC_PREFETCH_CFG_S1,

		MALI_AFBCD_TOP_CTRL,
		VPU_MAFBC_IRQ_MASK,
		VPU_MAFBC_SURFACE_CFG,
		VPU_MAFBC_COMMAND,
		VPU_MAFBC_IRQ_RAW_STATUS,
		VPU_MAFBC_IRQ_CLEAR,

		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
	},
	{
		VIU2_OSD1_CTRL_STAT,
		VIU2_OSD1_CTRL_STAT2,
		VIU2_OSD1_COLOR_ADDR,
		VIU2_OSD1_COLOR,
		VIU2_OSD1_TCOLOR_AG0,
		VIU2_OSD1_TCOLOR_AG1,
		VIU2_OSD1_TCOLOR_AG2,
		VIU2_OSD1_TCOLOR_AG3,
		VIU2_OSD1_BLK0_CFG_W0,
		VIU2_OSD1_BLK0_CFG_W1,
		VIU2_OSD1_BLK0_CFG_W2,
		VIU2_OSD1_BLK0_CFG_W3,
		VIU2_OSD1_BLK0_CFG_W4,
		VIU2_OSD1_BLK1_CFG_W4,
		VIU2_OSD1_BLK2_CFG_W4,
		VIU2_OSD1_FIFO_CTRL_STAT,
		VIU2_OSD1_TEST_RDDATA,
		VIU2_OSD1_PROT_CTRL,
		VIU2_OSD1_MALI_UNPACK_CTRL,
		VIU2_OSD1_DIMM_CTRL,
		VIU2_OSD1_MATRIX_EN_CTRL,

		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,

		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
		}
};

struct hw_osd_reg_s hw_osd_reg_array_t7[HW_OSD_COUNT] = {
	{
		VIU_OSD1_CTRL_STAT,
		VIU_OSD1_CTRL_STAT2,
		VIU_OSD1_COLOR_ADDR,
		VIU_OSD1_COLOR,
		VIU_OSD1_TCOLOR_AG0,
		VIU_OSD1_TCOLOR_AG1,
		VIU_OSD1_TCOLOR_AG2,
		VIU_OSD1_TCOLOR_AG3,
		VIU_OSD1_BLK0_CFG_W0,
		VIU_OSD1_BLK0_CFG_W1,
		VIU_OSD1_BLK0_CFG_W2,
		VIU_OSD1_BLK0_CFG_W3,
		VIU_OSD1_BLK0_CFG_W4,
		VIU_OSD1_BLK1_CFG_W4,
		VIU_OSD1_BLK2_CFG_W4,
		VIU_OSD1_FIFO_CTRL_STAT,
		VIU_OSD1_TEST_RDDATA,
		VIU_OSD1_PROT_CTRL,
		VIU_OSD1_MALI_UNPACK_CTRL,
		VIU_OSD1_DIMM_CTRL,
		VPP_WRAP_OSD1_MATRIX_EN_CTRL,

		T7_VPP_OSD_SCALE_COEF_IDX,
		T7_VPP_OSD_SCALE_COEF,
		T7_VPP_OSD_VSC_PHASE_STEP,
		T7_VPP_OSD_VSC_INI_PHASE,
		T7_VPP_OSD_VSC_CTRL0,
		T7_VPP_OSD_HSC_PHASE_STEP,
		T7_VPP_OSD_HSC_INI_PHASE,
		T7_VPP_OSD_HSC_CTRL0,
		OSD_REG_UNSUPPORT,
		T7_VPP_OSD_SC_DUMMY_DATA,
		T7_VPP_OSD_SC_CTRL0,
		T7_VPP_OSD_SCI_WH_M1,
		T7_VPP_OSD_SCO_H_START_END,
		T7_VPP_OSD_SCO_V_START_END,
		OSD_DB_FLT_CTRL,
		VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0,
		VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0,
		VPU_MAFBC_FORMAT_SPECIFIER_S0,
		VPU_MAFBC_BUFFER_WIDTH_S0,
		VPU_MAFBC_BUFFER_HEIGHT_S0,
		VPU_MAFBC_BOUNDING_BOX_X_START_S0,
		VPU_MAFBC_BOUNDING_BOX_X_END_S0,
		VPU_MAFBC_BOUNDING_BOX_Y_START_S0,
		VPU_MAFBC_BOUNDING_BOX_Y_END_S0,
		VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0,
		VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0,
		VPU_MAFBC_OUTPUT_BUF_STRIDE_S0,
		VPU_MAFBC_PREFETCH_CFG_S0,

		MALI_AFBCD_TOP_CTRL,
		VPU_MAFBC_IRQ_MASK,
		VPU_MAFBC_SURFACE_CFG,
		VPU_MAFBC_COMMAND,
		VPU_MAFBC_IRQ_RAW_STATUS,
		VPU_MAFBC_IRQ_CLEAR,

		VPP_OSD1_SCALE_CTRL,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
	},
	{
		VIU_OSD2_CTRL_STAT,
		VIU_OSD2_CTRL_STAT2,
		VIU_OSD2_COLOR_ADDR,
		VIU_OSD2_COLOR,
		VIU_OSD2_TCOLOR_AG0,
		VIU_OSD2_TCOLOR_AG1,
		VIU_OSD2_TCOLOR_AG2,
		VIU_OSD2_TCOLOR_AG3,
		VIU_OSD2_BLK0_CFG_W0,
		VIU_OSD2_BLK0_CFG_W1,
		VIU_OSD2_BLK0_CFG_W2,
		VIU_OSD2_BLK0_CFG_W3,
		VIU_OSD2_BLK0_CFG_W4,
		VIU_OSD2_BLK1_CFG_W4,
		VIU_OSD2_BLK2_CFG_W4,
		VIU_OSD2_FIFO_CTRL_STAT,
		VIU_OSD2_TEST_RDDATA,
		VIU_OSD2_PROT_CTRL,
		VIU_OSD2_MALI_UNPACK_CTRL,
		VIU_OSD2_DIMM_CTRL,
		VPP_WRAP_OSD2_MATRIX_EN_CTRL,

		T7_OSD2_SCALE_COEF_IDX,
		T7_OSD2_SCALE_COEF,
		T7_OSD2_VSC_PHASE_STEP,
		T7_OSD2_VSC_INI_PHASE,
		T7_OSD2_VSC_CTRL0,
		T7_OSD2_HSC_PHASE_STEP,
		T7_OSD2_HSC_INI_PHASE,
		T7_OSD2_HSC_CTRL0,
		OSD_REG_UNSUPPORT,
		T7_OSD2_SC_DUMMY_DATA,
		T7_OSD2_SC_CTRL0,
		T7_OSD2_SCI_WH_M1,
		T7_OSD2_SCO_H_START_END,
		T7_OSD2_SCO_V_START_END,
		OSD2_DB_FLT_CTRL,
		VPU_MAFBC_HEADER_BUF_ADDR_LOW_S1,
		VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S1,
		VPU_MAFBC_FORMAT_SPECIFIER_S1,
		VPU_MAFBC_BUFFER_WIDTH_S1,
		VPU_MAFBC_BUFFER_HEIGHT_S1,
		VPU_MAFBC_BOUNDING_BOX_X_START_S1,
		VPU_MAFBC_BOUNDING_BOX_X_END_S1,
		VPU_MAFBC_BOUNDING_BOX_Y_START_S1,
		VPU_MAFBC_BOUNDING_BOX_Y_END_S1,
		VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S1,
		VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S1,
		VPU_MAFBC_OUTPUT_BUF_STRIDE_S1,
		VPU_MAFBC_PREFETCH_CFG_S1,

		MALI_AFBCD_TOP_CTRL,
		VPU_MAFBC_IRQ_MASK,
		VPU_MAFBC_SURFACE_CFG,
		VPU_MAFBC_COMMAND,
		VPU_MAFBC_IRQ_RAW_STATUS,
		VPU_MAFBC_IRQ_CLEAR,

		VPP_OSD2_SCALE_CTRL,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
	},
	{
		VIU_OSD3_CTRL_STAT,
		VIU_OSD3_CTRL_STAT2,
		VIU_OSD3_COLOR_ADDR,
		VIU_OSD3_COLOR,
		VIU_OSD3_TCOLOR_AG0,
		VIU_OSD3_TCOLOR_AG1,
		VIU_OSD3_TCOLOR_AG2,
		VIU_OSD3_TCOLOR_AG3,
		VIU_OSD3_BLK0_CFG_W0,
		VIU_OSD3_BLK0_CFG_W1,
		VIU_OSD3_BLK0_CFG_W2,
		VIU_OSD3_BLK0_CFG_W3,
		VIU_OSD3_BLK0_CFG_W4,
		VIU_OSD3_BLK1_CFG_W4,
		VIU_OSD3_BLK2_CFG_W4,
		VIU_OSD3_FIFO_CTRL_STAT,
		VIU_OSD3_TEST_RDDATA,
		VIU_OSD3_PROT_CTRL,
		VIU_OSD3_MALI_UNPACK_CTRL,
		VIU_OSD3_DIMM_CTRL,
		VPP_WRAP_OSD3_MATRIX_EN_CTRL,

		T7_OSD34_SCALE_COEF_IDX,
		T7_OSD34_SCALE_COEF,
		T7_OSD34_VSC_PHASE_STEP,
		T7_OSD34_VSC_INI_PHASE,
		T7_OSD34_VSC_CTRL0,
		T7_OSD34_HSC_PHASE_STEP,
		T7_OSD34_HSC_INI_PHASE,
		T7_OSD34_HSC_CTRL0,
		OSD_REG_UNSUPPORT,
		T7_OSD34_SC_DUMMY_DATA,
		T7_OSD34_SC_CTRL0,
		T7_OSD34_SCI_WH_M1,
		T7_OSD34_SCO_H_START_END,
		T7_OSD34_SCO_V_START_END,
		OSD34_DB_FLT_CTRL,
		VPU_MAFBC1_HEADER_BUF_ADDR_LOW_S2,
		VPU_MAFBC1_HEADER_BUF_ADDR_HIGH_S2,
		VPU_MAFBC1_FORMAT_SPECIFIER_S2,
		VPU_MAFBC1_BUFFER_WIDTH_S2,
		VPU_MAFBC1_BUFFER_HEIGHT_S2,
		VPU_MAFBC1_BOUNDING_BOX_X_START_S2,
		VPU_MAFBC1_BOUNDING_BOX_X_END_S2,
		VPU_MAFBC1_BOUNDING_BOX_Y_START_S2,
		VPU_MAFBC1_BOUNDING_BOX_Y_END_S2,
		VPU_MAFBC1_OUTPUT_BUF_ADDR_LOW_S2,
		VPU_MAFBC1_OUTPUT_BUF_ADDR_HIGH_S2,
		VPU_MAFBC1_OUTPUT_BUF_STRIDE_S2,
		VPU_MAFBC1_PREFETCH_CFG_S2,

		MALI_AFBCD1_TOP_CTRL,
		VPU_MAFBC1_IRQ_MASK,
		VPU_MAFBC1_SURFACE_CFG,
		VPU_MAFBC1_COMMAND,
		VPU_MAFBC1_IRQ_RAW_STATUS,
		VPU_MAFBC1_IRQ_CLEAR,

		VPP_OSD3_SCALE_CTRL,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
	},
	{
		VIU_OSD4_CTRL_STAT,
		VIU_OSD4_CTRL_STAT2,
		VIU_OSD4_COLOR_ADDR,
		VIU_OSD4_COLOR,
		VIU_OSD4_TCOLOR_AG0,
		VIU_OSD4_TCOLOR_AG1,
		VIU_OSD4_TCOLOR_AG2,
		VIU_OSD4_TCOLOR_AG3,
		VIU_OSD4_BLK0_CFG_W0,
		VIU_OSD4_BLK0_CFG_W1,
		VIU_OSD4_BLK0_CFG_W2,
		VIU_OSD4_BLK0_CFG_W3,
		VIU_OSD4_BLK0_CFG_W4,
		VIU_OSD4_BLK1_CFG_W4,
		VIU_OSD4_BLK2_CFG_W4,
		VIU_OSD4_FIFO_CTRL_STAT,
		VIU_OSD4_TEST_RDDATA,
		VIU_OSD4_PROT_CTRL,
		VIU_OSD4_MALI_UNPACK_CTRL,
		VIU_OSD4_DIMM_CTRL,
		VIU_OSD4_MATRIX_EN_CTRL,

		T7_OSD4_SCALE_COEF_IDX,
		T7_OSD4_SCALE_COEF,
		T7_OSD4_VSC_PHASE_STEP,
		T7_OSD4_VSC_INI_PHASE,
		T7_OSD4_VSC_CTRL0,
		T7_OSD4_HSC_PHASE_STEP,
		T7_OSD4_HSC_INI_PHASE,
		T7_OSD4_HSC_CTRL0,
		OSD_REG_UNSUPPORT,
		T7_OSD4_SC_DUMMY_DATA,
		T7_OSD4_SC_CTRL0,
		T7_OSD4_SCI_WH_M1,
		T7_OSD4_SCO_H_START_END,
		T7_OSD4_SCO_V_START_END,
		OSD4_DB_FLT_CTRL,
		VPU_MAFBC2_HEADER_BUF_ADDR_LOW_S3,
		VPU_MAFBC2_HEADER_BUF_ADDR_HIGH_S3,
		VPU_MAFBC2_FORMAT_SPECIFIER_S3,
		VPU_MAFBC2_BUFFER_WIDTH_S3,
		VPU_MAFBC2_BUFFER_HEIGHT_S3,
		VPU_MAFBC2_BOUNDING_BOX_X_START_S3,
		VPU_MAFBC2_BOUNDING_BOX_X_END_S3,
		VPU_MAFBC2_BOUNDING_BOX_Y_START_S3,
		VPU_MAFBC2_BOUNDING_BOX_Y_END_S3,
		VPU_MAFBC2_OUTPUT_BUF_ADDR_LOW_S3,
		VPU_MAFBC2_OUTPUT_BUF_ADDR_HIGH_S3,
		VPU_MAFBC2_OUTPUT_BUF_STRIDE_S3,
		VPU_MAFBC2_PREFETCH_CFG_S3,

		MALI_AFBCD2_TOP_CTRL,
		VPU_MAFBC2_IRQ_MASK,
		VPU_MAFBC2_SURFACE_CFG,
		VPU_MAFBC2_COMMAND,
		VPU_MAFBC2_IRQ_RAW_STATUS,
		VPU_MAFBC2_IRQ_CLEAR,

		VPP_OSD4_SCALE_CTRL,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
	},
};

struct hw_osd_reg_s hw_osd_reg_array_t3[HW_OSD_COUNT] = {
	{
		VIU_OSD1_CTRL_STAT,
		VIU_OSD1_CTRL_STAT2,
		VIU_OSD1_COLOR_ADDR,
		VIU_OSD1_COLOR,
		VIU_OSD1_TCOLOR_AG0,
		VIU_OSD1_TCOLOR_AG1,
		VIU_OSD1_TCOLOR_AG2,
		VIU_OSD1_TCOLOR_AG3,
		VIU_OSD1_BLK0_CFG_W0,
		VIU_OSD1_BLK0_CFG_W1,
		VIU_OSD1_BLK0_CFG_W2,
		VIU_OSD1_BLK0_CFG_W3,
		VIU_OSD1_BLK0_CFG_W4,
		VIU_OSD1_BLK1_CFG_W4,
		VIU_OSD1_BLK2_CFG_W4,
		VIU_OSD1_FIFO_CTRL_STAT,
		VIU_OSD1_TEST_RDDATA,
		VIU_OSD1_PROT_CTRL,
		VIU_OSD1_MALI_UNPACK_CTRL,
		VIU_OSD1_DIMM_CTRL,
		VPP_WRAP_OSD1_MATRIX_EN_CTRL,

		T7_VPP_OSD_SCALE_COEF_IDX,
		T7_VPP_OSD_SCALE_COEF,
		T7_VPP_OSD_VSC_PHASE_STEP,
		T7_VPP_OSD_VSC_INI_PHASE,
		T7_VPP_OSD_VSC_CTRL0,
		T7_VPP_OSD_HSC_PHASE_STEP,
		T7_VPP_OSD_HSC_INI_PHASE,
		T7_VPP_OSD_HSC_CTRL0,
		OSD_REG_UNSUPPORT,
		T7_VPP_OSD_SC_DUMMY_DATA,
		T7_VPP_OSD_SC_CTRL0,
		T7_VPP_OSD_SCI_WH_M1,
		T7_VPP_OSD_SCO_H_START_END,
		T7_VPP_OSD_SCO_V_START_END,
		OSD_DB_FLT_CTRL,
		VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0,
		VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0,
		VPU_MAFBC_FORMAT_SPECIFIER_S0,
		VPU_MAFBC_BUFFER_WIDTH_S0,
		VPU_MAFBC_BUFFER_HEIGHT_S0,
		VPU_MAFBC_BOUNDING_BOX_X_START_S0,
		VPU_MAFBC_BOUNDING_BOX_X_END_S0,
		VPU_MAFBC_BOUNDING_BOX_Y_START_S0,
		VPU_MAFBC_BOUNDING_BOX_Y_END_S0,
		VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0,
		VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0,
		VPU_MAFBC_OUTPUT_BUF_STRIDE_S0,
		VPU_MAFBC_PREFETCH_CFG_S0,

		VIU_OSD1_PATH_CTRL,
		VPU_MAFBC_IRQ_MASK,
		VPU_MAFBC_SURFACE_CFG,
		VPU_MAFBC_COMMAND,
		VPU_MAFBC_IRQ_RAW_STATUS,
		VPU_MAFBC_IRQ_CLEAR,

		VIU_OSD1_PATH_CTRL,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
	},
	{
		VIU_OSD2_CTRL_STAT,
		VIU_OSD2_CTRL_STAT2,
		VIU_OSD2_COLOR_ADDR,
		VIU_OSD2_COLOR,
		VIU_OSD2_TCOLOR_AG0,
		VIU_OSD2_TCOLOR_AG1,
		VIU_OSD2_TCOLOR_AG2,
		VIU_OSD2_TCOLOR_AG3,
		VIU_OSD2_BLK0_CFG_W0,
		VIU_OSD2_BLK0_CFG_W1,
		VIU_OSD2_BLK0_CFG_W2,
		VIU_OSD2_BLK0_CFG_W3,
		VIU_OSD2_BLK0_CFG_W4,
		VIU_OSD2_BLK1_CFG_W4,
		VIU_OSD2_BLK2_CFG_W4,
		VIU_OSD2_FIFO_CTRL_STAT,
		VIU_OSD2_TEST_RDDATA,
		VIU_OSD2_PROT_CTRL,
		VIU_OSD2_MALI_UNPACK_CTRL,
		VIU_OSD2_DIMM_CTRL,
		VPP_WRAP_OSD2_MATRIX_EN_CTRL,

		T7_OSD2_SCALE_COEF_IDX,
		T7_OSD2_SCALE_COEF,
		T7_OSD2_VSC_PHASE_STEP,
		T7_OSD2_VSC_INI_PHASE,
		T7_OSD2_VSC_CTRL0,
		T7_OSD2_HSC_PHASE_STEP,
		T7_OSD2_HSC_INI_PHASE,
		T7_OSD2_HSC_CTRL0,
		OSD_REG_UNSUPPORT,
		T7_OSD2_SC_DUMMY_DATA,
		T7_OSD2_SC_CTRL0,
		T7_OSD2_SCI_WH_M1,
		T7_OSD2_SCO_H_START_END,
		T7_OSD2_SCO_V_START_END,
		OSD2_DB_FLT_CTRL,
		VPU_MAFBC_HEADER_BUF_ADDR_LOW_S1,
		VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S1,
		VPU_MAFBC_FORMAT_SPECIFIER_S1,
		VPU_MAFBC_BUFFER_WIDTH_S1,
		VPU_MAFBC_BUFFER_HEIGHT_S1,
		VPU_MAFBC_BOUNDING_BOX_X_START_S1,
		VPU_MAFBC_BOUNDING_BOX_X_END_S1,
		VPU_MAFBC_BOUNDING_BOX_Y_START_S1,
		VPU_MAFBC_BOUNDING_BOX_Y_END_S1,
		VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S1,
		VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S1,
		VPU_MAFBC_OUTPUT_BUF_STRIDE_S1,
		VPU_MAFBC_PREFETCH_CFG_S1,

		VIU_OSD2_PATH_CTRL,
		VPU_MAFBC_IRQ_MASK,
		VPU_MAFBC_SURFACE_CFG,
		VPU_MAFBC_COMMAND,
		VPU_MAFBC_IRQ_RAW_STATUS,
		VPU_MAFBC_IRQ_CLEAR,

		VIU_OSD2_PATH_CTRL,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
	},
	{
		VIU_OSD3_CTRL_STAT,
		VIU_OSD3_CTRL_STAT2,
		VIU_OSD3_COLOR_ADDR,
		VIU_OSD3_COLOR,
		VIU_OSD3_TCOLOR_AG0,
		VIU_OSD3_TCOLOR_AG1,
		VIU_OSD3_TCOLOR_AG2,
		VIU_OSD3_TCOLOR_AG3,
		VIU_OSD3_BLK0_CFG_W0,
		VIU_OSD3_BLK0_CFG_W1,
		VIU_OSD3_BLK0_CFG_W2,
		VIU_OSD3_BLK0_CFG_W3,
		VIU_OSD3_BLK0_CFG_W4,
		VIU_OSD3_BLK1_CFG_W4,
		VIU_OSD3_BLK2_CFG_W4,
		VIU_OSD3_FIFO_CTRL_STAT,
		VIU_OSD3_TEST_RDDATA,
		VIU_OSD3_PROT_CTRL,
		VIU_OSD3_MALI_UNPACK_CTRL,
		VIU_OSD3_DIMM_CTRL,
		VPP_WRAP_OSD3_MATRIX_EN_CTRL,

		T7_OSD34_SCALE_COEF_IDX,
		T7_OSD34_SCALE_COEF,
		T7_OSD34_VSC_PHASE_STEP,
		T7_OSD34_VSC_INI_PHASE,
		T7_OSD34_VSC_CTRL0,
		T7_OSD34_HSC_PHASE_STEP,
		T7_OSD34_HSC_INI_PHASE,
		T7_OSD34_HSC_CTRL0,
		OSD_REG_UNSUPPORT,
		T7_OSD34_SC_DUMMY_DATA,
		T7_OSD34_SC_CTRL0,
		T7_OSD34_SCI_WH_M1,
		T7_OSD34_SCO_H_START_END,
		T7_OSD34_SCO_V_START_END,
		OSD34_DB_FLT_CTRL,
		VPU_MAFBC1_HEADER_BUF_ADDR_LOW_S2,
		VPU_MAFBC1_HEADER_BUF_ADDR_HIGH_S2,
		VPU_MAFBC1_FORMAT_SPECIFIER_S2,
		VPU_MAFBC1_BUFFER_WIDTH_S2,
		VPU_MAFBC1_BUFFER_HEIGHT_S2,
		VPU_MAFBC1_BOUNDING_BOX_X_START_S2,
		VPU_MAFBC1_BOUNDING_BOX_X_END_S2,
		VPU_MAFBC1_BOUNDING_BOX_Y_START_S2,
		VPU_MAFBC1_BOUNDING_BOX_Y_END_S2,
		VPU_MAFBC1_OUTPUT_BUF_ADDR_LOW_S2,
		VPU_MAFBC1_OUTPUT_BUF_ADDR_HIGH_S2,
		VPU_MAFBC1_OUTPUT_BUF_STRIDE_S2,
		VPU_MAFBC1_PREFETCH_CFG_S2,

		VIU_OSD3_PATH_CTRL,
		VPU_MAFBC1_IRQ_MASK,
		VPU_MAFBC1_SURFACE_CFG,
		VPU_MAFBC1_COMMAND,
		VPU_MAFBC1_IRQ_RAW_STATUS,
		VPU_MAFBC1_IRQ_CLEAR,

		VIU_OSD3_PATH_CTRL,
		OSD_REG_UNSUPPORT,
		OSD_REG_UNSUPPORT,
	},
};

/* S5:OSD1 + OSD3 */
struct hw_osd_reg_s hw_osd_reg_array_s5[HW_OSD_COUNT] = {
	{
		S5_VIU_OSD1_CTRL_STAT,
		S5_VIU_OSD1_CTRL_STAT2,
		S5_VIU_OSD1_COLOR_ADDR,
		S5_VIU_OSD1_COLOR,
		S5_VIU_OSD1_TCOLOR_AG0,
		S5_VIU_OSD1_TCOLOR_AG1,
		S5_VIU_OSD1_TCOLOR_AG2,
		S5_VIU_OSD1_TCOLOR_AG3,
		S5_VIU_OSD1_BLK0_CFG_W0,
		S5_VIU_OSD1_BLK0_CFG_W1,
		S5_VIU_OSD1_BLK0_CFG_W2,
		S5_VIU_OSD1_BLK0_CFG_W3,
		S5_VIU_OSD1_BLK0_CFG_W4,
		S5_VIU_OSD1_BLK1_CFG_W4,
		S5_VIU_OSD1_BLK2_CFG_W4,
		S5_VIU_OSD1_FIFO_CTRL_STAT,
		S5_VIU_OSD1_TEST_RDDATA,
		S5_VIU_OSD1_PROT_CTRL,
		S5_VIU_OSD1_MALI_UNPACK_CTRL,
		S5_VIU_OSD1_DIMM_CTRL,
		OSD_REG_UNSUPPORT, /* VPP_WRAP_OSD1_MATRIX_EN_CTRL */

		OSD1_PROC_SCALE_COEF_IDX,
		OSD1_PROC_SCALE_COEF,
		OSD1_PROC_VSC_PHASE_STEP,
		OSD1_PROC_VSC_INI_PHASE,
		OSD1_PROC_VSC_CTRL0,
		OSD1_PROC_HSC_PHASE_STEP,
		OSD1_PROC_HSC_INI_PHASE,
		OSD1_PROC_HSC_CTRL0,
		OSD1_PROC_HSC_INI_PAT_CTRL,
		OSD1_PROC_SC_DUMMY_DATA,
		OSD1_PROC_SC_CTRL0,
		OSD1_PROC_SCI_WH_M1,
		OSD1_PROC_SCO_H_START_END,
		OSD1_PROC_SCO_V_START_END,
		OSD1_PROC_DB_FLT_CTRL,
		VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0,
		VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0,
		VPU_MAFBC_FORMAT_SPECIFIER_S0,
		VPU_MAFBC_BUFFER_WIDTH_S0,
		VPU_MAFBC_BUFFER_HEIGHT_S0,
		VPU_MAFBC_BOUNDING_BOX_X_START_S0,
		VPU_MAFBC_BOUNDING_BOX_X_END_S0,
		VPU_MAFBC_BOUNDING_BOX_Y_START_S0,
		VPU_MAFBC_BOUNDING_BOX_Y_END_S0,
		VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0,
		VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0,
		VPU_MAFBC_OUTPUT_BUF_STRIDE_S0,
		VPU_MAFBC_PREFETCH_CFG_S0,

		VPP_INTF_OSD1_CTRL, /* MALI_AFBCD_TOP_CTRL */
		VPU_MAFBC_IRQ_MASK,
		VPU_MAFBC_SURFACE_CFG,
		VPU_MAFBC_COMMAND,
		VPU_MAFBC_IRQ_RAW_STATUS,
		VPU_MAFBC_IRQ_CLEAR,

		OSD_REG_UNSUPPORT, /* VPP_OSD1_SCALE_CTRL */
		OSD1_PROC_IN_SIZE,
		OSD1_PROC_OUT_SIZE,
	},
	{
		S5_VIU_OSD3_CTRL_STAT,
		S5_VIU_OSD3_CTRL_STAT2,
		S5_VIU_OSD3_COLOR_ADDR,
		S5_VIU_OSD3_COLOR,
		S5_VIU_OSD3_TCOLOR_AG0,
		S5_VIU_OSD3_TCOLOR_AG1,
		S5_VIU_OSD3_TCOLOR_AG2,
		S5_VIU_OSD3_TCOLOR_AG3,
		S5_VIU_OSD3_BLK0_CFG_W0,
		S5_VIU_OSD3_BLK0_CFG_W1,
		S5_VIU_OSD3_BLK0_CFG_W2,
		S5_VIU_OSD3_BLK0_CFG_W3,
		S5_VIU_OSD3_BLK0_CFG_W4,
		S5_VIU_OSD3_BLK1_CFG_W4,
		S5_VIU_OSD3_BLK2_CFG_W4,
		S5_VIU_OSD3_FIFO_CTRL_STAT,
		S5_VIU_OSD3_TEST_RDDATA,
		S5_VIU_OSD3_PROT_CTRL,
		S5_VIU_OSD3_MALI_UNPACK_CTRL,
		S5_VIU_OSD3_DIMM_CTRL,
		OSD_REG_UNSUPPORT, /* VPP_WRAP_OSD3_MATRIX_EN_CTRL */

		OSD3_PROC_SCALE_COEF_IDX,
		OSD3_PROC_SCALE_COEF,
		OSD3_PROC_VSC_PHASE_STEP,
		OSD3_PROC_VSC_INI_PHASE,
		OSD3_PROC_VSC_CTRL0,
		OSD3_PROC_HSC_PHASE_STEP,
		OSD3_PROC_HSC_INI_PHASE,
		OSD3_PROC_HSC_CTRL0,
		OSD3_PROC_HSC_INI_PAT_CTRL,
		OSD3_PROC_SC_DUMMY_DATA,
		OSD3_PROC_SC_CTRL0,
		OSD3_PROC_SCI_WH_M1,
		OSD3_PROC_SCO_H_START_END,
		OSD3_PROC_SCO_V_START_END,
		OSD3_PROC_DB_FLT_CTRL,
		VPU_MAFBC1_HEADER_BUF_ADDR_LOW_S1,
		VPU_MAFBC1_HEADER_BUF_ADDR_HIGH_S1,
		VPU_MAFBC1_FORMAT_SPECIFIER_S1,
		VPU_MAFBC1_BUFFER_WIDTH_S1,
		VPU_MAFBC1_BUFFER_HEIGHT_S1,
		VPU_MAFBC1_BOUNDING_BOX_X_START_S1,
		VPU_MAFBC1_BOUNDING_BOX_X_END_S1,
		VPU_MAFBC1_BOUNDING_BOX_Y_START_S1,
		VPU_MAFBC1_BOUNDING_BOX_Y_END_S1,
		VPU_MAFBC1_OUTPUT_BUF_ADDR_LOW_S1,
		VPU_MAFBC1_OUTPUT_BUF_ADDR_HIGH_S1,
		VPU_MAFBC1_OUTPUT_BUF_STRIDE_S1,
		VPU_MAFBC1_PREFETCH_CFG_S1,

		VPP_INTF_OSD3_CTRL, /* MALI_AFBCD1_TOP_CTRL */
		VPU_MAFBC1_IRQ_MASK,
		VPU_MAFBC1_SURFACE_CFG,
		VPU_MAFBC1_COMMAND,
		VPU_MAFBC1_IRQ_RAW_STATUS,
		VPU_MAFBC1_IRQ_CLEAR,

		OSD_REG_UNSUPPORT, /* VPP_OSD3_SCALE_CTRL */
		OSD3_PROC_IN_SIZE,
		OSD3_PROC_OUT_SIZE,
	},
};

struct hw_osd_reg_s hw_osd_reg_array_t3x[HW_OSD_COUNT] = {
	{
		S5_VIU_OSD1_CTRL_STAT,
		S5_VIU_OSD1_CTRL_STAT2,
		S5_VIU_OSD1_COLOR_ADDR,
		S5_VIU_OSD1_COLOR,
		S5_VIU_OSD1_TCOLOR_AG0,
		S5_VIU_OSD1_TCOLOR_AG1,
		S5_VIU_OSD1_TCOLOR_AG2,
		S5_VIU_OSD1_TCOLOR_AG3,
		S5_VIU_OSD1_BLK0_CFG_W0,
		S5_VIU_OSD1_BLK0_CFG_W1,
		S5_VIU_OSD1_BLK0_CFG_W2,
		S5_VIU_OSD1_BLK0_CFG_W3,
		S5_VIU_OSD1_BLK0_CFG_W4,
		S5_VIU_OSD1_BLK1_CFG_W4,
		S5_VIU_OSD1_BLK2_CFG_W4,
		S5_VIU_OSD1_FIFO_CTRL_STAT,
		S5_VIU_OSD1_TEST_RDDATA,
		S5_VIU_OSD1_PROT_CTRL,
		S5_VIU_OSD1_MALI_UNPACK_CTRL,
		S5_VIU_OSD1_DIMM_CTRL,
		OSD_REG_UNSUPPORT, /* VPP_WRAP_OSD1_MATRIX_EN_CTRL */

		OSD1_PROC_SCALE_COEF_IDX,
		OSD1_PROC_SCALE_COEF,
		OSD1_PROC_VSC_PHASE_STEP,
		OSD1_PROC_VSC_INI_PHASE,
		OSD1_PROC_VSC_CTRL0,
		OSD1_PROC_HSC_PHASE_STEP,
		OSD1_PROC_HSC_INI_PHASE,
		OSD1_PROC_HSC_CTRL0,
		OSD1_PROC_HSC_INI_PAT_CTRL,
		OSD1_PROC_SC_DUMMY_DATA,
		OSD1_PROC_SC_CTRL0,
		OSD1_PROC_SCI_WH_M1,
		OSD1_PROC_SCO_H_START_END,
		OSD1_PROC_SCO_V_START_END,
		OSD1_PROC_DB_FLT_CTRL,
		VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0,
		VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0,
		VPU_MAFBC_FORMAT_SPECIFIER_S0,
		VPU_MAFBC_BUFFER_WIDTH_S0,
		VPU_MAFBC_BUFFER_HEIGHT_S0,
		VPU_MAFBC_BOUNDING_BOX_X_START_S0,
		VPU_MAFBC_BOUNDING_BOX_X_END_S0,
		VPU_MAFBC_BOUNDING_BOX_Y_START_S0,
		VPU_MAFBC_BOUNDING_BOX_Y_END_S0,
		VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0,
		VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0,
		VPU_MAFBC_OUTPUT_BUF_STRIDE_S0,
		VPU_MAFBC_PREFETCH_CFG_S0,

		VPP_INTF_OSD1_CTRL, /* MALI_AFBCD_TOP_CTRL */
		VPU_MAFBC_IRQ_MASK,
		VPU_MAFBC_SURFACE_CFG,
		VPU_MAFBC_COMMAND,
		VPU_MAFBC_IRQ_RAW_STATUS,
		VPU_MAFBC_IRQ_CLEAR,

		OSD_REG_UNSUPPORT, /* VPP_OSD1_SCALE_CTRL */
		OSD1_PROC_IN_SIZE,
		OSD1_PROC_OUT_SIZE,
	},
	{
		S5_VIU_OSD2_CTRL_STAT,
		S5_VIU_OSD2_CTRL_STAT2,
		S5_VIU_OSD2_COLOR_ADDR,
		S5_VIU_OSD2_COLOR,
		S5_VIU_OSD2_TCOLOR_AG0,
		S5_VIU_OSD2_TCOLOR_AG1,
		S5_VIU_OSD2_TCOLOR_AG2,
		S5_VIU_OSD2_TCOLOR_AG3,
		S5_VIU_OSD2_BLK0_CFG_W0,
		S5_VIU_OSD2_BLK0_CFG_W1,
		S5_VIU_OSD2_BLK0_CFG_W2,
		S5_VIU_OSD2_BLK0_CFG_W3,
		S5_VIU_OSD2_BLK0_CFG_W4,
		S5_VIU_OSD2_BLK1_CFG_W4,
		S5_VIU_OSD2_BLK2_CFG_W4,
		S5_VIU_OSD2_FIFO_CTRL_STAT,
		S5_VIU_OSD2_TEST_RDDATA,
		S5_VIU_OSD2_PROT_CTRL,
		S5_VIU_OSD2_MALI_UNPACK_CTRL,
		S5_VIU_OSD2_DIMM_CTRL,
		OSD_REG_UNSUPPORT, /* VPP_WRAP_OSD2_MATRIX_EN_CTRL */

		OSD2_PROC_SCALE_COEF_IDX,
		OSD2_PROC_SCALE_COEF,
		OSD2_PROC_VSC_PHASE_STEP,
		OSD2_PROC_VSC_INI_PHASE,
		OSD2_PROC_VSC_CTRL0,
		OSD2_PROC_HSC_PHASE_STEP,
		OSD2_PROC_HSC_INI_PHASE,
		OSD2_PROC_HSC_CTRL0,
		OSD2_PROC_HSC_INI_PAT_CTRL,
		OSD2_PROC_SC_DUMMY_DATA,
		OSD2_PROC_SC_CTRL0,
		OSD2_PROC_SCI_WH_M1,
		OSD2_PROC_SCO_H_START_END,
		OSD2_PROC_SCO_V_START_END,
		OSD2_PROC_DB_FLT_CTRL,
		VPU_MAFBC1_HEADER_BUF_ADDR_LOW_S1,
		VPU_MAFBC1_HEADER_BUF_ADDR_HIGH_S1,
		VPU_MAFBC1_FORMAT_SPECIFIER_S1,
		VPU_MAFBC1_BUFFER_WIDTH_S1,
		VPU_MAFBC1_BUFFER_HEIGHT_S1,
		VPU_MAFBC1_BOUNDING_BOX_X_START_S1,
		VPU_MAFBC1_BOUNDING_BOX_X_END_S1,
		VPU_MAFBC1_BOUNDING_BOX_Y_START_S1,
		VPU_MAFBC1_BOUNDING_BOX_Y_END_S1,
		VPU_MAFBC1_OUTPUT_BUF_ADDR_LOW_S1,
		VPU_MAFBC1_OUTPUT_BUF_ADDR_HIGH_S1,
		VPU_MAFBC1_OUTPUT_BUF_STRIDE_S1,
		VPU_MAFBC1_PREFETCH_CFG_S1,

		VPP_INTF_OSD2_CTRL, /* MALI_AFBCD1_TOP_CTRL */
		VPU_MAFBC1_IRQ_MASK,
		VPU_MAFBC1_SURFACE_CFG,
		VPU_MAFBC1_COMMAND,
		VPU_MAFBC1_IRQ_RAW_STATUS,
		VPU_MAFBC1_IRQ_CLEAR,

		OSD_REG_UNSUPPORT, /* VPP_OSD2_SCALE_CTRL */
		OSD2_PROC_IN_SIZE,
		OSD2_PROC_OUT_SIZE,
	},
	{
		S5_VIU_OSD3_CTRL_STAT,
		S5_VIU_OSD3_CTRL_STAT2,
		S5_VIU_OSD3_COLOR_ADDR,
		S5_VIU_OSD3_COLOR,
		S5_VIU_OSD3_TCOLOR_AG0,
		S5_VIU_OSD3_TCOLOR_AG1,
		S5_VIU_OSD3_TCOLOR_AG2,
		S5_VIU_OSD3_TCOLOR_AG3,
		S5_VIU_OSD3_BLK0_CFG_W0,
		S5_VIU_OSD3_BLK0_CFG_W1,
		S5_VIU_OSD3_BLK0_CFG_W2,
		S5_VIU_OSD3_BLK0_CFG_W3,
		S5_VIU_OSD3_BLK0_CFG_W4,
		S5_VIU_OSD3_BLK1_CFG_W4,
		S5_VIU_OSD3_BLK2_CFG_W4,
		S5_VIU_OSD3_FIFO_CTRL_STAT,
		S5_VIU_OSD3_TEST_RDDATA,
		S5_VIU_OSD3_PROT_CTRL,
		S5_VIU_OSD3_MALI_UNPACK_CTRL,
		S5_VIU_OSD3_DIMM_CTRL,
		OSD_REG_UNSUPPORT, /* VPP_WRAP_OSD3_MATRIX_EN_CTRL */

		OSD3_PROC_SCALE_COEF_IDX,
		OSD3_PROC_SCALE_COEF,
		OSD3_PROC_VSC_PHASE_STEP,
		OSD3_PROC_VSC_INI_PHASE,
		OSD3_PROC_VSC_CTRL0,
		OSD3_PROC_HSC_PHASE_STEP,
		OSD3_PROC_HSC_INI_PHASE,
		OSD3_PROC_HSC_CTRL0,
		OSD3_PROC_HSC_INI_PAT_CTRL,
		OSD3_PROC_SC_DUMMY_DATA,
		OSD3_PROC_SC_CTRL0,
		OSD3_PROC_SCI_WH_M1,
		OSD3_PROC_SCO_H_START_END,
		OSD3_PROC_SCO_V_START_END,
		OSD3_PROC_DB_FLT_CTRL,
		VPU_MAFBC2_HEADER_BUF_ADDR_LOW_S2,
		VPU_MAFBC2_HEADER_BUF_ADDR_HIGH_S2,
		VPU_MAFBC2_FORMAT_SPECIFIER_S2,
		VPU_MAFBC2_BUFFER_WIDTH_S2,
		VPU_MAFBC2_BUFFER_HEIGHT_S2,
		VPU_MAFBC2_BOUNDING_BOX_X_START_S2,
		VPU_MAFBC2_BOUNDING_BOX_X_END_S2,
		VPU_MAFBC2_BOUNDING_BOX_Y_START_S2,
		VPU_MAFBC2_BOUNDING_BOX_Y_END_S2,
		VPU_MAFBC2_OUTPUT_BUF_ADDR_LOW_S2,
		VPU_MAFBC2_OUTPUT_BUF_ADDR_HIGH_S2,
		VPU_MAFBC2_OUTPUT_BUF_STRIDE_S2,
		VPU_MAFBC2_PREFETCH_CFG_S2,

		VPP_INTF_OSD3_CTRL, /* MALI_AFBCD1_TOP_CTRL */
		VPU_MAFBC2_IRQ_MASK,
		VPU_MAFBC2_SURFACE_CFG,
		VPU_MAFBC2_COMMAND,
		VPU_MAFBC2_IRQ_RAW_STATUS,
		VPU_MAFBC2_IRQ_CLEAR,

		OSD_REG_UNSUPPORT, /* VPP_OSD3_SCALE_CTRL */
		OSD3_PROC_IN_SIZE,
		OSD3_PROC_OUT_SIZE,
	},
};

struct hw_osd_blend_reg_s hw_osd_blend_reg_legacy = {
	/* osd_blend */
	VIU_OSD_BLEND_CTRL,
	VIU_OSD_BLEND_CTRL1,
	VIU_OSD_BLEND_DIN0_SCOPE_H,
	VIU_OSD_BLEND_DIN0_SCOPE_V,
	VIU_OSD_BLEND_DIN1_SCOPE_H,
	VIU_OSD_BLEND_DIN1_SCOPE_V,
	VIU_OSD_BLEND_DIN2_SCOPE_H,
	VIU_OSD_BLEND_DIN2_SCOPE_V,
	VIU_OSD_BLEND_DIN3_SCOPE_H,
	VIU_OSD_BLEND_DIN3_SCOPE_V,
	VIU_OSD_BLEND_DUMMY_DATA0,
	VIU_OSD_BLEND_DUMMY_ALPHA,
	VIU_OSD_BLEND_BLEND0_SIZE,
	VIU_OSD_BLEND_BLEND1_SIZE,
	OSD_REG_UNSUPPORT,
	OSD_REG_UNSUPPORT,
	/* vpp_post_blend related */
	VPP_OSD1_BLD_H_SCOPE,
	VPP_OSD1_BLD_V_SCOPE,
	VPP_OSD2_BLD_H_SCOPE,
	VPP_OSD2_BLD_V_SCOPE,
	VD1_BLEND_SRC_CTRL,
	VD2_BLEND_SRC_CTRL,
	VD3_BLEND_SRC_CTRL,
	OSD1_BLEND_SRC_CTRL,
	OSD2_BLEND_SRC_CTRL
};

struct hw_osd_blend_reg_s hw_osd_blend_reg_s5 = {
	/* osd_blend */
	S5_VIU_OSD_BLEND_CTRL,
	S5_VIU_OSD_BLEND_CTRL1,
	S5_VIU_OSD_BLEND_DIN0_SCOPE_H,
	S5_VIU_OSD_BLEND_DIN0_SCOPE_V,
	S5_VIU_OSD_BLEND_DIN1_SCOPE_H,
	S5_VIU_OSD_BLEND_DIN1_SCOPE_V,
	S5_VIU_OSD_BLEND_DIN2_SCOPE_H,
	S5_VIU_OSD_BLEND_DIN2_SCOPE_V,
	S5_VIU_OSD_BLEND_DIN3_SCOPE_H,
	S5_VIU_OSD_BLEND_DIN3_SCOPE_V,
	S5_VIU_OSD_BLEND_DUMMY_DATA0,
	S5_VIU_OSD_BLEND_DUMMY_ALPHA,
	S5_VIU_OSD_BLEND_BLEND0_SIZE,
	S5_VIU_OSD_BLEND_BLEND1_SIZE,
	OSD_BLEND_DOUT0_SIZE,
	OSD_BLEND_DOUT1_SIZE,
	/* vpp_post_blend related */
	S5_VPP_OSD1_BLD_H_SCOPE,
	S5_VPP_OSD1_BLD_V_SCOPE,
	S5_VPP_OSD2_BLD_H_SCOPE,
	S5_VPP_OSD2_BLD_V_SCOPE,
	S5_VD1_BLEND_SRC_CTRL,
	S5_VD2_BLEND_SRC_CTRL,
	S5_VD3_BLEND_SRC_CTRL,
	S5_OSD1_BLEND_SRC_CTRL,
	S5_OSD2_BLEND_SRC_CTRL
};

struct hw_osd_slice2ppc_reg_s hw_osd_slice2ppc_reg =  {
	OSD_2SLICE2PPC_IN_SIZE,
	OSD_2SLICE2PPC_MODE,
	OSD_SYS_HWIN0_CUT,
	OSD_SYS_HWIN1_CUT,
	OSD_SYS_PAD_CTRL,
	OSD_SYS_PAD_DUMMY_DATA0,
	OSD_SYS_PAD_DUMMY_DATA1,
	OSD_SYS_PAD_H_SIZE,
	OSD_SYS_PAD_V_SIZE,
	OSD_SYS_2SLICE_HWIN_CUT
};

struct hw_osd_reg_s hw_osd_reg_array_c3[HW_OSD_COUNT] = {
	{
		VOUT_OSD1_CTRL_STAT,
		VOUT_OSD1_CTRL_STAT2,
		VOUT_OSD1_COLOR_ADDR,
		VOUT_OSD1_COLOR,
		VOUT_OSD1_TCOLOR_AG0,
		VOUT_OSD1_TCOLOR_AG1,
		VOUT_OSD1_TCOLOR_AG2,
		VOUT_OSD1_TCOLOR_AG3,
		VOUT_OSD1_BLK0_CFG_W0,
		VOUT_OSD1_BLK0_CFG_W1,
		VOUT_OSD1_BLK0_CFG_W2,
		VOUT_OSD1_BLK0_CFG_W3,
		VOUT_OSD1_BLK0_CFG_W4,
		VOUT_OSD1_BLK1_CFG_W4,
		VOUT_OSD1_BLK2_CFG_W4,
		VOUT_OSD1_FIFO_CTRL_STAT,
		VOUT_OSD1_TEST_RDDATA,
		VOUT_OSD1_PROT_CTRL,
		VOUT_OSD1_MALI_UNPACK_CTRL,
		VOUT_OSD1_DIMM_CTRL,
		VOUT_OSD1_CSC_EN_CTRL,

		VOUT_OSD1_SCALE_COEF_IDX,
		VOUT_OSD1_SCALE_COEF,
		VOUT_OSD1_VSC_PHASE_STEP,
		VOUT_OSD1_VSC_INI_PHASE,
		VOUT_OSD1_VSC_CTRL0,
		VOUT_OSD1_HSC_PHASE_STEP,
		VOUT_OSD1_HSC_INI_PHASE,
		VOUT_OSD1_HSC_CTRL0,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_SC_DUMMY_DATA,
		VOUT_OSD1_SC_CTRL0,
		VOUT_OSD1_SCI_WH_M1,
		VOUT_OSD1_SCO_H_START_END,
		VOUT_OSD1_SCO_V_START_END,
		VOUT_OSD1_DB_FLT_CTRL,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,

		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,

		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
		VOUT_OSD1_UNSUPPORT,
	},
};

#define VIU2_OSD_REG_NUM    13
static u32 viu2_osd_table[VIU2_OSD_REG_NUM];
static struct viu2_osd_reg_item viu2_osd_reg_table[VIU2_OSD_REG_NUM] = {
		{VIU2_OSD1_CTRL_STAT, 0, 0xc01ff9f7},
		{VIU2_OSD1_CTRL_STAT2, 0x0, 0x00007fff},
		{VIU2_OSD1_BLK0_CFG_W0, 0x0, 0x70ffff7f},
		{VIU2_OSD1_BLK0_CFG_W1, 0x0, 0x1fff1fff},
		{VIU2_OSD1_BLK0_CFG_W2, 0x0, 0x1fff1fff},
		{VIU2_OSD1_BLK0_CFG_W3, 0x0, 0x0fff0fff},
		{VIU2_OSD1_BLK0_CFG_W4, 0x0, 0x0fff0fff},
		{VIU2_OSD1_BLK1_CFG_W4, 0x0, 0xffffffff},
		{VIU2_OSD1_BLK2_CFG_W4, 0x0, 0xffffffff},
		{VIU2_OSD1_FIFO_CTRL_STAT, 0x0, 0xffc7ffff},
		{VIU2_OSD1_PROT_CTRL, 0x0, 0xffff0000},
		{VIU2_OSD1_MALI_UNPACK_CTRL, 0x0, 0x9f01ffff},
		{VIU2_OSD1_DIMM_CTRL, 0x0, 0x7fffffff},
};

static struct vpu_venc_regs venc_regs[3];
static struct vpu_venc_regs venc_regs_t7[3] = {
	{
		VPU_VENCI_STAT,
		VPU_VENCP_STAT,
		VPU_VENCL_STAT,
		ENCI_VFIFO2VD_LINE_TOP_START,
		ENCP_VIDEO_VAVON_BLINE,
		ENCL_VIDEO_VAVON_BLINE,
	},
	{
		VPU_VENCI_STAT + 0x600,
		VPU_VENCP_STAT + 0x600,
		VPU_VENCL_STAT + 0x600,
		ENCI_VFIFO2VD_LINE_TOP_START + 0x600,
		ENCP_VIDEO_VAVON_BLINE + 0x600,
		ENCL_VIDEO_VAVON_BLINE + 0x600,
	},
	{
		VPU_VENCI_STAT + 0x800,
		VPU_VENCP_STAT + 0x800,
		VPU_VENCL_STAT + 0x800,
		ENCI_VFIFO2VD_LINE_TOP_START + 0x800,
		ENCP_VIDEO_VAVON_BLINE + 0x800,
		ENCL_VIDEO_VAVON_BLINE + 0x800,
	}
};

static struct vpu_venc_regs venc_regs_t3x[3] = {
	{
		VPU_VENCI_STAT,
		VPU_VENCP_STAT,
		VPU_VENCL_STAT,
		ENCL_VIDEO_VAVON_LN_RNG,
		ENCL_VIDEO_VAVON_LN_RNG,
		ENCL_VIDEO_VAVON_LN_RNG,
	},
	{
		VPU_VENCI_STAT + 0x100,
		VPU_VENCP_STAT + 0x100,
		VPU_VENCL_STAT + 0x100,
		ENCL_VIDEO_VAVON_LN_RNG + 0x100,
		ENCL_VIDEO_VAVON_LN_RNG + 0x100,
		ENCL_VIDEO_VAVON_LN_RNG + 0x100,
	},
	{
		VPU_VENCI_STAT + 0x100,
		VPU_VENCP_STAT + 0x100,
		VPU_VENCL_STAT + 0x100,
		ENCL_VIDEO_VAVON_LN_RNG + 0x100,
		ENCL_VIDEO_VAVON_LN_RNG + 0x100,
		ENCL_VIDEO_VAVON_LN_RNG + 0x100,
	}
};

struct affinity_info_s {
	struct completion affinity_task_com;
	struct cpumask cpu_mask;
	int run_affinity_task;
	unsigned long affinity_mask;
};

static int osd_setting_blending_scope(u32 index);
static int vpp_blend_setting_default(u32 index);

#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
static struct affinity_info_s affinity_info;
/* sync fence relative variable. */
static int timeline_created[VIU_COUNT];
static void *osd_timeline[VIU_COUNT];
static u32 cur_streamline_val[VIU_COUNT];
/* thread control part */
struct kthread_worker buffer_toggle_worker[VIU_COUNT];
struct task_struct *buffer_toggle_thread[VIU_COUNT];
struct kthread_work buffer_toggle_work[VIU_COUNT];
struct list_head post_fence_list[VIU_COUNT];
struct mutex post_fence_list_lock[VIU_COUNT];/* fence mutex */
struct osd_layers_fence_map_s map_layers[VIU_COUNT];
struct file *displayed_bufs[HW_OSD_COUNT];
static void osd_pan_display_single_fence
	(struct osd_fence_map_s *fence_map);
static void osd_pan_display_layers_fence
	(struct osd_layers_fence_map_s *fence_map);
static void osd_pan_display_single_fence_viu2
	(struct osd_fence_map_s *fence_map);
static void osd_pan_display_layers_fence_viu2
	(struct osd_layers_fence_map_s *fence_map);

static void *osd_timeline_create(u32 output_index)
{
	char tlname[32] = {};

	sprintf(tlname, "osd_timeline_%d", output_index);
	if (!osd_timeline[output_index]) {
		if (osd_hw.hwc_enable[output_index])
			/* present fence */
			cur_streamline_val[output_index] = 0;
		else
			cur_streamline_val[output_index] = 1;
		osd_timeline[output_index] = aml_sync_create_timeline(tlname);
		osd_tprintk("osd timeline create\n");
	}

	return osd_timeline[output_index];
}

static int osd_timeline_create_fence(u32 output_index)
{
	int out_fence_fd = -1;
	u32 pt_val = 0;

	pt_val = cur_streamline_val[output_index] + 1;
	out_fence_fd = aml_sync_create_fence
		(osd_timeline[output_index], pt_val);
	osd_tprintk("osd created out pt:%d, fence_fd:%d\n",
		    pt_val, out_fence_fd);

	if (out_fence_fd >= 0)
		cur_streamline_val[output_index]++;
	else
		pr_info("create fence returned %d", out_fence_fd);
	return out_fence_fd;
}

static void  osd_timeline_increase(u32 output_index, u32 inc_cnt)
{
	aml_sync_inc_timeline(osd_timeline[output_index], inc_cnt);
	osd_tprintk("osd out timeline %d inc\n", output_index);
}

static struct dma_fence *osd_get_fenceobj(int fencefd)
{
	struct dma_fence *syncobj = NULL;

	if (fencefd < 0)
		return NULL;

	syncobj = aml_sync_get_fence(fencefd);
	osd_tprintk("osd get in fence%p, fd:%d\n", syncobj, fencefd);

	return syncobj;
}

static int osd_wait_fenceobj(struct dma_fence *fence, long timeout)
{
	osd_tprintk("osd wait in fence%p\n", fence);
	return aml_sync_wait_fence(fence, timeout);
}

static void osd_put_fenceobj(struct dma_fence *fence)
{
	osd_tprintk("osd put fence\n");
	aml_sync_put_fence(fence);
}

#endif

static int pxp_mode;
s64 timestamp[VIU_COUNT];

static unsigned int osd_h_filter_mode = 1;
#define BYTE_32_ALIGNED(x)	(((x) + 31) & ~31)
#define BYTE_16_ALIGNED(x)	(((x) + 15) & ~15)
#define BYTE_8_ALIGNED(x)	(((x) + 7) & ~7)
module_param(osd_h_filter_mode, uint, 0664);
MODULE_PARM_DESC(osd_h_filter_mode, "osd_h_filter_mode");

static unsigned int osd_v_filter_mode = 1;
module_param(osd_v_filter_mode, uint, 0664);
MODULE_PARM_DESC(osd_v_filter_mode, "osd_v_filter_mode");

static unsigned int osd_auto_adjust_filter = 1;
module_param(osd_auto_adjust_filter, uint, 0664);
MODULE_PARM_DESC(osd_auto_adjust_filter, "osd_auto_adjust_filter");

static int osd_logo_index = 1;
module_param(osd_logo_index, int, 0664);
MODULE_PARM_DESC(osd_logo_index, "osd_logo_index");

module_param(osd_afbc_dec_enable, int, 0664);
MODULE_PARM_DESC(osd_afbc_dec_enable, "osd_afbc_dec_enable");

static u32 osd_vpp_misc;
static u32 osd_vpp_misc_mask = OSD_RELATIVE_BITS;
static u32 osd_vpp1_bld_ctrl;
static u32 osd_vpp1_bld_ctrl_mask = 0x30;
static u32 osd_vpp2_bld_ctrl;
static u32 osd_vpp2_bld_ctrl_mask = 0x30;
/* indicates whether vpp1&vpp2 has been notified or not */
static u32 osd_vpp_bld_ctrl_update_mask = 0x80000000;
static u32 osd_mali_afbcd_top_ctrl;
static u32 osd_mali_afbcd_top_ctrl_mask = 0x00ffbfff;
static u32 osd_mali_afbcd1_top_ctrl;
static u32 osd_mali_afbcd1_top_ctrl_mask = 0x00f7ffff;

module_param(osd_vpp_misc, uint, 0444);
MODULE_PARM_DESC(osd_vpp_misc, "osd_vpp_misc");

static unsigned int rdarb_reqen_slv = 0xffff7f;
module_param(rdarb_reqen_slv, uint, 0664);
MODULE_PARM_DESC(rdarb_reqen_slv, "rdarb_reqen_slv");

static unsigned int supsend_delay;
module_param(supsend_delay, uint, 0664);
MODULE_PARM_DESC(supsend_delay, "supsend_delay");

int enable_vd_zorder = 1;
MODULE_PARM_DESC(enable_vd_zorder, "\n enable_vd_zorder\n");
module_param(enable_vd_zorder, uint, 0664);
static int vsync_enter_line_max;
static int vsync_exit_line_max;
static int line_threshold = 5;
static int line_threshold_2 = 90;
static int vsync_threshold = 10;
static int vsync_adjust_hit;
static int cur_begin_line[VIU_COUNT];
module_param_named(osd_vsync_enter_line_max, vsync_enter_line_max, uint, 0664);

module_param_named(osd_vsync_exit_line_max, vsync_exit_line_max, uint, 0664);

MODULE_PARM_DESC(line_threshold, "\n line_threshold\n");
module_param(line_threshold, uint, 0664);
MODULE_PARM_DESC(line_threshold_2, "\n line_threshold_2\n");
module_param(line_threshold_2, uint, 0664);
MODULE_PARM_DESC(vsync_threshold, "\n vsync_threshold\n");
module_param(vsync_threshold, uint, 0664);
MODULE_PARM_DESC(vsync_adjust_hit, "\n vsync_adjust_hit\n");
module_param(vsync_adjust_hit, uint, 0664);

static unsigned int osd_filter_coefs_bicubic_sharp[] = {
	0x01fa008c, 0x01fa0100, 0xff7f0200, 0xfe7f0300,
	0xfd7e0500, 0xfc7e0600, 0xfb7d0800, 0xfb7c0900,
	0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff,
	0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe,
	0xf76f1dfd, 0xf76d1ffd, 0xf76b21fd, 0xf76824fd,
	0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb,
	0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa,
	0xf8523cfa, 0xf8503ff9, 0xf84d42f9, 0xf84a45f9,
	0xf84848f8
};

static unsigned int osd_filter_coefs_bicubic[] = { /* bicubic	coef0 */
	0x00800000, 0x007f0100, 0xff7f0200, 0xfe7f0300, 0xfd7e0500, 0xfc7e0600,
	0xfb7d0800, 0xfb7c0900, 0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff,
	0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe, 0xf76f1dfd, 0xf76d1ffd,
	0xf76b21fd, 0xf76824fd, 0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb,
	0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa, 0xf8523cfa, 0xf8503ff9,
	0xf84d42f9, 0xf84a45f9, 0xf84848f8
};

static unsigned int osd_filter_coefs_bilinear[] = { /* 2 point bilinear	coef1 */
	0x00800000, 0x007e0200, 0x007c0400, 0x007a0600, 0x00780800, 0x00760a00,
	0x00740c00, 0x00720e00, 0x00701000, 0x006e1200, 0x006c1400, 0x006a1600,
	0x00681800, 0x00661a00, 0x00641c00, 0x00621e00, 0x00602000, 0x005e2200,
	0x005c2400, 0x005a2600, 0x00582800, 0x00562a00, 0x00542c00, 0x00522e00,
	0x00503000, 0x004e3200, 0x004c3400, 0x004a3600, 0x00483800, 0x00463a00,
	0x00443c00, 0x00423e00, 0x00404000
};

static unsigned int osd_filter_coefs_2point_bilinear[] = {
	/* 2 point bilinear, bank_length == 2	coef2 */
	0x80000000, 0x7e020000, 0x7c040000, 0x7a060000, 0x78080000, 0x760a0000,
	0x740c0000, 0x720e0000, 0x70100000, 0x6e120000, 0x6c140000, 0x6a160000,
	0x68180000, 0x661a0000, 0x641c0000, 0x621e0000, 0x60200000, 0x5e220000,
	0x5c240000, 0x5a260000, 0x58280000, 0x562a0000, 0x542c0000, 0x522e0000,
	0x50300000, 0x4e320000, 0x4c340000, 0x4a360000, 0x48380000, 0x463a0000,
	0x443c0000, 0x423e0000, 0x40400000
};

/* filt_triangle, point_num =3, filt_len =2.6, group_num = 64 */
static unsigned int osd_filter_coefs_3point_triangle_sharp[] = {
	0x40400000, 0x3e420000, 0x3d430000, 0x3b450000,
	0x3a460000, 0x38480000, 0x37490000, 0x354b0000,
	0x344c0000, 0x324e0000, 0x314f0000, 0x2f510000,
	0x2e520000, 0x2c540000, 0x2b550000, 0x29570000,
	0x28580000, 0x265a0000, 0x245c0000, 0x235d0000,
	0x215f0000, 0x20600000, 0x1e620000, 0x1d620100,
	0x1b620300, 0x19630400, 0x17630600, 0x15640700,
	0x14640800, 0x12640a00, 0x11640b00, 0x0f650c00,
	0x0d660d00
};

static unsigned int osd_filter_coefs_3point_triangle[] = {
	0x40400000, 0x3f400100, 0x3d410200, 0x3c410300,
	0x3a420400, 0x39420500, 0x37430600, 0x36430700,
	0x35430800, 0x33450800, 0x32450900, 0x31450a00,
	0x30450b00, 0x2e460c00, 0x2d460d00, 0x2c470d00,
	0x2b470e00, 0x29480f00, 0x28481000, 0x27481100,
	0x26491100, 0x25491200, 0x24491300, 0x234a1300,
	0x224a1400, 0x214a1500, 0x204a1600, 0x1f4b1600,
	0x1e4b1700, 0x1d4b1800, 0x1c4c1800, 0x1b4c1900,
	0x1a4c1a00
};

static unsigned int osd_filter_coefs_4point_triangle[] = {
	0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101,
	0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303,
	0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505,
	0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707,
	0x18382808, 0x18382808, 0x17372909, 0x17372909,
	0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b,
	0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d,
	0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f,
	0x10303010
};

/* 4th order (cubic) b-spline */
/* filt_cubic point_num =4, filt_len =4, group_num = 64 */
static unsigned int vpp_filter_coefs_4point_bspline[] = {
	0x15561500, 0x14561600, 0x13561700, 0x12561800,
	0x11551a00, 0x11541b00, 0x10541c00, 0x0f541d00,
	0x0f531e00, 0x0e531f00, 0x0d522100, 0x0c522200,
	0x0b522300, 0x0b512400, 0x0a502600, 0x0a4f2700,
	0x094e2900, 0x084e2a00, 0x084d2b00, 0x074c2c01,
	0x074b2d01, 0x064a2f01, 0x06493001, 0x05483201,
	0x05473301, 0x05463401, 0x04453601, 0x04433702,
	0x04423802, 0x03413a02, 0x03403b02, 0x033f3c02,
	0x033d3d03
};

/* filt_quadratic, point_num =3, filt_len =3, group_num = 64 */
static unsigned int osd_filter_coefs_3point_bspline[] = {
	0x40400000, 0x3e420000, 0x3c440000, 0x3a460000,
	0x38480000, 0x364a0000, 0x344b0100, 0x334c0100,
	0x314e0100, 0x304f0100, 0x2e500200, 0x2c520200,
	0x2a540200, 0x29540300, 0x27560300, 0x26570300,
	0x24580400, 0x23590400, 0x215a0500, 0x205b0500,
	0x1e5c0600, 0x1d5c0700, 0x1c5d0700, 0x1a5e0800,
	0x195e0900, 0x185e0a00, 0x175f0a00, 0x15600b00,
	0x14600c00, 0x13600d00, 0x12600e00, 0x11600f00,
	0x10601000
};

static unsigned int osd_filter_coefs_repeat[] = { /* repeat coef0 */
	0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000,
	0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000,
	0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000,
	0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000,
	0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000,
	0x00800000, 0x00800000, 0x00800000
};

static unsigned int *filter_table[] = {
	osd_filter_coefs_bicubic_sharp,
	osd_filter_coefs_bicubic,
	osd_filter_coefs_bilinear,
	osd_filter_coefs_2point_bilinear,
	osd_filter_coefs_3point_triangle_sharp,
	osd_filter_coefs_3point_triangle,
	osd_filter_coefs_4point_triangle,
	vpp_filter_coefs_4point_bspline,
	osd_filter_coefs_3point_bspline,
	osd_filter_coefs_repeat
};

#ifdef NEW_PPS_PHASE
#define OSD_ZOOM_BITS 20
#define OSD_PHASE_BITS 16

enum osd_f2v_vphase_type_e {
	OSD_F2V_IT2IT = 0,
	OSD_F2V_IB2IB,
	OSD_F2V_IT2IB,
	OSD_F2V_IB2IT,
	OSD_F2V_P2IT,
	OSD_F2V_P2IB,
	OSD_F2V_IT2P,
	OSD_F2V_IB2P,
	OSD_F2V_P2P,
	OSD_F2V_TYPE_MAX
};

struct osd_f2v_vphase_s {
	u8 rcv_num;
	u8 rpt_num;
	u16 phase;
};

#define COEFF_NORM(a) ((int)((((a) * 2048.0) + 1) / 2))
#define COEFF_NORM_NE(a) ((int)((((a) * 2048.0) - 1) / 2))
#define MATRIX_5x3_COEF_SIZE 24

static int RGB709_to_YUV709l_coeff[MATRIX_5x3_COEF_SIZE] = {
	0, 0, 0, /* pre offset */
	COEFF_NORM(0.181873), COEFF_NORM(0.611831), COEFF_NORM(0.061765),
	COEFF_NORM_NE(-0.100251), COEFF_NORM_NE(-0.337249), COEFF_NORM(0.437500),
	COEFF_NORM(0.437500), COEFF_NORM_NE(-0.397384), COEFF_NORM_NE(-0.040116),
	0, 0, 0, /* 10'/11'/12' */
	0, 0, 0, /* 20'/21'/22' */
	64, 512, 512, /* offset */
	0, 0, 0 /* mode, right_shift, clip_en */
};

static int is_yuv_format(u32 format)
{
	int b_yuv = 0;

	switch (format) {
	case COLOR_FMT_YUV422:
	case COLOR_FMT_YUV444:
	case COLOR_FMT_YUYV422:
	case COLOR_FMT_YVYU422:
	case COLOR_FMT_UYVY422:
	case COLOR_FMT_VYUY422:
	case COLOR_FMT_NV12:
	case COLOR_FMT_NV21:
		b_yuv = 1;
		break;
	default:
		break;
	}
	return b_yuv;
}

/* for c3 */
static void osd1_matrix_yuv2rgb(int yuv2rgb)
{
	int i;
	int mat_conv_en = 0;
	int pre_offset[3], post_offset[3];
	int mat_coef[15];
	int rgb2yuvpre[3] = {0, 0, 0};
	int rgb2yuvpos[3] = {64, 512, 512};
	int yuv2rgbpre[3] = {-64, -512, -512};
	int yuv2rgbpos[3] = {0, 0, 0};
	static int matrix_save;
	u32 output_index = VPP0;

	/* matrix coef BT709 */
	int rgb2ycbcr[15] = {264, 516, 100, -152, -296, 448,
		448, -376, -72, 0, 0, 0, 0, 0, 0};
	int ycbcr2rgb[15] = {1197, 0, 1726, 1197, -193, -669,
		1197, 2202, 0, 0, 0, 0, 0, 0, 0};

	memset(pre_offset, 0, sizeof(pre_offset));
	memset(post_offset, 0, sizeof(post_offset));
	memset(mat_coef, 0, sizeof(mat_coef));

	if (matrix_save == yuv2rgb)
		return;
	switch (yuv2rgb) {
	case MATRIX_BYPASS:
		mat_conv_en = 0;
		break;
	case YUV2RGB:
		mat_conv_en = 1;
		for (i = 0; i < 3; i++) {
			pre_offset[i] = yuv2rgbpre[i];
			post_offset[i] = yuv2rgbpos[i];
		}
		for (i = 0; i < 15; i++)
			mat_coef[i] = ycbcr2rgb[i];
		break;
	case RGB2YUV:
		mat_conv_en = 1;
		for (i = 0; i < 3; i++) {
			pre_offset[i] = rgb2yuvpre[i];
			post_offset[i] = rgb2yuvpos[i];
		}
		for (i = 0; i < 15; i++)
			mat_coef[i] = rgb2ycbcr[i];
		break;
	}
	matrix_save = yuv2rgb;
	if (yuv2rgb != MATRIX_BYPASS) {
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(VOUT_OSD1_CSC_COEF00_01,
			(mat_coef[0] << 16) |
			(mat_coef[1] & 0x1FFF));
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(VOUT_OSD1_CSC_COEF02_10,
			(mat_coef[2] << 16) |
			(mat_coef[1 * 3 + 0] & 0x1FFF));
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(VOUT_OSD1_CSC_COEF11_12,
			(mat_coef[1 * 3 + 1] << 16) |
			(mat_coef[1 * 3 + 2] & 0x1FFF));
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(VOUT_OSD1_CSC_COEF20_21,
			(mat_coef[2 * 3 + 0] << 16) |
			(mat_coef[2 * 3 + 1] & 0x1FFF));
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(VOUT_OSD1_CSC_COEF22,
			mat_coef[2 * 3 + 2]);
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(VOUT_OSD1_CSC_OFFSET0_1,
			(post_offset[0] << 16) |
			(post_offset[1] & 0xFFF));
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(VOUT_OSD1_CSC_OFFSET2,
			post_offset[2]);
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(VOUT_OSD1_CSC_PRE_OFFSET0_1,
			(pre_offset[0] << 16) |
			(pre_offset[1] & 0xFFF));
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(VOUT_OSD1_CSC_PRE_OFFSET2,
			pre_offset[2]);
	}
	/* vd1_mat_en */
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
		(VOUT_OSD1_CSC_EN_CTRL,
		mat_conv_en, 0, 1);
}

/*for G12A, set osd3 matrix(10bit) RGB2YUV*/
static void set_viu2_rgb2yuv(bool on)
{
	/* RGB -> 709 limit */
	int *m = RGB709_to_YUV709l_coeff;

	/* VPP WRAP OSD3 matrix */
	osd_reg_write(VIU2_OSD1_MATRIX_PRE_OFFSET0_1,
		      ((m[0] & 0xfff) << 16) | (m[1] & 0xfff));
	osd_reg_write(VIU2_OSD1_MATRIX_PRE_OFFSET2,
		      m[2] & 0xfff);
	osd_reg_write(VIU2_OSD1_MATRIX_COEF00_01,
		      ((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff));
	osd_reg_write(VIU2_OSD1_MATRIX_COEF02_10,
		      ((m[5]  & 0x1fff) << 16) | (m[6] & 0x1fff));
	osd_reg_write(VIU2_OSD1_MATRIX_COEF11_12,
		      ((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff));
	osd_reg_write(VIU2_OSD1_MATRIX_COEF20_21,
		      ((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff));
	osd_reg_write(VIU2_OSD1_MATRIX_COEF22,
		      m[11] & 0x1fff);

	osd_reg_write(VIU2_OSD1_MATRIX_OFFSET0_1,
		      ((m[18] & 0xfff) << 16) | (m[19] & 0xfff));
	osd_reg_write(VIU2_OSD1_MATRIX_OFFSET2,
		      m[20] & 0xfff);

	osd_reg_set_bits(VIU2_OSD1_MATRIX_EN_CTRL, on, 0, 1);
}

static void f2v_get_vertical_phase(u32 zoom_ratio,
				   enum osd_f2v_vphase_type_e type,
				   u8 bank_length,
				   struct osd_f2v_vphase_s *vphase)
{
	u8 f2v_420_in_pos_luma[OSD_F2V_TYPE_MAX] = {
		0, 2, 0, 2, 0, 0, 0, 2, 0};
	u8 f2v_420_out_pos[OSD_F2V_TYPE_MAX] = {
		0, 2, 2, 0, 0, 2, 0, 0, 0};
	s32 offset_in, offset_out;

	/* luma */
	offset_in = f2v_420_in_pos_luma[type]
		<< OSD_PHASE_BITS;
	offset_out = (f2v_420_out_pos[type] * zoom_ratio)
		>> (OSD_ZOOM_BITS - OSD_PHASE_BITS);

	vphase->rcv_num = bank_length;
	if (bank_length == 4 || bank_length == 3)
		vphase->rpt_num = 1;
	else
		vphase->rpt_num = 0;

	if (offset_in > offset_out) {
		vphase->rpt_num = vphase->rpt_num + 1;
		vphase->phase =
			((4 << OSD_PHASE_BITS) + offset_out - offset_in)
			>> 2;
	} else {
		while ((offset_in + (4 << OSD_PHASE_BITS))
			<= offset_out) {
			if (vphase->rpt_num == 1)
				vphase->rpt_num = 0;
			else
				vphase->rcv_num++;
			offset_in += 4 << OSD_PHASE_BITS;
		}
		vphase->phase = (offset_out - offset_in) >> 2;
	}
}
#endif

#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM
static bool osd_hdr_on;
#endif

static bool is_encp(u32 viu_type)
{
	u32 viu = VIU1;
	bool ret = false;

	if (viu_type == VIU1)
		viu = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) & 0x3;
	else if (viu_type == VIU2)
		viu = (osd_reg_read(VPU_VIU_VENC_MUX_CTRL) >> 2) & 0x3;
	if (viu == 2)
		/* encpi case, for 1080i */
		ret = true;
	/* for cvbs is enci */
	return ret;
}

static int get_venc_type(u32 viu_type)
{
	u32 venc_type = 0;

	if (osd_dev_hw.display_type == T7_DISPLAY ||
		osd_dev_hw.s5_display) {
		u32 venc_mux = 3;
		u32 venc_addr = VPU_VENC_CTRL;

		venc_mux = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) & 0x3f;
		venc_mux >>= (viu_type * 2);
		venc_mux &= 0x3;

		switch (venc_mux) {
		case 0:
			venc_addr = VPU_VENC_CTRL;
			break;
		case 1:
			venc_addr = VPU1_VENC_CTRL;
			break;
		case 2:
			venc_addr = VPU2_VENC_CTRL;
			break;
		}
		venc_type = osd_reg_read(venc_addr);
	} else {
		if (viu_type == VIU1)
			venc_type = osd_reg_read(VPU_VIU_VENC_MUX_CTRL);
		else if (viu_type == VIU2)
			venc_type = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) >> 2;
	}

	venc_type &= 0x3;

	return venc_type;
}

static int get_active_begin_line(u32 viu_type)
{
	int active_line_begin = 0;
	u32 reg = ENCL_VIDEO_VAVON_BLINE;

	if (osd_dev_hw.display_type == T7_DISPLAY ||
		osd_dev_hw.s5_display) {
		u32 venc_mux = 3;

		venc_mux = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) & 0x3f;
		venc_mux >>= (viu_type * 2);
		venc_mux &= 0x3;

		if (venc_mux >= 3)
			return 0;

		switch (get_venc_type(viu_type)) {
		case 0:
			reg = venc_regs[venc_mux].enci_vavon_bline;
			break;
		case 1:
			reg = venc_regs[venc_mux].encp_vavon_bline;
			break;
		case 2:
			reg = venc_regs[venc_mux].encl_vavon_bline;
			break;
		}
	} else {
		switch (get_venc_type(viu_type)) {
		case 0:
			reg = ENCL_VIDEO_VAVON_BLINE;
			break;
		case 1:
			reg = ENCI_VFIFO2VD_LINE_TOP_START;
			break;
		case 2:
			reg = ENCP_VIDEO_VAVON_BLINE;
			break;
		case 3:
			reg = ENCT_VIDEO_VAVON_BLINE;
			break;
		}
	}

	active_line_begin = osd_reg_read(reg);
	if (is_meson_t3x_cpu())
		active_line_begin = (active_line_begin >> 16) & 0xfff;
	return active_line_begin;
}

int get_encp_line(u32 viu_type)
{
	int enc_line = 0;
	unsigned int reg = VPU_VENCI_STAT;
	unsigned int reg_val = 0;
	u32 venc_type = get_venc_type(viu_type);

	if (osd_dev_hw.display_type == T7_DISPLAY ||
		osd_dev_hw.s5_display) {
		u32 venc_mux = 3;

		venc_mux = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) & 0x3f;
		venc_mux >>= (viu_type * 2);
		venc_mux &= 0x3;

		if (venc_mux >= 3)
			return 0;

		switch (venc_type) {
		case 0:
			reg = venc_regs[venc_mux].vpu_enci_stat;
			break;
		case 1:
			reg = venc_regs[venc_mux].vpu_encp_stat;
			break;
		case 2:
			reg = venc_regs[venc_mux].vpu_encl_stat;
			break;
		}
	} else {
		switch (venc_type) {
		case 0:
			reg = ENCL_INFO_READ;
			break;
		case 1:
			reg = ENCI_INFO_READ;
			break;
		case 2:
			reg = ENCP_INFO_READ;
			break;
		case 3:
			reg = ENCT_INFO_READ;
			break;
		}
	}

	reg_val = osd_reg_read(reg);

	enc_line = (reg_val >> 16) & 0x1fff;

	return enc_line;
}

static int get_enter_encp_line(u32 viu_type)
{
	int enc_line = 0;

	enc_line = get_encp_line(viu_type);
	if (enc_line > vsync_enter_line_max)
		vsync_enter_line_max = enc_line;
	return enc_line;
}

static int get_exit_encp_line(u32 viu_type)
{
	int enc_line = 0;

	enc_line = get_encp_line(viu_type);
	if (enc_line > vsync_exit_line_max)
		vsync_exit_line_max = enc_line;
	return enc_line;
}

static void osd_vpu_power_on(void)
{
#ifdef CONFIG_AMLOGIC_VPU
	struct vpu_dev_s *osd1_vpu_dev;
	struct vpu_dev_s *osd2_vpu_dev;
	struct vpu_dev_s *osd_scale_vpu_dev;

	osd1_vpu_dev = vpu_dev_register(VPU_VIU_OSD1, "OSD1");
	vpu_dev_mem_power_on(osd1_vpu_dev);
	osd2_vpu_dev = vpu_dev_register(VPU_VIU_OSD2, "OSD2");
	vpu_dev_mem_power_on(osd2_vpu_dev);
	osd_scale_vpu_dev =
		vpu_dev_register(VPU_VIU_OSD_SCALE, "OSD_SCALE");
	vpu_dev_mem_power_on(osd_scale_vpu_dev);
	if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE) {
		struct vpu_dev_s *osd2_scale_vpu_dev;
		struct vpu_dev_s *osd3_vpu_dev;
		struct vpu_dev_s *blend34_vpu_dev;

		osd2_scale_vpu_dev =
			vpu_dev_register(VPU_VD2_OSD2_SCALE, "OSD2_SCALE");
		vpu_dev_mem_power_on(osd2_scale_vpu_dev);
		osd3_vpu_dev = vpu_dev_register(VPU_VIU_OSD3, "OSD3");
		vpu_dev_mem_power_on(osd3_vpu_dev);
		blend34_vpu_dev =
			vpu_dev_register(VPU_OSD_BLD34, "BLEND34_SCALE");
		vpu_dev_mem_power_on(blend34_vpu_dev);
	}
	if (osd_hw.osd_meson_dev.afbc_type == MESON_AFBC) {
		struct vpu_dev_s *meson_afbc_vpu_dev;

		meson_afbc_vpu_dev =
			vpu_dev_register(VPU_AFBC_DEC, "MESON_AFBC");
		vpu_dev_mem_power_on(meson_afbc_vpu_dev);
	} else if (osd_hw.osd_meson_dev.afbc_type == MALI_AFBC) {
		struct vpu_dev_s *mali_afbc_vpu_dev;

		mali_afbc_vpu_dev =
			vpu_dev_register(VPU_MAIL_AFBCD, "MALI_AFBC");
		vpu_dev_mem_power_on(mali_afbc_vpu_dev);
	}
#endif
}

static void osd_vpu_power_on_viu2(void)
{
#ifdef CONFIG_AMLOGIC_VPU
	if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE) {
		struct vpu_dev_s *viu2_osd1_vpu_dev;
		struct vpu_dev_s *viu2_ofifo_vpu_dev;
		struct vpu_dev_s *viu2_osd_rot_vpu_dev;
		u32 val;

		viu2_osd1_vpu_dev =
			vpu_dev_register(VPU_VIU2_OSD1, "VIU2_OSD1");
		vpu_dev_mem_power_on(viu2_osd1_vpu_dev);
		viu2_ofifo_vpu_dev =
			vpu_dev_register(VPU_VIU2_OFIFO, "VIU2_OFIFO");
		vpu_dev_mem_power_on(viu2_ofifo_vpu_dev);
		viu2_osd_rot_vpu_dev =
			vpu_dev_register(VPU_VIU2_OSD_ROT, "VIU2_ROT");
		vpu_dev_mem_power_on(viu2_osd_rot_vpu_dev);
		val = osd_reg_read(VPU_CLK_GATE);
		val =  val | 0x30000;
		osd_reg_write(VPU_CLK_GATE, val);
	}
#endif
}

u32 to_osd_hw_index(u32 osd_index)
{
	u32 index = osd_index;

	/* for s5_display, only OSD1 + OSD3.
	 * osd_index 0 -> HW OSD1
	 * osd_index 1 -> HW OSD3
	 */
	if (osd_dev_hw.s5_display &&
	    osd_hw.osd_meson_dev.cpu_id == __MESON_CPU_MAJOR_ID_S5 &&
	    osd_index == 1)
		index = OSD3;

	return index;
}

static u32 to_osd_sw_index(u32 osd_index)
{
	u32 index = osd_index;

	/* for s5_display, only OSD1 + OSD3.
	 * HW OSD1 -> osd_index 0
	 * HW OSD3 -> osd_index 1
	 */
	if (osd_dev_hw.s5_display &&
	    osd_hw.osd_meson_dev.cpu_id == __MESON_CPU_MAJOR_ID_S5) {
		switch (osd_index) {
		case OSD1:
			index = 0;
			break;
		case OSD3:
			index = 1;
			break;
		default:
			index = OSD_ERR;
			break;
		}
	}

	return index;
}

static u32 to_reorder_hw_index(u32 reorder_index)
{
	u32 osd_index = reorder_index - 1;
	u32 hw_reoder_index;

	hw_reoder_index = to_osd_hw_index(osd_index) + 1;

	/* for s5_display
	 * 2slice_mode: slice2ppc -> din0
	 * normal_mode: osdx to din(x+1)
	 */
	if (osd_dev_hw.s5_display && !osd_hw.slice2ppc_enable)
		hw_reoder_index++;

	return hw_reoder_index;
}

static u32 to_din_scope_osd_index(u32 din_index)
{
	u32 osd_index = din_index;

	if (osd_dev_hw.s5_display) {
		u32 slice_mode = osd_hw.slice2ppc_enable;

		/* for s5_display
		 * 2slice_mode: only din_scope0
		 * normal_mode: din_scope1/2/3
		 */
		switch (din_index) {
		case 0:
			osd_index = slice_mode ? OSD1 : OSD_ERR;
			break;
		case 1:
			osd_index = slice_mode ? OSD_ERR : OSD1;
			break;
		case 2:
			osd_index = slice_mode ? OSD_ERR : OSD2;
			break;
		case 3:
			osd_index = slice_mode ? OSD_ERR : OSD3;
			break;
		}
	}
	osd_index = to_osd_sw_index(osd_index);

	return osd_index;
}

/* validate if osdx is routed to vpp_topx */
static int validate_osd(u32 osd_index, u32 viu_index)
{
	u32 ret = 0;
	u32 viu_osd_table = osd_hw.viu_osd_table[viu_index];

	while ((viu_osd_table & 0xf) != 0xf) {
		if (osd_index == (viu_osd_table & 0xf)) {
			ret = 1;
			break;
		}
		viu_osd_table = viu_osd_table >> 4;
	}

	return ret;
}

u32 get_output_device_id(u32 index)
{
	u32 output_index = VIU1;

	if (validate_osd(index, VIU1))
		output_index = VIU1;
	else if (validate_osd(index, VIU2))
		output_index = VIU2;
	else if (validate_osd(index, VIU3))
		output_index = VIU3;
	else
		osd_log_err("wrong osd index, %s, %d\n", __func__, __LINE__);

	return output_index;
}

static int get_osd_hwc_type(u32 index)
{
	int ret = 0;
	u32 output_index;

	output_index = get_output_device_id(index);
	/* new hwcomposer enable */
	if (osd_hw.hwc_enable[output_index]) {
		if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE)
			ret = OSD_G12A_NEW_HWC;
		else
			ret = OSD_OTHER_NEW_HWC;
	} else {
		ret = OSD_OLD_HWC;
	}
	return ret;
}

#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
static inline  int  find_buf_num(u32 yres, u32 yoffset)
{
	int n = yres;
	int i;

	for (i = 0; i < OSD_MAX_BUF_NUM; i++) {
		/* find current addr position. */
		if (yoffset  < (n))
			break;
		n += yres;
	}
	return i;
}

static void osd_toggle_buffer_single(struct kthread_work *work)
{
	struct osd_fence_map_s *data, *next;
	struct list_head saved_list;

	mutex_lock(&post_fence_list_lock[VIU1]);
	saved_list = post_fence_list[VIU1];
	list_replace_init(&post_fence_list[VIU1], &saved_list);
	mutex_unlock(&post_fence_list_lock[VIU1]);
	list_for_each_entry_safe(data, next, &saved_list, list) {
		osd_pan_display_single_fence(data);
		list_del(&data->list);
		kfree(data);
	}
}

static void release_fenceobj(struct osd_layers_fence_map_s *fence_map,
			 u32 output_index)
{
	int i = 0;
	int start_index = 0;
	int osd_count = 0;
	struct layer_fence_map_s *layer_map = NULL;

	if (output_index == VIU1) {
		osd_count = osd_hw.osd_meson_dev.viu1_osd_count;
		if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL)
			osd_count = 1;
		start_index = 0;
	} else if (output_index == VIU2) {
		if (osd_dev_hw.display_type == T7_DISPLAY ||
		    osd_dev_hw.display_type == S5_DISPLAY) {
			osd_count = osd_hw.osd_meson_dev.viu1_osd_count;
			start_index = 0;
		} else {
			start_index = osd_hw.osd_meson_dev.viu2_index;
			osd_count = start_index + 1;
		}
	} else {
		osd_log_err("invalid output_index=%d\n", output_index);
		return;
	}

	for (i = start_index; i < osd_count; i++) {
		if (!validate_osd(i, output_index))
			continue;
		layer_map = &fence_map->layer_map[i];

		if (layer_map->buf_file) {
			fput(layer_map->buf_file);
			osd_hw.file_info_debug[i].fput_count++;
		}
		if (layer_map->in_fence)
			osd_put_fenceobj(layer_map->in_fence);
	}
}

static int fence_combine_signaled(u32 output_index,
			   struct osd_layers_fence_map_s *fence_map)
{
	int i = 0, ret = 1;
	int start_index = 0;
	int osd_count = 0;
	struct layer_fence_map_s *layer_map = NULL;

	if (output_index == VIU1) {
		osd_count = osd_hw.osd_meson_dev.viu1_osd_count;
		if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL)
			osd_count = 1;
		start_index = 0;
	} else if (output_index == VIU2) {
		if (osd_dev_hw.display_type == T7_DISPLAY ||
		    osd_dev_hw.display_type == S5_DISPLAY) {
			osd_count = osd_hw.osd_meson_dev.viu1_osd_count;
			start_index = 0;
		} else {
			start_index = osd_hw.osd_meson_dev.viu2_index;
			osd_count = start_index + 1;
		}
	} else {
		osd_log_err("invalid output_index=%d\n", output_index);
		return 1;
	}

	for (i = start_index; i < osd_count; i++) {
		if (!validate_osd(i, output_index))
			continue;

		layer_map = &fence_map->layer_map[i];

		if (!layer_map->in_fence)
			continue;

		if (timeline_created[output_index] &&
		    layer_map->enable &&
		    fence_map->cmd == LAYER_SYNC) {
			ret = aml_sync_fence_status(layer_map->in_fence);
			if (!ret)
				break;
		}
	}

	return ret;
}

static int worker_list_empty(struct kthread_worker *worker)
{
	if (!worker) {
		osd_log_err("worker is NULL\n");
		return 1;
	}

	return list_empty(&worker->work_list) ? 1 : 0;
}

static void osd_toggle_buffer_layers(struct kthread_work *work)
{
	struct osd_layers_fence_map_s *data, *next;
	u32 game_mode = osd_game_mode[VIU1], timeline_inc;
	LIST_HEAD(saved_list);

cycle:
	mutex_lock(&post_fence_list_lock[VIU1]);
	if (list_empty(&post_fence_list[VIU1])) {
		mutex_unlock(&post_fence_list_lock[VIU1]);
			return;
	}

	if (!game_mode) {
		list_replace_init(&post_fence_list[VIU1], &saved_list);
	} else {
		list_for_each_entry_safe(data, next,
					 &post_fence_list[VIU1], list) {
			if (fence_combine_signaled(VIU1, data))
				list_move_tail(&data->list, &saved_list);
		}

		if (list_empty(&saved_list))
			list_move_tail(post_fence_list[VIU1].next, &saved_list);
	}
	mutex_unlock(&post_fence_list_lock[VIU1]);

	timeline_inc = 0;

	list_for_each_entry_safe(data, next, &saved_list, list) {
		if (!game_mode) {
			data->inc_cnt = 1;
			osd_pan_display_layers_fence(data);
		} else {
			timeline_inc++;
			if (list_is_last(&data->list, &saved_list)) {
				data->inc_cnt = timeline_inc;
				osd_pan_display_layers_fence(data);
			} else {
				release_fenceobj(data, VIU1);
			}
		}
		list_del(&data->list);
		kfree(data);
	}
	if (timeline_inc > 1)
		osd_log_dbg(MODULE_FENCE, "game mode, VIU1 timeline_inc %d\n",
			    timeline_inc);

	if (worker_list_empty(work->worker))
		goto cycle;
}

static void osd_toggle_buffer(struct kthread_work *work)
{
	u32 hwc_enable;

	hwc_enable = osd_hw.hwc_enable[VIU1];
	if (osd_hw.osd_fence[VIU1][hwc_enable].toggle_buffer_handler)
		osd_hw.osd_fence[VIU1][hwc_enable]
		.toggle_buffer_handler(work);
}

static void osd_toggle_buffer_single_viu2(struct kthread_work *work)
{
	struct osd_fence_map_s *data, *next;
	struct list_head saved_list;

	mutex_lock(&post_fence_list_lock[VIU2]);
	saved_list = post_fence_list[VIU2];
	list_replace_init(&post_fence_list[VIU2], &saved_list);
	mutex_unlock(&post_fence_list_lock[VIU2]);
	list_for_each_entry_safe(data, next, &saved_list, list) {
		osd_pan_display_single_fence_viu2(data);
		list_del(&data->list);
		kfree(data);
	}
}

static void osd_toggle_buffer_layers_viu2(struct kthread_work *work)
{
	struct osd_layers_fence_map_s *data, *next;
	u32 game_mode = osd_game_mode[VIU2], timeline_inc;
	LIST_HEAD(saved_list);

cycle:
	mutex_lock(&post_fence_list_lock[VIU2]);
	if (list_empty(&post_fence_list[VIU2])) {
		mutex_unlock(&post_fence_list_lock[VIU2]);
		return;
	}
	if (!game_mode) {
		list_replace_init(&post_fence_list[VIU2], &saved_list);
	} else {
		list_for_each_entry_safe(data, next,
					 &post_fence_list[VIU2], list) {
			if (fence_combine_signaled(VIU2, data))
				list_move_tail(&data->list, &saved_list);
		}

		if (list_empty(&saved_list))
			list_move_tail(post_fence_list[VIU2].next, &saved_list);
	}

	mutex_unlock(&post_fence_list_lock[VIU2]);
	timeline_inc = 0;
	list_for_each_entry_safe(data, next, &saved_list, list) {
		if (!game_mode) {
			data->inc_cnt = 1;
			osd_pan_display_layers_fence_viu2(data);
		} else {
			timeline_inc++;
			if (list_is_last(&data->list, &saved_list)) {
				data->inc_cnt = timeline_inc;
				osd_pan_display_layers_fence_viu2(data);
			} else {
				release_fenceobj(data, VIU2);
			}
		}
		list_del(&data->list);
		kfree(data);
	}
	if (timeline_inc > 1)
		osd_log_dbg(MODULE_FENCE, "game mode, VIU2 timeline_inc %d\n",
			    timeline_inc);

	if (worker_list_empty(work->worker))
		goto cycle;
}

static void osd_toggle_buffer_viu2(struct kthread_work *work)
{
	u32 hwc_enable;

	hwc_enable = osd_hw.hwc_enable[VIU2];
	if (osd_hw.osd_fence[VIU2][hwc_enable].toggle_buffer_handler)
		osd_hw.osd_fence[VIU2][hwc_enable]
			.toggle_buffer_handler(work);
}

static int out_fence_create(u32 output_index, int *release_fence_fd)
{
	int out_fence_fd = -1;
	struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
	char toggle_thread_name[32] = {};
	unsigned long _cpu_mask = *cpumask_bits(&affinity_info.cpu_mask) & (~1);

	if (!timeline_created[output_index]) {
		/* timeline has not been created */
		if (osd_timeline_create(output_index)) {
			kthread_init_worker
				(&buffer_toggle_worker[output_index]);
			sprintf(toggle_thread_name,
				"aml_buf_toggle_%d", output_index);
			buffer_toggle_thread[output_index] = kthread_run
				(kthread_worker_fn,
				 &buffer_toggle_worker[output_index],
				 toggle_thread_name);
			if (IS_ERR(buffer_toggle_thread[output_index])) {
				osd_log_err("create osd toggle kthread failed");
				return -1;
			}
			sched_setscheduler(buffer_toggle_thread[output_index],
					   SCHED_FIFO, &param);
			if (output_index == VIU1)
				kthread_init_work
					(&buffer_toggle_work[output_index],
					 osd_toggle_buffer);
			else if (output_index == VIU2)
				kthread_init_work
					(&buffer_toggle_work[output_index],
					 osd_toggle_buffer_viu2);
			/* set cpu affinity mask 0xe(work on cpu1~3) */
			set_cpus_allowed_ptr(buffer_toggle_thread[output_index],
					     (struct cpumask *)&_cpu_mask);
			timeline_created[output_index] = 1;
		}
	}

	/* hwc_enable disable create fence every time */
	if (!osd_hw.hwc_enable[output_index]) {
		out_fence_fd = osd_timeline_create_fence(output_index);
		if (out_fence_fd < 0) {
			osd_log_err("fence obj create fail\n");
			out_fence_fd = -1;
		}
	} else {
		/* hwc_enable enable create fence
		 * when first sync request called
		 */
		if (osd_hw.out_fence_fd[output_index] == -1) {
			out_fence_fd = osd_timeline_create_fence(output_index);
			if (out_fence_fd < 0) {
				osd_log_err("fence obj create fail\n");
				out_fence_fd = -1;
			}
			osd_hw.out_fence_fd[output_index] = out_fence_fd;
		} else {
			out_fence_fd = osd_hw.out_fence_fd[output_index];
		}
	}
	if (release_fence_fd)
		*release_fence_fd = out_fence_fd;
	return out_fence_fd;
}

int osd_sync_request(u32 index, u32 yres, struct fb_sync_request_s *request)
{
	int out_fence_fd = -1;
	int buf_num = 0;
	int in_fence_fd = -1;
	u32 output_index = 0;
	struct osd_fence_map_s *fence_map =
		kzalloc(sizeof(struct osd_fence_map_s), GFP_KERNEL);

	output_index = get_output_device_id(index);
	osd_hw.hwc_enable[output_index] = 0;
	if (request->sync_req.magic == FB_SYNC_REQUEST_MAGIC) {
		buf_num = find_buf_num(yres, request->sync_req.yoffset);
		if (!fence_map) {
			osd_log_err("could not allocate osd_fence_map\n");
			return -ENOMEM;
		}
		mutex_lock(&post_fence_list_lock[output_index]);
		fence_map->op = 0xffffffff;
		fence_map->fb_index = index;
		fence_map->buf_num = buf_num;
		fence_map->yoffset = request->sync_req.yoffset;
		fence_map->xoffset = request->sync_req.xoffset;
		fence_map->yres = yres;
		fence_map->format = request->sync_req.format;
		fence_map->in_fd = request->sync_req.in_fen_fd;
		in_fence_fd = request->sync_req.in_fen_fd;
		osd_tprintk("request fence fd:%d\n", fence_map->in_fd);
		fence_map->in_fence = osd_get_fenceobj
			(request->sync_req.in_fen_fd);
		fence_map->out_fd =
			out_fence_create(output_index, &out_fence_fd);
	} else {
		buf_num = find_buf_num(yres, request->sync_req_old.yoffset);
		if (!fence_map) {
			osd_log_err("could not allocate osd_fence_map\n");
			return -ENOMEM;
		}
		mutex_lock(&post_fence_list_lock[output_index]);
		fence_map->op = 0xffffffff;
		fence_map->fb_index = index;
		fence_map->buf_num = buf_num;
		fence_map->yoffset = request->sync_req_old.yoffset;
		fence_map->xoffset = request->sync_req_old.xoffset;
		fence_map->yres = yres;
		fence_map->in_fd = request->sync_req_old.in_fen_fd;
		in_fence_fd = request->sync_req_old.in_fen_fd;
		osd_tprintk("request fence fd:%d\n", fence_map->in_fd);
		fence_map->in_fence = osd_get_fenceobj
			(request->sync_req_old.in_fen_fd);
		fence_map->out_fd =
			out_fence_create(output_index, &out_fence_fd);
	}
	list_add_tail(&fence_map->list, &post_fence_list[output_index]);
	mutex_unlock(&post_fence_list_lock[output_index]);
	kthread_queue_work(&buffer_toggle_worker[output_index],
			   &buffer_toggle_work[output_index]);
	//if (in_fence_fd >= 0)
		//close_fd(in_fence_fd);
	return  out_fence_fd;
}

static int sync_render_single_fence(u32 index, u32 yres,
				    struct sync_req_render_s *request,
				    ulong phys_addr,
				    size_t len)
{
	int out_fence_fd = -1;
	int buf_num = 0;
	u32 xoffset, yoffset;
	u32 output_index = 0;
	struct osd_fence_map_s *fence_map =  NULL;

	if (index > OSD1)
		return -1;
	xoffset = request->xoffset;
	yoffset = request->yoffset;
	buf_num = find_buf_num(yres, yoffset);
	fence_map = kzalloc(sizeof(*fence_map), GFP_KERNEL);
	if (!fence_map) {
		osd_log_err("could not allocate osd_fence_map\n");
		return -ENOMEM;
	}
	output_index = get_output_device_id(index);
	mutex_lock(&post_fence_list_lock[output_index]);
	fence_map->op = 0xffffffff;
	fence_map->fb_index = index;
	fence_map->buf_num = buf_num;
	fence_map->yoffset = yoffset;
	fence_map->xoffset = xoffset;
	fence_map->yres = yres;
	fence_map->in_fd = request->in_fen_fd;
	fence_map->ext_addr = phys_addr;
	if (fence_map->ext_addr) {
		fence_map->width = request->width;
		fence_map->height = request->height;
		fence_map->dst_x = request->dst_x;
		fence_map->dst_y = request->dst_y;
		fence_map->dst_w = request->dst_w;
		fence_map->dst_h = request->dst_h;
		fence_map->byte_stride = request->byte_stride;
		fence_map->pxiel_stride = request->pxiel_stride;
		fence_map->afbc_inter_format = request->afbc_inter_format;
		fence_map->afbc_len = len;
	}
	fence_map->format = request->format;
	fence_map->compose_type = request->type;
	fence_map->op = request->op;

	osd_tprintk("direct render fence fd:%d\n", fence_map->in_fd);
	fence_map->in_fence = osd_get_fenceobj(fence_map->in_fd);
	fence_map->out_fd =
		out_fence_create(output_index, &out_fence_fd);
	/* Todo: */
	list_add_tail(&fence_map->list, &post_fence_list[output_index]);
	mutex_unlock(&post_fence_list_lock[output_index]);
	kthread_queue_work(&buffer_toggle_worker[output_index],
			   &buffer_toggle_work[output_index]);
	request->out_fen_fd = out_fence_fd;
	//if (request->in_fen_fd >= 0)
		//close_fd(request->in_fen_fd);
	return out_fence_fd;
}

static int sync_render_layers_fence(u32 index, u32 yres,
				    struct sync_req_render_s *request,
				    ulong phys_addr,
				    size_t len)
{
	int out_fence_fd = -1;
	s32 in_fence_fd;
	u32 output_index = 0;
	struct osd_layers_fence_map_s *fence_map = NULL;

	if (index >= OSD_MAX)
		return -1;
	output_index = get_output_device_id(index);
	in_fence_fd = request->in_fen_fd;
	mutex_lock(&post_fence_list_lock[output_index]);
	fence_map = &map_layers[output_index];
	fence_map->cmd = LAYER_SYNC;
	fence_map->layer_map[index].fb_index = index;
	/* layer_map[index].enable will update if have blank ioctl */
	fence_map->layer_map[index].enable = request->op;
	fence_map->layer_map[index].in_fd = request->in_fen_fd;
	if (request->shared_fd < 0) {
		fence_map->layer_map[index].buf_file = NULL;
	} else {
		fence_map->layer_map[index].buf_file = fget(request->shared_fd);
		osd_hw.file_info_debug[index].fget_count++;
	}
	fence_map->layer_map[index].ext_addr = phys_addr;
	fence_map->layer_map[index].format = request->format;
	fence_map->layer_map[index].compose_type = request->type;
	fence_map->layer_map[index].fb_width = request->fb_width;
	fence_map->layer_map[index].fb_height = request->fb_height;
	fence_map->layer_map[index].src_x = request->xoffset;
	fence_map->layer_map[index].src_y = request->yoffset;
	fence_map->layer_map[index].src_w = request->width;
	fence_map->layer_map[index].src_h = request->height;
	fence_map->layer_map[index].dst_x = request->dst_x;
	fence_map->layer_map[index].dst_y = request->dst_y;
	fence_map->layer_map[index].dst_w = request->dst_w;
	fence_map->layer_map[index].dst_h = request->dst_h;
	fence_map->layer_map[index].byte_stride =
		request->byte_stride;
	fence_map->layer_map[index].pxiel_stride =
		request->pxiel_stride;
	fence_map->layer_map[index].afbc_inter_format =
		request->afbc_inter_format;
	fence_map->layer_map[index].zorder = request->zorder;
	fence_map->layer_map[index].blend_mode =
		request->blend_mode;
	fence_map->layer_map[index].plane_alpha =
		request->plane_alpha;
	fence_map->layer_map[index].dim_layer = request->dim_layer;
	fence_map->layer_map[index].dim_color = request->dim_color;
	fence_map->layer_map[index].afbc_len = len;
	fence_map->layer_map[index].secure_enable = request->secure_enable;
	/* just return out_fd,but not signal */
	/* no longer put list, will put them via do_hwc */
	fence_map->layer_map[index].in_fence = osd_get_fenceobj(in_fence_fd);
	fence_map->layer_map[index].out_fd =
		out_fence_create(output_index, &out_fence_fd);
	mutex_unlock(&post_fence_list_lock[output_index]);
	osd_log_dbg(MODULE_FENCE, "%s:osd%d: ind_fd=%d,out_fd=%d\n",
		    __func__,
		    fence_map->layer_map[index].fb_index,
		    fence_map->layer_map[index].in_fd,
		    fence_map->layer_map[index].out_fd);
	request->out_fen_fd = out_fence_fd;
//	if (in_fence_fd >= 0)
//		close_fd(in_fence_fd);
//	if (request->shared_fd >= 0)
//		close_fd(request->shared_fd);
	return out_fence_fd;
}

int osd_sync_request_render(u32 index, u32 yres,
			    struct sync_req_render_s *request,
			    ulong phys_addr,
			    size_t len)
{
	int line, hwc_enable;
	u32 output_index = 0;

	line = get_encp_line(output_index);
	output_index = get_output_device_id(index);
	osd_log_dbg2(MODULE_RENDER,
		     "enter %s,encp line=%d\n",
		     __func__, line);
	if (request->magic == FB_SYNC_REQUEST_RENDER_MAGIC_V1)
		osd_hw.hwc_enable[output_index] = 0;
	else if (request->magic == FB_SYNC_REQUEST_RENDER_MAGIC_V2)
		osd_hw.hwc_enable[output_index] = 1;
	output_index = get_output_device_id(index);
	hwc_enable = osd_hw.hwc_enable[output_index];

	if (osd_hw.osd_fence[output_index][hwc_enable].sync_fence_handler)
		osd_hw.osd_fence[output_index][hwc_enable]
			.sync_fence_handler(index, yres,
			request, phys_addr, len);
	return request->out_fen_fd;
}

int osd_sync_do_hwc(u32 index, struct do_hwc_cmd_s *hwc_cmd)
{
	int out_fence_fd = -1;
	struct osd_layers_fence_map_s *fence_map = NULL;
	int line;
	u32 output_index = 0;

	output_index = get_output_device_id(index);
	line = get_encp_line(output_index);
	osd_log_dbg2(MODULE_RENDER,
		     "enter %s,encp line=%d\n",
		     __func__, line);
	fence_map = kzalloc(sizeof(*fence_map), GFP_KERNEL);
	if (!fence_map)
		return -ENOMEM;
	osd_hw.hwc_enable[output_index] = 1;
	mutex_lock(&post_fence_list_lock[output_index]);
	memcpy(fence_map, &map_layers[output_index],
	       sizeof(struct osd_layers_fence_map_s));
	/* clear map_layers, need alloc next add_sync ioctl */
	memset(&map_layers[output_index], 0,
	       sizeof(struct osd_layers_fence_map_s));
	fence_map->out_fd =
		out_fence_create(output_index, &out_fence_fd);
	fence_map->disp_info.background_w =
		hwc_cmd->disp_info.background_w;
	fence_map->disp_info.background_h =
		hwc_cmd->disp_info.background_h;
	fence_map->disp_info.fullscreen_w =
		hwc_cmd->disp_info.fullscreen_w;
	fence_map->disp_info.fullscreen_h =
		hwc_cmd->disp_info.fullscreen_h;
	fence_map->disp_info.position_x =
		hwc_cmd->disp_info.position_x;
	fence_map->disp_info.position_y =
		hwc_cmd->disp_info.position_y;
	fence_map->disp_info.position_w =
		hwc_cmd->disp_info.position_w;
	fence_map->disp_info.position_h =
		hwc_cmd->disp_info.position_h;
	fence_map->hdr_mode = hwc_cmd->hdr_mode;
	/* other info set via add_sync and blank ioctl */
	list_add_tail(&fence_map->list, &post_fence_list[output_index]);
	/* after do_hwc, clear osd_hw.out_fence_fd */
	if (timeline_created[output_index] &&
	    osd_hw.out_fence_fd[output_index])
		osd_hw.out_fence_fd[output_index] = -1;
	mutex_unlock(&post_fence_list_lock[output_index]);
	kthread_queue_work(&buffer_toggle_worker[output_index],
			   &buffer_toggle_work[output_index]);
	if (get_logo_loaded()) {
		int logo_index;

		logo_index = osd_get_logo_index();
		if (logo_index < 0) {
			osd_log_info("set logo loaded\n");
			set_logo_loaded();
		}
	}
	osd_log_dbg(MODULE_FENCE, "%s :out_fence_fd=%d\n",
		    __func__, out_fence_fd);
	return out_fence_fd;
}

static int osd_wait_buf_ready(struct osd_fence_map_s *fence_map)
{
	s32 ret = -1;
	struct dma_fence *buf_ready_fence = NULL;

	if (fence_map->in_fd <= 0)
		return -1;
	buf_ready_fence = fence_map->in_fence;
	if (!buf_ready_fence)
		return -1;/* no fence ,output directly. */
	ret = osd_wait_fenceobj(buf_ready_fence, msecs_to_jiffies(4000));
	if (ret <= 0) {
		osd_log_err("Sync Fence wait error:%d\n", ret);
		osd_log_err("-----wait buf idx:[%d] ERROR\n"
			    "-----on screen buf idx:[%d]\n",
			    fence_map->buf_num, find_buf_num(fence_map->yres,
			    osd_hw.pandata[fence_map->fb_index].y_start));
	} else {
		ret = 1;
	}
	return ret;
}

static int osd_wait_buf_ready_combine(struct layer_fence_map_s *layer_map)
{
	s32 ret = -1;
	struct dma_fence *buf_ready_fence = NULL;

	if (layer_map->in_fd <= 0)
		return -1;
	buf_ready_fence = layer_map->in_fence;
	if (!buf_ready_fence)
		return -1;/* no fence ,output directly. */

	ret = osd_wait_fenceobj(buf_ready_fence, msecs_to_jiffies(4000));
	if (ret <= 0)
		osd_log_err("osd%d: Sync Fence wait error:%d\n",
			    layer_map->fb_index, ret);
	else
		ret = 1;

	osd_log_dbg(MODULE_FENCE, "%s:osd%d,in_fd=%d\n",
		    __func__, layer_map->fb_index, layer_map->in_fd);
	return ret;
}

#else
int osd_sync_request(u32 index, u32 yres, struct fb_sync_request_s *request)
{
	osd_log_err("%s not supported\n", __func__);
	return -5566;
}

int osd_sync_request_render(u32 index, u32 yres,
			    struct sync_req_render_s *request,
			    ulong phys_addr,
			    size_t len)
{
	osd_log_err("%s not supported\n", __func__);
	return -5566;
}

int osd_sync_do_hwc(u32 index, struct do_hwc_cmd_s *hwc_cmd)
{
	osd_log_err("%s not supported\n", __func__);
	return -5566;
}
#endif
static void osd_get_max_window_size(struct dispdata_s *dst_data)
{
	int i;

	memset(dst_data, 0x0, sizeof(struct dispdata_s));
	for (i = 0; i < osd_hw.osd_meson_dev.viu1_osd_count; i++) {
		if (osd_hw.enable[i]) {
			if (dst_data->x > osd_hw.dst_data[i].x)
				dst_data->x = osd_hw.dst_data[i].x;
			if (dst_data->y > osd_hw.dst_data[i].y)
				dst_data->y = osd_hw.dst_data[i].y;
			if (dst_data->w < osd_hw.dst_data[i].w)
				dst_data->w = osd_hw.dst_data[i].w;
			if (dst_data->h < osd_hw.dst_data[i].h)
				dst_data->h = osd_hw.dst_data[i].h;
		}
	}
	osd_log_dbg(MODULE_BLEND, "max window size:%d, %d,%d,%d\n",
		    dst_data->x, dst_data->y, dst_data->w, dst_data->h);
}

static void osd_get_max_fb_size(struct dispdata_s *src_data)
{
	int i;

	memset(src_data, 0x0, sizeof(struct dispdata_s));
	for (i = 0; i < osd_hw.osd_meson_dev.viu1_osd_count; i++) {
		if (src_data->x > osd_hw.src_data[i].x)
			src_data->x = osd_hw.src_data[i].x;
		if (src_data->y > osd_hw.src_data[i].y)
			src_data->y = osd_hw.src_data[i].y;
		if (src_data->w < osd_hw.src_data[i].w)
			src_data->w = osd_hw.src_data[i].w;
		if (src_data->h < osd_hw.src_data[i].h)
			src_data->h = osd_hw.src_data[i].h;
	}
	osd_log_dbg(MODULE_BLEND, "max fb size:%d, %d,%d,%d\n",
		    src_data->x, src_data->y, src_data->w, src_data->h);
}

static void osd_update_disp_dst_size(u32 index)
{
	u32 output_index;

	output_index = get_output_device_id(index);
	if (osd_hw.hwc_enable[output_index] &&
	    osd_hw.osd_display_fb[output_index]) {
		struct display_flip_info_s disp_info;
		struct dispdata_s dst_data;

		osd_get_background_size(index, &disp_info);
		osd_get_max_window_size(&dst_data);
		disp_info.position_x = dst_data.x;
		disp_info.position_y = dst_data.y;
		disp_info.position_w = dst_data.w;
		disp_info.position_h = dst_data.h;
		osd_set_background_size(index, &disp_info);
	}
}

static void osd_update_disp_src_size(u32 index)
{
	u32 output_index;

	output_index = get_output_device_id(index);
	if (osd_hw.hwc_enable[output_index] &&
	    osd_hw.osd_display_fb[output_index]) {
		struct display_flip_info_s disp_info;
		struct dispdata_s fb_data;

		osd_get_background_size(index, &disp_info);
		osd_get_max_fb_size(&fb_data);
		disp_info.background_w = fb_data.w;
		disp_info.background_h = fb_data.h;
		osd_set_background_size(index, &disp_info);
	}
}

void osd_set_enable_hw(u32 index, u32 enable)
{
	u32 output_index = 0;

	output_index = get_output_device_id(index);
	if (osd_hw.hwc_enable[output_index]) {
		if (index >= OSD_MAX)
			return;
		if (osd_hw.osd_meson_dev.osd_ver < OSD_HIGH_ONE &&
		    index == OSD2) {
			osd_enable_hw(index, enable);
		} else {
#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
			mutex_lock(&post_fence_list_lock[output_index]);
			map_layers[output_index]
				.layer_map[index].fb_index = index;
			map_layers[output_index]
				.layer_map[index].enable = enable;
			map_layers[output_index].cmd = BLANK_CMD;
			mutex_unlock(&post_fence_list_lock[output_index]);
			osd_log_dbg(MODULE_BASE, "%s: osd%d,enable=%d\n",
				    __func__, index, enable);
#endif
		}
	} else {
		osd_enable_hw(index, enable);
	}
}

void osd_update_3d_mode(void)
{
	int i = 0;

	/* only called by vsync irq or rdma irq */
	for (i = 0; i <= OSD2; i++)
		if (osd_hw.mode_3d[i].enable)
			osd_update_disp_3d_mode(i);
}

static inline void wait_vsync_wakeup(void)
{
	wake_up_interruptible_all(&osd_vsync_wq);
}

static inline void wait_vsync_wakeup_viu2(void)
{
	wake_up_interruptible_all(&osd_vsync2_wq);
}

static inline void wait_vsync_wakeup_viu3(void)
{
	wake_up_interruptible_all(&osd_vsync3_wq);
}

static inline void wait_rdma_done_wakeup(void)
{
	vsync_hit[VIU1] = true;
	wake_up_interruptible_all(&osd_rdma_vpp0_done_wq);
}

static inline void wait_rdma_done_wakeup_viu2(void)
{
	vsync_hit[VIU2] = true;
	wake_up_interruptible_all(&osd_rdma_vpp1_done_wq);
}

static inline void wait_rdma_done_wakeup_viu3(void)
{
	vsync_hit[VIU3] = true;
	wake_up_interruptible_all(&osd_rdma_vpp2_done_wq);
}

static s64 get_adjust_vsynctime(u32 output_index)
{
	struct vinfo_s *vinfo = NULL;
	int line, active_begin_line;
	int vinfo_height;
	int thresh_line, vsync_time;
	s64 adjust_nsec;

	vinfo = get_current_vinfo();
	if (vinfo && vinfo->name && (!strcmp(vinfo->name, "invalid") ||
		      !strcmp(vinfo->name, "null"))) {
		active_begin_line = get_active_begin_line(output_index);
		line = get_enter_encp_line(output_index);
		/* if nearly vsync signal, wait vsync here */
		vinfo_height = osd_hw.field_out_en[output_index] ?
			(osd_hw.vinfo_height[output_index] * 2) :
			osd_hw.vinfo_height[output_index];
		thresh_line = vsync_threshold;
		if (line > thresh_line) {
			vsync_time = 1000000 * vinfo->sync_duration_den /
				vinfo->sync_duration_num;
			adjust_nsec = div_u64((u64)vsync_time *
					      (line - thresh_line),
					      (vinfo_height +
					       active_begin_line)) * 1000;
			vsync_adjust_hit++;
			return adjust_nsec;

		} else {
			return 0;
		}
	} else {
		return 0;
	}
}

void osd_update_vsync_timestamp(void)
{
	ktime_t stime;
	s64 cur_timestamp;

	stime = ktime_get();
	cur_timestamp = stime - get_adjust_vsynctime(VIU1);
	if (osd_log_level) {
		const struct vinfo_s *vinfo;
		s64 vsync_time, diff_time;

		vinfo = get_current_vinfo();
		if (vinfo) {
			diff_time = cur_timestamp - timestamp[VIU1];
			vsync_time = div_s64((s64)vinfo->sync_duration_den * (s64)1000000000,
					    (s64)vinfo->sync_duration_num);
			if (diff_time > (vsync_time + 1000000) ||
			    diff_time < (vsync_time - 1000000))
				osd_log_dbg2(MODULE_BASE,
					     "vsync timestamp warning: cur=%lld, pre=%lld, diff_time=%lld\n",
					     cur_timestamp, timestamp[VIU1],
					     diff_time);
		}
	}
	timestamp[VIU1] = cur_timestamp;
	wait_vsync_wakeup();
}

void osd_update_vsync_timestamp_viu2(void)
{
	ktime_t stime;

	stime = ktime_get();
	timestamp[VIU2] = stime - get_adjust_vsynctime(VIU2);
	wait_vsync_wakeup_viu2();
}

void osd_update_vsync_timestamp_viu3(void)
{
	ktime_t stime;

	stime = ktime_get();
	timestamp[VIU3] = stime - get_adjust_vsynctime(VIU3);
	wait_vsync_wakeup_viu3();
}

void osd_update_vsync_hit(void)
{
#ifdef FIQ_VSYNC
	fiq_bridge_pulse_trigger(&osd_hw.fiq_handle_item);
#else
	wait_rdma_done_wakeup();
#endif
}

void osd_update_vsync_hit_viu2(void)
{
#ifdef FIQ_VSYNC
	fiq_bridge_pulse_trigger(&osd_hw.fiq_handle_item);
#else
	wait_rdma_done_wakeup_viu2();
#endif
}

void osd_update_vsync_hit_viu3(void)
{
#ifdef FIQ_VSYNC
	fiq_bridge_pulse_trigger(&osd_hw.fiq_handle_item);
#else
	wait_rdma_done_wakeup_viu3();
#endif
}

/* the return stride unit is 128bit(16bytes) */
static u32 line_stride_calc(u32 fmt_mode,
			    u32 hsize,
			    u32 stride_align_32bytes)
{
	u32 line_stride = 0;
	u32 line_stride_32bytes;
	u32 line_stride_64bytes;

	switch (fmt_mode) {
	/* 2-bit LUT */
	case COLOR_INDEX_02_PAL4:
		line_stride = ((hsize << 1) + 127) >> 7;
		break;
	/* 4-bit LUT */
	case COLOR_INDEX_04_PAL16:
		line_stride = ((hsize << 2) + 127) >> 7;
		break;
	/* 8-bit LUT */
	case COLOR_INDEX_08_PAL256:
		line_stride = ((hsize << 3) + 127) >> 7;
		break;
	/* 4:2:2, 32-bit per 2 pixels */
	case COLOR_INDEX_YUV_422:
		line_stride = ((((hsize + 1) >> 1) << 5) + 127) >> 7;
		break;
	/* 16-bit LUT */
	case COLOR_INDEX_16_655:
	case COLOR_INDEX_16_844:
	case COLOR_INDEX_16_6442:
	case COLOR_INDEX_16_4444_R:
	case COLOR_INDEX_16_4642_R:
	case COLOR_INDEX_16_1555_A:
	case COLOR_INDEX_16_4444_A:
	case COLOR_INDEX_16_565:
		line_stride = ((hsize << 4) + 127) >> 7;
		break;
	/* 32-bit LUT */
	case COLOR_INDEX_32_BGRX:
	case COLOR_INDEX_32_XBGR:
	case COLOR_INDEX_32_RGBX:
	case COLOR_INDEX_32_XRGB:
	case COLOR_INDEX_32_BGRA:
	case COLOR_INDEX_32_ABGR:
	case COLOR_INDEX_32_RGBA:
	case COLOR_INDEX_32_ARGB:
		line_stride = ((hsize << 5) + 127) >> 7;
		break;
	/* 24-bit LUT */
	case COLOR_INDEX_24_6666_A:
	case COLOR_INDEX_24_6666_R:
	case COLOR_INDEX_24_8565:
	case COLOR_INDEX_24_5658:
	case COLOR_INDEX_24_888_B:
	case COLOR_INDEX_24_RGB:
		line_stride = ((hsize << 4) + (hsize << 3) + 127) >> 7;
		break;
	}
	line_stride_32bytes = ((line_stride + 1) >> 1) << 1;
	line_stride_64bytes = ((line_stride + 3) >> 2) << 2;
	/* need wr ddr is 32bytes aligned */
	if (stride_align_32bytes)
		line_stride = line_stride_32bytes;
	else
		line_stride = line_stride_64bytes;
	return line_stride;
}

static u32 line_stride_calc_afbc(u32 fmt_mode,
				 u32 hsize,
				 u32 stride_align_32bytes)
{
	u32 line_stride = 0;

	switch (fmt_mode) {
	case R8:
		line_stride = ((hsize << 3) + 127) >> 7;
		break;
	case YUV422_8B:
	case RGB565:
	case RGBA5551:
	case RGBA4444:
		line_stride = ((hsize << 4) + 127) >> 7;
		break;
	case RGBA8888:
	case RGB888:
	case YUV422_10B:
	case RGBA1010102:
		line_stride = ((hsize << 5) + 127) >> 7;
		break;
	}
	/* need wr ddr is 32bytes aligned */
	if (stride_align_32bytes)
		line_stride = ((line_stride + 1) >> 1) << 1;

	return line_stride;
}

static void osd_update_phy_addr(u32 index)
{
	u32 line_stride, bpp;
	u32 fmt_mode = COLOR_INDEX_32_BGRX;
	u32 output_index = get_output_device_id(index);

	if (osd_hw.color_info[index])
		fmt_mode =
			osd_hw.color_info[index]->color_index;
	bpp = osd_hw.color_info[index]->bpp / 8;
	/* 32 byte align */
	line_stride = line_stride_calc
		(fmt_mode,
		osd_hw.fb_gem[index].width / bpp, 1);
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(hw_osd_reg_array[index].osd_blk1_cfg_w4,
			     osd_hw.fb_gem[index].addr);
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
		(hw_osd_reg_array[index].osd_blk2_cfg_w4,
		line_stride,
		0, 12);
}

static void osd_update_mif_linear_addr(u32 index)
{
	u32 line_stride, bpp;
	u32 fmt_mode = COLOR_INDEX_32_BGRX;
	u32 output_index = get_output_device_id(index);

	if (osd_hw.color_info[index])
		fmt_mode =
			osd_hw.color_info[index]->color_index;
	else
		return;
	bpp = osd_hw.color_info[index]->bpp / 8;
	/* 64 bytes align */
	line_stride = line_stride_calc
		(fmt_mode,
		osd_hw.fb_gem[index].width / bpp, 0);
	/* set frame addr, 8G addr, need >> 4*/
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(hw_osd_reg_array[index].osd_blk1_cfg_w4,
		osd_hw.fb_gem[index].addr >> 4);
	/* set line stride */
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
		(hw_osd_reg_array[index].osd_blk2_cfg_w4,
		line_stride,
		0, 12);
	/* used phyic addr */
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
		(hw_osd_reg_array[index].osd_ctrl_stat,
		1, 2, 1);
}

/* only need judge osd1 and osd2 index, osd3 same with osd1 */
static void osd_update_interlace_mode(int index)
{
	/* only called by vsync irq or rdma irq */
	unsigned int fb0_cfg_w0 = 0, fb1_cfg_w0 = 0;
	unsigned int scan_line_number = 0;
	unsigned int odd_even;
	u32 output_index = VIU1;

	spin_lock_irqsave(&osd_lock, lock_flags);
	if ((index & (1 << OSD1)) == (1 << OSD1)) {
		output_index = get_output_device_id(OSD1);
		fb0_cfg_w0 = osd_hw.osd_rdma_func[output_index].osd_rdma_rd
			(hw_osd_reg_array[OSD1].osd_blk0_cfg_w0);
	}
	if ((index & (1 << OSD2)) == (1 << OSD2)) {
		output_index = get_output_device_id(OSD2);
		fb1_cfg_w0 = osd_hw.osd_rdma_func[output_index].osd_rdma_rd
			(hw_osd_reg_array[OSD2].osd_blk0_cfg_w0);
	}
	if (osd_reg_read(ENCP_VIDEO_MODE) & (1 << 12)) {
		/* 1080I */
		scan_line_number = ((osd_reg_read(ENCP_INFO_READ))
				& 0x1fff0000) >> 16;
		if ((osd_hw.pandata[OSD1].y_start % 2) == 0) {
			if (scan_line_number >= 562) {
				/* bottom field, odd lines*/
				odd_even = OSD_TYPE_BOT_FIELD;
			} else {
				/* top field, even lines*/
				odd_even = OSD_TYPE_TOP_FIELD;
			}
		} else {
			if (scan_line_number >= 562) {
				/* top field, even lines*/
				odd_even = OSD_TYPE_TOP_FIELD;
			} else {
				/* bottom field, odd lines*/
				odd_even = OSD_TYPE_BOT_FIELD;
			}
		}
	} else {
		if ((osd_hw.pandata[OSD1].y_start % 2) == 1) {
			odd_even = (osd_reg_read(ENCI_INFO_READ) & (1 << 29)) ?
				OSD_TYPE_TOP_FIELD : OSD_TYPE_BOT_FIELD;
		} else {
			odd_even = (osd_reg_read(ENCI_INFO_READ) & (1 << 29)) ?
				OSD_TYPE_BOT_FIELD : OSD_TYPE_TOP_FIELD;
		}
	}
	if (osd_hw.hw_rdma_en)
		/* when RDMA enabled, top/bottom fields changed in next vsync */
		odd_even = (odd_even == OSD_TYPE_TOP_FIELD) ?
			OSD_TYPE_BOT_FIELD : OSD_TYPE_TOP_FIELD;
	fb0_cfg_w0 &= ~1;
	fb1_cfg_w0 &= ~1;
	fb0_cfg_w0 |= odd_even;
	fb1_cfg_w0 |= odd_even;
	if ((index & (1 << OSD1)) == (1 << OSD1)) {
		output_index = get_output_device_id(OSD1);
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr_irq
			(hw_osd_reg_array[OSD1].osd_blk0_cfg_w0, fb0_cfg_w0);
		if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE) {
			if ((osd_hw.osd_meson_dev.viu1_osd_count - 1) == OSD3) {
				output_index = get_output_device_id(OSD3);
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr_irq
				(hw_osd_reg_array[OSD3].osd_blk0_cfg_w0,
				fb0_cfg_w0);
			}
		}
	}
	if ((index & (1 << OSD2)) == (1 << OSD2)) {
		output_index = get_output_device_id(OSD2);
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr_irq
			(hw_osd_reg_array[OSD2].osd_blk0_cfg_w0,
			fb1_cfg_w0);
	}

	spin_unlock_irqrestore(&osd_lock, lock_flags);
}

void osd_update_scan_mode(void)
{
	/* only called by vsync irq or rdma irq */
	unsigned int output_type = 0;
	int index = 0;
	int viu2_index = osd_hw.osd_meson_dev.viu2_index;
	int osd_count = osd_hw.osd_meson_dev.viu1_osd_count;
	int i;
	u32 scan_mode[HW_OSD_COUNT];

	output_type = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) & 0x3;
	for (i = 0; i < osd_count; i++)
		scan_mode[i] = SCAN_MODE_PROGRESSIVE;
	scan_mode[viu2_index] = SCAN_MODE_PROGRESSIVE;
	switch (output_type) {
	case VOUT_ENCP:
		if (osd_reg_read(ENCP_VIDEO_MODE) & (1 << 12)) {
			/* 1080i */
			for (i = 0; i < osd_count; i++)
				scan_mode[i] = SCAN_MODE_INTERLACE;
		}
		break;
	case VOUT_ENCI:
		if (osd_reg_read(ENCI_VIDEO_EN) & 1) {
			for (i = 0; i < osd_count; i++)
				scan_mode[i] = SCAN_MODE_INTERLACE;
		}
		break;
	}
	if (osd_hw.hw_cursor_en) {
		/* 3 layers osd don't support osd2 cursor */
		if (osd_hw.free_scale_enable[OSD1])
			scan_mode[OSD1] = SCAN_MODE_PROGRESSIVE;
		if (osd_hw.osd_afbcd[OSD1].enable)
			scan_mode[OSD1] = SCAN_MODE_PROGRESSIVE;

		if (scan_mode[OSD1] == SCAN_MODE_INTERLACE)
			index |= 1 << OSD1;
		if (scan_mode[OSD2] == SCAN_MODE_INTERLACE)
			index |= 1 << OSD2;
	} else {
		int i;

		for (i = 0; i < osd_count; i++) {
			if (osd_hw.free_scale_enable[i])
				scan_mode[i] = SCAN_MODE_PROGRESSIVE;
			if (osd_hw.osd_afbcd[i].enable)
				scan_mode[i] = SCAN_MODE_PROGRESSIVE;
			if (scan_mode[i] == SCAN_MODE_INTERLACE)
				index |= 1 << i;
		}
	}
	if (index)
		osd_update_interlace_mode(index);
}

static void osd_update_interlace_mode_viu2(void)
{
	/* only called by vsync irq or rdma irq */
	unsigned int fb3_cfg_w0 = 0;
	unsigned int odd_even = 0;
	u32 viu2_index;

	spin_lock_irqsave(&osd_lock, lock_flags);
	viu2_index = osd_hw.osd_meson_dev.viu2_index;
	if (osd_hw.powered[viu2_index]) {
		fb3_cfg_w0 = VSYNCOSD_RD_MPEG_REG
			(hw_osd_reg_array[viu2_index].osd_blk0_cfg_w0);
		if (osd_hw.scan_mode[viu2_index] == SCAN_MODE_INTERLACE) {
			if ((osd_hw.pandata[viu2_index].y_start % 2) == 1) {
				odd_even = (osd_reg_read(ENCI_INFO_READ) &
					(1 << 29)) ? OSD_TYPE_TOP_FIELD :
					OSD_TYPE_BOT_FIELD;
			} else {
				odd_even = (osd_reg_read(ENCI_INFO_READ)
				& (1 << 29)) ? OSD_TYPE_BOT_FIELD :
				OSD_TYPE_TOP_FIELD;
			}
		}
		fb3_cfg_w0 &= ~1;
		fb3_cfg_w0 |= odd_even;
		VSYNCOSD_IRQ_WR_MPEG_REG
			(hw_osd_reg_array[viu2_index].osd_blk0_cfg_w0,
			fb3_cfg_w0);
	}
	spin_unlock_irqrestore(&osd_lock, lock_flags);
}

void osd_update_scan_mode_viu2(void)
{
	/* only called by vsync irq or rdma irq */
	unsigned int output_type = 0;
	int viu2_index = osd_hw.osd_meson_dev.viu2_index;
	u32 scan_mode[HW_OSD_COUNT];

	output_type = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) & 0x3;
	scan_mode[viu2_index] = SCAN_MODE_PROGRESSIVE;
	if (osd_hw.powered[viu2_index]) {
		output_type = (osd_reg_read(VPU_VIU_VENC_MUX_CTRL)
			>> 2) & 0x3;
		switch (output_type) {
		case VOUT_ENCP:
			if (osd_reg_read(ENCP_VIDEO_MODE) & (1 << 12))
				/* 1080i */
				scan_mode[viu2_index] =
				SCAN_MODE_INTERLACE;
			break;
		case VOUT_ENCI:
			if (osd_reg_read(ENCI_VIDEO_EN) & 1)
				scan_mode[viu2_index] =
				SCAN_MODE_INTERLACE;
			break;
		}
	}
	if (scan_mode[viu2_index] == SCAN_MODE_INTERLACE)
		osd_update_interlace_mode_viu2();
}

//not rdma will call update func;
void walk_through_update_list(void)
{
	u32  i, j;

	for (i = 0; i < HW_OSD_COUNT; i++) {
		j = 0;
		while (osd_hw.updated[i] && j < HW_REG_INDEX_MAX) {
			if (osd_hw.updated[i] & (1 << j)) {
				if (osd_hw.reg[j].update_func)
					osd_hw.reg[j].update_func(i);
				remove_from_update_list(i, j);
			}
			j++;
		}
	}
}

/*************** for GXL/GXM hardware alpha bug workaround ***************/
static bool mali_afbc_get_error(void)
{
	u32 status;
	bool error = false;

	status = VSYNCOSD_RD_MPEG_REG(VPU_MAFBC_IRQ_RAW_STATUS);
	if (status & 0x3c) {
		osd_log_dbg(MODULE_BASE,
			    "afbc error happened,status=0x%x\n", status);
		osd_hw.afbc_err_cnt[0]++;
		error = true;
	}
	status = VSYNCOSD_IRQ_WR_MPEG_REG(VPU_MAFBC_IRQ_CLEAR, 0x3f);
	return error;
}

static bool mali_afbcn_get_error(u32 index)
{
	u32 status;
	bool error = false;
	struct hw_osd_reg_s *osd_reg = &hw_osd_reg_array[index];
	u32 output_index = get_output_device_id(index);

	status = osd_hw.osd_rdma_func[output_index].osd_rdma_rd
		(osd_reg->vpu_mafbc_irq_raw_status);
	if (status & 0x3c) {
		osd_log_dbg(MODULE_BASE,
			    "afbc(%d) error happened,status=0x%x\n", index, status);
		if (index == OSD1 || index == OSD2) {
			index = OSD1;
			osd_hw.afbc_err_cnt[index]++;
			index = OSD2;
			osd_hw.afbc_err_cnt[index]++;
		} else {
			osd_hw.afbc_err_cnt[index]++;
		}
		error = true;
	}
	status = osd_hw.osd_rdma_func[output_index].osd_rdma_wr_irq
		(osd_reg->vpu_mafbc_irq_clear, 0x3f);
	return error;
}

static u32 osd_get_hw_reset_flag(u32 output_index)
{
	u32 hw_reset_flag = HW_RESET_NONE;

	/* check hw version */
	switch (osd_hw.osd_meson_dev.cpu_id) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
	case __MESON_CPU_MAJOR_ID_GXTVBB:
		if (osd_hw.osd_afbcd[OSD1].enable)
			hw_reset_flag |= HW_RESET_AFBCD_REGS;
		break;
	case __MESON_CPU_MAJOR_ID_GXM:
		/* same bit, but gxm only reset hardware, not top reg*/
		if (osd_hw.osd_afbcd[OSD1].enable)
			hw_reset_flag |= HW_RESET_AFBCD_HARDWARE;
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM
		if (((hdr_osd_reg.viu_osd1_matrix_ctrl & 0x00000001)
			!= 0x0) ||
			((hdr_osd_reg.viu_osd1_eotf_ctl & 0x80000000)
			!= 0) ||
			((hdr_osd_reg.viu_osd1_oetf_ctl & 0xe0000000)
			!= 0)) {
			hw_reset_flag |= HW_RESET_OSD1_REGS;
			osd_hdr_on = true;
		} else if (osd_hdr_on) {
			hw_reset_flag |= HW_RESET_OSD1_REGS;
			osd_hdr_on = false;
		}
#endif
		break;
	case __MESON_CPU_MAJOR_ID_GXL:
	case __MESON_CPU_MAJOR_ID_TXL:
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM

		if (((hdr_osd_reg.viu_osd1_matrix_ctrl & 0x00000001)
			!= 0x0) ||
			((hdr_osd_reg.viu_osd1_eotf_ctl & 0x80000000)
			!= 0) ||
			((hdr_osd_reg.viu_osd1_oetf_ctl & 0xe0000000)
			!= 0)) {
			hw_reset_flag |= HW_RESET_OSD1_REGS;
			osd_hdr_on = true;
		} else if (osd_hdr_on) {
			hw_reset_flag |= HW_RESET_OSD1_REGS;
			osd_hdr_on = false;
		}
#endif
		break;
#endif
	case __MESON_CPU_MAJOR_ID_G12A:
	case __MESON_CPU_MAJOR_ID_G12B:
	case __MESON_CPU_MAJOR_ID_TL1:
	case __MESON_CPU_MAJOR_ID_SM1:
	case __MESON_CPU_MAJOR_ID_TM2:
	case __MESON_CPU_MAJOR_ID_SC2:
	case __MESON_CPU_MAJOR_ID_T5:
	case __MESON_CPU_MAJOR_ID_T5D:
	case __MESON_CPU_MAJOR_ID_S4:
	case __MESON_CPU_MAJOR_ID_TXHD2:
	case __MESON_CPU_MAJOR_ID_S1A:
		{
		int i, afbc_enable = 0;

		for (i = 0; i < osd_hw.osd_meson_dev.osd_count; i++)
			afbc_enable |= osd_hw.osd_afbcd[i].enable;
		if (afbc_enable &&
		    osd_hw.afbc_force_reset)
			hw_reset_flag |= HW_RESET_MALI_AFBCD_REGS;
		if (afbc_enable && mali_afbc_get_error() &&
		    osd_hw.afbc_status_err_reset)
			hw_reset_flag |= HW_RESET_MALI_AFBCD_REGS;
		}
		break;
	case __MESON_CPU_MAJOR_ID_T7:
	case __MESON_CPU_MAJOR_ID_T3:
	case __MESON_CPU_MAJOR_ID_T5W:
	case __MESON_CPU_MAJOR_ID_T5M:
		{
		int i, afbc_enable = 0;
		u32 mali_afbc_reset;

		for (i = 0; i < osd_hw.osd_meson_dev.osd_count; i++) {
			/* if OSDx is not in VIUx, skip it */
			if (!validate_osd(i, output_index))
				continue;

			mali_afbc_reset = 0;
			afbc_enable = osd_hw.osd_afbcd[i].enable;
			if (afbc_enable &&
			    osd_hw.afbc_force_reset)
				mali_afbc_reset = 1;
			if (afbc_enable && mali_afbcn_get_error(i) &&
			    osd_hw.afbc_status_err_reset)
				mali_afbc_reset = 1;

			if (mali_afbc_reset) {
				switch (i) {
				case OSD1:
				case OSD2:
					hw_reset_flag |= HW_RESET_MALI_AFBCD_REGS;
					break;
				case OSD3:
					hw_reset_flag |= HW_RESET_MALI_AFBCD1_REGS;
					break;
				case OSD4:
					hw_reset_flag |= HW_RESET_MALI_AFBCD2_REGS;
					break;
				}
			}
		}
		}
		break;
	default:
		hw_reset_flag = HW_RESET_NONE;
		break;
	}

	return hw_reset_flag;
}

void osd_hw_reset(u32 output_index)
{
	/* only called by vsync irq or rdma irq */
	u32 backup_mask;
	u32 reset_bit =
		osd_get_hw_reset_flag(output_index);

	struct osd_rdma_fun_s *rdma_func = &osd_hw.osd_rdma_func[output_index];
	osd_rdma_wr_irq_op rdma_wr_irq = rdma_func->osd_rdma_wr_irq;


	backup_mask = is_backup();
	osd_hw.hw_reset_flag = reset_bit;
	spin_lock_irqsave(&osd_lock, lock_flags);
	if ((reset_bit & HW_RESET_OSD1_REGS) &&
	    !(backup_mask & HW_RESET_OSD1_REGS))
		reset_bit &= ~HW_RESET_OSD1_REGS;

#ifndef CONFIG_AMLOGIC_REMOVE_OLD
	if ((get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB &&
	     osd_hw.osd_meson_dev.afbc_type == MESON_AFBC) &&
	    (reset_bit & HW_RESET_AFBCD_REGS) &&
	    !(backup_mask & HW_RESET_AFBCD_REGS))
		reset_bit &= ~HW_RESET_AFBCD_REGS;
#endif

	if (osd_hw.osd_meson_dev.afbc_type == MALI_AFBC &&
	    reset_bit & HW_RESET_MALI_AFBCD_REGS &&
	    !(backup_mask & HW_RESET_MALI_AFBCD_REGS))
		reset_bit &= ~HW_RESET_MALI_AFBCD_REGS;
	if (osd_hw.osd_meson_dev.afbc_type == MALI_AFBC &&
	    reset_bit & HW_RESET_MALI_AFBCD1_REGS &&
	    !(backup_mask & HW_RESET_MALI_AFBCD1_REGS))
		reset_bit &= ~HW_RESET_MALI_AFBCD1_REGS;
	if (osd_hw.osd_meson_dev.afbc_type == MALI_AFBC &&
	    reset_bit & HW_RESET_MALI_AFBCD2_REGS &&
	    !(backup_mask & HW_RESET_MALI_AFBCD2_REGS))
		reset_bit &= ~HW_RESET_MALI_AFBCD2_REGS;

	if (!osd_hw.hw_rdma_en) {
		/* if not osd rdma, don't reset osd1 for hdr */
		reset_bit &= ~HW_RESET_OSD1_REGS;
		backup_mask &= ~HW_RESET_OSD1_REGS;

		if (reset_bit) {
			rdma_wr_irq(VIU_SW_RESET, reset_bit);
			rdma_wr_irq(VIU_SW_RESET, 0);
		}
		if (reset_bit & HW_RESET_OSD1_REGS) {
			/* restore osd regs */
			int i;
			u32 addr;
			u32 base = hw_osd_reg_array[OSD1].osd_ctrl_stat;

			for (i = 0; i < OSD_REG_BACKUP_COUNT; i++) {
				addr = osd_reg_backup[i];
				rdma_wr_irq(addr, osd_backup[addr - base]);
			}
		}

		if (osd_hw.osd_meson_dev.afbc_type == MESON_AFBC &&
		    reset_bit & HW_RESET_AFBCD_REGS) {
			/* restore osd afbcd regs */
			int i;
			u32 addr;
			u32 value;
			u32 base = OSD1_AFBCD_ENABLE;

			for (i = 0; i < OSD_AFBC_REG_BACKUP_COUNT; i++) {
				addr = osd_afbc_reg_backup[i];
				value = osd_afbc_backup[addr - base];
				if (addr == OSD1_AFBCD_ENABLE)
					value |= 0x100;
				rdma_wr_irq(addr, value);
			}
		}
		if (osd_hw.osd_meson_dev.afbc_type == MALI_AFBC &&
		    !osd_dev_hw.multi_afbc_core &&
		    reset_bit & HW_RESET_MALI_AFBCD_REGS) {
			/* restore mali afbcd regs */
			if (osd_hw.afbc_regs_backup) {
				int i;
				u32 addr;
				u32 value;
				u32 base = VPU_MAFBC_IRQ_MASK;

				for (i = 0; i < MALI_AFBC_REG_BACKUP_COUNT;
					i++) {
					addr = mali_afbc_reg_backup[i];
					value = mali_afbc_backup[addr - base];
					rdma_wr_irq(addr, value);
				}
			}
			rdma_wr_irq(VPU_MAFBC_COMMAND, 1);
		}
		if (osd_hw.osd_meson_dev.afbc_type == MALI_AFBC &&
		    osd_dev_hw.multi_afbc_core) {
			if (reset_bit & HW_RESET_MALI_AFBCD_REGS) {
				/* restore mali afbcd regs */
				if (osd_hw.afbc_regs_backup) {
					int i;
					u32 addr;
					u32 value;
					u32 base = VPU_MAFBC_IRQ_MASK;

					for (i = 0; i < MALI_AFBC_REG_T7_BACKUP_COUNT;
						i++) {
						addr = mali_afbc_reg_t7_backup[i];
						value = mali_afbc_t7_backup[addr - base];
						rdma_wr_irq(addr, value);
					}
				}
				rdma_wr_irq(VPU_MAFBC_COMMAND, 1);
			}
			if (reset_bit & HW_RESET_MALI_AFBCD1_REGS) {
				/* restore mali afbcd regs */
				if (osd_hw.afbc_regs_backup) {
					int i;
					u32 addr;
					u32 value;
					u32 base = VPU_MAFBC1_IRQ_MASK;

					for (i = 0; i < MALI_AFBC1_REG_T7_BACKUP_COUNT;
						i++) {
						addr = mali_afbc1_reg_t7_backup[i];
						value = mali_afbc1_t7_backup[addr - base];
						rdma_wr_irq(addr, value);
					}
				}
				rdma_wr_irq(VPU_MAFBC1_COMMAND, 1);
			}
			if (reset_bit & HW_RESET_MALI_AFBCD2_REGS) {
				/* restore mali afbcd regs */
				if (osd_hw.afbc_regs_backup) {
					int i;
					u32 addr;
					u32 value;
					u32 base = VPU_MAFBC2_IRQ_MASK;

					for (i = 0; i < MALI_AFBC2_REG_T7_BACKUP_COUNT;
						i++) {
						addr = mali_afbc2_reg_t7_backup[i];
						value = mali_afbc2_t7_backup[addr - base];
						rdma_wr_irq(addr, value);
					}
				}
				rdma_wr_irq(VPU_MAFBC2_COMMAND, 1);
			}
		}

	} else {
		osd_rdma_reset_and_flush(output_index, reset_bit);
	}
	spin_unlock_irqrestore(&osd_lock, lock_flags);
	/* maybe change reset bit */
	osd_hw.hw_reset_flag = reset_bit;
}

static int notify_to_amvideo(void)
{
	u32 para[7];

	para[0] = osd_vpp_misc;
	para[1] = osd_vpp_misc_mask;
	/* osd_vpp1_bld_ctrl */
	para[2] = osd_vpp1_bld_ctrl;
	para[3] = osd_vpp1_bld_ctrl_mask;
	/* osd_vpp2_bld_ctrl */
	para[4] = osd_vpp2_bld_ctrl;
	para[5] = osd_vpp2_bld_ctrl_mask;
	para[6] = osd_vpp_bld_ctrl_update_mask;

	pr_debug("osd %s vpp misc:0x%08x, mask:0x%08x\n",
		 __func__, para[0], para[1]);
	pr_debug("vpp1_bld_ctrl:0x%08x, mask:0x%08x,vpp2_bld_ctrl:0x%08x, mask:0x%08x, notified_mask:0x%x\n",
		para[2], para[3], para[4], para[5], para[6]);

	if (osd_hw.hw_rdma_en) {
#ifdef CONFIG_AMLOGIC_MEDIA_VIDEO
		amvideo_notifier_call_chain(AMVIDEO_UPDATE_OSD_MODE,
					    (void *)&para[0]);
#endif
	}
	return 0;
}

int notify_preblend_to_amvideo(u32 preblend_en)
{
#ifdef CONFIG_AMLOGIC_MEDIA_VIDEO
	amvideo_notifier_call_chain
		(AMVIDEO_UPDATE_PREBLEND_MODE,
		(void *)&preblend_en);
#endif
	return 0;
}

static int notify_to_amdv(void)
{
	u32 para[4];

	if (osd_hw.osd_meson_dev.cpu_id != __MESON_CPU_MAJOR_ID_T7)
		return 0;

	para[0] = osd_mali_afbcd_top_ctrl;
	para[1] = osd_mali_afbcd_top_ctrl_mask;
	para[2] = osd_mali_afbcd1_top_ctrl;
	para[3] = osd_mali_afbcd1_top_ctrl_mask;

	pr_debug("mali_afbcd_top_ctrl:0x%08x, mask:0x%08x,mali_afbcd1_top_ctrl:0x%08x, mask:0x%08x\n",
		para[0], para[1], para[2], para[3]);

	if (osd_hw.hw_rdma_en) {
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
		amdv_notifier_call_chain(AMDV_UPDATE_OSD_MODE,
					    (void *)&para[0]);
#endif
	}
	return 0;
}

static void update_afbcdx_and_notify_amdv(u32 osd_index,
					  u32 val, u32 start, u32 len)
{
	if (osd_index == OSD1 || osd_index == OSD2) {
		osd_mali_afbcd_top_ctrl &= ~(((1 << len) - 1) << start);
		osd_mali_afbcd_top_ctrl |= val << start;
		notify_to_amdv();
	} else if (osd_index == OSD3) {
		osd_mali_afbcd1_top_ctrl &= ~(((1 << len) - 1) << start);
		osd_mali_afbcd1_top_ctrl |= val << start;
		notify_to_amdv();
	}
}

/*************** end of GXL/GXM hardware alpha bug workaround ***************/
static void viu2_osd_reg_table_init(void)
{
	int i = 0;

	for (i = 0; i < VIU2_OSD_REG_NUM; i++) {
		viu2_osd_reg_table[i].val =
			osd_reg_read(viu2_osd_reg_table[i].addr)
			& viu2_osd_reg_table[i].mask;
		viu2_osd_table[i] = viu2_osd_reg_table[i].val;
		osd_log_dbg(MODULE_VIU2, "init: reg:%x = %x\n",
			    viu2_osd_reg_table[i].addr,
			    viu2_osd_reg_table[i].val);
	}
}

static void viu2_osd_reg_table_write(u32 index)
{
	if ((viu2_osd_table[index] & viu2_osd_reg_table[index].mask) !=
		(viu2_osd_reg_table[index].val &
		viu2_osd_reg_table[index].mask)) {
		/* not same, need write to hw regs*/
		osd_reg_write(viu2_osd_reg_table[index].addr,
			      viu2_osd_table[index] &
			      viu2_osd_reg_table[index].mask);
		viu2_osd_reg_table[index].val =
			viu2_osd_table[index] & viu2_osd_reg_table[index].mask;
		osd_log_dbg(MODULE_VIU2, "write: reg:%x = %x, update table:%x\n",
			    viu2_osd_reg_table[index].addr,
			    viu2_osd_table[index],
			    viu2_osd_reg_table[index].val);
	}
}

u32 viu2_osd_reg_read(u32 addr)
{
	int i = 0;

	for (i = 0; i < VIU2_OSD_REG_NUM; i++) {
		if (addr == viu2_osd_reg_table[i].addr)
			return viu2_osd_table[i];
	}
	return 0;
}

void viu2_osd_reg_set(u32 addr, u32 val)
{
	int i = 0;

	osd_log_dbg2(MODULE_VIU2, "%s: reg:%x, val=%x\n",
		     __func__, addr, val);
	for (i = 0; i < VIU2_OSD_REG_NUM; i++) {
		if (addr == viu2_osd_reg_table[i].addr) {
			viu2_osd_table[i] = val;
			osd_log_dbg2(MODULE_VIU2, "%s: set table:%x\n",
				     __func__,
				     viu2_osd_table[i]);
			viu2_osd_reg_table_write(i);
			break;
		}
	}
}

void viu2_osd_reg_set_bits(u32 addr, u32 val, u32 start, u32 len)
{
	int i = 0;

	osd_log_dbg2(MODULE_VIU2, "%s: reg:%x,val=%x,%x,%x\n",
		     __func__, addr, val, start, len);
	for (i = 0; i < VIU2_OSD_REG_NUM; i++) {
		if (addr == viu2_osd_reg_table[i].addr) {
			viu2_osd_table[i] = ((viu2_osd_table[i] &
					 ~(((1L << (len)) - 1) << (start))) |
					(((val) & ((1L << (len)) - 1))
					<< (start)));
			osd_log_dbg2(MODULE_VIU2, "%s: set table:%x\n",
				     __func__,
				     viu2_osd_table[i]);
			viu2_osd_reg_table_write(i);
			break;
		}
	}
}

void viu2_osd_reg_set_mask(u32 addr, u32 _mask)
{
	int i = 0;

	osd_log_dbg2(MODULE_VIU2, "%s: reg:%x, mask:%x\n",
		     __func__, addr, _mask);
	for (i = 0; i < VIU2_OSD_REG_NUM; i++) {
		if (addr == viu2_osd_reg_table[i].addr) {
			viu2_osd_table[i] = (viu2_osd_table[i] | (_mask));
			osd_log_dbg2(MODULE_VIU2, "%s: set table:%x\n",
				     __func__,
				     viu2_osd_table[i]);
			viu2_osd_reg_table_write(i);
			break;
		}
	}
}

void viu2_osd_reg_clr_mask(u32 addr, u32 _mask)
{
	int i = 0;

	osd_log_dbg2(MODULE_VIU2, "%s: reg:%x, mask:%x\n",
		     __func__, addr, _mask);
	for (i = 0; i < VIU2_OSD_REG_NUM; i++) {
		if (addr == viu2_osd_reg_table[i].addr) {
			viu2_osd_table[i] = (viu2_osd_table[i] & (~(_mask)));
			osd_log_dbg2(MODULE_VIU2, "%s: set table:%x\n",
				     __func__,
				     viu2_osd_table[i]);
			viu2_osd_reg_table_write(i);
			break;
		}
	}
}

static void check_reg_changed(void)
{
	static u32 reg_value[72], reg_value_pre[72];
	int i;

	for (i = 0; i < 7; i++)
		reg_value[i] = osd_reg_read(0x39b0 + i);

	reg_value[7] = osd_reg_read(0x39bb);
	reg_value[8] = osd_reg_read(0x1df1);
	reg_value[9] = osd_reg_read(0x1df5);
	reg_value[10] = osd_reg_read(0x1df6);
	reg_value[11] = osd_reg_read(0x1d21);
	reg_value[12] = osd_reg_read(0x1da5);

	for (i = 0; i < 12; i++)
		reg_value[13 + i] = osd_reg_read(0x1dc0 + i);
	for (i = 0; i < 12; i++)
		reg_value[25 + i] = osd_reg_read(0x3d00 + i);
	for (i = 0; i < 12; i++)
		reg_value[37 + i] = osd_reg_read(0x3d20 + i);
	for (i = 0; i < 6; i++)
		reg_value[49 + i] = osd_reg_read(0x3a13 + i);
	for (i = 0; i < 6; i++)
		reg_value[55 + i] = osd_reg_read(0x3a33 + i);
	for (i = 0; i < 6; i++)
		reg_value[61 + i] = osd_reg_read(0x3a53 + i);
	reg_value[68] = osd_reg_read(0x1a1b) & 0xff7f;
	reg_value[69] = osd_reg_read(0x1a3b) & 0xff7f;
	reg_value[70] = osd_reg_read(0x3d88) & 0xff7f;

	for (i = 0; i < 72; i++) {
		if (reg_value[i] != reg_value_pre[i]) {
			if (i < 7)
				pr_info("Debug [0x%x] changed,pre:%x, now:%x\n",
					0x39b0 + i,
					reg_value_pre[i], reg_value[i]);
			else if (i >= 13 && i < 25)
				pr_info("Debug [0x%x] changed,pre:%x, now:%x\n",
					0x1dc0 + i - 13,
					reg_value_pre[i], reg_value[i]);
			else if (i >= 25 && i < 37)
				pr_info("Debug [0x%x] changed,pre:%x, now:%x\n",
					0x3d00 + i - 25,
					reg_value_pre[i], reg_value[i]);
			else if (i >= 37 && i < 49)
				pr_info("Debug [0x%x] changed,pre:%x, now:%x\n",
					0x3d20 + i - 37,
					reg_value_pre[i], reg_value[i]);
			else if (i >= 49 && i < 55)
				pr_info("Debug [0x%x] changed,pre:%x, now:%x\n",
					0x3a13 + i - 49,
					reg_value_pre[i], reg_value[i]);
			else if (i >= 55 && i < 61)
				pr_info("Debug [0x%x] changed,pre:%x, now:%x\n",
					0x3a33 + i - 55,
					reg_value_pre[i], reg_value[i]);
			else if (i >= 61 && i < 67)
				pr_info("Debug [0x%x] changed,pre:%x, now:%x\n",
					0x3a53 + i - 61,
					reg_value_pre[i], reg_value[i]);
			else if (i == 7)
				pr_info("Debug [0x39bb] changed,pre:%x, now:%x\n",
					reg_value_pre[i], reg_value[i]);
			else if (i == 8)
				pr_info("Debug [0x1df1] changed,pre:%x, now:%x\n",
					reg_value_pre[i], reg_value[i]);
			else if (i == 9)
				pr_info("Debug [0x1df5] changed,pre:%x, now:%x\n",
					reg_value_pre[i], reg_value[i]);
			else if (i == 10)
				pr_info("Debug [0x1df6] changed,pre:%x, now:%x\n",
					reg_value_pre[i], reg_value[i]);
			else if (i == 11)
				pr_info("Debug [0x1d21] changed,pre:%x, now:%x\n",
					reg_value_pre[i], reg_value[i]);
			else if (i == 12)
				pr_info("Debug [0x1da5] changed,pre:%x, now:%x\n",
					reg_value_pre[i], reg_value[i]);
			else if (i == 68)
				pr_info("Debug [0x1a1b] changed,pre:%x, now:%x\n",
					reg_value_pre[i], reg_value[i]);
			else if (i == 69)
				pr_info("Debug [0x1a3b] changed,pre:%x, now:%x\n",
					reg_value_pre[i], reg_value[i]);
			else if (i == 70)
				pr_info("Debug [0x3d88] changed,pre:%x, now:%x\n",
					reg_value_pre[i], reg_value[i]);
		}
	}

	for (i = 0; i < 72; i++)
		reg_value_pre[i] = reg_value[i];
}

/* for c3 irq clr*/
static void irq_clr_c3(void)
{
	u32 data32;

	data32 = osd_reg_read(VPU_VOUT_IRQ_CTRL);
	data32 |= 0x01;
	osd_reg_write(VPU_VOUT_IRQ_CTRL, data32);
}

#ifdef FIQ_VSYNC
static irqreturn_t vsync_isr(int irq, void *dev_id)
{
	if (suspend_flag)
		return IRQ_HANDLED;
	wait_vsync_wakeup();
	return IRQ_HANDLED;
}

static void osd_fiq_isr(void)
#else
static irqreturn_t vsync_isr(int irq, void *dev_id)
#endif
{
	if (suspend_flag) {
		if (osd_log_out)
			pr_info("osd suspend, vsync exit\n");
		osd_log_out = 0;
		return IRQ_HANDLED;
	}
	if (!osd_hw.hw_rdma_en) {
		if (osd_dev_hw.display_type == C3_DISPLAY)
			irq_clr_c3();
#ifdef CONFIG_AMLOGIC_VOUT
		osd_update_vsync_timestamp();
#endif
		osd_update_scan_mode();
		/* go through update list */
		walk_through_update_list();
		osd_update_3d_mode();
		osd_mali_afbc_start(VIU1);
		osd_update_vsync_hit();
		osd_hw_reset(VIU1);
	} else {
		osd_update_vsync_timestamp();
		osd_rdma_interrupt_done_clear(VPU_VPP0);
	}
	if (osd_hw.osd_reg_check)
		check_reg_changed();
#ifndef FIQ_VSYNC
	return IRQ_HANDLED;
#endif
}

#ifdef FIQ_VSYNC
static irqreturn_t vsync_viu2_isr(int irq, void *dev_id)
{
	return IRQ_HANDLED;
}

static void osd_viu2_fiq_isr(void)
#else
static irqreturn_t vsync_viu2_isr(int irq, void *dev_id)
#endif
{
	if (suspend_flag)
		return IRQ_HANDLED;
	/* osd_update_scan_mode_viu2(); */
	osd_update_vsync_timestamp_viu2();
#ifndef FIQ_VSYNC
	return IRQ_HANDLED;
#endif
}

#ifdef FIQ_VSYNC
static irqreturn_t vsync_viu3_isr(int irq, void *dev_id)
{
	return IRQ_HANDLED;
}

static void vsync_viu3_isr(void)
#else
static irqreturn_t vsync_viu3_isr(int irq, void *dev_id)
#endif
{
	if (suspend_flag)
		return IRQ_HANDLED;
	/* osd_update_scan_mode_viu2(); */
	osd_update_vsync_timestamp_viu3();
	osd_update_vsync_hit_viu3();
#ifndef FIQ_VSYNC
	return IRQ_HANDLED;
#endif
}

void osd_set_pxp_mode(u32 mode)
{
	pxp_mode = mode;
}

void osd_set_afbc(u32 index, u32 enable)
{
	if (osd_hw.osd_meson_dev.afbc_type)
		osd_hw.osd_afbcd[index].enable = enable;
	osd_log_info("afbc_type=%d,enable=%d\n",
		     osd_hw.osd_meson_dev.afbc_type,
		     osd_hw.osd_afbcd[index].enable);
}

u32 osd_get_afbc(u32 index)
{
	u32 afbc_type = 0;

	if (osd_hw.osd_meson_dev.cpu_id ==
		__MESON_CPU_MAJOR_ID_GXM)
		afbc_type = 1;
	else if (osd_hw.osd_meson_dev.cpu_id >=
		__MESON_CPU_MAJOR_ID_G12A)
		afbc_type = 2;
	else
		afbc_type = 0;
	return afbc_type;
}

u32 osd_get_reset_status(void)
{
	return osd_hw.hw_reset_flag;
}

static void osd_wait_vsync_hw_viux(u32 output_index)
{
	unsigned long timeout;
	wait_queue_head_t *wait_queue = &osd_rdma_vpp0_done_wq;

	if (osd_hw.fb_drvier_probe) {
		/* for the independent viu2 HW module,
		 * use the latch, waiting for vsync (not rdma interrupt).
		 */
		if (osd_hw.osd_meson_dev.has_viu2 && output_index == VIU2) {
			osd_wait_vsync_event_viu2();
			return;
		}

		vsync_hit[output_index] = false;

		if (pxp_mode) {
			timeout = msecs_to_jiffies(50);
		} else {
			struct vinfo_s *vinfo = NULL;

			switch (output_index) {
			case VIU1:
				#ifdef CONFIG_AMLOGIC_VOUT_SERVE
				vinfo = get_current_vinfo();
				#endif
				wait_queue = &osd_rdma_vpp0_done_wq;
				break;
			case VIU2:
				#ifdef CONFIG_AMLOGIC_VOUT2_SERVE
				vinfo = get_current_vinfo2();
				#endif
				wait_queue = &osd_rdma_vpp1_done_wq;
				break;
			case VIU3:
				#ifdef CONFIG_AMLOGIC_VOUT3_SERVE
				vinfo = get_current_vinfo3();
				#endif
				wait_queue = &osd_rdma_vpp2_done_wq;
				break;
			default:
				osd_log_err("%s, set output_index %u error\n",
					    __func__, output_index);
				break;

			};
			if (vinfo && vinfo->name &&
			    (!strcmp(vinfo->name, "invalid") ||
			     !strcmp(vinfo->name, "null")))
				timeout = msecs_to_jiffies(1);
			else
				timeout = msecs_to_jiffies(1000);
		}
		wait_event_interruptible_timeout(*wait_queue,
						 vsync_hit[output_index], timeout);
	}
}

void osd_wait_vsync_hw(u32 index)
{
	u32 output_index = get_output_device_id(index);

	osd_wait_vsync_hw_viux(output_index);
}

s64 osd_wait_vsync_event(void)
{
	unsigned long timeout;
	ktime_t stime;

	stime = ktime_get();
	if (pxp_mode)
		timeout = msecs_to_jiffies(50);
	else
		timeout = msecs_to_jiffies(1000);

	/* waiting for 10ms. */
	wait_event_interruptible_timeout(osd_vsync_wq,
		(timestamp[VIU1] > stime) ? true : false, timeout);
	return timestamp[VIU1];
}

s64 osd_wait_vsync_event_viu2(void)
{
	unsigned long timeout;
	ktime_t stime;

	stime = ktime_get();

	if (pxp_mode)
		timeout = msecs_to_jiffies(50);
	else
		timeout = msecs_to_jiffies(1000);

	/* waiting for 10ms. */
	wait_event_interruptible_timeout(osd_vsync2_wq,
		(timestamp[VIU2] > stime) ? true : false, timeout);

	return timestamp[VIU2];
}

s64 osd_wait_vsync_event_viu3(void)
{
	unsigned long timeout;
	ktime_t stime;

	stime = ktime_get();

	if (pxp_mode)
		timeout = msecs_to_jiffies(50);
	else
		timeout = msecs_to_jiffies(1000);

	/* waiting for 10ms. */
	wait_event_interruptible_timeout(osd_vsync3_wq,
		(timestamp[VIU3] > stime) ? true : false, timeout);

	return timestamp[VIU3];
}

int is_interlaced(struct vinfo_s *vinfo)
{
	if (!vinfo)
		return 0;
	if (vinfo->mode == VMODE_CVBS)
		return 1;
	if (vinfo->height != vinfo->field_height)
		return 1;
	else
		return 0;
}

int osd_set_scan_mode(u32 index)
{
	struct vinfo_s *vinfo = NULL;
	u32 data32 = 0x0;
	s32 y_end = 0;
	u32 output_index;
	u32 scale_input_w;

	output_index = get_output_device_id(index);
	osd_hw.scan_mode[index] = SCAN_MODE_PROGRESSIVE;
	if (output_index == VIU1)
#ifdef CONFIG_AMLOGIC_VOUT_SERVE
		vinfo = get_current_vinfo();
#endif
#ifdef CONFIG_AMLOGIC_VOUT2_SERVE
		else if (output_index == VIU2)
			vinfo = get_current_vinfo2();
#endif
	if (vinfo && vinfo->name && (strcmp(vinfo->name, "invalid") &&
		      strcmp(vinfo->name, "null"))) {
		osd_hw.scale_workaround = 0;
		if (osd_auto_adjust_filter) {
			osd_h_filter_mode = 1;
			osd_v_filter_mode = 1;
		}

		scale_input_w = osd_hw.free_src_data[index].x_end -
				osd_hw.free_src_data[index].x_start + 1;
		if ((osd_hw.fb_for_4k2k ||
		     scale_input_w > FREE_SCALE_MAX_WIDTH) &&
		    osd_hw.free_scale_enable[index])
			osd_hw.scale_workaround = 1;

		if (is_interlaced(vinfo)) {
			osd_hw.scan_mode[index] = SCAN_MODE_INTERLACE;
			if (osd_hw.osd_meson_dev.osd_ver == OSD_NORMAL)
				osd_hw.scan_mode[OSD2] = SCAN_MODE_INTERLACE;
			y_end = osd_hw.free_src_data[index].y_end;
			if (vinfo->width == 720 &&
			    vinfo->height == 480) {
				if (osd_hw.free_scale_mode[index]) {
					osd_hw.field_out_en[output_index] = 1;
					switch (y_end) {
					case 719:
						osd_hw.bot_type = 2;
						break;
					case 1079:
						osd_hw.bot_type = 3;
						break;
					default:
						osd_hw.bot_type = 2;
						break;
					}
				}
				if (osd_auto_adjust_filter) {
					osd_h_filter_mode = 6;
					osd_v_filter_mode = 6;
				}
			} else if (vinfo->width == 720 &&
				vinfo->height == 576) {
				if (osd_hw.free_scale_mode[index]) {
					osd_hw.field_out_en[output_index] = 1;
					switch (y_end) {
					case 719:
						osd_hw.bot_type = 2;
						break;
					case 1079:
						osd_hw.bot_type = 2;
						break;
					default:
						osd_hw.bot_type = 2;
						break;
					}
				}
				if (osd_auto_adjust_filter) {
					osd_h_filter_mode = 6;
					osd_v_filter_mode = 6;
				}

			} else if (vinfo->width == 1920 &&
				vinfo->height == 1080) {
				if (osd_hw.free_scale_mode[index]) {
					osd_hw.field_out_en[output_index] = 1;
					switch (y_end) {
					case 719:
						osd_hw.bot_type = 1;
						break;
					case 1079:
						osd_hw.bot_type = 2;
						break;
					default:
						osd_hw.bot_type = 1;
						break;
					}
				}
			}
		} else {
			if (vinfo->height >= 2160) {
				osd_hw.field_out_en[output_index] = 0;
				if (osd_auto_adjust_filter) {
					osd_h_filter_mode = 1;
					if (vinfo &&
						(!strcmp(vinfo->name, "2160p60hz420") ||
						 !strcmp(vinfo->name, "2160p50hz420")))
						osd_v_filter_mode = 2;
					else
						osd_v_filter_mode = 1;
				}
			} else if (vinfo->height >= 1080) {
				if (osd_auto_adjust_filter) {
					osd_h_filter_mode = 1;
					osd_v_filter_mode = 1;
				}
			} else if (vinfo->height >= 720) {
				if (osd_auto_adjust_filter) {
					osd_h_filter_mode = 7;
					osd_v_filter_mode = 7;
				}
				if (osd_hw.free_scale_mode[index])
					osd_hw.field_out_en[output_index] = 0;
			} else {
				if (osd_hw.free_scale_mode[index])
					osd_hw.field_out_en[output_index] = 0;
			}
		}
	}
	if (osd_hw.free_scale_enable[index])
		osd_hw.scan_mode[index] = SCAN_MODE_PROGRESSIVE;
	if (osd_hw.osd_afbcd[index].enable)
		osd_hw.scan_mode[index] = SCAN_MODE_PROGRESSIVE;
	if (index == OSD2) {
		if (osd_hw.scan_mode[OSD2] == SCAN_MODE_INTERLACE)
			return 1;
		data32 = (osd_hw.osd_rdma_func[output_index].osd_rdma_rd
			(hw_osd_reg_array[index].osd_blk0_cfg_w0) & 3) >> 1;
	} else {
		data32 = (osd_hw.osd_rdma_func[output_index].osd_rdma_rd
			(hw_osd_reg_array[index].osd_blk0_cfg_w0) & 3) >> 1;
	}
	if (data32 == osd_hw.scan_mode[index])
		return 1;
	else
		return 0;
}

void  osd_set_gbl_alpha_hw(u32 index, u32 gbl_alpha)
{
	/* normalized */
	if (gbl_alpha == 0xff)
		gbl_alpha = 0x100;
	if (osd_hw.gbl_alpha[index] != gbl_alpha) {
		osd_hw.gbl_alpha[index] = gbl_alpha;
		add_to_update_list(index, OSD_GBL_ALPHA);
		osd_wait_vsync_hw(index);
	}
}

u32 osd_get_gbl_alpha_hw(u32  index)
{
	return osd_hw.gbl_alpha[index];
}

void  osd_set_line_n_rdma(u32 line_n_rdma)
{
	if (osd_hw.line_n_rdma != line_n_rdma) {
		osd_hw.line_n_rdma = line_n_rdma;
		if (osd_hw.line_n_rdma)
			enable_line_n_rdma();
		else
			enable_vsync_rdma(VPU_VPP0);
	}
}

u32 osd_get_line_n_rdma(void)
{
	return osd_hw.line_n_rdma;
}

void osd_set_blend_bypass(int index, u32 blend_bypass)
{
	if (blend_bypass != osd_hw.blend_bypass[index]) {
		osd_hw.blend_bypass[index] = blend_bypass;
		if (blend_bypass) {
			VSYNCOSD_WR_MPEG_REG_BITS
				(hw_osd_reg_array[index].osd_mali_unpack_ctrl,
				0x0, 28, 1);
			if (osd_dev_hw.new_blend_bypass) {
				VSYNCOSD_WR_MPEG_REG_BITS
					(hw_osd_reg_array[index].vpp_osd1_scale_ctrl,
					0x1, 2, 1);
			} else {
				VSYNCOSD_WR_MPEG_REG_BITS
					(hw_osd_reg_blend.osd_blend_ctrl,
					0x1, 26, 1);
			}
		} else {
			if (osd_dev_hw.new_blend_bypass) {
				VSYNCOSD_WR_MPEG_REG_BITS
					(hw_osd_reg_array[index].vpp_osd1_scale_ctrl,
					0x0, 2, 1);
			} else {
				VSYNCOSD_WR_MPEG_REG_BITS
					(hw_osd_reg_blend.osd_blend_ctrl,
					0x0, 26, 1);
			}
		}
	}
}

u32 osd_get_blend_bypass(u32 index)
{
	return osd_hw.blend_bypass[index];
}

void osd_set_color_key_hw(u32 index, u32 color_index, u32 colorkey)
{
	u8 r = 0, g = 0, b = 0, a = (colorkey & 0xff000000) >> 24;
	u32 data32;

	colorkey &= 0x00ffffff;
	switch (color_index) {
	case COLOR_INDEX_16_655:
		r = (colorkey >> 10 & 0x3f) << 2;
		g = (colorkey >> 5 & 0x1f) << 3;
		b = (colorkey & 0x1f) << 3;
		break;
	case COLOR_INDEX_16_844:
		r = colorkey >> 8 & 0xff;
		g = (colorkey >> 4 & 0xf) << 4;
		b = (colorkey & 0xf) << 4;
		break;
	case COLOR_INDEX_16_565:
		r = (colorkey >> 11 & 0x1f) << 3;
		g = (colorkey >> 5 & 0x3f) << 2;
		b = (colorkey & 0x1f) << 3;
		break;
	case COLOR_INDEX_24_888_B:
		b = colorkey >> 16 & 0xff;
		g = colorkey >> 8 & 0xff;
		r = colorkey & 0xff;
		break;
	case COLOR_INDEX_24_RGB:
	case COLOR_INDEX_YUV_422:
		r = colorkey >> 16 & 0xff;
		g = colorkey >> 8 & 0xff;
		b = colorkey & 0xff;
		break;
	}
	data32 = r << 24 | g << 16 | b << 8 | a;
	if (osd_hw.color_key[index] != data32) {
		osd_hw.color_key[index] = data32;
		osd_log_dbg2(MODULE_BASE,
			     "bpp:%d--r:0x%x g:0x%x b:0x%x ,a:0x%x\n",
			     color_index, r, g, b, a);
		add_to_update_list(index, OSD_COLOR_KEY);
		osd_wait_vsync_hw(index);
	}
}

void  osd_srckey_enable_hw(u32  index, u8 enable)
{
	if (enable != osd_hw.color_key_enable[index]) {
		osd_hw.color_key_enable[index] = enable;
		add_to_update_list(index, OSD_COLOR_KEY_ENABLE);
		osd_wait_vsync_hw(index);
	}
}

void osd_set_color_mode(u32 index, const struct color_bit_define_s *color)
{
	if (color != osd_hw.color_info[index]) {
		osd_hw.color_info[index] = color;
		osd_hw.color_backup[index] = color;
		add_to_update_list(index, OSD_COLOR_MODE);
	}
}

void osd_update_disp_axis_hw(u32 index,
			     u32 display_h_start,
			     u32 display_h_end,
			     u32 display_v_start,
			     u32 display_v_end,
			     u32 xoffset,
			     u32 yoffset,
			     u32 mode_change)
{
	struct pandata_s disp_data;
	struct pandata_s pan_data;

	if (!osd_hw.color_info[index])
		return;
	disp_data.x_start = display_h_start;
	disp_data.y_start = display_v_start;
	disp_data.x_end = display_h_end;
	disp_data.y_end = display_v_end;
	pan_data.x_start = xoffset;
	pan_data.x_end = xoffset +
		osd_hw.pandata[index].x_end -
		osd_hw.pandata[index].x_start;
#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
	pan_data.y_start = osd_hw.pandata[index].y_start;
	pan_data.y_end = osd_hw.pandata[index].y_start +
		osd_hw.pandata[index].y_end - osd_hw.pandata[index].y_start;
#else
	pan_data.y_start = yoffset;
	pan_data.y_end = yoffset +
		osd_hw.pandata[index].y_end - osd_hw.pandata[index].y_start;
#endif
	/* if output mode change then reset pan ofFfset. */
	memcpy(&osd_hw.pandata[index], &pan_data, sizeof(struct pandata_s));
	memcpy(&osd_hw.dispdata[index], &disp_data, sizeof(struct pandata_s));
	memcpy(&osd_hw.dispdata_backup[index],
	       &disp_data, sizeof(struct pandata_s));
	osd_log_info("%s:pan_data(%d,%d,%d,%d)\n",
		     __func__,
		     pan_data.x_start,
		     pan_data.y_start,
		     pan_data.x_end,
		     pan_data.y_end);
	osd_log_info("%s:dispdata(%d,%d,%d,%d)\n",
		     __func__,
		     disp_data.x_start,
		     disp_data.y_start,
		     disp_data.x_end,
		     disp_data.y_end);
	spin_lock_irqsave(&osd_lock, lock_flags);
	if (mode_change) /* modify pandata . */
		osd_hw.reg[OSD_COLOR_MODE].update_func(index);
	osd_hw.reg[DISP_GEOMETRY].update_func(index);
	osd_update_window_axis = true;
	spin_unlock_irqrestore(&osd_lock, lock_flags);
	osd_wait_vsync_hw(index);
}

void osd_setup_hw(u32 index,
		  struct osd_ctl_s *osd_ctl,
		  u32 xoffset,
		  u32 yoffset,
		  u32 xres,
		  u32 yres,
		  u32 xres_virtual,
		  u32 yres_virtual,
		  u32 disp_start_x,
		  u32 disp_start_y,
		  u32 disp_end_x,
		  u32 disp_end_y,
		  phys_addr_t fbmem,
		  phys_addr_t *afbc_fbmem,
		  const struct color_bit_define_s *color)
{
	struct pandata_s disp_data;
	struct pandata_s pan_data;
	int update_color_mode = 0;
	int update_geometry = 0;
	u32 w = (color->bpp * xres_virtual + 7) >> 3;
	u32 i;

	osd_hw.buffer_alloc[index] = 1;
	pan_data.x_start = xoffset;
	pan_data.y_start = yoffset;
	disp_data.x_start = disp_start_x;
	disp_data.y_start = disp_start_y;

	pan_data.x_end = xoffset + xres - 1;
	pan_data.y_end = yoffset + yres - 1;
	disp_data.x_end = disp_end_x;
	disp_data.y_end = disp_end_y;

	/* need always set color mode for osd2 */
	if (color != osd_hw.color_info[index] ||
	    (index == (osd_hw.osd_meson_dev.osd_count - 1))) {
		update_color_mode = 1;
		osd_hw.color_info[index] = color;
		osd_hw.color_backup[index] = color;
	}

	if (osd_hw.fb_gem[index].addr != fbmem ||
	    osd_hw.fb_gem[index].width != w ||
	    osd_hw.fb_gem[index].height != yres_virtual) {
		osd_hw.fb_gem[index].addr = fbmem;
		osd_hw.fb_gem[index].width = w;
		osd_hw.fb_gem[index].height = yres_virtual;
		if (osd_hw.osd_afbcd[index].enable == ENABLE &&
		    afbc_fbmem) {
			osd_hw.osd_afbcd[index].frame_width = xres;
			/* osd_hw.osd_afbcd[index].frame_height =
			 *	ALIGN_CALC(yres, 16) +
			 *	ALIGN_CALC(yres, 64) / 64;
			 */
			osd_hw.osd_afbcd[index].frame_height = yres;
			for (i = 0; i < OSD_MAX_BUF_NUM; i++)
				osd_hw.osd_afbcd[index].addr[i] =
					afbc_fbmem[i];
			osd_hw.osd_afbcd[index].phy_addr =
				osd_hw.osd_afbcd[index].addr[0];

			/* we need update geometry
			 * and color mode for afbc mode
			 * update_geometry = 1;
			 * update_color_mode = 1;
			 */
			if (osd_hw.osd_meson_dev.afbc_type == MESON_AFBC) {
				if (xres <= 128)
					osd_hw.osd_afbcd[index]
					    .conv_lbuf_len = 32;
				else if (xres <= 256)
					osd_hw.osd_afbcd[index]
					    .conv_lbuf_len = 64;
				else if (xres <= 512)
					osd_hw.osd_afbcd[index]
					    .conv_lbuf_len = 128;
				else if (xres <= 1024)
					osd_hw.osd_afbcd[index]
					    .conv_lbuf_len = 256;
				else if (xres <= 2048)
					osd_hw.osd_afbcd[index]
					    .conv_lbuf_len = 512;
				else
					osd_hw.osd_afbcd[index]
					    .conv_lbuf_len = 1024;
			} else if (osd_hw.osd_meson_dev.afbc_type
			    == MALI_AFBC)
				osd_hw.osd_afbcd[index].out_addr_id = index + 1;
		}
		osd_hw.fb_gem[index].xres = xres;
		osd_hw.fb_gem[index].yres = yres;
		osd_log_info("osd[%d] canvas.idx =0x%x\n",
			     index, osd_hw.fb_gem[index].canvas_idx);
		osd_log_info("osd[%d] canvas.addr=0x%lx\n",
			     index, osd_hw.fb_gem[index].addr);
		osd_log_info("osd[%d] canvas.width=%d\n",
			     index, osd_hw.fb_gem[index].width);
		osd_log_info("osd[%d] canvas.height=%d\n",
			     index, osd_hw.fb_gem[index].height);
		osd_log_info("osd[%d] frame.width=%d\n",
			     index, osd_hw.fb_gem[index].xres);
		osd_log_info("osd[%d] frame.height=%d\n",
			     index, osd_hw.fb_gem[index].yres);
		osd_log_info("osd[%d] out_addr_id =0x%x\n",
			     index, osd_hw.osd_afbcd[index].out_addr_id);

		if (osd_hw.osd_meson_dev.osd_ver == OSD_SIMPLE &&
		osd_dev_hw.display_type != C3_DISPLAY)
			osd_update_phy_addr(0);
		else if (osd_hw.osd_meson_dev.mif_linear)
			osd_update_mif_linear_addr(index);
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
		else
			canvas_config(osd_hw.fb_gem[index].canvas_idx,
				      osd_hw.fb_gem[index].addr,
				      CANVAS_ALIGNED
				      (osd_hw.fb_gem[index].width),
				      osd_hw.fb_gem[index].height,
				      CANVAS_ADDR_NOWRAP,
				      CANVAS_BLKMODE_LINEAR);
#endif
	}

	/* osd blank only control by /sys/class/graphics/fbx/blank */
	if (memcmp(&pan_data, &osd_hw.pandata[index],
		   sizeof(struct pandata_s)) != 0 ||
	    memcmp(&disp_data, &osd_hw.dispdata[index],
		   sizeof(struct pandata_s)) != 0) {
		update_geometry = 1;
		memcpy(&osd_hw.pandata[index], &pan_data,
		       sizeof(struct pandata_s));
		memcpy(&osd_hw.dispdata[index], &disp_data,
		       sizeof(struct pandata_s));
		memcpy(&osd_hw.dispdata_backup[index], &disp_data,
		       sizeof(struct pandata_s));
		osd_hw.src_data[index].x = osd_hw.pandata[index].x_start;
		osd_hw.src_data[index].y = osd_hw.pandata[index].y_start;
		osd_hw.src_data[index].w = osd_hw.pandata[index].x_end
			- osd_hw.pandata[index].x_start + 1;
		osd_hw.src_data[index].h = osd_hw.pandata[index].y_end
			- osd_hw.pandata[index].y_start + 1;
		osd_update_disp_src_size(index);
	}
	spin_lock_irqsave(&osd_lock, lock_flags);
	if (update_color_mode)
		osd_hw.reg[OSD_COLOR_MODE].update_func(index);
	if (update_geometry)
		osd_hw.reg[DISP_GEOMETRY].update_func(index);
	spin_unlock_irqrestore(&osd_lock, lock_flags);

	if (osd_hw.antiflicker_mode)
		osd_antiflicker_update_pan(yoffset, yres);
	if (osd_hw.clone[index])
		osd_clone_pan(index, yoffset, 0);
#ifdef CONFIG_AMLOGIC_MEDIA_FB_EXT
	osd_ext_clone_pan(index);
#endif
	osd_wait_vsync_hw(index);
}

void osd_setpal_hw(u32 index,
		   unsigned int regno,
		   unsigned int red,
		   unsigned int green,
		   unsigned int blue,
		   unsigned int transp
		  )
{
	u32 output_index = get_output_device_id(index);

	if (osd_hw.osd_meson_dev.has_lut) {
		if (regno < 256) {
			u32 pal;

			pal = ((red   & 0xff) << 24) |
			      ((green & 0xff) << 16) |
			      ((blue  & 0xff) <<  8) |
			      (transp & 0xff);
			spin_lock_irqsave(&osd_lock, lock_flags);
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr
				(hw_osd_reg_array[index].osd_color_addr,
				regno);
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr
				(hw_osd_reg_array[index].osd_color, pal);
			spin_unlock_irqrestore(&osd_lock, lock_flags);
		}
	}
}

void osd_get_order_hw(u32 index, u32 *order)
{
	*order = osd_hw.order[index] & 0x3;
}

void osd_set_order_hw(u32 index, u32 order)
{
	osd_hw.order[index] = order;
	//add_to_update_list(index, OSD_CHANGE_ORDER);
	//osd_wait_vsync_hw();
}

/* osd free scale mode */
static void osd_set_free_scale_enable_mode1(u32 index, u32 enable)
{
	unsigned int h_enable = 0;
	unsigned int v_enable = 0;
	int ret = 0;

	if (osd_hw.osd_meson_dev.osd_ver == OSD_SIMPLE &&
		osd_dev_hw.display_type != C3_DISPLAY)
		return;
	h_enable = (enable & 0xffff0000 ? 1 : 0);
	v_enable = (enable & 0xffff ? 1 : 0);
	osd_hw.free_scale[index].h_enable = h_enable;
	osd_hw.free_scale[index].v_enable = v_enable;
	osd_hw.free_scale_backup[index].h_enable = h_enable;
	osd_hw.free_scale_backup[index].v_enable = v_enable;
	osd_hw.free_scale_enable[index] = enable;
	osd_hw.free_scale_enable_backup[index] = enable;
	if (osd_hw.free_scale_enable[index]) {
		ret = osd_set_scan_mode(index);
		spin_lock_irqsave(&osd_lock, lock_flags);
		if (ret)
			osd_hw.reg[OSD_COLOR_MODE].update_func(index);
		osd_hw.reg[OSD_FREESCALE_COEF].update_func(index);
		osd_hw.reg[DISP_GEOMETRY].update_func(index);
		osd_hw.reg[DISP_FREESCALE_ENABLE].update_func(index);
		osd_hw.reg[OSD_ENABLE].update_func(index);
		spin_unlock_irqrestore(&osd_lock, lock_flags);
	} else {
		ret = osd_set_scan_mode(index);
		spin_lock_irqsave(&osd_lock, lock_flags);
		if (ret)
			osd_hw.reg[OSD_COLOR_MODE].update_func(index);
		osd_hw.reg[DISP_GEOMETRY].update_func(index);
		osd_hw.reg[DISP_FREESCALE_ENABLE].update_func(index);
		osd_hw.reg[OSD_ENABLE].update_func(index);
		spin_unlock_irqrestore(&osd_lock, lock_flags);
	}
	if (get_osd_hwc_type(index) != OSD_G12A_NEW_HWC &&
	    osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE) {
		u32 output_index = VIU1;
		u32 background_w = 0, background_h = 0;
		u32 position_x = 0, position_y = 0;
		u32 position_w = 0, position_h = 0;

		background_w =
			osd_hw.free_src_data[index].x_end -
			osd_hw.free_src_data[index].x_start + 1;
		background_h =
			osd_hw.free_src_data[index].y_end -
			osd_hw.free_src_data[index].y_start + 1;

		position_x = osd_hw.free_dst_data[index].x_start;
		position_y = osd_hw.free_dst_data[index].y_start;
		position_w = osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		position_h = osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;

		output_index = get_output_device_id(index);
		osd_hw.disp_info[output_index].background_w =
			background_w;
		osd_hw.disp_info[output_index].background_h =
			background_h;

		osd_hw.disp_info[output_index].position_x = position_x;
		osd_hw.disp_info[output_index].position_y = position_x;
		osd_hw.disp_info[output_index].position_w = position_w;
		osd_hw.disp_info[output_index].position_h = position_h;

		osd_setting_default_hwc();
	}

	if (osd_dev_hw.display_type == C3_DISPLAY)
		osd_setting_vout_blend();
	osd_wait_vsync_hw(index);
}

void osd_set_free_scale_enable_hw(u32 index, u32 enable)
{
	if (osd_hw.free_scale_mode[index] &&
	    (osd_hw.osd_meson_dev.has_viu2 ?
	     (index != osd_hw.osd_meson_dev.viu2_index ?
	     1 : 0) : 1)) {
		osd_set_free_scale_enable_mode1(index, enable);
		if (osd_hw.osd_meson_dev.osd_ver == OSD_NORMAL ||
			osd_dev_hw.display_type == C3_DISPLAY) {
			u32 height_dst, height_src;

			height_dst = osd_hw.free_dst_data[index].y_end -
				osd_hw.free_dst_data[index].y_start + 1;
			height_src = osd_hw.free_src_data[index].y_end -
				osd_hw.free_src_data[index].y_start + 1;
			if (height_dst != height_src &&
			    osd_hw.free_dst_data[index].y_end <
			    osd_hw.vinfo_height[VIU1] - 1)
				osd_set_dummy_data(index, 0);
			else
				osd_set_dummy_data(index, 0xff);
		}
	} else if (enable)
		osd_log_info("osd[%d] %s mode is error %d\n",
			     index, __func__,
			     osd_hw.free_scale_mode[index]);
}

void osd_get_free_scale_enable_hw(u32 index, u32 *free_scale_enable)
{
	*free_scale_enable = osd_hw.free_scale_enable[index];
}

void osd_set_free_scale_mode_hw(u32 index, u32 freescale_mode)
{
	osd_hw.free_scale_mode[index] = freescale_mode;
	osd_hw.free_scale_mode_backup[index] = freescale_mode;
}

void osd_get_free_scale_mode_hw(u32 index, u32 *freescale_mode)
{
	*freescale_mode = osd_hw.free_scale_mode[index];
}

void osd_set_4k2k_fb_mode_hw(u32 fb_for_4k2k)
{
	osd_hw.fb_for_4k2k = fb_for_4k2k;
}

void osd_get_free_scale_width_hw(u32 index, u32 *free_scale_width)
{
	*free_scale_width = osd_hw.free_src_data_backup[index].x_end -
		osd_hw.free_src_data_backup[index].x_start + 1;
}

void osd_get_free_scale_height_hw(u32 index, u32 *free_scale_height)
{
	*free_scale_height = osd_hw.free_src_data_backup[index].y_end -
		osd_hw.free_src_data_backup[index].y_start + 1;
}

void osd_get_free_scale_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, s32 *y1)
{
	*x0 = osd_hw.free_src_data_backup[index].x_start;
	*y0 = osd_hw.free_src_data_backup[index].y_start;
	*x1 = osd_hw.free_src_data_backup[index].x_end;
	*y1 = osd_hw.free_src_data_backup[index].y_end;
}

void osd_set_free_scale_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, s32 y1)
{
	osd_hw.free_src_data[index].x_start = x0;
	osd_hw.free_src_data[index].y_start = y0;
	osd_hw.free_src_data[index].x_end = x1;
	osd_hw.free_src_data[index].y_end = y1;
	osd_hw.free_src_data_backup[index].x_start = x0;
	osd_hw.free_src_data_backup[index].y_start = y0;
	osd_hw.free_src_data_backup[index].x_end = x1;
	osd_hw.free_src_data_backup[index].y_end = y1;
	osd_hw.src_data[index].x = x0;
	osd_hw.src_data[index].y = y0;
	osd_hw.src_data[index].w = x1 - x0 + 1;
	osd_hw.src_data[index].h = y1 - y0 + 1;
}

void osd_get_scale_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, s32 *y1)
{
	*x0 = osd_hw.scaledata[index].x_start;
	*x1 = osd_hw.scaledata[index].x_end;
	*y0 = osd_hw.scaledata[index].y_start;
	*y1 = osd_hw.scaledata[index].y_end;
}

void osd_set_scale_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, s32 y1)
{
	osd_hw.scaledata[index].x_start = x0;
	osd_hw.scaledata[index].x_end = x1;
	osd_hw.scaledata[index].y_start = y0;
	osd_hw.scaledata[index].y_end = y1;
}

void osd_get_window_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, s32 *y1)
{
	struct vinfo_s *vinfo = NULL;
	s32 height;
	u32 output_index;

	output_index = get_output_device_id(index);
	if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL) {
		if (output_index == VIU1) {
#ifdef CONFIG_AMLOGIC_VOUT_SERVE
			vinfo = get_current_vinfo();
#endif
		}
#ifdef CONFIG_AMLOGIC_VOUT2_SERVE
		else if (output_index == VIU2)
			vinfo = get_current_vinfo2();
#endif
		if (vinfo && vinfo->name && (strcmp(vinfo->name, "invalid") &&
			      strcmp(vinfo->name, "null"))) {
			if (is_interlaced(vinfo)) {
				height = osd_hw.free_dst_data_backup[index]
					.y_end -
					osd_hw.free_dst_data_backup[index]
					.y_start + 1;
				height *= 2;
				*y0 = osd_hw.free_dst_data_backup[index]
					.y_start * 2;
				*y1 = height + *y0 - 1;
			} else {
				*y0 = osd_hw.free_dst_data_backup[index]
					.y_start;
				*y1 = osd_hw.free_dst_data_backup[index]
					.y_end;
			}
		} else {
			*y0 = osd_hw.free_dst_data_backup[index].y_start;
			*y1 = osd_hw.free_dst_data_backup[index].y_end;
		}
		*x0 = osd_hw.free_dst_data_backup[index].x_start;
		*x1 = osd_hw.free_dst_data_backup[index].x_end;
	} else {
		*x0 = osd_hw.dst_data[index].x;
		*y0 = osd_hw.dst_data[index].y;
		*x1 = osd_hw.dst_data[index].x +
			osd_hw.dst_data[index].w - 1;
		*y1 = osd_hw.dst_data[index].y +
			osd_hw.dst_data[index].h - 1;
	}
}

void osd_set_window_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, s32 y1)
{
	struct vinfo_s *vinfo = NULL;
	s32 temp_y0, temp_y1;
	u32 output_index;
	u32 height_dst, height_src;

	output_index = get_output_device_id(index);
	if (output_index == VIU1)
#ifdef CONFIG_AMLOGIC_VOUT_SERVE
		vinfo = get_current_vinfo();
#endif
#ifdef CONFIG_AMLOGIC_VOUT2_SERVE
	else if (output_index == VIU2)
		vinfo = get_current_vinfo2();
#endif
	mutex_lock(&osd_mutex);
	if (vinfo && vinfo->name && (strcmp(vinfo->name, "invalid") &&
		      strcmp(vinfo->name, "null"))) {
		if (is_interlaced(vinfo)) {
			temp_y0 = y0 / 2;
			temp_y1 = y1 / 2;
		} else {
			temp_y0 = y0;
			temp_y1 = y1;
		}
	} else {
		temp_y0 = y0;
		temp_y1 = y1;
	}

	/* use pi to scale up 2X for w and h */
	if (get_osd_hwc_type(index) != OSD_G12A_NEW_HWC) {
		if (osd_hw.osd_meson_dev.has_pi) {
			u32 w = x1 - x0 + 1;
			u32 h = temp_y1 - temp_y0 + 1;

			if (!osd_pi_debug) {
				if ((w > 3840 && h > 2160) ||
				    (w > 4096 && h > 2160))
					osd_hw.pi_enable = 1;
				else
					osd_hw.pi_enable = 0;
			} else {
				osd_hw.pi_enable = osd_pi_enable;
			}

			if (osd_hw.pi_enable) {
				osd_hw.pi_out.x_start = x0;
				osd_hw.pi_out.x_end = x1;
				osd_hw.pi_out.y_start = temp_y0;
				osd_hw.pi_out.y_end = temp_y1;

				w /= 2;
				h /= 2;

				x0 /= 2;
				x1 = x0 + w - 1;
				temp_y0 /= 2;
				temp_y1 = temp_y0 + h - 1;
			}
		}
	}

	osd_hw.free_dst_data[index].y_start = temp_y0;
	osd_hw.free_dst_data[index].y_end = temp_y1;
	osd_hw.free_dst_data[index].x_start = x0;
	osd_hw.free_dst_data[index].x_end = x1;
	osd_hw.free_dst_data_backup[index].y_start = temp_y0;
	osd_hw.free_dst_data_backup[index].y_end = temp_y1;
	osd_hw.free_dst_data_backup[index].x_start = x0;
	osd_hw.free_dst_data_backup[index].x_end = x1;
	if (osd_hw.hw_cursor_en) {
		osd_hw.cursor_dispdata[index].x_start = x0;
		osd_hw.cursor_dispdata[index].x_end = x1;
		osd_hw.cursor_dispdata[index].y_start = temp_y0;
		osd_hw.cursor_dispdata[index].y_end = temp_y1;
	}
	osd_hw.dst_data[index].x = x0;
	osd_hw.dst_data[index].y = y0;
	osd_hw.dst_data[index].w = x1 - x0 + 1;
	osd_hw.dst_data[index].h = y1 - y0 + 1;
	osd_log_dbg2(MODULE_BLEND,
		     "%s: osd%d orin dst(x:%d y:%d w:%d h:%d)\n",
		     __func__,
		     index, osd_hw.dst_data[index].x, osd_hw.dst_data[index].y,
		     osd_hw.dst_data[index].w, osd_hw.dst_data[index].h);

	height_dst = osd_hw.free_dst_data[index].y_end -
		osd_hw.free_dst_data[index].y_start + 1;
	height_src = osd_hw.free_src_data[index].y_end -
		osd_hw.free_src_data[index].y_start + 1;

	if (height_dst != height_src)
		osd_set_dummy_data(index, 0);
	else
		osd_set_dummy_data(index, 0xff);

	if (osd_hw.free_dst_data[index].y_end >= osd_hw.vinfo_height[output_index] - 1)
		osd_set_dummy_data(index, 0xff);
	osd_update_window_axis = true;
	osd_update_disp_dst_size(index);
	if (osd_hw.hwc_enable[output_index] &&
	    (osd_hw.osd_display_debug[output_index] == OSD_DISP_DEBUG ||
	    osd_hw.osd_display_fb[output_index]))

		osd_setting_blend(output_index);
	mutex_unlock(&osd_mutex);
}

void osd_set_src_position_from_reg(u32 index,
	s32 src_x_start, s32 src_x_end,
	s32 src_y_start, s32 src_y_end)
{
	struct hw_osd_reg_s *osd_reg = &hw_osd_reg_array[index];
	u32 data32 = 0x0;

	data32 = osd_reg_read(osd_reg->osd_blk0_cfg_w1);
	src_x_start = data32 & 0x1fff;
	src_x_end = (data32 >> 16) & 0x1fff;

	data32 = osd_reg_read(osd_reg->osd_blk0_cfg_w2);
	src_y_start = data32 & 0x1fff;
	src_y_end = (data32 >> 16) & 0x1fff;

	osd_set_free_scale_axis_hw(index, src_x_start, src_y_start,
					src_x_end, src_y_end);
}

s32 osd_get_position_from_reg(u32 index,
			      s32 *src_x_start, s32 *src_x_end,
			      s32 *src_y_start, s32 *src_y_end,
			      s32 *dst_x_start, s32 *dst_x_end,
			      s32 *dst_y_start, s32 *dst_y_end)
{
	struct hw_osd_reg_s *osd_reg = &hw_osd_reg_array[index];
	u32 data32 = 0x0;

	if (index >= OSD_MAX)
		return -1;

	if (!src_x_start || !src_x_end || !src_y_start || !src_y_end ||
	    !dst_y_start || !dst_x_end || !dst_y_start || !dst_y_end)
		return -1;

	data32 = osd_reg_read(osd_reg->osd_blk0_cfg_w1);
	*src_x_start = data32 & 0x1fff;
	*src_x_end = (data32 >> 16) & 0x1fff;

	data32 = osd_reg_read(osd_reg->osd_blk0_cfg_w2);
	*src_y_start = data32 & 0x1fff;
	*src_y_end = (data32 >> 16) & 0x1fff;

	if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE) {
		data32 = osd_reg_read(osd_reg->osd_sc_ctrl0);
		if ((data32 & 0xc) == 0xc) {
			data32 = osd_reg_read(osd_reg->osd_sco_h_start_end);
			*dst_x_end = data32 & 0x1fff;
			*dst_x_start = (data32 >> 16) & 0x1fff;

			data32 = osd_reg_read(osd_reg->osd_sco_v_start_end);
			*dst_y_end = data32 & 0x1fff;
			*dst_y_start = (data32 >> 16) & 0x1fff;
		} else {
			data32 = osd_reg_read(osd_reg->osd_blk0_cfg_w3);
			*dst_x_start = data32 & 0x1fff;
			*dst_x_end = (data32 >> 16) & 0x1fff;

			data32 = osd_reg_read(osd_reg->osd_blk0_cfg_w4);
			*dst_y_start = data32 & 0x1fff;
			*dst_y_end = (data32 >> 16) & 0x1fff;
		}
	} else if (osd_hw.osd_meson_dev.osd_ver == OSD_NORMAL) {
		s32 scaler_index = -1;

		osd_reg = &hw_osd_reg_array[0];
		data32 = osd_reg_read(osd_reg->osd_sc_ctrl0);

		if ((data32 & 3) == 0)
			scaler_index = 0;
		else if ((data32 & 3) == 1)
			scaler_index = 1;

		if (((data32 & 0xc) == 0xc) && ((u32)scaler_index == index)) {
			data32 = osd_reg_read(osd_reg->osd_sco_h_start_end);
			*dst_x_end = data32 & 0x1fff;
			*dst_x_start = (data32 >> 16) & 0x1fff;

			data32 = osd_reg_read(osd_reg->osd_sco_v_start_end);
			*dst_y_end = data32 & 0x1fff;
			*dst_y_start = (data32 >> 16) & 0x1fff;
		} else {
			osd_reg = &hw_osd_reg_array[index];
			data32 = osd_reg_read(osd_reg->osd_blk0_cfg_w3);
			*dst_x_start = data32 & 0x1fff;
			*dst_x_end = (data32 >> 16) & 0x1fff;

			data32 = osd_reg_read(osd_reg->osd_blk0_cfg_w4);
			*dst_y_start = data32 & 0x1fff;
			*dst_y_end = (data32 >> 16) & 0x1fff;
		}
	} else if (osd_hw.osd_meson_dev.osd_ver == OSD_SIMPLE ||
		osd_dev_hw.display_type == C3_DISPLAY) {
		osd_reg = &hw_osd_reg_array[0];
		data32 = osd_reg_read(osd_reg->osd_blk0_cfg_w3);
		*dst_x_start = data32 & 0x1fff;
		*dst_x_end = (data32 >> 16) & 0x1fff;

		data32 = osd_reg_read(osd_reg->osd_blk0_cfg_w4);
		*dst_y_start = data32 & 0x1fff;
		*dst_y_end = (data32 >> 16) & 0x1fff;
	}
	return 0;
}

void osd_get_block_windows_hw(u32 index, u32 *windows)
{
	/*
	 * memcpy(windows, osd_hw.block_windows[index],
	 *      sizeof(osd_hw.block_windows[index]));
	 */
}

void osd_set_block_windows_hw(u32 index, u32 *windows)
{
	/*
	 * memcpy(osd_hw.block_windows[index], windows,
	 *      sizeof(osd_hw.block_windows[index]));
	 */
	add_to_update_list(index, DISP_GEOMETRY);
	osd_wait_vsync_hw(index);
}

void osd_get_block_mode_hw(u32 index, u32 *mode)
{
	*mode = osd_hw.block_mode[index];
}

void osd_set_block_mode_hw(u32 index, u32 mode)
{
	/* for matrix debug */
	osd1_matrix_yuv2rgb(mode);
	/* osd_hw.block_mode[index] = mode; */
	/* add_to_update_list(index, DISP_GEOMETRY); */
	/* osd_wait_vsync_hw(index); */

}

void osd_enable_3d_mode_hw(u32 index, u32 enable)
{
	spin_lock_irqsave(&osd_lock, lock_flags);
	osd_hw.mode_3d[index].enable = enable;
	spin_unlock_irqrestore(&osd_lock, lock_flags);
	if (enable) {
		/* when disable 3d mode ,we should return to standard state. */
		osd_hw.mode_3d[index].left_right = OSD_LEFT;
		osd_hw.mode_3d[index].l_start = osd_hw.pandata[index].x_start;
		osd_hw.mode_3d[index].l_end = (osd_hw.pandata[index].x_end +
					osd_hw.pandata[index].x_start) >> 1;
		osd_hw.mode_3d[index].r_start = osd_hw.mode_3d[index].l_end + 1;
		osd_hw.mode_3d[index].r_end = osd_hw.pandata[index].x_end;
		osd_hw.mode_3d[index].origin_scale.h_enable =
					osd_hw.scale[index].h_enable;
		osd_hw.mode_3d[index].origin_scale.v_enable =
					osd_hw.scale[index].v_enable;
		osd_set_2x_scale_hw(index, 1, 0);
	} else {
		osd_set_2x_scale_hw
			(index,
			 osd_hw.mode_3d[index].origin_scale.h_enable,
			 osd_hw.mode_3d[index].origin_scale.v_enable);
	}
}

void osd_enable_hw(u32 index, u32 enable)
{
	int i = 0;
	int count = (pxp_mode == 1) ? 3 : WAIT_AFBC_READY_COUNT;
	u32 output_index;

	if (index == 0) {
		osd_log_info("osd[%d] enable: %d (%s)\n",
			     index, enable, current->comm);
	} else {
		osd_log_info("osd[%d] enable: %d (%s)\n",
			     index, enable, current->comm);
	}

	/* reset viu 31bit ?? */
	if (!osd_hw.enable[index] &&
	    osd_hw.osd_afbcd[index].enable && enable &&
	    (get_osd_hwc_type(index) != OSD_G12A_NEW_HWC)) {
		spin_lock_irqsave(&osd_lock, lock_flags);
		if (osd_hw.osd_meson_dev.afbc_type == MESON_AFBC) {
			osd_reg_write(VIU_SW_RESET, 0x80000000);
			osd_reg_write(VIU_SW_RESET, 0);
		}

		spin_unlock_irqrestore(&osd_lock, lock_flags);
		osd_afbc_dec_enable = 0;
		add_to_update_list(index, OSD_COLOR_MODE);
		add_to_update_list(index, OSD_GBL_ALPHA);
		add_to_update_list(index, DISP_GEOMETRY);
		osd_wait_vsync_hw(index);

		while ((index == 0) && osd_hw.osd_afbcd[index].enable &&
		       (osd_hw.osd_afbcd[index].phy_addr == 0) &&
		       enable && (i < count)) {
			osd_wait_vsync_hw(index);
			i++;
		}
		if (i > 0)
			osd_log_info("osd[%d]: wait %d vsync first buffer ready.\n",
				     index, i);
	}

	osd_hw.enable[index] = enable;
	output_index = get_output_device_id(index);
	osd_update_disp_src_size(index);
	osd_update_disp_dst_size(index);
	if (get_osd_hwc_type(index) != OSD_G12A_NEW_HWC) {
		if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE)
			osd_setting_default_hwc();
		add_to_update_list(index, OSD_ENABLE);
		osd_wait_vsync_hw(index);
	} else if (osd_hw.hwc_enable[output_index] &&
	    (osd_hw.osd_display_debug[output_index] == OSD_DISP_DEBUG ||
	    osd_hw.osd_display_fb[output_index])) {
		osd_setting_blend(output_index);
	}
}

void osd_set_2x_scale_hw(u32 index, u16 h_scale_enable, u16 v_scale_enable)
{
	osd_log_info("osd[%d] set scale, h_scale: %s, v_scale: %s\n",
		     index, h_scale_enable ? "ENABLE" : "DISABLE",
		     v_scale_enable ? "ENABLE" : "DISABLE");
	osd_log_info("osd[%d].scaledata: %d %d %d %d\n",
		     index,
		     osd_hw.scaledata[index].x_start,
		     osd_hw.scaledata[index].x_end,
		     osd_hw.scaledata[index].y_start,
		     osd_hw.scaledata[index].y_end);
	osd_log_info("osd[%d].pandata: %d %d %d %d\n",
		     index,
		     osd_hw.pandata[index].x_start,
		     osd_hw.pandata[index].x_end,
		     osd_hw.pandata[index].y_start,
		     osd_hw.pandata[index].y_end);
	osd_hw.scale[index].h_enable = h_scale_enable;
	osd_hw.scale[index].v_enable = v_scale_enable;
	spin_lock_irqsave(&osd_lock, lock_flags);
	osd_hw.reg[DISP_SCALE_ENABLE].update_func(index);
	osd_hw.reg[DISP_GEOMETRY].update_func(index);
	spin_unlock_irqrestore(&osd_lock, lock_flags);
	osd_wait_vsync_hw(index);
}

void osd_get_flush_rate_hw(u32 index, u32 *break_rate)
{
	const struct vinfo_s *vinfo = NULL;
	u32 output_index;

	output_index = get_output_device_id(index);
	if (output_index == VIU1)
#ifdef CONFIG_AMLOGIC_VOUT_SERVE
		vinfo = get_current_vinfo();
#endif
#ifdef CONFIG_AMLOGIC_VOUT2_SERVE
	else if (output_index == VIU2)
		vinfo = get_current_vinfo2();
#endif
	if (!vinfo)
		return;
	*break_rate = vinfo->sync_duration_num / vinfo->sync_duration_den;
}

void osd_set_antiflicker_hw(u32 index, struct vinfo_s *vinfo, u32 yres)
{
#ifdef NEED_ANTIFLICKER
	bool osd_need_antiflicker = false;

	if (is_interlaced(vinfo))
		osd_need_antiflicker = false;
	else
		osd_need_antiflicker = true;
	if (osd_need_antiflicker) {
		osd_hw.antiflicker_mode = 1;
		osd_antiflicker_task_start();
		osd_antiflicker_enable(1);
		osd_antiflicker_update_pan(osd_hw.pandata[index].y_start, yres);
	}
#else
	if (osd_hw.antiflicker_mode)
		osd_antiflicker_task_stop();
	osd_hw.antiflicker_mode = 0;
#endif
}

void osd_get_antiflicker_hw(u32 index, u32 *on_off)
{
	*on_off = osd_hw.antiflicker_mode;
}

/* Todo: how to expand to 3 osd */
void osd_clone_pan(u32 index, u32 yoffset, int debug_flag)
{
	s32 offset = 0;
	u32 index_buffer = 0;
	s32 osd0_buffer_number = 0;
	s32 height_osd1 = 0;

	if (yoffset != 0) {
		index_buffer = osd_hw.fb_gem[index].height / yoffset;
		if (index_buffer == 3)
			osd0_buffer_number = 1;
		else if (index_buffer == 1)
			osd0_buffer_number = 2;
	} else {
		osd0_buffer_number = 0;
	}
	osd_clone_get_virtual_yres(&height_osd1);
	if (osd_hw.clone[index]) {
		offset = osd0_buffer_number * height_osd1;
		osd_hw.pandata[OSD2].y_start = offset;
		osd_hw.pandata[OSD2].y_end = offset + height_osd1 - 1;
		if (osd_hw.angle[OSD2]) {
			if (debug_flag)
				osd_log_dbg(MODULE_BASE, "%s start when enable clone\n",
					    __func__);
			osd_clone_update_pan(osd0_buffer_number);
		}
		add_to_update_list(OSD2, DISP_GEOMETRY);
	}
}

/* Todo: how to expand to 3 osd */
void osd_set_angle_hw(u32 index, u32 angle, u32  virtual_osd1_yres,
		      u32 virtual_osd2_yres)
{
#ifndef OSD_GE2D_CLONE_SUPPORT
	osd_log_err("++ osd_clone depends on GE2D module!\n");
	return;
#endif
	if (angle > 4) {
		osd_log_err("++ invalid angle: %d\n", angle);
		return;
	}
	osd_log_info("++ virtual_osd1_yres is %d, virtual_osd2_yres is %d!\n",
		     virtual_osd1_yres, virtual_osd2_yres);
	osd_clone_set_virtual_yres(virtual_osd1_yres, virtual_osd2_yres);
	if (osd_hw.clone[index] == 0) {
		osd_log_info("++ set osd[%d]->angle: %d->%d\n",
			     index, osd_hw.angle[index], angle);
		osd_clone_set_angle(angle);
		osd_hw.angle[index] = angle;
	} else if (!((osd_hw.angle[index] == 0) || (angle == 0))) {
		osd_log_info("++ set osd[%d]->angle: %d->%d\n",
			     index, osd_hw.angle[index], angle);
		osd_clone_set_angle(angle);
		osd_hw.angle[index] = angle;
		osd_clone_pan(index, osd_hw.pandata[OSD1].y_start, 1);
	}
}

void osd_get_angle_hw(u32 index, u32 *angle)
{
	*angle = osd_hw.angle[index];
}

void osd_set_clone_hw(u32 index, u32 clone)
{
	int ret = -1;

	osd_log_info("++ set osd[%d]->clone: %d->%d\n",
		     index, osd_hw.clone[index], clone);
	osd_hw.clone[index] = clone;
	if (osd_hw.clone[index]) {
		if (osd_hw.angle[index]) {
			osd_hw.color_info[index] = osd_hw.color_info[OSD1];
			osd_hw.color_backup[index] = osd_hw.color_info[OSD1];
			ret = osd_clone_task_start();
			if (ret)
				osd_clone_pan(index,
					      osd_hw.pandata[OSD1].y_start, 1);
			else
				osd_log_err("++ start clone error\n");
		}
	} else {
		if (osd_hw.angle[index])
			osd_clone_task_stop();
	}
	add_to_update_list(index, OSD_COLOR_MODE);
}

void osd_set_update_pan_hw(u32 index)
{
	osd_clone_pan(index, osd_hw.pandata[OSD1].y_start, 1);
}

void osd_get_clone_hw(u32 index, u32 *clone)
{
	*clone = osd_hw.clone[index];
}

void osd_set_reverse_hw(u32 index, u32 reverse, u32 update)
{
	char *str[4] = {"NONE", "ALL", "X_REV", "Y_REV"};

	osd_hw.osd_reverse[index] = reverse;
	pr_info("set osd%d reverse as %s\n", index, str[reverse]);
	if (update) {
		add_to_update_list(index, DISP_OSD_REVERSE);
		osd_wait_vsync_hw(index);
	}
}

void osd_get_reverse_hw(u32 index, u32 *reverse)
{
	*reverse = osd_hw.osd_reverse[index];
}

/* Todo: how to do with uboot logo */
void osd_switch_free_scale(u32 pre_index, u32 pre_enable,
			   u32 pre_scale, u32 next_index,
			   u32 next_enable, u32 next_scale)
{
	unsigned int h_enable = 0;
	unsigned int v_enable = 0;
	int i = 0;
	int count = (pxp_mode == 1) ? 3 : WAIT_AFBC_READY_COUNT;

	osd_log_info("osd[%d] enable: %d scale:0x%x (%s)\n",
		     pre_index, pre_enable, pre_scale, current->comm);
	osd_log_info("osd[%d] enable: %d scale:0x%x (%s)\n",
		     next_index, next_enable, next_scale, current->comm);
	if (osd_hw.free_scale_mode[pre_index] ||
	    osd_hw.free_scale_mode[next_index]) {
		if (osd_hw.osd_meson_dev.osd_ver == OSD_NORMAL) {
			while (next_index == OSD1 &&
			       osd_hw.osd_afbcd[next_index].enable &&
			       (osd_hw.osd_afbcd[next_index].phy_addr == 0) &&
				next_enable && (i < count)) {
				osd_wait_vsync_hw(OSD1);
				i++;
			}
			if (i > 0)
				osd_log_info("osd[%d]: wait %d vsync first buffer ready.\n",
					     next_index, i);
		}
		if (pre_index != next_index) {
			h_enable = (pre_scale & 0xffff0000 ? 1 : 0);
			v_enable = (pre_scale & 0xffff ? 1 : 0);
			osd_hw.free_scale[pre_index].h_enable = h_enable;
			osd_hw.free_scale[pre_index].v_enable = v_enable;
			osd_hw.free_scale_enable[pre_index] = pre_scale;
			osd_hw.free_scale_backup[pre_index].h_enable = h_enable;
			osd_hw.free_scale_backup[pre_index].v_enable = v_enable;
			osd_hw.free_scale_enable_backup[pre_index] = pre_scale;
			osd_hw.enable[pre_index] = pre_enable;
		}
		h_enable = (next_scale & 0xffff0000 ? 1 : 0);
		v_enable = (next_scale & 0xffff ? 1 : 0);
		osd_hw.free_scale[next_index].h_enable = h_enable;
		osd_hw.free_scale[next_index].v_enable = v_enable;
		osd_hw.free_scale_enable[next_index] = next_scale;
		osd_hw.free_scale_backup[next_index].h_enable = h_enable;
		osd_hw.free_scale_backup[next_index].v_enable = v_enable;
		osd_hw.free_scale_enable_backup[next_index] = next_scale;
		osd_hw.enable[next_index] = next_enable;

		osd_set_scan_mode(next_index);
		spin_lock_irqsave(&osd_lock, lock_flags);
		if (next_index == OSD1 &&
		    osd_hw.osd_afbcd[next_index].enable &&
		    next_enable) {
			if (osd_hw.osd_meson_dev.osd_ver == OSD_NORMAL) {
				osd_reg_write(VIU_SW_RESET, 0x80000000);
				osd_reg_write(VIU_SW_RESET, 0);
			}
			osd_afbc_dec_enable = 0;
			osd_hw.reg[OSD_GBL_ALPHA].update_func(next_index);
		}
		if (pre_index != next_index) {
			osd_hw.reg[OSD_COLOR_MODE].update_func(pre_index);
			if (pre_scale)
				osd_hw.reg[OSD_FREESCALE_COEF]
					.update_func(pre_index);
			osd_hw.reg[DISP_GEOMETRY].update_func(pre_index);
			osd_hw.reg[DISP_FREESCALE_ENABLE]
				.update_func(pre_index);
			osd_hw.reg[OSD_ENABLE].update_func(pre_index);

			osd_hw.reg[OSD_COLOR_MODE].update_func(next_index);
			if (next_scale)
				osd_hw.reg[OSD_FREESCALE_COEF]
					.update_func(next_index);
			osd_hw.reg[DISP_GEOMETRY].update_func(next_index);
			osd_hw.reg[DISP_FREESCALE_ENABLE]
				.update_func(next_index);
			osd_hw.reg[OSD_ENABLE].update_func(next_index);
		}
		spin_unlock_irqrestore(&osd_lock, lock_flags);
		osd_wait_vsync_hw(next_index);
	} else {
		if (pre_index != next_index)
			osd_enable_hw(pre_index, pre_enable);
		osd_enable_hw(next_index, next_enable);
	}
}

void osd_get_urgent(u32 index, u32 *urgent)
{
	*urgent = osd_hw.urgent[index];
}

void osd_set_urgent(u32 index, u32 urgent)
{
	osd_hw.urgent[index] = urgent;
	add_to_update_list(index, OSD_FIFO);
	osd_wait_vsync_hw(index);
}

void osd_get_deband(u32 index, u32 *osd_deband_enable)
{
	*osd_deband_enable = osd_hw.osd_deband_enable[index];
}

void osd_set_deband(u32 index, u32 osd_deband_enable)
{
	u32 data32;
	struct hw_osd_reg_s *osd_reg = &hw_osd_reg_array[index];
	u32 output_index = get_output_device_id(index);

	if (osd_hw.osd_meson_dev.has_deband) {
		if (osd_hw.free_scale_enable[index]) {
			osd_hw.osd_deband_enable[index] = osd_deband_enable;
			spin_lock_irqsave(&osd_lock, lock_flags);

			data32 = osd_hw.osd_rdma_func[output_index].osd_rdma_rd
				(osd_reg->osd_db_flt_ctrl);
			if (osd_deband_enable) {
				/* Bit 23	 debanding registers of side
				 * lines, [0] for luma
				 * Bit 22	 debanding registers of side
				 * lines, [1] for chroma
				 * Bit 5debanding registers,for luma
				 * Bit 4debanding registers,for chroma
				 */
				data32 |= 3 << 4;
				data32 |= 3 << 22;
			} else {
				data32 |= 0 << 4;
				data32 |= 0 << 22;
			}
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr
				(osd_reg->osd_db_flt_ctrl, data32);
			spin_unlock_irqrestore(&osd_lock, lock_flags);
			osd_wait_vsync_hw_viux(output_index);
		}
	}
}

void osd_get_fps(u32 index, u32 *osd_fps)
{
	u32 output_index;

	output_index = get_output_device_id(index);
	*osd_fps = osd_hw.osd_fps[output_index];
}

void osd_set_fps(u32 index, u32 osd_fps_start)
{
	static int stime, etime;
	u32 output_index;

	output_index = get_output_device_id(index);
	osd_hw.osd_fps_start[output_index] = osd_fps_start;
	if (osd_fps_start) {
		/* start to calc fps */
		stime = ktime_to_us(ktime_get());
		osd_hw.osd_fps[output_index] = 0;
	} else {
		/* stop to calc fps */
		etime = ktime_to_us(ktime_get());
		osd_hw.osd_fps[output_index] =
			(osd_hw.osd_fps[output_index] * 1000000)
			/ (etime - stime);
		osd_log_info("osd fps:=%d\n", osd_hw.osd_fps[output_index]);
	}
}

void osd_get_display_debug(u32 index, u32 *osd_display_debug_enable)
{
	u32 output_index;

	output_index = get_output_device_id(index);
	*osd_display_debug_enable = osd_hw.osd_display_debug[output_index];
}

void osd_set_display_debug(u32 index, u32 osd_display_debug_enable)
{
	u32 output_index;

	output_index = get_output_device_id(index);
	osd_hw.osd_display_debug[output_index] = osd_display_debug_enable;
}

void osd_get_display_fb(u32 index, u32 *osd_display_fb)
{
	u32 output_index;

	output_index = get_output_device_id(index);
	*osd_display_fb = osd_hw.osd_display_fb[output_index];
}

void osd_set_display_fb(u32 index, u32 osd_display_fb)
{
	u32 output_index;

	output_index = get_output_device_id(index);
	osd_hw.osd_display_fb[output_index] = osd_display_fb;
}

void osd_get_sc_depend(u32 *osd_sc_depend)
{
	*osd_sc_depend = osd_hw.osd_meson_dev.osd0_sc_independ;
}

void osd_set_sc_depend(u32 osd_sc_depend)
{
	osd_hw.osd_meson_dev.osd0_sc_independ = osd_sc_depend;
}

void osd_get_background_size(u32 index, struct display_flip_info_s *disp_info)
{
	u32 output_index;

	output_index = get_output_device_id(index);
	memcpy(disp_info, &osd_hw.disp_info[output_index],
	       sizeof(struct display_flip_info_s));
}

void osd_set_background_size(u32 index, struct display_flip_info_s *disp_info)
{
	u32 output_index;

	output_index = get_output_device_id(index);
	memcpy(&osd_hw.disp_info[output_index], disp_info,
	       sizeof(struct display_flip_info_s));
}

void osd_get_hdr_used(u32 *val)
{
	*val = osd_hw.hdr_used;
}

void osd_set_hdr_used(u32 val)
{
	osd_hw.hdr_used = val;
}

void osd_get_afbc_format(u32 index, u32 *format, u32 *inter_format)
{
	*format = osd_hw.osd_afbcd[index].format;
	*inter_format = osd_hw.osd_afbcd[index].inter_format;
}

void osd_set_afbc_format(u32 index, u32 format, u32 inter_format)
{
	osd_hw.osd_afbcd[index].format = format;
	osd_hw.osd_afbcd[index].inter_format = inter_format;
}

void osd_get_hwc_enable(u32 index, u32 *hwc_enable)
{
	u32 output_index;

	output_index = get_output_device_id(index);
	*hwc_enable = osd_hw.hwc_enable[output_index];
}

void osd_set_hwc_enable(u32 index, u32 hwc_enable)
{
	u32 output_index;

	output_index = get_output_device_id(index);
	osd_hw.hwc_enable[output_index] = hwc_enable;
	/* setting default hwc path */
	if (!hwc_enable)
		osd_setting_blend(OSD1);
}

void osd_do_hwc(u32 index)
{
	u32 output_index;

	output_index = get_output_device_id(index);
	osd_setting_blend(output_index);
}

static void osd_set_two_ports(bool set)
{
	static u32 data32[2];

	if (osd_dev_hw.display_type == T7_DISPLAY || osd_dev_hw.s5_display) {
		if (osd_hw.osd_meson_dev.cpu_id ==
			__MESON_CPU_MAJOR_ID_T3) {
			/* set osd, video two port */
			if (set) {
				/*mali afbcd,dolby0, osd1-4 etc->VPU0*/
				/*aisr reshape, vd1, vd2, tcon p1 read->VPU2*/
				osd_reg_write(VPP_RDARB_MODE, 0x10c00000);
				osd_reg_write(VPU_RDARB_MODE_L2C1, 0x920000);
			} else {
				osd_reg_write(VPP_RDARB_MODE, 0xaa0000);
				osd_reg_write(VPU_RDARB_MODE_L2C1, 0x900000);
			}
		}
		return;
	}
	/* set osd, video two port */
	if (set) {
		data32[0] = osd_reg_read(VPP_RDARB_MODE);
		data32[1] = osd_reg_read(VPU_RDARB_MODE_L2C1);
		osd_reg_set_bits(VPP_RDARB_MODE, 2, 20, 8);
		osd_reg_set_bits(VPU_RDARB_MODE_L2C1, 2, 16, 8);
	} else {
		osd_reg_write(VPP_RDARB_MODE, data32[0]);
		osd_reg_write(VPU_RDARB_MODE_L2C1, data32[1]);
	}
}

static void osd_set_basic_urgent(bool set)
{
	if (set)
		osd_reg_write(0x27c2, 0xffff);
	else
		osd_reg_write(0x27c2, 0x0);
}

void osd_get_urgent_info(u32 *ports, u32 *basic_urgent)
{
	*basic_urgent = osd_hw.basic_urgent;
	*ports = osd_hw.two_ports;
}

void osd_set_urgent_info(u32 ports, u32 basic_urgent)
{
	osd_hw.basic_urgent = basic_urgent;
	osd_hw.two_ports = ports;
	osd_set_basic_urgent(osd_hw.basic_urgent);
	osd_set_two_ports(osd_hw.two_ports);
}

void osd_set_single_step_mode(u32 index, u32 osd_single_step_mode)
{
	u32 output_index;

	output_index = get_output_device_id(index);
	if (output_index != VIU1)
		return;
	osd_hw.osd_debug.osd_single_step_mode = osd_single_step_mode;
	if (osd_hw.osd_debug.wait_fence_release &&
	    osd_hw.osd_debug.osd_single_step_mode == 0) {
#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
		osd_timeline_increase(output_index, 1);
#endif
		osd_hw.osd_debug.wait_fence_release = 0;
	}
}

void osd_set_single_step(u32 index, u32 osd_single_step)
{
	u32 output_index;

	output_index = get_output_device_id(index);
	if (output_index != VIU1)
		return;
	osd_hw.osd_debug.osd_single_step = osd_single_step;
	if (osd_hw.osd_debug.wait_fence_release &&
	    osd_hw.osd_debug.osd_single_step > 0) {
#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
		osd_timeline_increase(output_index, 1);
#endif
		osd_hw.osd_debug.wait_fence_release = 0;
	}
}

void osd_get_rotate(u32 index, u32 *osd_rotate)
{
	*osd_rotate = osd_hw.osd_rotate[index];
}

void osd_set_rotate(u32 index, u32 osd_rotate)
{
	if (index != osd_hw.osd_meson_dev.viu2_index)
		osd_log_err("osd%d not support rotate\n", index);
	osd_hw.osd_rotate[index] = osd_rotate;
	add_to_update_list(index, DISP_OSD_ROTATE);
	osd_wait_vsync_hw(index);
}

void osd_get_afbc_err_cnt(u32 index, u32 *err_cnt)
{
	*err_cnt = osd_hw.afbc_err_cnt[index];
}

void osd_get_dimm_info(u32 index, u32 *osd_dimm_layer, u32 *osd_dimm_color)
{
	*osd_dimm_layer = osd_hw.dim_layer[index];
	*osd_dimm_color = osd_hw.dim_color[index];
}

void osd_set_dimm_info(u32 index, u32 osd_dimm_layer, u32 osd_dimm_color)
{
	osd_hw.dim_layer[index] = osd_dimm_layer;
	osd_hw.dim_color[index] = osd_dimm_color;
}

u32 osd_get_hold_line(u32 index)
{
	unsigned int data32 = 0, val = 0;
	u32 output_index = get_output_device_id(index);

	if (osd_hw.powered[index]) {
		data32 = osd_hw.osd_rdma_func[output_index].osd_rdma_rd
			(hw_osd_reg_array[index].osd_fifo_ctrl_stat);
		val = (data32 >> 5) & 0x1f;
	}
	return val;
}

void osd_set_hold_line(u32 index, int hold_line)
{
	unsigned int data32 = 0, val = 0;
	u32 output_index = get_output_device_id(index);

	if (osd_hw.powered[index]) {
		data32 = osd_hw.osd_rdma_func[output_index].osd_rdma_rd
			(hw_osd_reg_array[index].osd_fifo_ctrl_stat);
		val = (data32 >> 5) & 0x1f;
		if (val != hold_line) {
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(hw_osd_reg_array[index].osd_fifo_ctrl_stat,
				hold_line & 0x1f, 5, 5);
		}
	}
}

int osd_get_capability(u32 index)
{
	u32 capability = 0;
	u32 afbc = osd_hw.osd_meson_dev.afbc_type;

	if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE) {
		u32 output_index = get_output_device_id(index);
		u32 vpp_top = 0;

		if (output_index == VIU2)
			vpp_top = OSD_VIU2;
		else if (output_index == VIU3)
			vpp_top = OSD_VIU3;
		else
			vpp_top = OSD_VIU1 | OSD_ZORDER;

		if (index == OSD1)
			capability |= OSD_LAYER_ENABLE | OSD_FREESCALE
				| OSD_UBOOT_LOGO | vpp_top
				| OSD_PRIMARY | (afbc ? OSD_AFBC : 0);
		else if (index < osd_hw.osd_meson_dev.viu1_osd_count)
			capability |= OSD_LAYER_ENABLE |
				vpp_top |
				(osd_hw.pps_support[index] ?
				OSD_FREESCALE : 0) |
				((afbc && osd_hw.afbc_support[index]) ?
				OSD_AFBC : 0);
		else if (index == osd_hw.osd_meson_dev.viu2_index)
			capability |= OSD_LAYER_ENABLE | vpp_top;
	} else if (osd_hw.osd_meson_dev.osd_ver == OSD_NORMAL) {
		if (index == OSD1)
			capability |= OSD_LAYER_ENABLE | OSD_FREESCALE
				| OSD_VIU1 | (afbc ? OSD_AFBC : 0);
		else if (index == OSD2)
			capability |= OSD_LAYER_ENABLE |
				OSD_HW_CURSOR | OSD_FREESCALE
				| OSD_UBOOT_LOGO | OSD_VIU1 |
				(afbc ? OSD_AFBC : 0);
	}

	return capability;
}

static void save_blend_reg(struct hw_osd_blending_s *blending)
{
	struct osd_debug_backup_s *osd_backup;
	int count = osd_hw.osd_debug.backup_count;

	osd_backup = &osd_hw.osd_debug.osd_backup[count];
	memcpy(&osd_backup->osd_blend_reg,
		&blending->osd_blend_reg,
	       sizeof(struct osd_blend_reg_s));
	memcpy(&osd_backup->vpp0_blend_reg,
		&blending->vpp0_blend_reg,
	       sizeof(struct vpp0_blend_reg_s));
	osd_hw.osd_debug.backup_count++;
	if (osd_hw.osd_debug.backup_count >= OSD_BACKUP_COUNT)
		osd_hw.osd_debug.backup_count = 0;
}

static void osd_info_output(int count)
{
	struct osd_debug_backup_s *osd_backup;
	struct osd_blend_reg_s *osd_blend_reg;
	struct vpp0_blend_reg_s *vpp0_blend_reg;
	int index;
	u32 value;

	osd_backup = &osd_hw.osd_debug.osd_backup[count];
	osd_log_info("|index|enable|ext_addr|order|blend_mode|plane_alpha|dim_layer|dim_color|src axis|dst axis\n");
	for (index = 0; index < HW_OSD_COUNT; index++) {
		if (osd_backup->layer[index].enable) {
			osd_log_info("%d\t%4d\t  0x%8lx %2d\t%2d\t%2d\t%2d\t0x%x\t(%4d,%4d,%4d,%4d)\t(%4d,%4d,%4d,%4d)\n",
				     index,
				     osd_backup->layer[index].enable,
				     osd_backup->layer[index].ext_addr,
				     osd_backup->layer[index].zorder,
				     osd_backup->layer[index].blend_mode,
				     osd_backup->layer[index].plane_alpha,
				     osd_backup->layer[index].dim_layer,
				     osd_backup->layer[index].dim_color,
				     osd_backup->layer[index].src_x,
				     osd_backup->layer[index].src_y,
				     osd_backup->layer[index].src_w,
				     osd_backup->layer[index].src_h,
				     osd_backup->layer[index].dst_x,
				     osd_backup->layer[index].dst_y,
				     osd_backup->layer[index].dst_w,
				     osd_backup->layer[index].dst_h);
		}
	}

	osd_blend_reg = &osd_backup->osd_blend_reg;
	vpp0_blend_reg = &osd_backup->vpp0_blend_reg;

	value = 4                            << 29 |
		osd_blend_reg->blend2_premult_en << 27 |
		osd_blend_reg->din0_byp_blend    << 26 |
		osd_blend_reg->din2_osd_sel	     << 25 |
		osd_blend_reg->din3_osd_sel	     << 24 |
		osd_blend_reg->blend_din_en	     << 20 |
		osd_blend_reg->din_premult_en    << 16 |
		osd_blend_reg->din_reoder_sel;
	osd_log_info("(0x39b0)=0x%x\n", value);
	osd_log_info("(0x39bb)=0x%x\n",
		     osd_blend_reg->osd_blend_blend0_size);
	osd_log_info("(0x39bc)=0x%x\n",
		     osd_blend_reg->osd_blend_blend0_size);

	for (index = 0; index < HW_OSD_COUNT; index++) {
		if (osd_hw.enable[index]) {
			osd_log_info("(0x%x)=0x%x, (0x%x)=0x%x\n",
				     hw_osd_reg_blend.osd_blend_din0_scope_h + 2 * index,
				     osd_blend_reg->osd_blend_din_scope_h[index],
				     hw_osd_reg_blend.osd_blend_din0_scope_v + 2 * index,
				     osd_blend_reg->osd_blend_din_scope_v[index]);
		}
	}
	/* vpp osd1 blend ctrl */
	value = (0 & 0xf) << 0 |
		(0 & 0x1) << 4 |
		(vpp0_blend_reg->postbld_src3_sel & 0xf) << 8 |
		(vpp0_blend_reg->postbld_osd1_premult & 0x1) << 16 |
		(1 & 0x1) << 20;
	osd_log_info("(0x1dfd)=0x%x\n", value);

	/* vpp osd2 blend ctrl */
	value = (0 & 0xf) << 0 |
		(0 & 0x1) << 4 |
		(vpp0_blend_reg->postbld_src4_sel & 0xf) << 8 |
		(vpp0_blend_reg->postbld_osd2_premult & 0x1) << 16 |
		(1 & 0x1) << 20;
	osd_log_info("(0x1dfe)=0x%x\n", value);
	osd_log_info("(0x1df5)=0x%x, (0x1df6)=0x%x\n",
		     vpp0_blend_reg->osd1_h_start << 16 |
		     vpp0_blend_reg->osd1_h_end,
		     vpp0_blend_reg->osd1_v_start << 16 |
		     vpp0_blend_reg->osd1_v_end);
	osd_log_info("(0x1df7)=0x%x, (0x1df8)=0x%x\n",
		     vpp0_blend_reg->osd2_h_start << 16 |
		     vpp0_blend_reg->osd2_h_end,
		     vpp0_blend_reg->osd2_v_start << 16 |
		     vpp0_blend_reg->osd2_v_end);
}

void output_save_info(void)
{
	struct osd_debug_backup_s *osd_backup;
	int count = osd_hw.osd_debug.backup_count - 1;
	int i;

	osd_backup = &osd_hw.osd_debug.osd_backup[count];
	for (i = count; i >= 0; i--) {
		osd_log_info("save list %d\n", i);
		osd_info_output(i);
	}
	for (i = OSD_BACKUP_COUNT - 1; i > count; i--) {
		osd_log_info("save list %d\n", i);
		osd_info_output(i);
	}
}

#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
enum {
	HAL_PIXEL_FORMAT_RGBA_8888 = 1,
	HAL_PIXEL_FORMAT_RGBX_8888 = 2,
	HAL_PIXEL_FORMAT_RGB_888 = 3,
	HAL_PIXEL_FORMAT_RGB_565 = 4,
	HAL_PIXEL_FORMAT_BGRA_8888 = 5,
	HAL_PIXEL_FORMAT_RGBA_1010102 = 43,
	/* 0x2B */
};

static bool use_ext;
const struct color_bit_define_s extern_color_format_array[] = {
	/*32 bit color RGBA */
	{
		COLOR_INDEX_32_ABGR, 2, 5,
		0, 8, 0, 8, 8, 0, 16, 8, 0, 24, 8, 0,
		0, 32
	},
	/*32 bit color RGBX */
	{
		COLOR_INDEX_32_XBGR, 2, 5,
		0, 8, 0, 8, 8, 0, 16, 8, 0, 24, 0, 0,
		0, 32
	},
	/*24 bit color RGB */
	{
		COLOR_INDEX_24_RGB, 5, 7,
		16, 8, 0, 8, 8, 0, 0, 8, 0, 0, 0, 0,
		0, 24
	},
	/*16 bit color BGR */
	{
		COLOR_INDEX_16_565, 4, 4,
		11, 5, 0, 5, 6, 0, 0, 5, 0, 0, 0, 0,
		0, 16
	},
	/*32 bit color BGRA */
	{
		COLOR_INDEX_32_ARGB, 1, 5,
		16, 8, 0, 8, 8, 0, 0, 8, 0, 24, 8, 0,
		0, 32
	},
	/*32 bit color RGBA 1010102 for mali afbc*/
	{
		COLOR_INDEX_RGBA_1010102, 2, 9,
		0, 10, 0, 10, 10, 0, 20, 10, 0, 30, 2, 0,
		0, 32
	},
};

static void clear_backup_info(void)
{
	struct osd_debug_backup_s *osd_backup;
	int count = osd_hw.osd_debug.backup_count;
	int i;

	osd_backup = &osd_hw.osd_debug.osd_backup[count];
	for (i = 0; i < HW_OSD_COUNT; i++)
		memset(&osd_backup->layer[i], 0x0,
		       sizeof(struct layer_info_s));
}

static void save_layer_info(struct layer_fence_map_s *layer_map)
{
	struct osd_debug_backup_s *osd_backup;
	int count = osd_hw.osd_debug.backup_count;
	u32 index = layer_map->fb_index;

	if (index >= OSD_MAX)
		return;
	osd_backup = &osd_hw.osd_debug.osd_backup[count];
	osd_backup->layer[index].enable = layer_map->enable;
	osd_backup->layer[index].ext_addr = layer_map->ext_addr;
	osd_backup->layer[index].src_x = layer_map->src_x;
	osd_backup->layer[index].src_y = layer_map->src_y;
	osd_backup->layer[index].src_w = layer_map->src_w;
	osd_backup->layer[index].src_h = layer_map->src_h;
	osd_backup->layer[index].dst_x = layer_map->dst_x;
	osd_backup->layer[index].dst_y = layer_map->dst_y;
	osd_backup->layer[index].dst_w = layer_map->dst_w;
	osd_backup->layer[index].dst_h = layer_map->dst_h;
	osd_backup->layer[index].zorder = layer_map->zorder;
	osd_backup->layer[index].blend_mode = layer_map->blend_mode;
	osd_backup->layer[index].plane_alpha = layer_map->plane_alpha;
	osd_backup->layer[index].dim_layer = layer_map->dim_layer;
	osd_backup->layer[index].dim_color = layer_map->dim_color;
}

static bool is_keystone_enable_for_txhd2(void)
{
	if (osd_hw.osd_meson_dev.cpu_id ==
		    __MESON_CPU_MAJOR_ID_TXHD2 &&
		    osd_hw.osd_meson_dev.has_vpp1)
		return true;
	else
		return false;
}

static const struct color_bit_define_s *convert_hal_format(u32 format)
{
	const struct color_bit_define_s *color = NULL;
	int b_mali_afbc = 0;

	b_mali_afbc = (format & AFBC_EN) >> 31;
	format &= ~AFBC_EN;
	switch (format) {
	case HAL_PIXEL_FORMAT_RGBA_8888:
	case HAL_PIXEL_FORMAT_RGBX_8888:
	case HAL_PIXEL_FORMAT_RGB_888:
	case HAL_PIXEL_FORMAT_RGB_565:
	case HAL_PIXEL_FORMAT_BGRA_8888:
		color = &extern_color_format_array[format - 1];
		break;
	case HAL_PIXEL_FORMAT_RGBA_1010102:
		if (b_mali_afbc)
			color = &extern_color_format_array[format - 38];
		break;
	}
	return color;
}

static bool osd_ge2d_compose_pan_display(struct osd_fence_map_s *fence_map)
{
	u32 index = fence_map->fb_index;
	bool free_scale_set = false;

#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
	canvas_config(osd_hw.fb_gem[index].canvas_idx,
		      fence_map->ext_addr,
		      CANVAS_ALIGNED(fence_map->width *
				     (osd_hw.color_info[index]->bpp >> 3)),
		      fence_map->height,
		      CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
#endif
	osd_hw.screen_base[index] = fence_map->ext_addr;
	osd_hw.screen_size[index] =
		CANVAS_ALIGNED(fence_map->width *
		osd_hw.color_info[index]->bpp) * fence_map->height;
	osd_hw.pandata[index].x_start = 0;
	osd_hw.pandata[index].x_end = fence_map->width - 1;
	osd_hw.pandata[index].y_start = 0;
	osd_hw.pandata[index].y_end = fence_map->height - 1;
	if ((memcmp(&osd_hw.dispdata[index],
		    &osd_hw.dispdata_backup[index],
		    sizeof(struct pandata_s)) != 0) ||
	    (memcmp(&osd_hw.free_src_data[index],
		    &osd_hw.free_src_data_backup[index],
		    sizeof(struct pandata_s)) != 0) ||
	    (memcmp(&osd_hw.free_dst_data[index],
		    &osd_hw.free_dst_data_backup[index],
		    sizeof(struct pandata_s)) != 0)) {
		memcpy(&osd_hw.dispdata[index],
		       &osd_hw.dispdata_backup[index],
		       sizeof(struct pandata_s));
		memcpy(&osd_hw.free_src_data[index],
		       &osd_hw.free_src_data_backup[index],
		       sizeof(struct pandata_s));
		memcpy(&osd_hw.free_dst_data[index],
		       &osd_hw.free_dst_data_backup[index],
		       sizeof(struct pandata_s));
		free_scale_set = true;
	}

	if (osd_hw.free_scale[index].h_enable !=
		osd_hw.free_scale_backup[index].h_enable ||
		osd_hw.free_scale[index].v_enable !=
		osd_hw.free_scale_backup[index].v_enable ||
		osd_hw.free_scale_enable[index] !=
		osd_hw.free_scale_enable_backup[index] ||
		osd_hw.free_scale_mode[index] !=
		osd_hw.free_scale_mode_backup[index]) {
		osd_hw.free_scale[index].h_enable =
			osd_hw.free_scale_backup[index].h_enable;
		osd_hw.free_scale[index].v_enable =
			osd_hw.free_scale_backup[index].v_enable;
		osd_hw.free_scale_enable[index] =
			osd_hw.free_scale_enable_backup[index];
		osd_hw.free_scale_mode[index] =
			osd_hw.free_scale_mode_backup[index];
		free_scale_set = true;
	}
	return free_scale_set;
}

static bool osd_direct_compose_pan_display(struct osd_fence_map_s *fence_map)
{
	u32 index = fence_map->fb_index;
	u32 ext_addr = fence_map->ext_addr;
	u32 width_src = 0, width_dst = 0, height_src = 0, height_dst = 0;
	u32 x_start, x_end, y_start, y_end;
	bool freescale_update = false;
	struct pandata_s freescale_dst[HW_OSD_COUNT];

	ext_addr = ext_addr + fence_map->byte_stride * fence_map->yoffset;

	if (!osd_hw.osd_afbcd[index].enable) {
	#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
		canvas_config(osd_hw.fb_gem[index].canvas_idx,
			      ext_addr,
			      CANVAS_ALIGNED(fence_map->byte_stride),
			      fence_map->height,
			      CANVAS_ADDR_NOWRAP,
			      CANVAS_BLKMODE_LINEAR);
	#endif
		osd_hw.screen_base[index] = ext_addr;
		osd_hw.screen_size[index] =
			fence_map->byte_stride * fence_map->height;
	} else {
		osd_hw.osd_afbcd[index].phy_addr = ext_addr;
		osd_hw.osd_afbcd[index].frame_width =
			fence_map->width;
		osd_hw.osd_afbcd[index].frame_height =
			fence_map->height;
		if (osd_hw.osd_meson_dev.afbc_type == MESON_AFBC) {
			if (fence_map->width <= 128)
				osd_hw.osd_afbcd[index].conv_lbuf_len = 32;
			else if (fence_map->width <= 256)
				osd_hw.osd_afbcd[index].conv_lbuf_len = 64;
			else if (fence_map->width <= 512)
				osd_hw.osd_afbcd[index].conv_lbuf_len = 128;
			else if (fence_map->width <= 1024)
				osd_hw.osd_afbcd[index].conv_lbuf_len = 256;
			else if (fence_map->width <= 2048)
				osd_hw.osd_afbcd[index].conv_lbuf_len = 512;
			else
				osd_hw.osd_afbcd[index].conv_lbuf_len = 1024;
		}
		osd_hw.screen_base[index] = ext_addr;
		osd_hw.screen_size[index] = fence_map->afbc_len;
	}
	width_dst = osd_hw.free_dst_data_backup[index].x_end -
		osd_hw.free_dst_data_backup[index].x_start + 1;
	width_src = osd_hw.free_src_data_backup[index].x_end -
		osd_hw.free_src_data_backup[index].x_start + 1;

	height_dst = osd_hw.free_dst_data_backup[index].y_end -
		osd_hw.free_dst_data_backup[index].y_start + 1;
	height_src = osd_hw.free_src_data_backup[index].y_end -
		osd_hw.free_src_data_backup[index].y_start + 1;
	if (osd_hw.free_scale_enable[index] ||
	    width_src != width_dst ||
	    height_src != height_dst ||
	    fence_map->width != fence_map->dst_w ||
	    fence_map->height != fence_map->dst_h) {
		osd_hw.free_scale[index].h_enable = 1;
		osd_hw.free_scale[index].v_enable = 1;
		osd_hw.free_scale_enable[index] = 0x10001;
		osd_hw.free_scale_mode[index] = 1;
		if (osd_hw.free_scale_enable[index] !=
			osd_hw.free_scale_enable_backup[index]) {
			/* Todo: */
			osd_set_scan_mode(index);
			freescale_update = true;
		}

		osd_hw.pandata[index].x_start = fence_map->xoffset;
		osd_hw.pandata[index].x_end =
			fence_map->xoffset + fence_map->width - 1;
		osd_hw.pandata[index].y_start = 0;
		osd_hw.pandata[index].y_end = fence_map->height - 1;

		freescale_dst[index].x_start =
			osd_hw.free_dst_data_backup[index].x_start +
			(fence_map->dst_x * width_dst) / width_src;
		freescale_dst[index].x_end =
			osd_hw.free_dst_data_backup[index].x_start +
			((fence_map->dst_x + fence_map->dst_w) *
			width_dst) / width_src - 1;

		freescale_dst[index].y_start =
			osd_hw.free_dst_data_backup[index].y_start +
			(fence_map->dst_y * height_dst) / height_src;
		freescale_dst[index].y_end =
			osd_hw.free_dst_data_backup[index].y_start +
			((fence_map->dst_y + fence_map->dst_h) *
			height_dst) / height_src - 1;

		if (osd_hw.osd_reverse[index] == REVERSE_TRUE) {
			x_start = osd_hw.vinfo_width[VIU1]
				- freescale_dst[index].x_end - 1;
			y_start = osd_hw.vinfo_height[VIU1]
				- freescale_dst[index].y_end - 1;
			x_end = osd_hw.vinfo_width[VIU1]
				- freescale_dst[index].x_start - 1;
			y_end = osd_hw.vinfo_height[VIU1]
				- freescale_dst[index].y_start - 1;
			freescale_dst[index].x_start = x_start;
			freescale_dst[index].y_start = y_start;
			freescale_dst[index].x_end = x_end;
			freescale_dst[index].y_end = y_end;
		} else if (osd_hw.osd_reverse[index] == REVERSE_X) {
			x_start = osd_hw.vinfo_width[VIU1]
				- freescale_dst[index].x_end - 1;
			x_end = osd_hw.vinfo_width[VIU1]
				- freescale_dst[index].x_start - 1;
			freescale_dst[index].x_start = x_start;
			freescale_dst[index].x_end = x_end;

		} else if (osd_hw.osd_reverse[index] == REVERSE_Y) {
			y_start = osd_hw.vinfo_height[VIU1]
				- freescale_dst[index].y_end - 1;
			y_end = osd_hw.vinfo_height[VIU1]
				- freescale_dst[index].y_start - 1;
			freescale_dst[index].y_start = y_start;
			freescale_dst[index].y_end = y_end;
		}
		if (memcmp(&osd_hw.free_src_data[index],
			   &osd_hw.pandata[index],
			   sizeof(struct pandata_s)) != 0 ||
		    memcmp(&osd_hw.free_dst_data[index],
			   &freescale_dst[index],
			   sizeof(struct pandata_s)) != 0) {
			memcpy(&osd_hw.free_src_data[index],
			       &osd_hw.pandata[index],
			       sizeof(struct pandata_s));
			memcpy(&osd_hw.free_dst_data[index],
			       &freescale_dst[index],
			       sizeof(struct pandata_s));
			freescale_update = true;

			if ((height_dst != height_src ||
			     width_dst != width_src) &&
			    osd_hw.free_dst_data[index].y_end <
			    osd_hw.vinfo_height[VIU1] - 1)
				osd_set_dummy_data(index, 0);
			else
				osd_set_dummy_data(index, 0xff);
			osd_log_dbg(MODULE_BASE,
				    "direct pandata x=%d,x_end=%d,y=%d,y_end=%d,width=%d,height=%d\n",
				    osd_hw.pandata[index].x_start,
				    osd_hw.pandata[index].x_end,
				    osd_hw.pandata[index].y_start,
				    osd_hw.pandata[index].y_end,
				    fence_map->width,
				    fence_map->height);
			osd_log_dbg(MODULE_BASE,
				    "fence_map:xoffset=%d,yoffset=%d\n",
				    fence_map->xoffset,
				    fence_map->yoffset);
			osd_log_dbg(MODULE_BASE,
				    "fence_map:dst_x=%d,dst_y=%d,dst_w=%d,dst_h=%d,byte_stride=%d\n",
				    fence_map->dst_x,
				    fence_map->dst_y,
				    fence_map->dst_w,
				    fence_map->dst_h,
				    fence_map->byte_stride);
		}
	} else {
		osd_hw.pandata[index].x_start = 0;
		osd_hw.pandata[index].x_end = fence_map->width - 1;
		osd_hw.pandata[index].y_start = 0;
		osd_hw.pandata[index].y_end = fence_map->height - 1;

		osd_hw.dispdata[index].x_start = fence_map->dst_x;
		osd_hw.dispdata[index].x_end =
			fence_map->dst_x + fence_map->dst_w - 1;
		osd_hw.dispdata[index].y_start = fence_map->dst_y;
		osd_hw.dispdata[index].y_end =
			fence_map->dst_y + fence_map->dst_h - 1;
		if (osd_hw.osd_reverse[index] == REVERSE_TRUE) {
			x_start = osd_hw.vinfo_width[VIU1]
				- osd_hw.dispdata[index].x_end - 1;
			y_start = osd_hw.vinfo_height[VIU1]
				- osd_hw.dispdata[index].y_end - 1;
			x_end = osd_hw.vinfo_width[VIU1]
				- osd_hw.dispdata[index].x_start - 1;
			y_end = osd_hw.vinfo_height[VIU1]
				- osd_hw.dispdata[index].y_start - 1;
			osd_hw.dispdata[index].x_start = x_start;
			osd_hw.dispdata[index].y_start = y_start;
			osd_hw.dispdata[index].x_end = x_end;
			osd_hw.dispdata[index].y_end = y_end;
		} else if (osd_hw.osd_reverse[index] == REVERSE_X) {
			x_start = osd_hw.vinfo_width[VIU1]
				- osd_hw.dispdata[index].x_end - 1;
			x_end = osd_hw.vinfo_width[VIU1]
				- osd_hw.dispdata[index].x_start - 1;
			osd_hw.dispdata[index].x_start = x_start;
			osd_hw.dispdata[index].x_end = x_end;
		} else if (osd_hw.osd_reverse[index] == REVERSE_Y) {
			y_start = osd_hw.vinfo_height[VIU1]
				- osd_hw.dispdata[index].y_end - 1;
			y_end = osd_hw.vinfo_height[VIU1]
				- osd_hw.dispdata[index].y_start - 1;
			osd_hw.dispdata[index].y_start = y_start;
			osd_hw.dispdata[index].y_end = y_end;
		}
	}
	fence_map->ext_addr = ext_addr;
	return freescale_update;
}

static void osd_pan_display_single_fence(struct osd_fence_map_s *fence_map)
{
	s32 ret = 1;
	long diff_x, diff_y;
	u32 index = fence_map->fb_index;
	u32 xoffset = fence_map->xoffset;
	u32 yoffset = fence_map->yoffset;
	const struct color_bit_define_s *color = NULL;
	bool color_mode = false;
	bool freescale_update = false;
	u32 osd_enable = 0;
	bool skip = false;
	const struct vinfo_s *vinfo = NULL;
	u32 output_index = VIU1;

	if (index >= OSD2)
		goto out;
#ifdef CONFIG_AMLOGIC_VOUT_SERVE
	vinfo = get_current_vinfo();
#endif
	if (!vinfo || !vinfo->name || (!strcmp(vinfo->name, "invalid") ||
	    !strcmp(vinfo->name, "null")))
		goto out;

	osd_hw.vinfo_width[output_index] = vinfo->width;
	osd_hw.vinfo_height[output_index] = vinfo->height;

	if (timeline_created[output_index]) { /* out fence created success. */
		ret = osd_wait_buf_ready(fence_map);
		if (ret < 0)
			osd_log_dbg(MODULE_BASE, "fence wait ret %d\n", ret);
	}
	if (ret) {
		osd_hw.buffer_alloc[index] = 1;
		if (osd_hw.osd_fps_start[output_index])
			osd_hw.osd_fps[output_index]++;
		if (fence_map->op == 0xffffffff)
			skip = true;
		else
			osd_enable = (fence_map->op & 1) ? DISABLE : ENABLE;
		/* need update via direct render interface later */
		//fence_map->afbc_en = osd_hw.osd_afbcd[index].enable;
		if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE &&
		    osd_hw.osd_afbcd[index].enable) {
			osd_hw.osd_afbcd[index].inter_format =
				 AFBC_EN | BLOCK_SPLIT |
				 YUV_TRANSFORM | SUPER_BLOCK_ASPECT;
		}
		/* Todo: */
		if (fence_map->ext_addr && fence_map->width &&
		    fence_map->height) {
			spin_lock_irqsave(&osd_lock, lock_flags);
			use_ext = true;
			if (!osd_hw.osd_afbcd[index].enable) {
				osd_hw.fb_gem[index].canvas_idx =
				osd_extra_idx[index][ext_canvas_id[index]];
				ext_canvas_id[index] ^= 1;
				osd_hw.osd_afbcd[index].enable = DISABLE;
			} else {
				osd_hw.osd_afbcd[index].enable = ENABLE;
			}
			color = convert_hal_format(fence_map->format);
			if (color)
				osd_hw.color_info[index] = color;
			else
				osd_log_err("fence color format error %d\n",
					    fence_map->format);

			if (DIRECT_COMPOSE_MODE ==
				fence_map->compose_type)
				freescale_update =
				osd_direct_compose_pan_display(fence_map);
			else if (GE2D_COMPOSE_MODE ==
				fence_map->compose_type) {
				freescale_update =
				osd_ge2d_compose_pan_display(fence_map);
				if (freescale_update)
					osd_set_dummy_data(index, 0xff);
			}

			osd_hw.reg[OSD_COLOR_MODE].update_func(index);

			/* geometry and freescale need update with ioctl */
			osd_hw.reg[DISP_GEOMETRY].update_func(index);
			osd_hw.reg[DISP_OSD_REVERSE].update_func(index);
			if ((osd_hw.free_scale_enable[index] &&
			     osd_update_window_axis) ||
			    freescale_update) {
				if (!osd_hw.osd_display_debug[output_index])
					osd_hw.reg[DISP_FREESCALE_ENABLE]
						.update_func(index);
				osd_update_window_axis = false;
			}
			if ((osd_enable != osd_hw.enable[index] ||
			     (osd_hw.osd_meson_dev.afbc_type == MALI_AFBC &&
			      osd_hw.osd_afbcd[index].enable)) &&
			    !skip && !suspend_flag) {
				osd_hw.enable[index] = osd_enable;
				if (!osd_hw.osd_display_debug[output_index])
					osd_hw.reg[OSD_ENABLE]
					.update_func(index);
			}
			if (osd_hw.hw_rdma_en)
				osd_mali_afbc_start(output_index);
			spin_unlock_irqrestore(&osd_lock, lock_flags);
			osd_wait_vsync_hw(index);
		} else if (xoffset != osd_hw.pandata[index].x_start ||
			   yoffset != osd_hw.pandata[index].y_start ||
			   use_ext) {
			spin_lock_irqsave(&osd_lock, lock_flags);
			if (use_ext) {
				osd_hw.fb_gem[index].canvas_idx =
					OSD1_CANVAS_INDEX;

				osd_hw.pandata[index].x_start = xoffset;
				osd_hw.pandata[index].x_end   = xoffset +
					osd_hw.fb_gem[index].xres - 1;
				osd_hw.pandata[index].y_start = yoffset;
				osd_hw.pandata[index].y_end   = yoffset +
					osd_hw.fb_gem[index].yres - 1;
				osd_hw.screen_base[index] =
					osd_hw.screen_base_backup[index];
				osd_hw.screen_size[index] =
					osd_hw.screen_size_backup[index];

				osd_hw.dispdata[index].x_start =
					osd_hw.dispdata_backup[index].x_start;
				osd_hw.dispdata[index].x_end =
					osd_hw.dispdata_backup[index].x_end;
				osd_hw.dispdata[index].y_start =
					osd_hw.dispdata_backup[index].y_start;
				osd_hw.dispdata[index].y_end =
					osd_hw.dispdata_backup[index].y_end;

				/* restore free_scale info */
				osd_hw.free_scale[index].h_enable =
				osd_hw.free_scale_backup[index].h_enable;
				osd_hw.free_scale[index].v_enable =
				osd_hw.free_scale_backup[index].v_enable;
				osd_hw.free_scale_enable[index] =
					osd_hw.free_scale_enable_backup[index];
				osd_hw.free_scale_mode[index] =
					osd_hw.free_scale_mode_backup[index];

				memcpy(&osd_hw.free_src_data[index],
				       &osd_hw.free_src_data_backup[index],
				       sizeof(struct pandata_s));
				memcpy(&osd_hw.free_dst_data[index],
				       &osd_hw.free_dst_data_backup[index],
				       sizeof(struct pandata_s));
				osd_set_dummy_data(index, 0xff);
				osd_log_dbg(MODULE_BASE,
					    "switch back dispdata_backup x=%d,x_end=%d,y=%d,y_end=%d\n",
					    osd_hw.dispdata_backup[index].x_start,
					    osd_hw.dispdata_backup[index].x_end,
					    osd_hw.dispdata_backup[index].y_start,
					    osd_hw.dispdata_backup[index].y_end);
			#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
				canvas_config(osd_hw.fb_gem[index].canvas_idx,
					      osd_hw.fb_gem[index].addr,
					      CANVAS_ALIGNED
					      (osd_hw.fb_gem[index].width),
					      osd_hw.fb_gem[index].height,
					      CANVAS_ADDR_NOWRAP,
					      CANVAS_BLKMODE_LINEAR);
			#endif
				use_ext = false;
				color_mode = true;
				freescale_update = true;
			} else {
				diff_x = xoffset -
					osd_hw.pandata[index].x_start;
				diff_y = yoffset -
					osd_hw.pandata[index].y_start;
				osd_hw.pandata[index].x_start += diff_x;
				osd_hw.pandata[index].x_end   += diff_x;
				osd_hw.pandata[index].y_start += diff_y;
				osd_hw.pandata[index].y_end   += diff_y;
			}
			if (osd_hw.osd_afbcd[index].enable == ENABLE) {
				/* osd_hw.osd_afbcd[index].phy_addr =
				 *	(osd_hw.pandata[index].y_start /
				 *	osd_hw.osd_afbcd[index].frame_height) *
				 *	osd_hw.osd_afbcd[index].frame_height *
				 *  osd_hw.fb_gem[index].width;
				 *  osd_hw.osd_afbcd[index].phy_addr +=
				 *  osd_hw.fb_gem[index].addr;
				 */
				osd_hw.osd_afbcd[index].phy_addr =
					osd_hw.osd_afbcd[index].addr
					[osd_hw.pandata[index].y_start /
					osd_hw.osd_afbcd[index].frame_height];
			}
			color = convert_hal_format(fence_map->format);
			if (color) {
				if (color != osd_hw.color_backup[index]) {
					color_mode = true;
					osd_hw.color_backup[index] = color;
				}
				osd_hw.color_info[index] = color;
			} else {
				osd_log_err("fence color format error %d\n",
					    fence_map->format);
			}
			if (color_mode)
				osd_hw.reg[OSD_COLOR_MODE].update_func(index);
			osd_hw.reg[DISP_GEOMETRY].update_func(index);
			osd_hw.reg[DISP_OSD_REVERSE].update_func(index);
			if ((osd_hw.free_scale_enable[index] &&
			     osd_update_window_axis) ||
			    (osd_hw.free_scale_enable[index] &&
			     freescale_update)) {
				if (!osd_hw.osd_display_debug[output_index])
					osd_hw.reg[DISP_FREESCALE_ENABLE]
						.update_func(index);
				osd_update_window_axis = false;
			}
			if ((osd_enable != osd_hw.enable[index] ||
			     (osd_hw.osd_meson_dev.afbc_type == MALI_AFBC &&
			      osd_hw.osd_afbcd[index].enable)) &&
			     !skip && !suspend_flag) {
				osd_hw.enable[index] = osd_enable;
				if (!osd_hw.osd_display_debug[output_index])
					osd_hw.reg[OSD_ENABLE]
					.update_func(index);
			}
			if (osd_hw.hw_rdma_en)
				osd_mali_afbc_start(output_index);
			spin_unlock_irqrestore(&osd_lock, lock_flags);
			osd_wait_vsync_hw(index);
		} else if ((osd_enable != osd_hw.enable[index] ||
			(osd_hw.osd_meson_dev.afbc_type == MALI_AFBC &&
			osd_hw.osd_afbcd[index].enable)) && !skip) {
			spin_lock_irqsave(&osd_lock, lock_flags);
			if (!suspend_flag) {
				osd_hw.enable[index] = osd_enable;
				if (!osd_hw.osd_display_debug[output_index])
					osd_hw.reg[OSD_ENABLE]
					.update_func(index);
			}
			if (osd_hw.hw_rdma_en)
				osd_mali_afbc_start(output_index);
			spin_unlock_irqrestore(&osd_lock, lock_flags);
			osd_wait_vsync_hw(index);
		}
	}
#ifdef CONFIG_AMLOGIC_MEDIA_FB_EXT
		if (ret)
			osd_ext_clone_pan(index);
#endif
out:
	if (timeline_created[output_index]) {
		if (ret)
			osd_timeline_increase(output_index, 1);
		else
			osd_log_err("------NOT signal out_fence ERROR\n");
	}
	if (fence_map->in_fence)
		osd_put_fenceobj(fence_map->in_fence);
}

static void osd_pan_display_single_fence_viu2
	(struct osd_fence_map_s *fence_map)
{
	osd_log_err("osd hwc version not support viu2\n");
}

static void osd_pan_display_update_info(struct layer_fence_map_s *layer_map)
{
	u32 index = layer_map->fb_index;
	const struct color_bit_define_s *color = NULL;
	ulong ext_addr = 0;
	u32 format = 0;
	u32 output_index = 0;

	if (index >= OSD_MAX)
		return;
	/* get in fence_fd */
	osd_hw.in_fd[index] = layer_map->in_fd;
	osd_hw.buffer_alloc[index] = 1;
	osd_hw.enable[index] = layer_map->enable;
	if (osd_hw.enable[index] == 0) {
		osd_log_dbg(MODULE_BASE, "osd%d: blanked\n", index);
		return;
	}
	osd_hw.osd_afbcd[index].enable =
		(layer_map->afbc_inter_format & AFBC_EN) >> 31;
	if (layer_map->plane_alpha == 0xff)
		layer_map->plane_alpha = 0x100;
	osd_hw.gbl_alpha[index] = layer_map->plane_alpha;
	osd_hw.dim_layer[index] = layer_map->dim_layer;
	osd_hw.secure_enable[index] = layer_map->secure_enable;
	osd_hw.blend_mode[index] = layer_map->blend_mode;

	/* Todo: */
	if (layer_map->dim_layer || osd_hw.force_dimm[index]) {
		/* osd dim layer */
		if (osd_hw.force_dimm[index]) {
			osd_hw.dim_layer[index] = osd_hw.force_dimm[index];
		} else {
			osd_hw.dim_layer[index] = layer_map->dim_layer;
			osd_hw.dim_color[index] = layer_map->dim_color;
		}
		osd_hw.order[index] = layer_map->zorder;
		switch (layer_map->blend_mode) {
		case BLEND_MODE_PREMULTIPLIED:
			osd_hw.premult_en[index] = 1;
			break;
		case BLEND_MODE_COVERAGE:
		case BLEND_MODE_NONE:
		case BLEND_MODE_INVALID:
			osd_hw.premult_en[index] = 0;
			break;
		}
		osd_hw.src_data[index].x = 0;
		osd_hw.src_data[index].y = 0;
		osd_hw.src_data[index].w = 64;
		osd_hw.src_data[index].h = 64;
		osd_hw.dst_data[index].x = layer_map->dst_x;
		osd_hw.dst_data[index].y = layer_map->dst_y;
		osd_hw.dst_data[index].w = layer_map->dst_w;
		osd_hw.dst_data[index].h = layer_map->dst_h;
	} else if (layer_map->ext_addr &&
		   layer_map->src_w &&
		   layer_map->src_h) {
		if (!osd_hw.osd_afbcd[index].enable) {
			osd_hw.fb_gem[index].canvas_idx =
				osd_extra_idx[index][ext_canvas_id[index]];
			ext_canvas_id[index] ^= 1;
			osd_hw.osd_afbcd[index].enable = DISABLE;
		} else {
			osd_hw.osd_afbcd[index].enable = ENABLE;
		}
		if (osd_hw.osd_afbcd[index].enable)
			format = layer_map->format | AFBC_EN;
		else
			format = layer_map->format;
		color = convert_hal_format(format);
		if (color) {
			osd_hw.color_info[index] = color;
		} else {
			osd_log_err("fence color format error %d\n",
				    layer_map->format);
			return;
		}
		if (DIRECT_COMPOSE_MODE !=
			layer_map->compose_type)
			return;
		ext_addr = layer_map->ext_addr;
		if (!osd_hw.osd_afbcd[index].enable) {
			/*ext_addr is no crop, so height =
			 * layer_map->src_h + layer_map->src_y
			 */
			osd_hw.fb_gem[index].addr = ext_addr;
			osd_hw.fb_gem[index].width = layer_map->byte_stride;
			osd_hw.fb_gem[index].height =
				layer_map->src_h + layer_map->src_y;
			osd_hw.screen_base[index] = ext_addr;
			osd_hw.screen_size[index] =
				layer_map->byte_stride * layer_map->src_h;
			osd_log_dbg(MODULE_BLEND,
				     "osd%d byte_stride:%d src_h:%d src_y:%d\n",
				     index, layer_map->byte_stride, layer_map->src_h,
				     layer_map->src_y);

		} else {
			if (!osd_hw.afbc_support[index])
				pr_err("osd%d: not support afbc\n", index);
			osd_hw.osd_afbcd[index].phy_addr = ext_addr;
			if (osd_hw.osd_meson_dev.afbc_type ==
				MESON_AFBC) {
				osd_hw.osd_afbcd[index].frame_width =
					layer_map->src_w;
				osd_hw.osd_afbcd[index].frame_height =
					layer_map->src_h;
				if (layer_map->src_w <= 128)
					osd_hw.osd_afbcd[index]
						.conv_lbuf_len = 32;
				else if (layer_map->src_w <= 256)
					osd_hw.osd_afbcd[index]
						.conv_lbuf_len = 64;
				else if (layer_map->src_w <= 512)
					osd_hw.osd_afbcd[index]
						.conv_lbuf_len = 128;
				else if (layer_map->src_w <= 1024)
					osd_hw.osd_afbcd[index]
						.conv_lbuf_len = 256;
				else if (layer_map->src_w <= 2048)
					osd_hw.osd_afbcd[index]
						.conv_lbuf_len = 512;
				else
					osd_hw.osd_afbcd[index]
						.conv_lbuf_len = 1024;
				osd_hw.screen_base[index] = ext_addr;
				osd_hw.screen_size[index] =
					layer_map->afbc_len;
			} else if (osd_hw.osd_meson_dev
				.afbc_type == MALI_AFBC) {
				osd_hw.osd_afbcd[index].frame_width =
					layer_map->byte_stride / 4;
					//BYTE_32_ALIGNED(layer_map->src_w);
				osd_hw.osd_afbcd[index].frame_height =
					BYTE_8_ALIGNED(layer_map->fb_height);
					/*BYTE_8_ALIGNED(layer_map->src_h);*/
				osd_hw.screen_base[index] = ext_addr;
				osd_hw.screen_size[index] =
					layer_map->afbc_len;
			}
		}
		/* just get para, need update via do_hwc */
		osd_hw.order[index] = layer_map->zorder;
		switch (layer_map->blend_mode) {
		case BLEND_MODE_PREMULTIPLIED:
			osd_hw.premult_en[index] = 1;
			break;
		case BLEND_MODE_COVERAGE:
		case BLEND_MODE_NONE:
		case BLEND_MODE_INVALID:
			osd_hw.premult_en[index] = 0;
			break;
		}
		//Todo: fence_map.plane_alpha
		osd_hw.osd_afbcd[index].inter_format =
			layer_map->afbc_inter_format & 0x7fffffff;
		osd_hw.osd_afbcd[index].format =
			color->color_index;
		osd_hw.src_data[index].x = layer_map->src_x;
		osd_hw.src_data[index].y = layer_map->src_y;
		osd_hw.src_data[index].w = layer_map->src_w;
		osd_hw.src_data[index].h = layer_map->src_h;
		osd_hw.dst_data[index].x = layer_map->dst_x;
		osd_hw.dst_data[index].y = layer_map->dst_y;
		osd_hw.dst_data[index].w = layer_map->dst_w;
		osd_hw.dst_data[index].h = layer_map->dst_h;
		osd_log_dbg(MODULE_BLEND,
			     "osd%d src_data(x:%d y:%d w:%d h:%d)\n",
			     index, osd_hw.src_data[index].x, osd_hw.src_data[index].y,
			     osd_hw.src_data[index].w, osd_hw.src_data[index].h);

		osd_log_dbg(MODULE_BLEND,
			     "osd%d dst_data(x:%d y:%d w:%d h:%d)\n",
			     index, osd_hw.dst_data[index].x, osd_hw.dst_data[index].y,
			     osd_hw.dst_data[index].w, osd_hw.dst_data[index].h);

		if (layer_map->fb_height != layer_map->src_h ||
		    layer_map->fb_width != layer_map->src_w)
			osd_hw.src_crop[index] = 1;
		else
			osd_hw.src_crop[index] = 0;
		if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL) {
			osd_hw.free_src_data[index].x_start = layer_map->src_x;
			osd_hw.free_src_data[index].y_start = layer_map->src_y;
			osd_hw.free_src_data[index].x_end =
				layer_map->src_x + layer_map->src_w - 1;
			osd_hw.free_src_data[index].y_end =
				layer_map->src_y + layer_map->src_h - 1;
			osd_hw.free_dst_data[index].x_start = layer_map->dst_x;
			osd_hw.free_dst_data[index].y_start = layer_map->dst_y;
			osd_hw.free_dst_data[index].x_end =
				layer_map->dst_x + layer_map->dst_w - 1;
			osd_hw.free_dst_data[index].y_end =
				layer_map->dst_y + layer_map->dst_h - 1;
			output_index = get_output_device_id(index);
			if (osd_hw.field_out_en[output_index]) {
				osd_hw.free_dst_data[index].y_start /= 2;
				osd_hw.free_dst_data[index].y_end /= 2;
			}
		}
	}
}

static void check_and_reverse_axis(int start_index, int osd_count,
				   int output_index)
{
	u32 is_reverse_disp = REVERSE_FALSE;
	u32 min_x = 0xffff, min_y = 0xffff, max_x = 0, max_y = 0;
	u32 layer_x = 0, layer_y = 0;
	u32 disp_range_x = 0, disp_range_y = 0;
	u32 pps_w_den = 1, pps_w_num = 1;
	u32 pps_h_den = 1, pps_h_num = 1;
	u32 blend_w = osd_hw.vinfo_width[output_index];
	u32 blend_h = osd_hw.vinfo_height[output_index];
	int i;

	if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL)
		return;

	if (osd_hw.osd_preblend_en && output_index == VIU1) {
		s32 x_offset = 0, y_offset = 0;

		blend_h = osd_hw.field_out_en[output_index] ?
			blend_h * 2 : blend_h;
		pps_w_num = osd_hw.vinfo_width[output_index];
		pps_w_den = osd_hw.fix_target_width;
		pps_h_num = blend_h;
		pps_h_den = osd_hw.fix_target_height;
#ifdef CONFIG_AMLOGIC_MEDIA_VIDEO
		get_video_axis_offset(&x_offset, &y_offset);
#endif
		if (x_offset < 0)
			x_offset = 0;
		if (y_offset < 0)
			y_offset = 0;
		//pps_w_num -= 2 * x_offset;
		pps_h_num -= 2 * y_offset;
		blend_w = osd_hw.fix_target_width;
		blend_h = osd_hw.fix_target_height;
		osd_log_dbg2(MODULE_BLEND,
			    "blend_w=%d, blend_h=%d, x_offset=%d, y_offset=%d\n",
			    blend_w, blend_h,
			    x_offset, y_offset);
		osd_hw.preblend_y_offset = y_offset * pps_h_den / pps_h_num;
		osd_log_dbg2(MODULE_BLEND,
			    "osd_hw.preblend_y_offset=%d\n",
			    osd_hw.preblend_y_offset);
	}
	osd_hw.preblend_pps_w_den = pps_w_den;
	osd_hw.preblend_pps_h_den = pps_h_den;
	osd_hw.preblend_pps_w_num = pps_w_num;
	osd_hw.preblend_pps_h_num = pps_h_num;
	/* reverse layer dst x & y */
	for (i = start_index; i < osd_count; i++) {
		if (!osd_hw.enable[i] || !validate_osd(i, output_index))
			continue;
		osd_log_dbg2(MODULE_BLEND,
			     "osd%d orin dst(x:%d y:%d w:%d h:%d)\n",
			     i, osd_hw.dst_data[i].x, osd_hw.dst_data[i].y,
			     osd_hw.dst_data[i].w, osd_hw.dst_data[i].h);
		osd_log_dbg2(MODULE_BLEND, "pps_h_den:%d, pps_h_num=%d\n",
			pps_h_den, pps_h_num);
		osd_hw.dst_data[i].x = osd_hw.dst_data[i].x * pps_w_den / pps_w_num;
		osd_hw.dst_data[i].y = osd_hw.dst_data[i].y * pps_h_den / pps_h_num;
		osd_hw.dst_data[i].w = osd_hw.dst_data[i].w * pps_w_den / pps_w_num;
		osd_hw.dst_data[i].h = osd_hw.dst_data[i].h * pps_h_den / pps_h_num;

		if (osd_hw.osd_preblend_en) {
			osd_log_dbg2(MODULE_BLEND,
				     "osd%d preblend adjust dst(x:%d y:%d w:%d h:%d)\n",
				     i, osd_hw.dst_data[i].x, osd_hw.dst_data[i].y,
				     osd_hw.dst_data[i].w, osd_hw.dst_data[i].h);
		}
		if (min_x > osd_hw.dst_data[i].x)
			min_x = osd_hw.dst_data[i].x;
		if (min_y > osd_hw.dst_data[i].y)
			min_y = osd_hw.dst_data[i].y;
		if (max_x < (osd_hw.dst_data[i].x + osd_hw.dst_data[i].w - 1))
			max_x = osd_hw.dst_data[i].x + osd_hw.dst_data[i].w - 1;
		if (max_y < (osd_hw.dst_data[i].y + osd_hw.dst_data[i].h - 1))
			max_y = osd_hw.dst_data[i].y + osd_hw.dst_data[i].h - 1;

		if (osd_hw.osd_reverse[i] == REVERSE_TRUE) {
			layer_x = blend_w - osd_hw.dst_data[i].x -
					osd_hw.dst_data[i].w;
			layer_y = blend_h - osd_hw.dst_data[i].y -
					osd_hw.dst_data[i].h;
			is_reverse_disp = REVERSE_TRUE;
		} else if (osd_hw.osd_reverse[i] == REVERSE_X) {
			layer_x = blend_w - osd_hw.dst_data[i].x -
					osd_hw.dst_data[i].w;
			layer_y = osd_hw.dst_data[i].y;
			is_reverse_disp = REVERSE_X;
		} else if (osd_hw.osd_reverse[i] == REVERSE_Y) {
			layer_x = osd_hw.dst_data[i].x;
			layer_y = blend_h - osd_hw.dst_data[i].y -
					osd_hw.dst_data[i].h;
			is_reverse_disp = REVERSE_Y;
		} else {
			layer_x = osd_hw.dst_data[i].x;
			layer_y = osd_hw.dst_data[i].y;
		}
		osd_hw.dst_data[i].x = layer_x;
		osd_hw.dst_data[i].y = layer_y;

		osd_log_dbg2(MODULE_BLEND,
			     "osd%d adjust dst(x:%d y:%d w:%d h:%d)\n",
			     i, osd_hw.dst_data[i].x, osd_hw.dst_data[i].y,
			     osd_hw.dst_data[i].w, osd_hw.dst_data[i].h);
	}

	osd_log_dbg2(MODULE_BLEND, "orin disp position(x:%d y:%d w:%d h:%d)\n",
		    osd_hw.disp_info[output_index].position_x,
		    osd_hw.disp_info[output_index].position_y,
		    osd_hw.disp_info[output_index].position_w,
		    osd_hw.disp_info[output_index].position_h);

	/* reverse disp position dst x & y */
	if (is_reverse_disp == REVERSE_TRUE) {
		disp_range_x = blend_w - max_x - 1;
		disp_range_y = blend_h - max_y - 1;
	} else if (is_reverse_disp == REVERSE_X) {
		disp_range_x = blend_w - max_x - 1;
		disp_range_y = min_y;
	} else if (is_reverse_disp == REVERSE_Y) {
		disp_range_x = min_x;
		disp_range_y = blend_h - max_y - 1;
	} else {
		disp_range_x = min_x;
		disp_range_y = min_y;
	}
	osd_hw.disp_info[output_index].position_x = disp_range_x;
	osd_hw.disp_info[output_index].position_y = disp_range_y;
	if (osd_hw.osd_preblend_en) {
		osd_hw.adjust_position_x = disp_range_x;
		osd_hw.adjust_position_y = disp_range_y;
	}
	osd_log_dbg2(MODULE_BLEND, "adjust disp position(x:%d y:%d w:%d h:%d)\n",
		    osd_hw.disp_info[output_index].position_x,
		    osd_hw.disp_info[output_index].position_y,
		    osd_hw.disp_info[output_index].position_w,
		    osd_hw.disp_info[output_index].position_h);
}

static void _osd_pan_display_layers_fence
	(u32 output_index,
	 struct vinfo_s *vinfo,
	 struct osd_layers_fence_map_s *fence_map)
{
	int i = 0;
	int ret;
	int start_index = 0;
	int backup_en = 0;
	int osd_count = 0;
	/* osd_count need -1 when VIU2 enable */
	struct layer_fence_map_s *layer_map = NULL;
	u32 inc_cnt = fence_map->inc_cnt;

	if (output_index == VIU1) {
		osd_count = osd_hw.osd_meson_dev.viu1_osd_count;
		if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL)
			osd_count = 1;
		start_index = 0;
		backup_en = 1;
	} else if (output_index == VIU2) {
		if (osd_dev_hw.display_type == T7_DISPLAY ||
		    osd_dev_hw.display_type == S5_DISPLAY ||
		    is_keystone_enable_for_txhd2()) {
			osd_count = osd_hw.osd_meson_dev.viu1_osd_count;
			start_index = 0;
		} else {
			start_index = osd_hw.osd_meson_dev.viu2_index;
			osd_count = start_index + 1;
		}
		backup_en = 0;
	} else {
		osd_log_err("invalid output_index=%d\n", output_index);
		return;
	}

	if (!vinfo || !vinfo->name || (!strcmp(vinfo->name, "invalid") ||
	    !strcmp(vinfo->name, "null"))) {
		if (!vinfo) {
			osd_log_dbg(MODULE_BASE, "vinfo is NULL\n");
			goto out;
		}
		if (!vinfo->name)
			osd_log_dbg(MODULE_BASE, "vinfo->name is NULL\n");
		/* vout is null, release fence & buf file. */
		goto out;
	}

	osd_hw.vinfo_width[output_index] = vinfo->width;
	osd_hw.vinfo_height[output_index] = vinfo->field_height;

	memcpy(&osd_hw.disp_info[output_index], &fence_map->disp_info,
	       sizeof(struct display_flip_info_s));

	if (osd_hw.osd_fps_start[output_index])
		osd_hw.osd_fps[output_index]++;
	if (backup_en)
		clear_backup_info();
	osd_hw.hdr_used = fence_map->hdr_mode;
	for (i = start_index; i < osd_count; i++) {
		if (!validate_osd(i, output_index))
			continue;
		layer_map = &fence_map->layer_map[i];
		if (i != layer_map->fb_index) {
			osd_hw.screen_base[i] = 0;
			osd_hw.screen_size[i] = 0;
			osd_hw.enable[i] = 0;
			continue;
		}
		/* wait in fence */
		if (timeline_created[output_index] &&
		    layer_map->enable &&
		    fence_map->cmd == LAYER_SYNC) {
			ret = osd_wait_buf_ready_combine(layer_map);
			if (ret < 0)
				osd_log_dbg(MODULE_FENCE,
					    "fence wait ret %d\n", ret);
		}
		if (osd_hw.osd_display_debug[output_index] != OSD_DISP_DEBUG) {
			osd_pan_display_update_info(layer_map);
			if (backup_en)
				save_layer_info(layer_map);
		}
	}
	/* set hw regs */
	if (osd_hw.osd_display_debug[output_index] != OSD_DISP_DEBUG) {
		mutex_lock(&preblend_lock);
		osd_setting_blend(output_index);
		mutex_unlock(&preblend_lock);
	}
out:
	/* signal out fence */
	if (timeline_created[output_index]) {
		if (osd_hw.osd_debug.osd_single_step_mode) {
			/* single step mode */
			if (osd_hw.osd_debug.osd_single_step > 0) {
				osd_timeline_increase(output_index, inc_cnt);
				osd_log_dbg(MODULE_FENCE, "signal out fence\n");
				osd_hw.osd_debug.osd_single_step--;
			} else {
				osd_hw.osd_debug.wait_fence_release = true;
			}
		} else {
			osd_timeline_increase(output_index, inc_cnt);
		}
	}
	/* clear osd layer's order */
	for (i = start_index; i < osd_count; i++) {
		if (!validate_osd(i, output_index))
			continue;
		layer_map = &fence_map->layer_map[i];
		if (displayed_bufs[i]) {
			fput(displayed_bufs[i]);
			osd_hw.file_info_debug[i].fput_count++;
			displayed_bufs[i] = NULL;
		}
		if (layer_map->buf_file)
			displayed_bufs[i] = layer_map->buf_file;
		if (layer_map->in_fence)
			osd_put_fenceobj(layer_map->in_fence);
		osd_hw.order[i] = 0;
	}
}

static void osd_pan_display_layers_fence
	(struct osd_layers_fence_map_s *fence_map)
{
	u32 output_index = VIU1;
	struct vinfo_s *vinfo = NULL;

#ifdef CONFIG_AMLOGIC_VOUT_SERVE
	vinfo = get_current_vinfo();
#endif

	_osd_pan_display_layers_fence(output_index,
				      vinfo, fence_map);
}

static void osd_pan_display_layers_fence_viu2
	(struct osd_layers_fence_map_s *fence_map)
{
	u32 output_index = VIU2;
	struct vinfo_s *vinfo = NULL;

#ifdef CONFIG_AMLOGIC_VOUT2_SERVE
	vinfo = get_current_vinfo2();
#endif

	_osd_pan_display_layers_fence(output_index,
				      vinfo, fence_map);
}
#endif

void osd_pan_display_hw(u32 index, unsigned int xoffset, unsigned int yoffset)
{
	long diff_x, diff_y;
	u32 output_index;

	if (index >= HW_OSD_COUNT)
		return;
	output_index = get_output_device_id(index);
	if (xoffset != osd_hw.pandata[index].x_start ||
	    yoffset != osd_hw.pandata[index].y_start) {
		diff_x = xoffset - osd_hw.pandata[index].x_start;
		diff_y = yoffset - osd_hw.pandata[index].y_start;
		osd_hw.pandata[index].x_start += diff_x;
		osd_hw.pandata[index].x_end   += diff_x;
		osd_hw.pandata[index].y_start += diff_y;
		osd_hw.pandata[index].y_end   += diff_y;
		osd_hw.src_data[index].x = osd_hw.pandata[index].x_start;
		osd_hw.src_data[index].y = osd_hw.pandata[index].y_start;
		osd_hw.src_data[index].w = osd_hw.pandata[index].x_end
			- osd_hw.pandata[index].x_start + 1;
		osd_hw.src_data[index].h = osd_hw.pandata[index].y_end
			- osd_hw.pandata[index].y_start + 1;
		add_to_update_list(index, DISP_GEOMETRY);
		if (osd_hw.osd_fps_start[output_index])
			osd_hw.osd_fps[output_index]++;
		/* osd_wait_vsync_hw(); */
	}
#ifdef CONFIG_AMLOGIC_MEDIA_FB_EXT
	osd_ext_clone_pan(index);
#endif
	osd_log_dbg2(MODULE_BASE, "offset[%d-%d]x[%d-%d]y[%d-%d]\n",
		     xoffset, yoffset,
		     osd_hw.pandata[index].x_start,
		     osd_hw.pandata[index].x_end,
		     osd_hw.pandata[index].y_start,
		     osd_hw.pandata[index].y_end);
}

void osd_get_info(u32 index, ulong *addr, u32 *width, u32 *height)
{
	*addr = osd_hw.fb_gem[index].addr;
	*width = osd_hw.fb_gem[index].width;
	*height = osd_hw.fb_gem[index].yres;
}

static  void  osd_update_disp_scale_enable(u32 index)
{
	u32 osd2_cursor = 0;
	struct hw_osd_reg_s *osd_reg = &hw_osd_reg_array[index];
	u32 output_index = get_output_device_id(index);

	if (osd_hw.hw_cursor_en)
		osd2_cursor = 1;

	if (osd_hw.scale[index].h_enable) {
		osd_hw.osd_rdma_func[output_index].osd_rdma_set_mask
			(osd_reg->osd_blk0_cfg_w0, 3 << 12);
		if (index == OSD2 && osd2_cursor) {
			osd_hw.osd_rdma_func[output_index].osd_rdma_clr_mask
				(osd_reg->osd_blk0_cfg_w0, 3 << 12);
		}
	} else {
		osd_hw.osd_rdma_func[output_index].osd_rdma_clr_mask
			(osd_reg->osd_blk0_cfg_w0, 3 << 12);
	}
	if (osd_hw.scan_mode[index] != SCAN_MODE_INTERLACE) {
		if (osd_hw.scale[index].v_enable) {
			osd_hw.osd_rdma_func[output_index].osd_rdma_set_mask
				(osd_reg->osd_blk0_cfg_w0, 1 << 14);
			if (index == OSD2 && osd2_cursor) {
				osd_hw.osd_rdma_func[output_index].osd_rdma_clr_mask
					(osd_reg->osd_blk0_cfg_w0, 1 << 14);
			}
		} else {
			osd_hw.osd_rdma_func[output_index].osd_rdma_clr_mask
				(osd_reg->osd_blk0_cfg_w0, 1 << 14);
		}
	}
	remove_from_update_list(index, DISP_SCALE_ENABLE);
}

static void osd_set_dummy_data(u32 index, u32 alpha)
{
	u32 output_index = get_output_device_id(index);

	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(hw_osd_reg_array[index].osd_sc_dummy_data,
		osd_hw.osd_meson_dev.dummy_data | alpha);
}

static void osd_update_disp_freescale_enable(u32 index)
{
	u64 hf_phase_step, vf_phase_step;
	int src_w, src_h, dst_w, dst_h;
	int bot_ini_phase, top_ini_phase;
	int vsc_ini_rcv_num, vsc_ini_rpt_p0_num;
	int vsc_bot_rcv_num = 0, vsc_bot_rpt_p0_num = 0;
	int hsc_ini_rcv_num, hsc_ini_rpt_p0_num;
	int hf_bank_len = 4;
	int vf_bank_len = 4;
	int init_phase1 = 0, init_phase1_exp = 0;
	struct hw_osd_reg_s *osd_reg = &hw_osd_reg_array[index];
	u32 data32 = 0x0;
	u32 shift_workaround = 0;
	u32 output_index = 0;

	if (osd_hw.osd_meson_dev.osd_ver != OSD_HIGH_ONE)
		osd_reg = &hw_osd_reg_array[0];

	if (osd_hw.scale_workaround)
		vf_bank_len = 2;
	else
		vf_bank_len = 4;

	output_index = get_output_device_id(index);
	if (osd_hw.hwc_enable[output_index] && index == OSD1)
		shift_workaround = osd_hw.workaround_line;

#ifndef NEW_PPS_PHASE
	if (osd_hw.bot_type == 1) {
		vsc_bot_rcv_num = 4;
		vsc_bot_rpt_p0_num = 1;
	} else if (osd_hw.bot_type == 2) {
		vsc_bot_rcv_num = 6;
		vsc_bot_rpt_p0_num = 2;
	} else if (osd_hw.bot_type == 3) {
		vsc_bot_rcv_num = 8;
		vsc_bot_rpt_p0_num = 3;
	}
	vsc_ini_rcv_num = vf_bank_len;
	vsc_ini_rpt_p0_num =
		(vf_bank_len / 2 - 1) > 0 ? (vf_bank_len / 2 - 1) : 0;
#endif

	if (osd_hw.slice2ppc_enable) {
		src_w = osd_slice2ppc.in_hsize_total;
		src_h = osd_slice2ppc.in_vsize_total;
		dst_w = osd_slice2ppc.out_hsize_total;
		dst_h = osd_slice2ppc.out_vsize_total;
	} else {
		src_w = osd_hw.free_src_data[index].x_end -
			osd_hw.free_src_data[index].x_start + 1;
		src_h = osd_hw.free_src_data[index].y_end -
			osd_hw.free_src_data[index].y_start + 1;
		dst_w = osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		dst_h = osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;
	}
	/* config osd sc control reg */
	data32 = 0x0;
	if (osd_hw.free_scale_enable[index]) {
		/* enable osd scaler */
		if (osd_hw.free_scale_mode[index] & 0x1) {
			/* Todo: */
			if (osd_hw.osd_meson_dev.osd_ver == OSD_NORMAL)
				data32 |= index;  /* select osd1/2 input */
			/* Todo: vd alpha */
			data32 |= 1 << 2; /* enable osd scaler */
			data32 |= 1 << 3; /* enable osd scaler path */
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr
				(osd_reg->osd_sc_ctrl0,
				data32);
		}
	} else {
		/* disable osd scaler path */
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(osd_reg->osd_sc_ctrl0, 0);
	}

	hf_phase_step = (u64)src_w << 24;
	if (dst_w == 0)
		dst_w = 1;
	do_div(hf_phase_step, dst_w);
	if (shift_workaround) {
		vf_phase_step = (u64)(src_h - 1) << 20;
		if (dst_h == 0)
			dst_h = 1;
		do_div(vf_phase_step, dst_h);
	} else {
		vf_phase_step = (u64)src_h << 20;
		if (dst_h == 0)
			dst_h = 1;
		do_div(vf_phase_step, dst_h);
	}

#ifdef NEW_PPS_PHASE
	if (osd_hw.field_out_en[output_index]) {
		struct osd_f2v_vphase_s vphase;

		f2v_get_vertical_phase(vf_phase_step,
				       OSD_F2V_P2IT,
				       vf_bank_len,
				       &vphase);
		vsc_ini_rcv_num = vphase.rcv_num;
		vsc_ini_rpt_p0_num = vphase.rpt_num;
		top_ini_phase = vphase.phase;

		f2v_get_vertical_phase(vf_phase_step,
				       OSD_F2V_P2IB,
				       vf_bank_len,
				       &vphase);
		vsc_bot_rcv_num = vphase.rcv_num;
		vsc_bot_rpt_p0_num = vphase.rpt_num;
		bot_ini_phase = vphase.phase;
	} else {
		struct osd_f2v_vphase_s vphase;

		f2v_get_vertical_phase(vf_phase_step,
				       OSD_F2V_P2P,
				       vf_bank_len,
				       &vphase);
		vsc_ini_rcv_num = vphase.rcv_num;
		vsc_ini_rpt_p0_num = vphase.rpt_num;
		top_ini_phase = vphase.phase;

		vsc_bot_rcv_num = 0;
		vsc_bot_rpt_p0_num = 0;
		bot_ini_phase = 0;
	}
#else
	if (osd_hw.field_out_en[output_index])   /* interface output */
		bot_ini_phase = ((vf_phase_step / 2) >> 4);
	else
		bot_ini_phase = 0;
	top_ini_phase = 0;
#endif

	vf_phase_step = (vf_phase_step << 4);
	/* config osd scaler in/out hv size */
	data32 = 0x0;
	if (shift_workaround) {
		vsc_ini_rcv_num++;
		if (osd_hw.field_out_en[output_index])
			vsc_bot_rcv_num++;
	}

	/* calculate ini_phase */
	if (osd_hw.slice2ppc_enable &&
	    osd_slice2ppc.slice_pos[index] == SLICE_RIGHT) {
		u32 osd_slice_x_st = osd_slice2ppc.slice_in_x_start[index];
		u32 init_phase1_pre, init_phase, slice_ini_sum;
		u64 t;

		t = ((u64)osd_slice_x_st + 1) << 24;
		do_div(t, hf_phase_step);
		init_phase1_pre = (t * hf_phase_step) & 0xFFFFFF;
		init_phase =  init_phase1_pre & 0xFFFFFF;
		init_phase1     = init_phase >> 8;
		init_phase1_exp = init_phase & 0xff;

		slice_ini_sum = t * hf_phase_step;
		hsc_ini_rcv_num =
			4 - (osd_slice_x_st + 1 - (slice_ini_sum >> 24));
		hsc_ini_rpt_p0_num = 0;
	} else {
		hsc_ini_rcv_num = hf_bank_len;
		hsc_ini_rpt_p0_num = hf_bank_len / 2 - 1;
	}

	if (osd_hw.free_scale_enable[index]) {
		u32 in_width, in_height, out_width, out_height;
		u32 out_x_start, out_x_end, out_y_start, out_y_end;

		if (osd_hw.slice2ppc_enable) {
			in_width   = osd_slice2ppc.scaler_in_hsize[index];
			in_height  = osd_slice2ppc.scaler_in_vsize[index];
			out_x_start = 0;
			out_x_end   = osd_slice2ppc.scaler_out_hsize[index] - 1;
			out_y_start = 0;
			out_y_end   = osd_slice2ppc.scaler_out_vsize[index] - 1;
		} else {
			in_width   = src_w;
			in_height  = src_h;
			out_x_start = osd_hw.free_dst_data[index].x_start;
			out_x_end   = osd_hw.free_dst_data[index].x_end;
			out_y_start = osd_hw.free_dst_data[index].y_start;
			out_y_end   = osd_hw.free_dst_data[index].y_end;
		}

		if (osd_dev_hw.s5_display) {
			out_width   = out_x_end - out_x_start + 1;
			out_height  = out_y_end - out_y_start + 1;
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(osd_reg->osd_proc_in_size,
					 (in_height << 16) | in_width);
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(osd_reg->osd_proc_out_size,
					 (out_height << 16) | out_width);
		}

		data32 = ((in_height - 1) & 0x1fff) |
			((in_width - 1) & 0x1fff) << 16;
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(osd_reg->osd_sci_wh_m1, data32);
		data32 = ((out_x_end & 0xfff) | (out_x_start & 0xfff) << 16);
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(osd_reg->osd_sco_h_start_end, data32);
		data32 = ((out_y_end & 0xfff) | (out_y_start & 0xfff) << 16);
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(osd_reg->osd_sco_v_start_end, data32);
	}

	data32 = 0x0;
	if (osd_hw.free_scale[index].v_enable) {
		data32 |= (vf_bank_len & 0x7)
			| ((vsc_ini_rcv_num & 0xf) << 3)
			| ((vsc_ini_rpt_p0_num & 0x3) << 8);
		if (osd_hw.field_out_en[output_index])
			data32 |= ((vsc_bot_rcv_num & 0xf) << 11)
				| ((vsc_bot_rpt_p0_num & 0x3) << 16)
				| (1 << 23);
		if (osd_hw.scale_workaround)
			data32 |= 1 << 21;
		data32 |= 1 << 24;
		if (osd_hw.osd_meson_dev.cpu_id >=
			__MESON_CPU_MAJOR_ID_G12B)
			data32 |= 1 << 25;
	}
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(osd_reg->osd_vsc_ctrl0, data32);
	data32 = 0x0;
	if (osd_hw.free_scale[index].h_enable) {
		data32 |= (hf_bank_len & 0x7)
			| ((hsc_ini_rcv_num & 0xf) << 3)
			| ((hsc_ini_rpt_p0_num & 0x3) << 8);
		data32 |= 1 << 22;
	}
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(osd_reg->osd_hsc_ctrl0, data32);

	data32 = top_ini_phase;
	if (osd_hw.free_scale_enable[index]) {
		data32 |= (bot_ini_phase & 0xffff) << 16;
		if (osd_hw.field_out_en[output_index]) {
			if (shift_workaround)
				src_h--;
			if (src_h == dst_h * 2)
				data32 |= 0x80008000;
		}
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
			(osd_reg->osd_hsc_phase_step,
			hf_phase_step, 0, 28);
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
			(osd_reg->osd_hsc_init_phase, init_phase1, 0, 16);
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
			(osd_reg->osd_hsc_ini_pat_ctrl, init_phase1_exp, 0, 16);
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
			(osd_reg->osd_vsc_phase_step,
			vf_phase_step, 0, 28);
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(osd_reg->osd_vsc_init_phase,
			data32);
	}
	if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE &&
	    !osd_hw.hwc_enable[output_index]) {
		osd_setting_blending_scope(index);
		vpp_blend_setting_default(index);
	}

	remove_from_update_list(index, DISP_FREESCALE_ENABLE);
}

static void osd_update_coef(u32 index)
{
	int i;
	bool need_update_coef = false;
	int *hf_coef, *vf_coef;
	int use_v_filter_mode, use_h_filter_mode;
	int OSD_SCALE_COEF_IDX, OSD_SCALE_COEF;

	if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE) {
		OSD_SCALE_COEF_IDX =
			hw_osd_reg_array[index].osd_scale_coef_idx;
		OSD_SCALE_COEF =
			hw_osd_reg_array[index].osd_scale_coef;
	} else {
		OSD_SCALE_COEF_IDX =
			hw_osd_reg_array[0].osd_scale_coef_idx;
		OSD_SCALE_COEF =
			hw_osd_reg_array[0].osd_scale_coef;
	}
	use_v_filter_mode = osd_hw.use_v_filter_mode[index];
	use_h_filter_mode = osd_hw.use_h_filter_mode[index];
	if (osd_hw.scale_workaround) {
		if (use_v_filter_mode != 3) {
			use_v_filter_mode = 3;
			need_update_coef = true;
		} else {
			need_update_coef = false;
		}
	} else {
		if (use_v_filter_mode != osd_v_filter_mode) {
			use_v_filter_mode = osd_v_filter_mode;
			need_update_coef = true;
		} else {
			need_update_coef = false;
		}
	}
	if (need_update_coef) {
		vf_coef = filter_table[use_v_filter_mode];
		osd_reg_set_bits(OSD_SCALE_COEF_IDX, 0x0000, 0, 9);
		for (i = 0; i < 33; i++)
			osd_reg_write(OSD_SCALE_COEF, vf_coef[i]);
	}
	need_update_coef = false;
	if (use_h_filter_mode != osd_h_filter_mode) {
		use_h_filter_mode = osd_h_filter_mode;
		need_update_coef = true;
	}
	hf_coef = filter_table[use_h_filter_mode];
	if (need_update_coef) {
		osd_reg_set_bits(OSD_SCALE_COEF_IDX, 0x0100, 0, 9);
		for (i = 0; i < 33; i++)
			osd_reg_write(OSD_SCALE_COEF, hf_coef[i]);
	}
	osd_hw.use_v_filter_mode[index] = use_v_filter_mode;
	osd_hw.use_h_filter_mode[index] = use_h_filter_mode;

	remove_from_update_list(index, OSD_FREESCALE_COEF);
}

static int afbc_pix_format(u32 fmt_mode)
{
	u32 pix_format = RGBA8888;

	switch (fmt_mode) {
	case COLOR_INDEX_YUV_422:
		pix_format = YUV422_8B;
		break;
	case COLOR_INDEX_16_565:
		pix_format = RGB565;
		break;
	case COLOR_INDEX_16_1555_A:
		pix_format = RGBA5551;
		break;
	case COLOR_INDEX_16_4444_R:
	case COLOR_INDEX_16_4444_A:
		pix_format = RGBA4444;
		break;
	case COLOR_INDEX_32_BGRX:
	case COLOR_INDEX_32_XBGR:
	case COLOR_INDEX_32_RGBX:
	case COLOR_INDEX_32_XRGB:
	case COLOR_INDEX_32_BGRA:
	case COLOR_INDEX_32_ABGR:
	case COLOR_INDEX_32_RGBA:
	case COLOR_INDEX_32_ARGB:
		pix_format = RGBA8888;
		break;
	case COLOR_INDEX_24_888_B:
	case COLOR_INDEX_24_RGB:
		pix_format = RGB888;
		break;
	case COLOR_INDEX_RGBA_1010102:
		pix_format = RGBA1010102;
		break;
	default:
		osd_log_err("unsupport fmt:%x\n", fmt_mode);
		break;
	}
	return pix_format;
}

static void matrix_RGB2YUV(u32 index, int mtx_csc, int mtx_on)
{
	unsigned int matrix_coef00_01 = 0;
	unsigned int matrix_coef02_10 = 0;
	unsigned int matrix_coef11_12 = 0;
	unsigned int matrix_coef20_21 = 0;
	unsigned int matrix_coef22 = 0;
	unsigned int matrix_coef13_14 = 0;
	unsigned int matrix_coef23_24 = 0;
	unsigned int matrix_coef15_25 = 0;
	unsigned int matrix_clip = 0;
	unsigned int matrix_offset0_1 = 0;
	unsigned int matrix_offset2 = 0;
	unsigned int matrix_pre_offset0_1 = 0;
	unsigned int matrix_pre_offset2 = 0;
	unsigned int matrix_en_ctrl = 0;

	if (index == OSD1) {
		matrix_coef00_01 = VPP_OSD1_MATRIX_COEF00_01;
		matrix_coef02_10 = VPP_OSD1_MATRIX_COEF02_10;
		matrix_coef11_12 = VPP_OSD1_MATRIX_COEF11_12;
		matrix_coef20_21 = VPP_OSD1_MATRIX_COEF20_21;
		matrix_coef22 = VPP_OSD1_MATRIX_COEF22;
		matrix_coef13_14 = VPP_OSD1_MATRIX_COEF13_14;
		matrix_coef23_24 = VPP_OSD1_MATRIX_COEF23_24;
		matrix_coef15_25 = VPP_OSD1_MATRIX_COEF15_25;
		matrix_clip = VPP_OSD1_MATRIX_CLIP;
		matrix_offset0_1 = VPP_OSD1_MATRIX_OFFSET0_1;
		matrix_offset2 = VPP_OSD1_MATRIX_OFFSET2;
		matrix_pre_offset0_1 = VPP_OSD1_MATRIX_PRE_OFFSET0_1;
		matrix_pre_offset2 = VPP_OSD1_MATRIX_PRE_OFFSET2;
		matrix_en_ctrl = VPP_OSD1_MATRIX_EN_CTRL;
	} else {
		matrix_coef00_01 = VPP_OSD2_MATRIX_COEF00_01;
		matrix_coef02_10 = VPP_OSD2_MATRIX_COEF02_10;
		matrix_coef11_12 = VPP_OSD2_MATRIX_COEF11_12;
		matrix_coef20_21 = VPP_OSD2_MATRIX_COEF20_21;
		matrix_coef22 = VPP_OSD2_MATRIX_COEF22;
		matrix_coef13_14 = VPP_OSD2_MATRIX_COEF13_14;
		matrix_coef23_24 = VPP_OSD2_MATRIX_COEF23_24;
		matrix_coef15_25 = VPP_OSD2_MATRIX_COEF15_25;
		matrix_clip = VPP_OSD2_MATRIX_CLIP;
		matrix_offset0_1 = VPP_OSD2_MATRIX_OFFSET0_1;
		matrix_offset2 = VPP_OSD2_MATRIX_OFFSET2;
		matrix_pre_offset0_1 = VPP_OSD2_MATRIX_PRE_OFFSET0_1;
		matrix_pre_offset2 = VPP_OSD2_MATRIX_PRE_OFFSET2;
		matrix_en_ctrl = VPP_OSD2_MATRIX_EN_CTRL;
	}
	if (mtx_on) {
		VSYNCOSD_WR_MPEG_REG_BITS(matrix_en_ctrl, 1, 0, 1);
	} else {
		VSYNCOSD_WR_MPEG_REG_BITS(matrix_en_ctrl, 0, 0, 1);
		return;
	}

	switch (mtx_csc) {
	case MATRIX_RGB_YUV709:
		VSYNCOSD_WR_MPEG_REG(matrix_coef00_01, 0x00bb0275);
		VSYNCOSD_WR_MPEG_REG(matrix_coef02_10, 0x003f1f99);
		VSYNCOSD_WR_MPEG_REG(matrix_coef11_12, 0x1ea601c2);
		VSYNCOSD_WR_MPEG_REG(matrix_coef20_21, 0x01c21e67);
		VSYNCOSD_WR_MPEG_REG(matrix_coef22, 0x00001fd7);
		VSYNCOSD_WR_MPEG_REG(matrix_offset0_1, 0x00400200);
		VSYNCOSD_WR_MPEG_REG(matrix_offset2, 0x00000200);
		VSYNCOSD_WR_MPEG_REG(matrix_pre_offset0_1, 0x0);
		VSYNCOSD_WR_MPEG_REG(matrix_pre_offset2, 0x0);
		break;
	case MATRIX_YUV709_RGB:
		VSYNCOSD_WR_MPEG_REG(matrix_coef00_01, 0x04ac0000);
		VSYNCOSD_WR_MPEG_REG(matrix_coef02_10, 0x073104ac);
		VSYNCOSD_WR_MPEG_REG(matrix_coef11_12, 0x1f251ddd);
		VSYNCOSD_WR_MPEG_REG(matrix_coef20_21, 0x04ac0879);
		VSYNCOSD_WR_MPEG_REG(matrix_coef22, 0x0);
		VSYNCOSD_WR_MPEG_REG(matrix_offset0_1, 0x0);
		VSYNCOSD_WR_MPEG_REG(matrix_offset2, 0x0);
		VSYNCOSD_WR_MPEG_REG(matrix_pre_offset0_1, 0x7c00600);
		VSYNCOSD_WR_MPEG_REG(matrix_pre_offset2, 0x00000600);
		break;
	case MATRIX_YUV709F_RGB:/*full to full*/
		VSYNCOSD_WR_MPEG_REG(matrix_coef00_01, 0x04000000);
		VSYNCOSD_WR_MPEG_REG(matrix_coef02_10, 0x064D0400);
		VSYNCOSD_WR_MPEG_REG(matrix_coef11_12, 0x1F411E21);
		VSYNCOSD_WR_MPEG_REG(matrix_coef20_21, 0x0400076D);
		VSYNCOSD_WR_MPEG_REG(matrix_coef22, 0x0);
		VSYNCOSD_WR_MPEG_REG(matrix_offset0_1, 0x0);
		VSYNCOSD_WR_MPEG_REG(matrix_offset2, 0x0);
		VSYNCOSD_WR_MPEG_REG(matrix_pre_offset0_1, 0x0000600);
		VSYNCOSD_WR_MPEG_REG(matrix_pre_offset2, 0x00000600);
		break;
	default:
		break;
	}
}

static void osd_update_color_mode(u32 index)
{
	u32  data32 = 0;
	u8 hw_colormat = 0;
	struct hw_osd_reg_s *osd_reg = &hw_osd_reg_array[index];
	u32 output_index = get_output_device_id(index);

	if (osd_hw.color_info[index]) {
		enum color_index_e idx =
			osd_hw.color_info[index]->color_index;

		if (osd_hw.osd_meson_dev.cpu_id == __MESON_CPU_MAJOR_ID_S1A) {
			if (idx != COLOR_INDEX_YUV_422)
				matrix_RGB2YUV(index, MATRIX_RGB_YUV709, 1);
			else
				matrix_RGB2YUV(index, MATRIX_RGB_YUV709, 0);
		}
		data32 = (osd_hw.scan_mode[index] ==
			SCAN_MODE_INTERLACE) ? 2 : 0;
		data32 |= osd_hw.osd_rdma_func[output_index].osd_rdma_rd
			(osd_reg->osd_blk0_cfg_w0)
			& 0x70007040;
		data32 |= osd_hw.fb_gem[index].canvas_idx << 16;
		if (osd_hw.osd_afbcd[index].enable &&
		    osd_hw.osd_meson_dev.afbc_type == MALI_AFBC)
			data32 |= OSD_DATA_BIG_ENDIAN << 15;
		else
			data32 |= OSD_DATA_LITTLE_ENDIAN << 15;

		hw_colormat = osd_hw.color_info[index]->hw_colormat;
		/*after t3x VIU_OSD1_BLK0_CFG_W0 rgb16 format bit(bit2-bit5) has change*/
		if (osd_hw.color_info[index]->color_index == COLOR_INDEX_16_565 &&
			osd_hw.osd_meson_dev.cpu_id >= __MESON_CPU_MAJOR_ID_T3X)
			hw_colormat = 2;

		data32 |= hw_colormat << 2;

		/* Todo: what about osd3 */
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
		if (osd_hw.osd_meson_dev.cpu_id <
		    __MESON_CPU_MAJOR_ID_GXTVBB &&
		    index == OSD1) {
			if (osd_hw.color_info[index]->color_index <
				COLOR_INDEX_YUV_422)
				data32 |= 1 << 7; /* yuv enable */
		}
#endif
		if (osd_hw.osd_meson_dev.cpu_id !=
		    __MESON_CPU_MAJOR_ID_GXTVBB &&
		    index == OSD2) {
			if (osd_hw.color_info[index]->color_index <
				COLOR_INDEX_YUV_422)
				data32 |= 1 << 7; /* yuv enable */
		}
		/* osd_blk_mode */
		data32 |=  osd_hw.color_info[index]->hw_blkmode << 8;
		if (osd_hw.osd_v_skip[index])
			data32 |= 1 << 24;
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(osd_reg->osd_blk0_cfg_w0, data32);

		/*
		 * VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK1_CFG_W0, data32);
		 * VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK2_CFG_W0, data32);
		 * VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK3_CFG_W0, data32);
		 */
		if (osd_hw.osd_afbcd[index].enable) {
			if (osd_hw.osd_meson_dev.afbc_type == MESON_AFBC) {
				/* only the RGBA32 mode */
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(OSD1_AFBCD_MODE,
						     (3 << 24) |
						     (4 << 16) |
						     (0xe4 << 8) |
						     (1 << 6) |
						     (1 << 5) |
						     (0x15 << 0));
				/* TODO: add pixel_packing_fmt setting */
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(OSD1_AFBCD_CONV_CTRL,
					 osd_hw.osd_afbcd[index].conv_lbuf_len
					 & 0xffff);
				/* afbc mode RGBA32 -> RGB24
				 * data32 = (0x1b << 24) |
				 *	(osd_hw.osd_afbcd[OSD1].phy_addr
				 *   & 0xffffff);
				 * VSYNCOSD_WR_MPEG_REG(
				 *	OSD1_AFBCD_CHROMA_PTR,
				 *	data32);
				 */
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
					(OSD1_AFBCD_CHROMA_PTR, 0xe4, 24, 8);
				/*
				 * data32 = (0xe4 << 24) |
				 *	(osd_hw.osd_afbcd[OSD1].phy_addr
				 *   & 0xffffff);
				 * VSYNCOSD_WR_MPEG_REG(
				 *	OSD1_AFBCD_CHROMA_PTR,
				 *	data32);
				 */
			} else if (osd_hw.osd_meson_dev.afbc_type ==
				   MALI_AFBC) {
				u32 bpp, pixel_format;
				u32 line_stride, output_stride;
				u32 aligned_32 = 1; /* need get from hwc line */
				u32 afbc_color_reorder = 0x1234;
				/* 0x4321 = ABGR
				 * 0x1234 = RGBA
				 */
				pixel_format = afbc_pix_format
					(osd_hw.osd_afbcd[index].format);
				bpp = osd_hw.color_info[index]->bpp >> 3;
				line_stride = line_stride_calc_afbc
					(pixel_format,
					osd_hw.osd_afbcd[index].frame_width,
					aligned_32);
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(osd_reg->afbc_format_specifier_s,
					(osd_hw.osd_afbcd[index].inter_format |
					(pixel_format & 0xf)));
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
					(osd_reg->osd_mali_unpack_ctrl,
					afbc_color_reorder,
					0, 16);
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
					(osd_reg->osd_blk2_cfg_w4,
					line_stride, 0, 12);
				output_stride =
					osd_hw.osd_afbcd[index].frame_width
					* bpp;
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(osd_reg->afbc_output_buf_stride_s,
					output_stride);
			}
		} else {
			if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE) {
				if (!osd_hw.osd_meson_dev.mif_linear)
					/* line stride should not clear for mif */
					osd_hw.osd_rdma_func[output_index].osd_rdma_wr
						(osd_reg->osd_blk2_cfg_w4, 0);
			}
		}
		if ((idx >= COLOR_INDEX_32_BGRX &&
		     idx <= COLOR_INDEX_32_XRGB) ||
		    (idx >= COLOR_INDEX_32_BGRA &&
		     idx <= COLOR_INDEX_32_ARGB &&
		     osd_hw.blend_mode[index] == BLEND_MODE_NONE))
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(osd_reg->osd_ctrl_stat2,
				0x1ff, 6, 9);
		else
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(osd_reg->osd_ctrl_stat2,
				0, 6, 9);
	}
	remove_from_update_list(index, OSD_COLOR_MODE);
}

static void osd_update_enable(u32 index)
{
	u32 temp_val = 0, output_index;
	struct hw_osd_reg_s *osd_reg = &hw_osd_reg_array[index];

	output_index = get_output_device_id(index);

	if (osd_hw.osd_meson_dev.osd_ver == OSD_SIMPLE)
		osd_set_scan_mode(index);
	if (osd_hw.osd_meson_dev.afbc_type == MESON_AFBC &&
	    osd_hw.enable[index] == ENABLE) {
		/* only for osd1 */
		if ((osd_hw.osd_rdma_func[output_index].osd_rdma_rd
			(VPU_RDARB_MODE_L1C2) &
			(1 << 16)) == 0) {
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(VPU_RDARB_MODE_L1C2,
				1, 16, 1);
		}
	}
	if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL &&
		osd_dev_hw.display_type != C3_DISPLAY) {
		if (index == OSD1)
			temp_val = VPP_OSD1_POSTBLEND;
		else if (index == OSD2)
			temp_val = VPP_OSD2_POSTBLEND;
		if (osd_hw.enable[index] == ENABLE)
			osd_vpp_misc |= temp_val;
		else
			osd_vpp_misc &= ~temp_val;
	}
	if (osd_hw.enable[index] == ENABLE) {
		osd_hw.osd_rdma_func[output_index].osd_rdma_set_mask
			(osd_reg->osd_ctrl_stat,
			1 << 0);
		if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL) {
			if (osd_dev_hw.display_type == C3_DISPLAY) {
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
					(VPU_VOUT_BLEND_CTRL,
					1, 1, 1);
			} else {
				osd_hw.osd_rdma_func[output_index].osd_rdma_set_mask
					(VPP_MISC,
					temp_val |
					VPP_POSTBLEND_EN);
				notify_to_amvideo();
			}
		} else {
			/* notify osd_vpp1_bld_ctrl and osd_vpp2_bld_ctrl */
			if (get_output_device_id(index) != VPP0)
				notify_to_amvideo();
		}
	} else {
		if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL) {
			if (osd_dev_hw.display_type == C3_DISPLAY) {
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
					(VPU_VOUT_BLEND_CTRL,
					0, 1, 1);
			} else {
				notify_to_amvideo();
				osd_hw.osd_rdma_func[output_index].osd_rdma_clr_mask
					(VPP_MISC, temp_val);
			}
		} else {
			if (get_output_device_id(index) != VPP0)
				notify_to_amvideo();
		}
		if (!(osd_hw.osd_meson_dev.cpu_id ==
			__MESON_CPU_MAJOR_ID_G12B))
			osd_hw.osd_rdma_func[output_index].osd_rdma_clr_mask
				(osd_reg->osd_ctrl_stat,
				1 << 0);
	}
	if (osd_hw.osd_meson_dev.afbc_type == MESON_AFBC) {
		if (osd_hw.osd_afbcd[index].enable == ENABLE &&
		    osd_hw.enable[index] == ENABLE) {
			if (!osd_afbc_dec_enable &&
			    osd_hw.osd_afbcd[index].phy_addr != 0) {
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(OSD1_AFBCD_ENABLE, 0x8100);
				osd_afbc_dec_enable = 1;
			}
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(osd_reg->osd_ctrl_stat2,
				1, 15, 1);
			if ((osd_hw.osd_rdma_func[output_index].osd_rdma_rd
				(VIU_MISC_CTRL1) &
			     (0xff << 8)) != 0x9000) {
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
					(VIU_MISC_CTRL1,
					0x90, 8, 8);
			}
		} else {
			if (osd_afbc_dec_enable) {
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(OSD1_AFBCD_ENABLE, 0x8000);
				osd_afbc_dec_enable = 0;
			}
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(osd_reg->osd_ctrl_stat2,
				0, 15, 1);
		}
	} else if (osd_hw.osd_meson_dev.afbc_type
		== MALI_AFBC) {
		if (osd_hw.osd_afbcd[index].enable == ENABLE &&
		    osd_hw.enable[index] == ENABLE &&
		    !osd_hw.dim_layer[index]) {
			if ((!osd_hw.osd_afbcd[index].afbc_start &&
			    osd_hw.osd_afbcd[index].phy_addr != 0) ||
			    !(osd_reg_read(osd_reg->vpu_mafbc_surface_cfg) &
			    (1 << index))) {
				/* enable mali afbc */
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(osd_reg->vpu_mafbc_irq_mask, 0xf);
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
					(osd_reg->vpu_mafbc_surface_cfg,
					0x1, index, 1);
				osd_hw.osd_afbcd[index].afbc_start = 1;
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
					(osd_reg->osd_ctrl_stat2,
					1, 1, 1);
			}
		} else {
			/* disable mali afbc */
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(osd_reg->vpu_mafbc_surface_cfg,
				0x0, index, 1);
			osd_hw.osd_afbcd[index].afbc_start = 0;
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(osd_reg->osd_ctrl_stat2,
				0, 1, 1);
		}
	}
	if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE &&
		osd_hw.hwc_enable[output_index]) {
		u8 postbld_src_sel = 0;
		u8 postbld_osd1, postbld_osd2;

		if (osd_hw.enable[index] == ENABLE) {
			if (osd_dev_hw.display_type == T7_DISPLAY || osd_dev_hw.s5_display) {
				postbld_osd1 = POSTBLD_OSD1_T7;
				postbld_osd2 = POSTBLD_OSD2_T7;
			} else {
				postbld_osd1 = POSTBLD_OSD1;
				postbld_osd2 = POSTBLD_OSD2;
			}
			postbld_src_sel = (index == 0) ? postbld_osd1 : postbld_osd2;
		}
		if (index == 0) {
			if (osd_dev_hw.s5_display) {
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
				(hw_osd_reg_blend.osd1_blend_src_ctrl,
					     (postbld_src_sel & 0xf) << 0 |
					     (0 & 0x1) << 4);
			} else {
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
				(hw_osd_reg_blend.osd1_blend_src_ctrl,
					     (0 & 0xf) << 0 |
					     (0 & 0x1) << 4 |
					     (postbld_src_sel & 0xf) << 8 |
					     (0 & 0x1) << 16 |
					     (1 & 0x1) << 20);
			}
		} else if ((index == 1) && (!enable_vd_zorder)) {
			if (osd_dev_hw.s5_display) {
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
				(hw_osd_reg_blend.osd2_blend_src_ctrl,
					     (postbld_src_sel & 0xf) << 0 |
					     (0 & 0x1) << 4);
			} else {
				if (is_keystone_enable_for_txhd2()) {
					set_vpp_osd2_rgb2yuv(0);
					postbld_src_sel = POSTBLD_CLOSE;
				} else {
					set_vpp_osd2_rgb2yuv(1);
				}
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
				(hw_osd_reg_blend.osd2_blend_src_ctrl,
					     (0 & 0xf) << 0 |
					     (0 & 0x1) << 4 |
					     (postbld_src_sel & 0xf) << 8 |
					     (0 & 0x1) << 16 |
					     (1 & 0x1) << 20);
			}
		}
	}
	remove_from_update_list(index, OSD_ENABLE);
}

static void osd_update_disp_osd_reverse(u32 index)
{
	u32 output_index = get_output_device_id(index);

	if (osd_hw.osd_reverse[index] == REVERSE_TRUE) {
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
			(hw_osd_reg_array[index].osd_blk0_cfg_w0, 3, 28, 2);
		if (osd_hw.osd_meson_dev.afbc_type == MALI_AFBC &&
		    osd_hw.osd_afbcd[index].enable == ENABLE)
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
			(hw_osd_reg_array[index].afbc_prefetch_cfg_s, 3, 0, 2);
	} else if (osd_hw.osd_reverse[index] == REVERSE_X) {
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
			(hw_osd_reg_array[index].osd_blk0_cfg_w0, 1, 28, 2);
		if (osd_hw.osd_meson_dev.afbc_type == MALI_AFBC &&
		    osd_hw.osd_afbcd[index].enable == ENABLE)
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(hw_osd_reg_array[index].afbc_prefetch_cfg_s,
				 1, 0, 2);
	} else if (osd_hw.osd_reverse[index] == REVERSE_Y) {
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
			(hw_osd_reg_array[index].osd_blk0_cfg_w0, 2, 28, 2);
		if (osd_hw.osd_meson_dev.afbc_type == MALI_AFBC &&
		    osd_hw.osd_afbcd[index].enable == ENABLE)
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(hw_osd_reg_array[index].afbc_prefetch_cfg_s,
				 2, 0, 2);
	} else {
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
			(hw_osd_reg_array[index].osd_blk0_cfg_w0, 0, 28, 2);
		if (osd_hw.osd_meson_dev.afbc_type == MALI_AFBC &&
		    osd_hw.osd_afbcd[index].enable == ENABLE)
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(hw_osd_reg_array[index].afbc_prefetch_cfg_s,
				 0, 0, 2);
	}
	remove_from_update_list(index, DISP_OSD_REVERSE);
}

static int get_viu2_src_format(void)
{
	return RGBA;
}

#if defined(CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION) ||\
	defined(CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM)
/* -1: invalid osd index
 *  0: osd is disabled
 *  1: osd is enabled
 */
static int get_osd_status(u32 index)
{
	unsigned int sw_index;

	if (index >= HW_OSD_COUNT)
		return -1;

	sw_index = to_osd_sw_index(index);
	if (sw_index >= OSD_MAX)
		return -1;

	return osd_hw.enable[sw_index];
}
#endif

static void osd_update_disp_osd_rotate(u32 index)
{
	u32 rotate_en = osd_hw.osd_rotate[index];
	u32 src_fmt;
	u32 x_start, x_end, y_start, y_end;
	u32 src_width, src_height;
	u32 rot_hsize, blk_vsize, rd_blk_hsize;
	u32 reg_fmt_buf_en, reg_fmt_444_mode, line5_mode;
	u32 y_reverse = 0, x_reverse = 0;
	u32 data32;
	enum color_index_e idx;
	struct dispdata_s src_data;
	int out_y_crop_start = 0;
	int out_y_crop_end = 0;
#ifdef CONFIG_AMLOGIC_VOUT
#ifdef CONFIG_AMLOGIC_VOUT2_SERVE
	const struct vinfo_s *vinfo = get_current_vinfo2();

	if (!vinfo) {
		osd_log_err("current vinfo NULL\n");
		return;
	}
	out_y_crop_start = 0;
	out_y_crop_end = vinfo->height;
#endif
#endif

	if (osd_hw.osd_meson_dev.cpu_id != __MESON_CPU_MAJOR_ID_G12B)
		return;
	src_fmt = get_viu2_src_format();
	src_data.x = 0;
	src_data.y = 0;
	src_data.w = osd_hw.fb_gem[index].xres;
	src_data.h = osd_hw.fb_gem[index].yres;
	src_width = src_data.w;
	src_height = src_data.h;

	x_start = src_data.x;
	x_end = src_data.x + src_data.w - 1;
	y_start = src_data.y;
	y_end = src_data.y + src_data.h - 1;
	/* x/y start end can be crop axis */
	switch (src_fmt) {
	case YUV422:
		blk_vsize		  = 30;
		rd_blk_hsize	  = 32;
		reg_fmt_buf_en	  = 1;
		reg_fmt_444_mode  = 0;
		line5_mode		  = 1;
		break;
	case RGB:
		blk_vsize		  = 20;
		rd_blk_hsize	  = 22;
		reg_fmt_buf_en	  = 0;
		reg_fmt_444_mode  = 1;
		line5_mode		  = 0;
		break;
	case RGBA:
		blk_vsize		  = 15;
		rd_blk_hsize	  = 16;
		reg_fmt_buf_en	  = 0;
		reg_fmt_444_mode  = 1;
		line5_mode		  = 0;
		break;
	}
	osd_reg_set_bits(VPP2_MISC, rotate_en, 16, 1);
	rotate_en = 0;
	osd_reg_set_bits(VPU_VIU_VENC_MUX_CTRL,
			 rotate_en, 20, 1);
	idx = osd_hw.color_info[index]->color_index;
	data32 = (osd_hw.fb_gem[index].canvas_idx << 16) |
		(2 << 8) | (1 << 7) | (0 << 6) |
		(y_reverse << 5) |
		(x_reverse << 4) | src_fmt;
	osd_reg_set_bits(VIU2_RMIF_CTRL1, data32, 0, 32);
	osd_reg_set_bits(VIU2_RMIF_SCOPE_X,
			 x_end << 16 | x_start, 0, 32);
	osd_reg_set_bits(VIU2_RMIF_SCOPE_Y,
			 y_end << 16 | y_start, 0, 32);

	rot_hsize = (src_height + blk_vsize - 1) / blk_vsize;
	osd_reg_set_bits(VIU2_ROT_BLK_SIZE,
			 rd_blk_hsize | (blk_vsize << 8), 0, 32);
	osd_reg_set_bits(VIU2_ROT_LBUF_SIZE,
			 rot_hsize * rd_blk_hsize |
			 (rot_hsize << 16), 0, 32);
	osd_reg_set_bits(VIU2_ROT_FMT_CTRL,
			 reg_fmt_buf_en |
			 (line5_mode << 1) |
			 (reg_fmt_444_mode << 2) |
			 (180 << 8) | (0xe4 << 24), 0, 32);
	osd_reg_set_bits(VIU2_ROT_OUT_VCROP,
			 out_y_crop_end |
			 out_y_crop_start << 16, 0, 32);
	osd_reg_set_bits(VPP2_OFIFO_SIZE,
			 src_height - 1, 20, 12);
	remove_from_update_list(index, DISP_OSD_ROTATE);
}

static void osd_update_color_key(u32 index)
{
	u32 output_index = get_output_device_id(index);

	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(hw_osd_reg_array[index].osd_tcolor_ag0,
			     osd_hw.color_key[index]);
	remove_from_update_list(index, OSD_COLOR_KEY);
}

static void osd_update_color_key_enable(u32 index)
{
	u32  data32;
	u32 output_index = get_output_device_id(index);

	data32 = osd_hw.osd_rdma_func[output_index].osd_rdma_rd
		(hw_osd_reg_array[index].osd_blk0_cfg_w0);
	data32 &= ~(1 << 6);
	data32 |= (osd_hw.color_key_enable[index] << 6);
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(hw_osd_reg_array[index].osd_blk0_cfg_w0,
		data32);
	/*
	 * VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK1_CFG_W0, data32);
	 * VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK2_CFG_W0, data32);
	 * VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK3_CFG_W0, data32);
	 */
	remove_from_update_list(index, OSD_COLOR_KEY_ENABLE);
}

static void osd_update_gbl_alpha(u32 index)
{
	u32  data32;
	u32 output_index = get_output_device_id(index);

	data32 = osd_hw.osd_rdma_func[output_index].osd_rdma_rd
		(hw_osd_reg_array[index].osd_ctrl_stat);
	data32 &= ~(0x1ff << 12);
	data32 |= osd_hw.gbl_alpha[index] << 12;
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(hw_osd_reg_array[index].osd_ctrl_stat,
		data32);
	remove_from_update_list(index, OSD_GBL_ALPHA);
}

static void osd_update_order(u32 index)
{
	if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL &&
		osd_dev_hw.display_type != C3_DISPLAY) {
		switch (osd_hw.order[index]) {
		case  OSD_ORDER_01:
			if (!osd_hw.hw_rdma_en)
				osd_reg_clr_mask(VPP_MISC,
						 VPP_POST_FG_OSD2 |
						 VPP_PRE_FG_OSD2);
			osd_vpp_misc &= ~(VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2);
			break;
		case  OSD_ORDER_10:
			/* OSD2 is top */
			if (!osd_hw.hw_rdma_en)
				osd_reg_set_mask(VPP_MISC,
						 VPP_POST_FG_OSD2 |
						 VPP_PRE_FG_OSD2);
			osd_vpp_misc |= (VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2);
			break;
		default:
			break;
		}
		notify_to_amvideo();
	}

	remove_from_update_list(index, OSD_CHANGE_ORDER);
}

static void osd1_2x_scale_update_geometry(void)
{
	u32 data32;

	data32 = (osd_hw.scaledata[OSD1].x_start & 0x1fff) |
		 (osd_hw.scaledata[OSD1].x_end & 0x1fff) << 16;
	VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W1, data32);

	if (osd_hw.osd_afbcd[OSD1].enable) {
		data32 = (osd_hw.scaledata[OSD1].x_end & 0x1fff) |
			(osd_hw.scaledata[OSD1].x_start & 0x1fff) << 16;
		VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_PIXEL_HSCOPE, data32);
		data32 = (osd_hw.scaledata[OSD1].y_end & 0x1fff) |
			(osd_hw.scaledata[OSD1].y_start & 0x1fff) << 16;
		VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_PIXEL_VSCOPE, data32);
		VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_HDR_PTR,
				     osd_hw.osd_afbcd[OSD1].phy_addr >> 4);
		VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_FRAME_PTR,
				     osd_hw.osd_afbcd[OSD1].phy_addr >> 4);
		data32 = (0xe4 << 24) |
			(osd_hw.osd_afbcd[OSD1].phy_addr & 0xffffff);
		VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_CHROMA_PTR,
				     data32);
	}

	data32 = ((osd_hw.scaledata[OSD1].y_start
			+ osd_hw.pandata[OSD1].y_start) & 0x1fff)
		 | ((osd_hw.scaledata[OSD1].y_end
			+ osd_hw.pandata[OSD1].y_start) & 0x1fff) << 16;
	VSYNCOSD_WR_MPEG_REG
		(hw_osd_reg_array[OSD1].osd_blk0_cfg_w2, data32);
	/* adjust display x-axis */
	if (osd_hw.scale[OSD1].h_enable) {
		data32 = (osd_hw.dispdata[OSD1].x_start & 0xfff)
			 | ((osd_hw.dispdata[OSD1].x_start
				+ (osd_hw.scaledata[OSD1].x_end
				- osd_hw.scaledata[OSD1].x_start) * 2 + 1)
					 & 0xfff) << 16;
		VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_array[OSD1].osd_blk0_cfg_w3, data32);
		if (osd_hw.scan_mode[OSD1] == SCAN_MODE_INTERLACE) {
			data32 = ((osd_hw.dispdata[OSD1].y_start >> 1) & 0xfff)
				 | (((((osd_hw.dispdata[OSD1].y_start
					+ (osd_hw.scaledata[OSD1].y_end
					- osd_hw.scaledata[OSD1].y_start) * 2)
					+ 1) >> 1) - 1) & 0xfff) << 16;
		} else {
			data32 = (osd_hw.dispdata[OSD1].y_start & 0xfff)
				 | (((osd_hw.dispdata[OSD1].y_start
					+ (osd_hw.scaledata[OSD1].y_end
					- osd_hw.scaledata[OSD1].y_start) * 2))
						 & 0xfff) << 16;
		}
		VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_array[OSD1].osd_blk0_cfg_w4, data32);
	}
	/* adjust display y-axis */
	if (osd_hw.scale[OSD1].v_enable) {
		data32 = (osd_hw.dispdata[OSD1].x_start & 0xfff)
			 | ((osd_hw.dispdata[OSD1].x_start
				+ (osd_hw.scaledata[OSD1].x_end
				- osd_hw.scaledata[OSD1].x_start) * 2 + 1)
					 & 0xfff) << 16;
		VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_array[OSD1].osd_blk0_cfg_w3, data32);
		if (osd_hw.scan_mode[OSD1] == SCAN_MODE_INTERLACE) {
			data32 = ((osd_hw.dispdata[OSD1].y_start >> 1) & 0xfff)
				 | (((((osd_hw.dispdata[OSD1].y_start
					+ (osd_hw.scaledata[OSD1].y_end
					- osd_hw.scaledata[OSD1].y_start) * 2)
					+ 1) >> 1) - 1) & 0xfff) << 16;
		} else {
			data32 = (osd_hw.dispdata[OSD1].y_start & 0xfff)
				 | (((osd_hw.dispdata[OSD1].y_start
					+ (osd_hw.scaledata[OSD1].y_end
					- osd_hw.scaledata[OSD1].y_start) * 2))
						 & 0xfff) << 16;
		}
		VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_array[OSD1].osd_blk0_cfg_w4, data32);
	}
}

static u32 _set_bits(u32 data32, u32 bits, u32 value)
{
	data32 &= ~(1 << bits);
	data32 |= (value << bits);
	return data32;
}

void insert_sort(u32 *array, int length)
{
	int i = 0, j = 0;
	u32 temp;

	/* decrease */
	for (j = 0; j < length; j++) {
		for (i = j + 1; i < length; i++) {
			if (array[j] < array[i]) {
				temp = array[j];
				array[j] = array[i];
				array[i] = temp;
			}
		}
	}
}

static int get_available_layers(u32 output_index)
{
	int i;
	int available_layer = 0;

	for (i = 0 ; i < osd_hw.osd_meson_dev.osd_count; i++) {
		if (osd_hw.enable[i] && validate_osd(i, output_index))
			available_layer++;
	}
	return available_layer;
}

static u32 blend_din_to_osd(u32 blend_din_index,
			    struct hw_osd_blending_s *blending)
{
	u32 osd_index = 0;

	if (!blending)
		return 0;

	osd_index =
		blending->osd_to_bdin_table[blend_din_index];
	if (!validate_osd(osd_index, VIU1))
		return OSD_MAX;
	else
		return osd_index;
}

static u32 get_layer_to_osd(struct hw_osd_blending_s *blending, u32 layer)
{
	int i = 0;
	u32 osd_count = osd_hw.osd_meson_dev.viu1_osd_count;

	for (i = 0; i < osd_count; i++) {
		if (blending->reorder[i] == layer)
			return i;
	}
	return 0;
}

static void exchange_din0_din2(struct hw_osd_blending_s *blending)
{
	int temp1 = 0, temp2 = 0;

	osd_log_dbg(MODULE_BLEND, "need exchange osd din0 and din2 order\n");
	temp1 = blending->din_reoder_sel & 0x000f;
	temp2 = blending->din_reoder_sel & 0x0f00;
	blending->din_reoder_sel &= ~0x0f0f;
	blending->din_reoder_sel |= temp1 << 8;
	blending->din_reoder_sel |= temp2 >> 8;
	temp1 = blending->osd_to_bdin_table[0];
	temp2 = blending->osd_to_bdin_table[2];
	blending->osd_to_bdin_table[2] = temp1;
	blending->osd_to_bdin_table[0] = temp2;
	osd_log_dbg(MODULE_BLEND, "din_reoder_sel%x\n",
		    blending->din_reoder_sel);
}

static void exchange_din2_din3(struct hw_osd_blending_s *blending)
{
	int temp1 = 0, temp2 = 0;

	osd_log_dbg(MODULE_BLEND, "need exchange osd din2 and din3 order\n");
	temp1 = blending->din_reoder_sel & 0x0f00;
	temp2 = blending->din_reoder_sel & 0xf000;
	blending->din_reoder_sel &= ~0xff00;
	blending->din_reoder_sel |= temp1 << 4;
	blending->din_reoder_sel |= temp2 >> 4;
	temp1 = blending->osd_to_bdin_table[2];
	temp2 = blending->osd_to_bdin_table[3];
	blending->osd_to_bdin_table[3] = temp1;
	blending->osd_to_bdin_table[2] = temp2;
	osd_log_dbg(MODULE_BLEND, "din_reoder_sel%x\n",
		    blending->din_reoder_sel);
}

static void exchange_vpp_order(struct hw_osd_blending_s *blending)
{
	blending->b_exchange_blend_in = 1;
	osd_log_dbg(MODULE_BLEND, "need exchange vpp order\n");
}

static void generate_blend_din_table(struct hw_osd_blending_s *blending)
{
	int i = 0;
	int temp1 = 0, temp2 = 0;
	int osd_count = osd_hw.osd_meson_dev.osd_count;

	/* reorder[i] = osd[i]'s display layer */
	for (i = 0; i < OSD_BLEND_LAYERS; i++)
		blending->osd_to_bdin_table[i] = -1;
	blending->din_reoder_sel = 0;
	switch (blending->layer_cnt) {
	case 0:
		break;
	case 1:
		for (i = 0; i < osd_count; i++) {
			if (blending->reorder[i] != LAYER_UNSUPPORT) {
				/* blend_din1 */
				blending->din_reoder_sel |= (i + 1) << 0;
				/* blend_din1 -- osdx */
				blending->osd_to_bdin_table[0] = i;
				break;
			}
		}
		break;
	case 2:
	{
		int temp_index[2] = {0};
		int j = 0;

		for (i = 0; i < osd_count; i++) {
			if (blending->reorder[i] != LAYER_UNSUPPORT) {
				/* save the osd index */
				temp_index[j] = i;
				j++;
			}
		}
		osd_log_dbg(MODULE_BLEND, "blend_din4==%d\n",
			    blending->reorder[temp_index[0]]);
		osd_log_dbg(MODULE_BLEND, "blend_din1==%d\n",
			    blending->reorder[temp_index[1]]);
		/* mode A_C */
		if (blending->osd_blend_mode == OSD_BLEND_A_C) {
			/* blend_din1 */
			blending->din_reoder_sel |= (temp_index[0] + 1) << 0;
			/* blend_din1 -- osdx */
			blending->osd_to_bdin_table[0] = temp_index[0];
			/* blend_din3 */
			blending->din_reoder_sel |= (temp_index[1] + 1) << 12;
			/* blend_din3 -- osdx */
			blending->osd_to_bdin_table[3] = temp_index[1];
			/* exchane vpp osd blend in order */
			if (blending->reorder[temp_index[0]] <
				blending->reorder[temp_index[1]]) {
				blending->b_exchange_blend_in = 1;
				osd_log_dbg(MODULE_BLEND, "need exchange vpp order\n");
			}
		} else {
			if (blending->reorder[temp_index[0]] <
				blending->reorder[temp_index[1]]) {
				/* blend_din4 */
				blending->din_reoder_sel |=
					(temp_index[0] + 1) << 12;
				/* blend_din3 -- osdx */
				blending->osd_to_bdin_table[3] = temp_index[0];
				/* blend_din1 */
				blending->din_reoder_sel |=
					(temp_index[1] + 1) << 0;
				/* blend_din1 -- osdx */
				blending->osd_to_bdin_table[0] = temp_index[1];
				blending->b_exchange_din = 1;
				osd_log_dbg(MODULE_BLEND, "need exchange osd din order\n");
			} else {
				/* blend_din1 */
				blending->din_reoder_sel |=
					(temp_index[0] + 1) << 0;
				/* blend_din1 -- osdx */
				blending->osd_to_bdin_table[0] = temp_index[0];
				/* blend_din3 */
				blending->din_reoder_sel |=
					(temp_index[1] + 1) << 12;
				/* blend_din3 -- osdx */
				blending->osd_to_bdin_table[3] = temp_index[1];
			}
		}
		break;
	}
	case 3:
		/* blend_din1 is bottom, blend_din4 is top layer */
		osd_log_dbg(MODULE_BLEND, "reorder:%d,%d,%d,%d\n",
			    blending->reorder[OSD1],
			    blending->reorder[OSD2],
			    blending->reorder[OSD3],
			    blending->reorder[OSD4]);
		if (blending->osd_blend_mode == OSD_BLEND_AB_C) {
			/* suppose osd0 used blend_din1,
			 * osd1 used din2, osd3 used din4
			 */
			/* blend_din1 */
			blending->din_reoder_sel |= 1 << 0;
			/* blend_din1 -- osd1 */
			blending->osd_to_bdin_table[0] = OSD1;
			/* blend_din3 */
			blending->din_reoder_sel |= (OSD2 + 1) << 8;
			/* blend_din3 -- osd2 */
			blending->osd_to_bdin_table[2] = OSD2;
			/* blend_din4 */
			blending->din_reoder_sel |= (OSD3 + 1) << 12;
			/* blend_din4 -- osd3 */
			blending->osd_to_bdin_table[3] = OSD3;
			if (blending->reorder[OSD1] == LAYER_3 &&
			    blending->reorder[OSD2] == LAYER_2 &&
			    blending->reorder[OSD3] == LAYER_1) {
				osd_log_dbg2(MODULE_BLEND,
					     "use default order\n");
			} else if ((blending->reorder[OSD1] == LAYER_2) &&
				   (blending->reorder[OSD2] == LAYER_3) &&
				   (blending->reorder[OSD3] == LAYER_1)) {
				exchange_din0_din2(blending);
			} else if ((blending->reorder[OSD1] == LAYER_2) &&
				   (blending->reorder[OSD2] == LAYER_1) &&
				   (blending->reorder[OSD3] == LAYER_3)) {
				exchange_vpp_order(blending);
			} else if ((blending->reorder[OSD1] == LAYER_1) &&
				   (blending->reorder[OSD2] == LAYER_2) &&
				   (blending->reorder[OSD3] == LAYER_3)) {
				exchange_din0_din2(blending);
				exchange_vpp_order(blending);
			} else if ((blending->reorder[OSD1] == LAYER_3) &&
				   (blending->reorder[OSD2] == LAYER_1) &&
				   (blending->reorder[OSD3] == LAYER_2)) {
				exchange_din2_din3(blending);
			} else if (blending->reorder[OSD1] == LAYER_1 &&
				   blending->reorder[OSD2] == LAYER_3 &&
				   blending->reorder[OSD3] == LAYER_2) {
				exchange_din2_din3(blending);
				exchange_din0_din2(blending);
				exchange_vpp_order(blending);
			}
		} else if (blending->osd_blend_mode == OSD_BLEND_ABC) {
			u32 osd_index = 0;

			osd_index = get_layer_to_osd(blending, LAYER_3);
			/* blend_din1 is max_order*/
			blending->din_reoder_sel |= (osd_index + 1) << 0;
			blending->osd_to_bdin_table[0] = osd_index;

			osd_index = get_layer_to_osd(blending, LAYER_1);
			/* blend_din4 is min_order*/
			blending->din_reoder_sel |= (osd_index + 1) << 12;
			blending->osd_to_bdin_table[3] = osd_index;

			osd_index = get_layer_to_osd(blending, LAYER_2);
			/* blend_din3 is middle_order*/
			blending->din_reoder_sel |= (osd_index + 1) << 8;
			blending->osd_to_bdin_table[2] = osd_index;
		}
		break;
	case 4:
		/* blend_din1 is bottom, blend_din4 is top layer */
		osd_log_dbg2(MODULE_BLEND, "reorder:%d,%d,%d,%d\n",
			blending->reorder[OSD1],
			blending->reorder[OSD2],
			blending->reorder[OSD3],
			blending->reorder[OSD4]);
		if (blending->osd_blend_mode == OSD_BLEND_AB_CD) {
			u32 osd_index = 0;

			osd_index = get_layer_to_osd(blending, LAYER_1);
			/* blend_din4 is LAYER_1 */
			blending->din_reoder_sel |= (osd_index + 1) << 12;
			blending->osd_to_bdin_table[3] = osd_index;

			osd_index = get_layer_to_osd(blending, LAYER_2);
			/* blend_din3 is LAYER_2*/
			blending->din_reoder_sel |= (osd_index + 1) << 8;
			blending->osd_to_bdin_table[2] = osd_index;

			osd_index = get_layer_to_osd(blending, LAYER_3);
			/* blend_din2 is LAYER_3*/
			blending->din_reoder_sel |= (osd_index + 1) << 4;
			blending->osd_to_bdin_table[1] = osd_index;

			/* blend_din1 is LAYER_4*/
			osd_index = get_layer_to_osd(blending, LAYER_4);
			blending->din_reoder_sel |= (osd_index + 1) << 0;
			blending->osd_to_bdin_table[0] = osd_index;

		} else if (blending->osd_blend_mode == OSD_BLEND_ABCD) {
			u32 osd_index = 0;

			osd_index = get_layer_to_osd(blending, LAYER_1);
			/* blend_din4 is LAYER_1 */
			blending->din_reoder_sel |= (osd_index + 1) << 12;
			blending->osd_to_bdin_table[3] = osd_index;

			osd_index = get_layer_to_osd(blending, LAYER_2);
			/* blend_din3 is LAYER_2*/
			blending->din_reoder_sel |= (osd_index + 1) << 8;
			blending->osd_to_bdin_table[2] = osd_index;

			osd_index = get_layer_to_osd(blending, LAYER_3);
			/* blend_din2 is LAYER_3*/
			blending->din_reoder_sel |= (osd_index + 1) << 4;
			blending->osd_to_bdin_table[1] = osd_index;

			/* blend_din1 is LAYER_4*/
			osd_index = get_layer_to_osd(blending, LAYER_4);
			blending->din_reoder_sel |= (osd_index + 1) << 0;
			blending->osd_to_bdin_table[0] = osd_index;
		}
		break;
	}

	/* workaround for shift issue */
	/* not enable layers used osd4 */
	temp2 = 0;
	for (i = 0; i < OSD_BLEND_LAYERS; i++) {
		temp1 = (blending->din_reoder_sel >> (i * 4)) & 0xf;
		if (!(temp1 & 0x0f)) {
			temp2 |= (0x04 << (i * 4));
		} else {
			temp1 = to_reorder_hw_index(temp1);
			temp2 |= (temp1 << (i * 4));
		}
	}
	blending->din_reoder_sel = temp2;

	osd_log_dbg(MODULE_BLEND, "osd_to_bdin_table[i]=[%x,%x,%x,%x]\n",
		    blending->osd_to_bdin_table[0],
		    blending->osd_to_bdin_table[1],
		    blending->osd_to_bdin_table[2],
		    blending->osd_to_bdin_table[3]);
	blending->osd_blend_reg.din_reoder_sel =
		blending->din_reoder_sel;
}

#ifdef FREESCAL_CHECK
static bool is_freescale_para_changed(u32 index)
{
	static int first[HW_OSD_COUNT - 1] = {1};
	bool freescale_update = false;

	if (memcmp(&osd_hw.free_src_data[index],
		   &osd_hw.free_src_data_backup[index],
		   sizeof(struct pandata_s)) != 0 ||
	    memcmp(&osd_hw.free_dst_data[index],
		   &osd_hw.free_dst_data_backup[index],
		   sizeof(struct pandata_s)) != 0) {
		memcpy(&osd_hw.free_src_data_backup[index],
		       &osd_hw.free_src_data[index],
		       sizeof(struct pandata_s));
		memcpy(&osd_hw.free_dst_data_backup[index],
		       &osd_hw.free_dst_data[index],
		       sizeof(struct pandata_s));
		freescale_update = true;
	}
	if (first[index])
		freescale_update = true;
	first[index] = 0;
	return freescale_update;
}
#endif

static int osd_setting_blending_scope(u32 index)
{
	u32 bld_osd_h_start, bld_osd_h_end;
	u32 bld_osd_v_start, bld_osd_v_end;
	u32 reg_offset = 2;
	u32 output_index = get_output_device_id(index);
	u32 hw_index = index;

	if (index >= osd_hw.osd_meson_dev.viu1_osd_count) {
		osd_log_err("error osd index=%d\n", index);
		return -1;
	}

	if (index == OSD1 && !osd_dev_hw.s5_display &&
		 !osd_hw.osd_meson_dev.osd0_sc_independ) {
		bld_osd_h_start =
			osd_hw.free_src_data[index].x_start;
		bld_osd_h_end =
			osd_hw.free_src_data[index].x_end;
		bld_osd_v_start =
			osd_hw.free_src_data[index].y_start;
		bld_osd_v_end =
			osd_hw.free_src_data[index].y_end;
	} else {
		bld_osd_h_start =
			osd_hw.dst_data[index].x;
		bld_osd_h_end =
			osd_hw.dst_data[index].x +
			osd_hw.dst_data[index].w - 1;
		bld_osd_v_start =
			osd_hw.dst_data[index].y;
		bld_osd_v_end =
			osd_hw.dst_data[index].y +
			osd_hw.dst_data[index].h - 1;
	}

	osd_log_dbg(MODULE_BLEND, "osd%d_hw.dst_data:%d,%d,%d,%d\n",
		    index,
		    osd_hw.dst_data[index].x,
		    osd_hw.dst_data[index].y,
		    osd_hw.dst_data[index].w,
		    osd_hw.dst_data[index].h);
	osd_log_dbg(MODULE_BLEND, "h,v axis:%d,%d,%d,%d\n",
		    bld_osd_h_start,
		    bld_osd_h_end,
		    bld_osd_v_start,
		    bld_osd_v_end);

	hw_index = to_osd_hw_index(index);
	/* for s5_display, osdx to din_scope(x+1) */
	if (osd_dev_hw.s5_display)
		hw_index++;

	/* it is setting for osdx */
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(hw_osd_reg_blend.osd_blend_din0_scope_h +
		reg_offset * hw_index,
		bld_osd_h_end << 16 |
		bld_osd_h_start);
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(hw_osd_reg_blend.osd_blend_din0_scope_v +
		reg_offset * hw_index,
		bld_osd_v_end << 16 |
		bld_osd_v_start);
	return 0;
}

static int vpp_blend_setting_default(u32 index)
{
	u32 osd1_dst_h = 0, osd1_dst_v = 0;
	u32 osd1_h_start = 0, osd1_h_end = 0;
	u32 osd1_v_start = 0, osd1_v_end = 0;
	u32 output_index = get_output_device_id(index);

	osd_log_dbg(MODULE_BASE, "%s\n", __func__);

	if (index >= osd_hw.osd_meson_dev.viu1_osd_count) {
		osd_log_err("error osd index=%d\n", index);
		return -1;
	}
	if (osd_hw.free_scale_enable[index]) {
		if (osd_hw.pi_enable) {
			osd1_h_start = osd_hw.pi_out.x_start;
			osd1_h_end   = osd_hw.pi_out.x_end;
			osd1_v_start = osd_hw.pi_out.y_start;
			osd1_v_end   = osd_hw.pi_out.y_end;
		} else {
			osd1_dst_h = osd_hw.free_dst_data[index].x_end
				- osd_hw.free_dst_data[index].x_start + 1;
			osd1_dst_v = osd_hw.free_dst_data[index].y_end
				- osd_hw.free_dst_data[index].y_start + 1;
			osd1_h_start = osd_hw.free_dst_data[index].x_start;
			osd1_h_end = osd_hw.free_dst_data[index].x_end;
			osd1_v_start = osd_hw.free_dst_data[index].y_start;
			osd1_v_end = osd_hw.free_dst_data[index].y_end;
		}
	} else {
		osd1_dst_h = osd_hw.dispdata[index].x_end
			- osd_hw.dispdata[index].x_start + 1;
		osd1_dst_v = osd_hw.dispdata[index].y_end
			- osd_hw.dispdata[index].y_start + 1;
		osd1_h_start = osd_hw.dispdata[index].x_start;
		osd1_h_end = osd_hw.dispdata[index].x_end;
		osd1_v_start = osd_hw.dispdata[index].y_start;
		osd1_v_end = osd_hw.dispdata[index].y_end;
	}

	if (osd_hw.osd_meson_dev.has_pi) {
		if (osd_hw.pi_enable) {
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(OSD_PI_BYPASS_EN, 0, 0, 1);
		} else {
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(OSD_PI_BYPASS_EN, 1, 0, 1);
		}
		osd_log_dbg(MODULE_BASE, "pi_enable:%d\n", osd_hw.pi_enable);
	}
	/* setting blend scope */
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(hw_osd_reg_blend.vpp_osd1_bld_h_scope,
		osd1_h_start << 16 | osd1_h_end);
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(hw_osd_reg_blend.vpp_osd1_bld_v_scope,
		osd1_v_start << 16 | osd1_v_end);

	return 0;
}

static u32 order[HW_OSD_COUNT];
static struct hw_osd_blending_s osd_blending;

static void set_blend_order(struct hw_osd_blending_s *blending, u32 output_index)
{
	u32 org_order[HW_OSD_COUNT];
	int i = 0, j = 0;
	u32 osd_count = osd_hw.osd_meson_dev.osd_count;

	if (!blending)
		return;

	osd_log_dbg2(MODULE_BLEND, "user space zorder: %d %d %d %d\n",
		    osd_hw.order[0],
		    osd_hw.order[1],
		    osd_hw.order[2],
		    osd_hw.order[3]);

	/* number largest is top layer */
	for (i = 0; i < osd_count; i++) {
		org_order[i] = osd_hw.order[i];
		if (!osd_hw.enable[i] || !validate_osd(i, output_index))
			org_order[i] = 0;
		order[i] = org_order[i];
	}
	osd_log_dbg2(MODULE_BLEND, "org zorder: %d %d %d %d\n",
		     order[0], order[1], order[2], order[3]);

	insert_sort(order, osd_count);
	//check_order_continuous(order);
	osd_log_dbg2(MODULE_BLEND, "after sort:zorder:%d,%d,%d,%d\n",
		     order[0], order[1], order[2], order[3]);

	/* reorder[i] = osd[i]'s display layer */
	for (i = 0; i < osd_count; i++) {
		for (j = 0; j < osd_count; j++) {
			if (order[i] == org_order[j]) {
				if (osd_hw.enable[j] &&
				    validate_osd(j, output_index))
					blending->reorder[j] = LAYER_1 + i;
				else
					blending->reorder[j] =
					LAYER_UNSUPPORT;
			}
		}
	}
	osd_log_dbg2(MODULE_BLEND, "after reorder:zorder:%d,%d,%d,%d\n",
		     blending->reorder[0],
		     blending->reorder[1],
		     blending->reorder[2],
		     blending->reorder[3]);
}

static void set_blend_din(struct hw_osd_blending_s *blending)
{
	int i = 0, osd_index;
	/* workaround for shift issue */
	/* blend_din_en must equal 5 */
	u32 blend_din_en = 0x5;
	u32 osd_count = osd_hw.osd_meson_dev.viu1_osd_count;

	if (!blending)
		return;
	if (osd_dev_hw.display_type == T7_DISPLAY ||
		osd_dev_hw.s5_display)
		blend_din_en = 0x0;
	for (i = 0; i < OSD_BLEND_LAYERS; i++) {
		/* find osd index */
		osd_index = blend_din_to_osd(i, blending);
		if (osd_index >= OSD1 && osd_index < osd_count) {
			/* depend on osd enable */
			blend_din_en = _set_bits(blend_din_en,
						 i,
						 osd_hw.enable[osd_index]);
		}
	}
	osd_log_dbg2(MODULE_BLEND, "%s: blend_din_en=%x\n",
		     __func__, blend_din_en);

	blending->osd_blend_reg.blend_din_en = blend_din_en;
}

static void set_blend_mode(struct hw_osd_blending_s *blending)
{
	u8 osd_blend_mode = OSD_BLEND_NONE;

	if (!blending)
		return;
	switch (blending->layer_cnt) {
	case 0:
		osd_blend_mode = OSD_BLEND_NONE;
		break;
	case 1:
		if (osd_hw.slice2ppc_enable) {
			osd_blend_mode = OSD_BLEND_A_2SLICE;
		} else {
			/* select blend_din1 always */
			osd_blend_mode = OSD_BLEND_A;
		}
		break;
	case 2:
		/* select blend_din1, blend_din4 always */
		if (osd_hw.hdr_used &&
			osd_hw.osd_meson_dev.cpu_id != __MESON_CPU_MAJOR_ID_TXHD2)
			osd_blend_mode = OSD_BLEND_AC;
		else
			osd_blend_mode = OSD_BLEND_A_C;
		break;
	case 3:
		/* select blend_din1, blend_din3 blend_din4 always */
		if (osd_hw.hdr_used)
			osd_blend_mode = OSD_BLEND_ABC;
		else
			osd_blend_mode = OSD_BLEND_AB_C;
		break;
	case 4:
		if (osd_hw.hdr_used)
			osd_blend_mode = OSD_BLEND_ABCD;
		else
			osd_blend_mode = OSD_BLEND_AB_CD;
		break;
	}
	blending->osd_blend_mode = osd_blend_mode;
	osd_log_dbg2(MODULE_BLEND, "osd_blend_mode=%d\n",
		     blending->osd_blend_mode);
}

static void calc_max_output(struct hw_osd_blending_s *blending)
{
	struct layer_blend_s *layer_blend;
	int input1_end_x, input1_end_y;
	int input2_end_x, input2_end_y;
	u32 output_end_x, output_end_y;

	if (!blending)
		return;
	layer_blend = &blending->layer_blend;
	osd_log_dbg2(MODULE_BLEND, "%s input1_data:%d,%d,%d,%d\n",
		     __func__,
		     layer_blend->input1_data.x,
		     layer_blend->input1_data.y,
		     layer_blend->input1_data.w,
		     layer_blend->input1_data.h);
	osd_log_dbg2(MODULE_BLEND, "%s input2_data:%d,%d,%d,%d\n",
		     __func__,
		     layer_blend->input2_data.x,
		     layer_blend->input2_data.y,
		     layer_blend->input2_data.w,
		     layer_blend->input2_data.h);

	input1_end_x = layer_blend->input1_data.x +
		layer_blend->input1_data.w - 1;
	input1_end_y = layer_blend->input1_data.y +
		layer_blend->input1_data.h - 1;
	input2_end_x = layer_blend->input2_data.x +
		layer_blend->input2_data.w - 1;
	input2_end_y = layer_blend->input2_data.y +
		layer_blend->input2_data.h - 1;
	if (layer_blend->input1_data.x < layer_blend->input2_data.x)
		layer_blend->output_data.x = layer_blend->input1_data.x;
	else
		layer_blend->output_data.x = layer_blend->input2_data.x;
	if (layer_blend->input1_data.y < layer_blend->input2_data.y)
		layer_blend->output_data.y = layer_blend->input1_data.y;
	else
		layer_blend->output_data.y = layer_blend->input2_data.y;

	if (input1_end_x < input2_end_x)
		output_end_x = input2_end_x;
	else
		output_end_x = input1_end_x;
	if (input1_end_y < input2_end_y)
		output_end_y = input2_end_y;
	else
		output_end_y = input1_end_y;
	layer_blend->output_data.x = 0;
	layer_blend->output_data.y = 0;
	layer_blend->output_data.w = output_end_x -
		layer_blend->output_data.x + 1;
	layer_blend->output_data.h = output_end_y -
		layer_blend->output_data.y + 1;
}

static void osd_setting_blend0(struct hw_osd_blending_s *blending)
{
	struct osd_blend_reg_s *osd_blend_reg;
	struct layer_blend_s *layer_blend;
	u32 index = 0;
	u32 bld_osd_h_start = 0, bld_osd_h_end = 0;
	u32 bld_osd_v_start = 0, bld_osd_v_end = 0;
	u32 blend_hsize, blend_vsize;

	if (!blending)
		return;
	layer_blend = &blending->layer_blend;
	osd_blend_reg = &blending->osd_blend_reg;
	/* blend0 only accept input1 */
	if (layer_blend->input1 & BYPASS_DIN) {
		osd_blend_reg->din0_byp_blend = 1;
		layer_blend->input1 &= ~BYPASS_DIN;
	}  else if (layer_blend->input2 & BYPASS_DIN) {
		osd_blend_reg->din0_byp_blend = 1;
		layer_blend->input2 &= ~BYPASS_DIN;
	} else {
		osd_blend_reg->din0_byp_blend = 0;
	}
	if (layer_blend->input1 != BLEND_NO_DIN) {
		/* calculate osd blend din scope */
		index = blend_din_to_osd(layer_blend->input1, blending);
		if (index >= OSD_MAX)
			return;
		bld_osd_h_start =
			layer_blend->input1_data.x;
		bld_osd_h_end =
			layer_blend->input1_data.x +
			layer_blend->input1_data.w - 1;
		bld_osd_v_start =
			layer_blend->input1_data.y;
		bld_osd_v_end =
			layer_blend->input1_data.y +
			layer_blend->input1_data.h - 1;
		osd_blend_reg->osd_blend_din_scope_h[index] =
			bld_osd_h_end << 16 | bld_osd_h_start;
		osd_blend_reg->osd_blend_din_scope_v[index] =
			bld_osd_v_end << 16 | bld_osd_v_start;
		osd_log_dbg2(MODULE_BLEND,
			     "blend0:input1_data[osd%d]:%d,%d,%d,%d\n",
			     index,
			     layer_blend->input1_data.x,
			     layer_blend->input1_data.y,
			     layer_blend->input1_data.w,
			     layer_blend->input1_data.h);
	}
	if (layer_blend->input2 != BLEND_NO_DIN) {
		/* calculate osd blend din scope */
		index = blend_din_to_osd(layer_blend->input2, blending);
		if (index >= OSD_MAX)
			return;
		bld_osd_h_start =
			layer_blend->input2_data.x;
		bld_osd_h_end =
			layer_blend->input2_data.x +
			layer_blend->input2_data.w - 1;
		bld_osd_v_start =
			layer_blend->input2_data.y;
		bld_osd_v_end =
			layer_blend->input2_data.y +
			layer_blend->input2_data.h - 1;
		osd_blend_reg->osd_blend_din_scope_h[index] =
			bld_osd_h_end << 16 | bld_osd_h_start;
		osd_blend_reg->osd_blend_din_scope_v[index] =
			bld_osd_v_end << 16 | bld_osd_v_start;
		osd_log_dbg2(MODULE_BLEND,
			    "blend0:input2_data[osd%d]:%d,%d,%d,%d\n",
			     index,
			     layer_blend->input2_data.x,
			     layer_blend->input2_data.y,
			     layer_blend->input2_data.w,
			     layer_blend->input2_data.h);
	}
	if (osd_blend_reg->din0_byp_blend ||
		layer_blend->input1 == BLEND_NO_DIN ||
		layer_blend->input2 == BLEND_NO_DIN) {
		/* blend din3 bypass,output == input */
		if (layer_blend->input1 == BLEND_NO_DIN)
			memcpy(&layer_blend->output_data,
				&layer_blend->input2_data,
				sizeof(struct dispdata_s));
		else
			memcpy(&layer_blend->output_data,
				&layer_blend->input1_data,
				sizeof(struct dispdata_s));
	} else {
		calc_max_output(blending);
	}
	blend_hsize = layer_blend->output_data.w;
	blend_vsize = layer_blend->output_data.h;
	osd_blend_reg->osd_blend_blend0_size =
		blend_vsize  << 16 | blend_hsize;
	osd_log_dbg2(MODULE_BLEND,
		     "blend0:layer_blend->output_data:%d,%d,%d,%d\n",
		     layer_blend->output_data.x,
		     layer_blend->output_data.y,
		     layer_blend->output_data.w,
		     layer_blend->output_data.h);
}

static void osd_setting_blend1(struct hw_osd_blending_s *blending)
{
	struct layer_blend_s *layer_blend;
	struct osd_blend_reg_s *osd_blend_reg;
	u32 index = 0;
	u32 blend_hsize, blend_vsize;
	u32 bld_osd_h_start = 0, bld_osd_h_end = 0;
	u32 bld_osd_v_start = 0, bld_osd_v_end = 0;
	u32 workaround_line = 0;
	/* for g12a blend shift issue */

	if (!blending)
		return;
	if (osd_hw.hdr_used) {
		workaround_line = osd_hw.workaround_line;
	} else {
		if (blending->layer_cnt == 2)
			workaround_line = 0;
		else
			workaround_line = osd_hw.workaround_line;
	}
	layer_blend = &blending->layer_blend;
	osd_blend_reg = &blending->osd_blend_reg;

	if (layer_blend->input1 & BYPASS_DIN) {
		/* blend1_din2 bypass to dout1 */
		osd_blend_reg->din2_osd_sel = 1;
		layer_blend->input1 &= ~BYPASS_DIN;
	} else {
		/* blend1_dout to blend2 */
		osd_blend_reg->din2_osd_sel = 0;
	}
	if (layer_blend->input2 & BYPASS_DIN) {
		/* blend1_din3 bypass to dout1 */
		osd_blend_reg->din3_osd_sel = 1;
		layer_blend->input2 &= ~BYPASS_DIN;
	} else {
		/* blend1_din3 input to blend1 */
		osd_blend_reg->din3_osd_sel = 0;
	}

	if (layer_blend->input1 != BLEND_NO_DIN) {
		index = blend_din_to_osd(layer_blend->input1, blending);
		if (index >= OSD_MAX)
			return;
		/* calculate osd blend din scope */
		bld_osd_h_start =
			layer_blend->input1_data.x;
		bld_osd_h_end =
			layer_blend->input1_data.x +
			layer_blend->input1_data.w - 1;
		bld_osd_v_start =
			layer_blend->input1_data.y;
		bld_osd_v_end =
			layer_blend->input1_data.y +
			layer_blend->input1_data.h - 1;
		osd_blend_reg->osd_blend_din_scope_h[index] =
			bld_osd_h_end << 16 | bld_osd_h_start;
		osd_blend_reg->osd_blend_din_scope_v[index] =
			bld_osd_v_end << 16 | bld_osd_v_start;
		osd_log_dbg2(MODULE_BLEND,
			     "blend1:input1_data[osd%d]:%d,%d,%d,%d\n",
			     index,
			     layer_blend->input1_data.x,
			     layer_blend->input1_data.y,
			     layer_blend->input1_data.w,
			     layer_blend->input1_data.h);
	}
	if (layer_blend->input2 != BLEND_NO_DIN) {
		index = blend_din_to_osd(layer_blend->input2, blending);
		if (index >= OSD_MAX)
			return;
		/* calculate osd blend din scope */
		bld_osd_h_start =
			layer_blend->input2_data.x;
		bld_osd_h_end =
			layer_blend->input2_data.x +
			layer_blend->input2_data.w - 1;
		bld_osd_v_start =
			layer_blend->input2_data.y;
		bld_osd_v_end =
			layer_blend->input2_data.y +
			layer_blend->input2_data.h - 1;
		osd_blend_reg->osd_blend_din_scope_h[index] =
			bld_osd_h_end << 16 | bld_osd_h_start;
		osd_blend_reg->osd_blend_din_scope_v[index] =
			bld_osd_v_end << 16 | bld_osd_v_start;
		osd_log_dbg2(MODULE_BLEND,
			     "blend1:input2_data[osd%d]:%d,%d,%d,%d\n",
			     index,
			     layer_blend->input2_data.x,
			     layer_blend->input2_data.y,
			     layer_blend->input2_data.w,
			     layer_blend->input2_data.h);
	}
	if (osd_blend_reg->din3_osd_sel || layer_blend->input1 == BLEND_NO_DIN) {
		/* blend din3 bypass,output == input */
		if (layer_blend->input2 == BLEND_NO_DIN) {
			memcpy(&layer_blend->output_data,
			       &layer_blend->input1_data,
			       sizeof(struct dispdata_s));
		} else {
			memcpy(&layer_blend->output_data,
			       &layer_blend->input2_data,
			       sizeof(struct dispdata_s));
		}
		layer_blend->output_data.h += workaround_line;

	} else {
		calc_max_output(blending);
	}
	blend_hsize = layer_blend->output_data.w;
	blend_vsize = layer_blend->output_data.h;
	osd_blend_reg->osd_blend_blend1_size =
		blend_vsize  << 16 | blend_hsize;

	osd_log_dbg2(MODULE_BLEND, "blend1:layer_blend->output_data:%d,%d,%d,%d\n",
		     layer_blend->output_data.x,
		     layer_blend->output_data.y,
		     layer_blend->output_data.w,
		     layer_blend->output_data.h);
}

static void osd_setting_blend2(struct hw_osd_blending_s *blending)
{
	struct layer_blend_s *layer_blend;
	struct osd_blend_reg_s *osd_blend_reg;
	u32 blend_hsize, blend_vsize;
	int blend1_input = 0;

	if (!blending)
		return;
	layer_blend = &blending->layer_blend;
	osd_blend_reg = &blending->osd_blend_reg;

	blend_hsize = layer_blend->input1_data.w;
	blend_vsize = layer_blend->input1_data.h;
	/* always used input1_data */
	/* osd_blend_blend0_size share with blend2_size*/
	osd_blend_reg->osd_blend_blend0_size =
		blend_vsize  << 16 | blend_hsize;
	switch (layer_blend->input2) {
	case BLEND1_DIN:
		blend1_input = 0;
		break;
	default:
		/* blend1_dout to dout1 */
		blend1_input = 1;
		break;
	}

	/* premult set */
	osd_blend_reg->blend2_premult_en = 3;
	if (blend1_input) {
		memcpy(&layer_blend->output_data, &layer_blend->input1_data,
		       sizeof(struct dispdata_s));
	} else {
		calc_max_output(blending);
		blend_hsize = layer_blend->output_data.w;
		blend_vsize = layer_blend->output_data.h;
		osd_blend_reg->osd_blend_blend0_size =
			blend_vsize  << 16 | blend_hsize;
		/* blend 0 and blend1 size need same */
		osd_blend_reg->osd_blend_blend1_size =
			osd_blend_reg->osd_blend_blend0_size;
	}
	osd_log_dbg2(MODULE_BLEND, "layer_blend2->output_data:%d,%d,%d,%d\n",
		     layer_blend->output_data.x,
		     layer_blend->output_data.y,
		     layer_blend->output_data.w,
		     layer_blend->output_data.h);
}

static void vpp_setting_blend(struct hw_osd_blending_s *blending)
{
	struct layer_blend_s *layer_blend;
	struct osd_blend_reg_s *osd_blend_reg;
	struct vpp0_blend_reg_s *vpp0_blend_reg;
	u32 osd1_h_start = 0, osd1_h_end = 0;
	u32 osd1_v_start = 0, osd1_v_end = 0;
	u32 osd2_h_start = 0, osd2_h_end = 0;
	u32 osd2_v_start = 0, osd2_v_end = 0;
	u32 postbld_src3_sel = 0, postbld_osd1_premult = 0;
	u32 postbld_src4_sel = 0, postbld_osd2_premult = 0;

	if (!blending)
		return;
	layer_blend = &blending->layer_blend;
	osd_blend_reg = &blending->osd_blend_reg;
	vpp0_blend_reg = &blending->vpp0_blend_reg;

	osd1_h_start = layer_blend->input1_data.x;
	osd1_h_end = layer_blend->input1_data.x +
		layer_blend->input1_data.w - 1;
	osd1_v_start = layer_blend->input1_data.y;
	osd1_v_end = layer_blend->input1_data.y +
		layer_blend->input1_data.h - 1;
	osd2_h_start = layer_blend->input2_data.x;
	osd2_h_end = layer_blend->input2_data.x +
		layer_blend->input2_data.w - 1;
	osd2_v_start = layer_blend->input2_data.y;
	osd2_v_end = layer_blend->input2_data.y +
		layer_blend->input2_data.h - 1;
	/* vpp osd1 postblend scope */
	switch (layer_blend->input1) {
	case BLEND1_DIN:
		if (osd_dev_hw.display_type == T7_DISPLAY ||
			osd_dev_hw.s5_display)
			postbld_src3_sel = POSTBLD_OSD2_T7;
		else
			postbld_src3_sel = POSTBLD_OSD2;
		if (layer_blend->blend_core1_bypass)
			postbld_osd1_premult = 0;
		else
			postbld_osd1_premult = 1;
		vpp0_blend_reg->osd1_h_start = osd2_h_start;
		vpp0_blend_reg->osd1_h_end = osd2_h_end;
		vpp0_blend_reg->osd1_v_start = osd2_v_start;
		vpp0_blend_reg->osd1_v_end = osd2_v_end;
		vpp0_blend_reg->osd1_index = VPP_OSD1;
		break;
	case BLEND2_DIN:
		if (osd_dev_hw.display_type == T7_DISPLAY ||
			osd_dev_hw.s5_display)
			postbld_src3_sel = POSTBLD_OSD1_T7;
		else
			postbld_src3_sel = POSTBLD_OSD1;
		if (osd_blend_reg->din0_byp_blend)
			postbld_osd1_premult = 0;
		else
			postbld_osd1_premult = 1;
		vpp0_blend_reg->osd1_h_start = osd1_h_start;
		vpp0_blend_reg->osd1_h_end = osd1_h_end;
		vpp0_blend_reg->osd1_v_start = osd1_v_start;
		vpp0_blend_reg->osd1_v_end = osd1_v_end;
		vpp0_blend_reg->osd1_index = VPP_OSD1;
		break;
	default:
		postbld_src3_sel = POSTBLD_CLOSE;
		postbld_osd1_premult = 0;
		vpp0_blend_reg->osd1_index = VPP_DIN_NONE;
		break;
	}
	/* vpp osd2 postblend scope */
	switch (layer_blend->input2) {
	case BLEND1_DIN:
		if (osd_dev_hw.display_type == T7_DISPLAY ||
			osd_dev_hw.s5_display)
			postbld_src4_sel = POSTBLD_OSD2_T7;
		else
			postbld_src4_sel = POSTBLD_OSD2;
		if (layer_blend->blend_core1_bypass)
			postbld_osd2_premult = 0;
		else
			postbld_osd2_premult = 1;
		vpp0_blend_reg->osd2_h_start = osd2_h_start;
		vpp0_blend_reg->osd2_h_end = osd2_h_end;
		vpp0_blend_reg->osd2_v_start = osd2_v_start;
		vpp0_blend_reg->osd2_v_end = osd2_v_end;
		vpp0_blend_reg->osd2_index = VPP_OSD3;
		break;
	case BLEND2_DIN:
		if (osd_dev_hw.display_type == T7_DISPLAY ||
			osd_dev_hw.s5_display)
			postbld_src4_sel = POSTBLD_OSD1_T7;
		else
			postbld_src4_sel = POSTBLD_OSD1;
		if (osd_blend_reg->din0_byp_blend)
			postbld_osd2_premult = 0;
		else
			postbld_osd2_premult = 1;
		vpp0_blend_reg->osd2_h_start = osd1_h_start;
		vpp0_blend_reg->osd2_h_end = osd1_h_end;
		vpp0_blend_reg->osd2_v_start = osd1_v_start;
		vpp0_blend_reg->osd2_v_end = osd1_v_end;
		vpp0_blend_reg->osd2_index = VPP_OSD3;
		break;
	default:
		postbld_src4_sel = POSTBLD_CLOSE;
		postbld_osd2_premult = 0;
		vpp0_blend_reg->osd2_index = VPP_DIN_NONE;
		break;
	}
	if (osd_hw.osd_preblend_en) {
		vpp0_blend_reg->prebld_src3_sel = postbld_src3_sel;
		vpp0_blend_reg->prebld_osd1_premult = postbld_osd1_premult;
		vpp0_blend_reg->prebld_src4_sel = postbld_src4_sel;
		vpp0_blend_reg->prebld_osd2_premult = postbld_osd2_premult;
		if (osd_hw.osd_preblend_en == 1)
			vpp0_blend_reg->postbld_src3_sel = 1;
		else if (osd_hw.osd_preblend_en == 2)
			vpp0_blend_reg->postbld_src3_sel = 0;
		vpp0_blend_reg->postbld_osd1_premult = 0;
		vpp0_blend_reg->postbld_src4_sel = 0;
		vpp0_blend_reg->postbld_osd2_premult = 0;
	} else {
		vpp0_blend_reg->prebld_src3_sel = 0;
		vpp0_blend_reg->prebld_osd1_premult = 0;
		vpp0_blend_reg->prebld_src4_sel = 0;
		vpp0_blend_reg->prebld_osd2_premult = 0;
		vpp0_blend_reg->postbld_src3_sel = postbld_src3_sel;
		vpp0_blend_reg->postbld_osd1_premult = postbld_osd1_premult;
		vpp0_blend_reg->postbld_src4_sel = postbld_src4_sel;
		vpp0_blend_reg->postbld_osd2_premult = postbld_osd2_premult;
	}

	if (vpp0_blend_reg->postbld_osd1_premult ||
	    vpp0_blend_reg->prebld_osd1_premult)
		osd_blend_reg->osd_bld_out0_premult = 1;
	if (vpp0_blend_reg->postbld_osd2_premult ||
	    vpp0_blend_reg->prebld_osd2_premult)
		osd_blend_reg->osd_bld_out1_premult = 1;

	if (osd_hw.osd_meson_dev.has_pi && osd_hw.pi_enable) {
		vpp0_blend_reg->osd1_h_start = osd_hw.pi_out.x_start;
		vpp0_blend_reg->osd1_h_end   = osd_hw.pi_out.x_end;
		vpp0_blend_reg->osd1_v_start = osd_hw.pi_out.y_start;
		vpp0_blend_reg->osd1_v_end   = osd_hw.pi_out.y_end;
	}

	osd_log_dbg2(MODULE_BLEND,
		"vpp input1: x=%d, y=%d, w=%d, h=%d\n",
		layer_blend->input1_data.x,
		layer_blend->input1_data.y,
		layer_blend->input1_data.w,
		layer_blend->input1_data.h);
	osd_log_dbg2(MODULE_BLEND,
		"vpp input2: x=%d, y=%d, w=%d, h=%d\n",
		layer_blend->input2_data.x,
		layer_blend->input2_data.y,
		layer_blend->input2_data.w,
		layer_blend->input2_data.h);

	osd_log_dbg2(MODULE_BLEND,
		     "vpp_osd1_blend size=%d,%d,%d,%d\n",
		     vpp0_blend_reg->osd1_h_start,
		     vpp0_blend_reg->osd1_h_end,
		     vpp0_blend_reg->osd1_v_start,
		     vpp0_blend_reg->osd1_v_end);
	osd_log_dbg2(MODULE_BLEND,
		     "vpp_osd2_blend size=%d,%d,%d,%d\n",
		     vpp0_blend_reg->osd2_h_start,
		     vpp0_blend_reg->osd2_h_end,
		     vpp0_blend_reg->osd2_v_start,
		     vpp0_blend_reg->osd2_v_end);
	if (osd_hw.osd_meson_dev.has_pi)
		osd_log_dbg(MODULE_BLEND, "pi enable:%d\n", osd_hw.pi_enable);
}

static void set_osd_dummy_policy(u32 index, u32 src_height, u32 dst_height)
{
	u32 output_index;

	output_index = get_output_device_id(index);

	if (index == OSD1) {
		if (osd_hw.osd_meson_dev.cpu_id ==
		   __MESON_CPU_MAJOR_ID_G12A &&
		   dst_height != src_height &&
		   osd_hw.free_dst_data[index].y_end <
		   osd_hw.vinfo_height[output_index] - 1)
			osd_set_dummy_data(index, 0);
		else
			osd_set_dummy_data(index, 0xff);
	} else {
		if (osd_hw.osd_meson_dev.cpu_id ==
		   __MESON_CPU_MAJOR_ID_G12A &&
		   osd_hw.free_dst_data[index].y_end <
		   osd_hw.vinfo_height[output_index] - 1)
			osd_set_dummy_data(index, 0);
		else
			osd_set_dummy_data(index, 0xff);
	}
}

/* input w, h is background */
static void osd_set_freescale(u32 index,
			      struct hw_osd_blending_s *blending)

{
	struct layer_blend_s *layer_blend;
	struct osd_blend_reg_s *osd_blend_reg;
	u32 width, height;
	u32 src_height;
	u32 workaround_line = osd_hw.workaround_line;
	u32 output_index = 0;

	layer_blend = &blending->layer_blend;
	osd_blend_reg = &blending->osd_blend_reg;
	if (index >= osd_hw.osd_meson_dev.viu1_osd_count) {
		osd_log_err("error osd index=%d\n", index);
		return;
	}
	if (!(osd_hw.osd_display_debug[output_index] &&
	      !osd_hw.free_scale_enable[index])) {
		osd_hw.free_scale_enable[index] = 0x10001;
		osd_hw.free_scale[index].h_enable = 1;
		osd_hw.free_scale[index].v_enable = 1;
		osd_hw.free_scale_mode[index] = 1;
	}
	output_index = get_output_device_id(index);

	if (index == OSD1) {
		osd_hw.free_src_data[index].x_start =
			layer_blend->output_data.x;
		osd_hw.free_src_data[index].x_end =
			layer_blend->output_data.x +
			layer_blend->output_data.w - 1;
		osd_hw.free_src_data[index].y_start =
			layer_blend->output_data.y;
		osd_hw.free_src_data[index].y_end =
			layer_blend->output_data.y +
			layer_blend->output_data.h - 1;

		osd_hw.free_dst_data[index].x_start = 0;
		osd_hw.free_dst_data[index].y_start = 0;
		width = layer_blend->output_data.w *
			blending->screen_ratio_w_num /
			blending->screen_ratio_w_den;
		height = (layer_blend->output_data.h - workaround_line) *
			blending->screen_ratio_h_num /
			blending->screen_ratio_h_den;
		if (osd_hw.field_out_en[output_index])
			height = height >> 1;
	} else {
		osd_hw.free_src_data[index].x_start =
			osd_hw.src_data[index].x;
		osd_hw.free_src_data[index].x_end =
			osd_hw.src_data[index].x +
			osd_hw.src_data[index].w - 1;
		osd_hw.free_src_data[index].y_start =
			osd_hw.src_data[index].y;
		osd_hw.free_src_data[index].y_end =
			osd_hw.src_data[index].y +
			osd_hw.src_data[index].h - 1;
		if (osd_hw.osd_v_skip[index]) {
			osd_hw.free_src_data[index].y_end =
				(osd_hw.src_data[index].y +
			osd_hw.src_data[index].h) / 2 - 1;
		}

		if (blending->osd_blend_mode == OSD_BLEND_AC ||
		    blending->osd_blend_mode == OSD_BLEND_ABC ||
		    blending->osd_blend_mode == OSD_BLEND_ABCD) {
			/* combine mode, need uniformization */
			osd_hw.free_dst_data[index].x_start =
				osd_hw.dst_data[index].x *
				blending->screen_ratio_w_den /
				blending->screen_ratio_w_num;
			osd_hw.free_dst_data[index].y_start =
				osd_hw.dst_data[index].y *
				blending->screen_ratio_h_den /
				blending->screen_ratio_h_num;
			width = osd_hw.dst_data[index].w *
				blending->screen_ratio_w_den /
				blending->screen_ratio_w_num;
			height = osd_hw.dst_data[index].h *
				blending->screen_ratio_h_den /
				blending->screen_ratio_h_num;
		} else if (blending->osd_blend_mode == OSD_BLEND_AB_C) {
			osd_log_dbg(MODULE_BLEND, "blending->blend_din=%d\n",
				    blending->blend_din);
			if (blending->blend_din != BLEND_DIN4) {
				/* combine mode, need uniformization */
				osd_hw.free_dst_data[index].x_start =
					osd_hw.dst_data[index].x *
					blending->screen_ratio_w_den /
					blending->screen_ratio_w_num;
				osd_hw.free_dst_data[index].y_start =
					osd_hw.dst_data[index].y *
					blending->screen_ratio_h_den /
					blending->screen_ratio_h_num;
				width = osd_hw.dst_data[index].w *
					blending->screen_ratio_w_den /
					blending->screen_ratio_w_num;
				height = osd_hw.dst_data[index].h *
					blending->screen_ratio_h_den /
					blending->screen_ratio_h_num;
			} else {
				/* direct used dst as freescale dst */
				osd_hw.free_dst_data[index].x_start =
					osd_hw.dst_data[index].x;
				osd_hw.free_dst_data[index].y_start =
					osd_hw.dst_data[index].y;
				width = osd_hw.dst_data[index].w;
				height = osd_hw.dst_data[index].h;
				/* interleaved case */
				if (osd_hw.field_out_en[output_index]) {
					height = height >> 1;
					osd_hw.free_dst_data[index].y_start >>= 1;
				}
			}
		} else {
			/* direct used dst as freescale dst */
			osd_hw.free_dst_data[index].x_start =
				osd_hw.dst_data[index].x;
			osd_hw.free_dst_data[index].y_start =
				osd_hw.dst_data[index].y;
			width = osd_hw.dst_data[index].w;
			height = osd_hw.dst_data[index].h;
			if (osd_hw.field_out_en[output_index]) {
				height = height >> 1;
				osd_hw.free_dst_data[index].y_start >>= 1;
			}
		}
	}
	osd_hw.free_dst_data[index].x_end =
		osd_hw.free_dst_data[index].x_start +
		width - 1;
	osd_hw.free_dst_data[index].y_end =
		osd_hw.free_dst_data[index].y_start +
		height - 1;

	src_height = osd_hw.free_src_data[index].x_end -
		osd_hw.free_src_data[index].x_start + 1;
	set_osd_dummy_policy(index, src_height, height);
	osd_log_dbg2(MODULE_BLEND, "osd%d:free_src_data:%d,%d,%d,%d\n",
		     index,
		     osd_hw.free_src_data[index].x_start,
		     osd_hw.free_src_data[index].y_start,
		     osd_hw.free_src_data[index].x_end,
		     osd_hw.free_src_data[index].y_end);
	osd_log_dbg2(MODULE_BLEND, "osd%d:free_dst_data:%d,%d,%d,%d\n",
		     index,
		     osd_hw.free_dst_data[index].x_start,
		     osd_hw.free_dst_data[index].y_start,
		     osd_hw.free_dst_data[index].x_end,
		     osd_hw.free_dst_data[index].y_end);
}

static void osd_setting_blend0_input(u32 index,
				     struct hw_osd_blending_s *blending)
{
	struct layer_blend_s *layer_blend;
	u32 workaround_line = 0;
	/* for g12a blend shift issue */

	workaround_line = osd_hw.workaround_line;
	layer_blend = &blending->layer_blend;
	if (index == OSD1) {
		layer_blend->output_data.x =
			blending->dst_data.x;
		layer_blend->output_data.y =
			blending->dst_data.y
			+ workaround_line;
		layer_blend->output_data.w =
			blending->dst_data.w;
		layer_blend->output_data.h =
			blending->dst_data.h;
	} else {
		layer_blend->output_data.x =
			osd_hw.free_dst_data[index].x_start;
		layer_blend->output_data.y =
			osd_hw.free_dst_data[index].y_start
			+ workaround_line;
		layer_blend->output_data.w =
			osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		layer_blend->output_data.h =
			osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;
	}
	osd_log_dbg2(MODULE_BLEND,
		     "blend0_input:input_data[osd%d]:%d,%d,%d,%d\n",
		     index,
		     layer_blend->output_data.x,
		     layer_blend->output_data.y,
		     layer_blend->output_data.w,
		     layer_blend->output_data.h);
}

static void osd_setting_blend1_input(u32 index,
				     struct hw_osd_blending_s *blending)
{
	struct layer_blend_s *layer_blend;
	u32 workaround_line = 0;
	/* for g12a blend shift issue */

	if (osd_hw.hdr_used) {
		workaround_line = osd_hw.workaround_line;
	} else {
		if (blending->layer_cnt == 2)
			workaround_line = 0;
		else
			workaround_line = osd_hw.workaround_line;
	}

	layer_blend = &blending->layer_blend;
	if (index == OSD1) {
			layer_blend->output_data.x =
				blending->dst_data.x;
			layer_blend->output_data.y =
				blending->dst_data.y
				+ workaround_line;
			layer_blend->output_data.w =
				blending->dst_data.w;
			layer_blend->output_data.h =
				blending->dst_data.h;
	} else {
		layer_blend->output_data.x =
			osd_hw.free_dst_data[index].x_start;
		layer_blend->output_data.y =
			osd_hw.free_dst_data[index].y_start
			+ workaround_line;
		layer_blend->output_data.w =
			osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		layer_blend->output_data.h =
			osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;
	}
	osd_log_dbg2(MODULE_BLEND,
		     "blend1_input:input_data[osd%d]:%d,%d,%d,%d\n",
		     index,
		     layer_blend->output_data.x,
		     layer_blend->output_data.y,
		     layer_blend->output_data.w,
		     layer_blend->output_data.h);
}

/* every output is next path input */
static void set_blend_path(struct hw_osd_blending_s *blending)
{
	struct layer_blend_s *layer_blend;
	struct osd_blend_reg_s *osd_blend_reg;
	struct vpp0_blend_reg_s *vpp0_blend_reg;
	struct dispdata_s output1_data;
	u32 index = 0;
	u8 input1 = 0, input2 = 0;
	u32 output_index;
	s32 position_x, position_y;

	if (!blending)
		return;
	output_index = get_output_device_id(index);
	layer_blend = &blending->layer_blend;
	osd_blend_reg = &blending->osd_blend_reg;
	vpp0_blend_reg = &blending->vpp0_blend_reg;
	layer_blend->blend_core1_bypass = 0;
	memset(&layer_blend->input1_data, 0, sizeof(struct dispdata_s));
	memset(&layer_blend->input2_data, 0, sizeof(struct dispdata_s));

	if (osd_hw.osd_preblend_en && output_index == VIU1) {
		position_x = osd_hw.adjust_position_x;
		position_y = osd_hw.adjust_position_y - osd_hw.preblend_y_offset;
	} else {
		position_x = osd_hw.disp_info[output_index].position_x;
		position_y = osd_hw.disp_info[output_index].position_y;
	}
	osd_log_dbg2(MODULE_BLEND, "osd%d:position_x/y:%d,%d;adjust_position_x/y:%d,%d\n",
		     index,
		     position_x,
		     position_y,
		     osd_hw.adjust_position_x,
		     osd_hw.adjust_position_y);

	switch (blending->osd_blend_mode) {
	case OSD_BLEND_NONE:
		vpp0_blend_reg->postbld_osd1_premult = 0;
		vpp0_blend_reg->postbld_src4_sel = POSTBLD_CLOSE;
		vpp0_blend_reg->postbld_src3_sel = POSTBLD_CLOSE;
		vpp0_blend_reg->postbld_osd2_premult = 0;
		break;
	case OSD_BLEND_A:
		/* blend0-->blend2-->sc-->vpp_osd1 or */
		/* sc-->blend0-->blend2-->vpp_osd1 */
		layer_blend->input1 = BLEND_DIN1;
		if (osd_hw.blend_bypass[OSD1])
			layer_blend->input1 |= BYPASS_DIN;
		layer_blend->input2 = BLEND_NO_DIN;
		index = blend_din_to_osd(BLEND_DIN1, blending);
		if (index >= OSD_MAX)
			return;
		if (index == OSD1) {
			osd_setting_blend0_input(index, blending);
			memcpy(&layer_blend->input1_data,
				&layer_blend->output_data,
				sizeof(struct dispdata_s));
			osd_setting_blend0(blending);

			if (!osd_blend_reg->din0_byp_blend) {
				layer_blend->input1 = BLEND0_DIN;
				layer_blend->input2 = BLEND_NO_DIN;
				memcpy(&layer_blend->input1_data,
				       &layer_blend->output_data,
				       sizeof(struct dispdata_s));
				/* same with blend0's background */
				osd_setting_blend2(blending);
			}
			/* osd1 freescale,output is vinfo.w/h */
			osd_log_dbg2(MODULE_BLEND,
				     "after blend: set osd%d freescale\n",
				     index);
			osd_set_freescale(index, blending);

			layer_blend->input1 = BLEND2_DIN;
			layer_blend->input2 = BLEND_NO_DIN;

			layer_blend->input1_data.x =
				osd_hw.free_dst_data[index].x_start +
				position_x;
			layer_blend->input1_data.w =
				osd_hw.free_dst_data[index].x_end -
				osd_hw.free_dst_data[index].x_start + 1;
			layer_blend->input1_data.y =
				osd_hw.free_dst_data[index].y_start +
				position_y;
			layer_blend->input1_data.h =
				osd_hw.free_dst_data[index].y_end -
				osd_hw.free_dst_data[index].y_start + 1;
		} else {
			osd_log_dbg2(MODULE_BLEND,
				     "first: set osd%d freescale\n", index);
			osd_set_freescale(index, blending);
			osd_hw.free_dst_data[index].x_start +=
				position_x;
			osd_hw.free_dst_data[index].x_end +=
				position_x;
			osd_hw.free_dst_data[index].y_start +=
				position_y;
			osd_hw.free_dst_data[index].y_end +=
				position_y;

			osd_setting_blend0_input(index, blending);
			memcpy(&layer_blend->input1_data,
				&layer_blend->output_data,
				sizeof(struct dispdata_s));
			osd_setting_blend0(blending);
			if (!osd_blend_reg->din0_byp_blend) {
				layer_blend->input1 = BLEND0_DIN;
				layer_blend->input2 = BLEND_NO_DIN;
				memcpy(&layer_blend->input1_data,
				       &layer_blend->output_data,
				       sizeof(struct dispdata_s));
				/* same with blend0's background */
				osd_setting_blend2(blending);
			}

			if (index != OSD1) {
				/* if not osd1, need disable osd1 freescale */
				osd_hw.free_scale_enable[OSD1] = 0x0;
				osd_hw.free_scale[OSD1].h_enable = 0;
				osd_hw.free_scale[OSD1].v_enable = 0;
				blending->osd1_freescale_disable = 1;
			}
			/* freescale dst is != vpp input,need adjust */
			layer_blend->input1 = BLEND2_DIN;
			layer_blend->input2 = BLEND_NO_DIN;

			memcpy(&layer_blend->input1_data,
			       &layer_blend->output_data,
			       sizeof(struct dispdata_s));
		}
		vpp_setting_blend(blending);
		break;
	case OSD_BLEND_AC:
		/* blend0 & sc-->blend1-->blend2-->sc-->vpp_osd1 */
		/* sc-->blend0 & blend1-->blend2-->sc-->vpp_osd1 */
		if (!blending->b_exchange_din) {
			input1 = BLEND_DIN1;
			input2 = BLEND_DIN4;
		} else {
			input1 = BLEND_DIN4;
			input2 = BLEND_DIN1;
		}
		layer_blend->input1 = input1;
		layer_blend->input2 = BLEND_NO_DIN;
		index = blend_din_to_osd(input1, blending);
		if (index >= OSD_MAX)
			return;
		if (index != OSD1) {
			/* here used freescale osd1/osd2 */
			osd_log_dbg2(MODULE_BLEND,
				     "before blend0: set osd%d freescale\n",
				     index);
			osd_set_freescale(index, blending);
		}
		osd_setting_blend0_input(index, blending);
		memcpy(&layer_blend->input1_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));
		osd_setting_blend0(blending);
		memcpy(&output1_data, &layer_blend->output_data,
		       sizeof(struct dispdata_s));

		index = blend_din_to_osd(input2, blending);
		if (index >= OSD_MAX)
			return;
		if (index != OSD1) {
			osd_log_dbg2(MODULE_BLEND,
				     "before blend1: set osd%d freescale\n",
				     index);
			osd_set_freescale(index, blending);
		}
		layer_blend->input1 = BLEND_NO_DIN;
		layer_blend->input2 = input2;

		osd_setting_blend1_input(index, blending);
		memcpy(&layer_blend->input2_data,
		       &layer_blend->output_data,
		       sizeof(struct dispdata_s));

		osd_setting_blend1(blending);

		layer_blend->input1 = BLEND0_DIN;
		layer_blend->input2 = BLEND1_DIN;
		/* always used input1_data */
		memcpy(&layer_blend->input1_data, &output1_data,
		       sizeof(struct dispdata_s));
		osd_setting_blend2(blending);

		/* used osd0 freescale */
		osd_set_freescale(OSD1, blending);

		layer_blend->input1 = BLEND2_DIN;
		layer_blend->input2 = BLEND_NO_DIN;
		layer_blend->input1_data.x =
			osd_hw.free_dst_data[OSD1].x_start +
			position_x;
		layer_blend->input1_data.w =
			osd_hw.free_dst_data[OSD1].x_end -
			osd_hw.free_dst_data[OSD1].x_start + 1;
		layer_blend->input1_data.y =
			osd_hw.free_dst_data[OSD1].y_start +
			position_y;
		layer_blend->input1_data.h =
			osd_hw.free_dst_data[OSD1].y_end -
			osd_hw.free_dst_data[OSD1].y_start + 1;
		vpp_setting_blend(blending);
		break;
	case OSD_BLEND_A_C:
		/* blend0 -->blend2-->sc->vpp_osd1 */
		/* sc-->blend1 -->vpp_osd2 */
		/* or */
		/* sc-->blend0 -->blend2-->vpp_osd1 */
		/* sc-->blend1 -->vpp_osd2 */
		layer_blend->input1 = BLEND_DIN1;
		if (osd_hw.blend_bypass[OSD1])
			layer_blend->input1 |= BYPASS_DIN;
		layer_blend->input2 = BLEND_NO_DIN;
		index = blend_din_to_osd(BLEND_DIN1, blending);
		if (index >= OSD_MAX)
			return;
		osd_setting_blend0_input(index, blending);
		memcpy(&layer_blend->input1_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));
		osd_setting_blend0(blending);

		if (!osd_blend_reg->din0_byp_blend) {
			layer_blend->input1 = BLEND0_DIN;
			layer_blend->input2 = BLEND_NO_DIN;
			memcpy(&layer_blend->input1_data,
			       &layer_blend->output_data,
			       sizeof(struct dispdata_s));
			/* background is same with blend0's background */
			osd_setting_blend2(blending);
		}
		/* here freescale osd0 used */
		osd_log_dbg2(MODULE_BLEND,
			     "after blend: set osd%d freescale\n", index);
		osd_set_freescale(index, blending);
		/* save freescale output */
		output1_data.x =
			osd_hw.free_dst_data[index].x_start +
			position_x;
		output1_data.w =
			osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		output1_data.y =
			osd_hw.free_dst_data[index].y_start +
			position_y;
		output1_data.h =
			osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;

		osd_log_dbg2(MODULE_BLEND, "position_x=%d, y=%d\n",
			position_x,
			position_y);

		index = blend_din_to_osd(BLEND_DIN4, blending);
		if (index >= OSD_MAX)
			return;
		/* here freescale osd1/osd2 used */
		osd_log_dbg2(MODULE_BLEND,
			     "before blend1: set osd%d freescale\n", index);
		osd_set_freescale(index, blending);
		layer_blend->input1 = BLEND_NO_DIN;
		/* must bypass for shift workaround */
		layer_blend->input2 = BLEND_DIN4 | BYPASS_DIN;
		layer_blend->blend_core1_bypass = 1;
		osd_setting_blend1_input(index, blending);
		memcpy(&layer_blend->input2_data,
		       &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		/* adjust offset*/
		layer_blend->input2_data.x +=
			position_x;
		layer_blend->input2_data.y +=
			position_y;

		osd_setting_blend1(blending);

		if (!blending->b_exchange_blend_in) {
			layer_blend->input1 = BLEND2_DIN;
			layer_blend->input2 = BLEND1_DIN;
			memcpy(&layer_blend->input1_data, &output1_data,
			       sizeof(struct dispdata_s));
			memcpy(&layer_blend->input2_data,
			       &layer_blend->output_data,
			       sizeof(struct dispdata_s));
		} else {
			layer_blend->input1 = BLEND1_DIN;
			layer_blend->input2 = BLEND2_DIN;
			memcpy(&layer_blend->input1_data,
			       &layer_blend->output_data,
			       sizeof(struct dispdata_s));
			memcpy(&layer_blend->input2_data, &output1_data,
			       sizeof(struct dispdata_s));
		}
		vpp_setting_blend(blending);
		break;
	case OSD_BLEND_ABC:
		/* blend0 -->blend2-->sc-->vpp_osd1 */
		/* sc-->blend1 -->blend2 */
		input1 = BLEND_DIN1;
		input2 = BLEND_DIN4;
		layer_blend->input1 = input1;
		layer_blend->input2 = BLEND_NO_DIN;
		index = blend_din_to_osd(input1, blending);
		if (index >= OSD_MAX)
			return;
		if (index != OSD1) {
			osd_log_dbg2(MODULE_BLEND,
				     "index=%d, need set freescale\n", index);
			osd_set_freescale(index, blending);
		}
		osd_setting_blend0_input(index, blending);
		memcpy(&layer_blend->input1_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));
		osd_setting_blend0(blending);
		memcpy(&output1_data, &layer_blend->output_data,
		       sizeof(struct dispdata_s));

		layer_blend->input1 = BLEND_DIN3;
		layer_blend->input2 = input2;
		index = blend_din_to_osd(layer_blend->input1, blending);
		if (index != OSD1) {
			osd_log_dbg2(MODULE_BLEND,
				     "blend1 input1: set osd%d freescale\n",
				     index);
			osd_set_freescale(index, blending);
		}
		osd_setting_blend1_input(index, blending);
		memcpy(&layer_blend->input1_data,
		       &layer_blend->output_data,
		       sizeof(struct dispdata_s));

		index = blend_din_to_osd(layer_blend->input2, blending);
		if (index >= OSD_MAX)
			return;
		if (index != OSD1) {
			osd_log_dbg2(MODULE_BLEND,
				     "blend1 input2: set osd%d freescale\n",
				     index);
			osd_set_freescale(index, blending);
		}
		osd_setting_blend1_input(index, blending);
		memcpy(&layer_blend->input2_data,
		       &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		osd_setting_blend1(blending);

		layer_blend->input1 = BLEND0_DIN;
		layer_blend->input2 = BLEND1_DIN;
		memcpy(&layer_blend->input1_data, &output1_data,
		       sizeof(struct dispdata_s));
		memcpy(&layer_blend->input2_data, &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		osd_setting_blend2(blending);
		/* used osd0 freescale */
		osd_set_freescale(OSD1, blending);

		layer_blend->input1 = BLEND2_DIN;
		layer_blend->input2 = BLEND_NO_DIN;
		layer_blend->input1_data.x =
			osd_hw.free_dst_data[OSD1].x_start +
			position_x;
		layer_blend->input1_data.w =
			osd_hw.free_dst_data[OSD1].x_end -
			osd_hw.free_dst_data[OSD1].x_start + 1;
		layer_blend->input1_data.y =
			osd_hw.free_dst_data[OSD1].y_start +
			position_y;
		layer_blend->input1_data.h =
			osd_hw.free_dst_data[OSD1].y_end -
			osd_hw.free_dst_data[OSD1].y_start + 1;
		vpp_setting_blend(blending);
		break;
	case OSD_BLEND_A_BC:
		/* blend0 -->blend2-->sc->vpp_osd1 */
		/* 2input-->sc-->blend1 -->vpp_osd2 */
		layer_blend->input1 = BLEND_DIN1;
		if (osd_hw.blend_bypass[OSD1])
			layer_blend->input1 |= BYPASS_DIN;
		layer_blend->input2 = BLEND_NO_DIN;
		index = blend_din_to_osd(BLEND_DIN1, blending);
		if (index >= OSD_MAX)
			return;
		osd_setting_blend0_input(index, blending);
		osd_setting_blend0(blending);

		if (!osd_blend_reg->din0_byp_blend) {
			layer_blend->input1 = BLEND0_DIN;
			layer_blend->input2 = BLEND_NO_DIN;
			memcpy(&layer_blend->input1_data,
			       &layer_blend->output_data,
			       sizeof(struct dispdata_s));
			/* background is same with blend0's background */
			osd_setting_blend2(blending);
		}

		osd_log_dbg(MODULE_BLEND,
			    "after blend2: set osd%d freescale\n", index);
		osd_set_freescale(index, blending);
		/* save freescale output */
		output1_data.x =
			osd_hw.free_dst_data[index].x_start +
			position_x;
		output1_data.w =
			osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		output1_data.y =
			osd_hw.free_dst_data[index].y_start +
			position_y;
		output1_data.h =
			osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;
		index = blend_din_to_osd(BLEND_DIN3, blending);
		if (index >= OSD_MAX)
			return;
		osd_log_dbg2(MODULE_BLEND,
			     "before blend1: set osd%d freescale\n", index);
		osd_set_freescale(index, blending);
		layer_blend->input1_data.x =
			osd_hw.free_dst_data[index].x_start +
			position_x;
		layer_blend->input1_data.w =
			osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		layer_blend->input1_data.y =
			osd_hw.free_dst_data[index].y_start +
			position_y;
		layer_blend->input1_data.h =
			osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;

		index = blend_din_to_osd(BLEND_DIN4, blending);
		if (index >= OSD_MAX)
			return;
		osd_log_dbg2(MODULE_BLEND,
			     "before blend1: set osd%d freescale\n", index);
		osd_set_freescale(index, blending);
		layer_blend->input2_data.x =
			osd_hw.free_dst_data[index].x_start +
			position_x;
		layer_blend->input2_data.w =
			osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		layer_blend->input2_data.y =
			osd_hw.free_dst_data[index].y_start +
			position_y;
		layer_blend->input2_data.h =
			osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;

		/* always route(bypass) to dout1 */
		layer_blend->input1 = BLEND_DIN3 | BYPASS_DIN;
		layer_blend->input2 = BLEND_DIN4;

		osd_setting_blend1(blending);

		if (!blending->b_exchange_blend_in) {
			layer_blend->input1 = BLEND2_DIN;
			layer_blend->input2 = BLEND1_DIN;
			memcpy(&layer_blend->input1_data, &output1_data,
			       sizeof(struct dispdata_s));
			memcpy(&layer_blend->input2_data,
			       &layer_blend->output_data,
			       sizeof(struct dispdata_s));
		} else {
			layer_blend->input1 = BLEND1_DIN;
			layer_blend->input2 = BLEND2_DIN;
			memcpy(&layer_blend->input1_data,
			       &layer_blend->output_data,
			       sizeof(struct dispdata_s));
			memcpy(&layer_blend->input2_data,
			       &output1_data,
			       sizeof(struct dispdata_s));
		}
		vpp_setting_blend(blending);
		break;
	case OSD_BLEND_AB_C:
		/* blend0 -->blend2-->sc->vpp_osd1 */
		/* sc-->blend1-->blend2-->sc-->vpp_osd1 */
		/* sc -->vpp_osd2 */
		layer_blend->input1 = BLEND_DIN1;
		layer_blend->input2 = BLEND_NO_DIN;
		blending->blend_din = BLEND_DIN1;
		index = blend_din_to_osd(BLEND_DIN1, blending);
		if (index != OSD1) {
			osd_log_info("index=%d, need set freescale\n", index);
			osd_set_freescale(index, blending);
		}
		osd_setting_blend0_input(index, blending);
		memcpy(&layer_blend->input1_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));
		osd_setting_blend0(blending);
		/* save blend0 output */
		memcpy(&output1_data, &layer_blend->output_data,
		       sizeof(struct dispdata_s));

		/* din3 input to blend1 */
		layer_blend->input1 = BLEND_DIN3;
		layer_blend->input2 = BLEND_NO_DIN | BYPASS_DIN;
		layer_blend->blend_core1_bypass = 1;
		blending->blend_din = BLEND_DIN3;
		index = blend_din_to_osd(BLEND_DIN3, blending);
		if (index != OSD1) {
			osd_log_dbg2(MODULE_BLEND,
				     "before blend1: set osd%d freescale\n",
				     index);
			osd_set_freescale(index, blending);
		}
		osd_setting_blend1_input(index, blending);
		memcpy(&layer_blend->input1_data,
		       &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		osd_setting_blend1(blending);

		/* din1=>blend0 & din3-> blend1 ==> blend2 */
		layer_blend->input1 = BLEND0_DIN;
		layer_blend->input2 = BLEND1_DIN;
		memcpy(&layer_blend->input1_data, &output1_data,
		       sizeof(struct dispdata_s));
		memcpy(&layer_blend->input2_data, &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		osd_setting_blend2(blending);

		/* blend2 ==> osd0 freescale */
		osd_set_freescale(OSD1, blending);
		output1_data.x =
			osd_hw.free_dst_data[OSD1].x_start +
			position_x;
		output1_data.w =
			osd_hw.free_dst_data[OSD1].x_end -
			osd_hw.free_dst_data[OSD1].x_start + 1;
		output1_data.y =
			osd_hw.free_dst_data[OSD1].y_start +
			position_y;
		output1_data.h =
			osd_hw.free_dst_data[OSD1].y_end -
			osd_hw.free_dst_data[OSD1].y_start + 1;
		osd_log_dbg2(MODULE_BLEND, "output1_data:%d,%d,%d,%d\n",
			     output1_data.x,
			     output1_data.w,
			     output1_data.y,
			     output1_data.h);

		/* din4 ==> vpp */
		index = blend_din_to_osd(BLEND_DIN4, blending);
		blending->blend_din = BLEND_DIN4;
		osd_log_dbg2(MODULE_BLEND,
			     "bypass blend1: set osd%d freescale\n", index);
		osd_set_freescale(index, blending);

		layer_blend->input2_data.x =
			osd_hw.free_dst_data[index].x_start +
			position_x;
		layer_blend->input2_data.w =
			osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		layer_blend->input2_data.y =
			osd_hw.free_dst_data[index].y_start +
			position_y;
		layer_blend->input2_data.h =
			osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;

		/* 2vpp input */
		if (!blending->b_exchange_blend_in) {
			layer_blend->input1 = BLEND2_DIN;
			layer_blend->input2 = BLEND1_DIN;
			memcpy(&layer_blend->input1_data, &output1_data,
			       sizeof(struct dispdata_s));
		} else {
			layer_blend->input1 = BLEND1_DIN;
			layer_blend->input2 = BLEND2_DIN;
			memcpy(&layer_blend->input1_data,
			       &layer_blend->input2_data,
			       sizeof(struct dispdata_s));
			memcpy(&layer_blend->input2_data,
			       &output1_data,
			       sizeof(struct dispdata_s));
		}
		vpp_setting_blend(blending);
		break;
	case OSD_BLEND_ABCD:
		/* blend0 -->blend2-->sc-->vpp_osd1 */
		/* sc-->blend1 -->blend2 */
		layer_blend->input1 = BLEND_DIN1;
		layer_blend->input2 = BLEND_DIN2;
		blending->blend_din = BLEND_DIN1;
		index = blend_din_to_osd(layer_blend->input1, blending);
		if (index != OSD1) {
			osd_log_dbg2(MODULE_BLEND,
				    "index=%d, need set freescale\n", index);
			osd_set_freescale(index, blending);
		}
		osd_setting_blend0_input(index, blending);
		memcpy(&layer_blend->input1_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));

		blending->blend_din = BLEND_DIN2;
		index = blend_din_to_osd(layer_blend->input2, blending);
		if (index != OSD1) {
			osd_log_dbg2(MODULE_BLEND,
				    "index=%d, need set freescale\n", index);
			osd_set_freescale(index, blending);
		}
		osd_setting_blend0_input(index, blending);
		memcpy(&layer_blend->input2_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));
		osd_setting_blend0(blending);

		memcpy(&output1_data, &layer_blend->output_data,
			sizeof(struct dispdata_s));

		layer_blend->input1 = BLEND_DIN3;
		layer_blend->input2 = BLEND_DIN4;
		index = blend_din_to_osd(layer_blend->input1, blending);
		if (index != OSD1) {
			osd_log_dbg2(MODULE_BLEND,
				"blend1 input1: set osd%d freescale\n",
				index);
			osd_set_freescale(index, blending);
		}
		osd_setting_blend1_input(index, blending);
		memcpy(&layer_blend->input1_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));

		index = blend_din_to_osd(layer_blend->input2, blending);
		if (index >= OSD_MAX)
			return;
		if (index != OSD1) {
			osd_log_dbg2(MODULE_BLEND,
				"blend1 input2: set osd%d freescale\n",
				index);
			osd_set_freescale(index, blending);
		}
		osd_setting_blend1_input(index, blending);
		memcpy(&layer_blend->input2_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));
		osd_setting_blend1(blending);

		layer_blend->input1 = BLEND0_DIN;
		layer_blend->input2 = BLEND1_DIN;
		memcpy(&layer_blend->input1_data, &output1_data,
			sizeof(struct dispdata_s));
		memcpy(&layer_blend->input2_data, &layer_blend->output_data,
			sizeof(struct dispdata_s));
		osd_setting_blend2(blending);
		/* used osd0 freescale */
		osd_set_freescale(OSD1, blending);

		layer_blend->input1 = BLEND2_DIN;
		layer_blend->input2 = BLEND_NO_DIN;
		layer_blend->input1_data.x =
			osd_hw.free_dst_data[OSD1].x_start +
			position_x;
		layer_blend->input1_data.w =
			osd_hw.free_dst_data[OSD1].x_end -
			osd_hw.free_dst_data[OSD1].x_start + 1;
		layer_blend->input1_data.y =
			osd_hw.free_dst_data[OSD1].y_start +
			position_y;
		layer_blend->input1_data.h =
			osd_hw.free_dst_data[OSD1].y_end -
			osd_hw.free_dst_data[OSD1].y_start + 1;
		vpp_setting_blend(blending);
		break;
	case OSD_BLEND_AB_CD:
		/* blend0 -->blend2-->sc-->vpp_osd1 */
		/* sc-->blend1 -->blend2 */
		layer_blend->input1 = BLEND_DIN1;
		layer_blend->input2 = BLEND_DIN2;
		blending->blend_din = BLEND_DIN1;
		index = blend_din_to_osd(layer_blend->input1, blending);
		if (index != OSD1) {
			osd_log_dbg2(MODULE_BLEND,
				"index=%d, need set freescale\n", index);
			osd_set_freescale(index, blending);
		}
		osd_setting_blend0_input(index, blending);
		memcpy(&layer_blend->input1_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));
		blending->blend_din = BLEND_DIN2;
		index = blend_din_to_osd(layer_blend->input2, blending);
		if (index != OSD1) {
			osd_log_dbg2(MODULE_BLEND,
				"index=%d, need set freescale\n", index);
			osd_set_freescale(index, blending);
		}
		osd_setting_blend0_input(index, blending);
		memcpy(&layer_blend->input2_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));
		osd_setting_blend0(blending);

		if (!osd_blend_reg->din0_byp_blend) {
			layer_blend->input1 = BLEND0_DIN;
			layer_blend->input2 = BLEND_NO_DIN;
			memcpy(&layer_blend->input1_data,
				&layer_blend->output_data,
				sizeof(struct dispdata_s));
			/* background is same with blend0's background */
			osd_setting_blend2(blending);
		}

		osd_log_dbg2(MODULE_BLEND,
			    "after blend2: set osd%d freescale\n", OSD1);
		osd_set_freescale(OSD1, blending);
		/* save freescale output */
		output1_data.x =
			osd_hw.free_dst_data[OSD1].x_start +
			position_x;
		output1_data.w =
			osd_hw.free_dst_data[OSD1].x_end -
			osd_hw.free_dst_data[OSD1].x_start + 1;
		output1_data.y =
			osd_hw.free_dst_data[OSD1].y_start +
			position_y;
		output1_data.h =
			osd_hw.free_dst_data[OSD1].y_end -
			osd_hw.free_dst_data[OSD1].y_start + 1;

		index = blend_din_to_osd(BLEND_DIN3, blending);
		if (index >= OSD_MAX)
			return;
		osd_log_dbg2(MODULE_BLEND,
			    "before blend1: set osd%d freescale\n", index);
		osd_set_freescale(index, blending);
		layer_blend->input1_data.x =
			osd_hw.free_dst_data[index].x_start +
			position_x;
		layer_blend->input1_data.w =
			osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		layer_blend->input1_data.y =
			osd_hw.free_dst_data[index].y_start +
			position_y;
		layer_blend->input1_data.h =
			osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;

		index = blend_din_to_osd(BLEND_DIN4, blending);
		if (index >= OSD_MAX)
			return;
		osd_log_dbg2(MODULE_BLEND,
			    "before blend1: set osd%d freescale\n", index);
		osd_set_freescale(index, blending);
		layer_blend->input2_data.x =
			osd_hw.free_dst_data[index].x_start +
			position_x;
		layer_blend->input2_data.w =
			osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		layer_blend->input2_data.y =
			osd_hw.free_dst_data[index].y_start +
			position_y;
		layer_blend->input2_data.h =
			osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;

		/* always route(bypass) to dout1 */
		layer_blend->input1 = BLEND_DIN3 | BYPASS_DIN;
		layer_blend->input2 = BLEND_DIN4;

		osd_setting_blend1(blending);

		if (!blending->b_exchange_blend_in) {
			layer_blend->input1 = BLEND2_DIN;
			layer_blend->input2 = BLEND1_DIN;
			memcpy(&layer_blend->input1_data, &output1_data,
				sizeof(struct dispdata_s));
			memcpy(&layer_blend->input2_data,
				&layer_blend->output_data,
				sizeof(struct dispdata_s));
		} else {
			layer_blend->input1 = BLEND1_DIN;
			layer_blend->input2 = BLEND2_DIN;
			memcpy(&layer_blend->input1_data,
				&layer_blend->output_data,
				sizeof(struct dispdata_s));
			memcpy(&layer_blend->input2_data,
				&output1_data,
				sizeof(struct dispdata_s));
		}
		vpp_setting_blend(blending);
		break;
	}
}

static void osd_setting_blend0_new(struct hw_osd_blending_s *blending)
{
	struct osd_blend_reg_s *osd_blend_reg;
	struct layer_blend_s *layer_blend;
	u32 index = 0;
	u32 bld_osd_h_start = 0, bld_osd_h_end = 0;
	u32 bld_osd_v_start = 0, bld_osd_v_end = 0;
	u32 blend_hsize, blend_vsize;

	if (!blending)
		return;
	layer_blend = &blending->layer_blend;
	osd_blend_reg = &blending->osd_blend_reg;
	/* blend0 only accept input1 */
	if (layer_blend->input1 & BYPASS_DIN) {
		osd_blend_reg->din0_byp_blend = 1;
		layer_blend->input1 &= ~BYPASS_DIN;
	} else {
		osd_blend_reg->din0_byp_blend = 0;
	}
	if (layer_blend->input1 != BLEND_NO_DIN) {
		/* calculate osd blend din scope */
		index = blend_din_to_osd(layer_blend->input1, blending);
		if (index >= OSD_MAX)
			return;
		layer_blend->input1_data.x =
			osd_hw.free_dst_data[index].x_start;
		layer_blend->input1_data.y =
			osd_hw.free_dst_data[index].y_start;
		layer_blend->input1_data.w =
			osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		layer_blend->input1_data.h =
			osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;

		bld_osd_h_start =
			layer_blend->input1_data.x;
		bld_osd_h_end =
			layer_blend->input1_data.x +
			layer_blend->input1_data.w - 1;
		bld_osd_v_start =
			layer_blend->input1_data.y;
		bld_osd_v_end =
			layer_blend->input1_data.y +
			layer_blend->input1_data.h - 1;
		osd_blend_reg->osd_blend_din_scope_h[index] =
			bld_osd_h_end << 16 | bld_osd_h_start;
		osd_blend_reg->osd_blend_din_scope_v[index] =
			bld_osd_v_end << 16 | bld_osd_v_start;
		osd_log_dbg2(MODULE_BLEND,
			     "blend0:input1_data[osd%d]:%d,%d,%d,%d\n",
			     index,
			     layer_blend->input1_data.x,
			     layer_blend->input1_data.y,
			     layer_blend->input1_data.w,
			     layer_blend->input1_data.h);
	}
	if (layer_blend->input2 != BLEND_NO_DIN) {
		index = blend_din_to_osd(layer_blend->input2, blending);
		if (index >= OSD_MAX)
			return;
		layer_blend->input2_data.x =
			osd_hw.free_dst_data[index].x_start;
		layer_blend->input2_data.y =
			osd_hw.free_dst_data[index].y_start;
		layer_blend->input2_data.w =
			osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		layer_blend->input2_data.h =
			osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;
		/* calculate osd blend din scope */
		bld_osd_h_start =
			layer_blend->input2_data.x;
		bld_osd_h_end =
			layer_blend->input2_data.x +
			layer_blend->input2_data.w - 1;
		bld_osd_v_start =
			layer_blend->input2_data.y;
		bld_osd_v_end =
			layer_blend->input2_data.y +
			layer_blend->input2_data.h - 1;
		osd_blend_reg->osd_blend_din_scope_h[index] =
			bld_osd_h_end << 16 | bld_osd_h_start;
		osd_blend_reg->osd_blend_din_scope_v[index] =
			bld_osd_v_end << 16 | bld_osd_v_start;
		osd_log_dbg2(MODULE_BLEND,
			     "blend0:input2_data[osd%d]:%d,%d,%d,%d\n",
			     index,
			     layer_blend->input2_data.x,
			     layer_blend->input2_data.y,
			     layer_blend->input2_data.w,
			     layer_blend->input2_data.h);
	}

	if (osd_blend_reg->din0_byp_blend || layer_blend->input1 == BLEND_NO_DIN) {
		/* blend din3 bypass,output == input */
		if (layer_blend->input2 == BLEND_NO_DIN)
			memcpy(&layer_blend->output_data,
				&layer_blend->input1_data,
				sizeof(struct dispdata_s));
		else
			memcpy(&layer_blend->output_data,
				&layer_blend->input2_data,
				sizeof(struct dispdata_s));
	} else {
		calc_max_output(blending);
	}
	blend_hsize = layer_blend->output_data.w;
	blend_vsize = layer_blend->output_data.h;
	osd_blend_reg->osd_blend_blend0_size =
		blend_vsize  << 16 | blend_hsize;

	osd_log_dbg2(MODULE_BLEND,
		     "blend0:layer_blend->output_data:%d,%d,%d,%d\n",
		     layer_blend->output_data.x,
		     layer_blend->output_data.y,
		     layer_blend->output_data.w,
		     layer_blend->output_data.h);
}

static void osd_setting_blend1_new(struct hw_osd_blending_s *blending)
{
	struct layer_blend_s *layer_blend;
	struct osd_blend_reg_s *osd_blend_reg;
	u32 index = 0;
	u32 blend_hsize, blend_vsize;
	u32 bld_osd_h_start = 0, bld_osd_h_end = 0;
	u32 bld_osd_v_start = 0, bld_osd_v_end = 0;
	/* for g12a blend shift issue */

	if (!blending)
		return;
	layer_blend = &blending->layer_blend;
	osd_blend_reg = &blending->osd_blend_reg;
	if (layer_blend->input1 & BYPASS_DIN) {
		/* blend1_din2 bypass to dout1 */
		osd_blend_reg->din2_osd_sel = 1;
		layer_blend->input1 &= ~BYPASS_DIN;
	} else {
		/* blend1_dout to blend2 */
		osd_blend_reg->din2_osd_sel = 0;
	}
	if (layer_blend->input2 & BYPASS_DIN) {
		/* blend1_din3 bypass to dout1 */
		osd_blend_reg->din3_osd_sel = 1;
		layer_blend->input2 &= ~BYPASS_DIN;
	} else {
		/* blend1_din3 input to blend1 */
		osd_blend_reg->din3_osd_sel = 0;
	}
	if (layer_blend->input1 != BLEND_NO_DIN) {
		index = blend_din_to_osd(layer_blend->input1, blending);
		if (index >= OSD_MAX)
			return;
		layer_blend->input1_data.x =
			osd_hw.free_dst_data[index].x_start;
		layer_blend->input1_data.y =
			osd_hw.free_dst_data[index].y_start;
		layer_blend->input1_data.w =
			osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		layer_blend->input1_data.h =
			osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;

		/* calculate osd blend din scope */
		bld_osd_h_start =
			layer_blend->input1_data.x;
		bld_osd_h_end =
			layer_blend->input1_data.x +
			layer_blend->input1_data.w - 1;
		bld_osd_v_start =
			layer_blend->input1_data.y;
		bld_osd_v_end =
			layer_blend->input1_data.y +
			layer_blend->input1_data.h - 1;
		osd_blend_reg->osd_blend_din_scope_h[index] =
			bld_osd_h_end << 16 | bld_osd_h_start;
		osd_blend_reg->osd_blend_din_scope_v[index] =
			bld_osd_v_end << 16 | bld_osd_v_start;
		osd_log_dbg2(MODULE_BLEND,
			     "blend1:input1_data(osd%d):%d,%d,%d,%d\n",
			     index,
			     layer_blend->input1_data.x,
			     layer_blend->input1_data.y,
			     layer_blend->input1_data.w,
			     layer_blend->input1_data.h);
	}
	if (layer_blend->input2 != BLEND_NO_DIN) {
		index = blend_din_to_osd(layer_blend->input2, blending);
		if (index >= OSD_MAX)
			return;
		layer_blend->input2_data.x =
			osd_hw.free_dst_data[index].x_start;
		layer_blend->input2_data.y =
			osd_hw.free_dst_data[index].y_start;
		layer_blend->input2_data.w =
			osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		layer_blend->input2_data.h =
			osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;
		/* calculate osd blend din scope */
		bld_osd_h_start =
			layer_blend->input2_data.x;
		bld_osd_h_end =
			layer_blend->input2_data.x +
			layer_blend->input2_data.w - 1;
		bld_osd_v_start =
			layer_blend->input2_data.y;
		bld_osd_v_end =
			layer_blend->input2_data.y +
			layer_blend->input2_data.h - 1;
		osd_blend_reg->osd_blend_din_scope_h[index] =
			bld_osd_h_end << 16 | bld_osd_h_start;
		osd_blend_reg->osd_blend_din_scope_v[index] =
			bld_osd_v_end << 16 | bld_osd_v_start;
		osd_log_dbg2(MODULE_BLEND,
			     "layer_blend1:input2_data:%d,%d,%d,%d\n",
			     layer_blend->input2_data.x,
			     layer_blend->input2_data.y,
			     layer_blend->input2_data.w,
			     layer_blend->input2_data.h);
	}
	if (osd_blend_reg->din3_osd_sel || layer_blend->input1 == BLEND_NO_DIN) {
		/* blend din3 bypass,output == input */
		if (layer_blend->input2 == BLEND_NO_DIN) {
			memcpy(&layer_blend->output_data,
			       &layer_blend->input1_data,
			       sizeof(struct dispdata_s));
		} else {
			memcpy(&layer_blend->output_data,
			       &layer_blend->input2_data,
			       sizeof(struct dispdata_s));
		}
	} else {
		calc_max_output(blending);
	}
	blend_hsize = layer_blend->output_data.w;
	blend_vsize = layer_blend->output_data.h;
	osd_blend_reg->osd_blend_blend1_size =
		blend_vsize  << 16 | blend_hsize;

	osd_log_dbg2(MODULE_BLEND, "layer_blend1->output_data:%d,%d,%d,%d\n",
		     layer_blend->output_data.x,
		     layer_blend->output_data.y,
		     layer_blend->output_data.w,
		     layer_blend->output_data.h);
}

/* input w, h is background */
static void osd_set_freescale_new(u32 index,
				  struct hw_osd_blending_s *blending)

{
	struct layer_blend_s *layer_blend;
	struct osd_blend_reg_s *osd_blend_reg;
	u32 width, height;
	u32 src_height;
	u32 output_index;

	layer_blend = &blending->layer_blend;
	osd_blend_reg = &blending->osd_blend_reg;
	if (index >= osd_hw.osd_meson_dev.viu1_osd_count) {
		osd_log_err("error osd index=%d\n", index);
		return;
	}
	output_index = get_output_device_id(index);

	if (!(osd_hw.osd_display_debug[output_index] &&
	      !osd_hw.free_scale_enable[index])) {
		osd_hw.free_scale_enable[index] = 0x10001;
		osd_hw.free_scale[index].h_enable = 1;
		osd_hw.free_scale[index].v_enable = 1;
		osd_hw.free_scale_mode[index] = 1;
	}

	osd_hw.free_src_data[index].x_start =
		osd_hw.src_data[index].x;
	osd_hw.free_src_data[index].x_end =
		osd_hw.src_data[index].x +
		osd_hw.src_data[index].w - 1;
	osd_hw.free_src_data[index].y_start =
		osd_hw.src_data[index].y;
	osd_hw.free_src_data[index].y_end =
		osd_hw.src_data[index].y +
		osd_hw.src_data[index].h - 1;

	/* direct used dst as freescale dst */
	osd_hw.free_dst_data[index].x_start =
		osd_hw.dst_data[index].x;
	osd_hw.free_dst_data[index].y_start =
		osd_hw.dst_data[index].y;
	width = osd_hw.dst_data[index].w;
	height = osd_hw.dst_data[index].h;
	if (osd_hw.field_out_en[output_index]) {
		height = height >> 1;
		osd_hw.free_dst_data[index].y_start >>= 1;
	}
	osd_hw.free_dst_data[index].x_end =
		osd_hw.free_dst_data[index].x_start +
		width - 1;
	osd_hw.free_dst_data[index].y_end =
		osd_hw.free_dst_data[index].y_start +
		height - 1;

	src_height = osd_hw.free_src_data[index].x_end -
		osd_hw.free_src_data[index].x_start + 1;
	osd_set_dummy_data(index, 0xff);
	osd_log_dbg2(MODULE_BLEND, "osd%d:free_src_data:%d,%d,%d,%d\n",
		     index,
		     osd_hw.free_src_data[index].x_start,
		     osd_hw.free_src_data[index].y_start,
		     osd_hw.free_src_data[index].x_end,
		     osd_hw.free_src_data[index].y_end);
	osd_log_dbg2(MODULE_BLEND, "osd%d:free_dst_data:%d,%d,%d,%d\n",
		     index,
		     osd_hw.free_dst_data[index].x_start,
		     osd_hw.free_dst_data[index].y_start,
		     osd_hw.free_dst_data[index].x_end,
		     osd_hw.free_dst_data[index].y_end);
}

static void dup_param_for_osd_hw(u32 dst_index, u32 src_index)
{
	u32 src = src_index, dst = dst_index;

	osd_hw.enable[dst] = osd_hw.enable[src];
	osd_hw.osd_afbcd[dst].enable = osd_hw.osd_afbcd[src].enable;

	osd_hw.gbl_alpha[dst] = osd_hw.gbl_alpha[src];
	osd_hw.dim_layer[dst] = osd_hw.dim_layer[src];
	osd_hw.dim_color[dst] = osd_hw.dim_color[src];
	osd_hw.secure_enable[dst] = osd_hw.secure_enable[src];
	osd_hw.blend_mode[dst] = osd_hw.blend_mode[src];

	memcpy(&osd_hw.color_info[dst], &osd_hw.color_info[src],
	       sizeof(struct color_bit_define_s));
	memcpy(&osd_hw.fb_gem[dst], &osd_hw.fb_gem[src],
	       sizeof(struct fb_geometry_s));

	memcpy(&osd_hw.osd_afbcd[dst], &osd_hw.osd_afbcd[src],
		sizeof(struct afbcd_data_s));
	osd_hw.osd_afbcd[dst].out_addr_id = dst + 1;

	osd_hw.free_scale_enable[dst] = osd_hw.free_scale_enable[src];
	osd_hw.free_scale[dst].h_enable = osd_hw.free_scale[src].h_enable;
	osd_hw.free_scale[dst].v_enable = osd_hw.free_scale[src].v_enable;
	osd_hw.free_scale_mode[dst] = osd_hw.free_scale_mode[src];
}

static void osd_2slice_param_init(u32 index_orin)
{
	u32 horz_phase_step, osd_slice_in_x_st;
	u32 hwincut_en[HWIN_NUM] = {1, 1, 0};
	u32 hwincut_bgn[HWIN_NUM] = {0,};
	u32 hwincut_end[HWIN_NUM] = {0,};
	u32 osd_pps_din_hsize[OSD_MAX] = {0,}; /* pps include overlap */
	u32 osd_pps_dout_hsize[OSD_MAX] = {0,};
	u32 osd_slice_dout_hsize[OSD_MAX] = {0,};
	u32 slice_pad_en = 0;
	u32 slice_pad_h_bgn = 0, slice_pad_h_end = 0;
	u32 slice_pad_v_bgn = 0, slice_pad_v_end = 0;
	u32 xoffset, yoffset, left, right;
	u32 osd_in_hsize_real, osd_out_hsize_real;
	u32 osd_in_vsize_real, osd_out_vsize_real;
	u32 i, count  = osd_hw.osd_meson_dev.viu1_osd_count;
	u64 t;

	if (osd_dev_hw.s5_display) {
		if (osd_hw.osd_meson_dev.cpu_id == __MESON_CPU_MAJOR_ID_S5) {
			osd_slice2ppc.slice_pos[OSD1] = SLICE_LEFT;
			osd_slice2ppc.slice_pos[OSD2] = SLICE_RIGHT;
			osd_slice2ppc.slice_pos[OSD3] = SLICE_NONE;
			osd_slice2ppc.slice_pos[OSD4] = SLICE_NONE;
			left = OSD1;
			right = OSD2;
		} else {
			osd_slice2ppc.slice_pos[OSD1] = SLICE_LEFT;
			osd_slice2ppc.slice_pos[OSD2] = SLICE_NONE;
			osd_slice2ppc.slice_pos[OSD3] = SLICE_RIGHT;
			osd_slice2ppc.slice_pos[OSD4] = SLICE_NONE;
			left = OSD1;
			right = OSD3;
		}
	}

	for (i = 0; i < count; i++) {
		if (osd_slice2ppc.slice_pos[i] == SLICE_NONE || i == index_orin)
			continue;
		dup_param_for_osd_hw(i, index_orin);
	}

	/* 2slice in & out size */
	osd_in_hsize_real  = osd_hw.src_data[index_orin].w;
	osd_out_hsize_real = osd_hw.dst_data[index_orin].w;
	osd_in_vsize_real = osd_hw.src_data[index_orin].h;
	osd_out_vsize_real = osd_hw.dst_data[index_orin].h;

	xoffset = osd_hw.src_data[index_orin].x;
	yoffset = osd_hw.src_data[index_orin].y;

	if (osd_hw.field_out_en[VIU1])
		osd_out_vsize_real = osd_out_vsize_real >> 1;

	for (i = 0; i < count; i++) {
		t = (u64)osd_in_hsize_real << 24;
		do_div(t, osd_out_hsize_real);
		horz_phase_step = t;

		/* hscaler_en=0 */
		if (osd_in_hsize_real == osd_out_hsize_real) {
			if (osd_slice2ppc.slice_pos[i] == SLICE_LEFT) {
				osd_pps_dout_hsize[i] =
					SIZE_ALIG8(osd_out_hsize_real) / 2 +
					SCALER_OVERLAP;
				osd_pps_din_hsize[i] = osd_pps_dout_hsize[i];
				/* left hwincut */
				hwincut_bgn[HWIN_IN_0] = 0;
				hwincut_end[HWIN_IN_0] =
					SIZE_ALIG8(osd_out_hsize_real) / 2 - 1;
			}
			if (osd_slice2ppc.slice_pos[i] == SLICE_RIGHT) {
				osd_pps_dout_hsize[i] =
					osd_out_hsize_real -
					SIZE_ALIG8(osd_out_hsize_real) / 2 +
					SCALER_OVERLAP;
				osd_pps_din_hsize[i] = osd_pps_dout_hsize[i];
				/* right hwincut */
				hwincut_bgn[HWIN_IN_1] = SCALER_OVERLAP;
				hwincut_end[HWIN_IN_1] =
					osd_pps_dout_hsize[i] - 1;
			}
		/* hscaler_en=1 */
		} else {
			if (osd_slice2ppc.slice_pos[i] == SLICE_LEFT) {
				osd_slice_dout_hsize[i] =
					SIZE_ALIG8(osd_out_hsize_real) / 2;

				osd_pps_din_hsize[i] =
					(((u64)osd_slice_dout_hsize[i] *
					  horz_phase_step >> 24) + 1) / 2 * 2 +
					  SCALER_OVERLAP;
				t = (u64)osd_pps_din_hsize[i] << 24;
				do_div(t, horz_phase_step);
				osd_pps_dout_hsize[i] = (t + 1) / 2 * 2;

				/* left hwincut */
				hwincut_bgn[HWIN_IN_0] = 0;
				hwincut_end[HWIN_IN_0] =
					SIZE_ALIG8(osd_out_hsize_real) / 2 - 1;
			}

			if (osd_slice2ppc.slice_pos[i] == SLICE_RIGHT) {
				osd_slice_in_x_st =
					osd_pps_din_hsize[0] -
					SCALER_OVERLAP * 2;
				osd_slice_dout_hsize[i] =
					osd_out_hsize_real -
					SIZE_ALIG8(osd_out_hsize_real) / 2;

				osd_pps_din_hsize[i] =
					osd_in_hsize_real -
					osd_pps_din_hsize[0] +
					SCALER_OVERLAP * 2;
				t = (u64)osd_pps_din_hsize[i] << 24;
				do_div(t, horz_phase_step);
				osd_pps_dout_hsize[i] = (t + 1) / 2 * 2;

				/* right hwincut */
				hwincut_bgn[HWIN_IN_1] =
					osd_pps_dout_hsize[i] -
					osd_slice_dout_hsize[i];
				hwincut_end[HWIN_IN_1] =
					osd_pps_dout_hsize[i] - 1;
			}
		}

		/* right hwin padding */
		if (osd_slice2ppc.slice_pos[i] == SLICE_RIGHT) {
			slice_pad_h_bgn = 0;
			slice_pad_h_end = osd_out_hsize_real -
				SIZE_ALIG8(osd_out_hsize_real) / 2 - 1;
			slice_pad_v_bgn = 0;
			slice_pad_v_end = osd_out_vsize_real - 1;

			if (osd_out_hsize_real < SIZE_ALIG8(osd_out_hsize_real))
				slice_pad_en = 1;
			else
				slice_pad_en = 0;
		}
	}

	/* after 2slice hwincut */
	hwincut_bgn[HWIN_OUT] = 0;
	hwincut_end[HWIN_OUT] = osd_out_hsize_real / 2 - 1;

	if (osd_out_hsize_real < SIZE_ALIG8(osd_out_hsize_real))
		hwincut_en[HWIN_OUT] = 1;
	else
		hwincut_en[HWIN_OUT] = 0;

	/* a. 2slice register values */
	osd_slice2ppc.slice2ppc_hsize = SIZE_ALIG8(osd_out_hsize_real) / 2;
	osd_slice2ppc.slice2ppc_vsize = osd_out_vsize_real;
	osd_slice2ppc.slice2ppc_mode = 0;

	for (i = 0; i < HWIN_NUM; i++) {
		osd_slice2ppc.hwincut_en[i] = hwincut_en[i];
		osd_slice2ppc.hwincut_bgn[i] = hwincut_bgn[i];
		osd_slice2ppc.hwincut_end[i] = hwincut_end[i];
	}

	osd_slice2ppc.pad_en = slice_pad_en;
	osd_slice2ppc.pad_h_bgn = slice_pad_h_bgn;
	osd_slice2ppc.pad_h_end = slice_pad_h_end;
	osd_slice2ppc.pad_v_bgn = slice_pad_v_bgn;
	osd_slice2ppc.pad_v_end = slice_pad_v_end;

	/* b. values for calculation */
	osd_slice2ppc.in_hsize_total = osd_in_hsize_real;
	osd_slice2ppc.in_vsize_total = osd_in_vsize_real;
	osd_slice2ppc.out_hsize_total = osd_out_hsize_real;
	osd_slice2ppc.out_vsize_total = osd_out_vsize_real;

	for (i = 0; i < count; i++) {
		if (osd_slice2ppc.slice_pos[i] == SLICE_NONE)
			continue;
		osd_slice2ppc.scaler_in_hsize[i] = osd_pps_din_hsize[i];
		osd_slice2ppc.scaler_in_vsize[i] = osd_in_vsize_real;
		osd_slice2ppc.scaler_out_hsize[i] = osd_pps_dout_hsize[i];
		osd_slice2ppc.scaler_out_vsize[i] = osd_out_vsize_real;
	}
	osd_slice2ppc.slice_in_x_start[left]  = xoffset;
	osd_slice2ppc.slice_in_x_end[left]    = xoffset +
						osd_pps_din_hsize[0] - 1;
	osd_slice2ppc.slice_in_x_start[right] = xoffset +
						osd_pps_din_hsize[0] -
						SCALER_OVERLAP * 2;
	osd_slice2ppc.slice_in_x_end[right]   = xoffset +
						osd_in_hsize_real - 1;

	osd_slice2ppc.slice_in_y_start[left]  = yoffset;
	osd_slice2ppc.slice_in_y_end[left]    = yoffset +
						osd_in_vsize_real - 1;
	osd_slice2ppc.slice_in_y_start[right] = yoffset;
	osd_slice2ppc.slice_in_y_end[right]   = yoffset +
						osd_in_vsize_real - 1;

	osd_log_dbg2(MODULE_2SLICE, "in_hsize_total:%d in_vsize_total:%d\n",
		     osd_slice2ppc.in_hsize_total,
		     osd_slice2ppc.in_vsize_total);
	osd_log_dbg2(MODULE_2SLICE, "out_hsize_total:%d out_vsize_total:%d\n",
		     osd_slice2ppc.out_hsize_total,
		     osd_slice2ppc.out_vsize_total);

	osd_log_dbg2(MODULE_2SLICE, "slice2ppc --- hsize:%d vsize:%d mode:%d\n",
		     osd_slice2ppc.slice2ppc_hsize,
		     osd_slice2ppc.slice2ppc_vsize,
		     osd_slice2ppc.slice2ppc_mode);

	for (i = 0; i < HWIN_NUM; i++) {
		osd_log_dbg2(MODULE_2SLICE, "hwincut %d --- en:%d bgn:%d end:%d\n",
			     i,
			     osd_slice2ppc.hwincut_en[i],
			     osd_slice2ppc.hwincut_bgn[i],
			     osd_slice2ppc.hwincut_end[i]);
	}

	osd_log_dbg2(MODULE_2SLICE, "pad --- en%d h_bgn:%d h_end:%d v_bgn:%d v_end:%d\n",
		     osd_slice2ppc.pad_en,
		     osd_slice2ppc.pad_h_bgn, osd_slice2ppc.pad_h_end,
		     osd_slice2ppc.pad_v_bgn, osd_slice2ppc.pad_v_end);

	for (i = 0; i < count; i++) {
		if (osd_slice2ppc.slice_pos[i] == SLICE_NONE)
			continue;
		osd_log_dbg2(MODULE_2SLICE, "slice %d, osd%d ---\n",
			     osd_slice2ppc.slice_pos[i], i);

		osd_log_dbg2(MODULE_2SLICE, "scaler_in_hsize:%d scaler_in_vsize:%d\n",
			     osd_slice2ppc.scaler_in_hsize[i],
			     osd_slice2ppc.scaler_in_vsize[i]);
		osd_log_dbg2(MODULE_2SLICE, "scaler_out_hsize:%d scaler_out_vsize:%d\n",
			     osd_slice2ppc.scaler_out_hsize[i],
			     osd_slice2ppc.scaler_out_vsize[i]);
		osd_log_dbg2(MODULE_2SLICE, "slice_in_x_start:%d slice_in_x_end:%d\n",
			     osd_slice2ppc.slice_in_x_start[i],
			     osd_slice2ppc.slice_in_x_end[i]);
		osd_log_dbg2(MODULE_2SLICE, "slice_in_y_start:%d slice_in_y_end:%d\n",
			     osd_slice2ppc.slice_in_y_start[i],
			     osd_slice2ppc.slice_in_y_end[i]);
	}
}

/* every output is next path input */
static void set_blend_path_new(struct hw_osd_blending_s *blending)
{
	struct layer_blend_s *layer_blend;
	struct osd_blend_reg_s *osd_blend_reg;
	struct vpp0_blend_reg_s *vpp0_blend_reg;
	struct dispdata_s output1_data;
	u32 index = 0;
	u8 input1 = 0, input2 = 0;
	u32 output_index;
	s32 position_x, position_y;

	if (!blending)
		return;
	output_index = get_output_device_id(index);

	layer_blend = &blending->layer_blend;
	osd_blend_reg = &blending->osd_blend_reg;
	vpp0_blend_reg = &blending->vpp0_blend_reg;
	layer_blend->blend_core1_bypass = 0;
	memset(&layer_blend->input1_data, 0, sizeof(struct dispdata_s));
	memset(&layer_blend->input2_data, 0, sizeof(struct dispdata_s));

	if (osd_hw.osd_preblend_en && output_index == VIU1) {
		position_x = osd_hw.adjust_position_x;
		position_y = osd_hw.adjust_position_y - osd_hw.preblend_y_offset;
	} else {
		position_x = osd_hw.disp_info[output_index].position_x;
		position_y = osd_hw.disp_info[output_index].position_y;
	}
	switch (blending->osd_blend_mode) {
	case OSD_BLEND_NONE:
		vpp0_blend_reg->postbld_osd1_premult = 0;
		vpp0_blend_reg->postbld_src4_sel = POSTBLD_CLOSE;
		vpp0_blend_reg->postbld_src3_sel = POSTBLD_CLOSE;
		vpp0_blend_reg->postbld_osd2_premult = 0;
		break;
	case OSD_BLEND_A:
		/* sc-->blend0-->blend2-->vpp_osd1 */
		layer_blend->input1 = BLEND_DIN1;
		if (osd_hw.blend_bypass[OSD1])
			layer_blend->input1 |= BYPASS_DIN;
		layer_blend->input2 = BLEND_NO_DIN;
		index = blend_din_to_osd(BLEND_DIN1, blending);
		if (index >= OSD_MAX)
			return;
		osd_set_freescale_new(index, blending);
		osd_setting_blend0_new(blending);
		if (!osd_blend_reg->din0_byp_blend) {
			layer_blend->input1 = BLEND0_DIN;
			layer_blend->input2 = BLEND_NO_DIN;
			memcpy(&layer_blend->input1_data,
			       &layer_blend->output_data,
			       sizeof(struct dispdata_s));
			/* same with blend0's background */
			osd_setting_blend2(blending);
		}
		layer_blend->input1 = BLEND2_DIN;
		layer_blend->input2 = BLEND_NO_DIN;
		memcpy(&layer_blend->input1_data,
		       &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		layer_blend->input1_data.x +=
			position_x;
		layer_blend->input1_data.y +=
			position_y;
		vpp_setting_blend(blending);
		break;
	case OSD_BLEND_A_2SLICE:
		/* osdx --> sc-->
		 *               slice2ppc --> blend0-->blend2-->vpp_osd1
		 * osdy --> sc-->
		 */
		index = blend_din_to_osd(BLEND_DIN1, blending);
		if (index >= OSD_MAX)
			return;

		osd_2slice_param_init(index);

		layer_blend->input1 = BLEND_DIN1;
		if (osd_hw.blend_bypass[OSD1])
			layer_blend->input1 |= BYPASS_DIN;
		layer_blend->input2 = BLEND_NO_DIN;

		osd_set_freescale_new(index, blending);
		osd_setting_blend0_new(blending);
		if (!osd_blend_reg->din0_byp_blend) {
			layer_blend->input1 = BLEND0_DIN;
			layer_blend->input2 = BLEND_NO_DIN;
			memcpy(&layer_blend->input1_data,
			       &layer_blend->output_data,
			       sizeof(struct dispdata_s));
			/* same with blend0's background */
			osd_setting_blend2(blending);
		}
		layer_blend->input1 = BLEND2_DIN;
		layer_blend->input2 = BLEND_NO_DIN;
		memcpy(&layer_blend->input1_data,
		       &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		layer_blend->input1_data.x +=
			position_x;
		layer_blend->input1_data.y +=
			position_y;
		vpp_setting_blend(blending);
		break;
	case OSD_BLEND_AC:
		/* sc-->blend0 -->blend1-->blend2-->vpp_osd1 */
		/* sc-->blend0 & blend1-->blend2-->vpp_osd1 */
		if (!blending->b_exchange_din) {
			input1 = BLEND_DIN1;
			input2 = BLEND_DIN4;
		} else {
			input1 = BLEND_DIN4;
			input2 = BLEND_DIN1;
		}
		layer_blend->input1 = input1;
		layer_blend->input2 = BLEND_NO_DIN;
		index = blend_din_to_osd(input1, blending);
		if (index >= OSD_MAX)
			return;
		osd_set_freescale_new(index, blending);
		osd_setting_blend0_new(blending);
		/* save blend0 output */
		memcpy(&output1_data, &layer_blend->output_data,
		       sizeof(struct dispdata_s));

		index = blend_din_to_osd(input2, blending);
		if (index >= OSD_MAX)
			return;
		osd_set_freescale_new(index, blending);
		layer_blend->input1 = BLEND_NO_DIN;
		layer_blend->input2 = input2;
		osd_setting_blend1_new(blending);

		layer_blend->input1 = BLEND0_DIN;
		layer_blend->input2 = BLEND1_DIN;

		/* blend0 output-> blend2  input1 */
		memcpy(&layer_blend->input1_data, &output1_data,
		       sizeof(struct dispdata_s));
		/* blend1 output-> blend2  input2 */
		memcpy(&layer_blend->input2_data, &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		osd_setting_blend2(blending);

		layer_blend->input1 = BLEND2_DIN;
		layer_blend->input2 = BLEND_NO_DIN;
		memcpy(&layer_blend->input1_data,
		       &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		layer_blend->input1_data.x +=
			position_x;
		layer_blend->input1_data.y +=
			position_y;
		vpp_setting_blend(blending);
		break;
	case OSD_BLEND_A_C:
		/* sc-->blend0 -->blend2->vpp_osd1 */
		/* sc-->blend1 -->vpp_osd2 */
		layer_blend->input1 = BLEND_DIN1;
		if (osd_hw.blend_bypass[OSD1])
			layer_blend->input1 |= BYPASS_DIN;
		layer_blend->input2 = BLEND_NO_DIN;
		index = blend_din_to_osd(BLEND_DIN1, blending);
		if (index >= OSD_MAX)
			return;
		osd_set_freescale_new(index, blending);
		osd_setting_blend0_new(blending);
		if (!osd_blend_reg->din0_byp_blend) {
			layer_blend->input1 = BLEND0_DIN;
			layer_blend->input2 = BLEND_NO_DIN;
			memcpy(&layer_blend->input1_data,
			       &layer_blend->output_data,
			       sizeof(struct dispdata_s));
			/* background is same with blend0's background */
			osd_setting_blend2(blending);
		}
		/* save blend0/blend2 output */
		memcpy(&output1_data, &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		/* adjust input 1 offset*/
		output1_data.x +=
			position_x;
		output1_data.y +=
			position_y;

		index = blend_din_to_osd(BLEND_DIN4, blending);
		if (index >= OSD_MAX)
			return;
		osd_set_freescale_new(index, blending);
		layer_blend->input1 = BLEND_NO_DIN;
		layer_blend->input2 = BLEND_DIN4 | BYPASS_DIN;
		layer_blend->blend_core1_bypass = 1;
		osd_setting_blend1_new(blending);
		/* adjust input 2 offset*/
		layer_blend->output_data.x +=
			position_x;
		layer_blend->output_data.y +=
			position_y;

		if (!blending->b_exchange_blend_in) {
			layer_blend->input1 = BLEND2_DIN;
			layer_blend->input2 = BLEND1_DIN;
			memcpy(&layer_blend->input1_data, &output1_data,
			       sizeof(struct dispdata_s));
			memcpy(&layer_blend->input2_data,
			       &layer_blend->output_data,
				sizeof(struct dispdata_s));
		} else {
			layer_blend->input1 = BLEND1_DIN;
			layer_blend->input2 = BLEND2_DIN;
			memcpy(&layer_blend->input1_data,
			       &layer_blend->output_data,
			       sizeof(struct dispdata_s));
			memcpy(&layer_blend->input2_data, &output1_data,
			       sizeof(struct dispdata_s));
		}
		vpp_setting_blend(blending);
		break;
	case OSD_BLEND_ABC:
		/* sc->blend0 -->blend2-->vpp_osd1 */
		/* sc-->blend1 -->blend2 */
		input1 = BLEND_DIN1;
		input2 = BLEND_DIN4;
		layer_blend->input1 = input1;
		layer_blend->input2 = BLEND_NO_DIN;
		index = blend_din_to_osd(input1, blending);
		if (index >= OSD_MAX)
			return;
		osd_set_freescale_new(index, blending);
		osd_setting_blend0_new(blending);
		/* save blend0 output */
		memcpy(&output1_data, &layer_blend->output_data,
		       sizeof(struct dispdata_s));

		layer_blend->input1 = BLEND_DIN3;
		layer_blend->input2 = input2;
		index = blend_din_to_osd(layer_blend->input1, blending);
		osd_set_freescale_new(index, blending);
		index = blend_din_to_osd(layer_blend->input2, blending);
		osd_set_freescale_new(index, blending);
		osd_setting_blend1_new(blending);

		layer_blend->input1 = BLEND0_DIN;
		layer_blend->input2 = BLEND1_DIN;
		memcpy(&layer_blend->input1_data, &output1_data,
		       sizeof(struct dispdata_s));
		memcpy(&layer_blend->input2_data, &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		osd_setting_blend2(blending);

		layer_blend->input1 = BLEND2_DIN;
		layer_blend->input2 = BLEND_NO_DIN;
		memcpy(&layer_blend->input1_data,
		       &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		layer_blend->input1_data.x +=
			position_x;
		layer_blend->input1_data.y +=
			position_y;
		vpp_setting_blend(blending);
		break;
	case OSD_BLEND_AB_C:
		/* sc-->blend0 -->blend2->vpp_osd1 */
		/* sc-->blend1-->blend2-->vpp_osd1 */
		/* sc -->vpp_osd2 */
		layer_blend->input1 = BLEND_DIN1;
		layer_blend->input2 = BLEND_NO_DIN;
		blending->blend_din = BLEND_DIN1;
		index = blend_din_to_osd(BLEND_DIN1, blending);
		if (index >= OSD_MAX)
			return;
		osd_set_freescale_new(index, blending);
		osd_setting_blend0_new(blending);
		/* save blend0 output */
		memcpy(&output1_data, &layer_blend->output_data,
		       sizeof(struct dispdata_s));

		/* din3 input to blend1 */
		layer_blend->input1 = BLEND_DIN3;
		layer_blend->input2 = BLEND_NO_DIN | BYPASS_DIN;
		layer_blend->blend_core1_bypass = 1;
		blending->blend_din = BLEND_DIN3;
		index = blend_din_to_osd(BLEND_DIN3, blending);
		osd_set_freescale_new(index, blending);
		osd_setting_blend1_new(blending);

		/* din1=>blend0 & din3-> blend1 ==> blend2 */
		layer_blend->input1 = BLEND0_DIN;
		layer_blend->input2 = BLEND1_DIN;
		memcpy(&layer_blend->input1_data, &output1_data,
		       sizeof(struct dispdata_s));
		memcpy(&layer_blend->input2_data, &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		osd_setting_blend2(blending);
		memcpy(&output1_data, &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		output1_data.x +=
			position_x;
		output1_data.y +=
			position_y;
		osd_log_dbg2(MODULE_BLEND, "output1_data:%d,%d,%d,%d\n",
			     output1_data.x,
			output1_data.w,
			output1_data.y,
			output1_data.h);

		/* din4 ==> vpp */
		index = blend_din_to_osd(BLEND_DIN4, blending);
		blending->blend_din = BLEND_DIN4;
		osd_set_freescale_new(index, blending);
		layer_blend->input2_data.x =
			osd_hw.free_dst_data[index].x_start +
			position_x;
		layer_blend->input2_data.w =
			osd_hw.free_dst_data[index].x_end -
			osd_hw.free_dst_data[index].x_start + 1;
		layer_blend->input2_data.y =
			osd_hw.free_dst_data[index].y_start +
			position_y;
		layer_blend->input2_data.h =
			osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;

		/* 2vpp input */
		if (!blending->b_exchange_blend_in) {
			layer_blend->input1 = BLEND2_DIN;
			layer_blend->input2 = BLEND1_DIN;
			memcpy(&layer_blend->input1_data, &output1_data,
			       sizeof(struct dispdata_s));
		} else {
			layer_blend->input1 = BLEND1_DIN;
			layer_blend->input2 = BLEND2_DIN;
			memcpy(&layer_blend->input1_data,
			       &layer_blend->input2_data,
				sizeof(struct dispdata_s));
			memcpy(&layer_blend->input2_data,
			       &output1_data,
				sizeof(struct dispdata_s));
		}
		vpp_setting_blend(blending);
		break;
	case OSD_BLEND_ABCD:
		/* sc->blend0 -->blend2-->vpp_osd1 */
		/* sc-->blend1 -->blend2 */
		layer_blend->input1 = BLEND_DIN1;
		layer_blend->input2 = BLEND_DIN2;
		index = blend_din_to_osd(layer_blend->input1, blending);
		if (index >= OSD_MAX)
			return;
		osd_set_freescale_new(index, blending);
		index = blend_din_to_osd(layer_blend->input2, blending);
		if (index >= OSD_MAX)
			return;
		osd_set_freescale_new(index, blending);
		osd_setting_blend0_new(blending);
		/* save blend0 output */
		memcpy(&output1_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));

		layer_blend->input1 = BLEND_DIN3;
		layer_blend->input2 = BLEND_DIN4;
		index = blend_din_to_osd(layer_blend->input1, blending);
		osd_set_freescale_new(index, blending);
		index = blend_din_to_osd(layer_blend->input2, blending);
		osd_set_freescale_new(index, blending);
		osd_setting_blend1_new(blending);
		/* save blend1 output */
		memcpy(&layer_blend->input1_data,
			&output1_data,
			sizeof(struct dispdata_s));
		memcpy(&layer_blend->input2_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));

		layer_blend->input1 = BLEND0_DIN;
		layer_blend->input2 = BLEND1_DIN;
		osd_setting_blend2(blending);

		layer_blend->input1 = BLEND2_DIN;
		layer_blend->input2 = BLEND_NO_DIN;
		memcpy(&layer_blend->input1_data,
		       &layer_blend->output_data,
		       sizeof(struct dispdata_s));
		layer_blend->input1_data.x +=
			position_x;
		layer_blend->input1_data.y +=
			position_y;
		vpp_setting_blend(blending);
		break;
	case OSD_BLEND_AB_CD:
		/* sc->blend0 -->blend2-->vpp_osd1 */
		/* sc-->blend1 -->blend2 */
		layer_blend->input1 = BLEND_DIN1;
		layer_blend->input2 = BLEND_DIN2;
		index = blend_din_to_osd(layer_blend->input1, blending);
		if (index >= OSD_MAX)
			return;
		osd_set_freescale_new(index, blending);
		index = blend_din_to_osd(layer_blend->input2, blending);
		if (index >= OSD_MAX)
			return;
		osd_set_freescale_new(index, blending);
		osd_setting_blend0_new(blending);
		/* save blend0 output */
		memcpy(&layer_blend->input1_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));
		layer_blend->input1 = BLEND0_DIN;
		layer_blend->input2 = BLEND_NO_DIN;
		osd_setting_blend2(blending);
		/* save blend2 output */
		memcpy(&output1_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));

		/* always route(bypass) to dout1 */
		layer_blend->input1 = BLEND_DIN3;
		layer_blend->input2 = BLEND_DIN4;

		index = blend_din_to_osd(layer_blend->input1, blending);
		osd_set_freescale_new(index, blending);
		index = blend_din_to_osd(layer_blend->input2, blending);
		osd_set_freescale_new(index, blending);

		layer_blend->input1 = BLEND_DIN3 | BYPASS_DIN;
		osd_setting_blend1_new(blending);
		/* save blend1 output */
		memcpy(&layer_blend->input1_data,
			&output1_data,
			sizeof(struct dispdata_s));

		memcpy(&layer_blend->input2_data,
			&layer_blend->output_data,
			sizeof(struct dispdata_s));

		if (!blending->b_exchange_blend_in) {
			layer_blend->input1 = BLEND2_DIN;
			layer_blend->input2 = BLEND1_DIN;
			memcpy(&layer_blend->input1_data, &output1_data,
				sizeof(struct dispdata_s));
			layer_blend->input1_data.x +=
				position_x;
			layer_blend->input1_data.y +=
				position_y;
			memcpy(&layer_blend->input2_data,
				&layer_blend->output_data,
				sizeof(struct dispdata_s));
			layer_blend->input2_data.x +=
				position_x;
			layer_blend->input2_data.y +=
				position_y;
		} else {
			layer_blend->input1 = BLEND1_DIN;
			layer_blend->input2 = BLEND2_DIN;
			memcpy(&layer_blend->input1_data,
				&layer_blend->output_data,
				sizeof(struct dispdata_s));
			layer_blend->input1_data.x +=
				position_x;
			layer_blend->input1_data.y +=
				position_y;
			memcpy(&layer_blend->input2_data,
				&output1_data,
				sizeof(struct dispdata_s));
			layer_blend->input2_data.x +=
				position_x;
			layer_blend->input2_data.y +=
				position_y;
		}
		vpp_setting_blend(blending);
		break;
	}
}

static void osd_set_vpp_path(u32 vpp_osd_index, u32 vpp_index)
{
	struct osd_rdma_fun_s *rdma_func = &osd_hw.osd_rdma_func[vpp_index];
	osd_rdma_wr_bits_op rdma_wr_bits = rdma_func->osd_rdma_wr_bits;

	if (osd_dev_hw.has_multi_vpp) {
		/* osd_index is vpp mux input */
		/* default setting osd2 route to vpp0 vsync */
		if (vpp_osd_index == VPP_OSD3)
			rdma_wr_bits(PATH_START_SEL, vpp_index, 24, 2);
		/* default setting osd3 route to vpp0 vsync */
		if (vpp_osd_index == VPP_OSD4)
			rdma_wr_bits(PATH_START_SEL, vpp_index, 28, 2);
	}
}

static void set_osd_hdr_size_in(u32 osd_index, u32 osd_hsize, u32 osd_vsize)
{
	u32 output_index = get_output_device_id(osd_index);

	switch (osd_index) {
	case VPP_OSD1:
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(OSD1_HDR_IN_SIZE,
			osd_vsize << 16 | osd_hsize);
		break;
	case VPP_OSD2:
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(OSD2_HDR_IN_SIZE,
			osd_vsize << 16 | osd_hsize);
		break;
	case VPP_OSD3:
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(OSD3_HDR_IN_SIZE,
			osd_vsize << 16 | osd_hsize);
		break;
	case VPP_OSD4:
		osd_hw.osd_rdma_func[output_index].osd_rdma_wr
			(OSD4_HDR_IN_SIZE,
			osd_vsize << 16 | osd_hsize);
		break;
	default:
		break;
	}
}

static void set_vpp0_blend_reg(struct vpp0_blend_reg_s *vpp0_blend_reg)
{
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.vpp_osd1_bld_h_scope,
			     vpp0_blend_reg->osd1_h_start << 16 |
			     vpp0_blend_reg->osd1_h_end);
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.vpp_osd1_bld_v_scope,
			     vpp0_blend_reg->osd1_v_start << 16 |
			     vpp0_blend_reg->osd1_v_end);
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.vpp_osd2_bld_h_scope,
			     vpp0_blend_reg->osd2_h_start << 16 |
			     vpp0_blend_reg->osd2_h_end);
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.vpp_osd2_bld_v_scope,
			     vpp0_blend_reg->osd2_v_start << 16 |
			     vpp0_blend_reg->osd2_v_end);

	/* vpp osd1 blend ctrl */
	if (osd_dev_hw.s5_display)
		VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd1_blend_src_ctrl,
				     (vpp0_blend_reg->postbld_src3_sel & 0xf) << 0 |
				     (0 << 4));
	else
		VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd1_blend_src_ctrl,
				     (vpp0_blend_reg->prebld_src3_sel & 0xf) << 0 |
				     (0 & 0x1) << 4 |
				     (vpp0_blend_reg->postbld_src3_sel & 0xf) << 8 |
				     (0 << 16) |
				     ((!osd_hw.osd_preblend_en) & 0x1) << 20);
	/* vpp osd2 blend ctrl */
	if (!enable_vd_zorder) {
		if (osd_dev_hw.s5_display) {
			VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd2_blend_src_ctrl,
					     (vpp0_blend_reg->postbld_src4_sel & 0xf) << 0 |
					     (0 << 4));
		} else {
			if (is_keystone_enable_for_txhd2()) {
				vpp0_blend_reg->postbld_src4_sel = 0;
				set_vpp_osd2_rgb2yuv(0);
			} else {
				set_vpp_osd2_rgb2yuv(1);
			}
			VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd2_blend_src_ctrl,
					     (vpp0_blend_reg->prebld_src4_sel & 0xf) << 0 |
					     (0 & 0x1) << 4 |
					     (vpp0_blend_reg->postbld_src4_sel & 0xf) << 8 |
					     (0 << 16) |
					     ((!osd_hw.osd_preblend_en) & 0x1) << 20);
		}
	}
	if (osd_dev_hw.has_multi_vpp) {
		u32 osd_hsize, osd_vsize;

		/* vsync select */
		osd_set_vpp_path(vpp0_blend_reg->osd1_index, VPU_VPP0);
		osd_set_vpp_path(vpp0_blend_reg->osd2_index, VPU_VPP0);
		/* hdr size input */
		osd_hsize = vpp0_blend_reg->osd1_h_end -
			vpp0_blend_reg->osd1_h_start + 1;
		osd_vsize = vpp0_blend_reg->osd1_v_end -
			vpp0_blend_reg->osd1_v_start + 1;
		set_osd_hdr_size_in(vpp0_blend_reg->osd1_index,
				    osd_hsize,
				    osd_vsize);
		osd_hsize = vpp0_blend_reg->osd2_h_end -
			vpp0_blend_reg->osd2_h_start + 1;
		osd_vsize = vpp0_blend_reg->osd2_v_end -
			vpp0_blend_reg->osd2_v_start + 1;
		set_osd_hdr_size_in(vpp0_blend_reg->osd2_index,
				    osd_hsize,
				    osd_vsize);
		/* vpp input mux */
		VSYNCOSD_WR_MPEG_REG_BITS(OSD_PATH_MISC_CTRL,
				     vpp0_blend_reg->osd1_index |
				     vpp0_blend_reg->osd2_index << 4,
				     16, 8);
	}
}

static void set_osd0_scaler_before_blend(void)
{
	if (osd_hw.osd_meson_dev.cpu_id == __MESON_CPU_MAJOR_ID_T3 ||
		osd_hw.osd_meson_dev.cpu_id == __MESON_CPU_MAJOR_ID_T5W ||
		osd_hw.osd_meson_dev.cpu_id == __MESON_CPU_MAJOR_ID_T5M)
		VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD1_PATH_CTRL, 1, 0, 1);
}

static void set_osd_blend_reg(struct osd_blend_reg_s *osd_blend_reg)
{
	int i;
	u32 reg_offset = 2;
	u32 din_count = OSD_BLEND_LAYERS;
	u32 dv_core2_hsize;
	u32 dv_core2_vsize;
	u32 osd1_alpha_div = 0, osd2_alpha_div = 0;
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
	u32 tmp_h;
	u32 tmp_v;
#endif

	if (!osd_blend_reg)
		return;

	osd1_alpha_div = osd_blend_reg->osd_bld_out0_premult;
	osd2_alpha_div = osd_blend_reg->osd_bld_out1_premult;
	/* osd0 scale position before osd blend */
	if (osd_hw.osd_meson_dev.osd0_sc_independ) {
		VSYNCOSD_WR_MPEG_REG(VPP_OSD_SCALE_CTRL, 0x01);
		set_osd0_scaler_before_blend();
		osd_blend_reg->din_premult_en = 1;
	}
	if (osd_hw.blend_bypass[OSD1])
		osd_blend_reg->din0_byp_blend = 1;
	/* osd blend ctrl */
	VSYNCOSD_WR_MPEG_REG
		(hw_osd_reg_blend.osd_blend_ctrl,
		4                            << 29 |
		osd_blend_reg->blend2_premult_en << 27 |
		osd_blend_reg->din0_byp_blend    << 26 |
		osd_blend_reg->din2_osd_sel      << 25 |
		osd_blend_reg->din3_osd_sel	     << 24 |
		osd_blend_reg->blend_din_en      << 20 |
		osd_blend_reg->din_premult_en    << 16 |
		osd_blend_reg->din_reoder_sel);

	/* VIU_OSD_BLEND_CTRL1 */
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd_blend_ctrl1,
			     (osd1_alpha_div & 0x1) |
			     (3 << 4) |
			     ((osd2_alpha_div & 0x1) << 12) |
			     (3 << 16));
	if (osd_hw.osd_meson_dev.cpu_id == __MESON_CPU_MAJOR_ID_TXHD2) {
		VSYNCOSD_WR_MPEG_REG_BITS(hw_osd_reg_blend.osd_blend_ctrl, 0, 0, 1);
		VSYNCOSD_WR_MPEG_REG_BITS(hw_osd_reg_blend.osd_blend_ctrl1, 0, 0, 1);
	}

	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd_blend_blend0_size,
			     osd_blend_reg->osd_blend_blend0_size);

	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd_blend_blend1_size,
			     osd_blend_reg->osd_blend_blend1_size);

	/* hdr input size should set to osd blend0 output size */
	if (!osd_dev_hw.s5_display) {
		VSYNCOSD_WR_MPEG_REG(VPP_OSD1_IN_SIZE,
				     osd_blend_reg->osd_blend_blend0_size);
		VSYNCOSD_WR_MPEG_REG(OSD1_HDR_IN_SIZE,
				     osd_blend_reg->osd_blend_blend0_size);
	}

	if (osd_dev_hw.s5_display) {
		VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd_blend_dout0_size,
				     osd_blend_reg->osd_blend_blend0_size);
		VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd_blend_dout1_size,
				     osd_blend_reg->osd_blend_blend1_size);
	}

	for (i = 0; i < din_count; i++) {
		u32 osd_index = to_din_scope_osd_index(i);

		if (osd_index == OSD_ERR || osd_index >= OSD_MAX) {
			VSYNCOSD_WR_MPEG_REG
				(hw_osd_reg_blend.osd_blend_din0_scope_v +
				 reg_offset * i,
				     0xffffffff);
			continue;
		}

		if (osd_hw.enable[osd_index]) {
			VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_blend.osd_blend_din0_scope_h +
			reg_offset * i,
			osd_blend_reg->osd_blend_din_scope_h[osd_index]);
		}
		if ((osd_blend_reg->osd_blend_din_scope_v[osd_index] & 0xffff0000) == 0)
			osd_blend_reg->osd_blend_din_scope_v[osd_index] =
				0xffffffff;
		VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd_blend_din0_scope_v +
				     reg_offset * i,
				     osd_blend_reg->osd_blend_din_scope_v[osd_index]);
	}

	if (osd_dev_hw.s5_display) {
		u32 data32 = 0;

		if (osd_hw.slice2ppc_enable) {
			/* 1mux3, OSD1 & OSD3 -> slice2ppc */
			data32 = 1 << 0 | 1 << 4;

			/* 3mux2, OSD1 -> left slice, OSD3 -> right slice */
			data32 |= 1 << 6 | 3 << 10;
		} else {
			/* 1mux3, OSD1 & OSD3 -> blend */
			data32 = 2 << 0 | 2 << 2 | 2 << 4;
		}
		VSYNCOSD_WR_MPEG_REG(OSD_PROC_1MUX3_SEL, data32);

		if (osd_hw.pi_enable)
			VSYNCOSD_WR_MPEG_REG_BITS(OSD_PI_BYPASS_EN, 0, 0, 1);
		else
			VSYNCOSD_WR_MPEG_REG_BITS(OSD_PI_BYPASS_EN, 1, 0, 1);
	}

	dv_core2_vsize = (osd_blend_reg->osd_blend_blend0_size >> 16) & 0xfff;
	dv_core2_hsize = osd_blend_reg->osd_blend_blend0_size & 0xfff;

	if (osd_hw.osd_meson_dev.has_dolby_vision) {
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
		if (osd_dev_hw.s5_display) {
			for (i = 0; i < osd_hw.osd_meson_dev.osd_count; i++) {
				if (osd_hw.enable[i]) {/*s5 osd1+osd3 two core2*/
					/*s5: core2 is before pps and blend, use OSD1_PROC_IN_SIZE*/
					dv_core2_hsize = osd_hw.free_src_data[i].x_end -
						osd_hw.free_src_data[i].x_start + 1;
					dv_core2_vsize = osd_hw.free_src_data[i].y_end -
						osd_hw.free_src_data[i].y_start + 1;
					tmp_h = dv_core2_hsize;
					tmp_v = dv_core2_vsize;
					update_dvcore2_timing(&tmp_h, &tmp_v);
					VSYNCOSD_WR_MPEG_REG(S5_AMDV_CORE2A_SWAP_CTRL1,
							 ((tmp_h + 0x40) << 16)
							 | (tmp_v + 0x80 + 0));
					VSYNCOSD_WR_MPEG_REG(S5_AMDV_CORE2A_SWAP_CTRL2,
							 (tmp_h << 16) |
							 (tmp_v + 0));
					update_graphic_width_height
						(dv_core2_hsize, dv_core2_vsize,
						 to_osd_hw_index(i));
				}
			}
		} else {
			tmp_h = dv_core2_hsize;
			tmp_v = dv_core2_vsize;

			update_dvcore2_timing(&tmp_h, &tmp_v);
			VSYNCOSD_WR_MPEG_REG(AMDV_CORE2A_SWAP_CTRL1,
					     ((tmp_h + 0x40) << 16)
					     | (tmp_v + 0x80 + 0));
			VSYNCOSD_WR_MPEG_REG(AMDV_CORE2A_SWAP_CTRL2,
					     (tmp_h << 16) |
					     (tmp_v + 0));
			update_graphic_width_height(dv_core2_hsize, dv_core2_vsize, OSD1_INDEX);
		}
		if (!update_to_dv) {
			update_graphic_status();
			update_to_dv = true;
		}
#endif
	}
}

static  void set_blend_reg(struct hw_osd_blending_s *blending)
{
	set_osd_blend_reg(&blending->osd_blend_reg);
	set_vpp0_blend_reg(&blending->vpp0_blend_reg);
}

static void uniformization_fb(u32 index,
			      struct hw_osd_blending_s *blending)
{
	if (index == OSD1 && osd_hw.src_crop[index] &&
	   !osd_hw.osd_preblend_en) {
		blending->screen_ratio_w_den =
			osd_hw.src_data[index].w;
		blending->screen_ratio_h_den =
			osd_hw.src_data[index].h;
	}
	osd_log_dbg2(MODULE_BLEND,
		     "uniformization:osd%d:blending screen_ratio:%d,%d,%d,%d\n",
		     index,
		     blending->screen_ratio_w_den,
		     blending->screen_ratio_h_den,
		     blending->screen_ratio_w_num,
		     blending->screen_ratio_h_num);

	blending->dst_data.x = osd_hw.dst_data[index].x *
		blending->screen_ratio_w_den /
		blending->screen_ratio_w_num;
	blending->dst_data.y = osd_hw.dst_data[index].y *
		blending->screen_ratio_h_den /
		blending->screen_ratio_h_num;
	blending->dst_data.w = osd_hw.dst_data[index].w *
		blending->screen_ratio_w_den /
		blending->screen_ratio_w_num;
	blending->dst_data.h = osd_hw.dst_data[index].h *
		blending->screen_ratio_h_den /
		blending->screen_ratio_h_num;

	osd_log_dbg2(MODULE_BLEND,
		     "uniformization:osd%d:dst_data:%d,%d,%d,%d\n",
		     index,
		     blending->dst_data.x,
		     blending->dst_data.y,
		     blending->dst_data.w,
		     blending->dst_data.h);
}

static void adjust_dst_position(u32 output_index)
{
	int i = 0;
	int osd_count = 0;
	int start_index = 0;
	u32 position_x, position_y;

	if (output_index == VIU1) {
		osd_count = osd_hw.osd_meson_dev.viu1_osd_count;
		start_index = 0;
	} else if (output_index == VIU2) {
		start_index = osd_hw.osd_meson_dev.viu2_index;
		osd_count = start_index + 1;
	} else {
		osd_log_err("invalid output_index=%d\n", output_index);
		return;
	}

	if (osd_hw.osd_preblend_en && output_index == VIU1) {
		position_x = osd_hw.adjust_position_x;
		position_y = osd_hw.adjust_position_y;
	} else {
		position_x = osd_hw.disp_info[output_index].position_x;
		position_y = osd_hw.disp_info[output_index].position_y;
	}
	osd_log_dbg2(MODULE_BLEND,
		     "adjust dst_data:osd%d, position x=%d,y=%d\n",
		     i,
		     position_x,
		     position_y);
	for (i = 0; i < osd_count; i++) {
		if (osd_hw.enable[i] && validate_osd(i, output_index)) {
			osd_hw.dst_data[i].x -=
				position_x;
			osd_hw.dst_data[i].y -=
				position_y;
			if (osd_hw.dst_data[i].x < 0)
				osd_hw.dst_data[i].x = 0;
			if (osd_hw.dst_data[i].y < 0)
				osd_hw.dst_data[i].y = 0;
			osd_log_dbg2(MODULE_BLEND,
				     "adjust dst_data:osd%d:%d,%d,%d,%d\n",
				     i,
				     osd_hw.dst_data[i].x,
				     osd_hw.dst_data[i].y,
				     osd_hw.dst_data[i].w,
				     osd_hw.dst_data[i].h);
		}
	}
	if (osd_hw.field_out_en[output_index])
		osd_hw.disp_info[output_index].position_y /= 2;
}

#ifdef CONFIG_AMLOGIC_MEDIA_SECURITY
void osd_secure_cb(u32 arg)
{
	osd_log_dbg(MODULE_SECURE, "%s: arg=%x, secure_src=%x\n",
		    __func__,
		    arg, osd_hw.secure_src);
}
#endif

u32 get_cur_begin_line(u32 output_index)
{
	return cur_begin_line[output_index];
}

static void adjust_pi_axis(void)
{
	unsigned int x = osd_hw.disp_info[VIU1].position_x;
	unsigned int y = osd_hw.disp_info[VIU1].position_y;
	unsigned int w = osd_hw.disp_info[VIU1].position_w;
	unsigned int h = osd_hw.disp_info[VIU1].position_h;
	unsigned int i, osd_count = osd_hw.osd_meson_dev.osd_count;

	if (!osd_pi_debug) {
		if ((w > 3840 && h > 2160) || (w > 4096 && h > 2160))
			osd_hw.pi_enable = 1;
		else
			osd_hw.pi_enable = 0;
	} else {
		osd_hw.pi_enable = osd_pi_enable;
	}

	if (osd_hw.pi_enable) {
		if (osd_hw.field_out_en[VIU1]) {
			y = y >> 1;
			h = h >> 1;
		}
		osd_hw.pi_out.x_start = x;
		osd_hw.pi_out.x_end = x + w - 1;
		osd_hw.pi_out.y_start = y;
		osd_hw.pi_out.y_end = y + h - 1;

		for (i = 0; i < osd_count; i++) {
			if (!validate_osd(i, VIU1))
				continue;
			osd_hw.dst_data[i].x /= 2;
			osd_hw.dst_data[i].y /= 2;
			osd_hw.dst_data[i].w /= 2;
			osd_hw.dst_data[i].h /= 2;
		}
		osd_hw.disp_info[VIU1].position_x /= 2;
		osd_hw.disp_info[VIU1].position_y /= 2;
		osd_hw.disp_info[VIU1].position_w /= 2;
		osd_hw.disp_info[VIU1].position_h /= 2;
	}
}

static void set_slice2ppc_status(void)
{
	unsigned int w = osd_hw.disp_info[VIU1].position_w;
	unsigned int h = osd_hw.disp_info[VIU1].position_h;
	struct vinfo_s *vinfo = NULL;

#ifdef CONFIG_AMLOGIC_VOUT_SERVE
	vinfo = get_current_vinfo();
#endif
	if (!vinfo) {
		osd_log_err("%s current vinfo NULL\n", __func__);
		return;
	}

	if (!osd_slice2ppc_debug) {
		/* 4K120Hz */
		if (((w >= 3840 && h >= 2160) || (w >= 4096 && h >= 2160)) &&
		    vinfo->sync_duration_num / vinfo->sync_duration_den > 60)
			osd_hw.slice2ppc_enable = 1;
		else
			osd_hw.slice2ppc_enable = 0;
	} else {
		osd_hw.slice2ppc_enable = osd_slice2ppc_enable;
	}

	if (osd_hw.osd_meson_dev.has_slice2ppc)
		osd_log_dbg(MODULE_2SLICE, "slice2ppc enable:%d\n",
			    osd_hw.slice2ppc_enable);
}

static void set_slice2ppc_reg(void)
{
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_slice2ppc.osd_2slice2ppc_in_size,
			     osd_slice2ppc.slice2ppc_vsize << 16 |
			     osd_slice2ppc.slice2ppc_hsize);
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_slice2ppc.osd_2slice2ppc_mode,
			     osd_slice2ppc.slice2ppc_mode);
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_slice2ppc.osd_sys_hwin0_cut,
			     osd_slice2ppc.hwincut_en[HWIN_IN_0] << 29 |
			     osd_slice2ppc.hwincut_bgn[HWIN_IN_0] << 16 |
			     osd_slice2ppc.hwincut_end[HWIN_IN_0]);
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_slice2ppc.osd_sys_hwin1_cut,
			     osd_slice2ppc.hwincut_en[HWIN_IN_1] << 29 |
			     osd_slice2ppc.hwincut_bgn[HWIN_IN_1] << 16 |
			     osd_slice2ppc.hwincut_end[HWIN_IN_1]);
	VSYNCOSD_WR_MPEG_REG_BITS(hw_osd_reg_slice2ppc.osd_sys_pad_ctrl,
				  osd_slice2ppc.pad_en, 0, 1);
	/* hw_osd_reg_slice2ppc.osd_sys_pad_dummy_data0
	 * hw_osd_reg_slice2ppc.osd_sys_pad_dummy_data1
	 */
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_slice2ppc.osd_sys_pad_h_size,
			     osd_slice2ppc.pad_h_bgn << 16 |
			     osd_slice2ppc.pad_h_end);
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_slice2ppc.osd_sys_pad_v_size,
			     osd_slice2ppc.pad_v_bgn << 16 |
			     osd_slice2ppc.pad_v_end);
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_slice2ppc.osd_sys_2slice_hwin_cut,
			     osd_slice2ppc.hwincut_en[HWIN_OUT] << 29 |
			     osd_slice2ppc.hwincut_bgn[HWIN_OUT] << 16 |
			     osd_slice2ppc.hwincut_end[HWIN_OUT]);
}

static int osd_setting_order(u32 output_index)
{
	int i;
	struct hw_osd_blending_s *blending;
	u32 osd_count = osd_hw.osd_meson_dev.osd_count;
	int line1;
	int line2;
	int active_begin_line;
	u32 val, wait_cnt = 0;
#ifdef CONFIG_AMLOGIC_MEDIA_SECURITY
	u32 secure_src = 0;
#endif
	u32 total_line;

	if (osd_hw.osd_meson_dev.has_pi)
		adjust_pi_axis();

	if (osd_hw.osd_meson_dev.has_slice2ppc)
		set_slice2ppc_status();

	blending = &osd_blending;

	blending->vinfo_width = osd_hw.vinfo_width[output_index];
	blending->vinfo_height = osd_hw.vinfo_height[output_index];
	blending->screen_ratio_w_num =
		osd_hw.disp_info[output_index].position_w;
	blending->screen_ratio_w_den =
		osd_hw.disp_info[output_index].background_w;
	blending->screen_ratio_h_num =
		osd_hw.disp_info[output_index].position_h;
	blending->screen_ratio_h_den =
		osd_hw.disp_info[output_index].background_h;

	if (osd_hw.osd_preblend_en) {
		blending->screen_ratio_w_num =
			blending->screen_ratio_w_num *
			osd_hw.preblend_pps_w_den /
			osd_hw.preblend_pps_w_num;

		blending->screen_ratio_h_num =
			blending->screen_ratio_h_num *
			osd_hw.preblend_pps_h_den /
			osd_hw.preblend_pps_h_num;
		osd_log_dbg2(MODULE_BLEND,
			    "blending screen_ratio:%d,%d,%d,%d\n",
			    blending->screen_ratio_w_den,
			    blending->screen_ratio_h_den,
			    blending->screen_ratio_w_num,
			    blending->screen_ratio_h_num);
	}

	blending->layer_cnt = get_available_layers(output_index);
	set_blend_order(blending, output_index);

	osd_log_dbg(MODULE_BLEND, "layer_cnt:%d\n",
		    blending->layer_cnt);

	blending->b_exchange_din = 0;
	blending->b_exchange_blend_in = 0;
	blending->osd1_freescale_disable = 0;
	adjust_dst_position(output_index);
	if (!osd_hw.osd_meson_dev.osd0_sc_independ)
		uniformization_fb(OSD1, blending);

	/* set blend mode */
	set_blend_mode(blending);
	generate_blend_din_table(blending);

	set_blend_din(blending);

	/* set blend path */
	if (osd_hw.osd_meson_dev.osd0_sc_independ)
		set_blend_path_new(blending);
	else
		set_blend_path(blending);
	active_begin_line = get_active_begin_line(VIU1);
	line1 = get_enter_encp_line(VIU1);
	/* if nearly vsync signal, wait vsync here */
	if (osd_hw.field_out_en[VIU1] && is_encp(VIU1)) {
		total_line = osd_hw.vinfo_height[VIU1] + active_begin_line;
		if (line1 >= total_line)
			/* bottom*/
			line1 -= total_line;
	} else {
		total_line = osd_hw.vinfo_height[VIU1] + active_begin_line;
	}

	while (line1 >= total_line *
	      (100 - line_threshold) / 100 ||
	      line1 <= active_begin_line * line_threshold_2 / 100) {
		/* 0.5ms */
		usleep_range(500, 600);
		wait_cnt++;
		if (wait_cnt >= WAIT_CNT_MAX)
			break;
		line1 = get_enter_encp_line(VIU1);
	}
	cur_begin_line[VIU1] = line1;
	if (wait_cnt > 0)
		osd_hw.rdma_delayed_cnt1++;
	spin_lock_irqsave(&osd_lock, lock_flags);
	if (blending->osd1_freescale_disable)
		osd_hw.reg[DISP_FREESCALE_ENABLE].update_func(OSD1);
	for (i = 0; i < osd_count; i++) {
		if (!validate_osd(i, output_index))
			continue;

		if (osd_hw.enable[i]) {
			struct hw_osd_reg_s *osd_reg = &hw_osd_reg_array[i];
			enum color_index_e idx = COLOR_INDEX_32_BGRX;
			bool rgbx = false;

			if (osd_hw.color_info[i])
				idx = osd_hw.color_info[i]->color_index;
			else
				osd_log_err("osd%d color_info is NULL\n", i);
			/* update = is_freescale_para_changed(i); */
			if (!osd_hw.osd_afbcd[i].enable) {
				if (osd_hw.osd_meson_dev.mif_linear)
					osd_update_mif_linear_addr(i);
			#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
				else
					canvas_config(osd_hw.fb_gem[i].canvas_idx,
						      osd_hw.fb_gem[i].addr,
						      CANVAS_ALIGNED
						      (osd_hw.fb_gem[i].width),
						      osd_hw.fb_gem[i].height,
						      CANVAS_ADDR_NOWRAP,
						      CANVAS_BLKMODE_LINEAR);
			#endif
			}
			osd_set_scan_mode(i);
			osd_hw.reg[OSD_COLOR_MODE].update_func(i);
			if (!osd_hw.dim_layer[i]) {
				VSYNCOSD_WR_MPEG_REG(osd_reg->osd_dimm_ctrl,
						     0x00000000);
			} else {
				u32 dimm_rgb = 0;

				dimm_rgb =
					((osd_hw.dim_color[i] & 0xff000000)
					>> 24) << 22;
				dimm_rgb |=
					((osd_hw.dim_color[i] & 0xff0000)
					>> 16) << 12;
				dimm_rgb |=
					((osd_hw.dim_color[i] & 0xff00)
					>> 8) << 2;
				VSYNCOSD_WR_MPEG_REG(osd_reg->osd_dimm_ctrl,
						     0x40000000 | dimm_rgb);
				VSYNCOSD_WR_MPEG_REG_BITS
					(osd_reg->osd_ctrl_stat2, 0x1, 14, 1);
				VSYNCOSD_WR_MPEG_REG_BITS
					(osd_reg->osd_ctrl_stat2,
					osd_hw.dim_color[i] & 0xff, 6, 8);
			}
			osd_hw.reg[DISP_GEOMETRY].update_func(i);
			osd_hw.reg[OSD_GBL_ALPHA].update_func(i);
			osd_hw.reg[DISP_OSD_REVERSE].update_func(i);
			osd_hw.reg[OSD_FREESCALE_COEF].update_func(i);
			osd_hw.reg[DISP_FREESCALE_ENABLE]
				.update_func(i);
			if (osd_update_window_axis)
				osd_update_window_axis = false;
			if (idx >= COLOR_INDEX_32_BGRX &&
			    idx <= COLOR_INDEX_32_XRGB)
				rgbx = true;
			if (osd_hw.premult_en[i] && !osd_hw.blend_bypass[i] &&
			    !rgbx && !osd_hw.osd_meson_dev.osd0_sc_independ)
				VSYNCOSD_WR_MPEG_REG_BITS
					(osd_reg->osd_mali_unpack_ctrl,
					 0x1, 28, 1);
			else
				VSYNCOSD_WR_MPEG_REG_BITS
					(osd_reg->osd_mali_unpack_ctrl,
					0x0, 28, 1);
#ifdef CONFIG_AMLOGIC_MEDIA_SECURITY
			if (osd_hw.secure_enable[i]) {
				switch (i) {
				case 0:
					secure_src |= OSD1_INPUT_SECURE;
					break;
				case 1:
					secure_src |= OSD2_INPUT_SECURE;
					break;
				case 2:
					secure_src |= OSD3_INPUT_SECURE;
					break;
				case 3:
					secure_src |= OSD4_INPUT_SECURE;
					break;
				}
			}
			if (secure_src && osd_hw.osd_afbcd[i].enable)
				secure_src |= MALI_AFBCD_SECURE;
			osd_hw.secure_src = secure_src;
#endif
		}
		osd_hw.reg[OSD_ENABLE].update_func(i);
	}

	if (osd_hw.hw_rdma_en)
		osd_mali_afbc_start(output_index);

	if (osd_hw.slice2ppc_enable)
		set_slice2ppc_reg();

	set_blend_reg(blending);
	save_blend_reg(blending);
#ifdef CONFIG_AMLOGIC_MEDIA_SECURITY
	if (osd_hw.osd_meson_dev.cpu_id == __MESON_CPU_MAJOR_ID_T7) {
		/* TODO: force to add dv bit set after secure config */
		if (secure_src & OSD1_INPUT_SECURE)
			osd_mali_afbcd_top_ctrl |= 1 << 17;
		else
			osd_mali_afbcd_top_ctrl &= ~(1 << 17);
		if (secure_src & OSD2_INPUT_SECURE)
			osd_mali_afbcd_top_ctrl |= 1 << 22;
		else
			osd_mali_afbcd_top_ctrl &= ~(1 << 22);
		if (secure_src & MALI_AFBCD_SECURE)
			osd_mali_afbcd_top_ctrl |= 1 << 18;
		else
			osd_mali_afbcd_top_ctrl &= ~(1 << 18);
		if (secure_src & OSD3_INPUT_SECURE)
			osd_mali_afbcd1_top_ctrl |= 1 << 22;
		else
			osd_mali_afbcd1_top_ctrl &= ~(1 << 22);
		notify_to_amdv();
	}
	secure_config(OSD_MODULE, secure_src, output_index);
#endif
	/* append RDMA_DETECT_REG at last and detect if rdma missed some regs */
	rdma_dt_cnt++;
	VSYNCOSD_WR_MPEG_REG(RDMA_DETECT_REG, rdma_dt_cnt);
	spin_unlock_irqrestore(&osd_lock, lock_flags);
	line2 = get_exit_encp_line(VIU1);
	osd_log_dbg(MODULE_RENDER,
		"%s:rdma_done_line=%d, encp line1=%d, line2=%d, total_line=%d\n",
		__func__, get_rdma_irq_done_line(VIU1),
		line1, line2, total_line);
	osd_wait_vsync_hw_viux(output_index);
	val = osd_reg_read(RDMA_DETECT_REG);
	if (line2 < line1) {
		osd_hw.rdma_delayed_cnt3++;
		osd_log_dbg(MODULE_ENCP_STAT, "osd line stat %d,%d, rdma_delayed_cnt3=%d\n",
			line1, line2, osd_hw.rdma_delayed_cnt3);
	}
	/* if missed, need wait vsync */
	if (val != rdma_dt_cnt) {
		osd_wait_vsync_hw_viux(output_index);
		osd_hw.rdma_delayed_cnt2++;
		osd_log_dbg(MODULE_ENCP_STAT, "osd line stat %d,%d val=0x%x, rdma_dt_cnt=0x%x\n",
			line1, line2, val, rdma_dt_cnt);
	}
	return 0;
}

static void osd_setting_vout_blend(void)
{
	u32 output_index = VPP0;

	osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
		(VPU_VOUT_BLD_SRC1_HPOS,
		osd_hw.free_dst_data[0].x_start,
		0, 13);
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
		(VPU_VOUT_BLD_SRC1_HPOS,
		osd_hw.free_dst_data[0].x_end,
		16, 13);

	osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
		(VPU_VOUT_BLD_SRC1_VPOS,
		osd_hw.free_dst_data[0].y_start,
		0, 13);
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
		(VPU_VOUT_BLD_SRC1_VPOS,
		osd_hw.free_dst_data[0].y_end,
		16, 13);
}

/* only one layer */
static void osd_setting_default_hwc(void)
{
	u32 blend_hsize, blend_vsize;
	u32 blend2_premult_en = 3, din_premult_en = 0;
	u32 blend_din_en = 0x5;
	/* blend_din0 input to blend0 */
	u32 din0_byp_blend = 0;
	/* blend1_dout to blend2 */
	u32 din2_osd_sel = 0;
	/* blend1_din3 input to blend1 */
	u32 din3_osd_sel = 0;
	u32 din_reoder_sel = 0x4441;
	u32 postbld_src3_sel = 3, postbld_src4_sel = 0;
	u32 postbld_osd1_premult = 0, postbld_osd2_premult = 0;

	osd_log_dbg(MODULE_BASE, "%s\n", __func__);
	if (osd_dev_hw.display_type == T7_DISPLAY ||
		osd_dev_hw.s5_display)
		postbld_src3_sel = POSTBLD_OSD1_T7;
	else
		postbld_src3_sel = POSTBLD_OSD1;

	if (osd_dev_hw.s5_display) {
		/* OSDx to blend_din(x+1) */
		din_reoder_sel = 0x4442;
		/* enable din0 out only */
		blend_din_en = 0x1;
	}

	if (osd_hw.osd_meson_dev.osd0_sc_independ)
		din_premult_en = 1;
	/* depend on din0_premult_en */
	postbld_osd1_premult = 0;
	/* depend on din_premult_en bit 4 */
	postbld_osd2_premult = 0;
	/* osd blend ctrl */
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd_blend_ctrl,
			     4                 << 29 |
			     blend2_premult_en << 27 |
			     din0_byp_blend    << 26 |
			     din2_osd_sel      << 25 |
			     din3_osd_sel      << 24 |
			     blend_din_en      << 20 |
			     din_premult_en    << 16 |
			     din_reoder_sel);
	/* vpp osd1 blend ctrl */
	if (osd_dev_hw.s5_display)
		VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd1_blend_src_ctrl,
				     (postbld_src3_sel & 0xf) << 0 |
				     (postbld_osd1_premult & 0x1) << 4);
	else
		VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd1_blend_src_ctrl,
				     (0 & 0xf) << 0 |
				     (0 & 0x1) << 4 |
				     (postbld_src3_sel & 0xf) << 8 |
				     (postbld_osd1_premult & 0x1) << 16 |
				     (1 & 0x1) << 20);
	/* vpp osd2 blend ctrl */
	if (!enable_vd_zorder) {
		if (osd_dev_hw.s5_display)
			VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd2_blend_src_ctrl,
					     (postbld_src4_sel & 0xf) << 0 |
					     (postbld_osd2_premult & 0x1) << 4);
		else
			VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd2_blend_src_ctrl,
					     (0 & 0xf) << 0 |
					     (0 & 0x1) << 4 |
					     (postbld_src4_sel & 0xf) << 8 |
					     (postbld_osd2_premult & 0x1) << 16 |
					     (1 & 0x1) << 20);
	}
	/* Do later: different format select different dummy_data */
	/* used default dummy data */
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd_blend_dummy_data0,
			     0x0 << 16 |
			     0x0 << 8 |
			     0x0);
	/* used default dummy alpha data */
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd_blend_dummy_alpha,
			     0x0  << 20 |
			     0x0  << 11 |
			     0x0);

	if (osd_hw.osd_meson_dev.osd0_sc_independ) {
		blend_hsize = osd_hw.dst_data[OSD1].w;
		blend_vsize = osd_hw.dst_data[OSD1].h;
	} else {
		if (osd_dev_hw.s5_display) {
			blend_hsize = osd_hw.disp_info[VIU1].position_w;
			blend_vsize = osd_hw.disp_info[VIU1].position_h;
		} else {
			blend_hsize = osd_hw.disp_info[VIU1].background_w;
			blend_vsize = osd_hw.disp_info[VIU1].background_h;
		}
	}

	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd_blend_blend0_size,
			     blend_vsize  << 16 |
			     blend_hsize);

	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd_blend_blend1_size,
			     blend_vsize  << 16 |
			     blend_hsize);

	if (osd_dev_hw.s5_display) {
		VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd_blend_dout0_size,
				     blend_vsize  << 16 |
				     blend_hsize);
		VSYNCOSD_WR_MPEG_REG(hw_osd_reg_blend.osd_blend_dout1_size,
				     blend_vsize  << 16 |
				     blend_hsize);
	}
	/* hdr input size should set to osd blend0 output size */
	if (!osd_dev_hw.s5_display)
		VSYNCOSD_WR_MPEG_REG(VPP_OSD1_IN_SIZE,
				     blend_vsize  << 16 |
				     blend_hsize);
	if (osd_dev_hw.has_multi_vpp) {
		osd_set_vpp_path(VPP_OSD3, get_output_device_id(OSD3));
		osd_set_vpp_path(VPP_OSD4, get_output_device_id(OSD4));
		set_osd_hdr_size_in(VPP_OSD1,
				    blend_hsize,
				    blend_vsize);
		/* vpp input mux */
		VSYNCOSD_WR_MPEG_REG_BITS(OSD_PATH_MISC_CTRL, VPP_OSD1, 16, 4);
	}
	if (osd_hw.osd_meson_dev.cpu_id == __MESON_CPU_MAJOR_ID_TXHD2) {
		VSYNCOSD_WR_MPEG_REG_BITS(hw_osd_reg_blend.osd_blend_ctrl, 0, 0, 1);
		VSYNCOSD_WR_MPEG_REG_BITS(hw_osd_reg_blend.osd_blend_ctrl1, 0, 0, 1);
	}
}

static bool set_old_hwc_freescale(u32 index)
{
	u32 x_start, x_end, y_start, y_end, height_dst, height_src;

	if (osd_hw.osd_reverse[index] == REVERSE_TRUE) {
		x_start = osd_hw.vinfo_width[VIU1]
			- osd_hw.free_dst_data[index].x_end - 1;
		y_start = osd_hw.vinfo_height[VIU1]
			- osd_hw.free_dst_data[index].y_end - 1;
		x_end = osd_hw.vinfo_width[VIU1]
			- osd_hw.free_dst_data[index].x_start - 1;
		y_end = osd_hw.vinfo_height[VIU1]
			- osd_hw.free_dst_data[index].y_start - 1;
		osd_hw.free_dst_data[index].x_start = x_start;
		osd_hw.free_dst_data[index].y_start = y_start;
		osd_hw.free_dst_data[index].x_end = x_end;
		osd_hw.free_dst_data[index].y_end = y_end;
	} else if (osd_hw.osd_reverse[index] == REVERSE_X) {
		x_start = osd_hw.vinfo_width[VIU1]
			- osd_hw.free_dst_data[index].x_end - 1;
		x_end = osd_hw.vinfo_width[VIU1]
			- osd_hw.free_dst_data[index].x_start - 1;
		osd_hw.free_dst_data[index].x_start = x_start;
		osd_hw.free_dst_data[index].x_end = x_end;
	} else if (osd_hw.osd_reverse[index] == REVERSE_Y) {
		y_start = osd_hw.vinfo_height[VIU1]
			- osd_hw.free_dst_data[index].y_end - 1;
		y_end = osd_hw.vinfo_height[VIU1]
			- osd_hw.free_dst_data[index].y_start - 1;
		osd_hw.free_dst_data[index].y_start = y_start;
		osd_hw.free_dst_data[index].y_end = y_end;
	}
	/* set dummy_data alpha */
	height_dst = osd_hw.free_dst_data[index].y_end -
			osd_hw.free_dst_data[index].y_start + 1;
	height_src = osd_hw.free_src_data[index].y_end -
			osd_hw.free_src_data[index].y_start + 1;
	if (height_dst != height_src &&
	    osd_hw.free_dst_data[index].y_end <
	    osd_hw.vinfo_height[VIU1] - 1)
		osd_set_dummy_data(index, 0);
	else
		osd_set_dummy_data(index, 0xff);

	if ((memcmp(&osd_hw.free_src_data[index],
		    &osd_hw.free_src_data_backup[index],
		    sizeof(struct pandata_s)) != 0) ||
	    memcmp(&osd_hw.free_dst_data[index],
		   &osd_hw.free_dst_data_backup[index],
		   sizeof(struct pandata_s)) != 0) {
		memcpy(&osd_hw.free_src_data_backup[index],
		       &osd_hw.free_src_data[index],
		       sizeof(struct pandata_s));
		memcpy(&osd_hw.free_dst_data_backup[index],
		       &osd_hw.free_dst_data[index],
		       sizeof(struct pandata_s));
		return true;
	} else {
		return false;
	}
}

static void osd_setting_old_hwc(void)
{
	int index = OSD1, output_index = VIU1;
	bool freescale_update = false;
	static u32 osd_enable;
	static bool first_set = true;

	spin_lock_irqsave(&osd_lock, lock_flags);
	if (!osd_hw.osd_afbcd[index].enable && osd_hw.enable[index]) {
		if (osd_hw.osd_meson_dev.mif_linear)
			osd_update_mif_linear_addr(index);
	#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
		else
			canvas_config(osd_hw.fb_gem[index].canvas_idx,
				      osd_hw.fb_gem[index].addr,
				      CANVAS_ALIGNED(osd_hw.fb_gem[index].width),
				      osd_hw.fb_gem[index].height,
				      CANVAS_ADDR_NOWRAP,
				      CANVAS_BLKMODE_LINEAR);
	#endif
	}
	osd_hw.reg[OSD_COLOR_MODE].update_func(index);
	freescale_update = set_old_hwc_freescale(index);
	/* geometry and freescale need update with ioctl */
	osd_hw.reg[DISP_GEOMETRY].update_func(index);
	osd_hw.reg[DISP_OSD_REVERSE].update_func(index);
	if ((osd_hw.free_scale_enable[index] &&
	     osd_update_window_axis) ||
	    freescale_update) {
		if (!osd_hw.osd_display_debug[output_index]) {
			osd_set_scan_mode(index);
			osd_hw.reg[OSD_FREESCALE_COEF]
				.update_func(index);
			osd_hw.reg[DISP_FREESCALE_ENABLE]
				.update_func(index);
		}
		osd_update_window_axis = false;
	}
	if ((osd_enable != osd_hw.enable[index] || first_set) &&
	    !osd_hw.osd_display_debug[output_index] &&
	    !suspend_flag) {
		osd_hw.reg[OSD_ENABLE]
		.update_func(index);
		osd_enable = osd_hw.enable[index];
		first_set = false;
	}
	spin_unlock_irqrestore(&osd_lock, lock_flags);
	osd_wait_vsync_hw(index);
}

static struct hw_vppx_blend_reg_s vpp_topx_blend_reg_array[VPU_VPP_MAX] = {
	{/* reserved regs */},
	{
		VPP1_BLD_DIN1_HSCOPE,
		VPP1_BLD_DIN1_VSCOPE,
		VPP1_BLD_OUT_SIZE,
		VPP1_BLD_CTRL,
		VPP1_BLEND_BLEND_DUMMY_DATA,
		VPP1_BLEND_DUMMY_ALPHA,
	},
	{
		VPP2_BLD_DIN1_HSCOPE,
		VPP2_BLD_DIN1_VSCOPE,
		VPP2_BLD_OUT_SIZE,
		VPP2_BLD_CTRL,
		VPP2_BLEND_BLEND_DUMMY_DATA,
		VPP2_BLEND_DUMMY_ALPHA,
	},
};

static struct hw_vppx_blend_reg_s vpp_topx_blend_reg_array2[VPU_VPP_MAX] = {
	{/* reserved regs */},
	{
		T3X_VPP1_OSD3_BLD_H_SCOPE,
		T3X_VPP1_OSD3_BLD_V_SCOPE,
		T3X_VPP1_BLEND_H_V_SIZE,
		T3X_VPP1_BLD_CTRL,
		T3X_VPP1_BLEND_BLEND_DUMMY_DATA,
		T3X_VPP1_BLEND_DUMMY_ALPHA,
	},
};

static void osd_setting_viux(u32 output_index)
{
	int index = 0, i;
	struct hw_osd_reg_s *osd_reg = NULL;
	static int count;
	struct hw_vppx_blend_reg_s *vppx_blend_reg = NULL;
	struct vinfo_s *vinfo = NULL;
	u32 vpp_blend_ctrl = 0;
	/* 1:vd1  2:osd1 else :close */
	u32 bld_src2_sel = 2;
	u32 osd1_premult = 0;
	u32 blend_en = 1;
	u32 vd3_dpath_sel = 0, vpp1_dpath_sel = 0;
#ifdef CONFIG_AMLOGIC_MEDIA_SECURITY
	u32 secure_src = 0;
#endif

	osd_log_dbg2(MODULE_RENDER, "### vpp_top%d display\n", output_index);

	for (i = 0; i < osd_hw.osd_meson_dev.osd_count; i++) {
		if (validate_osd(i, output_index)) {
			index = i;
			break;
		}
	}

	osd_reg = &hw_osd_reg_array[index];

	if (osd_dev_hw.display_type == T7_DISPLAY ||
	    osd_dev_hw.display_type == S5_DISPLAY ||
	    is_keystone_enable_for_txhd2()) {
		u32 width, height;
		struct osd_rdma_fun_s *rdma_func = &osd_hw.osd_rdma_func[output_index];
		osd_rdma_rd_op rdma_rd = rdma_func->osd_rdma_rd;
		osd_rdma_wr_op rdma_wr = rdma_func->osd_rdma_wr;
		osd_rdma_wr_bits_op rdma_wr_bits = rdma_func->osd_rdma_wr_bits;

		/* enable free_scale */
		if (osd_hw.pps_support[index]) {
			osd_hw.free_scale_enable[index] = 0x10001;
			osd_hw.free_scale[index].h_enable = 1;
			osd_hw.free_scale[index].v_enable = 1;
			osd_hw.free_scale_mode[index] = 1;
		} else {
			osd_hw.free_scale_enable[index] = 0x0;
			osd_hw.free_scale[index].h_enable = 0;
			osd_hw.free_scale[index].v_enable = 0;
		}
		osd_set_scan_mode(index);
		osd_hw.free_src_data[index].x_start =
			osd_hw.src_data[index].x;
		osd_hw.free_src_data[index].x_end =
			osd_hw.src_data[index].x +
			osd_hw.src_data[index].w - 1;
		osd_hw.free_src_data[index].y_start =
			osd_hw.src_data[index].y;
		osd_hw.free_src_data[index].y_end =
			osd_hw.src_data[index].y +
			osd_hw.src_data[index].h - 1;
		if (osd_hw.osd_v_skip[index]) {
			osd_hw.free_src_data[index].y_end =
				(osd_hw.src_data[index].y +
			osd_hw.src_data[index].h) / 2 - 1;
		}

		osd_hw.free_dst_data[index].x_start =
			osd_hw.dst_data[index].x;
		osd_hw.free_dst_data[index].y_start =
			osd_hw.dst_data[index].y;
		width = osd_hw.dst_data[index].w;
		height = osd_hw.dst_data[index].h;
		if (osd_hw.field_out_en[output_index]) {
			height = height >> 1;
			osd_hw.free_dst_data[index].y_start >>= 1;
		}

		osd_hw.free_dst_data[index].x_end =
			osd_hw.free_dst_data[index].x_start +
			width - 1;
		osd_hw.free_dst_data[index].y_end =
			osd_hw.free_dst_data[index].y_start +
			height - 1;

		if (osd_hw.enable[index]) {
			struct hw_osd_reg_s *osd_reg = &hw_osd_reg_array[index];
			enum color_index_e idx = COLOR_INDEX_32_BGRX;
			bool rgbx = false;

			if (osd_hw.color_info[index])
				idx = osd_hw.color_info[index]->color_index;
			else
				osd_log_err("osd%d color_info is NULL\n",
					    index);

			/* update = is_freescale_para_changed(i); */
			if (!osd_hw.osd_afbcd[index].enable) {
				if (osd_hw.osd_meson_dev.mif_linear)
					osd_update_mif_linear_addr(index);
	#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
				else
					canvas_config(osd_hw.fb_gem[index].canvas_idx,
						      osd_hw.fb_gem[index].addr,
						      CANVAS_ALIGNED
						      (osd_hw.fb_gem[index].width),
						      osd_hw.fb_gem[index].height,
						      CANVAS_ADDR_NOWRAP,
						      CANVAS_BLKMODE_LINEAR);
	#endif
			}
			osd_hw.reg[OSD_COLOR_MODE].update_func(index);
			if (!osd_hw.dim_layer[index]) {
				rdma_wr(osd_reg->osd_dimm_ctrl, 0x00000000);
			} else {
				u32 dimm_rgb = 0;

				dimm_rgb =
					((osd_hw.dim_color[index] & 0xff000000)
					>> 24) << 22;
				dimm_rgb |=
					((osd_hw.dim_color[index] & 0xff0000)
					>> 16) << 12;
				dimm_rgb |=
					((osd_hw.dim_color[index] & 0xff00)
					>> 8) << 2;
				rdma_wr(osd_reg->osd_dimm_ctrl,
					0x40000000 | dimm_rgb);
				rdma_wr_bits(osd_reg->osd_ctrl_stat2,
					     0x1, 14, 1);
				rdma_wr_bits(osd_reg->osd_ctrl_stat2,
					     osd_hw.dim_color[index] & 0xff,
					     6, 8);
			}

			osd_hw.reg[DISP_GEOMETRY].update_func(index);
			osd_hw.reg[OSD_GBL_ALPHA].update_func(index);
			osd_hw.reg[DISP_OSD_REVERSE].update_func(index);
			osd_hw.reg[OSD_FREESCALE_COEF].update_func(index);
			osd_hw.reg[DISP_FREESCALE_ENABLE]
				.update_func(index);

			if (idx >= COLOR_INDEX_32_BGRX &&
			    idx <= COLOR_INDEX_32_XRGB)
				rgbx = true;
			if (osd_hw.premult_en[index] && !rgbx &&
				!osd_hw.osd_meson_dev.osd0_sc_independ)
				rdma_wr_bits(osd_reg->osd_mali_unpack_ctrl,
					     0x1, 28, 1);
			else
				rdma_wr_bits(osd_reg->osd_mali_unpack_ctrl,
					     0x0, 28, 1);
		}

		if (osd_dev_hw.display_type == T7_DISPLAY) {
			/* bypass free_scaler & osd_blend */
			if (osd_dev_hw.path_ctrl_independ) {
				rdma_wr_bits(VIU_OSD1_PATH_CTRL + index, 0x1, 4, 1);
				rdma_wr_bits(VIU_OSD1_PATH_CTRL + index, 0x1, 0, 1);
			} else {
				rdma_wr_bits(VPP_OSD1_SCALE_CTRL + index, 0x7, 0, 3);
			}

			/* hdr in size */
			set_osd_hdr_size_in(index, width, height);

			/* vpp_top input mux */
			rdma_wr_bits(OSD_PATH_MISC_CTRL, index + VPP_OSD1,
				     index * 4 + 16, 4);
			osd_set_vpp_path(index + VPP_OSD1, output_index);
		} else if (osd_dev_hw.display_type == S5_DISPLAY) {
			/* use vpp1 vsync */
			rdma_wr_bits(VIU_OSD3_MISC, 1, 0, 1);
			/* 1mux3,  OSD3 -> din5 */
			rdma_wr_bits(OSD_PROC_1MUX3_SEL, 0, 4, 2);
			/* 5mux4, select din5 */
			rdma_wr_bits(OSD_SYS_5MUX4_SEL, 5, 8, 4);
		}

		if (osd_hw.osd_meson_dev.cpu_id !=
				__MESON_CPU_MAJOR_ID_TXHD2) {
			/* to vpp_topx */
			if (osd_dev_hw.display_type == T7_DISPLAY) {
				vppx_blend_reg = &vpp_topx_blend_reg_array[output_index];
			} else if (osd_dev_hw.display_type == S5_DISPLAY) {
				vppx_blend_reg = &vpp_topx_blend_reg_array2[output_index];
			} else {
				osd_log_err("%s, no vppx_blend_reg\n", __func__);
				return;
			}

			rdma_wr(vppx_blend_reg->vpp_bld_din1_hscope,
				(osd_hw.free_dst_data[index].x_start << 16) |
				osd_hw.free_dst_data[index].x_end);

			rdma_wr(vppx_blend_reg->vpp_bld_din1_vscope,
				(osd_hw.free_dst_data[index].y_start << 16) |
				osd_hw.free_dst_data[index].y_end);

			if (osd_hw.enable[index] == ENABLE)
				bld_src2_sel = 2;
			else
				bld_src2_sel = 0;
			//vpp_blend_ctrl = rdma_rd(vppx_blend_reg->vpp_bld_ctrl);
			vpp_blend_ctrl |= bld_src2_sel << 4 |
					  osd1_premult << 17 |
					  blend_en << 31;

			if (osd_dev_hw.display_type == S5_DISPLAY) {
				/* 0:select postblend 1:select vpp1 blend */
				vd3_dpath_sel = 1;
				/* 1:output to vpp slice1 0:output to venc1 directly */
				vpp1_dpath_sel = 0;
				vpp_blend_ctrl |= vd3_dpath_sel << 29 |
						  vpp1_dpath_sel << 30;
			}

			if (output_index == VPU_VPP1)
				osd_vpp1_bld_ctrl = vpp_blend_ctrl |
						    osd_vpp_bld_ctrl_update_mask;
			else if (output_index == VPU_VPP2)
				osd_vpp2_bld_ctrl = vpp_blend_ctrl |
						    osd_vpp_bld_ctrl_update_mask;

			//rdma_wr(vppx_blend_reg->vpp_bld_ctrl, vpp_blend_ctrl);
			switch (output_index) {
			case VPU_VPP0:
				#ifdef CONFIG_AMLOGIC_VOUT_SERVE
				vinfo = get_current_vinfo();
				#endif
				break;
			case VPU_VPP1:
				#ifdef CONFIG_AMLOGIC_VOUT2_SERVE
				vinfo = get_current_vinfo2();
				#endif
				break;
			case VPU_VPP2:
				#ifdef CONFIG_AMLOGIC_VOUT3_SERVE
				vinfo = get_current_vinfo3();
				#endif
				break;
			default:
				osd_log_err("osd%d, vpp_top%x index error\n", index, output_index);
				break;
			}

			if (vinfo)
				osd_log_dbg2(MODULE_RENDER, "screen%d, W:%d H:%d\n",
					     output_index, vinfo->width,
					     vinfo->field_height);
			if (vinfo) {
				u32 read_value =
					rdma_rd(vppx_blend_reg->vpp_bld_out_size);

				if (((vinfo->field_height << 16) | vinfo->width) !=
				    read_value)
					rdma_wr(vppx_blend_reg->vpp_bld_out_size,
						((vinfo->field_height << 16) |
						 vinfo->width));
			} else {
				osd_log_err("%s, %d current vinfo NULL\n",
					    __func__, __LINE__);
			}
		}
		osd_hw.reg[OSD_ENABLE].update_func(index);

		if (osd_hw.hw_rdma_en)
			osd_mali_afbc_start(output_index);

	} else {
		count++;
		if (!osd_hw.osd_afbcd[index].enable)
	#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
			canvas_config(osd_hw.fb_gem[index].canvas_idx,
				      osd_hw.fb_gem[index].addr,
				      CANVAS_ALIGNED(osd_hw.fb_gem[index].width),
				      osd_hw.fb_gem[index].height,
				      CANVAS_ADDR_NOWRAP,
				      CANVAS_BLKMODE_LINEAR);
	#endif
		osd_set_scan_mode(index);
		osd_hw.reg[OSD_COLOR_MODE].update_func(index);
		if (count == 1) {
			/* geometry and freescale need update with ioctl */
			osd_hw.reg[DISP_GEOMETRY].update_func(index);
			osd_hw.reg[DISP_OSD_REVERSE].update_func(index);
			if (!osd_hw.osd_display_debug[output_index])
				osd_hw.reg[OSD_ENABLE]
				.update_func(index);
		}
		if (!osd_hw.dim_layer[index]) {
			VSYNCOSD_WR_MPEG_REG(osd_reg->osd_dimm_ctrl,
					     0x00000000);
		} else {
			u32 dimm_rgb = 0;

			dimm_rgb =
				((osd_hw.dim_color[index] & 0xff000000)
				>> 24) << 22;
			dimm_rgb |=
				((osd_hw.dim_color[index] & 0xff0000)
				>> 16) << 12;
			dimm_rgb |=
				((osd_hw.dim_color[index] & 0xff00)
				>> 8) << 2;
			VSYNCOSD_WR_MPEG_REG(osd_reg->osd_dimm_ctrl,
					     0x40000000 | dimm_rgb);
			VSYNCOSD_WR_MPEG_REG_BITS(osd_reg->osd_ctrl_stat2, 0x1, 14, 1);
			VSYNCOSD_WR_MPEG_REG_BITS(osd_reg->osd_ctrl_stat2,
						  osd_hw.dim_color[index] & 0xff, 6, 8);
		}
	}

#ifdef CONFIG_AMLOGIC_MEDIA_SECURITY
	if (osd_hw.secure_enable[i]) {
		switch (i) {
		case 0:
			secure_src |= OSD1_INPUT_SECURE;
			break;
		case 1:
			secure_src |= OSD2_INPUT_SECURE;
			break;
		case 2:
			secure_src |= OSD3_INPUT_SECURE;
			break;
		case 3:
			secure_src |= OSD4_INPUT_SECURE;
			break;
		}
	}
	if (secure_src && osd_hw.osd_afbcd[i].enable)
		secure_src |= MALI_AFBCD_SECURE;
	osd_hw.secure_src = secure_src;
	if (osd_hw.osd_meson_dev.cpu_id == __MESON_CPU_MAJOR_ID_T7) {
		/* TODO: force to add dv bit set after secure config */
		if (secure_src & OSD1_INPUT_SECURE)
			osd_mali_afbcd_top_ctrl |= 1 << 17;
		else
			osd_mali_afbcd_top_ctrl &= ~(1 << 17);
		if (secure_src & OSD2_INPUT_SECURE)
			osd_mali_afbcd_top_ctrl |= 1 << 22;
		else
			osd_mali_afbcd_top_ctrl &= ~(1 << 22);
		if (secure_src & MALI_AFBCD_SECURE)
			osd_mali_afbcd_top_ctrl |= 1 << 18;
		else
			osd_mali_afbcd_top_ctrl &= ~(1 << 18);
		if (secure_src & OSD3_INPUT_SECURE)
			osd_mali_afbcd1_top_ctrl |= 1 << 22;
		else
			osd_mali_afbcd1_top_ctrl &= ~(1 << 22);
		notify_to_amdv();
	}
	secure_config(OSD_MODULE, secure_src, output_index);
#endif

	osd_wait_vsync_hw_viux(output_index);
}

int osd_setting_blend(u32 output_index)
{
	int ret;
	int start_index = 0;
	int osd_count = 0;

	if (output_index == VIU1) {
		osd_count = osd_hw.osd_meson_dev.viu1_osd_count;
		if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL)
			osd_count = 1;
		start_index = 0;
	} else if (output_index == VIU2) {
		if (osd_dev_hw.display_type == T7_DISPLAY ||
		    osd_dev_hw.display_type == S5_DISPLAY) {
			osd_count = osd_hw.osd_meson_dev.viu1_osd_count;
			start_index = 0;
		} else {
			start_index = osd_hw.osd_meson_dev.viu2_index;
			osd_count = start_index + 1;
		}
	}

#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
	check_and_reverse_axis(start_index, osd_count, output_index);
#endif
	if (osd_hw.osd_meson_dev.osd_ver < OSD_HIGH_ONE) {
		osd_setting_old_hwc();
	} else {
		if (osd_hw.hwc_enable[output_index]) {
			if (output_index == VIU1) {
				ret = osd_setting_order(output_index);
				if (ret < 0)
					return -1;
			} else if (output_index == VIU2) {
				osd_setting_viux(VIU2);
			} else if (output_index == VIU3) {
				osd_setting_viux(VIU3);
			}
		} else {
			osd_setting_default_hwc();
		}
	}
	return 0;
}

void osd_mali_afbc_start(u32 output_index)
{
	int i, osd_count, afbc_enable = 0;
	struct hw_osd_reg_s *osd_reg;

	struct osd_rdma_fun_s *rdma_func = &osd_hw.osd_rdma_func[output_index];
	osd_rdma_wr_op rdma_wr = rdma_func->osd_rdma_wr;

	osd_count = osd_hw.osd_meson_dev.osd_count;
	if (osd_hw.osd_meson_dev.afbc_type == MALI_AFBC) {
		int afbc0_start = 0;

		for (i = 0; i < osd_count; i++) {
			u32 hw_index;

			osd_reg = &hw_osd_reg_array[i];
			if (osd_hw.osd_afbcd[i].afbc_start)
				/* enable mali afbc */
				afbc_enable |= (1 << i);

			if (osd_dev_hw.multi_afbc_core && osd_hw.osd_afbcd[i].afbc_start) {
				if (!validate_osd(i, output_index))
					continue;

				hw_index = to_osd_hw_index(i);
				osd_log_dbg2(MODULE_BASE, "i:%d hw_index:%d\n", i, hw_index);
				/* for osd_dev_hw.multi_afbc_core,
				 * OSD1+OSD2 uses afbc, OSD3 uses afbc1, OSD4 uses afbc2.
				 */
				if (osd_dev_hw.share_afbc_core &&
				    hw_index == OSD2 && afbc0_start)
					continue;

				rdma_wr(osd_reg->vpu_mafbc_command,
					(osd_hw.afbc_use_latch ?
					2 : 1));
				osd_log_dbg2(MODULE_BASE, "AFBC osd%d start command\n", i);
				if (hw_index == OSD1)
					afbc0_start = 1;
			}
		}
		if (!osd_dev_hw.multi_afbc_core && afbc_enable)
			VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_COMMAND,
					     (osd_hw.afbc_use_latch ?
					      2 : 1));
	}
}

static void osd_basic_update_disp_geometry(u32 index)
{
	struct hw_osd_reg_s *osd_reg = &hw_osd_reg_array[index];
	u32 data32;
	u32 output_index = get_output_device_id(index);
	u32 in_x_start, in_x_end, in_y_start, in_y_end;
	u32 disp_x_start, disp_x_end, disp_y_start, disp_y_end;

	if (osd_hw.slice2ppc_enable) {
		in_x_start = osd_slice2ppc.slice_in_x_start[index];
		in_x_end   = osd_slice2ppc.slice_in_x_end[index];
		in_y_start = osd_slice2ppc.slice_in_y_start[index];
		in_y_end   = osd_slice2ppc.slice_in_y_end[index];
		disp_x_start = 0;
		disp_x_end   = in_x_end - in_x_start;
		disp_y_start = 0;
		disp_y_end   = in_y_end - in_y_start;
	} else {
		in_x_start = osd_hw.src_data[index].x;
		in_x_end   = osd_hw.src_data[index].x +
			     osd_hw.src_data[index].w - 1;
		in_y_start = osd_hw.src_data[index].y;
		in_y_end   = osd_hw.src_data[index].y +
			     osd_hw.src_data[index].h - 1;
		disp_x_start = osd_hw.dispdata[index].x_start;
		disp_x_end   = osd_hw.dispdata[index].x_end;
		disp_y_start = osd_hw.dispdata[index].y_start;
		disp_y_end   = osd_hw.dispdata[index].y_end;
	}

	data32 = (disp_x_start & 0xfff) | (disp_x_end & 0xfff) << 16;
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(osd_reg->osd_blk0_cfg_w3, data32);
	if (osd_hw.scan_mode[index] == SCAN_MODE_INTERLACE)
		data32 = ((disp_y_start >> 1) & 0xfff)
			| ((((disp_y_end + 1) >> 1) - 1) & 0xfff) << 16;
	else
		data32 = (disp_y_start & 0xfff) | (disp_y_end & 0xfff) << 16;
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(osd_reg->osd_blk0_cfg_w4,
		data32);

	if (osd_hw.osd_meson_dev.afbc_type == MALI_AFBC) {
		if (osd_hw.osd_afbcd[index].enable) {
			u64 headr_addr, out_addr;

			/* set frame addr in linear: out_addr_id */
			headr_addr = osd_hw.osd_afbcd[index].phy_addr;
			/* mali afbc out ram addr = osd addr */
			out_addr = ((u64)osd_hw.osd_afbcd[index].out_addr_id)
					<< 24;
			/*  0:canvas_araddr
			 *  1:linear_araddr
			 */
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(osd_reg->osd_ctrl_stat,
				0x1, 2, 1);
			if (osd_dev_hw.has_8G_addr)
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(osd_reg->osd_blk1_cfg_w4,
					out_addr >> 4);
			else
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(osd_reg->osd_blk1_cfg_w4,
					out_addr);
			/* unpac mali src */
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(osd_reg->osd_mali_unpack_ctrl,
				0x1, 31, 1);

			/* osd switch to mali */
			if (osd_dev_hw.multi_afbc_core) {
				if (osd_dev_hw.s5_display) {
					osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
							(osd_reg->mali_afbcd_top_ctrl,
							 0x1, 0, 1);
				} else if (osd_dev_hw.path_ctrl_independ) {
					osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
							(osd_reg->mali_afbcd_top_ctrl,
							 0x1, 31, 1);
				} else {
					if (index == OSD1) {
						update_afbcdx_and_notify_amdv(index, 1, 16, 1);
						osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
							(osd_reg->mali_afbcd_top_ctrl,
							 0x1, 16, 1);
					} else {
						update_afbcdx_and_notify_amdv(index, 1, 21, 1);
						osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
							(osd_reg->mali_afbcd_top_ctrl,
							 0x1, 21, 1);
					}
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
					if (osd_hw.osd_meson_dev.cpu_id ==
						__MESON_CPU_MAJOR_ID_T7 &&
						validate_osd(index, VIU1))
						osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
							(MALI_AFBCD_TOP_CTRL,
							 is_amdv_graphic_on() ? 0 : 1,
							 14, 1);
#endif
				}
			} else {
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
					(OSD_PATH_MISC_CTRL,
					0x01, (index + 4), 1);
			}
			/* read from mali afbd decoder */
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(osd_reg->osd_blk0_cfg_w0,
						  0x1, 30, 1);

			osd_hw.osd_rdma_func[output_index].osd_rdma_wr
				(osd_reg->afbc_header_buf_addr_low_s,
				headr_addr & 0xffffffff);
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr
				(osd_reg->afbc_header_buf_addr_high_s,
				(headr_addr >> 32) & 0xffffffff);
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr
				(osd_reg->afbc_buffer_width_s,
				osd_hw.osd_afbcd[index].frame_width);
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr
				(osd_reg->afbc_buffer_hight_s,
				osd_hw.osd_afbcd[index].frame_height);
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr
				(osd_reg->afbc_output_buf_addr_low_s,
				out_addr & 0xffffffff);
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr
				(osd_reg->afbc_output_buf_addr_high_s,
				(out_addr >> 32) & 0xffffffff);
			if (osd_hw.osd_afbcd[index].enable) {
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(osd_reg->afbc_bounding_box_x_start_s,
					 in_x_start);
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(osd_reg->afbc_bounding_box_x_end_s,
					 in_x_end);
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(osd_reg->afbc_bounding_box_y_start_s,
					 in_y_start);
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr
					(osd_reg->afbc_bounding_box_y_end_s,
					 in_y_end);
			}
		} else {
			/* osd switch to mali */
			if (osd_dev_hw.multi_afbc_core) {
				if (osd_dev_hw.s5_display) {
					osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
							(osd_reg->mali_afbcd_top_ctrl,
							 0x0, 0, 1);
				} else if (osd_dev_hw.path_ctrl_independ) {
					osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
							(osd_reg->mali_afbcd_top_ctrl,
							 0x0, 31, 1);
				} else {
					if (index == OSD1) {
						update_afbcdx_and_notify_amdv(index, 0, 16, 1);
						osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
							(osd_reg->mali_afbcd_top_ctrl,
							 0x0, 16, 1);
					} else {
						update_afbcdx_and_notify_amdv(index, 0, 21, 1);
						osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
							(osd_reg->mali_afbcd_top_ctrl,
							 0x0, 21, 1);
					}
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
					if (osd_hw.osd_meson_dev.cpu_id ==
						__MESON_CPU_MAJOR_ID_T7 &&
						validate_osd(index, VIU1))
						osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
							(MALI_AFBCD_TOP_CTRL,
							 is_amdv_graphic_on() ? 0 : 1,
							 14, 1);
#endif
				}
			} else {
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
					(OSD_PATH_MISC_CTRL, 0x0, (index + 4), 1);
			}
			/*  unpac normal src */
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(osd_reg->osd_mali_unpack_ctrl,
				0x0, 31, 1);
			/* read from ddr */
			osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
				(osd_reg->osd_blk0_cfg_w0, 0x0, 30, 1);
			/* use canvas addr should not clear for mif */
			if (!osd_hw.osd_meson_dev.mif_linear)
				osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
					(osd_reg->osd_ctrl_stat, 0x0, 2, 1);
		}
	}

	data32 = (in_x_start & 0x1fff) | (in_x_end & 0x1fff) << 16;
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(hw_osd_reg_array[index].osd_blk0_cfg_w1, data32);

	data32 = (in_y_start & 0x1fff) | (in_y_end & 0x1fff) << 16;
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(osd_reg->osd_blk0_cfg_w2, data32);

	data32 = osd_hw.osd_rdma_func[output_index].osd_rdma_rd
		(osd_reg->osd_ctrl_stat);
	data32 &= ~0x1ff008;//0x1ff00e;
	data32 |= osd_hw.gbl_alpha[index] << 12;
	/* data32 |= HW_OSD_BLOCK_ENABLE_0; */
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(osd_reg->osd_ctrl_stat, data32);
	remove_from_update_list(index, DISP_GEOMETRY);
}

static void osd1_basic_update_disp_geometry(void)
{
	u32 data32;
	u32 buffer_w, buffer_h;

	data32 = (osd_hw.dispdata[OSD1].x_start & 0xfff)
		| (osd_hw.dispdata[OSD1].x_end & 0xfff) << 16;
	VSYNCOSD_WR_MPEG_REG
		(hw_osd_reg_array[OSD1].osd_blk0_cfg_w3, data32);
	if (osd_hw.scan_mode[OSD1] == SCAN_MODE_INTERLACE)
		data32 = ((osd_hw.dispdata[OSD1].y_start >> 1) & 0xfff)
			| ((((osd_hw.dispdata[OSD1].y_end + 1)
			>> 1) - 1) & 0xfff) << 16;
	else
		data32 = (osd_hw.dispdata[OSD1].y_start & 0xfff)
			| (osd_hw.dispdata[OSD1].y_end
			& 0xfff) << 16;
	VSYNCOSD_WR_MPEG_REG
		(hw_osd_reg_array[OSD1].osd_blk0_cfg_w4, data32);

	if (osd_hw.osd_afbcd[OSD1].enable)
		VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_SIZE_IN,
				     ((osd_hw.osd_afbcd[OSD1].frame_width
				     & 0xffff) << 16) |
				     ((osd_hw.osd_afbcd[OSD1].frame_height
				     & 0xffff) << 0));

	/* enable osd 2x scale */
	if (osd_hw.scale[OSD1].h_enable || osd_hw.scale[OSD1].v_enable) {
		osd1_2x_scale_update_geometry();
		data32 = VSYNCOSD_RD_MPEG_REG
			(hw_osd_reg_array[OSD1].osd_blk0_cfg_w1);
		buffer_w = ((data32 >> 16) & 0x1fff) - (data32 & 0x1fff) + 1;
		data32 = VSYNCOSD_RD_MPEG_REG
			(hw_osd_reg_array[OSD1].osd_blk0_cfg_w2);
		buffer_h = ((data32 >> 16) & 0x1fff) - (data32 & 0x1fff) + 1;
	} else if (osd_hw.free_scale_enable[OSD1] &&
		   (osd_hw.free_src_data[OSD1].x_end > 0) &&
		   (osd_hw.free_src_data[OSD1].y_end > 0)) {
		/* enable osd free scale */
		data32 = (osd_hw.free_src_data[OSD1].x_start & 0x1fff) |
			 (osd_hw.free_src_data[OSD1].x_end & 0x1fff) << 16;
		VSYNCOSD_WR_MPEG_REG(hw_osd_reg_array[OSD1].osd_blk0_cfg_w1,
				     data32);
		buffer_w = ((data32 >> 16) & 0x1fff) - (data32 & 0x1fff) + 1;
		if (osd_hw.osd_afbcd[OSD1].enable) {
			data32 =
				(osd_hw.free_src_data[OSD1].x_end & 0x1fff) |
				(osd_hw.free_src_data[OSD1].x_start & 0x1fff)
				<< 16;
			VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_PIXEL_HSCOPE, data32);
			data32 =
				(osd_hw.free_src_data[OSD1].y_end & 0x1fff) |
				(osd_hw.free_src_data[OSD1].y_start & 0x1fff)
				<< 16;
			VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_PIXEL_VSCOPE, data32);
			VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_HDR_PTR,
					     osd_hw.osd_afbcd[OSD1].phy_addr
					     >> 4);
			VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_FRAME_PTR,
					     osd_hw.osd_afbcd[OSD1].phy_addr
					     >> 4);
			data32 = (0xe4 << 24) |
				(osd_hw.osd_afbcd[OSD1].phy_addr & 0xffffff);
			VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_CHROMA_PTR,
					     data32);
		}
		data32 = ((osd_hw.free_src_data[OSD1].y_start
			+ osd_hw.pandata[OSD1].y_start) & 0x1fff)
			| ((osd_hw.free_src_data[OSD1].y_end
			+ osd_hw.pandata[OSD1].y_start) & 0x1fff) << 16;
		VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W2, data32);
		buffer_h = ((data32 >> 16) & 0x1fff) - (data32 & 0x1fff) + 1;
	} else {
		/* normal mode */
		data32 = (osd_hw.pandata[OSD1].x_start & 0x1fff)
			| (osd_hw.pandata[OSD1].x_end & 0x1fff) << 16;
		VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_array[OSD1].osd_blk0_cfg_w1, data32);
		buffer_w = ((data32 >> 16) & 0x1fff) - (data32 & 0x1fff) + 1;
		if (osd_hw.osd_afbcd[OSD1].enable) {
			u32 virtual_y_start, virtual_y_end;

			data32 = (osd_hw.pandata[OSD1].x_end & 0x1fff)
				| (osd_hw.pandata[OSD1].x_start & 0x1fff) << 16;
			VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_PIXEL_HSCOPE, data32);
			virtual_y_start = osd_hw.pandata[OSD1].y_start %
				osd_hw.osd_afbcd[OSD1].frame_height;
			virtual_y_end = osd_hw.pandata[OSD1].y_end -
				osd_hw.pandata[OSD1].y_start + virtual_y_start;
			data32 = (virtual_y_end & 0x1fff) |
				 (virtual_y_start & 0x1fff) << 16;
			VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_PIXEL_VSCOPE, data32);
			VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_HDR_PTR,
					     osd_hw.osd_afbcd[OSD1].phy_addr
					     >> 4);
			VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_FRAME_PTR,
					     osd_hw.osd_afbcd[OSD1].phy_addr
					     >> 4);
			data32 = (0xe4 << 24) |
				(osd_hw.osd_afbcd[OSD1].phy_addr & 0xffffff);
			VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_CHROMA_PTR,
					     data32);
		}
		data32 = (osd_hw.pandata[OSD1].y_start & 0x1fff)
			| (osd_hw.pandata[OSD1].y_end & 0x1fff) << 16;
		VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_array[OSD1].osd_blk0_cfg_w2, data32);
		buffer_h = ((data32 >> 16) & 0x1fff) - (data32 & 0x1fff) + 1;
	}
	if (osd_hw.osd_meson_dev.has_dolby_vision) {
		if (osd_dev_hw.s5_display) {
			VSYNCOSD_WR_MPEG_REG(S5_AMDV_CORE2A_SWAP_CTRL1,
						 ((buffer_w + 0x40) << 16)
						 | (buffer_h + 0x80 + 0));
			VSYNCOSD_WR_MPEG_REG(S5_AMDV_CORE2A_SWAP_CTRL2,
						 (buffer_w << 16) |
						 (buffer_h + 0));
		} else {
			VSYNCOSD_WR_MPEG_REG(AMDV_CORE2A_SWAP_CTRL1,
					     ((buffer_w + 0x40) << 16)
					     | (buffer_h + 0x80 + 0));
			VSYNCOSD_WR_MPEG_REG(AMDV_CORE2A_SWAP_CTRL2,
						(buffer_w << 16) | (buffer_h + 0));
		}
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
		update_graphic_width_height(buffer_w, buffer_h, 0);
#endif
	}
	if (osd_hw.osd_afbcd[OSD1].enable &&
	    !osd_afbc_dec_enable &&
	    osd_hw.osd_afbcd[OSD1].phy_addr != 0) {
		VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_ENABLE, 0x8100);
		osd_afbc_dec_enable = 1;
	}
	data32 = VSYNCOSD_RD_MPEG_REG
		(hw_osd_reg_array[OSD1].osd_ctrl_stat);
	data32 &= ~0x1ff00e;
	data32 |= osd_hw.gbl_alpha[OSD1] << 12;
	/* data32 |= HW_OSD_BLOCK_ENABLE_0; */
	VSYNCOSD_WR_MPEG_REG(hw_osd_reg_array[OSD1].osd_ctrl_stat, data32);
	remove_from_update_list(OSD1, DISP_GEOMETRY);
}

static void osd2_update_disp_geometry(void)
{
	u32 data32;

	data32 = (osd_hw.dispdata[OSD2].x_start & 0xfff)
		| (osd_hw.dispdata[OSD2].x_end & 0xfff) << 16;
	VSYNCOSD_WR_MPEG_REG
		(hw_osd_reg_array[OSD2].osd_blk0_cfg_w3, data32);
	if (osd_hw.scan_mode[OSD2] == SCAN_MODE_INTERLACE &&
	    osd_hw.dispdata[OSD2].y_start >= 0)
		data32 = (osd_hw.dispdata[OSD2].y_start & 0xfff)
			| ((((osd_hw.dispdata[OSD2].y_end + 1
			- osd_hw.dispdata[OSD2].y_start) >> 1)
			+ osd_hw.dispdata[OSD2].y_start - 1)
				& 0xfff) << 16;
	else
		data32 = (osd_hw.dispdata[OSD2].y_start & 0xfff)
			| (osd_hw.dispdata[OSD2].y_end & 0xfff) << 16;
	VSYNCOSD_WR_MPEG_REG
		(hw_osd_reg_array[OSD2].osd_blk0_cfg_w4, data32);
	if (osd_hw.scale[OSD2].h_enable || osd_hw.scale[OSD2].v_enable) {
#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR)
		data32 = (osd_hw.pandata[OSD2].x_start & 0x1fff)
			| (osd_hw.pandata[OSD2].x_end & 0x1fff) << 16;
		VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_array[OSD2].osd_blk0_cfg_w1, data32);
		data32 = (osd_hw.pandata[OSD2].y_start & 0x1fff)
			| (osd_hw.pandata[OSD2].y_end & 0x1fff) << 16;
		VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_array[OSD2].osd_blk0_cfg_w2, data32);
#else
		data32 = (osd_hw.scaledata[OSD2].x_start & 0x1fff) |
			 (osd_hw.scaledata[OSD2].x_end & 0x1fff) << 16;
		VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_array[OSD2].osd_blk0_cfg_w1, data32);
		data32 = ((osd_hw.scaledata[OSD2].y_start
				+ osd_hw.pandata[OSD2].y_start) & 0x1fff)
			 | ((osd_hw.scaledata[OSD2].y_end
				+ osd_hw.pandata[OSD2].y_start) & 0x1fff) << 16;
		VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_array[OSD2].osd_blk0_cfg_w2, data32);
#endif
	} else if (osd_hw.free_scale_enable[OSD2] &&
		   (osd_hw.free_src_data[OSD2].x_end > 0) &&
		   (osd_hw.free_src_data[OSD2].y_end > 0)) {
		/* enable osd free scale */
		data32 = (osd_hw.free_src_data[OSD2].x_start & 0x1fff)
			| (osd_hw.free_src_data[OSD2].x_end & 0x1fff) << 16;
		VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_array[OSD2].osd_blk0_cfg_w1, data32);
		data32 = ((osd_hw.free_src_data[OSD2].y_start
			+ osd_hw.pandata[OSD2].y_start) & 0x1fff)
			| ((osd_hw.free_src_data[OSD2].y_end
			+ osd_hw.pandata[OSD2].y_start) & 0x1fff) << 16;
		VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_array[OSD2].osd_blk0_cfg_w2, data32);
	} else {
		data32 = (osd_hw.pandata[OSD2].x_start & 0x1fff)
			| (osd_hw.pandata[OSD2].x_end & 0x1fff) << 16;
		VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_array[OSD2].osd_blk0_cfg_w1, data32);
		data32 = (osd_hw.pandata[OSD2].y_start & 0x1fff)
			| (osd_hw.pandata[OSD2].y_end & 0x1fff) << 16;
		VSYNCOSD_WR_MPEG_REG
			(hw_osd_reg_array[OSD2].osd_blk0_cfg_w2, data32);
	}
	data32 = VSYNCOSD_RD_MPEG_REG
		(hw_osd_reg_array[OSD2].osd_ctrl_stat);
	data32 &= ~0x1ff000;
	data32 |= osd_hw.gbl_alpha[OSD2] << 12;
	/* data32 |= HW_OSD_BLOCK_ENABLE_0; */
	VSYNCOSD_WR_MPEG_REG
		(hw_osd_reg_array[OSD2].osd_ctrl_stat, data32);
	remove_from_update_list(OSD2, DISP_GEOMETRY);
}

static void osd_update_disp_geometry(u32 index)
{
	if (osd_hw.block_mode[index] &&
	    osd_hw.osd_meson_dev.cpu_id <= __MESON_CPU_MAJOR_ID_GXBB) {
		osd_log_info("%s: not support block mode\n", __func__);
	} else {
		if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL &&
			osd_dev_hw.display_type != C3_DISPLAY) {
			/* single block */
			if (index == OSD1)
				osd1_basic_update_disp_geometry();
			else if (index == OSD2)
				osd2_update_disp_geometry();
		} else {
			osd_basic_update_disp_geometry(index);
		}
	}
}

static void osd_update_disp_3d_mode(u32 index)
{
	/*step 1 . set pan data */
	/* only called by vsync irq or rdma irq */
	u32  data32;

	if (osd_hw.mode_3d[index].left_right == OSD_LEFT) {
		data32 = (osd_hw.mode_3d[index].l_start & 0x1fff)
			| (osd_hw.mode_3d[index].l_end & 0x1fff) << 16;
		VSYNCOSD_IRQ_WR_MPEG_REG
			(hw_osd_reg_array[index].osd_blk0_cfg_w1, data32);
	} else {
		data32 = (osd_hw.mode_3d[index].r_start & 0x1fff)
			| (osd_hw.mode_3d[index].r_end & 0x1fff) << 16;
		VSYNCOSD_IRQ_WR_MPEG_REG
			(hw_osd_reg_array[index].osd_blk0_cfg_w1, data32);
	}
	osd_hw.mode_3d[index].left_right ^= 1;
}

static void osd_update_fifo(u32 index)
{
	u32 data32;
	u32 output_index = get_output_device_id(index);

	data32 = osd_hw.osd_rdma_func[output_index].osd_rdma_rd
			(hw_osd_reg_array[index].osd_fifo_ctrl_stat);
	data32 |= osd_hw.urgent[index] & 1;
	osd_hw.osd_rdma_func[output_index].osd_rdma_wr
		(hw_osd_reg_array[index].osd_fifo_ctrl_stat, data32);
	remove_from_update_list(index, OSD_FIFO);
}

void osd_init_scan_mode(void)
{
	unsigned int output_type = 0;

	output_type = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) & 0x3;
	osd_hw.scan_mode[OSD1] = SCAN_MODE_PROGRESSIVE;
	osd_hw.scan_mode[OSD2] = SCAN_MODE_PROGRESSIVE;
	osd_hw.scan_mode[OSD3] = SCAN_MODE_PROGRESSIVE;
	switch (output_type) {
	case VOUT_ENCP:
		if (osd_reg_read(ENCP_VIDEO_MODE) & (1 << 12)) {
			/* 1080i */
			osd_hw.scan_mode[OSD1] = SCAN_MODE_INTERLACE;
			osd_hw.scan_mode[OSD2] = SCAN_MODE_INTERLACE;
			osd_hw.scan_mode[OSD3] = SCAN_MODE_INTERLACE;
		}
		break;
	case VOUT_ENCI:
		if (osd_reg_read(ENCI_VIDEO_EN) & 1) {
			osd_hw.scan_mode[OSD1] = SCAN_MODE_INTERLACE;
			osd_hw.scan_mode[OSD2] = SCAN_MODE_INTERLACE;
			osd_hw.scan_mode[OSD3] = SCAN_MODE_INTERLACE;
		}
		break;
	}
}

static int osd_extra_canvas_alloc(void)
{
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
	int osd_num = 2;
#endif

	osd_extra_idx[0][0] = EXTERN1_CANVAS;
	osd_extra_idx[0][1] = EXTERN2_CANVAS;
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
	osd_num = (osd_hw.osd_meson_dev.osd_count - 1) * 2;
	if (canvas_pool_alloc_canvas_table("osd_extra",
					   &osd_extra_idx[1][0],
					   osd_num,
					   CANVAS_MAP_TYPE_1)) {
		osd_log_info("allocate osd extra canvas error.\n");
		return -1;
	}
#endif
	return 0;
}

#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
/* kthread affinity set api */
static void affinity_set(unsigned long mask)
{
	int i;

	for (i = 0; i < VIU_COUNT; i++) {
		if (buffer_toggle_thread[i])
			set_cpus_allowed_ptr(buffer_toggle_thread[i],
					     (struct cpumask *)&mask);
	}
}

static int affinity_set_task(void *data)
{
	int ret;
	struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};

	sched_setscheduler(current, SCHED_FIFO, &param);
	allow_signal(SIGTERM);

	while (affinity_info.run_affinity_task) {
		ret = wait_for_completion_interruptible
			(&affinity_info.affinity_task_com);
		msleep(200);
		affinity_set(affinity_info.affinity_mask);
	}

	return 0;
}

#ifdef CPU_NOTIFY
static int cpu_switch_cb(struct notifier_block *nfb,
			 unsigned long action, void *hcpu)
{
	int cpu;
	static int cpu_down_save;
	unsigned long _cpu_mask = *cpumask_bits(&affinity_info.cpu_mask);

	if (action == CPU_POST_DEAD) {
		/* cpu core offline */
		cpu = (unsigned long)hcpu;
		cpu_down_save |= (1 << cpu);
		if (cpu_down_save == (_cpu_mask & (~1))) {
			/* other cpu all off, except cpu0 */
			affinity_info.affinity_mask = 1;
			complete(&affinity_info.affinity_task_com);
		}
	} else if (action == CPU_ONLINE) {
		/* cpu core online */
		cpu = (unsigned long)hcpu;
		cpu_down_save &= ~(1 << cpu);
		if (cpu_down_save != (_cpu_mask & (~1))) {
			affinity_info.affinity_mask = _cpu_mask & (~1);
			complete(&affinity_info.affinity_task_com);
		}
	}
	return 0;
}
#endif

static void affinity_set_init(void)
{
	struct task_struct *affinity_thread;

	affinity_info.cpu_mask = *cpu_online_mask;
	init_completion(&affinity_info.affinity_task_com);
	affinity_info.run_affinity_task = 1;
	/* cpu_notifier(cpu_switch_cb, 0); */
	affinity_thread = kthread_run(affinity_set_task,
				      &affinity_info,
				      "affinity_set_thread");
	if (!affinity_thread)
		pr_err("create affinity thread fail!\n");
}
#endif

static void set_vpp_osd1_rgb2yuv(bool on)
{
	int *m = NULL;

	/* RGB -> 709 limit */
	m = RGB709_to_YUV709l_coeff;

	/* VPP WRAP OSD3 matrix */
	osd_reg_write(VPP_OSD1_MATRIX_PRE_OFFSET0_1,
		      ((m[0] & 0xfff) << 16) | (m[1] & 0xfff));
	osd_reg_write(VPP_OSD1_MATRIX_PRE_OFFSET2,
		      m[2] & 0xfff);
	osd_reg_write(VPP_OSD1_MATRIX_COEF00_01,
		      ((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff));
	osd_reg_write(VPP_OSD1_MATRIX_COEF02_10,
		      ((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff));
	osd_reg_write(VPP_OSD1_MATRIX_COEF11_12,
		      ((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff));
	osd_reg_write(VPP_OSD1_MATRIX_COEF20_21,
		      ((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff));
	osd_reg_write(VPP_OSD1_MATRIX_COEF22,
		      m[11] & 0x1fff);
	osd_reg_write(VPP_OSD1_MATRIX_OFFSET0_1,
		      ((m[18] & 0xfff) << 16) | (m[19] & 0xfff));
	osd_reg_write(VPP_OSD1_MATRIX_OFFSET2,
		      m[20] & 0xfff);
	osd_reg_set_bits(VPP_OSD1_MATRIX_EN_CTRL, on, 0, 1);
}

static void set_vpp_osd2_rgb2yuv(bool on)
{
	int *m = NULL;

	/* RGB -> 709 limit */
	m = RGB709_to_YUV709l_coeff;

	/* VPP WRAP OSD3 matrix */
	osd_reg_write(VPP_OSD2_MATRIX_PRE_OFFSET0_1,
		      ((m[0] & 0xfff) << 16) | (m[1] & 0xfff));
	osd_reg_write(VPP_OSD2_MATRIX_PRE_OFFSET2,
		      m[2] & 0xfff);
	osd_reg_write(VPP_OSD2_MATRIX_COEF00_01,
		      ((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff));
	osd_reg_write(VPP_OSD2_MATRIX_COEF02_10,
		      ((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff));
	osd_reg_write(VPP_OSD2_MATRIX_COEF11_12,
		      ((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff));
	osd_reg_write(VPP_OSD2_MATRIX_COEF20_21,
		      ((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff));
	osd_reg_write(VPP_OSD2_MATRIX_COEF22,
		      m[11] & 0x1fff);
	osd_reg_write(VPP_OSD2_MATRIX_OFFSET0_1,
		      ((m[18] & 0xfff) << 16) | (m[19] & 0xfff));
	osd_reg_write(VPP_OSD2_MATRIX_OFFSET2,
		      m[20] & 0xfff);
	osd_reg_set_bits(VPP_OSD2_MATRIX_EN_CTRL, on, 0, 1);
}

static void fix_vpu_clk2_default_regs(void)
{
	/* t7 eco default setting */
	if (osd_hw.osd_meson_dev.cpu_id == __MESON_CPU_MAJOR_ID_T7) {
		 /* default: osd byp osd_blend */
		osd_mali_afbcd_top_ctrl =
			osd_reg_read(MALI_AFBCD_TOP_CTRL) & osd_mali_afbcd_top_ctrl_mask;
		osd_mali_afbcd_top_ctrl |= 1 << 19;
		osd_mali_afbcd_top_ctrl &= ~(1 << 15);
		osd_mali_afbcd_top_ctrl &= ~(1 << 20);
		osd_mali_afbcd1_top_ctrl =
			osd_reg_read(MALI_AFBCD1_TOP_CTRL) & osd_mali_afbcd1_top_ctrl_mask;
		osd_mali_afbcd1_top_ctrl &= ~(1 << 20);
		notify_to_amdv();

		osd_reg_set_bits(VPP_OSD1_SCALE_CTRL, 0x2, 0, 3);
		osd_reg_set_bits(VPP_OSD2_SCALE_CTRL, 0x3, 0, 3);
		osd_reg_set_bits(VPP_OSD3_SCALE_CTRL, 0x3, 0, 3);
		osd_reg_set_bits(VPP_OSD4_SCALE_CTRL, 0x3, 0, 3);

		/* default: osd byp dolby */
		osd_reg_set_bits(VPP_VD1_DSC_CTRL, 0x1, 4, 1);
		osd_reg_set_bits(VPP_VD2_DSC_CTRL, 0x1, 4, 1);
		osd_reg_set_bits(VPP_VD3_DSC_CTRL, 0x1, 4, 1);
		/* move the control into uboot for osd dolby vision */
		/* osd_reg_set_bits(MALI_AFBCD_TOP_CTRL, 0x1, 14, 1); */
		osd_reg_set_bits(MALI_AFBCD_TOP_CTRL, 0x1, 19, 1);
		/* osd_reg_set_bits(MALI_AFBCD1_TOP_CTRL, 0x1, 19, 1); */
		osd_reg_set_bits(MALI_AFBCD2_TOP_CTRL, 0x1, 19, 1);

		/* default: osd 12bit path */
		osd_reg_set_bits(VPP_VD1_DSC_CTRL, 0x0, 5, 1);
		osd_reg_set_bits(VPP_VD2_DSC_CTRL, 0x0, 5, 1);
		osd_reg_set_bits(VPP_VD3_DSC_CTRL, 0x0, 5, 1);
		osd_reg_set_bits(MALI_AFBCD_TOP_CTRL, 0x0, 15, 1);
		osd_reg_set_bits(MALI_AFBCD_TOP_CTRL, 0x0, 20, 1);
		osd_reg_set_bits(MALI_AFBCD1_TOP_CTRL, 0x0, 20, 1);
		osd_reg_set_bits(MALI_AFBCD2_TOP_CTRL, 0x0, 20, 1);
	}
}

static void independ_path_default_regs(void)
{
	/* default: osd1_bld_din_sel -- do not osd_data_byp osd_blend */
	osd_reg_set_bits(VIU_OSD1_PATH_CTRL, 0x0, 4, 1);
	osd_reg_set_bits(VIU_OSD2_PATH_CTRL, 0x0, 4, 1);
	osd_reg_set_bits(VIU_OSD3_PATH_CTRL, 0x0, 4, 1);

	/* default: osd1_sc_path_sel -- before osd_blend or after hdr */
	osd_reg_set_bits(VIU_OSD1_PATH_CTRL, 0x0, 0, 1);
	osd_reg_set_bits(VIU_OSD2_PATH_CTRL, 0x1, 0, 1);
	osd_reg_set_bits(VIU_OSD3_PATH_CTRL, 0x1, 0, 1);

	/* default: osd byp dolby */
	osd_reg_set_bits(VIU_VD1_PATH_CTRL, 0x1, 16, 1);
	osd_reg_set_bits(VIU_VD2_PATH_CTRL, 0x1, 16, 1);
	osd_reg_set_bits(VIU_OSD1_PATH_CTRL, 0x1, 16, 1);
	osd_reg_set_bits(VIU_OSD2_PATH_CTRL, 0x1, 16, 1);
	osd_reg_set_bits(VIU_OSD3_PATH_CTRL, 0x1, 16, 1);

	/* default: osd 12bit path */
	osd_reg_set_bits(VIU_VD1_PATH_CTRL, 0x0, 17, 1);
	osd_reg_set_bits(VIU_VD2_PATH_CTRL, 0x0, 17, 1);
	osd_reg_set_bits(VIU_OSD1_PATH_CTRL, 0x0, 17, 1);
	osd_reg_set_bits(VIU_OSD2_PATH_CTRL, 0x0, 17, 1);
	osd_reg_set_bits(VIU_OSD3_PATH_CTRL, 0x0, 17, 1);
}

static void s5_clk_default_regs(void)
{
	/* default: osd byp dolby */
	osd_reg_set_bits(OSD_DOLBY_BYPASS_EN, 0x1, 0, 1);
	osd_reg_set_bits(OSD_DOLBY_BYPASS_EN, 0x1, 2, 1);
	osd_reg_set_bits(OSD_DOLBY_BYPASS_EN, 0x1, 4, 1);
	osd_reg_set_bits(OSD_DOLBY_BYPASS_EN, 0x1, 6, 1);

	/* default: osd 12bit path */
	osd_reg_set_bits(VIU_OSD1_MISC, 1, 17, 1);
	osd_reg_set_bits(VIU_OSD2_MISC, 1, 17, 1);
	osd_reg_set_bits(VIU_OSD3_MISC, 1, 17, 1);
	osd_reg_set_bits(VIU_OSD4_MISC, 1, 17, 1);
	osd_reg_set_bits(OSD_DOLBY_BYPASS_EN, 0x0, 1, 1);
	osd_reg_set_bits(OSD_DOLBY_BYPASS_EN, 0x0, 3, 1);
	osd_reg_set_bits(OSD_DOLBY_BYPASS_EN, 0x0, 5, 1);
	osd_reg_set_bits(OSD_DOLBY_BYPASS_EN, 0x0, 7, 1);
}

static void s5_default_path_settings(void)
{
	/* 2mux1, 0:use mali/mif 1:video */
	osd_reg_set_bits(VPP_INTF_OSD3_CTRL, 0, 1, 1);

	/* 1mux3, OSD1 & OSD3 -> osd_blend */
	osd_reg_write(OSD_PROC_1MUX3_SEL, 2 << 0 | 2 << 2 | 2 << 4);

	/* disable PI */
	osd_reg_set_bits(OSD_PI_BYPASS_EN, 1, 0, 1);
	/* select din1 */
	osd_reg_set_bits(OSD_SYS_5MUX4_SEL, 1, 0, 20);
}

static void multi_afbc_default_path_setting(void)
{
	if (osd_dev_hw.s5_display)
		s5_clk_default_regs();
	else if (osd_dev_hw.path_ctrl_independ)
		independ_path_default_regs();
	else
		fix_vpu_clk2_default_regs();
}

static void osd_set_vpp_path_default(u32 osd_index, u32 vpp_index)
{
	if (osd_dev_hw.has_multi_vpp) {
		/* osd_index is vpp mux input */
		/* default setting osdx route to vpp0 vsync */
		switch (osd_index) {
		case VPP_OSD1:
			osd_reg_set_bits(PATH_START_SEL,
					vpp_index, 16, 2);
			break;
		case VPP_OSD2:
			osd_reg_set_bits(PATH_START_SEL,
					vpp_index, 20, 2);
			break;
		case VPP_OSD3:
			osd_reg_set_bits(PATH_START_SEL,
					vpp_index, 24, 2);
			break;
		case VPP_OSD4:
			osd_reg_set_bits(PATH_START_SEL,
					vpp_index, 28, 2);
			break;
		}
	}
}

static void set_rdma_func_handler(void)
{
	int viu1 = VIU1;
	int viu2 = VIU2;
	int viu3 = VIU3;

	if (osd_dev_hw.display_type != C3_DISPLAY) {
		if (is_keystone_enable_for_txhd2()) {
			viu1 = VIU2;
			viu2 = VIU1;
		}
		osd_hw.osd_rdma_func[viu1].osd_rdma_rd =
			VSYNCOSD_RD_MPEG_REG;
		osd_hw.osd_rdma_func[viu1].osd_rdma_wr =
			VSYNCOSD_WR_MPEG_REG;
		osd_hw.osd_rdma_func[viu1].osd_rdma_wr_bits =
			VSYNCOSD_WR_MPEG_REG_BITS;
		osd_hw.osd_rdma_func[viu1].osd_rdma_set_mask =
			VSYNCOSD_SET_MPEG_REG_MASK;
		osd_hw.osd_rdma_func[viu1].osd_rdma_clr_mask =
			VSYNCOSD_CLR_MPEG_REG_MASK;
		osd_hw.osd_rdma_func[viu1].osd_rdma_wr_irq =
			VSYNCOSD_IRQ_WR_MPEG_REG;

		osd_hw.osd_rdma_func[viu2].osd_rdma_rd =
			VSYNCOSD_RD_MPEG_REG_VPP1;
		osd_hw.osd_rdma_func[viu2].osd_rdma_wr =
			VSYNCOSD_WR_MPEG_REG_VPP1;
		osd_hw.osd_rdma_func[viu2].osd_rdma_wr_bits =
			VSYNCOSD_WR_MPEG_REG_BITS_VPP1;
		osd_hw.osd_rdma_func[viu2].osd_rdma_set_mask =
			VSYNCOSD_SET_MPEG_REG_MASK_VPP1;
		osd_hw.osd_rdma_func[viu2].osd_rdma_clr_mask =
			VSYNCOSD_CLR_MPEG_REG_MASK_VPP1;
		osd_hw.osd_rdma_func[viu2].osd_rdma_wr_irq =
			VSYNCOSD_IRQ_WR_MPEG_REG_VPP1;

		osd_hw.osd_rdma_func[viu3].osd_rdma_rd =
			VSYNCOSD_RD_MPEG_REG_VPP2;
		osd_hw.osd_rdma_func[viu3].osd_rdma_wr =
			VSYNCOSD_WR_MPEG_REG_VPP2;
		osd_hw.osd_rdma_func[viu3].osd_rdma_wr_bits =
			VSYNCOSD_WR_MPEG_REG_BITS_VPP2;
		osd_hw.osd_rdma_func[viu3].osd_rdma_set_mask =
			VSYNCOSD_SET_MPEG_REG_MASK_VPP2;
		osd_hw.osd_rdma_func[viu3].osd_rdma_clr_mask =
			VSYNCOSD_CLR_MPEG_REG_MASK_VPP2;
		osd_hw.osd_rdma_func[viu3].osd_rdma_wr_irq =
			VSYNCOSD_IRQ_WR_MPEG_REG_VPP2;
	} else {
		osd_hw.osd_rdma_func[viu1].osd_rdma_rd =
			osd_reg_read;
		osd_hw.osd_rdma_func[viu1].osd_rdma_wr =
			osd_reg_write;
		osd_hw.osd_rdma_func[viu1].osd_rdma_wr_bits =
			osd_reg_set_bits;
		osd_hw.osd_rdma_func[viu1].osd_rdma_set_mask =
			osd_reg_set_mask;
		osd_hw.osd_rdma_func[viu1].osd_rdma_clr_mask =
			osd_reg_clr_mask;
		osd_hw.osd_rdma_func[viu1].osd_rdma_wr_irq =
			osd_reg_write;
	}

}

#ifdef DEBUG_FIRSTFRAME
static void set_force_dimm(u32 index)
{
	osd_hw.force_dimm[index] = 1;
	osd_hw.dim_color[index] = 0x555555ff;
}

static void set_force_save_frames(u32 index)
{
	osd_hw.force_save_frame = 1;
	osd_hw.save_frame_number[index] = 5;
}
#endif

static void osd_unsupport_flag_init(void)
{
	u32 osd_count = osd_hw.osd_meson_dev.osd_count, i;
	u32 *start_reg = NULL, reg_num, flag_reg, cnt = 0;

	if (osd_dev_hw.s5_display)
		flag_reg = S5_VIU_OSD2_TCOLOR_AG3;
	else
		flag_reg = VIU_OSD2_TCOLOR_AG3;

	reg_num = sizeof(struct hw_osd_reg_s) / sizeof(u32);
	start_reg = (u32 *)&hw_osd_reg_array[0];
	for (i = 0; i < osd_count * reg_num; i++) {
		if (*(start_reg + i) == OSD_REG_UNSUPPORT) {
			*(start_reg + i) = flag_reg;
			cnt++;
		}
	}
	osd_log_dbg(MODULE_BASE, "init osd unsupported reg count:%d\n", cnt);

	cnt = 0;
	reg_num = sizeof(struct osd_blend_reg_s) / sizeof(u32);
	start_reg = (u32 *)&hw_osd_reg_blend;
	for (i = 0; i < reg_num; i++) {
		if (*(start_reg + i) == OSD_REG_UNSUPPORT) {
			*(start_reg + i) = flag_reg;
			cnt++;
		}
	}
	osd_log_dbg(MODULE_BASE, "init blend unsupported reg count:%d\n", cnt);
}

static void osd_flag_regs_init(void)
{
	osd_unsupport_flag_init();
	osd_rdma_flag_init();
}

void osd_init_hw(u32 logo_loaded, u32 osd_probe,
		 struct osd_device_data_s *osd_meson)
{
	u32 idx, data32;
	int err_num = 0;
#ifdef CONFIG_AMLOGIC_MEDIA_SECURITY
	void *osd_secure_op[VPP_TOP_MAX] = {VSYNCOSD_WR_MPEG_REG_BITS,
					    VSYNCOSD_WR_MPEG_REG_BITS_VPP1,
					    VSYNCOSD_WR_MPEG_REG_BITS_VPP2};
#endif
#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
	int i = 0;

	for (i = 0 ; i < HW_OSD_COUNT; i++)
		displayed_bufs[i] = NULL;
#endif

	osd_hw.fb_drvier_probe = osd_probe;
	osd_hw.vpp_num = 1;

	memcpy(&osd_hw.osd_meson_dev, osd_meson,
	       sizeof(struct osd_device_data_s));
	if (osd_hw.osd_meson_dev.has_vpp1)
		osd_hw.vpp_num++;
	if (osd_hw.osd_meson_dev.has_vpp2)
		osd_hw.vpp_num++;
	osd_vpu_power_on();

	if (osd_meson->cpu_id == __MESON_CPU_MAJOR_ID_S5 ||
	    osd_meson->cpu_id == __MESON_CPU_MAJOR_ID_T3X)
		memcpy(&hw_osd_reg_blend, &hw_osd_blend_reg_s5,
		       sizeof(struct hw_osd_blend_reg_s));
	else
		memcpy(&hw_osd_reg_blend, &hw_osd_blend_reg_legacy,
		       sizeof(struct hw_osd_blend_reg_s));

	if (osd_hw.osd_meson_dev.has_slice2ppc)
		memcpy(&hw_osd_reg_slice2ppc, &hw_osd_slice2ppc_reg,
		       sizeof(struct hw_osd_slice2ppc_reg_s));

	if (osd_meson->osd_count == 3 &&
	    osd_meson->has_viu2) {
		/* VIU1 2 OSD + 1 VIU2 1 OSD*/
		memcpy(&hw_osd_reg_array[0], &hw_osd_reg_array_tl1[0],
		       sizeof(struct hw_osd_reg_s) *
		       osd_hw.osd_meson_dev.osd_count);
	} else if (osd_meson->cpu_id == __MESON_CPU_MAJOR_ID_T7) {
		/* 4 or 3 OSD, multi_afbc_core */
		memcpy(&hw_osd_reg_array[0], &hw_osd_reg_array_t7[0],
		       sizeof(struct hw_osd_reg_s) *
		       osd_hw.osd_meson_dev.osd_count);
	} else if (osd_meson->cpu_id == __MESON_CPU_MAJOR_ID_T3 ||
		   osd_meson->cpu_id == __MESON_CPU_MAJOR_ID_T5W ||
		   osd_meson->cpu_id == __MESON_CPU_MAJOR_ID_T5M) {
		/* 4 or 3 OSD, multi_afbc_core */
		memcpy(&hw_osd_reg_array[0], &hw_osd_reg_array_t3[0],
		       sizeof(struct hw_osd_reg_s) *
		       osd_hw.osd_meson_dev.osd_count);
	} else if (osd_meson->cpu_id == __MESON_CPU_MAJOR_ID_C3) {
		/* one osd, no afbc, no osd blend */
		memcpy(&hw_osd_reg_array[0], &hw_osd_reg_array_c3[0],
			   sizeof(struct hw_osd_reg_s) *
			   osd_hw.osd_meson_dev.osd_count);
	} else if (osd_meson->cpu_id == __MESON_CPU_MAJOR_ID_S5) {
		/* 2 OSD (OSD1 + OSD3), multi_afbc_core */
		memcpy(&hw_osd_reg_array[0], &hw_osd_reg_array_s5[0],
		       sizeof(struct hw_osd_reg_s) *
			   osd_hw.osd_meson_dev.osd_count);
	} else if (osd_meson->cpu_id == __MESON_CPU_MAJOR_ID_T3X) {
		/* 3 OSD, multi_afbc_core */
		memcpy(&hw_osd_reg_array[0], &hw_osd_reg_array_t3x[0],
		       sizeof(struct hw_osd_reg_s) *
		       osd_hw.osd_meson_dev.osd_count);
	} else {
		/* VIU1 3 OSD + 1 VIU2 1 OSD or VIU1 2 OSD*/
		memcpy(&hw_osd_reg_array[0], &hw_osd_reg_array_g12a[0],
		       sizeof(struct hw_osd_reg_s) *
		       osd_hw.osd_meson_dev.osd_count);
	}
	if (osd_dev_hw.display_type == T7_DISPLAY ||
		osd_dev_hw.s5_display) {
		if (osd_meson->cpu_id >= __MESON_CPU_MAJOR_ID_T3X) {
			memcpy(&venc_regs[0], &venc_regs_t3x[0],
				sizeof(struct vpu_venc_regs) * 3);
		} else {
			memcpy(&venc_regs[0], &venc_regs_t7[0],
				sizeof(struct vpu_venc_regs) * 3);
		}
	}
	if (osd_meson->cpu_id == __MESON_CPU_MAJOR_ID_GXTVBB) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
		backup_regs_init(HW_RESET_AFBCD_REGS);
#endif
	} else if (osd_meson->cpu_id == __MESON_CPU_MAJOR_ID_GXM) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
		backup_regs_init(HW_RESET_OSD1_REGS);
#endif
	} else if ((osd_meson->cpu_id >= __MESON_CPU_MAJOR_ID_GXL) &&
		 osd_meson->cpu_id <= __MESON_CPU_MAJOR_ID_TXL) {
#ifndef CONFIG_AMLOGIC_REMOVE_OLD
		backup_regs_init(HW_RESET_OSD1_REGS);
#endif
	} else if (osd_meson->cpu_id >= __MESON_CPU_MAJOR_ID_G12A) {
		if (osd_dev_hw.display_type != C3_DISPLAY) {
			if (osd_dev_hw.multi_afbc_core) {
				backup_regs_init(HW_RESET_NONE);
			} else {
				if (osd_meson->afbc_type == NO_AFBC)
					backup_regs_init(HW_RESET_NONE);
				else
					backup_regs_init(HW_RESET_MALI_AFBCD_REGS);
			}
		}
	} else {
		backup_regs_init(HW_RESET_NONE);
	}

	/*for c3 irq clr*/
	if (osd_dev_hw.display_type == C3_DISPLAY)
		irq_clr_c3();

	osd_flag_regs_init();
	recovery_regs_init();

	/* set osd vpp rdma func */
	set_rdma_func_handler();
	for (idx = 0; idx < HW_REG_INDEX_MAX; idx++)
		osd_hw.reg[idx].update_func =
		hw_func_array[idx];

#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM
	osd_hdr_on = false;
#endif
	osd_hw.hw_reset_flag = HW_RESET_NONE;
	osd_hw.hwc_enable[VIU1] = 0;
	osd_hw.hwc_enable[VIU2] = 0;
	if (osd_hw.osd_meson_dev.osd_ver == OSD_NORMAL) {
		osd_hw.hw_cursor_en = 1;
	} else if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE) {
		osd_hw.hw_cursor_en = 0;
		/* g12a and g12b need delay */
		supsend_delay = 50;
	}
	if (osd_hw.osd_meson_dev.has_rdma)
		osd_hw.hw_rdma_en = 1;
	/*close gamma only for axg*/
	if (osd_hw.osd_meson_dev.osd_ver == OSD_SIMPLE)
		osd_reg_write(L_GAMMA_CNTL_PORT, 0);

	/* here we will init default value ,these value only set once . */
	if (!logo_loaded) {
		if (osd_dev_hw.s5_display)
			s5_default_path_settings();

		if (osd_dev_hw.multi_afbc_core)
			multi_afbc_default_path_setting();

		/* init vpu fifo control register */
		if (osd_dev_hw.display_type != C3_DISPLAY) {
			data32 = osd_reg_read(VPP_OFIFO_SIZE);
			if (osd_hw.osd_meson_dev.osd_ver >= OSD_HIGH_ONE) {
				data32 &= ~((0xfff << 20) | 0x3fff);
				data32 |= (osd_hw.osd_meson_dev.vpp_fifo_len) << 20;
				data32 |= osd_hw.osd_meson_dev.vpp_fifo_len + 1;
			} else {
				data32 |= osd_hw.osd_meson_dev.vpp_fifo_len;
			}
			osd_reg_write(VPP_OFIFO_SIZE, data32);
			data32 = 0x08080808;
			osd_reg_write(VPP_HOLD_LINES, data32);
		}
		/* init osd fifo control register
		 * set DDR request priority to be urgent
		 */
		data32 = 1;
		/* hold_fifo_lines */
		if (osd_hw.osd_meson_dev.osd_ver >= OSD_HIGH_ONE)
			data32 |= VIU1_DEFAULT_HOLD_LINE << 5;
		else
			data32 |= MIN_HOLD_LINE << 5;
		/* burst_len_sel: 3=64, g12a = 5 */
		if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE ||
			osd_dev_hw.display_type == C3_DISPLAY) {
			data32 |= 1 << 10;
			data32 |= 1 << 31;
		} else {
			data32 |= 3 << 10;
		}
		/*
		 * bit 23:22, fifo_ctrl
		 * 00 : for 1 word in 1 burst
		 * 01 : for 2 words in 1 burst
		 * 10 : for 4 words in 1 burst
		 * 11 : reserved
		 */
		data32 |= 2 << 22;
		/* bit 28:24, fifo_lim */
		data32 |= 2 << 24;

		/* data32_ = data32; */
		/* fifo_depth_val: 32 or 64 *8 = 256 or 512 */
		data32 |= (osd_hw.osd_meson_dev.osd_fifo_len
			& 0xfffffff) << 12;
		for (idx = 0; idx < osd_hw.osd_meson_dev.viu1_osd_count; idx++)
			osd_reg_write(hw_osd_reg_array[idx].osd_fifo_ctrl_stat,
				      data32);
		/* osd_reg_write(VIU_OSD2_FIFO_CTRL_STAT, data32_); */
		if (osd_dev_hw.display_type != C3_DISPLAY) {
			if (osd_hw.osd_meson_dev.cpu_id ==
				__MESON_CPU_MAJOR_ID_S1A)
				osd_reg_clr_mask(VPP_MISC, VPP_VD1_POSTBLEND);
			osd_reg_set_mask(VPP_MISC, VPP_POSTBLEND_EN);
			osd_reg_clr_mask(VPP_MISC, VPP_PREBLEND_EN);
			if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL) {
				osd_vpp_misc =
					osd_reg_read(VPP_MISC) & OSD_RELATIVE_BITS;
				osd_vpp_misc &=
					~(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND);

				notify_to_amvideo();
				osd_reg_clr_mask(VPP_MISC,
						 VPP_OSD1_POSTBLEND |
						 VPP_OSD2_POSTBLEND);
			}
		}
		/* just disable osd to avoid booting hang up */
		data32 = 0x1 << 0;
		data32 |= OSD_GLOBAL_ALPHA_DEF << 12;
		for (idx = 0; idx < osd_hw.osd_meson_dev.viu1_osd_count; idx++)
			osd_reg_write(hw_osd_reg_array[idx].osd_ctrl_stat,
				      data32);
		if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE)
			osd_setting_default_hwc();
	} else if (osd_hw.osd_meson_dev.cpu_id ==
			__MESON_CPU_MAJOR_ID_T7) {
		osd_mali_afbcd_top_ctrl =
			osd_reg_read(MALI_AFBCD_TOP_CTRL) & osd_mali_afbcd_top_ctrl_mask;
		osd_mali_afbcd_top_ctrl |= 1 << 19;
		osd_mali_afbcd_top_ctrl &= ~(1 << 15);
		osd_mali_afbcd_top_ctrl &= ~(1 << 20);
		osd_mali_afbcd1_top_ctrl =
			osd_reg_read(MALI_AFBCD1_TOP_CTRL) & osd_mali_afbcd1_top_ctrl_mask;
		osd_mali_afbcd1_top_ctrl &= ~(1 << 20);
		notify_to_amdv();
	}
	if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL &&
		osd_dev_hw.display_type != C3_DISPLAY) {
		osd_vpp_misc =
			osd_reg_read(VPP_MISC) & OSD_RELATIVE_BITS;
		if (osd_hw.hw_cursor_en) {
			osd_vpp_misc |= (VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2);
			notify_to_amvideo();
			osd_reg_set_mask(VPP_MISC,
					 VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2);
			osd_hw.order[OSD1] = OSD_ORDER_10;
		} else {
			osd_vpp_misc &= ~(VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2);
			notify_to_amvideo();
			osd_reg_clr_mask(VPP_MISC,
					 VPP_POST_FG_OSD2 |
					 VPP_PRE_FG_OSD2);
			osd_hw.order[OSD1] = OSD_ORDER_01;
		}
	} else if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE) {
		osd_hw.order[OSD1] = LAYER_1;
		osd_hw.order[OSD2] = LAYER_2;
		osd_hw.order[OSD3] = LAYER_3;
		for (idx = 0; idx < VIU_COUNT; idx++) {
			osd_hw.disp_info[idx].background_w = 1920;
			osd_hw.disp_info[idx].background_h = 1080;
			osd_hw.disp_info[idx].fullscreen_w = 1920;
			osd_hw.disp_info[idx].fullscreen_h = 1080;
			osd_hw.disp_info[idx].position_x = 0;
			osd_hw.disp_info[idx].position_y = 0;
			osd_hw.disp_info[idx].position_w = 1920;
			osd_hw.disp_info[idx].background_h = 1080;
			osd_hw.vinfo_width[idx] = 1920;
			osd_hw.vinfo_height[idx] = 1080;
		}
		if ((osd_hw.osd_meson_dev.cpu_id ==
			__MESON_CPU_MAJOR_ID_G12A) ||
			((osd_hw.osd_meson_dev.cpu_id ==
			__MESON_CPU_MAJOR_ID_G12B) &&
			is_meson_rev_a()))
			osd_hw.workaround_line = 1;
		for (idx = 0; idx < osd_hw.osd_meson_dev.osd_count; idx++) {
			osd_hw.premult_en[idx] = 0;
			osd_hw.osd_afbcd[idx].format = COLOR_INDEX_32_ABGR;
			osd_hw.osd_afbcd[idx].inter_format =
				MALI_AFBC_32X8_PIXEL << 1 |
				MALI_AFBC_SPLIT_ON;
			osd_hw.osd_afbcd[idx].afbc_start = 0;

			osd_hw.osd_afbcd[idx].out_addr_id = idx + 1;
			if (osd_hw.osd_meson_dev.cpu_id ==
				__MESON_CPU_MAJOR_ID_G12A) {
				osd_hw.afbc_force_reset = 1;
				osd_hw.afbc_regs_backup = 1;
			}

			if (idx < osd_hw.osd_meson_dev.viu1_osd_count) {
				/* TODO: temp set at here,
				 * need move it to uboot
				 */
				osd_reg_set_bits
				(hw_osd_reg_array[idx].osd_fifo_ctrl_stat,
				 1, 31, 1);
				osd_reg_set_bits
				(hw_osd_reg_array[idx].osd_fifo_ctrl_stat,
				 1, 10, 2);
				osd_reg_set_bits
				(hw_osd_reg_array[idx].osd_fifo_ctrl_stat,
				 VIU1_DEFAULT_HOLD_LINE, 5, 5);
				if (osd_hw.osd_meson_dev.cpu_id ==
					__MESON_CPU_MAJOR_ID_G12B)
					osd_reg_set_bits
					(hw_osd_reg_array[idx].osd_ctrl_stat,
					1, 0, 1);
				osd_reg_set_bits
				(hw_osd_reg_array[idx].osd_ctrl_stat,
				 0, 31, 1);
				osd_hw.powered[idx] = 1;
			} else {
				osd_hw.powered[idx] = 0;
			}
		}
		osd_set_basic_urgent(true);
		if (osd_hw.osd_meson_dev.cpu_id !=
			__MESON_CPU_MAJOR_ID_TXHD2 &&
			osd_hw.osd_meson_dev.cpu_id !=
			__MESON_CPU_MAJOR_ID_S1A )
			osd_set_two_ports(true);
		if (osd_dev_hw.prevsync_support) {
			u32 vpp0_pre_go_field = 0;
			u32 vpp0_post_go_field = 3;
			u32 output_index;

			/* for t3 0: vpp0_pre_go_field, 3: vpp0_post_go_field */
			if (is_meson_rev_a()) {
				osd_set_vpp_path_default(VPP_OSD1, vpp0_pre_go_field);
				osd_set_vpp_path_default(VPP_OSD2, vpp0_pre_go_field);
				if (osd_hw.osd_meson_dev.osd_count > OSD3) {
					output_index = get_output_device_id(OSD3);
					if (output_index == VIU1)
						osd_set_vpp_path_default(VPP_OSD3,
							vpp0_pre_go_field);
					else
						osd_set_vpp_path_default(VPP_OSD3,
							output_index);
				}
				if (osd_hw.osd_meson_dev.osd_count > OSD4) {
					output_index = get_output_device_id(OSD4);
					if (output_index == VIU1)
						osd_set_vpp_path_default(VPP_OSD4,
							vpp0_pre_go_field);
					else
						osd_set_vpp_path_default(VPP_OSD4,
							output_index);
				}
			} else {
				osd_set_vpp_path_default(VPP_OSD1, vpp0_post_go_field);
				osd_set_vpp_path_default(VPP_OSD2, vpp0_post_go_field);
				if (osd_hw.osd_meson_dev.osd_count > OSD3) {
					output_index = get_output_device_id(OSD3);
					if (output_index == VIU1)
						osd_set_vpp_path_default(VPP_OSD3,
							vpp0_post_go_field);
					else
						osd_set_vpp_path_default(VPP_OSD3,
							output_index);
				}
				if (osd_hw.osd_meson_dev.osd_count > OSD4) {
					output_index = get_output_device_id(OSD4);
					if (output_index == VIU1)
						osd_set_vpp_path_default(VPP_OSD4,
							vpp0_post_go_field);
					else
						osd_set_vpp_path_default(VPP_OSD4,
							output_index);
				}
			}
		} else {
			/* for t7 0: vpp0_post_go_field, no pre go field */
			if (osd_hw.osd_meson_dev.osd_count > OSD3)
				osd_set_vpp_path_default(VPP_OSD3,
							 get_output_device_id(OSD3));
			if (osd_hw.osd_meson_dev.osd_count > OSD4)
				osd_set_vpp_path_default(VPP_OSD4,
							 get_output_device_id(OSD4));
		}
	}
	/* disable deband as default */
	if (osd_hw.osd_meson_dev.has_deband) {
		if (osd_dev_hw.display_type != C3_DISPLAY)
			osd_reg_write(OSD_DB_FLT_CTRL, 0);
		else
			osd_reg_write(VOUT_OSD1_DB_FLT_CTRL, 0);
	}
	for (idx = 0; idx < osd_hw.osd_meson_dev.osd_count; idx++) {
		osd_hw.updated[idx] = 0;
		osd_hw.urgent[idx] = 1;
		osd_hw.enable[idx] = DISABLE;
		osd_hw.fb_gem[idx].xres = 0;
		osd_hw.fb_gem[idx].yres = 0;
		osd_hw.gbl_alpha[idx] = OSD_GLOBAL_ALPHA_DEF;
		osd_hw.color_info[idx] = NULL;
		osd_hw.color_backup[idx] = NULL;
		osd_hw.color_key[idx] = 0xffffffff;
		osd_hw.color_key_enable[idx] = 0;
		osd_hw.mode_3d[idx].enable = 0;
		osd_hw.block_mode[idx] = 0;
		osd_hw.osd_reverse[idx] = REVERSE_FALSE;
		osd_hw.free_scale_enable[idx] = 0;
		osd_hw.free_scale_enable_backup[idx] = 0;
		osd_hw.scale[idx].h_enable = 0;
		osd_hw.scale[idx].v_enable = 0;
		osd_hw.free_scale[idx].h_enable = 0;
		osd_hw.free_scale[idx].h_enable = 0;
		osd_hw.free_scale_backup[idx].h_enable = 0;
		osd_hw.free_scale_backup[idx].v_enable = 0;
		osd_hw.free_src_data[idx].x_start = 0;
		osd_hw.free_src_data[idx].x_end = 0;
		osd_hw.free_src_data[idx].y_start = 0;
		osd_hw.free_src_data[idx].y_end = 0;
		osd_hw.free_src_data_backup[idx].x_start = 0;
		osd_hw.free_src_data_backup[idx].x_end = 0;
		osd_hw.free_src_data_backup[idx].y_start = 0;
		osd_hw.free_src_data_backup[idx].y_end = 0;
		osd_hw.free_scale_mode[idx] = 0;
		osd_hw.buffer_alloc[idx] = 0;
		osd_hw.osd_afbcd[idx].enable = 0;
		osd_hw.osd_afbcd[idx].phy_addr = 0;
		osd_hw.use_h_filter_mode[idx] = -1;
		osd_hw.use_v_filter_mode[idx] = -1;
		osd_hw.premult_en[idx] = 0;
		osd_hw.afbc_err_cnt[idx] = 0;
		osd_hw.blend_bypass[idx] = 0;
		osd_hw.osd_deband_enable[idx] = 1;
		if (osd_dev_hw.remove_afbc == idx + 1)
			osd_hw.afbc_support[idx] = false;
		else
			osd_hw.afbc_support[idx] = true;
		if (osd_dev_hw.remove_pps == idx + 1)
			osd_hw.pps_support[idx] = false;
		else
			osd_hw.pps_support[idx] = true;
		/*
		 * osd_hw.rotation_pandata[idx].x_start = 0;
		 * osd_hw.rotation_pandata[idx].y_start = 0;
		 */
		osd_set_dummy_data(idx, 0xff);
		osd_set_deband(idx, osd_hw.osd_deband_enable[idx]);
		#ifdef DEBUG_FIRSTFRAME
		set_force_dimm(idx);
		set_force_save_frames(idx);
		#endif
	}
	/* hwc_enable == 0 handler */
#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
	osd_hw.osd_fence[VIU1][DISABLE].sync_fence_handler =
		sync_render_single_fence;
	osd_hw.osd_fence[VIU1][DISABLE].toggle_buffer_handler =
		osd_toggle_buffer_single;
	/* hwc_enable == 1 handler */
	osd_hw.osd_fence[VIU1][ENABLE].sync_fence_handler =
		sync_render_layers_fence;
	osd_hw.osd_fence[VIU1][ENABLE].toggle_buffer_handler =
		osd_toggle_buffer_layers;
	if (osd_hw.osd_meson_dev.has_viu2 || osd_hw.osd_meson_dev.has_vpp1) {
		osd_hw.osd_fence[VIU2][DISABLE].sync_fence_handler =
			sync_render_single_fence;
		osd_hw.osd_fence[VIU2][DISABLE].toggle_buffer_handler =
			osd_toggle_buffer_single_viu2;
		/* hwc_enable == 1 handler */
		osd_hw.osd_fence[VIU2][ENABLE].sync_fence_handler =
			sync_render_layers_fence;
		osd_hw.osd_fence[VIU2][ENABLE].toggle_buffer_handler =
			osd_toggle_buffer_layers_viu2;
	}
#endif
	osd_hw.fb_gem[OSD1].canvas_idx = OSD1_CANVAS_INDEX;
	osd_hw.fb_gem[OSD2].canvas_idx = OSD2_CANVAS_INDEX;
	if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE) {
		osd_hw.fb_gem[OSD3].canvas_idx = OSD3_CANVAS_INDEX;
		if (osd_hw.osd_meson_dev.osd_count == 4)
			osd_hw.fb_gem[OSD4].canvas_idx = OSD4_CANVAS_INDEX;
	}
	if (osd_hw.osd_meson_dev.osd_ver != OSD_SIMPLE &&
		osd_hw.osd_meson_dev.cpu_id != __MESON_CPU_MAJOR_ID_S1A)
		osd_extra_canvas_alloc();
	osd_hw.antiflicker_mode = 0;
	osd_hw.out_fence_fd[VIU1] = -1;
	osd_hw.out_fence_fd[VIU2] = -1;
	osd_hw.osd_preblend_en = 0;
	osd_hw.fix_target_width = 1920;
	osd_hw.fix_target_height = 1080;
	if (osd_hw.osd_meson_dev.cpu_id == __MESON_CPU_MAJOR_ID_AXG) {
		data32 = osd_reg_read
			(hw_osd_reg_array[OSD1].osd_fifo_ctrl_stat);
		/* bit[9:5]: HOLD_FIFO_LINES */
		data32 &= ~(0x1f << 5);
		data32 |= 0x18 << 5;
		osd_reg_write(hw_osd_reg_array[OSD1].osd_fifo_ctrl_stat,
			      data32);
	}
	if (osd_hw.osd_meson_dev.cpu_id == __MESON_CPU_MAJOR_ID_TXHD2 &&
		osd_hw.osd_meson_dev.has_vpp1) {
		set_vpp_osd1_rgb2yuv(1);
		set_vpp_osd2_rgb2yuv(0);
	} else if (osd_hw.osd_meson_dev.osd_rgb2yuv == 1) {
		set_vpp_osd1_rgb2yuv(1);
		set_vpp_osd2_rgb2yuv(1);
	}
	if (osd_hw.fb_drvier_probe) {
#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
		INIT_LIST_HEAD(&post_fence_list[VIU1]);
		mutex_init(&post_fence_list_lock[VIU1]);
		INIT_LIST_HEAD(&post_fence_list[VIU2]);
		mutex_init(&post_fence_list_lock[VIU2]);
#endif
#ifdef FIQ_VSYNC
		osd_hw.fiq_handle_item.handle = vsync_isr;
		osd_hw.fiq_handle_item.key = (u32)vsync_isr;
		osd_hw.fiq_handle_item.name = "osd_vsync";
		if (register_fiq_bridge_handle(&osd_hw.fiq_handle_item))
			osd_log_err("can't request irq for vsync,err_num=%d\n",
				    -err_num);
#else
		err_num = request_irq(int_viu_vsync, &vsync_isr,
				      IRQF_SHARED, "osd-vsync", osd_setup_hw);
		if (err_num)
			osd_log_err("can't request irq for vsync,err_num=%d\n",
				    -err_num);
		if (osd_hw.osd_meson_dev.has_viu2 || osd_hw.osd_meson_dev.has_vpp1) {
			err_num = request_irq(int_viu2_vsync, &vsync_viu2_isr,
					      IRQF_SHARED,
					      "osd-vsync-viu2", osd_setup_hw);
			if (err_num)
				osd_log_err("can't request irq for viu2 vsync,err_num=%d\n",
					    -err_num);
		}
		if (osd_hw.osd_meson_dev.has_vpp2) {
			err_num = request_irq(int_viu3_vsync, &vsync_viu3_isr,
					      IRQF_SHARED,
					      "osd-vsync-viu3", osd_setup_hw);
			if (err_num)
				osd_log_err("can't request irq for viu3 vsync,err_num=%d\n",
					    -err_num);
		}
#endif
#ifdef FIQ_VSYNC
		request_fiq(INT_VIU_VSYNC, &osd_fiq_isr);
		if (osd_hw.osd_meson_dev.has_viu2)
			request_fiq(INT_VIU_VSYNC, &osd_viu2_fiq_isr);
#endif
	}
	if (osd_hw.hw_rdma_en) {
		osd_rdma_enable(VPU_VPP0, 2);
		if (osd_hw.osd_meson_dev.has_vpp1 &&
		   osd_hw.display_dev_cnt == 2)
			osd_rdma_enable(VPU_VPP1, 2);
		if (osd_hw.osd_meson_dev.has_vpp2 &&
		   osd_hw.display_dev_cnt == 3)
			osd_rdma_enable(VPU_VPP2, 2);
	} else {
		osd_hw.afbc_force_reset = 0;
	}
#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
	affinity_set_init();
#endif
#ifdef CONFIG_AMLOGIC_MEDIA_SECURITY
	secure_register(OSD_MODULE, 0,
			osd_secure_op,
			osd_secure_cb);
#endif
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
	register_osd_func(get_osd_status);
#endif
	osd_log_out = 1;
}

void set_viu2_format(u32 format)
{
	if (is_yuv_format(format))
		set_viu2_rgb2yuv(1);
	else
		set_viu2_rgb2yuv(0);
}

void osd_init_viu2(void)
{
	u32 idx, data32;
#ifdef CONFIG_AMLOGIC_VOUT2_SERVE
	struct vinfo_s *vinfo;
	vinfo = get_current_vinfo2();
	if (vinfo && vinfo->name && (strcmp(vinfo->name, "invalid") &&
		      strcmp(vinfo->name, "null")))
		set_viu2_format(vinfo->viu_color_fmt);
#endif

	idx = osd_hw.osd_meson_dev.viu2_index;
	if (osd_get_logo_index() != LOGO_DEV_VIU2_OSD0) {
		set_viu2_rgb2yuv(1);
		osd_vpu_power_on_viu2();
		/* here we will init default value, these value only set once */
		/* init vpu fifo control register */
		osd_reg_write(VPP2_OFIFO_SIZE, 0x7ff00800);
		/* init osd fifo control register
		 * set DDR request priority to be urgent
		 */
		data32 = 0x1 << 0;
		data32 |= OSD_GLOBAL_ALPHA_DEF << 12;
		osd_reg_write(hw_osd_reg_array[idx].osd_ctrl_stat, data32);

		osd_reg_set_bits(hw_osd_reg_array[idx].osd_fifo_ctrl_stat,
				 1, 31, 1);
		osd_reg_set_bits(hw_osd_reg_array[idx].osd_fifo_ctrl_stat,
				 1, 10, 2);

		data32 = 0;
		data32 = osd_reg_read(hw_osd_reg_array[idx].osd_ctrl_stat);
		data32 |= 0x80000000;
		osd_reg_write(hw_osd_reg_array[idx].osd_ctrl_stat, data32);

		data32 = 1;
		data32 |= VIU2_DEFAULT_HOLD_LINE << 5;  /* hold_fifo_lines */
		/* burst_len_sel: 3=64, g12a = 5 */
		if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE) {
			data32 |= 1 << 10;
			data32 |= 1 << 31;
		} else {
			data32 |= 3 << 10;
		}
		/*
		 * bit 23:22, fifo_ctrl
		 * 00 : for 1 word in 1 burst
		 * 01 : for 2 words in 1 burst
		 * 10 : for 4 words in 1 burst
		 * 11 : reserved
		 */
		data32 |= 2 << 22;
		/* bit 28:24, fifo_lim */
		data32 |= 2 << 24;
		/* data32_ = data32; */
		/* fifo_depth_val: 32 or 64 *8 = 256 or 512 */
		data32 |= (osd_hw.osd_meson_dev.osd_fifo_len & 0xfffffff) << 12;
		osd_reg_write(hw_osd_reg_array[idx].osd_fifo_ctrl_stat, data32);
	}

	/* enable for latch */
	osd_hw.osd_use_latch[idx] = 1;
	/* init osd reverse */
	osd_get_reverse_hw(idx, &data32);
	if (data32)
		osd_set_reverse_hw(idx, data32, 1);
	viu2_osd_reg_table_init();
	osd_hw.powered[idx] = 1;
}

void osd_cursor_hw(u32 index, s16 x, s16 y, s16 xstart, s16 ystart, u32 osd_w,
		   u32 osd_h)
{
	struct pandata_s disp_tmp;
	int w = 0, h = 0;
	int w_diff = 0;

	if (index != 1)
		return;

	osd_log_dbg(MODULE_CURSOR, "cursor: x=%d, y=%d, x0=%d, y0=%d, w=%d, h=%d\n",
		    x, y, xstart, ystart, osd_w, osd_h);

	if (osd_hw.free_scale_mode[OSD1]) {
		if (osd_hw.free_scale_enable[OSD1])
			memcpy(&disp_tmp, &osd_hw.cursor_dispdata[OSD1],
			       sizeof(struct pandata_s));
		else
			memcpy(&disp_tmp, &osd_hw.dispdata[OSD1],
			       sizeof(struct pandata_s));
	} else {
		memcpy(&disp_tmp, &osd_hw.dispdata[OSD1],
		       sizeof(struct pandata_s));
	}

	if (osd_hw.osd_reverse[OSD2] == REVERSE_TRUE) {
		if (osd_hw.free_scale_enable[OSD1]) {
			w = osd_hw.free_src_data[OSD1].x_end -
				osd_hw.free_src_data[OSD1].x_start + 1;
			h = osd_hw.free_src_data[OSD1].y_end -
				osd_hw.free_src_data[OSD1].y_start + 1;
		} else {
			w = osd_hw.pandata[OSD1].x_end -
				osd_hw.pandata[OSD1].x_start + 1;
			h = osd_hw.pandata[OSD1].y_end -
				osd_hw.pandata[OSD1].y_start + 1;
		}
		x = w - x;
		y = h - y;
	}
	if (osd_hw.scale[OSD1].h_enable)
		osd_hw.scaledata[OSD2].x_end *= 2;
	if (osd_hw.scale[OSD1].v_enable)
		osd_hw.scaledata[OSD2].y_end *= 2;
	if (osd_hw.scale[OSD2].h_enable &&
	    osd_hw.scaledata[OSD2].x_start > 0 &&
	    osd_hw.scaledata[OSD2].x_end > 0) {
		x = x * osd_hw.scaledata[OSD2].x_end /
			osd_hw.scaledata[OSD2].x_start;
	}
	if (osd_hw.scale[OSD2].v_enable &&
	    osd_hw.scaledata[OSD2].y_start > 0 &&
	    osd_hw.scaledata[OSD2].y_end > 0) {
		y = y * osd_hw.scaledata[OSD2].y_end /
			osd_hw.scaledata[OSD2].y_start;
	}
	x += xstart;
	y += ystart;
	if (osd_hw.osd_reverse[OSD2] == REVERSE_TRUE) {
		if (osd_w >= osd_h)
			w_diff = osd_w - osd_h;
		else
			w_diff = 0;
		osd_hw.pandata[OSD2].x_start = w_diff;
		osd_hw.pandata[OSD2].x_end = osd_w - 1;
		osd_hw.pandata[OSD2].y_start = 0;
		osd_hw.pandata[OSD2].y_end = osd_h - 1;
		x -= osd_w;
		y -= osd_h;
		osd_log_dbg(MODULE_CURSOR, "x=%d,y=%d\n", x, y);
	}
	/*
	 * Use pandata to show a partial cursor when it is at the edge because
	 * the registers can't have negative values and because we need to
	 * manually clip the cursor when it is past the edge.  The edge is
	 * hardcoded to the OSD0 area.
	 */
	osd_hw.dispdata[OSD2].x_start = x;
	osd_hw.dispdata[OSD2].y_start = y;
	if (osd_hw.osd_reverse[OSD2] == REVERSE_TRUE) {
		if (x <  disp_tmp.x_start) {
			/* if negative position, set osd x pan. */
			if ((disp_tmp.x_start - x) < osd_w) {
				osd_hw.pandata[OSD2].x_start =
					w_diff;
				osd_hw.pandata[OSD2].x_end =
					osd_w - 1 - (disp_tmp.x_start - x);
			}
			/* set osd x to disp_tmp.x_start */
			osd_hw.dispdata[OSD2].x_start = disp_tmp.x_start;
		}
		if (y < disp_tmp.y_start) {
			/* if negative position, set osd y pan. */
			if ((disp_tmp.y_start - y) < osd_h) {
				osd_hw.pandata[OSD2].y_start = 0;
				osd_hw.pandata[OSD2].y_end =
					osd_h - 1 - (disp_tmp.y_start - y);
			}
			/* set osd y to disp_tmp.y_start */
			osd_hw.dispdata[OSD2].y_start = disp_tmp.y_start;
		}
	} else {
		if (x <  disp_tmp.x_start) {
			/* if negative position, set osd to 0,y and pan. */
			if ((disp_tmp.x_start - x) < osd_w) {
				osd_hw.pandata[OSD2].x_start =
					disp_tmp.x_start - x;
				osd_hw.pandata[OSD2].x_end = osd_w - 1;
			}
			osd_hw.dispdata[OSD2].x_start = 0;
		} else {
			osd_hw.pandata[OSD2].x_start = 0;
			if (x + osd_w > disp_tmp.x_end) {
				/*
				 * if past positive edge,
				 * set osd to inside of the edge and pan.
				 */
				if (x < disp_tmp.x_end)
					osd_hw.pandata[OSD2].x_end =
					disp_tmp.x_end - x;
			} else {
				osd_hw.pandata[OSD2].x_end = osd_w - 1;
			}
		}
		if (y < disp_tmp.y_start) {
			if ((disp_tmp.y_start - y) < osd_h) {
				osd_hw.pandata[OSD2].y_start =
					disp_tmp.y_start - y;
				osd_hw.pandata[OSD2].y_end = osd_h - 1;
			}
			osd_hw.dispdata[OSD2].y_start = 0;
		} else {
			osd_hw.pandata[OSD2].y_start = 0;
			if (y + osd_h > disp_tmp.y_end) {
				if (y < disp_tmp.y_end)
					osd_hw.pandata[OSD2].y_end =
					disp_tmp.y_end - y;
			} else {
				osd_hw.pandata[OSD2].y_end = osd_h - 1;
			}
		}
	}
	osd_hw.dispdata[OSD2].x_end = osd_hw.dispdata[OSD2].x_start +
		osd_hw.pandata[OSD2].x_end - osd_hw.pandata[OSD2].x_start;
	osd_hw.dispdata[OSD2].y_end = osd_hw.dispdata[OSD2].y_start +
		osd_hw.pandata[OSD2].y_end - osd_hw.pandata[OSD2].y_start;
	add_to_update_list(OSD2, OSD_COLOR_MODE);
	add_to_update_list(OSD2, DISP_GEOMETRY);
	osd_log_dbg(MODULE_CURSOR, "dispdata: %d,%d,%d,%d\n",
		    osd_hw.dispdata[OSD2].x_start, osd_hw.dispdata[OSD2].x_end,
		    osd_hw.dispdata[OSD2].y_start, osd_hw.dispdata[OSD2].y_end);
}

void osd_cursor_hw_no_scale(u32 index, s16 x, s16 y, s16 xstart, s16 ystart,
			    u32 osd_w, u32 osd_h)
{
	struct pandata_s disp_tmp;
	struct vinfo_s *vinfo = NULL;
	int w = 0, h = 0;
	int w_diff = 0;

	if (index != 1)
		return;

	osd_log_dbg(MODULE_CURSOR, "cursor: x=%d, y=%d, x0=%d, y0=%d, w=%d, h=%d\n",
		    x, y, xstart, ystart, osd_w, osd_h);

	if (osd_hw.free_scale_mode[OSD1]) {
		if (osd_hw.free_scale_enable[OSD1])
			memcpy(&disp_tmp, &osd_hw.cursor_dispdata[OSD1],
			       sizeof(struct pandata_s));
		else
			memcpy(&disp_tmp, &osd_hw.dispdata[OSD1],
			       sizeof(struct pandata_s));
	} else {
		memcpy(&disp_tmp, &osd_hw.dispdata[OSD1],
		       sizeof(struct pandata_s));
	}

	if (osd_hw.field_out_en[VIU1]) {
		disp_tmp.y_start *= 2;
		disp_tmp.y_end *= 2;
	}

	if (osd_hw.osd_reverse[OSD2] == REVERSE_TRUE) {
	#ifdef CONFIG_AMLOGIC_VOUT_SERVE
		vinfo = get_current_vinfo();
	#endif
		if (!vinfo || vinfo->mode == VMODE_INIT_NULL)
			return;

		w = vinfo->width;
		h = vinfo->height;

		x = w - x;
		y = h - y;
	}

	x += xstart;
	y += ystart;

	if (osd_hw.osd_reverse[OSD2] == REVERSE_TRUE) {
		if (osd_w >= osd_h)
			w_diff = osd_w - osd_h;
		else
			w_diff = 0;
		osd_hw.pandata[OSD2].x_start = w_diff;
		osd_hw.pandata[OSD2].x_end = osd_w - 1;
		osd_hw.pandata[OSD2].y_start = 0;
		osd_hw.pandata[OSD2].y_end = osd_h - 1;
		x -= osd_w;
		y -= osd_h;
		osd_log_dbg(MODULE_CURSOR, "x=%d,y=%d\n", x, y);
	}
	/*
	 * Use pandata to show a partial cursor when it is at the edge because
	 * the registers can't have negative values and because we need to
	 * manually clip the cursor when it is past the edge.  The edge is
	 * hardcoded to the OSD0 area.
	 */
	osd_hw.dispdata[OSD2].x_start = x;
	osd_hw.dispdata[OSD2].y_start = y;
	if (osd_hw.osd_reverse[OSD2] == REVERSE_TRUE) {
		if (x <  disp_tmp.x_start) {
			/* if negative position, set osd x pan. */
			if ((disp_tmp.x_start - x) < osd_w) {
				osd_hw.pandata[OSD2].x_start =
					w_diff;
				osd_hw.pandata[OSD2].x_end =
					osd_w - 1 - (disp_tmp.x_start - x);
			}
			/* set osd x to disp_tmp.x_start */
			osd_hw.dispdata[OSD2].x_start = disp_tmp.x_start;
		}
		if (y < disp_tmp.y_start) {
			/* if negative position, set osd y pan. */
			if ((disp_tmp.y_start - y) < osd_h) {
				osd_hw.pandata[OSD2].y_start = 0;
				osd_hw.pandata[OSD2].y_end =
					osd_h - 1 - (disp_tmp.y_start - y);
			}
			/* set osd y to disp_tmp.y_start */
			osd_hw.dispdata[OSD2].y_start = disp_tmp.y_start;
		}
	} else {
		if (x <  disp_tmp.x_start) {
			/* if negative position, set osd to 0,y and pan. */
			if ((disp_tmp.x_start - x) < osd_w) {
				osd_hw.pandata[OSD2].x_start =
					disp_tmp.x_start - x;
				osd_hw.pandata[OSD2].x_end = osd_w - 1;
			}
			osd_hw.dispdata[OSD2].x_start = 0;
		} else {
			osd_hw.pandata[OSD2].x_start = 0;
			if (x + osd_w > disp_tmp.x_end) {
				/*
				 * if past positive edge,
				 * set osd to inside of the edge and pan.
				 */
				if (x < disp_tmp.x_end)
					osd_hw.pandata[OSD2].x_end =
					disp_tmp.x_end - x;
			} else {
				osd_hw.pandata[OSD2].x_end = osd_w - 1;
			}
		}
		if (y < disp_tmp.y_start) {
			if ((disp_tmp.y_start - y) < osd_h) {
				osd_hw.pandata[OSD2].y_start =
					disp_tmp.y_start - y;
				osd_hw.pandata[OSD2].y_end = osd_h - 1;
			}
			osd_hw.dispdata[OSD2].y_start = 0;
		} else {
			osd_hw.pandata[OSD2].y_start = 0;
			if (y + osd_h > disp_tmp.y_end) {
				if (y < disp_tmp.y_end)
					osd_hw.pandata[OSD2].y_end =
					disp_tmp.y_end - y;
			} else {
				osd_hw.pandata[OSD2].y_end = osd_h - 1;
			}
		}
	}

	if (osd_hw.field_out_en[VIU1])
		osd_hw.dispdata[OSD2].y_start /= 2;

	osd_hw.dispdata[OSD2].x_end = osd_hw.dispdata[OSD2].x_start +
		osd_hw.pandata[OSD2].x_end - osd_hw.pandata[OSD2].x_start;
	osd_hw.dispdata[OSD2].y_end = osd_hw.dispdata[OSD2].y_start +
		osd_hw.pandata[OSD2].y_end - osd_hw.pandata[OSD2].y_start;
	add_to_update_list(OSD2, OSD_COLOR_MODE);
	add_to_update_list(OSD2, DISP_GEOMETRY);
	osd_log_dbg(MODULE_CURSOR, "dispdata: %d,%d,%d,%d\n",
		    osd_hw.dispdata[OSD2].x_start, osd_hw.dispdata[OSD2].x_end,
		    osd_hw.dispdata[OSD2].y_start, osd_hw.dispdata[OSD2].y_end);
}

void  osd_suspend_hw(void)
{
	wait_vsync_wakeup();
	wait_vsync_wakeup_viu2();
	wait_vsync_wakeup_viu3();
	wait_rdma_done_wakeup();
	wait_rdma_done_wakeup_viu2();
	wait_rdma_done_wakeup_viu3();
	if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL &&
		osd_dev_hw.display_type != C3_DISPLAY) {
		osd_hw.reg_status_save =
			osd_reg_read(VPP_MISC) & OSD_RELATIVE_BITS;
		osd_vpp_misc &= ~OSD_RELATIVE_BITS;
		notify_to_amvideo();
		osd_reg_clr_mask(VPP_MISC, OSD_RELATIVE_BITS);
		/* VSYNCOSD_CLR_MPEG_REG_MASK(VPP_MISC, OSD_RELATIVE_BITS); */
	} else {
		int i = 0;

		spin_lock_irqsave(&osd_lock, lock_flags);
		suspend_flag = true;
		for (i = 0; i < osd_hw.osd_meson_dev.osd_count; i++) {
			if (osd_hw.enable[i]) {
				osd_hw.enable_save[i] = ENABLE;
				osd_hw.enable[i] = DISABLE;
				/* if display2 mode is set to null or invalid */
				if (osd_hw.osd_meson_dev.has_viu2 &&
				    i == osd_hw.osd_meson_dev.viu2_index) {
					struct vinfo_s *vinfo = NULL;

					vinfo = get_current_vinfo2();
					if (vinfo && vinfo->name &&
					    (!strncmp(vinfo->name, "null", 4) ||
					     !strncmp(vinfo->name, "invalid", 7)
					    )
					   )
						continue;
				}
				osd_hw.reg[OSD_ENABLE]
					.update_func(i);
			} else {
				osd_hw.enable_save[i] = DISABLE;
			}
		}
		osd_hw.reg_status_save =
			osd_reg_read(hw_osd_reg_blend.osd_blend_ctrl);
		osd_hw.reg_status_save1 =
			osd_reg_read(hw_osd_reg_blend.osd1_blend_src_ctrl);
		if (!osd_dev_hw.multi_afbc_core &&
			osd_hw.osd_meson_dev.afbc_type != NO_AFBC)
			osd_hw.reg_status_save4 =
				osd_reg_read(VPU_MAFBC_SURFACE_CFG);
		osd_reg_clr_mask(hw_osd_reg_blend.osd_blend_ctrl, 0xf0000);
		osd_reg_clr_mask(hw_osd_reg_blend.osd1_blend_src_ctrl, 0xf0f);
		if (!enable_vd_zorder) {
			osd_hw.reg_status_save2 =
				osd_reg_read(hw_osd_reg_blend.osd2_blend_src_ctrl);
			osd_reg_clr_mask(hw_osd_reg_blend.osd2_blend_src_ctrl, 0xf0f);
		}
		if (osd_dev_hw.s5_display) {
			osd_hw.reg_status_save3[0] =
				osd_reg_read(VPP_RDARB_REQEN_SLV0);
			osd_hw.reg_status_save3[1] =
				osd_reg_read(VPP_RDARB_REQEN_SLV1);
			osd_reg_clr_mask(VPP_RDARB_REQEN_SLV0,
					 rdarb_reqen_slv);
			osd_reg_clr_mask(VPP_RDARB_REQEN_SLV1,
					 rdarb_reqen_slv);
		} else {
			osd_hw.reg_status_save3[0] =
				osd_reg_read(VPP_RDARB_REQEN_SLV);
			osd_reg_clr_mask(VPP_RDARB_REQEN_SLV,
					 rdarb_reqen_slv);
		}

		if (!osd_dev_hw.multi_afbc_core  &&
			osd_hw.osd_meson_dev.afbc_type != NO_AFBC) {
			osd_reg_write(VPU_MAFBC_SURFACE_CFG, 0);
			osd_reg_write(VPU_MAFBC_COMMAND, 1);
		}
		if (osd_hw.hw_rdma_en) {
			osd_rdma_enable(VPU_VPP0, 0);
			if (osd_hw.osd_meson_dev.has_vpp1 &&
			   osd_hw.display_dev_cnt == 2)
				osd_rdma_enable(VPU_VPP1, 0);
			if (osd_hw.osd_meson_dev.has_vpp2 &&
			   osd_hw.display_dev_cnt == 3)
				osd_rdma_enable(VPU_VPP2, 0);
		}
		spin_unlock_irqrestore(&osd_lock, lock_flags);

		if (supsend_delay)
			mdelay(supsend_delay);
	}
	osd_log_info("osd_suspended\n");
}

void osd_resume_hw(void)
{
	if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL &&
		osd_dev_hw.display_type != C3_DISPLAY) {
		if (osd_hw.reg_status_save &
			(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND))
			osd_hw.reg_status_save |= VPP_POSTBLEND_EN;
		osd_vpp_misc = osd_hw.reg_status_save & OSD_RELATIVE_BITS;
		notify_to_amvideo();
		osd_reg_set_mask(VPP_MISC, osd_hw.reg_status_save);
		if (osd_hw.enable[OSD2] == ENABLE) {
			osd_vpp_misc |= VPP_OSD2_POSTBLEND;
			osd_reg_set_mask(VIU_OSD2_CTRL_STAT,
					 1 << 0);
			osd_reg_set_mask(VPP_MISC,
					 VPP_OSD2_POSTBLEND
					 | VPP_POSTBLEND_EN);
		} else {
			osd_vpp_misc &= ~VPP_OSD2_POSTBLEND;
			osd_reg_clr_mask(VPP_MISC,
					 VPP_OSD2_POSTBLEND);
			osd_reg_clr_mask(VIU_OSD2_CTRL_STAT,
					 1 << 0);
		}
		notify_to_amvideo();
	} else {
		int i = 0;

		spin_lock_irqsave(&osd_lock, lock_flags);
		if (osd_hw.hw_rdma_en) {
			osd_rdma_enable(VPU_VPP0, 2);
			if (osd_hw.osd_meson_dev.has_vpp1 &&
			   osd_hw.display_dev_cnt == 2)
				osd_rdma_enable(VPU_VPP1, 2);
			if (osd_hw.osd_meson_dev.has_vpp2 &&
			   osd_hw.display_dev_cnt == 3)
				osd_rdma_enable(VPU_VPP2, 2);
		}

		suspend_flag = false;
		for (i = 0; i < osd_hw.osd_meson_dev.osd_count; i++) {
			if (osd_hw.enable_save[i]) {
				osd_hw.enable[i] = ENABLE;
				/* if display2 mode is set to null or invalid */
				if (osd_hw.osd_meson_dev.has_viu2 &&
				    i == osd_hw.osd_meson_dev.viu2_index) {
					struct vinfo_s *vinfo = NULL;

					vinfo = get_current_vinfo2();
					if (vinfo && vinfo->name &&
					    (!strncmp(vinfo->name, "null", 4) ||
					     !strncmp(vinfo->name, "invalid", 7)
					    )
					   )
						continue;
				}
				osd_hw.reg[OSD_ENABLE]
					.update_func(i);
			}
		}
		osd_reg_write(hw_osd_reg_blend.osd_blend_ctrl,
			      osd_hw.reg_status_save);
		osd_reg_write(hw_osd_reg_blend.osd1_blend_src_ctrl,
			      osd_hw.reg_status_save1);
		if (!enable_vd_zorder)
			osd_reg_write(hw_osd_reg_blend.osd2_blend_src_ctrl,
				      osd_hw.reg_status_save2);
		if (osd_dev_hw.s5_display) {
			osd_reg_write(VPP_RDARB_REQEN_SLV0,
				      osd_hw.reg_status_save3[0]);
			osd_reg_write(VPP_RDARB_REQEN_SLV1,
				      osd_hw.reg_status_save3[1]);
		} else {
			osd_reg_write(VPP_RDARB_REQEN_SLV,
				      osd_hw.reg_status_save3[0]);
		}
		if (!osd_dev_hw.multi_afbc_core &&
			osd_hw.osd_meson_dev.afbc_type != NO_AFBC)
			osd_reg_write(VPU_MAFBC_SURFACE_CFG,
				      osd_hw.reg_status_save4);
		for (i = 0; i < osd_hw.osd_meson_dev.osd_count; i++)
			osd_hw.osd_afbcd[i].afbc_start = 0;
		spin_unlock_irqrestore(&osd_lock, lock_flags);
	}
	osd_log_out = 1;
	osd_log_info("osd_resumed\n");
}

void osd_shutdown_hw(void)
{
	wait_vsync_wakeup();
	wait_vsync_wakeup_viu2();
	wait_vsync_wakeup_viu3();
	wait_rdma_done_wakeup();
	wait_rdma_done_wakeup_viu2();
	wait_rdma_done_wakeup_viu3();
#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA
	if (osd_hw.osd_meson_dev.has_rdma)
		enable_rdma(0);
#endif
	if (osd_hw.hw_rdma_en) {
		osd_rdma_enable(VPU_VPP0, 0);
		if (osd_hw.osd_meson_dev.has_vpp1 &&
		   osd_hw.display_dev_cnt == 2)
			osd_rdma_enable(VPU_VPP1, 0);
		if (osd_hw.osd_meson_dev.has_vpp2 &&
		   osd_hw.display_dev_cnt == 3)
			osd_rdma_enable(VPU_VPP2, 0);
	}
	pr_info("osd_shutdown\n");
}

#ifdef CONFIG_HIBERNATION
static unsigned int fb0_cfg_w0_save;
static u32 __nosavedata free_scale_enable[HW_OSD_COUNT];

void osd_realdata_save_hw(void)
{
	int i;

	for (i = 0; i < osd_hw.osd_meson_dev.osd_count; i++)
		free_scale_enable[i] = osd_hw.free_scale_enable[i];
}

void osd_realdata_restore_hw(void)
{
	int i;

	for (i = 0; i < osd_hw.osd_meson_dev.osd_count; i++)
		osd_hw.free_scale_enable[i] = free_scale_enable[i];
}

void  osd_freeze_hw(void)
{
#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA
	if (osd_hw.osd_meson_dev.has_rdma)
		enable_rdma(0);
#endif
	if (osd_hw.hw_rdma_en) {
		osd_rdma_enable(VPU_VPP0, 0);
		if (osd_hw.osd_meson_dev.has_vpp1 &&
		   osd_hw.display_dev_cnt == 2)
			osd_rdma_enable(VPU_VPP1, 0);
		if (osd_hw.osd_meson_dev.has_vpp2 &&
		   osd_hw.display_dev_cnt == 3)
			osd_rdma_enable(VPU_VPP2, 0);
		if (get_backup_reg(VIU_OSD1_BLK0_CFG_W0,
				   &fb0_cfg_w0_save) != 0)
			fb0_cfg_w0_save =
				osd_reg_read(VIU_OSD1_BLK0_CFG_W0);
	} else {
		fb0_cfg_w0_save = osd_reg_read(VIU_OSD1_BLK0_CFG_W0);
	}
	pr_debug("osd_freezed\n");
}

void osd_thaw_hw(void)
{
	pr_debug("osd_thawed\n");
	if (osd_hw.hw_rdma_en) {
		osd_rdma_enable(VPU_VPP0, 2);
		if (osd_hw.osd_meson_dev.has_vpp1 &&
		   osd_hw.display_dev_cnt == 2)
			osd_rdma_enable(VPU_VPP1, 2);
		if (osd_hw.osd_meson_dev.has_vpp2 &&
		   osd_hw.display_dev_cnt == 3)
			osd_rdma_enable(VPU_VPP2, 2);
	}
#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA
	if (osd_hw.osd_meson_dev.has_rdma)
		enable_rdma(1);
#endif
}

void osd_restore_hw(void)
{
	int i;

	osd_reg_write(VIU_OSD1_BLK0_CFG_W0, fb0_cfg_w0_save);
	if (osd_hw.hw_rdma_en) {
		osd_rdma_enable(VPU_VPP0, 2);
		if (osd_hw.osd_meson_dev.has_vpp1 &&
		   osd_hw.display_dev_cnt == 2)
			osd_rdma_enable(VPU_VPP1, 2);
		if (osd_hw.osd_meson_dev.has_vpp2 &&
		   osd_hw.display_dev_cnt == 3)
			osd_rdma_enable(VPU_VPP2, 2);
	}
#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA
	if (osd_hw.osd_meson_dev.has_rdma)
		enable_rdma(1);
#endif

	if (osd_hw.osd_meson_dev.osd_ver == OSD_SIMPLE) {
		osd_update_phy_addr(0);
	} else if (osd_hw.osd_meson_dev.mif_linear) {
		for (i = 0; i < osd_hw.osd_meson_dev.osd_count; i++)
			osd_update_mif_linear_addr(i);
	} else {
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS

		for (i = 0; i < osd_hw.osd_meson_dev.osd_count; i++)
			canvas_config(osd_hw.fb_gem[i].canvas_idx,
				      osd_hw.fb_gem[i].addr,
				      CANVAS_ALIGNED(osd_hw.fb_gem[i].width),
				      osd_hw.fb_gem[i].height,
				      CANVAS_ADDR_NOWRAP,
				      CANVAS_BLKMODE_LINEAR);
#endif
	}
	pr_debug("osd_restored\n");
}
#endif

int osd_get_logo_index(void)
{
	return osd_logo_index;
}

void osd_set_logo_index(int index)
{
	osd_logo_index = index;
}

void osd_get_hw_para(struct hw_para_s **para)
{
	*para = &osd_hw;
}

void osd_get_blending_para(struct hw_osd_blending_s **para)
{
	*para = &osd_blending;
}

void osd_backup_screen_info(u32 index,
			    unsigned long screen_base,
			    unsigned long screen_size)
{
	osd_hw.screen_base_backup[index] = screen_base;
	osd_hw.screen_size_backup[index] = screen_size;
}

void osd_get_screen_info(u32 index,
			 char __iomem **screen_base,
			 unsigned long *screen_size)
{
	if (index >= OSD_MAX)
		return;
	*screen_base = (char __iomem *)osd_hw.screen_base[index];
	*screen_size = osd_hw.screen_size[index];
}

void osd_get_fence_count(u32 index, u32 *fence_cnt, u32 *timeline_cnt)
{
#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
	u32 output_index;
	struct sync_timeline *tl = NULL;
#endif

	if (index >= OSD_MAX || !fence_cnt || !timeline_cnt)
		return;

#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE
	output_index = get_output_device_id(index);
	tl = (struct sync_timeline *)osd_timeline[output_index];

	*fence_cnt = cur_streamline_val[output_index];
	*timeline_cnt = tl ? tl->value : 0;
#else
	*fence_cnt = 0;
	*timeline_cnt = 0;
#endif
}

int get_vmap_addr(u32 index, u8 __iomem **buf)
{
	unsigned long total_size;
	ulong phys;
	u32 offset, npages;
	struct page **pages = NULL;
	pgprot_t pgprot;
	static u8 *vaddr;
	int i;

	total_size = osd_hw.screen_size[index];

	npages = PAGE_ALIGN(total_size) / PAGE_SIZE;
	phys = osd_hw.screen_base[index];
	offset = phys & ~PAGE_MASK;
	if (offset)
		npages++;
	pages = vmalloc(sizeof(struct page *) * npages);
	if (!pages)
		return -ENOMEM;
	for (i = 0; i < npages; i++) {
		pages[i] = phys_to_page(phys);
		phys += PAGE_SIZE;
	}
	/*nocache*/
	pgprot = pgprot_writecombine(PAGE_KERNEL);
	if (vaddr) {
		/*  unmap previous vaddr */
		vunmap(vaddr);
		vaddr = NULL;
	}
	vaddr = vmap(pages, npages, VM_MAP, pgprot);
	if (!vaddr) {
		pr_err("the phy(%lx) vmaped fail, size: %d\n",
		       phys, npages << PAGE_SHIFT);
		vfree(pages);
		return -ENOMEM;
	}
	vfree(pages);
	*buf = (u8 __iomem *)(vaddr);
	return osd_hw.screen_size[index];
}

int osd_set_clear(u32 index)
{
	unsigned long total_size;
	ulong phys;
	u32 offset, npages;
	struct page **pages = NULL;
	pgprot_t pgprot;
	static u8 *vaddr;
	u8 __iomem *dst;
	int i, c, count, cnt = 0;

	total_size = osd_hw.screen_size[index];
	npages = PAGE_ALIGN(total_size) / PAGE_SIZE;
	phys = osd_hw.screen_base[index];
	offset = phys & (~PAGE_MASK);
	if (offset)
		npages++;
	pages = vmalloc(sizeof(struct page *) * npages);
	if (!pages)
		return -ENOMEM;
	for (i = 0; i < npages; i++) {
		pages[i] = phys_to_page(phys);
		phys += PAGE_SIZE;
	}
	/*nocache*/
	pgprot = pgprot_writecombine(PAGE_KERNEL);

	vaddr = vmap(pages, npages, VM_MAP, pgprot);
	if (!vaddr) {
		pr_err("the phy(%lx) vmaped fail, size: %d\n",
		       phys, npages << PAGE_SHIFT);
		vfree(pages);
		return -ENOMEM;
	}
	vfree(pages);
	dst = (u8 __iomem *)(vaddr);

	count = total_size;
	while (count) {
		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
		memset(dst, 0, c);
		dst += c;
		cnt += c;
		count -= c;
	}
	if (vaddr) {
		/*  unmap previous vaddr */
		vunmap(vaddr);
		vaddr = NULL;
	}

	return cnt;
}

static const struct color_bit_define_s *convert_panel_format(u32 format)
{
	const struct color_bit_define_s *color = NULL;

	format &= ~AFBC_EN;
	switch (format) {
	case COLOR_INDEX_02_PAL4:
	case COLOR_INDEX_04_PAL16:
	case COLOR_INDEX_08_PAL256:
	case COLOR_INDEX_16_655:
	case COLOR_INDEX_16_844:
	case COLOR_INDEX_16_6442:
	case COLOR_INDEX_16_4444_R:
	case COLOR_INDEX_16_4642_R:
	case COLOR_INDEX_16_1555_A:
	case COLOR_INDEX_16_4444_A:
	case COLOR_INDEX_16_565:
	case COLOR_INDEX_24_6666_A:
	case COLOR_INDEX_24_6666_R:
	case COLOR_INDEX_24_8565:
	case COLOR_INDEX_24_5658:
	case COLOR_INDEX_24_888_B:
	case COLOR_INDEX_24_RGB:
	case COLOR_INDEX_32_BGRX:
	case COLOR_INDEX_32_XBGR:
	case COLOR_INDEX_32_RGBX:
	case COLOR_INDEX_32_XRGB:
	case COLOR_INDEX_32_BGRA:
	case COLOR_INDEX_32_ABGR:
	case COLOR_INDEX_32_RGBA:
	case COLOR_INDEX_32_ARGB:
	case COLOR_INDEX_YUV_422:
		color = &default_color_format_array[format];
		break;
	}
	return color;
}

static bool osd_direct_render(struct osd_plane_map_s *plane_map)
{
	u32 index = plane_map->plane_index;
	u32 phy_addr = plane_map->phy_addr;
	u32 width_src, width_dst, height_src, height_dst;
	u32 x_start, x_end, y_start, y_end;
	bool freescale_update = false;
	struct pandata_s freescale_dst[HW_OSD_COUNT];
	u32 output_index;

	output_index = get_output_device_id(index);
	phy_addr = phy_addr + plane_map->byte_stride * plane_map->src_y;
	osd_hw.screen_base[index] = phy_addr;
	osd_hw.screen_size[index] =
		plane_map->byte_stride * plane_map->src_h;
	osd_log_dbg(MODULE_RENDER, "canvas_id=%x, phy_addr=%x\n",
		    osd_hw.fb_gem[index].canvas_idx, phy_addr);
	if (osd_hw.osd_meson_dev.osd_ver == OSD_SIMPLE) {
		osd_hw.fb_gem[index].addr = phy_addr;
		osd_hw.fb_gem[index].width = plane_map->byte_stride;
		osd_update_phy_addr(0);
	} else if (osd_hw.osd_meson_dev.mif_linear) {
		osd_update_mif_linear_addr(index);
	} else {
	#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
		canvas_config(osd_hw.fb_gem[index].canvas_idx,
			      phy_addr,
			      CANVAS_ALIGNED(plane_map->byte_stride),
			      plane_map->src_h,
			      CANVAS_ADDR_NOWRAP,
			      CANVAS_BLKMODE_LINEAR);
	#endif
	}
	if (osd_hw.hwc_enable[output_index]) {
		/* just get para, need update via do_hwc */
		osd_hw.order[index] = plane_map->zorder;
		switch (plane_map->blend_mode) {
		case BLEND_MODE_PREMULTIPLIED:
			osd_hw.premult_en[index] = 1;
			break;
		case BLEND_MODE_COVERAGE:
		case BLEND_MODE_NONE:
		case BLEND_MODE_INVALID:
			osd_hw.premult_en[index] = 0;
			break;
		}
		//Todo: fence_map.plane_alpha
		osd_hw.osd_afbcd[index].inter_format =
			plane_map->afbc_inter_format & 0x7fffffff;

		osd_hw.src_data[index].x = plane_map->src_x;
		osd_hw.src_data[index].y = plane_map->src_y;
		osd_hw.src_data[index].w = plane_map->src_w;
		osd_hw.src_data[index].h = plane_map->src_h;

		osd_hw.dst_data[index].x = plane_map->dst_x;
		osd_hw.dst_data[index].y = plane_map->dst_y;
		osd_hw.dst_data[index].w = plane_map->dst_w;
		osd_hw.dst_data[index].h = plane_map->dst_h;
		osd_log_dbg2(MODULE_RENDER, "index=%d\n", index);
		osd_log_dbg2(MODULE_RENDER, "order=%d\n",
			     osd_hw.order[index]);
		osd_log_dbg2(MODULE_RENDER, "premult_en=%d\n",
			     osd_hw.premult_en[index]);
		osd_log_dbg2(MODULE_RENDER, "osd_afbcd_en=%d\n",
			     osd_hw.osd_afbcd[index].enable);
		osd_log_dbg2(MODULE_RENDER, "osd_afbcd_inter_format=%d\n",
			     osd_hw.osd_afbcd[index].inter_format);
		return 0;
	}

	width_dst = osd_hw.free_dst_data_backup[index].x_end -
		osd_hw.free_dst_data_backup[index].x_start + 1;
	width_src = osd_hw.free_src_data_backup[index].x_end -
		osd_hw.free_src_data_backup[index].x_start + 1;

	height_dst = osd_hw.free_dst_data_backup[index].y_end -
		osd_hw.free_dst_data_backup[index].y_start + 1;
	height_src = osd_hw.free_src_data_backup[index].y_end -
		osd_hw.free_src_data_backup[index].y_start + 1;
	osd_hw.free_scale_enable[index] = 1;

	osd_hw.src_data[index].x = plane_map->src_x;
	osd_hw.src_data[index].y = plane_map->src_y;
	osd_hw.src_data[index].w = plane_map->src_w;
	osd_hw.src_data[index].h = plane_map->src_h;

	if (osd_hw.free_scale_enable[index] ||
	    width_src != width_dst ||
	    height_src != height_dst ||
	    plane_map->src_w != plane_map->dst_w ||
	    plane_map->src_h != plane_map->dst_h) {
		osd_hw.free_scale[index].h_enable = 1;
		osd_hw.free_scale[index].v_enable = 1;
		osd_hw.free_scale_enable[index] = 0x10001;
		osd_hw.free_scale_mode[index] = 1;
		if (osd_hw.free_scale_enable[index] !=
			osd_hw.free_scale_enable_backup[index]) {
			/* Todo: */
			osd_set_scan_mode(index);
			freescale_update = true;
		}

		osd_hw.pandata[index].x_start = plane_map->src_x;
		osd_hw.pandata[index].x_end =
			plane_map->src_x + plane_map->src_w - 1;
		osd_hw.pandata[index].y_start = 0;
		osd_hw.pandata[index].y_end = plane_map->src_h - 1;

		freescale_dst[index].x_start =
			osd_hw.free_dst_data_backup[index].x_start +
			(plane_map->dst_x * width_dst) / width_src;
		freescale_dst[index].x_end =
			osd_hw.free_dst_data_backup[index].x_start +
			((plane_map->dst_x + plane_map->dst_w) *
			width_dst) / width_src - 1;

		freescale_dst[index].y_start =
			osd_hw.free_dst_data_backup[index].y_start +
			(plane_map->dst_y * height_dst) / height_src;
		freescale_dst[index].y_end =
			osd_hw.free_dst_data_backup[index].y_start +
			((plane_map->dst_y + plane_map->dst_h) *
			height_dst) / height_src - 1;
		if (osd_hw.osd_reverse[index] == REVERSE_TRUE) {
			x_start = osd_hw.vinfo_width[output_index]
				- freescale_dst[index].x_end - 1;
			y_start = osd_hw.vinfo_height[output_index]
				- freescale_dst[index].y_end - 1;
			x_end = osd_hw.vinfo_width[output_index]
				- freescale_dst[index].x_start - 1;
			y_end = osd_hw.vinfo_height[output_index]
				- freescale_dst[index].y_start - 1;
			freescale_dst[index].x_start = x_start;
			freescale_dst[index].y_start = y_start;
			freescale_dst[index].x_end = x_end;
			freescale_dst[index].y_end = y_end;
		} else if (osd_hw.osd_reverse[index] == REVERSE_X) {
			x_start = osd_hw.vinfo_width[output_index]
				- freescale_dst[index].x_end - 1;
			x_end = osd_hw.vinfo_width[output_index]
				- freescale_dst[index].x_start - 1;
			freescale_dst[index].x_start = x_start;
			freescale_dst[index].x_end = x_end;

		} else if (osd_hw.osd_reverse[index] == REVERSE_Y) {
			y_start = osd_hw.vinfo_height[output_index]
				- freescale_dst[index].y_end - 1;
			y_end = osd_hw.vinfo_height[output_index]
				- freescale_dst[index].y_start - 1;
			freescale_dst[index].y_start = y_start;
			freescale_dst[index].y_end = y_end;
		}
		if (memcmp(&osd_hw.free_src_data[index],
			   &osd_hw.pandata[index],
			   sizeof(struct pandata_s)) != 0 ||
		    memcmp(&osd_hw.free_dst_data[index],
			   &freescale_dst[index],
			   sizeof(struct pandata_s)) != 0) {
			memcpy(&osd_hw.free_src_data[index],
			       &osd_hw.pandata[index],
			       sizeof(struct pandata_s));
			memcpy(&osd_hw.free_dst_data[index],
			       &freescale_dst[index],
				sizeof(struct pandata_s));
			freescale_update = true;
			osd_hw.dst_data[index].x =
				osd_hw.free_dst_data[index].x_start;
			osd_hw.dst_data[index].y =
				osd_hw.free_dst_data[index].x_start;
			osd_hw.dst_data[index].w =
				osd_hw.free_dst_data[index].x_end -
				osd_hw.free_dst_data[index].x_start + 1;
			osd_hw.dst_data[index].h =
				osd_hw.free_dst_data[index].y_end -
				osd_hw.free_dst_data[index].y_start + 1;

			if ((height_dst != height_src ||
			     width_dst != width_src) &&
			    osd_hw.free_dst_data[index].y_end <
			    osd_hw.vinfo_height[output_index] - 1)
				osd_set_dummy_data(index, 0);
			else
				osd_set_dummy_data(index, 0xff);
		}
		osd_log_dbg2(MODULE_RENDER,
			     "pandata x=%d,x_end=%d,y=%d,y_end=%d\n",
			     osd_hw.pandata[index].x_start,
			     osd_hw.pandata[index].x_end,
			     osd_hw.pandata[index].y_start,
			     osd_hw.pandata[index].y_end);
		osd_log_dbg2(MODULE_RENDER,
			     "plane_map:src_x=%d,src_y=%d,src_w=%d,src_h=%d\n",
			     plane_map->src_x,
			     plane_map->src_y,
			     plane_map->src_w,
			     plane_map->src_h);
		osd_log_dbg2(MODULE_RENDER,
			     "fence_map:dst_x=%d,dst_y=%d,dst_w=%d,dst_h=%d\n",
			     plane_map->dst_x,
			     plane_map->dst_y,
			     plane_map->dst_w,
			     plane_map->dst_h);
	} else {
		osd_hw.pandata[index].x_start = 0;
		osd_hw.pandata[index].x_end = plane_map->src_w - 1;
		osd_hw.pandata[index].y_start = 0;
		osd_hw.pandata[index].y_end = plane_map->src_h - 1;

		osd_hw.dispdata[index].x_start = plane_map->dst_x;
		osd_hw.dispdata[index].x_end =
			plane_map->dst_x + plane_map->dst_w - 1;
		osd_hw.dispdata[index].y_start = plane_map->dst_y;
		osd_hw.dispdata[index].y_end =
			plane_map->dst_y + plane_map->dst_h - 1;
		if (osd_hw.osd_reverse[index] == REVERSE_TRUE) {
			x_start = osd_hw.vinfo_width[output_index]
				- osd_hw.dispdata[index].x_end - 1;
			y_start = osd_hw.vinfo_height[output_index]
				- osd_hw.dispdata[index].y_end - 1;
			x_end = osd_hw.vinfo_width[output_index]
				- osd_hw.dispdata[index].x_start - 1;
			y_end = osd_hw.vinfo_height[output_index]
				- osd_hw.dispdata[index].y_start - 1;
			osd_hw.dispdata[index].x_start = x_start;
			osd_hw.dispdata[index].y_start = y_start;
			osd_hw.dispdata[index].x_end = x_end;
			osd_hw.dispdata[index].y_end = y_end;
		} else if (osd_hw.osd_reverse[index] == REVERSE_X) {
			x_start = osd_hw.vinfo_width[output_index]
				- osd_hw.dispdata[index].x_end - 1;
			x_end = osd_hw.vinfo_width[output_index]
				- osd_hw.dispdata[index].x_start - 1;
			osd_hw.dispdata[index].x_start = x_start;
			osd_hw.dispdata[index].x_end = x_end;

		} else if (osd_hw.osd_reverse[index] == REVERSE_Y) {
			y_start = osd_hw.vinfo_height[output_index]
				- osd_hw.dispdata[index].y_end - 1;
			y_end = osd_hw.vinfo_height[output_index]
				- osd_hw.dispdata[index].y_start - 1;
			osd_hw.dispdata[index].y_start = y_start;
			osd_hw.dispdata[index].y_end = y_end;
		}
		osd_hw.dst_data[index].x =
			osd_hw.dispdata[index].x_start;
		osd_hw.dst_data[index].y =
			osd_hw.dispdata[index].x_start;
		osd_hw.dst_data[index].w =
			osd_hw.dispdata[index].x_end -
			osd_hw.dispdata[index].x_start + 1;
		osd_hw.dst_data[index].h =
			osd_hw.dispdata[index].y_end -
			osd_hw.dispdata[index].y_start + 1;
	}
	return freescale_update;
}

static void osd_cursor_move(struct osd_plane_map_s *plane_map)
{
	u32 index = plane_map->plane_index;
	u32 phy_addr = plane_map->phy_addr;
	u32 x_start, x_end, y_start, y_end;
	u32 x, y;
	struct pandata_s disp_tmp;
	struct pandata_s free_dst_data_backup;
	u32 output_index;

	if (index != OSD2)
		return;
	output_index = get_output_device_id(index);
	phy_addr = phy_addr + plane_map->byte_stride * plane_map->src_y;
	osd_hw.screen_base[index] = phy_addr;
	osd_hw.screen_size[index] =
		plane_map->byte_stride * plane_map->src_h;
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
	canvas_config(osd_hw.fb_gem[index].canvas_idx,
		      phy_addr,
		      CANVAS_ALIGNED(plane_map->byte_stride),
		      plane_map->src_h,
		      CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
#endif
	osd_hw.pandata[index].x_start = plane_map->src_x;
	osd_hw.pandata[index].x_end = plane_map->src_w - 1;
	osd_hw.pandata[index].y_start = plane_map->src_y;
	osd_hw.pandata[index].y_end = plane_map->src_h - 1;

	if (osd_hw.free_scale_mode[OSD1]) {
		if (osd_hw.free_scale_enable[OSD1])
			memcpy(&disp_tmp, &osd_hw.cursor_dispdata[OSD1],
			       sizeof(struct pandata_s));
		else
			memcpy(&disp_tmp, &osd_hw.dispdata[OSD1],
			       sizeof(struct pandata_s));
	} else {
		memcpy(&disp_tmp, &osd_hw.dispdata[OSD1],
		       sizeof(struct pandata_s));
	}
	memcpy(&free_dst_data_backup,
	       &osd_hw.free_dst_data_backup[OSD1],
	       sizeof(struct pandata_s));
	x = plane_map->dst_x;
	y = plane_map->dst_y;
	if (osd_hw.free_src_data_backup[OSD1].x_end > 0 &&
	    free_dst_data_backup.x_end > 0) {
		x = x * free_dst_data_backup.x_end /
			osd_hw.free_src_data_backup[OSD1].x_end;
	}
	if (osd_hw.free_src_data_backup[OSD1].y_end > 0 &&
	    free_dst_data_backup.y_end > 0) {
		y = y * free_dst_data_backup.y_end /
			osd_hw.free_src_data_backup[OSD1].y_end;
	}

	/*
	 * Use pandata to show a partial cursor when it is at the edge because
	 * the registers can't have negative values and because we need to
	 * manually clip the cursor when it is past the edge.  The edge is
	 * hardcoded to the OSD0 area.
	 */
	osd_hw.dispdata[OSD2].x_start = x;
	osd_hw.dispdata[OSD2].y_start = y;
	if (x <  disp_tmp.x_start) {
		/* if negative position, set osd to 0,y and pan. */
		if ((disp_tmp.x_start - x) < plane_map->src_w) {
			osd_hw.pandata[OSD2].x_start = disp_tmp.x_start - x;
			osd_hw.pandata[OSD2].x_end = plane_map->src_w - 1;
		}
		osd_hw.dispdata[OSD2].x_start = 0;
	} else {
		osd_hw.pandata[OSD2].x_start = 0;
		if (x + plane_map->src_w > disp_tmp.x_end) {
			/*
			 * if past positive edge,
			 * set osd to inside of the edge and pan.
			 */
			if (x < disp_tmp.x_end)
				osd_hw.pandata[OSD2].x_end = disp_tmp.x_end - x;
		} else {
			osd_hw.pandata[OSD2].x_end = plane_map->src_w - 1;
		}
	}
	if (y < disp_tmp.y_start) {
		if ((disp_tmp.y_start - y) < plane_map->src_h) {
			osd_hw.pandata[OSD2].y_start = disp_tmp.y_start - y;
			osd_hw.pandata[OSD2].y_end = plane_map->src_h - 1;
		}
		osd_hw.dispdata[OSD2].y_start = 0;
	} else {
		osd_hw.pandata[OSD2].y_start = 0;
		if (y + plane_map->src_h > disp_tmp.y_end) {
			if (y < disp_tmp.y_end)
				osd_hw.pandata[OSD2].y_end = disp_tmp.y_end - y;
		} else {
			osd_hw.pandata[OSD2].y_end = plane_map->src_h - 1;
		}
	}
	osd_hw.dispdata[OSD2].x_end = osd_hw.dispdata[OSD2].x_start +
		osd_hw.pandata[OSD2].x_end - osd_hw.pandata[OSD2].x_start;
	osd_hw.dispdata[OSD2].y_end = osd_hw.dispdata[OSD2].y_start +
		osd_hw.pandata[OSD2].y_end - osd_hw.pandata[OSD2].y_start;

	if (osd_hw.osd_reverse[OSD2] == REVERSE_TRUE) {
		x_start = osd_hw.vinfo_width[output_index]
			- osd_hw.dispdata[index].x_end - 1;
		y_start = osd_hw.vinfo_height[output_index]
			- osd_hw.dispdata[index].y_end - 1;
		x_end = osd_hw.vinfo_width[output_index]
			- osd_hw.dispdata[index].x_start - 1;
		y_end = osd_hw.vinfo_height[output_index]
			- osd_hw.dispdata[index].y_start - 1;
		osd_hw.dispdata[index].x_start = x_start;
		osd_hw.dispdata[index].y_start = y_start;
		osd_hw.dispdata[index].x_end = x_end;
		osd_hw.dispdata[index].y_end = y_end;
	} else if (osd_hw.osd_reverse[OSD2] == REVERSE_X) {
		x_start = osd_hw.vinfo_width[output_index]
			- osd_hw.dispdata[index].x_end - 1;
		x_end = osd_hw.vinfo_width[output_index]
			- osd_hw.dispdata[index].x_start - 1;
		osd_hw.dispdata[index].x_start = x_start;
		osd_hw.dispdata[index].x_end = x_end;
	} else if (osd_hw.osd_reverse[OSD2] == REVERSE_Y) {
		y_start = osd_hw.vinfo_height[output_index]
			- osd_hw.dispdata[index].y_end - 1;
		y_end = osd_hw.vinfo_height[output_index]
			- osd_hw.dispdata[index].y_start - 1;
		osd_hw.dispdata[index].y_start = y_start;
		osd_hw.dispdata[index].y_end = y_end;
	}
	osd_log_dbg2(MODULE_CURSOR,
		     "plane_map:src_x=%d,src_y=%d,src_w=%d,src_h=%d\n",
		     plane_map->src_x,
		     plane_map->src_y,
		     plane_map->src_w,
		     plane_map->src_h);
	osd_log_dbg2(MODULE_CURSOR,
		     "fence_map:dst_x=%d,dst_y=%d,dst_w=%d,dst_h=%d\n",
		     plane_map->dst_x,
		     plane_map->dst_y,
		     plane_map->dst_w,
		     plane_map->dst_h);
	osd_log_dbg2(MODULE_CURSOR,
		     "cursor pandata x=%d,x_end=%d,y=%d,y_end=%d\n",
		     osd_hw.pandata[index].x_start,
		     osd_hw.pandata[index].x_end,
		     osd_hw.pandata[index].y_start,
		     osd_hw.pandata[index].y_end);
	osd_log_dbg2(MODULE_CURSOR,
		     "cursor dispdata x=%d,x_end=%d,y=%d,y_end=%d\n",
		     osd_hw.dispdata[index].x_start,
		     osd_hw.dispdata[index].x_end,
		     osd_hw.dispdata[index].y_start,
		     osd_hw.dispdata[index].y_end);
}

void osd_page_flip(struct osd_plane_map_s *plane_map)
{
	u32 index = plane_map->plane_index;
	const struct color_bit_define_s *color = NULL;
	bool freescale_update = false;
	u32 osd_enable = 0;
	u32 format = 0;
	const struct vinfo_s *vinfo = NULL;
	u32 output_index;

	output_index = get_output_device_id(index);
	if (!osd_hw.hwc_enable[output_index]) {
		if (index >= OSD2)
			return;
	} else {
		if (index > OSD3)
			return;
	}

	osd_hw.buffer_alloc[index] = 1;
	if (osd_hw.osd_fps_start[output_index])
		osd_hw.osd_fps[output_index]++;

	osd_enable = (plane_map->enable & 1) ? ENABLE : DISABLE;

#ifdef CONFIG_AMLOGIC_VOUT_SERVE
	if (output_index == VIU1)
		vinfo = get_current_vinfo();
#endif
#ifdef CONFIG_AMLOGIC_VOUT2_SERVE
	else if (output_index == VIU2)
		vinfo = get_current_vinfo2();
#endif
	if (!vinfo || !vinfo->name || (!strcmp(vinfo->name, "invalid") ||
	    !strcmp(vinfo->name, "null")))
		return;

	osd_hw.vinfo_width[output_index] = vinfo->width;
	osd_hw.vinfo_height[output_index] = vinfo->height;

	osd_hw.osd_afbcd[index].enable =
		(plane_map->afbc_inter_format & AFBC_EN) >> 31;
	if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL) {
		if (plane_map->phy_addr && plane_map->src_w &&
		    plane_map->src_h && index == OSD1) {
			osd_hw.fb_gem[index].canvas_idx =
				osd_extra_idx[index][ext_canvas_id[index]];
			ext_canvas_id[index] ^= 1;
			color = convert_panel_format(plane_map->format);
			if (color)
				osd_hw.color_info[index] = color;
			else
				osd_log_err("fence color format error %d\n",
					    plane_map->format);

			freescale_update = osd_direct_render(plane_map);

			if (index == OSD1 &&
			    osd_hw.osd_afbcd[index].enable == ENABLE)
				osd_hw.osd_afbcd[index].phy_addr =
					plane_map->phy_addr;
			osd_hw.reg[OSD_COLOR_MODE].update_func(index);
			osd_hw.reg[DISP_GEOMETRY].update_func(index);
			osd_hw.reg[DISP_OSD_REVERSE].update_func(index);
			if ((osd_hw.free_scale_enable[index] &&
			     osd_update_window_axis) ||
			    freescale_update) {
				if (!osd_hw.osd_display_debug[output_index])
					osd_hw.reg[DISP_FREESCALE_ENABLE]
					.update_func(index);
				osd_update_window_axis = false;
			}
			if (osd_hw.osd_afbcd[index].enable == DISABLE &&
			    osd_enable != osd_hw.enable[index] &&
			    !suspend_flag) {
				osd_hw.enable[index] = osd_enable;
				if (!osd_hw.osd_display_debug[output_index])
					osd_hw.reg[OSD_ENABLE]
						.update_func(index);
			}
			if (osd_hw.hw_rdma_en)
				osd_mali_afbc_start(output_index);
			osd_wait_vsync_hw(index);
		} else if (plane_map->phy_addr && plane_map->src_w &&
			   plane_map->src_h && index == OSD2) {
			color = convert_panel_format(plane_map->format);
			if (color) {
				osd_hw.color_info[index] = color;
			} else {
				osd_log_err("fence color format error %d\n",
					    plane_map->format);
			}
			if (osd_hw.hw_cursor_en)
				osd_cursor_move(plane_map);
			osd_hw.reg[OSD_COLOR_MODE].update_func(index);
			osd_hw.reg[DISP_GEOMETRY].update_func(index);
			osd_hw.reg[DISP_OSD_REVERSE].update_func(index);
			if (osd_enable != osd_hw.enable[index] &&
			    !suspend_flag) {
				osd_hw.enable[index] = osd_enable;
				if (!osd_hw.osd_display_debug[output_index])
					osd_hw.reg[OSD_ENABLE]
						.update_func(index);
			}
			if (osd_hw.hw_rdma_en)
				osd_mali_afbc_start(output_index);
		}
	} else {
		if (plane_map->phy_addr && plane_map->src_w &&
		    plane_map->src_h) {
			osd_hw.fb_gem[index].canvas_idx =
				osd_extra_idx[index][ext_canvas_id[index]];
			ext_canvas_id[index] ^= 1;

			if (osd_hw.osd_afbcd[index].enable)
				format = plane_map->format | AFBC_EN;
			else
				format = plane_map->format;
			color = convert_panel_format(format);
			if (color) {
				osd_hw.color_info[index] = color;
			} else {
				osd_log_err("fence color format error %d\n",
					    plane_map->format);
				return;
			}
			osd_hw.osd_afbcd[index].format =
				color->color_index;
			freescale_update = osd_direct_render(plane_map);

			if (osd_hw.osd_afbcd[index].enable == ENABLE)
				osd_hw.osd_afbcd[index].phy_addr =
					plane_map->phy_addr;
			osd_hw.reg[OSD_COLOR_MODE].update_func(index);
			if (!osd_hw.hwc_enable[output_index]) {
				osd_hw.reg[DISP_GEOMETRY].update_func(index);
				osd_hw.reg[DISP_OSD_REVERSE].update_func(index);
				if ((osd_hw.free_scale_enable[index] &&
				     osd_update_window_axis) ||
				    freescale_update) {
					if (!osd_hw.osd_display_debug
							[output_index])
						osd_hw.reg[DISP_FREESCALE_ENABLE]
							.update_func(index);
					osd_update_window_axis = false;
				}
			}
			if (osd_hw.osd_afbcd[index].enable == DISABLE &&
			    osd_enable != osd_hw.enable[index] &&
			    !suspend_flag) {
				osd_hw.enable[index] = osd_enable;
				if (!osd_hw.osd_display_debug[output_index])
					osd_hw.reg[OSD_ENABLE]
						.update_func(index);
			}
			if (osd_hw.hw_rdma_en)
				osd_mali_afbc_start(output_index);
			osd_wait_vsync_hw(index);
		}
	}
}
