Merge pull request #190 from tlauda/topic/interrupt_get_level

interrupt: arch_interrupt_get_level
diff --git a/src/audio/dai.c b/src/audio/dai.c
index 3e53566..9c2ed5f 100644
--- a/src/audio/dai.c
+++ b/src/audio/dai.c
@@ -596,7 +596,12 @@
 		break;
 	case COMP_TRIGGER_XRUN:
 		dd->xrun = 1;
-		/* fall through */
+		/* stop the DAI unconditionally */
+		dai_trigger(dd->dai, COMP_TRIGGER_STOP, dev->params.direction);
+		ret = dma_stop(dd->dma, dd->chan);
+		if (ret < 0)
+			return ret;
+		break;
 	case COMP_TRIGGER_PAUSE:
 	case COMP_TRIGGER_STOP:
 		wait_init(&dd->complete);
diff --git a/src/drivers/apl-ssp.c b/src/drivers/apl-ssp.c
index 1dd1386..70cb8af 100644
--- a/src/drivers/apl-ssp.c
+++ b/src/drivers/apl-ssp.c
@@ -149,6 +149,7 @@
 	uint32_t sample_width = 2;
 
 	bool inverted_frame = false;
+	bool cfs = false;
 	int ret = 0;
 
 	spin_lock(&ssp->lock);
@@ -215,10 +216,13 @@
 		break;
 	case SOF_DAI_FMT_CBS_CFS:
 		sscr1 |= SSCR1_SCFR;
+		cfs = true;
 		break;
 	case SOF_DAI_FMT_CBM_CFS:
 		sscr1 |= SSCR1_SCLKDIR;
 		/* FIXME: this mode has not been tested */
+
+		cfs = true;
 		break;
 	case SOF_DAI_FMT_CBS_CFM:
 		sscr1 |= SSCR1_SCFR | SSCR1_SFRMDIR;
@@ -255,6 +259,40 @@
 	mdivc = mn_reg_read(0x0);
 	mdivc |= 0x1;
 
