Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,60 @@
config EXYNOS_DECON_8890
bool "Samsung Exynos8890 Display system (VPP, DECON, MIPI, HDMI)"
depends on FB
if EXYNOS_DECON_8890
config USE_VSYNC_SKIP
bool "Vsync Skip Enable"
depends on EXYNOS_DECON_8890
default n
help
Say Y here if you want to enable vsync skip feature for DFS solution.
config EXYNOS_DECON_FB
bool "Samsung DECON Framebuffer driver"
depends on EXYNOS_DECON_8890
select MEDIA_EXYNOS
default y
help
Say Y here if you want support for the DECON in Samsung S5P SoCs.
This device produce image data to one of output interfaces.
config EXYNOS_MIPI_DSI
bool "Samsung Exynos MIPI-DSI driver"
depends on EXYNOS_DECON_8890
default y
help
Enable MIPI-DSI driver.
config DECON_MIPI_DSI_PKTGO
bool "Samsung Exynos MIPI-DSI Packet Go"
depends on EXYNOS_MIPI_DSI
default n
help
Enable/disable MIPI-DSI Packet Go function
config DECON_LPD_DISPLAY
bool "Decon Low Power Display MODE"
depends on EXYNOS_DECON_8890
default n
config FB_WINDOW_UPDATE
bool "DECON window update mode"
depends on EXYNOS_DECON_8890
default n
config DECON_BLOCKING_MODE
bool "DECON blocking mode"
depends on EXYNOS_DECON_8890
default n
config DECON_EVENT_LOG
bool "Display sub-system event logger (DECON/DSIM/VPP)"
depends on DEBUG_INFO && EXYNOS_DECON_8890
default y
source "drivers/video/fbdev/exynos/decon_8890/vpp/Kconfig"
endif
source "drivers/video/fbdev/exynos/decon_8890/panels/Kconfig"

View file

@ -0,0 +1,14 @@
#
# Copyright (c) 2013 Samsung Electronics Co., Ltd.
# http://www.samsung.com
#
# Licensed under GPLv2
#
obj-$(CONFIG_EXYNOS_VPP) += vpp/
obj-$(CONFIG_EXYNOS_MIPI_DSI) += dsim.o
dsim-y += dsim_drv.o dsim_reg_8890.o
obj-$(CONFIG_EXYNOS_DECON_8890) += decon.o
decon-y += decon_core.o decon_f.o decon_s.o decon_t.o decon_dsi.o decon_helper.o decon_bts.o
obj-$(CONFIG_SOC_EXYNOS8890) += decon_reg_8890.o
obj-y += panels/

View file

@ -0,0 +1,857 @@
/*
* Copyright (c) 2014 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 <linux/fb.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/kthread.h>
#include <linux/pm_qos.h>
#include <linux/delay.h>
#include <linux/seq_file.h>
#include <media/v4l2-device.h>
#include <media/videobuf2-core.h>
#include <media/exynos_mc.h>
#include "regs-decon.h"
#include "decon_common.h"
#include "./panels/decon_lcd.h"
extern struct ion_device *ion_exynos;
extern struct decon_device *decon_f_drvdata;
extern struct decon_device *decon_s_drvdata;
extern struct decon_device *decon_t_drvdata;
extern int decon_log_level;
#define NUM_DECON_IPS (3)
#define DRIVER_NAME "decon"
#define MAX_NAME_SIZE 32
#define MAX_DECON_PADS 9
#define DECON_PAD_WB 8
#define MAX_BUF_PLANE_CNT 3
#define DECON_ENTER_LPD_CNT 3
#define MIN_BLK_MODE_WIDTH 144
#define MIN_BLK_MODE_HEIGHT 10
#define VSYNC_TIMEOUT_MSEC 200
#define MAX_BW_PER_WINDOW (2560 * 1600 * 4 * 60)
#define LCD_DEFAULT_BPP 24
#define DECON_TZPC_OFFSET 3
#define MAX_DMA_TYPE 10
#define MAX_FRM_DONE_WAIT 34
#define DISP_UTIL 70
#define DECON_INT_UTIL 65
#ifndef NO_CNT_TH
/* BTS driver defines the Threshold */
#define NO_CNT_TH 10
#endif
#define UNDERRUN_FILTER_INTERVAL_MS 100
#define UNDERRUN_FILTER_INIT 0
#define UNDERRUN_FILTER_IDLE 1
#define DECON_UNDERRUN_THRESHOLD 0
#ifdef CONFIG_FB_WINDOW_UPDATE
#define DECON_WIN_UPDATE_IDX (8)
#define decon_win_update_dbg(fmt, ...) \
do { \
if (decon_log_level >= 7) \
pr_info(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#else
#define decon_win_update_dbg(fmt, ...) while (0)
#endif
#ifndef KHZ
#define KHZ (1000)
#endif
#ifndef MHZ
#define MHZ (1000*1000)
#endif
#define decon_err(fmt, ...) \
do { \
if (decon_log_level >= 3) { \
pr_err(pr_fmt(fmt), ##__VA_ARGS__); \
exynos_ss_printk(fmt, ##__VA_ARGS__); \
} \
} while (0)
#define decon_warn(fmt, ...) \
do { \
if (decon_log_level >= 4) { \
pr_warn(pr_fmt(fmt), ##__VA_ARGS__); \
exynos_ss_printk(fmt, ##__VA_ARGS__); \
} \
} while (0)
#define decon_info(fmt, ...) \
do { \
if (decon_log_level >= 6) \
pr_info(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define decon_dbg(fmt, ...) \
do { \
if (decon_log_level >= 7) \
pr_info(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
/*
* DECON_STATE_ON : disp power on, decon/dsim clock on & lcd on
* DECON_STATE_LPD_ENT_REQ : disp power on, decon/dsim clock on, lcd on & request for LPD
* DECON_STATE_LPD_EXIT_REQ : disp power off, decon/dsim clock off, lcd on & request for LPD exit.
* DECON_STATE_LPD : 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_LPD_ENT_REQ,
DECON_STATE_LPD_EXIT_REQ,
DECON_STATE_LPD,
DECON_STATE_OFF
};
struct exynos_decon_platdata {
enum decon_psr_mode psr_mode;
enum decon_trig_mode trig_mode;
enum decon_dsi_mode dsi_mode;
enum decon_output_type out_type;
int max_win;
int default_win;
};
struct decon_vsync {
wait_queue_head_t wait;
ktime_t timestamp;
bool active;
int irq_refcount;
struct mutex irq_lock;
struct task_struct *thread;
};
/*
* @width: The width of display in mm
* @height: The height of display in mm
*/
struct decon_fb_videomode {
struct fb_videomode videomode;
unsigned short width;
unsigned short height;
u8 cs_setup_time;
u8 wr_setup_time;
u8 wr_act_time;
u8 wr_hold_time;
u8 auto_cmd_rate;
u8 frame_skip:2;
u8 rs_pol:1;
};
struct decon_fb_pd_win {
struct decon_fb_videomode win_mode;
unsigned short default_bpp;
unsigned short max_bpp;
unsigned short virtual_x;
unsigned short virtual_y;
unsigned short width;
unsigned short height;
};
struct decon_dma_buf_data {
struct ion_handle *ion_handle;
struct dma_buf *dma_buf;
struct dma_buf_attachment *attachment;
struct sg_table *sg_table;
dma_addr_t dma_addr;
struct sync_fence *fence;
};
struct decon_win_rect {
int x;
int y;
u32 w;
u32 h;
};
struct decon_resources {
struct clk *dpll;
struct clk *pclk;
struct clk *eclk;
struct clk *eclk_leaf;
struct clk *vclk;
struct clk *vclk_leaf;
};
struct decon_rect {
int left;
int top;
int right;
int bottom;
};
struct decon_win {
struct decon_fb_pd_win windata;
struct decon_device *decon;
struct fb_info *fbinfo;
struct media_pad pad;
struct decon_fb_videomode win_mode;
struct decon_dma_buf_data dma_buf_data[MAX_BUF_PLANE_CNT];
int plane_cnt;
struct fb_var_screeninfo prev_var;
struct fb_fix_screeninfo prev_fix;
int fps;
int index;
int use;
int local;
unsigned long state;
int vpp_id;
u32 pseudo_palette[16];
};
struct decon_user_window {
int x;
int y;
};
struct s3c_fb_user_plane_alpha {
int channel;
unsigned char red;
unsigned char green;
unsigned char blue;
};
struct s3c_fb_user_chroma {
int enabled;
unsigned char red;
unsigned char green;
unsigned char blue;
};
struct s3c_fb_user_ion_client {
int fd[MAX_BUF_PLANE_CNT];
int offset;
};
enum decon_pixel_format {
/* RGB 32bit */
DECON_PIXEL_FORMAT_ARGB_8888 = 0,
DECON_PIXEL_FORMAT_ABGR_8888,
DECON_PIXEL_FORMAT_RGBA_8888,
DECON_PIXEL_FORMAT_BGRA_8888,
DECON_PIXEL_FORMAT_XRGB_8888,
DECON_PIXEL_FORMAT_XBGR_8888,
DECON_PIXEL_FORMAT_RGBX_8888,
DECON_PIXEL_FORMAT_BGRX_8888,
/* RGB 16 bit */
DECON_PIXEL_FORMAT_RGBA_5551,
DECON_PIXEL_FORMAT_RGB_565,
/* YUV422 2P */
DECON_PIXEL_FORMAT_NV16,
DECON_PIXEL_FORMAT_NV61,
/* YUV422 3P */
DECON_PIXEL_FORMAT_YVU422_3P,
/* YUV420 2P */
DECON_PIXEL_FORMAT_NV12,
DECON_PIXEL_FORMAT_NV21,
DECON_PIXEL_FORMAT_NV12M,
DECON_PIXEL_FORMAT_NV21M,
/* YUV420 3P */
DECON_PIXEL_FORMAT_YUV420,
DECON_PIXEL_FORMAT_YVU420,
DECON_PIXEL_FORMAT_YUV420M,
DECON_PIXEL_FORMAT_YVU420M,
DECON_PIXEL_FORMAT_MAX,
};
enum decon_blending {
DECON_BLENDING_NONE = 0,
DECON_BLENDING_PREMULT = 1,
DECON_BLENDING_COVERAGE = 2,
DECON_BLENDING_MAX = 3,
};
enum vpp_rotate {
VPP_ROT_NORMAL = 0x0,
VPP_ROT_XFLIP,
VPP_ROT_YFLIP,
VPP_ROT_180,
VPP_ROT_90,
VPP_ROT_90_XFLIP,
VPP_ROT_90_YFLIP,
VPP_ROT_270,
};
enum vpp_csc_eq {
BT_601_NARROW = 0x0,
BT_601_WIDE,
BT_709_NARROW,
BT_709_WIDE,
};
enum vpp_stop_status {
VPP_STOP_NORMAL = 0x0,
VPP_STOP_LPD,
VPP_STOP_ERR,
};
struct vpp_params {
dma_addr_t addr[MAX_BUF_PLANE_CNT];
enum vpp_rotate rot;
enum vpp_csc_eq eq_mode;
};
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,
} state;
/* Reusability:This struct is used for IDMA and ODMA */
union {
__u32 color;
struct {
int fd_idma[3];
int fence_fd;
int plane_alpha;
enum decon_blending blending;
enum decon_idma_type idma_type;
enum decon_pixel_format format;
struct vpp_params vpp_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;
};
struct decon_reg_data {
struct list_head list;
struct decon_window_regs win_regs[MAX_DECON_WIN];
struct decon_dma_buf_data dma_buf_data[MAX_DECON_WIN + 1][MAX_BUF_PLANE_CNT];
unsigned int bandwidth;
unsigned int num_of_window;
u32 win_overlap_cnt;
u32 bw;
u32 disp_bw;
u32 int_bw;
struct decon_rect overlap_rect;
struct decon_win_config vpp_config[MAX_DECON_WIN + 1];
struct decon_win_rect block_rect[MAX_DECON_WIN];
#ifdef CONFIG_FB_WINDOW_UPDATE
struct decon_win_rect update_win;
bool need_update;
#endif
bool protection[MAX_DECON_WIN];
};
struct decon_win_config_data {
int fence;
int fd_odma;
struct decon_win_config config[MAX_DECON_WIN + 1];
};
union decon_ioctl_data {
struct decon_user_window user_window;
struct s3c_fb_user_plane_alpha user_alpha;
struct s3c_fb_user_chroma user_chroma;
struct decon_win_config_data win_data;
u32 vsync;
};
struct decon_underrun_stat {
int prev_bw;
int prev_int_bw;
int prev_disp_bw;
int chmap;
int fifo_level;
int underrun_cnt;
unsigned long aclk;
unsigned long lh_disp0;
unsigned long mif_pll;
unsigned long used_windows;
};
struct disp_ss_size_info {
u32 w_in;
u32 h_in;
u32 w_out;
u32 h_out;
};
#ifdef CONFIG_DECON_EVENT_LOG
/**
* 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 disp_ss_event_type {
/* Related with FB interface */
DISP_EVT_BLANK = 0,
DISP_EVT_UNBLANK,
DISP_EVT_ACT_VSYNC,
DISP_EVT_DEACT_VSYNC,
DISP_EVT_WIN_CONFIG,
/* Related with interrupt */
DISP_EVT_TE_INTERRUPT,
DISP_EVT_UNDERRUN,
DISP_EVT_DECON_FRAMEDONE,
DISP_EVT_DSIM_FRAMEDONE,
DISP_EVT_RSC_CONFLICT,
/* Related with async event */
DISP_EVT_UPDATE_HANDLER,
DISP_EVT_DSIM_COMMAND,
DISP_EVT_TRIG_MASK,
DISP_EVT_TRIG_UNMASK,
DISP_EVT_DECON_FRAMEDONE_WAIT,
DISP_EVT_DECON_SHUTDOWN,
DISP_EVT_DSIM_SHUTDOWN,
/* Related with VPP */
DISP_EVT_VPP_WINCON,
DISP_EVT_VPP_FRAMEDONE,
DISP_EVT_VPP_STOP,
DISP_EVT_VPP_UPDATE_DONE,
DISP_EVT_VPP_SHADOW_UPDATE,
DISP_EVT_VPP_SUSPEND,
DISP_EVT_VPP_RESUME,
/* Related with PM */
DISP_EVT_DECON_SUSPEND,
DISP_EVT_DECON_RESUME,
DISP_EVT_ENTER_LPD,
DISP_EVT_EXIT_LPD,
DISP_EVT_DSIM_SUSPEND,
DISP_EVT_DSIM_RESUME,
DISP_EVT_ENTER_ULPS,
DISP_EVT_EXIT_ULPS,
DISP_EVT_LINECNT_ZERO,
/* write-back events */
DISP_EVT_WB_SET_BUFFER,
DISP_EVT_WB_SW_TRIGGER,
DISP_EVT_MAX, /* End of EVENT */
} disp_ss_event_t;
/* 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 DISP_CALLSTACK_MAX 4
struct dsim_log_cmd_buf {
u32 id;
u8 buf;
void *caller[DISP_CALLSTACK_MAX];
};
/* Related with VPP */
struct disp_log_vpp {
u32 id;
u32 start_cnt;
u32 done_cnt;
};
/**
* struct disp_ss_log - Display Subsystem Log
* This struct includes DECON/DSIM/VPP
*/
struct disp_ss_log {
ktime_t time;
disp_ss_event_t type;
union {
struct disp_log_vpp vpp;
struct decon_update_reg_data reg;
struct dsim_log_cmd_buf cmd_buf;
struct disp_log_pm pm;
} data;
};
struct disp_ss_size_err_info {
ktime_t time;
struct disp_ss_size_info info;
};
/* Definitions below are used in the DECON */
#define DISP_EVENT_LOG_MAX SZ_2K
#define DISP_EVENT_PRINT_MAX 512
#define DISP_EVENT_SIZE_ERR_MAX 16
typedef enum disp_ss_event_log_level_type {
DISP_EVENT_LEVEL_LOW = 0,
DISP_EVENT_LEVEL_HIGH,
} disp_ss_log_level_t;
/* APIs below are used in the DECON/DSIM/VPP driver */
#define DISP_SS_EVENT_START() ktime_t start = ktime_get()
void DISP_SS_EVENT_LOG(disp_ss_event_t type, struct v4l2_subdev *sd, ktime_t time);
void DISP_SS_EVENT_LOG_WINCON(struct v4l2_subdev *sd, struct decon_reg_data *regs);
void DISP_SS_EVENT_LOG_CMD(struct v4l2_subdev *sd, u32 cmd_id, unsigned long data);
void DISP_SS_EVENT_SHOW(struct seq_file *s, struct decon_device *decon);
void DISP_SS_EVENT_SIZE_ERR_LOG(struct v4l2_subdev *sd, struct disp_ss_size_info *info);
#else /*!*/
#define DISP_SS_EVENT_START(...) do { } while(0)
#define DISP_SS_EVENT_LOG(...) do { } while(0)
#define DISP_SS_EVENT_LOG_WINCON(...) do { } while(0)
#define DISP_SS_EVENT_LOG_CMD(...) do { } while(0)
#define DISP_SS_EVENT_SHOW(...) do { } while(0)
#define DISP_SS_EVENT_SIZE_ERR_LOG(...) do { } while(0)
#endif
/**
* END of CONFIG_DECON_EVENT_LOG
*/
#define MAX_VPP_LOG 10
struct vpp_drm_log {
unsigned long long time;
int decon_id;
int line;
bool protection;
};
/* VPP resource management */
enum decon_dma_state {
DMA_IDLE = 0,
DMA_RSVD,
};
struct dma_rsm {
/* TODO: 1) BLK power & Clk management. 2) locking mechanism */
u32 dma_state[MAX_DMA_TYPE-1];
u32 decon_dma_map[MAX_DMA_TYPE-1];
};
typedef struct decon_device decon_dev;
struct decon_device {
decon_dev *decon[NUM_DECON_IPS];
struct dma_rsm *dma_rsm;
u32 default_idma;
void __iomem *regs;
void __iomem *ss_regs;
void __iomem *eint_pend;
void __iomem *eint_mask;
struct device *dev;
struct exynos_decon_platdata *pdata;
struct media_pad pads[MAX_DECON_PADS];
struct v4l2_subdev sd;
struct decon_win *windows[MAX_DECON_WIN];
struct decon_resources res;
struct v4l2_subdev *output_sd;
struct exynos_md *mdev;
struct mutex update_regs_list_lock;
struct list_head update_regs_list;
struct task_struct *update_regs_thread;
struct kthread_worker update_regs_worker;
struct kthread_work update_regs_work;
struct mutex lpd_lock;
struct work_struct lpd_work;
struct workqueue_struct *lpd_wq;
atomic_t lpd_trig_cnt;
atomic_t lpd_block_cnt;
bool lpd_init_status;
struct ion_client *ion_client;
struct sw_sync_timeline *timeline;
int timeline_max;
struct mutex output_lock;
struct mutex mutex;
spinlock_t slock;
struct decon_vsync vsync_info;
enum decon_state state;
enum decon_output_type out_type;
int out_idx;
u32 prev_bw;
u32 prev_disp_bw;
u32 prev_int_bw;
u32 prev_frame_has_yuv;
u32 cur_frame_has_yuv;
int default_bw;
int cur_overlap_cnt;
int id;
int n_sink_pad;
int n_src_pad;
union decon_ioctl_data ioctl_data;
bool vpp_used[MAX_VPP_SUBDEV];
bool vpp_err_stat[MAX_VPP_SUBDEV];
u32 vpp_usage_bitmask;
struct decon_lcd *lcd_info;
#ifdef CONFIG_FB_WINDOW_UPDATE
struct decon_win_rect update_win;
bool need_update;
#endif
struct decon_underrun_stat underrun_stat;
void __iomem *cam_status[2];
u32 prev_protection_bitmask;
u32 cur_protection_bitmask;
unsigned int irq;
struct dentry *debug_root;
#ifdef CONFIG_DECON_EVENT_LOG
struct dentry *debug_event;
struct disp_ss_log disp_ss_log[DISP_EVENT_LOG_MAX];
atomic_t disp_ss_log_idx;
disp_ss_log_level_t disp_ss_log_level;
u32 disp_ss_size_log_idx;
struct disp_ss_size_err_info disp_ss_size_log[DISP_EVENT_SIZE_ERR_MAX];
#endif
struct pinctrl *pinctrl;
struct pinctrl_state *decon_te_on;
struct pinctrl_state *decon_te_off;
struct pm_qos_request mif_qos;
struct pm_qos_request int_qos;
struct pm_qos_request disp_qos;
u32 disp_cur;
u32 disp_prev;
struct decon_init_bts *bts_init_ops;
int frame_done_cnt_cur;
int frame_done_cnt_target;
int frame_start_cnt_cur;
int frame_start_cnt_target;
wait_queue_head_t wait_frmdone;
wait_queue_head_t wait_vstatus;
ktime_t trig_mask_timestamp;
int frame_idle;
int eint_status;
struct work_struct fifo_irq_work;
struct workqueue_struct *fifo_irq_wq;
int fifo_irq_status;
struct vpp_drm_log vpp_log[MAX_VPP_LOG];
int log_cnt;
int sw_te_wa;
};
static inline struct decon_device *get_decon_drvdata(u32 id)
{
if (id == 0)
return decon_f_drvdata;
else if (id == 1)
return decon_s_drvdata;
else
return decon_t_drvdata;
}
/* register access subroutines */
static inline u32 decon_read(u32 id, u32 reg_id)
{
struct decon_device *decon = get_decon_drvdata(id);
return readl(decon->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->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);
}
/* common function API */
bool decon_validate_x_alignment(struct decon_device *decon, int x, u32 w,
u32 bits_per_pixel);
int create_link_mipi(struct decon_device *decon, int id);
int decon_int_remap_eint(struct decon_device *decon);
int decon_f_register_irq(struct platform_device *pdev, struct decon_device *decon);
int decon_s_register_irq(struct platform_device *pdev, struct decon_device *decon);
int decon_t_register_irq(struct platform_device *pdev, struct decon_device *decon);
irqreturn_t decon_f_irq_handler(int irq, void *dev_data);
irqreturn_t decon_s_irq_handler(int irq, void *dev_data);
irqreturn_t decon_t_irq_handler(int irq, void *dev_data);
int decon_f_get_clocks(struct decon_device *decon);
int decon_s_get_clocks(struct decon_device *decon);
int decon_t_get_clocks(struct decon_device *decon);
void decon_f_set_clocks(struct decon_device *decon);
void decon_s_set_clocks(struct decon_device *decon);
void decon_t_set_clocks(struct decon_device *decon);
int decon_t_set_lcd_info(struct decon_device *decon);
int decon_register_lpd_work(struct decon_device *decon);
int decon_exit_lpd(struct decon_device *decon);
int decon_lpd_block_exit(struct decon_device *decon);
int decon_lcd_off(struct decon_device *decon);
int decon_enable(struct decon_device *decon);
int decon_disable(struct decon_device *decon);
int decon_tui_protection(struct decon_device *decon, bool tui_en);
int decon_wait_for_vsync(struct decon_device *decon, u32 timeout);
/* internal only function API */
int decon_config_eint_for_te(struct platform_device *pdev, struct decon_device *decon);
int decon_f_create_vsync_thread(struct decon_device *decon);
int decon_f_create_psr_thread(struct decon_device *decon);
void decon_f_destroy_vsync_thread(struct decon_device *decon);
void decon_f_destroy_psr_thread(struct decon_device *decon);
int decon_set_lcd_config(struct decon_device *decon);
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);
/* POWER and ClOCK API */
int init_display_decon_clocks(struct device *dev);
int disable_display_decon_clocks(struct device *dev);
void decon_clock_on(struct decon_device *decon);
void decon_clock_off(struct decon_device *decon);
u32 decon_reg_get_cam_status(void __iomem *);
void decon_reg_set_block_mode(u32 id, u32 win_idx, u32 x, u32 y, u32 h, u32 w, u32 enable);
void decon_reg_set_tui_va(u32 id, u32 va);
void decon_vpp_min_lock_release(struct decon_device *decon);
u32 wincon(u32 transp_len, u32 a0, u32 a1, int plane_alpha, enum decon_blending blending);
int find_subdev_mipi(struct decon_device *decon, int id);
#define is_rotation(config) (config->vpp_parm.rot >= VPP_ROT_90)
/* LPD related */
static inline void decon_lpd_block(struct decon_device *decon)
{
if (decon)
atomic_inc(&decon->lpd_block_cnt);
}
static inline bool decon_is_lpd_blocked(struct decon_device *decon)
{
return (atomic_read(&decon->lpd_block_cnt) > 0);
}
static inline int decon_get_lpd_block_cnt(struct decon_device *decon)
{
return (atomic_read(&decon->lpd_block_cnt));
}
static inline void decon_lpd_unblock(struct decon_device *decon)
{
if (decon) {
if (decon_is_lpd_blocked(decon))
atomic_dec(&decon->lpd_block_cnt);
}
}
static inline void decon_lpd_block_reset(struct decon_device *decon)
{
if (decon)
atomic_set(&decon->lpd_block_cnt, 0);
}
static inline void decon_lpd_trig_reset(struct decon_device *decon)
{
if (decon)
atomic_set(&decon->lpd_trig_cnt, 0);
}
static inline bool is_cam_not_running(struct decon_device *decon)
{
if (!decon->id)
return (!((decon_reg_get_cam_status(decon->cam_status[0]) & 0xF) ||
(decon_reg_get_cam_status(decon->cam_status[1]) & 0xF)));
else
return true;
}
static inline bool decon_lpd_enter_cond(struct decon_device *decon)
{
return ((atomic_read(&decon->lpd_block_cnt) <= 0) && is_cam_not_running(decon)
&& (atomic_inc_return(&decon->lpd_trig_cnt) >= DECON_ENTER_LPD_CNT));
}
static inline bool decon_min_lock_cond(struct decon_device *decon)
{
return (atomic_read(&decon->lpd_block_cnt) <= 0);
}
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));
}
/* IOCTL commands */
#define S3CFB_WIN_POSITION _IOW('F', 203, \
struct decon_user_window)
#define S3CFB_WIN_SET_PLANE_ALPHA _IOW('F', 204, \
struct s3c_fb_user_plane_alpha)
#define S3CFB_WIN_SET_CHROMA _IOW('F', 205, \
struct s3c_fb_user_chroma)
#define S3CFB_SET_VSYNC_INT _IOW('F', 206, __u32)
#define S3CFB_GET_ION_USER_HANDLE _IOWR('F', 208, \
struct s3c_fb_user_ion_client)
#define S3CFB_WIN_CONFIG _IOW('F', 209, \
struct decon_win_config_data)
#define S3CFB_WIN_PSR_EXIT _IOW('F', 210, int)
#define DECON_IOC_LPD_EXIT_LOCK _IOW('L', 0, u32)
#define DECON_IOC_LPD_UNLOCK _IOW('L', 1, u32)
#endif /* ___SAMSUNG_DECON_H__ */

View file

@ -0,0 +1,195 @@
/*
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Core file for Samsung 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.
*/
#include "decon_bts.h"
#include "vpp/vpp.h"
#include <soc/samsung/bts.h>
#define MULTI_FACTOR (1 << 10)
#define VPP_MAX 9
#define HALF_MIC 2
#define PIX_PER_CLK 2
#define ROTATION 4
#define NOT_ROT 1
#define RGB_FACTOR 4
#define YUV_FACTOR 4
/* If use float factor, DATA format factor should be multiflied by 2
* And then, should be divided using FORMAT_FACTOR at the end of bw_eq
*/
#define FORMAT_FACTOR 2
#define DISP_FACTOR 1
#define ENUM_OFFSET 2
#ifdef CONFIG_PM_DEVFREQ
void bts_int_mif_bw(struct vpp_dev *vpp)
{
struct decon_win_config *config = vpp->config;
struct decon_frame *src = &config->src;
struct decon_frame *dst = &config->dst;
struct decon_device *decon = get_decon_drvdata(0);
u32 vclk = (clk_get_rate(decon->res.vclk_leaf) * PIX_PER_CLK / MHZ);
/* TODO, parse mic factor automatically at dt */
u32 mic_factor = HALF_MIC; /* 1/2 MIC */
u64 s_ratio_h, s_ratio_v = 0;
/* bpl is multiplied 2, it should be divied at end of eq. */
u8 bpl = 0;
u8 rot_factor = is_rotation(config) ? ROTATION : NOT_ROT;
bool is_rotated = is_rotation(config) ? true : false;
if (is_rgb(config))
bpl = RGB_FACTOR;
else if (is_yuv(config))
bpl = YUV_FACTOR;
else
bpl = RGB_FACTOR;
if (is_rotated) {
s_ratio_h = MULTI_FACTOR * src->h / dst->w;
s_ratio_v = MULTI_FACTOR * src->w / dst->h;
} else {
s_ratio_h = MULTI_FACTOR * src->w / dst->w;
s_ratio_v = MULTI_FACTOR * src->h / dst->h;
}
/* BW = (VCLK * MIC_factor * Data format * ScaleRatio_H * ScaleRatio_V * RotationFactor) */
vpp->cur_bw = vclk * mic_factor * bpl * s_ratio_h * s_ratio_v
* rot_factor * KHZ / (MULTI_FACTOR * MULTI_FACTOR);
}
void bts_disp_bw(struct vpp_dev *vpp)
{
struct decon_win_config *config = vpp->config;
struct decon_frame *src = &config->src;
struct decon_frame *dst = &config->dst;
struct decon_device *decon = get_decon_drvdata(0);
u32 vclk = (clk_get_rate(decon->res.vclk_leaf) * PIX_PER_CLK / MHZ);
/* TODO, parse mic factor automatically at dt */
u32 mic_factor = HALF_MIC; /* 1/2 MIC */
/* TODO, parse lcd width automatically at dt */
u32 lcd_width = 1440;
u64 s_ratio_h, s_ratio_v = 0;
u32 src_w = is_rotation(config) ? src->h : src->w;
u32 src_h = is_rotation(config) ? src->w : src->h;
/* ACLK_DISP_400 [MHz] = (VCLK * MIC_factor * ScaleRatio_H * ScaleRatio_V * disp_factor) / 2 * (DST_width / LCD_width) */
s_ratio_h = (src_w <= dst->w) ? MULTI_FACTOR : MULTI_FACTOR * src_w / dst->w;
s_ratio_v = (src_h <= dst->h) ? MULTI_FACTOR : MULTI_FACTOR * src_h / dst->h;
vpp->disp_cur_bw = vclk * mic_factor * s_ratio_h * s_ratio_v
* DISP_FACTOR * KHZ * (MULTI_FACTOR * dst->w / lcd_width)
/ (MULTI_FACTOR * MULTI_FACTOR * MULTI_FACTOR) / 2;
}
void bts_mif_lock(struct vpp_dev *vpp)
{
struct decon_win_config *config = vpp->config;
if (is_rotation(config)) {
pm_qos_update_request(&vpp->vpp_mif_qos, 1144000);
} else {
pm_qos_update_request(&vpp->vpp_mif_qos, 0);
}
}
void bts_send_bw(struct vpp_dev *vpp, bool enable)
{
struct decon_win_config *config = vpp->config;
u8 vpp_type;
enum vpp_bw_type bw_type;
if (is_rotation(config)) {
if (config->src.w * config->src.h >= FULLHD_SRC)
bw_type = BW_FULLHD_ROT;
else
bw_type = BW_ROT;
} else {
bw_type = BW_DEFAULT;
}
vpp_type = vpp->id + ENUM_OFFSET;
if (enable) {
exynos_update_media_scenario(vpp_type, vpp->cur_bw, bw_type);
} else {
exynos_update_media_scenario(vpp_type, 0, BW_DEFAULT);
vpp->prev_bw = vpp->cur_bw = 0;
}
}
void bts_add_request(struct decon_device *decon)
{
pm_qos_add_request(&decon->mif_qos, PM_QOS_BUS_THROUGHPUT, 0);
pm_qos_add_request(&decon->disp_qos, PM_QOS_DISPLAY_THROUGHPUT, 0);
pm_qos_add_request(&decon->int_qos, PM_QOS_DEVICE_THROUGHPUT, 0);
}
void bts_send_init(struct decon_device *decon)
{
pm_qos_update_request(&decon->mif_qos, 546000);
}
void bts_send_release(struct decon_device *decon)
{
pm_qos_update_request(&decon->mif_qos, 0);
pm_qos_update_request(&decon->disp_qos, 0);
pm_qos_update_request(&decon->int_qos, 0);
decon->disp_cur = decon->disp_prev = 0;
}
void bts_remove_request(struct decon_device *decon)
{
pm_qos_remove_request(&decon->mif_qos);
pm_qos_remove_request(&decon->disp_qos);
pm_qos_remove_request(&decon->int_qos);
}
void bts_calc_bw(struct vpp_dev *vpp)
{
bts_disp_bw(vpp);
bts_int_mif_bw(vpp);
}
void bts_send_zero_bw(struct vpp_dev *vpp)
{
bts_send_bw(vpp, false);
}
void bts_send_calc_bw(struct vpp_dev *vpp)
{
bts_send_bw(vpp, true);
}
#else
void bts_add_request(struct decon_device *decon){ return; }
void bts_send_init(struct decon_device *decon){ return; }
void bts_send_release(struct decon_device *decon){ return; }
void bts_remove_request(struct decon_device *decon){ return; }
void bts_calc_bw(struct vpp_dev *vpp){ return; }
void bts_send_calc_bw(struct vpp_dev *vpp){ return; }
void bts_send_zero_bw(struct vpp_dev *vpp){ return; }
void bts_mif_lock(struct vpp_dev *vpp){ return; }
#endif
struct decon_init_bts decon_init_bts_control = {
.bts_add = bts_add_request,
.bts_set_init = bts_send_init,
.bts_release_init = bts_send_release,
.bts_remove = bts_remove_request,
};
struct decon_bts decon_bts_control = {
.bts_get_bw = bts_calc_bw,
.bts_set_calc_bw = bts_send_calc_bw,
.bts_set_zero_bw = bts_send_zero_bw,
.bts_set_rot_mif = bts_mif_lock,
};

