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_reset(void __iomem *base) 208 { 209 u32 val; 210 int timeout; 211 212 writel(1, base + ACP_SOFT_RESET); 213 timeout = 0; 214 while (++timeout < 500) { 215 val = readl(base + ACP_SOFT_RESET); 216 if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK) 217 break; 218 cpu_relax(); 219 } 220 writel(0, base + ACP_SOFT_RESET); 221 timeout = 0; 222 while (++timeout < 500) { 223 val = readl(base + ACP_SOFT_RESET); 224 if (!val) 225 return 0; 226 cpu_relax(); 227 } 228 return -ETIMEDOUT; 229 } 230 231 static void acp6x_enable_interrupts(struct acp_dev_data *adata) 232 { 233 struct acp_resource *rsrc = adata->rsrc; 234 u32 ext_intr_ctrl; 235 236 writel(0x01, ACP_EXTERNAL_INTR_ENB(adata)); 237 ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); 238 ext_intr_ctrl |= ACP_ERROR_MASK; 239 writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); 240 } 241 242 static void acp6x_disable_interrupts(struct acp_dev_data *adata) 243 { 244 struct acp_resource *rsrc = adata->rsrc; 245 246 writel(ACP_EXT_INTR_STAT_CLEAR_MASK, 247 ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); 248 writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); 249 } 250 251 static int rmb_acp_init(void __iomem *base) 252 { 253 int ret; 254 255 /* power on */ 256 ret = acp6x_power_on(base); 257 if (ret) { 258 pr_err("ACP power on failed\n"); 259 return ret; 260 } 261 writel(0x01, base + ACP_CONTROL); 262 263 /* Reset */ 264 ret = acp6x_reset(base); 265 if (ret) { 266 pr_err("ACP reset failed\n"); 267 return ret; 268 } 269 270 return 0; 271 } 272 273 static int rmb_acp_deinit(void __iomem *base) 274 { 275 int ret = 0; 276 277 /* Reset */ 278 ret = acp6x_reset(base); 279 if (ret) { 280 pr_err("ACP reset failed\n"); 281 return ret; 282 } 283 284 writel(0x00, base + ACP_CONTROL); 285 return 0; 286 } 287 288 static int rembrandt_audio_probe(struct platform_device *pdev) 289 { 290 struct device *dev = &pdev->dev; 291 struct acp_chip_info *chip; 292 struct acp_dev_data *adata; 293 struct resource *res; 294 295 chip = dev_get_platdata(&pdev->dev); 296 if (!chip || !chip->base) { 297 dev_err(&pdev->dev, "ACP chip data is NULL\n"); 298 return -ENODEV; 299 } 300 301 if (chip->acp_rev != ACP6X_DEV) { 302 dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); 303 return -ENODEV; 304 } 305 306 rmb_acp_init(chip->base); 307 308 adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL); 309 if (!adata) 310 return -ENOMEM; 311 312 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem"); 313 if (!res) { 314 dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); 315 return -ENODEV; 316 } 317 318 adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 319 if (!adata->acp_base) 320 return -ENOMEM; 321 322 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq"); 323 if (!res) { 324 dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); 325 return -ENODEV; 326 } 327 328 adata->i2s_irq = res->start; 329 adata->dev = dev; 330 adata->dai_driver = acp_rmb_dai; 331 adata->num_dai = ARRAY_SIZE(acp_rmb_dai); 332 adata->rsrc = &rsrc; 333 334 adata->machines = snd_soc_acpi_amd_rmb_acp_machines; 335 acp_machine_select(adata); 336 337 dev_set_drvdata(dev, adata); 338 acp6x_enable_interrupts(adata); 339 acp_platform_register(dev); 340 341 return 0; 342 } 343 344 static void rembrandt_audio_remove(struct platform_device *pdev) 345 { 346 struct device *dev = &pdev->dev; 347 struct acp_dev_data *adata = dev_get_drvdata(dev); 348 struct acp_chip_info *chip = dev_get_platdata(dev); 349 350 rmb_acp_deinit(chip->base); 351 352 acp6x_disable_interrupts(adata); 353 acp_platform_unregister(dev); 354 } 355 356 static struct platform_driver rembrandt_driver = { 357 .probe = rembrandt_audio_probe, 358 .remove_new = rembrandt_audio_remove, 359 .driver = { 360 .name = "acp_asoc_rembrandt", 361 }, 362 }; 363 364 module_platform_driver(rembrandt_driver); 365 366 MODULE_DESCRIPTION("AMD ACP Rembrandt Driver"); 367 MODULE_IMPORT_NS(SND_SOC_ACP_COMMON); 368 MODULE_LICENSE("Dual BSD/GPL"); 369 MODULE_ALIAS("platform:" DRV_NAME); 370