]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/msm/hdmi/hdmi_connector.c
drm/msm: basic KMS driver for snapdragon
[karo-tx-linux.git] / drivers / gpu / drm / msm / hdmi / hdmi_connector.c
1 /*
2  * Copyright (C) 2013 Red Hat
3  * Author: Rob Clark <robdclark@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 as published by
7  * the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <linux/gpio.h>
19
20 #include "msm_connector.h"
21 #include "hdmi.h"
22
23 struct hdmi_connector {
24         struct msm_connector base;
25         struct hdmi hdmi;
26         unsigned long int pixclock;
27         bool enabled;
28 };
29 #define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base)
30
31 static int gpio_config(struct hdmi *hdmi, bool on)
32 {
33         struct drm_device *dev = hdmi->dev;
34         struct hdmi_platform_config *config =
35                         hdmi->pdev->dev.platform_data;
36         int ret;
37
38         if (on) {
39                 ret = gpio_request(config->ddc_clk_gpio, "HDMI_DDC_CLK");
40                 if (ret) {
41                         dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
42                                 "HDMI_DDC_CLK", config->ddc_clk_gpio, ret);
43                         goto error1;
44                 }
45                 ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA");
46                 if (ret) {
47                         dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
48                                 "HDMI_DDC_DATA", config->ddc_data_gpio, ret);
49                         goto error2;
50                 }
51                 ret = gpio_request(config->hpd_gpio, "HDMI_HPD");
52                 if (ret) {
53                         dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
54                                 "HDMI_HPD", config->hpd_gpio, ret);
55                         goto error3;
56                 }
57                 if (config->pmic_gpio != -1) {
58                         ret = gpio_request(config->pmic_gpio, "PMIC_HDMI_MUX_SEL");
59                         if (ret) {
60                                 dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
61                                         "PMIC_HDMI_MUX_SEL", config->pmic_gpio, ret);
62                                 goto error4;
63                         }
64                         gpio_set_value_cansleep(config->pmic_gpio, 0);
65                 }
66                 DBG("gpio on");
67         } else {
68                 gpio_free(config->ddc_clk_gpio);
69                 gpio_free(config->ddc_data_gpio);
70                 gpio_free(config->hpd_gpio);
71
72                 if (config->pmic_gpio != -1) {
73                         gpio_set_value_cansleep(config->pmic_gpio, 1);
74                         gpio_free(config->pmic_gpio);
75                 }
76                 DBG("gpio off");
77         }
78
79         return 0;
80
81 error4:
82         gpio_free(config->hpd_gpio);
83 error3:
84         gpio_free(config->ddc_data_gpio);
85 error2:
86         gpio_free(config->ddc_clk_gpio);
87 error1:
88         return ret;
89 }
90
91 static int hpd_enable(struct hdmi_connector *hdmi_connector)
92 {
93         struct hdmi *hdmi = &hdmi_connector->hdmi;
94         struct drm_device *dev = hdmi_connector->base.base.dev;
95         struct hdmi_phy *phy = hdmi->phy;
96         uint32_t hpd_ctrl;
97         int ret;
98
99         ret = gpio_config(hdmi, true);
100         if (ret) {
101                 dev_err(dev->dev, "failed to configure GPIOs: %d\n", ret);
102                 goto fail;
103         }
104
105         ret = clk_prepare_enable(hdmi->clk);
106         if (ret) {
107                 dev_err(dev->dev, "failed to enable 'clk': %d\n", ret);
108                 goto fail;
109         }
110
111         ret = clk_prepare_enable(hdmi->m_pclk);
112         if (ret) {
113                 dev_err(dev->dev, "failed to enable 'm_pclk': %d\n", ret);
114                 goto fail;
115         }
116
117         ret = clk_prepare_enable(hdmi->s_pclk);
118         if (ret) {
119                 dev_err(dev->dev, "failed to enable 's_pclk': %d\n", ret);
120                 goto fail;
121         }
122
123         if (hdmi->mpp0)
124                 ret = regulator_enable(hdmi->mpp0);
125         if (!ret)
126                 ret = regulator_enable(hdmi->mvs);
127         if (ret) {
128                 dev_err(dev->dev, "failed to enable regulators: %d\n", ret);
129                 goto fail;
130         }
131
132         hdmi_set_mode(hdmi, false);
133         phy->funcs->reset(phy);
134         hdmi_set_mode(hdmi, true);
135
136         hdmi_write(hdmi, REG_HDMI_USEC_REFTIMER, 0x0001001b);
137
138         /* enable HPD events: */
139         hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
140                         HDMI_HPD_INT_CTRL_INT_CONNECT |
141                         HDMI_HPD_INT_CTRL_INT_EN);
142
143         /* set timeout to 4.1ms (max) for hardware debounce */
144         hpd_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
145         hpd_ctrl |= HDMI_HPD_CTRL_TIMEOUT(0x1fff);
146
147         /* Toggle HPD circuit to trigger HPD sense */
148         hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
149                         ~HDMI_HPD_CTRL_ENABLE & hpd_ctrl);
150         hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
151                         HDMI_HPD_CTRL_ENABLE | hpd_ctrl);
152
153         return 0;
154
155 fail:
156         return ret;
157 }
158
159 static int hdp_disable(struct hdmi_connector *hdmi_connector)
160 {
161         struct hdmi *hdmi = &hdmi_connector->hdmi;
162         struct drm_device *dev = hdmi_connector->base.base.dev;
163         int ret = 0;
164
165         /* Disable HPD interrupt */
166         hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0);
167
168         hdmi_set_mode(hdmi, false);
169
170         if (hdmi->mpp0)
171                 ret = regulator_disable(hdmi->mpp0);
172         if (!ret)
173                 ret = regulator_disable(hdmi->mvs);
174         if (ret) {
175                 dev_err(dev->dev, "failed to enable regulators: %d\n", ret);
176                 goto fail;
177         }
178
179         clk_disable_unprepare(hdmi->clk);
180         clk_disable_unprepare(hdmi->m_pclk);
181         clk_disable_unprepare(hdmi->s_pclk);
182
183         ret = gpio_config(hdmi, false);
184         if (ret) {
185                 dev_err(dev->dev, "failed to unconfigure GPIOs: %d\n", ret);
186                 goto fail;
187         }
188
189         return 0;
190
191 fail:
192         return ret;
193 }
194
195 void hdmi_connector_irq(struct drm_connector *connector)
196 {
197         struct msm_connector *msm_connector = to_msm_connector(connector);
198         struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
199         struct hdmi *hdmi = &hdmi_connector->hdmi;
200         uint32_t hpd_int_status, hpd_int_ctrl;
201
202         /* Process HPD: */
203         hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
204         hpd_int_ctrl   = hdmi_read(hdmi, REG_HDMI_HPD_INT_CTRL);
205
206         if ((hpd_int_ctrl & HDMI_HPD_INT_CTRL_INT_EN) &&
207                         (hpd_int_status & HDMI_HPD_INT_STATUS_INT)) {
208                 bool detected = !!(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED);
209
210                 DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl);
211
212                 /* ack the irq: */
213                 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
214                                 hpd_int_ctrl | HDMI_HPD_INT_CTRL_INT_ACK);
215
216                 drm_helper_hpd_irq_event(connector->dev);
217
218                 /* detect disconnect if we are connected or visa versa: */
219                 hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN;
220                 if (!detected)
221                         hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
222                 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);
223         }
224 }
225
226 static enum drm_connector_status hdmi_connector_detect(
227                 struct drm_connector *connector, bool force)
228 {
229         struct msm_connector *msm_connector = to_msm_connector(connector);
230         struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
231         struct hdmi *hdmi = &hdmi_connector->hdmi;
232         uint32_t hpd_int_status;
233         int retry = 20;
234
235         hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
236
237         /* sense seems to in some cases be momentarily de-asserted, don't
238          * let that trick us into thinking the monitor is gone:
239          */
240         while (retry-- && !(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED)) {
241                 mdelay(10);
242                 hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
243                 DBG("status=%08x", hpd_int_status);
244         }
245
246         return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ?
247                         connector_status_connected : connector_status_disconnected;
248 }
249
250 static void hdmi_connector_destroy(struct drm_connector *connector)
251 {
252         struct msm_connector *msm_connector = to_msm_connector(connector);
253         struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
254
255         hdp_disable(hdmi_connector);
256
257         drm_sysfs_connector_remove(connector);
258         drm_connector_cleanup(connector);
259
260         hdmi_destroy(&hdmi_connector->hdmi);
261
262         kfree(hdmi_connector);
263 }
264
265 static int hdmi_connector_get_modes(struct drm_connector *connector)
266 {
267         struct msm_connector *msm_connector = to_msm_connector(connector);
268         struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
269         struct hdmi *hdmi = &hdmi_connector->hdmi;
270         struct edid *edid;
271         uint32_t hdmi_ctrl;
272         int ret = 0;
273
274         hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL);
275         hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE);
276
277         edid = drm_get_edid(connector, hdmi->i2c);
278
279         hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
280
281         drm_mode_connector_update_edid_property(connector, edid);
282
283         if (edid) {
284                 ret = drm_add_edid_modes(connector, edid);
285                 kfree(edid);
286         }
287
288         return ret;
289 }
290
291 static int hdmi_connector_mode_valid(struct drm_connector *connector,
292                                  struct drm_display_mode *mode)
293 {
294         struct msm_connector *msm_connector = to_msm_connector(connector);
295         struct msm_drm_private *priv = connector->dev->dev_private;
296         struct msm_kms *kms = priv->kms;
297         long actual, requested;
298
299         requested = 1000 * mode->clock;
300         actual = kms->funcs->round_pixclk(kms,
301                         requested, msm_connector->encoder);
302
303         DBG("requested=%ld, actual=%ld", requested, actual);
304
305         if (actual != requested)
306                 return MODE_CLOCK_RANGE;
307
308         return 0;
309 }
310
311 static const struct drm_connector_funcs hdmi_connector_funcs = {
312         .dpms = drm_helper_connector_dpms,
313         .detect = hdmi_connector_detect,
314         .fill_modes = drm_helper_probe_single_connector_modes,
315         .destroy = hdmi_connector_destroy,
316 };
317
318 static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
319         .get_modes = hdmi_connector_get_modes,
320         .mode_valid = hdmi_connector_mode_valid,
321         .best_encoder = msm_connector_attached_encoder,
322 };
323
324 static void hdmi_connector_dpms(struct msm_connector *msm_connector, int mode)
325 {
326         struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
327         struct hdmi *hdmi = &hdmi_connector->hdmi;
328         struct hdmi_phy *phy = hdmi->phy;
329         bool enabled = (mode == DRM_MODE_DPMS_ON);
330
331         DBG("mode=%d", mode);
332
333         if (enabled == hdmi_connector->enabled)
334                 return;
335
336         if (enabled) {
337                 phy->funcs->powerup(phy, hdmi_connector->pixclock);
338                 hdmi_set_mode(hdmi, true);
339         } else {
340                 hdmi_set_mode(hdmi, false);
341                 phy->funcs->powerdown(phy);
342         }
343
344         hdmi_connector->enabled = enabled;
345 }
346
347 static void hdmi_connector_mode_set(struct msm_connector *msm_connector,
348                 struct drm_display_mode *mode)
349 {
350         struct hdmi_connector *hdmi_connector = to_hdmi_connector(msm_connector);
351         struct hdmi *hdmi = &hdmi_connector->hdmi;
352         int hstart, hend, vstart, vend;
353         uint32_t frame_ctrl;
354
355         hdmi_connector->pixclock = mode->clock * 1000;
356
357         hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1;
358
359         hstart = mode->htotal - mode->hsync_start;
360         hend   = mode->htotal - mode->hsync_start + mode->hdisplay;
361
362         vstart = mode->vtotal - mode->vsync_start - 1;
363         vend   = mode->vtotal - mode->vsync_start + mode->vdisplay - 1;
364
365         DBG("htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d",
366                         mode->htotal, mode->vtotal, hstart, hend, vstart, vend);
367
368         hdmi_write(hdmi, REG_HDMI_TOTAL,
369                         HDMI_TOTAL_H_TOTAL(mode->htotal - 1) |
370                         HDMI_TOTAL_V_TOTAL(mode->vtotal - 1));
371
372         hdmi_write(hdmi, REG_HDMI_ACTIVE_HSYNC,
373                         HDMI_ACTIVE_HSYNC_START(hstart) |
374                         HDMI_ACTIVE_HSYNC_END(hend));
375         hdmi_write(hdmi, REG_HDMI_ACTIVE_VSYNC,
376                         HDMI_ACTIVE_VSYNC_START(vstart) |
377                         HDMI_ACTIVE_VSYNC_END(vend));
378
379         if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
380                 hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
381                                 HDMI_VSYNC_TOTAL_F2_V_TOTAL(mode->vtotal));
382                 hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
383                                 HDMI_VSYNC_ACTIVE_F2_START(vstart + 1) |
384                                 HDMI_VSYNC_ACTIVE_F2_END(vend + 1));
385         } else {
386                 hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
387                                 HDMI_VSYNC_TOTAL_F2_V_TOTAL(0));
388                 hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
389                                 HDMI_VSYNC_ACTIVE_F2_START(0) |
390                                 HDMI_VSYNC_ACTIVE_F2_END(0));
391         }
392
393         frame_ctrl = 0;
394         if (mode->flags & DRM_MODE_FLAG_NHSYNC)
395                 frame_ctrl |= HDMI_FRAME_CTRL_HSYNC_LOW;
396         if (mode->flags & DRM_MODE_FLAG_NVSYNC)
397                 frame_ctrl |= HDMI_FRAME_CTRL_VSYNC_LOW;
398         if (mode->flags & DRM_MODE_FLAG_INTERLACE)
399                 frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
400         DBG("frame_ctrl=%08x", frame_ctrl);
401         hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
402
403         // TODO until we have audio, this might be safest:
404         if (hdmi->hdmi_mode)
405                 hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE);
406 }
407
408 static const struct msm_connector_funcs msm_connector_funcs = {
409                 .dpms = hdmi_connector_dpms,
410                 .mode_set = hdmi_connector_mode_set,
411 };
412
413 /* initialize connector */
414 struct drm_connector *hdmi_connector_init(struct drm_device *dev,
415                 struct drm_encoder *encoder)
416 {
417         struct drm_connector *connector = NULL;
418         struct hdmi_connector *hdmi_connector;
419         int ret;
420
421         hdmi_connector = kzalloc(sizeof(*hdmi_connector), GFP_KERNEL);
422         if (!hdmi_connector) {
423                 ret = -ENOMEM;
424                 goto fail;
425         }
426
427         connector = &hdmi_connector->base.base;
428
429         msm_connector_init(&hdmi_connector->base,
430                         &msm_connector_funcs, encoder);
431         drm_connector_init(dev, connector, &hdmi_connector_funcs,
432                         DRM_MODE_CONNECTOR_HDMIA);
433         drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
434
435         connector->polled = DRM_CONNECTOR_POLL_HPD;
436
437         connector->interlace_allowed = 1;
438         connector->doublescan_allowed = 0;
439
440         drm_sysfs_connector_add(connector);
441
442         ret = hdmi_init(&hdmi_connector->hdmi, dev, connector);
443         if (ret)
444                 goto fail;
445
446         ret = hpd_enable(hdmi_connector);
447         if (ret) {
448                 dev_err(dev->dev, "failed to enable HPD: %d\n", ret);
449                 goto fail;
450         }
451
452         drm_mode_connector_attach_encoder(connector, encoder);
453
454         return connector;
455
456 fail:
457         if (connector)
458                 hdmi_connector_destroy(connector);
459
460         return ERR_PTR(ret);
461 }