]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/msm/hdmi/hdmi_connector.c
drm: msm: Add ASoC generic hdmi audio codec support.
[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 #include <linux/pinctrl/consumer.h>
20
21 #include "msm_kms.h"
22 #include "hdmi.h"
23
24 struct hdmi_connector {
25         struct drm_connector base;
26         struct hdmi *hdmi;
27         struct work_struct hpd_work;
28 };
29 #define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base)
30
31 static void hdmi_phy_reset(struct hdmi *hdmi)
32 {
33         unsigned int val;
34
35         val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL);
36
37         if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
38                 /* pull low */
39                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
40                                 val & ~HDMI_PHY_CTRL_SW_RESET);
41         } else {
42                 /* pull high */
43                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
44                                 val | HDMI_PHY_CTRL_SW_RESET);
45         }
46
47         if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
48                 /* pull low */
49                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
50                                 val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
51         } else {
52                 /* pull high */
53                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
54                                 val | HDMI_PHY_CTRL_SW_RESET_PLL);
55         }
56
57         msleep(100);
58
59         if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
60                 /* pull high */
61                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
62                                 val | HDMI_PHY_CTRL_SW_RESET);
63         } else {
64                 /* pull low */
65                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
66                                 val & ~HDMI_PHY_CTRL_SW_RESET);
67         }
68
69         if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
70                 /* pull high */
71                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
72                                 val | HDMI_PHY_CTRL_SW_RESET_PLL);
73         } else {
74                 /* pull low */
75                 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
76                                 val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
77         }
78 }
79
80 static int gpio_config(struct hdmi *hdmi, bool on)
81 {
82         struct device *dev = &hdmi->pdev->dev;
83         const struct hdmi_platform_config *config = hdmi->config;
84         int ret;
85
86         if (on) {
87                 if (config->ddc_clk_gpio != -1) {
88                         ret = gpio_request(config->ddc_clk_gpio, "HDMI_DDC_CLK");
89                         if (ret) {
90                                 dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
91                                         "HDMI_DDC_CLK", config->ddc_clk_gpio, ret);
92                                 goto error1;
93                         }
94                         gpio_set_value_cansleep(config->ddc_clk_gpio, 1);
95                 }
96
97                 if (config->ddc_data_gpio != -1) {
98                         ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA");
99                         if (ret) {
100                                 dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
101                                         "HDMI_DDC_DATA", config->ddc_data_gpio, ret);
102                                 goto error2;
103                         }
104                         gpio_set_value_cansleep(config->ddc_data_gpio, 1);
105                 }
106
107                 ret = gpio_request(config->hpd_gpio, "HDMI_HPD");
108                 if (ret) {
109                         dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
110                                 "HDMI_HPD", config->hpd_gpio, ret);
111                         goto error3;
112                 }
113                 gpio_direction_input(config->hpd_gpio);
114                 gpio_set_value_cansleep(config->hpd_gpio, 1);
115
116                 if (config->mux_en_gpio != -1) {
117                         ret = gpio_request(config->mux_en_gpio, "HDMI_MUX_EN");
118                         if (ret) {
119                                 dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
120                                         "HDMI_MUX_EN", config->mux_en_gpio, ret);
121                                 goto error4;
122                         }
123                         gpio_set_value_cansleep(config->mux_en_gpio, 1);
124                 }
125
126                 if (config->mux_sel_gpio != -1) {
127                         ret = gpio_request(config->mux_sel_gpio, "HDMI_MUX_SEL");
128                         if (ret) {
129                                 dev_err(dev, "'%s'(%d) gpio_request failed: %d\n",
130                                         "HDMI_MUX_SEL", config->mux_sel_gpio, ret);
131                                 goto error5;
132                         }
133                         gpio_set_value_cansleep(config->mux_sel_gpio, 0);
134                 }
135
136                 if (config->mux_lpm_gpio != -1) {
137                         ret = gpio_request(config->mux_lpm_gpio,
138                                         "HDMI_MUX_LPM");
139                         if (ret) {
140                                 dev_err(dev,
141                                         "'%s'(%d) gpio_request failed: %d\n",
142                                         "HDMI_MUX_LPM",
143                                         config->mux_lpm_gpio, ret);
144                                 goto error6;
145                         }
146                         gpio_set_value_cansleep(config->mux_lpm_gpio, 1);
147                 }
148                 DBG("gpio on");
149         } else {
150                 if (config->ddc_clk_gpio != -1)
151                         gpio_free(config->ddc_clk_gpio);
152
153                 if (config->ddc_data_gpio != -1)
154                         gpio_free(config->ddc_data_gpio);
155
156                 gpio_free(config->hpd_gpio);
157
158                 if (config->mux_en_gpio != -1) {
159                         gpio_set_value_cansleep(config->mux_en_gpio, 0);
160                         gpio_free(config->mux_en_gpio);
161                 }
162
163                 if (config->mux_sel_gpio != -1) {
164                         gpio_set_value_cansleep(config->mux_sel_gpio, 1);
165                         gpio_free(config->mux_sel_gpio);
166                 }
167
168                 if (config->mux_lpm_gpio != -1) {
169                         gpio_set_value_cansleep(config->mux_lpm_gpio, 0);
170                         gpio_free(config->mux_lpm_gpio);
171                 }
172                 DBG("gpio off");
173         }
174
175         return 0;
176
177 error6:
178         if (config->mux_sel_gpio != -1)
179                 gpio_free(config->mux_sel_gpio);
180 error5:
181         if (config->mux_en_gpio != -1)
182                 gpio_free(config->mux_en_gpio);
183 error4:
184         gpio_free(config->hpd_gpio);
185 error3:
186         if (config->ddc_data_gpio != -1)
187                 gpio_free(config->ddc_data_gpio);
188 error2:
189         if (config->ddc_clk_gpio != -1)
190                 gpio_free(config->ddc_clk_gpio);
191 error1:
192         return ret;
193 }
194
195 static int hpd_enable(struct hdmi_connector *hdmi_connector)
196 {
197         struct hdmi *hdmi = hdmi_connector->hdmi;
198         const struct hdmi_platform_config *config = hdmi->config;
199         struct device *dev = &hdmi->pdev->dev;
200         uint32_t hpd_ctrl;
201         int i, ret;
202         unsigned long flags;
203
204         for (i = 0; i < config->hpd_reg_cnt; i++) {
205                 ret = regulator_enable(hdmi->hpd_regs[i]);
206                 if (ret) {
207                         dev_err(dev, "failed to enable hpd regulator: %s (%d)\n",
208                                         config->hpd_reg_names[i], ret);
209                         goto fail;
210                 }
211         }
212
213         ret = pinctrl_pm_select_default_state(dev);
214         if (ret) {
215                 dev_err(dev, "pinctrl state chg failed: %d\n", ret);
216                 goto fail;
217         }
218
219         ret = gpio_config(hdmi, true);
220         if (ret) {
221                 dev_err(dev, "failed to configure GPIOs: %d\n", ret);
222                 goto fail;
223         }
224
225         for (i = 0; i < config->hpd_clk_cnt; i++) {
226                 if (config->hpd_freq && config->hpd_freq[i]) {
227                         ret = clk_set_rate(hdmi->hpd_clks[i],
228                                         config->hpd_freq[i]);
229                         if (ret)
230                                 dev_warn(dev, "failed to set clk %s (%d)\n",
231                                                 config->hpd_clk_names[i], ret);
232                 }
233
234                 ret = clk_prepare_enable(hdmi->hpd_clks[i]);
235                 if (ret) {
236                         dev_err(dev, "failed to enable hpd clk: %s (%d)\n",
237                                         config->hpd_clk_names[i], ret);
238                         goto fail;
239                 }
240         }
241
242         hdmi_set_mode(hdmi, false);
243         hdmi_phy_reset(hdmi);
244         hdmi_set_mode(hdmi, true);
245
246         hdmi_write(hdmi, REG_HDMI_USEC_REFTIMER, 0x0001001b);
247
248         /* enable HPD events: */
249         hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
250                         HDMI_HPD_INT_CTRL_INT_CONNECT |
251                         HDMI_HPD_INT_CTRL_INT_EN);
252
253         /* set timeout to 4.1ms (max) for hardware debounce */
254         spin_lock_irqsave(&hdmi->reg_lock, flags);
255         hpd_ctrl = hdmi_read(hdmi, REG_HDMI_HPD_CTRL);
256         hpd_ctrl |= HDMI_HPD_CTRL_TIMEOUT(0x1fff);
257
258         /* Toggle HPD circuit to trigger HPD sense */
259         hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
260                         ~HDMI_HPD_CTRL_ENABLE & hpd_ctrl);
261         hdmi_write(hdmi, REG_HDMI_HPD_CTRL,
262                         HDMI_HPD_CTRL_ENABLE | hpd_ctrl);
263         spin_unlock_irqrestore(&hdmi->reg_lock, flags);
264
265         return 0;
266
267 fail:
268         return ret;
269 }
270
271 static void hdp_disable(struct hdmi_connector *hdmi_connector)
272 {
273         struct hdmi *hdmi = hdmi_connector->hdmi;
274         const struct hdmi_platform_config *config = hdmi->config;
275         struct device *dev = &hdmi->pdev->dev;
276         int i, ret = 0;
277
278         /* Disable HPD interrupt */
279         hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0);
280
281         hdmi_set_mode(hdmi, false);
282
283         for (i = 0; i < config->hpd_clk_cnt; i++)
284                 clk_disable_unprepare(hdmi->hpd_clks[i]);
285
286         ret = gpio_config(hdmi, false);
287         if (ret)
288                 dev_warn(dev, "failed to unconfigure GPIOs: %d\n", ret);
289
290         ret = pinctrl_pm_select_sleep_state(dev);
291         if (ret)
292                 dev_warn(dev, "pinctrl state chg failed: %d\n", ret);
293
294         for (i = 0; i < config->hpd_reg_cnt; i++) {
295                 ret = regulator_disable(hdmi->hpd_regs[i]);
296                 if (ret)
297                         dev_warn(dev, "failed to disable hpd regulator: %s (%d)\n",
298                                         config->hpd_reg_names[i], ret);
299         }
300 }
301
302 static void
303 hotplug_work(struct work_struct *work)
304 {
305         struct hdmi_connector *hdmi_connector =
306                 container_of(work, struct hdmi_connector, hpd_work);
307         struct drm_connector *connector = &hdmi_connector->base;
308         drm_helper_hpd_irq_event(connector->dev);
309 }
310
311 void hdmi_connector_irq(struct drm_connector *connector)
312 {
313         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
314         struct hdmi *hdmi = hdmi_connector->hdmi;
315         uint32_t hpd_int_status, hpd_int_ctrl;
316
317         /* Process HPD: */
318         hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
319         hpd_int_ctrl   = hdmi_read(hdmi, REG_HDMI_HPD_INT_CTRL);
320
321         if ((hpd_int_ctrl & HDMI_HPD_INT_CTRL_INT_EN) &&
322                         (hpd_int_status & HDMI_HPD_INT_STATUS_INT)) {
323                 bool detected = !!(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED);
324
325                 /* ack & disable (temporarily) HPD events: */
326                 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
327                         HDMI_HPD_INT_CTRL_INT_ACK);
328
329                 DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl);
330
331                 /* detect disconnect if we are connected or visa versa: */
332                 hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN;
333                 if (!detected)
334                         hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
335                 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);
336
337                 queue_work(hdmi->workq, &hdmi_connector->hpd_work);
338         }
339 }
340
341 static enum drm_connector_status detect_reg(struct hdmi *hdmi)
342 {
343         uint32_t hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
344         return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ?
345                         connector_status_connected : connector_status_disconnected;
346 }
347
348 static enum drm_connector_status detect_gpio(struct hdmi *hdmi)
349 {
350         const struct hdmi_platform_config *config = hdmi->config;
351         return gpio_get_value(config->hpd_gpio) ?
352                         connector_status_connected :
353                         connector_status_disconnected;
354 }
355
356 static enum drm_connector_status hdmi_connector_detect(
357                 struct drm_connector *connector, bool force)
358 {
359         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
360         struct hdmi *hdmi = hdmi_connector->hdmi;
361         enum drm_connector_status stat_gpio, stat_reg;
362         int retry = 20;
363
364         do {
365                 stat_gpio = detect_gpio(hdmi);
366                 stat_reg  = detect_reg(hdmi);
367
368                 if (stat_gpio == stat_reg)
369                         break;
370
371                 mdelay(10);
372         } while (--retry);
373
374         /* the status we get from reading gpio seems to be more reliable,
375          * so trust that one the most if we didn't manage to get hdmi and
376          * gpio status to agree:
377          */
378         if (stat_gpio != stat_reg) {
379                 DBG("HDMI_HPD_INT_STATUS tells us: %d", stat_reg);
380                 DBG("hpd gpio tells us: %d", stat_gpio);
381         }
382
383         return stat_gpio;
384 }
385
386 static void hdmi_connector_destroy(struct drm_connector *connector)
387 {
388         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
389
390         hdp_disable(hdmi_connector);
391
392         drm_connector_unregister(connector);
393         drm_connector_cleanup(connector);
394
395         kfree(hdmi_connector);
396 }
397
398 static int hdmi_connector_get_modes(struct drm_connector *connector)
399 {
400         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
401         struct hdmi *hdmi = hdmi_connector->hdmi;
402         struct edid *edid;
403         uint32_t hdmi_ctrl;
404         int ret = 0;
405
406         hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL);
407         hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE);
408
409         edid = drm_get_edid(connector, hdmi->i2c);
410
411         hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
412
413         hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid);
414         drm_mode_connector_update_edid_property(connector, edid);
415
416         if (edid) {
417                 ret = drm_add_edid_modes(connector, edid);
418                 kfree(edid);
419         }
420
421         return ret;
422 }
423
424 static int hdmi_connector_mode_valid(struct drm_connector *connector,
425                                  struct drm_display_mode *mode)
426 {
427         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
428         struct hdmi *hdmi = hdmi_connector->hdmi;
429         const struct hdmi_platform_config *config = hdmi->config;
430         struct msm_drm_private *priv = connector->dev->dev_private;
431         struct msm_kms *kms = priv->kms;
432         long actual, requested;
433
434         requested = 1000 * mode->clock;
435         actual = kms->funcs->round_pixclk(kms,
436                         requested, hdmi_connector->hdmi->encoder);
437
438         /* for mdp5/apq8074, we manage our own pixel clk (as opposed to
439          * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
440          * instead):
441          */
442         if (config->pwr_clk_cnt > 0)
443                 actual = clk_round_rate(hdmi->pwr_clks[0], actual);
444
445         DBG("requested=%ld, actual=%ld", requested, actual);
446
447         if (actual != requested)
448                 return MODE_CLOCK_RANGE;
449
450         return 0;
451 }
452
453 static struct drm_encoder *
454 hdmi_connector_best_encoder(struct drm_connector *connector)
455 {
456         struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
457         return hdmi_connector->hdmi->encoder;
458 }
459
460 static const struct drm_connector_funcs hdmi_connector_funcs = {
461         .dpms = drm_atomic_helper_connector_dpms,
462         .detect = hdmi_connector_detect,
463         .fill_modes = drm_helper_probe_single_connector_modes,
464         .destroy = hdmi_connector_destroy,
465         .reset = drm_atomic_helper_connector_reset,
466         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
467         .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
468 };
469
470 static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
471         .get_modes = hdmi_connector_get_modes,
472         .mode_valid = hdmi_connector_mode_valid,
473         .best_encoder = hdmi_connector_best_encoder,
474 };
475
476 /* initialize connector */
477 struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
478 {
479         struct drm_connector *connector = NULL;
480         struct hdmi_connector *hdmi_connector;
481         int ret;
482
483         hdmi_connector = kzalloc(sizeof(*hdmi_connector), GFP_KERNEL);
484         if (!hdmi_connector) {
485                 ret = -ENOMEM;
486                 goto fail;
487         }
488
489         hdmi_connector->hdmi = hdmi;
490         INIT_WORK(&hdmi_connector->hpd_work, hotplug_work);
491
492         connector = &hdmi_connector->base;
493
494         drm_connector_init(hdmi->dev, connector, &hdmi_connector_funcs,
495                         DRM_MODE_CONNECTOR_HDMIA);
496         drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
497
498         connector->polled = DRM_CONNECTOR_POLL_CONNECT |
499                         DRM_CONNECTOR_POLL_DISCONNECT;
500
501         connector->interlace_allowed = 0;
502         connector->doublescan_allowed = 0;
503
504         drm_connector_register(connector);
505
506         ret = hpd_enable(hdmi_connector);
507         if (ret) {
508                 dev_err(&hdmi->pdev->dev, "failed to enable HPD: %d\n", ret);
509                 goto fail;
510         }
511
512         drm_mode_connector_attach_encoder(connector, hdmi->encoder);
513
514         return connector;
515
516 fail:
517         if (connector)
518                 hdmi_connector_destroy(connector);
519
520         return ERR_PTR(ret);
521 }