Skip to content

Commit 145b42f

Browse files
6by9mripard
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 006ea1b commit 145b42f

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)
@@ -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

Comments
 (0)