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