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) 2021 Advanced Micro Devices, Inc. 7 // 8 // Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com> 9 // 10 11 /* 12 * Hardware interface for Renoir ACP block 13 */ 14 15 #include <linux/platform_device.h> 16 #include <linux/module.h> 17 #include <linux/err.h> 18 #include <linux/io.h> 19 #include <sound/pcm_params.h> 20 #include <sound/soc.h> 21 #include <sound/soc-dai.h> 22 #include <linux/dma-mapping.h> 23 24 #include "amd.h" 25 26 #define DRV_NAME "acp_asoc_renoir" 27 28 #define ACP_SOFT_RST_DONE_MASK 0x00010001 29 30 #define ACP_PWR_ON_MASK 0x01 31 #define ACP_PWR_OFF_MASK 0x00 32 #define ACP_PGFSM_STAT_MASK 0x03 33 #define ACP_POWERED_ON 0x00 34 #define ACP_PWR_ON_IN_PROGRESS 0x01 35 #define ACP_POWERED_OFF 0x02 36 #define DELAY_US 5 37 #define ACP_TIMEOUT 500 38 39 #define ACP_ERROR_MASK 0x20000000 40 #define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF 41 42 static struct acp_resource rsrc = { 43 .offset = 20, 44 .no_of_ctrls = 1, 45 .irqp_used = 0, 46 .irq_reg_offset = 0x1800, 47 .i2s_pin_cfg_offset = 0x1400, 48 .i2s_mode = 0x04, 49 .scratch_reg_offset = 0x12800, 50 .sram_pte_offset = 0x02052800, 51 }; 52 53 static struct snd_soc_acpi_codecs amp_rt1019 = { 54 .num_codecs = 1, 55 .codecs = {"10EC1019"} 56 }; 57 58 static struct snd_soc_acpi_codecs amp_max = { 59 .num_codecs = 1, 60 .codecs = {"MX98360A"} 61 }; 62 63 static struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[] = { 64 { 65 .id = "10EC5682", 66 .drv_name = "acp3xalc56821019", 67 .machine_quirk = snd_soc_acpi_codec_list, 68 .quirk_data = &_rt1019, 69 }, 70 { 71 .id = "RTL5682", 72 .drv_name = "acp3xalc5682sm98360", 73 .machine_quirk = snd_soc_acpi_codec_list, 74 .quirk_data = &_max, 75 }, 76 { 77 .id = "RTL5682", 78 .drv_name = "acp3xalc5682s1019", 79 .machine_quirk = snd_soc_acpi_codec_list, 80 .quirk_data = &_rt1019, 81 }, 82 { 83 .id = "AMDI1019", 84 .drv_name = "renoir-acp", 85 }, 86 {}, 87 }; 88 89 static struct snd_soc_dai_driver acp_renoir_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-pdm-dmic", 144 .id = DMIC_INSTANCE, 145 .capture = { 146 .rates = SNDRV_PCM_RATE_8000_48000, 147 .formats = SNDRV_PCM_FMTBIT_S32_LE, 148 .channels_min = 2, 149 .channels_max = 2, 150 .rate_min = 8000, 151 .rate_max = 48000, 152 }, 153 .ops = &acp_dmic_dai_ops, 154 }, 155 }; 156 157 static int acp3x_power_on(void __iomem *base) 158 { 159 u32 val; 160 161 val = readl(base + ACP_PGFSM_STATUS); 162 163 if (val == ACP_POWERED_ON) 164 return 0; 165 166 if ((val & ACP_PGFSM_STAT_MASK) != ACP_PWR_ON_IN_PROGRESS) 167 writel(ACP_PWR_ON_MASK, base + ACP_PGFSM_CONTROL); 168 169 return readl_poll_timeout(base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP_TIMEOUT); 170 } 171 172 static int acp3x_power_off(void __iomem *base) 173 { 174 u32 val; 175 176 writel(ACP_PWR_OFF_MASK, base + ACP_PGFSM_CONTROL); 177 178 return readl_poll_timeout(base + ACP_PGFSM_STATUS, val, 179 (val & ACP_PGFSM_STAT_MASK) == ACP_POWERED_OFF, 180 DELAY_US, ACP_TIMEOUT); 181 } 182 183 static int acp3x_reset(void __iomem *base) 184 { 185 u32 val; 186 int ret; 187 188 writel(1, base + ACP_SOFT_RESET); 189 190 ret = readl_poll_timeout(base + ACP_SOFT_RESET, val, val & ACP_SOFT_RST_DONE_MASK, 191 DELAY_US, ACP_TIMEOUT); 192 if (ret) 193 return ret; 194 195 writel(0, base + ACP_SOFT_RESET); 196 197 return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT); 198 } 199 200 static void acp3x_enable_interrupts(struct acp_dev_data *adata) 201 { 202 struct acp_resource *rsrc = adata->rsrc; 203 u32 ext_intr_ctrl; 204 205 writel(0x01, ACP_EXTERNAL_INTR_ENB(adata)); 206 ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); 207 ext_intr_ctrl |= ACP_ERROR_MASK; 208 writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); 209 } 210 211 static void acp3x_disable_interrupts(struct acp_dev_data *adata) 212 { 213 struct acp_resource *rsrc = adata->rsrc; 214 215 writel(ACP_EXT_INTR_STAT_CLEAR_MASK, 216 ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); 217 writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); 218 } 219 220 static int rn_acp_init(void __iomem *base) 221 { 222 int ret; 223 224 /* power on */ 225 ret = acp3x_power_on(base); 226 if (ret) 227 return ret; 228 229 writel(0x01, base + ACP_CONTROL); 230 231 /* Reset */ 232 ret = acp3x_reset(base); 233 if (ret) 234 return ret; 235 236 return 0; 237 } 238 239 static int rn_acp_deinit(void __iomem *base) 240 { 241 int ret = 0; 242 243 /* Reset */ 244 ret = acp3x_reset(base); 245 if (ret) 246 return ret; 247 248 writel(0x00, base + ACP_CONTROL); 249 250 /* power off */ 251 ret = acp3x_power_off(base); 252 if (ret) 253 return ret; 254 255 return 0; 256 } 257 static int renoir_audio_probe(struct platform_device *pdev) 258 { 259 struct device *dev = &pdev->dev; 260 struct acp_chip_info *chip; 261 struct acp_dev_data *adata; 262 struct resource *res; 263 int ret; 264 265 chip = dev_get_platdata(&pdev->dev); 266 if (!chip || !chip->base) { 267 dev_err(&pdev->dev, "ACP chip data is NULL\n"); 268 return -ENODEV; 269 } 270 271 if (chip->acp_rev != ACP3X_DEV) { 272 dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); 273 return -ENODEV; 274 } 275 276 ret = rn_acp_init(chip->base); 277 if (ret) { 278 dev_err(&pdev->dev, "ACP Init failed\n"); 279 return -EINVAL; 280 } 281 282 adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL); 283 if (!adata) 284 return -ENOMEM; 285 286 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem"); 287 if (!res) { 288 dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); 289 return -ENODEV; 290 } 291 292 adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 293 if (!adata->acp_base) 294 return -ENOMEM; 295 296 ret = platform_get_irq_byname(pdev, "acp_dai_irq"); 297 if (ret < 0) 298 return ret; 299 adata->i2s_irq = ret; 300 301 adata->dev = dev; 302 adata->dai_driver = acp_renoir_dai; 303 adata->num_dai = ARRAY_SIZE(acp_renoir_dai); 304 adata->rsrc = &rsrc; 305 306 adata->machines = snd_soc_acpi_amd_acp_machines; 307 acp_machine_select(adata); 308 309 dev_set_drvdata(dev, adata); 310 acp3x_enable_interrupts(adata); 311 acp_platform_register(dev); 312 313 return 0; 314 } 315 316 static int renoir_audio_remove(struct platform_device *pdev) 317 { 318 struct device *dev = &pdev->dev; 319 struct acp_dev_data *adata = dev_get_drvdata(dev); 320 struct acp_chip_info *chip; 321 int ret; 322 323 chip = dev_get_platdata(&pdev->dev); 324 325 acp3x_disable_interrupts(adata); 326 327 ret = rn_acp_deinit(chip->base); 328 if (ret) 329 dev_err(&pdev->dev, "ACP de-init Failed (%pe)\n", ERR_PTR(ret)); 330 331 acp_platform_unregister(dev); 332 return 0; 333 } 334 335 static struct platform_driver renoir_driver = { 336 .probe = renoir_audio_probe, 337 .remove = renoir_audio_remove, 338 .driver = { 339 .name = "acp_asoc_renoir", 340 }, 341 }; 342 343 module_platform_driver(renoir_driver); 344 345 MODULE_DESCRIPTION("AMD ACP Renoir Driver"); 346 MODULE_IMPORT_NS(SND_SOC_ACP_COMMON); 347 MODULE_LICENSE("Dual BSD/GPL"); 348 MODULE_ALIAS("platform:" DRV_NAME); 349