brintos

brintos / linux-shallow public Read only

0
0
Text · 14.3 KiB · 9947e0c Raw
541 lines · c
1// SPDX-License-Identifier: GPL-2.02// ff-protocol-latter.c - a part of driver for RME Fireface series3//4// Copyright (c) 2019 Takashi Sakamoto5 6#include <linux/delay.h>7 8#include "ff.h"9 10#define LATTER_STF		0xffff00000004ULL11#define LATTER_ISOC_CHANNELS	0xffff00000008ULL12#define LATTER_ISOC_START	0xffff0000000cULL13#define LATTER_FETCH_MODE	0xffff00000010ULL14#define LATTER_SYNC_STATUS	0x0000801c0000ULL15 16// The content of sync status register differs between models.17//18// Fireface UCX:19//  0xf0000000: (unidentified)20//  0x0f000000: effective rate of sampling clock21//  0x00f00000: detected rate of word clock on BNC interface22//  0x000f0000: detected rate of ADAT or S/PDIF on optical interface23//  0x0000f000: detected rate of S/PDIF on coaxial interface24//  0x00000e00: effective source of sampling clock25//    0x00000e00: Internal26//    0x00000800: (unidentified)27//    0x00000600: Word clock on BNC interface28//    0x00000400: ADAT on optical interface29//    0x00000200: S/PDIF on coaxial or optical interface30//  0x00000100: Optical interface is used for ADAT signal31//  0x00000080: (unidentified)32//  0x00000040: Synchronized to word clock on BNC interface33//  0x00000020: Synchronized to ADAT or S/PDIF on optical interface34//  0x00000010: Synchronized to S/PDIF on coaxial interface35//  0x00000008: (unidentified)36//  0x00000004: Lock word clock on BNC interface37//  0x00000002: Lock ADAT or S/PDIF on optical interface38//  0x00000001: Lock S/PDIF on coaxial interface39//40// Fireface 802 (and perhaps UFX):41//   0xf0000000: effective rate of sampling clock42//   0x0f000000: detected rate of ADAT-B on 2nd optical interface43//   0x00f00000: detected rate of ADAT-A on 1st optical interface44//   0x000f0000: detected rate of AES/EBU on XLR or coaxial interface45//   0x0000f000: detected rate of word clock on BNC interface46//   0x00000e00: effective source of sampling clock47//     0x00000e00: internal48//     0x00000800: ADAT-B49//     0x00000600: ADAT-A50//     0x00000400: AES/EBU51//     0x00000200: Word clock52//   0x00000080: Synchronized to ADAT-B on 2nd optical interface53//   0x00000040: Synchronized to ADAT-A on 1st optical interface54//   0x00000020: Synchronized to AES/EBU on XLR or 2nd optical interface55//   0x00000010: Synchronized to word clock on BNC interface56//   0x00000008: Lock ADAT-B on 2nd optical interface57//   0x00000004: Lock ADAT-A on 1st optical interface58//   0x00000002: Lock AES/EBU on XLR or 2nd optical interface59//   0x00000001: Lock word clock on BNC interface60//61// The pattern for rate bits:62//   0x00: 32.0 kHz63//   0x01: 44.1 kHz64//   0x02: 48.0 kHz65//   0x04: 64.0 kHz66//   0x05: 88.2 kHz67//   0x06: 96.0 kHz68//   0x08: 128.0 kHz69//   0x09: 176.4 kHz70//   0x0a: 192.0 kHz71static int parse_clock_bits(u32 data, unsigned int *rate,72			    enum snd_ff_clock_src *src,73			    enum snd_ff_unit_version unit_version)74{75	static const struct {76		unsigned int rate;77		u32 flag;78	} *rate_entry, rate_entries[] = {79		{ 32000,	0x00, },80		{ 44100,	0x01, },81		{ 48000,	0x02, },82		{ 64000,	0x04, },83		{ 88200,	0x05, },84		{ 96000,	0x06, },85		{ 128000,	0x08, },86		{ 176400,	0x09, },87		{ 192000,	0x0a, },88	};89	static const struct {90		enum snd_ff_clock_src src;91		u32 flag;92	} *clk_entry, *clk_entries, ucx_clk_entries[] = {93		{ SND_FF_CLOCK_SRC_SPDIF,	0x00000200, },94		{ SND_FF_CLOCK_SRC_ADAT1,	0x00000400, },95		{ SND_FF_CLOCK_SRC_WORD,	0x00000600, },96		{ SND_FF_CLOCK_SRC_INTERNAL,	0x00000e00, },97	}, ufx_ff802_clk_entries[] = {98		{ SND_FF_CLOCK_SRC_WORD,	0x00000200, },99		{ SND_FF_CLOCK_SRC_SPDIF,	0x00000400, },100		{ SND_FF_CLOCK_SRC_ADAT1,	0x00000600, },101		{ SND_FF_CLOCK_SRC_ADAT2,	0x00000800, },102		{ SND_FF_CLOCK_SRC_INTERNAL,	0x00000e00, },103	};104	u32 rate_bits;105	unsigned int clk_entry_count;106	int i;107 108	if (unit_version == SND_FF_UNIT_VERSION_UCX) {109		rate_bits = (data & 0x0f000000) >> 24;110		clk_entries = ucx_clk_entries;111		clk_entry_count = ARRAY_SIZE(ucx_clk_entries);112	} else {113		rate_bits = (data & 0xf0000000) >> 28;114		clk_entries = ufx_ff802_clk_entries;115		clk_entry_count = ARRAY_SIZE(ufx_ff802_clk_entries);116	}117 118	for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) {119		rate_entry = rate_entries + i;120		if (rate_bits == rate_entry->flag) {121			*rate = rate_entry->rate;122			break;123		}124	}125	if (i == ARRAY_SIZE(rate_entries))126		return -EIO;127 128	for (i = 0; i < clk_entry_count; ++i) {129		clk_entry = clk_entries + i;130		if ((data & 0x000e00) == clk_entry->flag) {131			*src = clk_entry->src;132			break;133		}134	}135	if (i == clk_entry_count)136		return -EIO;137 138	return 0;139}140 141static int latter_get_clock(struct snd_ff *ff, unsigned int *rate,142			   enum snd_ff_clock_src *src)143{144	__le32 reg;145	u32 data;146	int err;147 148	err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,149				 LATTER_SYNC_STATUS, &reg, sizeof(reg), 0);150	if (err < 0)151		return err;152	data = le32_to_cpu(reg);153 154	return parse_clock_bits(data, rate, src, ff->unit_version);155}156 157static int latter_switch_fetching_mode(struct snd_ff *ff, bool enable)158{159	u32 data;160	__le32 reg;161 162	if (enable)163		data = 0x00000000;164	else165		data = 0xffffffff;166	reg = cpu_to_le32(data);167 168	return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,169				  LATTER_FETCH_MODE, &reg, sizeof(reg), 0);170}171 172static int latter_allocate_resources(struct snd_ff *ff, unsigned int rate)173{174	enum snd_ff_stream_mode mode;175	unsigned int code;176	__le32 reg;177	unsigned int count;178	int i;179	int err;180 181	// Set the number of data blocks transferred in a second.182	if (rate % 48000 == 0)183		code = 0x04;184	else if (rate % 44100 == 0)185		code = 0x02;186	else if (rate % 32000 == 0)187		code = 0x00;188	else189		return -EINVAL;190 191	if (rate >= 64000 && rate < 128000)192		code |= 0x08;193	else if (rate >= 128000)194		code |= 0x10;195 196	reg = cpu_to_le32(code);197	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,198				 LATTER_STF, &reg, sizeof(reg), 0);199	if (err < 0)200		return err;201 202	// Confirm to shift transmission clock.203	count = 0;204	while (count++ < 10) {205		unsigned int curr_rate;206		enum snd_ff_clock_src src;207 208		err = latter_get_clock(ff, &curr_rate, &src);209		if (err < 0)210			return err;211 212		if (curr_rate == rate)213			break;214	}215	if (count > 10)216		return -ETIMEDOUT;217 218	for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); ++i) {219		if (rate == amdtp_rate_table[i])220			break;221	}222	if (i == ARRAY_SIZE(amdtp_rate_table))223		return -EINVAL;224 225	err = snd_ff_stream_get_multiplier_mode(i, &mode);226	if (err < 0)227		return err;228 229	// Keep resources for in-stream.230	ff->tx_resources.channels_mask = 0x00000000000000ffuLL;231	err = fw_iso_resources_allocate(&ff->tx_resources,232			amdtp_stream_get_max_payload(&ff->tx_stream),233			fw_parent_device(ff->unit)->max_speed);234	if (err < 0)235		return err;236 237	// Keep resources for out-stream.238	ff->rx_resources.channels_mask = 0x00000000000000ffuLL;239	err = fw_iso_resources_allocate(&ff->rx_resources,240			amdtp_stream_get_max_payload(&ff->rx_stream),241			fw_parent_device(ff->unit)->max_speed);242	if (err < 0)243		fw_iso_resources_free(&ff->tx_resources);244 245	return err;246}247 248static int latter_begin_session(struct snd_ff *ff, unsigned int rate)249{250	unsigned int generation = ff->rx_resources.generation;251	unsigned int flag;252	u32 data;253	__le32 reg;254	int err;255 256	if (ff->unit_version == SND_FF_UNIT_VERSION_UCX) {257		// For Fireface UCX. Always use the maximum number of data258		// channels in data block of packet.259		if (rate >= 32000 && rate <= 48000)260			flag = 0x92;261		else if (rate >= 64000 && rate <= 96000)262			flag = 0x8e;263		else if (rate >= 128000 && rate <= 192000)264			flag = 0x8c;265		else266			return -EINVAL;267	} else {268		// For Fireface UFX and 802. Due to bandwidth limitation on269		// IEEE 1394a (400 Mbps), Analog 1-12 and AES are available270		// without any ADAT at quadruple speed.271		if (rate >= 32000 && rate <= 48000)272			flag = 0x9e;273		else if (rate >= 64000 && rate <= 96000)274			flag = 0x96;275		else if (rate >= 128000 && rate <= 192000)276			flag = 0x8e;277		else278			return -EINVAL;279	}280 281	if (generation != fw_parent_device(ff->unit)->card->generation) {282		err = fw_iso_resources_update(&ff->tx_resources);283		if (err < 0)284			return err;285 286		err = fw_iso_resources_update(&ff->rx_resources);287		if (err < 0)288			return err;289	}290 291	data = (ff->tx_resources.channel << 8) | ff->rx_resources.channel;292	reg = cpu_to_le32(data);293	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,294				 LATTER_ISOC_CHANNELS, &reg, sizeof(reg), 0);295	if (err < 0)296		return err;297 298	reg = cpu_to_le32(flag);299	return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,300				  LATTER_ISOC_START, &reg, sizeof(reg), 0);301}302 303static void latter_finish_session(struct snd_ff *ff)304{305	__le32 reg;306 307	reg = cpu_to_le32(0x00000000);308	snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,309			   LATTER_ISOC_START, &reg, sizeof(reg), 0);310}311 312static void latter_dump_status(struct snd_ff *ff, struct snd_info_buffer *buffer)313{314	static const struct {315		char *const label;316		u32 locked_mask;317		u32 synced_mask;318	} *clk_entry, *clk_entries, ucx_clk_entries[] = {319		{ "S/PDIF",	0x00000001, 0x00000010, },320		{ "ADAT",	0x00000002, 0x00000020, },321		{ "WDClk",	0x00000004, 0x00000040, },322	}, ufx_ff802_clk_entries[] = {323		{ "WDClk",	0x00000001, 0x00000010, },324		{ "AES/EBU",	0x00000002, 0x00000020, },325		{ "ADAT-A",	0x00000004, 0x00000040, },326		{ "ADAT-B",	0x00000008, 0x00000080, },327	};328	__le32 reg;329	u32 data;330	unsigned int rate;331	enum snd_ff_clock_src src;332	const char *label;333	unsigned int clk_entry_count;334	int i;335	int err;336 337	err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,338				 LATTER_SYNC_STATUS, &reg, sizeof(reg), 0);339	if (err < 0)340		return;341	data = le32_to_cpu(reg);342 343	snd_iprintf(buffer, "External source detection:\n");344 345	if (ff->unit_version == SND_FF_UNIT_VERSION_UCX) {346		clk_entries = ucx_clk_entries;347		clk_entry_count = ARRAY_SIZE(ucx_clk_entries);348	} else {349		clk_entries = ufx_ff802_clk_entries;350		clk_entry_count = ARRAY_SIZE(ufx_ff802_clk_entries);351	}352 353	for (i = 0; i < clk_entry_count; ++i) {354		clk_entry = clk_entries + i;355		snd_iprintf(buffer, "%s: ", clk_entry->label);356		if (data & clk_entry->locked_mask) {357			if (data & clk_entry->synced_mask)358				snd_iprintf(buffer, "sync\n");359			else360				snd_iprintf(buffer, "lock\n");361		} else {362			snd_iprintf(buffer, "none\n");363		}364	}365 366	err = parse_clock_bits(data, &rate, &src, ff->unit_version);367	if (err < 0)368		return;369	label = snd_ff_proc_get_clk_label(src);370	if (!label)371		return;372 373	snd_iprintf(buffer, "Referred clock: %s %d\n", label, rate);374}375 376// NOTE: transactions are transferred within 0x00-0x7f in allocated range of377// address. This seems to be for check of discontinuity in receiver side.378//379// Like Fireface 400, drivers can select one of 4 options for lower 4 bytes of380// destination address by bit flags in quadlet register (little endian) at381// 0x'ffff'0000'0014:382//383// bit flags: offset of destination address384// - 0x00002000: 0x'....'....'0000'0000385// - 0x00004000: 0x'....'....'0000'0080386// - 0x00008000: 0x'....'....'0000'0100387// - 0x00010000: 0x'....'....'0000'0180388//389// Drivers can suppress the device to transfer asynchronous transactions by390// clear these bit flags.391//392// Actually, the register is write-only and includes the other settings such as393// input attenuation. This driver allocates for the first option394// (0x'....'....'0000'0000) and expects userspace application to configure the395// register for it.396static void latter_handle_midi_msg(struct snd_ff *ff, unsigned int offset, const __le32 *buf,397				   size_t length, u32 tstamp)398{399	u32 data = le32_to_cpu(*buf);400	unsigned int index = (data & 0x000000f0) >> 4;401	u8 byte[3];402	struct snd_rawmidi_substream *substream;403	unsigned int len;404 405	if (index >= ff->spec->midi_in_ports)406		return;407 408	switch (data & 0x0000000f) {409	case 0x00000008:410	case 0x00000009:411	case 0x0000000a:412	case 0x0000000b:413	case 0x0000000e:414		len = 3;415		break;416	case 0x0000000c:417	case 0x0000000d:418		len = 2;419		break;420	default:421		len = data & 0x00000003;422		if (len == 0)423			len = 3;424		break;425	}426 427	byte[0] = (data & 0x0000ff00) >> 8;428	byte[1] = (data & 0x00ff0000) >> 16;429	byte[2] = (data & 0xff000000) >> 24;430 431	substream = READ_ONCE(ff->tx_midi_substreams[index]);432	if (substream)433		snd_rawmidi_receive(substream, byte, len);434}435 436/*437 * When return minus value, given argument is not MIDI status.438 * When return 0, given argument is a beginning of system exclusive.439 * When return the others, given argument is MIDI data.440 */441static inline int calculate_message_bytes(u8 status)442{443	switch (status) {444	case 0xf6:	/* Tune request. */445	case 0xf8:	/* Timing clock. */446	case 0xfa:	/* Start. */447	case 0xfb:	/* Continue. */448	case 0xfc:	/* Stop. */449	case 0xfe:	/* Active sensing. */450	case 0xff:	/* System reset. */451		return 1;452	case 0xf1:	/* MIDI time code quarter frame. */453	case 0xf3:	/* Song select. */454		return 2;455	case 0xf2:	/* Song position pointer. */456		return 3;457	case 0xf0:	/* Exclusive. */458		return 0;459	case 0xf7:	/* End of exclusive. */460		break;461	case 0xf4:	/* Undefined. */462	case 0xf5:	/* Undefined. */463	case 0xf9:	/* Undefined. */464	case 0xfd:	/* Undefined. */465		break;466	default:467		switch (status & 0xf0) {468		case 0x80:	/* Note on. */469		case 0x90:	/* Note off. */470		case 0xa0:	/* Polyphonic key pressure. */471		case 0xb0:	/* Control change and Mode change. */472		case 0xe0:	/* Pitch bend change. */473			return 3;474		case 0xc0:	/* Program change. */475		case 0xd0:	/* Channel pressure. */476			return 2;477		default:478		break;479		}480	break;481	}482 483	return -EINVAL;484}485 486static int latter_fill_midi_msg(struct snd_ff *ff,487				struct snd_rawmidi_substream *substream,488				unsigned int port)489{490	u32 data = {0};491	u8 *buf = (u8 *)&data;492	int consumed;493 494	buf[0] = port << 4;495	consumed = snd_rawmidi_transmit_peek(substream, buf + 1, 3);496	if (consumed <= 0)497		return consumed;498 499	if (!ff->on_sysex[port]) {500		if (buf[1] != 0xf0) {501			if (consumed < calculate_message_bytes(buf[1]))502				return 0;503		} else {504			// The beginning of exclusives.505			ff->on_sysex[port] = true;506		}507 508		buf[0] |= consumed;509	} else {510		if (buf[1] != 0xf7) {511			if (buf[2] == 0xf7 || buf[3] == 0xf7) {512				// Transfer end code at next time.513				consumed -= 1;514			}515 516			buf[0] |= consumed;517		} else {518			// The end of exclusives.519			ff->on_sysex[port] = false;520			consumed = 1;521			buf[0] |= 0x0f;522		}523	}524 525	ff->msg_buf[port][0] = cpu_to_le32(data);526	ff->rx_bytes[port] = consumed;527 528	return 1;529}530 531const struct snd_ff_protocol snd_ff_protocol_latter = {532	.handle_msg		= latter_handle_midi_msg,533	.fill_midi_msg		= latter_fill_midi_msg,534	.get_clock		= latter_get_clock,535	.switch_fetching_mode	= latter_switch_fetching_mode,536	.allocate_resources	= latter_allocate_resources,537	.begin_session		= latter_begin_session,538	.finish_session		= latter_finish_session,539	.dump_status		= latter_dump_status,540};541