diff options
-rw-r--r-- | sound/soc/intel/skylake/skl-pcm.c | 1 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl-sst-ipc.h | 3 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl.c | 47 | ||||
-rw-r--r-- | sound/soc/intel/skylake/skl.h | 5 |
4 files changed, 56 insertions, 0 deletions
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index c966b40da180..b69e05ec6844 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c | |||
@@ -1211,6 +1211,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) | |||
1211 | return ret; | 1211 | return ret; |
1212 | } | 1212 | } |
1213 | skl_populate_modules(skl); | 1213 | skl_populate_modules(skl); |
1214 | skl->skl_sst->update_d0i3c = skl_update_d0i3c; | ||
1214 | } | 1215 | } |
1215 | pm_runtime_mark_last_busy(platform->dev); | 1216 | pm_runtime_mark_last_busy(platform->dev); |
1216 | pm_runtime_put_autosuspend(platform->dev); | 1217 | pm_runtime_put_autosuspend(platform->dev); |
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 1ae265d8ee08..ef2182d21934 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h | |||
@@ -83,6 +83,9 @@ struct skl_sst { | |||
83 | 83 | ||
84 | /* tplg manifest */ | 84 | /* tplg manifest */ |
85 | struct skl_dfw_manifest manifest; | 85 | struct skl_dfw_manifest manifest; |
86 | |||
87 | /* Callback to update D0i3C register */ | ||
88 | void (*update_d0i3c)(struct device *dev, bool enable); | ||
86 | }; | 89 | }; |
87 | 90 | ||
88 | struct skl_ipc_init_instance_msg { | 91 | struct skl_ipc_init_instance_msg { |
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 2989c164dafe..b9209af89915 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/pm_runtime.h> | 26 | #include <linux/pm_runtime.h> |
27 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
28 | #include <linux/firmware.h> | 28 | #include <linux/firmware.h> |
29 | #include <linux/delay.h> | ||
29 | #include <sound/pcm.h> | 30 | #include <sound/pcm.h> |
30 | #include "../common/sst-acpi.h" | 31 | #include "../common/sst-acpi.h" |
31 | #include <sound/hda_register.h> | 32 | #include <sound/hda_register.h> |
@@ -109,6 +110,52 @@ static int skl_init_chip(struct hdac_bus *bus, bool full_reset) | |||
109 | return ret; | 110 | return ret; |
110 | } | 111 | } |
111 | 112 | ||
113 | void skl_update_d0i3c(struct device *dev, bool enable) | ||
114 | { | ||
115 | struct pci_dev *pci = to_pci_dev(dev); | ||
116 | struct hdac_ext_bus *ebus = pci_get_drvdata(pci); | ||
117 | struct hdac_bus *bus = ebus_to_hbus(ebus); | ||
118 | u8 reg; | ||
119 | int timeout = 50; | ||
120 | |||
121 | reg = snd_hdac_chip_readb(bus, VS_D0I3C); | ||
122 | /* Do not write to D0I3C until command in progress bit is cleared */ | ||
123 | while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { | ||
124 | udelay(10); | ||
125 | reg = snd_hdac_chip_readb(bus, VS_D0I3C); | ||
126 | } | ||
127 | |||
128 | /* Highly unlikely. But if it happens, flag error explicitly */ | ||
129 | if (!timeout) { | ||
130 | dev_err(bus->dev, "Before D0I3C update: D0I3C CIP timeout\n"); | ||
131 | return; | ||
132 | } | ||
133 | |||
134 | if (enable) | ||
135 | reg = reg | AZX_REG_VS_D0I3C_I3; | ||
136 | else | ||
137 | reg = reg & (~AZX_REG_VS_D0I3C_I3); | ||
138 | |||
139 | snd_hdac_chip_writeb(bus, VS_D0I3C, reg); | ||
140 | |||
141 | timeout = 50; | ||
142 | /* Wait for cmd in progress to be cleared before exiting the function */ | ||
143 | reg = snd_hdac_chip_readb(bus, VS_D0I3C); | ||
144 | while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { | ||
145 | udelay(10); | ||
146 | reg = snd_hdac_chip_readb(bus, VS_D0I3C); | ||
147 | } | ||
148 | |||
149 | /* Highly unlikely. But if it happens, flag error explicitly */ | ||
150 | if (!timeout) { | ||
151 | dev_err(bus->dev, "After D0I3C update: D0I3C CIP timeout\n"); | ||
152 | return; | ||
153 | } | ||
154 | |||
155 | dev_dbg(bus->dev, "D0I3C register = 0x%x\n", | ||
156 | snd_hdac_chip_readb(bus, VS_D0I3C)); | ||
157 | } | ||
158 | |||
112 | /* called from IRQ */ | 159 | /* called from IRQ */ |
113 | static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr) | 160 | static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr) |
114 | { | 161 | { |
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 5d4fbb094c48..88ba54ba5f72 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h | |||
@@ -52,6 +52,9 @@ | |||
52 | #define AZX_PGCTL_LSRMD_MASK (1 << 4) | 52 | #define AZX_PGCTL_LSRMD_MASK (1 << 4) |
53 | #define AZX_PCIREG_CGCTL 0x48 | 53 | #define AZX_PCIREG_CGCTL 0x48 |
54 | #define AZX_CGCTL_MISCBDCGE_MASK (1 << 6) | 54 | #define AZX_CGCTL_MISCBDCGE_MASK (1 << 6) |
55 | /* D0I3C Register fields */ | ||
56 | #define AZX_REG_VS_D0I3C_CIP 0x1 /* Command in progress */ | ||
57 | #define AZX_REG_VS_D0I3C_I3 0x4 /* D0i3 enable */ | ||
55 | 58 | ||
56 | struct skl_dsp_resource { | 59 | struct skl_dsp_resource { |
57 | u32 max_mcps; | 60 | u32 max_mcps; |
@@ -125,4 +128,6 @@ int skl_suspend_dsp(struct skl *skl); | |||
125 | int skl_resume_dsp(struct skl *skl); | 128 | int skl_resume_dsp(struct skl *skl); |
126 | void skl_cleanup_resources(struct skl *skl); | 129 | void skl_cleanup_resources(struct skl *skl); |
127 | const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); | 130 | const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); |
131 | void skl_update_d0i3c(struct device *dev, bool enable); | ||
132 | |||
128 | #endif /* __SOUND_SOC_SKL_H */ | 133 | #endif /* __SOUND_SOC_SKL_H */ |