blob: 671d9d0c63b83d4504cdfdb6c2cbdb1b4d074400 [file] [log] [blame]
// 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>
#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
/* 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_sw_sync.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
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 bool update_to_dv;
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);
struct hw_osd_reg_s hw_osd_reg_array[HW_OSD_COUNT];
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,
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,
VIU2_OSD1_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,
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,
VIU2_OSD1_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,
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,
},
{
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,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_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,
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,
VIU2_OSD1_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,
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,
VIU2_OSD1_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,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_UNSUPPORT,
VIU2_OSD1_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,
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,
},
{
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,
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,
},
{
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,
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,
},
{
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,
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,
},
};
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,
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,
},
{
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,
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,
},
{
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,
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,
},
};
#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},
};
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)
{
aml_sync_inc_timeline(osd_timeline[output_index], 1);
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;
module_param(osd_vpp_misc, uint, 0444);
MODULE_PARM_DESC(osd_vpp_misc, "osd_vpp_misc");
static unsigned int rdarb_reqen_slv = 0xff7f;
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;
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_binilear[] = {
/* 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_binilear,
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 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(-0.100251), COEFF_NORM(-0.337249), COEFF_NORM(0.437500),
COEFF_NORM(0.437500), COEFF_NORM(-0.397384), COEFF_NORM(-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 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.t7_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 offset = 0;
u32 reg = ENCL_VIDEO_VAVON_BLINE;
if (osd_dev_hw.t7_display) {
u32 venc_mux = 3;
venc_mux = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) & 0x3f;
venc_mux >>= (viu_type * 2);
venc_mux &= 0x3;
switch (venc_mux) {
case 0:
offset = 0;
break;
case 1:
offset = 0x600;
break;
case 2:
offset = 0x800;
break;
}
switch (get_venc_type(viu_type)) {
case 0:
reg = ENCI_VFIFO2VD_LINE_TOP_START;
break;
case 1:
reg = ENCP_VIDEO_VAVON_BLINE;
break;
case 2:
reg = ENCL_VIDEO_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 + offset);
return active_line_begin;
}
static int get_encp_line(u32 viu_type)
{
int enc_line = 0;
unsigned int reg = VPU_VENCI_STAT;
unsigned int reg_val = 0;
u32 offset = 0;
u32 venc_type = get_venc_type(viu_type);
if (osd_dev_hw.t7_display) {
u32 venc_mux = 3;
venc_mux = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) & 0x3f;
venc_mux >>= (viu_type * 2);
venc_mux &= 0x3;
switch (venc_mux) {
case 0:
offset = 0;
break;
case 1:
offset = 0x600;
break;
case 2:
offset = 0x800;
break;
}
switch (venc_type) {
case 0:
reg = VPU_VENCI_STAT;
break;
case 1:
reg = VPU_VENCP_STAT;
break;
case 2:
reg = VPU_VENCL_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 + offset);
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
}
/* 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 osd_toggle_buffer_layers(struct kthread_work *work)
{
struct osd_layers_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_layers_fence(data);
list_del(&data->list);
kfree(data);
}
}
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;
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_layers_fence_viu2(data);
list_del(&data->list);
kfree(data);
}
}
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(current->files, 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(current->files, 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);
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(current->files, in_fence_fd);
if (request->shared_fd >= 0)
__close_fd(current->files, 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, 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, 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))
pr_info("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 has_osd3 = 0;
if ((osd_count - 1) == OSD3)
has_osd3 = 1;
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;
if (has_osd3)
osd_hw.scan_mode[OSD3] = SCAN_MODE_PROGRESSIVE;
osd_hw.scan_mode[viu2_index] = 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;
if (has_osd3)
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;
if (has_osd3)
osd_hw.scan_mode[OSD3] = 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])
osd_hw.scan_mode[OSD1] = SCAN_MODE_PROGRESSIVE;
if (osd_hw.osd_afbcd[OSD1].enable)
osd_hw.scan_mode[OSD1] = SCAN_MODE_PROGRESSIVE;
if (osd_hw.scan_mode[OSD1] == SCAN_MODE_INTERLACE)
index |= 1 << OSD1;
if (osd_hw.scan_mode[OSD2] == SCAN_MODE_INTERLACE)
index |= 1 << OSD2;
} else {
int i;
for (i = 0; i < osd_hw.osd_meson_dev.viu1_osd_count; i++) {
if (osd_hw.free_scale_enable[i])
osd_hw.scan_mode[i] = SCAN_MODE_PROGRESSIVE;
if (osd_hw.osd_afbcd[i].enable)
osd_hw.scan_mode[i] = SCAN_MODE_PROGRESSIVE;
if (osd_hw.scan_mode[i] == SCAN_MODE_INTERLACE)
index |= 1 << i;
}
}
if (osd_hw.scan_mode[OSD1] == SCAN_MODE_INTERLACE ||
osd_hw.scan_mode[OSD2] == SCAN_MODE_INTERLACE)
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;
output_type = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) & 0x3;
osd_hw.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 */
osd_hw.scan_mode[viu2_index] =
SCAN_MODE_INTERLACE;
break;
case VOUT_ENCI:
if (osd_reg_read(ENCI_VIDEO_EN) & 1)
osd_hw.scan_mode[viu2_index] =
SCAN_MODE_INTERLACE;
break;
}
}
if (osd_hw.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_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
(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:
{
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:
{
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;
}
/*************** 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];
}
#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) {
osd_update_vsync_timestamp();
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->width == 3840 &&
vinfo->height == 2160) ||
(vinfo->width == 4096 &&
vinfo->height == 2160)) {
osd_hw.field_out_en[output_index] = 0;
} else if ((vinfo->width == 720 &&
vinfo->height == 480) ||
(vinfo->width == 720 &&
vinfo->height == 576)) {
if (osd_auto_adjust_filter) {
osd_h_filter_mode = 6;
osd_v_filter_mode = 6;
}
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
(VIU_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
(VIU_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_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/graphcis/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)
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;
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;
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_setting_default_hwc();
}
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) {
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;
}
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);
}
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_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)
{
/* 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.t7_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);
#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);
#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_capbility(u32 index)
{
u32 capbility = 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)
capbility |= 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)
capbility |= 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)
capbility |= OSD_LAYER_ENABLE | vpp_top;
} else if (osd_hw.osd_meson_dev.osd_ver == OSD_NORMAL) {
if (index == OSD1)
capbility |= OSD_LAYER_ENABLE | OSD_FREESCALE
| OSD_VIU1 | (afbc ? OSD_AFBC : 0);
else if (index == OSD2)
capbility |= OSD_LAYER_ENABLE |
OSD_HW_CURSOR | OSD_FREESCALE
| OSD_UBOOT_LOGO | OSD_VIU1 |
(afbc ? OSD_AFBC : 0);
}
return capbility;
}
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",
VIU_OSD_BLEND_DIN0_SCOPE_H + 2 * index,
osd_blend_reg->osd_blend_din_scope_h[index],
VIU_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 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);
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 dim layer */
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;
} 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;
get_video_axis_offset(&x_offset, &y_offset);
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;
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.t7_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;
}
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)
osd_setting_blend(output_index);
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);
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);
}
}
/* 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]);
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;
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
hsc_ini_rcv_num = hf_bank_len;
hsc_ini_rpt_p0_num = hf_bank_len / 2 - 1;
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++;
}
if (osd_hw.free_scale_enable[index]) {
data32 = (((src_h - 1) & 0x1fff)
| ((src_w - 1) & 0x1fff) << 16);
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(osd_reg->osd_sci_wh_m1, data32);
data32 = ((osd_hw.free_dst_data[index].x_end & 0xfff) |
(osd_hw.free_dst_data[index].x_start & 0xfff) << 16);
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(osd_reg->osd_sco_h_start_end, data32);
data32 = ((osd_hw.free_dst_data[index].y_end & 0xfff) |
(osd_hw.free_dst_data[index].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,
0, 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 osd_update_color_mode(u32 index)
{
u32 data32 = 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;
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;
data32 |= osd_hw.color_info[index]->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.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) {
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) {
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) {
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) {
/* 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.t7_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)
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(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))
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(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;
}
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;
const struct vinfo_s *vinfo = NULL;
int out_y_crop_start, out_y_crop_end;
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;
#ifdef CONFIG_AMLOGIC_VOUT2_SERVE
vinfo = get_current_vinfo2();
#endif
if (!vinfo) {
osd_log_err("current vinfo NULL\n");
return;
}
out_y_crop_start = 0;
out_y_crop_end = vinfo->height;
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) {
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));
}
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);
if (index >= osd_hw.osd_meson_dev.viu1_osd_count) {
osd_log_err("error osd index=%d\n", index);
return -1;
}
if (index == OSD1) {
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);
/* it is setting for osdx */
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(VIU_OSD_BLEND_DIN0_SCOPE_H +
reg_offset * index,
bld_osd_h_end << 16 |
bld_osd_h_start);
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(VIU_OSD_BLEND_DIN0_SCOPE_V +
reg_offset * 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]) {
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;
}
/* setting blend scope */
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(VPP_OSD1_BLD_H_SCOPE,
osd1_h_start << 16 | osd1_h_end);
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(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.t7_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:
/* 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_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.t7_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.t7_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.t7_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.t7_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;
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);
}
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;
/* interleaced 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);
}
/* 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_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(VPP_OSD1_BLD_H_SCOPE,
vpp0_blend_reg->osd1_h_start << 16 |
vpp0_blend_reg->osd1_h_end);
VSYNCOSD_WR_MPEG_REG(VPP_OSD1_BLD_V_SCOPE,
vpp0_blend_reg->osd1_v_start << 16 |
vpp0_blend_reg->osd1_v_end);
VSYNCOSD_WR_MPEG_REG(VPP_OSD2_BLD_H_SCOPE,
vpp0_blend_reg->osd2_h_start << 16 |
vpp0_blend_reg->osd2_h_end);
VSYNCOSD_WR_MPEG_REG(VPP_OSD2_BLD_V_SCOPE,
vpp0_blend_reg->osd2_v_start << 16 |
vpp0_blend_reg->osd2_v_end);
/* vpp osd1 blend ctrl */
VSYNCOSD_WR_MPEG_REG(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)
VSYNCOSD_WR_MPEG_REG(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_osd_blend_reg(struct osd_blend_reg_s *osd_blend_reg)
{
int i;
u32 reg_offset = 2;
u32 osd_count = OSD_BLEND_LAYERS;
u32 dv_core2_hsize;
u32 dv_core2_vsize;
u32 osd1_alpha_div = 0, osd2_alpha_div = 0;
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);
if (osd_hw.blend_bypass[OSD1])
osd_blend_reg->din0_byp_blend = 1;
/* osd blend ctrl */
VSYNCOSD_WR_MPEG_REG
(VIU_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(VIU_OSD_BLEND_CTRL1,
(osd1_alpha_div & 0x1) |
(3 << 4) |
((osd2_alpha_div & 0x1) << 12) |
(3 << 16));
VSYNCOSD_WR_MPEG_REG(VIU_OSD_BLEND_BLEND0_SIZE,
osd_blend_reg->osd_blend_blend0_size);
/* hdr input size should set to osd blend0 output size */
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);
VSYNCOSD_WR_MPEG_REG(VIU_OSD_BLEND_BLEND1_SIZE,
osd_blend_reg->osd_blend_blend1_size);
for (i = 0; i < osd_count; i++) {
if (osd_hw.enable[i]) {
VSYNCOSD_WR_MPEG_REG
(VIU_OSD_BLEND_DIN0_SCOPE_H +
reg_offset * i,
osd_blend_reg->osd_blend_din_scope_h[i]);
}
if ((osd_blend_reg->osd_blend_din_scope_v[i] & 0xffff0000) == 0)
osd_blend_reg->osd_blend_din_scope_v[i] =
0xffffffff;
VSYNCOSD_WR_MPEG_REG(VIU_OSD_BLEND_DIN0_SCOPE_V +
reg_offset * i,
osd_blend_reg->osd_blend_din_scope_v[i]);
}
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) {
VSYNCOSD_WR_MPEG_REG(DOLBY_CORE2A_SWAP_CTRL1,
((dv_core2_hsize + 0x40) << 16)
| (dv_core2_vsize + 0x80 + 0));
VSYNCOSD_WR_MPEG_REG(DOLBY_CORE2A_SWAP_CTRL2,
(dv_core2_hsize << 16) |
(dv_core2_vsize + 0));
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
update_graphic_width_height(dv_core2_hsize, dv_core2_vsize);
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, reg:%x\n",
__func__,
arg, osd_hw.secure_src,
osd_reg_read(VIU_DATA_SEC));
}
#endif
static int osd_setting_order(u32 output_index)
{
#define RDMA_DETECT_REG VIU_OSD2_TCOLOR_AG0
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;
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);
}
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)
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);
set_blend_reg(blending);
save_blend_reg(blending);
#ifdef CONFIG_AMLOGIC_MEDIA_SECURITY
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:encp line1=%d, line2=%d, total_line=%d\n",
__func__, 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;
}
/* 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.t7_display)
postbld_src3_sel = POSTBLD_OSD1_T7;
else
postbld_src3_sel = POSTBLD_OSD1;
/* 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(VIU_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 */
VSYNCOSD_WR_MPEG_REG(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)
VSYNCOSD_WR_MPEG_REG(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(VIU_OSD_BLEND_DUMMY_DATA0,
0x80 << 16 |
0x80 << 8 |
0x80);
/* used default dummy alpha data */
VSYNCOSD_WR_MPEG_REG(VIU_OSD_BLEND_DUMMY_ALPHA,
0x0 << 20 |
0x0 << 11 |
0x0);
blend_hsize = osd_hw.disp_info[VIU1].background_w;
blend_vsize = osd_hw.disp_info[VIU1].background_h;
VSYNCOSD_WR_MPEG_REG(VIU_OSD_BLEND_BLEND0_SIZE,
blend_vsize << 16 |
blend_hsize);
VSYNCOSD_WR_MPEG_REG(VIU_OSD_BLEND_BLEND1_SIZE,
blend_vsize << 16 |
blend_hsize);
/* hdr input size should set to osd blend0 output size */
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);
}
}
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;
spin_lock_irqsave(&osd_lock, lock_flags);
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);
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] &&
!osd_hw.osd_display_debug[output_index] &&
!suspend_flag) {
osd_hw.reg[OSD_ENABLE]
.update_func(index);
osd_enable = osd_hw.enable[index];
}
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 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;
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.t7_display) {
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_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 =
osd_hw.color_info[index]->color_index;
bool rgbx = false;
/* 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_set_scan_mode(index);
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)
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);
}
/* 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, 8);
/* to vpp_topx */
vppx_blend_reg = &vpp_topx_blend_reg_array[output_index];
osd_set_vpp_path(index + VPP_OSD1, output_index);
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 (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_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);
}
}
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.t7_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++) {
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;
if (i == 1 && 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 (i == 0)
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 buffer_w, buffer_h;
u32 output_index = get_output_device_id(index);
data32 = (osd_hw.dispdata[index].x_start & 0xfff)
| (osd_hw.dispdata[index].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 = ((osd_hw.dispdata[index].y_start >> 1) & 0xfff)
| ((((osd_hw.dispdata[index].y_end + 1)
>> 1) - 1) & 0xfff) << 16;
else
data32 = (osd_hw.dispdata[index].y_start & 0xfff)
| (osd_hw.dispdata[index].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.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)
osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
(osd_reg->mali_afbcd_top_ctrl,
0x1, 16, 1);
else
osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
(osd_reg->mali_afbcd_top_ctrl,
0x1, 21, 1);
}
} 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_boundings_box_x_start_s,
osd_hw.src_data[index].x);
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(osd_reg->afbc_boundings_box_x_end_s,
osd_hw.src_data[index].x +
osd_hw.src_data[index].w - 1);
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(osd_reg->afbc_boundings_box_y_start_s,
osd_hw.src_data[index].y);
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(osd_reg->afbc_boundings_box_y_end_s,
osd_hw.src_data[index].y +
osd_hw.src_data[index].h - 1);
}
} else {
/* osd switch to mali */
if (osd_dev_hw.multi_afbc_core) {
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)
osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
(osd_reg->mali_afbcd_top_ctrl,
0x0, 16, 1);
else
osd_hw.osd_rdma_func[output_index].osd_rdma_wr_bits
(osd_reg->mali_afbcd_top_ctrl,
0x0, 21, 1);
}
} 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);
}
}
if (osd_hw.free_scale_enable[index] &&
osd_hw.free_src_data[index].x_end > 0 &&
osd_hw.free_src_data[index].y_end > 0) {
/* enable osd free scale */
data32 = (osd_hw.free_src_data[index].x_start & 0x1fff) |
(osd_hw.free_src_data[index].x_end & 0x1fff) << 16;
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(osd_reg->osd_blk0_cfg_w1, data32);
data32 = ((osd_hw.free_src_data[index].y_start
+ osd_hw.pandata[index].y_start) & 0x1fff)
| ((osd_hw.free_src_data[index].y_end
+ osd_hw.pandata[index].y_start) & 0x1fff) << 16;
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(osd_reg->osd_blk0_cfg_w2, data32);
} else {
/* normal mode */
data32 = (osd_hw.pandata[index].x_start & 0x1fff)
| (osd_hw.pandata[index].x_end & 0x1fff) << 16;
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(osd_reg->osd_blk0_cfg_w1, data32);
data32 = (osd_hw.pandata[index].y_start & 0x1fff)
| (osd_hw.pandata[index].y_end & 0x1fff) << 16;
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(osd_reg->osd_blk0_cfg_w2, data32);
}
data32 = (osd_hw.src_data[index].x & 0x1fff) |
((osd_hw.src_data[index].x +
osd_hw.src_data[index].w - 1) & 0x1fff) << 16;
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(hw_osd_reg_array[index].osd_blk0_cfg_w1, data32);
buffer_w = ((data32 >> 16) & 0x1fff) - (data32 & 0x1fff) + 1;
data32 = (osd_hw.src_data[index].y & 0x1fff)
| ((osd_hw.src_data[index].y +
osd_hw.src_data[index].h - 1) & 0x1fff) << 16;
osd_hw.osd_rdma_func[output_index].osd_rdma_wr
(osd_reg->osd_blk0_cfg_w2, data32);
buffer_h = ((data32 >> 16) & 0x1fff) - (data32 & 0x1fff) + 1;
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) {
VSYNCOSD_WR_MPEG_REG(DOLBY_CORE2A_SWAP_CTRL1,
((buffer_w + 0x40) << 16)
| (buffer_h + 0x80 + 0));
VSYNCOSD_WR_MPEG_REG(DOLBY_CORE2A_SWAP_CTRL2,
(buffer_w << 16) | (buffer_h + 0));
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
update_graphic_width_height(buffer_w, buffer_h);
#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) {
/* 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)
{
int osd_num = 2;
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_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);
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_AFBCD1_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_AFBCD1_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 multi_afbc_default_path_setting(void)
{
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 osd2 route to vpp0 vsync */
if (osd_index == VPP_OSD3)
osd_reg_set_bits(PATH_START_SEL,
vpp_index, 24, 2);
/* default setting osd3 route to vpp0 vsync */
if (osd_index == VPP_OSD4)
osd_reg_set_bits(PATH_START_SEL,
vpp_index, 28, 2);
}
}
static void set_rdma_func_handler(void)
{
osd_hw.osd_rdma_func[0].osd_rdma_rd =
VSYNCOSD_RD_MPEG_REG;
osd_hw.osd_rdma_func[0].osd_rdma_wr =
VSYNCOSD_WR_MPEG_REG;
osd_hw.osd_rdma_func[0].osd_rdma_wr_bits =
VSYNCOSD_WR_MPEG_REG_BITS;
osd_hw.osd_rdma_func[0].osd_rdma_set_mask =
VSYNCOSD_SET_MPEG_REG_MASK;
osd_hw.osd_rdma_func[0].osd_rdma_clr_mask =
VSYNCOSD_CLR_MPEG_REG_MASK;
osd_hw.osd_rdma_func[0].osd_rdma_wr_irq =
VSYNCOSD_IRQ_WR_MPEG_REG;
osd_hw.osd_rdma_func[1].osd_rdma_rd =
VSYNCOSD_RD_MPEG_REG_VPP1;
osd_hw.osd_rdma_func[1].osd_rdma_wr =
VSYNCOSD_WR_MPEG_REG_VPP1;
osd_hw.osd_rdma_func[1].osd_rdma_wr_bits =
VSYNCOSD_WR_MPEG_REG_BITS_VPP1;
osd_hw.osd_rdma_func[1].osd_rdma_set_mask =
VSYNCOSD_SET_MPEG_REG_MASK_VPP1;
osd_hw.osd_rdma_func[1].osd_rdma_clr_mask =
VSYNCOSD_CLR_MPEG_REG_MASK_VPP1;
osd_hw.osd_rdma_func[1].osd_rdma_wr_irq =
VSYNCOSD_IRQ_WR_MPEG_REG_VPP1;
osd_hw.osd_rdma_func[2].osd_rdma_rd =
VSYNCOSD_RD_MPEG_REG_VPP2;
osd_hw.osd_rdma_func[2].osd_rdma_wr =
VSYNCOSD_WR_MPEG_REG_VPP2;
osd_hw.osd_rdma_func[2].osd_rdma_wr_bits =
VSYNCOSD_WR_MPEG_REG_BITS_VPP2;
osd_hw.osd_rdma_func[2].osd_rdma_set_mask =
VSYNCOSD_SET_MPEG_REG_MASK_VPP2;
osd_hw.osd_rdma_func[2].osd_rdma_clr_mask =
VSYNCOSD_CLR_MPEG_REG_MASK_VPP2;
osd_hw.osd_rdma_func[2].osd_rdma_wr_irq =
VSYNCOSD_IRQ_WR_MPEG_REG_VPP2;
}
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->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) {
/* 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 {
/* 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_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.multi_afbc_core)
backup_regs_init(HW_RESET_MALI_AFBCD_REGS |
HW_RESET_MALI_AFBCD1_REGS |
HW_RESET_MALI_AFBCD2_REGS);
else
backup_regs_init(HW_RESET_MALI_AFBCD_REGS);
} else {
backup_regs_init(HW_RESET_NONE);
}
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;
if (osd_hw.osd_meson_dev.has_rdma)
osd_hw.hw_rdma_en = 1;
} else if (osd_hw.osd_meson_dev.osd_ver == OSD_HIGH_ONE) {
osd_hw.hw_cursor_en = 0;
if (osd_hw.osd_meson_dev.has_rdma)
osd_hw.hw_rdma_en = 1;
/* g12a and g12b need delay */
supsend_delay = 50;
}
/* here we will init default value ,these value only set once . */
if (!logo_loaded) {
if (osd_dev_hw.multi_afbc_core)
multi_afbc_default_path_setting();
/* init vpu fifo control register */
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) {
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_); */
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();
}
if (osd_hw.osd_meson_dev.osd_ver <= OSD_NORMAL) {
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);
osd_set_two_ports(true);
osd_set_vpp_path_default(VPP_OSD3,
get_output_device_id(OSD3));
osd_set_vpp_path_default(VPP_OSD4,
get_output_device_id(OSD4));
}
/* disable deband as default */
if (osd_hw.osd_meson_dev.has_deband)
osd_reg_write(OSD_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]);
}
/* 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;
}
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.osd_ver == OSD_SIMPLE) {
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.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);
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
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_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(VIU_OSD_BLEND_CTRL);
osd_hw.reg_status_save1 =
osd_reg_read(OSD1_BLEND_SRC_CTRL);
osd_hw.reg_status_save3 =
osd_reg_read(VPP_RDARB_REQEN_SLV);
if (!osd_dev_hw.multi_afbc_core)
osd_hw.reg_status_save4 =
osd_reg_read(VPU_MAFBC_SURFACE_CFG);
osd_reg_clr_mask(VIU_OSD_BLEND_CTRL, 0xf0000);
osd_reg_clr_mask(OSD1_BLEND_SRC_CTRL, 0xf0f);
if (!enable_vd_zorder) {
osd_hw.reg_status_save2 =
osd_reg_read(OSD2_BLEND_SRC_CTRL);
osd_reg_clr_mask(OSD2_BLEND_SRC_CTRL, 0xf0f);
}
osd_reg_clr_mask(VPP_RDARB_REQEN_SLV,
rdarb_reqen_slv);
if (!osd_dev_hw.multi_afbc_core) {
osd_reg_write(VPU_MAFBC_SURFACE_CFG, 0);
osd_reg_write(VPU_MAFBC_COMMAND, 1);
}
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) {
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);
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(VIU_OSD_BLEND_CTRL,
osd_hw.reg_status_save);
osd_reg_write(OSD1_BLEND_SRC_CTRL,
osd_hw.reg_status_save1);
if (!enable_vd_zorder)
osd_reg_write(OSD2_BLEND_SRC_CTRL,
osd_hw.reg_status_save2);
osd_reg_write(VPP_RDARB_REQEN_SLV,
osd_hw.reg_status_save3);
if (!osd_dev_hw.multi_afbc_core)
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 prevois 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 prevois 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);
}
}
}