View file

@ -0,0 +1,64 @@
/* linux/drivers/video/exynos/decon/decon_bts.h
*
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* header file for Samsung EXYNOS5 SoC series 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 DECON_BTS_H_
#define DECON_BTS_H_
#include <linux/clk-provider.h>
#include <linux/clk.h>
#include "decon.h"
#include "vpp/vpp.h"
#define call_bts_ops(q, op, args...) \
(((q)->bts_ops->op) ? ((q)->bts_ops->op(args)) : 0)
#define call_init_ops(q, op, args...) \
(((q)->bts_init_ops->op) ? ((q)->bts_init_ops->op(args)) : 0)
extern struct decon_bts decon_bts_control;
extern struct decon_init_bts decon_init_bts_control;
struct decon_init_bts {
void (*bts_add)(struct decon_device *decon);
void (*bts_set_init)(struct decon_device *decon);
void (*bts_release_init)(struct decon_device *decon);
void (*bts_remove)(struct decon_device *decon);
};
struct decon_bts {
void (*bts_get_bw)(struct vpp_dev *vpp);
void (*bts_set_calc_bw)(struct vpp_dev *vpp);
void (*bts_set_zero_bw)(struct vpp_dev *vpp);
void (*bts_set_rot_mif)(struct vpp_dev *vpp);
};
/* You should sync between enum init value of enum 'VPP0 = 2' and bts_media_type in bts driver */
enum disp_media_type {
VPP0 = 2,
VPP1,
VPP2,
VPP3,
VPP4,
VPP5,
VPP6,
VPP7,
VPP8,
};
#define is_rotation(config) (config->vpp_parm.rot >= VPP_ROT_90)
#define is_yuv(config) ((config->format >= DECON_PIXEL_FORMAT_NV16) && (config->format < DECON_PIXEL_FORMAT_MAX))
#define is_rgb(config) ((config->format >= DECON_PIXEL_FORMAT_ARGB_8888) && (config->format <= DECON_PIXEL_FORMAT_RGB_565))
#define is_scaling(vpp) ((vpp->h_ratio != (1 << 20)) || (vpp->v_ratio != (1 << 20)))
#define is_scale_down(vpp) ((vpp->h_ratio > (1 << 20)) || (vpp->v_ratio > (1 << 20)))
#endif

View file

@ -0,0 +1,313 @@
/*
* decon_common.h
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Header file for Exynos DECON driver for exynos8890
*
* 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_COMMON_H__
#define ___SAMSUNG_DECON_COMMON_H__
#include "./panels/decon_lcd.h"
#define MAX_DECON_WIN 8
#define MAX_VPP_SUBDEV 9
#define SHADOW_UPDATE_TIMEOUT (300 * 1000) /* 300ms */
enum decon_trig_mode {
DECON_HW_TRIG = 0,
DECON_SW_TRIG
};
enum decon_output_type {
DECON_OUT_DSI = 0,
DECON_OUT_EDP,
DECON_OUT_HDMI,
DECON_OUT_WB,
DECON_OUT_TUI
};
enum decon_dsi_mode {
DSI_MODE_SINGLE = 0,
DSI_MODE_DUAL_DSI,
DSI_MODE_DUAL_DISPLAY,
DSI_MODE_NONE
};
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_rgb_order {
DECON_RGB = 0x0,
DECON_GBR = 0x1,
DECON_BRG = 0x2,
DECON_BGR = 0x4,
DECON_RBG = 0x5,
DECON_GRB = 0x6,
};
/* Porter Duff Compositing Operators */
enum decon_win_func {
PD_FUNC_CLEAR = 0x0,
PD_FUNC_COPY = 0x1,
PD_FUNC_DESTINATION = 0x2,
PD_FUNC_SOURCE_OVER = 0x3,
PD_FUNC_DESTINATION_OVER = 0x4,
PD_FUNC_SOURCE_IN = 0x5,
PD_FUNC_DESTINATION_IN = 0x6,
PD_FUNC_SOURCE_OUT = 0x7,
PD_FUNC_DESTINATION_OUT = 0x8,
PD_FUNC_SOURCE_A_TOP = 0x9,
PD_FUNC_DESTINATION_A_TOP = 0xa,
PD_FUNC_XOR = 0xb,
PD_FUNC_PLUS = 0xc,
PD_FUNC_LEGACY = 0xd,
};
enum decon_win_alpha_sel {
/* for plane blending */
W_ALPHA_SEL_F_ALPAH0 = 0,
W_ALPHA_SEL_F_ALPAH1 = 1,
/* for pixel blending */
W_ALPHA_SEL_F_BYAEN = 2,
/* for multiplied alpha */
W_ALPHA_SEL_F_BYMUL = 4,
};
enum decon_set_trig {
DECON_TRIG_DISABLE = 0,
DECON_TRIG_ENABLE
};
enum decon_idma_type {
IDMA_G0 = 0, /* Dedicated to WIN7 */
IDMA_G1,
IDMA_VG0,
IDMA_VG1,
IDMA_G2,
IDMA_G3,
IDMA_VGR0,
IDMA_VGR1,
ODMA_WB,
IDMA_G0_S,
};
struct decon_mode_info {
enum decon_psr_mode psr_mode;
enum decon_trig_mode trig_mode;
enum decon_output_type out_type;
enum decon_dsi_mode dsi_mode;
};
struct decon_param {
struct decon_mode_info psr;
struct decon_lcd *lcd_info;
u32 nr_windows;
void __iomem *disp_ss_regs;
};
struct decon_window_regs {
u32 wincon;
u32 start_pos;
u32 end_pos;
u32 colormap;
u32 start_time;
u32 pixel_count;
/* OS used */
u32 whole_w;
u32 whole_h;
u32 offset_x;
u32 offset_y;
u32 winmap_state;
enum decon_idma_type type;
};
/* 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, /* DISP_PLL */
CLK_ID_RESOLUTION,
CLK_ID_MIC_RATIO,
CLK_ID_DSC_RATIO,
CLK_ID_MAX,
};
struct decon_clocks {
unsigned long decon[CLK_ID_DPLL + 1];
};
enum decon_data_path {
/* BLENDER-OUT -> No Comp -> SPLITTER(bypass) -> u0_FF -> u0_DISPIF */
DATAPATH_NOCOMP_SPLITTERBYPASS_U0FF_DISP0 = 0x01,
/* BLENDER-OUT -> No Comp -> SPLITTER(bypass) -> u1_FF -> u1_DISPIF */
DATAPATH_NOCOMP_SPLITTERBYPASS_U1FF_DISP1 = 0x02,
/* BLENDER-OUT -> No Comp -> SPLITTER(split) -> u0_FF/u1_FF -> u0_DISPIF/u1_DISPIF */
DATAPATH_NOCOMP_SPLITTER_U0FFU1FF_DISP0DISP1 = 0x03,
/* BLENDER-OUT -> MIC -> SPLITTER(bypass) -> u0_FF -> u0_DISPIF */
DATAPATH_MIC_SPLITTERBYPASS_U0FF_DISP0 = 0x09,
/* BLENDER-OUT -> MIC -> SPLITTER(bypass) -> u1_FF -> u1_DISPIF */
DATAPATH_MIC_SPLITTERBYPASS_U1FF_DISP1 = 0x0A,
/* BLENDER-OUT -> MIC -> SPLITTER(split) -> u0_FF/u1_FF -> u0_DISPIF/u1_DISPIF */
DATAPATH_MIC_SPLITTER_U0FFU1FF_DISP0DISP1 = 0x0B,
/* BLENDER-OUT -> DSCC,ENC0/1 -> u0_FF/u1_FF -> u_MERGER -> u0_DISPIF */
DATAPATH_DSCC_ENC0ENC1_U0FFU1FF_MERGER_DISP0 = 0x11,
/* BLENDER-OUT -> DSCC,ENC0/1 -> u0_FF/u1_FF -> u_MERGER -> u1_DISPIF */
DATAPATH_DSCC_ENC0ENC1_U0FFU1FF_MERGER_DISP1 = 0x12,
/* BLENDER-OUT -> DSCC,ENC0/1 -> u0_FF/u1_FF -> u0_DISPIF/u1_DISPIF */
DATAPATH_DSCC_ENC0ENC1_U0FFU1FF_DISP0DISP1 = 0x13,
/* BLENDER-OUT -> ENC0 -> SPLITTER(bypass) -> u0_FF u0_DISPIF */
DATAPATH_ENC0_SPLITTERBYPASS_U0FF_DISP0 = 0x21,
/* BLENDER-OUT -> ENC0 -> SPLITTER(bypass) -> u1_FF u1_DISPIF */
DATAPATH_ENC0_SPLITTERBYPASS_U1FF_DISP1 = 0x22,
/* BLENDER-OUT -> ENC0 -> SPLITTER(split) -> u0_FF/u1_FF -> u0_DISPIF/u1_DISPIF */
DATAPATH_ENC0_SPLITTER_U0FFU1FF_DISP0DISP1 = 0x23,
/* BLENDER-OUT -> No Comp -> SPLITTER(bypass) -> u0_FF -> POST-WB */
DATAPATH_NOCOMP_SPLITTERBYPASS_U0FF_POSTWB = 0x04,
/* BLENDER-OUT -> MIC -> SPLITTER(bypass) -> u0_FF -> POST-WB */
DATAPATH_MIC_SPLITTERBYPASS_U0FF_POSTWB = 0x0C,
/* BLENDER-OUT -> DSCC,ENC0/1 -> u0_FF/u1_FF -> u_MERGER -> POST-WB */
DATAPATH_DSCC_ENC0ENC1_U0FFU1FF_MERGER_POSTWB = 0x14,
/* BLENDER-OUT -> ENC0 -> SPLITTER(bypass) -> u0_FF -> POST-WB */
DATAPATH_ENC0_SPLITTERBYPASS_U0FF_POSTWB = 0x24,
/* u0_DISPIF (mapcolor mode) */
DATAPATH_DISP0_COLORMAP = 0x41,
/* u1_DISPIF (mapcolor mode) */
DATAPATH_DISP1_COLORMAP = 0x42,
/* u0_DISPIF/u1_DISPIF (mapcolor mode) */
DATAPATH_DISP0DISP1_ColorMap = 0x43,
/* PRE-WB & BLENDER-OUT -> No Comp -> SPLITTER(bypass) -> u0_FF -> u0_DISPIF */
DATAPATH_PREWB_NOCOMP_SPLITTERBYPASS_U0FF_DISP0 = 0x81,
/* PRE-WB & BLENDER-OUT -> No Comp -> SPLITTER(bypass) -> u1_FF -> u1_DISPIF */
DATAPATH_PREWB_NOCOMP_SPLITTERBYPASS_U1FF_DISP1 = 0x82,
/* PRE-WB & BLENDER-OUT -> No Comp -> SPLITTER(split) -> u0_FF/u1_FF -> u0_DISPIF/u1_DISPIF */
DATAPATH_PREWB_NOCOMP_SPLITTER_U0FFU1FF_DISP0DISP1 = 0x83,
/* PRE-WB & BLENDER-OUT -> MIC -> SPLITTER(bypass) -> u0_FF -> u0_DISPIF */
DATAPATH_PREWB_MIC_SPLITTERBYPASS_U0FF_DISP0 = 0x89,
/* PRE-WB & BLENDER-OUT -> MIC -> SPLITTER(bypass) -> u1_FF -> u1_DISPIF */
DATAPATH_PREWB_MIC_SPLITTERBYPASS_U1FF_DISP1 = 0x8A,
/* PRE-WB & BLENDER-OUT -> MIC -> SPLITTER(split) -> u0_FF/u1_FF -> u0_DISPIF/u1_DISPIF */
DATAPATH_PREWB_MIC_SPLITTER_U0FFU1FF_DISP0DISP1 = 0x8B,
/* PRE-WB & BLENDER-OUT -> DSCC,ENC0/1 -> u0_FF/u1_FF -> u_MERGER -> u0_DISPIF */
DATAPATH_PREWB_DSCC_ENC0ENC1_U0FFU1FF_MERGER_DISP0 = 0x91,
/* PRE-WB & BLENDER-OUT -> DSCC,ENC0/1 -> u0_FF/u1_FF -> u_MERGER -> u1_DISPIF */
DATAPATH_PREWB_DSCC_ENC0ENC1_U0FFU1FF_MERGER_DISP1 = 0x92,
/* PRE-WB & BLENDER-OUT -> DSCC,ENC0/1 -> u0_FF/u1_FF -> u0_DISPIF/u1_DISPIF */
DATAPATH_PREWB_DSCC_ENC0ENC1_U0FFU1FF_DISP0DISP1 = 0x93,
/* PRE-WB & BLENDER-OUT -> ENC0 -> SPLITTER(bypass) -> u0_FF -> u0_DISPIF */
DATAPATH_PREWB_ENC0_SPLITTERBYPASS_U0FF_DISP0 = 0xA1,
/* PRE-WB & BLENDER-OUT -> ENC0 -> SPLITTER(bypass) -> u1_FF -> u1_DISPIF */
DATAPATH_PREWB_ENC0_SPLITTERBYPASS_U1FF_DISP1 = 0xA2,
/* PRE-WB & BLENDER-OUT -> ENC0 -> SPLITTER(split) -> u0_FF/u1_FF -> u0_DISPIF/u1_DISPIF */
DATAPATH_PREWB_ENC0_SPLITTER_U0FFU1FF_DISP0DISP1 = 0xA3,
/* PRE-WB only */
DATAPATH_PREWB_ONLY = 0xC0,
};
enum decon_s_data_path {
/* BLENDER-OUT -> No Comp -> u0_FF -> u0_DISPIF */
DECONS_DATAPATH_NOCOMP_U0FF_DISP0 = 0x01,
/* BLENDER-OUT -> No Comp -> u0_FF -> POST_WB */
DECONS_DATAPATH_NOCOMP_U0FF_POSTWB = 0x04,
/* BLENDER-OUT -> ENC1 -> u0_FF --> u0_DISPIF */
DECONS_DATAPATH_ENC0_U0FF_DISP0 = 0x21,
/* BLENDER-OUT -> ENC1 -> u0_FF -> POST_WB */
DECONS_DATAPATH_ENC0_U0FF_POSTWB = 0x24,
/* u0_DISPIF (mapcolor mode) */
DECONS_DATAPATH_DISP0_COLORMAP = 0x41,
/* PRE_WB & BLENDER-OUT -> No Comp -> u0_FF -> u0_DISPIF */
DECONS_DATAPATH_PREWB_NOCOMP_U0FF_DISP0 = 0x81,
/* PRE_WB & BLENDER-OUT -> ENC1 -> u0_FF -> u0_DISPIF */
DECONS_DATAPATH_PREWB_ENC0_U0FF_DISP0 = 0xA1,
/* PRE_WB only */
DECONS_DATAPATH_PREWB_ONLY = 0xC0,
};
enum decon_enhance_path {
ENHANCEPATH_ENHANCE_ALL_OFF = 0x0,
ENHANCEPATH_DITHER_ON = 0x1,
ENHANCEPATH_DPU_ON = 0x2,
ENHANCEPATH_DPU_DITHER_ON = 0x3,
ENHANCEPATH_MDNIE_ON = 0x4,
ENHANCEPATH_MDNIE_DITHER_ON = 0x5,
};
/* CAL APIs list */
int decon_reg_init(u32 id, u32 dsi_idx, struct decon_param *p);
void decon_reg_init_probe(u32 id, u32 dsi_idx, struct decon_param *p);
int decon_reg_start(u32 id, struct decon_mode_info *psr);
int decon_reg_stop(u32 id, u32 dsi_idx, struct decon_mode_info *psr);
void decon_reg_release_resource(u32 id, struct decon_mode_info *psr);
void decon_reg_set_int(u32 id, struct decon_mode_info *psr, u32 en);
void decon_reg_set_window_control(u32 id, int win_idx, struct decon_window_regs *regs, u32 winmap_en);
void decon_reg_update_req_and_unmask(u32 id, struct decon_mode_info *psr);
int decon_reg_wait_update_done_and_mask(u32 id, struct decon_mode_info *psr, u32 timeout);
void decon_reg_set_trigger(u32 id, struct decon_mode_info *psr,
enum decon_set_trig en);
int decon_reg_wait_for_update_timeout(u32 id, unsigned long timeout);
int decon_reg_wait_for_window_update_timeout(u32 id, u32 win_idx, unsigned long timeout);
int decon_reg_get_interrupt_and_clear(u32 id);
/* CAL raw functions list */
void decon_reg_set_disp_ss_cfg(u32 id, void __iomem *disp_ss_regs, u32 dsi_idx, struct decon_mode_info *psr);
int decon_reg_reset(u32 id);
void decon_reg_set_clkgate_mode(u32 id, u32 en);
void decon_reg_set_vclk_freerun(u32 id, u32 en);
void decon_reg_set_vclk_divider(u32 id, u32 denom, u32 num);
void decon_reg_set_eclk_divider(u32 id, u32 denom, u32 num);
void decon_reg_set_sram_share(u32 id, u32 en);
void decon_reg_set_data_path(u32 id, enum decon_data_path data_path, enum decon_enhance_path enhance_path);
void decon_reg_get_data_path(u32 id, enum decon_data_path *data_path, enum decon_enhance_path *enhance_path);
void decon_reg_set_operation_mode(u32 id, enum decon_psr_mode mode);
void decon_reg_set_blender_bg_image_size(u32 id, enum decon_dsi_mode dsi_mode, struct decon_lcd *lcd_info);
void decon_reg_get_blender_bg_image_size(u32 id, u32 *p_width, u32 *p_height);
void decon_reg_set_underrun_scheme(u32 id, enum decon_hold_scheme mode);
void decon_reg_set_rgb_order(u32 id, enum decon_rgb_order order);
void decon_reg_set_frame_fifo_size(u32 id, enum decon_dsi_mode dsi_mode, u32 width, u32 height);
void decon_reg_set_splitter(u32 id, enum decon_dsi_mode dsi_mode, u32 width, u32 height);
void decon_reg_set_dispif_porch(u32 id, int dsi_idx, struct decon_lcd *lcd_info);
void decon_reg_set_dispif_size(u32 id, int dsi_idx, u32 width, u32 height);
void decon_reg_get_dispif_size(u32 id, int dsi_idx, u32 *p_width, u32 *p_height);
void decon_reg_set_comp_size(u32 id, enum decon_mic_comp_ratio cr, enum decon_dsi_mode dsi_mode, struct decon_lcd *lcd_info);
void decon_reg_config_mic(u32 id, enum decon_dsi_mode dsi_mode, struct decon_lcd *lcd_info);
void decon_reg_update_req_global(u32 id);
void decon_reg_update_req_window(u32 id, u32 win_idx);
void decon_reg_all_win_shadow_update_req(u32 id);
void decon_reg_direct_on_off(u32 id, u32 en);
void decon_reg_per_frame_off(u32 id);
void decon_reg_configure_lcd(u32 id, enum decon_dsi_mode dsi_mode, struct decon_lcd *lcd_info);
void decon_reg_configure_trigger(u32 id, enum decon_trig_mode mode);
u32 decon_reg_get_linecnt(u32 id, int dispif_idx);
int decon_reg_wait_linecnt_is_zero_timeout(u32 id, int dsi_idx, unsigned long timeout);
u32 decon_reg_get_run_status(u32 id);
int decon_reg_wait_run_status_timeout(u32 id, unsigned long timeout);
void decon_reg_clear_int_all(u32 id);
u32 decon_get_win_channel(u32 id, u32 win_idx, enum decon_idma_type type);
void decon_reg_config_win_channel(u32 id, u32 win_idx, enum decon_idma_type type);
int decon_reg_is_win_enabled(u32 id, int win_idx);
u32 decon_reg_get_width(u32 id, int dsi_mode);
u32 decon_reg_get_height(u32 id, int dsi_mode);
void decon_reg_get_clock_ratio(struct decon_clocks *clks, struct decon_lcd *lcd_info);
void decon_reg_set_partial_update(u32 id, enum decon_dsi_mode dsi_mode,
struct decon_lcd *lcd_info);
#endif /* ___SAMSUNG_DECON_COMMON_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,745 @@
/*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Core file for Samsung 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.
*/
#include <linux/of_gpio.h>
#include <linux/of.h>
#include <linux/clk-provider.h>
#include <linux/pm_runtime.h>
#include <linux/exynos_iovmm.h>
#include <linux/of_address.h>
#include <linux/clk-private.h>
#include <media/v4l2-subdev.h>
#include "decon.h"
#include "dsim.h"
#include "decon_helper.h"
int create_link_mipi(struct decon_device *decon, int id)
{
int i, ret = 0;
int n_pad = decon->n_sink_pad + decon->n_src_pad;
int flags = 0;
char err[80];
struct exynos_md *md = decon->mdev;
if (IS_ERR_OR_NULL(md->dsim_sd[id])) {
decon_err("failed to get subdev of dsim%d\n", decon->id);
return -EINVAL;
}
flags = MEDIA_LNK_FL_ENABLED;
for (i = decon->n_sink_pad; i < n_pad; i++) {
ret = media_entity_create_link(&decon->sd.entity, i,
&md->dsim_sd[id]->entity, 0, flags);
if (ret) {
snprintf(err, sizeof(err), "%s --> %s",
decon->sd.entity.name,
decon->output_sd->entity.name);
return ret;
}
decon_info("%s[%d] --> [0]%s link is created successfully\n",
decon->sd.entity.name, i,
decon->output_sd->entity.name);
}
return ret;
}
int find_subdev_mipi(struct decon_device *decon, int id)
{
struct exynos_md *md;
md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
if (!md) {
decon_err("failed to get mdev device(%d)\n", decon->id);
return -ENODEV;
}
decon->output_sd = md->dsim_sd[id];
decon->out_type = DECON_OUT_DSI;
decon->out_idx = id;
if (IS_ERR_OR_NULL(decon->output_sd))
decon_warn("couldn't find dsim%d subdev\n", id);
v4l2_subdev_call(decon->output_sd, core, ioctl, DSIM_IOC_GET_LCD_INFO, NULL);
decon->lcd_info = (struct decon_lcd *)v4l2_get_subdev_hostdata(decon->output_sd);
if (IS_ERR_OR_NULL(decon->lcd_info)) {
decon_err("failed to get lcd information\n");
return -EINVAL;
}
decon_dbg("###lcd_info[hfp %d hbp %d hsa %d vfp %d vbp %d vsa %d xres %d yres %d\n",
decon->lcd_info->hfp, decon->lcd_info->hbp, decon->lcd_info->hsa,
decon->lcd_info->vfp, decon->lcd_info->vbp, decon->lcd_info->vsa,
decon->lcd_info->xres, decon->lcd_info->yres);
return 0;
}
static u32 fb_visual(u32 bits_per_pixel, unsigned short palette_sz)
{
switch (bits_per_pixel) {
case 32:
case 24:
case 16:
case 12:
return FB_VISUAL_TRUECOLOR;
case 8:
if (palette_sz >= 256)
return FB_VISUAL_PSEUDOCOLOR;
else
return FB_VISUAL_TRUECOLOR;
case 1:
return FB_VISUAL_MONO01;
default:
return FB_VISUAL_PSEUDOCOLOR;
}
}
static inline u32 fb_linelength(u32 xres_virtual, u32 bits_per_pixel)
{
return (xres_virtual * bits_per_pixel) / 8;
}
static u16 fb_panstep(u32 res, u32 res_virtual)
{
return res_virtual > res ? 1 : 0;
}
int decon_set_par(struct fb_info *info)
{
struct fb_var_screeninfo *var = &info->var;
struct decon_win *win = info->par;
struct decon_device *decon = win->decon;
struct decon_window_regs win_regs;
int win_no = win->index;
memset(&win_regs, 0, sizeof(struct decon_window_regs));
dev_info(decon->dev, "setting framebuffer parameters\n");
if (decon->state == DECON_STATE_OFF)
return 0;
decon_lpd_block_exit(decon);
decon_reg_wait_for_update_timeout(decon->id, SHADOW_UPDATE_TIMEOUT);
info->fix.visual = fb_visual(var->bits_per_pixel, 0);
info->fix.line_length = fb_linelength(var->xres_virtual,
var->bits_per_pixel);
info->fix.xpanstep = fb_panstep(var->xres, var->xres_virtual);
info->fix.ypanstep = fb_panstep(var->yres, var->yres_virtual);
if (decon_reg_is_win_enabled(decon->id, win_no))
win_regs.wincon = WIN_CONTROL_EN_F;
else
win_regs.wincon = 0;
win_regs.wincon |= wincon(var->transp.length, 0, 0xFF,
0xFF, DECON_BLENDING_NONE);
win_regs.start_pos = win_start_pos(0, 0);
win_regs.end_pos = win_end_pos(0, 0, var->xres, var->yres);
win_regs.pixel_count = (var->xres * var->yres);
win_regs.whole_w = var->xoffset + var->xres;
win_regs.whole_h = var->yoffset + var->yres;
win_regs.offset_x = var->xoffset;
win_regs.offset_y = var->yoffset;
win_regs.type = decon->default_idma;
decon_reg_set_window_control(decon->id, win_no, &win_regs, false);
decon_lpd_unblock(decon);
return 0;
}
EXPORT_SYMBOL(decon_set_par);
int decon_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct decon_win *win = info->par;
struct decon_device *decon = win->decon;
int x, y;
unsigned long long hz;
var->xres_virtual = max(var->xres_virtual, var->xres);
var->yres_virtual = max(var->yres_virtual, var->yres);
if (!decon_validate_x_alignment(decon, 0, var->xres,
var->bits_per_pixel))
return -EINVAL;
/* always ensure these are zero, for drop through cases below */
var->transp.offset = 0;
var->transp.length = 0;
switch (var->bits_per_pixel) {
case 1:
case 2:
case 4:
case 8:
var->red.offset = 4;
var->green.offset = 2;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 3;
var->blue.length = 2;
var->transp.offset = 7;
var->transp.length = 1;
break;
case 19:
/* 666 with one bit alpha/transparency */
var->transp.offset = 18;
var->transp.length = 1;
case 18:
var->bits_per_pixel = 32;
/* 666 format */
var->red.offset = 12;
var->green.offset = 6;
var->blue.offset = 0;
var->red.length = 6;
var->green.length = 6;
var->blue.length = 6;
break;
case 16:
/* 16 bpp, 565 format */
var->red.offset = 11;
var->green.offset = 5;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 6;
var->blue.length = 5;
break;
case 32:
case 28:
case 25:
var->transp.length = var->bits_per_pixel - 24;
var->transp.offset = 24;
/* drop through */
case 24:
/* our 24bpp is unpacked, so 32bpp */
var->bits_per_pixel = 32;
var->red.offset = 16;
var->red.length = 8;
var->green.offset = 8;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
break;
default:
decon_err("invalid bpp %d\n", var->bits_per_pixel);
return -EINVAL;
}
if (decon->pdata->psr_mode == DECON_MIPI_COMMAND_MODE) {
x = var->xres;
y = var->yres;
} else {
x = var->xres + var->left_margin + var->right_margin + var->hsync_len;
y = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
}
hz = 1000000000000ULL; /* 1e12 picoseconds per second */
hz += (x * y) / 2;
do_div(hz, x * y); /* divide by x * y with rounding */
hz += var->pixclock / 2;
do_div(hz, var->pixclock); /* divide by pixclock with rounding */
win->fps = hz;
decon_dbg("xres:%d, yres:%d, v_xres:%d, v_yres:%d, bpp:%d, %lldhz\n",
var->xres, var->yres, var->xres_virtual,
var->yres_virtual, var->bits_per_pixel, hz);
return 0;
}
static inline unsigned int chan_to_field(unsigned int chan,
struct fb_bitfield *bf)
{
chan &= 0xffff;
chan >>= 16 - bf->length;
return chan << bf->offset;
}
int decon_setcolreg(unsigned regno,
unsigned red, unsigned green, unsigned blue,
unsigned transp, struct fb_info *info)
{
struct decon_win *win = info->par;
struct decon_device *decon = win->decon;
unsigned int val;
dev_dbg(decon->dev, "%s: win %d: %d => rgb=%d/%d/%d\n",
__func__, win->index, regno, red, green, blue);
if (decon->state == DECON_STATE_OFF)
return 0;
switch (info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
/* true-colour, use pseudo-palette */
if (regno < 16) {
u32 *pal = info->pseudo_palette;
val = chan_to_field(red, &info->var.red);
val |= chan_to_field(green, &info->var.green);
val |= chan_to_field(blue, &info->var.blue);
pal[regno] = val;
}
break;
default:
return 1; /* unknown type */
}
return 0;
}
EXPORT_SYMBOL(decon_setcolreg);
int decon_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct decon_win *win = info->par;
struct decon_device *decon = win->decon;
struct v4l2_subdev *sd = NULL;
struct decon_win_config config;
int ret = 0;
int shift = 0;
struct decon_mode_info psr;
decon_lpd_block_exit(decon);
decon_set_par(info);
decon->vpp_usage_bitmask |= (1 << decon->default_idma);
decon->vpp_used[decon->default_idma] = true;
memset(&config, 0, sizeof(struct decon_win_config));
switch (var->bits_per_pixel) {
case 16:
config.format = DECON_PIXEL_FORMAT_RGB_565;
shift = 2;
break;
case 24:
case 32:
config.format = DECON_PIXEL_FORMAT_BGRA_8888;
shift = 4;
break;
default:
decon_err("%s: bits_per_pixel %d\n", __func__, var->bits_per_pixel);
}
config.vpp_parm.addr[0] = info->fix.smem_start;
config.src.x = var->xoffset >> shift;
config.src.y = var->yoffset;
config.src.w = var->xres;
config.src.h = var->yres;
config.src.f_w = var->xres;
config.src.f_h = var->yres;
config.dst.w = config.src.w;
config.dst.h = config.src.h;
config.dst.f_w = config.src.f_w;
config.dst.f_h = config.src.f_h;
sd = decon->mdev->vpp_sd[decon->default_idma];
if (v4l2_subdev_call(sd, core, ioctl, VPP_WIN_CONFIG, &config)) {
decon_err("%s: Failed to config VPP-%d\n", __func__, win->vpp_id);
decon->vpp_usage_bitmask &= ~(1 << win->vpp_id);
decon->vpp_err_stat[win->vpp_id] = true;
}
decon_reg_update_req_window(decon->id, win->index);
decon_to_psr_info(decon, &psr);
decon_reg_start(decon->id, &psr);
decon_wait_for_vsync(decon, VSYNC_TIMEOUT_MSEC);
if (decon_reg_wait_update_done_and_mask(decon->id, &psr, SHADOW_UPDATE_TIMEOUT)
< 0)
decon_err("%s: wait_for_update_timeout\n", __func__);
decon_lpd_unblock(decon);
return ret;
}
EXPORT_SYMBOL(decon_pan_display);
int decon_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
#ifdef CONFIG_ION_EXYNOS
int ret;
struct decon_win *win = info->par;
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
ret = dma_buf_mmap(win->dma_buf_data[0].dma_buf, vma, 0);
return ret;
#else
return 0;
#endif
}
EXPORT_SYMBOL(decon_mmap);
static void decon_fb_missing_pixclock(struct decon_fb_videomode *win_mode,
enum decon_psr_mode mode)
{
u64 pixclk = 1000000000000ULL;
u32 div;
u32 width, height;
if (mode == DECON_MIPI_COMMAND_MODE) {
width = win_mode->videomode.xres;
height = win_mode->videomode.yres;
} else {
width = win_mode->videomode.left_margin + win_mode->videomode.hsync_len +
win_mode->videomode.right_margin + win_mode->videomode.xres;
height = win_mode->videomode.upper_margin + win_mode->videomode.vsync_len +
win_mode->videomode.lower_margin + win_mode->videomode.yres;
}
div = width * height * (win_mode->videomode.refresh ? : 60);
do_div(pixclk, div);
win_mode->videomode.pixclock = pixclk;
}
static void decon_parse_lcd_info(struct decon_device *decon)
{
int i;
struct decon_lcd *lcd_info = decon->lcd_info;
for (i = 0; i < decon->pdata->max_win; i++) {
decon->windows[i]->win_mode.videomode.left_margin = lcd_info->hbp;
decon->windows[i]->win_mode.videomode.right_margin = lcd_info->hfp;
decon->windows[i]->win_mode.videomode.upper_margin = lcd_info->vbp;
decon->windows[i]->win_mode.videomode.lower_margin = lcd_info->vfp;
decon->windows[i]->win_mode.videomode.hsync_len = lcd_info->hsa;
decon->windows[i]->win_mode.videomode.vsync_len = lcd_info->vsa;
decon->windows[i]->win_mode.videomode.xres = lcd_info->xres;
decon->windows[i]->win_mode.videomode.yres = lcd_info->yres;
decon->windows[i]->win_mode.width = lcd_info->width;
decon->windows[i]->win_mode.height = lcd_info->height;
}
}
int decon_set_lcd_config(struct decon_device *decon)
{
struct fb_info *fbinfo;
struct decon_fb_videomode *win_mode;
int i, ret = 0;
decon_parse_lcd_info(decon);
for (i = 0; i < decon->pdata->max_win; i++) {
if (!decon->windows[i])
continue;
win_mode = &decon->windows[i]->win_mode;
if (!win_mode->videomode.pixclock)
decon_fb_missing_pixclock(win_mode, decon->pdata->psr_mode);
fbinfo = decon->windows[i]->fbinfo;
fb_videomode_to_var(&fbinfo->var, &win_mode->videomode);
fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
fbinfo->fix.accel = FB_ACCEL_NONE;
fbinfo->fix.line_length = fb_linelength(fbinfo->var.xres_virtual,
fbinfo->var.bits_per_pixel);
fbinfo->var.activate = FB_ACTIVATE_NOW;
fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
fbinfo->var.bits_per_pixel = LCD_DEFAULT_BPP;
fbinfo->var.width = win_mode->width;
fbinfo->var.height = win_mode->height;
ret = decon_check_var(&fbinfo->var, fbinfo);
if (ret)
return ret;
decon_dbg("window[%d] verified parameters\n", i);
}
return ret;
}
irqreturn_t decon_fb_isr_for_eint(int irq, void *dev_id)
{
struct decon_device *decon = dev_id;
struct decon_mode_info psr;
ktime_t timestamp = ktime_get();
DISP_SS_EVENT_LOG(DISP_EVT_TE_INTERRUPT, &decon->sd, timestamp);
spin_lock(&decon->slock);
if (decon->pdata->trig_mode == DECON_SW_TRIG) {
decon_to_psr_info(decon, &psr);
decon_reg_set_trigger(decon->id, &psr, DECON_TRIG_ENABLE);
}
#ifdef CONFIG_DECON_LPD_DISPLAY
if ((decon->state == DECON_STATE_ON) && (decon->out_type == DECON_OUT_DSI)) {
if (decon_min_lock_cond(decon))
queue_work(decon->lpd_wq, &decon->lpd_work);
}
#endif
decon->vsync_info.timestamp = timestamp;
wake_up_interruptible_all(&decon->vsync_info.wait);
spin_unlock(&decon->slock);
return IRQ_HANDLED;
}
int decon_config_eint_for_te(struct platform_device *pdev, struct decon_device *decon)
{
struct device *dev = decon->dev;
int gpio;
int ret = 0;
/* Get IRQ resource and register IRQ handler. */
gpio = of_get_gpio(dev->of_node, 0);
if (gpio < 0) {
decon_err("failed to get proper gpio number\n");
return -EINVAL;
}
gpio = gpio_to_irq(gpio);
decon->irq = gpio;
ret = devm_request_irq(dev, gpio, decon_fb_isr_for_eint,
IRQF_TRIGGER_RISING, pdev->name, decon);
decon->eint_status = 1;
return ret;
}
static int decon_wait_for_vsync_thread(void *data)
{
struct decon_device *decon = data;
while (!kthread_should_stop()) {
ktime_t timestamp = decon->vsync_info.timestamp;
int ret = wait_event_interruptible(decon->vsync_info.wait,
!ktime_equal(timestamp, decon->vsync_info.timestamp) &&
decon->vsync_info.active);
if (!ret)
sysfs_notify(&decon->dev->kobj, NULL, "vsync");
}
return 0;
}
static ssize_t decon_vsync_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct decon_device *decon = dev_get_drvdata(dev);
return scnprintf(buf, PAGE_SIZE, "%llu\n",
ktime_to_ns(decon->vsync_info.timestamp));
}
static DEVICE_ATTR(vsync, S_IRUGO, decon_vsync_show, NULL);
static ssize_t decon_psr_info(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct decon_device *decon = dev_get_drvdata(dev);
return scnprintf(buf, PAGE_SIZE, "%d\n", decon->pdata->psr_mode);
}
static DEVICE_ATTR(psr_info, S_IRUGO, decon_psr_info, NULL);
int decon_f_create_vsync_thread(struct decon_device *decon)
{
int ret = 0;
ret = device_create_file(decon->dev, &dev_attr_vsync);
if (ret) {
decon_err("failed to create vsync file\n");
return ret;
}
decon->vsync_info.thread = kthread_run(decon_wait_for_vsync_thread,
decon, "s3c-fb-vsync");
if (decon->vsync_info.thread == ERR_PTR(-ENOMEM)) {
decon_err("failed to run vsync thread\n");
decon->vsync_info.thread = NULL;
}
return ret;
}
int decon_f_create_psr_thread(struct decon_device *decon)
{
int ret = 0;
ret = device_create_file(decon->dev, &dev_attr_psr_info);
if (ret) {
decon_err("failed to create psr info file\n");
return ret;
}
return ret;
}
void decon_f_destroy_vsync_thread(struct decon_device *decon)
{
device_remove_file(decon->dev, &dev_attr_vsync);
}
void decon_f_destroy_psr_thread(struct decon_device *decon)
{
device_remove_file(decon->dev, &dev_attr_psr_info);
}
/************* LPD funtions ************************/
u32 decon_reg_get_cam_status(void __iomem *cam_status)
{
if (cam_status)
return readl(cam_status);
else
return 0xF;
}
static int decon_enter_lpd(struct decon_device *decon)
{
int ret = 0;
#ifdef CONFIG_DECON_LPD_DISPLAY
DISP_SS_EVENT_START();
mutex_lock(&decon->lpd_lock);
if (decon_is_lpd_blocked(decon))
goto err2;
decon_lpd_block(decon);
if ((decon->state == DECON_STATE_LPD) ||
(decon->state != DECON_STATE_ON)) {
goto err;
}
exynos_ss_printk("%s +\n", __func__);
decon_lpd_trig_reset(decon);
decon->state = DECON_STATE_LPD_ENT_REQ;
decon_disable(decon);
decon->state = DECON_STATE_LPD;
exynos_ss_printk("%s -\n", __func__);
DISP_SS_EVENT_LOG(DISP_EVT_ENTER_LPD, &decon->sd, start);
err:
decon_lpd_unblock(decon);
err2:
mutex_unlock(&decon->lpd_lock);
#endif
return ret;
}
int decon_exit_lpd(struct decon_device *decon)
{
int ret = 0;
#ifdef CONFIG_DECON_LPD_DISPLAY
DISP_SS_EVENT_START();
decon_lpd_block(decon);
flush_workqueue(decon->lpd_wq);
mutex_lock(&decon->lpd_lock);
if (decon->state != DECON_STATE_LPD)
goto err;
exynos_ss_printk("%s +\n", __func__);
decon->state = DECON_STATE_LPD_EXIT_REQ;
decon_enable(decon);
decon_lpd_trig_reset(decon);
decon->state = DECON_STATE_ON;
exynos_ss_printk("%s -\n", __func__);
DISP_SS_EVENT_LOG(DISP_EVT_EXIT_LPD, &decon->sd, start);
err:
decon_lpd_unblock(decon);
mutex_unlock(&decon->lpd_lock);
#endif
return ret;
}
int decon_lpd_block_exit(struct decon_device *decon)
{
int ret = 0;
if (!decon || !decon->lpd_init_status)
return 0;
decon_lpd_block(decon);
ret = decon_exit_lpd(decon);
return ret;
}
#ifdef DECON_LPD_OPT
int decon_lcd_off(struct decon_device *decon)
{
/* It cann't be used incase of PACKET_GO mode */
int ret;
decon_info("%s +\n", __func__);
decon_lpd_block(decon);
flush_workqueue(decon->lpd_wq);
mutex_lock(&decon->lpd_lock);
ret = v4l2_subdev_call(decon->output_sd, core, ioctl, DSIM_IOC_LCD_OFF, NULL);
if (ret < 0)
decon_err("failed to turn off LCD\n");
decon->state = DECON_STATE_OFF;
mutex_unlock(&decon->lpd_lock);
decon_lpd_unblock(decon);
decon_info("%s -\n", __func__);
return 0;
}
#endif
static void decon_lpd_handler(struct work_struct *work)
{
struct decon_device *decon =
container_of(work, struct decon_device, lpd_work);
if (!decon || !decon->lpd_init_status)
return;
if (decon_lpd_enter_cond(decon))
decon_enter_lpd(decon);
}
int decon_register_lpd_work(struct decon_device *decon)
{
mutex_init(&decon->lpd_lock);
atomic_set(&decon->lpd_trig_cnt, 0);
atomic_set(&decon->lpd_block_cnt, 0);
decon->lpd_wq = create_singlethread_workqueue("decon_lpd");
if (decon->lpd_wq == NULL) {
decon_err("%s:failed to create workqueue for LPD\n", __func__);
return -ENOMEM;
}
INIT_WORK(&decon->lpd_work, decon_lpd_handler);
decon->lpd_init_status = true;
return 0;
}