+	/* Additional hardware settings */
+
+	/* Receiver Time-out Interrupt Disabled/Enabled */
+	sscr1 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_TINTE) ?
+		SSCR1_TINTE : 0;
+
+	/* Peripheral Trailing Byte Interrupts Disable/Enable */
+	sscr1 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_PINTE) ?
+		SSCR1_PINTE : 0;
+
+	/* Transmit data are driven at the same/opposite clock edge specified
+	 * in SSPSP.SCMODE[1:0]
+	 */
+	sscr2 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_SMTATF) ?
+		SSCR2_SMTATF : 0;
+
+	/* Receive data are sampled at the same/opposite clock edge specified
+	 * in SSPSP.SCMODE[1:0]
+	 */
+	sscr2 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_MMRATF) ?
+		SSCR2_MMRATF : 0;
+
+	/* Enable/disable the fix for PSP slave mode TXD wait for frame
+	 * de-assertion before starting the second channel
+	 */
+	sscr2 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_PSPSTWFDFD) ?
+		SSCR2_PSPSTWFDFD : 0;
+
+	/* Enable/disable the fix for PSP master mode FSRT with dummy stop &
+	 * frame end padding capability
+	 */
+	sscr2 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_PSPSRWFDFD) ?
+		SSCR2_PSPSRWFDFD : 0;
+
 #ifdef CONFIG_CANNONLAKE
 	if (!config->ssp.mclk_rate || config->ssp.mclk_rate > F_24000_kHz) {
 		trace_ssp_error("eci");
@@ -503,7 +541,21 @@
 		sscr0 |= SSCR0_MOD | SSCR0_FRDC(config->ssp.tdm_slots);
 
 		/* set asserted frame length */
-		frame_len = 1;
+		frame_len = 1; /* default */
+
+		if (cfs && ssp->params.frame_pulse_width > 0 &&
+			ssp->params.frame_pulse_width <=
+			SOF_DAI_INTEL_SSP_FRAME_PULSE_WIDTH_MAX) {
+			frame_len = ssp->params.frame_pulse_width;
+		}
+
+		/* frame_pulse_width must less or equal 38 */
+		if (ssp->params.frame_pulse_width >
+			SOF_DAI_INTEL_SSP_FRAME_PULSE_WIDTH_MAX) {
+			trace_ssp_error("efa");
+			ret = -EINVAL;
+			goto out;
+		}
 
 		/*
 		 * handle frame polarity, DSP_A default is rising/active high,
@@ -527,8 +579,21 @@
 		sscr0 |= SSCR0_MOD | SSCR0_FRDC(config->ssp.tdm_slots);
 
 		/* set asserted frame length */
-		frame_len = 1;
+		frame_len = 1; /* default */
 
+		if (cfs && ssp->params.frame_pulse_width > 0 &&
+			ssp->params.frame_pulse_width <=
+			SOF_DAI_INTEL_SSP_FRAME_PULSE_WIDTH_MAX) {
+			frame_len = ssp->params.frame_pulse_width;
+		}
+
+		/* frame_pulse_width must less or equal 38 */
+		if (ssp->params.frame_pulse_width >
+			SOF_DAI_INTEL_SSP_FRAME_PULSE_WIDTH_MAX) {
+			trace_ssp_error("efb");
+			ret = -EINVAL;
+			goto out;
+		}
 		/*
 		 * handle frame polarity, DSP_B default is rising/active high,
 		 * non-inverted(inverted_frame=0) -- active high(SFRMP=1),
diff --git a/src/drivers/dw-dma.c b/src/drivers/dw-dma.c
index d4f13bf..c5bbe19 100644
--- a/src/drivers/dw-dma.c
+++ b/src/drivers/dw-dma.c
@@ -484,19 +484,30 @@
 static int dw_dma_stop(struct dma *dma, int channel)
 {
 	struct dma_pdata *p = dma_get_drvdata(dma);
-	int  ret = 0;
+	int ret = 0;
+	int i = 0;
+	struct dw_lli2 *lli;
 	uint32_t flags;
 
 	spin_lock_irq(&dma->lock, flags);
 
 	trace_dma("DDi");
 
-	/* is channel stii active ? */
-	if ((dw_read(dma, DW_DMA_CHAN_EN) & (0x1 << channel))) {
-		trace_dma_error("ea0");
-		trace_error_value(channel);
+	dw_write(dma, DW_DMA_CHAN_EN, CHAN_DISABLE(channel));
+
+#if DW_USE_HW_LLI
+	for (i = 0; i < p->chan[channel].desc_count; i++) {
+		lli = p->chan[channel].lli;
+		lli->ctrl_hi &= ~DW_CTLH_DONE(1);
+		lli++;
 	}
 
+	dcache_writeback_region(p->chan[channel].lli,
+			sizeof(struct dw_lli2) * p->chan[channel].desc_count);
+#endif
+
+	dw_write(dma, DW_CLEAR_BLOCK, 0x1 << channel);
+
 	p->chan[channel].status = COMP_STATE_PREPARE;
 
 	spin_unlock_irq(&dma->lock, flags);
diff --git a/src/drivers/hda-dma.c b/src/drivers/hda-dma.c
index 948b990..f8fce18 100644
--- a/src/drivers/hda-dma.c
+++ b/src/drivers/hda-dma.c
@@ -44,7 +44,9 @@
 #include <sof/ipc.h>
 #include <sof/pm_runtime.h>
 #include <sof/wait.h>
+#include <sof/audio/format.h>
 #include <platform/dma.h>
+#include <platform/platform.h>
 #include <arch/cache.h>
 #include <uapi/ipc.h>
 
@@ -367,7 +369,8 @@
 	host_dma_reg_write(dma, channel, DGBS,  buffer_bytes);
 	host_dma_reg_write(dma, channel, DGBFPI,  0);
 	host_dma_reg_write(dma, channel, DGBSP,  period_bytes);
-	host_dma_reg_write(dma, channel, DGMBS,  period_bytes);
+	host_dma_reg_write(dma, channel, DGMBS,
+			ALIGN_UP(period_bytes, PLATFORM_HDA_BUFFER_ALIGNMENT));
 	host_dma_reg_write(dma, channel, DGLLPI,  0);
 	host_dma_reg_write(dma, channel, DGLPIBI,  0);
 
diff --git a/src/include/sof/audio/format.h b/src/include/sof/audio/format.h
index f00b6f9..67c1632 100644
--- a/src/include/sof/audio/format.h
+++ b/src/include/sof/audio/format.h
@@ -53,6 +53,13 @@
 #define MINUS_80DB_Q1_31     214748  /* 10^(-80/20) */
 #define MINUS_90DB_Q1_31      67909  /* 10^(-90/20) */
 
+/* Align the number to the nearest alignment value */
+#define ALIGN_UP(size, alignment) \
+	(((size) % (alignment) == 0) ? (size) : \
+	((size) - ((size) % (alignment)) + (alignment)))
+#define ALIGN_DOWN(size, alignment) \
+	((size) - ((size) % (alignment)))
+
 /* Compute the number of shifts
  * This will result in a compiler overflow error if shift bits are out of
  * range as INT64_MAX/MIN is greater than 32 bit Q shift parameter
diff --git a/src/include/sof/ssp.h b/src/include/sof/ssp.h
index b5e8175..e57aa84 100644
--- a/src/include/sof/ssp.h
+++ b/src/include/sof/ssp.h
@@ -134,9 +134,13 @@
 #elif defined CONFIG_APOLLOLAKE || defined CONFIG_CANNONLAKE \
 		|| defined CONFIG_HASWELL || defined CONFIG_BROADWELL
 #define SSCR2_TURM1		BIT(1)
+#define SSCR2_PSPSRWFDFD	BIT(3)
+#define SSCR2_PSPSTWFDFD	BIT(4)
 #define SSCR2_SDFD		BIT(14)
 #define SSCR2_SDPM		BIT(16)
 #define SSCR2_LJDFD		BIT(17)
+#define SSCR2_MMRATF		BIT(18)
+#define SSCR2_SMTATF		BIT(19)
 #endif
 
 
diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h
index 4cf569f..2cb246d 100644
--- a/src/include/uapi/ipc.h
+++ b/src/include/uapi/ipc.h
@@ -226,6 +226,23 @@
 #define SOF_DAI_FMT_INV_MASK		0x0f00
 #define SOF_DAI_FMT_MASTER_MASK		0xf000
 
+ /* ssc1: TINTE */
+#define SOF_DAI_INTEL_SSP_QUIRK_TINTE		(1 << 0)
+ /* ssc1: PINTE */
+#define SOF_DAI_INTEL_SSP_QUIRK_PINTE		(1 << 1)
+ /* ssc2: SMTATF */
+#define SOF_DAI_INTEL_SSP_QUIRK_SMTATF		(1 << 2)
+ /* ssc2: MMRATF */
+#define SOF_DAI_INTEL_SSP_QUIRK_MMRATF		(1 << 3)
+ /* ssc2: PSPSTWFDFD */
+#define SOF_DAI_INTEL_SSP_QUIRK_PSPSTWFDFD	(1 << 4)
+ /* ssc2: PSPSRWFDFD */
+#define SOF_DAI_INTEL_SSP_QUIRK_PSPSRWFDFD	(1 << 5)
+ /* here is the possibility to define others aux macros */
+
+
+#define SOF_DAI_INTEL_SSP_FRAME_PULSE_WIDTH_MAX		38
+
 /** \brief Types of DAI */
 enum sof_ipc_dai_type {
 	SOF_DAI_INTEL_NONE = 0,	/**< None */
@@ -259,8 +276,10 @@
 	uint32_t bclk_keep_active;
 	uint32_t fs_keep_active;
 
-	//uint32_t quirks; // FIXME: is 32 bits enough ?
+	uint16_t frame_pulse_width;
+	uint32_t quirks; // FIXME: is 32 bits enough ?
 
+	uint16_t padding;
 	/* private data, e.g. for quirks */
 	//uint32_t pdata[10]; // FIXME: would really need ~16 u32
 } __attribute__((packed));
diff --git a/src/platform/apollolake/include/platform/platform.h b/src/platform/apollolake/include/platform/platform.h
index d611a1c..c110068 100644
--- a/src/platform/apollolake/include/platform/platform.h
+++ b/src/platform/apollolake/include/platform/platform.h
@@ -41,6 +41,9 @@
 
 struct sof;
 
+/* DGMBS align value */
+#define PLATFORM_HDA_BUFFER_ALIGNMENT	0x20
+
 /* Host page size */
 #define HOST_PAGE_SIZE		4096
 #define PLATFORM_PAGE_TABLE_SIZE	256
diff --git a/src/platform/cannonlake/include/platform/platform.h b/src/platform/cannonlake/include/platform/platform.h
index 30f5580..a94465d 100644
--- a/src/platform/cannonlake/include/platform/platform.h
+++ b/src/platform/cannonlake/include/platform/platform.h
@@ -47,6 +47,9 @@
 #define PLATFORM_SSP_COUNT 3
 #define MAX_GPDMA_COUNT 2
 
+/* DGMBS align value */
+#define PLATFORM_HDA_BUFFER_ALIGNMENT	0x20
+
 /* Host page size */
 #define HOST_PAGE_SIZE		4096
 #define PLATFORM_PAGE_TABLE_SIZE	256