Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / gpu / drm / tegra / output.c
1 /*
2  * Copyright (C) 2012 Avionic Design GmbH
3  * Copyright (C) 2012 NVIDIA CORPORATION.  All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  */
9
10 #include <linux/of_gpio.h>
11
12 #include <drm/drm_atomic_helper.h>
13 #include <drm/drm_panel.h>
14 #include "drm.h"
15
16 int tegra_output_connector_get_modes(struct drm_connector *connector)
17 {
18         struct tegra_output *output = connector_to_output(connector);
19         struct edid *edid = NULL;
20         int err = 0;
21
22         /*
23          * If the panel provides one or more modes, use them exclusively and
24          * ignore any other means of obtaining a mode.
25          */
26         if (output->panel) {
27                 err = output->panel->funcs->get_modes(output->panel);
28                 if (err > 0)
29                         return err;
30         }
31
32         if (output->edid)
33                 edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL);
34         else if (output->ddc)
35                 edid = drm_get_edid(connector, output->ddc);
36
37         drm_mode_connector_update_edid_property(connector, edid);
38
39         if (edid) {
40                 err = drm_add_edid_modes(connector, edid);
41                 kfree(edid);
42         }
43
44         return err;
45 }
46
47 struct drm_encoder *
48 tegra_output_connector_best_encoder(struct drm_connector *connector)
49 {
50         struct tegra_output *output = connector_to_output(connector);
51
52         return &output->encoder;
53 }
54
55 enum drm_connector_status
56 tegra_output_connector_detect(struct drm_connector *connector, bool force)
57 {
58         struct tegra_output *output = connector_to_output(connector);
59         enum drm_connector_status status = connector_status_unknown;
60
61         if (gpio_is_valid(output->hpd_gpio)) {
62                 if (gpio_get_value(output->hpd_gpio) == 0)
63                         status = connector_status_disconnected;
64                 else
65                         status = connector_status_connected;
66         } else {
67                 if (!output->panel)
68                         status = connector_status_disconnected;
69                 else
70                         status = connector_status_connected;
71         }
72
73         return status;
74 }
75
76 void tegra_output_connector_destroy(struct drm_connector *connector)
77 {
78         drm_connector_unregister(connector);
79         drm_connector_cleanup(connector);
80 }
81
82 void tegra_output_encoder_destroy(struct drm_encoder *encoder)
83 {
84         drm_encoder_cleanup(encoder);
85 }
86
87 static irqreturn_t hpd_irq(int irq, void *data)
88 {
89         struct tegra_output *output = data;
90
91         if (output->connector.dev)
92                 drm_helper_hpd_irq_event(output->connector.dev);
93
94         return IRQ_HANDLED;
95 }
96
97 int tegra_output_probe(struct tegra_output *output)
98 {
99         struct device_node *ddc, *panel;
100         enum of_gpio_flags flags;
101         int err, size;
102
103         if (!output->of_node)
104                 output->of_node = output->dev->of_node;
105
106         panel = of_parse_phandle(output->of_node, "nvidia,panel", 0);
107         if (panel) {
108                 output->panel = of_drm_find_panel(panel);
109                 if (!output->panel)
110                         return -EPROBE_DEFER;
111
112                 of_node_put(panel);
113         }
114
115         output->edid = of_get_property(output->of_node, "nvidia,edid", &size);
116
117         ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0);
118         if (ddc) {
119                 output->ddc = of_find_i2c_adapter_by_node(ddc);
120                 if (!output->ddc) {
121                         err = -EPROBE_DEFER;
122                         of_node_put(ddc);
123                         return err;
124                 }
125
126                 of_node_put(ddc);
127         }
128
129         output->hpd_gpio = of_get_named_gpio_flags(output->of_node,
130                                                    "nvidia,hpd-gpio", 0,
131                                                    &flags);
132         if (gpio_is_valid(output->hpd_gpio)) {
133                 unsigned long flags;
134
135                 err = gpio_request_one(output->hpd_gpio, GPIOF_DIR_IN,
136                                        "HDMI hotplug detect");
137                 if (err < 0) {
138                         dev_err(output->dev, "gpio_request_one(): %d\n", err);
139                         return err;
140                 }
141
142                 err = gpio_to_irq(output->hpd_gpio);
143                 if (err < 0) {
144                         dev_err(output->dev, "gpio_to_irq(): %d\n", err);
145                         gpio_free(output->hpd_gpio);
146                         return err;
147                 }
148
149                 output->hpd_irq = err;
150
151                 flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
152                         IRQF_ONESHOT;
153
154                 err = request_threaded_irq(output->hpd_irq, NULL, hpd_irq,
155                                            flags, "hpd", output);
156                 if (err < 0) {
157                         dev_err(output->dev, "failed to request IRQ#%u: %d\n",
158                                 output->hpd_irq, err);
159                         gpio_free(output->hpd_gpio);
160                         return err;
161                 }
162
163                 output->connector.polled = DRM_CONNECTOR_POLL_HPD;
164
165                 /*
166                  * Disable the interrupt until the connector has been
167                  * initialized to avoid a race in the hotplug interrupt
168                  * handler.
169                  */
170                 disable_irq(output->hpd_irq);
171         }
172
173         return 0;
174 }
175
176 void tegra_output_remove(struct tegra_output *output)
177 {
178         if (gpio_is_valid(output->hpd_gpio)) {
179                 free_irq(output->hpd_irq, output);
180                 gpio_free(output->hpd_gpio);
181         }
182
183         if (output->ddc)
184                 put_device(&output->ddc->dev);
185 }
186
187 int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
188 {
189         int err;
190
191         if (output->panel) {
192                 err = drm_panel_attach(output->panel, &output->connector);
193                 if (err < 0)
194                         return err;
195         }
196
197         /*
198          * The connector is now registered and ready to receive hotplug events
199          * so the hotplug interrupt can be enabled.
200          */
201         if (gpio_is_valid(output->hpd_gpio))
202                 enable_irq(output->hpd_irq);
203
204         return 0;
205 }
206
207 void tegra_output_exit(struct tegra_output *output)
208 {
209         /*
210          * The connector is going away, so the interrupt must be disabled to
211          * prevent the hotplug interrupt handler from potentially crashing.
212          */
213         if (gpio_is_valid(output->hpd_gpio))
214                 disable_irq(output->hpd_irq);
215
216         if (output->panel)
217                 drm_panel_detach(output->panel);
218 }