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

lola_clock.c (7539B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Support for Digigram Lola PCI-e boards
      4 *
      5 *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
      6 */
      7
      8#include <linux/kernel.h>
      9#include <linux/init.h>
     10#include <linux/delay.h>
     11#include <sound/core.h>
     12#include <sound/pcm.h>
     13#include "lola.h"
     14
     15unsigned int lola_sample_rate_convert(unsigned int coded)
     16{
     17	unsigned int freq;
     18
     19	/* base frequency */
     20	switch (coded & 0x3) {
     21	case 0:     freq = 48000; break;
     22	case 1:     freq = 44100; break;
     23	case 2:     freq = 32000; break;
     24	default:    return 0;   /* error */
     25	}
     26
     27	/* multiplier / devisor */
     28	switch (coded & 0x1c) {
     29	case (0 << 2):    break;
     30	case (4 << 2):    break;
     31	case (1 << 2):    freq *= 2; break;
     32	case (2 << 2):    freq *= 4; break;
     33	case (5 << 2):    freq /= 2; break;
     34	case (6 << 2):    freq /= 4; break;
     35	default:        return 0;   /* error */
     36	}
     37
     38	/* ajustement */
     39	switch (coded & 0x60) {
     40	case (0 << 5):    break;
     41	case (1 << 5):    freq = (freq * 999) / 1000; break;
     42	case (2 << 5):    freq = (freq * 1001) / 1000; break;
     43	default:        return 0;   /* error */
     44	}
     45	return freq;
     46}
     47
     48/*
     49 * Granualrity
     50 */
     51
     52#define LOLA_MAXFREQ_AT_GRANULARITY_MIN         48000
     53#define LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX   96000
     54
     55static bool check_gran_clock_compatibility(struct lola *chip,
     56					   unsigned int val,
     57					   unsigned int freq)
     58{
     59	if (!chip->granularity)
     60		return true;
     61
     62	if (val < LOLA_GRANULARITY_MIN || val > LOLA_GRANULARITY_MAX ||
     63	    (val % LOLA_GRANULARITY_STEP) != 0)
     64		return false;
     65
     66	if (val == LOLA_GRANULARITY_MIN) {
     67		if (freq > LOLA_MAXFREQ_AT_GRANULARITY_MIN)
     68			return false;
     69	} else if (val < LOLA_GRANULARITY_MAX) {
     70		if (freq > LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX)
     71			return false;
     72	}
     73	return true;
     74}
     75
     76int lola_set_granularity(struct lola *chip, unsigned int val, bool force)
     77{
     78	int err;
     79
     80	if (!force) {
     81		if (val == chip->granularity)
     82			return 0;
     83#if 0
     84		/* change Gran only if there are no streams allocated ! */
     85		if (chip->audio_in_alloc_mask || chip->audio_out_alloc_mask)
     86			return -EBUSY;
     87#endif
     88		if (!check_gran_clock_compatibility(chip, val,
     89						    chip->clock.cur_freq))
     90			return -EINVAL;
     91	}
     92
     93	chip->granularity = val;
     94	val /= LOLA_GRANULARITY_STEP;
     95
     96	/* audio function group */
     97	err = lola_codec_write(chip, 1, LOLA_VERB_SET_GRANULARITY_STEPS,
     98			       val, 0);
     99	if (err < 0)
    100		return err;
    101	/* this can be a very slow function !!! */
    102	usleep_range(400 * val, 20000);
    103	return lola_codec_flush(chip);
    104}
    105
    106/*
    107 * Clock widget handling
    108 */
    109
    110int lola_init_clock_widget(struct lola *chip, int nid)
    111{
    112	unsigned int val;
    113	int i, j, nitems, nb_verbs, idx, idx_list;
    114	int err;
    115
    116	err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
    117	if (err < 0) {
    118		dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
    119		return err;
    120	}
    121
    122	if ((val & 0xfff00000) != 0x01f00000) { /* test SubType and Type */
    123		dev_dbg(chip->card->dev, "No valid clock widget\n");
    124		return 0;
    125	}
    126
    127	chip->clock.nid = nid;
    128	chip->clock.items = val & 0xff;
    129	dev_dbg(chip->card->dev, "clock_list nid=%x, entries=%d\n", nid,
    130		    chip->clock.items);
    131	if (chip->clock.items > MAX_SAMPLE_CLOCK_COUNT) {
    132		dev_err(chip->card->dev, "CLOCK_LIST too big: %d\n",
    133		       chip->clock.items);
    134		return -EINVAL;
    135	}
    136
    137	nitems = chip->clock.items;
    138	nb_verbs = DIV_ROUND_UP(nitems, 4);
    139	idx = 0;
    140	idx_list = 0;
    141	for (i = 0; i < nb_verbs; i++) {
    142		unsigned int res_ex;
    143		unsigned short items[4];
    144
    145		err = lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST,
    146				      idx, 0, &val, &res_ex);
    147		if (err < 0) {
    148			dev_err(chip->card->dev, "Can't read CLOCK_LIST\n");
    149			return -EINVAL;
    150		}
    151
    152		items[0] = val & 0xfff;
    153		items[1] = (val >> 16) & 0xfff;
    154		items[2] = res_ex & 0xfff;
    155		items[3] = (res_ex >> 16) & 0xfff;
    156
    157		for (j = 0; j < 4; j++) {
    158			unsigned char type = items[j] >> 8;
    159			unsigned int freq = items[j] & 0xff;
    160			int format = LOLA_CLOCK_FORMAT_NONE;
    161			bool add_clock = true;
    162			if (type == LOLA_CLOCK_TYPE_INTERNAL) {
    163				freq = lola_sample_rate_convert(freq);
    164				if (freq < chip->sample_rate_min)
    165					add_clock = false;
    166				else if (freq == 48000) {
    167					chip->clock.cur_index = idx_list;
    168					chip->clock.cur_freq = 48000;
    169					chip->clock.cur_valid = true;
    170				}
    171			} else if (type == LOLA_CLOCK_TYPE_VIDEO) {
    172				freq = lola_sample_rate_convert(freq);
    173				if (freq < chip->sample_rate_min)
    174					add_clock = false;
    175				/* video clock has a format (0:NTSC, 1:PAL)*/
    176				if (items[j] & 0x80)
    177					format = LOLA_CLOCK_FORMAT_NTSC;
    178				else
    179					format = LOLA_CLOCK_FORMAT_PAL;
    180			}
    181			if (add_clock) {
    182				struct lola_sample_clock *sc;
    183				sc = &chip->clock.sample_clock[idx_list];
    184				sc->type = type;
    185				sc->format = format;
    186				sc->freq = freq;
    187				/* keep the index used with the board */
    188				chip->clock.idx_lookup[idx_list] = idx;
    189				idx_list++;
    190			} else {
    191				chip->clock.items--;
    192			}
    193			if (++idx >= nitems)
    194				break;
    195		}
    196	}
    197	return 0;
    198}
    199
    200/* enable unsolicited events of the clock widget */
    201int lola_enable_clock_events(struct lola *chip)
    202{
    203	unsigned int res;
    204	int err;
    205
    206	err = lola_codec_read(chip, chip->clock.nid,
    207			      LOLA_VERB_SET_UNSOLICITED_ENABLE,
    208			      LOLA_UNSOLICITED_ENABLE | LOLA_UNSOLICITED_TAG,
    209			      0, &res, NULL);
    210	if (err < 0)
    211		return err;
    212	if (res) {
    213		dev_warn(chip->card->dev, "error in enable_clock_events %d\n",
    214		       res);
    215		return -EINVAL;
    216	}
    217	return 0;
    218}
    219
    220int lola_set_clock_index(struct lola *chip, unsigned int idx)
    221{
    222	unsigned int res;
    223	int err;
    224
    225	err = lola_codec_read(chip, chip->clock.nid,
    226			      LOLA_VERB_SET_CLOCK_SELECT,
    227			      chip->clock.idx_lookup[idx],
    228			      0, &res, NULL);
    229	if (err < 0)
    230		return err;
    231	if (res) {
    232		dev_warn(chip->card->dev, "error in set_clock %d\n", res);
    233		return -EINVAL;
    234	}
    235	return 0;
    236}
    237
    238bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val)
    239{
    240	unsigned int tag;
    241
    242	/* the current EXTERNAL clock information gets updated by interrupt
    243	 * with an unsolicited response
    244	 */
    245	if (!val)
    246		return false;
    247	tag = (val >> LOLA_UNSOL_RESP_TAG_OFFSET) & LOLA_UNSOLICITED_TAG_MASK;
    248	if (tag != LOLA_UNSOLICITED_TAG)
    249		return false;
    250
    251	/* only for current = external clocks */
    252	if (chip->clock.sample_clock[chip->clock.cur_index].type !=
    253	    LOLA_CLOCK_TYPE_INTERNAL) {
    254		chip->clock.cur_freq = lola_sample_rate_convert(val & 0x7f);
    255		chip->clock.cur_valid = (val & 0x100) != 0;
    256	}
    257	return true;
    258}
    259
    260int lola_set_clock(struct lola *chip, int idx)
    261{
    262	int freq = 0;
    263	bool valid = false;
    264
    265	if (idx == chip->clock.cur_index) {
    266		/* current clock is allowed */
    267		freq = chip->clock.cur_freq;
    268		valid = chip->clock.cur_valid;
    269	} else if (chip->clock.sample_clock[idx].type ==
    270		   LOLA_CLOCK_TYPE_INTERNAL) {
    271		/* internal clocks allowed */
    272		freq = chip->clock.sample_clock[idx].freq;
    273		valid = true;
    274	}
    275
    276	if (!freq || !valid)
    277		return -EINVAL;
    278
    279	if (!check_gran_clock_compatibility(chip, chip->granularity, freq))
    280		return -EINVAL;
    281
    282	if (idx != chip->clock.cur_index) {
    283		int err = lola_set_clock_index(chip, idx);
    284		if (err < 0)
    285			return err;
    286		/* update new settings */
    287		chip->clock.cur_index = idx;
    288		chip->clock.cur_freq = freq;
    289		chip->clock.cur_valid = true;
    290	}
    291	return 0;
    292}
    293
    294int lola_set_sample_rate(struct lola *chip, int rate)
    295{
    296	int i;
    297
    298	if (chip->clock.cur_freq == rate && chip->clock.cur_valid)
    299		return 0;
    300	/* search for new dwClockIndex */
    301	for (i = 0; i < chip->clock.items; i++) {
    302		if (chip->clock.sample_clock[i].type == LOLA_CLOCK_TYPE_INTERNAL &&
    303		    chip->clock.sample_clock[i].freq == rate)
    304			break;
    305	}
    306	if (i >= chip->clock.items)
    307		return -EINVAL;
    308	return lola_set_clock(chip, i);
    309}
    310