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,100 @@
config DRM_EXYNOS
tristate "DRM Support for Samsung SoC EXYNOS Series"
depends on OF && DRM && (PLAT_SAMSUNG || ARCH_MULTIPLATFORM)
select DRM_KMS_HELPER
select DRM_KMS_FB_HELPER
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
select VIDEOMODE_HELPERS
help
Choose this option if you have a Samsung SoC EXYNOS chipset.
If M is selected the module will be called exynosdrm.
config DRM_EXYNOS_IOMMU
bool "EXYNOS DRM IOMMU Support"
depends on DRM_EXYNOS && EXYNOS_IOMMU && ARM_DMA_USE_IOMMU
help
Choose this option if you want to use IOMMU feature for DRM.
config DRM_EXYNOS_DMABUF
bool "EXYNOS DRM DMABUF"
depends on DRM_EXYNOS
help
Choose this option if you want to use DMABUF feature for DRM.
config DRM_EXYNOS_FIMD
bool "Exynos DRM FIMD"
depends on DRM_EXYNOS && !FB_S3C
select FB_MODE_HELPERS
select MFD_SYSCON
help
Choose this option if you want to use Exynos FIMD for DRM.
config DRM_EXYNOS_DPI
bool "EXYNOS DRM parallel output support"
depends on DRM_EXYNOS_FIMD
select DRM_PANEL
default n
help
This enables support for Exynos parallel output.
config DRM_EXYNOS_DSI
bool "EXYNOS DRM MIPI-DSI driver support"
depends on DRM_EXYNOS_FIMD
select DRM_MIPI_DSI
select DRM_PANEL
default n
help
This enables support for Exynos MIPI-DSI device.
config DRM_EXYNOS_DP
bool "EXYNOS DRM DP driver support"
depends on DRM_EXYNOS_FIMD && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
default DRM_EXYNOS
select DRM_PANEL
help
This enables support for DP device.
config DRM_EXYNOS_HDMI
bool "Exynos DRM HDMI"
depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV
help
Choose this option if you want to use Exynos HDMI for DRM.
config DRM_EXYNOS_VIDI
bool "Exynos DRM Virtual Display"
depends on DRM_EXYNOS
help
Choose this option if you want to use Exynos VIDI for DRM.
config DRM_EXYNOS_G2D
bool "Exynos DRM G2D"
depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D
help
Choose this option if you want to use Exynos G2D for DRM.
config DRM_EXYNOS_IPP
bool "Exynos DRM IPP"
depends on DRM_EXYNOS
help
Choose this option if you want to use IPP feature for DRM.
config DRM_EXYNOS_FIMC
bool "Exynos DRM FIMC"
depends on DRM_EXYNOS_IPP && MFD_SYSCON
help
Choose this option if you want to use Exynos FIMC for DRM.
config DRM_EXYNOS_ROTATOR
bool "Exynos DRM Rotator"
depends on DRM_EXYNOS_IPP
help
Choose this option if you want to use Exynos Rotator for DRM.
config DRM_EXYNOS_GSC
bool "Exynos DRM GSC"
depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && !ARCH_MULTIPLATFORM
help
Choose this option if you want to use Exynos GSC for DRM.

View file

@ -0,0 +1,25 @@
#
# Makefile for the drm device driver. This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos
exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o \
exynos_drm_crtc.o exynos_drm_fbdev.o exynos_drm_fb.o \
exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \
exynos_drm_plane.o
exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
exynosdrm-$(CONFIG_DRM_EXYNOS_DPI) += exynos_drm_dpi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_DSI) += exynos_drm_dsi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o
exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o
exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o
exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMC) += exynos_drm_fimc.o
exynosdrm-$(CONFIG_DRM_EXYNOS_ROTATOR) += exynos_drm_rotator.o
exynosdrm-$(CONFIG_DRM_EXYNOS_GSC) += exynos_drm_gsc.o
obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,280 @@
/*
* Header file for Samsung DP (Display Port) interface driver.
*
* Copyright (C) 2012 Samsung Electronics Co., Ltd.
* Author: Jingoo Han <jg1.han@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DP_CORE_H
#define _EXYNOS_DP_CORE_H
#include <drm/drm_crtc.h>
#include <drm/drm_dp_helper.h>
#include <drm/exynos_drm.h>
#define DP_TIMEOUT_LOOP_COUNT 100
#define MAX_CR_LOOP 5
#define MAX_EQ_LOOP 5
enum link_rate_type {
LINK_RATE_1_62GBPS = 0x06,
LINK_RATE_2_70GBPS = 0x0a
};
enum link_lane_count_type {
LANE_COUNT1 = 1,
LANE_COUNT2 = 2,
LANE_COUNT4 = 4
};
enum link_training_state {
START,
CLOCK_RECOVERY,
EQUALIZER_TRAINING,
FINISHED,
FAILED
};
enum voltage_swing_level {
VOLTAGE_LEVEL_0,
VOLTAGE_LEVEL_1,
VOLTAGE_LEVEL_2,
VOLTAGE_LEVEL_3,
};
enum pre_emphasis_level {
PRE_EMPHASIS_LEVEL_0,
PRE_EMPHASIS_LEVEL_1,
PRE_EMPHASIS_LEVEL_2,
PRE_EMPHASIS_LEVEL_3,
};
enum pattern_set {
PRBS7,
D10_2,
TRAINING_PTN1,
TRAINING_PTN2,
DP_NONE
};
enum color_space {
COLOR_RGB,
COLOR_YCBCR422,
COLOR_YCBCR444
};
enum color_depth {
COLOR_6,
COLOR_8,
COLOR_10,
COLOR_12
};
enum color_coefficient {
COLOR_YCBCR601,
COLOR_YCBCR709
};
enum dynamic_range {
VESA,
CEA
};
enum pll_status {
PLL_UNLOCKED,
PLL_LOCKED
};
enum clock_recovery_m_value_type {
CALCULATED_M,
REGISTER_M
};
enum video_timing_recognition_type {
VIDEO_TIMING_FROM_CAPTURE,
VIDEO_TIMING_FROM_REGISTER
};
enum analog_power_block {
AUX_BLOCK,
CH0_BLOCK,
CH1_BLOCK,
CH2_BLOCK,
CH3_BLOCK,
ANALOG_TOTAL,
POWER_ALL
};
enum dp_irq_type {
DP_IRQ_TYPE_HP_CABLE_IN,
DP_IRQ_TYPE_HP_CABLE_OUT,
DP_IRQ_TYPE_HP_CHANGE,
DP_IRQ_TYPE_UNKNOWN,
};
struct video_info {
char *name;
bool h_sync_polarity;
bool v_sync_polarity;
bool interlaced;
enum color_space color_space;
enum dynamic_range dynamic_range;
enum color_coefficient ycbcr_coeff;
enum color_depth color_depth;
enum link_rate_type link_rate;
enum link_lane_count_type lane_count;
};
struct link_train {
int eq_loop;
int cr_loop[4];
u8 link_rate;
u8 lane_count;
u8 training_lane[4];
enum link_training_state lt_state;
};
struct exynos_dp_device {
struct device *dev;
struct drm_device *drm_dev;
struct drm_connector connector;
struct drm_encoder *encoder;
struct drm_panel *panel;
struct clk *clock;
unsigned int irq;
void __iomem *reg_base;
void __iomem *phy_addr;
unsigned int enable_mask;
struct video_info *video_info;
struct link_train link_train;
struct work_struct hotplug_work;
struct phy *phy;
int dpms_mode;
int hpd_gpio;
struct exynos_drm_panel_info priv;
};
/* exynos_dp_reg.c */
void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable);
void exynos_dp_stop_video(struct exynos_dp_device *dp);
void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable);
void exynos_dp_init_analog_param(struct exynos_dp_device *dp);
void exynos_dp_init_interrupt(struct exynos_dp_device *dp);
void exynos_dp_reset(struct exynos_dp_device *dp);
void exynos_dp_swreset(struct exynos_dp_device *dp);
void exynos_dp_config_interrupt(struct exynos_dp_device *dp);
enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp);
void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable);
void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
enum analog_power_block block,
bool enable);
void exynos_dp_init_analog_func(struct exynos_dp_device *dp);
void exynos_dp_init_hpd(struct exynos_dp_device *dp);
enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp);
void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp);
void exynos_dp_reset_aux(struct exynos_dp_device *dp);
void exynos_dp_init_aux(struct exynos_dp_device *dp);
int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp);
void exynos_dp_enable_sw_function(struct exynos_dp_device *dp);
int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp);
int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
unsigned int reg_addr,
unsigned char data);
int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
unsigned int reg_addr,
unsigned char *data);
int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
unsigned int reg_addr,
unsigned int count,
unsigned char data[]);
int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
unsigned int reg_addr,
unsigned int count,
unsigned char data[]);
int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
unsigned int device_addr,
unsigned int reg_addr);
int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
unsigned int device_addr,
unsigned int reg_addr,
unsigned int *data);
int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
unsigned int device_addr,
unsigned int reg_addr,
unsigned int count,
unsigned char edid[]);
void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype);
void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype);
void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count);
void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count);
void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable);
void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
enum pattern_set pattern);
void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level);
void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level);
void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level);
void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level);
void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
u32 training_lane);
void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
u32 training_lane);
void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
u32 training_lane);
void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
u32 training_lane);
u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp);
u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp);
u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp);
u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp);
void exynos_dp_reset_macro(struct exynos_dp_device *dp);
void exynos_dp_init_video(struct exynos_dp_device *dp);
void exynos_dp_set_video_color_format(struct exynos_dp_device *dp);
int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp);
void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
enum clock_recovery_m_value_type type,
u32 m_value,
u32 n_value);
void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type);
void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable);
void exynos_dp_start_video(struct exynos_dp_device *dp);
int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp);
void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp);
void exynos_dp_enable_scrambling(struct exynos_dp_device *dp);
void exynos_dp_disable_scrambling(struct exynos_dp_device *dp);
/* I2C EDID Chip ID, Slave Address */
#define I2C_EDID_DEVICE_ADDR 0x50
#define I2C_E_EDID_DEVICE_ADDR 0x30
#define EDID_BLOCK_LENGTH 0x80
#define EDID_HEADER_PATTERN 0x00
#define EDID_EXTENSION_FLAG 0x7e
#define EDID_CHECKSUM 0x7f
/* DP_MAX_LANE_COUNT */
#define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
#define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f)
/* DP_LANE_COUNT_SET */
#define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f)
/* DP_TRAINING_LANE0_SET */
#define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3)
#define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3)
#define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0)
#define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3)
#endif /* _EXYNOS_DP_CORE_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,366 @@
/*
* Register definition file for Samsung DP driver
*
* Copyright (C) 2012 Samsung Electronics Co., Ltd.
* Author: Jingoo Han <jg1.han@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 _EXYNOS_DP_REG_H
#define _EXYNOS_DP_REG_H
#define EXYNOS_DP_TX_SW_RESET 0x14
#define EXYNOS_DP_FUNC_EN_1 0x18
#define EXYNOS_DP_FUNC_EN_2 0x1C
#define EXYNOS_DP_VIDEO_CTL_1 0x20
#define EXYNOS_DP_VIDEO_CTL_2 0x24
#define EXYNOS_DP_VIDEO_CTL_3 0x28
#define EXYNOS_DP_VIDEO_CTL_8 0x3C
#define EXYNOS_DP_VIDEO_CTL_10 0x44
#define EXYNOS_DP_LANE_MAP 0x35C
#define EXYNOS_DP_ANALOG_CTL_1 0x370
#define EXYNOS_DP_ANALOG_CTL_2 0x374
#define EXYNOS_DP_ANALOG_CTL_3 0x378
#define EXYNOS_DP_PLL_FILTER_CTL_1 0x37C
#define EXYNOS_DP_TX_AMP_TUNING_CTL 0x380
#define EXYNOS_DP_AUX_HW_RETRY_CTL 0x390
#define EXYNOS_DP_COMMON_INT_STA_1 0x3C4
#define EXYNOS_DP_COMMON_INT_STA_2 0x3C8
#define EXYNOS_DP_COMMON_INT_STA_3 0x3CC
#define EXYNOS_DP_COMMON_INT_STA_4 0x3D0
#define EXYNOS_DP_INT_STA 0x3DC
#define EXYNOS_DP_COMMON_INT_MASK_1 0x3E0
#define EXYNOS_DP_COMMON_INT_MASK_2 0x3E4
#define EXYNOS_DP_COMMON_INT_MASK_3 0x3E8
#define EXYNOS_DP_COMMON_INT_MASK_4 0x3EC
#define EXYNOS_DP_INT_STA_MASK 0x3F8
#define EXYNOS_DP_INT_CTL 0x3FC
#define EXYNOS_DP_SYS_CTL_1 0x600
#define EXYNOS_DP_SYS_CTL_2 0x604
#define EXYNOS_DP_SYS_CTL_3 0x608
#define EXYNOS_DP_SYS_CTL_4 0x60C
#define EXYNOS_DP_PKT_SEND_CTL 0x640
#define EXYNOS_DP_HDCP_CTL 0x648
#define EXYNOS_DP_LINK_BW_SET 0x680
#define EXYNOS_DP_LANE_COUNT_SET 0x684
#define EXYNOS_DP_TRAINING_PTN_SET 0x688
#define EXYNOS_DP_LN0_LINK_TRAINING_CTL 0x68C
#define EXYNOS_DP_LN1_LINK_TRAINING_CTL 0x690
#define EXYNOS_DP_LN2_LINK_TRAINING_CTL 0x694
#define EXYNOS_DP_LN3_LINK_TRAINING_CTL 0x698
#define EXYNOS_DP_DEBUG_CTL 0x6C0
#define EXYNOS_DP_HPD_DEGLITCH_L 0x6C4
#define EXYNOS_DP_HPD_DEGLITCH_H 0x6C8
#define EXYNOS_DP_LINK_DEBUG_CTL 0x6E0
#define EXYNOS_DP_M_VID_0 0x700
#define EXYNOS_DP_M_VID_1 0x704
#define EXYNOS_DP_M_VID_2 0x708
#define EXYNOS_DP_N_VID_0 0x70C
#define EXYNOS_DP_N_VID_1 0x710
#define EXYNOS_DP_N_VID_2 0x714
#define EXYNOS_DP_PLL_CTL 0x71C
#define EXYNOS_DP_PHY_PD 0x720
#define EXYNOS_DP_PHY_TEST 0x724
#define EXYNOS_DP_VIDEO_FIFO_THRD 0x730
#define EXYNOS_DP_AUDIO_MARGIN 0x73C
#define EXYNOS_DP_M_VID_GEN_FILTER_TH 0x764
#define EXYNOS_DP_M_AUD_GEN_FILTER_TH 0x778
#define EXYNOS_DP_AUX_CH_STA 0x780
#define EXYNOS_DP_AUX_CH_DEFER_CTL 0x788
#define EXYNOS_DP_AUX_RX_COMM 0x78C
#define EXYNOS_DP_BUFFER_DATA_CTL 0x790
#define EXYNOS_DP_AUX_CH_CTL_1 0x794
#define EXYNOS_DP_AUX_ADDR_7_0 0x798
#define EXYNOS_DP_AUX_ADDR_15_8 0x79C
#define EXYNOS_DP_AUX_ADDR_19_16 0x7A0
#define EXYNOS_DP_AUX_CH_CTL_2 0x7A4
#define EXYNOS_DP_BUF_DATA_0 0x7C0
#define EXYNOS_DP_SOC_GENERAL_CTL 0x800
/* EXYNOS_DP_TX_SW_RESET */
#define RESET_DP_TX (0x1 << 0)
/* EXYNOS_DP_FUNC_EN_1 */
#define MASTER_VID_FUNC_EN_N (0x1 << 7)
#define SLAVE_VID_FUNC_EN_N (0x1 << 5)
#define AUD_FIFO_FUNC_EN_N (0x1 << 4)
#define AUD_FUNC_EN_N (0x1 << 3)
#define HDCP_FUNC_EN_N (0x1 << 2)
#define CRC_FUNC_EN_N (0x1 << 1)
#define SW_FUNC_EN_N (0x1 << 0)
/* EXYNOS_DP_FUNC_EN_2 */
#define SSC_FUNC_EN_N (0x1 << 7)
#define AUX_FUNC_EN_N (0x1 << 2)
#define SERDES_FIFO_FUNC_EN_N (0x1 << 1)
#define LS_CLK_DOMAIN_FUNC_EN_N (0x1 << 0)
/* EXYNOS_DP_VIDEO_CTL_1 */
#define VIDEO_EN (0x1 << 7)
#define HDCP_VIDEO_MUTE (0x1 << 6)
/* EXYNOS_DP_VIDEO_CTL_1 */
#define IN_D_RANGE_MASK (0x1 << 7)
#define IN_D_RANGE_SHIFT (7)
#define IN_D_RANGE_CEA (0x1 << 7)
#define IN_D_RANGE_VESA (0x0 << 7)
#define IN_BPC_MASK (0x7 << 4)
#define IN_BPC_SHIFT (4)
#define IN_BPC_12_BITS (0x3 << 4)
#define IN_BPC_10_BITS (0x2 << 4)
#define IN_BPC_8_BITS (0x1 << 4)
#define IN_BPC_6_BITS (0x0 << 4)
#define IN_COLOR_F_MASK (0x3 << 0)
#define IN_COLOR_F_SHIFT (0)
#define IN_COLOR_F_YCBCR444 (0x2 << 0)
#define IN_COLOR_F_YCBCR422 (0x1 << 0)
#define IN_COLOR_F_RGB (0x0 << 0)
/* EXYNOS_DP_VIDEO_CTL_3 */
#define IN_YC_COEFFI_MASK (0x1 << 7)
#define IN_YC_COEFFI_SHIFT (7)
#define IN_YC_COEFFI_ITU709 (0x1 << 7)
#define IN_YC_COEFFI_ITU601 (0x0 << 7)
#define VID_CHK_UPDATE_TYPE_MASK (0x1 << 4)
#define VID_CHK_UPDATE_TYPE_SHIFT (4)
#define VID_CHK_UPDATE_TYPE_1 (0x1 << 4)
#define VID_CHK_UPDATE_TYPE_0 (0x0 << 4)
/* EXYNOS_DP_VIDEO_CTL_8 */
#define VID_HRES_TH(x) (((x) & 0xf) << 4)
#define VID_VRES_TH(x) (((x) & 0xf) << 0)
/* EXYNOS_DP_VIDEO_CTL_10 */
#define FORMAT_SEL (0x1 << 4)
#define INTERACE_SCAN_CFG (0x1 << 2)
#define VSYNC_POLARITY_CFG (0x1 << 1)
#define HSYNC_POLARITY_CFG (0x1 << 0)
/* EXYNOS_DP_LANE_MAP */
#define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6)
#define LANE3_MAP_LOGIC_LANE_1 (0x1 << 6)
#define LANE3_MAP_LOGIC_LANE_2 (0x2 << 6)
#define LANE3_MAP_LOGIC_LANE_3 (0x3 << 6)
#define LANE2_MAP_LOGIC_LANE_0 (0x0 << 4)
#define LANE2_MAP_LOGIC_LANE_1 (0x1 << 4)
#define LANE2_MAP_LOGIC_LANE_2 (0x2 << 4)
#define LANE2_MAP_LOGIC_LANE_3 (0x3 << 4)
#define LANE1_MAP_LOGIC_LANE_0 (0x0 << 2)
#define LANE1_MAP_LOGIC_LANE_1 (0x1 << 2)
#define LANE1_MAP_LOGIC_LANE_2 (0x2 << 2)
#define LANE1_MAP_LOGIC_LANE_3 (0x3 << 2)
#define LANE0_MAP_LOGIC_LANE_0 (0x0 << 0)
#define LANE0_MAP_LOGIC_LANE_1 (0x1 << 0)
#define LANE0_MAP_LOGIC_LANE_2 (0x2 << 0)
#define LANE0_MAP_LOGIC_LANE_3 (0x3 << 0)
/* EXYNOS_DP_ANALOG_CTL_1 */
#define TX_TERMINAL_CTRL_50_OHM (0x1 << 4)
/* EXYNOS_DP_ANALOG_CTL_2 */
#define SEL_24M (0x1 << 3)
#define TX_DVDD_BIT_1_0625V (0x4 << 0)
/* EXYNOS_DP_ANALOG_CTL_3 */
#define DRIVE_DVDD_BIT_1_0625V (0x4 << 5)
#define VCO_BIT_600_MICRO (0x5 << 0)
/* EXYNOS_DP_PLL_FILTER_CTL_1 */
#define PD_RING_OSC (0x1 << 6)
#define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4)
#define TX_CUR1_2X (0x1 << 2)
#define TX_CUR_16_MA (0x3 << 0)
/* EXYNOS_DP_TX_AMP_TUNING_CTL */
#define CH3_AMP_400_MV (0x0 << 24)
#define CH2_AMP_400_MV (0x0 << 16)
#define CH1_AMP_400_MV (0x0 << 8)
#define CH0_AMP_400_MV (0x0 << 0)
/* EXYNOS_DP_AUX_HW_RETRY_CTL */
#define AUX_BIT_PERIOD_EXPECTED_DELAY(x) (((x) & 0x7) << 8)
#define AUX_HW_RETRY_INTERVAL_MASK (0x3 << 3)
#define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS (0x0 << 3)
#define AUX_HW_RETRY_INTERVAL_800_MICROSECONDS (0x1 << 3)
#define AUX_HW_RETRY_INTERVAL_1000_MICROSECONDS (0x2 << 3)
#define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS (0x3 << 3)
#define AUX_HW_RETRY_COUNT_SEL(x) (((x) & 0x7) << 0)
/* EXYNOS_DP_COMMON_INT_STA_1 */
#define VSYNC_DET (0x1 << 7)
#define PLL_LOCK_CHG (0x1 << 6)
#define SPDIF_ERR (0x1 << 5)
#define SPDIF_UNSTBL (0x1 << 4)
#define VID_FORMAT_CHG (0x1 << 3)
#define AUD_CLK_CHG (0x1 << 2)
#define VID_CLK_CHG (0x1 << 1)
#define SW_INT (0x1 << 0)
/* EXYNOS_DP_COMMON_INT_STA_2 */
#define ENC_EN_CHG (0x1 << 6)
#define HW_BKSV_RDY (0x1 << 3)
#define HW_SHA_DONE (0x1 << 2)
#define HW_AUTH_STATE_CHG (0x1 << 1)
#define HW_AUTH_DONE (0x1 << 0)
/* EXYNOS_DP_COMMON_INT_STA_3 */
#define AFIFO_UNDER (0x1 << 7)
#define AFIFO_OVER (0x1 << 6)
#define R0_CHK_FLAG (0x1 << 5)
/* EXYNOS_DP_COMMON_INT_STA_4 */
#define PSR_ACTIVE (0x1 << 7)
#define PSR_INACTIVE (0x1 << 6)
#define SPDIF_BI_PHASE_ERR (0x1 << 5)
#define HOTPLUG_CHG (0x1 << 2)
#define HPD_LOST (0x1 << 1)
#define PLUG (0x1 << 0)
/* EXYNOS_DP_INT_STA */
#define INT_HPD (0x1 << 6)
#define HW_TRAINING_FINISH (0x1 << 5)
#define RPLY_RECEIV (0x1 << 1)
#define AUX_ERR (0x1 << 0)
/* EXYNOS_DP_INT_CTL */
#define SOFT_INT_CTRL (0x1 << 2)
#define INT_POL1 (0x1 << 1)
#define INT_POL0 (0x1 << 0)
/* EXYNOS_DP_SYS_CTL_1 */
#define DET_STA (0x1 << 2)
#define FORCE_DET (0x1 << 1)
#define DET_CTRL (0x1 << 0)
/* EXYNOS_DP_SYS_CTL_2 */
#define CHA_CRI(x) (((x) & 0xf) << 4)
#define CHA_STA (0x1 << 2)
#define FORCE_CHA (0x1 << 1)
#define CHA_CTRL (0x1 << 0)
/* EXYNOS_DP_SYS_CTL_3 */
#define HPD_STATUS (0x1 << 6)
#define F_HPD (0x1 << 5)
#define HPD_CTRL (0x1 << 4)
#define HDCP_RDY (0x1 << 3)
#define STRM_VALID (0x1 << 2)
#define F_VALID (0x1 << 1)
#define VALID_CTRL (0x1 << 0)
/* EXYNOS_DP_SYS_CTL_4 */
#define FIX_M_AUD (0x1 << 4)
#define ENHANCED (0x1 << 3)
#define FIX_M_VID (0x1 << 2)
#define M_VID_UPDATE_CTRL (0x3 << 0)
/* EXYNOS_DP_TRAINING_PTN_SET */
#define SCRAMBLER_TYPE (0x1 << 9)
#define HW_LINK_TRAINING_PATTERN (0x1 << 8)
#define SCRAMBLING_DISABLE (0x1 << 5)
#define SCRAMBLING_ENABLE (0x0 << 5)
#define LINK_QUAL_PATTERN_SET_MASK (0x3 << 2)
#define LINK_QUAL_PATTERN_SET_PRBS7 (0x3 << 2)
#define LINK_QUAL_PATTERN_SET_D10_2 (0x1 << 2)
#define LINK_QUAL_PATTERN_SET_DISABLE (0x0 << 2)
#define SW_TRAINING_PATTERN_SET_MASK (0x3 << 0)
#define SW_TRAINING_PATTERN_SET_PTN2 (0x2 << 0)
#define SW_TRAINING_PATTERN_SET_PTN1 (0x1 << 0)
#define SW_TRAINING_PATTERN_SET_NORMAL (0x0 << 0)
/* EXYNOS_DP_LN0_LINK_TRAINING_CTL */
#define PRE_EMPHASIS_SET_MASK (0x3 << 3)
#define PRE_EMPHASIS_SET_SHIFT (3)
/* EXYNOS_DP_DEBUG_CTL */
#define PLL_LOCK (0x1 << 4)
#define F_PLL_LOCK (0x1 << 3)
#define PLL_LOCK_CTRL (0x1 << 2)
#define PN_INV (0x1 << 0)
/* EXYNOS_DP_PLL_CTL */
#define DP_PLL_PD (0x1 << 7)
#define DP_PLL_RESET (0x1 << 6)
#define DP_PLL_LOOP_BIT_DEFAULT (0x1 << 4)
#define DP_PLL_REF_BIT_1_1250V (0x5 << 0)
#define DP_PLL_REF_BIT_1_2500V (0x7 << 0)
/* EXYNOS_DP_PHY_PD */
#define DP_PHY_PD (0x1 << 5)
#define AUX_PD (0x1 << 4)
#define CH3_PD (0x1 << 3)
#define CH2_PD (0x1 << 2)
#define CH1_PD (0x1 << 1)
#define CH0_PD (0x1 << 0)
/* EXYNOS_DP_PHY_TEST */
#define MACRO_RST (0x1 << 5)
#define CH1_TEST (0x1 << 1)
#define CH0_TEST (0x1 << 0)
/* EXYNOS_DP_AUX_CH_STA */
#define AUX_BUSY (0x1 << 4)
#define AUX_STATUS_MASK (0xf << 0)
/* EXYNOS_DP_AUX_CH_DEFER_CTL */
#define DEFER_CTRL_EN (0x1 << 7)
#define DEFER_COUNT(x) (((x) & 0x7f) << 0)
/* EXYNOS_DP_AUX_RX_COMM */
#define AUX_RX_COMM_I2C_DEFER (0x2 << 2)
#define AUX_RX_COMM_AUX_DEFER (0x2 << 0)
/* EXYNOS_DP_BUFFER_DATA_CTL */
#define BUF_CLR (0x1 << 7)
#define BUF_DATA_COUNT(x) (((x) & 0x1f) << 0)
/* EXYNOS_DP_AUX_CH_CTL_1 */
#define AUX_LENGTH(x) (((x - 1) & 0xf) << 4)
#define AUX_TX_COMM_MASK (0xf << 0)
#define AUX_TX_COMM_DP_TRANSACTION (0x1 << 3)
#define AUX_TX_COMM_I2C_TRANSACTION (0x0 << 3)
#define AUX_TX_COMM_MOT (0x1 << 2)
#define AUX_TX_COMM_WRITE (0x0 << 0)
#define AUX_TX_COMM_READ (0x1 << 0)
/* EXYNOS_DP_AUX_ADDR_7_0 */
#define AUX_ADDR_7_0(x) (((x) >> 0) & 0xff)
/* EXYNOS_DP_AUX_ADDR_15_8 */
#define AUX_ADDR_15_8(x) (((x) >> 8) & 0xff)
/* EXYNOS_DP_AUX_ADDR_19_16 */
#define AUX_ADDR_19_16(x) (((x) >> 16) & 0x0f)
/* EXYNOS_DP_AUX_CH_CTL_2 */
#define ADDR_ONLY (0x1 << 1)
#define AUX_EN (0x1 << 0)
/* EXYNOS_DP_SOC_GENERAL_CTL */
#define AUDIO_MODE_SPDIF_MODE (0x1 << 8)
#define AUDIO_MODE_MASTER_MODE (0x0 << 8)
#define MASTER_VIDEO_INTERLACE_EN (0x1 << 4)
#define VIDEO_MASTER_CLK_SEL (0x1 << 2)
#define VIDEO_MASTER_MODE_EN (0x1 << 1)
#define VIDEO_MODE_MASK (0x1 << 0)
#define VIDEO_MODE_SLAVE_MODE (0x1 << 0)
#define VIDEO_MODE_MASTER_MODE (0x0 << 0)
#endif /* _EXYNOS_DP_REG_H */

View file

@ -0,0 +1,186 @@
/* exynos_drm_buf.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Author: Inki Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <drm/drmP.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_buf.h"
#include "exynos_drm_iommu.h"
static int lowlevel_buffer_allocate(struct drm_device *dev,
unsigned int flags, struct exynos_drm_gem_buf *buf)
{
int ret = 0;
enum dma_attr attr;
unsigned int nr_pages;
if (buf->dma_addr) {
DRM_DEBUG_KMS("already allocated.\n");
return 0;
}
init_dma_attrs(&buf->dma_attrs);
/*
* if EXYNOS_BO_CONTIG, fully physically contiguous memory
* region will be allocated else physically contiguous
* as possible.
*/
if (!(flags & EXYNOS_BO_NONCONTIG))
dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &buf->dma_attrs);
/*
* if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping
* else cachable mapping.
*/
if (flags & EXYNOS_BO_WC || !(flags & EXYNOS_BO_CACHABLE))
attr = DMA_ATTR_WRITE_COMBINE;
else
attr = DMA_ATTR_NON_CONSISTENT;
dma_set_attr(attr, &buf->dma_attrs);
dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &buf->dma_attrs);
nr_pages = buf->size >> PAGE_SHIFT;
if (!is_drm_iommu_supported(dev)) {
dma_addr_t start_addr;
unsigned int i = 0;
buf->pages = drm_calloc_large(nr_pages, sizeof(struct page *));
if (!buf->pages) {
DRM_ERROR("failed to allocate pages.\n");
return -ENOMEM;
}
buf->kvaddr = (void __iomem *)dma_alloc_attrs(dev->dev,
buf->size,
&buf->dma_addr, GFP_KERNEL,
&buf->dma_attrs);
if (!buf->kvaddr) {
DRM_ERROR("failed to allocate buffer.\n");
ret = -ENOMEM;
goto err_free;
}
start_addr = buf->dma_addr;
while (i < nr_pages) {
buf->pages[i] = phys_to_page(start_addr);
start_addr += PAGE_SIZE;
i++;
}
} else {
buf->pages = dma_alloc_attrs(dev->dev, buf->size,
&buf->dma_addr, GFP_KERNEL,
&buf->dma_attrs);
if (!buf->pages) {
DRM_ERROR("failed to allocate buffer.\n");
return -ENOMEM;
}
}
buf->sgt = drm_prime_pages_to_sg(buf->pages, nr_pages);
if (IS_ERR(buf->sgt)) {
DRM_ERROR("failed to get sg table.\n");
ret = PTR_ERR(buf->sgt);
goto err_free_attrs;
}
DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
(unsigned long)buf->dma_addr,
buf->size);
return ret;
err_free_attrs:
dma_free_attrs(dev->dev, buf->size, buf->pages,
(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
buf->dma_addr = (dma_addr_t)NULL;
err_free:
if (!is_drm_iommu_supported(dev))
drm_free_large(buf->pages);
return ret;
}
static void lowlevel_buffer_deallocate(struct drm_device *dev,
unsigned int flags, struct exynos_drm_gem_buf *buf)
{
if (!buf->dma_addr) {
DRM_DEBUG_KMS("dma_addr is invalid.\n");
return;
}
DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
(unsigned long)buf->dma_addr,
buf->size);
sg_free_table(buf->sgt);
kfree(buf->sgt);
buf->sgt = NULL;
if (!is_drm_iommu_supported(dev)) {
dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
drm_free_large(buf->pages);
} else
dma_free_attrs(dev->dev, buf->size, buf->pages,
(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
buf->dma_addr = (dma_addr_t)NULL;
}
struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
unsigned int size)
{
struct exynos_drm_gem_buf *buffer;
DRM_DEBUG_KMS("desired size = 0x%x\n", size);
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer)
return NULL;
buffer->size = size;
return buffer;
}
void exynos_drm_fini_buf(struct drm_device *dev,
struct exynos_drm_gem_buf *buffer)
{
kfree(buffer);
buffer = NULL;
}
int exynos_drm_alloc_buf(struct drm_device *dev,
struct exynos_drm_gem_buf *buf, unsigned int flags)
{
/*
* allocate memory region and set the memory information
* to vaddr and dma_addr of a buffer object.
*/
if (lowlevel_buffer_allocate(dev, flags, buf) < 0)
return -ENOMEM;
return 0;
}
void exynos_drm_free_buf(struct drm_device *dev,
unsigned int flags, struct exynos_drm_gem_buf *buffer)
{
lowlevel_buffer_deallocate(dev, flags, buffer);
}

View file

@ -0,0 +1,33 @@
/* exynos_drm_buf.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Author: Inki Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_BUF_H_
#define _EXYNOS_DRM_BUF_H_
/* create and initialize buffer object. */
struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
unsigned int size);
/* destroy buffer object. */
void exynos_drm_fini_buf(struct drm_device *dev,
struct exynos_drm_gem_buf *buffer);
/* allocate physical memory region and setup sgt. */
int exynos_drm_alloc_buf(struct drm_device *dev,
struct exynos_drm_gem_buf *buf,
unsigned int flags);
/* release physical memory region, and sgt. */
void exynos_drm_free_buf(struct drm_device *dev,
unsigned int flags,
struct exynos_drm_gem_buf *buffer);
#endif

View file

@ -0,0 +1,245 @@
/*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_encoder.h"
#include "exynos_drm_connector.h"
#define to_exynos_connector(x) container_of(x, struct exynos_drm_connector,\
drm_connector)
struct exynos_drm_connector {
struct drm_connector drm_connector;
uint32_t encoder_id;
struct exynos_drm_display *display;
};
static int exynos_drm_connector_get_modes(struct drm_connector *connector)
{
struct exynos_drm_connector *exynos_connector =
to_exynos_connector(connector);
struct exynos_drm_display *display = exynos_connector->display;
struct edid *edid = NULL;
unsigned int count = 0;
int ret;
/*
* if get_edid() exists then get_edid() callback of hdmi side
* is called to get edid data through i2c interface else
* get timing from the FIMD driver(display controller).
*
* P.S. in case of lcd panel, count is always 1 if success
* because lcd panel has only one mode.
*/
if (display->ops->get_edid) {
edid = display->ops->get_edid(display, connector);
if (IS_ERR_OR_NULL(edid)) {
ret = PTR_ERR(edid);
edid = NULL;
DRM_ERROR("Panel operation get_edid failed %d\n", ret);
goto out;
}
count = drm_add_edid_modes(connector, edid);
if (!count) {
DRM_ERROR("Add edid modes failed %d\n", count);
goto out;
}
drm_mode_connector_update_edid_property(connector, edid);
} else {
struct exynos_drm_panel_info *panel;
struct drm_display_mode *mode = drm_mode_create(connector->dev);
if (!mode) {
DRM_ERROR("failed to create a new display mode.\n");
return 0;
}
if (display->ops->get_panel)
panel = display->ops->get_panel(display);
else {
drm_mode_destroy(connector->dev, mode);
return 0;
}
drm_display_mode_from_videomode(&panel->vm, mode);
mode->width_mm = panel->width_mm;
mode->height_mm = panel->height_mm;
connector->display_info.width_mm = mode->width_mm;
connector->display_info.height_mm = mode->height_mm;
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_set_name(mode);
drm_mode_probed_add(connector, mode);
count = 1;
}
out:
kfree(edid);
return count;
}
static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct exynos_drm_connector *exynos_connector =
to_exynos_connector(connector);
struct exynos_drm_display *display = exynos_connector->display;
int ret = MODE_BAD;
DRM_DEBUG_KMS("%s\n", __FILE__);
if (display->ops->check_mode)
if (!display->ops->check_mode(display, mode))
ret = MODE_OK;
return ret;
}
static struct drm_encoder *exynos_drm_best_encoder(
struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct exynos_drm_connector *exynos_connector =
to_exynos_connector(connector);
return drm_encoder_find(dev, exynos_connector->encoder_id);
}
static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
.get_modes = exynos_drm_connector_get_modes,
.mode_valid = exynos_drm_connector_mode_valid,
.best_encoder = exynos_drm_best_encoder,
};
static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
unsigned int max_width, unsigned int max_height)
{
struct exynos_drm_connector *exynos_connector =
to_exynos_connector(connector);
struct exynos_drm_display *display = exynos_connector->display;
unsigned int width, height;
width = max_width;
height = max_height;
/*
* if specific driver want to find desired_mode using maxmum
* resolution then get max width and height from that driver.
*/
if (display->ops->get_max_resol)
display->ops->get_max_resol(display, &width, &height);
return drm_helper_probe_single_connector_modes(connector, width,
height);
}
/* get detection status of display device. */
static enum drm_connector_status
exynos_drm_connector_detect(struct drm_connector *connector, bool force)
{
struct exynos_drm_connector *exynos_connector =
to_exynos_connector(connector);
struct exynos_drm_display *display = exynos_connector->display;
enum drm_connector_status status = connector_status_disconnected;
if (display->ops->is_connected) {
if (display->ops->is_connected(display))
status = connector_status_connected;
else
status = connector_status_disconnected;
}
return status;
}
static void exynos_drm_connector_destroy(struct drm_connector *connector)
{
struct exynos_drm_connector *exynos_connector =
to_exynos_connector(connector);
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
kfree(exynos_connector);
}
static struct drm_connector_funcs exynos_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = exynos_drm_connector_fill_modes,
.detect = exynos_drm_connector_detect,
.destroy = exynos_drm_connector_destroy,
};
struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
struct drm_encoder *encoder)
{
struct exynos_drm_connector *exynos_connector;
struct exynos_drm_display *display = exynos_drm_get_display(encoder);
struct drm_connector *connector;
int type;
int err;
exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL);
if (!exynos_connector)
return NULL;
connector = &exynos_connector->drm_connector;
switch (display->type) {
case EXYNOS_DISPLAY_TYPE_HDMI:
type = DRM_MODE_CONNECTOR_HDMIA;
connector->interlace_allowed = true;
connector->polled = DRM_CONNECTOR_POLL_HPD;
break;
case EXYNOS_DISPLAY_TYPE_VIDI:
type = DRM_MODE_CONNECTOR_VIRTUAL;
connector->polled = DRM_CONNECTOR_POLL_HPD;
break;
default:
type = DRM_MODE_CONNECTOR_Unknown;
break;
}
drm_connector_init(dev, connector, &exynos_connector_funcs, type);
drm_connector_helper_add(connector, &exynos_connector_helper_funcs);
err = drm_connector_register(connector);
if (err)
goto err_connector;
exynos_connector->encoder_id = encoder->base.id;
exynos_connector->display = display;
connector->dpms = DRM_MODE_DPMS_OFF;
connector->encoder = encoder;
err = drm_mode_connector_attach_encoder(connector, encoder);
if (err) {
DRM_ERROR("failed to attach a connector to a encoder\n");
goto err_sysfs;
}
DRM_DEBUG_KMS("connector has been created\n");
return connector;
err_sysfs:
drm_connector_unregister(connector);
err_connector:
drm_connector_cleanup(connector);
kfree(exynos_connector);
return NULL;
}

