[alsa-devel] [PATCH V5 3/3] ASoC: AMD: add AMD ASoC ACP-I2S driver

maruthi srinivas maruthi.srinivas.b at gmail.com
Fri Aug 21 04:51:07 PDT 2015


On Fri, Aug 21, 2015 at 4:48 AM, Mark Brown <broonie at kernel.org> wrote:
>
> On Thu, Aug 20, 2015 at 05:36:34PM -0400, Alex Deucher wrote:
> > From: Maruthi Srinivas Bayyavarapu <Maruthi.Bayyavarapu at amd.com>
> >
> > ACP IP block consists of dedicated DMA and I2S blocks. The PCM driver
> > provides the DMA and CPU DAI components to ALSA core.
>
> This is flagged as patch 3/3 but appears to be sent as a single patch.
> Please don't do this, the purpose of numbering patches is to help people
> tell which order they are in.  Numbering only makes sense when you send
> more than one patch, if you are sending a single patch there is no need
> to number.

Ok, sorry. I will be more careful next time. Actually, two patches are
sent - one for
DRM and other ASoC. It should have been represented as 2/2.

>
>
> > +++ b/sound/soc/amd/Kconfig
> > @@ -0,0 +1,5 @@
> > +config SND_SOC_AMD_ACP
> > +     tristate "AMD Audio Coprocessor support"
> > +     depends on MFD_CORE
>
> What is the dependency on the MFD core?

None. Sorry, I forgot to remove this.
Actually, AMD DRM driver depends on MFD_CORE to create a platform device
for ASoC. This is already present in DRM patch.

>
>
> > +/*
> > + * AMD ALSA SoC PCM Driver
> > + *
> > + * Copyright 2014-2015 Advanced Micro Devices, Inc.
> > + *
> > + * Permission is hereby granted, free of charge, to any person obtaining a
> > + * copy of this software and associated documentation files (the "Software"),
> > + * to deal in the Software without restriction, including without limitation
> > + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> > + * and/or sell copies of the Software, and to permit persons to whom the
> > + * Software is furnished to do so, subject to the following conditions:
> > + *
> > + * The above copyright notice and this permission notice shall be included in
> > + * all copies or substantial portions of the Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> > + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> > + * OTHER DEALINGS IN THE SOFTWARE.
>
> Still not happy with the licensing.

 I will contact our internal teams and get back on this.

>
> > +static const struct snd_soc_component_driver dw_i2s_component = {
> > +     .name = "dw-i2s",
> > +};
>
> We already have a driver for the DesignWare I2S controller.  To repeat
> the concern I raised in a slightly different bit of the code last time:
>
> | This doesn't appear to be a designware-i2s driver, we already have one
> | of those?
>

Our IP block includes few AMD IPs along with DesignWare I2S IP.  I have reused
code from Designware I2S controller from
sound/soc/dwc/designware_i2s.c and because
of the way IPs are coupled together, I couldn't use existing
Designware I2S driver as is.
I have given credit to the original author in DRM patch copyright
header, where register I2S read/writes
are made. Do I need to add the same header in ASoC driver too ?

>
> Like I say please stop ignoring review comments.  The hw_params()
> certainly seems to bear more than a passing resemblance.
>

Iam sorry,  this mistake won't be repeated.

>
> > +static void acp_pcm_period_elapsed(struct device *dev, u16 play_intr,
> > +                                                     u16 capture_intr)
> > +{
> > +     struct snd_pcm_substream *substream;
> > +     struct audio_drv_data *irq_data = dev_get_drvdata(dev);
> > +
> > +     /* Inform ALSA about the period elapsed (one out of two periods) */
> > +     if (play_intr)
> > +             substream = irq_data->play_stream;
> > +     else
> > +             substream = irq_data->capture_stream;
>
> So you've replaced the two if statements with an if/else which means
> subsstream is now guaranteed to be initialized but perhaps not in the
> way the caller intended...  I did find the caller (which got moved into
> another patch in this version) and it appears that the two u16s are
> actually used to pass boolean flags.  The whole interface here now
> seems odd, what is going on here?
>

Agreed. I will modify this interface to use a bool, in next revision

