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

Commit a9c48f7f authored by Jeeja KP's avatar Jeeja KP Committed by Mark Brown
Browse files

ALSA: hdac: Add support for hda DMA Resume capability



Skylake sports new capability of DMA resume, DRSM where we can
resume the DMA. This capability is defined by presence of
AZX_DRSM_CAP_ID.

If this capability is present, we use this capability.
So we add:

snd_hdac_ext_stream_drsm_enable() - DMA resume caps
snd_hdac_ext_stream_set_dpibr() - set the DMA position
snd_hdac_ext_stream_set_lpib() - set the lpib

Signed-off-by: default avatarJeeja KP <jeeja.kp@intel.com>
Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
Reviewed-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 1e83b047
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -230,6 +230,15 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_MLCTL_SPA			(1<<16)
#define AZX_MLCTL_CPA			23


/* registers for DMA Resume Capability Structure */
#define AZX_DRSM_CAP_ID			0x5
#define AZX_REG_DRSM_CTL		0x4
/* Base used to calculate the iterating register offset */
#define AZX_DRSM_BASE			0x08
/* Interval used to calculate the iterating register offset */
#define AZX_DRSM_INTERVAL		0x08

/*
 * helpers to read the stream position
 */
+14 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
 * @spbcap: SPIB capabilities pointer
 * @mlcap: MultiLink capabilities pointer
 * @gtscap: gts capabilities pointer
 * @drsmcap: dma resume capabilities pointer
 * @hlink_list: link list of HDA links
 */
struct hdac_ext_bus {
@@ -23,6 +24,7 @@ struct hdac_ext_bus {
	void __iomem *spbcap;
	void __iomem *mlcap;
	void __iomem *gtscap;
	void __iomem *drsmcap;

	struct list_head hlink_list;
};
@@ -72,6 +74,9 @@ enum hdac_ext_stream_type {
 * @pplc_addr: processing pipe link stream pointer
 * @spib_addr: software position in buffers stream pointer
 * @fifo_addr: software position Max fifos stream pointer
 * @dpibr_addr: DMA position in buffer resume pointer
 * @dpib: DMA position in buffer
 * @lpib: Linear position in buffer
 * @decoupled: stream host and link is decoupled
 * @link_locked: link is locked
 * @link_prepared: link is prepared
@@ -86,6 +91,10 @@ struct hdac_ext_stream {
	void __iomem *spib_addr;
	void __iomem *fifo_addr;

	void __iomem *dpibr_addr;

	u32 dpib;
	u32 lpib;
	bool decoupled:1;
	bool link_locked:1;
	bool link_prepared;
@@ -116,6 +125,11 @@ int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus,
				 struct hdac_ext_stream *stream, u32 value);
int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
				 struct hdac_ext_stream *stream);
void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
				bool enable, int index);
int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
				struct hdac_ext_stream *stream, u32 value);
int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value);

void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hstream);
void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hstream);
+6 −0
Original line number Diff line number Diff line
@@ -77,6 +77,12 @@ int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *ebus)
			ebus->spbcap = bus->remap_addr + offset;
			break;

		case AZX_DRSM_CAP_ID:
			/* DMA resume  capability found, handler function */
			dev_dbg(bus->dev, "Found DRSM capability\n");
			ebus->drsmcap = bus->remap_addr + offset;
			break;

		default:
			dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap);
			break;
+71 −0
Original line number Diff line number Diff line
@@ -59,6 +59,10 @@ void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus,
					AZX_SPB_MAXFIFO;
	}

	if (ebus->drsmcap)
		stream->dpibr_addr = ebus->drsmcap + AZX_DRSM_BASE +
					AZX_DRSM_INTERVAL * idx;

	stream->decoupled = false;
	snd_hdac_stream_init(bus, &stream->hstream, idx, direction, tag);
}
@@ -497,3 +501,70 @@ void snd_hdac_ext_stop_streams(struct hdac_ext_bus *ebus)
	}
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stop_streams);

/**
 * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream
 * @ebus: HD-audio ext core bus
 * @enable: flag to enable/disable DRSM
 * @index: stream index for which DRSM need to be enabled
 */
void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
				bool enable, int index)
{
	u32 mask = 0;
	u32 register_mask = 0;
	struct hdac_bus *bus = &ebus->bus;

	if (!ebus->drsmcap) {
		dev_err(bus->dev, "Address of DRSM capability is NULL");
		return;
	}

	mask |= (1 << index);

	register_mask = readl(ebus->drsmcap + AZX_REG_SPB_SPBFCCTL);

	mask |= register_mask;

	if (enable)
		snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, 0, mask);
	else
		snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, mask, 0);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);

/**
 * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream
 * @ebus: HD-audio ext core bus
 * @stream: hdac_ext_stream
 * @value: dpib value to set
 */
int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
				 struct hdac_ext_stream *stream, u32 value)
{
	struct hdac_bus *bus = &ebus->bus;

	if (!ebus->drsmcap) {
		dev_err(bus->dev, "Address of DRSM capability is NULL");
		return -EINVAL;
	}

	writel(value, stream->dpibr_addr);

	return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr);

/**
 * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream
 * @ebus: HD-audio ext core bus
 * @stream: hdac_ext_stream
 * @value: lpib value to set
 */
int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value)
{
	snd_hdac_stream_writel(&stream->hstream, SD_LPIB, value);

	return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib);