Unverified Commit d8b3e396 authored by Martin Povišer's avatar Martin Povišer Committed by Mark Brown
Browse files

ASoC: apple: mca: Fix SERDES reset sequence



Fix the reset sequence of reads and writes that we invoke from within
the early trigger. It looks like there never was a SERDES_CONF_SOME_RST
bit that should be involved in the reset sequence, and its presence in
the driver code is a mistake from earlier.

Instead, the reset sequence should go as follows: We should switch the
the SERDES unit's SYNC_SEL mux to the value of 7 (so outside the range
of 1...6 representing cluster's SYNCGEN units), then raise the RST bit
in SERDES_STATUS and wait for it to clear.

Properly resetting the SERDES unit fixes frame desynchronization hazard
in case of long frames (longer than 4 used slots). The desynchronization
manifests itself by rotating the PCM channels.

Fixes: 3df5d0d9 ("ASoC: apple: mca: Start new platform driver")
Signed-off-by: default avatarMartin Povišer <povik+lin@cutebit.org>
Link: https://lore.kernel.org/r/20230224153302.45365-2-povik+lin@cutebit.org


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent aaf5f0d7
Loading
Loading
Loading
Loading
+13 −5
Original line number Diff line number Diff line
@@ -101,7 +101,6 @@
#define SERDES_CONF_UNK3	BIT(14)
#define SERDES_CONF_NO_DATA_FEEDBACK	BIT(15)
#define SERDES_CONF_SYNC_SEL	GENMASK(18, 16)
#define SERDES_CONF_SOME_RST	BIT(19)
#define REG_TX_SERDES_BITSTART	0x08
#define REG_RX_SERDES_BITSTART	0x0c
#define REG_TX_SERDES_SLOTMASK	0x0c
@@ -203,15 +202,24 @@ static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd,
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
			   FIELD_PREP(SERDES_CONF_SYNC_SEL, 0));
		mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
			   FIELD_PREP(SERDES_CONF_SYNC_SEL, 7));
		mca_modify(cl, serdes_unit + REG_SERDES_STATUS,
			   SERDES_STATUS_EN | SERDES_STATUS_RST,
			   SERDES_STATUS_RST);
		mca_modify(cl, serdes_conf, SERDES_CONF_SOME_RST,
			   SERDES_CONF_SOME_RST);
		readl_relaxed(cl->base + serdes_conf);
		mca_modify(cl, serdes_conf, SERDES_STATUS_RST, 0);
		/*
		 * Experiments suggest that it takes at most ~1 us
		 * for the bit to clear, so wait 2 us for good measure.
		 */
		udelay(2);
		WARN_ON(readl_relaxed(cl->base + serdes_unit + REG_SERDES_STATUS) &
			SERDES_STATUS_RST);
		mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
			   FIELD_PREP(SERDES_CONF_SYNC_SEL, 0));
		mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
			   FIELD_PREP(SERDES_CONF_SYNC_SEL, cl->no + 1));
		break;
	default:
		break;