View file

@ -0,0 +1,260 @@
/*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Core file for Samsung 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.
*/
#include <linux/of_gpio.h>
#include <linux/of.h>
#include <linux/clk-provider.h>
#include <linux/pm_runtime.h>
#include <linux/exynos_iovmm.h>
#include <linux/of_address.h>
#include <linux/clk-private.h>
#include <media/v4l2-subdev.h>
#include "../../../../soc/samsung/pwrcal/pwrcal.h"
#include "../../../../soc/samsung/pwrcal/S5E8890/S5E8890-vclk.h"
#include "decon.h"
#include "dsim.h"
#include "decon_helper.h"
static void decon_oneshot_underrun_log(struct decon_device *decon)
{
DISP_SS_EVENT_LOG(DISP_EVT_UNDERRUN, &decon->sd, ktime_set(0, 0));
decon->underrun_stat.underrun_cnt++;
if (decon->fifo_irq_status++ > UNDERRUN_FILTER_IDLE)
return;
if (decon->underrun_stat.underrun_cnt > DECON_UNDERRUN_THRESHOLD) {
decon_warn("[underrun]: (cnt %d), tot_bw %d, int_bw %d, disp_bw %d\n",
decon->underrun_stat.underrun_cnt,
decon->underrun_stat.prev_bw,
decon->underrun_stat.prev_int_bw,
decon->underrun_stat.prev_disp_bw);
decon_warn(" chmap(0x%08x), win(0x%lx), aclk(%ld)\n",
decon->underrun_stat.chmap,
decon->underrun_stat.used_windows,
decon->underrun_stat.aclk / MHZ);
decon->underrun_stat.underrun_cnt = 0;
}
queue_work(decon->fifo_irq_wq, &decon->fifo_irq_work);
}
static void decon_f_get_enabled_win(struct decon_device *decon)
{
int i;
decon->underrun_stat.used_windows = 0;
for (i = 0; i < MAX_DECON_WIN; ++i)
if (decon_read(decon->id, (WIN_CONTROL(i)) + SHADOW_OFFSET) & WIN_CONTROL_EN_F)
set_bit(i * 4, &decon->underrun_stat.used_windows);
}
irqreturn_t decon_f_irq_handler(int irq, void *dev_data)
{
struct decon_device *decon = dev_data;
u32 irq_sts_reg;
ktime_t timestamp;
u32 fifo_level = 0;
timestamp = ktime_get();
spin_lock(&decon->slock);
if ((decon->state == DECON_STATE_OFF) ||
(decon->state == DECON_STATE_LPD)) {
goto irq_end;
}
irq_sts_reg = decon_reg_get_interrupt_and_clear(decon->id);
if (irq_sts_reg & INTERRUPT_DISPIF_VSTATUS_INT_EN) {
/* VSYNC interrupt, accept it */
decon->frame_start_cnt_cur++;
wake_up_interruptible_all(&decon->wait_vstatus);
if (decon->pdata->psr_mode == DECON_VIDEO_MODE) {
decon->vsync_info.timestamp = timestamp;
wake_up_interruptible_all(&decon->vsync_info.wait);
}
}
if (irq_sts_reg & INTERRUPT_FIFO_LEVEL_INT_EN) {
decon->underrun_stat.fifo_level = fifo_level;
decon->underrun_stat.prev_bw = decon->prev_bw;
decon->underrun_stat.prev_int_bw = decon->prev_int_bw;
decon->underrun_stat.prev_disp_bw = decon->prev_disp_bw;
decon->underrun_stat.chmap = decon_read(0, RESOURCE_SEL_1);
decon->underrun_stat.aclk = decon->res.pclk->rate;
decon_f_get_enabled_win(decon);
decon_oneshot_underrun_log(decon);
}
if (irq_sts_reg & INTERRUPT_FRAME_DONE_INT_EN) {
DISP_SS_EVENT_LOG(DISP_EVT_DECON_FRAMEDONE, &decon->sd, ktime_set(0, 0));
decon->frame_done_cnt_cur++;
decon_lpd_trig_reset(decon);
wake_up_interruptible_all(&decon->wait_frmdone);
if (decon->sw_te_wa) {
decon->vsync_info.timestamp = timestamp;
wake_up_interruptible_all(&decon->vsync_info.wait);
}
}
if (irq_sts_reg & INTERRUPT_RESOURCE_CONFLICT_INT_EN)
DISP_SS_EVENT_LOG(DISP_EVT_RSC_CONFLICT, &decon->sd, ktime_set(0, 0));
irq_end:
spin_unlock(&decon->slock);
return IRQ_HANDLED;
}
int decon_f_get_clocks(struct decon_device *decon)
{
decon->res.dpll = clk_get(decon->dev, "disp_pll");
if (IS_ERR_OR_NULL(decon->res.dpll)) {
decon_err("failed to get disp_pll\n");
return -ENODEV;
}
decon->res.pclk = clk_get(decon->dev, "decon_pclk");
if (IS_ERR_OR_NULL(decon->res.pclk)) {
decon_err("failed to get decon_pclk\n");
return -ENODEV;
}
decon->res.eclk = clk_get(decon->dev, "eclk_user");
if (IS_ERR_OR_NULL(decon->res.eclk)) {
decon_err("failed to get eclk_user\n");
return -ENODEV;
}
decon->res.eclk_leaf = clk_get(decon->dev, "eclk_leaf");
if (IS_ERR_OR_NULL(decon->res.eclk_leaf)) {
decon_err("failed to get eclk_leaf\n");
return -ENODEV;
}
decon->res.vclk = clk_get(decon->dev, "vclk_user");
if (IS_ERR_OR_NULL(decon->res.vclk)) {
decon_err("failed to get vclk_user\n");
return -ENODEV;
}
decon->res.vclk_leaf = clk_get(decon->dev, "vclk_leaf");
if (IS_ERR_OR_NULL(decon->res.vclk_leaf)) {
decon_err("failed to get vclk_leaf\n");
return -ENODEV;
}
return 0;
}
void decon_f_set_clocks(struct decon_device *decon)
{
struct device *dev = decon->dev;
struct decon_clocks clks;
struct decon_param p;
decon_to_init_param(decon, &p);
decon_reg_get_clock_ratio(&clks, p.lcd_info);
/* VCLK */
decon_clk_set_rate(dev, decon->res.dpll,
NULL, clks.decon[CLK_ID_DPLL] * MHZ);
decon_clk_set_rate(dev, decon->res.vclk_leaf,
NULL, clks.decon[CLK_ID_VCLK] * MHZ);
/* ECLK */
decon_clk_set_rate(dev, decon->res.eclk_leaf,
NULL, clks.decon[CLK_ID_ECLK] * MHZ);
/* TODO: PCLK */
/* TODO: ACLK */
if (!IS_ENABLED(CONFIG_PM_DEVFREQ))
cal_dfs_set_rate(dvfs_disp, clks.decon[CLK_ID_ACLK] * 1000);
decon_dbg("%s:dpll %ld pclk %ld vclk %ld eclk %ld Mhz\n",
__func__,
clk_get_rate(decon->res.dpll) / MHZ,
clk_get_rate(decon->res.pclk) / MHZ,
clk_get_rate(decon->res.vclk_leaf) / MHZ,
clk_get_rate(decon->res.eclk_leaf) / MHZ);
return;
}
static void underrun_filter_handler(struct work_struct *work)
{
struct decon_device *decon =
container_of(work, struct decon_device, fifo_irq_work);
msleep(UNDERRUN_FILTER_INTERVAL_MS);
decon->fifo_irq_status = UNDERRUN_FILTER_IDLE;
}
int decon_f_register_irq(struct platform_device *pdev, struct decon_device *decon)
{
struct device *dev = decon->dev;
struct resource *res;
int ret = 0;
/* Get IRQ resource and register IRQ handler. */
/* 0: FIFO irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
ret = devm_request_irq(dev, res->start, decon_f_irq_handler, 0,
pdev->name, decon);
if (ret) {
decon_err("failed to install FIFO irq\n");
return ret;
}
/* 1: VSTATUS INFO irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
ret = devm_request_irq(dev, res->start, decon_f_irq_handler,
0, pdev->name, decon);
if (ret) {
decon_err("failed to install VSTATUS irq\n");
return ret;
}
if (decon->pdata->psr_mode == DECON_MIPI_COMMAND_MODE) {
/* 2: I80 FrameDone irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
ret = devm_request_irq(dev, res->start, decon_f_irq_handler,
0, pdev->name, decon);
if (ret) {
decon_err("failed to install FrameDone irq\n");
return ret;
}
}
/* 3: Extra Interrupts: Resource Conflict irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 3);
ret = devm_request_irq(dev, res->start, decon_f_irq_handler,
0, pdev->name, decon);
if (ret) {
decon_err("failed to install Extra irq\n");
return ret;
}
if (decon->fifo_irq_status++ == UNDERRUN_FILTER_INIT) {
decon->fifo_irq_wq = create_singlethread_workqueue("decon_fifo_irq_wq");
if (decon->fifo_irq_wq == NULL) {
decon_err("%s:failed to create workqueue for fifo_irq_wq\n", __func__);
return -ENOMEM;
}
INIT_WORK(&decon->fifo_irq_work, underrun_filter_handler);
}
return ret;
}

View file

@ -0,0 +1,586 @@
/*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Helper file for Samsung 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.
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/pm_runtime.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
#include "decon.h"
#include "dsim.h"
#include "./vpp/vpp.h"
#include "decon_helper.h"
#include "./panels/lcd_ctrl.h"
#include <video/mipi_display.h>
extern void *return_address(int);
int decon_clk_set_parent(struct device *dev, const char *child, const char *parent)
{
struct clk *p;
struct clk *c;
p = clk_get(dev, parent);
if (IS_ERR_OR_NULL(p)) {
decon_err("%s: couldn't get clock : %s\n", __func__, parent);
return -ENODEV;
}
c = clk_get(dev, child);
if (IS_ERR_OR_NULL(c)) {
decon_err("%s: couldn't get clock : %s\n", __func__, child);
return -ENODEV;
}
clk_set_parent(c, p);
clk_put(p);
clk_put(c);
return 0;
}
int decon_clk_set_rate(struct device *dev, struct clk *clk,
const char *conid, unsigned long rate)
{
if (IS_ERR_OR_NULL(clk)) {
if (IS_ERR_OR_NULL(conid)) {
decon_err("%s: couldn't set clock(%ld)\n", __func__, rate);
return -ENODEV;
}
clk = clk_get(dev, conid);
clk_set_rate(clk, rate);
clk_put(clk);
} else {
clk_set_rate(clk, rate);
}
return 0;
}
unsigned long decon_clk_get_rate(struct device *dev, const char *clkid)
{
struct clk *target;
unsigned long rate;
target = clk_get(dev, clkid);
if (IS_ERR_OR_NULL(target)) {
decon_err("%s: couldn't get clock : %s\n", __func__, clkid);
return -ENODEV;
}
rate = clk_get_rate(target);
clk_put(target);
return rate;
}
void decon_to_psr_info(struct decon_device *decon, struct decon_mode_info *psr)
{
psr->psr_mode = decon->pdata->psr_mode;
psr->trig_mode = decon->pdata->trig_mode;
psr->dsi_mode = decon->pdata->dsi_mode;
psr->out_type = decon->out_type;
}
void decon_to_init_param(struct decon_device *decon, struct decon_param *p)
{
struct decon_lcd *lcd_info = decon->lcd_info;
struct v4l2_mbus_framefmt mbus_fmt;
mbus_fmt.width = 0;
mbus_fmt.height = 0;
mbus_fmt.code = 0;
mbus_fmt.field = 0;
mbus_fmt.colorspace = 0;
p->lcd_info = lcd_info;
p->psr.psr_mode = decon->pdata->psr_mode;
p->psr.trig_mode = decon->pdata->trig_mode;
p->psr.dsi_mode = decon->pdata->dsi_mode;
p->psr.out_type = decon->out_type;
p->nr_windows = decon->pdata->max_win;
p->disp_ss_regs = decon->ss_regs;
decon_dbg("###psr_mode %d trig_mode %d out_type %d nr_windows %d LCD[%d %d]\n",
p->psr.psr_mode, p->psr.trig_mode, p->psr.out_type, p->nr_windows,
decon->lcd_info->xres, decon->lcd_info->yres);
}
/**
* ----- APIs for DISPLAY_SUBSYSTEM_EVENT_LOG -----
*/
/* ===== STATIC APIs ===== */
#ifdef CONFIG_DECON_EVENT_LOG
/* logging a event related with DECON */
static inline void disp_ss_event_log_decon
(disp_ss_event_t type, struct v4l2_subdev *sd, ktime_t time)
{
struct decon_device *decon = container_of(sd, struct decon_device, sd);
int idx = atomic_inc_return(&decon->disp_ss_log_idx) % DISP_EVENT_LOG_MAX;
struct disp_ss_log *log = &decon->disp_ss_log[idx];
if (time.tv64)
log->time = time;
else
log->time = ktime_get();
log->type = type;
switch (type) {
case DISP_EVT_DECON_SUSPEND:
case DISP_EVT_DECON_RESUME:
case DISP_EVT_ENTER_LPD:
case DISP_EVT_EXIT_LPD:
log->data.pm.pm_status = pm_runtime_active(decon->dev);
log->data.pm.elapsed = ktime_sub(ktime_get(), log->time);
break;
case DISP_EVT_WB_SET_BUFFER:
case DISP_EVT_WB_SW_TRIGGER:
break;
case DISP_EVT_TE_INTERRUPT:
case DISP_EVT_UNDERRUN:
case DISP_EVT_LINECNT_ZERO:
break;
default:
/* Any remaining types will be log just time and type */
break;
}
}
/* logging a event related with DSIM */
static inline void disp_ss_event_log_dsim
(disp_ss_event_t type, struct v4l2_subdev *sd, ktime_t time)
{
struct dsim_device *dsim = container_of(sd, struct dsim_device, sd);
struct decon_device *decon = get_decon_drvdata(dsim->id);
int idx = atomic_inc_return(&decon->disp_ss_log_idx) % DISP_EVENT_LOG_MAX;
struct disp_ss_log *log = &decon->disp_ss_log[idx];
if (time.tv64)
log->time = time;
else
log->time = ktime_get();
log->type = type;
switch (type) {
case DISP_EVT_DSIM_SUSPEND:
case DISP_EVT_DSIM_RESUME:
case DISP_EVT_ENTER_ULPS:
case DISP_EVT_EXIT_ULPS:
log->data.pm.pm_status = pm_runtime_active(dsim->dev);
log->data.pm.elapsed = ktime_sub(ktime_get(), log->time);
break;
default:
/* Any remaining types will be log just time and type */
break;
}
}
/* get decon's id used by vpp */
static int __get_decon_id_for_vpp(struct v4l2_subdev *sd)
{
struct decon_device *decon;
struct vpp_dev *vpp = v4l2_get_subdevdata(sd);
int idx;
int ret = 0;
for (idx = 0; idx < NUM_DECON_IPS; idx++) {
decon = get_decon_drvdata(idx);
if (!decon || IS_ERR_OR_NULL(decon->debug_event))
continue;
if (decon->vpp_used[vpp->id] == true)
ret = decon->id;
}
return ret;
}
/* logging a event related with VPP */
static inline void disp_ss_event_log_vpp
(disp_ss_event_t type, struct v4l2_subdev *sd, ktime_t time)
{
struct decon_device *decon = get_decon_drvdata(__get_decon_id_for_vpp(sd));
int idx = atomic_inc_return(&decon->disp_ss_log_idx) % DISP_EVENT_LOG_MAX;
struct disp_ss_log *log = &decon->disp_ss_log[idx];
struct vpp_dev *vpp = v4l2_get_subdevdata(sd);
if (time.tv64)
log->time = time;
else
log->time = ktime_get();
log->type = type;
switch (type) {
case DISP_EVT_VPP_SUSPEND:
case DISP_EVT_VPP_RESUME:
log->data.pm.pm_status = pm_runtime_active(&vpp->pdev->dev);
log->data.pm.elapsed = ktime_sub(ktime_get(), log->time);
break;
case DISP_EVT_VPP_FRAMEDONE:
case DISP_EVT_VPP_STOP:
case DISP_EVT_VPP_WINCON:
log->data.vpp.id = vpp->id;
log->data.vpp.start_cnt = vpp->start_count;
log->data.vpp.done_cnt = vpp->done_count;
break;
default:
log->data.vpp.id = vpp->id;
break;
}
return;
}
/* If event are happend continuously, then ignore */
static bool disp_ss_event_ignore
(disp_ss_event_t type, struct decon_device *decon)
{
int latest = atomic_read(&decon->disp_ss_log_idx) % DISP_EVENT_LOG_MAX;
struct disp_ss_log *log;
int idx;
/* Seek a oldest from current index */
idx = (latest + DISP_EVENT_LOG_MAX - DECON_ENTER_LPD_CNT) % DISP_EVENT_LOG_MAX;
do {
if (++idx >= DISP_EVENT_LOG_MAX)
idx = 0;
log = &decon->disp_ss_log[idx];
if (log->type != type)
return false;
} while (latest != idx);
return true;
}
/* ===== EXTERN APIs ===== */
/* Common API to log a event related with DECON/DSIM/VPP */
void DISP_SS_EVENT_LOG(disp_ss_event_t type, struct v4l2_subdev *sd, ktime_t time)
{
struct decon_device *decon = get_decon_drvdata(0);
if (!decon || IS_ERR_OR_NULL(decon->debug_event))
return;
/* log a eventy softly */
switch (type) {
case DISP_EVT_TE_INTERRUPT:
case DISP_EVT_UNDERRUN:
/* If occurs continuously, skipped. It is a burden */
if (disp_ss_event_ignore(type, decon))
break;
case DISP_EVT_BLANK:
case DISP_EVT_UNBLANK:
case DISP_EVT_ENTER_LPD:
case DISP_EVT_EXIT_LPD:
case DISP_EVT_DECON_SUSPEND:
case DISP_EVT_DECON_RESUME:
case DISP_EVT_LINECNT_ZERO:
case DISP_EVT_TRIG_MASK:
case DISP_EVT_TRIG_UNMASK:
case DISP_EVT_DECON_FRAMEDONE:
case DISP_EVT_DECON_FRAMEDONE_WAIT:
case DISP_EVT_WB_SET_BUFFER:
case DISP_EVT_WB_SW_TRIGGER:
case DISP_EVT_DECON_SHUTDOWN:
case DISP_EVT_RSC_CONFLICT:
disp_ss_event_log_decon(type, sd, time);
break;
case DISP_EVT_DSIM_FRAMEDONE:
case DISP_EVT_ENTER_ULPS:
case DISP_EVT_EXIT_ULPS:
case DISP_EVT_DSIM_SHUTDOWN:
disp_ss_event_log_dsim(type, sd, time);
break;
case DISP_EVT_VPP_FRAMEDONE:
case DISP_EVT_VPP_STOP:
case DISP_EVT_VPP_WINCON:
disp_ss_event_log_vpp(type, sd, time);
break;
default:
break;
}
if (decon->disp_ss_log_level == DISP_EVENT_LEVEL_LOW)
return;
/* additionally logging hardly */
switch (type) {
case DISP_EVT_ACT_VSYNC:
case DISP_EVT_DEACT_VSYNC:
case DISP_EVT_WIN_CONFIG:
disp_ss_event_log_decon(type, sd, time);
break;
case DISP_EVT_DSIM_SUSPEND:
case DISP_EVT_DSIM_RESUME:
disp_ss_event_log_dsim(type, sd, time);
break;
case DISP_EVT_VPP_SUSPEND:
case DISP_EVT_VPP_RESUME:
case DISP_EVT_VPP_UPDATE_DONE:
case DISP_EVT_VPP_SHADOW_UPDATE:
disp_ss_event_log_vpp(type, sd, time);
default:
break;
}
}
void DISP_SS_EVENT_LOG_WINCON(struct v4l2_subdev *sd, struct decon_reg_data *regs)
{
struct decon_device *decon = container_of(sd, struct decon_device, sd);
int idx = atomic_inc_return(&decon->disp_ss_log_idx) % DISP_EVENT_LOG_MAX;
struct disp_ss_log *log = &decon->disp_ss_log[idx];
int win = 0;
bool window_updated = false;
log->time = ktime_get();
log->type = DISP_EVT_UPDATE_HANDLER;
for (win = 0; win < MAX_DECON_WIN; win++) {
if (regs->win_regs[win].wincon & WIN_CONTROL_EN_F) {
memcpy(&log->data.reg.win_regs[win], &regs->win_regs[win],
sizeof(struct decon_window_regs));
memcpy(&log->data.reg.win_config[win], &regs->vpp_config[win],
sizeof(struct decon_win_config));
} else {
log->data.reg.win_config[win].state = DECON_WIN_STATE_DISABLED;
}
}
if (decon->out_type == DECON_OUT_WB)
memcpy(&log->data.reg.win_config[MAX_DECON_WIN], &regs->vpp_config[MAX_DECON_WIN],
sizeof(struct decon_win_config));
#ifdef CONFIG_FB_WINDOW_UPDATE
if ((regs->need_update) ||
(decon->need_update && regs->update_win.w)) {
window_updated = true;
memcpy(&log->data.reg.win, &regs->update_win,
sizeof(struct decon_rect));
}
#endif
if (!window_updated) {
log->data.reg.win.x = 0;
log->data.reg.win.y = 0;
log->data.reg.win.w = decon->lcd_info->xres;
log->data.reg.win.h = decon->lcd_info->yres;
}
}
/* Common API to log a event related with DSIM COMMAND */
void DISP_SS_EVENT_LOG_CMD(struct v4l2_subdev *sd, u32 cmd_id, unsigned long data)
{
struct dsim_device *dsim = container_of(sd, struct dsim_device, sd);
struct decon_device *decon = get_decon_drvdata(dsim->id);
int idx, i;
struct disp_ss_log *log;
if (!decon || IS_ERR_OR_NULL(decon->debug_event))
return;
idx = atomic_inc_return(&decon->disp_ss_log_idx) % DISP_EVENT_LOG_MAX;
log = &decon->disp_ss_log[idx];
log->time = ktime_get();
log->type = DISP_EVT_DSIM_COMMAND;
log->data.cmd_buf.id = cmd_id;
if (cmd_id == MIPI_DSI_DCS_LONG_WRITE)
log->data.cmd_buf.buf = *(u8 *)(data);
else
log->data.cmd_buf.buf = (u8)data;
for (i = 0; i < DISP_CALLSTACK_MAX; i++)
log->data.cmd_buf.caller[i] = (void *)((size_t)return_address(i + 1));
}
/* display logged events related with DECON */
void DISP_SS_EVENT_SHOW(struct seq_file *s, struct decon_device *decon)
{
int idx = atomic_read(&decon->disp_ss_log_idx) % DISP_EVENT_LOG_MAX;
struct disp_ss_log *log;
int latest = idx;
struct timeval tv;
ktime_t prev_ktime;
/* TITLE */
seq_printf(s, "-------------------DECON%d EVENT LOGGER ----------------------\n",
decon->id);
seq_printf(s, "-- STATUS: LPD(%s) ", IS_ENABLED(CONFIG_DECON_LPD_DISPLAY) ? "on" : "off");
seq_printf(s, "PKTGO(%s) ", IS_ENABLED(CONFIG_DECON_MIPI_DSI_PKTGO) ? "on" : "off");
seq_printf(s, "BlockMode(%s) ", IS_ENABLED(CONFIG_DECON_BLOCKING_MODE) ? "on" : "off");
seq_printf(s, "Window_Update(%s)\n", IS_ENABLED(CONFIG_FB_WINDOW_UPDATE) ? "on" : "off");
seq_puts(s, "-------------------------------------------------------------\n");
seq_printf(s, "%14s %20s %20s\n",
"Time", "Event ID", "Remarks");
seq_puts(s, "-------------------------------------------------------------\n");
/* return if there is no event log */
if (idx < 0)
return;
/* Seek a oldest from current index */
idx = (idx + DISP_EVENT_LOG_MAX - DISP_EVENT_PRINT_MAX) % DISP_EVENT_LOG_MAX;
prev_ktime = ktime_set(0, 0);
do {
if (++idx >= DISP_EVENT_LOG_MAX)
idx = 0;
/* Seek a index */
log = &decon->disp_ss_log[idx];
/* TIME */
tv = ktime_to_timeval(log->time);
seq_printf(s, "[%6ld.%06ld] ", tv.tv_sec, tv.tv_usec);
/* If there is no timestamp, then exit directly */
if (!tv.tv_sec)
break;
/* EVETN ID + Information */
switch (log->type) {
case DISP_EVT_BLANK:
seq_printf(s, "%20s %20s", "FB_BLANK", "-\n");
break;
case DISP_EVT_UNBLANK:
seq_printf(s, "%20s %20s", "FB_UNBLANK", "-\n");
break;
case DISP_EVT_ACT_VSYNC:
seq_printf(s, "%20s %20s", "ACT_VSYNC", "-\n");
break;
case DISP_EVT_DEACT_VSYNC:
seq_printf(s, "%20s %20s", "DEACT_VSYNC", "-\n");
break;
case DISP_EVT_WIN_CONFIG:
seq_printf(s, "%20s %20s", "WIN_CONFIG", "-\n");
break;
case DISP_EVT_TE_INTERRUPT:
prev_ktime = ktime_sub(log->time, prev_ktime);
seq_printf(s, "%20s ", "TE_INTERRUPT");
seq_printf(s, "time_diff=[%ld.%04lds]\n",
ktime_to_timeval(prev_ktime).tv_sec,
ktime_to_timeval(prev_ktime).tv_usec/100);
/* Update for latest DISP_EVT_TE time */
prev_ktime = log->time;
break;
case DISP_EVT_UNDERRUN:
seq_printf(s, "%20s %20s", "UNDER_RUN", "-\n");
break;
case DISP_EVT_DECON_FRAMEDONE:
seq_printf(s, "%20s %20s", "DECON_FRAME_DONE", "-\n");
break;
case DISP_EVT_UPDATE_HANDLER:
seq_printf(s, "%20s ", "UPDATE_HANDLER");
seq_printf(s, "Partial Size (%d,%d,%d,%d)\n",
log->data.reg.win.x,
log->data.reg.win.y,
log->data.reg.win.w,
log->data.reg.win.h);
break;
case DISP_EVT_DSIM_COMMAND:
seq_printf(s, "%20s ", "DSIM_COMMAND");
seq_printf(s, "id=0x%x, command=0x%x\n",
log->data.cmd_buf.id,
log->data.cmd_buf.buf);
break;
case DISP_EVT_TRIG_MASK:
seq_printf(s, "%20s %20s", "TRIG_MASK", "-\n");
break;
case DISP_EVT_TRIG_UNMASK:
seq_printf(s, "%20s %20s", "TRIG_UNMASK", "-\n");
break;
case DISP_EVT_VPP_WINCON:
seq_printf(s, "%20s ", "VPP_WINCON");
seq_printf(s, "ID:%d, start= %d, done= %d\n",
log->data.vpp.id,
log->data.vpp.start_cnt,
log->data.vpp.done_cnt);
break;
case DISP_EVT_VPP_FRAMEDONE:
seq_printf(s, "%20s ", "VPP_FRAMEDONE");
seq_printf(s, "ID:%d, start=%d, done=%d\n",
log->data.vpp.id,
log->data.vpp.start_cnt,
log->data.vpp.done_cnt);
break;
case DISP_EVT_VPP_STOP:
seq_printf(s, "%20s ", "VPP_STOP");
seq_printf(s, "(id:%d)\n", log->data.vpp.id);
break;
case DISP_EVT_VPP_SUSPEND:
seq_printf(s, "%20s %20s", "VPP_SUSPEND", "-\n");
break;
case DISP_EVT_VPP_RESUME:
seq_printf(s, "%20s %20s", "VPP_RESUME", "-\n");
break;
case DISP_EVT_DECON_SUSPEND:
seq_printf(s, "%20s %20s", "DECON_SUSPEND", "-\n");
break;
case DISP_EVT_DECON_RESUME:
seq_printf(s, "%20s %20s", "DECON_RESUME", "-\n");
break;
case DISP_EVT_ENTER_LPD:
seq_printf(s, "%20s ", "ENTER_LPD");
tv = ktime_to_timeval(log->data.pm.elapsed);
seq_printf(s, "pm=%s, elapsed=[%ld.%03lds]\n",
log->data.pm.pm_status ? "active " : "suspend",
tv.tv_sec, tv.tv_usec/1000);
break;
case DISP_EVT_EXIT_LPD:
seq_printf(s, "%20s ", "EXIT_LPD");
tv = ktime_to_timeval(log->data.pm.elapsed);
seq_printf(s, "pm=%s, elapsed=[%ld.%03lds]\n",
log->data.pm.pm_status ? "active " : "suspend",
tv.tv_sec, tv.tv_usec/1000);
break;
case DISP_EVT_DSIM_SUSPEND:
seq_printf(s, "%20s %20s", "DSIM_SUSPEND", "-\n");
break;
case DISP_EVT_DSIM_RESUME:
seq_printf(s, "%20s %20s", "DSIM_RESUME", "-\n");
break;
case DISP_EVT_ENTER_ULPS:
seq_printf(s, "%20s ", "ENTER_ULPS");
tv = ktime_to_timeval(log->data.pm.elapsed);
seq_printf(s, "pm=%s, elapsed=[%ld.%03lds]\n",
log->data.pm.pm_status ? "active " : "suspend",
tv.tv_sec, tv.tv_usec/1000);
break;
case DISP_EVT_EXIT_ULPS:
seq_printf(s, "%20s ", "EXIT_ULPS");
tv = ktime_to_timeval(log->data.pm.elapsed);
seq_printf(s, "pm=%s, elapsed=[%ld.%03lds]\n",
log->data.pm.pm_status ? "active " : "suspend",
tv.tv_sec, tv.tv_usec/1000);
break;
default:
seq_printf(s, "%20s (%2d)\n", "NO_DEFINED", log->type);
break;
}
} while (latest != idx);
seq_puts(s, "-------------------------------------------------------------\n");
return;
}
void DISP_SS_EVENT_SIZE_ERR_LOG(struct v4l2_subdev *sd, struct disp_ss_size_info *info)
{
struct decon_device *decon = container_of(sd, struct decon_device, sd);
int idx = (decon->disp_ss_size_log_idx++) % DISP_EVENT_SIZE_ERR_MAX;
struct disp_ss_size_err_info *log = &decon->disp_ss_size_log[idx];
if (!decon)
return;
log->time = ktime_get();
memcpy(&log->info, info, sizeof(struct disp_ss_size_info));
}
#endif

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2014 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_HELPER_H__
#define __SAMSUNG_DECON_HELPER_H__
#include <linux/device.h>
#include "decon.h"
int decon_clk_set_parent(struct device *dev, const char *c, const char *p);
int decon_clk_set_rate(struct device *dev, struct clk *clk,
const char *conid, unsigned long rate);
unsigned long decon_clk_get_rate(struct device *dev, const char *clkid);
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);
#endif /* __SAMSUNG_DECON_HELPER_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Core file for Samsung 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.
*/
#include <linux/of_gpio.h>
#include <linux/clk-provider.h>
#include "decon.h"
#include "decon_helper.h"
irqreturn_t decon_s_irq_handler(int irq, void *dev_data)
{
struct decon_device *decon = dev_data;
ktime_t timestamp = ktime_get();
u32 irq_sts_reg;
spin_lock(&decon->slock);
if ((decon->state == DECON_STATE_OFF) ||
(decon->state == DECON_STATE_LPD)) {
goto irq_end;
}
irq_sts_reg = decon_reg_get_interrupt_and_clear(decon->id);
if (irq_sts_reg & INTERRUPT_DISPIF_VSTATUS_INT_EN) {
decon->vsync_info.timestamp = timestamp;
wake_up_interruptible_all(&decon->vsync_info.wait);
}
if (irq_sts_reg & INTERRUPT_FIFO_LEVEL_INT_EN) {
DISP_SS_EVENT_LOG(DISP_EVT_UNDERRUN, &decon->sd, ktime_set(0, 0));
decon_err("DECON-ext FIFO underrun\n");
}
if (irq_sts_reg & INTERRUPT_FRAME_DONE_INT_EN) {
DISP_SS_EVENT_LOG(DISP_EVT_DECON_FRAMEDONE, &decon->sd, ktime_set(0, 0));
decon_warn("DECON-ext frame done interrupt shouldn't happen\n");
decon->frame_done_cnt_cur++;
decon_lpd_trig_reset(decon);
}
if (irq_sts_reg & INTERRUPT_RESOURCE_CONFLICT_INT_EN)
DISP_SS_EVENT_LOG(DISP_EVT_RSC_CONFLICT, &decon->sd,
ktime_set(0, 0));
irq_end:
spin_unlock(&decon->slock);
return IRQ_HANDLED;
}
int decon_s_get_clocks(struct decon_device *decon)
{
return 0;
}
void decon_s_set_clocks(struct decon_device *decon)
{
}
int decon_s_register_irq(struct platform_device *pdev, struct decon_device *decon)
{
struct device *dev = decon->dev;
struct resource *res;
int ret = 0;
/* Get IRQ resource and register IRQ handler. */
/* 0: FIFO irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
ret = devm_request_irq(dev, res->start, decon_s_irq_handler, 0,
pdev->name, decon);
if (ret) {
decon_err("failed to install irq\n");
return ret;
}
/* 1: VStatus irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
ret = devm_request_irq(dev, res->start, decon_s_irq_handler, 0,
pdev->name, decon);
if (ret) {
decon_err("failed to install irq\n");
return ret;
}
/* 2: FrameDone irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
ret = devm_request_irq(dev, res->start, decon_s_irq_handler, 0,
pdev->name, decon);
if (ret) {
decon_err("failed to install irq\n");
return ret;
}
/* 3: Extra Interrupts: Resource Conflict irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 3);
ret = devm_request_irq(dev, res->start, decon_s_irq_handler, 0,
pdev->name, decon);
if (ret) {
decon_err("failed to install irq\n");
return ret;
}
return ret;
}

View file

@ -0,0 +1,170 @@
/*
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Core file for Samsung 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.
*/
#include <linux/of_gpio.h>
#include <linux/clk-provider.h>
#include "decon.h"
#include "decon_helper.h"
#include "../../../../staging/android/sw_sync.h"
int decon_t_set_lcd_info(struct decon_device *decon)
{
struct decon_lcd *lcd_info;
if (decon->lcd_info != NULL)
return 0;
lcd_info = kzalloc(sizeof(struct decon_lcd), GFP_KERNEL);
if (!lcd_info) {
decon_err("could not allocate decon_lcd for wb\n");
return -ENOMEM;
}
decon->lcd_info = lcd_info;
decon->lcd_info->width = 1920;
decon->lcd_info->height = 1080;
decon->lcd_info->xres = 1920;
decon->lcd_info->yres = 1080;
decon->lcd_info->vfp = 2;
decon->lcd_info->vbp = 20;
decon->lcd_info->hfp = 20;
decon->lcd_info->hbp = 20;
decon->lcd_info->vsa = 2;
decon->lcd_info->hsa = 20;
decon->lcd_info->fps = 60;
decon->out_type = DECON_OUT_WB;
decon_info("decon_%d output size for writeback %dx%d\n", decon->id,
decon->lcd_info->width, decon->lcd_info->height);
return 0;
}
irqreturn_t decon_t_irq_handler(int irq, void *dev_data)
{
struct decon_device *decon = dev_data;
u32 irq_sts_reg;
spin_lock(&decon->slock);
if ((decon->state == DECON_STATE_OFF) ||
(decon->state == DECON_STATE_LPD)) {
goto irq_end;
}
irq_sts_reg = decon_reg_get_interrupt_and_clear(decon->id);
if (irq_sts_reg & INTERRUPT_FIFO_LEVEL_INT_EN) {
DISP_SS_EVENT_LOG(DISP_EVT_UNDERRUN, &decon->sd, ktime_set(0, 0));
decon_err("DECON_T FIFO underrun\n");
}
if (irq_sts_reg & INTERRUPT_FRAME_DONE_INT_EN) {
decon_lpd_trig_reset(decon);
DISP_SS_EVENT_LOG(DISP_EVT_DECON_FRAMEDONE, &decon->sd, ktime_set(0, 0));
decon_dbg("%s Frame Done is occured. timeline:%d, %d\n",
__func__, decon->timeline->value, decon->timeline_max);
}
if (irq_sts_reg & INTERRUPT_RESOURCE_CONFLICT_INT_EN)
DISP_SS_EVENT_LOG(DISP_EVT_RSC_CONFLICT, &decon->sd, ktime_set(0, 0));
irq_end:
spin_unlock(&decon->slock);
return IRQ_HANDLED;
}
int decon_t_get_clocks(struct decon_device *decon)
{
decon->res.pclk = clk_get(decon->dev, "decon_pclk");
if (IS_ERR_OR_NULL(decon->res.pclk)) {
decon_err("failed to get decon_pclk\n");
return -ENODEV;
}
decon->res.eclk = clk_get(decon->dev, "eclk_user");
if (IS_ERR_OR_NULL(decon->res.eclk)) {
decon_err("failed to get eclk_user\n");
return -ENODEV;
}
decon->res.eclk_leaf = clk_get(decon->dev, "eclk_leaf");
if (IS_ERR_OR_NULL(decon->res.eclk_leaf)) {
decon_err("failed to get eclk_leaf\n");
return -ENODEV;
}
return 0;
}
void decon_t_set_clocks(struct decon_device *decon)
{
struct device *dev = decon->dev;
struct decon_clocks clks;
struct decon_param p;
decon_to_init_param(decon, &p);
decon_reg_get_clock_ratio(&clks, p.lcd_info);
/* ECLK */
decon_clk_set_rate(dev, decon->res.eclk_leaf,
NULL, clks.decon[CLK_ID_ECLK] * MHZ);
decon_dbg("%s: pclk %ld eclk %ld Mhz\n",
__func__,
clk_get_rate(decon->res.pclk) / MHZ,
clk_get_rate(decon->res.eclk_leaf) / MHZ);
return;
}
int decon_t_register_irq(struct platform_device *pdev, struct decon_device *decon)
{
struct device *dev = decon->dev;
struct resource *res;
int ret = 0;
/* Get IRQ resource and register IRQ handler. */
/* 0: FIFO irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
ret = devm_request_irq(dev, res->start, decon_t_irq_handler, 0,
pdev->name, decon);
if (ret) {
decon_err("failed to install irq\n");
return ret;
}
/* 1: VStatus irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
ret = devm_request_irq(dev, res->start, decon_t_irq_handler, 0,
pdev->name, decon);
if (ret) {
decon_err("failed to install irq\n");
return ret;
}
/* 2: FrameDone irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
ret = devm_request_irq(dev, res->start, decon_t_irq_handler, 0,
pdev->name, decon);
if (ret) {
decon_err("failed to install irq\n");
return ret;
}
/* 3: Extra Interrupts: Resource Conflict irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 3);
ret = devm_request_irq(dev, res->start, decon_t_irq_handler, 0,
pdev->name, decon);
if (ret) {
decon_err("failed to install irq\n");
return ret;
}
return ret;
}

View file

@ -0,0 +1,228 @@
/* linux/drivers/video/exynos_decon/dsim.h
*
* Header file for Samsung MIPI-DSI common driver.
*
* Copyright (c) 2013 Samsung Electronics
* Haowei Li <haowei.li@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __DSIM_H__
#define __DSIM_H__
#include <linux/device.h>
#include <linux/fb.h>
#include <linux/notifier.h>
#include <linux/kernel.h>
#include <linux/regulator/consumer.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <media/v4l2-subdev.h>
#include <media/media-entity.h>
#include "./panels/decon_lcd.h"
#include "regs-dsim.h"
#include "dsim_common.h"
#define DSIM_PAD_SINK 0
#define DSIM_PADS_NUM 1
#define DSIM_RX_FIFO_READ_DONE (0x30800002)
#define DSIM_MAX_RX_FIFO (64)
#define dsim_err(fmt, ...) \
do { \
pr_err(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define dsim_info(fmt, ...) \
do { \
pr_info(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define dsim_dbg(fmt, ...) \
do { \
pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define call_panel_ops(q, op, args...) \
(((q)->panel_ops->op) ? ((q)->panel_ops->op(args)) : 0)
extern struct dsim_device *dsim0_for_decon;
extern struct dsim_device *dsim1_for_decon;
extern struct mipi_dsim_lcd_driver s6e3ha0_mipi_lcd_driver;
extern struct mipi_dsim_lcd_driver s6e3ha2k_mipi_lcd_driver;
extern struct mipi_dsim_lcd_driver s6e3hf2_mipi_lcd_driver;
extern struct mipi_dsim_lcd_driver s6e3hf2_wqhd_mipi_lcd_driver;
extern struct mipi_dsim_lcd_driver s6e3fa0_mipi_lcd_driver;
enum mipi_dsim_pktgo_state {
DSIM_PKTGO_DISABLED,
DSIM_PKTGO_STANDBY,
DSIM_PKTGO_ENABLED
};
/* operation state of dsim driver */
enum dsim_state {
DSIM_STATE_HSCLKEN, /* HS clock was enabled. */
DSIM_STATE_ULPS, /* DSIM was entered ULPS state */
DSIM_STATE_SUSPEND /* DSIM is suspend state */
};
struct dsim_resources {
struct clk *pclk;
struct clk *dphy_esc;
struct clk *dphy_byte;
struct clk *rgb_vclk0;
struct clk *pclk_disp;
int lcd_power[2];
int lcd_reset;
};
struct panel_private {
struct backlight_device *bd;
unsigned int power;
unsigned int lcdConnected;
};
struct dsim_device {
struct device *dev;
void *decon;
struct dsim_resources res;
unsigned int irq;
void __iomem *reg_base;
enum dsim_state state;
unsigned int data_lane;
unsigned long hs_clk;
unsigned long byte_clk;
unsigned long escape_clk;
unsigned char freq_band;
struct notifier_block fb_notif;
struct lcd_device *lcd;
unsigned int enabled;
struct decon_lcd lcd_info;
struct dphy_timing_value timing;
int pktgo;
int id;
u32 data_lane_cnt;
struct mipi_dsim_lcd_driver *panel_ops;
spinlock_t slock;
struct mutex lock;
struct v4l2_subdev sd;
struct media_pad pad;
struct panel_private priv;
struct dsim_clks_param clks_param;
struct phy *phy;
};
/**
* driver structure for mipi-dsi based lcd panel.
*
* this structure should be registered by lcd panel driver.
* mipi-dsi driver seeks lcd panel registered through name field
* and calls these callback functions in appropriate time.
*/
struct mipi_dsim_lcd_driver {
int (*probe)(struct dsim_device *dsim);
int (*suspend)(struct dsim_device *dsim);
int (*displayon)(struct dsim_device *dsim);
int (*resume)(struct dsim_device *dsim);
int (*dump)(struct dsim_device *dsim);
};
int dsim_write_data(struct dsim_device *dsim, unsigned int data_id,
unsigned long data0, unsigned int data1);
int dsim_read_data(struct dsim_device *dsim, u32 data_id, u32 addr,
u32 count, u8 *buf);
#ifdef CONFIG_DECON_MIPI_DSI_PKTGO
void dsim_pkt_go_ready(struct dsim_device *dsim);
void dsim_pkt_go_enable(struct dsim_device *dsim, bool enable);
#endif
static inline struct dsim_device *get_dsim_drvdata(u32 id)
{
if (id)
return dsim1_for_decon;
else
return dsim0_for_decon;
}
static inline int dsim_rd_data(u32 id, u32 cmd_id,
u32 addr, u32 size, u8 *buf)
{
int ret;
struct dsim_device *dsim = get_dsim_drvdata(id);
ret = dsim_read_data(dsim, cmd_id, addr, size, buf);
if (ret)
return ret;
return 0;
}
static inline int dsim_wr_data(u32 id, u32 cmd_id, unsigned long d0, u32 d1)
{
int ret;
struct dsim_device *dsim = get_dsim_drvdata(id);
ret = dsim_write_data(dsim, cmd_id, d0, d1);
if (ret)
return ret;
return 0;
}
/* register access subroutines */
static inline u32 dsim_read(u32 id, u32 reg_id)
{
struct dsim_device *dsim = get_dsim_drvdata(id);
return readl(dsim->reg_base + reg_id);
}
static inline u32 dsim_read_mask(u32 id, u32 reg_id, u32 mask)
{
u32 val = dsim_read(id, reg_id);
val &= (mask);
return val;
}
static inline void dsim_write(u32 id, u32 reg_id, u32 val)
{
struct dsim_device *dsim = get_dsim_drvdata(id);
writel(val, dsim->reg_base + reg_id);
}
static inline void dsim_write_mask(u32 id, u32 reg_id, u32 val, u32 mask)
{
struct dsim_device *dsim = get_dsim_drvdata(id);
u32 old = dsim_read(id, reg_id);
val = (val & mask) | (old & ~mask);
writel(val, dsim->reg_base + reg_id);
}
u32 dsim_reg_get_yres(u32 id);
u32 dsim_reg_get_xres(u32 id);
#define DSIM_IOC_ENTER_ULPS _IOW('D', 0, u32)
#define DSIM_IOC_LCD_OFF _IOW('D', 1, u32)
#define DSIM_IOC_PKT_GO_ENABLE _IOW('D', 2, u32)
#define DSIM_IOC_PKT_GO_DISABLE _IOW('D', 3, u32)
#define DSIM_IOC_PKT_GO_READY _IOW('D', 4, u32)
#define DSIM_IOC_GET_LCD_INFO _IOW('D', 5, struct decon_lcd *)
#define DSIM_IOC_PARTIAL_CMD _IOW('D', 6, u32)
#define DSIM_IOC_SET_PORCH _IOW('D', 7, struct decon_lcd *)
#define DSIM_IOC_DUMP _IOW('D', 8, u32)
#endif /* __DSIM_H__ */

View file

@ -0,0 +1,169 @@
/* dsim_common.h
*
* Header file for Samsung MIPI-DSI lowlevel driver.
*
* Copyright (c) 2014 Samsung Electronics
* Jiun Yu <jiun.yu@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _DSIM_COMMON_H_
#define _DSIM_COMMON_H_
#include "./panels/decon_lcd.h"
#define DSIM_PIXEL_FORMAT_RGB24 0x7
#define DSIM_PIXEL_FORMAT_RGB18 0x6
#define DSIM_PIXEL_FORMAT_RGB18_PACKED 0x5
/* define DSI lane types. */
enum {
DSIM_LANE_CLOCK = (1 << 0),
DSIM_LANE_DATA0 = (1 << 1),
DSIM_LANE_DATA1 = (1 << 2),
DSIM_LANE_DATA2 = (1 << 3),
DSIM_LANE_DATA3 = (1 << 4),
};
struct dsim_pll_param {
u32 p;
u32 m;
u32 s;
u32 pll_freq; /* in/out parameter: Mhz */
};
struct dsim_clks {
u32 hs_clk;
u32 esc_clk;
u32 byte_clk;
};
struct dphy_timing_value {
u32 bps;
u32 clk_prepare;
u32 clk_zero;
u32 clk_post;
u32 clk_trail;
u32 hs_prepare;
u32 hs_zero;
u32 hs_trail;
u32 lpx;
u32 hs_exit;
u32 b_dphyctl;
};
struct dsim_clks_param {
struct dsim_clks clks;
struct dsim_pll_param pll;
struct dphy_timing_value t;
u32 esc_div;
};
/* CAL APIs list */
int dsim_reg_init(u32 id, struct decon_lcd *lcd_info,
u32 data_lane_cnt, struct dsim_clks *clks);
void dsim_reg_init_probe(u32 id, struct decon_lcd *lcd_info,
u32 data_lane_cnt, struct dsim_clks *clks);
int dsim_reg_set_clocks(u32 id, struct dsim_clks *clks, struct stdphy_pms *dphy_pms, u32 en);
int dsim_reg_set_lanes(u32 id, u32 lanes, u32 en);
int dsim_reg_set_hs_clock(u32 id, u32 en);
void dsim_reg_set_int(u32 id, u32 en);
int dsim_reg_set_ulps(u32 id, u32 en, u32 lanes);
int dsim_reg_set_smddi_ulps(u32 id, u32 en, u32 lanes);
/* CAL raw functions list */
void dsim_reg_sw_reset(u32 id);
void dsim_reg_dphy_reset(u32 id);
void dsim_reg_funtion_reset(u32 id);
void dsim_reg_dp_dn_swap(u32 id, u32 en);
void dsim_reg_set_num_of_lane(u32 id, u32 lane);
void dsim_reg_enable_lane(u32 id, u32 lane, u32 en);
void dsim_reg_set_pll_freq(u32 id, u32 p, u32 m, u32 s);
void dsim_reg_pll_stable_time(u32 id);
void dsim_reg_set_dphy_timing_values(u32 id, struct dphy_timing_value *t);
void dsim_reg_clear_int(u32 id, u32 int_src);
void dsim_reg_clear_int_all(u32 id);
void dsim_reg_set_pll(u32 id, u32 en);
u32 dsim_reg_is_pll_stable(u32 id);
int dsim_reg_enable_pll(u32 id, u32 en);
void dsim_reg_set_byte_clock(u32 id, u32 en);
void dsim_reg_set_esc_clk_prescaler(u32 id, u32 en, u32 p);
void dsim_reg_set_esc_clk_on_lane(u32 id, u32 en, u32 lane);
u32 dsim_reg_wait_lane_stop_state(u32 id);
void dsim_reg_set_stop_state_cnt(u32 id);
void dsim_reg_set_bta_timeout(u32 id);
void dsim_reg_set_lpdr_timeout(u32 id);
void dsim_reg_set_porch(u32 id, struct decon_lcd *lcd);
void dsim_reg_set_pixel_format(u32 id, u32 pixformat);
void dsim_reg_set_config(u32 id, struct decon_lcd *lcd_info, u32 data_lane_cnt);
void dsim_reg_set_cmd_transfer_mode(u32 id, u32 lp);
void dsim_reg_set_multipix(u32 id, u32 multipix);
void dsim_reg_set_vc_id(u32 id, u32 vcid);
void dsim_reg_set_video_mode(u32 id, u32 mode);
void dsim_reg_enable_dsc(u32 id, u32 en);
void dsim_reg_disable_hsa(u32 id, u32 en);
void dsim_reg_disable_hbp(u32 id, u32 en);
void dsim_reg_disable_hfp(u32 id, u32 en);
void dsim_reg_disable_hse(u32 id, u32 en);
void dsim_reg_set_hsync_preserve(u32 id, u32 en);
void dsim_reg_set_burst_mode(u32 id, u32 burst);
void dsim_reg_set_sync_inform(u32 id, u32 inform);
void dsim_reg_set_cmdallow(u32 id, u32 cmdallow);
void dsim_reg_set_stable_vfp(u32 id, u32 stablevfp);
void dsim_reg_set_vbp(u32 id, u32 vbp);
void dsim_reg_set_hfp(u32 id, u32 hfp);
void dsim_reg_set_hbp(u32 id, u32 hbp);
void dsim_reg_set_vsa(u32 id, u32 vsa);
void dsim_reg_set_hsa(u32 id, u32 hsa);
void dsim_reg_set_vresol(u32 id, u32 vresol);
void dsim_reg_set_hresol(u32 id, u32 hresol, struct decon_lcd *lcd);
void dsim_reg_set_multi_packet_count(u32 id, u32 multipacketcnt);
void dsim_reg_set_command_control(u32 id, u32 cmdcontrol);
void dsim_reg_set_time_stable_vfp(u32 id, u32 stablevfp);
void dsim_reg_set_time_vsync_timeout(u32 id, u32 vsynctout);
void dsim_reg_set_time_te_protect_on(u32 id, u32 teprotecton);
void dsim_reg_set_time_te_timeout(u32 id, u32 tetout);
void dsim_reg_set_hsync_timeout(u32 id, u32 hsynctout);
void dsim_reg_enable_mflush(u32 id, u32 en);
void dsim_reg_enable_noncontinuous_clock(u32 id, u32 en);
void dsim_reg_enable_clocklane_stop_start(u32 id, u32 en);
void dsim_reg_enable_packetgo(u32 id, u32 en);
void dsim_reg_set_packetgo_ready(u32 id);
void dsim_reg_enable_multi_command_packet(u32 id, u32 en);
void dsim_reg_enable_shadow(u32 id, u32 en);
void dsim_reg_enable_hs_clock(u32 id, u32 en);
void dsim_reg_enable_byte_clock(u32 id, u32 en);
u32 dsim_reg_is_hs_clk_ready(u32 id);
void dsim_reg_enable_per_frame_read(u32 id, u32 en);
void dsim_reg_enable_qchannel(u32 id, u32 en);
int dsim_reg_wait_hs_clk_ready(u32 id);
void dsim_reg_set_fifo_ctrl(u32 id, u32 cfg);
void dsim_reg_force_dphy_stop_state(u32 id, u32 en);
void dsim_reg_wr_tx_header(u32 id, u32 data_id, unsigned long data0, u32 data1);
void dsim_reg_wr_tx_payload(u32 id, u32 payload);
void dsim_reg_enter_ulps(u32 id, u32 enter);
void dsim_reg_exit_ulps(u32 id, u32 exit);
int dsim_reg_set_ulps_by_ddi(u32 id, u32 ddi_type, u32 lanes, u32 en);
int dsim_reg_wait_enter_ulps_state(u32 id, u32 lanes);
int dsim_reg_wait_exit_ulps_state(u32 id);
void dsim_reg_set_standby(u32 id, u32 en);
void dsim_reg_set_bist(u32 id, u32 en, u32 vfp, u32 format, u32 type);
void dsim_reg_set_packet_ctrl(u32 id);
void dsim_reg_enable_loopback(u32 id, u32 en);
void dsim_reg_set_loopback_id(u32 id, u32 en);
void dsim_reg_set_pkt_go_enable(u32 id, bool en);
void dsim_reg_set_pkt_go_ready(u32 id);
void dsim_reg_set_pkt_go_cnt(u32 id, unsigned int count);
void dsim_reg_set_shadow(u32 id, u32 en);
void dsim_reg_shadow_update(u32 id);
int dsim_reg_exit_ulps_and_start(u32 id, u32 ddi_type, u32 lanes);
int dsim_reg_stop_and_enter_ulps(u32 id, u32 ddi_type, u32 lanes);
void dsim_reg_start(u32 id, struct dsim_clks *clks, u32 lanes);
void dsim_reg_stop(u32 id, u32 lanes);
void dsim_reg_set_partial_update(u32 id, struct decon_lcd *lcd_info);
#endif /* _DSIM_COMMON_H_ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,7 @@
config EXYNOS_DECON_LCD
depends on EXYNOS_DECON_8890
bool "Select LCD panel driver"
config EXYNOS_DECON_LCD_S6E3HA2K
depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSI
tristate "S6E3HA2K AMOLED WQHD LCD driver(1440 x 2560)"

View file

@ -0,0 +1 @@
obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3HA2K) += s6e3ha2k_mipi_lcd.o s6e3ha2k_lcd_ctrl.o

View file

@ -0,0 +1,72 @@
/* drivers/video/exynos_decon/lcd.h
*
* Copyright (c) 2011 Samsung Electronics
* 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 __DECON_LCD__
#define __DECON_LCD__
enum decon_psr_mode {
DECON_VIDEO_MODE = 0,
DECON_DP_PSR_MODE = 1,
DECON_MIPI_COMMAND_MODE = 2,
};
/* Mic ratio: 0: 1/2 ratio, 1: 1/3 ratio */
enum decon_mic_comp_ratio {
MIC_COMP_RATIO_1_2 = 0,
MIC_COMP_RATIO_1_3 = 1,
MIC_COMP_BYPASS
};
enum mic_ver {
MIC_VER_1_1,
MIC_VER_1_2,
MIC_VER_2_0,
};
enum type_of_ddi {
TYPE_OF_SM_DDI = 0,
TYPE_OF_MAGNA_DDI,
TYPE_OF_NORMAL_DDI,
};
struct stdphy_pms {
unsigned int p;
unsigned int m;
unsigned int s;
};
struct decon_lcd {
enum decon_psr_mode mode;
unsigned int vfp;
unsigned int vbp;
unsigned int hfp;
unsigned int hbp;
unsigned int vsa;
unsigned int hsa;
unsigned int xres;
unsigned int yres;
unsigned int width;
unsigned int height;
unsigned int hs_clk;
struct stdphy_pms dphy_pms;
unsigned int esc_clk;
unsigned int fps;
unsigned int mic_enabled;
enum decon_mic_comp_ratio mic_ratio;
unsigned int dsc_enabled;
unsigned int dsc_slice;
enum mic_ver mic_ver;
enum type_of_ddi ddi_type;
};
#endif

View file

@ -0,0 +1,24 @@
/* linux/drivers/video/decon_display/s6e3fa0_gamma.h
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
*
* Haowe Li <haowei.li@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LCD_CTRL_H__
#define __LCD_CTRL_H__
#include "decon_lcd.h"
void lcd_init(int id, struct decon_lcd *lcd);
void lcd_enable(int id);
void lcd_disable(int id);
int lcd_gamma_ctrl(int id, unsigned int backlightlevel);
int lcd_gamma_update(int id);
int lcd_dump(int id);
#endif /* __LCD_CTRL_H__ */

View file

@ -0,0 +1,364 @@
/*
* drivers/video/decon/panels/s6e3ha2k_lcd_ctrl.c
*
* Samsung SoC MIPI LCD CONTROL functions
*
* Copyright (c) 2014 Samsung Electronics
*
* Jiun Yu, <jiun.yu@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "s6e3ha2k_param.h"
#include "lcd_ctrl.h"
/* use FW_TEST definition when you test CAL on firmware */
/* #define FW_TEST */
#ifdef FW_TEST
#include "../dsim_fw.h"
#include "mipi_display.h"
#else
#include "../dsim.h"
#include <video/mipi_display.h>
#endif
/* Porch values. It depends on command or video mode */
#define S6E3HA2K_CMD_VBP 15
#define S6E3HA2K_CMD_VFP 1
#define S6E3HA2K_CMD_VSA 1
#define S6E3HA2K_CMD_HBP 1
#define S6E3HA2K_CMD_HFP 1
#define S6E3HA2K_CMD_HSA 1
/* These need to define */
#define S6E3HA2K_VIDEO_VBP 15
#define S6E3HA2K_VIDEO_VFP 1
#define S6E3HA2K_VIDEO_VSA 1
#define S6E3HA2K_VIDEO_HBP 20
#define S6E3HA2K_VIDEO_HFP 20
#define S6E3HA2K_VIDEO_HSA 20
#define S6E3HA2K_HORIZONTAL 1440
#define S6E3HA2K_VERTICAL 2560
#ifdef FW_TEST /* This information is moved to DT */
#define CONFIG_FB_I80_COMMAND_MODE
struct decon_lcd s6e3ha2k_lcd_info = {
#ifdef CONFIG_FB_I80_COMMAND_MODE
.mode = DECON_MIPI_COMMAND_MODE,
.vfp = S6E3HA2K_CMD_VFP,
.vbp = S6E3HA2K_CMD_VBP,
.hfp = S6E3HA2K_CMD_HFP,
.hbp = S6E3HA2K_CMD_HBP,
.vsa = S6E3HA2K_CMD_VSA,
.hsa = S6E3HA2K_CMD_HSA,
#else
.mode = DECON_VIDEO_MODE,
.vfp = S6E3HA2K_VIDEO_VFP,
.vbp = S6E3HA2K_VIDEO_VBP,
.hfp = S6E3HA2K_VIDEO_HFP,
.hbp = S6E3HA2K_VIDEO_HBP,
.vsa = S6E3HA2K_VIDEO_VSA,
.hsa = S6E3HA2K_VIDEO_HSA,
#endif
.xres = S6E3HA2K_HORIZONTAL,
.yres = S6E3HA2K_VERTICAL,
/* Maybe, width and height will be removed */
.width = 70,
.height = 121,
/* Mhz */
.hs_clk = 1100,
.esc_clk = 20,
.fps = 60,
.mic_enabled = 1,
.mic_ver = MIC_VER_1_2,
};
#endif
/*
* 3HA2K lcd init sequence
*
* Parameters
* - mic_enabled : if mic is enabled, MIC_ENABLE command must be sent
* - mode : LCD init sequence depends on command or video mode
*/
void lcd_init(int id, struct decon_lcd *lcd)
{
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TEST_KEY_ON_F0,
ARRAY_SIZE(SEQ_TEST_KEY_ON_F0)) < 0)
dsim_err("fail to write KEY_ON init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_REG_F2,
ARRAY_SIZE(SEQ_REG_F2)) < 0)
dsim_err("fail to write F2 init command.\n");
if (lcd->mic_enabled)
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_REG_F9,
ARRAY_SIZE(SEQ_REG_F9)) < 0)
dsim_err("fail to write F9 init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, (unsigned long)SEQ_SLEEP_OUT[0], 0) < 0)
dsim_err("fail to write SLEEP_OUT init command.\n");
msleep(10);
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TEST_KEY_ON_F0,
ARRAY_SIZE(SEQ_TEST_KEY_ON_F0)) < 0)
dsim_err("fail to write KEY_ON init command.\n");
/* TE rising time change : 10 line earlier */
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TE_START_SETTING,
ARRAY_SIZE(SEQ_TE_START_SETTING)) < 0)
dsim_err("fail to write TE_START_SETTING command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_REG_F2,
ARRAY_SIZE(SEQ_REG_F2)) < 0)
dsim_err("fail to write F2 init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, SEQ_TE_ON[0], 0) < 0)
dsim_err("fail to write TE_on init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TOUCH_HSYNC,
ARRAY_SIZE(SEQ_TOUCH_HSYNC)) < 0)
dsim_err("fail to write TOUCH_HSYNC init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_PENTILE_CONTROL,
ARRAY_SIZE(SEQ_PENTILE_CONTROL)) < 0)
dsim_err("fail to write PENTILE_CONTROL init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_COLUMN_ADDRESS,
ARRAY_SIZE(SEQ_COLUMN_ADDRESS)) < 0)
dsim_err("fail to write COLUMN_ADDRESS init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_GAMMA_CONDITION_SET,
ARRAY_SIZE(SEQ_GAMMA_CONDITION_SET)) < 0)
dsim_err("fail to write GAMMA_CONDITION_SET init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_AID_SET,
ARRAY_SIZE(SEQ_AID_SET)) < 0)
dsim_err("fail to write AID_SET init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_ELVSS_SET,
ARRAY_SIZE(SEQ_ELVSS_SET)) < 0)
dsim_err("fail to write ELVSS_SET init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_GAMMA_UPDATE,
ARRAY_SIZE(SEQ_GAMMA_UPDATE)) < 0)
dsim_err("fail to write GAMMA_UPDATE init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_ACL_OFF,
ARRAY_SIZE(SEQ_ACL_OFF)) < 0)
dsim_err("fail to write ACL_OFF init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_ACL_OPR,
ARRAY_SIZE(SEQ_ACL_OPR)) < 0)
dsim_err("fail to write ACL_OPR init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_HBM_OFF,
ARRAY_SIZE(SEQ_HBM_OFF)) < 0)
dsim_err("fail to write HBM_OFF init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TSET_GLOBAL,
ARRAY_SIZE(SEQ_TSET_GLOBAL)) < 0)
dsim_err("fail to write TSET_GLOBAL init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TSET,
ARRAY_SIZE(SEQ_TSET)) < 0)
dsim_err("fail to write TSET init command.\n");
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TEST_KEY_OFF_F0,
ARRAY_SIZE(SEQ_TEST_KEY_OFF_F0)) < 0)
dsim_err("fail to write KEY_OFF init command.\n");
/* Added 120ms delay before SEQ_DISPLAY_ON */
msleep(120);
}
void lcd_enable(int id)
{
if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, (unsigned long)SEQ_DISPLAY_ON[0], 0) < 0)
dsim_err("fail to write DISPLAY_ON command.\n");
}
void lcd_disable(int id)
{
/* This function needs to implement */
}
/*
* Set gamma values
*
* Parameter
* - backlightlevel : It is from 0 to 26.
*/
int lcd_gamma_ctrl(int id, u32 backlightlevel)
{
/* This will be implemented
int ret;
ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (u32)gamma22_table[backlightlevel],
GAMMA_PARAM_SIZE);
if (ret) {
dsim_err("fail to write gamma value.\n");
return ret;
}
*/
return 0;
}
int lcd_gamma_update(int id)
{
/* This will be implemented
int ret;
ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (u32)SEQ_GAMMA_UPDATE,
ARRAY_SIZE(SEQ_GAMMA_UPDATE));
if (ret) {
dsim_err("fail to update gamma value.\n");
return ret;
}
*/
return 0;
}
int dsim_write_by_panel(int id, const u8 *cmd, u32 cmdSize)
{
int ret;
if (cmdSize == 1)
ret = dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, cmd[0], 0);
else if (cmdSize == 2)
ret = dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd[0], cmd[1]);
else
ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)cmd, cmdSize);
return ret;
}
int dsim_read_from_panel(int id, u8 addr, u32 size, u8 *buf)
{
int ret;
ret = dsim_rd_data(id, MIPI_DSI_DCS_READ, (u32)addr, size, buf);
return ret;
}
static int s6e3ha2_wqhd_dump(int dsim)
{
int ret = 0;
unsigned char id[S6E3HA2_RD_LEN];
unsigned char rddpm[S6E3HA2_RD_LEN + 1];
unsigned char rddsm[S6E3HA2_RD_LEN + 1];
unsigned char err_buf[S6E3HA2_RD_LEN + 1];
dsim_info(" + %s\n", __func__);
ret = dsim_write_by_panel(dsim, SEQ_TEST_KEY_ON_F0, ARRAY_SIZE(SEQ_TEST_KEY_ON_F0));
if (ret < 0) {
dsim_err("%s : fail to write CMD : SEQ_TEST_KEY_ON_F0\n", __func__);
}
ret = dsim_write_by_panel(dsim, SEQ_TEST_KEY_ON_FC, ARRAY_SIZE(SEQ_TEST_KEY_ON_FC));
if (ret < 0) {
dsim_err("%s : fail to write CMD : SEQ_TEST_KEY_ON_FC\n", __func__);
}
ret = dsim_read_from_panel(dsim, 0xEA, S6E3HA2_RD_LEN, err_buf);
if (ret != S6E3HA2_RD_LEN) {
dsim_err("%s : can't read Panel's EA Reg\n",__func__);
goto dump_exit;
}
dsim_dbg("=== Panel's 0xEA Reg Value ===\n");
dsim_dbg("* 0xEA : buf[0] = %x\n", err_buf[0]);
dsim_dbg("* 0xEA : buf[1] = %x\n", err_buf[1]);
ret = dsim_read_from_panel(dsim, S6E3HA2_RDDPM_ADDR, S6E3HA2_RD_LEN, rddpm);
if (ret != S6E3HA2_RD_LEN) {
dsim_err("%s : can't read RDDPM Reg\n",__func__);
goto dump_exit;
}
dsim_info("=== Panel's RDDPM Reg Value : %x ===\n", rddpm[0]);
if (rddpm[0] & 0x80)
dsim_info("* Booster Voltage Status : ON\n");
else
dsim_info("* Booster Voltage Status : OFF\n");
if (rddpm[0] & 0x40)
dsim_info("* Idle Mode : On\n");
else
dsim_info("* Idle Mode : OFF\n");
if (rddpm[0] & 0x20)
dsim_info("* Partial Mode : On\n");
else
dsim_info("* Partial Mode : OFF\n");
if (rddpm[0] & 0x10)
dsim_info("* Sleep OUT and Working Ok\n");
else
dsim_info("* Sleep IN\n");
if (rddpm[0] & 0x08)
dsim_info("* Normal Mode On and Working Ok\n");
else
dsim_info("* Sleep IN\n");
if (rddpm[0] & 0x04)
dsim_info("* Display On and Working Ok\n");
else
dsim_info("* Display Off\n");
ret = dsim_read_from_panel(dsim, S6E3HA2_RDDSM_ADDR, S6E3HA2_RD_LEN, rddsm);
if (ret != S6E3HA2_RD_LEN) {
dsim_err("%s : can't read RDDSM Reg\n",__func__);
goto dump_exit;
}
dsim_info("=== Panel's RDDSM Reg Value : %x ===\n", rddsm[0]);
if (rddsm[0] & 0x80)
dsim_info("* TE On\n");
else
dsim_info("* TE OFF\n");
if (rddsm[0] & 0x02)
dsim_info("* S_DSI_ERR : Found\n");
if (rddsm[0] & 0x01)
dsim_info("* DSI_ERR : Found\n");
ret = dsim_read_from_panel(dsim, S6E3HA2_ID_REG, S6E3HA2_RD_LEN, id);
if (ret != S6E3HA2_RD_LEN) {
dsim_err("%s : can't read panel id\n",__func__);
goto dump_exit;
}
ret = dsim_write_by_panel(dsim, SEQ_TEST_KEY_OFF_FC, ARRAY_SIZE(SEQ_TEST_KEY_OFF_FC));
if (ret < 0) {
dsim_err("%s : fail to write CMD : SEQ_TEST_KEY_OFF_FC\n", __func__);
}
ret = dsim_write_by_panel(dsim, SEQ_TEST_KEY_OFF_F0, ARRAY_SIZE(SEQ_TEST_KEY_OFF_F0));
if (ret < 0) {
dsim_err("%s : fail to write CMD : SEQ_TEST_KEY_OFF_F0\n", __func__);
}
dump_exit:
dsim_info(" - %s\n", __func__);
return ret;
}
int lcd_dump(int id)
{
s6e3ha2_wqhd_dump(id);
return 0;
}

