2015-12-15 08:58:26 +08:00
/*
* Copyright ( C ) Fuzhou Rockchip Electronics Co . Ltd
* Author : Mark Yao < mark . yao @ 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/component.h>
# include "rockchip_drm_vop.h"
# include "rockchip_vop_reg.h"
# define VOP_REG(off, _mask, s) \
{ . offset = off , \
. mask = _mask , \
. shift = s , }
2015-12-15 09:57:13 +08:00
static const uint32_t formats_win_full [ ] = {
2015-12-15 08:58:26 +08:00
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_ARGB8888 ,
DRM_FORMAT_XBGR8888 ,
DRM_FORMAT_ABGR8888 ,
DRM_FORMAT_RGB888 ,
DRM_FORMAT_BGR888 ,
DRM_FORMAT_RGB565 ,
DRM_FORMAT_BGR565 ,
DRM_FORMAT_NV12 ,
DRM_FORMAT_NV16 ,
DRM_FORMAT_NV24 ,
} ;
2015-12-15 09:57:13 +08:00
static const uint32_t formats_win_lite [ ] = {
2015-12-15 08:58:26 +08:00
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_ARGB8888 ,
DRM_FORMAT_XBGR8888 ,
DRM_FORMAT_ABGR8888 ,
DRM_FORMAT_RGB888 ,
DRM_FORMAT_BGR888 ,
DRM_FORMAT_RGB565 ,
DRM_FORMAT_BGR565 ,
} ;
2015-12-15 09:57:13 +08:00
static const struct vop_scl_extension rk3288_win_full_scl_ext = {
. cbcr_vsd_mode = VOP_REG ( RK3288_WIN0_CTRL1 , 0x1 , 31 ) ,
. cbcr_vsu_mode = VOP_REG ( RK3288_WIN0_CTRL1 , 0x1 , 30 ) ,
. cbcr_hsd_mode = VOP_REG ( RK3288_WIN0_CTRL1 , 0x3 , 28 ) ,
. cbcr_ver_scl_mode = VOP_REG ( RK3288_WIN0_CTRL1 , 0x3 , 26 ) ,
. cbcr_hor_scl_mode = VOP_REG ( RK3288_WIN0_CTRL1 , 0x3 , 24 ) ,
. yrgb_vsd_mode = VOP_REG ( RK3288_WIN0_CTRL1 , 0x1 , 23 ) ,
. yrgb_vsu_mode = VOP_REG ( RK3288_WIN0_CTRL1 , 0x1 , 22 ) ,
. yrgb_hsd_mode = VOP_REG ( RK3288_WIN0_CTRL1 , 0x3 , 20 ) ,
. yrgb_ver_scl_mode = VOP_REG ( RK3288_WIN0_CTRL1 , 0x3 , 18 ) ,
. yrgb_hor_scl_mode = VOP_REG ( RK3288_WIN0_CTRL1 , 0x3 , 16 ) ,
. line_load_mode = VOP_REG ( RK3288_WIN0_CTRL1 , 0x1 , 15 ) ,
. cbcr_axi_gather_num = VOP_REG ( RK3288_WIN0_CTRL1 , 0x7 , 12 ) ,
. yrgb_axi_gather_num = VOP_REG ( RK3288_WIN0_CTRL1 , 0xf , 8 ) ,
. vsd_cbcr_gt2 = VOP_REG ( RK3288_WIN0_CTRL1 , 0x1 , 7 ) ,
. vsd_cbcr_gt4 = VOP_REG ( RK3288_WIN0_CTRL1 , 0x1 , 6 ) ,
. vsd_yrgb_gt2 = VOP_REG ( RK3288_WIN0_CTRL1 , 0x1 , 5 ) ,
. vsd_yrgb_gt4 = VOP_REG ( RK3288_WIN0_CTRL1 , 0x1 , 4 ) ,
. bic_coe_sel = VOP_REG ( RK3288_WIN0_CTRL1 , 0x3 , 2 ) ,
. cbcr_axi_gather_en = VOP_REG ( RK3288_WIN0_CTRL1 , 0x1 , 1 ) ,
. yrgb_axi_gather_en = VOP_REG ( RK3288_WIN0_CTRL1 , 0x1 , 0 ) ,
. lb_mode = VOP_REG ( RK3288_WIN0_CTRL0 , 0x7 , 5 ) ,
} ;
static const struct vop_scl_regs rk3288_win_full_scl = {
. ext = & rk3288_win_full_scl_ext ,
. scale_yrgb_x = VOP_REG ( RK3288_WIN0_SCL_FACTOR_YRGB , 0xffff , 0x0 ) ,
. scale_yrgb_y = VOP_REG ( RK3288_WIN0_SCL_FACTOR_YRGB , 0xffff , 16 ) ,
. scale_cbcr_x = VOP_REG ( RK3288_WIN0_SCL_FACTOR_CBR , 0xffff , 0x0 ) ,
. scale_cbcr_y = VOP_REG ( RK3288_WIN0_SCL_FACTOR_CBR , 0xffff , 16 ) ,
} ;
static const struct vop_win_phy rk3288_win01_data = {
. scl = & rk3288_win_full_scl ,
. data_formats = formats_win_full ,
. nformats = ARRAY_SIZE ( formats_win_full ) ,
. enable = VOP_REG ( RK3288_WIN0_CTRL0 , 0x1 , 0 ) ,
. format = VOP_REG ( RK3288_WIN0_CTRL0 , 0x7 , 1 ) ,
. rb_swap = VOP_REG ( RK3288_WIN0_CTRL0 , 0x1 , 12 ) ,
. act_info = VOP_REG ( RK3288_WIN0_ACT_INFO , 0x1fff1fff , 0 ) ,
. dsp_info = VOP_REG ( RK3288_WIN0_DSP_INFO , 0x0fff0fff , 0 ) ,
. dsp_st = VOP_REG ( RK3288_WIN0_DSP_ST , 0x1fff1fff , 0 ) ,
. yrgb_mst = VOP_REG ( RK3288_WIN0_YRGB_MST , 0xffffffff , 0 ) ,
. uv_mst = VOP_REG ( RK3288_WIN0_CBR_MST , 0xffffffff , 0 ) ,
. yrgb_vir = VOP_REG ( RK3288_WIN0_VIR , 0x3fff , 0 ) ,
. uv_vir = VOP_REG ( RK3288_WIN0_VIR , 0x3fff , 16 ) ,
. src_alpha_ctl = VOP_REG ( RK3288_WIN0_SRC_ALPHA_CTRL , 0xff , 0 ) ,
. dst_alpha_ctl = VOP_REG ( RK3288_WIN0_DST_ALPHA_CTRL , 0xff , 0 ) ,
} ;
static const struct vop_win_phy rk3288_win23_data = {
. data_formats = formats_win_lite ,
. nformats = ARRAY_SIZE ( formats_win_lite ) ,
. enable = VOP_REG ( RK3288_WIN2_CTRL0 , 0x1 , 0 ) ,
. format = VOP_REG ( RK3288_WIN2_CTRL0 , 0x7 , 1 ) ,
. rb_swap = VOP_REG ( RK3288_WIN2_CTRL0 , 0x1 , 12 ) ,
. dsp_info = VOP_REG ( RK3288_WIN2_DSP_INFO0 , 0x0fff0fff , 0 ) ,
. dsp_st = VOP_REG ( RK3288_WIN2_DSP_ST0 , 0x1fff1fff , 0 ) ,
. yrgb_mst = VOP_REG ( RK3288_WIN2_MST0 , 0xffffffff , 0 ) ,
. yrgb_vir = VOP_REG ( RK3288_WIN2_VIR0_1 , 0x1fff , 0 ) ,
. src_alpha_ctl = VOP_REG ( RK3288_WIN2_SRC_ALPHA_CTRL , 0xff , 0 ) ,
. dst_alpha_ctl = VOP_REG ( RK3288_WIN2_DST_ALPHA_CTRL , 0xff , 0 ) ,
} ;
static const struct vop_ctrl rk3288_ctrl_data = {
. standby = VOP_REG ( RK3288_SYS_CTRL , 0x1 , 22 ) ,
. gate_en = VOP_REG ( RK3288_SYS_CTRL , 0x1 , 23 ) ,
. mmu_en = VOP_REG ( RK3288_SYS_CTRL , 0x1 , 20 ) ,
. rgb_en = VOP_REG ( RK3288_SYS_CTRL , 0x1 , 12 ) ,
. hdmi_en = VOP_REG ( RK3288_SYS_CTRL , 0x1 , 13 ) ,
. edp_en = VOP_REG ( RK3288_SYS_CTRL , 0x1 , 14 ) ,
. mipi_en = VOP_REG ( RK3288_SYS_CTRL , 0x1 , 15 ) ,
. dither_down = VOP_REG ( RK3288_DSP_CTRL1 , 0xf , 1 ) ,
. dither_up = VOP_REG ( RK3288_DSP_CTRL1 , 0x1 , 6 ) ,
. data_blank = VOP_REG ( RK3288_DSP_CTRL0 , 0x1 , 19 ) ,
. out_mode = VOP_REG ( RK3288_DSP_CTRL0 , 0xf , 0 ) ,
. pin_pol = VOP_REG ( RK3288_DSP_CTRL0 , 0xf , 4 ) ,
. htotal_pw = VOP_REG ( RK3288_DSP_HTOTAL_HS_END , 0x1fff1fff , 0 ) ,
. hact_st_end = VOP_REG ( RK3288_DSP_HACT_ST_END , 0x1fff1fff , 0 ) ,
. vtotal_pw = VOP_REG ( RK3288_DSP_VTOTAL_VS_END , 0x1fff1fff , 0 ) ,
. vact_st_end = VOP_REG ( RK3288_DSP_VACT_ST_END , 0x1fff1fff , 0 ) ,
. hpost_st_end = VOP_REG ( RK3288_POST_DSP_HACT_INFO , 0x1fff1fff , 0 ) ,
. vpost_st_end = VOP_REG ( RK3288_POST_DSP_VACT_INFO , 0x1fff1fff , 0 ) ,
. cfg_done = VOP_REG ( RK3288_REG_CFG_DONE , 0x1 , 0 ) ,
} ;
static const struct vop_reg_data rk3288_init_reg_table [ ] = {
{ RK3288_SYS_CTRL , 0x00c00000 } ,
{ RK3288_DSP_CTRL0 , 0x00000000 } ,
{ RK3288_WIN0_CTRL0 , 0x00000080 } ,
{ RK3288_WIN1_CTRL0 , 0x00000080 } ,
2015-12-15 08:58:26 +08:00
/* TODO: Win2/3 support multiple area function, but we haven't found
* a suitable way to use it yet , so let ' s just use them as other windows
* with only area 0 enabled .
*/
2015-12-15 09:57:13 +08:00
{ RK3288_WIN2_CTRL0 , 0x00000010 } ,
{ RK3288_WIN3_CTRL0 , 0x00000010 } ,
2015-12-15 08:58:26 +08:00
} ;
/*
* Note : rk3288 has a dedicated ' cursor ' window , however , that window requires
* special support to get alpha blending working . For now , just use overlay
* window 3 for the drm cursor .
*
*/
static const struct vop_win_data rk3288_vop_win_data [ ] = {
2015-12-15 09:57:13 +08:00
{ . base = 0x00 , . phy = & rk3288_win01_data ,
. type = DRM_PLANE_TYPE_PRIMARY } ,
{ . base = 0x40 , . phy = & rk3288_win01_data ,
. type = DRM_PLANE_TYPE_OVERLAY } ,
{ . base = 0x00 , . phy = & rk3288_win23_data ,
. type = DRM_PLANE_TYPE_OVERLAY } ,
{ . base = 0x50 , . phy = & rk3288_win23_data ,
. type = DRM_PLANE_TYPE_CURSOR } ,
2015-12-15 08:58:26 +08:00
} ;
static const int rk3288_vop_intrs [ ] = {
DSP_HOLD_VALID_INTR ,
FS_INTR ,
LINE_FLAG_INTR ,
BUS_ERROR_INTR ,
} ;
static const struct vop_intr rk3288_vop_intr = {
. intrs = rk3288_vop_intrs ,
. nintrs = ARRAY_SIZE ( rk3288_vop_intrs ) ,
2015-12-15 09:57:13 +08:00
. status = VOP_REG ( RK3288_INTR_CTRL0 , 0xf , 0 ) ,
. enable = VOP_REG ( RK3288_INTR_CTRL0 , 0xf , 4 ) ,
. clear = VOP_REG ( RK3288_INTR_CTRL0 , 0xf , 8 ) ,
2015-12-15 08:58:26 +08:00
} ;
static const struct vop_data rk3288_vop = {
2015-12-15 09:57:13 +08:00
. init_table = rk3288_init_reg_table ,
. table_size = ARRAY_SIZE ( rk3288_init_reg_table ) ,
2015-12-15 08:58:26 +08:00
. intr = & rk3288_vop_intr ,
2015-12-15 09:57:13 +08:00
. ctrl = & rk3288_ctrl_data ,
2015-12-15 08:58:26 +08:00
. win = rk3288_vop_win_data ,
. win_size = ARRAY_SIZE ( rk3288_vop_win_data ) ,
} ;
2015-12-15 09:57:13 +08:00
static const struct vop_scl_regs rk3066_win_scl = {
. scale_yrgb_x = VOP_REG ( RK3036_WIN0_SCL_FACTOR_YRGB , 0xffff , 0x0 ) ,
. scale_yrgb_y = VOP_REG ( RK3036_WIN0_SCL_FACTOR_YRGB , 0xffff , 16 ) ,
. scale_cbcr_x = VOP_REG ( RK3036_WIN0_SCL_FACTOR_CBR , 0xffff , 0x0 ) ,
. scale_cbcr_y = VOP_REG ( RK3036_WIN0_SCL_FACTOR_CBR , 0xffff , 16 ) ,
} ;
static const struct vop_win_phy rk3036_win0_data = {
. scl = & rk3066_win_scl ,
. data_formats = formats_win_full ,
. nformats = ARRAY_SIZE ( formats_win_full ) ,
. enable = VOP_REG ( RK3036_SYS_CTRL , 0x1 , 0 ) ,
. format = VOP_REG ( RK3036_SYS_CTRL , 0x7 , 3 ) ,
. rb_swap = VOP_REG ( RK3036_SYS_CTRL , 0x1 , 15 ) ,
. act_info = VOP_REG ( RK3036_WIN0_ACT_INFO , 0x1fff1fff , 0 ) ,
. dsp_info = VOP_REG ( RK3036_WIN0_DSP_INFO , 0x0fff0fff , 0 ) ,
. dsp_st = VOP_REG ( RK3036_WIN0_DSP_ST , 0x1fff1fff , 0 ) ,
. yrgb_mst = VOP_REG ( RK3036_WIN0_YRGB_MST , 0xffffffff , 0 ) ,
. uv_mst = VOP_REG ( RK3036_WIN0_CBR_MST , 0xffffffff , 0 ) ,
. yrgb_vir = VOP_REG ( RK3036_WIN0_VIR , 0xffff , 0 ) ,
} ;
static const struct vop_win_phy rk3036_win1_data = {
. data_formats = formats_win_lite ,
. nformats = ARRAY_SIZE ( formats_win_lite ) ,
. enable = VOP_REG ( RK3036_SYS_CTRL , 0x1 , 1 ) ,
. format = VOP_REG ( RK3036_SYS_CTRL , 0x7 , 6 ) ,
. rb_swap = VOP_REG ( RK3036_SYS_CTRL , 0x1 , 19 ) ,
. act_info = VOP_REG ( RK3036_WIN1_ACT_INFO , 0x1fff1fff , 0 ) ,
. dsp_info = VOP_REG ( RK3036_WIN1_DSP_INFO , 0x0fff0fff , 0 ) ,
. dsp_st = VOP_REG ( RK3036_WIN1_DSP_ST , 0x1fff1fff , 0 ) ,
. yrgb_mst = VOP_REG ( RK3036_WIN1_MST , 0xffffffff , 0 ) ,
. yrgb_vir = VOP_REG ( RK3036_WIN1_VIR , 0xffff , 0 ) ,
} ;
static const struct vop_win_data rk3036_vop_win_data [ ] = {
{ . base = 0x00 , . phy = & rk3036_win0_data ,
. type = DRM_PLANE_TYPE_PRIMARY } ,
{ . base = 0x00 , . phy = & rk3036_win1_data ,
. type = DRM_PLANE_TYPE_CURSOR } ,
} ;
static const int rk3036_vop_intrs [ ] = {
DSP_HOLD_VALID_INTR ,
FS_INTR ,
LINE_FLAG_INTR ,
BUS_ERROR_INTR ,
} ;
static const struct vop_intr rk3036_intr = {
. intrs = rk3036_vop_intrs ,
. nintrs = ARRAY_SIZE ( rk3036_vop_intrs ) ,
. status = VOP_REG ( RK3036_INT_STATUS , 0xf , 0 ) ,
. enable = VOP_REG ( RK3036_INT_STATUS , 0xf , 4 ) ,
. clear = VOP_REG ( RK3036_INT_STATUS , 0xf , 8 ) ,
} ;
static const struct vop_ctrl rk3036_ctrl_data = {
. standby = VOP_REG ( RK3036_SYS_CTRL , 0x1 , 30 ) ,
. out_mode = VOP_REG ( RK3036_DSP_CTRL0 , 0xf , 0 ) ,
. pin_pol = VOP_REG ( RK3036_DSP_CTRL0 , 0xf , 4 ) ,
. htotal_pw = VOP_REG ( RK3036_DSP_HTOTAL_HS_END , 0x1fff1fff , 0 ) ,
. hact_st_end = VOP_REG ( RK3036_DSP_HACT_ST_END , 0x1fff1fff , 0 ) ,
. vtotal_pw = VOP_REG ( RK3036_DSP_VTOTAL_VS_END , 0x1fff1fff , 0 ) ,
. vact_st_end = VOP_REG ( RK3036_DSP_VACT_ST_END , 0x1fff1fff , 0 ) ,
. cfg_done = VOP_REG ( RK3036_REG_CFG_DONE , 0x1 , 0 ) ,
} ;
static const struct vop_reg_data rk3036_vop_init_reg_table [ ] = {
{ RK3036_DSP_CTRL1 , 0x00000000 } ,
} ;
static const struct vop_data rk3036_vop = {
. init_table = rk3036_vop_init_reg_table ,
. table_size = ARRAY_SIZE ( rk3036_vop_init_reg_table ) ,
. ctrl = & rk3036_ctrl_data ,
. intr = & rk3036_intr ,
. win = rk3036_vop_win_data ,
. win_size = ARRAY_SIZE ( rk3036_vop_win_data ) ,
} ;
2015-12-15 08:58:26 +08:00
static const struct of_device_id vop_driver_dt_match [ ] = {
{ . compatible = " rockchip,rk3288-vop " ,
. data = & rk3288_vop } ,
2015-12-15 09:57:13 +08:00
{ . compatible = " rockchip,rk3036-vop " ,
. data = & rk3036_vop } ,
2015-12-15 08:58:26 +08:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , vop_driver_dt_match ) ;
static int vop_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
if ( ! dev - > of_node ) {
dev_err ( dev , " can't find vop devices \n " ) ;
return - ENODEV ;
}
return component_add ( dev , & vop_component_ops ) ;
}
static int vop_remove ( struct platform_device * pdev )
{
component_del ( & pdev - > dev , & vop_component_ops ) ;
return 0 ;
}
struct platform_driver vop_platform_driver = {
. probe = vop_probe ,
. remove = vop_remove ,
. driver = {
. name = " rockchip-vop " ,
. owner = THIS_MODULE ,
. of_match_table = of_match_ptr ( vop_driver_dt_match ) ,
} ,
} ;
module_platform_driver ( vop_platform_driver ) ;
MODULE_AUTHOR ( " Mark Yao <mark.yao@rock-chips.com> " ) ;
MODULE_DESCRIPTION ( " ROCKCHIP VOP Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;