1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // Loongson ALSA SoC Platform (DMA) driver 4 // 5 // Copyright (C) 2023 Loongson Technology Corporation Limited 6 // Author: Yingkun Meng <mengyingkun@loongson.cn> 7 // Binbin ZHou <zhoubinbin@loongson.cn> 8 // 9 10 #include <linux/module.h> 11 #include <linux/io-64-nonatomic-lo-hi.h> 12 #include <linux/delay.h> 13 #include <linux/pm_runtime.h> 14 #include <linux/dma-mapping.h> 15 #include <sound/soc.h> 16 #include <sound/pcm.h> 17 #include <sound/pcm_params.h> 18 #include "loongson_i2s.h" 19 20 /* Internal DMA dma_order Register */ 21 #define DMA_ORDER_STOP BIT(4) /* DMA stop */ 22 #define DMA_ORDER_START BIT(3) /* DMA start */ 23 #define DMA_ORDER_ASK_VALID BIT(2) /* DMA ask valid flag */ 24 #define DMA_ORDER_AXI_UNCO BIT(1) /* Uncache access */ 25 #define DMA_ORDER_ADDR_64 BIT(0) /* 64bits address support */ 26 27 #define DMA_ORDER_ASK_MASK (~0x1fUL) /* Ask addr mask */ 28 #define DMA_ORDER_CTRL_MASK (0x0fUL) /* Control mask */ 29 30 /* 31 * Internal DMA registers descriptor. 32 */ 33 struct loongson_idma_desc { 34 u32 order; /* Next descriptor address register */ 35 u32 saddr; /* Source address register */ 36 u32 daddr; /* Device address register */ 37 u32 length; /* Total length register */ 38 u32 step_length; /* Memory stride register */ 39 u32 step_times; /* Repeat time register */ 40 u32 cmd; /* Command register */ 41 u32 stats; /* Status register */ 42 u32 order_hi; /* Next descriptor high address register */ 43 u32 saddr_hi; /* High source address register */ 44 u32 res[6]; /* Reserved */ 45 } __packed; 46 47 struct loongson_runtime_data { 48 struct loongson_idma_data *dma_data; 49 50 struct loongson_idma_desc *dma_desc_arr; 51 dma_addr_t dma_desc_arr_phy; 52 int dma_desc_arr_size; 53 54 struct loongson_idma_desc *dma_pos_desc; 55 dma_addr_t dma_pos_desc_phy; 56 }; 57 58 static const struct snd_pcm_hardware loongson_idma_hardware = { 59 .info = SNDRV_PCM_INFO_MMAP | 60 SNDRV_PCM_INFO_INTERLEAVED | 61 SNDRV_PCM_INFO_MMAP_VALID | 62 SNDRV_PCM_INFO_RESUME | 63 SNDRV_PCM_INFO_PAUSE, 64 .formats = (SNDRV_PCM_FMTBIT_S8 | 65 SNDRV_PCM_FMTBIT_S16_LE | 66 SNDRV_PCM_FMTBIT_S20_3LE | 67 SNDRV_PCM_FMTBIT_S24_LE), 68 .period_bytes_min = 128, 69 .period_bytes_max = 128 * 1024, 70 .periods_min = 1, 71 .periods_max = PAGE_SIZE / sizeof(struct loongson_idma_desc), 72 .buffer_bytes_max = 1024 * 1024, 73 }; 74 75 static struct loongson_idma_desc *dma_desc_save(struct loongson_runtime_data *prtd) 76 { 77 void __iomem *order_reg = prtd->dma_data->order_addr; 78 u64 val; 79 80 val = (u64)prtd->dma_pos_desc_phy & DMA_ORDER_ASK_MASK; 81 val |= (readq(order_reg) & DMA_ORDER_CTRL_MASK); 82 val |= DMA_ORDER_ASK_VALID; 83 writeq(val, order_reg); 84 85 while (readl(order_reg) & DMA_ORDER_ASK_VALID) 86 udelay(2); 87 88 return prtd->dma_pos_desc; 89 } 90 91 static int loongson_idma_pcm_trigger(struct snd_soc_component *component, 92 struct snd_pcm_substream *substream, int cmd) 93 { 94 struct loongson_runtime_data *prtd = substream->runtime->private_data; 95 struct device *dev = substream->pcm->card->dev; 96 void __iomem *order_reg = prtd->dma_data->order_addr; 97 u64 val; 98 99 switch (cmd) { 100 case SNDRV_PCM_TRIGGER_START: 101 case SNDRV_PCM_TRIGGER_RESUME: 102 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 103 val = prtd->dma_pos_desc_phy & DMA_ORDER_ASK_MASK; 104 if (dev->coherent_dma_mask == DMA_BIT_MASK(64)) 105 val |= DMA_ORDER_ADDR_64; 106 else 107 val &= ~DMA_ORDER_ADDR_64; 108 val |= (readq(order_reg) & DMA_ORDER_CTRL_MASK); 109 val |= DMA_ORDER_START; 110 writeq(val, order_reg); 111 112 while ((readl(order_reg) & DMA_ORDER_START)) 113 udelay(2); 114 break; 115 case SNDRV_PCM_TRIGGER_STOP: 116 case SNDRV_PCM_TRIGGER_SUSPEND: 117 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 118 dma_desc_save(prtd); 119 120 /* dma stop */ 121 val = readq(order_reg) | DMA_ORDER_STOP; 122 writeq(val, order_reg); 123 udelay(1000); 124 125 break; 126 default: 127 dev_err(dev, "Invalid pcm trigger operation\n"); 128 return -EINVAL; 129 } 130 131 return 0; 132 } 133 134 static int loongson_idma_pcm_hw_params(struct snd_soc_component *component, 135 struct snd_pcm_substream *substream, 136 struct snd_pcm_hw_params *params) 137 { 138 struct snd_pcm_runtime *runtime = substream->runtime; 139 struct device *dev = substream->pcm->card->dev; 140 struct loongson_runtime_data *prtd = runtime->private_data; 141 size_t buf_len = params_buffer_bytes(params); 142 size_t period_len = params_period_bytes(params); 143 dma_addr_t order_addr, mem_addr; 144 struct loongson_idma_desc *desc; 145 u32 num_periods; 146 int i; 147 148 if (buf_len % period_len) { 149 dev_err(dev, "buf len not multiply of period len\n"); 150 return -EINVAL; 151 } 152 153 num_periods = buf_len / period_len; 154 if (!num_periods || num_periods > prtd->dma_desc_arr_size) { 155 dev_err(dev, "dma data too small or too big\n"); 156 return -EINVAL; 157 } 158 159 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 160 runtime->dma_bytes = buf_len; 161 162 /* initialize dma descriptor array */ 163 mem_addr = runtime->dma_addr; 164 order_addr = prtd->dma_desc_arr_phy; 165 for (i = 0; i < num_periods; i++) { 166 desc = &prtd->dma_desc_arr[i]; 167 168 /* next descriptor physical address */ 169 order_addr += sizeof(*desc); 170 desc->order = lower_32_bits(order_addr | BIT(0)); 171 desc->order_hi = upper_32_bits(order_addr); 172 173 desc->saddr = lower_32_bits(mem_addr); 174 desc->saddr_hi = upper_32_bits(mem_addr); 175 desc->daddr = prtd->dma_data->dev_addr; 176 177 desc->cmd = BIT(0); 178 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 179 desc->cmd |= BIT(12); 180 181 desc->length = period_len >> 2; 182 desc->step_length = 0; 183 desc->step_times = 1; 184 185 mem_addr += period_len; 186 } 187 desc = &prtd->dma_desc_arr[num_periods - 1]; 188 desc->order = lower_32_bits(prtd->dma_desc_arr_phy | BIT(0)); 189 desc->order_hi = upper_32_bits(prtd->dma_desc_arr_phy); 190 191 /* init position descriptor */ 192 *prtd->dma_pos_desc = *prtd->dma_desc_arr; 193 194 return 0; 195 } 196 197 static snd_pcm_uframes_t 198 loongson_idma_pcm_pointer(struct snd_soc_component *component, 199 struct snd_pcm_substream *substream) 200 { 201 struct snd_pcm_runtime *runtime = substream->runtime; 202 struct device *dev = substream->pcm->card->dev; 203 struct loongson_runtime_data *prtd = runtime->private_data; 204 struct loongson_idma_desc *desc; 205 snd_pcm_uframes_t x; 206 u64 addr; 207 208 desc = dma_desc_save(prtd); 209 addr = ((u64)desc->saddr_hi << 32) | desc->saddr; 210 211 if (addr < runtime->dma_addr || 212 addr > runtime->dma_addr + runtime->dma_bytes) { 213 dev_warn(dev, "WARNING! dma_addr:0x%llx\n", addr); 214 x = 0; 215 } else { 216 x = bytes_to_frames(runtime, addr - runtime->dma_addr); 217 if (x == runtime->buffer_size) 218 x = 0; 219 } 220 221 return x; 222 } 223 224 static irqreturn_t loongson_idma_pcm_dma_irq(int irq, void *devid) 225 { 226 struct snd_pcm_substream *substream = devid; 227 228 snd_pcm_period_elapsed(substream); 229 return IRQ_HANDLED; 230 } 231 232 static int loongson_idma_pcm_open(struct snd_soc_component *component, 233 struct snd_pcm_substream *substream) 234 { 235 struct snd_pcm_runtime *runtime = substream->runtime; 236 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 237 struct snd_card *card = substream->pcm->card; 238 struct loongson_runtime_data *prtd; 239 struct loongson_idma_data *dma_data; 240 241 /* 242 * For mysterious reasons (and despite what the manual says) 243 * playback samples are lost if the DMA count is not a multiple 244 * of the DMA burst size. Let's add a rule to enforce that. 245 */ 246 snd_pcm_hw_constraint_step(runtime, 0, 247 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); 248 snd_pcm_hw_constraint_step(runtime, 0, 249 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128); 250 snd_pcm_hw_constraint_integer(substream->runtime, 251 SNDRV_PCM_HW_PARAM_PERIODS); 252 snd_soc_set_runtime_hwparams(substream, &loongson_idma_hardware); 253 254 prtd = kzalloc_obj(*prtd); 255 if (!prtd) 256 return -ENOMEM; 257 258 prtd->dma_desc_arr = dma_alloc_coherent(card->dev, PAGE_SIZE, 259 &prtd->dma_desc_arr_phy, 260 GFP_KERNEL); 261 if (!prtd->dma_desc_arr) 262 goto desc_err; 263 264 prtd->dma_desc_arr_size = PAGE_SIZE / sizeof(*prtd->dma_desc_arr); 265 266 prtd->dma_pos_desc = dma_alloc_coherent(card->dev, 267 sizeof(*prtd->dma_pos_desc), 268 &prtd->dma_pos_desc_phy, 269 GFP_KERNEL); 270 if (!prtd->dma_pos_desc) 271 goto pos_err; 272 273 dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream); 274 prtd->dma_data = dma_data; 275 276 substream->runtime->private_data = prtd; 277 278 return 0; 279 pos_err: 280 dma_free_coherent(card->dev, PAGE_SIZE, prtd->dma_desc_arr, 281 prtd->dma_desc_arr_phy); 282 desc_err: 283 kfree(prtd); 284 285 return -ENOMEM; 286 } 287 288 static int loongson_idma_pcm_close(struct snd_soc_component *component, 289 struct snd_pcm_substream *substream) 290 { 291 struct snd_card *card = substream->pcm->card; 292 struct loongson_runtime_data *prtd = substream->runtime->private_data; 293 294 dma_free_coherent(card->dev, PAGE_SIZE, prtd->dma_desc_arr, 295 prtd->dma_desc_arr_phy); 296 297 dma_free_coherent(card->dev, sizeof(*prtd->dma_pos_desc), 298 prtd->dma_pos_desc, prtd->dma_pos_desc_phy); 299 300 kfree(prtd); 301 return 0; 302 } 303 304 static int loongson_idma_pcm_mmap(struct snd_soc_component *component, 305 struct snd_pcm_substream *substream, 306 struct vm_area_struct *vma) 307 { 308 return remap_pfn_range(vma, vma->vm_start, 309 substream->dma_buffer.addr >> PAGE_SHIFT, 310 vma->vm_end - vma->vm_start, vma->vm_page_prot); 311 } 312 313 static int loongson_idma_pcm_new(struct snd_soc_component *component, 314 struct snd_soc_pcm_runtime *rtd) 315 { 316 struct snd_card *card = rtd->card->snd_card; 317 struct snd_pcm_substream *substream; 318 struct loongson_idma_data *dma_data; 319 unsigned int i; 320 int ret; 321 322 for_each_pcm_streams(i) { 323 substream = rtd->pcm->streams[i].substream; 324 if (!substream) 325 continue; 326 327 dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), 328 substream); 329 ret = devm_request_irq(card->dev, dma_data->irq, 330 loongson_idma_pcm_dma_irq, 331 IRQF_TRIGGER_HIGH, LS_I2S_DRVNAME, 332 substream); 333 if (ret < 0) { 334 dev_err(card->dev, "request irq for DMA failed\n"); 335 return ret; 336 } 337 } 338 339 return snd_pcm_set_fixed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, 340 card->dev, 341 loongson_idma_hardware.buffer_bytes_max); 342 } 343 344 /* Internal DMA component */ 345 const struct snd_soc_component_driver loongson_i2s_idma_component = { 346 .name = LS_I2S_DRVNAME, 347 .open = loongson_idma_pcm_open, 348 .close = loongson_idma_pcm_close, 349 .hw_params = loongson_idma_pcm_hw_params, 350 .trigger = loongson_idma_pcm_trigger, 351 .pointer = loongson_idma_pcm_pointer, 352 .mmap = loongson_idma_pcm_mmap, 353 .pcm_new = loongson_idma_pcm_new, 354 }; 355 EXPORT_SYMBOL_GPL(loongson_i2s_idma_component); 356 357 static const struct snd_pcm_hardware loongson_edma_hardware = { 358 .info = SNDRV_PCM_INFO_MMAP | 359 SNDRV_PCM_INFO_INTERLEAVED | 360 SNDRV_PCM_INFO_MMAP_VALID | 361 SNDRV_PCM_INFO_RESUME | 362 SNDRV_PCM_INFO_PAUSE, 363 .formats = SNDRV_PCM_FMTBIT_S16_LE | 364 SNDRV_PCM_FMTBIT_S20_3LE | 365 SNDRV_PCM_FMTBIT_S24_LE, 366 .period_bytes_min = 128, 367 .period_bytes_max = 128 * 1024, 368 .periods_min = 1, 369 .periods_max = 64, 370 .buffer_bytes_max = 1024 * 1024, 371 }; 372 373 const struct snd_dmaengine_pcm_config loongson_dmaengine_pcm_config = { 374 .pcm_hardware = &loongson_edma_hardware, 375 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, 376 .prealloc_buffer_size = 128 * 1024, 377 }; 378 EXPORT_SYMBOL_GPL(loongson_dmaengine_pcm_config); 379 380 /* External DMA component */ 381 static int loongson_edma_pcm_open(struct snd_soc_component *component, 382 struct snd_pcm_substream *substream) 383 { 384 struct snd_pcm_runtime *runtime = substream->runtime; 385 386 if (substream->pcm->device & 1) { 387 runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; 388 runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; 389 } 390 391 if (substream->pcm->device & 2) 392 runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | 393 SNDRV_PCM_INFO_MMAP_VALID); 394 /* 395 * For mysterious reasons (and despite what the manual says) 396 * playback samples are lost if the DMA count is not a multiple 397 * of the DMA burst size. Let's add a rule to enforce that. 398 */ 399 snd_pcm_hw_constraint_step(runtime, 0, 400 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); 401 snd_pcm_hw_constraint_step(runtime, 0, 402 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128); 403 snd_pcm_hw_constraint_integer(substream->runtime, 404 SNDRV_PCM_HW_PARAM_PERIODS); 405 406 return 0; 407 } 408 409 const struct snd_soc_component_driver loongson_i2s_edma_component = { 410 .name = LS_I2S_DRVNAME, 411 .open = loongson_edma_pcm_open, 412 }; 413 EXPORT_SYMBOL_GPL(loongson_i2s_edma_component); 414