@@ -33,6 +33,7 @@ static const struct hvs_format {
3333 u32 hvs ; /* HVS_FORMAT_* */
3434 u32 pixel_order ;
3535 u32 pixel_order_hvs5 ;
36+ bool hvs5_only ;
3637} hvs_formats [] = {
3738 {
3839 .drm = DRM_FORMAT_XRGB8888 ,
@@ -128,6 +129,12 @@ static const struct hvs_format {
128129 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE ,
129130 .pixel_order = HVS_PIXEL_ORDER_XYCRCB ,
130131 },
132+ {
133+ .drm = DRM_FORMAT_P030 ,
134+ .hvs = HVS_PIXEL_FORMAT_YCBCR_10BIT ,
135+ .pixel_order = HVS_PIXEL_ORDER_XYCBCR ,
136+ .hvs5_only = true,
137+ },
131138};
132139
133140static const struct hvs_format * vc4_get_hvs_format (u32 drm_format )
@@ -848,47 +855,90 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
848855 case DRM_FORMAT_MOD_BROADCOM_SAND128 :
849856 case DRM_FORMAT_MOD_BROADCOM_SAND256 : {
850857 uint32_t param = fourcc_mod_broadcom_param (fb -> modifier );
851- u32 tile_w , tile , x_off , pix_per_tile ;
852-
853- hvs_format = HVS_PIXEL_FORMAT_H264 ;
854-
855- switch (base_format_mod ) {
856- case DRM_FORMAT_MOD_BROADCOM_SAND64 :
857- tiling = SCALER_CTL0_TILING_64B ;
858- tile_w = 64 ;
859- break ;
860- case DRM_FORMAT_MOD_BROADCOM_SAND128 :
861- tiling = SCALER_CTL0_TILING_128B ;
862- tile_w = 128 ;
863- break ;
864- case DRM_FORMAT_MOD_BROADCOM_SAND256 :
865- tiling = SCALER_CTL0_TILING_256B_OR_T ;
866- tile_w = 256 ;
867- break ;
868- default :
869- break ;
870- }
871858
872859 if (param > SCALER_TILE_HEIGHT_MASK ) {
873- DRM_DEBUG_KMS ("SAND height too large (%d)\n" , param );
860+ DRM_DEBUG_KMS ("SAND height too large (%d)\n" ,
861+ param );
874862 return - EINVAL ;
875863 }
876864
877- pix_per_tile = tile_w / fb -> format -> cpp [0 ];
878- tile = vc4_state -> src_x / pix_per_tile ;
879- x_off = vc4_state -> src_x % pix_per_tile ;
865+ if (fb -> format -> format == DRM_FORMAT_P030 ) {
866+ hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT ;
867+ tiling = SCALER_CTL0_TILING_128B ;
868+ } else {
869+ hvs_format = HVS_PIXEL_FORMAT_H264 ;
870+
871+ switch (base_format_mod ) {
872+ case DRM_FORMAT_MOD_BROADCOM_SAND64 :
873+ tiling = SCALER_CTL0_TILING_64B ;
874+ break ;
875+ case DRM_FORMAT_MOD_BROADCOM_SAND128 :
876+ tiling = SCALER_CTL0_TILING_128B ;
877+ break ;
878+ case DRM_FORMAT_MOD_BROADCOM_SAND256 :
879+ tiling = SCALER_CTL0_TILING_256B_OR_T ;
880+ break ;
881+ default :
882+ return - EINVAL ;
883+ }
884+ }
880885
881886 /* Adjust the base pointer to the first pixel to be scanned
882887 * out.
888+ *
889+ * For P030, y_ptr [31:4] is the 128bit word for the start pixel
890+ * y_ptr [3:0] is the pixel (0-11) contained within that 128bit
891+ * word that should be taken as the first pixel.
892+ * Ditto uv_ptr [31:4] vs [3:0], however [3:0] contains the
893+ * element within the 128bit word, eg for pixel 3 the value
894+ * should be 6.
883895 */
884896 for (i = 0 ; i < num_planes ; i ++ ) {
897+ u32 tile_w , tile , x_off , pix_per_tile ;
898+
899+ if (fb -> format -> format == DRM_FORMAT_P030 ) {
900+ /*
901+ * Spec says: bits [31:4] of the given address
902+ * should point to the 128-bit word containing
903+ * the desired starting pixel, and bits[3:0]
904+ * should be between 0 and 11, indicating which
905+ * of the 12-pixels in that 128-bit word is the
906+ * first pixel to be used
907+ */
908+ u32 remaining_pixels = vc4_state -> src_x % 96 ;
909+ u32 aligned = remaining_pixels / 12 ;
910+ u32 last_bits = remaining_pixels % 12 ;
911+
912+ x_off = aligned * 16 + last_bits ;
913+ tile_w = 128 ;
914+ pix_per_tile = 96 ;
915+ } else {
916+ switch (base_format_mod ) {
917+ case DRM_FORMAT_MOD_BROADCOM_SAND64 :
918+ tile_w = 64 ;
919+ break ;
920+ case DRM_FORMAT_MOD_BROADCOM_SAND128 :
921+ tile_w = 128 ;
922+ break ;
923+ case DRM_FORMAT_MOD_BROADCOM_SAND256 :
924+ tile_w = 256 ;
925+ break ;
926+ default :
927+ return - EINVAL ;
928+ }
929+ pix_per_tile = tile_w / fb -> format -> cpp [0 ];
930+ x_off = (vc4_state -> src_x % pix_per_tile ) /
931+ (i ? h_subsample : 1 ) *
932+ fb -> format -> cpp [i ];
933+ }
934+
935+ tile = vc4_state -> src_x / pix_per_tile ;
936+
885937 vc4_state -> offsets [i ] += param * tile_w * tile ;
886938 vc4_state -> offsets [i ] += src_y /
887939 (i ? v_subsample : 1 ) *
888940 tile_w ;
889- vc4_state -> offsets [i ] += x_off /
890- (i ? h_subsample : 1 ) *
891- fb -> format -> cpp [i ];
941+ vc4_state -> offsets [i ] += x_off & ~(i ? 1 : 0 );
892942 }
893943
894944 pitch0 = VC4_SET_FIELD (param , SCALER_TILE_HEIGHT );
@@ -1031,7 +1081,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
10311081
10321082 /* Pitch word 1/2 */
10331083 for (i = 1 ; i < num_planes ; i ++ ) {
1034- if (hvs_format != HVS_PIXEL_FORMAT_H264 ) {
1084+ if (hvs_format != HVS_PIXEL_FORMAT_H264 &&
1085+ hvs_format != HVS_PIXEL_FORMAT_YCBCR_10BIT ) {
10351086 vc4_dlist_write (vc4_state ,
10361087 VC4_SET_FIELD (fb -> pitches [i ],
10371088 SCALER_SRC_PITCH ));
@@ -1396,6 +1447,13 @@ static bool vc4_format_mod_supported(struct drm_plane *plane,
13961447 default :
13971448 return false;
13981449 }
1450+ case DRM_FORMAT_P030 :
1451+ switch (fourcc_mod_broadcom_mod (modifier )) {
1452+ case DRM_FORMAT_MOD_BROADCOM_SAND128 :
1453+ return true;
1454+ default :
1455+ return false;
1456+ }
13991457 case DRM_FORMAT_RGBX1010102 :
14001458 case DRM_FORMAT_BGRX1010102 :
14011459 case DRM_FORMAT_RGBA1010102 :
@@ -1428,8 +1486,11 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
14281486 struct drm_plane * plane = NULL ;
14291487 struct vc4_plane * vc4_plane ;
14301488 u32 formats [ARRAY_SIZE (hvs_formats )];
1489+ int num_formats = 0 ;
14311490 int ret = 0 ;
14321491 unsigned i ;
1492+ bool hvs5 = of_device_is_compatible (dev -> dev -> of_node ,
1493+ "brcm,bcm2711-vc5" );
14331494 static const uint64_t modifiers [] = {
14341495 DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED ,
14351496 DRM_FORMAT_MOD_BROADCOM_SAND128 ,
@@ -1444,13 +1505,17 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
14441505 if (!vc4_plane )
14451506 return ERR_PTR (- ENOMEM );
14461507
1447- for (i = 0 ; i < ARRAY_SIZE (hvs_formats ); i ++ )
1448- formats [i ] = hvs_formats [i ].drm ;
1508+ for (i = 0 ; i < ARRAY_SIZE (hvs_formats ); i ++ ) {
1509+ if (!hvs_formats [i ].hvs5_only || hvs5 ) {
1510+ formats [num_formats ] = hvs_formats [i ].drm ;
1511+ num_formats ++ ;
1512+ }
1513+ }
14491514
14501515 plane = & vc4_plane -> base ;
14511516 ret = drm_universal_plane_init (dev , plane , 0 ,
14521517 & vc4_plane_funcs ,
1453- formats , ARRAY_SIZE ( formats ) ,
1518+ formats , num_formats ,
14541519 modifiers , type , NULL );
14551520 if (ret )
14561521 return ERR_PTR (ret );
0 commit comments