View file

@ -0,0 +1,213 @@
/* drivers/video/exynos/decon/panels/s6e3ha2k_mipi_lcd.c
*
* Samsung SoC MIPI LCD driver.
*
* Copyright (c) 2014 Samsung Electronics
*
* Haowei Li, <haowei.li@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/delay.h>
#include <linux/gpio.h>
#include <video/mipi_display.h>
#include <linux/platform_device.h>
#include "../dsim.h"
#include "lcd_ctrl.h"
#include "decon_lcd.h"
#define MAX_BRIGHTNESS 255
#define MIN_BRIGHTNESS 0
#define DEFAULT_BRIGHTNESS 0
static struct dsim_device *dsim_base;
static struct backlight_device *bd;
static int s6e3ha2k_get_brightness(struct backlight_device *bd)
{
return bd->props.brightness;
}
static int get_backlight_level(int brightness)
{
int backlightlevel;
switch (brightness) {
case 0:
backlightlevel = 0;
break;
case 1 ... 29:
backlightlevel = 0;
break;
case 30 ... 34:
backlightlevel = 1;
break;
case 35 ... 39:
backlightlevel = 2;
break;
case 40 ... 44:
backlightlevel = 3;
break;
case 45 ... 49:
backlightlevel = 4;
break;
case 50 ... 54:
backlightlevel = 5;
break;
case 55 ... 64:
backlightlevel = 6;
break;
case 65 ... 74:
backlightlevel = 7;
break;
case 75 ... 83:
backlightlevel = 8;
break;
case 84 ... 93:
backlightlevel = 9;
break;
case 94 ... 103:
backlightlevel = 10;
break;
case 104 ... 113:
backlightlevel = 11;
break;
case 114 ... 122:
backlightlevel = 12;
break;
case 123 ... 132:
backlightlevel = 13;
break;
case 133 ... 142:
backlightlevel = 14;
break;
case 143 ... 152:
backlightlevel = 15;
break;
case 153 ... 162:
backlightlevel = 16;
break;
case 163 ... 171:
backlightlevel = 17;
break;
case 172 ... 181:
backlightlevel = 18;
break;
case 182 ... 191:
backlightlevel = 19;
break;
case 192 ... 201:
backlightlevel = 20;
break;
case 202 ... 210:
backlightlevel = 21;
break;
case 211 ... 220:
backlightlevel = 22;
break;
case 221 ... 230:
backlightlevel = 23;
break;
case 231 ... 240:
backlightlevel = 24;
break;
case 241 ... 250:
backlightlevel = 25;
break;
case 251 ... 255:
backlightlevel = 26;
break;
default:
backlightlevel = 12;
break;
}
return backlightlevel;
}
static int update_brightness(int brightness)
{
int backlightlevel;
backlightlevel = get_backlight_level(brightness);
/* Need to implement
if (s5p_mipi_dsi_wr_data(dsim_base, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int)gamma22_table[backlightlevel],
GAMMA_PARAM_SIZE) == -1)
printk(KERN_ERR "fail to write gamma value.\n");
if (s5p_mipi_dsi_wr_data(dsim_base, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
(unsigned int)0xF7, (unsigned int)0x03) == -1)
printk(KERN_ERR "fail to update gamma value.\n");
*/
return 0;
}
static int s6e3ha2k_set_brightness(struct backlight_device *bd)
{
int brightness = bd->props.brightness;
if (brightness < MIN_BRIGHTNESS || brightness > MAX_BRIGHTNESS) {
pr_err("Brightness should be in the range of 0 ~ 255\n");
return -EINVAL;
}
update_brightness(brightness);
return 0;
}
static const struct backlight_ops s6e3ha2k_backlight_ops = {
.get_brightness = s6e3ha2k_get_brightness,
.update_status = s6e3ha2k_set_brightness,
};
static int s6e3ha2k_probe(struct dsim_device *dsim)
{
dsim_base = dsim;
bd = backlight_device_register("pwm-backlight.0", NULL,
NULL, &s6e3ha2k_backlight_ops, NULL);
if (IS_ERR(bd))
pr_err("failed to register backlight device!\n");
bd->props.max_brightness = MAX_BRIGHTNESS;
bd->props.brightness = DEFAULT_BRIGHTNESS;
return 0;
}
static int s6e3ha2k_displayon(struct dsim_device *dsim)
{
lcd_init(dsim->id, &dsim->lcd_info);
lcd_enable(dsim->id);
return 1;
}
static int s6e3ha2k_suspend(struct dsim_device *dsim)
{
return 0;
}
static int s6e3ha2k_resume(struct dsim_device *dsim)
{
return 0;
}
static int s6e3ha2k_dump(struct dsim_device *dsim)
{
lcd_dump(dsim->id);
return 0;
}
struct mipi_dsim_lcd_driver s6e3ha2k_mipi_lcd_driver = {
.probe = s6e3ha2k_probe,
.displayon = s6e3ha2k_displayon,
.suspend = s6e3ha2k_suspend,
.resume = s6e3ha2k_resume,
.dump = s6e3ha2k_dump,
};

