brintos

brintos / linux-shallow public Read only

0
0
Text · 17.0 KiB · 4c677c8 Raw
709 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * dice_stream.c - a part of driver for DICE based devices4 *5 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>6 * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>7 */8 9#include "dice.h"10 11#define	READY_TIMEOUT_MS	20012#define NOTIFICATION_TIMEOUT_MS	10013 14struct reg_params {15	unsigned int count;16	unsigned int size;17};18 19const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = {20	/* mode 0 */21	[0] =  32000,22	[1] =  44100,23	[2] =  48000,24	/* mode 1 */25	[3] =  88200,26	[4] =  96000,27	/* mode 2 */28	[5] = 176400,29	[6] = 192000,30};31 32int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,33				  enum snd_dice_rate_mode *mode)34{35	/* Corresponding to each entry in snd_dice_rates. */36	static const enum snd_dice_rate_mode modes[] = {37		[0] = SND_DICE_RATE_MODE_LOW,38		[1] = SND_DICE_RATE_MODE_LOW,39		[2] = SND_DICE_RATE_MODE_LOW,40		[3] = SND_DICE_RATE_MODE_MIDDLE,41		[4] = SND_DICE_RATE_MODE_MIDDLE,42		[5] = SND_DICE_RATE_MODE_HIGH,43		[6] = SND_DICE_RATE_MODE_HIGH,44	};45	int i;46 47	for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) {48		if (!(dice->clock_caps & BIT(i)))49			continue;50		if (snd_dice_rates[i] != rate)51			continue;52 53		*mode = modes[i];54		return 0;55	}56 57	return -EINVAL;58}59 60static int select_clock(struct snd_dice *dice, unsigned int rate)61{62	__be32 reg, new;63	u32 data;64	int i;65	int err;66 67	err = snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT,68					       &reg, sizeof(reg));69	if (err < 0)70		return err;71 72	data = be32_to_cpu(reg);73 74	data &= ~CLOCK_RATE_MASK;75	for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {76		if (snd_dice_rates[i] == rate)77			break;78	}79	if (i == ARRAY_SIZE(snd_dice_rates))80		return -EINVAL;81	data |= i << CLOCK_RATE_SHIFT;82 83	if (completion_done(&dice->clock_accepted))84		reinit_completion(&dice->clock_accepted);85 86	new = cpu_to_be32(data);87	err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,88						&new, sizeof(new));89	if (err < 0)90		return err;91 92	if (wait_for_completion_timeout(&dice->clock_accepted,93			msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) {94		if (reg != new)95			return -ETIMEDOUT;96	}97 98	return 0;99}100 101static int get_register_params(struct snd_dice *dice,102			       struct reg_params *tx_params,103			       struct reg_params *rx_params)104{105	__be32 reg[2];106	int err;107 108	err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, sizeof(reg));109	if (err < 0)110		return err;111	tx_params->count =112			min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);113	tx_params->size = be32_to_cpu(reg[1]) * 4;114 115	err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, sizeof(reg));116	if (err < 0)117		return err;118	rx_params->count =119			min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);120	rx_params->size = be32_to_cpu(reg[1]) * 4;121 122	return 0;123}124 125static void release_resources(struct snd_dice *dice)126{127	int i;128 129	for (i = 0; i < MAX_STREAMS; ++i) {130		fw_iso_resources_free(&dice->tx_resources[i]);131		fw_iso_resources_free(&dice->rx_resources[i]);132	}133}134 135static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,136			 struct reg_params *params)137{138	__be32 reg;139	unsigned int i;140 141	for (i = 0; i < params->count; i++) {142		reg = cpu_to_be32((u32)-1);143		if (dir == AMDTP_IN_STREAM) {144			snd_dice_transaction_write_tx(dice,145					params->size * i + TX_ISOCHRONOUS,146					&reg, sizeof(reg));147		} else {148			snd_dice_transaction_write_rx(dice,149					params->size * i + RX_ISOCHRONOUS,150					&reg, sizeof(reg));151		}152	}153}154 155static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream,156			  struct fw_iso_resources *resources, unsigned int rate,157			  unsigned int pcm_chs, unsigned int midi_ports)158{159	bool double_pcm_frames;160	unsigned int i;161	int err;162 163	// At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in164	// one data block of AMDTP packet. Thus sampling transfer frequency is165	// a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are166	// transferred on AMDTP packets at 96 kHz. Two successive samples of a167	// channel are stored consecutively in the packet. This quirk is called168	// as 'Dual Wire'.169	// For this quirk, blocking mode is required and PCM buffer size should170	// be aligned to SYT_INTERVAL.171	double_pcm_frames = (rate > 96000 && !dice->disable_double_pcm_frames);172	if (double_pcm_frames) {173		rate /= 2;174		pcm_chs *= 2;175	}176 177	err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports,178					 double_pcm_frames);179	if (err < 0)180		return err;181 182	if (double_pcm_frames) {183		pcm_chs /= 2;184 185		for (i = 0; i < pcm_chs; i++) {186			amdtp_am824_set_pcm_position(stream, i, i * 2);187			amdtp_am824_set_pcm_position(stream, i + pcm_chs,188						     i * 2 + 1);189		}190	}191 192	return fw_iso_resources_allocate(resources,193				amdtp_stream_get_max_payload(stream),194				fw_parent_device(dice->unit)->max_speed);195}196 197static int keep_dual_resources(struct snd_dice *dice, unsigned int rate,198			       enum amdtp_stream_direction dir,199			       struct reg_params *params)200{201	enum snd_dice_rate_mode mode;202	int i;203	int err;204 205	err = snd_dice_stream_get_rate_mode(dice, rate, &mode);206	if (err < 0)207		return err;208 209	for (i = 0; i < params->count; ++i) {210		__be32 reg[2];211		struct amdtp_stream *stream;212		struct fw_iso_resources *resources;213		unsigned int pcm_cache;214		unsigned int pcm_chs;215		unsigned int midi_ports;216 217		if (dir == AMDTP_IN_STREAM) {218			stream = &dice->tx_stream[i];219			resources = &dice->tx_resources[i];220 221			pcm_cache = dice->tx_pcm_chs[i][mode];222			err = snd_dice_transaction_read_tx(dice,223					params->size * i + TX_NUMBER_AUDIO,224					reg, sizeof(reg));225		} else {226			stream = &dice->rx_stream[i];227			resources = &dice->rx_resources[i];228 229			pcm_cache = dice->rx_pcm_chs[i][mode];230			err = snd_dice_transaction_read_rx(dice,231					params->size * i + RX_NUMBER_AUDIO,232					reg, sizeof(reg));233		}234		if (err < 0)235			return err;236		pcm_chs = be32_to_cpu(reg[0]);237		midi_ports = be32_to_cpu(reg[1]);238 239		// These are important for developer of this driver.240		if (pcm_chs != pcm_cache) {241			dev_info(&dice->unit->device,242				 "cache mismatch: pcm: %u:%u, midi: %u\n",243				 pcm_chs, pcm_cache, midi_ports);244			return -EPROTO;245		}246 247		err = keep_resources(dice, stream, resources, rate, pcm_chs,248				     midi_ports);249		if (err < 0)250			return err;251	}252 253	return 0;254}255 256static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,257			   struct reg_params *rx_params)258{259	stop_streams(dice, AMDTP_IN_STREAM, tx_params);260	stop_streams(dice, AMDTP_OUT_STREAM, rx_params);261 262	snd_dice_transaction_clear_enable(dice);263}264 265int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate,266				   unsigned int events_per_period,267				   unsigned int events_per_buffer)268{269	unsigned int curr_rate;270	int err;271 272	// Check sampling transmission frequency.273	err = snd_dice_transaction_get_rate(dice, &curr_rate);274	if (err < 0)275		return err;276	if (rate == 0)277		rate = curr_rate;278 279	if (dice->substreams_counter == 0 || curr_rate != rate) {280		struct reg_params tx_params, rx_params;281 282		amdtp_domain_stop(&dice->domain);283 284		err = get_register_params(dice, &tx_params, &rx_params);285		if (err < 0)286			return err;287		finish_session(dice, &tx_params, &rx_params);288 289		release_resources(dice);290 291		// Just after owning the unit (GLOBAL_OWNER), the unit can292		// return invalid stream formats. Selecting clock parameters293		// have an effect for the unit to refine it.294		err = select_clock(dice, rate);295		if (err < 0)296			return err;297 298		// After changing sampling transfer frequency, the value of299		// register can be changed.300		err = get_register_params(dice, &tx_params, &rx_params);301		if (err < 0)302			return err;303 304		err = keep_dual_resources(dice, rate, AMDTP_IN_STREAM,305					  &tx_params);306		if (err < 0)307			goto error;308 309		err = keep_dual_resources(dice, rate, AMDTP_OUT_STREAM,310					  &rx_params);311		if (err < 0)312			goto error;313 314		err = amdtp_domain_set_events_per_period(&dice->domain,315					events_per_period, events_per_buffer);316		if (err < 0)317			goto error;318	}319 320	return 0;321error:322	release_resources(dice);323	return err;324}325 326static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,327			 unsigned int rate, struct reg_params *params)328{329	unsigned int max_speed = fw_parent_device(dice->unit)->max_speed;330	int i;331	int err;332 333	for (i = 0; i < params->count; i++) {334		struct amdtp_stream *stream;335		struct fw_iso_resources *resources;336		__be32 reg;337 338		if (dir == AMDTP_IN_STREAM) {339			stream = dice->tx_stream + i;340			resources = dice->tx_resources + i;341		} else {342			stream = dice->rx_stream + i;343			resources = dice->rx_resources + i;344		}345 346		reg = cpu_to_be32(resources->channel);347		if (dir == AMDTP_IN_STREAM) {348			err = snd_dice_transaction_write_tx(dice,349					params->size * i + TX_ISOCHRONOUS,350					&reg, sizeof(reg));351		} else {352			err = snd_dice_transaction_write_rx(dice,353					params->size * i + RX_ISOCHRONOUS,354					&reg, sizeof(reg));355		}356		if (err < 0)357			return err;358 359		if (dir == AMDTP_IN_STREAM) {360			reg = cpu_to_be32(max_speed);361			err = snd_dice_transaction_write_tx(dice,362					params->size * i + TX_SPEED,363					&reg, sizeof(reg));364			if (err < 0)365				return err;366		}367 368		err = amdtp_domain_add_stream(&dice->domain, stream,369					      resources->channel, max_speed);370		if (err < 0)371			return err;372	}373 374	return 0;375}376 377/*378 * MEMO: After this function, there're two states of streams:379 *  - None streams are running.380 *  - All streams are running.381 */382int snd_dice_stream_start_duplex(struct snd_dice *dice)383{384	unsigned int generation = dice->rx_resources[0].generation;385	struct reg_params tx_params, rx_params;386	unsigned int i;387	unsigned int rate;388	enum snd_dice_rate_mode mode;389	int err;390 391	if (dice->substreams_counter == 0)392		return -EIO;393 394	err = get_register_params(dice, &tx_params, &rx_params);395	if (err < 0)396		return err;397 398	// Check error of packet streaming.399	for (i = 0; i < MAX_STREAMS; ++i) {400		if (amdtp_streaming_error(&dice->tx_stream[i]) ||401		    amdtp_streaming_error(&dice->rx_stream[i])) {402			amdtp_domain_stop(&dice->domain);403			finish_session(dice, &tx_params, &rx_params);404			break;405		}406	}407 408	if (generation != fw_parent_device(dice->unit)->card->generation) {409		for (i = 0; i < MAX_STREAMS; ++i) {410			if (i < tx_params.count)411				fw_iso_resources_update(dice->tx_resources + i);412			if (i < rx_params.count)413				fw_iso_resources_update(dice->rx_resources + i);414		}415	}416 417	// Check required streams are running or not.418	err = snd_dice_transaction_get_rate(dice, &rate);419	if (err < 0)420		return err;421	err = snd_dice_stream_get_rate_mode(dice, rate, &mode);422	if (err < 0)423		return err;424	for (i = 0; i < MAX_STREAMS; ++i) {425		if (dice->tx_pcm_chs[i][mode] > 0 &&426		    !amdtp_stream_running(&dice->tx_stream[i]))427			break;428		if (dice->rx_pcm_chs[i][mode] > 0 &&429		    !amdtp_stream_running(&dice->rx_stream[i]))430			break;431	}432	if (i < MAX_STREAMS) {433		// Start both streams.434		err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params);435		if (err < 0)436			goto error;437 438		err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params);439		if (err < 0)440			goto error;441 442		err = snd_dice_transaction_set_enable(dice);443		if (err < 0) {444			dev_err(&dice->unit->device,445				"fail to enable interface\n");446			goto error;447		}448 449		// MEMO: The device immediately starts packet transmission when enabled. Some450		// devices are strictly to generate any discontinuity in the sequence of tx packet451		// when they receives invalid sequence of presentation time in CIP header. The452		// sequence replay for media clock recovery can suppress the behaviour.453		err = amdtp_domain_start(&dice->domain, 0, true, false);454		if (err < 0)455			goto error;456 457		if (!amdtp_domain_wait_ready(&dice->domain, READY_TIMEOUT_MS)) {458			err = -ETIMEDOUT;459			goto error;460		}461	}462 463	return 0;464error:465	amdtp_domain_stop(&dice->domain);466	finish_session(dice, &tx_params, &rx_params);467	return err;468}469 470/*471 * MEMO: After this function, there're two states of streams:472 *  - None streams are running.473 *  - All streams are running.474 */475void snd_dice_stream_stop_duplex(struct snd_dice *dice)476{477	struct reg_params tx_params, rx_params;478 479	if (dice->substreams_counter == 0) {480		if (get_register_params(dice, &tx_params, &rx_params) >= 0)481			finish_session(dice, &tx_params, &rx_params);482 483		amdtp_domain_stop(&dice->domain);484		release_resources(dice);485	}486}487 488static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir,489		       unsigned int index)490{491	struct amdtp_stream *stream;492	struct fw_iso_resources *resources;493	int err;494 495	if (dir == AMDTP_IN_STREAM) {496		stream = &dice->tx_stream[index];497		resources = &dice->tx_resources[index];498	} else {499		stream = &dice->rx_stream[index];500		resources = &dice->rx_resources[index];501	}502 503	err = fw_iso_resources_init(resources, dice->unit);504	if (err < 0)505		goto end;506	resources->channels_mask = 0x00000000ffffffffuLL;507 508	err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING);509	if (err < 0) {510		amdtp_stream_destroy(stream);511		fw_iso_resources_destroy(resources);512	}513end:514	return err;515}516 517/*518 * This function should be called before starting streams or after stopping519 * streams.520 */521static void destroy_stream(struct snd_dice *dice,522			   enum amdtp_stream_direction dir,523			   unsigned int index)524{525	struct amdtp_stream *stream;526	struct fw_iso_resources *resources;527 528	if (dir == AMDTP_IN_STREAM) {529		stream = &dice->tx_stream[index];530		resources = &dice->tx_resources[index];531	} else {532		stream = &dice->rx_stream[index];533		resources = &dice->rx_resources[index];534	}535 536	amdtp_stream_destroy(stream);537	fw_iso_resources_destroy(resources);538}539 540int snd_dice_stream_init_duplex(struct snd_dice *dice)541{542	int i, err;543 544	for (i = 0; i < MAX_STREAMS; i++) {545		err = init_stream(dice, AMDTP_IN_STREAM, i);546		if (err < 0) {547			for (; i >= 0; i--)548				destroy_stream(dice, AMDTP_IN_STREAM, i);549			goto end;550		}551	}552 553	for (i = 0; i < MAX_STREAMS; i++) {554		err = init_stream(dice, AMDTP_OUT_STREAM, i);555		if (err < 0) {556			for (; i >= 0; i--)557				destroy_stream(dice, AMDTP_OUT_STREAM, i);558			for (i = 0; i < MAX_STREAMS; i++)559				destroy_stream(dice, AMDTP_IN_STREAM, i);560			goto end;561		}562	}563 564	err = amdtp_domain_init(&dice->domain);565	if (err < 0) {566		for (i = 0; i < MAX_STREAMS; ++i) {567			destroy_stream(dice, AMDTP_OUT_STREAM, i);568			destroy_stream(dice, AMDTP_IN_STREAM, i);569		}570	}571end:572	return err;573}574 575void snd_dice_stream_destroy_duplex(struct snd_dice *dice)576{577	unsigned int i;578 579	for (i = 0; i < MAX_STREAMS; i++) {580		destroy_stream(dice, AMDTP_IN_STREAM, i);581		destroy_stream(dice, AMDTP_OUT_STREAM, i);582	}583 584	amdtp_domain_destroy(&dice->domain);585}586 587void snd_dice_stream_update_duplex(struct snd_dice *dice)588{589	struct reg_params tx_params, rx_params;590 591	/*592	 * On a bus reset, the DICE firmware disables streaming and then goes593	 * off contemplating its own navel for hundreds of milliseconds before594	 * it can react to any of our attempts to reenable streaming.  This595	 * means that we lose synchronization anyway, so we force our streams596	 * to stop so that the application can restart them in an orderly597	 * manner.598	 */599	dice->global_enabled = false;600 601	if (get_register_params(dice, &tx_params, &rx_params) == 0) {602		amdtp_domain_stop(&dice->domain);603 604		stop_streams(dice, AMDTP_IN_STREAM, &tx_params);605		stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);606	}607}608 609int snd_dice_stream_detect_current_formats(struct snd_dice *dice)610{611	unsigned int rate;612	enum snd_dice_rate_mode mode;613	__be32 reg[2];614	struct reg_params tx_params, rx_params;615	int i;616	int err;617 618	/* If extended protocol is available, detect detail spec. */619	err = snd_dice_detect_extension_formats(dice);620	if (err >= 0)621		return err;622 623	/*624	 * Available stream format is restricted at current mode of sampling625	 * clock.626	 */627	err = snd_dice_transaction_get_rate(dice, &rate);628	if (err < 0)629		return err;630 631	err = snd_dice_stream_get_rate_mode(dice, rate, &mode);632	if (err < 0)633		return err;634 635	/*636	 * Just after owning the unit (GLOBAL_OWNER), the unit can return637	 * invalid stream formats. Selecting clock parameters have an effect638	 * for the unit to refine it.639	 */640	err = select_clock(dice, rate);641	if (err < 0)642		return err;643 644	err = get_register_params(dice, &tx_params, &rx_params);645	if (err < 0)646		return err;647 648	for (i = 0; i < tx_params.count; ++i) {649		err = snd_dice_transaction_read_tx(dice,650				tx_params.size * i + TX_NUMBER_AUDIO,651				reg, sizeof(reg));652		if (err < 0)653			return err;654		dice->tx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);655		dice->tx_midi_ports[i] = max_t(unsigned int,656				be32_to_cpu(reg[1]), dice->tx_midi_ports[i]);657	}658	for (i = 0; i < rx_params.count; ++i) {659		err = snd_dice_transaction_read_rx(dice,660				rx_params.size * i + RX_NUMBER_AUDIO,661				reg, sizeof(reg));662		if (err < 0)663			return err;664		dice->rx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);665		dice->rx_midi_ports[i] = max_t(unsigned int,666				be32_to_cpu(reg[1]), dice->rx_midi_ports[i]);667	}668 669	return 0;670}671 672static void dice_lock_changed(struct snd_dice *dice)673{674	dice->dev_lock_changed = true;675	wake_up(&dice->hwdep_wait);676}677 678int snd_dice_stream_lock_try(struct snd_dice *dice)679{680	int err;681 682	spin_lock_irq(&dice->lock);683 684	if (dice->dev_lock_count < 0) {685		err = -EBUSY;686		goto out;687	}688 689	if (dice->dev_lock_count++ == 0)690		dice_lock_changed(dice);691	err = 0;692out:693	spin_unlock_irq(&dice->lock);694	return err;695}696 697void snd_dice_stream_lock_release(struct snd_dice *dice)698{699	spin_lock_irq(&dice->lock);700 701	if (WARN_ON(dice->dev_lock_count <= 0))702		goto out;703 704	if (--dice->dev_lock_count == 0)705		dice_lock_changed(dice);706out:707	spin_unlock_irq(&dice->lock);708}709