View file

@ -0,0 +1,20 @@
/*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_CONNECTOR_H_
#define _EXYNOS_DRM_CONNECTOR_H_
struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
struct drm_encoder *encoder);
#endif

View file

@ -0,0 +1,161 @@
/* exynos_drm_core.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Author:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <drm/drmP.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
#include "exynos_drm_encoder.h"
#include "exynos_drm_fbdev.h"
static LIST_HEAD(exynos_drm_subdrv_list);
int exynos_drm_create_enc_conn(struct drm_device *dev,
struct exynos_drm_display *display)
{
struct drm_encoder *encoder;
int ret;
unsigned long possible_crtcs = 0;
ret = exynos_drm_crtc_get_pipe_from_type(dev, display->type);
if (ret < 0)
return ret;
possible_crtcs |= 1 << ret;
/* create and initialize a encoder for this sub driver. */
encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
if (!encoder) {
DRM_ERROR("failed to create encoder\n");
return -EFAULT;
}
display->encoder = encoder;
ret = display->ops->create_connector(display, encoder);
if (ret) {
DRM_ERROR("failed to create connector ret = %d\n", ret);
goto err_destroy_encoder;
}
return 0;
err_destroy_encoder:
encoder->funcs->destroy(encoder);
return ret;
}
int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
{
if (!subdrv)
return -EINVAL;
list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
return 0;
}
EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
{
if (!subdrv)
return -EINVAL;
list_del(&subdrv->list);
return 0;
}
EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
int exynos_drm_device_subdrv_probe(struct drm_device *dev)
{
struct exynos_drm_subdrv *subdrv, *n;
int err;
if (!dev)
return -EINVAL;
list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
if (subdrv->probe) {
subdrv->drm_dev = dev;
/*
* this probe callback would be called by sub driver
* after setting of all resources to this sub driver,
* such as clock, irq and register map are done.
*/
err = subdrv->probe(dev, subdrv->dev);
if (err) {
DRM_DEBUG("exynos drm subdrv probe failed.\n");
list_del(&subdrv->list);
continue;
}
}
}
return 0;
}
EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_probe);
int exynos_drm_device_subdrv_remove(struct drm_device *dev)
{
struct exynos_drm_subdrv *subdrv;
if (!dev) {
WARN(1, "Unexpected drm device unregister!\n");
return -EINVAL;
}
list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
if (subdrv->remove)
subdrv->remove(dev, subdrv->dev);
}
return 0;
}
EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_remove);
int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
{
struct exynos_drm_subdrv *subdrv;
int ret;
list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
if (subdrv->open) {
ret = subdrv->open(dev, subdrv->dev, file);
if (ret)
goto err;
}
}
return 0;
err:
list_for_each_entry_reverse(subdrv, &subdrv->list, list) {
if (subdrv->close)
subdrv->close(dev, subdrv->dev, file);
}
return ret;
}
EXPORT_SYMBOL_GPL(exynos_drm_subdrv_open);
void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
{
struct exynos_drm_subdrv *subdrv;
list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
if (subdrv->close)
subdrv->close(dev, subdrv->dev, file);
}
}
EXPORT_SYMBOL_GPL(exynos_drm_subdrv_close);

View file

@ -0,0 +1,524 @@
/* exynos_drm_crtc.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include "exynos_drm_crtc.h"
#include "exynos_drm_drv.h"
#include "exynos_drm_encoder.h"
#include "exynos_drm_plane.h"
#define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\
drm_crtc)
enum exynos_crtc_mode {
CRTC_MODE_NORMAL, /* normal mode */
CRTC_MODE_BLANK, /* The private plane of crtc is blank */
};
/*
* Exynos specific crtc structure.
*
* @drm_crtc: crtc object.
* @manager: the manager associated with this crtc
* @pipe: a crtc index created at load() with a new crtc object creation
* and the crtc object would be set to private->crtc array
* to get a crtc object corresponding to this pipe from private->crtc
* array when irq interrupt occurred. the reason of using this pipe is that
* drm framework doesn't support multiple irq yet.
* we can refer to the crtc to current hardware interrupt occurred through
* this pipe value.
* @dpms: store the crtc dpms value
* @mode: store the crtc mode value
*/
struct exynos_drm_crtc {
struct drm_crtc drm_crtc;
struct exynos_drm_manager *manager;
unsigned int pipe;
unsigned int dpms;
enum exynos_crtc_mode mode;
wait_queue_head_t pending_flip_queue;
atomic_t pending_flip;
};
static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct exynos_drm_manager *manager = exynos_crtc->manager;
DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
if (exynos_crtc->dpms == mode) {
DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
return;
}
if (mode > DRM_MODE_DPMS_ON) {
/* wait for the completion of page flip. */
if (!wait_event_timeout(exynos_crtc->pending_flip_queue,
!atomic_read(&exynos_crtc->pending_flip),
HZ/20))
atomic_set(&exynos_crtc->pending_flip, 0);
drm_crtc_vblank_off(crtc);
}
if (manager->ops->dpms)
manager->ops->dpms(manager, mode);
exynos_crtc->dpms = mode;
if (mode == DRM_MODE_DPMS_ON)
drm_crtc_vblank_on(crtc);
}
static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
{
/* drm framework doesn't check NULL. */
}
static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct exynos_drm_manager *manager = exynos_crtc->manager;
exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
exynos_plane_commit(crtc->primary);
if (manager->ops->commit)
manager->ops->commit(manager);
exynos_plane_dpms(crtc->primary, DRM_MODE_DPMS_ON);
}
static bool
exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct exynos_drm_manager *manager = exynos_crtc->manager;
if (manager->ops->mode_fixup)
return manager->ops->mode_fixup(manager, mode, adjusted_mode);
return true;
}
static int
exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode, int x, int y,
struct drm_framebuffer *old_fb)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct exynos_drm_manager *manager = exynos_crtc->manager;
struct drm_framebuffer *fb = crtc->primary->fb;
unsigned int crtc_w;
unsigned int crtc_h;
/*
* copy the mode data adjusted by mode_fixup() into crtc->mode
* so that hardware can be seet to proper mode.
*/
memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
crtc_w = fb->width - x;
crtc_h = fb->height - y;
if (manager->ops->mode_set)
manager->ops->mode_set(manager, &crtc->mode);
return exynos_plane_mode_set(crtc->primary, crtc, fb, 0, 0,
crtc_w, crtc_h, x, y, crtc_w, crtc_h);
}
static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct drm_framebuffer *fb = crtc->primary->fb;
unsigned int crtc_w;
unsigned int crtc_h;
int ret;
/* when framebuffer changing is requested, crtc's dpms should be on */
if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) {
DRM_ERROR("failed framebuffer changing request.\n");
return -EPERM;
}
crtc_w = fb->width - x;
crtc_h = fb->height - y;
ret = exynos_plane_mode_set(crtc->primary, crtc, fb, 0, 0,
crtc_w, crtc_h, x, y, crtc_w, crtc_h);
if (ret)
return ret;
exynos_drm_crtc_commit(crtc);
return 0;
}
static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
return exynos_drm_crtc_mode_set_commit(crtc, x, y, old_fb);
}
static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
{
struct drm_plane *plane;
int ret;
exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) {
if (plane->crtc != crtc)
continue;
ret = plane->funcs->disable_plane(plane);
if (ret)
DRM_ERROR("Failed to disable plane %d\n", ret);
}
}
static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
.dpms = exynos_drm_crtc_dpms,
.prepare = exynos_drm_crtc_prepare,
.commit = exynos_drm_crtc_commit,
.mode_fixup = exynos_drm_crtc_mode_fixup,
.mode_set = exynos_drm_crtc_mode_set,
.mode_set_base = exynos_drm_crtc_mode_set_base,
.disable = exynos_drm_crtc_disable,
};
static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event,
uint32_t page_flip_flags)
{
struct drm_device *dev = crtc->dev;
struct exynos_drm_private *dev_priv = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct drm_framebuffer *old_fb = crtc->primary->fb;
int ret = -EINVAL;
/* when the page flip is requested, crtc's dpms should be on */
if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) {
DRM_ERROR("failed page flip request.\n");
return -EINVAL;
}
mutex_lock(&dev->struct_mutex);
if (event) {
/*
* the pipe from user always is 0 so we can set pipe number
* of current owner to event.
*/
event->pipe = exynos_crtc->pipe;
ret = drm_vblank_get(dev, exynos_crtc->pipe);
if (ret) {
DRM_DEBUG("failed to acquire vblank counter\n");
goto out;
}
spin_lock_irq(&dev->event_lock);
list_add_tail(&event->base.link,
&dev_priv->pageflip_event_list);
atomic_set(&exynos_crtc->pending_flip, 1);
spin_unlock_irq(&dev->event_lock);
crtc->primary->fb = fb;
ret = exynos_drm_crtc_mode_set_commit(crtc, crtc->x, crtc->y,
NULL);
if (ret) {
crtc->primary->fb = old_fb;
spin_lock_irq(&dev->event_lock);
drm_vblank_put(dev, exynos_crtc->pipe);
list_del(&event->base.link);
atomic_set(&exynos_crtc->pending_flip, 0);
spin_unlock_irq(&dev->event_lock);
goto out;
}
}
out:
mutex_unlock(&dev->struct_mutex);
return ret;
}
static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct exynos_drm_private *private = crtc->dev->dev_private;
private->crtc[exynos_crtc->pipe] = NULL;
drm_crtc_cleanup(crtc);
kfree(exynos_crtc);
}
static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
struct drm_property *property,
uint64_t val)
{
struct drm_device *dev = crtc->dev;
struct exynos_drm_private *dev_priv = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
if (property == dev_priv->crtc_mode_property) {
enum exynos_crtc_mode mode = val;
if (mode == exynos_crtc->mode)
return 0;
exynos_crtc->mode = mode;
switch (mode) {
case CRTC_MODE_NORMAL:
exynos_drm_crtc_commit(crtc);
break;
case CRTC_MODE_BLANK:
exynos_plane_dpms(crtc->primary, DRM_MODE_DPMS_OFF);
break;
default:
break;
}
return 0;
}
return -EINVAL;
}
static struct drm_crtc_funcs exynos_crtc_funcs = {
.set_config = drm_crtc_helper_set_config,
.page_flip = exynos_drm_crtc_page_flip,
.destroy = exynos_drm_crtc_destroy,
.set_property = exynos_drm_crtc_set_property,
};
static const struct drm_prop_enum_list mode_names[] = {
{ CRTC_MODE_NORMAL, "normal" },
{ CRTC_MODE_BLANK, "blank" },
};
static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct exynos_drm_private *dev_priv = dev->dev_private;
struct drm_property *prop;
prop = dev_priv->crtc_mode_property;
if (!prop) {
prop = drm_property_create_enum(dev, 0, "mode", mode_names,
ARRAY_SIZE(mode_names));
if (!prop)
return;
dev_priv->crtc_mode_property = prop;
}
drm_object_attach_property(&crtc->base, prop, 0);
}
int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
{
struct exynos_drm_crtc *exynos_crtc;
struct drm_plane *plane;
struct exynos_drm_private *private = manager->drm_dev->dev_private;
struct drm_crtc *crtc;
int ret;
exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
if (!exynos_crtc)
return -ENOMEM;
init_waitqueue_head(&exynos_crtc->pending_flip_queue);
atomic_set(&exynos_crtc->pending_flip, 0);
exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
exynos_crtc->manager = manager;
exynos_crtc->pipe = manager->pipe;
plane = exynos_plane_init(manager->drm_dev, 1 << manager->pipe,
DRM_PLANE_TYPE_PRIMARY);
if (IS_ERR(plane)) {
ret = PTR_ERR(plane);
goto err_plane;
}
manager->crtc = &exynos_crtc->drm_crtc;
crtc = &exynos_crtc->drm_crtc;
private->crtc[manager->pipe] = crtc;
ret = drm_crtc_init_with_planes(manager->drm_dev, crtc, plane, NULL,
&exynos_crtc_funcs);
if (ret < 0)
goto err_crtc;
drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
exynos_drm_crtc_attach_mode_property(crtc);
return 0;
err_crtc:
plane->funcs->destroy(plane);
err_plane:
kfree(exynos_crtc);
return ret;
}
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
{
struct exynos_drm_private *private = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc =
to_exynos_crtc(private->crtc[pipe]);
struct exynos_drm_manager *manager = exynos_crtc->manager;
if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
return -EPERM;
if (manager->ops->enable_vblank)
manager->ops->enable_vblank(manager);
return 0;
}
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
{
struct exynos_drm_private *private = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc =
to_exynos_crtc(private->crtc[pipe]);
struct exynos_drm_manager *manager = exynos_crtc->manager;
if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
return;
if (manager->ops->disable_vblank)
manager->ops->disable_vblank(manager);
}
void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
{
struct exynos_drm_private *dev_priv = dev->dev_private;
struct drm_pending_vblank_event *e, *t;
struct drm_crtc *drm_crtc = dev_priv->crtc[pipe];
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
base.link) {
/* if event's pipe isn't same as crtc then ignore it. */
if (pipe != e->pipe)
continue;
list_del(&e->base.link);
drm_send_vblank_event(dev, -1, e);
drm_vblank_put(dev, pipe);
atomic_set(&exynos_crtc->pending_flip, 0);
wake_up(&exynos_crtc->pending_flip_queue);
}
spin_unlock_irqrestore(&dev->event_lock, flags);
}
void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
struct exynos_drm_overlay *overlay)
{
struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
if (manager->ops->win_mode_set)
manager->ops->win_mode_set(manager, overlay);
}
void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos)
{
struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
if (manager->ops->win_commit)
manager->ops->win_commit(manager, zpos);
}
void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos)
{
struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
if (manager->ops->win_enable)
manager->ops->win_enable(manager, zpos);
}
void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos)
{
struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
if (manager->ops->win_disable)
manager->ops->win_disable(manager, zpos);
}
void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
{
struct exynos_drm_manager *manager;
struct drm_device *dev = fb->dev;
struct drm_crtc *crtc;
/*
* make sure that overlay data are updated to real hardware
* for all encoders.
*/
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
manager = to_exynos_crtc(crtc)->manager;
/*
* wait for vblank interrupt
* - this makes sure that overlay data are updated to
* real hardware.
*/
if (manager->ops->wait_for_vblank)
manager->ops->wait_for_vblank(manager);
}
}
int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
unsigned int out_type)
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
struct exynos_drm_crtc *exynos_crtc;
exynos_crtc = to_exynos_crtc(crtc);
if (exynos_crtc->manager->type == out_type)
return exynos_crtc->manager->pipe;
}
return -EPERM;
}
void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
{
struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
if (manager->ops->te_handler)
manager->ops->te_handler(manager);
}

View file

@ -0,0 +1,46 @@
/* exynos_drm_crtc.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_CRTC_H_
#define _EXYNOS_DRM_CRTC_H_
struct drm_device;
struct drm_crtc;
struct exynos_drm_manager;
struct exynos_drm_overlay;
int exynos_drm_crtc_create(struct exynos_drm_manager *manager);
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe);
void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
struct exynos_drm_overlay *overlay);
void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos);
void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos);
void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos);
/* This function gets pipe value to crtc device matched with out_type. */
int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
unsigned int out_type);
/*
* This function calls the crtc device(manager)'s te_handler() callback
* to trigger to transfer video image at the tearing effect synchronization
* signal.
*/
void exynos_drm_crtc_te_handler(struct drm_crtc *crtc);
#endif

View file

@ -0,0 +1,285 @@
/* exynos_drm_dmabuf.c
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* Author: Inki Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <drm/drmP.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_dmabuf.h"
#include "exynos_drm_drv.h"
#include "exynos_drm_gem.h"
#include <linux/dma-buf.h>
struct exynos_drm_dmabuf_attachment {
struct sg_table sgt;
enum dma_data_direction dir;
bool is_mapped;
};
static struct exynos_drm_gem_obj *dma_buf_to_obj(struct dma_buf *buf)
{
return to_exynos_gem_obj(buf->priv);
}
static int exynos_gem_attach_dma_buf(struct dma_buf *dmabuf,
struct device *dev,
struct dma_buf_attachment *attach)
{
struct exynos_drm_dmabuf_attachment *exynos_attach;
exynos_attach = kzalloc(sizeof(*exynos_attach), GFP_KERNEL);
if (!exynos_attach)
return -ENOMEM;
exynos_attach->dir = DMA_NONE;
attach->priv = exynos_attach;
return 0;
}
static void exynos_gem_detach_dma_buf(struct dma_buf *dmabuf,
struct dma_buf_attachment *attach)
{
struct exynos_drm_dmabuf_attachment *exynos_attach = attach->priv;
struct sg_table *sgt;
if (!exynos_attach)
return;
sgt = &exynos_attach->sgt;
if (exynos_attach->dir != DMA_NONE)
dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
exynos_attach->dir);
sg_free_table(sgt);
kfree(exynos_attach);
attach->priv = NULL;
}
static struct sg_table *
exynos_gem_map_dma_buf(struct dma_buf_attachment *attach,
enum dma_data_direction dir)
{
struct exynos_drm_dmabuf_attachment *exynos_attach = attach->priv;
struct exynos_drm_gem_obj *gem_obj = dma_buf_to_obj(attach->dmabuf);
struct drm_device *dev = gem_obj->base.dev;
struct exynos_drm_gem_buf *buf;
struct scatterlist *rd, *wr;
struct sg_table *sgt = NULL;
unsigned int i;
int nents, ret;
/* just return current sgt if already requested. */
if (exynos_attach->dir == dir && exynos_attach->is_mapped)
return &exynos_attach->sgt;
buf = gem_obj->buffer;
if (!buf) {
DRM_ERROR("buffer is null.\n");
return ERR_PTR(-ENOMEM);
}
sgt = &exynos_attach->sgt;
ret = sg_alloc_table(sgt, buf->sgt->orig_nents, GFP_KERNEL);
if (ret) {
DRM_ERROR("failed to alloc sgt.\n");
return ERR_PTR(-ENOMEM);
}
mutex_lock(&dev->struct_mutex);
rd = buf->sgt->sgl;
wr = sgt->sgl;
for (i = 0; i < sgt->orig_nents; ++i) {
sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
rd = sg_next(rd);
wr = sg_next(wr);
}
if (dir != DMA_NONE) {
nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir);
if (!nents) {
DRM_ERROR("failed to map sgl with iommu.\n");
sg_free_table(sgt);
sgt = ERR_PTR(-EIO);
goto err_unlock;
}
}
exynos_attach->is_mapped = true;
exynos_attach->dir = dir;
attach->priv = exynos_attach;
DRM_DEBUG_PRIME("buffer size = 0x%lx\n", buf->size);
err_unlock:
mutex_unlock(&dev->struct_mutex);
return sgt;
}
static void exynos_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
struct sg_table *sgt,
enum dma_data_direction dir)
{
/* Nothing to do. */
}
static void *exynos_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf,
unsigned long page_num)
{
/* TODO */
return NULL;
}
static void exynos_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,
unsigned long page_num,
void *addr)
{
/* TODO */
}
static void *exynos_gem_dmabuf_kmap(struct dma_buf *dma_buf,
unsigned long page_num)
{
/* TODO */
return NULL;
}
static void exynos_gem_dmabuf_kunmap(struct dma_buf *dma_buf,
unsigned long page_num, void *addr)
{
/* TODO */
}
static int exynos_gem_dmabuf_mmap(struct dma_buf *dma_buf,
struct vm_area_struct *vma)
{
return -ENOTTY;
}
static struct dma_buf_ops exynos_dmabuf_ops = {
.attach = exynos_gem_attach_dma_buf,
.detach = exynos_gem_detach_dma_buf,
.map_dma_buf = exynos_gem_map_dma_buf,
.unmap_dma_buf = exynos_gem_unmap_dma_buf,
.kmap = exynos_gem_dmabuf_kmap,
.kmap_atomic = exynos_gem_dmabuf_kmap_atomic,
.kunmap = exynos_gem_dmabuf_kunmap,
.kunmap_atomic = exynos_gem_dmabuf_kunmap_atomic,
.mmap = exynos_gem_dmabuf_mmap,
.release = drm_gem_dmabuf_release,
};
struct dma_buf *exynos_dmabuf_prime_export(struct drm_device *drm_dev,
struct drm_gem_object *obj, int flags)
{
struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
return dma_buf_export(obj, &exynos_dmabuf_ops,
exynos_gem_obj->base.size, flags, NULL);
}
struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
struct dma_buf *dma_buf)
{
struct dma_buf_attachment *attach;
struct sg_table *sgt;
struct scatterlist *sgl;
struct exynos_drm_gem_obj *exynos_gem_obj;
struct exynos_drm_gem_buf *buffer;
int ret;
/* is this one of own objects? */
if (dma_buf->ops == &exynos_dmabuf_ops) {
struct drm_gem_object *obj;
obj = dma_buf->priv;
/* is it from our device? */
if (obj->dev == drm_dev) {
/*
* Importing dmabuf exported from out own gem increases
* refcount on gem itself instead of f_count of dmabuf.
*/
drm_gem_object_reference(obj);
return obj;
}
}
attach = dma_buf_attach(dma_buf, drm_dev->dev);
if (IS_ERR(attach))
return ERR_PTR(-EINVAL);
get_dma_buf(dma_buf);
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
if (IS_ERR(sgt)) {
ret = PTR_ERR(sgt);
goto err_buf_detach;
}
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer) {
ret = -ENOMEM;
goto err_unmap_attach;
}
exynos_gem_obj = exynos_drm_gem_init(drm_dev, dma_buf->size);
if (!exynos_gem_obj) {
ret = -ENOMEM;
goto err_free_buffer;
}
sgl = sgt->sgl;
buffer->size = dma_buf->size;
buffer->dma_addr = sg_dma_address(sgl);
if (sgt->nents == 1) {
/* always physically continuous memory if sgt->nents is 1. */
exynos_gem_obj->flags |= EXYNOS_BO_CONTIG;
} else {
/*
* this case could be CONTIG or NONCONTIG type but for now
* sets NONCONTIG.
* TODO. we have to find a way that exporter can notify
* the type of its own buffer to importer.
*/
exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG;
}
exynos_gem_obj->buffer = buffer;
buffer->sgt = sgt;
exynos_gem_obj->base.import_attach = attach;
DRM_DEBUG_PRIME("dma_addr = %pad, size = 0x%lx\n", &buffer->dma_addr,
buffer->size);
return &exynos_gem_obj->base;
err_free_buffer:
kfree(buffer);
buffer = NULL;
err_unmap_attach:
dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
err_buf_detach:
dma_buf_detach(dma_buf, attach);
dma_buf_put(dma_buf);
return ERR_PTR(ret);
}
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
MODULE_DESCRIPTION("Samsung SoC DRM DMABUF Module");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,25 @@
/* exynos_drm_dmabuf.h
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* Author: Inki Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_DMABUF_H_
#define _EXYNOS_DRM_DMABUF_H_
#ifdef CONFIG_DRM_EXYNOS_DMABUF
struct dma_buf *exynos_dmabuf_prime_export(struct drm_device *drm_dev,
struct drm_gem_object *obj, int flags);
struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
struct dma_buf *dma_buf);
#else
#define exynos_dmabuf_prime_export NULL
#define exynos_dmabuf_prime_import NULL
#endif
#endif

View file

@ -0,0 +1,351 @@
/*
* Exynos DRM Parallel output support.
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd
*
* Contacts: Andrzej Hajda <a.hajda@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 <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_panel.h>
#include <linux/regulator/consumer.h>
#include <video/of_videomode.h>
#include <video/videomode.h>
#include "exynos_drm_drv.h"
struct exynos_dpi {
struct device *dev;
struct device_node *panel_node;
struct drm_panel *panel;
struct drm_connector connector;
struct drm_encoder *encoder;
struct videomode *vm;
int dpms_mode;
};
#define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector)
static enum drm_connector_status
exynos_dpi_detect(struct drm_connector *connector, bool force)
{
struct exynos_dpi *ctx = connector_to_dpi(connector);
if (ctx->panel && !ctx->panel->connector)
drm_panel_attach(ctx->panel, &ctx->connector);
return connector_status_connected;
}
static void exynos_dpi_connector_destroy(struct drm_connector *connector)
{
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
}
static struct drm_connector_funcs exynos_dpi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.detect = exynos_dpi_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = exynos_dpi_connector_destroy,
};
static int exynos_dpi_get_modes(struct drm_connector *connector)
{
struct exynos_dpi *ctx = connector_to_dpi(connector);
/* fimd timings gets precedence over panel modes */
if (ctx->vm) {
struct drm_display_mode *mode;
mode = drm_mode_create(connector->dev);
if (!mode) {
DRM_ERROR("failed to create a new display mode\n");
return 0;
}
drm_display_mode_from_videomode(ctx->vm, mode);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
return 1;
}
if (ctx->panel)
return ctx->panel->funcs->get_modes(ctx->panel);
return 0;
}
static struct drm_encoder *
exynos_dpi_best_encoder(struct drm_connector *connector)
{
struct exynos_dpi *ctx = connector_to_dpi(connector);
return ctx->encoder;
}
static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
.get_modes = exynos_dpi_get_modes,
.best_encoder = exynos_dpi_best_encoder,
};
static int exynos_dpi_create_connector(struct exynos_drm_display *display,
struct drm_encoder *encoder)
{
struct exynos_dpi *ctx = display->ctx;
struct drm_connector *connector = &ctx->connector;
int ret;
ctx->encoder = encoder;
connector->polled = DRM_CONNECTOR_POLL_HPD;
ret = drm_connector_init(encoder->dev, connector,
&exynos_dpi_connector_funcs,
DRM_MODE_CONNECTOR_VGA);
if (ret) {
DRM_ERROR("failed to initialize connector with drm\n");
return ret;
}
drm_connector_helper_add(connector, &exynos_dpi_connector_helper_funcs);
drm_connector_register(connector);
drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}
static void exynos_dpi_poweron(struct exynos_dpi *ctx)
{
if (ctx->panel) {
drm_panel_prepare(ctx->panel);
drm_panel_enable(ctx->panel);
}
}
static void exynos_dpi_poweroff(struct exynos_dpi *ctx)
{
if (ctx->panel) {
drm_panel_disable(ctx->panel);
drm_panel_unprepare(ctx->panel);
}
}
static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode)
{
struct exynos_dpi *ctx = display->ctx;
switch (mode) {
case DRM_MODE_DPMS_ON:
if (ctx->dpms_mode != DRM_MODE_DPMS_ON)
exynos_dpi_poweron(ctx);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
if (ctx->dpms_mode == DRM_MODE_DPMS_ON)
exynos_dpi_poweroff(ctx);
break;
default:
break;
}
ctx->dpms_mode = mode;
}
static struct exynos_drm_display_ops exynos_dpi_display_ops = {
.create_connector = exynos_dpi_create_connector,
.dpms = exynos_dpi_dpms
};
static struct exynos_drm_display exynos_dpi_display = {
.type = EXYNOS_DISPLAY_TYPE_LCD,
.ops = &exynos_dpi_display_ops,
};
/* of_* functions will be removed after merge of of_graph patches */
static struct device_node *
of_get_child_by_name_reg(struct device_node *parent, const char *name, u32 reg)
{
struct device_node *np;
for_each_child_of_node(parent, np) {
u32 r;
if (!np->name || of_node_cmp(np->name, name))
continue;
if (of_property_read_u32(np, "reg", &r) < 0)
r = 0;
if (reg == r)
break;
}
return np;
}
static struct device_node *of_graph_get_port_by_reg(struct device_node *parent,
u32 reg)
{
struct device_node *ports, *port;
ports = of_get_child_by_name(parent, "ports");
if (ports)
parent = ports;
port = of_get_child_by_name_reg(parent, "port", reg);
of_node_put(ports);
return port;
}
static struct device_node *
of_graph_get_endpoint_by_reg(struct device_node *port, u32 reg)
{
return of_get_child_by_name_reg(port, "endpoint", reg);
}
static struct device_node *
of_graph_get_remote_port_parent(const struct device_node *node)
{
struct device_node *np;
unsigned int depth;
np = of_parse_phandle(node, "remote-endpoint", 0);
/* Walk 3 levels up only if there is 'ports' node. */
for (depth = 3; depth && np; depth--) {
np = of_get_next_parent(np);
if (depth == 2 && of_node_cmp(np->name, "ports"))
break;
}
return np;
}
enum {
FIMD_PORT_IN0,
FIMD_PORT_IN1,
FIMD_PORT_IN2,
FIMD_PORT_RGB,
FIMD_PORT_WRB,
};
static struct device_node *exynos_dpi_of_find_panel_node(struct device *dev)
{
struct device_node *np, *ep;
np = of_graph_get_port_by_reg(dev->of_node, FIMD_PORT_RGB);
if (!np)
return NULL;
ep = of_graph_get_endpoint_by_reg(np, 0);
of_node_put(np);
if (!ep)
return NULL;
np = of_graph_get_remote_port_parent(ep);
of_node_put(ep);
return np;
}
static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
{
struct device *dev = ctx->dev;
struct device_node *dn = dev->of_node;
struct device_node *np;
ctx->panel_node = exynos_dpi_of_find_panel_node(dev);
np = of_get_child_by_name(dn, "display-timings");
if (np) {
struct videomode *vm;
int ret;
of_node_put(np);
vm = devm_kzalloc(dev, sizeof(*ctx->vm), GFP_KERNEL);
if (!vm)
return -ENOMEM;
ret = of_get_videomode(dn, vm, 0);
if (ret < 0) {
devm_kfree(dev, vm);
return ret;
}
ctx->vm = vm;
return 0;
}
if (!ctx->panel_node)
return -EINVAL;
return 0;
}
struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
{
struct exynos_dpi *ctx;
int ret;
ret = exynos_drm_component_add(dev,
EXYNOS_DEVICE_TYPE_CONNECTOR,
exynos_dpi_display.type);
if (ret)
return ERR_PTR(ret);
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
goto err_del_component;
ctx->dev = dev;
exynos_dpi_display.ctx = ctx;
ctx->dpms_mode = DRM_MODE_DPMS_OFF;
ret = exynos_dpi_parse_dt(ctx);
if (ret < 0) {
devm_kfree(dev, ctx);
goto err_del_component;
}
if (ctx->panel_node) {
ctx->panel = of_drm_find_panel(ctx->panel_node);
if (!ctx->panel) {
exynos_drm_component_del(dev,
EXYNOS_DEVICE_TYPE_CONNECTOR);
return ERR_PTR(-EPROBE_DEFER);
}
}
return &exynos_dpi_display;
err_del_component:
exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
return NULL;
}
int exynos_dpi_remove(struct device *dev)
{
struct exynos_dpi *ctx = exynos_dpi_display.ctx;
exynos_dpi_dpms(&exynos_dpi_display, DRM_MODE_DPMS_OFF);
if (ctx->panel)
drm_panel_detach(ctx->panel);
exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
return 0;
}

View file

