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

Commit 8355aaf6 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'topic/hda-link-time' into for-next

parents 41f5e3bd bfcba288
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -89,6 +89,19 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_REG_SD_BDLPL		0x18
#define AZX_REG_SD_BDLPU		0x1c

/* GTS registers */
#define AZX_REG_LLCH			0x14

#define AZX_REG_GTS_BASE		0x520

#define AZX_REG_GTSCC	(AZX_REG_GTS_BASE + 0x00)
#define AZX_REG_WALFCC	(AZX_REG_GTS_BASE + 0x04)
#define AZX_REG_TSCCL	(AZX_REG_GTS_BASE + 0x08)
#define AZX_REG_TSCCU	(AZX_REG_GTS_BASE + 0x0C)
#define AZX_REG_LLPFOC	(AZX_REG_GTS_BASE + 0x14)
#define AZX_REG_LLPCL	(AZX_REG_GTS_BASE + 0x18)
#define AZX_REG_LLPCU	(AZX_REG_GTS_BASE + 0x1C)

/* Haswell/Broadwell display HD-A controller Extended Mode registers */
#define AZX_REG_HSW_EM4			0x100c
#define AZX_REG_HSW_EM5			0x1010
@@ -242,6 +255,29 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
/* Interval used to calculate the iterating register offset */
#define AZX_DRSM_INTERVAL		0x08

/* Global time synchronization registers */
#define GTSCC_TSCCD_MASK		0x80000000
#define GTSCC_TSCCD_SHIFT		BIT(31)
#define GTSCC_TSCCI_MASK		0x20
#define GTSCC_CDMAS_DMA_DIR_SHIFT	4

#define WALFCC_CIF_MASK			0x1FF
#define WALFCC_FN_SHIFT			9
#define HDA_CLK_CYCLES_PER_FRAME	512

/*
 * An error occurs near frame "rollover". The clocks in frame value indicates
 * whether this error may have occurred. Here we use the value of 10. Please
 * see the errata for the right number [<10]
 */
#define HDA_MAX_CYCLE_VALUE		499
#define HDA_MAX_CYCLE_OFFSET		10
#define HDA_MAX_CYCLE_READ_RETRY	10

#define TSCCU_CCU_SHIFT			32
#define LLPC_CCU_SHIFT			32


/*
 * helpers to read the stream position
 */
+13 −0
Original line number Diff line number Diff line
@@ -245,6 +245,12 @@ struct hdac_rb {

/*
 * HD-audio bus base driver
 *
 * @ppcap: pp capabilities pointer
 * @spbcap: SPIB capabilities pointer
 * @mlcap: MultiLink capabilities pointer
 * @gtscap: gts capabilities pointer
 * @drsmcap: dma resume capabilities pointer
 */
struct hdac_bus {
	struct device *dev;
@@ -256,6 +262,12 @@ struct hdac_bus {
	void __iomem *remap_addr;
	int irq;

	void __iomem *ppcap;
	void __iomem *spbcap;
	void __iomem *mlcap;
	void __iomem *gtscap;
	void __iomem *drsmcap;

	/* codec linked list */
	struct list_head codec_list;
	unsigned int num_codecs;
@@ -335,6 +347,7 @@ static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val);
int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
			      unsigned int *res);
int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus);
int snd_hdac_link_power(struct hdac_device *codec, bool enable);

bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset);
+0 −12
Original line number Diff line number Diff line
@@ -8,11 +8,6 @@
 *
 * @bus: hdac bus
 * @num_streams: streams supported
 * @ppcap: pp capabilities pointer
 * @spbcap: SPIB capabilities pointer
 * @mlcap: MultiLink capabilities pointer
 * @gtscap: gts capabilities pointer
 * @drsmcap: dma resume capabilities pointer
 * @hlink_list: link list of HDA links
 * @lock: lock for link mgmt
 * @cmd_dma_state: state of cmd DMAs: CORB and RIRB
