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) 2023 Advanced Micro Devices, Inc. 7 // 8 // Authors: Syed Saba kareem <syed.sabakareem@amd.com> 9 /* 10 * Hardware interface for ACP6.3 block 11 */ 12 13 #include <linux/platform_device.h> 14 #include <linux/module.h> 15 #include <linux/err.h> 16 #include <linux/io.h> 17 #include <sound/pcm_params.h> 18 #include <sound/soc.h> 19 #include <sound/soc-dai.h> 20 #include <linux/dma-mapping.h> 21 #include <linux/pm_runtime.h> 22 #include <linux/pci.h> 23 #include "amd.h" 24 #include "acp-mach.h" 25 #include "../mach-config.h" 26 27 #define DRV_NAME "acp_asoc_acp63" 28 29 #define CLK_PLL_PWR_REQ_N0 0X0006C2C0 30 #define CLK_SPLL_FIELD_2_N0 0X0006C114 31 #define CLK_PLL_REQ_N0 0X0006C0DC 32 #define CLK_DFSBYPASS_CONTR 0X0006C2C8 33 #define CLK_DFS_CNTL_N0 0X0006C1A4 34 35 #define PLL_AUTO_STOP_REQ BIT(4) 36 #define PLL_AUTO_START_REQ BIT(0) 37 #define PLL_FRANCE_EN BIT(4) 38 #define EXIT_DPF_BYPASS_0 BIT(16) 39 #define EXIT_DPF_BYPASS_1 BIT(17) 40 #define CLK0_DIVIDER 0X30 41 42 union clk_pll_req_no { 43 struct { 44 u32 fb_mult_int : 9; 45 u32 reserved : 3; 46 u32 pll_spine_div : 4; 47 u32 gb_mult_frac : 16; 48 } bitfields, bits; 49 u32 clk_pll_req_no_reg; 50 }; 51 52 static struct acp_resource rsrc = { 53 .offset = 0, 54 .no_of_ctrls = 2, 55 .irqp_used = 1, 56 .soc_mclk = true, 57 .irq_reg_offset = 0x1a00, 58 .scratch_reg_offset = 0x12800, 59 .sram_pte_offset = 0x03802800, 60 }; 61 62 static struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_acp_machines[] = { 63 { 64 .id = "AMDI0052", 65 .drv_name = "acp63-acp", 66 }, 67 {}, 68 }; 69 70 static struct snd_soc_dai_driver acp63_dai[] = { 71 { 72 .name = "acp-i2s-sp", 73 .id = I2S_SP_INSTANCE, 74 .playback = { 75 .stream_name = "I2S SP Playback", 76 .rates = SNDRV_PCM_RATE_8000_96000, 77 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | 78 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, 79 .channels_min = 2, 80 .channels_max = 8, 81 .rate_min = 8000, 82 .rate_max = 96000, 83 }, 84 .capture = { 85 .stream_name = "I2S SP Capture", 86 .rates = SNDRV_PCM_RATE_8000_48000, 87 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | 88 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, 89 .channels_min = 2, 90 .channels_max = 2, 91 .rate_min = 8000, 92 .rate_max = 48000, 93 }, 94 .ops = &asoc_acp_cpu_dai_ops, 95 }, 96 { 97 .name = "acp-i2s-bt", 98 .id = I2S_BT_INSTANCE, 99 .playback = { 100 .stream_name = "I2S BT Playback", 101 .rates = SNDRV_PCM_RATE_8000_96000, 102 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | 103 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, 104 .channels_min = 2, 105 .channels_max = 8, 106 .rate_min = 8000, 107 .rate_max = 96000, 108 }, 109 .capture = { 110 .stream_name = "I2S BT Capture", 111 .rates = SNDRV_PCM_RATE_8000_48000, 112 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | 113 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, 114 .channels_min = 2, 115 .channels_max = 2, 116 .rate_min = 8000, 117 .rate_max = 48000, 118 }, 119 .ops = &asoc_acp_cpu_dai_ops, 120 }, 121 { 122 .name = "acp-i2s-hs", 123 .id = I2S_HS_INSTANCE, 124 .playback = { 125 .stream_name = "I2S HS Playback", 126 .rates = SNDRV_PCM_RATE_8000_96000, 127 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | 128 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, 129 .channels_min = 2, 130 .channels_max = 8, 131 .rate_min = 8000, 132 .rate_max = 96000, 133 }, 134 .capture = { 135 .stream_name = "I2S HS Capture", 136 .rates = SNDRV_PCM_RATE_8000_48000, 137 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | 138 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, 139 .channels_min = 2, 140 .channels_max = 8, 141 .rate_min = 8000, 142 .rate_max = 48000, 143 }, 144 .ops = &asoc_acp_cpu_dai_ops, 145 }, 146 { 147 .name = "acp-pdm-dmic", 148 .id = DMIC_INSTANCE, 149 .capture = { 150 .rates = SNDRV_PCM_RATE_8000_48000, 151 .formats = SNDRV_PCM_FMTBIT_S32_LE, 152 .channels_min = 2, 153 .channels_max = 2, 154 .rate_min = 8000, 155 .rate_max = 48000, 156 }, 157 .ops = &acp_dmic_dai_ops, 158 }, 159 }; 160 161 static int acp63_i2s_master_clock_generate(struct acp_dev_data *adata) 162 { 163 u32 data; 164 union clk_pll_req_no clk_pll; 165 struct pci_dev *smn_dev; 166 167 smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x14E8, NULL); 168 if (!smn_dev) 169 return -ENODEV; 170 171 /* Clk5 pll register values to get mclk as 196.6MHz*/ 172 clk_pll.bits.fb_mult_int = 0x31; 173 clk_pll.bits.pll_spine_div = 0; 174 clk_pll.bits.gb_mult_frac = 0x26E9; 175 176 data = smn_read(smn_dev, CLK_PLL_PWR_REQ_N0); 177 smn_write(smn_dev, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_STOP_REQ); 178 179 data = smn_read(smn_dev, CLK_SPLL_FIELD_2_N0); 180 if (data & PLL_FRANCE_EN) 181 smn_write(smn_dev, CLK_SPLL_FIELD_2_N0, data | PLL_FRANCE_EN); 182 183 smn_write(smn_dev, CLK_PLL_REQ_N0, clk_pll.clk_pll_req_no_reg); 184 185 data = smn_read(smn_dev, CLK_PLL_PWR_REQ_N0); 186 smn_write(smn_dev, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_START_REQ); 187 188 data = smn_read(smn_dev, CLK_DFSBYPASS_CONTR); 189 smn_write(smn_dev, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_0); 190 smn_write(smn_dev, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_1); 191 192 smn_write(smn_dev, CLK_DFS_CNTL_N0, CLK0_DIVIDER); 193 return 0; 194 } 195 196 static int acp63_audio_probe(struct platform_device *pdev) 197 { 198 struct device *dev = &pdev->dev; 199 struct acp_chip_info *chip; 200 struct acp_dev_data *adata; 201 struct resource *res; 202 int ret; 203 204 chip = dev_get_platdata(&pdev->dev); 205 if (!chip || !chip->base) { 206 dev_err(&pdev->dev, "ACP chip data is NULL\n"); 207 return -ENODEV; 208 } 209 210 if (chip->acp_rev != ACP63_DEV) { 211 dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); 212 return -ENODEV; 213 } 214 215 adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL); 216 if (!adata) 217 return -ENOMEM; 218 219 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem"); 220 if (!res) { 221 dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); 222 return -ENODEV; 223 } 224 225 adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 226 if (!adata->acp_base) 227 return -ENOMEM; 228 229 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq"); 230 if (!res) { 231 dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); 232 return -ENODEV; 233 } 234 235 adata->i2s_irq = res->start; 236 adata->dev = dev; 237 adata->dai_driver = acp63_dai; 238 adata->num_dai = ARRAY_SIZE(acp63_dai); 239 adata->rsrc = &rsrc; 240 adata->platform = ACP63; 241 adata->flag = chip->flag; 242 adata->is_i2s_config = chip->is_i2s_config; 243 adata->machines = snd_soc_acpi_amd_acp63_acp_machines; 244 acp_machine_select(adata); 245 dev_set_drvdata(dev, adata); 246 247 if (chip->is_i2s_config && rsrc.soc_mclk) { 248 ret = acp63_i2s_master_clock_generate(adata); 249 if (ret) 250 return ret; 251 } 252 acp_enable_interrupts(adata); 253 acp_platform_register(dev); 254 pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS); 255 pm_runtime_use_autosuspend(&pdev->dev); 256 pm_runtime_mark_last_busy(&pdev->dev); 257 pm_runtime_set_active(&pdev->dev); 258 pm_runtime_enable(&pdev->dev); 259 return 0; 260 } 261 262 static void acp63_audio_remove(struct platform_device *pdev) 263 { 264 struct device *dev = &pdev->dev; 265 struct acp_dev_data *adata = dev_get_drvdata(dev); 266 267 acp_disable_interrupts(adata); 268 acp_platform_unregister(dev); 269 pm_runtime_disable(&pdev->dev); 270 } 271 272 static int __maybe_unused acp63_pcm_resume(struct device *dev) 273 { 274 struct acp_dev_data *adata = dev_get_drvdata(dev); 275 struct acp_stream *stream; 276 struct snd_pcm_substream *substream; 277 snd_pcm_uframes_t buf_in_frames; 278 u64 buf_size; 279 280 if (adata->is_i2s_config && adata->rsrc->soc_mclk) 281 acp63_i2s_master_clock_generate(adata); 282 283 spin_lock(&adata->acp_lock); 284 list_for_each_entry(stream, &adata->stream_list, list) { 285 substream = stream->substream; 286 if (substream && substream->runtime) { 287 buf_in_frames = (substream->runtime->buffer_size); 288 buf_size = frames_to_bytes(substream->runtime, buf_in_frames); 289 config_pte_for_stream(adata, stream); 290 config_acp_dma(adata, stream, buf_size); 291 if (stream->dai_id) 292 restore_acp_i2s_params(substream, adata, stream); 293 else 294 restore_acp_pdm_params(substream, adata); 295 } 296 } 297 spin_unlock(&adata->acp_lock); 298 return 0; 299 } 300 301 static const struct dev_pm_ops acp63_dma_pm_ops = { 302 SET_SYSTEM_SLEEP_PM_OPS(NULL, acp63_pcm_resume) 303 }; 304 305 static struct platform_driver acp63_driver = { 306 .probe = acp63_audio_probe, 307 .remove_new = acp63_audio_remove, 308 .driver = { 309 .name = "acp_asoc_acp63", 310 .pm = &acp63_dma_pm_ops, 311 }, 312 }; 313 314 module_platform_driver(acp63_driver); 315 316 MODULE_DESCRIPTION("AMD ACP acp63 Driver"); 317 MODULE_IMPORT_NS(SND_SOC_ACP_COMMON); 318 MODULE_LICENSE("Dual BSD/GPL"); 319 MODULE_ALIAS("platform:" DRV_NAME); 320
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.