diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 72b990d4942b..6b974e41ccb0 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -1296,7 +1296,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, u32 v_subsample = fb->format->vsub; bool mix_plane_alpha; bool covers_screen; - u32 scl0, scl1, pitch0; + u32 scl0, scl1, pitch[2]; u32 tiling, src_x, src_y; u32 width, height; u32 hvs_format = format->hvs; @@ -1350,7 +1350,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, switch (base_format_mod) { case DRM_FORMAT_MOD_LINEAR: tiling = SCALER_CTL0_TILING_LINEAR; - pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH); + pitch[0] = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH); /* Adjust the base pointer to the first pixel to be scanned * out. @@ -1402,23 +1402,23 @@ static int vc4_plane_mode_set(struct drm_plane *plane, */ if (rotation & DRM_MODE_REFLECT_Y) { y_off = tile_h_mask - y_off; - pitch0 = SCALER_PITCH0_TILE_LINE_DIR; + pitch[0] = SCALER_PITCH0_TILE_LINE_DIR; } else { - pitch0 = 0; + pitch[0] = 0; } tiling = SCALER_CTL0_TILING_256B_OR_T; - pitch0 |= (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) | - VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) | - VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) | - VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R)); + pitch[0] |= (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) | + VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) | + VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) | + VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R)); offsets[0] += tiles_t * (tiles_w << tile_size_shift); offsets[0] += subtile_y << 8; offsets[0] += utile_y << 4; /* Rows of tiles alternate left-to-right and right-to-left. */ if (tiles_t & 1) { - pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR; + pitch[0] |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR; offsets[0] += (tiles_w - tiles_l) << tile_size_shift; offsets[0] -= (1 + !tile_y) << 10; } else { @@ -1433,6 +1433,7 @@ 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); + unsigned int tile_width = 0; if (param > SCALER_TILE_HEIGHT_MASK) { DRM_DEBUG_KMS("SAND height too large (%d)\n", @@ -1443,18 +1444,22 @@ static int vc4_plane_mode_set(struct drm_plane *plane, if (fb->format->format == DRM_FORMAT_P030) { hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT; tiling = SCALER_CTL0_TILING_128B; + tile_width = 128; } else { hvs_format = HVS_PIXEL_FORMAT_H264; switch (base_format_mod) { case DRM_FORMAT_MOD_BROADCOM_SAND64: tiling = SCALER_CTL0_TILING_64B; + tile_width = 64; break; case DRM_FORMAT_MOD_BROADCOM_SAND128: tiling = SCALER_CTL0_TILING_128B; + tile_width = 128; break; case DRM_FORMAT_MOD_BROADCOM_SAND256: tiling = SCALER_CTL0_TILING_256B_OR_T; + tile_width = 256; break; default: return -EINVAL; @@ -1472,7 +1477,16 @@ static int vc4_plane_mode_set(struct drm_plane *plane, * should be 6. */ for (i = 0; i < num_planes; i++) { - u32 tile_w, tile, x_off, pix_per_tile; + u32 tile, x_off, pix_per_tile; + + switch (param) { + case 0: + pitch[i] = fb->pitches[i]; + break; + default: + pitch[i] = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT); + break; + } if (fb->format->format == DRM_FORMAT_P030) { /* @@ -1488,23 +1502,9 @@ static int vc4_plane_mode_set(struct drm_plane *plane, 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]; + pix_per_tile = tile_width / fb->format->cpp[0]; x_off = (src_x % pix_per_tile) / (i ? h_subsample : 1) * fb->format->cpp[i]; @@ -1512,12 +1512,10 @@ static int vc4_plane_mode_set(struct drm_plane *plane, tile = src_x / pix_per_tile; - offsets[i] += param * tile_w * tile; - offsets[i] += src_y / (i ? v_subsample : 1) * tile_w; + offsets[i] += pitch[i] * tile; + offsets[i] += src_y / (i ? v_subsample : 1) * tile_width; offsets[i] += x_off & ~(i ? 1 : 0); } - - pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT); break; } @@ -1672,7 +1670,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, vc4_dlist_write(vc4_state, 0xc0c0c0c0); /* Pitch word 0 */ - vc4_dlist_write(vc4_state, pitch0); + vc4_dlist_write(vc4_state, pitch[0]); /* Pitch word 1/2 */ for (i = 1; i < num_planes; i++) { @@ -1682,7 +1680,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, VC4_SET_FIELD(fb->pitches[i], SCALER_SRC_PITCH)); } else { - vc4_dlist_write(vc4_state, pitch0); + vc4_dlist_write(vc4_state, pitch[1]); } } @@ -1837,7 +1835,7 @@ static int vc6_plane_mode_set(struct drm_plane *plane, u32 v_subsample = fb->format->vsub; bool mix_plane_alpha; bool covers_screen; - u32 scl0, scl1, pitch0; + u32 scl0, scl1, pitch[2]; u32 tiling, src_x, src_y; u32 width, height; u32 hvs_format = format->hvs; @@ -1907,6 +1905,7 @@ static int vc6_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); + unsigned int tile_width = 0; u32 components_per_word; u32 starting_offset; u32 fetch_count; @@ -1920,21 +1919,29 @@ static int vc6_plane_mode_set(struct drm_plane *plane, if (fb->format->format == DRM_FORMAT_P030) { hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT; tiling = SCALER6_CTL0_ADDR_MODE_128B; + tile_width = 128; } else { hvs_format = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE; switch (base_format_mod) { case DRM_FORMAT_MOD_BROADCOM_SAND128: tiling = SCALER6_CTL0_ADDR_MODE_128B; + tile_width = 128; break; case DRM_FORMAT_MOD_BROADCOM_SAND256: tiling = SCALER6_CTL0_ADDR_MODE_256B; + tile_width = 256; break; default: return -EINVAL; } } + components_per_word = fb->format->format == DRM_FORMAT_P030 ? 24 : 32; + starting_offset = src_x % components_per_word; + fetch_count = (width + starting_offset + components_per_word - 1) / + components_per_word; + /* Adjust the base pointer to the first pixel to be scanned * out. * @@ -1946,7 +1953,16 @@ static int vc6_plane_mode_set(struct drm_plane *plane, * should be 6. */ for (i = 0; i < num_planes; i++) { - u32 tile_w, tile, x_off, pix_per_tile; + u32 tile, x_off, pix_per_tile; + + switch (param) { + case 0: + pitch[i] = fb->pitches[i]; + break; + default: + pitch[i] = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT); + break; + } if (fb->format->format == DRM_FORMAT_P030) { /* @@ -1962,20 +1978,9 @@ static int vc6_plane_mode_set(struct drm_plane *plane, 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_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]; + pix_per_tile = tile_width / fb->format->cpp[0]; x_off = (src_x % pix_per_tile) / (i ? h_subsample : 1) * fb->format->cpp[i]; @@ -1983,18 +1988,18 @@ static int vc6_plane_mode_set(struct drm_plane *plane, tile = src_x / pix_per_tile; - offsets[i] += param * tile_w * tile; - offsets[i] += src_y / (i ? v_subsample : 1) * tile_w; + offsets[i] += pitch[i] * tile; + offsets[i] += src_y / (i ? v_subsample : 1) * tile_width; offsets[i] += x_off & ~(i ? 1 : 0); + + /* + * Finished using the pitch as a pitch, so pack it as the + * register value. + */ + pitch[i] = VC4_SET_FIELD(pitch[i], SCALER6_PTR2_PITCH) | + VC4_SET_FIELD(fetch_count - 1, SCALER6_PTR2_FETCH_COUNT); } - components_per_word = fb->format->format == DRM_FORMAT_P030 ? 24 : 32; - starting_offset = src_x % components_per_word; - fetch_count = (width + starting_offset + components_per_word - 1) / - components_per_word; - - pitch0 = VC4_SET_FIELD(param, SCALER6_PTR2_PITCH) | - VC4_SET_FIELD(fetch_count - 1, SCALER6_PTR2_FETCH_COUNT); break; } @@ -2107,7 +2112,7 @@ static int vc6_plane_mode_set(struct drm_plane *plane, VC4_SET_FIELD(fb->pitches[i], SCALER6_PTR2_PITCH)); } else { - vc4_dlist_write(vc4_state, pitch0); + vc4_dlist_write(vc4_state, pitch[i]); } } @@ -2616,9 +2621,9 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, unsigned i; static const uint64_t modifiers[] = { DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, - DRM_FORMAT_MOD_BROADCOM_SAND128, - DRM_FORMAT_MOD_BROADCOM_SAND64, - DRM_FORMAT_MOD_BROADCOM_SAND256, + DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(0), + DRM_FORMAT_MOD_BROADCOM_SAND64_COL_HEIGHT(0), + DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(0), DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID };