diff options
author | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2012-05-11 08:38:23 -0400 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2012-05-11 08:38:23 -0400 |
commit | 037983e61b61e82fa28fea38d02e354d74c66bab (patch) | |
tree | 8d502829f3b27b5d8b587fb965919260d832497a | |
parent | 38137c8f0ce8dfaea467884cb2eb45de8df1bdfc (diff) | |
parent | f3a97491f2c54e5239663f8f147b34c280cf7db5 (diff) |
Merge branch 'omapdss-hdmi-audio'
Merge OMAP DSS HDMI audio patches from Ricardo Neri
-rw-r--r-- | Documentation/arm/OMAP/DSS | 45 | ||||
-rw-r--r-- | drivers/video/omap2/dss/Kconfig | 4 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss.h | 8 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss_features.c | 8 | ||||
-rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 359 | ||||
-rw-r--r-- | drivers/video/omap2/dss/hdmi_panel.c | 236 | ||||
-rw-r--r-- | drivers/video/omap2/dss/ti_hdmi.h | 32 | ||||
-rw-r--r-- | drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | 316 | ||||
-rw-r--r-- | drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h | 104 | ||||
-rw-r--r-- | include/video/omapdss.h | 34 |
10 files changed, 710 insertions, 436 deletions
diff --git a/Documentation/arm/OMAP/DSS b/Documentation/arm/OMAP/DSS index d0aea9192204..a564ceea9e98 100644 --- a/Documentation/arm/OMAP/DSS +++ b/Documentation/arm/OMAP/DSS | |||
@@ -47,6 +47,51 @@ flexible way to enable non-common multi-display configuration. In addition to | |||
47 | modelling the hardware overlays, omapdss supports virtual overlays and overlay | 47 | modelling the hardware overlays, omapdss supports virtual overlays and overlay |
48 | managers. These can be used when updating a display with CPU or system DMA. | 48 | managers. These can be used when updating a display with CPU or system DMA. |
49 | 49 | ||
50 | omapdss driver support for audio | ||
51 | -------------------------------- | ||
52 | There exist several display technologies and standards that support audio as | ||
53 | well. Hence, it is relevant to update the DSS device driver to provide an audio | ||
54 | interface that may be used by an audio driver or any other driver interested in | ||
55 | the functionality. | ||
56 | |||
57 | The audio_enable function is intended to prepare the relevant | ||
58 | IP for playback (e.g., enabling an audio FIFO, taking in/out of reset | ||
59 | some IP, enabling companion chips, etc). It is intended to be called before | ||
60 | audio_start. The audio_disable function performs the reverse operation and is | ||
61 | intended to be called after audio_stop. | ||
62 | |||
63 | While a given DSS device driver may support audio, it is possible that for | ||
64 | certain configurations audio is not supported (e.g., an HDMI display using a | ||
65 | VESA video timing). The audio_supported function is intended to query whether | ||
66 | the current configuration of the display supports audio. | ||
67 | |||
68 | The audio_config function is intended to configure all the relevant audio | ||
69 | parameters of the display. In order to make the function independent of any | ||
70 | specific DSS device driver, a struct omap_dss_audio is defined. Its purpose | ||
71 | is to contain all the required parameters for audio configuration. At the | ||
72 | moment, such structure contains pointers to IEC-60958 channel status word | ||
73 | and CEA-861 audio infoframe structures. This should be enough to support | ||
74 | HDMI and DisplayPort, as both are based on CEA-861 and IEC-60958. | ||
75 | |||
76 | The audio_enable/disable, audio_config and audio_supported functions could be | ||
77 | implemented as functions that may sleep. Hence, they should not be called | ||
78 | while holding a spinlock or a readlock. | ||
79 | |||
80 | The audio_start/audio_stop function is intended to effectively start/stop audio | ||
81 | playback after the configuration has taken place. These functions are designed | ||
82 | to be used in an atomic context. Hence, audio_start should return quickly and be | ||
83 | called only after all the needed resources for audio playback (audio FIFOs, | ||
84 | DMA channels, companion chips, etc) have been enabled to begin data transfers. | ||
85 | audio_stop is designed to only stop the audio transfers. The resources used | ||
86 | for playback are released using audio_disable. | ||
87 | |||
88 | The enum omap_dss_audio_state may be used to help the implementations of | ||
89 | the interface to keep track of the audio state. The initial state is _DISABLED; | ||
90 | then, the state transitions to _CONFIGURED, and then, when it is ready to | ||
91 | play audio, to _ENABLED. The state _PLAYING is used when the audio is being | ||
92 | rendered. | ||
93 | |||
94 | |||
50 | Panel and controller drivers | 95 | Panel and controller drivers |
51 | ---------------------------- | 96 | ---------------------------- |
52 | 97 | ||
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index 9aaf3246f821..43324e5ed25f 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig | |||
@@ -68,6 +68,10 @@ config OMAP4_DSS_HDMI | |||
68 | HDMI Interface. This adds the High Definition Multimedia Interface. | 68 | HDMI Interface. This adds the High Definition Multimedia Interface. |
69 | See http://www.hdmi.org/ for HDMI specification. | 69 | See http://www.hdmi.org/ for HDMI specification. |
70 | 70 | ||
71 | config OMAP4_DSS_HDMI_AUDIO | ||
72 | bool | ||
73 | depends on OMAP4_DSS_HDMI | ||
74 | |||
71 | config OMAP2_DSS_SDI | 75 | config OMAP2_DSS_SDI |
72 | bool "SDI support" | 76 | bool "SDI support" |
73 | depends on ARCH_OMAP3 | 77 | depends on ARCH_OMAP3 |
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index d5cb19fe7e8b..4aa9529a4768 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h | |||
@@ -464,6 +464,14 @@ int omapdss_hdmi_read_edid(u8 *buf, int len); | |||
464 | bool omapdss_hdmi_detect(void); | 464 | bool omapdss_hdmi_detect(void); |
465 | int hdmi_panel_init(void); | 465 | int hdmi_panel_init(void); |
466 | void hdmi_panel_exit(void); | 466 | void hdmi_panel_exit(void); |
467 | #ifdef CONFIG_OMAP4_DSS_HDMI_AUDIO | ||
468 | int hdmi_audio_enable(void); | ||
469 | void hdmi_audio_disable(void); | ||
470 | int hdmi_audio_start(void); | ||
471 | void hdmi_audio_stop(void); | ||
472 | bool hdmi_mode_has_audio(void); | ||
473 | int hdmi_audio_config(struct omap_dss_audio *audio); | ||
474 | #endif | ||
467 | 475 | ||
468 | /* RFBI */ | 476 | /* RFBI */ |
469 | int rfbi_init_platform_driver(void) __init; | 477 | int rfbi_init_platform_driver(void) __init; |
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 1d10a014bc55..2627441731b1 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c | |||
@@ -568,13 +568,17 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { | |||
568 | .pll_enable = ti_hdmi_4xxx_pll_enable, | 568 | .pll_enable = ti_hdmi_4xxx_pll_enable, |
569 | .pll_disable = ti_hdmi_4xxx_pll_disable, | 569 | .pll_disable = ti_hdmi_4xxx_pll_disable, |
570 | .video_enable = ti_hdmi_4xxx_wp_video_start, | 570 | .video_enable = ti_hdmi_4xxx_wp_video_start, |
571 | .video_disable = ti_hdmi_4xxx_wp_video_stop, | ||
571 | .dump_wrapper = ti_hdmi_4xxx_wp_dump, | 572 | .dump_wrapper = ti_hdmi_4xxx_wp_dump, |
572 | .dump_core = ti_hdmi_4xxx_core_dump, | 573 | .dump_core = ti_hdmi_4xxx_core_dump, |
573 | .dump_pll = ti_hdmi_4xxx_pll_dump, | 574 | .dump_pll = ti_hdmi_4xxx_pll_dump, |
574 | .dump_phy = ti_hdmi_4xxx_phy_dump, | 575 | .dump_phy = ti_hdmi_4xxx_phy_dump, |
575 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 576 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) |
576 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
577 | .audio_enable = ti_hdmi_4xxx_wp_audio_enable, | 577 | .audio_enable = ti_hdmi_4xxx_wp_audio_enable, |
578 | .audio_disable = ti_hdmi_4xxx_wp_audio_disable, | ||
579 | .audio_start = ti_hdmi_4xxx_audio_start, | ||
580 | .audio_stop = ti_hdmi_4xxx_audio_stop, | ||
581 | .audio_config = ti_hdmi_4xxx_audio_config, | ||
578 | #endif | 582 | #endif |
579 | 583 | ||
580 | }; | 584 | }; |
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 5f2e2f677bef..8195c7166d20 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c | |||
@@ -33,12 +33,6 @@ | |||
33 | #include <linux/pm_runtime.h> | 33 | #include <linux/pm_runtime.h> |
34 | #include <linux/clk.h> | 34 | #include <linux/clk.h> |
35 | #include <video/omapdss.h> | 35 | #include <video/omapdss.h> |
36 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
37 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
38 | #include <sound/soc.h> | ||
39 | #include <sound/pcm_params.h> | ||
40 | #include "ti_hdmi_4xxx_ip.h" | ||
41 | #endif | ||
42 | 36 | ||
43 | #include "ti_hdmi.h" | 37 | #include "ti_hdmi.h" |
44 | #include "dss.h" | 38 | #include "dss.h" |
@@ -324,7 +318,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
324 | 318 | ||
325 | hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); | 319 | hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); |
326 | 320 | ||
327 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); | 321 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); |
328 | 322 | ||
329 | /* config the PLL and PHY hdmi_set_pll_pwrfirst */ | 323 | /* config the PLL and PHY hdmi_set_pll_pwrfirst */ |
330 | r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); | 324 | r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); |
@@ -358,7 +352,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
358 | /* tv size */ | 352 | /* tv size */ |
359 | dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); | 353 | dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); |
360 | 354 | ||
361 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1); | 355 | r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data); |
356 | if (r) | ||
357 | goto err_vid_enable; | ||
362 | 358 | ||
363 | r = dss_mgr_enable(dssdev->manager); | 359 | r = dss_mgr_enable(dssdev->manager); |
364 | if (r) | 360 | if (r) |
@@ -367,7 +363,8 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
367 | return 0; | 363 | return 0; |
368 | 364 | ||
369 | err_mgr_enable: | 365 | err_mgr_enable: |
370 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); | 366 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); |
367 | err_vid_enable: | ||
371 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | 368 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); |
372 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | 369 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); |
373 | err: | 370 | err: |
@@ -379,7 +376,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev) | |||
379 | { | 376 | { |
380 | dss_mgr_disable(dssdev->manager); | 377 | dss_mgr_disable(dssdev->manager); |
381 | 378 | ||
382 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); | 379 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); |
383 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | 380 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); |
384 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | 381 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); |
385 | hdmi_runtime_put(); | 382 | hdmi_runtime_put(); |
@@ -536,241 +533,171 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) | |||
536 | mutex_unlock(&hdmi.lock); | 533 | mutex_unlock(&hdmi.lock); |
537 | } | 534 | } |
538 | 535 | ||
539 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 536 | static int hdmi_get_clocks(struct platform_device *pdev) |
540 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
541 | |||
542 | static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, | ||
543 | struct snd_soc_dai *dai) | ||
544 | { | 537 | { |
545 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 538 | struct clk *clk; |
546 | struct snd_soc_codec *codec = rtd->codec; | ||
547 | struct platform_device *pdev = to_platform_device(codec->dev); | ||
548 | struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec); | ||
549 | int err = 0; | ||
550 | 539 | ||
551 | if (!(ip_data->ops) && !(ip_data->ops->audio_enable)) { | 540 | clk = clk_get(&pdev->dev, "sys_clk"); |
552 | dev_err(&pdev->dev, "Cannot enable/disable audio\n"); | 541 | if (IS_ERR(clk)) { |
553 | return -ENODEV; | 542 | DSSERR("can't get sys_clk\n"); |
543 | return PTR_ERR(clk); | ||
554 | } | 544 | } |
555 | 545 | ||
556 | switch (cmd) { | 546 | hdmi.sys_clk = clk; |
557 | case SNDRV_PCM_TRIGGER_START: | 547 | |
558 | case SNDRV_PCM_TRIGGER_RESUME: | 548 | return 0; |
559 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 549 | } |
560 | ip_data->ops->audio_enable(ip_data, true); | 550 | |
561 | break; | 551 | static void hdmi_put_clocks(void) |
562 | case SNDRV_PCM_TRIGGER_STOP: | 552 | { |
563 | case SNDRV_PCM_TRIGGER_SUSPEND: | 553 | if (hdmi.sys_clk) |
564 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 554 | clk_put(hdmi.sys_clk); |
565 | ip_data->ops->audio_enable(ip_data, false); | 555 | } |
566 | break; | 556 | |
567 | default: | 557 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) |
568 | err = -EINVAL; | 558 | int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts) |
569 | } | 559 | { |
570 | return err; | 560 | u32 deep_color; |
571 | } | 561 | bool deep_color_correct = false; |
572 | 562 | u32 pclk = hdmi.ip_data.cfg.timings.pixel_clock; | |
573 | static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, | 563 | |
574 | struct snd_pcm_hw_params *params, | 564 | if (n == NULL || cts == NULL) |
575 | struct snd_soc_dai *dai) | ||
576 | { | ||
577 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
578 | struct snd_soc_codec *codec = rtd->codec; | ||
579 | struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec); | ||
580 | struct hdmi_audio_format audio_format; | ||
581 | struct hdmi_audio_dma audio_dma; | ||
582 | struct hdmi_core_audio_config core_cfg; | ||
583 | struct hdmi_core_infoframe_audio aud_if_cfg; | ||
584 | int err, n, cts; | ||
585 | enum hdmi_core_audio_sample_freq sample_freq; | ||
586 | |||
587 | switch (params_format(params)) { | ||
588 | case SNDRV_PCM_FORMAT_S16_LE: | ||
589 | core_cfg.i2s_cfg.word_max_length = | ||
590 | HDMI_AUDIO_I2S_MAX_WORD_20BITS; | ||
591 | core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_16_BITS; | ||
592 | core_cfg.i2s_cfg.in_length_bits = | ||
593 | HDMI_AUDIO_I2S_INPUT_LENGTH_16; | ||
594 | core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
595 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES; | ||
596 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS; | ||
597 | audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
598 | audio_dma.transfer_size = 0x10; | ||
599 | break; | ||
600 | case SNDRV_PCM_FORMAT_S24_LE: | ||
601 | core_cfg.i2s_cfg.word_max_length = | ||
602 | HDMI_AUDIO_I2S_MAX_WORD_24BITS; | ||
603 | core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_24_BITS; | ||
604 | core_cfg.i2s_cfg.in_length_bits = | ||
605 | HDMI_AUDIO_I2S_INPUT_LENGTH_24; | ||
606 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE; | ||
607 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS; | ||
608 | audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
609 | core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
610 | audio_dma.transfer_size = 0x20; | ||
611 | break; | ||
612 | default: | ||
613 | return -EINVAL; | 565 | return -EINVAL; |
614 | } | ||
615 | 566 | ||
616 | switch (params_rate(params)) { | 567 | /* TODO: When implemented, query deep color mode here. */ |
568 | deep_color = 100; | ||
569 | |||
570 | /* | ||
571 | * When using deep color, the default N value (as in the HDMI | ||
572 | * specification) yields to an non-integer CTS. Hence, we | ||
573 | * modify it while keeping the restrictions described in | ||
574 | * section 7.2.1 of the HDMI 1.4a specification. | ||
575 | */ | ||
576 | switch (sample_freq) { | ||
617 | case 32000: | 577 | case 32000: |
618 | sample_freq = HDMI_AUDIO_FS_32000; | 578 | case 48000: |
579 | case 96000: | ||
580 | case 192000: | ||
581 | if (deep_color == 125) | ||
582 | if (pclk == 27027 || pclk == 74250) | ||
583 | deep_color_correct = true; | ||
584 | if (deep_color == 150) | ||
585 | if (pclk == 27027) | ||
586 | deep_color_correct = true; | ||
619 | break; | 587 | break; |
620 | case 44100: | 588 | case 44100: |
621 | sample_freq = HDMI_AUDIO_FS_44100; | 589 | case 88200: |
622 | break; | 590 | case 176400: |
623 | case 48000: | 591 | if (deep_color == 125) |
624 | sample_freq = HDMI_AUDIO_FS_48000; | 592 | if (pclk == 27027) |
593 | deep_color_correct = true; | ||
625 | break; | 594 | break; |
626 | default: | 595 | default: |
627 | return -EINVAL; | 596 | return -EINVAL; |
628 | } | 597 | } |
629 | 598 | ||
630 | err = hdmi_config_audio_acr(ip_data, params_rate(params), &n, &cts); | 599 | if (deep_color_correct) { |
631 | if (err < 0) | 600 | switch (sample_freq) { |
632 | return err; | 601 | case 32000: |
633 | 602 | *n = 8192; | |
634 | /* Audio wrapper config */ | 603 | break; |
635 | audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL; | 604 | case 44100: |
636 | audio_format.active_chnnls_msk = 0x03; | 605 | *n = 12544; |
637 | audio_format.type = HDMI_AUDIO_TYPE_LPCM; | 606 | break; |
638 | audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST; | 607 | case 48000: |
639 | /* Disable start/stop signals of IEC 60958 blocks */ | 608 | *n = 8192; |
640 | audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF; | 609 | break; |
641 | 610 | case 88200: | |
642 | audio_dma.block_size = 0xC0; | 611 | *n = 25088; |
643 | audio_dma.mode = HDMI_AUDIO_TRANSF_DMA; | 612 | break; |
644 | audio_dma.fifo_threshold = 0x20; /* in number of samples */ | 613 | case 96000: |
645 | 614 | *n = 16384; | |
646 | hdmi_wp_audio_config_dma(ip_data, &audio_dma); | 615 | break; |
647 | hdmi_wp_audio_config_format(ip_data, &audio_format); | 616 | case 176400: |
648 | 617 | *n = 50176; | |
649 | /* | 618 | break; |
650 | * I2S config | 619 | case 192000: |
651 | */ | 620 | *n = 32768; |
652 | core_cfg.i2s_cfg.en_high_bitrate_aud = false; | 621 | break; |
653 | /* Only used with high bitrate audio */ | 622 | default: |
654 | core_cfg.i2s_cfg.cbit_order = false; | 623 | return -EINVAL; |
655 | /* Serial data and word select should change on sck rising edge */ | 624 | } |
656 | core_cfg.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING; | ||
657 | core_cfg.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM; | ||
658 | /* Set I2S word select polarity */ | ||
659 | core_cfg.i2s_cfg.ws_polarity = HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT; | ||
660 | core_cfg.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST; | ||
661 | /* Set serial data to word select shift. See Phillips spec. */ | ||
662 | core_cfg.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT; | ||
663 | /* Enable one of the four available serial data channels */ | ||
664 | core_cfg.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN; | ||
665 | |||
666 | /* Core audio config */ | ||
667 | core_cfg.freq_sample = sample_freq; | ||
668 | core_cfg.n = n; | ||
669 | core_cfg.cts = cts; | ||
670 | if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) { | ||
671 | core_cfg.aud_par_busclk = 0; | ||
672 | core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW; | ||
673 | core_cfg.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK); | ||
674 | } else { | 625 | } else { |
675 | core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8); | 626 | switch (sample_freq) { |
676 | core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW; | 627 | case 32000: |
677 | core_cfg.use_mclk = true; | 628 | *n = 4096; |
629 | break; | ||
630 | case 44100: | ||
631 | *n = 6272; | ||
632 | break; | ||
633 | case 48000: | ||
634 | *n = 6144; | ||
635 | break; | ||
636 | case 88200: | ||
637 | *n = 12544; | ||
638 | break; | ||
639 | case 96000: | ||
640 | *n = 12288; | ||
641 | break; | ||
642 | case 176400: | ||
643 | *n = 25088; | ||
644 | break; | ||
645 | case 192000: | ||
646 | *n = 24576; | ||
647 | break; | ||
648 | default: | ||
649 | return -EINVAL; | ||
650 | } | ||
678 | } | 651 | } |
652 | /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */ | ||
653 | *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10); | ||
679 | 654 | ||
680 | if (core_cfg.use_mclk) | ||
681 | core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS; | ||
682 | core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH; | ||
683 | core_cfg.en_spdif = false; | ||
684 | /* Use sample frequency from channel status word */ | ||
685 | core_cfg.fs_override = true; | ||
686 | /* Enable ACR packets */ | ||
687 | core_cfg.en_acr_pkt = true; | ||
688 | /* Disable direct streaming digital audio */ | ||
689 | core_cfg.en_dsd_audio = false; | ||
690 | /* Use parallel audio interface */ | ||
691 | core_cfg.en_parallel_aud_input = true; | ||
692 | |||
693 | hdmi_core_audio_config(ip_data, &core_cfg); | ||
694 | |||
695 | /* | ||
696 | * Configure packet | ||
697 | * info frame audio see doc CEA861-D page 74 | ||
698 | */ | ||
699 | aud_if_cfg.db1_coding_type = HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM; | ||
700 | aud_if_cfg.db1_channel_count = 2; | ||
701 | aud_if_cfg.db2_sample_freq = HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM; | ||
702 | aud_if_cfg.db2_sample_size = HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM; | ||
703 | aud_if_cfg.db4_channel_alloc = 0x00; | ||
704 | aud_if_cfg.db5_downmix_inh = false; | ||
705 | aud_if_cfg.db5_lsv = 0; | ||
706 | |||
707 | hdmi_core_audio_infoframe_config(ip_data, &aud_if_cfg); | ||
708 | return 0; | 655 | return 0; |
709 | } | 656 | } |
710 | 657 | ||
711 | static int hdmi_audio_startup(struct snd_pcm_substream *substream, | 658 | int hdmi_audio_enable(void) |
712 | struct snd_soc_dai *dai) | ||
713 | { | 659 | { |
714 | if (!hdmi.ip_data.cfg.cm.mode) { | 660 | DSSDBG("audio_enable\n"); |
715 | pr_err("Current video settings do not support audio.\n"); | 661 | |
716 | return -EIO; | 662 | return hdmi.ip_data.ops->audio_enable(&hdmi.ip_data); |
717 | } | ||
718 | return 0; | ||
719 | } | 663 | } |
720 | 664 | ||
721 | static int hdmi_audio_codec_probe(struct snd_soc_codec *codec) | 665 | void hdmi_audio_disable(void) |
722 | { | 666 | { |
723 | struct hdmi_ip_data *priv = &hdmi.ip_data; | 667 | DSSDBG("audio_disable\n"); |
724 | 668 | ||
725 | snd_soc_codec_set_drvdata(codec, priv); | 669 | hdmi.ip_data.ops->audio_disable(&hdmi.ip_data); |
726 | return 0; | ||
727 | } | 670 | } |
728 | 671 | ||
729 | static struct snd_soc_codec_driver hdmi_audio_codec_drv = { | 672 | int hdmi_audio_start(void) |
730 | .probe = hdmi_audio_codec_probe, | 673 | { |
731 | }; | 674 | DSSDBG("audio_start\n"); |
732 | |||
733 | static struct snd_soc_dai_ops hdmi_audio_codec_ops = { | ||
734 | .hw_params = hdmi_audio_hw_params, | ||
735 | .trigger = hdmi_audio_trigger, | ||
736 | .startup = hdmi_audio_startup, | ||
737 | }; | ||
738 | 675 | ||
739 | static struct snd_soc_dai_driver hdmi_codec_dai_drv = { | 676 | return hdmi.ip_data.ops->audio_start(&hdmi.ip_data); |
740 | .name = "hdmi-audio-codec", | 677 | } |
741 | .playback = { | ||
742 | .channels_min = 2, | ||
743 | .channels_max = 2, | ||
744 | .rates = SNDRV_PCM_RATE_32000 | | ||
745 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | ||
746 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
747 | SNDRV_PCM_FMTBIT_S24_LE, | ||
748 | }, | ||
749 | .ops = &hdmi_audio_codec_ops, | ||
750 | }; | ||
751 | #endif | ||
752 | 678 | ||
753 | static int hdmi_get_clocks(struct platform_device *pdev) | 679 | void hdmi_audio_stop(void) |
754 | { | 680 | { |
755 | struct clk *clk; | 681 | DSSDBG("audio_stop\n"); |
756 | 682 | ||
757 | clk = clk_get(&pdev->dev, "sys_clk"); | 683 | hdmi.ip_data.ops->audio_stop(&hdmi.ip_data); |
758 | if (IS_ERR(clk)) { | 684 | } |
759 | DSSERR("can't get sys_clk\n"); | ||
760 | return PTR_ERR(clk); | ||
761 | } | ||
762 | |||
763 | hdmi.sys_clk = clk; | ||
764 | 685 | ||
765 | return 0; | 686 | bool hdmi_mode_has_audio(void) |
687 | { | ||
688 | if (hdmi.ip_data.cfg.cm.mode == HDMI_HDMI) | ||
689 | return true; | ||
690 | else | ||
691 | return false; | ||
766 | } | 692 | } |
767 | 693 | ||
768 | static void hdmi_put_clocks(void) | 694 | int hdmi_audio_config(struct omap_dss_audio *audio) |
769 | { | 695 | { |
770 | if (hdmi.sys_clk) | 696 | return hdmi.ip_data.ops->audio_config(&hdmi.ip_data, audio); |
771 | clk_put(hdmi.sys_clk); | ||
772 | } | 697 | } |
773 | 698 | ||
699 | #endif | ||
700 | |||
774 | static void __init hdmi_probe_pdata(struct platform_device *pdev) | 701 | static void __init hdmi_probe_pdata(struct platform_device *pdev) |
775 | { | 702 | { |
776 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 703 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
@@ -838,17 +765,6 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | |||
838 | 765 | ||
839 | hdmi_probe_pdata(pdev); | 766 | hdmi_probe_pdata(pdev); |
840 | 767 | ||
841 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
842 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
843 | |||
844 | /* Register ASoC codec DAI */ | ||
845 | r = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv, | ||
846 | &hdmi_codec_dai_drv, 1); | ||
847 | if (r) { | ||
848 | DSSERR("can't register ASoC HDMI audio codec\n"); | ||
849 | return r; | ||
850 | } | ||
851 | #endif | ||
852 | return 0; | 768 | return 0; |
853 | } | 769 | } |
854 | 770 | ||
@@ -858,11 +774,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) | |||
858 | 774 | ||
859 | hdmi_panel_exit(); | 775 | hdmi_panel_exit(); |
860 | 776 | ||
861 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
862 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
863 | snd_soc_unregister_codec(&pdev->dev); | ||
864 | #endif | ||
865 | |||
866 | pm_runtime_disable(&pdev->dev); | 777 | pm_runtime_disable(&pdev->dev); |
867 | 778 | ||
868 | hdmi_put_clocks(); | 779 | hdmi_put_clocks(); |
diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c index 533d5dc634d2..1179e3c4b1c7 100644 --- a/drivers/video/omap2/dss/hdmi_panel.c +++ b/drivers/video/omap2/dss/hdmi_panel.c | |||
@@ -30,7 +30,12 @@ | |||
30 | #include "dss.h" | 30 | #include "dss.h" |
31 | 31 | ||
32 | static struct { | 32 | static struct { |
33 | struct mutex hdmi_lock; | 33 | /* This protects the panel ops, mainly when accessing the HDMI IP. */ |
34 | struct mutex lock; | ||
35 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
36 | /* This protects the audio ops, specifically. */ | ||
37 | spinlock_t audio_lock; | ||
38 | #endif | ||
34 | } hdmi; | 39 | } hdmi; |
35 | 40 | ||
36 | 41 | ||
@@ -54,12 +59,168 @@ static void hdmi_panel_remove(struct omap_dss_device *dssdev) | |||
54 | 59 | ||
55 | } | 60 | } |
56 | 61 | ||
62 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
63 | static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev) | ||
64 | { | ||
65 | unsigned long flags; | ||
66 | int r; | ||
67 | |||
68 | mutex_lock(&hdmi.lock); | ||
69 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
70 | |||
71 | /* enable audio only if the display is active and supports audio */ | ||
72 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || | ||
73 | !hdmi_mode_has_audio()) { | ||
74 | DSSERR("audio not supported or display is off\n"); | ||
75 | r = -EPERM; | ||
76 | goto err; | ||
77 | } | ||
78 | |||
79 | r = hdmi_audio_enable(); | ||
80 | |||
81 | if (!r) | ||
82 | dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED; | ||
83 | |||
84 | err: | ||
85 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
86 | mutex_unlock(&hdmi.lock); | ||
87 | return r; | ||
88 | } | ||
89 | |||
90 | static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev) | ||
91 | { | ||
92 | unsigned long flags; | ||
93 | |||
94 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
95 | |||
96 | hdmi_audio_disable(); | ||
97 | |||
98 | dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED; | ||
99 | |||
100 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
101 | } | ||
102 | |||
103 | static int hdmi_panel_audio_start(struct omap_dss_device *dssdev) | ||
104 | { | ||
105 | unsigned long flags; | ||
106 | int r; | ||
107 | |||
108 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
109 | /* | ||
110 | * No need to check the panel state. It was checked when trasitioning | ||
111 | * to AUDIO_ENABLED. | ||
112 | */ | ||
113 | if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED) { | ||
114 | DSSERR("audio start from invalid state\n"); | ||
115 | r = -EPERM; | ||
116 | goto err; | ||
117 | } | ||
118 | |||
119 | r = hdmi_audio_start(); | ||
120 | |||
121 | if (!r) | ||
122 | dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING; | ||
123 | |||
124 | err: | ||
125 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
126 | return r; | ||
127 | } | ||
128 | |||
129 | static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev) | ||
130 | { | ||
131 | unsigned long flags; | ||
132 | |||
133 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
134 | |||
135 | hdmi_audio_stop(); | ||
136 | dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED; | ||
137 | |||
138 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
139 | } | ||
140 | |||
141 | static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev) | ||
142 | { | ||
143 | bool r = false; | ||
144 | |||
145 | mutex_lock(&hdmi.lock); | ||
146 | |||
147 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
148 | goto err; | ||
149 | |||
150 | if (!hdmi_mode_has_audio()) | ||
151 | goto err; | ||
152 | |||
153 | r = true; | ||
154 | err: | ||
155 | mutex_unlock(&hdmi.lock); | ||
156 | return r; | ||
157 | } | ||
158 | |||
159 | static int hdmi_panel_audio_config(struct omap_dss_device *dssdev, | ||
160 | struct omap_dss_audio *audio) | ||
161 | { | ||
162 | unsigned long flags; | ||
163 | int r; | ||
164 | |||
165 | mutex_lock(&hdmi.lock); | ||
166 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
167 | |||
168 | /* config audio only if the display is active and supports audio */ | ||
169 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || | ||
170 | !hdmi_mode_has_audio()) { | ||
171 | DSSERR("audio not supported or display is off\n"); | ||
172 | r = -EPERM; | ||
173 | goto err; | ||
174 | } | ||
175 | |||
176 | r = hdmi_audio_config(audio); | ||
177 | |||
178 | if (!r) | ||
179 | dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED; | ||
180 | |||
181 | err: | ||
182 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
183 | mutex_unlock(&hdmi.lock); | ||
184 | return r; | ||
185 | } | ||
186 | |||
187 | #else | ||
188 | static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev) | ||
189 | { | ||
190 | return -EPERM; | ||
191 | } | ||
192 | |||
193 | static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev) | ||
194 | { | ||
195 | } | ||
196 | |||
197 | static int hdmi_panel_audio_start(struct omap_dss_device *dssdev) | ||
198 | { | ||
199 | return -EPERM; | ||
200 | } | ||
201 | |||
202 | static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev) | ||
203 | { | ||
204 | } | ||
205 | |||
206 | static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev) | ||
207 | { | ||
208 | return false; | ||
209 | } | ||
210 | |||
211 | static int hdmi_panel_audio_config(struct omap_dss_device *dssdev, | ||
212 | struct omap_dss_audio *audio) | ||
213 | { | ||
214 | return -EPERM; | ||
215 | } | ||
216 | #endif | ||
217 | |||
57 | static int hdmi_panel_enable(struct omap_dss_device *dssdev) | 218 | static int hdmi_panel_enable(struct omap_dss_device *dssdev) |
58 | { | 219 | { |
59 | int r = 0; | 220 | int r = 0; |
60 | DSSDBG("ENTER hdmi_panel_enable\n"); | 221 | DSSDBG("ENTER hdmi_panel_enable\n"); |
61 | 222 | ||
62 | mutex_lock(&hdmi.hdmi_lock); | 223 | mutex_lock(&hdmi.lock); |
63 | 224 | ||
64 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { | 225 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { |
65 | r = -EINVAL; | 226 | r = -EINVAL; |
@@ -75,40 +236,52 @@ static int hdmi_panel_enable(struct omap_dss_device *dssdev) | |||
75 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 236 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
76 | 237 | ||
77 | err: | 238 | err: |
78 | mutex_unlock(&hdmi.hdmi_lock); | 239 | mutex_unlock(&hdmi.lock); |
79 | 240 | ||
80 | return r; | 241 | return r; |
81 | } | 242 | } |
82 | 243 | ||
83 | static void hdmi_panel_disable(struct omap_dss_device *dssdev) | 244 | static void hdmi_panel_disable(struct omap_dss_device *dssdev) |
84 | { | 245 | { |
85 | mutex_lock(&hdmi.hdmi_lock); | 246 | mutex_lock(&hdmi.lock); |
86 | 247 | ||
87 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 248 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { |
249 | /* | ||
250 | * TODO: notify audio users that the display was disabled. For | ||
251 | * now, disable audio locally to not break our audio state | ||
252 | * machine. | ||
253 | */ | ||
254 | hdmi_panel_audio_disable(dssdev); | ||
88 | omapdss_hdmi_display_disable(dssdev); | 255 | omapdss_hdmi_display_disable(dssdev); |
256 | } | ||
89 | 257 | ||
90 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 258 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
91 | 259 | ||
92 | mutex_unlock(&hdmi.hdmi_lock); | 260 | mutex_unlock(&hdmi.lock); |
93 | } | 261 | } |
94 | 262 | ||
95 | static int hdmi_panel_suspend(struct omap_dss_device *dssdev) | 263 | static int hdmi_panel_suspend(struct omap_dss_device *dssdev) |
96 | { | 264 | { |
97 | int r = 0; | 265 | int r = 0; |
98 | 266 | ||
99 | mutex_lock(&hdmi.hdmi_lock); | 267 | mutex_lock(&hdmi.lock); |
100 | 268 | ||
101 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | 269 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { |
102 | r = -EINVAL; | 270 | r = -EINVAL; |
103 | goto err; | 271 | goto err; |
104 | } | 272 | } |
105 | 273 | ||
106 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | 274 | /* |
275 | * TODO: notify audio users that the display was suspended. For now, | ||
276 | * disable audio locally to not break our audio state machine. | ||
277 | */ | ||
278 | hdmi_panel_audio_disable(dssdev); | ||
107 | 279 | ||
280 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
108 | omapdss_hdmi_display_disable(dssdev); | 281 | omapdss_hdmi_display_disable(dssdev); |
109 | 282 | ||
110 | err: | 283 | err: |
111 | mutex_unlock(&hdmi.hdmi_lock); | 284 | mutex_unlock(&hdmi.lock); |
112 | 285 | ||
113 | return r; | 286 | return r; |
114 | } | 287 | } |
@@ -117,7 +290,7 @@ static int hdmi_panel_resume(struct omap_dss_device *dssdev) | |||
117 | { | 290 | { |
118 | int r = 0; | 291 | int r = 0; |
119 | 292 | ||
120 | mutex_lock(&hdmi.hdmi_lock); | 293 | mutex_lock(&hdmi.lock); |
121 | 294 | ||
122 | if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { | 295 | if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { |
123 | r = -EINVAL; | 296 | r = -EINVAL; |
@@ -129,11 +302,12 @@ static int hdmi_panel_resume(struct omap_dss_device *dssdev) | |||
129 | DSSERR("failed to power on\n"); | 302 | DSSERR("failed to power on\n"); |
130 | goto err; | 303 | goto err; |
131 | } | 304 | } |
305 | /* TODO: notify audio users that the panel resumed. */ | ||
132 | 306 | ||
133 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 307 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
134 | 308 | ||
135 | err: | 309 | err: |
136 | mutex_unlock(&hdmi.hdmi_lock); | 310 | mutex_unlock(&hdmi.lock); |
137 | 311 | ||
138 | return r; | 312 | return r; |
139 | } | 313 | } |
@@ -141,11 +315,11 @@ err: | |||
141 | static void hdmi_get_timings(struct omap_dss_device *dssdev, | 315 | static void hdmi_get_timings(struct omap_dss_device *dssdev, |
142 | struct omap_video_timings *timings) | 316 | struct omap_video_timings *timings) |
143 | { | 317 | { |
144 | mutex_lock(&hdmi.hdmi_lock); | 318 | mutex_lock(&hdmi.lock); |
145 | 319 | ||
146 | *timings = dssdev->panel.timings; | 320 | *timings = dssdev->panel.timings; |
147 | 321 | ||
148 | mutex_unlock(&hdmi.hdmi_lock); | 322 | mutex_unlock(&hdmi.lock); |
149 | } | 323 | } |
150 | 324 | ||
151 | static void hdmi_set_timings(struct omap_dss_device *dssdev, | 325 | static void hdmi_set_timings(struct omap_dss_device *dssdev, |
@@ -153,12 +327,18 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev, | |||
153 | { | 327 | { |
154 | DSSDBG("hdmi_set_timings\n"); | 328 | DSSDBG("hdmi_set_timings\n"); |
155 | 329 | ||
156 | mutex_lock(&hdmi.hdmi_lock); | 330 | mutex_lock(&hdmi.lock); |
331 | |||
332 | /* | ||
333 | * TODO: notify audio users that there was a timings change. For | ||
334 | * now, disable audio locally to not break our audio state machine. | ||
335 | */ | ||
336 | hdmi_panel_audio_disable(dssdev); | ||
157 | 337 | ||
158 | dssdev->panel.timings = *timings; | 338 | dssdev->panel.timings = *timings; |
159 | omapdss_hdmi_display_set_timing(dssdev); | 339 | omapdss_hdmi_display_set_timing(dssdev); |
160 | 340 | ||
161 | mutex_unlock(&hdmi.hdmi_lock); | 341 | mutex_unlock(&hdmi.lock); |
162 | } | 342 | } |
163 | 343 | ||
164 | static int hdmi_check_timings(struct omap_dss_device *dssdev, | 344 | static int hdmi_check_timings(struct omap_dss_device *dssdev, |
@@ -168,11 +348,11 @@ static int hdmi_check_timings(struct omap_dss_device *dssdev, | |||
168 | 348 | ||
169 | DSSDBG("hdmi_check_timings\n"); | 349 | DSSDBG("hdmi_check_timings\n"); |
170 | 350 | ||
171 | mutex_lock(&hdmi.hdmi_lock); | 351 | mutex_lock(&hdmi.lock); |
172 | 352 | ||
173 | r = omapdss_hdmi_display_check_timing(dssdev, timings); | 353 | r = omapdss_hdmi_display_check_timing(dssdev, timings); |
174 | 354 | ||
175 | mutex_unlock(&hdmi.hdmi_lock); | 355 | mutex_unlock(&hdmi.lock); |
176 | return r; | 356 | return r; |
177 | } | 357 | } |
178 | 358 | ||
@@ -180,7 +360,7 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len) | |||
180 | { | 360 | { |
181 | int r; | 361 | int r; |
182 | 362 | ||
183 | mutex_lock(&hdmi.hdmi_lock); | 363 | mutex_lock(&hdmi.lock); |
184 | 364 | ||
185 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | 365 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { |
186 | r = omapdss_hdmi_display_enable(dssdev); | 366 | r = omapdss_hdmi_display_enable(dssdev); |
@@ -194,7 +374,7 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len) | |||
194 | dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) | 374 | dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) |
195 | omapdss_hdmi_display_disable(dssdev); | 375 | omapdss_hdmi_display_disable(dssdev); |
196 | err: | 376 | err: |
197 | mutex_unlock(&hdmi.hdmi_lock); | 377 | mutex_unlock(&hdmi.lock); |
198 | 378 | ||
199 | return r; | 379 | return r; |
200 | } | 380 | } |
@@ -203,7 +383,7 @@ static bool hdmi_detect(struct omap_dss_device *dssdev) | |||
203 | { | 383 | { |
204 | int r; | 384 | int r; |
205 | 385 | ||
206 | mutex_lock(&hdmi.hdmi_lock); | 386 | mutex_lock(&hdmi.lock); |
207 | 387 | ||
208 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | 388 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { |
209 | r = omapdss_hdmi_display_enable(dssdev); | 389 | r = omapdss_hdmi_display_enable(dssdev); |
@@ -217,7 +397,7 @@ static bool hdmi_detect(struct omap_dss_device *dssdev) | |||
217 | dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) | 397 | dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) |
218 | omapdss_hdmi_display_disable(dssdev); | 398 | omapdss_hdmi_display_disable(dssdev); |
219 | err: | 399 | err: |
220 | mutex_unlock(&hdmi.hdmi_lock); | 400 | mutex_unlock(&hdmi.lock); |
221 | 401 | ||
222 | return r; | 402 | return r; |
223 | } | 403 | } |
@@ -234,6 +414,12 @@ static struct omap_dss_driver hdmi_driver = { | |||
234 | .check_timings = hdmi_check_timings, | 414 | .check_timings = hdmi_check_timings, |
235 | .read_edid = hdmi_read_edid, | 415 | .read_edid = hdmi_read_edid, |
236 | .detect = hdmi_detect, | 416 | .detect = hdmi_detect, |
417 | .audio_enable = hdmi_panel_audio_enable, | ||
418 | .audio_disable = hdmi_panel_audio_disable, | ||
419 | .audio_start = hdmi_panel_audio_start, | ||
420 | .audio_stop = hdmi_panel_audio_stop, | ||
421 | .audio_supported = hdmi_panel_audio_supported, | ||
422 | .audio_config = hdmi_panel_audio_config, | ||
237 | .driver = { | 423 | .driver = { |
238 | .name = "hdmi_panel", | 424 | .name = "hdmi_panel", |
239 | .owner = THIS_MODULE, | 425 | .owner = THIS_MODULE, |
@@ -242,7 +428,11 @@ static struct omap_dss_driver hdmi_driver = { | |||
242 | 428 | ||
243 | int hdmi_panel_init(void) | 429 | int hdmi_panel_init(void) |
244 | { | 430 | { |
245 | mutex_init(&hdmi.hdmi_lock); | 431 | mutex_init(&hdmi.lock); |
432 | |||
433 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
434 | spin_lock_init(&hdmi.audio_lock); | ||
435 | #endif | ||
246 | 436 | ||
247 | omap_dss_register_driver(&hdmi_driver); | 437 | omap_dss_register_driver(&hdmi_driver); |
248 | 438 | ||
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index 1f58b84d6901..e734cb444bc7 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h | |||
@@ -96,7 +96,9 @@ struct ti_hdmi_ip_ops { | |||
96 | 96 | ||
97 | void (*pll_disable)(struct hdmi_ip_data *ip_data); | 97 | void (*pll_disable)(struct hdmi_ip_data *ip_data); |
98 | 98 | ||
99 | void (*video_enable)(struct hdmi_ip_data *ip_data, bool start); | 99 | int (*video_enable)(struct hdmi_ip_data *ip_data); |
100 | |||
101 | void (*video_disable)(struct hdmi_ip_data *ip_data); | ||
100 | 102 | ||
101 | void (*dump_wrapper)(struct hdmi_ip_data *ip_data, struct seq_file *s); | 103 | void (*dump_wrapper)(struct hdmi_ip_data *ip_data, struct seq_file *s); |
102 | 104 | ||
@@ -106,9 +108,17 @@ struct ti_hdmi_ip_ops { | |||
106 | 108 | ||
107 | void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); | 109 | void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); |
108 | 110 | ||
109 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 111 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) |
110 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | 112 | int (*audio_enable)(struct hdmi_ip_data *ip_data); |
111 | void (*audio_enable)(struct hdmi_ip_data *ip_data, bool start); | 113 | |
114 | void (*audio_disable)(struct hdmi_ip_data *ip_data); | ||
115 | |||
116 | int (*audio_start)(struct hdmi_ip_data *ip_data); | ||
117 | |||
118 | void (*audio_stop)(struct hdmi_ip_data *ip_data); | ||
119 | |||
120 | int (*audio_config)(struct hdmi_ip_data *ip_data, | ||
121 | struct omap_dss_audio *audio); | ||
112 | #endif | 122 | #endif |
113 | 123 | ||
114 | }; | 124 | }; |
@@ -173,7 +183,8 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data); | |||
173 | void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); | 183 | void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); |
174 | int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len); | 184 | int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len); |
175 | bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data); | 185 | bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data); |
176 | void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start); | 186 | int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data); |
187 | void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data); | ||
177 | int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data); | 188 | int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data); |
178 | void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data); | 189 | void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data); |
179 | void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data); | 190 | void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data); |
@@ -181,8 +192,13 @@ void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | |||
181 | void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | 192 | void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); |
182 | void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | 193 | void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); |
183 | void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | 194 | void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); |
184 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 195 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) |
185 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | 196 | int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts); |
186 | void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable); | 197 | int ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data); |
198 | void ti_hdmi_4xxx_wp_audio_disable(struct hdmi_ip_data *ip_data); | ||
199 | int ti_hdmi_4xxx_audio_start(struct hdmi_ip_data *ip_data); | ||
200 | void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data); | ||
201 | int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data, | ||
202 | struct omap_dss_audio *audio); | ||
187 | #endif | 203 | #endif |
188 | #endif | 204 | #endif |
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index 35f59e47d7fe..667c960e10b9 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | |||
@@ -29,9 +29,14 @@ | |||
29 | #include <linux/string.h> | 29 | #include <linux/string.h> |
30 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
31 | #include <linux/gpio.h> | 31 | #include <linux/gpio.h> |
32 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
33 | #include <sound/asound.h> | ||
34 | #include <sound/asoundef.h> | ||
35 | #endif | ||
32 | 36 | ||
33 | #include "ti_hdmi_4xxx_ip.h" | 37 | #include "ti_hdmi_4xxx_ip.h" |
34 | #include "dss.h" | 38 | #include "dss.h" |
39 | #include "dss_features.h" | ||
35 | 40 | ||
36 | static inline void hdmi_write_reg(void __iomem *base_addr, | 41 | static inline void hdmi_write_reg(void __iomem *base_addr, |
37 | const u16 idx, u32 val) | 42 | const u16 idx, u32 val) |
@@ -699,9 +704,15 @@ static void hdmi_wp_init(struct omap_video_timings *timings, | |||
699 | 704 | ||
700 | } | 705 | } |
701 | 706 | ||
702 | void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start) | 707 | int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data) |
708 | { | ||
709 | REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, true, 31, 31); | ||
710 | return 0; | ||
711 | } | ||
712 | |||
713 | void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data) | ||
703 | { | 714 | { |
704 | REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, start, 31, 31); | 715 | REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, false, 31, 31); |
705 | } | 716 | } |
706 | 717 | ||
707 | static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt, | 718 | static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt, |
@@ -1014,9 +1025,8 @@ void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) | |||
1014 | DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL); | 1025 | DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL); |
1015 | } | 1026 | } |
1016 | 1027 | ||
1017 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 1028 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) |
1018 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | 1029 | static void ti_hdmi_4xxx_wp_audio_config_format(struct hdmi_ip_data *ip_data, |
1019 | void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data, | ||
1020 | struct hdmi_audio_format *aud_fmt) | 1030 | struct hdmi_audio_format *aud_fmt) |
1021 | { | 1031 | { |
1022 | u32 r; | 1032 | u32 r; |
@@ -1035,7 +1045,7 @@ void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data, | |||
1035 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG, r); | 1045 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG, r); |
1036 | } | 1046 | } |
1037 | 1047 | ||
1038 | void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data, | 1048 | static void ti_hdmi_4xxx_wp_audio_config_dma(struct hdmi_ip_data *ip_data, |
1039 | struct hdmi_audio_dma *aud_dma) | 1049 | struct hdmi_audio_dma *aud_dma) |
1040 | { | 1050 | { |
1041 | u32 r; | 1051 | u32 r; |
@@ -1053,7 +1063,7 @@ void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data, | |||
1053 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL, r); | 1063 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL, r); |
1054 | } | 1064 | } |
1055 | 1065 | ||
1056 | void hdmi_core_audio_config(struct hdmi_ip_data *ip_data, | 1066 | static void ti_hdmi_4xxx_core_audio_config(struct hdmi_ip_data *ip_data, |
1057 | struct hdmi_core_audio_config *cfg) | 1067 | struct hdmi_core_audio_config *cfg) |
1058 | { | 1068 | { |
1059 | u32 r; | 1069 | u32 r; |
@@ -1104,27 +1114,33 @@ void hdmi_core_audio_config(struct hdmi_ip_data *ip_data, | |||
1104 | REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL, | 1114 | REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL, |
1105 | cfg->fs_override, 1, 1); | 1115 | cfg->fs_override, 1, 1); |
1106 | 1116 | ||
1107 | /* I2S parameters */ | 1117 | /* |
1108 | REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_CHST4, | 1118 | * Set IEC-60958-3 channel status word. It is passed to the IP |
1109 | cfg->freq_sample, 3, 0); | 1119 | * just as it is received. The user of the driver is responsible |
1110 | 1120 | * for its contents. | |
1121 | */ | ||
1122 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST0, | ||
1123 | cfg->iec60958_cfg->status[0]); | ||
1124 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST1, | ||
1125 | cfg->iec60958_cfg->status[1]); | ||
1126 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST2, | ||
1127 | cfg->iec60958_cfg->status[2]); | ||
1128 | /* yes, this is correct: status[3] goes to CHST4 register */ | ||
1129 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST4, | ||
1130 | cfg->iec60958_cfg->status[3]); | ||
1131 | /* yes, this is correct: status[4] goes to CHST5 register */ | ||
1132 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST5, | ||
1133 | cfg->iec60958_cfg->status[4]); | ||
1134 | |||
1135 | /* set I2S parameters */ | ||
1111 | r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL); | 1136 | r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL); |
1112 | r = FLD_MOD(r, cfg->i2s_cfg.en_high_bitrate_aud, 7, 7); | ||
1113 | r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6); | 1137 | r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6); |
1114 | r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5); | ||
1115 | r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4); | 1138 | r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4); |
1116 | r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3); | ||
1117 | r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2); | 1139 | r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2); |
1118 | r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1); | 1140 | r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1); |
1119 | r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0); | 1141 | r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0); |
1120 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL, r); | 1142 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL, r); |
1121 | 1143 | ||
1122 | r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_CHST5); | ||
1123 | r = FLD_MOD(r, cfg->freq_sample, 7, 4); | ||
1124 | r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1); | ||
1125 | r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0); | ||
1126 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST5, r); | ||
1127 | |||
1128 | REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_IN_LEN, | 1144 | REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_IN_LEN, |
1129 | cfg->i2s_cfg.in_length_bits, 3, 0); | 1145 | cfg->i2s_cfg.in_length_bits, 3, 0); |
1130 | 1146 | ||
@@ -1136,12 +1152,19 @@ void hdmi_core_audio_config(struct hdmi_ip_data *ip_data, | |||
1136 | r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2); | 1152 | r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2); |
1137 | r = FLD_MOD(r, cfg->en_spdif, 1, 1); | 1153 | r = FLD_MOD(r, cfg->en_spdif, 1, 1); |
1138 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_MODE, r); | 1154 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_MODE, r); |
1155 | |||
1156 | /* Audio channel mappings */ | ||
1157 | /* TODO: Make channel mapping dynamic. For now, map channels | ||
1158 | * in the ALSA order: FL/FR/RL/RR/C/LFE/SL/SR. Remapping is needed as | ||
1159 | * HDMI speaker order is different. See CEA-861 Section 6.6.2. | ||
1160 | */ | ||
1161 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_MAP, 0x78); | ||
1162 | REG_FLD_MOD(av_base, HDMI_CORE_AV_SWAP_I2S, 1, 5, 5); | ||
1139 | } | 1163 | } |
1140 | 1164 | ||
1141 | void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, | 1165 | static void ti_hdmi_4xxx_core_audio_infoframe_cfg(struct hdmi_ip_data *ip_data, |
1142 | struct hdmi_core_infoframe_audio *info_aud) | 1166 | struct snd_cea_861_aud_if *info_aud) |
1143 | { | 1167 | { |
1144 | u8 val; | ||
1145 | u8 sum = 0, checksum = 0; | 1168 | u8 sum = 0, checksum = 0; |
1146 | void __iomem *av_base = hdmi_av_base(ip_data); | 1169 | void __iomem *av_base = hdmi_av_base(ip_data); |
1147 | 1170 | ||
@@ -1155,24 +1178,23 @@ void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, | |||
1155 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_LEN, 0x0a); | 1178 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_LEN, 0x0a); |
1156 | sum += 0x84 + 0x001 + 0x00a; | 1179 | sum += 0x84 + 0x001 + 0x00a; |
1157 | 1180 | ||
1158 | val = (info_aud->db1_coding_type << 4) | 1181 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(0), |
1159 | | (info_aud->db1_channel_count - 1); | 1182 | info_aud->db1_ct_cc); |
1160 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(0), val); | 1183 | sum += info_aud->db1_ct_cc; |
1161 | sum += val; | ||
1162 | 1184 | ||
1163 | val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size; | 1185 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(1), |
1164 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(1), val); | 1186 | info_aud->db2_sf_ss); |
1165 | sum += val; | 1187 | sum += info_aud->db2_sf_ss; |
1166 | 1188 | ||
1167 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), 0x00); | 1189 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), info_aud->db3); |
1190 | sum += info_aud->db3; | ||
1168 | 1191 | ||
1169 | val = info_aud->db4_channel_alloc; | 1192 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), info_aud->db4_ca); |
1170 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), val); | 1193 | sum += info_aud->db4_ca; |
1171 | sum += val; | ||
1172 | 1194 | ||
1173 | val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3); | 1195 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(4), |
1174 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(4), val); | 1196 | info_aud->db5_dminh_lsv); |
1175 | sum += val; | 1197 | sum += info_aud->db5_dminh_lsv; |
1176 | 1198 | ||
1177 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(5), 0x00); | 1199 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(5), 0x00); |
1178 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(6), 0x00); | 1200 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(6), 0x00); |
@@ -1190,70 +1212,212 @@ void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, | |||
1190 | */ | 1212 | */ |
1191 | } | 1213 | } |
1192 | 1214 | ||
1193 | int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, | 1215 | int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data, |
1194 | u32 sample_freq, u32 *n, u32 *cts) | 1216 | struct omap_dss_audio *audio) |
1195 | { | 1217 | { |
1196 | u32 r; | 1218 | struct hdmi_audio_format audio_format; |
1197 | u32 deep_color = 0; | 1219 | struct hdmi_audio_dma audio_dma; |
1198 | u32 pclk = ip_data->cfg.timings.pixel_clock; | 1220 | struct hdmi_core_audio_config core; |
1199 | 1221 | int err, n, cts, channel_count; | |
1200 | if (n == NULL || cts == NULL) | 1222 | unsigned int fs_nr; |
1223 | bool word_length_16b = false; | ||
1224 | |||
1225 | if (!audio || !audio->iec || !audio->cea || !ip_data) | ||
1201 | return -EINVAL; | 1226 | return -EINVAL; |
1227 | |||
1228 | core.iec60958_cfg = audio->iec; | ||
1229 | /* | ||
1230 | * In the IEC-60958 status word, check if the audio sample word length | ||
1231 | * is 16-bit as several optimizations can be performed in such case. | ||
1232 | */ | ||
1233 | if (!(audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24)) | ||
1234 | if (audio->iec->status[4] & IEC958_AES4_CON_WORDLEN_20_16) | ||
1235 | word_length_16b = true; | ||
1236 | |||
1237 | /* I2S configuration. See Phillips' specification */ | ||
1238 | if (word_length_16b) | ||
1239 | core.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
1240 | else | ||
1241 | core.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
1202 | /* | 1242 | /* |
1203 | * Obtain current deep color configuration. This needed | 1243 | * The I2S input word length is twice the lenght given in the IEC-60958 |
1204 | * to calculate the TMDS clock based on the pixel clock. | 1244 | * status word. If the word size is greater than |
1245 | * 20 bits, increment by one. | ||
1205 | */ | 1246 | */ |
1206 | r = REG_GET(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, 1, 0); | 1247 | core.i2s_cfg.in_length_bits = audio->iec->status[4] |
1207 | switch (r) { | 1248 | & IEC958_AES4_CON_WORDLEN; |
1208 | case 1: /* No deep color selected */ | 1249 | if (audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24) |
1209 | deep_color = 100; | 1250 | core.i2s_cfg.in_length_bits++; |
1251 | core.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING; | ||
1252 | core.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM; | ||
1253 | core.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST; | ||
1254 | core.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT; | ||
1255 | |||
1256 | /* convert sample frequency to a number */ | ||
1257 | switch (audio->iec->status[3] & IEC958_AES3_CON_FS) { | ||
1258 | case IEC958_AES3_CON_FS_32000: | ||
1259 | fs_nr = 32000; | ||
1260 | break; | ||
1261 | case IEC958_AES3_CON_FS_44100: | ||
1262 | fs_nr = 44100; | ||
1263 | break; | ||
1264 | case IEC958_AES3_CON_FS_48000: | ||
1265 | fs_nr = 48000; | ||
1210 | break; | 1266 | break; |
1211 | case 2: /* 10-bit deep color selected */ | 1267 | case IEC958_AES3_CON_FS_88200: |
1212 | deep_color = 125; | 1268 | fs_nr = 88200; |
1213 | break; | 1269 | break; |
1214 | case 3: /* 12-bit deep color selected */ | 1270 | case IEC958_AES3_CON_FS_96000: |
1215 | deep_color = 150; | 1271 | fs_nr = 96000; |
1272 | break; | ||
1273 | case IEC958_AES3_CON_FS_176400: | ||
1274 | fs_nr = 176400; | ||
1275 | break; | ||
1276 | case IEC958_AES3_CON_FS_192000: | ||
1277 | fs_nr = 192000; | ||
1216 | break; | 1278 | break; |
1217 | default: | 1279 | default: |
1218 | return -EINVAL; | 1280 | return -EINVAL; |
1219 | } | 1281 | } |
1220 | 1282 | ||
1221 | switch (sample_freq) { | 1283 | err = hdmi_compute_acr(fs_nr, &n, &cts); |
1222 | case 32000: | 1284 | |
1223 | if ((deep_color == 125) && ((pclk == 54054) | 1285 | /* Audio clock regeneration settings */ |
1224 | || (pclk == 74250))) | 1286 | core.n = n; |
1225 | *n = 8192; | 1287 | core.cts = cts; |
1226 | else | 1288 | if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) { |
1227 | *n = 4096; | 1289 | core.aud_par_busclk = 0; |
1290 | core.cts_mode = HDMI_AUDIO_CTS_MODE_SW; | ||
1291 | core.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK); | ||
1292 | } else { | ||
1293 | core.aud_par_busclk = (((128 * 31) - 1) << 8); | ||
1294 | core.cts_mode = HDMI_AUDIO_CTS_MODE_HW; | ||
1295 | core.use_mclk = true; | ||
1296 | } | ||
1297 | |||
1298 | if (core.use_mclk) | ||
1299 | core.mclk_mode = HDMI_AUDIO_MCLK_128FS; | ||
1300 | |||
1301 | /* Audio channels settings */ | ||
1302 | channel_count = (audio->cea->db1_ct_cc & | ||
1303 | CEA861_AUDIO_INFOFRAME_DB1CC) + 1; | ||
1304 | |||
1305 | switch (channel_count) { | ||
1306 | case 2: | ||
1307 | audio_format.active_chnnls_msk = 0x03; | ||
1308 | break; | ||
1309 | case 3: | ||
1310 | audio_format.active_chnnls_msk = 0x07; | ||
1311 | break; | ||
1312 | case 4: | ||
1313 | audio_format.active_chnnls_msk = 0x0f; | ||
1314 | break; | ||
1315 | case 5: | ||
1316 | audio_format.active_chnnls_msk = 0x1f; | ||
1228 | break; | 1317 | break; |
1229 | case 44100: | 1318 | case 6: |
1230 | *n = 6272; | 1319 | audio_format.active_chnnls_msk = 0x3f; |
1231 | break; | 1320 | break; |
1232 | case 48000: | 1321 | case 7: |
1233 | if ((deep_color == 125) && ((pclk == 54054) | 1322 | audio_format.active_chnnls_msk = 0x7f; |
1234 | || (pclk == 74250))) | 1323 | break; |
1235 | *n = 8192; | 1324 | case 8: |
1236 | else | 1325 | audio_format.active_chnnls_msk = 0xff; |
1237 | *n = 6144; | ||
1238 | break; | 1326 | break; |
1239 | default: | 1327 | default: |
1240 | *n = 0; | ||
1241 | return -EINVAL; | 1328 | return -EINVAL; |
1242 | } | 1329 | } |
1243 | 1330 | ||
1244 | /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */ | 1331 | /* |
1245 | *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10); | 1332 | * the HDMI IP needs to enable four stereo channels when transmitting |
1333 | * more than 2 audio channels | ||
1334 | */ | ||
1335 | if (channel_count == 2) { | ||
1336 | audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL; | ||
1337 | core.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN; | ||
1338 | core.layout = HDMI_AUDIO_LAYOUT_2CH; | ||
1339 | } else { | ||
1340 | audio_format.stereo_channels = HDMI_AUDIO_STEREO_FOURCHANNELS; | ||
1341 | core.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN | | ||
1342 | HDMI_AUDIO_I2S_SD1_EN | HDMI_AUDIO_I2S_SD2_EN | | ||
1343 | HDMI_AUDIO_I2S_SD3_EN; | ||
1344 | core.layout = HDMI_AUDIO_LAYOUT_8CH; | ||
1345 | } | ||
1346 | |||
1347 | core.en_spdif = false; | ||
1348 | /* use sample frequency from channel status word */ | ||
1349 | core.fs_override = true; | ||
1350 | /* enable ACR packets */ | ||
1351 | core.en_acr_pkt = true; | ||
1352 | /* disable direct streaming digital audio */ | ||
1353 | core.en_dsd_audio = false; | ||
1354 | /* use parallel audio interface */ | ||
1355 | core.en_parallel_aud_input = true; | ||
1356 | |||
1357 | /* DMA settings */ | ||
1358 | if (word_length_16b) | ||
1359 | audio_dma.transfer_size = 0x10; | ||
1360 | else | ||
1361 | audio_dma.transfer_size = 0x20; | ||
1362 | audio_dma.block_size = 0xC0; | ||
1363 | audio_dma.mode = HDMI_AUDIO_TRANSF_DMA; | ||
1364 | audio_dma.fifo_threshold = 0x20; /* in number of samples */ | ||
1365 | |||
1366 | /* audio FIFO format settings */ | ||
1367 | if (word_length_16b) { | ||
1368 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES; | ||
1369 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS; | ||
1370 | audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
1371 | } else { | ||
1372 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE; | ||
1373 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS; | ||
1374 | audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
1375 | } | ||
1376 | audio_format.type = HDMI_AUDIO_TYPE_LPCM; | ||
1377 | audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST; | ||
1378 | /* disable start/stop signals of IEC 60958 blocks */ | ||
1379 | audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON; | ||
1380 | |||
1381 | /* configure DMA and audio FIFO format*/ | ||
1382 | ti_hdmi_4xxx_wp_audio_config_dma(ip_data, &audio_dma); | ||
1383 | ti_hdmi_4xxx_wp_audio_config_format(ip_data, &audio_format); | ||
1384 | |||
1385 | /* configure the core*/ | ||
1386 | ti_hdmi_4xxx_core_audio_config(ip_data, &core); | ||
1246 | 1387 | ||
1388 | /* configure CEA 861 audio infoframe*/ | ||
1389 | ti_hdmi_4xxx_core_audio_infoframe_cfg(ip_data, audio->cea); | ||
1390 | |||
1391 | return 0; | ||
1392 | } | ||
1393 | |||
1394 | int ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data) | ||
1395 | { | ||
1396 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
1397 | HDMI_WP_AUDIO_CTRL, true, 31, 31); | ||
1247 | return 0; | 1398 | return 0; |
1248 | } | 1399 | } |
1249 | 1400 | ||
1250 | void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable) | 1401 | void ti_hdmi_4xxx_wp_audio_disable(struct hdmi_ip_data *ip_data) |
1402 | { | ||
1403 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
1404 | HDMI_WP_AUDIO_CTRL, false, 31, 31); | ||
1405 | } | ||
1406 | |||
1407 | int ti_hdmi_4xxx_audio_start(struct hdmi_ip_data *ip_data) | ||
1251 | { | 1408 | { |
1252 | REG_FLD_MOD(hdmi_av_base(ip_data), | 1409 | REG_FLD_MOD(hdmi_av_base(ip_data), |
1253 | HDMI_CORE_AV_AUD_MODE, enable, 0, 0); | 1410 | HDMI_CORE_AV_AUD_MODE, true, 0, 0); |
1254 | REG_FLD_MOD(hdmi_wp_base(ip_data), | 1411 | REG_FLD_MOD(hdmi_wp_base(ip_data), |
1255 | HDMI_WP_AUDIO_CTRL, enable, 31, 31); | 1412 | HDMI_WP_AUDIO_CTRL, true, 30, 30); |
1413 | return 0; | ||
1414 | } | ||
1415 | |||
1416 | void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data) | ||
1417 | { | ||
1418 | REG_FLD_MOD(hdmi_av_base(ip_data), | ||
1419 | HDMI_CORE_AV_AUD_MODE, false, 0, 0); | ||
1256 | REG_FLD_MOD(hdmi_wp_base(ip_data), | 1420 | REG_FLD_MOD(hdmi_wp_base(ip_data), |
1257 | HDMI_WP_AUDIO_CTRL, enable, 30, 30); | 1421 | HDMI_WP_AUDIO_CTRL, false, 30, 30); |
1258 | } | 1422 | } |
1259 | #endif | 1423 | #endif |
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h index b724bc68307a..8366ae19e82e 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h | |||
@@ -24,11 +24,6 @@ | |||
24 | #include <linux/string.h> | 24 | #include <linux/string.h> |
25 | #include <video/omapdss.h> | 25 | #include <video/omapdss.h> |
26 | #include "ti_hdmi.h" | 26 | #include "ti_hdmi.h" |
27 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
28 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
29 | #include <sound/soc.h> | ||
30 | #include <sound/pcm_params.h> | ||
31 | #endif | ||
32 | 27 | ||
33 | /* HDMI Wrapper */ | 28 | /* HDMI Wrapper */ |
34 | 29 | ||
@@ -279,35 +274,6 @@ enum hdmi_core_infoframe { | |||
279 | HDMI_INFOFRAME_AVI_DB5PR_8 = 7, | 274 | HDMI_INFOFRAME_AVI_DB5PR_8 = 7, |
280 | HDMI_INFOFRAME_AVI_DB5PR_9 = 8, | 275 | HDMI_INFOFRAME_AVI_DB5PR_9 = 8, |
281 | HDMI_INFOFRAME_AVI_DB5PR_10 = 9, | 276 | HDMI_INFOFRAME_AVI_DB5PR_10 = 9, |
282 | HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM = 0, | ||
283 | HDMI_INFOFRAME_AUDIO_DB1CT_IEC60958 = 1, | ||
284 | HDMI_INFOFRAME_AUDIO_DB1CT_AC3 = 2, | ||
285 | HDMI_INFOFRAME_AUDIO_DB1CT_MPEG1 = 3, | ||
286 | HDMI_INFOFRAME_AUDIO_DB1CT_MP3 = 4, | ||
287 | HDMI_INFOFRAME_AUDIO_DB1CT_MPEG2_MULTICH = 5, | ||
288 | HDMI_INFOFRAME_AUDIO_DB1CT_AAC = 6, | ||
289 | HDMI_INFOFRAME_AUDIO_DB1CT_DTS = 7, | ||
290 | HDMI_INFOFRAME_AUDIO_DB1CT_ATRAC = 8, | ||
291 | HDMI_INFOFRAME_AUDIO_DB1CT_ONEBIT = 9, | ||
292 | HDMI_INFOFRAME_AUDIO_DB1CT_DOLBY_DIGITAL_PLUS = 10, | ||
293 | HDMI_INFOFRAME_AUDIO_DB1CT_DTS_HD = 11, | ||
294 | HDMI_INFOFRAME_AUDIO_DB1CT_MAT = 12, | ||
295 | HDMI_INFOFRAME_AUDIO_DB1CT_DST = 13, | ||
296 | HDMI_INFOFRAME_AUDIO_DB1CT_WMA_PRO = 14, | ||
297 | HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM = 0, | ||
298 | HDMI_INFOFRAME_AUDIO_DB2SF_32000 = 1, | ||
299 | HDMI_INFOFRAME_AUDIO_DB2SF_44100 = 2, | ||
300 | HDMI_INFOFRAME_AUDIO_DB2SF_48000 = 3, | ||
301 | HDMI_INFOFRAME_AUDIO_DB2SF_88200 = 4, | ||
302 | HDMI_INFOFRAME_AUDIO_DB2SF_96000 = 5, | ||
303 | HDMI_INFOFRAME_AUDIO_DB2SF_176400 = 6, | ||
304 | HDMI_INFOFRAME_AUDIO_DB2SF_192000 = 7, | ||
305 | HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM = 0, | ||
306 | HDMI_INFOFRAME_AUDIO_DB2SS_16BIT = 1, | ||
307 | HDMI_INFOFRAME_AUDIO_DB2SS_20BIT = 2, | ||
308 | HDMI_INFOFRAME_AUDIO_DB2SS_24BIT = 3, | ||
309 | HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PERMITTED = 0, | ||
310 | HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PROHIBITED = 1 | ||
311 | }; | 277 | }; |
312 | 278 | ||
313 | enum hdmi_packing_mode { | 279 | enum hdmi_packing_mode { |
@@ -317,17 +283,6 @@ enum hdmi_packing_mode { | |||
317 | HDMI_PACK_ALREADYPACKED = 7 | 283 | HDMI_PACK_ALREADYPACKED = 7 |
318 | }; | 284 | }; |
319 | 285 | ||
320 | enum hdmi_core_audio_sample_freq { | ||
321 | HDMI_AUDIO_FS_32000 = 0x3, | ||
322 | HDMI_AUDIO_FS_44100 = 0x0, | ||
323 | HDMI_AUDIO_FS_48000 = 0x2, | ||
324 | HDMI_AUDIO_FS_88200 = 0x8, | ||
325 | HDMI_AUDIO_FS_96000 = 0xA, | ||
326 | HDMI_AUDIO_FS_176400 = 0xC, | ||
327 | HDMI_AUDIO_FS_192000 = 0xE, | ||
328 | HDMI_AUDIO_FS_NOT_INDICATED = 0x1 | ||
329 | }; | ||
330 | |||
331 | enum hdmi_core_audio_layout { | 286 | enum hdmi_core_audio_layout { |
332 | HDMI_AUDIO_LAYOUT_2CH = 0, | 287 | HDMI_AUDIO_LAYOUT_2CH = 0, |
333 | HDMI_AUDIO_LAYOUT_8CH = 1 | 288 | HDMI_AUDIO_LAYOUT_8CH = 1 |
@@ -382,37 +337,12 @@ enum hdmi_audio_blk_strt_end_sig { | |||
382 | }; | 337 | }; |
383 | 338 | ||
384 | enum hdmi_audio_i2s_config { | 339 | enum hdmi_audio_i2s_config { |
385 | HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT = 0, | ||
386 | HDMI_AUDIO_I2S_WS_POLARIT_YLOW_IS_RIGHT = 1, | ||
387 | HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0, | 340 | HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0, |
388 | HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1, | 341 | HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1, |
389 | HDMI_AUDIO_I2S_MAX_WORD_20BITS = 0, | ||
390 | HDMI_AUDIO_I2S_MAX_WORD_24BITS = 1, | ||
391 | HDMI_AUDIO_I2S_CHST_WORD_NOT_SPECIFIED = 0, | ||
392 | HDMI_AUDIO_I2S_CHST_WORD_16_BITS = 1, | ||
393 | HDMI_AUDIO_I2S_CHST_WORD_17_BITS = 6, | ||
394 | HDMI_AUDIO_I2S_CHST_WORD_18_BITS = 2, | ||
395 | HDMI_AUDIO_I2S_CHST_WORD_19_BITS = 4, | ||
396 | HDMI_AUDIO_I2S_CHST_WORD_20_BITS_20MAX = 5, | ||
397 | HDMI_AUDIO_I2S_CHST_WORD_20_BITS_24MAX = 1, | ||
398 | HDMI_AUDIO_I2S_CHST_WORD_21_BITS = 6, | ||
399 | HDMI_AUDIO_I2S_CHST_WORD_22_BITS = 2, | ||
400 | HDMI_AUDIO_I2S_CHST_WORD_23_BITS = 4, | ||
401 | HDMI_AUDIO_I2S_CHST_WORD_24_BITS = 5, | ||
402 | HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0, | 342 | HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0, |
403 | HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1, | 343 | HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1, |
404 | HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0, | 344 | HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0, |
405 | HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1, | 345 | HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1, |
406 | HDMI_AUDIO_I2S_INPUT_LENGTH_NA = 0, | ||
407 | HDMI_AUDIO_I2S_INPUT_LENGTH_16 = 2, | ||
408 | HDMI_AUDIO_I2S_INPUT_LENGTH_17 = 12, | ||
409 | HDMI_AUDIO_I2S_INPUT_LENGTH_18 = 4, | ||
410 | HDMI_AUDIO_I2S_INPUT_LENGTH_19 = 8, | ||
411 | HDMI_AUDIO_I2S_INPUT_LENGTH_20 = 10, | ||
412 | HDMI_AUDIO_I2S_INPUT_LENGTH_21 = 13, | ||
413 | HDMI_AUDIO_I2S_INPUT_LENGTH_22 = 5, | ||
414 | HDMI_AUDIO_I2S_INPUT_LENGTH_23 = 9, | ||
415 | HDMI_AUDIO_I2S_INPUT_LENGTH_24 = 11, | ||
416 | HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0, | 346 | HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0, |
417 | HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1, | 347 | HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1, |
418 | HDMI_AUDIO_I2S_SD0_EN = 1, | 348 | HDMI_AUDIO_I2S_SD0_EN = 1, |
@@ -441,20 +371,6 @@ struct hdmi_core_video_config { | |||
441 | enum hdmi_core_tclkselclkmult tclk_sel_clkmult; | 371 | enum hdmi_core_tclkselclkmult tclk_sel_clkmult; |
442 | }; | 372 | }; |
443 | 373 | ||
444 | /* | ||
445 | * Refer to section 8.2 in HDMI 1.3 specification for | ||
446 | * details about infoframe databytes | ||
447 | */ | ||
448 | struct hdmi_core_infoframe_audio { | ||
449 | u8 db1_coding_type; | ||
450 | u8 db1_channel_count; | ||
451 | u8 db2_sample_freq; | ||
452 | u8 db2_sample_size; | ||
453 | u8 db4_channel_alloc; | ||
454 | bool db5_downmix_inh; | ||
455 | u8 db5_lsv; /* Level shift values for downmix */ | ||
456 | }; | ||
457 | |||
458 | struct hdmi_core_packet_enable_repeat { | 374 | struct hdmi_core_packet_enable_repeat { |
459 | u32 audio_pkt; | 375 | u32 audio_pkt; |
460 | u32 audio_pkt_repeat; | 376 | u32 audio_pkt_repeat; |
@@ -491,15 +407,10 @@ struct hdmi_audio_dma { | |||
491 | }; | 407 | }; |
492 | 408 | ||
493 | struct hdmi_core_audio_i2s_config { | 409 | struct hdmi_core_audio_i2s_config { |
494 | u8 word_max_length; | ||
495 | u8 word_length; | ||
496 | u8 in_length_bits; | 410 | u8 in_length_bits; |
497 | u8 justification; | 411 | u8 justification; |
498 | u8 en_high_bitrate_aud; | ||
499 | u8 sck_edge_mode; | 412 | u8 sck_edge_mode; |
500 | u8 cbit_order; | ||
501 | u8 vbit; | 413 | u8 vbit; |
502 | u8 ws_polarity; | ||
503 | u8 direction; | 414 | u8 direction; |
504 | u8 shift; | 415 | u8 shift; |
505 | u8 active_sds; | 416 | u8 active_sds; |
@@ -507,7 +418,7 @@ struct hdmi_core_audio_i2s_config { | |||
507 | 418 | ||
508 | struct hdmi_core_audio_config { | 419 | struct hdmi_core_audio_config { |
509 | struct hdmi_core_audio_i2s_config i2s_cfg; | 420 | struct hdmi_core_audio_i2s_config i2s_cfg; |
510 | enum hdmi_core_audio_sample_freq freq_sample; | 421 | struct snd_aes_iec958 *iec60958_cfg; |
511 | bool fs_override; | 422 | bool fs_override; |
512 | u32 n; | 423 | u32 n; |
513 | u32 cts; | 424 | u32 cts; |
@@ -522,17 +433,4 @@ struct hdmi_core_audio_config { | |||
522 | bool en_spdif; | 433 | bool en_spdif; |
523 | }; | 434 | }; |
524 | 435 | ||
525 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
526 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
527 | int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, | ||
528 | u32 sample_freq, u32 *n, u32 *cts); | ||
529 | void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, | ||
530 | struct hdmi_core_infoframe_audio *info_aud); | ||
531 | void hdmi_core_audio_config(struct hdmi_ip_data *ip_data, | ||
532 | struct hdmi_core_audio_config *cfg); | ||
533 | void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data, | ||
534 | struct hdmi_audio_dma *aud_dma); | ||
535 | void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data, | ||
536 | struct hdmi_audio_format *aud_fmt); | ||
537 | #endif | ||
538 | #endif | 436 | #endif |
diff --git a/include/video/omapdss.h b/include/video/omapdss.h index 1217df40cb7e..bb30242eeea1 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h | |||
@@ -51,6 +51,8 @@ | |||
51 | 51 | ||
52 | struct omap_dss_device; | 52 | struct omap_dss_device; |
53 | struct omap_overlay_manager; | 53 | struct omap_overlay_manager; |
54 | struct snd_aes_iec958; | ||
55 | struct snd_cea_861_aud_if; | ||
54 | 56 | ||
55 | enum omap_display_type { | 57 | enum omap_display_type { |
56 | OMAP_DISPLAY_TYPE_NONE = 0, | 58 | OMAP_DISPLAY_TYPE_NONE = 0, |
@@ -158,6 +160,13 @@ enum omap_dss_display_state { | |||
158 | OMAP_DSS_DISPLAY_SUSPENDED, | 160 | OMAP_DSS_DISPLAY_SUSPENDED, |
159 | }; | 161 | }; |
160 | 162 | ||
163 | enum omap_dss_audio_state { | ||
164 | OMAP_DSS_AUDIO_DISABLED = 0, | ||
165 | OMAP_DSS_AUDIO_ENABLED, | ||
166 | OMAP_DSS_AUDIO_CONFIGURED, | ||
167 | OMAP_DSS_AUDIO_PLAYING, | ||
168 | }; | ||
169 | |||
161 | /* XXX perhaps this should be removed */ | 170 | /* XXX perhaps this should be removed */ |
162 | enum omap_dss_overlay_managers { | 171 | enum omap_dss_overlay_managers { |
163 | OMAP_DSS_OVL_MGR_LCD, | 172 | OMAP_DSS_OVL_MGR_LCD, |
@@ -583,6 +592,8 @@ struct omap_dss_device { | |||
583 | 592 | ||
584 | enum omap_dss_display_state state; | 593 | enum omap_dss_display_state state; |
585 | 594 | ||
595 | enum omap_dss_audio_state audio_state; | ||
596 | |||
586 | /* platform specific */ | 597 | /* platform specific */ |
587 | int (*platform_enable)(struct omap_dss_device *dssdev); | 598 | int (*platform_enable)(struct omap_dss_device *dssdev); |
588 | void (*platform_disable)(struct omap_dss_device *dssdev); | 599 | void (*platform_disable)(struct omap_dss_device *dssdev); |
@@ -595,6 +606,11 @@ struct omap_dss_hdmi_data | |||
595 | int hpd_gpio; | 606 | int hpd_gpio; |
596 | }; | 607 | }; |
597 | 608 | ||
609 | struct omap_dss_audio { | ||
610 | struct snd_aes_iec958 *iec; | ||
611 | struct snd_cea_861_aud_if *cea; | ||
612 | }; | ||
613 | |||
598 | struct omap_dss_driver { | 614 | struct omap_dss_driver { |
599 | struct device_driver driver; | 615 | struct device_driver driver; |
600 | 616 | ||
@@ -642,6 +658,24 @@ struct omap_dss_driver { | |||
642 | 658 | ||
643 | int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len); | 659 | int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len); |
644 | bool (*detect)(struct omap_dss_device *dssdev); | 660 | bool (*detect)(struct omap_dss_device *dssdev); |
661 | |||
662 | /* | ||
663 | * For display drivers that support audio. This encompasses | ||
664 | * HDMI and DisplayPort at the moment. | ||
665 | */ | ||
666 | /* | ||
667 | * Note: These functions might sleep. Do not call while | ||
668 | * holding a spinlock/readlock. | ||
669 | */ | ||
670 | int (*audio_enable)(struct omap_dss_device *dssdev); | ||
671 | void (*audio_disable)(struct omap_dss_device *dssdev); | ||
672 | bool (*audio_supported)(struct omap_dss_device *dssdev); | ||
673 | int (*audio_config)(struct omap_dss_device *dssdev, | ||
674 | struct omap_dss_audio *audio); | ||
675 | /* Note: These functions may not sleep */ | ||
676 | int (*audio_start)(struct omap_dss_device *dssdev); | ||
677 | void (*audio_stop)(struct omap_dss_device *dssdev); | ||
678 | |||
645 | }; | 679 | }; |
646 | 680 | ||
647 | int omap_dss_register_driver(struct omap_dss_driver *); | 681 | int omap_dss_register_driver(struct omap_dss_driver *); |