Path: blob/master/sound/firewire/fireface/ff-protocol-latter.c
26424 views
// SPDX-License-Identifier: GPL-2.01// ff-protocol-latter.c - a part of driver for RME Fireface series2//3// Copyright (c) 2019 Takashi Sakamoto45#include <linux/delay.h>67#include "ff.h"89#define LATTER_STF 0xffff00000004ULL10#define LATTER_ISOC_CHANNELS 0xffff00000008ULL11#define LATTER_ISOC_START 0xffff0000000cULL12#define LATTER_FETCH_MODE 0xffff00000010ULL13#define LATTER_SYNC_STATUS 0x0000801c0000ULL1415// The content of sync status register differs between models.16//17// Fireface UCX:18// 0xf0000000: (unidentified)19// 0x0f000000: effective rate of sampling clock20// 0x00f00000: detected rate of word clock on BNC interface21// 0x000f0000: detected rate of ADAT or S/PDIF on optical interface22// 0x0000f000: detected rate of S/PDIF on coaxial interface23// 0x00000e00: effective source of sampling clock24// 0x00000e00: Internal25// 0x00000800: (unidentified)26// 0x00000600: Word clock on BNC interface27// 0x00000400: ADAT on optical interface28// 0x00000200: S/PDIF on coaxial or optical interface29// 0x00000100: Optical interface is used for ADAT signal30// 0x00000080: (unidentified)31// 0x00000040: Synchronized to word clock on BNC interface32// 0x00000020: Synchronized to ADAT or S/PDIF on optical interface33// 0x00000010: Synchronized to S/PDIF on coaxial interface34// 0x00000008: (unidentified)35// 0x00000004: Lock word clock on BNC interface36// 0x00000002: Lock ADAT or S/PDIF on optical interface37// 0x00000001: Lock S/PDIF on coaxial interface38//39// Fireface 802 (and perhaps UFX):40// 0xf0000000: effective rate of sampling clock41// 0x0f000000: detected rate of ADAT-B on 2nd optical interface42// 0x00f00000: detected rate of ADAT-A on 1st optical interface43// 0x000f0000: detected rate of AES/EBU on XLR or coaxial interface44// 0x0000f000: detected rate of word clock on BNC interface45// 0x00000e00: effective source of sampling clock46// 0x00000e00: internal47// 0x00000800: ADAT-B48// 0x00000600: ADAT-A49// 0x00000400: AES/EBU50// 0x00000200: Word clock51// 0x00000080: Synchronized to ADAT-B on 2nd optical interface52// 0x00000040: Synchronized to ADAT-A on 1st optical interface53// 0x00000020: Synchronized to AES/EBU on XLR or 2nd optical interface54// 0x00000010: Synchronized to word clock on BNC interface55// 0x00000008: Lock ADAT-B on 2nd optical interface56// 0x00000004: Lock ADAT-A on 1st optical interface57// 0x00000002: Lock AES/EBU on XLR or 2nd optical interface58// 0x00000001: Lock word clock on BNC interface59//60// The pattern for rate bits:61// 0x00: 32.0 kHz62// 0x01: 44.1 kHz63// 0x02: 48.0 kHz64// 0x04: 64.0 kHz65// 0x05: 88.2 kHz66// 0x06: 96.0 kHz67// 0x08: 128.0 kHz68// 0x09: 176.4 kHz69// 0x0a: 192.0 kHz70static int parse_clock_bits(u32 data, unsigned int *rate,71enum snd_ff_clock_src *src,72enum snd_ff_unit_version unit_version)73{74static const struct {75unsigned int rate;76u32 flag;77} *rate_entry, rate_entries[] = {78{ 32000, 0x00, },79{ 44100, 0x01, },80{ 48000, 0x02, },81{ 64000, 0x04, },82{ 88200, 0x05, },83{ 96000, 0x06, },84{ 128000, 0x08, },85{ 176400, 0x09, },86{ 192000, 0x0a, },87};88static const struct {89enum snd_ff_clock_src src;90u32 flag;91} *clk_entry, *clk_entries, ucx_clk_entries[] = {92{ SND_FF_CLOCK_SRC_SPDIF, 0x00000200, },93{ SND_FF_CLOCK_SRC_ADAT1, 0x00000400, },94{ SND_FF_CLOCK_SRC_WORD, 0x00000600, },95{ SND_FF_CLOCK_SRC_INTERNAL, 0x00000e00, },96}, ufx_ff802_clk_entries[] = {97{ SND_FF_CLOCK_SRC_WORD, 0x00000200, },98{ SND_FF_CLOCK_SRC_SPDIF, 0x00000400, },99{ SND_FF_CLOCK_SRC_ADAT1, 0x00000600, },100{ SND_FF_CLOCK_SRC_ADAT2, 0x00000800, },101{ SND_FF_CLOCK_SRC_INTERNAL, 0x00000e00, },102};103u32 rate_bits;104unsigned int clk_entry_count;105int i;106107if (unit_version == SND_FF_UNIT_VERSION_UCX) {108rate_bits = (data & 0x0f000000) >> 24;109clk_entries = ucx_clk_entries;110clk_entry_count = ARRAY_SIZE(ucx_clk_entries);111} else {112rate_bits = (data & 0xf0000000) >> 28;113clk_entries = ufx_ff802_clk_entries;114clk_entry_count = ARRAY_SIZE(ufx_ff802_clk_entries);115}116117for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) {118rate_entry = rate_entries + i;119if (rate_bits == rate_entry->flag) {120*rate = rate_entry->rate;121break;122}123}124if (i == ARRAY_SIZE(rate_entries))125return -EIO;126127for (i = 0; i < clk_entry_count; ++i) {128clk_entry = clk_entries + i;129if ((data & 0x000e00) == clk_entry->flag) {130*src = clk_entry->src;131break;132}133}134if (i == clk_entry_count)135return -EIO;136137return 0;138}139140static int latter_get_clock(struct snd_ff *ff, unsigned int *rate,141enum snd_ff_clock_src *src)142{143__le32 reg;144u32 data;145int err;146147err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,148LATTER_SYNC_STATUS, ®, sizeof(reg), 0);149if (err < 0)150return err;151data = le32_to_cpu(reg);152153return parse_clock_bits(data, rate, src, ff->unit_version);154}155156static int latter_switch_fetching_mode(struct snd_ff *ff, bool enable)157{158u32 data;159__le32 reg;160161if (enable)162data = 0x00000000;163else164data = 0xffffffff;165reg = cpu_to_le32(data);166167return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,168LATTER_FETCH_MODE, ®, sizeof(reg), 0);169}170171static int latter_allocate_resources(struct snd_ff *ff, unsigned int rate)172{173enum snd_ff_stream_mode mode;174unsigned int code;175__le32 reg;176unsigned int count;177int i;178int err;179180// Set the number of data blocks transferred in a second.181if (rate % 48000 == 0)182code = 0x04;183else if (rate % 44100 == 0)184code = 0x02;185else if (rate % 32000 == 0)186code = 0x00;187else188return -EINVAL;189190if (rate >= 64000 && rate < 128000)191code |= 0x08;192else if (rate >= 128000)193code |= 0x10;194195reg = cpu_to_le32(code);196err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,197LATTER_STF, ®, sizeof(reg), 0);198if (err < 0)199return err;200201// Confirm to shift transmission clock.202count = 0;203while (count++ < 10) {204unsigned int curr_rate;205enum snd_ff_clock_src src;206207err = latter_get_clock(ff, &curr_rate, &src);208if (err < 0)209return err;210211if (curr_rate == rate)212break;213}214if (count > 10)215return -ETIMEDOUT;216217for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); ++i) {218if (rate == amdtp_rate_table[i])219break;220}221if (i == ARRAY_SIZE(amdtp_rate_table))222return -EINVAL;223224err = snd_ff_stream_get_multiplier_mode(i, &mode);225if (err < 0)226return err;227228// Keep resources for in-stream.229ff->tx_resources.channels_mask = 0x00000000000000ffuLL;230err = fw_iso_resources_allocate(&ff->tx_resources,231amdtp_stream_get_max_payload(&ff->tx_stream),232fw_parent_device(ff->unit)->max_speed);233if (err < 0)234return err;235236// Keep resources for out-stream.237ff->rx_resources.channels_mask = 0x00000000000000ffuLL;238err = fw_iso_resources_allocate(&ff->rx_resources,239amdtp_stream_get_max_payload(&ff->rx_stream),240fw_parent_device(ff->unit)->max_speed);241if (err < 0)242fw_iso_resources_free(&ff->tx_resources);243244return err;245}246247static int latter_begin_session(struct snd_ff *ff, unsigned int rate)248{249unsigned int generation = ff->rx_resources.generation;250unsigned int flag;251u32 data;252__le32 reg;253int err;254255if (ff->unit_version == SND_FF_UNIT_VERSION_UCX) {256// For Fireface UCX. Always use the maximum number of data257// channels in data block of packet.258if (rate >= 32000 && rate <= 48000)259flag = 0x92;260else if (rate >= 64000 && rate <= 96000)261flag = 0x8e;262else if (rate >= 128000 && rate <= 192000)263flag = 0x8c;264else265return -EINVAL;266} else {267// For Fireface UFX and 802. Due to bandwidth limitation on268// IEEE 1394a (400 Mbps), Analog 1-12 and AES are available269// without any ADAT at quadruple speed.270if (rate >= 32000 && rate <= 48000)271flag = 0x9e;272else if (rate >= 64000 && rate <= 96000)273flag = 0x96;274else if (rate >= 128000 && rate <= 192000)275flag = 0x8e;276else277return -EINVAL;278}279280if (generation != fw_parent_device(ff->unit)->card->generation) {281err = fw_iso_resources_update(&ff->tx_resources);282if (err < 0)283return err;284285err = fw_iso_resources_update(&ff->rx_resources);286if (err < 0)287return err;288}289290data = (ff->tx_resources.channel << 8) | ff->rx_resources.channel;291reg = cpu_to_le32(data);292err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,293LATTER_ISOC_CHANNELS, ®, sizeof(reg), 0);294if (err < 0)295return err;296297reg = cpu_to_le32(flag);298return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,299LATTER_ISOC_START, ®, sizeof(reg), 0);300}301302static void latter_finish_session(struct snd_ff *ff)303{304__le32 reg;305306reg = cpu_to_le32(0x00000000);307snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,308LATTER_ISOC_START, ®, sizeof(reg), 0);309}310311static void latter_dump_status(struct snd_ff *ff, struct snd_info_buffer *buffer)312{313static const struct {314char *const label;315u32 locked_mask;316u32 synced_mask;317} *clk_entry, *clk_entries, ucx_clk_entries[] = {318{ "S/PDIF", 0x00000001, 0x00000010, },319{ "ADAT", 0x00000002, 0x00000020, },320{ "WDClk", 0x00000004, 0x00000040, },321}, ufx_ff802_clk_entries[] = {322{ "WDClk", 0x00000001, 0x00000010, },323{ "AES/EBU", 0x00000002, 0x00000020, },324{ "ADAT-A", 0x00000004, 0x00000040, },325{ "ADAT-B", 0x00000008, 0x00000080, },326};327__le32 reg;328u32 data;329unsigned int rate;330enum snd_ff_clock_src src;331const char *label;332unsigned int clk_entry_count;333int i;334int err;335336err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,337LATTER_SYNC_STATUS, ®, sizeof(reg), 0);338if (err < 0)339return;340data = le32_to_cpu(reg);341342snd_iprintf(buffer, "External source detection:\n");343344if (ff->unit_version == SND_FF_UNIT_VERSION_UCX) {345clk_entries = ucx_clk_entries;346clk_entry_count = ARRAY_SIZE(ucx_clk_entries);347} else {348clk_entries = ufx_ff802_clk_entries;349clk_entry_count = ARRAY_SIZE(ufx_ff802_clk_entries);350}351352for (i = 0; i < clk_entry_count; ++i) {353clk_entry = clk_entries + i;354snd_iprintf(buffer, "%s: ", clk_entry->label);355if (data & clk_entry->locked_mask) {356if (data & clk_entry->synced_mask)357snd_iprintf(buffer, "sync\n");358else359snd_iprintf(buffer, "lock\n");360} else {361snd_iprintf(buffer, "none\n");362}363}364365err = parse_clock_bits(data, &rate, &src, ff->unit_version);366if (err < 0)367return;368label = snd_ff_proc_get_clk_label(src);369if (!label)370return;371372snd_iprintf(buffer, "Referred clock: %s %d\n", label, rate);373}374375// NOTE: transactions are transferred within 0x00-0x7f in allocated range of376// address. This seems to be for check of discontinuity in receiver side.377//378// Like Fireface 400, drivers can select one of 4 options for lower 4 bytes of379// destination address by bit flags in quadlet register (little endian) at380// 0x'ffff'0000'0014:381//382// bit flags: offset of destination address383// - 0x00002000: 0x'....'....'0000'0000384// - 0x00004000: 0x'....'....'0000'0080385// - 0x00008000: 0x'....'....'0000'0100386// - 0x00010000: 0x'....'....'0000'0180387//388// Drivers can suppress the device to transfer asynchronous transactions by389// clear these bit flags.390//391// Actually, the register is write-only and includes the other settings such as392// input attenuation. This driver allocates for the first option393// (0x'....'....'0000'0000) and expects userspace application to configure the394// register for it.395static void latter_handle_midi_msg(struct snd_ff *ff, unsigned int offset, const __le32 *buf,396size_t length, u32 tstamp)397{398u32 data = le32_to_cpu(*buf);399unsigned int index = (data & 0x000000f0) >> 4;400u8 byte[3];401struct snd_rawmidi_substream *substream;402unsigned int len;403404if (index >= ff->spec->midi_in_ports)405return;406407switch (data & 0x0000000f) {408case 0x00000008:409case 0x00000009:410case 0x0000000a:411case 0x0000000b:412case 0x0000000e:413len = 3;414break;415case 0x0000000c:416case 0x0000000d:417len = 2;418break;419default:420len = data & 0x00000003;421if (len == 0)422len = 3;423break;424}425426byte[0] = (data & 0x0000ff00) >> 8;427byte[1] = (data & 0x00ff0000) >> 16;428byte[2] = (data & 0xff000000) >> 24;429430substream = READ_ONCE(ff->tx_midi_substreams[index]);431if (substream)432snd_rawmidi_receive(substream, byte, len);433}434435/*436* When return minus value, given argument is not MIDI status.437* When return 0, given argument is a beginning of system exclusive.438* When return the others, given argument is MIDI data.439*/440static inline int calculate_message_bytes(u8 status)441{442switch (status) {443case 0xf6: /* Tune request. */444case 0xf8: /* Timing clock. */445case 0xfa: /* Start. */446case 0xfb: /* Continue. */447case 0xfc: /* Stop. */448case 0xfe: /* Active sensing. */449case 0xff: /* System reset. */450return 1;451case 0xf1: /* MIDI time code quarter frame. */452case 0xf3: /* Song select. */453return 2;454case 0xf2: /* Song position pointer. */455return 3;456case 0xf0: /* Exclusive. */457return 0;458case 0xf7: /* End of exclusive. */459break;460case 0xf4: /* Undefined. */461case 0xf5: /* Undefined. */462case 0xf9: /* Undefined. */463case 0xfd: /* Undefined. */464break;465default:466switch (status & 0xf0) {467case 0x80: /* Note on. */468case 0x90: /* Note off. */469case 0xa0: /* Polyphonic key pressure. */470case 0xb0: /* Control change and Mode change. */471case 0xe0: /* Pitch bend change. */472return 3;473case 0xc0: /* Program change. */474case 0xd0: /* Channel pressure. */475return 2;476default:477break;478}479break;480}481482return -EINVAL;483}484485static int latter_fill_midi_msg(struct snd_ff *ff,486struct snd_rawmidi_substream *substream,487unsigned int port)488{489u32 data = {0};490u8 *buf = (u8 *)&data;491int consumed;492493buf[0] = port << 4;494consumed = snd_rawmidi_transmit_peek(substream, buf + 1, 3);495if (consumed <= 0)496return consumed;497498if (!ff->on_sysex[port]) {499if (buf[1] != 0xf0) {500if (consumed < calculate_message_bytes(buf[1]))501return 0;502} else {503// The beginning of exclusives.504ff->on_sysex[port] = true;505}506507buf[0] |= consumed;508} else {509if (buf[1] != 0xf7) {510if (buf[2] == 0xf7 || buf[3] == 0xf7) {511// Transfer end code at next time.512consumed -= 1;513}514515buf[0] |= consumed;516} else {517// The end of exclusives.518ff->on_sysex[port] = false;519consumed = 1;520buf[0] |= 0x0f;521}522}523524ff->msg_buf[port][0] = cpu_to_le32(data);525ff->rx_bytes[port] = consumed;526527return 1;528}529530const struct snd_ff_protocol snd_ff_protocol_latter = {531.handle_msg = latter_handle_midi_msg,532.fill_midi_msg = latter_fill_midi_msg,533.get_clock = latter_get_clock,534.switch_fetching_mode = latter_switch_fetching_mode,535.allocate_resources = latter_allocate_resources,536.begin_session = latter_begin_session,537.finish_session = latter_finish_session,538.dump_status = latter_dump_status,539};540541542