mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 14:42:37 +02:00
rk3288 chromium: drm grafic fb support for x11 mali gpu
This commit is contained in:
parent
b21384df76
commit
bdafdac384
|
|
@ -201,6 +201,8 @@ config DRM_SAVAGE
|
|||
|
||||
source "drivers/gpu/drm/exynos/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/rockchip/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/vmwgfx/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/gma500/Kconfig"
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
|
|||
obj-$(CONFIG_DRM_VIA) +=via/
|
||||
obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
|
||||
obj-$(CONFIG_DRM_EXYNOS) +=exynos/
|
||||
obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
|
||||
obj-$(CONFIG_DRM_GMA500) += gma500/
|
||||
obj-$(CONFIG_DRM_UDL) += udl/
|
||||
obj-$(CONFIG_DRM_AST) += ast/
|
||||
|
|
|
|||
|
|
@ -3461,7 +3461,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fb->pixel_format = crtc->fb->pixel_format;
|
||||
if (crtc->fb->pixel_format != fb->pixel_format) {
|
||||
DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
|
||||
ret = -EINVAL;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
#include <drm/drmP.h>
|
||||
#include <drm/drm_core.h>
|
||||
|
||||
unsigned int drm_debug = 0; /* 1 to enable debug output */
|
||||
unsigned int drm_debug = 0xf; /* 1 to enable debug output */
|
||||
EXPORT_SYMBOL(drm_debug);
|
||||
|
||||
unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */
|
||||
|
|
|
|||
54
drivers/gpu/drm/rockchip/Kconfig
Normal file
54
drivers/gpu/drm/rockchip/Kconfig
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
config DRM_ROCKCHIP
|
||||
tristate "DRM Support for ROCKCHIP "
|
||||
depends on DRM && ARCH_MULTIPLATFORM
|
||||
select DRM_KMS_HELPER
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
|
||||
help
|
||||
Choose this option if you have a ROCKCHIP soc chipset.
|
||||
If M is selected the module will be called rockchipdrm.
|
||||
|
||||
config DRM_ROCKCHIP_IOMMU
|
||||
bool "ROCKCHIP DRM IOMMU Support"
|
||||
depends on DRM_ROCKCHIP && ARM_DMA_USE_IOMMU
|
||||
help
|
||||
Choose this option if you want to use IOMMU feature for DRM.
|
||||
|
||||
config DRM_ROCKCHIP_DMABUF
|
||||
bool "ROCKCHIP DRM DMABUF"
|
||||
depends on DRM_ROCKCHIP
|
||||
help
|
||||
Choose this option if you want to use DMABUF feature for DRM.
|
||||
|
||||
config DRM_RK3188_FIMD
|
||||
bool "RK3188 DRM FIMD"
|
||||
depends on OF && DRM_ROCKCHIP
|
||||
select FB_MODE_HELPERS
|
||||
select VIDEOMODE_HELPERS
|
||||
help
|
||||
Choose this option if you want to use Rockchip FIMD for DRM.
|
||||
|
||||
config DRM_RK3288_FIMD
|
||||
bool "RK3288 DRM FIMD"
|
||||
depends on OF && DRM_ROCKCHIP
|
||||
select FB_MODE_HELPERS
|
||||
select VIDEOMODE_HELPERS
|
||||
help
|
||||
Choose this option if you want to use Rockchip FIMD for DRM.
|
||||
|
||||
|
||||
config DRM_ROCKCHIP_HDMI
|
||||
bool "Rockchip DRM HDMI"
|
||||
depends on DRM_ROCKCHIP
|
||||
help
|
||||
Choose this option if you want to use Rockchip HDMI for DRM.
|
||||
|
||||
config DRM_ROCKCHIP_VIDI
|
||||
bool "Rockchip DRM Virtual Display"
|
||||
depends on DRM_ROCKCHIP
|
||||
help
|
||||
Choose this option if you want to use rockchip VIDI for DRM.
|
||||
|
||||
source "drivers/gpu/drm/rockchip/screen/Kconfig"
|
||||
22
drivers/gpu/drm/rockchip/Makefile
Normal file
22
drivers/gpu/drm/rockchip/Makefile
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# 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/rockchip
|
||||
rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_encoder.o rockchip_drm_connector.o \
|
||||
rockchip_drm_crtc.o rockchip_drm_fbdev.o rockchip_drm_fb.o \
|
||||
rockchip_drm_buf.o rockchip_drm_gem.o rockchip_drm_core.o \
|
||||
rockchip_drm_plane.o
|
||||
|
||||
rockchipdrm-$(CONFIG_DRM_ROCKCHIP_IOMMU) += rockchip_drm_iommu.o
|
||||
rockchipdrm-$(CONFIG_DRM_ROCKCHIP_DMABUF) += rockchip_drm_dmabuf.o
|
||||
rockchipdrm-$(CONFIG_DRM_RK3188_FIMD) += rk3188_drm_fimd.o
|
||||
rockchipdrm-$(CONFIG_DRM_RK3288_FIMD) += rk3288_drm_fimd.o
|
||||
rockchipdrm-$(CONFIG_DRM_ROCKCHIP_HDMI) += rockchip_hdmi.o rockchip_mixer.o \
|
||||
rockchip_ddc.o rockchip_hdmiphy.o \
|
||||
rockchip_drm_hdmi.o
|
||||
rockchipdrm-$(CONFIG_DRM_ROCKCHIP_VIDI) += rockchip_drm_vidi.o
|
||||
|
||||
obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o
|
||||
obj-y += screen/
|
||||
obj-y += transmitter/
|
||||
1170
drivers/gpu/drm/rockchip/rk3188_drm_fimd.c
Normal file
1170
drivers/gpu/drm/rockchip/rk3188_drm_fimd.c
Normal file
File diff suppressed because it is too large
Load Diff
386
drivers/gpu/drm/rockchip/rk3188_drm_fimd.h
Normal file
386
drivers/gpu/drm/rockchip/rk3188_drm_fimd.h
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
/********************************************************************
|
||||
** display output interface supported by rockchip lcdc *
|
||||
********************************************************************/
|
||||
/* */
|
||||
#define OUT_P888 0 //24bit screen,connect to lcdc D0~D23
|
||||
#define OUT_P666 1 //18bit screen,connect to lcdc D0~D17
|
||||
#define OUT_P565 2
|
||||
#define OUT_S888x 4
|
||||
#define OUT_CCIR656 6
|
||||
#define OUT_S888 8
|
||||
#define OUT_S888DUMY 12
|
||||
#define OUT_RGB_AAA 15
|
||||
#define OUT_P16BPP4 24
|
||||
#define OUT_D888_P666 0x21 //18bit screen,connect to lcdc D2~D7, D10~D15, D18~D23
|
||||
#define OUT_D888_P565 0x22
|
||||
|
||||
/*******************register definition**********************/
|
||||
|
||||
#define SYS_CTRL (0x00)
|
||||
#define m_WIN0_EN (1<<0)
|
||||
#define m_WIN1_EN (1<<1)
|
||||
#define m_HWC_EN (1<<2)
|
||||
#define m_WIN0_FORMAT (7<<3)
|
||||
#define m_WIN1_FORMAT (7<<6)
|
||||
#define m_HWC_COLOR_MODE (1<<9)
|
||||
#define m_HWC_SIZE (1<<10)
|
||||
#define m_WIN0_3D_EN (1<<11)
|
||||
#define m_WIN0_3D_MODE (7<<12)
|
||||
#define m_WIN0_RB_SWAP (1<<15)
|
||||
#define m_WIN0_ALPHA_SWAP (1<<16)
|
||||
#define m_WIN0_Y8_SWAP (1<<17)
|
||||
#define m_WIN0_UV_SWAP (1<<18)
|
||||
#define m_WIN1_RB_SWAP (1<<19)
|
||||
#define m_WIN1_ALPHA_SWAP (1<<20)
|
||||
#define m_WIN1_BL_SWAP (1<<21)
|
||||
#define m_WIN0_OTSD_DISABLE (1<<22)
|
||||
#define m_WIN1_OTSD_DISABLE (1<<23)
|
||||
#define m_DMA_BURST_LENGTH (3<<24)
|
||||
#define m_HWC_LODAD_EN (1<<26)
|
||||
#define m_WIN1_LUT_EN (1<<27)
|
||||
#define m_DSP_LUT_EN (1<<28)
|
||||
#define m_DMA_STOP (1<<29)
|
||||
#define m_LCDC_STANDBY (1<<30)
|
||||
#define m_AUTO_GATING_EN (1<<31)
|
||||
#define v_WIN0_EN(x) (((x)&1)<<0)
|
||||
#define v_WIN1_EN(x) (((x)&1)<<1)
|
||||
#define v_HWC_EN(x) (((x)&1)<<2)
|
||||
#define v_WIN0_FORMAT(x) (((x)&7)<<3)
|
||||
#define v_WIN1_FORMAT(x) (((x)&7)<<6)
|
||||
#define v_HWC_COLOR_MODE(x) (((x)&1)<<9)
|
||||
#define v_HWC_SIZE(x) (((x)&1)<<10)
|
||||
#define v_WIN0_3D_EN(x) (((x)&1)<<11)
|
||||
#define v_WIN0_3D_MODE(x) (((x)&7)<<12)
|
||||
#define v_WIN0_RB_SWAP(x) (((x)&1)<<15)
|
||||
#define v_WIN0_ALPHA_SWAP(x) (((x)&1)<<16)
|
||||
#define v_WIN0_Y8_SWAP(x) (((x)&1)<<17)
|
||||
#define v_WIN0_UV_SWAP(x) (((x)&1)<<18)
|
||||
#define v_WIN1_RB_SWAP(x) (((x)&1)<<19)
|
||||
#define v_WIN1_ALPHA_SWAP(x) (((x)&1)<<20)
|
||||
#define v_WIN1_BL_SWAP(x) (((x)&1)<<21)
|
||||
#define v_WIN0_OTSD_DISABLE(x) (((x)&1)<<22)
|
||||
#define v_WIN1_OTSD_DISABLE(x) (((x)&1)<<23)
|
||||
#define v_DMA_BURST_LENGTH(x) (((x)&3)<<24)
|
||||
#define v_HWC_LODAD_EN(x) (((x)&1)<<26)
|
||||
#define v_WIN1_LUT_EN(x) (((x)&1)<<27)
|
||||
#define v_DSP_LUT_EN(x) (((x)&1)<<28)
|
||||
#define v_DMA_STOP(x) (((x)&1)<<29)
|
||||
#define v_LCDC_STANDBY(x) (((x)&1)<<30)
|
||||
#define v_AUTO_GATING_EN(x) (((x)&1)<<31)
|
||||
|
||||
|
||||
#define DSP_CTRL0 (0x04)
|
||||
#define m_DSP_OUT_FORMAT (0x0f<<0)
|
||||
#define m_HSYNC_POL (1<<4)
|
||||
#define m_VSYNC_POL (1<<5)
|
||||
#define m_DEN_POL (1<<6)
|
||||
#define m_DCLK_POL (1<<7)
|
||||
#define m_WIN0_TOP (1<<8)
|
||||
#define m_DITHER_UP_EN (1<<9)
|
||||
#define m_DITHER_DOWN_MODE (1<<10)
|
||||
#define m_DITHER_DOWN_EN (1<<11)
|
||||
#define m_INTERLACE_DSP_EN (1<<12)
|
||||
#define m_INTERLACE_POL (1<<13)
|
||||
#define m_WIN0_INTERLACE_EN (1<<14)
|
||||
#define m_WIN1_INTERLACE_EN (1<<15)
|
||||
#define m_WIN0_YRGB_DEFLICK_EN (1<<16)
|
||||
#define m_WIN0_CBR_DEFLICK_EN (1<<17)
|
||||
#define m_WIN0_ALPHA_MODE (1<<18)
|
||||
#define m_WIN1_ALPHA_MODE (1<<19)
|
||||
#define m_WIN0_CSC_MODE (3<<20)
|
||||
#define m_WIN1_CSC_MODE (1<<22)
|
||||
#define m_WIN0_YUV_CLIP (1<<23)
|
||||
#define m_DSP_CCIR656_AVG (1<<24)
|
||||
#define m_DCLK_OUTPUT_MODE (1<<25)
|
||||
#define m_DCLK_PHASE_LOCK (1<<26)
|
||||
#define m_DITHER_DOWN_SEL (3<<27)
|
||||
#define m_ALPHA_MODE_SEL0 (1<<29)
|
||||
#define m_ALPHA_MODE_SEL1 (1<<30)
|
||||
#define m_DIFF_DCLK_EN (1<<31)
|
||||
#define v_DSP_OUT_FORMAT(x) (((x)&0x0f)<<0)
|
||||
#define v_HSYNC_POL(x) (((x)&1)<<4)
|
||||
#define v_VSYNC_POL(x) (((x)&1)<<5)
|
||||
#define v_DEN_POL(x) (((x)&1)<<6)
|
||||
#define v_DCLK_POL(x) (((x)&1)<<7)
|
||||
#define v_WIN0_TOP(x) (((x)&1)<<8)
|
||||
#define v_DITHER_UP_EN(x) (((x)&1)<<9)
|
||||
#define v_DITHER_DOWN_MODE(x) (((x)&1)<<10)
|
||||
#define v_DITHER_DOWN_EN(x) (((x)&1)<<11)
|
||||
#define v_INTERLACE_DSP_EN(x) (((x)&1)<<12)
|
||||
#define v_INTERLACE_POL(x) (((x)&1)<<13)
|
||||
#define v_WIN0_INTERLACE_EN(x) (((x)&1)<<14)
|
||||
#define v_WIN1_INTERLACE_EN(x) (((x)&1)<<15)
|
||||
#define v_WIN0_YRGB_DEFLICK_EN(x) (((x)&1)<<16)
|
||||
#define v_WIN0_CBR_DEFLICK_EN(x) (((x)&1)<<17)
|
||||
#define v_WIN0_ALPHA_MODE(x) (((x)&1)<<18)
|
||||
#define v_WIN1_ALPHA_MODE(x) (((x)&1)<<19)
|
||||
#define v_WIN0_CSC_MODE(x) (((x)&3)<<20)
|
||||
#define v_WIN1_CSC_MODE(x) (((x)&1)<<22)
|
||||
#define v_WIN0_YUV_CLIP(x) (((x)&1)<<23)
|
||||
#define v_DSP_CCIR656_AVG(x) (((x)&1)<<24)
|
||||
#define v_DCLK_OUTPUT_MODE(x) (((x)&1)<<25)
|
||||
#define v_DCLK_PHASE_LOCK(x) (((x)&1)<<26)
|
||||
#define v_DITHER_DOWN_SEL(x) (((x)&1)<<27)
|
||||
#define v_ALPHA_MODE_SEL0(x) (((x)&1)<<29)
|
||||
#define v_ALPHA_MODE_SEL1(x) (((x)&1)<<30)
|
||||
#define v_DIFF_DCLK_EN(x) (((x)&1)<<31)
|
||||
|
||||
|
||||
#define DSP_CTRL1 (0x08)
|
||||
#define m_BG_COLOR (0xffffff<<0)
|
||||
#define m_BG_B (0xff<<0)
|
||||
#define m_BG_G (0xff<<8)
|
||||
#define m_BG_R (0xff<<16)
|
||||
#define m_BLANK_EN (1<<24)
|
||||
#define m_BLACK_EN (1<<25)
|
||||
#define m_DSP_BG_SWAP (1<<26)
|
||||
#define m_DSP_RB_SWAP (1<<27)
|
||||
#define m_DSP_RG_SWAP (1<<28)
|
||||
#define m_DSP_DELTA_SWAP (1<<29)
|
||||
#define m_DSP_DUMMY_SWAP (1<<30)
|
||||
#define m_DSP_OUT_ZERO (1<<31)
|
||||
#define v_BG_COLOR(x) (((x)&0xffffff)<<0)
|
||||
#define v_BG_B(x) (((x)&0xff)<<0)
|
||||
#define v_BG_G(x) (((x)&0xff)<<8)
|
||||
#define v_BG_R(x) (((x)&0xff)<<16)
|
||||
#define v_BLANK_EN(x) (((x)&1)<<24)
|
||||
#define v_BLACK_EN(x) (((x)&1)<<25)
|
||||
#define v_DSP_BG_SWAP(x) (((x)&1)<<26)
|
||||
#define v_DSP_RB_SWAP(x) (((x)&1)<<27)
|
||||
#define v_DSP_RG_SWAP(x) (((x)&1)<<28)
|
||||
#define v_DSP_DELTA_SWAP(x) (((x)&1)<<29)
|
||||
#define v_DSP_DUMMY_SWAP(x) (((x)&1)<<30)
|
||||
#define v_DSP_OUT_ZERO(x) (((x)&1)<<31)
|
||||
|
||||
|
||||
#define MCU_CTRL (0x0c)
|
||||
#define m_MCU_PIX_TOTAL (0x3f<<0)
|
||||
#define m_MCU_CS_ST (0x0f<<6)
|
||||
#define m_MCU_CS_END (0x3f<<10)
|
||||
#define m_MCU_RW_ST (0x0f<<16)
|
||||
#define m_MCU_RW_END (0x3f<<20)
|
||||
#define m_MCU_CLK_SEL (1<<26)
|
||||
#define m_MCU_HOLD_MODE (1<<27)
|
||||
#define m_MCU_FS_HOLD_STA (1<<28)
|
||||
#define m_MCU_RS_SELECT (1<<29)
|
||||
#define m_MCU_BYPASS (1<<30)
|
||||
#define m_MCU_TYPE (1<<31)
|
||||
|
||||
#define v_MCU_PIX_TOTAL(x) (((x)&0x3f)<<0)
|
||||
#define v_MCU_CS_ST(x) (((x)&0x0f)<<6)
|
||||
#define v_MCU_CS_END(x) (((x)&0x3f)<<10)
|
||||
#define v_MCU_RW_ST(x) (((x)&0x0f)<<16)
|
||||
#define v_MCU_RW_END(x) (((x)&0x3f)<<20)
|
||||
#define v_MCU_CLK_SEL(x) (((x)&1)<<26)
|
||||
#define v_MCU_HOLD_MODE(x) (((x)&1)<<27)
|
||||
#define v_MCU_FS_HOLD_STA(x) (((x)&1)<<28)
|
||||
#define v_MCU_RS_SELECT(x) (((x)&1)<<29)
|
||||
#define v_MCU_BYPASS(x) (((x)&1)<<30)
|
||||
#define v_MCU_TYPE(x) (((x)&1)<<31)
|
||||
|
||||
#define INT_STATUS (0x10)
|
||||
#define m_HS_INT_STA (1<<0) //status
|
||||
#define m_FS_INT_STA (1<<1)
|
||||
#define m_LF_INT_STA (1<<2)
|
||||
#define m_BUS_ERR_INT_STA (1<<3)
|
||||
#define m_HS_INT_EN (1<<4) //enable
|
||||
#define m_FS_INT_EN (1<<5)
|
||||
#define m_LF_INT_EN (1<<6)
|
||||
#define m_BUS_ERR_INT_EN (1<<7)
|
||||
#define m_HS_INT_CLEAR (1<<8) //auto clear
|
||||
#define m_FS_INT_CLEAR (1<<9)
|
||||
#define m_LF_INT_CLEAR (1<<10)
|
||||
#define m_BUS_ERR_INT_CLEAR (1<<11)
|
||||
#define m_LF_INT_NUM (0xfff<<12)
|
||||
#define v_HS_INT_EN(x) (((x)&1)<<4)
|
||||
#define v_FS_INT_EN(x) (((x)&1)<<5)
|
||||
#define v_LF_INT_EN(x) (((x)&1)<<6)
|
||||
#define v_BUS_ERR_INT_EN(x) (((x)&1)<<7)
|
||||
#define v_HS_INT_CLEAR(x) (((x)&1)<<8)
|
||||
#define v_FS_INT_CLEAR(x) (((x)&1)<<9)
|
||||
#define v_LF_INT_CLEAR(x) (((x)&1)<<10)
|
||||
#define v_BUS_ERR_INT_CLEAR(x) (((x)&1)<<11)
|
||||
#define v_LF_INT_NUM(x) (((x)&0xfff)<<12)
|
||||
|
||||
|
||||
#define ALPHA_CTRL (0x14)
|
||||
#define m_WIN0_ALPHA_EN (1<<0)
|
||||
#define m_WIN1_ALPHA_EN (1<<1)
|
||||
#define m_HWC_ALPAH_EN (1<<2)
|
||||
#define m_WIN0_ALPHA_VAL (0xff<<4)
|
||||
#define m_WIN1_ALPHA_VAL (0xff<<12)
|
||||
#define m_HWC_ALPAH_VAL (0x0f<<20)
|
||||
#define v_WIN0_ALPHA_EN(x) (((x)&1)<<0)
|
||||
#define v_WIN1_ALPHA_EN(x) (((x)&1)<<1)
|
||||
#define v_HWC_ALPAH_EN(x) (((x)&1)<<2)
|
||||
#define v_WIN0_ALPHA_VAL(x) (((x)&0xff)<<4)
|
||||
#define v_WIN1_ALPHA_VAL(x) (((x)&0xff)<<12)
|
||||
#define v_HWC_ALPAH_VAL(x) (((x)&0x0f)<<20)
|
||||
|
||||
#define WIN0_COLOR_KEY (0x18)
|
||||
#define m_COLOR_KEY_VAL (0xffffff<<0)
|
||||
#define m_COLOR_KEY_EN (1<<24)
|
||||
#define v_COLOR_KEY_VAL(x) (((x)&0xffffff)<<0)
|
||||
#define v_COLOR_KEY_EN(x) (((x)&1)<<24)
|
||||
|
||||
#define WIN1_COLOR_KEY (0x1C)
|
||||
|
||||
|
||||
#define WIN0_YRGB_MST0 (0x20)
|
||||
#define WIN0_CBR_MST0 (0x24)
|
||||
#define WIN0_YRGB_MST1 (0x28)
|
||||
#define WIN0_CBR_MST1 (0x2C)
|
||||
#define WIN_VIR (0x30)
|
||||
#define m_WIN0_VIR (0x1fff << 0)
|
||||
#define m_WIN1_VIR (0x1fff << 16)
|
||||
#define v_WIN0_VIR_VAL(x) ((x)<<0)
|
||||
#define v_WIN1_VIR_VAL(x) ((x)<<16)
|
||||
#define v_ARGB888_VIRWIDTH(x) (((x)&0x1fff)<<0)
|
||||
#define v_RGB888_VIRWIDTH(x) (((((x*3)>>2)+((x)%3))&0x1fff)<<0)
|
||||
#define v_RGB565_VIRWIDTH(x) ((DIV_ROUND_UP(x,2)&0x1fff)<<0)
|
||||
#define v_YUV_VIRWIDTH(x) ((DIV_ROUND_UP(x,4)&0x1fff)<<0)
|
||||
#define v_WIN1_ARGB888_VIRWIDTH(x) (((x)&0x1fff)<<16)
|
||||
#define v_WIN1_RGB888_VIRWIDTH(x) (((((x*3)>>2)+((x)%3))&0x1fff)<<16)
|
||||
#define v_WIN1_RGB565_VIRWIDTH(x) ((DIV_ROUND_UP(x,2)&0x1fff)<<16)
|
||||
|
||||
|
||||
|
||||
#define WIN0_ACT_INFO (0x34)
|
||||
#define m_ACT_WIDTH (0x1fff<<0)
|
||||
#define m_ACT_HEIGHT (0x1fff<<16)
|
||||
#define v_ACT_WIDTH(x) (((x-1)&0x1fff)<<0)
|
||||
#define v_ACT_HEIGHT(x) (((x-1)&0x1fff)<<16)
|
||||
|
||||
#define WIN0_DSP_INFO (0x38)
|
||||
#define v_DSP_WIDTH(x) (((x-1)&0x7ff)<<0)
|
||||
#define v_DSP_HEIGHT(x) (((x-1)&0x7ff)<<16)
|
||||
|
||||
#define WIN0_DSP_ST (0x3C)
|
||||
#define v_DSP_STX(x) (((x)&0xfff)<<0)
|
||||
#define v_DSP_STY(x) (((x)&0xfff)<<16)
|
||||
|
||||
#define WIN0_SCL_FACTOR_YRGB (0x40)
|
||||
#define v_X_SCL_FACTOR(x) (((x)&0xffff)<<0)
|
||||
#define v_Y_SCL_FACTOR(x) (((x)&0xffff)<<16)
|
||||
|
||||
#define WIN0_SCL_FACTOR_CBR (0x44)
|
||||
#define WIN0_SCL_OFFSET (0x48)
|
||||
#define WIN1_MST (0x4C)
|
||||
#define WIN1_DSP_INFO (0x50)
|
||||
#define WIN1_DSP_ST (0x54)
|
||||
#define HWC_MST (0x58)
|
||||
#define HWC_DSP_ST (0x5C)
|
||||
#define HWC_COLOR_LUT0 (0x60)
|
||||
#define HWC_COLOR_LUT1 (0x64)
|
||||
#define HWC_COLOR_LUT2 (0x68)
|
||||
#define DSP_HTOTAL_HS_END (0x6C)
|
||||
#define v_HSYNC(x) (((x)&0xfff)<<0) //hsync pulse width
|
||||
#define v_HORPRD(x) (((x)&0xfff)<<16) //horizontal period
|
||||
|
||||
#define DSP_HACT_ST_END (0x70)
|
||||
#define v_HAEP(x) (((x)&0xfff)<<0) //horizontal active end point
|
||||
#define v_HASP(x) (((x)&0xfff)<<16) //horizontal active start point
|
||||
|
||||
#define DSP_VTOTAL_VS_END (0x74)
|
||||
#define v_VSYNC(x) (((x)&0xfff)<<0)
|
||||
#define v_VERPRD(x) (((x)&0xfff)<<16)
|
||||
#define DSP_VACT_ST_END (0x78)
|
||||
#define v_VAEP(x) (((x)&0xfff)<<0)
|
||||
#define v_VASP(x) (((x)&0xfff)<<16)
|
||||
|
||||
#define DSP_VS_ST_END_F1 (0x7C)
|
||||
#define DSP_VACT_ST_END_F1 (0x80)
|
||||
#define REG_CFG_DONE (0x90)
|
||||
#define MCU_BYPASS_WPORT (0x100)
|
||||
#define MCU_BYPASS_RPORT (0x200)
|
||||
#define WIN1_LUT_ADDR (0x400)
|
||||
#define DSP_LUT_ADDR (0x800)
|
||||
|
||||
/*
|
||||
RK3026/RK3028A max output resolution 1920x1080
|
||||
support IEP instead of 3d
|
||||
*/
|
||||
//#ifdef CONFIG_ARCH_RK3026
|
||||
//SYS_CTRL 0x00
|
||||
#define m_DIRECT_PATCH_EN (1<<11)
|
||||
#define m_DIRECT_PATH_LAY_SEL (1<<12)
|
||||
|
||||
#define v_DIRECT_PATCH_EN(x) (((x)&1)<<11)
|
||||
#define v_DIRECT_PATH_LAY_SEL(x) (((x)&1)<<12)
|
||||
|
||||
//INT_STATUS 0x10
|
||||
#define m_WIN0_EMPTY_INTR_EN (1<<24)
|
||||
#define m_WIN1_EMPTY_INTR_EN (1<<25)
|
||||
#define m_WIN0_EMPTY_INTR_CLR (1<<26)
|
||||
#define m_WIN1_EMPTY_INTR_CLR (1<<27)
|
||||
#define m_WIN0_EMPTY_INTR_STA (1<<28)
|
||||
#define m_WIN1_EMPTY_INTR_STA (1<<29)
|
||||
|
||||
#define v_WIN0_EMPTY_INTR_EN(x) (((x)&1)<<24)
|
||||
#define v_WIN1_EMPTY_INTR_EN(x) (((x)&1)<<25)
|
||||
#define v_WIN0_EMPTY_INTR_CLR(x) (((x)&1)<<26)
|
||||
#define v_WIN1_EMPTY_INTR_CLR(x) (((x)&1)<<27)
|
||||
#define v_WIN0_EMPTY_INTR_STA(x) (((x)&1)<<28)
|
||||
#define v_WIN1_EMPTY_INTR_STA(x) (((x)&1)<<29)
|
||||
//#endif
|
||||
|
||||
|
||||
#define CalScale(x, y) ((((u32)(x-1))*0x1000)/(y-1))
|
||||
|
||||
static inline void lcdc_writel(struct fimd_context *ctx,u32 offset,u32 v)
|
||||
{
|
||||
u32 *_pv = (u32*)ctx->regsbak;
|
||||
_pv += (offset >> 2);
|
||||
*_pv = v;
|
||||
writel_relaxed(v,ctx->regs+offset);
|
||||
}
|
||||
|
||||
static inline u32 lcdc_readl(struct fimd_context *ctx,u32 offset)
|
||||
{
|
||||
u32 v;
|
||||
u32 *_pv = (u32*)ctx->regsbak;
|
||||
_pv += (offset >> 2);
|
||||
v = readl_relaxed(ctx->regs+offset);
|
||||
*_pv = v;
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline u32 lcdc_read_bit(struct fimd_context *ctx,u32 offset,u32 msk)
|
||||
{
|
||||
u32 _v = readl_relaxed(ctx->regs+offset);
|
||||
_v &= msk;
|
||||
return (_v >> msk);
|
||||
}
|
||||
|
||||
static inline void lcdc_set_bit(struct fimd_context *ctx,u32 offset,u32 msk)
|
||||
{
|
||||
u32* _pv = (u32*)ctx->regsbak;
|
||||
_pv += (offset >> 2);
|
||||
(*_pv) |= msk;
|
||||
writel_relaxed(*_pv,ctx->regs + offset);
|
||||
}
|
||||
|
||||
static inline void lcdc_clr_bit(struct fimd_context *ctx,u32 offset,u32 msk)
|
||||
{
|
||||
u32* _pv = (u32*)ctx->regsbak;
|
||||
_pv += (offset >> 2);
|
||||
(*_pv) &= (~msk);
|
||||
writel_relaxed(*_pv,ctx->regs + offset);
|
||||
}
|
||||
|
||||
static inline void lcdc_msk_reg(struct fimd_context *ctx,u32 offset,u32 msk,u32 v)
|
||||
{
|
||||
u32 *_pv = (u32*)ctx->regsbak;
|
||||
_pv += (offset >> 2);
|
||||
(*_pv) &= (~msk);
|
||||
(*_pv) |= v;
|
||||
writel_relaxed(*_pv,ctx->regs+offset);
|
||||
}
|
||||
|
||||
static inline void lcdc_cfg_done(struct fimd_context *ctx)
|
||||
{
|
||||
writel_relaxed(0x01,ctx->regs+REG_CFG_DONE);
|
||||
dsb();
|
||||
}
|
||||
|
||||
|
||||
1480
drivers/gpu/drm/rockchip/rk3288_drm_fimd.c
Normal file
1480
drivers/gpu/drm/rockchip/rk3288_drm_fimd.c
Normal file
File diff suppressed because it is too large
Load Diff
1368
drivers/gpu/drm/rockchip/rk3288_drm_fimd.h
Normal file
1368
drivers/gpu/drm/rockchip/rk3288_drm_fimd.h
Normal file
File diff suppressed because it is too large
Load Diff
203
drivers/gpu/drm/rockchip/rockchip_drm_buf.c
Normal file
203
drivers/gpu/drm/rockchip/rockchip_drm_buf.c
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/* rockchip_drm_buf.c
|
||||
*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/rockchip_drm.h>
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_gem.h"
|
||||
#include "rockchip_drm_buf.h"
|
||||
#include "rockchip_drm_iommu.h"
|
||||
|
||||
static int lowlevel_buffer_allocate(struct drm_device *dev,
|
||||
unsigned int flags, struct rockchip_drm_gem_buf *buf)
|
||||
{
|
||||
int ret = 0;
|
||||
enum dma_attr attr;
|
||||
unsigned int nr_pages;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (buf->dma_addr) {
|
||||
DRM_DEBUG_KMS("already allocated.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
init_dma_attrs(&buf->dma_attrs);
|
||||
|
||||
/*
|
||||
* if ROCKCHIP_BO_CONTIG, fully physically contiguous memory
|
||||
* region will be allocated else physically contiguous
|
||||
* as possible.
|
||||
*/
|
||||
if (!(flags & ROCKCHIP_BO_NONCONTIG))
|
||||
dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &buf->dma_attrs);
|
||||
|
||||
/*
|
||||
* if ROCKCHIP_BO_WC or ROCKCHIP_BO_NONCACHABLE, writecombine mapping
|
||||
* else cachable mapping.
|
||||
*/
|
||||
if (flags & ROCKCHIP_BO_WC || !(flags & ROCKCHIP_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 = kzalloc(sizeof(struct page) * nr_pages,
|
||||
GFP_KERNEL);
|
||||
if (!buf->pages) {
|
||||
DRM_ERROR("failed to allocate pages.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
buf->kvaddr = 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");
|
||||
kfree(buf->pages);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
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 (!buf->sgt) {
|
||||
DRM_ERROR("failed to get sg table.\n");
|
||||
ret = -ENOMEM;
|
||||
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;
|
||||
|
||||
if (!is_drm_iommu_supported(dev))
|
||||
kfree(buf->pages);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void lowlevel_buffer_deallocate(struct drm_device *dev,
|
||||
unsigned int flags, struct rockchip_drm_gem_buf *buf)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s.\n", __FILE__);
|
||||
|
||||
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);
|
||||
kfree(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 rockchip_drm_gem_buf *rockchip_drm_init_buf(struct drm_device *dev,
|
||||
unsigned int size)
|
||||
{
|
||||
struct rockchip_drm_gem_buf *buffer;
|
||||
|
||||
DRM_DEBUG_KMS("%s.\n", __FILE__);
|
||||
DRM_DEBUG_KMS("desired size = 0x%x\n", size);
|
||||
|
||||
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
DRM_ERROR("failed to allocate rockchip_drm_gem_buf.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer->size = size;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void rockchip_drm_fini_buf(struct drm_device *dev,
|
||||
struct rockchip_drm_gem_buf *buffer)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s.\n", __FILE__);
|
||||
|
||||
if (!buffer) {
|
||||
DRM_DEBUG_KMS("buffer is null.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
kfree(buffer);
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
int rockchip_drm_alloc_buf(struct drm_device *dev,
|
||||
struct rockchip_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 rockchip_drm_free_buf(struct drm_device *dev,
|
||||
unsigned int flags, struct rockchip_drm_gem_buf *buffer)
|
||||
{
|
||||
|
||||
lowlevel_buffer_deallocate(dev, flags, buffer);
|
||||
}
|
||||
34
drivers/gpu/drm/rockchip/rockchip_drm_buf.h
Normal file
34
drivers/gpu/drm/rockchip/rockchip_drm_buf.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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 _ROCKCHIP_DRM_BUF_H_
|
||||
#define _ROCKCHIP_DRM_BUF_H_
|
||||
|
||||
/* create and initialize buffer object. */
|
||||
struct rockchip_drm_gem_buf *rockchip_drm_init_buf(struct drm_device *dev,
|
||||
unsigned int size);
|
||||
|
||||
/* destroy buffer object. */
|
||||
void rockchip_drm_fini_buf(struct drm_device *dev,
|
||||
struct rockchip_drm_gem_buf *buffer);
|
||||
|
||||
/* allocate physical memory region and setup sgt. */
|
||||
int rockchip_drm_alloc_buf(struct drm_device *dev,
|
||||
struct rockchip_drm_gem_buf *buf,
|
||||
unsigned int flags);
|
||||
|
||||
/* release physical memory region, and sgt. */
|
||||
void rockchip_drm_free_buf(struct drm_device *dev,
|
||||
unsigned int flags,
|
||||
struct rockchip_drm_gem_buf *buffer);
|
||||
|
||||
#endif
|
||||
382
drivers/gpu/drm/rockchip/rockchip_drm_connector.c
Normal file
382
drivers/gpu/drm/rockchip/rockchip_drm_connector.c
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
||||
#include <drm/rockchip_drm.h>
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_encoder.h"
|
||||
|
||||
#define to_rockchip_connector(x) container_of(x, struct rockchip_drm_connector,\
|
||||
drm_connector)
|
||||
|
||||
struct rockchip_drm_connector {
|
||||
struct drm_connector drm_connector;
|
||||
uint32_t encoder_id;
|
||||
struct rockchip_drm_manager *manager;
|
||||
uint32_t dpms;
|
||||
};
|
||||
|
||||
/* convert rockchip_video_timings to drm_display_mode */
|
||||
static inline void
|
||||
convert_to_display_mode(struct drm_display_mode *mode,
|
||||
struct rockchip_drm_panel_info *panel)
|
||||
{
|
||||
struct fb_videomode *timing = &panel->timing;
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
mode->clock = timing->pixclock / 1000;
|
||||
mode->vrefresh = timing->refresh;
|
||||
|
||||
mode->hdisplay = timing->xres;
|
||||
mode->hsync_start = mode->hdisplay + timing->right_margin;
|
||||
mode->hsync_end = mode->hsync_start + timing->hsync_len;
|
||||
mode->htotal = mode->hsync_end + timing->left_margin;
|
||||
|
||||
mode->vdisplay = timing->yres;
|
||||
mode->vsync_start = mode->vdisplay + timing->lower_margin;
|
||||
mode->vsync_end = mode->vsync_start + timing->vsync_len;
|
||||
mode->vtotal = mode->vsync_end + timing->upper_margin;
|
||||
mode->width_mm = panel->width_mm;
|
||||
mode->height_mm = panel->height_mm;
|
||||
|
||||
if (timing->vmode & FB_VMODE_INTERLACED)
|
||||
mode->flags |= DRM_MODE_FLAG_INTERLACE;
|
||||
|
||||
if (timing->vmode & FB_VMODE_DOUBLE)
|
||||
mode->flags |= DRM_MODE_FLAG_DBLSCAN;
|
||||
}
|
||||
|
||||
/* convert drm_display_mode to rockchip_video_timings */
|
||||
static inline void
|
||||
convert_to_video_timing(struct fb_videomode *timing,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
memset(timing, 0, sizeof(*timing));
|
||||
|
||||
timing->pixclock = mode->clock * 1000;
|
||||
timing->refresh = drm_mode_vrefresh(mode);
|
||||
|
||||
timing->xres = mode->hdisplay;
|
||||
timing->right_margin = mode->hsync_start - mode->hdisplay;
|
||||
timing->hsync_len = mode->hsync_end - mode->hsync_start;
|
||||
timing->left_margin = mode->htotal - mode->hsync_end;
|
||||
|
||||
timing->yres = mode->vdisplay;
|
||||
timing->lower_margin = mode->vsync_start - mode->vdisplay;
|
||||
timing->vsync_len = mode->vsync_end - mode->vsync_start;
|
||||
timing->upper_margin = mode->vtotal - mode->vsync_end;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
timing->vmode = FB_VMODE_INTERLACED;
|
||||
else
|
||||
timing->vmode = FB_VMODE_NONINTERLACED;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
timing->vmode |= FB_VMODE_DOUBLE;
|
||||
}
|
||||
|
||||
static int rockchip_drm_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct rockchip_drm_connector *rockchip_connector =
|
||||
to_rockchip_connector(connector);
|
||||
struct rockchip_drm_manager *manager = rockchip_connector->manager;
|
||||
struct rockchip_drm_display_ops *display_ops = manager->display_ops;
|
||||
struct edid *edid = NULL;
|
||||
unsigned int count = 0;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (!display_ops) {
|
||||
DRM_DEBUG_KMS("display_ops is null.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(manager->dev, 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 rockchip_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(manager->dev);
|
||||
else {
|
||||
drm_mode_destroy(connector->dev, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
convert_to_display_mode(mode, panel);
|
||||
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 rockchip_drm_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct rockchip_drm_connector *rockchip_connector =
|
||||
to_rockchip_connector(connector);
|
||||
struct rockchip_drm_manager *manager = rockchip_connector->manager;
|
||||
struct rockchip_drm_display_ops *display_ops = manager->display_ops;
|
||||
struct fb_videomode timing;
|
||||
int ret = MODE_BAD;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
convert_to_video_timing(&timing, mode);
|
||||
|
||||
if (display_ops && display_ops->check_timing)
|
||||
if (!display_ops->check_timing(manager->dev, (void *)&timing))
|
||||
ret = MODE_OK;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct drm_encoder *rockchip_drm_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct rockchip_drm_connector *rockchip_connector =
|
||||
to_rockchip_connector(connector);
|
||||
struct drm_mode_object *obj;
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
obj = drm_mode_object_find(dev, rockchip_connector->encoder_id,
|
||||
DRM_MODE_OBJECT_ENCODER);
|
||||
if (!obj) {
|
||||
DRM_DEBUG_KMS("Unknown ENCODER ID %d\n",
|
||||
rockchip_connector->encoder_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
encoder = obj_to_encoder(obj);
|
||||
|
||||
return encoder;
|
||||
}
|
||||
|
||||
static struct drm_connector_helper_funcs rockchip_connector_helper_funcs = {
|
||||
.get_modes = rockchip_drm_connector_get_modes,
|
||||
.mode_valid = rockchip_drm_connector_mode_valid,
|
||||
.best_encoder = rockchip_drm_best_encoder,
|
||||
};
|
||||
|
||||
void rockchip_drm_display_power(struct drm_connector *connector, int mode)
|
||||
{
|
||||
struct drm_encoder *encoder = rockchip_drm_best_encoder(connector);
|
||||
struct rockchip_drm_connector *rockchip_connector;
|
||||
struct rockchip_drm_manager *manager = rockchip_drm_get_manager(encoder);
|
||||
struct rockchip_drm_display_ops *display_ops = manager->display_ops;
|
||||
|
||||
rockchip_connector = to_rockchip_connector(connector);
|
||||
|
||||
if (rockchip_connector->dpms == mode) {
|
||||
DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (display_ops && display_ops->power_on)
|
||||
display_ops->power_on(manager->dev, mode);
|
||||
|
||||
rockchip_connector->dpms = mode;
|
||||
}
|
||||
|
||||
static void rockchip_drm_connector_dpms(struct drm_connector *connector,
|
||||
int mode)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/*
|
||||
* in case that drm_crtc_helper_set_mode() is called,
|
||||
* encoder/crtc->funcs->dpms() will be just returned
|
||||
* because they already were DRM_MODE_DPMS_ON so only
|
||||
* rockchip_drm_display_power() will be called.
|
||||
*/
|
||||
drm_helper_connector_dpms(connector, mode);
|
||||
|
||||
rockchip_drm_display_power(connector, mode);
|
||||
|
||||
}
|
||||
|
||||
static int rockchip_drm_connector_fill_modes(struct drm_connector *connector,
|
||||
unsigned int max_width, unsigned int max_height)
|
||||
{
|
||||
struct rockchip_drm_connector *rockchip_connector =
|
||||
to_rockchip_connector(connector);
|
||||
struct rockchip_drm_manager *manager = rockchip_connector->manager;
|
||||
struct rockchip_drm_manager_ops *ops = manager->ops;
|
||||
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 (ops && ops->get_max_resol)
|
||||
ops->get_max_resol(manager->dev, &width, &height);
|
||||
|
||||
return drm_helper_probe_single_connector_modes(connector, width,
|
||||
height);
|
||||
}
|
||||
|
||||
/* get detection status of display device. */
|
||||
static enum drm_connector_status
|
||||
rockchip_drm_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct rockchip_drm_connector *rockchip_connector =
|
||||
to_rockchip_connector(connector);
|
||||
struct rockchip_drm_manager *manager = rockchip_connector->manager;
|
||||
struct rockchip_drm_display_ops *display_ops =
|
||||
manager->display_ops;
|
||||
enum drm_connector_status status = connector_status_disconnected;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (display_ops && display_ops->is_connected) {
|
||||
if (display_ops->is_connected(manager->dev))
|
||||
status = connector_status_connected;
|
||||
else
|
||||
status = connector_status_disconnected;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void rockchip_drm_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
struct rockchip_drm_connector *rockchip_connector =
|
||||
to_rockchip_connector(connector);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
drm_sysfs_connector_remove(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
kfree(rockchip_connector);
|
||||
}
|
||||
|
||||
static struct drm_connector_funcs rockchip_connector_funcs = {
|
||||
.dpms = rockchip_drm_connector_dpms,
|
||||
.fill_modes = rockchip_drm_connector_fill_modes,
|
||||
.detect = rockchip_drm_connector_detect,
|
||||
.destroy = rockchip_drm_connector_destroy,
|
||||
};
|
||||
|
||||
struct drm_connector *rockchip_drm_connector_create(struct drm_device *dev,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
struct rockchip_drm_connector *rockchip_connector;
|
||||
struct rockchip_drm_manager *manager = rockchip_drm_get_manager(encoder);
|
||||
struct drm_connector *connector;
|
||||
int type;
|
||||
int err;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
rockchip_connector = kzalloc(sizeof(*rockchip_connector), GFP_KERNEL);
|
||||
if (!rockchip_connector) {
|
||||
DRM_ERROR("failed to allocate connector\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
connector = &rockchip_connector->drm_connector;
|
||||
|
||||
switch (manager->display_ops->type) {
|
||||
case ROCKCHIP_DISPLAY_TYPE_HDMI:
|
||||
type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
connector->interlace_allowed = true;
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
break;
|
||||
case ROCKCHIP_DISPLAY_TYPE_VIDI:
|
||||
type = DRM_MODE_CONNECTOR_VIRTUAL;
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
break;
|
||||
case ROCKCHIP_DISPLAY_TYPE_LCD:
|
||||
type = DRM_MODE_CONNECTOR_LVDS;
|
||||
break;
|
||||
default:
|
||||
type = DRM_MODE_CONNECTOR_Unknown;
|
||||
break;
|
||||
}
|
||||
|
||||
drm_connector_init(dev, connector, &rockchip_connector_funcs, type);
|
||||
drm_connector_helper_add(connector, &rockchip_connector_helper_funcs);
|
||||
|
||||
err = drm_sysfs_connector_add(connector);
|
||||
if (err)
|
||||
goto err_connector;
|
||||
|
||||
rockchip_connector->encoder_id = encoder->base.id;
|
||||
rockchip_connector->manager = manager;
|
||||
rockchip_connector->dpms = DRM_MODE_DPMS_OFF;
|
||||
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_sysfs_connector_remove(connector);
|
||||
err_connector:
|
||||
drm_connector_cleanup(connector);
|
||||
kfree(rockchip_connector);
|
||||
return NULL;
|
||||
}
|
||||
23
drivers/gpu/drm/rockchip/rockchip_drm_connector.h
Normal file
23
drivers/gpu/drm/rockchip/rockchip_drm_connector.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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 _ROCKCHIP_DRM_CONNECTOR_H_
|
||||
#define _ROCKCHIP_DRM_CONNECTOR_H_
|
||||
|
||||
struct drm_connector *rockchip_drm_connector_create(struct drm_device *dev,
|
||||
struct drm_encoder *encoder);
|
||||
|
||||
struct drm_encoder *rockchip_drm_best_encoder(struct drm_connector *connector);
|
||||
|
||||
void rockchip_drm_display_power(struct drm_connector *connector, int mode);
|
||||
|
||||
#endif
|
||||
241
drivers/gpu/drm/rockchip/rockchip_drm_core.c
Normal file
241
drivers/gpu/drm/rockchip/rockchip_drm_core.c
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_encoder.h"
|
||||
#include "rockchip_drm_connector.h"
|
||||
#include "rockchip_drm_fbdev.h"
|
||||
|
||||
static LIST_HEAD(rockchip_drm_subdrv_list);
|
||||
|
||||
static int rockchip_drm_create_enc_conn(struct drm_device *dev,
|
||||
struct rockchip_drm_subdrv *subdrv)
|
||||
{
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
subdrv->manager->dev = subdrv->dev;
|
||||
|
||||
/* create and initialize a encoder for this sub driver. */
|
||||
encoder = rockchip_drm_encoder_create(dev, subdrv->manager,
|
||||
(1 << MAX_CRTC) - 1);
|
||||
if (!encoder) {
|
||||
DRM_ERROR("failed to create encoder\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/*
|
||||
* create and initialize a connector for this sub driver and
|
||||
* attach the encoder created above to the connector.
|
||||
*/
|
||||
connector = rockchip_drm_connector_create(dev, encoder);
|
||||
if (!connector) {
|
||||
DRM_ERROR("failed to create connector\n");
|
||||
ret = -EFAULT;
|
||||
goto err_destroy_encoder;
|
||||
}
|
||||
|
||||
subdrv->encoder = encoder;
|
||||
subdrv->connector = connector;
|
||||
|
||||
return 0;
|
||||
|
||||
err_destroy_encoder:
|
||||
encoder->funcs->destroy(encoder);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rockchip_drm_destroy_enc_conn(struct rockchip_drm_subdrv *subdrv)
|
||||
{
|
||||
if (subdrv->encoder) {
|
||||
struct drm_encoder *encoder = subdrv->encoder;
|
||||
encoder->funcs->destroy(encoder);
|
||||
subdrv->encoder = NULL;
|
||||
}
|
||||
|
||||
if (subdrv->connector) {
|
||||
struct drm_connector *connector = subdrv->connector;
|
||||
connector->funcs->destroy(connector);
|
||||
subdrv->connector = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int rockchip_drm_subdrv_probe(struct drm_device *dev,
|
||||
struct rockchip_drm_subdrv *subdrv)
|
||||
{
|
||||
if (subdrv->probe) {
|
||||
int ret;
|
||||
|
||||
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 or by load()
|
||||
* of rockchip drm driver.
|
||||
*
|
||||
* P.S. note that this driver is considered for modularization.
|
||||
*/
|
||||
ret = subdrv->probe(dev, subdrv->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rockchip_drm_subdrv_remove(struct drm_device *dev,
|
||||
struct rockchip_drm_subdrv *subdrv)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
if (subdrv->remove)
|
||||
subdrv->remove(dev, subdrv->dev);
|
||||
}
|
||||
|
||||
int rockchip_drm_device_register(struct drm_device *dev)
|
||||
{
|
||||
struct rockchip_drm_subdrv *subdrv, *n;
|
||||
unsigned int fine_cnt = 0;
|
||||
int err;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
list_for_each_entry_safe(subdrv, n, &rockchip_drm_subdrv_list, list) {
|
||||
err = rockchip_drm_subdrv_probe(dev, subdrv);
|
||||
if (err) {
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
DRM_DEBUG("rockchip drm subdrv probe failed.\n");
|
||||
list_del(&subdrv->list);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* if manager is null then it means that this sub driver
|
||||
* doesn't need encoder and connector.
|
||||
*/
|
||||
if (!subdrv->manager) {
|
||||
fine_cnt++;
|
||||
continue;
|
||||
}
|
||||
|
||||
err = rockchip_drm_create_enc_conn(dev, subdrv);
|
||||
if (err) {
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
DRM_DEBUG("failed to create encoder and connector.\n");
|
||||
rockchip_drm_subdrv_remove(dev, subdrv);
|
||||
list_del(&subdrv->list);
|
||||
continue;
|
||||
}
|
||||
|
||||
fine_cnt++;
|
||||
}
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
if (!fine_cnt)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_drm_device_register);
|
||||
|
||||
int rockchip_drm_device_unregister(struct drm_device *dev)
|
||||
{
|
||||
struct rockchip_drm_subdrv *subdrv;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
if (!dev) {
|
||||
WARN(1, "Unexpected drm device unregister!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
list_for_each_entry(subdrv, &rockchip_drm_subdrv_list, list) {
|
||||
rockchip_drm_subdrv_remove(dev, subdrv);
|
||||
rockchip_drm_destroy_enc_conn(subdrv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_drm_device_unregister);
|
||||
|
||||
int rockchip_drm_subdrv_register(struct rockchip_drm_subdrv *subdrv)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
if (!subdrv)
|
||||
return -EINVAL;
|
||||
|
||||
list_add_tail(&subdrv->list, &rockchip_drm_subdrv_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_drm_subdrv_register);
|
||||
|
||||
int rockchip_drm_subdrv_unregister(struct rockchip_drm_subdrv *subdrv)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
if (!subdrv)
|
||||
return -EINVAL;
|
||||
|
||||
list_del(&subdrv->list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_drm_subdrv_unregister);
|
||||
|
||||
int rockchip_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
struct rockchip_drm_subdrv *subdrv;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(subdrv, &rockchip_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(rockchip_drm_subdrv_open);
|
||||
|
||||
void rockchip_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
struct rockchip_drm_subdrv *subdrv;
|
||||
|
||||
list_for_each_entry(subdrv, &rockchip_drm_subdrv_list, list) {
|
||||
if (subdrv->close)
|
||||
subdrv->close(dev, subdrv->dev, file);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_drm_subdrv_close);
|
||||
432
drivers/gpu/drm/rockchip/rockchip_drm_crtc.c
Normal file
432
drivers/gpu/drm/rockchip/rockchip_drm_crtc.c
Normal file
|
|
@ -0,0 +1,432 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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.
|
||||
*/
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_encoder.h"
|
||||
#include "rockchip_drm_plane.h"
|
||||
|
||||
#define to_rockchip_crtc(x) container_of(x, struct rockchip_drm_crtc,\
|
||||
drm_crtc)
|
||||
|
||||
enum rockchip_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.
|
||||
* @drm_plane: pointer of private plane object for 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 occured. 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 occured through
|
||||
* this pipe value.
|
||||
* @dpms: store the crtc dpms value
|
||||
* @mode: store the crtc mode value
|
||||
*/
|
||||
struct rockchip_drm_crtc {
|
||||
struct drm_crtc drm_crtc;
|
||||
struct drm_plane *plane;
|
||||
unsigned int pipe;
|
||||
unsigned int dpms;
|
||||
enum rockchip_crtc_mode mode;
|
||||
wait_queue_head_t pending_flip_queue;
|
||||
atomic_t pending_flip;
|
||||
};
|
||||
|
||||
static void rockchip_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
{
|
||||
struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
|
||||
|
||||
DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
|
||||
|
||||
if (rockchip_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. */
|
||||
wait_event(rockchip_crtc->pending_flip_queue,
|
||||
atomic_read(&rockchip_crtc->pending_flip) == 0);
|
||||
drm_vblank_off(crtc->dev, rockchip_crtc->pipe);
|
||||
}
|
||||
|
||||
rockchip_drm_fn_encoder(crtc, &mode, rockchip_drm_encoder_crtc_dpms);
|
||||
rockchip_crtc->dpms = mode;
|
||||
}
|
||||
|
||||
static void rockchip_drm_crtc_prepare(struct drm_crtc *crtc)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* drm framework doesn't check NULL. */
|
||||
}
|
||||
|
||||
static void rockchip_drm_crtc_commit(struct drm_crtc *crtc)
|
||||
{
|
||||
struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
rockchip_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
|
||||
rockchip_plane_commit(rockchip_crtc->plane);
|
||||
rockchip_plane_dpms(rockchip_crtc->plane, DRM_MODE_DPMS_ON);
|
||||
}
|
||||
|
||||
static bool
|
||||
rockchip_drm_crtc_mode_fixup(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* drm framework doesn't check NULL */
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
rockchip_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 rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
|
||||
struct drm_plane *plane = rockchip_crtc->plane;
|
||||
unsigned int crtc_w;
|
||||
unsigned int crtc_h;
|
||||
int pipe = rockchip_crtc->pipe;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/*
|
||||
* 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 = crtc->fb->width - x;
|
||||
crtc_h = crtc->fb->height - y;
|
||||
|
||||
ret = rockchip_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
|
||||
x, y, crtc_w, crtc_h);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
plane->crtc = crtc;
|
||||
plane->fb = crtc->fb;
|
||||
|
||||
rockchip_drm_fn_encoder(crtc, &pipe, rockchip_drm_encoder_crtc_pipe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
|
||||
struct drm_plane *plane = rockchip_crtc->plane;
|
||||
unsigned int crtc_w;
|
||||
unsigned int crtc_h;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* when framebuffer changing is requested, crtc's dpms should be on */
|
||||
if (rockchip_crtc->dpms > DRM_MODE_DPMS_ON) {
|
||||
DRM_ERROR("failed framebuffer changing request.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
crtc_w = crtc->fb->width - x;
|
||||
crtc_h = crtc->fb->height - y;
|
||||
|
||||
ret = rockchip_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
|
||||
x, y, crtc_w, crtc_h);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rockchip_drm_crtc_commit(crtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rockchip_drm_crtc_load_lut(struct drm_crtc *crtc)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
/* drm framework doesn't check NULL */
|
||||
}
|
||||
|
||||
static void rockchip_drm_crtc_disable(struct drm_crtc *crtc)
|
||||
{
|
||||
struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
rockchip_plane_dpms(rockchip_crtc->plane, DRM_MODE_DPMS_OFF);
|
||||
rockchip_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
|
||||
static struct drm_crtc_helper_funcs rockchip_crtc_helper_funcs = {
|
||||
.dpms = rockchip_drm_crtc_dpms,
|
||||
.prepare = rockchip_drm_crtc_prepare,
|
||||
.commit = rockchip_drm_crtc_commit,
|
||||
.mode_fixup = rockchip_drm_crtc_mode_fixup,
|
||||
.mode_set = rockchip_drm_crtc_mode_set,
|
||||
.mode_set_base = rockchip_drm_crtc_mode_set_base,
|
||||
.load_lut = rockchip_drm_crtc_load_lut,
|
||||
.disable = rockchip_drm_crtc_disable,
|
||||
};
|
||||
|
||||
static int rockchip_drm_crtc_page_flip(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct rockchip_drm_private *dev_priv = dev->dev_private;
|
||||
struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
|
||||
struct drm_framebuffer *old_fb = crtc->fb;
|
||||
int ret = -EINVAL;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* when the page flip is requested, crtc's dpms should be on */
|
||||
if (rockchip_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 = rockchip_crtc->pipe;
|
||||
|
||||
ret = drm_vblank_get(dev, rockchip_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(&rockchip_crtc->pending_flip, 1);
|
||||
spin_unlock_irq(&dev->event_lock);
|
||||
|
||||
crtc->fb = fb;
|
||||
ret = rockchip_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y,
|
||||
NULL);
|
||||
if (ret) {
|
||||
crtc->fb = old_fb;
|
||||
|
||||
spin_lock_irq(&dev->event_lock);
|
||||
drm_vblank_put(dev, rockchip_crtc->pipe);
|
||||
list_del(&event->base.link);
|
||||
spin_unlock_irq(&dev->event_lock);
|
||||
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rockchip_drm_crtc_destroy(struct drm_crtc *crtc)
|
||||
{
|
||||
struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
|
||||
struct rockchip_drm_private *private = crtc->dev->dev_private;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
private->crtc[rockchip_crtc->pipe] = NULL;
|
||||
|
||||
drm_crtc_cleanup(crtc);
|
||||
kfree(rockchip_crtc);
|
||||
}
|
||||
|
||||
static int rockchip_drm_crtc_set_property(struct drm_crtc *crtc,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct rockchip_drm_private *dev_priv = dev->dev_private;
|
||||
struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __func__);
|
||||
|
||||
if (property == dev_priv->crtc_mode_property) {
|
||||
enum rockchip_crtc_mode mode = val;
|
||||
|
||||
if (mode == rockchip_crtc->mode)
|
||||
return 0;
|
||||
|
||||
rockchip_crtc->mode = mode;
|
||||
|
||||
switch (mode) {
|
||||
case CRTC_MODE_NORMAL:
|
||||
rockchip_drm_crtc_commit(crtc);
|
||||
break;
|
||||
case CRTC_MODE_BLANK:
|
||||
rockchip_plane_dpms(rockchip_crtc->plane,
|
||||
DRM_MODE_DPMS_OFF);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct drm_crtc_funcs rockchip_crtc_funcs = {
|
||||
.set_config = drm_crtc_helper_set_config,
|
||||
.page_flip = rockchip_drm_crtc_page_flip,
|
||||
.destroy = rockchip_drm_crtc_destroy,
|
||||
.set_property = rockchip_drm_crtc_set_property,
|
||||
};
|
||||
|
||||
static const struct drm_prop_enum_list mode_names[] = {
|
||||
{ CRTC_MODE_NORMAL, "normal" },
|
||||
{ CRTC_MODE_BLANK, "blank" },
|
||||
};
|
||||
|
||||
static void rockchip_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct rockchip_drm_private *dev_priv = dev->dev_private;
|
||||
struct drm_property *prop;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __func__);
|
||||
|
||||
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 rockchip_drm_crtc_create(struct drm_device *dev, unsigned int nr)
|
||||
{
|
||||
struct rockchip_drm_crtc *rockchip_crtc;
|
||||
struct rockchip_drm_private *private = dev->dev_private;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
rockchip_crtc = kzalloc(sizeof(*rockchip_crtc), GFP_KERNEL);
|
||||
if (!rockchip_crtc) {
|
||||
DRM_ERROR("failed to allocate rockchip crtc\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rockchip_crtc->pipe = nr;
|
||||
rockchip_crtc->dpms = DRM_MODE_DPMS_OFF;
|
||||
init_waitqueue_head(&rockchip_crtc->pending_flip_queue);
|
||||
atomic_set(&rockchip_crtc->pending_flip, 0);
|
||||
rockchip_crtc->plane = rockchip_plane_init(dev, 1 << nr, true);
|
||||
if (!rockchip_crtc->plane) {
|
||||
kfree(rockchip_crtc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
crtc = &rockchip_crtc->drm_crtc;
|
||||
|
||||
private->crtc[nr] = crtc;
|
||||
|
||||
drm_crtc_init(dev, crtc, &rockchip_crtc_funcs);
|
||||
drm_crtc_helper_add(crtc, &rockchip_crtc_helper_funcs);
|
||||
|
||||
rockchip_drm_crtc_attach_mode_property(crtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
|
||||
{
|
||||
struct rockchip_drm_private *private = dev->dev_private;
|
||||
struct rockchip_drm_crtc *rockchip_crtc =
|
||||
to_rockchip_crtc(private->crtc[crtc]);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (rockchip_crtc->dpms != DRM_MODE_DPMS_ON)
|
||||
return -EPERM;
|
||||
|
||||
rockchip_drm_fn_encoder(private->crtc[crtc], &crtc,
|
||||
rockchip_drm_enable_vblank);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
|
||||
{
|
||||
struct rockchip_drm_private *private = dev->dev_private;
|
||||
struct rockchip_drm_crtc *rockchip_crtc =
|
||||
to_rockchip_crtc(private->crtc[crtc]);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (rockchip_crtc->dpms != DRM_MODE_DPMS_ON)
|
||||
return;
|
||||
|
||||
rockchip_drm_fn_encoder(private->crtc[crtc], &crtc,
|
||||
rockchip_drm_disable_vblank);
|
||||
}
|
||||
|
||||
void rockchip_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
|
||||
{
|
||||
struct rockchip_drm_private *dev_priv = dev->dev_private;
|
||||
struct drm_pending_vblank_event *e, *t;
|
||||
struct drm_crtc *drm_crtc = dev_priv->crtc[crtc];
|
||||
struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(drm_crtc);
|
||||
unsigned long flags;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
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 (crtc != e->pipe)
|
||||
continue;
|
||||
|
||||
list_del(&e->base.link);
|
||||
drm_send_vblank_event(dev, -1, e);
|
||||
drm_vblank_put(dev, crtc);
|
||||
atomic_set(&rockchip_crtc->pending_flip, 0);
|
||||
wake_up(&rockchip_crtc->pending_flip_queue);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
}
|
||||
21
drivers/gpu/drm/rockchip/rockchip_drm_crtc.h
Normal file
21
drivers/gpu/drm/rockchip/rockchip_drm_crtc.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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 _ROCKCHIP_DRM_CRTC_H_
|
||||
#define _ROCKCHIP_DRM_CRTC_H_
|
||||
|
||||
int rockchip_drm_crtc_create(struct drm_device *dev, unsigned int nr);
|
||||
int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
|
||||
void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
|
||||
void rockchip_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc);
|
||||
|
||||
#endif
|
||||
307
drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.c
Normal file
307
drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.c
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/rockchip_drm.h>
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_gem.h"
|
||||
|
||||
#include <linux/dma-buf.h>
|
||||
|
||||
struct rockchip_drm_dmabuf_attachment {
|
||||
struct sg_table sgt;
|
||||
enum dma_data_direction dir;
|
||||
bool is_mapped;
|
||||
};
|
||||
|
||||
static int rockchip_gem_attach_dma_buf(struct dma_buf *dmabuf,
|
||||
struct device *dev,
|
||||
struct dma_buf_attachment *attach)
|
||||
{
|
||||
struct rockchip_drm_dmabuf_attachment *rockchip_attach;
|
||||
|
||||
rockchip_attach = kzalloc(sizeof(*rockchip_attach), GFP_KERNEL);
|
||||
if (!rockchip_attach)
|
||||
return -ENOMEM;
|
||||
|
||||
rockchip_attach->dir = DMA_NONE;
|
||||
attach->priv = rockchip_attach;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rockchip_gem_detach_dma_buf(struct dma_buf *dmabuf,
|
||||
struct dma_buf_attachment *attach)
|
||||
{
|
||||
struct rockchip_drm_dmabuf_attachment *rockchip_attach = attach->priv;
|
||||
struct sg_table *sgt;
|
||||
|
||||
if (!rockchip_attach)
|
||||
return;
|
||||
|
||||
sgt = &rockchip_attach->sgt;
|
||||
|
||||
if (rockchip_attach->dir != DMA_NONE)
|
||||
dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
|
||||
rockchip_attach->dir);
|
||||
|
||||
sg_free_table(sgt);
|
||||
kfree(rockchip_attach);
|
||||
attach->priv = NULL;
|
||||
}
|
||||
|
||||
static struct sg_table *
|
||||
rockchip_gem_map_dma_buf(struct dma_buf_attachment *attach,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
struct rockchip_drm_dmabuf_attachment *rockchip_attach = attach->priv;
|
||||
struct rockchip_drm_gem_obj *gem_obj = attach->dmabuf->priv;
|
||||
struct drm_device *dev = gem_obj->base.dev;
|
||||
struct rockchip_drm_gem_buf *buf;
|
||||
struct scatterlist *rd, *wr;
|
||||
struct sg_table *sgt = NULL;
|
||||
unsigned int i;
|
||||
int nents, ret;
|
||||
|
||||
DRM_DEBUG_PRIME("%s\n", __FILE__);
|
||||
|
||||
/* just return current sgt if already requested. */
|
||||
if (rockchip_attach->dir == dir && rockchip_attach->is_mapped)
|
||||
return &rockchip_attach->sgt;
|
||||
|
||||
buf = gem_obj->buffer;
|
||||
if (!buf) {
|
||||
DRM_ERROR("buffer is null.\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
sgt = &rockchip_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;
|
||||
}
|
||||
}
|
||||
|
||||
rockchip_attach->is_mapped = true;
|
||||
rockchip_attach->dir = dir;
|
||||
attach->priv = rockchip_attach;
|
||||
|
||||
DRM_DEBUG_PRIME("buffer size = 0x%lx\n", buf->size);
|
||||
|
||||
err_unlock:
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return sgt;
|
||||
}
|
||||
|
||||
static void rockchip_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
|
||||
struct sg_table *sgt,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
static void rockchip_dmabuf_release(struct dma_buf *dmabuf)
|
||||
{
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj = dmabuf->priv;
|
||||
|
||||
DRM_DEBUG_PRIME("%s\n", __FILE__);
|
||||
|
||||
/*
|
||||
* rockchip_dmabuf_release() call means that file object's
|
||||
* f_count is 0 and it calls drm_gem_object_handle_unreference()
|
||||
* to drop the references that these values had been increased
|
||||
* at drm_prime_handle_to_fd()
|
||||
*/
|
||||
if (rockchip_gem_obj->base.export_dma_buf == dmabuf) {
|
||||
rockchip_gem_obj->base.export_dma_buf = NULL;
|
||||
|
||||
/*
|
||||
* drop this gem object refcount to release allocated buffer
|
||||
* and resources.
|
||||
*/
|
||||
drm_gem_object_unreference_unlocked(&rockchip_gem_obj->base);
|
||||
}
|
||||
}
|
||||
|
||||
static void *rockchip_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf,
|
||||
unsigned long page_num)
|
||||
{
|
||||
/* TODO */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rockchip_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,
|
||||
unsigned long page_num,
|
||||
void *addr)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
static void *rockchip_gem_dmabuf_kmap(struct dma_buf *dma_buf,
|
||||
unsigned long page_num)
|
||||
{
|
||||
/* TODO */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rockchip_gem_dmabuf_kunmap(struct dma_buf *dma_buf,
|
||||
unsigned long page_num, void *addr)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
static int rockchip_gem_dmabuf_mmap(struct dma_buf *dma_buf,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
static struct dma_buf_ops rockchip_dmabuf_ops = {
|
||||
.attach = rockchip_gem_attach_dma_buf,
|
||||
.detach = rockchip_gem_detach_dma_buf,
|
||||
.map_dma_buf = rockchip_gem_map_dma_buf,
|
||||
.unmap_dma_buf = rockchip_gem_unmap_dma_buf,
|
||||
.kmap = rockchip_gem_dmabuf_kmap,
|
||||
.kmap_atomic = rockchip_gem_dmabuf_kmap_atomic,
|
||||
.kunmap = rockchip_gem_dmabuf_kunmap,
|
||||
.kunmap_atomic = rockchip_gem_dmabuf_kunmap_atomic,
|
||||
.mmap = rockchip_gem_dmabuf_mmap,
|
||||
.release = rockchip_dmabuf_release,
|
||||
};
|
||||
|
||||
struct dma_buf *rockchip_dmabuf_prime_export(struct drm_device *drm_dev,
|
||||
struct drm_gem_object *obj, int flags)
|
||||
{
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj = to_rockchip_gem_obj(obj);
|
||||
|
||||
return dma_buf_export(rockchip_gem_obj, &rockchip_dmabuf_ops,
|
||||
rockchip_gem_obj->base.size, flags);
|
||||
}
|
||||
|
||||
struct drm_gem_object *rockchip_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 rockchip_drm_gem_obj *rockchip_gem_obj;
|
||||
struct rockchip_drm_gem_buf *buffer;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_PRIME("%s\n", __FILE__);
|
||||
|
||||
/* is this one of own objects? */
|
||||
if (dma_buf->ops == &rockchip_dmabuf_ops) {
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
rockchip_gem_obj = dma_buf->priv;
|
||||
obj = &rockchip_gem_obj->base;
|
||||
|
||||
/* 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_OR_NULL(sgt)) {
|
||||
ret = PTR_ERR(sgt);
|
||||
goto err_buf_detach;
|
||||
}
|
||||
|
||||
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
DRM_ERROR("failed to allocate rockchip_drm_gem_buf.\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_unmap_attach;
|
||||
}
|
||||
|
||||
rockchip_gem_obj = rockchip_drm_gem_init(drm_dev, dma_buf->size);
|
||||
if (!rockchip_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. */
|
||||
rockchip_gem_obj->flags |= ROCKCHIP_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.
|
||||
*/
|
||||
rockchip_gem_obj->flags |= ROCKCHIP_BO_NONCONTIG;
|
||||
}
|
||||
|
||||
rockchip_gem_obj->buffer = buffer;
|
||||
buffer->sgt = sgt;
|
||||
rockchip_gem_obj->base.import_attach = attach;
|
||||
|
||||
DRM_DEBUG_PRIME("dma_addr = 0x%x, size = 0x%lx\n", buffer->dma_addr,
|
||||
buffer->size);
|
||||
|
||||
return &rockchip_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);
|
||||
}
|
||||
|
||||
26
drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.h
Normal file
26
drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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 _ROCKCHIP_DRM_DMABUF_H_
|
||||
#define _ROCKCHIP_DRM_DMABUF_H_
|
||||
|
||||
#ifdef CONFIG_DRM_ROCKCHIP_DMABUF
|
||||
struct dma_buf *rockchip_dmabuf_prime_export(struct drm_device *drm_dev,
|
||||
struct drm_gem_object *obj, int flags);
|
||||
|
||||
struct drm_gem_object *rockchip_dmabuf_prime_import(struct drm_device *drm_dev,
|
||||
struct dma_buf *dma_buf);
|
||||
#else
|
||||
#define rockchip_dmabuf_prime_export NULL
|
||||
#define rockchip_dmabuf_prime_import NULL
|
||||
#endif
|
||||
#endif
|
||||
374
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
Normal file
374
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
||||
#include <drm/rockchip_drm.h>
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_crtc.h"
|
||||
#include "rockchip_drm_encoder.h"
|
||||
#include "rockchip_drm_fbdev.h"
|
||||
#include "rockchip_drm_fb.h"
|
||||
#include "rockchip_drm_gem.h"
|
||||
#include "rockchip_drm_plane.h"
|
||||
#include "rockchip_drm_dmabuf.h"
|
||||
#include "rockchip_drm_iommu.h"
|
||||
|
||||
#define DRIVER_NAME "rockchip"
|
||||
#define DRIVER_DESC "rockchip Soc DRM"
|
||||
#define DRIVER_DATE "20140318"
|
||||
#define DRIVER_MAJOR 1
|
||||
#define DRIVER_MINOR 0
|
||||
|
||||
#define VBLANK_OFF_DELAY 50000
|
||||
|
||||
/* platform device pointer for eynos drm device. */
|
||||
static struct platform_device *rockchip_drm_pdev;
|
||||
|
||||
static int rockchip_drm_load(struct drm_device *dev, unsigned long flags)
|
||||
{
|
||||
struct rockchip_drm_private *private;
|
||||
int ret;
|
||||
int nr;
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
private = kzalloc(sizeof(struct rockchip_drm_private), GFP_KERNEL);
|
||||
if (!private) {
|
||||
DRM_ERROR("failed to allocate private\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
INIT_LIST_HEAD(&private->pageflip_event_list);
|
||||
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.
|
||||
*/
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
ret = drm_create_iommu_mapping(dev);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to create iommu mapping.\n");
|
||||
goto err_crtc;
|
||||
}
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
drm_mode_config_init(dev);
|
||||
|
||||
/* init kms poll for handling hpd */
|
||||
drm_kms_helper_poll_init(dev);
|
||||
|
||||
rockchip_drm_mode_config_init(dev);
|
||||
|
||||
/*
|
||||
* ROCKCHIP4 is enough to have two CRTCs and each crtc would be used
|
||||
* without dependency of hardware.
|
||||
*/
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
for (nr = 0; nr < MAX_CRTC; nr++) {
|
||||
ret = rockchip_drm_crtc_create(dev, nr);
|
||||
if (ret)
|
||||
goto err_release_iommu_mapping;
|
||||
}
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
for (nr = 0; nr < MAX_PLANE; nr++) {
|
||||
struct drm_plane *plane;
|
||||
unsigned int possible_crtcs = (1 << MAX_CRTC) - 1;
|
||||
|
||||
plane = rockchip_plane_init(dev, possible_crtcs, false);
|
||||
if (!plane)
|
||||
goto err_release_iommu_mapping;
|
||||
}
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
ret = drm_vblank_init(dev, MAX_CRTC);
|
||||
if (ret)
|
||||
goto err_release_iommu_mapping;
|
||||
|
||||
/*
|
||||
* probe sub drivers such as display controller and hdmi driver,
|
||||
* that were registered at probe() of platform driver
|
||||
* to the sub driver and create encoder and connector for them.
|
||||
*/
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
ret = rockchip_drm_device_register(dev);
|
||||
if (ret)
|
||||
goto err_vblank;
|
||||
|
||||
/* setup possible_clones. */
|
||||
rockchip_drm_encoder_setup(dev);
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
/*
|
||||
* create and configure fb helper and also rockchip specific
|
||||
* fbdev object.
|
||||
*/
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
ret = rockchip_drm_fbdev_init(dev);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to initialize drm fbdev\n");
|
||||
goto err_drm_device;
|
||||
}
|
||||
|
||||
drm_vblank_offdelay = VBLANK_OFF_DELAY;
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
return 0;
|
||||
|
||||
err_drm_device:
|
||||
rockchip_drm_device_unregister(dev);
|
||||
err_vblank:
|
||||
drm_vblank_cleanup(dev);
|
||||
err_release_iommu_mapping:
|
||||
drm_release_iommu_mapping(dev);
|
||||
err_crtc:
|
||||
drm_mode_config_cleanup(dev);
|
||||
kfree(private);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_drm_unload(struct drm_device *dev)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
rockchip_drm_fbdev_fini(dev);
|
||||
rockchip_drm_device_unregister(dev);
|
||||
drm_vblank_cleanup(dev);
|
||||
drm_kms_helper_poll_fini(dev);
|
||||
drm_mode_config_cleanup(dev);
|
||||
|
||||
drm_release_iommu_mapping(dev);
|
||||
kfree(dev->dev_private);
|
||||
|
||||
dev->dev_private = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_drm_open(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
struct drm_rockchip_file_private *file_priv;
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
|
||||
if (!file_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
file->driver_priv = file_priv;
|
||||
|
||||
return rockchip_drm_subdrv_open(dev, file);
|
||||
}
|
||||
|
||||
static void rockchip_drm_preclose(struct drm_device *dev,
|
||||
struct drm_file *file)
|
||||
{
|
||||
struct rockchip_drm_private *private = dev->dev_private;
|
||||
struct drm_pending_vblank_event *e, *t;
|
||||
unsigned long flags;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
/* release events of current file */
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
list_for_each_entry_safe(e, t, &private->pageflip_event_list,
|
||||
base.link) {
|
||||
if (e->base.file_priv == file) {
|
||||
list_del(&e->base.link);
|
||||
e->base.destroy(&e->base);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
|
||||
rockchip_drm_subdrv_close(dev, file);
|
||||
}
|
||||
|
||||
static void rockchip_drm_postclose(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
if (!file->driver_priv)
|
||||
return;
|
||||
|
||||
kfree(file->driver_priv);
|
||||
file->driver_priv = NULL;
|
||||
}
|
||||
|
||||
static void rockchip_drm_lastclose(struct drm_device *dev)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
rockchip_drm_fbdev_restore_mode(dev);
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct rockchip_drm_gem_vm_ops = {
|
||||
.fault = rockchip_drm_gem_fault,
|
||||
.open = drm_gem_vm_open,
|
||||
.close = drm_gem_vm_close,
|
||||
};
|
||||
|
||||
static struct drm_ioctl_desc rockchip_ioctls[] = {
|
||||
DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_CREATE, rockchip_drm_gem_create_ioctl,
|
||||
DRM_UNLOCKED | DRM_AUTH),
|
||||
DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_MAP_OFFSET,
|
||||
rockchip_drm_gem_map_offset_ioctl, DRM_UNLOCKED |
|
||||
DRM_AUTH),
|
||||
DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_MMAP,
|
||||
rockchip_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
|
||||
DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_GET,
|
||||
rockchip_drm_gem_get_ioctl, DRM_UNLOCKED),
|
||||
};
|
||||
|
||||
static const struct file_operations rockchip_drm_driver_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.mmap = rockchip_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 rockchip_drm_driver = {
|
||||
.driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET |
|
||||
DRIVER_GEM | DRIVER_PRIME,
|
||||
.load = rockchip_drm_load,
|
||||
.unload = rockchip_drm_unload,
|
||||
.open = rockchip_drm_open,
|
||||
.preclose = rockchip_drm_preclose,
|
||||
.lastclose = rockchip_drm_lastclose,
|
||||
.postclose = rockchip_drm_postclose,
|
||||
.get_vblank_counter = drm_vblank_count,
|
||||
.enable_vblank = rockchip_drm_crtc_enable_vblank,
|
||||
.disable_vblank = rockchip_drm_crtc_disable_vblank,
|
||||
.gem_init_object = rockchip_drm_gem_init_object,
|
||||
.gem_free_object = rockchip_drm_gem_free_object,
|
||||
.gem_vm_ops = &rockchip_drm_gem_vm_ops,
|
||||
.dumb_create = rockchip_drm_gem_dumb_create,
|
||||
.dumb_map_offset = rockchip_drm_gem_dumb_map_offset,
|
||||
.dumb_destroy = rockchip_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 = rockchip_dmabuf_prime_export,
|
||||
.gem_prime_import = rockchip_dmabuf_prime_import,
|
||||
.ioctls = rockchip_ioctls,
|
||||
.fops = &rockchip_drm_driver_fops,
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
};
|
||||
|
||||
static int rockchip_drm_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
|
||||
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
rockchip_drm_driver.num_ioctls = DRM_ARRAY_SIZE(rockchip_ioctls);
|
||||
|
||||
return drm_platform_init(&rockchip_drm_driver, pdev);
|
||||
}
|
||||
|
||||
static int rockchip_drm_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
|
||||
drm_platform_exit(&rockchip_drm_driver, pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver rockchip_drm_platform_driver = {
|
||||
.probe = rockchip_drm_platform_probe,
|
||||
.remove = rockchip_drm_platform_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "rockchip-drm",
|
||||
},
|
||||
};
|
||||
|
||||
static int __init rockchip_drm_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
#ifdef CONFIG_DRM_RK3288_FIMD
|
||||
ret = platform_driver_register(&fimd_driver);
|
||||
if (ret < 0)
|
||||
goto out_fimd;
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_RK3188_FIMD
|
||||
ret = platform_driver_register(&fimd_driver);
|
||||
if (ret < 0)
|
||||
goto out_fimd;
|
||||
#endif
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
ret = platform_driver_register(&rockchip_drm_platform_driver);
|
||||
if (ret < 0)
|
||||
goto out_drm;
|
||||
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
rockchip_drm_pdev = platform_device_register_simple("rockchip-drm", -1,
|
||||
NULL, 0);
|
||||
if (IS_ERR(rockchip_drm_pdev)) {
|
||||
ret = PTR_ERR(rockchip_drm_pdev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
printk(KERN_ERR"----->yzq %s %d\n",__func__,__LINE__);
|
||||
return 0;
|
||||
|
||||
out:
|
||||
platform_driver_unregister(&rockchip_drm_platform_driver);
|
||||
out_drm:
|
||||
#ifdef CONFIG_DRM_RK3188_FIMD
|
||||
platform_driver_unregister(&fimd_driver);
|
||||
out_fimd:
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_RK3288_FIMD
|
||||
platform_driver_unregister(&fimd_driver);
|
||||
out_fimd:
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit rockchip_drm_exit(void)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
platform_device_unregister(rockchip_drm_pdev);
|
||||
|
||||
platform_driver_unregister(&rockchip_drm_platform_driver);
|
||||
}
|
||||
|
||||
module_init(rockchip_drm_init);
|
||||
module_exit(rockchip_drm_exit);
|
||||
350
drivers/gpu/drm/rockchip/rockchip_drm_drv.h
Normal file
350
drivers/gpu/drm/rockchip/rockchip_drm_drv.h
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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 _ROCKCHIP_DRM_DRV_H_
|
||||
#define _ROCKCHIP_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 rockchip_drm_overlay;
|
||||
struct drm_connector;
|
||||
|
||||
extern unsigned int drm_vblank_offdelay;
|
||||
|
||||
/* this enumerates display type. */
|
||||
enum rockchip_drm_output_type {
|
||||
ROCKCHIP_DISPLAY_TYPE_NONE,
|
||||
/* RGB or CPU Interface. */
|
||||
ROCKCHIP_DISPLAY_TYPE_LCD,
|
||||
/* HDMI Interface. */
|
||||
ROCKCHIP_DISPLAY_TYPE_HDMI,
|
||||
/* Virtual Display Interface. */
|
||||
ROCKCHIP_DISPLAY_TYPE_VIDI,
|
||||
};
|
||||
|
||||
/*
|
||||
* Exynos drm overlay ops structure.
|
||||
*
|
||||
* @mode_set: copy drm overlay info to hw specific overlay info.
|
||||
* @commit: apply hardware specific overlay data to registers.
|
||||
* @enable: enable hardware specific overlay.
|
||||
* @disable: disable hardware specific overlay.
|
||||
*/
|
||||
struct rockchip_drm_overlay_ops {
|
||||
void (*mode_set)(struct device *subdrv_dev,
|
||||
struct rockchip_drm_overlay *overlay);
|
||||
void (*commit)(struct device *subdrv_dev, int zpos);
|
||||
void (*enable)(struct device *subdrv_dev, int zpos);
|
||||
void (*disable)(struct device *subdrv_dev, int zpos);
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 rockchip SoC and its contents would be copied
|
||||
* to hardware specific overlay info.
|
||||
*/
|
||||
struct rockchip_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.
|
||||
*
|
||||
* @type: one of ROCKCHIP_DISPLAY_TYPE_LCD and HDMI.
|
||||
* @is_connected: check for that display is connected or not.
|
||||
* @get_edid: get edid modes from display driver.
|
||||
* @get_panel: get panel object from display driver.
|
||||
* @check_timing: check if timing is valid or not.
|
||||
* @power_on: display device on or off.
|
||||
*/
|
||||
struct rockchip_drm_display_ops {
|
||||
enum rockchip_drm_output_type type;
|
||||
bool (*is_connected)(struct device *dev);
|
||||
struct edid *(*get_edid)(struct device *dev,
|
||||
struct drm_connector *connector);
|
||||
void *(*get_panel)(struct device *dev);
|
||||
int (*check_timing)(struct device *dev, void *timing);
|
||||
int (*power_on)(struct device *dev, int mode);
|
||||
};
|
||||
|
||||
/*
|
||||
* Exynos drm manager ops
|
||||
*
|
||||
* @dpms: control device power.
|
||||
* @apply: set timing, vblank and overlay data to registers.
|
||||
* @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().
|
||||
* @get_max_resol: get maximum resolution to specific hardware.
|
||||
* @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.
|
||||
*/
|
||||
struct rockchip_drm_manager_ops {
|
||||
void (*dpms)(struct device *subdrv_dev, int mode);
|
||||
void (*apply)(struct device *subdrv_dev);
|
||||
void (*mode_fixup)(struct device *subdrv_dev,
|
||||
struct drm_connector *connector,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
void (*mode_set)(struct device *subdrv_dev, void *mode);
|
||||
void (*get_max_resol)(struct device *subdrv_dev, unsigned int *width,
|
||||
unsigned int *height);
|
||||
void (*commit)(struct device *subdrv_dev);
|
||||
int (*enable_vblank)(struct device *subdrv_dev);
|
||||
void (*disable_vblank)(struct device *subdrv_dev);
|
||||
void (*wait_for_vblank)(struct device *subdrv_dev);
|
||||
};
|
||||
|
||||
/*
|
||||
* Exynos drm common manager structure.
|
||||
*
|
||||
* @dev: pointer to device object for subdrv device driver.
|
||||
* sub drivers such as display controller or hdmi driver,
|
||||
* have their own device object.
|
||||
* @ops: pointer to callbacks for rockchip drm specific framebuffer.
|
||||
* these callbacks should be set by specific drivers such fimd
|
||||
* or hdmi driver and are used to control hardware global registers.
|
||||
* @overlay_ops: pointer to callbacks for rockchip drm specific framebuffer.
|
||||
* these callbacks should be set by specific drivers such fimd
|
||||
* or hdmi driver and are used to control hardware overlay reigsters.
|
||||
* @display: pointer to callbacks for rockchip drm specific framebuffer.
|
||||
* these callbacks should be set by specific drivers such fimd
|
||||
* or hdmi driver and are used to control display devices such as
|
||||
* analog tv, digital tv and lcd panel and also get timing data for them.
|
||||
*/
|
||||
struct rockchip_drm_manager {
|
||||
struct device *dev;
|
||||
int pipe;
|
||||
struct rockchip_drm_manager_ops *ops;
|
||||
struct rockchip_drm_overlay_ops *overlay_ops;
|
||||
struct rockchip_drm_display_ops *display_ops;
|
||||
};
|
||||
|
||||
struct rockchip_drm_g2d_private {
|
||||
struct device *dev;
|
||||
struct list_head inuse_cmdlist;
|
||||
struct list_head event_list;
|
||||
struct list_head userptr_list;
|
||||
};
|
||||
|
||||
struct rockchip_drm_ipp_private {
|
||||
struct device *dev;
|
||||
struct list_head event_list;
|
||||
};
|
||||
|
||||
struct drm_rockchip_file_private {
|
||||
struct rockchip_drm_g2d_private *g2d_priv;
|
||||
struct rockchip_drm_ipp_private *ipp_priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* @da_space_order: order to device address space.
|
||||
*/
|
||||
struct rockchip_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 long da_space_order;
|
||||
};
|
||||
|
||||
/*
|
||||
* Exynos drm sub driver structure.
|
||||
*
|
||||
* @list: sub driver has its own list object to register to rockchip 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 rockchip_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 rockchip 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.
|
||||
* @encoder: encoder object owned by this sub driver.
|
||||
* @connector: connector object owned by this sub driver.
|
||||
*/
|
||||
struct rockchip_drm_subdrv {
|
||||
struct list_head list;
|
||||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
struct rockchip_drm_manager *manager;
|
||||
|
||||
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);
|
||||
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
};
|
||||
|
||||
/*
|
||||
* this function calls a probe callback registered to sub driver list and
|
||||
* create its own encoder and connector and then set drm_device object
|
||||
* to global one.
|
||||
*/
|
||||
int rockchip_drm_device_register(struct drm_device *dev);
|
||||
/*
|
||||
* this function calls a remove callback registered to sub driver list and
|
||||
* destroy its own encoder and connetor.
|
||||
*/
|
||||
int rockchip_drm_device_unregister(struct drm_device *dev);
|
||||
|
||||
/*
|
||||
* this function would be called by sub drivers such as display controller
|
||||
* or hdmi driver to register this sub driver object to rockchip drm driver
|
||||
* and when a sub driver is registered to rockchip drm driver a probe callback
|
||||
* of the sub driver is called and creates its own encoder and connector.
|
||||
*/
|
||||
int rockchip_drm_subdrv_register(struct rockchip_drm_subdrv *drm_subdrv);
|
||||
|
||||
/* this function removes subdrv list from rockchip drm driver */
|
||||
int rockchip_drm_subdrv_unregister(struct rockchip_drm_subdrv *drm_subdrv);
|
||||
|
||||
int rockchip_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
|
||||
void rockchip_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
|
||||
|
||||
/*
|
||||
* this function registers rockchip drm hdmi platform device. It ensures only one
|
||||
* instance of the device is created.
|
||||
*/
|
||||
int rockchip_platform_device_hdmi_register(void);
|
||||
|
||||
/*
|
||||
* this function unregisters rockchip drm hdmi platform device if it exists.
|
||||
*/
|
||||
void rockchip_platform_device_hdmi_unregister(void);
|
||||
|
||||
/*
|
||||
* this function registers rockchip drm ipp platform device.
|
||||
*/
|
||||
int rockchip_platform_device_ipp_register(void);
|
||||
|
||||
/*
|
||||
* this function unregisters rockchip drm ipp platform device if it exists.
|
||||
*/
|
||||
void rockchip_platform_device_ipp_unregister(void);
|
||||
|
||||
extern struct platform_driver fimd_driver;
|
||||
extern struct platform_driver hdmi_driver;
|
||||
extern struct platform_driver mixer_driver;
|
||||
extern struct platform_driver rockchip_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
|
||||
518
drivers/gpu/drm/rockchip/rockchip_drm_encoder.c
Normal file
518
drivers/gpu/drm/rockchip/rockchip_drm_encoder.c
Normal file
|
|
@ -0,0 +1,518 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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.
|
||||
*/
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_encoder.h"
|
||||
#include "rockchip_drm_connector.h"
|
||||
|
||||
#define to_rockchip_encoder(x) container_of(x, struct rockchip_drm_encoder,\
|
||||
drm_encoder)
|
||||
|
||||
/*
|
||||
* rockchip specific encoder structure.
|
||||
*
|
||||
* @drm_encoder: encoder object.
|
||||
* @manager: specific encoder has its own manager to control a hardware
|
||||
* appropriately and we can access a hardware drawing on this manager.
|
||||
* @dpms: store the encoder dpms value.
|
||||
* @updated: indicate whether overlay data updating is needed or not.
|
||||
*/
|
||||
struct rockchip_drm_encoder {
|
||||
struct drm_crtc *old_crtc;
|
||||
struct drm_encoder drm_encoder;
|
||||
struct rockchip_drm_manager *manager;
|
||||
int dpms;
|
||||
bool updated;
|
||||
};
|
||||
|
||||
static void rockchip_drm_connector_power(struct drm_encoder *encoder, int mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_connector *connector;
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (rockchip_drm_best_encoder(connector) == encoder) {
|
||||
DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
|
||||
connector->base.id, mode);
|
||||
|
||||
rockchip_drm_display_power(connector, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rockchip_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct rockchip_drm_manager *manager = rockchip_drm_get_manager(encoder);
|
||||
struct rockchip_drm_manager_ops *manager_ops = manager->ops;
|
||||
struct rockchip_drm_encoder *rockchip_encoder = to_rockchip_encoder(encoder);
|
||||
|
||||
DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);
|
||||
|
||||
if (rockchip_encoder->dpms == mode) {
|
||||
DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
switch (mode) {
|
||||
case DRM_MODE_DPMS_ON:
|
||||
if (manager_ops && manager_ops->apply)
|
||||
if (!rockchip_encoder->updated)
|
||||
manager_ops->apply(manager->dev);
|
||||
|
||||
rockchip_drm_connector_power(encoder, mode);
|
||||
rockchip_encoder->dpms = mode;
|
||||
break;
|
||||
case DRM_MODE_DPMS_STANDBY:
|
||||
case DRM_MODE_DPMS_SUSPEND:
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
rockchip_drm_connector_power(encoder, mode);
|
||||
rockchip_encoder->dpms = mode;
|
||||
rockchip_encoder->updated = false;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("unspecified mode %d\n", mode);
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
static bool
|
||||
rockchip_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 drm_connector *connector;
|
||||
struct rockchip_drm_manager *manager = rockchip_drm_get_manager(encoder);
|
||||
struct rockchip_drm_manager_ops *manager_ops = manager->ops;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (connector->encoder == encoder)
|
||||
if (manager_ops && manager_ops->mode_fixup)
|
||||
manager_ops->mode_fixup(manager->dev, connector,
|
||||
mode, adjusted_mode);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void disable_plane_to_crtc(struct drm_device *dev,
|
||||
struct drm_crtc *old_crtc,
|
||||
struct drm_crtc *new_crtc)
|
||||
{
|
||||
struct drm_plane *plane;
|
||||
|
||||
/*
|
||||
* if old_crtc isn't same as encoder->crtc then it means that
|
||||
* user changed crtc id to another one so the plane to old_crtc
|
||||
* should be disabled and plane->crtc should be set to new_crtc
|
||||
* (encoder->crtc)
|
||||
*/
|
||||
list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
|
||||
if (plane->crtc == old_crtc) {
|
||||
/*
|
||||
* do not change below call order.
|
||||
*
|
||||
* plane->funcs->disable_plane call checks
|
||||
* if encoder->crtc is same as plane->crtc and if same
|
||||
* then overlay_ops->disable callback will be called
|
||||
* to diasble current hw overlay so plane->crtc should
|
||||
* have new_crtc because new_crtc was set to
|
||||
* encoder->crtc in advance.
|
||||
*/
|
||||
plane->crtc = new_crtc;
|
||||
plane->funcs->disable_plane(plane);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rockchip_drm_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_connector *connector;
|
||||
struct rockchip_drm_manager *manager;
|
||||
struct rockchip_drm_manager_ops *manager_ops;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (connector->encoder == encoder) {
|
||||
struct rockchip_drm_encoder *rockchip_encoder;
|
||||
|
||||
rockchip_encoder = to_rockchip_encoder(encoder);
|
||||
|
||||
if (rockchip_encoder->old_crtc != encoder->crtc &&
|
||||
rockchip_encoder->old_crtc) {
|
||||
|
||||
/*
|
||||
* disable a plane to old crtc and change
|
||||
* crtc of the plane to new one.
|
||||
*/
|
||||
disable_plane_to_crtc(dev,
|
||||
rockchip_encoder->old_crtc,
|
||||
encoder->crtc);
|
||||
}
|
||||
|
||||
manager = rockchip_drm_get_manager(encoder);
|
||||
manager_ops = manager->ops;
|
||||
|
||||
if (manager_ops && manager_ops->mode_set)
|
||||
manager_ops->mode_set(manager->dev,
|
||||
adjusted_mode);
|
||||
|
||||
rockchip_encoder->old_crtc = encoder->crtc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rockchip_drm_encoder_prepare(struct drm_encoder *encoder)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* drm framework doesn't check NULL. */
|
||||
}
|
||||
|
||||
static void rockchip_drm_encoder_commit(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rockchip_drm_encoder *rockchip_encoder = to_rockchip_encoder(encoder);
|
||||
struct rockchip_drm_manager *manager = rockchip_encoder->manager;
|
||||
struct rockchip_drm_manager_ops *manager_ops = manager->ops;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (manager_ops && manager_ops->commit)
|
||||
manager_ops->commit(manager->dev);
|
||||
|
||||
/*
|
||||
* this will avoid one issue that overlay data is updated to
|
||||
* real hardware two times.
|
||||
* And this variable will be used to check if the data was
|
||||
* already updated or not by rockchip_drm_encoder_dpms function.
|
||||
*/
|
||||
rockchip_encoder->updated = true;
|
||||
|
||||
/*
|
||||
* In case of setcrtc, there is no way to update encoder's dpms
|
||||
* so update it here.
|
||||
*/
|
||||
rockchip_encoder->dpms = DRM_MODE_DPMS_ON;
|
||||
}
|
||||
|
||||
void rockchip_drm_encoder_complete_scanout(struct drm_framebuffer *fb)
|
||||
{
|
||||
struct rockchip_drm_encoder *rockchip_encoder;
|
||||
struct rockchip_drm_manager_ops *ops;
|
||||
struct drm_device *dev = fb->dev;
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
/*
|
||||
* make sure that overlay data are updated to real hardware
|
||||
* for all encoders.
|
||||
*/
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
rockchip_encoder = to_rockchip_encoder(encoder);
|
||||
ops = rockchip_encoder->manager->ops;
|
||||
|
||||
/*
|
||||
* wait for vblank interrupt
|
||||
* - this makes sure that overlay data are updated to
|
||||
* real hardware.
|
||||
*/
|
||||
if (ops->wait_for_vblank)
|
||||
ops->wait_for_vblank(rockchip_encoder->manager->dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void rockchip_drm_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_plane *plane;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
|
||||
rockchip_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
|
||||
|
||||
/* all planes connected to this encoder should be also disabled. */
|
||||
list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
|
||||
if (plane->crtc == encoder->crtc)
|
||||
plane->funcs->disable_plane(plane);
|
||||
}
|
||||
}
|
||||
|
||||
static struct drm_encoder_helper_funcs rockchip_encoder_helper_funcs = {
|
||||
.dpms = rockchip_drm_encoder_dpms,
|
||||
.mode_fixup = rockchip_drm_encoder_mode_fixup,
|
||||
.mode_set = rockchip_drm_encoder_mode_set,
|
||||
.prepare = rockchip_drm_encoder_prepare,
|
||||
.commit = rockchip_drm_encoder_commit,
|
||||
.disable = rockchip_drm_encoder_disable,
|
||||
};
|
||||
|
||||
static void rockchip_drm_encoder_destroy(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rockchip_drm_encoder *rockchip_encoder =
|
||||
to_rockchip_encoder(encoder);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
rockchip_encoder->manager->pipe = -1;
|
||||
|
||||
drm_encoder_cleanup(encoder);
|
||||
kfree(rockchip_encoder);
|
||||
}
|
||||
|
||||
static struct drm_encoder_funcs rockchip_encoder_funcs = {
|
||||
.destroy = rockchip_drm_encoder_destroy,
|
||||
};
|
||||
|
||||
static unsigned int rockchip_drm_encoder_clones(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_encoder *clone;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct rockchip_drm_encoder *rockchip_encoder = to_rockchip_encoder(encoder);
|
||||
struct rockchip_drm_display_ops *display_ops =
|
||||
rockchip_encoder->manager->display_ops;
|
||||
unsigned int clone_mask = 0;
|
||||
int cnt = 0;
|
||||
|
||||
list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
|
||||
switch (display_ops->type) {
|
||||
case ROCKCHIP_DISPLAY_TYPE_LCD:
|
||||
case ROCKCHIP_DISPLAY_TYPE_HDMI:
|
||||
case ROCKCHIP_DISPLAY_TYPE_VIDI:
|
||||
clone_mask |= (1 << (cnt++));
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return clone_mask;
|
||||
}
|
||||
|
||||
void rockchip_drm_encoder_setup(struct drm_device *dev)
|
||||
{
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
|
||||
encoder->possible_clones = rockchip_drm_encoder_clones(encoder);
|
||||
}
|
||||
|
||||
struct drm_encoder *
|
||||
rockchip_drm_encoder_create(struct drm_device *dev,
|
||||
struct rockchip_drm_manager *manager,
|
||||
unsigned int possible_crtcs)
|
||||
{
|
||||
struct drm_encoder *encoder;
|
||||
struct rockchip_drm_encoder *rockchip_encoder;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (!manager || !possible_crtcs)
|
||||
return NULL;
|
||||
|
||||
if (!manager->dev)
|
||||
return NULL;
|
||||
|
||||
rockchip_encoder = kzalloc(sizeof(*rockchip_encoder), GFP_KERNEL);
|
||||
if (!rockchip_encoder) {
|
||||
DRM_ERROR("failed to allocate encoder\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rockchip_encoder->dpms = DRM_MODE_DPMS_OFF;
|
||||
rockchip_encoder->manager = manager;
|
||||
encoder = &rockchip_encoder->drm_encoder;
|
||||
encoder->possible_crtcs = possible_crtcs;
|
||||
|
||||
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
|
||||
|
||||
drm_encoder_init(dev, encoder, &rockchip_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS);
|
||||
|
||||
drm_encoder_helper_add(encoder, &rockchip_encoder_helper_funcs);
|
||||
|
||||
DRM_DEBUG_KMS("encoder has been created\n");
|
||||
|
||||
return encoder;
|
||||
}
|
||||
|
||||
struct rockchip_drm_manager *rockchip_drm_get_manager(struct drm_encoder *encoder)
|
||||
{
|
||||
return to_rockchip_encoder(encoder)->manager;
|
||||
}
|
||||
|
||||
void rockchip_drm_fn_encoder(struct drm_crtc *crtc, void *data,
|
||||
void (*fn)(struct drm_encoder *, void *))
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_encoder *encoder;
|
||||
struct rockchip_drm_private *private = dev->dev_private;
|
||||
struct rockchip_drm_manager *manager;
|
||||
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
/*
|
||||
* if crtc is detached from encoder, check pipe,
|
||||
* otherwise check crtc attached to encoder
|
||||
*/
|
||||
if (!encoder->crtc) {
|
||||
manager = to_rockchip_encoder(encoder)->manager;
|
||||
if (manager->pipe < 0 ||
|
||||
private->crtc[manager->pipe] != crtc)
|
||||
continue;
|
||||
} else {
|
||||
if (encoder->crtc != crtc)
|
||||
continue;
|
||||
}
|
||||
|
||||
fn(encoder, data);
|
||||
}
|
||||
}
|
||||
|
||||
void rockchip_drm_enable_vblank(struct drm_encoder *encoder, void *data)
|
||||
{
|
||||
struct rockchip_drm_manager *manager =
|
||||
to_rockchip_encoder(encoder)->manager;
|
||||
struct rockchip_drm_manager_ops *manager_ops = manager->ops;
|
||||
int crtc = *(int *)data;
|
||||
|
||||
if (manager->pipe != crtc)
|
||||
return;
|
||||
|
||||
if (manager_ops->enable_vblank)
|
||||
manager_ops->enable_vblank(manager->dev);
|
||||
}
|
||||
|
||||
void rockchip_drm_disable_vblank(struct drm_encoder *encoder, void *data)
|
||||
{
|
||||
struct rockchip_drm_manager *manager =
|
||||
to_rockchip_encoder(encoder)->manager;
|
||||
struct rockchip_drm_manager_ops *manager_ops = manager->ops;
|
||||
int crtc = *(int *)data;
|
||||
|
||||
if (manager->pipe != crtc)
|
||||
return;
|
||||
|
||||
if (manager_ops->disable_vblank)
|
||||
manager_ops->disable_vblank(manager->dev);
|
||||
}
|
||||
|
||||
void rockchip_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
|
||||
{
|
||||
struct rockchip_drm_encoder *rockchip_encoder = to_rockchip_encoder(encoder);
|
||||
struct rockchip_drm_manager *manager = rockchip_encoder->manager;
|
||||
struct rockchip_drm_manager_ops *manager_ops = manager->ops;
|
||||
int mode = *(int *)data;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (manager_ops && manager_ops->dpms)
|
||||
manager_ops->dpms(manager->dev, mode);
|
||||
|
||||
/*
|
||||
* if this condition is ok then it means that the crtc is already
|
||||
* detached from encoder and last function for detaching is properly
|
||||
* done, so clear pipe from manager to prevent repeated call.
|
||||
*/
|
||||
if (mode > DRM_MODE_DPMS_ON) {
|
||||
if (!encoder->crtc)
|
||||
manager->pipe = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void rockchip_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data)
|
||||
{
|
||||
struct rockchip_drm_manager *manager =
|
||||
to_rockchip_encoder(encoder)->manager;
|
||||
int pipe = *(int *)data;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/*
|
||||
* when crtc is detached from encoder, this pipe is used
|
||||
* to select manager operation
|
||||
*/
|
||||
manager->pipe = pipe;
|
||||
}
|
||||
|
||||
void rockchip_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
|
||||
{
|
||||
struct rockchip_drm_manager *manager =
|
||||
to_rockchip_encoder(encoder)->manager;
|
||||
struct rockchip_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
||||
struct rockchip_drm_overlay *overlay = data;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (overlay_ops && overlay_ops->mode_set)
|
||||
overlay_ops->mode_set(manager->dev, overlay);
|
||||
}
|
||||
|
||||
void rockchip_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
|
||||
{
|
||||
struct rockchip_drm_manager *manager =
|
||||
to_rockchip_encoder(encoder)->manager;
|
||||
struct rockchip_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
||||
int zpos = DEFAULT_ZPOS;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (data)
|
||||
zpos = *(int *)data;
|
||||
|
||||
if (overlay_ops && overlay_ops->commit)
|
||||
overlay_ops->commit(manager->dev, zpos);
|
||||
}
|
||||
|
||||
void rockchip_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
|
||||
{
|
||||
struct rockchip_drm_manager *manager =
|
||||
to_rockchip_encoder(encoder)->manager;
|
||||
struct rockchip_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
||||
int zpos = DEFAULT_ZPOS;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (data)
|
||||
zpos = *(int *)data;
|
||||
|
||||
if (overlay_ops && overlay_ops->enable)
|
||||
overlay_ops->enable(manager->dev, zpos);
|
||||
}
|
||||
|
||||
void rockchip_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
|
||||
{
|
||||
struct rockchip_drm_manager *manager =
|
||||
to_rockchip_encoder(encoder)->manager;
|
||||
struct rockchip_drm_overlay_ops *overlay_ops = manager->overlay_ops;
|
||||
int zpos = DEFAULT_ZPOS;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (data)
|
||||
zpos = *(int *)data;
|
||||
|
||||
if (overlay_ops && overlay_ops->disable)
|
||||
overlay_ops->disable(manager->dev, zpos);
|
||||
}
|
||||
37
drivers/gpu/drm/rockchip/rockchip_drm_encoder.h
Normal file
37
drivers/gpu/drm/rockchip/rockchip_drm_encoder.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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 _ROCKCHIP_DRM_ENCODER_H_
|
||||
#define _ROCKCHIP_DRM_ENCODER_H_
|
||||
|
||||
struct rockchip_drm_manager;
|
||||
|
||||
void rockchip_drm_encoder_setup(struct drm_device *dev);
|
||||
struct drm_encoder *rockchip_drm_encoder_create(struct drm_device *dev,
|
||||
struct rockchip_drm_manager *mgr,
|
||||
unsigned int possible_crtcs);
|
||||
struct rockchip_drm_manager *
|
||||
rockchip_drm_get_manager(struct drm_encoder *encoder);
|
||||
void rockchip_drm_fn_encoder(struct drm_crtc *crtc, void *data,
|
||||
void (*fn)(struct drm_encoder *, void *));
|
||||
void rockchip_drm_enable_vblank(struct drm_encoder *encoder, void *data);
|
||||
void rockchip_drm_disable_vblank(struct drm_encoder *encoder, void *data);
|
||||
void rockchip_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
|
||||
void rockchip_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data);
|
||||
void rockchip_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data);
|
||||
void rockchip_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data);
|
||||
void rockchip_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data);
|
||||
void rockchip_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data);
|
||||
void rockchip_drm_encoder_complete_scanout(struct drm_framebuffer *fb);
|
||||
|
||||
#endif
|
||||
336
drivers/gpu/drm/rockchip/rockchip_drm_fb.c
Normal file
336
drivers/gpu/drm/rockchip/rockchip_drm_fb.c
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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.
|
||||
*/
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <uapi/drm/rockchip_drm.h>
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_fb.h"
|
||||
#include "rockchip_drm_gem.h"
|
||||
#include "rockchip_drm_iommu.h"
|
||||
#include "rockchip_drm_encoder.h"
|
||||
|
||||
#define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)
|
||||
|
||||
/*
|
||||
* rockchip specific framebuffer structure.
|
||||
*
|
||||
* @fb: drm framebuffer obejct.
|
||||
* @buf_cnt: a buffer count to drm framebuffer.
|
||||
* @rockchip_gem_obj: array of rockchip specific gem object containing a gem object.
|
||||
*/
|
||||
struct rockchip_drm_fb {
|
||||
struct drm_framebuffer fb;
|
||||
unsigned int buf_cnt;
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj[MAX_FB_BUFFER];
|
||||
};
|
||||
|
||||
static int check_fb_gem_memory_type(struct drm_device *drm_dev,
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj)
|
||||
{
|
||||
unsigned int flags;
|
||||
|
||||
/*
|
||||
* if rockchip drm driver supports iommu then framebuffer can use
|
||||
* all the buffer types.
|
||||
*/
|
||||
if (is_drm_iommu_supported(drm_dev))
|
||||
return 0;
|
||||
|
||||
flags = rockchip_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 rockchip_drm_fb_destroy(struct drm_framebuffer *fb)
|
||||
{
|
||||
struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
|
||||
unsigned int i;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* make sure that overlay data are updated before relesing fb. */
|
||||
rockchip_drm_encoder_complete_scanout(fb);
|
||||
|
||||
drm_framebuffer_cleanup(fb);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rockchip_fb->rockchip_gem_obj); i++) {
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
if (rockchip_fb->rockchip_gem_obj[i] == NULL)
|
||||
continue;
|
||||
|
||||
obj = &rockchip_fb->rockchip_gem_obj[i]->base;
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
}
|
||||
|
||||
kfree(rockchip_fb);
|
||||
rockchip_fb = NULL;
|
||||
}
|
||||
|
||||
static int rockchip_drm_fb_create_handle(struct drm_framebuffer *fb,
|
||||
struct drm_file *file_priv,
|
||||
unsigned int *handle)
|
||||
{
|
||||
struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* This fb should have only one gem object. */
|
||||
if (WARN_ON(rockchip_fb->buf_cnt != 1))
|
||||
return -EINVAL;
|
||||
|
||||
return drm_gem_handle_create(file_priv,
|
||||
&rockchip_fb->rockchip_gem_obj[0]->base, handle);
|
||||
}
|
||||
|
||||
static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb,
|
||||
struct drm_file *file_priv, unsigned flags,
|
||||
unsigned color, struct drm_clip_rect *clips,
|
||||
unsigned num_clips)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* TODO */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
|
||||
.destroy = rockchip_drm_fb_destroy,
|
||||
.create_handle = rockchip_drm_fb_create_handle,
|
||||
.dirty = rockchip_drm_fb_dirty,
|
||||
};
|
||||
|
||||
void rockchip_drm_fb_set_buf_cnt(struct drm_framebuffer *fb,
|
||||
unsigned int cnt)
|
||||
{
|
||||
struct rockchip_drm_fb *rockchip_fb;
|
||||
|
||||
rockchip_fb = to_rockchip_fb(fb);
|
||||
|
||||
rockchip_fb->buf_cnt = cnt;
|
||||
}
|
||||
|
||||
unsigned int rockchip_drm_fb_get_buf_cnt(struct drm_framebuffer *fb)
|
||||
{
|
||||
struct rockchip_drm_fb *rockchip_fb;
|
||||
|
||||
rockchip_fb = to_rockchip_fb(fb);
|
||||
|
||||
return rockchip_fb->buf_cnt;
|
||||
}
|
||||
|
||||
struct drm_framebuffer *
|
||||
rockchip_drm_framebuffer_init(struct drm_device *dev,
|
||||
struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj)
|
||||
{
|
||||
struct rockchip_drm_fb *rockchip_fb;
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj;
|
||||
int ret;
|
||||
|
||||
rockchip_gem_obj = to_rockchip_gem_obj(obj);
|
||||
|
||||
ret = check_fb_gem_memory_type(dev, rockchip_gem_obj);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("cannot use this gem memory type for fb.\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
rockchip_fb = kzalloc(sizeof(*rockchip_fb), GFP_KERNEL);
|
||||
if (!rockchip_fb) {
|
||||
DRM_ERROR("failed to allocate rockchip drm framebuffer\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
drm_helper_mode_fill_fb_struct(&rockchip_fb->fb, mode_cmd);
|
||||
rockchip_fb->rockchip_gem_obj[0] = rockchip_gem_obj;
|
||||
|
||||
ret = drm_framebuffer_init(dev, &rockchip_fb->fb, &rockchip_drm_fb_funcs);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to initialize framebuffer\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return &rockchip_fb->fb;
|
||||
}
|
||||
|
||||
static u32 rockchip_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 *
|
||||
rockchip_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 rockchip_drm_gem_obj *rockchip_gem_obj;
|
||||
struct rockchip_drm_fb *rockchip_fb;
|
||||
int i, ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
rockchip_fb = kzalloc(sizeof(*rockchip_fb), GFP_KERNEL);
|
||||
if (!rockchip_fb) {
|
||||
DRM_ERROR("failed to allocate rockchip drm framebuffer\n");
|
||||
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(&rockchip_fb->fb, mode_cmd);
|
||||
rockchip_fb->rockchip_gem_obj[0] = to_rockchip_gem_obj(obj);
|
||||
rockchip_fb->buf_cnt = rockchip_drm_format_num_buffers(mode_cmd);
|
||||
|
||||
DRM_DEBUG_KMS("buf_cnt = %d\n", rockchip_fb->buf_cnt);
|
||||
|
||||
for (i = 1; i < rockchip_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;
|
||||
rockchip_fb->buf_cnt = i;
|
||||
goto err_unreference;
|
||||
}
|
||||
|
||||
rockchip_gem_obj = to_rockchip_gem_obj(obj);
|
||||
rockchip_fb->rockchip_gem_obj[i] = rockchip_gem_obj;
|
||||
|
||||
ret = check_fb_gem_memory_type(dev, rockchip_gem_obj);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("cannot use this gem memory type for fb.\n");
|
||||
goto err_unreference;
|
||||
}
|
||||
}
|
||||
|
||||
ret = drm_framebuffer_init(dev, &rockchip_fb->fb, &rockchip_drm_fb_funcs);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to init framebuffer.\n");
|
||||
goto err_unreference;
|
||||
}
|
||||
|
||||
return &rockchip_fb->fb;
|
||||
|
||||
err_unreference:
|
||||
for (i = 0; i < rockchip_fb->buf_cnt; i++) {
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
obj = &rockchip_fb->rockchip_gem_obj[i]->base;
|
||||
if (obj)
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
}
|
||||
err_free:
|
||||
kfree(rockchip_fb);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
struct rockchip_drm_gem_buf *rockchip_drm_fb_buffer(struct drm_framebuffer *fb,
|
||||
int index)
|
||||
{
|
||||
struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
|
||||
struct rockchip_drm_gem_buf *buffer;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (index >= MAX_FB_BUFFER)
|
||||
return NULL;
|
||||
|
||||
buffer = rockchip_fb->rockchip_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 rockchip_drm_output_poll_changed(struct drm_device *dev)
|
||||
{
|
||||
struct rockchip_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);
|
||||
}
|
||||
|
||||
static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
|
||||
.fb_create = rockchip_user_fb_create,
|
||||
.output_poll_changed = rockchip_drm_output_poll_changed,
|
||||
};
|
||||
|
||||
void rockchip_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 = &rockchip_drm_mode_config_funcs;
|
||||
}
|
||||
34
drivers/gpu/drm/rockchip/rockchip_drm_fb.h
Normal file
34
drivers/gpu/drm/rockchip/rockchip_drm_fb.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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 _ROCKCHIP_DRM_FB_H_
|
||||
#define _ROCKCHIP_DRM_FB_H
|
||||
|
||||
struct drm_framebuffer *
|
||||
rockchip_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 rockchip_drm_gem_buf *rockchip_drm_fb_buffer(struct drm_framebuffer *fb,
|
||||
int index);
|
||||
|
||||
void rockchip_drm_mode_config_init(struct drm_device *dev);
|
||||
|
||||
/* set a buffer count to drm framebuffer. */
|
||||
void rockchip_drm_fb_set_buf_cnt(struct drm_framebuffer *fb,
|
||||
unsigned int cnt);
|
||||
|
||||
/* get a buffer count to drm framebuffer. */
|
||||
unsigned int rockchip_drm_fb_get_buf_cnt(struct drm_framebuffer *fb);
|
||||
|
||||
#endif
|
||||
355
drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
Normal file
355
drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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.
|
||||
*/
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_fb.h"
|
||||
#include "rockchip_drm_gem.h"
|
||||
#include "rockchip_drm_iommu.h"
|
||||
|
||||
#define MAX_CONNECTOR 4
|
||||
#define PREFERRED_BPP 32
|
||||
|
||||
#define to_rockchip_fbdev(x) container_of(x, struct rockchip_drm_fbdev,\
|
||||
drm_fb_helper)
|
||||
|
||||
struct rockchip_drm_fbdev {
|
||||
struct drm_fb_helper drm_fb_helper;
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj;
|
||||
};
|
||||
|
||||
static int rockchip_drm_fb_mmap(struct fb_info *info,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct drm_fb_helper *helper = info->par;
|
||||
struct rockchip_drm_fbdev *rockchip_fbd = to_rockchip_fbdev(helper);
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj = rockchip_fbd->rockchip_gem_obj;
|
||||
struct rockchip_drm_gem_buf *buffer = rockchip_gem_obj->buffer;
|
||||
unsigned long vm_size;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __func__);
|
||||
|
||||
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 rockchip_drm_fb_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.fb_mmap = rockchip_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 rockchip_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 rockchip_drm_gem_buf *buffer;
|
||||
unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
|
||||
unsigned long offset;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
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 = rockchip_drm_fb_buffer(fb, 0);
|
||||
if (!buffer) {
|
||||
DRM_LOG_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 = 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 = 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. */
|
||||
rockchip_drm_fb_set_buf_cnt(fb, 1);
|
||||
|
||||
offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);
|
||||
offset += fbi->var.yoffset * fb->pitches[0];
|
||||
|
||||
dev->mode_config.fb_base = (resource_size_t)buffer->dma_addr;
|
||||
fbi->screen_base = buffer->kvaddr + offset;
|
||||
if (is_drm_iommu_supported(dev))
|
||||
fbi->fix.smem_start = (unsigned long)
|
||||
(page_to_phys(sg_page(buffer->sgt->sgl)) + offset);
|
||||
else
|
||||
fbi->fix.smem_start = (unsigned long)buffer->dma_addr;
|
||||
|
||||
fbi->screen_size = size;
|
||||
fbi->fix.smem_len = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size *sizes)
|
||||
{
|
||||
struct rockchip_drm_fbdev *rockchip_fbdev = to_rockchip_fbdev(helper);
|
||||
struct rockchip_drm_gem_obj *rockchip_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("%s\n", __FILE__);
|
||||
|
||||
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;
|
||||
|
||||
/* 0 means to allocate physically continuous memory */
|
||||
rockchip_gem_obj = rockchip_drm_gem_create(dev, 0, size);
|
||||
if (IS_ERR(rockchip_gem_obj)) {
|
||||
ret = PTR_ERR(rockchip_gem_obj);
|
||||
goto err_release_framebuffer;
|
||||
}
|
||||
|
||||
rockchip_fbdev->rockchip_gem_obj = rockchip_gem_obj;
|
||||
|
||||
helper->fb = rockchip_drm_framebuffer_init(dev, &mode_cmd,
|
||||
&rockchip_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 = &rockchip_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 = rockchip_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:
|
||||
rockchip_drm_gem_destroy(rockchip_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 struct drm_fb_helper_funcs rockchip_drm_fb_helper_funcs = {
|
||||
.fb_probe = rockchip_drm_fbdev_create,
|
||||
};
|
||||
|
||||
int rockchip_drm_fbdev_init(struct drm_device *dev)
|
||||
{
|
||||
struct rockchip_drm_fbdev *fbdev;
|
||||
struct rockchip_drm_private *private = dev->dev_private;
|
||||
struct drm_fb_helper *helper;
|
||||
unsigned int num_crtc;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
|
||||
return 0;
|
||||
|
||||
fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
|
||||
if (!fbdev) {
|
||||
DRM_ERROR("failed to allocate drm fbdev.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
private->fb_helper = helper = &fbdev->drm_fb_helper;
|
||||
helper->funcs = &rockchip_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 rockchip_drm_fbdev_destroy(struct drm_device *dev,
|
||||
struct drm_fb_helper *fb_helper)
|
||||
{
|
||||
struct rockchip_drm_fbdev *rockchip_fbd = to_rockchip_fbdev(fb_helper);
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj = rockchip_fbd->rockchip_gem_obj;
|
||||
struct drm_framebuffer *fb;
|
||||
|
||||
if (is_drm_iommu_supported(dev) && rockchip_gem_obj->buffer->kvaddr)
|
||||
vunmap(rockchip_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 rockchip_drm_fbdev_fini(struct drm_device *dev)
|
||||
{
|
||||
struct rockchip_drm_private *private = dev->dev_private;
|
||||
struct rockchip_drm_fbdev *fbdev;
|
||||
|
||||
if (!private || !private->fb_helper)
|
||||
return;
|
||||
|
||||
fbdev = to_rockchip_fbdev(private->fb_helper);
|
||||
|
||||
if (fbdev->rockchip_gem_obj)
|
||||
rockchip_drm_gem_destroy(fbdev->rockchip_gem_obj);
|
||||
|
||||
rockchip_drm_fbdev_destroy(dev, private->fb_helper);
|
||||
kfree(fbdev);
|
||||
private->fb_helper = NULL;
|
||||
}
|
||||
|
||||
void rockchip_drm_fbdev_restore_mode(struct drm_device *dev)
|
||||
{
|
||||
struct rockchip_drm_private *private = dev->dev_private;
|
||||
|
||||
if (!private || !private->fb_helper)
|
||||
return;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
drm_fb_helper_restore_fbdev_mode(private->fb_helper);
|
||||
drm_modeset_unlock_all(dev);
|
||||
}
|
||||
21
drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h
Normal file
21
drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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 _ROCKCHIP_DRM_FBDEV_H_
|
||||
#define _ROCKCHIP_DRM_FBDEV_H_
|
||||
|
||||
int rockchip_drm_fbdev_init(struct drm_device *dev);
|
||||
int rockchip_drm_fbdev_reinit(struct drm_device *dev);
|
||||
void rockchip_drm_fbdev_fini(struct drm_device *dev);
|
||||
void rockchip_drm_fbdev_restore_mode(struct drm_device *dev);
|
||||
|
||||
#endif
|
||||
817
drivers/gpu/drm/rockchip/rockchip_drm_gem.c
Normal file
817
drivers/gpu/drm/rockchip/rockchip_drm_gem.c
Normal file
|
|
@ -0,0 +1,817 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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.
|
||||
*/
|
||||
#include <drm/drmP.h>
|
||||
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <drm/rockchip_drm.h>
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_gem.h"
|
||||
#include "rockchip_drm_buf.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 & ~(ROCKCHIP_BO_MASK)) {
|
||||
DRM_ERROR("invalid flags.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void update_vm_cache_attr(struct rockchip_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 & ROCKCHIP_BO_CACHABLE)
|
||||
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
|
||||
else if (obj->flags & ROCKCHIP_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 rockchip_drm_gem_map_buf(struct drm_gem_object *obj,
|
||||
struct vm_area_struct *vma,
|
||||
unsigned long f_vaddr,
|
||||
pgoff_t page_offset)
|
||||
{
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj = to_rockchip_gem_obj(obj);
|
||||
struct rockchip_drm_gem_buf *buf = rockchip_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 rockchip_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 rockchip_drm_gem_destroy(struct rockchip_drm_gem_obj *rockchip_gem_obj)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
struct rockchip_drm_gem_buf *buf;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
obj = &rockchip_gem_obj->base;
|
||||
buf = rockchip_gem_obj->buffer;
|
||||
|
||||
DRM_DEBUG_KMS("handle count = %d\n", atomic_read(&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;
|
||||
|
||||
rockchip_drm_free_buf(obj->dev, rockchip_gem_obj->flags, buf);
|
||||
|
||||
out:
|
||||
rockchip_drm_fini_buf(obj->dev, buf);
|
||||
rockchip_gem_obj->buffer = NULL;
|
||||
|
||||
if (obj->map_list.map)
|
||||
drm_gem_free_mmap_offset(obj);
|
||||
|
||||
/* release file pointer to gem object. */
|
||||
drm_gem_object_release(obj);
|
||||
|
||||
kfree(rockchip_gem_obj);
|
||||
rockchip_gem_obj = NULL;
|
||||
}
|
||||
|
||||
unsigned long rockchip_drm_gem_get_size(struct drm_device *dev,
|
||||
unsigned int gem_handle,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct rockchip_drm_gem_obj *rockchip_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;
|
||||
}
|
||||
|
||||
rockchip_gem_obj = to_rockchip_gem_obj(obj);
|
||||
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
|
||||
return rockchip_gem_obj->buffer->size;
|
||||
}
|
||||
|
||||
|
||||
struct rockchip_drm_gem_obj *rockchip_drm_gem_init(struct drm_device *dev,
|
||||
unsigned long size)
|
||||
{
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj;
|
||||
struct drm_gem_object *obj;
|
||||
int ret;
|
||||
|
||||
rockchip_gem_obj = kzalloc(sizeof(*rockchip_gem_obj), GFP_KERNEL);
|
||||
if (!rockchip_gem_obj) {
|
||||
DRM_ERROR("failed to allocate rockchip gem object\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rockchip_gem_obj->size = size;
|
||||
obj = &rockchip_gem_obj->base;
|
||||
|
||||
ret = drm_gem_object_init(dev, obj, size);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to initialize gem object\n");
|
||||
kfree(rockchip_gem_obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp);
|
||||
|
||||
return rockchip_gem_obj;
|
||||
}
|
||||
|
||||
struct rockchip_drm_gem_obj *rockchip_drm_gem_create(struct drm_device *dev,
|
||||
unsigned int flags,
|
||||
unsigned long size)
|
||||
{
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj;
|
||||
struct rockchip_drm_gem_buf *buf;
|
||||
int ret;
|
||||
|
||||
if (!size) {
|
||||
DRM_ERROR("invalid size.\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
size = roundup_gem_size(size, flags);
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
ret = check_gem_flags(flags);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
buf = rockchip_drm_init_buf(dev, size);
|
||||
if (!buf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
rockchip_gem_obj = rockchip_drm_gem_init(dev, size);
|
||||
if (!rockchip_gem_obj) {
|
||||
ret = -ENOMEM;
|
||||
goto err_fini_buf;
|
||||
}
|
||||
|
||||
rockchip_gem_obj->buffer = buf;
|
||||
|
||||
/* set memory type and cache attribute from user side. */
|
||||
rockchip_gem_obj->flags = flags;
|
||||
|
||||
ret = rockchip_drm_alloc_buf(dev, buf, flags);
|
||||
if (ret < 0) {
|
||||
drm_gem_object_release(&rockchip_gem_obj->base);
|
||||
goto err_fini_buf;
|
||||
}
|
||||
|
||||
return rockchip_gem_obj;
|
||||
|
||||
err_fini_buf:
|
||||
rockchip_drm_fini_buf(dev, buf);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
int rockchip_drm_gem_create_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_rockchip_gem_create *args = data;
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
rockchip_gem_obj = rockchip_drm_gem_create(dev, args->flags, args->size);
|
||||
if (IS_ERR(rockchip_gem_obj))
|
||||
return PTR_ERR(rockchip_gem_obj);
|
||||
|
||||
ret = rockchip_drm_gem_handle_create(&rockchip_gem_obj->base, file_priv,
|
||||
&args->handle);
|
||||
if (ret) {
|
||||
rockchip_drm_gem_destroy(rockchip_gem_obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
dma_addr_t *rockchip_drm_gem_get_dma_addr(struct drm_device *dev,
|
||||
unsigned int gem_handle,
|
||||
struct drm_file *filp)
|
||||
{
|
||||
struct rockchip_drm_gem_obj *rockchip_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);
|
||||
}
|
||||
|
||||
rockchip_gem_obj = to_rockchip_gem_obj(obj);
|
||||
|
||||
return &rockchip_gem_obj->buffer->dma_addr;
|
||||
}
|
||||
|
||||
void rockchip_drm_gem_put_dma_addr(struct drm_device *dev,
|
||||
unsigned int gem_handle,
|
||||
struct drm_file *filp)
|
||||
{
|
||||
struct rockchip_drm_gem_obj *rockchip_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;
|
||||
}
|
||||
|
||||
rockchip_gem_obj = to_rockchip_gem_obj(obj);
|
||||
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
|
||||
/*
|
||||
* decrease obj->refcount one more time because we has already
|
||||
* increased it at rockchip_drm_gem_get_dma_addr().
|
||||
*/
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
}
|
||||
|
||||
int rockchip_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_rockchip_gem_map_off *args = data;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
DRM_DEBUG_KMS("handle = 0x%x, offset = 0x%lx\n",
|
||||
args->handle, (unsigned long)args->offset);
|
||||
|
||||
if (!(dev->driver->driver_features & DRIVER_GEM)) {
|
||||
DRM_ERROR("does not support GEM.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return rockchip_drm_gem_dumb_map_offset(file_priv, dev, args->handle,
|
||||
&args->offset);
|
||||
}
|
||||
|
||||
static struct drm_file *rockchip_drm_find_drm_file(struct drm_device *drm_dev,
|
||||
struct file *filp)
|
||||
{
|
||||
struct drm_file *file_priv;
|
||||
|
||||
/* find current process's drm_file from filelist. */
|
||||
list_for_each_entry(file_priv, &drm_dev->filelist, lhead)
|
||||
if (file_priv->filp == filp)
|
||||
return file_priv;
|
||||
|
||||
WARN_ON(1);
|
||||
|
||||
return ERR_PTR(-EFAULT);
|
||||
}
|
||||
|
||||
static int rockchip_drm_gem_mmap_buffer(struct file *filp,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct drm_gem_object *obj = filp->private_data;
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj = to_rockchip_gem_obj(obj);
|
||||
struct drm_device *drm_dev = obj->dev;
|
||||
struct rockchip_drm_gem_buf *buffer;
|
||||
struct drm_file *file_priv;
|
||||
unsigned long vm_size;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
|
||||
vma->vm_private_data = obj;
|
||||
vma->vm_ops = drm_dev->driver->gem_vm_ops;
|
||||
|
||||
/* restore it to driver's fops. */
|
||||
filp->f_op = fops_get(drm_dev->driver->fops);
|
||||
|
||||
file_priv = rockchip_drm_find_drm_file(drm_dev, filp);
|
||||
if (IS_ERR(file_priv))
|
||||
return PTR_ERR(file_priv);
|
||||
|
||||
/* restore it to drm_file. */
|
||||
filp->private_data = file_priv;
|
||||
|
||||
update_vm_cache_attr(rockchip_gem_obj, vma);
|
||||
|
||||
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 = rockchip_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;
|
||||
}
|
||||
|
||||
/*
|
||||
* take a reference to this mapping of the object. And this reference
|
||||
* is unreferenced by the corresponding vm_close call.
|
||||
*/
|
||||
drm_gem_object_reference(obj);
|
||||
|
||||
drm_vm_open_locked(drm_dev, vma);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations rockchip_drm_gem_fops = {
|
||||
.mmap = rockchip_drm_gem_mmap_buffer,
|
||||
};
|
||||
|
||||
int rockchip_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_rockchip_gem_mmap *args = data;
|
||||
struct drm_gem_object *obj;
|
||||
unsigned int addr;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (!(dev->driver->driver_features & DRIVER_GEM)) {
|
||||
DRM_ERROR("does not support GEM.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
|
||||
if (!obj) {
|
||||
DRM_ERROR("failed to lookup gem object.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to use gem object and its fops for specific mmaper,
|
||||
* but vm_mmap() can deliver only filp. So we have to change
|
||||
* filp->f_op and filp->private_data temporarily, then restore
|
||||
* again. So it is important to keep lock until restoration the
|
||||
* settings to prevent others from misuse of filp->f_op or
|
||||
* filp->private_data.
|
||||
*/
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
/*
|
||||
* Set specific mmper's fops. And it will be restored by
|
||||
* rockchip_drm_gem_mmap_buffer to dev->driver->fops.
|
||||
* This is used to call specific mapper temporarily.
|
||||
*/
|
||||
file_priv->filp->f_op = &rockchip_drm_gem_fops;
|
||||
|
||||
/*
|
||||
* Set gem object to private_data so that specific mmaper
|
||||
* can get the gem object. And it will be restored by
|
||||
* rockchip_drm_gem_mmap_buffer to drm_file.
|
||||
*/
|
||||
file_priv->filp->private_data = obj;
|
||||
|
||||
addr = vm_mmap(file_priv->filp, 0, args->size,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED, 0);
|
||||
|
||||
drm_gem_object_unreference(obj);
|
||||
|
||||
if (IS_ERR((void *)addr)) {
|
||||
/* check filp->f_op, filp->private_data are restored */
|
||||
if (file_priv->filp->f_op == &rockchip_drm_gem_fops) {
|
||||
file_priv->filp->f_op = fops_get(dev->driver->fops);
|
||||
file_priv->filp->private_data = file_priv;
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return PTR_ERR((void *)addr);
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
args->mapped = addr;
|
||||
|
||||
DRM_DEBUG_KMS("mapped = 0x%lx\n", (unsigned long)args->mapped);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rockchip_drm_gem_get_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{ struct rockchip_drm_gem_obj *rockchip_gem_obj;
|
||||
struct drm_rockchip_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;
|
||||
}
|
||||
|
||||
rockchip_gem_obj = to_rockchip_gem_obj(obj);
|
||||
|
||||
args->flags = rockchip_gem_obj->flags;
|
||||
args->size = rockchip_gem_obj->size;
|
||||
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct vm_area_struct *rockchip_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 rockchip_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 rockchip_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 rockchip_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 rockchip_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 rockchip_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);
|
||||
}
|
||||
|
||||
int rockchip_drm_gem_init_object(struct drm_gem_object *obj)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rockchip_drm_gem_free_object(struct drm_gem_object *obj)
|
||||
{
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj;
|
||||
struct rockchip_drm_gem_buf *buf;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
rockchip_gem_obj = to_rockchip_gem_obj(obj);
|
||||
buf = rockchip_gem_obj->buffer;
|
||||
|
||||
if (obj->import_attach)
|
||||
drm_prime_gem_destroy(obj, buf->sgt);
|
||||
|
||||
rockchip_drm_gem_destroy(to_rockchip_gem_obj(obj));
|
||||
}
|
||||
|
||||
int rockchip_drm_gem_dumb_create(struct drm_file *file_priv,
|
||||
struct drm_device *dev,
|
||||
struct drm_mode_create_dumb *args)
|
||||
{
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/*
|
||||
* alocate 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;
|
||||
|
||||
rockchip_gem_obj = rockchip_drm_gem_create(dev, ROCKCHIP_BO_CONTIG |
|
||||
ROCKCHIP_BO_WC, args->size);
|
||||
if (IS_ERR(rockchip_gem_obj))
|
||||
return PTR_ERR(rockchip_gem_obj);
|
||||
|
||||
ret = rockchip_drm_gem_handle_create(&rockchip_gem_obj->base, file_priv,
|
||||
&args->handle);
|
||||
if (ret) {
|
||||
rockchip_drm_gem_destroy(rockchip_gem_obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rockchip_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;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!obj->map_list.map) {
|
||||
ret = drm_gem_create_mmap_offset(obj);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
*offset = (u64)obj->map_list.hash.key << PAGE_SHIFT;
|
||||
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 rockchip_drm_gem_dumb_destroy(struct drm_file *file_priv,
|
||||
struct drm_device *dev,
|
||||
unsigned int handle)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/*
|
||||
* obj->refcount and obj->handle_count are decreased and
|
||||
* if both them are 0 then rockchip_drm_gem_free_object()
|
||||
* would be called by callback to release resources.
|
||||
*/
|
||||
ret = drm_gem_handle_delete(file_priv, handle);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to delete drm_gem_handle.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rockchip_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 = rockchip_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 rockchip_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
{
|
||||
struct rockchip_drm_gem_obj *rockchip_gem_obj;
|
||||
struct drm_gem_object *obj;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* 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;
|
||||
rockchip_gem_obj = to_rockchip_gem_obj(obj);
|
||||
|
||||
ret = check_gem_flags(rockchip_gem_obj->flags);
|
||||
if (ret) {
|
||||
drm_gem_vm_close(vma);
|
||||
drm_gem_free_mmap_offset(obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
vma->vm_flags &= ~VM_PFNMAP;
|
||||
vma->vm_flags |= VM_MIXEDMAP;
|
||||
|
||||
update_vm_cache_attr(rockchip_gem_obj, vma);
|
||||
|
||||
return ret;
|
||||
}
|
||||
202
drivers/gpu/drm/rockchip/rockchip_drm_gem.h
Normal file
202
drivers/gpu/drm/rockchip/rockchip_drm_gem.h
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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 _ROCKCHIP_DRM_GEM_H_
|
||||
#define _ROCKCHIP_DRM_GEM_H_
|
||||
|
||||
#define to_rockchip_gem_obj(x) container_of(x,\
|
||||
struct rockchip_drm_gem_obj, base)
|
||||
|
||||
#define IS_NONCONTIG_BUFFER(f) (f & ROCKCHIP_BO_NONCONTIG)
|
||||
|
||||
/*
|
||||
* rockchip 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 rockchip_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;
|
||||
};
|
||||
|
||||
/*
|
||||
* rockchip 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 rockchip_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 transfered to user as kms_bo.handle so
|
||||
* user can access the buffer through kms_bo.handle.
|
||||
*/
|
||||
struct rockchip_drm_gem_obj {
|
||||
struct drm_gem_object base;
|
||||
struct rockchip_drm_gem_buf *buffer;
|
||||
unsigned long size;
|
||||
struct vm_area_struct *vma;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
struct page **rockchip_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
|
||||
|
||||
/* destroy a buffer with gem object */
|
||||
void rockchip_drm_gem_destroy(struct rockchip_drm_gem_obj *rockchip_gem_obj);
|
||||
|
||||
/* create a private gem object and initialize it. */
|
||||
struct rockchip_drm_gem_obj *rockchip_drm_gem_init(struct drm_device *dev,
|
||||
unsigned long size);
|
||||
|
||||
/* create a new buffer with gem object */
|
||||
struct rockchip_drm_gem_obj *rockchip_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 rockchip_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 *rockchip_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 rockchip_drm_gem_put_dma_addr(struct drm_device *dev,
|
||||
unsigned int gem_handle,
|
||||
struct drm_file *filp);
|
||||
|
||||
/* get buffer offset to map to user space. */
|
||||
int rockchip_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
/*
|
||||
* mmap the physically continuous memory that a gem object contains
|
||||
* to user space.
|
||||
*/
|
||||
int rockchip_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
/* map user space allocated by malloc to pages. */
|
||||
int rockchip_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 rockchip_drm_gem_get_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
/* get buffer size to gem handle. */
|
||||
unsigned long rockchip_drm_gem_get_size(struct drm_device *dev,
|
||||
unsigned int gem_handle,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
/* initialize gem object. */
|
||||
int rockchip_drm_gem_init_object(struct drm_gem_object *obj);
|
||||
|
||||
/* free gem object. */
|
||||
void rockchip_drm_gem_free_object(struct drm_gem_object *gem_obj);
|
||||
|
||||
/* create memory region for drm framebuffer. */
|
||||
int rockchip_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 rockchip_drm_gem_dumb_map_offset(struct drm_file *file_priv,
|
||||
struct drm_device *dev, uint32_t handle,
|
||||
uint64_t *offset);
|
||||
|
||||
/*
|
||||
* destroy memory region allocated.
|
||||
* - a gem handle and physical memory region pointed by a gem object
|
||||
* would be released by drm_gem_handle_delete().
|
||||
*/
|
||||
int rockchip_drm_gem_dumb_destroy(struct drm_file *file_priv,
|
||||
struct drm_device *dev,
|
||||
unsigned int handle);
|
||||
|
||||
/* page fault handler and mmap fault address(virtual) to physical memory. */
|
||||
int rockchip_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 rockchip_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 *rockchip_gem_get_vma(struct vm_area_struct *vma);
|
||||
|
||||
/* release a userspace virtual memory area. */
|
||||
void rockchip_gem_put_vma(struct vm_area_struct *vma);
|
||||
|
||||
/* get pages from user space. */
|
||||
int rockchip_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 rockchip_gem_put_pages_to_userptr(struct page **pages,
|
||||
unsigned int npages,
|
||||
struct vm_area_struct *vma);
|
||||
|
||||
/* map sgt with dma region. */
|
||||
int rockchip_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 rockchip_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
|
||||
struct sg_table *sgt,
|
||||
enum dma_data_direction dir);
|
||||
|
||||
#endif
|
||||
483
drivers/gpu/drm/rockchip/rockchip_drm_hdmi.c
Normal file
483
drivers/gpu/drm/rockchip/rockchip_drm_hdmi.c
Normal file
|
|
@ -0,0 +1,483 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <drm/rockchip_drm.h>
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_hdmi.h"
|
||||
|
||||
#define to_context(dev) platform_get_drvdata(to_platform_device(dev))
|
||||
#define to_subdrv(dev) to_context(dev)
|
||||
#define get_ctx_from_subdrv(subdrv) container_of(subdrv,\
|
||||
struct drm_hdmi_context, subdrv);
|
||||
|
||||
/* platform device pointer for common drm hdmi device. */
|
||||
static struct platform_device *rockchip_drm_hdmi_pdev;
|
||||
|
||||
/* Common hdmi subdrv needs to access the hdmi and mixer though context.
|
||||
* These should be initialied by the repective drivers */
|
||||
static struct rockchip_drm_hdmi_context *hdmi_ctx;
|
||||
static struct rockchip_drm_hdmi_context *mixer_ctx;
|
||||
|
||||
/* these callback points shoud be set by specific drivers. */
|
||||
static struct rockchip_hdmi_ops *hdmi_ops;
|
||||
static struct rockchip_mixer_ops *mixer_ops;
|
||||
|
||||
struct drm_hdmi_context {
|
||||
struct rockchip_drm_subdrv subdrv;
|
||||
struct rockchip_drm_hdmi_context *hdmi_ctx;
|
||||
struct rockchip_drm_hdmi_context *mixer_ctx;
|
||||
|
||||
bool enabled[MIXER_WIN_NR];
|
||||
};
|
||||
|
||||
int rockchip_platform_device_hdmi_register(void)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
|
||||
if (rockchip_drm_hdmi_pdev)
|
||||
return -EEXIST;
|
||||
|
||||
pdev = platform_device_register_simple(
|
||||
"rockchip-drm-hdmi", -1, NULL, 0);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
rockchip_drm_hdmi_pdev = pdev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rockchip_platform_device_hdmi_unregister(void)
|
||||
{
|
||||
if (rockchip_drm_hdmi_pdev) {
|
||||
platform_device_unregister(rockchip_drm_hdmi_pdev);
|
||||
rockchip_drm_hdmi_pdev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void rockchip_hdmi_drv_attach(struct rockchip_drm_hdmi_context *ctx)
|
||||
{
|
||||
if (ctx)
|
||||
hdmi_ctx = ctx;
|
||||
}
|
||||
|
||||
void rockchip_mixer_drv_attach(struct rockchip_drm_hdmi_context *ctx)
|
||||
{
|
||||
if (ctx)
|
||||
mixer_ctx = ctx;
|
||||
}
|
||||
|
||||
void rockchip_hdmi_ops_register(struct rockchip_hdmi_ops *ops)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (ops)
|
||||
hdmi_ops = ops;
|
||||
}
|
||||
|
||||
void rockchip_mixer_ops_register(struct rockchip_mixer_ops *ops)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (ops)
|
||||
mixer_ops = ops;
|
||||
}
|
||||
|
||||
static bool drm_hdmi_is_connected(struct device *dev)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (hdmi_ops && hdmi_ops->is_connected)
|
||||
return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct edid *drm_hdmi_get_edid(struct device *dev,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (hdmi_ops && hdmi_ops->get_edid)
|
||||
return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int drm_hdmi_check_timing(struct device *dev, void *timing)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(dev);
|
||||
int ret = 0;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/*
|
||||
* Both, mixer and hdmi should be able to handle the requested mode.
|
||||
* If any of the two fails, return mode as BAD.
|
||||
*/
|
||||
|
||||
if (mixer_ops && mixer_ops->check_timing)
|
||||
ret = mixer_ops->check_timing(ctx->mixer_ctx->ctx, timing);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (hdmi_ops && hdmi_ops->check_timing)
|
||||
return hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, timing);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_hdmi_power_on(struct device *dev, int mode)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (hdmi_ops && hdmi_ops->power_on)
|
||||
return hdmi_ops->power_on(ctx->hdmi_ctx->ctx, mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rockchip_drm_display_ops drm_hdmi_display_ops = {
|
||||
.type = ROCKCHIP_DISPLAY_TYPE_HDMI,
|
||||
.is_connected = drm_hdmi_is_connected,
|
||||
.get_edid = drm_hdmi_get_edid,
|
||||
.check_timing = drm_hdmi_check_timing,
|
||||
.power_on = drm_hdmi_power_on,
|
||||
};
|
||||
|
||||
static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
struct rockchip_drm_subdrv *subdrv = &ctx->subdrv;
|
||||
struct rockchip_drm_manager *manager = subdrv->manager;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (mixer_ops && mixer_ops->enable_vblank)
|
||||
return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
|
||||
manager->pipe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (mixer_ops && mixer_ops->disable_vblank)
|
||||
return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
|
||||
}
|
||||
|
||||
static void drm_hdmi_wait_for_vblank(struct device *subdrv_dev)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (mixer_ops && mixer_ops->wait_for_vblank)
|
||||
mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx);
|
||||
}
|
||||
|
||||
static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
|
||||
struct drm_connector *connector,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_display_mode *m;
|
||||
int mode_ok;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
drm_mode_set_crtcinfo(adjusted_mode, 0);
|
||||
|
||||
mode_ok = drm_hdmi_check_timing(subdrv_dev, adjusted_mode);
|
||||
|
||||
/* just return if user desired mode exists. */
|
||||
if (mode_ok == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* otherwise, find the most suitable mode among modes and change it
|
||||
* to adjusted_mode.
|
||||
*/
|
||||
list_for_each_entry(m, &connector->modes, head) {
|
||||
mode_ok = drm_hdmi_check_timing(subdrv_dev, m);
|
||||
|
||||
if (mode_ok == 0) {
|
||||
struct drm_mode_object base;
|
||||
struct list_head head;
|
||||
|
||||
DRM_INFO("desired mode doesn't exist so\n");
|
||||
DRM_INFO("use the most suitable mode among modes.\n");
|
||||
|
||||
DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
|
||||
m->hdisplay, m->vdisplay, m->vrefresh);
|
||||
|
||||
/* preserve display mode header while copying. */
|
||||
head = adjusted_mode->head;
|
||||
base = adjusted_mode->base;
|
||||
memcpy(adjusted_mode, m, sizeof(*m));
|
||||
adjusted_mode->head = head;
|
||||
adjusted_mode->base = base;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (hdmi_ops && hdmi_ops->mode_set)
|
||||
hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
|
||||
}
|
||||
|
||||
static void drm_hdmi_get_max_resol(struct device *subdrv_dev,
|
||||
unsigned int *width, unsigned int *height)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (hdmi_ops && hdmi_ops->get_max_resol)
|
||||
hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
|
||||
}
|
||||
|
||||
static void drm_hdmi_commit(struct device *subdrv_dev)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (hdmi_ops && hdmi_ops->commit)
|
||||
hdmi_ops->commit(ctx->hdmi_ctx->ctx);
|
||||
}
|
||||
|
||||
static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (mixer_ops && mixer_ops->dpms)
|
||||
mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
|
||||
|
||||
if (hdmi_ops && hdmi_ops->dpms)
|
||||
hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
|
||||
}
|
||||
|
||||
static void drm_hdmi_apply(struct device *subdrv_dev)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
int i;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
for (i = 0; i < MIXER_WIN_NR; i++) {
|
||||
if (!ctx->enabled[i])
|
||||
continue;
|
||||
if (mixer_ops && mixer_ops->win_commit)
|
||||
mixer_ops->win_commit(ctx->mixer_ctx->ctx, i);
|
||||
}
|
||||
|
||||
if (hdmi_ops && hdmi_ops->commit)
|
||||
hdmi_ops->commit(ctx->hdmi_ctx->ctx);
|
||||
}
|
||||
|
||||
static struct rockchip_drm_manager_ops drm_hdmi_manager_ops = {
|
||||
.dpms = drm_hdmi_dpms,
|
||||
.apply = drm_hdmi_apply,
|
||||
.enable_vblank = drm_hdmi_enable_vblank,
|
||||
.disable_vblank = drm_hdmi_disable_vblank,
|
||||
.wait_for_vblank = drm_hdmi_wait_for_vblank,
|
||||
.mode_fixup = drm_hdmi_mode_fixup,
|
||||
.mode_set = drm_hdmi_mode_set,
|
||||
.get_max_resol = drm_hdmi_get_max_resol,
|
||||
.commit = drm_hdmi_commit,
|
||||
};
|
||||
|
||||
static void drm_mixer_mode_set(struct device *subdrv_dev,
|
||||
struct rockchip_drm_overlay *overlay)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (mixer_ops && mixer_ops->win_mode_set)
|
||||
mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
|
||||
}
|
||||
|
||||
static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (win < 0 || win > MIXER_WIN_NR) {
|
||||
DRM_ERROR("mixer window[%d] is wrong\n", win);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mixer_ops && mixer_ops->win_commit)
|
||||
mixer_ops->win_commit(ctx->mixer_ctx->ctx, win);
|
||||
|
||||
ctx->enabled[win] = true;
|
||||
}
|
||||
|
||||
static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (win < 0 || win > MIXER_WIN_NR) {
|
||||
DRM_ERROR("mixer window[%d] is wrong\n", win);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mixer_ops && mixer_ops->win_disable)
|
||||
mixer_ops->win_disable(ctx->mixer_ctx->ctx, win);
|
||||
|
||||
ctx->enabled[win] = false;
|
||||
}
|
||||
|
||||
static struct rockchip_drm_overlay_ops drm_hdmi_overlay_ops = {
|
||||
.mode_set = drm_mixer_mode_set,
|
||||
.commit = drm_mixer_commit,
|
||||
.disable = drm_mixer_disable,
|
||||
};
|
||||
|
||||
static struct rockchip_drm_manager hdmi_manager = {
|
||||
.pipe = -1,
|
||||
.ops = &drm_hdmi_manager_ops,
|
||||
.overlay_ops = &drm_hdmi_overlay_ops,
|
||||
.display_ops = &drm_hdmi_display_ops,
|
||||
};
|
||||
|
||||
static int hdmi_subdrv_probe(struct drm_device *drm_dev,
|
||||
struct device *dev)
|
||||
{
|
||||
struct rockchip_drm_subdrv *subdrv = to_subdrv(dev);
|
||||
struct drm_hdmi_context *ctx;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (!hdmi_ctx) {
|
||||
DRM_ERROR("hdmi context not initialized.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!mixer_ctx) {
|
||||
DRM_ERROR("mixer context not initialized.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ctx = get_ctx_from_subdrv(subdrv);
|
||||
|
||||
if (!ctx) {
|
||||
DRM_ERROR("no drm hdmi context.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ctx->hdmi_ctx = hdmi_ctx;
|
||||
ctx->mixer_ctx = mixer_ctx;
|
||||
|
||||
ctx->hdmi_ctx->drm_dev = drm_dev;
|
||||
ctx->mixer_ctx->drm_dev = drm_dev;
|
||||
|
||||
if (mixer_ops->iommu_on)
|
||||
mixer_ops->iommu_on(ctx->mixer_ctx->ctx, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hdmi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
|
||||
{
|
||||
struct drm_hdmi_context *ctx;
|
||||
struct rockchip_drm_subdrv *subdrv = to_subdrv(dev);
|
||||
|
||||
ctx = get_ctx_from_subdrv(subdrv);
|
||||
|
||||
if (mixer_ops->iommu_on)
|
||||
mixer_ops->iommu_on(ctx->mixer_ctx->ctx, false);
|
||||
}
|
||||
|
||||
static int rockchip_drm_hdmi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rockchip_drm_subdrv *subdrv;
|
||||
struct drm_hdmi_context *ctx;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx) {
|
||||
DRM_LOG_KMS("failed to alloc common hdmi context.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
subdrv = &ctx->subdrv;
|
||||
|
||||
subdrv->dev = dev;
|
||||
subdrv->manager = &hdmi_manager;
|
||||
subdrv->probe = hdmi_subdrv_probe;
|
||||
subdrv->remove = hdmi_subdrv_remove;
|
||||
|
||||
platform_set_drvdata(pdev, subdrv);
|
||||
|
||||
rockchip_drm_subdrv_register(subdrv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_drm_hdmi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
rockchip_drm_subdrv_unregister(&ctx->subdrv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct platform_driver rockchip_drm_common_hdmi_driver = {
|
||||
.probe = rockchip_drm_hdmi_probe,
|
||||
.remove = rockchip_drm_hdmi_remove,
|
||||
.driver = {
|
||||
.name = "rockchip-drm-hdmi",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
68
drivers/gpu/drm/rockchip/rockchip_drm_hdmi.h
Normal file
68
drivers/gpu/drm/rockchip/rockchip_drm_hdmi.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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 _ROCKCHIP_DRM_HDMI_H_
|
||||
#define _ROCKCHIP_DRM_HDMI_H_
|
||||
|
||||
#define MIXER_WIN_NR 3
|
||||
#define MIXER_DEFAULT_WIN 0
|
||||
|
||||
/*
|
||||
* rockchip hdmi common context structure.
|
||||
*
|
||||
* @drm_dev: pointer to drm_device.
|
||||
* @ctx: pointer to the context of specific device driver.
|
||||
* this context should be hdmi_context or mixer_context.
|
||||
*/
|
||||
struct rockchip_drm_hdmi_context {
|
||||
struct drm_device *drm_dev;
|
||||
void *ctx;
|
||||
};
|
||||
|
||||
struct rockchip_hdmi_ops {
|
||||
/* display */
|
||||
bool (*is_connected)(void *ctx);
|
||||
struct edid *(*get_edid)(void *ctx,
|
||||
struct drm_connector *connector);
|
||||
int (*check_timing)(void *ctx, struct fb_videomode *timing);
|
||||
int (*power_on)(void *ctx, int mode);
|
||||
|
||||
/* manager */
|
||||
void (*mode_set)(void *ctx, void *mode);
|
||||
void (*get_max_resol)(void *ctx, unsigned int *width,
|
||||
unsigned int *height);
|
||||
void (*commit)(void *ctx);
|
||||
void (*dpms)(void *ctx, int mode);
|
||||
};
|
||||
|
||||
struct rockchip_mixer_ops {
|
||||
/* manager */
|
||||
int (*iommu_on)(void *ctx, bool enable);
|
||||
int (*enable_vblank)(void *ctx, int pipe);
|
||||
void (*disable_vblank)(void *ctx);
|
||||
void (*wait_for_vblank)(void *ctx);
|
||||
void (*dpms)(void *ctx, int mode);
|
||||
|
||||
/* overlay */
|
||||
void (*win_mode_set)(void *ctx, struct rockchip_drm_overlay *overlay);
|
||||
void (*win_commit)(void *ctx, int zpos);
|
||||
void (*win_disable)(void *ctx, int zpos);
|
||||
|
||||
/* display */
|
||||
int (*check_timing)(void *ctx, struct fb_videomode *timing);
|
||||
};
|
||||
|
||||
void rockchip_hdmi_drv_attach(struct rockchip_drm_hdmi_context *ctx);
|
||||
void rockchip_mixer_drv_attach(struct rockchip_drm_hdmi_context *ctx);
|
||||
void rockchip_hdmi_ops_register(struct rockchip_hdmi_ops *ops);
|
||||
void rockchip_mixer_ops_register(struct rockchip_mixer_ops *ops);
|
||||
#endif
|
||||
138
drivers/gpu/drm/rockchip/rockchip_drm_iommu.c
Normal file
138
drivers/gpu/drm/rockchip/rockchip_drm_iommu.c
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <drmP.h>
|
||||
#include <drm/rockchip_drm.h>
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/kref.h>
|
||||
|
||||
#include <asm/dma-iommu.h>
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_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 rockchip_drm_private *priv = drm_dev->dev_private;
|
||||
struct device *dev = drm_dev->dev;
|
||||
|
||||
if (!priv->da_start)
|
||||
priv->da_start = ROCKCHIP_DEV_ADDR_START;
|
||||
if (!priv->da_space_size)
|
||||
priv->da_space_size = ROCKCHIP_DEV_ADDR_SIZE;
|
||||
if (!priv->da_space_order)
|
||||
priv->da_space_order = ROCKCHIP_DEV_ADDR_ORDER;
|
||||
|
||||
mapping = arm_iommu_create_mapping(&platform_bus_type, priv->da_start,
|
||||
priv->da_space_size,
|
||||
priv->da_space_order);
|
||||
if (IS_ERR(mapping))
|
||||
return PTR_ERR(mapping);
|
||||
|
||||
dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
|
||||
GFP_KERNEL);
|
||||
dma_set_max_seg_size(dev, 0xffffffffu);
|
||||
dev->archdata.mapping = mapping;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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);
|
||||
}
|
||||
72
drivers/gpu/drm/rockchip/rockchip_drm_iommu.h
Normal file
72
drivers/gpu/drm/rockchip/rockchip_drm_iommu.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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 _ROCKCHIP_DRM_IOMMU_H_
|
||||
#define _ROCKCHIP_DRM_IOMMU_H_
|
||||
|
||||
#define ROCKCHIP_DEV_ADDR_START 0x20000000
|
||||
#define ROCKCHIP_DEV_ADDR_SIZE 0x40000000
|
||||
#define ROCKCHIP_DEV_ADDR_ORDER 0x0
|
||||
|
||||
#ifdef CONFIG_DRM_ROCKCHIP_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
|
||||
305
drivers/gpu/drm/rockchip/rockchip_drm_plane.c
Normal file
305
drivers/gpu/drm/rockchip/rockchip_drm_plane.c
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
|
||||
#include <drm/rockchip_drm.h>
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_encoder.h"
|
||||
#include "rockchip_drm_fb.h"
|
||||
#include "rockchip_drm_gem.h"
|
||||
|
||||
#define to_rockchip_plane(x) container_of(x, struct rockchip_plane, base)
|
||||
|
||||
struct rockchip_plane {
|
||||
struct drm_plane base;
|
||||
struct rockchip_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 rockchip_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 rockchip_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 rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
|
||||
struct rockchip_drm_overlay *overlay = &rockchip_plane->overlay;
|
||||
unsigned int actual_w;
|
||||
unsigned int actual_h;
|
||||
int nr;
|
||||
int i;
|
||||
|
||||
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||
|
||||
nr = rockchip_drm_fb_get_buf_cnt(fb);
|
||||
for (i = 0; i < nr; i++) {
|
||||
struct rockchip_drm_gem_buf *buffer = rockchip_drm_fb_buffer(fb, i);
|
||||
|
||||
if (!buffer) {
|
||||
DRM_LOG_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 = rockchip_plane_get_size(crtc_x, crtc_w, crtc->mode.hdisplay);
|
||||
actual_h = rockchip_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);
|
||||
|
||||
rockchip_drm_fn_encoder(crtc, overlay, rockchip_drm_encoder_plane_mode_set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rockchip_plane_commit(struct drm_plane *plane)
|
||||
{
|
||||
struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
|
||||
struct rockchip_drm_overlay *overlay = &rockchip_plane->overlay;
|
||||
|
||||
rockchip_drm_fn_encoder(plane->crtc, &overlay->zpos,
|
||||
rockchip_drm_encoder_plane_commit);
|
||||
}
|
||||
|
||||
void rockchip_plane_dpms(struct drm_plane *plane, int mode)
|
||||
{
|
||||
struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
|
||||
struct rockchip_drm_overlay *overlay = &rockchip_plane->overlay;
|
||||
|
||||
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||
|
||||
if (mode == DRM_MODE_DPMS_ON) {
|
||||
if (rockchip_plane->enabled)
|
||||
return;
|
||||
|
||||
rockchip_drm_fn_encoder(plane->crtc, &overlay->zpos,
|
||||
rockchip_drm_encoder_plane_enable);
|
||||
|
||||
rockchip_plane->enabled = true;
|
||||
} else {
|
||||
if (!rockchip_plane->enabled)
|
||||
return;
|
||||
|
||||
rockchip_drm_fn_encoder(plane->crtc, &overlay->zpos,
|
||||
rockchip_drm_encoder_plane_disable);
|
||||
|
||||
rockchip_plane->enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
rockchip_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;
|
||||
|
||||
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||
|
||||
ret = rockchip_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;
|
||||
|
||||
plane->crtc = crtc;
|
||||
|
||||
rockchip_plane_commit(plane);
|
||||
rockchip_plane_dpms(plane, DRM_MODE_DPMS_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_disable_plane(struct drm_plane *plane)
|
||||
{
|
||||
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||
|
||||
rockchip_plane_dpms(plane, DRM_MODE_DPMS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rockchip_plane_destroy(struct drm_plane *plane)
|
||||
{
|
||||
struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
|
||||
|
||||
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||
|
||||
rockchip_disable_plane(plane);
|
||||
drm_plane_cleanup(plane);
|
||||
kfree(rockchip_plane);
|
||||
}
|
||||
|
||||
static int rockchip_plane_set_property(struct drm_plane *plane,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
|
||||
struct rockchip_drm_private *dev_priv = dev->dev_private;
|
||||
|
||||
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||
|
||||
if (property == dev_priv->plane_zpos_property) {
|
||||
rockchip_plane->overlay.zpos = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct drm_plane_funcs rockchip_plane_funcs = {
|
||||
.update_plane = rockchip_update_plane,
|
||||
.disable_plane = rockchip_disable_plane,
|
||||
.destroy = rockchip_plane_destroy,
|
||||
.set_property = rockchip_plane_set_property,
|
||||
};
|
||||
|
||||
static void rockchip_plane_attach_zpos_property(struct drm_plane *plane)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct rockchip_drm_private *dev_priv = dev->dev_private;
|
||||
struct drm_property *prop;
|
||||
|
||||
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||
|
||||
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 *rockchip_plane_init(struct drm_device *dev,
|
||||
unsigned int possible_crtcs, bool priv)
|
||||
{
|
||||
struct rockchip_plane *rockchip_plane;
|
||||
int err;
|
||||
|
||||
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||
|
||||
rockchip_plane = kzalloc(sizeof(struct rockchip_plane), GFP_KERNEL);
|
||||
if (!rockchip_plane) {
|
||||
DRM_ERROR("failed to allocate plane\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = drm_plane_init(dev, &rockchip_plane->base, possible_crtcs,
|
||||
&rockchip_plane_funcs, formats, ARRAY_SIZE(formats),
|
||||
priv);
|
||||
if (err) {
|
||||
DRM_ERROR("failed to initialize plane\n");
|
||||
kfree(rockchip_plane);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (priv)
|
||||
rockchip_plane->overlay.zpos = DEFAULT_ZPOS;
|
||||
else
|
||||
rockchip_plane_attach_zpos_property(&rockchip_plane->base);
|
||||
|
||||
return &rockchip_plane->base;
|
||||
}
|
||||
21
drivers/gpu/drm/rockchip/rockchip_drm_plane.h
Normal file
21
drivers/gpu/drm/rockchip/rockchip_drm_plane.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
* Author:yzq<yzq@rock-chips.com>
|
||||
* 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.
|
||||
*/
|
||||
int rockchip_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 rockchip_plane_commit(struct drm_plane *plane);
|
||||
void rockchip_plane_dpms(struct drm_plane *plane, int mode);
|
||||
struct drm_plane *rockchip_plane_init(struct drm_device *dev,
|
||||
unsigned int possible_crtcs, bool priv);
|
||||
4
drivers/gpu/drm/rockchip/screen/.gitignore
vendored
Normal file
4
drivers/gpu/drm/rockchip/screen/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#
|
||||
# Generated files
|
||||
#
|
||||
*lcd.h
|
||||
14
drivers/gpu/drm/rockchip/screen/Kconfig
Executable file
14
drivers/gpu/drm/rockchip/screen/Kconfig
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
choice
|
||||
prompt "LCD Panel Select"
|
||||
|
||||
config LCD_GENERAL
|
||||
bool "General lcd panel"
|
||||
help
|
||||
select if the panel do not need initialization
|
||||
config LCD_LD089WU1_MIPI
|
||||
bool "mipi dsi lcd LD089WU1 1920X1200"
|
||||
config LCD_B080XAN02_MIPI
|
||||
bool "mipi dsi lcd B080XAN02 1024X768"
|
||||
endchoice
|
||||
|
||||
|
||||
24
drivers/gpu/drm/rockchip/screen/Makefile
Normal file
24
drivers/gpu/drm/rockchip/screen/Makefile
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
obj-$(CONFIG_LCD_GENERAL) += lcd_general.o
|
||||
obj-$(CONFIG_LCD_LD089WU1_MIPI) += lcd_LD089WU1_mipi.o
|
||||
obj-$(CONFIG_LCD_B080XAN02_MIPI) += lcd_B080XAN02_mipi.o
|
||||
|
||||
|
||||
quiet_cmd_gen = GEN $@
|
||||
cmd_gen = cmp -s $< $@ || cp $< $@
|
||||
|
||||
lcd-obj := $(filter lcd_%.o,$(obj-y))
|
||||
lcd-cfile := $(patsubst %.o,%.c,$(lcd-obj))
|
||||
lcd-cpath := $(src)/$(lcd-cfile)
|
||||
|
||||
obj-y := $(filter-out $(lcd-obj),$(obj-y))
|
||||
|
||||
$(obj)/lcd.h: $(lcd-cpath) FORCE
|
||||
$(call if_changed,gen)
|
||||
|
||||
$(obj)/rk_screen.o: $(obj)/lcd.h
|
||||
obj-y += rk_screen.o
|
||||
|
||||
clean-files := lcd.h
|
||||
|
||||
|
||||
|
||||
72
drivers/gpu/drm/rockchip/screen/lcd_B080XAN02_mipi.c
Executable file
72
drivers/gpu/drm/rockchip/screen/lcd_B080XAN02_mipi.c
Executable file
|
|
@ -0,0 +1,72 @@
|
|||
#ifndef __LCD_B080XAN02__
|
||||
#define __LCD_B080XAN02__
|
||||
|
||||
#if defined(CONFIG_MIPI_DSI)
|
||||
#include "../transmitter/mipi_dsi.h"
|
||||
#endif
|
||||
#include <linux/delay.h>
|
||||
|
||||
|
||||
|
||||
#define RK_SCREEN_INIT 1
|
||||
|
||||
/* about mipi */
|
||||
#define MIPI_DSI_LANE 4
|
||||
#define MIPI_DSI_HS_CLK 528*1000000 //1000*1000000
|
||||
|
||||
|
||||
#if defined(RK_SCREEN_INIT)
|
||||
static struct rk29lcd_info *gLcd_info = NULL;
|
||||
|
||||
int rk_lcd_init(void) {
|
||||
|
||||
u8 dcs[16] = {0};
|
||||
if(dsi_is_active() != 1)
|
||||
return -1;
|
||||
/*below is changeable*/
|
||||
dsi_enable_hs_clk(1);
|
||||
|
||||
dcs[0] = LPDT;
|
||||
dcs[1] = dcs_exit_sleep_mode;
|
||||
dsi_send_dcs_packet(dcs, 2);
|
||||
msleep(1);
|
||||
dcs[0] = LPDT;
|
||||
dcs[1] = dcs_set_display_on;
|
||||
dsi_send_dcs_packet(dcs, 2);
|
||||
msleep(10);
|
||||
//dsi_enable_command_mode(0);
|
||||
dsi_enable_video_mode(1);
|
||||
|
||||
printk("++++++++++++++++%s:%d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rk_lcd_standby(u8 enable) {
|
||||
|
||||
u8 dcs[16] = {0};
|
||||
if(dsi_is_active() != 1)
|
||||
return -1;
|
||||
|
||||
if(enable) {
|
||||
/*below is changeable*/
|
||||
dcs[0] = LPDT;
|
||||
dcs[1] = dcs_set_display_off;
|
||||
dsi_send_dcs_packet(dcs, 2);
|
||||
msleep(1);
|
||||
dcs[0] = LPDT;
|
||||
dcs[1] = dcs_enter_sleep_mode;
|
||||
dsi_send_dcs_packet(dcs, 2);
|
||||
msleep(1);
|
||||
|
||||
printk("++++enable++++++++++++%s:%d\n", __func__, __LINE__);
|
||||
|
||||
} else {
|
||||
/*below is changeable*/
|
||||
rk_lcd_init();
|
||||
printk("++++++++++++++++%s:%d\n", __func__, __LINE__);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
70
drivers/gpu/drm/rockchip/screen/lcd_LD089WU1_mipi.c
Normal file
70
drivers/gpu/drm/rockchip/screen/lcd_LD089WU1_mipi.c
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef __LCD_LD089WU1__
|
||||
#define __LCD_LD089WU1__
|
||||
|
||||
#if defined(CONFIG_MIPI_DSI)
|
||||
#include "../transmitter/mipi_dsi.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#define RK_SCREEN_INIT 1
|
||||
|
||||
/* about mipi */
|
||||
#define MIPI_DSI_LANE 4
|
||||
#define MIPI_DSI_HS_CLK 1000*1000000
|
||||
|
||||
#if defined(RK_SCREEN_INIT)
|
||||
static struct rk29lcd_info *gLcd_info = NULL;
|
||||
|
||||
int rk_lcd_init(void) {
|
||||
|
||||
u8 dcs[16] = {0};
|
||||
if(dsi_is_active() != 1)
|
||||
return -1;
|
||||
|
||||
/*below is changeable*/
|
||||
dsi_enable_hs_clk(1);
|
||||
dsi_enable_video_mode(0);
|
||||
dsi_enable_command_mode(1);
|
||||
dcs[0] = dcs_exit_sleep_mode;
|
||||
dsi_send_dcs_packet(dcs, 1);
|
||||
msleep(1);
|
||||
dcs[0] = dcs_set_display_on;
|
||||
dsi_send_dcs_packet(dcs, 1);
|
||||
msleep(10);
|
||||
dsi_enable_command_mode(0);
|
||||
dsi_enable_video_mode(1);
|
||||
//printk("++++++++++++++++%s:%d\n", __func__, __LINE__);
|
||||
};
|
||||
|
||||
|
||||
|
||||
int rk_lcd_standby(u8 enable) {
|
||||
|
||||
u8 dcs[16] = {0};
|
||||
if(dsi_is_active() != 1)
|
||||
return -1;
|
||||
|
||||
if(enable) {
|
||||
dsi_enable_video_mode(0);
|
||||
dsi_enable_command_mode(1);
|
||||
/*below is changeable*/
|
||||
dcs[0] = dcs_set_display_off;
|
||||
dsi_send_dcs_packet(dcs, 1);
|
||||
msleep(1);
|
||||
dcs[0] = dcs_enter_sleep_mode;
|
||||
dsi_send_dcs_packet(dcs, 1);
|
||||
msleep(1);
|
||||
//printk("++++++++++++++++%s:%d\n", __func__, __LINE__);
|
||||
|
||||
} else {
|
||||
/*below is changeable*/
|
||||
rk_lcd_init();
|
||||
//printk("++++++++++++++++%s:%d\n", __func__, __LINE__);
|
||||
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
8
drivers/gpu/drm/rockchip/screen/lcd_general.c
Normal file
8
drivers/gpu/drm/rockchip/screen/lcd_general.c
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
#ifndef __LCD_NULL__
|
||||
#define __LCD_NULL__
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
65
drivers/gpu/drm/rockchip/screen/rk_screen.c
Normal file
65
drivers/gpu/drm/rockchip/screen/rk_screen.c
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
#include <linux/rk_fb.h>
|
||||
#include <linux/device.h>
|
||||
#include "lcd.h"
|
||||
|
||||
static struct rk_screen *rk_screen;
|
||||
int rk_fb_get_prmry_screen(struct rk_screen *screen)
|
||||
{
|
||||
memcpy(screen, rk_screen, sizeof(struct rk_screen));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
size_t get_fb_size(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int rk_screen_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret;
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "Missing device tree node.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
rk_screen = devm_kzalloc(&pdev->dev, sizeof(struct rk_screen), GFP_KERNEL);
|
||||
if (!rk_screen) {
|
||||
dev_err(&pdev->dev, "kmalloc for rk screen fail!");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = rk_fb_prase_timing_dt(np,rk_screen);
|
||||
dev_info(&pdev->dev, "rockchip screen probe %s\n",
|
||||
ret? "failed" : "success");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id rk_screen_dt_ids[] = {
|
||||
{ .compatible = "rockchip,screen", },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver rk_screen_driver = {
|
||||
.probe = rk_screen_probe,
|
||||
.driver = {
|
||||
.name = "rk-screen",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(rk_screen_dt_ids),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init rk_screen_init(void)
|
||||
{
|
||||
return platform_driver_register(&rk_screen_driver);
|
||||
}
|
||||
|
||||
static void __exit rk_screen_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&rk_screen_driver);
|
||||
}
|
||||
|
||||
subsys_initcall_sync(rk_screen_init);
|
||||
module_exit(rk_screen_exit);
|
||||
|
||||
72
drivers/gpu/drm/rockchip/transmitter/Kconfig
Normal file
72
drivers/gpu/drm/rockchip/transmitter/Kconfig
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
|
||||
menuconfig RK_TRSM
|
||||
bool "RockChip display transmitter support"
|
||||
depends on FB_ROCKCHIP
|
||||
|
||||
config RK2928_LVDS
|
||||
bool "RK2928/RK2926 lvds transmitter support"
|
||||
depends on ARCH_RK2928 && RK_TRSM
|
||||
|
||||
config RK3026_LVDS
|
||||
depends on ARCH_RK3026 && RK_TRSM
|
||||
bool "RK3026/RK3028A lvds transmitter support"
|
||||
default y
|
||||
|
||||
config RK32_LVDS
|
||||
bool "RK32 lvds transmitter support"
|
||||
depends on RK_TRSM
|
||||
|
||||
config RK610_LVDS
|
||||
bool "RK610(Jetta) lvds transmitter support"
|
||||
depends on MFD_RK610 && RK_TRSM
|
||||
help
|
||||
Support Jetta(RK610) to output LCD1 and LVDS.
|
||||
|
||||
config RK616_LVDS
|
||||
bool "RK616(JettaB) lvds,lcd,scaler vido interface support"
|
||||
depends on MFD_RK616 && RK_TRSM
|
||||
help
|
||||
RK616(Jetta B) LVDS,LCD,scaler transmitter support.
|
||||
|
||||
|
||||
config DP_ANX6345
|
||||
bool "RGB to DisplayPort transmitter anx6345,anx9804,anx9805 support"
|
||||
depends on RK_TRSM
|
||||
|
||||
config DP501
|
||||
bool"RGB to DisplayPort transmitter dp501 support"
|
||||
depends on RK_TRSM
|
||||
|
||||
config RK32_DP
|
||||
bool "RK32 RGB to DisplayPort transmitter support "
|
||||
depends on RK_TRSM
|
||||
|
||||
config MIPI_DSI
|
||||
depends on RK_TRSM
|
||||
bool "Rockchip MIPI DSI support"
|
||||
|
||||
config TC358768_RGB2MIPI
|
||||
tristate "toshiba TC358768 RGB to MIPI DSI"
|
||||
depends on MIPI_DSI
|
||||
help
|
||||
"a chip that change RGB interface parallel signal into DSI serial signal"
|
||||
|
||||
config SSD2828_RGB2MIPI
|
||||
tristate "solomon SSD2828 RGB to MIPI DSI"
|
||||
depends on MIPI_DSI
|
||||
help
|
||||
"a chip that change RGB interface parallel signal into DSI serial signal"
|
||||
|
||||
config RK616_MIPI_DSI
|
||||
tristate "Rockchip mipi dsi support"
|
||||
depends on MIPI_DSI
|
||||
help
|
||||
Rockchip mipi dsi support.
|
||||
|
||||
|
||||
config RK616_MIPI_DSI_RST
|
||||
bool "Reset the rockchip mipi dsi"
|
||||
depends on MFD_RK616 && RK616_MIPI_DSI && RK616_USE_MCLK_12M
|
||||
default y
|
||||
help
|
||||
if you say y here: inset the hdmi, mipi lcd will be reset.
|
||||
16
drivers/gpu/drm/rockchip/transmitter/Makefile
Normal file
16
drivers/gpu/drm/rockchip/transmitter/Makefile
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#
|
||||
# Makefile for display transmitter like lvds edp mipi
|
||||
#
|
||||
obj-$(CONFIG_RK2928_LVDS) += rk2928_lvds.o
|
||||
obj-$(CONFIG_RK3026_LVDS) += rk3026_lvds.o
|
||||
obj-$(CONFIG_RK610_LVDS) += rk610_lcd.o
|
||||
obj-$(CONFIG_RK616_LVDS) += rk616_lvds.o
|
||||
obj-y += rk32_lvds.o
|
||||
obj-$(CONFIG_DP_ANX6345) += dp_anx6345.o
|
||||
obj-$(CONFIG_DP501) += dp501.o
|
||||
obj-$(CONFIG_RK32_DP) += rk32_dp.o rk32_dp_reg.o
|
||||
obj-$(CONFIG_MIPI_DSI) += mipi_dsi.o
|
||||
obj-$(CONFIG_RK616_MIPI_DSI) += rk616_mipi_dsi.o
|
||||
obj-$(CONFIG_TC358768_RGB2MIPI) += tc358768.o
|
||||
obj-$(CONFIG_SSD2828_RGB2MIPI) += ssd2828.o
|
||||
|
||||
323
drivers/gpu/drm/rockchip/transmitter/rk32_lvds.c
Executable file
323
drivers/gpu/drm/rockchip/transmitter/rk32_lvds.c
Executable file
|
|
@ -0,0 +1,323 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/rk_fb.h>
|
||||
#include <linux/rockchip/iomap.h>
|
||||
#include <linux/rockchip/grf.h>
|
||||
#include "rk32_lvds.h"
|
||||
|
||||
//#define TTL_TO_LVDS 1
|
||||
static struct rk32_lvds *rk32_lvds;
|
||||
static int rk32_lvds_disable(void)
|
||||
{
|
||||
struct rk32_lvds *lvds = rk32_lvds;
|
||||
writel_relaxed(0x80008000, RK_GRF_VIRT + RK3288_GRF_SOC_CON7);
|
||||
writel_relaxed(0x00, lvds->regs + LVDS_CFG_REG_21); /*disable tx*/
|
||||
writel_relaxed(0xff, lvds->regs + LVDS_CFG_REG_c); /*disable pll*/
|
||||
clk_disable_unprepare(lvds->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk32_lvds_en(void)
|
||||
{
|
||||
struct rk32_lvds *lvds = rk32_lvds;
|
||||
struct rk_screen *screen = &lvds->screen;
|
||||
u32 h_bp = screen->mode.hsync_len + screen->mode.left_margin;
|
||||
u32 i,j, val ;
|
||||
|
||||
clk_prepare_enable(lvds->clk);
|
||||
screen->type = SCREEN_RGB;
|
||||
|
||||
screen->lcdc_id = 1;
|
||||
if (screen->lcdc_id == 1) /*lcdc1 = vop little,lcdc0 = vop big*/
|
||||
val = LVDS_SEL_VOP_LIT | (LVDS_SEL_VOP_LIT << 16);
|
||||
else
|
||||
val = LVDS_SEL_VOP_LIT << 16;
|
||||
writel_relaxed(val, RK_GRF_VIRT + RK3288_GRF_SOC_CON6);
|
||||
|
||||
val = screen->lvds_format;
|
||||
if (screen->type == SCREEN_DUAL_LVDS)
|
||||
val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN;
|
||||
else if(screen->type == SCREEN_LVDS)
|
||||
val |= LVDS_CH0_EN;
|
||||
|
||||
//val |= LVDS_MSB;
|
||||
else if (screen->type == SCREEN_RGB)
|
||||
val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN;
|
||||
|
||||
if (h_bp & 0x01)
|
||||
val |= LVDS_START_PHASE_RST_1;
|
||||
|
||||
val |= (screen->pin_dclk << 8) | (screen->pin_hsync << 9) |
|
||||
(screen->pin_den << 10);
|
||||
val |= 0xffff << 16;
|
||||
//val = 0x08010801;
|
||||
writel_relaxed(val, RK_GRF_VIRT + RK3288_GRF_SOC_CON7);
|
||||
|
||||
if (screen->type == SCREEN_LVDS)
|
||||
val = 0xbf;
|
||||
else
|
||||
val = 0x7f;
|
||||
#if 0
|
||||
for(i=0;i<0x200;){
|
||||
val = readl_relaxed(lvds->regs + i);
|
||||
printk("0x%08x:0x%08x ",i,val);
|
||||
i += 4;
|
||||
if(i % 16 == 0)
|
||||
printk("\n");
|
||||
}
|
||||
#endif
|
||||
#ifdef TTL_TO_LVDS // 0 ttl 1 lvds
|
||||
val = 0x007f007f;//0x1<<6 |0x1 <<4;
|
||||
writel_relaxed(val, RK_GRF_VIRT + 0xc);
|
||||
|
||||
|
||||
lvds_writel(lvds, LVDS_CH0_REG_0, 0x7f);
|
||||
lvds_writel(lvds, LVDS_CH0_REG_1, 0x40);
|
||||
lvds_writel(lvds, LVDS_CH0_REG_2, 0x00);
|
||||
|
||||
if (screen->type == SCREEN_RGB)
|
||||
val = 0x1f;
|
||||
else
|
||||
val = 0x00;
|
||||
lvds_writel(lvds, LVDS_CH0_REG_4, 0x3f);
|
||||
lvds_writel(lvds, LVDS_CH0_REG_5, 0x3f);
|
||||
lvds_writel(lvds, LVDS_CH0_REG_3, 0x46);
|
||||
lvds_writel(lvds, LVDS_CH0_REG_d, 0x0a);
|
||||
lvds_writel(lvds, LVDS_CH0_REG_20,0x44);/* 44:LSB 45:MSB*/
|
||||
writel_relaxed(0x00, lvds->regs + LVDS_CFG_REG_c); /*eanble pll*/
|
||||
writel_relaxed(0x92, lvds->regs + LVDS_CFG_REG_21); /*enable tx*/
|
||||
|
||||
lvds_writel(lvds, 0x100, 0x7f);
|
||||
lvds_writel(lvds, 0x104, 0x40);
|
||||
lvds_writel(lvds, 0x108, 0x00);
|
||||
lvds_writel(lvds, 0x10c, 0x46);
|
||||
lvds_writel(lvds, 0x110, 0x3f);
|
||||
lvds_writel(lvds, 0x114, 0x3f);
|
||||
lvds_writel(lvds, 0x134, 0x0a);
|
||||
#else
|
||||
val = readl_relaxed(lvds->regs + 0x88);
|
||||
printk("0x88:0x%x\n",val);
|
||||
|
||||
lvds_writel(lvds, LVDS_CH0_REG_0, 0xbf);
|
||||
lvds_writel(lvds, LVDS_CH0_REG_1, 0x3f);// 3f
|
||||
lvds_writel(lvds, LVDS_CH0_REG_2, 0xfe);
|
||||
lvds_writel(lvds, LVDS_CH0_REG_3, 0x46);//0x46
|
||||
lvds_writel(lvds, LVDS_CH0_REG_4, 0x00);
|
||||
//lvds_writel(lvds, LVDS_CH0_REG_9, 0x20);
|
||||
//lvds_writel(lvds, LVDS_CH0_REG_d, 0x4b);
|
||||
//lvds_writel(lvds, LVDS_CH0_REG_f, 0x0d);
|
||||
lvds_writel(lvds, LVDS_CH0_REG_d, 0x0a);//0a
|
||||
lvds_writel(lvds, LVDS_CH0_REG_20,0x44);/* 44:LSB 45:MSB*/
|
||||
//lvds_writel(lvds, 0x24,0x20);
|
||||
//writel_relaxed(0x23, lvds->regs + 0x88);
|
||||
writel_relaxed(0x00, lvds->regs + LVDS_CFG_REG_c); /*eanble pll*/
|
||||
writel_relaxed(0x92, lvds->regs + LVDS_CFG_REG_21); /*enable tx*/
|
||||
|
||||
|
||||
//lvds_writel(lvds, 0x100, 0xbf);
|
||||
//lvds_writel(lvds, 0x104, 0x3f);
|
||||
//lvds_writel(lvds, 0x108, 0xfe);
|
||||
//lvds_writel(lvds, 0x10c, 0x46); //0x46
|
||||
//lvds_writel(lvds, 0x110, 0x00);
|
||||
//lvds_writel(lvds, 0x114, 0x00);
|
||||
//lvds_writel(lvds, 0x134, 0x0a);
|
||||
|
||||
#endif
|
||||
#if 0
|
||||
for(i=0;i<100;i++){
|
||||
mdelay(1000);
|
||||
mdelay(1000);
|
||||
mdelay(1000);
|
||||
mdelay(1000);
|
||||
mdelay(1000);
|
||||
printk("write LVDS_CH0_REG_20 :0x40\n");
|
||||
//writel_relaxed(0x10, lvds->regs + LVDS_CFG_REG_c);
|
||||
lvds_writel(lvds, LVDS_CH0_REG_20,0x40);/* 44:LSB 45:MSB*/
|
||||
val = readl_relaxed(lvds->regs + LVDS_CH0_REG_20);
|
||||
printk("read back LVDS_CH0_REG_20:0x%x\n",val);
|
||||
mdelay(1000);
|
||||
mdelay(1000);
|
||||
mdelay(1000);
|
||||
mdelay(1000);
|
||||
mdelay(1000);
|
||||
printk("write LVDS_CH0_REG_20 :0x44\n");
|
||||
lvds_writel(lvds, LVDS_CH0_REG_20,0x44);/* 44:LSB 45:MSB*/
|
||||
val = readl_relaxed(lvds->regs + LVDS_CH0_REG_20);
|
||||
printk("read back LVDS_CH0_REG_20:0x%x\n",val);
|
||||
}
|
||||
#endif
|
||||
//while(1)
|
||||
#if 0
|
||||
{
|
||||
val = readl_relaxed(RK_GRF_VIRT + RK3288_GRF_SOC_CON6);
|
||||
printk("RK3288_GRF_SOC_CON6:0x%x\n",val);
|
||||
val = readl_relaxed(RK_GRF_VIRT + RK3288_GRF_SOC_CON7);
|
||||
printk("RK3288_GRF_SOC_CON7:0x%x\n",val);
|
||||
val = readl_relaxed(RK_GRF_VIRT + RK3288_GRF_SOC_CON15);
|
||||
printk("RK3288_GRF_SOC_CON15:0x%x\n",val);
|
||||
|
||||
|
||||
val = readl_relaxed(lvds->regs + LVDS_CH0_REG_0);
|
||||
printk("LVDS_CH0_REG_0:0x%x\n",val);
|
||||
|
||||
val = readl_relaxed(lvds->regs + LVDS_CH0_REG_1);
|
||||
printk("LVDS_CH0_REG_1:0x%x\n",val);
|
||||
|
||||
val = readl_relaxed(lvds->regs + LVDS_CH0_REG_2);
|
||||
printk("LVDS_CH0_REG_2:0x%x\n",val);
|
||||
|
||||
val = readl_relaxed(lvds->regs + LVDS_CH0_REG_3);
|
||||
printk("LVDS_CH0_REG_3:0x%x\n",val);
|
||||
|
||||
val = readl_relaxed(lvds->regs + LVDS_CH0_REG_4);
|
||||
printk("LVDS_CH0_REG_4:0x%x\n",val);
|
||||
|
||||
val = readl_relaxed(lvds->regs + LVDS_CH0_REG_5);
|
||||
printk("LVDS_CH0_REG_5:0x%x\n",val);
|
||||
|
||||
val = readl_relaxed(lvds->regs + LVDS_CH0_REG_d);
|
||||
printk("LVDS_CH0_REG_d:0x%x\n",val);
|
||||
|
||||
val = readl_relaxed(lvds->regs + LVDS_CH0_REG_f);
|
||||
printk("LVDS_CH0_REG_f:0x%x\n",val);
|
||||
|
||||
|
||||
val = readl_relaxed(lvds->regs + LVDS_CFG_REG_c);
|
||||
printk("LVDS_CFG_REG_c:0x%x\n",val);
|
||||
|
||||
val = readl_relaxed(lvds->regs + LVDS_CFG_REG_21);
|
||||
printk("LVDS_CFG_REG_21:0x%x\n",val);
|
||||
val = readl_relaxed(lvds->regs + 0x100);
|
||||
printk("0x100:0x%x\n",val);
|
||||
|
||||
val = readl_relaxed(lvds->regs + 0x104);
|
||||
printk("0x104:0x%x\n",val);
|
||||
val = readl_relaxed(lvds->regs + 0x108);
|
||||
printk("0x108:0x%x\n",val);
|
||||
|
||||
val = readl_relaxed(lvds->regs + 0x10c);
|
||||
printk("0x10c:0x%x\n",val);
|
||||
|
||||
val = readl_relaxed(lvds->regs + 0x110);
|
||||
printk("0x110:0x%x\n",val);
|
||||
|
||||
val = readl_relaxed(lvds->regs + 0x114);
|
||||
printk("0x114:0x%x\n",val);
|
||||
val = readl_relaxed(lvds->regs + 0x118);
|
||||
printk("0x118:0x%x\n",val);
|
||||
|
||||
val = readl_relaxed(lvds->regs + 0x11c);
|
||||
printk("0x11c:0x%x\n",val);
|
||||
mdelay(1000);
|
||||
}
|
||||
|
||||
for(i=0;i<0x200;){
|
||||
val = readl_relaxed(lvds->regs + i);
|
||||
printk("0x%08x:0x%08x ",i,val);
|
||||
i += 4;
|
||||
if(i % 16 == 0)
|
||||
printk("\n");
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct rk_fb_trsm_ops trsm_lvds_ops = {
|
||||
.enable = rk32_lvds_en,
|
||||
.disable = rk32_lvds_disable,
|
||||
};
|
||||
|
||||
static int rk32_lvds_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk32_lvds *lvds;
|
||||
struct resource *res;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "Missing device tree node.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lvds = devm_kzalloc(&pdev->dev, sizeof(struct rk32_lvds), GFP_KERNEL);
|
||||
if (!lvds) {
|
||||
dev_err(&pdev->dev, "no memory for state\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
lvds->dev = &pdev->dev;
|
||||
rk_fb_get_prmry_screen(&lvds->screen);
|
||||
if ((lvds->screen.type != SCREEN_RGB) &&
|
||||
(lvds->screen.type != SCREEN_LVDS) &&
|
||||
(lvds->screen.type != SCREEN_DUAL_LVDS)) {
|
||||
dev_err(&pdev->dev, "screen is not lvds/rgb!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
platform_set_drvdata(pdev, lvds);
|
||||
dev_set_name(lvds->dev, "rk32-lvds");
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
lvds->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(lvds->regs)) {
|
||||
dev_err(&pdev->dev, "ioremap reg failed\n");
|
||||
return PTR_ERR(lvds->regs);
|
||||
}
|
||||
lvds->clk = devm_clk_get(&pdev->dev,NULL);
|
||||
if (IS_ERR(lvds->clk)) {
|
||||
dev_err(&pdev->dev, "get clk failed\n");
|
||||
return PTR_ERR(lvds->clk);
|
||||
}
|
||||
rk32_lvds = lvds;
|
||||
rk_fb_trsm_ops_register(&trsm_lvds_ops,SCREEN_LVDS);
|
||||
dev_info(&pdev->dev, "rk32 lvds driver probe success\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk32_lvds_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id rk32_lvds_dt_ids[] = {
|
||||
{.compatible = "rockchip, rk32-lvds",},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, rk32_lvds_dt_ids);
|
||||
#endif
|
||||
|
||||
static struct platform_driver rk32_lvds_driver = {
|
||||
.probe = rk32_lvds_probe,
|
||||
.driver = {
|
||||
.name = "rk32-lvds",
|
||||
.owner = THIS_MODULE,
|
||||
#if defined(CONFIG_OF)
|
||||
.of_match_table = of_match_ptr(rk32_lvds_dt_ids),
|
||||
#endif
|
||||
},
|
||||
.shutdown = rk32_lvds_shutdown,
|
||||
};
|
||||
|
||||
static int __init rk32_lvds_module_init(void)
|
||||
{
|
||||
return platform_driver_register(&rk32_lvds_driver);
|
||||
}
|
||||
|
||||
static void __exit rk32_lvds_module_exit(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
fs_initcall(rk32_lvds_module_init);
|
||||
module_exit(rk32_lvds_module_exit);
|
||||
|
||||
44
drivers/gpu/drm/rockchip/transmitter/rk32_lvds.h
Executable file
44
drivers/gpu/drm/rockchip/transmitter/rk32_lvds.h
Executable file
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef __RK32_LVDS__
|
||||
#define __RK32_LVDS__
|
||||
|
||||
#define LVDS_CH0_REG_0 0x00
|
||||
#define LVDS_CH0_REG_1 0x04
|
||||
#define LVDS_CH0_REG_2 0x08
|
||||
#define LVDS_CH0_REG_3 0x0c
|
||||
#define LVDS_CH0_REG_4 0x10
|
||||
#define LVDS_CH0_REG_5 0x14
|
||||
#define LVDS_CH0_REG_9 0x24
|
||||
#define LVDS_CFG_REG_c 0x30
|
||||
#define LVDS_CH0_REG_d 0x34
|
||||
#define LVDS_CH0_REG_f 0x3c
|
||||
#define LVDS_CH0_REG_20 0x80
|
||||
#define LVDS_CFG_REG_21 0x84
|
||||
|
||||
#define LVDS_SEL_VOP_LIT (1 << 3)
|
||||
|
||||
#define LVDS_FMT_MASK (0x07 << 16)
|
||||
#define LVDS_MSB (0x01 << 3)
|
||||
#define LVDS_DUAL (0x01 << 4)
|
||||
#define LVDS_FMT_1 (0x01 << 5)
|
||||
#define LVDS_TTL_EN (0x01 << 6)
|
||||
#define LVDS_START_PHASE_RST_1 (0x01 << 7)
|
||||
#define LVDS_DCLK_INV (0x01 << 8)
|
||||
#define LVDS_CH0_EN (0x01 << 11)
|
||||
#define LVDS_CH1_EN (0x01 << 12)
|
||||
#define LVDS_PWRDN (0x01 << 15)
|
||||
|
||||
struct rk32_lvds {
|
||||
struct device *dev;
|
||||
void __iomem *regs;
|
||||
struct clk *clk; /*phb clk*/
|
||||
struct rk_screen screen;
|
||||
};
|
||||
|
||||
static int inline lvds_writel(struct rk32_lvds *lvds, u32 offset, u32 val)
|
||||
{
|
||||
writel_relaxed(val, lvds->regs + offset);
|
||||
//if (lvds->screen.type == SCREEN_DUAL_LVDS)
|
||||
writel_relaxed(val, lvds->regs + offset + 0x100);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -204,7 +204,7 @@ int drm_err(const char *func, const char *format, ...);
|
|||
* \param fmt printf() like format string.
|
||||
* \param arg arguments
|
||||
*/
|
||||
#if DRM_DEBUG_CODE
|
||||
#if 0// DRM_DEBUG_CODE
|
||||
#define DRM_DEBUG(fmt, args...) \
|
||||
do { \
|
||||
drm_ut_debug_printk(DRM_UT_CORE, DRM_NAME, \
|
||||
|
|
|
|||
100
include/drm/rockchip_drm.h
Normal file
100
include/drm/rockchip_drm.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/* rockchip_drm.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 _rockchip_DRM_H_
|
||||
#define _rockchip_DRM_H_
|
||||
|
||||
#include <uapi/drm/rockchip_drm.h>
|
||||
|
||||
/**
|
||||
* A structure for lcd panel information.
|
||||
*
|
||||
* @timing: default video mode for initializing
|
||||
* @width_mm: physical size of lcd width.
|
||||
* @height_mm: physical size of lcd height.
|
||||
*/
|
||||
struct rockchip_drm_panel_info {
|
||||
struct fb_videomode timing;
|
||||
u32 width_mm;
|
||||
u32 height_mm;
|
||||
};
|
||||
|
||||
/**
|
||||
* Platform Specific Structure for DRM based FIMD.
|
||||
*
|
||||
* @panel: default panel info for initializing
|
||||
* @default_win: default window layer number to be used for UI.
|
||||
* @bpp: default bit per pixel.
|
||||
*/
|
||||
struct rockchip_drm_fimd_pdata {
|
||||
struct rockchip_drm_panel_info panel;
|
||||
u32 vidcon0;
|
||||
u32 vidcon1;
|
||||
unsigned int default_win;
|
||||
unsigned int bpp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Platform Specific Structure for DRM based HDMI.
|
||||
*
|
||||
* @hdmi_dev: device point to specific hdmi driver.
|
||||
* @mixer_dev: device point to specific mixer driver.
|
||||
*
|
||||
* this structure is used for common hdmi driver and each device object
|
||||
* would be used to access specific device driver(hdmi or mixer driver)
|
||||
*/
|
||||
struct rockchip_drm_common_hdmi_pd {
|
||||
struct device *hdmi_dev;
|
||||
struct device *mixer_dev;
|
||||
};
|
||||
|
||||
/**
|
||||
* Platform Specific Structure for DRM based HDMI core.
|
||||
*
|
||||
* @is_v13: set if hdmi version 13 is.
|
||||
* @cfg_hpd: function pointer to configure hdmi hotplug detection pin
|
||||
* @get_hpd: function pointer to get value of hdmi hotplug detection pin
|
||||
*/
|
||||
struct rockchip_drm_hdmi_pdata {
|
||||
bool is_v13;
|
||||
void (*cfg_hpd)(bool external);
|
||||
int (*get_hpd)(void);
|
||||
};
|
||||
|
||||
/**
|
||||
* Platform Specific Structure for DRM based IPP.
|
||||
*
|
||||
* @inv_pclk: if set 1. invert pixel clock
|
||||
* @inv_vsync: if set 1. invert vsync signal for wb
|
||||
* @inv_href: if set 1. invert href signal
|
||||
* @inv_hsync: if set 1. invert hsync signal for wb
|
||||
*/
|
||||
struct rockchip_drm_ipp_pol {
|
||||
unsigned int inv_pclk;
|
||||
unsigned int inv_vsync;
|
||||
unsigned int inv_href;
|
||||
unsigned int inv_hsync;
|
||||
};
|
||||
|
||||
/**
|
||||
* Platform Specific Structure for DRM based FIMC.
|
||||
*
|
||||
* @pol: current hardware block polarity settings.
|
||||
* @clk_rate: current hardware clock rate.
|
||||
*/
|
||||
struct rockchip_drm_fimc_pdata {
|
||||
struct rockchip_drm_ipp_pol pol;
|
||||
int clk_rate;
|
||||
};
|
||||
|
||||
#endif /* _rockchip_DRM_H_ */
|
||||
390
include/uapi/drm/rockchip_drm.h
Normal file
390
include/uapi/drm/rockchip_drm.h
Normal file
|
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (C) ROCKCHIP, Inc.
|
||||
*Author:yzq<yzq@rock-chips.com>
|
||||
* 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 _UAPI_ROCKCHIP_DRM_H_
|
||||
#define _UAPI_ROCKCHIP_DRM_H_
|
||||
|
||||
#include <drm/drm.h>
|
||||
|
||||
/**
|
||||
* User-desired buffer creation information structure.
|
||||
*
|
||||
* @size: user-desired memory allocation size.
|
||||
* - this size value would be page-aligned internally.
|
||||
* @flags: user request for setting memory type or cache attributes.
|
||||
* @handle: returned a handle to created gem object.
|
||||
* - this handle will be set by gem module of kernel side.
|
||||
*/
|
||||
struct drm_rockchip_gem_create {
|
||||
uint64_t size;
|
||||
unsigned int flags;
|
||||
unsigned int handle;
|
||||
};
|
||||
|
||||
/**
|
||||
* A structure for getting buffer offset.
|
||||
*
|
||||
* @handle: a pointer to gem object created.
|
||||
* @pad: just padding to be 64-bit aligned.
|
||||
* @offset: relatived offset value of the memory region allocated.
|
||||
* - this value should be set by user.
|
||||
*/
|
||||
struct drm_rockchip_gem_map_off {
|
||||
unsigned int handle;
|
||||
unsigned int pad;
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* A structure for mapping buffer.
|
||||
*
|
||||
* @handle: a handle to gem object created.
|
||||
* @pad: just padding to be 64-bit aligned.
|
||||
* @size: memory size to be mapped.
|
||||
* @mapped: having user virtual address mmaped.
|
||||
* - this variable would be filled by exynos gem module
|
||||
* of kernel side with user virtual address which is allocated
|
||||
* by do_mmap().
|
||||
*/
|
||||
struct drm_rockchip_gem_mmap {
|
||||
unsigned int handle;
|
||||
unsigned int pad;
|
||||
uint64_t size;
|
||||
uint64_t mapped;
|
||||
};
|
||||
|
||||
/**
|
||||
* A structure to gem information.
|
||||
*
|
||||
* @handle: a handle to gem object created.
|
||||
* @flags: flag value including memory type and cache attribute and
|
||||
* this value would be set by driver.
|
||||
* @size: size to memory region allocated by gem and this size would
|
||||
* be set by driver.
|
||||
*/
|
||||
struct drm_rockchip_gem_info {
|
||||
unsigned int handle;
|
||||
unsigned int flags;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* A structure for user connection request of virtual display.
|
||||
*
|
||||
* @connection: indicate whether doing connetion or not by user.
|
||||
* @extensions: if this value is 1 then the vidi driver would need additional
|
||||
* 128bytes edid data.
|
||||
* @edid: the edid data pointer from user side.
|
||||
*/
|
||||
struct drm_rockchip_vidi_connection {
|
||||
unsigned int connection;
|
||||
unsigned int extensions;
|
||||
uint64_t edid;
|
||||
};
|
||||
|
||||
/* memory type definitions. */
|
||||
enum e_drm_rockchip_gem_mem_type {
|
||||
/* Physically Continuous memory and used as default. */
|
||||
ROCKCHIP_BO_CONTIG = 0 << 0,
|
||||
/* Physically Non-Continuous memory. */
|
||||
ROCKCHIP_BO_NONCONTIG = 1 << 0,
|
||||
/* non-cachable mapping and used as default. */
|
||||
ROCKCHIP_BO_NONCACHABLE = 0 << 1,
|
||||
/* cachable mapping. */
|
||||
ROCKCHIP_BO_CACHABLE = 1 << 1,
|
||||
/* write-combine mapping. */
|
||||
ROCKCHIP_BO_WC = 1 << 2,
|
||||
ROCKCHIP_BO_MASK = ROCKCHIP_BO_NONCONTIG | ROCKCHIP_BO_CACHABLE |
|
||||
ROCKCHIP_BO_WC
|
||||
};
|
||||
|
||||
struct drm_rockchip_g2d_get_ver {
|
||||
__u32 major;
|
||||
__u32 minor;
|
||||
};
|
||||
|
||||
struct drm_rockchip_g2d_cmd {
|
||||
__u32 offset;
|
||||
__u32 data;
|
||||
};
|
||||
|
||||
enum drm_rockchip_g2d_buf_type {
|
||||
G2D_BUF_USERPTR = 1 << 31,
|
||||
};
|
||||
|
||||
enum drm_rockchip_g2d_event_type {
|
||||
G2D_EVENT_NOT,
|
||||
G2D_EVENT_NONSTOP,
|
||||
G2D_EVENT_STOP, /* not yet */
|
||||
};
|
||||
|
||||
struct drm_rockchip_g2d_userptr {
|
||||
unsigned long userptr;
|
||||
unsigned long size;
|
||||
};
|
||||
|
||||
struct drm_rockchip_g2d_set_cmdlist {
|
||||
__u64 cmd;
|
||||
__u64 cmd_buf;
|
||||
__u32 cmd_nr;
|
||||
__u32 cmd_buf_nr;
|
||||
|
||||
/* for g2d event */
|
||||
__u64 event_type;
|
||||
__u64 user_data;
|
||||
};
|
||||
|
||||
struct drm_rockchip_g2d_exec {
|
||||
__u64 async;
|
||||
};
|
||||
|
||||
enum drm_rockchip_ops_id {
|
||||
ROCKCHIP_DRM_OPS_SRC,
|
||||
ROCKCHIP_DRM_OPS_DST,
|
||||
ROCKCHIP_DRM_OPS_MAX,
|
||||
};
|
||||
|
||||
struct drm_rockchip_sz {
|
||||
__u32 hsize;
|
||||
__u32 vsize;
|
||||
};
|
||||
|
||||
struct drm_rockchip_pos {
|
||||
__u32 x;
|
||||
__u32 y;
|
||||
__u32 w;
|
||||
__u32 h;
|
||||
};
|
||||
|
||||
enum drm_rockchip_flip {
|
||||
ROCKCHIP_DRM_FLIP_NONE = (0 << 0),
|
||||
ROCKCHIP_DRM_FLIP_VERTICAL = (1 << 0),
|
||||
ROCKCHIP_DRM_FLIP_HORIZONTAL = (1 << 1),
|
||||
ROCKCHIP_DRM_FLIP_BOTH = ROCKCHIP_DRM_FLIP_VERTICAL |
|
||||
ROCKCHIP_DRM_FLIP_HORIZONTAL,
|
||||
};
|
||||
|
||||
enum drm_rockchip_degree {
|
||||
ROCKCHIP_DRM_DEGREE_0,
|
||||
ROCKCHIP_DRM_DEGREE_90,
|
||||
ROCKCHIP_DRM_DEGREE_180,
|
||||
ROCKCHIP_DRM_DEGREE_270,
|
||||
};
|
||||
|
||||
enum drm_rockchip_planer {
|
||||
ROCKCHIP_DRM_PLANAR_Y,
|
||||
ROCKCHIP_DRM_PLANAR_CB,
|
||||
ROCKCHIP_DRM_PLANAR_CR,
|
||||
ROCKCHIP_DRM_PLANAR_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* A structure for ipp supported property list.
|
||||
*
|
||||
* @version: version of this structure.
|
||||
* @ipp_id: id of ipp driver.
|
||||
* @count: count of ipp driver.
|
||||
* @writeback: flag of writeback supporting.
|
||||
* @flip: flag of flip supporting.
|
||||
* @degree: flag of degree information.
|
||||
* @csc: flag of csc supporting.
|
||||
* @crop: flag of crop supporting.
|
||||
* @scale: flag of scale supporting.
|
||||
* @refresh_min: min hz of refresh.
|
||||
* @refresh_max: max hz of refresh.
|
||||
* @crop_min: crop min resolution.
|
||||
* @crop_max: crop max resolution.
|
||||
* @scale_min: scale min resolution.
|
||||
* @scale_max: scale max resolution.
|
||||
*/
|
||||
struct drm_rockchip_ipp_prop_list {
|
||||
__u32 version;
|
||||
__u32 ipp_id;
|
||||
__u32 count;
|
||||
__u32 writeback;
|
||||
__u32 flip;
|
||||
__u32 degree;
|
||||
__u32 csc;
|
||||
__u32 crop;
|
||||
__u32 scale;
|
||||
__u32 refresh_min;
|
||||
__u32 refresh_max;
|
||||
__u32 reserved;
|
||||
struct drm_rockchip_sz crop_min;
|
||||
struct drm_rockchip_sz crop_max;
|
||||
struct drm_rockchip_sz scale_min;
|
||||
struct drm_rockchip_sz scale_max;
|
||||
};
|
||||
|
||||
/**
|
||||
* A structure for ipp config.
|
||||
*
|
||||
* @ops_id: property of operation directions.
|
||||
* @flip: property of mirror, flip.
|
||||
* @degree: property of rotation degree.
|
||||
* @fmt: property of image format.
|
||||
* @sz: property of image size.
|
||||
* @pos: property of image position(src-cropped,dst-scaler).
|
||||
*/
|
||||
struct drm_rockchip_ipp_config {
|
||||
enum drm_rockchip_ops_id ops_id;
|
||||
enum drm_rockchip_flip flip;
|
||||
enum drm_rockchip_degree degree;
|
||||
__u32 fmt;
|
||||
struct drm_rockchip_sz sz;
|
||||
struct drm_rockchip_pos pos;
|
||||
};
|
||||
|
||||
enum drm_rockchip_ipp_cmd {
|
||||
IPP_CMD_NONE,
|
||||
IPP_CMD_M2M,
|
||||
IPP_CMD_WB,
|
||||
IPP_CMD_OUTPUT,
|
||||
IPP_CMD_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* A structure for ipp property.
|
||||
*
|
||||
* @config: source, destination config.
|
||||
* @cmd: definition of command.
|
||||
* @ipp_id: id of ipp driver.
|
||||
* @prop_id: id of property.
|
||||
* @refresh_rate: refresh rate.
|
||||
*/
|
||||
struct drm_rockchip_ipp_property {
|
||||
struct drm_rockchip_ipp_config config[ROCKCHIP_DRM_OPS_MAX];
|
||||
enum drm_rockchip_ipp_cmd cmd;
|
||||
__u32 ipp_id;
|
||||
__u32 prop_id;
|
||||
__u32 refresh_rate;
|
||||
};
|
||||
|
||||
enum drm_rockchip_ipp_buf_type {
|
||||
IPP_BUF_ENQUEUE,
|
||||
IPP_BUF_DEQUEUE,
|
||||
};
|
||||
|
||||
/**
|
||||
* A structure for ipp buffer operations.
|
||||
*
|
||||
* @ops_id: operation directions.
|
||||
* @buf_type: definition of buffer.
|
||||
* @prop_id: id of property.
|
||||
* @buf_id: id of buffer.
|
||||
* @handle: Y, Cb, Cr each planar handle.
|
||||
* @user_data: user data.
|
||||
*/
|
||||
struct drm_rockchip_ipp_queue_buf {
|
||||
enum drm_rockchip_ops_id ops_id;
|
||||
enum drm_rockchip_ipp_buf_type buf_type;
|
||||
__u32 prop_id;
|
||||
__u32 buf_id;
|
||||
__u32 handle[ROCKCHIP_DRM_PLANAR_MAX];
|
||||
__u32 reserved;
|
||||
__u64 user_data;
|
||||
};
|
||||
|
||||
enum drm_rockchip_ipp_ctrl {
|
||||
IPP_CTRL_PLAY,
|
||||
IPP_CTRL_STOP,
|
||||
IPP_CTRL_PAUSE,
|
||||
IPP_CTRL_RESUME,
|
||||
IPP_CTRL_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* A structure for ipp start/stop operations.
|
||||
*
|
||||
* @prop_id: id of property.
|
||||
* @ctrl: definition of control.
|
||||
*/
|
||||
struct drm_rockchip_ipp_cmd_ctrl {
|
||||
__u32 prop_id;
|
||||
enum drm_rockchip_ipp_ctrl ctrl;
|
||||
};
|
||||
|
||||
#define DRM_ROCKCHIP_GEM_CREATE 0x00
|
||||
#define DRM_ROCKCHIP_GEM_MAP_OFFSET 0x01
|
||||
#define DRM_ROCKCHIP_GEM_MMAP 0x02
|
||||
/* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
|
||||
#define DRM_ROCKCHIP_GEM_GET 0x04
|
||||
#define DRM_ROCKCHIP_VIDI_CONNECTION 0x07
|
||||
|
||||
/* G2D */
|
||||
#define DRM_ROCKCHIP_G2D_GET_VER 0x20
|
||||
#define DRM_ROCKCHIP_G2D_SET_CMDLIST 0x21
|
||||
#define DRM_ROCKCHIP_G2D_EXEC 0x22
|
||||
|
||||
/* IPP - Image Post Processing */
|
||||
#define DRM_ROCKCHIP_IPP_GET_PROPERTY 0x30
|
||||
#define DRM_ROCKCHIP_IPP_SET_PROPERTY 0x31
|
||||
#define DRM_ROCKCHIP_IPP_QUEUE_BUF 0x32
|
||||
#define DRM_ROCKCHIP_IPP_CMD_CTRL 0x33
|
||||
|
||||
#define DRM_IOCTL_ROCKCHIP_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \
|
||||
DRM_ROCKCHIP_GEM_CREATE, struct drm_rockchip_gem_create)
|
||||
|
||||
#define DRM_IOCTL_ROCKCHIP_GEM_MAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + \
|
||||
DRM_ROCKCHIP_GEM_MAP_OFFSET, struct drm_rockchip_gem_map_off)
|
||||
|
||||
#define DRM_IOCTL_ROCKCHIP_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + \
|
||||
DRM_ROCKCHIP_GEM_MMAP, struct drm_rockchip_gem_mmap)
|
||||
|
||||
#define DRM_IOCTL_ROCKCHIP_GEM_GET DRM_IOWR(DRM_COMMAND_BASE + \
|
||||
DRM_ROCKCHIP_GEM_GET, struct drm_rockchip_gem_info)
|
||||
|
||||
#define DRM_IOCTL_ROCKCHIP_VIDI_CONNECTION DRM_IOWR(DRM_COMMAND_BASE + \
|
||||
DRM_ROCKCHIP_VIDI_CONNECTION, struct drm_rockchip_vidi_connection)
|
||||
|
||||
#define DRM_IOCTL_ROCKCHIP_G2D_GET_VER DRM_IOWR(DRM_COMMAND_BASE + \
|
||||
DRM_ROCKCHIP_G2D_GET_VER, struct drm_rockchip_g2d_get_ver)
|
||||
#define DRM_IOCTL_ROCKCHIP_G2D_SET_CMDLIST DRM_IOWR(DRM_COMMAND_BASE + \
|
||||
DRM_ROCKCHIP_G2D_SET_CMDLIST, struct drm_rockchip_g2d_set_cmdlist)
|
||||
#define DRM_IOCTL_ROCKCHIP_G2D_EXEC DRM_IOWR(DRM_COMMAND_BASE + \
|
||||
DRM_ROCKCHIP_G2D_EXEC, struct drm_rockchip_g2d_exec)
|
||||
|
||||
#define DRM_IOCTL_ROCKCHIP_IPP_GET_PROPERTY DRM_IOWR(DRM_COMMAND_BASE + \
|
||||
DRM_ROCKCHIP_IPP_GET_PROPERTY, struct drm_rockchip_ipp_prop_list)
|
||||
#define DRM_IOCTL_ROCKCHIP_IPP_SET_PROPERTY DRM_IOWR(DRM_COMMAND_BASE + \
|
||||
DRM_ROCKCHIP_IPP_SET_PROPERTY, struct drm_rockchip_ipp_property)
|
||||
#define DRM_IOCTL_ROCKCHIP_IPP_QUEUE_BUF DRM_IOWR(DRM_COMMAND_BASE + \
|
||||
DRM_ROCKCHIP_IPP_QUEUE_BUF, struct drm_rockchip_ipp_queue_buf)
|
||||
#define DRM_IOCTL_ROCKCHIP_IPP_CMD_CTRL DRM_IOWR(DRM_COMMAND_BASE + \
|
||||
DRM_ROCKCHIP_IPP_CMD_CTRL, struct drm_rockchip_ipp_cmd_ctrl)
|
||||
|
||||
/* ROCKCHIP specific events */
|
||||
#define DRM_ROCKCHIP_G2D_EVENT 0x80000000
|
||||
#define DRM_ROCKCHIP_IPP_EVENT 0x80000001
|
||||
|
||||
struct drm_rockchip_g2d_event {
|
||||
struct drm_event base;
|
||||
__u64 user_data;
|
||||
__u32 tv_sec;
|
||||
__u32 tv_usec;
|
||||
__u32 cmdlist_no;
|
||||
__u32 reserved;
|
||||
};
|
||||
|
||||
struct drm_rockchip_ipp_event {
|
||||
struct drm_event base;
|
||||
__u64 user_data;
|
||||
__u32 tv_sec;
|
||||
__u32 tv_usec;
|
||||
__u32 prop_id;
|
||||
__u32 reserved;
|
||||
__u32 buf_id[ROCKCHIP_DRM_OPS_MAX];
|
||||
};
|
||||
|
||||
#endif /* _UAPI_ROCKCHIP_DRM_H_ */
|
||||
|
|
@ -75,7 +75,7 @@ struct display_timing {
|
|||
struct timing_entry vsync_len; /* ver. sync len */
|
||||
|
||||
enum display_flags flags; /* display flags */
|
||||
#if defined(CONFIG_FB_ROCKCHIP)
|
||||
#if defined(CONFIG_FB_ROCKCHIP) || defined(CONFIG_DRM_ROCKCHIP)
|
||||
u16 screen_type; /*screen type*/
|
||||
u16 lvds_format; /*lvds data format for lvds screen*/
|
||||
u16 face; /*display output interface format:24bit 18bit 16bit*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user