5dc4d1a9cad851701c2f73922378dabf8be6bc22
[platform/adaptation/renesas_rcar/renesas_kernel.git] / 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_panel.h>
13 #include "drm.h"
14
15 static int tegra_connector_get_modes(struct drm_connector *connector)
16 {
17         struct tegra_output *output = connector_to_output(connector);
18         struct edid *edid = NULL;
19         int err = 0;
20
21         if (output->panel) {
22                 err = output->panel->funcs->get_modes(output->panel);
23                 if (err > 0)
24                         return err;
25         }
26
27         if (output->edid)
28                 edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL);
29         else if (output->ddc)
30                 edid = drm_get_edid(connector, output->ddc);
31
32         drm_mode_connector_update_edid_property(connector, edid);
33
34         if (edid) {
35                 err = drm_add_edid_modes(connector, edid);
36                 kfree(edid);
37         }
38
39         return err;
40 }
41
42 static int tegra_connector_mode_valid(struct drm_connector *connector,
43                                       struct drm_display_mode *mode)
44 {
45         struct tegra_output *output = connector_to_output(connector);
46         enum drm_mode_status status = MODE_OK;
47         int err;
48
49         err = tegra_output_check_mode(output, mode, &status);
50         if (err < 0)
51                 return MODE_ERROR;
52
53         return status;
54 }
55
56 static struct drm_encoder *
57 tegra_connector_best_encoder(struct drm_connector *connector)
58 {
59         struct tegra_output *output = connector_to_output(connector);
60
61         return &output->encoder;
62 }
63
64 static const struct drm_connector_helper_funcs connector_helper_funcs = {
65         .get_modes = tegra_connector_get_modes,
66         .mode_valid = tegra_connector_mode_valid,
67         .best_encoder = tegra_connector_best_encoder,
68 };
69
70 static enum drm_connector_status
71 tegra_connector_detect(struct drm_connector *connector, bool force)
72 {
73         struct tegra_output *output = connector_to_output(connector);
74         enum drm_connector_status status = connector_status_unknown;
75
76         if (gpio_is_valid(output->hpd_gpio)) {
77                 if (gpio_get_value(output->hpd_gpio) == 0)
78                         status = connector_status_disconnected;
79                 else
80                         status = connector_status_connected;
81         } else {
82                 if (!output->panel)
83                         status = connector_status_disconnected;
84                 else
85                         status = connector_status_connected;
86
87                 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
88                         status = connector_status_connected;
89         }
90
91         return status;
92 }
93
94 static void drm_connector_clear(struct drm_connector *connector)
95 {
96         memset(connector, 0, sizeof(*connector));
97 }
98
99 static void tegra_connector_destroy(struct drm_connector *connector)
100 {
101         drm_sysfs_connector_remove(connector);
102         drm_connector_cleanup(connector);
103         drm_connector_clear(connector);
104 }
105
106 static const struct drm_connector_funcs connector_funcs = {
107         .dpms = drm_helper_connector_dpms,
108         .detect = tegra_connector_detect,
109         .fill_modes = drm_helper_probe_single_connector_modes,
110         .destroy = tegra_connector_destroy,
111 };
112
113 static void drm_encoder_clear(struct drm_encoder *encoder)
114 {
115         memset(encoder, 0, sizeof(*encoder));
116 }
117
118 static void tegra_encoder_destroy(struct drm_encoder *encoder)
119 {
120         drm_encoder_cleanup(encoder);
121         drm_encoder_clear(encoder);
122 }
123
124 static const struct drm_encoder_funcs encoder_funcs = {
125         .destroy = tegra_encoder_destroy,
126 };
127
128 static void tegra_encoder_dpms(struct drm_encoder *encoder, int mode)
129 {
130         struct tegra_output *output = encoder_to_output(encoder);
131         struct drm_panel *panel = output->panel;
132
133         if (panel && panel->funcs) {
134                 if (mode != DRM_MODE_DPMS_ON)
135                         drm_panel_disable(panel);
136                 else
137                         drm_panel_enable(panel);
138         }
139 }
140
141 static bool tegra_encoder_mode_fixup(struct drm_encoder *encoder,
142                                      const struct drm_display_mode *mode,
143                                      struct drm_display_mode *adjusted)
144 {
145         return true;
146 }
147
148 static void tegra_encoder_prepare(struct drm_encoder *encoder)
149 {
150 }
151
152 static void tegra_encoder_commit(struct drm_encoder *encoder)
153 {
154 }
155
156 static void tegra_encoder_mode_set(struct drm_encoder *encoder,
157                                    struct drm_display_mode *mode,
158                                    struct drm_display_mode *adjusted)
159 {
160         struct tegra_output *output = encoder_to_output(encoder);
161         int err;
162
163         err = tegra_output_enable(output);
164         if (err < 0)
165                 dev_err(encoder->dev->dev, "tegra_output_enable(): %d\n", err);
166 }
167
168 static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
169         .dpms = tegra_encoder_dpms,
170         .mode_fixup = tegra_encoder_mode_fixup,
171         .prepare = tegra_encoder_prepare,
172         .commit = tegra_encoder_commit,
173         .mode_set = tegra_encoder_mode_set,
174 };
175
176 static irqreturn_t hpd_irq(int irq, void *data)
177 {
178         struct tegra_output *output = data;
179
180         drm_helper_hpd_irq_event(output->connector.dev);
181
182         return IRQ_HANDLED;
183 }
184
185 int tegra_output_probe(struct tegra_output *output)
186 {
187         struct device_node *ddc, *panel;
188         enum of_gpio_flags flags;
189         size_t size;
190         int err;
191
192         if (!output->of_node)
193                 output->of_node = output->dev->of_node;
194
195         panel = of_parse_phandle(output->of_node, "nvidia,panel", 0);
196         if (panel) {
197                 output->panel = of_drm_find_panel(panel);
198                 if (!output->panel)
199                         return -EPROBE_DEFER;
200
201                 of_node_put(panel);
202         }
203
204         output->edid = of_get_property(output->of_node, "nvidia,edid", &size);
205
206         ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0);
207         if (ddc) {
208                 output->ddc = of_find_i2c_adapter_by_node(ddc);
209                 if (!output->ddc) {
210                         err = -EPROBE_DEFER;
211                         of_node_put(ddc);
212                         return err;
213                 }
214
215                 of_node_put(ddc);
216         }
217
218         output->hpd_gpio = of_get_named_gpio_flags(output->of_node,
219                                                    "nvidia,hpd-gpio", 0,
220                                                    &flags);
221         if (gpio_is_valid(output->hpd_gpio)) {
222                 unsigned long flags;
223
224                 err = gpio_request_one(output->hpd_gpio, GPIOF_DIR_IN,
225                                        "HDMI hotplug detect");
226                 if (err < 0) {
227                         dev_err(output->dev, "gpio_request_one(): %d\n", err);
228                         return err;
229                 }
230
231                 err = gpio_to_irq(output->hpd_gpio);
232                 if (err < 0) {
233                         dev_err(output->dev, "gpio_to_irq(): %d\n", err);
234                         gpio_free(output->hpd_gpio);
235                         return err;
236                 }
237
238                 output->hpd_irq = err;
239
240                 flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
241                         IRQF_ONESHOT;
242
243                 err = request_threaded_irq(output->hpd_irq, NULL, hpd_irq,
244                                            flags, "hpd", output);
245                 if (err < 0) {
246                         dev_err(output->dev, "failed to request IRQ#%u: %d\n",
247                                 output->hpd_irq, err);
248                         gpio_free(output->hpd_gpio);
249                         return err;
250                 }
251
252                 output->connector.polled = DRM_CONNECTOR_POLL_HPD;
253         }
254
255         return 0;
256 }
257
258 int tegra_output_remove(struct tegra_output *output)
259 {
260         if (gpio_is_valid(output->hpd_gpio)) {
261                 free_irq(output->hpd_irq, output);
262                 gpio_free(output->hpd_gpio);
263         }
264
265         if (output->ddc)
266                 put_device(&output->ddc->dev);
267
268         return 0;
269 }
270
271 int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
272 {
273         int connector, encoder;
274
275         switch (output->type) {
276         case TEGRA_OUTPUT_RGB:
277                 connector = DRM_MODE_CONNECTOR_LVDS;
278                 encoder = DRM_MODE_ENCODER_LVDS;
279                 break;
280
281         case TEGRA_OUTPUT_HDMI:
282                 connector = DRM_MODE_CONNECTOR_HDMIA;
283                 encoder = DRM_MODE_ENCODER_TMDS;
284                 break;
285
286         default:
287                 connector = DRM_MODE_CONNECTOR_Unknown;
288                 encoder = DRM_MODE_ENCODER_NONE;
289                 break;
290         }
291
292         drm_connector_init(drm, &output->connector, &connector_funcs,
293                            connector);
294         drm_connector_helper_add(&output->connector, &connector_helper_funcs);
295         output->connector.dpms = DRM_MODE_DPMS_OFF;
296
297         if (output->panel)
298                 drm_panel_attach(output->panel, &output->connector);
299
300         drm_encoder_init(drm, &output->encoder, &encoder_funcs, encoder);
301         drm_encoder_helper_add(&output->encoder, &encoder_helper_funcs);
302
303         drm_mode_connector_attach_encoder(&output->connector, &output->encoder);
304         drm_sysfs_connector_add(&output->connector);
305
306         output->encoder.possible_crtcs = 0x3;
307
308         return 0;
309 }
310
311 int tegra_output_exit(struct tegra_output *output)
312 {
313         return 0;
314 }