From 1f93a7dfd1f8d5ff7a5c53246c7534fe2332d6f4 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 02:46:07 +0000 Subject: [PATCH] add audio --- kernel/sound/hda/hdac_i915.c | 82 ++++++++++++++++++++++++----------------- 1 files changed, 48 insertions(+), 34 deletions(-) diff --git a/kernel/sound/hda/hdac_i915.c b/kernel/sound/hda/hdac_i915.c index 3847fe8..454474a 100644 --- a/kernel/sound/hda/hdac_i915.c +++ b/kernel/sound/hda/hdac_i915.c @@ -1,15 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * hdac_i915.c - routines for sync between HD-A core and i915 display driver - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. */ #include <linux/init.h> @@ -20,9 +11,7 @@ #include <sound/hda_i915.h> #include <sound/hda_register.h> -static struct completion bind_complete; - -#define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \ +#define IS_HSW_CONTROLLER(pci) (((pci)->device == 0x0a0c) || \ ((pci)->device == 0x0c0c) || \ ((pci)->device == 0x0d0c) || \ ((pci)->device == 0x160c)) @@ -50,7 +39,7 @@ if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq) return; /* only for i915 binding */ - if (!CONTROLLER_IN_GPU(pci)) + if (!IS_HSW_CONTROLLER(pci)) return; /* only HSW/BDW */ cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); @@ -82,9 +71,49 @@ } EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk); -static int i915_component_master_match(struct device *dev, void *data) +/* returns true if the devices can be connected for audio */ +static bool connectivity_check(struct pci_dev *i915, struct pci_dev *hdac) { - return !strcmp(dev->driver->name, "i915"); + struct pci_bus *bus_a = i915->bus, *bus_b = hdac->bus; + + /* directly connected on the same bus */ + if (bus_a == bus_b) + return true; + + /* + * on i915 discrete GPUs with embedded HDA audio, the two + * devices are connected via 2nd level PCI bridge + */ + bus_a = bus_a->parent; + bus_b = bus_b->parent; + if (!bus_a || !bus_b) + return false; + bus_a = bus_a->parent; + bus_b = bus_b->parent; + if (bus_a && bus_a == bus_b) + return true; + + return false; +} + +static int i915_component_master_match(struct device *dev, int subcomponent, + void *data) +{ + struct pci_dev *hdac_pci, *i915_pci; + struct hdac_bus *bus = data; + + if (!dev_is_pci(dev)) + return 0; + + hdac_pci = to_pci_dev(bus->dev); + i915_pci = to_pci_dev(dev); + + if (!strcmp(dev->driver->name, "i915") && + subcomponent == I915_COMPONENT_AUDIO && + connectivity_check(i915_pci, hdac_pci)) + return 1; + + return 0; } /* check whether intel graphics is present */ @@ -98,19 +127,6 @@ }; return pci_dev_present(ids); } - -static int i915_master_bind(struct device *dev, - struct drm_audio_component *acomp) -{ - complete_all(&bind_complete); - /* clear audio_ops here as it was needed only for completion call */ - acomp->audio_ops = NULL; - return 0; -} - -static const struct drm_audio_component_audio_ops i915_init_ops = { - .master_bind = i915_master_bind -}; /** * snd_hdac_i915_init - Initialize i915 audio component @@ -132,9 +148,7 @@ if (!i915_gfx_present()) return -ENODEV; - init_completion(&bind_complete); - - err = snd_hdac_acomp_init(bus, &i915_init_ops, + err = snd_hdac_acomp_init(bus, NULL, i915_component_master_match, sizeof(struct i915_audio_component) - sizeof(*acomp)); if (err < 0) @@ -146,8 +160,8 @@ if (!IS_ENABLED(CONFIG_MODULES) || !request_module("i915")) { /* 60s timeout */ - wait_for_completion_timeout(&bind_complete, - msecs_to_jiffies(60 * 1000)); + wait_for_completion_timeout(&acomp->master_bind_complete, + msecs_to_jiffies(60 * 1000)); } } if (!acomp->ops) { -- Gitblit v1.6.2