blob: d335f9a29ce4aa59bbc46219195642224dee7e53 [file] [log] [blame]
Tom Cookseybed41002017-04-12 20:17:46 -07001/*
2 * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
3 *
4 * Parts of this file were based on sources as follows:
5 *
6 * Copyright (c) 2006-2008 Intel Corporation
7 * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
8 * Copyright (C) 2011 Texas Instruments
9 *
10 * This program is free software and is provided to you under the terms of the
11 * GNU General Public License version 2 as published by the Free Software
12 * Foundation, and any use by you of this program is subject to the terms of
13 * such GNU licence.
14 *
15 */
16
17/**
18 * pl111_drm_connector.c
19 * Implementation of the connector functions for PL111 DRM
20 */
21#include <linux/amba/clcd-regs.h>
22#include <linux/version.h>
23#include <linux/shmem_fs.h>
24#include <linux/dma-buf.h>
25
26#include <drm/drmP.h>
27#include <drm/drm_atomic_helper.h>
28#include <drm/drm_crtc_helper.h>
29#include <drm/drm_of.h>
30#include <drm/drm_panel.h>
31
32#include "pl111_drm.h"
33
34static void pl111_connector_destroy(struct drm_connector *connector)
35{
36 struct pl111_drm_connector *pl111_connector =
37 to_pl111_connector(connector);
38
39 if (pl111_connector->panel)
40 drm_panel_detach(pl111_connector->panel);
41
42 drm_connector_unregister(connector);
43 drm_connector_cleanup(connector);
44}
45
46static enum drm_connector_status pl111_connector_detect(struct drm_connector
47 *connector, bool force)
48{
49 struct pl111_drm_connector *pl111_connector =
50 to_pl111_connector(connector);
51
52 return (pl111_connector->panel ?
53 connector_status_connected :
54 connector_status_disconnected);
55}
56
57static int pl111_connector_helper_get_modes(struct drm_connector *connector)
58{
59 struct pl111_drm_connector *pl111_connector =
60 to_pl111_connector(connector);
61
62 if (!pl111_connector->panel)
63 return 0;
64
65 return drm_panel_get_modes(pl111_connector->panel);
66}
67
68const struct drm_connector_funcs connector_funcs = {
69 .fill_modes = drm_helper_probe_single_connector_modes,
70 .destroy = pl111_connector_destroy,
71 .detect = pl111_connector_detect,
Tom Cookseybed41002017-04-12 20:17:46 -070072 .reset = drm_atomic_helper_connector_reset,
73 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
74 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
75};
76
77const struct drm_connector_helper_funcs connector_helper_funcs = {
78 .get_modes = pl111_connector_helper_get_modes,
79};
80
81/* Walks the OF graph to find the panel node and then asks DRM to look
82 * up the panel.
83 */
84static struct drm_panel *pl111_get_panel(struct device *dev)
85{
86 struct device_node *endpoint, *panel_node;
87 struct device_node *np = dev->of_node;
88 struct drm_panel *panel;
89
90 endpoint = of_graph_get_next_endpoint(np, NULL);
91 if (!endpoint) {
92 dev_err(dev, "no endpoint to fetch panel\n");
93 return NULL;
94 }
95
96 /* don't proceed if we have an endpoint but no panel_node tied to it */
97 panel_node = of_graph_get_remote_port_parent(endpoint);
98 of_node_put(endpoint);
99 if (!panel_node) {
100 dev_err(dev, "no valid panel node\n");
101 return NULL;
102 }
103
104 panel = of_drm_find_panel(panel_node);
105 of_node_put(panel_node);
106
107 return panel;
108}
109
110int pl111_connector_init(struct drm_device *dev)
111{
112 struct pl111_drm_dev_private *priv = dev->dev_private;
113 struct pl111_drm_connector *pl111_connector = &priv->connector;
114 struct drm_connector *connector = &pl111_connector->connector;
115
116 drm_connector_init(dev, connector, &connector_funcs,
117 DRM_MODE_CONNECTOR_DPI);
118 drm_connector_helper_add(connector, &connector_helper_funcs);
119
120 pl111_connector->panel = pl111_get_panel(dev->dev);
121 if (pl111_connector->panel)
122 drm_panel_attach(pl111_connector->panel, connector);
123
124 return 0;
125}
126