Branch data Line data Source code
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 : : static struct completion bind_complete; 15 : : 16 : : #define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \ 17 : : ((pci)->device == 0x0c0c) || \ 18 : : ((pci)->device == 0x0d0c) || \ 19 : : ((pci)->device == 0x160c)) 20 : : 21 : : /** 22 : : * snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW 23 : : * @bus: HDA core bus 24 : : * 25 : : * Intel HSW/BDW display HDA controller is in GPU. Both its power and link BCLK 26 : : * depends on GPU. Two Extended Mode registers EM4 (M value) and EM5 (N Value) 27 : : * are used to convert CDClk (Core Display Clock) to 24MHz BCLK: 28 : : * BCLK = CDCLK * M / N 29 : : * The values will be lost when the display power well is disabled and need to 30 : : * be restored to avoid abnormal playback speed. 31 : : * 32 : : * Call this function at initializing and changing power well, as well as 33 : : * at ELD notifier for the hotplug. 34 : : */ 35 : 0 : void snd_hdac_i915_set_bclk(struct hdac_bus *bus) 36 : : { 37 : 0 : struct drm_audio_component *acomp = bus->audio_component; 38 : 0 : struct pci_dev *pci = to_pci_dev(bus->dev); 39 : 0 : int cdclk_freq; 40 : 0 : unsigned int bclk_m, bclk_n; 41 : : 42 [ # # # # : 0 : if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq) # # ] 43 : : return; /* only for i915 binding */ 44 [ # # # # : 0 : if (!CONTROLLER_IN_GPU(pci)) # # ] 45 : : return; /* only HSW/BDW */ 46 : : 47 : 0 : cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); 48 [ # # # # ]: 0 : switch (cdclk_freq) { 49 : : case 337500: 50 : : bclk_m = 16; 51 : : bclk_n = 225; 52 : : break; 53 : : 54 : 0 : case 450000: 55 : : default: /* default CDCLK 450MHz */ 56 : 0 : bclk_m = 4; 57 : 0 : bclk_n = 75; 58 : 0 : break; 59 : : 60 : 0 : case 540000: 61 : 0 : bclk_m = 4; 62 : 0 : bclk_n = 90; 63 : 0 : break; 64 : : 65 : 0 : case 675000: 66 : 0 : bclk_m = 8; 67 : 0 : bclk_n = 225; 68 : 0 : break; 69 : : } 70 : : 71 : 0 : snd_hdac_chip_writew(bus, HSW_EM4, bclk_m); 72 : 0 : snd_hdac_chip_writew(bus, HSW_EM5, bclk_n); 73 : : } 74 : : EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk); 75 : : 76 : 0 : static int i915_component_master_match(struct device *dev, int subcomponent, 77 : : void *data) 78 : : { 79 [ # # # # ]: 0 : return !strcmp(dev->driver->name, "i915") && 80 : : subcomponent == I915_COMPONENT_AUDIO; 81 : : } 82 : : 83 : : /* check whether intel graphics is present */ 84 : 0 : static bool i915_gfx_present(void) 85 : : { 86 : 0 : static const struct pci_device_id ids[] = { 87 : : { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), 88 : : .class = PCI_BASE_CLASS_DISPLAY << 16, 89 : : .class_mask = 0xff << 16 }, 90 : : {} 91 : : }; 92 : 0 : return pci_dev_present(ids); 93 : : } 94 : : 95 : 0 : static int i915_master_bind(struct device *dev, 96 : : struct drm_audio_component *acomp) 97 : : { 98 : 0 : complete_all(&bind_complete); 99 : : /* clear audio_ops here as it was needed only for completion call */ 100 : 0 : acomp->audio_ops = NULL; 101 : 0 : return 0; 102 : : } 103 : : 104 : : static const struct drm_audio_component_audio_ops i915_init_ops = { 105 : : .master_bind = i915_master_bind 106 : : }; 107 : : 108 : : /** 109 : : * snd_hdac_i915_init - Initialize i915 audio component 110 : : * @bus: HDA core bus 111 : : * 112 : : * This function is supposed to be used only by a HD-audio controller 113 : : * driver that needs the interaction with i915 graphics. 114 : : * 115 : : * This function initializes and sets up the audio component to communicate 116 : : * with i915 graphics driver. 117 : : * 118 : : * Returns zero for success or a negative error code. 119 : : */ 120 : 0 : int snd_hdac_i915_init(struct hdac_bus *bus) 121 : : { 122 : 0 : struct drm_audio_component *acomp; 123 : 0 : int err; 124 : : 125 [ # # ]: 0 : if (!i915_gfx_present()) 126 : : return -ENODEV; 127 : : 128 : 0 : init_completion(&bind_complete); 129 : : 130 : 0 : err = snd_hdac_acomp_init(bus, &i915_init_ops, 131 : : i915_component_master_match, 132 : : sizeof(struct i915_audio_component) - sizeof(*acomp)); 133 [ # # ]: 0 : if (err < 0) 134 : : return err; 135 : 0 : acomp = bus->audio_component; 136 [ # # ]: 0 : if (!acomp) 137 : : return -ENODEV; 138 [ # # ]: 0 : if (!acomp->ops) { 139 [ # # ]: 0 : if (!IS_ENABLED(CONFIG_MODULES) || 140 : 0 : !request_module("i915")) { 141 : : /* 60s timeout */ 142 : 0 : wait_for_completion_timeout(&bind_complete, 143 : : msecs_to_jiffies(60 * 1000)); 144 : : } 145 : : } 146 [ # # ]: 0 : if (!acomp->ops) { 147 : 0 : dev_info(bus->dev, "couldn't bind with audio component\n"); 148 : 0 : snd_hdac_acomp_exit(bus); 149 : 0 : return -ENODEV; 150 : : } 151 : : return 0; 152 : : } 153 : : EXPORT_SYMBOL_GPL(snd_hdac_i915_init);