>
> > +     if (NULL != pg) {
>
> We still normally write these checks more like (pg != NULL) or even just
> (pg).
>

Ok, will modify accordingly in next revision.

>
> > +             /* Save for runtime private data */
> > +             rtd->pg = pg;
> > +             rtd->order = get_order(size);
> > +
> > +             /* Let ACP know the Allocated memory */
> > +             num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
> > +
> > +             /* Fill the page table entries in ACP SRAM */
> > +             rtd->pg = pg;
> > +             rtd->size = size;
> > +             rtd->num_of_pages = num_of_pages;
> > +             rtd->direction = substream->stream;
> > +
> > +             acp_dev->config_dma(acp_dev, rtd);
> > +             status = 0;
> > +     } else {
> > +             status = -ENOMEM;
> > +     }
> > +     return status;
> > +}
> > +
> > +static int acp_dma_hw_free(struct snd_pcm_substream *substream)
> > +{
> > +     return snd_pcm_lib_free_pages(substream);
> > +}
>
> hw_free() doesn't seem to undo everything that we did on allocation?


Oh! I freed  in dma_close(), that were  allocated in dma_open(). Rest
of them  used devm_*
>
>
> > +             /* Now configure DMA to transfer only first half of System RAM
> > +              * buffer before playback is triggered. This will overwrite
> > +              * zero-ed second half of SRAM buffer */
> > +             acp_dev->config_dma_channel(acp_dev, SYSRAM_TO_ACP_CH_NUM,
> > +                                     PLAYBACK_START_DMA_DESCR_CH12,
> > +                                     1, 0);
>
> | Why?  The comments describe what's happening but it's not clear why it's
> | happening.
>

|------------|----------|
|    A        |       B   |   DRAM
|------------|----------|
           \    /
            \  /
             \/  DMA
             /\
|---------/-|-\--------|
|    C   /   |  \    D  |   SRAM ---DMA ---------> I2S
|-----------|----------|

buffer in System memory(DRAM) is divided into 2 periods - say A,B.
internal memory
inside ACP IP (SRAM) is also divided in similar way - say C,D. In
hw_params()  A and B
are filled with zeros. In prepare() , content of A and B are DMA'ed to
D and C respectively
(as per DMA configuration).  When ALSA core fills A and B with audio content
(start threshold = A+B size), trigger() is called and content of A is
transferred to D.
C still holds zeros by now. The internal buffer (SRAM) which holds C+D
will be DMA'ed to
I2S in cyclic way starting from C.

At the end of C or D's DMA to I2S, irq is generated. In irq handler
DMA is done from B to C
or A to D depending on C or D' DMA completion respectively and
snd_pcm_period_elapsed()
is called.

The reason for doing this is :  When C completes rendering, calls
period_elapsed() and informs
ALSA core there is free space to fill new data to system memory. In
the same irq handler, B is
DMA'ed to C to be ready by the time D completes rendering with
prefetched data (in trigger()).
when D completes rendering, new data fetched by ALSA core can be
DMA'ed  from A to D and
rendering is continued with C. This is done cyclically.

If I don’t do A->D, B->C and instead do A->C, B->D,  there would be
timing problem to have new
data ready to be rendered. The alternate approach would be implement
'copy' callback of
'snd_pcm_ops' in pcm driver. In that callback, I can use
copy_from_user()  to get new data and
then only issue DMA transfers (A->C / B->D). This can solve the timing
issue mentioned, but then
I can't handle MMAP based playback/capture. Existing design can handle
non-mmap and mmap based
transfers, but the only issue(?) would be 1 period size of zeros will
be played initially for any new
playback usecase.

> > +static struct snd_soc_dai_driver i2s_dai_driver = {
> > +     .playback = {
> > +                  .stream_name = "I2S Playback",
> > +                  .channels_min = 2,
> > +                  .channels_max = 2,
>
> Elsewhere support for 8 channels was declared and handled.

The board for which driver is developed, doesn't support more than 2 channels.

>
> > +                  .rates = SNDRV_PCM_RATE_8000_96000,
> > +                  .formats = SNDRV_PCM_FMTBIT_S24_LE |
> > +                             SNDRV_PCM_FMTBIT_S32_LE,
>
> Elsewhere there was 16 bit support declared and handled.

There is a bug in our I2S IP, which wrongly handles 16 bit and lower
resolutions.
So, I removed the support. All the players using the driver, will
handle unsupported
formats with the help of pulseaudio conversions.

>
> > +     pm_rts = pm_runtime_status_suspended(dev);
> > +     if (pm_rts == true) {
>
> There seem to be a lot of variables in here that have only one
> assignment and one user immediately next to them.  I'm not sure it's
> adding much.
>

Ok, I will reuse  variables, where required and remove extra ones in
the next version.

> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>


More information about the dri-devel mailing list