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,36 @@
#
# Exynos Video configuration
#
menuconfig EXYNOS_VIDEO
bool "Exynos Video driver support"
depends on ARCH_S5PV210 || ARCH_EXYNOS
help
This enables support for EXYNOS Video device.
if EXYNOS_VIDEO
#
# MIPI DSI driver
#
config EXYNOS_MIPI_DSI
bool "EXYNOS MIPI DSI driver support."
select GENERIC_PHY
help
This enables support for MIPI-DSI device.
config EXYNOS_LCD_S6E8AX0
bool "S6E8AX0 MIPI AMOLED LCD Driver"
depends on EXYNOS_MIPI_DSI && BACKLIGHT_CLASS_DEVICE
depends on (LCD_CLASS_DEVICE = y)
default n
help
If you have an S6E8AX0 MIPI AMOLED LCD Panel, say Y to enable its
LCD control driver.
if SOC_EXYNOS7570
source "drivers/video/fbdev/exynos/decon_7570/Kconfig"
endif # SOC_EXYNOS7570
endif # EXYNOS_VIDEO

View file

@ -0,0 +1,8 @@
#
# Makefile for the exynos video drivers.
#
obj-$(CONFIG_EXYNOS_MIPI_DSI) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
exynos_mipi_dsi_lowlevel.o
obj-$(CONFIG_EXYNOS_LCD_S6E8AX0) += s6e8ax0.o
obj-$(CONFIG_EXYNOS_DECON_7570) += decon_7570/

View file

@ -0,0 +1,105 @@
config EXYNOS_DECON_7570
bool "Samsung Exynos7570 Display system (DECON, MIPI)"
depends on FB
choice
prompt "Select Display Operation Mode"
depends on EXYNOS_DECON_7570
default EXYNOS7570_DISPLAY_VIDEO_MODE
help
Select the display operation mode (Command/Video).
config EXYNOS7570_DISPLAY_COMMAND_MODE
bool "Command Mode"
config EXYNOS7570_DISPLAY_VIDEO_MODE
bool "Video Mode"
endchoice
choice
prompt "Select TE IRQ Mode"
depends on EXYNOS_DECON_7570 && EXYNOS7570_DISPLAY_COMMAND_MODE
default EXYNOS7570_DISPLAY_TE_IRQ_GPIO
help
Select the TE IRQ mode.
config EXYNOS7570_DISPLAY_TE_IRQ_GPIO
bool "Dual GPIO"
config EXYNOS7570_DISPLAY_TE_IRQ_GIC
bool "GIC Interrupt"
endchoice
config USE_VSYNC_SKIP
bool "Vsync Skip Enable"
depends on EXYNOS_DECON_7570
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_7570
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_7570
default y
help
Enable MIPI-DSI driver.
config DECON_MIPI_DSI_PKTGO
bool "Samsung Exynos MIPI-DSI Packet Go"
depends on EXYNOS_DECON_7570 && 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_7570
depends on EXYNOS7570_DISPLAY_COMMAND_MODE
default n
config DECON_LPD_DISPLAY_WITH_CAMERA
bool "Decon Low Power Display MODE with Camera"
depends on DECON_LPD_DISPLAY
depends on EXYNOS7570_DISPLAY_COMMAND_MODE
config DECON_DEVFREQ
bool "Decon devfreq implementation"
depends on EXYNOS_DECON_7570
config FB_WINDOW_UPDATE
bool "DECON window update mode"
depends on EXYNOS_DECON_7570
depends on EXYNOS7570_DISPLAY_COMMAND_MODE
default n
config DECON_BLOCKING_MODE
bool "DECON blocking mode"
depends on EXYNOS_DECON_7570
default n
config DECON_USE_BOOTLOADER_FB
bool "DECON Bootloader Framebuffer support"
depends on EXYNOS7570_DISPLAY_VIDEO_MODE
default n
config DECON_EVENT_LOG
bool "Display sub-system event logger (DECON/DSIM)"
depends on DEBUG_INFO && EXYNOS_DECON_7570
default y
config EXYNOS_MIPI_DSI_ENABLE_EARLY
bool "Samsung Exynos MIPI-DSI Driver ENABLE EARLY"
default n
source "drivers/video/fbdev/exynos/decon_7570/panels/Kconfig"

View file

@ -0,0 +1,12 @@
#
# Copyright (c) 2013 Samsung Electronics Co., Ltd.
# http://www.samsung.com
#
# Licensed under GPLv2
#
obj-$(CONFIG_EXYNOS_MIPI_DSI) += dsim.o
dsim-y += dsim_drv.o dsim_reg_7570.o
obj-$(CONFIG_EXYNOS_DECON_7570) += decon.o
decon-y += decon_core.o decon-int_drv.o decon_helper.o decon_reg_7570.o decon_board.o
obj-y += panels/

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,879 @@
/*
* Copyright (c) 2015 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 <soc/samsung/bts.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_int_drvdata;
extern int decon_log_level;
#if defined(CONFIG_ARM_EXYNOS7570_BUS_DEVFREQ)
#define CONFIG_DECON_DEVFREQ
#endif
/*
* Lets Keep it same as 7420. This is the count for
* maximum number of layers supported by this driver.
* Real number of HW layers (or Active layers) will be
* provided by device tree.
*/
#define MAX_DECON_WIN (7)
#define DECON_INT (0)
#define DRIVER_NAME "decon"
#define MAX_NAME_SIZE 32
#define MAX_DECON_PADS 4
#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 DECON_ENABLE 1
#define DECON_DISABLE 0
#define DECON_BACKGROUND 0
#define VSYNC_TIMEOUT_MSEC 200
#define MAX_BW_PER_WINDOW (2560 * 1600 * 4 * 60)
#define LCD_DEFAULT_BPP 24
#define SHADOW_OFFSET (0x7000)
#define DRM_DEV_DECON 3
#define DECON_CFW_OFFSET 3
#define EVT_TYPE_INT BIT(31)
#define EVT_TYPE_IOCTL BIT(30)
#define EVT_TYPE_ASYNC_EVT BIT(29)
#define EVT_TYPE_PM BIT(28)
#define EVT_TYPE_WININFO BIT(27)
#define DECON_LOG_LEVEL_ERR 3
#define DECON_LOG_LEVEL_WARN 4
#define DECON_LOG_LEVEL_INFO 6
#define DECON_LOG_LEVEL_DBG 7
#define DECON_UNDERRUN_THRESHOLD 300
#ifdef CONFIG_FB_WINDOW_UPDATE
#define DECON_WIN_UPDATE_IDX (7)
#define decon_win_update_dbg(fmt, ...) \
do { \
if (decon_log_level >= DECON_LOG_LEVEL_DBG) \
pr_info(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#else
#define decon_win_update_dbg(fmt, ...) (while (0))
#endif
#define decon_err(fmt, ...) \
do { \
if (decon_log_level >= DECON_LOG_LEVEL_ERR) \
pr_err(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define decon_warn(fmt, ...) \
do { \
if (decon_log_level >= DECON_LOG_LEVEL_WARN) \
pr_warn(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define decon_info(fmt, ...) \
do { \
if (decon_log_level >= DECON_LOG_LEVEL_INFO) \
pr_info(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define decon_dbg(fmt, ...) \
do { \
if (decon_log_level >= DECON_LOG_LEVEL_DBG) \
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
};
enum decon_ip_version {
IP_VER_DECON_7I = BIT(0),
};
struct exynos_decon_platdata {
struct decon_clk_info decon_clk;
enum decon_ip_version ip_ver;
enum decon_psr_mode psr_mode;
enum decon_trig_mode trig_mode;
enum decon_dsi_mode dsi_mode;
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 *core_clk; /* Core CLock, APB, BUS */
struct clk *vclk; /* VCLK from MIF */
struct clk *vclk_leaf; /* VCLK Local (DISP PLL or MIF) */
};
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];
struct fb_var_screeninfo prev_var;
struct fb_fix_screeninfo prev_fix;
int fps;
int index;
int use;
int local;
unsigned long state;
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_NV21M_FULL,
DECON_PIXEL_FORMAT_MAX,
};
enum decon_blending {
DECON_BLENDING_NONE = 0,
DECON_BLENDING_PREMULT = 1,
DECON_BLENDING_COVERAGE = 2,
DECON_BLENDING_MAX = 3,
};
struct exynos_hdmi_data {
enum {
EXYNOS_HDMI_STATE_PRESET = 0,
EXYNOS_HDMI_STATE_ENUM_PRESET,
EXYNOS_HDMI_STATE_CEC_ADDR,
EXYNOS_HDMI_STATE_HDCP,
EXYNOS_HDMI_STATE_AUDIO,
} state;
struct v4l2_dv_timings timings;
struct v4l2_enum_dv_timings etimings;
__u32 cec_addr;
__u32 audio_info;
int hdcp;
};
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,
};
struct vpp_params {
dma_addr_t addr[MAX_BUF_PLANE_CNT];
enum vpp_rotate rot;
enum vpp_csc_eq eq_mode;
};
struct decon_phys_addr {
unsigned long phy_addr[MAX_BUF_PLANE_CNT];
unsigned int phy_addr_len[MAX_BUF_PLANE_CNT];
};
struct decon_phys_old_info {
int win_id;
int pixel_format;
int plane;
unsigned long int phys_addr[MAX_BUF_PLANE_CNT];
unsigned int phys_addr_len[MAX_BUF_PLANE_CNT];
};
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;
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;
u32 shadowcon;
u32 wincon[MAX_DECON_WIN];
u32 win_rgborder[MAX_DECON_WIN];
u32 winmap[MAX_DECON_WIN];
u32 vidosd_a[MAX_DECON_WIN];
u32 vidosd_b[MAX_DECON_WIN];
u32 vidosd_c[MAX_DECON_WIN];
u32 vidosd_d[MAX_DECON_WIN];
u32 vidw_alpha0[MAX_DECON_WIN];
u32 vidw_alpha1[MAX_DECON_WIN];
u32 blendeq[MAX_DECON_WIN - 1];
u32 buf_start[MAX_DECON_WIN];
struct decon_dma_buf_data dma_buf_data[MAX_DECON_WIN][MAX_BUF_PLANE_CNT];
unsigned int num_of_window;
u32 win_overlap_cnt;
u32 offset_x[MAX_DECON_WIN];
u32 offset_y[MAX_DECON_WIN];
u32 whole_w[MAX_DECON_WIN];
u32 whole_h[MAX_DECON_WIN];
struct decon_win_config win_config[MAX_DECON_WIN];
struct decon_win_rect block_rect[MAX_DECON_WIN];
struct decon_phys_addr phys_addr[MAX_DECON_WIN + 1];
#ifdef CONFIG_FB_WINDOW_UPDATE
struct decon_win_rect update_win;
bool need_update;
#endif
u64 cur_bw;
u64 bandwidth;
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 exynos_hdmi_data hdmi_data;
struct decon_win_config_data win_data;
u32 vsync;
};
struct decon_underrun_stat {
u64 prev_bw;
int chmap;
int fifo_level;
int underrun_cnt;
unsigned long aclk;
unsigned long lh_disp0;
unsigned long mif_pll;
unsigned long used_windows;
};
#ifdef CONFIG_DECON_EVENT_LOG
#define DEFAULT_BASE_IDX (-1)
/**
* 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 = EVT_TYPE_IOCTL,
DISP_EVT_UNBLANK,
DISP_EVT_ACT_VSYNC,
DISP_EVT_DEACT_VSYNC,
DISP_EVT_WIN_CONFIG,
DISP_EVT_ACT_PROT,
DISP_EVT_DEACT_PROT,
/* Related with interrupt */
DISP_EVT_TE_INTERRUPT = EVT_TYPE_INT,
DISP_EVT_UNDERRUN,
DISP_EVT_DECON_FRAMEDONE,
DISP_EVT_DSIM_FRAMEDONE,
DISP_EVT_UPDATE_TIMEOUT,
DISP_EVT_LINECNT_TIMEOUT,
/* Related with async event */
DISP_EVT_UPDATE_HANDLER = EVT_TYPE_ASYNC_EVT,
DISP_EVT_DSIM_COMMAND,
DISP_EVT_TRIG_MASK,
DISP_EVT_DECON_FRAMEDONE_WAIT,
DISP_EVT_LINECNT_ZERO,
DISP_EVT_SIZE_ERR,
DISP_EVT_DSIM_INTR_ENABLE,
DISP_EVT_DSIM_INTR_DISABLE,
DISP_EVT_DECON_SHUTDOWN,
DISP_EVT_DSIM_SHUTDOWN,
DISP_EVT_WIN_CONFIG_PARAM = EVT_TYPE_WININFO,
DISP_EVT_UPDATE_PARAMS,
/* Related with PM */
DISP_EVT_DECON_SUSPEND = EVT_TYPE_PM,
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_VSYNC_TIMEOUT,
DISP_EVT_VSTATUS_TIMEOUT,
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 {
bool need_update;
u32 overlap_cnt;
u32 bandwidth;
u32 wincon[MAX_DECON_WIN];
u32 offset_x[MAX_DECON_WIN];
u32 offset_y[MAX_DECON_WIN];
u32 whole_w[MAX_DECON_WIN];
u32 whole_h[MAX_DECON_WIN];
u32 vidosd_a[MAX_DECON_WIN];
u32 vidosd_b[MAX_DECON_WIN];
struct decon_win_config win_config[MAX_DECON_WIN];
struct decon_win_rect win;
};
/* Related with MIPI COMMAND read/write */
struct dsim_log_cmd_buf {
u32 id;
u8 buf;
};
/* Related with size mismatch error */
struct disp_ss_size_info {
u32 w_in;
u32 h_in;
u32 w_out;
u32 h_out;
};
/**
* struct disp_ss_log - Display Subsystem Log
* This struct includes DECON/DSIM
*/
struct disp_ss_log {
ktime_t time;
disp_ss_event_t type;
union {
struct disp_log_pm pm;
struct decon_update_reg_data reg;
struct dsim_log_cmd_buf cmd_buf;
struct decon_win_config_data win_data;
struct disp_ss_size_info size_mismatch;
} data;
};
/* bootloader framebuffer information */
struct disp_bootloader_fb_info {
u32 phy_addr;
u32 size;
u32 l;
u32 t;
u32 r;
u32 b;
u32 format;
};
struct esd_protect {
u32 pcd_irq;
u32 err_irq;
u32 det_irq;
u32 pcd_gpio;
u32 err_gpio;
u32 det_gpio;
int pcd_pin_active;
int err_pin_active;
int det_pin_active;
u32 err_count;
u32 det_count;
struct workqueue_struct *esd_wq;
struct work_struct esd_work;
u32 queuework_pending;
};
/* Definitions below are used in the DECON */
#define DISP_EVENT_LOG_MAX SZ_2K
#define DISP_EVENT_PRINT_MAX 256
/* APIs below are used in the DECON/DSIM 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_UPDATE_PARAMS(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, int base_idx, bool sync);
void DISP_SS_EVENT_LOG_WIN_CONFIG(struct v4l2_subdev *sd, struct decon_win_config_data *win_data);
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_LOG_UPDATE_PARAMS(...) do { } while(0)
#define DISP_SS_EVENT_LOG_WIN_CONFIG(...) do { } while(0)
#define DISP_SS_EVENT_SIZE_ERR_LOG(...) do { } while(0)
#endif
/**
* END of CONFIG_DECON_EVENT_LOG
*/
struct decon_device {
void __iomem *regs;
void __iomem *disp_ss_regs;
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;
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 mic_enabled;
int n_sink_pad;
int n_src_pad;
union decon_ioctl_data ioctl_data;
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_status;
u32 cur_protection_bitmask;
unsigned int irq;
int frame_idle;
bool eint_en_status;
struct dentry *debug_root;
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 idle_ip_index;
u64 max_win_bw;
u64 prev_bw;
#ifdef CONFIG_DECON_EVENT_LOG
wait_queue_head_t event_wait;
struct dentry *mask;
struct dentry *debug_event;
struct disp_ss_log disp_ss_log[DISP_EVENT_LOG_MAX];
atomic_t disp_ss_log_idx;
#endif
u32 disp_ss_log_unmask;
#ifdef CONFIG_DECON_USE_BOOTLOADER_FB
struct disp_bootloader_fb_info bl_fb_info;
#endif
struct pinctrl *pinctrl;
struct pinctrl_state *decon_te_on;
struct pinctrl_state *decon_te_off;
struct decon_phys_old_info old_info;
struct decon_regs_data win_regs;
bool ignore_vsync;
struct esd_protect esd;
unsigned int force_fullupdate;
unsigned int esd_recovery;
};
static inline struct decon_device *get_decon_drvdata(u32 id)
{
return decon_int_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)
{
struct decon_device *decon = get_decon_drvdata(id);
u32 old = decon_read(id, reg_id);
val = (val & mask) | (old & ~mask);
writel(val, decon->regs + reg_id);
}
/* common function API */
bool decon_validate_x_alignment(struct decon_device *decon, int x, u32 w,
u32 bits_per_pixel);
int find_subdev_mipi(struct decon_device *decon);
int find_subdev_hdmi(struct decon_device *decon);
int create_link_mipi(struct decon_device *decon);
int create_link_hdmi(struct decon_device *decon);
int decon_int_register_irq(struct platform_device *pdev, struct decon_device *decon);
irqreturn_t decon_int_irq_handler(int irq, void *dev_data);
int decon_int_get_clocks(struct decon_device *decon);
void decon_int_set_clocks(struct decon_device *decon);
int decon_int_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);
void decon_lpd_enable(void);
int decon_wait_for_vsync(struct decon_device *decon, u32 timeout);
/* internal only function API */
int decon_fb_config_eint_for_te(struct platform_device *pdev, struct decon_device *decon);
int decon_int_create_vsync_thread(struct decon_device *decon);
int decon_int_create_psr_thread(struct decon_device *decon);
void decon_int_destroy_vsync_thread(struct decon_device *decon);
void decon_int_destroy_psr_thread(struct decon_device *decon);
int decon_int_set_lcd_config(struct decon_device *decon);
int decon_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
int decon_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info);
/* external only function API */
struct decon_lcd *find_porch(struct v4l2_mbus_framefmt mbus_fmt);
int decon_get_hdmi_config(struct decon_device *decon,
struct exynos_hdmi_data *hdmi_data);
int decon_set_hdmi_config(struct decon_device *decon,
struct exynos_hdmi_data *hdmi_data);
/* 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_set_qos(struct decon_device *decon, struct decon_reg_data *regs,
bool is_after, bool is_default_qos);
/* LPD related */
static inline void decon_lpd_block(struct decon_device *decon)
{
if (!decon)
return;
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)
return;
if (decon_is_lpd_blocked(decon))
atomic_dec(&decon->lpd_block_cnt);
}
static inline void decon_lpd_block_reset(struct decon_device *decon)
{
atomic_set(&decon->lpd_block_cnt, 0);
}
static inline void decon_lpd_trig_reset(struct decon_device *decon)
{
atomic_set(&decon->lpd_trig_cnt, 0);
}
#ifdef CONFIG_DECON_LPD_DISPLAY_WITH_CAMERA
static inline bool is_cam_not_running(struct decon_device *decon)
{
return !(decon_reg_get_cam_status(decon->cam_status[0]) & 0xF);
}
#else
static inline bool is_cam_not_running(struct decon_device *decon)
{
return true;
}
#endif
static inline bool decon_lpd_enter_cond(struct decon_device *decon)
{
return ((atomic_inc_return(&decon->lpd_trig_cnt) > DECON_ENTER_LPD_CNT) &&
(atomic_read(&decon->lpd_block_cnt) <= 0) && is_cam_not_running(decon));
}
static inline bool is_any_pending_frames(struct decon_device *decon)
{
return ((decon->timeline_max - decon->timeline->value) > 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 EXYNOS_GET_HDMI_CONFIG _IOW('F', 220, \
struct exynos_hdmi_data)
#define EXYNOS_SET_HDMI_CONFIG _IOW('F', 221, \
struct exynos_hdmi_data)
#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,470 @@
/* linux/drivers/video/exynos/decon_display/decon_board.c
*
* Copyright (c) 2015 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.
*/
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include "../../../../pinctrl/core.h"
#include "decon_board.h"
/*
*
0. There is a pre-defined property of the name of "decon_board".
decon_board has a phandle value that uniquely identifies the other node
containing subnodes to control gpio, regulator, delay and pinctrl.
If you want make new list, write control sequence list in dts, and call run_list function with subnode name.
1. type
There are 4 pre-defined types
- GPIO has 2 kinds of subtype: HIGH, LOW
- REGULATOR has 2 kinds of subtype: ENABLE, DISABLE
- DELAY has 3 kinds of subtype: MDELAY, MSLEEP, USLEEP
- PINCTRL has no pre-defined subtype, it needs pinctrl name as string in subtype position.
2. subtype and property
- GPIO(HIGH, LOW) search gpios-property for gpio position. 1 at a time.
- REGULATOR(ENABLE, DISABLE) search regulator-property for regulator name. 1 at a time.
- DELAY(MDELAY, MSLEEP) search delay-property for delay duration. 1 at a time.
- DELAY(USLEEP) search delay-property for delay duration. 2 at a time.
3. property type
- type, subtype and desc property type is string
- gpio-property type is phandle
- regulator-property type is string
- delay-property type is u32
4. check rule
- number of type = number of subtype
- number of each type = number of each property.
But If subtype is USLEEP, it needs 2 parameter. So we check 1 USLEEP = 2 * u32 delay-property
- desc-property is for debugging message description. It's not essential.
5. example:
decon_board = <&node>;
node: node {
subnode {
type = "regulator,enable", "gpio,high", "delay,usleep", "pinctrl,turnon_tes", "delay,msleep";
desc = "ldo1 enable", "gpio high", "Wait 10ms", "te pin configuration", "30ms";
gpios = <&gpf1 5 0x1>;
delay = <10000 11000>, <30>;
regulator = "ldo1";
};
};
run_list(dev, "subnode");
*/
#ifdef CONFIG_LIST_DEBUG /* this is not defconfig */
#define list_dbg(format, arg...) printk(format, ##arg)
#else
#define list_dbg(format, arg...)
#endif
#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
#define STRNEQ(a, b) (strncmp((a), (b), (strlen(a))) == 0)
#define DECON_BOARD_DTS_NAME "decon_board"
struct list_info {
char *name;
struct list_head node;
};
struct action_info {
char *type;
char *subtype;
const char *desc;
unsigned int idx;
int gpio;
unsigned int delay[2];
struct regulator_bulk_data *supply;
struct pinctrl *pins;
struct pinctrl_state *state;
struct list_head node;
};
enum {
ACTION_DUMMY,
ACTION_GPIO_HIGH,
ACTION_GPIO_LOW,
ACTION_REGULATOR_ENABLE,
ACTION_REGULATOR_DISABLE,
ACTION_DELAY_MDELAY,
ACTION_DELAY_MSLEEP,
ACTION_DELAY_USLEEP, /* usleep_range */
ACTION_PINCTRL,
ACTION_MAX
};
const char *action_list[ACTION_MAX][2] = {
[ACTION_GPIO_HIGH] = {"gpio", "high"},
{"gpio", "low"},
{"regulator", "enable"},
{"regulator", "disable"},
{"delay", "mdelay"},
{"delay", "msleep"},
{"delay", "usleep"},
{"pinctrl", ""}
};
static struct list_info *lists[10];
static int print_action(struct action_info *info)
{
if (!IS_ERR_OR_NULL(info->desc))
list_dbg("[%2d] %s\n", info->idx, info->desc);
switch (info->idx) {
case ACTION_GPIO_HIGH:
list_dbg("[%2d] gpio(%d) high\n", info->idx, info->gpio);
break;
case ACTION_GPIO_LOW:
list_dbg("[%2d] gpio(%d) low\n", info->idx, info->gpio);
break;
case ACTION_REGULATOR_ENABLE:
list_dbg("[%2d] regulator(%s) enable\n", info->idx, info->supply->supply);
break;
case ACTION_REGULATOR_DISABLE:
list_dbg("[%2d] regulator(%s) disable\n", info->idx, info->supply->supply);
break;
case ACTION_DELAY_MDELAY:
list_dbg("[%2d] mdelay(%d)\n", info->idx, info->delay[0]);
break;
case ACTION_DELAY_MSLEEP:
list_dbg("[%2d] msleep(%d)\n", info->idx, info->delay[0]);
break;
case ACTION_DELAY_USLEEP:
list_dbg("[%2d] usleep(%d %d)\n", info->idx, info->delay[0], info->delay[1]);
break;
case ACTION_PINCTRL:
list_dbg("[%2d] pinctrl(%s)\n", info->idx, info->state->name);
break;
default:
list_dbg("%s: unknown idx(%d)\n", __func__, info->idx);
break;
}
return 0;
}
static void dump_list(struct list_head *list)
{
struct action_info *info;
list_for_each_entry(info, list, node) {
print_action(info);
}
}
static int decide_action(const char *type, const char *subtype)
{
int i;
int action = ACTION_DUMMY;
if (type == NULL || *type == '\0')
return 0;
if (subtype == NULL || *subtype == '\0')
return 0;
if (STRNEQ("pinctrl", type)) {
action = ACTION_PINCTRL;
goto exit;
}
for (i = ACTION_GPIO_HIGH; i < ACTION_MAX; i++) {
if (STRNEQ(action_list[i][0], type) && STRNEQ(action_list[i][1], subtype)) {
action = i;
break;
}
}
exit:
if (action == ACTION_DUMMY)
pr_err("no valid action for %s %s\n", type, subtype);
return action;
}
static int check_dt(struct device_node *np)
{
struct property *prop;
const char *s;
int type, desc;
int gpio = 0, delay = 0, regulator = 0, pinctrl = 0, delay_property = 0;
of_property_for_each_string(np, "type", prop, s) {
if (STRNEQ("gpio", s))
gpio++;
else if (STRNEQ("regulator", s))
regulator++;
else if (STRNEQ("delay", s))
delay++;
else if (STRNEQ("pinctrl", s))
pinctrl++;
else {
pr_err("there is no valid type for %s\n", s);
#ifdef CONFIG_LIST_DEBUG
BUG();
#endif
}
}
of_property_for_each_string(np, "type", prop, s) {
if (STRNEQ("delay,usleep", s))
delay++;
}
type = of_property_count_strings(np, "type");
if (of_find_property(np, "desc", NULL)) {
desc = of_property_count_strings(np, "desc");
WARN(type != desc, "type(%d) and desc(%d) is not match\n", type, desc);
#ifdef CONFIG_LIST_DEBUG
BUG_ON(type != desc);
#endif
}
if (of_find_property(np, "gpios", NULL)) {
WARN(gpio != of_gpio_count(np), "gpio(%d %d) is not match\n", gpio, of_gpio_count(np));
#ifdef CONFIG_LIST_DEBUG
BUG_ON(gpio != of_gpio_count(np));
#endif
}
if (of_find_property(np, "regulator", NULL)) {
WARN(regulator != of_property_count_strings(np, "regulator"),
"regulator(%d %d) is not match\n", regulator, of_property_count_strings(np, "regulator"));
#ifdef CONFIG_LIST_DEBUG
BUG_ON(regulator != of_property_count_strings(np, "regulator"));
#endif
}
if (of_find_property(np, "delay", &delay_property)) {
delay_property /= sizeof(u32);
WARN(delay != delay_property, "delay(%d %d) is not match\n", delay, delay_property);
#ifdef CONFIG_LIST_DEBUG
BUG_ON(delay != delay_property);
#endif
}
pr_info("%s: gpio: %d, regulator: %d, delay: %d, pinctrl: %d\n", __func__, gpio, regulator, delay, pinctrl);
return 0;
}
static int make_list(struct device *dev, struct list_head *list, const char *name)
{
struct device_node *np = NULL;
struct action_info *info;
int i, count;
int gpio = 0, delay = 0, regulator = 0, ret = 0;
const char *type;
np = of_parse_phandle(dev->of_node, DECON_BOARD_DTS_NAME, 0);
if (!np) {
pr_err("%s: %s node does not exist, so create dummy\n", __func__, DECON_BOARD_DTS_NAME);
}
np = of_find_node_by_name(np, name);
if (!np) {
pr_err("%s: %s node does not exist, so create dummy\n", __func__, name);
info = kzalloc(sizeof(struct action_info), GFP_KERNEL);
list_add_tail(&info->node, list);
return -EINVAL;
}
check_dt(np);
count = of_property_count_strings(np, "type");
for (i = 0; i < count; i++) {
of_property_read_string_index(np, "type", i, &type);
if (!lcdtype && !STRNEQ("delay", type)) {
pr_info("%s: lcdtype is zero, so skip to add %s: %2d: %s\n", __func__, name, count, type);
continue;
}
info = kzalloc(sizeof(struct action_info), GFP_KERNEL);
info->subtype = kstrdup(type, GFP_KERNEL);
info->type = strsep(&info->subtype, ",");
if (of_property_count_strings(np, "desc") == count)
of_property_read_string_index(np, "desc", i, &info->desc);
info->idx = decide_action(info->type, info->subtype);
list_add_tail(&info->node, list);
}
list_for_each_entry(info, list, node) {
switch (info->idx) {
case ACTION_GPIO_HIGH:
case ACTION_GPIO_LOW:
info->gpio = of_get_gpio(np, gpio);
if (!gpio_is_valid(info->gpio)) {
pr_err("%s: %d: of_get_gpio fail\n", __func__, __LINE__);
ret = -EINVAL;
}
gpio++;
break;
case ACTION_REGULATOR_ENABLE:
case ACTION_REGULATOR_DISABLE:
info->supply = kzalloc(sizeof(struct regulator_bulk_data), GFP_KERNEL);
of_property_read_string_index(np, "regulator", regulator, &info->supply->supply);
ret = regulator_bulk_get(NULL, 1, info->supply);
if (ret)
pr_err("%s: %d: regulator_bulk_get fail %s %d\n", __func__, __LINE__, info->supply->supply, ret);
regulator++;
break;
case ACTION_DELAY_MDELAY:
case ACTION_DELAY_MSLEEP:
ret = of_property_read_u32_index(np, "delay", delay, &info->delay[0]);
if (ret)
pr_err("%s: %d: of_property_read_u32_index\n", __func__, __LINE__);
delay++;
break;
case ACTION_DELAY_USLEEP:
ret = of_property_read_u32_index(np, "delay", delay, &info->delay[0]);
delay++;
ret += of_property_read_u32_index(np, "delay", delay, &info->delay[1]);
delay++;
if (ret)
pr_err("%s: %d: of_property_read_u32_index\n", __func__, __LINE__);
break;
case ACTION_PINCTRL:
info->pins = devm_pinctrl_get(dev);
if (IS_ERR(info->pins)) {
pr_err("%s: devm_pinctrl_get fail\n", __func__);
ret = -EINVAL;
}
info->state = pinctrl_lookup_state(info->pins, info->subtype);
if (IS_ERR(info->pins)) {
pr_err("%s: pinctrl_lookup_state fail %s\n", __func__, info->subtype);
ret = -EINVAL;
}
break;
default:
pr_err("%d %s %s error\n", info->idx, info->type, info->subtype);
ret = -EINVAL;
break;
}
}
#ifdef CONFIG_LIST_DEBUG
if (ret)
BUG();
#endif
return 0;
}
static int do_list(struct list_head *list)
{
struct action_info *info;
int ret = 0;
list_for_each_entry(info, list, node) {
switch (info->idx) {
case ACTION_GPIO_HIGH:
ret = gpio_request_one(info->gpio, GPIOF_OUT_INIT_HIGH, NULL);
if (ret)
pr_err("gpio_request_one fail\n");
gpio_free(info->gpio);
break;
case ACTION_GPIO_LOW:
ret = gpio_request_one(info->gpio, GPIOF_OUT_INIT_LOW, NULL);
if (ret)
pr_err("gpio_request_one fail\n");
gpio_free(info->gpio);
break;
case ACTION_REGULATOR_ENABLE:
ret = regulator_enable(info->supply->consumer);
if (ret)
pr_err("regulator_enable fail, %s\n", info->supply->supply);
break;
case ACTION_REGULATOR_DISABLE:
ret = regulator_disable(info->supply->consumer);
if (ret)
pr_err("regulator_disable fail, %s\n", info->supply->supply);
break;
case ACTION_DELAY_MDELAY:
mdelay(info->delay[0]);
break;
case ACTION_DELAY_MSLEEP:
msleep(info->delay[0]);
break;
case ACTION_DELAY_USLEEP:
usleep_range(info->delay[0], info->delay[1]);
break;
case ACTION_PINCTRL:
pinctrl_select_state(info->pins, info->state);
break;
case ACTION_DUMMY:
break;
default:
pr_err("%s: unknown idx(%d)\n", __func__, info->idx);
ret = -EINVAL;
break;
}
}
#ifdef CONFIG_LIST_DEBUG
if (ret)
BUG();
#endif
return 0;
}
static inline struct list_head *find_list(const char *name)
{
struct list_info *info = NULL;
int idx = 0;
list_dbg("%s: %s\n", __func__, name);
while (!IS_ERR_OR_NULL(lists[idx])) {
info = lists[idx];
list_dbg("%s: %dth list name is %s\n", __func__, idx, info->name);
if (STREQ(info->name, name))
return &info->node;
idx++;
BUG_ON(idx == ARRAY_SIZE(lists));
};
pr_info("%s is not exist, so create it\n", name);
info = kzalloc(sizeof(struct list_info), GFP_KERNEL);
info->name = kstrdup(name, GFP_KERNEL);
INIT_LIST_HEAD(&info->node);
lists[idx] = info;
return &info->node;
}
void run_list(struct device *dev, const char *name)
{
struct list_head *list = find_list(name);
if (unlikely(list_empty(list))) {
pr_info("%s is empty, so make list\n", name);
make_list(dev, list, name);
dump_list(list);
}
do_list(list);
}

View file

@ -0,0 +1,19 @@
/* linux/drivers/video/exynos/decon_display/decon_board.c
*
* Copyright (c) 2015 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_DISPLAY_BOARD_HEADER__
#define __DECON_DISPLAY_BOARD_HEADER__
#include <linux/device.h>
extern unsigned int lcdtype;
void run_list(struct device *dev, const char *name);
#endif

View file

@ -0,0 +1,162 @@
/*
* Copyright (c) 2015 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_COMMON_H__
#define ___SAMSUNG_DECON_COMMON_H__
#include "./panels/decon_lcd.h"
enum decon_dsi_mode {
DSI_MODE_SINGLE = 0,
};
enum decon_trig_mode {
DECON_HW_TRIG = 0,
DECON_SW_TRIG
};
enum decon_hold_scheme {
DECON_VCLK_HOLD = 0x00,
DECON_VCLK_RUNNING = 0x01,
DECON_VCLK_RUN_VDEN_DISABLE = 0x3,
};
enum decon_rgb_order {
DECON_RGB = 0x0,
DECON_GBR = 0x1,
DECON_BRG = 0x2,
DECON_BGR = 0x4,
DECON_RBG = 0x5,
DECON_GRB = 0x6,
};
enum decon_set_trig {
DECON_TRIG_DISABLE = 0,
DECON_TRIG_ENABLE
};
enum decon_set_eclk_idle_gate {
DECON_ECLK_IDLE_GATE_DISABLE = 0,
DECON_ECLK_IDLE_GATE_ENABLE
};
enum decon_idma_type {
IDMA_G0 = 0x0,
IDMA_G1,
IDMA_VG0,
IDMA_VG1,
IDMA_VGR0,
IDMA_VGR1,
IDMA_G2,
IDMA_G3,
IDMA_MAX
};
enum decon_output_type {
DECON_OUT_DSI = 0,
};
struct decon_clk_info {
u32 disp_vclk;
u32 mif_vclk;
u32 disp_dvfs;
u32 vclk_num;
u32 vclk_denom;
};
struct decon_psr_info {
enum decon_psr_mode psr_mode;
enum decon_trig_mode trig_mode;
enum decon_output_type out_type;
};
struct decon_init_param {
struct decon_psr_info psr;
struct decon_lcd *lcd_info;
struct decon_clk_info *decon_clk;
u32 nr_windows;
};
struct decon_regs_data {
u32 wincon;
u32 winmap;
u32 vidosd_a;
u32 vidosd_b;
u32 vidosd_c;
u32 vidosd_d;
u32 vidosd_e;
u32 vidw_buf_start;
u32 vidw_whole_w;
u32 vidw_whole_h;
u32 vidw_offset_x;
u32 vidw_offset_y;
u32 blendeq;
u32 vidw_plane2_buf_start;
u32 vidw_plane3_buf_start;
enum decon_idma_type type;
};
/* CAL APIs list */
void decon_reg_init(u32 id, enum decon_dsi_mode dsi_mode, struct decon_init_param *p);
void decon_reg_init_probe(u32 id, enum decon_dsi_mode dsi_mode, struct decon_init_param *p);
void decon_reg_start(u32 id, enum decon_dsi_mode dsi_mode, struct decon_psr_info *psr);
int decon_reg_stop(u32 id, enum decon_dsi_mode dsi_mode, struct decon_psr_info *psr);
void decon_reg_set_rgb_type(u32 id, int win_idx, u32 type);
void decon_reg_set_regs_data(u32 id, int win_idx, struct decon_regs_data *regs);
void decon_reg_set_int(u32 id, struct decon_psr_info *psr, enum decon_dsi_mode dsi_mode, u32 en);
void decon_reg_set_trigger(u32 id, enum decon_dsi_mode dsi_mode,
enum decon_trig_mode trig, enum decon_set_trig en);
int decon_reg_wait_for_update_timeout(u32 id, unsigned long timeout);
void decon_reg_shadow_protect_win(u32 id, u32 win_idx, u32 protect);
void decon_reg_activate_window(u32 id, u32 index);
void decon_enable_eclk_idle_gate(u32 id, enum decon_set_eclk_idle_gate en);
/* CAL raw functions list */
void decon_reg_set_disp_ss_cfg(void __iomem *disp_ss_regs, u32 enable);
int decon_reg_reset(u32 id);
void decon_reg_set_default_win_channel(u32 id);
void decon_reg_set_clkgate_mode(u32 id, u32 en);
void decon_reg_blend_alpha_bits(u32 id, u32 alpha_bits);
void decon_reg_set_vidout(u32 id, struct decon_psr_info *psr, enum decon_dsi_mode dsi_mode, u32 en);
void decon_reg_set_crc(u32 id, u32 en);
void decon_reg_set_fixvclk(u32 id, int dsi_idx, enum decon_hold_scheme mode);
void decon_reg_clear_win(u32 id, int win_idx);
void decon_reg_set_rgb_order(u32 id, int dsi_idx, enum decon_rgb_order order);
void decon_reg_set_porch(u32 id, int dsi_idx, struct decon_lcd *info);
void decon_reg_set_resolution(u32 id, int dsi_idx, struct decon_lcd *info);
void decon_reg_set_linecnt_op_threshold(u32 id, int dsi_idx, u32 th);
void decon_reg_set_clkval(u32 id, u32 clkdiv);
void decon_reg_direct_on_off(u32 id, u32 en);
void decon_reg_per_frame_off(u32 id);
void decon_reg_set_freerun_mode(u32 id, u32 en);
void decon_reg_set_vclk_divider(u32 id, u32 denom, u32 num);
void decon_reg_update_standalone(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);
void decon_reg_set_winmap(u32 id, u32 idx, u32 color, u32 en);
u32 decon_reg_get_linecnt(u32 id, int dsi_idx);
u32 decon_reg_get_vstatus(u32 id, int dsi_idx);
int decon_reg_wait_linecnt_is_zero_timeout(u32 id, int dsi_idx, unsigned long timeout);
u32 decon_reg_get_stop_status(u32 id);
int decon_reg_wait_stop_status_timeout(u32 id, unsigned long timeout);
int decon_reg_is_win_enabled(u32 id, int win_idx);
int decon_reg_is_shadow_updated(u32 id);
void decon_reg_config_mic(u32 id, int dsi_idx, struct decon_lcd *lcd_info);
void decon_reg_clear_int(u32 id);
void decon_reg_config_win_channel(u32 id, u32 win_idx, enum decon_idma_type type);
void decon_reg_set_mdnie_pclk(u32 id, u32 en);
void decon_reg_enable_mdnie(u32 id, u32 en);
void decon_reg_set_mdnie_blank(u32 id, u32 front, u32 sync, u32 back, u32 line);
u32 decon_reg_get_lineval(u32 id, int dsi_idx, struct decon_lcd *lcd_info);
u32 decon_reg_get_hozval(u32 id, int dsi_idx, 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,646 @@
/*
* Copyright (c) 2015 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 "decon.h"
#include "dsim.h"
#include "decon_helper.h"
#include <video/mipi_display.h>
inline int decon_is_no_bootloader_fb(struct decon_device *decon)
{
#ifdef CONFIG_DECON_USE_BOOTLOADER_FB
return !decon->bl_fb_info.phy_addr;
#else
return 1;
#endif
}
inline int decon_clk_set_parent(struct device *dev, struct clk *p, struct clk *c)
{
clk_set_parent(c, p);
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;
}
void decon_to_psr_info(struct decon_device *decon, struct decon_psr_info *psr)
{
psr->psr_mode = decon->pdata->psr_mode;
psr->trig_mode = decon->pdata->trig_mode;
psr->out_type = decon->out_type;
}
void decon_to_init_param(struct decon_device *decon, struct decon_init_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.out_type = decon->out_type;
p->nr_windows = decon->pdata->max_win;
p->decon_clk = &decon->pdata->decon_clk;
}
/**
* ----- APIs for DISPLAY_SUBSYSTEM_EVENT_LOG -----
*/
/* ===== STATIC APIs ===== */
#ifdef CONFIG_DECON_EVENT_LOG
/* logging a event related with DECON */
void disp_log_win_config(char *ts, struct seq_file *s,
struct decon_win_config *config)
{
int win;
struct decon_win_config *cfg;
char *state[] = { "D", "C", "B", "U" };
char *blending[] = { "N", "P", "C" };
char *idma[] = { "G0", "G1", "V0", "V1", "VR0", "VR1", "G2" };
for (win = 0; win < MAX_DECON_WIN; win++) {
cfg = &config[win];
if (cfg->state == DECON_WIN_STATE_DISABLED)
continue;
if (cfg->state == DECON_WIN_STATE_COLOR) {
seq_printf(s, "%s\t[%d] %s, C(%d), D(%d,%d,%d,%d) "
"P(%d)\n",
ts, win, state[cfg->state], cfg->color,
cfg->dst.x, cfg->dst.y,
cfg->dst.x + cfg->dst.w,
cfg->dst.y + cfg->dst.h,
cfg->protection);
} else {
seq_printf(s, "%s\t[%d] %s,(%d,%d,%d), F(%d) P(%d)"
" A(%d), %s, %s, f(%d) (%d,%d,%d,%d,%d,%d) ->"
" (%d,%d,%d,%d,%d,%d)\n",
ts, win, state[cfg->state], cfg->fd_idma[0],
cfg->fd_idma[1], cfg->fd_idma[2],
cfg->fence_fd, cfg->protection,
cfg->plane_alpha, blending[cfg->blending],
idma[cfg->idma_type], cfg->format,
cfg->src.x, cfg->src.y,
cfg->src.x + cfg->src.w,
cfg->src.y + cfg->src.h,
cfg->src.f_w, cfg->src.f_h,
cfg->dst.x, cfg->dst.y,
cfg->dst.x + cfg->dst.w,
cfg->dst.y + cfg->dst.h,
cfg->dst.f_w, cfg->dst.f_h);
}
}
}
void disp_log_update_info(char *ts, struct seq_file *s,
struct decon_update_reg_data *reg)
{
int win;
for (win = 0; win < MAX_DECON_WIN; win++) {
if (!(reg->wincon[win] & WINCON_ENWIN))
continue;
seq_printf(s, "%s\t[%d] U(%d): (%d,%d,%d,%d) -> "
"(%d,%d,%d,%d)\n",
ts, win, reg->need_update,
reg->offset_x[win], reg->offset_y[win],
reg->whole_w[win], reg->whole_h[win],
(reg->vidosd_a[win] >> 13) & 0x1fff,
(reg->vidosd_a[win]) & 0x1fff,
(reg->vidosd_b[win] >> 13) & 0x1fff,
(reg->vidosd_b[win]) & 0x1fff);
}
}
void disp_ss_event_log_win_update(char *ts, struct seq_file *s,
struct decon_update_reg_data *reg)
{
disp_log_win_config(ts, s, reg->win_config);
disp_log_update_info(ts, s, reg);
}
void disp_ss_event_log_win_config(char *ts, struct seq_file *s,
struct decon_win_config_data *win_cfg)
{
disp_log_win_config(ts, s, win_cfg->config);
}
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_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;
}
}
/* 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 */
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;
if (!(decon->disp_ss_log_unmask & type))
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_DECON_FRAMEDONE:
case DISP_EVT_DECON_FRAMEDONE_WAIT:
case DISP_EVT_ACT_VSYNC:
case DISP_EVT_DEACT_VSYNC:
case DISP_EVT_WIN_CONFIG:
case DISP_EVT_ACT_PROT:
case DISP_EVT_DEACT_PROT:
case DISP_EVT_UPDATE_TIMEOUT:
case DISP_EVT_LINECNT_TIMEOUT:
case DISP_EVT_VSYNC_TIMEOUT:
case DISP_EVT_VSTATUS_TIMEOUT:
disp_ss_event_log_decon(type, sd, time);
break;
case DISP_EVT_ENTER_ULPS:
case DISP_EVT_EXIT_ULPS:
case DISP_EVT_DSIM_SUSPEND:
case DISP_EVT_DSIM_RESUME:
case DISP_EVT_DSIM_FRAMEDONE:
case DISP_EVT_DSIM_INTR_ENABLE:
case DISP_EVT_DSIM_INTR_DISABLE:
disp_ss_event_log_dsim(type, sd, time);
break;
default:
return;
}
wake_up_interruptible_all(&decon->event_wait);
}
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 < 3; win++) {
if (regs->wincon[win] & WINCON_ENWIN) {
log->data.reg.wincon[win] = regs->wincon[win];
log->data.reg.offset_x[win] = regs->offset_x[win];
log->data.reg.offset_y[win] = regs->offset_y[win];
log->data.reg.whole_w[win] = regs->whole_w[win];
log->data.reg.whole_h[win] = regs->whole_h[win];
log->data.reg.vidosd_a[win] = regs->vidosd_a[win];
log->data.reg.vidosd_b[win] = regs->vidosd_b[win];
memcpy(&log->data.reg.win_config[win], &regs->win_config[win],
sizeof(struct decon_win_config));
} else {
log->data.reg.win_config[win].state = DECON_WIN_STATE_DISABLED;
}
}
#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;
}
}
void DISP_SS_EVENT_LOG_UPDATE_PARAMS(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;
if (!(decon->disp_ss_log_unmask & DISP_EVT_UPDATE_PARAMS))
return;
log->time = ktime_get();
log->type = DISP_EVT_UPDATE_PARAMS;
log->data.reg.overlap_cnt = regs->win_overlap_cnt;
log->data.reg.bandwidth = regs->cur_bw;
for (win = 0; win < MAX_DECON_WIN; win++) {
log->data.reg.wincon[win] = 0;
if (regs->wincon[win] & WINCON_ENWIN) {
log->data.reg.wincon[win] = regs->wincon[win];
log->data.reg.offset_x[win] = regs->offset_x[win];
log->data.reg.offset_y[win] = regs->offset_y[win];
log->data.reg.whole_w[win] = regs->whole_w[win];
log->data.reg.whole_h[win] = regs->whole_h[win];
log->data.reg.vidosd_a[win] = regs->vidosd_a[win];
log->data.reg.vidosd_b[win] = regs->vidosd_b[win];
memcpy(&log->data.reg.win_config[win], &regs->win_config[win],
sizeof(struct decon_win_config));
}
}
#ifdef CONFIG_FB_WINDOW_UPDATE
log->data.reg.need_update = regs->need_update;
if ((regs->need_update) ||
(decon->need_update && regs->update_win.w)) {
memcpy(&log->data.reg.win, &regs->update_win,
sizeof(struct decon_rect));
} else {
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;
}
#else
memset(&log->data.reg.win, 0, sizeof(struct decon_rect));
#endif
wake_up_interruptible_all(&decon->event_wait);
}
void DISP_SS_EVENT_LOG_WIN_CONFIG(struct v4l2_subdev *sd, struct decon_win_config_data *win_data)
{
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 (!(decon->disp_ss_log_unmask & DISP_EVT_WIN_CONFIG_PARAM))
return;
log->time = ktime_get();
log->type = DISP_EVT_WIN_CONFIG_PARAM;
memcpy(&log->data.win_data, win_data, sizeof(struct decon_win_config_data));
wake_up_interruptible_all(&decon->event_wait);
}
/* 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;
struct disp_ss_log *log;
if (!decon || IS_ERR_OR_NULL(decon->debug_event))
return;
if (!(decon->disp_ss_log_unmask & DISP_EVT_DSIM_COMMAND))
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;
if (cmd_id == MIPI_DSI_DCS_LONG_WRITE)
log->data.cmd_buf.buf = *(u8 *)(data);
else
log->data.cmd_buf.buf = (u8)data;
wake_up_interruptible_all(&decon->event_wait);
}
void DISP_SS_EVENT_SIZE_ERR_LOG(struct v4l2_subdev *sd, struct disp_ss_size_info *info)
{
struct dsim_device *dsim = container_of(sd, struct dsim_device, sd);
struct decon_device *decon = get_decon_drvdata(dsim->id);
int idx;
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_SIZE_ERR;
memcpy(&log->data.size_mismatch, info, sizeof(struct disp_ss_size_info));
wake_up_interruptible_all(&decon->event_wait);
}
/* display logged events related with DECON */
void DISP_SS_EVENT_SHOW(struct seq_file *s, struct decon_device *decon,
int base_idx, bool sync)
{
int idx = atomic_read(&decon->disp_ss_log_idx) % DISP_EVENT_LOG_MAX;
struct disp_ss_log *log;
int latest = idx;
struct timeval tv;
char ts[20];
if (!sync) {
/* TITLE */
seq_printf(s, "-------------------DECON EVENT LOGGER ----------------------\n");
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_printf(s, "-------------------------------------------------------------\n");
seq_printf(s, "%14s %20s %20s\n",
"Time", "Event ID", "Remarks");
seq_printf(s, "-------------------------------------------------------------\n");
if (idx < 0) {
seq_printf(s, "No Events available. Done.\n");
seq_printf(s, "-------------------------------------------------------------\n");
return;
}
}
if (sync) {
if (base_idx != DEFAULT_BASE_IDX)
idx = base_idx % DISP_EVENT_LOG_MAX;
} else {
/* Seek a oldest from current index */
idx = (idx + DISP_EVENT_LOG_MAX - DISP_EVENT_PRINT_MAX) % DISP_EVENT_LOG_MAX;
}
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);
sprintf(ts, "[%6ld.%06ld] ", tv.tv_sec, tv.tv_usec);
seq_printf(s, "%s", ts);
/* 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_WIN_CONFIG_PARAM:
seq_printf(s, "%20s %d %20s", "WIN_CONFIG_PARAM", log->data.win_data.fd_odma, "-\n");
disp_ss_event_log_win_config(ts, s, &log->data.win_data);
break;
case DISP_EVT_TE_INTERRUPT:
seq_printf(s, "%20s %20s", "TE_INTERRUPT", "-\n");
break;
case DISP_EVT_UNDERRUN:
seq_printf(s, "%20s %20s", "UNDER_RUN", "-\n");
break;
case DISP_EVT_DSIM_FRAMEDONE:
seq_printf(s, "%20s %20s", "DSIM_FRAME_DONE", "-\n");
break;
case DISP_EVT_DECON_FRAMEDONE:
seq_printf(s, "%20s %20s", "DECON_FRAME_DONE", "-\n");
break;
case DISP_EVT_TRIG_MASK:
seq_printf(s, "%20s %20s", "TRIG_MASK", "-\n");
break;
case DISP_EVT_DECON_FRAMEDONE_WAIT:
seq_printf(s, "%20s %20s", "FRAMEDONE_WAIT", "-\n");
break;
case DISP_EVT_ACT_PROT:
seq_printf(s, "%20s %20s", "PROTECTION_ENABLE", "-\n");
break;
case DISP_EVT_DEACT_PROT:
seq_printf(s, "%20s %20s", "PROTECTION_DISABLE", "-\n");
break;
case DISP_EVT_UPDATE_TIMEOUT:
seq_printf(s, "%20s %20s", "UPDATE_TIMEOUT", "-\n");
break;
case DISP_EVT_LINECNT_TIMEOUT:
seq_printf(s, "%20s %20s", "LINECNT_TIMEOUT", "-\n");
break;
case DISP_EVT_UPDATE_HANDLER:
seq_printf(s, "%20s ", "UPDATE_HANDLER");
seq_printf(s, "overlap=%d, bw=0x%x, (%d,%d,%d,%d) U=%d\n",
log->data.reg.overlap_cnt,
log->data.reg.bandwidth,
log->data.reg.win.x,
log->data.reg.win.y,
log->data.reg.win.x + log->data.reg.win.w,
log->data.reg.win.y + log->data.reg.win.h,
log->data.reg.need_update);
break;
case DISP_EVT_UPDATE_PARAMS:
seq_printf(s, "%20s ", "UPDATE_PARAMS");
seq_printf(s, "overlap=%d, bw=0x%x, (%d,%d,%d,%d) U=%d\n",
log->data.reg.overlap_cnt,
log->data.reg.bandwidth,
log->data.reg.win.x,
log->data.reg.win.y,
log->data.reg.win.w,
log->data.reg.win.h,
log->data.reg.need_update);
disp_ss_event_log_win_update(ts, s,
&log->data.reg);
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_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;
case DISP_EVT_DSIM_INTR_ENABLE:
seq_printf(s, "%20s %20s", "DSIM_INTR_ENABLE", "-\n");
break;
case DISP_EVT_DSIM_INTR_DISABLE:
seq_printf(s, "%20s %20s", "DSIM_INTR_DISABLE", "-\n");
break;
default:
break;
}
} while (latest != idx);
if (!sync)
seq_printf(s, "-------------------------------------------------------------\n");
return;
}
#endif

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2015 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_rate(struct device *dev, struct clk *clk,
const char *conid, unsigned long rate);
int decon_clk_set_parent(struct device *dev, struct clk *p, struct clk *c);
void decon_to_psr_info(struct decon_device *decon, struct decon_psr_info *psr);
void decon_to_init_param(struct decon_device *decon, struct decon_init_param *p);
int decon_get_psr_mode_from_config(void);
int decon_is_no_bootloader_fb(struct decon_device *decon);
#endif /* __SAMSUNG_DECON_HELPER_H__ */

View file

@ -0,0 +1,722 @@
/* drivers/video/fbdev/exynos/decon_7570/decon_reg_7570.c
*
* Copyright 2015 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.
*/
/* use this definition when you test CAL on firmware */
/* #define FW_TEST */
#ifdef FW_TEST
#include "decon_fw.h"
#else
#include "decon.h"
#endif
/******************* CAL raw functions implementation *************************/
void decon_reg_set_disp_ss_cfg(void __iomem *disp_ss_regs, u32 enable)
{
u32 val;
if (!disp_ss_regs) {
decon_err("decon disp_ss_regs is not mapped\n");
return;
}
val = readl(disp_ss_regs);
if (enable)
val = (val | DECON_SS_SEC);
else
val = (val & ~DECON_SS_SEC);
writel(val, disp_ss_regs);
decon_dbg("Display Configuration(DISP_CFG) value is 0x%x\n", val);
}
int decon_reg_reset(u32 id)
{
int tries;
decon_write(id, VIDCON0, VIDCON0_SWRESET);
for (tries = 2000; tries; --tries) {
if (~decon_read(id, VIDCON0) & VIDCON0_SWRESET)
break;
udelay(10);
}
if (!tries) {
decon_err("failed to reset Decon\n");
return -EBUSY;
}
return 0;
}
void decon_reg_set_default_win_channel(u32 id)
{
decon_write_mask(id, WINCHMAP0, WINCHMAP_DMA(0, 1), WINCHMAP_MASK(0));
decon_write_mask(id, WINCHMAP0, WINCHMAP_DMA(1, 1), WINCHMAP_MASK(1));
decon_write_mask(id, WINCHMAP0, WINCHMAP_DMA(2, 1), WINCHMAP_MASK(2));
}
void decon_reg_set_clkgate_mode(u32 id, u32 en)
{
}
void decon_reg_blend_alpha_bits(u32 id, u32 alpha_bits)
{
decon_write(id, BLENDCON, alpha_bits);
}
void decon_reg_set_vidout(u32 id, struct decon_psr_info *psr,
enum decon_dsi_mode dsi_mode, u32 en)
{
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
decon_write_mask(id, VIDOUTCON0, VIDOUTCON0_I80IF_F,
VIDOUTCON0_IF_MASK);
else
decon_write_mask(id, VIDOUTCON0, VIDOUTCON0_RGBIF_F,
VIDOUTCON0_IF_MASK);
decon_write_mask(id, VIDOUTCON0, en ? ~0 : 0, VIDOUTCON0_LCD_ON_F);
}
void decon_reg_set_crc(u32 id, u32 en)
{
u32 val = en ? ~0 : 0;
decon_write_mask(id, CRCCTRL, val,
CRCCTRL_CRCCLKEN | CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F);
}
void decon_reg_set_fixvclk(u32 id, int dsi_idx, enum decon_hold_scheme mode)
{
u32 val = VIDCON1_VCLK_HOLD;
switch (mode) {
case DECON_VCLK_HOLD:
val = VIDCON1_VCLK_HOLD;
break;
case DECON_VCLK_RUNNING:
val = VIDCON1_VCLK_RUN;
break;
case DECON_VCLK_RUN_VDEN_DISABLE:
val = VIDCON1_VCLK_RUN_VDEN_DISABLE;
break;
}
decon_write_mask(id, VIDCON1(dsi_idx), val, VIDCON1_VCLK_MASK);
}
void decon_reg_clear_win(u32 id, int win_idx)
{
decon_write(id, WINCON(win_idx), WINCON_RESET_VALUE);
decon_write(id, VIDOSD_A(win_idx), 0);
decon_write(id, VIDOSD_B(win_idx), 0);
decon_write(id, VIDOSD_C(win_idx), 0);
decon_write(id, VIDOSD_D(win_idx), 0);
}
void decon_reg_set_rgb_order(u32 id, int dsi_idx, enum decon_rgb_order order)
{
u32 val = VIDCON1_RGB_ORDER_O_RGB;
switch (order) {
case DECON_RGB:
val = VIDCON1_RGB_ORDER_O_RGB;
break;
case DECON_GBR:
val = VIDCON1_RGB_ORDER_O_GBR;
break;
case DECON_BRG:
val = VIDCON1_RGB_ORDER_O_BRG;
break;
case DECON_BGR:
val = VIDCON1_RGB_ORDER_O_BGR;
break;
case DECON_RBG:
val = VIDCON1_RGB_ORDER_O_RBG;
break;
case DECON_GRB:
val = VIDCON1_RGB_ORDER_O_GRB;
break;
}
decon_write_mask(id, VIDCON1(dsi_idx), val, VIDCON1_RGB_ORDER_O_MASK);
}
void decon_reg_set_porch(u32 id, int dsi_idx, struct decon_lcd *info)
{
u32 val = 0;
val = VIDTCON0_VBPD(info->decon_vbp - 1) | VIDTCON0_VFPD(info->decon_vfp - 1);
decon_write(id, VIDTCON0(dsi_idx), val);
val = VIDTCON1_VSPW(info->decon_vsa - 1);
decon_write(id, VIDTCON1(dsi_idx), val);
val = VIDTCON2_HBPD(info->decon_hbp - 1) | VIDTCON2_HFPD(info->decon_hfp - 1);
decon_write(id, VIDTCON2(dsi_idx), val);
val = VIDTCON3_HSPW(info->decon_hsa - 1);
decon_write(id, VIDTCON3(dsi_idx), val);
val = VIDTCON4_LINEVAL(info->yres - 1) |
VIDTCON4_HOZVAL(info->xres - 1);
decon_write(id, VIDTCON4(dsi_idx), val);
}
void decon_reg_set_resolution(u32 id, int dsi_idx, struct decon_lcd *info)
{
u32 val = 0;
/* from LCD info */
/* These values are fixed considering to 320 pixel restriction */
val = VIDTCON5_LINEVAL(info->dispif_h - 1) |
VIDTCON5_HOZVAL(info->dispif_w - 1);
decon_write(id, VIDTCON5(dsi_idx), val);
}
void decon_reg_set_linecnt_op_threshold(u32 id, int dsi_idx, u32 th)
{
decon_write(id, LINECNT_OP_THRESHOLD(dsi_idx), th);
}
void decon_reg_set_clkval(u32 id, u32 clkdiv)
{
decon_write_mask(id, VCLKCON0, ~0, VCLKCON0_CLKVALUP);
}
void decon_reg_direct_on_off(u32 id, u32 en)
{
u32 val = en ? ~0 : 0;
decon_write_mask(id, VIDCON0, val, VIDCON0_ENVID_F | VIDCON0_ENVID);
}
void decon_reg_per_frame_off(u32 id)
{
decon_write_mask(id, VIDCON0, 0, VIDCON0_ENVID_F);
}
void decon_reg_set_freerun_mode(u32 id, u32 en)
{
decon_write_mask(id, VCLKCON0, en ? ~0 : 0, VCLKCON0_VLCKFREE);
}
/*
* VCLK is the video source clock of DECON
* divider bit : 10bits
* NUM : NUM_VALUE_OF_VCLK[9:0]
* DENOM : DENOM_VALUE_OF_VCLK[25:16]
*/
void decon_reg_set_vclk_divider(u32 id, u32 denom, u32 num)
{
u32 val = 0;
if (num < 1 || denom < 1){
decon_err("Both num(%d) and denom(%d) should be over than 1 \n", num, denom);
return;
}
num = num - 1;
denom = denom - 1;
val = VCLKCON1_DENOM_VALUE_OF_CLK_F(denom)
| VCLKCON1_NUM_VALUE_OF_CLK_F(num);
/* VCLK controlled by DECON */
decon_write_mask(id, VCLKCON1, val, VCLKCON1_DENOM_VALUE_OF_CLK_F_MASK|VCLKCON1_NUM_VALUE_OF_CLK_F_MASK);
decon_info("%s(%d), VCLKCON1 is 0x%x\n", __func__, __LINE__, decon_read(id, VCLKCON1));
}
void decon_reg_update_standalone(u32 id)
{
decon_write_mask(id, DECON_UPDATE, ~0, DECON_UPDATE_STANDALONE_F);
}
void decon_reg_configure_lcd(u32 id, enum decon_dsi_mode dsi_mode,
struct decon_lcd *lcd_info)
{
decon_reg_set_rgb_order(id, 0, DECON_RGB);
decon_reg_set_porch(id, 0, lcd_info);
decon_reg_set_resolution(id, 0, lcd_info);
if (lcd_info->mic_enabled)
decon_reg_config_mic(id, 0, lcd_info);
if (lcd_info->mode == DECON_VIDEO_MODE)
decon_reg_set_linecnt_op_threshold(id, 0, lcd_info->yres - 1);
decon_reg_set_clkval(id, 0);
decon_reg_set_freerun_mode(id, 1);
decon_reg_direct_on_off(id, 0);
}
void decon_reg_configure_trigger(u32 id, enum decon_trig_mode mode)
{
u32 val, mask;
mask = TRIGCON_SWTRIGEN | TRIGCON_HWTRIGEN;
if (mode == DECON_SW_TRIG) {
val = TRIGCON_SWTRIGEN;
} else {
val = TRIGCON_HWTRIGEN | TRIGCON_HWTRIG_AUTO_MASK;
}
decon_write_mask(id, TRIGCON, val, mask);
}
void decon_reg_set_winmap(u32 id, u32 idx, u32 color, u32 en)
{
u32 val = en ? WIN_MAP_MAP : 0;
decon_reg_shadow_protect_win(id, idx, 1);
val |= WIN_MAP_MAP_COLOUR(color);
decon_write_mask(id, WIN_MAP(idx), val,
WIN_MAP_MAP | WIN_MAP_MAP_COLOUR_MASK);
decon_reg_shadow_protect_win(id, idx, 0);
}
u32 decon_reg_get_linecnt(u32 id, int dsi_idx)
{
return VIDCON1_LINECNT_GET(decon_read(id, VIDCON1(dsi_idx)));
}
u32 decon_reg_get_vstatus(u32 id, int dsi_idx)
{
return decon_read(id, VIDCON1(dsi_idx)) & VIDCON1_VSTATUS_MASK;
}
/* timeout : usec */
int decon_reg_wait_linecnt_is_zero_timeout(u32 id, int dsi_idx,
unsigned long timeout)
{
unsigned long delay_time = 10;
unsigned long cnt = timeout / delay_time;
u32 linecnt, vstatus;
do {
linecnt = decon_reg_get_linecnt(id, dsi_idx);
if (!linecnt) {
vstatus = decon_reg_get_vstatus(id, dsi_idx);
if (vstatus == VIDCON1_VSTATUS_IDLE)
break;
}
cnt--;
udelay(delay_time);
} while (cnt);
if (!cnt) {
decon_err("wait timeout linecount is zero(%u)\n", linecnt);
return -EBUSY;
}
return 0;
}
u32 decon_reg_get_stop_status(u32 id)
{
u32 val;
val = decon_read(id, VIDCON0);
if (val & VIDCON0_DECON_STOP_STATUS)
return 1;
return 0;
}
int decon_reg_wait_stop_status_timeout(u32 id, unsigned long timeout)
{
unsigned long delay_time = 10;
unsigned long cnt = timeout / delay_time;
u32 status;
do {
status = decon_reg_get_stop_status(id);
cnt--;
udelay(delay_time);
} while (status && cnt);
if (!cnt) {
decon_err("wait timeout decon stop status(%u)\n", status);
return -EBUSY;
}
return 0;
}
int decon_reg_is_win_enabled(u32 id, int win_idx)
{
if (decon_read(id, WINCON(win_idx)) & WINCON_ENWIN)
return 1;
return 0;
}
int decon_reg_is_shadow_updated(u32 id)
{
return 0;
}
void decon_reg_config_mic(u32 id, int dsi_idx, struct decon_lcd *lcd_info)
{
}
void decon_reg_clear_int(u32 id)
{
u32 mask;
mask = VIDINTCON1_INT_I80 | VIDINTCON1_INT_FRAME | VIDINTCON1_INT_FIFO;
decon_write_mask(id, VIDINTCON1, 0, mask);
}
void decon_reg_config_win_channel(u32 id, u32 win_idx,
enum decon_idma_type type)
{
switch (type) {
case IDMA_G0:
case IDMA_G1:
decon_write_mask(id, WINCHMAP0, WINCHMAP_DMA(type + 1, win_idx),
WINCHMAP_MASK(win_idx));
break;
case IDMA_VG0:
case IDMA_VG1:
case IDMA_VGR0:
case IDMA_VGR1:
case IDMA_G2:
case IDMA_G3:
decon_write_mask(id, WINCHMAP0, WINCHMAP_DMA(0, win_idx),
WINCHMAP_MASK(win_idx));
break;
default:
decon_err("channel(0x%x) is not valid\n", type);
return;
}
decon_dbg("decon-%s win[%d]-type[%d] WINCHMAP:%#x\n", "int",
win_idx, type, decon_read(id, WINCHMAP0));
}
/***************** CAL APIs implementation *******************/
void decon_reg_init(u32 id, enum decon_dsi_mode dsi_mode,
struct decon_init_param *p)
{
int win_idx;
struct decon_lcd *lcd_info = p->lcd_info;
struct decon_psr_info *psr = &p->psr;
decon_reg_reset(id);
decon_reg_set_clkgate_mode(id, 0);
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
decon_reg_set_vclk_divider(id, 1, 1); /* bypass decon divider */
else
decon_reg_set_vclk_divider(id, p->decon_clk->vclk_denom, p->decon_clk->vclk_num); /* set num/denom of decon divider */
decon_reg_blend_alpha_bits(id, BLENDCON_NEW_8BIT_ALPHA_VALUE);
decon_reg_set_vidout(id, psr, dsi_mode, 1);
decon_reg_set_crc(id, 0);
/* Does exynos7570 decon always use DECON_VCLK_HOLD ? No */
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
decon_reg_set_fixvclk(id, 0, DECON_VCLK_RUN_VDEN_DISABLE);
else
decon_reg_set_fixvclk(id, 0, DECON_VCLK_HOLD);
for (win_idx = 0; win_idx < p->nr_windows; win_idx++)
decon_reg_clear_win(id, win_idx);
/* RGB order -> porch values -> LINECNT_OP_THRESHOLD -> clock divider
* -> freerun mode --> stop DECON */
decon_reg_configure_lcd(id, dsi_mode, lcd_info);
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
decon_reg_configure_trigger(id, psr->trig_mode);
/* asserted interrupt should be cleared before initializing decon hw */
decon_reg_clear_int(id);
}
void decon_reg_init_probe(u32 id, enum decon_dsi_mode dsi_mode,
struct decon_init_param *p)
{
struct decon_lcd *lcd_info = p->lcd_info;
struct decon_psr_info *psr = &p->psr;
decon_reg_set_clkgate_mode(id, 0);
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
decon_reg_set_vclk_divider(id, 1, 1); /* bypass decon divider */
else
decon_reg_set_vclk_divider(id, p->decon_clk->vclk_denom, p->decon_clk->vclk_num); /* set num/denom of decon divider */
decon_reg_blend_alpha_bits(id, BLENDCON_NEW_8BIT_ALPHA_VALUE);
decon_reg_set_vidout(id, psr, dsi_mode, 1);
/* Does exynos7570 decon always use DECON_VCLK_HOLD ? */
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
decon_reg_set_fixvclk(id, 0, DECON_VCLK_RUN_VDEN_DISABLE);
else
decon_reg_set_fixvclk(id, 0, DECON_VCLK_HOLD);
decon_reg_set_rgb_order(id, 0, DECON_RGB);
decon_reg_set_porch(id, 0, lcd_info);
decon_reg_set_resolution(id, 0, lcd_info);
if (lcd_info->mic_enabled)
decon_reg_config_mic(id, 0, lcd_info);
if (lcd_info->mode == DECON_VIDEO_MODE)
decon_reg_set_linecnt_op_threshold(id, 0, lcd_info->yres - 1);
decon_reg_set_clkval(id, 0);
decon_reg_set_freerun_mode(id, 1);
decon_reg_update_standalone(id);
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
decon_reg_configure_trigger(id, psr->trig_mode);
}
void decon_reg_start(u32 id, enum decon_dsi_mode dsi_mode,
struct decon_psr_info *psr)
{
decon_reg_direct_on_off(id, 1);
decon_reg_update_standalone(id);
if ((psr->psr_mode == DECON_MIPI_COMMAND_MODE) &&
(psr->trig_mode == DECON_HW_TRIG))
decon_reg_set_trigger(id, dsi_mode, psr->trig_mode,
DECON_TRIG_ENABLE);
}
int decon_reg_stop(u32 id, enum decon_dsi_mode dsi_mode,
struct decon_psr_info *psr)
{
int ret = 0;
if ((psr->psr_mode == DECON_MIPI_COMMAND_MODE) &&
(psr->trig_mode == DECON_HW_TRIG)) {
decon_reg_set_trigger(id, dsi_mode, psr->trig_mode,
DECON_TRIG_DISABLE);
}
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE){
/* timeout : 50ms */
ret = decon_reg_wait_linecnt_is_zero_timeout(id, 0, 50 * 1000);
if (ret < 0)
goto err;
decon_reg_direct_on_off(id, 0);
} else {
decon_reg_per_frame_off(id);
}
/* set update bit */
decon_reg_update_standalone(id);
/* timeout : 30ms */
ret = decon_reg_wait_stop_status_timeout(id, 30 * 1000);
if(ret < 0){
goto err;
}
return 0;
err:
decon_err("failed to decon stop\n");
return ret;
}
void decon_reg_set_rgb_type(u32 id, int win_idx, u32 type)
{
u32 csc_eq = 0;
switch (type) {
case BT_601_NARROW:
csc_eq = WINCON_RGB_TYPE_BT601N;
break;
case BT_601_WIDE:
csc_eq = WINCON_RGB_TYPE_BT601W;
break;
default:
decon_err("Unsupported CSC Equation\n");
}
decon_dbg("win_idx: %d CSC mode : %x\n", win_idx, csc_eq);
decon_write_mask(id, WINCON(win_idx), csc_eq, (0x1 << 26));
}
void decon_reg_set_regs_data(u32 id, int win_idx,
struct decon_regs_data *regs)
{
u32 val;
if (regs->wincon & WINCON_ENWIN)
decon_reg_config_win_channel(id, win_idx, regs->type);
val = regs->wincon & WINCON_OUTSTAND_MAX_MASK;
if (val < (WINCON_OUTSTAND_MAX_DEFAULT << WINCON_OUTSTAND_MAX_POS)) {
val = regs->wincon & (~WINCON_OUTSTAND_MAX_MASK);
regs->wincon = val | (WINCON_OUTSTAND_MAX_DEFAULT <<
WINCON_OUTSTAND_MAX_POS);
}
decon_write(id, WINCON(win_idx), regs->wincon);
decon_write(id, WIN_MAP(win_idx), regs->winmap);
if (regs->winmap & WIN_MAP_MAP) {
decon_write_mask(id, WINCHMAP0, WINCHMAP_DMA(0x7, win_idx),
WINCHMAP_MASK(win_idx));
}
decon_write(id, VIDOSD_A(win_idx), regs->vidosd_a);
decon_write(id, VIDOSD_B(win_idx), regs->vidosd_b);
decon_write(id, VIDOSD_C(win_idx), regs->vidosd_c);
decon_write(id, VIDOSD_D(win_idx), regs->vidosd_d);
decon_write(id, VIDW_ADD0(win_idx), regs->vidw_buf_start);
decon_write(id, VIDW_WHOLE_X(win_idx), regs->vidw_whole_w);
decon_write(id, VIDW_WHOLE_Y(win_idx), regs->vidw_whole_h);
decon_write(id, VIDW_OFFSET_X(win_idx), regs->vidw_offset_x);
decon_write(id, VIDW_OFFSET_Y(win_idx), regs->vidw_offset_y);
decon_write(id, VIDW_ADD2(win_idx), regs->vidw_plane2_buf_start);
decon_write(id, VIDW_ADD3(win_idx), regs->vidw_plane3_buf_start);
if (win_idx)
decon_write(id, BLENDE(win_idx - 1), regs->blendeq);
decon_dbg("%s: regs->type(%d)\n", __func__, regs->type);
}
void decon_reg_set_int(u32 id, struct decon_psr_info *psr,
enum decon_dsi_mode dsi_mode, u32 en)
{
u32 val;
if (en) {
val = VIDINTCON0_INT_ENABLE | VIDINTCON0_FIFOLEVEL_EMPTY;
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE) {
decon_write_mask(id, VIDINTCON1, ~0,
VIDINTCON1_INT_I80);
val |= VIDINTCON0_INT_FIFO | VIDINTCON0_INT_I80_EN | VIDINTCON0_INT_FRAME
| VIDINTCON0_FRAMESEL0_VSYNC;
} else {
val |= VIDINTCON0_INT_FIFO | VIDINTCON0_INT_FRAME
| VIDINTCON0_FRAMESEL0_VSYNC;
}
decon_write_mask(id, VIDINTCON0, val, ~0);
} else {
decon_write_mask(id, VIDINTCON0, 0, VIDINTCON0_INT_ENABLE);
}
}
void decon_enable_eclk_idle_gate(u32 id, enum decon_set_eclk_idle_gate en)
{
u32 val = (en == DECON_ECLK_IDLE_GATE_ENABLE) ? ~0 : 0;
decon_write_mask(id, VCLKCON0, val, ECLK_IDLE_GATE_EN);
}
/* It is needed to unmask hw trigger and mask asynchronously for dual DSI */
/* enable(unmask) / disable(mask) hw trigger */
void decon_reg_set_trigger(u32 id, enum decon_dsi_mode dsi_mode,
enum decon_trig_mode trig, enum decon_set_trig en)
{
u32 val = (en == DECON_TRIG_ENABLE) ? ~0 : 0;
u32 mask;
if (trig == DECON_SW_TRIG)
mask = TRIGCON_SWTRIGCMD;
else
mask = TRIGCON_HWTRIGMASK_DISPIF0;
decon_write_mask(id, TRIGCON, val, mask);
}
/* wait until shadow update is finished */
int decon_reg_wait_for_update_timeout(u32 id, unsigned long timeout)
{
unsigned long delay_time = 100;
unsigned long cnt = timeout / delay_time;
struct decon_device *decon = get_decon_drvdata(id);
while ((decon_read(id, DECON_UPDATE) & DECON_UPDATE_STANDALONE_F) && --cnt) {
if (decon->pdata->psr_mode == DECON_MIPI_COMMAND_MODE && decon->ignore_vsync)
goto wait_exit;
udelay(delay_time);
}
if (!cnt) {
decon_err("timeout of updating decon registers\n");
return -EBUSY;
}
wait_exit:
return 0;
}
/* prohibit shadow update during writing something to SFR */
void decon_reg_shadow_protect_win(u32 id, u32 win_idx, u32 protect)
{
u32 val = protect ? ~0 : 0;
decon_write_mask(id, SHADOWCON, val, SHADOWCON_WIN_PROTECT(win_idx));
}
/* enable each window */
void decon_reg_activate_window(u32 id, u32 index)
{
decon_write_mask(id, WINCON(index), ~0, WINCON_ENWIN);
decon_reg_update_standalone(id);
}
void decon_reg_set_block_mode(u32 id, u32 win_idx, u32 x, u32 y, u32 w,
u32 h, u32 en)
{
u32 val = en ? ~0 : 0;
u32 blk_offset = 0, blk_size = 0;
blk_offset = VIDW_BLKOFFSET_Y_F(y) | VIDW_BLKOFFSET_X_F(x);
blk_size = VIDW_BLKSIZE_W_F(w) | VIDW_BLKSIZE_H_F(h);
decon_write_mask(id, VIDW_BLKOFFSET(win_idx), blk_offset,
VIDW_BLKOFFSET_MASK);
decon_write_mask(id, VIDW_BLKSIZE(win_idx), blk_size,
VIDW_BLKSIZE_MASK);
decon_write_mask(id, WINCON(win_idx), val, WINCON_BLK_EN_F);
}
void decon_reg_set_tui_va(u32 id, u32 va)
{
decon_write(id, VIDW_ADD2(6), va);
}
/* DECON disp i/f size is defined VIDTCON5 sfr instead of VIDTCON4 */
u32 decon_reg_get_lineval(u32 id, int dsi_idx, struct decon_lcd *lcd_info)
{
u32 val;
if (lcd_info->mode == DECON_VIDEO_MODE)
val = decon_read(id, VIDTCON4(dsi_idx) + SHADOW_OFFSET);
else
val = decon_read(id, VIDTCON5(dsi_idx) + SHADOW_OFFSET);
return VIDTCONx_LINEVAL_GET(val) + 1;
}
u32 decon_reg_get_hozval(u32 id, int dsi_idx, struct decon_lcd *lcd_info)
{
u32 val;
if (lcd_info->mode == DECON_VIDEO_MODE)
val = decon_read(id, VIDTCON4(dsi_idx) + SHADOW_OFFSET);
else
val = decon_read(id, VIDTCON5(dsi_idx) + SHADOW_OFFSET);
return VIDTCONx_HOZVAL_GET(val) + 1;
}

View file

@ -0,0 +1,259 @@
/* linux/drivers/video/fbdev/exynos/decon_7570/dsim.h
*
* Header file for Samsung MIPI-DSI common driver.
*
* Copyright (c) 2015 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_DDI_ID_LEN 3
#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;
#define PANEL_STATE_SUSPENED 0
#define PANEL_STATE_RESUMED 1
#define PANEL_STATE_SUSPENDING 2
#define PANEL_DISCONNEDTED 0
#define PANEL_CONNECTED 1
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 */
};
#ifdef CONFIG_EXYNOS_MIPI_DSI_ENABLE_EARLY
enum dsim_enable_early {
DSIM_ENABLE_EARLY_NORMAL,
DSIM_ENABLE_EARLY_REQUEST,
DSIM_ENABLE_EARLY_DONE
};
#endif
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 {
unsigned int lcdConnected;
void *par;
};
struct dsim_device {
struct device *dev;
void *decon;
struct dsim_resources res;
unsigned int irq;
void __iomem *reg_base;
enum dsim_state state;
#ifdef CONFIG_EXYNOS_MIPI_DSI_ENABLE_EARLY
enum dsim_enable_early enable_early;
#endif
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;
int octa_id;
#ifdef CONFIG_EXYNOS_MIPI_DSI_ENABLE_EARLY
s64 reset_start_time;
int resume_request;
struct notifier_block pm_notifier;
#endif
};
/**
* 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 (*early_probe)(struct dsim_device *dsim);
int (*probe)(struct dsim_device *dsim);
int (*suspend)(struct dsim_device *dsim);
int (*displayon)(struct dsim_device *dsim);
int (*displayon_late)(struct dsim_device *dsim);
int (*resume_early)(struct dsim_device *dsim);
int (*resume)(struct dsim_device *dsim);
int (*dump)(struct dsim_device *dsim);
#ifdef CONFIG_EXYNOS_MIPI_DSI_ENABLE_EARLY
int (*resume_reason)(struct dsim_device *dsim);
#endif
};
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
#ifdef CONFIG_EXYNOS_MIPI_DSI_ENABLE_EARLY
void dsim_resume_event(int event);
#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)
#define DSIM_IOC_VSYNC _IOW('D', 9, u32)
#endif /* __DSIM_H__ */

View file

@ -0,0 +1,210 @@
/* dsim_common.h
*
* Header file for Samsung MIPI-DSI lowlevel driver.
*
* Copyright (c) 2015 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 DSIM_RX_FIFO_MAX_DEPTH 64
/* 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),
};
/* DSI Error report bit definitions */
enum {
MIPI_DSI_ERR_SOT = (1 << 0),
MIPI_DSI_ERR_SOT_SYNC = (1 << 1),
MIPI_DSI_ERR_EOT_SYNC = (1 << 2),
MIPI_DSI_ERR_ESCAPE_MODE_ENTRY_CMD = (1 << 3),
MIPI_DSI_ERR_LOW_POWER_TRANSMIT_SYNC = (1 << 4),
MIPI_DSI_ERR_HS_RECEIVE_TIMEOUT = (1 << 5),
MIPI_DSI_ERR_FALSE_CONTROL = (1 << 6),
MIPI_DSI_ERR_CONTENTION_DETECTED = (1 << 7),
MIPI_DSI_ERR_ECC_SINGLE_BIT = (1 << 8),
MIPI_DSI_ERR_ECC_MULTI_BIT = (1 << 9),
MIPI_DSI_ERR_CHECKSUM = (1 << 10),
MIPI_DSI_ERR_DATA_TYPE_NOT_RECOGNIZED = (1 << 11),
MIPI_DSI_ERR_VCHANNEL_ID_INVALID = (1 << 12),
MIPI_DSI_ERR_INVALID_TRANSMIT_LENGTH = (1 << 13),
/* Bit 14 is reserved */
MIPI_DSI_ERR_PROTOCAL_VIOLATION = (1 << 15),
/* DSI_PROTOCAL_VIOLATION[15] is for protocol violation that is caused EoTp
* missing So this bit is egnored because of not supportung @S.LSI AP */
/* FALSE_ERROR_CONTROL[6] is for detect invalid escape or turnaround sequence.
* This bit is not supporting @S.LSI AP because of non standard
* ULPS enter/exit sequence during power-gating */
/* Bit [14] is reserved */
};
/* define DSI escape clock types. */
enum {
DSIM_ESCCLK_CLOCK = (1 << 4),
DSIM_ESCCLK_DATA0 = (1 << 0),
DSIM_ESCCLK_DATA1 = (1 << 1),
DSIM_ESCCLK_DATA2 = (1 << 2),
DSIM_ESCCLK_DATA3 = (1 << 3),
};
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);
/* RX related APIs list */
u32 dsim_reg_rx_fifo_is_empty(u32 id);
u32 dsim_reg_get_rx_fifo(u32 id);
int dsim_reg_rx_err_handler(u32 id, u32 rx_fifo);
/* 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,26 @@
config EXYNOS_DECON_LCD
depends on EXYNOS_DECON_7570
bool "Select LCD panel driver"
config EXYNOS_DECON_LCD_SYSFS
depends on EXYNOS_DECON_LCD
tristate "Support LCD SYSFS"
default y
config PANEL_AID_DIMMING
depends on EXYNOS_DECON_LCD
tristate "Support AID Dimming"
default n
config EXYNOS_DECON_MDNIE_LITE
depends on EXYNOS_DECON_LCD
tristate "Support MDNIE LITE"
default n
config PANEL_S6E8AA5X01
depends on EXYNOS_DECON_LCD
bool "S6E8AA5X01 AMOLE HD LCD driver(720 x 1280)"
config PANEL_TD4100
depends on EXYNOS_DECON_LCD
bool "TD4100 TFT INCELL HD LCD driver(720 x 1280)"

View file

@ -0,0 +1,5 @@
obj-$(CONFIG_EXYNOS_DECON_LCD) += dsim_panel.o
obj-$(CONFIG_EXYNOS_DECON_MDNIE_LITE) += mdnie_lite.o mdnie_tuning.o
obj-$(CONFIG_PANEL_S6E8AA5X01) += s6e8aa5x01_lcd_ctrl.o dimming_core.o
obj-$(CONFIG_PANEL_TD4100) += td4100_lcd_ctrl.o

View file

@ -0,0 +1,61 @@
/* linux/drivers/video/exynos_decon/panel/aid_dimming.h
*
* Header file for Samsung AID Dimming Driver.
*
* Copyright (c) 2013 Samsung Electronics
* Minwoo Kim <minwoo7945.kim@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 __AID_DIMMING_H__
#define __AID_DIMMING_H__
#if defined(CONFIG_PANEL_S6E8AA5X01)
#include "s6e8aa5x01_dimming.h"
#else
#error "ERROR !! Check LCD Panel Header File"
#endif
#define DIMMING_METHOD_AID 0
#define DIMMING_METHOD_FILL_CENTER 1
#define DIMMING_METHOD_INTERPOLATION 2
#define DIMMING_METHOD_FILL_HBM 3
#define DIMMING_METHOD_MAX 4
#define W1 DIMMING_METHOD_AID
#define W2 DIMMING_METHOD_FILL_CENTER
#define W3 DIMMING_METHOD_INTERPOLATION
#define W4 DIMMING_METHOD_FILL_HBM
enum {
CI_RED = 0,
CI_GREEN,
CI_BLUE,
CI_MAX,
};
struct dim_data {
int t_gamma[NUM_VREF][CI_MAX];
int mtp[NUM_VREF][CI_MAX];
int volt[MAX_GRADATION][CI_MAX];
int volt_vt[CI_MAX];
int vt_mtp[CI_MAX];
int look_volt[NUM_VREF][CI_MAX];
};
struct SmtDimInfo {
unsigned int br;
signed char *cTbl;
unsigned char *aid;
unsigned char *elvAcl;
unsigned char *elv;
unsigned char *m_gray;
unsigned char gamma[OLED_CMD_GAMMA_CNT];
unsigned int way;
};
#endif

View file

@ -0,0 +1,84 @@
/* 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 dsim_vfp;
unsigned int dsim_vbp;
unsigned int dsim_hfp;
unsigned int dsim_hbp;
unsigned int dsim_vsa;
unsigned int dsim_hsa;
unsigned int decon_vfp;
unsigned int decon_vbp;
unsigned int decon_hfp;
unsigned int decon_hbp;
unsigned int decon_vsa;
unsigned int decon_hsa;
unsigned int xres;
unsigned int yres;
unsigned int width;
unsigned int height;
unsigned int dispif_w;
unsigned int dispif_h;
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;
unsigned int clklane_onoff;
};
#endif

View file

@ -0,0 +1,733 @@
/* linux/drivers/video/exynos_decon/panel/dimming_core.c
*
* Header file for Samsung AID Dimming Driver.
*
* Copyright (c) 2013 Samsung Electronics
* Minwoo Kim <minwoo7945.kim@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 "dimming_core.h"
static int calc_vt_volt(int gamma)
{
int max;
max = (sizeof(vt_trans_volt) >> 2) - 1;
if (gamma > max) {
dimm_err("%s : exceed gamma value\n", __func__);
gamma = max;
}
return (int)vt_trans_volt[gamma];
}
static int calc_v0_volt(struct dim_data *data, int color)
{
return DOUBLE_MULTIPLE_VREGOUT;
}
static int calc_v3_volt(struct dim_data *data, int color)
{
int gap;
int ret, v11, gamma;
unsigned long temp;
gamma = data->t_gamma[V3][color];
if (gamma > vreg_element_max[V3]) {
dimm_err("%s : gamma overflow : %d\n", __func__, gamma);
gamma = vreg_element_max[V3];
}
if (gamma < 0) {
dimm_err("%s : gamma undeflow : %d\n", __func__, gamma);
gamma = 0;
}
v11 = data->volt[TBL_INDEX_V11][color];
gap = (DOUBLE_MULTIPLE_VREGOUT - v11);
temp = (unsigned long)gap * (unsigned long)v203_trans_volt[gamma];
temp >>= 10;
ret = DOUBLE_MULTIPLE_VREGOUT - (int)temp;
return ret;
}
static int calc_v11_volt(struct dim_data *data, int color)
{
int gap;
int vt, ret, v23, gamma;
unsigned long temp;
gamma = data->t_gamma[V11][color];
if (gamma > vreg_element_max[V11]) {
dimm_err("%s : gamma overflow : %d\n", __func__, gamma);
gamma = vreg_element_max[V11];
}
if (gamma < 0) {
dimm_err("%s : gamma undeflow : %d\n", __func__, gamma);
gamma = 0;
}
vt = data->volt_vt[color];
v23 = data->volt[TBL_INDEX_V23][color];
gap = vt - v23;
temp = (unsigned long)gap * (unsigned long)v203_trans_volt[gamma];
temp = temp >> 10;
ret = vt - (int)temp;
return ret;
}
static int calc_v23_volt(struct dim_data *data, int color)
{
int gap;
int vt, ret, v35, gamma;
unsigned long temp;
gamma = data->t_gamma[V23][color];
if (gamma > vreg_element_max[V23]) {
dsim_err("%s : gamma overflow : %d\n", __func__, gamma);
gamma = vreg_element_max[V23];
}
if (gamma < 0) {
dsim_err("%s : gamma undeflow : %d\n", __func__, gamma);
gamma = 0;
}
vt = data->volt_vt[color];
v35 = data->volt[TBL_INDEX_V35][color];
gap = vt - v35;
temp = (unsigned long)gap * (unsigned long)v203_trans_volt[gamma];
temp = temp >> 10;
ret = vt - (int)temp;
return ret;
}
static int calc_v35_volt(struct dim_data *data, int color)
{
int gap;
int vt, ret, v51, gamma;
unsigned long temp;
gamma = data->t_gamma[V35][color];
if (gamma > vreg_element_max[V35]) {
dsim_err("%s : gamma overflow : %d\n", __func__, gamma);
gamma = vreg_element_max[V35];
}
if (gamma < 0) {
dsim_err("%s : gamma undeflow : %d\n", __func__, gamma);
gamma = 0;
}
vt = data->volt_vt[color];
v51 = data->volt[TBL_INDEX_V51][color];
gap = vt - v51;
temp = (unsigned long)gap * (unsigned long)v203_trans_volt[gamma];
temp = temp >> 10;
ret = vt - (int)temp;
return ret;
}
static int calc_v51_volt(struct dim_data *data, int color)
{
int gap;
int vt, ret, v87, gamma;
unsigned long temp;
gamma = data->t_gamma[V51][color];
if (gamma > vreg_element_max[V51]) {
dsim_err("%s : gamma overflow : %d\n", __func__, gamma);
gamma = vreg_element_max[V51];
}
if (gamma < 0) {
dsim_err("%s : gamma undeflow : %d\n", __func__, gamma);
gamma = 0;
}
vt = data->volt_vt[color];
v87 = data->volt[TBL_INDEX_V87][color];
gap = vt - v87;
temp = (unsigned long)gap * (unsigned long)v203_trans_volt[gamma];
temp = temp >> 10;
ret = vt - (int)temp;
return ret;
}
static int calc_v87_volt(struct dim_data *data, int color)
{
int gap;
int vt, ret, v151, gamma;
unsigned long temp;
gamma = data->t_gamma[V87][color];
if (gamma > vreg_element_max[V87]) {
dsim_err("%s : gamma overflow : %d\n", __func__, gamma);
gamma = vreg_element_max[V87];
}
if (gamma < 0) {
dsim_err("%s : gamma undeflow : %d\n", __func__, gamma);
gamma = 0;
}
vt = data->volt_vt[color];
v151 = data->volt[TBL_INDEX_V151][color];
gap = vt - v151;
temp = (unsigned long)gap * (unsigned long)v203_trans_volt[gamma];
temp = temp >> 10;
ret = vt - (int)temp;
return ret;
}
static int calc_v151_volt(struct dim_data *data, int color)
{
int gap;
int vt, ret, v203, gamma;
unsigned long temp;
gamma = data->t_gamma[V151][color];
if (gamma > vreg_element_max[V151]) {
dsim_err("%s : gamma overflow : %d\n", __func__, gamma);
gamma = vreg_element_max[V151];
}
if (gamma < 0) {
dsim_err("%s : gamma undeflow : %d\n", __func__, gamma);
gamma = 0;
}
vt = data->volt_vt[color];
v203 = data->volt[TBL_INDEX_V203][color];
gap = vt - v203;
temp = (unsigned long)gap * (unsigned long)v203_trans_volt[gamma];
temp = temp >> 10;
ret = vt - (int)temp;
return ret;
}
static int calc_v203_volt(struct dim_data *data, int color)
{
int gap;
int vt, ret, v255, gamma;
unsigned long temp;
gamma = data->t_gamma[V203][color];
if (gamma > vreg_element_max[V203]) {
dsim_err("%s : gamma overflow : %d\n", __func__, gamma);
gamma = vreg_element_max[V203];
}
if (gamma < 0) {
dsim_err("%s : gamma undeflow : %d\n", __func__, gamma);
gamma = 0;
}
vt = data->volt_vt[color];
v255 = data->volt[TBL_INDEX_V255][color];
gap = vt - v255;
temp = (unsigned long)gap * (unsigned long)v203_trans_volt[gamma];
temp = temp >> 10;
ret = vt - (int)temp;
return ret;
}
static int calc_v255_volt(struct dim_data *data, int color)
{
int ret, gamma;
gamma = data->t_gamma[V255][color];
if (gamma > vreg_element_max[V255]) {
dsim_err("%s : gamma overflow : %d\n", __func__, gamma);
gamma = vreg_element_max[V255];
}
if (gamma < 0) {
dsim_err("%s : gamma undeflow : %d\n", __func__, gamma);
gamma = 0;
}
ret = (int)v255_trans_volt[gamma];
return ret;
}
static int calc_inter_v0_v3(struct dim_data *data, int gray, int color)
{
int ret = 0;
int v0, v3, ratio, temp;
ratio = (int)int_tbl_v0_v3[gray];
v0 = data->volt[TBL_INDEX_V0][color];
v3 = data->volt[TBL_INDEX_V3][color];
temp = (v0 - v3) * ratio;
temp >>= 10;
ret = v0 - temp;
return ret;
}
static int calc_inter_v3_v11(struct dim_data *data, int gray, int color)
{
int ret = 0;
int v3, v11, ratio, temp;
ratio = (int)int_tbl_v3_v11[gray];
v3 = data->volt[TBL_INDEX_V3][color];
v11 = data->volt[TBL_INDEX_V11][color];
temp = (v3 - v11) * ratio;
temp >>= 10;
ret = v3 - temp;
return ret;
}
static int calc_inter_v11_v23(struct dim_data *data, int gray, int color)
{
int ret = 0;
int v11, v23, ratio, temp;
ratio = (int)int_tbl_v11_v23[gray];
v11 = data->volt[TBL_INDEX_V11][color];
v23 = data->volt[TBL_INDEX_V23][color];
temp = (v11 - v23) * ratio;
temp >>= 10;
ret = v11 - temp;
return ret;
}
static int calc_inter_v23_v35(struct dim_data *data, int gray, int color)
{
int ret = 0;
int v23, v35, ratio, temp;
ratio = (int)int_tbl_v23_v35[gray];
v23 = data->volt[TBL_INDEX_V23][color];
v35 = data->volt[TBL_INDEX_V35][color];
temp = (v23 - v35) * ratio;
temp >>= 10;
ret = v23 - temp;
return ret;
}
static int calc_inter_v35_v51(struct dim_data *data, int gray, int color)
{
int ret = 0;
int v35, v51, ratio, temp;
ratio = (int)int_tbl_v35_v51[gray];
v35 = data->volt[TBL_INDEX_V35][color];
v51 = data->volt[TBL_INDEX_V51][color];
temp = (v35 - v51) * ratio;
temp >>= 10;
ret = v35 - temp;
return ret;
}
static int calc_inter_v51_v87(struct dim_data *data, int gray, int color)
{
int ret = 0;
int v51, v87, ratio, temp;
ratio = (int)int_tbl_v51_v87[gray];
v51 = data->volt[TBL_INDEX_V51][color];
v87 = data->volt[TBL_INDEX_V87][color];
temp = (v51 - v87) * ratio;
temp >>= 10;
ret = v51 - temp;
return ret;
}
static int calc_inter_v87_v151(struct dim_data *data, int gray, int color)
{
int ret = 0;
int v87, v151, ratio, temp;
ratio = (int)int_tbl_v87_v151[gray];
v87 = data->volt[TBL_INDEX_V87][color];
v151 = data->volt[TBL_INDEX_V151][color];
temp = (v87 - v151) * ratio;
temp >>= 10;
ret = v87 - temp;
return ret;
}
static int calc_inter_v151_v203(struct dim_data *data, int gray, int color)
{
int ret = 0;
int v151, v203, ratio, temp;
ratio = (int)int_tbl_v151_v203[gray];
v151 = data->volt[TBL_INDEX_V151][color];
v203 = data->volt[TBL_INDEX_V203][color];
temp = (v151 - v203) * ratio;
temp >>= 10;
ret = v151 - temp;
return ret;
}
static int calc_inter_v203_v255(struct dim_data *data, int gray, int color)
{
int ret = 0;
int v203, v255, ratio, temp;
ratio = (int)int_tbl_v203_v255[gray];
v203 = data->volt[TBL_INDEX_V203][color];
v255 = data->volt[TBL_INDEX_V255][color];
temp = (v203 - v255) * ratio;
temp >>= 10;
ret = v203 - temp;
return ret;
}
int generate_volt_table(struct dim_data *data)
{
int i, j;
int seq, index, gray;
int ret = 0;
int calc_seq[NUM_VREF] = {V0, V255, V203, V151, V87, V51, V35, V23, V11, V3};
int (*calc_volt_point[NUM_VREF])(struct dim_data *, int) = {
calc_v0_volt,
calc_v3_volt,
calc_v11_volt,
calc_v23_volt,
calc_v35_volt,
calc_v51_volt,
calc_v87_volt,
calc_v151_volt,
calc_v203_volt,
calc_v255_volt,
};
int (*calc_inter_volt[NUM_VREF])(struct dim_data *, int, int) = {
NULL,
calc_inter_v0_v3,
calc_inter_v3_v11,
calc_inter_v11_v23,
calc_inter_v23_v35,
calc_inter_v35_v51,
calc_inter_v51_v87,
calc_inter_v87_v151,
calc_inter_v151_v203,
calc_inter_v203_v255,
};
for (i = 0; i < CI_MAX; i++) {
data->volt_vt[i] = calc_vt_volt(data->vt_mtp[i]);
}
/* calculate voltage for every vref point */
for (j = 0; j < NUM_VREF; j++) {
seq = calc_seq[j];
index = vref_index[seq];
if (calc_volt_point[seq] != NULL) {
for (i = 0; i < CI_MAX; i++)
data->volt[index][i] = calc_volt_point[seq](data, i);
}
}
index = 0;
for (i = 0; i < MAX_GRADATION; i++) {
if (i == vref_index[index]) {
index++;
continue;
}
gray = (i - vref_index[index - 1]) - 1;
for (j = 0; j < CI_MAX; j++) {
if (calc_inter_volt[index] != NULL) {
data->volt[i][j] = calc_inter_volt[index](data, gray, j);
}
}
}
#if defined(SMART_DIMMING_DEBUG)
dsim_info("=========================== VT Voltage ===========================\n");
dsim_info("R : %05d : G: %05d : B : %05d\n",
data->volt_vt[0], data->volt_vt[1], data->volt_vt[2]);
dsim_info("\n=================================================================\n");
for (i = 0; i < MAX_GRADATION; i++) {
dsim_info("V%03d R : %05d : G : %05d B : %05d\n", i,
data->volt[i][CI_RED], data->volt[i][CI_GREEN], data->volt[i][CI_BLUE]);
}
#endif
return ret;
}
static int calc_reg_v3(struct dim_data *data, int color)
{
int ret;
int t1, t2;
unsigned long temp;
t1 = DOUBLE_MULTIPLE_VREGOUT - data->look_volt[V3][color];
t2 = DOUBLE_MULTIPLE_VREGOUT - data->look_volt[V11][color];
temp = ((unsigned long)t1 * (unsigned long)fix_const[V3].de) / (unsigned long)t2;
ret = temp - fix_const[V3].nu;
return ret;
}
static int calc_reg_v11(struct dim_data *data, int color)
{
int ret;
int t1, t2;
unsigned long temp;
t1 = data->volt_vt[color] - data->look_volt[V11][color];
t2 = data->volt_vt[color] - data->look_volt[V23][color];
temp = ((unsigned long)t1 * (unsigned long)fix_const[V11].de) / (unsigned long)t2;
ret = (int)temp - fix_const[V11].nu;
return ret;
}
static int calc_reg_v23(struct dim_data *data, int color)
{
int ret;
int t1, t2;
unsigned long temp;
t1 = data->volt_vt[color] - data->look_volt[V23][color];
t2 = data->volt_vt[color] - data->look_volt[V35][color];
temp = ((unsigned long)t1 * (unsigned long)fix_const[V23].de) / (unsigned long)t2;
ret = (int)temp - fix_const[V23].nu;
return ret;
}
static int calc_reg_v35(struct dim_data *data, int color)
{
int ret;
int t1, t2;
unsigned long temp;
t1 = data->volt_vt[color] - data->look_volt[V35][color];
t2 = data->volt_vt[color] - data->look_volt[V51][color];
temp = ((unsigned long)t1 * (unsigned long)fix_const[V35].de) / (unsigned long)t2;
ret = (int)temp - fix_const[V35].nu;
return ret;
}
static int calc_reg_v51(struct dim_data *data, int color)
{
int ret;
int t1, t2;
unsigned long temp;
t1 = data->volt_vt[color] - data->look_volt[V51][color];
t2 = data->volt_vt[color] - data->look_volt[V87][color];
temp = ((unsigned long)t1 * (unsigned long)fix_const[V51].de) / (unsigned long)t2;
ret = (int)temp - fix_const[V51].nu;
return ret;
}
static int calc_reg_v87(struct dim_data *data, int color)
{
int ret;
int t1, t2;
unsigned long temp;
t1 = data->volt_vt[color] - data->look_volt[V87][color];
t2 = data->volt_vt[color] - data->look_volt[V151][color];
temp = ((unsigned long)t1 * (unsigned long)fix_const[V87].de) / (unsigned long)t2;
ret = (int)temp - fix_const[V87].nu;
return ret;
}
static int calc_reg_v151(struct dim_data *data, int color)
{
int ret;
int t1, t2;
unsigned long temp;
t1 = data->volt_vt[color] - data->look_volt[V151][color];
t2 = data->volt_vt[color] - data->look_volt[V203][color];
temp = ((unsigned long)t1 * (unsigned long)fix_const[V151].de) / (unsigned long)t2;
ret = (int)temp - fix_const[V151].nu;
return ret;
}
static int calc_reg_v203(struct dim_data *data, int color)
{
int ret;
int t1, t2;
unsigned long temp;
t1 = data->volt_vt[color] - data->look_volt[V203][color];
t2 = data->volt_vt[color] - data->look_volt[V255][color];
temp = ((unsigned long)t1 * (unsigned long)fix_const[V203].de) / (unsigned long)t2;
ret = (int)temp - fix_const[V203].nu;
return ret;
}
static int calc_reg_v255(struct dim_data *data, int color)
{
int ret;
int t1;
unsigned long temp;
t1 = DOUBLE_MULTIPLE_VREGOUT - data->look_volt[V255][color];
temp = ((unsigned long)t1 * (unsigned long)fix_const[V255].de) / DOUBLE_MULTIPLE_VREGOUT;
ret = (int)temp - fix_const[V255].nu;
return ret;
}
int cal_gamma_from_index(struct dim_data *data, struct SmtDimInfo *brInfo)
{
int i, j, iv_min;
int ret = 0;
int index = 255;
signed int c_shift;
int gamma_int[NUM_VREF][CI_MAX];
int temp;
unsigned char *result;
int (*calc_reg[NUM_VREF])(struct dim_data *, int) = {
NULL,
calc_reg_v3,
calc_reg_v11,
calc_reg_v23,
calc_reg_v35,
calc_reg_v51,
calc_reg_v87,
calc_reg_v151,
calc_reg_v203,
calc_reg_v255,
};
result = brInfo->gamma;
for (i = V3; i < NUM_VREF; i++) {
if (brInfo->m_gray)
index = brInfo->m_gray[i];
for (j = 0; j < CI_MAX; j++) {
if (calc_reg[i] != NULL) {
data->look_volt[i][j] = data->volt[index][j];
}
}
}
for (i = V3; i < NUM_VREF; i++) {
for (j = 0; j < CI_MAX; j++) {
if (calc_reg[i] != NULL) {
index = (i * CI_MAX) + j;
#ifdef CONFIG_COLOR_SHIFT
if (brInfo->cTbl == NULL)
c_shift = 0;
else
c_shift = (signed int)brInfo->cTbl[index];
#else
c_shift = 0;
#endif
temp = calc_reg[i](data, j);
gamma_int[i][j] = (temp + c_shift) - data->mtp[i][j];
if (gamma_int[i][j] >= vreg_element_max[i])
gamma_int[i][j] = vreg_element_max[i];
if (gamma_int[i][j] < 0)
gamma_int[i][j] = 0;
}
}
}
for (j = 0; j < CI_MAX; j++) {
//gamma_int[VT][j] = data->mtp_gamma[VT][j];
gamma_int[VT][j] = data->t_gamma[VT][j] - data->mtp[VT][j];
}
index = 0;
result[index++] = OLED_CMD_GAMMA;
#ifdef HAS_NO_V0_GAMMA
iv_min = V0 + 1; /* for (i = V255; i > V0; i--) { */
#else
iv_min = V0; /* for (i = V255; i >= V0; i--) { */
#endif
for (i = V255; i >= iv_min; i--) {
for (j = 0; j < CI_MAX; j++) {
if (i == V255) {
result[index++] = gamma_int[i][j] > 0xff ? 1 : 0;
result[index++] = gamma_int[i][j] & 0xff;
} else {
result[index++] = (unsigned char)gamma_int[i][j];
}
}
}
//result[index++] = data->vt_mtp[CI_RED] | (data->vt_mtp[CI_GREEN] << 4);
//result[index++] = data->vt_mtp[CI_BLUE] & 0x0f;
result[index++] = 0x00;
result[index++] = 0x00;
return ret;
}

View file

@ -0,0 +1,42 @@
/* linux/drivers/video/exynos_decon/panel/dimming_core.h
*
* Header file for Samsung AID Dimming Driver.
*
* Copyright (c) 2013 Samsung Electronics
* Minwoo Kim <minwoo7945.kim@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 __DIMMING_CORE_H__
#define __DIMMING_CORE_H__
//#define SMART_DIMMING_DEBUG
#define CONFIG_REF_SHIFT
#define CONFIG_COLOR_SHIFT
#include "../dsim.h"
#include "aid_dimming.h"
#define dimm_err(fmt, ...) \
do { \
pr_err(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define dimm_info(fmt, ...) \
do { \
pr_info(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define dimm_dbg(fmt, ...) \
do { \
pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
int generate_volt_table(struct dim_data *data);
int cal_gamma_from_index(struct dim_data *data, struct SmtDimInfo *brInfo);
#endif

View file

@ -0,0 +1,48 @@
/* linux/drivers/video/fbdev/exynos/decon/panels/dsim_panel.c
*
* Copyright (c) 2015 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.
*/
#include <linux/lcd.h>
#include "../dsim.h"
#include "dsim_panel.h"
#if defined(CONFIG_PANEL_S6E8AA5X01)
struct mipi_dsim_lcd_driver *mipi_lcd_driver = &s6e8aa5x01_mipi_lcd_driver;
#elif defined(CONFIG_PANEL_TD4100)
struct mipi_dsim_lcd_driver *mipi_lcd_driver = &td4100_mipi_lcd_driver;
#endif
int dsim_panel_ops_init(struct dsim_device *dsim)
{
int ret = 0;
if (dsim)
dsim->panel_ops = mipi_lcd_driver;
return ret;
}
unsigned int lcdtype;
EXPORT_SYMBOL(lcdtype);
static int __init get_lcd_type(char *arg)
{
get_option(&arg, &lcdtype);
dsim_info("--- Parse LCD TYPE ---\n");
dsim_info("LCDTYPE : %08x\n", lcdtype);
return 0;
}
early_param("lcdtype", get_lcd_type);

View file

@ -0,0 +1,27 @@
/* linux/drivers/video/exynos_decon/panel/dsim_panel.h
*
* Header file for Samsung MIPI-DSI LCD Panel driver.
*
* Copyright (c) 2013 Samsung Electronics
* Minwoo Kim <minwoo7945.kim@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_PANEL__
#define __DSIM_PANEL__
extern unsigned int lcdtype;
#if defined(CONFIG_PANEL_S6E8AA5X01)
extern struct mipi_dsim_lcd_driver s6e8aa5x01_mipi_lcd_driver;
#elif defined(CONFIG_PANEL_TD4100)
extern struct mipi_dsim_lcd_driver td4100_mipi_lcd_driver;
#endif
int dsim_panel_ops_init(struct dsim_device *dsim);
#endif

View file

@ -0,0 +1,360 @@
/* linux/drivers/video/backlight/dynamic_aid.c
*
* Samsung Electronics Dynamic AID for AMOLED.
*
* Copyright (c) 2013 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/ctype.h>
#include "dynamic_aid.h"
#ifdef DYNAMIC_AID_DEBUG
#define aid_dbg(format, arg...) printk(format, ##arg)
#else
#define aid_dbg(format, arg...)
#endif
struct rgb64_t {
s64 rgb[3];
};
struct dynamic_aid_info {
struct dynamic_aid_param_t param;
int *iv_tbl;
int iv_max;
int iv_top;
int *ibr_tbl;
int ibr_max;
int *mtp;
int vreg;
int vref_h;
struct rgb64_t *point_voltages;
struct rgb64_t *output_voltages;
struct rgb64_t *m_voltage;
};
#define MUL_100(x) (x*100)
#define MUL_1000(x) (x*1000)
#define MUL_10000(x) (x*10000)
#define DIV_10(x) ((x+5)/10)
#define DIV_100(x) ((x+50)/100)
static int calc_point_voltages(struct dynamic_aid_info d_aid)
{
int ret, iv, c, iv_ref;
struct rgb64_t *vt, *vp;
int *vd, *mtp;
int numerator, denominator;
s64 vreg, vb;
s64 t1, t2;
struct rgb64_t *point_voltages;
point_voltages = d_aid.point_voltages;
vreg = d_aid.vreg;
ret = 0;
/* iv == 0; */
{
vd = (int *)&d_aid.param.gamma_default[0];
mtp = &d_aid.mtp[0];
numerator = d_aid.param.formular[0].numerator;
denominator = d_aid.param.formular[0].denominator;
for (c = 0; c < CI_MAX; c++) {
t1 = vreg;
t2 = vreg*d_aid.param.vt_voltage_value[vd[c] + mtp[c]];
point_voltages[0].rgb[c] = t1 - div_s64(t2, denominator);
}
}
iv = d_aid.iv_max - 1;
/* iv == (IV_MAX-1) ~ 1; */
for (; iv > 0; iv--) {
vt = &point_voltages[0];
vp = &point_voltages[iv+1];
vd = (int *)&d_aid.param.gamma_default[iv*CI_MAX];
mtp = &d_aid.mtp[iv*CI_MAX];
iv_ref = d_aid.param.iv_ref[iv];
numerator = d_aid.param.formular[iv].numerator;
denominator = d_aid.param.formular[iv].denominator;
for (c = 0; c < CI_MAX; c++) {
vb = (iv_ref < d_aid.iv_max) ? point_voltages[iv_ref].rgb[c] : vreg;
if (iv == d_aid.iv_max - 1) {
t1 = vb;
t2 = vb - d_aid.vref_h;
} else {
t1 = vb;
t2 = vb - vp->rgb[c];
}
t2 *= vd[c] + mtp[c] + numerator;
point_voltages[iv].rgb[c] = (t1 - div_s64(t2, denominator));
}
}
#ifdef DYNAMIC_AID_DEBUG
for (iv = 0; iv < d_aid.iv_max; iv++) {
aid_dbg("Point Voltage[%d] = ", iv);
for (c = 0; c < CI_MAX; c++)
aid_dbg("%lld ", point_voltages[iv].rgb[c]);
aid_dbg("\n");
}
#endif
return ret;
}
static int calc_output_voltages(struct dynamic_aid_info d_aid)
{
int iv, i, c;
int v_idx, v_cnt;
struct rgb_t v, v_diff;
struct rgb64_t *output_voltages;
struct rgb64_t *point_voltages;
output_voltages = d_aid.output_voltages;
point_voltages = d_aid.point_voltages;
iv = d_aid.iv_max - 1;
for (c = 0; c < CI_MAX; c++)
output_voltages[0].rgb[c] = d_aid.vreg;
/* iv == (IV_MAX-1) ~ 0; */
for (; iv > 0; iv--) {
v_cnt = d_aid.iv_tbl[iv] - d_aid.iv_tbl[iv-1];
v_idx = d_aid.iv_tbl[iv];
for (c = 0; c < CI_MAX; c++) {
v.rgb[c] = point_voltages[iv].rgb[c];
v_diff.rgb[c] = point_voltages[iv-1].rgb[c] - point_voltages[iv].rgb[c];
}
for (i = 0; i < v_cnt; i++, v_idx--) {
for (c = 0; c < CI_MAX; c++)
output_voltages[v_idx].rgb[c] = v.rgb[c] + v_diff.rgb[c]*i/v_cnt;
}
}
#ifdef DYNAMIC_AID_DEBUG
for (iv = 0; iv <= d_aid.iv_top; iv++) {
aid_dbg("Output Voltage[%d] = ", iv);
for (c = 0; c < CI_MAX; c++)
aid_dbg("%lld ", output_voltages[iv].rgb[c]);
aid_dbg("\n");
}
#endif
return 0;
}
static int calc_voltage_table(struct dynamic_aid_info d_aid)
{
int ret;
ret = calc_point_voltages(d_aid);
if (ret)
return ret;
ret = calc_output_voltages(d_aid);
if (ret)
return ret;
return 0;
}
static int calc_m_rgb_voltages(struct dynamic_aid_info d_aid, int ibr)
{
int iv, c;
struct rgb64_t *output_voltages;
struct rgb64_t *point_voltages;
int *m_gray;
struct rgb64_t *m_voltage;
output_voltages = d_aid.output_voltages;
point_voltages = d_aid.point_voltages;
m_gray = &((int(*)[d_aid.iv_max])d_aid.param.m_gray)[ibr][0];
m_voltage = d_aid.m_voltage;
iv = d_aid.iv_max - 1;
/* iv == (IV_MAX - 1) ~ 1; */
for (; iv > 0; iv--) {
for (c = 0; c < CI_MAX; c++)
m_voltage[iv].rgb[c] = output_voltages[m_gray[iv]].rgb[c];
}
/* iv == 0; */
for (c = 0; c < CI_MAX; c++)
m_voltage[iv].rgb[c] = point_voltages[0].rgb[c];
#ifdef DYNAMIC_AID_DEBUG
aid_dbg("M-RGB voltage (%d) =\n", d_aid.ibr_tbl[ibr]);
for (iv = 0; iv < d_aid.iv_max; iv++) {
aid_dbg("[%d] = ", iv);
for (c = 0; c < CI_MAX; c++)
aid_dbg("%lld ", d_aid.m_voltage[iv].rgb[c]);
aid_dbg("\n");
}
#endif
return 0;
}
static int calc_gamma(struct dynamic_aid_info d_aid, int ibr, int *result)
{
int ret, iv, c, iv_ref;
int numerator, denominator;
s64 t1, t2, vb;
int *vd, *mtp, *res;
struct rgb_t (*offset_color)[d_aid.iv_max];
struct rgb64_t *m_voltage;
offset_color = (struct rgb_t(*)[])d_aid.param.offset_color;
m_voltage = d_aid.m_voltage;
iv = d_aid.iv_max - 1;
ret = 0;
/* iv == (IV_MAX - 1) ~ 1; */
for (; iv > 0; iv--) {
mtp = &d_aid.mtp[iv*CI_MAX];
res = &result[iv*CI_MAX];
numerator = d_aid.param.formular[iv].numerator;
denominator = d_aid.param.formular[iv].denominator;
iv_ref = d_aid.param.iv_ref[iv];
for (c = 0; c < CI_MAX; c++) {
vb = (iv_ref < d_aid.iv_max) ? m_voltage[iv_ref].rgb[c] : d_aid.vreg;
if (iv == d_aid.iv_max - 1) {
t1 = vb - m_voltage[iv].rgb[c];
t2 = vb - d_aid.vref_h;
} else {
t1 = vb - m_voltage[iv].rgb[c];
t2 = vb - m_voltage[iv+1].rgb[c];
}
res[c] = div64_s64((t1 + 1) * denominator, t2) - numerator;
res[c] -= mtp[c];
if (offset_color)
res[c] += offset_color[ibr][iv].rgb[c];
res[c] = (res[c] < 0) ? 0 : res[c];
if ((res[c] > 255) && (iv != d_aid.iv_max - 1))
res[c] = 255;
}
}
/* iv == 0; */
vd = (int *)&d_aid.param.gamma_default[0];
res = &result[0];
for (c = 0; c < CI_MAX; c++)
res[c] = vd[c];
#ifdef DYNAMIC_AID_DEBUG
aid_dbg("Gamma (%d) =\n", d_aid.ibr_tbl[ibr]);
for (iv = 0; iv < d_aid.iv_max; iv++) {
aid_dbg("[%d] = ", iv);
for (c = 0; c < CI_MAX; c++)
aid_dbg("%X ", result[iv*CI_MAX+c]);
aid_dbg("\n");
}
#endif
return ret;
}
static int calc_gamma_table(struct dynamic_aid_info d_aid, int **gamma)
{
int ibr;
#ifdef DYNAMIC_AID_DEBUG
int iv, c;
#endif
/* ibr == 0 ~ (IBRIGHTNESS_MAX - 1); */
for (ibr = 0; ibr < d_aid.ibr_max; ibr++) {
calc_m_rgb_voltages(d_aid, ibr);
calc_gamma(d_aid, ibr, gamma[ibr]);
}
#ifdef DYNAMIC_AID_DEBUG
for (ibr = 0; ibr < d_aid.ibr_max; ibr++) {
aid_dbg("Gamma [%3d] = ", d_aid.ibr_tbl[ibr]);
for (iv = 0; iv < d_aid.iv_max; iv++) {
for (c = 0; c < CI_MAX; c++)
aid_dbg("%4d ", gamma[ibr][iv*CI_MAX+c]);
}
aid_dbg("\n");
}
#endif
return 0;
}
int dynamic_aid(struct dynamic_aid_param_t param, int **gamma)
{
struct dynamic_aid_info d_aid;
int ret;
d_aid.param = param;
d_aid.iv_tbl = (int *)param.iv_tbl;
d_aid.iv_max = param.iv_max;
d_aid.iv_top = param.iv_tbl[param.iv_max-1];
d_aid.mtp = param.mtp;
d_aid.vreg = MUL_100(param.vreg);
d_aid.vref_h = param.vref_h;
d_aid.ibr_tbl = (int *)param.ibr_tbl;
d_aid.ibr_max = param.ibr_max;
d_aid.point_voltages = kzalloc(sizeof(struct rgb64_t)*d_aid.iv_max, GFP_KERNEL);
if (!d_aid.point_voltages) {
pr_err("failed to allocate point_voltages\n");
ret = -ENOMEM;
goto error1;
}
d_aid.output_voltages = kzalloc(sizeof(struct rgb64_t)*(d_aid.iv_top+1), GFP_KERNEL);
if (!d_aid.output_voltages) {
pr_err("failed to allocate output_voltages\n");
ret = -ENOMEM;
goto error2;
}
d_aid.m_voltage = kzalloc(sizeof(struct rgb64_t)*d_aid.iv_max, GFP_KERNEL);
if (!d_aid.m_voltage) {
pr_err("failed to allocate m_voltage\n");
ret = -ENOMEM;
goto error3;
}
ret = calc_voltage_table(d_aid);
if (ret)
goto error4;
ret = calc_gamma_table(d_aid, gamma);
if (ret)
goto error4;
pr_info("Dynamic Aid Finished !\n");
error4:
kfree(d_aid.m_voltage);
error3:
kfree(d_aid.output_voltages);
error2:
kfree(d_aid.point_voltages);
error1:
return ret;
}

View file

@ -0,0 +1,44 @@
#ifndef __DYNAMIC_AID_H
#define __DYNAMIC_AID_H __FILE__
enum {
CI_RED,
CI_GREEN,
CI_BLUE,
CI_MAX
};
struct rgb_t {
int rgb[CI_MAX];
};
struct formular_t {
int numerator;
int denominator;
};
struct m_gray_limit_t {
int min;
int max;
};
struct dynamic_aid_param_t {
int vreg;
int vref_h;
const int *iv_tbl;
int iv_max;
int *mtp;
const int *gamma_default;
const struct formular_t *formular;
const int *vt_voltage_value;
const int *ibr_tbl;
int ibr_max;
const struct rgb_t (*offset_color)[];
int *iv_ref;
const int (*m_gray)[];
};
extern int dynamic_aid(struct dynamic_aid_param_t d_aid, int **gamma);
#endif /* __DYNAMIC_AID_H */

View file

@ -0,0 +1,153 @@
#ifndef __MDNIE_H__
#define __MDNIE_H__
typedef u8 mdnie_t;
enum MODE {
DYNAMIC,
STANDARD,
NATURAL,
MOVIE,
AUTO,
EBOOK,
MODE_MAX
};
enum SCENARIO {
UI_MODE,
VIDEO_NORMAL_MODE,
CAMERA_MODE = 4,
NAVI_MODE,
GALLERY_MODE,
VT_MODE,
BROWSER_MODE,
EBOOK_MODE,
EMAIL_MODE,
GAME_LOW_MODE,
GAME_MID_MODE,
GAME_HIGH_MODE,
HMT_8_MODE,
HMT_16_MODE,
SCENARIO_MAX,
DMB_NORMAL_MODE = 20,
DMB_MODE_MAX
};
enum BYPASS {
BYPASS_OFF,
BYPASS_ON,
BYPASS_MAX
};
enum ACCESSIBILITY {
ACCESSIBILITY_OFF,
NEGATIVE,
COLOR_BLIND,
SCREEN_CURTAIN,
GRAYSCALE,
GRAYSCALE_NEGATIVE,
ACCESSIBILITY_MAX
};
enum HBM {
HBM_OFF,
HBM_ON,
HBM_MAX
};
enum hmt_mode {
HMT_MDNIE_OFF,
HMT_MDNIE_ON,
HMT_3000K = HMT_MDNIE_ON,
HMT_4000K,
HMT_6400K,
HMT_7500K,
HMT_MDNIE_MAX
};
struct mdnie_seq_info {
mdnie_t *cmd;
unsigned int len;
unsigned int sleep;
};
struct mdnie_table {
char *name;
unsigned int update_flag[4];
struct mdnie_seq_info seq[4 + 1];
};
struct mdnie_scr_info {
u32 index;
u32 color_blind; /* Cyan Red */
u32 white_r;
u32 white_g;
u32 white_b;
};
struct mdnie_tune {
struct mdnie_table *bypass_table;
struct mdnie_table *accessibility_table;
struct mdnie_table *hbm_table;
struct mdnie_table *hmt_table;
struct mdnie_table (*main_table)[MODE_MAX];
struct mdnie_table *dmb_table;
struct mdnie_scr_info *scr_info;
unsigned char **coordinate_table;
int (*get_hbm_index)(int);
int (*color_offset[])(int, int);
};
struct mdnie_ops {
int (*write)(void *data, struct mdnie_seq_info *seq, u32 len);
int (*read)(void *data, u8 addr, mdnie_t *buf, u32 len);
};
typedef int (*mdnie_w)(void *devdata, struct mdnie_seq_info *seq, u32 len);
typedef int (*mdnie_r)(void *devdata, u8 addr, u8 *buf, u32 len);
struct mdnie_info {
struct device *dev;
struct mutex dev_lock;
struct mutex lock;
unsigned int enable;
struct mdnie_tune *tune;
enum SCENARIO scenario;
enum MODE mode;
enum BYPASS bypass;
enum HBM hbm;
enum hmt_mode hmt_mode;
unsigned int tuning;
unsigned int accessibility;
unsigned int color_correction;
char path[50];
void *data;
struct mdnie_ops ops;
struct notifier_block fb_notif;
unsigned int white_r;
unsigned int white_g;
unsigned int white_b;
struct mdnie_table table_buffer;
mdnie_t sequence_buffer[256];
u16 coordinate[2];
};
extern int mdnie_calibration(int *r);
extern int mdnie_open_file(const char *path, char **fp);
extern int mdnie_register(struct device *p, void *data, mdnie_w w, mdnie_r r, unsigned int *coordinate, struct mdnie_tune *tune);
extern uintptr_t mdnie_request_table(char *path, struct mdnie_table *s);
extern ssize_t attr_store_for_each(struct class *cls, const char *name, const char *buf, size_t size);
extern struct class *get_mdnie_class(void);
#endif /* __MDNIE_H__ */

View file

@ -0,0 +1,823 @@
/* linux/drivers/video/mdnie.c
*
* Register interface file for Samsung mDNIe driver
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/lcd.h>
#include <linux/fb.h>
#include <linux/pm_runtime.h>
#include "mdnie.h"
#define MDNIE_SYSFS_PREFIX "/sdcard/mdnie/"
#define IS_DMB(idx) (idx == DMB_NORMAL_MODE)
#define IS_SCENARIO(idx) (idx < SCENARIO_MAX && !(idx > VIDEO_NORMAL_MODE && idx < CAMERA_MODE))
#define IS_ACCESSIBILITY(idx) (idx && idx < ACCESSIBILITY_MAX)
#define IS_HBM(idx) (idx && idx < HBM_MAX)
#define IS_HMT(idx) (idx && idx < HMT_MDNIE_MAX)
#define SCENARIO_IS_VALID(idx) (IS_DMB(idx) || IS_SCENARIO(idx))
/* Split 16 bit as 8bit x 2 */
#define GET_MSB_8BIT(x) ((x >> 8) & (BIT(8) - 1))
#define GET_LSB_8BIT(x) ((x >> 0) & (BIT(8) - 1))
static struct class *mdnie_class;
/* Do not call mdnie write directly */
static int mdnie_write(struct mdnie_info *mdnie, struct mdnie_table *table, unsigned int num)
{
int ret = 0;
if (mdnie->enable)
ret = mdnie->ops.write(mdnie->data, table->seq, num);
return ret;
}
static int mdnie_write_table(struct mdnie_info *mdnie, struct mdnie_table *table)
{
int i, ret = 0;
struct mdnie_table *buf = NULL;
for (i = 0; table->seq[i].len; i++) {
if (IS_ERR_OR_NULL(table->seq[i].cmd)) {
dev_info(mdnie->dev, "mdnie sequence %s %dth is null\n", table->name, i);
return -EPERM;
}
}
mutex_lock(&mdnie->dev_lock);
buf = table;
ret = mdnie_write(mdnie, buf, i);
mutex_unlock(&mdnie->dev_lock);
return ret;
}
static struct mdnie_table *mdnie_find_table(struct mdnie_info *mdnie)
{
struct mdnie_table *table = NULL;
mutex_lock(&mdnie->lock);
if (IS_ACCESSIBILITY(mdnie->accessibility)) {
table = mdnie->tune->accessibility_table ? &mdnie->tune->accessibility_table[mdnie->accessibility] : NULL;
goto exit;
} else if (IS_HMT(mdnie->hmt_mode)) {
table = mdnie->tune->hmt_table ? &mdnie->tune->hmt_table[mdnie->hmt_mode] : NULL;
goto exit;
} else if (IS_HBM(mdnie->hbm)) {
table = mdnie->tune->hbm_table ? &mdnie->tune->hbm_table[mdnie->hbm] : NULL;
goto exit;
} else if (IS_DMB(mdnie->scenario)) {
table = mdnie->tune->dmb_table ? &mdnie->tune->dmb_table[mdnie->mode] : NULL;
goto exit;
} else if (IS_SCENARIO(mdnie->scenario)) {
table = mdnie->tune->main_table ? &mdnie->tune->main_table[mdnie->scenario][mdnie->mode] : NULL;
goto exit;
}
exit:
mutex_unlock(&mdnie->lock);
return table;
}
static void mdnie_update_sequence(struct mdnie_info *mdnie, struct mdnie_table *table)
{
if (mdnie->tuning)
mdnie_request_table(mdnie->path, table);
mdnie_write_table(mdnie, table);
}
static void mdnie_update(struct mdnie_info *mdnie)
{
struct mdnie_table *table = NULL;
struct mdnie_scr_info *scr_info = mdnie->tune->scr_info;
if (!mdnie->enable) {
dev_err(mdnie->dev, "mdnie state is off\n");
return;
}
table = mdnie_find_table(mdnie);
if (!IS_ERR_OR_NULL(table) && !IS_ERR_OR_NULL(table->name)) {
mdnie_update_sequence(mdnie, table);
dev_info(mdnie->dev, "%s\n", table->name);
mdnie->white_r = table->seq[scr_info->index].cmd[scr_info->white_r];
mdnie->white_g = table->seq[scr_info->index].cmd[scr_info->white_g];
mdnie->white_b = table->seq[scr_info->index].cmd[scr_info->white_b];
}
}
static void update_color_position(struct mdnie_info *mdnie, unsigned int idx)
{
u8 mode, scenario;
mdnie_t *wbuf;
struct mdnie_scr_info *scr_info = mdnie->tune->scr_info;
dev_info(mdnie->dev, "%s: idx=%d\n", __func__, idx);
mutex_lock(&mdnie->lock);
for (mode = 0; mode < MODE_MAX; mode++) {
for (scenario = 0; scenario <= EMAIL_MODE; scenario++) {
wbuf = mdnie->tune->main_table[scenario][mode].seq[scr_info->index].cmd;
if (IS_ERR_OR_NULL(wbuf))
continue;
if ((scenario != EBOOK_MODE) && (mode != EBOOK)) {
wbuf[scr_info->white_r] = mdnie->tune->coordinate_table[mode][idx * 3 + 0];
wbuf[scr_info->white_g] = mdnie->tune->coordinate_table[mode][idx * 3 + 1];
wbuf[scr_info->white_b] = mdnie->tune->coordinate_table[mode][idx * 3 + 2];
}
}
}
mutex_unlock(&mdnie->lock);
}
static int get_panel_coordinate(struct mdnie_info *mdnie, int *result)
{
int ret = 0;
unsigned short x, y;
x = mdnie->coordinate[0];
y = mdnie->coordinate[1];
if (!(x || y)) {
dev_info(mdnie->dev, "This panel do not need to adjust coordinate\n");
ret = -EINVAL;
goto skip_color_correction;
}
result[1] = mdnie->tune->color_offset[0](x, y);
result[2] = mdnie->tune->color_offset[1](x, y);
result[3] = mdnie->tune->color_offset[2](x, y);
result[4] = mdnie->tune->color_offset[3](x, y);
ret = mdnie_calibration(result);
dev_info(mdnie->dev, "%s: %d, %d, idx=%d\n", __func__, x, y, ret);
skip_color_correction:
mdnie->color_correction = 1;
return ret;
}
static ssize_t mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", mdnie->mode);
}
static ssize_t mode_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
unsigned int value = 0;
int ret;
int result[5] = {0,};
ret = kstrtouint(buf, 0, &value);
if (ret < 0)
return ret;
dev_info(dev, "%s: value=%d\n", __func__, value);
if (value >= MODE_MAX) {
value = STANDARD;
return -EINVAL;
}
mutex_lock(&mdnie->lock);
mdnie->mode = value;
mutex_unlock(&mdnie->lock);
if (!mdnie->color_correction) {
ret = get_panel_coordinate(mdnie, result);
if (ret > 0)
update_color_position(mdnie, ret);
}
mdnie_update(mdnie);
return count;
}
static ssize_t scenario_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", mdnie->scenario);
}
static ssize_t scenario_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
unsigned int value;
int ret;
ret = kstrtouint(buf, 0, &value);
if (ret < 0)
return ret;
dev_info(dev, "%s: value=%d\n", __func__, value);
if (!SCENARIO_IS_VALID(value))
value = UI_MODE;
mutex_lock(&mdnie->lock);
mdnie->scenario = value;
mutex_unlock(&mdnie->lock);
mdnie_update(mdnie);
return count;
}
static ssize_t tuning_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
char *pos = buf;
struct mdnie_table *table = NULL;
int i, idx;
pos += sprintf(pos, "++ %s: %s\n", __func__, mdnie->path);
if (!mdnie->tuning) {
pos += sprintf(pos, "tunning mode is off\n");
goto exit;
}
if (strncmp(mdnie->path, MDNIE_SYSFS_PREFIX, sizeof(MDNIE_SYSFS_PREFIX) - 1)) {
pos += sprintf(pos, "file path is invalid, %s\n", mdnie->path);
goto exit;
}
table = mdnie_find_table(mdnie);
if (!IS_ERR_OR_NULL(table) && !IS_ERR_OR_NULL(table->name)) {
mdnie_request_table(mdnie->path, table);
for (idx = 0; table->seq[idx].len; idx++) {
for (i = 0; i < table->seq[idx].len; i++)
pos += sprintf(pos, "0x%02x ", table->seq[idx].cmd[i]);
}
pos += sprintf(pos, "\n");
}
exit:
pos += sprintf(pos, "-- %s\n", __func__);
return pos - buf;
}
static ssize_t tuning_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
int ret;
if (sysfs_streq(buf, "0") || sysfs_streq(buf, "1")) {
ret = kstrtouint(buf, 0, &mdnie->tuning);
if (ret < 0)
return ret;
if (!mdnie->tuning)
memset(mdnie->path, 0, sizeof(mdnie->path));
dev_info(dev, "%s: %s\n", __func__, mdnie->tuning ? "enable" : "disable");
} else {
if (!mdnie->tuning)
return count;
if (count > (sizeof(mdnie->path) - sizeof(MDNIE_SYSFS_PREFIX))) {
dev_err(dev, "file name %s is too long\n", mdnie->path);
return -ENOMEM;
}
memset(mdnie->path, 0, sizeof(mdnie->path));
snprintf(mdnie->path, sizeof(MDNIE_SYSFS_PREFIX) + count-1, "%s%s", MDNIE_SYSFS_PREFIX, buf);
dev_info(dev, "%s: %s\n", __func__, mdnie->path);
mdnie_update(mdnie);
}
return count;
}
static ssize_t accessibility_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", mdnie->accessibility);
}
static ssize_t accessibility_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
unsigned int value, s[9], i = 0;
int ret;
mdnie_t *wbuf;
struct mdnie_scr_info *scr_info = mdnie->tune->scr_info;
ret = sscanf(buf, "%d %x %x %x %x %x %x %x %x %x",
&value, &s[0], &s[1], &s[2], &s[3],
&s[4], &s[5], &s[6], &s[7], &s[8]);
dev_info(dev, "%s: value=%d, %d\n", __func__, value, ret);
if (ret < 0)
return ret;
else {
if (value >= ACCESSIBILITY_MAX)
value = ACCESSIBILITY_OFF;
mutex_lock(&mdnie->lock);
mdnie->accessibility = value;
if (value == COLOR_BLIND) {
if (ret > ARRAY_SIZE(s) + 1) {
mutex_unlock(&mdnie->lock);
return -EINVAL;
}
wbuf = &mdnie->tune->accessibility_table[value].seq[scr_info->index].cmd[scr_info->color_blind];
while (i < ret - 1) {
wbuf[i * 2 + 0] = GET_LSB_8BIT(s[i]);
wbuf[i * 2 + 1] = GET_MSB_8BIT(s[i]);
i++;
}
dev_info(dev, "%s: %s\n", __func__, buf);
}
mutex_unlock(&mdnie->lock);
mdnie_update(mdnie);
}
return count;
}
static ssize_t color_correct_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
char *pos = buf;
int i, idx, result[5] = {0,};
if (!mdnie->color_correction)
return -EINVAL;
idx = get_panel_coordinate(mdnie, result);
for (i = 1; i < ARRAY_SIZE(result); i++)
pos += sprintf(pos, "f%d: %d, ", i, result[i]);
pos += sprintf(pos, "tune%d\n", idx);
return pos - buf;
}
static ssize_t bypass_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", mdnie->bypass);
}
static ssize_t bypass_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
struct mdnie_table *table = NULL;
unsigned int value;
int ret;
ret = kstrtouint(buf, 0, &value);
dev_info(dev, "%s :: value=%d\n", __func__, value);
if (ret < 0)
return ret;
else {
if (value >= BYPASS_MAX)
value = BYPASS_OFF;
value = (value) ? BYPASS_ON : BYPASS_OFF;
mutex_lock(&mdnie->lock);
mdnie->bypass = value;
mutex_unlock(&mdnie->lock);
table = &mdnie->tune->bypass_table[value];
if (!IS_ERR_OR_NULL(table)) {
mdnie_write_table(mdnie, table);
dev_info(mdnie->dev, "%s\n", table->name);
}
}
return count;
}
static ssize_t lux_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", mdnie->hbm);
}
static ssize_t lux_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
unsigned int hbm = 0, update = 0;
int ret, value;
ret = kstrtoint(buf, 0, &value);
if (ret < 0)
return ret;
if (!mdnie->tune->get_hbm_index)
return ret;
mutex_lock(&mdnie->lock);
hbm = mdnie->tune->get_hbm_index(value);
update = (mdnie->hbm != hbm) ? 1 : 0;
mdnie->hbm = update ? hbm : mdnie->hbm;
mutex_unlock(&mdnie->lock);
if (update) {
dev_info(dev, "%s: %d\n", __func__, value);
mdnie_update(mdnie);
}
return count;
}
/* Temporary solution: Do not use this sysfs as official purpose */
static ssize_t mdnie_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
char *pos = buf;
struct mdnie_table *table = NULL;
int i, j;
u8 *buffer;
if (!mdnie->enable) {
dev_err(mdnie->dev, "mdnie state is off\n");
goto exit;
}
table = mdnie_find_table(mdnie);
for (i = 0; table->seq[i].len; i++) {
if (IS_ERR_OR_NULL(table->seq[i].cmd)) {
dev_err(mdnie->dev, "mdnie sequence %s %dth command is null,\n", table->name, i);
goto exit;
}
}
pos += sprintf(pos, "+ %s\n", table->name);
for (j = 0; table->seq[j].len; j++) {
if (!table->update_flag[j]) {
mdnie->ops.write(mdnie->data, &table->seq[j], 1);
continue;
}
buffer = kzalloc(table->seq[j].len, GFP_KERNEL);
mdnie->ops.read(mdnie->data, table->seq[j].cmd[0], buffer, table->seq[j].len - 1);
pos += sprintf(pos, " 0:\t0x%02x\t0x%02x\n", table->seq[j].cmd[0], table->seq[j].cmd[0]);
for (i = 0; i < table->seq[j].len - 1; i++) {
pos += sprintf(pos, "%3d:\t0x%02x\t0x%02x", i + 1, table->seq[j].cmd[i+1], buffer[i]);
if (table->seq[j].cmd[i+1] != buffer[i])
pos += sprintf(pos, "\t(X)");
pos += sprintf(pos, "\n");
}
kfree(buffer);
}
pos += sprintf(pos, "- %s\n", table->name);
exit:
return pos - buf;
}
static ssize_t sensorRGB_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
return sprintf(buf, "%d %d %d\n", mdnie->white_r, mdnie->white_g, mdnie->white_b);
}
static ssize_t sensorRGB_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
struct mdnie_table *table = NULL;
unsigned int white_red, white_green, white_blue;
int ret;
struct mdnie_scr_info *scr_info = mdnie->tune->scr_info;
ret = sscanf(buf, "%d %d %d",
&white_red, &white_green, &white_blue);
if (ret < 0)
return ret;
if (mdnie->enable && (mdnie->accessibility == ACCESSIBILITY_OFF)
&& (mdnie->mode == AUTO)
&& ((mdnie->scenario == BROWSER_MODE)
|| (mdnie->scenario == EBOOK_MODE))) {
dev_info(dev, "%s, white_r %d, white_g %d, white_b %d\n",
__func__, white_red, white_green, white_blue);
table = mdnie_find_table(mdnie);
memcpy(&(mdnie->table_buffer),
table, sizeof(struct mdnie_table));
memcpy(mdnie->sequence_buffer,
table->seq[scr_info->index].cmd,
table->seq[scr_info->index].len);
mdnie->table_buffer.seq[scr_info->index].cmd
= mdnie->sequence_buffer;
mdnie->table_buffer.seq[scr_info->index].cmd
[scr_info->white_r] = (unsigned char)white_red;
mdnie->table_buffer.seq[scr_info->index].cmd
[scr_info->white_g] = (unsigned char)white_green;
mdnie->table_buffer.seq[scr_info->index].cmd
[scr_info->white_b] = (unsigned char)white_blue;
mdnie->white_r = white_red;
mdnie->white_g = white_green;
mdnie->white_b = white_blue;
mdnie_update_sequence(mdnie, &(mdnie->table_buffer));
}
return count;
}
#ifdef CONFIG_LCD_HMT
static ssize_t hmtColorTemp_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
return sprintf(buf, "hmt_mode: %d\n", mdnie->hmt_mode);
}
static ssize_t hmtColorTemp_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct mdnie_info *mdnie = dev_get_drvdata(dev);
unsigned int value;
int ret;
ret = kstrtouint(buf, 0, &value);
if (ret < 0)
return ret;
if (value != mdnie->hmt_mode && value < HMT_MDNIE_MAX) {
mutex_lock(&mdnie->lock);
mdnie->hmt_mode = value;
mutex_unlock(&mdnie->lock);
mdnie_update(mdnie);
}
return count;
}
#endif
static DEVICE_ATTR(mode, 0664, mode_show, mode_store);
static DEVICE_ATTR(scenario, 0664, scenario_show, scenario_store);
static DEVICE_ATTR(tuning, 0664, tuning_show, tuning_store);
static DEVICE_ATTR(accessibility, 0664, accessibility_show, accessibility_store);
static DEVICE_ATTR(color_correct, 0444, color_correct_show, NULL);
static DEVICE_ATTR(bypass, 0664, bypass_show, bypass_store);
static DEVICE_ATTR(lux, 0000, lux_show, lux_store);
static DEVICE_ATTR(mdnie, 0444, mdnie_show, NULL);
static DEVICE_ATTR(sensorRGB, 0664, sensorRGB_show, sensorRGB_store);
#ifdef CONFIG_LCD_HMT
static DEVICE_ATTR(hmt_color_temperature, 0664, hmtColorTemp_show, hmtColorTemp_store);
#endif
static struct attribute *mdnie_attrs[] = {
&dev_attr_mode.attr,
&dev_attr_scenario.attr,
&dev_attr_tuning.attr,
&dev_attr_accessibility.attr,
&dev_attr_color_correct.attr,
&dev_attr_bypass.attr,
&dev_attr_lux.attr,
&dev_attr_mdnie.attr,
&dev_attr_sensorRGB.attr,
#ifdef CONFIG_LCD_HMT
&dev_attr_hmt_color_temperature.attr,
#endif
NULL,
};
ATTRIBUTE_GROUPS(mdnie);
static int fb_notifier_callback(struct notifier_block *self,
unsigned long event, void *data)
{
struct mdnie_info *mdnie;
struct fb_event *evdata = data;
int fb_blank;
switch (event) {
case FB_EVENT_BLANK:
break;
default:
return 0;
}
mdnie = container_of(self, struct mdnie_info, fb_notif);
fb_blank = *(int *)evdata->data;
dev_info(mdnie->dev, "%s: %d\n", __func__, fb_blank);
if (evdata->info->node != 0)
return 0;
if (fb_blank == FB_BLANK_UNBLANK) {
mutex_lock(&mdnie->lock);
mdnie->enable = 1;
mutex_unlock(&mdnie->lock);
mdnie_update(mdnie);
} else if (fb_blank == FB_BLANK_POWERDOWN) {
mutex_lock(&mdnie->lock);
mdnie->enable = 0;
mutex_unlock(&mdnie->lock);
}
return 0;
}
static int mdnie_register_fb(struct mdnie_info *mdnie)
{
memset(&mdnie->fb_notif, 0, sizeof(mdnie->fb_notif));
mdnie->fb_notif.notifier_call = fb_notifier_callback;
return fb_register_client(&mdnie->fb_notif);
}
int mdnie_register(struct device *p, void *data, mdnie_w w, mdnie_r r, unsigned int *coordinate, struct mdnie_tune *tune)
{
int ret = 0;
struct mdnie_info *mdnie;
static unsigned int mdnie_no;
if (IS_ERR_OR_NULL(mdnie_class)) {
mdnie_class = class_create(THIS_MODULE, "mdnie");
if (IS_ERR_OR_NULL(mdnie_class)) {
pr_err("failed to create mdnie class\n");
ret = -EINVAL;
goto error0;
}
mdnie_class->dev_groups = mdnie_groups;
}
mdnie = kzalloc(sizeof(struct mdnie_info), GFP_KERNEL);
if (!mdnie) {
pr_err("failed to allocate mdnie\n");
ret = -ENOMEM;
goto error1;
}
mdnie->dev = device_create(mdnie_class, p, 0, &mdnie, !mdnie_no ? "mdnie" : "mdnie%d", mdnie_no);
if (IS_ERR_OR_NULL(mdnie->dev)) {
pr_err("failed to create mdnie device\n");
ret = -EINVAL;
goto error2;
}
mdnie_no++;
mdnie->scenario = UI_MODE;
mdnie->mode = STANDARD;
mdnie->enable = 0;
mdnie->tuning = 0;
mdnie->accessibility = ACCESSIBILITY_OFF;
mdnie->bypass = BYPASS_OFF;
mdnie->data = data;
mdnie->ops.write = w;
mdnie->ops.read = r;
mdnie->coordinate[0] = coordinate ? coordinate[0] : 0;
mdnie->coordinate[1] = coordinate ? coordinate[1] : 0;
mdnie->tune = tune;
mutex_init(&mdnie->lock);
mutex_init(&mdnie->dev_lock);
dev_set_drvdata(mdnie->dev, mdnie);
mdnie_register_fb(mdnie);
mdnie->enable = 1;
mdnie_update(mdnie);
dev_info(mdnie->dev, "registered successfully\n");
return 0;
error2:
kfree(mdnie);
error1:
class_destroy(mdnie_class);
error0:
return ret;
}
static int attr_find_and_store(struct device *dev,
const char *name, const char *buf, size_t size)
{
struct device_attribute *dev_attr;
struct kernfs_node *kn;
struct attribute *attr;
kn = kernfs_find_and_get(dev->kobj.sd, name);
if (!kn) {
pr_info("%s: not found: %s\n", __func__, name);
return 0;
}
attr = kn->priv;
dev_attr = container_of(attr, struct device_attribute, attr);
if (dev_attr && dev_attr->store)
dev_attr->store(dev, dev_attr, buf, size);
kernfs_put(kn);
return 0;
}
ssize_t attr_store_for_each(struct class *cls,
const char *name, const char *buf, size_t size)
{
struct class_dev_iter iter;
struct device *dev;
int error = 0;
struct class *class = cls;
if (!class)
return -EINVAL;
if (!class->p) {
WARN(1, "%s called for class '%s' before it was initialized",
__func__, class->name);
return -EINVAL;
}
class_dev_iter_init(&iter, class, NULL, NULL);
while ((dev = class_dev_iter_next(&iter))) {
error = attr_find_and_store(dev, name, buf, size);
if (error)
break;
}
class_dev_iter_exit(&iter);
return error;
}
struct class *get_mdnie_class(void)
{
return mdnie_class;
}

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,246 @@
/* linux/drivers/video/mdnie_tuning.c
*
* Register interface file for Samsung mDNIe driver
*
* 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/poll.h>
#include <linux/wait.h>
#include <linux/fs.h>
#include <linux/irq.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/lcd.h>
#include <linux/rtc.h>
#include <linux/fb.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ctype.h>
#include <linux/uaccess.h>
#include <linux/magic.h>
#include "mdnie.h"
int mdnie_calibration(int *r)
{
int ret = 0;
if (r[1] > 0) {
if (r[3] > 0)
ret = 3;
else
ret = (r[4] < 0) ? 1 : 2;
} else {
if (r[2] < 0) {
if (r[3] > 0)
ret = 9;
else
ret = (r[4] < 0) ? 7 : 8;
} else {
if (r[3] > 0)
ret = 6;
else
ret = (r[4] < 0) ? 4 : 5;
}
}
pr_info("%d, %d, %d, %d, tune%d\n", r[1], r[2], r[3], r[4], ret);
return ret;
}
int mdnie_open_file(const char *path, char **fp)
{
struct file *filp;
char *dp;
long length;
int ret;
struct super_block *sb;
loff_t pos = 0;
if (!path) {
pr_err("%s: path is invalid\n", __func__);
return -EPERM;
}
filp = filp_open(path, O_RDONLY, 0);
if (IS_ERR(filp)) {
pr_err("%s: filp_open skip: %s\n", __func__, path);
return -EPERM;
}
length = i_size_read(filp->f_path.dentry->d_inode);
if (length <= 0) {
pr_err("%s: file length is %ld\n", __func__, length);
return -EPERM;
}
dp = kzalloc(length + 1, GFP_KERNEL);
if (dp == NULL) {
pr_err("%s: failed to alloc size %ld\n", __func__, length);
filp_close(filp, current->files);
return -EPERM;
}
ret = kernel_read(filp, pos, dp, length);
if (ret != length) {
/* check node is sysfs, bus this way is not safe */
sb = filp->f_path.dentry->d_inode->i_sb;
if ((sb->s_magic != SYSFS_MAGIC) && (length != sb->s_blocksize)) {
pr_err("%s: read size= %d, length= %ld\n", __func__, ret, length);
kfree(dp);
filp_close(filp, current->files);
return -EPERM;
}
}
filp_close(filp, current->files);
*fp = dp;
return ret;
}
int mdnie_check_firmware(const char *path, char *name)
{
char *fp, *p = NULL;
int count = 0, size;
size = mdnie_open_file(path, &fp);
if (IS_ERR_OR_NULL(fp) || size <= 0) {
pr_err("%s: file open skip %s\n", __func__, path);
kfree(p);
return -EPERM;
}
p = fp;
while ((p = strstr(p, name)) != NULL) {
count++;
p++;
}
kfree(fp);
pr_info("%s found %d times in %s\n", name, count, path);
/* if count is 1, it means tuning header. if count is 0, it means tuning data */
return count;
}
static int mdnie_request_firmware(char *path, char *name, unsigned int **buf)
{
char *token, *ptr = NULL;
int ret = 0, size, data[2];
unsigned int count = 0, i;
unsigned int *dp;
size = mdnie_open_file(path, &ptr);
if (IS_ERR_OR_NULL(ptr) || size <= 0) {
pr_err("%s: file open skip %s\n", __func__, path);
kfree(ptr);
return -EPERM;
}
dp = kcalloc(size + 1, sizeof(*dp), GFP_KERNEL);
if (dp == NULL) {
pr_err("%s: failed to alloc size %d\n", __func__, size);
kfree(ptr);
return -ENOMEM;
}
while (!IS_ERR_OR_NULL(ptr)) {
ptr = (name) ? strstr(ptr, name) : ptr;
while ((token = strsep(&ptr, "\n")) != NULL) {
ret = sscanf(token, "%i, %i", &data[0], &data[1]);
pr_info("sscanf: %2d, strlen: %2d, %s\n", ret, (int)strlen(token), token);
if (!ret && strlen(token) <= 1) {
dp[count] = 0xffff;
pr_info("stop at %d\n", count);
if (count)
count = (dp[count - 1] == dp[count]) ? count : count + 1;
break;
}
for (i = 0; i < ret; count++, i++)
dp[count] = data[i];
}
}
*buf = dp;
for (i = 0; i < count; i++)
pr_info("[%4d] %04x\n", i, dp[i]);
kfree(ptr);
return count;
}
/* this function is not official one. its only purpose is for tuning */
uintptr_t mdnie_request_table(char *path, struct mdnie_table *org)
{
unsigned int i, j = 0, k = 0, len;
unsigned int *buf = NULL;
mdnie_t *cmd = 0;
int size, ret = 0, cmd_found = 0;
ret = mdnie_check_firmware(path, org->name);
if (ret < 0)
goto exit;
size = mdnie_request_firmware(path, ret ? org->name : NULL, &buf);
if (size <= 0) {
if (buf)
kfree(buf);
goto exit;
}
cmd = kcalloc(size, sizeof(mdnie_t), GFP_KERNEL);
if (IS_ERR_OR_NULL(cmd))
goto exit;
for (i = 0; org->seq[i].len; i++) {
if (!org->update_flag[i])
continue;
for (len = 0; k < size; len++, j++, k++) {
if (buf[k] == 0xffff) {
pr_info("stop at %d, %d, %d\n", k, j, len);
k++;
break;
}
cmd[j] = buf[k];
pr_info("seq[%d].len[%3d], cmd[%3d]: %02x, buf[%3d]: %02x\n", i, len, j, cmd[j], k, buf[k]);
}
org->seq[i].cmd = &cmd[j - len];
org->seq[i].len = len;
cmd_found = 1;
pr_info("seq[%d].cmd: &cmd[%3d], seq[%d].len: %d\n", i, j - len, i, len);
}
kfree(buf);
if (!cmd_found) {
kfree(cmd);
cmd = 0;
}
for (i = 0; org->seq[i].len; i++) {
pr_info("%d: size is %d\n", i, org->seq[i].len);
for (j = 0; j < org->seq[i].len; j++)
pr_info("%d: %03d: %02x\n", i, j, org->seq[i].cmd[j]);
}
exit:
/* return allocated address for prevent */
return (uintptr_t)cmd;
}

View file

@ -0,0 +1,233 @@
/* linux/drivers/video/exynos/decon_7580/panels/s6e8aa5x01_aid_dimming.h
*
* Header file for Samsung AID Dimming Driver.
*
* Copyright (c) 2013 Samsung Electronics
* Minwoo Kim <minwoo7945.kim@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 __S6E8AA5X01_AID_DIMMING_H__
#define __S6E8AA5X01_AID_DIMMING_H__
/* s6e8aa5x01 */
static signed char ctbl5nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 1, -14, 0, -2, -6, 0, -3, -5, 0, 4, -3, 0, 0, -1, 0, 2, 0, 0, 1, 2, 0, 1};
static signed char ctbl6nit[30] = {0, 0, 0, 0, 0, 0,-3, 0, 1, -13, 0, -4, -6, 0, -3, -4, 0, 4, -2, 0, 0, -1, 0, 1, 0, 0, 1, 2, 0, 1};
static signed char ctbl7nit[30] = {0, 0, 0, 0, 0, 0,-6, 0, 0, -13, 0, -3, -5, 0, -3, -4, 0, 3, -3, 0, 0, 0, 0, 2, 0, 0, 1, 2, 0, 1};
static signed char ctbl8nit[30] = {0, 0, 0, 0, 0, 0,-8, 0, 0, -12, 0, -4, -5, 0, -4, -4, 0, 3, -1, 0, 1, 0, 0, 2, 0, 0, 1, 2, 0, 1};
static signed char ctbl9nit[30] = {0, 0, 0, 0, 0, 0,-10, 0, 1, -10, 0, -2, -5, 0, -5, -3, 0, 3, -1, 0, 1, 0, 0, 2, 0, 0, 1, 2, 0, 1};
static signed char ctbl10nit[30] = {0, 0, 0, 0, 0, 0,-12, 0, -1, -8, 0, -2, -4, 0, -3, -4, 0, 2, 0, 0, 1, -1, 0, 1, 0, 0, 1, 2, 0, 1};
static signed char ctbl11nit[30] = {0, 0, 0, 0, 0, 0,-13, 0, -1, -9, 0, -3, -4, 0, -3, -3, 0, 2, 0, 0, 1, -1, 0, 1, 0, 0, 1, 2, 0, 1};
static signed char ctbl12nit[30] = {0, 0, 0, 0, 0, 0,-13, 0, -1, -9, 0, -2, -3, 0, -5, -2, 0, 3, -1, 0, 1, -1, 0, 1, 0, 0, 1, 2, 0, 1};
static signed char ctbl13nit[30] = {0, 0, 0, 0, 0, 0,-11, 0, -1, -7, 0, -1, -3, 0, -5, -3, 0, 2, -1, 0, 1, 0, 0, 1, 0, 0, 1, 2, 0, 1};
static signed char ctbl14nit[30] = {0, 0, 0, 0, 0, 0,-11, 0, -1, -5, 0, -2, -2, 0, -5, -2, 0, 3, -2, 0, 0, 0, 0, 2, 0, 0, 1, 2, 0, 1};
static signed char ctbl15nit[30] = {0, 0, 0, 0, 0, 0,-11, 0, -2, -7, 0, -3, -1, 0, -4, -2, 0, 3, -2, 0, 0, 0, 0, 1, 0, 0, 1, 2, 0, 1};
static signed char ctbl16nit[30] = {0, 0, 0, 0, 0, 0,-13, 0, -2, -5, 0, -3, -1, 0, -4, -1, 0, 3, -2, 0, 0, 0, 0, 1, 0, 0, 1, 2, 0, 1};
static signed char ctbl17nit[30] = {0, 0, 0, 0, 0, 0,-11, 0, 0, -5, 0, -3, -1, 0, -4, -2, 0, 2, -2, 0, 0, 0, 0, 2, 0, 0, 1, 2, 0, 1};
static signed char ctbl19nit[30] = {0, 0, 0, 0, 0, 0,-9, 0, 1, -5, 0, -4, -1, 0, -4, -2, 0, 2, 0, 0, 1, 0, 0, 2, -1, 0, 0, 2, 0, 1};
static signed char ctbl20nit[30] = {0, 0, 0, 0, 0, 0,-8, 0, 2, -5, 0, -3, -1, 0, -4, -2, 0, 2, 0, 0, 1, 0, 0, 2, -1, 0, 0, 2, 0, 1};
static signed char ctbl21nit[30] = {0, 0, 0, 0, 0, 0,-7, 0, 0, -6, 0, -5, 0, 0, -4, -2, 0, 2, 0, 0, 1, 0, 0, 2, -1, 0, 0, 2, 0, 1};
static signed char ctbl22nit[30] = {0, 0, 0, 0, 0, 0,-7, 1, -3, -6, 0, -4, 0, 0, -4, -2, 0, 2, 0, 0, 1, 0, 0, 2, -1, 0, 0, 2, 0, 1};
static signed char ctbl24nit[30] = {0, 0, 0, 0, 0, 0,-7, 1, -3, -6, 0, -6, 0, 0, -4, -2, 0, 2, 0, 0, 1, 0, 0, 2, -1, 0, 0, 2, 0, 1};
static signed char ctbl25nit[30] = {0, 0, 0, 0, 0, 0,-9, 0, -4, -5, 0, -5, 0, 0, -5, -3, 0, 1, 0, 0, 1, 0, 0, 2, -1, 0, 0, 2, 0, 1};
static signed char ctbl27nit[30] = {0, 0, 0, 0, 0, 0,-9, 0, -5, -3, 0, -5, 0, 0, -5, -2, 0, 1, -1, 0, 0, 0, 0, 2, -1, 0, 1, 2, 0, 1};
static signed char ctbl29nit[30] = {0, 0, 0, 0, 0, 0,-9, 0, -5, -3, 0, -5, 0, 0, -5, -2, 0, 1, -1, 0, 0, 0, 0, 2, -1, 0, 1, 2, 0, 1};
static signed char ctbl30nit[30] = {0, 0, 0, 0, 0, 0,-9, 0, -7, -4, 0, -5, 0, 0, -6, -2, 0, 1, -1, 0, 0, 0, 0, 2, -1, 0, 1, 2, 0, 1};
static signed char ctbl32nit[30] = {0, 0, 0, 0, 0, 0,-9, 0, -6, -3, 0, -5, 1, 0, -6, -2, 0, 1, -1, 0, 0, 0, 0, 2, -1, 0, 1, 2, 0, 0};
static signed char ctbl34nit[30] = {0, 0, 0, 0, 0, 0,-9, 0, -6, -3, 0, -4, 1, 0, -6, -1, 0, 1, -1, 0, 0, 0, 0, 2, -1, 0, 1, 2, 0, 0};
static signed char ctbl37nit[30] = {0, 0, 0, 0, 0, 0,-9, 0, -7, -2, 0, -4, 1, 0, -6, -1, 0, 1, -1, 0, 0, 0, 0, 2, -1, 0, 1, 2, 0, 0};
static signed char ctbl39nit[30] = {0, 0, 0, 0, 0, 0,-8, 0, -4, -2, 0, -5, 1, 0, -6, -1, 0, 1, -1, 0, 0, 0, 0, 2, -1, 0, 1, 2, 0, 0};
static signed char ctbl41nit[30] = {0, 0, 0, 0, 0, 0,-8, 0, -3, -1, 0, -4, 2, 0, -6, -1, 0, 1, -1, 0, 0, -1, 0, 2, -1, 0, 1, 2, 0, 0};
static signed char ctbl44nit[30] = {0, 0, 0, 0, 0, 0,-7, 0, -2, -1, 0, -4, 2, 0, -6, -1, 0, 1, -1, 0, 0, -1, 0, 2, -1, 0, 1, 2, 0, 0};
static signed char ctbl47nit[30] = {0, 0, 0, 0, 0, 0,-6, 0, -3, -1, 0, -4, 2, 0, -6, -1, 0, 1, -1, 0, 0, -1, 0, 2, -1, 0, 1, 2, 0, 0};
static signed char ctbl50nit[30] = {0, 0, 0, 0, 0, 0,-5, 0, -1, -2, 0, -4, 3, 0, -5, -1, 0, 1, -1, 0, 0, -1, 0, 2, -1, 0, 1, 2, 0, 0};
static signed char ctbl53nit[30] = {0, 0, 0, 0, 0, 0,-5, 0, 0, -1, 0, -4, 3, 0, -5, -1, 0, 1, -1, 0, 0, -1, 0, 2, -1, 0, 1, 2, 0, 0};
static signed char ctbl56nit[30] = {0, 0, 0, 0, 0, 0,-5, 0, 1, -1, 0, -4, 3, 0, -5, -1, 0, 1, -1, 0, 0, -1, 0, 2, -1, 0, 1, 2, 0, 0};
static signed char ctbl60nit[30] = {0, 0, 0, 0, 0, 0,-5, 0, 3, 0, 0, -4, 3, 0, -5, -1, 0, 1, -1, 0, 0, -1, 0, 2, -1, 0, 1, 2, 0, 0};
static signed char ctbl64nit[30] = {0, 0, 0, 0, 0, 0,-5, 0, 4, 0, 0, -4, 3, 0, -5, -1, 0, 1, -1, 0, 0, -1, 0, 2, -1, 0, 1, 2, 0, 0};
static signed char ctbl68nit[30] = {0, 0, 0, 0, 0, 0,-6, 0, 0, 0, 0, -4, 3, 0, -5, 0, 0, 2, -1, 0, 0, -1, 0, 1, -1, 0, 0, 1, 0, 0};
static signed char ctbl72nit[30] = {0, 0, 0, 0, 0, 0,-5, 0, 0, 0, 0, -4, 2, 0, -4, 0, 0, 2, -1, 0, 0, -1, 0, 1, -1, 0, 0, 1, 0, 0};
static signed char ctbl77nit[30] = {0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 0, -3, 1, 0, -5, 0, 0, 2, -1, 0, 0, -1, 0, 1, -1, 0, 0, 1, 0, 0};
static signed char ctbl82nit[30] = {0, 0, 0, 0, 0, 0,-5, 0, 0, 0, 0, -3, 1, 0, -4, 0, 0, 2, -1, 0, 0, -1, 0, 1, -1, 0, 0, 1, 0, 0};
static signed char ctbl87nit[30] = {0, 0, 0, 0, 0, 0,-3, 0, 1, 0, 0, -4, 1, 0, -4, 0, 0, 3, -1, 0, -1, -1, 0, 1, -1, 0, 0, 1, 0, 0};
static signed char ctbl93nit[30] = {0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 0, -4, 3, 0, -4, -1, 0, 2, -1, 0, -1, -1, 0, 1, -1, 0, 0, 1, 0, 0};
static signed char ctbl98nit[30] = {0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 0, -4, 3, 0, -3, 0, 0, 2, -1, 0, -1, -1, 0, 1, -1, 0, 0, 1, 0, 0};
static signed char ctbl105nit[30] = {0, 0, 0, 0, 0, 0,-4, 0, 0, 0, 0, -4, 1, 0, -4, 0, 0, 2, -1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, 0};
static signed char ctbl111nit[30] = {0, 0, 0, 0, 0, 0,-3, 0, -1, 0, 0, -4, 1, 0, -3, 0, 0, 2, -1, 0, -1, 0, 0, 1, 0, 0, 0, 1, 0, 0};
static signed char ctbl119nit[30] = {0, 0, 0, 0, 0, 0,-2, 0, -1, 1, 0, -1, 0, 0, -3, 0, 0, 0, -1, 0, 0, -1, 0, 1, 1, 0, -1, 0, 0, 0};
static signed char ctbl126nit[30] = {0, 0, 0, 0, 0, 0,-1, 0, 0, 1, 0, -1, 1, 0, -3, -1, 0, 1, -1, 0, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0};
static signed char ctbl134nit[30] = {0, 0, 0, 0, 0, 0,-1, 0, 0, 1, 0, -1, 1, 0, -3, -1, 0, 1, -1, 0, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0};
static signed char ctbl143nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 1, 1, 0, -1, 1, 0, -3, -1, 0, 1, -1, 0, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0};
static signed char ctbl152nit[30] = {0, 0, 0, 0, 0, 0,1, 0, 1, 1, 0, -1, 1, 0, -3, -1, 0, 1, -1, 0, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0};
static signed char ctbl162nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 1, 0, 0, -2, 1, 0, -3, -1, 0, 1, 0, 0, 1, -1, 0, 0, 1, 0, -1, 0, 0, 0};
static signed char ctbl172nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 1, 0, 0, -2, 1, 0, -3, -1, 0, 1, 0, 0, 1, -1, 0, 0, 1, 0, -1, 0, 0, 0};
static signed char ctbl183nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static signed char ctbl195nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static signed char ctbl207nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static signed char ctbl220nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static signed char ctbl234nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static signed char ctbl249nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static signed char ctbl265nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static signed char ctbl282nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static signed char ctbl300nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static signed char ctbl316nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static signed char ctbl333nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static signed char ctbl360nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static signed char aid5[5] = {0xB2, 0x04, 0xEE, 0x00, 0x0F};
static signed char aid6[5] = {0xB2, 0x04, 0xE1, 0x00, 0x0F};
static signed char aid7[5] = {0xB2, 0x04, 0xD4, 0x00, 0x0F};
static signed char aid8[5] = {0xB2, 0x04, 0xCF, 0x00, 0x0F};
static signed char aid9[5] = {0xB2, 0x04, 0xC2, 0x00, 0x0F};
static signed char aid10[5] = {0xB2, 0x04, 0xB4, 0x00, 0x0F};
static signed char aid11[5] = {0xB2, 0x04, 0xAF, 0x00, 0x0F};
static signed char aid12[5] = {0xB2, 0x04, 0xA3, 0x00, 0x0F};
static signed char aid13[5] = {0xB2, 0x04, 0x96, 0x00, 0x0F};
static signed char aid14[5] = {0xB2, 0x04, 0x91, 0x00, 0x0F};
static signed char aid15[5] = {0xB2, 0x04, 0x82, 0x00, 0x0F};
static signed char aid16[5] = {0xB2, 0x04, 0x75, 0x00, 0x0F};
static signed char aid17[5] = {0xB2, 0x04, 0x70, 0x00, 0x0F};
static signed char aid19[5] = {0xB2, 0x04, 0x54, 0x00, 0x0F};
static signed char aid20[5] = {0xB2, 0x04, 0x50, 0x00, 0x0F};
static signed char aid21[5] = {0xB2, 0x04, 0x42, 0x00, 0x0F};
static signed char aid22[5] = {0xB2, 0x04, 0x33, 0x00, 0x0F};
static signed char aid24[5] = {0xB2, 0x04, 0x1E, 0x00, 0x0F};
static signed char aid25[5] = {0xB2, 0x04, 0x10, 0x00, 0x0F};
static signed char aid27[5] = {0xB2, 0x03, 0xF2, 0x00, 0x0F};
static signed char aid29[5] = {0xB2, 0x03, 0xDE, 0x00, 0x0F};
static signed char aid30[5] = {0xB2, 0x03, 0xC6, 0x00, 0x0F};
static signed char aid32[5] = {0xB2, 0x03, 0xB1, 0x00, 0x0F};
static signed char aid34[5] = {0xB2, 0x03, 0x95, 0x00, 0x0F};
static signed char aid37[5] = {0xB2, 0x03, 0x73, 0x00, 0x0F};
static signed char aid39[5] = {0xB2, 0x03, 0x5F, 0x00, 0x0F};
static signed char aid41[5] = {0xB2, 0x03, 0x43, 0x00, 0x0F};
static signed char aid44[5] = {0xB2, 0x03, 0x20, 0x00, 0x0F};
static signed char aid47[5] = {0xB2, 0x02, 0xFE, 0x00, 0x0F};
static signed char aid50[5] = {0xB2, 0x02, 0xDF, 0x00, 0x0F};
static signed char aid53[5] = {0xB2, 0x02, 0xB2, 0x00, 0x0F};
static signed char aid56[5] = {0xB2, 0x02, 0x90, 0x00, 0x0F};
static signed char aid60[5] = {0xB2, 0x02, 0x5E, 0x00, 0x0F};
static signed char aid64[5] = {0xB2, 0x02, 0x30, 0x00, 0x0F};
static signed char aid68[5] = {0xB2, 0x01, 0xF4, 0x00, 0x0F};
static signed char aid72[5] = {0xB2, 0x01, 0xF4, 0x00, 0x0F};
static signed char aid77[5] = {0xB2, 0x01, 0xF4, 0x00, 0x0F};
static signed char aid82[5] = {0xB2, 0x01, 0xF4, 0x00, 0x0F};
static signed char aid87[5] = {0xB2, 0x01, 0xF4, 0x00, 0x0F};
static signed char aid93[5] = {0xB2, 0x01, 0xF4, 0x00, 0x0F};
static signed char aid98[5] = {0xB2, 0x01, 0xF4, 0x00, 0x0F};
static signed char aid105[5] = {0xB2, 0x01, 0xF4, 0x00, 0x0F};
static signed char aid110[5] = {0xB2, 0x01, 0xF4, 0x00, 0x0F};
static signed char aid119[5] = {0xB2, 0x01, 0xF4, 0x00, 0x0F};
static signed char aid126[5] = {0xB2, 0x01, 0xBF, 0x00, 0x0F};
static signed char aid134[5] = {0xB2, 0x01, 0x82, 0x00, 0x0F};
static signed char aid143[5] = {0xB2, 0x01, 0x40, 0x00, 0x0F};
static signed char aid152[5] = {0xB2, 0x01, 0x00, 0x00, 0x0F};
static signed char aid162[5] = {0xB2, 0x00, 0xB2, 0x00, 0x0F};
static signed char aid172[5] = {0xB2, 0x00, 0x62, 0x00, 0x0F};
static signed char aid183[5] = {0xB2, 0x00, 0x0F, 0x00, 0x0F};
static signed char aid195[5] = {0xB2, 0x00, 0x0F, 0x00, 0x0F};
static signed char aid207[5] = {0xB2, 0x00, 0x0F, 0x00, 0x0F};
static signed char aid220[5] = {0xB2, 0x00, 0x0F, 0x00, 0x0F};
static signed char aid234[5] = {0xB2, 0x00, 0x0F, 0x00, 0x0F};
static signed char aid249[5] = {0xB2, 0x00, 0x0F, 0x00, 0x0F};
static signed char aid265[5] = {0xB2, 0x00, 0x0F, 0x00, 0x0F};
static signed char aid282[5] = {0xB2, 0x00, 0x0F, 0x00, 0x0F};
static signed char aid300[5] = {0xB2, 0x00, 0x0F, 0x00, 0x0F};
static signed char aid316[5] = {0xB2, 0x00, 0x0F, 0x00, 0x0F};
static signed char aid333[5] = {0xB2, 0x00, 0x0F, 0x00, 0x0F};
static signed char aid360[5] = {0xB2, 0x00, 0x0F, 0x00, 0x0F};
/* [0xB6] [1st] [2nd] [22th T > 0] [22th 0 >= T > -20] [22th T <= -20]*/
static unsigned char elv_HBM[6] = {0xB6, 0xBC, 0x0F, 0x00, 0x00, 0x00};
static unsigned char elv_360[6] = {0xB6, 0xBC, 0x0F, 0x00, 0x00, 0x00};
static unsigned char elv_333[6] = {0xB6, 0xBC, 0x10, 0x00, 0x00, 0x00};
static unsigned char elv_316[6] = {0xB6, 0xBC, 0x12, 0x00, 0x00, 0x00};
static unsigned char elv_300[6] = {0xB6, 0xBC, 0x13, 0x00, 0x00, 0x00};
static unsigned char elv_282[6] = {0xB6, 0xBC, 0x14, 0x00, 0x00, 0x00};
static unsigned char elv_265[6] = {0xB6, 0xBC, 0x16, 0x00, 0x00, 0x00};
static unsigned char elv_249[6] = {0xB6, 0xBC, 0x17, 0x00, 0x00, 0x00};
static unsigned char elv_234[6] = {0xB6, 0xBC, 0x18, 0x00, 0x00, 0x00};
static unsigned char elv_220[6] = {0xB6, 0xBC, 0x18, 0x00, 0x00, 0x00};
static unsigned char elv_207[6] = {0xB6, 0xBC, 0x1A, 0x00, 0x00, 0x00};
static unsigned char elv_195[6] = {0xB6, 0xBC, 0x1B, 0x00, 0x00, 0x00};
static unsigned char elv_183[6] = {0xB6, 0xBC, 0x1C, 0x00, 0x00, 0x00};
static unsigned char elv_143[6] = {0xB6, 0xBC, 0x1D, 0x00, 0x00, 0x00};
static unsigned char elv_111[6] = {0xB6, 0xBC, 0x1E, 0x00, 0x00, 0x00};
static unsigned char elv_41[6] = {0xB6, 0xBC, 0x1F, 0x00, 0x00, 0x00};
static unsigned char elv_30[6] = {0xB6, 0xAC, 0x1F, 0x00, 0x00, 0x00};
static unsigned char elv_29[6] = {0xB6, 0xAC, 0x1D, 0x07, 0x0A, 0x0A};
static unsigned char elv_27[6] = {0xB6, 0xAC, 0x1B, 0x07, 0x0B, 0x0C};
static unsigned char elv_25[6] = {0xB6, 0xAC, 0x19, 0x07, 0x0C, 0x0E};
static unsigned char elv_24[6] = {0xB6, 0xAC, 0x17, 0x07, 0x0D, 0x10};
static unsigned char elv_22[6] = {0xB6, 0xAC, 0x14, 0x07, 0x0E, 0x12};
static unsigned char elv_21[6] = {0xB6, 0xAC, 0x11, 0x07, 0x0F, 0x13};
static unsigned char elv_5[6] = {0xB6, 0xAC, 0x0F, 0x05, 0x0F, 0x13};
static unsigned char m_gray_005[] = {0, 7, 15, 20, 23, 32, 51, 87, 117, 143};
static unsigned char m_gray_006[] = {0, 7, 15, 19, 23, 32, 51, 86, 116, 143};
static unsigned char m_gray_007[] = {0, 7, 15, 19, 23, 32, 51, 87, 117, 143};
static unsigned char m_gray_008[] = {0, 7, 14, 18, 23, 31, 50, 87, 117, 143};
static unsigned char m_gray_009[] = {0, 7, 13, 18, 22, 31, 50, 87, 117, 143};
static unsigned char m_gray_010[] = {0, 7, 13, 18, 22, 31, 50, 86, 116, 143};
static unsigned char m_gray_011[] = {0, 7, 13, 17, 22, 30, 50, 86, 116, 143};
static unsigned char m_gray_012[] = {0, 7, 12, 17, 22, 31, 50, 87, 117, 143};
static unsigned char m_gray_013[] = {0, 7, 12, 17, 22, 30, 50, 86, 116, 143};
static unsigned char m_gray_014[] = {0, 7, 11, 17, 22, 31, 50, 87, 117, 143};
static unsigned char m_gray_015[] = {0, 7, 11, 16, 22, 30, 50, 86, 116, 143};
static unsigned char m_gray_016[] = {0, 7, 10, 16, 21, 30, 50, 86, 116, 143};
static unsigned char m_gray_017[] = {0, 7, 10, 16, 21, 30, 50, 87, 117, 143};
static unsigned char m_gray_019[] = {0, 7, 10, 16, 21, 30, 50, 86, 116, 143};
static unsigned char m_gray_020[] = {0, 7, 10, 16, 21, 30, 50, 87, 117, 143};
static unsigned char m_gray_021[] = {0, 7, 10, 16, 21, 30, 50, 87, 117, 143};
static unsigned char m_gray_022[] = {0, 7, 10, 16, 22, 30, 50, 87, 117, 143};
static unsigned char m_gray_024[] = {0, 7, 10, 16, 22, 31, 50, 87, 117, 143};
static unsigned char m_gray_025[] = {0, 7, 11, 17, 22, 31, 51, 87, 117, 143};
static unsigned char m_gray_027[] = {0, 7, 11, 17, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_029[] = {0, 7, 11, 17, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_030[] = {0, 7, 11, 17, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_032[] = {0, 7, 11, 17, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_034[] = {0, 7, 11, 17, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_037[] = {0, 7, 10, 17, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_039[] = {0, 7, 10, 16, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_041[] = {0, 7, 10, 16, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_044[] = {0, 6, 10, 16, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_047[] = {0, 6, 9, 16, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_050[] = {0, 6, 9, 16, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_053[] = {0, 6, 9, 15, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_056[] = {0, 6, 9, 15, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_060[] = {0, 5, 9, 15, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_064[] = {0, 5, 9, 15, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_068[] = {0, 5, 9, 15, 22, 31, 51, 88, 117, 143};
static unsigned char m_gray_072[] = {0, 5, 9, 15, 22, 31, 52, 89, 119, 146};
static unsigned char m_gray_077[] = {0, 5, 9, 16, 23, 32, 54, 93, 124, 151};
static unsigned char m_gray_082[] = {0, 5, 9, 16, 23, 33, 56, 95, 127, 156};
static unsigned char m_gray_087[] = {0, 5, 9, 16, 24, 34, 59, 98, 130, 160};
static unsigned char m_gray_093[] = {0, 5, 9, 17, 25, 35, 60, 101, 134, 165};
static unsigned char m_gray_098[] = {0, 5, 9, 17, 25, 36, 62, 104, 138, 170};
static unsigned char m_gray_105[] = {0, 5, 10, 18, 26, 38, 64, 107, 142, 176};
static unsigned char m_gray_111[] = {0, 5, 10, 18, 27, 39, 66, 110, 146, 180};
static unsigned char m_gray_119[] = {0, 5, 10, 19, 28, 40, 68, 113, 150, 186};
static unsigned char m_gray_126[] = {0, 5, 10, 19, 28, 40, 68, 113, 150, 186};
static unsigned char m_gray_134[] = {0, 5, 10, 19, 28, 40, 68, 113, 150, 186};
static unsigned char m_gray_143[] = {0, 4, 10, 19, 28, 40, 68, 113, 150, 186};
static unsigned char m_gray_152[] = {0, 4, 10, 19, 28, 39, 68, 113, 150, 186};
static unsigned char m_gray_162[] = {0, 4, 10, 19, 28, 39, 67, 113, 150, 186};
static unsigned char m_gray_172[] = {0, 4, 10, 19, 28, 39, 67, 113, 150, 186};
static unsigned char m_gray_183[] = {0, 4, 10, 19, 28, 39, 67, 113, 149, 186};
static unsigned char m_gray_195[] = {0, 4, 10, 19, 28, 40, 68, 117, 154, 192};
static unsigned char m_gray_207[] = {0, 4, 10, 20, 29, 41, 70, 120, 158, 197};
static unsigned char m_gray_220[] = {0, 4, 10, 20, 30, 43, 72, 123, 163, 203};
static unsigned char m_gray_234[] = {0, 4, 10, 21, 31, 44, 74, 126, 167, 208};
static unsigned char m_gray_249[] = {0, 4, 10, 21, 31, 45, 76, 130, 172, 215};
static unsigned char m_gray_265[] = {0, 4, 10, 22, 32, 46, 78, 134, 177, 221};
static unsigned char m_gray_282[] = {0, 4, 10, 21, 33, 47, 80, 137, 182, 227};
static unsigned char m_gray_300[] = {0, 3, 10, 22, 34, 49, 82, 140, 187, 234};
static unsigned char m_gray_316[] = {0, 3, 10, 23, 34, 50, 84, 143, 191, 240};
static unsigned char m_gray_333[] = {0, 3, 11, 23, 35, 51, 85, 147, 196, 246};
static unsigned char m_gray_360[] = {0, 3, 11, 23, 35, 51, 87, 151, 203, 255};
#endif

View file

@ -0,0 +1,771 @@
/* linux/drivers/video/exynos/decon_7580/panels/s6e8aa5x01_dimming.h
*
* Header file for Samsung AID Dimming Driver.
*
* Copyright (c) 2013 Samsung Electronics
* Minwoo Kim <minwoo7945.kim@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 __S6E8AA5X01_DIMMING_H__
#define __S6E8AA5X01_DIMMING_H__
#include <linux/types.h>
#include <linux/kernel.h>
/* CAUTION !!!
This file was generated by Smart Dimming Header Generation Tool Do not modify manually */
struct v_constant {
int nu;
int de;
};
enum {
V0 = 0,
V3,
V11,
V23,
V35,
V51,
V87,
V151,
V203,
V255,
VMAX
};
#define VT V0
#define NUM_VREF VMAX /* 10 */
#define LDI_MODEL S6E8AA5X01
#define MAX_BRIGHTNESS 360
#define MAX_GRADATION 256
#define MULTIPLY_VALUE 1024
#define MULTIPLE_VREGOUT 5939
#define DOUBLE_MULTIPLE_VREGOUT 6081740
#define REFERENCE_GAMMA 20
#define MAX_GRAYSCALE 255
#define TBL_INDEX_V0 0
#define TBL_INDEX_V3 3
#define TBL_INDEX_V11 11
#define TBL_INDEX_V23 23
#define TBL_INDEX_V35 35
#define TBL_INDEX_V51 51
#define TBL_INDEX_V87 87
#define TBL_INDEX_V151 151
#define TBL_INDEX_V203 203
#define TBL_INDEX_V255 255
#define OLED_CMD_GAMMA_CNT 34
#define OLED_CMD_ELVSS_CNT 3
#define OLED_CMD_AID_CNT 6
#define OLED_CMD_GAMMA 0xCA
#define OLED_CMD_HBM_GAMMA 0xB4
#define MAX_BR_INFO 63
#define HAS_NO_V0_GAMMA
#define dimm_err(fmt, ...) \
do { \
pr_err(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define dimm_info(fmt, ...) \
do { \
pr_info(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define dimm_dbg(fmt, ...) \
do { \
pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
static const unsigned int vref_index[NUM_VREF] = {
TBL_INDEX_V0,
TBL_INDEX_V3,
TBL_INDEX_V11,
TBL_INDEX_V23,
TBL_INDEX_V35,
TBL_INDEX_V51,
TBL_INDEX_V87,
TBL_INDEX_V151,
TBL_INDEX_V203,
TBL_INDEX_V255,
};
static const int vreg_element_max[NUM_VREF] = {
0x0f,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0x1ff,
};
static const struct v_constant vt_fix_const = {
.nu = 0,
.de = 860
};
static const struct v_constant fix_const[NUM_VREF] = {
{.nu = 0, .de = 860},
{.nu = 64, .de = 320},
{.nu = 64, .de = 320},
{.nu = 64, .de = 320},
{.nu = 64, .de = 320},
{.nu = 64, .de = 320},
{.nu = 64, .de = 320},
{.nu = 64, .de = 320},
{.nu = 64, .de = 320},
{.nu = 72, .de = 860},
};
// < precalculated VT volgate * 1024 *1024 >
// DOUBLE_MULTIPLE_VREGOUT * (de_VT - VT voltage hex Value) /de_VT
// VT voltage hex Value's hex value is from table in Base Luminance of Dynamic sheet excel
// MTP VT gamma can be from 0x0 to 0xF
static const unsigned int vt_trans_volt[16] = {
6081741, 5996879, 5912018, 5827156, 5742295, 5657433, 5572572, 5487710,
5402849, 5317987, 5105834, 5035116, 4964398, 4893680, 4822962, 4766388,
};
// < precalculated V255 volgate * 1024 *1024 >
// DOUBLE_MULTIPLE_VREGOUT - DOUBLE_MULTIPLE_VREGOUT(256 + MTP V255 gamma +nu_v255) /de_V255
// MTP V255 gamma can be from -256 to +255
static const unsigned int v255_trans_volt[512] = {
5572572,
5565500,
5558428,
5551356,
5544285,
5537213,
5530141,
5523069,
5515997,
5508926,
5501854,
5494782,
5487710,
5480639,
5473567,
5466495,
5459423,
5452351,
5445280,
5438208,
5431136,
5424064,
5416992,
5409921,
5402849,
5395777,
5388705,
5381633,
5374562,
5367490,
5360418,
5353346,
5346274,
5339203,
5332131,
5325059,
5317987,
5310916,
5303844,
5296772,
5289700,
5282628,
5275557,
5268485,
5261413,
5254341,
5247269,
5240198,
5233126,
5226054,
5218982,
5211910,
5204839,
5197767,
5190695,
5183623,
5176551,
5169480,
5162408,
5155336,
5148264,
5141193,
5134121,
5127049,
5119977,
5112905,
5105834,
5098762,
5091690,
5084618,
5077546,
5070475,
5063403,
5056331,
5049259,
5042187,
5035116,
5028044,
5020972,
5013900,
5006828,
4999757,
4992685,
4985613,
4978541,
4971470,
4964398,
4957326,
4950254,
4943182,
4936111,
4929039,
4921967,
4914895,
4907823,
4900752,
4893680,
4886608,
4879536,
4872464,
4865393,
4858321,
4851249,
4844177,
4837105,
4830034,
4822962,
4815890,
4808818,
4801747,
4794675,
4787603,
4780531,
4773459,
4766388,
4759316,
4752244,
4745172,
4738100,
4731029,
4723957,
4716885,
4709813,
4702741,
4695670,
4688598,
4681526,
4674454,
4667382,
4660311,
4653239,
4646167,
4639095,
4632024,
4624952,
4617880,
4610808,
4603736,
4596665,
4589593,
4582521,
4575449,
4568377,
4561306,
4554234,
4547162,
4540090,
4533018,
4525947,
4518875,
4511803,
4504731,
4497659,
4490588,
4483516,
4476444,
4469372,
4462301,
4455229,
4448157,
4441085,
4434013,
4426942,
4419870,
4412798,
4405726,
4398654,
4391583,
4384511,
4377439,
4370367,
4363295,
4356224,
4349152,
4342080,
4335008,
4327936,
4320865,
4313793,
4306721,
4299649,
4292578,
4285506,
4278434,
4271362,
4264290,
4257219,
4250147,
4243075,
4236003,
4228931,
4221860,
4214788,
4207716,
4200644,
4193572,
4186501,
4179429,
4172357,
4165285,
4158213,
4151142,
4144070,
4136998,
4129926,
4122855,
4115783,
4108711,
4101639,
4094567,
4087496,
4080424,
4073352,
4066280,
4059208,
4052137,
4045065,
4037993,
4030921,
4023849,
4016778,
4009706,
4002634,
3995562,
3988490,
3981419,
3974347,
3967275,
3960203,
3953132,
3946060,
3938988,
3931916,
3924844,
3917773,
3910701,
3903629,
3896557,
3889485,
3882414,
3875342,
3868270,
3861198,
3854126,
3847055,
3839983,
3832911,
3825839,
3818767,
3811696,
3804624,
3797552,
3790480,
3783409,
3776337,
3769265,
3762193,
3755121,
3748050,
3740978,
3733906,
3726834,
3719762,
3712691,
3705619,
3698547,
3691475,
3684403,
3677332,
3670260,
3663188,
3656116,
3649044,
3641973,
3634901,
3627829,
3620757,
3613686,
3606614,
3599542,
3592470,
3585398,
3578327,
3571255,
3564183,
3557111,
3550039,
3542968,
3535896,
3528824,
3521752,
3514680,
3507609,
3500537,
3493465,
3486393,
3479321,
3472250,
3465178,
3458106,
3451034,
3443963,
3436891,
3429819,
3422747,
3415675,
3408604,
3401532,
3394460,
3387388,
3380316,
3373245,
3366173,
3359101,
3352029,
3344957,
3337886,
3330814,
3323742,
3316670,
3309598,
3302527,
3295455,
3288383,
3281311,
3274240,
3267168,
3260096,
3253024,
3245952,
3238881,
3231809,
3224737,
3217665,
3210593,
3203522,
3196450,
3189378,
3182306,
3175234,
3168163,
3161091,
3154019,
3146947,
3139875,
3132804,
3125732,
3118660,
3111588,
3104517,
3097445,
3090373,
3083301,
3076229,
3069158,
3062086,
3055014,
3047942,
3040870,
3033799,
3026727,
3019655,
3012583,
3005511,
2998440,
2991368,
2984296,
2977224,
2970152,
2963081,
2956009,
2948937,
2941865,
2934794,
2927722,
2920650,
2913578,
2906506,
2899435,
2892363,
2885291,
2878219,
2871147,
2864076,
2857004,
2849932,
2842860,
2835788,
2828717,
2821645,
2814573,
2807501,
2800429,
2793358,
2786286,
2779214,
2772142,
2765071,
2757999,
2750927,
2743855,
2736783,
2729712,
2722640,
2715568,
2708496,
2701424,
2694353,
2687281,
2680209,
2673137,
2666065,
2658994,
2651922,
2644850,
2637778,
2630706,
2623635,
2616563,
2609491,
2602419,
2595348,
2588276,
2581204,
2574132,
2567060,
2559989,
2552917,
2545845,
2538773,
2531701,
2524630,
2517558,
2510486,
2503414,
2496342,
2489271,
2482199,
2475127,
2468055,
2460983,
2453912,
2446840,
2439768,
2432696,
2425625,
2418553,
2411481,
2404409,
2397337,
2390266,
2383194,
2376122,
2369050,
2361978,
2354907,
2347835,
2340763,
2333691,
2326619,
2319548,
2312476,
2305404,
2298332,
2291260,
2284189,
2277117,
2270045,
2262973,
2255902,
2248830,
2241758,
2234686,
2227614,
2220543,
2213471,
2206399,
2199327,
2192255,
2185184,
2178112,
2171040,
2163968,
2156896,
2149825,
2142753,
2135681,
2128609,
2121537,
2114466,
2107394,
2100322,
2093250,
2086179,
2079107,
2072035,
2064963,
2057891,
2050820,
2043748,
2036676,
2029604,
2022532,
2015461,
2008389,
2001317,
1994245,
1987173,
1980102,
1973030,
1965958,
1958886,
};
static const unsigned int v203_trans_volt[256] = {
204, 207, 211, 214, 217, 220, 224, 227,
230, 233, 236, 240, 243, 246, 249, 252,
256, 259, 262, 265, 268, 271, 275, 278,
281, 284, 288, 291, 294, 297, 300, 304,
307, 310, 313, 316, 320, 323, 326, 329,
332, 335, 339, 342, 345, 348, 352, 355,
358, 361, 364, 368, 371, 374, 377, 380,
384, 387, 390, 393, 396, 399, 403, 406,
409, 412, 416, 419, 422, 425, 428, 432,
435, 438, 441, 444, 448, 451, 454, 457,
460, 463, 467, 470, 473, 476, 480, 483,
486, 489, 492, 496, 499, 502, 505, 508,
512, 515, 518, 521, 524, 527, 531, 534,
537, 540, 544, 547, 550, 553, 556, 560,
563, 566, 569, 572, 576, 579, 582, 585,
588, 591, 595, 598, 601, 604, 608, 611,
614, 617, 620, 624, 627, 630, 633, 636,
640, 643, 646, 649, 652, 655, 659, 662,
665, 668, 672, 675, 678, 681, 684, 688,
691, 694, 697, 700, 704, 707, 710, 713,
716, 719, 723, 726, 729, 732, 736, 739,
742, 745, 748, 752, 755, 758, 761, 764,
768, 771, 774, 777, 780, 783, 787, 790,
793, 796, 800, 803, 806, 809, 812, 816,
819, 822, 825, 828, 832, 835, 838, 841,
844, 847, 851, 854, 857, 860, 864, 867,
870, 873, 876, 880, 883, 886, 889, 892,
896, 899, 902, 905, 908, 911, 915, 918,
921, 924, 928, 931, 934, 937, 940, 944,
947, 950, 953, 956, 960, 963, 966, 969,
972, 975, 979, 982, 985, 988, 992, 995,
998, 1001, 1004, 1008, 1011, 1014, 1017, 1020,
};
static const short int_tbl_v0_v3[2] = {
341, 683,
};
static const short int_tbl_v3_v11[7] = {
128, 256, 384, 512, 640, 768, 896,
};
static const short int_tbl_v11_v23[11] = {
85, 171, 256, 341, 427, 512, 597, 683,
768, 853, 939,
};
static const short int_tbl_v23_v35[11] = {
85, 171, 256, 341, 427, 512, 597, 683,
768, 853, 939,
};
static const short int_tbl_v35_v51[15] = {
64, 128, 192, 256, 320, 384, 448, 512,
576, 640, 704, 768, 832, 896, 960,
};
static const short int_tbl_v51_v87[35] = {
28, 57, 85, 114, 142, 171, 199, 228,
256, 284, 313, 341, 370, 398, 427, 455,
484, 512, 540, 569, 597, 626, 654, 683,
711, 740, 768, 796, 825, 853, 882, 910,
939, 967, 996,
};
static const short int_tbl_v87_v151[63] = {
16, 32, 48, 64, 80, 96, 112, 128,
144, 160, 176, 192, 208, 224, 240, 256,
272, 288, 304, 320, 336, 352, 368, 384,
400, 416, 432, 448, 464, 480, 496, 512,
528, 544, 560, 576, 592, 608, 624, 640,
656, 672, 688, 704, 720, 736, 752, 768,
784, 800, 816, 832, 848, 864, 880, 896,
912, 928, 944, 960, 976, 992, 1008,
};
static const short int_tbl_v151_v203[51] = {
20, 39, 59, 79, 98, 118, 138, 158,
177, 197, 217, 236, 256, 276, 295, 315,
335, 354, 374, 394, 414, 433, 453, 473,
492, 512, 532, 551, 571, 591, 610, 630,
650, 670, 689, 709, 729, 748, 768, 788,
807, 827, 847, 866, 886, 906, 926, 945,
965, 985, 1004,
};
static const short int_tbl_v203_v255[51] = {
20, 39, 59, 79, 98, 118, 138, 158,
177, 197, 217, 236, 256, 276, 295, 315,
335, 354, 374, 394, 414, 433, 453, 473,
492, 512, 532, 551, 571, 591, 610, 630,
650, 670, 689, 709, 729, 748, 768, 788,
807, 827, 847, 866, 886, 906, 926, 945,
965, 985, 1004,
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,262 @@
#ifndef __S6E8AA5X01_PARAM_H__
#define __S6E8AA5X01_PARAM_H__
#include <linux/types.h>
#include <linux/kernel.h>
struct lcd_seq_info {
unsigned char *cmd;
unsigned int len;
unsigned int sleep;
};
enum {
HBM_STATUS_OFF,
HBM_STATUS_ON,
HBM_STATUS_MAX,
};
enum {
ACL_STATUS_0P,
ACL_STATUS_15P,
ACL_STATUS_MAX
};
enum {
ACL_OPR_16_FRAME,
ACL_OPR_32_FRAME,
ACL_OPR_MAX
};
#define POWER_IS_ON(pwr) (pwr <= FB_BLANK_NORMAL)
#define LEVEL_IS_HBM(brightness) (brightness == EXTEND_BRIGHTNESS)
#define UNDER_MINUS_20(temperature) (temperature <= -20)
#define ACL_IS_ON(nit) (nit != 360)
#define NORMAL_TEMPERATURE 25 /* 25 degrees Celsius */
#define EXTEND_BRIGHTNESS 355
#define UI_MAX_BRIGHTNESS 255
#define UI_MIN_BRIGHTNESS 0
#define UI_DEFAULT_BRIGHTNESS 134
// 0xC8h Info
// 01~39th : gamma mtp
// 41~45th : manufacture date
// 73~87th : HBM gamma
#define S6E8AA5X01_MTP_ADDR 0xC8
#define S6E8AA5X01_MTP_SIZE 33
#define S6E8AA5X01_MTP_HBM_GAMMA_SIZE 21
#define S6E8AA5X01_MTP_DATE_SIZE 87
#define S6E8AA5X01_MTP_OFFSET_GAMMA 0x00 //0
#define S6E8AA5X01_MTP_OFFSET_DATE 0x28 //40
#define S6E8AA5X01_MTP_OFFSET_HBM 0x48 //72
#define S6E8AA5X01_MTP_SIZE_GAMMA 39
#define S6E8AA5X01_MTP_SIZE_DATE 5
#define S6E8AA5X01_MTP_SIZE_HBM 15
#define S6E8AA5X01_CODE_REG 0xD5
#define S6E8AA5X01_CODE_LEN 5
#define S6E8AA5X01_COORDINATE_REG 0xD7
#define S6E8AA5X01_COORDINATE_LEN 7 /*4~7th*/
#define S6E8AA5X01_ID_REG 0x04
#define S6E8AA5X01_ID_LEN 3
#define S6E8AA5X01_CHIP_ID_REG 0xD5
#define S6E8AA5X01_CHIP_ID_LEN 5
#define TSET_REG 0xB8
#define TSET_LEN 2
#define ELVSS_REG 0xB6
#define ELVSS_MTP_LEN 22
#define ELVSS_LEN 3
#define S6E8AA5X01_DATE_REG 0xD7
#define S6E8AA5X01_DATE_LEN 7 /* 4 ~ 7th para */
#define GAMMA_CMD_CNT 34
#define AID_CMD_CNT 5
#define ELVSS_CMD_CNT 3
#define HBM_GAMMA_CMD_CNT 35
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,
0x00, 0x00, 0x00
};
static const unsigned char SEQ_AID_SET[] = {
0xB2,
0x40, 0x0A, 0x17, 0x00, 0x0A,
};
static const unsigned char SEQ_ELVSS_SET[] = {
0xB6,
0x2C, 0x0B,
};
static const unsigned char SEQ_ELVSS_GLOBAL[] = {
0xB0,
0x15,
};
static const unsigned char SEQ_HBM_OFF[] = {
0x53,
0x00,
};
static const unsigned char SEQ_HBM_ON[] = {
0x53,
0xC0,
};
static const unsigned char SEQ_ACL_SET[] = {
0x55,
0x01,
};
static const unsigned char SEQ_ACL_15[] = {
0x55,
0x02,
};
static const unsigned char SEQ_ACL_ON_OPR_AVR[] = {
0xB5,
0x50
};
static const unsigned char SEQ_ACL_OFF_OPR_AVR[] = {
0xB5,
0x40
};
/* ACL on 15% */
static const unsigned char SEQ_ACL_SET_S6E88A0[] = {
0x55,
0x01,
};
static const unsigned char SEQ_SLEEP_IN[] = {
0x10,
0x00, 0x00
};
static const unsigned char SEQ_SLEEP_OUT[] = {
0x11,
0x00, 0x00
};
static const unsigned char SEQ_DISPLAY_ON[] = {
0x29,
0x00, 0x00
};
static const unsigned char SEQ_DISPLAY_OFF[] = {
0x28,
0x00, 0x00
};
static const unsigned char SEQ_TEST_KEY_ON_F0[] = {
0xF0,
0x5A, 0x5A,
};
static const unsigned char SEQ_TEST_KEY_OFF_F0[] = {
0xF0,
0xA5, 0xA5,
};
static const unsigned char SEQ_TEST_KEY_ON_F1[] = {
0xF1,
0x5A, 0x5A,
};
static const unsigned char SEQ_TEST_KEY_OFF_F1[] = {
0xF1,
0xA5, 0xA5,
};
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_PENTILE_SETTING[] = {
0xC0,
0xD8, 0xD8, 0x40, /* pentile setting */
};
static const unsigned char SEQ_DE_DIM_GP[] = {
0xB0,
0x06, /* Global para(7th) */
};
static const unsigned char SEQ_DE_DIM_SETTING[] = {
0xB8,
0xA8, /* DE_DIN On */
};
static const unsigned char SEQ_AID_360NIT[] = {
0xB2,
0x00, 0x0F, 0x00, 0x0F,
};
static const unsigned char SEQ_ELVSS_360NIT[] = {
0xB6,
0xBC, 0x0F,
};
static const unsigned char SEQ_GAMMA_UPDATE[] = {
0xF7,
0x03,
};
static const unsigned char SEQ_GAMMA_UPDATE_L[] = {
0xF7,
0x00,
};
static const unsigned char SEQ_ACL_OFF_OPR[] = {
0xB5,
0x40, /* 0x40 : at ACL OFF */
};
static const unsigned char SEQ_ACL_OFF[] = {
0x55,
0x00, /* 0x00 : ACL OFF */
};
static const unsigned char SEQ_TSET_GP[] = {
0xB0,
0x07,
};
static const unsigned char SEQ_TSET[] = {
0xB8,
0x19,
};
static const unsigned char SEQ_MTP_READ_DATE_GP[] = {
0xB0,
S6E8AA5X01_MTP_OFFSET_DATE,
};
static const unsigned char SEQ_MTP_READ_HBM_GP[] = {
0xB0,
S6E8AA5X01_MTP_OFFSET_HBM,
};
#endif /* __S6E8AA5X01_PARAM_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,297 @@
#ifndef __TD4100_PARAM_H__
#define __TD4100_PARAM_H__
#include <linux/types.h>
#include <linux/kernel.h>
#define EXTEND_BRIGHTNESS 306
#define UI_MAX_BRIGHTNESS 255
#define UI_MIN_BRIGHTNESS 0
#define UI_DEFAULT_BRIGHTNESS 128
#define TDDI_MAX_BRIGHTNESS 180
#define TDDI_OUTDOOR_BRIGHTNESS 220
#define LEVEL_IS_HBM(brightness) (brightness == EXTEND_BRIGHTNESS)
struct lcd_seq_info {
unsigned char *cmd;
unsigned int len;
unsigned int sleep;
};
struct ISL98611_rom_data {
u8 addr;
u8 val;
};
static const struct ISL98611_rom_data ISL98611_INIT[] = {
{0x01, 0x00},
{0x02, 0xBF},
{0x03, 0x02},
{0x04, 0x14},
{0x05, 0x14},
{0x06, 0xF4},
{0x10, 0xFF},
{0x11, 0x07},
{0x12, 0xBF},
{0x13, 0x87},
{0x14, 0xFD},
{0x16, 0xF5},
{0x17, 0x8D},
};
static const unsigned char SEQ_TD4100_BLON[] = {
0x53,
0x0C,
};
static const unsigned char SEQ_TD4100_BL[] = {
0x51,
0xFF,
};
static const unsigned char SEQ_TD4100_ADDRESS[] = {
0x36,
0x40, 0x00
};
static const unsigned char SEQ_TEON_CTL[] = {
0x35,
0x01,
};
static const unsigned char SEQ_SLEEP_OUT[] = {
0x11,
0x00, 0x00
};
const const unsigned char SEQ_SLEEP_IN[] = {
0x10,
0x00, 0x00
};
const const unsigned char SEQ_DISPLAY_OFF[] = {
0x28,
0x00, 0x00
};
static const unsigned char SEQ_DISPLAY_ON[] = {
0x29,
0x00, 0x00
};
static const unsigned char SEQ_TD4100_CABC_OFF[] = {
0x55,
0x00,
};
static const unsigned char SEQ_TD4100_B0[] = {
0xB0,
0x04,
};
static const unsigned char SEQ_TD4100_B3[] = {
0xB3,
0x10, 0x00, 0x06,
};
static const unsigned char SEQ_TD4100_B6[] = {
0xB6,
0x33, 0x43, 0x80, 0x00, 0x00, 0x07, 0x86,
};
static const unsigned char SEQ_TD4100_BA[] = {
0xBA,
0x07, 0x87, 0x3A, 0x0A, 0x2D, 0x88,
};
static const unsigned char SEQ_TD4100_BB[] = {
0xBB,
0x00, 0xB4, 0xA0,
};
static const unsigned char SEQ_TD4100_BC[] = {
0xBC,
0x00, 0xB4, 0xA0,
};
static const unsigned char SEQ_TD4100_BD[] = {
0xBD,
0x00, 0xB4, 0xA0,
};
static const unsigned char SEQ_TD4100_BE[] = {
0xBE,
0x04,
};
static const unsigned char SEQ_TD4100_C0[] = {
0xC0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char SEQ_TD4100_C1[] = {
0xC1,
0x04, 0x48, 0x01, 0x00, 0x33, 0x08, 0x11, 0x00, 0x11, 0x00,
0x73, 0x23, 0x23, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0x00, 0x30, 0x00,
0x01, 0x00, 0x00, 0x00,
};
static const unsigned char SEQ_TD4100_C2[] = {
0xC2,
0x00, 0xF0, 0x05, 0x00, 0x0A, 0x04, 0x08, 0x00, 0x24, 0x19,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
};
static const unsigned char SEQ_TD4100_C3[] = {
0xC3,
0x51, 0x15, 0x11, 0x51, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x03, 0x28, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x01,
0x00, 0x00, 0x00, 0x00, 0x6C, 0x01, 0x00, 0x00, 0x00, 0x00,
0x40, 0x20, 0x04,
};
static const unsigned char SEQ_TD4100_C4[] = {
0xC4,
0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
};
static const unsigned char SEQ_TD4100_C5[] = {
0xC5,
0x08, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x2D, 0x41,
};
static const unsigned char SEQ_TD4100_C6[] = {
0xC6,
0xB8, 0x25, 0x9B, 0x00, 0x00, 0x25, 0x9B, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xC3, 0xB8,
};
static const unsigned char SEQ_TD4100_C7[] = {
0xC7,
0x01, 0x12, 0x1E, 0x2D, 0x39, 0x46, 0x5F, 0x71, 0x80, 0x8E,
0x40, 0x4E, 0x5B, 0x6E, 0x78, 0x84, 0x9A, 0x98, 0xA0, 0x00,
0x12, 0x1E, 0x2C, 0x39, 0x46, 0x5F, 0x71, 0x84, 0x8E, 0x44,
0x4E, 0x5B, 0x6E, 0x78, 0x84, 0x8F, 0x9A, 0xA0, 0x00, 0x97,
0x00, 0x97, 0x00, 0x97, 0x00, 0x97,
};
static const unsigned char SEQ_TD4100_C8[] = {
0xC8,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFC, 0x00,
};
static const unsigned char SEQ_TD4100_C9[] = {
0xC9,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00,
};
static const unsigned char SEQ_TD4100_CA[] = {
0xCA,
0x1D, 0xFA, 0xFC, 0xFA, 0x00, 0xE6, 0xE1, 0xA5, 0x00, 0xDB,
0xB1, 0xDC, 0x00, 0xCD, 0x00, 0x05, 0xF7, 0xE5, 0x00, 0x00,
0x07, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
};
static const unsigned char SEQ_TD4100_CC[] = {
0xCC,
0x00, 0x00, 0xD2, 0x72, 0x46, 0x42, 0x12, 0x16, 0x1A, 0x1E,
0x00, 0x00, 0xD0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x70, 0xD0, 0x00, 0x00, 0x1C, 0x18, 0x14, 0x10, 0x40, 0x44,
0x72, 0xD2, 0x00, 0x00, 0x00,
};
static const unsigned char SEQ_TD4100_CD[] = {
0xCD,
0x32, 0x05, 0x6E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
};
static const unsigned char SEQ_TD4100_CE[] = {
0xCE,
0x7d, 0x40, 0x48, 0x56, 0x67, 0x78, 0x88, 0x98, 0xA7, 0xB5,
0xC3, 0xD1, 0xDE, 0xE9, 0xF2, 0xFA, 0xFF, 0x04, 0x00, 0x04,
0x04, 0x45, 0x00, 0x00,
};
static const unsigned char SEQ_TD4100_CF[] = {
0xCF,
0x48, 0x10
};
static const unsigned char SEQ_TD4100_D0[] = {
0xD0,
0x11, 0x04, 0x5A, 0xDA, 0x03, 0x10, 0x10, 0x40, 0x19, 0x08,
0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char SEQ_TD4100_D1[] = {
0xD1,
0x04
};
static const unsigned char SEQ_TD4100_D3[] = {
0xD3,
0xBB, 0x3B, 0x33, 0x3B, 0x44, 0x3B, 0x44, 0x3B, 0x00, 0x00,
0xEC, 0x9B, 0x8B, 0x23, 0x22, 0xD5, 0xD9, 0x3B, 0xBB, 0x4F,
0xD0, 0x3C, 0x10, 0x12, 0x10, 0x00, 0x10,
};
static const unsigned char SEQ_TD4100_D4[] = {
0xD4,
0x80, 0x04, 0x04, 0x33, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x90,
0x05, 0x00, 0x64, 0x94,
};
static const unsigned char SEQ_TD4100_D6_C1[] = {
0xD6,
0xC1
};
static const unsigned char SEQ_TD4100_D6_01[] = {
0xD6,
0x01
};
static const unsigned char SEQ_TD4100_D7[] = {
0xD7,
0xF6, 0xFF, 0x03, 0x05, 0x43, 0x24, 0x80, 0x1F, 0xC7, 0x1F,
0x1B, 0x00, 0x0F, 0x01, 0x20, 0x08, 0x80, 0x3F, 0x00, 0x78,
0x00, 0x40, 0x24, 0x15, 0x00, 0x33, 0x02, 0xC0, 0xAF, 0xCB,
0x60, 0x30, 0xFC, 0x00, 0x3F, 0x00,
};
static const unsigned char SEQ_TD4100_D8[] = {
0xD8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char SEQ_TD4100_DD[] = {
0xDD,
0x30, 0x06, 0x23, 0x65,
};
static const unsigned char SEQ_TD4100_DE[] = {
0xDE,
0x00, 0xFF, 0xFF, 0x90,
};
#endif /* __TD4100_PARAM_H__ */

View file

@ -0,0 +1,262 @@
/*
* drivers/video/fbdev/exynos/decon_7570/regs-decon.h
*
* Register definition file for Samsung DECON driver
*
* Copyright (c) 2015 Samsung Electronics
* Jiun Yu <jiun.yu@samsung.com>
* Shaik Ameer Basha <shaik.ameer@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_DECON_H
#define _REGS_DECON_H
#define VIDCON0 0x0000
#define VIDCON0_SWRESET (1 << 28)
#define VIDCON0_DECON_STOP_STATUS (1 << 2)
#define VIDCON0_ENVID (1 << 1)
#define VIDCON0_ENVID_F (1 << 0)
#define VIDOUTCON0 0x0004
#define VIDOUTCON0_LCD_ON_F (0x1 << 24)
#define VIDOUTCON0_IF_MASK (0x1 << 23)
#define VIDOUTCON0_RGBIF_F (0x0 << 23)
#define VIDOUTCON0_I80IF_F (0x1 << 23)
#define VCLKCON0 0x0010
#define ECLK_IDLE_GATE_EN (1 << 12)
#define VCLKCON0_CLKVALUP (1 << 8)
#define VCLKCON0_VLCKFREE (1 << 0)
#define VCLKCON1 (0x0014)
#define VCLKCON1_DENOM_VALUE_OF_CLK_F(_v) ((_v) << 16)
#define VCLKCON1_NUM_VALUE_OF_CLK_F(_v) ((_v) << 0)
#define VCLKCON1_DENOM_VALUE_OF_CLK_F_MASK (0x3ff << 16)
#define VCLKCON1_NUM_VALUE_OF_CLK_F_MASK (0x3ff << 0)
#define VCLKCON2 (0x0018)
#define SHADOWCON 0x0030
#define SHADOWCON_WIN_PROTECT(_win) (1 << (8 + (_win)))
#define SHADOWCON_AUTO_PROTECT (1 << 0)
#define WINCHMAP0 0x0040
#define WINCHMAP_MASK(_win) (0x7 << ((_win) * 4))
#define WINCHMAP_DMA(_v, _win) ((_v) << ((_win) * 4))
#define WINCHMAP0_W5CHMAP_F(_v) ((_v) << 20)
#define WINCHMAP0_W5CHMAP_F_MASK (0x7 << 20)
#define WINCHMAP0_W4CHMAP_F(_v) ((_v) << 16)
#define WINCHMAP0_W4CHMAP_F_MASK (0x7 << 16)
#define WINCHMAP0_W3CHMAP_F(_v) ((_v) << 12)
#define WINCHMAP0_W3CHMAP_F_MASK (0x7 << 12)
#define WINCHMAP0_W2CHMAP_F(_v) ((_v) << 8)
#define WINCHMAP0_W2CHMAP_F_MASK (0x7 << 8)
#define WINCHMAP0_W1CHMAP_F(_v) ((_v) << 4)
#define WINCHMAP0_W1CHMAP_F_MASK (0x7 << 4)
#define WINCHMAP0_W0CHMAP_F(_v) ((_v) << 0)
#define WINCHMAP0_W0CHMAP_F_MASK (0x7 << 0)
#define WINCON(_win) (0x0050 + ((_win) * 4))
#define WINCON_RESET_VALUE (0x0001E000)
#define WINCON_RGB_TYPE_BT601W (0 << 26)
#define WINCON_RGB_TYPE_BT601N (1 << 26)
#define WINCON_RGB_TYPE_BT709W (2 << 26)
#define WINCON_RGB_TYPE_BT709N (3 << 26)
#define WINCON_BLK_EN_F (1 << 23)
#define WINCON_OUTSTAND_MAX_DEFAULT (0xF)
#define WINCON_OUTSTAND_MAX_POS (13)
#define WINCON_OUTSTAND_MAX_MASK (0x1F << 13)
#define WINCON_BURSTLEN_16WORD (0x0 << 10)
#define WINCON_BURSTLEN_8WORD (0x1 << 10)
#define WINCON_BURSTLEN_4WORD (0x2 << 10)
#define WINCON_INTERPOLATION_EN (1 << 9)
#define WINCON_BLD_PLANE (0 << 8)
#define WINCON_BLD_PIX (1 << 8)
#define WINCON_ALPHA_MUL (1 << 7)
#define WINCON_BPPMODE_ARGB8888 (0x0 << 2)
#define WINCON_BPPMODE_ABGR8888 (0x1 << 2)
#define WINCON_BPPMODE_RGBA8888 (0x2 << 2)
#define WINCON_BPPMODE_BGRA8888 (0x3 << 2)
#define WINCON_BPPMODE_XRGB8888 (0x4 << 2)
#define WINCON_BPPMODE_XBGR8888 (0x5 << 2)
#define WINCON_BPPMODE_RGBX8888 (0x6 << 2)
#define WINCON_BPPMODE_BGRX8888 (0x7 << 2)
#define WINCON_BPPMODE_RGB565 (0x8 << 2)
/*
* Todo: both formats are working but if 0x18 is passed for NV21
* and 0x19 is passed as NV12. This information is reversed in
* user manual. Need to check with Hardware team.
*/
#define WINCON_BPPMODE_NV21 (0x18 << 2)
#define WINCON_BPPMODE_NV12 (0x19 << 2)
#define WINCON_ALPHA_SEL (1 << 1)
#define WINCON_ENWIN (1 << 0)
#define VIDW_ADD0(_win) (0x0880 + ((_win) * 0x10))
#define VIDW_ADD2(_win) (0x1020 + ((_win) * 0x20))
#define VIDW_ADD3(_win) (0x1030 + ((_win) * 0x20))
#define VIDW_WHOLE_X(_win) (0x0130 + ((_win) * 8))
#define VIDW_WHOLE_Y(_win) (0x0134 + ((_win) * 8))
#define VIDW_OFFSET_X(_win) (0x0170 + ((_win) * 8))
#define VIDW_OFFSET_Y(_win) (0x0174 + ((_win) * 8))
#define VIDW_BLKOFFSET(_win) (0x01B0 + ((_win) * 4))
#define VIDW_BLKSIZE(_win) (0x0200 + ((_win) * 4))
#define VIDW_BLKOFFSET_Y_F(_v) (((_v) & 0x1fff) << 13)
#define VIDW_BLKOFFSET_X_F(_v) ((_v) & 0x1fff)
#define VIDW_BLKOFFSET_MASK (0x3ffffff)
#define VIDW_BLKSIZE_MASK (0x3ffffff)
#define VIDW_BLKSIZE_H_F(_v) (((_v) & 0x1fff) << 13)
#define VIDW_BLKSIZE_W_F(_v) ((_v) & 0x1fff)
#define VIDOSD_A(_win) (0x0230 + ((_win) * 0x20))
#define VIDOSD_A_TOPLEFT_X(_v) (((_v) & 0x1fff) << 13)
#define VIDOSD_A_TOPLEFT_Y(_v) (((_v) & 0x1fff) << 0)
#define VIDOSD_B(_win) (0x0234 + ((_win) * 0x20))
#define VIDOSD_B_BOTRIGHT_X(_v) (((_v) & 0x1fff) << 13)
#define VIDOSD_B_BOTRIGHT_Y(_v) (((_v) & 0x1fff) << 0)
#define VIDOSD_C(_win) (0x0238 + ((_win) * 0x20))
#define VIDOSD_C_ALPHA0_R_F(_v) (((_v) & 0xFF) << 16)
#define VIDOSD_C_ALPHA0_G_F(_v) (((_v) & 0xFF) << 8)
#define VIDOSD_C_ALPHA0_B_F(_v) (((_v) & 0xFF) << 0)
#define VIDOSD_D(_win) (0x023C + ((_win) * 0x20))
#define VIDOSD_D_ALPHA1_R_F(_v) (((_v) & 0xFF) << 16)
#define VIDOSD_D_ALPHA1_G_F(_v) (((_v) & 0xFF) << 8)
#define VIDOSD_D_ALPHA1_B_F(_v) (((_v) & 0xFF) >> 0)
#define WIN_MAP(_win) (0x0340 + ((_win) * 4))
#define WIN_MAP_MAP (1 << 24)
#define WIN_MAP_MAP_COLOUR(_v) ((_v) << 0)
#define WIN_MAP_MAP_COLOUR_MASK (0xffffff << 0)
#define W_KEYCON0(_win) (0x0370 + ((_win) * 8))
#define W_KEYCON1(_win) (0x0374 + ((_win) * 8))
#define W_KEYALPHA(_win) (0x03A0 + ((_win) * 4))
#define BLENDE(_win) (0x03C0 + ((_win) * 4))
#define BLENDE_COEF_ZERO 0x0
#define BLENDE_COEF_ONE 0x1
#define BLENDE_COEF_ALPHA_A 0x2
#define BLENDE_COEF_ONE_MINUS_ALPHA_A 0x3
#define BLENDE_COEF_ALPHA_B 0x4
#define BLENDE_COEF_ONE_MINUS_ALPHA_B 0x5
#define BLENDE_COEF_ALPHA0 0x6
#define BLENDE_COEF_A 0xA
#define BLENDE_COEF_ONE_MINUS_A 0xB
#define BLENDE_COEF_B 0xC
#define BLENDE_COEF_ONE_MINUS_B 0xD
#define BLENDE_Q_FUNC(_v) ((_v) << 18)
#define BLENDE_P_FUNC(_v) ((_v) << 12)
#define BLENDE_B_FUNC(_v) ((_v) << 6)
#define BLENDE_A_FUNC(_v) ((_v) << 0)
#define BLENDCON 0x03D8
#define BLENDCON_NEW_8BIT_ALPHA_VALUE (1 << 0)
#define BLENDCON_NEW_4BIT_ALPHA_VALUE (0 << 0)
#define VIDINTCON0 0x0500
#define VIDINTCON0_INT_EXTRA_EN (1 << 21)
#define VIDINTCON0_INT_I80_EN (1 << 17)
#define VIDINTCON0_FRAMESEL0_BACKPORCH (0x0 << 15)
#define VIDINTCON0_FRAMESEL0_VSYNC (0x1 << 15)
#define VIDINTCON0_FRAMESEL0_ACTIVE (0x2 << 15)
#define VIDINTCON0_FRAMESEL0_FRONTPORCH (0x3 << 15)
#define VIDINTCON0_INT_FRAME (1 << 11)
#define VIDINTCON0_FIFOLEVEL_EMPTY (0x0 << 3)
#define VIDINTCON0_FIFOLEVEL_TO25PC (0x1 << 3)
#define VIDINTCON0_FIFOLEVEL_TO50PC (0x2 << 3)
#define VIDINTCON0_FIFOLEVEL_FULL (0x4 << 3)
#define VIDINTCON0_INT_FIFO (1 << 1)
#define VIDINTCON0_INT_ENABLE (1 << 0)
#define VIDINTCON1 0x0504
#define VIDINTCON1_FIFOEP_TH_SHIFT 10
#define VIDINTCON1_INT_DPU1 (1 << 5)
#define VIDINTCON1_INT_DPU0 (1 << 4)
#define VIDINTCON1_INT_EXTRA (1 << 3)
#define VIDINTCON1_INT_I80 (1 << 2)
#define VIDINTCON1_INT_FRAME (1 << 1)
#define VIDINTCON1_INT_FIFO (1 << 0)
#define FRAMEFIFO_REG7 0x052C
#define FRAMEFIFO_FIFO0_VALID_SIZE_GET(_v) (((_v) >> 13) & 0x1fff)
#define VIDCON1(_x) (0x0600 + ((_x) * 0x50))
#define VIDCON1_LINECNT_GET(_v) (((_v) >> 17) & 0x1fff)
#define VIDCON1_VSTATUS_MASK (0x7 << 13)
#define VIDCON1_VSTATUS_IDLE (0x0 << 13)
#define VIDCON1_VSTATUS_VSYNC (0x1 << 13)
#define VIDCON1_VSTATUS_BACKPORCH (0x2 << 13)
#define VIDCON1_VSTATUS_ACTIVE (0x3 << 13)
#define VIDCON1_VSTATUS_FRONTPORCH (0x4 << 13)
#define VIDCON1_VCLK_MASK (0x3 << 9)
#define VIDCON1_VCLK_HOLD (0x0 << 9)
#define VIDCON1_VCLK_RUN (0x1 << 9)
#define VIDCON1_VCLK_RUN_VDEN_DISABLE (0x3 << 9)
#define VIDCON1_RGB_ORDER_O_MASK (0x7 << 4)
#define VIDCON1_RGB_ORDER_O_RGB (0x0 << 4)
#define VIDCON1_RGB_ORDER_O_GBR (0x1 << 4)
#define VIDCON1_RGB_ORDER_O_BRG (0x2 << 4)
#define VIDCON1_RGB_ORDER_O_BGR (0x4 << 4)
#define VIDCON1_RGB_ORDER_O_RBG (0x5 << 4)
#define VIDCON1_RGB_ORDER_O_GRB (0x6 << 4)
#define VIDTCON0(_x) (0x0610 + ((_x) * 0x50))
#define VIDTCON0_VBPD(_v) ((_v) << 16)
#define VIDTCON0_VFPD(_v) ((_v) << 0)
#define VIDTCON1(_x) (0x0614 + ((_x) * 0x50))
#define VIDTCON1_VSPW(_v) ((_v) << 16)
#define VIDTCON2(_x) (0x0618 + ((_x) * 0x50))
#define VIDTCON2_HBPD(_v) ((_v) << 16)
#define VIDTCON2_HFPD(_v) ((_v) << 0)
#define VIDTCON3(_x) (0x061C + ((_x) * 0x50))
#define VIDTCON3_HSPW(_v) ((_v) << 16)
#define VIDTCON4(_x) (0x0620 + ((_x) * 0x50))
#define VIDTCON4_LINEVAL(_v) (((_v) & 0x1fff) << 16)
#define VIDTCON4_HOZVAL(_v) (((_v) & 0x1fff) << 0)
#define VIDTCON5(_x) (0x09a8 + ((_x) * 0x50))
#define VIDTCON5_LINEVAL(_v) (((_v) & 0x1fff) << 16)
#define VIDTCON5_HOZVAL(_v) (((_v) & 0x1fff) << 0)
#define VIDTCONx_LINEVAL_GET(_v) (((_v) >> 16) & 0x1fff)
#define VIDTCONx_HOZVAL_GET(_v) (((_v) >> 0) & 0x1fff)
#define LINECNT_OP_THRESHOLD(_x) (0x0630 + ((_x) * 0x50))
#define TRIGCON 0x06B0
#define TRIGCON_TRIG_SAVE_DISABLE_SYNCMGR (1 << 13)
#define TRIGCON_HWTRIG_AUTO_MASK (1 << 6)
#define TRIGCON_HWTRIGMASK_DISPIF0 (1 << 4)
#define TRIGCON_HWTRIGEN (1 << 3)
#define TRIGCON_HWTRIG_INV (1 << 2)
#define TRIGCON_SWTRIGCMD (1 << 1)
#define TRIGCON_SWTRIGEN (1 << 0)
#define CRCRDATA_E 0x06C0
#define CRCRDATA_V 0x06C4
#define CRCCTRL 0x06C8
#define CRCCTRL_CRCCLKEN (0x1 << 2)
#define CRCCTRL_CRCSTART_F (0x1 << 1)
#define CRCCTRL_CRCEN (0x1 << 0)
#define DECON_UPDATE 0x0710
#define DECON_UPDATE_STANDALONE_F (1 << 0)
#define DECON_SS_SEC (0x1 << 0)
/* TBD: Registers for Debugging features to be added */
#endif /* _REGS_DECON_H */

View file

@ -0,0 +1,304 @@
/* 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>
* Shaik Ameer Basha <shaik.ameer@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 (0xff << 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,101 @@
config EXYNOS_DECON_7870
bool "Samsung Exynos7870 Display system (DECON, MIPI)"
depends on FB
choice
prompt "Select Display Operation Mode"
depends on EXYNOS_DECON_7870
default EXYNOS7870_DISPLAY_VIDEO_MODE
help
Select the display operation mode (Command/Video).
config EXYNOS7870_DISPLAY_COMMAND_MODE
bool "Command Mode"
config EXYNOS7870_DISPLAY_VIDEO_MODE
bool "Video Mode"
endchoice
choice
prompt "Select TE IRQ Mode"
depends on EXYNOS_DECON_7870 && EXYNOS7870_DISPLAY_COMMAND_MODE
default EXYNOS7870_DISPLAY_TE_IRQ_GPIO
help
Select the TE IRQ mode.
config EXYNOS7870_DISPLAY_TE_IRQ_GPIO
bool "Dual GPIO"
config EXYNOS7870_DISPLAY_TE_IRQ_GIC
bool "GIC Interrupt"
endchoice
config USE_VSYNC_SKIP
bool "Vsync Skip Enable"
depends on EXYNOS_DECON_7870
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_7870
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_7870
default y
help
Enable MIPI-DSI driver.
config DECON_MIPI_DSI_PKTGO
bool "Samsung Exynos MIPI-DSI Packet Go"
depends on EXYNOS_DECON_7870 && 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_7870
depends on EXYNOS7870_DISPLAY_COMMAND_MODE
default n
config DECON_LPD_DISPLAY_WITH_CAMERA
bool "Decon Low Power Display MODE with Camera"
depends on DECON_LPD_DISPLAY
depends on EXYNOS7870_DISPLAY_COMMAND_MODE
config DECON_DEVFREQ
bool "Decon devfreq implementation"
depends on EXYNOS_DECON_7870
config FB_WINDOW_UPDATE
bool "DECON window update mode"
depends on EXYNOS_DECON_7870
depends on EXYNOS7870_DISPLAY_COMMAND_MODE
default n
config DECON_BLOCKING_MODE
bool "DECON blocking mode"
depends on EXYNOS_DECON_7870
default n
config DECON_USE_BOOTLOADER_FB
bool "DECON Bootloader Framebuffer support"
depends on EXYNOS7870_DISPLAY_VIDEO_MODE
default n
config DECON_EVENT_LOG
bool "Display sub-system event logger (DECON/DSIM)"
depends on DEBUG_INFO && EXYNOS_DECON_7870
default y
source "drivers/video/fbdev/exynos/decon_7870/panels/Kconfig"

View file

@ -0,0 +1,12 @@
#
# Copyright (c) 2013 Samsung Electronics Co., Ltd.
# http://www.samsung.com
#
# Licensed under GPLv2
#
obj-$(CONFIG_EXYNOS_MIPI_DSI) += dsim.o
dsim-y += dsim_drv.o dsim_reg_7870.o
obj-$(CONFIG_EXYNOS_DECON_7870) += decon.o
decon-y += decon_core.o decon-int_drv.o decon_helper.o decon_reg_7870.o
obj-y += panels/

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,852 @@
/*
* Copyright (c) 2015 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 <soc/samsung/bts.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_int_drvdata;
extern int decon_log_level;
#if defined(CONFIG_ARM_EXYNOS7870_BUS_DEVFREQ)
#define CONFIG_DECON_DEVFREQ
#endif
/*
* Lets Keep it same as 7420. This is the count for
* maximum number of layers supported by this driver.
* Real number of HW layers (or Active layers) will be
* provided by device tree.
*/
#define MAX_DECON_WIN (7)
#define DECON_INT (0)
#define DRIVER_NAME "decon"
#define MAX_NAME_SIZE 32
#define MAX_DECON_PADS 9
#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 DECON_ENABLE 1
#define DECON_DISABLE 0
#define DECON_BACKGROUND 0
#define VSYNC_TIMEOUT_MSEC 200
#define MAX_BW_PER_WINDOW (2560 * 1600 * 4 * 60)
#define LCD_DEFAULT_BPP 24
#define SHADOW_OFFSET (0x7000)
#define DRM_DEV_DECON 3
#define DECON_CFW_OFFSET 3
#define EVT_TYPE_INT BIT(31)
#define EVT_TYPE_IOCTL BIT(30)
#define EVT_TYPE_ASYNC_EVT BIT(29)
#define EVT_TYPE_PM BIT(28)
#define EVT_TYPE_WININFO BIT(27)
#define DECON_LOG_LEVEL_ERR 3
#define DECON_LOG_LEVEL_WARN 4
#define DECON_LOG_LEVEL_INFO 6
#define DECON_LOG_LEVEL_DBG 7
#define DECON_UNDERRUN_THRESHOLD 300
#ifdef CONFIG_FB_WINDOW_UPDATE
#define DECON_WIN_UPDATE_IDX (7)
#define decon_win_update_dbg(fmt, ...) \
do { \
if (decon_log_level >= DECON_LOG_LEVEL_DBG) \
pr_info(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#else
#define decon_win_update_dbg(fmt, ...) (while (0))
#endif
#define decon_err(fmt, ...) \
do { \
if (decon_log_level >= DECON_LOG_LEVEL_ERR) \
pr_err(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define decon_warn(fmt, ...) \
do { \
if (decon_log_level >= DECON_LOG_LEVEL_WARN) \
pr_warn(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define decon_info(fmt, ...) \
do { \
if (decon_log_level >= DECON_LOG_LEVEL_INFO) \
pr_info(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0)
#define decon_dbg(fmt, ...) \
do { \
if (decon_log_level >= DECON_LOG_LEVEL_DBG) \
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
};
enum decon_ip_version {
IP_VER_DECON_7I = BIT(0),
};
struct exynos_decon_platdata {
enum decon_ip_version ip_ver;
enum decon_psr_mode psr_mode;
enum decon_trig_mode trig_mode;
enum decon_dsi_mode dsi_mode;
int max_win;
int default_win;
u32 disp_pll_clk;
u32 disp_eclk;
u32 disp_vclk;
u32 disp_dvfs;
};
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; /* Display PLL */
struct clk *core_clk; /* Core CLock, APB, BUS */
struct clk *eclk; /* ECLK from MIF */
struct clk *eclk_leaf; /* ECLK Local (DISP PLL or MIF) */
struct clk *vclk; /* VCLK from MIF */
struct clk *vclk_leaf; /* VCLK Local (DISP PLL or MIF) */
};
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];
struct fb_var_screeninfo prev_var;
struct fb_fix_screeninfo prev_fix;
int fps;
int index;
int use;
int local;
unsigned long state;
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_NV21M_FULL,
DECON_PIXEL_FORMAT_MAX,
};
enum decon_blending {
DECON_BLENDING_NONE = 0,
DECON_BLENDING_PREMULT = 1,
DECON_BLENDING_COVERAGE = 2,
DECON_BLENDING_MAX = 3,
};
struct exynos_hdmi_data {
enum {
EXYNOS_HDMI_STATE_PRESET = 0,
EXYNOS_HDMI_STATE_ENUM_PRESET,
EXYNOS_HDMI_STATE_CEC_ADDR,
EXYNOS_HDMI_STATE_HDCP,
EXYNOS_HDMI_STATE_AUDIO,
} state;
struct v4l2_dv_timings timings;
struct v4l2_enum_dv_timings etimings;
__u32 cec_addr;
__u32 audio_info;
int hdcp;
};
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,
};
struct vpp_params {
dma_addr_t addr[MAX_BUF_PLANE_CNT];
enum vpp_rotate rot;
enum vpp_csc_eq eq_mode;
};
struct decon_phys_addr {
unsigned long phy_addr[MAX_BUF_PLANE_CNT];
unsigned int phy_addr_len[MAX_BUF_PLANE_CNT];
};
struct decon_phys_old_info {
int win_id;
int pixel_format;
int plane;
unsigned long int phys_addr[MAX_BUF_PLANE_CNT];
unsigned int phys_addr_len[MAX_BUF_PLANE_CNT];
};
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;
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;
u32 shadowcon;
u32 wincon[MAX_DECON_WIN];
u32 win_rgborder[MAX_DECON_WIN];
u32 winmap[MAX_DECON_WIN];
u32 vidosd_a[MAX_DECON_WIN];
u32 vidosd_b[MAX_DECON_WIN];
u32 vidosd_c[MAX_DECON_WIN];
u32 vidosd_d[MAX_DECON_WIN];
u32 vidw_alpha0[MAX_DECON_WIN];
u32 vidw_alpha1[MAX_DECON_WIN];
u32 blendeq[MAX_DECON_WIN - 1];
u32 buf_start[MAX_DECON_WIN];
struct decon_dma_buf_data dma_buf_data[MAX_DECON_WIN][MAX_BUF_PLANE_CNT];
unsigned int num_of_window;
u32 win_overlap_cnt;
u32 offset_x[MAX_DECON_WIN];
u32 offset_y[MAX_DECON_WIN];
u32 whole_w[MAX_DECON_WIN];
u32 whole_h[MAX_DECON_WIN];
struct decon_win_config win_config[MAX_DECON_WIN];
struct decon_win_rect block_rect[MAX_DECON_WIN];
struct decon_phys_addr phys_addr[MAX_DECON_WIN + 1];
#ifdef CONFIG_FB_WINDOW_UPDATE
struct decon_win_rect update_win;
bool need_update;
#endif
u64 cur_bw;
u64 bandwidth;
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 exynos_hdmi_data hdmi_data;
struct decon_win_config_data win_data;
u32 vsync;
};
struct decon_underrun_stat {
u64 prev_bw;
int chmap;
int fifo_level;
int underrun_cnt;
unsigned long aclk;
unsigned long lh_disp0;
unsigned long mif_pll;
unsigned long used_windows;
};
#ifdef CONFIG_DECON_EVENT_LOG
#define DEFAULT_BASE_IDX (-1)
/**
* 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 = EVT_TYPE_IOCTL,
DISP_EVT_UNBLANK,
DISP_EVT_ACT_VSYNC,
DISP_EVT_DEACT_VSYNC,
DISP_EVT_WIN_CONFIG,
DISP_EVT_ACT_PROT,
DISP_EVT_DEACT_PROT,
/* Related with interrupt */
DISP_EVT_TE_INTERRUPT = EVT_TYPE_INT,
DISP_EVT_UNDERRUN,
DISP_EVT_DECON_FRAMEDONE,
DISP_EVT_DSIM_FRAMEDONE,
DISP_EVT_UPDATE_TIMEOUT,
DISP_EVT_LINECNT_TIMEOUT,
/* Related with async event */
DISP_EVT_UPDATE_HANDLER = EVT_TYPE_ASYNC_EVT,
DISP_EVT_DSIM_COMMAND,
DISP_EVT_TRIG_MASK,
DISP_EVT_DECON_FRAMEDONE_WAIT,
DISP_EVT_LINECNT_ZERO,
DISP_EVT_SIZE_ERR,
DISP_EVT_DSIM_INTR_ENABLE,
DISP_EVT_DSIM_INTR_DISABLE,
DISP_EVT_DECON_SHUTDOWN,
DISP_EVT_DSIM_SHUTDOWN,
DISP_EVT_WIN_CONFIG_PARAM = EVT_TYPE_WININFO,
DISP_EVT_UPDATE_PARAMS,
/* Related with PM */
DISP_EVT_DECON_SUSPEND = EVT_TYPE_PM,
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_VSYNC_TIMEOUT,
DISP_EVT_VSTATUS_TIMEOUT,
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 {
bool need_update;
u32 overlap_cnt;
u32 bandwidth;
u32 wincon[MAX_DECON_WIN];
u32 offset_x[MAX_DECON_WIN];
u32 offset_y[MAX_DECON_WIN];
u32 whole_w[MAX_DECON_WIN];
u32 whole_h[MAX_DECON_WIN];
u32 vidosd_a[MAX_DECON_WIN];
u32 vidosd_b[MAX_DECON_WIN];
struct decon_win_config win_config[MAX_DECON_WIN];
struct decon_win_rect win;
};
/* Related with MIPI COMMAND read/write */
struct dsim_log_cmd_buf {
u32 id;
u8 buf;
};
/* Related with size mismatch error */
struct disp_ss_size_info {
u32 w_in;
u32 h_in;
u32 w_out;
u32 h_out;
};
/**
* struct disp_ss_log - Display Subsystem Log
* This struct includes DECON/DSIM
*/
struct disp_ss_log {
ktime_t time;
disp_ss_event_t type;
union {
struct disp_log_pm pm;
struct decon_update_reg_data reg;
struct dsim_log_cmd_buf cmd_buf;
struct decon_win_config_data win_data;
struct disp_ss_size_info size_mismatch;
} data;
};
/* bootloader framebuffer information */
struct disp_bootloader_fb_info {
u32 phy_addr;
u32 size;
u32 l;
u32 t;
u32 r;
u32 b;
u32 format;
};
/* Definitions below are used in the DECON */
#define DISP_EVENT_LOG_MAX SZ_2K
#define DISP_EVENT_PRINT_MAX 256
/* APIs below are used in the DECON/DSIM 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_UPDATE_PARAMS(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, int base_idx, bool sync);
void DISP_SS_EVENT_LOG_WIN_CONFIG(struct v4l2_subdev *sd, struct decon_win_config_data *win_data);
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_LOG_UPDATE_PARAMS(...) do { } while(0)
#define DISP_SS_EVENT_LOG_WIN_CONFIG(...) do { } while(0)
#define DISP_SS_EVENT_SIZE_ERR_LOG(...) do { } while(0)
#endif
/**
* END of CONFIG_DECON_EVENT_LOG
*/
struct decon_device {
void __iomem *regs;
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;
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 mic_enabled;
int n_sink_pad;
int n_src_pad;
union decon_ioctl_data ioctl_data;
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_status;
u32 cur_protection_bitmask;
unsigned int irq;
int frame_idle;
bool eint_en_status;
struct dentry *debug_root;
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 idle_ip_index;
u64 max_win_bw;
u64 prev_bw;
#ifdef CONFIG_DECON_EVENT_LOG
wait_queue_head_t event_wait;
struct dentry *mask;
struct dentry *debug_event;
struct disp_ss_log disp_ss_log[DISP_EVENT_LOG_MAX];
atomic_t disp_ss_log_idx;
#endif
u32 disp_ss_log_unmask;
#ifdef CONFIG_DECON_USE_BOOTLOADER_FB
struct disp_bootloader_fb_info bl_fb_info;
#endif
struct pinctrl *pinctrl;
struct pinctrl_state *decon_te_on;
struct pinctrl_state *decon_te_off;
struct decon_phys_old_info old_info;
};
static inline struct decon_device *get_decon_drvdata(u32 id)
{
return decon_int_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)
{
struct decon_device *decon = get_decon_drvdata(id);
u32 old = decon_read(id, reg_id);
val = (val & mask) | (old & ~mask);
writel(val, decon->regs + reg_id);
}
/* common function API */
bool decon_validate_x_alignment(struct decon_device *decon, int x, u32 w,
u32 bits_per_pixel);
int find_subdev_mipi(struct decon_device *decon);
int find_subdev_hdmi(struct decon_device *decon);
int create_link_mipi(struct decon_device *decon);
int create_link_hdmi(struct decon_device *decon);
int decon_int_register_irq(struct platform_device *pdev, struct decon_device *decon);
irqreturn_t decon_int_irq_handler(int irq, void *dev_data);
int decon_int_get_clocks(struct decon_device *decon);
void decon_int_set_clocks(struct decon_device *decon);
int decon_int_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);
void decon_lpd_enable(void);
/* internal only function API */
int decon_fb_config_eint_for_te(struct platform_device *pdev, struct decon_device *decon);
int decon_int_create_vsync_thread(struct decon_device *decon);
int decon_int_create_psr_thread(struct decon_device *decon);
void decon_int_destroy_vsync_thread(struct decon_device *decon);
void decon_int_destroy_psr_thread(struct decon_device *decon);
int decon_int_set_lcd_config(struct decon_device *decon);
int decon_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
int decon_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info);
/* external only function API */
struct decon_lcd *find_porch(struct v4l2_mbus_framefmt mbus_fmt);
int decon_get_hdmi_config(struct decon_device *decon,
struct exynos_hdmi_data *hdmi_data);
int decon_set_hdmi_config(struct decon_device *decon,
struct exynos_hdmi_data *hdmi_data);
/* 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_set_qos(struct decon_device *decon, struct decon_reg_data *regs,
bool is_after, bool is_default_qos);
/* LPD related */
static inline void decon_lpd_block(struct decon_device *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_is_lpd_blocked(decon))
atomic_dec(&decon->lpd_block_cnt);
}
static inline void decon_lpd_block_reset(struct decon_device *decon)
{
atomic_set(&decon->lpd_block_cnt, 0);
}
static inline void decon_lpd_trig_reset(struct decon_device *decon)
{
atomic_set(&decon->lpd_trig_cnt, 0);
}
#ifdef CONFIG_DECON_LPD_DISPLAY_WITH_CAMERA
static inline bool is_cam_not_running(struct decon_device *decon)
{
return !(decon_reg_get_cam_status(decon->cam_status[0]) & 0xF);
}
#else
static inline bool is_cam_not_running(struct decon_device *decon)
{
return true;
}
#endif
static inline bool decon_lpd_enter_cond(struct decon_device *decon)
{
return ((atomic_inc_return(&decon->lpd_trig_cnt) > DECON_ENTER_LPD_CNT) &&
(atomic_read(&decon->lpd_block_cnt) <= 0) && is_cam_not_running(decon));
}
static inline bool is_any_pending_frames(struct decon_device *decon)
{
return ((decon->timeline_max - decon->timeline->value) > 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 EXYNOS_GET_HDMI_CONFIG _IOW('F', 220, \
struct exynos_hdmi_data)
#define EXYNOS_SET_HDMI_CONFIG _IOW('F', 221, \
struct exynos_hdmi_data)
#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,149 @@
/*
* Copyright (c) 2015 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_COMMON_H__
#define ___SAMSUNG_DECON_COMMON_H__
#include "./panels/decon_lcd.h"
enum decon_dsi_mode {
DSI_MODE_SINGLE = 0,
};
enum decon_trig_mode {
DECON_HW_TRIG = 0,
DECON_SW_TRIG
};
enum decon_hold_scheme {
DECON_VCLK_HOLD = 0x00,
DECON_VCLK_RUNNING = 0x01,
DECON_VCLK_RUN_VDEN_DISABLE = 0x3,
};
enum decon_rgb_order {
DECON_RGB = 0x0,
DECON_GBR = 0x1,
DECON_BRG = 0x2,
DECON_BGR = 0x4,
DECON_RBG = 0x5,
DECON_GRB = 0x6,
};
enum decon_set_trig {
DECON_TRIG_DISABLE = 0,
DECON_TRIG_ENABLE
};
enum decon_set_eclk_idle_gate {
DECON_ECLK_IDLE_GATE_DISABLE = 0,
DECON_ECLK_IDLE_GATE_ENABLE
};
enum decon_idma_type {
IDMA_G0 = 0x0,
IDMA_G1,
IDMA_VG0,
IDMA_VG1,
IDMA_VGR0,
IDMA_VGR1,
IDMA_G2,
IDMA_G3,
IDMA_MAX
};
enum decon_output_type {
DECON_OUT_DSI = 0,
};
struct decon_psr_info {
enum decon_psr_mode psr_mode;
enum decon_trig_mode trig_mode;
enum decon_output_type out_type;
};
struct decon_init_param {
struct decon_psr_info psr;
struct decon_lcd *lcd_info;
u32 nr_windows;
};
struct decon_regs_data {
u32 wincon;
u32 winmap;
u32 vidosd_a;
u32 vidosd_b;
u32 vidosd_c;
u32 vidosd_d;
u32 vidosd_e;
u32 vidw_buf_start;
u32 vidw_whole_w;
u32 vidw_whole_h;
u32 vidw_offset_x;
u32 vidw_offset_y;
u32 blendeq;
u32 vidw_plane2_buf_start;
u32 vidw_plane3_buf_start;
enum decon_idma_type type;
};
/* CAL APIs list */
void decon_reg_init(u32 id, enum decon_dsi_mode dsi_mode, struct decon_init_param *p);
void decon_reg_init_probe(u32 id, enum decon_dsi_mode dsi_mode, struct decon_init_param *p);
void decon_reg_start(u32 id, enum decon_dsi_mode dsi_mode, struct decon_psr_info *psr);
int decon_reg_stop(u32 id, enum decon_dsi_mode dsi_mode, struct decon_psr_info *psr);
void decon_reg_set_regs_data(u32 id, int win_idx, struct decon_regs_data *regs);
void decon_reg_set_int(u32 id, struct decon_psr_info *psr, enum decon_dsi_mode dsi_mode, u32 en);
void decon_reg_set_trigger(u32 id, enum decon_dsi_mode dsi_mode,
enum decon_trig_mode trig, enum decon_set_trig en);
int decon_reg_wait_for_update_timeout(u32 id, unsigned long timeout);
void decon_reg_shadow_protect_win(u32 id, u32 win_idx, u32 protect);
void decon_reg_activate_window(u32 id, u32 index);
void decon_enable_eclk_idle_gate(u32 id, enum decon_set_eclk_idle_gate en);
/* CAL raw functions list */
int decon_reg_reset(u32 id);
void decon_reg_set_default_win_channel(u32 id);
void decon_reg_set_clkgate_mode(u32 id, u32 en);
void decon_reg_blend_alpha_bits(u32 id, u32 alpha_bits);
void decon_reg_set_vidout(u32 id, struct decon_psr_info *psr, enum decon_dsi_mode dsi_mode, u32 en);
void decon_reg_set_crc(u32 id, u32 en);
void decon_reg_set_fixvclk(u32 id, int dsi_idx, enum decon_hold_scheme mode);
void decon_reg_clear_win(u32 id, int win_idx);
void decon_reg_set_rgb_order(u32 id, int dsi_idx, enum decon_rgb_order order);
void decon_reg_set_porch(u32 id, int dsi_idx, struct decon_lcd *info);
void decon_reg_set_linecnt_op_threshold(u32 id, int dsi_idx, u32 th);
void decon_reg_set_clkval(u32 id, u32 clkdiv);
void decon_reg_direct_on_off(u32 id, u32 en);
void decon_reg_per_frame_off(u32 id);
void decon_reg_set_freerun_mode(u32 id, u32 en);
void decon_reg_update_standalone(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);
void decon_reg_set_winmap(u32 id, u32 idx, u32 color, u32 en);
u32 decon_reg_get_linecnt(u32 id, int dsi_idx);
u32 decon_reg_get_vstatus(u32 id, int dsi_idx);
int decon_reg_wait_linecnt_is_zero_timeout(u32 id, int dsi_idx, unsigned long timeout);
u32 decon_reg_get_stop_status(u32 id);
int decon_reg_wait_stop_status_timeout(u32 id, unsigned long timeout);
int decon_reg_is_win_enabled(u32 id, int win_idx);
int decon_reg_is_shadow_updated(u32 id);
void decon_reg_config_mic(u32 id, int dsi_idx, struct decon_lcd *lcd_info);
void decon_reg_clear_int(u32 id);
void decon_reg_config_win_channel(u32 id, u32 win_idx, enum decon_idma_type type);
void decon_reg_set_mdnie_pclk(u32 id, u32 en);
void decon_reg_enable_mdnie(u32 id, u32 en);
void decon_reg_set_mdnie_blank(u32 id, u32 front, u32 sync, u32 back, u32 line);
u32 decon_reg_get_lineval(u32 id, int dsi_idx, struct decon_lcd *lcd_info);
u32 decon_reg_get_hozval(u32 id, int dsi_idx, 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,646 @@
/*
* Copyright (c) 2015 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 "decon.h"
#include "dsim.h"
#include "decon_helper.h"
#include "./panels/lcd_ctrl.h"
#include <video/mipi_display.h>
inline int decon_is_no_bootloader_fb(struct decon_device *decon)
{
#ifdef CONFIG_DECON_USE_BOOTLOADER_FB
return !decon->bl_fb_info.phy_addr;
#else
return 1;
#endif
}
inline int decon_clk_set_parent(struct device *dev, struct clk *p, struct clk *c)
{
clk_set_parent(c, p);
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;
}
void decon_to_psr_info(struct decon_device *decon, struct decon_psr_info *psr)
{
psr->psr_mode = decon->pdata->psr_mode;
psr->trig_mode = decon->pdata->trig_mode;
psr->out_type = decon->out_type;
}
void decon_to_init_param(struct decon_device *decon, struct decon_init_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.out_type = decon->out_type;
p->nr_windows = decon->pdata->max_win;
}
/**
* ----- APIs for DISPLAY_SUBSYSTEM_EVENT_LOG -----
*/
/* ===== STATIC APIs ===== */
#ifdef CONFIG_DECON_EVENT_LOG
/* logging a event related with DECON */
void disp_log_win_config(char *ts, struct seq_file *s,
struct decon_win_config *config)
{
int win;
struct decon_win_config *cfg;
char *state[] = { "D", "C", "B", "U" };
char *blending[] = { "N", "P", "C" };
char *idma[] = { "G0", "G1", "V0", "V1", "VR0", "VR1", "G2" };
for (win = 0; win < MAX_DECON_WIN; win++) {
cfg = &config[win];
if (cfg->state == DECON_WIN_STATE_DISABLED)
continue;
if (cfg->state == DECON_WIN_STATE_COLOR) {
seq_printf(s, "%s\t[%d] %s, C(%d), D(%d,%d,%d,%d) "
"P(%d)\n",
ts, win, state[cfg->state], cfg->color,
cfg->dst.x, cfg->dst.y,
cfg->dst.x + cfg->dst.w,
cfg->dst.y + cfg->dst.h,
cfg->protection);
} else {
seq_printf(s, "%s\t[%d] %s,(%d,%d,%d), F(%d) P(%d)"
" A(%d), %s, %s, f(%d) (%d,%d,%d,%d,%d,%d) ->"
" (%d,%d,%d,%d,%d,%d)\n",
ts, win, state[cfg->state], cfg->fd_idma[0],
cfg->fd_idma[1], cfg->fd_idma[2],
cfg->fence_fd, cfg->protection,
cfg->plane_alpha, blending[cfg->blending],
idma[cfg->idma_type], cfg->format,
cfg->src.x, cfg->src.y,
cfg->src.x + cfg->src.w,
cfg->src.y + cfg->src.h,
cfg->src.f_w, cfg->src.f_h,
cfg->dst.x, cfg->dst.y,
cfg->dst.x + cfg->dst.w,
cfg->dst.y + cfg->dst.h,
cfg->dst.f_w, cfg->dst.f_h);
}
}
}
void disp_log_update_info(char *ts, struct seq_file *s,
struct decon_update_reg_data *reg)
{
int win;
for (win = 0; win < MAX_DECON_WIN; win++) {
if (!(reg->wincon[win] & WINCON_ENWIN))
continue;
seq_printf(s, "%s\t[%d] U(%d): (%d,%d,%d,%d) -> "
"(%d,%d,%d,%d)\n",
ts, win, reg->need_update,
reg->offset_x[win], reg->offset_y[win],
reg->whole_w[win], reg->whole_h[win],
(reg->vidosd_a[win] >> 13) & 0x1fff,
(reg->vidosd_a[win]) & 0x1fff,
(reg->vidosd_b[win] >> 13) & 0x1fff,
(reg->vidosd_b[win]) & 0x1fff);
}
}
void disp_ss_event_log_win_update(char *ts, struct seq_file *s,
struct decon_update_reg_data *reg)
{
disp_log_win_config(ts, s, reg->win_config);
disp_log_update_info(ts, s, reg);
}
void disp_ss_event_log_win_config(char *ts, struct seq_file *s,
struct decon_win_config_data *win_cfg)
{
disp_log_win_config(ts, s, win_cfg->config);
}
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_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;
}
}
/* 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 */
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;
if (!(decon->disp_ss_log_unmask & type))
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_DECON_FRAMEDONE:
case DISP_EVT_DECON_FRAMEDONE_WAIT:
case DISP_EVT_ACT_VSYNC:
case DISP_EVT_DEACT_VSYNC:
case DISP_EVT_WIN_CONFIG:
case DISP_EVT_ACT_PROT:
case DISP_EVT_DEACT_PROT:
case DISP_EVT_UPDATE_TIMEOUT:
case DISP_EVT_LINECNT_TIMEOUT:
case DISP_EVT_VSYNC_TIMEOUT:
case DISP_EVT_VSTATUS_TIMEOUT:
disp_ss_event_log_decon(type, sd, time);
break;
case DISP_EVT_ENTER_ULPS:
case DISP_EVT_EXIT_ULPS:
case DISP_EVT_DSIM_SUSPEND:
case DISP_EVT_DSIM_RESUME:
case DISP_EVT_DSIM_FRAMEDONE:
case DISP_EVT_DSIM_INTR_ENABLE:
case DISP_EVT_DSIM_INTR_DISABLE:
disp_ss_event_log_dsim(type, sd, time);
break;
default:
return;
}
wake_up_interruptible_all(&decon->event_wait);
}
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 < 3; win++) {
if (regs->wincon[win] & WINCON_ENWIN) {
log->data.reg.wincon[win] = regs->wincon[win];
log->data.reg.offset_x[win] = regs->offset_x[win];
log->data.reg.offset_y[win] = regs->offset_y[win];
log->data.reg.whole_w[win] = regs->whole_w[win];
log->data.reg.whole_h[win] = regs->whole_h[win];
log->data.reg.vidosd_a[win] = regs->vidosd_a[win];
log->data.reg.vidosd_b[win] = regs->vidosd_b[win];
memcpy(&log->data.reg.win_config[win], &regs->win_config[win],
sizeof(struct decon_win_config));
} else {
log->data.reg.win_config[win].state = DECON_WIN_STATE_DISABLED;
}
}
#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;
}
}
void DISP_SS_EVENT_LOG_UPDATE_PARAMS(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;
if (!(decon->disp_ss_log_unmask & DISP_EVT_UPDATE_PARAMS))
return;
log->time = ktime_get();
log->type = DISP_EVT_UPDATE_PARAMS;
log->data.reg.overlap_cnt = regs->win_overlap_cnt;
log->data.reg.bandwidth = regs->cur_bw;
for (win = 0; win < MAX_DECON_WIN; win++) {
log->data.reg.wincon[win] = 0;
if (regs->wincon[win] & WINCON_ENWIN) {
log->data.reg.wincon[win] = regs->wincon[win];
log->data.reg.offset_x[win] = regs->offset_x[win];
log->data.reg.offset_y[win] = regs->offset_y[win];
log->data.reg.whole_w[win] = regs->whole_w[win];
log->data.reg.whole_h[win] = regs->whole_h[win];
log->data.reg.vidosd_a[win] = regs->vidosd_a[win];
log->data.reg.vidosd_b[win] = regs->vidosd_b[win];
memcpy(&log->data.reg.win_config[win], &regs->win_config[win],
sizeof(struct decon_win_config));
}
}
#ifdef CONFIG_FB_WINDOW_UPDATE
log->data.reg.need_update = regs->need_update;
if ((regs->need_update) ||
(decon->need_update && regs->update_win.w)) {
memcpy(&log->data.reg.win, &regs->update_win,
sizeof(struct decon_rect));
} else {
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;
}
#else
memset(&log->data.reg.win, 0, sizeof(struct decon_rect));
#endif
wake_up_interruptible_all(&decon->event_wait);
}
void DISP_SS_EVENT_LOG_WIN_CONFIG(struct v4l2_subdev *sd, struct decon_win_config_data *win_data)
{
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 (!(decon->disp_ss_log_unmask & DISP_EVT_WIN_CONFIG_PARAM))
return;
log->time = ktime_get();
log->type = DISP_EVT_WIN_CONFIG_PARAM;
memcpy(&log->data.win_data, win_data, sizeof(struct decon_win_config_data));
wake_up_interruptible_all(&decon->event_wait);
}
/* 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;
struct disp_ss_log *log;
if (!decon || IS_ERR_OR_NULL(decon->debug_event))
return;
if (!(decon->disp_ss_log_unmask & DISP_EVT_DSIM_COMMAND))
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;
if (cmd_id == MIPI_DSI_DCS_LONG_WRITE)
log->data.cmd_buf.buf = *(u8 *)(data);
else
log->data.cmd_buf.buf = (u8)data;
wake_up_interruptible_all(&decon->event_wait);
}
void DISP_SS_EVENT_SIZE_ERR_LOG(struct v4l2_subdev *sd, struct disp_ss_size_info *info)
{
struct dsim_device *dsim = container_of(sd, struct dsim_device, sd);
struct decon_device *decon = get_decon_drvdata(dsim->id);
int idx;
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_SIZE_ERR;
memcpy(&log->data.size_mismatch, info, sizeof(struct disp_ss_size_info));
wake_up_interruptible_all(&decon->event_wait);
}
/* display logged events related with DECON */
void DISP_SS_EVENT_SHOW(struct seq_file *s, struct decon_device *decon,
int base_idx, bool sync)
{
int idx = atomic_read(&decon->disp_ss_log_idx) % DISP_EVENT_LOG_MAX;
struct disp_ss_log *log;
int latest = idx;
struct timeval tv;
char ts[20];
if (!sync) {
/* TITLE */
seq_printf(s, "-------------------DECON EVENT LOGGER ----------------------\n");
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_printf(s, "-------------------------------------------------------------\n");
seq_printf(s, "%14s %20s %20s\n",
"Time", "Event ID", "Remarks");
seq_printf(s, "-------------------------------------------------------------\n");
if (idx < 0) {
seq_printf(s, "No Events available. Done.\n");
seq_printf(s, "-------------------------------------------------------------\n");
return;
}
}
if (sync) {
if (base_idx != DEFAULT_BASE_IDX)
idx = base_idx % DISP_EVENT_LOG_MAX;
} else {
/* Seek a oldest from current index */
idx = (idx + DISP_EVENT_LOG_MAX - DISP_EVENT_PRINT_MAX) % DISP_EVENT_LOG_MAX;
}
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);
sprintf(ts, "[%6ld.%06ld] ", tv.tv_sec, tv.tv_usec);
seq_printf(s, "%s", ts);
/* 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_WIN_CONFIG_PARAM:
seq_printf(s, "%20s %d %20s", "WIN_CONFIG_PARAM", log->data.win_data.fd_odma, "-\n");
disp_ss_event_log_win_config(ts, s, &log->data.win_data);
break;
case DISP_EVT_TE_INTERRUPT:
seq_printf(s, "%20s %20s", "TE_INTERRUPT", "-\n");
break;
case DISP_EVT_UNDERRUN:
seq_printf(s, "%20s %20s", "UNDER_RUN", "-\n");
break;
case DISP_EVT_DSIM_FRAMEDONE:
seq_printf(s, "%20s %20s", "DSIM_FRAME_DONE", "-\n");
break;
case DISP_EVT_DECON_FRAMEDONE:
seq_printf(s, "%20s %20s", "DECON_FRAME_DONE", "-\n");
break;
case DISP_EVT_TRIG_MASK:
seq_printf(s, "%20s %20s", "TRIG_MASK", "-\n");
break;
case DISP_EVT_DECON_FRAMEDONE_WAIT:
seq_printf(s, "%20s %20s", "FRAMEDONE_WAIT", "-\n");
break;
case DISP_EVT_ACT_PROT:
seq_printf(s, "%20s %20s", "PROTECTION_ENABLE", "-\n");
break;
case DISP_EVT_DEACT_PROT:
seq_printf(s, "%20s %20s", "PROTECTION_DISABLE", "-\n");
break;
case DISP_EVT_UPDATE_TIMEOUT:
seq_printf(s, "%20s %20s", "UPDATE_TIMEOUT", "-\n");
break;
case DISP_EVT_LINECNT_TIMEOUT:
seq_printf(s, "%20s %20s", "LINECNT_TIMEOUT", "-\n");
break;
case DISP_EVT_UPDATE_HANDLER:
seq_printf(s, "%20s ", "UPDATE_HANDLER");
seq_printf(s, "overlap=%d, bw=0x%x, (%d,%d,%d,%d) U=%d\n",
log->data.reg.overlap_cnt,
log->data.reg.bandwidth,
log->data.reg.win.x,
log->data.reg.win.y,
log->data.reg.win.x + log->data.reg.win.w,
log->data.reg.win.y + log->data.reg.win.h,
log->data.reg.need_update);
break;
case DISP_EVT_UPDATE_PARAMS:
seq_printf(s, "%20s ", "UPDATE_PARAMS");
seq_printf(s, "overlap=%d, bw=0x%x, (%d,%d,%d,%d) U=%d\n",
log->data.reg.overlap_cnt,
log->data.reg.bandwidth,
log->data.reg.win.x,
log->data.reg.win.y,
log->data.reg.win.w,
log->data.reg.win.h,
log->data.reg.need_update);
disp_ss_event_log_win_update(ts, s,
&log->data.reg);
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_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;
case DISP_EVT_DSIM_INTR_ENABLE:
seq_printf(s, "%20s %20s", "DSIM_INTR_ENABLE", "-\n");
break;
case DISP_EVT_DSIM_INTR_DISABLE:
seq_printf(s, "%20s %20s", "DSIM_INTR_DISABLE", "-\n");
break;
default:
break;
}
} while (latest != idx);
if (!sync)
seq_printf(s, "-------------------------------------------------------------\n");
return;
}
#endif

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2015 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_rate(struct device *dev, struct clk *clk,
const char *conid, unsigned long rate);
int decon_clk_set_parent(struct device *dev, struct clk *p, struct clk *c);
void decon_to_psr_info(struct decon_device *decon, struct decon_psr_info *psr);
void decon_to_init_param(struct decon_device *decon, struct decon_init_param *p);
int decon_get_psr_mode_from_config(void);
int decon_is_no_bootloader_fb(struct decon_device *decon);
#endif /* __SAMSUNG_DECON_HELPER_H__ */

View file

@ -0,0 +1,615 @@
/* drivers/video/fbdev/exynos/decon_7870/decon_reg_7870.c
*
* Copyright 2015 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.
*/
/* use this definition when you test CAL on firmware */
/* #define FW_TEST */
#ifdef FW_TEST
#include "decon_fw.h"
#else
#include "decon.h"
#endif
/******************* CAL raw functions implementation *************************/
int decon_reg_reset(u32 id)
{
int tries;
decon_write(id, VIDCON0, VIDCON0_SWRESET);
for (tries = 2000; tries; --tries) {
if (~decon_read(id, VIDCON0) & VIDCON0_SWRESET)
break;
udelay(10);
}
if (!tries) {
decon_err("failed to reset Decon\n");
return -EBUSY;
}
return 0;
}
void decon_reg_set_default_win_channel(u32 id)
{
decon_write_mask(id, WINCHMAP0, WINCHMAP_DMA(0, 1), WINCHMAP_MASK(0));
decon_write_mask(id, WINCHMAP0, WINCHMAP_DMA(1, 1), WINCHMAP_MASK(1));
decon_write_mask(id, WINCHMAP0, WINCHMAP_DMA(2, 1), WINCHMAP_MASK(2));
}
void decon_reg_set_clkgate_mode(u32 id, u32 en)
{
}
void decon_reg_blend_alpha_bits(u32 id, u32 alpha_bits)
{
decon_write(id, BLENDCON, alpha_bits);
}
void decon_reg_set_vidout(u32 id, struct decon_psr_info *psr,
enum decon_dsi_mode dsi_mode, u32 en)
{
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
decon_write_mask(id, VIDOUTCON0, VIDOUTCON0_I80IF_F,
VIDOUTCON0_IF_MASK);
else
decon_write_mask(id, VIDOUTCON0, VIDOUTCON0_RGBIF_F,
VIDOUTCON0_IF_MASK);
decon_write_mask(id, VIDOUTCON0, en ? ~0 : 0, VIDOUTCON0_LCD_ON_F);
}
void decon_reg_set_crc(u32 id, u32 en)
{
u32 val = en ? ~0 : 0;
decon_write_mask(id, CRCCTRL, val,
CRCCTRL_CRCCLKEN | CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F);
}
void decon_reg_set_fixvclk(u32 id, int dsi_idx, enum decon_hold_scheme mode)
{
u32 val = VIDCON1_VCLK_HOLD;
switch (mode) {
case DECON_VCLK_HOLD:
val = VIDCON1_VCLK_HOLD;
break;
case DECON_VCLK_RUNNING:
val = VIDCON1_VCLK_RUN;
break;
case DECON_VCLK_RUN_VDEN_DISABLE:
val = VIDCON1_VCLK_RUN_VDEN_DISABLE;
break;
}
decon_write_mask(id, VIDCON1(dsi_idx), val, VIDCON1_VCLK_MASK);
}
void decon_reg_clear_win(u32 id, int win_idx)
{
decon_write(id, WINCON(win_idx), WINCON_RESET_VALUE);
decon_write(id, VIDOSD_A(win_idx), 0);
decon_write(id, VIDOSD_B(win_idx), 0);
decon_write(id, VIDOSD_C(win_idx), 0);
decon_write(id, VIDOSD_D(win_idx), 0);
}
void decon_reg_set_rgb_order(u32 id, int dsi_idx, enum decon_rgb_order order)
{
u32 val = VIDCON1_RGB_ORDER_O_RGB;
switch (order) {
case DECON_RGB:
val = VIDCON1_RGB_ORDER_O_RGB;
break;
case DECON_GBR:
val = VIDCON1_RGB_ORDER_O_GBR;
break;
case DECON_BRG:
val = VIDCON1_RGB_ORDER_O_BRG;
break;
case DECON_BGR:
val = VIDCON1_RGB_ORDER_O_BGR;
break;
case DECON_RBG:
val = VIDCON1_RGB_ORDER_O_RBG;
break;
case DECON_GRB:
val = VIDCON1_RGB_ORDER_O_GRB;
break;
}
decon_write_mask(id, VIDCON1(dsi_idx), val, VIDCON1_RGB_ORDER_O_MASK);
}
void decon_reg_set_porch(u32 id, int dsi_idx, struct decon_lcd *info)
{
u32 val = 0;
val = VIDTCON0_VBPD(info->vbp - 1) | VIDTCON0_VFPD(info->vfp - 1);
decon_write(id, VIDTCON0(dsi_idx), val);
val = VIDTCON1_VSPW(info->vsa - 1);
decon_write(id, VIDTCON1(dsi_idx), val);
val = VIDTCON2_HBPD(info->hbp - 1) | VIDTCON2_HFPD(info->hfp - 1);
decon_write(id, VIDTCON2(dsi_idx), val);
val = VIDTCON3_HSPW(info->hsa - 1);
decon_write(id, VIDTCON3(dsi_idx), val);
val = VIDTCON4_LINEVAL(info->yres - 1) |
VIDTCON4_HOZVAL(info->xres - 1);
decon_write(id, VIDTCON4(dsi_idx), val);
}
void decon_reg_set_linecnt_op_threshold(u32 id, int dsi_idx, u32 th)
{
decon_write(id, LINECNT_OP_THRESHOLD(dsi_idx), th);
}
void decon_reg_set_clkval(u32 id, u32 clkdiv)
{
decon_write_mask(id, VCLKCON0, ~0, VCLKCON0_CLKVALUP);
}
void decon_reg_direct_on_off(u32 id, u32 en)
{
u32 val = en ? ~0 : 0;
decon_write_mask(id, VIDCON0, val, VIDCON0_ENVID_F | VIDCON0_ENVID);
}
void decon_reg_per_frame_off(u32 id)
{
decon_write_mask(id, VIDCON0, 0, VIDCON0_ENVID_F);
}
void decon_reg_set_freerun_mode(u32 id, u32 en)
{
decon_write_mask(id, VCLKCON0, en ? ~0 : 0, VCLKCON0_VLCKFREE);
}
void decon_reg_update_standalone(u32 id)
{
decon_write_mask(id, DECON_UPDATE, ~0, DECON_UPDATE_STANDALONE_F);
}
void decon_reg_configure_lcd(u32 id, enum decon_dsi_mode dsi_mode,
struct decon_lcd *lcd_info)
{
decon_reg_set_rgb_order(id, 0, DECON_RGB);
decon_reg_set_porch(id, 0, lcd_info);
if (lcd_info->mic_enabled)
decon_reg_config_mic(id, 0, lcd_info);
if (lcd_info->mode == DECON_VIDEO_MODE)
decon_reg_set_linecnt_op_threshold(id, 0, lcd_info->yres - 1);
decon_reg_set_clkval(id, 0);
decon_reg_set_freerun_mode(id, 1);
decon_reg_direct_on_off(id, 0);
}
void decon_reg_configure_trigger(u32 id, enum decon_trig_mode mode)
{
u32 val, mask;
mask = TRIGCON_SWTRIGEN_I80_RGB | TRIGCON_HWTRIGEN_I80_RGB |
TRIGCON_TRIG_SAVE_DISABLE_SYNCMGR;
if (mode == DECON_SW_TRIG) {
val = TRIGCON_SWTRIGEN_I80_RGB;
} else {
val = TRIGCON_HWTRIGEN_I80_RGB | TRIGCON_HWTRIG_AUTO_MASK |
TRIGCON_TRIG_SAVE_DISABLE_SYNCMGR;
}
decon_write_mask(id, TRIGCON, val, mask);
}
void decon_reg_set_winmap(u32 id, u32 idx, u32 color, u32 en)
{
u32 val = en ? WIN_MAP_MAP : 0;
decon_reg_shadow_protect_win(id, idx, 1);
val |= WIN_MAP_MAP_COLOUR(color);
decon_write_mask(id, WIN_MAP(idx), val,
WIN_MAP_MAP | WIN_MAP_MAP_COLOUR_MASK);
decon_reg_shadow_protect_win(id, idx, 0);
}
u32 decon_reg_get_linecnt(u32 id, int dsi_idx)
{
return VIDCON1_LINECNT_GET(decon_read(id, VIDCON1(dsi_idx)));
}
u32 decon_reg_get_vstatus(u32 id, int dsi_idx)
{
return decon_read(id, VIDCON1(dsi_idx)) & VIDCON1_VSTATUS_MASK;
}
/* timeout : usec */
int decon_reg_wait_linecnt_is_zero_timeout(u32 id, int dsi_idx,
unsigned long timeout)
{
unsigned long delay_time = 10;
unsigned long cnt = timeout / delay_time;
u32 linecnt, vstatus;
do {
linecnt = decon_reg_get_linecnt(id, dsi_idx);
if (!linecnt) {
vstatus = decon_reg_get_vstatus(id, dsi_idx);
if (vstatus == VIDCON1_VSTATUS_IDLE)
break;
}
cnt--;
udelay(delay_time);
} while (cnt);
if (!cnt) {
decon_err("wait timeout linecount is zero(%u)\n", linecnt);
return -EBUSY;
}
return 0;
}
u32 decon_reg_get_stop_status(u32 id)
{
u32 val;
val = decon_read(id, VIDCON0);
if (val & VIDCON0_DECON_STOP_STATUS)
return 1;
return 0;
}
int decon_reg_wait_stop_status_timeout(u32 id, unsigned long timeout)
{
unsigned long delay_time = 10;
unsigned long cnt = timeout / delay_time;
u32 status;
do {
status = decon_reg_get_stop_status(id);
cnt--;
udelay(delay_time);
} while (status && cnt);
if (!cnt) {
decon_err("wait timeout decon stop status(%u)\n", status);
return -EBUSY;
}
return 0;
}
int decon_reg_is_win_enabled(u32 id, int win_idx)
{
if (decon_read(id, WINCON(win_idx)) & WINCON_ENWIN)
return 1;
return 0;
}
int decon_reg_is_shadow_updated(u32 id)
{
return 0;
}
void decon_reg_config_mic(u32 id, int dsi_idx, struct decon_lcd *lcd_info)
{
}
void decon_reg_clear_int(u32 id)
{
u32 mask;
mask = VIDINTCON1_INT_I80 | VIDINTCON1_INT_FRAME | VIDINTCON1_INT_FIFO;
decon_write_mask(id, VIDINTCON1, 0, mask);
}
void decon_reg_config_win_channel(u32 id, u32 win_idx,
enum decon_idma_type type)
{
switch (type) {
case IDMA_G0:
case IDMA_G1:
decon_write_mask(id, WINCHMAP0, WINCHMAP_DMA(type + 1, win_idx),
WINCHMAP_MASK(win_idx));
break;
case IDMA_VG0:
case IDMA_VG1:
case IDMA_VGR0:
case IDMA_VGR1:
case IDMA_G2:
case IDMA_G3:
decon_write_mask(id, WINCHMAP0, WINCHMAP_DMA(0, win_idx),
WINCHMAP_MASK(win_idx));
break;
default:
decon_err("channel(0x%x) is not valid\n", type);
return;
}
decon_dbg("decon-%s win[%d]-type[%d] WINCHMAP:%#x\n", "int",
win_idx, type, decon_read(id, WINCHMAP0));
}
/***************** CAL APIs implementation *******************/
void decon_reg_init(u32 id, enum decon_dsi_mode dsi_mode,
struct decon_init_param *p)
{
int win_idx;
struct decon_lcd *lcd_info = p->lcd_info;
struct decon_psr_info *psr = &p->psr;
decon_reg_reset(id);
decon_reg_set_clkgate_mode(id, 0);
decon_reg_blend_alpha_bits(id, BLENDCON_NEW_8BIT_ALPHA_VALUE);
decon_reg_set_vidout(id, psr, dsi_mode, 1);
decon_reg_set_crc(id, 0);
/* Does exynos7870 decon always use DECON_VCLK_HOLD ? No */
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
decon_reg_set_fixvclk(id, 0, DECON_VCLK_RUN_VDEN_DISABLE);
else
decon_reg_set_fixvclk(id, 0, DECON_VCLK_HOLD);
for (win_idx = 0; win_idx < p->nr_windows; win_idx++)
decon_reg_clear_win(id, win_idx);
/* RGB order -> porch values -> LINECNT_OP_THRESHOLD -> clock divider
* -> freerun mode --> stop DECON */
decon_reg_configure_lcd(id, dsi_mode, lcd_info);
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
decon_reg_configure_trigger(id, psr->trig_mode);
/* asserted interrupt should be cleared before initializing decon hw */
decon_reg_clear_int(id);
}
void decon_reg_init_probe(u32 id, enum decon_dsi_mode dsi_mode,
struct decon_init_param *p)
{
struct decon_lcd *lcd_info = p->lcd_info;
struct decon_psr_info *psr = &p->psr;
decon_reg_set_clkgate_mode(id, 0);
decon_reg_blend_alpha_bits(id, BLENDCON_NEW_8BIT_ALPHA_VALUE);
decon_reg_set_vidout(id, psr, dsi_mode, 1);
/* Does exynos7870 decon always use DECON_VCLK_HOLD ? */
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
decon_reg_set_fixvclk(id, 0, DECON_VCLK_RUN_VDEN_DISABLE);
else
decon_reg_set_fixvclk(id, 0, DECON_VCLK_HOLD);
decon_reg_set_rgb_order(id, 0, DECON_RGB);
decon_reg_set_porch(id, 0, lcd_info);
if (lcd_info->mic_enabled)
decon_reg_config_mic(id, 0, lcd_info);
if (lcd_info->mode == DECON_VIDEO_MODE)
decon_reg_set_linecnt_op_threshold(id, 0, lcd_info->yres - 1);
decon_reg_set_clkval(id, 0);
decon_reg_set_freerun_mode(id, 1);
decon_reg_update_standalone(id);
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
decon_reg_configure_trigger(id, psr->trig_mode);
}
void decon_reg_start(u32 id, enum decon_dsi_mode dsi_mode,
struct decon_psr_info *psr)
{
decon_reg_direct_on_off(id, 1);
decon_reg_update_standalone(id);
if ((psr->psr_mode == DECON_MIPI_COMMAND_MODE) &&
(psr->trig_mode == DECON_HW_TRIG))
decon_reg_set_trigger(id, dsi_mode, psr->trig_mode,
DECON_TRIG_ENABLE);
}
int decon_reg_stop(u32 id, enum decon_dsi_mode dsi_mode,
struct decon_psr_info *psr)
{
int ret = 0;
if ((psr->psr_mode == DECON_MIPI_COMMAND_MODE) &&
(psr->trig_mode == DECON_HW_TRIG)) {
decon_reg_set_trigger(id, dsi_mode, psr->trig_mode,
DECON_TRIG_DISABLE);
}
if (decon_reg_get_stop_status(id) == 1) {
/* timeout : 50ms */
/* TODO: dual DSI scenario */
ret = decon_reg_wait_linecnt_is_zero_timeout(id, 0, 50 * 1000);
if (ret)
goto err;
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
decon_reg_direct_on_off(id, 0);
else
decon_reg_per_frame_off(id);
/* timeout : 20ms */
ret = decon_reg_wait_stop_status_timeout(id, 20 * 1000);
if (ret)
goto err;
}
err:
ret = decon_reg_reset(id);
return ret;
}
void decon_reg_set_regs_data(u32 id, int win_idx,
struct decon_regs_data *regs)
{
u32 val;
if (regs->wincon & WINCON_ENWIN)
decon_reg_config_win_channel(id, win_idx, regs->type);
val = regs->wincon & WINCON_OUTSTAND_MAX_MASK;
if (val < (WINCON_OUTSTAND_MAX_DEFAULT << WINCON_OUTSTAND_MAX_POS)) {
val = regs->wincon & (~WINCON_OUTSTAND_MAX_MASK);
regs->wincon = val | (WINCON_OUTSTAND_MAX_DEFAULT <<
WINCON_OUTSTAND_MAX_POS);
}
decon_write(id, WINCON(win_idx), regs->wincon);
decon_write(id, WIN_MAP(win_idx), regs->winmap);
if (regs->winmap & WIN_MAP_MAP) {
decon_write_mask(id, WINCHMAP0, WINCHMAP_DMA(0x7, win_idx),
WINCHMAP_MASK(win_idx));
}
decon_write(id, VIDOSD_A(win_idx), regs->vidosd_a);
decon_write(id, VIDOSD_B(win_idx), regs->vidosd_b);
decon_write(id, VIDOSD_C(win_idx), regs->vidosd_c);
decon_write(id, VIDOSD_D(win_idx), regs->vidosd_d);
decon_write(id, VIDW_ADD0(win_idx), regs->vidw_buf_start);
decon_write(id, VIDW_WHOLE_X(win_idx), regs->vidw_whole_w);
decon_write(id, VIDW_WHOLE_Y(win_idx), regs->vidw_whole_h);
decon_write(id, VIDW_OFFSET_X(win_idx), regs->vidw_offset_x);
decon_write(id, VIDW_OFFSET_Y(win_idx), regs->vidw_offset_y);
decon_write(id, VIDW_ADD2(win_idx), regs->vidw_plane2_buf_start);
decon_write(id, VIDW_ADD3(win_idx), regs->vidw_plane3_buf_start);
if (win_idx)
decon_write(id, BLENDE(win_idx - 1), regs->blendeq);
decon_dbg("%s: regs->type(%d)\n", __func__, regs->type);
}
void decon_reg_set_int(u32 id, struct decon_psr_info *psr,
enum decon_dsi_mode dsi_mode, u32 en)
{
u32 val;
if (en) {
val = VIDINTCON0_INT_ENABLE | VIDINTCON0_FIFOLEVEL_EMPTY;
if (psr->psr_mode == DECON_MIPI_COMMAND_MODE) {
decon_write_mask(id, VIDINTCON1, ~0,
VIDINTCON1_INT_I80);
val |= VIDINTCON0_INT_FIFO | VIDINTCON0_INT_I80_EN | VIDINTCON0_INT_FRAME
| VIDINTCON0_FRAMESEL0_VSYNC;
} else {
val |= VIDINTCON0_INT_FIFO | VIDINTCON0_INT_FRAME
| VIDINTCON0_FRAMESEL0_VSYNC;
}
decon_write_mask(id, VIDINTCON0, val, ~0);
} else {
decon_write_mask(id, VIDINTCON0, 0, VIDINTCON0_INT_ENABLE);
}
}
void decon_enable_eclk_idle_gate(u32 id, enum decon_set_eclk_idle_gate en)
{
u32 val = (en == DECON_ECLK_IDLE_GATE_ENABLE) ? ~0 : 0;
decon_write_mask(id, VCLKCON0, val, ECLK_IDLE_GATE_EN);
}
/* It is needed to unmask hw trigger and mask asynchronously for dual DSI */
/* enable(unmask) / disable(mask) hw trigger */
void decon_reg_set_trigger(u32 id, enum decon_dsi_mode dsi_mode,
enum decon_trig_mode trig, enum decon_set_trig en)
{
u32 val = (en == DECON_TRIG_ENABLE) ? ~0 : 0;
u32 mask;
if (trig == DECON_SW_TRIG)
mask = TRIGCON_SWTRIGCMD_I80_RGB;
else
mask = TRIGCON_HWTRIGMASK_DISPIF0;
decon_write_mask(id, TRIGCON, val, mask);
}
/* wait until shadow update is finished */
int decon_reg_wait_for_update_timeout(u32 id, unsigned long timeout)
{
unsigned long delay_time = 100;
unsigned long cnt = timeout / delay_time;
while ((decon_read(id, DECON_UPDATE) & DECON_UPDATE_STANDALONE_F) &&
--cnt)
udelay(delay_time);
if (!cnt) {
decon_err("timeout of updating decon registers\n");
return -EBUSY;
}
return 0;
}
/* prohibit shadow update during writing something to SFR */
void decon_reg_shadow_protect_win(u32 id, u32 win_idx, u32 protect)
{
u32 val = protect ? ~0 : 0;
decon_write_mask(id, SHADOWCON, val, SHADOWCON_WIN_PROTECT(win_idx));
}
/* enable each window */
void decon_reg_activate_window(u32 id, u32 index)
{
decon_write_mask(id, WINCON(index), ~0, WINCON_ENWIN);
decon_reg_update_standalone(id);
}
void decon_reg_set_block_mode(u32 id, u32 win_idx, u32 x, u32 y, u32 w,
u32 h, u32 en)
{
u32 val = en ? ~0 : 0;
u32 blk_offset = 0, blk_size = 0;
blk_offset = VIDW_BLKOFFSET_Y_F(y) | VIDW_BLKOFFSET_X_F(x);
blk_size = VIDW_BLKSIZE_W_F(w) | VIDW_BLKSIZE_H_F(h);
decon_write_mask(id, VIDW_BLKOFFSET(win_idx), blk_offset,
VIDW_BLKOFFSET_MASK);
decon_write_mask(id, VIDW_BLKSIZE(win_idx), blk_size,
VIDW_BLKSIZE_MASK);
decon_write_mask(id, WINCON(win_idx), val, WINCON_BLK_EN_F);
}
void decon_reg_set_tui_va(u32 id, u32 va)
{
decon_write(id, VIDW_ADD2(6), va);
}
u32 decon_reg_get_lineval(u32 id, int dsi_idx, struct decon_lcd *lcd_info)
{
u32 val;
val = decon_read(id, VIDTCON4(dsi_idx) + SHADOW_OFFSET);
return VIDTCONx_LINEVAL_GET(val) + 1;
}
u32 decon_reg_get_hozval(u32 id, int dsi_idx, struct decon_lcd *lcd_info)
{
u32 val;
val = decon_read(id, VIDTCON4(dsi_idx) + SHADOW_OFFSET);
return VIDTCONx_HOZVAL_GET(val) + 1;
}

View file

@ -0,0 +1,230 @@
/* linux/drivers/video/fbdev/exynos/decon_7870/dsim.h
*
* Header file for Samsung MIPI-DSI common driver.
*
* Copyright (c) 2015 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;
extern struct mipi_dsim_lcd_driver ea8064g_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)
#define DSIM_IOC_VSYNC _IOW('D', 9, u32)
#endif /* __DSIM_H__ */

View file

@ -0,0 +1,169 @@
/* dsim_common.h
*
* Header file for Samsung MIPI-DSI lowlevel driver.
*
* Copyright (c) 2015 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,40 @@
config EXYNOS7870_DECON_DISP_LCD
depends on EXYNOS_DECON_7870 && EXYNOS_MIPI_DSI
bool "Select LCD panel driver"
config EXYNOS7870_DECON_DISP_LCD_NAME
string
default "s6d78a" if EXYNOS_DECON_LCD_S6D78A
default "s6e8aa0" if EXYNOS_DECON_LCD_S6E8AA0
default "s6e3fa0" if EXYNOS_DECON_LCD_S6E3FA0
help
This string is compared with lcd name fron Device Tree.
choice
prompt "Select Panel"
depends on EXYNOS7870_DECON_DISP_LCD
default EXYNOS_DECON_LCD_S6E3FA0
help
select the display panel.
config EXYNOS_DECON_LCD_S6D78A
depends on EXYNOS7870_DECON_DISP_LCD
depends on EXYNOS7870_DISPLAY_VIDEO_MODE
bool "S6D78A AMOLED qHD LCD driver(540 x 960)"
config EXYNOS_DECON_LCD_S6E8AA0
depends on EXYNOS7870_DECON_DISP_LCD
depends on EXYNOS7870_DISPLAY_VIDEO_MODE
bool "S6E8AA0 AMOLED HD LCD driver(800 x 1280)"
config EXYNOS_DECON_LCD_EA8064G
depends on EXYNOS7870_DECON_DISP_LCD
depends on EXYNOS7870_DISPLAY_COMMAND_MODE
bool "EA8064G COMMAND MODE AMOLED FHD LCD driver(1080 x 1920)"
config EXYNOS_DECON_LCD_S6E3FA0
depends on EXYNOS7870_DECON_DISP_LCD
depends on EXYNOS7870_DISPLAY_COMMAND_MODE || EXYNOS7870_DISPLAY_VIDEO_MODE
bool "S6E3FA0 COMMAND/VIDEO MODE AMOLED FHD LCD driver(1080 x 1920)"
endchoice

View file

@ -0,0 +1,4 @@
obj-$(CONFIG_EXYNOS_DECON_LCD_S6E8AA0) += s6e8aa0_mipi_lcd.o s6e8aa0_lcd_ctrl.o
obj-$(CONFIG_EXYNOS_DECON_LCD_S6D78A) += s6d78a_mipi_lcd.o s6d78a_lcd_ctrl.o
obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3FA0) += s6e3fa0_mipi_lcd.o s6e3fa0_lcd_ctrl.o
obj-$(CONFIG_EXYNOS_DECON_LCD_EA8064G) += ea8064g_mipi_lcd.o ea8064g_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,521 @@
/* linux/drivers/video/backlight/dynamic_aid.c
*
* Samsung Electronics Dynamic AID for AMOLED.
*
* Copyright (c) 2013 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/ctype.h>
#include "dynamic_aid.h"
#ifdef DYNAMIC_AID_DEBUG
#define aid_dbg(format, arg...) printk(format, ##arg)
#else
#define aid_dbg(format, arg...)
#endif
struct rgb64_t {
s64 rgb[3];
};
struct dynamic_aid_info {
struct dynamic_aid_param_t param;
int *iv_tbl;
int iv_max;
int iv_top;
int *ibr_tbl;
int ibr_max;
int ibr_top;
int *mtp;
int vreg;
struct rgb64_t *point_voltages;
struct rgb64_t *output_voltages;
int *l_value;
int *l_lookup_table;
int *m_gray;
struct rgb64_t *m_voltage;
};
#define MUL_100(x) (x*100)
#define MUL_1000(x) (x*1000)
#define MUL_10000(x) (x*10000)
#define DIV_10(x) ((x+5)/10)
#define DIV_100(x) ((x+50)/100)
static int calc_point_voltages(struct dynamic_aid_info d_aid)
{
int ret, iv, c;
struct rgb64_t *vt, *vp;
int *vd, *mtp;
int numerator, denominator;
s64 v0;
s64 t1, t2;
struct rgb64_t *point_voltages;
point_voltages = d_aid.point_voltages;
v0 = d_aid.vreg;
ret = 0;
/* iv == 0; */
{
vd = (int *)&d_aid.param.gamma_default[0];
mtp = &d_aid.mtp[0];
numerator = d_aid.param.formular[0].numerator;
denominator = d_aid.param.formular[0].denominator;
for (c = 0; c < CI_MAX; c++) {
t1 = v0;
t2 = v0*d_aid.param.vt_voltage_value[vd[c] +
mtp[c]];
point_voltages[0].rgb[c] = t1 -
div_s64(t2, denominator);
}
}
iv = d_aid.iv_max - 1;
/* iv == (IV_MAX-1) ~ 1; */
for (; iv > 0; iv--) {
vt = &point_voltages[0];
vp = &point_voltages[iv+1];
vd = (int *)&d_aid.param.gamma_default[iv*CI_MAX];
mtp = &d_aid.mtp[iv*CI_MAX];
numerator = d_aid.param.formular[iv].numerator;
denominator = d_aid.param.formular[iv].denominator;
for (c = 0; c < CI_MAX; c++) {
if (iv == 1) {
t1 = v0;
t2 = v0 - vp->rgb[c];
} else if (iv == d_aid.iv_max - 1) {
t1 = v0;
t2 = v0;
} else {
t1 = vt->rgb[c];
t2 = vt->rgb[c] - vp->rgb[c];
}
t2 *= vd[c] + mtp[c] + numerator;
point_voltages[iv].rgb[c] = (t1 -
div_s64(t2, denominator));
}
}
#ifdef DYNAMIC_AID_DEBUG
for (iv = 0; iv < d_aid.iv_max; iv++) {
aid_dbg("Point Voltage[%d] = ", iv);
for (c = 0; c < CI_MAX; c++)
aid_dbg("%lld ", point_voltages[iv].rgb[c]);
aid_dbg("\n");
}
#endif
return ret;
}
static int calc_output_voltages(struct dynamic_aid_info d_aid)
{
int iv, i, c;
int v_idx, v_cnt;
struct rgb_t v, v_diff;
struct rgb64_t *output_voltages;
struct rgb64_t *point_voltages;
output_voltages = d_aid.output_voltages;
point_voltages = d_aid.point_voltages;
iv = d_aid.iv_max - 1;
/* iv == (IV_MAX-1) ~ 0; */
for (; iv > 0; iv--) {
v_cnt = d_aid.iv_tbl[iv] - d_aid.iv_tbl[iv-1];
v_idx = d_aid.iv_tbl[iv];
for (c = 0; c < CI_MAX; c++) {
v.rgb[c] = point_voltages[iv].rgb[c];
v_diff.rgb[c] =
point_voltages[iv-1].rgb[c] -
point_voltages[iv].rgb[c];
}
if (iv == 1)
for (c = 0; c < CI_MAX; c++)
v_diff.rgb[c] = d_aid.vreg -
point_voltages[iv].rgb[c];
for (i = 0; i < v_cnt; i++, v_idx--) {
for (c = 0; c < CI_MAX; c++)
output_voltages[v_idx].rgb[c] = v.rgb[c]
+ v_diff.rgb[c]*i/v_cnt;
}
}
for (c = 0; c < CI_MAX; c++)
output_voltages[0].rgb[c] = d_aid.vreg;
#ifdef DYNAMIC_AID_DEBUG
for (iv = 0; iv <= d_aid.iv_top; iv++) {
aid_dbg("Output Voltage[%d] = ", iv);
for (c = 0; c < CI_MAX; c++)
aid_dbg("%lld ", output_voltages[iv].rgb[c]);
aid_dbg("\n");
}
#endif
return 0;
}
static int calc_voltage_table(struct dynamic_aid_info d_aid)
{
int ret;
ret = calc_point_voltages(d_aid);
if (ret)
return ret;
ret = calc_output_voltages(d_aid);
if (ret)
return ret;
return 0;
}
static int init_l_lookup_table(struct dynamic_aid_info d_aid)
{
int iv;
int *gamma_curve;
int *l_lookup_table;
gamma_curve = (int *)d_aid.param.gc_lut;
l_lookup_table = d_aid.l_lookup_table;
for (iv = 0; iv <= d_aid.iv_top; iv++)
l_lookup_table[iv] = DIV_100(d_aid.ibr_top*gamma_curve[iv]);
#ifdef DYNAMIC_AID_DEBUG
for (iv = 0; iv <= d_aid.iv_top; iv++)
aid_dbg("L lookup table[%d] = %d\n", iv, l_lookup_table[iv]);
#endif
return 0;
}
static int min_diff_gray(int in, int *table, int table_cnt)
{
int ret, i, min, temp;
ret = min = table[table_cnt] + 1;
for (i = 0; i <= table_cnt; i++) {
temp = table[i] - in;
if (temp < 0)
temp = -temp;
if (temp <= min) {
min = temp;
ret = i;
}
if ((in >= table[i-1]) && (in <= table[i]))
break;
}
return ret;
}
static int calc_l_values(struct dynamic_aid_info d_aid, int ibr)
{
int iv;
int *gamma_curve;
int *br_base;
int *l_value;
gamma_curve = (int *)d_aid.param.gc_tbls[ibr];
br_base = (int *)d_aid.param.br_base;
l_value = d_aid.l_value;
iv = d_aid.iv_max - 1;
/* iv == (IV_MAX - 1) ~ 0; */
for (; iv >= 0; iv--) {
if (iv == d_aid.iv_max - 1)
l_value[iv] = MUL_10000(br_base[ibr]);
else
l_value[iv] = DIV_100(br_base[ibr]*
gamma_curve[d_aid.iv_tbl[iv]]);
}
#ifdef DYNAMIC_AID_DEBUG
aid_dbg("L value (%d) = ", d_aid.ibr_tbl[ibr]);
for (iv = 0; iv < d_aid.iv_max; iv++)
aid_dbg("%d ", l_value[iv]);
aid_dbg("\n");
#endif
return 0;
}
static int calc_m_gray_values(struct dynamic_aid_info d_aid, int ibr)
{
int iv;
int (*offset_gra)[d_aid.iv_max];
int *l_lookup_table;
int *l_value;
int *m_gray;
offset_gra = (int(*)[])d_aid.param.offset_gra;
l_lookup_table = d_aid.l_lookup_table;
l_value = d_aid.l_value;
m_gray = d_aid.m_gray;
iv = d_aid.iv_max - 1;
/* iv == (IV_MAX - 1) ~ 0; */
for (; iv >= 0; iv--) {
m_gray[iv] = min_diff_gray(l_value[iv], l_lookup_table,
d_aid.iv_top);
if (offset_gra)
m_gray[iv] += offset_gra[ibr][iv];
}
#ifdef DYNAMIC_AID_DEBUG
aid_dbg("M-Gray value[%d] = ", d_aid.ibr_tbl[ibr]);
for (iv = 0; iv < d_aid.iv_max; iv++)
aid_dbg("%d ", d_aid.m_gray[iv]);
aid_dbg("\n");
#endif
return 0;
}
static int calc_m_rgb_voltages(struct dynamic_aid_info d_aid, int ibr)
{
int iv, c;
struct rgb64_t *output_voltages;
struct rgb64_t *point_voltages;
int *m_gray;
struct rgb64_t *m_voltage;
output_voltages = d_aid.output_voltages;
point_voltages = d_aid.point_voltages;
m_gray = d_aid.m_gray;
m_voltage = d_aid.m_voltage;
iv = d_aid.iv_max - 1;
/* iv == (IV_MAX - 1) ~ 1; */
for (; iv > 0; iv--) {
for (c = 0; c < CI_MAX; c++)
m_voltage[iv].rgb[c] =
output_voltages[m_gray[iv]].rgb[c];
}
/* iv == 0; */
for (c = 0; c < CI_MAX; c++)
m_voltage[iv].rgb[c] = point_voltages[0].rgb[c];
#ifdef DYNAMIC_AID_DEBUG
aid_dbg("M-RGB voltage (%d) =\n", d_aid.ibr_tbl[ibr]);
for (iv = 0; iv < d_aid.iv_max; iv++) {
aid_dbg("[%d] = ", iv);
for (c = 0; c < CI_MAX; c++)
aid_dbg("%lld ", d_aid.m_voltage[iv].rgb[c]);
aid_dbg("\n");
}
#endif
return 0;
}
static int calc_gamma(struct dynamic_aid_info d_aid, int ibr, int *result)
{
int ret, iv, c;
int numerator, denominator;
s64 t1, t2;
int *vd, *mtp, *res;
struct rgb_t (*offset_color)[d_aid.iv_max];
struct rgb64_t *m_voltage;
offset_color = (struct rgb_t(*)[])d_aid.param.offset_color;
m_voltage = d_aid.m_voltage;
iv = d_aid.iv_max - 1;
ret = 0;
/* iv == (IV_MAX - 1) ~ 1; */
for (; iv > 0; iv--) {
mtp = &d_aid.mtp[iv*CI_MAX];
res = &result[iv*CI_MAX];
numerator = d_aid.param.formular[iv].numerator;
denominator = d_aid.param.formular[iv].denominator;
for (c = 0; c < CI_MAX; c++) {
if (iv == 0) {
t1 = 0;
t2 = 1;
} else if (iv == 1) {
t1 = d_aid.vreg - m_voltage[iv].rgb[c];
t2 = d_aid.vreg - m_voltage[iv+1].rgb[c];
} else if (iv == d_aid.iv_max - 1) {
t1 = d_aid.vreg - m_voltage[iv].rgb[c];
t2 = d_aid.vreg;
} else {
t1 = m_voltage[0].rgb[c] -
m_voltage[iv].rgb[c];
t2 = m_voltage[0].rgb[c] -
m_voltage[iv+1].rgb[c];
}
res[c] = div64_s64((t1 + 1) * denominator,
t2) - numerator;
res[c] -= mtp[c];
if (offset_color)
res[c] += offset_color[ibr][iv].rgb[c];
if ((res[c] > 255) && (iv != d_aid.iv_max - 1))
res[c] = 255;
}
}
/* iv == 0; */
vd = (int *)&d_aid.param.gamma_default[0];
res = &result[0];
for (c = 0; c < CI_MAX; c++)
res[c] = vd[c];
#ifdef DYNAMIC_AID_DEBUG
aid_dbg("Gamma (%d) =\n", d_aid.ibr_tbl[ibr]);
for (iv = 0; iv < d_aid.iv_max; iv++) {
aid_dbg("[%d] = ", iv);
for (c = 0; c < CI_MAX; c++)
aid_dbg("%X ", result[iv*CI_MAX+c]);
aid_dbg("\n");
}
#endif
return ret;
}
static int calc_gamma_table(struct dynamic_aid_info d_aid, int **gamma)
{
int ibr;
#ifdef DYNAMIC_AID_DEBUG
int iv, c;
#endif
init_l_lookup_table(d_aid);
/* ibr == 0 ~ (IBRIGHTNESS_MAX - 1); */
for (ibr = 0; ibr < d_aid.ibr_max; ibr++) {
calc_l_values(d_aid, ibr);
calc_m_gray_values(d_aid, ibr);
calc_m_rgb_voltages(d_aid, ibr);
calc_gamma(d_aid, ibr, gamma[ibr]);
}
#ifdef DYNAMIC_AID_DEBUG
for (ibr = 0; ibr < d_aid.ibr_max; ibr++) {
aid_dbg("Gamma [%03d] = ", d_aid.ibr_tbl[ibr]);
for (iv = 1; iv < d_aid.iv_max; iv++) {
for (c = 0; c < CI_MAX; c++)
aid_dbg("%04d ",
gamma[ibr][iv*CI_MAX+c]);
}
for (c = 0; c < CI_MAX; c++)
aid_dbg("%d ", gamma[ibr][c]);
aid_dbg("\n");
}
#endif
return 0;
}
int dynamic_aid(struct dynamic_aid_param_t param, int **gamma)
{
struct dynamic_aid_info d_aid;
int ret;
d_aid.param = param;
d_aid.iv_tbl = (int *)param.iv_tbl;
d_aid.iv_max = param.iv_max;
/* number of top voltage index: 255 */
d_aid.iv_top = param.iv_tbl[param.iv_max-1];
d_aid.mtp = param.mtp;
d_aid.vreg = MUL_100(param.vreg);
d_aid.ibr_tbl = (int *)param.ibr_tbl;
d_aid.ibr_max = param.ibr_max;
/* number of top brightness : 300nt */
d_aid.ibr_top = param.ibr_tbl[param.ibr_max-1];
d_aid.point_voltages = kzalloc(sizeof(struct rgb64_t)*d_aid.iv_max,
GFP_KERNEL);
if (!d_aid.point_voltages) {
printk(KERN_ERR "failed to allocate point_voltages\n");
ret = -ENOMEM;
goto error1;
}
d_aid.output_voltages = kzalloc(sizeof(struct rgb64_t)*
(d_aid.iv_top+1), GFP_KERNEL);
if (!d_aid.output_voltages) {
printk(KERN_ERR "failed to allocate output_voltages\n");
ret = -ENOMEM;
goto error2;
}
d_aid.l_value = kzalloc(sizeof(int)*d_aid.iv_max, GFP_KERNEL);
if (!d_aid.l_value) {
printk(KERN_ERR "failed to allocate l_value\n");
ret = -ENOMEM;
goto error3;
}
d_aid.l_lookup_table = kzalloc(sizeof(int)*(d_aid.iv_top+1),
GFP_KERNEL);
if (!d_aid.l_lookup_table) {
printk(KERN_ERR "failed to allocate l_lookup_table\n");
ret = -ENOMEM;
goto error4;
}
d_aid.m_gray = kzalloc(sizeof(int)*d_aid.iv_max, GFP_KERNEL);
if (!d_aid.m_gray) {
printk(KERN_ERR "failed to allocate m_gray\n");
ret = -ENOMEM;
goto error5;
}
d_aid.m_voltage = kzalloc(sizeof(struct rgb64_t)*d_aid.iv_max,
GFP_KERNEL);
if (!d_aid.m_voltage) {
printk(KERN_ERR "failed to allocate m_voltage\n");
ret = -ENOMEM;
goto error6;
}
ret = calc_voltage_table(d_aid);
if (ret)
goto error7;
ret = calc_gamma_table(d_aid, gamma);
if (ret)
goto error7;
printk(KERN_INFO "Dynamic Aid Finished !\n");
error7:
kfree(d_aid.m_voltage);
error6:
kfree(d_aid.m_gray);
error5:
kfree(d_aid.l_lookup_table);
error4:
kfree(d_aid.l_value);
error3:
kfree(d_aid.output_voltages);
error2:
kfree(d_aid.point_voltages);
error1:
return ret;
}

View file

@ -0,0 +1,40 @@
#ifndef __DYNAMIC_AID_H
#define __DYNAMIC_AID_H __FILE__
enum {
CI_RED,
CI_GREEN,
CI_BLUE,
CI_MAX
};
struct rgb_t {
int rgb[CI_MAX];
};
struct formular_t {
int numerator;
int denominator;
};
struct dynamic_aid_param_t {
int vreg;
const int *iv_tbl;
int iv_max;
int *mtp;
const int *gamma_default;
const struct formular_t *formular;
const int *vt_voltage_value;
const int *ibr_tbl;
int ibr_max;
const int *br_base;
const int **gc_tbls; /* Gamma curve tables */
const int *gc_lut; /* Gamma curve for generating the Lookup Table */
const int (*offset_gra)[];
const struct rgb_t (*offset_color)[];
};
extern int dynamic_aid(struct dynamic_aid_param_t d_aid, int **gamma);
#endif /* __DYNAMIC_AID_H */

View file

@ -0,0 +1,739 @@
#ifndef __DYNAMIC_AID_GAMMA_CURVE_H
#define __DYNAMIC_AID_GAMMA_CURVE_H __FILE__
static const int gamma_curve_1p60_table[256] = {
0, 141, 428, 818, 1297, 1853, 2481, 3175,
3931, 4746, 5617, 6543, 7520, 8548, 9624, 10747,
11916, 13130, 14387, 15687, 17029, 18411, 19834, 21296,
22797, 24335, 25912, 27524, 29174, 30858, 32578, 34333,
36122, 37945, 39802, 41691, 43613, 45568, 47554, 49572,
51622, 53702, 55813, 57954, 60126, 62327, 64558, 66818,
69107, 71425, 73771, 76146, 78549, 80980, 83438, 85924,
88438, 90978, 93545, 96139, 98759, 101406, 104079, 106778,
109502, 112253, 115029, 117830, 120656, 123508, 126384, 129285,
132211, 135161, 138136, 141135, 144158, 147204, 150275, 153370,
156488, 159629, 162794, 165982, 169193, 172427, 175684, 178964,
182267, 185592, 188940, 192310, 195702, 199117, 202554, 206012,
209493, 212996, 216520, 220066, 223633, 227222, 230832, 234464,
238116, 241790, 245485, 249201, 252938, 256695, 260474, 264273,
268092, 271933, 275793, 279674, 283575, 287497, 291439, 295400,
299382, 303384, 307405, 311447, 315508, 319589, 323689, 327810,
331949, 336108, 340287, 344485, 348702, 352938, 357193, 361468,
365761, 370074, 374406, 378756, 383125, 387513, 391920, 396345,
400789, 405251, 409732, 414232, 418750, 423286, 427840, 432413,
437004, 441613, 446240, 450886, 455549, 460230, 464929, 469647,
474381, 479134, 483905, 488693, 493499, 498322, 503163, 508021,
512897, 517791, 522702, 527630, 532576, 537538, 542518, 547516,
552530, 557562, 562610, 567676, 572759, 577858, 582975, 588108,
593259, 598426, 603610, 608811, 614028, 619262, 624513, 629780,
635064, 640365, 645682, 651015, 656365, 661731, 667114, 672513,
677928, 683360, 688808, 694272, 699752, 705248, 710760, 716289,
721834, 727394, 732971, 738563, 744172, 749796, 755436, 761092,
766764, 772452, 778155, 783874, 789609, 795359, 801125, 806907,
812704, 818517, 824345, 830189, 836048, 841923, 847813, 853719,
859640, 865576, 871527, 877494, 883476, 889474, 895486, 901514,
907557, 913614, 919688, 925776, 931879, 937997, 944130, 950278,
956441, 962620, 968812, 975020, 981243, 987481, 993733, 1000000
};
static const int gamma_curve_1p65_table[256] = {
0, 107, 336, 655, 1053, 1522, 2057, 2652,
3306, 4015, 4778, 5591, 6454, 7366, 8324, 9327,
10375, 11467, 12601, 13777, 14994, 16251, 17547, 18883,
20256, 21668, 23116, 24601, 26123, 27680, 29272, 30900,
32562, 34258, 35987, 37750, 39546, 41375, 43237, 45130,
47055, 49012, 51000, 53019, 55069, 57149, 59260, 61400,
63571, 65771, 68000, 70259, 72546, 74862, 77207, 79581,
81982, 84412, 86869, 89354, 91867, 94407, 96974, 99568,
102189, 104837, 107512, 110213, 112940, 115694, 118473, 121279,
124110, 126967, 129850, 132758, 135691, 138650, 141633, 144642,
147675, 150733, 153816, 156923, 160055, 163211, 166392, 169596,
172824, 176077, 179353, 182653, 185977, 189324, 192695, 196089,
199506, 202947, 206410, 209897, 213407, 216940, 220495, 224073,
227674, 231298, 234943, 238612, 242303, 246015, 249751, 253508,
257287, 261089, 264912, 268757, 272624, 276513, 280423, 284355,
288309, 292284, 296280, 300298, 304337, 308397, 312478, 316581,
320705, 324849, 329015, 333201, 337408, 341636, 345885, 350154,
354444, 358755, 363086, 367437, 371809, 376201, 380614, 385046,
389499, 393972, 398466, 402979, 407512, 412065, 416638, 421231,
425844, 430477, 435129, 439801, 444492, 449203, 453934, 458684,
463454, 468243, 473052, 477879, 482726, 487593, 492478, 497383,
502307, 507250, 512212, 517193, 522193, 527211, 532249, 537306,
542381, 547475, 552588, 557720, 562870, 568039, 573227, 578433,
583658, 588901, 594162, 599442, 604741, 610057, 615392, 620746,
626117, 631507, 636915, 642341, 647785, 653248, 658728, 664227,
669743, 675277, 680830, 686400, 691988, 697594, 703217, 708859,
714518, 720195, 725890, 731602, 737332, 743079, 748844, 754627,
760427, 766244, 772079, 777932, 783802, 789689, 795593, 801515,
807454, 813411, 819384, 825375, 831383, 837408, 843451, 849510,
855586, 861680, 867790, 873918, 880062, 886224, 892402, 898598,
904810, 911039, 917285, 923547, 929826, 936123, 942435, 948765,
955111, 961474, 967854, 974250, 980663, 987092, 993538, 1000000
};
static const int gamma_curve_1p70_table[256] = {
0, 81, 263, 525, 856, 1251, 1705, 2216,
2781, 3397, 4063, 4778, 5540, 6347, 7199, 8095,
9034, 10015, 11037, 12099, 13202, 14343, 15524, 16742,
17999, 19292, 20622, 21989, 23391, 24829, 26302, 27810,
29352, 30928, 32538, 34182, 35859, 37569, 39311, 41086,
42893, 44732, 46602, 48504, 50437, 52401, 54396, 56422,
58478, 60564, 62680, 64826, 67002, 69207, 71442, 73705,
75998, 78319, 80669, 83048, 85455, 87891, 90354, 92845,
95365, 97912, 100486, 103088, 105717, 108374, 111058, 113768,
116506, 119270, 122061, 124878, 127722, 130592, 133488, 136410,
139359, 142333, 145333, 148359, 151411, 154488, 157590, 160718,
163871, 167049, 170253, 173481, 176734, 180013, 183315, 186643,
189995, 193372, 196773, 200199, 203649, 207123, 210621, 214144,
217690, 221260, 224855, 228473, 232114, 235780, 239469, 243182,
246918, 250677, 254460, 258266, 262096, 265949, 269824, 273723,
277645, 281590, 285557, 289548, 293561, 297597, 301656, 305737,
309841, 313967, 318116, 322287, 326481, 330696, 334934, 339195,
343477, 347782, 352108, 356457, 360827, 365220, 369634, 374070,
378528, 383008, 387509, 392032, 396576, 401142, 405730, 410339,
414969, 419621, 424294, 428988, 433704, 438441, 443199, 447978,
452778, 457600, 462442, 467305, 472189, 477094, 482020, 486967,
491935, 496923, 501932, 506962, 512012, 517083, 522174, 527286,
532419, 537572, 542745, 547939, 553153, 558387, 563642, 568917,
574212, 579527, 584862, 590218, 595594, 600989, 606405, 611841,
617296, 622772, 628268, 633783, 639318, 644873, 650448, 656042,
661657, 667291, 672944, 678617, 684310, 690023, 695754, 701506,
707277, 713067, 718877, 724706, 730555, 736422, 742310, 748216,
754142, 760087, 766051, 772034, 778037, 784059, 790099, 796159,
802238, 808336, 814453, 820589, 826744, 832918, 839110, 845322,
851552, 857801, 864069, 870356, 876662, 882986, 889329, 895691,
902071, 908470, 914888, 921324, 927779, 934252, 940744, 947254,
953783, 960330, 966896, 973480, 980082, 986703, 993342, 1000000
};
static const int gamma_curve_1p75_table[256] = {
0, 61, 207, 420, 695, 1027, 1414, 1851,
2339, 2874, 3456, 4083, 4755, 5470, 6227, 7026,
7866, 8747, 9667, 10626, 11624, 12660, 13734, 14845,
15993, 17177, 18397, 19654, 20945, 22272, 23633, 25029,
26459, 27922, 29420, 30951, 32515, 34112, 35742, 37404,
39098, 40825, 42583, 44374, 46195, 48048, 49932, 51847,
53793, 55770, 57777, 59814, 61881, 63979, 66106, 68264,
70450, 72667, 74912, 77187, 79491, 81824, 84186, 86577,
88996, 91444, 93920, 96424, 98957, 101517, 104106, 106723,
109367, 112039, 114739, 117466, 120220, 123002, 125811, 128648,
131511, 134401, 137318, 140262, 143233, 146230, 149254, 152305,
155382, 158485, 161614, 164770, 167951, 171159, 174393, 177652,
180938, 184249, 187586, 190949, 194337, 197750, 201189, 204654,
208144, 211659, 215199, 218764, 222355, 225970, 229611, 233276,
236966, 240681, 244421, 248185, 251974, 255788, 259626, 263489,
267376, 271287, 275223, 279183, 283167, 287175, 291208, 295264,
299345, 303450, 307578, 311731, 315907, 320107, 324331, 328578,
332849, 337144, 341463, 345804, 350170, 354559, 358971, 363407,
367865, 372348, 376853, 381382, 385934, 390509, 395107, 399728,
404372, 409039, 413729, 418442, 423178, 427936, 432718, 437522,
442349, 447198, 452070, 456965, 461882, 466822, 471785, 476770,
481777, 486807, 491859, 496933, 502030, 507149, 512290, 517453,
522639, 527847, 533077, 538329, 543603, 548899, 554217, 559557,
564919, 570302, 575708, 581136, 586585, 592056, 597549, 603064,
608600, 614158, 619737, 625339, 630961, 636606, 642272, 647959,
653668, 659398, 665150, 670923, 676718, 682533, 688371, 694229,
700109, 706010, 711932, 717875, 723840, 729825, 735832, 741860,
747909, 753979, 760070, 766182, 772315, 778469, 784644, 790839,
797056, 803293, 809551, 815830, 822130, 828451, 834792, 841154,
847537, 853940, 860364, 866809, 873274, 879760, 886267, 892793,
899341, 905909, 912497, 919106, 925735, 932385, 939055, 945746,
952456, 959188, 965939, 972711, 979503, 986315, 993147, 1000000
};
static const int gamma_curve_1p80_table[256] = {
0, 47, 162, 337, 565, 844, 1172, 1547,
1967, 2431, 2939, 3489, 4081, 4713, 5386, 6098,
6849, 7639, 8467, 9332, 10235, 11174, 12150, 13162,
14210, 15294, 16413, 17566, 18755, 19978, 21235, 22526,
23851, 25209, 26600, 28025, 29483, 30974, 32497, 34052,
35640, 37260, 38911, 40595, 42310, 44057, 45834, 47644,
49484, 51355, 53257, 55189, 57152, 59146, 61170, 63224,
65308, 67422, 69566, 71740, 73943, 76177, 78439, 80731,
83052, 85403, 87782, 90191, 92628, 95095, 97590, 100114,
102666, 105247, 107856, 110494, 113160, 115854, 118576, 121327,
124105, 126911, 129746, 132608, 135497, 138415, 141359, 144332,
147332, 150359, 153414, 156496, 159605, 162741, 165904, 169095,
172312, 175556, 178828, 182126, 185450, 188802, 192180, 195585,
199016, 202474, 205958, 209468, 213005, 216569, 220158, 223774,
227416, 231083, 234777, 238497, 242243, 246015, 249813, 253637,
257486, 261361, 265262, 269189, 273141, 277119, 281122, 285151,
289205, 293285, 297390, 301520, 305676, 309857, 314063, 318294,
322550, 326832, 331139, 335470, 339827, 344209, 348616, 353047,
357503, 361985, 366491, 371021, 375577, 380157, 384762, 389391,
394045, 398724, 403427, 408155, 412907, 417683, 422484, 427309,
432159, 437033, 441931, 446854, 451800, 456771, 461766, 466785,
471829, 476896, 481987, 487103, 492242, 497406, 502593, 507804,
513039, 518298, 523581, 528887, 534218, 539572, 544949, 550351,
555776, 561225, 566697, 572193, 577713, 583256, 588822, 594412,
600026, 605663, 611323, 617007, 622714, 628444, 634198, 639975,
645776, 651599, 657446, 663316, 669209, 675126, 681065, 687028,
693013, 699022, 705054, 711109, 717187, 723288, 729411, 735558,
741728, 747920, 754135, 760374, 766635, 772919, 779225, 785555,
791907, 798282, 804679, 811100, 817543, 824008, 830496, 837007,
843541, 850097, 856675, 863276, 869900, 876546, 883215, 889906,
896619, 903355, 910113, 916894, 923697, 930522, 937370, 944240,
951132, 958046, 964983, 971942, 978923, 985927, 992952, 1000000
};
static const int gamma_curve_1p85_table[256] = {
0, 35, 127, 270, 459, 693, 972, 1292,
1654, 2057, 2500, 2982, 3503, 4062, 4658, 5293,
5964, 6672, 7416, 8196, 9012, 9863, 10749, 11671,
12627, 13617, 14642, 15701, 16794, 17920, 19080, 20273,
21499, 22759, 24051, 25376, 26734, 28124, 29546, 31001,
32487, 34006, 35556, 37138, 38751, 40397, 42073, 43781,
45519, 47289, 49090, 50922, 52785, 54678, 56602, 58556,
60541, 62556, 64601, 66677, 68783, 70919, 73085, 75280,
77506, 79761, 82046, 84360, 86705, 89078, 91481, 93914,
96375, 98866, 101386, 103936, 106514, 109121, 111757, 114422,
117116, 119839, 122590, 125370, 128179, 131016, 133882, 136776,
139699, 142650, 145629, 148637, 151673, 154737, 157829, 160949,
164098, 167274, 170478, 173710, 176970, 180258, 183574, 186917,
190288, 193687, 197114, 200568, 204049, 207558, 211095, 214659,
218250, 221869, 225515, 229188, 232888, 236616, 240371, 244153,
247962, 251799, 255662, 259552, 263470, 267414, 271385, 275383,
279408, 283460, 287538, 291644, 295776, 299934, 304120, 308332,
312570, 316835, 321127, 325445, 329790, 334161, 338559, 342983,
347433, 351910, 356413, 360942, 365498, 370080, 374688, 379322,
383982, 388669, 393382, 398120, 402885, 407676, 412493, 417336,
422204, 427099, 432020, 436966, 441938, 446937, 451961, 457010,
462086, 467187, 472314, 477467, 482646, 487850, 493079, 498335,
503616, 508922, 514254, 519612, 524995, 530403, 535837, 541296,
546781, 552292, 557827, 563388, 568974, 574586, 580223, 585885,
591572, 597285, 603023, 608786, 614574, 620388, 626226, 632090,
637979, 643893, 649831, 655795, 661784, 667798, 673837, 679901,
685990, 692104, 698243, 704406, 710595, 716808, 723046, 729309,
735597, 741910, 748247, 754610, 760996, 767408, 773844, 780305,
786791, 793302, 799837, 806396, 812981, 819589, 826223, 832881,
839563, 846270, 853002, 859758, 866539, 873344, 880173, 887027,
893905, 900808, 907735, 914687, 921662, 928663, 935687, 942736,
949809, 956906, 964028, 971174, 978344, 985539, 992757, 1000000
};
static const int gamma_curve_1p90_table[256] = {
0, 27, 100, 216, 373, 570, 805, 1080,
1391, 1740, 2126, 2548, 3006, 3500, 4029, 4594,
5193, 5827, 6495, 7198, 7935, 8705, 9510, 10348,
11220, 12124, 13062, 14033, 15037, 16074, 17144, 18246,
19380, 20547, 21746, 22978, 24241, 25536, 26863, 28223,
29613, 31036, 32490, 33975, 35492, 37041, 38620, 40231,
41873, 43546, 45250, 46985, 48751, 50547, 52375, 54233,
56122, 58041, 59991, 61972, 63982, 66024, 68095, 70197,
72330, 74492, 76684, 78907, 81160, 83442, 85755, 88098,
90470, 92872, 95305, 97766, 100258, 102779, 105330, 107911,
110521, 113161, 115830, 118528, 121256, 124014, 126800, 129616,
132462, 135336, 138240, 141173, 144135, 147127, 150147, 153196,
156275, 159382, 162519, 165684, 168878, 172101, 175353, 178634,
181944, 185282, 188649, 192045, 195469, 198923, 202404, 205915,
209454, 213021, 216617, 220242, 223895, 227576, 231286, 235024,
238791, 242586, 246409, 250261, 254141, 258049, 261986, 265950,
269943, 273964, 278014, 282091, 286196, 290330, 294492, 298681,
302899, 307144, 311418, 315720, 320049, 324407, 328792, 333205,
337647, 342116, 346612, 351137, 355689, 360270, 364877, 369513,
374176, 378868, 383586, 388333, 393107, 397908, 402738, 407594,
412479, 417391, 422330, 427297, 432292, 437314, 442363, 447440,
452545, 457676, 462835, 468022, 473236, 478477, 483746, 489042,
494365, 499716, 505093, 510498, 515931, 521390, 526877, 532391,
537932, 543500, 549096, 554719, 560368, 566045, 571749, 577480,
583238, 589023, 594836, 600675, 606541, 612434, 618354, 624302,
630276, 636277, 642305, 648360, 654442, 660550, 666686, 672849,
679038, 685254, 691497, 697767, 704063, 710387, 716737, 723114,
729518, 735948, 742405, 748889, 755400, 761937, 768501, 775091,
781709, 788352, 795023, 801720, 808444, 815194, 821971, 828775,
835605, 842461, 849344, 856254, 863190, 870153, 877142, 884158,
891200, 898268, 905363, 912485, 919633, 926807, 934007, 941235,
948488, 955768, 963074, 970407, 977765, 985151, 992562, 1000000
};
static const int gamma_curve_1p95_table[256] = {
0, 20, 78, 173, 303, 468, 668, 902,
1170, 1472, 1808, 2178, 2580, 3016, 3485, 3987,
4521, 5089, 5689, 6321, 6986, 7684, 8413, 9175,
9969, 10795, 11653, 12543, 13465, 14419, 15404, 16421,
17470, 18550, 19662, 20806, 21980, 23187, 24424, 25693,
26994, 28325, 29688, 31082, 32507, 33963, 35451, 36969,
38518, 40099, 41710, 43352, 45025, 46729, 48463, 50229,
52025, 53852, 55710, 57598, 59517, 61467, 63447, 65458,
67499, 69571, 71673, 73806, 75969, 78163, 80387, 82642,
84927, 87242, 89588, 91964, 94370, 96806, 99273, 101770,
104297, 106854, 109442, 112060, 114707, 117385, 120093, 122831,
125599, 128398, 131226, 134084, 136972, 139891, 142839, 145817,
148825, 151863, 154931, 158028, 161156, 164314, 167501, 170718,
173965, 177242, 180548, 183884, 187250, 190646, 194072, 197527,
201012, 204527, 208071, 211645, 215248, 218882, 222544, 226237,
229959, 233710, 237492, 241302, 245143, 249013, 252912, 256841,
260799, 264787, 268804, 272851, 276927, 281033, 285168, 289333,
293527, 297750, 302003, 306285, 310596, 314937, 319307, 323707,
328136, 332594, 337081, 341598, 346144, 350719, 355324, 359958,
364621, 369313, 374035, 378786, 383566, 388375, 393213, 398081,
402977, 407903, 412858, 417842, 422856, 427898, 432970, 438070,
443200, 448359, 453547, 458764, 464010, 469285, 474589, 479922,
485284, 490676, 496096, 501545, 507023, 512531, 518067, 523632,
529226, 534849, 540501, 546182, 551892, 557631, 563399, 569196,
575021, 580876, 586759, 592672, 598613, 604583, 610582, 616609,
622666, 628751, 634866, 641009, 647181, 653381, 659611, 665869,
672156, 678472, 684817, 691190, 697592, 704023, 710483, 716971,
723488, 730034, 736609, 743212, 749844, 756505, 763194, 769912,
776659, 783434, 790238, 797071, 803933, 810823, 817741, 824689,
831665, 838669, 845702, 852764, 859855, 866974, 874121, 881298,
888502, 895736, 902998, 910288, 917607, 924955, 932331, 939736,
947169, 954631, 962121, 969640, 977187, 984763, 992367, 1000000
};
static const int gamma_curve_2p00_table[256] = {
0, 15, 62, 138, 246, 384, 554, 754,
984, 1246, 1538, 1861, 2215, 2599, 3014, 3460,
3937, 4444, 4983, 5552, 6151, 6782, 7443, 8135,
8858, 9612, 10396, 11211, 12057, 12933, 13841, 14779,
15748, 16747, 17778, 18839, 19931, 21053, 22207, 23391,
24606, 25852, 27128, 28435, 29773, 31142, 32541, 33972,
35433, 36924, 38447, 40000, 41584, 43199, 44844, 46521,
48228, 49965, 51734, 53533, 55363, 57224, 59116, 61038,
62991, 64975, 66990, 69035, 71111, 73218, 75356, 77524,
79723, 81953, 84214, 86505, 88827, 91180, 93564, 95978,
98424, 100900, 103406, 105944, 108512, 111111, 113741, 116401,
119093, 121815, 124567, 127351, 130165, 133010, 135886, 138793,
141730, 144698, 147697, 150727, 153787, 156878, 160000, 163153,
166336, 169550, 172795, 176071, 179377, 182714, 186082, 189481,
192910, 196371, 199862, 203383, 206936, 210519, 214133, 217778,
221453, 225160, 228897, 232664, 236463, 240292, 244152, 248043,
251965, 255917, 259900, 263914, 267958, 272034, 276140, 280277,
284444, 288643, 292872, 297132, 301423, 305744, 310096, 314479,
318893, 323337, 327812, 332318, 336855, 341423, 346021, 350650,
355309, 360000, 364721, 369473, 374256, 379070, 383914, 388789,
393695, 398631, 403599, 408597, 413626, 418685, 423775, 428897,
434048, 439231, 444444, 449689, 454963, 460269, 465606, 470973,
476371, 481799, 487259, 492749, 498270, 503822, 509404, 515017,
520661, 526336, 532042, 537778, 543545, 549343, 555171, 561030,
566920, 572841, 578793, 584775, 590788, 596832, 602907, 609012,
615148, 621315, 627512, 633741, 640000, 646290, 652611, 658962,
665344, 671757, 678201, 684675, 691180, 697716, 704283, 710880,
717509, 724168, 730857, 737578, 744329, 751111, 757924, 764767,
771642, 778547, 785483, 792449, 799446, 806474, 813533, 820623,
827743, 834894, 842076, 849289, 856532, 863806, 871111, 878447,
885813, 893210, 900638, 908097, 915586, 923106, 930657, 938239,
945852, 953495, 961169, 968874, 976609, 984375, 992172, 1000000
};
static const int gamma_curve_2p05_table[256] = {
0, 12, 48, 111, 200, 316, 459, 630,
828, 1054, 1308, 1590, 1901, 2240, 2607, 3003,
3428, 3882, 4364, 4876, 5416, 5986, 6585, 7213,
7871, 8558, 9274, 10020, 10796, 11601, 12436, 13301,
14195, 15120, 16074, 17058, 18072, 19116, 20191, 21295,
22429, 23594, 24789, 26014, 27269, 28555, 29871, 31217,
32594, 34001, 35439, 36907, 38406, 39935, 41495, 43086,
44707, 46359, 48042, 49755, 51499, 53274, 55080, 56917,
58784, 60683, 62612, 64572, 66563, 68586, 70639, 72723,
74838, 76985, 79162, 81371, 83610, 85881, 88183, 90517,
92881, 95277, 97704, 100162, 102651, 105172, 107724, 110308,
112923, 115569, 118247, 120956, 123697, 126469, 129272, 132107,
134974, 137872, 140801, 143762, 146755, 149779, 152835, 155923,
159042, 162192, 165375, 168589, 171835, 175112, 178422, 181763,
185135, 188540, 191976, 195444, 198944, 202476, 206040, 209635,
213262, 216922, 220613, 224336, 228090, 231877, 235696, 239547,
243429, 247344, 251291, 255269, 259280, 263323, 267398, 271504,
275643, 279814, 284017, 288252, 292520, 296819, 301151, 305514,
309910, 314338, 318798, 323291, 327815, 332372, 336961, 341582,
346236, 350922, 355640, 360390, 365172, 369987, 374835, 379714,
384626, 389570, 394547, 399556, 404597, 409671, 414777, 419915,
425086, 430289, 435525, 440793, 446094, 451427, 456792, 462190,
467621, 473084, 478579, 484107, 489667, 495261, 500886, 506544,
512235, 517958, 523714, 529502, 535323, 541177, 547063, 552982,
558934, 564918, 570934, 576984, 583066, 589181, 595328, 601508,
607721, 613966, 620245, 626555, 632899, 639275, 645685, 652126,
658601, 665109, 671649, 678222, 684827, 691466, 698137, 704842,
711579, 718348, 725151, 731986, 738855, 745756, 752690, 759657,
766657, 773690, 780755, 787854, 794985, 802150, 809347, 816577,
823840, 831136, 838465, 845827, 853222, 860650, 868111, 875605,
883132, 890692, 898285, 905911, 913570, 921262, 928987, 936745,
944536, 952360, 960218, 968108, 976031, 983988, 991977, 1000000
};
static const int gamma_curve_2p10_table[256] = {
0, 9, 38, 89, 162, 259, 381, 526,
696, 892, 1112, 1359, 1631, 1930, 2255, 2606,
2985, 3390, 3822, 4282, 4769, 5284, 5826, 6396,
6994, 7620, 8274, 8956, 9667, 10406, 11174, 11971,
12796, 13650, 14534, 15446, 16387, 17358, 18357, 19387,
20445, 21533, 22651, 23798, 24976, 26183, 27419, 28686,
29983, 31310, 32667, 34054, 35471, 36919, 38397, 39905,
41444, 43013, 44613, 46244, 47905, 49597, 51320, 53074,
54858, 56674, 58520, 60398, 62307, 64246, 66217, 68219,
70253, 72318, 74414, 76541, 78700, 80890, 83112, 85366,
87651, 89967, 92316, 94696, 97107, 99551, 102026, 104534,
107073, 109644, 112247, 114882, 117549, 120249, 122980, 125743,
128539, 131367, 134227, 137120, 140044, 143001, 145991, 149013,
152067, 155154, 158273, 161425, 164610, 167827, 171076, 174359,
177674, 181022, 184402, 187815, 191261, 194740, 198252, 201797,
205374, 208985, 212628, 216305, 220014, 223757, 227533, 231341,
235183, 239058, 242967, 246908, 250883, 254891, 258932, 263007,
267114, 271256, 275430, 279638, 283880, 288155, 292463, 296805,
301181, 305589, 310032, 314508, 319018, 323561, 328139, 332749,
337394, 342072, 346784, 351530, 356309, 361123, 365970, 370851,
375766, 380715, 385698, 390715, 395765, 400850, 405969, 411122,
416308, 421529, 426784, 432073, 437397, 442754, 448146, 453571,
459031, 464525, 470054, 475617, 481214, 486845, 492511, 498211,
503945, 509714, 515517, 521354, 527226, 533133, 539074, 545049,
551059, 557104, 563183, 569296, 575444, 581627, 587845, 594097,
600383, 606705, 613061, 619451, 625877, 632337, 638832, 645362,
651926, 658526, 665160, 671829, 678533, 685272, 692045, 698854,
705697, 712576, 719489, 726438, 733421, 740439, 747493, 754581,
761704, 768863, 776057, 783285, 790549, 797848, 805182, 812551,
819956, 827395, 834870, 842380, 849925, 857506, 865122, 872773,
880459, 888181, 895938, 903730, 911558, 919421, 927319, 935253,
943222, 951227, 959267, 967343, 975454, 983600, 991782, 1000000
};
static const int gamma_curve_2p12_table[256] = {
0, 8, 34, 81, 149, 240, 353, 489,
650, 834, 1043, 1276, 1535, 1818, 2128, 2463,
2824, 3211, 3625, 4065, 4532, 5026, 5547, 6095,
6671, 7274, 7905, 8563, 9249, 9964, 10706, 11477,
12276, 13103, 13960, 14844, 15758, 16700, 17672, 18672,
19702, 20760, 21849, 22966, 24113, 25290, 26496, 27732,
28998, 30294, 31619, 32975, 34361, 35777, 37223, 38699,
40206, 41744, 43311, 44910, 46539, 48199, 49889, 51610,
53363, 55146, 56960, 58805, 60681, 62589, 64527, 66497,
68498, 70531, 72595, 74690, 76817, 78976, 81166, 83388,
85642, 87927, 90244, 92593, 94974, 97387, 99832, 102309,
104819, 107360, 109933, 112539, 115177, 117847, 120550, 123285,
126052, 128852, 131684, 134549, 137447, 140377, 143340, 146336,
149364, 152425, 155519, 158646, 161805, 164998, 168224, 171482,
174774, 178099, 181457, 184848, 188272, 191729, 195220, 198744,
202301, 205892, 209516, 213174, 216865, 220589, 224347, 228139,
231964, 235822, 239715, 243641, 247601, 251594, 255621, 259682,
263777, 267906, 272069, 276265, 280496, 284760, 289059, 293391,
297758, 302159, 306593, 311062, 315566, 320103, 324675, 329280,
333921, 338595, 343304, 348047, 352825, 357637, 362483, 367364,
372280, 377230, 382214, 387233, 392287, 397375, 402498, 407656,
412848, 418075, 423337, 428634, 433965, 439332, 444733, 450169,
455640, 461146, 466686, 472262, 477873, 483519, 489200, 494916,
500667, 506453, 512274, 518130, 524022, 529949, 535911, 541908,
547941, 554008, 560111, 566250, 572424, 578633, 584878, 591158,
597473, 603824, 610211, 616633, 623090, 629583, 636112, 642676,
649276, 655911, 662582, 669289, 676031, 682810, 689623, 696473,
703359, 710280, 717237, 724230, 731258, 738323, 745424, 752560,
759732, 766941, 774185, 781465, 788781, 796134, 803522, 810947,
818407, 825904, 833436, 841005, 848610, 856251, 863929, 871642,
879392, 887178, 895001, 902859, 910754, 918686, 926653, 934657,
942698, 950774, 958887, 967037, 975223, 983446, 991705, 1000000
};
static const int gamma_curve_2p13_table[256] = {
0, 7, 33, 78, 143, 231, 340, 472,
628, 807, 1009, 1237, 1488, 1765, 2067, 2394,
2747, 3126, 3530, 3961, 4418, 4902, 5413, 5950,
6515, 7107, 7726, 8373, 9047, 9749, 10479, 11238,
12024, 12838, 13681, 14552, 15452, 16381, 17338, 18325,
19340, 20384, 21458, 22561, 23693, 24855, 26046, 27267,
28518, 29798, 31108, 32448, 33819, 35219, 36650, 38110,
39601, 41123, 42675, 44257, 45870, 47514, 49189, 50894,
52630, 54397, 56195, 58024, 59884, 61776, 63698, 65652,
67638, 69654, 71702, 73782, 75893, 78036, 80210, 82417,
84655, 86925, 89226, 91560, 93926, 96323, 98753, 101215,
103709, 106236, 108794, 111385, 114009, 116664, 119353, 122073,
124827, 127612, 130431, 133282, 136166, 139083, 142033, 145015,
148030, 151078, 154160, 157274, 160421, 163602, 166815, 170062,
173342, 176655, 180002, 183382, 186795, 190242, 193722, 197235,
200782, 204363, 207977, 211625, 215307, 219022, 222771, 226554,
230370, 234221, 238105, 242023, 245976, 249962, 253982, 258036,
262124, 266247, 270403, 274594, 278819, 283078, 287371, 291699,
296061, 300458, 304888, 309354, 313853, 318388, 322956, 327560,
332197, 336870, 341577, 346319, 351095, 355906, 360752, 365633,
370548, 375499, 380484, 385504, 390559, 395649, 400774, 405934,
411129, 416359, 421624, 426925, 432260, 437631, 443036, 448477,
453954, 459465, 465012, 470594, 476211, 481864, 487553, 493276,
499035, 504830, 510660, 516526, 522427, 528364, 534336, 540344,
546388, 552467, 558582, 564733, 570919, 577142, 583400, 589694,
596023, 602389, 608790, 615228, 621701, 628210, 634756, 641337,
647954, 654608, 661297, 668022, 674784, 681582, 688416, 695286,
702192, 709135, 716113, 723128, 730180, 737267, 744391, 751552,
758748, 765981, 773251, 780557, 787899, 795278, 802693, 810145,
817634, 825159, 832720, 840319, 847953, 855625, 863333, 871078,
878859, 886678, 894533, 902424, 910353, 918318, 926320, 934359,
942435, 950548, 958698, 966884, 975108, 983368, 991666, 1000000
};
static const int gamma_curve_2p15_table[256] = {
0, 7, 30, 71, 132, 213, 315, 439,
586, 754, 946, 1161, 1400, 1663, 1950, 2262,
2599, 2961, 3348, 3761, 4199, 4663, 5154, 5671,
6214, 6784, 7381, 8005, 8656, 9335, 10040, 10774,
11535, 12324, 13141, 13986, 14859, 15761, 16691, 17649,
18637, 19653, 20698, 21772, 22875, 24007, 25169, 26360,
27581, 28831, 30111, 31421, 32760, 34130, 35529, 36959,
38419, 39909, 41429, 42980, 44562, 46174, 47817, 49490,
51195, 52930, 54696, 56494, 58322, 60182, 62073, 63995,
65948, 67933, 69950, 71998, 74078, 76189, 78333, 80508,
82715, 84954, 87224, 89528, 91863, 94230, 96630, 99062,
101526, 104022, 106552, 109113, 111708, 114334, 116994, 119686,
122411, 125169, 127960, 130784, 133641, 136530, 139453, 142409,
145399, 148421, 151477, 154566, 157688, 160844, 164034, 167257,
170513, 173803, 177127, 180484, 183875, 187300, 190759, 194252,
197778, 201339, 204933, 208562, 212224, 215921, 219652, 223417,
227217, 231050, 234918, 238821, 242757, 246729, 250734, 254775,
258849, 262959, 267103, 271282, 275495, 279743, 284026, 288344,
292697, 297084, 301507, 305964, 310457, 314984, 319547, 324145,
328778, 333446, 338149, 342888, 347661, 352471, 357315, 362195,
367110, 372061, 377047, 382069, 387126, 392219, 397348, 402512,
407712, 412948, 418219, 423526, 428869, 434248, 439663, 445113,
450600, 456122, 461681, 467275, 472906, 478572, 484275, 490014,
495789, 501600, 507448, 513332, 519252, 525208, 531201, 537230,
543296, 549398, 555536, 561711, 567923, 574171, 580455, 586777,
593134, 599529, 605960, 612428, 618933, 625474, 632052, 638668,
645319, 652008, 658734, 665497, 672296, 679133, 686006, 692917,
699865, 706850, 713872, 720931, 728027, 735160, 742331, 749539,
756784, 764066, 771386, 778743, 786138, 793569, 801039, 808545,
816089, 823671, 831290, 838947, 846641, 854373, 862143, 869950,
877794, 885677, 893597, 901555, 909550, 917584, 925655, 933764,
941911, 950095, 958318, 966578, 974877, 983213, 991588, 1000000
};
static const int gamma_curve_2p18_table[256] = {
0, 6, 26, 62, 116, 189, 282, 395,
528, 682, 859, 1057, 1277, 1521, 1788, 2078,
2392, 2730, 3092, 3479, 3890, 4327, 4789, 5276,
5789, 6328, 6893, 7484, 8101, 8745, 9416, 10114,
10839, 11591, 12370, 13177, 14011, 14874, 15764, 16683,
17629, 18604, 19608, 20640, 21700, 22790, 23909, 25056,
26233, 27439, 28675, 29940, 31234, 32558, 33913, 35297,
36711, 38155, 39629, 41134, 42669, 44235, 45831, 47457,
49115, 50803, 52523, 54273, 56055, 57867, 59711, 61587,
63493, 65431, 67401, 69403, 71436, 73501, 75598, 77727,
79887, 82080, 84306, 86563, 88853, 91175, 93530, 95917,
98336, 100789, 103274, 105792, 108343, 110926, 113543, 116193,
118876, 121592, 124341, 127124, 129940, 132789, 135672, 138589,
141539, 144522, 147540, 150591, 153676, 156795, 159948, 163135,
166356, 169611, 172900, 176223, 179581, 182973, 186400, 189861,
193356, 196886, 200450, 204050, 207683, 211352, 215055, 218794,
222567, 226375, 230218, 234096, 238009, 241957, 245941, 249960,
254014, 258103, 262228, 266388, 270584, 274815, 279081, 283384,
287722, 292095, 296505, 300950, 305431, 309948, 314501, 319089,
323714, 328375, 333072, 337805, 342574, 347379, 352221, 357099,
362013, 366963, 371950, 376974, 382034, 387131, 392264, 397433,
402640, 407883, 413163, 418479, 423833, 429223, 434650, 440114,
445615, 451153, 456728, 462341, 467990, 473676, 479400, 485161,
490959, 496794, 502667, 508577, 514525, 520510, 526533, 532593,
538690, 544825, 550998, 557209, 563457, 569743, 576066, 582428,
588827, 595264, 601739, 608252, 614803, 621392, 628019, 634684,
641387, 648129, 654908, 661726, 668582, 675476, 682409, 689379,
696388, 703436, 710522, 717647, 724809, 732011, 739251, 746530,
753847, 761203, 768597, 776030, 783502, 791013, 798563, 806151,
813779, 821445, 829150, 836894, 844677, 852499, 860360, 868260,
876199, 884178, 892195, 900252, 908348, 916483, 924658, 932871,
941124, 949417, 957749, 966120, 974531, 982981, 991471, 1000000
};
static const int gamma_curve_2p20_table[256] = {
0, 5, 23, 57, 107, 175, 262, 367,
493, 638, 805, 992, 1202, 1433, 1687, 1963,
2263, 2586, 2932, 3303, 3697, 4116, 4560, 5028,
5522, 6041, 6585, 7155, 7751, 8373, 9021, 9696,
10398, 11126, 11881, 12664, 13473, 14311, 15175, 16068,
16988, 17936, 18913, 19918, 20951, 22013, 23104, 24223,
25371, 26549, 27755, 28991, 30257, 31551, 32876, 34230,
35614, 37029, 38473, 39947, 41452, 42987, 44553, 46149,
47776, 49433, 51122, 52842, 54592, 56374, 58187, 60032,
61907, 63815, 65754, 67725, 69727, 71761, 73828, 75926,
78057, 80219, 82414, 84642, 86901, 89194, 91518, 93876,
96266, 98689, 101145, 103634, 106156, 108711, 111299, 113921,
116576, 119264, 121986, 124741, 127530, 130352, 133209, 136099,
139022, 141980, 144972, 147998, 151058, 154152, 157281, 160444,
163641, 166872, 170138, 173439, 176774, 180144, 183549, 186989,
190463, 193972, 197516, 201096, 204710, 208360, 212044, 215764,
219520, 223310, 227137, 230998, 234895, 238828, 242796, 246800,
250840, 254916, 259027, 263175, 267358, 271577, 275833, 280124,
284452, 288816, 293216, 297653, 302125, 306635, 311180, 315763,
320382, 325037, 329729, 334458, 339223, 344026, 348865, 353741,
358654, 363604, 368591, 373615, 378676, 383775, 388910, 394083,
399293, 404541, 409826, 415148, 420508, 425905, 431340, 436813,
442323, 447871, 453456, 459080, 464741, 470440, 476177, 481952,
487765, 493616, 499505, 505432, 511398, 517401, 523443, 529523,
535642, 541798, 547994, 554227, 560499, 566810, 573159, 579547,
585973, 592438, 598942, 605484, 612066, 618686, 625345, 632043,
638779, 645555, 652370, 659224, 666117, 673049, 680020, 687031,
694081, 701170, 708298, 715465, 722672, 729919, 737205, 744530,
751895, 759300, 766744, 774227, 781751, 789314, 796917, 804559,
812241, 819964, 827726, 835528, 843370, 851252, 859174, 867136,
875138, 883180, 891262, 899385, 907547, 915750, 923993, 932277,
940601, 948965, 957370, 965815, 974300, 982826, 991393, 1000000
};
static const int gamma_curve_2p21_table[256] = {
0, 5, 22, 54, 103, 168, 252, 354,
476, 617, 779, 962, 1166, 1391, 1639, 1909,
2201, 2517, 2856, 3218, 3604, 4015, 4449, 4909,
5393, 5902, 6436, 6996, 7582, 8193, 8830, 9494,
10184, 10901, 11644, 12415, 13212, 14037, 14889, 15769,
16676, 17612, 18575, 19566, 20586, 21634, 22711, 23817,
24951, 26114, 27307, 28528, 29779, 31060, 32370, 33709,
35079, 36478, 37907, 39367, 40856, 42377, 43927, 45508,
47120, 48762, 50436, 52140, 53875, 55642, 57440, 59269,
61130, 63022, 64945, 66901, 68888, 70907, 72958, 75042,
77157, 79305, 81484, 83697, 85942, 88219, 90529, 92872,
95247, 97656, 100097, 102572, 105079, 107620, 110194, 112802,
115442, 118117, 120825, 123566, 126342, 129151, 131994, 134870,
137781, 140726, 143705, 146718, 149766, 152848, 155964, 159115,
162300, 165520, 168774, 172063, 175387, 178746, 182140, 185569,
189033, 192532, 196066, 199635, 203240, 206879, 210555, 214266,
218012, 221794, 225611, 229465, 233354, 237278, 241239, 245236,
249268, 253337, 257442, 261583, 265760, 269973, 274223, 278509,
282831, 287190, 291586, 296018, 300486, 304992, 309534, 314113,
318728, 323381, 328070, 332797, 337560, 342361, 347199, 352074,
356986, 361936, 366923, 371947, 377008, 382108, 387244, 392419,
397631, 402880, 408167, 413492, 418855, 424256, 429695, 435171,
440686, 446239, 451829, 457458, 463125, 468830, 474574, 480356,
486176, 492035, 497932, 503867, 509841, 515854, 521905, 527995,
534124, 540291, 546497, 552742, 559026, 565349, 571711, 578111,
584551, 591030, 597548, 604105, 610701, 617337, 624012, 630726,
637479, 644272, 651105, 657977, 664888, 671839, 678829, 685860,
692929, 700039, 707188, 714377, 721606, 728875, 736184, 743532,
750921, 758350, 765818, 773327, 780876, 788465, 796095, 803764,
811474, 819224, 827015, 834846, 842717, 850629, 858581, 866574,
874607, 882681, 890796, 898951, 907147, 915384, 923661, 931980,
940339, 948739, 957180, 965662, 974185, 982749, 991354, 1000000
};
static const int gamma_curve_2p22_table[256] = {
0, 5, 21, 52, 99, 162, 243, 342,
460, 597, 754, 932, 1130, 1350, 1592, 1855,
2141, 2449, 2781, 3136, 3514, 3916, 4342, 4792,
5267, 5766, 6291, 6841, 7416, 8017, 8644, 9296,
9975, 10680, 11412, 12171, 12956, 13769, 14608, 15475,
16370, 17293, 18243, 19221, 20228, 21262, 22326, 23417,
24538, 25687, 26865, 28073, 29309, 30575, 31871, 33196,
34551, 35935, 37350, 38795, 40270, 41775, 43310, 44876,
46473, 48100, 49759, 51448, 53168, 54919, 56702, 58516,
60361, 62238, 64147, 66087, 68059, 70063, 72099, 74167,
76268, 78400, 80565, 82763, 84993, 87255, 89550, 91878,
94239, 96633, 99060, 101520, 104014, 106540, 109100, 111693,
114320, 116981, 119675, 122403, 125164, 127960, 130790, 133653,
136551, 139483, 142449, 145450, 148485, 151554, 154658, 157797,
160970, 164178, 167421, 170699, 174011, 177359, 180742, 184160,
187613, 191102, 194625, 198185, 201779, 205410, 209076, 212777,
216514, 220288, 224096, 227941, 231822, 235739, 239692, 243681,
247706, 251768, 255866, 260000, 264171, 268378, 272622, 276902,
281220, 285573, 289964, 294392, 298856, 303357, 307896, 312471,
317083, 321733, 326420, 331144, 335906, 340705, 345541, 350415,
355326, 360275, 365262, 370286, 375348, 380448, 385586, 390761,
395975, 401226, 406516, 411843, 417209, 422613, 428056, 433536,
439055, 444612, 450208, 455842, 461515, 467226, 472976, 478765,
484592, 490458, 496363, 502307, 508290, 514311, 520372, 526472,
532610, 538788, 545005, 551261, 557557, 563892, 570266, 576680,
583133, 589625, 596157, 602729, 609340, 615991, 622682, 629412,
636182, 642992, 649842, 656732, 663661, 670631, 677641, 684690,
691780, 698910, 706080, 713291, 720542, 727833, 735164, 742536,
749948, 757401, 764894, 772428, 780003, 787618, 795274, 802970,
810707, 818485, 826304, 834164, 842065, 850006, 857989, 866012,
874077, 882183, 890330, 898518, 906747, 915018, 923330, 931683,
940077, 948513, 956990, 965509, 974070, 982671, 991315, 1000000
};
static const int gamma_curve_2p23_table[256] = {
0, 4, 20, 50, 95, 156, 234, 330,
444, 577, 730, 903, 1096, 1311, 1546, 1803,
2083, 2384, 2708, 3055, 3425, 3819, 4237, 4678,
5144, 5634, 6149, 6689, 7254, 7844, 8460, 9102,
9770, 10464, 11184, 11931, 12705, 13505, 14333, 15188,
16070, 16979, 17917, 18882, 19875, 20897, 21947, 23025,
24131, 25267, 26431, 27625, 28847, 30099, 31380, 32691,
34031, 35401, 36801, 38231, 39691, 41181, 42702, 44253,
45835, 47447, 49091, 50765, 52470, 54206, 55974, 57773,
59603, 61465, 63358, 65283, 67240, 69229, 71250, 73303,
75389, 77506, 79656, 81839, 84054, 86302, 88582, 90896,
93242, 95621, 98034, 100480, 102959, 105471, 108017, 110596,
113209, 115855, 118536, 121250, 123998, 126780, 129597, 132447,
135332, 138251, 141204, 144192, 147214, 150271, 153363, 156490,
159651, 162847, 166078, 169345, 172646, 175983, 179354, 182762,
186204, 189682, 193196, 196745, 200330, 203950, 207607, 211299,
215027, 218792, 222592, 226428, 230301, 234210, 238155, 242136,
246154, 250209, 254300, 258427, 262592, 266793, 271031, 275305,
279617, 283966, 288352, 292774, 297234, 301732, 306266, 310838,
315447, 320094, 324778, 329500, 334259, 339056, 343891, 348763,
353674, 358622, 363608, 368633, 373695, 378795, 383934, 389111,
394326, 399579, 404871, 410201, 415570, 420977, 426423, 431907,
437430, 442992, 448592, 454232, 459910, 465627, 471384, 477179,
483013, 488887, 494800, 500751, 506743, 512773, 518843, 524952,
531101, 537289, 543517, 549785, 556092, 562439, 568825, 575251,
581718, 588224, 594770, 601356, 607982, 614648, 621354, 628101,
634887, 641714, 648581, 655489, 662437, 669425, 676454, 683523,
690633, 697783, 704974, 712206, 719479, 726792, 734146, 741541,
748977, 756454, 763972, 771530, 779130, 786771, 794453, 802177,
809941, 817747, 825594, 833483, 841413, 849384, 857397, 865451,
873547, 881685, 889864, 898085, 906347, 914652, 922998, 931386,
939816, 948287, 956801, 965357, 973954, 982594, 991276, 1000000
};
static const int gamma_curve_2p24_table[256] = {
0, 4, 19, 48, 91, 150, 225, 318,
429, 558, 707, 875, 1063, 1272, 1502, 1753,
2026, 2320, 2637, 2977, 3339, 3725, 4134, 4567,
5024, 5505, 6010, 6540, 7096, 7676, 8281, 8913,
9569, 10252, 10961, 11697, 12459, 13247, 14063, 14905,
15775, 16672, 17597, 18549, 19529, 20537, 21574, 22639,
23732, 24854, 26004, 27184, 28392, 29630, 30897, 32193,
33519, 34875, 36260, 37675, 39121, 40597, 42102, 43639,
45206, 46803, 48432, 50091, 51781, 53502, 55255, 57039,
58854, 60701, 62579, 64489, 66431, 68405, 70411, 72449,
74520, 76623, 78758, 80925, 83126, 85359, 87625, 89923,
92255, 94620, 97018, 99450, 101914, 104412, 106944, 109509,
112108, 114741, 117408, 120108, 122843, 125612, 128415, 131252,
134123, 137029, 139970, 142945, 145955, 149000, 152079, 155193,
158343, 161527, 164747, 168001, 171292, 174617, 177978, 181374,
184806, 188274, 191777, 195316, 198891, 202502, 206148, 209831,
213550, 217306, 221097, 224925, 228789, 232690, 236627, 240601,
244612, 248659, 252743, 256864, 261022, 265217, 269449, 273718,
278024, 282367, 286748, 291166, 295622, 300115, 304645, 309213,
313819, 318463, 323144, 327863, 332621, 337416, 342249, 347120,
352029, 356977, 361963, 366987, 372049, 377150, 382289, 387467,
392684, 397939, 403233, 408565, 413936, 419347, 424796, 430284,
435811, 441377, 446983, 452627, 458311, 464034, 469797, 475598,
481440, 487320, 493241, 499201, 505200, 511240, 517319, 523437,
529596, 535795, 542033, 548312, 554630, 560989, 567388, 573827,
580306, 586826, 593386, 599986, 606627, 613308, 620030, 626792,
633595, 640439, 647323, 654248, 661214, 668221, 675269, 682358,
689488, 696658, 703870, 711123, 718417, 725753, 733129, 740547,
748007, 755508, 763050, 770634, 778259, 785926, 793634, 801384,
809176, 817010, 824885, 832802, 840762, 848763, 856806, 864891,
873018, 881187, 889399, 897652, 905948, 914286, 922666, 931089,
939554, 948062, 956612, 965204, 973839, 982517, 991237, 1000000
};
static const int gamma_curve_2p25_table[256] = {
0, 4, 18, 46, 87, 144, 217, 307,
414, 540, 684, 848, 1031, 1235, 1459, 1704,
1970, 2258, 2568, 2901, 3255, 3633, 4034, 4458,
4906, 5378, 5875, 6395, 6940, 7511, 8106, 8727,
9373, 10045, 10743, 11467, 12217, 12994, 13797, 14628,
15485, 16370, 17282, 18222, 19189, 20184, 21208, 22259,
23339, 24447, 25584, 26750, 27944, 29168, 30421, 31703,
33015, 34356, 35727, 37128, 38559, 40020, 41511, 43033,
44585, 46168, 47781, 49426, 51101, 52807, 54545, 56314,
58114, 59946, 61810, 63705, 65632, 67591, 69582, 71605,
73661, 75749, 77869, 80022, 82208, 84426, 86677, 88962,
91279, 93629, 96013, 98430, 100880, 103364, 105882, 108433,
111018, 113637, 116290, 118977, 121698, 124454, 127243, 130067,
132926, 135819, 138747, 141709, 144707, 147739, 150806, 153908,
157045, 160218, 163426, 166669, 169948, 173262, 176612, 179997,
183418, 186875, 190368, 193897, 197462, 201063, 204700, 208374,
212084, 215830, 219613, 223432, 227288, 231180, 235110, 239076,
243079, 247119, 251196, 255310, 259461, 263650, 267876, 272139,
276440, 280778, 285153, 289567, 294018, 298506, 303033, 307597,
312200, 316840, 321519, 326235, 330990, 335783, 340614, 345484,
350392, 355339, 360324, 365348, 370410, 375512, 380652, 385831,
391048, 396305, 401601, 406936, 412310, 417723, 423175, 428667,
434198, 439769, 445379, 451028, 456718, 462446, 468215, 474023,
479871, 485759, 491687, 497655, 503663, 509711, 515799, 521927,
528095, 534304, 540553, 546843, 553173, 559543, 565954, 572406,
578898, 585431, 592005, 598619, 605275, 611971, 618708, 625486,
632306, 639166, 646068, 653010, 659994, 667020, 674086, 681194,
688344, 695535, 702768, 710042, 717357, 724715, 732114, 739555,
747038, 754563, 762129, 769738, 777388, 785081, 792816, 800593,
808412, 816273, 824177, 832123, 840111, 848142, 856215, 864331,
872489, 880690, 888933, 897220, 905548, 913920, 922335, 930792,
939293, 947836, 956422, 965051, 973724, 982439, 991198, 1000000
};
#endif /* __DYNAMIC_AID_GAMMA_CURVE_H */

View file

@ -0,0 +1,188 @@
/*
* drivers/video/decon_7580/panels/ea8064g_lcd_ctrl.c
*
* Samsung SoC MIPI LCD CONTROL functions
*
* Copyright (c) 2015 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.
*/
#include "ea8064g_param.h"
#include <video/mipi_display.h>
#include "../dsim.h"
static int dsim_write_hl_data(u32 id, const u8 *cmd, u32 cmdSize)
{
int ret;
int retry;
retry = 5;
try_write:
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);
if (ret != 0) {
if (--retry)
goto try_write;
else
dsim_err("dsim write failed, cmd : %x\n", cmd[0]);
}
return ret;
}
void lcd_enable(void)
{
int id = 0;
int ret = 0;
dsim_info("MDD : %s was called\n", __func__);
ret = dsim_write_hl_data(id, SEQ_DISPLAY_ON, ARRAY_SIZE(SEQ_DISPLAY_ON));
if (ret < 0)
dsim_err("%s : fail to write CMD : DISPLAY_ON\n", __func__);
}
void lcd_disable(struct dsim_device *dsim)
{
/* This function needs to implement */
}
void lcd_init(struct decon_lcd *lcd)
{
int id = 0;
int ret = 0;
dsim_info("MDD : %s was called\n", __func__);
/* set_brightness */
ret = dsim_write_hl_data(id, 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__);
goto init_exit;
}
ret = dsim_write_hl_data(id, SEQ_TEST_KEY_ON_F1, ARRAY_SIZE(SEQ_TEST_KEY_ON_F1));
if (ret < 0) {
dsim_err("%s : fail to write CMD : SEQ_TEST_KEY_ON_F1\n", __func__);
goto init_exit;
}
ret = dsim_write_hl_data(id, 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__);
goto init_exit;
}
ret = dsim_write_hl_data(id, SEQ_BRIGHTNESS_1, ARRAY_SIZE(SEQ_BRIGHTNESS_1));
if (ret < 0) {
dsim_err("%s : fail to write CMD : SEQ_BRIGHTNESS_1\n", __func__);
goto init_exit;
}
ret = dsim_write_hl_data(id, SEQ_BRIGHTNESS_2, ARRAY_SIZE(SEQ_BRIGHTNESS_2));
if (ret < 0) {
dsim_err("%s : fail to write CMD : SEQ_BRIGHTNESS_2\n", __func__);
goto init_exit;
}
ret = dsim_write_hl_data(id, SEQ_BRIGHTNESS_3, ARRAY_SIZE(SEQ_BRIGHTNESS_3));
if (ret < 0) {
dsim_err("%s : fail to write CMD : SEQ_BRIGHTNESS_3\n", __func__);
goto init_exit;
}
ret = dsim_write_hl_data(id, SEQ_GAMMA_UPDATE_EA8064G, ARRAY_SIZE(SEQ_GAMMA_UPDATE_EA8064G));
if (ret < 0) {
dsim_err(":%s fail to write CMD : SEQ_GAMMA_UPDATE_EA8064G\n", __func__);
goto init_exit;
}
ret = dsim_write_hl_data(id, 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__);
goto init_exit;
}
ret = dsim_write_hl_data(id, SEQ_TEST_KEY_OFF_F1, ARRAY_SIZE(SEQ_TEST_KEY_OFF_F1));
if (ret < 0) {
dsim_err(":%s fail to write CMD : SEQ_TEST_KEY_OFF_F1\n", __func__);
goto init_exit;
}
ret = dsim_write_hl_data(id, 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__);
goto init_exit;
}
/* panel init */
ret = dsim_write_hl_data(id, 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__);
goto init_exit;
}
ret = dsim_write_hl_data(id, 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__);
goto init_exit;
}
ret = dsim_write_hl_data(id, SEQ_SLEEP_OUT, ARRAY_SIZE(SEQ_SLEEP_OUT));
if (ret < 0) {
dsim_err("%s : fail to write CMD : SEQ_SLEEP_OUT\n", __func__);
goto init_exit;
}
msleep(25);
ret = dsim_write_hl_data(id, SEQ_DCDC1_GP, ARRAY_SIZE(SEQ_DCDC1_GP));
if (ret < 0) {
dsim_err(":%s fail to write CMD : SEQ_SOURCE_CONTROL\n", __func__);
goto init_exit;
}
ret = dsim_write_hl_data(id, SEQ_DCDC1_SET, ARRAY_SIZE(SEQ_DCDC1_SET));
if (ret < 0) {
dsim_err(":%s fail to write CMD : SEQ_SOURCE_CONTROL\n", __func__);
goto init_exit;
}
ret = dsim_write_hl_data(id, SEQ_SOURCE_CONTROL, ARRAY_SIZE(SEQ_SOURCE_CONTROL));
if (ret < 0) {
dsim_err(":%s fail to write CMD : SEQ_SOURCE_CONTROL\n", __func__);
goto init_exit;
}
ret = dsim_write_hl_data(id, SEQ_PCD_CONTROL, ARRAY_SIZE(SEQ_PCD_CONTROL));
if (ret < 0) {
dsim_err(":%s fail to write CMD : SEQ_PCD_CONTROL\n", __func__);
goto init_exit;
}
ret = dsim_write_hl_data(id, 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__);
goto init_exit;
}
msleep(120);
ret = dsim_write_hl_data(id, SEQ_TE_OUT, ARRAY_SIZE(SEQ_TE_OUT));
if (ret < 0) {
dsim_err(":%s fail to write CMD : SEQ_TE_OUT\n", __func__);
goto init_exit;
}
ret = dsim_write_hl_data(id, 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__);
goto init_exit;
}
init_exit:
return;
}

View file

@ -0,0 +1,77 @@
/* drivers/video/fbdev/exynos/decon_7870/panels/ea8064g_mipi_lcd.c
*
* Samsung SoC MIPI LCD driver.
*
* Copyright (c) 2015 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.
*/
#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 backlight_device *bd;
static int ea8064g_get_brightness(struct backlight_device *bd)
{
return bd->props.brightness;
}
static int ea8064g_set_brightness(struct backlight_device *bd)
{
return 1;
}
static const struct backlight_ops ea8064g_backlight_ops = {
.get_brightness = ea8064g_get_brightness,
.update_status = ea8064g_set_brightness,
};
static int ea8064g_probe(struct dsim_device *dsim)
{
bd = backlight_device_register("pwm-backlight.0", NULL,
NULL, &ea8064g_backlight_ops, NULL);
if (IS_ERR(bd))
pr_alert("failed to register backlight device!\n");
bd->props.max_brightness = MAX_BRIGHTNESS;
bd->props.brightness = DEFAULT_BRIGHTNESS;
return 1;
}
static int ea8064g_displayon(struct dsim_device *dsim)
{
lcd_init(&dsim->lcd_info);
lcd_enable();
return 1;
}
static int ea8064g_suspend(struct dsim_device *dsim)
{
return 1;
}
static int ea8064g_resume(struct dsim_device *dsim)
{
return 1;
}
struct mipi_dsim_lcd_driver ea8064g_mipi_lcd_driver = {
.probe = ea8064g_probe,
.displayon = ea8064g_displayon,
.suspend = ea8064g_suspend,
.resume = ea8064g_resume,
};

View file

@ -0,0 +1,239 @@
/* linux/drivers/video/fbdev/exynos/decon_7870/panels/ea8064g_param.h
*
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
*
* 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 __EA8064G_PARAM_H__
#define __EA8064G_PARAM_H__
#include <linux/types.h>
#include <linux/kernel.h>
static const unsigned char SEQ_TEST_KEY_ON_F0[] = {
0xF0,
0x5A, 0x5A
};
static const unsigned char SEQ_TEST_KEY_OFF_F0[] = {
0xF0,
0xA5, 0xA5
};
static const unsigned char SEQ_TEST_KEY_ON_F1[] = {
0xF1,
0x5A, 0x5A
};
static const unsigned char SEQ_TEST_KEY_OFF_F1[] = {
0xF1,
0xA5, 0xA5
};
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_SOURCE_CONTROL[] = {
0xBA,
0x32, 0x30, 0x01
};
static const unsigned char SEQ_PCD_CONTROL[] = {
0xCC,
0x55,
};
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,
0x00, 0x00, 0x00
};
static const unsigned char SEQ_AID_SET[] = {
0xB2,
0x00, 0x0E, 0x00, 0x0E,
};
static const unsigned char SEQ_AID_SET_RevF[] = {
0xB2,
0x00, 0x06, 0x00, 0x06,
};
static const unsigned char SEQ_ELVSS_SET[] = {
0xB6,
0x98, 0x0A,
};
static const unsigned char SEQ_CAPS_ELVSS_SET[] = {
0xB6,
0x98, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x55, 0x54,
0x20, 0x00, 0x08, 0x88, 0x8F, 0x0F, 0x02, 0x11, 0x11, 0x10
};
static const unsigned char SEQ_GAMMA_UPDATE[] = {
0xF7,
0x03
};
static const unsigned char SEQ_GAMMA_UPDATE_L[] = {
0xF7,
0x00
};
static const unsigned char SEQ_GAMMA_UPDATE_EA8064G[] = {
0xF7,
0x01
};
static const unsigned char SEQ_HBM_OFF[] = {
0x53,
0x00
};
static const unsigned char SEQ_HBM_ON[] = {
0x53,
0xD0
};
static const unsigned char SEQ_ACL_SET[] = {
0x55,
0x02
};
static const unsigned char SEQ_ACL_OFF[] = {
0x55,
0x00
};
static const unsigned char SEQ_ACL_15[] = {
0x55,
0x02,
};
static const unsigned char SEQ_ACL_OFF_OPR_AVR[] = {
0xB5,
0x21
};
static const unsigned char SEQ_ACL_ON_OPR_AVR[] = {
0xB5,
0x29
};
static const unsigned char SEQ_ACL_OFF_OPR_AVR_EA8064G[] = {
0xB5,
0x21
};
static const unsigned char SEQ_ACL_ON_OPR_AVR_EA8064G[] = {
0xB5,
0x29
};
static const unsigned char SEQ_TSET_GLOBAL[] = {
0xB0,
0x05
};
static const unsigned char SEQ_TSET[] = {
0xB8,
0x19
};
static const unsigned char SEQ_TE_OUT[] = {
0x35,
0x00
};
static const unsigned char SEQ_GPARAM_TE[] = {
0xB0,
0x02
};
static const unsigned char SEQ_TE_ON_SET1[] = {
0xFD,
0x0A
};
static const unsigned char SEQ_TE_ON_SET2[] = {
0xFE,
0x80
};
static const unsigned char SEQ_TE_ON_SET3[] = {
0xFE,
0x00
};
static const unsigned char SEQ_ERR_FG[] = {
0xED,
0x01, 0x00
};
static const unsigned char SEQ_DISPLAY_ON[] = {
0x29
};
static const unsigned char SEQ_DISPLAY_OFF[] = {
0x28,
0x00, 0x00
};
static const unsigned char SEQ_SLEEP_IN[] = {
0x10,
0x00, 0x00
};
static const unsigned char SEQ_TOUCH_HSYNC_ON_RevG[] = {
0xBD,
0x05, 0x02, 0x02
};
static const unsigned char SEQ_TOUCH_HSYNC_ON[] = {
0xBD,
0x05, 0x02, 0x0C
};
static const unsigned char SEQ_DCDC1_GP[] = {
0xB0,
0x01
};
static const unsigned char SEQ_DCDC1_SET[] = {
0xB8,
0x04,
};
static const unsigned char SEQ_BRIGHTNESS_1[] = {
0xca, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x0, 0x0, 0x0,
};
static const unsigned char SEQ_BRIGHTNESS_2[] = {
0xb2, 0x0, 0xe, 0x0, 0x10,
};
static const unsigned char SEQ_BRIGHTNESS_3[] = {
0xb6, 0x5c, 0x84, 0xb8, 0x13,
};
#endif /* __EA8064G_PARAM_H__ */

View file

@ -0,0 +1,23 @@
/* 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(struct decon_lcd *lcd);
void lcd_enable(void);
void lcd_disable(void);
int lcd_gamma_ctrl(unsigned int backlightlevel);
int lcd_gamma_update(void);
#endif /* __LCD_CTRL_H__ */

View file

@ -0,0 +1,164 @@
/* s6d78a_lcd_ctrl.c
*
* Samsung SoC MIPI LCD CONTROL functions
*
* Copyright (c) 2015 Samsung Electronics
*
* Manseok Kim, <Manseoks.kim@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 "s6d78a_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
#define VIDEO_MODE 1
#define ID 0
void lcd_init(struct decon_lcd * lcd)
{
/* Initializing Sequence(1-1) */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT1_1,
ARRAY_SIZE(SEQ_INIT1_1)) == -1)
dsim_err("failed to send init_seq1_level_1_command.\n");
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT1_2,
ARRAY_SIZE(SEQ_INIT1_2)) == -1)
dsim_err("failed to send init_seq1_level_2_command.\n");
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT1_3,
ARRAY_SIZE(SEQ_INIT1_3)) == -1)
dsim_err("failed to send init_seq1_level_3_command.\n");
/* sleep out */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_SLEEP_OUT,
ARRAY_SIZE(SEQ_SLEEP_OUT)) == -1)
dsim_err("failed to send sleep_exit_command.\n");
/* 120ms delay */
msleep(120);
/* Initializing Sequence(3) */
#if 0
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT3_INT_CLK,
ARRAY_SIZE(SEQ_INIT3_INT_CLK)) == -1)
dsim_err("failed to send internal_clk_command.\n");
#endif
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT3_PAN_PROTECT,
ARRAY_SIZE(SEQ_INIT3_PAN_PROTECT)) == -1)
dsim_err("failed to send panel_protection_command.\n");
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT3_INT_POW,
ARRAY_SIZE(SEQ_INIT3_INT_POW)) == -1)
dsim_err("failed to send internal_power_seq_command.\n");
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT3_GOA,
ARRAY_SIZE(SEQ_INIT3_GOA)) == -1)
dsim_err("failed to send goa_timing_command.\n");
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT3_INT_PORCH,
ARRAY_SIZE(SEQ_INIT3_INT_PORCH)) == -1)
dsim_err("failed to send internal_porch_command.\n");
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT3_SRC_CONT,
ARRAY_SIZE(SEQ_INIT3_SRC_CONT)) == -1)
dsim_err("failed to send source_control_command.\n");
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT3_MIPI_ABNORMAL,
ARRAY_SIZE(SEQ_INIT3_MIPI_ABNORMAL)) == -1)
dsim_err("failed to send mipi_abnormal_detect_command.\n");
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT3_MIPI_AUTO_RECOVERY,
ARRAY_SIZE(SEQ_INIT3_MIPI_AUTO_RECOVERY)) == -1)
dsim_err("failed to send mipi_auto_recover_command.\n");
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT3_GOA_OUTPUT,
ARRAY_SIZE(SEQ_INIT3_GOA_OUTPUT)) == -1)
dsim_err("failed to send goa_output_command.\n");
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT3_MEM_ACC_CONT,
ARRAY_SIZE(SEQ_INIT3_MEM_ACC_CONT)) == -1)
dsim_err("failed to memory_data_access_command.\n");
/* Gamma Setting Sequence(4) */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_GAMMA_POSITIVE_CONT,
ARRAY_SIZE(SEQ_GAMMA_POSITIVE_CONT)) == -1)
dsim_err("failed to send positive_gama_control_command.\n");
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_GAMMA_NEGATIVE_CONT,
ARRAY_SIZE(SEQ_GAMMA_NEGATIVE_CONT)) == -1)
dsim_err("failed to send negative_gama_control_command.\n");
/* display_on */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_DISPLAY_ON,
ARRAY_SIZE(SEQ_DISPLAY_ON)) == -1)
dsim_err("failed to display_on_command.\n");
/* 20ms delay */
msleep(20);
/* Initializing Sequence(2) */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT2_1,
ARRAY_SIZE(SEQ_INIT2_1)) == -1)
dsim_err("failed to send init_seq2_level_1_command.\n");
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT2_2,
ARRAY_SIZE(SEQ_INIT2_2)) == -1)
dsim_err("failed to send init_seq2_level_2_command.\n");
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) SEQ_INIT2_3,
ARRAY_SIZE(SEQ_INIT2_3)) == -1)
dsim_err("failed to send init_seq2_level_3_command.\n");
}
void lcd_enable(void)
{
}
void lcd_disable(void)
{
}
int lcd_gamma_ctrl(u32 backlightlevel)
{
return 0;
}
int lcd_gamma_update(void)
{
return 0;
}

View file

@ -0,0 +1,211 @@
/* s6d78a_mipi_lcd.c
*
* Samsung SoC MIPI LCD driver.
*
* Copyright (c) 2015 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"
#include "s6d78a_param.h"
#define GAMMA_PARAM_SIZE 26
#define MAX_BRIGHTNESS 255
#define MIN_BRIGHTNESS 0
#define DEFAULT_BRIGHTNESS 0
static struct dsim_device *dsim_base;
struct backlight_device *bd;
#ifdef CONFIG_HAS_EARLYSUSPEND
static struct early_suspend s6d78a_early_suspend;
#endif
static int s6d78a_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_INFO "fail to write gamma value.\n");
if (s5p_mipi_dsi_wr_data(dsim_base, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int)gamma_update,
ARRAY_SIZE(gamma_update)) == -1)
printk(KERN_INFO "fail to update gamma value.\n");
*/
return 1;
}
static int s6d78a_set_brightness(struct backlight_device *bd)
{
int brightness = bd->props.brightness;
if (brightness < MIN_BRIGHTNESS || brightness > MAX_BRIGHTNESS) {
printk(KERN_ALERT "Brightness should be in the range of 0 ~ 255\n");
return -EINVAL;
}
update_brightness(brightness);
return 1;
}
static const struct backlight_ops s6d78a_backlight_ops = {
.get_brightness = s6d78a_get_brightness,
.update_status = s6d78a_set_brightness,
};
static int s6d78a_probe(struct dsim_device *dsim)
{
dsim_base = dsim;
bd = backlight_device_register("pwm-backlight.0", NULL,
NULL, &s6d78a_backlight_ops, NULL);
if (IS_ERR(bd))
printk(KERN_ALERT "failed to register backlight device!\n");
bd->props.max_brightness = MAX_BRIGHTNESS;
bd->props.brightness = DEFAULT_BRIGHTNESS;
return 1;
}
static int s6d78a_displayon(struct dsim_device *dsim)
{
lcd_init(&dsim->lcd_info);
return 1;
}
static int s6d78a_suspend(struct dsim_device *dsim)
{
return 1;
}
static int s6d78a_resume(struct dsim_device *dsim)
{
return 1;
}
struct mipi_dsim_lcd_driver s6d78a_mipi_lcd_driver = {
.probe = s6d78a_probe,
.displayon = s6d78a_displayon,
.suspend = s6d78a_suspend,
.resume = s6d78a_resume,
};

View file

@ -0,0 +1,185 @@
/* s6d78a_param.h
*
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
*
* Manseok Kim, <Manseoks.kim@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 __S6D78A_PARAM_H__
#define __S6D78A_PARAM_H__
/* Initializing Sequence(1) - password */
static const unsigned char SEQ_INIT1_1[3] = {
/* command */
0xF0,
/* parameter */
0x5A, 0x5A
};
static const unsigned char SEQ_INIT1_2[3] = {
/* command */
0xF1,
/* parameter */
0x5A, 0x5A
};
static const unsigned char SEQ_INIT1_3[3] = {
/* command */
0xFC,
/* parameter */
0xA5, 0xA5
};
/* Initializing Sequence(2) - password */
static const unsigned char SEQ_INIT2_1[3] = {
/* command */
0xF0,
/* parameter */
0xA5, 0xA5
};
static const unsigned char SEQ_INIT2_2[3] = {
/* command */
0xF1,
/* parameter */
0xA5, 0xA5
};
static const unsigned char SEQ_INIT2_3[3] = {
/* command */
0xFC,
/* parameter */
0x5A, 0x5A
};
/* Initializing Sequence(3) */
static const unsigned char SEQ_INIT3_INT_CLK[3] = {
/* command */
0xB1,
/* parameter */
0x93, 0x00
};
static const unsigned char SEQ_INIT3_PAN_PROTECT[3] = {
/* command */
0xB5,
/* parameter */
0x10, 0x00
};
static const unsigned char SEQ_INIT3_INT_POW[18] = {
/* command */
0xF4,
/* parameter */
0x01, 0x10, 0x32, 0x00, 0x24,
0x26, 0x28, 0x27, 0x27, 0x27,
0xB7, 0x2B, 0x2C, 0x65, 0x6A,
0x34, 0x20
};
static const unsigned char SEQ_INIT3_GOA[21] = {
/* command */
0xEF,
/* parameter */
0x01, 0x01, 0x81, 0x22, 0x83,
0x04, 0x00, 0x00, 0x00, 0x00,
0x28, 0x81, 0x00, 0x21, 0x21,
0x03, 0x03, 0x40, 0x00, 0x10,
};
static const unsigned char SEQ_INIT3_INT_PORCH[9] = {
/* command */
0xF2,
/* parameter */
0x19, 0x04, 0x08, 0x08, 0x08,
0x14, 0x14, 0x00
};
static const unsigned char SEQ_INIT3_SRC_CONT[7] = {
/* command */
0xF6,
/* parameter */
0x93, 0x23, 0x15, 0x07, 0x07,
0x0C
};
static const unsigned char SEQ_INIT3_MIPI_ABNORMAL[7] = {
/* command */
0xE1,
/* parameter */
0x01, 0xFF, 0x01, 0x1B, 0x20,
0x17
};
static const unsigned char SEQ_INIT3_MIPI_AUTO_RECOVERY[4] = {
/* command */
0xE2,
/* parameter */
0xED, 0xC7, 0x23
};
static const unsigned char SEQ_INIT3_GOA_OUTPUT[39] = {
/* command */
0xF7,
/* parameter */
0x01, 0x01, 0x0A, 0x0B, 0x05,
0x1B, 0x1A, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x08, 0x09, 0x04, 0x1B,
0x1A, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01
};
static const unsigned char SEQ_INIT3_MEM_ACC_CONT[3] = {
/* command */
0x36,
/* parameter */
0x10, 0x00
};
/* Gamma Setting Sequence(4) */
static const unsigned char SEQ_GAMMA_POSITIVE_CONT[40] = {
/* command */
0xFA,
/* parameter */
0x00, 0x19, 0x21, 0x1E, 0x14,
0x0B, 0x10, 0x0E, 0x09, 0x0B,
0x00, 0x00, 0x0A,
0x00, 0x1D, 0x21, 0x1E, 0x14,
0x0B, 0x10, 0x0E, 0x09, 0x0B,
0x00, 0x00, 0x0A,
0x00, 0x1C, 0x21, 0x1E, 0x14,
0x0B, 0x10, 0x0E, 0x09, 0x0B,
0x00, 0x00, 0x0A,
};
static const unsigned char SEQ_GAMMA_NEGATIVE_CONT[40] = {
/* command */
0xFB,
/* parameter */
0x07, 0x2D, 0x22, 0x24, 0x18,
0x0E, 0x11, 0x0C, 0x05, 0x05,
0x00, 0x00, 0x0A,
0x00, 0x29, 0x22, 0x24, 0x18,
0x0E, 0x11, 0x0C, 0x05, 0x05,
0x00, 0x00, 0x0A,
0x07, 0x2A, 0x22, 0x24, 0x18,
0x0E, 0x11, 0x0C, 0x05, 0x05,
0x00, 0x00, 0x0A,
};
static const unsigned char SEQ_SLEEP_OUT[3] = {
0x11, 0x00, 0x00
};
static const unsigned char SEQ_DISPLAY_ON[3] = {
0x29, 0x00, 0x00
};
#endif /* __S6D78A_PARAM_H__ */

View file

@ -0,0 +1,270 @@
/* 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 __S6E3FA0_GAMMA_H__
#define __S6E3FA0_GAMMA_H__
static const unsigned char gamma22_30[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xDF, 0x86, 0xF5,
0xD5, 0xC7, 0xCF, 0xDF, 0xE0, 0xE0,
0xC9, 0xC9, 0xCC, 0xD7, 0xD6, 0xD5,
0x00, 0x68, 0x00, 0x68, 0x00, 0x75,
};
static const unsigned char gamma22_40[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xE5, 0xAA, 0xF2,
0xD6, 0xCC, 0xCF, 0xE0, 0xE2, 0xE2,
0xC8, 0xC9, 0xCA, 0xD2, 0xD2, 0xCF,
0x00, 0x71, 0x00, 0x70, 0x00, 0x80,
};
static const unsigned char gamma22_50[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xE7, 0xBB, 0xEE,
0xD6, 0xCE, 0xD0, 0xE0, 0xE3, 0xE4,
0xC5, 0xC4, 0xC5, 0xD2, 0xD2, 0xCF,
0x00, 0x78, 0x00, 0x78, 0x00, 0x88,
};
static const unsigned char gamma22_60[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xE9, 0xC4, 0xEB,
0xD6, 0xD0, 0xD1, 0xE0, 0xE3, 0xE4,
0xC3, 0xC2, 0xC2, 0xD2, 0xD1, 0xCF,
0x00, 0x7E, 0x00, 0x7E, 0x00, 0x8F,
};
static const unsigned char gamma22_70[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xEA, 0xC9, 0xEA,
0xD6, 0xD2, 0xD2, 0xDF, 0xE1, 0xE3,
0xC2, 0xC1, 0xC0, 0xD1, 0xD0, 0xCE,
0x00, 0x84, 0x00, 0x84, 0x00, 0x96,
};
static const unsigned char gamma22_80[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xEB, 0xCC, 0xE9,
0xD5, 0xD4, 0xD3, 0xDE, 0xE1, 0xE2,
0xC2, 0xBF, 0xBF, 0xCF, 0xCF, 0xCC,
0x00, 0x89, 0x00, 0x89, 0x00, 0x9C,
};
static const unsigned char gamma22_90[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xEB, 0xD0, 0xE9,
0xD4, 0xD5, 0xD4, 0xDF, 0xE0, 0xE1,
0xC1, 0xBE, 0xBD, 0xCD, 0xCD, 0xCA,
0x00, 0x8E, 0x00, 0x8F, 0x00, 0xA2,
};
static const unsigned char gamma22_100[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xEA, 0xD2, 0xE7,
0xD7, 0xD6, 0xD6, 0xDF, 0xDF, 0xE2,
0xBF, 0xBD, 0xBC, 0xCD, 0xCD, 0xC9,
0x00, 0x92, 0x00, 0x93, 0x00, 0xA7,
};
static const unsigned char gamma22_110[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xEB, 0xD4, 0xE5,
0xD6, 0xD6, 0xD7, 0xDE, 0xDF, 0xE0,
0xBE, 0xBC, 0xBB, 0xCE, 0xCC, 0xC9,
0x00, 0x96, 0x00, 0x97, 0x00, 0xAC,
};
static const unsigned char gamma22_120[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xED, 0xD6, 0xE6,
0xD6, 0xD7, 0xD8, 0xDE, 0xDE, 0xE0,
0xBC, 0xBC, 0xB9, 0xCD, 0xCA, 0xC8,
0x00, 0x9A, 0x00, 0x9C, 0x00, 0xB1,
};
static const unsigned char gamma22_130[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xEC, 0xD7, 0xE6,
0xD3, 0xD8, 0xD7, 0xDE, 0xDD, 0xDF,
0xBD, 0xBB, 0xB8, 0xCA, 0xC9, 0xC6,
0x00, 0x9F, 0x00, 0xA0, 0x00, 0xB7,
};
static const unsigned char gamma22_140[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xEC, 0xD9, 0xE5,
0xD4, 0xD8, 0xD9, 0xDE, 0xDD, 0xDF,
0xBB, 0xB9, 0xB7, 0xCA, 0xC9, 0xC5,
0x00, 0xA3, 0x00, 0xA4, 0x00, 0xBB,
};
static const unsigned char gamma22_150[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xEC, 0xDA, 0xE5,
0xD4, 0xD8, 0xD9, 0xDD, 0xDD, 0xDD,
0xBB, 0xB9, 0xB6, 0xC9, 0xC7, 0xC5,
0x00, 0xA6, 0x00, 0xA8, 0x00, 0xBF,
};
static const unsigned char gamma22_160[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xED, 0xDB, 0xE6,
0xD4, 0xD7, 0xD9, 0xDC, 0xDD, 0xDD,
0xB9, 0xB8, 0xB4, 0xC9, 0xC6, 0xC4,
0x00, 0xAA, 0x00, 0xAC, 0x00, 0xC4,
};
static const unsigned char gamma22_170[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xEC, 0xDC, 0xE5,
0xD5, 0xD8, 0xD9, 0xDD, 0xDC, 0xDD,
0xBA, 0xB7, 0xB5, 0xC7, 0xC6, 0xC3,
0x00, 0xAD, 0x00, 0xAF, 0x00, 0xC7,
};
static const unsigned char gamma22_180[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xEE, 0xDD, 0xE6,
0xD4, 0xD7, 0xD9, 0xDB, 0xDC, 0xDB,
0xB9, 0xB7, 0xB4, 0xC6, 0xC4, 0xC2,
0x00, 0xB1, 0x00, 0xB3, 0x00, 0xCC,
};
static const unsigned char gamma22_190[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xED, 0xDE, 0xE6,
0xD3, 0xD8, 0xD8, 0xDD, 0xDB, 0xDC,
0xB9, 0xB6, 0xB4, 0xC5, 0xC4, 0xC0,
0x00, 0xB4, 0x00, 0xB6, 0x00, 0xD0,
};
static const unsigned char gamma22_200[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xED, 0xDF, 0xE6,
0xD3, 0xD7, 0xD8, 0xDB, 0xDB, 0xDA,
0xB8, 0xB6, 0xB3, 0xC4, 0xC3, 0xC0,
0x00, 0xB8, 0x00, 0xB9, 0x00, 0xD4,
};
static const unsigned char gamma22_210[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xEC, 0xE0, 0xE5,
0xD5, 0xD7, 0xD9, 0xDB, 0xDA, 0xDA,
0xB7, 0xB5, 0xB1, 0xC4, 0xC2, 0xC0,
0x00, 0xBA, 0x00, 0xBD, 0x00, 0xD7,
};
static const unsigned char gamma22_220[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xED, 0xE0, 0xE6,
0xD4, 0xD7, 0xD9, 0xDA, 0xDA, 0xD9,
0xB7, 0xB4, 0xB1, 0xC2, 0xC2, 0xBE,
0x00, 0xBE, 0x00, 0xC0, 0x00, 0xDC,
};
static const unsigned char gamma22_230[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xEC, 0xE2, 0xE6,
0xD3, 0xD6, 0xD8, 0xDC, 0xD9, 0xD9,
0xB6, 0xB4, 0xB1, 0xC1, 0xC1, 0xBD,
0x00, 0xC1, 0x00, 0xC3, 0x00, 0xDF,
};
static const unsigned char gamma22_240[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xED, 0xE2, 0xE6,
0xD4, 0xD6, 0xD8, 0xDA, 0xDA, 0xDA,
0xB6, 0xB3, 0xB0, 0xC1, 0xBF, 0xBC,
0x00, 0xC4, 0x00, 0xC7, 0x00, 0xE3,
};
static const unsigned char gamma22_250[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xED, 0xE3, 0xE7,
0xD4, 0xD6, 0xD8, 0xDB, 0xD9, 0xD9,
0xB3, 0xB2, 0xAE, 0xC1, 0xC0, 0xBC,
0x00, 0xC7, 0x00, 0xC9, 0x00, 0xE7,
};
static const unsigned char gamma22_260[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xED, 0xE4, 0xE7,
0xD4, 0xD5, 0xD7, 0xDA, 0xD9, 0xD9,
0xB3, 0xB2, 0xAD, 0xC1, 0xBE, 0xBC,
0x00, 0xC9, 0x00, 0xCD, 0x00, 0xEA,
};
static const unsigned char gamma22_270[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xED, 0xE5, 0xE8,
0xD3, 0xD5, 0xD5, 0xDB, 0xD9, 0xD9,
0xB3, 0xB1, 0xAE, 0xBF, 0xBE, 0xBA,
0x00, 0xCC, 0x00, 0xD0, 0x00, 0xEE,
};
static const unsigned char gamma22_280[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xEC, 0xE5, 0xE6,
0xD2, 0xD4, 0xD6, 0xDA, 0xD9, 0xD8,
0xB3, 0xB1, 0xAD, 0xBF, 0xBD, 0xBA,
0x00, 0xCF, 0x00, 0xD3, 0x00, 0xF1,
};
static const unsigned char gamma22_290[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xEC, 0xE6, 0xE7,
0xD2, 0xD4, 0xD5, 0xDB, 0xD8, 0xD8,
0xB1, 0xB0, 0xAC, 0xBE, 0xBD, 0xB9,
0x00, 0xD3, 0x00, 0xD6, 0x00, 0xF5,
};
static const unsigned char gamma22_300[] = {
0xFA, 0x01,
0x1F, 0x1F, 0x1F, 0xED, 0xE6, 0xE7,
0xD1, 0xD3, 0xD4, 0xDA, 0xD8, 0xD7,
0xB1, 0xAF, 0xAB, 0xBD, 0xBB, 0xB8,
0x00, 0xD6, 0x00, 0xDA, 0x00, 0xFA,
};
static const unsigned char *gamma22_table[] = {
gamma22_30,
gamma22_40,
gamma22_50,
gamma22_60,
gamma22_70,
gamma22_80,
gamma22_90,
gamma22_100,
gamma22_110,
gamma22_120,
gamma22_130,
gamma22_140,
gamma22_150,
gamma22_160,
gamma22_170,
gamma22_180,
gamma22_190,
gamma22_200,
gamma22_210,
gamma22_220,
gamma22_230,
gamma22_240,
gamma22_250,
gamma22_260,
gamma22_270,
gamma22_280,
gamma22_290,
};
#endif /* __S6E3FA0_GAMMA_H__ */

View file

@ -0,0 +1,237 @@
/* drivers/video/exynos/panels/s6e3fa0_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 "s6e3fa0_gamma.h"
#include "s6e3fa0_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
#define GAMMA_PARAM_SIZE 26
/* Porch values. It depends on command or video mode */
#define S6E3FA0_CMD_VBP 10
#define S6E3FA0_CMD_VFP 1
#define S6E3FA0_CMD_VSA 1
#define S6E3FA0_CMD_HBP 1
#define S6E3FA0_CMD_HFP 1
#define S6E3FA0_CMD_HSA 1
#define S6E3FA0_VIDEO_VBP 2
#define S6E3FA0_VIDEO_VFP 20
#define S6E3FA0_VIDEO_VSA 2
#define S6E3FA0_VIDEO_HBP 20
#define S6E3FA0_VIDEO_HFP 20
#define S6E3FA0_VIDEO_HSA 20
#define S6E3FA0_HORIZONTAL 1080
#define S6E3FA0_VERTICAL 1920
#ifdef FW_TEST /* This information is moved to DT */
#define CONFIG_FB_I80_COMMAND_MODE
struct decon_lcd s6e3fa0_lcd_info = {
#ifdef CONFIG_FB_I80_COMMAND_MODE
.mode = DECON_MIPI_COMMAND_MODE,
.vfp = S6E3FA0_CMD_VFP,
.vbp = S6E3FA0_CMD_VBP,
.hfp = S6E3FA0_CMD_HFP,
.hbp = S6E3FA0_CMD_HBP,
.vsa = S6E3FA0_CMD_VSA,
.hsa = S6E3FA0_CMD_HSA,
#else
.mode = DECON_VIDEO_MODE,
.vfp = S6E3FA0_VIDEO_VFP,
.vbp = S6E3FA0_VIDEO_VBP,
.hfp = S6E3FA0_VIDEO_HFP,
.hbp = S6E3FA0_VIDEO_HBP,
.vsa = S6E3FA0_VIDEO_VSA,
.hsa = S6E3FA0_VIDEO_HSA,
#endif
.xres = S6E3FA0_HORIZONTAL,
.yres = S6E3FA0_VERTICAL,
/* Maybe, width and height will be removed */
.width = 70,
.height = 121,
/* Mhz */
.hs_clk = 1100,
.esc_clk = 20,
.fps = 60,
.mic_enabled = 0,
.mic_ver = MIC_VER_1_2,
};
#endif
/*
* 3FAH0 lcd init sequence
*
* Parameters
* - mic : if mic is enabled, MIC_ENABLE command must be sent
* - mode : LCD init sequence depends on command or video mode
*/
void lcd_init(struct decon_lcd *lcd)
{
int id = 0;
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 send SEQ_TEST_KEY_ON_F0 command.\n");
msleep(12);
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
(unsigned long)SEQ_TEST_KEY_ON_F1,
ARRAY_SIZE(SEQ_TEST_KEY_ON_F1)) < 0)
dsim_err("fail to send SEQ_TEST_KEY_ON_F1 command.\n");
msleep(12);
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
(unsigned long)SEQ_TEST_KEY_ON_FC,
ARRAY_SIZE(SEQ_TEST_KEY_ON_FC)) < 0)
dsim_err("fail to send SEQ_TEST_KEY_ON_FC command.\n");
msleep(12);
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
(unsigned long)SEQ_TEST_KEY_ON_ED,
ARRAY_SIZE(SEQ_TEST_KEY_ON_ED)) < 0)
dsim_err("fail to send SEQ_TEST_KEY_ON_ED command.\n");
msleep(12);
if (lcd->mode == DECON_MIPI_COMMAND_MODE) {
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
(unsigned long)SEQ_TEST_KEY_ON_FD,
ARRAY_SIZE(SEQ_TEST_KEY_ON_FD)) < 0)
dsim_err(
"fail to send SEQ_TEST_KEY_ON_FD command.\n");
msleep(12);
if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
SEQ_TEST_KEY_ON_F6[0],
SEQ_TEST_KEY_ON_F6[1]) < 0)
dsim_err(
"fail to send SEQ_TEST_KEY_ON_F6 command.\n");
mdelay(12);
} else {
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
(unsigned long)SEQ_TEST_KEY_ON_E7,
ARRAY_SIZE(SEQ_TEST_KEY_ON_E7)) < 0)
dsim_err(
"fail to send SEQ_TEST_KEY_ON_E7 command.\n");
msleep(120);
}
if (lcd->mic_enabled)
dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
SEQ_MIC_ENABLE[0],
SEQ_MIC_ENABLE[1]);
if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
SEQ_SLEEP_OUT[0], 0) < 0)
dsim_err("fail to send SEQ_SLEEP_OUT command.\n");
mdelay(20);
if (lcd->mode == DECON_VIDEO_MODE) {
if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
SEQ_DISPLAY_ON[0], 0) < 0)
dsim_err("fail to send SEQ_DISPLAY_ON command.\n");
mdelay(120);
if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
SEQ_TEST_KEY_ON_F2[0],
SEQ_TEST_KEY_ON_F2[1]) < 0)
dsim_err(
"fail to send SEQ_TEST_KEY_ON_F2 command.\n");
mdelay(12);
}
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
(unsigned long)SEQ_TEST_KEY_ON_EB,
ARRAY_SIZE(SEQ_TEST_KEY_ON_EB)) < 0)
dsim_err("fail to send SEQ_TEST_KEY_ON_EB command.\n");
mdelay(12);
if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
(unsigned long)SEQ_TEST_KEY_ON_C0,
ARRAY_SIZE(SEQ_TEST_KEY_ON_C0)) < 0)
dsim_err("fail to send SEQ_TEST_KEY_ON_C0 command.\n");
mdelay(12);
if (lcd->mode == DECON_MIPI_COMMAND_MODE) {
if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
SEQ_TE_ON[0], 0) < 0)
dsim_err("fail to send SEQ_TE_ON command.\n");
mdelay(12);
}
}
void lcd_enable()
{
int id = 0;
if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
SEQ_DISPLAY_ON[0], 0) < 0)
dsim_err("fail to send SEQ_DISPLAY_ON command.\n");
}
void lcd_disable()
{
/* This function needs to implement */
}
/*
* Set gamma values
*
* Parameter
* - backlightlevel : It is from 0 to 26.
*/
int lcd_gamma_ctrl(u32 backlightlevel)
{
int id = 0;
int ret;
ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
(unsigned long)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 = 0;
int ret;
ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
(unsigned long)SEQ_GAMMA_UPDATE,
ARRAY_SIZE(SEQ_GAMMA_UPDATE));
if (ret) {
dsim_err("fail to update gamma value.\n");
return ret;
}
return 0;
}

View file

@ -0,0 +1,212 @@
/* drivers/video/exynos/panels/s6e3fa0_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 "s6e3fa0_param.h"
#include "lcd_ctrl.h"
#include "decon_lcd.h"
#include "../dsim.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 s6e3fa0_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 implemnt
while (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");
while (s5p_mipi_dsi_wr_data(dsim_base, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int)SEQ_GAMMA_UPDATE,
ARRAY_SIZE(SEQ_GAMMA_UPDATE)) == -1)
printk(KERN_ERR "fail to update gamma value.\n");
*/
return 0;
}
static int s6e3fa0_set_brightness(struct backlight_device *bd)
{
int brightness = bd->props.brightness;
if (brightness < MIN_BRIGHTNESS || brightness > MAX_BRIGHTNESS) {
printk(
KERN_ALERT "Brightness should be in the range of 0 ~ 255\n"
);
return -EINVAL;
}
update_brightness(brightness);
return 1;
}
static const struct backlight_ops s6e3fa0_backlight_ops = {
.get_brightness = s6e3fa0_get_brightness,
.update_status = s6e3fa0_set_brightness,
};
static int s6e3fa0_probe(struct dsim_device *dsim)
{
char bl_name[SZ_64];
dsim_base = dsim;
snprintf(bl_name, SZ_64, "pwm-backlight.%d", dsim->id);
bd = backlight_device_register(bl_name, NULL,
NULL, &s6e3fa0_backlight_ops, NULL);
if (IS_ERR(bd))
printk(KERN_ALERT "failed to register backlight device!\n");
bd->props.max_brightness = MAX_BRIGHTNESS;
bd->props.brightness = DEFAULT_BRIGHTNESS;
return 1;
}
static int s6e3fa0_displayon(struct dsim_device *dsim)
{
lcd_init(&dsim->lcd_info);
lcd_enable();
return 1;
}
static int s6e3fa0_suspend(struct dsim_device *dsim)
{
return 1;
}
static int s6e3fa0_resume(struct dsim_device *dsim)
{
return 1;
}
struct mipi_dsim_lcd_driver s6e3fa0_mipi_lcd_driver = {
.probe = s6e3fa0_probe,
.displayon = s6e3fa0_displayon,
.suspend = s6e3fa0_suspend,
.resume = s6e3fa0_resume,
};

View file

@ -0,0 +1,188 @@
/* 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 __S6E3FA0_PARAM_H__
#define __S6E3FA0_PARAM_H__
/* MIPI commands list */
static const unsigned char SEQ_TEST_KEY_ON_C0[] = {
0xc0,
0x63, 0x02, 0x03, 0x32, 0xFF, 0x44, 0x44, 0xC0, 0x00, 0x40
};
static const unsigned char SEQ_TEST_KEY_ON_EB[] = {
0xeb,
0x01, 0x00
};
static const unsigned char SEQ_TEST_KEY_ON_F2[] = {
0xf2,
0x02,
};
static const unsigned char SEQ_MIC_ENABLE[] = {
0xf9,
0x2b
};
static const unsigned char SEQ_TEST_KEY_ON_E7[] = {
0xE7,
0xED, 0xC7, 0x23, 0x57, 0xA5
};
static const unsigned char SEQ_TEST_KEY_ON_F6[] = {
0xf6,
0x08
};
static const unsigned char SEQ_TEST_KEY_ON_FD[] = {
0xfd,
0x16, 0x80
};
static const unsigned char SEQ_TEST_KEY_ON_ED[] = {
0xed,
0x01, 0x00
};
static const unsigned char SEQ_READ_ID[] = {
0x04,
0x5A, 0x5A,
};
static const unsigned char SEQ_TEST_KEY_ON_F0[] = {
0xF0,
0x5A, 0x5A,
};
static const unsigned char SEQ_TEST_KEY_ON_F1[] = {
0xF1,
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_GAMMA_CONTROL_SET_300CD[] = {
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,
0x00, 0x00, 0x00,
};
static const unsigned char SEQ_AOR_CONTROL[] = {
0xB2,
0x00, 0x06, 0x00, 0x06, 0x06, 0x06, 0x48, 0x18, 0x3F, 0xFF,
0xFF,
};
static const unsigned char SEQ_ELVSS_CONDITION_SET[] = {
0xB6,
0x88, 0x0A,
};
static const unsigned char SEQ_GAMMA_UPDATE[] = {
0xF7,
0x03, 0x00
};
static const unsigned char SEQ_SLEEP_OUT[] = {
0x11,
};
static const unsigned char SEQ_ACL_CONTROL[] = {
0xB5,
0x03, 0x98, 0x26, 0x36, 0x45,
};
static const unsigned char SEQ_ETC_PENTILE_SETTING[] = {
0xC0,
0x00, 0x02, 0x03, 0x32, 0xD8, 0x44, 0x44, 0xC0, 0x00, 0x48,
0x20, 0xD8,
};
static const unsigned char SEQ_GLOBAL_PARAM_SOURCE_AMP[] = {
0xB0,
0x24,
};
static const unsigned char SEQ_ETC_SOURCE_AMP[] = {
0xD7,
0xA5,
};
static const unsigned char SEQ_GLOBAL_PARAM_BIAS_CURRENT[] = {
0xB0,
0x1F,
};
static const unsigned char SEQ_ETC_BIAS_CURRENT[] = {
0xD7,
0x0A,
};
static const unsigned char SEQ_TE_ON[] = {
0x35,
};
static const unsigned char SEQ_DISPLAY_ON[] = {
0x29,
};
static const unsigned char SEQ_DISPLAY_OFF[] = {
0x28,
0x00, 0x00
};
static const unsigned char SEQ_SLEEP_IN[] = {
0x10,
0x00, 0x00
};
static const unsigned char SEQ_TOUCHKEY_OFF[] = {
0xFF,
0x00,
};
static const unsigned char SEQ_TOUCHKEY_ON[] = {
0xFF,
0x01,
};
static const unsigned char SEQ_ACL_OFF[] = {
0x55, 0x00,
0x00
};
static const unsigned char SEQ_ACL_40[] = {
0x55, 0x02,
0x00
};
static const unsigned char SEQ_ACL_40_RE_LOW[] = {
0x55, 0x02,
0x00
};
static const unsigned char SEQ_DISPCTL[] = {
0xF2,
0x02, 0x03, 0xC, 0xA0, 0x01, 0x48
};
#endif /* __S6E3FA0_PARAM_H__ */

View file

@ -0,0 +1,176 @@
/* s6e3ha2k_lcd_ctrl.c
*
* Samsung SoC MIPI LCD CONTROL functions
*
* Copyright (c) 2015 Samsung Electronics
*
* Manseok Kim, <Manseoks.kim@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 "s6e8aa0_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
#define VIDEO_MODE 1
#define COMMAND_MODE 0
#define ID 0
struct decon_lcd s6e8aa0_lcd_info = {
/* Only availaable VIDEO MODE */
.mode = VIDEO_MODE,
.vfp = 0x1,
.vbp = 0xD,
.hfp = 0x18,
.hbp = 0x18,
.vsa = 0x02,
.hsa = 0x02,
.xres = 800,
.yres = 1280,
.width = 71,
.height = 114,
/* Mhz */
.hs_clk = 480,
.esc_clk = 20,
.fps = 60,
};
struct decon_lcd *decon_get_lcd_info(void)
{
return &s6e8aa0_lcd_info;
}
void lcd_init(struct decon_lcd * lcd)
{
/*level1_command (to be added)*/
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) apply_level_1_key,
ARRAY_SIZE(apply_level_1_key)) == -1)
dsim_err("failed to send apply_level_1_key_command.\n");
/*level2_command*/
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) apply_level_2_key,
ARRAY_SIZE(apply_level_2_key)) == -1)
dsim_err("failed to send apply_level_2_key_command.\n");
/*sleep out */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) sleep_out,
ARRAY_SIZE(sleep_out)) == -1)
dsim_err("failed to send sleep_out_command.\n");
/*5ms delay */
msleep(5);
/*panel_condition_set */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) panel_condition_set,
ARRAY_SIZE(panel_condition_set)) == -1)
dsim_err("failed to send panel_condition_set_command.\n");
/*panel_condition_update */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) panel_condition_update,
ARRAY_SIZE(panel_condition_update)) == -1)
dsim_err("failed to send panel_condition_update_command.\n");
/*gamma_condition_set */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) gamma_condition_set,
ARRAY_SIZE(gamma_condition_set)) == -1)
dsim_err("failed to send gamma_condition_set_command.\n");
/*gamma_condition_update */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) gamma_update,
ARRAY_SIZE(gamma_update)) == -1)
dsim_err("failed to send gamma_update_command.\n");
/*source control */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) etc_set_source_ctrl,
ARRAY_SIZE(etc_set_source_ctrl)) == -1)
dsim_err("failed to etc_set_source_ctrl_command.\n");
/*pentile control */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) etc_set_pentile_ctrl,
ARRAY_SIZE(etc_set_pentile_ctrl)) == -1)
dsim_err("failed to send etc_set_pentile_ctrl_command.\n");
/*nvm setting */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) elvss_NVM_set,
ARRAY_SIZE(elvss_NVM_set)) == -1)
dsim_err("failed to send elvss_NVM_set_command.\n");
/*power control */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) etc_set_power_ctrl,
ARRAY_SIZE(etc_set_power_ctrl)) == -1)
dsim_err("failed to send etc_set_power_ctrl_command.\n");
/*dynamic elvss control */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) elvss_ctrl_set,
ARRAY_SIZE(elvss_ctrl_set)) == -1)
dsim_err("failed to send dyanmic_elvss_ctrl_set_command.\n");
/*acl control1 */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) acl_ctrl1,
ARRAY_SIZE(acl_ctrl1)) == -1)
dsim_err("failed to send acl_ctrl1_command.\n");
/*acl control2 */
while(dsim_wr_data(ID, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int) acl_ctrl2,
ARRAY_SIZE(acl_ctrl2)) == -1)
dsim_err("failed to send acl_ctrl2_command.\n");
/* 120ms delay */
msleep(120);
/* display on */
dsim_wr_data(ID, MIPI_DSI_DCS_SHORT_WRITE,
0x29, 0);
}
void lcd_enable(void)
{
}
void lcd_disable(void)
{
}
int lcd_gamma_ctrl(u32 backlightlevel)
{
return 0;
}
int lcd_gamma_update(void)
{
return 0;
}

View file

@ -0,0 +1,211 @@
/* s6e8aa0_mipi_lcd.c
*
* Samsung SoC MIPI LCD driver.
*
* Copyright (c) 2015 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"
#include "s6e8aa0_param.h"
#define GAMMA_PARAM_SIZE 26
#define MAX_BRIGHTNESS 255
#define MIN_BRIGHTNESS 0
#define DEFAULT_BRIGHTNESS 0
static struct dsim_device *dsim_base;
struct backlight_device *bd;
#ifdef CONFIG_HAS_EARLYSUSPEND
static struct early_suspend s6e8aa0_early_suspend;
#endif
static int s6e8aa0_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_INFO "fail to write gamma value.\n");
if (s5p_mipi_dsi_wr_data(dsim_base, MIPI_DSI_DCS_LONG_WRITE,
(unsigned int)gamma_update,
ARRAY_SIZE(gamma_update)) == -1)
printk(KERN_INFO "fail to update gamma value.\n");
*/
return 1;
}
static int s6e8aa0_set_brightness(struct backlight_device *bd)
{
int brightness = bd->props.brightness;
if (brightness < MIN_BRIGHTNESS || brightness > MAX_BRIGHTNESS) {
printk(KERN_ALERT "Brightness should be in the range of 0 ~ 255\n");
return -EINVAL;
}
update_brightness(brightness);
return 1;
}
static const struct backlight_ops s6e8aa0_backlight_ops = {
.get_brightness = s6e8aa0_get_brightness,
.update_status = s6e8aa0_set_brightness,
};
static int s6e8aa0_probe(struct dsim_device *dsim)
{
dsim_base = dsim;
bd = backlight_device_register("pwm-backlight.0", NULL,
NULL, &s6e8aa0_backlight_ops, NULL);
if (IS_ERR(bd))
printk(KERN_ALERT "failed to register backlight device!\n");
bd->props.max_brightness = MAX_BRIGHTNESS;
bd->props.brightness = DEFAULT_BRIGHTNESS;
return 1;
}
static int s6e8aa0_displayon(struct dsim_device *dsim)
{
lcd_init(&dsim->lcd_info);
return 1;
}
static int s6e8aa0_suspend(struct dsim_device *dsim)
{
return 1;
}
static int s6e8aa0_resume(struct dsim_device *dsim)
{
return 1;
}
struct mipi_dsim_lcd_driver s6e8aa0_mipi_lcd_driver = {
.probe = s6e8aa0_probe,
.displayon = s6e8aa0_displayon,
.suspend = s6e8aa0_suspend,
.resume = s6e8aa0_resume,
};

View file

@ -0,0 +1,93 @@
/* s6e8aa0_param.h
*
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
*
* Manseok Kim, <Manseoks.kim@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 __S6E8AA0_PARAM_H__
#define __S6E8AA0_PARAM_H__
static const unsigned char apply_level_1_key[3] = {
/* command */
0xF0,
/* parameter */
0x5A, 0x5A
};
static const unsigned char apply_level_2_key[3] = {
/* command */
0xf1,
/* parameter */
0x5a, 0x5a
};
static const unsigned char sleep_out[1] = {
0x11,
};
static const unsigned char panel_condition_set[39] = {
0xF8,
0x3D, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3C, 0x7D, 0x08,
0x27, 0x7D, 0x3F, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08, 0x6E,
0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xC0, 0xC8,
0x08, 0x48, 0xC1, 0x00, 0xC1, 0xFF, 0xFF, 0xC8
};
static const unsigned char panel_condition_update[4] = {
0xF2, 0x80, 0x03, 0x0D
};
static const unsigned char gamma_condition_set[26] = {
0xFA,
0x01, 0x46, 0x46, 0x46, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
0xBE, 0x00, 0xBE, 0x00, 0xBE
};
static const unsigned char gamma_update[2] = {
0xF7,0x03
};
static const unsigned char etc_set_source_ctrl[3] = {
0xF6,0x00, 0x02
};
static const unsigned char etc_set_pentile_ctrl[10] = {
0xB6,
0x0C, 0x02, 0x03, 0x32, 0xFF, 0x44, 0x44, 0xC0, 0x00
};
static const unsigned char elvss_NVM_set[15] = {
0xD9,
0x14, 0x40, 0x0C, 0xCB, 0xCE, 0x6E, 0xC4, 0x07, 0x40, 0x41,
0xCB, 0x00, 0x60, 0x19
};
static const unsigned char etc_set_power_ctrl[8] = {
0xF4,
0xCF, 0x0A, 0x12, 0x10, 0x1E, 0x33, 0x02
};
static const unsigned char elvss_ctrl_set[3] = {
0xB1, 0x04, 0x95
};
static const unsigned char acl_ctrl1[2] = {
0xC0, 0x01
};
static const unsigned char acl_ctrl2[28] = {
0x47, 0x53, 0x13, 0x53, 0x00,
0x00, 0x02, 0xCF, 0x00, 0x00,
0x04, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x09, 0x10,
0x18, 0x1F, 0x27, 0x2E, 0x36,
0x3D, 0x45, 0x4C
};
#endif /* __S6E8AA0_PARAM_H__ */

View file

@ -0,0 +1,252 @@
/*
* drivers/video/fbdev/exynos/decon_7870/regs-decon.h
*
* Register definition file for Samsung DECON driver
*
* Copyright (c) 2015 Samsung Electronics
* Jiun Yu <jiun.yu@samsung.com>
* Shaik Ameer Basha <shaik.ameer@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_DECON_H
#define _REGS_DECON_H
#define VIDCON0 0x0000
#define VIDCON0_SWRESET (1 << 28)
#define VIDCON0_DECON_STOP_STATUS (1 << 2)
#define VIDCON0_ENVID (1 << 1)
#define VIDCON0_ENVID_F (1 << 0)
#define VIDOUTCON0 0x0004
#define VIDOUTCON0_LCD_ON_F (0x1 << 24)
#define VIDOUTCON0_IF_MASK (0x1 << 23)
#define VIDOUTCON0_RGBIF_F (0x0 << 23)
#define VIDOUTCON0_I80IF_F (0x1 << 23)
#define VCLKCON0 0x0010
#define ECLK_IDLE_GATE_EN (1 << 12)
#define VCLKCON0_CLKVALUP (1 << 8)
#define VCLKCON0_VLCKFREE (1 << 0)
#define VCLKCON1 (0x0014)
#define VCLKCON2 (0x0018)
#define VCLKCON_CLKVAL_F(_v) ((_v) << 16)
#define VCLKCON_CLKVAL_F_MASK (0xff << 16)
#define SHADOWCON 0x0030
#define SHADOWCON_WIN_PROTECT(_win) (1 << (8 + (_win)))
#define SHADOWCON_AUTO_PROTECT (1 << 0)
#define WINCHMAP0 0x0040
#define WINCHMAP_MASK(_win) (0x7 << ((_win) * 4))
#define WINCHMAP_DMA(_v, _win) ((_v) << ((_win) * 4))
#define WINCHMAP0_W5CHMAP_F(_v) ((_v) << 20)
#define WINCHMAP0_W5CHMAP_F_MASK (0x7 << 20)
#define WINCHMAP0_W4CHMAP_F(_v) ((_v) << 16)
#define WINCHMAP0_W4CHMAP_F_MASK (0x7 << 16)
#define WINCHMAP0_W3CHMAP_F(_v) ((_v) << 12)
#define WINCHMAP0_W3CHMAP_F_MASK (0x7 << 12)
#define WINCHMAP0_W2CHMAP_F(_v) ((_v) << 8)
#define WINCHMAP0_W2CHMAP_F_MASK (0x7 << 8)
#define WINCHMAP0_W1CHMAP_F(_v) ((_v) << 4)
#define WINCHMAP0_W1CHMAP_F_MASK (0x7 << 4)
#define WINCHMAP0_W0CHMAP_F(_v) ((_v) << 0)
#define WINCHMAP0_W0CHMAP_F_MASK (0x7 << 0)
#define WINCON(_win) (0x0050 + ((_win) * 4))
#define WINCON_RESET_VALUE (0x0001E000)
#define WINCON_RGB_TYPE_BT601W (0 << 26)
#define WINCON_RGB_TYPE_BT601N (1 << 26)
#define WINCON_RGB_TYPE_BT709W (2 << 26)
#define WINCON_RGB_TYPE_BT709N (3 << 26)
#define WINCON_BLK_EN_F (1 << 23)
#define WINCON_OUTSTAND_MAX_DEFAULT (0xF)
#define WINCON_OUTSTAND_MAX_POS (13)
#define WINCON_OUTSTAND_MAX_MASK (0x1F << 13)
#define WINCON_BURSTLEN_16WORD (0x0 << 10)
#define WINCON_BURSTLEN_8WORD (0x1 << 10)
#define WINCON_BURSTLEN_4WORD (0x2 << 10)
#define WINCON_INTERPOLATION_EN (1 << 9)
#define WINCON_BLD_PLANE (0 << 8)
#define WINCON_BLD_PIX (1 << 8)
#define WINCON_ALPHA_MUL (1 << 7)
#define WINCON_BPPMODE_ARGB8888 (0x0 << 2)
#define WINCON_BPPMODE_ABGR8888 (0x1 << 2)
#define WINCON_BPPMODE_RGBA8888 (0x2 << 2)
#define WINCON_BPPMODE_BGRA8888 (0x3 << 2)
#define WINCON_BPPMODE_XRGB8888 (0x4 << 2)
#define WINCON_BPPMODE_XBGR8888 (0x5 << 2)
#define WINCON_BPPMODE_RGBX8888 (0x6 << 2)
#define WINCON_BPPMODE_BGRX8888 (0x7 << 2)
#define WINCON_BPPMODE_RGB565 (0x8 << 2)
/*
* Todo: both formats are working but if 0x18 is passed for NV21
* and 0x19 is passed as NV12. This information is reversed in
* user manual. Need to check with Hardware team.
*/
#define WINCON_BPPMODE_NV21 (0x18 << 2)
#define WINCON_BPPMODE_NV12 (0x19 << 2)
#define WINCON_ALPHA_SEL (1 << 1)
#define WINCON_ENWIN (1 << 0)
#define VIDW_ADD0(_win) (0x0880 + ((_win) * 0x10))
#define VIDW_ADD2(_win) (0x1020 + ((_win) * 0x20))
#define VIDW_ADD3(_win) (0x1030 + ((_win) * 0x20))
#define VIDW_WHOLE_X(_win) (0x0130 + ((_win) * 8))
#define VIDW_WHOLE_Y(_win) (0x0134 + ((_win) * 8))
#define VIDW_OFFSET_X(_win) (0x0170 + ((_win) * 8))
#define VIDW_OFFSET_Y(_win) (0x0174 + ((_win) * 8))
#define VIDW_BLKOFFSET(_win) (0x01B0 + ((_win) * 4))
#define VIDW_BLKSIZE(_win) (0x0200 + ((_win) * 4))
#define VIDW_BLKOFFSET_Y_F(_v) (((_v) & 0x1fff) << 13)
#define VIDW_BLKOFFSET_X_F(_v) ((_v) & 0x1fff)
#define VIDW_BLKOFFSET_MASK (0x3ffffff)
#define VIDW_BLKSIZE_MASK (0x3ffffff)
#define VIDW_BLKSIZE_H_F(_v) (((_v) & 0x1fff) << 13)
#define VIDW_BLKSIZE_W_F(_v) ((_v) & 0x1fff)
#define VIDOSD_A(_win) (0x0230 + ((_win) * 0x20))
#define VIDOSD_A_TOPLEFT_X(_v) (((_v) & 0x1fff) << 13)
#define VIDOSD_A_TOPLEFT_Y(_v) (((_v) & 0x1fff) << 0)
#define VIDOSD_B(_win) (0x0234 + ((_win) * 0x20))
#define VIDOSD_B_BOTRIGHT_X(_v) (((_v) & 0x1fff) << 13)
#define VIDOSD_B_BOTRIGHT_Y(_v) (((_v) & 0x1fff) << 0)
#define VIDOSD_C(_win) (0x0238 + ((_win) * 0x20))
#define VIDOSD_C_ALPHA0_R_F(_v) (((_v) & 0xFF) << 16)
#define VIDOSD_C_ALPHA0_G_F(_v) (((_v) & 0xFF) << 8)
#define VIDOSD_C_ALPHA0_B_F(_v) (((_v) & 0xFF) << 0)
#define VIDOSD_D(_win) (0x023C + ((_win) * 0x20))
#define VIDOSD_D_ALPHA1_R_F(_v) (((_v) & 0xFF) << 16)
#define VIDOSD_D_ALPHA1_G_F(_v) (((_v) & 0xFF) << 8)
#define VIDOSD_D_ALPHA1_B_F(_v) (((_v) & 0xFF) >> 0)
#define WIN_MAP(_win) (0x0340 + ((_win) * 4))
#define WIN_MAP_MAP (1 << 24)
#define WIN_MAP_MAP_COLOUR(_v) ((_v) << 0)
#define WIN_MAP_MAP_COLOUR_MASK (0xffffff << 0)
#define W_KEYCON0(_win) (0x0370 + ((_win) * 8))
#define W_KEYCON1(_win) (0x0374 + ((_win) * 8))
#define W_KEYALPHA(_win) (0x03A0 + ((_win) * 4))
#define BLENDE(_win) (0x03C0 + ((_win) * 4))
#define BLENDE_COEF_ZERO 0x0
#define BLENDE_COEF_ONE 0x1
#define BLENDE_COEF_ALPHA_A 0x2
#define BLENDE_COEF_ONE_MINUS_ALPHA_A 0x3
#define BLENDE_COEF_ALPHA_B 0x4
#define BLENDE_COEF_ONE_MINUS_ALPHA_B 0x5
#define BLENDE_COEF_ALPHA0 0x6
#define BLENDE_COEF_A 0xA
#define BLENDE_COEF_ONE_MINUS_A 0xB
#define BLENDE_COEF_B 0xC
#define BLENDE_COEF_ONE_MINUS_B 0xD
#define BLENDE_Q_FUNC(_v) ((_v) << 18)
#define BLENDE_P_FUNC(_v) ((_v) << 12)
#define BLENDE_B_FUNC(_v) ((_v) << 6)
#define BLENDE_A_FUNC(_v) ((_v) << 0)
#define BLENDCON 0x03D8
#define BLENDCON_NEW_8BIT_ALPHA_VALUE (1 << 0)
#define BLENDCON_NEW_4BIT_ALPHA_VALUE (0 << 0)
#define VIDINTCON0 0x0500
#define VIDINTCON0_INT_EXTRA_EN (1 << 21)
#define VIDINTCON0_INT_I80_EN (1 << 17)
#define VIDINTCON0_FRAMESEL0_BACKPORCH (0x0 << 15)
#define VIDINTCON0_FRAMESEL0_VSYNC (0x1 << 15)
#define VIDINTCON0_FRAMESEL0_ACTIVE (0x2 << 15)
#define VIDINTCON0_FRAMESEL0_FRONTPORCH (0x3 << 15)
#define VIDINTCON0_INT_FRAME (1 << 11)
#define VIDINTCON0_FIFOLEVEL_EMPTY (0x0 << 3)
#define VIDINTCON0_FIFOLEVEL_TO25PC (0x1 << 3)
#define VIDINTCON0_FIFOLEVEL_TO50PC (0x2 << 3)
#define VIDINTCON0_FIFOLEVEL_FULL (0x4 << 3)
#define VIDINTCON0_INT_FIFO (1 << 1)
#define VIDINTCON0_INT_ENABLE (1 << 0)
#define VIDINTCON1 0x0504
#define VIDINTCON1_FIFOEP_TH_SHIFT 10
#define VIDINTCON1_INT_DPU1 (1 << 5)
#define VIDINTCON1_INT_DPU0 (1 << 4)
#define VIDINTCON1_INT_EXTRA (1 << 3)
#define VIDINTCON1_INT_I80 (1 << 2)
#define VIDINTCON1_INT_FRAME (1 << 1)
#define VIDINTCON1_INT_FIFO (1 << 0)
#define FRAMEFIFO_REG7 0x052C
#define FRAMEFIFO_FIFO0_VALID_SIZE_GET(_v) (((_v) >> 13) & 0x1fff)
#define VIDCON1(_x) (0x0600 + ((_x) * 0x50))
#define VIDCON1_LINECNT_GET(_v) (((_v) >> 17) & 0x1fff)
#define VIDCON1_VSTATUS_MASK (0x7 << 13)
#define VIDCON1_VSTATUS_IDLE (0x0 << 13)
#define VIDCON1_VSTATUS_VSYNC (0x1 << 13)
#define VIDCON1_VSTATUS_BACKPORCH (0x2 << 13)
#define VIDCON1_VSTATUS_ACTIVE (0x3 << 13)
#define VIDCON1_VSTATUS_FRONTPORCH (0x4 << 13)
#define VIDCON1_VCLK_MASK (0x3 << 9)
#define VIDCON1_VCLK_HOLD (0x0 << 9)
#define VIDCON1_VCLK_RUN (0x1 << 9)
#define VIDCON1_VCLK_RUN_VDEN_DISABLE (0x3 << 9)
#define VIDCON1_RGB_ORDER_O_MASK (0x7 << 4)
#define VIDCON1_RGB_ORDER_O_RGB (0x0 << 4)
#define VIDCON1_RGB_ORDER_O_GBR (0x1 << 4)
#define VIDCON1_RGB_ORDER_O_BRG (0x2 << 4)
#define VIDCON1_RGB_ORDER_O_BGR (0x4 << 4)
#define VIDCON1_RGB_ORDER_O_RBG (0x5 << 4)
#define VIDCON1_RGB_ORDER_O_GRB (0x6 << 4)
#define VIDTCON0(_x) (0x0610 + ((_x) * 0x50))
#define VIDTCON0_VBPD(_v) ((_v) << 16)
#define VIDTCON0_VFPD(_v) ((_v) << 0)
#define VIDTCON1(_x) (0x0614 + ((_x) * 0x50))
#define VIDTCON1_VSPW(_v) ((_v) << 16)
#define VIDTCON2(_x) (0x0618 + ((_x) * 0x50))
#define VIDTCON2_HBPD(_v) ((_v) << 16)
#define VIDTCON2_HFPD(_v) ((_v) << 0)
#define VIDTCON3(_x) (0x061C + ((_x) * 0x50))
#define VIDTCON3_HSPW(_v) ((_v) << 16)
#define VIDTCON4(_x) (0x0620 + ((_x) * 0x50))
#define VIDTCON4_LINEVAL(_v) (((_v) & 0x1fff) << 16)
#define VIDTCON4_HOZVAL(_v) (((_v) & 0x1fff) << 0)
#define VIDTCONx_LINEVAL_GET(_v) (((_v) >> 16) & 0x1fff)
#define VIDTCONx_HOZVAL_GET(_v) (((_v) >> 0) & 0x1fff)
#define LINECNT_OP_THRESHOLD(_x) (0x0630 + ((_x) * 0x50))
#define TRIGCON 0x06B0
#define TRIGCON_TRIG_SAVE_DISABLE_SYNCMGR (1 << 13)
#define TRIGCON_HWTRIG_AUTO_MASK (1 << 6)
#define TRIGCON_HWTRIGMASK_DISPIF0 (1 << 4)
#define TRIGCON_HWTRIGEN_I80_RGB (1 << 3)
#define TRIGCON_HWTRIG_INV_I80_RGB (1 << 2)
#define TRIGCON_SWTRIGCMD_I80_RGB (1 << 1)
#define TRIGCON_SWTRIGEN_I80_RGB (1 << 0)
#define CRCRDATA_E 0x06C0
#define CRCRDATA_V 0x06C4
#define CRCCTRL 0x06C8
#define CRCCTRL_CRCCLKEN (0x1 << 2)
#define CRCCTRL_CRCSTART_F (0x1 << 1)
#define CRCCTRL_CRCEN (0x1 << 0)
#define DECON_UPDATE 0x0710
#define DECON_UPDATE_STANDALONE_F (1 << 0)
/* TBD: Registers for Debugging features to be added */
#endif /* _REGS_DECON_H */

View file

@ -0,0 +1,304 @@
/* 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>
* Shaik Ameer Basha <shaik.ameer@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,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__ */

Some files were not shown because too many files have changed in this diff Show more