.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * hdac_i915.c - routines for sync between HD-A core and i915 display driver |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify it |
---|
5 | | - * under the terms of the GNU General Public License as published by the Free |
---|
6 | | - * Software Foundation; either version 2 of the License, or (at your option) |
---|
7 | | - * any later version. |
---|
8 | | - * |
---|
9 | | - * This program is distributed in the hope that it will be useful, but |
---|
10 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
---|
11 | | - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
---|
12 | | - * for more details. |
---|
13 | 4 | */ |
---|
14 | 5 | |
---|
15 | 6 | #include <linux/init.h> |
---|
.. | .. |
---|
20 | 11 | #include <sound/hda_i915.h> |
---|
21 | 12 | #include <sound/hda_register.h> |
---|
22 | 13 | |
---|
23 | | -static struct completion bind_complete; |
---|
24 | | - |
---|
25 | | -#define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \ |
---|
| 14 | +#define IS_HSW_CONTROLLER(pci) (((pci)->device == 0x0a0c) || \ |
---|
26 | 15 | ((pci)->device == 0x0c0c) || \ |
---|
27 | 16 | ((pci)->device == 0x0d0c) || \ |
---|
28 | 17 | ((pci)->device == 0x160c)) |
---|
.. | .. |
---|
50 | 39 | |
---|
51 | 40 | if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq) |
---|
52 | 41 | return; /* only for i915 binding */ |
---|
53 | | - if (!CONTROLLER_IN_GPU(pci)) |
---|
| 42 | + if (!IS_HSW_CONTROLLER(pci)) |
---|
54 | 43 | return; /* only HSW/BDW */ |
---|
55 | 44 | |
---|
56 | 45 | cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); |
---|
.. | .. |
---|
82 | 71 | } |
---|
83 | 72 | EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk); |
---|
84 | 73 | |
---|
85 | | -static int i915_component_master_match(struct device *dev, void *data) |
---|
| 74 | +/* returns true if the devices can be connected for audio */ |
---|
| 75 | +static bool connectivity_check(struct pci_dev *i915, struct pci_dev *hdac) |
---|
86 | 76 | { |
---|
87 | | - return !strcmp(dev->driver->name, "i915"); |
---|
| 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 | + |
---|
| 99 | +static 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; |
---|
88 | 117 | } |
---|
89 | 118 | |
---|
90 | 119 | /* check whether intel graphics is present */ |
---|
.. | .. |
---|
98 | 127 | }; |
---|
99 | 128 | return pci_dev_present(ids); |
---|
100 | 129 | } |
---|
101 | | - |
---|
102 | | -static int i915_master_bind(struct device *dev, |
---|
103 | | - struct drm_audio_component *acomp) |
---|
104 | | -{ |
---|
105 | | - complete_all(&bind_complete); |
---|
106 | | - /* clear audio_ops here as it was needed only for completion call */ |
---|
107 | | - acomp->audio_ops = NULL; |
---|
108 | | - return 0; |
---|
109 | | -} |
---|
110 | | - |
---|
111 | | -static const struct drm_audio_component_audio_ops i915_init_ops = { |
---|
112 | | - .master_bind = i915_master_bind |
---|
113 | | -}; |
---|
114 | 130 | |
---|
115 | 131 | /** |
---|
116 | 132 | * snd_hdac_i915_init - Initialize i915 audio component |
---|
.. | .. |
---|
132 | 148 | if (!i915_gfx_present()) |
---|
133 | 149 | return -ENODEV; |
---|
134 | 150 | |
---|
135 | | - init_completion(&bind_complete); |
---|
136 | | - |
---|
137 | | - err = snd_hdac_acomp_init(bus, &i915_init_ops, |
---|
| 151 | + err = snd_hdac_acomp_init(bus, NULL, |
---|
138 | 152 | i915_component_master_match, |
---|
139 | 153 | sizeof(struct i915_audio_component) - sizeof(*acomp)); |
---|
140 | 154 | if (err < 0) |
---|
.. | .. |
---|
146 | 160 | if (!IS_ENABLED(CONFIG_MODULES) || |
---|
147 | 161 | !request_module("i915")) { |
---|
148 | 162 | /* 60s timeout */ |
---|
149 | | - wait_for_completion_timeout(&bind_complete, |
---|
150 | | - msecs_to_jiffies(60 * 1000)); |
---|
| 163 | + wait_for_completion_timeout(&acomp->master_bind_complete, |
---|
| 164 | + msecs_to_jiffies(60 * 1000)); |
---|
151 | 165 | } |
---|
152 | 166 | } |
---|
153 | 167 | if (!acomp->ops) { |
---|