@ -0,0 +1,805 @@
/*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/pm_runtime.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <linux/component.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
#include "exynos_drm_encoder.h"
#include "exynos_drm_fbdev.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_plane.h"
#include "exynos_drm_vidi.h"
#include "exynos_drm_dmabuf.h"
#include "exynos_drm_g2d.h"
#include "exynos_drm_ipp.h"
#include "exynos_drm_iommu.h"
#define DRIVER_NAME "exynos"
#define DRIVER_DESC "Samsung SoC DRM"
#define DRIVER_DATE "20110530"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0
static struct platform_device *exynos_drm_pdev;
static DEFINE_MUTEX(drm_component_lock);
static LIST_HEAD(drm_component_list);
struct component_dev {
struct list_head list;
struct device *crtc_dev;
struct device *conn_dev;
enum exynos_drm_output_type out_type;
unsigned int dev_type_flag;
};
static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
{
struct exynos_drm_private *private;
int ret;
int nr;
private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
if (!private)
return -ENOMEM;
INIT_LIST_HEAD(&private->pageflip_event_list);
dev_set_drvdata(dev->dev, dev);
dev->dev_private = (void *)private;
/*
* create mapping to manage iommu table and set a pointer to iommu
* mapping structure to iommu_mapping of private data.
* also this iommu_mapping can be used to check if iommu is supported
* or not.
*/
ret = drm_create_iommu_mapping(dev);
if (ret < 0) {
DRM_ERROR("failed to create iommu mapping.\n");
goto err_free_private;
}
drm_mode_config_init(dev);
exynos_drm_mode_config_init(dev);
for (nr = 0; nr < MAX_PLANE; nr++) {
struct drm_plane *plane;
unsigned long possible_crtcs = (1 << MAX_CRTC) - 1;
plane = exynos_plane_init(dev, possible_crtcs,
DRM_PLANE_TYPE_OVERLAY);
if (!IS_ERR(plane))
continue;
ret = PTR_ERR(plane);
goto err_mode_config_cleanup;
}
/* setup possible_clones. */
exynos_drm_encoder_setup(dev);
platform_set_drvdata(dev->platformdev, dev);
/* Try to bind all sub drivers. */
ret = component_bind_all(dev->dev, dev);
if (ret)
goto err_mode_config_cleanup;
ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
if (ret)
goto err_unbind_all;
/* Probe non kms sub drivers and virtual display driver. */
ret = exynos_drm_device_subdrv_probe(dev);
if (ret)
goto err_cleanup_vblank;
/*
* enable drm irq mode.
* - with irq_enabled = true, we can use the vblank feature.
*
* P.S. note that we wouldn't use drm irq handler but
* just specific driver own one instead because
* drm framework supports only one irq handler.
*/
dev->irq_enabled = true;
/*
* with vblank_disable_allowed = true, vblank interrupt will be disabled
* by drm timer once a current process gives up ownership of
* vblank event.(after drm_vblank_put function is called)
*/
dev->vblank_disable_allowed = true;
/* init kms poll for handling hpd */
drm_kms_helper_poll_init(dev);
/* force connectors detection */
drm_helper_hpd_irq_event(dev);
return 0;
err_cleanup_vblank:
drm_vblank_cleanup(dev);
err_unbind_all:
component_unbind_all(dev->dev, dev);
err_mode_config_cleanup:
drm_mode_config_cleanup(dev);
drm_release_iommu_mapping(dev);
err_free_private:
kfree(private);
return ret;
}
static int exynos_drm_unload(struct drm_device *dev)
{
exynos_drm_device_subdrv_remove(dev);
exynos_drm_fbdev_fini(dev);
drm_kms_helper_poll_fini(dev);
drm_vblank_cleanup(dev);
component_unbind_all(dev->dev, dev);
drm_mode_config_cleanup(dev);
drm_release_iommu_mapping(dev);
kfree(dev->dev_private);
dev->dev_private = NULL;
return 0;
}
static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state)
{
struct drm_connector *connector;
drm_modeset_lock_all(dev);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
int old_dpms = connector->dpms;
if (connector->funcs->dpms)
connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
/* Set the old mode back to the connector for resume */
connector->dpms = old_dpms;
}
drm_modeset_unlock_all(dev);
return 0;
}
static int exynos_drm_resume(struct drm_device *dev)
{
struct drm_connector *connector;
drm_modeset_lock_all(dev);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->funcs->dpms) {
int dpms = connector->dpms;
connector->dpms = DRM_MODE_DPMS_OFF;
connector->funcs->dpms(connector, dpms);
}
}
drm_modeset_unlock_all(dev);
drm_helper_resume_force_mode(dev);
return 0;
}
static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
{
struct drm_exynos_file_private *file_priv;
int ret;
file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
if (!file_priv)
return -ENOMEM;
file->driver_priv = file_priv;
ret = exynos_drm_subdrv_open(dev, file);
if (ret)
goto err_file_priv_free;
return ret;
err_file_priv_free:
kfree(file_priv);
file->driver_priv = NULL;
return ret;
}
static void exynos_drm_preclose(struct drm_device *dev,
struct drm_file *file)
{
exynos_drm_subdrv_close(dev, file);
}
static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
{
struct exynos_drm_private *private = dev->dev_private;
struct drm_pending_vblank_event *v, *vt;
struct drm_pending_event *e, *et;
unsigned long flags;
if (!file->driver_priv)
return;
/* Release all events not unhandled by page flip handler. */
spin_lock_irqsave(&dev->event_lock, flags);
list_for_each_entry_safe(v, vt, &private->pageflip_event_list,
base.link) {
if (v->base.file_priv == file) {
list_del(&v->base.link);
drm_vblank_put(dev, v->pipe);
v->base.destroy(&v->base);
}
}
/* Release all events handled by page flip handler but not freed. */
list_for_each_entry_safe(e, et, &file->event_list, link) {
list_del(&e->link);
e->destroy(e);
}
spin_unlock_irqrestore(&dev->event_lock, flags);
kfree(file->driver_priv);
file->driver_priv = NULL;
}
static void exynos_drm_lastclose(struct drm_device *dev)
{
exynos_drm_fbdev_restore_mode(dev);
}
static const struct vm_operations_struct exynos_drm_gem_vm_ops = {
.fault = exynos_drm_gem_fault,
.open = drm_gem_vm_open,
.close = drm_gem_vm_close,
};
static const struct drm_ioctl_desc exynos_ioctls[] = {
DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl,
DRM_UNLOCKED | DRM_AUTH),
DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET,
exynos_drm_gem_get_ioctl, DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER,
exynos_g2d_get_ver_ioctl, DRM_UNLOCKED | DRM_AUTH),
DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST,
exynos_g2d_set_cmdlist_ioctl, DRM_UNLOCKED | DRM_AUTH),
DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC,
exynos_g2d_exec_ioctl, DRM_UNLOCKED | DRM_AUTH),
DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY,
exynos_drm_ipp_get_property, DRM_UNLOCKED | DRM_AUTH),
DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY,
exynos_drm_ipp_set_property, DRM_UNLOCKED | DRM_AUTH),
DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF,
exynos_drm_ipp_queue_buf, DRM_UNLOCKED | DRM_AUTH),
DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL,
exynos_drm_ipp_cmd_ctrl, DRM_UNLOCKED | DRM_AUTH),
};
static const struct file_operations exynos_drm_driver_fops = {
.owner = THIS_MODULE,
.open = drm_open,
.mmap = exynos_drm_gem_mmap,
.poll = drm_poll,
.read = drm_read,
.unlocked_ioctl = drm_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = drm_compat_ioctl,
#endif
.release = drm_release,
};
static struct drm_driver exynos_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
.load = exynos_drm_load,
.unload = exynos_drm_unload,
.suspend = exynos_drm_suspend,
.resume = exynos_drm_resume,
.open = exynos_drm_open,
.preclose = exynos_drm_preclose,
.lastclose = exynos_drm_lastclose,
.postclose = exynos_drm_postclose,
.set_busid = drm_platform_set_busid,
.get_vblank_counter = drm_vblank_count,
.enable_vblank = exynos_drm_crtc_enable_vblank,
.disable_vblank = exynos_drm_crtc_disable_vblank,
.gem_free_object = exynos_drm_gem_free_object,
.gem_vm_ops = &exynos_drm_gem_vm_ops,
.dumb_create = exynos_drm_gem_dumb_create,
.dumb_map_offset = exynos_drm_gem_dumb_map_offset,
.dumb_destroy = drm_gem_dumb_destroy,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_export = exynos_dmabuf_prime_export,
.gem_prime_import = exynos_dmabuf_prime_import,
.ioctls = exynos_ioctls,
.num_ioctls = ARRAY_SIZE(exynos_ioctls),
.fops = &exynos_drm_driver_fops,
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
};
#ifdef CONFIG_PM_SLEEP
static int exynos_drm_sys_suspend(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
pm_message_t message;
if (pm_runtime_suspended(dev) || !drm_dev)
return 0;
message.event = PM_EVENT_SUSPEND;
return exynos_drm_suspend(drm_dev, message);
}
static int exynos_drm_sys_resume(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
if (pm_runtime_suspended(dev) || !drm_dev)
return 0;
return exynos_drm_resume(drm_dev);
}
#endif
static const struct dev_pm_ops exynos_drm_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume)
};
int exynos_drm_component_add(struct device *dev,
enum exynos_drm_device_type dev_type,
enum exynos_drm_output_type out_type)
{
struct component_dev *cdev;
if (dev_type != EXYNOS_DEVICE_TYPE_CRTC &&
dev_type != EXYNOS_DEVICE_TYPE_CONNECTOR) {
DRM_ERROR("invalid device type.\n");
return -EINVAL;
}
mutex_lock(&drm_component_lock);
/*
* Make sure to check if there is a component which has two device
* objects, for connector and for encoder/connector.
* It should make sure that crtc and encoder/connector drivers are
* ready before exynos drm core binds them.
*/
list_for_each_entry(cdev, &drm_component_list, list) {
if (cdev->out_type == out_type) {
/*
* If crtc and encoder/connector device objects are
* added already just return.
*/
if (cdev->dev_type_flag == (EXYNOS_DEVICE_TYPE_CRTC |
EXYNOS_DEVICE_TYPE_CONNECTOR)) {
mutex_unlock(&drm_component_lock);
return 0;
}
if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) {
cdev->crtc_dev = dev;
cdev->dev_type_flag |= dev_type;
}
if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) {
cdev->conn_dev = dev;
cdev->dev_type_flag |= dev_type;
}
mutex_unlock(&drm_component_lock);
return 0;
}
}
mutex_unlock(&drm_component_lock);
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return -ENOMEM;
if (dev_type == EXYNOS_DEVICE_TYPE_CRTC)
cdev->crtc_dev = dev;
if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR)
cdev->conn_dev = dev;
cdev->out_type = out_type;
cdev->dev_type_flag = dev_type;
mutex_lock(&drm_component_lock);
list_add_tail(&cdev->list, &drm_component_list);
mutex_unlock(&drm_component_lock);
return 0;
}
void exynos_drm_component_del(struct device *dev,
enum exynos_drm_device_type dev_type)
{
struct component_dev *cdev, *next;
mutex_lock(&drm_component_lock);
list_for_each_entry_safe(cdev, next, &drm_component_list, list) {
if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) {
if (cdev->crtc_dev == dev) {
cdev->crtc_dev = NULL;
cdev->dev_type_flag &= ~dev_type;
}
}
if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) {
if (cdev->conn_dev == dev) {
cdev->conn_dev = NULL;
cdev->dev_type_flag &= ~dev_type;
}
}
/*
* Release cdev object only in case that both of crtc and
* encoder/connector device objects are NULL.
*/
if (!cdev->crtc_dev && !cdev->conn_dev) {
list_del(&cdev->list);
kfree(cdev);
}
break;
}
mutex_unlock(&drm_component_lock);
}
static int compare_dev(struct device *dev, void *data)
{
return dev == (struct device *)data;
}
static struct component_match *exynos_drm_match_add(struct device *dev)
{
struct component_match *match = NULL;
struct component_dev *cdev;
unsigned int attach_cnt = 0;
mutex_lock(&drm_component_lock);
/* Do not retry to probe if there is no any kms driver regitered. */
if (list_empty(&drm_component_list)) {
mutex_unlock(&drm_component_lock);
return ERR_PTR(-ENODEV);
}
list_for_each_entry(cdev, &drm_component_list, list) {
/*
* Add components to master only in case that crtc and
* encoder/connector device objects exist.
*/
if (!cdev->crtc_dev || !cdev->conn_dev)
continue;
attach_cnt++;
mutex_unlock(&drm_component_lock);
/*
* fimd and dpi modules have same device object so add
* only crtc device object in this case.
*/
if (cdev->crtc_dev == cdev->conn_dev) {
component_match_add(dev, &match, compare_dev,
cdev->crtc_dev);
goto out_lock;
}
/*
* Do not chage below call order.
* crtc device first should be added to master because
* connector/encoder need pipe number of crtc when they
* are created.
*/
component_match_add(dev, &match, compare_dev, cdev->crtc_dev);
component_match_add(dev, &match, compare_dev, cdev->conn_dev);
out_lock:
mutex_lock(&drm_component_lock);
}
mutex_unlock(&drm_component_lock);
return attach_cnt ? match : ERR_PTR(-EPROBE_DEFER);
}
static int exynos_drm_bind(struct device *dev)
{
return drm_platform_init(&exynos_drm_driver, to_platform_device(dev));
}
static void exynos_drm_unbind(struct device *dev)
{
drm_put_dev(dev_get_drvdata(dev));
}
static const struct component_master_ops exynos_drm_ops = {
.bind = exynos_drm_bind,
.unbind = exynos_drm_unbind,
};
static int exynos_drm_platform_probe(struct platform_device *pdev)
{
struct component_match *match;
int ret;
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls);
#ifdef CONFIG_DRM_EXYNOS_FIMD
ret = platform_driver_register(&fimd_driver);
if (ret < 0)
return ret;
#endif
#ifdef CONFIG_DRM_EXYNOS_DP
ret = platform_driver_register(&dp_driver);
if (ret < 0)
goto err_unregister_fimd_drv;
#endif
#ifdef CONFIG_DRM_EXYNOS_DSI
ret = platform_driver_register(&dsi_driver);
if (ret < 0)
goto err_unregister_dp_drv;
#endif
#ifdef CONFIG_DRM_EXYNOS_HDMI
ret = platform_driver_register(&mixer_driver);
if (ret < 0)
goto err_unregister_dsi_drv;
ret = platform_driver_register(&hdmi_driver);
if (ret < 0)
goto err_unregister_mixer_drv;
#endif
match = exynos_drm_match_add(&pdev->dev);
if (IS_ERR(match)) {
ret = PTR_ERR(match);
goto err_unregister_hdmi_drv;
}
ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops,
match);
if (ret < 0)
goto err_unregister_hdmi_drv;
#ifdef CONFIG_DRM_EXYNOS_G2D
ret = platform_driver_register(&g2d_driver);
if (ret < 0)
goto err_del_component_master;
#endif
#ifdef CONFIG_DRM_EXYNOS_FIMC
ret = platform_driver_register(&fimc_driver);
if (ret < 0)
goto err_unregister_g2d_drv;
#endif
#ifdef CONFIG_DRM_EXYNOS_ROTATOR
ret = platform_driver_register(&rotator_driver);
if (ret < 0)
goto err_unregister_fimc_drv;
#endif
#ifdef CONFIG_DRM_EXYNOS_GSC
ret = platform_driver_register(&gsc_driver);
if (ret < 0)
goto err_unregister_rotator_drv;
#endif
#ifdef CONFIG_DRM_EXYNOS_IPP
ret = platform_driver_register(&ipp_driver);
if (ret < 0)
goto err_unregister_gsc_drv;
ret = exynos_platform_device_ipp_register();
if (ret < 0)
goto err_unregister_ipp_drv;
#endif
return ret;
#ifdef CONFIG_DRM_EXYNOS_IPP
err_unregister_ipp_drv:
platform_driver_unregister(&ipp_driver);
err_unregister_gsc_drv:
#endif
#ifdef CONFIG_DRM_EXYNOS_GSC
platform_driver_unregister(&gsc_driver);
err_unregister_rotator_drv:
#endif
#ifdef CONFIG_DRM_EXYNOS_ROTATOR
platform_driver_unregister(&rotator_driver);
err_unregister_fimc_drv:
#endif
#ifdef CONFIG_DRM_EXYNOS_FIMC
platform_driver_unregister(&fimc_driver);
err_unregister_g2d_drv:
#endif
#ifdef CONFIG_DRM_EXYNOS_G2D
platform_driver_unregister(&g2d_driver);
err_del_component_master:
#endif
component_master_del(&pdev->dev, &exynos_drm_ops);
err_unregister_hdmi_drv:
#ifdef CONFIG_DRM_EXYNOS_HDMI
platform_driver_unregister(&hdmi_driver);
err_unregister_mixer_drv:
platform_driver_unregister(&mixer_driver);
err_unregister_dsi_drv:
#endif
#ifdef CONFIG_DRM_EXYNOS_DSI
platform_driver_unregister(&dsi_driver);
err_unregister_dp_drv:
#endif
#ifdef CONFIG_DRM_EXYNOS_DP
platform_driver_unregister(&dp_driver);
err_unregister_fimd_drv:
#endif
#ifdef CONFIG_DRM_EXYNOS_FIMD
platform_driver_unregister(&fimd_driver);
#endif
return ret;
}
static int exynos_drm_platform_remove(struct platform_device *pdev)
{
#ifdef CONFIG_DRM_EXYNOS_IPP
exynos_platform_device_ipp_unregister();
platform_driver_unregister(&ipp_driver);
#endif
#ifdef CONFIG_DRM_EXYNOS_GSC
platform_driver_unregister(&gsc_driver);
#endif
#ifdef CONFIG_DRM_EXYNOS_ROTATOR
platform_driver_unregister(&rotator_driver);
#endif
#ifdef CONFIG_DRM_EXYNOS_FIMC
platform_driver_unregister(&fimc_driver);
#endif
#ifdef CONFIG_DRM_EXYNOS_G2D
platform_driver_unregister(&g2d_driver);
#endif
#ifdef CONFIG_DRM_EXYNOS_HDMI
platform_driver_unregister(&mixer_driver);
platform_driver_unregister(&hdmi_driver);
#endif
#ifdef CONFIG_DRM_EXYNOS_FIMD
platform_driver_unregister(&fimd_driver);
#endif
#ifdef CONFIG_DRM_EXYNOS_DSI
platform_driver_unregister(&dsi_driver);
#endif
#ifdef CONFIG_DRM_EXYNOS_DP
platform_driver_unregister(&dp_driver);
#endif
component_master_del(&pdev->dev, &exynos_drm_ops);
return 0;
}
static struct platform_driver exynos_drm_platform_driver = {
.probe = exynos_drm_platform_probe,
.remove = exynos_drm_platform_remove,
.driver = {
.owner = THIS_MODULE,
.name = "exynos-drm",
.pm = &exynos_drm_pm_ops,
},
};
static int exynos_drm_init(void)
{
int ret;
/*
* Register device object only in case of Exynos SoC.
*
* Below codes resolves temporarily infinite loop issue incurred
* by Exynos drm driver when using multi-platform kernel.
* So these codes will be replaced with more generic way later.
*/
if (!of_machine_is_compatible("samsung,exynos3") &&
!of_machine_is_compatible("samsung,exynos4") &&
!of_machine_is_compatible("samsung,exynos5"))
return -ENODEV;
exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1,
NULL, 0);
if (IS_ERR(exynos_drm_pdev))
return PTR_ERR(exynos_drm_pdev);
#ifdef CONFIG_DRM_EXYNOS_VIDI
ret = exynos_drm_probe_vidi();
if (ret < 0)
goto err_unregister_pd;
#endif
ret = platform_driver_register(&exynos_drm_platform_driver);
if (ret)
goto err_remove_vidi;
return 0;
err_remove_vidi:
#ifdef CONFIG_DRM_EXYNOS_VIDI
exynos_drm_remove_vidi();
err_unregister_pd:
#endif
platform_device_unregister(exynos_drm_pdev);
return ret;
}
static void exynos_drm_exit(void)
{
platform_driver_unregister(&exynos_drm_platform_driver);
#ifdef CONFIG_DRM_EXYNOS_VIDI
exynos_drm_remove_vidi();
#endif
platform_device_unregister(exynos_drm_pdev);
}
module_init(exynos_drm_init);
module_exit(exynos_drm_exit);
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
MODULE_DESCRIPTION("Samsung SoC DRM Driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,378 @@
/* exynos_drm_drv.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_DRV_H_
#define _EXYNOS_DRM_DRV_H_
#include <linux/module.h>
#define MAX_CRTC 3
#define MAX_PLANE 5
#define MAX_FB_BUFFER 4
#define DEFAULT_ZPOS -1
#define _wait_for(COND, MS) ({ \
unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \
int ret__ = 0; \
while (!(COND)) { \
if (time_after(jiffies, timeout__)) { \
ret__ = -ETIMEDOUT; \
break; \
} \
} \
ret__; \
})
#define wait_for(COND, MS) _wait_for(COND, MS)
struct drm_device;
struct exynos_drm_overlay;
struct drm_connector;
/* This enumerates device type. */
enum exynos_drm_device_type {
EXYNOS_DEVICE_TYPE_NONE,
EXYNOS_DEVICE_TYPE_CRTC,
EXYNOS_DEVICE_TYPE_CONNECTOR,
};
/* this enumerates display type. */
enum exynos_drm_output_type {
EXYNOS_DISPLAY_TYPE_NONE,
/* RGB or CPU Interface. */
EXYNOS_DISPLAY_TYPE_LCD,
/* HDMI Interface. */
EXYNOS_DISPLAY_TYPE_HDMI,
/* Virtual Display Interface. */
EXYNOS_DISPLAY_TYPE_VIDI,
};
/*
* Exynos drm common overlay structure.
*
* @fb_x: offset x on a framebuffer to be displayed.
* - the unit is screen coordinates.
* @fb_y: offset y on a framebuffer to be displayed.
* - the unit is screen coordinates.
* @fb_width: width of a framebuffer.
* @fb_height: height of a framebuffer.
* @src_width: width of a partial image to be displayed from framebuffer.
* @src_height: height of a partial image to be displayed from framebuffer.
* @crtc_x: offset x on hardware screen.
* @crtc_y: offset y on hardware screen.
* @crtc_width: window width to be displayed (hardware screen).
* @crtc_height: window height to be displayed (hardware screen).
* @mode_width: width of screen mode.
* @mode_height: height of screen mode.
* @refresh: refresh rate.
* @scan_flag: interlace or progressive way.
* (it could be DRM_MODE_FLAG_*)
* @bpp: pixel size.(in bit)
* @pixel_format: fourcc pixel format of this overlay
* @dma_addr: array of bus(accessed by dma) address to the memory region
* allocated for a overlay.
* @zpos: order of overlay layer(z position).
* @default_win: a window to be enabled.
* @color_key: color key on or off.
* @index_color: if using color key feature then this value would be used
* as index color.
* @local_path: in case of lcd type, local path mode on or off.
* @transparency: transparency on or off.
* @activated: activated or not.
*
* this structure is common to exynos SoC and its contents would be copied
* to hardware specific overlay info.
*/
struct exynos_drm_overlay {
unsigned int fb_x;
unsigned int fb_y;
unsigned int fb_width;
unsigned int fb_height;
unsigned int src_width;
unsigned int src_height;
unsigned int crtc_x;
unsigned int crtc_y;
unsigned int crtc_width;
unsigned int crtc_height;
unsigned int mode_width;
unsigned int mode_height;
unsigned int refresh;
unsigned int scan_flag;
unsigned int bpp;
unsigned int pitch;
uint32_t pixel_format;
dma_addr_t dma_addr[MAX_FB_BUFFER];
int zpos;
bool default_win;
bool color_key;
unsigned int index_color;
bool local_path;
bool transparency;
bool activated;
};
/*
* Exynos DRM Display Structure.
* - this structure is common to analog tv, digital tv and lcd panel.
*
* @remove: cleans up the display for removal
* @mode_fixup: fix mode data comparing to hw specific display mode.
* @mode_set: convert drm_display_mode to hw specific display mode and
* would be called by encoder->mode_set().
* @check_mode: check if mode is valid or not.
* @dpms: display device on or off.
* @commit: apply changes to hw
*/
struct exynos_drm_display;
struct exynos_drm_display_ops {
int (*create_connector)(struct exynos_drm_display *display,
struct drm_encoder *encoder);
void (*remove)(struct exynos_drm_display *display);
void (*mode_fixup)(struct exynos_drm_display *display,
struct drm_connector *connector,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
void (*mode_set)(struct exynos_drm_display *display,
struct drm_display_mode *mode);
int (*check_mode)(struct exynos_drm_display *display,
struct drm_display_mode *mode);
void (*dpms)(struct exynos_drm_display *display, int mode);
void (*commit)(struct exynos_drm_display *display);
};
/*
* Exynos drm display structure, maps 1:1 with an encoder/connector
*
* @list: the list entry for this manager
* @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
* @encoder: encoder object this display maps to
* @connector: connector object this display maps to
* @ops: pointer to callbacks for exynos drm specific functionality
* @ctx: A pointer to the display's implementation specific context
*/
struct exynos_drm_display {
struct list_head list;
enum exynos_drm_output_type type;
struct drm_encoder *encoder;
struct drm_connector *connector;
struct exynos_drm_display_ops *ops;
void *ctx;
};
/*
* Exynos drm manager ops
*
* @dpms: control device power.
* @mode_fixup: fix mode data before applying it
* @mode_set: set the given mode to the manager
* @commit: set current hw specific display mode to hw.
* @enable_vblank: specific driver callback for enabling vblank interrupt.
* @disable_vblank: specific driver callback for disabling vblank interrupt.
* @wait_for_vblank: wait for vblank interrupt to make sure that
* hardware overlay is updated.
* @win_mode_set: copy drm overlay info to hw specific overlay info.
* @win_commit: apply hardware specific overlay data to registers.
* @win_enable: enable hardware specific overlay.
* @win_disable: disable hardware specific overlay.
* @te_handler: trigger to transfer video image at the tearing effect
* synchronization signal if there is a page flip request.
*/
struct exynos_drm_manager;
struct exynos_drm_manager_ops {
void (*dpms)(struct exynos_drm_manager *mgr, int mode);
bool (*mode_fixup)(struct exynos_drm_manager *mgr,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
void (*mode_set)(struct exynos_drm_manager *mgr,
const struct drm_display_mode *mode);
void (*commit)(struct exynos_drm_manager *mgr);
int (*enable_vblank)(struct exynos_drm_manager *mgr);
void (*disable_vblank)(struct exynos_drm_manager *mgr);
void (*wait_for_vblank)(struct exynos_drm_manager *mgr);
void (*win_mode_set)(struct exynos_drm_manager *mgr,
struct exynos_drm_overlay *overlay);
void (*win_commit)(struct exynos_drm_manager *mgr, int zpos);
void (*win_enable)(struct exynos_drm_manager *mgr, int zpos);
void (*win_disable)(struct exynos_drm_manager *mgr, int zpos);
void (*te_handler)(struct exynos_drm_manager *mgr);
};
/*
* Exynos drm common manager structure, maps 1:1 with a crtc
*
* @list: the list entry for this manager
* @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
* @drm_dev: pointer to the drm device
* @crtc: crtc object.
* @pipe: the pipe number for this crtc/manager
* @ops: pointer to callbacks for exynos drm specific functionality
* @ctx: A pointer to the manager's implementation specific context
*/
struct exynos_drm_manager {
struct list_head list;
enum exynos_drm_output_type type;
struct drm_device *drm_dev;
struct drm_crtc *crtc;
int pipe;
struct exynos_drm_manager_ops *ops;
void *ctx;
};
struct exynos_drm_g2d_private {
struct device *dev;
struct list_head inuse_cmdlist;
struct list_head event_list;
struct list_head userptr_list;
};
struct drm_exynos_file_private {
struct exynos_drm_g2d_private *g2d_priv;
struct device *ipp_dev;
};
/*
* Exynos drm private structure.
*
* @da_start: start address to device address space.
* with iommu, device address space starts from this address
* otherwise default one.
* @da_space_size: size of device address space.
* if 0 then default value is used for it.
* @pipe: the pipe number for this crtc/manager.
*/
struct exynos_drm_private {
struct drm_fb_helper *fb_helper;
/* list head for new event to be added. */
struct list_head pageflip_event_list;
/*
* created crtc object would be contained at this array and
* this array is used to be aware of which crtc did it request vblank.
*/
struct drm_crtc *crtc[MAX_CRTC];
struct drm_property *plane_zpos_property;
struct drm_property *crtc_mode_property;
unsigned long da_start;
unsigned long da_space_size;
unsigned int pipe;
};
/*
* Exynos drm sub driver structure.
*
* @list: sub driver has its own list object to register to exynos drm driver.
* @dev: pointer to device object for subdrv device driver.
* @drm_dev: pointer to drm_device and this pointer would be set
* when sub driver calls exynos_drm_subdrv_register().
* @manager: subdrv has its own manager to control a hardware appropriately
* and we can access a hardware drawing on this manager.
* @probe: this callback would be called by exynos drm driver after
* subdrv is registered to it.
* @remove: this callback is used to release resources created
* by probe callback.
* @open: this would be called with drm device file open.
* @close: this would be called with drm device file close.
*/
struct exynos_drm_subdrv {
struct list_head list;
struct device *dev;
struct drm_device *drm_dev;
int (*probe)(struct drm_device *drm_dev, struct device *dev);
void (*remove)(struct drm_device *drm_dev, struct device *dev);
int (*open)(struct drm_device *drm_dev, struct device *dev,
struct drm_file *file);
void (*close)(struct drm_device *drm_dev, struct device *dev,
struct drm_file *file);
};
/* This function would be called by non kms drivers such as g2d and ipp. */
int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv);
/* this function removes subdrv list from exynos drm driver */
int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv);
int exynos_drm_device_subdrv_probe(struct drm_device *dev);
int exynos_drm_device_subdrv_remove(struct drm_device *dev);
int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
/*
* this function registers exynos drm hdmi platform device. It ensures only one
* instance of the device is created.
*/
int exynos_platform_device_hdmi_register(void);
/*
* this function unregisters exynos drm hdmi platform device if it exists.
*/
void exynos_platform_device_hdmi_unregister(void);
/*
* this function registers exynos drm ipp platform device.
*/
int exynos_platform_device_ipp_register(void);
/*
* this function unregisters exynos drm ipp platform device if it exists.
*/
void exynos_platform_device_ipp_unregister(void);
#ifdef CONFIG_DRM_EXYNOS_DPI
struct exynos_drm_display * exynos_dpi_probe(struct device *dev);
int exynos_dpi_remove(struct device *dev);
#else
static inline struct exynos_drm_display *
exynos_dpi_probe(struct device *dev) { return NULL; }
static inline int exynos_dpi_remove(struct device *dev) { return 0; }
#endif
/*
* this function registers exynos drm vidi platform device/driver.
*/
int exynos_drm_probe_vidi(void);
/*
* this function unregister exynos drm vidi platform device/driver.
*/
void exynos_drm_remove_vidi(void);
/* This function creates a encoder and a connector, and initializes them. */
int exynos_drm_create_enc_conn(struct drm_device *dev,
struct exynos_drm_display *display);
int exynos_drm_component_add(struct device *dev,
enum exynos_drm_device_type dev_type,
enum exynos_drm_output_type out_type);
void exynos_drm_component_del(struct device *dev,
enum exynos_drm_device_type dev_type);
extern struct platform_driver fimd_driver;
extern struct platform_driver dp_driver;
extern struct platform_driver dsi_driver;
extern struct platform_driver mixer_driver;
extern struct platform_driver hdmi_driver;
extern struct platform_driver exynos_drm_common_hdmi_driver;
extern struct platform_driver vidi_driver;
extern struct platform_driver g2d_driver;
extern struct platform_driver fimc_driver;
extern struct platform_driver rotator_driver;
extern struct platform_driver gsc_driver;
extern struct platform_driver ipp_driver;
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,197 @@
/* exynos_drm_encoder.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_encoder.h"
#define to_exynos_encoder(x) container_of(x, struct exynos_drm_encoder,\
drm_encoder)
/*
* exynos specific encoder structure.
*
* @drm_encoder: encoder object.
* @display: the display structure that maps to this encoder
*/
struct exynos_drm_encoder {
struct drm_encoder drm_encoder;
struct exynos_drm_display *display;
};
static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
{
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
struct exynos_drm_display *display = exynos_encoder->display;
DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
if (display->ops->dpms)
display->ops->dpms(display, mode);
}
static bool
exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct drm_device *dev = encoder->dev;
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
struct exynos_drm_display *display = exynos_encoder->display;
struct drm_connector *connector;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->encoder != encoder)
continue;
if (display->ops->mode_fixup)
display->ops->mode_fixup(display, connector, mode,
adjusted_mode);
}
return true;
}
static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
struct exynos_drm_display *display = exynos_encoder->display;
if (display->ops->mode_set)
display->ops->mode_set(display, adjusted_mode);
}
static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
{
/* drm framework doesn't check NULL. */
}
static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
{
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
struct exynos_drm_display *display = exynos_encoder->display;
if (display->ops->dpms)
display->ops->dpms(display, DRM_MODE_DPMS_ON);
if (display->ops->commit)
display->ops->commit(display);
}
static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
{
struct drm_plane *plane;
struct drm_device *dev = encoder->dev;
exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
/* all planes connected to this encoder should be also disabled. */
drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
if (plane->crtc == encoder->crtc)
plane->funcs->disable_plane(plane);
}
}
static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
.dpms = exynos_drm_encoder_dpms,
.mode_fixup = exynos_drm_encoder_mode_fixup,
.mode_set = exynos_drm_encoder_mode_set,
.prepare = exynos_drm_encoder_prepare,
.commit = exynos_drm_encoder_commit,
.disable = exynos_drm_encoder_disable,
};
static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
{
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
drm_encoder_cleanup(encoder);
kfree(exynos_encoder);
}
static struct drm_encoder_funcs exynos_encoder_funcs = {
.destroy = exynos_drm_encoder_destroy,
};
static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
{
struct drm_encoder *clone;
struct drm_device *dev = encoder->dev;
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
struct exynos_drm_display *display = exynos_encoder->display;
unsigned int clone_mask = 0;
int cnt = 0;
list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
switch (display->type) {
case EXYNOS_DISPLAY_TYPE_LCD:
case EXYNOS_DISPLAY_TYPE_HDMI:
case EXYNOS_DISPLAY_TYPE_VIDI:
clone_mask |= (1 << (cnt++));
break;
default:
continue;
}
}
return clone_mask;
}
void exynos_drm_encoder_setup(struct drm_device *dev)
{
struct drm_encoder *encoder;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
encoder->possible_clones = exynos_drm_encoder_clones(encoder);
}
struct drm_encoder *
exynos_drm_encoder_create(struct drm_device *dev,
struct exynos_drm_display *display,
unsigned long possible_crtcs)
{
struct drm_encoder *encoder;
struct exynos_drm_encoder *exynos_encoder;
if (!possible_crtcs)
return NULL;
exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
if (!exynos_encoder)
return NULL;
exynos_encoder->display = display;
encoder = &exynos_encoder->drm_encoder;
encoder->possible_crtcs = possible_crtcs;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
drm_encoder_init(dev, encoder, &exynos_encoder_funcs,
DRM_MODE_ENCODER_TMDS);
drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
DRM_DEBUG_KMS("encoder has been created\n");
return encoder;
}
struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder)
{
return to_exynos_encoder(encoder)->display;
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_ENCODER_H_
#define _EXYNOS_DRM_ENCODER_H_
struct exynos_drm_manager;
void exynos_drm_encoder_setup(struct drm_device *dev);
struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev,
struct exynos_drm_display *mgr,
unsigned long possible_crtcs);
struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder);
#endif

View file

@ -0,0 +1,328 @@
/* exynos_drm_fb.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <uapi/drm/exynos_drm.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_fbdev.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_iommu.h"
#include "exynos_drm_crtc.h"
#define to_exynos_fb(x) container_of(x, struct exynos_drm_fb, fb)
/*
* exynos specific framebuffer structure.
*
* @fb: drm framebuffer obejct.
* @buf_cnt: a buffer count to drm framebuffer.
* @exynos_gem_obj: array of exynos specific gem object containing a gem object.
*/
struct exynos_drm_fb {
struct drm_framebuffer fb;
unsigned int buf_cnt;
struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER];
};
static int check_fb_gem_memory_type(struct drm_device *drm_dev,
struct exynos_drm_gem_obj *exynos_gem_obj)
{
unsigned int flags;
/*
* if exynos drm driver supports iommu then framebuffer can use
* all the buffer types.
*/
if (is_drm_iommu_supported(drm_dev))
return 0;
flags = exynos_gem_obj->flags;
/*
* without iommu support, not support physically non-continuous memory
* for framebuffer.
*/
if (IS_NONCONTIG_BUFFER(flags)) {
DRM_ERROR("cannot use this gem memory type for fb.\n");
return -EINVAL;
}
return 0;
}
static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
{
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
unsigned int i;
/* make sure that overlay data are updated before relesing fb. */
exynos_drm_crtc_complete_scanout(fb);
drm_framebuffer_cleanup(fb);
for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem_obj); i++) {
struct drm_gem_object *obj;
if (exynos_fb->exynos_gem_obj[i] == NULL)
continue;
obj = &exynos_fb->exynos_gem_obj[i]->base;
drm_gem_object_unreference_unlocked(obj);
}
kfree(exynos_fb);
exynos_fb = NULL;
}
static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,
struct drm_file *file_priv,
unsigned int *handle)
{
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
/* This fb should have only one gem object. */
if (WARN_ON(exynos_fb->buf_cnt != 1))
return -EINVAL;
return drm_gem_handle_create(file_priv,
&exynos_fb->exynos_gem_obj[0]->base, handle);
}
static int exynos_drm_fb_dirty(struct drm_framebuffer *fb,
struct drm_file *file_priv, unsigned flags,
unsigned color, struct drm_clip_rect *clips,
unsigned num_clips)
{
/* TODO */
return 0;
}
static struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
.destroy = exynos_drm_fb_destroy,
.create_handle = exynos_drm_fb_create_handle,
.dirty = exynos_drm_fb_dirty,
};
void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb,
unsigned int cnt)
{
struct exynos_drm_fb *exynos_fb;
exynos_fb = to_exynos_fb(fb);
exynos_fb->buf_cnt = cnt;
}
unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb)
{
struct exynos_drm_fb *exynos_fb;
exynos_fb = to_exynos_fb(fb);
return exynos_fb->buf_cnt;
}
struct drm_framebuffer *
exynos_drm_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
struct exynos_drm_fb *exynos_fb;
struct exynos_drm_gem_obj *exynos_gem_obj;
int ret;
exynos_gem_obj = to_exynos_gem_obj(obj);
ret = check_fb_gem_memory_type(dev, exynos_gem_obj);
if (ret < 0) {
DRM_ERROR("cannot use this gem memory type for fb.\n");
return ERR_PTR(-EINVAL);
}
exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
if (!exynos_fb)
return ERR_PTR(-ENOMEM);
drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
exynos_fb->exynos_gem_obj[0] = exynos_gem_obj;
ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs);
if (ret) {
kfree(exynos_fb);
DRM_ERROR("failed to initialize framebuffer\n");
return ERR_PTR(ret);
}
return &exynos_fb->fb;
}
static u32 exynos_drm_format_num_buffers(struct drm_mode_fb_cmd2 *mode_cmd)
{
unsigned int cnt = 0;
if (mode_cmd->pixel_format != DRM_FORMAT_NV12)
return drm_format_num_planes(mode_cmd->pixel_format);
while (cnt != MAX_FB_BUFFER) {
if (!mode_cmd->handles[cnt])
break;
cnt++;
}
/*
* check if NV12 or NV12M.
*
* NV12
* handles[0] = base1, offsets[0] = 0
* handles[1] = base1, offsets[1] = Y_size
*
* NV12M
* handles[0] = base1, offsets[0] = 0
* handles[1] = base2, offsets[1] = 0
*/
if (cnt == 2) {
/*
* in case of NV12 format, offsets[1] is not 0 and
* handles[0] is same as handles[1].
*/
if (mode_cmd->offsets[1] &&
mode_cmd->handles[0] == mode_cmd->handles[1])
cnt = 1;
}
return cnt;
}
static struct drm_framebuffer *
exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
struct drm_mode_fb_cmd2 *mode_cmd)
{
struct drm_gem_object *obj;
struct exynos_drm_gem_obj *exynos_gem_obj;
struct exynos_drm_fb *exynos_fb;
int i, ret;
exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
if (!exynos_fb)
return ERR_PTR(-ENOMEM);
obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
if (!obj) {
DRM_ERROR("failed to lookup gem object\n");
ret = -ENOENT;
goto err_free;
}
drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj);
exynos_fb->buf_cnt = exynos_drm_format_num_buffers(mode_cmd);
DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt);
for (i = 1; i < exynos_fb->buf_cnt; i++) {
obj = drm_gem_object_lookup(dev, file_priv,
mode_cmd->handles[i]);
if (!obj) {
DRM_ERROR("failed to lookup gem object\n");
ret = -ENOENT;
exynos_fb->buf_cnt = i;
goto err_unreference;
}
exynos_gem_obj = to_exynos_gem_obj(obj);
exynos_fb->exynos_gem_obj[i] = exynos_gem_obj;
ret = check_fb_gem_memory_type(dev, exynos_gem_obj);
if (ret < 0) {
DRM_ERROR("cannot use this gem memory type for fb.\n");
goto err_unreference;
}
}
ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs);
if (ret) {
DRM_ERROR("failed to init framebuffer.\n");
goto err_unreference;
}
return &exynos_fb->fb;
err_unreference:
for (i = 0; i < exynos_fb->buf_cnt; i++) {
struct drm_gem_object *obj;
obj = &exynos_fb->exynos_gem_obj[i]->base;
if (obj)
drm_gem_object_unreference_unlocked(obj);
}
err_free:
kfree(exynos_fb);
return ERR_PTR(ret);
}
struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
int index)
{
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
struct exynos_drm_gem_buf *buffer;
if (index >= MAX_FB_BUFFER)
return NULL;
buffer = exynos_fb->exynos_gem_obj[index]->buffer;
if (!buffer)
return NULL;
DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)buffer->dma_addr);
return buffer;
}
static void exynos_drm_output_poll_changed(struct drm_device *dev)
{
struct exynos_drm_private *private = dev->dev_private;
struct drm_fb_helper *fb_helper = private->fb_helper;
if (fb_helper)
drm_fb_helper_hotplug_event(fb_helper);
else
exynos_drm_fbdev_init(dev);
}
static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
.fb_create = exynos_user_fb_create,
.output_poll_changed = exynos_drm_output_poll_changed,
};
void exynos_drm_mode_config_init(struct drm_device *dev)
{
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
/*
* set max width and height as default value(4096x4096).
* this value would be used to check framebuffer size limitation
* at drm_mode_addfb().
*/
dev->mode_config.max_width = 4096;
dev->mode_config.max_height = 4096;
dev->mode_config.funcs = &exynos_drm_mode_config_funcs;
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_FB_H_
#define _EXYNOS_DRM_FB_H
struct drm_framebuffer *
exynos_drm_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
/* get memory information of a drm framebuffer */
struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
int index);
void exynos_drm_mode_config_init(struct drm_device *dev);
/* set a buffer count to drm framebuffer. */
void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb,
unsigned int cnt);
/* get a buffer count to drm framebuffer. */
unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb);
#endif

View file

