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> |
98d8fc6c | 13 | |
534ad9af | 14 | #define IS_HSW_CONTROLLER(pci) (((pci)->device == 0x0a0c) || \ |
bb03ed21 TI |
15 | ((pci)->device == 0x0c0c) || \ |
16 | ((pci)->device == 0x0d0c) || \ | |
17 | ((pci)->device == 0x160c)) | |
18 | ||
78dd5e21 | 19 | /** |
bb03ed21 | 20 | * snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW |
78dd5e21 TI |
21 | * @bus: HDA core bus |
22 | * | |
bb03ed21 TI |
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. | |
78dd5e21 | 29 | * |
bb03ed21 TI |
30 | * Call this function at initializing and changing power well, as well as |
31 | * at ELD notifier for the hotplug. | |
78dd5e21 | 32 | */ |
bb03ed21 | 33 | void snd_hdac_i915_set_bclk(struct hdac_bus *bus) |
98d8fc6c | 34 | { |
ae891abe | 35 | struct drm_audio_component *acomp = bus->audio_component; |
bb03ed21 TI |
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 */ | |
534ad9af | 42 | if (!IS_HSW_CONTROLLER(pci)) |
bb03ed21 TI |
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 | } | |
98d8fc6c | 68 | |
bb03ed21 TI |
69 | snd_hdac_chip_writew(bus, HSW_EM4, bclk_m); |
70 | snd_hdac_chip_writew(bus, HSW_EM5, bclk_n); | |
98d8fc6c | 71 | } |
bb03ed21 | 72 | EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk); |
98d8fc6c | 73 | |
502f389a | 74 | /* returns true if the devices can be connected for audio */ |
7b882fe3 KV |
75 | static 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 | ||
8857c7d0 DV |
99 | static int i915_component_master_match(struct device *dev, int subcomponent, |
100 | void *data) | |
e2dc7d7d | 101 | { |
7b882fe3 KV |
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; | |
98d8fc6c ML |
117 | } |
118 | ||
c9db8a30 KV |
119 | /* check whether Intel graphics is present and reachable */ |
120 | static int i915_gfx_present(struct pci_dev *hdac_pci) | |
bfa5fb14 | 121 | { |
c9db8a30 KV |
122 | unsigned int class = PCI_BASE_CLASS_DISPLAY << 16; |
123 | struct pci_dev *display_dev = NULL; | |
124 | bool match = false; | |
125 | ||
126 | do { | |
127 | display_dev = pci_get_class(class, display_dev); | |
128 | ||
129 | if (display_dev && display_dev->vendor == PCI_VENDOR_ID_INTEL && | |
00fd7cfa LDM |
130 | connectivity_check(display_dev, hdac_pci)) { |
131 | pci_dev_put(display_dev); | |
c9db8a30 | 132 | match = true; |
00fd7cfa | 133 | } |
c9db8a30 KV |
134 | } while (!match && display_dev); |
135 | ||
136 | return match; | |
bfa5fb14 TI |
137 | } |
138 | ||
78dd5e21 TI |
139 | /** |
140 | * snd_hdac_i915_init - Initialize i915 audio component | |
141 | * @bus: HDA core bus | |
142 | * | |
143 | * This function is supposed to be used only by a HD-audio controller | |
144 | * driver that needs the interaction with i915 graphics. | |
145 | * | |
146 | * This function initializes and sets up the audio component to communicate | |
147 | * with i915 graphics driver. | |
148 | * | |
149 | * Returns zero for success or a negative error code. | |
150 | */ | |
98d8fc6c ML |
151 | int snd_hdac_i915_init(struct hdac_bus *bus) |
152 | { | |
ae891abe | 153 | struct drm_audio_component *acomp; |
a57942bf | 154 | int err; |
d745f5e7 | 155 | |
c9db8a30 | 156 | if (!i915_gfx_present(to_pci_dev(bus->dev))) |
bfa5fb14 TI |
157 | return -ENODEV; |
158 | ||
96e503f9 | 159 | err = snd_hdac_acomp_init(bus, NULL, |
a57942bf TI |
160 | i915_component_master_match, |
161 | sizeof(struct i915_audio_component) - sizeof(*acomp)); | |
162 | if (err < 0) | |
163 | return err; | |
164 | acomp = bus->audio_component; | |
165 | if (!acomp) | |
166 | return -ENODEV; | |
f9b54e19 | 167 | if (!acomp->ops) { |
74bf71ed ST |
168 | if (!IS_ENABLED(CONFIG_MODULES) || |
169 | !request_module("i915")) { | |
170 | /* 60s timeout */ | |
327e8ba5 KV |
171 | wait_for_completion_killable_timeout(&acomp->master_bind_complete, |
172 | msecs_to_jiffies(60 * 1000)); | |
74bf71ed | 173 | } |
f9b54e19 | 174 | } |
98d8fc6c | 175 | if (!acomp->ops) { |
b3a5402c | 176 | dev_info(bus->dev, "couldn't bind with audio component\n"); |
a57942bf TI |
177 | snd_hdac_acomp_exit(bus); |
178 | return -ENODEV; | |
98d8fc6c | 179 | } |
98d8fc6c | 180 | return 0; |
98d8fc6c ML |
181 | } |
182 | EXPORT_SYMBOL_GPL(snd_hdac_i915_init); |