cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tw686x-audio.c (10851B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar
      4 *
      5 * Based on the audio support from the tw6869 driver:
      6 * Copyright 2015 www.starterkit.ru <info@starterkit.ru>
      7 *
      8 * Based on:
      9 * Driver for Intersil|Techwell TW6869 based DVR cards
     10 * (c) 2011-12 liran <jli11@intersil.com> [Intersil|Techwell China]
     11 */
     12
     13#include <linux/types.h>
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/init.h>
     17#include <linux/kmod.h>
     18#include <linux/mutex.h>
     19#include <linux/pci.h>
     20#include <linux/delay.h>
     21
     22#include <sound/core.h>
     23#include <sound/initval.h>
     24#include <sound/pcm.h>
     25#include <sound/control.h>
     26#include "tw686x.h"
     27#include "tw686x-regs.h"
     28
     29#define AUDIO_CHANNEL_OFFSET 8
     30
     31void tw686x_audio_irq(struct tw686x_dev *dev, unsigned long requests,
     32		      unsigned int pb_status)
     33{
     34	unsigned long flags;
     35	unsigned int ch, pb;
     36
     37	for_each_set_bit(ch, &requests, max_channels(dev)) {
     38		struct tw686x_audio_channel *ac = &dev->audio_channels[ch];
     39		struct tw686x_audio_buf *done = NULL;
     40		struct tw686x_audio_buf *next = NULL;
     41		struct tw686x_dma_desc *desc;
     42
     43		pb = !!(pb_status & BIT(AUDIO_CHANNEL_OFFSET + ch));
     44
     45		spin_lock_irqsave(&ac->lock, flags);
     46
     47		/* Sanity check */
     48		if (!ac->ss || !ac->curr_bufs[0] || !ac->curr_bufs[1]) {
     49			spin_unlock_irqrestore(&ac->lock, flags);
     50			continue;
     51		}
     52
     53		if (!list_empty(&ac->buf_list)) {
     54			next = list_first_entry(&ac->buf_list,
     55					struct tw686x_audio_buf, list);
     56			list_move_tail(&next->list, &ac->buf_list);
     57			done = ac->curr_bufs[!pb];
     58			ac->curr_bufs[pb] = next;
     59		}
     60		spin_unlock_irqrestore(&ac->lock, flags);
     61
     62		if (!done || !next)
     63			continue;
     64		/*
     65		 * Checking for a non-nil dma_desc[pb]->virt buffer is
     66		 * the same as checking for memcpy DMA mode.
     67		 */
     68		desc = &ac->dma_descs[pb];
     69		if (desc->virt) {
     70			memcpy(done->virt, desc->virt,
     71			       dev->period_size);
     72		} else {
     73			u32 reg = pb ? ADMA_B_ADDR[ch] : ADMA_P_ADDR[ch];
     74			reg_write(dev, reg, next->dma);
     75		}
     76		ac->ptr = done->dma - ac->buf[0].dma;
     77		snd_pcm_period_elapsed(ac->ss);
     78	}
     79}
     80
     81/*
     82 * Audio parameters are global and shared among all
     83 * capture channels. The driver prevents changes to
     84 * the parameters if any audio channel is capturing.
     85 */
     86static const struct snd_pcm_hardware tw686x_capture_hw = {
     87	.info			= (SNDRV_PCM_INFO_MMAP |
     88				   SNDRV_PCM_INFO_INTERLEAVED |
     89				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
     90				   SNDRV_PCM_INFO_MMAP_VALID),
     91	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
     92	.rates			= SNDRV_PCM_RATE_8000_48000,
     93	.rate_min		= 8000,
     94	.rate_max		= 48000,
     95	.channels_min		= 1,
     96	.channels_max		= 1,
     97	.buffer_bytes_max	= TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX,
     98	.period_bytes_min	= AUDIO_DMA_SIZE_MIN,
     99	.period_bytes_max	= AUDIO_DMA_SIZE_MAX,
    100	.periods_min		= TW686X_AUDIO_PERIODS_MIN,
    101	.periods_max		= TW686X_AUDIO_PERIODS_MAX,
    102};
    103
    104static int tw686x_pcm_open(struct snd_pcm_substream *ss)
    105{
    106	struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
    107	struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
    108	struct snd_pcm_runtime *rt = ss->runtime;
    109	int err;
    110
    111	ac->ss = ss;
    112	rt->hw = tw686x_capture_hw;
    113
    114	err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
    115	if (err < 0)
    116		return err;
    117
    118	return 0;
    119}
    120
    121static int tw686x_pcm_close(struct snd_pcm_substream *ss)
    122{
    123	struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
    124	struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
    125
    126	ac->ss = NULL;
    127	return 0;
    128}
    129
    130static int tw686x_pcm_prepare(struct snd_pcm_substream *ss)
    131{
    132	struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
    133	struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
    134	struct snd_pcm_runtime *rt = ss->runtime;
    135	unsigned int period_size = snd_pcm_lib_period_bytes(ss);
    136	struct tw686x_audio_buf *p_buf, *b_buf;
    137	unsigned long flags;
    138	int i;
    139
    140	spin_lock_irqsave(&dev->lock, flags);
    141	/*
    142	 * Given the audio parameters are global (i.e. shared across
    143	 * DMA channels), we need to check new params are allowed.
    144	 */
    145	if (((dev->audio_rate != rt->rate) ||
    146	     (dev->period_size != period_size)) && dev->audio_enabled)
    147		goto err_audio_busy;
    148
    149	tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch);
    150	spin_unlock_irqrestore(&dev->lock, flags);
    151
    152	if (dev->audio_rate != rt->rate) {
    153		u32 reg;
    154
    155		dev->audio_rate = rt->rate;
    156		reg = ((125000000 / rt->rate) << 16) +
    157		       ((125000000 % rt->rate) << 16) / rt->rate;
    158
    159		reg_write(dev, AUDIO_CONTROL2, reg);
    160	}
    161
    162	if (dev->period_size != period_size) {
    163		u32 reg;
    164
    165		dev->period_size = period_size;
    166		reg = reg_read(dev, AUDIO_CONTROL1);
    167		reg &= ~(AUDIO_DMA_SIZE_MASK << AUDIO_DMA_SIZE_SHIFT);
    168		reg |= period_size << AUDIO_DMA_SIZE_SHIFT;
    169
    170		reg_write(dev, AUDIO_CONTROL1, reg);
    171	}
    172
    173	if (rt->periods < TW686X_AUDIO_PERIODS_MIN ||
    174	    rt->periods > TW686X_AUDIO_PERIODS_MAX)
    175		return -EINVAL;
    176
    177	spin_lock_irqsave(&ac->lock, flags);
    178	INIT_LIST_HEAD(&ac->buf_list);
    179
    180	for (i = 0; i < rt->periods; i++) {
    181		ac->buf[i].dma = rt->dma_addr + period_size * i;
    182		ac->buf[i].virt = rt->dma_area + period_size * i;
    183		INIT_LIST_HEAD(&ac->buf[i].list);
    184		list_add_tail(&ac->buf[i].list, &ac->buf_list);
    185	}
    186
    187	p_buf =	list_first_entry(&ac->buf_list, struct tw686x_audio_buf, list);
    188	list_move_tail(&p_buf->list, &ac->buf_list);
    189
    190	b_buf =	list_first_entry(&ac->buf_list, struct tw686x_audio_buf, list);
    191	list_move_tail(&b_buf->list, &ac->buf_list);
    192
    193	ac->curr_bufs[0] = p_buf;
    194	ac->curr_bufs[1] = b_buf;
    195	ac->ptr = 0;
    196
    197	if (dev->dma_mode != TW686X_DMA_MODE_MEMCPY) {
    198		reg_write(dev, ADMA_P_ADDR[ac->ch], p_buf->dma);
    199		reg_write(dev, ADMA_B_ADDR[ac->ch], b_buf->dma);
    200	}
    201
    202	spin_unlock_irqrestore(&ac->lock, flags);
    203
    204	return 0;
    205
    206err_audio_busy:
    207	spin_unlock_irqrestore(&dev->lock, flags);
    208	return -EBUSY;
    209}
    210
    211static int tw686x_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
    212{
    213	struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
    214	struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
    215	unsigned long flags;
    216	int err = 0;
    217
    218	switch (cmd) {
    219	case SNDRV_PCM_TRIGGER_START:
    220		if (ac->curr_bufs[0] && ac->curr_bufs[1]) {
    221			spin_lock_irqsave(&dev->lock, flags);
    222			dev->audio_enabled = 1;
    223			tw686x_enable_channel(dev,
    224				AUDIO_CHANNEL_OFFSET + ac->ch);
    225			spin_unlock_irqrestore(&dev->lock, flags);
    226
    227			mod_timer(&dev->dma_delay_timer,
    228				  jiffies + msecs_to_jiffies(100));
    229		} else {
    230			err = -EIO;
    231		}
    232		break;
    233	case SNDRV_PCM_TRIGGER_STOP:
    234		spin_lock_irqsave(&dev->lock, flags);
    235		dev->audio_enabled = 0;
    236		tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch);
    237		spin_unlock_irqrestore(&dev->lock, flags);
    238
    239		spin_lock_irqsave(&ac->lock, flags);
    240		ac->curr_bufs[0] = NULL;
    241		ac->curr_bufs[1] = NULL;
    242		spin_unlock_irqrestore(&ac->lock, flags);
    243		break;
    244	default:
    245		err = -EINVAL;
    246	}
    247	return err;
    248}
    249
    250static snd_pcm_uframes_t tw686x_pcm_pointer(struct snd_pcm_substream *ss)
    251{
    252	struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
    253	struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
    254
    255	return bytes_to_frames(ss->runtime, ac->ptr);
    256}
    257
    258static const struct snd_pcm_ops tw686x_pcm_ops = {
    259	.open = tw686x_pcm_open,
    260	.close = tw686x_pcm_close,
    261	.prepare = tw686x_pcm_prepare,
    262	.trigger = tw686x_pcm_trigger,
    263	.pointer = tw686x_pcm_pointer,
    264};
    265
    266static int tw686x_snd_pcm_init(struct tw686x_dev *dev)
    267{
    268	struct snd_card *card = dev->snd_card;
    269	struct snd_pcm *pcm;
    270	struct snd_pcm_substream *ss;
    271	unsigned int i;
    272	int err;
    273
    274	err = snd_pcm_new(card, card->driver, 0, 0, max_channels(dev), &pcm);
    275	if (err < 0)
    276		return err;
    277
    278	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &tw686x_pcm_ops);
    279	snd_pcm_chip(pcm) = dev;
    280	pcm->info_flags = 0;
    281	strscpy(pcm->name, "tw686x PCM", sizeof(pcm->name));
    282
    283	for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
    284	     ss; ss = ss->next, i++)
    285		snprintf(ss->name, sizeof(ss->name), "vch%u audio", i);
    286
    287	snd_pcm_set_managed_buffer_all(pcm,
    288				SNDRV_DMA_TYPE_DEV,
    289				&dev->pci_dev->dev,
    290				TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX,
    291				TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX);
    292	return 0;
    293}
    294
    295static void tw686x_audio_dma_free(struct tw686x_dev *dev,
    296				  struct tw686x_audio_channel *ac)
    297{
    298	int pb;
    299
    300	for (pb = 0; pb < 2; pb++) {
    301		if (!ac->dma_descs[pb].virt)
    302			continue;
    303		dma_free_coherent(&dev->pci_dev->dev, ac->dma_descs[pb].size,
    304				  ac->dma_descs[pb].virt,
    305				  ac->dma_descs[pb].phys);
    306		ac->dma_descs[pb].virt = NULL;
    307	}
    308}
    309
    310static int tw686x_audio_dma_alloc(struct tw686x_dev *dev,
    311				  struct tw686x_audio_channel *ac)
    312{
    313	int pb;
    314
    315	/*
    316	 * In the memcpy DMA mode we allocate a coherent buffer
    317	 * and use it for the DMA capture. Otherwise, DMA
    318	 * acts on the ALSA buffers as received in pcm_prepare.
    319	 */
    320	if (dev->dma_mode != TW686X_DMA_MODE_MEMCPY)
    321		return 0;
    322
    323	for (pb = 0; pb < 2; pb++) {
    324		u32 reg = pb ? ADMA_B_ADDR[ac->ch] : ADMA_P_ADDR[ac->ch];
    325		void *virt;
    326
    327		virt = dma_alloc_coherent(&dev->pci_dev->dev,
    328					  AUDIO_DMA_SIZE_MAX,
    329					  &ac->dma_descs[pb].phys, GFP_KERNEL);
    330		if (!virt) {
    331			dev_err(&dev->pci_dev->dev,
    332				"dma%d: unable to allocate audio DMA %s-buffer\n",
    333				ac->ch, pb ? "B" : "P");
    334			return -ENOMEM;
    335		}
    336		ac->dma_descs[pb].virt = virt;
    337		ac->dma_descs[pb].size = AUDIO_DMA_SIZE_MAX;
    338		reg_write(dev, reg, ac->dma_descs[pb].phys);
    339	}
    340	return 0;
    341}
    342
    343void tw686x_audio_free(struct tw686x_dev *dev)
    344{
    345	unsigned long flags;
    346	u32 dma_ch_mask;
    347	u32 dma_cmd;
    348
    349	spin_lock_irqsave(&dev->lock, flags);
    350	dma_cmd = reg_read(dev, DMA_CMD);
    351	dma_ch_mask = reg_read(dev, DMA_CHANNEL_ENABLE);
    352	reg_write(dev, DMA_CMD, dma_cmd & ~0xff00);
    353	reg_write(dev, DMA_CHANNEL_ENABLE, dma_ch_mask & ~0xff00);
    354	spin_unlock_irqrestore(&dev->lock, flags);
    355
    356	if (!dev->snd_card)
    357		return;
    358	snd_card_free(dev->snd_card);
    359	dev->snd_card = NULL;
    360}
    361
    362int tw686x_audio_init(struct tw686x_dev *dev)
    363{
    364	struct pci_dev *pci_dev = dev->pci_dev;
    365	struct snd_card *card;
    366	int err, ch;
    367
    368	/* Enable external audio */
    369	reg_write(dev, AUDIO_CONTROL1, BIT(0));
    370
    371	err = snd_card_new(&pci_dev->dev, SNDRV_DEFAULT_IDX1,
    372			   SNDRV_DEFAULT_STR1,
    373			   THIS_MODULE, 0, &card);
    374	if (err < 0)
    375		return err;
    376
    377	dev->snd_card = card;
    378	strscpy(card->driver, "tw686x", sizeof(card->driver));
    379	strscpy(card->shortname, "tw686x", sizeof(card->shortname));
    380	strscpy(card->longname, pci_name(pci_dev), sizeof(card->longname));
    381	snd_card_set_dev(card, &pci_dev->dev);
    382
    383	for (ch = 0; ch < max_channels(dev); ch++) {
    384		struct tw686x_audio_channel *ac;
    385
    386		ac = &dev->audio_channels[ch];
    387		spin_lock_init(&ac->lock);
    388		ac->dev = dev;
    389		ac->ch = ch;
    390
    391		err = tw686x_audio_dma_alloc(dev, ac);
    392		if (err < 0)
    393			goto err_cleanup;
    394	}
    395
    396	err = tw686x_snd_pcm_init(dev);
    397	if (err < 0)
    398		goto err_cleanup;
    399
    400	err = snd_card_register(card);
    401	if (!err)
    402		return 0;
    403
    404err_cleanup:
    405	for (ch = 0; ch < max_channels(dev); ch++) {
    406		if (!dev->audio_channels[ch].dev)
    407			continue;
    408		tw686x_audio_dma_free(dev, &dev->audio_channels[ch]);
    409	}
    410	snd_card_free(card);
    411	dev->snd_card = NULL;
    412	return err;
    413}