162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Implementation of primary alsa driver code base for Intel HD Audio.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  Copyright(c) 2004 Intel Corporation. All rights reserved.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
962306a36Sopenharmony_ci *                     PeiSen Hou <pshou@realtek.com.tw>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/clocksource.h>
1362306a36Sopenharmony_ci#include <linux/delay.h>
1462306a36Sopenharmony_ci#include <linux/interrupt.h>
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#ifdef CONFIG_X86
2162306a36Sopenharmony_ci/* for art-tsc conversion */
2262306a36Sopenharmony_ci#include <asm/tsc.h>
2362306a36Sopenharmony_ci#endif
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <sound/core.h>
2662306a36Sopenharmony_ci#include <sound/initval.h>
2762306a36Sopenharmony_ci#include "hda_controller.h"
2862306a36Sopenharmony_ci#include "hda_local.h"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
3162306a36Sopenharmony_ci#include "hda_controller_trace.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* DSP lock helpers */
3462306a36Sopenharmony_ci#define dsp_lock(dev)		snd_hdac_dsp_lock(azx_stream(dev))
3562306a36Sopenharmony_ci#define dsp_unlock(dev)		snd_hdac_dsp_unlock(azx_stream(dev))
3662306a36Sopenharmony_ci#define dsp_is_locked(dev)	snd_hdac_stream_is_locked(azx_stream(dev))
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/* assign a stream for the PCM */
3962306a36Sopenharmony_cistatic inline struct azx_dev *
4062306a36Sopenharmony_ciazx_assign_device(struct azx *chip, struct snd_pcm_substream *substream)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	struct hdac_stream *s;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	s = snd_hdac_stream_assign(azx_bus(chip), substream);
4562306a36Sopenharmony_ci	if (!s)
4662306a36Sopenharmony_ci		return NULL;
4762306a36Sopenharmony_ci	return stream_to_azx_dev(s);
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/* release the assigned stream */
5162306a36Sopenharmony_cistatic inline void azx_release_device(struct azx_dev *azx_dev)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	snd_hdac_stream_release(azx_stream(azx_dev));
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic inline struct hda_pcm_stream *
5762306a36Sopenharmony_cito_hda_pcm_stream(struct snd_pcm_substream *substream)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
6062306a36Sopenharmony_ci	return &apcm->info->stream[substream->stream];
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream,
6462306a36Sopenharmony_ci				u64 nsec)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
6762306a36Sopenharmony_ci	struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
6862306a36Sopenharmony_ci	u64 codec_frames, codec_nsecs;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	if (!hinfo->ops.get_delay)
7162306a36Sopenharmony_ci		return nsec;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	codec_frames = hinfo->ops.get_delay(hinfo, apcm->codec, substream);
7462306a36Sopenharmony_ci	codec_nsecs = div_u64(codec_frames * 1000000000LL,
7562306a36Sopenharmony_ci			      substream->runtime->rate);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
7862306a36Sopenharmony_ci		return nsec + codec_nsecs;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/*
8462306a36Sopenharmony_ci * PCM ops
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic int azx_pcm_close(struct snd_pcm_substream *substream)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
9062306a36Sopenharmony_ci	struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
9162306a36Sopenharmony_ci	struct azx *chip = apcm->chip;
9262306a36Sopenharmony_ci	struct azx_dev *azx_dev = get_azx_dev(substream);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	trace_azx_pcm_close(chip, azx_dev);
9562306a36Sopenharmony_ci	mutex_lock(&chip->open_mutex);
9662306a36Sopenharmony_ci	azx_release_device(azx_dev);
9762306a36Sopenharmony_ci	if (hinfo->ops.close)
9862306a36Sopenharmony_ci		hinfo->ops.close(hinfo, apcm->codec, substream);
9962306a36Sopenharmony_ci	snd_hda_power_down(apcm->codec);
10062306a36Sopenharmony_ci	mutex_unlock(&chip->open_mutex);
10162306a36Sopenharmony_ci	snd_hda_codec_pcm_put(apcm->info);
10262306a36Sopenharmony_ci	return 0;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic int azx_pcm_hw_params(struct snd_pcm_substream *substream,
10662306a36Sopenharmony_ci			     struct snd_pcm_hw_params *hw_params)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
10962306a36Sopenharmony_ci	struct azx *chip = apcm->chip;
11062306a36Sopenharmony_ci	struct azx_dev *azx_dev = get_azx_dev(substream);
11162306a36Sopenharmony_ci	int ret = 0;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	trace_azx_pcm_hw_params(chip, azx_dev);
11462306a36Sopenharmony_ci	dsp_lock(azx_dev);
11562306a36Sopenharmony_ci	if (dsp_is_locked(azx_dev)) {
11662306a36Sopenharmony_ci		ret = -EBUSY;
11762306a36Sopenharmony_ci		goto unlock;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	azx_dev->core.bufsize = 0;
12162306a36Sopenharmony_ci	azx_dev->core.period_bytes = 0;
12262306a36Sopenharmony_ci	azx_dev->core.format_val = 0;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ciunlock:
12562306a36Sopenharmony_ci	dsp_unlock(azx_dev);
12662306a36Sopenharmony_ci	return ret;
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic int azx_pcm_hw_free(struct snd_pcm_substream *substream)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
13262306a36Sopenharmony_ci	struct azx_dev *azx_dev = get_azx_dev(substream);
13362306a36Sopenharmony_ci	struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/* reset BDL address */
13662306a36Sopenharmony_ci	dsp_lock(azx_dev);
13762306a36Sopenharmony_ci	if (!dsp_is_locked(azx_dev))
13862306a36Sopenharmony_ci		snd_hdac_stream_cleanup(azx_stream(azx_dev));
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	azx_stream(azx_dev)->prepared = 0;
14362306a36Sopenharmony_ci	dsp_unlock(azx_dev);
14462306a36Sopenharmony_ci	return 0;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic int azx_pcm_prepare(struct snd_pcm_substream *substream)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
15062306a36Sopenharmony_ci	struct azx *chip = apcm->chip;
15162306a36Sopenharmony_ci	struct azx_dev *azx_dev = get_azx_dev(substream);
15262306a36Sopenharmony_ci	struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
15362306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
15462306a36Sopenharmony_ci	unsigned int format_val, stream_tag;
15562306a36Sopenharmony_ci	int err;
15662306a36Sopenharmony_ci	struct hda_spdif_out *spdif =
15762306a36Sopenharmony_ci		snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid);
15862306a36Sopenharmony_ci	unsigned short ctls = spdif ? spdif->ctls : 0;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	trace_azx_pcm_prepare(chip, azx_dev);
16162306a36Sopenharmony_ci	dsp_lock(azx_dev);
16262306a36Sopenharmony_ci	if (dsp_is_locked(azx_dev)) {
16362306a36Sopenharmony_ci		err = -EBUSY;
16462306a36Sopenharmony_ci		goto unlock;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	snd_hdac_stream_reset(azx_stream(azx_dev));
16862306a36Sopenharmony_ci	format_val = snd_hdac_calc_stream_format(runtime->rate,
16962306a36Sopenharmony_ci						runtime->channels,
17062306a36Sopenharmony_ci						runtime->format,
17162306a36Sopenharmony_ci						hinfo->maxbps,
17262306a36Sopenharmony_ci						ctls);
17362306a36Sopenharmony_ci	if (!format_val) {
17462306a36Sopenharmony_ci		dev_err(chip->card->dev,
17562306a36Sopenharmony_ci			"invalid format_val, rate=%d, ch=%d, format=%d\n",
17662306a36Sopenharmony_ci			runtime->rate, runtime->channels, runtime->format);
17762306a36Sopenharmony_ci		err = -EINVAL;
17862306a36Sopenharmony_ci		goto unlock;
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	err = snd_hdac_stream_set_params(azx_stream(azx_dev), format_val);
18262306a36Sopenharmony_ci	if (err < 0)
18362306a36Sopenharmony_ci		goto unlock;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	snd_hdac_stream_setup(azx_stream(azx_dev));
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	stream_tag = azx_dev->core.stream_tag;
18862306a36Sopenharmony_ci	/* CA-IBG chips need the playback stream starting from 1 */
18962306a36Sopenharmony_ci	if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) &&
19062306a36Sopenharmony_ci	    stream_tag > chip->capture_streams)
19162306a36Sopenharmony_ci		stream_tag -= chip->capture_streams;
19262306a36Sopenharmony_ci	err = snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
19362306a36Sopenharmony_ci				     azx_dev->core.format_val, substream);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci unlock:
19662306a36Sopenharmony_ci	if (!err)
19762306a36Sopenharmony_ci		azx_stream(azx_dev)->prepared = 1;
19862306a36Sopenharmony_ci	dsp_unlock(azx_dev);
19962306a36Sopenharmony_ci	return err;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
20562306a36Sopenharmony_ci	struct azx *chip = apcm->chip;
20662306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
20762306a36Sopenharmony_ci	struct azx_dev *azx_dev;
20862306a36Sopenharmony_ci	struct snd_pcm_substream *s;
20962306a36Sopenharmony_ci	struct hdac_stream *hstr;
21062306a36Sopenharmony_ci	bool start;
21162306a36Sopenharmony_ci	int sbits = 0;
21262306a36Sopenharmony_ci	int sync_reg;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	azx_dev = get_azx_dev(substream);
21562306a36Sopenharmony_ci	trace_azx_pcm_trigger(chip, azx_dev, cmd);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	hstr = azx_stream(azx_dev);
21862306a36Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
21962306a36Sopenharmony_ci		sync_reg = AZX_REG_OLD_SSYNC;
22062306a36Sopenharmony_ci	else
22162306a36Sopenharmony_ci		sync_reg = AZX_REG_SSYNC;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	if (dsp_is_locked(azx_dev) || !hstr->prepared)
22462306a36Sopenharmony_ci		return -EPIPE;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	switch (cmd) {
22762306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
22862306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
22962306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
23062306a36Sopenharmony_ci		start = true;
23162306a36Sopenharmony_ci		break;
23262306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
23362306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
23462306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
23562306a36Sopenharmony_ci		start = false;
23662306a36Sopenharmony_ci		break;
23762306a36Sopenharmony_ci	default:
23862306a36Sopenharmony_ci		return -EINVAL;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	snd_pcm_group_for_each_entry(s, substream) {
24262306a36Sopenharmony_ci		if (s->pcm->card != substream->pcm->card)
24362306a36Sopenharmony_ci			continue;
24462306a36Sopenharmony_ci		azx_dev = get_azx_dev(s);
24562306a36Sopenharmony_ci		sbits |= 1 << azx_dev->core.index;
24662306a36Sopenharmony_ci		snd_pcm_trigger_done(s, substream);
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	spin_lock(&bus->reg_lock);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/* first, set SYNC bits of corresponding streams */
25262306a36Sopenharmony_ci	snd_hdac_stream_sync_trigger(hstr, true, sbits, sync_reg);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	snd_pcm_group_for_each_entry(s, substream) {
25562306a36Sopenharmony_ci		if (s->pcm->card != substream->pcm->card)
25662306a36Sopenharmony_ci			continue;
25762306a36Sopenharmony_ci		azx_dev = get_azx_dev(s);
25862306a36Sopenharmony_ci		if (start) {
25962306a36Sopenharmony_ci			azx_dev->insufficient = 1;
26062306a36Sopenharmony_ci			snd_hdac_stream_start(azx_stream(azx_dev));
26162306a36Sopenharmony_ci		} else {
26262306a36Sopenharmony_ci			snd_hdac_stream_stop(azx_stream(azx_dev));
26362306a36Sopenharmony_ci		}
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci	spin_unlock(&bus->reg_lock);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	snd_hdac_stream_sync(hstr, start, sbits);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	spin_lock(&bus->reg_lock);
27062306a36Sopenharmony_ci	/* reset SYNC bits */
27162306a36Sopenharmony_ci	snd_hdac_stream_sync_trigger(hstr, false, sbits, sync_reg);
27262306a36Sopenharmony_ci	if (start)
27362306a36Sopenharmony_ci		snd_hdac_stream_timecounter_init(hstr, sbits);
27462306a36Sopenharmony_ci	spin_unlock(&bus->reg_lock);
27562306a36Sopenharmony_ci	return 0;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ciunsigned int azx_get_pos_lpib(struct azx *chip, struct azx_dev *azx_dev)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	return snd_hdac_stream_get_pos_lpib(azx_stream(azx_dev));
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_get_pos_lpib);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ciunsigned int azx_get_pos_posbuf(struct azx *chip, struct azx_dev *azx_dev)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	return snd_hdac_stream_get_pos_posbuf(azx_stream(azx_dev));
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_get_pos_posbuf);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ciunsigned int azx_get_position(struct azx *chip,
29162306a36Sopenharmony_ci			      struct azx_dev *azx_dev)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	struct snd_pcm_substream *substream = azx_dev->core.substream;
29462306a36Sopenharmony_ci	unsigned int pos;
29562306a36Sopenharmony_ci	int stream = substream->stream;
29662306a36Sopenharmony_ci	int delay = 0;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (chip->get_position[stream])
29962306a36Sopenharmony_ci		pos = chip->get_position[stream](chip, azx_dev);
30062306a36Sopenharmony_ci	else /* use the position buffer as default */
30162306a36Sopenharmony_ci		pos = azx_get_pos_posbuf(chip, azx_dev);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (pos >= azx_dev->core.bufsize)
30462306a36Sopenharmony_ci		pos = 0;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	if (substream->runtime) {
30762306a36Sopenharmony_ci		struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
30862306a36Sopenharmony_ci		struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci		if (chip->get_delay[stream])
31162306a36Sopenharmony_ci			delay += chip->get_delay[stream](chip, azx_dev, pos);
31262306a36Sopenharmony_ci		if (hinfo->ops.get_delay)
31362306a36Sopenharmony_ci			delay += hinfo->ops.get_delay(hinfo, apcm->codec,
31462306a36Sopenharmony_ci						      substream);
31562306a36Sopenharmony_ci		substream->runtime->delay = delay;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	trace_azx_get_position(chip, azx_dev, pos, delay);
31962306a36Sopenharmony_ci	return pos;
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_get_position);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
32662306a36Sopenharmony_ci	struct azx *chip = apcm->chip;
32762306a36Sopenharmony_ci	struct azx_dev *azx_dev = get_azx_dev(substream);
32862306a36Sopenharmony_ci	return bytes_to_frames(substream->runtime,
32962306a36Sopenharmony_ci			       azx_get_position(chip, azx_dev));
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci/*
33362306a36Sopenharmony_ci * azx_scale64: Scale base by mult/div while not overflowing sanely
33462306a36Sopenharmony_ci *
33562306a36Sopenharmony_ci * Derived from scale64_check_overflow in kernel/time/timekeeping.c
33662306a36Sopenharmony_ci *
33762306a36Sopenharmony_ci * The tmestamps for a 48Khz stream can overflow after (2^64/10^9)/48K which
33862306a36Sopenharmony_ci * is about 384307 ie ~4.5 days.
33962306a36Sopenharmony_ci *
34062306a36Sopenharmony_ci * This scales the calculation so that overflow will happen but after 2^64 /
34162306a36Sopenharmony_ci * 48000 secs, which is pretty large!
34262306a36Sopenharmony_ci *
34362306a36Sopenharmony_ci * In caln below:
34462306a36Sopenharmony_ci *	base may overflow, but since there isn’t any additional division
34562306a36Sopenharmony_ci *	performed on base it’s OK
34662306a36Sopenharmony_ci *	rem can’t overflow because both are 32-bit values
34762306a36Sopenharmony_ci */
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci#ifdef CONFIG_X86
35062306a36Sopenharmony_cistatic u64 azx_scale64(u64 base, u32 num, u32 den)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	u64 rem;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	rem = do_div(base, den);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	base *= num;
35762306a36Sopenharmony_ci	rem *= num;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	do_div(rem, den);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	return base + rem;
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic int azx_get_sync_time(ktime_t *device,
36562306a36Sopenharmony_ci		struct system_counterval_t *system, void *ctx)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	struct snd_pcm_substream *substream = ctx;
36862306a36Sopenharmony_ci	struct azx_dev *azx_dev = get_azx_dev(substream);
36962306a36Sopenharmony_ci	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
37062306a36Sopenharmony_ci	struct azx *chip = apcm->chip;
37162306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime;
37262306a36Sopenharmony_ci	u64 ll_counter, ll_counter_l, ll_counter_h;
37362306a36Sopenharmony_ci	u64 tsc_counter, tsc_counter_l, tsc_counter_h;
37462306a36Sopenharmony_ci	u32 wallclk_ctr, wallclk_cycles;
37562306a36Sopenharmony_ci	bool direction;
37662306a36Sopenharmony_ci	u32 dma_select;
37762306a36Sopenharmony_ci	u32 timeout;
37862306a36Sopenharmony_ci	u32 retry_count = 0;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	runtime = substream->runtime;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
38362306a36Sopenharmony_ci		direction = 1;
38462306a36Sopenharmony_ci	else
38562306a36Sopenharmony_ci		direction = 0;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	/* 0th stream tag is not used, so DMA ch 0 is for 1st stream tag */
38862306a36Sopenharmony_ci	do {
38962306a36Sopenharmony_ci		timeout = 100;
39062306a36Sopenharmony_ci		dma_select = (direction << GTSCC_CDMAS_DMA_DIR_SHIFT) |
39162306a36Sopenharmony_ci					(azx_dev->core.stream_tag - 1);
39262306a36Sopenharmony_ci		snd_hdac_chip_writel(azx_bus(chip), GTSCC, dma_select);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		/* Enable the capture */
39562306a36Sopenharmony_ci		snd_hdac_chip_updatel(azx_bus(chip), GTSCC, 0, GTSCC_TSCCI_MASK);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci		while (timeout) {
39862306a36Sopenharmony_ci			if (snd_hdac_chip_readl(azx_bus(chip), GTSCC) &
39962306a36Sopenharmony_ci						GTSCC_TSCCD_MASK)
40062306a36Sopenharmony_ci				break;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci			timeout--;
40362306a36Sopenharmony_ci		}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci		if (!timeout) {
40662306a36Sopenharmony_ci			dev_err(chip->card->dev, "GTSCC capture Timedout!\n");
40762306a36Sopenharmony_ci			return -EIO;
40862306a36Sopenharmony_ci		}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		/* Read wall clock counter */
41162306a36Sopenharmony_ci		wallclk_ctr = snd_hdac_chip_readl(azx_bus(chip), WALFCC);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		/* Read TSC counter */
41462306a36Sopenharmony_ci		tsc_counter_l = snd_hdac_chip_readl(azx_bus(chip), TSCCL);
41562306a36Sopenharmony_ci		tsc_counter_h = snd_hdac_chip_readl(azx_bus(chip), TSCCU);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci		/* Read Link counter */
41862306a36Sopenharmony_ci		ll_counter_l = snd_hdac_chip_readl(azx_bus(chip), LLPCL);
41962306a36Sopenharmony_ci		ll_counter_h = snd_hdac_chip_readl(azx_bus(chip), LLPCU);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci		/* Ack: registers read done */
42262306a36Sopenharmony_ci		snd_hdac_chip_writel(azx_bus(chip), GTSCC, GTSCC_TSCCD_SHIFT);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci		tsc_counter = (tsc_counter_h << TSCCU_CCU_SHIFT) |
42562306a36Sopenharmony_ci						tsc_counter_l;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci		ll_counter = (ll_counter_h << LLPC_CCU_SHIFT) |	ll_counter_l;
42862306a36Sopenharmony_ci		wallclk_cycles = wallclk_ctr & WALFCC_CIF_MASK;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci		/*
43162306a36Sopenharmony_ci		 * An error occurs near frame "rollover". The clocks in
43262306a36Sopenharmony_ci		 * frame value indicates whether this error may have
43362306a36Sopenharmony_ci		 * occurred. Here we use the value of 10 i.e.,
43462306a36Sopenharmony_ci		 * HDA_MAX_CYCLE_OFFSET
43562306a36Sopenharmony_ci		 */
43662306a36Sopenharmony_ci		if (wallclk_cycles < HDA_MAX_CYCLE_VALUE - HDA_MAX_CYCLE_OFFSET
43762306a36Sopenharmony_ci					&& wallclk_cycles > HDA_MAX_CYCLE_OFFSET)
43862306a36Sopenharmony_ci			break;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci		/*
44162306a36Sopenharmony_ci		 * Sleep before we read again, else we may again get
44262306a36Sopenharmony_ci		 * value near to MAX_CYCLE. Try to sleep for different
44362306a36Sopenharmony_ci		 * amount of time so we dont hit the same number again
44462306a36Sopenharmony_ci		 */
44562306a36Sopenharmony_ci		udelay(retry_count++);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	} while (retry_count != HDA_MAX_CYCLE_READ_RETRY);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	if (retry_count == HDA_MAX_CYCLE_READ_RETRY) {
45062306a36Sopenharmony_ci		dev_err_ratelimited(chip->card->dev,
45162306a36Sopenharmony_ci			"Error in WALFCC cycle count\n");
45262306a36Sopenharmony_ci		return -EIO;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	*device = ns_to_ktime(azx_scale64(ll_counter,
45662306a36Sopenharmony_ci				NSEC_PER_SEC, runtime->rate));
45762306a36Sopenharmony_ci	*device = ktime_add_ns(*device, (wallclk_cycles * NSEC_PER_SEC) /
45862306a36Sopenharmony_ci			       ((HDA_MAX_CYCLE_VALUE + 1) * runtime->rate));
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	*system = convert_art_to_tsc(tsc_counter);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	return 0;
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci#else
46662306a36Sopenharmony_cistatic int azx_get_sync_time(ktime_t *device,
46762306a36Sopenharmony_ci		struct system_counterval_t *system, void *ctx)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	return -ENXIO;
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci#endif
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic int azx_get_crosststamp(struct snd_pcm_substream *substream,
47462306a36Sopenharmony_ci			      struct system_device_crosststamp *xtstamp)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	return get_device_system_crosststamp(azx_get_sync_time,
47762306a36Sopenharmony_ci					substream, NULL, xtstamp);
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic inline bool is_link_time_supported(struct snd_pcm_runtime *runtime,
48162306a36Sopenharmony_ci				struct snd_pcm_audio_tstamp_config *ts)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	if (runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME)
48462306a36Sopenharmony_ci		if (ts->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED)
48562306a36Sopenharmony_ci			return true;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	return false;
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic int azx_get_time_info(struct snd_pcm_substream *substream,
49162306a36Sopenharmony_ci			struct timespec64 *system_ts, struct timespec64 *audio_ts,
49262306a36Sopenharmony_ci			struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
49362306a36Sopenharmony_ci			struct snd_pcm_audio_tstamp_report *audio_tstamp_report)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct azx_dev *azx_dev = get_azx_dev(substream);
49662306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
49762306a36Sopenharmony_ci	struct system_device_crosststamp xtstamp;
49862306a36Sopenharmony_ci	int ret;
49962306a36Sopenharmony_ci	u64 nsec;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) &&
50262306a36Sopenharmony_ci		(audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) {
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci		snd_pcm_gettime(substream->runtime, system_ts);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci		nsec = timecounter_read(&azx_dev->core.tc);
50762306a36Sopenharmony_ci		if (audio_tstamp_config->report_delay)
50862306a36Sopenharmony_ci			nsec = azx_adjust_codec_delay(substream, nsec);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		*audio_ts = ns_to_timespec64(nsec);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci		audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK;
51362306a36Sopenharmony_ci		audio_tstamp_report->accuracy_report = 1; /* rest of structure is valid */
51462306a36Sopenharmony_ci		audio_tstamp_report->accuracy = 42; /* 24 MHz WallClock == 42ns resolution */
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	} else if (is_link_time_supported(runtime, audio_tstamp_config)) {
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci		ret = azx_get_crosststamp(substream, &xtstamp);
51962306a36Sopenharmony_ci		if (ret)
52062306a36Sopenharmony_ci			return ret;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci		switch (runtime->tstamp_type) {
52362306a36Sopenharmony_ci		case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC:
52462306a36Sopenharmony_ci			return -EINVAL;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci		case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW:
52762306a36Sopenharmony_ci			*system_ts = ktime_to_timespec64(xtstamp.sys_monoraw);
52862306a36Sopenharmony_ci			break;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci		default:
53162306a36Sopenharmony_ci			*system_ts = ktime_to_timespec64(xtstamp.sys_realtime);
53262306a36Sopenharmony_ci			break;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci		}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		*audio_ts = ktime_to_timespec64(xtstamp.device);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci		audio_tstamp_report->actual_type =
53962306a36Sopenharmony_ci			SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED;
54062306a36Sopenharmony_ci		audio_tstamp_report->accuracy_report = 1;
54162306a36Sopenharmony_ci		/* 24 MHz WallClock == 42ns resolution */
54262306a36Sopenharmony_ci		audio_tstamp_report->accuracy = 42;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	} else {
54562306a36Sopenharmony_ci		audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	return 0;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic const struct snd_pcm_hardware azx_pcm_hw = {
55262306a36Sopenharmony_ci	.info =			(SNDRV_PCM_INFO_MMAP |
55362306a36Sopenharmony_ci				 SNDRV_PCM_INFO_INTERLEAVED |
55462306a36Sopenharmony_ci				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
55562306a36Sopenharmony_ci				 SNDRV_PCM_INFO_MMAP_VALID |
55662306a36Sopenharmony_ci				 /* No full-resume yet implemented */
55762306a36Sopenharmony_ci				 /* SNDRV_PCM_INFO_RESUME |*/
55862306a36Sopenharmony_ci				 SNDRV_PCM_INFO_PAUSE |
55962306a36Sopenharmony_ci				 SNDRV_PCM_INFO_SYNC_START |
56062306a36Sopenharmony_ci				 SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */
56162306a36Sopenharmony_ci				 SNDRV_PCM_INFO_HAS_LINK_ATIME |
56262306a36Sopenharmony_ci				 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
56362306a36Sopenharmony_ci	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
56462306a36Sopenharmony_ci	.rates =		SNDRV_PCM_RATE_48000,
56562306a36Sopenharmony_ci	.rate_min =		48000,
56662306a36Sopenharmony_ci	.rate_max =		48000,
56762306a36Sopenharmony_ci	.channels_min =		2,
56862306a36Sopenharmony_ci	.channels_max =		2,
56962306a36Sopenharmony_ci	.buffer_bytes_max =	AZX_MAX_BUF_SIZE,
57062306a36Sopenharmony_ci	.period_bytes_min =	128,
57162306a36Sopenharmony_ci	.period_bytes_max =	AZX_MAX_BUF_SIZE / 2,
57262306a36Sopenharmony_ci	.periods_min =		2,
57362306a36Sopenharmony_ci	.periods_max =		AZX_MAX_FRAG,
57462306a36Sopenharmony_ci	.fifo_size =		0,
57562306a36Sopenharmony_ci};
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic int azx_pcm_open(struct snd_pcm_substream *substream)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
58062306a36Sopenharmony_ci	struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
58162306a36Sopenharmony_ci	struct azx *chip = apcm->chip;
58262306a36Sopenharmony_ci	struct azx_dev *azx_dev;
58362306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
58462306a36Sopenharmony_ci	int err;
58562306a36Sopenharmony_ci	int buff_step;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	snd_hda_codec_pcm_get(apcm->info);
58862306a36Sopenharmony_ci	mutex_lock(&chip->open_mutex);
58962306a36Sopenharmony_ci	azx_dev = azx_assign_device(chip, substream);
59062306a36Sopenharmony_ci	trace_azx_pcm_open(chip, azx_dev);
59162306a36Sopenharmony_ci	if (azx_dev == NULL) {
59262306a36Sopenharmony_ci		err = -EBUSY;
59362306a36Sopenharmony_ci		goto unlock;
59462306a36Sopenharmony_ci	}
59562306a36Sopenharmony_ci	runtime->private_data = azx_dev;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	runtime->hw = azx_pcm_hw;
59862306a36Sopenharmony_ci	if (chip->gts_present)
59962306a36Sopenharmony_ci		runtime->hw.info |= SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME;
60062306a36Sopenharmony_ci	runtime->hw.channels_min = hinfo->channels_min;
60162306a36Sopenharmony_ci	runtime->hw.channels_max = hinfo->channels_max;
60262306a36Sopenharmony_ci	runtime->hw.formats = hinfo->formats;
60362306a36Sopenharmony_ci	runtime->hw.rates = hinfo->rates;
60462306a36Sopenharmony_ci	snd_pcm_limit_hw_rates(runtime);
60562306a36Sopenharmony_ci	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	/* avoid wrap-around with wall-clock */
60862306a36Sopenharmony_ci	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME,
60962306a36Sopenharmony_ci				     20,
61062306a36Sopenharmony_ci				     178000000);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	if (chip->align_buffer_size)
61362306a36Sopenharmony_ci		/* constrain buffer sizes to be multiple of 128
61462306a36Sopenharmony_ci		   bytes. This is more efficient in terms of memory
61562306a36Sopenharmony_ci		   access but isn't required by the HDA spec and
61662306a36Sopenharmony_ci		   prevents users from specifying exact period/buffer
61762306a36Sopenharmony_ci		   sizes. For example for 44.1kHz, a period size set
61862306a36Sopenharmony_ci		   to 20ms will be rounded to 19.59ms. */
61962306a36Sopenharmony_ci		buff_step = 128;
62062306a36Sopenharmony_ci	else
62162306a36Sopenharmony_ci		/* Don't enforce steps on buffer sizes, still need to
62262306a36Sopenharmony_ci		   be multiple of 4 bytes (HDA spec). Tested on Intel
62362306a36Sopenharmony_ci		   HDA controllers, may not work on all devices where
62462306a36Sopenharmony_ci		   option needs to be disabled */
62562306a36Sopenharmony_ci		buff_step = 4;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
62862306a36Sopenharmony_ci				   buff_step);
62962306a36Sopenharmony_ci	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
63062306a36Sopenharmony_ci				   buff_step);
63162306a36Sopenharmony_ci	snd_hda_power_up(apcm->codec);
63262306a36Sopenharmony_ci	if (hinfo->ops.open)
63362306a36Sopenharmony_ci		err = hinfo->ops.open(hinfo, apcm->codec, substream);
63462306a36Sopenharmony_ci	else
63562306a36Sopenharmony_ci		err = -ENODEV;
63662306a36Sopenharmony_ci	if (err < 0) {
63762306a36Sopenharmony_ci		azx_release_device(azx_dev);
63862306a36Sopenharmony_ci		goto powerdown;
63962306a36Sopenharmony_ci	}
64062306a36Sopenharmony_ci	snd_pcm_limit_hw_rates(runtime);
64162306a36Sopenharmony_ci	/* sanity check */
64262306a36Sopenharmony_ci	if (snd_BUG_ON(!runtime->hw.channels_min) ||
64362306a36Sopenharmony_ci	    snd_BUG_ON(!runtime->hw.channels_max) ||
64462306a36Sopenharmony_ci	    snd_BUG_ON(!runtime->hw.formats) ||
64562306a36Sopenharmony_ci	    snd_BUG_ON(!runtime->hw.rates)) {
64662306a36Sopenharmony_ci		azx_release_device(azx_dev);
64762306a36Sopenharmony_ci		if (hinfo->ops.close)
64862306a36Sopenharmony_ci			hinfo->ops.close(hinfo, apcm->codec, substream);
64962306a36Sopenharmony_ci		err = -EINVAL;
65062306a36Sopenharmony_ci		goto powerdown;
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/* disable LINK_ATIME timestamps for capture streams
65462306a36Sopenharmony_ci	   until we figure out how to handle digital inputs */
65562306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
65662306a36Sopenharmony_ci		runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */
65762306a36Sopenharmony_ci		runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME;
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	snd_pcm_set_sync(substream);
66162306a36Sopenharmony_ci	mutex_unlock(&chip->open_mutex);
66262306a36Sopenharmony_ci	return 0;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci powerdown:
66562306a36Sopenharmony_ci	snd_hda_power_down(apcm->codec);
66662306a36Sopenharmony_ci unlock:
66762306a36Sopenharmony_ci	mutex_unlock(&chip->open_mutex);
66862306a36Sopenharmony_ci	snd_hda_codec_pcm_put(apcm->info);
66962306a36Sopenharmony_ci	return err;
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistatic const struct snd_pcm_ops azx_pcm_ops = {
67362306a36Sopenharmony_ci	.open = azx_pcm_open,
67462306a36Sopenharmony_ci	.close = azx_pcm_close,
67562306a36Sopenharmony_ci	.hw_params = azx_pcm_hw_params,
67662306a36Sopenharmony_ci	.hw_free = azx_pcm_hw_free,
67762306a36Sopenharmony_ci	.prepare = azx_pcm_prepare,
67862306a36Sopenharmony_ci	.trigger = azx_pcm_trigger,
67962306a36Sopenharmony_ci	.pointer = azx_pcm_pointer,
68062306a36Sopenharmony_ci	.get_time_info =  azx_get_time_info,
68162306a36Sopenharmony_ci};
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_cistatic void azx_pcm_free(struct snd_pcm *pcm)
68462306a36Sopenharmony_ci{
68562306a36Sopenharmony_ci	struct azx_pcm *apcm = pcm->private_data;
68662306a36Sopenharmony_ci	if (apcm) {
68762306a36Sopenharmony_ci		list_del(&apcm->list);
68862306a36Sopenharmony_ci		apcm->info->pcm = NULL;
68962306a36Sopenharmony_ci		kfree(apcm);
69062306a36Sopenharmony_ci	}
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci#define MAX_PREALLOC_SIZE	(32 * 1024 * 1024)
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ciint snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec,
69662306a36Sopenharmony_ci			      struct hda_pcm *cpcm)
69762306a36Sopenharmony_ci{
69862306a36Sopenharmony_ci	struct hdac_bus *bus = &_bus->core;
69962306a36Sopenharmony_ci	struct azx *chip = bus_to_azx(bus);
70062306a36Sopenharmony_ci	struct snd_pcm *pcm;
70162306a36Sopenharmony_ci	struct azx_pcm *apcm;
70262306a36Sopenharmony_ci	int pcm_dev = cpcm->device;
70362306a36Sopenharmony_ci	unsigned int size;
70462306a36Sopenharmony_ci	int s, err;
70562306a36Sopenharmony_ci	int type = SNDRV_DMA_TYPE_DEV_SG;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	list_for_each_entry(apcm, &chip->pcm_list, list) {
70862306a36Sopenharmony_ci		if (apcm->pcm->device == pcm_dev) {
70962306a36Sopenharmony_ci			dev_err(chip->card->dev, "PCM %d already exists\n",
71062306a36Sopenharmony_ci				pcm_dev);
71162306a36Sopenharmony_ci			return -EBUSY;
71262306a36Sopenharmony_ci		}
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci	err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
71562306a36Sopenharmony_ci			  cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
71662306a36Sopenharmony_ci			  cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams,
71762306a36Sopenharmony_ci			  &pcm);
71862306a36Sopenharmony_ci	if (err < 0)
71962306a36Sopenharmony_ci		return err;
72062306a36Sopenharmony_ci	strscpy(pcm->name, cpcm->name, sizeof(pcm->name));
72162306a36Sopenharmony_ci	apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
72262306a36Sopenharmony_ci	if (apcm == NULL) {
72362306a36Sopenharmony_ci		snd_device_free(chip->card, pcm);
72462306a36Sopenharmony_ci		return -ENOMEM;
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci	apcm->chip = chip;
72762306a36Sopenharmony_ci	apcm->pcm = pcm;
72862306a36Sopenharmony_ci	apcm->codec = codec;
72962306a36Sopenharmony_ci	apcm->info = cpcm;
73062306a36Sopenharmony_ci	pcm->private_data = apcm;
73162306a36Sopenharmony_ci	pcm->private_free = azx_pcm_free;
73262306a36Sopenharmony_ci	if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
73362306a36Sopenharmony_ci		pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
73462306a36Sopenharmony_ci	list_add_tail(&apcm->list, &chip->pcm_list);
73562306a36Sopenharmony_ci	cpcm->pcm = pcm;
73662306a36Sopenharmony_ci	for (s = 0; s < 2; s++) {
73762306a36Sopenharmony_ci		if (cpcm->stream[s].substreams)
73862306a36Sopenharmony_ci			snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
73962306a36Sopenharmony_ci	}
74062306a36Sopenharmony_ci	/* buffer pre-allocation */
74162306a36Sopenharmony_ci	size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
74262306a36Sopenharmony_ci	if (size > MAX_PREALLOC_SIZE)
74362306a36Sopenharmony_ci		size = MAX_PREALLOC_SIZE;
74462306a36Sopenharmony_ci	if (chip->uc_buffer)
74562306a36Sopenharmony_ci		type = SNDRV_DMA_TYPE_DEV_WC_SG;
74662306a36Sopenharmony_ci	snd_pcm_set_managed_buffer_all(pcm, type, chip->card->dev,
74762306a36Sopenharmony_ci				       size, MAX_PREALLOC_SIZE);
74862306a36Sopenharmony_ci	return 0;
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_cistatic unsigned int azx_command_addr(u32 cmd)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	unsigned int addr = cmd >> 28;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (addr >= AZX_MAX_CODECS) {
75662306a36Sopenharmony_ci		snd_BUG();
75762306a36Sopenharmony_ci		addr = 0;
75862306a36Sopenharmony_ci	}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	return addr;
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci/* receive a response */
76462306a36Sopenharmony_cistatic int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr,
76562306a36Sopenharmony_ci				 unsigned int *res)
76662306a36Sopenharmony_ci{
76762306a36Sopenharmony_ci	struct azx *chip = bus_to_azx(bus);
76862306a36Sopenharmony_ci	struct hda_bus *hbus = &chip->bus;
76962306a36Sopenharmony_ci	int err;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci again:
77262306a36Sopenharmony_ci	err = snd_hdac_bus_get_response(bus, addr, res);
77362306a36Sopenharmony_ci	if (!err)
77462306a36Sopenharmony_ci		return 0;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	if (hbus->no_response_fallback)
77762306a36Sopenharmony_ci		return -EIO;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	if (!bus->polling_mode) {
78062306a36Sopenharmony_ci		dev_warn(chip->card->dev,
78162306a36Sopenharmony_ci			 "azx_get_response timeout, switching to polling mode: last cmd=0x%08x\n",
78262306a36Sopenharmony_ci			 bus->last_cmd[addr]);
78362306a36Sopenharmony_ci		bus->polling_mode = 1;
78462306a36Sopenharmony_ci		goto again;
78562306a36Sopenharmony_ci	}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	if (chip->msi) {
78862306a36Sopenharmony_ci		dev_warn(chip->card->dev,
78962306a36Sopenharmony_ci			 "No response from codec, disabling MSI: last cmd=0x%08x\n",
79062306a36Sopenharmony_ci			 bus->last_cmd[addr]);
79162306a36Sopenharmony_ci		if (chip->ops->disable_msi_reset_irq &&
79262306a36Sopenharmony_ci		    chip->ops->disable_msi_reset_irq(chip) < 0)
79362306a36Sopenharmony_ci			return -EIO;
79462306a36Sopenharmony_ci		goto again;
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	if (chip->probing) {
79862306a36Sopenharmony_ci		/* If this critical timeout happens during the codec probing
79962306a36Sopenharmony_ci		 * phase, this is likely an access to a non-existing codec
80062306a36Sopenharmony_ci		 * slot.  Better to return an error and reset the system.
80162306a36Sopenharmony_ci		 */
80262306a36Sopenharmony_ci		return -EIO;
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	/* no fallback mechanism? */
80662306a36Sopenharmony_ci	if (!chip->fallback_to_single_cmd)
80762306a36Sopenharmony_ci		return -EIO;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	/* a fatal communication error; need either to reset or to fallback
81062306a36Sopenharmony_ci	 * to the single_cmd mode
81162306a36Sopenharmony_ci	 */
81262306a36Sopenharmony_ci	if (hbus->allow_bus_reset && !hbus->response_reset && !hbus->in_reset) {
81362306a36Sopenharmony_ci		hbus->response_reset = 1;
81462306a36Sopenharmony_ci		dev_err(chip->card->dev,
81562306a36Sopenharmony_ci			"No response from codec, resetting bus: last cmd=0x%08x\n",
81662306a36Sopenharmony_ci			bus->last_cmd[addr]);
81762306a36Sopenharmony_ci		return -EAGAIN; /* give a chance to retry */
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	dev_err(chip->card->dev,
82162306a36Sopenharmony_ci		"azx_get_response timeout, switching to single_cmd mode: last cmd=0x%08x\n",
82262306a36Sopenharmony_ci		bus->last_cmd[addr]);
82362306a36Sopenharmony_ci	chip->single_cmd = 1;
82462306a36Sopenharmony_ci	hbus->response_reset = 0;
82562306a36Sopenharmony_ci	snd_hdac_bus_stop_cmd_io(bus);
82662306a36Sopenharmony_ci	return -EIO;
82762306a36Sopenharmony_ci}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci/*
83062306a36Sopenharmony_ci * Use the single immediate command instead of CORB/RIRB for simplicity
83162306a36Sopenharmony_ci *
83262306a36Sopenharmony_ci * Note: according to Intel, this is not preferred use.  The command was
83362306a36Sopenharmony_ci *       intended for the BIOS only, and may get confused with unsolicited
83462306a36Sopenharmony_ci *       responses.  So, we shouldn't use it for normal operation from the
83562306a36Sopenharmony_ci *       driver.
83662306a36Sopenharmony_ci *       I left the codes, however, for debugging/testing purposes.
83762306a36Sopenharmony_ci */
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci/* receive a response */
84062306a36Sopenharmony_cistatic int azx_single_wait_for_response(struct azx *chip, unsigned int addr)
84162306a36Sopenharmony_ci{
84262306a36Sopenharmony_ci	int timeout = 50;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	while (timeout--) {
84562306a36Sopenharmony_ci		/* check IRV busy bit */
84662306a36Sopenharmony_ci		if (azx_readw(chip, IRS) & AZX_IRS_VALID) {
84762306a36Sopenharmony_ci			/* reuse rirb.res as the response return value */
84862306a36Sopenharmony_ci			azx_bus(chip)->rirb.res[addr] = azx_readl(chip, IR);
84962306a36Sopenharmony_ci			return 0;
85062306a36Sopenharmony_ci		}
85162306a36Sopenharmony_ci		udelay(1);
85262306a36Sopenharmony_ci	}
85362306a36Sopenharmony_ci	if (printk_ratelimit())
85462306a36Sopenharmony_ci		dev_dbg(chip->card->dev, "get_response timeout: IRS=0x%x\n",
85562306a36Sopenharmony_ci			azx_readw(chip, IRS));
85662306a36Sopenharmony_ci	azx_bus(chip)->rirb.res[addr] = -1;
85762306a36Sopenharmony_ci	return -EIO;
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci/* send a command */
86162306a36Sopenharmony_cistatic int azx_single_send_cmd(struct hdac_bus *bus, u32 val)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	struct azx *chip = bus_to_azx(bus);
86462306a36Sopenharmony_ci	unsigned int addr = azx_command_addr(val);
86562306a36Sopenharmony_ci	int timeout = 50;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	bus->last_cmd[azx_command_addr(val)] = val;
86862306a36Sopenharmony_ci	while (timeout--) {
86962306a36Sopenharmony_ci		/* check ICB busy bit */
87062306a36Sopenharmony_ci		if (!((azx_readw(chip, IRS) & AZX_IRS_BUSY))) {
87162306a36Sopenharmony_ci			/* Clear IRV valid bit */
87262306a36Sopenharmony_ci			azx_writew(chip, IRS, azx_readw(chip, IRS) |
87362306a36Sopenharmony_ci				   AZX_IRS_VALID);
87462306a36Sopenharmony_ci			azx_writel(chip, IC, val);
87562306a36Sopenharmony_ci			azx_writew(chip, IRS, azx_readw(chip, IRS) |
87662306a36Sopenharmony_ci				   AZX_IRS_BUSY);
87762306a36Sopenharmony_ci			return azx_single_wait_for_response(chip, addr);
87862306a36Sopenharmony_ci		}
87962306a36Sopenharmony_ci		udelay(1);
88062306a36Sopenharmony_ci	}
88162306a36Sopenharmony_ci	if (printk_ratelimit())
88262306a36Sopenharmony_ci		dev_dbg(chip->card->dev,
88362306a36Sopenharmony_ci			"send_cmd timeout: IRS=0x%x, val=0x%x\n",
88462306a36Sopenharmony_ci			azx_readw(chip, IRS), val);
88562306a36Sopenharmony_ci	return -EIO;
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci/* receive a response */
88962306a36Sopenharmony_cistatic int azx_single_get_response(struct hdac_bus *bus, unsigned int addr,
89062306a36Sopenharmony_ci				   unsigned int *res)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	if (res)
89362306a36Sopenharmony_ci		*res = bus->rirb.res[addr];
89462306a36Sopenharmony_ci	return 0;
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci/*
89862306a36Sopenharmony_ci * The below are the main callbacks from hda_codec.
89962306a36Sopenharmony_ci *
90062306a36Sopenharmony_ci * They are just the skeleton to call sub-callbacks according to the
90162306a36Sopenharmony_ci * current setting of chip->single_cmd.
90262306a36Sopenharmony_ci */
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci/* send a command */
90562306a36Sopenharmony_cistatic int azx_send_cmd(struct hdac_bus *bus, unsigned int val)
90662306a36Sopenharmony_ci{
90762306a36Sopenharmony_ci	struct azx *chip = bus_to_azx(bus);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	if (chip->disabled)
91062306a36Sopenharmony_ci		return 0;
91162306a36Sopenharmony_ci	if (chip->single_cmd)
91262306a36Sopenharmony_ci		return azx_single_send_cmd(bus, val);
91362306a36Sopenharmony_ci	else
91462306a36Sopenharmony_ci		return snd_hdac_bus_send_cmd(bus, val);
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci/* get a response */
91862306a36Sopenharmony_cistatic int azx_get_response(struct hdac_bus *bus, unsigned int addr,
91962306a36Sopenharmony_ci			    unsigned int *res)
92062306a36Sopenharmony_ci{
92162306a36Sopenharmony_ci	struct azx *chip = bus_to_azx(bus);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	if (chip->disabled)
92462306a36Sopenharmony_ci		return 0;
92562306a36Sopenharmony_ci	if (chip->single_cmd)
92662306a36Sopenharmony_ci		return azx_single_get_response(bus, addr, res);
92762306a36Sopenharmony_ci	else
92862306a36Sopenharmony_ci		return azx_rirb_get_response(bus, addr, res);
92962306a36Sopenharmony_ci}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_cistatic const struct hdac_bus_ops bus_core_ops = {
93262306a36Sopenharmony_ci	.command = azx_send_cmd,
93362306a36Sopenharmony_ci	.get_response = azx_get_response,
93462306a36Sopenharmony_ci};
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci#ifdef CONFIG_SND_HDA_DSP_LOADER
93762306a36Sopenharmony_ci/*
93862306a36Sopenharmony_ci * DSP loading code (e.g. for CA0132)
93962306a36Sopenharmony_ci */
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci/* use the first stream for loading DSP */
94262306a36Sopenharmony_cistatic struct azx_dev *
94362306a36Sopenharmony_ciazx_get_dsp_loader_dev(struct azx *chip)
94462306a36Sopenharmony_ci{
94562306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
94662306a36Sopenharmony_ci	struct hdac_stream *s;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	list_for_each_entry(s, &bus->stream_list, list)
94962306a36Sopenharmony_ci		if (s->index == chip->playback_index_offset)
95062306a36Sopenharmony_ci			return stream_to_azx_dev(s);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	return NULL;
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ciint snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format,
95662306a36Sopenharmony_ci				   unsigned int byte_size,
95762306a36Sopenharmony_ci				   struct snd_dma_buffer *bufp)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	struct hdac_bus *bus = &codec->bus->core;
96062306a36Sopenharmony_ci	struct azx *chip = bus_to_azx(bus);
96162306a36Sopenharmony_ci	struct azx_dev *azx_dev;
96262306a36Sopenharmony_ci	struct hdac_stream *hstr;
96362306a36Sopenharmony_ci	bool saved = false;
96462306a36Sopenharmony_ci	int err;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	azx_dev = azx_get_dsp_loader_dev(chip);
96762306a36Sopenharmony_ci	hstr = azx_stream(azx_dev);
96862306a36Sopenharmony_ci	spin_lock_irq(&bus->reg_lock);
96962306a36Sopenharmony_ci	if (hstr->opened) {
97062306a36Sopenharmony_ci		chip->saved_azx_dev = *azx_dev;
97162306a36Sopenharmony_ci		saved = true;
97262306a36Sopenharmony_ci	}
97362306a36Sopenharmony_ci	spin_unlock_irq(&bus->reg_lock);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	err = snd_hdac_dsp_prepare(hstr, format, byte_size, bufp);
97662306a36Sopenharmony_ci	if (err < 0) {
97762306a36Sopenharmony_ci		spin_lock_irq(&bus->reg_lock);
97862306a36Sopenharmony_ci		if (saved)
97962306a36Sopenharmony_ci			*azx_dev = chip->saved_azx_dev;
98062306a36Sopenharmony_ci		spin_unlock_irq(&bus->reg_lock);
98162306a36Sopenharmony_ci		return err;
98262306a36Sopenharmony_ci	}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	hstr->prepared = 0;
98562306a36Sopenharmony_ci	return err;
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_load_dsp_prepare);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_civoid snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	struct hdac_bus *bus = &codec->bus->core;
99262306a36Sopenharmony_ci	struct azx *chip = bus_to_azx(bus);
99362306a36Sopenharmony_ci	struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	snd_hdac_dsp_trigger(azx_stream(azx_dev), start);
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_load_dsp_trigger);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_civoid snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
100062306a36Sopenharmony_ci				    struct snd_dma_buffer *dmab)
100162306a36Sopenharmony_ci{
100262306a36Sopenharmony_ci	struct hdac_bus *bus = &codec->bus->core;
100362306a36Sopenharmony_ci	struct azx *chip = bus_to_azx(bus);
100462306a36Sopenharmony_ci	struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
100562306a36Sopenharmony_ci	struct hdac_stream *hstr = azx_stream(azx_dev);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	if (!dmab->area || !hstr->locked)
100862306a36Sopenharmony_ci		return;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	snd_hdac_dsp_cleanup(hstr, dmab);
101162306a36Sopenharmony_ci	spin_lock_irq(&bus->reg_lock);
101262306a36Sopenharmony_ci	if (hstr->opened)
101362306a36Sopenharmony_ci		*azx_dev = chip->saved_azx_dev;
101462306a36Sopenharmony_ci	hstr->locked = false;
101562306a36Sopenharmony_ci	spin_unlock_irq(&bus->reg_lock);
101662306a36Sopenharmony_ci}
101762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_load_dsp_cleanup);
101862306a36Sopenharmony_ci#endif /* CONFIG_SND_HDA_DSP_LOADER */
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci/*
102162306a36Sopenharmony_ci * reset and start the controller registers
102262306a36Sopenharmony_ci */
102362306a36Sopenharmony_civoid azx_init_chip(struct azx *chip, bool full_reset)
102462306a36Sopenharmony_ci{
102562306a36Sopenharmony_ci	if (snd_hdac_bus_init_chip(azx_bus(chip), full_reset)) {
102662306a36Sopenharmony_ci		/* correct RINTCNT for CXT */
102762306a36Sopenharmony_ci		if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
102862306a36Sopenharmony_ci			azx_writew(chip, RINTCNT, 0xc0);
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci}
103162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_init_chip);
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_civoid azx_stop_all_streams(struct azx *chip)
103462306a36Sopenharmony_ci{
103562306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	snd_hdac_stop_streams(bus);
103862306a36Sopenharmony_ci}
103962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_stop_all_streams);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_civoid azx_stop_chip(struct azx *chip)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	snd_hdac_bus_stop_chip(azx_bus(chip));
104462306a36Sopenharmony_ci}
104562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_stop_chip);
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci/*
104862306a36Sopenharmony_ci * interrupt handler
104962306a36Sopenharmony_ci */
105062306a36Sopenharmony_cistatic void stream_update(struct hdac_bus *bus, struct hdac_stream *s)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	struct azx *chip = bus_to_azx(bus);
105362306a36Sopenharmony_ci	struct azx_dev *azx_dev = stream_to_azx_dev(s);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	/* check whether this IRQ is really acceptable */
105662306a36Sopenharmony_ci	if (!chip->ops->position_check ||
105762306a36Sopenharmony_ci	    chip->ops->position_check(chip, azx_dev)) {
105862306a36Sopenharmony_ci		spin_unlock(&bus->reg_lock);
105962306a36Sopenharmony_ci		snd_pcm_period_elapsed(azx_stream(azx_dev)->substream);
106062306a36Sopenharmony_ci		spin_lock(&bus->reg_lock);
106162306a36Sopenharmony_ci	}
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ciirqreturn_t azx_interrupt(int irq, void *dev_id)
106562306a36Sopenharmony_ci{
106662306a36Sopenharmony_ci	struct azx *chip = dev_id;
106762306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
106862306a36Sopenharmony_ci	u32 status;
106962306a36Sopenharmony_ci	bool active, handled = false;
107062306a36Sopenharmony_ci	int repeat = 0; /* count for avoiding endless loop */
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci#ifdef CONFIG_PM
107362306a36Sopenharmony_ci	if (azx_has_pm_runtime(chip))
107462306a36Sopenharmony_ci		if (!pm_runtime_active(chip->card->dev))
107562306a36Sopenharmony_ci			return IRQ_NONE;
107662306a36Sopenharmony_ci#endif
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	spin_lock(&bus->reg_lock);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	if (chip->disabled)
108162306a36Sopenharmony_ci		goto unlock;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	do {
108462306a36Sopenharmony_ci		status = azx_readl(chip, INTSTS);
108562306a36Sopenharmony_ci		if (status == 0 || status == 0xffffffff)
108662306a36Sopenharmony_ci			break;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci		handled = true;
108962306a36Sopenharmony_ci		active = false;
109062306a36Sopenharmony_ci		if (snd_hdac_bus_handle_stream_irq(bus, status, stream_update))
109162306a36Sopenharmony_ci			active = true;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci		status = azx_readb(chip, RIRBSTS);
109462306a36Sopenharmony_ci		if (status & RIRB_INT_MASK) {
109562306a36Sopenharmony_ci			/*
109662306a36Sopenharmony_ci			 * Clearing the interrupt status here ensures that no
109762306a36Sopenharmony_ci			 * interrupt gets masked after the RIRB wp is read in
109862306a36Sopenharmony_ci			 * snd_hdac_bus_update_rirb. This avoids a possible
109962306a36Sopenharmony_ci			 * race condition where codec response in RIRB may
110062306a36Sopenharmony_ci			 * remain unserviced by IRQ, eventually falling back
110162306a36Sopenharmony_ci			 * to polling mode in azx_rirb_get_response.
110262306a36Sopenharmony_ci			 */
110362306a36Sopenharmony_ci			azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
110462306a36Sopenharmony_ci			active = true;
110562306a36Sopenharmony_ci			if (status & RIRB_INT_RESPONSE) {
110662306a36Sopenharmony_ci				if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
110762306a36Sopenharmony_ci					udelay(80);
110862306a36Sopenharmony_ci				snd_hdac_bus_update_rirb(bus);
110962306a36Sopenharmony_ci			}
111062306a36Sopenharmony_ci		}
111162306a36Sopenharmony_ci	} while (active && ++repeat < 10);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci unlock:
111462306a36Sopenharmony_ci	spin_unlock(&bus->reg_lock);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	return IRQ_RETVAL(handled);
111762306a36Sopenharmony_ci}
111862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_interrupt);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci/*
112162306a36Sopenharmony_ci * Codec initerface
112262306a36Sopenharmony_ci */
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci/*
112562306a36Sopenharmony_ci * Probe the given codec address
112662306a36Sopenharmony_ci */
112762306a36Sopenharmony_cistatic int probe_codec(struct azx *chip, int addr)
112862306a36Sopenharmony_ci{
112962306a36Sopenharmony_ci	unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
113062306a36Sopenharmony_ci		(AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
113162306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
113262306a36Sopenharmony_ci	int err;
113362306a36Sopenharmony_ci	unsigned int res = -1;
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	mutex_lock(&bus->cmd_mutex);
113662306a36Sopenharmony_ci	chip->probing = 1;
113762306a36Sopenharmony_ci	azx_send_cmd(bus, cmd);
113862306a36Sopenharmony_ci	err = azx_get_response(bus, addr, &res);
113962306a36Sopenharmony_ci	chip->probing = 0;
114062306a36Sopenharmony_ci	mutex_unlock(&bus->cmd_mutex);
114162306a36Sopenharmony_ci	if (err < 0 || res == -1)
114262306a36Sopenharmony_ci		return -EIO;
114362306a36Sopenharmony_ci	dev_dbg(chip->card->dev, "codec #%d probed OK\n", addr);
114462306a36Sopenharmony_ci	return 0;
114562306a36Sopenharmony_ci}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_civoid snd_hda_bus_reset(struct hda_bus *bus)
114862306a36Sopenharmony_ci{
114962306a36Sopenharmony_ci	struct azx *chip = bus_to_azx(&bus->core);
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	bus->in_reset = 1;
115262306a36Sopenharmony_ci	azx_stop_chip(chip);
115362306a36Sopenharmony_ci	azx_init_chip(chip, true);
115462306a36Sopenharmony_ci	if (bus->core.chip_init)
115562306a36Sopenharmony_ci		snd_hda_bus_reset_codecs(bus);
115662306a36Sopenharmony_ci	bus->in_reset = 0;
115762306a36Sopenharmony_ci}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci/* HD-audio bus initialization */
116062306a36Sopenharmony_ciint azx_bus_init(struct azx *chip, const char *model)
116162306a36Sopenharmony_ci{
116262306a36Sopenharmony_ci	struct hda_bus *bus = &chip->bus;
116362306a36Sopenharmony_ci	int err;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	err = snd_hdac_bus_init(&bus->core, chip->card->dev, &bus_core_ops);
116662306a36Sopenharmony_ci	if (err < 0)
116762306a36Sopenharmony_ci		return err;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	bus->card = chip->card;
117062306a36Sopenharmony_ci	mutex_init(&bus->prepare_mutex);
117162306a36Sopenharmony_ci	bus->pci = chip->pci;
117262306a36Sopenharmony_ci	bus->modelname = model;
117362306a36Sopenharmony_ci	bus->mixer_assigned = -1;
117462306a36Sopenharmony_ci	bus->core.snoop = azx_snoop(chip);
117562306a36Sopenharmony_ci	if (chip->get_position[0] != azx_get_pos_lpib ||
117662306a36Sopenharmony_ci	    chip->get_position[1] != azx_get_pos_lpib)
117762306a36Sopenharmony_ci		bus->core.use_posbuf = true;
117862306a36Sopenharmony_ci	bus->core.bdl_pos_adj = chip->bdl_pos_adj;
117962306a36Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)
118062306a36Sopenharmony_ci		bus->core.corbrp_self_clear = true;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY)
118362306a36Sopenharmony_ci		bus->core.align_bdle_4k = true;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	/* enable sync_write flag for stable communication as default */
118662306a36Sopenharmony_ci	bus->core.sync_write = 1;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	return 0;
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_bus_init);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci/* Probe codecs */
119362306a36Sopenharmony_ciint azx_probe_codecs(struct azx *chip, unsigned int max_slots)
119462306a36Sopenharmony_ci{
119562306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
119662306a36Sopenharmony_ci	int c, codecs, err;
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	codecs = 0;
119962306a36Sopenharmony_ci	if (!max_slots)
120062306a36Sopenharmony_ci		max_slots = AZX_DEFAULT_CODECS;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	/* First try to probe all given codec slots */
120362306a36Sopenharmony_ci	for (c = 0; c < max_slots; c++) {
120462306a36Sopenharmony_ci		if ((bus->codec_mask & (1 << c)) & chip->codec_probe_mask) {
120562306a36Sopenharmony_ci			if (probe_codec(chip, c) < 0) {
120662306a36Sopenharmony_ci				/* Some BIOSen give you wrong codec addresses
120762306a36Sopenharmony_ci				 * that don't exist
120862306a36Sopenharmony_ci				 */
120962306a36Sopenharmony_ci				dev_warn(chip->card->dev,
121062306a36Sopenharmony_ci					 "Codec #%d probe error; disabling it...\n", c);
121162306a36Sopenharmony_ci				bus->codec_mask &= ~(1 << c);
121262306a36Sopenharmony_ci				/* More badly, accessing to a non-existing
121362306a36Sopenharmony_ci				 * codec often screws up the controller chip,
121462306a36Sopenharmony_ci				 * and disturbs the further communications.
121562306a36Sopenharmony_ci				 * Thus if an error occurs during probing,
121662306a36Sopenharmony_ci				 * better to reset the controller chip to
121762306a36Sopenharmony_ci				 * get back to the sanity state.
121862306a36Sopenharmony_ci				 */
121962306a36Sopenharmony_ci				azx_stop_chip(chip);
122062306a36Sopenharmony_ci				azx_init_chip(chip, true);
122162306a36Sopenharmony_ci			}
122262306a36Sopenharmony_ci		}
122362306a36Sopenharmony_ci	}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	/* Then create codec instances */
122662306a36Sopenharmony_ci	for (c = 0; c < max_slots; c++) {
122762306a36Sopenharmony_ci		if ((bus->codec_mask & (1 << c)) & chip->codec_probe_mask) {
122862306a36Sopenharmony_ci			struct hda_codec *codec;
122962306a36Sopenharmony_ci			err = snd_hda_codec_new(&chip->bus, chip->card, c, &codec);
123062306a36Sopenharmony_ci			if (err < 0)
123162306a36Sopenharmony_ci				continue;
123262306a36Sopenharmony_ci			codec->jackpoll_interval = chip->jackpoll_interval;
123362306a36Sopenharmony_ci			codec->beep_mode = chip->beep_mode;
123462306a36Sopenharmony_ci			codec->ctl_dev_id = chip->ctl_dev_id;
123562306a36Sopenharmony_ci			codecs++;
123662306a36Sopenharmony_ci		}
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci	if (!codecs) {
123962306a36Sopenharmony_ci		dev_err(chip->card->dev, "no codecs initialized\n");
124062306a36Sopenharmony_ci		return -ENXIO;
124162306a36Sopenharmony_ci	}
124262306a36Sopenharmony_ci	return 0;
124362306a36Sopenharmony_ci}
124462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_probe_codecs);
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci/* configure each codec instance */
124762306a36Sopenharmony_ciint azx_codec_configure(struct azx *chip)
124862306a36Sopenharmony_ci{
124962306a36Sopenharmony_ci	struct hda_codec *codec, *next;
125062306a36Sopenharmony_ci	int success = 0;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	list_for_each_codec(codec, &chip->bus) {
125362306a36Sopenharmony_ci		if (!snd_hda_codec_configure(codec))
125462306a36Sopenharmony_ci			success++;
125562306a36Sopenharmony_ci	}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	if (success) {
125862306a36Sopenharmony_ci		/* unregister failed codecs if any codec has been probed */
125962306a36Sopenharmony_ci		list_for_each_codec_safe(codec, next, &chip->bus) {
126062306a36Sopenharmony_ci			if (!codec->configured) {
126162306a36Sopenharmony_ci				codec_err(codec, "Unable to configure, disabling\n");
126262306a36Sopenharmony_ci				snd_hdac_device_unregister(&codec->core);
126362306a36Sopenharmony_ci			}
126462306a36Sopenharmony_ci		}
126562306a36Sopenharmony_ci	}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	return success ? 0 : -ENODEV;
126862306a36Sopenharmony_ci}
126962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_codec_configure);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_cistatic int stream_direction(struct azx *chip, unsigned char index)
127262306a36Sopenharmony_ci{
127362306a36Sopenharmony_ci	if (index >= chip->capture_index_offset &&
127462306a36Sopenharmony_ci	    index < chip->capture_index_offset + chip->capture_streams)
127562306a36Sopenharmony_ci		return SNDRV_PCM_STREAM_CAPTURE;
127662306a36Sopenharmony_ci	return SNDRV_PCM_STREAM_PLAYBACK;
127762306a36Sopenharmony_ci}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci/* initialize SD streams */
128062306a36Sopenharmony_ciint azx_init_streams(struct azx *chip)
128162306a36Sopenharmony_ci{
128262306a36Sopenharmony_ci	int i;
128362306a36Sopenharmony_ci	int stream_tags[2] = { 0, 0 };
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	/* initialize each stream (aka device)
128662306a36Sopenharmony_ci	 * assign the starting bdl address to each stream (device)
128762306a36Sopenharmony_ci	 * and initialize
128862306a36Sopenharmony_ci	 */
128962306a36Sopenharmony_ci	for (i = 0; i < chip->num_streams; i++) {
129062306a36Sopenharmony_ci		struct azx_dev *azx_dev = kzalloc(sizeof(*azx_dev), GFP_KERNEL);
129162306a36Sopenharmony_ci		int dir, tag;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci		if (!azx_dev)
129462306a36Sopenharmony_ci			return -ENOMEM;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci		dir = stream_direction(chip, i);
129762306a36Sopenharmony_ci		/* stream tag must be unique throughout
129862306a36Sopenharmony_ci		 * the stream direction group,
129962306a36Sopenharmony_ci		 * valid values 1...15
130062306a36Sopenharmony_ci		 * use separate stream tag if the flag
130162306a36Sopenharmony_ci		 * AZX_DCAPS_SEPARATE_STREAM_TAG is used
130262306a36Sopenharmony_ci		 */
130362306a36Sopenharmony_ci		if (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG)
130462306a36Sopenharmony_ci			tag = ++stream_tags[dir];
130562306a36Sopenharmony_ci		else
130662306a36Sopenharmony_ci			tag = i + 1;
130762306a36Sopenharmony_ci		snd_hdac_stream_init(azx_bus(chip), azx_stream(azx_dev),
130862306a36Sopenharmony_ci				     i, dir, tag);
130962306a36Sopenharmony_ci	}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	return 0;
131262306a36Sopenharmony_ci}
131362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_init_streams);
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_civoid azx_free_streams(struct azx *chip)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
131862306a36Sopenharmony_ci	struct hdac_stream *s;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	while (!list_empty(&bus->stream_list)) {
132162306a36Sopenharmony_ci		s = list_first_entry(&bus->stream_list, struct hdac_stream, list);
132262306a36Sopenharmony_ci		list_del(&s->list);
132362306a36Sopenharmony_ci		kfree(stream_to_azx_dev(s));
132462306a36Sopenharmony_ci	}
132562306a36Sopenharmony_ci}
132662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(azx_free_streams);
1327