diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2018-03-07 16:58:19 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2018-03-07 17:14:24 -0500 |
commit | df99dd9202216f54eaf672e07808e9198d868af6 (patch) | |
tree | ee75d257bc640dec1ff405deca483e83b63216e2 /drivers | |
parent | 2e7a66a8b5ebf1b04a866e5d7c981640f7f62934 (diff) |
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
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/pl111/pl111_display.c | 36 | ||||
-rw-r--r-- | drivers/gpu/drm/pl111/pl111_drm.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/pl111/pl111_drv.c | 6 |
3 files changed, 43 insertions, 0 deletions
diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c index 5b8368c76734..310646427907 100644 --- a/drivers/gpu/drm/pl111/pl111_display.c +++ b/drivers/gpu/drm/pl111/pl111_display.c | |||
@@ -50,6 +50,41 @@ irqreturn_t pl111_irq(int irq, void *data) | |||
50 | return status; | 50 | return status; |
51 | } | 51 | } |
52 | 52 | ||
53 | static enum drm_mode_status | ||
54 | pl111_mode_valid(struct drm_crtc *crtc, | ||
55 | const struct drm_display_mode *mode) | ||
56 | { | ||
57 | struct drm_device *drm = crtc->dev; | ||
58 | struct pl111_drm_dev_private *priv = drm->dev_private; | ||
59 | u32 cpp = priv->variant->fb_bpp / 8; | ||
60 | u64 bw; | ||
61 | |||
62 | /* | ||
63 | * We use the pixelclock to also account for interlaced modes, the | ||
64 | * resulting bandwidth is in bytes per second. | ||
65 | */ | ||
66 | bw = mode->clock * 1000; /* In Hz */ | ||
67 | bw = bw * mode->hdisplay * mode->vdisplay * cpp; | ||
68 | bw = div_u64(bw, mode->htotal * mode->vtotal); | ||
69 | |||
70 | /* | ||
71 | * If no bandwidth constraints, anything goes, else | ||
72 | * check if we are too fast. | ||
73 | */ | ||
74 | if (priv->memory_bw && (bw > priv->memory_bw)) { | ||
75 | DRM_DEBUG_KMS("%d x %d @ %d Hz, %d cpp, bw %llu too fast\n", | ||
76 | mode->hdisplay, mode->vdisplay, | ||
77 | mode->clock * 1000, cpp, bw); | ||
78 | |||
79 | return MODE_BAD; | ||
80 | } | ||
81 | DRM_DEBUG_KMS("%d x %d @ %d Hz, %d cpp, bw %llu bytes/s OK\n", | ||
82 | mode->hdisplay, mode->vdisplay, | ||
83 | mode->clock * 1000, cpp, bw); | ||
84 | |||
85 | return MODE_OK; | ||
86 | } | ||
87 | |||
53 | static int pl111_display_check(struct drm_simple_display_pipe *pipe, | 88 | static int pl111_display_check(struct drm_simple_display_pipe *pipe, |
54 | struct drm_plane_state *pstate, | 89 | struct drm_plane_state *pstate, |
55 | struct drm_crtc_state *cstate) | 90 | struct drm_crtc_state *cstate) |
@@ -348,6 +383,7 @@ static int pl111_display_prepare_fb(struct drm_simple_display_pipe *pipe, | |||
348 | } | 383 | } |
349 | 384 | ||
350 | static struct drm_simple_display_pipe_funcs pl111_display_funcs = { | 385 | static struct drm_simple_display_pipe_funcs pl111_display_funcs = { |
386 | .mode_valid = pl111_mode_valid, | ||
351 | .check = pl111_display_check, | 387 | .check = pl111_display_check, |
352 | .enable = pl111_display_enable, | 388 | .enable = pl111_display_enable, |
353 | .disable = pl111_display_disable, | 389 | .disable = pl111_display_disable, |
diff --git a/drivers/gpu/drm/pl111/pl111_drm.h b/drivers/gpu/drm/pl111/pl111_drm.h index 2a93e0134061..8639b2d4ddf7 100644 --- a/drivers/gpu/drm/pl111/pl111_drm.h +++ b/drivers/gpu/drm/pl111/pl111_drm.h | |||
@@ -65,6 +65,7 @@ struct pl111_drm_dev_private { | |||
65 | struct drm_simple_display_pipe pipe; | 65 | struct drm_simple_display_pipe pipe; |
66 | 66 | ||
67 | void *regs; | 67 | void *regs; |
68 | u32 memory_bw; | ||
68 | u32 ienb; | 69 | u32 ienb; |
69 | u32 ctrl; | 70 | u32 ctrl; |
70 | /* The pixel clock (a reference to our clock divider off of CLCDCLK). */ | 71 | /* The pixel clock (a reference to our clock divider off of CLCDCLK). */ |
diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index e92a406c9ea9..4621259d5387 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c | |||
@@ -257,6 +257,12 @@ static int pl111_amba_probe(struct amba_device *amba_dev, | |||
257 | drm->dev_private = priv; | 257 | drm->dev_private = priv; |
258 | priv->variant = variant; | 258 | priv->variant = variant; |
259 | 259 | ||
260 | if (of_property_read_u32(dev->of_node, "max-memory-bandwidth", | ||
261 | &priv->memory_bw)) { | ||
262 | dev_info(dev, "no max memory bandwidth specified, assume unlimited\n"); | ||
263 | priv->memory_bw = 0; | ||
264 | } | ||
265 | |||
260 | /* The two variants swap this register */ | 266 | /* The two variants swap this register */ |
261 | if (variant->is_pl110) { | 267 | if (variant->is_pl110) { |
262 | priv->ienb = CLCD_PL110_IENB; | 268 | priv->ienb = CLCD_PL110_IENB; |