162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Freescale DMA ALSA SoC PCM driver 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Author: Timur Tabi <timur@freescale.com> 662306a36Sopenharmony_ci// 762306a36Sopenharmony_ci// Copyright 2007-2010 Freescale Semiconductor, Inc. 862306a36Sopenharmony_ci// 962306a36Sopenharmony_ci// This driver implements ASoC support for the Elo DMA controller, which is 1062306a36Sopenharmony_ci// the DMA controller on Freescale 83xx, 85xx, and 86xx SOCs. In ALSA terms, 1162306a36Sopenharmony_ci// the PCM driver is what handles the DMA buffer. 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1762306a36Sopenharmony_ci#include <linux/interrupt.h> 1862306a36Sopenharmony_ci#include <linux/delay.h> 1962306a36Sopenharmony_ci#include <linux/gfp.h> 2062306a36Sopenharmony_ci#include <linux/of_address.h> 2162306a36Sopenharmony_ci#include <linux/of_irq.h> 2262306a36Sopenharmony_ci#include <linux/of_platform.h> 2362306a36Sopenharmony_ci#include <linux/list.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <sound/core.h> 2762306a36Sopenharmony_ci#include <sound/pcm.h> 2862306a36Sopenharmony_ci#include <sound/pcm_params.h> 2962306a36Sopenharmony_ci#include <sound/soc.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <asm/io.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include "fsl_dma.h" 3462306a36Sopenharmony_ci#include "fsl_ssi.h" /* For the offset of stx0 and srx0 */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define DRV_NAME "fsl_dma" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * The formats that the DMA controller supports, which is anything 4062306a36Sopenharmony_ci * that is 8, 16, or 32 bits. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci#define FSLDMA_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ 4362306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U8 | \ 4462306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_LE | \ 4562306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_BE | \ 4662306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U16_LE | \ 4762306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U16_BE | \ 4862306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | \ 4962306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_BE | \ 5062306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U24_LE | \ 5162306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U24_BE | \ 5262306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE | \ 5362306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_BE | \ 5462306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U32_LE | \ 5562306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U32_BE) 5662306a36Sopenharmony_cistruct dma_object { 5762306a36Sopenharmony_ci struct snd_soc_component_driver dai; 5862306a36Sopenharmony_ci dma_addr_t ssi_stx_phys; 5962306a36Sopenharmony_ci dma_addr_t ssi_srx_phys; 6062306a36Sopenharmony_ci unsigned int ssi_fifo_depth; 6162306a36Sopenharmony_ci struct ccsr_dma_channel __iomem *channel; 6262306a36Sopenharmony_ci unsigned int irq; 6362306a36Sopenharmony_ci bool assigned; 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* 6762306a36Sopenharmony_ci * The number of DMA links to use. Two is the bare minimum, but if you 6862306a36Sopenharmony_ci * have really small links you might need more. 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_ci#define NUM_DMA_LINKS 2 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/** fsl_dma_private: p-substream DMA data 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * Each substream has a 1-to-1 association with a DMA channel. 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * The link[] array is first because it needs to be aligned on a 32-byte 7762306a36Sopenharmony_ci * boundary, so putting it first will ensure alignment without padding the 7862306a36Sopenharmony_ci * structure. 7962306a36Sopenharmony_ci * 8062306a36Sopenharmony_ci * @link[]: array of link descriptors 8162306a36Sopenharmony_ci * @dma_channel: pointer to the DMA channel's registers 8262306a36Sopenharmony_ci * @irq: IRQ for this DMA channel 8362306a36Sopenharmony_ci * @substream: pointer to the substream object, needed by the ISR 8462306a36Sopenharmony_ci * @ssi_sxx_phys: bus address of the STX or SRX register to use 8562306a36Sopenharmony_ci * @ld_buf_phys: physical address of the LD buffer 8662306a36Sopenharmony_ci * @current_link: index into link[] of the link currently being processed 8762306a36Sopenharmony_ci * @dma_buf_phys: physical address of the DMA buffer 8862306a36Sopenharmony_ci * @dma_buf_next: physical address of the next period to process 8962306a36Sopenharmony_ci * @dma_buf_end: physical address of the byte after the end of the DMA 9062306a36Sopenharmony_ci * @buffer period_size: the size of a single period 9162306a36Sopenharmony_ci * @num_periods: the number of periods in the DMA buffer 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cistruct fsl_dma_private { 9462306a36Sopenharmony_ci struct fsl_dma_link_descriptor link[NUM_DMA_LINKS]; 9562306a36Sopenharmony_ci struct ccsr_dma_channel __iomem *dma_channel; 9662306a36Sopenharmony_ci unsigned int irq; 9762306a36Sopenharmony_ci struct snd_pcm_substream *substream; 9862306a36Sopenharmony_ci dma_addr_t ssi_sxx_phys; 9962306a36Sopenharmony_ci unsigned int ssi_fifo_depth; 10062306a36Sopenharmony_ci dma_addr_t ld_buf_phys; 10162306a36Sopenharmony_ci unsigned int current_link; 10262306a36Sopenharmony_ci dma_addr_t dma_buf_phys; 10362306a36Sopenharmony_ci dma_addr_t dma_buf_next; 10462306a36Sopenharmony_ci dma_addr_t dma_buf_end; 10562306a36Sopenharmony_ci size_t period_size; 10662306a36Sopenharmony_ci unsigned int num_periods; 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/** 11062306a36Sopenharmony_ci * fsl_dma_hardare: define characteristics of the PCM hardware. 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * The PCM hardware is the Freescale DMA controller. This structure defines 11362306a36Sopenharmony_ci * the capabilities of that hardware. 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * Since the sampling rate and data format are not controlled by the DMA 11662306a36Sopenharmony_ci * controller, we specify no limits for those values. The only exception is 11762306a36Sopenharmony_ci * period_bytes_min, which is set to a reasonably low value to prevent the 11862306a36Sopenharmony_ci * DMA controller from generating too many interrupts per second. 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci * Since each link descriptor has a 32-bit byte count field, we set 12162306a36Sopenharmony_ci * period_bytes_max to the largest 32-bit number. We also have no maximum 12262306a36Sopenharmony_ci * number of periods. 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * Note that we specify SNDRV_PCM_INFO_JOINT_DUPLEX here, but only because a 12562306a36Sopenharmony_ci * limitation in the SSI driver requires the sample rates for playback and 12662306a36Sopenharmony_ci * capture to be the same. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_cistatic const struct snd_pcm_hardware fsl_dma_hardware = { 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci .info = SNDRV_PCM_INFO_INTERLEAVED | 13162306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP | 13262306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 13362306a36Sopenharmony_ci SNDRV_PCM_INFO_JOINT_DUPLEX | 13462306a36Sopenharmony_ci SNDRV_PCM_INFO_PAUSE, 13562306a36Sopenharmony_ci .formats = FSLDMA_PCM_FORMATS, 13662306a36Sopenharmony_ci .period_bytes_min = 512, /* A reasonable limit */ 13762306a36Sopenharmony_ci .period_bytes_max = (u32) -1, 13862306a36Sopenharmony_ci .periods_min = NUM_DMA_LINKS, 13962306a36Sopenharmony_ci .periods_max = (unsigned int) -1, 14062306a36Sopenharmony_ci .buffer_bytes_max = 128 * 1024, /* A reasonable limit */ 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/** 14462306a36Sopenharmony_ci * fsl_dma_abort_stream: tell ALSA that the DMA transfer has aborted 14562306a36Sopenharmony_ci * 14662306a36Sopenharmony_ci * This function should be called by the ISR whenever the DMA controller 14762306a36Sopenharmony_ci * halts data transfer. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_cistatic void fsl_dma_abort_stream(struct snd_pcm_substream *substream) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci snd_pcm_stop_xrun(substream); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/** 15562306a36Sopenharmony_ci * fsl_dma_update_pointers - update LD pointers to point to the next period 15662306a36Sopenharmony_ci * 15762306a36Sopenharmony_ci * As each period is completed, this function changes the link 15862306a36Sopenharmony_ci * descriptor pointers for that period to point to the next period. 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_cistatic void fsl_dma_update_pointers(struct fsl_dma_private *dma_private) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct fsl_dma_link_descriptor *link = 16362306a36Sopenharmony_ci &dma_private->link[dma_private->current_link]; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Update our link descriptors to point to the next period. On a 36-bit 16662306a36Sopenharmony_ci * system, we also need to update the ESAD bits. We also set (keep) the 16762306a36Sopenharmony_ci * snoop bits. See the comments in fsl_dma_hw_params() about snooping. 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_ci if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 17062306a36Sopenharmony_ci link->source_addr = cpu_to_be32(dma_private->dma_buf_next); 17162306a36Sopenharmony_ci#ifdef CONFIG_PHYS_64BIT 17262306a36Sopenharmony_ci link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP | 17362306a36Sopenharmony_ci upper_32_bits(dma_private->dma_buf_next)); 17462306a36Sopenharmony_ci#endif 17562306a36Sopenharmony_ci } else { 17662306a36Sopenharmony_ci link->dest_addr = cpu_to_be32(dma_private->dma_buf_next); 17762306a36Sopenharmony_ci#ifdef CONFIG_PHYS_64BIT 17862306a36Sopenharmony_ci link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP | 17962306a36Sopenharmony_ci upper_32_bits(dma_private->dma_buf_next)); 18062306a36Sopenharmony_ci#endif 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* Update our variables for next time */ 18462306a36Sopenharmony_ci dma_private->dma_buf_next += dma_private->period_size; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (dma_private->dma_buf_next >= dma_private->dma_buf_end) 18762306a36Sopenharmony_ci dma_private->dma_buf_next = dma_private->dma_buf_phys; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (++dma_private->current_link >= NUM_DMA_LINKS) 19062306a36Sopenharmony_ci dma_private->current_link = 0; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/** 19462306a36Sopenharmony_ci * fsl_dma_isr: interrupt handler for the DMA controller 19562306a36Sopenharmony_ci * 19662306a36Sopenharmony_ci * @irq: IRQ of the DMA channel 19762306a36Sopenharmony_ci * @dev_id: pointer to the dma_private structure for this DMA channel 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_cistatic irqreturn_t fsl_dma_isr(int irq, void *dev_id) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct fsl_dma_private *dma_private = dev_id; 20262306a36Sopenharmony_ci struct snd_pcm_substream *substream = dma_private->substream; 20362306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 20462306a36Sopenharmony_ci struct device *dev = rtd->dev; 20562306a36Sopenharmony_ci struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; 20662306a36Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 20762306a36Sopenharmony_ci u32 sr, sr2 = 0; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* We got an interrupt, so read the status register to see what we 21062306a36Sopenharmony_ci were interrupted for. 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_ci sr = in_be32(&dma_channel->sr); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (sr & CCSR_DMA_SR_TE) { 21562306a36Sopenharmony_ci dev_err(dev, "dma transmit error\n"); 21662306a36Sopenharmony_ci fsl_dma_abort_stream(substream); 21762306a36Sopenharmony_ci sr2 |= CCSR_DMA_SR_TE; 21862306a36Sopenharmony_ci ret = IRQ_HANDLED; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (sr & CCSR_DMA_SR_CH) 22262306a36Sopenharmony_ci ret = IRQ_HANDLED; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (sr & CCSR_DMA_SR_PE) { 22562306a36Sopenharmony_ci dev_err(dev, "dma programming error\n"); 22662306a36Sopenharmony_ci fsl_dma_abort_stream(substream); 22762306a36Sopenharmony_ci sr2 |= CCSR_DMA_SR_PE; 22862306a36Sopenharmony_ci ret = IRQ_HANDLED; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (sr & CCSR_DMA_SR_EOLNI) { 23262306a36Sopenharmony_ci sr2 |= CCSR_DMA_SR_EOLNI; 23362306a36Sopenharmony_ci ret = IRQ_HANDLED; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (sr & CCSR_DMA_SR_CB) 23762306a36Sopenharmony_ci ret = IRQ_HANDLED; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (sr & CCSR_DMA_SR_EOSI) { 24062306a36Sopenharmony_ci /* Tell ALSA we completed a period. */ 24162306a36Sopenharmony_ci snd_pcm_period_elapsed(substream); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* 24462306a36Sopenharmony_ci * Update our link descriptors to point to the next period. We 24562306a36Sopenharmony_ci * only need to do this if the number of periods is not equal to 24662306a36Sopenharmony_ci * the number of links. 24762306a36Sopenharmony_ci */ 24862306a36Sopenharmony_ci if (dma_private->num_periods != NUM_DMA_LINKS) 24962306a36Sopenharmony_ci fsl_dma_update_pointers(dma_private); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci sr2 |= CCSR_DMA_SR_EOSI; 25262306a36Sopenharmony_ci ret = IRQ_HANDLED; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (sr & CCSR_DMA_SR_EOLSI) { 25662306a36Sopenharmony_ci sr2 |= CCSR_DMA_SR_EOLSI; 25762306a36Sopenharmony_ci ret = IRQ_HANDLED; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* Clear the bits that we set */ 26162306a36Sopenharmony_ci if (sr2) 26262306a36Sopenharmony_ci out_be32(&dma_channel->sr, sr2); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return ret; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci/** 26862306a36Sopenharmony_ci * fsl_dma_new: initialize this PCM driver. 26962306a36Sopenharmony_ci * 27062306a36Sopenharmony_ci * This function is called when the codec driver calls snd_soc_new_pcms(), 27162306a36Sopenharmony_ci * once for each .dai_link in the machine driver's snd_soc_card 27262306a36Sopenharmony_ci * structure. 27362306a36Sopenharmony_ci * 27462306a36Sopenharmony_ci * snd_dma_alloc_pages() is just a front-end to dma_alloc_coherent(), which 27562306a36Sopenharmony_ci * (currently) always allocates the DMA buffer in lowmem, even if GFP_HIGHMEM 27662306a36Sopenharmony_ci * is specified. Therefore, any DMA buffers we allocate will always be in low 27762306a36Sopenharmony_ci * memory, but we support for 36-bit physical addresses anyway. 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * Regardless of where the memory is actually allocated, since the device can 28062306a36Sopenharmony_ci * technically DMA to any 36-bit address, we do need to set the DMA mask to 36. 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_cistatic int fsl_dma_new(struct snd_soc_component *component, 28362306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct snd_card *card = rtd->card->snd_card; 28662306a36Sopenharmony_ci struct snd_pcm *pcm = rtd->pcm; 28762306a36Sopenharmony_ci int ret; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(36)); 29062306a36Sopenharmony_ci if (ret) 29162306a36Sopenharmony_ci return ret; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 29462306a36Sopenharmony_ci card->dev, 29562306a36Sopenharmony_ci fsl_dma_hardware.buffer_bytes_max); 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci/** 29962306a36Sopenharmony_ci * fsl_dma_open: open a new substream. 30062306a36Sopenharmony_ci * 30162306a36Sopenharmony_ci * Each substream has its own DMA buffer. 30262306a36Sopenharmony_ci * 30362306a36Sopenharmony_ci * ALSA divides the DMA buffer into N periods. We create NUM_DMA_LINKS link 30462306a36Sopenharmony_ci * descriptors that ping-pong from one period to the next. For example, if 30562306a36Sopenharmony_ci * there are six periods and two link descriptors, this is how they look 30662306a36Sopenharmony_ci * before playback starts: 30762306a36Sopenharmony_ci * 30862306a36Sopenharmony_ci * The last link descriptor 30962306a36Sopenharmony_ci * ____________ points back to the first 31062306a36Sopenharmony_ci * | | 31162306a36Sopenharmony_ci * V | 31262306a36Sopenharmony_ci * ___ ___ | 31362306a36Sopenharmony_ci * | |->| |->| 31462306a36Sopenharmony_ci * |___| |___| 31562306a36Sopenharmony_ci * | | 31662306a36Sopenharmony_ci * | | 31762306a36Sopenharmony_ci * V V 31862306a36Sopenharmony_ci * _________________________________________ 31962306a36Sopenharmony_ci * | | | | | | | The DMA buffer is 32062306a36Sopenharmony_ci * | | | | | | | divided into 6 parts 32162306a36Sopenharmony_ci * |______|______|______|______|______|______| 32262306a36Sopenharmony_ci * 32362306a36Sopenharmony_ci * and here's how they look after the first period is finished playing: 32462306a36Sopenharmony_ci * 32562306a36Sopenharmony_ci * ____________ 32662306a36Sopenharmony_ci * | | 32762306a36Sopenharmony_ci * V | 32862306a36Sopenharmony_ci * ___ ___ | 32962306a36Sopenharmony_ci * | |->| |->| 33062306a36Sopenharmony_ci * |___| |___| 33162306a36Sopenharmony_ci * | | 33262306a36Sopenharmony_ci * |______________ 33362306a36Sopenharmony_ci * | | 33462306a36Sopenharmony_ci * V V 33562306a36Sopenharmony_ci * _________________________________________ 33662306a36Sopenharmony_ci * | | | | | | | 33762306a36Sopenharmony_ci * | | | | | | | 33862306a36Sopenharmony_ci * |______|______|______|______|______|______| 33962306a36Sopenharmony_ci * 34062306a36Sopenharmony_ci * The first link descriptor now points to the third period. The DMA 34162306a36Sopenharmony_ci * controller is currently playing the second period. When it finishes, it 34262306a36Sopenharmony_ci * will jump back to the first descriptor and play the third period. 34362306a36Sopenharmony_ci * 34462306a36Sopenharmony_ci * There are four reasons we do this: 34562306a36Sopenharmony_ci * 34662306a36Sopenharmony_ci * 1. The only way to get the DMA controller to automatically restart the 34762306a36Sopenharmony_ci * transfer when it gets to the end of the buffer is to use chaining 34862306a36Sopenharmony_ci * mode. Basic direct mode doesn't offer that feature. 34962306a36Sopenharmony_ci * 2. We need to receive an interrupt at the end of every period. The DMA 35062306a36Sopenharmony_ci * controller can generate an interrupt at the end of every link transfer 35162306a36Sopenharmony_ci * (aka segment). Making each period into a DMA segment will give us the 35262306a36Sopenharmony_ci * interrupts we need. 35362306a36Sopenharmony_ci * 3. By creating only two link descriptors, regardless of the number of 35462306a36Sopenharmony_ci * periods, we do not need to reallocate the link descriptors if the 35562306a36Sopenharmony_ci * number of periods changes. 35662306a36Sopenharmony_ci * 4. All of the audio data is still stored in a single, contiguous DMA 35762306a36Sopenharmony_ci * buffer, which is what ALSA expects. We're just dividing it into 35862306a36Sopenharmony_ci * contiguous parts, and creating a link descriptor for each one. 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_cistatic int fsl_dma_open(struct snd_soc_component *component, 36162306a36Sopenharmony_ci struct snd_pcm_substream *substream) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 36462306a36Sopenharmony_ci struct device *dev = component->dev; 36562306a36Sopenharmony_ci struct dma_object *dma = 36662306a36Sopenharmony_ci container_of(component->driver, struct dma_object, dai); 36762306a36Sopenharmony_ci struct fsl_dma_private *dma_private; 36862306a36Sopenharmony_ci struct ccsr_dma_channel __iomem *dma_channel; 36962306a36Sopenharmony_ci dma_addr_t ld_buf_phys; 37062306a36Sopenharmony_ci u64 temp_link; /* Pointer to next link descriptor */ 37162306a36Sopenharmony_ci u32 mr; 37262306a36Sopenharmony_ci int ret = 0; 37362306a36Sopenharmony_ci unsigned int i; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* 37662306a36Sopenharmony_ci * Reject any DMA buffer whose size is not a multiple of the period 37762306a36Sopenharmony_ci * size. We need to make sure that the DMA buffer can be evenly divided 37862306a36Sopenharmony_ci * into periods. 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_ci ret = snd_pcm_hw_constraint_integer(runtime, 38162306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS); 38262306a36Sopenharmony_ci if (ret < 0) { 38362306a36Sopenharmony_ci dev_err(dev, "invalid buffer size\n"); 38462306a36Sopenharmony_ci return ret; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (dma->assigned) { 38862306a36Sopenharmony_ci dev_err(dev, "dma channel already assigned\n"); 38962306a36Sopenharmony_ci return -EBUSY; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci dma_private = dma_alloc_coherent(dev, sizeof(struct fsl_dma_private), 39362306a36Sopenharmony_ci &ld_buf_phys, GFP_KERNEL); 39462306a36Sopenharmony_ci if (!dma_private) { 39562306a36Sopenharmony_ci dev_err(dev, "can't allocate dma private data\n"); 39662306a36Sopenharmony_ci return -ENOMEM; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 39962306a36Sopenharmony_ci dma_private->ssi_sxx_phys = dma->ssi_stx_phys; 40062306a36Sopenharmony_ci else 40162306a36Sopenharmony_ci dma_private->ssi_sxx_phys = dma->ssi_srx_phys; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci dma_private->ssi_fifo_depth = dma->ssi_fifo_depth; 40462306a36Sopenharmony_ci dma_private->dma_channel = dma->channel; 40562306a36Sopenharmony_ci dma_private->irq = dma->irq; 40662306a36Sopenharmony_ci dma_private->substream = substream; 40762306a36Sopenharmony_ci dma_private->ld_buf_phys = ld_buf_phys; 40862306a36Sopenharmony_ci dma_private->dma_buf_phys = substream->dma_buffer.addr; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci ret = request_irq(dma_private->irq, fsl_dma_isr, 0, "fsldma-audio", 41162306a36Sopenharmony_ci dma_private); 41262306a36Sopenharmony_ci if (ret) { 41362306a36Sopenharmony_ci dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n", 41462306a36Sopenharmony_ci dma_private->irq, ret); 41562306a36Sopenharmony_ci dma_free_coherent(dev, sizeof(struct fsl_dma_private), 41662306a36Sopenharmony_ci dma_private, dma_private->ld_buf_phys); 41762306a36Sopenharmony_ci return ret; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci dma->assigned = true; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware); 42362306a36Sopenharmony_ci runtime->private_data = dma_private; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* Program the fixed DMA controller parameters */ 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci dma_channel = dma_private->dma_channel; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci temp_link = dma_private->ld_buf_phys + 43062306a36Sopenharmony_ci sizeof(struct fsl_dma_link_descriptor); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci for (i = 0; i < NUM_DMA_LINKS; i++) { 43362306a36Sopenharmony_ci dma_private->link[i].next = cpu_to_be64(temp_link); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci temp_link += sizeof(struct fsl_dma_link_descriptor); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci /* The last link descriptor points to the first */ 43862306a36Sopenharmony_ci dma_private->link[i - 1].next = cpu_to_be64(dma_private->ld_buf_phys); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* Tell the DMA controller where the first link descriptor is */ 44162306a36Sopenharmony_ci out_be32(&dma_channel->clndar, 44262306a36Sopenharmony_ci CCSR_DMA_CLNDAR_ADDR(dma_private->ld_buf_phys)); 44362306a36Sopenharmony_ci out_be32(&dma_channel->eclndar, 44462306a36Sopenharmony_ci CCSR_DMA_ECLNDAR_ADDR(dma_private->ld_buf_phys)); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* The manual says the BCR must be clear before enabling EMP */ 44762306a36Sopenharmony_ci out_be32(&dma_channel->bcr, 0); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* 45062306a36Sopenharmony_ci * Program the mode register for interrupts, external master control, 45162306a36Sopenharmony_ci * and source/destination hold. Also clear the Channel Abort bit. 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_ci mr = in_be32(&dma_channel->mr) & 45462306a36Sopenharmony_ci ~(CCSR_DMA_MR_CA | CCSR_DMA_MR_DAHE | CCSR_DMA_MR_SAHE); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* 45762306a36Sopenharmony_ci * We want External Master Start and External Master Pause enabled, 45862306a36Sopenharmony_ci * because the SSI is controlling the DMA controller. We want the DMA 45962306a36Sopenharmony_ci * controller to be set up in advance, and then we signal only the SSI 46062306a36Sopenharmony_ci * to start transferring. 46162306a36Sopenharmony_ci * 46262306a36Sopenharmony_ci * We want End-Of-Segment Interrupts enabled, because this will generate 46362306a36Sopenharmony_ci * an interrupt at the end of each segment (each link descriptor 46462306a36Sopenharmony_ci * represents one segment). Each DMA segment is the same thing as an 46562306a36Sopenharmony_ci * ALSA period, so this is how we get an interrupt at the end of every 46662306a36Sopenharmony_ci * period. 46762306a36Sopenharmony_ci * 46862306a36Sopenharmony_ci * We want Error Interrupt enabled, so that we can get an error if 46962306a36Sopenharmony_ci * the DMA controller is mis-programmed somehow. 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_ci mr |= CCSR_DMA_MR_EOSIE | CCSR_DMA_MR_EIE | CCSR_DMA_MR_EMP_EN | 47262306a36Sopenharmony_ci CCSR_DMA_MR_EMS_EN; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* For playback, we want the destination address to be held. For 47562306a36Sopenharmony_ci capture, set the source address to be held. */ 47662306a36Sopenharmony_ci mr |= (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 47762306a36Sopenharmony_ci CCSR_DMA_MR_DAHE : CCSR_DMA_MR_SAHE; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci out_be32(&dma_channel->mr, mr); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return 0; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci/** 48562306a36Sopenharmony_ci * fsl_dma_hw_params: continue initializing the DMA links 48662306a36Sopenharmony_ci * 48762306a36Sopenharmony_ci * This function obtains hardware parameters about the opened stream and 48862306a36Sopenharmony_ci * programs the DMA controller accordingly. 48962306a36Sopenharmony_ci * 49062306a36Sopenharmony_ci * One drawback of big-endian is that when copying integers of different 49162306a36Sopenharmony_ci * sizes to a fixed-sized register, the address to which the integer must be 49262306a36Sopenharmony_ci * copied is dependent on the size of the integer. 49362306a36Sopenharmony_ci * 49462306a36Sopenharmony_ci * For example, if P is the address of a 32-bit register, and X is a 32-bit 49562306a36Sopenharmony_ci * integer, then X should be copied to address P. However, if X is a 16-bit 49662306a36Sopenharmony_ci * integer, then it should be copied to P+2. If X is an 8-bit register, 49762306a36Sopenharmony_ci * then it should be copied to P+3. 49862306a36Sopenharmony_ci * 49962306a36Sopenharmony_ci * So for playback of 8-bit samples, the DMA controller must transfer single 50062306a36Sopenharmony_ci * bytes from the DMA buffer to the last byte of the STX0 register, i.e. 50162306a36Sopenharmony_ci * offset by 3 bytes. For 16-bit samples, the offset is two bytes. 50262306a36Sopenharmony_ci * 50362306a36Sopenharmony_ci * For 24-bit samples, the offset is 1 byte. However, the DMA controller 50462306a36Sopenharmony_ci * does not support 3-byte copies (the DAHTS register supports only 1, 2, 4, 50562306a36Sopenharmony_ci * and 8 bytes at a time). So we do not support packed 24-bit samples. 50662306a36Sopenharmony_ci * 24-bit data must be padded to 32 bits. 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_cistatic int fsl_dma_hw_params(struct snd_soc_component *component, 50962306a36Sopenharmony_ci struct snd_pcm_substream *substream, 51062306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 51362306a36Sopenharmony_ci struct fsl_dma_private *dma_private = runtime->private_data; 51462306a36Sopenharmony_ci struct device *dev = component->dev; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* Number of bits per sample */ 51762306a36Sopenharmony_ci unsigned int sample_bits = 51862306a36Sopenharmony_ci snd_pcm_format_physical_width(params_format(hw_params)); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* Number of bytes per frame */ 52162306a36Sopenharmony_ci unsigned int sample_bytes = sample_bits / 8; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* Bus address of SSI STX register */ 52462306a36Sopenharmony_ci dma_addr_t ssi_sxx_phys = dma_private->ssi_sxx_phys; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* Size of the DMA buffer, in bytes */ 52762306a36Sopenharmony_ci size_t buffer_size = params_buffer_bytes(hw_params); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci /* Number of bytes per period */ 53062306a36Sopenharmony_ci size_t period_size = params_period_bytes(hw_params); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* Pointer to next period */ 53362306a36Sopenharmony_ci dma_addr_t temp_addr = substream->dma_buffer.addr; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci /* Pointer to DMA controller */ 53662306a36Sopenharmony_ci struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci u32 mr; /* DMA Mode Register */ 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci unsigned int i; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* Initialize our DMA tracking variables */ 54362306a36Sopenharmony_ci dma_private->period_size = period_size; 54462306a36Sopenharmony_ci dma_private->num_periods = params_periods(hw_params); 54562306a36Sopenharmony_ci dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size; 54662306a36Sopenharmony_ci dma_private->dma_buf_next = dma_private->dma_buf_phys + 54762306a36Sopenharmony_ci (NUM_DMA_LINKS * period_size); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (dma_private->dma_buf_next >= dma_private->dma_buf_end) 55062306a36Sopenharmony_ci /* This happens if the number of periods == NUM_DMA_LINKS */ 55162306a36Sopenharmony_ci dma_private->dma_buf_next = dma_private->dma_buf_phys; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci mr = in_be32(&dma_channel->mr) & ~(CCSR_DMA_MR_BWC_MASK | 55462306a36Sopenharmony_ci CCSR_DMA_MR_SAHTS_MASK | CCSR_DMA_MR_DAHTS_MASK); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* Due to a quirk of the SSI's STX register, the target address 55762306a36Sopenharmony_ci * for the DMA operations depends on the sample size. So we calculate 55862306a36Sopenharmony_ci * that offset here. While we're at it, also tell the DMA controller 55962306a36Sopenharmony_ci * how much data to transfer per sample. 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_ci switch (sample_bits) { 56262306a36Sopenharmony_ci case 8: 56362306a36Sopenharmony_ci mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1; 56462306a36Sopenharmony_ci ssi_sxx_phys += 3; 56562306a36Sopenharmony_ci break; 56662306a36Sopenharmony_ci case 16: 56762306a36Sopenharmony_ci mr |= CCSR_DMA_MR_DAHTS_2 | CCSR_DMA_MR_SAHTS_2; 56862306a36Sopenharmony_ci ssi_sxx_phys += 2; 56962306a36Sopenharmony_ci break; 57062306a36Sopenharmony_ci case 32: 57162306a36Sopenharmony_ci mr |= CCSR_DMA_MR_DAHTS_4 | CCSR_DMA_MR_SAHTS_4; 57262306a36Sopenharmony_ci break; 57362306a36Sopenharmony_ci default: 57462306a36Sopenharmony_ci /* We should never get here */ 57562306a36Sopenharmony_ci dev_err(dev, "unsupported sample size %u\n", sample_bits); 57662306a36Sopenharmony_ci return -EINVAL; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* 58062306a36Sopenharmony_ci * BWC determines how many bytes are sent/received before the DMA 58162306a36Sopenharmony_ci * controller checks the SSI to see if it needs to stop. BWC should 58262306a36Sopenharmony_ci * always be a multiple of the frame size, so that we always transmit 58362306a36Sopenharmony_ci * whole frames. Each frame occupies two slots in the FIFO. The 58462306a36Sopenharmony_ci * parameter for CCSR_DMA_MR_BWC() is rounded down the next power of two 58562306a36Sopenharmony_ci * (MR[BWC] can only represent even powers of two). 58662306a36Sopenharmony_ci * 58762306a36Sopenharmony_ci * To simplify the process, we set BWC to the largest value that is 58862306a36Sopenharmony_ci * less than or equal to the FIFO watermark. For playback, this ensures 58962306a36Sopenharmony_ci * that we transfer the maximum amount without overrunning the FIFO. 59062306a36Sopenharmony_ci * For capture, this ensures that we transfer the maximum amount without 59162306a36Sopenharmony_ci * underrunning the FIFO. 59262306a36Sopenharmony_ci * 59362306a36Sopenharmony_ci * f = SSI FIFO depth 59462306a36Sopenharmony_ci * w = SSI watermark value (which equals f - 2) 59562306a36Sopenharmony_ci * b = DMA bandwidth count (in bytes) 59662306a36Sopenharmony_ci * s = sample size (in bytes, which equals frame_size * 2) 59762306a36Sopenharmony_ci * 59862306a36Sopenharmony_ci * For playback, we never transmit more than the transmit FIFO 59962306a36Sopenharmony_ci * watermark, otherwise we might write more data than the FIFO can hold. 60062306a36Sopenharmony_ci * The watermark is equal to the FIFO depth minus two. 60162306a36Sopenharmony_ci * 60262306a36Sopenharmony_ci * For capture, two equations must hold: 60362306a36Sopenharmony_ci * w > f - (b / s) 60462306a36Sopenharmony_ci * w >= b / s 60562306a36Sopenharmony_ci * 60662306a36Sopenharmony_ci * So, b > 2 * s, but b must also be <= s * w. To simplify, we set 60762306a36Sopenharmony_ci * b = s * w, which is equal to 60862306a36Sopenharmony_ci * (dma_private->ssi_fifo_depth - 2) * sample_bytes. 60962306a36Sopenharmony_ci */ 61062306a36Sopenharmony_ci mr |= CCSR_DMA_MR_BWC((dma_private->ssi_fifo_depth - 2) * sample_bytes); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci out_be32(&dma_channel->mr, mr); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci for (i = 0; i < NUM_DMA_LINKS; i++) { 61562306a36Sopenharmony_ci struct fsl_dma_link_descriptor *link = &dma_private->link[i]; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci link->count = cpu_to_be32(period_size); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* The snoop bit tells the DMA controller whether it should tell 62062306a36Sopenharmony_ci * the ECM to snoop during a read or write to an address. For 62162306a36Sopenharmony_ci * audio, we use DMA to transfer data between memory and an I/O 62262306a36Sopenharmony_ci * device (the SSI's STX0 or SRX0 register). Snooping is only 62362306a36Sopenharmony_ci * needed if there is a cache, so we need to snoop memory 62462306a36Sopenharmony_ci * addresses only. For playback, that means we snoop the source 62562306a36Sopenharmony_ci * but not the destination. For capture, we snoop the 62662306a36Sopenharmony_ci * destination but not the source. 62762306a36Sopenharmony_ci * 62862306a36Sopenharmony_ci * Note that failing to snoop properly is unlikely to cause 62962306a36Sopenharmony_ci * cache incoherency if the period size is larger than the 63062306a36Sopenharmony_ci * size of L1 cache. This is because filling in one period will 63162306a36Sopenharmony_ci * flush out the data for the previous period. So if you 63262306a36Sopenharmony_ci * increased period_bytes_min to a large enough size, you might 63362306a36Sopenharmony_ci * get more performance by not snooping, and you'll still be 63462306a36Sopenharmony_ci * okay. You'll need to update fsl_dma_update_pointers() also. 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 63762306a36Sopenharmony_ci link->source_addr = cpu_to_be32(temp_addr); 63862306a36Sopenharmony_ci link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP | 63962306a36Sopenharmony_ci upper_32_bits(temp_addr)); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci link->dest_addr = cpu_to_be32(ssi_sxx_phys); 64262306a36Sopenharmony_ci link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP | 64362306a36Sopenharmony_ci upper_32_bits(ssi_sxx_phys)); 64462306a36Sopenharmony_ci } else { 64562306a36Sopenharmony_ci link->source_addr = cpu_to_be32(ssi_sxx_phys); 64662306a36Sopenharmony_ci link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP | 64762306a36Sopenharmony_ci upper_32_bits(ssi_sxx_phys)); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci link->dest_addr = cpu_to_be32(temp_addr); 65062306a36Sopenharmony_ci link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP | 65162306a36Sopenharmony_ci upper_32_bits(temp_addr)); 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci temp_addr += period_size; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return 0; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci/** 66162306a36Sopenharmony_ci * fsl_dma_pointer: determine the current position of the DMA transfer 66262306a36Sopenharmony_ci * 66362306a36Sopenharmony_ci * This function is called by ALSA when ALSA wants to know where in the 66462306a36Sopenharmony_ci * stream buffer the hardware currently is. 66562306a36Sopenharmony_ci * 66662306a36Sopenharmony_ci * For playback, the SAR register contains the physical address of the most 66762306a36Sopenharmony_ci * recent DMA transfer. For capture, the value is in the DAR register. 66862306a36Sopenharmony_ci * 66962306a36Sopenharmony_ci * The base address of the buffer is stored in the source_addr field of the 67062306a36Sopenharmony_ci * first link descriptor. 67162306a36Sopenharmony_ci */ 67262306a36Sopenharmony_cistatic snd_pcm_uframes_t fsl_dma_pointer(struct snd_soc_component *component, 67362306a36Sopenharmony_ci struct snd_pcm_substream *substream) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 67662306a36Sopenharmony_ci struct fsl_dma_private *dma_private = runtime->private_data; 67762306a36Sopenharmony_ci struct device *dev = component->dev; 67862306a36Sopenharmony_ci struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; 67962306a36Sopenharmony_ci dma_addr_t position; 68062306a36Sopenharmony_ci snd_pcm_uframes_t frames; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci /* Obtain the current DMA pointer, but don't read the ESAD bits if we 68362306a36Sopenharmony_ci * only have 32-bit DMA addresses. This function is typically called 68462306a36Sopenharmony_ci * in interrupt context, so we need to optimize it. 68562306a36Sopenharmony_ci */ 68662306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 68762306a36Sopenharmony_ci position = in_be32(&dma_channel->sar); 68862306a36Sopenharmony_ci#ifdef CONFIG_PHYS_64BIT 68962306a36Sopenharmony_ci position |= (u64)(in_be32(&dma_channel->satr) & 69062306a36Sopenharmony_ci CCSR_DMA_ATR_ESAD_MASK) << 32; 69162306a36Sopenharmony_ci#endif 69262306a36Sopenharmony_ci } else { 69362306a36Sopenharmony_ci position = in_be32(&dma_channel->dar); 69462306a36Sopenharmony_ci#ifdef CONFIG_PHYS_64BIT 69562306a36Sopenharmony_ci position |= (u64)(in_be32(&dma_channel->datr) & 69662306a36Sopenharmony_ci CCSR_DMA_ATR_ESAD_MASK) << 32; 69762306a36Sopenharmony_ci#endif 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* 70162306a36Sopenharmony_ci * When capture is started, the SSI immediately starts to fill its FIFO. 70262306a36Sopenharmony_ci * This means that the DMA controller is not started until the FIFO is 70362306a36Sopenharmony_ci * full. However, ALSA calls this function before that happens, when 70462306a36Sopenharmony_ci * MR.DAR is still zero. In this case, just return zero to indicate 70562306a36Sopenharmony_ci * that nothing has been received yet. 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_ci if (!position) 70862306a36Sopenharmony_ci return 0; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if ((position < dma_private->dma_buf_phys) || 71162306a36Sopenharmony_ci (position > dma_private->dma_buf_end)) { 71262306a36Sopenharmony_ci dev_err(dev, "dma pointer is out of range, halting stream\n"); 71362306a36Sopenharmony_ci return SNDRV_PCM_POS_XRUN; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci frames = bytes_to_frames(runtime, position - dma_private->dma_buf_phys); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* 71962306a36Sopenharmony_ci * If the current address is just past the end of the buffer, wrap it 72062306a36Sopenharmony_ci * around. 72162306a36Sopenharmony_ci */ 72262306a36Sopenharmony_ci if (frames == runtime->buffer_size) 72362306a36Sopenharmony_ci frames = 0; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci return frames; 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci/** 72962306a36Sopenharmony_ci * fsl_dma_hw_free: release resources allocated in fsl_dma_hw_params() 73062306a36Sopenharmony_ci * 73162306a36Sopenharmony_ci * Release the resources allocated in fsl_dma_hw_params() and de-program the 73262306a36Sopenharmony_ci * registers. 73362306a36Sopenharmony_ci * 73462306a36Sopenharmony_ci * This function can be called multiple times. 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_cistatic int fsl_dma_hw_free(struct snd_soc_component *component, 73762306a36Sopenharmony_ci struct snd_pcm_substream *substream) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 74062306a36Sopenharmony_ci struct fsl_dma_private *dma_private = runtime->private_data; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (dma_private) { 74362306a36Sopenharmony_ci struct ccsr_dma_channel __iomem *dma_channel; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci dma_channel = dma_private->dma_channel; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci /* Stop the DMA */ 74862306a36Sopenharmony_ci out_be32(&dma_channel->mr, CCSR_DMA_MR_CA); 74962306a36Sopenharmony_ci out_be32(&dma_channel->mr, 0); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* Reset all the other registers */ 75262306a36Sopenharmony_ci out_be32(&dma_channel->sr, -1); 75362306a36Sopenharmony_ci out_be32(&dma_channel->clndar, 0); 75462306a36Sopenharmony_ci out_be32(&dma_channel->eclndar, 0); 75562306a36Sopenharmony_ci out_be32(&dma_channel->satr, 0); 75662306a36Sopenharmony_ci out_be32(&dma_channel->sar, 0); 75762306a36Sopenharmony_ci out_be32(&dma_channel->datr, 0); 75862306a36Sopenharmony_ci out_be32(&dma_channel->dar, 0); 75962306a36Sopenharmony_ci out_be32(&dma_channel->bcr, 0); 76062306a36Sopenharmony_ci out_be32(&dma_channel->nlndar, 0); 76162306a36Sopenharmony_ci out_be32(&dma_channel->enlndar, 0); 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci return 0; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci/** 76862306a36Sopenharmony_ci * fsl_dma_close: close the stream. 76962306a36Sopenharmony_ci */ 77062306a36Sopenharmony_cistatic int fsl_dma_close(struct snd_soc_component *component, 77162306a36Sopenharmony_ci struct snd_pcm_substream *substream) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 77462306a36Sopenharmony_ci struct fsl_dma_private *dma_private = runtime->private_data; 77562306a36Sopenharmony_ci struct device *dev = component->dev; 77662306a36Sopenharmony_ci struct dma_object *dma = 77762306a36Sopenharmony_ci container_of(component->driver, struct dma_object, dai); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci if (dma_private) { 78062306a36Sopenharmony_ci if (dma_private->irq) 78162306a36Sopenharmony_ci free_irq(dma_private->irq, dma_private); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci /* Deallocate the fsl_dma_private structure */ 78462306a36Sopenharmony_ci dma_free_coherent(dev, sizeof(struct fsl_dma_private), 78562306a36Sopenharmony_ci dma_private, dma_private->ld_buf_phys); 78662306a36Sopenharmony_ci substream->runtime->private_data = NULL; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci dma->assigned = false; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci return 0; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci/** 79562306a36Sopenharmony_ci * find_ssi_node -- returns the SSI node that points to its DMA channel node 79662306a36Sopenharmony_ci * 79762306a36Sopenharmony_ci * Although this DMA driver attempts to operate independently of the other 79862306a36Sopenharmony_ci * devices, it still needs to determine some information about the SSI device 79962306a36Sopenharmony_ci * that it's working with. Unfortunately, the device tree does not contain 80062306a36Sopenharmony_ci * a pointer from the DMA channel node to the SSI node -- the pointer goes the 80162306a36Sopenharmony_ci * other way. So we need to scan the device tree for SSI nodes until we find 80262306a36Sopenharmony_ci * the one that points to the given DMA channel node. It's ugly, but at least 80362306a36Sopenharmony_ci * it's contained in this one function. 80462306a36Sopenharmony_ci */ 80562306a36Sopenharmony_cistatic struct device_node *find_ssi_node(struct device_node *dma_channel_np) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci struct device_node *ssi_np, *np; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci for_each_compatible_node(ssi_np, NULL, "fsl,mpc8610-ssi") { 81062306a36Sopenharmony_ci /* Check each DMA phandle to see if it points to us. We 81162306a36Sopenharmony_ci * assume that device_node pointers are a valid comparison. 81262306a36Sopenharmony_ci */ 81362306a36Sopenharmony_ci np = of_parse_phandle(ssi_np, "fsl,playback-dma", 0); 81462306a36Sopenharmony_ci of_node_put(np); 81562306a36Sopenharmony_ci if (np == dma_channel_np) 81662306a36Sopenharmony_ci return ssi_np; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci np = of_parse_phandle(ssi_np, "fsl,capture-dma", 0); 81962306a36Sopenharmony_ci of_node_put(np); 82062306a36Sopenharmony_ci if (np == dma_channel_np) 82162306a36Sopenharmony_ci return ssi_np; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci return NULL; 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic int fsl_soc_dma_probe(struct platform_device *pdev) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci struct dma_object *dma; 83062306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 83162306a36Sopenharmony_ci struct device_node *ssi_np; 83262306a36Sopenharmony_ci struct resource res; 83362306a36Sopenharmony_ci const uint32_t *iprop; 83462306a36Sopenharmony_ci int ret; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* Find the SSI node that points to us. */ 83762306a36Sopenharmony_ci ssi_np = find_ssi_node(np); 83862306a36Sopenharmony_ci if (!ssi_np) { 83962306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot find parent SSI node\n"); 84062306a36Sopenharmony_ci return -ENODEV; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci ret = of_address_to_resource(ssi_np, 0, &res); 84462306a36Sopenharmony_ci if (ret) { 84562306a36Sopenharmony_ci dev_err(&pdev->dev, "could not determine resources for %pOF\n", 84662306a36Sopenharmony_ci ssi_np); 84762306a36Sopenharmony_ci of_node_put(ssi_np); 84862306a36Sopenharmony_ci return ret; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci dma = kzalloc(sizeof(*dma), GFP_KERNEL); 85262306a36Sopenharmony_ci if (!dma) { 85362306a36Sopenharmony_ci of_node_put(ssi_np); 85462306a36Sopenharmony_ci return -ENOMEM; 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci dma->dai.name = DRV_NAME; 85862306a36Sopenharmony_ci dma->dai.open = fsl_dma_open; 85962306a36Sopenharmony_ci dma->dai.close = fsl_dma_close; 86062306a36Sopenharmony_ci dma->dai.hw_params = fsl_dma_hw_params; 86162306a36Sopenharmony_ci dma->dai.hw_free = fsl_dma_hw_free; 86262306a36Sopenharmony_ci dma->dai.pointer = fsl_dma_pointer; 86362306a36Sopenharmony_ci dma->dai.pcm_construct = fsl_dma_new; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci /* Store the SSI-specific information that we need */ 86662306a36Sopenharmony_ci dma->ssi_stx_phys = res.start + REG_SSI_STX0; 86762306a36Sopenharmony_ci dma->ssi_srx_phys = res.start + REG_SSI_SRX0; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL); 87062306a36Sopenharmony_ci if (iprop) 87162306a36Sopenharmony_ci dma->ssi_fifo_depth = be32_to_cpup(iprop); 87262306a36Sopenharmony_ci else 87362306a36Sopenharmony_ci /* Older 8610 DTs didn't have the fifo-depth property */ 87462306a36Sopenharmony_ci dma->ssi_fifo_depth = 8; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci of_node_put(ssi_np); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, &dma->dai, NULL, 0); 87962306a36Sopenharmony_ci if (ret) { 88062306a36Sopenharmony_ci dev_err(&pdev->dev, "could not register platform\n"); 88162306a36Sopenharmony_ci kfree(dma); 88262306a36Sopenharmony_ci return ret; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci dma->channel = of_iomap(np, 0); 88662306a36Sopenharmony_ci dma->irq = irq_of_parse_and_map(np, 0); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci dev_set_drvdata(&pdev->dev, dma); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci return 0; 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_cistatic void fsl_soc_dma_remove(struct platform_device *pdev) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci struct dma_object *dma = dev_get_drvdata(&pdev->dev); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci iounmap(dma->channel); 89862306a36Sopenharmony_ci irq_dispose_mapping(dma->irq); 89962306a36Sopenharmony_ci kfree(dma); 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_cistatic const struct of_device_id fsl_soc_dma_ids[] = { 90362306a36Sopenharmony_ci { .compatible = "fsl,ssi-dma-channel", }, 90462306a36Sopenharmony_ci {} 90562306a36Sopenharmony_ci}; 90662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, fsl_soc_dma_ids); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_cistatic struct platform_driver fsl_soc_dma_driver = { 90962306a36Sopenharmony_ci .driver = { 91062306a36Sopenharmony_ci .name = "fsl-pcm-audio", 91162306a36Sopenharmony_ci .of_match_table = fsl_soc_dma_ids, 91262306a36Sopenharmony_ci }, 91362306a36Sopenharmony_ci .probe = fsl_soc_dma_probe, 91462306a36Sopenharmony_ci .remove_new = fsl_soc_dma_remove, 91562306a36Sopenharmony_ci}; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_cimodule_platform_driver(fsl_soc_dma_driver); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ciMODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); 92062306a36Sopenharmony_ciMODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM Driver"); 92162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 922