View file

@ -0,0 +1,132 @@
/* linux/drivers/video/decon_display/s6e3fa0_param.h
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
*
* Jiun Yu <jiun.yu@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __S6E3HA0K_PARAM_H__
#define __S6E3HA0K_PARAM_H__
#define S6E3HA2_ID_REG 0x04
#define S6E3HA2_RD_LEN 3
#define S6E3HA2_RDDPM_ADDR 0x0A
#define S6E3HA2_RDDSM_ADDR 0x0E
/* MIPI commands list */
static const unsigned char SEQ_TEST_KEY_ON_F0[] = {
0xF0,
0x5A, 0x5A
};
static const unsigned char SEQ_TEST_KEY_ON_FC[] = {
0xFC,
0x5A, 0x5A
};
static const unsigned char SEQ_TEST_KEY_OFF_FC[] = {
0xFC,
0xA5, 0xA5
};
static const unsigned char SEQ_SLEEP_OUT[] = {
0x11,
};
static const unsigned char SEQ_REG_F2[] = {
0xF2,
0x67, 0x41, 0xC3, 0x06, 0x0A
};
static const unsigned char SEQ_TE_START_SETTING[] = {
0xB9,
0x10, 0x09, 0xFF, 0x00, 0x09
};
static const unsigned char SEQ_REG_F9[] = {
0xF9,
0x29
};
static const unsigned char SEQ_TOUCH_HSYNC[] = {
0xBD,
0x30, 0x22, 0x02, 0x16, 0x02, 0x16
};
static const unsigned char SEQ_PENTILE_CONTROL[] = {
0xC0,
0x30, 0x00, 0xD8, 0xD8
};
static const unsigned char SEQ_COLUMN_ADDRESS[] = {
0x2A,
0x00, 0x00, 0x05, 0x9F
};
static const unsigned char SEQ_GAMMA_CONDITION_SET[] = {
0xCA,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x00, 0x00
};
static const unsigned char SEQ_AID_SET[] = {
0xB2,
0x03, 0x10
};
static const unsigned char SEQ_ELVSS_SET[] = {
0xB6,
0x9C, 0x0A
};
static const unsigned char SEQ_GAMMA_UPDATE[] = {
0xF7,
0x03
};
static const unsigned char SEQ_ACL_OFF[] = {
0x55,
0x00
};
static const unsigned char SEQ_ACL_OPR[] = {
0xB5,
0x40
};
static const unsigned char SEQ_HBM_OFF[] = {
0xB4,
0x04
};
static const unsigned char SEQ_TSET_GLOBAL[] = {
0xB0,
0x07
};
static const unsigned char SEQ_TSET[] = {
0xB8,
0x19
};
static const unsigned char SEQ_TEST_KEY_OFF_F0[] = {
0xF0,
0xA5, 0xA5
};
static const unsigned char SEQ_DISPLAY_ON[] = {
0x29,
};
static const unsigned char SEQ_TE_ON[] = {
0x35,
0x00
};
#endif /* __S6E3HA0K_PARAM_H__ */

View file

@ -0,0 +1,443 @@
/*
* drivers/video/exynos_8890/decon/regs-decon.h
*
* Register definition file for Samsung DECON driver
*
* Copyright (c) 2014 Samsung Electronics
* Sewoon Park <seuni.park@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _REGS_DISP_SS_H
#define _REGS_DISP_SS_H
#define DISP_CFG 0x0000
#define DISP_CFG_DP_PATH_CFG0_EN (0x1 << 20)
#define DISP_CFG_DSIM_PATH_CFG1_DISP_IF_MASK(_v) (0x3 << (9 + (_v) * 4))
#define DISP_CFG_DSIM_PATH_CFG1_DISP_IF0(_v) (0x0 << (9 + (_v) * 4))
#define DISP_CFG_DSIM_PATH_CFG1_DISP_IF1(_v) (0x1 << (9 + (_v) * 4))
#define DISP_CFG_DSIM_PATH_CFG1_DISP_IF2(_v) (0x2 << (9 + (_v) * 4))
#define DISP_CFG_DSIM_PATH_CFG0_EN(_v) (0x1 << (8 + (_v) * 4))
#define DISP_CFG_DSIM_PATH_CFG0_MASK(_v) (0x1 << (8 + (_v) * 4))
#define DISP_CFG_SYNC_MODE1_TE(_v) ((_v) << 2)
#define DISP_CFG_SYNC_MODE1_MASK (0x3 << 2)
#define DISP_CFG_SYNC_MODE0_TE(_v) ((_v) << 0)
#define DISP_CFG_SYNC_MODE0_MASK (0x3 << 0)
#define DISP_CFG_SYNC_MODE1_TE_F (0x0 << 2)
#define DISP_CFG_SYNC_MODE1_TE_S (0x1 << 2)
#define DISP_CFG_SYNC_MODE1_TE_T (0x2 << 2)
#define DISP_CFG_SYNC_MODE1_MASK (0x3 << 2)
#define DISP_CFG_SYNC_MODE0_TE_F (0x0 << 0)
#define DISP_CFG_SYNC_MODE0_TE_S (0x1 << 0)
#define DISP_CFG_SYNC_MODE0_TE_T (0x2 << 0)
#define DISP_CFG_SYNC_MODE0_MASK (0x3 << 0)
#endif /* _REGS_DISP_SS_H */
#ifndef _REGS_DECON_H
#define _REGS_DECON_H
/*
* IP start_offset end_offset
*=================================================
* DECON_F 0x0000 0x007f
* DECON_F/DISPIF0,1 0x0080 0x00F4
* DECON_F 0x00F8 0x0FFF
*-------------------------------------------------
* MIC 0x1000 0x1FFF
*-------------------------------------------------
* DSC_ENC0 0x2000 0x2FFF
* DSC_ENC1 0x3000 0x3FFF
*-------------------------------------------------
* DECON_S/DISPIF2 0x5000 0x5FFF
* DECON_T/DISPIF3 0x6000 0x6FFF
*-------------------------------------------------
*-------------------------------------------------
* SHD_DECON_F 0x7000 0x7FFF
*-------------------------------------------------
* SHD_MIC 0x8000 0x8FFF
*-------------------------------------------------
* SHD_DSC_ENC0 0x9000 0x9FFF
* SHD_DSC_ENC1 0xA000 0xAFFF
*-------------------------------------------------
* SHD_DISPIF2 0xB000 0xBFFF
* SHD_DISPIF3 0xC000 0xCFFF
*-------------------------------------------------
* mDNIe 0xD000 0xDFFF
*-------------------------------------------------
* DPU 0xE000 0xFFFF
*/
/*
* DECON_F registers
* ->
* updated by SHADOW_REG_UPDATE_REQ[31] : SHADOW_REG_UPDATE_REQ
* (0x0000~0x011C, 0x0230~0x209C, Dither/MIC/DSC)
*/
#define GLOBAL_CONTROL 0x0000
#define GLOBAL_CONTROL_SRESET (1 << 28)
#define GLOBAL_CONTROL_AUTOMATIC_MAPCOLOR_ENTER_EN_F (1 << 12)
#define GLOBAL_CONTROL_OPERATION_MODE_F (1 << 8)
#define GLOBAL_CONTROL_OPERATION_MODE_RGBIF_F (0 << 8)
#define GLOBAL_CONTROL_OPERATION_MODE_I80IF_F (1 << 8)
#define GLOBAL_CONTROL_URGENT_STATUS (1 << 6)
#define GLOBAL_CONTROL_IDLE_STATUS (1 << 5)
#define GLOBAL_CONTROL_RUN_STATUS (1 << 4)
#define GLOBAL_CONTROL_DECON_EN (1 << 1)
#define GLOBAL_CONTROL_DECON_EN_F (1 << 0)
#define AUTOMATIC_MAPCOLOR_PERIOD_CONTROL 0x0004
#define AUTOMATIC_MAPCOLOR_PERIOD_F(_v) ((_v) << 0)
#define RESOURCE_OCCUPANCY_INFO_0 0x0010
#define RESOURCE_OCCUPANCY_INFO_1 0x0014
#define RESOURCE_SEL_0 0x0018/* DECon_F only */
#define RESOURCE_SEL_1 0x001C/* DECon_F only */
#define RESOURCE_CONFLICTION_INDUCER 0x0020
#define SRAM_SHARE_ENABLE 0x0030/* DECon_F only */
#define SRAM_SHARE_ENABLE_DSC_F (1 << 4)
#define SRAM_SHARE_ENABLE_F (1 << 0)
#define INTERRUPT_ENABLE 0x0040
#define INTERRUPT_DPU1_INT_EN (1 << 29)
#define INTERRUPT_DPU0_INT_EN (1 << 28)
#define INTERRUPT_DISPIF_VSTATUS_INT_EN (1 << 24)
#define INTERRUPT_DISPIF_VSTATUS_VBP (0 << 20)
#define INTERRUPT_DISPIF_VSTATUS_VSA (1 << 20)
#define INTERRUPT_DISPIF_VSTATUS_VACTIVE (2 << 20)
#define INTERRUPT_DISPIF_VSTATUS_VFP (3 << 20)
#define INTERRUPT_RESOURCE_CONFLICT_INT_EN (1 << 18)
#define INTERRUPT_EVEN_FRAME_START_INT_EN (1 << 17)
#define INTERRUPT_ODD_FRAME_START_INT_EN (1 << 16)
#define INTERRUPT_FRAME_DONE_INT_EN (1 << 12)
#define INTERRUPT_FIFO_LEVEL_INT_EN (1 << 8)
#define INTERRUPT_INT_EN (1 << 0)
#define UNDER_RUN_CYCLE_THRESHOLD 0x0044
#define INTERRUPT_PENDING 0x0048
#define SHADOW_REG_UPDATE_REQ 0x0060
#define SHADOW_REG_UPDATE_REQ_GLOBAL (1 << 31)
#define SHADOW_REG_UPDATE_REQ_DPU (1 << 28)
#define SHADOW_REG_UPDATE_REQ_MDNIE (1 << 24)
#define SHADOW_REG_UPDATE_REQ_WIN(_win) (1 << (_win))
#define SHADOW_REG_UPDATE_REQ_FOR_DECON_F (0xff)
#define SHADOW_REG_UPDATE_REQ_FOR_DECON_T (0xf)
#define HW_SW_TRIG_CONTROL 0x0070
#define HW_SW_TRIG_CONTROL_TRIG_AUTO_MASK_TRIG (1 << 12)
/* 1 : s/w trigger */
#define HW_SW_TRIG_CONTROL_SW_TRIG (1 << 8)
/* 0 : unmask, 1 : mask */
#define HW_SW_TRIG_CONTROL_HW_TRIG_MASK (1 << 5)
/* 0 : s/w trigger, 1 : h/w trigger */
#define HW_SW_TRIG_CONTROL_HW_TRIG_EN (1 << 4)
#define DISPIF0_DISPIF1_CONTROL 0x0080/* DECon_F only */
#define DISPIF0_DISPIF1_CONTROL_FREE_RUN_EN (1 << 4)
#define DISPIF0_DISPIF1_CONTROL_UNDERRUN_SCHEME_F(_v) ((_v) << 12)
#define DISPIF0_DISPIF1_CONTROL_UNDERRUN_SCHEME_MASK (0x3 << 12)
#define DISPIF0_DISPIF1_CONTROL_OUT_RGB_ORDER_F(_v) ((_v) << 8)
#define DISPIF0_DISPIF1_CONTROL_OUT_RGB_ORDER_MASK (0x7 << 8)
#define DISPIF0_MAPCOLOR 0x0084/* DECon_F only */
#define DISPIF1_MAPCOLOR 0x0088/* DECon_F only */
#define DISPIF_LINE_COUNT 0x008C/* DECon_F only */
#define DISPIF_LINE_COUNT_DISPIF1_SHIFT 16
#define DISPIF_LINE_COUNT_DISPIF1_MASK (0xffff << 16)
#define DISPIF_LINE_COUNT_DISPIF0_SHIFT 0
#define DISPIF_LINE_COUNT_DISPIF0_MASK (0xffff << 0)
#define DISPIF0_TIMING_CONTROL_0 0x0090/* DECon_F only */
#define DISPIF_TIMING_VBPD_F(_v) ((_v) << 16)
#define DISPIF_TIMING_VFPD_F(_v) ((_v) << 0)
#define DISPIF0_TIMING_CONTROL_1 0x0094/* DECon_F only */
#define DISPIF_TIMING_VSPD_F(_v) ((_v) << 0)
#define DISPIF0_TIMING_CONTROL_2 0x0098/* DECon_F only */
#define DISPIF_TIMING_HBPD_F(_v) ((_v) << 16)
#define DISPIF_TIMING_HFPD_F(_v) ((_v) << 0)
#define DISPIF0_TIMING_CONTROL_3 0x009C/* DECon_F only */
#define DISPIF_TIMING_HSPD_F(_v) ((_v) << 0)
#define DISPIF0_SIZE_CONTROL_0 0x00A0/* DECon_F only */
#define DISPIF_HEIGHT_F(_v) ((_v) << 16)
#define DISPIF_HEIGHT_MASK (0x3fff << 16)
#define DISPIF_HEIGHT_GET(_v) (((_v) >> 16) & 0x3fff)
#define DISPIF_WIDTH_F(_v) ((_v) << 0)
#define DISPIF_WIDTH_MASK (0x3fff << 0)
#define DISPIF_WIDTH_GET(_v) (((_v) >> 0) & 0x3fff)
/* All of DECON */
/* DISP INTERFACE OFFSET : IF0,1 = 0x0, IF2 = 0x5000, IF3 = 0x6000 */
#define IF_OFFSET(_x) ((((_x) < 2) ? 0 : 0x1000) * ((_x) + 3))
/* For TIMING VALUE : IF0,2,3 = 0x0, IF1 = 0x30 */
#define IF1_OFFSET(_x) (((_x) == 1) ? 0x30 : 0x0)
#define DISPIF_SIZE_CONTROL_0(_if_idx) \
(0x00A0 + IF_OFFSET(_if_idx) + IF1_OFFSET(_if_idx))
#define DISPIF_WIDTH_START_POS (0)
#define DISPIF_HEIGHT_START_POS (16)
#define DISPIF0_SIZE_CONTROL_1 0x00A4/* DECon_F only */
#define DISPIF0_URGENT_CONTROL 0x00A8/* DECon_F only */
#define DISPIF1_TIMING_CONTROL_0 0x00C0/* DECon_F only */
#define DISPIF1_TIMING_CONTROL_1 0x00C4/* DECon_F only */
#define DISPIF1_TIMING_CONTROL_2 0x00C8/* DECon_F only */
#define DISPIF1_TIMING_CONTROL_3 0x00CC/* DECon_F only */
#define DISPIF1_SIZE_CONTROL_0 0x00D0/* DECon_F only */
#define DISPIF1_SIZE_CONTROL_1 0x00D4/* DECon_F only */
#define DISPIF1_URGENT_CONTROL 0x00D8/* DECon_F only */
#define CLOCK_CONTROL_0 0x00F0
/* [16] 0: QACTIVE is dynamically changed by DECON h/w,
* 1: QACTIVE is stuck to 1'b1
*/
#define CLOCK_CONTROL_0_F_MASK (0xF31000FF)
#define CLOCK_CONTROL_0_S_MASK (0x1300FF0F)
#define CLOCK_CONTROL_0_T_MASK (0x1300FF0F)
#define VCLK_DIVIDER_CONTROL 0x00F4/* DECon_F only */
#define ECLK_DIVIDER_CONTROL 0x00F8
#define BLENDER_BG_IMAGE_SIZE_0 0x0110
#define BLENDER_BG_HEIGHT_F(_v) ((_v) << 16)
#define BLENDER_BG_HEIGHT_MASK (0x3fff << 16)
#define BLENDER_BG_HEIGHT_GET(_v) (((_v) >> 16) & 0x3fff)
#define BLENDER_BG_WIDTH_F(_v) ((_v) << 0)
#define BLENDER_BG_WIDTH_MASK (0x3fff << 0)
#define BLENDER_BG_WIDTH_GET(_v) (((_v) >> 0) & 0x3fff)
#define BLENDER_BG_IMAGE_SIZE_1 0x0114
#define BLENDER_BG_IMAGE_COLOR 0x0118
#define LRMERGER_MODE_CONTROL 0x011C
#define WIN_CONTROL(_win) (0x0130 + ((_win) * 0x20))
#define WIN_CONTROL_ALPHA1_F(_v) (((_v) & 0xFF) << 24)
#define WIN_CONTROL_ALPHA1_MASK (0xFF << 24)
#define WIN_CONTROL_ALPHA0_F(_v) (((_v) & 0xFF) << 16)
#define WIN_CONTROL_ALPHA0_MASK (0xFF << 16)
#define WIN_CONTROL_CHMAP_F(_v) (((_v) & 0x7) << 12)
#define WIN_CONTROL_CHMAP_MASK (0x7 << 12)
#define WIN_CONTROL_FUNC_F(_v) (((_v) & 0xF) << 8)
#define WIN_CONTROL_FUNC_MASK (0xF << 8)
#define WIN_CONTROL_ALPHA_MUL_F (1 << 6)
#define WIN_CONTROL_ALPHA_SEL_F(_v) (((_v) & 0x7) << 4)
#define WIN_CONTROL_ALPHA_SEL_MASK (0x7 << 4)
#define WIN_CONTROL_MAPCOLOR_EN_F (1 << 1)
#define WIN_CONTROL_MAPCOLOR_EN_MASK (1 << 1)
#define WIN_CONTROL_EN_F (1 << 0)
#define WIN_START_POSITION(_win) (0x0134 + ((_win) * 0x20))
#define WIN_STRPTR_Y_F(_v) (((_v) & 0x1FFF) << 16)
#define WIN_STRPTR_X_F(_v) (((_v) & 0x1FFF) << 0)
#define WIN_END_POSITION(_win) (0x0138 + ((_win) * 0x20))
#define WIN_ENDPTR_Y_F(_v) (((_v) & 0x1FFF) << 16)
#define WIN_ENDPTR_X_F(_v) (((_v) & 0x1FFF) << 0)
#define WIN_COLORMAP(_win) (0x013C + ((_win) * 0x20))
#define WIN_COLORMAP_MAPCOLOR_F(_v) ((_v) << 0)
#define WIN_COLORMAP_MAPCOLOR_MASK (0xffffff << 0)
#define WIN_START_TIME_CONTROL(_win) (0x0140 + ((_win) * 0x20))
#define WIN_PIXEL_COUNT(_win) (0x0144 + ((_win) * 0x20))
#define DATA_PATH_CONTROL 0x0230
#define DATA_PATH_CONTROL_ENHANCE_SHIFT 8
#define DATA_PATH_CONTROL_ENHANCE_MASK (0x7 << 8)
#define DATA_PATH_CONTROL_ENHANCE(_v) ((_v) << 8)
#define DATA_PATH_CONTROL_ENHANCE_GET(_v) (((_v) >> 8) & 0x7)
#define DATA_PATH_CONTROL_PATH_SHIFT 0
#define DATA_PATH_CONTROL_PATH_MASK (0xFF << 0)
#define DATA_PATH_CONTROL_PATH(_v) ((_v) << 0)
#define DATA_PATH_CONTROL_PATH_GET(_v) (((_v) >> 0) & 0xFF)
#define SPLITTER_CONTROL_0 0x0240/* DECon_F only */
#define SPLITTER_SIZE_CONTROL_0 0x0244/* DECon_F only */
#define SPLITTER_HEIGHT_F(_v) ((_v) << 16)
#define SPLITTER_HEIGHT_MASK (0x3fff << 16)
#define SPLITTER_WIDTH_F(_v) ((_v) << 0)
#define SPLITTER_WIDTH_MASK (0x3fff << 0)
#define SPLITTER_SIZE_CONTROL_1 0x0248/* DECon_F only */
#define FRAME_FIFO_CONTROL 0x024C
#define FRAME_FIFO_0_SIZE_CONTROL_0 0x0250
#define FRAME_FIFO_HEIGHT_F(_v) ((_v) << 16)
#define FRAME_FIFO_HEIGHT_MASK (0x3fff << 16)
#define FRAME_FIFO_WIDTH_F(_v) ((_v) << 0)
#define FRAME_FIFO_WIDTH_MASK (0x3fff << 0)
#define FRAME_FIFO_0_SIZE_CONTROL_1 0x0254
#define FRAME_FIFO_1_SIZE_CONTROL_0 0x0258/* DECon_F only */
#define FRAME_FIFO_1_SIZE_CONTROL_1 0x025C/* DECon_F only */
#define FRAME_FIFO_INFO_0 0x0260
#define FRAME_FIFO_INFO_1 0x0264
#define FRAME_FIFO_INFO_2 0x0268
#define FRAME_FIFO_INFO_3 0x026C
#define SRAM_SHARE_COMP_INFO 0x0270/* DECon_F only */
#define SRAM_SHARE_ENH_INFO 0x0274/* DECon_F only */
#define CRC_DATA_0 0x0280
#define CRC_DATA_2 0x0284/* DECon_F only */
#define CRC_CONTROL 0x0288
#define FRAME_ID 0x02A0
#define DEBUG_CLOCK_OUT_SEL 0x02AC
#define DITHER_CONTROL 0x0300/* DECon_F only */
/*
* MIC registers
* ->
* 0x1004 ~
* updated by SHADOW_REG_UPDATE_REQ[31] : SHADOW_REG_UPDATE_REQ
*/
#define MIC_CONTROL 0x1004
#define MIC_DUMMY_F(_v) ((_v) << 20)
#define MIC_DUMMY_MASK (0x1ff << 20)
/* 0 : single slice, 1: dual slice */
#define MIC_SLICE_NUM_F(_v) ((_v) << 8)
#define MIC_SLICE_NUM_MASK (0x3 << 8)
/* 0 : {PIX0, PIX1}, 1 : {PIX1, PIX0} */
#define MIC_PIXEL_ORDER_F(_v) ((_v) << 4)
#define MIC_PIXEL_ORDER_MASK (1 << 4)
/* 0 : 1/2, 1: 1/3 */
#define MIC_PARA_CR_CTRL_F(_v) ((_v) << 1)
#define MIC_PARA_CR_CTRL_MASK (1 << 1)
#define MIC_PARA_CR_CTRL_SHIFT 1
#define MIC_ENC_PARAM0 0x1008
#define MIC_ENC_PARAM1 0x100C
#define MIC_ENC_PARAM2 0x1010
#define MIC_ENC_PARAM3 0x1014
#define MIC_BG_COLOR 0x1018
#define MIC_SIZE_CONTROL 0x101C
#define MIC_WIDTH_C_F(_v) ((_v) << 0)
#define MIC_WIDTH_C_MASK (0x3fff << 0)
/*
* <-
* MIC registers
*/
/*
* DSC registers
* ->
* 0x2000 ~
* updated by SHADOW_REG_UPDATE_REQ[31] : SHADOW_REG_UPDATE_REQ
*
* @ regs-dsc.h
*
* <-
* DSC registers
*/
/*
* DISPIF2,3 registers
* ->
*/
#define DISPIF2_CONTROL 0x5080/* DECon_F only */
#define DISPIF2_CONTROL_FREE_RUN_EN (1 << 4)
#define DISPIF2_CONTROL_UNDERRUN_SCHEME_F(_v) ((_v) << 12)
#define DISPIF2_CONTROL_UNDERRUN_SCHEME_MASK (0x3 << 12)
#define DISPIF2_CONTROL_OUT_RGB_ORDER_F(_v) ((_v) << 8)
#define DISPIF2_CONTROL_OUT_RGB_ORDER_MASK (0x7 << 8)
#define DISPIF2_MAPCOLOR 0x5084/* DECon_F only */
#define DISPIF2_LINE_COUNT 0x508C
#define DISPIF2_LINE_COUNT_SHIFT 0
#define DISPIF2_LINE_COUNT_MASK (0xffff << 0)
#define DISPIF2_TIMING_CONTROL_0 0x5090/* DECon_F only */
#define DISPIF2_TIMING_CONTROL_1 0x5094/* DECon_F only */
#define DISPIF2_TIMING_CONTROL_2 0x5098/* DECon_F only */
#define DISPIF2_TIMING_CONTROL_3 0x509C/* DECon_F only */
#define DISPIF2_SIZE_CONTROL_0 0x50A0/* DECon_F only */
#define DISPIF2_SIZE_CONTROL_1 0x50A4/* DECon_F only */
#define VCLK2_DIVIDER_CONTROL 0x50F4/* DECon_F only */
#define DISPIF3_CONTROL 0x6080/* DECon_F only */
#define DISPIF3_CONTROL_FREE_RUN_EN (1 << 4)
#define DISPIF3_CONTROL_UNDERRUN_SCHEME_F(_v) ((_v) << 12)
#define DISPIF3_CONTROL_UNDERRUN_SCHEME_MASK (0x3 << 12)
#define DISPIF3_CONTROL_OUT_RGB_ORDER_F(_v) ((_v) << 8)
#define DISPIF3_CONTROL_OUT_RGB_ORDER_MASK (0x7 << 8)
#define DISPIF3_MAPCOLOR 0x6084/* DECon_F only */
#define DISPIF3_LINE_COUNT 0x608C/* DECon_F only */
#define DISPIF3_LINE_COUNT_SHIFT 0
#define DISPIF3_LINE_COUNT_MASK (0xffff << 0)
#define DISPIF3_TIMING_CONTROL_0 0x6090/* DECon_F only */
#define DISPIF3_TIMING_CONTROL_1 0x6094/* DECon_F only */
#define DISPIF3_TIMING_CONTROL_2 0x6098/* DECon_F only */
#define DISPIF3_TIMING_CONTROL_3 0x609C/* DECon_F only */
#define DISPIF3_SIZE_CONTROL_0 0x60A0/* DECon_F only */
#define DISPIF3_SIZE_CONTROL_1 0x60A4/* DECon_F only */
#define VCLK3_DIVIDER_CONTROL 0x60F4/* DECon_F only */
#define DIVIDER_DENOM_VALUE_OF_CLK_F(_v) ((_v) << 16)
#define DIVIDER_NUM_VALUE_OF_CLK_F(_v) ((_v) << 0)
/* <-
* DISPIF2,3 registers
*/
/*
* mDNIe registers
* ->
* 0xD000 ~
* updated by SHADOW_REG_UPDATE_REQ[24] : SHADOW_REG_UPDATE_REQ_mDNIe
*
* @ regs-mdnie.h
*
* <-
* mDNIe registers
*/
/*
* DPU registers
* ->
* 0xE000 ~
* updated by SHADOW_REG_UPDATE_REQ[28] : SHADOW_REG_UPDATE_REQ_DPU
*
* @ regs-dpu.h
*
* <-
* DPU registers
*/
#define SHADOW_OFFSET 0x7000
#endif /* _REGS_DECON_H */