@ -0,0 +1,370 @@
/* exynos_drm_fbdev.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_fbdev.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_iommu.h"
#define MAX_CONNECTOR 4
#define PREFERRED_BPP 32
#define to_exynos_fbdev(x) container_of(x, struct exynos_drm_fbdev,\
drm_fb_helper)
struct exynos_drm_fbdev {
struct drm_fb_helper drm_fb_helper;
struct exynos_drm_gem_obj *exynos_gem_obj;
};
static int exynos_drm_fb_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
struct drm_fb_helper *helper = info->par;
struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper);
struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj;
struct exynos_drm_gem_buf *buffer = exynos_gem_obj->buffer;
unsigned long vm_size;
int ret;
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
vm_size = vma->vm_end - vma->vm_start;
if (vm_size > buffer->size)
return -EINVAL;
ret = dma_mmap_attrs(helper->dev->dev, vma, buffer->pages,
buffer->dma_addr, buffer->size, &buffer->dma_attrs);
if (ret < 0) {
DRM_ERROR("failed to mmap.\n");
return ret;
}
return 0;
}
static struct fb_ops exynos_drm_fb_ops = {
.owner = THIS_MODULE,
.fb_mmap = exynos_drm_fb_mmap,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par,
.fb_blank = drm_fb_helper_blank,
.fb_pan_display = drm_fb_helper_pan_display,
.fb_setcmap = drm_fb_helper_setcmap,
};
static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
struct drm_framebuffer *fb)
{
struct fb_info *fbi = helper->fbdev;
struct drm_device *dev = helper->dev;
struct exynos_drm_gem_buf *buffer;
unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
unsigned long offset;
drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
/* RGB formats use only one buffer */
buffer = exynos_drm_fb_buffer(fb, 0);
if (!buffer) {
DRM_DEBUG_KMS("buffer is null.\n");
return -EFAULT;
}
/* map pages with kernel virtual space. */
if (!buffer->kvaddr) {
if (is_drm_iommu_supported(dev)) {
unsigned int nr_pages = buffer->size >> PAGE_SHIFT;
buffer->kvaddr = (void __iomem *) vmap(buffer->pages,
nr_pages, VM_MAP,
pgprot_writecombine(PAGE_KERNEL));
} else {
phys_addr_t dma_addr = buffer->dma_addr;
if (dma_addr)
buffer->kvaddr = (void __iomem *)phys_to_virt(dma_addr);
else
buffer->kvaddr = (void __iomem *)NULL;
}
if (!buffer->kvaddr) {
DRM_ERROR("failed to map pages to kernel space.\n");
return -EIO;
}
}
/* buffer count to framebuffer always is 1 at booting time. */
exynos_drm_fb_set_buf_cnt(fb, 1);
offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);
offset += fbi->var.yoffset * fb->pitches[0];
fbi->screen_base = buffer->kvaddr + offset;
fbi->screen_size = size;
fbi->fix.smem_len = size;
return 0;
}
static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper);
struct exynos_drm_gem_obj *exynos_gem_obj;
struct drm_device *dev = helper->dev;
struct fb_info *fbi;
struct drm_mode_fb_cmd2 mode_cmd = { 0 };
struct platform_device *pdev = dev->platformdev;
unsigned long size;
int ret;
DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d\n",
sizes->surface_width, sizes->surface_height,
sizes->surface_bpp);
mode_cmd.width = sizes->surface_width;
mode_cmd.height = sizes->surface_height;
mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3);
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
sizes->surface_depth);
mutex_lock(&dev->struct_mutex);
fbi = framebuffer_alloc(0, &pdev->dev);
if (!fbi) {
DRM_ERROR("failed to allocate fb info.\n");
ret = -ENOMEM;
goto out;
}
size = mode_cmd.pitches[0] * mode_cmd.height;
exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size);
/*
* If physically contiguous memory allocation fails and if IOMMU is
* supported then try to get buffer from non physically contiguous
* memory area.
*/
if (IS_ERR(exynos_gem_obj) && is_drm_iommu_supported(dev)) {
dev_warn(&pdev->dev, "contiguous FB allocation failed, falling back to non-contiguous\n");
exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG,
size);
}
if (IS_ERR(exynos_gem_obj)) {
ret = PTR_ERR(exynos_gem_obj);
goto err_release_framebuffer;
}
exynos_fbdev->exynos_gem_obj = exynos_gem_obj;
helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd,
&exynos_gem_obj->base);
if (IS_ERR(helper->fb)) {
DRM_ERROR("failed to create drm framebuffer.\n");
ret = PTR_ERR(helper->fb);
goto err_destroy_gem;
}
helper->fbdev = fbi;
fbi->par = helper;
fbi->flags = FBINFO_FLAG_DEFAULT;
fbi->fbops = &exynos_drm_fb_ops;
ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
if (ret) {
DRM_ERROR("failed to allocate cmap.\n");
goto err_destroy_framebuffer;
}
ret = exynos_drm_fbdev_update(helper, helper->fb);
if (ret < 0)
goto err_dealloc_cmap;
mutex_unlock(&dev->struct_mutex);
return ret;
err_dealloc_cmap:
fb_dealloc_cmap(&fbi->cmap);
err_destroy_framebuffer:
drm_framebuffer_cleanup(helper->fb);
err_destroy_gem:
exynos_drm_gem_destroy(exynos_gem_obj);
err_release_framebuffer:
framebuffer_release(fbi);
/*
* if failed, all resources allocated above would be released by
* drm_mode_config_cleanup() when drm_load() had been called prior
* to any specific driver such as fimd or hdmi driver.
*/
out:
mutex_unlock(&dev->struct_mutex);
return ret;
}
static const struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = {
.fb_probe = exynos_drm_fbdev_create,
};
static bool exynos_drm_fbdev_is_anything_connected(struct drm_device *dev)
{
struct drm_connector *connector;
bool ret = false;
mutex_lock(&dev->mode_config.mutex);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->status != connector_status_connected)
continue;
ret = true;
break;
}
mutex_unlock(&dev->mode_config.mutex);
return ret;
}
int exynos_drm_fbdev_init(struct drm_device *dev)
{
struct exynos_drm_fbdev *fbdev;
struct exynos_drm_private *private = dev->dev_private;
struct drm_fb_helper *helper;
unsigned int num_crtc;
int ret;
if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
return 0;
if (!exynos_drm_fbdev_is_anything_connected(dev))
return 0;
fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
if (!fbdev)
return -ENOMEM;
private->fb_helper = helper = &fbdev->drm_fb_helper;
drm_fb_helper_prepare(dev, helper, &exynos_drm_fb_helper_funcs);
num_crtc = dev->mode_config.num_crtc;
ret = drm_fb_helper_init(dev, helper, num_crtc, MAX_CONNECTOR);
if (ret < 0) {
DRM_ERROR("failed to initialize drm fb helper.\n");
goto err_init;
}
ret = drm_fb_helper_single_add_all_connectors(helper);
if (ret < 0) {
DRM_ERROR("failed to register drm_fb_helper_connector.\n");
goto err_setup;
}
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(dev);
ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP);
if (ret < 0) {
DRM_ERROR("failed to set up hw configuration.\n");
goto err_setup;
}
return 0;
err_setup:
drm_fb_helper_fini(helper);
err_init:
private->fb_helper = NULL;
kfree(fbdev);
return ret;
}
static void exynos_drm_fbdev_destroy(struct drm_device *dev,
struct drm_fb_helper *fb_helper)
{
struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(fb_helper);
struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj;
struct drm_framebuffer *fb;
if (is_drm_iommu_supported(dev) && exynos_gem_obj->buffer->kvaddr)
vunmap(exynos_gem_obj->buffer->kvaddr);
/* release drm framebuffer and real buffer */
if (fb_helper->fb && fb_helper->fb->funcs) {
fb = fb_helper->fb;
if (fb) {
drm_framebuffer_unregister_private(fb);
drm_framebuffer_remove(fb);
}
}
/* release linux framebuffer */
if (fb_helper->fbdev) {
struct fb_info *info;
int ret;
info = fb_helper->fbdev;
ret = unregister_framebuffer(info);
if (ret < 0)
DRM_DEBUG_KMS("failed unregister_framebuffer()\n");
if (info->cmap.len)
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
}
drm_fb_helper_fini(fb_helper);
}
void exynos_drm_fbdev_fini(struct drm_device *dev)
{
struct exynos_drm_private *private = dev->dev_private;
struct exynos_drm_fbdev *fbdev;
if (!private || !private->fb_helper)
return;
fbdev = to_exynos_fbdev(private->fb_helper);
exynos_drm_fbdev_destroy(dev, private->fb_helper);
kfree(fbdev);
private->fb_helper = NULL;
}
void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
{
struct exynos_drm_private *private = dev->dev_private;
if (!private || !private->fb_helper)
return;
drm_fb_helper_restore_fbdev_mode_unlocked(private->fb_helper);
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
*
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_FBDEV_H_
#define _EXYNOS_DRM_FBDEV_H_
int exynos_drm_fbdev_init(struct drm_device *dev);
int exynos_drm_fbdev_reinit(struct drm_device *dev);
void exynos_drm_fbdev_fini(struct drm_device *dev);
void exynos_drm_fbdev_restore_mode(struct drm_device *dev);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
*
* Authors:
* Eunchul Kim <chulspro.kim@samsung.com>
* Jinyoung Jeon <jy0.jeon@samsung.com>
* Sangmin Lee <lsmin.lee@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_FIMC_H_
#define _EXYNOS_DRM_FIMC_H_
/*
* TODO
* FIMD output interface notifier callback.
*/
#endif /* _EXYNOS_DRM_FIMC_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,36 @@
/*
* Copyright (C) 2012 Samsung Electronics Co.Ltd
* Authors: Joonyoung Shim <jy0922.shim@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 Foundationr
*/
#ifdef CONFIG_DRM_EXYNOS_G2D
extern int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
#else
static inline int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
return -ENODEV;
}
static inline int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev,
void *data,
struct drm_file *file_priv)
{
return -ENODEV;
}
static inline int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
return -ENODEV;
}
#endif

View file

@ -0,0 +1,651 @@
/* exynos_drm_gem.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Author: Inki Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <drm/drmP.h>
#include <drm/drm_vma_manager.h>
#include <linux/shmem_fs.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_buf.h"
#include "exynos_drm_iommu.h"
static unsigned int convert_to_vm_err_msg(int msg)
{
unsigned int out_msg;
switch (msg) {
case 0:
case -ERESTARTSYS:
case -EINTR:
out_msg = VM_FAULT_NOPAGE;
break;
case -ENOMEM:
out_msg = VM_FAULT_OOM;
break;
default:
out_msg = VM_FAULT_SIGBUS;
break;
}
return out_msg;
}
static int check_gem_flags(unsigned int flags)
{
if (flags & ~(EXYNOS_BO_MASK)) {
DRM_ERROR("invalid flags.\n");
return -EINVAL;
}
return 0;
}
static void update_vm_cache_attr(struct exynos_drm_gem_obj *obj,
struct vm_area_struct *vma)
{
DRM_DEBUG_KMS("flags = 0x%x\n", obj->flags);
/* non-cachable as default. */
if (obj->flags & EXYNOS_BO_CACHABLE)
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
else if (obj->flags & EXYNOS_BO_WC)
vma->vm_page_prot =
pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
else
vma->vm_page_prot =
pgprot_noncached(vm_get_page_prot(vma->vm_flags));
}
static unsigned long roundup_gem_size(unsigned long size, unsigned int flags)
{
/* TODO */
return roundup(size, PAGE_SIZE);
}
static int exynos_drm_gem_map_buf(struct drm_gem_object *obj,
struct vm_area_struct *vma,
unsigned long f_vaddr,
pgoff_t page_offset)
{
struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
struct exynos_drm_gem_buf *buf = exynos_gem_obj->buffer;
struct scatterlist *sgl;
unsigned long pfn;
int i;
if (!buf->sgt)
return -EINTR;
if (page_offset >= (buf->size >> PAGE_SHIFT)) {
DRM_ERROR("invalid page offset\n");
return -EINVAL;
}
sgl = buf->sgt->sgl;
for_each_sg(buf->sgt->sgl, sgl, buf->sgt->nents, i) {
if (page_offset < (sgl->length >> PAGE_SHIFT))
break;
page_offset -= (sgl->length >> PAGE_SHIFT);
}
pfn = __phys_to_pfn(sg_phys(sgl)) + page_offset;
return vm_insert_mixed(vma, f_vaddr, pfn);
}
static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
struct drm_file *file_priv,
unsigned int *handle)
{
int ret;
/*
* allocate a id of idr table where the obj is registered
* and handle has the id what user can see.
*/
ret = drm_gem_handle_create(file_priv, obj, handle);
if (ret)
return ret;
DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle);
/* drop reference from allocate - handle holds it now. */
drm_gem_object_unreference_unlocked(obj);
return 0;
}
void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
{
struct drm_gem_object *obj;
struct exynos_drm_gem_buf *buf;
obj = &exynos_gem_obj->base;
buf = exynos_gem_obj->buffer;
DRM_DEBUG_KMS("handle count = %d\n", obj->handle_count);
/*
* do not release memory region from exporter.
*
* the region will be released by exporter
* once dmabuf's refcount becomes 0.
*/
if (obj->import_attach)
goto out;
exynos_drm_free_buf(obj->dev, exynos_gem_obj->flags, buf);
out:
exynos_drm_fini_buf(obj->dev, buf);
exynos_gem_obj->buffer = NULL;
drm_gem_free_mmap_offset(obj);
/* release file pointer to gem object. */
drm_gem_object_release(obj);
kfree(exynos_gem_obj);
exynos_gem_obj = NULL;
}
unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
unsigned int gem_handle,
struct drm_file *file_priv)
{
struct exynos_drm_gem_obj *exynos_gem_obj;
struct drm_gem_object *obj;
obj = drm_gem_object_lookup(dev, file_priv, gem_handle);
if (!obj) {
DRM_ERROR("failed to lookup gem object.\n");
return 0;
}
exynos_gem_obj = to_exynos_gem_obj(obj);
drm_gem_object_unreference_unlocked(obj);
return exynos_gem_obj->buffer->size;
}
struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
unsigned long size)
{
struct exynos_drm_gem_obj *exynos_gem_obj;
struct drm_gem_object *obj;
int ret;
exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL);
if (!exynos_gem_obj)
return NULL;
exynos_gem_obj->size = size;
obj = &exynos_gem_obj->base;
ret = drm_gem_object_init(dev, obj, size);
if (ret < 0) {
DRM_ERROR("failed to initialize gem object\n");
kfree(exynos_gem_obj);
return NULL;
}
DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp);
return exynos_gem_obj;
}
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
unsigned int flags,
unsigned long size)
{
struct exynos_drm_gem_obj *exynos_gem_obj;
struct exynos_drm_gem_buf *buf;
int ret;
if (!size) {
DRM_ERROR("invalid size.\n");
return ERR_PTR(-EINVAL);
}
size = roundup_gem_size(size, flags);
ret = check_gem_flags(flags);
if (ret)
return ERR_PTR(ret);
buf = exynos_drm_init_buf(dev, size);
if (!buf)
return ERR_PTR(-ENOMEM);
exynos_gem_obj = exynos_drm_gem_init(dev, size);
if (!exynos_gem_obj) {
ret = -ENOMEM;
goto err_fini_buf;
}
exynos_gem_obj->buffer = buf;
/* set memory type and cache attribute from user side. */
exynos_gem_obj->flags = flags;
ret = exynos_drm_alloc_buf(dev, buf, flags);
if (ret < 0)
goto err_gem_fini;
return exynos_gem_obj;
err_gem_fini:
drm_gem_object_release(&exynos_gem_obj->base);
kfree(exynos_gem_obj);
err_fini_buf:
exynos_drm_fini_buf(dev, buf);
return ERR_PTR(ret);
}
int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_exynos_gem_create *args = data;
struct exynos_drm_gem_obj *exynos_gem_obj;
int ret;
exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
if (IS_ERR(exynos_gem_obj))
return PTR_ERR(exynos_gem_obj);
ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv,
&args->handle);
if (ret) {
exynos_drm_gem_destroy(exynos_gem_obj);
return ret;
}
return 0;
}
dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
unsigned int gem_handle,
struct drm_file *filp)
{
struct exynos_drm_gem_obj *exynos_gem_obj;
struct drm_gem_object *obj;
obj = drm_gem_object_lookup(dev, filp, gem_handle);
if (!obj) {
DRM_ERROR("failed to lookup gem object.\n");
return ERR_PTR(-EINVAL);
}
exynos_gem_obj = to_exynos_gem_obj(obj);
return &exynos_gem_obj->buffer->dma_addr;
}
void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
unsigned int gem_handle,
struct drm_file *filp)
{
struct drm_gem_object *obj;
obj = drm_gem_object_lookup(dev, filp, gem_handle);
if (!obj) {
DRM_ERROR("failed to lookup gem object.\n");
return;
}
drm_gem_object_unreference_unlocked(obj);
/*
* decrease obj->refcount one more time because we has already
* increased it at exynos_drm_gem_get_dma_addr().
*/
drm_gem_object_unreference_unlocked(obj);
}
int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem_obj *exynos_gem_obj,
struct vm_area_struct *vma)
{
struct drm_device *drm_dev = exynos_gem_obj->base.dev;
struct exynos_drm_gem_buf *buffer;
unsigned long vm_size;
int ret;
vma->vm_flags &= ~VM_PFNMAP;
vma->vm_pgoff = 0;
vm_size = vma->vm_end - vma->vm_start;
/*
* a buffer contains information to physically continuous memory
* allocated by user request or at framebuffer creation.
*/
buffer = exynos_gem_obj->buffer;
/* check if user-requested size is valid. */
if (vm_size > buffer->size)
return -EINVAL;
ret = dma_mmap_attrs(drm_dev->dev, vma, buffer->pages,
buffer->dma_addr, buffer->size,
&buffer->dma_attrs);
if (ret < 0) {
DRM_ERROR("failed to mmap.\n");
return ret;
}
return 0;
}
int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{ struct exynos_drm_gem_obj *exynos_gem_obj;
struct drm_exynos_gem_info *args = data;
struct drm_gem_object *obj;
mutex_lock(&dev->struct_mutex);
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (!obj) {
DRM_ERROR("failed to lookup gem object.\n");
mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
exynos_gem_obj = to_exynos_gem_obj(obj);
args->flags = exynos_gem_obj->flags;
args->size = exynos_gem_obj->size;
drm_gem_object_unreference(obj);
mutex_unlock(&dev->struct_mutex);
return 0;
}
struct vm_area_struct *exynos_gem_get_vma(struct vm_area_struct *vma)
{
struct vm_area_struct *vma_copy;
vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
if (!vma_copy)
return NULL;
if (vma->vm_ops && vma->vm_ops->open)
vma->vm_ops->open(vma);
if (vma->vm_file)
get_file(vma->vm_file);
memcpy(vma_copy, vma, sizeof(*vma));
vma_copy->vm_mm = NULL;
vma_copy->vm_next = NULL;
vma_copy->vm_prev = NULL;
return vma_copy;
}
void exynos_gem_put_vma(struct vm_area_struct *vma)
{
if (!vma)
return;
if (vma->vm_ops && vma->vm_ops->close)
vma->vm_ops->close(vma);
if (vma->vm_file)
fput(vma->vm_file);
kfree(vma);
}
int exynos_gem_get_pages_from_userptr(unsigned long start,
unsigned int npages,
struct page **pages,
struct vm_area_struct *vma)
{
int get_npages;
/* the memory region mmaped with VM_PFNMAP. */
if (vma_is_io(vma)) {
unsigned int i;
for (i = 0; i < npages; ++i, start += PAGE_SIZE) {
unsigned long pfn;
int ret = follow_pfn(vma, start, &pfn);
if (ret)
return ret;
pages[i] = pfn_to_page(pfn);
}
if (i != npages) {
DRM_ERROR("failed to get user_pages.\n");
return -EINVAL;
}
return 0;
}
get_npages = get_user_pages(current, current->mm, start,
npages, 1, 1, pages, NULL);
get_npages = max(get_npages, 0);
if (get_npages != npages) {
DRM_ERROR("failed to get user_pages.\n");
while (get_npages)
put_page(pages[--get_npages]);
return -EFAULT;
}
return 0;
}
void exynos_gem_put_pages_to_userptr(struct page **pages,
unsigned int npages,
struct vm_area_struct *vma)
{
if (!vma_is_io(vma)) {
unsigned int i;
for (i = 0; i < npages; i++) {
set_page_dirty_lock(pages[i]);
/*
* undo the reference we took when populating
* the table.
*/
put_page(pages[i]);
}
}
}
int exynos_gem_map_sgt_with_dma(struct drm_device *drm_dev,
struct sg_table *sgt,
enum dma_data_direction dir)
{
int nents;
mutex_lock(&drm_dev->struct_mutex);
nents = dma_map_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir);
if (!nents) {
DRM_ERROR("failed to map sgl with dma.\n");
mutex_unlock(&drm_dev->struct_mutex);
return nents;
}
mutex_unlock(&drm_dev->struct_mutex);
return 0;
}
void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
struct sg_table *sgt,
enum dma_data_direction dir)
{
dma_unmap_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir);
}
void exynos_drm_gem_free_object(struct drm_gem_object *obj)
{
struct exynos_drm_gem_obj *exynos_gem_obj;
struct exynos_drm_gem_buf *buf;
exynos_gem_obj = to_exynos_gem_obj(obj);
buf = exynos_gem_obj->buffer;
if (obj->import_attach)
drm_prime_gem_destroy(obj, buf->sgt);
exynos_drm_gem_destroy(to_exynos_gem_obj(obj));
}
int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args)
{
struct exynos_drm_gem_obj *exynos_gem_obj;
int ret;
/*
* allocate memory to be used for framebuffer.
* - this callback would be called by user application
* with DRM_IOCTL_MODE_CREATE_DUMB command.
*/
args->pitch = args->width * ((args->bpp + 7) / 8);
args->size = args->pitch * args->height;
if (is_drm_iommu_supported(dev)) {
exynos_gem_obj = exynos_drm_gem_create(dev,
EXYNOS_BO_NONCONTIG | EXYNOS_BO_WC,
args->size);
} else {
exynos_gem_obj = exynos_drm_gem_create(dev,
EXYNOS_BO_CONTIG | EXYNOS_BO_WC,
args->size);
}
if (IS_ERR(exynos_gem_obj)) {
dev_warn(dev->dev, "FB allocation failed.\n");
return PTR_ERR(exynos_gem_obj);
}
ret = exynos_drm_gem_handle_create(&exynos_gem_obj->base, file_priv,
&args->handle);
if (ret) {
exynos_drm_gem_destroy(exynos_gem_obj);
return ret;
}
return 0;
}
int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
struct drm_device *dev, uint32_t handle,
uint64_t *offset)
{
struct drm_gem_object *obj;
int ret = 0;
mutex_lock(&dev->struct_mutex);
/*
* get offset of memory allocated for drm framebuffer.
* - this callback would be called by user application
* with DRM_IOCTL_MODE_MAP_DUMB command.
*/
obj = drm_gem_object_lookup(dev, file_priv, handle);
if (!obj) {
DRM_ERROR("failed to lookup gem object.\n");
ret = -EINVAL;
goto unlock;
}
ret = drm_gem_create_mmap_offset(obj);
if (ret)
goto out;
*offset = drm_vma_node_offset_addr(&obj->vma_node);
DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset);
out:
drm_gem_object_unreference(obj);
unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
}
int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct drm_gem_object *obj = vma->vm_private_data;
struct drm_device *dev = obj->dev;
unsigned long f_vaddr;
pgoff_t page_offset;
int ret;
page_offset = ((unsigned long)vmf->virtual_address -
vma->vm_start) >> PAGE_SHIFT;
f_vaddr = (unsigned long)vmf->virtual_address;
mutex_lock(&dev->struct_mutex);
ret = exynos_drm_gem_map_buf(obj, vma, f_vaddr, page_offset);
if (ret < 0)
DRM_ERROR("failed to map a buffer with user.\n");
mutex_unlock(&dev->struct_mutex);
return convert_to_vm_err_msg(ret);
}
int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct exynos_drm_gem_obj *exynos_gem_obj;
struct drm_gem_object *obj;
int ret;
/* set vm_area_struct. */
ret = drm_gem_mmap(filp, vma);
if (ret < 0) {
DRM_ERROR("failed to mmap.\n");
return ret;
}
obj = vma->vm_private_data;
exynos_gem_obj = to_exynos_gem_obj(obj);
ret = check_gem_flags(exynos_gem_obj->flags);
if (ret)
goto err_close_vm;
update_vm_cache_attr(exynos_gem_obj, vma);
ret = exynos_drm_gem_mmap_buffer(exynos_gem_obj, vma);
if (ret)
goto err_close_vm;
return ret;
err_close_vm:
drm_gem_vm_close(vma);
drm_gem_free_mmap_offset(obj);
return ret;
}

View file

@ -0,0 +1,180 @@
/* exynos_drm_gem.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authoer: Inki Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_GEM_H_
#define _EXYNOS_DRM_GEM_H_
#include <drm/drm_gem.h>
#define to_exynos_gem_obj(x) container_of(x,\
struct exynos_drm_gem_obj, base)
#define IS_NONCONTIG_BUFFER(f) (f & EXYNOS_BO_NONCONTIG)
/*
* exynos drm gem buffer structure.
*
* @kvaddr: kernel virtual address to allocated memory region.
* *userptr: user space address.
* @dma_addr: bus address(accessed by dma) to allocated memory region.
* - this address could be physical address without IOMMU and
* device address with IOMMU.
* @write: whether pages will be written to by the caller.
* @pages: Array of backing pages.
* @sgt: sg table to transfer page data.
* @size: size of allocated memory region.
* @pfnmap: indicate whether memory region from userptr is mmaped with
* VM_PFNMAP or not.
*/
struct exynos_drm_gem_buf {
void __iomem *kvaddr;
unsigned long userptr;
dma_addr_t dma_addr;
struct dma_attrs dma_attrs;
unsigned int write;
struct page **pages;
struct sg_table *sgt;
unsigned long size;
bool pfnmap;
};
/*
* exynos drm buffer structure.
*
* @base: a gem object.
* - a new handle to this gem object would be created
* by drm_gem_handle_create().
* @buffer: a pointer to exynos_drm_gem_buffer object.
* - contain the information to memory region allocated
* by user request or at framebuffer creation.
* continuous memory region allocated by user request
* or at framebuffer creation.
* @size: size requested from user, in bytes and this size is aligned
* in page unit.
* @vma: a pointer to vm_area.
* @flags: indicate memory type to allocated buffer and cache attruibute.
*
* P.S. this object would be transferred to user as kms_bo.handle so
* user can access the buffer through kms_bo.handle.
*/
struct exynos_drm_gem_obj {
struct drm_gem_object base;
struct exynos_drm_gem_buf *buffer;
unsigned long size;
struct vm_area_struct *vma;
unsigned int flags;
};
struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
/* destroy a buffer with gem object */
void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj);
/* create a private gem object and initialize it. */
struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
unsigned long size);
/* create a new buffer with gem object */
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
unsigned int flags,
unsigned long size);
/*
* request gem object creation and buffer allocation as the size
* that it is calculated with framebuffer information such as width,
* height and bpp.
*/
int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
/*
* get dma address from gem handle and this function could be used for
* other drivers such as 2d/3d acceleration drivers.
* with this function call, gem object reference count would be increased.
*/
dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
unsigned int gem_handle,
struct drm_file *filp);
/*
* put dma address from gem handle and this function could be used for
* other drivers such as 2d/3d acceleration drivers.
* with this function call, gem object reference count would be decreased.
*/
void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
unsigned int gem_handle,
struct drm_file *filp);
/* map user space allocated by malloc to pages. */
int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
/* get buffer information to memory region allocated by gem. */
int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
/* get buffer size to gem handle. */
unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
unsigned int gem_handle,
struct drm_file *file_priv);
/* free gem object. */
void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj);
/* create memory region for drm framebuffer. */
int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args);
/* map memory region for drm framebuffer to user space. */
int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
struct drm_device *dev, uint32_t handle,
uint64_t *offset);
/* page fault handler and mmap fault address(virtual) to physical memory. */
int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
/* set vm_flags and we can change the vm attribute to other one at here. */
int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
static inline int vma_is_io(struct vm_area_struct *vma)
{
return !!(vma->vm_flags & (VM_IO | VM_PFNMAP));
}
/* get a copy of a virtual memory region. */
struct vm_area_struct *exynos_gem_get_vma(struct vm_area_struct *vma);
/* release a userspace virtual memory area. */
void exynos_gem_put_vma(struct vm_area_struct *vma);
/* get pages from user space. */
int exynos_gem_get_pages_from_userptr(unsigned long start,
unsigned int npages,
struct page **pages,
struct vm_area_struct *vma);
/* drop the reference to pages. */
void exynos_gem_put_pages_to_userptr(struct page **pages,
unsigned int npages,
struct vm_area_struct *vma);
/* map sgt with dma region. */
int exynos_gem_map_sgt_with_dma(struct drm_device *drm_dev,
struct sg_table *sgt,
enum dma_data_direction dir);
/* unmap sgt from dma region. */
void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
struct sg_table *sgt,
enum dma_data_direction dir);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
*
* Authors:
* Eunchul Kim <chulspro.kim@samsung.com>
* Jinyoung Jeon <jy0.jeon@samsung.com>
* Sangmin Lee <lsmin.lee@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_GSC_H_
#define _EXYNOS_DRM_GSC_H_
/*
* TODO
* FIMD output interface notifier callback.
* Mixer output interface notifier callback.
*/
#endif /* _EXYNOS_DRM_GSC_H_ */

View file

@ -0,0 +1,143 @@
/* exynos_drm_iommu.c
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* Author: Inki Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <drmP.h>
#include <drm/exynos_drm.h>
#include <linux/dma-mapping.h>
#include <linux/iommu.h>
#include <linux/kref.h>
#include <asm/dma-iommu.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_iommu.h"
/*
* drm_create_iommu_mapping - create a mapping structure
*
* @drm_dev: DRM device
*/
int drm_create_iommu_mapping(struct drm_device *drm_dev)
{
struct dma_iommu_mapping *mapping = NULL;
struct exynos_drm_private *priv = drm_dev->dev_private;
struct device *dev = drm_dev->dev;
if (!priv->da_start)
priv->da_start = EXYNOS_DEV_ADDR_START;
if (!priv->da_space_size)
priv->da_space_size = EXYNOS_DEV_ADDR_SIZE;
mapping = arm_iommu_create_mapping(&platform_bus_type, priv->da_start,
priv->da_space_size);
if (IS_ERR(mapping))
return PTR_ERR(mapping);
dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
GFP_KERNEL);
if (!dev->dma_parms)
goto error;
dma_set_max_seg_size(dev, 0xffffffffu);
dev->archdata.mapping = mapping;
return 0;
error:
arm_iommu_release_mapping(mapping);
return -ENOMEM;
}
/*
* drm_release_iommu_mapping - release iommu mapping structure
*
* @drm_dev: DRM device
*
* if mapping->kref becomes 0 then all things related to iommu mapping
* will be released
*/
void drm_release_iommu_mapping(struct drm_device *drm_dev)
{
struct device *dev = drm_dev->dev;
arm_iommu_release_mapping(dev->archdata.mapping);
}
/*
* drm_iommu_attach_device- attach device to iommu mapping
*
* @drm_dev: DRM device
* @subdrv_dev: device to be attach
*
* This function should be called by sub drivers to attach it to iommu
* mapping.
*/
int drm_iommu_attach_device(struct drm_device *drm_dev,
struct device *subdrv_dev)
{
struct device *dev = drm_dev->dev;
int ret;
if (!dev->archdata.mapping) {
DRM_ERROR("iommu_mapping is null.\n");
return -EFAULT;
}
subdrv_dev->dma_parms = devm_kzalloc(subdrv_dev,
sizeof(*subdrv_dev->dma_parms),
GFP_KERNEL);
if (!subdrv_dev->dma_parms)
return -ENOMEM;
dma_set_max_seg_size(subdrv_dev, 0xffffffffu);
ret = arm_iommu_attach_device(subdrv_dev, dev->archdata.mapping);
if (ret < 0) {
DRM_DEBUG_KMS("failed iommu attach.\n");
return ret;
}
/*
* Set dma_ops to drm_device just one time.
*
* The dma mapping api needs device object and the api is used
* to allocate physial memory and map it with iommu table.
* If iommu attach succeeded, the sub driver would have dma_ops
* for iommu and also all sub drivers have same dma_ops.
*/
if (!dev->archdata.dma_ops)
dev->archdata.dma_ops = subdrv_dev->archdata.dma_ops;
return 0;
}
/*
* drm_iommu_detach_device -detach device address space mapping from device
*
* @drm_dev: DRM device
* @subdrv_dev: device to be detached
*
* This function should be called by sub drivers to detach it from iommu
* mapping
*/
void drm_iommu_detach_device(struct drm_device *drm_dev,
struct device *subdrv_dev)
{
struct device *dev = drm_dev->dev;
struct dma_iommu_mapping *mapping = dev->archdata.mapping;
if (!mapping || !mapping->domain)
return;
iommu_detach_device(mapping->domain, subdrv_dev);
drm_release_iommu_mapping(drm_dev);
}

View file

@ -0,0 +1,70 @@
/* exynos_drm_iommu.h
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* Authoer: Inki Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_IOMMU_H_
#define _EXYNOS_DRM_IOMMU_H_
#define EXYNOS_DEV_ADDR_START 0x20000000
#define EXYNOS_DEV_ADDR_SIZE 0x40000000
#ifdef CONFIG_DRM_EXYNOS_IOMMU
int drm_create_iommu_mapping(struct drm_device *drm_dev);
void drm_release_iommu_mapping(struct drm_device *drm_dev);
int drm_iommu_attach_device(struct drm_device *drm_dev,
struct device *subdrv_dev);
void drm_iommu_detach_device(struct drm_device *dev_dev,
struct device *subdrv_dev);
static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
{
#ifdef CONFIG_ARM_DMA_USE_IOMMU
struct device *dev = drm_dev->dev;
return dev->archdata.mapping ? true : false;
#else
return false;
#endif
}
#else
struct dma_iommu_mapping;
static inline int drm_create_iommu_mapping(struct drm_device *drm_dev)
{
return 0;
}
static inline void drm_release_iommu_mapping(struct drm_device *drm_dev)
{
}
static inline int drm_iommu_attach_device(struct drm_device *drm_dev,
struct device *subdrv_dev)
{
return 0;
}
static inline void drm_iommu_detach_device(struct drm_device *drm_dev,
struct device *subdrv_dev)
{
}
static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
{
return false;
}
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,252 @@
/*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
*
* Authors:
* Eunchul Kim <chulspro.kim@samsung.com>
* Jinyoung Jeon <jy0.jeon@samsung.com>
* Sangmin Lee <lsmin.lee@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_IPP_H_
#define _EXYNOS_DRM_IPP_H_
#define for_each_ipp_ops(pos) \
for (pos = 0; pos < EXYNOS_DRM_OPS_MAX; pos++)
#define for_each_ipp_planar(pos) \
for (pos = 0; pos < EXYNOS_DRM_PLANAR_MAX; pos++)
#define IPP_GET_LCD_WIDTH _IOR('F', 302, int)
#define IPP_GET_LCD_HEIGHT _IOR('F', 303, int)
#define IPP_SET_WRITEBACK _IOW('F', 304, u32)
/* definition of state */
enum drm_exynos_ipp_state {
IPP_STATE_IDLE,
IPP_STATE_START,
IPP_STATE_STOP,
};
/*
* A structure of command work information.
* @work: work structure.
* @ippdrv: current work ippdrv.
* @c_node: command node information.
* @ctrl: command control.
*/
struct drm_exynos_ipp_cmd_work {
struct work_struct work;
struct exynos_drm_ippdrv *ippdrv;
struct drm_exynos_ipp_cmd_node *c_node;
enum drm_exynos_ipp_ctrl ctrl;
};
/*
* A structure of command node.
*
* @list: list head to command queue information.
* @event_list: list head of event.
* @mem_list: list head to source,destination memory queue information.
* @lock: lock for synchronization of access to ioctl.
* @mem_lock: lock for synchronization of access to memory nodes.
* @event_lock: lock for synchronization of access to scheduled event.
* @start_complete: completion of start of command.
* @stop_complete: completion of stop of command.
* @property: property information.
* @start_work: start command work structure.
* @stop_work: stop command work structure.
* @event_work: event work structure.
* @state: state of command node.
* @filp: associated file pointer.
*/
struct drm_exynos_ipp_cmd_node {
struct list_head list;
struct list_head event_list;
struct list_head mem_list[EXYNOS_DRM_OPS_MAX];
struct mutex lock;
struct mutex mem_lock;
struct mutex event_lock;
struct completion start_complete;
struct completion stop_complete;
struct drm_exynos_ipp_property property;
struct drm_exynos_ipp_cmd_work *start_work;
struct drm_exynos_ipp_cmd_work *stop_work;
struct drm_exynos_ipp_event_work *event_work;
enum drm_exynos_ipp_state state;
struct drm_file *filp;
};
/*
* A structure of buffer information.
*
* @handles: Y, Cb, Cr each gem object handle.
* @base: Y, Cb, Cr each planar address.
*/
struct drm_exynos_ipp_buf_info {
unsigned long handles[EXYNOS_DRM_PLANAR_MAX];
dma_addr_t base[EXYNOS_DRM_PLANAR_MAX];
};
/*
* A structure of wb setting information.
*
* @enable: enable flag for wb.
* @refresh: HZ of the refresh rate.
*/
struct drm_exynos_ipp_set_wb {
__u32 enable;
__u32 refresh;
};
/*
* A structure of event work information.
*
* @work: work structure.
* @ippdrv: current work ippdrv.
* @buf_id: id of src, dst buffer.
*/
struct drm_exynos_ipp_event_work {
struct work_struct work;
struct exynos_drm_ippdrv *ippdrv;
u32 buf_id[EXYNOS_DRM_OPS_MAX];
};
/*
* A structure of source,destination operations.
*
* @set_fmt: set format of image.
* @set_transf: set transform(rotations, flip).
* @set_size: set size of region.
* @set_addr: set address for dma.
*/
struct exynos_drm_ipp_ops {
int (*set_fmt)(struct device *dev, u32 fmt);
int (*set_transf)(struct device *dev,
enum drm_exynos_degree degree,
enum drm_exynos_flip flip, bool *swap);
int (*set_size)(struct device *dev, int swap,
struct drm_exynos_pos *pos, struct drm_exynos_sz *sz);
int (*set_addr)(struct device *dev,
struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id,
enum drm_exynos_ipp_buf_type buf_type);
};
/*
* A structure of ipp driver.
*
* @drv_list: list head for registed sub driver information.
* @parent_dev: parent device information.
* @dev: platform device.
* @drm_dev: drm device.
* @dedicated: dedicated ipp device.
* @ops: source, destination operations.
* @event_workq: event work queue.
* @c_node: current command information.
* @cmd_list: list head for command information.
* @cmd_lock: lock for synchronization of access to cmd_list.
* @prop_list: property informations of current ipp driver.
* @check_property: check property about format, size, buffer.
* @reset: reset ipp block.
* @start: ipp each device start.
* @stop: ipp each device stop.
* @sched_event: work schedule handler.
*/
struct exynos_drm_ippdrv {
struct list_head drv_list;
struct device *parent_dev;
struct device *dev;
struct drm_device *drm_dev;
bool dedicated;
struct exynos_drm_ipp_ops *ops[EXYNOS_DRM_OPS_MAX];
struct workqueue_struct *event_workq;
struct drm_exynos_ipp_cmd_node *c_node;
struct list_head cmd_list;
struct mutex cmd_lock;
struct drm_exynos_ipp_prop_list prop_list;
int (*check_property)(struct device *dev,
struct drm_exynos_ipp_property *property);
int (*reset)(struct device *dev);
int (*start)(struct device *dev, enum drm_exynos_ipp_cmd cmd);
void (*stop)(struct device *dev, enum drm_exynos_ipp_cmd cmd);
void (*sched_event)(struct work_struct *work);
};
#ifdef CONFIG_DRM_EXYNOS_IPP
extern int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv);
extern int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv);
extern int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data,
struct drm_file *file);
extern int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
struct drm_file *file);
extern int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
struct drm_file *file);
extern int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,
struct drm_file *file);
extern int exynos_drm_ippnb_register(struct notifier_block *nb);
extern int exynos_drm_ippnb_unregister(struct notifier_block *nb);
extern int exynos_drm_ippnb_send_event(unsigned long val, void *v);
extern void ipp_sched_cmd(struct work_struct *work);
extern void ipp_sched_event(struct work_struct *work);
#else
static inline int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv)
{
return -ENODEV;
}
static inline int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv)
{
return -ENODEV;
}
static inline int exynos_drm_ipp_get_property(struct drm_device *drm_dev,
void *data,
struct drm_file *file_priv)
{
return -ENOTTY;
}
static inline int exynos_drm_ipp_set_property(struct drm_device *drm_dev,
void *data,
struct drm_file *file_priv)
{
return -ENOTTY;
}
static inline int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev,
void *data,
struct drm_file *file)
{
return -ENOTTY;
}
static inline int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev,
void *data,
struct drm_file *file)
{
return -ENOTTY;
}
static inline int exynos_drm_ippnb_register(struct notifier_block *nb)
{
return -ENODEV;
}
static inline int exynos_drm_ippnb_unregister(struct notifier_block *nb)
{
return -ENODEV;
}
static inline int exynos_drm_ippnb_send_event(unsigned long val, void *v)
{
return -ENOTTY;
}
#endif
#endif /* _EXYNOS_DRM_IPP_H_ */

View file

