linux/drivers/gpu/drm/pl111/pl111_connector.c
Tom Cooksey bed41005e6 drm/pl111: Initial drm/kms driver for pl111
This is a modesetting driver for the pl111 CLCD display controller
found on various ARM platforms such as the Versatile Express. The
driver has only been tested on the bcm911360_entphn platform so far,
with PRIME-based buffer sharing between vc4 and clcd.

It reuses the existing devicetree binding, while not using quite as
many of its properties as the fbdev driver does (those are left for
future work).

v2: Nearly complete rewrite by anholt, cutting 2/3 of the code thanks
    to DRM core's excellent new helpers.
v3: Don't match pl110 any more, don't attach if we don't have a DRM
    panel, use DRM_GEM_CMA_FOPS, update MAINTAINERS, use the simple
    display helper, use drm_gem_cma_dumb_create (same as our wrapper).
v4: Change the driver's .name to not clash with fbdev in sysfs, drop
    platform alias, drop redundant "drm" in DRM driver name, hook up
    .prepare_fb to the CMA helper so that DMA fences should work.
v5: Move register definitions inside the driver directory, fix build
    in COMPILE_TEST and !AMBA mode.
v6: Drop TIM2_CLKSEL for now to be consistent with existing DT
    bindings, switch back to external register definitions.

Signed-off-by: Tom Cooksey <tom.cooksey@arm.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org> (v5)
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/20170413031746.12921-2-eric@anholt.net
2017-05-08 12:24:06 -07:00

128 lines
3.5 KiB
C

/*
* (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
*
* Parts of this file were based on sources as follows:
*
* Copyright (c) 2006-2008 Intel Corporation
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
* Copyright (C) 2011 Texas Instruments
*
* 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.
*
*/
/**
* pl111_drm_connector.c
* Implementation of the connector functions for PL111 DRM
*/
#include <linux/amba/clcd-regs.h>
#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 "pl111_drm.h"
static void pl111_connector_destroy(struct drm_connector *connector)
{
struct pl111_drm_connector *pl111_connector =
to_pl111_connector(connector);
if (pl111_connector->panel)
drm_panel_detach(pl111_connector->panel);
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
}
static enum drm_connector_status pl111_connector_detect(struct drm_connector
*connector, bool force)
{
struct pl111_drm_connector *pl111_connector =
to_pl111_connector(connector);
return (pl111_connector->panel ?
connector_status_connected :
connector_status_disconnected);
}
static int pl111_connector_helper_get_modes(struct drm_connector *connector)
{
struct pl111_drm_connector *pl111_connector =
to_pl111_connector(connector);
if (!pl111_connector->panel)
return 0;
return drm_panel_get_modes(pl111_connector->panel);
}
const struct drm_connector_funcs connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = pl111_connector_destroy,
.detect = pl111_connector_detect,
.dpms = drm_atomic_helper_connector_dpms,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
const struct drm_connector_helper_funcs connector_helper_funcs = {
.get_modes = pl111_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 *pl111_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 pl111_connector_init(struct drm_device *dev)
{
struct pl111_drm_dev_private *priv = dev->dev_private;
struct pl111_drm_connector *pl111_connector = &priv->connector;
struct drm_connector *connector = &pl111_connector->connector;
drm_connector_init(dev, connector, &connector_funcs,
DRM_MODE_CONNECTOR_DPI);
drm_connector_helper_add(connector, &connector_helper_funcs);
pl111_connector->panel = pl111_get_panel(dev->dev);
if (pl111_connector->panel)
drm_panel_attach(pl111_connector->panel, connector);
return 0;
}