GNU Linux-libre 4.14.303-gnu1
[releases.git] / drivers / gpu / drm / pl111 / pl111_connector.c
1 /*
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
34 static 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
46 static 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
57 static 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
68 const 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,
72         .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
77 const 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  */
84 static 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
110 int 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