All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC v2 0/3] ALSA: hda: add hda controller to hda core
@ 2015-03-25  6:01 Vinod Koul
  2015-03-25  6:01 ` [RFC v2 1/3] ALSA: hda: add HDA_MAX_CODECS Vinod Koul
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Vinod Koul @ 2015-03-25  6:01 UTC (permalink / raw)
  To: alsa-devel; +Cc: tiwai, jeeja.kp, Vinod Koul, lgirdwood

This series starts adding base hda controller code to hda core. There are
few more changes like dsp loader etc planned to be added as well.

This is based on Takashi's test/hda-core branch with patches posted last
week, we have modified naming convention loosely based on takashi's work,
Takshi feel free to recommend more changes if you think they are required


Jeeja KP (2):
  ALSA: hda: move common hda controller register defines up
  ALSA: hda: add hda controller to hda

Vinod Koul (1):
  ALSA: hda: add HDA_MAX_CODECS

 include/sound/hda_registers.h  |  200 +++++++
 include/sound/hda_verbs.h      |    1 +
 include/sound/hdaudio.h        |  215 +++++++
 sound/hda/Makefile             |    2 +-
 sound/hda/hdac_controller.c    | 1284 ++++++++++++++++++++++++++++++++++++++++
 sound/pci/hda/hda_controller.c |    4 +-
 sound/pci/hda/hda_controller.h |  203 +------
 7 files changed, 1707 insertions(+), 202 deletions(-)
 create mode 100644 include/sound/hda_registers.h
 create mode 100644 sound/hda/hdac_controller.c

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC v2 1/3] ALSA: hda: add HDA_MAX_CODECS
  2015-03-25  6:01 [RFC v2 0/3] ALSA: hda: add hda controller to hda core Vinod Koul
@ 2015-03-25  6:01 ` Vinod Koul
  2015-03-25  6:48   ` Takashi Iwai
  2015-03-25  6:01 ` [RFC v2 2/3] ALSA: hda: move common hda controller register defines up Vinod Koul
  2015-03-25  6:01 ` [RFC v2 3/3] ALSA: hda: add hda controller to hda Vinod Koul
  2 siblings, 1 reply; 10+ messages in thread
From: Vinod Koul @ 2015-03-25  6:01 UTC (permalink / raw)
  To: alsa-devel; +Cc: tiwai, jeeja.kp, Vinod Koul, lgirdwood

This moves AZX_MAX_CODECS define to HDA_MAX_CODECS so that common code can
use this as well

Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 include/sound/hda_verbs.h      |    1 +
 sound/pci/hda/hda_controller.c |    4 ++--
 sound/pci/hda/hda_controller.h |    9 ++++-----
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/include/sound/hda_verbs.h b/include/sound/hda_verbs.h
index d0509db6d0ec..42b8415b2254 100644
--- a/include/sound/hda_verbs.h
+++ b/include/sound/hda_verbs.h
@@ -550,5 +550,6 @@ enum {
 
 /* max. codec address */
 #define HDA_MAX_CODEC_ADDRESS	0x0f
+#define HDA_MAX_CODECS		8
 
 #endif /* __SOUND_HDA_VERBS_H */
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 26ce990592a0..abb3822f5488 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -1066,7 +1066,7 @@ static unsigned int azx_command_addr(u32 cmd)
 {
 	unsigned int addr = cmd >> 28;
 
-	if (addr >= AZX_MAX_CODECS) {
+	if (addr >= HDA_MAX_CODECS) {
 		snd_BUG();
 		addr = 0;
 	}
@@ -1136,7 +1136,7 @@ static void azx_update_rirb(struct azx *chip)
 		res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
 		res = le32_to_cpu(chip->rirb.buf[rp]);
 		addr = res_ex & 0xf;
-		if ((addr >= AZX_MAX_CODECS) || !(chip->codec_mask & (1 << addr))) {
+		if ((addr >= HDA_MAX_CODECS) || !(chip->codec_mask & (1 << addr))) {
 			dev_err(chip->card->dev, "spurious response %#x:%#x, rp = %d, wp = %d",
 				res, res_ex,
 				chip->rirb.rp, wp);
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
index be1b7ded8d82..2aa75e34a718 100644
--- a/sound/pci/hda/hda_controller.h
+++ b/sound/pci/hda/hda_controller.h
@@ -119,9 +119,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define RIRB_INT_MASK		0x05
 
 /* STATESTS int mask: S3,SD2,SD1,SD0 */
-#define AZX_MAX_CODECS		8
 #define AZX_DEFAULT_CODECS	4
-#define STATESTS_INT_MASK	((1 << AZX_MAX_CODECS) - 1)
+#define STATESTS_INT_MASK	((1 << HDA_MAX_CODECS) - 1)
 
 /* SD_CTL bits */
 #define SD_CTL_STREAM_RESET	0x01	/* stream reset bit */
@@ -245,8 +244,8 @@ struct azx_rb {
 	dma_addr_t addr;	/* physical address of CORB/RIRB buffer */
 	/* for RIRB */
 	unsigned short rp, wp;	/* read/write pointers */
-	int cmds[AZX_MAX_CODECS];	/* number of pending requests */
-	u32 res[AZX_MAX_CODECS];	/* last read value */
+	int cmds[HDA_MAX_CODECS];	/* number of pending requests */
+	u32 res[HDA_MAX_CODECS];	/* last read value */
 };
 
 struct azx;
@@ -360,7 +359,7 @@ struct azx {
 	unsigned int disabled:1; /* disabled by VGA-switcher */
 
 	/* for debugging */
-	unsigned int last_cmd[AZX_MAX_CODECS];
+	unsigned int last_cmd[HDA_MAX_CODECS];
 
 #ifdef CONFIG_SND_HDA_DSP_LOADER
 	struct azx_dev saved_azx_dev;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [RFC v2 2/3] ALSA: hda: move common hda controller register defines up
  2015-03-25  6:01 [RFC v2 0/3] ALSA: hda: add hda controller to hda core Vinod Koul
  2015-03-25  6:01 ` [RFC v2 1/3] ALSA: hda: add HDA_MAX_CODECS Vinod Koul
@ 2015-03-25  6:01 ` Vinod Koul
  2015-03-25  6:01 ` [RFC v2 3/3] ALSA: hda: add hda controller to hda Vinod Koul
  2 siblings, 0 replies; 10+ messages in thread
From: Vinod Koul @ 2015-03-25  6:01 UTC (permalink / raw)
  To: alsa-devel; +Cc: tiwai, jeeja.kp, Vinod Koul, lgirdwood

From: Jeeja KP <jeeja.kp@intel.com>

The HDA register defines would be accessed by both existing codes as well as
new code, so move it up to include/sound
No code change, fixed few alignment though

Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 include/sound/hda_registers.h  |  200 ++++++++++++++++++++++++++++++++++++++++
 sound/pci/hda/hda_controller.h |  196 +--------------------------------------
 2 files changed, 201 insertions(+), 195 deletions(-)
 create mode 100644 include/sound/hda_registers.h

