1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Au12x0/Au1550 PSC ALSA ASoC audio support. 4 * 5 * (c) 2007-2008 MSC Vertriebsges.m.b.H., 6 * Manuel Lauss <manuel.lauss@gmail.com> 7 * 8 * DMA glue for Au1x-PSC audio. 9 */ 10 11 12 #include <linux/module.h> 13 #include <linux/init.h> 14 #include <linux/platform_device.h> 15 #include <linux/slab.h> 16 #include <linux/dma-mapping.h> 17 18 #include <sound/core.h> 19 #include <sound/pcm.h> 20 #include <sound/pcm_params.h> 21 #include <sound/soc.h> 22 23 #include <asm/mach-au1x00/au1000.h> 24 #include <asm/mach-au1x00/au1xxx_dbdma.h> 25 #include <asm/mach-au1x00/au1xxx_psc.h> 26 27 #include "psc.h" 28 29 /*#define PCM_DEBUG*/ 30 31 #define DRV_NAME "dbdma2" 32 33 #define MSG(x...) printk(KERN_INFO "au1xpsc_pcm: " x) 34 #ifdef PCM_DEBUG 35 #define DBG MSG 36 #else 37 #define DBG(x...) do {} while (0) 38 #endif 39 40 struct au1xpsc_audio_dmadata { 41 /* DDMA control data */ 42 unsigned int ddma_id; /* DDMA direction ID for this PSC */ 43 u32 ddma_chan; /* DDMA context */ 44 45 /* PCM context (for irq handlers) */ 46 struct snd_pcm_substream *substream; 47 unsigned long curr_period; /* current segment DDMA is working on */ 48 unsigned long q_period; /* queue period(s) */ 49 dma_addr_t dma_area; /* address of queued DMA area */ 50 dma_addr_t dma_area_s; /* start address of DMA area */ 51 unsigned long pos; /* current byte position being played */ 52 unsigned long periods; /* number of SG segments in total */ 53 unsigned long period_bytes; /* size in bytes of one SG segment */ 54 55 /* runtime data */ 56 int msbits; 57 }; 58 59 /* 60 * These settings are somewhat okay, at least on my machine audio plays 61 * almost skip-free. Especially the 64kB buffer seems to help a LOT. 62 */ 63 #define AU1XPSC_PERIOD_MIN_BYTES 1024 64 #define AU1XPSC_BUFFER_MIN_BYTES 65536 65 66 /* PCM hardware DMA capabilities - platform specific */ 67 static const struct snd_pcm_hardware au1xpsc_pcm_hardware = { 68 .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | 69 SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH, 70 .period_bytes_min = AU1XPSC_PERIOD_MIN_BYTES, 71 .period_bytes_max = 4096 * 1024 - 1, 72 .periods_min = 2, 73 .periods_max = 4096, /* 2 to as-much-as-you-like */ 74 .buffer_bytes_max = 4096 * 1024 - 1, 75 .fifo_size = 16, /* fifo entries of AC97/I2S PSC */ 76 }; 77 78 static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd) 79 { 80 au1xxx_dbdma_put_source(cd->ddma_chan, cd->dma_area, 81 cd->period_bytes, DDMA_FLAGS_IE); 82 83 /* update next-to-queue period */ 84 ++cd->q_period; 85 cd->dma_area += cd->period_bytes; 86 if (cd->q_period >= cd->periods) { 87 cd->q_period = 0; 88 cd->dma_area = cd->dma_area_s; 89 } 90 } 91 92 static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata *cd) 93 { 94 au1xxx_dbdma_put_dest(cd->ddma_chan, cd->dma_area, 95 cd->period_bytes, DDMA_FLAGS_IE); 96 97 /* update next-to-queue period */ 98 ++cd->q_period; 99 cd->dma_area += cd->period_bytes; 100 if (cd->q_period >= cd->periods) { 101 cd->q_period = 0; 102 cd->dma_area = cd->dma_area_s; 103 } 104 } 105 106 static void au1x_pcm_dmatx_cb(int irq, void *dev_id) 107 { 108 struct au1xpsc_audio_dmadata *cd = dev_id; 109 110 cd->pos += cd->period_bytes; 111 if (++cd->curr_period >= cd->periods) { 112 cd->pos = 0; 113 cd->curr_period = 0; 114 } 115 snd_pcm_period_elapsed(cd->substream); 116 au1x_pcm_queue_tx(cd); 117 } 118 119 static void au1x_pcm_dmarx_cb(int irq, void *dev_id) 120 { 121 struct au1xpsc_audio_dmadata *cd = dev_id; 122 123 cd->pos += cd->period_bytes; 124 if (++cd->curr_period >= cd->periods) { 125 cd->pos = 0; 126 cd->curr_period = 0; 127 } 128 snd_pcm_period_elapsed(cd->substream); 129 au1x_pcm_queue_rx(cd); 130 } 131 132 static void au1x_pcm_dbdma_free(struct au1xpsc_audio_dmadata *pcd) 133 { 134 if (pcd->ddma_chan) { 135 au1xxx_dbdma_stop(pcd->ddma_chan); 136 au1xxx_dbdma_reset(pcd->ddma_chan); 137 au1xxx_dbdma_chan_free(pcd->ddma_chan); 138 pcd->ddma_chan = 0; 139 pcd->msbits = 0; 140 } 141 } 142 143 /* in case of missing DMA ring or changed TX-source / RX-dest bit widths, 144 * allocate (or reallocate) a 2-descriptor DMA ring with bit depth according 145 * to ALSA-supplied sample depth. This is due to limitations in the dbdma api 146 * (cannot adjust source/dest widths of already allocated descriptor ring). 147 */ 148 static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd, 149 int stype, int msbits) 150 { 151 /* DMA only in 8/16/32 bit widths */ 152 if (msbits == 24) 153 msbits = 32; 154 155 /* check current config: correct bits and descriptors allocated? */ 156 if ((pcd->ddma_chan) && (msbits == pcd->msbits)) 157 goto out; /* all ok! */ 158 159 au1x_pcm_dbdma_free(pcd); 160 161 if (stype == SNDRV_PCM_STREAM_CAPTURE) 162 pcd->ddma_chan = au1xxx_dbdma_chan_alloc(pcd->ddma_id, 163 DSCR_CMD0_ALWAYS, 164 au1x_pcm_dmarx_cb, (void *)pcd); 165 else 166 pcd->ddma_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS, 167 pcd->ddma_id, 168 au1x_pcm_dmatx_cb, (void *)pcd); 169 170 if (!pcd->ddma_chan) 171 return -ENOMEM; 172 173 au1xxx_dbdma_set_devwidth(pcd->ddma_chan, msbits); 174 au1xxx_dbdma_ring_alloc(pcd->ddma_chan, 2); 175 176 pcd->msbits = msbits; 177 178 au1xxx_dbdma_stop(pcd->ddma_chan); 179 au1xxx_dbdma_reset(pcd->ddma_chan); 180 181 out: 182 return 0; 183 } 184 185 static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss) 186 { 187 struct snd_soc_pcm_runtime *rtd = ss->private_data; 188 struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); 189 struct au1xpsc_audio_dmadata *pcd = snd_soc_component_get_drvdata(component); 190 return &pcd[ss->stream]; 191 } 192 193 static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, 194 struct snd_pcm_hw_params *params) 195 { 196 struct snd_pcm_runtime *runtime = substream->runtime; 197 struct au1xpsc_audio_dmadata *pcd; 198 int stype, ret; 199 200 ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); 201 if (ret < 0) 202 goto out; 203 204 stype = substream->stream; 205 pcd = to_dmadata(substream); 206 207 DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %zu " 208 "runtime->min_align %lu\n", 209 (unsigned long)runtime->dma_area, 210 (unsigned long)runtime->dma_addr, runtime->dma_bytes, 211 runtime->min_align); 212 213 DBG("bits %d frags %d frag_bytes %d is_rx %d\n", params->msbits, 214 params_periods(params), params_period_bytes(params), stype); 215 216 ret = au1x_pcm_dbdma_realloc(pcd, stype, params->msbits); 217 if (ret) { 218 MSG("DDMA channel (re)alloc failed!\n"); 219 goto out; 220 } 221 222 pcd->substream = substream; 223 pcd->period_bytes = params_period_bytes(params); 224 pcd->periods = params_periods(params); 225 pcd->dma_area_s = pcd->dma_area = runtime->dma_addr; 226 pcd->q_period = 0; 227 pcd->curr_period = 0; 228 pcd->pos = 0; 229 230 ret = 0; 231 out: 232 return ret; 233 } 234 235 static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream) 236 { 237 snd_pcm_lib_free_pages(substream); 238 return 0; 239 } 240 241 static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream) 242 { 243 struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream); 244 245 au1xxx_dbdma_reset(pcd->ddma_chan); 246 247 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 248 au1x_pcm_queue_rx(pcd); 249 au1x_pcm_queue_rx(pcd); 250 } else { 251 au1x_pcm_queue_tx(pcd); 252 au1x_pcm_queue_tx(pcd); 253 } 254 255 return 0; 256 } 257 258 static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 259 { 260 u32 c = to_dmadata(substream)->ddma_chan; 261 262 switch (cmd) { 263 case SNDRV_PCM_TRIGGER_START: 264 case SNDRV_PCM_TRIGGER_RESUME: 265 au1xxx_dbdma_start(c); 266 break; 267 case SNDRV_PCM_TRIGGER_STOP: 268 case SNDRV_PCM_TRIGGER_SUSPEND: 269 au1xxx_dbdma_stop(c); 270 break; 271 default: 272 return -EINVAL; 273 } 274 return 0; 275 } 276 277 static snd_pcm_uframes_t 278 au1xpsc_pcm_pointer(struct snd_pcm_substream *substream) 279 { 280 return bytes_to_frames(substream->runtime, to_dmadata(substream)->pos); 281 } 282 283 static int au1xpsc_pcm_open(struct snd_pcm_substream *substream) 284 { 285 struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream); 286 struct snd_soc_pcm_runtime *rtd = substream->private_data; 287 int stype = substream->stream, *dmaids; 288 289 dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); 290 if (!dmaids) 291 return -ENODEV; /* whoa, has ordering changed? */ 292 293 pcd->ddma_id = dmaids[stype]; 294 295 snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware); 296 return 0; 297 } 298 299 static int au1xpsc_pcm_close(struct snd_pcm_substream *substream) 300 { 301 au1x_pcm_dbdma_free(to_dmadata(substream)); 302 return 0; 303 } 304 305 static const struct snd_pcm_ops au1xpsc_pcm_ops = { 306 .open = au1xpsc_pcm_open, 307 .close = au1xpsc_pcm_close, 308 .ioctl = snd_pcm_lib_ioctl, 309 .hw_params = au1xpsc_pcm_hw_params, 310 .hw_free = au1xpsc_pcm_hw_free, 311 .prepare = au1xpsc_pcm_prepare, 312 .trigger = au1xpsc_pcm_trigger, 313 .pointer = au1xpsc_pcm_pointer, 314 }; 315 316 static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd) 317 { 318 struct snd_card *card = rtd->card->snd_card; 319 struct snd_pcm *pcm = rtd->pcm; 320 321 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, 322 card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1); 323 324 return 0; 325 } 326 327 /* au1xpsc audio platform */ 328 static struct snd_soc_component_driver au1xpsc_soc_component = { 329 .name = DRV_NAME, 330 .ops = &au1xpsc_pcm_ops, 331 .pcm_new = au1xpsc_pcm_new, 332 }; 333 334 static int au1xpsc_pcm_drvprobe(struct platform_device *pdev) 335 { 336 struct au1xpsc_audio_dmadata *dmadata; 337 338 dmadata = devm_kcalloc(&pdev->dev, 339 2, sizeof(struct au1xpsc_audio_dmadata), 340 GFP_KERNEL); 341 if (!dmadata) 342 return -ENOMEM; 343 344 platform_set_drvdata(pdev, dmadata); 345 346 return devm_snd_soc_register_component(&pdev->dev, 347 &au1xpsc_soc_component, NULL, 0); 348 } 349 350 static struct platform_driver au1xpsc_pcm_driver = { 351 .driver = { 352 .name = "au1xpsc-pcm", 353 }, 354 .probe = au1xpsc_pcm_drvprobe, 355 }; 356 357 module_platform_driver(au1xpsc_pcm_driver); 358 359 MODULE_LICENSE("GPL"); 360 MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver"); 361 MODULE_AUTHOR("Manuel Lauss"); 362