@@ -22,12 +17,6 @@ struct hdac_ext_bus {
	int num_streams;
	int idx;

	void __iomem *ppcap;
	void __iomem *spbcap;
	void __iomem *mlcap;
	void __iomem *gtscap;
	void __iomem *drsmcap;

	struct list_head hlink_list;

	struct mutex lock;
@@ -54,7 +43,6 @@ void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus);
#define HDA_CODEC_EXT_ENTRY(_vid, _revid, _name, _drv_data) \
	HDA_CODEC_REV_EXT_ENTRY(_vid, _revid, _name, _drv_data)

int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *sbus);
void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *chip, bool enable);
void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *chip, bool enable);

+8 −83
Original line number Diff line number Diff line
@@ -29,81 +29,6 @@
 */
#define HDAC_MAX_CAPS 10

/**
 * snd_hdac_ext_bus_parse_capabilities - parse capablity structure
 * @ebus: the pointer to extended bus object
 *
 * Returns 0 if successful, or a negative error code.
 */
int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *ebus)
{
	unsigned int cur_cap;
	unsigned int offset;
	struct hdac_bus *bus = &ebus->bus;
	unsigned int counter = 0;

	offset = snd_hdac_chip_readl(bus, LLCH);

	/* Lets walk the linked capabilities list */
	do {
		cur_cap = _snd_hdac_chip_read(l, bus, offset);

		dev_dbg(bus->dev, "Capability version: 0x%x\n",
				((cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF));

		dev_dbg(bus->dev, "HDA capability ID: 0x%x\n",
				(cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF);

		switch ((cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF) {
		case AZX_ML_CAP_ID:
			dev_dbg(bus->dev, "Found ML capability\n");
			ebus->mlcap = bus->remap_addr + offset;
			break;

		case AZX_GTS_CAP_ID:
			dev_dbg(bus->dev, "Found GTS capability offset=%x\n", offset);
			ebus->gtscap = bus->remap_addr + offset;
			break;

		case AZX_PP_CAP_ID:
			/* PP capability found, the Audio DSP is present */
			dev_dbg(bus->dev, "Found PP capability offset=%x\n", offset);
			ebus->ppcap = bus->remap_addr + offset;
			break;

		case AZX_SPB_CAP_ID:
			/* SPIB capability found, handler function */
			dev_dbg(bus->dev, "Found SPB capability\n");
			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;
		}

		counter++;

		if (counter > HDAC_MAX_CAPS) {
			dev_err(bus->dev, "We exceeded HDAC Ext capablities!!!\n");
			break;
		}

		/* read the offset of next capabiity */
		offset = cur_cap & AZX_CAP_HDR_NXT_PTR_MASK;

	} while (offset);

	return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_parse_capabilities);

/*
 * processing pipe helpers - these helpers are useful for dealing with HDA
 * new capability of processing pipelines
@@ -118,15 +43,15 @@ void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *ebus, bool enable)
{
	struct hdac_bus *bus = &ebus->bus;

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

	if (enable)
		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN);
		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN);
	else
		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0);
		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable);

@@ -139,15 +64,15 @@ void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *ebus, bool enable)
{
	struct hdac_bus *bus = &ebus->bus;

	if (!ebus->ppcap) {
	if (!bus->ppcap) {
		dev_err(bus->dev, "Address of PP capability is NULL\n");
		return;
	}

	if (enable)
		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE);
		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE);
	else
		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0);
		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable);

@@ -171,7 +96,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
	struct hdac_ext_link *hlink;
	struct hdac_bus *bus = &ebus->bus;

	link_count = readl(ebus->mlcap + AZX_REG_ML_MLCD) + 1;
	link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1;

	dev_dbg(bus->dev, "In %s Link count: %d\n", __func__, link_count);

@@ -181,7 +106,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
			return -ENOMEM;
		hlink->index = idx;
		hlink->bus = bus;
		hlink->ml_addr = ebus->mlcap + AZX_ML_BASE +
		hlink->ml_addr = bus->mlcap + AZX_ML_BASE +
					(AZX_ML_INTERVAL * idx);
		hlink->lcaps  = readl(hlink->ml_addr + AZX_REG_ML_LCAP);
		hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID);
+23 −23
Original line number Diff line number Diff line
@@ -40,27 +40,27 @@ void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus,
{
	struct hdac_bus *bus = &ebus->bus;

	if (ebus->ppcap) {
		stream->pphc_addr = ebus->ppcap + AZX_PPHC_BASE +
	if (bus->ppcap) {
		stream->pphc_addr = bus->ppcap + AZX_PPHC_BASE +
				AZX_PPHC_INTERVAL * idx;

		stream->pplc_addr = ebus->ppcap + AZX_PPLC_BASE +
		stream->pplc_addr = bus->ppcap + AZX_PPLC_BASE +
				AZX_PPLC_MULTI * ebus->num_streams +
				AZX_PPLC_INTERVAL * idx;
	}

	if (ebus->spbcap) {
		stream->spib_addr = ebus->spbcap + AZX_SPB_BASE +
	if (bus->spbcap) {
		stream->spib_addr = bus->spbcap + AZX_SPB_BASE +
					AZX_SPB_INTERVAL * idx +
					AZX_SPB_SPIB;

		stream->fifo_addr = ebus->spbcap + AZX_SPB_BASE +
		stream->fifo_addr = bus->spbcap + AZX_SPB_BASE +
					AZX_SPB_INTERVAL * idx +
					AZX_SPB_MAXFIFO;
	}

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

	stream->decoupled = false;
@@ -131,10 +131,10 @@ void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus,

	spin_lock_irq(&bus->reg_lock);
	if (decouple)
		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0,
		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0,
				AZX_PPCTL_PROCEN(hstream->index));
	else
		snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL,
		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
					AZX_PPCTL_PROCEN(hstream->index), 0);
	stream->decoupled = decouple;
	spin_unlock_irq(&bus->reg_lock);
@@ -255,7 +255,7 @@ hdac_ext_link_stream_assign(struct hdac_ext_bus *ebus,
	struct hdac_stream *stream = NULL;
	struct hdac_bus *hbus = &ebus->bus;

	if (!ebus->ppcap) {
	if (!hbus->ppcap) {
		dev_err(hbus->dev, "stream type not supported\n");
		return NULL;
	}
@@ -296,7 +296,7 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
	struct hdac_stream *stream = NULL;
	struct hdac_bus *hbus = &ebus->bus;

	if (!ebus->ppcap) {
	if (!hbus->ppcap) {
		dev_err(hbus->dev, "stream type not supported\n");
		return NULL;
	}
@@ -423,21 +423,21 @@ void snd_hdac_ext_stream_spbcap_enable(struct hdac_ext_bus *ebus,
	u32 register_mask = 0;
	struct hdac_bus *bus = &ebus->bus;

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

	mask |= (1 << index);

	register_mask = readl(ebus->spbcap + AZX_REG_SPB_SPBFCCTL);
	register_mask = readl(bus->spbcap + AZX_REG_SPB_SPBFCCTL);

	mask |= register_mask;

	if (enable)
		snd_hdac_updatel(ebus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask);
		snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask);
	else
		snd_hdac_updatel(ebus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0);
		snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable);

@@ -452,7 +452,7 @@ int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus,
{
	struct hdac_bus *bus = &ebus->bus;

	if (!ebus->spbcap) {
	if (!bus->spbcap) {
		dev_err(bus->dev, "Address of SPB capability is NULL");
		return -EINVAL;
	}
@@ -475,7 +475,7 @@ int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
{
	struct hdac_bus *bus = &ebus->bus;

	if (!ebus->spbcap) {
	if (!bus->spbcap) {
		dev_err(bus->dev, "Address of SPB capability is NULL");
		return -EINVAL;
	}
@@ -515,21 +515,21 @@ void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
	u32 register_mask = 0;
	struct hdac_bus *bus = &ebus->bus;

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

	mask |= (1 << index);

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

	mask |= register_mask;

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

@@ -544,7 +544,7 @@ int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
{
	struct hdac_bus *bus = &ebus->bus;

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