From 179c02fe90a4104d32e92a46b9ff4ecc32bf3647 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 20 Aug 2017 12:05:55 +0200 Subject: drm/tve200: Add new driver for TVE200 This adds a new DRM driver for the Faraday Technology TVE200 block. This "TV Encoder" encodes a ITU-T BT.656 stream and can be found in the StorLink SL3516 (later Cortina Systems CS3516) as well as the Grain Media GM8180. I do not have definitive word from anyone at Faraday that this IP block is theirs, but it bears the hallmark of their 3-digit version code (200) and is used in two SoCs from completely different companies. (Grain Media was fully owned by Faraday until it was transferred to NovoTek this january, and Faraday did lots of work on the StorLink SoCs.) The D-Link DIR-685 uses this in connection with the Ilitek ILI9322 panel driver that supports BT.656 input, while the GM8180 apparently has been used with the Cirrus Logic CS4954 digital video encoder. The oldest user seems to be something called Techwall 2835. This driver is heavily inspired by Eric Anholt's PL111 driver and therefore I have mentioned all the ancestor authors in the header file. Acked-by: Daniel Vetter Reviewed-by: Eric Anholt Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20170820100557.24991-2-linus.walleij@linaro.org --- drivers/gpu/drm/tve200/tve200_display.c | 344 ++++++++++++++++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 drivers/gpu/drm/tve200/tve200_display.c (limited to 'drivers/gpu/drm/tve200/tve200_display.c') diff --git a/drivers/gpu/drm/tve200/tve200_display.c b/drivers/gpu/drm/tve200/tve200_display.c new file mode 100644 index 000000000000..37fb333331f3 --- /dev/null +++ b/drivers/gpu/drm/tve200/tve200_display.c @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2017 Linus Walleij + * Parts of this file were based on sources as follows: + * + * Copyright (C) 2006-2008 Intel Corporation + * Copyright (C) 2007 Amos Lee + * Copyright (C) 2007 Dave Airlie + * Copyright (C) 2011 Texas Instruments + * Copyright (C) 2017 Eric Anholt + * + * This program is free software and is provided to you under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation, and any use by you of this program is subject to the terms of + * such GNU licence. + */ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "tve200_drm.h" + +irqreturn_t tve200_irq(int irq, void *data) +{ + struct tve200_drm_dev_private *priv = data; + u32 stat; + u32 val; + + stat = readl(priv->regs + TVE200_INT_STAT); + + if (!stat) + return IRQ_NONE; + + /* + * Vblank IRQ + * + * The hardware is a bit tilted: the line stays high after clearing + * the vblank IRQ, firing many more interrupts. We counter this + * by toggling the IRQ back and forth from firing at vblank and + * firing at start of active image, which works around the problem + * since those occur strictly in sequence, and we get two IRQs for each + * frame, one at start of Vblank (that we make call into the CRTC) and + * another one at the start of the image (that we discard). + */ + if (stat & TVE200_INT_V_STATUS) { + val = readl(priv->regs + TVE200_CTRL); + /* We have an actual start of vsync */ + if (!(val & TVE200_VSTSTYPE_BITS)) { + drm_crtc_handle_vblank(&priv->pipe.crtc); + /* Toggle trigger to start of active image */ + val |= TVE200_VSTSTYPE_VAI; + } else { + /* Toggle trigger back to start of vsync */ + val &= ~TVE200_VSTSTYPE_BITS; + } + writel(val, priv->regs + TVE200_CTRL); + } else + dev_err(priv->drm->dev, "stray IRQ %08x\n", stat); + + /* Clear the interrupt once done */ + writel(stat, priv->regs + TVE200_INT_CLR); + + return IRQ_HANDLED; +} + +static int tve200_display_check(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *pstate, + struct drm_crtc_state *cstate) +{ + const struct drm_display_mode *mode = &cstate->mode; + struct drm_framebuffer *old_fb = pipe->plane.state->fb; + struct drm_framebuffer *fb = pstate->fb; + + /* + * We support these specific resolutions and nothing else. + */ + if (!(mode->hdisplay == 352 && mode->vdisplay == 240) && /* SIF(525) */ + !(mode->hdisplay == 352 && mode->vdisplay == 288) && /* CIF(625) */ + !(mode->hdisplay == 640 && mode->vdisplay == 480) && /* VGA */ + !(mode->hdisplay == 720 && mode->vdisplay == 480) && /* D1 */ + !(mode->hdisplay == 720 && mode->vdisplay == 576)) { /* D1 */ + DRM_DEBUG_KMS("unsupported display mode (%u x %u)\n", + mode->hdisplay, mode->vdisplay); + return -EINVAL; + } + + if (fb) { + u32 offset = drm_fb_cma_get_gem_addr(fb, pstate, 0); + + /* FB base address must be dword aligned. */ + if (offset & 3) { + DRM_DEBUG_KMS("FB not 32-bit aligned\n"); + return -EINVAL; + } + + /* + * There's no pitch register, the mode's hdisplay + * controls this. + */ + if (fb->pitches[0] != mode->hdisplay * fb->format->cpp[0]) { + DRM_DEBUG_KMS("can't handle pitches\n"); + return -EINVAL; + } + + /* + * We can't change the FB format in a flicker-free + * manner (and only update it during CRTC enable). + */ + if (old_fb && old_fb->format != fb->format) + cstate->mode_changed = true; + } + + return 0; +} + +static void tve200_display_enable(struct drm_simple_display_pipe *pipe, + struct drm_crtc_state *cstate) +{ + struct drm_crtc *crtc = &pipe->crtc; + struct drm_plane *plane = &pipe->plane; + struct drm_device *drm = crtc->dev; + struct tve200_drm_dev_private *priv = drm->dev_private; + const struct drm_display_mode *mode = &cstate->mode; + struct drm_framebuffer *fb = plane->state->fb; + struct drm_connector *connector = &priv->connector.connector; + u32 format = fb->format->format; + u32 ctrl1 = 0; + + clk_prepare_enable(priv->clk); + + /* Function 1 */ + ctrl1 |= TVE200_CTRL_CSMODE; + /* Interlace mode for CCIR656: parameterize? */ + ctrl1 |= TVE200_CTRL_NONINTERLACE; + /* 32 words per burst */ + ctrl1 |= TVE200_CTRL_BURST_32_WORDS; + /* 16 retries */ + ctrl1 |= TVE200_CTRL_RETRYCNT_16; + /* NTSC mode: parametrize? */ + ctrl1 |= TVE200_CTRL_NTSC; + + /* Vsync IRQ at start of Vsync at first */ + ctrl1 |= TVE200_VSTSTYPE_VSYNC; + + if (connector->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE) + ctrl1 |= TVE200_CTRL_TVCLKP; + + if ((mode->hdisplay == 352 && mode->vdisplay == 240) || /* SIF(525) */ + (mode->hdisplay == 352 && mode->vdisplay == 288)) { /* CIF(625) */ + ctrl1 |= TVE200_CTRL_IPRESOL_CIF; + dev_info(drm->dev, "CIF mode\n"); + } else if (mode->hdisplay == 640 && mode->vdisplay == 480) { + ctrl1 |= TVE200_CTRL_IPRESOL_VGA; + dev_info(drm->dev, "VGA mode\n"); + } else if ((mode->hdisplay == 720 && mode->vdisplay == 480) || + (mode->hdisplay == 720 && mode->vdisplay == 576)) { + ctrl1 |= TVE200_CTRL_IPRESOL_D1; + dev_info(drm->dev, "D1 mode\n"); + } + + if (format & DRM_FORMAT_BIG_ENDIAN) { + ctrl1 |= TVE200_CTRL_BBBP; + format &= ~DRM_FORMAT_BIG_ENDIAN; + } + + switch (format) { + case DRM_FORMAT_XRGB8888: + ctrl1 |= TVE200_IPDMOD_RGB888; + break; + case DRM_FORMAT_RGB565: + ctrl1 |= TVE200_IPDMOD_RGB565; + break; + case DRM_FORMAT_XRGB1555: + ctrl1 |= TVE200_IPDMOD_RGB555; + break; + case DRM_FORMAT_XBGR8888: + ctrl1 |= TVE200_IPDMOD_RGB888 | TVE200_BGR; + break; + case DRM_FORMAT_BGR565: + ctrl1 |= TVE200_IPDMOD_RGB565 | TVE200_BGR; + break; + case DRM_FORMAT_XBGR1555: + ctrl1 |= TVE200_IPDMOD_RGB555 | TVE200_BGR; + break; + case DRM_FORMAT_YUYV: + ctrl1 |= TVE200_IPDMOD_YUV422; + ctrl1 |= TVE200_CTRL_YCBCRODR_CR0Y1CB0Y0; + break; + case DRM_FORMAT_YVYU: + ctrl1 |= TVE200_IPDMOD_YUV422; + ctrl1 |= TVE200_CTRL_YCBCRODR_CB0Y1CR0Y0; + break; + case DRM_FORMAT_UYVY: + ctrl1 |= TVE200_IPDMOD_YUV422; + ctrl1 |= TVE200_CTRL_YCBCRODR_Y1CR0Y0CB0; + break; + case DRM_FORMAT_VYUY: + ctrl1 |= TVE200_IPDMOD_YUV422; + ctrl1 |= TVE200_CTRL_YCBCRODR_Y1CB0Y0CR0; + break; + case DRM_FORMAT_YUV420: + ctrl1 |= TVE200_CTRL_YUV420; + ctrl1 |= TVE200_IPDMOD_YUV420; + break; + default: + dev_err(drm->dev, "Unknown FB format 0x%08x\n", + fb->format->format); + break; + } + + ctrl1 |= TVE200_TVEEN; + + drm_panel_prepare(priv->connector.panel); + + /* Turn it on */ + writel(ctrl1, priv->regs + TVE200_CTRL); + + drm_panel_enable(priv->connector.panel); + + drm_crtc_vblank_on(crtc); +} + +void tve200_display_disable(struct drm_simple_display_pipe *pipe) +{ + struct drm_crtc *crtc = &pipe->crtc; + struct drm_device *drm = crtc->dev; + struct tve200_drm_dev_private *priv = drm->dev_private; + + drm_crtc_vblank_off(crtc); + + drm_panel_disable(priv->connector.panel); + + /* Disable and Power Down */ + writel(0, priv->regs + TVE200_CTRL); + + drm_panel_unprepare(priv->connector.panel); + + clk_disable_unprepare(priv->clk); +} + +static void tve200_display_update(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *old_pstate) +{ + struct drm_crtc *crtc = &pipe->crtc; + struct drm_device *drm = crtc->dev; + struct tve200_drm_dev_private *priv = drm->dev_private; + struct drm_pending_vblank_event *event = crtc->state->event; + struct drm_plane *plane = &pipe->plane; + struct drm_plane_state *pstate = plane->state; + struct drm_framebuffer *fb = pstate->fb; + + if (fb) { + /* For RGB, the Y component is used as base address */ + writel(drm_fb_cma_get_gem_addr(fb, pstate, 0), + priv->regs + TVE200_Y_FRAME_BASE_ADDR); + + /* For three plane YUV we need two more addresses */ + if (fb->format->format == DRM_FORMAT_YUV420) { + writel(drm_fb_cma_get_gem_addr(fb, pstate, 1), + priv->regs + TVE200_U_FRAME_BASE_ADDR); + writel(drm_fb_cma_get_gem_addr(fb, pstate, 2), + priv->regs + TVE200_V_FRAME_BASE_ADDR); + } + } + + if (event) { + crtc->state->event = NULL; + + spin_lock_irq(&crtc->dev->event_lock); + if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0) + drm_crtc_arm_vblank_event(crtc, event); + else + drm_crtc_send_vblank_event(crtc, event); + spin_unlock_irq(&crtc->dev->event_lock); + } +} + +int tve200_enable_vblank(struct drm_device *drm, unsigned int crtc) +{ + struct tve200_drm_dev_private *priv = drm->dev_private; + + writel(TVE200_INT_V_STATUS, priv->regs + TVE200_INT_EN); + return 0; +} + +void tve200_disable_vblank(struct drm_device *drm, unsigned int crtc) +{ + struct tve200_drm_dev_private *priv = drm->dev_private; + + writel(0, priv->regs + TVE200_INT_EN); +} + +static int tve200_display_prepare_fb(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *plane_state) +{ + return drm_fb_cma_prepare_fb(&pipe->plane, plane_state); +} + +const struct drm_simple_display_pipe_funcs tve200_display_funcs = { + .check = tve200_display_check, + .enable = tve200_display_enable, + .disable = tve200_display_disable, + .update = tve200_display_update, + .prepare_fb = tve200_display_prepare_fb, +}; + +int tve200_display_init(struct drm_device *drm) +{ + struct tve200_drm_dev_private *priv = drm->dev_private; + int ret; + static const u32 formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_RGB565, + DRM_FORMAT_BGR565, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_XBGR1555, + /* + * The controller actually supports any YCbCr ordering, + * for packed YCbCr. This just lists the orderings that + * DRM supports. + */ + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + /* This uses three planes */ + DRM_FORMAT_YUV420, + }; + + ret = drm_simple_display_pipe_init(drm, &priv->pipe, + &tve200_display_funcs, + formats, ARRAY_SIZE(formats), + &priv->connector.connector); + if (ret) + return ret; + + return 0; +} -- cgit v1.2.3 From b07b9146635e90b72551bc8992eb85ecbaa0e593 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 25 Aug 2017 13:16:12 -0700 Subject: drm/tve200: Pass NULL format_modifier to drm_simple_display_pipe_init This Fixes build on branches where we already have format-modifier. Reference: https://lists.freedesktop.org/archives/dri-devel/2017-August/151044.html Fixes: 179c02fe90a4 ("drm/tve200: Add new driver for TVE200") Cc: Linus Walleij Cc: Janet Morgan Cc: Ben Widawsky Cc: Daniel Stone (v2) Cc: Liviu Dudau Cc: Daniel Stone Signed-off-by: Rodrigo Vivi Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20170825201612.23056-1-rodrigo.vivi@intel.com --- drivers/gpu/drm/tve200/tve200_display.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm/tve200/tve200_display.c') diff --git a/drivers/gpu/drm/tve200/tve200_display.c b/drivers/gpu/drm/tve200/tve200_display.c index 37fb333331f3..3f4b97bf2a13 100644 --- a/drivers/gpu/drm/tve200/tve200_display.c +++ b/drivers/gpu/drm/tve200/tve200_display.c @@ -336,6 +336,7 @@ int tve200_display_init(struct drm_device *drm) ret = drm_simple_display_pipe_init(drm, &priv->pipe, &tve200_display_funcs, formats, ARRAY_SIZE(formats), + NULL, &priv->connector.connector); if (ret) return ret; -- cgit v1.2.3 From 14b469f9c02d458a4388479fb393a625f15af488 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 2 Sep 2017 22:07:11 +0200 Subject: drm/tve200: Replace custom connector with panel bridge This replaces the custom connector in the TVE200 with the panel bridge helper. As long as we're just using panels and no other bridges, this works just fine. Reviewed-by: Eric Anholt Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20170902200711.29298-1-linus.walleij@linaro.org --- drivers/gpu/drm/tve200/Kconfig | 3 +- drivers/gpu/drm/tve200/Makefile | 3 +- drivers/gpu/drm/tve200/tve200_connector.c | 125 ------------------------------ drivers/gpu/drm/tve200/tve200_display.c | 15 ++-- drivers/gpu/drm/tve200/tve200_drm.h | 10 +-- drivers/gpu/drm/tve200/tve200_drv.c | 66 +++++++++++----- 6 files changed, 59 insertions(+), 163 deletions(-) delete mode 100644 drivers/gpu/drm/tve200/tve200_connector.c (limited to 'drivers/gpu/drm/tve200/tve200_display.c') diff --git a/drivers/gpu/drm/tve200/Kconfig b/drivers/gpu/drm/tve200/Kconfig index 21d9841ddb88..c5f03bf4570c 100644 --- a/drivers/gpu/drm/tve200/Kconfig +++ b/drivers/gpu/drm/tve200/Kconfig @@ -4,7 +4,8 @@ config DRM_TVE200 depends on CMA depends on ARM || COMPILE_TEST depends on OF - select DRM_PANEL + select DRM_BRIDGE + select DRM_PANEL_BRIDGE select DRM_KMS_HELPER select DRM_KMS_CMA_HELPER select DRM_GEM_CMA_HELPER diff --git a/drivers/gpu/drm/tve200/Makefile b/drivers/gpu/drm/tve200/Makefile index a9dba54f7ee5..6b7a6a1dcbf8 100644 --- a/drivers/gpu/drm/tve200/Makefile +++ b/drivers/gpu/drm/tve200/Makefile @@ -1,5 +1,4 @@ -tve200_drm-y += tve200_connector.o \ - tve200_display.o \ +tve200_drm-y += tve200_display.o \ tve200_drv.o obj-$(CONFIG_DRM_TVE200) += tve200_drm.o diff --git a/drivers/gpu/drm/tve200/tve200_connector.c b/drivers/gpu/drm/tve200/tve200_connector.c deleted file mode 100644 index 5e6c20b57d6d..000000000000 --- a/drivers/gpu/drm/tve200/tve200_connector.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2017 Linus Walleij - * Parts of this file were based on sources as follows: - * - * Copyright (C) 2006-2008 Intel Corporation - * Copyright (C) 2007 Amos Lee - * Copyright (C) 2007 Dave Airlie - * Copyright (C) 2011 Texas Instruments - * Copyright (C) 2017 Eric Anholt - * - * This program is free software and is provided to you under the terms of the - * GNU General Public License version 2 as published by the Free Software - * Foundation, and any use by you of this program is subject to the terms of - * such GNU licence. - */ - -/** - * tve200_drm_connector.c - * Implementation of the connector functions for the Faraday TV Encoder - */ -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "tve200_drm.h" - -static void tve200_connector_destroy(struct drm_connector *connector) -{ - struct tve200_drm_connector *tve200con = - to_tve200_connector(connector); - - if (tve200con->panel) - drm_panel_detach(tve200con->panel); - - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - -static enum drm_connector_status tve200_connector_detect(struct drm_connector - *connector, bool force) -{ - struct tve200_drm_connector *tve200con = - to_tve200_connector(connector); - - return (tve200con->panel ? - connector_status_connected : - connector_status_disconnected); -} - -static int tve200_connector_helper_get_modes(struct drm_connector *connector) -{ - struct tve200_drm_connector *tve200con = - to_tve200_connector(connector); - - if (!tve200con->panel) - return 0; - - return drm_panel_get_modes(tve200con->panel); -} - -static const struct drm_connector_funcs connector_funcs = { - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = tve200_connector_destroy, - .detect = tve200_connector_detect, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static const struct drm_connector_helper_funcs connector_helper_funcs = { - .get_modes = tve200_connector_helper_get_modes, -}; - -/* - * Walks the OF graph to find the panel node and then asks DRM to look - * up the panel. - */ -static struct drm_panel *tve200_get_panel(struct device *dev) -{ - struct device_node *endpoint, *panel_node; - struct device_node *np = dev->of_node; - struct drm_panel *panel; - - endpoint = of_graph_get_next_endpoint(np, NULL); - if (!endpoint) { - dev_err(dev, "no endpoint to fetch panel\n"); - return NULL; - } - - /* Don't proceed if we have an endpoint but no panel_node tied to it */ - panel_node = of_graph_get_remote_port_parent(endpoint); - of_node_put(endpoint); - if (!panel_node) { - dev_err(dev, "no valid panel node\n"); - return NULL; - } - - panel = of_drm_find_panel(panel_node); - of_node_put(panel_node); - - return panel; -} - -int tve200_connector_init(struct drm_device *dev) -{ - struct tve200_drm_dev_private *priv = dev->dev_private; - struct tve200_drm_connector *tve200con = &priv->connector; - struct drm_connector *connector = &tve200con->connector; - - drm_connector_init(dev, connector, &connector_funcs, - DRM_MODE_CONNECTOR_DPI); - drm_connector_helper_add(connector, &connector_helper_funcs); - - tve200con->panel = tve200_get_panel(dev->dev); - if (tve200con->panel) - drm_panel_attach(tve200con->panel, connector); - - return 0; -} diff --git a/drivers/gpu/drm/tve200/tve200_display.c b/drivers/gpu/drm/tve200/tve200_display.c index 3f4b97bf2a13..1ad02fdbb074 100644 --- a/drivers/gpu/drm/tve200/tve200_display.c +++ b/drivers/gpu/drm/tve200/tve200_display.c @@ -127,7 +127,7 @@ static void tve200_display_enable(struct drm_simple_display_pipe *pipe, struct tve200_drm_dev_private *priv = drm->dev_private; const struct drm_display_mode *mode = &cstate->mode; struct drm_framebuffer *fb = plane->state->fb; - struct drm_connector *connector = &priv->connector.connector; + struct drm_connector *connector = priv->connector; u32 format = fb->format->format; u32 ctrl1 = 0; @@ -215,13 +215,9 @@ static void tve200_display_enable(struct drm_simple_display_pipe *pipe, ctrl1 |= TVE200_TVEEN; - drm_panel_prepare(priv->connector.panel); - /* Turn it on */ writel(ctrl1, priv->regs + TVE200_CTRL); - drm_panel_enable(priv->connector.panel); - drm_crtc_vblank_on(crtc); } @@ -233,13 +229,9 @@ void tve200_display_disable(struct drm_simple_display_pipe *pipe) drm_crtc_vblank_off(crtc); - drm_panel_disable(priv->connector.panel); - /* Disable and Power Down */ writel(0, priv->regs + TVE200_CTRL); - drm_panel_unprepare(priv->connector.panel); - clk_disable_unprepare(priv->clk); } @@ -337,9 +329,12 @@ int tve200_display_init(struct drm_device *drm) &tve200_display_funcs, formats, ARRAY_SIZE(formats), NULL, - &priv->connector.connector); + priv->connector); if (ret) return ret; + /* We need the encoder to attach the bridge */ + priv->encoder = &priv->pipe.encoder; + return 0; } diff --git a/drivers/gpu/drm/tve200/tve200_drm.h b/drivers/gpu/drm/tve200/tve200_drm.h index f00fc47a6bd1..b463624c1f29 100644 --- a/drivers/gpu/drm/tve200/tve200_drm.h +++ b/drivers/gpu/drm/tve200/tve200_drm.h @@ -96,15 +96,13 @@ #include #include -struct tve200_drm_connector { - struct drm_connector connector; - struct drm_panel *panel; -}; - struct tve200_drm_dev_private { struct drm_device *drm; - struct tve200_drm_connector connector; + struct drm_connector *connector; + struct drm_encoder *encoder; + struct drm_panel *panel; + struct drm_bridge *bridge; struct drm_simple_display_pipe pipe; struct drm_fbdev_cma *fbdev; diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c index fe742106db4e..c22644692a88 100644 --- a/drivers/gpu/drm/tve200/tve200_drv.c +++ b/drivers/gpu/drm/tve200/tve200_drv.c @@ -47,6 +47,8 @@ #include #include #include +#include +#include #include "tve200_drm.h" @@ -62,6 +64,8 @@ static int tve200_modeset_init(struct drm_device *dev) { struct drm_mode_config *mode_config; struct tve200_drm_dev_private *priv = dev->dev_private; + struct drm_panel *panel; + struct drm_bridge *bridge; int ret = 0; drm_mode_config_init(dev); @@ -72,35 +76,51 @@ static int tve200_modeset_init(struct drm_device *dev) mode_config->min_height = 240; mode_config->max_height = 576; - ret = tve200_connector_init(dev); + ret = drm_of_find_panel_or_bridge(dev->dev->of_node, + 0, 0, &panel, &bridge); + if (ret && ret != -ENODEV) + return ret; + if (panel) { + bridge = drm_panel_bridge_add(panel, + DRM_MODE_CONNECTOR_Unknown); + if (IS_ERR(bridge)) { + ret = PTR_ERR(bridge); + goto out_bridge; + } + } + + ret = tve200_display_init(dev); if (ret) { - dev_err(dev->dev, "Failed to create tve200_drm_connector\n"); - goto out_config; + dev_err(dev->dev, "failed to init display\n"); + goto out_bridge; + } + + if (bridge) { + ret = drm_bridge_attach(priv->encoder, bridge, NULL); + if (ret) + goto out_bridge; } /* - * Don't actually attach if we didn't find a drm_panel - * attached to us. + * TODO: when we are using a different bridge than a panel + * (such as a dumb VGA connector) we need to devise a different + * method to get the connector out of the bridge. */ - if (!priv->connector.panel) { - dev_info(dev->dev, - "deferring due to lack of DRM panel device\n"); - ret = -EPROBE_DEFER; - goto out_config; + if (!panel) { + dev_err(dev->dev, "the bridge is not a panel\n"); + goto out_bridge; } - dev_info(dev->dev, "attached to panel %s\n", - dev_name(priv->connector.panel->dev)); + priv->panel = panel; + priv->connector = panel->connector; + priv->bridge = bridge; - ret = tve200_display_init(dev); - if (ret) { - dev_err(dev->dev, "failed to init display\n"); - goto out_config; - } + dev_info(dev->dev, "attached to panel %s\n", + dev_name(panel->dev)); ret = drm_vblank_init(dev, 1); if (ret) { dev_err(dev->dev, "failed to init vblank\n"); - goto out_config; + goto out_bridge; } drm_mode_config_reset(dev); @@ -115,7 +135,11 @@ static int tve200_modeset_init(struct drm_device *dev) goto finish; -out_config: +out_bridge: + if (panel) + drm_panel_bridge_remove(bridge); + else + drm_bridge_remove(bridge); drm_mode_config_cleanup(dev); finish: return ret; @@ -249,6 +273,10 @@ static int tve200_remove(struct platform_device *pdev) drm_dev_unregister(drm); if (priv->fbdev) drm_fbdev_cma_fini(priv->fbdev); + if (priv->panel) + drm_panel_bridge_remove(priv->bridge); + else + drm_bridge_remove(priv->bridge); drm_mode_config_cleanup(drm); clk_disable_unprepare(priv->pclk); drm_dev_unref(drm); -- cgit v1.2.3 From 9ab12e88a0b46b4e6fa32bb0a2875c813a928e73 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 11 Sep 2017 00:08:01 +0200 Subject: drm/tve200: Clean up panel bridging This makes use of the drm_simple_display_pipe_attach_bridge() call and removes the two calls removing the bridge, which were erroneous: they unregister the bridge which is not what we want, we just want to unreference it and that is already handled by the core. Reviewed-by: Eric Anholt Acked-by: Daniel Vetter Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20170910220801.28588-1-linus.walleij@linaro.org --- drivers/gpu/drm/tve200/tve200_display.c | 3 --- drivers/gpu/drm/tve200/tve200_drm.h | 1 - drivers/gpu/drm/tve200/tve200_drv.c | 30 +++++++++++++----------------- 3 files changed, 13 insertions(+), 21 deletions(-) (limited to 'drivers/gpu/drm/tve200/tve200_display.c') diff --git a/drivers/gpu/drm/tve200/tve200_display.c b/drivers/gpu/drm/tve200/tve200_display.c index 1ad02fdbb074..18457de47bbc 100644 --- a/drivers/gpu/drm/tve200/tve200_display.c +++ b/drivers/gpu/drm/tve200/tve200_display.c @@ -333,8 +333,5 @@ int tve200_display_init(struct drm_device *drm) if (ret) return ret; - /* We need the encoder to attach the bridge */ - priv->encoder = &priv->pipe.encoder; - return 0; } diff --git a/drivers/gpu/drm/tve200/tve200_drm.h b/drivers/gpu/drm/tve200/tve200_drm.h index b463624c1f29..628b79324c48 100644 --- a/drivers/gpu/drm/tve200/tve200_drm.h +++ b/drivers/gpu/drm/tve200/tve200_drm.h @@ -100,7 +100,6 @@ struct tve200_drm_dev_private { struct drm_device *drm; struct drm_connector *connector; - struct drm_encoder *encoder; struct drm_panel *panel; struct drm_bridge *bridge; struct drm_simple_display_pipe pipe; diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c index c22644692a88..eae38b669f0a 100644 --- a/drivers/gpu/drm/tve200/tve200_drv.c +++ b/drivers/gpu/drm/tve200/tve200_drv.c @@ -87,6 +87,14 @@ static int tve200_modeset_init(struct drm_device *dev) ret = PTR_ERR(bridge); goto out_bridge; } + } else { + /* + * TODO: when we are using a different bridge than a panel + * (such as a dumb VGA connector) we need to devise a different + * method to get the connector out of the bridge. + */ + dev_err(dev->dev, "the bridge is not a panel\n"); + goto out_bridge; } ret = tve200_display_init(dev); @@ -95,21 +103,13 @@ static int tve200_modeset_init(struct drm_device *dev) goto out_bridge; } - if (bridge) { - ret = drm_bridge_attach(priv->encoder, bridge, NULL); - if (ret) - goto out_bridge; - } - - /* - * TODO: when we are using a different bridge than a panel - * (such as a dumb VGA connector) we need to devise a different - * method to get the connector out of the bridge. - */ - if (!panel) { - dev_err(dev->dev, "the bridge is not a panel\n"); + ret = drm_simple_display_pipe_attach_bridge(&priv->pipe, + bridge); + if (ret) { + dev_err(dev->dev, "failed to attach bridge\n"); goto out_bridge; } + priv->panel = panel; priv->connector = panel->connector; priv->bridge = bridge; @@ -138,8 +138,6 @@ static int tve200_modeset_init(struct drm_device *dev) out_bridge: if (panel) drm_panel_bridge_remove(bridge); - else - drm_bridge_remove(bridge); drm_mode_config_cleanup(dev); finish: return ret; @@ -275,8 +273,6 @@ static int tve200_remove(struct platform_device *pdev) drm_fbdev_cma_fini(priv->fbdev); if (priv->panel) drm_panel_bridge_remove(priv->bridge); - else - drm_bridge_remove(priv->bridge); drm_mode_config_cleanup(drm); clk_disable_unprepare(priv->pclk); drm_dev_unref(drm); -- cgit v1.2.3 From 4ea30958d96b3f997afadeeb9de29e6dea3a80f5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 22 Sep 2017 17:05:16 +0100 Subject: drm/tve200: make two functions static The functions tve200_display_disable and tve200_display_funcs are local to the source and do not need to be in global scope, so make them static. Cleans up sparse warnings: symbol 'tve200_display_disable' was not declared. Should it be static? symbol 'tve200_display_funcs' was not declared. Should it be static? Signed-off-by: Colin Ian King Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20170922160516.16283-1-colin.king@canonical.com --- drivers/gpu/drm/tve200/tve200_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/tve200/tve200_display.c') diff --git a/drivers/gpu/drm/tve200/tve200_display.c b/drivers/gpu/drm/tve200/tve200_display.c index 18457de47bbc..904e38b93530 100644 --- a/drivers/gpu/drm/tve200/tve200_display.c +++ b/drivers/gpu/drm/tve200/tve200_display.c @@ -221,7 +221,7 @@ static void tve200_display_enable(struct drm_simple_display_pipe *pipe, drm_crtc_vblank_on(crtc); } -void tve200_display_disable(struct drm_simple_display_pipe *pipe) +static void tve200_display_disable(struct drm_simple_display_pipe *pipe) { struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; @@ -293,7 +293,7 @@ static int tve200_display_prepare_fb(struct drm_simple_display_pipe *pipe, return drm_fb_cma_prepare_fb(&pipe->plane, plane_state); } -const struct drm_simple_display_pipe_funcs tve200_display_funcs = { +static const struct drm_simple_display_pipe_funcs tve200_display_funcs = { .check = tve200_display_check, .enable = tve200_display_enable, .disable = tve200_display_disable, -- cgit v1.2.3 From 57b8a4bf87806cbb64ed91078f32fbf37f556c5e Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Sun, 24 Sep 2017 14:26:24 +0200 Subject: drm/tve200: Use drm_gem_fb_create() and drm_gem_fb_prepare_fb() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_fb_cma_create() and drm_fb_cma_prepare_fb() are just wrappers now, use drm_gem_fb_create() and drm_gem_fb_prepare_fb() directly. Cc: Linus Walleij Signed-off-by: Noralf Trønnes Reviewed-by: Linus Walleij Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/1506255985-61113-10-git-send-email-noralf@tronnes.org --- drivers/gpu/drm/tve200/tve200_display.c | 3 ++- drivers/gpu/drm/tve200/tve200_drv.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/tve200/tve200_display.c') diff --git a/drivers/gpu/drm/tve200/tve200_display.c b/drivers/gpu/drm/tve200/tve200_display.c index 904e38b93530..2c668bd6d997 100644 --- a/drivers/gpu/drm/tve200/tve200_display.c +++ b/drivers/gpu/drm/tve200/tve200_display.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "tve200_drm.h" @@ -290,7 +291,7 @@ void tve200_disable_vblank(struct drm_device *drm, unsigned int crtc) static int tve200_display_prepare_fb(struct drm_simple_display_pipe *pipe, struct drm_plane_state *plane_state) { - return drm_fb_cma_prepare_fb(&pipe->plane, plane_state); + return drm_gem_fb_prepare_fb(&pipe->plane, plane_state); } static const struct drm_simple_display_pipe_funcs tve200_display_funcs = { diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c index 6939f7455a2d..bd6c9454d767 100644 --- a/drivers/gpu/drm/tve200/tve200_drv.c +++ b/drivers/gpu/drm/tve200/tve200_drv.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -55,7 +56,7 @@ #define DRIVER_DESC "DRM module for Faraday TVE200" static const struct drm_mode_config_funcs mode_config_funcs = { - .fb_create = drm_fb_cma_create, + .fb_create = drm_gem_fb_create, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; -- cgit v1.2.3