Commit 0a038c1c authored by Boris Brezillon's avatar Boris Brezillon

drm/vc4: Move LBM creation out of vc4_plane_mode_set()

We are about to use vc4_plane_mode_set() in the async check path, and
async updates require that LBM size stay the same since they reuse the
LBM from the previous state. So we definitely don't want to allocate a
new LBM region that we know for sure will be free right away.

Move the LBM allocation out of vc4_plane_mode_set() and call the new
function (vc4_plane_update_lbm()) from vc4_plane_atomic_check().
Signed-off-by: default avatarBoris Brezillon <boris.brezillon@bootlin.com>
Reviewed-by: default avatarEric Anholt <eric@anholt.net>
Link: https://patchwork.freedesktop.org/patch/msgid/20181130090254.594-2-boris.brezillon@bootlin.com
parent b2e554d4
...@@ -338,6 +338,7 @@ struct vc4_plane_state { ...@@ -338,6 +338,7 @@ struct vc4_plane_state {
u32 pos0_offset; u32 pos0_offset;
u32 pos2_offset; u32 pos2_offset;
u32 ptr0_offset; u32 ptr0_offset;
u32 lbm_offset;
/* Offset where the plane's dlist was last stored in the /* Offset where the plane's dlist was last stored in the
* hardware at vc4_crtc_atomic_flush() time. * hardware at vc4_crtc_atomic_flush() time.
......
...@@ -452,6 +452,43 @@ static void vc4_write_scaling_parameters(struct drm_plane_state *state, ...@@ -452,6 +452,43 @@ static void vc4_write_scaling_parameters(struct drm_plane_state *state,
} }
} }
static int vc4_plane_allocate_lbm(struct drm_plane_state *state)
{
struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
unsigned long irqflags;
u32 lbm_size;
lbm_size = vc4_lbm_size(state);
if (!lbm_size)
return 0;
if (WARN_ON(!vc4_state->lbm_offset))
return -EINVAL;
/* Allocate the LBM memory that the HVS will use for temporary
* storage due to our scaling/format conversion.
*/
if (!vc4_state->lbm.allocated) {
int ret;
spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm,
&vc4_state->lbm,
lbm_size, 32, 0, 0);
spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
if (ret)
return ret;
} else {
WARN_ON_ONCE(lbm_size != vc4_state->lbm.size);
}
vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start;
return 0;
}
/* Writes out a full display list for an active plane to the plane's /* Writes out a full display list for an active plane to the plane's
* private dlist state. * private dlist state.
*/ */
...@@ -469,31 +506,11 @@ static int vc4_plane_mode_set(struct drm_plane *plane, ...@@ -469,31 +506,11 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
bool mix_plane_alpha; bool mix_plane_alpha;
bool covers_screen; bool covers_screen;
u32 scl0, scl1, pitch0; u32 scl0, scl1, pitch0;
u32 lbm_size, tiling; u32 tiling;
unsigned long irqflags;
u32 hvs_format = format->hvs; u32 hvs_format = format->hvs;
int ret, i; int ret, i;
ret = vc4_plane_setup_clipping_and_scaling(state); ret = vc4_plane_setup_clipping_and_scaling(state);
if (ret)
return ret;
/* Allocate the LBM memory that the HVS will use for temporary
* storage due to our scaling/format conversion.
*/
lbm_size = vc4_lbm_size(state);
if (lbm_size) {
if (!vc4_state->lbm.allocated) {
spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm,
&vc4_state->lbm,
lbm_size, 32, 0, 0);
spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
} else {
WARN_ON_ONCE(lbm_size != vc4_state->lbm.size);
}
}
if (ret) if (ret)
return ret; return ret;
...@@ -717,15 +734,18 @@ static int vc4_plane_mode_set(struct drm_plane *plane, ...@@ -717,15 +734,18 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5); vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
} }
vc4_state->lbm_offset = 0;
if (vc4_state->x_scaling[0] != VC4_SCALING_NONE || if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||
vc4_state->x_scaling[1] != VC4_SCALING_NONE || vc4_state->x_scaling[1] != VC4_SCALING_NONE ||
vc4_state->y_scaling[0] != VC4_SCALING_NONE || vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
vc4_state->y_scaling[1] != VC4_SCALING_NONE) { vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
/* LBM Base Address. */ /* Reserve a slot for the LBM Base Address. The real value will
* be set when calling vc4_plane_allocate_lbm().
*/
if (vc4_state->y_scaling[0] != VC4_SCALING_NONE || if (vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
vc4_state->y_scaling[1] != VC4_SCALING_NONE) { vc4_state->y_scaling[1] != VC4_SCALING_NONE)
vc4_dlist_write(vc4_state, vc4_state->lbm.start); vc4_state->lbm_offset = vc4_state->dlist_count++;
}
if (num_planes > 1) { if (num_planes > 1) {
/* Emit Cb/Cr as channel 0 and Y as channel /* Emit Cb/Cr as channel 0 and Y as channel
...@@ -785,13 +805,18 @@ static int vc4_plane_atomic_check(struct drm_plane *plane, ...@@ -785,13 +805,18 @@ static int vc4_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state) struct drm_plane_state *state)
{ {
struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
int ret;
vc4_state->dlist_count = 0; vc4_state->dlist_count = 0;
if (plane_enabled(state)) if (!plane_enabled(state))
return vc4_plane_mode_set(plane, state);
else
return 0; return 0;
ret = vc4_plane_mode_set(plane, state);
if (ret)
return ret;
return vc4_plane_allocate_lbm(state);
} }
static void vc4_plane_atomic_update(struct drm_plane *plane, static void vc4_plane_atomic_update(struct drm_plane *plane,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment