1 // SPDX-License-Identifier: GPL-2.0+ 2 // 3 // AMD Vangogh ACP PCI Driver 4 // 5 // Copyright (C) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved. 6 7 #include <linux/pci.h> 8 #include <linux/module.h> 9 #include <linux/io.h> 10 #include <linux/delay.h> 11 #include <linux/platform_device.h> 12 #include <linux/interrupt.h> 13 #include <linux/pm_runtime.h> 14 15 #include "acp5x.h" 16 #include "../mach-config.h" 17 18 struct acp5x_dev_data { 19 void __iomem *acp5x_base; 20 bool acp5x_audio_mode; 21 struct resource *res; 22 struct platform_device *pdev[ACP5x_DEVS]; 23 }; 24 25 static int acp5x_power_on(void __iomem *acp5x_base) 26 { 27 u32 val; 28 int timeout; 29 30 val = acp_readl(acp5x_base + ACP_PGFSM_STATUS); 31 32 if (val == 0) 33 return val; 34 35 if ((val & ACP_PGFSM_STATUS_MASK) != 36 ACP_POWER_ON_IN_PROGRESS) 37 acp_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, 38 acp5x_base + ACP_PGFSM_CONTROL); 39 timeout = 0; 40 while (++timeout < 500) { 41 val = acp_readl(acp5x_base + ACP_PGFSM_STATUS); 42 if ((val & ACP_PGFSM_STATUS_MASK) == ACP_POWERED_ON) 43 return 0; 44 udelay(1); 45 } 46 return -ETIMEDOUT; 47 } 48 49 static int acp5x_reset(void __iomem *acp5x_base) 50 { 51 u32 val; 52 int timeout; 53 54 acp_writel(1, acp5x_base + ACP_SOFT_RESET); 55 timeout = 0; 56 while (++timeout < 500) { 57 val = acp_readl(acp5x_base + ACP_SOFT_RESET); 58 if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK) 59 break; 60 cpu_relax(); 61 } 62 acp_writel(0, acp5x_base + ACP_SOFT_RESET); 63 timeout = 0; 64 while (++timeout < 500) { 65 val = acp_readl(acp5x_base + ACP_SOFT_RESET); 66 if (!val) 67 return 0; 68 cpu_relax(); 69 } 70 return -ETIMEDOUT; 71 } 72 73 static void acp5x_enable_interrupts(void __iomem *acp5x_base) 74 { 75 acp_writel(0x01, acp5x_base + ACP_EXTERNAL_INTR_ENB); 76 } 77 78 static void acp5x_disable_interrupts(void __iomem *acp5x_base) 79 { 80 acp_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp5x_base + 81 ACP_EXTERNAL_INTR_STAT); 82 acp_writel(0x00, acp5x_base + ACP_EXTERNAL_INTR_CNTL); 83 acp_writel(0x00, acp5x_base + ACP_EXTERNAL_INTR_ENB); 84 } 85 86 static int acp5x_init(void __iomem *acp5x_base) 87 { 88 int ret; 89 90 /* power on */ 91 ret = acp5x_power_on(acp5x_base); 92 if (ret) { 93 pr_err("ACP5x power on failed\n"); 94 return ret; 95 } 96 acp_writel(0x01, acp5x_base + ACP_CONTROL); 97 /* Reset */ 98 ret = acp5x_reset(acp5x_base); 99 if (ret) { 100 pr_err("ACP5x reset failed\n"); 101 return ret; 102 } 103 acp_writel(0x03, acp5x_base + ACP_CLKMUX_SEL); 104 acp5x_enable_interrupts(acp5x_base); 105 return 0; 106 } 107 108 static int acp5x_deinit(void __iomem *acp5x_base) 109 { 110 int ret; 111 112 acp5x_disable_interrupts(acp5x_base); 113 /* Reset */ 114 ret = acp5x_reset(acp5x_base); 115 if (ret) { 116 pr_err("ACP5x reset failed\n"); 117 return ret; 118 } 119 acp_writel(0x00, acp5x_base + ACP_CLKMUX_SEL); 120 acp_writel(0x00, acp5x_base + ACP_CONTROL); 121 return 0; 122 } 123 124 static int snd_acp5x_probe(struct pci_dev *pci, 125 const struct pci_device_id *pci_id) 126 { 127 struct acp5x_dev_data *adata; 128 struct platform_device_info pdevinfo[ACP5x_DEVS]; 129 unsigned int irqflags, flag; 130 int ret, i; 131 u32 addr, val; 132 133 /* Return if acp config flag is defined */ 134 flag = snd_amd_acp_find_config(pci); 135 if (flag != FLAG_AMD_LEGACY) 136 return -ENODEV; 137 138 irqflags = IRQF_SHARED; 139 if (pci->revision != 0x50) 140 return -ENODEV; 141 142 if (pci_enable_device(pci)) { 143 dev_err(&pci->dev, "pci_enable_device failed\n"); 144 return -ENODEV; 145 } 146 147 ret = pci_request_regions(pci, "AMD ACP5x audio"); 148 if (ret < 0) { 149 dev_err(&pci->dev, "pci_request_regions failed\n"); 150 goto disable_pci; 151 } 152 153 adata = devm_kzalloc(&pci->dev, sizeof(struct acp5x_dev_data), 154 GFP_KERNEL); 155 if (!adata) { 156 ret = -ENOMEM; 157 goto release_regions; 158 } 159 addr = pci_resource_start(pci, 0); 160 adata->acp5x_base = devm_ioremap(&pci->dev, addr, 161 pci_resource_len(pci, 0)); 162 if (!adata->acp5x_base) { 163 ret = -ENOMEM; 164 goto release_regions; 165 } 166 pci_set_master(pci); 167 pci_set_drvdata(pci, adata); 168 ret = acp5x_init(adata->acp5x_base); 169 if (ret) 170 goto release_regions; 171 172 val = acp_readl(adata->acp5x_base + ACP_PIN_CONFIG); 173 switch (val) { 174 case I2S_MODE: 175 adata->res = devm_kzalloc(&pci->dev, 176 sizeof(struct resource) * ACP5x_RES, 177 GFP_KERNEL); 178 if (!adata->res) { 179 ret = -ENOMEM; 180 goto de_init; 181 } 182 183 adata->res[0].name = "acp5x_i2s_iomem"; 184 adata->res[0].flags = IORESOURCE_MEM; 185 adata->res[0].start = addr; 186 adata->res[0].end = addr + (ACP5x_REG_END - ACP5x_REG_START); 187 188 adata->res[1].name = "acp5x_i2s_sp"; 189 adata->res[1].flags = IORESOURCE_MEM; 190 adata->res[1].start = addr + ACP5x_I2STDM_REG_START; 191 adata->res[1].end = addr + ACP5x_I2STDM_REG_END; 192 193 adata->res[2].name = "acp5x_i2s_hs"; 194 adata->res[2].flags = IORESOURCE_MEM; 195 adata->res[2].start = addr + ACP5x_HS_TDM_REG_START; 196 adata->res[2].end = addr + ACP5x_HS_TDM_REG_END; 197 198 adata->res[3].name = "acp5x_i2s_irq"; 199 adata->res[3].flags = IORESOURCE_IRQ; 200 adata->res[3].start = pci->irq; 201 adata->res[3].end = adata->res[3].start; 202 203 adata->acp5x_audio_mode = ACP5x_I2S_MODE; 204 205 memset(&pdevinfo, 0, sizeof(pdevinfo)); 206 pdevinfo[0].name = "acp5x_i2s_dma"; 207 pdevinfo[0].id = 0; 208 pdevinfo[0].parent = &pci->dev; 209 pdevinfo[0].num_res = 4; 210 pdevinfo[0].res = &adata->res[0]; 211 pdevinfo[0].data = &irqflags; 212 pdevinfo[0].size_data = sizeof(irqflags); 213 214 pdevinfo[1].name = "acp5x_i2s_playcap"; 215 pdevinfo[1].id = 0; 216 pdevinfo[1].parent = &pci->dev; 217 pdevinfo[1].num_res = 1; 218 pdevinfo[1].res = &adata->res[1]; 219 220 pdevinfo[2].name = "acp5x_i2s_playcap"; 221 pdevinfo[2].id = 1; 222 pdevinfo[2].parent = &pci->dev; 223 pdevinfo[2].num_res = 1; 224 pdevinfo[2].res = &adata->res[2]; 225 226 pdevinfo[3].name = "acp5x_mach"; 227 pdevinfo[3].id = 0; 228 pdevinfo[3].parent = &pci->dev; 229 for (i = 0; i < ACP5x_DEVS; i++) { 230 adata->pdev[i] = 231 platform_device_register_full(&pdevinfo[i]); 232 if (IS_ERR(adata->pdev[i])) { 233 dev_err(&pci->dev, "cannot register %s device\n", 234 pdevinfo[i].name); 235 ret = PTR_ERR(adata->pdev[i]); 236 goto unregister_devs; 237 } 238 } 239 break; 240 default: 241 dev_info(&pci->dev, "ACP audio mode : %d\n", val); 242 } 243 pm_runtime_set_autosuspend_delay(&pci->dev, 2000); 244 pm_runtime_use_autosuspend(&pci->dev); 245 pm_runtime_put_noidle(&pci->dev); 246 pm_runtime_allow(&pci->dev); 247 return 0; 248 249 unregister_devs: 250 for (--i; i >= 0; i--) 251 platform_device_unregister(adata->pdev[i]); 252 de_init: 253 if (acp5x_deinit(adata->acp5x_base)) 254 dev_err(&pci->dev, "ACP de-init failed\n"); 255 release_regions: 256 pci_release_regions(pci); 257 disable_pci: 258 pci_disable_device(pci); 259 260 return ret; 261 } 262 263 static int __maybe_unused snd_acp5x_suspend(struct device *dev) 264 { 265 int ret; 266 struct acp5x_dev_data *adata; 267 268 adata = dev_get_drvdata(dev); 269 ret = acp5x_deinit(adata->acp5x_base); 270 if (ret) 271 dev_err(dev, "ACP de-init failed\n"); 272 else 273 dev_dbg(dev, "ACP de-initialized\n"); 274 275 return ret; 276 } 277 278 static int __maybe_unused snd_acp5x_resume(struct device *dev) 279 { 280 int ret; 281 struct acp5x_dev_data *adata; 282 283 adata = dev_get_drvdata(dev); 284 ret = acp5x_init(adata->acp5x_base); 285 if (ret) { 286 dev_err(dev, "ACP init failed\n"); 287 return ret; 288 } 289 return 0; 290 } 291 292 static const struct dev_pm_ops acp5x_pm = { 293 SET_RUNTIME_PM_OPS(snd_acp5x_suspend, 294 snd_acp5x_resume, NULL) 295 SET_SYSTEM_SLEEP_PM_OPS(snd_acp5x_suspend, snd_acp5x_resume) 296 }; 297 298 static void snd_acp5x_remove(struct pci_dev *pci) 299 { 300 struct acp5x_dev_data *adata; 301 int i, ret; 302 303 adata = pci_get_drvdata(pci); 304 if (adata->acp5x_audio_mode == ACP5x_I2S_MODE) { 305 for (i = 0; i < ACP5x_DEVS; i++) 306 platform_device_unregister(adata->pdev[i]); 307 } 308 ret = acp5x_deinit(adata->acp5x_base); 309 if (ret) 310 dev_err(&pci->dev, "ACP de-init failed\n"); 311 pm_runtime_forbid(&pci->dev); 312 pm_runtime_get_noresume(&pci->dev); 313 pci_release_regions(pci); 314 pci_disable_device(pci); 315 } 316 317 static const struct pci_device_id snd_acp5x_ids[] = { 318 { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID), 319 .class = PCI_CLASS_MULTIMEDIA_OTHER << 8, 320 .class_mask = 0xffffff }, 321 { 0, }, 322 }; 323 MODULE_DEVICE_TABLE(pci, snd_acp5x_ids); 324 325 static struct pci_driver acp5x_driver = { 326 .name = KBUILD_MODNAME, 327 .id_table = snd_acp5x_ids, 328 .probe = snd_acp5x_probe, 329 .remove = snd_acp5x_remove, 330 .driver = { 331 .pm = &acp5x_pm, 332 } 333 }; 334 335 module_pci_driver(acp5x_driver); 336 337 MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); 338 MODULE_DESCRIPTION("AMD Vangogh ACP PCI driver"); 339 MODULE_LICENSE("GPL v2"); 340