@ -0,0 +1,282 @@
/*
* Copyright (C) 2011 Samsung Electronics Co.Ltd
* Authors: Joonyoung Shim <jy0922.shim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <drm/drmP.h>
#include <drm/exynos_drm.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_plane.h"
#define to_exynos_plane(x) container_of(x, struct exynos_plane, base)
struct exynos_plane {
struct drm_plane base;
struct exynos_drm_overlay overlay;
bool enabled;
};
static const uint32_t formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_NV12,
DRM_FORMAT_NV12MT,
};
/*
* This function is to get X or Y size shown via screen. This needs length and
* start position of CRTC.
*
* <--- length --->
* CRTC ----------------
* ^ start ^ end
*
* There are six cases from a to f.
*
* <----- SCREEN ----->
* 0 last
* ----------|------------------|----------
* CRTCs
* a -------
* b -------
* c --------------------------
* d --------
* e -------
* f -------
*/
static int exynos_plane_get_size(int start, unsigned length, unsigned last)
{
int end = start + length;
int size = 0;
if (start <= 0) {
if (end > 0)
size = min_t(unsigned, end, last);
} else if (start <= last) {
size = min_t(unsigned, last - start, length);
}
return size;
}
int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h)
{
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
unsigned int actual_w;
unsigned int actual_h;
int nr;
int i;
nr = exynos_drm_fb_get_buf_cnt(fb);
for (i = 0; i < nr; i++) {
struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i);
if (!buffer) {
DRM_DEBUG_KMS("buffer is null\n");
return -EFAULT;
}
overlay->dma_addr[i] = buffer->dma_addr;
DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
i, (unsigned long)overlay->dma_addr[i]);
}
actual_w = exynos_plane_get_size(crtc_x, crtc_w, crtc->mode.hdisplay);
actual_h = exynos_plane_get_size(crtc_y, crtc_h, crtc->mode.vdisplay);
if (crtc_x < 0) {
if (actual_w)
src_x -= crtc_x;
crtc_x = 0;
}
if (crtc_y < 0) {
if (actual_h)
src_y -= crtc_y;
crtc_y = 0;
}
/* set drm framebuffer data. */
overlay->fb_x = src_x;
overlay->fb_y = src_y;
overlay->fb_width = fb->width;
overlay->fb_height = fb->height;
overlay->src_width = src_w;
overlay->src_height = src_h;
overlay->bpp = fb->bits_per_pixel;
overlay->pitch = fb->pitches[0];
overlay->pixel_format = fb->pixel_format;
/* set overlay range to be displayed. */
overlay->crtc_x = crtc_x;
overlay->crtc_y = crtc_y;
overlay->crtc_width = actual_w;
overlay->crtc_height = actual_h;
/* set drm mode data. */
overlay->mode_width = crtc->mode.hdisplay;
overlay->mode_height = crtc->mode.vdisplay;
overlay->refresh = crtc->mode.vrefresh;
overlay->scan_flag = crtc->mode.flags;
DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
overlay->crtc_x, overlay->crtc_y,
overlay->crtc_width, overlay->crtc_height);
plane->crtc = crtc;
exynos_drm_crtc_plane_mode_set(crtc, overlay);
return 0;
}
void exynos_plane_commit(struct drm_plane *plane)
{
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
exynos_drm_crtc_plane_commit(plane->crtc, overlay->zpos);
}
void exynos_plane_dpms(struct drm_plane *plane, int mode)
{
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
if (mode == DRM_MODE_DPMS_ON) {
if (exynos_plane->enabled)
return;
exynos_drm_crtc_plane_enable(plane->crtc, overlay->zpos);
exynos_plane->enabled = true;
} else {
if (!exynos_plane->enabled)
return;
exynos_drm_crtc_plane_disable(plane->crtc, overlay->zpos);
exynos_plane->enabled = false;
}
}
static int
exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h)
{
int ret;
ret = exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
crtc_w, crtc_h, src_x >> 16, src_y >> 16,
src_w >> 16, src_h >> 16);
if (ret < 0)
return ret;
exynos_plane_commit(plane);
exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
return 0;
}
static int exynos_disable_plane(struct drm_plane *plane)
{
exynos_plane_dpms(plane, DRM_MODE_DPMS_OFF);
return 0;
}
static void exynos_plane_destroy(struct drm_plane *plane)
{
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
exynos_disable_plane(plane);
drm_plane_cleanup(plane);
kfree(exynos_plane);
}
static int exynos_plane_set_property(struct drm_plane *plane,
struct drm_property *property,
uint64_t val)
{
struct drm_device *dev = plane->dev;
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_private *dev_priv = dev->dev_private;
if (property == dev_priv->plane_zpos_property) {
exynos_plane->overlay.zpos = val;
return 0;
}
return -EINVAL;
}
static struct drm_plane_funcs exynos_plane_funcs = {
.update_plane = exynos_update_plane,
.disable_plane = exynos_disable_plane,
.destroy = exynos_plane_destroy,
.set_property = exynos_plane_set_property,
};
static void exynos_plane_attach_zpos_property(struct drm_plane *plane)
{
struct drm_device *dev = plane->dev;
struct exynos_drm_private *dev_priv = dev->dev_private;
struct drm_property *prop;
prop = dev_priv->plane_zpos_property;
if (!prop) {
prop = drm_property_create_range(dev, 0, "zpos", 0,
MAX_PLANE - 1);
if (!prop)
return;
dev_priv->plane_zpos_property = prop;
}
drm_object_attach_property(&plane->base, prop, 0);
}
struct drm_plane *exynos_plane_init(struct drm_device *dev,
unsigned long possible_crtcs,
enum drm_plane_type type)
{
struct exynos_plane *exynos_plane;
int err;
exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
if (!exynos_plane)
return ERR_PTR(-ENOMEM);
err = drm_universal_plane_init(dev, &exynos_plane->base, possible_crtcs,
&exynos_plane_funcs, formats,
ARRAY_SIZE(formats), type);
if (err) {
DRM_ERROR("failed to initialize plane\n");
kfree(exynos_plane);
return ERR_PTR(err);
}
if (type == DRM_PLANE_TYPE_PRIMARY)
exynos_plane->overlay.zpos = DEFAULT_ZPOS;
else
exynos_plane_attach_zpos_property(&exynos_plane->base);
return &exynos_plane->base;
}

View file

@ -0,0 +1,21 @@
/*
* Copyright (C) 2011 Samsung Electronics Co.Ltd
* Authors: Joonyoung Shim <jy0922.shim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h);
void exynos_plane_commit(struct drm_plane *plane);
void exynos_plane_dpms(struct drm_plane *plane, int mode);
struct drm_plane *exynos_plane_init(struct drm_device *dev,
unsigned long possible_crtcs,
enum drm_plane_type type);

View file

@ -0,0 +1,856 @@
/*
* Copyright (C) 2012 Samsung Electronics Co.Ltd
* Authors:
* YoungJun Cho <yj44.cho@samsung.com>
* Eunchul Kim <chulspro.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 Foundationr
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <drm/drmP.h>
#include <drm/exynos_drm.h>
#include "regs-rotator.h"
#include "exynos_drm.h"
#include "exynos_drm_drv.h"
#include "exynos_drm_ipp.h"
/*
* Rotator supports image crop/rotator and input/output DMA operations.
* input DMA reads image data from the memory.
* output DMA writes image data to memory.
*
* M2M operation : supports crop/scale/rotation/csc so on.
* Memory ----> Rotator H/W ----> Memory.
*/
/*
* TODO
* 1. check suspend/resume api if needed.
* 2. need to check use case platform_device_id.
* 3. check src/dst size with, height.
* 4. need to add supported list in prop_list.
*/
#define get_rot_context(dev) platform_get_drvdata(to_platform_device(dev))
#define get_ctx_from_ippdrv(ippdrv) container_of(ippdrv,\
struct rot_context, ippdrv);
#define rot_read(offset) readl(rot->regs + (offset))
#define rot_write(cfg, offset) writel(cfg, rot->regs + (offset))
enum rot_irq_status {
ROT_IRQ_STATUS_COMPLETE = 8,
ROT_IRQ_STATUS_ILLEGAL = 9,
};
/*
* A structure of limitation.
*
* @min_w: minimum width.
* @min_h: minimum height.
* @max_w: maximum width.
* @max_h: maximum height.
* @align: align size.
*/
struct rot_limit {
u32 min_w;
u32 min_h;
u32 max_w;
u32 max_h;
u32 align;
};
/*
* A structure of limitation table.
*
* @ycbcr420_2p: case of YUV.
* @rgb888: case of RGB.
*/
struct rot_limit_table {
struct rot_limit ycbcr420_2p;
struct rot_limit rgb888;
};
/*
* A structure of rotator context.
* @ippdrv: prepare initialization using ippdrv.
* @regs_res: register resources.
* @regs: memory mapped io registers.
* @clock: rotator gate clock.
* @limit_tbl: limitation of rotator.
* @irq: irq number.
* @cur_buf_id: current operation buffer id.
* @suspended: suspended state.
*/
struct rot_context {
struct exynos_drm_ippdrv ippdrv;
struct resource *regs_res;
void __iomem *regs;
struct clk *clock;
struct rot_limit_table *limit_tbl;
int irq;
int cur_buf_id[EXYNOS_DRM_OPS_MAX];
bool suspended;
};
static void rotator_reg_set_irq(struct rot_context *rot, bool enable)
{
u32 val = rot_read(ROT_CONFIG);
if (enable == true)
val |= ROT_CONFIG_IRQ;
else
val &= ~ROT_CONFIG_IRQ;
rot_write(val, ROT_CONFIG);
}
static u32 rotator_reg_get_fmt(struct rot_context *rot)
{
u32 val = rot_read(ROT_CONTROL);
val &= ROT_CONTROL_FMT_MASK;
return val;
}
static enum rot_irq_status rotator_reg_get_irq_status(struct rot_context *rot)
{
u32 val = rot_read(ROT_STATUS);
val = ROT_STATUS_IRQ(val);
if (val == ROT_STATUS_IRQ_VAL_COMPLETE)
return ROT_IRQ_STATUS_COMPLETE;
return ROT_IRQ_STATUS_ILLEGAL;
}
static irqreturn_t rotator_irq_handler(int irq, void *arg)
{
struct rot_context *rot = arg;
struct exynos_drm_ippdrv *ippdrv = &rot->ippdrv;
struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
struct drm_exynos_ipp_event_work *event_work = c_node->event_work;
enum rot_irq_status irq_status;
u32 val;
/* Get execution result */
irq_status = rotator_reg_get_irq_status(rot);
/* clear status */
val = rot_read(ROT_STATUS);
val |= ROT_STATUS_IRQ_PENDING((u32)irq_status);
rot_write(val, ROT_STATUS);
if (irq_status == ROT_IRQ_STATUS_COMPLETE) {
event_work->ippdrv = ippdrv;
event_work->buf_id[EXYNOS_DRM_OPS_DST] =
rot->cur_buf_id[EXYNOS_DRM_OPS_DST];
queue_work(ippdrv->event_workq, &event_work->work);
} else {
DRM_ERROR("the SFR is set illegally\n");
}
return IRQ_HANDLED;
}
static void rotator_align_size(struct rot_context *rot, u32 fmt, u32 *hsize,
u32 *vsize)
{
struct rot_limit_table *limit_tbl = rot->limit_tbl;
struct rot_limit *limit;
u32 mask, val;
/* Get size limit */
if (fmt == ROT_CONTROL_FMT_RGB888)
limit = &limit_tbl->rgb888;
else
limit = &limit_tbl->ycbcr420_2p;
/* Get mask for rounding to nearest aligned val */
mask = ~((1 << limit->align) - 1);
/* Set aligned width */
val = ROT_ALIGN(*hsize, limit->align, mask);
if (val < limit->min_w)
*hsize = ROT_MIN(limit->min_w, mask);
else if (val > limit->max_w)
*hsize = ROT_MAX(limit->max_w, mask);
else
*hsize = val;
/* Set aligned height */
val = ROT_ALIGN(*vsize, limit->align, mask);
if (val < limit->min_h)
*vsize = ROT_MIN(limit->min_h, mask);
else if (val > limit->max_h)
*vsize = ROT_MAX(limit->max_h, mask);
else
*vsize = val;
}
static int rotator_src_set_fmt(struct device *dev, u32 fmt)
{
struct rot_context *rot = dev_get_drvdata(dev);
u32 val;
val = rot_read(ROT_CONTROL);
val &= ~ROT_CONTROL_FMT_MASK;
switch (fmt) {
case DRM_FORMAT_NV12:
val |= ROT_CONTROL_FMT_YCBCR420_2P;
break;
case DRM_FORMAT_XRGB8888:
val |= ROT_CONTROL_FMT_RGB888;
break;
default:
DRM_ERROR("invalid image format\n");
return -EINVAL;
}
rot_write(val, ROT_CONTROL);
return 0;
}
static inline bool rotator_check_reg_fmt(u32 fmt)
{
if ((fmt == ROT_CONTROL_FMT_YCBCR420_2P) ||
(fmt == ROT_CONTROL_FMT_RGB888))
return true;
return false;
}
static int rotator_src_set_size(struct device *dev, int swap,
struct drm_exynos_pos *pos,
struct drm_exynos_sz *sz)
{
struct rot_context *rot = dev_get_drvdata(dev);
u32 fmt, hsize, vsize;
u32 val;
/* Get format */
fmt = rotator_reg_get_fmt(rot);
if (!rotator_check_reg_fmt(fmt)) {
DRM_ERROR("invalid format.\n");
return -EINVAL;
}
/* Align buffer size */
hsize = sz->hsize;
vsize = sz->vsize;
rotator_align_size(rot, fmt, &hsize, &vsize);
/* Set buffer size configuration */
val = ROT_SET_BUF_SIZE_H(vsize) | ROT_SET_BUF_SIZE_W(hsize);
rot_write(val, ROT_SRC_BUF_SIZE);
/* Set crop image position configuration */
val = ROT_CROP_POS_Y(pos->y) | ROT_CROP_POS_X(pos->x);
rot_write(val, ROT_SRC_CROP_POS);
val = ROT_SRC_CROP_SIZE_H(pos->h) | ROT_SRC_CROP_SIZE_W(pos->w);
rot_write(val, ROT_SRC_CROP_SIZE);
return 0;
}
static int rotator_src_set_addr(struct device *dev,
struct drm_exynos_ipp_buf_info *buf_info,
u32 buf_id, enum drm_exynos_ipp_buf_type buf_type)
{
struct rot_context *rot = dev_get_drvdata(dev);
dma_addr_t addr[EXYNOS_DRM_PLANAR_MAX];
u32 val, fmt, hsize, vsize;
int i;
/* Set current buf_id */
rot->cur_buf_id[EXYNOS_DRM_OPS_SRC] = buf_id;
switch (buf_type) {
case IPP_BUF_ENQUEUE:
/* Set address configuration */
for_each_ipp_planar(i)
addr[i] = buf_info->base[i];
/* Get format */
fmt = rotator_reg_get_fmt(rot);
if (!rotator_check_reg_fmt(fmt)) {
DRM_ERROR("invalid format.\n");
return -EINVAL;
}
/* Re-set cb planar for NV12 format */
if ((fmt == ROT_CONTROL_FMT_YCBCR420_2P) &&
!addr[EXYNOS_DRM_PLANAR_CB]) {
val = rot_read(ROT_SRC_BUF_SIZE);
hsize = ROT_GET_BUF_SIZE_W(val);
vsize = ROT_GET_BUF_SIZE_H(val);
/* Set cb planar */
addr[EXYNOS_DRM_PLANAR_CB] =
addr[EXYNOS_DRM_PLANAR_Y] + hsize * vsize;
}
for_each_ipp_planar(i)
rot_write(addr[i], ROT_SRC_BUF_ADDR(i));
break;
case IPP_BUF_DEQUEUE:
for_each_ipp_planar(i)
rot_write(0x0, ROT_SRC_BUF_ADDR(i));
break;
default:
/* Nothing to do */
break;
}
return 0;
}
static int rotator_dst_set_transf(struct device *dev,
enum drm_exynos_degree degree,
enum drm_exynos_flip flip, bool *swap)
{
struct rot_context *rot = dev_get_drvdata(dev);
u32 val;
/* Set transform configuration */
val = rot_read(ROT_CONTROL);
val &= ~ROT_CONTROL_FLIP_MASK;
switch (flip) {
case EXYNOS_DRM_FLIP_VERTICAL:
val |= ROT_CONTROL_FLIP_VERTICAL;
break;
case EXYNOS_DRM_FLIP_HORIZONTAL:
val |= ROT_CONTROL_FLIP_HORIZONTAL;
break;
default:
/* Flip None */
break;
}
val &= ~ROT_CONTROL_ROT_MASK;
switch (degree) {
case EXYNOS_DRM_DEGREE_90:
val |= ROT_CONTROL_ROT_90;
break;
case EXYNOS_DRM_DEGREE_180:
val |= ROT_CONTROL_ROT_180;
break;
case EXYNOS_DRM_DEGREE_270:
val |= ROT_CONTROL_ROT_270;
break;
default:
/* Rotation 0 Degree */
break;
}
rot_write(val, ROT_CONTROL);
/* Check degree for setting buffer size swap */
if ((degree == EXYNOS_DRM_DEGREE_90) ||
(degree == EXYNOS_DRM_DEGREE_270))
*swap = true;
else
*swap = false;
return 0;
}
static int rotator_dst_set_size(struct device *dev, int swap,
struct drm_exynos_pos *pos,
struct drm_exynos_sz *sz)
{
struct rot_context *rot = dev_get_drvdata(dev);
u32 val, fmt, hsize, vsize;
/* Get format */
fmt = rotator_reg_get_fmt(rot);
if (!rotator_check_reg_fmt(fmt)) {
DRM_ERROR("invalid format.\n");
return -EINVAL;
}
/* Align buffer size */
hsize = sz->hsize;
vsize = sz->vsize;
rotator_align_size(rot, fmt, &hsize, &vsize);
/* Set buffer size configuration */
val = ROT_SET_BUF_SIZE_H(vsize) | ROT_SET_BUF_SIZE_W(hsize);
rot_write(val, ROT_DST_BUF_SIZE);
/* Set crop image position configuration */
val = ROT_CROP_POS_Y(pos->y) | ROT_CROP_POS_X(pos->x);
rot_write(val, ROT_DST_CROP_POS);
return 0;
}
static int rotator_dst_set_addr(struct device *dev,
struct drm_exynos_ipp_buf_info *buf_info,
u32 buf_id, enum drm_exynos_ipp_buf_type buf_type)
{
struct rot_context *rot = dev_get_drvdata(dev);
dma_addr_t addr[EXYNOS_DRM_PLANAR_MAX];
u32 val, fmt, hsize, vsize;
int i;
/* Set current buf_id */
rot->cur_buf_id[EXYNOS_DRM_OPS_DST] = buf_id;
switch (buf_type) {
case IPP_BUF_ENQUEUE:
/* Set address configuration */
for_each_ipp_planar(i)
addr[i] = buf_info->base[i];
/* Get format */
fmt = rotator_reg_get_fmt(rot);
if (!rotator_check_reg_fmt(fmt)) {
DRM_ERROR("invalid format.\n");
return -EINVAL;
}
/* Re-set cb planar for NV12 format */
if ((fmt == ROT_CONTROL_FMT_YCBCR420_2P) &&
!addr[EXYNOS_DRM_PLANAR_CB]) {
/* Get buf size */
val = rot_read(ROT_DST_BUF_SIZE);
hsize = ROT_GET_BUF_SIZE_W(val);
vsize = ROT_GET_BUF_SIZE_H(val);
/* Set cb planar */
addr[EXYNOS_DRM_PLANAR_CB] =
addr[EXYNOS_DRM_PLANAR_Y] + hsize * vsize;
}
for_each_ipp_planar(i)
rot_write(addr[i], ROT_DST_BUF_ADDR(i));
break;
case IPP_BUF_DEQUEUE:
for_each_ipp_planar(i)
rot_write(0x0, ROT_DST_BUF_ADDR(i));
break;
default:
/* Nothing to do */
break;
}
return 0;
}
static struct exynos_drm_ipp_ops rot_src_ops = {
.set_fmt = rotator_src_set_fmt,
.set_size = rotator_src_set_size,
.set_addr = rotator_src_set_addr,
};
static struct exynos_drm_ipp_ops rot_dst_ops = {
.set_transf = rotator_dst_set_transf,
.set_size = rotator_dst_set_size,
.set_addr = rotator_dst_set_addr,
};
static int rotator_init_prop_list(struct exynos_drm_ippdrv *ippdrv)
{
struct drm_exynos_ipp_prop_list *prop_list = &ippdrv->prop_list;
prop_list->version = 1;
prop_list->flip = (1 << EXYNOS_DRM_FLIP_VERTICAL) |
(1 << EXYNOS_DRM_FLIP_HORIZONTAL);
prop_list->degree = (1 << EXYNOS_DRM_DEGREE_0) |
(1 << EXYNOS_DRM_DEGREE_90) |
(1 << EXYNOS_DRM_DEGREE_180) |
(1 << EXYNOS_DRM_DEGREE_270);
prop_list->csc = 0;
prop_list->crop = 0;
prop_list->scale = 0;
return 0;
}
static inline bool rotator_check_drm_fmt(u32 fmt)
{
switch (fmt) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_NV12:
return true;
default:
DRM_DEBUG_KMS("not support format\n");
return false;
}
}
static inline bool rotator_check_drm_flip(enum drm_exynos_flip flip)
{
switch (flip) {
case EXYNOS_DRM_FLIP_NONE:
case EXYNOS_DRM_FLIP_VERTICAL:
case EXYNOS_DRM_FLIP_HORIZONTAL:
case EXYNOS_DRM_FLIP_BOTH:
return true;
default:
DRM_DEBUG_KMS("invalid flip\n");
return false;
}
}
static int rotator_ippdrv_check_property(struct device *dev,
struct drm_exynos_ipp_property *property)
{
struct drm_exynos_ipp_config *src_config =
&property->config[EXYNOS_DRM_OPS_SRC];
struct drm_exynos_ipp_config *dst_config =
&property->config[EXYNOS_DRM_OPS_DST];
struct drm_exynos_pos *src_pos = &src_config->pos;
struct drm_exynos_pos *dst_pos = &dst_config->pos;
struct drm_exynos_sz *src_sz = &src_config->sz;
struct drm_exynos_sz *dst_sz = &dst_config->sz;
bool swap = false;
/* Check format configuration */
if (src_config->fmt != dst_config->fmt) {
DRM_DEBUG_KMS("not support csc feature\n");
return -EINVAL;
}
if (!rotator_check_drm_fmt(dst_config->fmt)) {
DRM_DEBUG_KMS("invalid format\n");
return -EINVAL;
}
/* Check transform configuration */
if (src_config->degree != EXYNOS_DRM_DEGREE_0) {
DRM_DEBUG_KMS("not support source-side rotation\n");
return -EINVAL;
}
switch (dst_config->degree) {
case EXYNOS_DRM_DEGREE_90:
case EXYNOS_DRM_DEGREE_270:
swap = true;
case EXYNOS_DRM_DEGREE_0:
case EXYNOS_DRM_DEGREE_180:
/* No problem */
break;
default:
DRM_DEBUG_KMS("invalid degree\n");
return -EINVAL;
}
if (src_config->flip != EXYNOS_DRM_FLIP_NONE) {
DRM_DEBUG_KMS("not support source-side flip\n");
return -EINVAL;
}
if (!rotator_check_drm_flip(dst_config->flip)) {
DRM_DEBUG_KMS("invalid flip\n");
return -EINVAL;
}
/* Check size configuration */
if ((src_pos->x + src_pos->w > src_sz->hsize) ||
(src_pos->y + src_pos->h > src_sz->vsize)) {
DRM_DEBUG_KMS("out of source buffer bound\n");
return -EINVAL;
}
if (swap) {
if ((dst_pos->x + dst_pos->h > dst_sz->vsize) ||
(dst_pos->y + dst_pos->w > dst_sz->hsize)) {
DRM_DEBUG_KMS("out of destination buffer bound\n");
return -EINVAL;
}
if ((src_pos->w != dst_pos->h) || (src_pos->h != dst_pos->w)) {
DRM_DEBUG_KMS("not support scale feature\n");
return -EINVAL;
}
} else {
if ((dst_pos->x + dst_pos->w > dst_sz->hsize) ||
(dst_pos->y + dst_pos->h > dst_sz->vsize)) {
DRM_DEBUG_KMS("out of destination buffer bound\n");
return -EINVAL;
}
if ((src_pos->w != dst_pos->w) || (src_pos->h != dst_pos->h)) {
DRM_DEBUG_KMS("not support scale feature\n");
return -EINVAL;
}
}
return 0;
}
static int rotator_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
{
struct rot_context *rot = dev_get_drvdata(dev);
u32 val;
if (rot->suspended) {
DRM_ERROR("suspended state\n");
return -EPERM;
}
if (cmd != IPP_CMD_M2M) {
DRM_ERROR("not support cmd: %d\n", cmd);
return -EINVAL;
}
/* Set interrupt enable */
rotator_reg_set_irq(rot, true);
val = rot_read(ROT_CONTROL);
val |= ROT_CONTROL_START;
rot_write(val, ROT_CONTROL);
return 0;
}
static struct rot_limit_table rot_limit_tbl_4210 = {
.ycbcr420_2p = {
.min_w = 32,
.min_h = 32,
.max_w = SZ_64K,
.max_h = SZ_64K,
.align = 3,
},
.rgb888 = {
.min_w = 8,
.min_h = 8,
.max_w = SZ_16K,
.max_h = SZ_16K,
.align = 2,
},
};
static struct rot_limit_table rot_limit_tbl_4x12 = {
.ycbcr420_2p = {
.min_w = 32,
.min_h = 32,
.max_w = SZ_32K,
.max_h = SZ_32K,
.align = 3,
},
.rgb888 = {
.min_w = 8,
.min_h = 8,
.max_w = SZ_8K,
.max_h = SZ_8K,
.align = 2,
},
};
static struct rot_limit_table rot_limit_tbl_5250 = {
.ycbcr420_2p = {
.min_w = 32,
.min_h = 32,
.max_w = SZ_32K,
.max_h = SZ_32K,
.align = 3,
},
.rgb888 = {
.min_w = 8,
.min_h = 8,
.max_w = SZ_8K,
.max_h = SZ_8K,
.align = 1,
},
};
static const struct of_device_id exynos_rotator_match[] = {
{
.compatible = "samsung,exynos4210-rotator",
.data = &rot_limit_tbl_4210,
},
{
.compatible = "samsung,exynos4212-rotator",
.data = &rot_limit_tbl_4x12,
},
{
.compatible = "samsung,exynos5250-rotator",
.data = &rot_limit_tbl_5250,
},
{},
};
MODULE_DEVICE_TABLE(of, exynos_rotator_match);
static int rotator_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rot_context *rot;
struct exynos_drm_ippdrv *ippdrv;
const struct of_device_id *match;
int ret;
if (!dev->of_node) {
dev_err(dev, "cannot find of_node.\n");
return -ENODEV;
}
rot = devm_kzalloc(dev, sizeof(*rot), GFP_KERNEL);
if (!rot)
return -ENOMEM;
match = of_match_node(exynos_rotator_match, dev->of_node);
if (!match) {
dev_err(dev, "failed to match node\n");
return -ENODEV;
}
rot->limit_tbl = (struct rot_limit_table *)match->data;
rot->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rot->regs = devm_ioremap_resource(dev, rot->regs_res);
if (IS_ERR(rot->regs))
return PTR_ERR(rot->regs);
rot->irq = platform_get_irq(pdev, 0);
if (rot->irq < 0) {
dev_err(dev, "failed to get irq\n");
return rot->irq;
}
ret = devm_request_threaded_irq(dev, rot->irq, NULL,
rotator_irq_handler, IRQF_ONESHOT, "drm_rotator", rot);
if (ret < 0) {
dev_err(dev, "failed to request irq\n");
return ret;
}
rot->clock = devm_clk_get(dev, "rotator");
if (IS_ERR(rot->clock)) {
dev_err(dev, "failed to get clock\n");
return PTR_ERR(rot->clock);
}
pm_runtime_enable(dev);
ippdrv = &rot->ippdrv;
ippdrv->dev = dev;
ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &rot_src_ops;
ippdrv->ops[EXYNOS_DRM_OPS_DST] = &rot_dst_ops;
ippdrv->check_property = rotator_ippdrv_check_property;
ippdrv->start = rotator_ippdrv_start;
ret = rotator_init_prop_list(ippdrv);
if (ret < 0) {
dev_err(dev, "failed to init property list.\n");
goto err_ippdrv_register;
}
DRM_DEBUG_KMS("ippdrv[0x%x]\n", (int)ippdrv);
platform_set_drvdata(pdev, rot);
ret = exynos_drm_ippdrv_register(ippdrv);
if (ret < 0) {
dev_err(dev, "failed to register drm rotator device\n");
goto err_ippdrv_register;
}
dev_info(dev, "The exynos rotator is probed successfully\n");
return 0;
err_ippdrv_register:
pm_runtime_disable(dev);
return ret;
}
static int rotator_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rot_context *rot = dev_get_drvdata(dev);
struct exynos_drm_ippdrv *ippdrv = &rot->ippdrv;
exynos_drm_ippdrv_unregister(ippdrv);
pm_runtime_disable(dev);
return 0;
}
static int rotator_clk_crtl(struct rot_context *rot, bool enable)
{
if (enable) {
clk_enable(rot->clock);
rot->suspended = false;
} else {
clk_disable(rot->clock);
rot->suspended = true;
}
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int rotator_suspend(struct device *dev)
{
struct rot_context *rot = dev_get_drvdata(dev);
if (pm_runtime_suspended(dev))
return 0;
return rotator_clk_crtl(rot, false);
}
static int rotator_resume(struct device *dev)
{
struct rot_context *rot = dev_get_drvdata(dev);
if (!pm_runtime_suspended(dev))
return rotator_clk_crtl(rot, true);
return 0;
}
#endif
#ifdef CONFIG_PM_RUNTIME
static int rotator_runtime_suspend(struct device *dev)
{
struct rot_context *rot = dev_get_drvdata(dev);
return rotator_clk_crtl(rot, false);
}
static int rotator_runtime_resume(struct device *dev)
{
struct rot_context *rot = dev_get_drvdata(dev);
return rotator_clk_crtl(rot, true);
}
#endif
static const struct dev_pm_ops rotator_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(rotator_suspend, rotator_resume)
SET_RUNTIME_PM_OPS(rotator_runtime_suspend, rotator_runtime_resume,
NULL)
};
struct platform_driver rotator_driver = {
.probe = rotator_probe,
.remove = rotator_remove,
.driver = {
.name = "exynos-rot",
.owner = THIS_MODULE,
.pm = &rotator_pm_ops,
.of_match_table = exynos_rotator_match,
},
};

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
*
* Authors:
* YoungJun Cho <yj44.cho@samsung.com>
* Eunchul Kim <chulspro.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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_ROTATOR_H_
#define _EXYNOS_DRM_ROTATOR_H_
/* TODO */
#endif

View file

@ -0,0 +1,679 @@
/* exynos_drm_vidi.c
*
* Copyright (C) 2012 Samsung Electronics Co.Ltd
* Authors:
* Inki Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <drm/drmP.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <drm/exynos_drm.h>
#include <drm/drm_edid.h>
#include <drm/drm_crtc_helper.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
#include "exynos_drm_encoder.h"
#include "exynos_drm_vidi.h"
/* vidi has totally three virtual windows. */
#define WINDOWS_NR 3
#define get_vidi_mgr(dev) platform_get_drvdata(to_platform_device(dev))
#define ctx_from_connector(c) container_of(c, struct vidi_context, \
connector)
struct vidi_win_data {
unsigned int offset_x;
unsigned int offset_y;
unsigned int ovl_width;
unsigned int ovl_height;
unsigned int fb_width;
unsigned int fb_height;
unsigned int bpp;
dma_addr_t dma_addr;
unsigned int buf_offsize;
unsigned int line_size; /* bytes */
bool enabled;
};
struct vidi_context {
struct drm_device *drm_dev;
struct drm_crtc *crtc;
struct drm_encoder *encoder;
struct drm_connector connector;
struct exynos_drm_subdrv subdrv;
struct vidi_win_data win_data[WINDOWS_NR];
struct edid *raw_edid;
unsigned int clkdiv;
unsigned int default_win;
unsigned long irq_flags;
unsigned int connected;
bool vblank_on;
bool suspended;
bool direct_vblank;
struct work_struct work;
struct mutex lock;
int pipe;
};
static const char fake_edid_info[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd,
0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00,
0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1,
0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83,
0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00,
0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a,
0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00,
0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 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, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x06
};
static void vidi_apply(struct exynos_drm_manager *mgr)
{
struct vidi_context *ctx = mgr->ctx;
struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
struct vidi_win_data *win_data;
int i;
for (i = 0; i < WINDOWS_NR; i++) {
win_data = &ctx->win_data[i];
if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
mgr_ops->win_commit(mgr, i);
}
if (mgr_ops && mgr_ops->commit)
mgr_ops->commit(mgr);
}
static void vidi_commit(struct exynos_drm_manager *mgr)
{
struct vidi_context *ctx = mgr->ctx;
if (ctx->suspended)
return;
}
static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
{
struct vidi_context *ctx = mgr->ctx;
if (ctx->suspended)
return -EPERM;
if (!test_and_set_bit(0, &ctx->irq_flags))
ctx->vblank_on = true;
ctx->direct_vblank = true;
/*
* in case of page flip request, vidi_finish_pageflip function
* will not be called because direct_vblank is true and then
* that function will be called by manager_ops->win_commit callback
*/
schedule_work(&ctx->work);
return 0;
}
static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
{
struct vidi_context *ctx = mgr->ctx;
if (ctx->suspended)
return;
if (test_and_clear_bit(0, &ctx->irq_flags))
ctx->vblank_on = false;
}
static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
struct exynos_drm_overlay *overlay)
{
struct vidi_context *ctx = mgr->ctx;
struct vidi_win_data *win_data;
int win;
unsigned long offset;
if (!overlay) {
DRM_ERROR("overlay is NULL\n");
return;
}
win = overlay->zpos;
if (win == DEFAULT_ZPOS)
win = ctx->default_win;
if (win < 0 || win >= WINDOWS_NR)
return;
offset = overlay->fb_x * (overlay->bpp >> 3);
offset += overlay->fb_y * overlay->pitch;
DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
win_data = &ctx->win_data[win];
win_data->offset_x = overlay->crtc_x;
win_data->offset_y = overlay->crtc_y;
win_data->ovl_width = overlay->crtc_width;
win_data->ovl_height = overlay->crtc_height;
win_data->fb_width = overlay->fb_width;
win_data->fb_height = overlay->fb_height;
win_data->dma_addr = overlay->dma_addr[0] + offset;
win_data->bpp = overlay->bpp;
win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
(overlay->bpp >> 3);
win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
/*
* some parts of win_data should be transferred to user side
* through specific ioctl.
*/
DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
win_data->offset_x, win_data->offset_y);
DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
win_data->ovl_width, win_data->ovl_height);
DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
overlay->fb_width, overlay->crtc_width);
}
static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
{
struct vidi_context *ctx = mgr->ctx;
struct vidi_win_data *win_data;
int win = zpos;
if (ctx->suspended)
return;
if (win == DEFAULT_ZPOS)
win = ctx->default_win;
if (win < 0 || win >= WINDOWS_NR)
return;
win_data = &ctx->win_data[win];
win_data->enabled = true;
DRM_DEBUG_KMS("dma_addr = %pad\n", &win_data->dma_addr);
if (ctx->vblank_on)
schedule_work(&ctx->work);
}
static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
{
struct vidi_context *ctx = mgr->ctx;
struct vidi_win_data *win_data;
int win = zpos;
if (win == DEFAULT_ZPOS)
win = ctx->default_win;
if (win < 0 || win >= WINDOWS_NR)
return;
win_data = &ctx->win_data[win];
win_data->enabled = false;
/* TODO. */
}
static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
{
struct vidi_context *ctx = mgr->ctx;
DRM_DEBUG_KMS("%s\n", __FILE__);
if (enable != false && enable != true)
return -EINVAL;
if (enable) {
ctx->suspended = false;
/* if vblank was enabled status, enable it again. */
if (test_and_clear_bit(0, &ctx->irq_flags))
vidi_enable_vblank(mgr);
vidi_apply(mgr);
} else {
ctx->suspended = true;
}
return 0;
}
static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
{
struct vidi_context *ctx = mgr->ctx;
DRM_DEBUG_KMS("%d\n", mode);
mutex_lock(&ctx->lock);
switch (mode) {
case DRM_MODE_DPMS_ON:
vidi_power_on(mgr, true);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
vidi_power_on(mgr, false);
break;
default:
DRM_DEBUG_KMS("unspecified mode %d\n", mode);
break;
}
mutex_unlock(&ctx->lock);
}
static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
struct drm_device *drm_dev)
{
struct vidi_context *ctx = mgr->ctx;
struct exynos_drm_private *priv = drm_dev->dev_private;
mgr->drm_dev = ctx->drm_dev = drm_dev;
mgr->pipe = ctx->pipe = priv->pipe++;
return 0;
}
static struct exynos_drm_manager_ops vidi_manager_ops = {
.dpms = vidi_dpms,
.commit = vidi_commit,
.enable_vblank = vidi_enable_vblank,
.disable_vblank = vidi_disable_vblank,
.win_mode_set = vidi_win_mode_set,
.win_commit = vidi_win_commit,
.win_disable = vidi_win_disable,
};
static struct exynos_drm_manager vidi_manager = {
.type = EXYNOS_DISPLAY_TYPE_VIDI,
.ops = &vidi_manager_ops,
};
static void vidi_fake_vblank_handler(struct work_struct *work)
{
struct vidi_context *ctx = container_of(work, struct vidi_context,
work);
if (ctx->pipe < 0)
return;
/* refresh rate is about 50Hz. */
usleep_range(16000, 20000);
mutex_lock(&ctx->lock);
if (ctx->direct_vblank) {
drm_handle_vblank(ctx->drm_dev, ctx->pipe);
ctx->direct_vblank = false;
mutex_unlock(&ctx->lock);
return;
}
mutex_unlock(&ctx->lock);
exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
}
static int vidi_show_connection(struct device *dev,
struct device_attribute *attr, char *buf)
{
int rc;
struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
struct vidi_context *ctx = mgr->ctx;
mutex_lock(&ctx->lock);
rc = sprintf(buf, "%d\n", ctx->connected);
mutex_unlock(&ctx->lock);
return rc;
}
static int vidi_store_connection(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
struct vidi_context *ctx = mgr->ctx;
int ret;
ret = kstrtoint(buf, 0, &ctx->connected);
if (ret)
return ret;
if (ctx->connected > 1)
return -EINVAL;
/* use fake edid data for test. */
if (!ctx->raw_edid)
ctx->raw_edid = (struct edid *)fake_edid_info;
/* if raw_edid isn't same as fake data then it can't be tested. */
if (ctx->raw_edid != (struct edid *)fake_edid_info) {
DRM_DEBUG_KMS("edid data is not fake data.\n");
return -EINVAL;
}
DRM_DEBUG_KMS("requested connection.\n");
drm_helper_hpd_irq_event(ctx->drm_dev);
return len;
}
static DEVICE_ATTR(connection, 0644, vidi_show_connection,
vidi_store_connection);
int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
struct drm_file *file_priv)
{
struct vidi_context *ctx = NULL;
struct drm_encoder *encoder;
struct exynos_drm_display *display;
struct drm_exynos_vidi_connection *vidi = data;
if (!vidi) {
DRM_DEBUG_KMS("user data for vidi is null.\n");
return -EINVAL;
}
if (vidi->connection > 1) {
DRM_DEBUG_KMS("connection should be 0 or 1.\n");
return -EINVAL;
}
list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
head) {
display = exynos_drm_get_display(encoder);
if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
ctx = display->ctx;
break;
}
}
if (!ctx) {
DRM_DEBUG_KMS("not found virtual device type encoder.\n");
return -EINVAL;
}
if (ctx->connected == vidi->connection) {
DRM_DEBUG_KMS("same connection request.\n");
return -EINVAL;
}
if (vidi->connection) {
struct edid *raw_edid = (struct edid *)(uint32_t)vidi->edid;
if (!drm_edid_is_valid(raw_edid)) {
DRM_DEBUG_KMS("edid data is invalid.\n");
return -EINVAL;
}
ctx->raw_edid = drm_edid_duplicate(raw_edid);
if (!ctx->raw_edid) {
DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
return -ENOMEM;
}
} else {
/*
* with connection = 0, free raw_edid
* only if raw edid data isn't same as fake data.
*/
if (ctx->raw_edid && ctx->raw_edid !=
(struct edid *)fake_edid_info) {
kfree(ctx->raw_edid);
ctx->raw_edid = NULL;
}
}
ctx->connected = vidi->connection;
drm_helper_hpd_irq_event(ctx->drm_dev);
return 0;
}
static enum drm_connector_status vidi_detect(struct drm_connector *connector,
bool force)
{
struct vidi_context *ctx = ctx_from_connector(connector);
/*
* connection request would come from user side
* to do hotplug through specific ioctl.
*/
return ctx->connected ? connector_status_connected :
connector_status_disconnected;
}
static void vidi_connector_destroy(struct drm_connector *connector)
{
}
static struct drm_connector_funcs vidi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = vidi_detect,
.destroy = vidi_connector_destroy,
};
static int vidi_get_modes(struct drm_connector *connector)
{
struct vidi_context *ctx = ctx_from_connector(connector);
struct edid *edid;
int edid_len;
/*
* the edid data comes from user side and it would be set
* to ctx->raw_edid through specific ioctl.
*/
if (!ctx->raw_edid) {
DRM_DEBUG_KMS("raw_edid is null.\n");
return -EFAULT;
}
edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH;
edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL);
if (!edid) {
DRM_DEBUG_KMS("failed to allocate edid\n");
return -ENOMEM;
}
drm_mode_connector_update_edid_property(connector, edid);
return drm_add_edid_modes(connector, edid);
}
static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector)
{
struct vidi_context *ctx = ctx_from_connector(connector);
return ctx->encoder;
}
static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
.get_modes = vidi_get_modes,
.best_encoder = vidi_best_encoder,
};
static int vidi_create_connector(struct exynos_drm_display *display,
struct drm_encoder *encoder)
{
struct vidi_context *ctx = display->ctx;
struct drm_connector *connector = &ctx->connector;
int ret;
ctx->encoder = encoder;
connector->polled = DRM_CONNECTOR_POLL_HPD;
ret = drm_connector_init(ctx->drm_dev, connector,
&vidi_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
if (ret) {
DRM_ERROR("Failed to initialize connector with drm\n");
return ret;
}
drm_connector_helper_add(connector, &vidi_connector_helper_funcs);
drm_connector_register(connector);
drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}
static struct exynos_drm_display_ops vidi_display_ops = {
.create_connector = vidi_create_connector,
};
static struct exynos_drm_display vidi_display = {
.type = EXYNOS_DISPLAY_TYPE_VIDI,
.ops = &vidi_display_ops,
};
static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
{
struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
struct vidi_context *ctx = mgr->ctx;
struct drm_crtc *crtc = ctx->crtc;
int ret;
vidi_mgr_initialize(mgr, drm_dev);
ret = exynos_drm_crtc_create(&vidi_manager);
if (ret) {
DRM_ERROR("failed to create crtc.\n");
return ret;
}
ret = exynos_drm_create_enc_conn(drm_dev, &vidi_display);
if (ret) {
crtc->funcs->destroy(crtc);
DRM_ERROR("failed to create encoder and connector.\n");
return ret;
}
return 0;
}
static int vidi_probe(struct platform_device *pdev)
{
struct exynos_drm_subdrv *subdrv;
struct vidi_context *ctx;
int ret;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->default_win = 0;
INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
vidi_manager.ctx = ctx;
vidi_display.ctx = ctx;
mutex_init(&ctx->lock);
platform_set_drvdata(pdev, &vidi_manager);
subdrv = &ctx->subdrv;
subdrv->dev = &pdev->dev;
subdrv->probe = vidi_subdrv_probe;
ret = exynos_drm_subdrv_register(subdrv);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register drm vidi device\n");
return ret;
}
ret = device_create_file(&pdev->dev, &dev_attr_connection);
if (ret < 0) {
exynos_drm_subdrv_unregister(subdrv);
DRM_INFO("failed to create connection sysfs.\n");
}
return 0;
}
static int vidi_remove(struct platform_device *pdev)
{
struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
struct vidi_context *ctx = mgr->ctx;
if (ctx->raw_edid != (struct edid *)fake_edid_info) {
kfree(ctx->raw_edid);
ctx->raw_edid = NULL;
return -EINVAL;
}
return 0;
}
struct platform_driver vidi_driver = {
.probe = vidi_probe,
.remove = vidi_remove,
.driver = {
.name = "exynos-drm-vidi",
.owner = THIS_MODULE,
},
};
int exynos_drm_probe_vidi(void)
{
struct platform_device *pdev;
int ret;
pdev = platform_device_register_simple("exynos-drm-vidi", -1, NULL, 0);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
ret = platform_driver_register(&vidi_driver);
if (ret) {
platform_device_unregister(pdev);
return ret;
}
return ret;
}
void exynos_drm_remove_vidi(void)
{
struct vidi_context *ctx = vidi_manager.ctx;
struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
struct platform_device *pdev = to_platform_device(subdrv->dev);
platform_driver_unregister(&vidi_driver);
platform_device_unregister(pdev);
}

