Skip to content

Commit bfcba28

Browse files
gune42tiwai
authored andcommitted
ALSA - hda: Add support for link audio time reporting
The HDA controller from SKL onwards support additional timestamp reporting of the link time. The link time is read from HW registers and converted to audio values. Signed-off-by: Guneshwor Singh <[email protected]> Signed-off-by: Hardik T Shah <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent 50279d9 commit bfcba28

File tree

1 file changed

+197
-1
lines changed

1 file changed

+197
-1
lines changed

sound/pci/hda/hda_controller.c

Lines changed: 197 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@
2727
#include <linux/module.h>
2828
#include <linux/pm_runtime.h>
2929
#include <linux/slab.h>
30+
31+
#ifdef CONFIG_X86
32+
/* for art-tsc conversion */
33+
#include <asm/tsc.h>
34+
#endif
35+
3036
#include <sound/core.h>
3137
#include <sound/initval.h>
3238
#include "hda_controller.h"
@@ -337,12 +343,173 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
337343
azx_get_position(chip, azx_dev));
338344
}
339345

346+
/*
347+
* azx_scale64: Scale base by mult/div while not overflowing sanely
348+
*
349+
* Derived from scale64_check_overflow in kernel/time/timekeeping.c
350+
*
351+
* The tmestamps for a 48Khz stream can overflow after (2^64/10^9)/48K which
352+
* is about 384307 ie ~4.5 days.
353+
*
354+
* This scales the calculation so that overflow will happen but after 2^64 /
355+
* 48000 secs, which is pretty large!
356+
*
357+
* In caln below:
358+
* base may overflow, but since there isn’t any additional division
359+
* performed on base it’s OK
360+
* rem can’t overflow because both are 32-bit values
361+
*/
362+
363+
#ifdef CONFIG_X86
364+
static u64 azx_scale64(u64 base, u32 num, u32 den)
365+
{
366+
u64 rem;
367+
368+
rem = do_div(base, den);
369+
370+
base *= num;
371+
rem *= num;
372+
373+
do_div(rem, den);
374+
375+
return base + rem;
376+
}
377+
378+
static int azx_get_sync_time(ktime_t *device,
379+
struct system_counterval_t *system, void *ctx)
380+
{
381+
struct snd_pcm_substream *substream = ctx;
382+
struct azx_dev *azx_dev = get_azx_dev(substream);
383+
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
384+
struct azx *chip = apcm->chip;
385+
struct snd_pcm_runtime *runtime;
386+
u64 ll_counter, ll_counter_l, ll_counter_h;
387+
u64 tsc_counter, tsc_counter_l, tsc_counter_h;
388+
u32 wallclk_ctr, wallclk_cycles;
389+
bool direction;
390+
u32 dma_select;
391+
u32 timeout = 200;
392+
u32 retry_count = 0;
393+
394+
runtime = substream->runtime;
395+
396+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
397+
direction = 1;
398+
else
399+
direction = 0;
400+
401+
/* 0th stream tag is not used, so DMA ch 0 is for 1st stream tag */
402+
do {
403+
timeout = 100;
404+
dma_select = (direction << GTSCC_CDMAS_DMA_DIR_SHIFT) |
405+
(azx_dev->core.stream_tag - 1);
406+
snd_hdac_chip_writel(azx_bus(chip), GTSCC, dma_select);
407+
408+
/* Enable the capture */
409+
snd_hdac_chip_updatel(azx_bus(chip), GTSCC, 0, GTSCC_TSCCI_MASK);
410+
411+
while (timeout) {
412+
if (snd_hdac_chip_readl(azx_bus(chip), GTSCC) &
413+
GTSCC_TSCCD_MASK)
414+
break;
415+
416+
timeout--;
417+
}
418+
419+
if (!timeout) {
420+
dev_err(chip->card->dev, "GTSCC capture Timedout!\n");
421+
return -EIO;
422+
}
423+
424+
/* Read wall clock counter */
425+
wallclk_ctr = snd_hdac_chip_readl(azx_bus(chip), WALFCC);
426+
427+
/* Read TSC counter */
428+
tsc_counter_l = snd_hdac_chip_readl(azx_bus(chip), TSCCL);
429+
tsc_counter_h = snd_hdac_chip_readl(azx_bus(chip), TSCCU);
430+
431+
/* Read Link counter */
432+
ll_counter_l = snd_hdac_chip_readl(azx_bus(chip), LLPCL);
433+
ll_counter_h = snd_hdac_chip_readl(azx_bus(chip), LLPCU);
434+
435+
/* Ack: registers read done */
436+
snd_hdac_chip_writel(azx_bus(chip), GTSCC, GTSCC_TSCCD_SHIFT);
437+
438+
tsc_counter = (tsc_counter_h << TSCCU_CCU_SHIFT) |
439+
tsc_counter_l;
440+
441+
ll_counter = (ll_counter_h << LLPC_CCU_SHIFT) | ll_counter_l;
442+
wallclk_cycles = wallclk_ctr & WALFCC_CIF_MASK;
443+
444+
/*
445+
* An error occurs near frame "rollover". The clocks in
446+
* frame value indicates whether this error may have
447+
* occurred. Here we use the value of 10 i.e.,
448+
* HDA_MAX_CYCLE_OFFSET
449+
*/
450+
if (wallclk_cycles < HDA_MAX_CYCLE_VALUE - HDA_MAX_CYCLE_OFFSET
451+
&& wallclk_cycles > HDA_MAX_CYCLE_OFFSET)
452+
break;
453+
454+
/*
455+
* Sleep before we read again, else we may again get
456+
* value near to MAX_CYCLE. Try to sleep for different
457+
* amount of time so we dont hit the same number again
458+
*/
459+
udelay(retry_count++);
460+
461+
} while (retry_count != HDA_MAX_CYCLE_READ_RETRY);
462+
463+
if (retry_count == HDA_MAX_CYCLE_READ_RETRY) {
464+
dev_err_ratelimited(chip->card->dev,
465+
"Error in WALFCC cycle count\n");
466+
return -EIO;
467+
}
468+
469+
*device = ns_to_ktime(azx_scale64(ll_counter,
470+
NSEC_PER_SEC, runtime->rate));
471+
*device = ktime_add_ns(*device, (wallclk_cycles * NSEC_PER_SEC) /
472+
((HDA_MAX_CYCLE_VALUE + 1) * runtime->rate));
473+
474+
*system = convert_art_to_tsc(tsc_counter);
475+
476+
return 0;
477+
}
478+
479+
#else
480+
static int azx_get_sync_time(ktime_t *device,
481+
struct system_counterval_t *system, void *ctx)
482+
{
483+
return -ENXIO;
484+
}
485+
#endif
486+
487+
static int azx_get_crosststamp(struct snd_pcm_substream *substream,
488+
struct system_device_crosststamp *xtstamp)
489+
{
490+
return get_device_system_crosststamp(azx_get_sync_time,
491+
substream, NULL, xtstamp);
492+
}
493+
494+
static inline bool is_link_time_supported(struct snd_pcm_runtime *runtime,
495+
struct snd_pcm_audio_tstamp_config *ts)
496+
{
497+
if (runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME)
498+
if (ts->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED)
499+
return true;
500+
501+
return false;
502+
}
503+
340504
static int azx_get_time_info(struct snd_pcm_substream *substream,
341505
struct timespec *system_ts, struct timespec *audio_ts,
342506
struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
343507
struct snd_pcm_audio_tstamp_report *audio_tstamp_report)
344508
{
345509
struct azx_dev *azx_dev = get_azx_dev(substream);
510+
struct snd_pcm_runtime *runtime = substream->runtime;
511+
struct system_device_crosststamp xtstamp;
512+
int ret;
346513
u64 nsec;
347514

348515
if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) &&
@@ -361,8 +528,37 @@ static int azx_get_time_info(struct snd_pcm_substream *substream,
361528
audio_tstamp_report->accuracy_report = 1; /* rest of structure is valid */
362529
audio_tstamp_report->accuracy = 42; /* 24 MHz WallClock == 42ns resolution */
363530

364-
} else
531+
} else if (is_link_time_supported(runtime, audio_tstamp_config)) {
532+
533+
ret = azx_get_crosststamp(substream, &xtstamp);
534+
if (ret)
535+
return ret;
536+
537+
switch (runtime->tstamp_type) {
538+
case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC:
539+
return -EINVAL;
540+
541+
case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW:
542+
*system_ts = ktime_to_timespec(xtstamp.sys_monoraw);
543+
break;
544+
545+
default:
546+
*system_ts = ktime_to_timespec(xtstamp.sys_realtime);
547+
break;
548+
549+
}
550+
551+
*audio_ts = ktime_to_timespec(xtstamp.device);
552+
553+
audio_tstamp_report->actual_type =
554+
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED;
555+
audio_tstamp_report->accuracy_report = 1;
556+
/* 24 MHz WallClock == 42ns resolution */
557+
audio_tstamp_report->accuracy = 42;
558+
559+
} else {
365560
audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
561+
}
366562

367563
return 0;
368564
}

0 commit comments

Comments
 (0)