diff --git a/include/sound/hda_registers.h b/include/sound/hda_registers.h
new file mode 100644
index 000000000000..d891c4f28f6f
--- /dev/null
+++ b/include/sound/hda_registers.h
@@ -0,0 +1,200 @@
+#ifndef __SOUND_HDA_REGISTERS_H
+#define __SOUND_HDA_REGISTERS_H
+
+/*
+ * registers
+ */
+#define AZX_REG_GCAP			0x00
+#define AZX_GCAP_64OK			(1 << 0)   /* 64bit address support */
+#define AZX_GCAP_NSDO			(3 << 1)   /* # of serial data out signals */
+#define AZX_GCAP_BSS			(31 << 3)  /* # of bidirectional streams */
+#define AZX_GCAP_ISS			(15 << 8)  /* # of input streams */
+#define AZX_GCAP_OSS			(15 << 12) /* # of output streams */
+#define AZX_REG_VMIN			0x02
+#define AZX_REG_VMAJ			0x03
+#define AZX_REG_OUTPAY			0x04
+#define AZX_REG_INPAY			0x06
+#define AZX_REG_GCTL			0x08
+#define AZX_GCTL_RESET			(1 << 0)   /* controller reset */
+#define AZX_GCTL_FCNTRL			(1 << 1)   /* flush control */
+#define AZX_GCTL_UNSOL			(1 << 8)   /* accept unsol. response enable */
+#define AZX_REG_WAKEEN			0x0c
+#define AZX_REG_STATESTS		0x0e
+#define AZX_REG_GSTS			0x10
+#define AZX_GSTS_FSTS			(1 << 1)   /* flush status */
+#define AZX_REG_INTCTL			0x20
+#define AZX_REG_INTSTS			0x24
+#define AZX_REG_WALLCLK			0x30	/* 24Mhz source */
+#define AZX_REG_OLD_SSYNC		0x34	/* SSYNC for old ICH */
+#define AZX_REG_SSYNC			0x38
+#define AZX_REG_CORBLBASE		0x40
+#define AZX_REG_CORBUBASE		0x44
+#define AZX_REG_CORBWP			0x48
+#define AZX_REG_CORBRP			0x4a
+#define AZX_CORBRP_RST			(1 << 15)  /* read pointer reset */
+#define AZX_REG_CORBCTL			0x4c
+#define AZX_CORBCTL_RUN			(1 << 1)   /* enable DMA */
+#define AZX_CORBCTL_CMEIE		(1 << 0)   /* enable memory error irq */
+#define AZX_REG_CORBSTS			0x4d
+#define AZX_CORBSTS_CMEI		(1 << 0)   /* memory error indication */
+#define AZX_REG_CORBSIZE		0x4e
+
+#define AZX_REG_RIRBLBASE		0x50
+#define AZX_REG_RIRBUBASE		0x54
+#define AZX_REG_RIRBWP			0x58
+#define AZX_RIRBWP_RST			(1 << 15)  /* write pointer reset */
+#define AZX_REG_RINTCNT			0x5a
+#define AZX_REG_RIRBCTL			0x5c
+#define AZX_RBCTL_IRQ_EN		(1 << 0)   /* enable IRQ */
+#define AZX_RBCTL_DMA_EN		(1 << 1)   /* enable DMA */
+#define AZX_RBCTL_OVERRUN_EN		(1 << 2)   /* enable overrun irq */
+#define AZX_REG_RIRBSTS			0x5d
+#define AZX_RBSTS_IRQ			(1 << 0)   /* response irq */
+#define AZX_RBSTS_OVERRUN		(1 << 2)   /* overrun irq */
+#define AZX_REG_RIRBSIZE		0x5e
+
+#define AZX_REG_IC			0x60
+#define AZX_REG_IR			0x64
+#define AZX_REG_IRS			0x68
+#define AZX_IRS_VALID			(1<<1)
+#define AZX_IRS_BUSY			(1<<0)
+
+#define AZX_REG_DPLBASE			0x70
+#define AZX_REG_DPUBASE			0x74
+#define AZX_DPLBASE_ENABLE		0x1	/* Enable position buffer */
+
+/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
+
+/* stream register offsets from stream base */
+#define AZX_REG_SD_CTL			0x00
+#define AZX_REG_SD_STS			0x03
+#define AZX_REG_SD_LPIB			0x04
+#define AZX_REG_SD_CBL			0x08
+#define AZX_REG_SD_LVI			0x0c
+#define AZX_REG_SD_FIFOW		0x0e
+#define AZX_REG_SD_FIFOSIZE		0x10
+#define AZX_REG_SD_FORMAT		0x12
+#define AZX_REG_SD_BDLPL		0x18
+#define AZX_REG_SD_BDLPU		0x1c
+
+/* PCI space */
+#define AZX_PCIREG_TCSEL		0x44
+
+/*
+ * other constants
+ */
+
+/* max number of fragments - we may use more if allocating more pages for BDL */
+#define BDL_SIZE		4096
+#define AZX_MAX_BDL_ENTRIES	(BDL_SIZE / 16)
+#define AZX_MAX_FRAG		32
+/* max buffer size - no h/w limit, you can increase as you like */
+#define AZX_MAX_BUF_SIZE	(1024*1024*1024)
+
+/* RIRB int mask: overrun[2], response[0] */
+#define RIRB_INT_RESPONSE	0x01
+#define RIRB_INT_OVERRUN	0x04
+#define RIRB_INT_MASK		0x05
+
+/* STATESTS int mask: S3,SD2,SD1,SD0 */
+#define AZX_DEFAULT_CODECS	4
+#define STATESTS_INT_MASK	((1 << HDA_MAX_CODECS) - 1)
+
+/* SD_CTL bits */
+#define SD_CTL_STREAM_RESET	0x01	/* stream reset bit */
+#define SD_CTL_DMA_START	0x02	/* stream DMA start bit */
+#define SD_CTL_STRIPE		(3 << 16)	/* stripe control */
+#define SD_CTL_TRAFFIC_PRIO	(1 << 18)	/* traffic priority */
+#define SD_CTL_DIR		(1 << 19)	/* bi-directional stream */
+#define SD_CTL_STREAM_TAG_MASK	(0xf << 20)
+#define SD_CTL_STREAM_TAG_SHIFT	20
+
+/* SD_CTL and SD_STS */
+#define SD_INT_DESC_ERR		0x10	/* descriptor error interrupt */
+#define SD_INT_FIFO_ERR		0x08	/* FIFO error interrupt */
+#define SD_INT_COMPLETE		0x04	/* completion interrupt */
+#define SD_INT_MASK		(SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
+				 SD_INT_COMPLETE)
+
+/* SD_STS */
+#define SD_STS_FIFO_READY	0x20	/* FIFO ready */
+
+/* INTCTL and INTSTS */
+#define AZX_INT_ALL_STREAM	0xff	   /* all stream interrupts */
+#define AZX_INT_CTRL_EN		0x40000000 /* controller interrupt enable bit */
+#define AZX_INT_GLOBAL_EN	0x80000000 /* global interrupt enable bit */
+
+/* below are so far hardcoded - should read registers in future */
+#define AZX_MAX_CORB_ENTRIES	256
+#define AZX_MAX_RIRB_ENTRIES	256
+
+/* driver quirks (capabilities) */
+/* bits 0-7 are used for indicating driver type */
+#define AZX_DCAPS_NO_TCSEL		(1 << 8)	/* No Intel TCSEL bit */
+#define AZX_DCAPS_NO_MSI		(1 << 9)	/* No MSI support */
+#define AZX_DCAPS_SNOOP_MASK		(3 << 10)	/* snoop type mask */
+#define AZX_DCAPS_SNOOP_OFF		(1 << 12)	/* snoop default off */
+#define AZX_DCAPS_RIRB_DELAY		(1 << 13)	/* Long delay in read loop */
+#define AZX_DCAPS_RIRB_PRE_DELAY 	(1 << 14)	/* Put a delay before read */
+#define AZX_DCAPS_CTX_WORKAROUND 	(1 << 15)	/* X-Fi workaround */
+#define AZX_DCAPS_POSFIX_LPIB		(1 << 16)	/* Use LPIB as default */
+#define AZX_DCAPS_POSFIX_VIA		(1 << 17)	/* Use VIACOMBO as default */
+#define AZX_DCAPS_NO_64BIT		(1 << 18)	/* No 64bit address */
+#define AZX_DCAPS_SYNC_WRITE		(1 << 19)	/* sync each cmd write */
+#define AZX_DCAPS_OLD_SSYNC		(1 << 20)	/* Old SSYNC reg for ICH */
+#define AZX_DCAPS_NO_ALIGN_BUFSIZE 	(1 << 21)	/* no buffer size alignment */
+/* 22 unused */
+#define AZX_DCAPS_4K_BDLE_BOUNDARY 	(1 << 23)	/* BDLE in 4k boundary */
+#define AZX_DCAPS_REVERSE_ASSIGN 	(1 << 24)	/* Assign devices in reverse order */
+#define AZX_DCAPS_COUNT_LPIB_DELAY	(1 << 25)	/* Take LPIB as delay */
+#define AZX_DCAPS_PM_RUNTIME		(1 << 26)	/* runtime PM support */
+#define AZX_DCAPS_I915_POWERWELL 	(1 << 27)	/* HSW i915 powerwell support */
+#define AZX_DCAPS_CORBRP_SELF_CLEAR 	(1 << 28)	/* CORBRP clears itself after reset */
+#define AZX_DCAPS_NO_MSI64      	(1 << 29)	/* Stick to 32-bit MSIs */
+#define AZX_DCAPS_SEPARATE_STREAM_TAG	(1 << 30) /* capture and playback use separate stream tag */
+
+enum {
+	AZX_SNOOP_TYPE_NONE,
+	AZX_SNOOP_TYPE_SCH,
+	AZX_SNOOP_TYPE_ATI,
+	AZX_SNOOP_TYPE_NVIDIA,
+};
+
+/* HD Audio class code */
+#define PCI_CLASS_MULTIMEDIA_HD_AUDIO	0x0403
+
+/*
+ * macros for easy use
+ */
+
+#define azx_writel(chip, reg, value) \
+	((chip)->ops->reg_writel(value, (chip)->remap_addr + AZX_REG_##reg))
+#define azx_readl(chip, reg) \
+	((chip)->ops->reg_readl((chip)->remap_addr + AZX_REG_##reg))
+#define azx_writew(chip, reg, value) \
+	((chip)->ops->reg_writew(value, (chip)->remap_addr + AZX_REG_##reg))
+#define azx_readw(chip, reg) \
+	((chip)->ops->reg_readw((chip)->remap_addr + AZX_REG_##reg))
+#define azx_writeb(chip, reg, value) \
+	((chip)->ops->reg_writeb(value, (chip)->remap_addr + AZX_REG_##reg))
+#define azx_readb(chip, reg) \
+	((chip)->ops->reg_readb((chip)->remap_addr + AZX_REG_##reg))
+
+#define azx_sd_writel(chip, dev, reg, value) \
+	((chip)->ops->reg_writel(value, (dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_readl(chip, dev, reg) \
+	((chip)->ops->reg_readl((dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_writew(chip, dev, reg, value) \
+	((chip)->ops->reg_writew(value, (dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_readw(chip, dev, reg) \
+	((chip)->ops->reg_readw((dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_writeb(chip, dev, reg, value) \
+	((chip)->ops->reg_writeb(value, (dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_readb(chip, dev, reg) \
+	((chip)->ops->reg_readb((dev)->sd_addr + AZX_REG_##reg))
+
+#define azx_has_pm_runtime(chip) \
+	(!AZX_DCAPS_PM_RUNTIME || ((chip)->driver_caps & AZX_DCAPS_PM_RUNTIME))
+
+#endif
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
index 2aa75e34a718..e5d35b495363 100644
--- a/sound/pci/hda/hda_controller.h
+++ b/sound/pci/hda/hda_controller.h
@@ -20,171 +20,9 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
+#include <sound/hda_registers.h>
 #include "hda_codec.h"
 
-/*
- * registers
- */
-#define AZX_REG_GCAP			0x00
-#define   AZX_GCAP_64OK		(1 << 0)   /* 64bit address support */
-#define   AZX_GCAP_NSDO		(3 << 1)   /* # of serial data out signals */
-#define   AZX_GCAP_BSS		(31 << 3)  /* # of bidirectional streams */
-#define   AZX_GCAP_ISS		(15 << 8)  /* # of input streams */
-#define   AZX_GCAP_OSS		(15 << 12) /* # of output streams */
-#define AZX_REG_VMIN			0x02
-#define AZX_REG_VMAJ			0x03
-#define AZX_REG_OUTPAY			0x04
-#define AZX_REG_INPAY			0x06
-#define AZX_REG_GCTL			0x08
-#define   AZX_GCTL_RESET	(1 << 0)   /* controller reset */
-#define   AZX_GCTL_FCNTRL	(1 << 1)   /* flush control */
-#define   AZX_GCTL_UNSOL	(1 << 8)   /* accept unsol. response enable */
-#define AZX_REG_WAKEEN			0x0c
-#define AZX_REG_STATESTS		0x0e
-#define AZX_REG_GSTS			0x10
-#define   AZX_GSTS_FSTS		(1 << 1)   /* flush status */
-#define AZX_REG_INTCTL			0x20
-#define AZX_REG_INTSTS			0x24
-#define AZX_REG_WALLCLK			0x30	/* 24Mhz source */
-#define AZX_REG_OLD_SSYNC		0x34	/* SSYNC for old ICH */
-#define AZX_REG_SSYNC			0x38
-#define AZX_REG_CORBLBASE		0x40
-#define AZX_REG_CORBUBASE		0x44
-#define AZX_REG_CORBWP			0x48
-#define AZX_REG_CORBRP			0x4a
-#define   AZX_CORBRP_RST	(1 << 15)  /* read pointer reset */
-#define AZX_REG_CORBCTL			0x4c
-#define   AZX_CORBCTL_RUN	(1 << 1)   /* enable DMA */
-#define   AZX_CORBCTL_CMEIE	(1 << 0)   /* enable memory error irq */
-#define AZX_REG_CORBSTS			0x4d
-#define   AZX_CORBSTS_CMEI	(1 << 0)   /* memory error indication */
-#define AZX_REG_CORBSIZE		0x4e
-
-#define AZX_REG_RIRBLBASE		0x50
-#define AZX_REG_RIRBUBASE		0x54
-#define AZX_REG_RIRBWP			0x58
-#define   AZX_RIRBWP_RST	(1 << 15)  /* write pointer reset */
-#define AZX_REG_RINTCNT			0x5a
-#define AZX_REG_RIRBCTL			0x5c
-#define   AZX_RBCTL_IRQ_EN	(1 << 0)   /* enable IRQ */
-#define   AZX_RBCTL_DMA_EN	(1 << 1)   /* enable DMA */
-#define   AZX_RBCTL_OVERRUN_EN	(1 << 2)   /* enable overrun irq */
-#define AZX_REG_RIRBSTS			0x5d
-#define   AZX_RBSTS_IRQ		(1 << 0)   /* response irq */
-#define   AZX_RBSTS_OVERRUN	(1 << 2)   /* overrun irq */
-#define AZX_REG_RIRBSIZE		0x5e
-
-#define AZX_REG_IC			0x60
-#define AZX_REG_IR			0x64
-#define AZX_REG_IRS			0x68
-#define   AZX_IRS_VALID		(1<<1)
-#define   AZX_IRS_BUSY		(1<<0)
-
-#define AZX_REG_DPLBASE			0x70
-#define AZX_REG_DPUBASE			0x74
-#define   AZX_DPLBASE_ENABLE	0x1	/* Enable position buffer */
-
-/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
-enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
-
-/* stream register offsets from stream base */
-#define AZX_REG_SD_CTL			0x00
-#define AZX_REG_SD_STS			0x03
-#define AZX_REG_SD_LPIB			0x04
-#define AZX_REG_SD_CBL			0x08
-#define AZX_REG_SD_LVI			0x0c
-#define AZX_REG_SD_FIFOW		0x0e
-#define AZX_REG_SD_FIFOSIZE		0x10
-#define AZX_REG_SD_FORMAT		0x12
-#define AZX_REG_SD_BDLPL		0x18
-#define AZX_REG_SD_BDLPU		0x1c
-
-/* PCI space */
-#define AZX_PCIREG_TCSEL		0x44
-
-/*
- * other constants
- */
-
-/* max number of fragments - we may use more if allocating more pages for BDL */
-#define BDL_SIZE		4096
-#define AZX_MAX_BDL_ENTRIES	(BDL_SIZE / 16)
-#define AZX_MAX_FRAG		32
-/* max buffer size - no h/w limit, you can increase as you like */
-#define AZX_MAX_BUF_SIZE	(1024*1024*1024)
-
-/* RIRB int mask: overrun[2], response[0] */
-#define RIRB_INT_RESPONSE	0x01
-#define RIRB_INT_OVERRUN	0x04
-#define RIRB_INT_MASK		0x05
-
-/* STATESTS int mask: S3,SD2,SD1,SD0 */
-#define AZX_DEFAULT_CODECS	4
-#define STATESTS_INT_MASK	((1 << HDA_MAX_CODECS) - 1)
-
-/* SD_CTL bits */
-#define SD_CTL_STREAM_RESET	0x01	/* stream reset bit */
-#define SD_CTL_DMA_START	0x02	/* stream DMA start bit */
-#define SD_CTL_STRIPE		(3 << 16)	/* stripe control */
-#define SD_CTL_TRAFFIC_PRIO	(1 << 18)	/* traffic priority */
-#define SD_CTL_DIR		(1 << 19)	/* bi-directional stream */
-#define SD_CTL_STREAM_TAG_MASK	(0xf << 20)
-#define SD_CTL_STREAM_TAG_SHIFT	20
-
-/* SD_CTL and SD_STS */
-#define SD_INT_DESC_ERR		0x10	/* descriptor error interrupt */
-#define SD_INT_FIFO_ERR		0x08	/* FIFO error interrupt */
-#define SD_INT_COMPLETE		0x04	/* completion interrupt */
-#define SD_INT_MASK		(SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
-				 SD_INT_COMPLETE)
-
-/* SD_STS */
-#define SD_STS_FIFO_READY	0x20	/* FIFO ready */
-
-/* INTCTL and INTSTS */
-#define AZX_INT_ALL_STREAM	0xff	   /* all stream interrupts */
-#define AZX_INT_CTRL_EN	0x40000000 /* controller interrupt enable bit */
-#define AZX_INT_GLOBAL_EN	0x80000000 /* global interrupt enable bit */
-
-/* below are so far hardcoded - should read registers in future */
-#define AZX_MAX_CORB_ENTRIES	256
-#define AZX_MAX_RIRB_ENTRIES	256
-
-/* driver quirks (capabilities) */
-/* bits 0-7 are used for indicating driver type */
-#define AZX_DCAPS_NO_TCSEL	(1 << 8)	/* No Intel TCSEL bit */
-#define AZX_DCAPS_NO_MSI	(1 << 9)	/* No MSI support */
-#define AZX_DCAPS_SNOOP_MASK	(3 << 10)	/* snoop type mask */
-#define AZX_DCAPS_SNOOP_OFF	(1 << 12)	/* snoop default off */
-#define AZX_DCAPS_RIRB_DELAY	(1 << 13)	/* Long delay in read loop */
-#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14)	/* Put a delay before read */
-#define AZX_DCAPS_CTX_WORKAROUND (1 << 15)	/* X-Fi workaround */
-#define AZX_DCAPS_POSFIX_LPIB	(1 << 16)	/* Use LPIB as default */
-#define AZX_DCAPS_POSFIX_VIA	(1 << 17)	/* Use VIACOMBO as default */
-#define AZX_DCAPS_NO_64BIT	(1 << 18)	/* No 64bit address */
-#define AZX_DCAPS_SYNC_WRITE	(1 << 19)	/* sync each cmd write */
-#define AZX_DCAPS_OLD_SSYNC	(1 << 20)	/* Old SSYNC reg for ICH */
-#define AZX_DCAPS_NO_ALIGN_BUFSIZE (1 << 21)	/* no buffer size alignment */
-/* 22 unused */
-#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)	/* BDLE in 4k boundary */
-#define AZX_DCAPS_REVERSE_ASSIGN (1 << 24)	/* Assign devices in reverse order */
-#define AZX_DCAPS_COUNT_LPIB_DELAY  (1 << 25)	/* Take LPIB as delay */
-#define AZX_DCAPS_PM_RUNTIME	(1 << 26)	/* runtime PM support */
-#define AZX_DCAPS_I915_POWERWELL (1 << 27)	/* HSW i915 powerwell support */
-#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28)	/* CORBRP clears itself after reset */
-#define AZX_DCAPS_NO_MSI64      (1 << 29)	/* Stick to 32-bit MSIs */
-#define AZX_DCAPS_SEPARATE_STREAM_TAG	(1 << 30) /* capture and playback use separate stream tag */
-
-enum {
-	AZX_SNOOP_TYPE_NONE,
-	AZX_SNOOP_TYPE_SCH,
-	AZX_SNOOP_TYPE_ATI,
-	AZX_SNOOP_TYPE_NVIDIA,
-};
-
-/* HD Audio class code */
-#define PCI_CLASS_MULTIMEDIA_HD_AUDIO	0x0403
-
 struct azx_dev {
 	struct snd_dma_buffer bdl; /* BDL buffer */
 	u32 *posbuf;		/* position buffer pointer */
@@ -372,38 +210,6 @@ struct azx {
 #define azx_snoop(chip)		true
 #endif
 
-/*
- * macros for easy use
- */
-
-#define azx_writel(chip, reg, value) \
-	((chip)->ops->reg_writel(value, (chip)->remap_addr + AZX_REG_##reg))
-#define azx_readl(chip, reg) \
-	((chip)->ops->reg_readl((chip)->remap_addr + AZX_REG_##reg))
-#define azx_writew(chip, reg, value) \
-	((chip)->ops->reg_writew(value, (chip)->remap_addr + AZX_REG_##reg))
-#define azx_readw(chip, reg) \
-	((chip)->ops->reg_readw((chip)->remap_addr + AZX_REG_##reg))
-#define azx_writeb(chip, reg, value) \
-	((chip)->ops->reg_writeb(value, (chip)->remap_addr + AZX_REG_##reg))
-#define azx_readb(chip, reg) \
-	((chip)->ops->reg_readb((chip)->remap_addr + AZX_REG_##reg))
-
-#define azx_sd_writel(chip, dev, reg, value) \
-	((chip)->ops->reg_writel(value, (dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_readl(chip, dev, reg) \
-	((chip)->ops->reg_readl((dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_writew(chip, dev, reg, value) \
-	((chip)->ops->reg_writew(value, (dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_readw(chip, dev, reg) \
-	((chip)->ops->reg_readw((dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_writeb(chip, dev, reg, value) \
-	((chip)->ops->reg_writeb(value, (dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_readb(chip, dev, reg) \
-	((chip)->ops->reg_readb((dev)->sd_addr + AZX_REG_##reg))
-
-#define azx_has_pm_runtime(chip) \
-	(!AZX_DCAPS_PM_RUNTIME || ((chip)->driver_caps & AZX_DCAPS_PM_RUNTIME))
 
 /* PCM setup */
 static inline struct azx_dev *get_azx_dev(struct snd_pcm_substream *substream)
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [RFC v2 3/3] ALSA: hda: add hda controller to hda
  2015-03-25  6:01 [RFC v2 0/3] ALSA: hda: add hda controller to hda core Vinod Koul
  2015-03-25  6:01 ` [RFC v2 1/3] ALSA: hda: add HDA_MAX_CODECS Vinod Koul
  2015-03-25  6:01 ` [RFC v2 2/3] ALSA: hda: move common hda controller register defines up Vinod Koul
@ 2015-03-25  6:01 ` Vinod Koul
  2015-03-25  7:05   ` Takashi Iwai
  2 siblings, 1 reply; 10+ messages in thread
From: Vinod Koul @ 2015-03-25  6:01 UTC (permalink / raw)
  To: alsa-devel; +Cc: tiwai, jeeja.kp, Vinod Koul, lgirdwood

From: Jeeja KP <jeeja.kp@intel.com>

This adds hdac_controller into hda core.

Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 include/sound/hdaudio.h     |  215 ++++++++
 sound/hda/Makefile          |    2 +-
 sound/hda/hdac_controller.c | 1284 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1500 insertions(+), 1 deletion(-)
 create mode 100644 sound/hda/hdac_controller.c

diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 675614dc2b88..2843471efc7a 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -5,8 +5,11 @@
 #ifndef __SOUND_HDAUDIO_H
 #define __SOUND_HDAUDIO_H
 
+#include <linux/timecounter.h>
+#include <sound/core.h>
 #include <linux/device.h>
 #include <sound/hda_verbs.h>
+#include <sound/pcm.h>
 
 /* codec node id */
 typedef u16 hda_nid_t;
@@ -15,6 +18,7 @@ struct hdac_bus;
 struct hdac_device;
 struct hdac_driver;
 struct hdac_widget_tree;
+struct hda;
 
 /*
  * exported bus type
@@ -125,6 +129,8 @@ struct hdac_bus_ops {
 	/* get a response from the last command */
 	int (*get_response)(struct hdac_bus *bus, unsigned int addr,
 			    unsigned int *res);
+	/* reset bus for retry verb */
+	void (*bus_reset)(struct hdac_bus *bus);
 };
 
 #define HDA_UNSOL_QUEUE_SIZE	64
@@ -144,6 +150,7 @@ struct hdac_bus {
 	u32 unsol_queue[HDA_UNSOL_QUEUE_SIZE * 2]; /* ring buffer */
 	unsigned int unsol_rp, unsol_wp;
 	struct work_struct unsol_work;
+	struct workqueue_struct *workq; /* common workqueue for codecs */
 
 	/* bit flags of powered codecs */
 	unsigned long codec_powered;
@@ -153,6 +160,17 @@ struct hdac_bus {
 
 	/* locks */
 	struct mutex cmd_mutex;
+
+	void *private_data;
+
+	/* msic op flags */
+	unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */
+
+	/*status for controller */
+	unsigned int rirb_error:1;      /* error in codec communication */
+	unsigned int response_reset:1;  /* controller was reset */
+	unsigned int no_response_fallback:1; /* don't fallback at RIRB error */
+	unsigned int in_reset:1;        /* during reset operation */
 };
 
 int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
@@ -178,4 +196,201 @@ static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
 	clear_bit(codec->addr, &codec->bus->codec_powered);
 }
 
+/*
+ * HD-audio contoller base device
+ */
+struct hda_device {
+	struct snd_dma_buffer bdl;	/* BDL buffer */
+	u32 *posbuf;			/* position buffer pointer */
+
+	unsigned int bufsize;		/* size of the play buffer in bytes */
+	unsigned int period_bytes;	 /* size of the period in bytes */
+	unsigned int frags;		/* number for period in the play buffer */
+	unsigned int fifo_size;		/* FIFO size */
+	unsigned long start_wallclk;	/* start + minimum wallclk */
+	unsigned long period_wallclk;	/* wallclk for period */
+
+	void __iomem *sd_addr;		/* stream descriptor pointer */
+
+	u32 sd_int_sta_mask;		/* stream int status mask */
+
+	/* pcm support */
+	struct snd_pcm_substream *substream;	/* assigned substream,
+						 * set in PCM open
+						 */
+	unsigned int format_val;	/* format value to be set in the
+					 * controller and the codec
+					 */
+	unsigned char stream_tag;	/* assigned stream */
+	unsigned char index;		/* stream index */
+	int assigned_key;		/* last device# key assigned to */
+
+	unsigned int opened:1;
+	unsigned int running:1;
+	unsigned int irq_pending:1;
+	unsigned int prepared:1;
+	unsigned int locked:1;
+	unsigned int wc_marked:1;
+	unsigned int no_period_wakeup:1;
+
+	struct timecounter  tc;
+	struct cyclecounter cc;
+
+	int delay_negative_threshold;
+
+	/* Allows dsp load to have sole access to the playback stream. */
+	struct mutex dsp_mutex;
+};
+
+/* CORB/RIRB */
+struct hda_rb {
+	u32 *buf;			/* CORB/RIRB buffer
+					 * Each CORB entry is 4byte, RIRB is 8byte
+					 */
+	dma_addr_t addr;		/* physical address of CORB/RIRB buffer */
+
+	/* for RIRB */
+	unsigned short rp, wp;		/* read/write pointers */
+	int cmds[HDA_MAX_CODECS];	/* number of pending requests */
+	u32 res[HDA_MAX_CODECS];	/* last read value */
+};
+
+/* Functions to read/write to hda registers. */
+/* FIXME: should we name this something else ??? */
+struct hda_ops {
+	void (*reg_writel)(u32 value, u32 __iomem *addr);
+	u32 (*reg_readl)(u32 __iomem *addr);
+	void (*reg_writew)(u16 value, u16 __iomem *addr);
+	u16 (*reg_readw)(u16 __iomem *addr);
+	void (*reg_writeb)(u8 value, u8 __iomem *addr);
+	u8 (*reg_readb)(u8 __iomem *addr);
+	/* Disable msi if supported, PCI only */
+	int (*disable_msi_reset_irq)(struct hda *);
+	/* Allocation ops */
+	int (*dma_alloc_pages)(struct hda *chip,
+			       int type,
+			       size_t size,
+			       struct snd_dma_buffer *buf);
+	void (*dma_free_pages)(struct hda *chip, struct snd_dma_buffer *buf);
+	int (*substream_alloc_pages)(struct hda *chip,
+				     struct snd_pcm_substream *substream,
+				     size_t size);
+	int (*substream_free_pages)(struct hda *chip,
+				    struct snd_pcm_substream *substream);
+	void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
+				 struct vm_area_struct *area);
+	/* Check if current position is acceptable */
+	int (*position_check)(struct hda *chip, struct hda_device *hda_dev);
+};
+
+typedef unsigned int (*hda_get_pos_callback_t)(struct hda *, struct hda_device *);
+typedef int (*hda_get_delay_callback_t)(struct hda *, struct hda_device *,
+			 unsigned int pos);
+
+struct hda {
+	struct pci_dev *pci; /* FIXME: should we remove PCI assumption, right now its true for us always */
+	struct device *dev;
+	int dev_index;
+
+	/* chip type specific */
+	int driver_type;
+	unsigned int driver_caps;
+	int playback_streams;
+	int playback_index_offset;
+	int capture_streams;
+	int capture_index_offset;
+	int num_streams;
+
+	/* Register interaction. */
+	const struct hda_ops *ops;
+
+	/* position adjustment callbacks */
+	hda_get_pos_callback_t get_position[2];
+	hda_get_delay_callback_t get_delay[2];
+
+	/* pci resources */
+	unsigned long addr;
+	void __iomem *remap_addr;
+	int irq;
+
+	/* locks */
+	spinlock_t reg_lock;
+	struct mutex open_mutex; /* Prevents concurrent open/close operations */
+	struct completion probe_wait;
+
+	/* streams (x num_streams) */
+	struct hda_device *hda_dev;
+
+	/* HD codec */
+	unsigned short codec_mask;
+	int  codec_probe_mask; /* copied from probe_mask option */
+	struct hdac_bus *bus;
+	unsigned int beep_mode;
+
+	/* CORB/RIRB */
+	struct hda_rb corb;
+	struct hda_rb rirb;
+
+	/* CORB/RIRB and position buffers */
+	struct snd_dma_buffer rb;
+	struct snd_dma_buffer posbuf;
+
+	/* flags */
+	const int *bdl_pos_adj;
+	int poll_count;
+	unsigned int running:1;
+	unsigned int initialized:1;
+	unsigned int single_cmd:1;
+	unsigned int polling_mode:1;
+	unsigned int msi:1;
+	unsigned int probing:1; /* codec probing phase */
+	unsigned int snoop:1;
+	unsigned int align_buffer_size:1;
+	unsigned int region_requested:1;
+	unsigned int disabled:1; /* disabled by VGA-switcher */
+
+	/* for debugging */
+	unsigned int last_cmd[HDA_MAX_CODECS];
+
+	/* reboot notifier (for mysterious hangup problem at power-down) */
+	struct notifier_block reboot_notifier;
+
+	struct hda_device saved_hda_dev; /* FIXME: check if we need this */
+};
+
+/* Allocation functions. */
+int hda_alloc_stream_pages(struct hda *chip);
+void hda_free_stream_pages(struct hda *chip);
+
+/* pcm helper functions */
+int hda_setup_periods(struct hda *chip,
+			struct snd_pcm_substream *substream,
+			struct hda_device *dev);
+void hda_reset_device(struct hda *chip, struct hda_device *hda_dev);
+int hda_set_device_params(struct hda *chip, struct snd_pcm_substream *substream,
+				unsigned int format_val);
+void hda_set_pcm_constrains(struct hda *chip, struct snd_pcm_runtime *runtime);
+
+/* PCM setup */
+static inline struct hda_device *get_hda_dev(struct snd_pcm_substream *substream)
+{
+	return substream->runtime->private_data;
+}
+unsigned int hda_get_position(struct hda *chip, struct hda_device *hda_dev,
+		int codec_delay);
+unsigned int hda_get_pos_lpib(struct hda *chip, struct hda_device *hda_dev);
+unsigned int hda_get_pos_posbuf(struct hda *chip, struct hda_device *hda_dev);
+
+/* Stream control. */
+void hda_stream_stop(struct hda *chip, struct hda_device *hda_dev);
+
+/* Allocation functions. */
+int hda_alloc_stream_pages(struct hda *chip);
+void hda_free_stream_pages(struct hda *chip);
+
+/* Low level azx interface */
+void hda_init_chip(struct hda *chip, bool full_reset);
+void hda_stop_chip(struct hda *chip);
+void hda_enter_link_reset(struct hda *chip);
+
 #endif /* __SOUND_HDAUDIO_H */
diff --git a/sound/hda/Makefile b/sound/hda/Makefile
index eec5da03b41f..836c5f34b4dd 100644
--- a/sound/hda/Makefile
+++ b/sound/hda/Makefile
@@ -1,4 +1,4 @@
-snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o
+snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o hdac_controller.o
 
 snd-hda-core-objs += trace.o
 CFLAGS_trace.o := -I$(src)
diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c
new file mode 100644
index 000000000000..3b14f7be43da
--- /dev/null
+++ b/sound/hda/hdac_controller.c
@@ -0,0 +1,1284 @@
+/*
+ *
+ *  Implementation of Common HDA driver funcitons for Intel HD Audio.
+ *
+ *  Copyright (c) 2014 Intel Corporation
+ *  Copyright(c) 2004 Intel Corporation. All rights reserved.
+ *
+ *  Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *                     PeiSen Hou <pshou@realtek.com.tw>
+ *
+ *  Modified by: KP Jeeja <jeeja.kp@intel.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ *
+ *
+ */
+
+#include <linux/clocksource.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/reboot.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_registers.h>
+
+/* DSP lock helpers */
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+#define dsp_lock_init(dev)	mutex_init(&(dev)->dsp_mutex)
+#define dsp_lock(dev)		mutex_lock(&(dev)->dsp_mutex)
+#define dsp_unlock(dev)		mutex_unlock(&(dev)->dsp_mutex)
+#define dsp_is_locked(dev)	((dev)->locked)
+#else
+#define dsp_lock_init(dev)	do {} while (0)
+#define dsp_lock(dev)		do {} while (0)
+#define dsp_unlock(dev)		do {} while (0)
+#define dsp_is_locked(dev)	0
+#endif
+
+/*
+ * AZX stream operations.
+ */
+
+/* start a stream */
+void hda_stream_start(struct hda *chip, struct hda_device *azx_dev)
+{
+	/* enable SIE */
+	azx_writel(chip, INTCTL,
+		   azx_readl(chip, INTCTL) | (1 << azx_dev->index));
+	/* set DMA start and interrupt mask */
+	azx_sd_writeb(chip, azx_dev, SD_CTL,
+		      azx_sd_readb(chip, azx_dev, SD_CTL) |
+		      SD_CTL_DMA_START | SD_INT_MASK);
+}
+EXPORT_SYMBOL_GPL(hda_stream_start);
+/* stop DMA */
+static void hda_stream_clear(struct hda *chip, struct hda_device *azx_dev)
+{
+	azx_sd_writeb(chip, azx_dev, SD_CTL,
+		      azx_sd_readb(chip, azx_dev, SD_CTL) &
+		      ~(SD_CTL_DMA_START | SD_INT_MASK));
+	azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
+}
+
+/* stop a stream */
+void hda_stream_stop(struct hda *chip, struct hda_device *azx_dev)
+{
+	hda_stream_clear(chip, azx_dev);
+	/* disable SIE */
+	azx_writel(chip, INTCTL,
+		   azx_readl(chip, INTCTL) & ~(1 << azx_dev->index));
+}
+EXPORT_SYMBOL_GPL(hda_stream_stop);
+
+/* reset stream */
+void hda_stream_reset(struct hda *chip, struct hda_device *azx_dev)
+{
+	unsigned char val;
+	int timeout;
+
+	hda_stream_clear(chip, azx_dev);
+
+	azx_sd_writeb(chip, azx_dev, SD_CTL,
+		      azx_sd_readb(chip, azx_dev, SD_CTL) |
+		      SD_CTL_STREAM_RESET);
+	udelay(3);
+	timeout = 300;
+	while (!((val = azx_sd_readb(chip, azx_dev, SD_CTL)) &
+		 SD_CTL_STREAM_RESET) && --timeout)
+		;
+	val &= ~SD_CTL_STREAM_RESET;
+	azx_sd_writeb(chip, azx_dev, SD_CTL, val);
+	udelay(3);
+
+	timeout = 300;
+	/* waiting for hardware to report that the stream is out of reset */
+	while (((val = azx_sd_readb(chip, azx_dev, SD_CTL)) &
+		SD_CTL_STREAM_RESET) && --timeout)
+		;
+
+	/* reset first position - may not be synced with hw at this time */
+	*azx_dev->posbuf = 0;
+}
+EXPORT_SYMBOL_GPL(hda_stream_reset);
+
+/*
+ * set up the SD for streaming
+ */
+int hda_setup_controller(struct hda *chip, struct hda_device *azx_dev)
+{
+	unsigned int val;
+	/* make sure the run bit is zero for SD */
+	hda_stream_clear(chip, azx_dev);
+	/* program the stream_tag */
+	val = azx_sd_readl(chip, azx_dev, SD_CTL);
+	val = (val & ~SD_CTL_STREAM_TAG_MASK) |
+		(azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT);
+	azx_sd_writel(chip, azx_dev, SD_CTL, val);
+
+	/* program the length of samples in cyclic buffer */
+	azx_sd_writel(chip, azx_dev, SD_CBL, azx_dev->bufsize);
+
+	/* program the stream format */
+	/* this value needs to be the same as the one programmed */
+	azx_sd_writew(chip, azx_dev, SD_FORMAT, azx_dev->format_val);
+
+	/* program the stream LVI (last valid index) of the BDL */
+	azx_sd_writew(chip, azx_dev, SD_LVI, azx_dev->frags - 1);
+
+	/* program the BDL address */
+	/* lower BDL address */
+	azx_sd_writel(chip, azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
+	/* upper BDL address */
+	azx_sd_writel(chip, azx_dev, SD_BDLPU,
+		      upper_32_bits(azx_dev->bdl.addr));
+
+	/* enable the position buffer */
+	if (chip->get_position[0] != hda_get_pos_lpib ||
+	    chip->get_position[1] != hda_get_pos_lpib) {
+		if (!(azx_readl(chip, DPLBASE) & AZX_DPLBASE_ENABLE))
+			azx_writel(chip, DPLBASE,
+				(u32)chip->posbuf.addr | AZX_DPLBASE_ENABLE);
+	}
+
+	/* set the interrupt enable bits in the descriptor control register */
+	azx_sd_writel(chip, azx_dev, SD_CTL,
+		      azx_sd_readl(chip, azx_dev, SD_CTL) | SD_INT_MASK);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hda_setup_controller);
+
+/* assign a stream for the PCM */
+struct hda_device *
+hda_assign_device(struct hda *chip, struct snd_pcm_substream *substream)
+{
+	int dev, i, nums;
+	struct hda_device *res = NULL;
+	/* make a non-zero unique key for the substream */
+	int key = (substream->pcm->device << 16) | (substream->number << 2) |
+		(substream->stream + 1);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		dev = chip->playback_index_offset;
+		nums = chip->playback_streams;
+	} else {
+		dev = chip->capture_index_offset;
+		nums = chip->capture_streams;
+	}
+	for (i = 0; i < nums; i++, dev++) {
+		struct hda_device *azx_dev = &chip->hda_dev[dev];
+
+		dsp_lock(azx_dev);
+		if (!azx_dev->opened && !dsp_is_locked(azx_dev)) {
+			if (azx_dev->assigned_key == key) {
+				azx_dev->opened = 1;
+				azx_dev->assigned_key = key;
+				dsp_unlock(azx_dev);
+				return azx_dev;
+			}
+			if (!res ||
+			    (chip->driver_caps & AZX_DCAPS_REVERSE_ASSIGN))
+				res = azx_dev;
+		}
+		dsp_unlock(azx_dev);
+	}
+	if (res) {
+		dsp_lock(res);
+		res->opened = 1;
+		res->assigned_key = key;
+		dsp_unlock(res);
+	}
+	return res;
+}
+EXPORT_SYMBOL_GPL(hda_assign_device);
+
+/* release the assigned stream */
+void hda_release_device(struct hda_device *hda_dev)
+{
+	hda_dev->opened = 0;
+}
+EXPORT_SYMBOL_GPL(hda_release_device);
+
+/*
+ * set up a BDL entry
+ */
+int hda_setup_bdle(struct hda *chip,
+		      struct snd_dma_buffer *dmab,
+		      struct hda_device *azx_dev, u32 **bdlp,
+		      int ofs, int size, int with_ioc)
+{
+	u32 *bdl = *bdlp;
+
+	while (size > 0) {
+		dma_addr_t addr;
+		int chunk;
+
+		if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
+			return -EINVAL;
+
+		addr = snd_sgbuf_get_addr(dmab, ofs);
+		dev_dbg(chip->dev, "buffer address=%#llx\n", (u64)addr);
+		/* program the address field of the BDL entry */
+		bdl[0] = cpu_to_le32((u32)addr);
+		bdl[1] = cpu_to_le32(upper_32_bits(addr));
+		/* program the size field of the BDL entry */
+		chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size);
+		/* one BDLE cannot cross 4K boundary on CTHDA chips */
+		if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
+			u32 remain = 0x1000 - (ofs & 0xfff);
+
+			if (chunk > remain)
+				chunk = remain;
+		}
+		bdl[2] = cpu_to_le32(chunk);
+		/* program the IOC to enable interrupt
+		 * only when the whole fragment is processed
+		 */
+		size -= chunk;
+		bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
+		bdl += 4;
+		azx_dev->frags++;
+		ofs += chunk;
+	}
+	*bdlp = bdl;
+	dev_dbg(chip->dev, "bdl: 0x%p, ofs:0x%x\n", bdl, ofs);
+	return ofs;
+}
+EXPORT_SYMBOL_GPL(hda_setup_bdle);
+
+/*
+ * set up BDL entries
+ */
+int hda_setup_periods(struct hda *chip,
+			     struct snd_pcm_substream *substream,
+			     struct hda_device *azx_dev)
+{
+	u32 *bdl;
+	int i, ofs, periods, period_bytes;
+	int pos_adj = 0;
+
+	/* reset BDL address */
+	azx_sd_writel(chip, azx_dev, SD_BDLPL, 0);
+	azx_sd_writel(chip, azx_dev, SD_BDLPU, 0);
+
+	period_bytes = azx_dev->period_bytes;
+	periods = azx_dev->bufsize / period_bytes;
+
+	/* program the initial BDL entries */
+	bdl = (u32 *)azx_dev->bdl.area;
+	ofs = 0;
+	azx_dev->frags = 0;
+
+	if (chip->bdl_pos_adj)
+		pos_adj = chip->bdl_pos_adj[chip->dev_index];
+	if (!azx_dev->no_period_wakeup && pos_adj > 0) {
+		struct snd_pcm_runtime *runtime = substream->runtime;
+		int pos_align = pos_adj;
+
+		pos_adj = (pos_adj * runtime->rate + 47999) / 48000;
+		if (!pos_adj)
+			pos_adj = pos_align;
+		else
+			pos_adj = ((pos_adj + pos_align - 1) / pos_align) *
+				pos_align;
+		pos_adj = frames_to_bytes(runtime, pos_adj);
+		if (pos_adj >= period_bytes) {
+			dev_warn(chip->dev, "Too big adjustment %d\n",
+				 pos_adj);
+			pos_adj = 0;
+		} else {
+			ofs = hda_setup_bdle(chip, snd_pcm_get_dma_buf(substream),
+					 azx_dev,
+					 &bdl, ofs, pos_adj, true);
+			if (ofs < 0)
+				goto error;
+		}
+	} else
+		pos_adj = 0;
+
+	for (i = 0; i < periods; i++) {
+		if (i == periods - 1 && pos_adj)
+			ofs = hda_setup_bdle(chip, snd_pcm_get_dma_buf(substream),
+					 azx_dev, &bdl, ofs,
+					 period_bytes - pos_adj, 0);
+		else
+			ofs = hda_setup_bdle(chip, snd_pcm_get_dma_buf(substream),
+					 azx_dev, &bdl, ofs,
+					 period_bytes,
+					 !azx_dev->no_period_wakeup);
+		if (ofs < 0)
+			goto error;
+	}
+	return 0;
+
+ error:
+	dev_err(chip->dev, "Too many BDL entries: buffer=%d, period=%d\n",
+		azx_dev->bufsize, period_bytes);
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(hda_setup_periods);
+
+unsigned int hda_get_pos_lpib(struct hda *chip, struct hda_device *azx_dev)
+{
+	return azx_sd_readl(chip, azx_dev, SD_LPIB);
+}
+EXPORT_SYMBOL_GPL(hda_get_pos_lpib);
+
+unsigned int hda_get_pos_posbuf(struct hda *chip, struct hda_device *azx_dev)
+{
+	return le32_to_cpu(*azx_dev->posbuf);
+}
+EXPORT_SYMBOL_GPL(hda_get_pos_posbuf);
+
+unsigned int hda_get_position(struct hda *chip,
+			      struct hda_device *azx_dev, int codec_delay)
+{
+	struct snd_pcm_substream *substream = azx_dev->substream;
+	unsigned int pos;
+	int stream = substream->stream;
+	int delay = 0;
+
+	if (chip->get_position[stream])
+		pos = chip->get_position[stream](chip, azx_dev);
+	else /* use the position buffer as default */
+		pos = hda_get_pos_posbuf(chip, azx_dev);
+
+	if (pos >= azx_dev->bufsize)
+		pos = 0;
+
+	if (substream->runtime) {
+		if (chip->get_delay[stream])
+			delay += chip->get_delay[stream](chip, azx_dev, pos);
+			delay += codec_delay;
+		substream->runtime->delay = delay;
+	}
+
+	return pos;
+}
+EXPORT_SYMBOL_GPL(hda_get_position);
+
+void hda_reset_device(struct hda *chip, struct hda_device *azx_dev)
+{
+	azx_sd_writel(chip, azx_dev, SD_BDLPL, 0);
+	azx_sd_writel(chip, azx_dev, SD_BDLPU, 0);
+	azx_sd_writel(chip, azx_dev, SD_CTL, 0);
+	azx_dev->bufsize = 0;
+	azx_dev->period_bytes = 0;
+	azx_dev->format_val = 0;
+}
+EXPORT_SYMBOL_GPL(hda_reset_device);
+
+int hda_set_device_params(struct hda *chip, struct snd_pcm_substream *substream,
+				unsigned int format_val)
+{
+
+	unsigned int bufsize, period_bytes, stream_tag;
+	struct hda_device *azx_dev = get_hda_dev(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int err;
+
+	bufsize = snd_pcm_lib_buffer_bytes(substream);
+	period_bytes = snd_pcm_lib_period_bytes(substream);
+
+	dev_dbg(chip->dev, "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
+		bufsize, format_val);
+
+	if (bufsize != azx_dev->bufsize ||
+	    period_bytes != azx_dev->period_bytes ||
+	    format_val != azx_dev->format_val ||
+	    runtime->no_period_wakeup != azx_dev->no_period_wakeup) {
+		azx_dev->bufsize = bufsize;
+		azx_dev->period_bytes = period_bytes;
+		azx_dev->format_val = format_val;
+		azx_dev->no_period_wakeup = runtime->no_period_wakeup;
+		err = hda_setup_periods(chip, substream, azx_dev);
+		if (err < 0)
+			return err;
+	}
+
+	/* when LPIB delay correction gives a small negative value,
+	 * we ignore it; currently set the threshold statically to
+	 * 64 frames
+	 */
+	if (runtime->period_size > 64)
+		azx_dev->delay_negative_threshold = -frames_to_bytes(runtime, 64);
+	else
+		azx_dev->delay_negative_threshold = 0;
+
+	/* wallclk has 24Mhz clock source */
+	azx_dev->period_wallclk = (((runtime->period_size * 24000) /
+						runtime->rate) * 1000);
+	hda_setup_controller(chip, azx_dev);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		azx_dev->fifo_size =
+			azx_sd_readw(chip, azx_dev, SD_FIFOSIZE) + 1;
+	else
+		azx_dev->fifo_size = 0;
+
+	stream_tag = azx_dev->stream_tag;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hda_set_device_params);
+
+void hda_set_pcm_constrains(struct hda *chip, struct snd_pcm_runtime *runtime)
+{
+	int buff_step;
+
+	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+
+	/* avoid wrap-around with wall-clock */
+	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME,
+				     20,
+				     178000000);
+
+	if (chip->align_buffer_size)
+		/* constrain buffer sizes to be multiple of 128
+		   bytes. This is more efficient in terms of memory
+		   access but isn't required by the HDA spec and
+		   prevents users from specifying exact period/buffer
+		   sizes. For example for 44.1kHz, a period size set
+		   to 20ms will be rounded to 19.59ms. */
+		buff_step = 128;
+	else
+		/* Don't enforce steps on buffer sizes, still need to
+		   be multiple of 4 bytes (HDA spec). Tested on Intel
+		   HDA controllers, may not work on all devices where
+		   option needs to be disabled */
+		buff_step = 4;
+
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+				   buff_step);
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+				   buff_step);
+
+}
+EXPORT_SYMBOL_GPL(hda_set_pcm_constrains);
+
+/*
+ * CORB / RIRB interface
+ */
+static int hda_alloc_cmd_io(struct hda *chip)
+{
+	int err;
+
+	/* single page (at least 4096 bytes) must suffice for both ringbuffes */
+	err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
+					 PAGE_SIZE, &chip->rb);
+	if (err < 0)
+		dev_err(chip->dev, "cannot allocate CORB/RIRB\n");
+	return err;
+}
+EXPORT_SYMBOL_GPL(hda_alloc_cmd_io);
+
+static void hda_init_cmd_io(struct hda *chip)
+{
+	int timeout;
+
+	spin_lock_irq(&chip->reg_lock);
+	/* CORB set up */
+	chip->corb.addr = chip->rb.addr;
+	chip->corb.buf = (u32 *)chip->rb.area;
+	azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
+	azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr));
+
+	/* set the corb size to 256 entries (ULI requires explicitly) */
+	azx_writeb(chip, CORBSIZE, 0x02);
+	/* set the corb write pointer to 0 */
+	azx_writew(chip, CORBWP, 0);
+
+	/* reset the corb hw read pointer */
+	azx_writew(chip, CORBRP, AZX_CORBRP_RST);
+	if (!(chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)) {
+		for (timeout = 1000; timeout > 0; timeout--) {
+			if ((azx_readw(chip, CORBRP) & AZX_CORBRP_RST) == AZX_CORBRP_RST)
+				break;
+			udelay(1);
+		}
+		if (timeout <= 0)
+			dev_err(chip->dev, "CORB reset timeout#1, CORBRP = %d\n",
+				azx_readw(chip, CORBRP));
+
+		azx_writew(chip, CORBRP, 0);
+		for (timeout = 1000; timeout > 0; timeout--) {
+			if (azx_readw(chip, CORBRP) == 0)
+				break;
+			udelay(1);
+		}
+		if (timeout <= 0)
+			dev_err(chip->dev, "CORB reset timeout#2, CORBRP = %d\n",
+				azx_readw(chip, CORBRP));
+	}
+
+	/* enable corb dma */
+	azx_writeb(chip, CORBCTL, AZX_CORBCTL_RUN);
+
+	/* RIRB set up */
+	chip->rirb.addr = chip->rb.addr + 2048;
+	chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
+	chip->rirb.wp = chip->rirb.rp = 0;
+	memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds));
+	azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
+	azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr));
+
+	/* set the rirb size to 256 entries (ULI requires explicitly) */
+	azx_writeb(chip, RIRBSIZE, 0x02);
+	/* reset the rirb hw write pointer */
+	azx_writew(chip, RIRBWP, AZX_RIRBWP_RST);
+	/* set N=1, get RIRB response interrupt for new entry */
+	if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
+		azx_writew(chip, RINTCNT, 0xc0);
+	else
+		azx_writew(chip, RINTCNT, 1);
+	/* enable rirb dma and response irq */
+	azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN);
+	spin_unlock_irq(&chip->reg_lock);
+}
+EXPORT_SYMBOL_GPL(hda_init_cmd_io);
+
+static void hda_free_cmd_io(struct hda *chip)
+{
+	spin_lock_irq(&chip->reg_lock);
+	/* disable ringbuffer DMAs */
+	azx_writeb(chip, RIRBCTL, 0);
+	azx_writeb(chip, CORBCTL, 0);
+	spin_unlock_irq(&chip->reg_lock);
+}
+EXPORT_SYMBOL_GPL(hda_free_cmd_io);
+
+static unsigned int hda_command_addr(u32 cmd)
+{
+	unsigned int addr = cmd >> 28;
+
+	if (addr >= HDA_MAX_CODECS) {
+		snd_BUG();
+		addr = 0;
+	}
+
+	return addr;
+}
+
+/* send a command */
+static int hda_corb_send_cmd(struct hdac_bus *bus, u32 val)
+{
+	struct hda *chip = bus->private_data;
+	unsigned int addr = hda_command_addr(val);
+	unsigned int wp, rp;
+
+	spin_lock_irq(&chip->reg_lock);
+
+	/* add command to corb */
+	wp = azx_readw(chip, CORBWP);
+	if (wp == 0xffff) {
+		/* something wrong, controller likely turned to D3 */
+		spin_unlock_irq(&chip->reg_lock);
+		return -EIO;
+	}
+	wp++;
+	wp %= AZX_MAX_CORB_ENTRIES;
+
+	rp = azx_readw(chip, CORBRP);
+	if (wp == rp) {
+		/* oops, it's full */
+		spin_unlock_irq(&chip->reg_lock);
+		return -EAGAIN;
+	}
+
+	chip->rirb.cmds[addr]++;
+	chip->corb.buf[wp] = cpu_to_le32(val);
+	azx_writew(chip, CORBWP, wp);
+
+	spin_unlock_irq(&chip->reg_lock);
+
+	return 0;
+}
+
+#define AZX_RIRB_EX_UNSOL_EV	(1<<4)
+
+/**
+ * hda_queue_unsol_event - add an unsolicited event to queue
+ * @bus: the BUS
+ * @res: unsolicited event (lower 32bit of RIRB entry)
+ * @res_ex: codec addr and flags (upper 32bit or RIRB entry)
+ *
+ * Adds the given event to the queue.  The events are processed in
+ * the workqueue asynchronously.  Call this function in the interrupt
+ * hanlder when RIRB receives an unsolicited event.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int hda_queue_unsol_event(struct hdac_bus *bus, u32 res, u32 res_ex)
+{
+	unsigned int wp;
+
+	if (!bus)
+		return 0;
+
+	wp = (bus->unsol_wp + 1) % HDA_UNSOL_QUEUE_SIZE;
+
+	wp <<= 1;
+	bus->unsol_queue[wp] = res;
+	bus->unsol_queue[wp + 1] = res_ex;
+
+	queue_work(bus->workq, &bus->unsol_work);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hda_queue_unsol_event);
+
+/* retrieve RIRB entry - called from interrupt handler */
+static void hda_update_rirb(struct hda *chip)
+{
+	unsigned int rp, wp;
+	unsigned int addr;
+	u32 res, res_ex;
+
+	wp = azx_readw(chip, RIRBWP);
+	if (wp == 0xffff) {
+		/* something wrong, controller likely turned to D3 */
+		return;
+	}
+
+	if (wp == chip->rirb.wp)
+		return;
+	chip->rirb.wp = wp;
+
+	while (chip->rirb.rp != wp) {
+		chip->rirb.rp++;
+		chip->rirb.rp %= AZX_MAX_RIRB_ENTRIES;
+
+		rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */
+		res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
+		res = le32_to_cpu(chip->rirb.buf[rp]);
+		addr = res_ex & 0xf;
+		if ((addr >= HDA_MAX_CODECS) || !(chip->codec_mask & (1 << addr))) {
+			dev_err(chip->dev, "spurious response %#x:%#x, rp = %d, wp = %d",
+				res, res_ex,
+				chip->rirb.rp, wp);
+			snd_BUG();
+		} else if (res_ex & AZX_RIRB_EX_UNSOL_EV)
+			hda_queue_unsol_event(chip->bus, res, res_ex);
+		else if (chip->rirb.cmds[addr]) {
+			chip->rirb.res[addr] = res;
+			smp_wmb();
+			chip->rirb.cmds[addr]--;
+		} else if (printk_ratelimit()) {
+			dev_err(chip->dev, "spurious response %#x:%#x, last cmd=%#08x\n",
+				res, res_ex,
+				chip->last_cmd[addr]);
+		}
+	}
+}
+
+/* receive a response */
+static unsigned int hda_rirb_get_response(struct hdac_bus *bus,
+					  unsigned int addr)
+{
+	struct hda *chip = bus->private_data;
+	unsigned long timeout;
+	unsigned long loopcounter;
+	int do_poll = 0;
+
+ again:
+	timeout = jiffies + msecs_to_jiffies(1000);
+
+	for (loopcounter = 0;; loopcounter++) {
+		if (chip->polling_mode || do_poll) {
+			spin_lock_irq(&chip->reg_lock);
+			hda_update_rirb(chip);
+			spin_unlock_irq(&chip->reg_lock);
+		}
+		if (!chip->rirb.cmds[addr]) {
+			smp_rmb();
+			bus->rirb_error = 0;
+
+			if (!do_poll)
+				chip->poll_count = 0;
+			return chip->rirb.res[addr]; /* the last value */
+		}
+		if (time_after(jiffies, timeout))
+			break;
+		else {
+			udelay(10);
+			cond_resched();
+		}
+	}
+
+	if (!bus->no_response_fallback)
+		return -1;
+
+	if (!chip->polling_mode && chip->poll_count < 2) {
+		dev_dbg(chip->dev,
+			"azx_get_response timeout, polling the codec once: last cmd=0x%08x\n",
+			chip->last_cmd[addr]);
+		do_poll = 1;
+		chip->poll_count++;
+		goto again;
+	}
+
+
+	if (!chip->polling_mode) {
+		dev_warn(chip->dev,
+			 "azx_get_response timeout, switching to polling mode: last cmd=0x%08x\n",
+			 chip->last_cmd[addr]);
+		chip->polling_mode = 1;
+		goto again;
+	}
+
+	if (chip->msi) {
+		dev_warn(chip->dev,
+			 "No response from codec, disabling MSI: last cmd=0x%08x\n",
+			 chip->last_cmd[addr]);
+		if (chip->ops->disable_msi_reset_irq(chip) &&
+		    chip->ops->disable_msi_reset_irq(chip) < 0) {
+			bus->rirb_error = 1;
+			return -1;
+		}
+		goto again;
+	}
+
+	if (chip->probing) {
+		/* If this critical timeout happens during the codec probing
+		 * phase, this is likely an access to a non-existing codec
+		 * slot.  Better to return an error and reset the system.
+		 */
+		return -1;
+	}
+
+	/* a fatal communication error; need either to reset or to fallback
+	 * to the single_cmd mode
+	 */
+	bus->rirb_error = 1;
+	if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) {
+		bus->response_reset = 1;
+		return -1; /* give a chance to retry */
+	}
+
+	dev_err(chip->dev,
+		"azx_get_response timeout, switching to single_cmd mode: last cmd=0x%08x\n",
+		chip->last_cmd[addr]);
+	chip->single_cmd = 1;
+	bus->response_reset = 0;
+	/* release CORB/RIRB */
+	hda_free_cmd_io(chip);
+	/* disable unsolicited responses */
+	azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_UNSOL);
+	return -1;
+}
+
+/*
+ * Use the single immediate command instead of CORB/RIRB for simplicity
+ *
+ * Note: according to Intel, this is not preferred use.  The command was
+ *       intended for the BIOS only, and may get confused with unsolicited
+ *       responses.  So, we shouldn't use it for normal operation from the
+ *       driver.
+ *       I left the codes, however, for debugging/testing purposes.
+ */
+
+/* receive a response */
+static int hda_single_wait_for_response(struct hda *chip, unsigned int addr)
+{
+	int timeout = 50;
+
+	while (timeout--) {
+		/* check IRV busy bit */
+		if (azx_readw(chip, IRS) & AZX_IRS_VALID) {
+			/* reuse rirb.res as the response return value */
+			chip->rirb.res[addr] = azx_readl(chip, IR);
+			return 0;
+		}
+		udelay(1);
+	}
+	if (printk_ratelimit())
+		dev_dbg(chip->dev, "get_response timeout: IRS=0x%x\n",
+			azx_readw(chip, IRS));
+	chip->rirb.res[addr] = -1;
+	return -EIO;
+}
+
+/* send a command */
+static int hda_single_send_cmd(struct hdac_bus *bus, u32 val)
+{
+	struct hda *chip = bus->private_data;
+	unsigned int addr = hda_command_addr(val);
+	int timeout = 50;
+
+	bus->rirb_error = 0;
+	while (timeout--) {
+		/* check ICB busy bit */
+		if (!((azx_readw(chip, IRS) & AZX_IRS_BUSY))) {
+			/* Clear IRV valid bit */
+			azx_writew(chip, IRS, azx_readw(chip, IRS) |
+				   AZX_IRS_VALID);
+			azx_writel(chip, IC, val);
+			azx_writew(chip, IRS, azx_readw(chip, IRS) |
+				   AZX_IRS_BUSY);
+			return hda_single_wait_for_response(chip, addr);
+		}
+		udelay(1);
+	}
+	if (printk_ratelimit())
+		dev_dbg(chip->dev,
+			"send_cmd timeout: IRS=0x%x, val=0x%x\n",
+			azx_readw(chip, IRS), val);
+	return -EIO;
+}
+
+/* receive a response */
+static unsigned int hda_single_get_response(struct hdac_bus *bus,
+					    unsigned int addr)
+{
+	struct hda *chip = bus->private_data;
+
+	return chip->rirb.res[addr];
+}
+
+/*
+ * The below are the main callbacks from hda_codec.
+ *
+ * They are just the skeleton to call sub-callbacks according to the
+ * current setting of chip->single_cmd.
+ */
+
+/* send a command */
+int hda_send_cmd(struct hdac_bus *bus, unsigned int val)
+{
+	struct hda *chip = bus->private_data;
+
+	if (chip->disabled)
+		return 0;
+	chip->last_cmd[hda_command_addr(val)] = val;
+	if (chip->single_cmd)
+		return hda_single_send_cmd(bus, val);
+	else
+		return hda_corb_send_cmd(bus, val);
+}
+EXPORT_SYMBOL_GPL(hda_send_cmd);
+
+/* get a response */
+unsigned int hda_get_response(struct hdac_bus *bus,
+				     unsigned int addr)
+{
+	struct hda *chip = bus->private_data;
+
+	if (chip->disabled)
+		return 0;
+	if (chip->single_cmd)
+		return hda_single_get_response(bus, addr);
+	else
+		return hda_rirb_get_response(bus, addr);
+}
+EXPORT_SYMBOL_GPL(hda_get_response);
+
+void hda_bus_reset(struct hdac_bus *bus)
+{
+	struct hda *chip = bus->private_data;
+
+	bus->in_reset = 1;
+	hda_stop_chip(chip);
+	hda_init_chip(chip, true);
+	bus->in_reset = 0;
+}
+EXPORT_SYMBOL_GPL(hda_bus_reset);
+
+int hda_alloc_stream_pages(struct hda *chip)
+{
+	int i, err;
+
+	for (i = 0; i < chip->num_streams; i++) {
+		dsp_lock_init(&chip->hda_dev[i]);
+		/* allocate memory for the BDL for each stream */
+		err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
+						 BDL_SIZE,
+						 &chip->hda_dev[i].bdl);
+		if (err < 0) {
+			dev_err(chip->dev, "cannot allocate BDL\n");
+			return -ENOMEM;
+		}
+	}
+	/* allocate memory for the position buffer */
+	err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
+					 chip->num_streams * 8, &chip->posbuf);
+	if (err < 0) {
+		dev_err(chip->dev, "cannot allocate posbuf\n");
+		return -ENOMEM;
+	}
+
+	/* allocate CORB/RIRB */
+	err = hda_alloc_cmd_io(chip);
+	if (err < 0)
+		return err;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hda_alloc_stream_pages);
+
+void hda_free_stream_pages(struct hda *chip)
+{
+	int i;
+
+	if (chip->hda_dev) {
+		for (i = 0; i < chip->num_streams; i++)
+			if (chip->hda_dev[i].bdl.area)
+				chip->ops->dma_free_pages(
+					chip, &chip->hda_dev[i].bdl);
+	}
+	if (chip->rb.area)
+		chip->ops->dma_free_pages(chip, &chip->rb);
+	if (chip->posbuf.area)
+		chip->ops->dma_free_pages(chip, &chip->posbuf);
+}
+EXPORT_SYMBOL_GPL(hda_free_stream_pages);
+
+/*
+ * Lowlevel interface
+ */
+
+/* enter link reset */
+void hda_enter_link_reset(struct hda *chip)
+{
+	unsigned long timeout;
+
+	/* reset controller */
+	azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_RESET);
+
+	timeout = jiffies + msecs_to_jiffies(100);
+	while ((azx_readb(chip, GCTL) & AZX_GCTL_RESET) &&
+			time_before(jiffies, timeout))
+		usleep_range(500, 1000);
+}
+EXPORT_SYMBOL_GPL(hda_enter_link_reset);
+
+/* exit link reset */
+void hda_exit_link_reset(struct hda *chip)
+{
+	unsigned long timeout;
+
+	azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | AZX_GCTL_RESET);
+
+	timeout = jiffies + msecs_to_jiffies(100);
+	while (!azx_readb(chip, GCTL) &&
+			time_before(jiffies, timeout))
+		usleep_range(500, 1000);
+}
+EXPORT_SYMBOL_GPL(hda_exit_link_reset);
+
+/* reset codec link */
+static int hda_reset(struct hda *chip, bool full_reset)
+{
+	if (!full_reset)
+		goto __skip;
+
+	/* clear STATESTS */
+	azx_writew(chip, STATESTS, STATESTS_INT_MASK);
+
+	/* reset controller */
+	hda_enter_link_reset(chip);
+
+	/* delay for >= 100us for codec PLL to settle per spec
+	 * Rev 0.9 section 5.5.1
+	 */
+	usleep_range(500, 1000);
+
+	/* Bring controller out of reset */
+	hda_exit_link_reset(chip);
+
+	/* Brent Chartrand said to wait >= 540us for codecs to initialize */
+	usleep_range(1000, 1200);
+
+__skip:
+	/* check to see if controller is ready */
+	if (!azx_readb(chip, GCTL)) {
+		dev_dbg(chip->dev, "azx_reset: controller not ready!\n");
+		return -EBUSY;
+	}
+
+	/* Accept unsolicited responses */
+	if (!chip->single_cmd)
+		azx_writel(chip, GCTL, azx_readl(chip, GCTL) |
+			   AZX_GCTL_UNSOL);
+
+	/* detect codecs */
+	if (!chip->codec_mask) {
+		chip->codec_mask = azx_readw(chip, STATESTS);
+		dev_dbg(chip->dev, "codec_mask = 0x%x\n",
+			chip->codec_mask);
+	}
+
+	return 0;
+}
+
+/* enable interrupts */
+static void hda_int_enable(struct hda *chip)
+{
+	/* enable controller CIE and GIE */
+	azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) |
+		   AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN);
+}
+
+/* disable interrupts */
+static void hda_int_disable(struct hda *chip)
+{
+	int i;
+
+	/* disable interrupts in stream descriptor */
+	for (i = 0; i < chip->num_streams; i++) {
+		struct hda_device *azx_dev = &chip->hda_dev[i];
+
+		azx_sd_writeb(chip, azx_dev, SD_CTL,
+			      azx_sd_readb(chip, azx_dev, SD_CTL) &
+					~SD_INT_MASK);
+	}
+
+	/* disable SIE for all streams */
+	azx_writeb(chip, INTCTL, 0);
+
+	/* disable controller CIE and GIE */
+	azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) &
+		   ~(AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN));
+}
+
+/* clear interrupts */
+static void hda_int_clear(struct hda *chip)
+{
+	int i;
+
+	/* clear stream status */
+	for (i = 0; i < chip->num_streams; i++) {
+		struct hda_device *azx_dev = &chip->hda_dev[i];
+
+		azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK);
+	}
+
+	/* clear STATESTS */
+	azx_writew(chip, STATESTS, STATESTS_INT_MASK);
+
+	/* clear rirb status */
+	azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
+
+	/* clear int status */
+	azx_writel(chip, INTSTS, AZX_INT_CTRL_EN | AZX_INT_ALL_STREAM);
+}
+
+/*
+ * reset and start the controller registers
+ */
+void hda_init_chip(struct hda *chip, bool full_reset)
+{
+	if (chip->initialized)
+		return;
+
+	/* reset controller */
+	hda_reset(chip, full_reset);
+
+	/* initialize interrupts */
+	hda_int_clear(chip);
+	hda_int_enable(chip);
+
+	/* initialize the codec command I/O */
+	if (!chip->single_cmd)
+		hda_init_cmd_io(chip);
+
+	/* program the position buffer */
+	azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
+	azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr));
+
+	chip->initialized = 1;
+}
+EXPORT_SYMBOL_GPL(hda_init_chip);
+
+void hda_stop_chip(struct hda *chip)
+{
+	if (!chip->initialized)
+		return;
+
+	/* disable interrupts */
+	hda_int_disable(chip);
+	hda_int_clear(chip);
+
+	/* disable CORB/RIRB */
+	hda_free_cmd_io(chip);
+
+	/* disable position buffer */
+	azx_writel(chip, DPLBASE, 0);
+	azx_writel(chip, DPUBASE, 0);
+
+	chip->initialized = 0;
+}
+EXPORT_SYMBOL_GPL(hda_stop_chip);
+
+/*
+ * interrupt handler
+ */
+irqreturn_t hda_interrupt(int irq, void *dev_id)
+{
+	struct hda *chip = dev_id;
+	u32 status;
+
+#ifdef CONFIG_PM_RUNTIME
+	if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
+		if (!pm_runtime_active(chip->dev))
+			return IRQ_NONE;
+#endif
+
+	spin_lock(&chip->reg_lock);
+
+	if (chip->disabled) {
+		spin_unlock(&chip->reg_lock);
+		return IRQ_NONE;
+	}
+
+	status = azx_readl(chip, INTSTS);
+	if (status == 0 || status == 0xffffffff) {
+		spin_unlock(&chip->reg_lock);
+		return IRQ_NONE;
+	}
+	spin_unlock(&chip->reg_lock);
+
+	return IRQ_WAKE_THREAD;
+}
+EXPORT_SYMBOL_GPL(hda_interrupt);
+
+
+irqreturn_t hda_threaded_handler(int irq, void *dev_id)
+{
+	struct hda *chip = dev_id;
+	struct hda_device *azx_dev;
+	u32 status;
+	u8 sd_status;
+	int i;
+	unsigned long cookie;
+
+	status = azx_readl(chip, INTSTS);
+	spin_lock_irqsave(&chip->reg_lock, cookie);
+	for (i = 0; i < chip->num_streams; i++) {
+		azx_dev = &chip->hda_dev[i];
+		if (status & azx_dev->sd_int_sta_mask) {
+			sd_status = azx_sd_readb(chip, azx_dev, SD_STS);
+			azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK);
+			if (!azx_dev->substream || !azx_dev->running ||
+			    !(sd_status & SD_INT_COMPLETE))
+				continue;
+			/* check whether this IRQ is really acceptable */
+			if (!chip->ops->position_check ||
+			    chip->ops->position_check(chip, azx_dev)) {
+				spin_unlock_irqrestore(&chip->reg_lock, cookie);
+				snd_pcm_period_elapsed(azx_dev->substream);
+				spin_lock_irqsave(&chip->reg_lock, cookie);
+			}
+		}
+	}
+
+	/* clear rirb int */
+	status = azx_readb(chip, RIRBSTS);
+	if (status & RIRB_INT_MASK) {
+		if (status & RIRB_INT_RESPONSE) {
+			if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY)
+				udelay(80);
+			hda_update_rirb(chip);
+		}
+		azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
+	}
+
+	spin_unlock_irqrestore(&chip->reg_lock, cookie);
+
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(hda_threaded_handler);
+
+static bool is_input_stream(struct hda *chip, unsigned char index)
+{
+	return (index >= chip->capture_index_offset &&
+		 index < chip->capture_index_offset + chip->capture_streams);
+}
+
+/* initialize SD streams */
+int hda_init_stream(struct hda *chip)
+{
+	int i;
+	int in_stream_tag = 0;
+	int out_stream_tag = 0;
+
+	/* initialize each stream (aka device)
+	 * assign the starting bdl address to each stream (device)
+	 * and initialize
+	 */
+	for (i = 0; i < chip->num_streams; i++) {
+		struct hda_device *azx_dev = &chip->hda_dev[i];
+
+		azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
+		/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+		azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
+		/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
+		azx_dev->sd_int_sta_mask = 1 << i;
+		azx_dev->index = i;
+
+		/* stream tag must be unique throughout
+		 * the stream direction group,
+		 * valid values 1...15
+		 * use separate stream tag if the flag
+		 * AZX_DCAPS_SEPARATE_STREAM_TAG is used
+		 */
+		if (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG)
+			azx_dev->stream_tag =
+				is_input_stream(chip, i) ?
+				++in_stream_tag :
+				++out_stream_tag;
+		else
+			azx_dev->stream_tag = i + 1;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hda_init_stream);
+
+void hda_timecounter_init(struct snd_pcm_substream *substream,
+				bool force, cycle_t last, void *read_fn)
+{
+	struct hda_device *azx_dev = get_hda_dev(substream);
+	struct timecounter *tc = &azx_dev->tc;
+	struct cyclecounter *cc = &azx_dev->cc;
+	u64 nsec;
+
+	cc->read = read_fn;
+	cc->mask = CLOCKSOURCE_MASK(32);
+
+	/*
+	 * Converting from 24 MHz to ns means applying a 125/3 factor.
+	 * To avoid any saturation issues in intermediate operations,
+	 * the 125 factor is applied first. The division is applied
+	 * last after reading the timecounter value.
+	 * Applying the 1/3 factor as part of the multiplication
+	 * requires at least 20 bits for a decent precision, however
+	 * overflows occur after about 4 hours or less, not a option.
+	 */
+
+	cc->mult = 125; /* saturation after 195 years */
+	cc->shift = 0;
+
+	nsec = 0; /* audio time is elapsed time since trigger */
+	timecounter_init(tc, cc, nsec);
+	if (force)
+		/*
+		 * force timecounter to use predefined value,
+		 * used for synchronized starts
+		 */
+		tc->cycle_last = last;
+}
+EXPORT_SYMBOL_GPL(hda_timecounter_init);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Common HDA driver funcitons");
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [RFC v2 1/3] ALSA: hda: add HDA_MAX_CODECS
  2015-03-25  6:01 ` [RFC v2 1/3] ALSA: hda: add HDA_MAX_CODECS Vinod Koul
@ 2015-03-25  6:48   ` Takashi Iwai
  2015-03-25  7:51     ` Vinod Koul
  0 siblings, 1 reply; 10+ messages in thread
From: Takashi Iwai @ 2015-03-25  6:48 UTC (permalink / raw)
  To: Vinod Koul; +Cc: jeeja.kp, alsa-devel, lgirdwood

At Wed, 25 Mar 2015 11:31:37 +0530,
Vinod Koul wrote:
> 
> This moves AZX_MAX_CODECS define to HDA_MAX_CODECS so that common code can
> use this as well

Well, HDA_MAX_CODECS = 8 isn't about the codec specification, but
rather a limitation of the current standard HD-audio controller h/w.
The spec itself limits to 16 (= 0x0f).

So, I don't want to mix this into hda_verbs.h that is the place
defining the specification.  It's fine to move to hdaudio.h instead,
though.


thanks,

Takashi

> 
> Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
> ---
>  include/sound/hda_verbs.h      |    1 +
>  sound/pci/hda/hda_controller.c |    4 ++--
>  sound/pci/hda/hda_controller.h |    9 ++++-----
>  3 files changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/include/sound/hda_verbs.h b/include/sound/hda_verbs.h
> index d0509db6d0ec..42b8415b2254 100644
> --- a/include/sound/hda_verbs.h
> +++ b/include/sound/hda_verbs.h
> @@ -550,5 +550,6 @@ enum {
>  
>  /* max. codec address */
>  #define HDA_MAX_CODEC_ADDRESS	0x0f
> +#define HDA_MAX_CODECS		8
>  
>  #endif /* __SOUND_HDA_VERBS_H */
> diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
> index 26ce990592a0..abb3822f5488 100644
> --- a/sound/pci/hda/hda_controller.c
> +++ b/sound/pci/hda/hda_controller.c
> @@ -1066,7 +1066,7 @@ static unsigned int azx_command_addr(u32 cmd)
>  {
>  	unsigned int addr = cmd >> 28;
>  
> -	if (addr >= AZX_MAX_CODECS) {
> +	if (addr >= HDA_MAX_CODECS) {
>  		snd_BUG();
>  		addr = 0;
>  	}
> @@ -1136,7 +1136,7 @@ static void azx_update_rirb(struct azx *chip)
>  		res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
>  		res = le32_to_cpu(chip->rirb.buf[rp]);
>  		addr = res_ex & 0xf;
> -		if ((addr >= AZX_MAX_CODECS) || !(chip->codec_mask & (1 << addr))) {
> +		if ((addr >= HDA_MAX_CODECS) || !(chip->codec_mask & (1 << addr))) {
>  			dev_err(chip->card->dev, "spurious response %#x:%#x, rp = %d, wp = %d",
>  				res, res_ex,
>  				chip->rirb.rp, wp);
> diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
> index be1b7ded8d82..2aa75e34a718 100644
> --- a/sound/pci/hda/hda_controller.h
> +++ b/sound/pci/hda/hda_controller.h
> @@ -119,9 +119,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
>  #define RIRB_INT_MASK		0x05
>  
>  /* STATESTS int mask: S3,SD2,SD1,SD0 */
> -#define AZX_MAX_CODECS		8
>  #define AZX_DEFAULT_CODECS	4
> -#define STATESTS_INT_MASK	((1 << AZX_MAX_CODECS) - 1)
> +#define STATESTS_INT_MASK	((1 << HDA_MAX_CODECS) - 1)
>  
>  /* SD_CTL bits */
>  #define SD_CTL_STREAM_RESET	0x01	/* stream reset bit */
> @@ -245,8 +244,8 @@ struct azx_rb {
>  	dma_addr_t addr;	/* physical address of CORB/RIRB buffer */
>  	/* for RIRB */
>  	unsigned short rp, wp;	/* read/write pointers */
> -	int cmds[AZX_MAX_CODECS];	/* number of pending requests */
> -	u32 res[AZX_MAX_CODECS];	/* last read value */
> +	int cmds[HDA_MAX_CODECS];	/* number of pending requests */
> +	u32 res[HDA_MAX_CODECS];	/* last read value */
>  };
>  
>  struct azx;
> @@ -360,7 +359,7 @@ struct azx {
>  	unsigned int disabled:1; /* disabled by VGA-switcher */
>  
>  	/* for debugging */
> -	unsigned int last_cmd[AZX_MAX_CODECS];
> +	unsigned int last_cmd[HDA_MAX_CODECS];
>  
>  #ifdef CONFIG_SND_HDA_DSP_LOADER
>  	struct azx_dev saved_azx_dev;
> -- 
> 1.7.9.5
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC v2 3/3] ALSA: hda: add hda controller to hda
  2015-03-25  6:01 ` [RFC v2 3/3] ALSA: hda: add hda controller to hda Vinod Koul
@ 2015-03-25  7:05   ` Takashi Iwai
  2015-03-25  8:01     ` Vinod Koul
  0 siblings, 1 reply; 10+ messages in thread
From: Takashi Iwai @ 2015-03-25  7:05 UTC (permalink / raw)
  To: Vinod Koul; +Cc: jeeja.kp, alsa-devel, lgirdwood

At Wed, 25 Mar 2015 11:31:39 +0530,
Vinod Koul wrote:
> 
> From: Jeeja KP <jeeja.kp@intel.com>
> 
> This adds hdac_controller into hda core.
> 
> Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
> Signed-off-by: Vinod Koul <vinod.koul@intel.com>

Now the question is whether we need all codes.
For example, the bus reset isn't needed for Intel chips but it's a
workaround for old AMD chips.  Also, polling and single_cmd fallbacks
are also for buggy chips, and I don't think we'd need them for SKL.

The rirb_error flag can be removed and converted to the normal error
code propagation with the new code.  It's there just because the old
interface didn't give the error code in get_response op.  And, of
course, there are superfluous DSP loader for CA0132...

You can find some code I wrote in a couple of weeks ago in
test/hda-dev2 branch of sound-unstable git tree.  I rebased it on top
of hda-regmap branch now, so it's mostly clean.  There you can find
the subset of HDA controller codes that should be enough for a clean
controller driver implementation.

I don't mean that mine is necessarily the best.  But my point is that
we don't have to copy the whole in sound/hda.  Rather start from a
smaller and mandatory subset for the new driver, then integrate this
into the existing legacy driver.


thanks,

Takashi

> ---
>  include/sound/hdaudio.h     |  215 ++++++++
>  sound/hda/Makefile          |    2 +-
>  sound/hda/hdac_controller.c | 1284 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 1500 insertions(+), 1 deletion(-)
>  create mode 100644 sound/hda/hdac_controller.c
> 
> diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
> index 675614dc2b88..2843471efc7a 100644
> --- a/include/sound/hdaudio.h
> +++ b/include/sound/hdaudio.h
> @@ -5,8 +5,11 @@
>  #ifndef __SOUND_HDAUDIO_H
>  #define __SOUND_HDAUDIO_H
>  
> +#include <linux/timecounter.h>
> +#include <sound/core.h>
>  #include <linux/device.h>
>  #include <sound/hda_verbs.h>
> +#include <sound/pcm.h>
>  
>  /* codec node id */
>  typedef u16 hda_nid_t;
> @@ -15,6 +18,7 @@ struct hdac_bus;
>  struct hdac_device;
>  struct hdac_driver;
>  struct hdac_widget_tree;
> +struct hda;
>  
>  /*
>   * exported bus type
> @@ -125,6 +129,8 @@ struct hdac_bus_ops {
>  	/* get a response from the last command */
>  	int (*get_response)(struct hdac_bus *bus, unsigned int addr,
>  			    unsigned int *res);
> +	/* reset bus for retry verb */
> +	void (*bus_reset)(struct hdac_bus *bus);
>  };
>  
>  #define HDA_UNSOL_QUEUE_SIZE	64
> @@ -144,6 +150,7 @@ struct hdac_bus {
>  	u32 unsol_queue[HDA_UNSOL_QUEUE_SIZE * 2]; /* ring buffer */
>  	unsigned int unsol_rp, unsol_wp;
>  	struct work_struct unsol_work;
> +	struct workqueue_struct *workq; /* common workqueue for codecs */
>  
>  	/* bit flags of powered codecs */
>  	unsigned long codec_powered;
> @@ -153,6 +160,17 @@ struct hdac_bus {
>  
>  	/* locks */
>  	struct mutex cmd_mutex;
> +
> +	void *private_data;
> +
> +	/* msic op flags */
> +	unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */
> +
> +	/*status for controller */
> +	unsigned int rirb_error:1;      /* error in codec communication */
> +	unsigned int response_reset:1;  /* controller was reset */
> +	unsigned int no_response_fallback:1; /* don't fallback at RIRB error */
> +	unsigned int in_reset:1;        /* during reset operation */
>  };
>  
>  int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
> @@ -178,4 +196,201 @@ static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
>  	clear_bit(codec->addr, &codec->bus->codec_powered);
>  }
>  
> +/*
> + * HD-audio contoller base device
> + */
> +struct hda_device {
> +	struct snd_dma_buffer bdl;	/* BDL buffer */
> +	u32 *posbuf;			/* position buffer pointer */
> +
> +	unsigned int bufsize;		/* size of the play buffer in bytes */
> +	unsigned int period_bytes;	 /* size of the period in bytes */
> +	unsigned int frags;		/* number for period in the play buffer */
> +	unsigned int fifo_size;		/* FIFO size */
> +	unsigned long start_wallclk;	/* start + minimum wallclk */
> +	unsigned long period_wallclk;	/* wallclk for period */
> +
> +	void __iomem *sd_addr;		/* stream descriptor pointer */
> +
> +	u32 sd_int_sta_mask;		/* stream int status mask */
> +
> +	/* pcm support */
> +	struct snd_pcm_substream *substream;	/* assigned substream,
> +						 * set in PCM open
> +						 */
> +	unsigned int format_val;	/* format value to be set in the
> +					 * controller and the codec
> +					 */
> +	unsigned char stream_tag;	/* assigned stream */
> +	unsigned char index;		/* stream index */
> +	int assigned_key;		/* last device# key assigned to */
> +
> +	unsigned int opened:1;
> +	unsigned int running:1;
> +	unsigned int irq_pending:1;
> +	unsigned int prepared:1;
> +	unsigned int locked:1;
> +	unsigned int wc_marked:1;
> +	unsigned int no_period_wakeup:1;
> +
> +	struct timecounter  tc;
> +	struct cyclecounter cc;
> +
> +	int delay_negative_threshold;
> +
> +	/* Allows dsp load to have sole access to the playback stream. */
> +	struct mutex dsp_mutex;
> +};
> +
> +/* CORB/RIRB */
> +struct hda_rb {
> +	u32 *buf;			/* CORB/RIRB buffer
> +					 * Each CORB entry is 4byte, RIRB is 8byte
> +					 */
> +	dma_addr_t addr;		/* physical address of CORB/RIRB buffer */
> +
> +	/* for RIRB */
> +	unsigned short rp, wp;		/* read/write pointers */
> +	int cmds[HDA_MAX_CODECS];	/* number of pending requests */
> +	u32 res[HDA_MAX_CODECS];	/* last read value */
> +};
> +
> +/* Functions to read/write to hda registers. */
> +/* FIXME: should we name this something else ??? */
> +struct hda_ops {
> +	void (*reg_writel)(u32 value, u32 __iomem *addr);
> +	u32 (*reg_readl)(u32 __iomem *addr);
> +	void (*reg_writew)(u16 value, u16 __iomem *addr);
> +	u16 (*reg_readw)(u16 __iomem *addr);
> +	void (*reg_writeb)(u8 value, u8 __iomem *addr);
> +	u8 (*reg_readb)(u8 __iomem *addr);
> +	/* Disable msi if supported, PCI only */
> +	int (*disable_msi_reset_irq)(struct hda *);
> +	/* Allocation ops */
> +	int (*dma_alloc_pages)(struct hda *chip,
> +			       int type,
> +			       size_t size,
> +			       struct snd_dma_buffer *buf);
> +	void (*dma_free_pages)(struct hda *chip, struct snd_dma_buffer *buf);
> +	int (*substream_alloc_pages)(struct hda *chip,
> +				     struct snd_pcm_substream *substream,
> +				     size_t size);
> +	int (*substream_free_pages)(struct hda *chip,
> +				    struct snd_pcm_substream *substream);
> +	void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
> +				 struct vm_area_struct *area);
> +	/* Check if current position is acceptable */
> +	int (*position_check)(struct hda *chip, struct hda_device *hda_dev);
> +};
> +
> +typedef unsigned int (*hda_get_pos_callback_t)(struct hda *, struct hda_device *);
> +typedef int (*hda_get_delay_callback_t)(struct hda *, struct hda_device *,
> +			 unsigned int pos);
> +
> +struct hda {
> +	struct pci_dev *pci; /* FIXME: should we remove PCI assumption, right now its true for us always */
> +	struct device *dev;
> +	int dev_index;
> +
> +	/* chip type specific */
> +	int driver_type;
> +	unsigned int driver_caps;
> +	int playback_streams;
> +	int playback_index_offset;
> +	int capture_streams;
> +	int capture_index_offset;
> +	int num_streams;
> +
> +	/* Register interaction. */
> +	const struct hda_ops *ops;
> +
> +	/* position adjustment callbacks */
> +	hda_get_pos_callback_t get_position[2];
> +	hda_get_delay_callback_t get_delay[2];
> +
> +	/* pci resources */
> +	unsigned long addr;
> +	void __iomem *remap_addr;
> +	int irq;
> +
> +	/* locks */
> +	spinlock_t reg_lock;
> +	struct mutex open_mutex; /* Prevents concurrent open/close operations */
> +	struct completion probe_wait;
> +
> +	/* streams (x num_streams) */
> +	struct hda_device *hda_dev;
> +
> +	/* HD codec */
> +	unsigned short codec_mask;
> +	int  codec_probe_mask; /* copied from probe_mask option */
> +	struct hdac_bus *bus;
> +	unsigned int beep_mode;
> +
> +	/* CORB/RIRB */
> +	struct hda_rb corb;
> +	struct hda_rb rirb;
> +
> +	/* CORB/RIRB and position buffers */
> +	struct snd_dma_buffer rb;
> +	struct snd_dma_buffer posbuf;
> +
> +	/* flags */
> +	const int *bdl_pos_adj;
> +	int poll_count;
> +	unsigned int running:1;
> +	unsigned int initialized:1;
> +	unsigned int single_cmd:1;
> +	unsigned int polling_mode:1;
> +	unsigned int msi:1;
> +	unsigned int probing:1; /* codec probing phase */
> +	unsigned int snoop:1;
> +	unsigned int align_buffer_size:1;
> +	unsigned int region_requested:1;
> +	unsigned int disabled:1; /* disabled by VGA-switcher */
> +
> +	/* for debugging */
> +	unsigned int last_cmd[HDA_MAX_CODECS];
> +
> +	/* reboot notifier (for mysterious hangup problem at power-down) */
> +	struct notifier_block reboot_notifier;
> +
> +	struct hda_device saved_hda_dev; /* FIXME: check if we need this */
> +};
> +
> +/* Allocation functions. */
> +int hda_alloc_stream_pages(struct hda *chip);
> +void hda_free_stream_pages(struct hda *chip);
> +
> +/* pcm helper functions */
> +int hda_setup_periods(struct hda *chip,
> +			struct snd_pcm_substream *substream,
> +			struct hda_device *dev);
> +void hda_reset_device(struct hda *chip, struct hda_device *hda_dev);
> +int hda_set_device_params(struct hda *chip, struct snd_pcm_substream *substream,
> +				unsigned int format_val);
> +void hda_set_pcm_constrains(struct hda *chip, struct snd_pcm_runtime *runtime);
> +
> +/* PCM setup */
> +static inline struct hda_device *get_hda_dev(struct snd_pcm_substream *substream)
> +{
> +	return substream->runtime->private_data;
> +}
> +unsigned int hda_get_position(struct hda *chip, struct hda_device *hda_dev,
> +		int codec_delay);
> +unsigned int hda_get_pos_lpib(struct hda *chip, struct hda_device *hda_dev);
> +unsigned int hda_get_pos_posbuf(struct hda *chip, struct hda_device *hda_dev);
> +
> +/* Stream control. */
> +void hda_stream_stop(struct hda *chip, struct hda_device *hda_dev);
> +
> +/* Allocation functions. */
> +int hda_alloc_stream_pages(struct hda *chip);
> +void hda_free_stream_pages(struct hda *chip);
> +
> +/* Low level azx interface */
> +void hda_init_chip(struct hda *chip, bool full_reset);
> +void hda_stop_chip(struct hda *chip);
> +void hda_enter_link_reset(struct hda *chip);
> +
>  #endif /* __SOUND_HDAUDIO_H */
> diff --git a/sound/hda/Makefile b/sound/hda/Makefile
> index eec5da03b41f..836c5f34b4dd 100644
> --- a/sound/hda/Makefile
> +++ b/sound/hda/Makefile
> @@ -1,4 +1,4 @@
> -snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o
> +snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o hdac_controller.o
>  
>  snd-hda-core-objs += trace.o
>  CFLAGS_trace.o := -I$(src)
> diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c
> new file mode 100644
> index 000000000000..3b14f7be43da
> --- /dev/null
> +++ b/sound/hda/hdac_controller.c
> @@ -0,0 +1,1284 @@
> +/*
> + *
> + *  Implementation of Common HDA driver funcitons for Intel HD Audio.
> + *
> + *  Copyright (c) 2014 Intel Corporation
> + *  Copyright(c) 2004 Intel Corporation. All rights reserved.
> + *
> + *  Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
> + *                     PeiSen Hou <pshou@realtek.com.tw>
> + *
> + *  Modified by: KP Jeeja <jeeja.kp@intel.com>
> + *
> + *  This program is free software; you can redistribute it and/or modify it
> + *  under the terms of the GNU General Public License as published by the Free
> + *  Software Foundation; either version 2 of the License, or (at your option)
> + *  any later version.
> + *
> + *  This program is distributed in the hope that it will be useful, but WITHOUT
> + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + *  more details.
> + *
> + *
> + */
> +
> +#include <linux/clocksource.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/slab.h>
> +#include <linux/reboot.h>
> +#include <sound/core.h>
> +#include <sound/initval.h>
> +#include <sound/hdaudio.h>
> +#include <sound/hda_registers.h>
> +
> +/* DSP lock helpers */
> +#ifdef CONFIG_SND_HDA_DSP_LOADER
> +#define dsp_lock_init(dev)	mutex_init(&(dev)->dsp_mutex)
> +#define dsp_lock(dev)		mutex_lock(&(dev)->dsp_mutex)
> +#define dsp_unlock(dev)		mutex_unlock(&(dev)->dsp_mutex)
> +#define dsp_is_locked(dev)	((dev)->locked)
> +#else
> +#define dsp_lock_init(dev)	do {} while (0)
> +#define dsp_lock(dev)		do {} while (0)
> +#define dsp_unlock(dev)		do {} while (0)
> +#define dsp_is_locked(dev)	0
> +#endif
> +
> +/*
> + * AZX stream operations.
> + */
> +
> +/* start a stream */
> +void hda_stream_start(struct hda *chip, struct hda_device *azx_dev)
> +{
> +	/* enable SIE */
> +	azx_writel(chip, INTCTL,
> +		   azx_readl(chip, INTCTL) | (1 << azx_dev->index));
> +	/* set DMA start and interrupt mask */
> +	azx_sd_writeb(chip, azx_dev, SD_CTL,
> +		      azx_sd_readb(chip, azx_dev, SD_CTL) |
> +		      SD_CTL_DMA_START | SD_INT_MASK);
> +}
> +EXPORT_SYMBOL_GPL(hda_stream_start);
> +/* stop DMA */
> +static void hda_stream_clear(struct hda *chip, struct hda_device *azx_dev)
> +{
> +	azx_sd_writeb(chip, azx_dev, SD_CTL,
> +		      azx_sd_readb(chip, azx_dev, SD_CTL) &
> +		      ~(SD_CTL_DMA_START | SD_INT_MASK));
> +	azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
> +}
> +
> +/* stop a stream */
> +void hda_stream_stop(struct hda *chip, struct hda_device *azx_dev)
> +{
> +	hda_stream_clear(chip, azx_dev);
> +	/* disable SIE */
> +	azx_writel(chip, INTCTL,
> +		   azx_readl(chip, INTCTL) & ~(1 << azx_dev->index));
> +}
> +EXPORT_SYMBOL_GPL(hda_stream_stop);
> +
> +/* reset stream */
> +void hda_stream_reset(struct hda *chip, struct hda_device *azx_dev)
> +{
> +	unsigned char val;
> +	int timeout;
> +
> +	hda_stream_clear(chip, azx_dev);
> +
> +	azx_sd_writeb(chip, azx_dev, SD_CTL,
> +		      azx_sd_readb(chip, azx_dev, SD_CTL) |
> +		      SD_CTL_STREAM_RESET);
> +	udelay(3);
> +	timeout = 300;
> +	while (!((val = azx_sd_readb(chip, azx_dev, SD_CTL)) &
> +		 SD_CTL_STREAM_RESET) && --timeout)
> +		;
> +	val &= ~SD_CTL_STREAM_RESET;
> +	azx_sd_writeb(chip, azx_dev, SD_CTL, val);
> +	udelay(3);
> +
> +	timeout = 300;
> +	/* waiting for hardware to report that the stream is out of reset */
> +	while (((val = azx_sd_readb(chip, azx_dev, SD_CTL)) &
> +		SD_CTL_STREAM_RESET) && --timeout)
> +		;
> +
> +	/* reset first position - may not be synced with hw at this time */
> +	*azx_dev->posbuf = 0;
> +}
> +EXPORT_SYMBOL_GPL(hda_stream_reset);
> +
> +/*
> + * set up the SD for streaming
> + */
> +int hda_setup_controller(struct hda *chip, struct hda_device *azx_dev)
> +{
> +	unsigned int val;
> +	/* make sure the run bit is zero for SD */
> +	hda_stream_clear(chip, azx_dev);
> +	/* program the stream_tag */
> +	val = azx_sd_readl(chip, azx_dev, SD_CTL);
> +	val = (val & ~SD_CTL_STREAM_TAG_MASK) |
> +		(azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT);
> +	azx_sd_writel(chip, azx_dev, SD_CTL, val);
> +
> +	/* program the length of samples in cyclic buffer */
> +	azx_sd_writel(chip, azx_dev, SD_CBL, azx_dev->bufsize);
> +
> +	/* program the stream format */
> +	/* this value needs to be the same as the one programmed */
> +	azx_sd_writew(chip, azx_dev, SD_FORMAT, azx_dev->format_val);
> +
> +	/* program the stream LVI (last valid index) of the BDL */
> +	azx_sd_writew(chip, azx_dev, SD_LVI, azx_dev->frags - 1);
> +
> +	/* program the BDL address */
> +	/* lower BDL address */
> +	azx_sd_writel(chip, azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
> +	/* upper BDL address */
> +	azx_sd_writel(chip, azx_dev, SD_BDLPU,
> +		      upper_32_bits(azx_dev->bdl.addr));
> +
> +	/* enable the position buffer */
> +	if (chip->get_position[0] != hda_get_pos_lpib ||
> +	    chip->get_position[1] != hda_get_pos_lpib) {
> +		if (!(azx_readl(chip, DPLBASE) & AZX_DPLBASE_ENABLE))
> +			azx_writel(chip, DPLBASE,
> +				(u32)chip->posbuf.addr | AZX_DPLBASE_ENABLE);
> +	}
> +
> +	/* set the interrupt enable bits in the descriptor control register */
> +	azx_sd_writel(chip, azx_dev, SD_CTL,
> +		      azx_sd_readl(chip, azx_dev, SD_CTL) | SD_INT_MASK);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(hda_setup_controller);
> +
> +/* assign a stream for the PCM */
> +struct hda_device *
> +hda_assign_device(struct hda *chip, struct snd_pcm_substream *substream)
> +{
> +	int dev, i, nums;
> +	struct hda_device *res = NULL;
> +	/* make a non-zero unique key for the substream */
> +	int key = (substream->pcm->device << 16) | (substream->number << 2) |
> +		(substream->stream + 1);
> +
> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> +		dev = chip->playback_index_offset;
> +		nums = chip->playback_streams;
> +	} else {
> +		dev = chip->capture_index_offset;
> +		nums = chip->capture_streams;
> +	}
> +	for (i = 0; i < nums; i++, dev++) {
> +		struct hda_device *azx_dev = &chip->hda_dev[dev];
> +
> +		dsp_lock(azx_dev);
> +		if (!azx_dev->opened && !dsp_is_locked(azx_dev)) {
> +			if (azx_dev->assigned_key == key) {
> +				azx_dev->opened = 1;
> +				azx_dev->assigned_key = key;
> +				dsp_unlock(azx_dev);
> +				return azx_dev;
> +			}
> +			if (!res ||
> +			    (chip->driver_caps & AZX_DCAPS_REVERSE_ASSIGN))
> +				res = azx_dev;
> +		}
> +		dsp_unlock(azx_dev);
> +	}
> +	if (res) {
> +		dsp_lock(res);
> +		res->opened = 1;
> +		res->assigned_key = key;
> +		dsp_unlock(res);
> +	}
> +	return res;
> +}
> +EXPORT_SYMBOL_GPL(hda_assign_device);
> +
> +/* release the assigned stream */
> +void hda_release_device(struct hda_device *hda_dev)
> +{
> +	hda_dev->opened = 0;
> +}
> +EXPORT_SYMBOL_GPL(hda_release_device);
> +
> +/*
> + * set up a BDL entry
> + */
> +int hda_setup_bdle(struct hda *chip,
> +		      struct snd_dma_buffer *dmab,
> +		      struct hda_device *azx_dev, u32 **bdlp,
> +		      int ofs, int size, int with_ioc)
> +{
> +	u32 *bdl = *bdlp;
> +
> +	while (size > 0) {
> +		dma_addr_t addr;
> +		int chunk;
> +
> +		if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
> +			return -EINVAL;
> +
> +		addr = snd_sgbuf_get_addr(dmab, ofs);
> +		dev_dbg(chip->dev, "buffer address=%#llx\n", (u64)addr);
> +		/* program the address field of the BDL entry */
> +		bdl[0] = cpu_to_le32((u32)addr);
> +		bdl[1] = cpu_to_le32(upper_32_bits(addr));
> +		/* program the size field of the BDL entry */
> +		chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size);
> +		/* one BDLE cannot cross 4K boundary on CTHDA chips */
> +		if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
> +			u32 remain = 0x1000 - (ofs & 0xfff);
> +
> +			if (chunk > remain)
> +				chunk = remain;
> +		}
> +		bdl[2] = cpu_to_le32(chunk);
> +		/* program the IOC to enable interrupt
> +		 * only when the whole fragment is processed
> +		 */
> +		size -= chunk;
> +		bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
> +		bdl += 4;
> +		azx_dev->frags++;
> +		ofs += chunk;
> +	}
> +	*bdlp = bdl;
> +	dev_dbg(chip->dev, "bdl: 0x%p, ofs:0x%x\n", bdl, ofs);
> +	return ofs;
> +}
> +EXPORT_SYMBOL_GPL(hda_setup_bdle);
> +
> +/*
> + * set up BDL entries
> + */
> +int hda_setup_periods(struct hda *chip,
> +			     struct snd_pcm_substream *substream,
> +			     struct hda_device *azx_dev)
> +{
> +	u32 *bdl;
> +	int i, ofs, periods, period_bytes;
> +	int pos_adj = 0;
> +
> +	/* reset BDL address */
> +	azx_sd_writel(chip, azx_dev, SD_BDLPL, 0);
> +	azx_sd_writel(chip, azx_dev, SD_BDLPU, 0);
> +
> +	period_bytes = azx_dev->period_bytes;
> +	periods = azx_dev->bufsize / period_bytes;
> +
> +	/* program the initial BDL entries */
> +	bdl = (u32 *)azx_dev->bdl.area;
> +	ofs = 0;
> +	azx_dev->frags = 0;
> +
> +	if (chip->bdl_pos_adj)
> +		pos_adj = chip->bdl_pos_adj[chip->dev_index];
> +	if (!azx_dev->no_period_wakeup && pos_adj > 0) {
> +		struct snd_pcm_runtime *runtime = substream->runtime;
> +		int pos_align = pos_adj;
> +
> +		pos_adj = (pos_adj * runtime->rate + 47999) / 48000;
> +		if (!pos_adj)
> +			pos_adj = pos_align;
> +		else
> +			pos_adj = ((pos_adj + pos_align - 1) / pos_align) *
> +				pos_align;
> +		pos_adj = frames_to_bytes(runtime, pos_adj);
> +		if (pos_adj >= period_bytes) {
> +			dev_warn(chip->dev, "Too big adjustment %d\n",
> +				 pos_adj);
> +			pos_adj = 0;
> +		} else {
> +			ofs = hda_setup_bdle(chip, snd_pcm_get_dma_buf(substream),
> +					 azx_dev,
> +					 &bdl, ofs, pos_adj, true);
> +			if (ofs < 0)
> +				goto error;
> +		}
> +	} else
> +		pos_adj = 0;
> +
> +	for (i = 0; i < periods; i++) {
> +		if (i == periods - 1 && pos_adj)
> +			ofs = hda_setup_bdle(chip, snd_pcm_get_dma_buf(substream),
> +					 azx_dev, &bdl, ofs,
> +					 period_bytes - pos_adj, 0);
> +		else
> +			ofs = hda_setup_bdle(chip, snd_pcm_get_dma_buf(substream),
> +					 azx_dev, &bdl, ofs,
> +					 period_bytes,
> +					 !azx_dev->no_period_wakeup);
> +		if (ofs < 0)
> +			goto error;
> +	}
> +	return 0;
> +
> + error:
> +	dev_err(chip->dev, "Too many BDL entries: buffer=%d, period=%d\n",
> +		azx_dev->bufsize, period_bytes);
> +	return -EINVAL;
> +}
> +EXPORT_SYMBOL_GPL(hda_setup_periods);
> +
> +unsigned int hda_get_pos_lpib(struct hda *chip, struct hda_device *azx_dev)
> +{
> +	return azx_sd_readl(chip, azx_dev, SD_LPIB);
> +}
> +EXPORT_SYMBOL_GPL(hda_get_pos_lpib);
> +
> +unsigned int hda_get_pos_posbuf(struct hda *chip, struct hda_device *azx_dev)
> +{
> +	return le32_to_cpu(*azx_dev->posbuf);
> +}
> +EXPORT_SYMBOL_GPL(hda_get_pos_posbuf);
> +
> +unsigned int hda_get_position(struct hda *chip,
> +			      struct hda_device *azx_dev, int codec_delay)
> +{
> +	struct snd_pcm_substream *substream = azx_dev->substream;
> +	unsigned int pos;
> +	int stream = substream->stream;
> +	int delay = 0;
> +
> +	if (chip->get_position[stream])
> +		pos = chip->get_position[stream](chip, azx_dev);
> +	else /* use the position buffer as default */
> +		pos = hda_get_pos_posbuf(chip, azx_dev);
> +
> +	if (pos >= azx_dev->bufsize)
> +		pos = 0;
> +
> +	if (substream->runtime) {
> +		if (chip->get_delay[stream])
> +			delay += chip->get_delay[stream](chip, azx_dev, pos);
> +			delay += codec_delay;
> +		substream->runtime->delay = delay;
> +	}
> +
> +	return pos;
> +}
> +EXPORT_SYMBOL_GPL(hda_get_position);
> +
> +void hda_reset_device(struct hda *chip, struct hda_device *azx_dev)
> +{
> +	azx_sd_writel(chip, azx_dev, SD_BDLPL, 0);
> +	azx_sd_writel(chip, azx_dev, SD_BDLPU, 0);
> +	azx_sd_writel(chip, azx_dev, SD_CTL, 0);
> +	azx_dev->bufsize = 0;
> +	azx_dev->period_bytes = 0;
> +	azx_dev->format_val = 0;
> +}
> +EXPORT_SYMBOL_GPL(hda_reset_device);
> +
> +int hda_set_device_params(struct hda *chip, struct snd_pcm_substream *substream,
> +				unsigned int format_val)
> +{
> +
> +	unsigned int bufsize, period_bytes, stream_tag;
> +	struct hda_device *azx_dev = get_hda_dev(substream);
> +	struct snd_pcm_runtime *runtime = substream->runtime;
> +	int err;
> +
> +	bufsize = snd_pcm_lib_buffer_bytes(substream);
> +	period_bytes = snd_pcm_lib_period_bytes(substream);
> +
> +	dev_dbg(chip->dev, "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
> +		bufsize, format_val);
> +
> +	if (bufsize != azx_dev->bufsize ||
> +	    period_bytes != azx_dev->period_bytes ||
> +	    format_val != azx_dev->format_val ||
> +	    runtime->no_period_wakeup != azx_dev->no_period_wakeup) {
> +		azx_dev->bufsize = bufsize;
> +		azx_dev->period_bytes = period_bytes;
> +		azx_dev->format_val = format_val;
> +		azx_dev->no_period_wakeup = runtime->no_period_wakeup;
> +		err = hda_setup_periods(chip, substream, azx_dev);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	/* when LPIB delay correction gives a small negative value,
> +	 * we ignore it; currently set the threshold statically to
> +	 * 64 frames
> +	 */
> +	if (runtime->period_size > 64)
> +		azx_dev->delay_negative_threshold = -frames_to_bytes(runtime, 64);
> +	else
> +		azx_dev->delay_negative_threshold = 0;
> +
> +	/* wallclk has 24Mhz clock source */
> +	azx_dev->period_wallclk = (((runtime->period_size * 24000) /
> +						runtime->rate) * 1000);
> +	hda_setup_controller(chip, azx_dev);
> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +		azx_dev->fifo_size =
> +			azx_sd_readw(chip, azx_dev, SD_FIFOSIZE) + 1;
> +	else
> +		azx_dev->fifo_size = 0;
> +
> +	stream_tag = azx_dev->stream_tag;
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(hda_set_device_params);
> +
> +void hda_set_pcm_constrains(struct hda *chip, struct snd_pcm_runtime *runtime)
> +{
> +	int buff_step;
> +
> +	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
> +
> +	/* avoid wrap-around with wall-clock */
> +	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME,
> +				     20,
> +				     178000000);
> +
> +	if (chip->align_buffer_size)
> +		/* constrain buffer sizes to be multiple of 128
> +		   bytes. This is more efficient in terms of memory
> +		   access but isn't required by the HDA spec and
> +		   prevents users from specifying exact period/buffer
> +		   sizes. For example for 44.1kHz, a period size set
> +		   to 20ms will be rounded to 19.59ms. */
> +		buff_step = 128;
> +	else
> +		/* Don't enforce steps on buffer sizes, still need to
> +		   be multiple of 4 bytes (HDA spec). Tested on Intel
> +		   HDA controllers, may not work on all devices where
> +		   option needs to be disabled */
> +		buff_step = 4;
> +
> +	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
> +				   buff_step);
> +	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
> +				   buff_step);
> +
> +}
> +EXPORT_SYMBOL_GPL(hda_set_pcm_constrains);
> +
> +/*
> + * CORB / RIRB interface
> + */
> +static int hda_alloc_cmd_io(struct hda *chip)
> +{
> +	int err;
> +
> +	/* single page (at least 4096 bytes) must suffice for both ringbuffes */
> +	err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
> +					 PAGE_SIZE, &chip->rb);
> +	if (err < 0)
> +		dev_err(chip->dev, "cannot allocate CORB/RIRB\n");
> +	return err;
> +}
> +EXPORT_SYMBOL_GPL(hda_alloc_cmd_io);
> +
> +static void hda_init_cmd_io(struct hda *chip)
> +{
> +	int timeout;
> +
> +	spin_lock_irq(&chip->reg_lock);
> +	/* CORB set up */
> +	chip->corb.addr = chip->rb.addr;
> +	chip->corb.buf = (u32 *)chip->rb.area;
> +	azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
> +	azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr));
> +
> +	/* set the corb size to 256 entries (ULI requires explicitly) */
> +	azx_writeb(chip, CORBSIZE, 0x02);
> +	/* set the corb write pointer to 0 */
> +	azx_writew(chip, CORBWP, 0);
> +
> +	/* reset the corb hw read pointer */
> +	azx_writew(chip, CORBRP, AZX_CORBRP_RST);
> +	if (!(chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)) {
> +		for (timeout = 1000; timeout > 0; timeout--) {
> +			if ((azx_readw(chip, CORBRP) & AZX_CORBRP_RST) == AZX_CORBRP_RST)
> +				break;
> +			udelay(1);
> +		}
> +		if (timeout <= 0)
> +			dev_err(chip->dev, "CORB reset timeout#1, CORBRP = %d\n",
> +				azx_readw(chip, CORBRP));
> +
> +		azx_writew(chip, CORBRP, 0);
> +		for (timeout = 1000; timeout > 0; timeout--) {
> +			if (azx_readw(chip, CORBRP) == 0)
> +				break;
> +			udelay(1);
> +		}
> +		if (timeout <= 0)
> +			dev_err(chip->dev, "CORB reset timeout#2, CORBRP = %d\n",
> +				azx_readw(chip, CORBRP));
> +	}
> +
> +	/* enable corb dma */
> +	azx_writeb(chip, CORBCTL, AZX_CORBCTL_RUN);
> +
> +	/* RIRB set up */
> +	chip->rirb.addr = chip->rb.addr + 2048;
> +	chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
> +	chip->rirb.wp = chip->rirb.rp = 0;
> +	memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds));
> +	azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
> +	azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr));
> +
> +	/* set the rirb size to 256 entries (ULI requires explicitly) */
> +	azx_writeb(chip, RIRBSIZE, 0x02);
> +	/* reset the rirb hw write pointer */
> +	azx_writew(chip, RIRBWP, AZX_RIRBWP_RST);
> +	/* set N=1, get RIRB response interrupt for new entry */
> +	if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
> +		azx_writew(chip, RINTCNT, 0xc0);
> +	else
> +		azx_writew(chip, RINTCNT, 1);
> +	/* enable rirb dma and response irq */
> +	azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN);
> +	spin_unlock_irq(&chip->reg_lock);
> +}
> +EXPORT_SYMBOL_GPL(hda_init_cmd_io);
> +
> +static void hda_free_cmd_io(struct hda *chip)
> +{
> +	spin_lock_irq(&chip->reg_lock);
> +	/* disable ringbuffer DMAs */
> +	azx_writeb(chip, RIRBCTL, 0);
> +	azx_writeb(chip, CORBCTL, 0);
> +	spin_unlock_irq(&chip->reg_lock);
> +}
> +EXPORT_SYMBOL_GPL(hda_free_cmd_io);
> +
> +static unsigned int hda_command_addr(u32 cmd)
> +{
> +	unsigned int addr = cmd >> 28;
> +
> +	if (addr >= HDA_MAX_CODECS) {
> +		snd_BUG();
> +		addr = 0;
> +	}
> +
> +	return addr;
> +}
> +
> +/* send a command */
> +static int hda_corb_send_cmd(struct hdac_bus *bus, u32 val)
> +{
> +	struct hda *chip = bus->private_data;
> +	unsigned int addr = hda_command_addr(val);
> +	unsigned int wp, rp;
> +
> +	spin_lock_irq(&chip->reg_lock);
> +
> +	/* add command to corb */
> +	wp = azx_readw(chip, CORBWP);
> +	if (wp == 0xffff) {
> +		/* something wrong, controller likely turned to D3 */
> +		spin_unlock_irq(&chip->reg_lock);
> +		return -EIO;
> +	}
> +	wp++;
> +	wp %= AZX_MAX_CORB_ENTRIES;
> +
> +	rp = azx_readw(chip, CORBRP);
> +	if (wp == rp) {
> +		/* oops, it's full */
> +		spin_unlock_irq(&chip->reg_lock);
> +		return -EAGAIN;
> +	}
> +
> +	chip->rirb.cmds[addr]++;
> +	chip->corb.buf[wp] = cpu_to_le32(val);
> +	azx_writew(chip, CORBWP, wp);
> +
> +	spin_unlock_irq(&chip->reg_lock);
> +
> +	return 0;
> +}
> +
> +#define AZX_RIRB_EX_UNSOL_EV	(1<<4)
> +
> +/**
> + * hda_queue_unsol_event - add an unsolicited event to queue
> + * @bus: the BUS
> + * @res: unsolicited event (lower 32bit of RIRB entry)
> + * @res_ex: codec addr and flags (upper 32bit or RIRB entry)
> + *
> + * Adds the given event to the queue.  The events are processed in
> + * the workqueue asynchronously.  Call this function in the interrupt
> + * hanlder when RIRB receives an unsolicited event.
> + *
> + * Returns 0 if successful, or a negative error code.
> + */
> +int hda_queue_unsol_event(struct hdac_bus *bus, u32 res, u32 res_ex)
> +{
> +	unsigned int wp;
> +
> +	if (!bus)
> +		return 0;
> +
> +	wp = (bus->unsol_wp + 1) % HDA_UNSOL_QUEUE_SIZE;
> +
> +	wp <<= 1;
> +	bus->unsol_queue[wp] = res;
> +	bus->unsol_queue[wp + 1] = res_ex;
> +
> +	queue_work(bus->workq, &bus->unsol_work);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(hda_queue_unsol_event);
> +
> +/* retrieve RIRB entry - called from interrupt handler */
> +static void hda_update_rirb(struct hda *chip)
> +{
> +	unsigned int rp, wp;
> +	unsigned int addr;
> +	u32 res, res_ex;
> +
> +	wp = azx_readw(chip, RIRBWP);
> +	if (wp == 0xffff) {
> +		/* something wrong, controller likely turned to D3 */
> +		return;
> +	}
> +
> +	if (wp == chip->rirb.wp)
> +		return;
> +	chip->rirb.wp = wp;
> +
> +	while (chip->rirb.rp != wp) {
> +		chip->rirb.rp++;
> +		chip->rirb.rp %= AZX_MAX_RIRB_ENTRIES;
> +
> +		rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */
> +		res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
> +		res = le32_to_cpu(chip->rirb.buf[rp]);
> +		addr = res_ex & 0xf;
> +		if ((addr >= HDA_MAX_CODECS) || !(chip->codec_mask & (1 << addr))) {
> +			dev_err(chip->dev, "spurious response %#x:%#x, rp = %d, wp = %d",
> +				res, res_ex,
> +				chip->rirb.rp, wp);
> +			snd_BUG();
> +		} else if (res_ex & AZX_RIRB_EX_UNSOL_EV)
> +			hda_queue_unsol_event(chip->bus, res, res_ex);
> +		else if (chip->rirb.cmds[addr]) {
> +			chip->rirb.res[addr] = res;
> +			smp_wmb();
> +			chip->rirb.cmds[addr]--;
> +		} else if (printk_ratelimit()) {
> +			dev_err(chip->dev, "spurious response %#x:%#x, last cmd=%#08x\n",
> +				res, res_ex,
> +				chip->last_cmd[addr]);
> +		}
> +	}
> +}
> +
> +/* receive a response */
> +static unsigned int hda_rirb_get_response(struct hdac_bus *bus,
> +					  unsigned int addr)
> +{
> +	struct hda *chip = bus->private_data;
> +	unsigned long timeout;
> +	unsigned long loopcounter;
> +	int do_poll = 0;
> +
> + again:
> +	timeout = jiffies + msecs_to_jiffies(1000);
> +
> +	for (loopcounter = 0;; loopcounter++) {
> +		if (chip->polling_mode || do_poll) {
> +			spin_lock_irq(&chip->reg_lock);
> +			hda_update_rirb(chip);
> +			spin_unlock_irq(&chip->reg_lock);
> +		}
> +		if (!chip->rirb.cmds[addr]) {
> +			smp_rmb();
> +			bus->rirb_error = 0;
> +
> +			if (!do_poll)
> +				chip->poll_count = 0;
> +			return chip->rirb.res[addr]; /* the last value */
> +		}
> +		if (time_after(jiffies, timeout))
> +			break;
> +		else {
> +			udelay(10);
> +			cond_resched();
> +		}
> +	}
> +
> +	if (!bus->no_response_fallback)
> +		return -1;
> +
> +	if (!chip->polling_mode && chip->poll_count < 2) {
> +		dev_dbg(chip->dev,
> +			"azx_get_response timeout, polling the codec once: last cmd=0x%08x\n",
> +			chip->last_cmd[addr]);
> +		do_poll = 1;
> +		chip->poll_count++;
> +		goto again;
> +	}
> +
> +
> +	if (!chip->polling_mode) {
> +		dev_warn(chip->dev,
> +			 "azx_get_response timeout, switching to polling mode: last cmd=0x%08x\n",
> +			 chip->last_cmd[addr]);
> +		chip->polling_mode = 1;
> +		goto again;
> +	}
> +
> +	if (chip->msi) {
> +		dev_warn(chip->dev,
> +			 "No response from codec, disabling MSI: last cmd=0x%08x\n",
> +			 chip->last_cmd[addr]);
> +		if (chip->ops->disable_msi_reset_irq(chip) &&
> +		    chip->ops->disable_msi_reset_irq(chip) < 0) {
> +			bus->rirb_error = 1;
> +			return -1;
> +		}
> +		goto again;
> +	}
> +
> +	if (chip->probing) {
> +		/* If this critical timeout happens during the codec probing
> +		 * phase, this is likely an access to a non-existing codec
> +		 * slot.  Better to return an error and reset the system.
> +		 */
> +		return -1;
> +	}
> +
> +	/* a fatal communication error; need either to reset or to fallback
> +	 * to the single_cmd mode
> +	 */
> +	bus->rirb_error = 1;
> +	if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) {
> +		bus->response_reset = 1;
> +		return -1; /* give a chance to retry */
> +	}
> +
> +	dev_err(chip->dev,
> +		"azx_get_response timeout, switching to single_cmd mode: last cmd=0x%08x\n",
> +		chip->last_cmd[addr]);
> +	chip->single_cmd = 1;
> +	bus->response_reset = 0;
> +	/* release CORB/RIRB */
> +	hda_free_cmd_io(chip);
> +	/* disable unsolicited responses */
> +	azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_UNSOL);
> +	return -1;
> +}
> +
> +/*
> + * Use the single immediate command instead of CORB/RIRB for simplicity
> + *
> + * Note: according to Intel, this is not preferred use.  The command was
> + *       intended for the BIOS only, and may get confused with unsolicited
> + *       responses.  So, we shouldn't use it for normal operation from the
> + *       driver.
> + *       I left the codes, however, for debugging/testing purposes.
> + */
> +
> +/* receive a response */
> +static int hda_single_wait_for_response(struct hda *chip, unsigned int addr)
> +{
> +	int timeout = 50;
> +
> +	while (timeout--) {
> +		/* check IRV busy bit */
> +		if (azx_readw(chip, IRS) & AZX_IRS_VALID) {
> +			/* reuse rirb.res as the response return value */
> +			chip->rirb.res[addr] = azx_readl(chip, IR);
> +			return 0;
> +		}
> +		udelay(1);
> +	}
> +	if (printk_ratelimit())
> +		dev_dbg(chip->dev, "get_response timeout: IRS=0x%x\n",
> +			azx_readw(chip, IRS));
> +	chip->rirb.res[addr] = -1;
> +	return -EIO;
> +}
> +
> +/* send a command */
> +static int hda_single_send_cmd(struct hdac_bus *bus, u32 val)
> +{
> +	struct hda *chip = bus->private_data;
> +	unsigned int addr = hda_command_addr(val);
> +	int timeout = 50;
> +
> +	bus->rirb_error = 0;
> +	while (timeout--) {
> +		/* check ICB busy bit */
> +		if (!((azx_readw(chip, IRS) & AZX_IRS_BUSY))) {
> +			/* Clear IRV valid bit */
> +			azx_writew(chip, IRS, azx_readw(chip, IRS) |
> +				   AZX_IRS_VALID);
> +			azx_writel(chip, IC, val);
> +			azx_writew(chip, IRS, azx_readw(chip, IRS) |
> +				   AZX_IRS_BUSY);
> +			return hda_single_wait_for_response(chip, addr);
> +		}
> +		udelay(1);
> +	}
> +	if (printk_ratelimit())
> +		dev_dbg(chip->dev,
> +			"send_cmd timeout: IRS=0x%x, val=0x%x\n",
> +			azx_readw(chip, IRS), val);
> +	return -EIO;
> +}
> +
> +/* receive a response */
> +static unsigned int hda_single_get_response(struct hdac_bus *bus,
> +					    unsigned int addr)
> +{
> +	struct hda *chip = bus->private_data;
> +
> +	return chip->rirb.res[addr];
> +}
> +
> +/*
> + * The below are the main callbacks from hda_codec.
> + *
> + * They are just the skeleton to call sub-callbacks according to the
> + * current setting of chip->single_cmd.
> + */
> +
> +/* send a command */
> +int hda_send_cmd(struct hdac_bus *bus, unsigned int val)
> +{
> +	struct hda *chip = bus->private_data;
> +
> +	if (chip->disabled)
> +		return 0;
> +	chip->last_cmd[hda_command_addr(val)] = val;
> +	if (chip->single_cmd)
> +		return hda_single_send_cmd(bus, val);
> +	else
> +		return hda_corb_send_cmd(bus, val);
> +}
> +EXPORT_SYMBOL_GPL(hda_send_cmd);
> +
> +/* get a response */
> +unsigned int hda_get_response(struct hdac_bus *bus,
> +				     unsigned int addr)
> +{
> +	struct hda *chip = bus->private_data;
> +
> +	if (chip->disabled)
> +		return 0;
> +	if (chip->single_cmd)
> +		return hda_single_get_response(bus, addr);
> +	else
> +		return hda_rirb_get_response(bus, addr);
> +}
> +EXPORT_SYMBOL_GPL(hda_get_response);
> +
> +void hda_bus_reset(struct hdac_bus *bus)
> +{
> +	struct hda *chip = bus->private_data;
> +
> +	bus->in_reset = 1;
> +	hda_stop_chip(chip);
> +	hda_init_chip(chip, true);
> +	bus->in_reset = 0;
> +}
> +EXPORT_SYMBOL_GPL(hda_bus_reset);
> +
> +int hda_alloc_stream_pages(struct hda *chip)
> +{
> +	int i, err;
> +
> +	for (i = 0; i < chip->num_streams; i++) {
> +		dsp_lock_init(&chip->hda_dev[i]);
> +		/* allocate memory for the BDL for each stream */
> +		err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
> +						 BDL_SIZE,
> +						 &chip->hda_dev[i].bdl);
> +		if (err < 0) {
> +			dev_err(chip->dev, "cannot allocate BDL\n");
> +			return -ENOMEM;
> +		}
> +	}
> +	/* allocate memory for the position buffer */
> +	err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
> +					 chip->num_streams * 8, &chip->posbuf);
> +	if (err < 0) {
> +		dev_err(chip->dev, "cannot allocate posbuf\n");
> +		return -ENOMEM;
> +	}
> +
> +	/* allocate CORB/RIRB */
> +	err = hda_alloc_cmd_io(chip);
> +	if (err < 0)
> +		return err;
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(hda_alloc_stream_pages);
> +
> +void hda_free_stream_pages(struct hda *chip)
> +{
> +	int i;
> +
> +	if (chip->hda_dev) {
> +		for (i = 0; i < chip->num_streams; i++)
> +			if (chip->hda_dev[i].bdl.area)
> +				chip->ops->dma_free_pages(
> +					chip, &chip->hda_dev[i].bdl);
> +	}
> +	if (chip->rb.area)
> +		chip->ops->dma_free_pages(chip, &chip->rb);
> +	if (chip->posbuf.area)
> +		chip->ops->dma_free_pages(chip, &chip->posbuf);
> +}
> +EXPORT_SYMBOL_GPL(hda_free_stream_pages);
> +
> +/*
> + * Lowlevel interface
> + */
> +
> +/* enter link reset */
> +void hda_enter_link_reset(struct hda *chip)
> +{
> +	unsigned long timeout;
> +
> +	/* reset controller */
> +	azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_RESET);
> +
> +	timeout = jiffies + msecs_to_jiffies(100);
> +	while ((azx_readb(chip, GCTL) & AZX_GCTL_RESET) &&
> +			time_before(jiffies, timeout))
> +		usleep_range(500, 1000);
> +}
> +EXPORT_SYMBOL_GPL(hda_enter_link_reset);
> +
> +/* exit link reset */
> +void hda_exit_link_reset(struct hda *chip)
> +{
> +	unsigned long timeout;
> +
> +	azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | AZX_GCTL_RESET);
> +
> +	timeout = jiffies + msecs_to_jiffies(100);
> +	while (!azx_readb(chip, GCTL) &&
> +			time_before(jiffies, timeout))
> +		usleep_range(500, 1000);
> +}
> +EXPORT_SYMBOL_GPL(hda_exit_link_reset);
> +
> +/* reset codec link */
> +static int hda_reset(struct hda *chip, bool full_reset)
> +{
> +	if (!full_reset)
> +		goto __skip;
> +
> +	/* clear STATESTS */
> +	azx_writew(chip, STATESTS, STATESTS_INT_MASK);
> +
> +	/* reset controller */
> +	hda_enter_link_reset(chip);
> +
> +	/* delay for >= 100us for codec PLL to settle per spec
> +	 * Rev 0.9 section 5.5.1
> +	 */
> +	usleep_range(500, 1000);
> +
> +	/* Bring controller out of reset */
> +	hda_exit_link_reset(chip);
> +
> +	/* Brent Chartrand said to wait >= 540us for codecs to initialize */
> +	usleep_range(1000, 1200);
> +
> +__skip:
> +	/* check to see if controller is ready */
> +	if (!azx_readb(chip, GCTL)) {
> +		dev_dbg(chip->dev, "azx_reset: controller not ready!\n");
> +		return -EBUSY;
> +	}
> +
> +	/* Accept unsolicited responses */
> +	if (!chip->single_cmd)
> +		azx_writel(chip, GCTL, azx_readl(chip, GCTL) |
> +			   AZX_GCTL_UNSOL);
> +
> +	/* detect codecs */
> +	if (!chip->codec_mask) {
> +		chip->codec_mask = azx_readw(chip, STATESTS);
> +		dev_dbg(chip->dev, "codec_mask = 0x%x\n",
> +			chip->codec_mask);
> +	}
> +
> +	return 0;
> +}
> +
> +/* enable interrupts */
> +static void hda_int_enable(struct hda *chip)
> +{
> +	/* enable controller CIE and GIE */
> +	azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) |
> +		   AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN);
> +}
> +
> +/* disable interrupts */
> +static void hda_int_disable(struct hda *chip)
> +{
> +	int i;
> +
> +	/* disable interrupts in stream descriptor */
> +	for (i = 0; i < chip->num_streams; i++) {
> +		struct hda_device *azx_dev = &chip->hda_dev[i];
> +
> +		azx_sd_writeb(chip, azx_dev, SD_CTL,
> +			      azx_sd_readb(chip, azx_dev, SD_CTL) &
> +					~SD_INT_MASK);
> +	}
> +
> +	/* disable SIE for all streams */
> +	azx_writeb(chip, INTCTL, 0);
> +
> +	/* disable controller CIE and GIE */
> +	azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) &
> +		   ~(AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN));
> +}
> +
> +/* clear interrupts */
> +static void hda_int_clear(struct hda *chip)
> +{
> +	int i;
> +
> +	/* clear stream status */
> +	for (i = 0; i < chip->num_streams; i++) {
> +		struct hda_device *azx_dev = &chip->hda_dev[i];
> +
> +		azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK);
> +	}
> +
> +	/* clear STATESTS */
> +	azx_writew(chip, STATESTS, STATESTS_INT_MASK);
> +
> +	/* clear rirb status */
> +	azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
> +
> +	/* clear int status */
> +	azx_writel(chip, INTSTS, AZX_INT_CTRL_EN | AZX_INT_ALL_STREAM);
> +}
> +
> +/*
> + * reset and start the controller registers
> + */
> +void hda_init_chip(struct hda *chip, bool full_reset)
> +{
> +	if (chip->initialized)
> +		return;
> +
> +	/* reset controller */
> +	hda_reset(chip, full_reset);
> +
> +	/* initialize interrupts */
> +	hda_int_clear(chip);
> +	hda_int_enable(chip);
> +
> +	/* initialize the codec command I/O */
> +	if (!chip->single_cmd)
> +		hda_init_cmd_io(chip);
> +
> +	/* program the position buffer */
> +	azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
> +	azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr));
> +
> +	chip->initialized = 1;
> +}
> +EXPORT_SYMBOL_GPL(hda_init_chip);
> +
> +void hda_stop_chip(struct hda *chip)
> +{
> +	if (!chip->initialized)
> +		return;
> +
> +	/* disable interrupts */
> +	hda_int_disable(chip);
> +	hda_int_clear(chip);
> +
> +	/* disable CORB/RIRB */
> +	hda_free_cmd_io(chip);
> +
> +	/* disable position buffer */
> +	azx_writel(chip, DPLBASE, 0);
> +	azx_writel(chip, DPUBASE, 0);
> +
> +	chip->initialized = 0;
> +}
> +EXPORT_SYMBOL_GPL(hda_stop_chip);
> +
> +/*
> + * interrupt handler
> + */
> +irqreturn_t hda_interrupt(int irq, void *dev_id)
> +{
> +	struct hda *chip = dev_id;
> +	u32 status;
> +
> +#ifdef CONFIG_PM_RUNTIME
> +	if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
> +		if (!pm_runtime_active(chip->dev))
> +			return IRQ_NONE;
> +#endif
> +
> +	spin_lock(&chip->reg_lock);
> +
> +	if (chip->disabled) {
> +		spin_unlock(&chip->reg_lock);
> +		return IRQ_NONE;
> +	}
> +
> +	status = azx_readl(chip, INTSTS);
> +	if (status == 0 || status == 0xffffffff) {
> +		spin_unlock(&chip->reg_lock);
> +		return IRQ_NONE;
> +	}
> +	spin_unlock(&chip->reg_lock);
> +
> +	return IRQ_WAKE_THREAD;
> +}
> +EXPORT_SYMBOL_GPL(hda_interrupt);
> +
> +
> +irqreturn_t hda_threaded_handler(int irq, void *dev_id)
> +{
> +	struct hda *chip = dev_id;
> +	struct hda_device *azx_dev;
> +	u32 status;
> +	u8 sd_status;
> +	int i;
> +	unsigned long cookie;
> +
> +	status = azx_readl(chip, INTSTS);
> +	spin_lock_irqsave(&chip->reg_lock, cookie);
> +	for (i = 0; i < chip->num_streams; i++) {
> +		azx_dev = &chip->hda_dev[i];
> +		if (status & azx_dev->sd_int_sta_mask) {
> +			sd_status = azx_sd_readb(chip, azx_dev, SD_STS);
> +			azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK);
> +			if (!azx_dev->substream || !azx_dev->running ||
> +			    !(sd_status & SD_INT_COMPLETE))
> +				continue;
> +			/* check whether this IRQ is really acceptable */
> +			if (!chip->ops->position_check ||
> +			    chip->ops->position_check(chip, azx_dev)) {
> +				spin_unlock_irqrestore(&chip->reg_lock, cookie);
> +				snd_pcm_period_elapsed(azx_dev->substream);
> +				spin_lock_irqsave(&chip->reg_lock, cookie);
> +			}
> +		}
> +	}
> +
> +	/* clear rirb int */
> +	status = azx_readb(chip, RIRBSTS);
> +	if (status & RIRB_INT_MASK) {
> +		if (status & RIRB_INT_RESPONSE) {
> +			if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY)
> +				udelay(80);
> +			hda_update_rirb(chip);
> +		}
> +		azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
> +	}
> +
> +	spin_unlock_irqrestore(&chip->reg_lock, cookie);
> +
> +	return IRQ_HANDLED;
> +}
> +EXPORT_SYMBOL_GPL(hda_threaded_handler);
> +
> +static bool is_input_stream(struct hda *chip, unsigned char index)
> +{
> +	return (index >= chip->capture_index_offset &&
> +		 index < chip->capture_index_offset + chip->capture_streams);
> +}
> +
> +/* initialize SD streams */
> +int hda_init_stream(struct hda *chip)
> +{
> +	int i;
> +	int in_stream_tag = 0;
> +	int out_stream_tag = 0;
> +
> +	/* initialize each stream (aka device)
> +	 * assign the starting bdl address to each stream (device)
> +	 * and initialize
> +	 */
> +	for (i = 0; i < chip->num_streams; i++) {
> +		struct hda_device *azx_dev = &chip->hda_dev[i];
> +
> +		azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
> +		/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
> +		azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
> +		/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
> +		azx_dev->sd_int_sta_mask = 1 << i;
> +		azx_dev->index = i;
> +
> +		/* stream tag must be unique throughout
> +		 * the stream direction group,
> +		 * valid values 1...15
> +		 * use separate stream tag if the flag
> +		 * AZX_DCAPS_SEPARATE_STREAM_TAG is used
> +		 */
> +		if (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG)
> +			azx_dev->stream_tag =
> +				is_input_stream(chip, i) ?
> +				++in_stream_tag :
> +				++out_stream_tag;
> +		else
> +			azx_dev->stream_tag = i + 1;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(hda_init_stream);
> +
> +void hda_timecounter_init(struct snd_pcm_substream *substream,
> +				bool force, cycle_t last, void *read_fn)
> +{
> +	struct hda_device *azx_dev = get_hda_dev(substream);
> +	struct timecounter *tc = &azx_dev->tc;
> +	struct cyclecounter *cc = &azx_dev->cc;
> +	u64 nsec;
> +
> +	cc->read = read_fn;
> +	cc->mask = CLOCKSOURCE_MASK(32);
> +
> +	/*
> +	 * Converting from 24 MHz to ns means applying a 125/3 factor.
> +	 * To avoid any saturation issues in intermediate operations,
> +	 * the 125 factor is applied first. The division is applied
> +	 * last after reading the timecounter value.
> +	 * Applying the 1/3 factor as part of the multiplication
> +	 * requires at least 20 bits for a decent precision, however
> +	 * overflows occur after about 4 hours or less, not a option.
> +	 */
> +
> +	cc->mult = 125; /* saturation after 195 years */
> +	cc->shift = 0;
> +
> +	nsec = 0; /* audio time is elapsed time since trigger */
> +	timecounter_init(tc, cc, nsec);
> +	if (force)
> +		/*
> +		 * force timecounter to use predefined value,
> +		 * used for synchronized starts
> +		 */
> +		tc->cycle_last = last;
> +}
> +EXPORT_SYMBOL_GPL(hda_timecounter_init);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("Common HDA driver funcitons");
> -- 
> 1.7.9.5
> 
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC v2 1/3] ALSA: hda: add HDA_MAX_CODECS
  2015-03-25  6:48   ` Takashi Iwai
@ 2015-03-25  7:51     ` Vinod Koul
  0 siblings, 0 replies; 10+ messages in thread
From: Vinod Koul @ 2015-03-25  7:51 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: jeeja.kp, alsa-devel, lgirdwood

On Wed, Mar 25, 2015 at 07:48:44AM +0100, Takashi Iwai wrote:
> At Wed, 25 Mar 2015 11:31:37 +0530,
> Vinod Koul wrote:
> > 
> > This moves AZX_MAX_CODECS define to HDA_MAX_CODECS so that common code can
> > use this as well
> 
> Well, HDA_MAX_CODECS = 8 isn't about the codec specification, but
> rather a limitation of the current standard HD-audio controller h/w.
> The spec itself limits to 16 (= 0x0f).
> 
> So, I don't want to mix this into hda_verbs.h that is the place
> defining the specification.  It's fine to move to hdaudio.h instead,
> though.
Sure I will move it there...

-- 
~Vinod

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC v2 3/3] ALSA: hda: add hda controller to hda
  2015-03-25  7:05   ` Takashi Iwai
@ 2015-03-25  8:01     ` Vinod Koul
  2015-03-25  8:31       ` Takashi Iwai
  0 siblings, 1 reply; 10+ messages in thread
From: Vinod Koul @ 2015-03-25  8:01 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: jeeja.kp, alsa-devel, lgirdwood

On Wed, Mar 25, 2015 at 08:05:21AM +0100, Takashi Iwai wrote:
> At Wed, 25 Mar 2015 11:31:39 +0530,
> Vinod Koul wrote:
> > 
> > From: Jeeja KP <jeeja.kp@intel.com>
> > 
> > This adds hdac_controller into hda core.
> > 
> > Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
> > Signed-off-by: Vinod Koul <vinod.koul@intel.com>
> 
> Now the question is whether we need all codes.
> For example, the bus reset isn't needed for Intel chips but it's a
> workaround for old AMD chips.  Also, polling and single_cmd fallbacks
> are also for buggy chips, and I don't think we'd need them for SKL.
I dont have a reason to think this is required
> 
> The rirb_error flag can be removed and converted to the normal error
> code propagation with the new code.  It's there just because the old
> interface didn't give the error code in get_response op.  And, of
> course, there are superfluous DSP loader for CA0132...
okay, but the DSP loader code would be bought in for us. We need to use that
to load code for the DSP. I was planning to send that out after this

> You can find some code I wrote in a couple of weeks ago in
> test/hda-dev2 branch of sound-unstable git tree.  I rebased it on top
> of hda-regmap branch now, so it's mostly clean.  There you can find
> the subset of HDA controller codes that should be enough for a clean
> controller driver implementation.
> 
> I don't mean that mine is necessarily the best.  But my point is that
> we don't have to copy the whole in sound/hda.  Rather start from a
> smaller and mandatory subset for the new driver, then integrate this
> into the existing legacy driver.

Okay sounds okay to me. The current code set has lots of legacy so deciding
which bits are required and which are not will take a while for us! Thanks
for pointing them out. I will take the code from unstable on top of this
series and see what else do we need to do.

One question I have is regarding conventions to be adopted, do we need
hdac_xxx everywhere, since I though hdac stands for hda codec.

-- 
~Vinod
> 
> 
> thanks,
> 
> Takashi
> 
> > ---
> >  include/sound/hdaudio.h     |  215 ++++++++
> >  sound/hda/Makefile          |    2 +-
> >  sound/hda/hdac_controller.c | 1284 +++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 1500 insertions(+), 1 deletion(-)
> >  create mode 100644 sound/hda/hdac_controller.c
> > 
> > diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
> > index 675614dc2b88..2843471efc7a 100644
> > --- a/include/sound/hdaudio.h
> > +++ b/include/sound/hdaudio.h
> > @@ -5,8 +5,11 @@
> >  #ifndef __SOUND_HDAUDIO_H
> >  #define __SOUND_HDAUDIO_H
> >  
> > +#include <linux/timecounter.h>
> > +#include <sound/core.h>
> >  #include <linux/device.h>
> >  #include <sound/hda_verbs.h>
> > +#include <sound/pcm.h>
> >  
> >  /* codec node id */
> >  typedef u16 hda_nid_t;
> > @@ -15,6 +18,7 @@ struct hdac_bus;
> >  struct hdac_device;
> >  struct hdac_driver;
> >  struct hdac_widget_tree;
> > +struct hda;
> >  
> >  /*
> >   * exported bus type
> > @@ -125,6 +129,8 @@ struct hdac_bus_ops {
> >  	/* get a response from the last command */
> >  	int (*get_response)(struct hdac_bus *bus, unsigned int addr,
> >  			    unsigned int *res);
> > +	/* reset bus for retry verb */
> > +	void (*bus_reset)(struct hdac_bus *bus);
> >  };
> >  
> >  #define HDA_UNSOL_QUEUE_SIZE	64
> > @@ -144,6 +150,7 @@ struct hdac_bus {
> >  	u32 unsol_queue[HDA_UNSOL_QUEUE_SIZE * 2]; /* ring buffer */
> >  	unsigned int unsol_rp, unsol_wp;
> >  	struct work_struct unsol_work;
> > +	struct workqueue_struct *workq; /* common workqueue for codecs */
> >  
> >  	/* bit flags of powered codecs */
> >  	unsigned long codec_powered;
> > @@ -153,6 +160,17 @@ struct hdac_bus {
> >  
> >  	/* locks */
> >  	struct mutex cmd_mutex;
> > +
> > +	void *private_data;
> > +
> > +	/* msic op flags */
> > +	unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */
> > +
> > +	/*status for controller */
> > +	unsigned int rirb_error:1;      /* error in codec communication */
> > +	unsigned int response_reset:1;  /* controller was reset */
> > +	unsigned int no_response_fallback:1; /* don't fallback at RIRB error */
> > +	unsigned int in_reset:1;        /* during reset operation */
> >  };
> >  
> >  int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
> > @@ -178,4 +196,201 @@ static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
> >  	clear_bit(codec->addr, &codec->bus->codec_powered);
> >  }
> >  
> > +/*
> > + * HD-audio contoller base device
> > + */
> > +struct hda_device {
> > +	struct snd_dma_buffer bdl;	/* BDL buffer */
> > +	u32 *posbuf;			/* position buffer pointer */
> > +
> > +	unsigned int bufsize;		/* size of the play buffer in bytes */
> > +	unsigned int period_bytes;	 /* size of the period in bytes */
> > +	unsigned int frags;		/* number for period in the play buffer */
> > +	unsigned int fifo_size;		/* FIFO size */
> > +	unsigned long start_wallclk;	/* start + minimum wallclk */
> > +	unsigned long period_wallclk;	/* wallclk for period */
> > +
> > +	void __iomem *sd_addr;		/* stream descriptor pointer */
> > +
> > +	u32 sd_int_sta_mask;		/* stream int status mask */
> > +
> > +	/* pcm support */
> > +	struct snd_pcm_substream *substream;	/* assigned substream,
> > +						 * set in PCM open
> > +						 */
> > +	unsigned int format_val;	/* format value to be set in the
> > +					 * controller and the codec
> > +					 */
> > +	unsigned char stream_tag;	/* assigned stream */
> > +	unsigned char index;		/* stream index */
> > +	int assigned_key;		/* last device# key assigned to */
> > +
> > +	unsigned int opened:1;
> > +	unsigned int running:1;
> > +	unsigned int irq_pending:1;
> > +	unsigned int prepared:1;
> > +	unsigned int locked:1;
> > +	unsigned int wc_marked:1;
> > +	unsigned int no_period_wakeup:1;
> > +
> > +	struct timecounter  tc;
> > +	struct cyclecounter cc;
> > +
> > +	int delay_negative_threshold;
> > +
> > +	/* Allows dsp load to have sole access to the playback stream. */
> > +	struct mutex dsp_mutex;
> > +};
> > +
> > +/* CORB/RIRB */
> > +struct hda_rb {
> > +	u32 *buf;			/* CORB/RIRB buffer
> > +					 * Each CORB entry is 4byte, RIRB is 8byte
> > +					 */
> > +	dma_addr_t addr;		/* physical address of CORB/RIRB buffer */
> > +
> > +	/* for RIRB */
> > +	unsigned short rp, wp;		/* read/write pointers */
> > +	int cmds[HDA_MAX_CODECS];	/* number of pending requests */
> > +	u32 res[HDA_MAX_CODECS];	/* last read value */
> > +};
> > +
> > +/* Functions to read/write to hda registers. */
> > +/* FIXME: should we name this something else ??? */
> > +struct hda_ops {
> > +	void (*reg_writel)(u32 value, u32 __iomem *addr);
> > +	u32 (*reg_readl)(u32 __iomem *addr);
> > +	void (*reg_writew)(u16 value, u16 __iomem *addr);
> > +	u16 (*reg_readw)(u16 __iomem *addr);
> > +	void (*reg_writeb)(u8 value, u8 __iomem *addr);
> > +	u8 (*reg_readb)(u8 __iomem *addr);
> > +	/* Disable msi if supported, PCI only */
> > +	int (*disable_msi_reset_irq)(struct hda *);
> > +	/* Allocation ops */
> > +	int (*dma_alloc_pages)(struct hda *chip,
> > +			       int type,
> > +			       size_t size,
> > +			       struct snd_dma_buffer *buf);
> > +	void (*dma_free_pages)(struct hda *chip, struct snd_dma_buffer *buf);
> > +	int (*substream_alloc_pages)(struct hda *chip,
> > +				     struct snd_pcm_substream *substream,
> > +				     size_t size);
> > +	int (*substream_free_pages)(struct hda *chip,
> > +				    struct snd_pcm_substream *substream);
> > +	void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
> > +				 struct vm_area_struct *area);
> > +	/* Check if current position is acceptable */
> > +	int (*position_check)(struct hda *chip, struct hda_device *hda_dev);
> > +};
> > +
> > +typedef unsigned int (*hda_get_pos_callback_t)(struct hda *, struct hda_device *);
> > +typedef int (*hda_get_delay_callback_t)(struct hda *, struct hda_device *,
> > +			 unsigned int pos);
> > +
> > +struct hda {
> > +	struct pci_dev *pci; /* FIXME: should we remove PCI assumption, right now its true for us always */
> > +	struct device *dev;
> > +	int dev_index;
> > +
> > +	/* chip type specific */
> > +	int driver_type;
> > +	unsigned int driver_caps;
> > +	int playback_streams;
> > +	int playback_index_offset;
> > +	int capture_streams;
> > +	int capture_index_offset;
> > +	int num_streams;
> > +
> > +	/* Register interaction. */
> > +	const struct hda_ops *ops;
> > +
> > +	/* position adjustment callbacks */
> > +	hda_get_pos_callback_t get_position[2];
> > +	hda_get_delay_callback_t get_delay[2];
> > +
> > +	/* pci resources */
> > +	unsigned long addr;
> > +	void __iomem *remap_addr;
> > +	int irq;
> > +
> > +	/* locks */
> > +	spinlock_t reg_lock;
> > +	struct mutex open_mutex; /* Prevents concurrent open/close operations */
> > +	struct completion probe_wait;
> > +
> > +	/* streams (x num_streams) */
> > +	struct hda_device *hda_dev;
> > +
> > +	/* HD codec */
> > +	unsigned short codec_mask;
> > +	int  codec_probe_mask; /* copied from probe_mask option */
> > +	struct hdac_bus *bus;
> > +	unsigned int beep_mode;
> > +
> > +	/* CORB/RIRB */
> > +	struct hda_rb corb;
> > +	struct hda_rb rirb;
> > +
> > +	/* CORB/RIRB and position buffers */
> > +	struct snd_dma_buffer rb;
> > +	struct snd_dma_buffer posbuf;
> > +
> > +	/* flags */
> > +	const int *bdl_pos_adj;
> > +	int poll_count;
> > +	unsigned int running:1;
> > +	unsigned int initialized:1;
> > +	unsigned int single_cmd:1;
> > +	unsigned int polling_mode:1;
> > +	unsigned int msi:1;
> > +	unsigned int probing:1; /* codec probing phase */
> > +	unsigned int snoop:1;
> > +	unsigned int align_buffer_size:1;
> > +	unsigned int region_requested:1;
> > +	unsigned int disabled:1; /* disabled by VGA-switcher */
> > +
> > +	/* for debugging */
> > +	unsigned int last_cmd[HDA_MAX_CODECS];
> > +
> > +	/* reboot notifier (for mysterious hangup problem at power-down) */
> > +	struct notifier_block reboot_notifier;
> > +
> > +	struct hda_device saved_hda_dev; /* FIXME: check if we need this */
> > +};
> > +
> > +/* Allocation functions. */
> > +int hda_alloc_stream_pages(struct hda *chip);
> > +void hda_free_stream_pages(struct hda *chip);
> > +
> > +/* pcm helper functions */
> > +int hda_setup_periods(struct hda *chip,
> > +			struct snd_pcm_substream *substream,
> > +			struct hda_device *dev);
> > +void hda_reset_device(struct hda *chip, struct hda_device *hda_dev);
> > +int hda_set_device_params(struct hda *chip, struct snd_pcm_substream *substream,
> > +				unsigned int format_val);
> > +void hda_set_pcm_constrains(struct hda *chip, struct snd_pcm_runtime *runtime);
> > +
> > +/* PCM setup */
> > +static inline struct hda_device *get_hda_dev(struct snd_pcm_substream *substream)
> > +{
> > +	return substream->runtime->private_data;
> > +}
> > +unsigned int hda_get_position(struct hda *chip, struct hda_device *hda_dev,
> > +		int codec_delay);
> > +unsigned int hda_get_pos_lpib(struct hda *chip, struct hda_device *hda_dev);
> > +unsigned int hda_get_pos_posbuf(struct hda *chip, struct hda_device *hda_dev);
> > +
> > +/* Stream control. */
> > +void hda_stream_stop(struct hda *chip, struct hda_device *hda_dev);
> > +
> > +/* Allocation functions. */
> > +int hda_alloc_stream_pages(struct hda *chip);
> > +void hda_free_stream_pages(struct hda *chip);
> > +
> > +/* Low level azx interface */
> > +void hda_init_chip(struct hda *chip, bool full_reset);
> > +void hda_stop_chip(struct hda *chip);
> > +void hda_enter_link_reset(struct hda *chip);
> > +
> >  #endif /* __SOUND_HDAUDIO_H */
> > diff --git a/sound/hda/Makefile b/sound/hda/Makefile
> > index eec5da03b41f..836c5f34b4dd 100644
> > --- a/sound/hda/Makefile
> > +++ b/sound/hda/Makefile
> > @@ -1,4 +1,4 @@
> > -snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o
> > +snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o hdac_controller.o
> >  
> >  snd-hda-core-objs += trace.o
> >  CFLAGS_trace.o := -I$(src)
> > diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c
> > new file mode 100644
> > index 000000000000..3b14f7be43da
> > --- /dev/null
> > +++ b/sound/hda/hdac_controller.c
> > @@ -0,0 +1,1284 @@
> > +/*
> > + *
> > + *  Implementation of Common HDA driver funcitons for Intel HD Audio.
> > + *
> > + *  Copyright (c) 2014 Intel Corporation
> > + *  Copyright(c) 2004 Intel Corporation. All rights reserved.
> > + *
> > + *  Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
> > + *                     PeiSen Hou <pshou@realtek.com.tw>
> > + *
> > + *  Modified by: KP Jeeja <jeeja.kp@intel.com>
> > + *
> > + *  This program is free software; you can redistribute it and/or modify it
> > + *  under the terms of the GNU General Public License as published by the Free
> > + *  Software Foundation; either version 2 of the License, or (at your option)
> > + *  any later version.
> > + *
> > + *  This program is distributed in the hope that it will be useful, but WITHOUT
> > + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + *  more details.
> > + *
> > + *
> > + */
> > +
> > +#include <linux/clocksource.h>
> > +#include <linux/delay.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/slab.h>
> > +#include <linux/reboot.h>
> > +#include <sound/core.h>
> > +#include <sound/initval.h>
> > +#include <sound/hdaudio.h>
> > +#include <sound/hda_registers.h>
> > +
> > +/* DSP lock helpers */
> > +#ifdef CONFIG_SND_HDA_DSP_LOADER
> > +#define dsp_lock_init(dev)	mutex_init(&(dev)->dsp_mutex)
> > +#define dsp_lock(dev)		mutex_lock(&(dev)->dsp_mutex)
> > +#define dsp_unlock(dev)		mutex_unlock(&(dev)->dsp_mutex)
> > +#define dsp_is_locked(dev)	((dev)->locked)
> > +#else
> > +#define dsp_lock_init(dev)	do {} while (0)
> > +#define dsp_lock(dev)		do {} while (0)
> > +#define dsp_unlock(dev)		do {} while (0)
> > +#define dsp_is_locked(dev)	0
> > +#endif
> > +
> > +/*
> > + * AZX stream operations.
> > + */
> > +
> > +/* start a stream */
> > +void hda_stream_start(struct hda *chip, struct hda_device *azx_dev)
> > +{
> > +	/* enable SIE */
> > +	azx_writel(chip, INTCTL,
> > +		   azx_readl(chip, INTCTL) | (1 << azx_dev->index));
> > +	/* set DMA start and interrupt mask */
> > +	azx_sd_writeb(chip, azx_dev, SD_CTL,
> > +		      azx_sd_readb(chip, azx_dev, SD_CTL) |
> > +		      SD_CTL_DMA_START | SD_INT_MASK);
> > +}
> > +EXPORT_SYMBOL_GPL(hda_stream_start);
> > +/* stop DMA */
> > +static void hda_stream_clear(struct hda *chip, struct hda_device *azx_dev)
> > +{
> > +	azx_sd_writeb(chip, azx_dev, SD_CTL,
> > +		      azx_sd_readb(chip, azx_dev, SD_CTL) &
> > +		      ~(SD_CTL_DMA_START | SD_INT_MASK));
> > +	azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
> > +}
> > +
> > +/* stop a stream */
> > +void hda_stream_stop(struct hda *chip, struct hda_device *azx_dev)
> > +{
> > +	hda_stream_clear(chip, azx_dev);
> > +	/* disable SIE */
> > +	azx_writel(chip, INTCTL,
> > +		   azx_readl(chip, INTCTL) & ~(1 << azx_dev->index));
> > +}
> > +EXPORT_SYMBOL_GPL(hda_stream_stop);
> > +
> > +/* reset stream */
> > +void hda_stream_reset(struct hda *chip, struct hda_device *azx_dev)
> > +{
> > +	unsigned char val;
> > +	int timeout;
> > +
> > +	hda_stream_clear(chip, azx_dev);
> > +
> > +	azx_sd_writeb(chip, azx_dev, SD_CTL,
> > +		      azx_sd_readb(chip, azx_dev, SD_CTL) |
> > +		      SD_CTL_STREAM_RESET);
> > +	udelay(3);
> > +	timeout = 300;
> > +	while (!((val = azx_sd_readb(chip, azx_dev, SD_CTL)) &
> > +		 SD_CTL_STREAM_RESET) && --timeout)
> > +		;
> > +	val &= ~SD_CTL_STREAM_RESET;
> > +	azx_sd_writeb(chip, azx_dev, SD_CTL, val);
> > +	udelay(3);
> > +
> > +	timeout = 300;
> > +	/* waiting for hardware to report that the stream is out of reset */
> > +	while (((val = azx_sd_readb(chip, azx_dev, SD_CTL)) &
> > +		SD_CTL_STREAM_RESET) && --timeout)
> > +		;
> > +
> > +	/* reset first position - may not be synced with hw at this time */
> > +	*azx_dev->posbuf = 0;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_stream_reset);
> > +
> > +/*
> > + * set up the SD for streaming
> > + */
> > +int hda_setup_controller(struct hda *chip, struct hda_device *azx_dev)
> > +{
> > +	unsigned int val;
> > +	/* make sure the run bit is zero for SD */
> > +	hda_stream_clear(chip, azx_dev);
> > +	/* program the stream_tag */
> > +	val = azx_sd_readl(chip, azx_dev, SD_CTL);
> > +	val = (val & ~SD_CTL_STREAM_TAG_MASK) |
> > +		(azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT);
> > +	azx_sd_writel(chip, azx_dev, SD_CTL, val);
> > +
> > +	/* program the length of samples in cyclic buffer */
> > +	azx_sd_writel(chip, azx_dev, SD_CBL, azx_dev->bufsize);
> > +
> > +	/* program the stream format */
> > +	/* this value needs to be the same as the one programmed */
> > +	azx_sd_writew(chip, azx_dev, SD_FORMAT, azx_dev->format_val);
> > +
> > +	/* program the stream LVI (last valid index) of the BDL */
> > +	azx_sd_writew(chip, azx_dev, SD_LVI, azx_dev->frags - 1);
> > +
> > +	/* program the BDL address */
> > +	/* lower BDL address */
> > +	azx_sd_writel(chip, azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
> > +	/* upper BDL address */
> > +	azx_sd_writel(chip, azx_dev, SD_BDLPU,
> > +		      upper_32_bits(azx_dev->bdl.addr));
> > +
> > +	/* enable the position buffer */
> > +	if (chip->get_position[0] != hda_get_pos_lpib ||
> > +	    chip->get_position[1] != hda_get_pos_lpib) {
> > +		if (!(azx_readl(chip, DPLBASE) & AZX_DPLBASE_ENABLE))
> > +			azx_writel(chip, DPLBASE,
> > +				(u32)chip->posbuf.addr | AZX_DPLBASE_ENABLE);
> > +	}
> > +
> > +	/* set the interrupt enable bits in the descriptor control register */
> > +	azx_sd_writel(chip, azx_dev, SD_CTL,
> > +		      azx_sd_readl(chip, azx_dev, SD_CTL) | SD_INT_MASK);
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_setup_controller);
> > +
> > +/* assign a stream for the PCM */
> > +struct hda_device *
> > +hda_assign_device(struct hda *chip, struct snd_pcm_substream *substream)
> > +{
> > +	int dev, i, nums;
> > +	struct hda_device *res = NULL;
> > +	/* make a non-zero unique key for the substream */
> > +	int key = (substream->pcm->device << 16) | (substream->number << 2) |
> > +		(substream->stream + 1);
> > +
> > +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> > +		dev = chip->playback_index_offset;
> > +		nums = chip->playback_streams;
> > +	} else {
> > +		dev = chip->capture_index_offset;
> > +		nums = chip->capture_streams;
> > +	}
> > +	for (i = 0; i < nums; i++, dev++) {
> > +		struct hda_device *azx_dev = &chip->hda_dev[dev];
> > +
> > +		dsp_lock(azx_dev);
> > +		if (!azx_dev->opened && !dsp_is_locked(azx_dev)) {
> > +			if (azx_dev->assigned_key == key) {
> > +				azx_dev->opened = 1;
> > +				azx_dev->assigned_key = key;
> > +				dsp_unlock(azx_dev);
> > +				return azx_dev;
> > +			}
> > +			if (!res ||
> > +			    (chip->driver_caps & AZX_DCAPS_REVERSE_ASSIGN))
> > +				res = azx_dev;
> > +		}
> > +		dsp_unlock(azx_dev);
> > +	}
> > +	if (res) {
> > +		dsp_lock(res);
> > +		res->opened = 1;
> > +		res->assigned_key = key;
> > +		dsp_unlock(res);
> > +	}
> > +	return res;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_assign_device);
> > +
> > +/* release the assigned stream */
> > +void hda_release_device(struct hda_device *hda_dev)
> > +{
> > +	hda_dev->opened = 0;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_release_device);
> > +
> > +/*
> > + * set up a BDL entry
> > + */
> > +int hda_setup_bdle(struct hda *chip,
> > +		      struct snd_dma_buffer *dmab,
> > +		      struct hda_device *azx_dev, u32 **bdlp,
> > +		      int ofs, int size, int with_ioc)
> > +{
> > +	u32 *bdl = *bdlp;
> > +
> > +	while (size > 0) {
> > +		dma_addr_t addr;
> > +		int chunk;
> > +
> > +		if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
> > +			return -EINVAL;
> > +
> > +		addr = snd_sgbuf_get_addr(dmab, ofs);
> > +		dev_dbg(chip->dev, "buffer address=%#llx\n", (u64)addr);
> > +		/* program the address field of the BDL entry */
> > +		bdl[0] = cpu_to_le32((u32)addr);
> > +		bdl[1] = cpu_to_le32(upper_32_bits(addr));
> > +		/* program the size field of the BDL entry */
> > +		chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size);
> > +		/* one BDLE cannot cross 4K boundary on CTHDA chips */
> > +		if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
> > +			u32 remain = 0x1000 - (ofs & 0xfff);
> > +
> > +			if (chunk > remain)
> > +				chunk = remain;
> > +		}
> > +		bdl[2] = cpu_to_le32(chunk);
> > +		/* program the IOC to enable interrupt
> > +		 * only when the whole fragment is processed
> > +		 */
> > +		size -= chunk;
> > +		bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
> > +		bdl += 4;
> > +		azx_dev->frags++;
> > +		ofs += chunk;
> > +	}
> > +	*bdlp = bdl;
> > +	dev_dbg(chip->dev, "bdl: 0x%p, ofs:0x%x\n", bdl, ofs);
> > +	return ofs;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_setup_bdle);
> > +
> > +/*
> > + * set up BDL entries
> > + */
> > +int hda_setup_periods(struct hda *chip,
> > +			     struct snd_pcm_substream *substream,
> > +			     struct hda_device *azx_dev)
> > +{
> > +	u32 *bdl;
> > +	int i, ofs, periods, period_bytes;
> > +	int pos_adj = 0;
> > +
> > +	/* reset BDL address */
> > +	azx_sd_writel(chip, azx_dev, SD_BDLPL, 0);
> > +	azx_sd_writel(chip, azx_dev, SD_BDLPU, 0);
> > +
> > +	period_bytes = azx_dev->period_bytes;
> > +	periods = azx_dev->bufsize / period_bytes;
> > +
> > +	/* program the initial BDL entries */
> > +	bdl = (u32 *)azx_dev->bdl.area;
> > +	ofs = 0;
> > +	azx_dev->frags = 0;
> > +
> > +	if (chip->bdl_pos_adj)
> > +		pos_adj = chip->bdl_pos_adj[chip->dev_index];
> > +	if (!azx_dev->no_period_wakeup && pos_adj > 0) {
> > +		struct snd_pcm_runtime *runtime = substream->runtime;
> > +		int pos_align = pos_adj;
> > +
> > +		pos_adj = (pos_adj * runtime->rate + 47999) / 48000;
> > +		if (!pos_adj)
> > +			pos_adj = pos_align;
> > +		else
> > +			pos_adj = ((pos_adj + pos_align - 1) / pos_align) *
> > +				pos_align;
> > +		pos_adj = frames_to_bytes(runtime, pos_adj);
> > +		if (pos_adj >= period_bytes) {
> > +			dev_warn(chip->dev, "Too big adjustment %d\n",
> > +				 pos_adj);
> > +			pos_adj = 0;
> > +		} else {
> > +			ofs = hda_setup_bdle(chip, snd_pcm_get_dma_buf(substream),
> > +					 azx_dev,
> > +					 &bdl, ofs, pos_adj, true);
> > +			if (ofs < 0)
> > +				goto error;
> > +		}
> > +	} else
> > +		pos_adj = 0;
> > +
> > +	for (i = 0; i < periods; i++) {
> > +		if (i == periods - 1 && pos_adj)
> > +			ofs = hda_setup_bdle(chip, snd_pcm_get_dma_buf(substream),
> > +					 azx_dev, &bdl, ofs,
> > +					 period_bytes - pos_adj, 0);
> > +		else
> > +			ofs = hda_setup_bdle(chip, snd_pcm_get_dma_buf(substream),
> > +					 azx_dev, &bdl, ofs,
> > +					 period_bytes,
> > +					 !azx_dev->no_period_wakeup);
> > +		if (ofs < 0)
> > +			goto error;
> > +	}
> > +	return 0;
> > +
> > + error:
> > +	dev_err(chip->dev, "Too many BDL entries: buffer=%d, period=%d\n",
> > +		azx_dev->bufsize, period_bytes);
> > +	return -EINVAL;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_setup_periods);
> > +
> > +unsigned int hda_get_pos_lpib(struct hda *chip, struct hda_device *azx_dev)
> > +{
> > +	return azx_sd_readl(chip, azx_dev, SD_LPIB);
> > +}
> > +EXPORT_SYMBOL_GPL(hda_get_pos_lpib);
> > +
> > +unsigned int hda_get_pos_posbuf(struct hda *chip, struct hda_device *azx_dev)
> > +{
> > +	return le32_to_cpu(*azx_dev->posbuf);
> > +}
> > +EXPORT_SYMBOL_GPL(hda_get_pos_posbuf);
> > +
> > +unsigned int hda_get_position(struct hda *chip,
> > +			      struct hda_device *azx_dev, int codec_delay)
> > +{
> > +	struct snd_pcm_substream *substream = azx_dev->substream;
> > +	unsigned int pos;
> > +	int stream = substream->stream;
> > +	int delay = 0;
> > +
> > +	if (chip->get_position[stream])
> > +		pos = chip->get_position[stream](chip, azx_dev);
> > +	else /* use the position buffer as default */
> > +		pos = hda_get_pos_posbuf(chip, azx_dev);
> > +
> > +	if (pos >= azx_dev->bufsize)
> > +		pos = 0;
> > +
> > +	if (substream->runtime) {
> > +		if (chip->get_delay[stream])
> > +			delay += chip->get_delay[stream](chip, azx_dev, pos);
> > +			delay += codec_delay;
> > +		substream->runtime->delay = delay;
> > +	}
> > +
> > +	return pos;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_get_position);
> > +
> > +void hda_reset_device(struct hda *chip, struct hda_device *azx_dev)
> > +{
> > +	azx_sd_writel(chip, azx_dev, SD_BDLPL, 0);
> > +	azx_sd_writel(chip, azx_dev, SD_BDLPU, 0);
> > +	azx_sd_writel(chip, azx_dev, SD_CTL, 0);
> > +	azx_dev->bufsize = 0;
> > +	azx_dev->period_bytes = 0;
> > +	azx_dev->format_val = 0;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_reset_device);
> > +
> > +int hda_set_device_params(struct hda *chip, struct snd_pcm_substream *substream,
> > +				unsigned int format_val)
> > +{
> > +
> > +	unsigned int bufsize, period_bytes, stream_tag;
> > +	struct hda_device *azx_dev = get_hda_dev(substream);
> > +	struct snd_pcm_runtime *runtime = substream->runtime;
> > +	int err;
> > +
> > +	bufsize = snd_pcm_lib_buffer_bytes(substream);
> > +	period_bytes = snd_pcm_lib_period_bytes(substream);
> > +
> > +	dev_dbg(chip->dev, "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
> > +		bufsize, format_val);
> > +
> > +	if (bufsize != azx_dev->bufsize ||
> > +	    period_bytes != azx_dev->period_bytes ||
> > +	    format_val != azx_dev->format_val ||
> > +	    runtime->no_period_wakeup != azx_dev->no_period_wakeup) {
> > +		azx_dev->bufsize = bufsize;
> > +		azx_dev->period_bytes = period_bytes;
> > +		azx_dev->format_val = format_val;
> > +		azx_dev->no_period_wakeup = runtime->no_period_wakeup;
> > +		err = hda_setup_periods(chip, substream, azx_dev);
> > +		if (err < 0)
> > +			return err;
> > +	}
> > +
> > +	/* when LPIB delay correction gives a small negative value,
> > +	 * we ignore it; currently set the threshold statically to
> > +	 * 64 frames
> > +	 */
> > +	if (runtime->period_size > 64)
> > +		azx_dev->delay_negative_threshold = -frames_to_bytes(runtime, 64);
> > +	else
> > +		azx_dev->delay_negative_threshold = 0;
> > +
> > +	/* wallclk has 24Mhz clock source */
> > +	azx_dev->period_wallclk = (((runtime->period_size * 24000) /
> > +						runtime->rate) * 1000);
> > +	hda_setup_controller(chip, azx_dev);
> > +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> > +		azx_dev->fifo_size =
> > +			azx_sd_readw(chip, azx_dev, SD_FIFOSIZE) + 1;
> > +	else
> > +		azx_dev->fifo_size = 0;
> > +
> > +	stream_tag = azx_dev->stream_tag;
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_set_device_params);
> > +
> > +void hda_set_pcm_constrains(struct hda *chip, struct snd_pcm_runtime *runtime)
> > +{
> > +	int buff_step;
> > +
> > +	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
> > +
> > +	/* avoid wrap-around with wall-clock */
> > +	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME,
> > +				     20,
> > +				     178000000);
> > +
> > +	if (chip->align_buffer_size)
> > +		/* constrain buffer sizes to be multiple of 128
> > +		   bytes. This is more efficient in terms of memory
> > +		   access but isn't required by the HDA spec and
> > +		   prevents users from specifying exact period/buffer
> > +		   sizes. For example for 44.1kHz, a period size set
> > +		   to 20ms will be rounded to 19.59ms. */
> > +		buff_step = 128;
> > +	else
> > +		/* Don't enforce steps on buffer sizes, still need to
> > +		   be multiple of 4 bytes (HDA spec). Tested on Intel
> > +		   HDA controllers, may not work on all devices where
> > +		   option needs to be disabled */
> > +		buff_step = 4;
> > +
> > +	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
> > +				   buff_step);
> > +	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
> > +				   buff_step);
> > +
> > +}
> > +EXPORT_SYMBOL_GPL(hda_set_pcm_constrains);
> > +
> > +/*
> > + * CORB / RIRB interface
> > + */
> > +static int hda_alloc_cmd_io(struct hda *chip)
> > +{
> > +	int err;
> > +
> > +	/* single page (at least 4096 bytes) must suffice for both ringbuffes */
> > +	err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
> > +					 PAGE_SIZE, &chip->rb);
> > +	if (err < 0)
> > +		dev_err(chip->dev, "cannot allocate CORB/RIRB\n");
> > +	return err;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_alloc_cmd_io);
> > +
> > +static void hda_init_cmd_io(struct hda *chip)
> > +{
> > +	int timeout;
> > +
> > +	spin_lock_irq(&chip->reg_lock);
> > +	/* CORB set up */
> > +	chip->corb.addr = chip->rb.addr;
> > +	chip->corb.buf = (u32 *)chip->rb.area;
> > +	azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
> > +	azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr));
> > +
> > +	/* set the corb size to 256 entries (ULI requires explicitly) */
> > +	azx_writeb(chip, CORBSIZE, 0x02);
> > +	/* set the corb write pointer to 0 */
> > +	azx_writew(chip, CORBWP, 0);
> > +
> > +	/* reset the corb hw read pointer */
> > +	azx_writew(chip, CORBRP, AZX_CORBRP_RST);
> > +	if (!(chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)) {
> > +		for (timeout = 1000; timeout > 0; timeout--) {
> > +			if ((azx_readw(chip, CORBRP) & AZX_CORBRP_RST) == AZX_CORBRP_RST)
> > +				break;
> > +			udelay(1);
> > +		}
> > +		if (timeout <= 0)
> > +			dev_err(chip->dev, "CORB reset timeout#1, CORBRP = %d\n",
> > +				azx_readw(chip, CORBRP));
> > +
> > +		azx_writew(chip, CORBRP, 0);
> > +		for (timeout = 1000; timeout > 0; timeout--) {
> > +			if (azx_readw(chip, CORBRP) == 0)
> > +				break;
> > +			udelay(1);
> > +		}
> > +		if (timeout <= 0)
> > +			dev_err(chip->dev, "CORB reset timeout#2, CORBRP = %d\n",
> > +				azx_readw(chip, CORBRP));
> > +	}
> > +
> > +	/* enable corb dma */
> > +	azx_writeb(chip, CORBCTL, AZX_CORBCTL_RUN);
> > +
> > +	/* RIRB set up */
> > +	chip->rirb.addr = chip->rb.addr + 2048;
> > +	chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
> > +	chip->rirb.wp = chip->rirb.rp = 0;
> > +	memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds));
> > +	azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
> > +	azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr));
> > +
> > +	/* set the rirb size to 256 entries (ULI requires explicitly) */
> > +	azx_writeb(chip, RIRBSIZE, 0x02);
> > +	/* reset the rirb hw write pointer */
> > +	azx_writew(chip, RIRBWP, AZX_RIRBWP_RST);
> > +	/* set N=1, get RIRB response interrupt for new entry */
> > +	if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
> > +		azx_writew(chip, RINTCNT, 0xc0);
> > +	else
> > +		azx_writew(chip, RINTCNT, 1);
> > +	/* enable rirb dma and response irq */
> > +	azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN);
> > +	spin_unlock_irq(&chip->reg_lock);
> > +}
> > +EXPORT_SYMBOL_GPL(hda_init_cmd_io);
> > +
> > +static void hda_free_cmd_io(struct hda *chip)
> > +{
> > +	spin_lock_irq(&chip->reg_lock);
> > +	/* disable ringbuffer DMAs */
> > +	azx_writeb(chip, RIRBCTL, 0);
> > +	azx_writeb(chip, CORBCTL, 0);
> > +	spin_unlock_irq(&chip->reg_lock);
> > +}
> > +EXPORT_SYMBOL_GPL(hda_free_cmd_io);
> > +
> > +static unsigned int hda_command_addr(u32 cmd)
> > +{
> > +	unsigned int addr = cmd >> 28;
> > +
> > +	if (addr >= HDA_MAX_CODECS) {
> > +		snd_BUG();
> > +		addr = 0;
> > +	}
> > +
> > +	return addr;
> > +}
> > +
> > +/* send a command */
> > +static int hda_corb_send_cmd(struct hdac_bus *bus, u32 val)
> > +{
> > +	struct hda *chip = bus->private_data;
> > +	unsigned int addr = hda_command_addr(val);
> > +	unsigned int wp, rp;
> > +
> > +	spin_lock_irq(&chip->reg_lock);
> > +
> > +	/* add command to corb */
> > +	wp = azx_readw(chip, CORBWP);
> > +	if (wp == 0xffff) {
> > +		/* something wrong, controller likely turned to D3 */
> > +		spin_unlock_irq(&chip->reg_lock);
> > +		return -EIO;
> > +	}
> > +	wp++;
> > +	wp %= AZX_MAX_CORB_ENTRIES;
> > +
> > +	rp = azx_readw(chip, CORBRP);
> > +	if (wp == rp) {
> > +		/* oops, it's full */
> > +		spin_unlock_irq(&chip->reg_lock);
> > +		return -EAGAIN;
> > +	}
> > +
> > +	chip->rirb.cmds[addr]++;
> > +	chip->corb.buf[wp] = cpu_to_le32(val);
> > +	azx_writew(chip, CORBWP, wp);
> > +
> > +	spin_unlock_irq(&chip->reg_lock);
> > +
> > +	return 0;
> > +}
> > +
> > +#define AZX_RIRB_EX_UNSOL_EV	(1<<4)
> > +
> > +/**
> > + * hda_queue_unsol_event - add an unsolicited event to queue
> > + * @bus: the BUS
> > + * @res: unsolicited event (lower 32bit of RIRB entry)
> > + * @res_ex: codec addr and flags (upper 32bit or RIRB entry)
> > + *
> > + * Adds the given event to the queue.  The events are processed in
> > + * the workqueue asynchronously.  Call this function in the interrupt
> > + * hanlder when RIRB receives an unsolicited event.
> > + *
> > + * Returns 0 if successful, or a negative error code.
> > + */
> > +int hda_queue_unsol_event(struct hdac_bus *bus, u32 res, u32 res_ex)
> > +{
> > +	unsigned int wp;
> > +
> > +	if (!bus)
> > +		return 0;
> > +
> > +	wp = (bus->unsol_wp + 1) % HDA_UNSOL_QUEUE_SIZE;
> > +
> > +	wp <<= 1;
> > +	bus->unsol_queue[wp] = res;
> > +	bus->unsol_queue[wp + 1] = res_ex;
> > +
> > +	queue_work(bus->workq, &bus->unsol_work);
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_queue_unsol_event);
> > +
> > +/* retrieve RIRB entry - called from interrupt handler */
> > +static void hda_update_rirb(struct hda *chip)
> > +{
> > +	unsigned int rp, wp;
> > +	unsigned int addr;
> > +	u32 res, res_ex;
> > +
> > +	wp = azx_readw(chip, RIRBWP);
> > +	if (wp == 0xffff) {
> > +		/* something wrong, controller likely turned to D3 */
> > +		return;
> > +	}
> > +
> > +	if (wp == chip->rirb.wp)
> > +		return;
> > +	chip->rirb.wp = wp;
> > +
> > +	while (chip->rirb.rp != wp) {
> > +		chip->rirb.rp++;
> > +		chip->rirb.rp %= AZX_MAX_RIRB_ENTRIES;
> > +
> > +		rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */
> > +		res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]);
> > +		res = le32_to_cpu(chip->rirb.buf[rp]);
> > +		addr = res_ex & 0xf;
> > +		if ((addr >= HDA_MAX_CODECS) || !(chip->codec_mask & (1 << addr))) {
> > +			dev_err(chip->dev, "spurious response %#x:%#x, rp = %d, wp = %d",
> > +				res, res_ex,
> > +				chip->rirb.rp, wp);
> > +			snd_BUG();
> > +		} else if (res_ex & AZX_RIRB_EX_UNSOL_EV)
> > +			hda_queue_unsol_event(chip->bus, res, res_ex);
> > +		else if (chip->rirb.cmds[addr]) {
> > +			chip->rirb.res[addr] = res;
> > +			smp_wmb();
> > +			chip->rirb.cmds[addr]--;
> > +		} else if (printk_ratelimit()) {
> > +			dev_err(chip->dev, "spurious response %#x:%#x, last cmd=%#08x\n",
> > +				res, res_ex,
> > +				chip->last_cmd[addr]);
> > +		}
> > +	}
> > +}
> > +
> > +/* receive a response */
> > +static unsigned int hda_rirb_get_response(struct hdac_bus *bus,
> > +					  unsigned int addr)
> > +{
> > +	struct hda *chip = bus->private_data;
> > +	unsigned long timeout;
> > +	unsigned long loopcounter;
> > +	int do_poll = 0;
> > +
> > + again:
> > +	timeout = jiffies + msecs_to_jiffies(1000);
> > +
> > +	for (loopcounter = 0;; loopcounter++) {
> > +		if (chip->polling_mode || do_poll) {
> > +			spin_lock_irq(&chip->reg_lock);
> > +			hda_update_rirb(chip);
> > +			spin_unlock_irq(&chip->reg_lock);
> > +		}
> > +		if (!chip->rirb.cmds[addr]) {
> > +			smp_rmb();
> > +			bus->rirb_error = 0;
> > +
> > +			if (!do_poll)
> > +				chip->poll_count = 0;
> > +			return chip->rirb.res[addr]; /* the last value */
> > +		}
> > +		if (time_after(jiffies, timeout))
> > +			break;
> > +		else {
> > +			udelay(10);
> > +			cond_resched();
> > +		}
> > +	}
> > +
> > +	if (!bus->no_response_fallback)
> > +		return -1;
> > +
> > +	if (!chip->polling_mode && chip->poll_count < 2) {
> > +		dev_dbg(chip->dev,
> > +			"azx_get_response timeout, polling the codec once: last cmd=0x%08x\n",
> > +			chip->last_cmd[addr]);
> > +		do_poll = 1;
> > +		chip->poll_count++;
> > +		goto again;
> > +	}
> > +
> > +
> > +	if (!chip->polling_mode) {
> > +		dev_warn(chip->dev,
> > +			 "azx_get_response timeout, switching to polling mode: last cmd=0x%08x\n",
> > +			 chip->last_cmd[addr]);
> > +		chip->polling_mode = 1;
> > +		goto again;
> > +	}
> > +
> > +	if (chip->msi) {
> > +		dev_warn(chip->dev,
> > +			 "No response from codec, disabling MSI: last cmd=0x%08x\n",
> > +			 chip->last_cmd[addr]);
> > +		if (chip->ops->disable_msi_reset_irq(chip) &&
> > +		    chip->ops->disable_msi_reset_irq(chip) < 0) {
> > +			bus->rirb_error = 1;
> > +			return -1;
> > +		}
> > +		goto again;
> > +	}
> > +
> > +	if (chip->probing) {
> > +		/* If this critical timeout happens during the codec probing
> > +		 * phase, this is likely an access to a non-existing codec
> > +		 * slot.  Better to return an error and reset the system.
> > +		 */
> > +		return -1;
> > +	}
> > +
> > +	/* a fatal communication error; need either to reset or to fallback
> > +	 * to the single_cmd mode
> > +	 */
> > +	bus->rirb_error = 1;
> > +	if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) {
> > +		bus->response_reset = 1;
> > +		return -1; /* give a chance to retry */
> > +	}
> > +
> > +	dev_err(chip->dev,
> > +		"azx_get_response timeout, switching to single_cmd mode: last cmd=0x%08x\n",
> > +		chip->last_cmd[addr]);
> > +	chip->single_cmd = 1;
> > +	bus->response_reset = 0;
> > +	/* release CORB/RIRB */
> > +	hda_free_cmd_io(chip);
> > +	/* disable unsolicited responses */
> > +	azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_UNSOL);
> > +	return -1;
> > +}
> > +
> > +/*
> > + * Use the single immediate command instead of CORB/RIRB for simplicity
> > + *
> > + * Note: according to Intel, this is not preferred use.  The command was
> > + *       intended for the BIOS only, and may get confused with unsolicited
> > + *       responses.  So, we shouldn't use it for normal operation from the
> > + *       driver.
> > + *       I left the codes, however, for debugging/testing purposes.
> > + */
> > +
> > +/* receive a response */
> > +static int hda_single_wait_for_response(struct hda *chip, unsigned int addr)
> > +{
> > +	int timeout = 50;
> > +
> > +	while (timeout--) {
> > +		/* check IRV busy bit */
> > +		if (azx_readw(chip, IRS) & AZX_IRS_VALID) {
> > +			/* reuse rirb.res as the response return value */
> > +			chip->rirb.res[addr] = azx_readl(chip, IR);
> > +			return 0;
> > +		}
> > +		udelay(1);
> > +	}
> > +	if (printk_ratelimit())
> > +		dev_dbg(chip->dev, "get_response timeout: IRS=0x%x\n",
> > +			azx_readw(chip, IRS));
> > +	chip->rirb.res[addr] = -1;
> > +	return -EIO;
> > +}
> > +
> > +/* send a command */
> > +static int hda_single_send_cmd(struct hdac_bus *bus, u32 val)
> > +{
> > +	struct hda *chip = bus->private_data;
> > +	unsigned int addr = hda_command_addr(val);
> > +	int timeout = 50;
> > +
> > +	bus->rirb_error = 0;
> > +	while (timeout--) {
> > +		/* check ICB busy bit */
> > +		if (!((azx_readw(chip, IRS) & AZX_IRS_BUSY))) {
> > +			/* Clear IRV valid bit */
> > +			azx_writew(chip, IRS, azx_readw(chip, IRS) |
> > +				   AZX_IRS_VALID);
> > +			azx_writel(chip, IC, val);
> > +			azx_writew(chip, IRS, azx_readw(chip, IRS) |
> > +				   AZX_IRS_BUSY);
> > +			return hda_single_wait_for_response(chip, addr);
> > +		}
> > +		udelay(1);
> > +	}
> > +	if (printk_ratelimit())
> > +		dev_dbg(chip->dev,
> > +			"send_cmd timeout: IRS=0x%x, val=0x%x\n",
> > +			azx_readw(chip, IRS), val);
> > +	return -EIO;
> > +}
> > +
> > +/* receive a response */
> > +static unsigned int hda_single_get_response(struct hdac_bus *bus,
> > +					    unsigned int addr)
> > +{
> > +	struct hda *chip = bus->private_data;
> > +
> > +	return chip->rirb.res[addr];
> > +}
> > +
> > +/*
> > + * The below are the main callbacks from hda_codec.
> > + *
> > + * They are just the skeleton to call sub-callbacks according to the
> > + * current setting of chip->single_cmd.
> > + */
> > +
> > +/* send a command */
> > +int hda_send_cmd(struct hdac_bus *bus, unsigned int val)
> > +{
> > +	struct hda *chip = bus->private_data;
> > +
> > +	if (chip->disabled)
> > +		return 0;
> > +	chip->last_cmd[hda_command_addr(val)] = val;
> > +	if (chip->single_cmd)
> > +		return hda_single_send_cmd(bus, val);
> > +	else
> > +		return hda_corb_send_cmd(bus, val);
> > +}
> > +EXPORT_SYMBOL_GPL(hda_send_cmd);
> > +
> > +/* get a response */
> > +unsigned int hda_get_response(struct hdac_bus *bus,
> > +				     unsigned int addr)
> > +{
> > +	struct hda *chip = bus->private_data;
> > +
> > +	if (chip->disabled)
> > +		return 0;
> > +	if (chip->single_cmd)
> > +		return hda_single_get_response(bus, addr);
> > +	else
> > +		return hda_rirb_get_response(bus, addr);
> > +}
> > +EXPORT_SYMBOL_GPL(hda_get_response);
> > +
> > +void hda_bus_reset(struct hdac_bus *bus)
> > +{
> > +	struct hda *chip = bus->private_data;
> > +
> > +	bus->in_reset = 1;
> > +	hda_stop_chip(chip);
> > +	hda_init_chip(chip, true);
> > +	bus->in_reset = 0;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_bus_reset);
> > +
> > +int hda_alloc_stream_pages(struct hda *chip)
> > +{
> > +	int i, err;
> > +
> > +	for (i = 0; i < chip->num_streams; i++) {
> > +		dsp_lock_init(&chip->hda_dev[i]);
> > +		/* allocate memory for the BDL for each stream */
> > +		err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
> > +						 BDL_SIZE,
> > +						 &chip->hda_dev[i].bdl);
> > +		if (err < 0) {
> > +			dev_err(chip->dev, "cannot allocate BDL\n");
> > +			return -ENOMEM;
> > +		}
> > +	}
> > +	/* allocate memory for the position buffer */
> > +	err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
> > +					 chip->num_streams * 8, &chip->posbuf);
> > +	if (err < 0) {
> > +		dev_err(chip->dev, "cannot allocate posbuf\n");
> > +		return -ENOMEM;
> > +	}
> > +
> > +	/* allocate CORB/RIRB */
> > +	err = hda_alloc_cmd_io(chip);
> > +	if (err < 0)
> > +		return err;
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_alloc_stream_pages);
> > +
> > +void hda_free_stream_pages(struct hda *chip)
> > +{
> > +	int i;
> > +
> > +	if (chip->hda_dev) {
> > +		for (i = 0; i < chip->num_streams; i++)
> > +			if (chip->hda_dev[i].bdl.area)
> > +				chip->ops->dma_free_pages(
> > +					chip, &chip->hda_dev[i].bdl);
> > +	}
> > +	if (chip->rb.area)
> > +		chip->ops->dma_free_pages(chip, &chip->rb);
> > +	if (chip->posbuf.area)
> > +		chip->ops->dma_free_pages(chip, &chip->posbuf);
> > +}
> > +EXPORT_SYMBOL_GPL(hda_free_stream_pages);
> > +
> > +/*
> > + * Lowlevel interface
> > + */
> > +
> > +/* enter link reset */
> > +void hda_enter_link_reset(struct hda *chip)
> > +{
> > +	unsigned long timeout;
> > +
> > +	/* reset controller */
> > +	azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~AZX_GCTL_RESET);
> > +
> > +	timeout = jiffies + msecs_to_jiffies(100);
> > +	while ((azx_readb(chip, GCTL) & AZX_GCTL_RESET) &&
> > +			time_before(jiffies, timeout))
> > +		usleep_range(500, 1000);
> > +}
> > +EXPORT_SYMBOL_GPL(hda_enter_link_reset);
> > +
> > +/* exit link reset */
> > +void hda_exit_link_reset(struct hda *chip)
> > +{
> > +	unsigned long timeout;
> > +
> > +	azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | AZX_GCTL_RESET);
> > +
> > +	timeout = jiffies + msecs_to_jiffies(100);
> > +	while (!azx_readb(chip, GCTL) &&
> > +			time_before(jiffies, timeout))
> > +		usleep_range(500, 1000);
> > +}
> > +EXPORT_SYMBOL_GPL(hda_exit_link_reset);
> > +
> > +/* reset codec link */
> > +static int hda_reset(struct hda *chip, bool full_reset)
> > +{
> > +	if (!full_reset)
> > +		goto __skip;
> > +
> > +	/* clear STATESTS */
> > +	azx_writew(chip, STATESTS, STATESTS_INT_MASK);
> > +
> > +	/* reset controller */
> > +	hda_enter_link_reset(chip);
> > +
> > +	/* delay for >= 100us for codec PLL to settle per spec
> > +	 * Rev 0.9 section 5.5.1
> > +	 */
> > +	usleep_range(500, 1000);
> > +
> > +	/* Bring controller out of reset */
> > +	hda_exit_link_reset(chip);
> > +
> > +	/* Brent Chartrand said to wait >= 540us for codecs to initialize */
> > +	usleep_range(1000, 1200);
> > +
> > +__skip:
> > +	/* check to see if controller is ready */
> > +	if (!azx_readb(chip, GCTL)) {
> > +		dev_dbg(chip->dev, "azx_reset: controller not ready!\n");
> > +		return -EBUSY;
> > +	}
> > +
> > +	/* Accept unsolicited responses */
> > +	if (!chip->single_cmd)
> > +		azx_writel(chip, GCTL, azx_readl(chip, GCTL) |
> > +			   AZX_GCTL_UNSOL);
> > +
> > +	/* detect codecs */
> > +	if (!chip->codec_mask) {
> > +		chip->codec_mask = azx_readw(chip, STATESTS);
> > +		dev_dbg(chip->dev, "codec_mask = 0x%x\n",
> > +			chip->codec_mask);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +/* enable interrupts */
> > +static void hda_int_enable(struct hda *chip)
> > +{
> > +	/* enable controller CIE and GIE */
> > +	azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) |
> > +		   AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN);
> > +}
> > +
> > +/* disable interrupts */
> > +static void hda_int_disable(struct hda *chip)
> > +{
> > +	int i;
> > +
> > +	/* disable interrupts in stream descriptor */
> > +	for (i = 0; i < chip->num_streams; i++) {
> > +		struct hda_device *azx_dev = &chip->hda_dev[i];
> > +
> > +		azx_sd_writeb(chip, azx_dev, SD_CTL,
> > +			      azx_sd_readb(chip, azx_dev, SD_CTL) &
> > +					~SD_INT_MASK);
> > +	}
> > +
> > +	/* disable SIE for all streams */
> > +	azx_writeb(chip, INTCTL, 0);
> > +
> > +	/* disable controller CIE and GIE */
> > +	azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) &
> > +		   ~(AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN));
> > +}
> > +
> > +/* clear interrupts */
> > +static void hda_int_clear(struct hda *chip)
> > +{
> > +	int i;
> > +
> > +	/* clear stream status */
> > +	for (i = 0; i < chip->num_streams; i++) {
> > +		struct hda_device *azx_dev = &chip->hda_dev[i];
> > +
> > +		azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK);
> > +	}
> > +
> > +	/* clear STATESTS */
> > +	azx_writew(chip, STATESTS, STATESTS_INT_MASK);
> > +
> > +	/* clear rirb status */
> > +	azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
> > +
> > +	/* clear int status */
> > +	azx_writel(chip, INTSTS, AZX_INT_CTRL_EN | AZX_INT_ALL_STREAM);
> > +}
> > +
> > +/*
> > + * reset and start the controller registers
> > + */
> > +void hda_init_chip(struct hda *chip, bool full_reset)
> > +{
> > +	if (chip->initialized)
> > +		return;
> > +
> > +	/* reset controller */
> > +	hda_reset(chip, full_reset);
> > +
> > +	/* initialize interrupts */
> > +	hda_int_clear(chip);
> > +	hda_int_enable(chip);
> > +
> > +	/* initialize the codec command I/O */
> > +	if (!chip->single_cmd)
> > +		hda_init_cmd_io(chip);
> > +
> > +	/* program the position buffer */
> > +	azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
> > +	azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr));
> > +
> > +	chip->initialized = 1;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_init_chip);
> > +
> > +void hda_stop_chip(struct hda *chip)
> > +{
> > +	if (!chip->initialized)
> > +		return;
> > +
> > +	/* disable interrupts */
> > +	hda_int_disable(chip);
> > +	hda_int_clear(chip);
> > +
> > +	/* disable CORB/RIRB */
> > +	hda_free_cmd_io(chip);
> > +
> > +	/* disable position buffer */
> > +	azx_writel(chip, DPLBASE, 0);
> > +	azx_writel(chip, DPUBASE, 0);
> > +
> > +	chip->initialized = 0;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_stop_chip);
> > +
> > +/*
> > + * interrupt handler
> > + */
> > +irqreturn_t hda_interrupt(int irq, void *dev_id)
> > +{
> > +	struct hda *chip = dev_id;
> > +	u32 status;
> > +
> > +#ifdef CONFIG_PM_RUNTIME
> > +	if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
> > +		if (!pm_runtime_active(chip->dev))
> > +			return IRQ_NONE;
> > +#endif
> > +
> > +	spin_lock(&chip->reg_lock);
> > +
> > +	if (chip->disabled) {
> > +		spin_unlock(&chip->reg_lock);
> > +		return IRQ_NONE;
> > +	}
> > +
> > +	status = azx_readl(chip, INTSTS);
> > +	if (status == 0 || status == 0xffffffff) {
> > +		spin_unlock(&chip->reg_lock);
> > +		return IRQ_NONE;
> > +	}
> > +	spin_unlock(&chip->reg_lock);
> > +
> > +	return IRQ_WAKE_THREAD;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_interrupt);
> > +
> > +
> > +irqreturn_t hda_threaded_handler(int irq, void *dev_id)
> > +{
> > +	struct hda *chip = dev_id;
> > +	struct hda_device *azx_dev;
> > +	u32 status;
> > +	u8 sd_status;
> > +	int i;
> > +	unsigned long cookie;
> > +
> > +	status = azx_readl(chip, INTSTS);
> > +	spin_lock_irqsave(&chip->reg_lock, cookie);
> > +	for (i = 0; i < chip->num_streams; i++) {
> > +		azx_dev = &chip->hda_dev[i];
> > +		if (status & azx_dev->sd_int_sta_mask) {
> > +			sd_status = azx_sd_readb(chip, azx_dev, SD_STS);
> > +			azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK);
> > +			if (!azx_dev->substream || !azx_dev->running ||
> > +			    !(sd_status & SD_INT_COMPLETE))
> > +				continue;
> > +			/* check whether this IRQ is really acceptable */
> > +			if (!chip->ops->position_check ||
> > +			    chip->ops->position_check(chip, azx_dev)) {
> > +				spin_unlock_irqrestore(&chip->reg_lock, cookie);
> > +				snd_pcm_period_elapsed(azx_dev->substream);
> > +				spin_lock_irqsave(&chip->reg_lock, cookie);
> > +			}
> > +		}
> > +	}
> > +
> > +	/* clear rirb int */
> > +	status = azx_readb(chip, RIRBSTS);
> > +	if (status & RIRB_INT_MASK) {
> > +		if (status & RIRB_INT_RESPONSE) {
> > +			if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY)
> > +				udelay(80);
> > +			hda_update_rirb(chip);
> > +		}
> > +		azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
> > +	}
> > +
> > +	spin_unlock_irqrestore(&chip->reg_lock, cookie);
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_threaded_handler);
> > +
> > +static bool is_input_stream(struct hda *chip, unsigned char index)
> > +{
> > +	return (index >= chip->capture_index_offset &&
> > +		 index < chip->capture_index_offset + chip->capture_streams);
> > +}
> > +
> > +/* initialize SD streams */
> > +int hda_init_stream(struct hda *chip)
> > +{
> > +	int i;
> > +	int in_stream_tag = 0;
> > +	int out_stream_tag = 0;
> > +
> > +	/* initialize each stream (aka device)
> > +	 * assign the starting bdl address to each stream (device)
> > +	 * and initialize
> > +	 */
> > +	for (i = 0; i < chip->num_streams; i++) {
> > +		struct hda_device *azx_dev = &chip->hda_dev[i];
> > +
> > +		azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
> > +		/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
> > +		azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
> > +		/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
> > +		azx_dev->sd_int_sta_mask = 1 << i;
> > +		azx_dev->index = i;
> > +
> > +		/* stream tag must be unique throughout
> > +		 * the stream direction group,
> > +		 * valid values 1...15
> > +		 * use separate stream tag if the flag
> > +		 * AZX_DCAPS_SEPARATE_STREAM_TAG is used
> > +		 */
> > +		if (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG)
> > +			azx_dev->stream_tag =
> > +				is_input_stream(chip, i) ?
> > +				++in_stream_tag :
> > +				++out_stream_tag;
> > +		else
> > +			azx_dev->stream_tag = i + 1;
> > +	}
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_init_stream);
> > +
> > +void hda_timecounter_init(struct snd_pcm_substream *substream,
> > +				bool force, cycle_t last, void *read_fn)
> > +{
> > +	struct hda_device *azx_dev = get_hda_dev(substream);
> > +	struct timecounter *tc = &azx_dev->tc;
> > +	struct cyclecounter *cc = &azx_dev->cc;
> > +	u64 nsec;
> > +
> > +	cc->read = read_fn;
> > +	cc->mask = CLOCKSOURCE_MASK(32);
> > +
> > +	/*
> > +	 * Converting from 24 MHz to ns means applying a 125/3 factor.
> > +	 * To avoid any saturation issues in intermediate operations,
> > +	 * the 125 factor is applied first. The division is applied
> > +	 * last after reading the timecounter value.
> > +	 * Applying the 1/3 factor as part of the multiplication
> > +	 * requires at least 20 bits for a decent precision, however
> > +	 * overflows occur after about 4 hours or less, not a option.
> > +	 */
> > +
> > +	cc->mult = 125; /* saturation after 195 years */
> > +	cc->shift = 0;
> > +
> > +	nsec = 0; /* audio time is elapsed time since trigger */
> > +	timecounter_init(tc, cc, nsec);
> > +	if (force)
> > +		/*
> > +		 * force timecounter to use predefined value,
> > +		 * used for synchronized starts
> > +		 */
> > +		tc->cycle_last = last;
> > +}
> > +EXPORT_SYMBOL_GPL(hda_timecounter_init);
> > +
> > +MODULE_LICENSE("GPL v2");
> > +MODULE_DESCRIPTION("Common HDA driver funcitons");
> > -- 
> > 1.7.9.5
> > 
> > 

-- 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC v2 3/3] ALSA: hda: add hda controller to hda
  2015-03-25  8:01     ` Vinod Koul
@ 2015-03-25  8:31       ` Takashi Iwai
  2015-03-25 10:52         ` Vinod Koul
  0 siblings, 1 reply; 10+ messages in thread
From: Takashi Iwai @ 2015-03-25  8:31 UTC (permalink / raw)
  To: Vinod Koul; +Cc: jeeja.kp, alsa-devel, lgirdwood

At Wed, 25 Mar 2015 13:31:41 +0530,
Vinod Koul wrote:
> 
> On Wed, Mar 25, 2015 at 08:05:21AM +0100, Takashi Iwai wrote:
> > At Wed, 25 Mar 2015 11:31:39 +0530,
> > Vinod Koul wrote:
> > > 
> > > From: Jeeja KP <jeeja.kp@intel.com>
> > > 
> > > This adds hdac_controller into hda core.
> > > 
> > > Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
> > > Signed-off-by: Vinod Koul <vinod.koul@intel.com>
> > 
> > Now the question is whether we need all codes.
> > For example, the bus reset isn't needed for Intel chips but it's a
> > workaround for old AMD chips.  Also, polling and single_cmd fallbacks
> > are also for buggy chips, and I don't think we'd need them for SKL.
> I dont have a reason to think this is required
> > 
> > The rirb_error flag can be removed and converted to the normal error
> > code propagation with the new code.  It's there just because the old
> > interface didn't give the error code in get_response op.  And, of
> > course, there are superfluous DSP loader for CA0132...
> okay, but the DSP loader code would be bought in for us. We need to use that
> to load code for the DSP. I was planning to send that out after this

Ah, if it's usable for you guys, then it's good to keep / reorg the
code.

> > You can find some code I wrote in a couple of weeks ago in
> > test/hda-dev2 branch of sound-unstable git tree.  I rebased it on top
> > of hda-regmap branch now, so it's mostly clean.  There you can find
> > the subset of HDA controller codes that should be enough for a clean
> > controller driver implementation.
> > 
> > I don't mean that mine is necessarily the best.  But my point is that
> > we don't have to copy the whole in sound/hda.  Rather start from a
> > smaller and mandatory subset for the new driver, then integrate this
> > into the existing legacy driver.
> 
> Okay sounds okay to me. The current code set has lots of legacy so deciding
> which bits are required and which are not will take a while for us! Thanks
> for pointing them out. I will take the code from unstable on top of this
> series and see what else do we need to do.

Note that the commit is incomplete, lacking the whole description,
etc.  But you can grasp the idea behind it, at least.

> One question I have is regarding conventions to be adopted, do we need
> hdac_xxx everywhere, since I though hdac stands for hda codec.

It's hda "core".  I didn't want to have too lengthy names as a
prefix.


Takashi

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC v2 3/3] ALSA: hda: add hda controller to hda
  2015-03-25  8:31       ` Takashi Iwai
@ 2015-03-25 10:52         ` Vinod Koul
  0 siblings, 0 replies; 10+ messages in thread
From: Vinod Koul @ 2015-03-25 10:52 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: jeeja.kp, alsa-devel, lgirdwood

On Wed, Mar 25, 2015 at 09:31:22AM +0100, Takashi Iwai wrote:
> At Wed, 25 Mar 2015 13:31:41 +0530,
> Vinod Koul wrote:
> > 
> > On Wed, Mar 25, 2015 at 08:05:21AM +0100, Takashi Iwai wrote:
> > > At Wed, 25 Mar 2015 11:31:39 +0530,
> > > Vinod Koul wrote:
> > > > 
> > > > From: Jeeja KP <jeeja.kp@intel.com>
> > > > 
> > > > This adds hdac_controller into hda core.
> > > > 
> > > > Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
> > > > Signed-off-by: Vinod Koul <vinod.koul@intel.com>
> > > 
> > > Now the question is whether we need all codes.
> > > For example, the bus reset isn't needed for Intel chips but it's a
> > > workaround for old AMD chips.  Also, polling and single_cmd fallbacks
> > > are also for buggy chips, and I don't think we'd need them for SKL.
> > I dont have a reason to think this is required
> > > 
> > > The rirb_error flag can be removed and converted to the normal error
> > > code propagation with the new code.  It's there just because the old
> > > interface didn't give the error code in get_response op.  And, of
> > > course, there are superfluous DSP loader for CA0132...
> > okay, but the DSP loader code would be bought in for us. We need to use that
> > to load code for the DSP. I was planning to send that out after this
> 
> Ah, if it's usable for you guys, then it's good to keep / reorg the
> code.
> 
> > > You can find some code I wrote in a couple of weeks ago in
> > > test/hda-dev2 branch of sound-unstable git tree.  I rebased it on top
> > > of hda-regmap branch now, so it's mostly clean.  There you can find
> > > the subset of HDA controller codes that should be enough for a clean
> > > controller driver implementation.
> > > 
> > > I don't mean that mine is necessarily the best.  But my point is that
> > > we don't have to copy the whole in sound/hda.  Rather start from a
> > > smaller and mandatory subset for the new driver, then integrate this
> > > into the existing legacy driver.
> > 
> > Okay sounds okay to me. The current code set has lots of legacy so deciding
> > which bits are required and which are not will take a while for us! Thanks
> > for pointing them out. I will take the code from unstable on top of this
> > series and see what else do we need to do.
> 
> Note that the commit is incomplete, lacking the whole description,
> etc.  But you can grasp the idea behind it, at least.
Yes I am cherry-picking this branch now and modifying and trying to bring it
to some logical conslusion. We can keep adding on top of it.
Will be able to send by tomorrow or so

> > One question I have is regarding conventions to be adopted, do we need
> > hdac_xxx everywhere, since I though hdac stands for hda codec.
> 
> It's hda "core".  I didn't want to have too lengthy names as a
> prefix.
Sounds good

-- 
~Vinod

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2015-03-25 10:56 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-25  6:01 [RFC v2 0/3] ALSA: hda: add hda controller to hda core Vinod Koul
2015-03-25  6:01 ` [RFC v2 1/3] ALSA: hda: add HDA_MAX_CODECS Vinod Koul
2015-03-25  6:48   ` Takashi Iwai
2015-03-25  7:51     ` Vinod Koul
2015-03-25  6:01 ` [RFC v2 2/3] ALSA: hda: move common hda controller register defines up Vinod Koul
2015-03-25  6:01 ` [RFC v2 3/3] ALSA: hda: add hda controller to hda Vinod Koul
2015-03-25  7:05   ` Takashi Iwai
2015-03-25  8:01     ` Vinod Koul
2015-03-25  8:31       ` Takashi Iwai
2015-03-25 10:52         ` Vinod Koul

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.