View file

@ -0,0 +1,22 @@
/* exynos_drm_vidi.h
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* Author: Inki Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _EXYNOS_DRM_VIDI_H_
#define _EXYNOS_DRM_VIDI_H_
#ifdef CONFIG_DRM_EXYNOS_VIDI
int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
struct drm_file *file_priv);
#else
#define vidi_connection_ioctl NULL
#endif
#endif

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,20 @@
/*
* Copyright (C) 2013 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _EXYNOS_MIXER_H_
#define _EXYNOS_MIXER_H_
/* This function returns 0 if the given timing is valid for the mixer */
int mixer_check_mode(struct drm_display_mode *mode);
#endif

View file

@ -0,0 +1,668 @@
/* drivers/gpu/drm/exynos/regs-fimc.h
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Register definition file for Samsung Camera Interface (FIMC) 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 EXYNOS_REGS_FIMC_H
#define EXYNOS_REGS_FIMC_H
/*
* Register part
*/
/* Input source format */
#define EXYNOS_CISRCFMT (0x00)
/* Window offset */
#define EXYNOS_CIWDOFST (0x04)
/* Global control */
#define EXYNOS_CIGCTRL (0x08)
/* Window offset 2 */
#define EXYNOS_CIWDOFST2 (0x14)
/* Y 1st frame start address for output DMA */
#define EXYNOS_CIOYSA1 (0x18)
/* Y 2nd frame start address for output DMA */
#define EXYNOS_CIOYSA2 (0x1c)
/* Y 3rd frame start address for output DMA */
#define EXYNOS_CIOYSA3 (0x20)
/* Y 4th frame start address for output DMA */
#define EXYNOS_CIOYSA4 (0x24)
/* Cb 1st frame start address for output DMA */
#define EXYNOS_CIOCBSA1 (0x28)
/* Cb 2nd frame start address for output DMA */
#define EXYNOS_CIOCBSA2 (0x2c)
/* Cb 3rd frame start address for output DMA */
#define EXYNOS_CIOCBSA3 (0x30)
/* Cb 4th frame start address for output DMA */
#define EXYNOS_CIOCBSA4 (0x34)
/* Cr 1st frame start address for output DMA */
#define EXYNOS_CIOCRSA1 (0x38)
/* Cr 2nd frame start address for output DMA */
#define EXYNOS_CIOCRSA2 (0x3c)
/* Cr 3rd frame start address for output DMA */
#define EXYNOS_CIOCRSA3 (0x40)
/* Cr 4th frame start address for output DMA */
#define EXYNOS_CIOCRSA4 (0x44)
/* Target image format */
#define EXYNOS_CITRGFMT (0x48)
/* Output DMA control */
#define EXYNOS_CIOCTRL (0x4c)
/* Pre-scaler control 1 */
#define EXYNOS_CISCPRERATIO (0x50)
/* Pre-scaler control 2 */
#define EXYNOS_CISCPREDST (0x54)
/* Main scaler control */
#define EXYNOS_CISCCTRL (0x58)
/* Target area */
#define EXYNOS_CITAREA (0x5c)
/* Status */
#define EXYNOS_CISTATUS (0x64)
/* Status2 */
#define EXYNOS_CISTATUS2 (0x68)
/* Image capture enable command */
#define EXYNOS_CIIMGCPT (0xc0)
/* Capture sequence */
#define EXYNOS_CICPTSEQ (0xc4)
/* Image effects */
#define EXYNOS_CIIMGEFF (0xd0)
/* Y frame start address for input DMA */
#define EXYNOS_CIIYSA0 (0xd4)
/* Cb frame start address for input DMA */
#define EXYNOS_CIICBSA0 (0xd8)
/* Cr frame start address for input DMA */
#define EXYNOS_CIICRSA0 (0xdc)
/* Input DMA Y Line Skip */
#define EXYNOS_CIILINESKIP_Y (0xec)
/* Input DMA Cb Line Skip */
#define EXYNOS_CIILINESKIP_CB (0xf0)
/* Input DMA Cr Line Skip */
#define EXYNOS_CIILINESKIP_CR (0xf4)
/* Real input DMA image size */
#define EXYNOS_CIREAL_ISIZE (0xf8)
/* Input DMA control */
#define EXYNOS_MSCTRL (0xfc)
/* Y frame start address for input DMA */
#define EXYNOS_CIIYSA1 (0x144)
/* Cb frame start address for input DMA */
#define EXYNOS_CIICBSA1 (0x148)
/* Cr frame start address for input DMA */
#define EXYNOS_CIICRSA1 (0x14c)
/* Output DMA Y offset */
#define EXYNOS_CIOYOFF (0x168)
/* Output DMA CB offset */
#define EXYNOS_CIOCBOFF (0x16c)
/* Output DMA CR offset */
#define EXYNOS_CIOCROFF (0x170)
/* Input DMA Y offset */
#define EXYNOS_CIIYOFF (0x174)
/* Input DMA CB offset */
#define EXYNOS_CIICBOFF (0x178)
/* Input DMA CR offset */
#define EXYNOS_CIICROFF (0x17c)
/* Input DMA original image size */
#define EXYNOS_ORGISIZE (0x180)
/* Output DMA original image size */
#define EXYNOS_ORGOSIZE (0x184)
/* Real output DMA image size */
#define EXYNOS_CIEXTEN (0x188)
/* DMA parameter */
#define EXYNOS_CIDMAPARAM (0x18c)
/* MIPI CSI image format */
#define EXYNOS_CSIIMGFMT (0x194)
/* FIMC Clock Source Select */
#define EXYNOS_MISC_FIMC (0x198)
/* Add for FIMC v5.1 */
/* Output Frame Buffer Sequence */
#define EXYNOS_CIFCNTSEQ (0x1fc)
/* Y 5th frame start address for output DMA */
#define EXYNOS_CIOYSA5 (0x200)
/* Y 6th frame start address for output DMA */
#define EXYNOS_CIOYSA6 (0x204)
/* Y 7th frame start address for output DMA */
#define EXYNOS_CIOYSA7 (0x208)
/* Y 8th frame start address for output DMA */
#define EXYNOS_CIOYSA8 (0x20c)
/* Y 9th frame start address for output DMA */
#define EXYNOS_CIOYSA9 (0x210)
/* Y 10th frame start address for output DMA */
#define EXYNOS_CIOYSA10 (0x214)
/* Y 11th frame start address for output DMA */
#define EXYNOS_CIOYSA11 (0x218)
/* Y 12th frame start address for output DMA */
#define EXYNOS_CIOYSA12 (0x21c)
/* Y 13th frame start address for output DMA */
#define EXYNOS_CIOYSA13 (0x220)
/* Y 14th frame start address for output DMA */
#define EXYNOS_CIOYSA14 (0x224)
/* Y 15th frame start address for output DMA */
#define EXYNOS_CIOYSA15 (0x228)
/* Y 16th frame start address for output DMA */
#define EXYNOS_CIOYSA16 (0x22c)
/* Y 17th frame start address for output DMA */
#define EXYNOS_CIOYSA17 (0x230)
/* Y 18th frame start address for output DMA */
#define EXYNOS_CIOYSA18 (0x234)
/* Y 19th frame start address for output DMA */
#define EXYNOS_CIOYSA19 (0x238)
/* Y 20th frame start address for output DMA */
#define EXYNOS_CIOYSA20 (0x23c)
/* Y 21th frame start address for output DMA */
#define EXYNOS_CIOYSA21 (0x240)
/* Y 22th frame start address for output DMA */
#define EXYNOS_CIOYSA22 (0x244)
/* Y 23th frame start address for output DMA */
#define EXYNOS_CIOYSA23 (0x248)
/* Y 24th frame start address for output DMA */
#define EXYNOS_CIOYSA24 (0x24c)
/* Y 25th frame start address for output DMA */
#define EXYNOS_CIOYSA25 (0x250)
/* Y 26th frame start address for output DMA */
#define EXYNOS_CIOYSA26 (0x254)
/* Y 27th frame start address for output DMA */
#define EXYNOS_CIOYSA27 (0x258)
/* Y 28th frame start address for output DMA */
#define EXYNOS_CIOYSA28 (0x25c)
/* Y 29th frame start address for output DMA */
#define EXYNOS_CIOYSA29 (0x260)
/* Y 30th frame start address for output DMA */
#define EXYNOS_CIOYSA30 (0x264)
/* Y 31th frame start address for output DMA */
#define EXYNOS_CIOYSA31 (0x268)
/* Y 32th frame start address for output DMA */
#define EXYNOS_CIOYSA32 (0x26c)
/* CB 5th frame start address for output DMA */
#define EXYNOS_CIOCBSA5 (0x270)
/* CB 6th frame start address for output DMA */
#define EXYNOS_CIOCBSA6 (0x274)
/* CB 7th frame start address for output DMA */
#define EXYNOS_CIOCBSA7 (0x278)
/* CB 8th frame start address for output DMA */
#define EXYNOS_CIOCBSA8 (0x27c)
/* CB 9th frame start address for output DMA */
#define EXYNOS_CIOCBSA9 (0x280)
/* CB 10th frame start address for output DMA */
#define EXYNOS_CIOCBSA10 (0x284)
/* CB 11th frame start address for output DMA */
#define EXYNOS_CIOCBSA11 (0x288)
/* CB 12th frame start address for output DMA */
#define EXYNOS_CIOCBSA12 (0x28c)
/* CB 13th frame start address for output DMA */
#define EXYNOS_CIOCBSA13 (0x290)
/* CB 14th frame start address for output DMA */
#define EXYNOS_CIOCBSA14 (0x294)
/* CB 15th frame start address for output DMA */
#define EXYNOS_CIOCBSA15 (0x298)
/* CB 16th frame start address for output DMA */
#define EXYNOS_CIOCBSA16 (0x29c)
/* CB 17th frame start address for output DMA */
#define EXYNOS_CIOCBSA17 (0x2a0)
/* CB 18th frame start address for output DMA */
#define EXYNOS_CIOCBSA18 (0x2a4)
/* CB 19th frame start address for output DMA */
#define EXYNOS_CIOCBSA19 (0x2a8)
/* CB 20th frame start address for output DMA */
#define EXYNOS_CIOCBSA20 (0x2ac)
/* CB 21th frame start address for output DMA */
#define EXYNOS_CIOCBSA21 (0x2b0)
/* CB 22th frame start address for output DMA */
#define EXYNOS_CIOCBSA22 (0x2b4)
/* CB 23th frame start address for output DMA */
#define EXYNOS_CIOCBSA23 (0x2b8)
/* CB 24th frame start address for output DMA */
#define EXYNOS_CIOCBSA24 (0x2bc)
/* CB 25th frame start address for output DMA */
#define EXYNOS_CIOCBSA25 (0x2c0)
/* CB 26th frame start address for output DMA */
#define EXYNOS_CIOCBSA26 (0x2c4)
/* CB 27th frame start address for output DMA */
#define EXYNOS_CIOCBSA27 (0x2c8)
/* CB 28th frame start address for output DMA */
#define EXYNOS_CIOCBSA28 (0x2cc)
/* CB 29th frame start address for output DMA */
#define EXYNOS_CIOCBSA29 (0x2d0)
/* CB 30th frame start address for output DMA */
#define EXYNOS_CIOCBSA30 (0x2d4)
/* CB 31th frame start address for output DMA */
#define EXYNOS_CIOCBSA31 (0x2d8)
/* CB 32th frame start address for output DMA */
#define EXYNOS_CIOCBSA32 (0x2dc)
/* CR 5th frame start address for output DMA */
#define EXYNOS_CIOCRSA5 (0x2e0)
/* CR 6th frame start address for output DMA */
#define EXYNOS_CIOCRSA6 (0x2e4)
/* CR 7th frame start address for output DMA */
#define EXYNOS_CIOCRSA7 (0x2e8)
/* CR 8th frame start address for output DMA */
#define EXYNOS_CIOCRSA8 (0x2ec)
/* CR 9th frame start address for output DMA */
#define EXYNOS_CIOCRSA9 (0x2f0)
/* CR 10th frame start address for output DMA */
#define EXYNOS_CIOCRSA10 (0x2f4)
/* CR 11th frame start address for output DMA */
#define EXYNOS_CIOCRSA11 (0x2f8)
/* CR 12th frame start address for output DMA */
#define EXYNOS_CIOCRSA12 (0x2fc)
/* CR 13th frame start address for output DMA */
#define EXYNOS_CIOCRSA13 (0x300)
/* CR 14th frame start address for output DMA */
#define EXYNOS_CIOCRSA14 (0x304)
/* CR 15th frame start address for output DMA */
#define EXYNOS_CIOCRSA15 (0x308)
/* CR 16th frame start address for output DMA */
#define EXYNOS_CIOCRSA16 (0x30c)
/* CR 17th frame start address for output DMA */
#define EXYNOS_CIOCRSA17 (0x310)
/* CR 18th frame start address for output DMA */
#define EXYNOS_CIOCRSA18 (0x314)
/* CR 19th frame start address for output DMA */
#define EXYNOS_CIOCRSA19 (0x318)
/* CR 20th frame start address for output DMA */
#define EXYNOS_CIOCRSA20 (0x31c)
/* CR 21th frame start address for output DMA */
#define EXYNOS_CIOCRSA21 (0x320)
/* CR 22th frame start address for output DMA */
#define EXYNOS_CIOCRSA22 (0x324)
/* CR 23th frame start address for output DMA */
#define EXYNOS_CIOCRSA23 (0x328)
/* CR 24th frame start address for output DMA */
#define EXYNOS_CIOCRSA24 (0x32c)
/* CR 25th frame start address for output DMA */
#define EXYNOS_CIOCRSA25 (0x330)
/* CR 26th frame start address for output DMA */
#define EXYNOS_CIOCRSA26 (0x334)
/* CR 27th frame start address for output DMA */
#define EXYNOS_CIOCRSA27 (0x338)
/* CR 28th frame start address for output DMA */
#define EXYNOS_CIOCRSA28 (0x33c)
/* CR 29th frame start address for output DMA */
#define EXYNOS_CIOCRSA29 (0x340)
/* CR 30th frame start address for output DMA */
#define EXYNOS_CIOCRSA30 (0x344)
/* CR 31th frame start address for output DMA */
#define EXYNOS_CIOCRSA31 (0x348)
/* CR 32th frame start address for output DMA */
#define EXYNOS_CIOCRSA32 (0x34c)
/*
* Macro part
*/
/* frame start address 1 ~ 4, 5 ~ 32 */
/* Number of Default PingPong Memory */
#define DEF_PP 4
#define EXYNOS_CIOYSA(__x) \
(((__x) < DEF_PP) ? \
(EXYNOS_CIOYSA1 + (__x) * 4) : \
(EXYNOS_CIOYSA5 + ((__x) - DEF_PP) * 4))
#define EXYNOS_CIOCBSA(__x) \
(((__x) < DEF_PP) ? \
(EXYNOS_CIOCBSA1 + (__x) * 4) : \
(EXYNOS_CIOCBSA5 + ((__x) - DEF_PP) * 4))
#define EXYNOS_CIOCRSA(__x) \
(((__x) < DEF_PP) ? \
(EXYNOS_CIOCRSA1 + (__x) * 4) : \
(EXYNOS_CIOCRSA5 + ((__x) - DEF_PP) * 4))
/* Number of Default PingPong Memory */
#define DEF_IPP 1
#define EXYNOS_CIIYSA(__x) \
(((__x) < DEF_IPP) ? \
(EXYNOS_CIIYSA0) : (EXYNOS_CIIYSA1))
#define EXYNOS_CIICBSA(__x) \
(((__x) < DEF_IPP) ? \
(EXYNOS_CIICBSA0) : (EXYNOS_CIICBSA1))
#define EXYNOS_CIICRSA(__x) \
(((__x) < DEF_IPP) ? \
(EXYNOS_CIICRSA0) : (EXYNOS_CIICRSA1))
#define EXYNOS_CISRCFMT_SOURCEHSIZE(x) ((x) << 16)
#define EXYNOS_CISRCFMT_SOURCEVSIZE(x) ((x) << 0)
#define EXYNOS_CIWDOFST_WINHOROFST(x) ((x) << 16)
#define EXYNOS_CIWDOFST_WINVEROFST(x) ((x) << 0)
#define EXYNOS_CIWDOFST2_WINHOROFST2(x) ((x) << 16)
#define EXYNOS_CIWDOFST2_WINVEROFST2(x) ((x) << 0)
#define EXYNOS_CITRGFMT_TARGETHSIZE(x) (((x) & 0x1fff) << 16)
#define EXYNOS_CITRGFMT_TARGETVSIZE(x) (((x) & 0x1fff) << 0)
#define EXYNOS_CISCPRERATIO_SHFACTOR(x) ((x) << 28)
#define EXYNOS_CISCPRERATIO_PREHORRATIO(x) ((x) << 16)
#define EXYNOS_CISCPRERATIO_PREVERRATIO(x) ((x) << 0)
#define EXYNOS_CISCPREDST_PREDSTWIDTH(x) ((x) << 16)
#define EXYNOS_CISCPREDST_PREDSTHEIGHT(x) ((x) << 0)
#define EXYNOS_CISCCTRL_MAINHORRATIO(x) ((x) << 16)
#define EXYNOS_CISCCTRL_MAINVERRATIO(x) ((x) << 0)
#define EXYNOS_CITAREA_TARGET_AREA(x) ((x) << 0)
#define EXYNOS_CISTATUS_GET_FRAME_COUNT(x) (((x) >> 26) & 0x3)
#define EXYNOS_CISTATUS_GET_FRAME_END(x) (((x) >> 17) & 0x1)
#define EXYNOS_CISTATUS_GET_LAST_CAPTURE_END(x) (((x) >> 16) & 0x1)
#define EXYNOS_CISTATUS_GET_LCD_STATUS(x) (((x) >> 9) & 0x1)
#define EXYNOS_CISTATUS_GET_ENVID_STATUS(x) (((x) >> 8) & 0x1)
#define EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(x) (((x) >> 7) & 0x3f)
#define EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(x) ((x) & 0x3f)
#define EXYNOS_CIIMGEFF_FIN(x) ((x & 0x7) << 26)
#define EXYNOS_CIIMGEFF_PAT_CB(x) ((x) << 13)
#define EXYNOS_CIIMGEFF_PAT_CR(x) ((x) << 0)
#define EXYNOS_CIILINESKIP(x) (((x) & 0xf) << 24)
#define EXYNOS_CIREAL_ISIZE_HEIGHT(x) ((x) << 16)
#define EXYNOS_CIREAL_ISIZE_WIDTH(x) ((x) << 0)
#define EXYNOS_MSCTRL_SUCCESSIVE_COUNT(x) ((x) << 24)
#define EXYNOS_MSCTRL_GET_INDMA_STATUS(x) ((x) & 0x1)
#define EXYNOS_CIOYOFF_VERTICAL(x) ((x) << 16)
#define EXYNOS_CIOYOFF_HORIZONTAL(x) ((x) << 0)
#define EXYNOS_CIOCBOFF_VERTICAL(x) ((x) << 16)
#define EXYNOS_CIOCBOFF_HORIZONTAL(x) ((x) << 0)
#define EXYNOS_CIOCROFF_VERTICAL(x) ((x) << 16)
#define EXYNOS_CIOCROFF_HORIZONTAL(x) ((x) << 0)
#define EXYNOS_CIIYOFF_VERTICAL(x) ((x) << 16)
#define EXYNOS_CIIYOFF_HORIZONTAL(x) ((x) << 0)
#define EXYNOS_CIICBOFF_VERTICAL(x) ((x) << 16)
#define EXYNOS_CIICBOFF_HORIZONTAL(x) ((x) << 0)
#define EXYNOS_CIICROFF_VERTICAL(x) ((x) << 16)
#define EXYNOS_CIICROFF_HORIZONTAL(x) ((x) << 0)
#define EXYNOS_ORGISIZE_VERTICAL(x) ((x) << 16)
#define EXYNOS_ORGISIZE_HORIZONTAL(x) ((x) << 0)
#define EXYNOS_ORGOSIZE_VERTICAL(x) ((x) << 16)
#define EXYNOS_ORGOSIZE_HORIZONTAL(x) ((x) << 0)
#define EXYNOS_CIEXTEN_TARGETH_EXT(x) ((((x) & 0x2000) >> 13) << 26)
#define EXYNOS_CIEXTEN_TARGETV_EXT(x) ((((x) & 0x2000) >> 13) << 24)
#define EXYNOS_CIEXTEN_MAINHORRATIO_EXT(x) (((x) & 0x3F) << 10)
#define EXYNOS_CIEXTEN_MAINVERRATIO_EXT(x) ((x) & 0x3F)
/*
* Bit definition part
*/
/* Source format register */
#define EXYNOS_CISRCFMT_ITU601_8BIT (1 << 31)
#define EXYNOS_CISRCFMT_ITU656_8BIT (0 << 31)
#define EXYNOS_CISRCFMT_ITU601_16BIT (1 << 29)
#define EXYNOS_CISRCFMT_ORDER422_YCBYCR (0 << 14)
#define EXYNOS_CISRCFMT_ORDER422_YCRYCB (1 << 14)
#define EXYNOS_CISRCFMT_ORDER422_CBYCRY (2 << 14)
#define EXYNOS_CISRCFMT_ORDER422_CRYCBY (3 << 14)
/* ITU601 16bit only */
#define EXYNOS_CISRCFMT_ORDER422_Y4CBCRCBCR (0 << 14)
/* ITU601 16bit only */
#define EXYNOS_CISRCFMT_ORDER422_Y4CRCBCRCB (1 << 14)
/* Window offset register */
#define EXYNOS_CIWDOFST_WINOFSEN (1 << 31)
#define EXYNOS_CIWDOFST_CLROVFIY (1 << 30)
#define EXYNOS_CIWDOFST_CLROVRLB (1 << 29)
#define EXYNOS_CIWDOFST_WINHOROFST_MASK (0x7ff << 16)
#define EXYNOS_CIWDOFST_CLROVFICB (1 << 15)
#define EXYNOS_CIWDOFST_CLROVFICR (1 << 14)
#define EXYNOS_CIWDOFST_WINVEROFST_MASK (0xfff << 0)
/* Global control register */
#define EXYNOS_CIGCTRL_SWRST (1 << 31)
#define EXYNOS_CIGCTRL_CAMRST_A (1 << 30)
#define EXYNOS_CIGCTRL_SELCAM_ITU_B (0 << 29)
#define EXYNOS_CIGCTRL_SELCAM_ITU_A (1 << 29)
#define EXYNOS_CIGCTRL_SELCAM_ITU_MASK (1 << 29)
#define EXYNOS_CIGCTRL_TESTPATTERN_NORMAL (0 << 27)
#define EXYNOS_CIGCTRL_TESTPATTERN_COLOR_BAR (1 << 27)
#define EXYNOS_CIGCTRL_TESTPATTERN_HOR_INC (2 << 27)
#define EXYNOS_CIGCTRL_TESTPATTERN_VER_INC (3 << 27)
#define EXYNOS_CIGCTRL_TESTPATTERN_MASK (3 << 27)
#define EXYNOS_CIGCTRL_TESTPATTERN_SHIFT (27)
#define EXYNOS_CIGCTRL_INVPOLPCLK (1 << 26)
#define EXYNOS_CIGCTRL_INVPOLVSYNC (1 << 25)
#define EXYNOS_CIGCTRL_INVPOLHREF (1 << 24)
#define EXYNOS_CIGCTRL_IRQ_OVFEN (1 << 22)
#define EXYNOS_CIGCTRL_HREF_MASK (1 << 21)
#define EXYNOS_CIGCTRL_IRQ_EDGE (0 << 20)
#define EXYNOS_CIGCTRL_IRQ_LEVEL (1 << 20)
#define EXYNOS_CIGCTRL_IRQ_CLR (1 << 19)
#define EXYNOS_CIGCTRL_IRQ_END_DISABLE (1 << 18)
#define EXYNOS_CIGCTRL_IRQ_DISABLE (0 << 16)
#define EXYNOS_CIGCTRL_IRQ_ENABLE (1 << 16)
#define EXYNOS_CIGCTRL_SHADOW_DISABLE (1 << 12)
#define EXYNOS_CIGCTRL_CAM_JPEG (1 << 8)
#define EXYNOS_CIGCTRL_SELCAM_MIPI_B (0 << 7)
#define EXYNOS_CIGCTRL_SELCAM_MIPI_A (1 << 7)
#define EXYNOS_CIGCTRL_SELCAM_MIPI_MASK (1 << 7)
#define EXYNOS_CIGCTRL_SELWB_CAMIF_CAMERA (0 << 6)
#define EXYNOS_CIGCTRL_SELWB_CAMIF_WRITEBACK (1 << 6)
#define EXYNOS_CIGCTRL_SELWRITEBACK_MASK (1 << 10)
#define EXYNOS_CIGCTRL_SELWRITEBACK_A (1 << 10)
#define EXYNOS_CIGCTRL_SELWRITEBACK_B (0 << 10)
#define EXYNOS_CIGCTRL_SELWB_CAMIF_MASK (1 << 6)
#define EXYNOS_CIGCTRL_CSC_ITU601 (0 << 5)
#define EXYNOS_CIGCTRL_CSC_ITU709 (1 << 5)
#define EXYNOS_CIGCTRL_CSC_MASK (1 << 5)
#define EXYNOS_CIGCTRL_INVPOLHSYNC (1 << 4)
#define EXYNOS_CIGCTRL_SELCAM_FIMC_ITU (0 << 3)
#define EXYNOS_CIGCTRL_SELCAM_FIMC_MIPI (1 << 3)
#define EXYNOS_CIGCTRL_SELCAM_FIMC_MASK (1 << 3)
#define EXYNOS_CIGCTRL_PROGRESSIVE (0 << 0)
#define EXYNOS_CIGCTRL_INTERLACE (1 << 0)
/* Window offset2 register */
#define EXYNOS_CIWDOFST_WINHOROFST2_MASK (0xfff << 16)
#define EXYNOS_CIWDOFST_WINVEROFST2_MASK (0xfff << 16)
/* Target format register */
#define EXYNOS_CITRGFMT_INROT90_CLOCKWISE (1 << 31)
#define EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420 (0 << 29)
#define EXYNOS_CITRGFMT_OUTFORMAT_YCBCR422 (1 << 29)
#define EXYNOS_CITRGFMT_OUTFORMAT_YCBCR422_1PLANE (2 << 29)
#define EXYNOS_CITRGFMT_OUTFORMAT_RGB (3 << 29)
#define EXYNOS_CITRGFMT_OUTFORMAT_MASK (3 << 29)
#define EXYNOS_CITRGFMT_FLIP_SHIFT (14)
#define EXYNOS_CITRGFMT_FLIP_NORMAL (0 << 14)
#define EXYNOS_CITRGFMT_FLIP_X_MIRROR (1 << 14)
#define EXYNOS_CITRGFMT_FLIP_Y_MIRROR (2 << 14)
#define EXYNOS_CITRGFMT_FLIP_180 (3 << 14)
#define EXYNOS_CITRGFMT_FLIP_MASK (3 << 14)
#define EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE (1 << 13)
#define EXYNOS_CITRGFMT_TARGETV_MASK (0x1fff << 0)
#define EXYNOS_CITRGFMT_TARGETH_MASK (0x1fff << 16)
/* Output DMA control register */
#define EXYNOS_CIOCTRL_WEAVE_OUT (1 << 31)
#define EXYNOS_CIOCTRL_WEAVE_MASK (1 << 31)
#define EXYNOS_CIOCTRL_LASTENDEN (1 << 30)
#define EXYNOS_CIOCTRL_ORDER2P_LSB_CBCR (0 << 24)
#define EXYNOS_CIOCTRL_ORDER2P_LSB_CRCB (1 << 24)
#define EXYNOS_CIOCTRL_ORDER2P_MSB_CRCB (2 << 24)
#define EXYNOS_CIOCTRL_ORDER2P_MSB_CBCR (3 << 24)
#define EXYNOS_CIOCTRL_ORDER2P_SHIFT (24)
#define EXYNOS_CIOCTRL_ORDER2P_MASK (3 << 24)
#define EXYNOS_CIOCTRL_YCBCR_3PLANE (0 << 3)
#define EXYNOS_CIOCTRL_YCBCR_2PLANE (1 << 3)
#define EXYNOS_CIOCTRL_YCBCR_PLANE_MASK (1 << 3)
#define EXYNOS_CIOCTRL_LASTIRQ_ENABLE (1 << 2)
#define EXYNOS_CIOCTRL_ALPHA_OUT (0xff << 4)
#define EXYNOS_CIOCTRL_ORDER422_YCBYCR (0 << 0)
#define EXYNOS_CIOCTRL_ORDER422_YCRYCB (1 << 0)
#define EXYNOS_CIOCTRL_ORDER422_CBYCRY (2 << 0)
#define EXYNOS_CIOCTRL_ORDER422_CRYCBY (3 << 0)
#define EXYNOS_CIOCTRL_ORDER422_MASK (3 << 0)
/* Main scaler control register */
#define EXYNOS_CISCCTRL_SCALERBYPASS (1 << 31)
#define EXYNOS_CISCCTRL_SCALEUP_H (1 << 30)
#define EXYNOS_CISCCTRL_SCALEUP_V (1 << 29)
#define EXYNOS_CISCCTRL_CSCR2Y_NARROW (0 << 28)
#define EXYNOS_CISCCTRL_CSCR2Y_WIDE (1 << 28)
#define EXYNOS_CISCCTRL_CSCY2R_NARROW (0 << 27)
#define EXYNOS_CISCCTRL_CSCY2R_WIDE (1 << 27)
#define EXYNOS_CISCCTRL_LCDPATHEN_FIFO (1 << 26)
#define EXYNOS_CISCCTRL_PROGRESSIVE (0 << 25)
#define EXYNOS_CISCCTRL_INTERLACE (1 << 25)
#define EXYNOS_CISCCTRL_SCAN_MASK (1 << 25)
#define EXYNOS_CISCCTRL_SCALERSTART (1 << 15)
#define EXYNOS_CISCCTRL_INRGB_FMT_RGB565 (0 << 13)
#define EXYNOS_CISCCTRL_INRGB_FMT_RGB666 (1 << 13)
#define EXYNOS_CISCCTRL_INRGB_FMT_RGB888 (2 << 13)
#define EXYNOS_CISCCTRL_INRGB_FMT_RGB_MASK (3 << 13)
#define EXYNOS_CISCCTRL_OUTRGB_FMT_RGB565 (0 << 11)
#define EXYNOS_CISCCTRL_OUTRGB_FMT_RGB666 (1 << 11)
#define EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888 (2 << 11)
#define EXYNOS_CISCCTRL_OUTRGB_FMT_RGB_MASK (3 << 11)
#define EXYNOS_CISCCTRL_EXTRGB_NORMAL (0 << 10)
#define EXYNOS_CISCCTRL_EXTRGB_EXTENSION (1 << 10)
#define EXYNOS_CISCCTRL_ONE2ONE (1 << 9)
#define EXYNOS_CISCCTRL_MAIN_V_RATIO_MASK (0x1ff << 0)
#define EXYNOS_CISCCTRL_MAIN_H_RATIO_MASK (0x1ff << 16)
/* Status register */
#define EXYNOS_CISTATUS_OVFIY (1 << 31)
#define EXYNOS_CISTATUS_OVFICB (1 << 30)
#define EXYNOS_CISTATUS_OVFICR (1 << 29)
#define EXYNOS_CISTATUS_VSYNC (1 << 28)
#define EXYNOS_CISTATUS_SCALERSTART (1 << 26)
#define EXYNOS_CISTATUS_WINOFSTEN (1 << 25)
#define EXYNOS_CISTATUS_IMGCPTEN (1 << 22)
#define EXYNOS_CISTATUS_IMGCPTENSC (1 << 21)
#define EXYNOS_CISTATUS_VSYNC_A (1 << 20)
#define EXYNOS_CISTATUS_VSYNC_B (1 << 19)
#define EXYNOS_CISTATUS_OVRLB (1 << 18)
#define EXYNOS_CISTATUS_FRAMEEND (1 << 17)
#define EXYNOS_CISTATUS_LASTCAPTUREEND (1 << 16)
#define EXYNOS_CISTATUS_VVALID_A (1 << 15)
#define EXYNOS_CISTATUS_VVALID_B (1 << 14)
/* Image capture enable register */
#define EXYNOS_CIIMGCPT_IMGCPTEN (1 << 31)
#define EXYNOS_CIIMGCPT_IMGCPTEN_SC (1 << 30)
#define EXYNOS_CIIMGCPT_CPT_FREN_ENABLE (1 << 25)
#define EXYNOS_CIIMGCPT_CPT_FRMOD_EN (0 << 18)
#define EXYNOS_CIIMGCPT_CPT_FRMOD_CNT (1 << 18)
/* Image effects register */
#define EXYNOS_CIIMGEFF_IE_DISABLE (0 << 30)
#define EXYNOS_CIIMGEFF_IE_ENABLE (1 << 30)
#define EXYNOS_CIIMGEFF_IE_SC_BEFORE (0 << 29)
#define EXYNOS_CIIMGEFF_IE_SC_AFTER (1 << 29)
#define EXYNOS_CIIMGEFF_FIN_BYPASS (0 << 26)
#define EXYNOS_CIIMGEFF_FIN_ARBITRARY (1 << 26)
#define EXYNOS_CIIMGEFF_FIN_NEGATIVE (2 << 26)
#define EXYNOS_CIIMGEFF_FIN_ARTFREEZE (3 << 26)
#define EXYNOS_CIIMGEFF_FIN_EMBOSSING (4 << 26)
#define EXYNOS_CIIMGEFF_FIN_SILHOUETTE (5 << 26)
#define EXYNOS_CIIMGEFF_FIN_MASK (7 << 26)
#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK ((0xff < 13) | (0xff < 0))
/* Real input DMA size register */
#define EXYNOS_CIREAL_ISIZE_AUTOLOAD_ENABLE (1 << 31)
#define EXYNOS_CIREAL_ISIZE_ADDR_CH_DISABLE (1 << 30)
#define EXYNOS_CIREAL_ISIZE_HEIGHT_MASK (0x3FFF << 16)
#define EXYNOS_CIREAL_ISIZE_WIDTH_MASK (0x3FFF << 0)
/* Input DMA control register */
#define EXYNOS_MSCTRL_FIELD_MASK (1 << 31)
#define EXYNOS_MSCTRL_FIELD_WEAVE (1 << 31)
#define EXYNOS_MSCTRL_FIELD_NORMAL (0 << 31)
#define EXYNOS_MSCTRL_BURST_CNT (24)
#define EXYNOS_MSCTRL_BURST_CNT_MASK (0xf << 24)
#define EXYNOS_MSCTRL_ORDER2P_LSB_CBCR (0 << 16)
#define EXYNOS_MSCTRL_ORDER2P_LSB_CRCB (1 << 16)
#define EXYNOS_MSCTRL_ORDER2P_MSB_CRCB (2 << 16)
#define EXYNOS_MSCTRL_ORDER2P_MSB_CBCR (3 << 16)
#define EXYNOS_MSCTRL_ORDER2P_SHIFT (16)
#define EXYNOS_MSCTRL_ORDER2P_SHIFT_MASK (0x3 << 16)
#define EXYNOS_MSCTRL_C_INT_IN_3PLANE (0 << 15)
#define EXYNOS_MSCTRL_C_INT_IN_2PLANE (1 << 15)
#define EXYNOS_MSCTRL_FLIP_SHIFT (13)
#define EXYNOS_MSCTRL_FLIP_NORMAL (0 << 13)
#define EXYNOS_MSCTRL_FLIP_X_MIRROR (1 << 13)
#define EXYNOS_MSCTRL_FLIP_Y_MIRROR (2 << 13)
#define EXYNOS_MSCTRL_FLIP_180 (3 << 13)
#define EXYNOS_MSCTRL_FLIP_MASK (3 << 13)
#define EXYNOS_MSCTRL_ORDER422_CRYCBY (0 << 4)
#define EXYNOS_MSCTRL_ORDER422_YCRYCB (1 << 4)
#define EXYNOS_MSCTRL_ORDER422_CBYCRY (2 << 4)
#define EXYNOS_MSCTRL_ORDER422_YCBYCR (3 << 4)
#define EXYNOS_MSCTRL_INPUT_EXTCAM (0 << 3)
#define EXYNOS_MSCTRL_INPUT_MEMORY (1 << 3)
#define EXYNOS_MSCTRL_INPUT_MASK (1 << 3)
#define EXYNOS_MSCTRL_INFORMAT_YCBCR420 (0 << 1)
#define EXYNOS_MSCTRL_INFORMAT_YCBCR422 (1 << 1)
#define EXYNOS_MSCTRL_INFORMAT_YCBCR422_1PLANE (2 << 1)
#define EXYNOS_MSCTRL_INFORMAT_RGB (3 << 1)
#define EXYNOS_MSCTRL_ENVID (1 << 0)
/* DMA parameter register */
#define EXYNOS_CIDMAPARAM_R_MODE_LINEAR (0 << 29)
#define EXYNOS_CIDMAPARAM_R_MODE_CONFTILE (1 << 29)
#define EXYNOS_CIDMAPARAM_R_MODE_16X16 (2 << 29)
#define EXYNOS_CIDMAPARAM_R_MODE_64X32 (3 << 29)
#define EXYNOS_CIDMAPARAM_R_MODE_MASK (3 << 29)
#define EXYNOS_CIDMAPARAM_R_TILE_HSIZE_64 (0 << 24)
#define EXYNOS_CIDMAPARAM_R_TILE_HSIZE_128 (1 << 24)
#define EXYNOS_CIDMAPARAM_R_TILE_HSIZE_256 (2 << 24)
#define EXYNOS_CIDMAPARAM_R_TILE_HSIZE_512 (3 << 24)
#define EXYNOS_CIDMAPARAM_R_TILE_HSIZE_1024 (4 << 24)
#define EXYNOS_CIDMAPARAM_R_TILE_HSIZE_2048 (5 << 24)
#define EXYNOS_CIDMAPARAM_R_TILE_HSIZE_4096 (6 << 24)
#define EXYNOS_CIDMAPARAM_R_TILE_VSIZE_1 (0 << 20)
#define EXYNOS_CIDMAPARAM_R_TILE_VSIZE_2 (1 << 20)
#define EXYNOS_CIDMAPARAM_R_TILE_VSIZE_4 (2 << 20)
#define EXYNOS_CIDMAPARAM_R_TILE_VSIZE_8 (3 << 20)
#define EXYNOS_CIDMAPARAM_R_TILE_VSIZE_16 (4 << 20)
#define EXYNOS_CIDMAPARAM_R_TILE_VSIZE_32 (5 << 20)
#define EXYNOS_CIDMAPARAM_W_MODE_LINEAR (0 << 13)
#define EXYNOS_CIDMAPARAM_W_MODE_CONFTILE (1 << 13)
#define EXYNOS_CIDMAPARAM_W_MODE_16X16 (2 << 13)
#define EXYNOS_CIDMAPARAM_W_MODE_64X32 (3 << 13)
#define EXYNOS_CIDMAPARAM_W_MODE_MASK (3 << 13)
#define EXYNOS_CIDMAPARAM_W_TILE_HSIZE_64 (0 << 8)
#define EXYNOS_CIDMAPARAM_W_TILE_HSIZE_128 (1 << 8)
#define EXYNOS_CIDMAPARAM_W_TILE_HSIZE_256 (2 << 8)
#define EXYNOS_CIDMAPARAM_W_TILE_HSIZE_512 (3 << 8)
#define EXYNOS_CIDMAPARAM_W_TILE_HSIZE_1024 (4 << 8)
#define EXYNOS_CIDMAPARAM_W_TILE_HSIZE_2048 (5 << 8)
#define EXYNOS_CIDMAPARAM_W_TILE_HSIZE_4096 (6 << 8)
#define EXYNOS_CIDMAPARAM_W_TILE_VSIZE_1 (0 << 4)
#define EXYNOS_CIDMAPARAM_W_TILE_VSIZE_2 (1 << 4)
#define EXYNOS_CIDMAPARAM_W_TILE_VSIZE_4 (2 << 4)
#define EXYNOS_CIDMAPARAM_W_TILE_VSIZE_8 (3 << 4)
#define EXYNOS_CIDMAPARAM_W_TILE_VSIZE_16 (4 << 4)
#define EXYNOS_CIDMAPARAM_W_TILE_VSIZE_32 (5 << 4)
/* Gathering Extension register */
#define EXYNOS_CIEXTEN_TARGETH_EXT_MASK (1 << 26)
#define EXYNOS_CIEXTEN_TARGETV_EXT_MASK (1 << 24)
#define EXYNOS_CIEXTEN_MAINHORRATIO_EXT_MASK (0x3F << 10)
#define EXYNOS_CIEXTEN_MAINVERRATIO_EXT_MASK (0x3F)
#define EXYNOS_CIEXTEN_YUV444_OUT (1 << 22)
/* FIMC Clock Source Select register */
#define EXYNOS_CLKSRC_HCLK (0 << 1)
#define EXYNOS_CLKSRC_HCLK_MASK (1 << 1)
#define EXYNOS_CLKSRC_SCLK (1 << 1)
/* SYSREG for FIMC writeback */
#define SYSREG_CAMERA_BLK (0x0218)
#define SYSREG_FIMD0WB_DEST_MASK (0x3 << 23)
#define SYSREG_FIMD0WB_DEST_SHIFT 23
#endif /* EXYNOS_REGS_FIMC_H */

