/* * Copyright (c) 2016 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Header file for Exynos DECON driver * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifndef ___SAMSUNG_DECON_H__ #define ___SAMSUNG_DECON_H__ #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CONFIG_EXYNOS_BTS) #include #endif #if defined(CONFIG_EXYNOS_ITMON) #include #endif #if defined(CONFIG_EXYNOS_PD) #include #endif #if defined(CONFIG_SUPPORT_LEGACY_ION) #include #include #endif #include #include /* TODO: SoC dependency will be removed */ #if defined(CONFIG_SOC_EXYNOS9610) #include "./cal_9610/regs-decon.h" #include "./cal_9610/decon_cal.h" #endif #include "./panels/decon_lcd.h" #include "decon_abd.h" #include "dsim.h" #if defined(CONFIG_EXYNOS_DISPLAYPORT) #include "displayport.h" #endif #if defined(CONFIG_SUPPORT_LEGACY_FENCE) #include "../../../../dma-buf/sync_debug.h" #endif #include "hdr_metadata.h" #define SUCCESS_EXYNOS_SMC 0 #define MAX_DECON_CNT 3 #if defined(CONFIG_SUPPORT_LEGACY_ION) extern struct ion_device *ion_exynos; #endif extern struct decon_device *decon_drvdata[MAX_DECON_CNT]; extern int decon_log_level; extern int dpu_bts_log_level; extern int win_update_log_level; extern int dpu_mres_log_level; extern int decon_systrace_enable; extern struct decon_bts_ops decon_bts_control; #define DECON_MODULE_NAME "exynos-decon" #define MAX_NAME_SIZE 32 #define MAX_PLANE_CNT 3 #define MAX_PLANE_ADDR_CNT 4 #define DECON_ENTER_HIBER_CNT 3 #define DECON_ENTER_LPD_CNT 3 #define MIN_BLK_MODE_WIDTH 144 #define MIN_BLK_MODE_HEIGHT 16 #define VSYNC_TIMEOUT_MSEC 200 #define DEFAULT_BPP 32 #define FD_TRY_CNT 3 #define VALID_FD_VAL 3 #define DECON_TRACE_BUF_SIZE 40 #define DECON_WIN_UPDATE_IDX MAX_DECON_WIN #ifndef KHZ #define KHZ (1000) #endif #ifndef MHZ #define MHZ (1000*1000) #endif #ifndef MSEC #define MSEC (1000) #endif #define SHADOW_UPDATE_TIMEOUT (300 * 1000) /* 300ms */ #define IDLE_WAIT_TIMEOUT (50 * 1000) /* 50ms */ #define RUN_WAIT_TIMEOUT IDLE_WAIT_TIMEOUT #define DSC_INIT_XMIT_DELAY 0x200 #define EINT_PEND(x) ((x == 0) ? 2 : ((x == 1) ? 4 : 1)) #define MAX_DSC_SLICE_CNT 4 void dpu_debug_printk(const char *function_name, const char *format, ...); #define decon_err(fmt, ...) \ do { \ if (decon_log_level >= 3) { \ pr_err(pr_fmt("decon: "fmt), ##__VA_ARGS__); \ } \ } while (0) #define decon_warn(fmt, ...) \ do { \ if (decon_log_level >= 4) { \ pr_warn(pr_fmt("decon: "fmt), ##__VA_ARGS__); \ } \ } while (0) #define decon_info(fmt, ...) \ do { \ if (decon_log_level >= 6) \ pr_info(pr_fmt("decon: "fmt), ##__VA_ARGS__); \ } while (0) #define decon_dbg(fmt, ...) \ do { \ if (decon_log_level >= 7) \ pr_info(pr_fmt("decon: "fmt), ##__VA_ARGS__); \ } while (0) #define DPU_DEBUG_WIN(fmt, args...) \ do { \ if (win_update_log_level >= 7) \ dpu_debug_printk("WIN_UPDATE", fmt, ##args); \ } while (0) #define DPU_DEBUG_BTS(fmt, args...) \ do { \ if (dpu_bts_log_level >= 7) \ dpu_debug_printk("BTS", fmt, ##args); \ } while (0) #define DPU_INFO_BTS(fmt, args...) \ do { \ if (dpu_bts_log_level >= 6) \ dpu_debug_printk("BTS", fmt, ##args); \ } while (0) #define DPU_ERR_BTS(fmt, args...) \ do { \ if (dpu_bts_log_level >= 3) \ dpu_debug_printk("BTS", fmt, ##args); \ } while (0) #define DPU_DEBUG_MRES(fmt, args...) \ do { \ if (dpu_mres_log_level >= 7) \ dpu_debug_printk("MRES", fmt, ##args); \ } while (0) #define DPU_INFO_MRES(fmt, args...) \ do { \ if (dpu_mres_log_level >= 6) \ dpu_debug_printk("MRES", fmt, ##args); \ } while (0) #define DPU_ERR_MRES(fmt, args...) \ do { \ if (dpu_mres_log_level >= 3) \ dpu_debug_printk("MRES", fmt, ##args); \ } while (0) /* DECON systrace related */ void tracing_mark_write(struct decon_device *decon, char id, char *str1, int value); #define decon_systrace(decon, id, str1, value) \ do { \ if (decon_systrace_enable) \ tracing_mark_write(decon, id, str1, value); \ } while (0) enum decon_hold_scheme { /* should be set to this value in case of DSIM video mode */ DECON_VCLK_HOLD_ONLY = 0x00, /* should be set to this value in case of DSIM command mode */ DECON_VCLK_RUNNING_VDEN_DISABLE = 0x01, DECON_VCLK_HOLD_VDEN_DISABLE = 0x02, /* should be set to this value in case of HDMI, eDP */ DECON_VCLK_NOT_AFFECTED = 0x03, }; enum decon_win_alpha_coef { BND_COEF_ZERO = 0x0, BND_COEF_ONE = 0x1, BND_COEF_AF = 0x2, BND_COEF_1_M_AF = 0x3, BND_COEF_AB = 0x4, BND_COEF_1_M_AB = 0x5, BND_COEF_PLNAE_ALPHA0 = 0x6, BND_COEF_1_M_PLNAE_ALPHA0 = 0x7, BND_COEF_PLNAE_ALPHA1 = 0x8, BND_COEF_1_M_PLNAE_ALPHA1 = 0x9, BND_COEF_ALPHA_MULT = 0xA, BND_COEF_1_M_ALPHA_MULT = 0xB, }; enum decon_win_alpha_sel { ALPHA_MULT_SRC_SEL_ALPHA0 = 0, ALPHA_MULT_SRC_SEL_ALPHA1 = 1, ALPHA_MULT_SRC_SEL_AF = 2, ALPHA_MULT_SRC_SEL_AB = 3, }; enum decon_merger_mode { DECON_LRM_NO = 0x0, DECON_LRM_NOSWAP_RF = 0x4, DECON_LRM_NOSWAP_LF = 0x5, DECON_LRM_SWAP_RF = 0x6, DECON_LRM_SWAP_LF = 0x7, }; enum decon_te_src { DECON_TE_FROM_DDI0 = 0, DECON_TE_FROM_DDI1, DECON_TE_FROM_DDI2, DECON_TE_FROM_USB, }; /* * DECON_STATE_ON : disp power on, decon/dsim clock on & lcd on * DECON_HIBER : disp power off, decon/dsim clock off & lcd on * DECON_STATE_OFF : disp power off, decon/dsim clock off & lcd off */ enum decon_state { DECON_STATE_INIT = 0, DECON_STATE_ON, DECON_STATE_DOZE, DECON_STATE_HIBER, DECON_STATE_DOZE_SUSPEND, DECON_STATE_OFF, DECON_STATE_TUI, }; /* To find a proper CLOCK ratio */ enum decon_clk_id { CLK_ID_VCLK = 0, CLK_ID_ECLK, CLK_ID_ACLK, CLK_ID_PCLK, CLK_ID_DPLL, /* DPU_PLL */ CLK_ID_RESOLUTION, CLK_ID_MIC_RATIO, CLK_ID_DSC_RATIO, CLK_ID_MAX, }; enum decon_dsc_id { DECON_DSC_ENC0 = 0x0, DECON_DSC_ENC1 = 0x1, DECON_DSC_ENC2 = 0x2, }; enum decon_share_path { SHAREPATH_DQE_USE = 0x0, SHAREPATH_VG0_USE = 0x1, SHAREPATH_VG1_USE = 0x2, SHAREPATH_VGF1_USE = 0x3, SHAREPATH_VGF0_USE = 0x4, }; enum dpp_rotate { DPP_ROT_NORMAL = 0x0, DPP_ROT_XFLIP, DPP_ROT_YFLIP, DPP_ROT_180, DPP_ROT_90, DPP_ROT_90_XFLIP, DPP_ROT_90_YFLIP, DPP_ROT_270, }; enum dpp_csc_eq { /* eq_mode : 6bits [5:0] */ CSC_STANDARD_SHIFT = 0, CSC_BT_601 = 0, CSC_BT_709 = 1, CSC_BT_2020 = 2, CSC_DCI_P3 = 3, CSC_STANDARD_UNSPECIFIED = 63, /* eq_mode : 3bits [8:6] */ CSC_RANGE_SHIFT = 6, CSC_RANGE_LIMITED = 0x0, CSC_RANGE_FULL = 0x1, CSC_RANGE_UNSPECIFIED = 7, }; enum dpp_comp_src { DPP_COMP_SRC_NONE = 0, DPP_COMP_SRC_G2D, DPP_COMP_SRC_GPU }; enum dpp_hdr_standard { DPP_HDR_OFF = 0, DPP_HDR_ST2084, DPP_HDR_HLG, }; struct decon_clocks { unsigned long decon[CLK_ID_DPLL + 1]; }; struct decon_dma_buf_data { #if defined(CONFIG_SUPPORT_LEGACY_ION) struct ion_handle *ion_handle; #endif struct dma_buf *dma_buf; struct dma_buf_attachment *attachment; struct sg_table *sg_table; dma_addr_t dma_addr; #if defined(CONFIG_SUPPORT_LEGACY_FENCE) struct sync_file *fence; #else struct dma_fence *fence; #endif }; struct decon_win_rect { int x; int y; u32 w; u32 h; }; struct decon_rect { u32 left; u32 top; u32 right; u32 bottom; }; struct dpp_params { dma_addr_t addr[MAX_PLANE_CNT]; enum dpp_rotate rot; enum dpp_csc_eq eq_mode; enum dpp_comp_src comp_src; enum dpp_hdr_standard hdr_std; u32 min_luminance; u32 max_luminance; }; struct decon_frame { int x; int y; u32 w; u32 h; u32 f_w; u32 f_h; }; struct decon_win_config { enum { DECON_WIN_STATE_DISABLED = 0, DECON_WIN_STATE_COLOR, DECON_WIN_STATE_BUFFER, DECON_WIN_STATE_UPDATE, DECON_WIN_STATE_CURSOR, DECON_WIN_STATE_MRESOL = 0x10000, DECON_WIN_STATE_FINGERPRINT = 0x20000, } state; /* Reusability:This struct is used for IDMA and ODMA */ union { __u32 color; struct { int fd_idma[3]; int acq_fence; int rel_fence; int plane_alpha; enum decon_blending blending; enum decon_idma_type idma_type; enum decon_pixel_format format; struct dpp_params dpp_parm; /* no read area of IDMA */ struct decon_win_rect block_area; struct decon_win_rect transparent_area; struct decon_win_rect opaque_area; /* source framebuffer coordinates */ struct decon_frame src; }; }; /* destination OSD coordinates */ struct decon_frame dst; bool protection; bool compression; }; struct decon_reg_data { u32 num_of_window; int plane_cnt[MAX_DECON_WIN + 1]; struct list_head list; struct decon_rect blender_bg; struct decon_win_config dpp_config[MAX_DECON_WIN + 1]; struct decon_win_rect block_rect[MAX_DECON_WIN]; struct decon_window_regs win_regs[MAX_DECON_WIN]; struct decon_dma_buf_data dma_buf_data[MAX_DECON_WIN + 1][MAX_PLANE_CNT]; #if !defined(CONFIG_SUPPORT_LEGACY_FENCE) struct dma_fence *retire_fence; #endif /* * If window update size is changed, that size has to be applied to * DECON, DSIM and panel in case of below * - full size -> partial size * - partial size -> different partial size * - partial size -> full size * * need_update flag indicates whether changes are applied to hw or not */ bool need_update; /* current update region */ struct decon_rect up_region; /* protected contents playback */ bool protection[MAX_DECON_WIN + 1]; /* cursor async */ bool is_cursor_win[MAX_DECON_WIN]; int cursor_win; #if defined(CONFIG_SUPPORT_MASK_LAYER) bool mask_layer; #endif bool mres_update; u32 lcd_width; u32 lcd_height; int mres_idx; }; struct decon_win_config_extra { int remained_frames; u32 reserved[7]; }; struct decon_win_config_data_old { int retire_fence; int fd_odma; struct decon_win_config config[MAX_DECON_WIN + 1]; }; struct decon_win_config_data { int retire_fence; int fd_odma; struct decon_win_config config[MAX_DECON_WIN + 1]; struct decon_win_config_extra extra; }; enum hwc_ver { HWC_INIT = 0, HWC_1_0 = 1, HWC_2_0 = 2, }; struct decon_disp_info { enum hwc_ver ver; enum decon_psr_mode psr_mode; struct lcd_mres_info mres_info; u32 chip_ver; unsigned char reverved[128]; }; struct dpu_size_info { u32 w_in; u32 h_in; u32 w_out; u32 h_out; }; /** * Display Subsystem event management status. * * These status labels are used internally by the DECON to indicate the * current status of a device with operations. */ typedef enum dpu_event_type { /* Related with FB interface */ DPU_EVT_BLANK = 0, DPU_EVT_UNBLANK, DPU_EVT_ACT_VSYNC, DPU_EVT_DEACT_VSYNC, DPU_EVT_WIN_CONFIG, DPU_EVT_DISP_INFO, /* Related with interrupt */ DPU_EVT_TE_INTERRUPT, DPU_EVT_UNDERRUN, DPU_EVT_DECON_FRAMEDONE, DPU_EVT_DSIM_FRAMEDONE, DPU_EVT_RSC_CONFLICT, DPU_EVT_DSIM_PL_FIFO_EMPTY, DPU_EVT_DSIM_PH_FIFO_EMPTY, DPU_EVT_DSIM_VT_STATUS, DPU_EVT_DSIM_UNDER_RUN, /* Related with async event */ DPU_EVT_UPDATE_HANDLER, DPU_EVT_DSIM_COMMAND, DPU_EVT_TRIG_MASK, DPU_EVT_TRIG_UNMASK, DPU_EVT_FENCE_ACQUIRE, DPU_EVT_FENCE_RELEASE, DPU_EVT_DECON_FRAMEDONE_WAIT, DPU_EVT_DECON_SHUTDOWN, DPU_EVT_DSIM_SHUTDOWN, DPU_EVT_DECON_FRAMESTART, /* Related with DPP */ DPU_EVT_DPP_WINCON, DPU_EVT_DPP_FRAMEDONE, DPU_EVT_DPP_STOP, DPU_EVT_DPP_UPDATE_DONE, DPU_EVT_DPP_SHADOW_UPDATE, DPU_EVT_DPP_SUSPEND, DPU_EVT_DPP_RESUME, /* Related with PM */ DPU_EVT_DECON_SUSPEND, DPU_EVT_DECON_RESUME, DPU_EVT_ENTER_HIBER, DPU_EVT_EXIT_HIBER, DPU_EVT_DSIM_SUSPEND, DPU_EVT_DSIM_RESUME, DPU_EVT_ENTER_ULPS, DPU_EVT_EXIT_ULPS, DPU_EVT_LINECNT_ZERO, /* write-back events */ DPU_EVT_WB_SET_BUFFER, DPU_EVT_WB_SW_TRIGGER, DPU_EVT_DMA_FRAMEDONE, DPU_EVT_DMA_RECOVERY, DPU_EVT_DECON_SET_BUFFER, /* cursor async */ DPU_EVT_CURSOR_POS, DPU_EVT_CURSOR_UPDATE, /* window update */ DPU_EVT_WINUP_UPDATE_REGION, DPU_EVT_WINUP_FLAGS, DPU_EVT_WINUP_APPLY_REGION, DPU_EVT_DOZE, DPU_EVT_DOZE_SUSPEND, DPU_EVT_MAX, /* End of EVENT */ } dpu_event_t; /* Related with Cursor */ struct disp_log_cursor { u32 xpos; u32 ypos; ktime_t elapsed; /* End time - Start time */ }; /* Related with Fence */ #define ACQ_FENCE_LEN 40 struct disp_log_fence { char acq_fence[MAX_DECON_WIN][ACQ_FENCE_LEN]; u32 timeline_value; int timeline_max; }; /* Related with PM */ struct disp_log_pm { u32 pm_status; /* ACTIVE(1) or SUSPENDED(0) */ ktime_t elapsed; /* End time - Start time */ }; /* Related with S3CFB_WIN_CONFIG */ struct decon_update_reg_data { struct decon_window_regs win_regs[MAX_DECON_WIN]; struct decon_win_config win_config[MAX_DECON_WIN + 1]; struct decon_win_rect win; }; /* Related with MIPI COMMAND read/write */ #define DPU_CALLSTACK_MAX 10 struct dsim_log_cmd_buf { u32 id; u8 buf; void *caller[DPU_CALLSTACK_MAX]; }; /* Related with DPP */ struct disp_log_dpp { u32 id; u32 start_cnt; u32 done_cnt; u32 comp; u32 rot; u32 hdr_std; struct decon_frame src; struct decon_frame dst; }; /* Related with window update information */ struct disp_log_winup { struct decon_frame req_region; struct decon_frame adj_region; struct decon_frame apl_region; bool need_update; bool reconfigure; }; /** * struct dpu_log - Display Subsystem Log * This struct includes DECON/DSIM/DPP */ struct dpu_log { ktime_t time; dpu_event_t type; union { struct disp_log_dpp dpp; struct decon_update_reg_data reg; struct dsim_log_cmd_buf cmd_buf; struct disp_log_pm pm; struct disp_log_fence fence; struct disp_log_cursor cursor; struct disp_log_winup winup; } data; }; struct dpu_size_err_info { ktime_t time; struct dpu_size_info info; }; /* Definitions below are used in the DECON */ #define DPU_EVENT_LOG_MAX SZ_512 #define DPU_EVENT_PRINT_MAX (DPU_EVENT_LOG_MAX >> 1) #define DPU_EVENT_LOG_RETRY 3 typedef enum dpu_event_log_level_type { DPU_EVENT_LEVEL_LOW = 0, DPU_EVENT_LEVEL_HIGH, } dpu_log_level_t; /* APIs below are used in the DECON/DSIM/DPP driver */ #define DPU_EVENT_START() ktime_t start = ktime_get() void DPU_EVENT_LOG(dpu_event_t type, struct v4l2_subdev *sd, ktime_t time); void DPU_EVENT_LOG_WINCON(struct v4l2_subdev *sd, struct decon_reg_data *regs); void DPU_EVENT_LOG_CMD(struct v4l2_subdev *sd, u32 cmd_id, unsigned long data); void DPU_EVENT_LOG_CURSOR(struct v4l2_subdev *sd, struct decon_reg_data *regs); /* cursor async */ void DPU_EVENT_LOG_UPDATE_REGION(struct v4l2_subdev *sd, struct decon_frame *req_region, struct decon_frame *adj_region); void DPU_EVENT_LOG_WINUP_FLAGS(struct v4l2_subdev *sd, bool need_update, bool reconfigure); void DPU_EVENT_LOG_APPLY_REGION(struct v4l2_subdev *sd, struct decon_rect *apl_rect); void DPU_EVENT_LOG_FENCE(struct v4l2_subdev *sd, struct decon_reg_data *regs, dpu_event_t type); void DPU_EVENT_SHOW(struct seq_file *s, struct decon_device *decon); int decon_create_debugfs(struct decon_device *decon); void decon_destroy_debugfs(struct decon_device *decon); /* HDR information of panel */ enum decon_hdr_type { HDR_NONE = 0, HDR_DOLBY_VISION = 1, HDR_HDR10 = 2, HDR_HLG = 3, }; struct decon_hdr_capabilities { unsigned int out_types[HDR_CAPA_NUM]; }; struct decon_hdr_capabilities_info { int out_num; int max_luminance; int max_average_luminance; int min_luminance; }; struct decon_resources { int irq; void __iomem *regs; void __iomem *ss_regs; struct clk *aclk; struct clk *dpll; struct clk *pclk; struct clk *eclk; struct clk *eclk_leaf; struct clk *vclk; struct clk *vclk_leaf; struct clk *busp; struct clk *busd; struct clk *busc; struct clk *core; struct pinctrl *pinctrl; struct pinctrl_state *hw_te_on; struct pinctrl_state *hw_te_off; }; struct decon_dt_info { enum decon_psr_mode psr_mode; enum decon_trig_mode trig_mode; enum decon_dsi_mode dsi_mode; enum decon_out_type out_type; int out_idx[MAX_DSIM_CNT]; int max_win; int dft_win; int dft_idma; const char *pd_name; int dpp_cnt; int dsim_cnt; int decon_cnt; int chip_ver; }; struct decon_win { struct decon_device *decon; struct fb_info *fbinfo; struct fb_videomode videomode; struct decon_dma_buf_data dma_buf_data[MAX_PLANE_CNT]; #if defined(CONFIG_FB_TEST) struct decon_dma_buf_data fb_buf_data; #endif int plane_cnt; int idx; int dpp_id; u32 pseudo_palette[16]; }; /* cursor async */ struct decon_user_window { int x; int y; }; struct dpu_afbc_info { dma_addr_t dma_addr[MAX_DECON_WIN]; void *dma_v_addr[MAX_DECON_WIN]; struct dma_buf *dma_buf[MAX_DECON_WIN]; bool is_afbc[MAX_DECON_WIN]; struct sg_table *sg_table[MAX_DECON_WIN]; }; struct decon_debug { void __iomem *eint_pend; struct dentry *debug_root; struct dentry *debug_event; struct dentry *debug_dump; struct dentry *debug_bts; struct dentry *debug_win; struct dentry *debug_systrace; #if defined(CONFIG_DSIM_CMD_TEST) struct dentry *debug_cmd; #endif struct dentry *debug_recovery_cnt; struct dentry *debug_cmd_lp_ref; struct dentry *debug_mres; struct dpu_log *event_log; u32 event_log_cnt; atomic_t event_log_idx; dpu_log_level_t event_log_level; struct dentry *debug_low_persistence; struct dpu_afbc_info prev_afbc_info; struct dpu_afbc_info cur_afbc_info; #if defined(CONFIG_SUPPORT_LEGACY_ION) struct ion_handle *handle[MAX_DECON_WIN][MAX_PLANE_CNT]; #else struct dma_buf *dmabuf[MAX_DECON_WIN][MAX_PLANE_CNT]; #endif int prev_afbc_win_id[MAX_DECON_WIN]; }; struct decon_update_regs { struct mutex lock; struct list_head list; struct list_head saved_list; struct task_struct *thread; struct kthread_worker worker; struct kthread_work work; atomic_t remaining_frame; }; struct decon_vsync { wait_queue_head_t wait; ktime_t timestamp; bool active; int irq_refcount; struct mutex lock; struct task_struct *thread; }; #if defined(CONFIG_EXYNOS_READ_ESD_SOLUTION) struct decon_esd { #define PWR_STATE_RECHECK_TIME 5 #define ESD_SLEEP_TIME 4 struct mutex lock; struct task_struct *thread; }; #endif struct decon_hiber { struct mutex lock; struct task_struct *thread; struct kthread_worker worker; struct kthread_work work; atomic_t trig_cnt; atomic_t block_cnt; void __iomem *cam_status; u32 enter_cnt; u32 exit_cnt; bool enabled; atomic_t remaining_hiber; }; struct decon_win_update { bool enabled; u32 rect_w; u32 rect_h; u32 hori_cnt; u32 verti_cnt; /* previous update region */ struct decon_rect prev_up_region; }; struct decon_bts_ops { void (*bts_init)(struct decon_device *decon); void (*bts_calc_bw)(struct decon_device *decon, struct decon_reg_data *regs); void (*bts_update_bw)(struct decon_device *decon, struct decon_reg_data *regs, u32 is_after); void (*bts_acquire_bw)(struct decon_device *decon); void (*bts_release_bw)(struct decon_device *decon); void (*bts_deinit)(struct decon_device *decon); }; struct decon_bts { bool enabled; u32 resol_clk; u32 peak; u32 total_bw; u32 prev_total_bw; u32 max_disp_freq; u32 prev_max_disp_freq; u64 ppc; #if defined(CONFIG_EXYNOS_BTS) struct decon_bts_bw bw[BTS_DPP_MAX]; /* each decon must know other decon's BW to get overall BW */ u32 ch_bw[3][BTS_DPU_MAX]; enum bts_bw_type type; struct bts_decon_info bts_info; #endif struct decon_bts_ops *ops; struct pm_qos_request mif_qos; struct pm_qos_request int_qos; struct pm_qos_request disp_qos; u32 scen_updated; }; /* cursor async */ struct decon_cursor { struct decon_reg_data regs; struct mutex lock; u32 xpos; u32 ypos; bool unmask; /* if true, cursor unmask period */ bool enabled; }; /* systrace */ struct decon_systrace_data { pid_t pid; }; #if !defined(CONFIG_SUPPORT_LEGACY_FENCE) struct decon_fence { char name[8]; u64 context; atomic_t timeline; spinlock_t lock; }; #endif struct decon_device { int id; enum decon_state state; unsigned int ignore_vsync; struct abd_protect abd; atomic_t ffu_flag; /* first frame update */ #if defined(CONFIG_SUPPORT_MASK_LAYER) bool current_mask_layer; struct decon_reg_data *mask_regs; u32 wait_mask_layer_trigger; wait_queue_head_t wait_mask_layer_trigger_queue; #endif unsigned int partial_force_disable; unsigned long prev_used_dpp; unsigned long cur_using_dpp; unsigned long dpp_err_stat; struct mutex lock; struct mutex pm_lock; spinlock_t slock; #if defined(CONFIG_EXYNOS_READ_ESD_SOLUTION) struct decon_esd esd; #endif #if defined(CONFIG_SUPPORT_LEGACY_ION) struct ion_client *ion_client; #endif #if defined(CONFIG_SUPPORT_LEGACY_FENCE) struct sync_timeline *timeline; int timeline_max; #endif struct v4l2_subdev *out_sd[MAX_DSIM_CNT]; struct v4l2_subdev *dsim_sd[MAX_DSIM_CNT]; /* TODO: MAX_DPP_SUBDEV wil be changed to MAX_DPP_CNT */ struct v4l2_subdev *dpp_sd[MAX_DPP_SUBDEV]; struct v4l2_subdev *displayport_sd; struct v4l2_device v4l2_dev; struct v4l2_subdev sd; struct device *dev; struct decon_dt_info dt; struct decon_win *win[MAX_DECON_WIN]; struct decon_resources res; struct decon_debug d; struct decon_update_regs up; struct decon_vsync vsync; struct decon_lcd *lcd_info; struct decon_win_update win_up; struct decon_hiber hiber; struct decon_bts bts; struct decon_cursor cursor; #if !defined(CONFIG_SUPPORT_LEGACY_FENCE) struct decon_fence fence; #endif int frame_cnt; int frame_cnt_target; wait_queue_head_t wait_vstatus; int eint_status; #ifdef CONFIG_LOGGING_BIGDATA_BUG int eint_pend; #endif u32 prev_protection_bitmask; unsigned long prev_aclk_khz; atomic_t is_shutdown; bool up_list_saved; #if defined(CONFIG_EXYNOS_ITMON) struct notifier_block itmon_nb; bool notified; #endif #if defined(CONFIG_EXYNOS_PD) struct exynos_pm_domain *pm_domain; #endif unsigned long prev_hdr_bits; struct exynos_hdr_static_info prev_hdr_info; enum hwc_ver ver; /* systrace */ struct decon_systrace_data systrace; int update_regs_list_cnt; bool mres_enabled; bool low_persistence; #if defined(CONFIG_EXYNOS_READ_ESD_SOLUTION) atomic_t bypass; struct decon_reg_data last_regs; #endif }; static inline struct decon_device *get_decon_drvdata(u32 id) { return decon_drvdata[id]; } /* register access subroutines */ static inline u32 decon_read(u32 id, u32 reg_id) { struct decon_device *decon = get_decon_drvdata(id); return readl(decon->res.regs + reg_id); } static inline u32 decon_read_mask(u32 id, u32 reg_id, u32 mask) { u32 val = decon_read(id, reg_id); val &= (mask); return val; } static inline void decon_write(u32 id, u32 reg_id, u32 val) { struct decon_device *decon = get_decon_drvdata(id); writel(val, decon->res.regs + reg_id); } static inline void decon_write_mask(u32 id, u32 reg_id, u32 val, u32 mask) { u32 old = decon_read(id, reg_id); val = (val & mask) | (old & ~mask); decon_write(id, reg_id, val); } static inline u32 dsc_read(u32 dsc_id, u32 reg_id) { struct decon_device *decon = get_decon_drvdata(0); u32 dsc_offset = dsc_id ? DSC1_OFFSET : DSC0_OFFSET; return readl(decon->res.regs + dsc_offset + reg_id); } static inline void dsc_write(u32 dsc_id, u32 reg_id, u32 val) { struct decon_device *decon = get_decon_drvdata(0); u32 dsc_offset = dsc_id ? DSC1_OFFSET : DSC0_OFFSET; writel(val, decon->res.regs + dsc_offset + reg_id); } static inline void dsc_write_mask(u32 dsc_id, u32 reg_id, u32 val, u32 mask) { u32 old = dsc_read(dsc_id, reg_id); val = (val & mask) | (old & ~mask); dsc_write(dsc_id, reg_id, val); } static inline u32 sysreg_read(u32 id, u32 reg_id) { struct decon_device *decon = get_decon_drvdata(id); return readl(decon->res.ss_regs + reg_id); } static inline u32 sysreg_read_mask(u32 id, u32 reg_id, u32 mask) { u32 val = sysreg_read(id, reg_id); val &= (mask); return val; } static inline void sysreg_write(u32 id, u32 reg_id, u32 val) { struct decon_device *decon = get_decon_drvdata(id); writel(val, decon->res.ss_regs + reg_id); } static inline void sysreg_write_mask(u32 id, u32 reg_id, u32 val, u32 mask) { u32 old = sysreg_read(id, reg_id); val = (val & mask) | (old & ~mask); sysreg_write(id, reg_id, val); } /* common function API */ bool decon_validate_x_alignment(struct decon_device *decon, int x, u32 w, u32 bits_per_pixel); int decon_wait_for_vsync(struct decon_device *decon, u32 timeout); int decon_check_limitation(struct decon_device *decon, int idx, struct decon_win_config *config); /* DECON to DSI interface functions */ int decon_register_irq(struct decon_device *decon); int decon_get_clocks(struct decon_device *decon); void decon_set_clocks(struct decon_device *decon); int decon_get_out_sd(struct decon_device *decon); int decon_get_pinctrl(struct decon_device *decon); int decon_register_ext_irq(struct decon_device *decon); int decon_create_vsync_thread(struct decon_device *decon); void decon_destroy_vsync_thread(struct decon_device *decon); int decon_create_esd_thread(struct decon_device *decon); void decon_destroy_esd_thread(struct decon_device *decon); int decon_create_psr_info(struct decon_device *decon); void decon_destroy_psr_info(struct decon_device *decon); /* DECON to writeback interface functions */ int decon_wb_register_irq(struct decon_device *decon); void decon_wb_free_irq(struct decon_device *decon); int decon_wb_get_clocks(struct decon_device *decon); void decon_wb_set_clocks(struct decon_device *decon); int decon_wb_get_out_sd(struct decon_device *decon); #if defined(CONFIG_EXYNOS_DISPLAYPORT) /* DECON to DISPLAYPORT interface functions */ int decon_displayport_register_irq(struct decon_device *decon); void decon_displayport_free_irq(struct decon_device *decon); int decon_displayport_create_vsync_thread(struct decon_device *decon); int decon_displayport_get_clocks(struct decon_device *decon); int decon_displayport_get_out_sd(struct decon_device *decon); int decon_displayport_get_hdr_capa(struct decon_device *decon, struct decon_hdr_capabilities *hdr_capa); int decon_displayport_get_hdr_capa_info(struct decon_device *decon, struct decon_hdr_capabilities_info *hdr_capa_info); int decon_displayport_get_config(struct decon_device *dex, struct exynos_displayport_data *displayport_data); int decon_displayport_set_config(struct decon_device *dex, struct exynos_displayport_data *displayport_data); #endif /* window update related function */ #define DPU_FULL_RECT(r, lcd) \ do { \ (r)->left = 0; \ (r)->top = 0; \ (r)->right = (lcd)->xres - 1; \ (r)->bottom = (lcd)->yres - 1; \ } while (0) void dpu_init_win_update(struct decon_device *decon); void dpu_prepare_win_update_config(struct decon_device *decon, struct decon_win_config_data *win_data, struct decon_reg_data *regs); void dpu_set_win_update_config(struct decon_device *decon, struct decon_reg_data *regs); void dpu_set_win_update_partial_size(struct decon_device *decon, struct decon_rect *up_region); /* low persistence mode */ void decon_init_low_persistence_mode(struct decon_device *decon); /* multi-resolution related function */ void dpu_set_mres_config(struct decon_device *decon, struct decon_reg_data *regs); /* internal only function API */ int decon_check_var(struct fb_var_screeninfo *var, struct fb_info *info); int decon_set_par(struct fb_info *info); int decon_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); int decon_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info); int decon_mmap(struct fb_info *info, struct vm_area_struct *vma); u32 wincon(u32 transp_len, u32 a0, u32 a1, int plane_alpha, enum decon_blending blending, int idx); static inline u32 win_start_pos(int x, int y) { return (WIN_STRPTR_Y_F(y) | WIN_STRPTR_X_F(x)); } static inline u32 win_end_pos(int x, int y, u32 xres, u32 yres) { return (WIN_ENDPTR_Y_F(y + yres - 1) | WIN_ENDPTR_X_F(x + xres - 1)); } /* HIBER releated */ int decon_exit_hiber(struct decon_device *decon); int decon_enter_hiber(struct decon_device *decon); int decon_lcd_off(struct decon_device *decon); int decon_register_hiber_work(struct decon_device *decon); int decon_hiber_block_exit(struct decon_device *decon); u32 decon_reg_get_cam_status(void __iomem *cam_status); static inline void decon_hiber_block(struct decon_device *decon) { if (decon) atomic_inc(&decon->hiber.block_cnt); } static inline bool decon_is_hiber_blocked(struct decon_device *decon) { return (atomic_read(&decon->hiber.block_cnt) > 0); } static inline int decon_get_hiber_block_cnt(struct decon_device *decon) { return (atomic_read(&decon->hiber.block_cnt)); } static inline void decon_hiber_unblock(struct decon_device *decon) { if (decon) { if (decon_is_hiber_blocked(decon)) atomic_dec(&decon->hiber.block_cnt); } } static inline void decon_hiber_block_reset(struct decon_device *decon) { if (decon) atomic_set(&decon->hiber.block_cnt, 0); } static inline void decon_hiber_trig_reset(struct decon_device *decon) { if (decon) atomic_set(&decon->hiber.trig_cnt, 0); } static inline bool decon_min_lock_cond(struct decon_device *decon) { return (atomic_read(&decon->hiber.block_cnt) <= 0); } static inline bool is_cam_not_running(struct decon_device *decon) { if (!decon->id) return (!(decon_reg_get_cam_status(decon->hiber.cam_status) & 0xF)); else return true; } static inline bool decon_hiber_enter_cond(struct decon_device *decon) { return ((atomic_read(&decon->hiber.block_cnt) <= 0) && is_cam_not_running(decon) #if defined(CONFIG_EXYNOS_DISPLAYPORT) && is_displayport_not_running() #endif && (!decon->low_persistence) && (atomic_inc_return(&decon->hiber.trig_cnt) > DECON_ENTER_HIBER_CNT)); } static inline void decon_enter_shutdown(struct decon_device *decon) { atomic_inc(&decon->is_shutdown); } static inline bool decon_is_enter_shutdown(struct decon_device *decon) { return atomic_read(&decon->is_shutdown); } static inline void decon_enter_shutdown_reset(struct decon_device *decon) { atomic_set(&decon->is_shutdown, 0); } #if defined(CONFIG_EXYNOS_READ_ESD_SOLUTION) static inline void decon_set_bypass(struct decon_device *decon, bool on) { atomic_set(&decon->bypass, !!on); } static inline void decon_bypass_on(struct decon_device *decon) { atomic_inc(&decon->bypass); } static inline void decon_bypass_off(struct decon_device *decon) { atomic_dec(&decon->bypass); } static inline bool decon_is_bypass(struct decon_device *decon) { return atomic_read(&decon->bypass); } #endif int decon_update_pwr_state(struct decon_device *decon, u32 mode); enum disp_pwr_mode { DISP_PWR_OFF = 0, DISP_PWR_DOZE, DISP_PWR_NORMAL, DISP_PWR_DOZE_SUSPEND, DISP_PWR_MAX, }; typedef int (*set_pwr_state_t)(void *); struct disp_pwr_state { u32 state; set_pwr_state_t set_pwr_state; }; static inline bool IS_DECON_ON_STATE(struct decon_device *decon) { return decon->state == DECON_STATE_INIT || decon->state == DECON_STATE_ON || decon->state == DECON_STATE_DOZE || decon->state == DECON_STATE_TUI; } static inline bool IS_DECON_OFF_STATE(struct decon_device *decon) { return decon->state == DECON_STATE_HIBER || decon->state == DECON_STATE_DOZE_SUSPEND || decon->state == DECON_STATE_OFF; } static inline bool IS_DECON_HIBER_STATE(struct decon_device *decon) { return decon->state == DECON_STATE_HIBER; } /* tui feature support external to security driver(gud) */ int decon_tui_protection(bool tui_en); /* helper functions */ int dpu_get_sd_by_drvname(struct decon_device *decon, char *drvname); u32 dpu_translate_fmt_to_dpp(u32 format); u32 dpu_get_bpp(enum decon_pixel_format fmt); int dpu_get_meta_plane_cnt(enum decon_pixel_format format); int dpu_get_plane_cnt(enum decon_pixel_format format, bool is_hdr); u32 dpu_get_alpha_len(int format); void dpu_unify_rect(struct decon_rect *r1, struct decon_rect *r2, struct decon_rect *dst); void decon_dump(struct decon_device *decon); void decon_to_psr_info(struct decon_device *decon, struct decon_mode_info *psr); void decon_to_init_param(struct decon_device *decon, struct decon_param *p); void decon_create_timeline(struct decon_device *decon, char *name); void decon_create_release_fences(struct decon_device *decon, struct decon_win_config_data *win_data, struct sync_file *sync_file); int decon_create_fence(struct decon_device *decon, struct sync_file **sync_file); #if defined(CONFIG_SUPPORT_LEGACY_FENCE) int decon_wait_fence(struct sync_file *fence); void decon_signal_fence(struct decon_device *decon); #else int decon_wait_fence(struct dma_fence *fence); void decon_signal_fence(struct dma_fence *fence); #endif bool decon_intersect(struct decon_rect *r1, struct decon_rect *r2); int decon_intersection(struct decon_rect *r1, struct decon_rect *r2, struct decon_rect *r3); bool is_decon_rect_differ(struct decon_rect *r1, struct decon_rect *r2); bool is_rgb32(int format); bool is_scaling(struct decon_win_config *config); bool is_full(struct decon_rect *r, struct decon_lcd *lcd); bool is_decon_opaque_format(int format); void __iomem *dpu_get_sysreg_addr(void); void dpu_dump_afbc_info(void); #if defined(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION) void decon_set_protected_content(struct decon_device *decon, struct decon_reg_data *regs); #endif int decon_runtime_suspend(struct device *dev); int decon_runtime_resume(struct device *dev); void decon_dpp_stop(struct decon_device *decon, bool do_reset); /* cursor async mode functions */ void decon_set_cursor_reset(struct decon_device *decon, struct decon_reg_data *regs); void decon_set_cursor_unmask(struct decon_device *decon, bool unmask); void dpu_cursor_win_update_config(struct decon_device *decon, struct decon_reg_data *regs); int decon_set_cursor_win_config(struct decon_device *decon, int x, int y); void dpu_init_cursor_mode(struct decon_device *decon); int dpu_sysmmu_fault_handler(struct iommu_domain *domain, struct device *dev, unsigned long iova, int flags, void *token); #if defined(CONFIG_EXYNOS_PD) int dpu_pm_domain_check_status(struct exynos_pm_domain *pm_domain); #endif int decon_set_out_sd_state(struct decon_device *decon, enum decon_state state); int decon_update_last_regs(struct decon_device *decon, struct decon_reg_data *regs); /* IOCTL commands */ #define S3CFB_SET_VSYNC_INT _IOW('F', 206, __u32) #define S3CFB_DECON_SELF_REFRESH _IOW('F', 207, __u32) #define S3CFB_WIN_CONFIG_OLD _IOW('F', 209, \ struct decon_win_config_data_old) #define S3CFB_WIN_CONFIG _IOW('F', 209, \ struct decon_win_config_data) /* cursor async */ #define DECON_WIN_CURSOR_POS _IOW('F', 222, struct decon_user_window) #define S3CFB_POWER_MODE _IOW('F', 223, __u32) #define EXYNOS_DISP_INFO _IOW('F', 260, \ struct decon_disp_info) #define S3CFB_START_CRC _IOW('F', 270, u32) #define S3CFB_SEL_CRC_BITS _IOW('F', 271, u32) #define S3CFB_GET_CRC_DATA _IOR('F', 272, u32) #define EXYNOS_GET_DISPLAYPORT_CONFIG _IOW('F', 300, \ struct exynos_displayport_data) #define EXYNOS_SET_DISPLAYPORT_CONFIG _IOW('F', 301, \ struct exynos_displayport_data) #define EXYNOS_DPU_DUMP _IOW('F', 302, \ struct decon_win_config_data) /* HDR support */ #define S3CFB_GET_HDR_CAPABILITIES _IOW('F', 400, struct decon_hdr_capabilities) #define S3CFB_GET_HDR_CAPABILITIES_NUM _IOW('F', 401, struct decon_hdr_capabilities_info) /* DPU aclk */ #define EXYNOS_DPU_GET_ACLK _IOR('F', 500, u32) #endif /* ___SAMSUNG_DECON_H__ */