560 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * tascam-stream.c - a part of driver for TASCAM FireWire series4 *5 * Copyright (c) 2015 Takashi Sakamoto6 */7 8#include <linux/delay.h>9#include "tascam.h"10 11#define CLOCK_STATUS_MASK 0xffff000012#define CLOCK_CONFIG_MASK 0x0000ffff13 14#define READY_TIMEOUT_MS 400015 16static int get_clock(struct snd_tscm *tscm, u32 *data)17{18 int trial = 0;19 __be32 reg;20 int err;21 22 while (trial++ < 5) {23 err = snd_fw_transaction(tscm->unit, TCODE_READ_QUADLET_REQUEST,24 TSCM_ADDR_BASE + TSCM_OFFSET_CLOCK_STATUS,25 ®, sizeof(reg), 0);26 if (err < 0)27 return err;28 29 *data = be32_to_cpu(reg);30 if (*data & CLOCK_STATUS_MASK)31 break;32 33 // In intermediate state after changing clock status.34 msleep(50);35 }36 37 // Still in the intermediate state.38 if (trial >= 5)39 return -EAGAIN;40 41 return 0;42}43 44static int set_clock(struct snd_tscm *tscm, unsigned int rate,45 enum snd_tscm_clock clock)46{47 u32 data;48 __be32 reg;49 int err;50 51 err = get_clock(tscm, &data);52 if (err < 0)53 return err;54 data &= CLOCK_CONFIG_MASK;55 56 if (rate > 0) {57 data &= 0x000000ff;58 /* Base rate. */59 if ((rate % 44100) == 0) {60 data |= 0x00000100;61 /* Multiplier. */62 if (rate / 44100 == 2)63 data |= 0x00008000;64 } else if ((rate % 48000) == 0) {65 data |= 0x00000200;66 /* Multiplier. */67 if (rate / 48000 == 2)68 data |= 0x00008000;69 } else {70 return -EAGAIN;71 }72 }73 74 if (clock != INT_MAX) {75 data &= 0x0000ff00;76 data |= clock + 1;77 }78 79 reg = cpu_to_be32(data);80 81 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,82 TSCM_ADDR_BASE + TSCM_OFFSET_CLOCK_STATUS,83 ®, sizeof(reg), 0);84 if (err < 0)85 return err;86 87 if (data & 0x00008000)88 reg = cpu_to_be32(0x0000001a);89 else90 reg = cpu_to_be32(0x0000000d);91 92 return snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,93 TSCM_ADDR_BASE + TSCM_OFFSET_MULTIPLEX_MODE,94 ®, sizeof(reg), 0);95}96 97int snd_tscm_stream_get_rate(struct snd_tscm *tscm, unsigned int *rate)98{99 u32 data;100 int err;101 102 err = get_clock(tscm, &data);103 if (err < 0)104 return err;105 106 data = (data & 0xff000000) >> 24;107 108 /* Check base rate. */109 if ((data & 0x0f) == 0x01)110 *rate = 44100;111 else if ((data & 0x0f) == 0x02)112 *rate = 48000;113 else114 return -EAGAIN;115 116 /* Check multiplier. */117 if ((data & 0xf0) == 0x80)118 *rate *= 2;119 else if ((data & 0xf0) != 0x00)120 return -EAGAIN;121 122 return err;123}124 125int snd_tscm_stream_get_clock(struct snd_tscm *tscm, enum snd_tscm_clock *clock)126{127 u32 data;128 int err;129 130 err = get_clock(tscm, &data);131 if (err < 0)132 return err;133 134 *clock = ((data & 0x00ff0000) >> 16) - 1;135 if (*clock < 0 || *clock > SND_TSCM_CLOCK_ADAT)136 return -EIO;137 138 return 0;139}140 141static int enable_data_channels(struct snd_tscm *tscm)142{143 __be32 reg;144 u32 data;145 unsigned int i;146 int err;147 148 data = 0;149 for (i = 0; i < tscm->spec->pcm_capture_analog_channels; ++i)150 data |= BIT(i);151 if (tscm->spec->has_adat)152 data |= 0x0000ff00;153 if (tscm->spec->has_spdif)154 data |= 0x00030000;155 156 reg = cpu_to_be32(data);157 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,158 TSCM_ADDR_BASE + TSCM_OFFSET_TX_PCM_CHANNELS,159 ®, sizeof(reg), 0);160 if (err < 0)161 return err;162 163 data = 0;164 for (i = 0; i < tscm->spec->pcm_playback_analog_channels; ++i)165 data |= BIT(i);166 if (tscm->spec->has_adat)167 data |= 0x0000ff00;168 if (tscm->spec->has_spdif)169 data |= 0x00030000;170 171 reg = cpu_to_be32(data);172 return snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,173 TSCM_ADDR_BASE + TSCM_OFFSET_RX_PCM_CHANNELS,174 ®, sizeof(reg), 0);175}176 177static int set_stream_formats(struct snd_tscm *tscm, unsigned int rate)178{179 __be32 reg;180 int err;181 182 // Set an option for unknown purpose.183 reg = cpu_to_be32(0x00200000);184 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,185 TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,186 ®, sizeof(reg), 0);187 if (err < 0)188 return err;189 190 return enable_data_channels(tscm);191}192 193static void finish_session(struct snd_tscm *tscm)194{195 __be32 reg;196 197 reg = 0;198 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,199 TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING,200 ®, sizeof(reg), 0);201 202 reg = 0;203 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,204 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_ON,205 ®, sizeof(reg), 0);206 207 // Unregister channels.208 reg = cpu_to_be32(0x00000000);209 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,210 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,211 ®, sizeof(reg), 0);212 reg = cpu_to_be32(0x00000000);213 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,214 TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,215 ®, sizeof(reg), 0);216 reg = cpu_to_be32(0x00000000);217 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,218 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,219 ®, sizeof(reg), 0);220}221 222static int begin_session(struct snd_tscm *tscm)223{224 __be32 reg;225 int err;226 227 // Register the isochronous channel for transmitting stream.228 reg = cpu_to_be32(tscm->tx_resources.channel);229 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,230 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,231 ®, sizeof(reg), 0);232 if (err < 0)233 return err;234 235 // Unknown.236 reg = cpu_to_be32(0x00000002);237 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,238 TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,239 ®, sizeof(reg), 0);240 if (err < 0)241 return err;242 243 // Register the isochronous channel for receiving stream.244 reg = cpu_to_be32(tscm->rx_resources.channel);245 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,246 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,247 ®, sizeof(reg), 0);248 if (err < 0)249 return err;250 251 reg = cpu_to_be32(0x00000001);252 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,253 TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING,254 ®, sizeof(reg), 0);255 if (err < 0)256 return err;257 258 reg = cpu_to_be32(0x00000001);259 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,260 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_ON,261 ®, sizeof(reg), 0);262 if (err < 0)263 return err;264 265 // Set an option for unknown purpose.266 reg = cpu_to_be32(0x00002000);267 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,268 TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,269 ®, sizeof(reg), 0);270 if (err < 0)271 return err;272 273 // Start multiplexing PCM samples on packets.274 reg = cpu_to_be32(0x00000001);275 return snd_fw_transaction(tscm->unit,276 TCODE_WRITE_QUADLET_REQUEST,277 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_ON,278 ®, sizeof(reg), 0);279}280 281static int keep_resources(struct snd_tscm *tscm, unsigned int rate,282 struct amdtp_stream *stream)283{284 struct fw_iso_resources *resources;285 int err;286 287 if (stream == &tscm->tx_stream)288 resources = &tscm->tx_resources;289 else290 resources = &tscm->rx_resources;291 292 err = amdtp_tscm_set_parameters(stream, rate);293 if (err < 0)294 return err;295 296 return fw_iso_resources_allocate(resources,297 amdtp_stream_get_max_payload(stream),298 fw_parent_device(tscm->unit)->max_speed);299}300 301static int init_stream(struct snd_tscm *tscm, struct amdtp_stream *s)302{303 struct fw_iso_resources *resources;304 enum amdtp_stream_direction dir;305 unsigned int pcm_channels;306 int err;307 308 if (s == &tscm->tx_stream) {309 resources = &tscm->tx_resources;310 dir = AMDTP_IN_STREAM;311 pcm_channels = tscm->spec->pcm_capture_analog_channels;312 } else {313 resources = &tscm->rx_resources;314 dir = AMDTP_OUT_STREAM;315 pcm_channels = tscm->spec->pcm_playback_analog_channels;316 }317 318 if (tscm->spec->has_adat)319 pcm_channels += 8;320 if (tscm->spec->has_spdif)321 pcm_channels += 2;322 323 err = fw_iso_resources_init(resources, tscm->unit);324 if (err < 0)325 return err;326 327 err = amdtp_tscm_init(s, tscm->unit, dir, pcm_channels);328 if (err < 0)329 fw_iso_resources_free(resources);330 331 return err;332}333 334static void destroy_stream(struct snd_tscm *tscm, struct amdtp_stream *s)335{336 amdtp_stream_destroy(s);337 338 if (s == &tscm->tx_stream)339 fw_iso_resources_destroy(&tscm->tx_resources);340 else341 fw_iso_resources_destroy(&tscm->rx_resources);342}343 344int snd_tscm_stream_init_duplex(struct snd_tscm *tscm)345{346 int err;347 348 err = init_stream(tscm, &tscm->tx_stream);349 if (err < 0)350 return err;351 352 err = init_stream(tscm, &tscm->rx_stream);353 if (err < 0) {354 destroy_stream(tscm, &tscm->tx_stream);355 return err;356 }357 358 err = amdtp_domain_init(&tscm->domain);359 if (err < 0) {360 destroy_stream(tscm, &tscm->tx_stream);361 destroy_stream(tscm, &tscm->rx_stream);362 }363 364 return err;365}366 367// At bus reset, streaming is stopped and some registers are clear.368void snd_tscm_stream_update_duplex(struct snd_tscm *tscm)369{370 amdtp_domain_stop(&tscm->domain);371 372 amdtp_stream_pcm_abort(&tscm->tx_stream);373 amdtp_stream_pcm_abort(&tscm->rx_stream);374}375 376// This function should be called before starting streams or after stopping377// streams.378void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm)379{380 amdtp_domain_destroy(&tscm->domain);381 382 destroy_stream(tscm, &tscm->rx_stream);383 destroy_stream(tscm, &tscm->tx_stream);384}385 386int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate,387 unsigned int frames_per_period,388 unsigned int frames_per_buffer)389{390 unsigned int curr_rate;391 int err;392 393 err = snd_tscm_stream_get_rate(tscm, &curr_rate);394 if (err < 0)395 return err;396 397 if (tscm->substreams_counter == 0 || rate != curr_rate) {398 amdtp_domain_stop(&tscm->domain);399 400 finish_session(tscm);401 402 fw_iso_resources_free(&tscm->tx_resources);403 fw_iso_resources_free(&tscm->rx_resources);404 405 err = set_clock(tscm, rate, INT_MAX);406 if (err < 0)407 return err;408 409 err = keep_resources(tscm, rate, &tscm->tx_stream);410 if (err < 0)411 return err;412 413 err = keep_resources(tscm, rate, &tscm->rx_stream);414 if (err < 0) {415 fw_iso_resources_free(&tscm->tx_resources);416 return err;417 }418 419 err = amdtp_domain_set_events_per_period(&tscm->domain,420 frames_per_period, frames_per_buffer);421 if (err < 0) {422 fw_iso_resources_free(&tscm->tx_resources);423 fw_iso_resources_free(&tscm->rx_resources);424 return err;425 }426 427 tscm->need_long_tx_init_skip = (rate != curr_rate);428 }429 430 return 0;431}432 433int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)434{435 unsigned int generation = tscm->rx_resources.generation;436 int err;437 438 if (tscm->substreams_counter == 0)439 return 0;440 441 if (amdtp_streaming_error(&tscm->rx_stream) ||442 amdtp_streaming_error(&tscm->tx_stream)) {443 amdtp_domain_stop(&tscm->domain);444 finish_session(tscm);445 }446 447 if (generation != fw_parent_device(tscm->unit)->card->generation) {448 err = fw_iso_resources_update(&tscm->tx_resources);449 if (err < 0)450 goto error;451 452 err = fw_iso_resources_update(&tscm->rx_resources);453 if (err < 0)454 goto error;455 }456 457 if (!amdtp_stream_running(&tscm->rx_stream)) {458 int spd = fw_parent_device(tscm->unit)->max_speed;459 unsigned int tx_init_skip_cycles;460 461 err = set_stream_formats(tscm, rate);462 if (err < 0)463 goto error;464 465 err = begin_session(tscm);466 if (err < 0)467 goto error;468 469 err = amdtp_domain_add_stream(&tscm->domain, &tscm->rx_stream,470 tscm->rx_resources.channel, spd);471 if (err < 0)472 goto error;473 474 err = amdtp_domain_add_stream(&tscm->domain, &tscm->tx_stream,475 tscm->tx_resources.channel, spd);476 if (err < 0)477 goto error;478 479 if (tscm->need_long_tx_init_skip)480 tx_init_skip_cycles = 16000;481 else482 tx_init_skip_cycles = 0;483 484 // MEMO: Just after starting packet streaming, it transfers packets without any485 // event. Enough after receiving the sequence of packets, it multiplexes events into486 // the packet. However, just after changing sampling transfer frequency, it stops487 // multiplexing during packet transmission. Enough after, it restarts multiplexing488 // again. The device ignores presentation time expressed by the value of syt field489 // of CIP header in received packets. The sequence of the number of data blocks per490 // packet is important for media clock recovery.491 err = amdtp_domain_start(&tscm->domain, tx_init_skip_cycles, true, true);492 if (err < 0)493 goto error;494 495 if (!amdtp_domain_wait_ready(&tscm->domain, READY_TIMEOUT_MS)) {496 err = -ETIMEDOUT;497 goto error;498 }499 }500 501 return 0;502error:503 amdtp_domain_stop(&tscm->domain);504 finish_session(tscm);505 506 return err;507}508 509void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm)510{511 if (tscm->substreams_counter == 0) {512 amdtp_domain_stop(&tscm->domain);513 finish_session(tscm);514 515 fw_iso_resources_free(&tscm->tx_resources);516 fw_iso_resources_free(&tscm->rx_resources);517 518 tscm->need_long_tx_init_skip = false;519 }520}521 522void snd_tscm_stream_lock_changed(struct snd_tscm *tscm)523{524 tscm->dev_lock_changed = true;525 wake_up(&tscm->hwdep_wait);526}527 528int snd_tscm_stream_lock_try(struct snd_tscm *tscm)529{530 int err;531 532 spin_lock_irq(&tscm->lock);533 534 /* user land lock this */535 if (tscm->dev_lock_count < 0) {536 err = -EBUSY;537 goto end;538 }539 540 /* this is the first time */541 if (tscm->dev_lock_count++ == 0)542 snd_tscm_stream_lock_changed(tscm);543 err = 0;544end:545 spin_unlock_irq(&tscm->lock);546 return err;547}548 549void snd_tscm_stream_lock_release(struct snd_tscm *tscm)550{551 spin_lock_irq(&tscm->lock);552 553 if (WARN_ON(tscm->dev_lock_count <= 0))554 goto end;555 if (--tscm->dev_lock_count == 0)556 snd_tscm_stream_lock_changed(tscm);557end:558 spin_unlock_irq(&tscm->lock);559}560