From 8f3f600b52b100f254fc16a60af1261d2e4dc239 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 14 Apr 2015 12:53:28 +0200 Subject: ALSA: hda - Add DSP loader to core library code Copied from the legacy driver code, no transition done yet. Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound/pci/hda/Kconfig') diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index a5ed1c181784..47aa7b8b7519 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -38,9 +38,6 @@ config SND_HDA_TEGRA if SND_HDA -config SND_HDA_DSP_LOADER - bool - config SND_HDA_PREALLOC_SIZE int "Pre-allocated buffer size for HD-audio driver" range 0 32768 -- cgit v1.2.3 From 9058cbe1eed29381f84dec9f96980f5a4ea1025f Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Mon, 27 Apr 2015 21:20:56 +0800 Subject: ALSA: jack: implement kctl creating for jack devices Currently the ALSA jack core registers only input devices for each jack registered. These jack input devices are not readable by userspace devices that run as non root. This patch series will implement kctls inside the core jack part, including kctls creating, status changing report, for both HD-Audio and ASoC jack. This allows non root userspace to read jack status and act on it. This patch adds a new API called snd_jack_add_new_kctl(), which will create a kcontrol, add it to the card, and also attach it to the jack kctl list. This patch also initialises the jack kctl list after jack is newed, and reports kctl status when jack insertion/removal events occur. snd_jack_new() is updated in the following patches to also support creating phantom jacks and jack kcontrols. We then remove these duplicated features from HDA jack and have jack kctls handled by core throughout HDA and ASoC. Signed-off-by: Liam Girdwood Modified-by: Jie Yang Signed-off-by: Jie Yang Reveiwed-by: Mark Brown Signed-off-by: Takashi Iwai --- include/sound/jack.h | 9 ++++- sound/core/Kconfig | 3 -- sound/core/Makefile | 3 +- sound/core/jack.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++ sound/pci/hda/Kconfig | 2 +- 5 files changed, 103 insertions(+), 7 deletions(-) (limited to 'sound/pci/hda/Kconfig') diff --git a/include/sound/jack.h b/include/sound/jack.h index 218235030ebc..433b13b89125 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h @@ -73,6 +73,8 @@ enum snd_jack_types { struct snd_jack { struct input_dev *input_dev; + struct list_head kctl_list; + struct snd_card *card; int registered; int type; const char *id; @@ -86,6 +88,7 @@ struct snd_jack { int snd_jack_new(struct snd_card *card, const char *id, int type, struct snd_jack **jack); +int snd_jack_add_new_kctl(struct snd_jack *jack, const char * name, int mask); void snd_jack_set_parent(struct snd_jack *jack, struct device *parent); int snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type, int keytype); @@ -93,13 +96,17 @@ int snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type, void snd_jack_report(struct snd_jack *jack, int status); #else - static inline int snd_jack_new(struct snd_card *card, const char *id, int type, struct snd_jack **jack) { return 0; } +static inline int snd_jack_add_new_kctl(struct snd_jack *jack, const char * name, int mask) +{ + return 0; +} + static inline void snd_jack_set_parent(struct snd_jack *jack, struct device *parent) { diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 313f22e9d929..63cc2e967099 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -221,9 +221,6 @@ config SND_PCM_XRUN_DEBUG config SND_VMASTER bool -config SND_KCTL_JACK - bool - config SND_DMA_SGBUF def_bool y depends on X86 diff --git a/sound/core/Makefile b/sound/core/Makefile index 4daf2f58261c..e041dc25f2c8 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -7,8 +7,7 @@ snd-y := sound.o init.o memory.o info.o control.o misc.o device.o snd-$(CONFIG_ISA_DMA_API) += isadma.o snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o snd-$(CONFIG_SND_VMASTER) += vmaster.o -snd-$(CONFIG_SND_KCTL_JACK) += ctljack.o -snd-$(CONFIG_SND_JACK) += jack.o +snd-$(CONFIG_SND_JACK) += ctljack.o jack.o snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ pcm_memory.o memalloc.o diff --git a/sound/core/jack.c b/sound/core/jack.c index 8658578eb584..db69ecc23651 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -24,6 +24,13 @@ #include #include #include +#include + +struct snd_jack_kctl { + struct snd_kcontrol *kctl; + struct list_head list; /* list of controls belong to the same jack */ + unsigned int mask_bits; /* only masked status bits are reported via kctl */ +}; static int jack_switch_types[SND_JACK_SWITCH_TYPES] = { SW_HEADPHONE_INSERT, @@ -54,7 +61,13 @@ static int snd_jack_dev_disconnect(struct snd_device *device) static int snd_jack_dev_free(struct snd_device *device) { struct snd_jack *jack = device->device_data; + struct snd_card *card = device->card; + struct snd_jack_kctl *jack_kctl, *tmp_jack_kctl; + list_for_each_entry_safe(jack_kctl, tmp_jack_kctl, &jack->kctl_list, list) { + list_del_init(&jack_kctl->list); + snd_ctl_remove(card, jack_kctl->kctl); + } if (jack->private_free) jack->private_free(jack); @@ -100,6 +113,77 @@ static int snd_jack_dev_register(struct snd_device *device) return err; } +static void snd_jack_kctl_private_free(struct snd_kcontrol *kctl) +{ + struct snd_jack_kctl *jack_kctl; + + jack_kctl = kctl->private_data; + if (jack_kctl) { + list_del(&jack_kctl->list); + kfree(jack_kctl); + } +} + +static void snd_jack_kctl_add(struct snd_jack *jack, struct snd_jack_kctl *jack_kctl) +{ + list_add_tail(&jack_kctl->list, &jack->kctl_list); +} + +static struct snd_jack_kctl * snd_jack_kctl_new(struct snd_card *card, const char *name, unsigned int mask) +{ + struct snd_kcontrol *kctl; + struct snd_jack_kctl *jack_kctl; + int err; + + kctl = snd_kctl_jack_new(name, 0, card); + if (!kctl) + return NULL; + + err = snd_ctl_add(card, kctl); + if (err < 0) + return NULL; + + jack_kctl = kzalloc(sizeof(*jack_kctl), GFP_KERNEL); + + if (!jack_kctl) + goto error; + + jack_kctl->kctl = kctl; + jack_kctl->mask_bits = mask; + + kctl->private_data = jack_kctl; + kctl->private_free = snd_jack_kctl_private_free; + + return jack_kctl; +error: + snd_ctl_free_one(kctl); + return NULL; +} + +/** + * snd_jack_add_new_kctl - Create a new snd_jack_kctl and add it to jack + * @jack: the jack instance which the kctl will attaching to + * @name: the name for the snd_kcontrol object + * @mask: a bitmask of enum snd_jack_type values that can be detected + * by this snd_jack_kctl object. + * + * Creates a new snd_kcontrol object and adds it to the jack kctl_list. + * + * Return: Zero if successful, or a negative error code on failure. + */ +int snd_jack_add_new_kctl(struct snd_jack *jack, const char * name, int mask) +{ + struct snd_jack_kctl *jack_kctl; + + jack_kctl = snd_jack_kctl_new(jack->card, name, mask); + if (!jack_kctl) + return -ENOMEM; + + snd_jack_kctl_add(jack, jack_kctl); + return 0; +} +EXPORT_SYMBOL(snd_jack_add_new_kctl); + /** * snd_jack_new - Create a new jack * @card: the card instance @@ -150,6 +234,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, if (err < 0) goto fail_input; + jack->card = card; + INIT_LIST_HEAD(&jack->kctl_list); + *jjack = jack; return 0; @@ -230,6 +317,7 @@ EXPORT_SYMBOL(snd_jack_set_key); */ void snd_jack_report(struct snd_jack *jack, int status) { + struct snd_jack_kctl *jack_kctl; int i; if (!jack) @@ -252,6 +340,11 @@ void snd_jack_report(struct snd_jack *jack, int status) } input_sync(jack->input_dev); + + list_for_each_entry(jack_kctl, &jack->kctl_list, list) + snd_kctl_jack_report(jack->card, jack_kctl->kctl, + status & jack_kctl->mask_bits); + } EXPORT_SYMBOL(snd_jack_report); diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index a5ed1c181784..4d3d4747e55a 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -4,7 +4,7 @@ config SND_HDA tristate select SND_PCM select SND_VMASTER - select SND_KCTL_JACK + select SND_JACK select SND_HDA_CORE config SND_HDA_INTEL -- cgit v1.2.3 From 973109cafc9d11e41be4d64667ff2165bf79d948 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Sat, 2 May 2015 15:28:07 +0800 Subject: ALSA: jack: fix a randconfig build issue Building errors reported such as below when 'CONFIG_INPUT=m': ...undefined reference to `input_xxx'... Here change to enable SND_JACK selectively to fix the issue. Also remove the config 'SND_HDA_INPUT_JACK' which won't be used anymore. Signed-off-by: Jie Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 10 +--------- sound/pci/hda/hda_codec.h | 2 -- 2 files changed, 1 insertion(+), 11 deletions(-) (limited to 'sound/pci/hda/Kconfig') diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 4d3d4747e55a..78e9e411977a 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -4,7 +4,7 @@ config SND_HDA tristate select SND_PCM select SND_VMASTER - select SND_JACK + select SND_JACK if INPUT=y || INPUT=SND select SND_HDA_CORE config SND_HDA_INTEL @@ -87,14 +87,6 @@ config SND_HDA_INPUT_BEEP_MODE Set 1 to always enable the digital beep interface for HD-audio by default. -config SND_HDA_INPUT_JACK - bool "Support jack plugging notification via input layer" - depends on INPUT=y || INPUT=SND - select SND_JACK - help - Say Y here to enable the jack plugging notification via - input layer. - config SND_HDA_PATCH_LOADER bool "Support initialization patch loading for HD-audio" select FW_LOADER diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 9075ac28dc4b..28a1f1c81562 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -300,10 +300,8 @@ struct hda_codec { unsigned long jackpoll_interval; /* In jiffies. Zero means no poll, rely on unsol events */ struct delayed_work jackpoll_work; -#ifdef CONFIG_SND_HDA_INPUT_JACK /* jack detection */ struct snd_array jacks; -#endif int depop_delay; /* depop delay in ms, -1 for default delay time */ -- cgit v1.2.3 From 98d8fc6c5d3652e91c61d78941e0fa6f94771d67 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Tue, 19 May 2015 22:29:30 +0800 Subject: ALSA: hda - Move hda_i915.c from sound/pci/hda to sound/hda The file is moved to hda core and renamed to hdac_i915.c, so can be used by both legacy HDA driver and new Skylake audio driver. - Add snd_hdac_ prefix to the public APIs. - The i915 audio component is moved to core bus and dynamically allocated. - A static pointer hdac_acomp is used to help bind/unbind callbacks to get this component, because the sound card's private_data is used by the azx chip pointer, which is a legacy structure. It could be removed if private _data changes to some core structure which can be extended to find the bus. - snd_hdac_get_display_clk() is added to get the display core clock for HSW/BDW. - haswell_set_bclk() is moved to hda_intel.c because it needs to write the controller registers EM4/EM5, and only legacy HD-A needs it for HSW/BDW. - Move definition of HSW/BDW-specific registers EM4/EM5 to hda_register.h and rename them to HSW_EM4/HSW_EM5, because other HD-A controllers have different layout for the extended mode registers. Signed-off-by: Mengdong Lin Signed-off-by: Takashi Iwai --- include/sound/hda_i915.h | 36 +++++++ include/sound/hda_register.h | 4 + include/sound/hdaudio.h | 5 + sound/hda/Kconfig | 6 ++ sound/hda/Makefile | 3 + sound/hda/hdac_i915.c | 193 ++++++++++++++++++++++++++++++++++++ sound/pci/hda/Kconfig | 5 - sound/pci/hda/Makefile | 2 - sound/pci/hda/hda_i915.c | 227 ------------------------------------------- sound/pci/hda/hda_intel.c | 82 +++++++++++++--- sound/pci/hda/hda_intel.h | 30 ------ 11 files changed, 313 insertions(+), 280 deletions(-) create mode 100644 include/sound/hda_i915.h create mode 100644 sound/hda/hdac_i915.c delete mode 100644 sound/pci/hda/hda_i915.c (limited to 'sound/pci/hda/Kconfig') diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h new file mode 100644 index 000000000000..adb5ba5cbd9d --- /dev/null +++ b/include/sound/hda_i915.h @@ -0,0 +1,36 @@ +/* + * HD-Audio helpers to sync with i915 driver + */ +#ifndef __SOUND_HDA_I915_H +#define __SOUND_HDA_I915_H + +#ifdef CONFIG_SND_HDA_I915 +int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); +int snd_hdac_display_power(struct hdac_bus *bus, bool enable); +int snd_hdac_get_display_clk(struct hdac_bus *bus); +int snd_hdac_i915_init(struct hdac_bus *bus); +int snd_hdac_i915_exit(struct hdac_bus *bus); +#else +static int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) +{ + return 0; +} +static inline int snd_hdac_display_power(struct hdac_bus *bus, bool enable) +{ + return 0; +} +static inline int snd_hdac_get_display_clk(struct hdac_bus *bus) +{ + return 0; +} +static inline int snd_hdac_i915_init(struct hdac_bus *bus) +{ + return -ENODEV; +} +static inline int snd_hdac_i915_exit(struct hdac_bus *bus) +{ + return 0; +} +#endif + +#endif /* __SOUND_HDA_I915_H */ diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index 4f6d3fce6ee6..0c7536e30fa4 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h @@ -84,6 +84,10 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_REG_SD_BDLPL 0x18 #define AZX_REG_SD_BDLPU 0x1c +/* Haswell/Broadwell display HD-A controller Extended Mode registers */ +#define AZX_REG_HSW_EM4 0x100c +#define AZX_REG_HSW_EM5 0x1010 + /* PCI space */ #define AZX_PCIREG_TCSEL 0x44 diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index b97c59eab7ab..64fff4db81bb 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -11,6 +11,7 @@ #include #include #include +#include /* codec node id */ typedef u16 hda_nid_t; @@ -285,6 +286,10 @@ struct hdac_bus { /* locks */ spinlock_t reg_lock; struct mutex cmd_mutex; + + /* i915 component interface */ + struct i915_audio_component *audio_component; + int i915_power_refcount; }; int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index 7a17fca4f627..ac5ffac2a272 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -4,3 +4,9 @@ config SND_HDA_CORE config SND_HDA_DSP_LOADER bool + +config SND_HDA_I915 + bool + default y + depends on DRM_I915 + depends on SND_HDA_CORE diff --git a/sound/hda/Makefile b/sound/hda/Makefile index 5b4bb47c16fd..55dd465c7042 100644 --- a/sound/hda/Makefile +++ b/sound/hda/Makefile @@ -4,4 +4,7 @@ snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o \ snd-hda-core-objs += trace.o CFLAGS_trace.o := -I$(src) +# for sync with i915 gfx driver +snd-hda-core-$(CONFIG_SND_HDA_I915) += hdac_i915.o + obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c new file mode 100644 index 000000000000..cb78c25585ac --- /dev/null +++ b/sound/hda/hdac_i915.c @@ -0,0 +1,193 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +static struct i915_audio_component *hdac_acomp; + +int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) +{ + struct i915_audio_component *acomp = bus->audio_component; + + if (!acomp->ops) + return -ENODEV; + + if (!acomp->ops->codec_wake_override) { + dev_warn(bus->dev, + "Invalid codec wake callback\n"); + return 0; + } + + dev_dbg(bus->dev, "%s codec wakeup\n", + enable ? "enable" : "disable"); + + acomp->ops->codec_wake_override(acomp->dev, enable); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup); + +int snd_hdac_display_power(struct hdac_bus *bus, bool enable) +{ + struct i915_audio_component *acomp = bus->audio_component; + + if (!acomp->ops) + return -ENODEV; + + dev_dbg(bus->dev, "display power %s\n", + enable ? "enable" : "disable"); + + if (enable) { + if (!bus->i915_power_refcount++) + acomp->ops->get_power(acomp->dev); + } else { + WARN_ON(!bus->i915_power_refcount); + if (!--bus->i915_power_refcount) + acomp->ops->put_power(acomp->dev); + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hdac_display_power); + +int snd_hdac_get_display_clk(struct hdac_bus *bus) +{ + struct i915_audio_component *acomp = bus->audio_component; + + if (!acomp->ops) + return -ENODEV; + + return acomp->ops->get_cdclk_freq(acomp->dev); +} +EXPORT_SYMBOL_GPL(snd_hdac_get_display_clk); + +static int hdac_component_master_bind(struct device *dev) +{ + struct i915_audio_component *acomp = hdac_acomp; + int ret; + + ret = component_bind_all(dev, acomp); + if (ret < 0) + return ret; + + if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power && + acomp->ops->put_power && acomp->ops->get_cdclk_freq))) { + ret = -EINVAL; + goto out_unbind; + } + + /* + * Atm, we don't support dynamic unbinding initiated by the child + * component, so pin its containing module until we unbind. + */ + if (!try_module_get(acomp->ops->owner)) { + ret = -ENODEV; + goto out_unbind; + } + + return 0; + +out_unbind: + component_unbind_all(dev, acomp); + + return ret; +} + +static void hdac_component_master_unbind(struct device *dev) +{ + struct i915_audio_component *acomp = hdac_acomp; + + module_put(acomp->ops->owner); + component_unbind_all(dev, acomp); + WARN_ON(acomp->ops || acomp->dev); +} + +static const struct component_master_ops hdac_component_master_ops = { + .bind = hdac_component_master_bind, + .unbind = hdac_component_master_unbind, +}; + +static int hdac_component_master_match(struct device *dev, void *data) +{ + /* i915 is the only supported component */ + return !strcmp(dev->driver->name, "i915"); +} + +int snd_hdac_i915_init(struct hdac_bus *bus) +{ + struct component_match *match = NULL; + struct device *dev = bus->dev; + struct i915_audio_component *acomp; + int ret; + + acomp = kzalloc(sizeof(*acomp), GFP_KERNEL); + if (!acomp) + return -ENOMEM; + bus->audio_component = acomp; + hdac_acomp = acomp; + + component_match_add(dev, &match, hdac_component_master_match, bus); + ret = component_master_add_with_match(dev, &hdac_component_master_ops, + match); + if (ret < 0) + goto out_err; + + /* + * Atm, we don't support deferring the component binding, so make sure + * i915 is loaded and that the binding successfully completes. + */ + request_module("i915"); + + if (!acomp->ops) { + ret = -ENODEV; + goto out_master_del; + } + dev_dbg(dev, "bound to i915 component master\n"); + + return 0; +out_master_del: + component_master_del(dev, &hdac_component_master_ops); +out_err: + kfree(acomp); + bus->audio_component = NULL; + dev_err(dev, "failed to add i915 component master (%d)\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_hdac_i915_init); + +int snd_hdac_i915_exit(struct hdac_bus *bus) +{ + struct device *dev = bus->dev; + struct i915_audio_component *acomp = bus->audio_component; + + WARN_ON(bus->i915_power_refcount); + if (bus->i915_power_refcount > 0 && acomp && acomp->ops) + acomp->ops->put_power(acomp->dev); + + component_master_del(dev, &hdac_component_master_ops); + + kfree(acomp); + bus->audio_component = NULL; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hdac_i915_exit); diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 117bf5cf9f1d..98ced971cb43 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -145,11 +145,6 @@ config SND_HDA_CODEC_HDMI comment "Set to Y if you want auto-loading the codec driver" depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m -config SND_HDA_I915 - bool - default y - depends on DRM_I915 - config SND_HDA_CODEC_CIRRUS tristate "Build Cirrus Logic codec support" select SND_HDA_GENERIC diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 9c259ced979a..90e69b243b41 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,7 +1,5 @@ snd-hda-intel-objs := hda_intel.o snd-hda-tegra-objs := hda_tegra.o -# for haswell power well -snd-hda-intel-$(CONFIG_SND_HDA_I915) += hda_i915.o snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o snd-hda-codec-y += hda_controller.o diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c deleted file mode 100644 index 852170258266..000000000000 --- a/sound/pci/hda/hda_i915.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * hda_i915.c - routines for Haswell HDA controller power well support - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include "hda_controller.h" -#include "hda_intel.h" - -/* Intel HSW/BDW display HDA controller Extended Mode registers. - * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display - * Clock) to 24MHz BCLK: BCLK = CDCLK * M / N - * The values will be lost when the display power well is disabled. - */ -#define AZX_REG_EM4 0x100c -#define AZX_REG_EM5 0x1010 - -int hda_set_codec_wakeup(struct hda_intel *hda, bool enable) -{ - struct i915_audio_component *acomp = &hda->audio_component; - - if (!acomp->ops) - return -ENODEV; - - if (!acomp->ops->codec_wake_override) { - dev_warn(&hda->chip.pci->dev, - "Invalid codec wake callback\n"); - return 0; - } - - dev_dbg(&hda->chip.pci->dev, "%s codec wakeup\n", - enable ? "enable" : "disable"); - - acomp->ops->codec_wake_override(acomp->dev, enable); - - return 0; -} - -int hda_display_power(struct hda_intel *hda, bool enable) -{ - struct i915_audio_component *acomp = &hda->audio_component; - - if (!acomp->ops) - return -ENODEV; - - dev_dbg(&hda->chip.pci->dev, "display power %s\n", - enable ? "enable" : "disable"); - - if (enable) { - if (!hda->i915_power_refcount++) - acomp->ops->get_power(acomp->dev); - } else { - WARN_ON(!hda->i915_power_refcount); - if (!--hda->i915_power_refcount) - acomp->ops->put_power(acomp->dev); - } - - return 0; -} - -void haswell_set_bclk(struct hda_intel *hda) -{ - int cdclk_freq; - unsigned int bclk_m, bclk_n; - struct i915_audio_component *acomp = &hda->audio_component; - struct pci_dev *pci = hda->chip.pci; - - /* Only Haswell/Broadwell need set BCLK */ - if (pci->device != 0x0a0c && pci->device != 0x0c0c - && pci->device != 0x0d0c && pci->device != 0x160c) - return; - - if (!acomp->ops) - return; - - cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); - switch (cdclk_freq) { - case 337500: - bclk_m = 16; - bclk_n = 225; - break; - - case 450000: - default: /* default CDCLK 450MHz */ - bclk_m = 4; - bclk_n = 75; - break; - - case 540000: - bclk_m = 4; - bclk_n = 90; - break; - - case 675000: - bclk_m = 8; - bclk_n = 225; - break; - } - - azx_writew(&hda->chip, EM4, bclk_m); - azx_writew(&hda->chip, EM5, bclk_n); -} - -static int hda_component_master_bind(struct device *dev) -{ - struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - struct i915_audio_component *acomp = &hda->audio_component; - int ret; - - ret = component_bind_all(dev, acomp); - if (ret < 0) - return ret; - - if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power && - acomp->ops->put_power && acomp->ops->get_cdclk_freq))) { - ret = -EINVAL; - goto out_unbind; - } - - /* - * Atm, we don't support dynamic unbinding initiated by the child - * component, so pin its containing module until we unbind. - */ - if (!try_module_get(acomp->ops->owner)) { - ret = -ENODEV; - goto out_unbind; - } - - return 0; - -out_unbind: - component_unbind_all(dev, acomp); - - return ret; -} - -static void hda_component_master_unbind(struct device *dev) -{ - struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - struct i915_audio_component *acomp = &hda->audio_component; - - module_put(acomp->ops->owner); - component_unbind_all(dev, acomp); - WARN_ON(acomp->ops || acomp->dev); -} - -static const struct component_master_ops hda_component_master_ops = { - .bind = hda_component_master_bind, - .unbind = hda_component_master_unbind, -}; - -static int hda_component_master_match(struct device *dev, void *data) -{ - /* i915 is the only supported component */ - return !strcmp(dev->driver->name, "i915"); -} - -int hda_i915_init(struct hda_intel *hda) -{ - struct component_match *match = NULL; - struct device *dev = &hda->chip.pci->dev; - struct i915_audio_component *acomp = &hda->audio_component; - int ret; - - component_match_add(dev, &match, hda_component_master_match, hda); - ret = component_master_add_with_match(dev, &hda_component_master_ops, - match); - if (ret < 0) - goto out_err; - - /* - * Atm, we don't support deferring the component binding, so make sure - * i915 is loaded and that the binding successfully completes. - */ - request_module("i915"); - - if (!acomp->ops) { - ret = -ENODEV; - goto out_master_del; - } - - dev_dbg(dev, "bound to i915 component master\n"); - - return 0; -out_master_del: - component_master_del(dev, &hda_component_master_ops); -out_err: - dev_err(dev, "failed to add i915 component master (%d)\n", ret); - - return ret; -} - -int hda_i915_exit(struct hda_intel *hda) -{ - struct device *dev = &hda->chip.pci->dev; - struct i915_audio_component *acomp = &hda->audio_component; - - WARN_ON(hda->i915_power_refcount); - if (hda->i915_power_refcount > 0 && acomp->ops) - acomp->ops->put_power(acomp->dev); - - component_master_del(dev, &hda_component_master_ops); - - return 0; -} diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 5c84d40b7700..391e4f834436 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -57,6 +57,8 @@ #endif #include #include +#include +#include #include #include #include @@ -496,13 +498,13 @@ static void azx_init_pci(struct azx *chip) static void hda_intel_init_chip(struct azx *chip, bool full_reset) { - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct hdac_bus *bus = azx_bus(chip); if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - hda_set_codec_wakeup(hda, true); + snd_hdac_set_codec_wakeup(bus, true); azx_init_chip(chip, full_reset); if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - hda_set_codec_wakeup(hda, false); + snd_hdac_set_codec_wakeup(bus, false); } /* calculate runtime delay from LPIB */ @@ -560,9 +562,9 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) /* Enable/disable i915 display power for the link */ static int azx_intel_link_power(struct azx *chip, bool enable) { - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct hdac_bus *bus = azx_bus(chip); - return hda_display_power(hda, enable); + return snd_hdac_display_power(bus, enable); } /* @@ -800,6 +802,50 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) #define azx_del_card_list(chip) /* NOP */ #endif /* CONFIG_PM */ +/* Intel HSW/BDW display HDA controller is in GPU. Both its power and link BCLK + * depends on GPU. Two Extended Mode registers EM4 (M value) and EM5 (N Value) + * are used to convert CDClk (Core Display Clock) to 24MHz BCLK: + * BCLK = CDCLK * M / N + * The values will be lost when the display power well is disabled and need to + * be restored to avoid abnormal playback speed. + */ +static void haswell_set_bclk(struct hda_intel *hda) +{ + struct azx *chip = &hda->chip; + int cdclk_freq; + unsigned int bclk_m, bclk_n; + + if (!hda->need_i915_power) + return; + + cdclk_freq = snd_hdac_get_display_clk(azx_bus(chip)); + switch (cdclk_freq) { + case 337500: + bclk_m = 16; + bclk_n = 225; + break; + + case 450000: + default: /* default CDCLK 450MHz */ + bclk_m = 4; + bclk_n = 75; + break; + + case 540000: + bclk_m = 4; + bclk_n = 90; + break; + + case 675000: + bclk_m = 8; + bclk_n = 225; + break; + } + + azx_writew(chip, HSW_EM4, bclk_m); + azx_writew(chip, HSW_EM5, bclk_n); +} + #if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO) /* * power management @@ -833,7 +879,7 @@ static int azx_suspend(struct device *dev) pci_disable_msi(chip->pci); if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL && hda->need_i915_power) - hda_display_power(hda, false); + snd_hdac_display_power(bus, false); trace_azx_suspend(chip); return 0; @@ -856,7 +902,7 @@ static int azx_resume(struct device *dev) if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL && hda->need_i915_power) { - hda_display_power(hda, true); + snd_hdac_display_power(azx_bus(chip), true); haswell_set_bclk(hda); } if (chip->msi) @@ -902,7 +948,7 @@ static int azx_runtime_suspend(struct device *dev) azx_clear_irq_pending(chip); if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL && hda->need_i915_power) - hda_display_power(hda, false); + snd_hdac_display_power(azx_bus(chip), false); trace_azx_runtime_suspend(chip); return 0; @@ -913,6 +959,7 @@ static int azx_runtime_resume(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; struct hda_intel *hda; + struct hdac_bus *bus; struct hda_codec *codec; int status; @@ -929,11 +976,12 @@ static int azx_runtime_resume(struct device *dev) if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL && hda->need_i915_power) { - hda_display_power(hda, true); + bus = azx_bus(chip); + snd_hdac_display_power(bus, true); haswell_set_bclk(hda); /* toggle codec wakeup bit for STATESTS read */ - hda_set_codec_wakeup(hda, true); - hda_set_codec_wakeup(hda, false); + snd_hdac_set_codec_wakeup(bus, true); + snd_hdac_set_codec_wakeup(bus, false); } /* Read STATESTS before controller reset */ @@ -1152,10 +1200,11 @@ static int azx_free(struct azx *chip) #ifdef CONFIG_SND_HDA_PATCH_LOADER release_firmware(chip->fw); #endif + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { if (hda->need_i915_power) - hda_display_power(hda, false); - hda_i915_exit(hda); + snd_hdac_display_power(bus, false); + snd_hdac_i915_exit(bus); } kfree(hda); @@ -1914,6 +1963,7 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = { static int azx_probe_continue(struct azx *chip) { struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct hdac_bus *bus = azx_bus(chip); struct pci_dev *pci = chip->pci; int dev = chip->dev_index; int err; @@ -1930,11 +1980,11 @@ static int azx_probe_continue(struct azx *chip) if (pci->device != 0x0f04 && pci->device != 0x2284) hda->need_i915_power = 1; - err = hda_i915_init(hda); + err = snd_hdac_i915_init(bus); if (err < 0) goto i915_power_fail; - err = hda_display_power(hda, true); + err = snd_hdac_display_power(bus, true); if (err < 0) { dev_err(chip->card->dev, "Cannot turn on display power on i915\n"); @@ -1986,7 +2036,7 @@ static int azx_probe_continue(struct azx *chip) out_free: if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL && !hda->need_i915_power) - hda_display_power(hda, false); + snd_hdac_display_power(bus, false); i915_power_fail: if (err < 0) diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h index 7fd3254a2f3f..354f0bbed833 100644 --- a/sound/pci/hda/hda_intel.h +++ b/sound/pci/hda/hda_intel.h @@ -16,7 +16,6 @@ #ifndef __SOUND_HDA_INTEL_H #define __SOUND_HDA_INTEL_H -#include #include "hda_controller.h" struct hda_intel { @@ -44,36 +43,7 @@ struct hda_intel { /* secondary power domain for hdmi audio under vga device */ struct dev_pm_domain hdmi_pm_domain; - /* i915 component interface */ bool need_i915_power:1; /* the hda controller needs i915 power */ - struct i915_audio_component audio_component; - int i915_power_refcount; }; -#ifdef CONFIG_SND_HDA_I915 -int hda_set_codec_wakeup(struct hda_intel *hda, bool enable); -int hda_display_power(struct hda_intel *hda, bool enable); -void haswell_set_bclk(struct hda_intel *hda); -int hda_i915_init(struct hda_intel *hda); -int hda_i915_exit(struct hda_intel *hda); -#else -static inline int hda_set_codec_wakeup(struct hda_intel *hda, bool enable) -{ - return 0; -} -static inline int hda_display_power(struct hda_intel *hda, bool enable) -{ - return 0; -} -static inline void haswell_set_bclk(struct hda_intel *hda) { return; } -static inline int hda_i915_init(struct hda_intel *hda) -{ - return 0; -} -static inline int hda_i915_exit(struct hda_intel *hda) -{ - return 0; -} -#endif - #endif -- cgit v1.2.3 From d39513f85163e202a44283856286fabb6902f2e0 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 16 Jun 2015 21:00:22 +0530 Subject: ALSA: HDAC: move SND_HDA_PREALLOC_SIZE to core Since this is common option for HDA driver to specfiy pre-allocated buffer, we should make this option availble to all HDA driver by moving this to HDA core Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai --- sound/hda/Kconfig | 13 +++++++++++++ sound/pci/hda/Kconfig | 13 ------------- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'sound/pci/hda/Kconfig') diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index 6dc3914fd28b..3129546398d0 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -14,3 +14,16 @@ config SND_HDA_I915 config SND_HDA_EXT_CORE tristate select SND_HDA_CORE + +config SND_HDA_PREALLOC_SIZE + int "Pre-allocated buffer size for HD-audio driver" + range 0 32768 + default 64 + help + Specifies the default pre-allocated buffer-size in kB for the + HD-audio driver. A larger buffer (e.g. 2048) is preferred + for systems using PulseAudio. The default 64 is chosen just + for compatibility reasons. + + Note that the pre-allocation size can be changed dynamically + via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 98ced971cb43..e94cfd5c69f7 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -38,19 +38,6 @@ config SND_HDA_TEGRA if SND_HDA -config SND_HDA_PREALLOC_SIZE - int "Pre-allocated buffer size for HD-audio driver" - range 0 32768 - default 64 - help - Specifies the default pre-allocated buffer-size in kB for the - HD-audio driver. A larger buffer (e.g. 2048) is preferred - for systems using PulseAudio. The default 64 is chosen just - for compatibility reasons. - - Note that the pre-allocation size can be changed dynamically - via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. - config SND_HDA_HWDEP bool "Build hwdep interface for HD-audio driver" select SND_HWDEP -- cgit v1.2.3