1*a85cb24fSFrançois Tigeot /* 2*a85cb24fSFrançois Tigeot * Copyright © 2016 Intel Corporation 3*a85cb24fSFrançois Tigeot * 4*a85cb24fSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 5*a85cb24fSFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 6*a85cb24fSFrançois Tigeot * to deal in the Software without restriction, including without limitation 7*a85cb24fSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8*a85cb24fSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 9*a85cb24fSFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 10*a85cb24fSFrançois Tigeot * 11*a85cb24fSFrançois Tigeot * The above copyright notice and this permission notice (including the next 12*a85cb24fSFrançois Tigeot * paragraph) shall be included in all copies or substantial portions of the 13*a85cb24fSFrançois Tigeot * Software. 14*a85cb24fSFrançois Tigeot * 15*a85cb24fSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16*a85cb24fSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17*a85cb24fSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18*a85cb24fSFrançois Tigeot * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19*a85cb24fSFrançois Tigeot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20*a85cb24fSFrançois Tigeot * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21*a85cb24fSFrançois Tigeot * IN THE SOFTWARE. 22*a85cb24fSFrançois Tigeot * 23*a85cb24fSFrançois Tigeot * Authors: 24*a85cb24fSFrançois Tigeot * Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> 25*a85cb24fSFrançois Tigeot * Jerome Anand <jerome.anand@intel.com> 26*a85cb24fSFrançois Tigeot * based on VED patches 27*a85cb24fSFrançois Tigeot * 28*a85cb24fSFrançois Tigeot */ 29*a85cb24fSFrançois Tigeot 30*a85cb24fSFrançois Tigeot /** 31*a85cb24fSFrançois Tigeot * DOC: LPE Audio integration for HDMI or DP playback 32*a85cb24fSFrançois Tigeot * 33*a85cb24fSFrançois Tigeot * Motivation: 34*a85cb24fSFrançois Tigeot * Atom platforms (e.g. valleyview and cherryTrail) integrates a DMA-based 35*a85cb24fSFrançois Tigeot * interface as an alternative to the traditional HDaudio path. While this 36*a85cb24fSFrançois Tigeot * mode is unrelated to the LPE aka SST audio engine, the documentation refers 37*a85cb24fSFrançois Tigeot * to this mode as LPE so we keep this notation for the sake of consistency. 38*a85cb24fSFrançois Tigeot * 39*a85cb24fSFrançois Tigeot * The interface is handled by a separate standalone driver maintained in the 40*a85cb24fSFrançois Tigeot * ALSA subsystem for simplicity. To minimize the interaction between the two 41*a85cb24fSFrançois Tigeot * subsystems, a bridge is setup between the hdmi-lpe-audio and i915: 42*a85cb24fSFrançois Tigeot * 1. Create a platform device to share MMIO/IRQ resources 43*a85cb24fSFrançois Tigeot * 2. Make the platform device child of i915 device for runtime PM. 44*a85cb24fSFrançois Tigeot * 3. Create IRQ chip to forward the LPE audio irqs. 45*a85cb24fSFrançois Tigeot * the hdmi-lpe-audio driver probes the lpe audio device and creates a new 46*a85cb24fSFrançois Tigeot * sound card 47*a85cb24fSFrançois Tigeot * 48*a85cb24fSFrançois Tigeot * Threats: 49*a85cb24fSFrançois Tigeot * Due to the restriction in Linux platform device model, user need manually 50*a85cb24fSFrançois Tigeot * uninstall the hdmi-lpe-audio driver before uninstalling i915 module, 51*a85cb24fSFrançois Tigeot * otherwise we might run into use-after-free issues after i915 removes the 52*a85cb24fSFrançois Tigeot * platform device: even though hdmi-lpe-audio driver is released, the modules 53*a85cb24fSFrançois Tigeot * is still in "installed" status. 54*a85cb24fSFrançois Tigeot * 55*a85cb24fSFrançois Tigeot * Implementation: 56*a85cb24fSFrançois Tigeot * The MMIO/REG platform resources are created according to the registers 57*a85cb24fSFrançois Tigeot * specification. 58*a85cb24fSFrançois Tigeot * When forwarding LPE audio irqs, the flow control handler selection depends 59*a85cb24fSFrançois Tigeot * on the platform, for example on valleyview handle_simple_irq is enough. 60*a85cb24fSFrançois Tigeot * 61*a85cb24fSFrançois Tigeot */ 62*a85cb24fSFrançois Tigeot 63*a85cb24fSFrançois Tigeot #include <linux/acpi.h> 64*a85cb24fSFrançois Tigeot #include <linux/device.h> 65*a85cb24fSFrançois Tigeot #include <linux/pci.h> 66*a85cb24fSFrançois Tigeot #include <linux/pm_runtime.h> 67*a85cb24fSFrançois Tigeot 68*a85cb24fSFrançois Tigeot #include "i915_drv.h" 69*a85cb24fSFrançois Tigeot #include <linux/delay.h> 70*a85cb24fSFrançois Tigeot #include <drm/intel_lpe_audio.h> 71*a85cb24fSFrançois Tigeot 72*a85cb24fSFrançois Tigeot #define HAS_LPE_AUDIO(dev_priv) ((dev_priv)->lpe_audio.platdev != NULL) 73*a85cb24fSFrançois Tigeot 74*a85cb24fSFrançois Tigeot #if 0 75*a85cb24fSFrançois Tigeot static struct platform_device * 76*a85cb24fSFrançois Tigeot lpe_audio_platdev_create(struct drm_i915_private *dev_priv) 77*a85cb24fSFrançois Tigeot { 78*a85cb24fSFrançois Tigeot int ret; 79*a85cb24fSFrançois Tigeot struct drm_device *dev = &dev_priv->drm; 80*a85cb24fSFrançois Tigeot struct platform_device_info pinfo = {}; 81*a85cb24fSFrançois Tigeot struct resource *rsc; 82*a85cb24fSFrançois Tigeot struct platform_device *platdev; 83*a85cb24fSFrançois Tigeot struct intel_hdmi_lpe_audio_pdata *pdata; 84*a85cb24fSFrançois Tigeot 85*a85cb24fSFrançois Tigeot pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); 86*a85cb24fSFrançois Tigeot if (!pdata) 87*a85cb24fSFrançois Tigeot return ERR_PTR(-ENOMEM); 88*a85cb24fSFrançois Tigeot 89*a85cb24fSFrançois Tigeot rsc = kcalloc(2, sizeof(*rsc), GFP_KERNEL); 90*a85cb24fSFrançois Tigeot if (!rsc) { 91*a85cb24fSFrançois Tigeot kfree(pdata); 92*a85cb24fSFrançois Tigeot return ERR_PTR(-ENOMEM); 93*a85cb24fSFrançois Tigeot } 94*a85cb24fSFrançois Tigeot 95*a85cb24fSFrançois Tigeot rsc[0].start = rsc[0].end = dev_priv->lpe_audio.irq; 96*a85cb24fSFrançois Tigeot rsc[0].flags = IORESOURCE_IRQ; 97*a85cb24fSFrançois Tigeot rsc[0].name = "hdmi-lpe-audio-irq"; 98*a85cb24fSFrançois Tigeot 99*a85cb24fSFrançois Tigeot rsc[1].start = pci_resource_start(dev->pdev, 0) + 100*a85cb24fSFrançois Tigeot I915_HDMI_LPE_AUDIO_BASE; 101*a85cb24fSFrançois Tigeot rsc[1].end = pci_resource_start(dev->pdev, 0) + 102*a85cb24fSFrançois Tigeot I915_HDMI_LPE_AUDIO_BASE + I915_HDMI_LPE_AUDIO_SIZE - 1; 103*a85cb24fSFrançois Tigeot rsc[1].flags = IORESOURCE_MEM; 104*a85cb24fSFrançois Tigeot rsc[1].name = "hdmi-lpe-audio-mmio"; 105*a85cb24fSFrançois Tigeot 106*a85cb24fSFrançois Tigeot pinfo.parent = dev->dev; 107*a85cb24fSFrançois Tigeot pinfo.name = "hdmi-lpe-audio"; 108*a85cb24fSFrançois Tigeot pinfo.id = -1; 109*a85cb24fSFrançois Tigeot pinfo.res = rsc; 110*a85cb24fSFrançois Tigeot pinfo.num_res = 2; 111*a85cb24fSFrançois Tigeot pinfo.data = pdata; 112*a85cb24fSFrançois Tigeot pinfo.size_data = sizeof(*pdata); 113*a85cb24fSFrançois Tigeot pinfo.dma_mask = DMA_BIT_MASK(32); 114*a85cb24fSFrançois Tigeot 115*a85cb24fSFrançois Tigeot spin_lock_init(&pdata->lpe_audio_slock); 116*a85cb24fSFrançois Tigeot 117*a85cb24fSFrançois Tigeot platdev = platform_device_register_full(&pinfo); 118*a85cb24fSFrançois Tigeot if (IS_ERR(platdev)) { 119*a85cb24fSFrançois Tigeot ret = PTR_ERR(platdev); 120*a85cb24fSFrançois Tigeot DRM_ERROR("Failed to allocate LPE audio platform device\n"); 121*a85cb24fSFrançois Tigeot goto err; 122*a85cb24fSFrançois Tigeot } 123*a85cb24fSFrançois Tigeot 124*a85cb24fSFrançois Tigeot kfree(rsc); 125*a85cb24fSFrançois Tigeot 126*a85cb24fSFrançois Tigeot pm_runtime_forbid(&platdev->dev); 127*a85cb24fSFrançois Tigeot pm_runtime_set_active(&platdev->dev); 128*a85cb24fSFrançois Tigeot pm_runtime_enable(&platdev->dev); 129*a85cb24fSFrançois Tigeot 130*a85cb24fSFrançois Tigeot pm_runtime_forbid(&platdev->dev); 131*a85cb24fSFrançois Tigeot pm_runtime_set_active(&platdev->dev); 132*a85cb24fSFrançois Tigeot pm_runtime_enable(&platdev->dev); 133*a85cb24fSFrançois Tigeot 134*a85cb24fSFrançois Tigeot return platdev; 135*a85cb24fSFrançois Tigeot 136*a85cb24fSFrançois Tigeot err: 137*a85cb24fSFrançois Tigeot kfree(rsc); 138*a85cb24fSFrançois Tigeot kfree(pdata); 139*a85cb24fSFrançois Tigeot return ERR_PTR(ret); 140*a85cb24fSFrançois Tigeot } 141*a85cb24fSFrançois Tigeot 142*a85cb24fSFrançois Tigeot static void lpe_audio_platdev_destroy(struct drm_i915_private *dev_priv) 143*a85cb24fSFrançois Tigeot { 144*a85cb24fSFrançois Tigeot /* XXX Note that platform_device_register_full() allocates a dma_mask 145*a85cb24fSFrançois Tigeot * and never frees it. We can't free it here as we cannot guarantee 146*a85cb24fSFrançois Tigeot * this is the last reference (i.e. that the dma_mask will not be 147*a85cb24fSFrançois Tigeot * used after our unregister). So ee choose to leak the sizeof(u64) 148*a85cb24fSFrançois Tigeot * allocation here - it should be fixed in the platform_device rather 149*a85cb24fSFrançois Tigeot * than us fiddle with its internals. 150*a85cb24fSFrançois Tigeot */ 151*a85cb24fSFrançois Tigeot 152*a85cb24fSFrançois Tigeot platform_device_unregister(dev_priv->lpe_audio.platdev); 153*a85cb24fSFrançois Tigeot } 154*a85cb24fSFrançois Tigeot 155*a85cb24fSFrançois Tigeot static void lpe_audio_irq_unmask(struct irq_data *d) 156*a85cb24fSFrançois Tigeot { 157*a85cb24fSFrançois Tigeot } 158*a85cb24fSFrançois Tigeot 159*a85cb24fSFrançois Tigeot static void lpe_audio_irq_mask(struct irq_data *d) 160*a85cb24fSFrançois Tigeot { 161*a85cb24fSFrançois Tigeot } 162*a85cb24fSFrançois Tigeot 163*a85cb24fSFrançois Tigeot static struct irq_chip lpe_audio_irqchip = { 164*a85cb24fSFrançois Tigeot .name = "hdmi_lpe_audio_irqchip", 165*a85cb24fSFrançois Tigeot .irq_mask = lpe_audio_irq_mask, 166*a85cb24fSFrançois Tigeot .irq_unmask = lpe_audio_irq_unmask, 167*a85cb24fSFrançois Tigeot }; 168*a85cb24fSFrançois Tigeot 169*a85cb24fSFrançois Tigeot static int lpe_audio_irq_init(struct drm_i915_private *dev_priv) 170*a85cb24fSFrançois Tigeot { 171*a85cb24fSFrançois Tigeot int irq = dev_priv->lpe_audio.irq; 172*a85cb24fSFrançois Tigeot 173*a85cb24fSFrançois Tigeot WARN_ON(!intel_irqs_enabled(dev_priv)); 174*a85cb24fSFrançois Tigeot irq_set_chip_and_handler_name(irq, 175*a85cb24fSFrançois Tigeot &lpe_audio_irqchip, 176*a85cb24fSFrançois Tigeot handle_simple_irq, 177*a85cb24fSFrançois Tigeot "hdmi_lpe_audio_irq_handler"); 178*a85cb24fSFrançois Tigeot 179*a85cb24fSFrançois Tigeot return irq_set_chip_data(irq, dev_priv); 180*a85cb24fSFrançois Tigeot } 181*a85cb24fSFrançois Tigeot 182*a85cb24fSFrançois Tigeot static bool lpe_audio_detect(struct drm_i915_private *dev_priv) 183*a85cb24fSFrançois Tigeot { 184*a85cb24fSFrançois Tigeot int lpe_present = false; 185*a85cb24fSFrançois Tigeot 186*a85cb24fSFrançois Tigeot if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { 187*a85cb24fSFrançois Tigeot static const struct pci_device_id atom_hdaudio_ids[] = { 188*a85cb24fSFrançois Tigeot /* Baytrail */ 189*a85cb24fSFrançois Tigeot {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0f04)}, 190*a85cb24fSFrançois Tigeot /* Braswell */ 191*a85cb24fSFrançois Tigeot {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2284)}, 192*a85cb24fSFrançois Tigeot {} 193*a85cb24fSFrançois Tigeot }; 194*a85cb24fSFrançois Tigeot 195*a85cb24fSFrançois Tigeot if (!pci_dev_present(atom_hdaudio_ids)) { 196*a85cb24fSFrançois Tigeot DRM_INFO("%s\n", "HDaudio controller not detected, using LPE audio instead\n"); 197*a85cb24fSFrançois Tigeot lpe_present = true; 198*a85cb24fSFrançois Tigeot } 199*a85cb24fSFrançois Tigeot } 200*a85cb24fSFrançois Tigeot return lpe_present; 201*a85cb24fSFrançois Tigeot } 202*a85cb24fSFrançois Tigeot 203*a85cb24fSFrançois Tigeot static int lpe_audio_setup(struct drm_i915_private *dev_priv) 204*a85cb24fSFrançois Tigeot { 205*a85cb24fSFrançois Tigeot int ret; 206*a85cb24fSFrançois Tigeot 207*a85cb24fSFrançois Tigeot dev_priv->lpe_audio.irq = irq_alloc_desc(0); 208*a85cb24fSFrançois Tigeot if (dev_priv->lpe_audio.irq < 0) { 209*a85cb24fSFrançois Tigeot DRM_ERROR("Failed to allocate IRQ desc: %d\n", 210*a85cb24fSFrançois Tigeot dev_priv->lpe_audio.irq); 211*a85cb24fSFrançois Tigeot ret = dev_priv->lpe_audio.irq; 212*a85cb24fSFrançois Tigeot goto err; 213*a85cb24fSFrançois Tigeot } 214*a85cb24fSFrançois Tigeot 215*a85cb24fSFrançois Tigeot DRM_DEBUG("irq = %d\n", dev_priv->lpe_audio.irq); 216*a85cb24fSFrançois Tigeot 217*a85cb24fSFrançois Tigeot ret = lpe_audio_irq_init(dev_priv); 218*a85cb24fSFrançois Tigeot 219*a85cb24fSFrançois Tigeot if (ret) { 220*a85cb24fSFrançois Tigeot DRM_ERROR("Failed to initialize irqchip for lpe audio: %d\n", 221*a85cb24fSFrançois Tigeot ret); 222*a85cb24fSFrançois Tigeot goto err_free_irq; 223*a85cb24fSFrançois Tigeot } 224*a85cb24fSFrançois Tigeot 225*a85cb24fSFrançois Tigeot dev_priv->lpe_audio.platdev = lpe_audio_platdev_create(dev_priv); 226*a85cb24fSFrançois Tigeot 227*a85cb24fSFrançois Tigeot if (IS_ERR(dev_priv->lpe_audio.platdev)) { 228*a85cb24fSFrançois Tigeot ret = PTR_ERR(dev_priv->lpe_audio.platdev); 229*a85cb24fSFrançois Tigeot DRM_ERROR("Failed to create lpe audio platform device: %d\n", 230*a85cb24fSFrançois Tigeot ret); 231*a85cb24fSFrançois Tigeot goto err_free_irq; 232*a85cb24fSFrançois Tigeot } 233*a85cb24fSFrançois Tigeot 234*a85cb24fSFrançois Tigeot /* enable chicken bit; at least this is required for Dell Wyse 3040 235*a85cb24fSFrançois Tigeot * with DP outputs (but only sometimes by some reason!) 236*a85cb24fSFrançois Tigeot */ 237*a85cb24fSFrançois Tigeot I915_WRITE(VLV_AUD_CHICKEN_BIT_REG, VLV_CHICKEN_BIT_DBG_ENABLE); 238*a85cb24fSFrançois Tigeot 239*a85cb24fSFrançois Tigeot return 0; 240*a85cb24fSFrançois Tigeot err_free_irq: 241*a85cb24fSFrançois Tigeot irq_free_desc(dev_priv->lpe_audio.irq); 242*a85cb24fSFrançois Tigeot err: 243*a85cb24fSFrançois Tigeot dev_priv->lpe_audio.irq = -1; 244*a85cb24fSFrançois Tigeot dev_priv->lpe_audio.platdev = NULL; 245*a85cb24fSFrançois Tigeot return ret; 246*a85cb24fSFrançois Tigeot } 247*a85cb24fSFrançois Tigeot #endif 248*a85cb24fSFrançois Tigeot 249*a85cb24fSFrançois Tigeot /** 250*a85cb24fSFrançois Tigeot * intel_lpe_audio_irq_handler() - forwards the LPE audio irq 251*a85cb24fSFrançois Tigeot * @dev_priv: the i915 drm device private data 252*a85cb24fSFrançois Tigeot * 253*a85cb24fSFrançois Tigeot * the LPE Audio irq is forwarded to the irq handler registered by LPE audio 254*a85cb24fSFrançois Tigeot * driver. 255*a85cb24fSFrançois Tigeot */ 256*a85cb24fSFrançois Tigeot void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv) 257*a85cb24fSFrançois Tigeot { 258*a85cb24fSFrançois Tigeot #if 0 259*a85cb24fSFrançois Tigeot int ret; 260*a85cb24fSFrançois Tigeot 261*a85cb24fSFrançois Tigeot if (!HAS_LPE_AUDIO(dev_priv)) 262*a85cb24fSFrançois Tigeot return; 263*a85cb24fSFrançois Tigeot 264*a85cb24fSFrançois Tigeot ret = generic_handle_irq(dev_priv->lpe_audio.irq); 265*a85cb24fSFrançois Tigeot if (ret) 266*a85cb24fSFrançois Tigeot DRM_ERROR_RATELIMITED("error handling LPE audio irq: %d\n", 267*a85cb24fSFrançois Tigeot ret); 268*a85cb24fSFrançois Tigeot #endif 269*a85cb24fSFrançois Tigeot } 270*a85cb24fSFrançois Tigeot 271*a85cb24fSFrançois Tigeot /** 272*a85cb24fSFrançois Tigeot * intel_lpe_audio_init() - detect and setup the bridge between HDMI LPE Audio 273*a85cb24fSFrançois Tigeot * driver and i915 274*a85cb24fSFrançois Tigeot * @dev_priv: the i915 drm device private data 275*a85cb24fSFrançois Tigeot * 276*a85cb24fSFrançois Tigeot * Return: 0 if successful. non-zero if detection or 277*a85cb24fSFrançois Tigeot * llocation/initialization fails 278*a85cb24fSFrançois Tigeot */ 279*a85cb24fSFrançois Tigeot int intel_lpe_audio_init(struct drm_i915_private *dev_priv) 280*a85cb24fSFrançois Tigeot { 281*a85cb24fSFrançois Tigeot int ret = -ENODEV; 282*a85cb24fSFrançois Tigeot 283*a85cb24fSFrançois Tigeot #if 0 284*a85cb24fSFrançois Tigeot if (lpe_audio_detect(dev_priv)) { 285*a85cb24fSFrançois Tigeot ret = lpe_audio_setup(dev_priv); 286*a85cb24fSFrançois Tigeot if (ret < 0) 287*a85cb24fSFrançois Tigeot DRM_ERROR("failed to setup LPE Audio bridge\n"); 288*a85cb24fSFrançois Tigeot } 289*a85cb24fSFrançois Tigeot #endif 290*a85cb24fSFrançois Tigeot return ret; 291*a85cb24fSFrançois Tigeot } 292*a85cb24fSFrançois Tigeot 293*a85cb24fSFrançois Tigeot /** 294*a85cb24fSFrançois Tigeot * intel_lpe_audio_teardown() - destroy the bridge between HDMI LPE 295*a85cb24fSFrançois Tigeot * audio driver and i915 296*a85cb24fSFrançois Tigeot * @dev_priv: the i915 drm device private data 297*a85cb24fSFrançois Tigeot * 298*a85cb24fSFrançois Tigeot * release all the resources for LPE audio <-> i915 bridge. 299*a85cb24fSFrançois Tigeot */ 300*a85cb24fSFrançois Tigeot void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv) 301*a85cb24fSFrançois Tigeot { 302*a85cb24fSFrançois Tigeot #if 0 303*a85cb24fSFrançois Tigeot struct irq_desc *desc; 304*a85cb24fSFrançois Tigeot 305*a85cb24fSFrançois Tigeot if (!HAS_LPE_AUDIO(dev_priv)) 306*a85cb24fSFrançois Tigeot return; 307*a85cb24fSFrançois Tigeot 308*a85cb24fSFrançois Tigeot desc = irq_to_desc(dev_priv->lpe_audio.irq); 309*a85cb24fSFrançois Tigeot 310*a85cb24fSFrançois Tigeot lpe_audio_platdev_destroy(dev_priv); 311*a85cb24fSFrançois Tigeot 312*a85cb24fSFrançois Tigeot irq_free_desc(dev_priv->lpe_audio.irq); 313*a85cb24fSFrançois Tigeot #endif 314*a85cb24fSFrançois Tigeot } 315*a85cb24fSFrançois Tigeot 316*a85cb24fSFrançois Tigeot 317*a85cb24fSFrançois Tigeot /** 318*a85cb24fSFrançois Tigeot * intel_lpe_audio_notify() - notify lpe audio event 319*a85cb24fSFrançois Tigeot * audio driver and i915 320*a85cb24fSFrançois Tigeot * @dev_priv: the i915 drm device private data 321*a85cb24fSFrançois Tigeot * @eld : ELD data 322*a85cb24fSFrançois Tigeot * @pipe: pipe id 323*a85cb24fSFrançois Tigeot * @port: port id 324*a85cb24fSFrançois Tigeot * @tmds_clk_speed: tmds clock frequency in Hz 325*a85cb24fSFrançois Tigeot * 326*a85cb24fSFrançois Tigeot * Notify lpe audio driver of eld change. 327*a85cb24fSFrançois Tigeot */ 328*a85cb24fSFrançois Tigeot void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, 329*a85cb24fSFrançois Tigeot void *eld, int port, int pipe, int tmds_clk_speed, 330*a85cb24fSFrançois Tigeot bool dp_output, int link_rate) 331*a85cb24fSFrançois Tigeot { 332*a85cb24fSFrançois Tigeot #if 0 333*a85cb24fSFrançois Tigeot unsigned long irq_flags; 334*a85cb24fSFrançois Tigeot struct intel_hdmi_lpe_audio_pdata *pdata = NULL; 335*a85cb24fSFrançois Tigeot u32 audio_enable; 336*a85cb24fSFrançois Tigeot 337*a85cb24fSFrançois Tigeot if (!HAS_LPE_AUDIO(dev_priv)) 338*a85cb24fSFrançois Tigeot return; 339*a85cb24fSFrançois Tigeot 340*a85cb24fSFrançois Tigeot pdata = dev_get_platdata( 341*a85cb24fSFrançois Tigeot &(dev_priv->lpe_audio.platdev->dev)); 342*a85cb24fSFrançois Tigeot 343*a85cb24fSFrançois Tigeot spin_lock_irqsave(&pdata->lpe_audio_slock, irq_flags); 344*a85cb24fSFrançois Tigeot 345*a85cb24fSFrançois Tigeot audio_enable = I915_READ(VLV_AUD_PORT_EN_DBG(port)); 346*a85cb24fSFrançois Tigeot 347*a85cb24fSFrançois Tigeot if (eld != NULL) { 348*a85cb24fSFrançois Tigeot memcpy(pdata->eld.eld_data, eld, 349*a85cb24fSFrançois Tigeot HDMI_MAX_ELD_BYTES); 350*a85cb24fSFrançois Tigeot pdata->eld.port_id = port; 351*a85cb24fSFrançois Tigeot pdata->eld.pipe_id = pipe; 352*a85cb24fSFrançois Tigeot pdata->hdmi_connected = true; 353*a85cb24fSFrançois Tigeot 354*a85cb24fSFrançois Tigeot pdata->dp_output = dp_output; 355*a85cb24fSFrançois Tigeot if (tmds_clk_speed) 356*a85cb24fSFrançois Tigeot pdata->tmds_clock_speed = tmds_clk_speed; 357*a85cb24fSFrançois Tigeot if (link_rate) 358*a85cb24fSFrançois Tigeot pdata->link_rate = link_rate; 359*a85cb24fSFrançois Tigeot 360*a85cb24fSFrançois Tigeot /* Unmute the amp for both DP and HDMI */ 361*a85cb24fSFrançois Tigeot I915_WRITE(VLV_AUD_PORT_EN_DBG(port), 362*a85cb24fSFrançois Tigeot audio_enable & ~VLV_AMP_MUTE); 363*a85cb24fSFrançois Tigeot 364*a85cb24fSFrançois Tigeot } else { 365*a85cb24fSFrançois Tigeot memset(pdata->eld.eld_data, 0, 366*a85cb24fSFrançois Tigeot HDMI_MAX_ELD_BYTES); 367*a85cb24fSFrançois Tigeot pdata->hdmi_connected = false; 368*a85cb24fSFrançois Tigeot pdata->dp_output = false; 369*a85cb24fSFrançois Tigeot 370*a85cb24fSFrançois Tigeot /* Mute the amp for both DP and HDMI */ 371*a85cb24fSFrançois Tigeot I915_WRITE(VLV_AUD_PORT_EN_DBG(port), 372*a85cb24fSFrançois Tigeot audio_enable | VLV_AMP_MUTE); 373*a85cb24fSFrançois Tigeot } 374*a85cb24fSFrançois Tigeot 375*a85cb24fSFrançois Tigeot if (pdata->notify_audio_lpe) 376*a85cb24fSFrançois Tigeot pdata->notify_audio_lpe(dev_priv->lpe_audio.platdev); 377*a85cb24fSFrançois Tigeot else 378*a85cb24fSFrançois Tigeot pdata->notify_pending = true; 379*a85cb24fSFrançois Tigeot 380*a85cb24fSFrançois Tigeot spin_unlock_irqrestore(&pdata->lpe_audio_slock, 381*a85cb24fSFrançois Tigeot irq_flags); 382*a85cb24fSFrançois Tigeot #endif 383*a85cb24fSFrançois Tigeot } 384