Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f87e7f25 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: hda - Improved position reporting on SKL+



Apply the same methods to obtain the current stream position as ASoC
Intel SKL driver uses.  It reads the position from DPIB for a playback
stream while it still reads from the position buffer for a capture
stream.  For a capture stream, some ugly workaround is needed to
settle down the inconsistent position.

Acked-by: default avatarVinod Koul <vinod.koul@intel.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 70eafad8
Loading
Loading
Loading
Loading
+34 −2
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ enum {
	POS_FIX_POSBUF,
	POS_FIX_VIACOMBO,
	POS_FIX_COMBO,
	POS_FIX_SKL,
};

/* Defines for ATI HD Audio support in SB450 south bridge */
@@ -148,7 +149,7 @@ module_param_array(model, charp, NULL, 0444);
MODULE_PARM_DESC(model, "Use the given board model.");
module_param_array(position_fix, int, NULL, 0444);
MODULE_PARM_DESC(position_fix, "DMA pointer read method."
		 "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO).");
		 "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO, 5 = SKL+).");
module_param_array(bdl_pos_adj, int, NULL, 0644);
MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
module_param_array(probe_mask, int, NULL, 0444);
@@ -815,6 +816,31 @@ static unsigned int azx_via_get_position(struct azx *chip,
	return bound_pos + mod_dma_pos;
}

static unsigned int azx_skl_get_dpib_pos(struct azx *chip,
					 struct azx_dev *azx_dev)
{
	return _snd_hdac_chip_readl(azx_bus(chip),
				    AZX_REG_VS_SDXDPIB_XBASE +
				    (AZX_REG_VS_SDXDPIB_XINTERVAL *
				     azx_dev->core.index));
}

/* get the current DMA position with correction on SKL+ chips */
static unsigned int azx_get_pos_skl(struct azx *chip, struct azx_dev *azx_dev)
{
	/* DPIB register gives a more accurate position for playback */
	if (azx_dev->core.substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		return azx_skl_get_dpib_pos(chip, azx_dev);

	/* For capture, we need to read posbuf, but it requires a delay
	 * for the possible boundary overlap; the read of DPIB fetches the
	 * actual posbuf
	 */
	udelay(20);
	azx_skl_get_dpib_pos(chip, azx_dev);
	return azx_get_pos_posbuf(chip, azx_dev);
}

#ifdef CONFIG_PM
static DEFINE_MUTEX(card_list_lock);
static LIST_HEAD(card_list);
@@ -1351,6 +1377,7 @@ static int check_position_fix(struct azx *chip, int fix)
	case POS_FIX_POSBUF:
	case POS_FIX_VIACOMBO:
	case POS_FIX_COMBO:
	case POS_FIX_SKL:
		return fix;
	}

@@ -1371,6 +1398,10 @@ static int check_position_fix(struct azx *chip, int fix)
		dev_dbg(chip->card->dev, "Using LPIB position fix\n");
		return POS_FIX_LPIB;
	}
	if (IS_SKL_PLUS(chip->pci)) {
		dev_dbg(chip->card->dev, "Using SKL position fix\n");
		return POS_FIX_SKL;
	}
	return POS_FIX_AUTO;
}

@@ -1382,6 +1413,7 @@ static void assign_position_fix(struct azx *chip, int fix)
		[POS_FIX_POSBUF] = azx_get_pos_posbuf,
		[POS_FIX_VIACOMBO] = azx_via_get_position,
		[POS_FIX_COMBO] = azx_get_pos_lpib,
		[POS_FIX_SKL] = azx_get_pos_skl,
	};

	chip->get_position[0] = chip->get_position[1] = callbacks[fix];
@@ -1390,7 +1422,7 @@ static void assign_position_fix(struct azx *chip, int fix)
	if (fix == POS_FIX_COMBO)
		chip->get_position[1] = NULL;

	if (fix == POS_FIX_POSBUF &&
	if ((fix == POS_FIX_POSBUF || fix == POS_FIX_SKL) &&
	    (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
		chip->get_delay[0] = chip->get_delay[1] =
			azx_get_delay_from_lpib;