linux/sound/hda/hdac_i915.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  hdac_i915.c - routines for sync between HD-A core and i915 display driver
   4 */
   5
   6#include <linux/init.h>
   7#include <linux/module.h>
   8#include <linux/pci.h>
   9#include <sound/core.h>
  10#include <sound/hdaudio.h>
  11#include <sound/hda_i915.h>
  12#include <sound/hda_register.h>
  13
  14#define IS_HSW_CONTROLLER(pci) (((pci)->device == 0x0a0c) || \
  15                                ((pci)->device == 0x0c0c) || \
  16                                ((pci)->device == 0x0d0c) || \
  17                                ((pci)->device == 0x160c))
  18
  19/**
  20 * snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW
  21 * @bus: HDA core bus
  22 *
  23 * Intel HSW/BDW display HDA controller is in GPU. Both its power and link BCLK
  24 * depends on GPU. Two Extended Mode registers EM4 (M value) and EM5 (N Value)
  25 * are used to convert CDClk (Core Display Clock) to 24MHz BCLK:
  26 * BCLK = CDCLK * M / N
  27 * The values will be lost when the display power well is disabled and need to
  28 * be restored to avoid abnormal playback speed.
  29 *
  30 * Call this function at initializing and changing power well, as well as
  31 * at ELD notifier for the hotplug.
  32 */
  33void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
  34{
  35        struct drm_audio_component *acomp = bus->audio_component;
  36        struct pci_dev *pci = to_pci_dev(bus->dev);
  37        int cdclk_freq;
  38        unsigned int bclk_m, bclk_n;
  39
  40        if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq)
  41                return; /* only for i915 binding */
  42        if (!IS_HSW_CONTROLLER(pci))
  43                return; /* only HSW/BDW */
  44
  45        cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev);
  46        switch (cdclk_freq) {
  47        case 337500:
  48                bclk_m = 16;
  49                bclk_n = 225;
  50                break;
  51
  52        case 450000:
  53        default: /* default CDCLK 450MHz */
  54                bclk_m = 4;
  55                bclk_n = 75;
  56                break;
  57
  58        case 540000:
  59                bclk_m = 4;
  60                bclk_n = 90;
  61                break;
  62
  63        case 675000:
  64                bclk_m = 8;
  65                bclk_n = 225;
  66                break;
  67        }
  68
  69        snd_hdac_chip_writew(bus, HSW_EM4, bclk_m);
  70        snd_hdac_chip_writew(bus, HSW_EM5, bclk_n);
  71}
  72EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk);
  73
  74/* returns true if the devices can be connected for audio */
  75static bool connectivity_check(struct pci_dev *i915, struct pci_dev *hdac)
  76{
  77        struct pci_bus *bus_a = i915->bus, *bus_b = hdac->bus;
  78
  79        /* directly connected on the same bus */
  80        if (bus_a == bus_b)
  81                return true;
  82
  83        /*
  84         * on i915 discrete GPUs with embedded HDA audio, the two
  85         * devices are connected via 2nd level PCI bridge
  86         */
  87        bus_a = bus_a->parent;
  88        bus_b = bus_b->parent;
  89        if (!bus_a || !bus_b)
  90                return false;
  91        bus_a = bus_a->parent;
  92        bus_b = bus_b->parent;
  93        if (bus_a && bus_a == bus_b)
  94                return true;
  95
  96        return false;
  97}
  98
  99static int i915_component_master_match(struct device *dev, int subcomponent,
 100                                       void *data)
 101{
 102        struct pci_dev *hdac_pci, *i915_pci;
 103        struct hdac_bus *bus = data;
 104
 105        if (!dev_is_pci(dev))
 106                return 0;
 107
 108        hdac_pci = to_pci_dev(bus->dev);
 109        i915_pci = to_pci_dev(dev);
 110
 111        if (!strcmp(dev->driver->name, "i915") &&
 112            subcomponent == I915_COMPONENT_AUDIO &&
 113            connectivity_check(i915_pci, hdac_pci))
 114                return 1;
 115
 116        return 0;
 117}
 118
 119/* check whether intel graphics is present */
 120static bool i915_gfx_present(void)
 121{
 122        static const struct pci_device_id ids[] = {
 123                { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
 124                  .class = PCI_BASE_CLASS_DISPLAY << 16,
 125                  .class_mask = 0xff << 16 },
 126                {}
 127        };
 128        return pci_dev_present(ids);
 129}
 130
 131/**
 132 * snd_hdac_i915_init - Initialize i915 audio component
 133 * @bus: HDA core bus
 134 *
 135 * This function is supposed to be used only by a HD-audio controller
 136 * driver that needs the interaction with i915 graphics.
 137 *
 138 * This function initializes and sets up the audio component to communicate
 139 * with i915 graphics driver.
 140 *
 141 * Returns zero for success or a negative error code.
 142 */
 143int snd_hdac_i915_init(struct hdac_bus *bus)
 144{
 145        struct drm_audio_component *acomp;
 146        int err;
 147
 148        if (!i915_gfx_present())
 149                return -ENODEV;
 150
 151        err = snd_hdac_acomp_init(bus, NULL,
 152                                  i915_component_master_match,
 153                                  sizeof(struct i915_audio_component) - sizeof(*acomp));
 154        if (err < 0)
 155                return err;
 156        acomp = bus->audio_component;
 157        if (!acomp)
 158                return -ENODEV;
 159        if (!acomp->ops) {
 160                if (!IS_ENABLED(CONFIG_MODULES) ||
 161                    !request_module("i915")) {
 162                        /* 60s timeout */
 163                        wait_for_completion_timeout(&acomp->master_bind_complete,
 164                                                    msecs_to_jiffies(60 * 1000));
 165                }
 166        }
 167        if (!acomp->ops) {
 168                dev_info(bus->dev, "couldn't bind with audio component\n");
 169                snd_hdac_acomp_exit(bus);
 170                return -ENODEV;
 171        }
 172        return 0;
 173}
 174EXPORT_SYMBOL_GPL(snd_hdac_i915_init);
 175