1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 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 // 6 // Copyright(c) 2022 Advanced Micro Devices, Inc. 7 // 8 // Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com> 9 // V sujith kumar Reddy <Vsujithkumar.Reddy@amd.com> 10 /* 11 * Hardware interface for Renoir ACP block 12 */ 13 14 #include <linux/platform_device.h> 15 #include <linux/module.h> 16 #include <linux/err.h> 17 #include <linux/io.h> 18 #include <sound/pcm_params.h> 19 #include <sound/soc.h> 20 #include <sound/soc-dai.h> 21 #include <linux/dma-mapping.h> 22 23 #include "amd.h" 24 25 #define DRV_NAME "acp_asoc_rembrandt" 26 27 #define ACP6X_PGFSM_CONTROL 0x1024 28 #define ACP6X_PGFSM_STATUS 0x1028 29 30 #define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001 31 32 #define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01 33 #define ACP_PGFSM_CNTL_POWER_OFF_MASK 0x00 34 #define ACP_PGFSM_STATUS_MASK 0x03 35 #define ACP_POWERED_ON 0x00 36 #define ACP_POWER_ON_IN_PROGRESS 0x01 37 #define ACP_POWERED_OFF 0x02 38 #define ACP_POWER_OFF_IN_PROGRESS 0x03 39 40 #define ACP_ERROR_MASK 0x20000000 41 #define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF 42 43 44 static int rmb_acp_init(void __iomem *base); 45 static int rmb_acp_deinit(void __iomem *base); 46 47 static struct acp_resource rsrc = { 48 .offset = 0, 49 .no_of_ctrls = 2, 50 .irqp_used = 1, 51 .soc_mclk = true, 52 .irq_reg_offset = 0x1a00, 53 .i2s_pin_cfg_offset = 0x1440, 54 .i2s_mode = 0x0a, 55 .scratch_reg_offset = 0x12800, 56 .sram_pte_offset = 0x03802800, 57 }; 58 59 static struct snd_soc_acpi_codecs amp_rt1019 = { 60 .num_codecs = 1, 61 .codecs = {"10EC1019"} 62 }; 63 64 static struct snd_soc_acpi_codecs amp_max = { 65 .num_codecs = 1, 66 .codecs = {"MX98360A"} 67 }; 68 69 static struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines[] = { 70 { 71 .id = "10508825", 72 .drv_name = "rmb-nau8825-max", 73 .machine_quirk = snd_soc_acpi_codec_list, 74 .quirk_data = &_max, 75 }, 76 { 77 .id = "AMDI0007", 78 .drv_name = "rembrandt-acp", 79 }, 80 { 81 .id = "RTL5682", 82 .drv_name = "rmb-rt5682s-rt1019", 83 .machine_quirk = snd_soc_acpi_codec_list, 84 .quirk_data = &_rt1019, 85 }, 86 {}, 87 }; 88 89 static struct snd_soc_dai_driver acp_rmb_dai[] = { 90 { 91 .name = "acp-i2s-sp", 92 .id = I2S_SP_INSTANCE, 93 .playback = { 94 .stream_name = "I2S SP Playback", 95 .rates = SNDRV_PCM_RATE_8000_96000, 96 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | 97 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, 98 .channels_min = 2, 99 .channels_max = 8, 100 .rate_min = 8000, 101 .rate_max = 96000, 102 }, 103 .capture = { 104 .stream_name = "I2S SP Capture", 105 .rates = SNDRV_PCM_RATE_8000_48000, 106 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | 107 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, 108 .channels_min = 2, 109 .channels_max = 2, 110 .rate_min = 8000, 111 .rate_max = 48000, 112 }, 113 .ops = &asoc_acp_cpu_dai_ops, 114 .probe = &asoc_acp_i2s_probe, 115 }, 116 { 117 .name = "acp-i2s-bt", 118 .id = I2S_BT_INSTANCE, 119 .playback = { 120 .stream_name = "I2S BT Playback", 121 .rates = SNDRV_PCM_RATE_8000_96000, 122 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | 123 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, 124 .channels_min = 2, 125 .channels_max = 8, 126 .rate_min = 8000, 127 .rate_max = 96000, 128 }, 129 .capture = { 130 .stream_name = "I2S BT Capture", 131 .rates = SNDRV_PCM_RATE_8000_48000, 132 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | 133 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, 134 .channels_min = 2, 135 .channels_max = 2, 136 .rate_min = 8000, 137 .rate_max = 48000, 138 }, 139 .ops = &asoc_acp_cpu_dai_ops, 140 .probe = &asoc_acp_i2s_probe, 141 }, 142 { 143 .name = "acp-i2s-hs", 144 .id = I2S_HS_INSTANCE, 145 .playback = { 146 .stream_name = "I2S HS Playback", 147 .rates = SNDRV_PCM_RATE_8000_96000, 148 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | 149 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, 150 .channels_min = 2, 151 .channels_max = 8, 152 .rate_min = 8000, 153 .rate_max = 96000, 154 }, 155 .capture = { 156 .stream_name = "I2S HS Capture", 157 .rates = SNDRV_PCM_RATE_8000_48000, 158 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | 159 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, 160 .channels_min = 2, 161 .channels_max = 8, 162 .rate_min = 8000, 163 .rate_max = 48000, 164 }, 165 .ops = &asoc_acp_cpu_dai_ops, 166 .probe = &asoc_acp_i2s_probe, 167 }, 168 { 169 .name = "acp-pdm-dmic", 170 .id = DMIC_INSTANCE, 171 .capture = { 172 .rates = SNDRV_PCM_RATE_8000_48000, 173 .formats = SNDRV_PCM_FMTBIT_S32_LE, 174 .channels_min = 2, 175 .channels_max = 2, 176 .rate_min = 8000, 177 .rate_max = 48000, 178 }, 179 .ops = &acp_dmic_dai_ops, 180 }, 181 }; 182 183 static int acp6x_power_on(void __iomem *base) 184 { 185 u32 val; 186 int timeout; 187 188 val = readl(base + ACP6X_PGFSM_STATUS); 189 190 if (val == ACP_POWERED_ON) 191 return 0; 192 193 if ((val & ACP_PGFSM_STATUS_MASK) != 194 ACP_POWER_ON_IN_PROGRESS) 195 writel(ACP_PGFSM_CNTL_POWER_ON_MASK, 196 base + ACP6X_PGFSM_CONTROL); 197 timeout = 0; 198 while (++timeout < 500) { 199 val = readl(base + ACP6X_PGFSM_STATUS); 200 if (!val) 201 return 0; 202 udelay(1); 203 } 204 return -ETIMEDOUT; 205 } 206 207 static int acp6x_power_off(void __iomem *base) 208 { 209 u32 val; 210 int timeout; 211 212 writel(ACP_PGFSM_CNTL_POWER_OFF_MASK, 213 base + ACP6X_PGFSM_CONTROL); 214 timeout = 0; 215 while (++timeout < 500) { 216 val = readl(base + ACP6X_PGFSM_STATUS); 217 if ((val & ACP_PGFSM_STATUS_MASK) == ACP_POWERED_OFF) 218 return 0; 219 udelay(1); 220 } 221 return -ETIMEDOUT; 222 } 223 224 static int acp6x_reset(void __iomem *base) 225 { 226 u32 val; 227 int timeout; 228 229 writel(1, base + ACP_SOFT_RESET); 230 timeout = 0; 231 while (++timeout < 500) { 232 val = readl(base + ACP_SOFT_RESET); 233 if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK) 234 break; 235 cpu_relax(); 236 } 237 writel(0, base + ACP_SOFT_RESET); 238 timeout = 0; 239 while (++timeout < 500) { 240 val = readl(base + ACP_SOFT_RESET); 241 if (!val) 242 return 0; 243 cpu_relax(); 244 } 245 return -ETIMEDOUT; 246 } 247 248 static void acp6x_enable_interrupts(struct acp_dev_data *adata) 249 { 250 struct acp_resource *rsrc = adata->rsrc; 251 u32 ext_intr_ctrl; 252 253 writel(0x01, ACP_EXTERNAL_INTR_ENB(adata)); 254 ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); 255 ext_intr_ctrl |= ACP_ERROR_MASK; 256 writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); 257 } 258 259 static void acp6x_disable_interrupts(struct acp_dev_data *adata) 260 { 261 struct acp_resource *rsrc = adata->rsrc; 262 263 writel(ACP_EXT_INTR_STAT_CLEAR_MASK, 264 ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); 265 writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); 266 } 267 268 static int rmb_acp_init(void __iomem *base) 269 { 270 int ret; 271 272 /* power on */ 273 ret = acp6x_power_on(base); 274 if (ret) { 275 pr_err("ACP power on failed\n"); 276 return ret; 277 } 278 writel(0x01, base + ACP_CONTROL); 279 280 /* Reset */ 281 ret = acp6x_reset(base); 282 if (ret) { 283 pr_err("ACP reset failed\n"); 284 return ret; 285 } 286 287 return 0; 288 } 289 290 static int rmb_acp_deinit(void __iomem *base) 291 { 292 int ret = 0; 293 294 /* Reset */ 295 ret = acp6x_reset(base); 296 if (ret) { 297 pr_err("ACP reset failed\n"); 298 return ret; 299 } 300 301 writel(0x00, base + ACP_CONTROL); 302 303 /* power off */ 304 ret = acp6x_power_off(base); 305 if (ret) { 306 pr_err("ACP power off failed\n"); 307 return ret; 308 } 309 310 return 0; 311 } 312 313 static int rembrandt_audio_probe(struct platform_device *pdev) 314 { 315 struct device *dev = &pdev->dev; 316 struct acp_chip_info *chip; 317 struct acp_dev_data *adata; 318 struct resource *res; 319 320 chip = dev_get_platdata(&pdev->dev); 321 if (!chip || !chip->base) { 322 dev_err(&pdev->dev, "ACP chip data is NULL\n"); 323 return -ENODEV; 324 } 325 326 if (chip->acp_rev != ACP6X_DEV) { 327 dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); 328 return -ENODEV; 329 } 330 331 rmb_acp_init(chip->base); 332 333 adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL); 334 if (!adata) 335 return -ENOMEM; 336 337 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem"); 338 if (!res) { 339 dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); 340 return -ENODEV; 341 } 342 343 adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 344 if (!adata->acp_base) 345 return -ENOMEM; 346 347 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq"); 348 if (!res) { 349 dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); 350 return -ENODEV; 351 } 352 353 adata->i2s_irq = res->start; 354 adata->dev = dev; 355 adata->dai_driver = acp_rmb_dai; 356 adata->num_dai = ARRAY_SIZE(acp_rmb_dai); 357 adata->rsrc = &rsrc; 358 359 adata->machines = snd_soc_acpi_amd_rmb_acp_machines; 360 acp_machine_select(adata); 361 362 dev_set_drvdata(dev, adata); 363 acp6x_enable_interrupts(adata); 364 acp_platform_register(dev); 365 366 return 0; 367 } 368 369 static void rembrandt_audio_remove(struct platform_device *pdev) 370 { 371 struct device *dev = &pdev->dev; 372 struct acp_dev_data *adata = dev_get_drvdata(dev); 373 struct acp_chip_info *chip = dev_get_platdata(dev); 374 375 rmb_acp_deinit(chip->base); 376 377 acp6x_disable_interrupts(adata); 378 acp_platform_unregister(dev); 379 } 380 381 static struct platform_driver rembrandt_driver = { 382 .probe = rembrandt_audio_probe, 383 .remove_new = rembrandt_audio_remove, 384 .driver = { 385 .name = "acp_asoc_rembrandt", 386 }, 387 }; 388 389 module_platform_driver(rembrandt_driver); 390 391 MODULE_DESCRIPTION("AMD ACP Rembrandt Driver"); 392 MODULE_IMPORT_NS(SND_SOC_ACP_COMMON); 393 MODULE_LICENSE("Dual BSD/GPL"); 394 MODULE_ALIAS("platform:" DRV_NAME); 395