Commit 49f81d80 authored by Linus Walleij's avatar Linus Walleij Committed by Archit Taneja

drm/pl111: Support handling bridge timings

If the bridge has a too strict setup time for the incoming
signals, we may not be fast enough and then we need to
compensate by outputting the signal on the inverse clock
edge so it is for sure stable when the bridge samples it.

Since bridges in difference to panels does not expose their
connectors, make the connector optional in the display
setup code.
Acked-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: default avatarEric Anholt <eric@anholt.net>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarArchit Taneja <architt@codeaurora.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20180112074854.9560-4-linus.walleij@linaro.org
parent 88dda5b4
...@@ -8,6 +8,7 @@ config DRM_PL111 ...@@ -8,6 +8,7 @@ config DRM_PL111
select DRM_GEM_CMA_HELPER select DRM_GEM_CMA_HELPER
select DRM_BRIDGE select DRM_BRIDGE
select DRM_PANEL_BRIDGE select DRM_PANEL_BRIDGE
select DRM_DUMB_VGA_DAC
select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
help help
Choose this option for DRM support for the PL111 CLCD controller. Choose this option for DRM support for the PL111 CLCD controller.
......
...@@ -94,6 +94,7 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, ...@@ -94,6 +94,7 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
const struct drm_display_mode *mode = &cstate->mode; const struct drm_display_mode *mode = &cstate->mode;
struct drm_framebuffer *fb = plane->state->fb; struct drm_framebuffer *fb = plane->state->fb;
struct drm_connector *connector = priv->connector; struct drm_connector *connector = priv->connector;
struct drm_bridge *bridge = priv->bridge;
u32 cntl; u32 cntl;
u32 ppl, hsw, hfp, hbp; u32 ppl, hsw, hfp, hbp;
u32 lpp, vsw, vfp, vbp; u32 lpp, vsw, vfp, vbp;
...@@ -143,11 +144,37 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, ...@@ -143,11 +144,37 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
if (mode->flags & DRM_MODE_FLAG_NVSYNC) if (mode->flags & DRM_MODE_FLAG_NVSYNC)
tim2 |= TIM2_IVS; tim2 |= TIM2_IVS;
if (connector->display_info.bus_flags & DRM_BUS_FLAG_DE_LOW) if (connector) {
tim2 |= TIM2_IOE; if (connector->display_info.bus_flags & DRM_BUS_FLAG_DE_LOW)
tim2 |= TIM2_IOE;
if (connector->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE) if (connector->display_info.bus_flags &
tim2 |= TIM2_IPC; DRM_BUS_FLAG_PIXDATA_NEGEDGE)
tim2 |= TIM2_IPC;
}
if (bridge) {
const struct drm_bridge_timings *btimings = bridge->timings;
/*
* Here is when things get really fun. Sometimes the bridge
* timings are such that the signal out from PL11x is not
* stable before the receiving bridge (such as a dumb VGA DAC
* or similar) samples it. If that happens, we compensate by
* the only method we have: output the data on the opposite
* edge of the clock so it is for sure stable when it gets
* sampled.
*
* The PL111 manual does not contain proper timining diagrams
* or data for these details, but we know from experiments
* that the setup time is more than 3000 picoseconds (3 ns).
* If we have a bridge that requires the signal to be stable
* earlier than 3000 ps before the clock pulse, we have to
* output the data on the opposite edge to avoid flicker.
*/
if (btimings && btimings->setup_time_ps >= 3000)
tim2 ^= TIM2_IPC;
}
tim2 |= cpl << 16; tim2 |= cpl << 16;
writel(tim2, priv->regs + CLCD_TIM2); writel(tim2, priv->regs + CLCD_TIM2);
......
...@@ -108,11 +108,17 @@ static int pl111_modeset_init(struct drm_device *dev) ...@@ -108,11 +108,17 @@ static int pl111_modeset_init(struct drm_device *dev)
ret = PTR_ERR(bridge); ret = PTR_ERR(bridge);
goto out_config; goto out_config;
} }
/* } else if (bridge) {
* TODO: when we are using a different bridge than a panel dev_info(dev->dev, "Using non-panel bridge\n");
* (such as a dumb VGA connector) we need to devise a different } else {
* method to get the connector out of the bridge. dev_err(dev->dev, "No bridge, exiting\n");
*/ return -ENODEV;
}
priv->bridge = bridge;
if (panel) {
priv->panel = panel;
priv->connector = panel->connector;
} }
ret = pl111_display_init(dev); ret = pl111_display_init(dev);
...@@ -126,10 +132,6 @@ static int pl111_modeset_init(struct drm_device *dev) ...@@ -126,10 +132,6 @@ static int pl111_modeset_init(struct drm_device *dev)
if (ret) if (ret)
return ret; return ret;
priv->bridge = bridge;
priv->panel = panel;
priv->connector = panel->connector;
ret = drm_vblank_init(dev, 1); ret = drm_vblank_init(dev, 1);
if (ret != 0) { if (ret != 0) {
dev_err(dev->dev, "Failed to init vblank\n"); dev_err(dev->dev, "Failed to init vblank\n");
......
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