From 9c0b8420369cb5d7fd2fea51d4705cbd0ea52743 Mon Sep 17 00:00:00 2001 From: Ricardo Neri Date: Tue, 6 Mar 2012 18:20:37 -0600 Subject: [PATCH 01/15] OMAPDSS: Provide an interface for audio support There exist several display technologies and standards that support audio as well. Hence, it is relevant to update the DSS device driver to provide an audio interface that may be used by an audio driver or any other driver interested in the functionality. The audio_enable function is intended to prepare the relevant IP for playback (e.g., enabling an audio FIFO, taking in/out of reset some IP, enabling companion chips, etc). It is intended to be called before audio_start. The audio_disable function performs the reverse operation and is intended to be called after audio_stop. While a given DSS device driver may support audio, it is possible that for certain configurations audio is not supported (e.g., an HDMI display using a VESA video timing). The audio_supported function is intended to query whether the current configuration of the display supports audio. The audio_config function is intended to configure all the relevant audio parameters of the display. In order to make the function independent of any specific DSS device driver, a struct omap_dss_audio is defined. Its purpose is to contain all the required parameters for audio configuration. At the moment, such structure contains pointers to IEC-60958 channel status word and CEA-861 audio infoframe structures. This should be enough to support HDMI and DisplayPort, as both are based on CEA-861 and IEC-60958. The omap_dss_audio structure may be extended in the future if required. The audio_enable/disable, audio_config and audio_supported functions could be implemented as functions that may sleep. Hence, they should not be called while holding a spinlock or a readlock. The audio_start/audio_stop function is intended to effectively start/stop audio playback after the configuration has taken place. These functions are designed to be used in an atomic context. Hence, audio_start should return quickly and be called only after all the needed resources for audio playback (audio FIFOs, DMA channels, companion chips, etc) have been enabled to begin data transfers. audio_stop is designed to only stop the audio transfers. The resources used for playback are released using audio_disable. A new enum omap_dss_audio_state is introduced to help the implementations of the interface to keep track of the audio state. The initial state is _DISABLED; then, the state transitions to _CONFIGURED, and then, when it is ready to play audio, to _ENABLED. The state _PLAYING is used when the audio is being rendered. Signed-off-by: Ricardo Neri --- Documentation/arm/OMAP/DSS | 45 ++++++++++++++++++++++++++++++++++++++ include/video/omapdss.h | 34 ++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) 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 modelling the hardware overlays, omapdss supports virtual overlays and overlay managers. These can be used when updating a display with CPU or system DMA. +omapdss driver support for audio +-------------------------------- +There exist several display technologies and standards that support audio as +well. Hence, it is relevant to update the DSS device driver to provide an audio +interface that may be used by an audio driver or any other driver interested in +the functionality. + +The audio_enable function is intended to prepare the relevant +IP for playback (e.g., enabling an audio FIFO, taking in/out of reset +some IP, enabling companion chips, etc). It is intended to be called before +audio_start. The audio_disable function performs the reverse operation and is +intended to be called after audio_stop. + +While a given DSS device driver may support audio, it is possible that for +certain configurations audio is not supported (e.g., an HDMI display using a +VESA video timing). The audio_supported function is intended to query whether +the current configuration of the display supports audio. + +The audio_config function is intended to configure all the relevant audio +parameters of the display. In order to make the function independent of any +specific DSS device driver, a struct omap_dss_audio is defined. Its purpose +is to contain all the required parameters for audio configuration. At the +moment, such structure contains pointers to IEC-60958 channel status word +and CEA-861 audio infoframe structures. This should be enough to support +HDMI and DisplayPort, as both are based on CEA-861 and IEC-60958. + +The audio_enable/disable, audio_config and audio_supported functions could be +implemented as functions that may sleep. Hence, they should not be called +while holding a spinlock or a readlock. + +The audio_start/audio_stop function is intended to effectively start/stop audio +playback after the configuration has taken place. These functions are designed +to be used in an atomic context. Hence, audio_start should return quickly and be +called only after all the needed resources for audio playback (audio FIFOs, +DMA channels, companion chips, etc) have been enabled to begin data transfers. +audio_stop is designed to only stop the audio transfers. The resources used +for playback are released using audio_disable. + +The enum omap_dss_audio_state may be used to help the implementations of +the interface to keep track of the audio state. The initial state is _DISABLED; +then, the state transitions to _CONFIGURED, and then, when it is ready to +play audio, to _ENABLED. The state _PLAYING is used when the audio is being +rendered. + + Panel and controller drivers ---------------------------- 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 @@ struct omap_dss_device; struct omap_overlay_manager; +struct snd_aes_iec958; +struct snd_cea_861_aud_if; enum omap_display_type { OMAP_DISPLAY_TYPE_NONE = 0, @@ -158,6 +160,13 @@ enum omap_dss_display_state { OMAP_DSS_DISPLAY_SUSPENDED, }; +enum omap_dss_audio_state { + OMAP_DSS_AUDIO_DISABLED = 0, + OMAP_DSS_AUDIO_ENABLED, + OMAP_DSS_AUDIO_CONFIGURED, + OMAP_DSS_AUDIO_PLAYING, +}; + /* XXX perhaps this should be removed */ enum omap_dss_overlay_managers { OMAP_DSS_OVL_MGR_LCD, @@ -583,6 +592,8 @@ struct omap_dss_device { enum omap_dss_display_state state; + enum omap_dss_audio_state audio_state; + /* platform specific */ int (*platform_enable)(struct omap_dss_device *dssdev); void (*platform_disable)(struct omap_dss_device *dssdev); @@ -595,6 +606,11 @@ struct omap_dss_hdmi_data int hpd_gpio; }; +struct omap_dss_audio { + struct snd_aes_iec958 *iec; + struct snd_cea_861_aud_if *cea; +}; + struct omap_dss_driver { struct device_driver driver; @@ -642,6 +658,24 @@ struct omap_dss_driver { int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len); bool (*detect)(struct omap_dss_device *dssdev); + + /* + * For display drivers that support audio. This encompasses + * HDMI and DisplayPort at the moment. + */ + /* + * Note: These functions might sleep. Do not call while + * holding a spinlock/readlock. + */ + int (*audio_enable)(struct omap_dss_device *dssdev); + void (*audio_disable)(struct omap_dss_device *dssdev); + bool (*audio_supported)(struct omap_dss_device *dssdev); + int (*audio_config)(struct omap_dss_device *dssdev, + struct omap_dss_audio *audio); + /* Note: These functions may not sleep */ + int (*audio_start)(struct omap_dss_device *dssdev); + void (*audio_stop)(struct omap_dss_device *dssdev); + }; int omap_dss_register_driver(struct omap_dss_driver *); From 027bdc85ee74f8f456a47dc53154252ef7d1792f Mon Sep 17 00:00:00 2001 From: Ricardo Neri Date: Fri, 20 Apr 2012 17:17:46 -0500 Subject: [PATCH 02/15] OMAPDSS: HDMI: Split audio_enable into audio_enable/disable To improve readability, split the audio_enable HDMI IP operation into two separate functions for enabling and disabling audio. The audio_enable function is also modified to return an error value. While there, update these operations for the OMAP4 IP accordingly. Signed-off-by: Ricardo Neri --- drivers/video/omap2/dss/dss_features.c | 1 + drivers/video/omap2/dss/hdmi.c | 4 ++-- drivers/video/omap2/dss/ti_hdmi.h | 7 +++++-- drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | 19 +++++++++++++++---- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 1d10a014bc55..3a28c5c79f46 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -575,6 +575,7 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) .audio_enable = ti_hdmi_4xxx_wp_audio_enable, + .audio_disable = ti_hdmi_4xxx_wp_audio_disable, #endif }; diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 5f2e2f677bef..2a011401c8f2 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -557,12 +557,12 @@ static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ip_data->ops->audio_enable(ip_data, true); + ip_data->ops->audio_enable(ip_data); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ip_data->ops->audio_enable(ip_data, false); + ip_data->ops->audio_disable(ip_data); break; default: err = -EINVAL; diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index 1f58b84d6901..88fdc1cda364 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h @@ -108,7 +108,9 @@ struct ti_hdmi_ip_ops { #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) - void (*audio_enable)(struct hdmi_ip_data *ip_data, bool start); + int (*audio_enable)(struct hdmi_ip_data *ip_data); + + void (*audio_disable)(struct hdmi_ip_data *ip_data); #endif }; @@ -183,6 +185,7 @@ void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) -void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable); +int ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data); +void ti_hdmi_4xxx_wp_audio_disable(struct hdmi_ip_data *ip_data); #endif #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..39fbd6ad8429 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c @@ -1247,13 +1247,24 @@ int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, return 0; } -void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable) +int ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data) { REG_FLD_MOD(hdmi_av_base(ip_data), - HDMI_CORE_AV_AUD_MODE, enable, 0, 0); + HDMI_CORE_AV_AUD_MODE, true, 0, 0); REG_FLD_MOD(hdmi_wp_base(ip_data), - HDMI_WP_AUDIO_CTRL, enable, 31, 31); + HDMI_WP_AUDIO_CTRL, true, 31, 31); REG_FLD_MOD(hdmi_wp_base(ip_data), - HDMI_WP_AUDIO_CTRL, enable, 30, 30); + HDMI_WP_AUDIO_CTRL, true, 30, 30); + return 0; +} + +void ti_hdmi_4xxx_wp_audio_disable(struct hdmi_ip_data *ip_data) +{ + REG_FLD_MOD(hdmi_av_base(ip_data), + HDMI_CORE_AV_AUD_MODE, false, 0, 0); + REG_FLD_MOD(hdmi_wp_base(ip_data), + HDMI_WP_AUDIO_CTRL, false, 31, 31); + REG_FLD_MOD(hdmi_wp_base(ip_data), + HDMI_WP_AUDIO_CTRL, false, 30, 30); } #endif From c0456be38fef2866b1dbeceb756485b001fa23b9 Mon Sep 17 00:00:00 2001 From: Ricardo Neri Date: Fri, 27 Apr 2012 13:48:45 -0500 Subject: [PATCH 03/15] OMAPDSS: HDMI: Split video_enable into video_enable/disable To improve readability, split the video_enable HDMI IP operation into two separate functions for enabling and disabling video. The video_enable function is also modified to return an error value. While there, update these operations for the OMAP4 IP accordingly. Signed-off-by: Ricardo Neri --- drivers/video/omap2/dss/dss_features.c | 1 + drivers/video/omap2/dss/hdmi.c | 11 +++++++---- drivers/video/omap2/dss/ti_hdmi.h | 7 +++++-- drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | 10 ++++++++-- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 3a28c5c79f46..234ed8ad89ea 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -568,6 +568,7 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { .pll_enable = ti_hdmi_4xxx_pll_enable, .pll_disable = ti_hdmi_4xxx_pll_disable, .video_enable = ti_hdmi_4xxx_wp_video_start, + .video_disable = ti_hdmi_4xxx_wp_video_stop, .dump_wrapper = ti_hdmi_4xxx_wp_dump, .dump_core = ti_hdmi_4xxx_core_dump, .dump_pll = ti_hdmi_4xxx_pll_dump, diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 2a011401c8f2..8f0549a2e796 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -324,7 +324,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); - hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); + hdmi.ip_data.ops->video_disable(&hdmi.ip_data); /* config the PLL and PHY hdmi_set_pll_pwrfirst */ r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); @@ -358,7 +358,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) /* tv size */ dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); - hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1); + r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data); + if (r) + goto err_vid_enable; r = dss_mgr_enable(dssdev->manager); if (r) @@ -367,7 +369,8 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) return 0; err_mgr_enable: - hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); + hdmi.ip_data.ops->video_disable(&hdmi.ip_data); +err_vid_enable: hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); err: @@ -379,7 +382,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev) { dss_mgr_disable(dssdev->manager); - hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); + hdmi.ip_data.ops->video_disable(&hdmi.ip_data); hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); hdmi_runtime_put(); diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index 88fdc1cda364..4c84a9cf2931 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 { void (*pll_disable)(struct hdmi_ip_data *ip_data); - void (*video_enable)(struct hdmi_ip_data *ip_data, bool start); + int (*video_enable)(struct hdmi_ip_data *ip_data); + + void (*video_disable)(struct hdmi_ip_data *ip_data); void (*dump_wrapper)(struct hdmi_ip_data *ip_data, struct seq_file *s); @@ -175,7 +177,8 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data); void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len); bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data); -void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start); +int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data); +void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data); int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data); void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data); void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data); diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index 39fbd6ad8429..bc499bf30266 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c @@ -699,9 +699,15 @@ static void hdmi_wp_init(struct omap_video_timings *timings, } -void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start) +int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data) { - REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, start, 31, 31); + REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, true, 31, 31); + return 0; +} + +void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data) +{ + REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, false, 31, 31); } static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt, From 7c3291f06b4e025c4bd373adbb3f6354080f5097 Mon Sep 17 00:00:00 2001 From: Ricardo Neri Date: Thu, 15 Mar 2012 12:58:51 -0600 Subject: [PATCH 04/15] OMAPDSS: HDMI: Remove ASoC codec Remove the ASoC OMAP HDMI audio codec. The goal of removing the codec is to, in subsequent patches, give way to the implementation of the HDMI audio support using the DSS device driver audio interface. This approach will expose the HDMI audio functionality to any interested entity. In a separate patch, ASoC will use this new approach to expose HDMI audio to ALSA. Signed-off-by: Ricardo Neri --- drivers/video/omap2/dss/hdmi.c | 236 ---------------------- drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h | 5 - 2 files changed, 241 deletions(-) diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 8f0549a2e796..0f8efc961e6b 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -33,12 +33,6 @@ #include #include #include