View file

@ -0,0 +1,284 @@
/* linux/drivers/gpu/drm/exynos/regs-gsc.h
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Register definition file for Samsung G-Scaler driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef EXYNOS_REGS_GSC_H_
#define EXYNOS_REGS_GSC_H_
/* G-Scaler enable */
#define GSC_ENABLE 0x00
#define GSC_ENABLE_PP_UPDATE_TIME_MASK (1 << 9)
#define GSC_ENABLE_PP_UPDATE_TIME_CURR (0 << 9)
#define GSC_ENABLE_PP_UPDATE_TIME_EOPAS (1 << 9)
#define GSC_ENABLE_CLK_GATE_MODE_MASK (1 << 8)
#define GSC_ENABLE_CLK_GATE_MODE_FREE (1 << 8)
#define GSC_ENABLE_IPC_MODE_MASK (1 << 7)
#define GSC_ENABLE_NORM_MODE (0 << 7)
#define GSC_ENABLE_IPC_MODE (1 << 7)
#define GSC_ENABLE_PP_UPDATE_MODE_MASK (1 << 6)
#define GSC_ENABLE_PP_UPDATE_FIRE_MODE (1 << 6)
#define GSC_ENABLE_IN_PP_UPDATE (1 << 5)
#define GSC_ENABLE_ON_CLEAR_MASK (1 << 4)
#define GSC_ENABLE_ON_CLEAR_ONESHOT (1 << 4)
#define GSC_ENABLE_QOS_ENABLE (1 << 3)
#define GSC_ENABLE_OP_STATUS (1 << 2)
#define GSC_ENABLE_SFR_UPDATE (1 << 1)
#define GSC_ENABLE_ON (1 << 0)
/* G-Scaler S/W reset */
#define GSC_SW_RESET 0x04
#define GSC_SW_RESET_SRESET (1 << 0)
/* G-Scaler IRQ */
#define GSC_IRQ 0x08
#define GSC_IRQ_STATUS_OR_IRQ (1 << 17)
#define GSC_IRQ_STATUS_OR_FRM_DONE (1 << 16)
#define GSC_IRQ_OR_MASK (1 << 2)
#define GSC_IRQ_FRMDONE_MASK (1 << 1)
#define GSC_IRQ_ENABLE (1 << 0)
/* G-Scaler input control */
#define GSC_IN_CON 0x10
#define GSC_IN_CHROM_STRIDE_SEL_MASK (1 << 20)
#define GSC_IN_CHROM_STRIDE_SEPAR (1 << 20)
#define GSC_IN_RB_SWAP_MASK (1 << 19)
#define GSC_IN_RB_SWAP (1 << 19)
#define GSC_IN_ROT_MASK (7 << 16)
#define GSC_IN_ROT_270 (7 << 16)
#define GSC_IN_ROT_90_YFLIP (6 << 16)
#define GSC_IN_ROT_90_XFLIP (5 << 16)
#define GSC_IN_ROT_90 (4 << 16)
#define GSC_IN_ROT_180 (3 << 16)
#define GSC_IN_ROT_YFLIP (2 << 16)
#define GSC_IN_ROT_XFLIP (1 << 16)
#define GSC_IN_RGB_TYPE_MASK (3 << 14)
#define GSC_IN_RGB_HD_WIDE (3 << 14)
#define GSC_IN_RGB_HD_NARROW (2 << 14)
#define GSC_IN_RGB_SD_WIDE (1 << 14)
#define GSC_IN_RGB_SD_NARROW (0 << 14)
#define GSC_IN_YUV422_1P_ORDER_MASK (1 << 13)
#define GSC_IN_YUV422_1P_ORDER_LSB_Y (0 << 13)
#define GSC_IN_YUV422_1P_OEDER_LSB_C (1 << 13)
#define GSC_IN_CHROMA_ORDER_MASK (1 << 12)
#define GSC_IN_CHROMA_ORDER_CBCR (0 << 12)
#define GSC_IN_CHROMA_ORDER_CRCB (1 << 12)
#define GSC_IN_FORMAT_MASK (7 << 8)
#define GSC_IN_XRGB8888 (0 << 8)
#define GSC_IN_RGB565 (1 << 8)
#define GSC_IN_YUV420_2P (2 << 8)
#define GSC_IN_YUV420_3P (3 << 8)
#define GSC_IN_YUV422_1P (4 << 8)
#define GSC_IN_YUV422_2P (5 << 8)
#define GSC_IN_YUV422_3P (6 << 8)
#define GSC_IN_TILE_TYPE_MASK (1 << 4)
#define GSC_IN_TILE_C_16x8 (0 << 4)
#define GSC_IN_TILE_C_16x16 (1 << 4)
#define GSC_IN_TILE_MODE (1 << 3)
#define GSC_IN_LOCAL_SEL_MASK (3 << 1)
#define GSC_IN_LOCAL_CAM3 (3 << 1)
#define GSC_IN_LOCAL_FIMD_WB (2 << 1)
#define GSC_IN_LOCAL_CAM1 (1 << 1)
#define GSC_IN_LOCAL_CAM0 (0 << 1)
#define GSC_IN_PATH_MASK (1 << 0)
#define GSC_IN_PATH_LOCAL (1 << 0)
#define GSC_IN_PATH_MEMORY (0 << 0)
/* G-Scaler source image size */
#define GSC_SRCIMG_SIZE 0x14
#define GSC_SRCIMG_HEIGHT_MASK (0x1fff << 16)
#define GSC_SRCIMG_HEIGHT(x) ((x) << 16)
#define GSC_SRCIMG_WIDTH_MASK (0x3fff << 0)
#define GSC_SRCIMG_WIDTH(x) ((x) << 0)
/* G-Scaler source image offset */
#define GSC_SRCIMG_OFFSET 0x18
#define GSC_SRCIMG_OFFSET_Y_MASK (0x1fff << 16)
#define GSC_SRCIMG_OFFSET_Y(x) ((x) << 16)
#define GSC_SRCIMG_OFFSET_X_MASK (0x1fff << 0)
#define GSC_SRCIMG_OFFSET_X(x) ((x) << 0)
/* G-Scaler cropped source image size */
#define GSC_CROPPED_SIZE 0x1C
#define GSC_CROPPED_HEIGHT_MASK (0x1fff << 16)
#define GSC_CROPPED_HEIGHT(x) ((x) << 16)
#define GSC_CROPPED_WIDTH_MASK (0x1fff << 0)
#define GSC_CROPPED_WIDTH(x) ((x) << 0)
/* G-Scaler output control */
#define GSC_OUT_CON 0x20
#define GSC_OUT_GLOBAL_ALPHA_MASK (0xff << 24)
#define GSC_OUT_GLOBAL_ALPHA(x) ((x) << 24)
#define GSC_OUT_CHROM_STRIDE_SEL_MASK (1 << 13)
#define GSC_OUT_CHROM_STRIDE_SEPAR (1 << 13)
#define GSC_OUT_RB_SWAP_MASK (1 << 12)
#define GSC_OUT_RB_SWAP (1 << 12)
#define GSC_OUT_RGB_TYPE_MASK (3 << 10)
#define GSC_OUT_RGB_HD_NARROW (3 << 10)
#define GSC_OUT_RGB_HD_WIDE (2 << 10)
#define GSC_OUT_RGB_SD_NARROW (1 << 10)
#define GSC_OUT_RGB_SD_WIDE (0 << 10)
#define GSC_OUT_YUV422_1P_ORDER_MASK (1 << 9)
#define GSC_OUT_YUV422_1P_ORDER_LSB_Y (0 << 9)
#define GSC_OUT_YUV422_1P_OEDER_LSB_C (1 << 9)
#define GSC_OUT_CHROMA_ORDER_MASK (1 << 8)
#define GSC_OUT_CHROMA_ORDER_CBCR (0 << 8)
#define GSC_OUT_CHROMA_ORDER_CRCB (1 << 8)
#define GSC_OUT_FORMAT_MASK (7 << 4)
#define GSC_OUT_XRGB8888 (0 << 4)
#define GSC_OUT_RGB565 (1 << 4)
#define GSC_OUT_YUV420_2P (2 << 4)
#define GSC_OUT_YUV420_3P (3 << 4)
#define GSC_OUT_YUV422_1P (4 << 4)
#define GSC_OUT_YUV422_2P (5 << 4)
#define GSC_OUT_YUV444 (7 << 4)
#define GSC_OUT_TILE_TYPE_MASK (1 << 2)
#define GSC_OUT_TILE_C_16x8 (0 << 2)
#define GSC_OUT_TILE_C_16x16 (1 << 2)
#define GSC_OUT_TILE_MODE (1 << 1)
#define GSC_OUT_PATH_MASK (1 << 0)
#define GSC_OUT_PATH_LOCAL (1 << 0)
#define GSC_OUT_PATH_MEMORY (0 << 0)
/* G-Scaler scaled destination image size */
#define GSC_SCALED_SIZE 0x24
#define GSC_SCALED_HEIGHT_MASK (0x1fff << 16)
#define GSC_SCALED_HEIGHT(x) ((x) << 16)
#define GSC_SCALED_WIDTH_MASK (0x1fff << 0)
#define GSC_SCALED_WIDTH(x) ((x) << 0)
/* G-Scaler pre scale ratio */
#define GSC_PRE_SCALE_RATIO 0x28
#define GSC_PRESC_SHFACTOR_MASK (7 << 28)
#define GSC_PRESC_SHFACTOR(x) ((x) << 28)
#define GSC_PRESC_V_RATIO_MASK (7 << 16)
#define GSC_PRESC_V_RATIO(x) ((x) << 16)
#define GSC_PRESC_H_RATIO_MASK (7 << 0)
#define GSC_PRESC_H_RATIO(x) ((x) << 0)
/* G-Scaler main scale horizontal ratio */
#define GSC_MAIN_H_RATIO 0x2C
#define GSC_MAIN_H_RATIO_MASK (0xfffff << 0)
#define GSC_MAIN_H_RATIO_VALUE(x) ((x) << 0)
/* G-Scaler main scale vertical ratio */
#define GSC_MAIN_V_RATIO 0x30
#define GSC_MAIN_V_RATIO_MASK (0xfffff << 0)
#define GSC_MAIN_V_RATIO_VALUE(x) ((x) << 0)
/* G-Scaler input chrominance stride */
#define GSC_IN_CHROM_STRIDE 0x3C
#define GSC_IN_CHROM_STRIDE_MASK (0x3fff << 0)
#define GSC_IN_CHROM_STRIDE_VALUE(x) ((x) << 0)
/* G-Scaler destination image size */
#define GSC_DSTIMG_SIZE 0x40
#define GSC_DSTIMG_HEIGHT_MASK (0x1fff << 16)
#define GSC_DSTIMG_HEIGHT(x) ((x) << 16)
#define GSC_DSTIMG_WIDTH_MASK (0x1fff << 0)
#define GSC_DSTIMG_WIDTH(x) ((x) << 0)
/* G-Scaler destination image offset */
#define GSC_DSTIMG_OFFSET 0x44
#define GSC_DSTIMG_OFFSET_Y_MASK (0x1fff << 16)
#define GSC_DSTIMG_OFFSET_Y(x) ((x) << 16)
#define GSC_DSTIMG_OFFSET_X_MASK (0x1fff << 0)
#define GSC_DSTIMG_OFFSET_X(x) ((x) << 0)
/* G-Scaler output chrominance stride */
#define GSC_OUT_CHROM_STRIDE 0x48
#define GSC_OUT_CHROM_STRIDE_MASK (0x3fff << 0)
#define GSC_OUT_CHROM_STRIDE_VALUE(x) ((x) << 0)
/* G-Scaler input y address mask */
#define GSC_IN_BASE_ADDR_Y_MASK 0x4C
/* G-Scaler input y base address */
#define GSC_IN_BASE_ADDR_Y(n) (0x50 + (n) * 0x4)
/* G-Scaler input y base current address */
#define GSC_IN_BASE_ADDR_Y_CUR(n) (0x60 + (n) * 0x4)
/* G-Scaler input cb address mask */
#define GSC_IN_BASE_ADDR_CB_MASK 0x7C
/* G-Scaler input cb base address */
#define GSC_IN_BASE_ADDR_CB(n) (0x80 + (n) * 0x4)
/* G-Scaler input cb base current address */
#define GSC_IN_BASE_ADDR_CB_CUR(n) (0x90 + (n) * 0x4)
/* G-Scaler input cr address mask */
#define GSC_IN_BASE_ADDR_CR_MASK 0xAC
/* G-Scaler input cr base address */
#define GSC_IN_BASE_ADDR_CR(n) (0xB0 + (n) * 0x4)
/* G-Scaler input cr base current address */
#define GSC_IN_BASE_ADDR_CR_CUR(n) (0xC0 + (n) * 0x4)
/* G-Scaler input address mask */
#define GSC_IN_CURR_ADDR_INDEX (0xf << 24)
#define GSC_IN_CURR_GET_INDEX(x) ((x) >> 24)
#define GSC_IN_BASE_ADDR_PINGPONG(x) ((x) << 16)
#define GSC_IN_BASE_ADDR_MASK (0xff << 0)
/* G-Scaler output y address mask */
#define GSC_OUT_BASE_ADDR_Y_MASK 0x10C
/* G-Scaler output y base address */
#define GSC_OUT_BASE_ADDR_Y(n) (0x110 + (n) * 0x4)
/* G-Scaler output cb address mask */
#define GSC_OUT_BASE_ADDR_CB_MASK 0x15C
/* G-Scaler output cb base address */
#define GSC_OUT_BASE_ADDR_CB(n) (0x160 + (n) * 0x4)
/* G-Scaler output cr address mask */
#define GSC_OUT_BASE_ADDR_CR_MASK 0x1AC
/* G-Scaler output cr base address */
#define GSC_OUT_BASE_ADDR_CR(n) (0x1B0 + (n) * 0x4)
/* G-Scaler output address mask */
#define GSC_OUT_CURR_ADDR_INDEX (0xf << 24)
#define GSC_OUT_CURR_GET_INDEX(x) ((x) >> 24)
#define GSC_OUT_BASE_ADDR_PINGPONG(x) ((x) << 16)
#define GSC_OUT_BASE_ADDR_MASK (0xffff << 0)
/* G-Scaler horizontal scaling filter */
#define GSC_HCOEF(n, s, x) (0x300 + (n) * 0x4 + (s) * 0x30 + (x) * 0x300)
/* G-Scaler vertical scaling filter */
#define GSC_VCOEF(n, s, x) (0x200 + (n) * 0x4 + (s) * 0x30 + (x) * 0x300)
/* G-Scaler BUS control */
#define GSC_BUSCON 0xA78
#define GSC_BUSCON_INT_TIME_MASK (1 << 8)
#define GSC_BUSCON_INT_DATA_TRANS (0 << 8)
#define GSC_BUSCON_INT_AXI_RESPONSE (1 << 8)
#define GSC_BUSCON_AWCACHE(x) ((x) << 4)
#define GSC_BUSCON_ARCACHE(x) ((x) << 0)
/* G-Scaler V position */
#define GSC_VPOSITION 0xA7C
#define GSC_VPOS_F(x) ((x) << 0)
/* G-Scaler clock initial count */
#define GSC_CLK_INIT_COUNT 0xC00
#define GSC_CLK_GATE_MODE_INIT_CNT(x) ((x) << 0)
/* G-Scaler clock snoop count */
#define GSC_CLK_SNOOP_COUNT 0xC04
#define GSC_CLK_GATE_MODE_SNOOP_CNT(x) ((x) << 0)
/* SYSCON. GSCBLK_CFG */
#define SYSREG_GSCBLK_CFG1 (S3C_VA_SYS + 0x0224)
#define GSC_BLK_DISP1WB_DEST(x) (x << 10)
#define GSC_BLK_SW_RESET_WB_DEST(x) (1 << (18 + x))
#define GSC_BLK_PXLASYNC_LO_MASK_WB(x) (0 << (14 + x))
#define GSC_BLK_GSCL_WB_IN_SRC_SEL(x) (1 << (2 * x))
#define SYSREG_GSCBLK_CFG2 (S3C_VA_SYS + 0x2000)
#define PXLASYNC_LO_MASK_CAMIF_GSCL(x) (1 << (x))
#endif /* EXYNOS_REGS_GSC_H_ */

View file

