Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
98d8fc6c ML |
2 | /* |
3 | * hdac_i915.c - routines for sync between HD-A core and i915 display driver | |
98d8fc6c ML |
4 | */ |
5 | ||
6 | #include <linux/init.h> | |
7 | #include <linux/module.h> | |
8 | #include <linux/pci.h> | |
98d8fc6c ML |
9 | #include <sound/core.h> |
10 | #include <sound/hdaudio.h> | |
11 | #include <sound/hda_i915.h> | |
bb03ed21 | 12 | #include <sound/hda_register.h> |
2e8c9038 ML |
13 | #include <video/nomodeset.h> |
14 | ||
15 | static int gpu_bind = -1; | |
16 | module_param(gpu_bind, int, 0644); | |
17 | MODULE_PARM_DESC(gpu_bind, "Whether to bind sound component to GPU " | |
18 | "(1=always, 0=never, -1=on nomodeset(default))"); | |
98d8fc6c | 19 | |
78dd5e21 | 20 | /** |
bb03ed21 | 21 | * snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW |
78dd5e21 TI |
22 | * @bus: HDA core bus |
23 | * | |
bb03ed21 TI |
24 | * Intel HSW/BDW display HDA controller is in GPU. Both its power and link BCLK |
25 | * depends on GPU. Two Extended Mode registers EM4 (M value) and EM5 (N Value) | |
26 | * are used to convert CDClk (Core Display Clock) to 24MHz BCLK: | |
27 | * BCLK = CDCLK * M / N | |
28 | * The values will be lost when the display power well is disabled and need to | |
29 | * be restored to avoid abnormal playback speed. | |
78dd5e21 | 30 | * |
bb03ed21 TI |
31 | * Call this function at initializing and changing power well, as well as |
32 | * at ELD notifier for the hotplug. | |
78dd5e21 | 33 | */ |
bb03ed21 | 34 | void snd_hdac_i915_set_bclk(struct hdac_bus *bus) |
98d8fc6c | 35 | { |
ae891abe | 36 | struct drm_audio_component *acomp = bus->audio_component; |
bb03ed21 TI |
37 | struct pci_dev *pci = to_pci_dev(bus->dev); |
38 | int cdclk_freq; | |
39 | unsigned int bclk_m, bclk_n; | |
40 | ||
41 | if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq) | |
42 | return; /* only for i915 binding */ | |
fd6f3a84 | 43 | if (!HDA_CONTROLLER_IS_HSW(pci)) |
bb03ed21 TI |
44 | return; /* only HSW/BDW */ |
45 | ||
46 | cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); | |
47 | switch (cdclk_freq) { | |
48 | case 337500: | |
49 | bclk_m = 16; | |
50 | bclk_n = 225; | |
51 | break; | |
52 | ||
53 | case 450000: | |
54 | default: /* default CDCLK 450MHz */ | |
55 | bclk_m = 4; | |
56 | bclk_n = 75; | |
57 | break; | |
58 | ||
59 | case 540000: | |
60 | bclk_m = 4; | |
61 | bclk_n = 90; | |
62 | break; | |
63 | ||
64 | case 675000: | |
65 | bclk_m = 8; | |
66 | bclk_n = 225; | |
67 | break; | |
68 | } | |
98d8fc6c | 69 | |
bb03ed21 TI |
70 | snd_hdac_chip_writew(bus, HSW_EM4, bclk_m); |
71 | snd_hdac_chip_writew(bus, HSW_EM5, bclk_n); | |
98d8fc6c | 72 | } |
bb03ed21 | 73 | EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk); |
98d8fc6c | 74 | |
502f389a | 75 | /* returns true if the devices can be connected for audio */ |
7b882fe3 KV |
76 | static bool connectivity_check(struct pci_dev *i915, struct pci_dev *hdac) |
77 | { | |
78 | struct pci_bus *bus_a = i915->bus, *bus_b = hdac->bus; | |
79 | ||
80 | /* directly connected on the same bus */ | |
81 | if (bus_a == bus_b) | |
82 | return true; | |
83 | ||
7b882fe3 KV |
84 | bus_a = bus_a->parent; |
85 | bus_b = bus_b->parent; | |
3f8c530f KV |
86 | |
87 | /* connected via parent bus (may be NULL!) */ | |
88 | if (bus_a == bus_b) | |
89 | return true; | |
90 | ||
7b882fe3 KV |
91 | if (!bus_a || !bus_b) |
92 | return false; | |
3f8c530f KV |
93 | |
94 | /* | |
95 | * on i915 discrete GPUs with embedded HDA audio, the two | |
96 | * devices are connected via 2nd level PCI bridge | |
97 | */ | |
7b882fe3 KV |
98 | bus_a = bus_a->parent; |
99 | bus_b = bus_b->parent; | |
100 | if (bus_a && bus_a == bus_b) | |
101 | return true; | |
102 | ||
103 | return false; | |
104 | } | |
105 | ||
8857c7d0 DV |
106 | static int i915_component_master_match(struct device *dev, int subcomponent, |
107 | void *data) | |
e2dc7d7d | 108 | { |
7b882fe3 KV |
109 | struct pci_dev *hdac_pci, *i915_pci; |
110 | struct hdac_bus *bus = data; | |
111 | ||
112 | if (!dev_is_pci(dev)) | |
113 | return 0; | |
114 | ||
115 | hdac_pci = to_pci_dev(bus->dev); | |
116 | i915_pci = to_pci_dev(dev); | |
117 | ||
e8e3f869 ML |
118 | if ((!strcmp(dev->driver->name, "i915") || |
119 | !strcmp(dev->driver->name, "xe")) && | |
7b882fe3 KV |
120 | subcomponent == I915_COMPONENT_AUDIO && |
121 | connectivity_check(i915_pci, hdac_pci)) | |
122 | return 1; | |
123 | ||
124 | return 0; | |
98d8fc6c ML |
125 | } |
126 | ||
c9db8a30 KV |
127 | /* check whether Intel graphics is present and reachable */ |
128 | static int i915_gfx_present(struct pci_dev *hdac_pci) | |
bfa5fb14 | 129 | { |
bd6e4c4a CR |
130 | /* List of known platforms with no i915 support. */ |
131 | static const struct pci_device_id denylist[] = { | |
132 | /* CNL */ | |
133 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a40), 0x030000, 0xff0000 }, | |
134 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a41), 0x030000, 0xff0000 }, | |
135 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a42), 0x030000, 0xff0000 }, | |
136 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a44), 0x030000, 0xff0000 }, | |
137 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a49), 0x030000, 0xff0000 }, | |
138 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a4a), 0x030000, 0xff0000 }, | |
139 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a4c), 0x030000, 0xff0000 }, | |
140 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a50), 0x030000, 0xff0000 }, | |
141 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a51), 0x030000, 0xff0000 }, | |
142 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a52), 0x030000, 0xff0000 }, | |
143 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a54), 0x030000, 0xff0000 }, | |
144 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a59), 0x030000, 0xff0000 }, | |
145 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a5a), 0x030000, 0xff0000 }, | |
146 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a5c), 0x030000, 0xff0000 }, | |
147 | /* LKF */ | |
148 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9840), 0x030000, 0xff0000 }, | |
149 | {} | |
150 | }; | |
c9db8a30 | 151 | struct pci_dev *display_dev = NULL; |
c9db8a30 | 152 | |
2e8c9038 ML |
153 | if (!gpu_bind || (gpu_bind < 0 && video_firmware_drivers_only())) |
154 | return false; | |
155 | ||
36a38c53 | 156 | for_each_pci_dev(display_dev) { |
bd6e4c4a CR |
157 | if (display_dev->vendor != PCI_VENDOR_ID_INTEL || |
158 | (display_dev->class >> 16) != PCI_BASE_CLASS_DISPLAY) | |
159 | continue; | |
160 | ||
161 | if (pci_match_id(denylist, display_dev)) | |
162 | continue; | |
163 | ||
164 | if (connectivity_check(display_dev, hdac_pci)) { | |
00fd7cfa | 165 | pci_dev_put(display_dev); |
36a38c53 | 166 | return true; |
00fd7cfa | 167 | } |
36a38c53 | 168 | } |
c9db8a30 | 169 | |
36a38c53 | 170 | return false; |
bfa5fb14 TI |
171 | } |
172 | ||
78dd5e21 TI |
173 | /** |
174 | * snd_hdac_i915_init - Initialize i915 audio component | |
175 | * @bus: HDA core bus | |
176 | * | |
177 | * This function is supposed to be used only by a HD-audio controller | |
178 | * driver that needs the interaction with i915 graphics. | |
179 | * | |
180 | * This function initializes and sets up the audio component to communicate | |
181 | * with i915 graphics driver. | |
182 | * | |
183 | * Returns zero for success or a negative error code. | |
184 | */ | |
e6d0c13e | 185 | int snd_hdac_i915_init(struct hdac_bus *bus) |
98d8fc6c | 186 | { |
ae891abe | 187 | struct drm_audio_component *acomp; |
a57942bf | 188 | int err; |
d745f5e7 | 189 | |
c9db8a30 | 190 | if (!i915_gfx_present(to_pci_dev(bus->dev))) |
bfa5fb14 TI |
191 | return -ENODEV; |
192 | ||
96e503f9 | 193 | err = snd_hdac_acomp_init(bus, NULL, |
a57942bf TI |
194 | i915_component_master_match, |
195 | sizeof(struct i915_audio_component) - sizeof(*acomp)); | |
196 | if (err < 0) | |
197 | return err; | |
198 | acomp = bus->audio_component; | |
199 | if (!acomp) | |
200 | return -ENODEV; | |
98d8fc6c | 201 | if (!acomp->ops) { |
a57942bf | 202 | snd_hdac_acomp_exit(bus); |
e6d0c13e ML |
203 | return dev_err_probe(bus->dev, -EPROBE_DEFER, |
204 | "couldn't bind with audio component\n"); | |
98d8fc6c | 205 | } |
98d8fc6c | 206 | return 0; |
98d8fc6c ML |
207 | } |
208 | EXPORT_SYMBOL_GPL(snd_hdac_i915_init); |