diff options
| author | Takashi Iwai <tiwai@suse.de> | 2017-02-20 08:52:50 +0100 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2017-02-20 08:52:50 +0100 |
| commit | fc0e23fad33198fc7d74227dba7bbc3a5d7755aa (patch) | |
| tree | 669319e33fb63a456986b6ac41cf3b584f583caf | |
| parent | af677166cf63c179dc2485053166e02c4aea01eb (diff) | |
| parent | 3bb9eca913025ed05c0510de831c67b7bef652c5 (diff) | |
| download | linux-fc0e23fad33198fc7d74227dba7bbc3a5d7755aa.tar.gz linux-fc0e23fad33198fc7d74227dba7bbc3a5d7755aa.tar.bz2 linux-fc0e23fad33198fc7d74227dba7bbc3a5d7755aa.zip | |
Merge branch 'for-next' into for-linus
83 files changed, 3399 insertions, 395 deletions
diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst index 117d2ab7a5f7..7fb605af090e 100644 --- a/Documentation/gpu/i915.rst +++ b/Documentation/gpu/i915.rst @@ -144,6 +144,15 @@ High Definition Audio .. kernel-doc:: include/drm/i915_component.h :internal: +Intel HDMI LPE Audio Support +---------------------------- + +.. kernel-doc:: drivers/gpu/drm/i915/intel_lpe_audio.c + :doc: LPE Audio integration for HDMI or DP playback + +.. kernel-doc:: drivers/gpu/drm/i915/intel_lpe_audio.c + :internal: + Panel Self Refresh PSR (PSR/SRD) -------------------------------- diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 3dea46af9fe6..78711dddd937 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -122,6 +122,9 @@ i915-y += intel_gvt.o include $(src)/gvt/Makefile endif +# LPE Audio for VLV and CHT +i915-y += intel_lpe_audio.o + obj-$(CONFIG_DRM_I915) += i915.o CFLAGS_i915_trace_points.o := -I$(src) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index b2c4a0b8a627..77ae0be3d4ba 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1138,7 +1138,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) if (IS_GEN5(dev_priv)) intel_gpu_ips_init(dev_priv); - i915_audio_component_init(dev_priv); + intel_audio_init(dev_priv); /* * Some ports require correctly set-up hpd registers for detection to @@ -1156,7 +1156,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) */ static void i915_driver_unregister(struct drm_i915_private *dev_priv) { - i915_audio_component_cleanup(dev_priv); + intel_audio_deinit(dev_priv); intel_gpu_ips_teardown(); acpi_video_unregister(); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8493e19b563a..029d5c3c81ef 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2140,6 +2140,12 @@ struct drm_i915_private { /* Used to save the pipe-to-encoder mapping for audio */ struct intel_encoder *av_enc_map[I915_MAX_PIPES]; + /* necessary resource sharing with HDMI LPE audio driver. */ + struct { + struct platform_device *platdev; + int irq; + } lpe_audio; + /* * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch * will be rejected. Instead look for a better place. @@ -3387,6 +3393,14 @@ extern int i915_restore_state(struct drm_device *dev); void i915_setup_sysfs(struct drm_i915_private *dev_priv); void i915_teardown_sysfs(struct drm_i915_private *dev_priv); +/* intel_lpe_audio.c */ +int intel_lpe_audio_init(struct drm_i915_private *dev_priv); +void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv); +void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv); +void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, + void *eld, int port, int pipe, int tmds_clk_speed, + bool dp_output, int link_rate); + /* intel_i2c.c */ extern int intel_setup_gmbus(struct drm_device *dev); extern void intel_teardown_gmbus(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 07ca71cabb2b..f0880afbb878 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1893,6 +1893,10 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) * signalled in iir */ valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats); + if (iir & (I915_LPE_PIPE_A_INTERRUPT | + I915_LPE_PIPE_B_INTERRUPT)) + intel_lpe_audio_irq_handler(dev_priv); + /* * VLV_IIR is single buffered, and reflects the level * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last. @@ -1973,6 +1977,11 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg) * signalled in iir */ valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats); + if (iir & (I915_LPE_PIPE_A_INTERRUPT | + I915_LPE_PIPE_B_INTERRUPT | + I915_LPE_PIPE_C_INTERRUPT)) + intel_lpe_audio_irq_handler(dev_priv); + /* * VLV_IIR is single buffered, and reflects the level * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last. @@ -2914,6 +2923,7 @@ static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv) u32 pipestat_mask; u32 enable_mask; enum pipe pipe; + u32 val; pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV | PIPE_CRC_DONE_INTERRUPT_STATUS; @@ -2930,6 +2940,12 @@ static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv) WARN_ON(dev_priv->irq_mask != ~0); + val = (I915_LPE_PIPE_A_INTERRUPT | + I915_LPE_PIPE_B_INTERRUPT | + I915_LPE_PIPE_C_INTERRUPT); + + enable_mask |= val; + dev_priv->irq_mask = ~enable_mask; GEN5_IRQ_INIT(VLV_, dev_priv->irq_mask, enable_mask); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c70c07a7b586..4f15a3dc6d98 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2058,6 +2058,22 @@ enum skl_disp_power_wells { #define I915_ASLE_INTERRUPT (1<<0) #define I915_BSD_USER_INTERRUPT (1<<25) +#define I915_HDMI_LPE_AUDIO_BASE (VLV_DISPLAY_BASE + 0x65000) +#define I915_HDMI_LPE_AUDIO_SIZE 0x1000 + +/* DisplayPort Audio w/ LPE */ +#define VLV_AUD_CHICKEN_BIT_REG _MMIO(VLV_DISPLAY_BASE + 0x62F38) +#define VLV_CHICKEN_BIT_DBG_ENABLE (1 << 0) + +#define _VLV_AUD_PORT_EN_B_DBG (VLV_DISPLAY_BASE + 0x62F20) +#define _VLV_AUD_PORT_EN_C_DBG (VLV_DISPLAY_BASE + 0x62F30) +#define _VLV_AUD_PORT_EN_D_DBG (VLV_DISPLAY_BASE + 0x62F34) +#define VLV_AUD_PORT_EN_DBG(port) _MMIO_PORT3((port) - PORT_B, \ + _VLV_AUD_PORT_EN_B_DBG, \ + _VLV_AUD_PORT_EN_C_DBG, \ + _VLV_AUD_PORT_EN_D_DBG) +#define VLV_AMP_MUTE (1 << 1) + #define GEN6_BSD_RNCID _MMIO(0x12198) #define GEN7_FF_THREAD_MODE _MMIO(0x20a0) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 49f10538d4aa..892169b7952b 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -24,6 +24,7 @@ #include <linux/kernel.h> #include <linux/component.h> #include <drm/i915_component.h> +#include <drm/intel_lpe_audio.h> #include "intel_drv.h" #include <drm/drmP.h> @@ -623,13 +624,28 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder, dev_priv->av_enc_map[pipe] = intel_encoder; mutex_unlock(&dev_priv->av_mutex); - /* audio drivers expect pipe = -1 to indicate Non-MST cases */ - if (intel_encoder->type != INTEL_OUTPUT_DP_MST) - pipe = -1; - - if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) + if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) { + /* audio drivers expect pipe = -1 to indicate Non-MST cases */ + if (intel_encoder->type != INTEL_OUTPUT_DP_MST) + pipe = -1; acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port, (int) pipe); + } + + switch (intel_encoder->type) { + case INTEL_OUTPUT_HDMI: + intel_lpe_audio_notify(dev_priv, connector->eld, port, pipe, + crtc_state->port_clock, + false, 0); + break; + case INTEL_OUTPUT_DP: + intel_lpe_audio_notify(dev_priv, connector->eld, port, pipe, + adjusted_mode->crtc_clock, + true, crtc_state->port_clock); + break; + default: + break; + } } /** @@ -656,13 +672,15 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder) dev_priv->av_enc_map[pipe] = NULL; mutex_unlock(&dev_priv->av_mutex); - /* audio drivers expect pipe = -1 to indicate Non-MST cases */ - if (intel_encoder->type != INTEL_OUTPUT_DP_MST) - pipe = -1; - - if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) + if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) { + /* audio drivers expect pipe = -1 to indicate Non-MST cases */ + if (intel_encoder->type != INTEL_OUTPUT_DP_MST) + pipe = -1; acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port, (int) pipe); + } + + intel_lpe_audio_notify(dev_priv, NULL, port, pipe, 0, false, 0); } /** @@ -931,3 +949,28 @@ void i915_audio_component_cleanup(struct drm_i915_private *dev_priv) component_del(dev_priv->drm.dev, &i915_audio_component_bind_ops); dev_priv->audio_component_registered = false; } + +/** + * intel_audio_init() - Initialize the audio driver either using + * component framework or using lpe audio bridge + * @dev_priv: the i915 drm device private data + * + */ +void intel_audio_init(struct drm_i915_private *dev_priv) +{ + if (intel_lpe_audio_init(dev_priv) < 0) + i915_audio_component_init(dev_priv); +} + +/** + * intel_audio_deinit() - deinitialize the audio driver + * @dev_priv: the i915 drm device private data + * + */ +void intel_audio_deinit(struct drm_i915_private *dev_priv) +{ + if ((dev_priv)->lpe_audio.platdev != NULL) + intel_lpe_audio_teardown(dev_priv); + else + i915_audio_component_cleanup(dev_priv); +} diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 03a2112004f9..ba2323f1b92b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1196,6 +1196,8 @@ void intel_audio_codec_enable(struct intel_encoder *encoder, void intel_audio_codec_disable(struct intel_encoder *encoder); void i915_audio_component_init(struct drm_i915_private *dev_priv); void i915_audio_component_cleanup(struct drm_i915_private *dev_priv); +void intel_audio_init(struct drm_i915_private *dev_priv); +void intel_audio_deinit(struct drm_i915_private *dev_priv); /* intel_display.c */ enum transcoder intel_crtc_pch_transcoder(struct intel_crtc *crtc); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index fb88e32e25a3..02d50e334ac6 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -36,6 +36,7 @@ #include <drm/drm_edid.h> #include "intel_drv.h" #include <drm/i915_drm.h> +#include <drm/intel_lpe_audio.h> #include "i915_drv.h" static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi) diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c new file mode 100644 index 000000000000..7a5b41b1c024 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_lpe_audio.c @@ -0,0 +1,392 @@ +/* + * Copyright © 2016 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> + * Jerome Anand <jerome.anand@intel.com> + * based on VED patches + * + */ + +/** + * DOC: LPE Audio integration for HDMI or DP playback + * + * Motivation: + * Atom platforms (e.g. valleyview and cherryTrail) integrates a DMA-based + * interface as an alternative to the traditional HDaudio path. While this + * mode is unrelated to the LPE aka SST audio engine, the documentation refers + * to this mode as LPE so we keep this notation for the sake of consistency. + * + * The interface is handled by a separate standalone driver maintained in the + * ALSA subsystem for simplicity. To minimize the interaction between the two + * subsystems, a bridge is setup between the hdmi-lpe-audio and i915: + * 1. Create a platform device to share MMIO/IRQ resources + * 2. Make the platform device child of i915 device for runtime PM. + * 3. Create IRQ chip to forward the LPE audio irqs. + * the hdmi-lpe-audio driver probes the lpe audio device and creates a new + * sound card + * + * Threats: + * Due to the restriction in Linux platform device model, user need manually + * uninstall the hdmi-lpe-audio driver before uninstalling i915 module, + * otherwise we might run into use-after-free issues after i915 removes the + * platform device: even though hdmi-lpe-audio driver is released, the modules + * is still in "installed" status. + * + * Implementation: + * The MMIO/REG platform resources are created according to the registers + * specification. + * When forwarding LPE audio irqs, the flow control handler selection depends + * on the platform, for example on valleyview handle_simple_irq is enough. + * + */ + +#include <linux/acpi.h> +#include <linux/device.h> +#include <linux/pci.h> + +#include "i915_drv.h" +#include <linux/delay.h> +#include <drm/intel_lpe_audio.h> + +#define HAS_LPE_AUDIO(dev_priv) ((dev_priv)->lpe_audio.platdev != NULL) + +static struct platform_device * +lpe_audio_platdev_create(struct drm_i915_private *dev_priv) +{ + int ret; + struct drm_de |
