mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 06:31:52 +00:00
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 <dave.stevenson@raspberrypi.com> Signed-off-by: Maxime Ripard <maxime@cerno.tech> Acked-by: Thomas Zimmermann <tzimmermann@suse.de> Link: https://lore.kernel.org/r/20211215091739.135042-3-maxime@cerno.tech
This commit is contained in:
parent
006ea1b582
commit
145b42fbae
@ -33,6 +33,7 @@ static const struct hvs_format {
|
||||
u32 hvs; /* HVS_FORMAT_* */
|
||||
u32 pixel_order;
|
||||
u32 pixel_order_hvs5;
|
||||
bool hvs5_only;
|
||||
} hvs_formats[] = {
|
||||
{
|
||||
.drm = DRM_FORMAT_XRGB8888,
|
||||
@ -128,6 +129,12 @@ static const struct hvs_format {
|
||||
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
|
||||
.pixel_order = HVS_PIXEL_ORDER_XYCRCB,
|
||||
},
|
||||
{
|
||||
.drm = DRM_FORMAT_P030,
|
||||
.hvs = HVS_PIXEL_FORMAT_YCBCR_10BIT,
|
||||
.pixel_order = HVS_PIXEL_ORDER_XYCBCR,
|
||||
.hvs5_only = true,
|
||||
},
|
||||
};
|
||||
|
||||
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,
|
||||
case DRM_FORMAT_MOD_BROADCOM_SAND128:
|
||||
case DRM_FORMAT_MOD_BROADCOM_SAND256: {
|
||||
uint32_t param = fourcc_mod_broadcom_param(fb->modifier);
|
||||
u32 tile_w, tile, x_off, pix_per_tile;
|
||||
|
||||
hvs_format = HVS_PIXEL_FORMAT_H264;
|
||||
|
||||
switch (base_format_mod) {
|
||||
case DRM_FORMAT_MOD_BROADCOM_SAND64:
|
||||
tiling = SCALER_CTL0_TILING_64B;
|
||||
tile_w = 64;
|
||||
break;
|
||||
case DRM_FORMAT_MOD_BROADCOM_SAND128:
|
||||
tiling = SCALER_CTL0_TILING_128B;
|
||||
tile_w = 128;
|
||||
break;
|
||||
case DRM_FORMAT_MOD_BROADCOM_SAND256:
|
||||
tiling = SCALER_CTL0_TILING_256B_OR_T;
|
||||
tile_w = 256;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (param > SCALER_TILE_HEIGHT_MASK) {
|
||||
DRM_DEBUG_KMS("SAND height too large (%d)\n", param);
|
||||
DRM_DEBUG_KMS("SAND height too large (%d)\n",
|
||||
param);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pix_per_tile = tile_w / fb->format->cpp[0];
|
||||
tile = vc4_state->src_x / pix_per_tile;
|
||||
x_off = vc4_state->src_x % pix_per_tile;
|
||||
if (fb->format->format == DRM_FORMAT_P030) {
|
||||
hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT;
|
||||
tiling = SCALER_CTL0_TILING_128B;
|
||||
} else {
|
||||
hvs_format = HVS_PIXEL_FORMAT_H264;
|
||||
|
||||
switch (base_format_mod) {
|
||||
case DRM_FORMAT_MOD_BROADCOM_SAND64:
|
||||
tiling = SCALER_CTL0_TILING_64B;
|
||||
break;
|
||||
case DRM_FORMAT_MOD_BROADCOM_SAND128:
|
||||
tiling = SCALER_CTL0_TILING_128B;
|
||||
break;
|
||||
case DRM_FORMAT_MOD_BROADCOM_SAND256:
|
||||
tiling = SCALER_CTL0_TILING_256B_OR_T;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust the base pointer to the first pixel to be scanned
|
||||
* out.
|
||||
*
|
||||
* For P030, y_ptr [31:4] is the 128bit word for the start pixel
|
||||
* y_ptr [3:0] is the pixel (0-11) contained within that 128bit
|
||||
* word that should be taken as the first pixel.
|
||||
* Ditto uv_ptr [31:4] vs [3:0], however [3:0] contains the
|
||||
* element within the 128bit word, eg for pixel 3 the value
|
||||
* should be 6.
|
||||
*/
|
||||
for (i = 0; i < num_planes; i++) {
|
||||
u32 tile_w, tile, x_off, pix_per_tile;
|
||||
|
||||
if (fb->format->format == DRM_FORMAT_P030) {
|
||||
/*
|
||||
* Spec says: bits [31:4] of the given address
|
||||
* should point to the 128-bit word containing
|
||||
* the desired starting pixel, and bits[3:0]
|
||||
* should be between 0 and 11, indicating which
|
||||
* of the 12-pixels in that 128-bit word is the
|
||||
* first pixel to be used
|
||||
*/
|
||||
u32 remaining_pixels = vc4_state->src_x % 96;
|
||||
u32 aligned = remaining_pixels / 12;
|
||||
u32 last_bits = remaining_pixels % 12;
|
||||
|
||||
x_off = aligned * 16 + last_bits;
|
||||
tile_w = 128;
|
||||
pix_per_tile = 96;
|
||||
} else {
|
||||
switch (base_format_mod) {
|
||||
case DRM_FORMAT_MOD_BROADCOM_SAND64:
|
||||
tile_w = 64;
|
||||
break;
|
||||
case DRM_FORMAT_MOD_BROADCOM_SAND128:
|
||||
tile_w = 128;
|
||||
break;
|
||||
case DRM_FORMAT_MOD_BROADCOM_SAND256:
|
||||
tile_w = 256;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
pix_per_tile = tile_w / fb->format->cpp[0];
|
||||
x_off = (vc4_state->src_x % pix_per_tile) /
|
||||
(i ? h_subsample : 1) *
|
||||
fb->format->cpp[i];
|
||||
}
|
||||
|
||||
tile = vc4_state->src_x / pix_per_tile;
|
||||
|
||||
vc4_state->offsets[i] += param * tile_w * tile;
|
||||
vc4_state->offsets[i] += src_y /
|
||||
(i ? v_subsample : 1) *
|
||||
tile_w;
|
||||
vc4_state->offsets[i] += x_off /
|
||||
(i ? h_subsample : 1) *
|
||||
fb->format->cpp[i];
|
||||
vc4_state->offsets[i] += x_off & ~(i ? 1 : 0);
|
||||
}
|
||||
|
||||
pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT);
|
||||
@ -955,7 +1005,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
|
||||
|
||||
/* Pitch word 1/2 */
|
||||
for (i = 1; i < num_planes; i++) {
|
||||
if (hvs_format != HVS_PIXEL_FORMAT_H264) {
|
||||
if (hvs_format != HVS_PIXEL_FORMAT_H264 &&
|
||||
hvs_format != HVS_PIXEL_FORMAT_YCBCR_10BIT) {
|
||||
vc4_dlist_write(vc4_state,
|
||||
VC4_SET_FIELD(fb->pitches[i],
|
||||
SCALER_SRC_PITCH));
|
||||
@ -1315,6 +1366,13 @@ static bool vc4_format_mod_supported(struct drm_plane *plane,
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case DRM_FORMAT_P030:
|
||||
switch (fourcc_mod_broadcom_mod(modifier)) {
|
||||
case DRM_FORMAT_MOD_BROADCOM_SAND128:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case DRM_FORMAT_RGBX1010102:
|
||||
case DRM_FORMAT_BGRX1010102:
|
||||
case DRM_FORMAT_RGBA1010102:
|
||||
@ -1347,8 +1405,11 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
|
||||
struct drm_plane *plane = NULL;
|
||||
struct vc4_plane *vc4_plane;
|
||||
u32 formats[ARRAY_SIZE(hvs_formats)];
|
||||
int num_formats = 0;
|
||||
int ret = 0;
|
||||
unsigned i;
|
||||
bool hvs5 = of_device_is_compatible(dev->dev->of_node,
|
||||
"brcm,bcm2711-vc5");
|
||||
static const uint64_t modifiers[] = {
|
||||
DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
|
||||
DRM_FORMAT_MOD_BROADCOM_SAND128,
|
||||
@ -1363,13 +1424,17 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
|
||||
if (!vc4_plane)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hvs_formats); i++)
|
||||
formats[i] = hvs_formats[i].drm;
|
||||
for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
|
||||
if (!hvs_formats[i].hvs5_only || hvs5) {
|
||||
formats[num_formats] = hvs_formats[i].drm;
|
||||
num_formats++;
|
||||
}
|
||||
}
|
||||
|
||||
plane = &vc4_plane->base;
|
||||
ret = drm_universal_plane_init(dev, plane, 0,
|
||||
&vc4_plane_funcs,
|
||||
formats, ARRAY_SIZE(formats),
|
||||
formats, num_formats,
|
||||
modifiers, type, NULL);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
Loading…
Reference in New Issue
Block a user