Commit | Line | Data |
---|---|---|
e149ca29 | 1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) |
78ad1f07 KJ |
2 | // |
3 | // This file is provided under a dual BSD/GPLv2 license. When using or | |
4 | // redistributing this file, you may do so under either license. | |
5 | // | |
293ad281 | 6 | // Copyright(c) 2018 Intel Corporation |
78ad1f07 KJ |
7 | // |
8 | // Authors: Keyon Jie <yang.jie@linux.intel.com> | |
9 | ||
10 | #include <linux/io.h> | |
11 | #include <sound/hdaudio.h> | |
c99fafdf | 12 | #include <sound/hda_i915.h> |
fd572393 KV |
13 | #include <sound/hda_codec.h> |
14 | #include <sound/hda_register.h> | |
78ad1f07 KJ |
15 | #include "../sof-priv.h" |
16 | #include "hda.h" | |
17 | ||
d4ff1b39 | 18 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) |
40073a9d | 19 | #include "../../codecs/hdac_hda.h" |
d4ff1b39 | 20 | #define sof_hda_ext_ops snd_soc_hdac_hda_get_ops() |
78ad1f07 | 21 | |
fd572393 KV |
22 | static void update_codec_wake_enable(struct hdac_bus *bus, unsigned int addr, bool link_power) |
23 | { | |
24 | unsigned int mask = snd_hdac_chip_readw(bus, WAKEEN); | |
25 | ||
26 | if (link_power) | |
27 | mask &= ~BIT(addr); | |
28 | else | |
29 | mask |= BIT(addr); | |
30 | ||
31 | snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask); | |
32 | } | |
33 | ||
c99fafdf KV |
34 | static void sof_hda_bus_link_power(struct hdac_device *codec, bool enable) |
35 | { | |
36 | struct hdac_bus *bus = codec->bus; | |
37 | bool oldstate = test_bit(codec->addr, &bus->codec_powered); | |
38 | ||
39 | snd_hdac_ext_bus_link_power(codec, enable); | |
40 | ||
41 | if (enable == oldstate) | |
42 | return; | |
43 | ||
44 | /* | |
45 | * Both codec driver and controller can hold references to | |
46 | * display power. To avoid unnecessary power-up/down cycles, | |
47 | * controller doesn't immediately release its reference. | |
48 | * | |
49 | * If the codec driver powers down the link, release | |
50 | * the controller reference as well. | |
51 | */ | |
52 | if (codec->addr == HDA_IDISP_ADDR && !enable) | |
53 | snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); | |
fd572393 KV |
54 | |
55 | /* WAKEEN needs to be set for disabled links */ | |
56 | update_codec_wake_enable(bus, codec->addr, enable); | |
c99fafdf KV |
57 | } |
58 | ||
87fc20e4 KV |
59 | static const struct hdac_bus_ops bus_core_ops = { |
60 | .command = snd_hdac_bus_send_cmd, | |
61 | .get_response = snd_hdac_bus_get_response, | |
c99fafdf | 62 | .link_power = sof_hda_bus_link_power, |
87fc20e4 KV |
63 | }; |
64 | #endif | |
65 | ||
78ad1f07 KJ |
66 | /* |
67 | * This can be used for both with/without hda link support. | |
68 | */ | |
afae0942 | 69 | void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev) |
78ad1f07 | 70 | { |
afae0942 PLB |
71 | struct hdac_bus *bus = sof_to_bus(sdev); |
72 | ||
fb0bdfe2 | 73 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) |
afae0942 | 74 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) |
05cf17f1 PU |
75 | const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata); |
76 | ||
87fc20e4 | 77 | snd_hdac_ext_bus_init(bus, dev, &bus_core_ops, sof_hda_ext_ops); |
05cf17f1 PU |
78 | |
79 | if (chip && chip->hw_ip_version == SOF_INTEL_ACE_2_0) | |
80 | bus->use_pio_for_commands = true; | |
fb0bdfe2 PLB |
81 | #else |
82 | snd_hdac_ext_bus_init(bus, dev, NULL, NULL); | |
83 | #endif | |
84 | #else | |
85 | ||
78ad1f07 KJ |
86 | memset(bus, 0, sizeof(*bus)); |
87 | bus->dev = dev; | |
88 | ||
78ad1f07 KJ |
89 | INIT_LIST_HEAD(&bus->stream_list); |
90 | ||
91 | bus->irq = -1; | |
d1a6459f ZY |
92 | |
93 | /* | |
94 | * There is only one HDA bus atm. keep the index as 0. | |
95 | * Need to fix when there are more than one HDA bus. | |
96 | */ | |
97 | bus->idx = 0; | |
78ad1f07 KJ |
98 | |
99 | spin_lock_init(&bus->reg_lock); | |
fb0bdfe2 | 100 | #endif /* CONFIG_SND_SOC_SOF_HDA_LINK */ |
afae0942 | 101 | } |
6fe61f31 | 102 | EXPORT_SYMBOL_NS(sof_hda_bus_init, SND_SOC_SOF_INTEL_HDA_COMMON); |
afae0942 PLB |
103 | |
104 | void sof_hda_bus_exit(struct snd_sof_dev *sdev) | |
105 | { | |
fb0bdfe2 | 106 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) |
afae0942 PLB |
107 | struct hdac_bus *bus = sof_to_bus(sdev); |
108 | ||
109 | snd_hdac_ext_bus_exit(bus); | |
110 | #endif | |
78ad1f07 | 111 | } |
6fe61f31 | 112 | EXPORT_SYMBOL_NS(sof_hda_bus_exit, SND_SOC_SOF_INTEL_HDA_COMMON); |