]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/gpu/drm/omapdrm/dss/hdmi5.c
drm: omapdrm: hdmi4: Allocate the omap_hdmi data structure dynamically
[mirror_ubuntu-jammy-kernel.git] / drivers / gpu / drm / omapdrm / dss / hdmi5.c
CommitLineData
f5bab222
TV
1/*
2 * HDMI driver for OMAP5
3 *
bb5cdf8d 4 * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
f5bab222
TV
5 *
6 * Authors:
7 * Yong Zhi
8 * Mythri pk
9 * Archit Taneja <archit@ti.com>
10 * Tomi Valkeinen <tomi.valkeinen@ti.com>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License version 2 as published by
14 * the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * this program. If not, see <http://www.gnu.org/licenses/>.
23 */
24
25#define DSS_SUBSYS_NAME "HDMI"
26
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/err.h>
30#include <linux/io.h>
31#include <linux/interrupt.h>
32#include <linux/mutex.h>
33#include <linux/delay.h>
34#include <linux/string.h>
35#include <linux/platform_device.h>
36#include <linux/pm_runtime.h>
37#include <linux/clk.h>
38#include <linux/gpio.h>
39#include <linux/regulator/consumer.h>
736e60dd 40#include <linux/component.h>
d9e32ecd 41#include <linux/of.h>
09bffa6e 42#include <linux/of_graph.h>
45302d7e 43#include <sound/omap-hdmi-audio.h>
f5bab222 44
32043da7 45#include "omapdss.h"
f5bab222
TV
46#include "hdmi5_core.h"
47#include "dss.h"
f5bab222 48
945514b5 49static struct omap_hdmi hdmi;
f5bab222
TV
50
51static int hdmi_runtime_get(void)
52{
53 int r;
54
55 DSSDBG("hdmi_runtime_get\n");
56
57 r = pm_runtime_get_sync(&hdmi.pdev->dev);
58 WARN_ON(r < 0);
59 if (r < 0)
60 return r;
61
62 return 0;
63}
64
65static void hdmi_runtime_put(void)
66{
67 int r;
68
69 DSSDBG("hdmi_runtime_put\n");
70
71 r = pm_runtime_put_sync(&hdmi.pdev->dev);
72 WARN_ON(r < 0 && r != -ENOSYS);
73}
74
75static irqreturn_t hdmi_irq_handler(int irq, void *data)
76{
77 struct hdmi_wp_data *wp = data;
78 u32 irqstatus;
79
80 irqstatus = hdmi_wp_get_irqstatus(wp);
81 hdmi_wp_set_irqstatus(wp, irqstatus);
82
83 if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
84 irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
85 u32 v;
86 /*
87 * If we get both connect and disconnect interrupts at the same
88 * time, turn off the PHY, clear interrupts, and restart, which
89 * raises connect interrupt if a cable is connected, or nothing
90 * if cable is not connected.
91 */
92
93 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
94
95 /*
96 * We always get bogus CONNECT & DISCONNECT interrupts when
97 * setting the PHY to LDOON. To ignore those, we force the RXDET
98 * line to 0 until the PHY power state has been changed.
99 */
100 v = hdmi_read_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL);
101 v = FLD_MOD(v, 1, 15, 15); /* FORCE_RXDET_HIGH */
102 v = FLD_MOD(v, 0, 14, 7); /* RXDET_LINE */
103 hdmi_write_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v);
104
105 hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
106 HDMI_IRQ_LINK_DISCONNECT);
107
108 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
109
110 REG_FLD_MOD(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15);
111
112 } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
113 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
114 } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
115 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
116 }
117
118 return IRQ_HANDLED;
119}
120
121static int hdmi_init_regulator(void)
122{
f5bab222
TV
123 struct regulator *reg;
124
125 if (hdmi.vdda_reg != NULL)
126 return 0;
127
128 reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
129 if (IS_ERR(reg)) {
130 DSSERR("can't get VDDA regulator\n");
131 return PTR_ERR(reg);
132 }
133
f5bab222
TV
134 hdmi.vdda_reg = reg;
135
136 return 0;
137}
138
139static int hdmi_power_on_core(struct omap_dss_device *dssdev)
140{
141 int r;
142
143 r = regulator_enable(hdmi.vdda_reg);
144 if (r)
145 return r;
146
147 r = hdmi_runtime_get();
148 if (r)
149 goto err_runtime_get;
150
151 /* Make selection of HDMI in DSS */
8aea8e6a 152 dss_select_hdmi_venc_clk_source(hdmi.dss, DSS_HDMI_M_PCLK);
f5bab222
TV
153
154 hdmi.core_enabled = true;
155
156 return 0;
157
158err_runtime_get:
159 regulator_disable(hdmi.vdda_reg);
160
161 return r;
162}
163
164static void hdmi_power_off_core(struct omap_dss_device *dssdev)
165{
166 hdmi.core_enabled = false;
167
168 hdmi_runtime_put();
169 regulator_disable(hdmi.vdda_reg);
170}
171
172static int hdmi_power_on_full(struct omap_dss_device *dssdev)
173{
174 int r;
da11bbbb 175 struct videomode *vm;
c84c3a5b 176 struct dss_pll_clock_info hdmi_cinfo = { 0 };
d11e5c82 177 unsigned int pc;
f5bab222
TV
178
179 r = hdmi_power_on_core(dssdev);
180 if (r)
181 return r;
182
da11bbbb 183 vm = &hdmi.cfg.vm;
f5bab222 184
da11bbbb
PU
185 DSSDBG("hdmi_power_on hactive= %d vactive = %d\n", vm->hactive,
186 vm->vactive);
f5bab222 187
da11bbbb
PU
188 pc = vm->pixelclock;
189 if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
67d8ffdd
TV
190 pc *= 2;
191
c107751d
TV
192 /* DSS_HDMI_TCLK is bitclk / 10 */
193 pc *= 10;
194
c17dc0e3
TV
195 dss_pll_calc_b(&hdmi.pll.pll, clk_get_rate(hdmi.pll.pll.clkin),
196 pc, &hdmi_cinfo);
f5bab222
TV
197
198 /* disable and clear irqs */
199 hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
200 hdmi_wp_set_irqstatus(&hdmi.wp,
201 hdmi_wp_get_irqstatus(&hdmi.wp));
202
c84c3a5b 203 r = dss_pll_enable(&hdmi.pll.pll);
f5bab222 204 if (r) {
c2fbd061 205 DSSERR("Failed to enable PLL\n");
f5bab222
TV
206 goto err_pll_enable;
207 }
208
c84c3a5b 209 r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
c2fbd061
TV
210 if (r) {
211 DSSERR("Failed to configure PLL\n");
212 goto err_pll_cfg;
213 }
214
c84c3a5b
TV
215 r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
216 hdmi_cinfo.clkout[0]);
f5bab222
TV
217 if (r) {
218 DSSDBG("Failed to start PHY\n");
219 goto err_phy_cfg;
220 }
221
222 r = hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_LDOON);
223 if (r)
224 goto err_phy_pwr;
225
226 hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
227
f5bab222 228 /* tv size */
28d79f3e 229 dss_mgr_set_timings(&hdmi.output, vm);
f5bab222 230
28d79f3e 231 r = dss_mgr_enable(&hdmi.output);
f5bab222
TV
232 if (r)
233 goto err_mgr_enable;
234
4e4b53ce
TV
235 r = hdmi_wp_video_start(&hdmi.wp);
236 if (r)
237 goto err_vid_enable;
238
f5bab222
TV
239 hdmi_wp_set_irqenable(&hdmi.wp,
240 HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
241
242 return 0;
243
f5bab222 244err_vid_enable:
28d79f3e 245 dss_mgr_disable(&hdmi.output);
4e4b53ce 246err_mgr_enable:
f5bab222
TV
247 hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
248err_phy_pwr:
249err_phy_cfg:
c2fbd061 250err_pll_cfg:
c84c3a5b 251 dss_pll_disable(&hdmi.pll.pll);
f5bab222
TV
252err_pll_enable:
253 hdmi_power_off_core(dssdev);
254 return -EIO;
255}
256
257static void hdmi_power_off_full(struct omap_dss_device *dssdev)
258{
f5bab222
TV
259 hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
260
f5bab222
TV
261 hdmi_wp_video_stop(&hdmi.wp);
262
28d79f3e 263 dss_mgr_disable(&hdmi.output);
4e4b53ce 264
f5bab222
TV
265 hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
266
c84c3a5b 267 dss_pll_disable(&hdmi.pll.pll);
f5bab222
TV
268
269 hdmi_power_off_core(dssdev);
270}
271
272static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
da11bbbb 273 struct videomode *vm)
f5bab222 274{
8a7eda76 275 if (!dispc_mgr_timings_ok(hdmi.dss->dispc, dssdev->dispc_channel, vm))
f5bab222
TV
276 return -EINVAL;
277
278 return 0;
279}
280
281static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
da11bbbb 282 struct videomode *vm)
f5bab222 283{
f5bab222
TV
284 mutex_lock(&hdmi.lock);
285
da11bbbb 286 hdmi.cfg.vm = *vm;
f5bab222 287
8a7eda76 288 dispc_set_tv_pclk(hdmi.dss->dispc, vm->pixelclock);
f5bab222
TV
289
290 mutex_unlock(&hdmi.lock);
291}
292
293static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
da11bbbb 294 struct videomode *vm)
f5bab222 295{
da11bbbb 296 *vm = hdmi.cfg.vm;
f5bab222
TV
297}
298
f33656e1 299static int hdmi_dump_regs(struct seq_file *s, void *p)
f5bab222
TV
300{
301 mutex_lock(&hdmi.lock);
302
303 if (hdmi_runtime_get()) {
304 mutex_unlock(&hdmi.lock);
f33656e1 305 return 0;
f5bab222
TV
306 }
307
308 hdmi_wp_dump(&hdmi.wp, s);
309 hdmi_pll_dump(&hdmi.pll, s);
310 hdmi_phy_dump(&hdmi.phy, s);
311 hdmi5_core_dump(&hdmi.core, s);
312
313 hdmi_runtime_put();
314 mutex_unlock(&hdmi.lock);
f33656e1 315 return 0;
f5bab222
TV
316}
317
318static int read_edid(u8 *buf, int len)
319{
320 int r;
321 int idlemode;
322
323 mutex_lock(&hdmi.lock);
324
325 r = hdmi_runtime_get();
326 BUG_ON(r);
327
328 idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
329 /* No-idle mode */
330 REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
331
332 r = hdmi5_read_edid(&hdmi.core, buf, len);
333
334 REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2);
335
336 hdmi_runtime_put();
337 mutex_unlock(&hdmi.lock);
338
339 return r;
340}
341
8a9d4626
JS
342static void hdmi_start_audio_stream(struct omap_hdmi *hd)
343{
344 REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
345 hdmi_wp_audio_enable(&hd->wp, true);
346 hdmi_wp_audio_core_req_enable(&hd->wp, true);
347}
348
349static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
350{
351 hdmi_wp_audio_core_req_enable(&hd->wp, false);
352 hdmi_wp_audio_enable(&hd->wp, false);
353 REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
354}
355
f5bab222
TV
356static int hdmi_display_enable(struct omap_dss_device *dssdev)
357{
358 struct omap_dss_device *out = &hdmi.output;
8a9d4626 359 unsigned long flags;
f5bab222
TV
360 int r = 0;
361
362 DSSDBG("ENTER hdmi_display_enable\n");
363
364 mutex_lock(&hdmi.lock);
365
f1504ad0 366 if (!out->dispc_channel_connected) {
f5bab222
TV
367 DSSERR("failed to enable display: no output/manager\n");
368 r = -ENODEV;
369 goto err0;
370 }
371
372 r = hdmi_power_on_full(dssdev);
373 if (r) {
374 DSSERR("failed to power on device\n");
375 goto err0;
376 }
377
8a9d4626
JS
378 if (hdmi.audio_configured) {
379 r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config,
da11bbbb 380 hdmi.cfg.vm.pixelclock);
8a9d4626
JS
381 if (r) {
382 DSSERR("Error restoring audio configuration: %d", r);
383 hdmi.audio_abort_cb(&hdmi.pdev->dev);
384 hdmi.audio_configured = false;
385 }
386 }
387
388 spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
389 if (hdmi.audio_configured && hdmi.audio_playing)
390 hdmi_start_audio_stream(&hdmi);
45302d7e 391 hdmi.display_enabled = true;
8a9d4626 392 spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
45302d7e 393
f5bab222
TV
394 mutex_unlock(&hdmi.lock);
395 return 0;
396
397err0:
398 mutex_unlock(&hdmi.lock);
399 return r;
400}
401
402static void hdmi_display_disable(struct omap_dss_device *dssdev)
403{
8a9d4626
JS
404 unsigned long flags;
405
f5bab222
TV
406 DSSDBG("Enter hdmi_display_disable\n");
407
408 mutex_lock(&hdmi.lock);
409
8a9d4626
JS
410 spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
411 hdmi_stop_audio_stream(&hdmi);
412 hdmi.display_enabled = false;
413 spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
45302d7e 414
f5bab222
TV
415 hdmi_power_off_full(dssdev);
416
417 mutex_unlock(&hdmi.lock);
418}
419
420static int hdmi_core_enable(struct omap_dss_device *dssdev)
421{
422 int r = 0;
423
424 DSSDBG("ENTER omapdss_hdmi_core_enable\n");
425
426 mutex_lock(&hdmi.lock);
427
428 r = hdmi_power_on_core(dssdev);
429 if (r) {
430 DSSERR("failed to power on device\n");
431 goto err0;
432 }
433
434 mutex_unlock(&hdmi.lock);
435 return 0;
436
437err0:
438 mutex_unlock(&hdmi.lock);
439 return r;
440}
441
442static void hdmi_core_disable(struct omap_dss_device *dssdev)
443{
444 DSSDBG("Enter omapdss_hdmi_core_disable\n");
445
446 mutex_lock(&hdmi.lock);
447
448 hdmi_power_off_core(dssdev);
449
450 mutex_unlock(&hdmi.lock);
451}
452
f5bab222
TV
453static int hdmi_connect(struct omap_dss_device *dssdev,
454 struct omap_dss_device *dst)
455{
f5bab222
TV
456 int r;
457
458 r = hdmi_init_regulator();
459 if (r)
460 return r;
461
28d79f3e 462 r = dss_mgr_connect(&hdmi.output, dssdev);
f5bab222
TV
463 if (r)
464 return r;
465
466 r = omapdss_output_set_device(dssdev, dst);
467 if (r) {
468 DSSERR("failed to connect output to new device: %s\n",
469 dst->name);
28d79f3e 470 dss_mgr_disconnect(&hdmi.output, dssdev);
f5bab222
TV
471 return r;
472 }
473
474 return 0;
475}
476
477static void hdmi_disconnect(struct omap_dss_device *dssdev,
478 struct omap_dss_device *dst)
479{
480 WARN_ON(dst != dssdev->dst);
481
482 if (dst != dssdev->dst)
483 return;
484
485 omapdss_output_unset_device(dssdev);
486
28d79f3e 487 dss_mgr_disconnect(&hdmi.output, dssdev);
f5bab222
TV
488}
489
490static int hdmi_read_edid(struct omap_dss_device *dssdev,
491 u8 *edid, int len)
492{
493 bool need_enable;
494 int r;
495
496 need_enable = hdmi.core_enabled == false;
497
498 if (need_enable) {
499 r = hdmi_core_enable(dssdev);
500 if (r)
501 return r;
502 }
503
504 r = read_edid(edid, len);
505
506 if (need_enable)
507 hdmi_core_disable(dssdev);
508
509 return r;
510}
511
769dcb11
TV
512static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
513 const struct hdmi_avi_infoframe *avi)
514{
515 hdmi.cfg.infoframe = *avi;
516 return 0;
517}
518
519static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
520 bool hdmi_mode)
521{
522 hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
523 return 0;
524}
525
f5bab222
TV
526static const struct omapdss_hdmi_ops hdmi_ops = {
527 .connect = hdmi_connect,
528 .disconnect = hdmi_disconnect,
529
530 .enable = hdmi_display_enable,
531 .disable = hdmi_display_disable,
532
533 .check_timings = hdmi_display_check_timing,
534 .set_timings = hdmi_display_set_timing,
535 .get_timings = hdmi_display_get_timings,
536
537 .read_edid = hdmi_read_edid,
769dcb11
TV
538 .set_infoframe = hdmi_set_infoframe,
539 .set_hdmi_mode = hdmi_set_hdmi_mode,
f5bab222
TV
540};
541
542static void hdmi_init_output(struct platform_device *pdev)
543{
544 struct omap_dss_device *out = &hdmi.output;
545
546 out->dev = &pdev->dev;
547 out->id = OMAP_DSS_OUTPUT_HDMI;
548 out->output_type = OMAP_DISPLAY_TYPE_HDMI;
549 out->name = "hdmi.0";
550 out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
551 out->ops.hdmi = &hdmi_ops;
552 out->owner = THIS_MODULE;
553
554 omapdss_register_output(out);
555}
556
39c1b7bf 557static void hdmi_uninit_output(struct platform_device *pdev)
f5bab222
TV
558{
559 struct omap_dss_device *out = &hdmi.output;
560
561 omapdss_unregister_output(out);
562}
563
564static int hdmi_probe_of(struct platform_device *pdev)
565{
566 struct device_node *node = pdev->dev.of_node;
567 struct device_node *ep;
568 int r;
569
09bffa6e 570 ep = of_graph_get_endpoint_by_regs(node, 0, 0);
f5bab222
TV
571 if (!ep)
572 return 0;
573
574 r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy);
575 if (r)
576 goto err;
577
578 of_node_put(ep);
579 return 0;
580
581err:
582 of_node_put(ep);
583 return r;
584}
585
45302d7e
JS
586/* Audio callbacks */
587static int hdmi_audio_startup(struct device *dev,
588 void (*abort_cb)(struct device *dev))
589{
590 struct omap_hdmi *hd = dev_get_drvdata(dev);
591 int ret = 0;
592
593 mutex_lock(&hd->lock);
594
595 if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
596 ret = -EPERM;
597 goto out;
598 }
599
600 hd->audio_abort_cb = abort_cb;
601
602out:
603 mutex_unlock(&hd->lock);
604
605 return ret;
606}
607
608static int hdmi_audio_shutdown(struct device *dev)
609{
610 struct omap_hdmi *hd = dev_get_drvdata(dev);
611
612 mutex_lock(&hd->lock);
613 hd->audio_abort_cb = NULL;
8a9d4626
JS
614 hd->audio_configured = false;
615 hd->audio_playing = false;
45302d7e
JS
616 mutex_unlock(&hd->lock);
617
618 return 0;
619}
620
621static int hdmi_audio_start(struct device *dev)
622{
623 struct omap_hdmi *hd = dev_get_drvdata(dev);
8a9d4626 624 unsigned long flags;
45302d7e
JS
625
626 WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
45302d7e 627
8a9d4626 628 spin_lock_irqsave(&hd->audio_playing_lock, flags);
2d7639bc 629
8a9d4626
JS
630 if (hd->display_enabled)
631 hdmi_start_audio_stream(hd);
632 hd->audio_playing = true;
45302d7e 633
8a9d4626 634 spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
45302d7e
JS
635 return 0;
636}
637
638static void hdmi_audio_stop(struct device *dev)
639{
640 struct omap_hdmi *hd = dev_get_drvdata(dev);
8a9d4626 641 unsigned long flags;
45302d7e
JS
642
643 WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
45302d7e 644
8a9d4626
JS
645 spin_lock_irqsave(&hd->audio_playing_lock, flags);
646
647 if (hd->display_enabled)
648 hdmi_stop_audio_stream(hd);
649 hd->audio_playing = false;
2d7639bc 650
8a9d4626 651 spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
45302d7e
JS
652}
653
654static int hdmi_audio_config(struct device *dev,
655 struct omap_dss_audio *dss_audio)
656{
657 struct omap_hdmi *hd = dev_get_drvdata(dev);
658 int ret;
659
660 mutex_lock(&hd->lock);
661
662 if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
663 ret = -EPERM;
664 goto out;
665 }
666
667 ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
da11bbbb 668 hd->cfg.vm.pixelclock);
45302d7e 669
8a9d4626
JS
670 if (!ret) {
671 hd->audio_configured = true;
672 hd->audio_config = *dss_audio;
673 }
45302d7e
JS
674out:
675 mutex_unlock(&hd->lock);
676
677 return ret;
678}
679
680static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
681 .audio_startup = hdmi_audio_startup,
682 .audio_shutdown = hdmi_audio_shutdown,
683 .audio_start = hdmi_audio_start,
684 .audio_stop = hdmi_audio_stop,
685 .audio_config = hdmi_audio_config,
686};
687
688static int hdmi_audio_register(struct device *dev)
689{
690 struct omap_hdmi_audio_pdata pdata = {
691 .dev = dev,
d20fa5a0 692 .version = 5,
45302d7e
JS
693 .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
694 .ops = &hdmi_audio_ops,
695 };
696
697 hdmi.audio_pdev = platform_device_register_data(
698 dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
699 &pdata, sizeof(pdata));
700
701 if (IS_ERR(hdmi.audio_pdev))
702 return PTR_ERR(hdmi.audio_pdev);
703
8a9d4626
JS
704 hdmi_runtime_get();
705 hdmi.wp_idlemode =
706 REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
707 hdmi_runtime_put();
708
45302d7e
JS
709 return 0;
710}
711
f5bab222 712/* HDMI HW IP initialisation */
736e60dd 713static int hdmi5_bind(struct device *dev, struct device *master, void *data)
f5bab222 714{
736e60dd 715 struct platform_device *pdev = to_platform_device(dev);
7b295257 716 struct dss_device *dss = dss_get_device(master);
f5bab222
TV
717 int r;
718 int irq;
719
720 hdmi.pdev = pdev;
8aea8e6a 721 hdmi.dss = dss;
945514b5 722 dev_set_drvdata(&pdev->dev, &hdmi);
f5bab222
TV
723
724 mutex_init(&hdmi.lock);
8a9d4626 725 spin_lock_init(&hdmi.audio_playing_lock);
f5bab222 726
1dff212c
LP
727 r = hdmi_probe_of(pdev);
728 if (r)
729 return r;
f5bab222 730
fe16bc51 731 r = hdmi_wp_init(pdev, &hdmi.wp, 5);
f5bab222
TV
732 if (r)
733 return r;
734
7b295257 735 r = hdmi_pll_init(dss, pdev, &hdmi.pll, &hdmi.wp);
f5bab222
TV
736 if (r)
737 return r;
738
37ea27b9 739 r = hdmi_phy_init(pdev, &hdmi.phy, 5);
f5bab222 740 if (r)
c84c3a5b 741 goto err;
f5bab222
TV
742
743 r = hdmi5_core_init(pdev, &hdmi.core);
744 if (r)
c84c3a5b 745 goto err;
f5bab222
TV
746
747 irq = platform_get_irq(pdev, 0);
748 if (irq < 0) {
749 DSSERR("platform_get_irq failed\n");
c84c3a5b
TV
750 r = -ENODEV;
751 goto err;
f5bab222
TV
752 }
753
754 r = devm_request_threaded_irq(&pdev->dev, irq,
755 NULL, hdmi_irq_handler,
756 IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
757 if (r) {
758 DSSERR("HDMI IRQ request failed\n");
c84c3a5b 759 goto err;
f5bab222
TV
760 }
761
762 pm_runtime_enable(&pdev->dev);
763
764 hdmi_init_output(pdev);
765
45302d7e
JS
766 r = hdmi_audio_register(&pdev->dev);
767 if (r) {
768 DSSERR("Registering HDMI audio failed %d\n", r);
769 hdmi_uninit_output(pdev);
770 pm_runtime_disable(&pdev->dev);
771 return r;
772 }
773
1c4b92ee
LP
774 hdmi.debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
775 &hdmi);
f5bab222
TV
776
777 return 0;
c84c3a5b
TV
778err:
779 hdmi_pll_uninit(&hdmi.pll);
780 return r;
f5bab222
TV
781}
782
736e60dd 783static void hdmi5_unbind(struct device *dev, struct device *master, void *data)
f5bab222 784{
736e60dd
TV
785 struct platform_device *pdev = to_platform_device(dev);
786
f33656e1
LP
787 dss_debugfs_remove_file(hdmi.debugfs);
788
45302d7e
JS
789 if (hdmi.audio_pdev)
790 platform_device_unregister(hdmi.audio_pdev);
791
f5bab222
TV
792 hdmi_uninit_output(pdev);
793
c84c3a5b
TV
794 hdmi_pll_uninit(&hdmi.pll);
795
f5bab222 796 pm_runtime_disable(&pdev->dev);
736e60dd
TV
797}
798
799static const struct component_ops hdmi5_component_ops = {
800 .bind = hdmi5_bind,
801 .unbind = hdmi5_unbind,
802};
f5bab222 803
736e60dd
TV
804static int hdmi5_probe(struct platform_device *pdev)
805{
806 return component_add(&pdev->dev, &hdmi5_component_ops);
807}
808
809static int hdmi5_remove(struct platform_device *pdev)
810{
811 component_del(&pdev->dev, &hdmi5_component_ops);
f5bab222
TV
812 return 0;
813}
814
815static int hdmi_runtime_suspend(struct device *dev)
816{
50638ae5
LP
817 struct omap_hdmi *hdmi = dev_get_drvdata(dev);
818
819 dispc_runtime_put(hdmi->dss->dispc);
f5bab222
TV
820
821 return 0;
822}
823
824static int hdmi_runtime_resume(struct device *dev)
825{
50638ae5 826 struct omap_hdmi *hdmi = dev_get_drvdata(dev);
f5bab222
TV
827 int r;
828
50638ae5 829 r = dispc_runtime_get(hdmi->dss->dispc);
f5bab222
TV
830 if (r < 0)
831 return r;
832
f5bab222
TV
833 return 0;
834}
835
836static const struct dev_pm_ops hdmi_pm_ops = {
837 .runtime_suspend = hdmi_runtime_suspend,
838 .runtime_resume = hdmi_runtime_resume,
839};
840
841static const struct of_device_id hdmi_of_match[] = {
842 { .compatible = "ti,omap5-hdmi", },
adb5ff83 843 { .compatible = "ti,dra7-hdmi", },
f5bab222
TV
844 {},
845};
846
d66c36a3 847struct platform_driver omapdss_hdmi5hw_driver = {
736e60dd
TV
848 .probe = hdmi5_probe,
849 .remove = hdmi5_remove,
f5bab222
TV
850 .driver = {
851 .name = "omapdss_hdmi5",
f5bab222
TV
852 .pm = &hdmi_pm_ops,
853 .of_match_table = hdmi_of_match,
422ccbd5 854 .suppress_bind_attrs = true,
f5bab222
TV
855 },
856};