Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC/soundwire: revisit interrupt and lcount handling

Merge series from Bard Liao <yung-chuan.liao@linux.intel.com>:

The code in drivers/soundwire/intel_init.c is hardware-dependent and the
code does not apply to new generations starting with MeteorLake. Refactor
and clean-up the code to make this intel_init.c hardware-agnostic and
move all hardware-dependencies in the SOF driver using chip descriptors.

+139 -122
-37
drivers/soundwire/intel_init.c
··· 125 125 return 0; 126 126 } 127 127 128 - #define HDA_DSP_REG_ADSPIC2 (0x10) 129 - #define HDA_DSP_REG_ADSPIS2 (0x14) 130 - #define HDA_DSP_REG_ADSPIC2_SNDW BIT(5) 131 - 132 - /** 133 - * sdw_intel_enable_irq() - enable/disable Intel SoundWire IRQ 134 - * @mmio_base: The mmio base of the control register 135 - * @enable: true if enable 136 - */ 137 - void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable) 138 - { 139 - u32 val; 140 - 141 - val = readl(mmio_base + HDA_DSP_REG_ADSPIC2); 142 - 143 - if (enable) 144 - val |= HDA_DSP_REG_ADSPIC2_SNDW; 145 - else 146 - val &= ~HDA_DSP_REG_ADSPIC2_SNDW; 147 - 148 - writel(val, mmio_base + HDA_DSP_REG_ADSPIC2); 149 - } 150 - EXPORT_SYMBOL_NS(sdw_intel_enable_irq, SOUNDWIRE_INTEL_INIT); 151 - 152 128 irqreturn_t sdw_intel_thread(int irq, void *dev_id) 153 129 { 154 130 struct sdw_intel_ctx *ctx = dev_id; ··· 133 157 list_for_each_entry(link, &ctx->link_list, list) 134 158 sdw_cdns_irq(irq, link->cdns); 135 159 136 - sdw_intel_enable_irq(ctx->mmio_base, true); 137 160 return IRQ_HANDLED; 138 161 } 139 162 EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT); ··· 272 297 { 273 298 struct acpi_device *adev = acpi_fetch_acpi_dev(ctx->handle); 274 299 struct sdw_intel_link_dev *ldev; 275 - u32 caps; 276 300 u32 link_mask; 277 301 int i; 278 302 279 303 if (!adev) 280 304 return -EINVAL; 281 - 282 - /* Check SNDWLCAP.LCOUNT */ 283 - caps = ioread32(ctx->mmio_base + ctx->shim_base + SDW_SHIM_LCAP); 284 - caps &= SDW_SHIM_LCAP_LCOUNT_MASK; 285 - 286 - /* Check HW supported vs property value */ 287 - if (caps < ctx->count) { 288 - dev_err(&adev->dev, 289 - "BIOS master count is larger than hardware capabilities\n"); 290 - return -EINVAL; 291 - } 292 305 293 306 if (!ctx->ldev) 294 307 return -EINVAL;
-2
include/linux/soundwire/sdw_intel.h
··· 286 286 287 287 void sdw_intel_exit(struct sdw_intel_ctx *ctx); 288 288 289 - void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable); 290 - 291 289 irqreturn_t sdw_intel_thread(int irq, void *dev_id); 292 290 293 291 #define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1)
+4
sound/soc/sof/intel/cnl.c
··· 457 457 .sdw_shim_base = SDW_SHIM_BASE, 458 458 .sdw_alh_base = SDW_ALH_BASE, 459 459 .d0i3_offset = SOF_HDA_VS_D0I3C, 460 + .read_sdw_lcount = hda_sdw_check_lcount_common, 461 + .enable_sdw_irq = hda_common_enable_sdw_irq, 460 462 .check_sdw_irq = hda_common_check_sdw_irq, 461 463 .check_ipc_irq = hda_dsp_check_ipc_irq, 462 464 .cl_init = cl_dsp_init, ··· 492 490 .sdw_shim_base = SDW_SHIM_BASE, 493 491 .sdw_alh_base = SDW_ALH_BASE, 494 492 .d0i3_offset = SOF_HDA_VS_D0I3C, 493 + .read_sdw_lcount = hda_sdw_check_lcount_common, 494 + .enable_sdw_irq = hda_common_enable_sdw_irq, 495 495 .check_sdw_irq = hda_common_check_sdw_irq, 496 496 .check_ipc_irq = hda_dsp_check_ipc_irq, 497 497 .cl_init = cl_dsp_init,
+60 -3
sound/soc/sof/intel/hda.c
··· 155 155 .free_stream = sdw_free_stream, 156 156 }; 157 157 158 + void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) 159 + { 160 + struct sof_intel_hda_dev *hdev; 161 + 162 + hdev = sdev->pdata->hw_pdata; 163 + 164 + if (!hdev->sdw) 165 + return; 166 + 167 + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC2, 168 + HDA_DSP_REG_ADSPIC2_SNDW, 169 + enable ? HDA_DSP_REG_ADSPIC2_SNDW : 0); 170 + } 171 + 158 172 void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) 159 173 { 160 - sdw_intel_enable_irq(sdev->bar[HDA_DSP_BAR], enable); 174 + const struct sof_intel_dsp_desc *chip; 175 + 176 + chip = get_chip_info(sdev->pdata); 177 + if (chip && chip->enable_sdw_irq) 178 + chip->enable_sdw_irq(sdev, enable); 161 179 } 162 180 163 181 static int hda_sdw_acpi_scan(struct snd_sof_dev *sdev) ··· 238 220 return 0; 239 221 } 240 222 223 + int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev) 224 + { 225 + struct sof_intel_hda_dev *hdev; 226 + struct sdw_intel_ctx *ctx; 227 + u32 caps; 228 + 229 + hdev = sdev->pdata->hw_pdata; 230 + ctx = hdev->sdw; 231 + 232 + caps = snd_sof_dsp_read(sdev, HDA_DSP_BAR, ctx->shim_base + SDW_SHIM_LCAP); 233 + caps &= SDW_SHIM_LCAP_LCOUNT_MASK; 234 + 235 + /* Check HW supported vs property value */ 236 + if (caps < ctx->count) { 237 + dev_err(sdev->dev, 238 + "BIOS master count %d is larger than hardware capabilities %d\n", 239 + ctx->count, caps); 240 + return -EINVAL; 241 + } 242 + 243 + return 0; 244 + } 245 + 246 + static int hda_sdw_check_lcount(struct snd_sof_dev *sdev) 247 + { 248 + const struct sof_intel_dsp_desc *chip; 249 + 250 + chip = get_chip_info(sdev->pdata); 251 + if (chip && chip->read_sdw_lcount) 252 + return chip->read_sdw_lcount(sdev); 253 + 254 + return 0; 255 + } 256 + 241 257 int hda_sdw_startup(struct snd_sof_dev *sdev) 242 258 { 243 259 struct sof_intel_hda_dev *hdev; 244 260 struct snd_sof_pdata *pdata = sdev->pdata; 261 + int ret; 245 262 246 263 hdev = sdev->pdata->hw_pdata; 247 264 ··· 285 232 286 233 if (pdata->machine && !pdata->machine->mach_params.link_mask) 287 234 return 0; 235 + 236 + ret = hda_sdw_check_lcount(sdev); 237 + if (ret < 0) 238 + return ret; 288 239 289 240 return sdw_intel_startup(hdev->sdw); 290 241 } ··· 944 887 return ret; 945 888 } 946 889 890 + hda_bus_ml_get_capabilities(bus); 891 + 947 892 /* scan SoundWire capabilities exposed by DSDT */ 948 893 ret = hda_sdw_acpi_scan(sdev); 949 894 if (ret < 0) { ··· 973 914 } 974 915 975 916 skip_soundwire: 976 - 977 - hda_bus_ml_get_capabilities(bus); 978 917 979 918 /* create codec instances */ 980 919 hda_codec_probe_bus(sdev);
+12
sound/soc/sof/intel/hda.h
··· 294 294 #define HDA_DSP_REG_ADSPIC2 (HDA_DSP_GEN_BASE + 0x10) 295 295 #define HDA_DSP_REG_ADSPIS2 (HDA_DSP_GEN_BASE + 0x14) 296 296 297 + #define HDA_DSP_REG_ADSPIC2_SNDW BIT(5) 297 298 #define HDA_DSP_REG_ADSPIS2_SNDW BIT(5) 298 299 299 300 /* Intel HD Audio Inter-Processor Communication Registers */ ··· 795 794 */ 796 795 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) 797 796 797 + int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev); 798 798 int hda_sdw_startup(struct snd_sof_dev *sdev); 799 + void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable); 799 800 void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable); 800 801 void hda_sdw_process_wakeen(struct snd_sof_dev *sdev); 801 802 bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev); 802 803 803 804 #else 804 805 806 + static inline int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev) 807 + { 808 + return 0; 809 + } 810 + 805 811 static inline int hda_sdw_startup(struct snd_sof_dev *sdev) 806 812 { 807 813 return 0; 814 + } 815 + 816 + static inline void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) 817 + { 808 818 } 809 819 810 820 static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
+2
sound/soc/sof/intel/icl.c
··· 181 181 .sdw_shim_base = SDW_SHIM_BASE, 182 182 .sdw_alh_base = SDW_ALH_BASE, 183 183 .d0i3_offset = SOF_HDA_VS_D0I3C, 184 + .read_sdw_lcount = hda_sdw_check_lcount_common, 185 + .enable_sdw_irq = hda_common_enable_sdw_irq, 184 186 .check_sdw_irq = hda_common_check_sdw_irq, 185 187 .check_ipc_irq = hda_dsp_check_ipc_irq, 186 188 .cl_init = cl_dsp_init,
+51 -80
sound/soc/sof/intel/mtl.c
··· 134 134 MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE, 0); 135 135 } 136 136 137 - static int mtl_enable_interrupts(struct snd_sof_dev *sdev) 137 + static void mtl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) 138 138 { 139 - u32 hfintipptr; 140 - u32 irqinten; 141 - u32 host_ipc; 142 139 u32 hipcie; 140 + u32 mask; 141 + u32 val; 143 142 int ret; 144 143 145 - /* read Interrupt IP Pointer */ 146 - hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK; 144 + /* Enable/Disable SoundWire interrupt */ 145 + mask = MTL_DSP_REG_HfSNDWIE_IE_MASK; 146 + if (enable) 147 + val = mask; 148 + else 149 + val = 0; 147 150 148 - /* Enable Host IPC and SOUNDWIRE */ 149 - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr, 150 - MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK, 151 - MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK); 152 - 153 - /* check if operation was successful */ 154 - host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK; 155 - ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten, 156 - (irqinten & host_ipc) == host_ipc, 157 - HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); 158 - if (ret < 0) { 159 - dev_err(sdev->dev, "failed to enable Host IPC and/or SOUNDWIRE\n"); 160 - return ret; 161 - } 162 - 163 - /* Set Host IPC interrupt enable */ 164 - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, 165 - MTL_DSP_REG_HfHIPCIE_IE_MASK, MTL_DSP_REG_HfHIPCIE_IE_MASK); 151 + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, mask, val); 166 152 167 153 /* check if operation was successful */ 168 - host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK; 169 - ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie, 170 - (hipcie & host_ipc) == host_ipc, 171 - HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); 172 - if (ret < 0) { 173 - dev_err(sdev->dev, "failed to set Host IPC interrupt enable\n"); 174 - return ret; 175 - } 176 - 177 - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, 178 - MTL_DSP_REG_HfSNDWIE_IE_MASK, MTL_DSP_REG_HfSNDWIE_IE_MASK); 179 - host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK; 180 154 ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie, 181 - (hipcie & host_ipc) == host_ipc, 155 + (hipcie & mask) == val, 182 156 HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); 183 157 if (ret < 0) 184 - dev_err(sdev->dev, "failed to set SoundWire IPC interrupt enable\n"); 185 - 186 - return ret; 158 + dev_err(sdev->dev, "failed to set SoundWire IPC interrupt %s\n", 159 + enable ? "enable" : "disable"); 187 160 } 188 161 189 - static int mtl_disable_interrupts(struct snd_sof_dev *sdev) 162 + static int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable) 190 163 { 191 164 u32 hfintipptr; 192 165 u32 irqinten; 193 - u32 host_ipc; 194 166 u32 hipcie; 195 - int ret1; 167 + u32 mask; 168 + u32 val; 196 169 int ret; 197 170 198 171 /* read Interrupt IP Pointer */ 199 172 hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK; 200 173 201 - /* Disable Host IPC and SOUNDWIRE */ 202 - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr, 203 - MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK, 0); 174 + /* Enable/Disable Host IPC and SOUNDWIRE */ 175 + mask = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK; 176 + if (enable) 177 + val = mask; 178 + else 179 + val = 0; 180 + 181 + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr, mask, val); 204 182 205 183 /* check if operation was successful */ 206 - host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK; 207 184 ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten, 208 - (irqinten & host_ipc) == 0, 185 + (irqinten & mask) == val, 209 186 HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); 210 - /* Continue to disable other interrupts when error happens */ 211 - if (ret < 0) 212 - dev_err(sdev->dev, "failed to disable Host IPC and SoundWire\n"); 213 - 214 - /* Set Host IPC interrupt disable */ 215 - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, 216 - MTL_DSP_REG_HfHIPCIE_IE_MASK, 0); 217 - 218 - /* check if operation was successful */ 219 - host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK; 220 - ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie, 221 - (hipcie & host_ipc) == 0, 222 - HDA_DSP_REG_POLL_INTERVAL_US, 223 - HDA_DSP_RESET_TIMEOUT_US); 224 - if (ret1 < 0) { 225 - dev_err(sdev->dev, "failed to set Host IPC interrupt disable\n"); 226 - if (!ret) 227 - ret = ret1; 187 + if (ret < 0) { 188 + dev_err(sdev->dev, "failed to %s Host IPC and/or SOUNDWIRE\n", 189 + enable ? "enable" : "disable"); 190 + return ret; 228 191 } 229 192 230 - /* Set SoundWire IPC interrupt disable */ 231 - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, 232 - MTL_DSP_REG_HfSNDWIE_IE_MASK, 0); 233 - host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK; 234 - ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie, 235 - (hipcie & host_ipc) == 0, 236 - HDA_DSP_REG_POLL_INTERVAL_US, 237 - HDA_DSP_RESET_TIMEOUT_US); 238 - if (ret1 < 0) { 239 - dev_err(sdev->dev, "failed to set SoundWire IPC interrupt disable\n"); 240 - if (!ret) 241 - ret = ret1; 193 + /* Enable/Disable Host IPC interrupt*/ 194 + mask = MTL_DSP_REG_HfHIPCIE_IE_MASK; 195 + if (enable) 196 + val = mask; 197 + else 198 + val = 0; 199 + 200 + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, mask, val); 201 + 202 + /* check if operation was successful */ 203 + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie, 204 + (hipcie & mask) == val, 205 + HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); 206 + if (ret < 0) { 207 + dev_err(sdev->dev, "failed to set Host IPC interrupt %s\n", 208 + enable ? "enable" : "disable"); 209 + return ret; 242 210 } 243 211 244 212 return ret; ··· 441 473 chip->ipc_ack_mask); 442 474 443 475 /* step 4: enable interrupts */ 444 - ret = mtl_enable_interrupts(sdev); 476 + ret = mtl_enable_interrupts(sdev, true); 445 477 if (ret < 0) { 446 478 if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) 447 479 dev_err(sdev->dev, "%s: failed to enable interrupts\n", __func__); ··· 576 608 577 609 static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev) 578 610 { 611 + mtl_enable_sdw_irq(sdev, false); 579 612 mtl_disable_ipc_interrupts(sdev); 580 - return mtl_disable_interrupts(sdev); 613 + return mtl_enable_interrupts(sdev, false); 581 614 } 582 615 583 616 /* Meteorlake ops */ ··· 654 685 .sdw_shim_base = SDW_SHIM_BASE_ACE, 655 686 .sdw_alh_base = SDW_ALH_BASE_ACE, 656 687 .d0i3_offset = MTL_HDA_VS_D0I3C, 688 + .read_sdw_lcount = hda_sdw_check_lcount_common, 689 + .enable_sdw_irq = mtl_enable_sdw_irq, 657 690 .check_sdw_irq = mtl_dsp_check_sdw_irq, 658 691 .check_ipc_irq = mtl_dsp_check_ipc_irq, 659 692 .cl_init = mtl_dsp_cl_init,
+2
sound/soc/sof/intel/shim.h
··· 185 185 u32 d0i3_offset; 186 186 u32 quirks; 187 187 enum sof_intel_hw_ip_version hw_ip_version; 188 + int (*read_sdw_lcount)(struct snd_sof_dev *sdev); 189 + void (*enable_sdw_irq)(struct snd_sof_dev *sdev, bool enable); 188 190 bool (*check_sdw_irq)(struct snd_sof_dev *sdev); 189 191 bool (*check_ipc_irq)(struct snd_sof_dev *sdev); 190 192 int (*power_down_dsp)(struct snd_sof_dev *sdev);
+8
sound/soc/sof/intel/tgl.c
··· 136 136 .sdw_shim_base = SDW_SHIM_BASE, 137 137 .sdw_alh_base = SDW_ALH_BASE, 138 138 .d0i3_offset = SOF_HDA_VS_D0I3C, 139 + .read_sdw_lcount = hda_sdw_check_lcount_common, 140 + .enable_sdw_irq = hda_common_enable_sdw_irq, 139 141 .check_sdw_irq = hda_common_check_sdw_irq, 140 142 .check_ipc_irq = hda_dsp_check_ipc_irq, 141 143 .cl_init = cl_dsp_init, ··· 164 162 .sdw_shim_base = SDW_SHIM_BASE, 165 163 .sdw_alh_base = SDW_ALH_BASE, 166 164 .d0i3_offset = SOF_HDA_VS_D0I3C, 165 + .read_sdw_lcount = hda_sdw_check_lcount_common, 166 + .enable_sdw_irq = hda_common_enable_sdw_irq, 167 167 .check_sdw_irq = hda_common_check_sdw_irq, 168 168 .check_ipc_irq = hda_dsp_check_ipc_irq, 169 169 .cl_init = cl_dsp_init, ··· 192 188 .sdw_shim_base = SDW_SHIM_BASE, 193 189 .sdw_alh_base = SDW_ALH_BASE, 194 190 .d0i3_offset = SOF_HDA_VS_D0I3C, 191 + .read_sdw_lcount = hda_sdw_check_lcount_common, 192 + .enable_sdw_irq = hda_common_enable_sdw_irq, 195 193 .check_sdw_irq = hda_common_check_sdw_irq, 196 194 .check_ipc_irq = hda_dsp_check_ipc_irq, 197 195 .cl_init = cl_dsp_init, ··· 220 214 .sdw_shim_base = SDW_SHIM_BASE, 221 215 .sdw_alh_base = SDW_ALH_BASE, 222 216 .d0i3_offset = SOF_HDA_VS_D0I3C, 217 + .read_sdw_lcount = hda_sdw_check_lcount_common, 218 + .enable_sdw_irq = hda_common_enable_sdw_irq, 223 219 .check_sdw_irq = hda_common_check_sdw_irq, 224 220 .check_ipc_irq = hda_dsp_check_ipc_irq, 225 221 .cl_init = cl_dsp_init,