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

vx_uer.c (6954B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Driver for Digigram VX soundcards
      4 *
      5 * IEC958 stuff
      6 *
      7 * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
      8 */
      9
     10#include <linux/delay.h>
     11#include <sound/core.h>
     12#include <sound/vx_core.h>
     13#include "vx_cmd.h"
     14
     15
     16/*
     17 * vx_modify_board_clock - tell the board that its clock has been modified
     18 * @sync: DSP needs to resynchronize its FIFO
     19 */
     20static int vx_modify_board_clock(struct vx_core *chip, int sync)
     21{
     22	struct vx_rmh rmh;
     23
     24	vx_init_rmh(&rmh, CMD_MODIFY_CLOCK);
     25	/* Ask the DSP to resynchronize its FIFO. */
     26	if (sync)
     27		rmh.Cmd[0] |= CMD_MODIFY_CLOCK_S_BIT;
     28	return vx_send_msg(chip, &rmh);
     29}
     30
     31/*
     32 * vx_modify_board_inputs - resync audio inputs
     33 */
     34static int vx_modify_board_inputs(struct vx_core *chip)
     35{
     36	struct vx_rmh rmh;
     37
     38	vx_init_rmh(&rmh, CMD_RESYNC_AUDIO_INPUTS);
     39        rmh.Cmd[0] |= 1 << 0; /* reference: AUDIO 0 */
     40	return vx_send_msg(chip, &rmh);
     41}
     42
     43/*
     44 * vx_read_one_cbit - read one bit from UER config
     45 * @index: the bit index
     46 * returns 0 or 1.
     47 */
     48static int vx_read_one_cbit(struct vx_core *chip, int index)
     49{
     50	int val;
     51
     52	mutex_lock(&chip->lock);
     53	if (chip->type >= VX_TYPE_VXPOCKET) {
     54		vx_outb(chip, CSUER, 1); /* read */
     55		vx_outb(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK);
     56		val = (vx_inb(chip, RUER) >> 7) & 0x01;
     57	} else {
     58		vx_outl(chip, CSUER, 1); /* read */
     59		vx_outl(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK);
     60		val = (vx_inl(chip, RUER) >> 7) & 0x01;
     61	}
     62	mutex_unlock(&chip->lock);
     63	return val;
     64}
     65
     66/*
     67 * vx_write_one_cbit - write one bit to UER config
     68 * @index: the bit index
     69 * @val: bit value, 0 or 1
     70 */
     71static void vx_write_one_cbit(struct vx_core *chip, int index, int val)
     72{
     73	val = !!val;	/* 0 or 1 */
     74	mutex_lock(&chip->lock);
     75	if (vx_is_pcmcia(chip)) {
     76		vx_outb(chip, CSUER, 0); /* write */
     77		vx_outb(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK));
     78	} else {
     79		vx_outl(chip, CSUER, 0); /* write */
     80		vx_outl(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK));
     81	}
     82	mutex_unlock(&chip->lock);
     83}
     84
     85/*
     86 * vx_read_uer_status - read the current UER status
     87 * @mode: pointer to store the UER mode, VX_UER_MODE_XXX
     88 *
     89 * returns the frequency of UER, or 0 if not sync,
     90 * or a negative error code.
     91 */
     92static int vx_read_uer_status(struct vx_core *chip, unsigned int *mode)
     93{
     94	int val, freq;
     95
     96	/* Default values */
     97	freq = 0;
     98
     99	/* Read UER status */
    100	if (vx_is_pcmcia(chip))
    101	    val = vx_inb(chip, CSUER);
    102	else
    103	    val = vx_inl(chip, CSUER);
    104	if (val < 0)
    105		return val;
    106	/* If clock is present, read frequency */
    107	if (val & VX_SUER_CLOCK_PRESENT_MASK) {
    108		switch (val & VX_SUER_FREQ_MASK) {
    109		case VX_SUER_FREQ_32KHz_MASK:
    110			freq = 32000;
    111			break;
    112		case VX_SUER_FREQ_44KHz_MASK:
    113			freq = 44100;
    114			break;
    115		case VX_SUER_FREQ_48KHz_MASK:
    116			freq = 48000;
    117			break;
    118		}
    119        }
    120	if (val & VX_SUER_DATA_PRESENT_MASK)
    121		/* bit 0 corresponds to consumer/professional bit */
    122		*mode = vx_read_one_cbit(chip, 0) ?
    123			VX_UER_MODE_PROFESSIONAL : VX_UER_MODE_CONSUMER;
    124	else
    125		*mode = VX_UER_MODE_NOT_PRESENT;
    126
    127	return freq;
    128}
    129
    130
    131/*
    132 * compute the sample clock value from frequency
    133 *
    134 * The formula is as follows:
    135 *
    136 *    HexFreq = (dword) ((double) ((double) 28224000 / (double) Frequency))
    137 *    switch ( HexFreq & 0x00000F00 )
    138 *    case 0x00000100: ;
    139 *    case 0x00000200:
    140 *    case 0x00000300: HexFreq -= 0x00000201 ;
    141 *    case 0x00000400:
    142 *    case 0x00000500:
    143 *    case 0x00000600:
    144 *    case 0x00000700: HexFreq = (dword) (((double) 28224000 / (double) (Frequency*2)) - 1)
    145 *    default        : HexFreq = (dword) ((double) 28224000 / (double) (Frequency*4)) - 0x000001FF
    146 */
    147
    148static int vx_calc_clock_from_freq(struct vx_core *chip, int freq)
    149{
    150	int hexfreq;
    151
    152	if (snd_BUG_ON(freq <= 0))
    153		return 0;
    154
    155	hexfreq = (28224000 * 10) / freq;
    156	hexfreq = (hexfreq + 5) / 10;
    157
    158	/* max freq = 55125 Hz */
    159	if (snd_BUG_ON(hexfreq <= 0x00000200))
    160		return 0;
    161
    162	if (hexfreq <= 0x03ff)
    163		return hexfreq - 0x00000201;
    164	if (hexfreq <= 0x07ff) 
    165		return (hexfreq / 2) - 1;
    166	if (hexfreq <= 0x0fff)
    167		return (hexfreq / 4) + 0x000001ff;
    168
    169	return 0x5fe; 	/* min freq = 6893 Hz */
    170}
    171
    172
    173/*
    174 * vx_change_clock_source - change the clock source
    175 * @source: the new source
    176 */
    177static void vx_change_clock_source(struct vx_core *chip, int source)
    178{
    179	/* we mute DAC to prevent clicks */
    180	vx_toggle_dac_mute(chip, 1);
    181	mutex_lock(&chip->lock);
    182	chip->ops->set_clock_source(chip, source);
    183	chip->clock_source = source;
    184	mutex_unlock(&chip->lock);
    185	/* unmute */
    186	vx_toggle_dac_mute(chip, 0);
    187}
    188
    189
    190/*
    191 * set the internal clock
    192 */
    193void vx_set_internal_clock(struct vx_core *chip, unsigned int freq)
    194{
    195	int clock;
    196
    197	/* Get real clock value */
    198	clock = vx_calc_clock_from_freq(chip, freq);
    199	snd_printdd(KERN_DEBUG "set internal clock to 0x%x from freq %d\n", clock, freq);
    200	mutex_lock(&chip->lock);
    201	if (vx_is_pcmcia(chip)) {
    202		vx_outb(chip, HIFREQ, (clock >> 8) & 0x0f);
    203		vx_outb(chip, LOFREQ, clock & 0xff);
    204	} else {
    205		vx_outl(chip, HIFREQ, (clock >> 8) & 0x0f);
    206		vx_outl(chip, LOFREQ, clock & 0xff);
    207	}
    208	mutex_unlock(&chip->lock);
    209}
    210
    211
    212/*
    213 * set the iec958 status bits
    214 * @bits: 32-bit status bits
    215 */
    216void vx_set_iec958_status(struct vx_core *chip, unsigned int bits)
    217{
    218	int i;
    219
    220	if (chip->chip_status & VX_STAT_IS_STALE)
    221		return;
    222
    223	for (i = 0; i < 32; i++)
    224		vx_write_one_cbit(chip, i, bits & (1 << i));
    225}
    226
    227
    228/*
    229 * vx_set_clock - change the clock and audio source if necessary
    230 */
    231int vx_set_clock(struct vx_core *chip, unsigned int freq)
    232{
    233	int src_changed = 0;
    234
    235	if (chip->chip_status & VX_STAT_IS_STALE)
    236		return 0;
    237
    238	/* change the audio source if possible */
    239	vx_sync_audio_source(chip);
    240
    241	if (chip->clock_mode == VX_CLOCK_MODE_EXTERNAL ||
    242	    (chip->clock_mode == VX_CLOCK_MODE_AUTO &&
    243	     chip->audio_source == VX_AUDIO_SRC_DIGITAL)) {
    244		if (chip->clock_source != UER_SYNC) {
    245			vx_change_clock_source(chip, UER_SYNC);
    246			mdelay(6);
    247			src_changed = 1;
    248		}
    249	} else if (chip->clock_mode == VX_CLOCK_MODE_INTERNAL ||
    250		   (chip->clock_mode == VX_CLOCK_MODE_AUTO &&
    251		    chip->audio_source != VX_AUDIO_SRC_DIGITAL)) {
    252		if (chip->clock_source != INTERNAL_QUARTZ) {
    253			vx_change_clock_source(chip, INTERNAL_QUARTZ);
    254			src_changed = 1;
    255		}
    256		if (chip->freq == freq)
    257			return 0;
    258		vx_set_internal_clock(chip, freq);
    259		if (src_changed)
    260			vx_modify_board_inputs(chip);
    261	}
    262	if (chip->freq == freq)
    263		return 0;
    264	chip->freq = freq;
    265	vx_modify_board_clock(chip, 1);
    266	return 0;
    267}
    268
    269
    270/*
    271 * vx_change_frequency - called from interrupt handler
    272 */
    273int vx_change_frequency(struct vx_core *chip)
    274{
    275	int freq;
    276
    277	if (chip->chip_status & VX_STAT_IS_STALE)
    278		return 0;
    279
    280	if (chip->clock_source == INTERNAL_QUARTZ)
    281		return 0;
    282	/*
    283	 * Read the real UER board frequency
    284	 */
    285	freq = vx_read_uer_status(chip, &chip->uer_detected);
    286	if (freq < 0)
    287		return freq;
    288	/*
    289	 * The frequency computed by the DSP is good and
    290	 * is different from the previous computed.
    291	 */
    292	if (freq == 48000 || freq == 44100 || freq == 32000)
    293		chip->freq_detected = freq;
    294
    295	return 0;
    296}