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

motu-protocol-v2.c (8541B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * motu-protocol-v2.c - a part of driver for MOTU FireWire series
      4 *
      5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
      6 */
      7
      8#include "motu.h"
      9
     10#define V2_CLOCK_STATUS_OFFSET			0x0b14
     11#define  V2_CLOCK_RATE_MASK			0x00000038
     12#define  V2_CLOCK_RATE_SHIFT			3
     13#define  V2_CLOCK_SRC_MASK			0x00000007
     14#define  V2_CLOCK_SRC_SHIFT			0
     15#define   V2_CLOCK_SRC_AESEBU_ON_XLR		0x07	// In Traveler.
     16#define   V2_CLOCK_SRC_ADAT_ON_DSUB		0x05
     17#define   V2_CLOCK_SRC_WORD_ON_BNC		0x04
     18#define   V2_CLOCK_SRC_SPH			0x03
     19#define   V2_CLOCK_SRC_SPDIF			0x02	// on either coaxial or optical. AES/EBU in 896HD.
     20#define   V2_CLOCK_SRC_ADAT_ON_OPT		0x01
     21#define   V2_CLOCK_SRC_INTERNAL			0x00
     22#define  V2_CLOCK_FETCH_ENABLE			0x02000000
     23#define  V2_CLOCK_MODEL_SPECIFIC		0x04000000
     24
     25#define V2_IN_OUT_CONF_OFFSET			0x0c04
     26#define  V2_OPT_OUT_IFACE_MASK			0x00000c00
     27#define  V2_OPT_OUT_IFACE_SHIFT			10
     28#define  V2_OPT_IN_IFACE_MASK			0x00000300
     29#define  V2_OPT_IN_IFACE_SHIFT			8
     30#define  V2_OPT_IFACE_MODE_NONE			0
     31#define  V2_OPT_IFACE_MODE_ADAT			1
     32#define  V2_OPT_IFACE_MODE_SPDIF		2
     33
     34static int get_clock_rate(u32 data, unsigned int *rate)
     35{
     36	unsigned int index = (data & V2_CLOCK_RATE_MASK) >> V2_CLOCK_RATE_SHIFT;
     37	if (index >= ARRAY_SIZE(snd_motu_clock_rates))
     38		return -EIO;
     39
     40	*rate = snd_motu_clock_rates[index];
     41
     42	return 0;
     43}
     44
     45int snd_motu_protocol_v2_get_clock_rate(struct snd_motu *motu,
     46					unsigned int *rate)
     47{
     48	__be32 reg;
     49	int err;
     50
     51	err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
     52					sizeof(reg));
     53	if (err < 0)
     54		return err;
     55
     56	return get_clock_rate(be32_to_cpu(reg), rate);
     57}
     58
     59int snd_motu_protocol_v2_set_clock_rate(struct snd_motu *motu,
     60					unsigned int rate)
     61{
     62	__be32 reg;
     63	u32 data;
     64	int i;
     65	int err;
     66
     67	for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
     68		if (snd_motu_clock_rates[i] == rate)
     69			break;
     70	}
     71	if (i == ARRAY_SIZE(snd_motu_clock_rates))
     72		return -EINVAL;
     73
     74	err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
     75					sizeof(reg));
     76	if (err < 0)
     77		return err;
     78	data = be32_to_cpu(reg);
     79
     80	data &= ~V2_CLOCK_RATE_MASK;
     81	data |= i << V2_CLOCK_RATE_SHIFT;
     82
     83	reg = cpu_to_be32(data);
     84	return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, &reg,
     85					  sizeof(reg));
     86}
     87
     88static int get_clock_source(struct snd_motu *motu, u32 data,
     89			    enum snd_motu_clock_source *src)
     90{
     91	switch (data & V2_CLOCK_SRC_MASK) {
     92	case V2_CLOCK_SRC_INTERNAL:
     93		*src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
     94		break;
     95	case V2_CLOCK_SRC_ADAT_ON_OPT:
     96		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
     97		break;
     98	case V2_CLOCK_SRC_SPDIF:
     99	{
    100		bool support_iec60958_on_opt = (motu->spec == &snd_motu_spec_828mk2 ||
    101						motu->spec == &snd_motu_spec_traveler);
    102
    103		if (motu->spec == &snd_motu_spec_896hd) {
    104			*src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR;
    105		} else if (!support_iec60958_on_opt) {
    106			*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
    107		} else {
    108			__be32 reg;
    109
    110			// To check the configuration of optical interface.
    111			int err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,
    112							    sizeof(reg));
    113			if (err < 0)
    114				return err;
    115
    116			if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) ==
    117			    V2_OPT_IFACE_MODE_SPDIF)
    118				*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;
    119			else
    120				*src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
    121		}
    122		break;
    123	}
    124	case V2_CLOCK_SRC_SPH:
    125		*src = SND_MOTU_CLOCK_SOURCE_SPH;
    126		break;
    127	case V2_CLOCK_SRC_WORD_ON_BNC:
    128		*src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
    129		break;
    130	case V2_CLOCK_SRC_ADAT_ON_DSUB:
    131		*src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
    132		break;
    133	case V2_CLOCK_SRC_AESEBU_ON_XLR:
    134		// For Traveler.
    135		*src = SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR;
    136		break;
    137	default:
    138		*src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
    139		break;
    140	}
    141
    142	return 0;
    143}
    144
    145int snd_motu_protocol_v2_get_clock_source(struct snd_motu *motu,
    146					  enum snd_motu_clock_source *src)
    147{
    148	__be32 reg;
    149	int err;
    150
    151	err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
    152					sizeof(reg));
    153	if (err < 0)
    154		return err;
    155
    156	return get_clock_source(motu, be32_to_cpu(reg), src);
    157}
    158
    159// Expected for Traveler, which implements Altera Cyclone EP1C3.
    160static int switch_fetching_mode_cyclone(struct snd_motu *motu, u32 *data,
    161					bool enable)
    162{
    163	*data |= V2_CLOCK_MODEL_SPECIFIC;
    164
    165	return 0;
    166}
    167
    168// For UltraLite and 8pre, which implements Xilinx Spartan XC3S200.
    169static int switch_fetching_mode_spartan(struct snd_motu *motu, u32 *data,
    170					bool enable)
    171{
    172	unsigned int rate;
    173	enum snd_motu_clock_source src;
    174	int err;
    175
    176	err = get_clock_source(motu, *data, &src);
    177	if (err < 0)
    178		return err;
    179
    180	err = get_clock_rate(*data, &rate);
    181	if (err < 0)
    182		return err;
    183
    184	if (src == SND_MOTU_CLOCK_SOURCE_SPH && rate > 48000)
    185		*data |= V2_CLOCK_MODEL_SPECIFIC;
    186
    187	return 0;
    188}
    189
    190int snd_motu_protocol_v2_switch_fetching_mode(struct snd_motu *motu,
    191					      bool enable)
    192{
    193	if (motu->spec == &snd_motu_spec_828mk2) {
    194		// 828mkII implements Altera ACEX 1K EP1K30. Nothing to do.
    195		return 0;
    196	} else if (motu->spec == &snd_motu_spec_896hd) {
    197		// 896HD implements Altera Cyclone EP1C3 but nothing to do.
    198		return 0;
    199	} else {
    200		__be32 reg;
    201		u32 data;
    202		int err;
    203
    204		err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET,
    205						&reg, sizeof(reg));
    206		if (err < 0)
    207			return err;
    208		data = be32_to_cpu(reg);
    209
    210		data &= ~(V2_CLOCK_FETCH_ENABLE | V2_CLOCK_MODEL_SPECIFIC);
    211		if (enable)
    212			data |= V2_CLOCK_FETCH_ENABLE;
    213
    214		if (motu->spec == &snd_motu_spec_traveler)
    215			err = switch_fetching_mode_cyclone(motu, &data, enable);
    216		else
    217			err = switch_fetching_mode_spartan(motu, &data, enable);
    218		if (err < 0)
    219			return err;
    220
    221		reg = cpu_to_be32(data);
    222		return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET,
    223						  &reg, sizeof(reg));
    224	}
    225}
    226
    227int snd_motu_protocol_v2_cache_packet_formats(struct snd_motu *motu)
    228{
    229	bool has_two_opt_ifaces = (motu->spec == &snd_motu_spec_8pre);
    230	__be32 reg;
    231	u32 data;
    232	int err;
    233
    234	motu->tx_packet_formats.pcm_byte_offset = 10;
    235	motu->rx_packet_formats.pcm_byte_offset = 10;
    236
    237	motu->tx_packet_formats.msg_chunks = 2;
    238	motu->rx_packet_formats.msg_chunks = 2;
    239
    240	err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,
    241					sizeof(reg));
    242	if (err < 0)
    243		return err;
    244	data = be32_to_cpu(reg);
    245
    246	memcpy(motu->tx_packet_formats.pcm_chunks,
    247	       motu->spec->tx_fixed_pcm_chunks,
    248	       sizeof(motu->tx_packet_formats.pcm_chunks));
    249	memcpy(motu->rx_packet_formats.pcm_chunks,
    250	       motu->spec->rx_fixed_pcm_chunks,
    251	       sizeof(motu->rx_packet_formats.pcm_chunks));
    252
    253	if (((data & V2_OPT_IN_IFACE_MASK) >> V2_OPT_IN_IFACE_SHIFT) == V2_OPT_IFACE_MODE_ADAT) {
    254		motu->tx_packet_formats.pcm_chunks[0] += 8;
    255
    256		if (!has_two_opt_ifaces)
    257			motu->tx_packet_formats.pcm_chunks[1] += 4;
    258		else
    259			motu->tx_packet_formats.pcm_chunks[1] += 8;
    260	}
    261
    262	if (((data & V2_OPT_OUT_IFACE_MASK) >> V2_OPT_OUT_IFACE_SHIFT) == V2_OPT_IFACE_MODE_ADAT) {
    263		motu->rx_packet_formats.pcm_chunks[0] += 8;
    264
    265		if (!has_two_opt_ifaces)
    266			motu->rx_packet_formats.pcm_chunks[1] += 4;
    267		else
    268			motu->rx_packet_formats.pcm_chunks[1] += 8;
    269	}
    270
    271	return 0;
    272}
    273
    274const struct snd_motu_spec snd_motu_spec_828mk2 = {
    275	.name = "828mk2",
    276	.protocol_version = SND_MOTU_PROTOCOL_V2,
    277	.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
    278		 SND_MOTU_SPEC_TX_MIDI_2ND_Q |
    279		 SND_MOTU_SPEC_REGISTER_DSP,
    280	.tx_fixed_pcm_chunks = {14, 14, 0},
    281	.rx_fixed_pcm_chunks = {14, 14, 0},
    282};
    283
    284const struct snd_motu_spec snd_motu_spec_896hd = {
    285	.name = "896HD",
    286	.protocol_version = SND_MOTU_PROTOCOL_V2,
    287	.flags = SND_MOTU_SPEC_REGISTER_DSP,
    288	.tx_fixed_pcm_chunks = {14, 14, 8},
    289	.rx_fixed_pcm_chunks = {14, 14, 8},
    290};
    291
    292const struct snd_motu_spec snd_motu_spec_traveler = {
    293	.name = "Traveler",
    294	.protocol_version = SND_MOTU_PROTOCOL_V2,
    295	.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
    296		 SND_MOTU_SPEC_TX_MIDI_2ND_Q |
    297		 SND_MOTU_SPEC_REGISTER_DSP,
    298	.tx_fixed_pcm_chunks = {14, 14, 8},
    299	.rx_fixed_pcm_chunks = {14, 14, 8},
    300};
    301
    302const struct snd_motu_spec snd_motu_spec_ultralite = {
    303	.name = "UltraLite",
    304	.protocol_version = SND_MOTU_PROTOCOL_V2,
    305	.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
    306		 SND_MOTU_SPEC_TX_MIDI_2ND_Q |
    307		 SND_MOTU_SPEC_REGISTER_DSP,
    308	.tx_fixed_pcm_chunks = {14, 14, 0},
    309	.rx_fixed_pcm_chunks = {14, 14, 0},
    310};
    311
    312const struct snd_motu_spec snd_motu_spec_8pre = {
    313	.name = "8pre",
    314	.protocol_version = SND_MOTU_PROTOCOL_V2,
    315	.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
    316		 SND_MOTU_SPEC_TX_MIDI_2ND_Q |
    317		 SND_MOTU_SPEC_REGISTER_DSP,
    318	// Two dummy chunks always in the end of data block.
    319	.tx_fixed_pcm_chunks = {10, 10, 0},
    320	.rx_fixed_pcm_chunks = {6, 6, 0},
    321};