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

vxp_ops.c (14894B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Driver for Digigram VXpocket soundcards
      4 *
      5 * lowlevel routines for VXpocket soundcards
      6 *
      7 * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
      8 */
      9
     10#include <linux/delay.h>
     11#include <linux/device.h>
     12#include <linux/firmware.h>
     13#include <linux/io.h>
     14#include <sound/core.h>
     15#include "vxpocket.h"
     16
     17
     18static const int vxp_reg_offset[VX_REG_MAX] = {
     19	[VX_ICR]	= 0x00,		// ICR
     20	[VX_CVR]	= 0x01,		// CVR
     21	[VX_ISR]	= 0x02,		// ISR
     22	[VX_IVR]	= 0x03,		// IVR
     23	[VX_RXH]	= 0x05,		// RXH
     24	[VX_RXM]	= 0x06,		// RXM
     25	[VX_RXL]	= 0x07,		// RXL
     26	[VX_DMA]	= 0x04,		// DMA
     27	[VX_CDSP]	= 0x08,		// CDSP
     28	[VX_LOFREQ]	= 0x09,		// LFREQ
     29	[VX_HIFREQ]	= 0x0a,		// HFREQ
     30	[VX_DATA]	= 0x0b,		// DATA
     31	[VX_MICRO]	= 0x0c,		// MICRO
     32	[VX_DIALOG]	= 0x0d,		// DIALOG
     33	[VX_CSUER]	= 0x0e,		// CSUER
     34	[VX_RUER]	= 0x0f,		// RUER
     35};
     36
     37
     38static inline unsigned long vxp_reg_addr(struct vx_core *_chip, int reg)
     39{
     40	struct snd_vxpocket *chip = to_vxpocket(_chip);
     41	return chip->port + vxp_reg_offset[reg];
     42}
     43
     44/*
     45 * snd_vx_inb - read a byte from the register
     46 * @offset: register offset
     47 */
     48static unsigned char vxp_inb(struct vx_core *chip, int offset)
     49{
     50	return inb(vxp_reg_addr(chip, offset));
     51}
     52
     53/*
     54 * snd_vx_outb - write a byte on the register
     55 * @offset: the register offset
     56 * @val: the value to write
     57 */
     58static void vxp_outb(struct vx_core *chip, int offset, unsigned char val)
     59{
     60	outb(val, vxp_reg_addr(chip, offset));
     61}
     62
     63/*
     64 * redefine macros to call directly
     65 */
     66#undef vx_inb
     67#define vx_inb(chip,reg)	vxp_inb((struct vx_core *)(chip), VX_##reg)
     68#undef vx_outb
     69#define vx_outb(chip,reg,val)	vxp_outb((struct vx_core *)(chip), VX_##reg,val)
     70
     71
     72/*
     73 * vx_check_magic - check the magic word on xilinx
     74 *
     75 * returns zero if a magic word is detected, or a negative error code.
     76 */
     77static int vx_check_magic(struct vx_core *chip)
     78{
     79	unsigned long end_time = jiffies + HZ / 5;
     80	int c;
     81	do {
     82		c = vx_inb(chip, CDSP);
     83		if (c == CDSP_MAGIC)
     84			return 0;
     85		msleep(10);
     86	} while (time_after_eq(end_time, jiffies));
     87	snd_printk(KERN_ERR "cannot find xilinx magic word (%x)\n", c);
     88	return -EIO;
     89}
     90
     91
     92/*
     93 * vx_reset_dsp - reset the DSP
     94 */
     95
     96#define XX_DSP_RESET_WAIT_TIME		2	/* ms */
     97
     98static void vxp_reset_dsp(struct vx_core *_chip)
     99{
    100	struct snd_vxpocket *chip = to_vxpocket(_chip);
    101
    102	/* set the reset dsp bit to 1 */
    103	vx_outb(chip, CDSP, chip->regCDSP | VXP_CDSP_DSP_RESET_MASK);
    104	vx_inb(chip, CDSP);
    105	mdelay(XX_DSP_RESET_WAIT_TIME);
    106	/* reset the bit */
    107	chip->regCDSP &= ~VXP_CDSP_DSP_RESET_MASK;
    108	vx_outb(chip, CDSP, chip->regCDSP);
    109	vx_inb(chip, CDSP);
    110	mdelay(XX_DSP_RESET_WAIT_TIME);
    111}
    112
    113/*
    114 * reset codec bit
    115 */
    116static void vxp_reset_codec(struct vx_core *_chip)
    117{
    118	struct snd_vxpocket *chip = to_vxpocket(_chip);
    119
    120	/* Set the reset CODEC bit to 1. */
    121	vx_outb(chip, CDSP, chip->regCDSP | VXP_CDSP_CODEC_RESET_MASK);
    122	vx_inb(chip, CDSP);
    123	msleep(10);
    124	/* Set the reset CODEC bit to 0. */
    125	chip->regCDSP &= ~VXP_CDSP_CODEC_RESET_MASK;
    126	vx_outb(chip, CDSP, chip->regCDSP);
    127	vx_inb(chip, CDSP);
    128	msleep(1);
    129}
    130
    131/*
    132 * vx_load_xilinx_binary - load the xilinx binary image
    133 * the binary image is the binary array converted from the bitstream file.
    134 */
    135static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware *fw)
    136{
    137	struct snd_vxpocket *chip = to_vxpocket(_chip);
    138	unsigned int i;
    139	int c;
    140	int regCSUER, regRUER;
    141	const unsigned char *image;
    142	unsigned char data;
    143
    144	/* Switch to programmation mode */
    145	chip->regDIALOG |= VXP_DLG_XILINX_REPROG_MASK;
    146	vx_outb(chip, DIALOG, chip->regDIALOG);
    147
    148	/* Save register CSUER and RUER */
    149	regCSUER = vx_inb(chip, CSUER);
    150	regRUER = vx_inb(chip, RUER);
    151
    152	/* reset HF0 and HF1 */
    153	vx_outb(chip, ICR, 0);
    154
    155	/* Wait for answer HF2 equal to 1 */
    156	snd_printdd(KERN_DEBUG "check ISR_HF2\n");
    157	if (vx_check_isr(_chip, ISR_HF2, ISR_HF2, 20) < 0)
    158		goto _error;
    159
    160	/* set HF1 for loading xilinx binary */
    161	vx_outb(chip, ICR, ICR_HF1);
    162	image = fw->data;
    163	for (i = 0; i < fw->size; i++, image++) {
    164		data = *image;
    165		if (vx_wait_isr_bit(_chip, ISR_TX_EMPTY) < 0)
    166			goto _error;
    167		vx_outb(chip, TXL, data);
    168		/* wait for reading */
    169		if (vx_wait_for_rx_full(_chip) < 0)
    170			goto _error;
    171		c = vx_inb(chip, RXL);
    172		if (c != (int)data)
    173			snd_printk(KERN_ERR "vxpocket: load xilinx mismatch at %d: 0x%x != 0x%x\n", i, c, (int)data);
    174        }
    175
    176	/* reset HF1 */
    177	vx_outb(chip, ICR, 0);
    178
    179	/* wait for HF3 */
    180	if (vx_check_isr(_chip, ISR_HF3, ISR_HF3, 20) < 0)
    181		goto _error;
    182
    183	/* read the number of bytes received */
    184	if (vx_wait_for_rx_full(_chip) < 0)
    185		goto _error;
    186
    187	c = (int)vx_inb(chip, RXH) << 16;
    188	c |= (int)vx_inb(chip, RXM) << 8;
    189	c |= vx_inb(chip, RXL);
    190
    191	snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%zx\n", c, fw->size);
    192
    193	vx_outb(chip, ICR, ICR_HF0);
    194
    195	/* TEMPO 250ms : wait until Xilinx is downloaded */
    196	msleep(300);
    197
    198	/* test magical word */
    199	if (vx_check_magic(_chip) < 0)
    200		goto _error;
    201
    202	/* Restore register 0x0E and 0x0F (thus replacing COR and FCSR) */
    203	vx_outb(chip, CSUER, regCSUER);
    204	vx_outb(chip, RUER, regRUER);
    205
    206	/* Reset the Xilinx's signal enabling IO access */
    207	chip->regDIALOG |= VXP_DLG_XILINX_REPROG_MASK;
    208	vx_outb(chip, DIALOG, chip->regDIALOG);
    209	vx_inb(chip, DIALOG);
    210	msleep(10);
    211	chip->regDIALOG &= ~VXP_DLG_XILINX_REPROG_MASK;
    212	vx_outb(chip, DIALOG, chip->regDIALOG);
    213	vx_inb(chip, DIALOG);
    214
    215	/* Reset of the Codec */
    216	vxp_reset_codec(_chip);
    217	vx_reset_dsp(_chip);
    218
    219	return 0;
    220
    221 _error:
    222	vx_outb(chip, CSUER, regCSUER);
    223	vx_outb(chip, RUER, regRUER);
    224	chip->regDIALOG &= ~VXP_DLG_XILINX_REPROG_MASK;
    225	vx_outb(chip, DIALOG, chip->regDIALOG);
    226	return -EIO;
    227}
    228
    229
    230/*
    231 * vxp_load_dsp - load_dsp callback
    232 */
    233static int vxp_load_dsp(struct vx_core *vx, int index, const struct firmware *fw)
    234{
    235	int err;
    236
    237	switch (index) {
    238	case 0:
    239		/* xilinx boot */
    240		err = vx_check_magic(vx);
    241		if (err < 0)
    242			return err;
    243		err = snd_vx_load_boot_image(vx, fw);
    244		if (err < 0)
    245			return err;
    246		return 0;
    247	case 1:
    248		/* xilinx image */
    249		return vxp_load_xilinx_binary(vx, fw);
    250	case 2:
    251		/* DSP boot */
    252		return snd_vx_dsp_boot(vx, fw);
    253	case 3:
    254		/* DSP image */
    255		return snd_vx_dsp_load(vx, fw);
    256	default:
    257		snd_BUG();
    258		return -EINVAL;
    259	}
    260}
    261		
    262
    263/*
    264 * vx_test_and_ack - test and acknowledge interrupt
    265 *
    266 * called from irq hander, too
    267 *
    268 * spinlock held!
    269 */
    270static int vxp_test_and_ack(struct vx_core *_chip)
    271{
    272	struct snd_vxpocket *chip = to_vxpocket(_chip);
    273
    274	/* not booted yet? */
    275	if (! (_chip->chip_status & VX_STAT_XILINX_LOADED))
    276		return -ENXIO;
    277
    278	if (! (vx_inb(chip, DIALOG) & VXP_DLG_MEMIRQ_MASK))
    279		return -EIO;
    280	
    281	/* ok, interrupts generated, now ack it */
    282	/* set ACQUIT bit up and down */
    283	vx_outb(chip, DIALOG, chip->regDIALOG | VXP_DLG_ACK_MEMIRQ_MASK);
    284	/* useless read just to spend some time and maintain
    285	 * the ACQUIT signal up for a while ( a bus cycle )
    286	 */
    287	vx_inb(chip, DIALOG);
    288	vx_outb(chip, DIALOG, chip->regDIALOG & ~VXP_DLG_ACK_MEMIRQ_MASK);
    289
    290	return 0;
    291}
    292
    293
    294/*
    295 * vx_validate_irq - enable/disable IRQ
    296 */
    297static void vxp_validate_irq(struct vx_core *_chip, int enable)
    298{
    299	struct snd_vxpocket *chip = to_vxpocket(_chip);
    300
    301	/* Set the interrupt enable bit to 1 in CDSP register */
    302	if (enable)
    303		chip->regCDSP |= VXP_CDSP_VALID_IRQ_MASK;
    304	else
    305		chip->regCDSP &= ~VXP_CDSP_VALID_IRQ_MASK;
    306	vx_outb(chip, CDSP, chip->regCDSP);
    307}
    308
    309/*
    310 * vx_setup_pseudo_dma - set up the pseudo dma read/write mode.
    311 * @do_write: 0 = read, 1 = set up for DMA write
    312 */
    313static void vx_setup_pseudo_dma(struct vx_core *_chip, int do_write)
    314{
    315	struct snd_vxpocket *chip = to_vxpocket(_chip);
    316
    317	/* Interrupt mode and HREQ pin enabled for host transmit / receive data transfers */
    318	vx_outb(chip, ICR, do_write ? ICR_TREQ : ICR_RREQ);
    319	/* Reset the pseudo-dma register */
    320	vx_inb(chip, ISR);
    321	vx_outb(chip, ISR, 0);
    322
    323	/* Select DMA in read/write transfer mode and in 16-bit accesses */
    324	chip->regDIALOG |= VXP_DLG_DMA16_SEL_MASK;
    325	chip->regDIALOG |= do_write ? VXP_DLG_DMAWRITE_SEL_MASK : VXP_DLG_DMAREAD_SEL_MASK;
    326	vx_outb(chip, DIALOG, chip->regDIALOG);
    327
    328}
    329
    330/*
    331 * vx_release_pseudo_dma - disable the pseudo-DMA mode
    332 */
    333static void vx_release_pseudo_dma(struct vx_core *_chip)
    334{
    335	struct snd_vxpocket *chip = to_vxpocket(_chip);
    336
    337	/* Disable DMA and 16-bit accesses */
    338	chip->regDIALOG &= ~(VXP_DLG_DMAWRITE_SEL_MASK|
    339			     VXP_DLG_DMAREAD_SEL_MASK|
    340			     VXP_DLG_DMA16_SEL_MASK);
    341	vx_outb(chip, DIALOG, chip->regDIALOG);
    342	/* HREQ pin disabled. */
    343	vx_outb(chip, ICR, 0);
    344}
    345
    346/*
    347 * vx_pseudo_dma_write - write bulk data on pseudo-DMA mode
    348 * @count: data length to transfer in bytes
    349 *
    350 * data size must be aligned to 6 bytes to ensure the 24bit alignment on DSP.
    351 * NB: call with a certain lock!
    352 */
    353static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
    354			  struct vx_pipe *pipe, int count)
    355{
    356	long port = vxp_reg_addr(chip, VX_DMA);
    357	int offset = pipe->hw_ptr;
    358	unsigned short *addr = (unsigned short *)(runtime->dma_area + offset);
    359
    360	vx_setup_pseudo_dma(chip, 1);
    361	if (offset + count >= pipe->buffer_bytes) {
    362		int length = pipe->buffer_bytes - offset;
    363		count -= length;
    364		length >>= 1; /* in 16bit words */
    365		/* Transfer using pseudo-dma. */
    366		for (; length > 0; length--) {
    367			outw(*addr, port);
    368			addr++;
    369		}
    370		addr = (unsigned short *)runtime->dma_area;
    371		pipe->hw_ptr = 0;
    372	}
    373	pipe->hw_ptr += count;
    374	count >>= 1; /* in 16bit words */
    375	/* Transfer using pseudo-dma. */
    376	for (; count > 0; count--) {
    377		outw(*addr, port);
    378		addr++;
    379	}
    380	vx_release_pseudo_dma(chip);
    381}
    382
    383
    384/*
    385 * vx_pseudo_dma_read - read bulk data on pseudo DMA mode
    386 * @offset: buffer offset in bytes
    387 * @count: data length to transfer in bytes
    388 *
    389 * the read length must be aligned to 6 bytes, as well as write.
    390 * NB: call with a certain lock!
    391 */
    392static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
    393			 struct vx_pipe *pipe, int count)
    394{
    395	struct snd_vxpocket *pchip = to_vxpocket(chip);
    396	long port = vxp_reg_addr(chip, VX_DMA);
    397	int offset = pipe->hw_ptr;
    398	unsigned short *addr = (unsigned short *)(runtime->dma_area + offset);
    399
    400	if (snd_BUG_ON(count % 2))
    401		return;
    402	vx_setup_pseudo_dma(chip, 0);
    403	if (offset + count >= pipe->buffer_bytes) {
    404		int length = pipe->buffer_bytes - offset;
    405		count -= length;
    406		length >>= 1; /* in 16bit words */
    407		/* Transfer using pseudo-dma. */
    408		for (; length > 0; length--)
    409			*addr++ = inw(port);
    410		addr = (unsigned short *)runtime->dma_area;
    411		pipe->hw_ptr = 0;
    412	}
    413	pipe->hw_ptr += count;
    414	count >>= 1; /* in 16bit words */
    415	/* Transfer using pseudo-dma. */
    416	for (; count > 1; count--)
    417		*addr++ = inw(port);
    418	/* Disable DMA */
    419	pchip->regDIALOG &= ~VXP_DLG_DMAREAD_SEL_MASK;
    420	vx_outb(chip, DIALOG, pchip->regDIALOG);
    421	/* Read the last word (16 bits) */
    422	*addr = inw(port);
    423	/* Disable 16-bit accesses */
    424	pchip->regDIALOG &= ~VXP_DLG_DMA16_SEL_MASK;
    425	vx_outb(chip, DIALOG, pchip->regDIALOG);
    426	/* HREQ pin disabled. */
    427	vx_outb(chip, ICR, 0);
    428}
    429
    430
    431/*
    432 * write a codec data (24bit)
    433 */
    434static void vxp_write_codec_reg(struct vx_core *chip, int codec, unsigned int data)
    435{
    436	int i;
    437
    438	/* Activate access to the corresponding codec register */
    439	if (! codec)
    440		vx_inb(chip, LOFREQ);
    441	else
    442		vx_inb(chip, CODEC2);
    443		
    444	/* We have to send 24 bits (3 x 8 bits). Start with most signif. Bit */
    445	for (i = 0; i < 24; i++, data <<= 1)
    446		vx_outb(chip, DATA, ((data & 0x800000) ? VX_DATA_CODEC_MASK : 0));
    447	
    448	/* Terminate access to codec registers */
    449	vx_inb(chip, HIFREQ);
    450}
    451
    452
    453/*
    454 * vx_set_mic_boost - set mic boost level (on vxp440 only)
    455 * @boost: 0 = 20dB, 1 = +38dB
    456 */
    457void vx_set_mic_boost(struct vx_core *chip, int boost)
    458{
    459	struct snd_vxpocket *pchip = to_vxpocket(chip);
    460
    461	if (chip->chip_status & VX_STAT_IS_STALE)
    462		return;
    463
    464	mutex_lock(&chip->lock);
    465	if (pchip->regCDSP & P24_CDSP_MICS_SEL_MASK) {
    466		if (boost) {
    467			/* boost: 38 dB */
    468			pchip->regCDSP &= ~P24_CDSP_MIC20_SEL_MASK;
    469			pchip->regCDSP |=  P24_CDSP_MIC38_SEL_MASK;
    470		} else {
    471			/* minimum value: 20 dB */
    472			pchip->regCDSP |=  P24_CDSP_MIC20_SEL_MASK;
    473			pchip->regCDSP &= ~P24_CDSP_MIC38_SEL_MASK;
    474                }
    475		vx_outb(chip, CDSP, pchip->regCDSP);
    476	}
    477	mutex_unlock(&chip->lock);
    478}
    479
    480/*
    481 * remap the linear value (0-8) to the actual value (0-15)
    482 */
    483static int vx_compute_mic_level(int level)
    484{
    485	switch (level) {
    486	case 5: level = 6 ; break;
    487	case 6: level = 8 ; break;
    488	case 7: level = 11; break;
    489	case 8: level = 15; break;
    490	default: break ;
    491	}
    492	return level;
    493}
    494
    495/*
    496 * vx_set_mic_level - set mic level (on vxpocket only)
    497 * @level: the mic level = 0 - 8 (max)
    498 */
    499void vx_set_mic_level(struct vx_core *chip, int level)
    500{
    501	struct snd_vxpocket *pchip = to_vxpocket(chip);
    502
    503	if (chip->chip_status & VX_STAT_IS_STALE)
    504		return;
    505
    506	mutex_lock(&chip->lock);
    507	if (pchip->regCDSP & VXP_CDSP_MIC_SEL_MASK) {
    508		level = vx_compute_mic_level(level);
    509		vx_outb(chip, MICRO, level);
    510	}
    511	mutex_unlock(&chip->lock);
    512}
    513
    514
    515/*
    516 * change the input audio source
    517 */
    518static void vxp_change_audio_source(struct vx_core *_chip, int src)
    519{
    520	struct snd_vxpocket *chip = to_vxpocket(_chip);
    521
    522	switch (src) {
    523	case VX_AUDIO_SRC_DIGITAL:
    524		chip->regCDSP |= VXP_CDSP_DATAIN_SEL_MASK;
    525		vx_outb(chip, CDSP, chip->regCDSP);
    526		break;
    527	case VX_AUDIO_SRC_LINE:
    528		chip->regCDSP &= ~VXP_CDSP_DATAIN_SEL_MASK;
    529		if (_chip->type == VX_TYPE_VXP440)
    530			chip->regCDSP &= ~P24_CDSP_MICS_SEL_MASK;
    531		else
    532			chip->regCDSP &= ~VXP_CDSP_MIC_SEL_MASK;
    533		vx_outb(chip, CDSP, chip->regCDSP);
    534		break;
    535	case VX_AUDIO_SRC_MIC:
    536		chip->regCDSP &= ~VXP_CDSP_DATAIN_SEL_MASK;
    537		/* reset mic levels */
    538		if (_chip->type == VX_TYPE_VXP440) {
    539			chip->regCDSP &= ~P24_CDSP_MICS_SEL_MASK;
    540			if (chip->mic_level)
    541				chip->regCDSP |=  P24_CDSP_MIC38_SEL_MASK;
    542			else
    543				chip->regCDSP |= P24_CDSP_MIC20_SEL_MASK;
    544			vx_outb(chip, CDSP, chip->regCDSP);
    545		} else {
    546			chip->regCDSP |= VXP_CDSP_MIC_SEL_MASK;
    547			vx_outb(chip, CDSP, chip->regCDSP);
    548			vx_outb(chip, MICRO, vx_compute_mic_level(chip->mic_level));
    549		}
    550		break;
    551	}
    552}
    553
    554/*
    555 * change the clock source
    556 * source = INTERNAL_QUARTZ or UER_SYNC
    557 */
    558static void vxp_set_clock_source(struct vx_core *_chip, int source)
    559{
    560	struct snd_vxpocket *chip = to_vxpocket(_chip);
    561
    562	if (source == INTERNAL_QUARTZ)
    563		chip->regCDSP &= ~VXP_CDSP_CLOCKIN_SEL_MASK;
    564	else
    565		chip->regCDSP |= VXP_CDSP_CLOCKIN_SEL_MASK;
    566	vx_outb(chip, CDSP, chip->regCDSP);
    567}
    568
    569
    570/*
    571 * reset the board
    572 */
    573static void vxp_reset_board(struct vx_core *_chip, int cold_reset)
    574{
    575	struct snd_vxpocket *chip = to_vxpocket(_chip);
    576
    577	chip->regCDSP = 0;
    578	chip->regDIALOG = 0;
    579}
    580
    581
    582/*
    583 * callbacks
    584 */
    585/* exported */
    586const struct snd_vx_ops snd_vxpocket_ops = {
    587	.in8 = vxp_inb,
    588	.out8 = vxp_outb,
    589	.test_and_ack = vxp_test_and_ack,
    590	.validate_irq = vxp_validate_irq,
    591	.write_codec = vxp_write_codec_reg,
    592	.reset_codec = vxp_reset_codec,
    593	.change_audio_source = vxp_change_audio_source,
    594	.set_clock_source = vxp_set_clock_source,
    595	.load_dsp = vxp_load_dsp,
    596	.add_controls = vxp_add_mic_controls,
    597	.reset_dsp = vxp_reset_dsp,
    598	.reset_board = vxp_reset_board,
    599	.dma_write = vxp_dma_write,
    600	.dma_read = vxp_dma_read,
    601};