mirror of
https://github.com/torvalds/linux.git
synced 2024-11-14 08:02:07 +00:00
drm/pl111: Use max memory bandwidth for resolution
We were previously selecting 1024x768 and 32BPP as the default set-up for the PL111 consumers. This does not work on elder systems: the device tree bindings support a property "max-memory-bandwidth" in bytes/second that states that if you exceed this the memory bus will saturate. The result is flickering and unstable images. Parse the "max-memory-bandwidth" and respect it when intializing the driver. On the RealView PB11MP, Versatile and Integrator/CP we get a nice console as default with this code. Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180307215819.15814-1-linus.walleij@linaro.org
This commit is contained in:
parent
2e7a66a8b5
commit
df99dd9202
@ -50,6 +50,41 @@ irqreturn_t pl111_irq(int irq, void *data)
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
pl111_mode_valid(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_device *drm = crtc->dev;
|
||||
struct pl111_drm_dev_private *priv = drm->dev_private;
|
||||
u32 cpp = priv->variant->fb_bpp / 8;
|
||||
u64 bw;
|
||||
|
||||
/*
|
||||
* We use the pixelclock to also account for interlaced modes, the
|
||||
* resulting bandwidth is in bytes per second.
|
||||
*/
|
||||
bw = mode->clock * 1000; /* In Hz */
|
||||
bw = bw * mode->hdisplay * mode->vdisplay * cpp;
|
||||
bw = div_u64(bw, mode->htotal * mode->vtotal);
|
||||
|
||||
/*
|
||||
* If no bandwidth constraints, anything goes, else
|
||||
* check if we are too fast.
|
||||
*/
|
||||
if (priv->memory_bw && (bw > priv->memory_bw)) {
|
||||
DRM_DEBUG_KMS("%d x %d @ %d Hz, %d cpp, bw %llu too fast\n",
|
||||
mode->hdisplay, mode->vdisplay,
|
||||
mode->clock * 1000, cpp, bw);
|
||||
|
||||
return MODE_BAD;
|
||||
}
|
||||
DRM_DEBUG_KMS("%d x %d @ %d Hz, %d cpp, bw %llu bytes/s OK\n",
|
||||
mode->hdisplay, mode->vdisplay,
|
||||
mode->clock * 1000, cpp, bw);
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static int pl111_display_check(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *pstate,
|
||||
struct drm_crtc_state *cstate)
|
||||
@ -348,6 +383,7 @@ static int pl111_display_prepare_fb(struct drm_simple_display_pipe *pipe,
|
||||
}
|
||||
|
||||
static struct drm_simple_display_pipe_funcs pl111_display_funcs = {
|
||||
.mode_valid = pl111_mode_valid,
|
||||
.check = pl111_display_check,
|
||||
.enable = pl111_display_enable,
|
||||
.disable = pl111_display_disable,
|
||||
|
@ -65,6 +65,7 @@ struct pl111_drm_dev_private {
|
||||
struct drm_simple_display_pipe pipe;
|
||||
|
||||
void *regs;
|
||||
u32 memory_bw;
|
||||
u32 ienb;
|
||||
u32 ctrl;
|
||||
/* The pixel clock (a reference to our clock divider off of CLCDCLK). */
|
||||
|
@ -257,6 +257,12 @@ static int pl111_amba_probe(struct amba_device *amba_dev,
|
||||
drm->dev_private = priv;
|
||||
priv->variant = variant;
|
||||
|
||||
if (of_property_read_u32(dev->of_node, "max-memory-bandwidth",
|
||||
&priv->memory_bw)) {
|
||||
dev_info(dev, "no max memory bandwidth specified, assume unlimited\n");
|
||||
priv->memory_bw = 0;
|
||||
}
|
||||
|
||||
/* The two variants swap this register */
|
||||
if (variant->is_pl110) {
|
||||
priv->ienb = CLCD_PL110_IENB;
|
||||
|
Loading…
Reference in New Issue
Block a user