View file

@ -0,0 +1,303 @@
/* regs-dsim.h
*
* Register definition file for Samsung MIPI-DSIM driver
*
* Copyright (c) 2015 Samsung Electronics
* Jiun Yu <jiun.yu@samsung.com>
* Seuni Park <seuni.park@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _REGS_DSIM_H
#define _REGS_DSIM_H
#define DSIM_LINK_STATUS (0x4)
#define DSIM_STATUS_PLL_STABLE (1 << 24)
#define DSIM_DPHY_STATUS (0x8)
#define DSIM_STATUS_STOP_STATE_DAT(_x) (((_x) & 0xf) << 0)
#define DSIM_STATUS_ULPS_DAT(_x) (((_x) & 0xf) << 4)
#define DSIM_STATUS_STOP_STATE_CLK (1 << 8)
#define DSIM_STATUS_ULPS_CLK (1 << 9)
#define DSIM_STATUS_TX_READY_HS_CLK (1 << 10)
#define DSIM_STATUS_ULPS_DATA_LANE_GET(x) (((x) >> 4) & 0xf)
#define DSIM_SWRST (0xc)
#define DSIM_SWRST_FUNCRST (1 << 16)
#define DSIM_DPHY_RST (1 << 8)
#define DSIM_SWRST_RESET (1 << 0)
#define DSIM_CLKCTRL (0x10)
#define DSIM_CLKCTRL_TX_REQUEST_HSCLK (1 << 20)
#define DSIM_CLKCTRL_BYTECLK_EN (1 << 17)
#define DSIM_CLKCTRL_ESCCLK_EN (1 << 16)
#define DSIM_CLKCTRL_LANE_ESCCLK_EN_MASK (0x1f << 8)
#define DSIM_CLKCTRL_LANE_ESCCLK_EN(_x) ((_x) << 8)
#define DSIM_CLKCTRL_ESC_PRESCALER(_x) ((_x) << 0)
#define DSIM_CLKCTRL_ESC_PRESCALER_MASK (0xffff << 0)
/* Time out register */
#define DSIM_TIMEOUT0 (0x14)
#define DSIM_TIMEOUT_BTA_TOUT(_x) ((_x) << 16)
#define DSIM_TIMEOUT_BTA_TOUT_MASK (0xff << 16)
#define DSIM_TIMEOUT_LPDR_TOUT(_x) ((_x) << 0)
#define DSIM_TIMEOUT_LPDR_TOUT_MASK (0xffff << 0)
/* Time out register */
#define DSIM_TIMEOUT1 (0x18)
#define DSIM_TIMEOUT_HSYNC_TOUT(_x) ((_x) << 0)
#define DSIM_TIMEOUT_HSYNC_TOUT_MASK (0xff << 0)
/* Escape mode register */
#define DSIM_ESCMODE (0x1c)
#define DSIM_ESCMODE_STOP_STATE_CNT(_x) ((_x) << 21)
#define DSIM_ESCMODE_STOP_STATE_CNT_MASK (0x7ff << 21)
#define DSIM_ESCMODE_FORCE_STOP_STATE (1 << 20)
#define DSIM_ESCMODE_FORCE_BTA (1 << 16)
#define DSIM_ESCMODE_CMD_LPDT (1 << 7)
#define DSIM_ESCMODE_TRIGGER_RST (1 << 4)
#define DSIM_ESCMODE_TX_ULPS_DATA (1 << 3)
#define DSIM_ESCMODE_TX_ULPS_DATA_EXIT (1 << 2)
#define DSIM_ESCMODE_TX_ULPS_CLK (1 << 1)
#define DSIM_ESCMODE_TX_ULPS_CLK_EXIT (1 << 0)
/* Display image resolution register */
#define DSIM_RESOL (0x20)
#define DSIM_RESOL_VRESOL(x) (((x) & 0xfff) << 16)
#define DSIM_RESOL_VRESOL_MASK (0xfff << 16)
#define DSIM_RESOL_HRESOL(x) (((x) & 0Xfff) << 0)
#define DSIM_RESOL_HRESOL_MASK (0xfff << 0)
#define DSIM_RESOL_LINEVAL_GET(_v) (((_v) >> 16) & 0xfff)
#define DSIM_RESOL_HOZVAL_GET(_v) (((_v) >> 0) & 0xfff)
/* Main display Vporch register */
#define DSIM_VPORCH (0x24)
#define DSIM_VPORCH_CMD_ALLOW(_x) ((_x) << 28)
#define DSIM_VPORCH_CMD_ALLOW_MASK (0xf << 28)
#define DSIM_VPORCH_STABLE_VFP(_x) ((_x) << 16)
#define DSIM_VPORCH_STABLE_VFP_MASK (0x7ff << 16)
#define DSIM_VPORCH_VBP(_x) ((_x) << 0)
#define DSIM_VPORCH_VBP_MASK (0x7ff << 0)
/* Main display Hporch register */
#define DSIM_HPORCH (0x28)
#define DSIM_HPORCH_HFP(_x) ((_x) << 16)
#define DSIM_HPORCH_HFP_MASK (0xffff << 16)
#define DSIM_HPORCH_HBP(_x) ((_x) << 0)
#define DSIM_HPORCH_HBP_MASK (0xffff << 0)
/* Main display sync area register */
#define DSIM_SYNC (0x2C)
#define DSIM_SYNC_VSA(_x) ((_x) << 16)
#define DSIM_SYNC_VSA_MASK (0x7ff << 16)
#define DSIM_SYNC_HSA(_x) ((_x) << 0)
#define DSIM_SYNC_HSA_MASK (0xffff << 0)
/* Configuration register */
#define DSIM_CONFIG (0x30)
#define DSIM_CONFIG_NONCONTINUOUS_CLOCK_LANE (1 << 31)
#define DSIM_CONFIG_CLKLANE_STOP_START (1 << 30)
#define DSIM_CONFIG_FLUSH_VS (1 << 29)
#define DSIM_CONFIG_SYNC_INFORM (1 << 27)
#define DSIM_CONFIG_BURST_MODE (1 << 26)
#define DSIM_CONFIG_HSYNC_PRESERVE (1 << 25)
#define DSIM_CONFIG_HSE_DISABLE (1 << 23)
#define DSIM_CONFIG_HFP_DISABLE (1 << 22)
#define DSIM_CONFIG_HBP_DISABLE (1 << 21)
#define DSIM_CONFIG_HSA_DISABLE (1 << 20)
#define DSIM_CONFIG_CPRS_EN (1 << 19)
#define DSIM_CONFIG_VIDEO_MODE (1 << 18)
#define DSIM_CONFIG_VC_CONTROL (1 << 17)
#define DSIM_CONFIG_VC_ID(_x) ((_x) << 16)
#define DSIM_CONFIG_VC_ID_MASK (0x3 << 16)
#define DSIM_CONFIG_PIXEL_FORMAT(_x) ((_x) << 12)
#define DSIM_CONFIG_PIXEL_FORMAT_MASK (0x7 << 12)
#define DSIM_CONFIG_MULTI_PIX (1 << 11)
#define DSIM_CONFIG_Q_CHANNEL_EN (1 << 10)
#define DSIM_CONFIG_PER_FRAME_READ_EN (1 << 9)
#define DSIM_CONFIG_NUM_OF_DATA_LANE(_x) ((_x) << 5)
#define DSIM_CONFIG_NUM_OF_DATA_LANE_MASK (0x3 << 5)
#define DSIM_CONFIG_LANES_EN(_x) (((_x) & 0x1f) << 0)
/* Interrupt source register */
#define DSIM_INTSRC (0x34)
#define DSIM_INTSRC_PLL_STABLE (1 << 31)
#define DSIM_INTSRC_SW_RST_RELEASE (1 << 30)
#define DSIM_INTSRC_SFR_PL_FIFO_EMPTY (1 << 29)
#define DSIM_INTSRC_SFR_PH_FIFO_EMPTY (1 << 28)
#define DSIM_INTSRC_SFR_PH_FIFO_OVERFLOW (1 << 26)
#define DSIM_INTSRC_BUS_TURN_OVER (1 << 25)
#define DSIM_INTSRC_FRAME_DONE (1 << 24)
#define DSIM_INTSRC_ABNRMAL_CMD_ST (1 << 22)
#define DSIM_INTSRC_LPDR_TOUT (1 << 21)
#define DSIM_INTSRC_BTA_TOUT (1 << 20)
#define DSIM_INTSRC_HSYNC_TOUT (1 << 19)
#define DSIM_INTSRC_RX_DATA_DONE (1 << 18)
#define DSIM_INTSRC_ERR_RX_ECC (1 << 15)
/* Interrupt mask register */
#define DSIM_INTMSK (0x38)
#define DSIM_INTMSK_PLL_STABLE (1 << 31)
#define DSIM_INTSRC_SW_RST_RELEASE (1 << 30)
#define DSIM_INTMSK_SFR_PL_FIFO_EMPTY (1 << 29)
#define DSIM_INTMSK_SFR_PH_FIFO_EMPTY (1 << 28)
#define DSIM_INTMSK_SFR_PH_FIFO_OVERFLOW (1 << 26)
#define DSIM_INTMSK_BUS_TURN_OVER (1 << 25)
#define DSIM_INTMSK_FRAME_DONE (1 << 24)
#define DSIM_INTMSK_ABNORMAL_CMD_ST (1 << 22)
#define DSIM_INTMSK_LPDR_TOUT (1 << 21)
#define DSIM_INTMSK_BTA_TOUT (1 << 20)
#define DSIM_INTMSK_HSYNC_TOUT (1 << 19)
#define DSIM_INTMSK_RX_DATA_DONE (1 << 18)
#define DSIM_INTMSK_ERR_RX_ECC (1 << 15)
/* Packet Header FIFO register */
#define DSIM_PKTHDR (0x3c)
#define DSIM_PKTHDR_ID(_x) ((_x) << 0)
#define DSIM_PKTHDR_DATA0(_x) ((_x) << 8)
#define DSIM_PKTHDR_DATA1(_x) ((_x) << 16)
/* Payload FIFO register */
#define DSIM_PAYLOAD (0x40)
/* Read FIFO register */
#define DSIM_RXFIFO (0x44)
/* SFR control Register for Stanby & Shadow*/
#define DSIM_SFR_CTRL (0x48)
#define DSIM_SFR_CTRL_STANDBY (1 << 4)
#define DSIM_SFR_CTRL_SHADOW_UPDATE (1 << 1)
#define DSIM_SFR_CTRL_SHADOW_EN (1 << 0)
/* FIFO status and control register */
#define DSIM_FIFOCTRL (0x4C)
#define DSIM_FIFOCTRL_NUMBER_OF_PH_SFR(_x) (((_x) & 0x3f) << 16)
#define DSIM_FIFOCTRL_EMPTY_RX (1 << 12)
#define DSIM_FIFOCTRL_FULL_PH_SFR (1 << 11)
#define DSIM_FIFOCTRL_FULL_PL_SFR (1 << 9)
#define DSIM_FIFOCTRL_INIT_RX (1 << 2)
#define DSIM_FIFOCTRL_INIT_SFR (1 << 1)
/* Muli slice setting register*/
#define DSIM_CPRS_CTRL (0x58)
#define DSIM_CPRS_CTRL_MULI_SLICE_PACKET (1 << 3)
#define DSIM_CPRS_CTRL_NUM_OF_SLICE(_x) ((_x) << 0)
#define DSIM_CPRS_CTRL_NUM_OF_SLICE_MASK (0x7 << 0)
/*Slice01 size register*/
#define DSIM_SLICE01 (0x5C)
#define DSIM_SLICE01_SIZE_OF_SLICE1(_x) ((_x) << 16)
#define DSIM_SLICE01_SIZE_OF_SLICE1_MASK (0x1fff << 16)
#define DSIM_SLICE01_SIZE_OF_SLICE0(_x) ((_x) << 0)
#define DSIM_SLICE01_SIZE_OF_SLICE0_MASK (0x1fff << 0)
/*Slice23 size register*/
#define DSIM_SLICE23 (0x60)
#define DSIM_SLICE23_SIZE_OF_SLICE3(_x) ((_x) << 16)
#define DSIM_SLICE23_SIZE_OF_SLICE3_MASK (0x1fff << 16)
#define DSIM_SLICE23_SIZE_OF_SLICE2(_x) ((_x) << 0)
#define DSIM_SLICE23_SIZE_OF_SLICE2_MASK (0x1fff << 0)
/* Command configuration register */
#define DSIM_CMD_CONFIG (0x78)
#define DSIM_CMD_CONFIG_TE_DETECT_POLARITY (1 << 25)
#define DSIM_CMD_CONFIG_VSYNC_DETECT_POLARITY (1 << 24)
#define DSIM_CMD_CONFIG_PKT_GO_RDY (1 << 22)
#define DSIM_CMD_CONFIG_PKT_GO_EN (1 << 21)
#define DSIM_CMD_CONFIG_CMD_CTRL_SEL (1 << 20)
#define DSIM_CMD_CONFIG_PKT_SEND_CNT(_x) ((_x) << 8)
#define DSIM_CMD_CONFIG_PKT_SEND_CNT_MASK (0xfff << 8)
#define DSIM_CMD_CONFIG_MULTI_CMD_PKT_EN (1 << 7)
#define DSIM_CMD_CONFIG_MULTI_PKT_CNT(_x) ((_x) << 0)
#define DSIM_CMD_CONFIG_MULTI_PKT_CNT_MASK (0xffff << 0)
/* TE based command register*/
#define DSIM_CMD_TE_CTRL0 (0x7C)
#define DSIM_CMD_TE_CTRL0_TIME_STABLE_VFP(_x) ((_x) << 16)
#define DSIM_CMD_TE_CTRL0_TIME_STABLE_VFP_MASK (0xffff << 16)
#define DSIM_CMD_TE_CTRL0_TIME_VSYNC_TOUT(_x) ((_x) << 0)
#define DSIM_CMD_TE_CTRL0_TIME_VSYNC_TOUT_MASK (0xffff << 0)
/* TE based command register*/
#define DSIM_CMD_TE_CTRL1 (0x80)
#define DSIM_CMD_TE_CTRL1_TIME_TE_PROTECT_ON(_x) ((_x) << 16)
#define DSIM_CMD_TE_CTRL1_TIME_TE_PROTECT_ON_MASK (0xffff << 16)
#define DSIM_CMD_TE_CTRL1_TIME_TE_TOUT(_x) ((_x) << 0)
#define DSIM_CMD_TE_CTRL1_TIME_TE_TOUT_MASK (0xffff << 0)
/*Command Mode Status register*/
#define DSIM_CMD_STATUS (0x87)
#define DSIM_CMD_STATUS_ABNORMAL_CAUSE_ST(_x) (((_x) & 0x3ff) << 0)
/*BIST generation register*/
#define DSIM_BIST_GEN (0x88)
#define DSIM_BIST_GEN_BIST_VFP(_x) ((_x) << 20)
#define DSIM_BIST_GEN_BIST_VFP_MASK (0x7ff << 20)
#define DSIM_BIST_GEN_BIST_START (1 << 16)
#define DSIM_BIST_GEN_COLORIMETRIC_FORMAT (1 << 6)
#define DSIM_BIST_GEN_HSYNC_POLARITY (1 << 5)
#define DSIM_BIST_GEN_VSYNC_POLARITY (1 << 4)
#define DSIM_BIST_GEN_BIST_BAR_WIDTH (1 << 3)
#define DSIM_BIST_GEN_BIST_TYPE(_x) ((_x) << 1)
#define DSIM_BIST_GEN_BIST_TYPE_MASK (0x3 << 1)
#define DSIM_BIST_GEN_BIST_EN (1 << 0)
/*DSIM to CSI loopback register*/
#define DSIM_CSIS_LB (0x8C)
#define DSIM_CSIS_LB_CSIS_LB_EN (1 << 8)
#define DSIM_CSIS_LB_CSIS_PH(_x) ((_x) << 0)
#define DSIM_CSIS_LB_CSIS_PH_MASK (0xff << 0)
/* PLL control register */
#define DSIM_PLLCTRL (0x94)
#define DSIM_PLLCTRL_DPDN_SWAP_CLK (1 << 25)
#define DSIM_PLLCTRL_DPDN_SWAP_DATA (1 << 24)
#define DSIM_PLLCTRL_PLL_EN (1 << 23)
#define DSIM_PLLCTRL_PMS_MASK (0x7ffff << 0)
/* M_PLL CTR1 register*/
#define DSIM_PLL_CTRL1 (0x98)
#define DSIM_PLL_CTRL1_M_PLL_CTRL1 (0xffffffff << 0)
/* M_PLL CTR1 register*/
#define DSIM_PLL_CTRL2 (0x9C)
#define DSIM_PLL_CTRL2_M_PLL_CTRL2 (0xffffffff << 0)
/* PLL timer register */
#define DSIM_PLLTMR (0xa0)
/* D-PHY Master & Slave Analog block characteristics control register */
#define DSIM_PHYCTRL (0xa4)
#define DSIM_PHYCTRL_VREG (1 << 26)
#define DSIM_PHYCTRL_B_DPHYCTL0(_x) ((_x) << 0)
#define DSIM_PHYCTRL_B_DPHYCTL0_MASK (0x3ff << 0)
/* D-PHY Master global operating timing register */
#define DSIM_PHYTIMING (0xb4)
#define DSIM_PHYTIMING_M_TLPXCTL(_x) ((_x) << 8)
#define DSIM_PHYTIMING_M_TLPXCTL_MASK (0xff << 8)
#define DSIM_PHYTIMING_M_THSEXITCTL(_x) ((_x) << 0)
#define DSIM_PHYTIMING_M_THSEXITCTL_MASK (0xff << 0)
#define DSIM_PHYTIMING1 (0xb8)
#define DSIM_PHYTIMING1_M_TCLKPRPRCTL(_x) ((_x) << 24)
#define DSIM_PHYTIMING1_M_TCLKPRPRCTL_MASK (0xff << 24)
#define DSIM_PHYTIMING1_M_TCLKZEROCTL(_x) ((_x) << 16)
#define DSIM_PHYTIMING1_M_TCLKZEROCTL_MASK (0xff << 16)
#define DSIM_PHYTIMING1_M_TCLKPOSTCTL(_x) ((_x) << 8)
#define DSIM_PHYTIMING1_M_TCLKPOSTCTL_MASK (0xff << 8)
#define DSIM_PHYTIMING1_M_TCLKTRAILCTL(_x) ((_x) << 0)
#define DSIM_PHYTIMING1_M_TCLKTRAILCTL_MASK (0xff << 0)
#define DSIM_PHYTIMING2 (0xbc)
#define DSIM_PHYTIMING2_M_THSPRPRCTL(_x) ((_x) << 16)
#define DSIM_PHYTIMING2_M_THSPRPRCTL_MASK (0xff << 16)
#define DSIM_PHYTIMING2_M_THSZEROCTL(_x) ((_x) << 8)
#define DSIM_PHYTIMING2_M_THSZEROCTL_MASK (0xff << 8)
#define DSIM_PHYTIMING2_M_THSTRAILCTL(_x) ((_x) << 0)
#define DSIM_PHYTIMING2_M_THSTRAILCTL_MASK (0xff << 0)
#endif /* _REGS_DSIM_H */

View file

@ -0,0 +1,6 @@
config EXYNOS_VPP
bool "Samsung Exynos Video Post Processor driver"
depends on EXYNOS_DECON_8890
default y
help
Enable VPP driver.

View file

@ -0,0 +1,2 @@
vpp-objs := vpp_drv.o vpp_reg_8890.o
obj-$(CONFIG_EXYNOS_VPP) += vpp.o

View file

@ -0,0 +1,233 @@
/* linux/drivers/video/decon_2.0/regs-vpp.h
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Register definition file for Samsung vpp 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 VPP_REGS_H_
#define VPP_REGS_H_
/* IDMA_VG(R)x_ENABLE */
#define VG_ENABLE (0x00)
#define VG_ENABLE_OP_STATUS (1 << 2)
#define VG_ENABLE_SFR_UPDATE_FORCE (1 << 4)
#define VG_ENABLE_INT_CLOCK_GATE_EN (1 << 8)
#define VG_ENABLE_SRAM_CLOCK_GATE_EN (1 << 9)
#define VG_ENABLE_SFR_CLOCK_GATE_EN (1 << 10)
#define VG_ENABLE_SCALER_CLOCK_GATE_EN (1 << 11)
#define VG_ENABLE_RT_PATH_EN (1 << 16)
#define VG_ENABLE_RT_PATH_EN_S (1 << 17)
#define VG_ENABLE_SRESET (1 << 24)
#define VG_ENABLE_VSD_SRESET_MASK (1 << 25)
/* IDMA_VG(R)x_IRQ */
#define VG_IRQ (0x04)
#define VG_IRQ_ENABLE (1 << 0)
#define VG_IRQ_FRAMEDONE_MASK (1 << 1)
#define VG_IRQ_DEADLOCK_STATUS_MASK (1 << 2)
#define VG_IRQ_READ_SLAVE_ERROR_MASK (1 << 4)
#define VG_IRQ_HW_RESET_DONE_MASK (1 << 5)
#define VG_IRQ_SFR_UPDATE_DONE_MASK (1 << 6)
#define VG_IRQ_FRAMEDONE (1 << 16)
#define VG_IRQ_DEADLOCK_STATUS (1 << 17)
#define VG_IRQ_READ_SLAVE_ERROR (1 << 19)
#define VG_IRQ_HW_RESET_DONE (1 << 20)
#define VG_IRQ_SFR_UPDATE_DONE (1 << 21)
/* IDMA_VG(R)x_IN_CON */
#define VG_IN_CON (0x08)
#define VG_IN_CON_BLOCKING_FEATURE_EN (1 << 3)
#define VG_IN_CON_CHROMINANCE_STRIDE_EN (1 << 4)
#define VG_IN_CON_SCAN_MODE_MASK (3 << 5)
#define VG_IN_CON_SCAN_MODE_PRO_TO_PRO (1 << 5)
#define VG_IN_CON_SCAN_MODE_INT_TO_PRO (2 << 5)
#define VG_IN_CON_SCAN_MODE_INT_TO_INT (3 << 5)
#define VG_IN_CON_IN_ROTATION_MASK (7 << 8)
#define VG_IN_CON_IN_ROTATION_X_FLIP (1 << 8)
#define VG_IN_CON_IN_ROTATION_Y_FLIP (2 << 8)
#define VG_IN_CON_IN_ROTATION_180 (3 << 8)
#define VG_IN_CON_IN_ROTATION_90 (4 << 8)
#define VG_IN_CON_IN_ROTATION_90_X_FLIP (5 << 8)
#define VG_IN_CON_IN_ROTATION_90_Y_FLIP (6 << 8)
#define VG_IN_CON_IN_ROTATION_270 (7 << 8)
#define VG_IN_CON_IMG_FORMAT_MASK (31 << 11)
#define VG_IN_CON_IMG_FORMAT_ARGB8888 (0 << 11)
#define VG_IN_CON_IMG_FORMAT_ABGR8888 (1 << 11)
#define VG_IN_CON_IMG_FORMAT_RGBA8888 (2 << 11)
#define VG_IN_CON_IMG_FORMAT_BGRA8888 (3 << 11)
#define VG_IN_CON_IMG_FORMAT_XRGB8888 (4 << 11)
#define VG_IN_CON_IMG_FORMAT_XBGR8888 (5 << 11)
#define VG_IN_CON_IMG_FORMAT_RGBX8888 (6 << 11)
#define VG_IN_CON_IMG_FORMAT_BGRX8888 (7 << 11)
#define VG_IN_CON_IMG_FORMAT_RGB565 (8 << 11)
#define VG_IN_CON_IMG_FORMAT_YUV422_2P (20 << 11)
#define VG_IN_CON_IMG_FORMAT_YVU422_2P (21 << 11)
#define VG_IN_CON_IMG_FORMAT_YUV422_3P (22 << 11)
#define VG_IN_CON_IMG_FORMAT_YUV420_2P (24 << 11)
#define VG_IN_CON_IMG_FORMAT_YVU420_2P (25 << 11)
#define VG_IN_CON_IMG_FORMAT_YUV420_3P (26 << 11)
#define VG_IN_CON_BURST_LENGTH_MASK (0xF << 24)
#define VG_IN_CON_BURST_LENGTH_0 (0 << 24)
#define VG_IN_CON_BURST_LENGTH_1 (1 << 24)
#define VG_IN_CON_BURST_LENGTH_2 (2 << 24)
#define VG_IN_CON_BURST_LENGTH_3 (3 << 24)
#define VG_IN_CON_IN_AFBC_EN (1 << 7)
/* IDMA_VG(R)x_OUT_CON */
#define VG_OUT_CON (0x0C)
#define VG_OUT_CON_RGB_TYPE_MASK (3 << 17)
#define VG_OUT_CON_RGB_TYPE_601_NARROW (0 << 17)
#define VG_OUT_CON_RGB_TYPE_601_WIDE (1 << 17)
#define VG_OUT_CON_RGB_TYPE_709_NARROW (2 << 17)
#define VG_OUT_CON_RGB_TYPE_709_WIDE (3 << 17)
#define VG_OUT_CON_FRAME_ALPHA_MASK (0xFF << 24)
#define VG_OUT_CON_FRAME_ALPHA(x) (x << 24)
/* IDMA_VG(R)x_SRC_SIZE */
#define VG_SRC_SIZE (0x10)
#define VG_SRC_SIZE_HEIGHT_MASK (0x1FFF << 16)
#define VG_SRC_SIZE_HEIGHT(x) ((x) << 16)
#define VG_SRC_SIZE_WIDTH_MASK (0x1FFF << 0)
#define VG_SRC_SIZE_WIDTH(x) ((x) << 0)
/* IDMA_VG(R)x_SRC_OFFSET */
#define VG_SRC_OFFSET (0x14)
#define VG_SRC_OFFSET_Y_MASK (0x1FFF << 16)
#define VG_SRC_OFFSET_Y(x) ((x) << 16)
#define VG_SRC_OFFSET_X_MASK (0x1FFF << 0)
#define VG_SRC_OFFSET_X(x) ((x) << 0)
/* IDMA_VG(R)x_IMG_SIZE */
#define VG_IMG_SIZE (0x18)
#define VG_IMG_SIZE_HEIGHT_MASK (0x1FFF << 16)
#define VG_IMG_SIZE_HEIGHT(x) ((x) << 16)
#define VG_IMG_SIZE_WIDTH_MASK (0x1FFF << 0)
#define VG_IMG_SIZE_WIDTH(x) ((x) << 0)
/* IDMA_x_PINGPONG_UPDATE */
#define VG_PINGPONG_UPDATE (0x1C)
#define VG_ADDR_PINGPONG_UPDATE (1 << 0)
/* IDMA_VG(R)x_CHROMINANCE_STRIDE */
#define VG_CHROMINANCE_STRIDE (0x20)
#define VG_CHROMINANCE_STRIDE_MASK (0x1FFF << 0)
#define VG_CHROMINANCE_STRIDE_SIZE(x) ((x) << 0)
/* IDMA_VG(R)x_BLK_OFFSET */
#define VG_BLK_OFFSET (0x24)
#define VG_BLK_OFFSET_Y_MASK (0x1FFF << 16)
#define VG_BLK_OFFSET_Y(x) ((x) << 16)
#define VG_BLK_OFFSET_X_MASK (0x1FFF << 0)
#define VG_BLK_OFFSET_X(x) ((x) << 0)
/* IDMA_VG(R)x_BLK_SIZE */
#define VG_BLK_SIZE (0x28)
#define VG_BLK_SIZE_HEIGHT_MASK (0x1FFF << 16)
#define VG_BLK_SIZE_HEIGHT(x) ((x) << 16)
#define VG_BLK_SIZE_WIDTH_MASK (0x1FFF << 0)
#define VG_BLK_SIZE_WIDTH(x) ((x) << 0)
/* IDMA_VG(R)x_SCALED_SIZE */
#define VG_SCALED_SIZE (0x2C)
#define VG_SCALED_SIZE_HEIGHT_MASK (0x1FFF << 16)
#define VG_SCALED_SIZE_HEIGHT(x) ((x) << 16)
#define VG_SCALED_SIZE_WIDTH_MASK (0x1FFF << 0)
#define VG_SCALED_SIZE_WIDTH(x) ((x) << 0)
/* IDMA_VG(R)x_H_RATIO */
#define VG_H_RATIO (0x44)
#define VG_H_RATIO_MASK (0xFFFFFF << 0)
#define VG_H_RATIO_VALUE(x) ((x) << 0)
/* IDMA_VG(R)x_V_RATIO */
#define VG_V_RATIO (0x48)
#define VG_V_RATIO_MASK (0xFFFFFF << 0)
#define VG_V_RATIO_VALUE(x) ((x) << 0)
/* IDMA_VG(R)x LOOKUP TABLE */
#define VG_QOS_LUT07_00 (0x60)
#define VG_QOS_LUT15_08 (0x64)
/* IDMA_VG(R)x BASE ADDRESS CONTROL */
#define VG_BASE_ADDR_CON (0x70)
#define VG_BASE_ADDR_CON_MASK(n) (1 << (x))
#define VG_BASE_ADDR_CON_PINGPONG_MASK (3 << 16)
#define VG_BASE_ADDR_CON_PINGPONG(n) ((x) << 16)
#define VG_BASE_ADDR_CON_CURRENT(n) ((x) >> 24)
#define VG_BASE_ADDR_CON_CURRENT_INDEX_INIT (1 << 31)
/* IDMA_VG(R)x BASE ADDRESS */
#define VG_BASE_ADDR_Y(n) (0x74 + (n) * 0x4)
#define VG_BASE_ADDR_Y_EVEN(n) (0x84 + (n) * 0x4)
#define VG_BASE_ADDR_CB(n) (0x94 + (n) * 0x4)
#define VG_BASE_ADDR_CB_EVEN(n) (0xA4 + (n) * 0x4)
/* IDMA_VG(R)x scaling filter */
#define VG_H_COEF(n, s, x) (0x290 + (n) * 0x4 + (s) * 0x24 + (x) * 0x200)
#define VG_V_COEF(n, s, x) (0x200 + (n) * 0x4 + (s) * 0x24 + (x) * 0x200)
/* IDMA_VG(R)x Y(R) start H position */
#define VG_YHPOSITION0 (0x5B0)
/* IDMA_VG(R)x Y(R) start V position */
#define VG_YVPOSITION0 (0x5B4)
/* IDMA_VG(R)x CB(G)/CR(B) H position */
#define VG_CHPOSITION0 (0x5B8)
/* IDMA_VG(R)x CB(G)/CR(B) V position */
#define VG_CVPOSITION0 (0x5BC)
/* IDMA_VG(R)x Y(R) start H position for odd frame */
#define VG_YHPOSITION1 (0x5C0)
/* IDMA_VG(R)x Y(R) start V position for odd frame */
#define VG_YVPOSITION1 (0x5C4)
/* IDMA_VG(R)x CB(G)/CR(B) H position for odd frame */
#define VG_CHPOSITION1 (0x5C8)
/* IDMA_VG(R)x CB(G)/CR(B) V position for odd frame */
#define VG_CVPOSITION1 (0x5CC)
#define VG_POSITION_F_MASK (0xFFFFF << 0)
/* IDMA_VG(R)x Deadlock Counter Number */
#define VG_DEADLOCK_NUM (0xA00)
/* IDMA_VG(R)x Sharpness Enhancer Control */
#define VG_SHE_CON (0xA0C)
#define VG_SHE_CON_SHARP_PATTERN_MASK (1 << 3)
#define VG_SHE_CON_SHARP_PATTERN_ENABLE (0 << 3)
#define VG_SHE_CON_SHARP_EFFECT_MASK (7 << 0)
#define VG_SHE_CON_SHARP_EFFECT_MAX (7 << 0)
#define VG_SHE_CON_SHARP_EN (1 << 4)
#define VG_SHE_CON_SHARP_BYPASS (1 << 5)
/* IDMA_VG(R)x SMART Interface Pixel Number */
#define VG_SMART_IF_PIXEL_NUM (0xA48)
/* IDMA_VG(R)x Dynamic clock gating */
#define VG_DYNAMIC_GATING_ENABLE (0xA54)
#endif

View file

@ -0,0 +1,252 @@
/* linux/drivers/video/exynos/decon/vpp_core.h
*
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* header file for Samsung EXYNOS5 SoC series VPP 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 VPP_H_
#define VPP_H_
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/exynos_iovmm.h>
#include <media/exynos_mc.h>
#include "regs-vpp.h"
#include "vpp_common.h"
#include "../decon.h"
#define VPP_PADS_NUM 1
#define DEV (&vpp->pdev->dev)
#define is_rotation(config) (config->vpp_parm.rot >= VPP_ROT_90)
#define is_normal(config) (VPP_ROT_NORMAL)
#define is_yuv(config) ((config->format >= DECON_PIXEL_FORMAT_NV16) && (config->format < DECON_PIXEL_FORMAT_MAX))
#define is_yuv422(config) ((config->format >= DECON_PIXEL_FORMAT_NV16) && (config->format <= DECON_PIXEL_FORMAT_YVU422_3P))
#define is_yuv420(config) ((config->format >= DECON_PIXEL_FORMAT_NV12) && (config->format <= DECON_PIXEL_FORMAT_YVU420M))
#define is_rgb(config) ((config->format >= DECON_PIXEL_FORMAT_ARGB_8888) && (config->format <= DECON_PIXEL_FORMAT_RGB_565))
#define is_rgb16(config) ((config->format == DECON_PIXEL_FORMAT_RGB_565))
#define is_ayv12(config) (config->format == DECON_PIXEL_FORMAT_YVU420)
#define is_fraction(x) ((x) >> 15)
#define is_vpp0_series(vpp) ((vpp->id == 0 || vpp->id == 1 || vpp->id == 2 || vpp->id == 3))
#define is_vgr(vpp) ((vpp->id == 6) || (vpp->id == 7))
#define is_vgr1(vpp) (vpp->id == 7)
#define is_g(vpp) ((vpp->id == 0) || (vpp->id == 1) || (vpp->id == 4) || (vpp->id == 5))
#define is_wb(vpp) (vpp->id == 8)
#define is_scaling(vpp) ((vpp->h_ratio != (1 << 20)) || (vpp->v_ratio != (1 << 20)))
#define is_scale_down(vpp) ((vpp->h_ratio > (1 << 20)) || (vpp->v_ratio > (1 << 20)))
#define vpp_err(fmt, ...) \
do { \
pr_err(pr_fmt(fmt), ##__VA_ARGS__); \
exynos_ss_printk(fmt, ##__VA_ARGS__); \
} while (0)
#define vpp_info(fmt, ...) \
do { \
pr_info(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define vpp_dbg(fmt, ...) \
do { \
pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
enum vpp_dev_state {
VPP_RUNNING,
VPP_POWER_ON,
VPP_STOPPING,
};
struct vpp_resources {
struct clk *gate;
};
struct vpp_fraction {
u32 y_x;
u32 y_y;
u32 c_x;
u32 c_y;
u32 w;
u32 h;
};
struct vpp_minlock_entry {
bool rotation;
u32 scalefactor;
u32 dvfsfreq;
};
struct vpp_minlock_table {
struct list_head node;
u16 width;
u16 height;
int num_entries;
struct vpp_minlock_entry entries[0];
};
struct vpp_dev {
int id;
struct platform_device *pdev;
spinlock_t slock;
struct media_pad pad;
struct exynos_md *mdev;
struct v4l2_subdev *sd;
void __iomem *regs;
unsigned long state;
struct clk *gate_clk;
struct vpp_resources res;
wait_queue_head_t stop_queue;
wait_queue_head_t update_queue;
struct timer_list op_timer;
u32 start_count;
u32 done_count;
u32 update_cnt;
u32 update_cnt_prev;
struct decon_win_config *config;
struct pm_qos_request *vpp_disp_qos;
struct pm_qos_request *vpp_int_qos;
struct pm_qos_request vpp_mif_qos;
u32 h_ratio;
u32 v_ratio;
struct vpp_fraction fract_val;
struct mutex mlock;
unsigned int irq;
u32 prev_read_order;
u32 pbuf_num;
u64 disp_cur_bw;
u64 cur_bw;
u64 prev_bw;
u32 sc_w;
u32 sc_h;
struct decon_bts *bts_ops;
};
extern struct vpp_dev *vpp0_for_decon;
extern struct vpp_dev *vpp1_for_decon;
extern struct vpp_dev *vpp2_for_decon;
extern struct vpp_dev *vpp3_for_decon;
extern struct vpp_dev *vpp4_for_decon;
extern struct vpp_dev *vpp5_for_decon;
extern struct vpp_dev *vpp6_for_decon;
extern struct vpp_dev *vpp7_for_decon;
extern struct vpp_dev *vpp8_for_decon;
static inline struct vpp_dev *get_vpp_drvdata(u32 id)
{
switch (id) {
case 0:
return vpp0_for_decon;
case 1:
return vpp1_for_decon;
case 2:
return vpp2_for_decon;
case 3:
return vpp3_for_decon;
case 4:
return vpp4_for_decon;
case 5:
return vpp5_for_decon;
case 6:
return vpp6_for_decon;
case 7:
return vpp7_for_decon;
case 8:
return vpp8_for_decon;
default:
return NULL;
}
}
static inline u32 vpp_read(u32 id, u32 reg_id)
{
struct vpp_dev *vpp = get_vpp_drvdata(id);
return readl(vpp->regs + reg_id);
}
static inline u32 vpp_read_mask(u32 id, u32 reg_id, u32 mask)
{
u32 val = vpp_read(id, reg_id);
val &= (~mask);
return val;
}
static inline void vpp_write(u32 id, u32 reg_id, u32 val)
{
struct vpp_dev *vpp = get_vpp_drvdata(id);
writel(val, vpp->regs + reg_id);
}
static inline void vpp_write_mask(u32 id, u32 reg_id, u32 val, u32 mask)
{
struct vpp_dev *vpp = get_vpp_drvdata(id);
u32 old = vpp_read(id, reg_id);
val = (val & mask) | (old & ~mask);
writel(val, vpp->regs + reg_id);
}
static inline void vpp_select_format(struct vpp_dev *vpp, struct vpp_img_format *vi)
{
struct decon_win_config *config = vpp->config;
vi->vgr = is_vgr(vpp);
vi->normal = is_normal(vpp);
vi->rot = is_rotation(config);
vi->scale = is_scaling(vpp);
vi->yuv = is_yuv(config);
vi->yuv422 = is_yuv422(config);
vi->yuv420 = is_yuv420(config);
vi->pre_none = 1;
vi->pre_12 = 0;
vi->pre_14 = 0;
vi->wb = is_wb(vpp);
}
static inline void vpp_to_scale_params(struct vpp_dev *vpp, struct vpp_size_param *p)
{
struct decon_win_config *config = vpp->config;
struct vpp_params *vpp_parm = &vpp->config->vpp_parm;
struct vpp_fraction *fr = &vpp->fract_val;
p->src_x = config->src.x;
p->src_y = config->src.y;
p->src_w = config->src.w;
p->src_h = config->src.h;
p->fr_w = fr->w;
p->fr_h = fr->h;
p->dst_w = config->dst.w;
p->dst_h = config->dst.h;
p->vpp_h_ratio = vpp->h_ratio;
p->vpp_v_ratio = vpp->v_ratio;
p->src_fw = config->src.f_w;
p->src_fh = config->src.f_h;
p->fr_yx = vpp->fract_val.y_x;
p->fr_yy = vpp->fract_val.y_y;
p->fr_cx = vpp->fract_val.c_x;
p->fr_cy = vpp->fract_val.c_y;
p->rot = config->vpp_parm.rot;
p->block_x = config->block_area.x;
p->block_y = config->block_area.y;
p->block_w = config->block_area.w;
p->block_h = config->block_area.h;
p->addr0 = vpp_parm->addr[0];
p->addr1 = vpp_parm->addr[1];
p->addr2 = vpp_parm->addr[2];
}
#endif

View file

@ -0,0 +1,263 @@
/* linux/drivers/video/exynos/decon/vpp/vpp_coef.c
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* VPP poly-phase filter coefficients
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 2 of the License,
* or (at your option) any later version.
*/
#include <linux/types.h>
#include "vpp.h"
/* 8-tap Filter Coefficient */
const s16 h_coef_8t[7][16][8] = {
{ /* Ratio <= 65536 (~8:8) */
{ 0, 0, 0, 128, 0, 0, 0, 0 },/* 0 */
{ -1, 2, -6, 127, 7, -2, 1, 0 },/* 1 */
{ -1, 4, -12, 125, 16, -5, 1, 0 },/* 2 */
{ -1, 5, -15, 120, 25, -8, 2, 0 },/* 3 */
{ -1, 6, -18, 114, 35, -10, 3, -1 },/* 4 */
{ -1, 6, -20, 107, 46, -13, 4, -1 },/* 5 */
{ -2, 7, -21, 99, 57, -16, 5, -1 },/* 6 */
{ -1, 6, -20, 89, 68, -18, 5, -1 },/* 7 */
{ -1, 6, -20, 79, 79, -20, 6, -1 },/* 8 */
{ -1, 5, -18, 68, 89, -20, 6, -1 },/* 9 */
{ -1, 5, -16, 57, 99, -21, 7, -2 },/* 10 */
{ -1, 4, -13, 46, 107, -20, 6, -1 },/* 11 */
{ -1, 3, -10, 35, 114, -18, 6, -1 },/* 12 */
{ 0, 2, -8, 25, 120, -15, 5, -1 },/* 13 */
{ 0, 1, -5, 16, 125, -12, 4, -1 },/* 14 */
{ 0, 1, -2, 7, 127, -6, 2, -1 } /* 15 */
}, { /* 65536 < Ratio <= 74898 (~8:7) */
{ 3, -8, 14, 111, 13, -8, 3, 0 },/* 0 */
{ 2, -6, 7, 112, 21, -10, 3, -1 },/* 1 */
{ 2, -4, 1, 110, 28, -12, 4, -1 },/* 2 */
{ 1, -2, -3, 106, 36, -13, 4, -1 },/* 3 */
{ 1, -1, -7, 103, 44, -15, 4, -1 },/* 4 */
{ 1, 1, -11, 97, 53, -16, 4, -1 },/* 5 */
{ 0, 2, -13, 91, 61, -16, 4, -1 },/* 6 */
{ 0, 3, -15, 85, 69, -17, 4, -1 },/* 7 */
{ 0, 3, -16, 77, 77, -16, 3, 0 },/* 8 */
{ -1, 4, -17, 69, 85, -15, 3, 0 },/* 9 */
{ -1, 4, -16, 61, 91, -13, 2, 0 },/* 10 */
{ -1, 4, -16, 53, 97, -11, 1, 1 },/* 11 */
{ -1, 4, -15, 44, 103, -7, -1, 1 },/* 12 */
{ -1, 4, -13, 36, 106, -3, -2, 1 },/* 13 */
{ -1, 4, -12, 28, 110, 1, -4, 2 },/* 14 */
{ -1, 3, -10, 21, 112, 7, -6, 2 } /* 15 */
}, { /* 74898 < Ratio <= 87381 (~8:6) */
{ 2, -11, 25, 96, 25, -11, 2, 0 },/* 0 */
{ 2, -10, 19, 96, 31, -12, 2, 0 },/* 1 */
{ 2, -9, 14, 94, 37, -12, 2, 0 },/* 2 */
{ 2, -8, 10, 92, 43, -12, 1, 0 },/* 3 */
{ 2, -7, 5, 90, 49, -12, 1, 0 },/* 4 */
{ 2, -5, 1, 86, 55, -12, 0, 1 },/* 5 */
{ 2, -4, -2, 82, 61, -11, -1, 1 },/* 6 */
{ 1, -3, -5, 77, 67, -9, -1, 1 },/* 7 */
{ 1, -2, -7, 72, 72, -7, -2, 1 },/* 8 */
{ 1, -1, -9, 67, 77, -5, -3, 1 },/* 9 */
{ 1, -1, -11, 61, 82, -2, -4, 2 },/* 10 */
{ 1, 0, -12, 55, 86, 1, -5, 2 },/* 11 */
{ 0, 1, -12, 49, 90, 5, -7, 2 },/* 12 */
{ 0, 1, -12, 43, 92, 10, -8, 2 },/* 13 */
{ 0, 2, -12, 37, 94, 14, -9, 2 },/* 14 */
{ 0, 2, -12, 31, 96, 19, -10, 2 } /* 15 */
}, { /* 87381 < Ratio <= 104857 (~8:5) */
{ -1, -8, 33, 80, 33, -8, -1, 0 },/* 0 */
{ -1, -8, 28, 80, 37, -7, -2, 1 },/* 1 */
{ 0, -8, 24, 79, 41, -7, -2, 1 },/* 2 */
{ 0, -8, 20, 78, 46, -6, -3, 1 },/* 3 */
{ 0, -8, 16, 76, 50, -4, -3, 1 },/* 4 */
{ 0, -7, 13, 74, 54, -3, -4, 1 },/* 5 */
{ 1, -7, 10, 71, 58, -1, -5, 1 },/* 6 */
{ 1, -6, 6, 68, 62, 1, -5, 1 },/* 7 */
{ 1, -6, 4, 65, 65, 4, -6, 1 },/* 8 */
{ 1, -5, 1, 62, 68, 6, -6, 1 },/* 9 */
{ 1, -5, -1, 58, 71, 10, -7, 1 },/* 10 */
{ 1, -4, -3, 54, 74, 13, -7, 0 },/* 11 */
{ 1, -3, -4, 50, 76, 16, -8, 0 },/* 12 */
{ 1, -3, -6, 46, 78, 20, -8, 0 },/* 13 */
{ 1, -2, -7, 41, 79, 24, -8, 0 },/* 14 */
{ 1, -2, -7, 37, 80, 28, -8, -1 } /* 15 */
}, { /* 104857 < Ratio <= 131072 (~8:4) */
{ -3, 0, 35, 64, 35, 0, -3, 0 },/* 0 */
{ -3, -1, 32, 64, 38, 1, -3, 0 },/* 1 */
{ -2, -2, 29, 63, 41, 2, -3, 0 },/* 2 */
{ -2, -3, 27, 63, 43, 4, -4, 0 },/* 3 */
{ -2, -3, 24, 61, 46, 6, -4, 0 },/* 4 */
{ -2, -3, 21, 60, 49, 7, -4, 0 },/* 5 */
{ -1, -4, 19, 59, 51, 9, -4, -1 },/* 6 */
{ -1, -4, 16, 57, 53, 12, -4, -1 },/* 7 */
{ -1, -4, 14, 55, 55, 14, -4, -1 },/* 8 */
{ -1, -4, 12, 53, 57, 16, -4, -1 },/* 9 */
{ -1, -4, 9, 51, 59, 19, -4, -1 },/* 10 */
{ 0, -4, 7, 49, 60, 21, -3, -2 },/* 11 */
{ 0, -4, 6, 46, 61, 24, -3, -2 },/* 12 */
{ 0, -4, 4, 43, 63, 27, -3, -2 },/* 13 */
{ 0, -3, 2, 41, 63, 29, -2, -2 },/* 14 */
{ 0, -3, 1, 38, 64, 32, -1, -3 } /* 15 */
}, { /* 131072 < Ratio <= 174762 (~8:3) */
{ -1, 8, 33, 48, 33, 8, -1, 0 },/* 0 */
{ -1, 7, 31, 49, 35, 9, -1, -1 },/* 1 */
{ -1, 6, 30, 49, 36, 10, -1, -1 },/* 2 */
{ -1, 5, 28, 48, 38, 12, -1, -1 },/* 3 */
{ -1, 4, 26, 48, 39, 13, 0, -1 },/* 4 */
{ -1, 3, 24, 47, 41, 15, 0, -1 },/* 5 */
{ -1, 2, 23, 47, 42, 16, 0, -1 },/* 6 */
{ -1, 2, 21, 45, 43, 18, 1, -1 },/* 7 */
{ -1, 1, 19, 45, 45, 19, 1, -1 },/* 8 */
{ -1, 1, 18, 43, 45, 21, 2, -1 },/* 9 */
{ -1, 0, 16, 42, 47, 23, 2, -1 },/* 10 */
{ -1, 0, 15, 41, 47, 24, 3, -1 },/* 11 */
{ -1, 0, 13, 39, 48, 26, 4, -1 },/* 12 */
{ -1, -1, 12, 38, 48, 28, 5, -1 },/* 13 */
{ -1, -1, 10, 36, 49, 30, 6, -1 },/* 14 */
{ -1, -1, 9, 35, 49, 31, 7, -1 } /* 15 */
}, { /* 174762 < Ratio <= 262144 (~8:2) */
{ 2, 13, 30, 38, 30, 13, 2, 0 },/* 0 */
{ 2, 12, 29, 38, 30, 14, 3, 0 },/* 1 */
{ 2, 11, 28, 38, 31, 15, 3, 0 },/* 2 */
{ 2, 10, 26, 38, 32, 16, 4, 0 },/* 3 */
{ 1, 10, 26, 37, 33, 17, 4, 0 },/* 4 */
{ 1, 9, 24, 37, 34, 18, 5, 0 },/* 5 */
{ 1, 8, 24, 37, 34, 19, 5, 0 },/* 6 */
{ 1, 7, 22, 36, 35, 20, 6, 1 },/* 7 */
{ 1, 6, 21, 36, 36, 21, 6, 1 },/* 8 */
{ 1, 6, 20, 35, 36, 22, 7, 1 },/* 9 */
{ 0, 5, 19, 34, 37, 24, 8, 1 },/* 10 */
{ 0, 5, 18, 34, 37, 24, 9, 1 },/* 11 */
{ 0, 4, 17, 33, 37, 26, 10, 1 },/* 12 */
{ 0, 4, 16, 32, 38, 26, 10, 2 },/* 13 */
{ 0, 3, 15, 31, 38, 28, 11, 2 },/* 14 */
{ 0, 3, 14, 30, 38, 29, 12, 2 } /* 15 */
}
};
/* 4-tap Filter Coefficient */
const s16 v_coef_4t[7][16][4] = {
{ /* Ratio <= 65536 (~8:8) */
{ 0, 128, 0, 0 },/* 0 */
{ -4, 127, 5, 0 },/* 1 */
{ -6, 124, 11, -1 },/* 2 */
{ -8, 118, 19, -1 },/* 3 */
{ -8, 111, 27, -2 },/* 4 */
{ -8, 102, 37, -3 },/* 5 */
{ -8, 92, 48, -4 },/* 6 */
{ -7, 81, 59, -5 },/* 7 */
{ -6, 70, 70, -6 },/* 8 */
{ -5, 59, 81, -7 },/* 9 */
{ -4, 48, 92, -8 },/* 10 */
{ -3, 37, 102, -8 },/* 11 */
{ -2, 27, 111, -8 },/* 12 */
{ -1, 19, 118, -8 },/* 13 */
{ -1, 11, 124, -6 },/* 14 */
{ 0, 5, 127, -4 } /* 15 */
}, { /* 65536 < Ratio <= 74898 (~8:7) */
{ 8, 112, 8, 0 },/* 0 */
{ 4, 111, 14, -1 },/* 1 */
{ 1, 109, 20, -2 },/* 2 */
{ -2, 105, 27, -2 },/* 3 */
{ -3, 100, 34, -3 },/* 4 */
{ -5, 93, 43, -3 },/* 5 */
{ -5, 86, 51, -4 },/* 6 */
{ -5, 77, 60, -4 },/* 7 */
{ -5, 69, 69, -5 },/* 8 */
{ -4, 60, 77, -5 },/* 9 */
{ -4, 51, 86, -5 },/* 10 */
{ -3, 43, 93, -5 },/* 11 */
{ -3, 34, 100, -3 },/* 12 */
{ -2, 27, 105, -2 },/* 13 */
{ -2, 20, 109, 1 },/* 14 */
{ -1, 14, 111, 4 } /* 15 */
}, { /* 74898 < Ratio <= 87381 (~8:6) */
{ 16, 96, 16, 0 },/* 0 */
{ 12, 97, 21, -2 },/* 1 */
{ 8, 96, 26, -2 },/* 2 */
{ 5, 93, 32, -2 },/* 3 */
{ 2, 89, 39, -2 },/* 4 */
{ 0, 84, 46, -2 },/* 5 */
{ -1, 79, 53, -3 },/* 6 */
{ -2, 73, 59, -2 },/* 7 */
{ -2, 66, 66, -2 },/* 8 */
{ -2, 59, 73, -2 },/* 9 */
{ -3, 53, 79, -1 },/* 10 */
{ -2, 46, 84, 0 },/* 11 */
{ -2, 39, 89, 2 },/* 12 */
{ -2, 32, 93, 5 },/* 13 */
{ -2, 26, 96, 8 },/* 14 */
{ -2, 21, 97, 12 } /* 15 */
}, { /* 87381 < Ratio <= 104857 (~8:5) */
{ 22, 84, 22, 0 },/* 0 */
{ 18, 85, 26, -1 },/* 1 */
{ 14, 84, 31, -1 },/* 2 */
{ 11, 82, 36, -1 },/* 3 */
{ 8, 79, 42, -1 },/* 4 */
{ 6, 76, 47, -1 },/* 5 */
{ 4, 72, 52, 0 },/* 6 */
{ 2, 68, 58, 0 },/* 7 */
{ 1, 63, 63, 1 },/* 8 */
{ 0, 58, 68, 2 },/* 9 */
{ 0, 52, 72, 4 },/* 10 */
{ -1, 47, 76, 6 },/* 11 */
{ -1, 42, 79, 8 },/* 12 */
{ -1, 36, 82, 11 },/* 13 */
{ -1, 31, 84, 14 },/* 14 */
{ -1, 26, 85, 18 } /* 15 */
}, { /* 104857 < Ratio <= 131072 (~8:4) */
{ 26, 76, 26, 0 },/* 0 */
{ 22, 76, 30, 0 },/* 1 */
{ 19, 75, 34, 0 },/* 2 */
{ 16, 73, 38, 1 },/* 3 */
{ 13, 71, 43, 1 },/* 4 */
{ 10, 69, 47, 2 },/* 5 */
{ 8, 66, 51, 3 },/* 6 */
{ 6, 63, 55, 4 },/* 7 */
{ 5, 59, 59, 5 },/* 8 */
{ 4, 55, 63, 6 },/* 9 */
{ 3, 51, 66, 8 },/* 10 */
{ 2, 47, 69, 10 },/* 11 */
{ 1, 43, 71, 13 },/* 12 */
{ 1, 38, 73, 16 },/* 13 */
{ 0, 34, 75, 19 },/* 14 */
{ 0, 30, 76, 22 } /* 15 */
}, { /* 131072 < Ratio <= 174762 (~8:3) */
{ 29, 70, 29, 0 },/* 0 */
{ 26, 68, 32, 2 },/* 1 */
{ 23, 67, 36, 2 },/* 2 */
{ 20, 66, 39, 3 },/* 3 */
{ 17, 65, 43, 3 },/* 4 */
{ 15, 63, 46, 4 },/* 5 */
{ 12, 61, 50, 5 },/* 6 */
{ 10, 58, 53, 7 },/* 7 */
{ 8, 56, 56, 8 },/* 8 */
{ 7, 53, 58, 10 },/* 9 */
{ 5, 50, 61, 12 },/* 10 */
{ 4, 46, 63, 15 },/* 11 */
{ 3, 43, 65, 17 },/* 12 */
{ 3, 39, 66, 20 },/* 13 */
{ 2, 36, 67, 23 },/* 14 */
{ 2, 32, 68, 26 } /* 15 */
}, { /* 174762 < Ratio <= 262144 (~8:2) */
{ 32, 64, 32, 0 },/* 0 */
{ 28, 63, 34, 3 },/* 1 */
{ 25, 62, 37, 4 },/* 2 */
{ 22, 62, 40, 4 },/* 3 */
{ 19, 61, 43, 5 },/* 4 */
{ 17, 59, 46, 6 },/* 5 */
{ 15, 58, 48, 7 },/* 6 */
{ 13, 55, 51, 9 },/* 7 */
{ 11, 53, 53, 11 },/* 8 */
{ 9, 51, 55, 13 },/* 9 */
{ 7, 48, 58, 15 },/* 10 */
{ 6, 46, 59, 17 },/* 11 */
{ 5, 43, 61, 19 },/* 12 */
{ 4, 40, 62, 22 },/* 13 */
{ 4, 37, 62, 25 },/* 14 */
{ 3, 34, 63, 28 } /* 15 */
}
};

View file