@ -0,0 +1,597 @@
/*
*
* Cloned from drivers/media/video/s5p-tv/regs-hdmi.h
*
* Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* HDMI register header file for Samsung TVOUT 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_REGS_HDMI_H
#define SAMSUNG_REGS_HDMI_H
/*
* Register part
*/
/* HDMI Version 1.3 & Common */
#define HDMI_CTRL_BASE(x) ((x) + 0x00000000)
#define HDMI_CORE_BASE(x) ((x) + 0x00010000)
#define HDMI_I2S_BASE(x) ((x) + 0x00040000)
#define HDMI_TG_BASE(x) ((x) + 0x00050000)
/* Control registers */
#define HDMI_INTC_CON HDMI_CTRL_BASE(0x0000)
#define HDMI_INTC_FLAG HDMI_CTRL_BASE(0x0004)
#define HDMI_HPD_STATUS HDMI_CTRL_BASE(0x000C)
#define HDMI_V13_PHY_RSTOUT HDMI_CTRL_BASE(0x0014)
#define HDMI_V13_PHY_VPLL HDMI_CTRL_BASE(0x0018)
#define HDMI_V13_PHY_CMU HDMI_CTRL_BASE(0x001C)
#define HDMI_V13_CORE_RSTOUT HDMI_CTRL_BASE(0x0020)
/* Core registers */
#define HDMI_CON_0 HDMI_CORE_BASE(0x0000)
#define HDMI_CON_1 HDMI_CORE_BASE(0x0004)
#define HDMI_CON_2 HDMI_CORE_BASE(0x0008)
#define HDMI_SYS_STATUS HDMI_CORE_BASE(0x0010)
#define HDMI_V13_PHY_STATUS HDMI_CORE_BASE(0x0014)
#define HDMI_STATUS_EN HDMI_CORE_BASE(0x0020)
#define HDMI_HPD HDMI_CORE_BASE(0x0030)
#define HDMI_MODE_SEL HDMI_CORE_BASE(0x0040)
#define HDMI_ENC_EN HDMI_CORE_BASE(0x0044)
#define HDMI_V13_BLUE_SCREEN_0 HDMI_CORE_BASE(0x0050)
#define HDMI_V13_BLUE_SCREEN_1 HDMI_CORE_BASE(0x0054)
#define HDMI_V13_BLUE_SCREEN_2 HDMI_CORE_BASE(0x0058)
#define HDMI_H_BLANK_0 HDMI_CORE_BASE(0x00A0)
#define HDMI_H_BLANK_1 HDMI_CORE_BASE(0x00A4)
#define HDMI_V13_V_BLANK_0 HDMI_CORE_BASE(0x00B0)
#define HDMI_V13_V_BLANK_1 HDMI_CORE_BASE(0x00B4)
#define HDMI_V13_V_BLANK_2 HDMI_CORE_BASE(0x00B8)
#define HDMI_V13_H_V_LINE_0 HDMI_CORE_BASE(0x00C0)
#define HDMI_V13_H_V_LINE_1 HDMI_CORE_BASE(0x00C4)
#define HDMI_V13_H_V_LINE_2 HDMI_CORE_BASE(0x00C8)
#define HDMI_VSYNC_POL HDMI_CORE_BASE(0x00E4)
#define HDMI_INT_PRO_MODE HDMI_CORE_BASE(0x00E8)
#define HDMI_V13_V_BLANK_F_0 HDMI_CORE_BASE(0x0110)
#define HDMI_V13_V_BLANK_F_1 HDMI_CORE_BASE(0x0114)
#define HDMI_V13_V_BLANK_F_2 HDMI_CORE_BASE(0x0118)
#define HDMI_V13_H_SYNC_GEN_0 HDMI_CORE_BASE(0x0120)
#define HDMI_V13_H_SYNC_GEN_1 HDMI_CORE_BASE(0x0124)
#define HDMI_V13_H_SYNC_GEN_2 HDMI_CORE_BASE(0x0128)
#define HDMI_V13_V_SYNC_GEN_1_0 HDMI_CORE_BASE(0x0130)
#define HDMI_V13_V_SYNC_GEN_1_1 HDMI_CORE_BASE(0x0134)
#define HDMI_V13_V_SYNC_GEN_1_2 HDMI_CORE_BASE(0x0138)
#define HDMI_V13_V_SYNC_GEN_2_0 HDMI_CORE_BASE(0x0140)
#define HDMI_V13_V_SYNC_GEN_2_1 HDMI_CORE_BASE(0x0144)
#define HDMI_V13_V_SYNC_GEN_2_2 HDMI_CORE_BASE(0x0148)
#define HDMI_V13_V_SYNC_GEN_3_0 HDMI_CORE_BASE(0x0150)
#define HDMI_V13_V_SYNC_GEN_3_1 HDMI_CORE_BASE(0x0154)
#define HDMI_V13_V_SYNC_GEN_3_2 HDMI_CORE_BASE(0x0158)
#define HDMI_V13_ACR_CON HDMI_CORE_BASE(0x0180)
#define HDMI_V13_AVI_CON HDMI_CORE_BASE(0x0300)
#define HDMI_V13_AVI_BYTE(n) HDMI_CORE_BASE(0x0320 + 4 * (n))
#define HDMI_V13_DC_CONTROL HDMI_CORE_BASE(0x05C0)
#define HDMI_V13_VIDEO_PATTERN_GEN HDMI_CORE_BASE(0x05C4)
#define HDMI_V13_HPD_GEN HDMI_CORE_BASE(0x05C8)
#define HDMI_V13_AUI_CON HDMI_CORE_BASE(0x0360)
#define HDMI_V13_SPD_CON HDMI_CORE_BASE(0x0400)
/* Timing generator registers */
#define HDMI_TG_CMD HDMI_TG_BASE(0x0000)
#define HDMI_TG_H_FSZ_L HDMI_TG_BASE(0x0018)
#define HDMI_TG_H_FSZ_H HDMI_TG_BASE(0x001C)
#define HDMI_TG_HACT_ST_L HDMI_TG_BASE(0x0020)
#define HDMI_TG_HACT_ST_H HDMI_TG_BASE(0x0024)
#define HDMI_TG_HACT_SZ_L HDMI_TG_BASE(0x0028)
#define HDMI_TG_HACT_SZ_H HDMI_TG_BASE(0x002C)
#define HDMI_TG_V_FSZ_L HDMI_TG_BASE(0x0030)
#define HDMI_TG_V_FSZ_H HDMI_TG_BASE(0x0034)
#define HDMI_TG_VSYNC_L HDMI_TG_BASE(0x0038)
#define HDMI_TG_VSYNC_H HDMI_TG_BASE(0x003C)
#define HDMI_TG_VSYNC2_L HDMI_TG_BASE(0x0040)
#define HDMI_TG_VSYNC2_H HDMI_TG_BASE(0x0044)
#define HDMI_TG_VACT_ST_L HDMI_TG_BASE(0x0048)
#define HDMI_TG_VACT_ST_H HDMI_TG_BASE(0x004C)
#define HDMI_TG_VACT_SZ_L HDMI_TG_BASE(0x0050)
#define HDMI_TG_VACT_SZ_H HDMI_TG_BASE(0x0054)
#define HDMI_TG_FIELD_CHG_L HDMI_TG_BASE(0x0058)
#define HDMI_TG_FIELD_CHG_H HDMI_TG_BASE(0x005C)
#define HDMI_TG_VACT_ST2_L HDMI_TG_BASE(0x0060)
#define HDMI_TG_VACT_ST2_H HDMI_TG_BASE(0x0064)
#define HDMI_TG_VSYNC_TOP_HDMI_L HDMI_TG_BASE(0x0078)
#define HDMI_TG_VSYNC_TOP_HDMI_H HDMI_TG_BASE(0x007C)
#define HDMI_TG_VSYNC_BOT_HDMI_L HDMI_TG_BASE(0x0080)
#define HDMI_TG_VSYNC_BOT_HDMI_H HDMI_TG_BASE(0x0084)
#define HDMI_TG_FIELD_TOP_HDMI_L HDMI_TG_BASE(0x0088)
#define HDMI_TG_FIELD_TOP_HDMI_H HDMI_TG_BASE(0x008C)
#define HDMI_TG_FIELD_BOT_HDMI_L HDMI_TG_BASE(0x0090)
#define HDMI_TG_FIELD_BOT_HDMI_H HDMI_TG_BASE(0x0094)
/*
* Bit definition part
*/
/* HDMI_INTC_CON */
#define HDMI_INTC_EN_GLOBAL (1 << 6)
#define HDMI_INTC_EN_HPD_PLUG (1 << 3)
#define HDMI_INTC_EN_HPD_UNPLUG (1 << 2)
/* HDMI_INTC_FLAG */
#define HDMI_INTC_FLAG_HPD_PLUG (1 << 3)
#define HDMI_INTC_FLAG_HPD_UNPLUG (1 << 2)
/* HDMI_PHY_RSTOUT */
#define HDMI_PHY_SW_RSTOUT (1 << 0)
/* HDMI_CORE_RSTOUT */
#define HDMI_CORE_SW_RSTOUT (1 << 0)
/* HDMI_CON_0 */
#define HDMI_BLUE_SCR_EN (1 << 5)
#define HDMI_ASP_EN (1 << 2)
#define HDMI_ASP_DIS (0 << 2)
#define HDMI_ASP_MASK (1 << 2)
#define HDMI_EN (1 << 0)
/* HDMI_CON_2 */
#define HDMI_VID_PREAMBLE_DIS (1 << 5)
#define HDMI_GUARD_BAND_DIS (1 << 1)
/* HDMI_PHY_STATUS */
#define HDMI_PHY_STATUS_READY (1 << 0)
/* HDMI_MODE_SEL */
#define HDMI_MODE_HDMI_EN (1 << 1)
#define HDMI_MODE_DVI_EN (1 << 0)
#define HDMI_MODE_MASK (3 << 0)
/* HDMI_TG_CMD */
#define HDMI_TG_EN (1 << 0)
#define HDMI_FIELD_EN (1 << 1)
/* HDMI Version 1.4 */
/* Control registers */
/* #define HDMI_INTC_CON HDMI_CTRL_BASE(0x0000) */
/* #define HDMI_INTC_FLAG HDMI_CTRL_BASE(0x0004) */
#define HDMI_HDCP_KEY_LOAD HDMI_CTRL_BASE(0x0008)
/* #define HDMI_HPD_STATUS HDMI_CTRL_BASE(0x000C) */
#define HDMI_INTC_CON_1 HDMI_CTRL_BASE(0x0010)
#define HDMI_INTC_FLAG_1 HDMI_CTRL_BASE(0x0014)
#define HDMI_PHY_STATUS_0 HDMI_CTRL_BASE(0x0020)
#define HDMI_PHY_STATUS_CMU HDMI_CTRL_BASE(0x0024)
#define HDMI_PHY_STATUS_PLL HDMI_CTRL_BASE(0x0028)
#define HDMI_PHY_CON_0 HDMI_CTRL_BASE(0x0030)
#define HDMI_HPD_CTRL HDMI_CTRL_BASE(0x0040)
#define HDMI_HPD_ST HDMI_CTRL_BASE(0x0044)
#define HDMI_HPD_TH_X HDMI_CTRL_BASE(0x0050)
#define HDMI_AUDIO_CLKSEL HDMI_CTRL_BASE(0x0070)
#define HDMI_PHY_RSTOUT HDMI_CTRL_BASE(0x0074)
#define HDMI_PHY_VPLL HDMI_CTRL_BASE(0x0078)
#define HDMI_PHY_CMU HDMI_CTRL_BASE(0x007C)
#define HDMI_CORE_RSTOUT HDMI_CTRL_BASE(0x0080)
/* PHY Control bit definition */
/* HDMI_PHY_CON_0 */
#define HDMI_PHY_POWER_OFF_EN (1 << 0)
/* Video related registers */
#define HDMI_YMAX HDMI_CORE_BASE(0x0060)
#define HDMI_YMIN HDMI_CORE_BASE(0x0064)
#define HDMI_CMAX HDMI_CORE_BASE(0x0068)
#define HDMI_CMIN HDMI_CORE_BASE(0x006C)
#define HDMI_V2_BLANK_0 HDMI_CORE_BASE(0x00B0)
#define HDMI_V2_BLANK_1 HDMI_CORE_BASE(0x00B4)
#define HDMI_V1_BLANK_0 HDMI_CORE_BASE(0x00B8)
#define HDMI_V1_BLANK_1 HDMI_CORE_BASE(0x00BC)
#define HDMI_V_LINE_0 HDMI_CORE_BASE(0x00C0)
#define HDMI_V_LINE_1 HDMI_CORE_BASE(0x00C4)
#define HDMI_H_LINE_0 HDMI_CORE_BASE(0x00C8)
#define HDMI_H_LINE_1 HDMI_CORE_BASE(0x00CC)
#define HDMI_HSYNC_POL HDMI_CORE_BASE(0x00E0)
#define HDMI_V_BLANK_F0_0 HDMI_CORE_BASE(0x0110)
#define HDMI_V_BLANK_F0_1 HDMI_CORE_BASE(0x0114)
#define HDMI_V_BLANK_F1_0 HDMI_CORE_BASE(0x0118)
#define HDMI_V_BLANK_F1_1 HDMI_CORE_BASE(0x011C)
#define HDMI_H_SYNC_START_0 HDMI_CORE_BASE(0x0120)
#define HDMI_H_SYNC_START_1 HDMI_CORE_BASE(0x0124)
#define HDMI_H_SYNC_END_0 HDMI_CORE_BASE(0x0128)
#define HDMI_H_SYNC_END_1 HDMI_CORE_BASE(0x012C)
#define HDMI_V_SYNC_LINE_BEF_2_0 HDMI_CORE_BASE(0x0130)
#define HDMI_V_SYNC_LINE_BEF_2_1 HDMI_CORE_BASE(0x0134)
#define HDMI_V_SYNC_LINE_BEF_1_0 HDMI_CORE_BASE(0x0138)
#define HDMI_V_SYNC_LINE_BEF_1_1 HDMI_CORE_BASE(0x013C)
#define HDMI_V_SYNC_LINE_AFT_2_0 HDMI_CORE_BASE(0x0140)
#define HDMI_V_SYNC_LINE_AFT_2_1 HDMI_CORE_BASE(0x0144)
#define HDMI_V_SYNC_LINE_AFT_1_0 HDMI_CORE_BASE(0x0148)
#define HDMI_V_SYNC_LINE_AFT_1_1 HDMI_CORE_BASE(0x014C)
#define HDMI_V_SYNC_LINE_AFT_PXL_2_0 HDMI_CORE_BASE(0x0150)
#define HDMI_V_SYNC_LINE_AFT_PXL_2_1 HDMI_CORE_BASE(0x0154)
#define HDMI_V_SYNC_LINE_AFT_PXL_1_0 HDMI_CORE_BASE(0x0158)
#define HDMI_V_SYNC_LINE_AFT_PXL_1_1 HDMI_CORE_BASE(0x015C)
#define HDMI_V_BLANK_F2_0 HDMI_CORE_BASE(0x0160)
#define HDMI_V_BLANK_F2_1 HDMI_CORE_BASE(0x0164)
#define HDMI_V_BLANK_F3_0 HDMI_CORE_BASE(0x0168)
#define HDMI_V_BLANK_F3_1 HDMI_CORE_BASE(0x016C)
#define HDMI_V_BLANK_F4_0 HDMI_CORE_BASE(0x0170)
#define HDMI_V_BLANK_F4_1 HDMI_CORE_BASE(0x0174)
#define HDMI_V_BLANK_F5_0 HDMI_CORE_BASE(0x0178)
#define HDMI_V_BLANK_F5_1 HDMI_CORE_BASE(0x017C)
#define HDMI_V_SYNC_LINE_AFT_3_0 HDMI_CORE_BASE(0x0180)
#define HDMI_V_SYNC_LINE_AFT_3_1 HDMI_CORE_BASE(0x0184)
#define HDMI_V_SYNC_LINE_AFT_4_0 HDMI_CORE_BASE(0x0188)
#define HDMI_V_SYNC_LINE_AFT_4_1 HDMI_CORE_BASE(0x018C)
#define HDMI_V_SYNC_LINE_AFT_5_0 HDMI_CORE_BASE(0x0190)
#define HDMI_V_SYNC_LINE_AFT_5_1 HDMI_CORE_BASE(0x0194)
#define HDMI_V_SYNC_LINE_AFT_6_0 HDMI_CORE_BASE(0x0198)
#define HDMI_V_SYNC_LINE_AFT_6_1 HDMI_CORE_BASE(0x019C)
#define HDMI_V_SYNC_LINE_AFT_PXL_3_0 HDMI_CORE_BASE(0x01A0)
#define HDMI_V_SYNC_LINE_AFT_PXL_3_1 HDMI_CORE_BASE(0x01A4)
#define HDMI_V_SYNC_LINE_AFT_PXL_4_0 HDMI_CORE_BASE(0x01A8)
#define HDMI_V_SYNC_LINE_AFT_PXL_4_1 HDMI_CORE_BASE(0x01AC)
#define HDMI_V_SYNC_LINE_AFT_PXL_5_0 HDMI_CORE_BASE(0x01B0)
#define HDMI_V_SYNC_LINE_AFT_PXL_5_1 HDMI_CORE_BASE(0x01B4)
#define HDMI_V_SYNC_LINE_AFT_PXL_6_0 HDMI_CORE_BASE(0x01B8)
#define HDMI_V_SYNC_LINE_AFT_PXL_6_1 HDMI_CORE_BASE(0x01BC)
#define HDMI_VACT_SPACE_1_0 HDMI_CORE_BASE(0x01C0)
#define HDMI_VACT_SPACE_1_1 HDMI_CORE_BASE(0x01C4)
#define HDMI_VACT_SPACE_2_0 HDMI_CORE_BASE(0x01C8)
#define HDMI_VACT_SPACE_2_1 HDMI_CORE_BASE(0x01CC)
#define HDMI_VACT_SPACE_3_0 HDMI_CORE_BASE(0x01D0)
#define HDMI_VACT_SPACE_3_1 HDMI_CORE_BASE(0x01D4)
#define HDMI_VACT_SPACE_4_0 HDMI_CORE_BASE(0x01D8)
#define HDMI_VACT_SPACE_4_1 HDMI_CORE_BASE(0x01DC)
#define HDMI_VACT_SPACE_5_0 HDMI_CORE_BASE(0x01E0)
#define HDMI_VACT_SPACE_5_1 HDMI_CORE_BASE(0x01E4)
#define HDMI_VACT_SPACE_6_0 HDMI_CORE_BASE(0x01E8)
#define HDMI_VACT_SPACE_6_1 HDMI_CORE_BASE(0x01EC)
#define HDMI_GCP_CON HDMI_CORE_BASE(0x0200)
#define HDMI_GCP_BYTE1 HDMI_CORE_BASE(0x0210)
#define HDMI_GCP_BYTE2 HDMI_CORE_BASE(0x0214)
#define HDMI_GCP_BYTE3 HDMI_CORE_BASE(0x0218)
/* Audio related registers */
#define HDMI_ASP_CON HDMI_CORE_BASE(0x0300)
#define HDMI_ASP_SP_FLAT HDMI_CORE_BASE(0x0304)
#define HDMI_ASP_CHCFG0 HDMI_CORE_BASE(0x0310)
#define HDMI_ASP_CHCFG1 HDMI_CORE_BASE(0x0314)
#define HDMI_ASP_CHCFG2 HDMI_CORE_BASE(0x0318)
#define HDMI_ASP_CHCFG3 HDMI_CORE_BASE(0x031C)
#define HDMI_ACR_CON HDMI_CORE_BASE(0x0400)
#define HDMI_ACR_MCTS0 HDMI_CORE_BASE(0x0410)
#define HDMI_ACR_MCTS1 HDMI_CORE_BASE(0x0414)
#define HDMI_ACR_MCTS2 HDMI_CORE_BASE(0x0418)
#define HDMI_ACR_CTS0 HDMI_CORE_BASE(0x0420)
#define HDMI_ACR_CTS1 HDMI_CORE_BASE(0x0424)
#define HDMI_ACR_CTS2 HDMI_CORE_BASE(0x0428)
#define HDMI_ACR_N0 HDMI_CORE_BASE(0x0430)
#define HDMI_ACR_N1 HDMI_CORE_BASE(0x0434)
#define HDMI_ACR_N2 HDMI_CORE_BASE(0x0438)
/* Packet related registers */
#define HDMI_ACP_CON HDMI_CORE_BASE(0x0500)
#define HDMI_ACP_TYPE HDMI_CORE_BASE(0x0514)
#define HDMI_ACP_DATA(n) HDMI_CORE_BASE(0x0520 + 4 * (n))
#define HDMI_ISRC_CON HDMI_CORE_BASE(0x0600)
#define HDMI_ISRC1_HEADER1 HDMI_CORE_BASE(0x0614)
#define HDMI_ISRC1_DATA(n) HDMI_CORE_BASE(0x0620 + 4 * (n))
#define HDMI_ISRC2_DATA(n) HDMI_CORE_BASE(0x06A0 + 4 * (n))
#define HDMI_AVI_CON HDMI_CORE_BASE(0x0700)
#define HDMI_AVI_HEADER0 HDMI_CORE_BASE(0x0710)
#define HDMI_AVI_HEADER1 HDMI_CORE_BASE(0x0714)
#define HDMI_AVI_HEADER2 HDMI_CORE_BASE(0x0718)
#define HDMI_AVI_CHECK_SUM HDMI_CORE_BASE(0x071C)
#define HDMI_AVI_BYTE(n) HDMI_CORE_BASE(0x0720 + 4 * (n-1))
#define HDMI_AUI_CON HDMI_CORE_BASE(0x0800)
#define HDMI_AUI_HEADER0 HDMI_CORE_BASE(0x0810)
#define HDMI_AUI_HEADER1 HDMI_CORE_BASE(0x0814)
#define HDMI_AUI_HEADER2 HDMI_CORE_BASE(0x0818)
#define HDMI_AUI_CHECK_SUM HDMI_CORE_BASE(0x081C)
#define HDMI_AUI_BYTE(n) HDMI_CORE_BASE(0x0820 + 4 * (n-1))
#define HDMI_MPG_CON HDMI_CORE_BASE(0x0900)
#define HDMI_MPG_CHECK_SUM HDMI_CORE_BASE(0x091C)
#define HDMI_MPG_DATA(n) HDMI_CORE_BASE(0x0920 + 4 * (n))
#define HDMI_SPD_CON HDMI_CORE_BASE(0x0A00)
#define HDMI_SPD_HEADER0 HDMI_CORE_BASE(0x0A10)
#define HDMI_SPD_HEADER1 HDMI_CORE_BASE(0x0A14)
#define HDMI_SPD_HEADER2 HDMI_CORE_BASE(0x0A18)
#define HDMI_SPD_DATA(n) HDMI_CORE_BASE(0x0A20 + 4 * (n))
#define HDMI_GAMUT_CON HDMI_CORE_BASE(0x0B00)
#define HDMI_GAMUT_HEADER0 HDMI_CORE_BASE(0x0B10)
#define HDMI_GAMUT_HEADER1 HDMI_CORE_BASE(0x0B14)
#define HDMI_GAMUT_HEADER2 HDMI_CORE_BASE(0x0B18)
#define HDMI_GAMUT_METADATA(n) HDMI_CORE_BASE(0x0B20 + 4 * (n))
#define HDMI_VSI_CON HDMI_CORE_BASE(0x0C00)
#define HDMI_VSI_HEADER0 HDMI_CORE_BASE(0x0C10)
#define HDMI_VSI_HEADER1 HDMI_CORE_BASE(0x0C14)
#define HDMI_VSI_HEADER2 HDMI_CORE_BASE(0x0C18)
#define HDMI_VSI_DATA(n) HDMI_CORE_BASE(0x0C20 + 4 * (n))
#define HDMI_DC_CONTROL HDMI_CORE_BASE(0x0D00)
#define HDMI_VIDEO_PATTERN_GEN HDMI_CORE_BASE(0x0D04)
#define HDMI_AN_SEED_SEL HDMI_CORE_BASE(0x0E48)
#define HDMI_AN_SEED_0 HDMI_CORE_BASE(0x0E58)
#define HDMI_AN_SEED_1 HDMI_CORE_BASE(0x0E5C)
#define HDMI_AN_SEED_2 HDMI_CORE_BASE(0x0E60)
#define HDMI_AN_SEED_3 HDMI_CORE_BASE(0x0E64)
/* AVI bit definition */
#define HDMI_AVI_CON_DO_NOT_TRANSMIT (0 << 1)
#define HDMI_AVI_CON_EVERY_VSYNC (1 << 1)
#define AVI_ACTIVE_FORMAT_VALID (1 << 4)
#define AVI_UNDERSCANNED_DISPLAY_VALID (1 << 1)
/* AUI bit definition */
#define HDMI_AUI_CON_NO_TRAN (0 << 0)
/* VSI bit definition */
#define HDMI_VSI_CON_DO_NOT_TRANSMIT (0 << 0)
/* HDCP related registers */
#define HDMI_HDCP_SHA1(n) HDMI_CORE_BASE(0x7000 + 4 * (n))
#define HDMI_HDCP_KSV_LIST(n) HDMI_CORE_BASE(0x7050 + 4 * (n))
#define HDMI_HDCP_KSV_LIST_CON HDMI_CORE_BASE(0x7064)
#define HDMI_HDCP_SHA_RESULT HDMI_CORE_BASE(0x7070)
#define HDMI_HDCP_CTRL1 HDMI_CORE_BASE(0x7080)
#define HDMI_HDCP_CTRL2 HDMI_CORE_BASE(0x7084)
#define HDMI_HDCP_CHECK_RESULT HDMI_CORE_BASE(0x7090)
#define HDMI_HDCP_BKSV(n) HDMI_CORE_BASE(0x70A0 + 4 * (n))
#define HDMI_HDCP_AKSV(n) HDMI_CORE_BASE(0x70C0 + 4 * (n))
#define HDMI_HDCP_AN(n) HDMI_CORE_BASE(0x70E0 + 4 * (n))
#define HDMI_HDCP_BCAPS HDMI_CORE_BASE(0x7100)
#define HDMI_HDCP_BSTATUS_0 HDMI_CORE_BASE(0x7110)
#define HDMI_HDCP_BSTATUS_1 HDMI_CORE_BASE(0x7114)
#define HDMI_HDCP_RI_0 HDMI_CORE_BASE(0x7140)
#define HDMI_HDCP_RI_1 HDMI_CORE_BASE(0x7144)
#define HDMI_HDCP_I2C_INT HDMI_CORE_BASE(0x7180)
#define HDMI_HDCP_AN_INT HDMI_CORE_BASE(0x7190)
#define HDMI_HDCP_WDT_INT HDMI_CORE_BASE(0x71A0)
#define HDMI_HDCP_RI_INT HDMI_CORE_BASE(0x71B0)
#define HDMI_HDCP_RI_COMPARE_0 HDMI_CORE_BASE(0x71D0)
#define HDMI_HDCP_RI_COMPARE_1 HDMI_CORE_BASE(0x71D4)
#define HDMI_HDCP_FRAME_COUNT HDMI_CORE_BASE(0x71E0)
#define HDMI_RGB_ROUND_EN HDMI_CORE_BASE(0xD500)
#define HDMI_VACT_SPACE_R_0 HDMI_CORE_BASE(0xD504)
#define HDMI_VACT_SPACE_R_1 HDMI_CORE_BASE(0xD508)
#define HDMI_VACT_SPACE_G_0 HDMI_CORE_BASE(0xD50C)
#define HDMI_VACT_SPACE_G_1 HDMI_CORE_BASE(0xD510)
#define HDMI_VACT_SPACE_B_0 HDMI_CORE_BASE(0xD514)
#define HDMI_VACT_SPACE_B_1 HDMI_CORE_BASE(0xD518)
#define HDMI_BLUE_SCREEN_B_0 HDMI_CORE_BASE(0xD520)
#define HDMI_BLUE_SCREEN_B_1 HDMI_CORE_BASE(0xD524)
#define HDMI_BLUE_SCREEN_G_0 HDMI_CORE_BASE(0xD528)
#define HDMI_BLUE_SCREEN_G_1 HDMI_CORE_BASE(0xD52C)
#define HDMI_BLUE_SCREEN_R_0 HDMI_CORE_BASE(0xD530)
#define HDMI_BLUE_SCREEN_R_1 HDMI_CORE_BASE(0xD534)
/* HDMI I2S register */
#define HDMI_I2S_CLK_CON HDMI_I2S_BASE(0x000)
#define HDMI_I2S_CON_1 HDMI_I2S_BASE(0x004)
#define HDMI_I2S_CON_2 HDMI_I2S_BASE(0x008)
#define HDMI_I2S_PIN_SEL_0 HDMI_I2S_BASE(0x00c)
#define HDMI_I2S_PIN_SEL_1 HDMI_I2S_BASE(0x010)
#define HDMI_I2S_PIN_SEL_2 HDMI_I2S_BASE(0x014)
#define HDMI_I2S_PIN_SEL_3 HDMI_I2S_BASE(0x018)
#define HDMI_I2S_DSD_CON HDMI_I2S_BASE(0x01c)
#define HDMI_I2S_MUX_CON HDMI_I2S_BASE(0x020)
#define HDMI_I2S_CH_ST_CON HDMI_I2S_BASE(0x024)
#define HDMI_I2S_CH_ST_0 HDMI_I2S_BASE(0x028)
#define HDMI_I2S_CH_ST_1 HDMI_I2S_BASE(0x02c)
#define HDMI_I2S_CH_ST_2 HDMI_I2S_BASE(0x030)
#define HDMI_I2S_CH_ST_3 HDMI_I2S_BASE(0x034)
#define HDMI_I2S_CH_ST_4 HDMI_I2S_BASE(0x038)
#define HDMI_I2S_CH_ST_SH_0 HDMI_I2S_BASE(0x03c)
#define HDMI_I2S_CH_ST_SH_1 HDMI_I2S_BASE(0x040)
#define HDMI_I2S_CH_ST_SH_2 HDMI_I2S_BASE(0x044)
#define HDMI_I2S_CH_ST_SH_3 HDMI_I2S_BASE(0x048)
#define HDMI_I2S_CH_ST_SH_4 HDMI_I2S_BASE(0x04c)
#define HDMI_I2S_MUX_CH HDMI_I2S_BASE(0x054)
#define HDMI_I2S_MUX_CUV HDMI_I2S_BASE(0x058)
/* I2S bit definition */
/* I2S_CLK_CON */
#define HDMI_I2S_CLK_DIS (0)
#define HDMI_I2S_CLK_EN (1)
/* I2S_CON_1 */
#define HDMI_I2S_SCLK_FALLING_EDGE (0 << 1)
#define HDMI_I2S_SCLK_RISING_EDGE (1 << 1)
#define HDMI_I2S_L_CH_LOW_POL (0)
#define HDMI_I2S_L_CH_HIGH_POL (1)
/* I2S_CON_2 */
#define HDMI_I2S_MSB_FIRST_MODE (0 << 6)
#define HDMI_I2S_LSB_FIRST_MODE (1 << 6)
#define HDMI_I2S_BIT_CH_32FS (0 << 4)
#define HDMI_I2S_BIT_CH_48FS (1 << 4)
#define HDMI_I2S_BIT_CH_RESERVED (2 << 4)
#define HDMI_I2S_SDATA_16BIT (1 << 2)
#define HDMI_I2S_SDATA_20BIT (2 << 2)
#define HDMI_I2S_SDATA_24BIT (3 << 2)
#define HDMI_I2S_BASIC_FORMAT (0)
#define HDMI_I2S_L_JUST_FORMAT (2)
#define HDMI_I2S_R_JUST_FORMAT (3)
#define HDMI_I2S_CON_2_CLR (~(0xFF))
#define HDMI_I2S_SET_BIT_CH(x) (((x) & 0x7) << 4)
#define HDMI_I2S_SET_SDATA_BIT(x) (((x) & 0x7) << 2)
/* I2S_PIN_SEL_0 */
#define HDMI_I2S_SEL_SCLK(x) (((x) & 0x7) << 4)
#define HDMI_I2S_SEL_LRCK(x) ((x) & 0x7)
/* I2S_PIN_SEL_1 */
#define HDMI_I2S_SEL_SDATA1(x) (((x) & 0x7) << 4)
#define HDMI_I2S_SEL_SDATA2(x) ((x) & 0x7)
/* I2S_PIN_SEL_2 */
#define HDMI_I2S_SEL_SDATA3(x) (((x) & 0x7) << 4)
#define HDMI_I2S_SEL_SDATA2(x) ((x) & 0x7)
/* I2S_PIN_SEL_3 */
#define HDMI_I2S_SEL_DSD(x) ((x) & 0x7)
/* I2S_DSD_CON */
#define HDMI_I2S_DSD_CLK_RI_EDGE (1 << 1)
#define HDMI_I2S_DSD_CLK_FA_EDGE (0 << 1)
#define HDMI_I2S_DSD_ENABLE (1)
#define HDMI_I2S_DSD_DISABLE (0)
/* I2S_MUX_CON */
#define HDMI_I2S_NOISE_FILTER_ZERO (0 << 5)
#define HDMI_I2S_NOISE_FILTER_2_STAGE (1 << 5)
#define HDMI_I2S_NOISE_FILTER_3_STAGE (2 << 5)
#define HDMI_I2S_NOISE_FILTER_4_STAGE (3 << 5)
#define HDMI_I2S_NOISE_FILTER_5_STAGE (4 << 5)
#define HDMI_I2S_IN_DISABLE (1 << 4)
#define HDMI_I2S_IN_ENABLE (0 << 4)
#define HDMI_I2S_AUD_SPDIF (0 << 2)
#define HDMI_I2S_AUD_I2S (1 << 2)
#define HDMI_I2S_AUD_DSD (2 << 2)
#define HDMI_I2S_CUV_SPDIF_ENABLE (0 << 1)
#define HDMI_I2S_CUV_I2S_ENABLE (1 << 1)
#define HDMI_I2S_MUX_DISABLE (0)
#define HDMI_I2S_MUX_ENABLE (1)
#define HDMI_I2S_MUX_CON_CLR (~(0xFF))
/* I2S_CH_ST_CON */
#define HDMI_I2S_CH_STATUS_RELOAD (1)
#define HDMI_I2S_CH_ST_CON_CLR (~(1))
/* I2S_CH_ST_0 / I2S_CH_ST_SH_0 */
#define HDMI_I2S_CH_STATUS_MODE_0 (0 << 6)
#define HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH (0 << 3)
#define HDMI_I2S_2AUD_CH_WITH_PREEMPH (1 << 3)
#define HDMI_I2S_DEFAULT_EMPHASIS (0 << 3)
#define HDMI_I2S_COPYRIGHT (0 << 2)
#define HDMI_I2S_NO_COPYRIGHT (1 << 2)
#define HDMI_I2S_LINEAR_PCM (0 << 1)
#define HDMI_I2S_NO_LINEAR_PCM (1 << 1)
#define HDMI_I2S_CONSUMER_FORMAT (0)
#define HDMI_I2S_PROF_FORMAT (1)
#define HDMI_I2S_CH_ST_0_CLR (~(0xFF))
/* I2S_CH_ST_1 / I2S_CH_ST_SH_1 */
#define HDMI_I2S_CD_PLAYER (0x00)
#define HDMI_I2S_DAT_PLAYER (0x03)
#define HDMI_I2S_DCC_PLAYER (0x43)
#define HDMI_I2S_MINI_DISC_PLAYER (0x49)
/* I2S_CH_ST_2 / I2S_CH_ST_SH_2 */
#define HDMI_I2S_CHANNEL_NUM_MASK (0xF << 4)
#define HDMI_I2S_SOURCE_NUM_MASK (0xF)
#define HDMI_I2S_SET_CHANNEL_NUM(x) (((x) & (0xF)) << 4)
#define HDMI_I2S_SET_SOURCE_NUM(x) ((x) & (0xF))
/* I2S_CH_ST_3 / I2S_CH_ST_SH_3 */
#define HDMI_I2S_CLK_ACCUR_LEVEL_1 (1 << 4)
#define HDMI_I2S_CLK_ACCUR_LEVEL_2 (0 << 4)
#define HDMI_I2S_CLK_ACCUR_LEVEL_3 (2 << 4)
#define HDMI_I2S_SMP_FREQ_44_1 (0x0)
#define HDMI_I2S_SMP_FREQ_48 (0x2)
#define HDMI_I2S_SMP_FREQ_32 (0x3)
#define HDMI_I2S_SMP_FREQ_96 (0xA)
#define HDMI_I2S_SET_SMP_FREQ(x) ((x) & (0xF))
/* I2S_CH_ST_4 / I2S_CH_ST_SH_4 */
#define HDMI_I2S_ORG_SMP_FREQ_44_1 (0xF << 4)
#define HDMI_I2S_ORG_SMP_FREQ_88_2 (0x7 << 4)
#define HDMI_I2S_ORG_SMP_FREQ_22_05 (0xB << 4)
#define HDMI_I2S_ORG_SMP_FREQ_176_4 (0x3 << 4)
#define HDMI_I2S_WORD_LEN_NOT_DEFINE (0x0 << 1)
#define HDMI_I2S_WORD_LEN_MAX24_20BITS (0x1 << 1)
#define HDMI_I2S_WORD_LEN_MAX24_22BITS (0x2 << 1)
#define HDMI_I2S_WORD_LEN_MAX24_23BITS (0x4 << 1)
#define HDMI_I2S_WORD_LEN_MAX24_24BITS (0x5 << 1)
#define HDMI_I2S_WORD_LEN_MAX24_21BITS (0x6 << 1)
#define HDMI_I2S_WORD_LEN_MAX20_16BITS (0x1 << 1)
#define HDMI_I2S_WORD_LEN_MAX20_18BITS (0x2 << 1)
#define HDMI_I2S_WORD_LEN_MAX20_19BITS (0x4 << 1)
#define HDMI_I2S_WORD_LEN_MAX20_20BITS (0x5 << 1)
#define HDMI_I2S_WORD_LEN_MAX20_17BITS (0x6 << 1)
#define HDMI_I2S_WORD_LEN_MAX_24BITS (1)
#define HDMI_I2S_WORD_LEN_MAX_20BITS (0)
/* I2S_MUX_CH */
#define HDMI_I2S_CH3_R_EN (1 << 7)
#define HDMI_I2S_CH3_L_EN (1 << 6)
#define HDMI_I2S_CH3_EN (3 << 6)
#define HDMI_I2S_CH2_R_EN (1 << 5)
#define HDMI_I2S_CH2_L_EN (1 << 4)
#define HDMI_I2S_CH2_EN (3 << 4)
#define HDMI_I2S_CH1_R_EN (1 << 3)
#define HDMI_I2S_CH1_L_EN (1 << 2)
#define HDMI_I2S_CH1_EN (3 << 2)
#define HDMI_I2S_CH0_R_EN (1 << 1)
#define HDMI_I2S_CH0_L_EN (1)
#define HDMI_I2S_CH0_EN (3)
#define HDMI_I2S_CH_ALL_EN (0xFF)
#define HDMI_I2S_MUX_CH_CLR (~HDMI_I2S_CH_ALL_EN)
/* I2S_MUX_CUV */
#define HDMI_I2S_CUV_R_EN (1 << 1)
#define HDMI_I2S_CUV_L_EN (1)
#define HDMI_I2S_CUV_RL_EN (0x03)
/* I2S_CUV_L_R */
#define HDMI_I2S_CUV_R_DATA_MASK (0x7 << 4)
#define HDMI_I2S_CUV_L_DATA_MASK (0x7)
/* Timing generator registers */
/* TG configure/status registers */
#define HDMI_TG_VACT_ST3_L HDMI_TG_BASE(0x0068)
#define HDMI_TG_VACT_ST3_H HDMI_TG_BASE(0x006c)
#define HDMI_TG_VACT_ST4_L HDMI_TG_BASE(0x0070)
#define HDMI_TG_VACT_ST4_H HDMI_TG_BASE(0x0074)
#define HDMI_TG_3D HDMI_TG_BASE(0x00F0)
/* HDMI PHY Registers Offsets*/
#define HDMIPHY_POWER (0x74 >> 2)
#define HDMIPHY_MODE_SET_DONE (0x7c >> 2)
/* HDMI PHY Values */
#define HDMI_PHY_POWER_ON 0x80
#define HDMI_PHY_POWER_OFF 0xff
/* HDMI PHY Values */
#define HDMI_PHY_DISABLE_MODE_SET 0x80
#define HDMI_PHY_ENABLE_MODE_SET 0x00
/* PMU Registers for PHY */
#define PMU_HDMI_PHY_CONTROL 0x700
#define PMU_HDMI_PHY_ENABLE_BIT BIT(0)
#endif /* SAMSUNG_REGS_HDMI_H */

View file

@ -0,0 +1,152 @@
/*
*
* Cloned from drivers/media/video/s5p-tv/regs-mixer.h
*
* Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Mixer register header file for Samsung Mixer 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_REGS_MIXER_H
#define SAMSUNG_REGS_MIXER_H
/*
* Register part
*/
#define MXR_STATUS 0x0000
#define MXR_CFG 0x0004
#define MXR_INT_EN 0x0008
#define MXR_INT_STATUS 0x000C
#define MXR_LAYER_CFG 0x0010
#define MXR_VIDEO_CFG 0x0014
#define MXR_GRAPHIC0_CFG 0x0020
#define MXR_GRAPHIC0_BASE 0x0024
#define MXR_GRAPHIC0_SPAN 0x0028
#define MXR_GRAPHIC0_SXY 0x002C
#define MXR_GRAPHIC0_WH 0x0030
#define MXR_GRAPHIC0_DXY 0x0034
#define MXR_GRAPHIC0_BLANK 0x0038
#define MXR_GRAPHIC1_CFG 0x0040
#define MXR_GRAPHIC1_BASE 0x0044
#define MXR_GRAPHIC1_SPAN 0x0048
#define MXR_GRAPHIC1_SXY 0x004C
#define MXR_GRAPHIC1_WH 0x0050
#define MXR_GRAPHIC1_DXY 0x0054
#define MXR_GRAPHIC1_BLANK 0x0058
#define MXR_BG_CFG 0x0060
#define MXR_BG_COLOR0 0x0064
#define MXR_BG_COLOR1 0x0068
#define MXR_BG_COLOR2 0x006C
#define MXR_CM_COEFF_Y 0x0080
#define MXR_CM_COEFF_CB 0x0084
#define MXR_CM_COEFF_CR 0x0088
#define MXR_MO 0x0304
#define MXR_RESOLUTION 0x0310
#define MXR_GRAPHIC0_BASE_S 0x2024
#define MXR_GRAPHIC1_BASE_S 0x2044
/* for parametrized access to layer registers */
#define MXR_GRAPHIC_CFG(i) (0x0020 + (i) * 0x20)
#define MXR_GRAPHIC_BASE(i) (0x0024 + (i) * 0x20)
#define MXR_GRAPHIC_SPAN(i) (0x0028 + (i) * 0x20)
#define MXR_GRAPHIC_SXY(i) (0x002C + (i) * 0x20)
#define MXR_GRAPHIC_WH(i) (0x0030 + (i) * 0x20)
#define MXR_GRAPHIC_DXY(i) (0x0034 + (i) * 0x20)
#define MXR_GRAPHIC_BLANK(i) (0x0038 + (i) * 0x20)
#define MXR_GRAPHIC_BASE_S(i) (0x2024 + (i) * 0x20)
/*
* Bit definition part
*/
/* generates mask for range of bits */
#define MXR_MASK(high_bit, low_bit) \
(((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
#define MXR_MASK_VAL(val, high_bit, low_bit) \
(((val) << (low_bit)) & MXR_MASK(high_bit, low_bit))
/* bits for MXR_STATUS */
#define MXR_STATUS_SOFT_RESET (1 << 8)
#define MXR_STATUS_16_BURST (1 << 7)
#define MXR_STATUS_BURST_MASK (1 << 7)
#define MXR_STATUS_BIG_ENDIAN (1 << 3)
#define MXR_STATUS_ENDIAN_MASK (1 << 3)
#define MXR_STATUS_SYNC_ENABLE (1 << 2)
#define MXR_STATUS_REG_IDLE (1 << 1)
#define MXR_STATUS_REG_RUN (1 << 0)
/* bits for MXR_CFG */
#define MXR_CFG_LAYER_UPDATE (1 << 31)
#define MXR_CFG_LAYER_UPDATE_COUNT_MASK (3 << 29)
#define MXR_CFG_RGB601_0_255 (0 << 9)
#define MXR_CFG_RGB601_16_235 (1 << 9)
#define MXR_CFG_RGB709_0_255 (2 << 9)
#define MXR_CFG_RGB709_16_235 (3 << 9)
#define MXR_CFG_RGB_FMT_MASK 0x600
#define MXR_CFG_OUT_YUV444 (0 << 8)
#define MXR_CFG_OUT_RGB888 (1 << 8)
#define MXR_CFG_OUT_MASK (1 << 8)
#define MXR_CFG_DST_SDO (0 << 7)
#define MXR_CFG_DST_HDMI (1 << 7)
#define MXR_CFG_DST_MASK (1 << 7)
#define MXR_CFG_SCAN_HD_720 (0 << 6)
#define MXR_CFG_SCAN_HD_1080 (1 << 6)
#define MXR_CFG_GRP1_ENABLE (1 << 5)
#define MXR_CFG_GRP0_ENABLE (1 << 4)
#define MXR_CFG_VP_ENABLE (1 << 3)
#define MXR_CFG_SCAN_INTERLACE (0 << 2)
#define MXR_CFG_SCAN_PROGRASSIVE (1 << 2)
#define MXR_CFG_SCAN_NTSC (0 << 1)
#define MXR_CFG_SCAN_PAL (1 << 1)
#define MXR_CFG_SCAN_SD (0 << 0)
#define MXR_CFG_SCAN_HD (1 << 0)
#define MXR_CFG_SCAN_MASK 0x47
/* bits for MXR_GRAPHICn_CFG */
#define MXR_GRP_CFG_COLOR_KEY_DISABLE (1 << 21)
#define MXR_GRP_CFG_BLEND_PRE_MUL (1 << 20)
#define MXR_GRP_CFG_WIN_BLEND_EN (1 << 17)
#define MXR_GRP_CFG_PIXEL_BLEND_EN (1 << 16)
#define MXR_GRP_CFG_FORMAT_VAL(x) MXR_MASK_VAL(x, 11, 8)
#define MXR_GRP_CFG_FORMAT_MASK MXR_GRP_CFG_FORMAT_VAL(~0)
#define MXR_GRP_CFG_ALPHA_VAL(x) MXR_MASK_VAL(x, 7, 0)
/* bits for MXR_GRAPHICn_WH */
#define MXR_GRP_WH_H_SCALE(x) MXR_MASK_VAL(x, 28, 28)
#define MXR_GRP_WH_V_SCALE(x) MXR_MASK_VAL(x, 12, 12)
#define MXR_GRP_WH_WIDTH(x) MXR_MASK_VAL(x, 26, 16)
#define MXR_GRP_WH_HEIGHT(x) MXR_MASK_VAL(x, 10, 0)
/* bits for MXR_RESOLUTION */
#define MXR_MXR_RES_HEIGHT(x) MXR_MASK_VAL(x, 26, 16)
#define MXR_MXR_RES_WIDTH(x) MXR_MASK_VAL(x, 10, 0)
/* bits for MXR_GRAPHICn_SXY */
#define MXR_GRP_SXY_SX(x) MXR_MASK_VAL(x, 26, 16)
#define MXR_GRP_SXY_SY(x) MXR_MASK_VAL(x, 10, 0)
/* bits for MXR_GRAPHICn_DXY */
#define MXR_GRP_DXY_DX(x) MXR_MASK_VAL(x, 26, 16)
#define MXR_GRP_DXY_DY(x) MXR_MASK_VAL(x, 10, 0)
/* bits for MXR_INT_EN */
#define MXR_INT_EN_VSYNC (1 << 11)
#define MXR_INT_EN_ALL (0x0f << 8)
/* bit for MXR_INT_STATUS */
#define MXR_INT_CLEAR_VSYNC (1 << 11)
#define MXR_INT_STATUS_VSYNC (1 << 0)
/* bit for MXR_LAYER_CFG */
#define MXR_LAYER_CFG_GRP1_VAL(x) MXR_MASK_VAL(x, 11, 8)
#define MXR_LAYER_CFG_GRP0_VAL(x) MXR_MASK_VAL(x, 7, 4)
#define MXR_LAYER_CFG_VP_VAL(x) MXR_MASK_VAL(x, 3, 0)
#endif /* SAMSUNG_REGS_MIXER_H */

View file

@ -0,0 +1,73 @@
/* drivers/gpu/drm/exynos/regs-rotator.h
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Register definition file for Samsung Rotator Interface (Rotator) 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 EXYNOS_REGS_ROTATOR_H
#define EXYNOS_REGS_ROTATOR_H
/* Configuration */
#define ROT_CONFIG 0x00
#define ROT_CONFIG_IRQ (3 << 8)
/* Image Control */
#define ROT_CONTROL 0x10
#define ROT_CONTROL_PATTERN_WRITE (1 << 16)
#define ROT_CONTROL_FMT_YCBCR420_2P (1 << 8)
#define ROT_CONTROL_FMT_RGB888 (6 << 8)
#define ROT_CONTROL_FMT_MASK (7 << 8)
#define ROT_CONTROL_FLIP_VERTICAL (2 << 6)
#define ROT_CONTROL_FLIP_HORIZONTAL (3 << 6)
#define ROT_CONTROL_FLIP_MASK (3 << 6)
#define ROT_CONTROL_ROT_90 (1 << 4)
#define ROT_CONTROL_ROT_180 (2 << 4)
#define ROT_CONTROL_ROT_270 (3 << 4)
#define ROT_CONTROL_ROT_MASK (3 << 4)
#define ROT_CONTROL_START (1 << 0)
/* Status */
#define ROT_STATUS 0x20
#define ROT_STATUS_IRQ_PENDING(x) (1 << (x))
#define ROT_STATUS_IRQ(x) (((x) >> 8) & 0x3)
#define ROT_STATUS_IRQ_VAL_COMPLETE 1
#define ROT_STATUS_IRQ_VAL_ILLEGAL 2
/* Buffer Address */
#define ROT_SRC_BUF_ADDR(n) (0x30 + ((n) << 2))
#define ROT_DST_BUF_ADDR(n) (0x50 + ((n) << 2))
/* Buffer Size */
#define ROT_SRC_BUF_SIZE 0x3c
#define ROT_DST_BUF_SIZE 0x5c
#define ROT_SET_BUF_SIZE_H(x) ((x) << 16)
#define ROT_SET_BUF_SIZE_W(x) ((x) << 0)
#define ROT_GET_BUF_SIZE_H(x) ((x) >> 16)
#define ROT_GET_BUF_SIZE_W(x) ((x) & 0xffff)
/* Crop Position */
#define ROT_SRC_CROP_POS 0x40
#define ROT_DST_CROP_POS 0x60
#define ROT_CROP_POS_Y(x) ((x) << 16)
#define ROT_CROP_POS_X(x) ((x) << 0)
/* Source Crop Size */
#define ROT_SRC_CROP_SIZE 0x44
#define ROT_SRC_CROP_SIZE_H(x) ((x) << 16)
#define ROT_SRC_CROP_SIZE_W(x) ((x) << 0)
/* Round to nearest aligned value */
#define ROT_ALIGN(x, align, mask) (((x) + (1 << ((align) - 1))) & (mask))
/* Minimum limit value */
#define ROT_MIN(min, mask) (((min) + ~(mask)) & (mask))
/* Maximum limit value */
#define ROT_MAX(max, mask) ((max) & (mask))
#endif /* EXYNOS_REGS_ROTATOR_H */

View file

@ -0,0 +1,91 @@
/*
*
* Cloned from drivers/media/video/s5p-tv/regs-vp.h
*
* Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Video processor register header file for Samsung Mixer 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_REGS_VP_H
#define SAMSUNG_REGS_VP_H
/*
* Register part
*/
#define VP_ENABLE 0x0000
#define VP_SRESET 0x0004
#define VP_SHADOW_UPDATE 0x0008
#define VP_FIELD_ID 0x000C
#define VP_MODE 0x0010
#define VP_IMG_SIZE_Y 0x0014
#define VP_IMG_SIZE_C 0x0018
#define VP_PER_RATE_CTRL 0x001C
#define VP_TOP_Y_PTR 0x0028
#define VP_BOT_Y_PTR 0x002C
#define VP_TOP_C_PTR 0x0030
#define VP_BOT_C_PTR 0x0034
#define VP_ENDIAN_MODE 0x03CC
#define VP_SRC_H_POSITION 0x0044
#define VP_SRC_V_POSITION 0x0048
#define VP_SRC_WIDTH 0x004C
#define VP_SRC_HEIGHT 0x0050
#define VP_DST_H_POSITION 0x0054
#define VP_DST_V_POSITION 0x0058
#define VP_DST_WIDTH 0x005C
#define VP_DST_HEIGHT 0x0060
#define VP_H_RATIO 0x0064
#define VP_V_RATIO 0x0068
#define VP_POLY8_Y0_LL 0x006C
#define VP_POLY4_Y0_LL 0x00EC
#define VP_POLY4_C0_LL 0x012C
/*
* Bit definition part
*/
/* generates mask for range of bits */
#define VP_MASK(high_bit, low_bit) \
(((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
#define VP_MASK_VAL(val, high_bit, low_bit) \
(((val) << (low_bit)) & VP_MASK(high_bit, low_bit))
/* VP_ENABLE */
#define VP_ENABLE_ON (1 << 0)
/* VP_SRESET */
#define VP_SRESET_PROCESSING (1 << 0)
/* VP_SHADOW_UPDATE */
#define VP_SHADOW_UPDATE_ENABLE (1 << 0)
/* VP_MODE */
#define VP_MODE_NV12 (0 << 6)
#define VP_MODE_NV21 (1 << 6)
#define VP_MODE_LINE_SKIP (1 << 5)
#define VP_MODE_MEM_LINEAR (0 << 4)
#define VP_MODE_MEM_TILED (1 << 4)
#define VP_MODE_FMT_MASK (5 << 4)
#define VP_MODE_FIELD_ID_AUTO_TOGGLING (1 << 2)
#define VP_MODE_2D_IPC (1 << 1)
/* VP_IMG_SIZE_Y */
/* VP_IMG_SIZE_C */
#define VP_IMG_HSIZE(x) VP_MASK_VAL(x, 29, 16)
#define VP_IMG_VSIZE(x) VP_MASK_VAL(x, 13, 0)
/* VP_SRC_H_POSITION */
#define VP_SRC_H_POSITION_VAL(x) VP_MASK_VAL(x, 14, 4)
/* VP_ENDIAN_MODE */
#define VP_ENDIAN_MODE_LITTLE (1 << 0)
#endif /* SAMSUNG_REGS_VP_H */