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
-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
+++ /dev/null
-/*
- * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
- * Parts of this file were based on sources as follows:
- *
- * Copyright (C) 2006-2008 Intel Corporation
- * Copyright (C) 2007 Amos Lee <amos_lee@storlinksemi.com>
- * Copyright (C) 2007 Dave Airlie <airlied@linux.ie>
- * 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 <linux/version.h>
-#include <linux/shmem_fs.h>
-#include <linux/dma-buf.h>
-
-#include <drm/drmP.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
-
-#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;
-}
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;
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);
}
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);
}
&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;
}
#include <drm/drm_gem.h>
#include <drm/drm_simple_kms_helper.h>
-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;
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_panel.h>
+#include <drm/drm_of.h>
+#include <drm/drm_bridge.h>
#include "tve200_drm.h"
{
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);
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);
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;
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);