@ -0,0 +1,226 @@
/*
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Header file for Exynos VPP 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_VPP_COMMON_H__
#define ___SAMSUNG_VPP_COMMON_H__
#define YUV_SRC_OFFSET_MULTIPLE 2
#define YUV_SRC_SIZE_MULTIPLE 2
#define YUV_SRC_SIZE_MUL_HEIGHT 1
#define YUV_SRC_WIDTH_MAX 65534
#define YUV_SRC_HEIGHT_MAX 8190
#define YUV_SRC_WIDTH_MIN 32
#define YUV_SRC_HEIGHT_MIN 16
#define RGB_SRC_OFFSET_MULTIPLE 1
#define RGB_SRC_SIZE_MULTIPLE 1
#define RGB_SRC_WIDTH_MAX 65535
#define RGB_SRC_HEIGHT_MAX 8191
#define RGB_SRC_WIDTH_MIN 16
#define RGB_SRC_HEIGHT_MIN 8
#define ROT1_RGB_SRC_WIDTH_MIN 32
#define ROT1_RGB_SRC_HEIGHT_MIN 16
#define ROT1_YUV_SRC_WIDTH_MIN 64
#define ROT1_YUV_SRC_HEIGHT_MIN 32
#define ROT2_RGB_SRC_WIDTH_MIN 16
#define ROT2_RGB_SRC_HEIGHT_MIN 32
#define ROT2_YUV_SRC_WIDTH_MIN 32
#define ROT2_YUV_SRC_HEIGHT_MIN 64
#define YUV_IMG_SIZE_MULTIPLE 2
#define RGB_IMG_SIZE_MULTIPLE 1
#define IMG_WIDTH_MAX 4096
#define IMG_HEIGHT_MAX 4096
#define RGB_IMG_WIDTH_MIN 16
#define RGB_IMG_HEIGHT_MIN 8
#define YUV_IMG_WIDTH_MIN 32
#define YUV_IMG_HEIGHT_MIN 16
#define IMG_SIZE_MULTIPLE 2
#define ROT1_RGB_IMG_WIDTH_MIN 32
#define ROT1_RGB_IMG_HEIGHT_MIN 16
#define ROT1_YUV_IMG_WIDTH_MIN 64
#define ROT1_YUV_IMG_HEIGHT_MIN 32
#define ROT2_RGB_IMG_WIDTH_MIN 16
#define ROT2_RGB_IMG_HEIGHT_MIN 32
#define ROT2_YUV_IMG_WIDTH_MIN 32
#define ROT2_YUV_IMG_HEIGHT_MIN 64
#define ROT3_RGB_IMG_WIDTH_MAX 4096
#define ROT3_RGB_IMG_HEIGHT_MAX 4096
#define ROT3_YUV_IMG_WIDTH_MAX 4096
#define ROT3_YUV_IMG_HEIGHT_MAX 4096
#define ROT4_RGB_IMG_WIDTH_MAX 2048
#define ROT4_RGB_IMG_HEIGHT_MAX 2048
#define ROT4_YUV_IMG_WIDTH_MAX 2048
#define ROT4_YUV_IMG_HEIGHT_MAX 2048
#define BLK_WIDTH_MAX 4096
#define BLK_HEIGHT_MAX 4096
#define BLK_WIDTH_MIN 144
#define BLK_HEIGHT_MIN 10
#define ROT3_RGB_BLK_WIDTH_MAX 4096
#define ROT3_RGB_BLK_HEIGHT_MAX 4096
#define ROT3_RGB_BLK_WIDTH_MIN 128
#define ROT3_RGB_BLK_HEIGHT_MIN 16
#define ROT4_RGB_BLK_WIDTH_MAX 2048
#define ROT4_RGB_BLK_HEIGHT_MAX 2048
#define SCALED_SIZE_MULTIPLE 1
#define SCALED_WIDTH_MAX 4096
#define SCALED_HEIGHT_MAX 4096
#define SCALED_WIDTH_MIN 16
#define SCALED_HEIGHT_MIN 8
#define PRE_RGB_WIDTH 1
#define PRE_RGB_HEIGHT 1
#define PRE_YUV_WIDTH 2
#define PRE_YUV_HEIGHT 2
#define PRE_ROT1_YUV_HEIGHT 1
#define PRE12_RGB_WIDTH 2
#define PRE12_RGB_HEIGHT 2
#define PRE12_YUV_WIDTH 4
#define PRE12_ROT1_YUV_HEIGHT 2
#define PRE12_YUV_HEIGHT 4
#define PRE14_RGB_WIDTH 4
#define PRE14_RGB_HEIGHT 4
#define PRE14_YUV_WIDTH 8
#define PRE14_YUV_HEIGHT 8
#define PRE14_ROT1_YUV_HEIGHT 4
#define SRC_SIZE_MULTIPLE 2
#define SRC_ROT1_MUL_Y 1
#define SRC_ROT2_MUL_Y 2
#define DST_SIZE_MULTIPLE 1
#define DST_SIZE_WIDTH_MIN 16
#define DST_SIZE_WIDTH_MAX 8191
#define DST_SIZE_HEIGHT_MIN 8
#define DST_SIZE_HEIGHT_MAX 8191
#define DST_OFFSET_MULTIPLE 1
#define DST_IMGAGE_MULTIPLE 1
#define DST_IMG_WIDTH_MIN 16
#define DST_IMG_HEIGHT_MIN 8
#define DST_IMG_MAX 4096
struct vpp_size_constraints {
u32 src_mul_w;
u32 src_mul_h;
u32 src_w_min;
u32 src_w_max;
u32 src_h_min;
u32 src_h_max;
u32 img_mul_w;
u32 img_mul_h;
u32 img_w_min;
u32 img_w_max;
u32 img_h_min;
u32 img_h_max;
u32 blk_w_min;
u32 blk_w_max;
u32 blk_h_min;
u32 blk_h_max;
u32 blk_mul_w;
u32 blk_mul_h;
u32 src_mul_x;
u32 src_mul_y;
u32 sca_w_min;
u32 sca_w_max;
u32 sca_h_min;
u32 sca_h_max;
u32 sca_mul_w;
u32 sca_mul_h;
u32 dst_mul_w;
u32 dst_mul_h;
u32 dst_w_min;
u32 dst_w_max;
u32 dst_h_min;
u32 dst_h_max;
u32 dst_mul_x;
u32 dst_mul_y;
};
struct vpp_img_format {
u32 vgr;
u32 normal;
u32 pre_none;
u32 pre_12;
u32 pre_14;
u32 rot;
u32 scale;
u32 yuv;
u32 yuv422;
u32 yuv420;
u32 wb;
};
struct vpp_size_param {
u32 src_x;
u32 src_y;
u32 src_fw;
u32 src_fh;
u32 src_w;
u32 src_h;
u32 dst_w;
u32 dst_h;
u32 fr_w;
u32 fr_h;
u32 fr_yx;
u32 fr_yy;
u32 fr_cx;
u32 fr_cy;
u32 vpp_h_ratio;
u32 vpp_v_ratio;
u32 rot;
u32 block_w;
u32 block_h;
u32 block_x;
u32 block_y;
u64 addr0;
u64 addr1;
u64 addr2;
};
/* CAL APIs list */
void vpp_reg_set_realtime_path(u32 id);
void vpp_reg_set_framedone_irq(u32 id, u32 enable);
void vpp_reg_set_deadlock_irq(u32 id, u32 enable);
void vpp_reg_set_read_slave_err_irq(u32 id, u32 enable);
void vpp_reg_set_sfr_update_done_irq(u32 id, u32 enable);
void vpp_reg_set_hw_reset_done_mask(u32 id, u32 enable);
void vpp_reg_set_lookup_table(u32 id);
void vpp_reg_set_enable_interrupt(u32 id);
void vpp_reg_set_rgb_type(u32 id, u32 type);
void vpp_reg_set_dynamic_clock_gating(u32 id);
void vpp_reg_set_plane_alpha_fixed(u32 id);
/* CAL raw functions list */
int vpp_reg_set_sw_reset(u32 id);
void vpp_reg_set_in_size(u32 id, struct vpp_size_param *p);
void vpp_reg_set_out_size(u32 id, u32 dst_w, u32 dst_h);
void vpp_reg_set_scale_ratio(u32 id, struct vpp_size_param *p, u32 rot_en);
int vpp_reg_set_in_format(u32 id, u32 format, struct vpp_img_format *vi);
void vpp_reg_set_in_block_size(u32 id, u32 enable, struct vpp_size_param *p);
void vpp_reg_set_in_buf_addr(u32 id, struct vpp_size_param *p);
void vpp_reg_set_smart_if_pix_num(u32 id, u32 dst_w, u32 dst_h);
void vpp_reg_set_sfr_update_force(u32 id);
int vpp_reg_wait_op_status(u32 id);
int vpp_reg_set_rotation(u32 id, struct vpp_size_param *p);
void vpp_reg_set_plane_alpha(u32 id, u32 plane_alpha);
void vpp_reg_wait_idle(u32 id);
int vpp_reg_get_irq_status(u32 id);
void vpp_reg_set_clear_irq(u32 id, u32 irq);
void vpp_constraints_params(struct vpp_size_constraints *vc, struct vpp_img_format *vi);
void vpp_reg_init(u32 id);
void vpp_reg_deinit(u32 id, u32 reset_en);
void vpp_reg_wait_pingpong_clear(u32 id);
#endif /* ___SAMSUNG_VPP_COMMON_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,671 @@
/* linux/drivers/video/exynos/decon/vpp/vpp_regs.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Samsung EXYNOS5 SoC series G-scaler driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 2 of the License,
* or (at your option) any later version.
*/
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/ktime.h>
#include "vpp.h"
#include "vpp_common.h"
#include "vpp_coef.h"
#define VPP_SC_RATIO_MAX ((1 << 20) * 8 / 8)
#define VPP_SC_RATIO_7_8 ((1 << 20) * 8 / 7)
#define VPP_SC_RATIO_6_8 ((1 << 20) * 8 / 6)
#define VPP_SC_RATIO_5_8 ((1 << 20) * 8 / 5)
#define VPP_SC_RATIO_4_8 ((1 << 20) * 8 / 4)
#define VPP_SC_RATIO_3_8 ((1 << 20) * 8 / 3)
int vpp_reg_wait_op_status(u32 id)
{
u32 cfg = 0;
unsigned long cnt = 100000;
do {
cfg = vpp_read(id, VG_ENABLE);
if (!(cfg & (VG_ENABLE_OP_STATUS)))
return 0;
udelay(10);
} while (--cnt);
vpp_err("timeout op_status to idle\n");
return -EBUSY;
}
void vpp_reg_wait_idle(u32 id)
{
u32 cfg = 0;
unsigned long cnt = 100000;
do {
cfg = vpp_read(id, VG_ENABLE);
if (!(cfg & (VG_ENABLE_OP_STATUS)))
return;
vpp_info("vpp%d is operating...\n", id);
udelay(10);
} while (--cnt);
vpp_err("timeout op_status to idle\n");
}
int vpp_reg_set_sw_reset(u32 id)
{
u32 cfg = 0;
unsigned long cnt = 100000;
vpp_write_mask(id, VG_ENABLE, ~0, VG_ENABLE_SRESET);
do {
cfg = vpp_read(id, VG_ENABLE);
if (!(cfg & (VG_ENABLE_SRESET)))
return 0;
udelay(10);
} while (--cnt);
vpp_err("timeout sw reset\n");
return -EBUSY;
}
void vpp_reg_wait_pingpong_clear(u32 id)
{
u32 cfg = 0;
unsigned long cnt = 1700;
do {
cfg = vpp_read(id, VG_PINGPONG_UPDATE);
if (!(cfg & (VG_ADDR_PINGPONG_UPDATE)))
return;
udelay(10);
} while (--cnt);
vpp_err("timeout of VPP(%d) pingpong_clear\n", id);
}
void vpp_reg_set_realtime_path(u32 id)
{
vpp_write_mask(id, VG_ENABLE, ~0, VG_ENABLE_RT_PATH_EN);
}
void vpp_reg_set_framedone_irq(u32 id, u32 enable)
{
u32 val = enable ? ~0 : 0;
vpp_write_mask(id, VG_IRQ, val, VG_IRQ_FRAMEDONE_MASK);
}
void vpp_reg_set_deadlock_irq(u32 id, u32 enable)
{
u32 val = enable ? ~0 : 0;
vpp_write_mask(id, VG_IRQ, val, VG_IRQ_DEADLOCK_STATUS_MASK);
}
void vpp_reg_set_read_slave_err_irq(u32 id, u32 enable)
{
u32 val = enable ? ~0 : 0;
vpp_write_mask(id, VG_IRQ, val, VG_IRQ_READ_SLAVE_ERROR_MASK);
}
void vpp_reg_set_sfr_update_done_irq(u32 id, u32 enable)
{
u32 val = enable ? ~0 : 0;
vpp_write_mask(id, VG_IRQ, val, VG_IRQ_SFR_UPDATE_DONE_MASK);
}
void vpp_reg_set_sfr_update_force(u32 id)
{
vpp_write_mask(id, VG_ENABLE, ~0, VG_ENABLE_SFR_UPDATE_FORCE);
}
void vpp_reg_set_enable_interrupt(u32 id)
{
vpp_write_mask(id, VG_IRQ, ~0, VG_IRQ_ENABLE);
}
void vpp_reg_set_hw_reset_done_mask(u32 id, u32 enable)
{
u32 val = enable ? ~0 : 0;
vpp_write_mask(id, VG_IRQ, val, VG_IRQ_HW_RESET_DONE_MASK);
}
int vpp_reg_set_in_format(u32 id, u32 format, struct vpp_img_format *vi)
{
u32 cfg = vpp_read(id, VG_IN_CON);
cfg &= ~(VG_IN_CON_IMG_FORMAT_MASK |
VG_IN_CON_CHROMINANCE_STRIDE_EN);
if ((id == 0 || id == 1 || id == 4 || id == 5) &&
(format >= DECON_PIXEL_FORMAT_NV16)) {
vpp_err("Unsupported YUV format in G%d \n", id);
return -EINVAL;
}
if (!vi->vgr && (vi->scale || vi->rot)) {
vpp_err("Unsupported Scailing in (V)G%d \n", id);
return -EINVAL;
}
switch (format) {
case DECON_PIXEL_FORMAT_ARGB_8888:
cfg |= VG_IN_CON_IMG_FORMAT_ARGB8888;
break;
case DECON_PIXEL_FORMAT_ABGR_8888:
cfg |= VG_IN_CON_IMG_FORMAT_ABGR8888;
break;
case DECON_PIXEL_FORMAT_RGBA_8888:
cfg |= VG_IN_CON_IMG_FORMAT_RGBA8888;
break;
case DECON_PIXEL_FORMAT_BGRA_8888:
cfg |= VG_IN_CON_IMG_FORMAT_BGRA8888;
break;
case DECON_PIXEL_FORMAT_XRGB_8888:
cfg |= VG_IN_CON_IMG_FORMAT_XRGB8888;
break;
case DECON_PIXEL_FORMAT_XBGR_8888:
cfg |= VG_IN_CON_IMG_FORMAT_XBGR8888;
break;
case DECON_PIXEL_FORMAT_RGBX_8888:
cfg |= VG_IN_CON_IMG_FORMAT_RGBX8888;
break;
case DECON_PIXEL_FORMAT_BGRX_8888:
cfg |= VG_IN_CON_IMG_FORMAT_BGRX8888;
break;
case DECON_PIXEL_FORMAT_RGB_565:
cfg |= VG_IN_CON_IMG_FORMAT_RGB565;
break;
case DECON_PIXEL_FORMAT_NV16:
cfg |= VG_IN_CON_IMG_FORMAT_YUV422_2P;
break;
case DECON_PIXEL_FORMAT_NV61:
cfg |= VG_IN_CON_IMG_FORMAT_YVU422_2P;
break;
case DECON_PIXEL_FORMAT_NV12:
case DECON_PIXEL_FORMAT_NV12M:
cfg |= VG_IN_CON_IMG_FORMAT_YUV420_2P;
break;
case DECON_PIXEL_FORMAT_NV21:
case DECON_PIXEL_FORMAT_NV21M:
cfg |= VG_IN_CON_IMG_FORMAT_YVU420_2P;
break;
default:
vpp_err("Unsupported Format\n");
return -EINVAL;
}
vpp_write(id, VG_IN_CON, cfg);
return 0;
}
void vpp_reg_set_h_coef(u32 id, u32 h_ratio)
{
int i, j, k, sc_ratio;
if (h_ratio <= VPP_SC_RATIO_MAX)
sc_ratio = 0;
else if (h_ratio <= VPP_SC_RATIO_7_8)
sc_ratio = 1;
else if (h_ratio <= VPP_SC_RATIO_6_8)
sc_ratio = 2;
else if (h_ratio <= VPP_SC_RATIO_5_8)
sc_ratio = 3;
else if (h_ratio <= VPP_SC_RATIO_4_8)
sc_ratio = 4;
else if (h_ratio <= VPP_SC_RATIO_3_8)
sc_ratio = 5;
else
sc_ratio = 6;
for (i = 0; i < 9; i++) {
for (j = 0; j < 8; j++) {
for (k = 0; k < 2; k++) {
vpp_write(id, VG_H_COEF(i, j, k),
h_coef_8t[sc_ratio][i][j]);
}
}
}
}
void vpp_reg_set_v_coef(u32 id, u32 v_ratio)
{
int i, j, k, sc_ratio;
if (v_ratio <= VPP_SC_RATIO_MAX)
sc_ratio = 0;
else if (v_ratio <= VPP_SC_RATIO_7_8)
sc_ratio = 1;
else if (v_ratio <= VPP_SC_RATIO_6_8)
sc_ratio = 2;
else if (v_ratio <= VPP_SC_RATIO_5_8)
sc_ratio = 3;
else if (v_ratio <= VPP_SC_RATIO_4_8)
sc_ratio = 4;
else if (v_ratio <= VPP_SC_RATIO_3_8)
sc_ratio = 5;
else
sc_ratio = 6;
for (i = 0; i < 9; i++) {
for (j = 0; j < 4; j++) {
for (k = 0; k < 2; k++) {
vpp_write(id, VG_V_COEF(i, j, k),
v_coef_4t[sc_ratio][i][j]);
}
}
}
}
int vpp_reg_set_rotation(u32 id, struct vpp_size_param *p)
{
vpp_write_mask(id, VG_IN_CON, p->rot << 8, VG_IN_CON_IN_ROTATION_MASK);
return 0;
}
void vpp_reg_set_scale_ratio(u32 id, struct vpp_size_param *p, u32 rot_en)
{
u32 h_ratio, v_ratio = 0;
u32 tmp_width, tmp_height = 0;
u32 tmp_fr_w, tmp_fr_h = 0;
if (rot_en) {
tmp_width = p->src_h;
tmp_height = p->src_w;
tmp_fr_w = p->fr_h;
tmp_fr_h = p->fr_w;
} else {
tmp_width = p->src_w;
tmp_height = p->src_h;
tmp_fr_w = p->fr_w;
tmp_fr_h = p->fr_h;
}
h_ratio = ((tmp_width << 20) + tmp_fr_w) / p->dst_w;
v_ratio = ((tmp_height << 20) + tmp_fr_h) / p->dst_h;
if (p->vpp_h_ratio != h_ratio) {
vpp_write(id, VG_H_RATIO, h_ratio);
vpp_reg_set_h_coef(id, h_ratio);
}
if (p->vpp_v_ratio != v_ratio) {
vpp_write(id, VG_V_RATIO, v_ratio);
vpp_reg_set_v_coef(id, v_ratio);
}
p->vpp_h_ratio = h_ratio;
p->vpp_v_ratio = v_ratio;
vpp_dbg("h_ratio : %#x, v_ratio : %#x\n", p->vpp_h_ratio, p->vpp_v_ratio);
}
void vpp_reg_set_in_buf_addr(u32 id, struct vpp_size_param *p)
{
vpp_dbg("y : %llu, cb : %llu, cr : %llu\n", p->addr0, p->addr1, p->addr2);
vpp_write(id, VG_BASE_ADDR_Y(0), p->addr0);
vpp_write(id, VG_BASE_ADDR_CB(0), p->addr1);
vpp_write(id, VG_PINGPONG_UPDATE, VG_ADDR_PINGPONG_UPDATE);
}
void vpp_reg_set_in_size(u32 id, struct vpp_size_param *p)
{
u32 cfg = 0;
/* source offset */
cfg = VG_SRC_OFFSET_X(p->src_x) | VG_SRC_OFFSET_Y(p->src_y);
vpp_write(id, VG_SRC_OFFSET, cfg);
/* source full(alloc) size */
cfg = VG_SRC_SIZE_WIDTH(p->src_fw) | VG_SRC_SIZE_HEIGHT(p->src_fh);
vpp_write(id, VG_SRC_SIZE, cfg);
/* source cropped size */
cfg = VG_IMG_SIZE_WIDTH(p->src_w) | VG_IMG_SIZE_HEIGHT(p->src_h);
vpp_write(id, VG_IMG_SIZE, cfg);
if (p->fr_w)
p->src_w--;
if (p->fr_h)
p->src_h--;
/* fraction position */
vpp_write(id, VG_YHPOSITION0, p->fr_yx);
vpp_write(id, VG_YVPOSITION0, p->fr_yy);
vpp_write(id, VG_CHPOSITION0, p->fr_cx);
vpp_write(id, VG_CVPOSITION0, p->fr_cy);
}
void vpp_reg_set_in_block_size(u32 id, u32 enable, struct vpp_size_param *p)
{
u32 cfg = 0;
if (!enable) {
vpp_write_mask(id, VG_IN_CON, 0, VG_IN_CON_BLOCKING_FEATURE_EN);
return;
}
/* blocking area offset */
cfg = VG_BLK_OFFSET_X(p->block_x) | VG_BLK_OFFSET_Y(p->block_y);
vpp_write(id, VG_BLK_OFFSET, cfg);
/* blocking area size */
cfg = VG_BLK_SIZE_WIDTH(p->block_w) | VG_BLK_SIZE_HEIGHT(p->block_h);
vpp_write(id, VG_BLK_SIZE, cfg);
vpp_write_mask(id, VG_IN_CON, ~0, VG_IN_CON_BLOCKING_FEATURE_EN);
vpp_dbg("block x : %d, y : %d, w : %d, h : %d\n",
p->block_x, p->block_y, p->block_w, p->block_h);
}
void vpp_reg_set_out_size(u32 id, u32 dst_w, u32 dst_h)
{
u32 cfg = 0;
/* destination scaled size */
cfg = VG_SCALED_SIZE_WIDTH(dst_w) | VG_SCALED_SIZE_HEIGHT(dst_h);
vpp_write(id, VG_SCALED_SIZE, cfg);
}
void vpp_reg_set_rgb_type(u32 id, u32 type)
{
u32 csc_eq = 0;
switch (type) {
case BT_601_NARROW:
csc_eq = VG_OUT_CON_RGB_TYPE_601_NARROW;
break;
case BT_601_WIDE:
csc_eq = VG_OUT_CON_RGB_TYPE_601_WIDE;
break;
case BT_709_NARROW:
csc_eq = VG_OUT_CON_RGB_TYPE_709_NARROW;
break;
case BT_709_WIDE:
csc_eq = VG_OUT_CON_RGB_TYPE_709_WIDE;
break;
default:
vpp_err("Unsupported CSC Equation\n");
}
vpp_write(id, VG_OUT_CON, csc_eq);
}
void vpp_reg_set_plane_alpha(u32 id, u32 plane_alpha)
{
if (plane_alpha > 0xFF)
vpp_info("%d is too much value\n", plane_alpha);
vpp_write_mask(id, VG_OUT_CON, VG_OUT_CON_FRAME_ALPHA(plane_alpha),
VG_OUT_CON_FRAME_ALPHA_MASK);
}
void vpp_reg_set_plane_alpha_fixed(u32 id)
{
vpp_write_mask(id, VG_OUT_CON, VG_OUT_CON_FRAME_ALPHA(0xFF),
VG_OUT_CON_FRAME_ALPHA_MASK);
}
void vpp_reg_set_smart_if_pix_num(u32 id, u32 dst_w, u32 dst_h)
{
vpp_write(id, VG_SMART_IF_PIXEL_NUM, dst_w * dst_h);
}
void vpp_reg_set_lookup_table(u32 id)
{
vpp_write(id, VG_QOS_LUT07_00, 0x44444444);
vpp_write(id, VG_QOS_LUT15_08, 0x44444444);
}
void vpp_reg_set_dynamic_clock_gating(u32 id)
{
vpp_write(id, VG_DYNAMIC_GATING_ENABLE, 0x3F);
}
int vpp_reg_get_irq_status(u32 id)
{
u32 cfg = vpp_read(id, VG_IRQ);
cfg &= (VG_IRQ_SFR_UPDATE_DONE | VG_IRQ_HW_RESET_DONE |
VG_IRQ_READ_SLAVE_ERROR | VG_IRQ_DEADLOCK_STATUS |
VG_IRQ_FRAMEDONE);
return cfg;
}
void vpp_reg_set_clear_irq(u32 id, u32 irq)
{
vpp_write_mask(id, VG_IRQ, ~0, irq);
}
void vpp_constraints_params(struct vpp_size_constraints *vc, struct vpp_img_format *vi)
{
if (!vi->wb) {
if (!vi->vgr) {
if (vi->yuv) {
vc->src_mul_w = YUV_SRC_SIZE_MULTIPLE;
vc->src_mul_h = YUV_SRC_SIZE_MULTIPLE;
vc->src_w_min = YUV_SRC_WIDTH_MIN;
vc->src_w_max = YUV_SRC_WIDTH_MAX;
vc->src_h_min = YUV_SRC_HEIGHT_MIN;
vc->src_h_max = YUV_SRC_HEIGHT_MAX;
vc->img_mul_w = YUV_IMG_SIZE_MULTIPLE;
vc->img_mul_h = YUV_IMG_SIZE_MULTIPLE;
vc->img_w_min = YUV_IMG_WIDTH_MIN;
vc->img_w_max = IMG_WIDTH_MAX;
vc->img_h_min = YUV_IMG_HEIGHT_MIN;
vc->img_h_max = IMG_WIDTH_MAX;
vc->src_mul_x = YUV_SRC_OFFSET_MULTIPLE;
vc->src_mul_y = YUV_SRC_OFFSET_MULTIPLE;
vc->sca_w_min = SCALED_WIDTH_MIN;
vc->sca_w_max = SCALED_WIDTH_MAX;
vc->sca_h_min = SCALED_HEIGHT_MIN;
vc->sca_h_max = SCALED_HEIGHT_MAX;
vc->sca_mul_w = SCALED_SIZE_MULTIPLE;
vc->sca_mul_h = SCALED_SIZE_MULTIPLE;
} else {
vc->src_mul_w = RGB_SRC_SIZE_MULTIPLE;
vc->src_mul_h = RGB_SRC_SIZE_MULTIPLE;
vc->src_w_min = RGB_SRC_WIDTH_MIN;
vc->src_w_max = RGB_SRC_WIDTH_MAX;
vc->src_h_min = RGB_SRC_HEIGHT_MIN;
vc->src_h_max = RGB_SRC_HEIGHT_MAX;
vc->img_mul_w = RGB_IMG_SIZE_MULTIPLE;
vc->img_mul_h = RGB_IMG_SIZE_MULTIPLE;
vc->img_w_min = RGB_IMG_WIDTH_MIN;
vc->img_w_max = IMG_WIDTH_MAX;
vc->img_h_min = RGB_IMG_HEIGHT_MIN;
vc->img_h_max = IMG_WIDTH_MAX;
vc->src_mul_x = RGB_SRC_OFFSET_MULTIPLE;
vc->src_mul_y = RGB_SRC_OFFSET_MULTIPLE;
vc->sca_w_min = SCALED_WIDTH_MIN;
vc->sca_w_max = SCALED_WIDTH_MAX;
vc->sca_h_min = SCALED_HEIGHT_MIN;
vc->sca_h_max = SCALED_HEIGHT_MAX;
vc->sca_mul_w = SCALED_SIZE_MULTIPLE;
vc->sca_mul_h = SCALED_SIZE_MULTIPLE;
}
} else {
if (!vi->yuv) {
vc->src_mul_w = RGB_SRC_SIZE_MULTIPLE;
vc->src_mul_h = RGB_SRC_SIZE_MULTIPLE;
vc->src_w_max = RGB_SRC_WIDTH_MAX;
vc->src_h_max = RGB_SRC_HEIGHT_MAX;
vc->sca_w_min = SCALED_WIDTH_MIN;
vc->sca_w_max = SCALED_WIDTH_MAX;
vc->sca_h_min = SCALED_HEIGHT_MIN;
vc->sca_h_max = SCALED_HEIGHT_MAX;
vc->src_mul_x = RGB_SRC_OFFSET_MULTIPLE;
vc->src_mul_y = RGB_SRC_OFFSET_MULTIPLE;
vc->sca_mul_w = SCALED_SIZE_MULTIPLE;
if (vi->pre_none) {
vc->img_mul_w = PRE_RGB_WIDTH;
vc->img_mul_h = PRE_RGB_HEIGHT;
} else if (vi->pre_12) {
vc->img_mul_w = PRE12_RGB_WIDTH;
vc->img_mul_h = PRE12_RGB_HEIGHT;
} else if (vi->pre_14) {
vc->img_mul_w = PRE14_RGB_WIDTH;
vc->img_mul_h = PRE14_RGB_HEIGHT;
}
if (!vi->rot) {
vc->src_w_min = ROT1_RGB_SRC_WIDTH_MIN;
vc->src_h_min = ROT1_RGB_SRC_HEIGHT_MIN;
vc->img_w_min = ROT1_RGB_IMG_WIDTH_MIN;
vc->img_h_min = ROT1_RGB_IMG_HEIGHT_MIN;
vc->sca_mul_h = SCALED_SIZE_MULTIPLE;
} else {
vc->src_w_min = ROT2_RGB_SRC_WIDTH_MIN;
vc->src_h_min = ROT2_RGB_SRC_HEIGHT_MIN;
vc->img_w_min = ROT2_RGB_IMG_WIDTH_MIN;
vc->img_h_min = ROT2_RGB_IMG_HEIGHT_MIN;
vc->sca_mul_h = SCALED_SIZE_MULTIPLE;
}
if (vi->normal) {
vc->img_w_max = ROT3_RGB_IMG_WIDTH_MAX;
vc->img_h_max = ROT3_RGB_IMG_HEIGHT_MAX;
} else {
vc->img_w_max = ROT4_RGB_IMG_WIDTH_MAX;
vc->img_h_max = ROT4_RGB_IMG_HEIGHT_MAX;
vc->blk_w_min = ROT3_RGB_BLK_WIDTH_MIN;
vc->blk_w_max = ROT3_RGB_BLK_WIDTH_MAX;
vc->blk_h_min = ROT3_RGB_BLK_HEIGHT_MIN;
vc->blk_h_max = ROT3_RGB_BLK_HEIGHT_MAX;
}
} else {
vc->src_mul_w = YUV_SRC_SIZE_MULTIPLE;
vc->src_w_max = YUV_SRC_WIDTH_MAX;
vc->src_h_max = YUV_SRC_HEIGHT_MAX;
vc->sca_w_min = SCALED_WIDTH_MIN;
vc->sca_w_max = SCALED_WIDTH_MAX;
vc->sca_h_min = SCALED_HEIGHT_MIN;
vc->sca_h_max = SCALED_HEIGHT_MAX;
vc->src_mul_x = SRC_SIZE_MULTIPLE;
vc->sca_mul_w = SCALED_SIZE_MULTIPLE;
if (!vi->rot) {
vc->src_w_min = ROT1_YUV_SRC_WIDTH_MIN;
vc->src_h_min = ROT1_YUV_SRC_HEIGHT_MIN;
vc->img_w_min = ROT1_YUV_IMG_WIDTH_MIN;
vc->img_h_min = ROT1_YUV_IMG_HEIGHT_MIN;
} else {
vc->src_w_min = ROT2_YUV_SRC_WIDTH_MIN;
vc->src_h_min = ROT2_YUV_SRC_HEIGHT_MIN;
vc->img_w_min = ROT2_YUV_IMG_WIDTH_MIN;
vc->img_h_min = ROT2_YUV_IMG_HEIGHT_MIN;
}
if (vi->normal) {
vc->img_w_max = ROT3_YUV_IMG_WIDTH_MAX;
vc->img_h_max = ROT3_YUV_IMG_HEIGHT_MAX;
} else {
vc->img_w_max = ROT4_YUV_IMG_WIDTH_MAX;
vc->img_h_max = ROT4_YUV_IMG_HEIGHT_MAX;
}
if (vi->yuv422) {
vc->src_mul_h = YUV_SRC_SIZE_MUL_HEIGHT;
if (vi->pre_none) {
vc->img_mul_w = PRE_YUV_WIDTH;
if (!vi->rot)
vc->img_mul_h = PRE_ROT1_YUV_HEIGHT;
else
vc->img_mul_h = PRE_YUV_HEIGHT;
} else if (vi->pre_12) {
vc->img_mul_w = PRE12_YUV_WIDTH;
if (!vi->rot)
vc->img_mul_h = PRE12_ROT1_YUV_HEIGHT;
else
vc->img_mul_h = PRE12_YUV_HEIGHT;
} else if (vi->pre_14) {
vc->img_mul_w = PRE14_YUV_WIDTH;
if (!vi->rot) {
vc->img_mul_h = PRE14_ROT1_YUV_HEIGHT;
} else {
vc->img_mul_h = PRE14_YUV_HEIGHT;
}
}
if (!vi->rot) {
vc->src_mul_y = SRC_ROT2_MUL_Y;
vc->sca_mul_h = SCALED_SIZE_MULTIPLE;
} else {
vc->src_mul_y = SRC_ROT1_MUL_Y;
vc->sca_mul_h = SCALED_SIZE_MULTIPLE;
}
} else {
vc->src_mul_h = YUV_SRC_SIZE_MULTIPLE;
vc->src_mul_y = YUV_SRC_OFFSET_MULTIPLE;
vc->sca_mul_h = SCALED_SIZE_MULTIPLE;
if (vi->pre_none) {
vc->img_mul_w = PRE_YUV_WIDTH;
vc->img_mul_h = PRE_YUV_HEIGHT;
} else if (vi->pre_12) {
vc->img_mul_w = PRE12_YUV_WIDTH;
vc->img_mul_h = PRE12_YUV_HEIGHT;
} else if (vi->pre_14) {
vc->img_mul_w = PRE14_YUV_WIDTH;
vc->img_mul_h = PRE14_YUV_HEIGHT;
}
}
}
}
} else { /* write-back case */
vc->src_mul_w = DST_SIZE_MULTIPLE;
vc->src_mul_h = DST_SIZE_MULTIPLE;
vc->src_w_min = DST_SIZE_WIDTH_MIN;
vc->src_w_max = DST_SIZE_WIDTH_MAX;
vc->src_h_min = DST_SIZE_HEIGHT_MIN;
vc->src_h_max = DST_SIZE_HEIGHT_MAX;
vc->img_mul_w = DST_IMGAGE_MULTIPLE;
vc->img_mul_h = DST_IMGAGE_MULTIPLE;
vc->img_w_min = DST_IMG_WIDTH_MIN;
vc->img_w_max = DST_IMG_MAX;
vc->img_h_min = DST_IMG_HEIGHT_MIN;
vc->img_h_max = DST_IMG_MAX;
vc->sca_w_min = DST_SIZE_WIDTH_MIN;
vc->sca_w_max = DST_SIZE_WIDTH_MAX;
vc->sca_h_min = DST_SIZE_HEIGHT_MIN;
vc->sca_h_max = DST_SIZE_HEIGHT_MAX;
vc->src_mul_x = DST_OFFSET_MULTIPLE;
vc->src_mul_y = DST_OFFSET_MULTIPLE;
vc->sca_mul_w = DST_OFFSET_MULTIPLE;
vc->sca_mul_h = DST_OFFSET_MULTIPLE;
}
}
void vpp_reg_init(u32 id)
{
vpp_reg_set_realtime_path(id);
vpp_reg_set_framedone_irq(id, false);
vpp_reg_set_deadlock_irq(id, false);
vpp_reg_set_read_slave_err_irq(id, false);
vpp_reg_set_hw_reset_done_mask(id, false);
vpp_reg_set_sfr_update_done_irq(id, false);
vpp_reg_set_enable_interrupt(id);
vpp_reg_set_lookup_table(id);
vpp_reg_set_dynamic_clock_gating(id);
vpp_reg_set_plane_alpha_fixed(id);
}
void vpp_reg_deinit(u32 id, u32 reset_en)
{
unsigned int vpp_irq = 0;
vpp_irq = vpp_reg_get_irq_status(id);
vpp_reg_set_clear_irq(id, vpp_irq);
vpp_reg_set_framedone_irq(id, true);
vpp_reg_set_deadlock_irq(id, true);
vpp_reg_set_read_slave_err_irq(id, true);
vpp_reg_set_hw_reset_done_mask(id, true);
vpp_reg_set_sfr_update_done_irq(id, true);
if (reset_en)
vpp_reg_set_sw_reset(id);
}