9191#define VOP_WIN_TO_INDEX (vop_win ) \
9292 ((vop_win) - (vop_win)->vop->win)
9393
94+ #define VOP_AFBC_SET (vop , name , v ) \
95+ do { \
96+ if ((vop)->data->afbc) \
97+ vop_reg_set((vop), &(vop)->data->afbc->name, \
98+ 0, ~0, v, #name); \
99+ } while (0)
100+
94101#define to_vop (x ) container_of(x, struct vop, crtc)
95102#define to_vop_win (x ) container_of(x, struct vop_win, base)
96103
104+ #define AFBC_FMT_RGB565 0x0
105+ #define AFBC_FMT_U8U8U8U8 0x5
106+ #define AFBC_FMT_U8U8U8 0x4
107+
108+ #define AFBC_TILE_16x16 BIT(4)
109+
97110/*
98111 * The coefficients of the following matrix are all fixed points.
99112 * The format is S2.10 for the 3x3 part of the matrix, and S9.12 for the offsets.
@@ -274,6 +287,29 @@ static enum vop_data_format vop_convert_format(uint32_t format)
274287 }
275288}
276289
290+ static int vop_convert_afbc_format (uint32_t format )
291+ {
292+ switch (format ) {
293+ case DRM_FORMAT_XRGB8888 :
294+ case DRM_FORMAT_ARGB8888 :
295+ case DRM_FORMAT_XBGR8888 :
296+ case DRM_FORMAT_ABGR8888 :
297+ return AFBC_FMT_U8U8U8U8 ;
298+ case DRM_FORMAT_RGB888 :
299+ case DRM_FORMAT_BGR888 :
300+ return AFBC_FMT_U8U8U8 ;
301+ case DRM_FORMAT_RGB565 :
302+ case DRM_FORMAT_BGR565 :
303+ return AFBC_FMT_RGB565 ;
304+ /* either of the below should not be reachable */
305+ default :
306+ DRM_WARN_ONCE ("unsupported AFBC format[%08x]\n" , format );
307+ return - EINVAL ;
308+ }
309+
310+ return - EINVAL ;
311+ }
312+
277313static uint16_t scl_vop_cal_scale (enum scale_mode mode , uint32_t src ,
278314 uint32_t dst , bool is_horizontal ,
279315 int vsu_mode , int * vskiplines )
@@ -598,6 +634,17 @@ static int vop_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
598634 vop_win_disable (vop , vop_win );
599635 }
600636 }
637+
638+ if (vop -> data -> afbc ) {
639+ struct rockchip_crtc_state * s ;
640+ /*
641+ * Disable AFBC and forget there was a vop window with AFBC
642+ */
643+ VOP_AFBC_SET (vop , enable , 0 );
644+ s = to_rockchip_crtc_state (crtc -> state );
645+ s -> enable_afbc = false;
646+ }
647+
601648 spin_unlock (& vop -> reg_lock );
602649
603650 vop_cfg_done (vop );
@@ -710,6 +757,26 @@ static void vop_plane_destroy(struct drm_plane *plane)
710757 drm_plane_cleanup (plane );
711758}
712759
760+ static inline bool rockchip_afbc (u64 modifier )
761+ {
762+ return modifier == ROCKCHIP_AFBC_MOD ;
763+ }
764+
765+ static bool rockchip_mod_supported (struct drm_plane * plane ,
766+ u32 format , u64 modifier )
767+ {
768+ if (modifier == DRM_FORMAT_MOD_LINEAR )
769+ return true;
770+
771+ if (!rockchip_afbc (modifier )) {
772+ DRM_DEBUG_KMS ("Unsupported format modifer 0x%llx\n" , modifier );
773+
774+ return false;
775+ }
776+
777+ return vop_convert_afbc_format (format ) >= 0 ;
778+ }
779+
713780static int vop_plane_atomic_check (struct drm_plane * plane ,
714781 struct drm_plane_state * state )
715782{
@@ -758,6 +825,30 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
758825 return - EINVAL ;
759826 }
760827
828+ if (rockchip_afbc (fb -> modifier )) {
829+ struct vop * vop = to_vop (crtc );
830+
831+ if (!vop -> data -> afbc ) {
832+ DRM_ERROR ("vop does not support AFBC\n" );
833+ return - EINVAL ;
834+ }
835+
836+ ret = vop_convert_afbc_format (fb -> format -> format );
837+ if (ret < 0 )
838+ return ret ;
839+
840+ if (state -> src .x1 || state -> src .y1 ) {
841+ DRM_ERROR ("AFBC does not support offset display, xpos=%d, ypos=%d, offset=%d\n" , state -> src .x1 , state -> src .y1 , fb -> offsets [0 ]);
842+ return - EINVAL ;
843+ }
844+
845+ if (state -> rotation && state -> rotation != DRM_MODE_ROTATE_0 ) {
846+ DRM_ERROR ("No rotation support in AFBC, rotation=%d\n" ,
847+ state -> rotation );
848+ return - EINVAL ;
849+ }
850+ }
851+
761852 return 0 ;
762853}
763854
@@ -846,6 +937,16 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
846937
847938 spin_lock (& vop -> reg_lock );
848939
940+ if (rockchip_afbc (fb -> modifier )) {
941+ int afbc_format = vop_convert_afbc_format (fb -> format -> format );
942+
943+ VOP_AFBC_SET (vop , format , afbc_format | AFBC_TILE_16x16 );
944+ VOP_AFBC_SET (vop , hreg_block_split , 0 );
945+ VOP_AFBC_SET (vop , win_sel , VOP_WIN_TO_INDEX (vop_win ));
946+ VOP_AFBC_SET (vop , hdr_ptr , dma_addr );
947+ VOP_AFBC_SET (vop , pic_size , act_info );
948+ }
949+
849950 VOP_WIN_SET (vop , win , format , format );
850951 VOP_WIN_SET (vop , win , yrgb_vir , DIV_ROUND_UP (fb -> pitches [0 ], 4 ));
851952 VOP_WIN_SET (vop , win , yrgb_mst , dma_addr );
@@ -1001,6 +1102,7 @@ static const struct drm_plane_funcs vop_plane_funcs = {
10011102 .reset = drm_atomic_helper_plane_reset ,
10021103 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state ,
10031104 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state ,
1105+ .format_mod_supported = rockchip_mod_supported ,
10041106};
10051107
10061108static int vop_crtc_enable_vblank (struct drm_crtc * crtc )
@@ -1310,6 +1412,10 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc,
13101412 struct drm_crtc_state * crtc_state )
13111413{
13121414 struct vop * vop = to_vop (crtc );
1415+ struct drm_plane * plane ;
1416+ struct drm_plane_state * plane_state ;
1417+ struct rockchip_crtc_state * s ;
1418+ int afbc_planes = 0 ;
13131419
13141420 if (vop -> lut_regs && crtc_state -> color_mgmt_changed &&
13151421 crtc_state -> gamma_lut ) {
@@ -1323,6 +1429,27 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc,
13231429 }
13241430 }
13251431
1432+ drm_atomic_crtc_state_for_each_plane (plane , crtc_state ) {
1433+ plane_state =
1434+ drm_atomic_get_plane_state (crtc_state -> state , plane );
1435+ if (IS_ERR (plane_state )) {
1436+ DRM_DEBUG_KMS ("Cannot get plane state for plane %s\n" ,
1437+ plane -> name );
1438+ return PTR_ERR (plane_state );
1439+ }
1440+
1441+ if (drm_is_afbc (plane_state -> fb -> modifier ))
1442+ ++ afbc_planes ;
1443+ }
1444+
1445+ if (afbc_planes > 1 ) {
1446+ DRM_DEBUG_KMS ("Invalid number of AFBC planes; got %d, expected at most 1\n" , afbc_planes );
1447+ return - EINVAL ;
1448+ }
1449+
1450+ s = to_rockchip_crtc_state (crtc_state );
1451+ s -> enable_afbc = afbc_planes > 0 ;
1452+
13261453 return 0 ;
13271454}
13281455
@@ -1333,13 +1460,17 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
13331460 struct drm_plane_state * old_plane_state , * new_plane_state ;
13341461 struct vop * vop = to_vop (crtc );
13351462 struct drm_plane * plane ;
1463+ struct rockchip_crtc_state * s ;
13361464 int i ;
13371465
13381466 if (WARN_ON (!vop -> is_enabled ))
13391467 return ;
13401468
13411469 spin_lock (& vop -> reg_lock );
13421470
1471+ /* Enable AFBC if there is some AFBC window, disable otherwise. */
1472+ s = to_rockchip_crtc_state (crtc -> state );
1473+ VOP_AFBC_SET (vop , enable , s -> enable_afbc );
13431474 vop_cfg_done (vop );
13441475
13451476 spin_unlock (& vop -> reg_lock );
@@ -1634,7 +1765,8 @@ static int vop_create_crtc(struct vop *vop)
16341765 0 , & vop_plane_funcs ,
16351766 win_data -> phy -> data_formats ,
16361767 win_data -> phy -> nformats ,
1637- NULL , win_data -> type , NULL );
1768+ win_data -> phy -> format_modifiers ,
1769+ win_data -> type , NULL );
16381770 if (ret ) {
16391771 DRM_DEV_ERROR (vop -> dev , "failed to init plane %d\n" ,
16401772 ret );
@@ -1678,7 +1810,8 @@ static int vop_create_crtc(struct vop *vop)
16781810 & vop_plane_funcs ,
16791811 win_data -> phy -> data_formats ,
16801812 win_data -> phy -> nformats ,
1681- NULL , win_data -> type , NULL );
1813+ win_data -> phy -> format_modifiers ,
1814+ win_data -> type , NULL );
16821815 if (ret ) {
16831816 DRM_DEV_ERROR (vop -> dev , "failed to init overlay %d\n" ,
16841817 ret );
0 commit comments