diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-06-25 19:06:12 +0200 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-06-25 19:10:36 +0200 |
commit | 7b0cfee1a24efdfe0235bac62e53f686fe8a8e24 (patch) | |
tree | eeeb8cc3bf7be5ec0e54b7c4f3808ef88ecca012 /drivers/video/omap2/dss/hdmi_panel.c | |
parent | 9756fe38d10b2bf90c81dc4d2f17d5632e135364 (diff) | |
parent | 6b16351acbd415e66ba16bf7d473ece1574cf0bc (diff) | |
download | talos-obmc-linux-7b0cfee1a24efdfe0235bac62e53f686fe8a8e24.tar.gz talos-obmc-linux-7b0cfee1a24efdfe0235bac62e53f686fe8a8e24.zip |
Merge tag 'v3.5-rc4' into drm-intel-next-queued
I want to merge the "no more fake agp on gen6+" patches into
drm-intel-next (well, the last pieces). But a patch in 3.5-rc4 also
adds a new use of dev->agp. Hence the backmarge to sort this out, for
otherwise drm-intel-next merged into Linus' tree would conflict in the
relevant code, things would compile but nicely OOPS at driver load :(
Conflicts in this merge are just simple cases of "both branches
changed/added lines at the same place". The only tricky part is to
keep the order correct wrt the unwind code in case of errors in
intel_ringbuffer.c (and the MI_DISPLAY_FLIP #defines in i915_reg.h
together, obviously).
Conflicts:
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_ringbuffer.c
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/video/omap2/dss/hdmi_panel.c')
-rw-r--r-- | drivers/video/omap2/dss/hdmi_panel.c | 236 |
1 files changed, 213 insertions, 23 deletions
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 @@ #include "dss.h" static struct { - struct mutex hdmi_lock; + /* This protects the panel ops, mainly when accessing the HDMI IP. */ + struct mutex lock; +#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) + /* This protects the audio ops, specifically. */ + spinlock_t audio_lock; +#endif } hdmi; @@ -54,12 +59,168 @@ static void hdmi_panel_remove(struct omap_dss_device *dssdev) } +#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) +static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev) +{ + unsigned long flags; + int r; + + mutex_lock(&hdmi.lock); + spin_lock_irqsave(&hdmi.audio_lock, flags); + + /* enable audio only if the display is active and supports audio */ + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || + !hdmi_mode_has_audio()) { + DSSERR("audio not supported or display is off\n"); + r = -EPERM; + goto err; + } + + r = hdmi_audio_enable(); + + if (!r) + dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED; + +err: + spin_unlock_irqrestore(&hdmi.audio_lock, flags); + mutex_unlock(&hdmi.lock); + return r; +} + +static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev) +{ + unsigned long flags; + + spin_lock_irqsave(&hdmi.audio_lock, flags); + + hdmi_audio_disable(); + + dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED; + + spin_unlock_irqrestore(&hdmi.audio_lock, flags); +} + +static int hdmi_panel_audio_start(struct omap_dss_device *dssdev) +{ + unsigned long flags; + int r; + + spin_lock_irqsave(&hdmi.audio_lock, flags); + /* + * No need to check the panel state. It was checked when trasitioning + * to AUDIO_ENABLED. + */ + if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED) { + DSSERR("audio start from invalid state\n"); + r = -EPERM; + goto err; + } + + r = hdmi_audio_start(); + + if (!r) + dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING; + +err: + spin_unlock_irqrestore(&hdmi.audio_lock, flags); + return r; +} + +static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev) +{ + unsigned long flags; + + spin_lock_irqsave(&hdmi.audio_lock, flags); + + hdmi_audio_stop(); + dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED; + + spin_unlock_irqrestore(&hdmi.audio_lock, flags); +} + +static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev) +{ + bool r = false; + + mutex_lock(&hdmi.lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + goto err; + + if (!hdmi_mode_has_audio()) + goto err; + + r = true; +err: + mutex_unlock(&hdmi.lock); + return r; +} + +static int hdmi_panel_audio_config(struct omap_dss_device *dssdev, + struct omap_dss_audio *audio) +{ + unsigned long flags; + int r; + + mutex_lock(&hdmi.lock); + spin_lock_irqsave(&hdmi.audio_lock, flags); + + /* config audio only if the display is active and supports audio */ + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || + !hdmi_mode_has_audio()) { + DSSERR("audio not supported or display is off\n"); + r = -EPERM; + goto err; + } + + r = hdmi_audio_config(audio); + + if (!r) + dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED; + +err: + spin_unlock_irqrestore(&hdmi.audio_lock, flags); + mutex_unlock(&hdmi.lock); + return r; +} + +#else +static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev) +{ + return -EPERM; +} + +static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev) +{ +} + +static int hdmi_panel_audio_start(struct omap_dss_device *dssdev) +{ + return -EPERM; +} + +static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev) +{ +} + +static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev) +{ + return false; +} + +static int hdmi_panel_audio_config(struct omap_dss_device *dssdev, + struct omap_dss_audio *audio) +{ + return -EPERM; +} +#endif + static int hdmi_panel_enable(struct omap_dss_device *dssdev) { int r = 0; DSSDBG("ENTER hdmi_panel_enable\n"); - mutex_lock(&hdmi.hdmi_lock); + mutex_lock(&hdmi.lock); if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { r = -EINVAL; @@ -75,40 +236,52 @@ static int hdmi_panel_enable(struct omap_dss_device *dssdev) dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; err: - mutex_unlock(&hdmi.hdmi_lock); + mutex_unlock(&hdmi.lock); return r; } static void hdmi_panel_disable(struct omap_dss_device *dssdev) { - mutex_lock(&hdmi.hdmi_lock); - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + mutex_lock(&hdmi.lock); + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { + /* + * TODO: notify audio users that the display was disabled. For + * now, disable audio locally to not break our audio state + * machine. + */ + hdmi_panel_audio_disable(dssdev); omapdss_hdmi_display_disable(dssdev); + } dssdev->state = OMAP_DSS_DISPLAY_DISABLED; - mutex_unlock(&hdmi.hdmi_lock); + mutex_unlock(&hdmi.lock); } static int hdmi_panel_suspend(struct omap_dss_device *dssdev) { int r = 0; - mutex_lock(&hdmi.hdmi_lock); + mutex_lock(&hdmi.lock); if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { r = -EINVAL; goto err; } - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + /* + * TODO: notify audio users that the display was suspended. For now, + * disable audio locally to not break our audio state machine. + */ + hdmi_panel_audio_disable(dssdev); + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; omapdss_hdmi_display_disable(dssdev); err: - mutex_unlock(&hdmi.hdmi_lock); + mutex_unlock(&hdmi.lock); return r; } @@ -117,7 +290,7 @@ static int hdmi_panel_resume(struct omap_dss_device *dssdev) { int r = 0; - mutex_lock(&hdmi.hdmi_lock); + mutex_lock(&hdmi.lock); if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { r = -EINVAL; @@ -129,11 +302,12 @@ static int hdmi_panel_resume(struct omap_dss_device *dssdev) DSSERR("failed to power on\n"); goto err; } + /* TODO: notify audio users that the panel resumed. */ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; err: - mutex_unlock(&hdmi.hdmi_lock); + mutex_unlock(&hdmi.lock); return r; } @@ -141,11 +315,11 @@ err: static void hdmi_get_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - mutex_lock(&hdmi.hdmi_lock); + mutex_lock(&hdmi.lock); *timings = dssdev->panel.timings; - mutex_unlock(&hdmi.hdmi_lock); + mutex_unlock(&hdmi.lock); } static void hdmi_set_timings(struct omap_dss_device *dssdev, @@ -153,12 +327,18 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev, { DSSDBG("hdmi_set_timings\n"); - mutex_lock(&hdmi.hdmi_lock); + mutex_lock(&hdmi.lock); + + /* + * TODO: notify audio users that there was a timings change. For + * now, disable audio locally to not break our audio state machine. + */ + hdmi_panel_audio_disable(dssdev); dssdev->panel.timings = *timings; omapdss_hdmi_display_set_timing(dssdev); - mutex_unlock(&hdmi.hdmi_lock); + mutex_unlock(&hdmi.lock); } static int hdmi_check_timings(struct omap_dss_device *dssdev, @@ -168,11 +348,11 @@ static int hdmi_check_timings(struct omap_dss_device *dssdev, DSSDBG("hdmi_check_timings\n"); - mutex_lock(&hdmi.hdmi_lock); + mutex_lock(&hdmi.lock); r = omapdss_hdmi_display_check_timing(dssdev, timings); - mutex_unlock(&hdmi.hdmi_lock); + mutex_unlock(&hdmi.lock); return r; } @@ -180,7 +360,7 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len) { int r; - mutex_lock(&hdmi.hdmi_lock); + mutex_lock(&hdmi.lock); if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { r = omapdss_hdmi_display_enable(dssdev); @@ -194,7 +374,7 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len) dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) omapdss_hdmi_display_disable(dssdev); err: - mutex_unlock(&hdmi.hdmi_lock); + mutex_unlock(&hdmi.lock); return r; } @@ -203,7 +383,7 @@ static bool hdmi_detect(struct omap_dss_device *dssdev) { int r; - mutex_lock(&hdmi.hdmi_lock); + mutex_lock(&hdmi.lock); if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { r = omapdss_hdmi_display_enable(dssdev); @@ -217,7 +397,7 @@ static bool hdmi_detect(struct omap_dss_device *dssdev) dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) omapdss_hdmi_display_disable(dssdev); err: - mutex_unlock(&hdmi.hdmi_lock); + mutex_unlock(&hdmi.lock); return r; } @@ -234,6 +414,12 @@ static struct omap_dss_driver hdmi_driver = { .check_timings = hdmi_check_timings, .read_edid = hdmi_read_edid, .detect = hdmi_detect, + .audio_enable = hdmi_panel_audio_enable, + .audio_disable = hdmi_panel_audio_disable, + .audio_start = hdmi_panel_audio_start, + .audio_stop = hdmi_panel_audio_stop, + .audio_supported = hdmi_panel_audio_supported, + .audio_config = hdmi_panel_audio_config, .driver = { .name = "hdmi_panel", .owner = THIS_MODULE, @@ -242,7 +428,11 @@ static struct omap_dss_driver hdmi_driver = { int hdmi_panel_init(void) { - mutex_init(&hdmi.hdmi_lock); + mutex_init(&hdmi.lock); + +#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) + spin_lock_init(&hdmi.audio_lock); +#endif omap_dss_register_driver(&hdmi_driver); |