Skip to content

Commit 6715fcf

Browse files
6by9woqidaideshi
authored andcommitted
drm/vc4: plane: Add support for DRM_FORMAT_P030
The P030 format, used with the DRM_FORMAT_MOD_BROADCOM_SAND128 modifier, is a format output by the video decoder on the BCM2711. Add native support to the KMS planes for that format. Signed-off-by: Dave Stevenson <[email protected]> Signed-off-by: Maxime Ripard <[email protected]> Acked-by: Thomas Zimmermann <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 8e56ca8 commit 6715fcf

File tree

1 file changed

+96
-31
lines changed

1 file changed

+96
-31
lines changed

drivers/gpu/drm/vc4/vc4_plane.c

Lines changed: 96 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -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

133140
static 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

Comments
 (0)