@@ -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 )
@@ -762,47 +769,90 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
762769 case DRM_FORMAT_MOD_BROADCOM_SAND128 :
763770 case DRM_FORMAT_MOD_BROADCOM_SAND256 : {
764771 uint32_t param = fourcc_mod_broadcom_param (fb -> modifier );
765- u32 tile_w , tile , x_off , pix_per_tile ;
766-
767- hvs_format = HVS_PIXEL_FORMAT_H264 ;
768-
769- switch (base_format_mod ) {
770- case DRM_FORMAT_MOD_BROADCOM_SAND64 :
771- tiling = SCALER_CTL0_TILING_64B ;
772- tile_w = 64 ;
773- break ;
774- case DRM_FORMAT_MOD_BROADCOM_SAND128 :
775- tiling = SCALER_CTL0_TILING_128B ;
776- tile_w = 128 ;
777- break ;
778- case DRM_FORMAT_MOD_BROADCOM_SAND256 :
779- tiling = SCALER_CTL0_TILING_256B_OR_T ;
780- tile_w = 256 ;
781- break ;
782- default :
783- break ;
784- }
785772
786773 if (param > SCALER_TILE_HEIGHT_MASK ) {
787- DRM_DEBUG_KMS ("SAND height too large (%d)\n" , param );
774+ DRM_DEBUG_KMS ("SAND height too large (%d)\n" ,
775+ param );
788776 return - EINVAL ;
789777 }
790778
791- pix_per_tile = tile_w / fb -> format -> cpp [0 ];
792- tile = vc4_state -> src_x / pix_per_tile ;
793- x_off = vc4_state -> src_x % pix_per_tile ;
779+ if (fb -> format -> format == DRM_FORMAT_P030 ) {
780+ hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT ;
781+ tiling = SCALER_CTL0_TILING_128B ;
782+ } else {
783+ hvs_format = HVS_PIXEL_FORMAT_H264 ;
784+
785+ switch (base_format_mod ) {
786+ case DRM_FORMAT_MOD_BROADCOM_SAND64 :
787+ tiling = SCALER_CTL0_TILING_64B ;
788+ break ;
789+ case DRM_FORMAT_MOD_BROADCOM_SAND128 :
790+ tiling = SCALER_CTL0_TILING_128B ;
791+ break ;
792+ case DRM_FORMAT_MOD_BROADCOM_SAND256 :
793+ tiling = SCALER_CTL0_TILING_256B_OR_T ;
794+ break ;
795+ default :
796+ return - EINVAL ;
797+ }
798+ }
794799
795800 /* Adjust the base pointer to the first pixel to be scanned
796801 * out.
802+ *
803+ * For P030, y_ptr [31:4] is the 128bit word for the start pixel
804+ * y_ptr [3:0] is the pixel (0-11) contained within that 128bit
805+ * word that should be taken as the first pixel.
806+ * Ditto uv_ptr [31:4] vs [3:0], however [3:0] contains the
807+ * element within the 128bit word, eg for pixel 3 the value
808+ * should be 6.
797809 */
798810 for (i = 0 ; i < num_planes ; i ++ ) {
811+ u32 tile_w , tile , x_off , pix_per_tile ;
812+
813+ if (fb -> format -> format == DRM_FORMAT_P030 ) {
814+ /*
815+ * Spec says: bits [31:4] of the given address
816+ * should point to the 128-bit word containing
817+ * the desired starting pixel, and bits[3:0]
818+ * should be between 0 and 11, indicating which
819+ * of the 12-pixels in that 128-bit word is the
820+ * first pixel to be used
821+ */
822+ u32 remaining_pixels = vc4_state -> src_x % 96 ;
823+ u32 aligned = remaining_pixels / 12 ;
824+ u32 last_bits = remaining_pixels % 12 ;
825+
826+ x_off = aligned * 16 + last_bits ;
827+ tile_w = 128 ;
828+ pix_per_tile = 96 ;
829+ } else {
830+ switch (base_format_mod ) {
831+ case DRM_FORMAT_MOD_BROADCOM_SAND64 :
832+ tile_w = 64 ;
833+ break ;
834+ case DRM_FORMAT_MOD_BROADCOM_SAND128 :
835+ tile_w = 128 ;
836+ break ;
837+ case DRM_FORMAT_MOD_BROADCOM_SAND256 :
838+ tile_w = 256 ;
839+ break ;
840+ default :
841+ return - EINVAL ;
842+ }
843+ pix_per_tile = tile_w / fb -> format -> cpp [0 ];
844+ x_off = (vc4_state -> src_x % pix_per_tile ) /
845+ (i ? h_subsample : 1 ) *
846+ fb -> format -> cpp [i ];
847+ }
848+
849+ tile = vc4_state -> src_x / pix_per_tile ;
850+
799851 vc4_state -> offsets [i ] += param * tile_w * tile ;
800852 vc4_state -> offsets [i ] += src_y /
801853 (i ? v_subsample : 1 ) *
802854 tile_w ;
803- vc4_state -> offsets [i ] += x_off /
804- (i ? h_subsample : 1 ) *
805- fb -> format -> cpp [i ];
855+ vc4_state -> offsets [i ] += x_off & ~(i ? 1 : 0 );
806856 }
807857
808858 pitch0 = VC4_SET_FIELD (param , SCALER_TILE_HEIGHT );
@@ -955,7 +1005,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
9551005
9561006 /* Pitch word 1/2 */
9571007 for (i = 1 ; i < num_planes ; i ++ ) {
958- if (hvs_format != HVS_PIXEL_FORMAT_H264 ) {
1008+ if (hvs_format != HVS_PIXEL_FORMAT_H264 &&
1009+ hvs_format != HVS_PIXEL_FORMAT_YCBCR_10BIT ) {
9591010 vc4_dlist_write (vc4_state ,
9601011 VC4_SET_FIELD (fb -> pitches [i ],
9611012 SCALER_SRC_PITCH ));
@@ -1315,6 +1366,13 @@ static bool vc4_format_mod_supported(struct drm_plane *plane,
13151366 default :
13161367 return false;
13171368 }
1369+ case DRM_FORMAT_P030 :
1370+ switch (fourcc_mod_broadcom_mod (modifier )) {
1371+ case DRM_FORMAT_MOD_BROADCOM_SAND128 :
1372+ return true;
1373+ default :
1374+ return false;
1375+ }
13181376 case DRM_FORMAT_RGBX1010102 :
13191377 case DRM_FORMAT_BGRX1010102 :
13201378 case DRM_FORMAT_RGBA1010102 :
@@ -1347,8 +1405,11 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
13471405 struct drm_plane * plane = NULL ;
13481406 struct vc4_plane * vc4_plane ;
13491407 u32 formats [ARRAY_SIZE (hvs_formats )];
1408+ int num_formats = 0 ;
13501409 int ret = 0 ;
13511410 unsigned i ;
1411+ bool hvs5 = of_device_is_compatible (dev -> dev -> of_node ,
1412+ "brcm,bcm2711-vc5" );
13521413 static const uint64_t modifiers [] = {
13531414 DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED ,
13541415 DRM_FORMAT_MOD_BROADCOM_SAND128 ,
@@ -1363,13 +1424,17 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
13631424 if (!vc4_plane )
13641425 return ERR_PTR (- ENOMEM );
13651426
1366- for (i = 0 ; i < ARRAY_SIZE (hvs_formats ); i ++ )
1367- formats [i ] = hvs_formats [i ].drm ;
1427+ for (i = 0 ; i < ARRAY_SIZE (hvs_formats ); i ++ ) {
1428+ if (!hvs_formats [i ].hvs5_only || hvs5 ) {
1429+ formats [num_formats ] = hvs_formats [i ].drm ;
1430+ num_formats ++ ;
1431+ }
1432+ }
13681433
13691434 plane = & vc4_plane -> base ;
13701435 ret = drm_universal_plane_init (dev , plane , 0 ,
13711436 & vc4_plane_funcs ,
1372- formats , ARRAY_SIZE ( formats ) ,
1437+ formats , num_formats ,
13731438 modifiers , type , NULL );
13741439 if (ret )
13751440 return ERR_PTR (ret );
0 commit comments