mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-09 01:28:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
100
drivers/gpu/drm/exynos/Kconfig
Normal file
100
drivers/gpu/drm/exynos/Kconfig
Normal 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.
|
25
drivers/gpu/drm/exynos/Makefile
Normal file
25
drivers/gpu/drm/exynos/Makefile
Normal 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
|
1453
drivers/gpu/drm/exynos/exynos_dp_core.c
Normal file
1453
drivers/gpu/drm/exynos/exynos_dp_core.c
Normal file
File diff suppressed because it is too large
Load diff
280
drivers/gpu/drm/exynos/exynos_dp_core.h
Normal file
280
drivers/gpu/drm/exynos/exynos_dp_core.h
Normal 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 */
|
1263
drivers/gpu/drm/exynos/exynos_dp_reg.c
Normal file
1263
drivers/gpu/drm/exynos/exynos_dp_reg.c
Normal file
File diff suppressed because it is too large
Load diff
366
drivers/gpu/drm/exynos/exynos_dp_reg.h
Normal file
366
drivers/gpu/drm/exynos/exynos_dp_reg.h
Normal 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 */
|
186
drivers/gpu/drm/exynos/exynos_drm_buf.c
Normal file
186
drivers/gpu/drm/exynos/exynos_drm_buf.c
Normal 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);
|
||||
}
|
33
drivers/gpu/drm/exynos/exynos_drm_buf.h
Normal file
33
drivers/gpu/drm/exynos/exynos_drm_buf.h
Normal 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
|
245
drivers/gpu/drm/exynos/exynos_drm_connector.c
Normal file
245
drivers/gpu/drm/exynos/exynos_drm_connector.c
Normal 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;
|
||||
}
|
20
drivers/gpu/drm/exynos/exynos_drm_connector.h
Normal file
20
drivers/gpu/drm/exynos/exynos_drm_connector.h
Normal 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
|
161
drivers/gpu/drm/exynos/exynos_drm_core.c
Normal file
161
drivers/gpu/drm/exynos/exynos_drm_core.c
Normal 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);
|
524
drivers/gpu/drm/exynos/exynos_drm_crtc.c
Normal file
524
drivers/gpu/drm/exynos/exynos_drm_crtc.c
Normal 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);
|
||||
}
|
46
drivers/gpu/drm/exynos/exynos_drm_crtc.h
Normal file
46
drivers/gpu/drm/exynos/exynos_drm_crtc.h
Normal 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
|
285
drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
Normal file
285
drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
Normal 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");
|
25
drivers/gpu/drm/exynos/exynos_drm_dmabuf.h
Normal file
25
drivers/gpu/drm/exynos/exynos_drm_dmabuf.h
Normal 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
|
351
drivers/gpu/drm/exynos/exynos_drm_dpi.c
Normal file
351
drivers/gpu/drm/exynos/exynos_drm_dpi.c
Normal 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;
|
||||
}
|
805
drivers/gpu/drm/exynos/exynos_drm_drv.c
Normal file
805
drivers/gpu/drm/exynos/exynos_drm_drv.c
Normal 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");
|
378
drivers/gpu/drm/exynos/exynos_drm_drv.h
Normal file
378
drivers/gpu/drm/exynos/exynos_drm_drv.h
Normal 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
|
1799
drivers/gpu/drm/exynos/exynos_drm_dsi.c
Normal file
1799
drivers/gpu/drm/exynos/exynos_drm_dsi.c
Normal file
File diff suppressed because it is too large
Load diff
197
drivers/gpu/drm/exynos/exynos_drm_encoder.c
Normal file
197
drivers/gpu/drm/exynos/exynos_drm_encoder.c
Normal 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;
|
||||
}
|
25
drivers/gpu/drm/exynos/exynos_drm_encoder.h
Normal file
25
drivers/gpu/drm/exynos/exynos_drm_encoder.h
Normal 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
|
328
drivers/gpu/drm/exynos/exynos_drm_fb.c
Normal file
328
drivers/gpu/drm/exynos/exynos_drm_fb.c
Normal 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;
|
||||
}
|
35
drivers/gpu/drm/exynos/exynos_drm_fb.h
Normal file
35
drivers/gpu/drm/exynos/exynos_drm_fb.h
Normal 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
|
370
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
Normal file
370
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
Normal 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);
|
||||
}
|
23
drivers/gpu/drm/exynos/exynos_drm_fbdev.h
Normal file
23
drivers/gpu/drm/exynos/exynos_drm_fbdev.h
Normal 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
|
1862
drivers/gpu/drm/exynos/exynos_drm_fimc.c
Normal file
1862
drivers/gpu/drm/exynos/exynos_drm_fimc.c
Normal file
File diff suppressed because it is too large
Load diff
23
drivers/gpu/drm/exynos/exynos_drm_fimc.h
Normal file
23
drivers/gpu/drm/exynos/exynos_drm_fimc.h
Normal 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_ */
|
1227
drivers/gpu/drm/exynos/exynos_drm_fimd.c
Normal file
1227
drivers/gpu/drm/exynos/exynos_drm_fimd.c
Normal file
File diff suppressed because it is too large
Load diff
1587
drivers/gpu/drm/exynos/exynos_drm_g2d.c
Normal file
1587
drivers/gpu/drm/exynos/exynos_drm_g2d.c
Normal file
File diff suppressed because it is too large
Load diff
36
drivers/gpu/drm/exynos/exynos_drm_g2d.h
Normal file
36
drivers/gpu/drm/exynos/exynos_drm_g2d.h
Normal 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
|
651
drivers/gpu/drm/exynos/exynos_drm_gem.c
Normal file
651
drivers/gpu/drm/exynos/exynos_drm_gem.c
Normal 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;
|
||||
}
|
180
drivers/gpu/drm/exynos/exynos_drm_gem.h
Normal file
180
drivers/gpu/drm/exynos/exynos_drm_gem.h
Normal 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
|
1801
drivers/gpu/drm/exynos/exynos_drm_gsc.c
Normal file
1801
drivers/gpu/drm/exynos/exynos_drm_gsc.c
Normal file
File diff suppressed because it is too large
Load diff
24
drivers/gpu/drm/exynos/exynos_drm_gsc.h
Normal file
24
drivers/gpu/drm/exynos/exynos_drm_gsc.h
Normal 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_ */
|
143
drivers/gpu/drm/exynos/exynos_drm_iommu.c
Normal file
143
drivers/gpu/drm/exynos/exynos_drm_iommu.c
Normal 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);
|
||||
}
|
70
drivers/gpu/drm/exynos/exynos_drm_iommu.h
Normal file
70
drivers/gpu/drm/exynos/exynos_drm_iommu.h
Normal 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
|
1775
drivers/gpu/drm/exynos/exynos_drm_ipp.c
Normal file
1775
drivers/gpu/drm/exynos/exynos_drm_ipp.c
Normal file
File diff suppressed because it is too large
Load diff
252
drivers/gpu/drm/exynos/exynos_drm_ipp.h
Normal file
252
drivers/gpu/drm/exynos/exynos_drm_ipp.h
Normal 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_ */
|
||||
|
282
drivers/gpu/drm/exynos/exynos_drm_plane.c
Normal file
282
drivers/gpu/drm/exynos/exynos_drm_plane.c
Normal 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;
|
||||
}
|
21
drivers/gpu/drm/exynos/exynos_drm_plane.h
Normal file
21
drivers/gpu/drm/exynos/exynos_drm_plane.h
Normal 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);
|
856
drivers/gpu/drm/exynos/exynos_drm_rotator.c
Normal file
856
drivers/gpu/drm/exynos/exynos_drm_rotator.c
Normal 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,
|
||||
},
|
||||
};
|
19
drivers/gpu/drm/exynos/exynos_drm_rotator.h
Normal file
19
drivers/gpu/drm/exynos/exynos_drm_rotator.h
Normal 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
|
679
drivers/gpu/drm/exynos/exynos_drm_vidi.c
Normal file
679
drivers/gpu/drm/exynos/exynos_drm_vidi.c
Normal 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);
|
||||
}
|
22
drivers/gpu/drm/exynos/exynos_drm_vidi.h
Normal file
22
drivers/gpu/drm/exynos/exynos_drm_vidi.h
Normal 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
|
2539
drivers/gpu/drm/exynos/exynos_hdmi.c
Normal file
2539
drivers/gpu/drm/exynos/exynos_hdmi.c
Normal file
File diff suppressed because it is too large
Load diff
1351
drivers/gpu/drm/exynos/exynos_mixer.c
Normal file
1351
drivers/gpu/drm/exynos/exynos_mixer.c
Normal file
File diff suppressed because it is too large
Load diff
20
drivers/gpu/drm/exynos/exynos_mixer.h
Normal file
20
drivers/gpu/drm/exynos/exynos_mixer.h
Normal 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
|
668
drivers/gpu/drm/exynos/regs-fimc.h
Normal file
668
drivers/gpu/drm/exynos/regs-fimc.h
Normal 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 */
|
284
drivers/gpu/drm/exynos/regs-gsc.h
Normal file
284
drivers/gpu/drm/exynos/regs-gsc.h
Normal 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_ */
|
597
drivers/gpu/drm/exynos/regs-hdmi.h
Normal file
597
drivers/gpu/drm/exynos/regs-hdmi.h
Normal 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 */
|
152
drivers/gpu/drm/exynos/regs-mixer.h
Normal file
152
drivers/gpu/drm/exynos/regs-mixer.h
Normal 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 */
|
||||
|
73
drivers/gpu/drm/exynos/regs-rotator.h
Normal file
73
drivers/gpu/drm/exynos/regs-rotator.h
Normal 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 */
|
||||
|
91
drivers/gpu/drm/exynos/regs-vp.h
Normal file
91
drivers/gpu/drm/exynos/regs-vp.h
Normal 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 */
|
Loading…
Add table
Add a link
Reference in a new issue