Merge commit '6157e899e21792885766c018a6c579122eea502d'

Merge commit corresponding to SOF v0.5 release.

BUG=b:112528390, b:110025789
TEST=cros deploy <BOARD> sof-topoogy and verify that the DSP
     boots on an octopus board.

Change-Id: I7c2837fc2563278f5e1ced999482b07f63eb7726
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..023e264
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,22 @@
+*.o
+*.in
+*~
+autom4te*
+*.Po
+*.swp
+Makefile
+config.*
+configure
+depcomp
+install-sh
+missing
+stamp-h1
+aclocal.m4
+compile
+ltmain.sh
+rimage/rimage
+rmbox/rmbox
+rwav/rwav
+*.tplg
+topology/*.conf
+topology/test/*.conf
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..12533d1
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,14 @@
+sudo: required
+
+language: c
+
+services:
+  - docker
+
+before_install:
+  - docker pull xiulipan/sof
+  - echo -e '#!/bin/bash \n./autogen.sh && ./configure && make' > quickbuild.sh
+  - chmod 755 quickbuild.sh
+
+script:
+  - docker run -it -v `pwd`:/home/sof/work/sof.git --user `id -u` xiulipan/sof ./quickbuild.sh
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..902f0e9
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,5 @@
+SUBDIRS = rmbox topology
+TESTDIR = topology/test
+
+tests:
+	$(MAKE) -C $(TESTDIR)
diff --git a/README b/README
new file mode 100644
index 0000000..a8f818b
--- /dev/null
+++ b/README
@@ -0,0 +1,42 @@
+Sound Open Firmware Tools
+=========================
+
+This is a collection of open source tools used to develop open source audio
+DSP firmwares for ALSA.
+
+Building and Installing
+=======================
+
+./autogen.sh (only needed first time)
+./configure
+make
+make install
+
+
+rimage
+======
+
+rimage is used to convert ELF executable firmware files to the firmware file
+formats used by the kernel drivers.
+
+e.g.
+
+rimage -i elf_file -o kernel_file -m machine
+
+rimage can also convert kernel firmware formats to flat binaries formats to
+assist in debugging :-
+
+e.g. convert to flat binary, then ELF then dissasemble
+
+rimage -i /lib/firmware/intel/reef-byt.ri -o image.bin -b -m byt
+
+xtensa-byt-elf-objcopy -I binary -O elf32-xtensa-le -B xtensa image.bin image.bin.elf
+
+xtensa-byt-elf-objdump -D image.bin.elf > image.dis.txt
+
+tests
+=====
+
+To generate all test configuration files:
+
+make tests
\ No newline at end of file
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..3b379b6
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+libtoolize -c --force
+aclocal -I m4 --install
+autoconf -Wall
+autoheader
+automake -a --copy --foreign --add-missing
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..0336378
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,36 @@
+
+AC_PREREQ([2.69])
+AC_INIT([sof-tools], [1.0.1])
+AM_INIT_AUTOMAKE([foreign])
+AC_CONFIG_SRCDIR([rmbox/rmbox.c])
+AC_CONFIG_HEADERS([config.h])
+AC_CHECK_HEADER([sof/uapi/abi.h])
+AC_CHECK_PROG([XARGS], xargs, "yes", "no", [$PATH])
+AM_CONDITIONAL(XARGS, test "$XARGS" = "yes")
+
+AC_CANONICAL_HOST
+
+dnl Initialize maintainer mode
+AM_MAINTAINER_MODE([enable])
+
+AC_PROG_CC
+
+AC_OUTPUT([
+	Makefile
+	rmbox/Makefile
+	topology/Makefile
+	topology/common/Makefile
+	topology/platform/Makefile
+	topology/platform/intel/Makefile
+	topology/platform/common/Makefile
+	topology/m4/Makefile
+	topology/sof/Makefile
+	topology/test/Makefile
+])
+
+echo "
+
+prefix:                        ${prefix}
+Compiler:                      ${CC}
+CFLAGS:                        ${CFLAGS}
+"
diff --git a/kmod_scripts/sof_bootloop.sh b/kmod_scripts/sof_bootloop.sh
new file mode 100755
index 0000000..da9296d
--- /dev/null
+++ b/kmod_scripts/sof_bootloop.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+MAXLOOPS=100
+COUNTER=0
+
+while [ $COUNTER -lt $MAXLOOPS ]; do
+    echo "test $COUNTER"
+    ./sof_bootone.sh
+    dmesg > boot_$COUNTER.bootlog
+    let COUNTER+=1
+done
diff --git a/kmod_scripts/sof_bootone.sh b/kmod_scripts/sof_bootone.sh
new file mode 100755
index 0000000..92071fa
--- /dev/null
+++ b/kmod_scripts/sof_bootone.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+dmesg -C
+./sof_remove.sh
+./sof_insert.sh
+sleep 1
+
+unset FW_BOOT
+unset ERROR
+FW_BOOT=$(dmesg | grep sof-audio | grep "boot complete")
+ERROR=$(dmesg | grep sof-audio | grep -v "DSP trace buffer overflow" | grep "error")
+TIMEOUT=$(dmesg | grep sof-audio | grep "ipc timed out")
+
+if [ ! -z "$ERROR" ] || [ -z "$FW_BOOT" ] || [ ! -z "$TIMEOUT" ]
+then
+    dmesg > boot_fail.log
+    echo "boot failed, see boot_fail.log for details"
+    exit 1
+else
+    echo "boot success"
+fi
+       
diff --git a/kmod_scripts/sof_insert.sh b/kmod_scripts/sof_insert.sh
new file mode 100755
index 0000000..6075310
--- /dev/null
+++ b/kmod_scripts/sof_insert.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+modprobe snd_soc_rt5670
+modprobe snd_soc_rt5645
+modprobe snd_soc_rt5651
+modprobe snd_soc_rt5640
+modprobe snd_soc_da7213
+modprobe snd_soc_pcm512x_i2c
+modprobe snd_soc_tdf8532
+modprobe snd_soc_rt274
+
+modprobe sof_acpi_dev
+modprobe sof_pci_dev
+
+
diff --git a/kmod_scripts/sof_remove.sh b/kmod_scripts/sof_remove.sh
new file mode 100755
index 0000000..8f0b49c
--- /dev/null
+++ b/kmod_scripts/sof_remove.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+remove_module() {
+
+    MODULE="$1"
+
+    if lsmod | grep "$MODULE" &> /dev/null ; then
+	echo "Removing $MODULE"
+	rmmod $MODULE
+    else
+	echo "skipping $MODULE, not loaded"
+    fi
+}
+
+remove_module sof_pci_dev
+remove_module sof_acpi_dev
+remove_module snd_soc_acpi_intel_match
+remove_module snd_sof_intel_byt
+remove_module snd_sof_intel_hsw
+remove_module snd_sof_intel_bdw
+remove_module snd_sof_intel_hda_common
+remove_module snd_sof_xtensa_dsp
+
+remove_module snd_soc_sst_bytcr_rt5640
+remove_module snd_soc_sst_bytcr_rt5651
+remove_module snd_soc_sst_cht_bsw_rt5645
+remove_module snd_soc_sst_cht_bsw_rt5670
+remove_module snd_soc_sst_byt_cht_da7213
+remove_module snd_soc_sst_bxt_pcm512x
+remove_module snd_soc_sst_bxt_tdf8532
+remove_module snd_soc_cnl_rt274
+remove_module snd_sof_nocodec
+remove_module snd_sof
+
+remove_module snd_soc_rt5670
+remove_module snd_soc_rt5645
+remove_module snd_soc_rt5651
+remove_module snd_soc_rt5640
+remove_module snd_soc_rl6231
+remove_module snd_soc_da7213
+remove_module snd_soc_pcm512x_i2c
+remove_module snd_soc_pcm512x
+remove_module snd_soc_tdf8532
+remove_module snd_soc_rt274
+remove_module snd_soc_acpi
diff --git a/logger/logger.c b/logger/logger.c
new file mode 100644
index 0000000..fbfd054
--- /dev/null
+++ b/logger/logger.c
@@ -0,0 +1,294 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include "/usr/local/include/sof/uapi/logging.h"
+
+#define CEIL(a, b) ((a+b-1)/b)
+
+/* elf signature params */
+#define SND_SOF_LOGS_SIG_SIZE	4
+#define SND_SOF_LOGS_SIG	"Logs"
+
+struct snd_sof_logs_header {
+	/* "Logs" */
+	unsigned char sig[SND_SOF_LOGS_SIG_SIZE];
+	/* address of log entries section */
+	uint32_t base_address;
+	/* amount of bytes following this header */
+	uint32_t data_length;
+	/* offset to first entry in this file */
+	uint32_t data_offset;
+};
+
+struct ldc_entry_header {			
+	uint32_t level;
+	uint32_t component_id;
+	uint32_t params_num;
+	uint32_t line_idx;
+	uint32_t file_name_len;	
+};
+
+struct ldc_entry {
+	struct ldc_entry_header header;
+	char *file_name;
+	uint32_t text_len;
+	char *text;
+	uint32_t *params;
+}; 
+
+struct dma_log {
+	struct log_entry_header header;
+	uint32_t address;
+};
+
+static int fetch_entry(FILE *f_ldc, FILE *f_dma, uint32_t base_address,
+	uint32_t data_offset, struct dma_log dma_log);
+static void print_table_header(void);
+static void print_entry_params(struct dma_log dma_log, struct ldc_entry);
+static void usage(char *name);
+
+static inline void print_table_header(void)
+{
+	fprintf(stdout, "%10s %8s %8s %14s %16s %24s\t%s\n", 
+		"ADDRESS", 
+		"CORE_ID", 
+		"LEVEL", 
+		"COMPONENT_ID", 
+		"TIMESTAMP", 
+		"FILE_NAME", 
+		"CONTENT");
+}
+							   			   
+static void print_entry_params(struct dma_log dma_log, 
+	struct ldc_entry entry)
+{
+	fprintf(stdout, "%10x %8u %8u %14u %16lu %20s:%u\t",
+		dma_log.address,
+		dma_log.header.core_id,
+		entry.header.level,
+		entry.header.component_id,
+		dma_log.header.timestamp,
+		entry.file_name,
+		entry.header.line_idx);
+	
+	switch (entry.header.params_num){
+	case 0:
+		fprintf(stdout, "%s", entry.text);
+		break;
+	case 1:
+		fprintf(stdout, entry.text, entry.params[0]);
+		break;
+	case 2:
+		fprintf(stdout, entry.text, entry.params[0],
+			entry.params[1]);
+		break;	
+	case 3:
+		fprintf(stdout, entry.text, entry.params[0], entry.params[1],
+			entry.params[2]);
+		break;
+	}
+	fprintf(stdout, "\n");
+}
+
+static void usage(char *name)

+{

+	fprintf(stdout, "Usage %s <file(s)>\n", name);

+	fprintf(stdout, "%s:\t Parse traces logs\n", name);

+	fprintf(stdout, "%s:\t -l *.ldc_file\t-d dma_dump_file\n", name);

+	exit(0);

+}
+
+
+static int fetch_entry(FILE *f_ldc, FILE *f_dma, uint32_t base_address,
+	uint32_t data_offset, struct dma_log dma_log)
+{
+
+	struct ldc_entry entry;
+	long int padding;
+
+	uint32_t entry_offset;
+	uint32_t text_len;
+
+	int ret;
+
+	entry.file_name = NULL;
+	entry.text = NULL;
+	entry.params = NULL;
+	
+	/* evaluate entry offset in input file */
+	entry_offset = dma_log.address - base_address;
+	
+	/* set file position to beginning of processed entry */
+	fseek(f_ldc, entry_offset + data_offset, SEEK_SET);
+	
+	/* fetching elf header params */
+	ret = fread(&entry.header, sizeof(entry.header), 1, f_ldc);
+	if (!ret) {
+		ret = -ferror(f_ldc);
+		goto out;
+	}
+	
+	entry.file_name = (char *) malloc(entry.header.file_name_len);
+	if (!entry.file_name){
+		fprintf(stderr, "error: can't allocate %d byte for "
+			"entry.file_name\n", entry.header.file_name_len);
+		ret = -ENOMEM;
+		goto out;
+	}
+	
+	ret = fread(entry.file_name, sizeof(char), entry.header.file_name_len,
+		f_ldc);
+	if (ret != entry.header.file_name_len) {
+		ret = -ferror(f_ldc);
+		goto out;
+	}
+
+	/* padding - sequences of chars are aligned to DWORDS */
+	fseek(f_ldc, CEIL(entry.header.file_name_len, sizeof(uint32_t)) *
+		sizeof(uint32_t) - entry.header.file_name_len, SEEK_CUR);
+	
+	/* fetching text length */
+	ret = fread(&entry.text_len, sizeof(entry.text_len), 1, f_ldc);
+	if (!ret) {
+		ret = -ferror(f_ldc);
+		goto out;
+	}
+	
+	/* fetching text */
+	entry.text = (char *) malloc(entry.text_len);
+	if (entry.text == NULL) {
+		fprintf(stderr, "error: can't allocate %d byte for "
+			"entry.text\n", entry.text_len);
+		ret = -ENOMEM;
+		goto out;
+	}
+	
+	ret = fread(entry.text, sizeof(char), entry.text_len, f_ldc);
+	if (ret != entry.text_len) {
+		ret = -ferror(f_ldc);
+		goto out;
+	}
+	
+	/* fetching entry params from dma dump */
+	entry.params = (uint32_t *) malloc(sizeof(uint32_t) *
+		entry.header.params_num);
+	ret = fread(entry.params, sizeof(uint32_t), entry.header.params_num, 
+		f_dma);
+	if (ret != entry.header.params_num) {
+		ret = -ferror(f_dma);
+		goto out;
+	}
+	
+	/* printing entry content */
+	print_entry_params(dma_log, entry);
+	
+	/* set f_ldc file position to the beginning */
+	rewind(f_ldc);
+	
+	ret = 0;
+out:
+	/* free alocated memory */
+	free(entry.params);
+	free(entry.text);
+	free(entry.file_name);
+
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	struct dma_log dma_log;
+	struct snd_sof_logs_header snd;
+
+	int ret;
+	int opt;
+
+	const char *ldc_dir = NULL; 
+	const char *dma_dump = NULL; 
+	
+	while ((opt = getopt(argc, argv, "l:d:")) != -1) {

+		switch (opt) {

+		case 'l':

+			ldc_dir = optarg;

+			break;

+		case 'd':

+			dma_dump = optarg;

+			break;

+		default:

+			usage(argv[0]);

+		}

+	}
+
+	if (!ldc_dir) {
+		fprintf(stderr, "error: invalid ldc file.\n");
+		return -EINVAL;
+	}
+	if (!dma_dump) {
+		fprintf(stderr, "error: invalid dma_dump file.\n");
+		return -EINVAL;
+	}
+
+	FILE *f_ldc = fopen(ldc_dir, "r");
+	FILE *f_dma = fopen(dma_dump, "r");
+
+	if (f_ldc == NULL) {
+		fprintf(stderr, "Error while opening %s. \n", ldc_dir);
+		ret = errno;
+		goto out;
+	}
+
+	if (f_dma == NULL) {
+		fprintf(stderr, "Error while opening %s. \n", dma_dump);
+		ret = errno;
+		goto out;
+	}
+
+	/* set file positions to the beginning */
+	rewind(f_ldc);
+	rewind(f_dma);
+
+	/* veryfing ldc signature */
+	ret = fread(&snd, sizeof(snd), 1, f_ldc);
+	if (!ret) {
+		ret = -ferror(f_ldc);
+		goto out;
+	}
+
+	if (strncmp(snd.sig, SND_SOF_LOGS_SIG, SND_SOF_LOGS_SIG_SIZE)) {
+		fprintf(stderr, "Error: Invalid ldc file signature. \n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	print_table_header();
+
+	while (!feof(f_dma)) {
+
+		/* getting entry parameters from dma dump */
+		ret = fread(&dma_log, sizeof(dma_log), 1, f_dma);
+		if (!ret) {
+			ret = -ferror(f_dma);
+			goto out;
+		}
+
+		/* checking log address */
+		if ((dma_log.address < snd.base_address) ||
+			(dma_log.address > (snd.base_address + snd.data_length)))
+			continue;
+
+		/* fetching entry from elf dump*/
+		ret = fetch_entry(f_ldc, f_dma, snd.base_address,
+			snd.data_offset, dma_log);
+		if (ret) goto out;
+	}
+
+	ret = 0;
+out:
+	if (f_dma) fclose(f_dma);
+	if (f_ldc) fclose(f_ldc);
+
+	return ret;
+}
diff --git a/rimage/keys/Makefile.am b/rimage/keys/Makefile.am
new file mode 100644
index 0000000..06fe307
--- /dev/null
+++ b/rimage/keys/Makefile.am
@@ -0,0 +1,9 @@
+install-data-local:
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(PEM_KEY_PREFIX); 
+	$(INSTALL_DATA) otc_private_key.pem $(PEM_KEY_PREFIX)
+	$(INSTALL_DATA) otc_public_key.pem $(PEM_KEY_PREFIX)
+
+EXTRA_DIST = \
+	otc_private_key.pem \
+	otc_public_key.pem
\ No newline at end of file
diff --git a/rimage/keys/README b/rimage/keys/README
new file mode 100644
index 0000000..3ece70c
--- /dev/null
+++ b/rimage/keys/README
@@ -0,0 +1,34 @@
+About
+=====
+
+Firmware binary signing is for audio DSP is mandatory on Intel products from
+Skylake onwards. i.e. no code signing on Baytrail, Cherrytrail, Braswell,
+Haswell and Broadwell but mandatory on Skylake, Kabylake, Apollolake and
+Cannonlake.
+
+rimage can now sign firmware binaries for Apollolake and Cannonlake targets.
+This is done automatically as part of the "make bin" part of the build.
+
+
+Key Pairs
+=========
+
+The key included here is the Intel OTC (Opensource Technology Center) community
+development key. It can be freely used by anyone and is intended for reference
+board makers and firmware developers.
+
+** This key is NOT intended for locking down firmware on end user production
+devices since the "private" key has been published here. A new key pair must
+be genrated for securing firmware ! **
+
+RSA Private and Public keys are generated as follows :-
+
+openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
+openssl rsa -pubout -in private_key.pem -out public_key.pem
+
+The public key needs to be programmed into the OEM Key manifest (cavsManifest0)
+within the BIOS in order to verify code signed with the private key. 
+Intel supplies tools to board makers to stitch the public key into the BIOS.
+
+The private key is used by rimage to sign the SOF binary. It should be kept
+secret and secure for production signing. 
\ No newline at end of file
diff --git a/rimage/keys/otc_private_key.pem b/rimage/keys/otc_private_key.pem
new file mode 100644
index 0000000..03ad749
--- /dev/null
+++ b/rimage/keys/otc_private_key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC5Q68ZJyiWWrXb
+TSjlj4I/UmgusmIfv5+MCtinahekLPasIvoBhmEAr/TBizlfhj2/VN4FKNsqy7HR
+QGn+iLhqnVrzpEVug4EQIpkFxTnycKMQPSDvpIqq8VL9pUCvKokSMub0oTCwoxjJ
+V81wJy+NE2AnamjtnuJEXqim9U5CGjsnVNSktv/YPbso/LYFjH658Fz5QGgWfbgi
+BPNFwMvemSFOIXw2J2B91ayP9ZJeI2tLyEP9EMeQqU3Gd8T5LfHIUmibpPFe1JDM
+s4HmIEs7Iay03EfwjEWLVd0P/fxv9I9YNTZAi+7o8IyrTNRHDsH55efW7V58GwfS
+66po4QCFAgMBAAECggEBALf7IlktTR47iRv2/WUz5hnyQWoWVmHHD6+oWc2wCzhM
+Os9pkLOQ+qYPF1ZZZ6mYi5uFsVKYZ0aRsM3oVRqkNdgS2m7YtObyC2q1oRdc7JX6
+C8Wlnx69XcQzEcK4qIsMB8Gd8UQBC3RvE79nxanaEFveYP/jqb5IqdVR19SuCYCU
+EZurwwAnYeLg0VSSdVQHSGVMlHkDwhgVAvp5NryPXhml51pT0gzUwnvJOsUcrc0m
+tqUa2yu7/Qju1/JtFL98RgW4x3mSo4TZO3B/d664pWPOxL72zCt7bD9s06ILZmga
+z1oMLMwTaNaeYIBaRvjmssKOqLXmDvfc415V82SwMYUCgYEA2p2At6acrD8Xx5GO
+GeCeUbZzm0Ke9zql1W+Diq89UroFX/i9XO9Mb/ZfwouC+5n3iLjyCG7jIaIwYAyV
+2qim9sINeieepM54HqYz0235nX5CqLHPDobYLn5tsbNYvXYBWiyjRppG+cnprMBk
+O6vLNXNc4sRemgbcmwT3sEYLLo8CgYEA2PInWZx0JoEXriEgefv/IZeyCjpaS9uH
+OOaPVAJTJPaaZhazA4ANV2bzrQAigiXbOgzPkXyldy7T7d/gHfVYnHbyhGwMEa6u
+WMnj5qFXPI0hYOOrJbqXofbfGkKC996eoQybnvE0WdIwscySIki1zAenE/5nVdCJ
+HLwK9xXMKasCgYA/ZxSQrsqbjgTYhVdgG+vuqOqoac7uxtyXpSrSSvaPCpJKfjp1
+PJW/lwW4x3tqewH2biUL2xUWiRJcmOnRK76YrDj6Z4k0JQljYjJ/rFKLobW1dTQm
+82a5PUOVGP2wnQvRWkbUUCQrh6q0xmuLfsyFqPqUbf090KWkc/Fd90KA8wKBgG6C
+q9jSAbi7ebyR02FQJJ6QD3l2UBjkMvWhPNGmfYQOuofWeEoIKMOlBevSbcGuVwYz
+EGkj/YXArOQ3borUN9c8ID2kbGF1ggpojVcmSLHnkmEwmDYX3rX6c5uE1gI9vMB9
+E6jbZbd7gqKPesFMGI9eNpXQugLUv4OLpmpHCEERAoGAMF5P9jSe3JirlZ7WaH7A
+I1I23L3oZfkmrcxP7B860k1ZLHDtx/MtWLkb609fq1Q2lqRuvdoaur1kW+Rv9IHS
+Db8cznu9jIz3OzmJ735lHDpomylzt0+nxL5rrUnoTyMsDK0kIWs03JhPYc0+S2Ip
+lkkvYQHB1eUUCxMnTgzWRr4=
+-----END PRIVATE KEY-----
diff --git a/rimage/keys/otc_public_key.pem b/rimage/keys/otc_public_key.pem
new file mode 100644
index 0000000..b8662bd
--- /dev/null
+++ b/rimage/keys/otc_public_key.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuUOvGScollq1200o5Y+C
+P1JoLrJiH7+fjArYp2oXpCz2rCL6AYZhAK/0wYs5X4Y9v1TeBSjbKsux0UBp/oi4
+ap1a86RFboOBECKZBcU58nCjED0g76SKqvFS/aVAryqJEjLm9KEwsKMYyVfNcCcv
+jRNgJ2po7Z7iRF6opvVOQho7J1TUpLb/2D27KPy2BYx+ufBc+UBoFn24IgTzRcDL
+3pkhTiF8NidgfdWsj/WSXiNrS8hD/RDHkKlNxnfE+S3xyFJom6TxXtSQzLOB5iBL
+OyGstNxH8IxFi1XdD/38b/SPWDU2QIvu6PCMq0zURw7B+eXn1u1efBsH0uuqaOEA
+hQIDAQAB
+-----END PUBLIC KEY-----
diff --git a/rmbox/Makefile.am b/rmbox/Makefile.am
new file mode 100644
index 0000000..bfeb184
--- /dev/null
+++ b/rmbox/Makefile.am
@@ -0,0 +1,4 @@
+bin_PROGRAMS = rmbox
+
+rmbox_SOURCES = \
+	rmbox.c
\ No newline at end of file
diff --git a/rmbox/rmbox.c b/rmbox/rmbox.c
new file mode 100644
index 0000000..913249b
--- /dev/null
+++ b/rmbox/rmbox.c
@@ -0,0 +1,422 @@
+/*
+ * mbox dump to debug log convertor.
+ *
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#define KNRM  "\x1B[0m"
+#define KRED  "\x1B[31m"
+
+// TODO: include all this stuff
+
+#define TRACE_CLASS_IRQ		(1 << 24)
+#define TRACE_CLASS_IPC		(2 << 24)
+#define TRACE_CLASS_PIPE	(3 << 24)
+#define TRACE_CLASS_HOST	(4 << 24)
+#define TRACE_CLASS_DAI		(5 << 24)
+#define TRACE_CLASS_DMA		(6 << 24)
+#define TRACE_CLASS_SSP		(7 << 24)
+#define TRACE_CLASS_COMP	(8 << 24)
+#define TRACE_CLASS_WAIT	(9 << 24)
+#define TRACE_CLASS_LOCK	(10 << 24)
+#define TRACE_CLASS_MEM		(11 << 24)
+#define TRACE_CLASS_MIXER	(12 << 24)
+#define TRACE_CLASS_BUFFER	(13 << 24)
+#define TRACE_CLASS_VOLUME	(14 << 24)
+#define TRACE_CLASS_SWITCH	(15 << 24)
+#define TRACE_CLASS_MUX		(16 << 24)
+#define TRACE_CLASS_SRC         (17 << 24)
+#define TRACE_CLASS_TONE        (18 << 24)
+#define TRACE_CLASS_EQ_FIR      (19 << 24)
+#define TRACE_CLASS_EQ_IIR      (20 << 24)
+#define TRACE_CLASS_SA          (21 << 24)
+#define TRACE_CLASS_DMIC        (22 << 24)
+#define TRACE_CLASS_POWER       (23 << 24)
+
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+
+#define TRACE_BLOCK_SIZE	8
+
+static inline char get_char(uint32_t val, int idx)
+{
+	char c = (val >> (idx * 8)) & 0xff;
+	if (c < '0' || c > 'z')
+		return '.';
+	else
+		return c;
+}
+
+static void usage(char *name)
+{
+	fprintf(stdout, "Usage %s <option(s)> <file(s)>\n", name);
+	fprintf(stdout, "%s:\t \t\t\tDisplay mailbox contents\n", name);
+	fprintf(stdout, "%s:\t -i infile -o outfile\tDump infile contents to outfile\n", name);
+	fprintf(stdout, "%s:\t -c\t\t\tSet timestamp clock in MHz\n", name);
+	fprintf(stdout, "%s:\t -s\t\t\tTake a snapshot of state\n", name);
+	fprintf(stdout, "%s:\t -t\t\t\tDisplay trace data\n", name);
+	exit(0);
+}
+
+static double to_usecs(uint64_t time, double clk)
+{
+	/* trace timestamp uses CPU system clock at default 25MHz ticks */
+	// TODO: support variable clock rates
+	return (double)time / clk;
+}
+
+static void show_trace(uint64_t val, uint64_t addr, uint64_t *timestamp, double clk)
+{
+	const char *trace;
+	uint32_t class;
+	uint64_t delta = val - *timestamp;
+	double fdelta = to_usecs(delta, clk);
+	double us = 0.0f;
+
+	/* timestamp or value ? */
+	if ((addr % (TRACE_BLOCK_SIZE * 2)) == 0) {
+
+		delta = val - *timestamp;
+		fdelta = to_usecs(delta, clk);
+
+		/* 64-bit timestamp */
+		us = to_usecs(val, clk);
+
+		/* empty data ? */
+		if (val == 0) {
+			*timestamp = 0;
+			return;
+		}
+
+		/* detect wrap around */
+		if (fdelta < 1000.0 * 1000.0 * 1000.0)
+			printf("0x%lx [%6.6f]\tdelta [%6.6f]\t", addr,
+				us / 1000000.0 , fdelta / 1000000.0);
+		else
+			printf("0x%lx [%6.6f]\tdelta [********]\t", addr,
+				us / 1000000.0);
+
+		*timestamp = val;
+		return;
+	} else if (*timestamp == 0)
+		return;
+
+	/* check for printable values - otherwise it's a value */
+	if (!isprint((char)(val >> 16)) || !isprint((char)(val >> 8)) || !isprint((char)val)) {
+		printf("value 0x%16.16lx\n", val);
+		return;
+	}
+
+	class = val & 0xff000000;
+	if (class == TRACE_CLASS_IRQ)
+		trace = "irq";
+	else if (class == TRACE_CLASS_IPC)
+		trace = "ipc";
+	else if (class == TRACE_CLASS_PIPE)
+		trace = "pipe";
+	else if (class == TRACE_CLASS_HOST)
+		trace = "host";
+	else if (class == TRACE_CLASS_DAI)
+		trace = "dai";
+	else if (class == TRACE_CLASS_DMA)
+		trace = "dma";
+	else if (class == TRACE_CLASS_SSP)
+		trace = "ssp";
+	else if (class == TRACE_CLASS_COMP)
+		trace = "comp";
+	else if (class == TRACE_CLASS_WAIT)
+		trace = "wait";
+	else if (class == TRACE_CLASS_LOCK)
+		trace = "lock";
+	else if (class == TRACE_CLASS_MEM)
+		trace = "mem";
+	else if (class == TRACE_CLASS_MIXER)
+		trace = "mixer";
+	else if (class == TRACE_CLASS_BUFFER)
+		trace = "buffer";
+	else if (class == TRACE_CLASS_VOLUME)
+		trace = "volume";
+	else if (class == TRACE_CLASS_SWITCH)
+		trace = "switch";
+	else if (class == TRACE_CLASS_MUX)
+		trace = "mux";
+	else if (class == TRACE_CLASS_SRC)
+		trace = "src";
+	else if (class == TRACE_CLASS_TONE)
+		trace = "tone";
+	else if (class == TRACE_CLASS_EQ_FIR)
+		trace = "eq-fir";
+	else if (class == TRACE_CLASS_EQ_IIR)
+		trace = "eq-iir";
+	else if (class == TRACE_CLASS_SA)
+		trace = "sa";
+	else if (class == TRACE_CLASS_DMIC)
+		trace = "dmic";
+	else if (class == TRACE_CLASS_POWER)
+		trace = "pm";
+	else {
+		printf("value 0x%8.8x\n", (uint32_t)val);
+		return;
+	}
+
+	switch ((char)(val >> 16)) {
+	case 'e':
+	case 'E':
+	case 'x':
+	case 'X':
+		printf("%s%s %c%c%c%s\n", KRED, trace,
+		(char)(val >> 16), (char)(val >> 8), (char)val, KNRM);
+		break;
+	default:
+		printf("%s %c%c%c\n", trace,
+		(char)(val >> 16), (char)(val >> 8), (char)val);
+		break;
+	}
+}
+
+static int trace_read(const char *in_file, const char *out_file, double clk)
+{
+	int count, i;
+	FILE *in_fd = NULL, *out_fd = NULL;
+	char c, tmp[TRACE_BLOCK_SIZE] = {0};
+	uint64_t addr = 0, val, timestamp = 0;
+
+	in_fd = fopen(in_file, "r");
+	if (in_fd == NULL) {
+		fprintf(stderr, "error: unable to open %s for reading %d\n",
+			in_file, errno);
+		return -EIO;
+	}
+
+	if (out_file == NULL)
+		goto trace;
+
+	out_fd = fopen(out_file, "w");
+	if (out_fd == NULL) {
+		fprintf(stderr, "error: unable to open %s for writing %d\n",
+			out_file, errno);
+	}
+
+trace:
+	fprintf(stdout, "using %2.2fMHz timestamp clock\n", clk);
+
+	while (1) {
+		count = fread(&tmp[0], 1, TRACE_BLOCK_SIZE, in_fd);
+		if (count != TRACE_BLOCK_SIZE)
+			break;
+
+		val = *((uint64_t*)tmp);
+
+		for (i = 0; i < TRACE_BLOCK_SIZE / 2; i++) {
+			c = tmp[i];
+			tmp[i] = tmp[TRACE_BLOCK_SIZE - i - 1];
+			tmp[TRACE_BLOCK_SIZE - i - 1] = c;
+		}
+
+		show_trace(val, addr, &timestamp, clk);
+
+		if (out_fd) {
+			count = fwrite(&tmp[0], 1, TRACE_BLOCK_SIZE, out_fd);
+			if (count != TRACE_BLOCK_SIZE)
+				break;
+		}
+
+		addr += TRACE_BLOCK_SIZE;
+	}
+
+	fclose(in_fd);
+	if (out_fd)
+		fclose(out_fd);
+
+	return 0;
+}
+
+static void show_data(uint32_t val, uint32_t addr)
+{
+	printf("data: 0x%x = \t0x%8.8x \t(%8.8d) \t|%c%c%c%c|\n",
+					(unsigned int)addr,
+					val, val,
+					get_char(val, 3), get_char(val, 2),
+					get_char(val, 1), get_char(val, 0));
+}
+
+
+static const char *debugfs[] = {
+	"dmac0", "dmac1", "ssp0", "ssp1",
+	"ssp2", "iram", "dram", "shim",
+	"mbox", "etrace",
+};
+
+static int snapshot(const char *name)
+{
+	const char *path = "/sys/kernel/debug/sof";
+	uint32_t val, addr;
+	char pinname[64], poutname[64], buffer[128];
+	FILE *in_fd, *out_fd;
+	int i, count;
+
+	if (name == NULL) {
+		fprintf(stderr, "error: need snapshot name\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(debugfs); i++) {
+
+		sprintf(pinname, "%s/%s", path, debugfs[i]);
+		sprintf(poutname, "%s.%s.txt", name, debugfs[i]);
+
+		/* open debugfs for reading */
+		in_fd = fopen(pinname, "r");
+		if (in_fd == NULL) {
+			fprintf(stderr, "error: unable to open %s for reading %d\n",
+				pinname, errno);
+			continue;
+		}
+
+		/* open outfile for reading */
+		out_fd = fopen(poutname, "w");
+		if (out_fd == NULL) {
+			fprintf(stderr, "error: unable to open %s for writing %d\n",
+				poutname, errno);
+			fclose(in_fd);
+			continue;
+		}
+
+		fprintf(stdout, "processing %s...\n", pinname);
+		addr = 0;
+
+		while (1) {
+			count = fread(&val, 1, 4, in_fd);
+			if (count != 4)
+				break;
+
+			sprintf(buffer, "0x%6.6x: 0x%8.8x\n", addr, val);
+
+			count = fwrite(buffer, 1, strlen(buffer), out_fd);
+
+			addr += 4;
+		}
+
+		fclose(in_fd);
+		fclose(out_fd);
+	}
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int opt, count, trace = 0;
+	const char * out_file = NULL, *in_file = NULL;
+	FILE *in_fd = NULL, *out_fd = NULL;
+	char c, tmp[8] = {0};
+	uint64_t addr = 0, val, timestamp = 0, align = 4, i;
+	double clk = 19.2;
+
+	while ((opt = getopt(argc, argv, "ho:i:s:m:c:t")) != -1) {
+		switch (opt) {
+		case 'o':
+			out_file = optarg;
+			break;
+		case 'i':
+			in_file = optarg;
+			break;
+		case 't':
+			trace = 1;
+			break;
+		case 'c':
+			clk = atof(optarg);
+			break;
+		case 's':
+			return snapshot(optarg);
+		case 'h':
+		default: /* '?' */
+			usage(argv[0]);
+		}
+	}
+
+	/* trace requested ? */
+	if (trace)
+		return trace_read("/sys/kernel/debug/sof/trace",
+			out_file, clk);
+
+	/* default option with no infile is to dump errors/debug data */
+	if (in_file == NULL) {
+		fprintf(stdout, "\nError log:\n");
+		return trace_read("/sys/kernel/debug/sof/etrace",
+			out_file, clk);
+	}
+
+	/* open infile for reading */
+	in_fd = fopen(in_file, "r");
+	if (in_fd == NULL) {
+		fprintf(stderr, "error: unable to open %s for reading %d\n",
+			in_file, errno);
+		return -EIO;
+	}
+
+	/* open outfile for writing */
+	if (out_file == NULL)
+		goto convert;
+
+	out_fd = fopen(out_file, "w");
+	if (out_fd == NULL) {
+		fprintf(stderr, "error: unable to open %s for writing %d\n",
+			out_file, errno);
+		fclose(in_fd);
+		return -EIO;
+	}
+
+	/* start to converting mailbox */
+convert:
+	fprintf(stdout, "using %2.2fMHz timestamp clock\n", clk);
+
+	while (1) {
+		count = fread(&tmp[0], 1, align, in_fd);
+		if (count != align)
+			break;
+
+		val = *((uint64_t*)tmp);
+
+		for (i = 0; i < align / 2; i++) {
+			c = tmp[i];
+			tmp[i] = tmp[align - i - 1];
+			tmp[align - i - 1] = c;
+		}
+
+		show_data(val, addr);
+
+		if (out_fd) {
+			count = fwrite(&tmp[0], 1, align, out_fd);
+			if (count != align)
+				break;
+		}
+
+		addr += align;
+	}
+
+	/* close files */
+	fclose(in_fd);
+	if (out_fd)
+		fclose(out_fd);
+
+	return 0;
+}
diff --git a/test/README b/test/README
new file mode 100644
index 0000000..488005a
--- /dev/null
+++ b/test/README
@@ -0,0 +1,64 @@
+SOF Audio Processing Components Tests
+=====================================
+
+This is a set of test scripts to test that performance requirements
+are met. The tests are currently for measured audio objective quality
+parameters. The used criteria for performance is only an initial
+assumption and need to be adjusted for various applications needs.
+
+The scripts support currently support the next list of objective
+quality parameters. The test scripts need Matlab(R) [2] or GNU Octave
+scientific programming language [3].
+
+	- Gain
+	- Frequency Response
+	- THD+N vs. Frequency
+	- Dynamic Range
+	- Attenuation of Alias Products
+	- Attenuation of Image Products
+
+Note: The metric is an effort to follow AES17 [1] recommendation for
+parameters and test procedures. This was created to help developers to
+quickly check their work but has not been verified to be
+compliant. Professional equipment and formal calibration process is
+recommended for professional applications where both accurate absolute
+and relative metric is needed.
+
+Note: The test bench uses by default raw binary data files. It is
+possible to convert with SoX (v14.4.1) [4] the raw data to e.g. wav
+format for other audio tools and subjective listening.
+
+$ sox -b 32 -c 2 -r 48000 -L -e signed-integer fr_test_out.raw fr_test_out.wav
+
+For debugging purposes it is possible to switch from test scripts the
+test vectors format to txt for easy manual data creation and
+inspection.
+
+
+Tests for component SRC
+-----------------------
+
+The top level shell script to launch tests is src_test.sh. See script
+src_run.sh for assumed install location of SOF host test bench
+executable and component libraries. Exit code 0 indicates success and
+exit code 1 indicates failed test cases.
+
+The default in/out rates matrix to test is defined in the beginning of
+script src_test.m. The matrix can be also passed from calling function
+src_test_top.m if need.
+
+The key objective quality parameters requiremements are in the
+beginning of script src_test.m as well under comment Generic test
+pass/fail criteria.
+
+Test run creates plots into directory "plots". Brief text format
+reports are placed to directory "reports".
+
+
+References
+----------
+
+[1]	AES17-1015 standard, http://www.aes.org/publications/standards/search.cfm?docID=21
+[2]	Matlab(R), https://www.mathworks.com/products/matlab.html
+[3]	GNU Octave, https://www.gnu.org/software/octave/
+[4]	SoX - Sound eXchange, http://sox.sourceforge.net/
diff --git a/test/src_run.sh b/test/src_run.sh
new file mode 100755
index 0000000..670dc44
--- /dev/null
+++ b/test/src_run.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+# SRC specifics
+COMP=src
+BITS_IN=$1
+BITS_OUT=$2
+FS1=$3
+FS2=$4
+FN_IN=$5
+FN_OUT=$6
+
+# The HOST_ROOT path need to be retrived from SOFT .configure command
+HOST_ROOT=../../host-root
+HOST_EXE=$HOST_ROOT/bin/testbench
+HOST_LIB=$HOST_ROOT/lib
+
+# Topology
+INFMT=s${BITS_IN}le
+OUTFMT=s${BITS_IN}le
+MCLK=24576k
+TPLG=../topology/test/test-playback-ssp2-mclk-0-I2S-${COMP}-${INFMT}-${OUTFMT}-48k-${MCLK}-nocodec.tplg
+
+# If binary test vectors
+if [ ${FN_IN: -4} == ".raw" ]; then
+    CMDFMT="-b S${BITS_IN}_LE"
+else
+    CMDFMT=""
+fi
+
+# Run command
+CMD0=$HOST_EXE
+CMD1="-d -r $FS1 -R $FS2 -i $FN_IN -o $FN_OUT -t $TPLG -a src=libsof_${COMP}.so $CMDFMT"
+CMD="$CMD0 $CMD1"
+export LD_LIBRARY_PATH=$HOST_LIB
+
+# Run test bench
+echo "Command: $CMD0"
+echo "Arg:     $CMD1"
+$CMD
diff --git a/test/src_test.m b/test/src_test.m
new file mode 100644
index 0000000..bad2206
--- /dev/null
+++ b/test/src_test.m
@@ -0,0 +1,609 @@
+function [n_fail, n_pass, n_na] = src_test(bits_in, bits_out, fs_in_list, fs_out_list)
+
+%%
+% src_test - test with SRC test bench objective audio quality parameters
+%
+% src_test(bits_in, bits_out, fs_in, fs_out)
+%
+% bits_in  - input word length
+% bits_out - output word length
+% fs_in    - vector of rates in
+% fs_out   - vector of rates out
+%
+% A default in-out matrix with 32 bits data is tested if the
+% paremeters are omitted.
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+addpath('std_utils');
+addpath('test_utils');
+addpath('../tune/src');
+mkdir_check('plots');
+mkdir_check('reports');
+
+%% Defaults for call parameters
+if nargin < 1
+	bits_in = 32;
+end
+if nargin < 2
+	bits_out = 32;
+end
+if nargin < 3
+        fs_in_list = [8e3 11025 12e3 16e3 18900 22050 24e3 32e3 44100 48e3 ...
+			  64e3 88.2e3 96e3 176400 192e3];
+end
+if nargin < 4
+	fs_out_list = [8e3 11025 12e3 16e3 18900 22050 24e3 32e3 44100 48e3];
+end
+
+%% Generic test pass/fail criteria
+%  Note that AAP and AIP are relaxed a bit from THD+N due to inclusion
+%  of point Fs/2 to test. The stopband of kaiser FIR is not equiripple
+%  and there's sufficient amount of attnuation at higher frequencies to
+%  meet THD+N requirement.
+t.g_db_tol = 0.1;
+t.thdnf_db_max = -80;
+t.dr_db_min = 100;
+t.aap_db_max = -60;
+t.aip_db_max = -60;
+
+%% Defaults for test
+t.fmt = 'raw';         % Can be 'raw' (fast binary) or 'txt' (debug)
+t.nch = 2;             % Number of channels
+t.ch = 0;              % 1..nch. With value 0 test a randomly selected channel.
+t.bits_in = bits_in;   % Input word length
+t.bits_out = bits_out; % Output word length
+t.full_test = 1;       % 0 is quick check only, 1 is full set
+
+%% Show graphics or not. With visible plot windows Octave may freeze if too
+%  many windows are kept open. As workaround setting close windows to
+%  1 shows only flashing windows while the test proceeds. With
+%  visibility set to to 0 only console text is seen. The plots are
+%  exported into plots directory in png format and can be viewed from
+%  there.
+t.close_plot_windows = 0;  % Workaround for visible windows if Octave hangs
+t.visible = 'off';         % Use off for batch tests and on for interactive
+t.delete = 1;              % Set to 0 to inspect the audio data files
+
+%% Init for test loop
+n_test = 7; % We have next seven test cases for SRC
+n_fsi = length(fs_in_list);
+n_fso = length(fs_out_list);
+r.fs_in_list = fs_in_list;
+r.fs_out_list = fs_out_list;
+r.g = NaN(n_fsi, n_fso);
+r.dr = NaN(n_fsi, n_fso);
+r.fr_db = NaN(n_fsi, n_fso);
+r.fr_hz = NaN(n_fsi, n_fso, 2);
+r.fr3db_hz = NaN(n_fsi, n_fso);
+r.thdnf = NaN(n_fsi, n_fso);
+r.aap = NaN(n_fsi, n_fso);
+r.aip = NaN(n_fsi, n_fso);
+r.pf = NaN(n_fsi, n_fso, n_test);
+r.n_fail = 0;
+r.n_pass = 0;
+r.n_skipped = 0;
+r.n_na = 0;
+%% Loop all modes to test
+for b = 1:n_fso
+        for a = 1:n_fsi
+                v = -ones(n_test,1); % Set pass/fail test verdict to not executed
+                tn = 1;
+                t.fs1 = fs_in_list(a);
+                t.fs2 = fs_out_list(b);
+                v(1) = chirp_test(t);
+                if v(1) ~= -1 && t.full_test == 1
+                        %% Chirp was processed so this in/out Fs is supported
+                        [v(2), r.g(a,b)] = g_test(t);
+                        [v(3), r.fr_db(a,b), r.fr_hz(a,b,:), r.fr3db_hz(a,b)] = fr_test(t);
+                        [v(4), r.thdnf(a,b)] = thdnf_test(t);
+                        [v(5), r.dr(a,b)] = dr_test(t);
+                        [v(6), r.aap(a,b)] = aap_test(t);
+                        [v(7), r.aip(a,b)] = aip_test(t);
+                end
+                %% Done, store pass/fail
+                r.pf(a, b, :) = v;
+		if v(1) ~= -1
+			idx = find(v > 0);
+			r.n_fail = r.n_fail + length(idx);
+			idx = find(v == 0);
+			r.n_pass = r.n_pass + length(idx);
+			idx = find(v == -1);
+			r.n_skipped = r.n_skipped + length(idx);
+			idx = find(v == -2);
+			r.n_na = r.n_na + length(idx);
+		end
+        end
+end
+
+%% Print table with test summary: Gain
+fn = 'reports/g_src.txt';
+print_val(fn, fs_in_list, fs_out_list, r.g, r.pf, 'Gain dB');
+
+%% Print table with test summary: FR
+fn = 'reports/fr_src.txt';
+print_fr(fn, fs_in_list, fs_out_list, r.fr_db, r.fr_hz, r.pf);
+
+%% Print table with test summary: FR
+fn = 'reports/fr_src.txt';
+print_val(fn, fs_in_list, fs_out_list, r.fr3db_hz/1e3, r.pf, ...
+        'Frequency response -3 dB 0 - X kHz');
+
+%% Print table with test summary: THD+N vs. frequency
+fn = 'reports/thdnf_src.txt';
+print_val(fn, fs_in_list, fs_out_list, r.thdnf, r.pf, ...
+        'Worst-case THD+N vs. frequency');
+
+%% Print table with test summary: DR
+fn = 'reports/dr_src.txt';
+print_val(fn, fs_in_list, fs_out_list, r.dr, r.pf, ...
+        'Dynamic range dB (CCIR-RMS)');
+
+%% Print table with test summary: AAP
+fn = 'reports/aap_src.txt';
+print_val(fn, fs_in_list, fs_out_list, r.aap, r.pf, ...
+        'Attenuation of alias products dB');
+
+%% Print table with test summary: AIP
+fn = 'reports/aip_src.txt';
+print_val(fn, fs_in_list, fs_out_list, r.aip, r.pf, ...
+        'Attenuation of image products dB');
+
+
+%% Print table with test summary: pass/fail
+fn = 'reports/pf_src.txt';
+print_pf(fn, fs_in_list, fs_out_list, r.pf);
+
+fprintf('\n');
+fprintf('Number of passed tests = %d\n', r.n_pass);
+fprintf('Number of failed tests = %d\n', r.n_fail);
+fprintf('Number of non-applicable tests = %d\n', r.n_na);
+fprintf('Number of skipped tests = %d\n', r.n_skipped);
+
+
+if r.n_fail > 0 || r.n_pass < 1
+	fprintf('\nERROR: TEST FAILED!!!\n');
+else
+	fprintf('\nTest passed.\n');
+end
+
+n_fail = r.n_fail;
+n_pass = r.n_pass;
+n_na = r.n_na;
+
+end
+
+
+%%
+%% Test execution with help of common functions
+%%
+
+function [fail, g_db] = g_test(t)
+
+%% Reference: AES17 6.2.2 Gain
+test = test_defaults_src(t);
+prm = src_param(t.fs1, t.fs2, test.coef_bits);
+test.fu = prm.c_pb*min(t.fs1,t.fs2);
+test.g_db_tol = t.g_db_tol;
+test.g_db_expect = 0;
+
+%% Create input file
+test = g_test_input(test);
+
+%% Run test
+test = test_run_src(test, t);
+
+%% Measure
+test.fs = t.fs2;
+test = g_test_measure(test);
+
+%% Get output parameters
+fail = test.fail;
+g_db = test.g_db;
+delete_check(t.delete, test.fn_in);
+delete_check(t.delete, test.fn_out);
+
+end
+
+function [fail, pm_range_db, range_hz, fr3db_hz] = fr_test(t)
+
+%% Reference: AES17 6.2.3 Frequency response
+test = test_defaults_src(t);
+prm = src_param(t.fs1, t.fs2, test.coef_bits);
+
+test.rp_max = prm.rp_tot;      % Max. ripple +/- dB allowed
+test.f_lo = 20;                % For response reporting, measure from 20 Hz
+test.f_hi = min(t.fs1,t.fs2)*prm.c_pb;   % to designed filter upper frequency
+test.f_max = min(t.fs1/2, t.fs2/2); % Measure up to Nyquist frequency
+
+%% Create input file
+test = fr_test_input(test);
+
+%% Run test
+test = test_run_src(test, t);
+
+%% Measure
+test.fs = t.fs2;
+test = fr_test_measure(test);
+
+fail = test.fail;
+pm_range_db = test.rp;
+range_hz = [test.f_lo test.f_hi];
+fr3db_hz = test.fr3db_hz;
+delete_check(t.delete, test.fn_in);
+delete_check(t.delete, test.fn_out);
+
+%% Print
+src_test_result_print(t, 'Frequency response', 'FR', test.ph);
+
+end
+
+function [fail, thdnf] = thdnf_test(t)
+
+%% Reference: AES17 6.3.2 THD+N ratio vs. frequency
+test = test_defaults_src(t);
+
+prm = src_param(t.fs1, t.fs2, test.coef_bits);
+test.f_start = 20;
+test.f_end = prm.c_pb*min(t.fs1, t.fs2);
+test.fu = prm.c_pb*min(t.fs1, t.fs2);
+%test.f_end = 0.4535*min(t.fs1, t.fs2);
+%test.fu = 0.4535*min(t.fs1, t.fs2);
+
+%% Create input file
+test = thdnf_test_input(test);
+
+%% Run test
+test = test_run_src(test, t);
+
+%% Measure
+test.fs = t.fs2;
+test.thdnf_max = t.thdnf_db_max;
+test = thdnf_test_measure(test);
+thdnf = max(max(test.thdnf));
+fail = test.fail;
+delete_check(t.delete, test.fn_in);
+delete_check(t.delete, test.fn_out);
+
+%% Print
+src_test_result_print(t, 'THD+N ratio vs. frequency', 'THDNF');
+
+end
+
+function [fail, dr_db] = dr_test(t)
+
+%% Reference: AES17 6.4.1 Dynamic range
+test = test_defaults_src(t);
+test.dr_db_min = t.dr_db_min;
+
+%% Create input file
+test = dr_test_input(test);
+
+%% Run test
+test = test_run_src(test, t);
+
+%% Measure
+test.fs = t.fs2;
+test = dr_test_measure(test);
+
+%% Get output parameters
+fail = test.fail;
+dr_db = test.dr_db;
+delete_check(t.delete, test.fn_in);
+delete_check(t.delete, test.fn_out);
+
+end
+
+
+function [fail, aap_db] = aap_test(t)
+
+%% Reference: AES17 6.6.6 Attenuation of alias products
+test = test_defaults_src(t);
+test.aap_max = t.aap_db_max;
+
+if t.fs1 <= t.fs2
+        %% Internal rate must be lower than input
+        fail = -2;
+        aap_db = NaN;
+        return;
+end
+
+test.f_start = 0.5*t.fs1;
+test.f_end = 0.5*t.fs2;
+
+%% Create input file
+test = aap_test_input(test);
+
+%% Run test
+test = test_run_src(test, t);
+
+%% Measure
+test.fs = t.fs2;
+test = aap_test_measure(test);
+aap_db = test.aap;
+fail = test.fail;
+delete_check(t.delete, test.fn_in);
+delete_check(t.delete, test.fn_out);
+
+%% Print
+src_test_result_print(t, 'Attenuation of alias products', 'AAP');
+
+end
+
+function [fail, aip_db] = aip_test(t)
+
+%% Reference: AES17 6.6.7 Attenuation of image products
+test = test_defaults_src(t);
+test.aip_max = t.aip_db_max;
+if t.fs1 >= t.fs2
+        %% Internal rate must be higher than input
+        fail = -2;
+        aip_db = NaN;
+        return;
+%%
+end
+
+%% Create input file
+test.f_end = t.fs1/2;
+test = aip_test_input(test);
+
+%% Run test
+test = test_run_src(test, t);
+
+%% Measure
+test.fs = t.fs2;
+test = aip_test_measure(test);
+aip_db = test.aip;
+fail = test.fail;
+delete_check(t.delete, test.fn_in);
+delete_check(t.delete, test.fn_out);
+
+%% Print
+src_test_result_print(t, 'Attenuation of image products', 'AIP');
+
+end
+
+%% Chirp spectrogram test. This is a visual check only. Aliasing is visible
+%  in the plot as additional freqiencies than main linear up sweep. The aliasing
+%  can be a line, few lines, or lattice pattern depending the SRC conversion
+%  to test. The main sweep line should be steady level and extend from near
+%  zero freqeuncy to near Nyquist (Fs/2).
+
+function fail = chirp_test(t)
+
+fprintf('Spectrogram test %d -> %d ...\n', t.fs1, t.fs2);
+
+%% Create input file
+test = test_defaults_src(t);
+test = chirp_test_input(test);
+
+%% Run test
+test = test_run_src(test, t);
+
+%% Analyze
+test.fs = t.fs2;
+test = chirp_test_analyze(test);
+src_test_result_print(t, 'Chirp', 'chirpf');
+
+% Delete files unless e.g. debugging and need data to run
+delete_check(t.delete, test.fn_in);
+delete_check(t.delete, test.fn_out);
+
+fail = test.fail;
+end
+
+
+%% Some SRC test specific utility functions
+%%
+
+function test = test_defaults_src(t)
+test.fmt = t.fmt;
+test.bits_in = t.bits_in;
+test.bits_out = t.bits_out;
+test.nch = t.nch;
+test.ch = t.ch;
+test.fs = t.fs1;
+test.fs1 = t.fs1;
+test.fs2 = t.fs2;
+test.mask_f = [];
+test.mask_lo = [];
+test.mask_hi = [];
+test.coef_bits = 24; % No need to use actual word length in test
+test.visible = t.visible;
+end
+
+function test = test_run_src(test, t)
+test.ex = './src_run.sh';
+test.arg = { num2str(t.bits_in), num2str(t.bits_out), num2str(t.fs1), num2str(t.fs2), test.fn_in, test.fn_out};
+delete_check(1, test.fn_out);
+test = test_run(test);
+end
+
+function src_test_result_print(t, testverbose, testacronym, ph)
+tstr = sprintf('%s SRC %d, %d', testverbose, t.fs1, t.fs2);
+if nargin > 3
+        title(ph, tstr);
+else
+        title(tstr);
+end
+pfn = sprintf('plots/%s_src_%d_%d.png', testacronym, t.fs1, t.fs2);
+% The print command caused a strange error with __osmesa_print__
+% so disable it for now until solved.
+%print(pfn, '-dpng');
+if t.close_plot_windows
+	close all;
+end
+end
+
+%% The next are results printing functions
+
+function  print_val(fn, fs_in_list, fs_out_list, val, pf, valstr)
+n_fsi = length(fs_in_list);
+n_fso = length(fs_out_list);
+fh = fopen(fn,'w');
+fprintf(fh,'\n');
+fprintf(fh,'SRC test result: %s\n', valstr);
+fprintf(fh,'%8s, ', 'in \ out');
+for a = 1:n_fso-1
+        fprintf(fh,'%8.1f, ', fs_out_list(a)/1e3);
+end
+fprintf(fh,'%8.1f', fs_out_list(n_fso)/1e3);
+fprintf(fh,'\n');
+for a = 1:n_fsi
+        fprintf(fh,'%8.1f, ', fs_in_list(a)/1e3);
+	for b = 1:n_fso
+                if pf(a,b,1) < 0
+                        cstr = 'x';
+                else
+                        if isnan(val(a,b))
+                                cstr = '-';
+                        else
+                                cstr = sprintf('%8.2f', val(a,b));
+                        end
+                end
+                if b < n_fso
+                        fprintf(fh,'%8s, ', cstr);
+                else
+                        fprintf(fh,'%8s', cstr);
+                end
+        end
+        fprintf(fh,'\n');
+end
+fclose(fh);
+type(fn);
+end
+
+function print_fr(fn, fs_in_list, fs_out_list, fr_db, fr_hz, pf)
+n_fsi = length(fs_in_list);
+n_fso = length(fs_out_list);
+fh = fopen(fn,'w');
+fprintf(fh,'\n');
+fprintf(fh,'SRC test result: Frequency response +/- X.XX dB (YY.Y kHz) \n');
+fprintf(fh,'%8s, ', 'in \ out');
+for a = 1:n_fso-1
+        fprintf(fh,'%12.1f, ', fs_out_list(a)/1e3);
+end
+fprintf(fh,'%12.1f', fs_out_list(n_fso)/1e3);
+fprintf(fh,'\n');
+for a = 1:n_fsi
+        fprintf(fh,'%8.1f, ', fs_in_list(a)/1e3);
+	for b = 1:n_fso
+                if pf(a,b,1) < 0
+                        cstr = 'x';
+                else
+                        cstr = sprintf('%4.2f (%4.1f)', fr_db(a,b), fr_hz(a,b,2)/1e3);
+                end
+                if b < n_fso
+                        fprintf(fh,'%12s, ', cstr);
+                else
+                        fprintf(fh,'%12s', cstr);
+                end
+        end
+        fprintf(fh,'\n');
+end
+fclose(fh);
+type(fn);
+end
+
+function print_fr3db(fn, fs_in_list, fs_out_list, fr3db_hz, pf)
+n_fsi = length(fs_in_list);
+n_fso = length(fs_out_list);
+fh = fopen(fn,'w');
+fprintf(fh,'\n');
+fprintf(fh,'SRC test result: Frequency response -3dB 0 - X.XX kHz\n');
+fprintf(fh,'%8s, ', 'in \ out');
+for a = 1:n_fso-1
+        fprintf(fh,'%8.1f, ', fs_out_list(a)/1e3);
+end
+fprintf(fh,'%8.1f', fs_out_list(n_fso)/1e3);
+fprintf(fh,'\n');
+for a = 1:n_fsi
+        fprintf(fh,'%8.1f, ', fs_in_list(a)/1e3);
+	for b = 1:n_fso
+                if pf(a,b,1) < 0
+                        cstr = 'x';
+                else
+                        cstr = sprintf('%4.1f', fr3db_hz(a,b)/1e3);
+                end
+                if b < n_fso
+                        fprintf(fh,'%8s, ', cstr);
+                else
+                        fprintf(fh,'%8s', cstr);
+                end
+        end
+        fprintf(fh,'\n');
+end
+fclose(fh);
+type(fn);
+end
+
+
+function print_pf(fn, fs_in_list, fs_out_list, pf)
+n_fsi = length(fs_in_list);
+n_fso = length(fs_out_list);
+fh = fopen(fn,'w');
+fprintf(fh,'\n');
+fprintf(fh,'SRC test result: Fails\n');
+fprintf(fh,'%8s, ', 'in \ out');
+for a = 1:n_fso-1
+        fprintf(fh,'%14.1f, ', fs_out_list(a)/1e3);
+end
+fprintf(fh,'%14.1f', fs_out_list(n_fso)/1e3);
+fprintf(fh,'\n');
+spf = size(pf);
+npf = spf(3);
+for a = 1:n_fsi
+        fprintf(fh,'%8.1f, ', fs_in_list(a)/1e3);
+	for b = 1:n_fso
+                if pf(a,b,1) < 0
+                        cstr = 'x';
+                else
+                        cstr = sprintf('%d', pf(a,b,1));
+                        for n=2:npf
+                                if pf(a,b,n) < 0
+                                        cstr = sprintf('%s/x', cstr);
+                                else
+                                        cstr = sprintf('%s/%d', cstr,pf(a,b,n));
+                                end
+                        end
+                end
+                if b < n_fso
+                        fprintf(fh,'%14s, ', cstr);
+                else
+                        fprintf(fh,'%14s', cstr);
+                end
+        end
+        fprintf(fh,'\n');
+end
+fclose(fh);
+type(fn);
+end
diff --git a/test/src_test.sh b/test/src_test.sh
new file mode 100755
index 0000000..84e88c9
--- /dev/null
+++ b/test/src_test.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# Copyright (c) 2017, Intel Corporation
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#   * Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+#   * Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#   * Neither the name of the Intel Corporation nor the
+#     names of its contributors may be used to endorse or promote products
+#     derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+#
+
+octave --no-gui src_test_top.m
+if [ $? -eq 0 ]; then
+    echo "Test passed."
+    exit 0
+else
+    echo "Test failed." >&2
+    exit 1
+fi
diff --git a/test/src_test_top.m b/test/src_test_top.m
new file mode 100644
index 0000000..a0bf826
--- /dev/null
+++ b/test/src_test_top.m
@@ -0,0 +1,42 @@
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+[n_fail, n_pass] = src_test(24, 24);
+if n_fail > 0 || n_pass < 1
+	fprintf('Error: SRC test with 24 bits data failed.\n');
+        quit(1)
+end
+[n_fail, n_pass] = src_test(32, 32);
+if n_fail > 0 || n_pass < 1
+	fprintf('Error: SRC test with 32 bits data failed.\n');
+        quit(1)
+end
+
+fprintf('Success: SRC test with 24 and 32 bits data passed.\n');
diff --git a/test/std_utils/aap_test_input.m b/test/std_utils/aap_test_input.m
new file mode 100644
index 0000000..0a969c6
--- /dev/null
+++ b/test/std_utils/aap_test_input.m
@@ -0,0 +1,103 @@
+function test = aap_test_input(test)
+
+%% t = aap_test_input(t)
+%
+% Create frequency sweep data file for playback & record on real device or
+% for algorithm simulation.
+%
+% Input parameters
+% t.f_start   - start frequency
+% t.f_end     - end frequency
+% t.fs        - sample rate
+% t.bits_in   - number of bits in signal
+% t.ch        - mix test signal to channel ch
+% t.nch       - total number of channels in data
+%
+% Output parameters
+% t.fn_in     - created input file name
+% t.fn_out    - proposed output file name for captured output
+% t.f         - frequencies in sweep
+% t.nf        - number of frequencies
+% t.tl        - tone length in seconds
+% t.ts        - tone start times
+% t.tr        - tone gain ramp length in seconds
+% t.ti        - ignore time from tone start and end, must be ti > tr
+% t.a         - tone amplitude (lin)
+% t.a_db      - tone amplitude (dB)
+% t.mark_t    - length of marker tone in seconds
+% t.mark_a    - amplitude max of marker tone (lin)
+% t.mark_a_db - amplitude max of marker tone (dB)
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.6.6 Attenuation of alias products
+%  http://www.aes.org/publications/standards/
+
+if nargin < 1
+        error('This function must be called with argunment.');
+end
+
+if test.ch == 0
+        test.ch = 1+round(rand(1,1)*(test.nch-1)); % Test random channel 1..Nch
+end
+
+fprintf('Using parameters Fstart=%d Hz, Fend=%d Hz, Fs=%.1f kHz, bits_in=%d, ch=%d, nch=%d\n', ...
+        test.f_start, test.f_end, test.fs, test.bits_in, test.ch, test.nch);
+
+
+test.fn_in = sprintf('aap_test_in.%s', test.fmt);
+test.fn_out = sprintf('aap_test_out.%s', test.fmt);
+f_first = 997;
+f_max = max(test.f_start, test.f_end);
+f_min = min(test.f_start, test.f_end);
+n_third = ceil(log(f_max/f_min)/log(2)*3); % max 1/3 octave step
+steps = max(n_third, 50); % Min 50 steps
+test.f = [f_first logspace(log10(test.f_start), log10(test.f_end), steps) ];
+
+%% Tone sweep parameters
+test.is = 20e-3; % Ignore signal from tone start
+test.ie = 20e-3; % Ignore signal from tone end
+test.tr = 10e-3; % Gain ramp time for tones
+test.sm = 3; % Seek start marker from 3s from start
+test.em = 3; % Seek end marker from 3s from end
+test.mt = 0.3; % Error if marker positions delta is greater than 0.3s
+test.tc = 20; % Min. 20 cycles of sine wave for a frequency
+t_min = 0.2;
+test.a_db = -20;
+test.a = 10^(test.a_db/20);
+% Use t_min or min cycles count as tone length
+test.tl = max(test.tc*1/min(test.f),t_min);
+
+%% Mix the input file for test and write output
+test = mix_sweep(test);
+
+end
diff --git a/test/std_utils/aap_test_measure.m b/test/std_utils/aap_test_measure.m
new file mode 100644
index 0000000..a61dadf
--- /dev/null
+++ b/test/std_utils/aap_test_measure.m
@@ -0,0 +1,77 @@
+function test = aap_test_measure(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.6.6 Attenuation of alias products
+%  http://www.aes.org/publications/standards/
+
+%% Load output file
+[x, nx] = load_test_output(test);
+if nx == 0
+        test.fail = 1;
+        return
+end
+
+%% Find sync
+[d, nt, nt_use, nt_skip] = find_test_signal(x, test);
+
+%% Measure
+win = hamming(nt_use);
+m0 = zeros(test.nf,1);
+for n=1:test.nf
+        fprintf('Measuring %.0f Hz ...\n', test.f(n));
+        i1 = d+(n-1)*nt+nt_skip;
+        i2 = i1+nt_use-1;
+        m0(n) = level_dbfs(x(i1:i2).*win);
+end
+
+%% Calculate levels relative to first 997 Hz frequency,
+% remove it from result, sort to ascinding order for plot
+m_ref = m0(1);
+test.m = m0(2:end)-m0(1);
+[test.f, idx] = sort(test.f(2:end));
+test.m = test.m(idx);
+test.aap = max(test.m); % Worst-case
+
+if test.aap > test.aap_max
+        test.fail = 1;
+else
+        test.fail = 0;
+end
+
+test.fh = figure('visible', test.visible);
+semilogx(test.f, test.m);
+grid on;
+xlabel('Frequency (Hz)');
+ylabel('Relative level (dB)');
+grid on;
+
+end
diff --git a/test/std_utils/aip_test_input.m b/test/std_utils/aip_test_input.m
new file mode 100644
index 0000000..a946c96
--- /dev/null
+++ b/test/std_utils/aip_test_input.m
@@ -0,0 +1,101 @@
+function test = aip_test_input(test)
+
+%% t = aap_test_input(t)
+%
+% Create frequency sweep data file for playback & record on real device or
+% for algorithm simulation.
+%
+% Input parameters
+% t.f_start   - start frequency
+% t.f_end     - end frequency
+% t.fs        - sample rate
+% t.bits_in   - number of bits in signal
+% t.ch        - mix test signal to channel ch
+% t.nch       - total number of channels in data
+%
+% Output parameters
+% t.fn_in     - created input file name
+% t.fn_out    - proposed output file name for captured output
+% t.f         - frequencies in sweep
+% t.nf        - number of frequencies
+% t.tl        - tone length in seconds
+% t.ts        - tone start times
+% t.tr        - tone gain ramp length in seconds
+% t.ti        - ignore time from tone start and end, must be ti > tr
+% t.a         - tone amplitude (lin)
+% t.a_db      - tone amplitude (dB)
+% t.mark_t    - length of marker tone in seconds
+% t.mark_a    - amplitude max of marker tone (lin)
+% t.mark_a_db - amplitude max of marker tone (dB)
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.6.7 Attenuation of image products
+%  http://www.aes.org/publications/standards/
+
+if nargin < 1
+        error('This function must be called with argument.');
+end
+
+if test.ch == 0
+        test.ch = 1+round(rand(1,1)*(test.nch-1)); % Test random channel 1..Nch
+end
+
+fprintf('Using parameters Fend=%d Hz, Fs=%.1f kHz, bits_in=%d, ch=%d, nch=%d\n', ...
+        test.f_end, test.fs, test.bits_in, test.ch, test.nch);
+
+test.fn_in = sprintf('aip_test_in.%s', test.fmt);
+test.fn_out = sprintf('aip_test_out.%s', test.fmt);
+f_first = 997;
+test.f_start = 20;
+f_min = min(test.f_start, test.f_end);
+f_max = max(test.f_start, test.f_end);
+test.fu = f_max;
+n_thirdoct = ceil(log(f_max/f_min)/log(2)*3); % max 1/3 octave step
+steps = n_thirdoct;
+test.f = [f_first logspace(log10(test.f_start), log10(test.f_end), steps) ];
+
+%% Tone sweep parameters
+test.is = 20e-3; % Ignore signal from tone start
+test.ie = 20e-3; % Ignore signal from tone end
+test.tr = 10e-3; % Gain ramp time for tones
+test.sm = 3; % Seek start marker from 3s from start
+test.em = 3; % Seek end marker from 3s from end
+test.mt = 0.1; % Error if marker positions delta is greater than 0.1s
+test.tl = 3;
+test.a_db = -20;
+test.a = 10^(test.a_db/20);
+
+%% Mix the input file for test and write output
+test = mix_sweep(test);
+
+end
diff --git a/test/std_utils/aip_test_measure.m b/test/std_utils/aip_test_measure.m
new file mode 100644
index 0000000..56aee93
--- /dev/null
+++ b/test/std_utils/aip_test_measure.m
@@ -0,0 +1,84 @@
+function test = aip_test_measure(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.6.7 Attenuation of image products
+%  http://www.aes.org/publications/standards/
+
+%% Load output file
+[x, nx] = load_test_output(test);
+if nx == 0
+        test.g_db = NaN;
+        test.fail = 1;
+        return
+end
+
+%% Find sync
+[d, nt, nt_use, nt_skip] = find_test_signal(x, test);
+
+%% Measure all test frequencies
+t_skip = 1.0;
+ml = zeros(test.nf,1);
+mn = zeros(test.nf,1);
+b_lpf = stdlpf_get(test.fu, test.fs); % Get LPF coef
+b_hpf = stdhpf_get(test.fu, test.fs); % Get HPF coef
+for n=1:test.nf
+        fprintf('Measuring %.0f Hz ...\n', test.f(n));
+        % Get notch coef for this frequency
+        [b_notch, a_notch] = stdnotch_get(test.f(n), test.fs);
+        i1 = d+(n-1)*nt+nt_skip;
+        i2 = i1+nt_use-1;
+        x_lpf = filter(b_lpf, 1, x(i1:i2)); % Standard LPF, need for 997 Hz only
+        x_notch = filter(b_notch, a_notch, x(i1:i2)); % Standard notch
+        x_hpf = filter(b_hpf, 1, x_notch); % Standard HPF
+        ml(n) = level_dbfs(x_lpf(round(t_skip*test.fs):end));
+        mn(n) = level_dbfs(x_hpf(round(t_skip*test.fs):end));
+end
+
+%% Calculate levels relative to first 997 Hz frequency,
+% remove it from result, sort to ascinding order for plot
+test.f = test.f(2:end);
+test.m = mn(2:end)-ml(1);
+test.aip = max(test.m); % Worst-case
+if test.aip > test.aip_max
+        test.fail = 1;
+else
+        test.fail = 0;
+end
+
+test.fh = figure('visible', test.visible);
+semilogx(test.f, test.m);
+grid on;
+xlabel('Frequency (Hz)');
+ylabel('Relative level (dB)');
+grid on;
+
+end
diff --git a/test/std_utils/dr_test_input.m b/test/std_utils/dr_test_input.m
new file mode 100644
index 0000000..396d7d0
--- /dev/null
+++ b/test/std_utils/dr_test_input.m
@@ -0,0 +1,91 @@
+function test = dr_test_input(test)
+
+%% t = dr_test_input(t)
+%
+% Create tone data file for playback & record on real device or
+% for algorithm simulation.
+%
+% Input parameters
+% t.fs        - sample rate
+% t.bits_in   - signal word length
+% t.ch        - mix test signal to channel ch
+% t.nch       - total number of channels in data
+%
+% Output parameters
+% t.fn_in     - created input file name
+% t.fn_out    - proposed output file name for captured output
+% t.f         - test signal frequency
+% t.tl        - tone length in seconds
+% t.ts        - tone start time
+% t.tr        - tone gain ramp length in seconds
+% t.ti        - ignore time from tone start and end, must be ti > tr
+% t.a         - tone amplitude (lin)
+% t.a_db      - tone amplitude (dB)
+% t.mark_t    - length of marker tone in seconds
+% t.mark_a    - amplitude max of marker tone (lin)
+% t.mark_a_db - amplitude max of marker tone (dB)
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.2.3 Frequency response
+
+if nargin < 1
+        fprintf('Warning, using default parameters!\n');
+        test.fs = 48e3; test.bits_in=32; test.ch=1; test.nch=1;
+end
+
+if test.ch == 0
+        test.ch = 1+round(rand(1,1)*(test.nch-1)); % Test random channel 1..Nch
+end
+
+fprintf('Using parameters Fs=%.1f, bits=%d, ch=%d, Nch=%d\n', ...
+        test.fs/1e3, test.bits_in, test.ch, test.nch );
+
+%% Test tone parameters
+test.fn_in = sprintf('dr_test_in.%s', test.fmt);
+test.fn_out = sprintf('dr_test_out.%s', test.fmt);
+test.f = 997;
+test.a_db = -60;
+test.a = 10^(test.a_db/20);
+test.is = 1.0; % Ignore signal from tone start
+test.ie = 20e-3; % Ignore signal from tone end
+test.tr = 10e-3; % Gain ramp time for tones
+test.sm = 3; % Seek start marker from 3s from start
+test.em = 3; % Seek end marker from 3s from end
+test.mt = 0.3; % Error if marker positions delta is greater than 0.3s
+test.tc = 25; % Min. 20 cycles of sine wave for a frequency
+test.tl = 3;  % 3 seconds tone
+
+%% Mix the input file for test and write output
+test = mix_sweep(test);
+
+end
diff --git a/test/std_utils/dr_test_measure.m b/test/std_utils/dr_test_measure.m
new file mode 100644
index 0000000..6e8634f
--- /dev/null
+++ b/test/std_utils/dr_test_measure.m
@@ -0,0 +1,76 @@
+function test = dr_test_measure(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Load output file
+[x, nx] = load_test_output(test);
+if nx == 0
+        test.dr_db = NaN;
+        test.fail = 1;
+        return
+end
+
+%% Find sync
+[d, nt, nt_use, nt_skip] = find_test_signal(x, test);
+
+%% Notch filter
+y0n = stdnotch(x, test.f, test.fs);
+
+%% CCIR-RMS weighting filter
+y0w = stdweight(y0n, test.fs);
+
+%% Trim sample by removing first 1s to let the notch to apply
+i1 = d+nt_skip;
+i2 = i1+nt_use-1;
+y = x(i1:i2);
+y_n = y0w(i1:i2);
+
+%% Gain, SNR
+level_in = test.a_db;
+level_out = level_dbfs(y);
+level_final = level_dbfs(y_n);
+test.dr_db = level_out-level_final-test.a_db;
+fprintf('DR = %5.1f dB\n', test.dr_db);
+if 0
+        plot(y);
+        hold on
+        plot(y_n,'g');
+        hold off
+end
+
+%% Check pass/fail
+test.fail = 0;
+if test.dr_db < test.dr_db_min
+        fprintf('Failed DR %f dB (min %f dB)\n', test.dr_db, test.dr_db_min);
+        test.fail = 1;
+end
+
+end
diff --git a/test/std_utils/fr_test_input.m b/test/std_utils/fr_test_input.m
new file mode 100644
index 0000000..5471bf7
--- /dev/null
+++ b/test/std_utils/fr_test_input.m
@@ -0,0 +1,123 @@
+function test = fr_test_input(test)
+
+%% t = fr_test_input(t)
+%
+% Create frequency sweep data file for playback & record on real device or
+% for algorithm simulation.
+%
+% Input parameters
+% t.f_max     - maximum frequency of sweep, set e.g. to 0.99*fs/2
+% t.fs        - sample rate
+% t.bits_in   - number of bits in signal
+% t.ch        - mix test signal to channel ch, e.g. set to [1 2] to measure
+%               two channels
+% t.nch       - total number of channels in data
+%
+% Output parameters
+% t.fn_in     - Created input file name
+% t.fn_out    - Proposed output file name for captured output
+% t.f_ref     - Reference frequency used to report deviation (997 Hz)
+% t.f_min     - Sweep start frequency
+% t.f         - Frequencies in sweep
+% t.is        - Ignore signal from tone start
+% t.ie        - Ignore signal from tone end
+% t.tr        - tone gain ramp length in seconds
+% t.sm        - Seek start marker this time length from start
+% t.em        - Seek end marker this time length from end
+% t.mt        - Error if marker positions delta is greater than this
+% t.tc        - Min cycles of sine wave per frequency
+% t.tl        - Tone length in seconds
+% t.a_db      - Tone amplitude (dB)
+% t.a         - Tone amplitude (lin)
+% t.nt        - Number of samples per tone
+% t.nf        - Number of frequencies
+% t.na        - Number of amplitudes
+% t.mark_t    - Length of marker tone in seconds
+% t.mark_a    - Amplitude max of marker tone (lin)
+% t.mark_a_db - Amplitude max of marker tone (dB)
+% t.ts        - Tone start times
+%
+% E.g.
+% t.fs=48e3; t.f_max=20e3; t.bits_in=16; t.ch=1; t.nch=2; t = fr_test_input(t);
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.2.3 Frequency response
+%  http://www.aes.org/publications/standards/
+
+if nargin < 1
+        fprintf('Warning, using default parameters!\n');
+        test.fs = 48e3; test.f_max = 0.99*test.fs/2; test.ch=1; test.nch=1;
+        test.bits_in=32;
+end
+
+if test.ch == 0
+        test.ch = 1+round(rand(1,1)*(test.nch-1)); % Test random channel 1..Nch
+end
+
+fprintf('Using parameters Fmax=%.1f kHz, Fs=%.1f, ch=%d, Nch=%d, bits_in=%d\n', ...
+        test.f_max/1e3, test.fs/1e3, test.ch, test.nch, test.bits_in);
+
+test.fn_in = sprintf('fr_test_in.%s', test.fmt);
+test.fn_out =  sprintf('fr_test_out.%s', test.fmt);
+test.f_ref = 997;
+test.f_min = 20;
+
+%% Use a dense frequency grid to see -3 dB point well
+n_oct = ceil(log(test.f_max/test.f_ref)/log(2)*35);
+f = logspace(log10(test.f_ref), log10(test.f_max), n_oct);
+c = f(1)/f(2);
+f_next = test.f_ref*c;
+while (f_next > test.f_min)
+        f = [f_next f];
+        f_next = f_next*c;
+end
+test.f = f;
+
+%% Tone sweep parameters
+test.is = 20e-3; % Ignore signal from tone start
+test.ie = 20e-3; % Ignore signal from tone end
+test.tr = 10e-3; % Gain ramp time for tones
+test.sm = 3; % Seek start marker from 3s from start
+test.em = 3; % Seek end marker from 3s from end
+test.mt = 0.1; % Error if marker positions delta is greater than 0.1s
+test.tc = 10; % Min. 10 cycles of sine wave for a frequency
+t_min = 0.2;
+% Use t_min or min cycles count as tone length
+test.tl = max(test.tc*1/min(f),t_min);
+test.a_db = -20;
+test.a = 10.^(test.a_db/20);
+
+%% Mix the input file for test and write output
+test = mix_sweep(test);
+
+end
diff --git a/test/std_utils/fr_test_measure.m b/test/std_utils/fr_test_measure.m
new file mode 100644
index 0000000..e7156fe
--- /dev/null
+++ b/test/std_utils/fr_test_measure.m
@@ -0,0 +1,173 @@
+function test = fr_test_measure(test)
+
+%% t = fr_test_measure(t)
+%
+% Measure frequency response from captured frequency sweep created by
+% fr_test_input() that sets most of the input struct fiels. The output
+% is read from file t.fn_out.
+%
+% Input parameters
+% t.f_lo    - Measure ripple start frequency
+% t.f_hi    - Measure ripple end frequency
+% t.rp_max  - Max. ripple +/- dB
+% t.mask_f  - Frequencies for mask
+% t.mask_lo - Upper limits of mask
+% t.mask_hi - Lower limits of mask
+%
+% Output parameters
+% t.m           - Measured frequency response
+% t.rp          - Measured ripple +/- dB
+% t.fr3db_hz    - Bandwidth in Hz for -3 dB attenuated response
+% t.fail        - Returns zero for passed
+% t.fh          - Figure handle
+% t.ph          - Plot handle
+%
+% E.g.
+% t.fs=48e3; t.f_max=20e3; t.bits_out=16; t.ch=1; t.nch=2; t=fr_test_input(t);
+% t.fn_out=t.fn_in; t.f_lo=20; t.f_hi=20e3; t.rp_max=[]; t.mask_f=[];
+% t=fr_test_measure(t);
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.2.3 Frequency response
+%  http://www.aes.org/publications/standards/
+
+[x, nx] = load_test_output(test);
+
+j = 1;
+for channel = test.ch
+
+        if nx == 0
+                test.rp(j) = NaN;
+                test.fr3db_hz(j) = NaN;
+                test.fail = 1;
+                return
+        end
+
+        %% Find sync
+        [d, nt, nt_use, nt_skip] = find_test_signal(x(:,j), test);
+
+        win = hamming(nt_use);
+        m0 = zeros(test.nf,1);
+        for n=1:test.nf
+                fprintf('Measuring %.0f Hz ...\n', test.f(n));
+                i1 = d+(n-1)*nt+nt_skip;
+                i2 = i1+nt_use-1;
+                m0(n) = level_dbfs(x(i1:i2,j).*win) -test.a_db;
+        end
+
+        %% Scale 997 Hz point as 0 dB
+        df = test.f - test.f_ref;
+        [~,i997] = min(abs(df));
+        m_offs = m0(i997);
+        test.m(:,j) = m0 - m_offs;
+
+        %% Check pass/fail
+        idx0 = find(test.f < test.f_hi);
+        idx1 = find(test.f(idx0) > test.f_lo);
+        range_db = max(test.m(idx1,j))-min(test.m(idx1,j));
+        test.rp(j) = range_db/2;
+        test.fail = 0;
+        if ~isempty(test.rp_max)
+                if test.rp > test.rp_max
+                        fprintf('Failed response +/- %f dBpp (max +/- %f dB)\n', ...
+                                test.rp, test.rp_max);
+                        test.fail = 1;
+                end
+        end
+
+        %% Find frequency response 3 dB 0-X Hz
+        idx3 = find(test.m(:,j) > -3);
+        test.fr3db_hz(j) = test.f(idx3(end));
+
+        %% Interpolate mask in logaritmic frequencies, check
+        if ~isempty(test.mask_f)
+                f_log = log(test.f);
+                mask_hi = interp1(log(test.mask_f), test.mask_hi(:,j), ...
+                        f_log, 'linear');
+                mask_lo = interp1(log(test.mask_f), test.mask_lo(:,j), ...
+                        f_log, 'linear');
+                over_mask = test.m(:,j)-mask_hi';
+                under_mask = mask_lo'-test.m(:,j);
+                idx = find(isnan(over_mask) == 0);
+                [m_over_mask, io] = max(over_mask(idx));
+                idx = find(isnan(under_mask) == 0);
+                [m_under_mask, iu] = max(under_mask(idx));
+                if m_over_mask > 0
+                        fprintf('Failed upper response mask around %.0f Hz\n', ...
+                                test.f(io));
+                        test.fail = 1;
+                end
+                if m_under_mask > 0
+                        fprintf('Failed lower response mask around %.0f Hz\n', ...
+                                test.f(iu));
+                        test.fail = 1;
+                end
+        end
+
+        test.fh(j) = figure('visible', test.visible);
+        subplot(1,1,1);
+        test.ph(j) = subplot(1,1,1);
+        %semilogx(test.f, test.m(:,j));
+        plot(test.f, test.m(:,j));
+        grid on;
+        xlabel('Frequency (Hz)');
+        ylabel('Magnitude (dB)');
+        if length(test.mask_f) > 0
+                hold on;
+                plot(test.f, mask_hi, 'r--');
+                plot(test.f, mask_lo, 'r--');
+                hold off;
+        end
+	ax = axis();
+	axis([ax(1:2) -4 1]);
+        if max(max(test.m(idx1,j))-min(test.m(idx1,j))) < 1
+                axes('Position', [ 0.2 0.2 0.4 0.2]);
+                box on;
+                plot(test.f(idx1), test.m(idx1,j));
+                if ~isempty(test.rp_max)
+                        hold on;
+                        plot([test.f_lo test.f_hi], ...
+                                [-test.rp_max/2 -test.rp_max/2], 'r--');
+                        plot([test.f_lo test.f_hi], ...
+                                [ test.rp_max/2  test.rp_max/2], 'r--');
+                        hold off;
+                end
+                grid on;
+                axis([0 test.f_hi -0.1 0.1]);
+        end
+
+        %% Next channel to measure
+        j=j+1;
+end
+
+end
diff --git a/test/std_utils/g_test_input.m b/test/std_utils/g_test_input.m
new file mode 100644
index 0000000..bc0e19b
--- /dev/null
+++ b/test/std_utils/g_test_input.m
@@ -0,0 +1,97 @@
+function test = g_test_input(test)
+
+%% t = dr_test_input(t)
+%
+% Create tone data file for playback & record on real device or
+% for algorithm simulation.
+%
+% Input parameters
+% t.fs        - sample rate
+% t.bits_in   - signal word length
+% t.ch        - mix test signal to channel ch
+% t.nch       - total number of channels in data
+%
+% Output parameters
+% t.fn_in     - created input file name
+% t.fn_out    - proposed output file name for captured output
+% t.f         - test signal frequency
+% t.tl        - tone length in seconds
+% t.ts        - tone start time
+% t.tr        - tone gain ramp length in seconds
+% t.ti        - ignore time from tone start and end, must be ti > tr
+% t.a         - tone amplitude (lin)
+% t.a_db      - tone amplitude (dB)
+% t.mark_t    - length of marker tone in seconds
+% t.mark_a    - amplitude max of marker tone (lin)
+% t.mark_a_db - amplitude max of marker tone (dB)
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.2.2 Gain
+%  http://www.aes.org/publications/standards/
+
+
+if nargin < 1
+        fprintf('Warning, using default parameters!\n');
+        test.fs = 48e3; test.bits=32; test.ch=1; test.nch=1;
+end
+
+if test.ch == 0
+        test.ch = 1+round(rand(1,1)*(test.nch-1)); % Test random channel 1..Nch
+end
+
+fprintf('Using parameters Fs=%.1f, bits_in=%d', test.fs/1e3, test.bits_in);
+fprintf(', ch=%d', test.ch );
+fprintf(', Nch=%d\n', test.nch );
+
+test.fn_in = sprintf('g_test_in.%s', test.fmt);
+test.fn_out = sprintf('g_test_out.%s', test.fmt);
+test.f = 997;
+
+
+%% Tone sweep parameters
+test.is = 20e-3; % Ignore signal from tone start
+test.ie = 20e-3; % Ignore signal from tone end
+test.tr = 10e-3; % Gain ramp time for tones
+test.sm = 3; % Seek start marker from 3s from start
+test.em = 3; % Seek end marker from 3s from end
+test.mt = 0.3; % Error if marker positions delta is greater than 0.3s
+test.tc = 25; % Min. 20 cycles of sine wave for a frequency
+test.a_db = -20; % -20 dBFS level
+test.a = 10^(test.a_db/20);
+% 0.5 seconds tone, this will be adjusted to be integer number of samples
+test.tl = 0.5;
+
+%% Mix the input file for test and write output
+test = mix_sweep(test);
+
+end
diff --git a/test/std_utils/g_test_measure.m b/test/std_utils/g_test_measure.m
new file mode 100644
index 0000000..40c9871
--- /dev/null
+++ b/test/std_utils/g_test_measure.m
@@ -0,0 +1,70 @@
+function test = g_test_measure(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.2.2 Gain
+%  http://www.aes.org/publications/standards/
+
+%% Load output file
+[x, nx] = load_test_output(test);
+
+if nx == 0
+        test.g_db = NaN;
+        test.fail = 1;
+        return
+end
+
+%% Standard low-pass
+y0 = stdlpf(x, test.fu, test.fs);
+
+%% Find sync
+[d, nt, nt_use, nt_skip] = find_test_signal(y0, test);
+
+%% Trim sample by removing first 1s to let the notch to apply
+i1 = d+nt_skip;
+i2 = i1+nt_use-1;
+y = y0(i1:i2);
+
+%% Gain, SNR
+level_in = test.a_db;
+level_out = level_dbfs(y);
+test.g_db = level_out-level_in;
+fprintf('Gain = %6.3f dB (expecting %6.3f dB)\n', test.g_db, test.g_db_expect);
+
+%% Check pass/fail
+test.fail = 0;
+if abs(test.g_db_expect-test.g_db) > test.g_db_tol
+        fprintf('Failed gain %f dB (max %f dB)\n', test.g_db, test.g_db_tol);
+        test.fail = 1;
+end
+
+end
+
diff --git a/test/std_utils/level_dbfs.m b/test/std_utils/level_dbfs.m
new file mode 100644
index 0000000..73cdded
--- /dev/null
+++ b/test/std_utils/level_dbfs.m
@@ -0,0 +1,46 @@
+function dbfs = level_dbfs(x)
+
+%% dbfs = level_dbfs(x)
+%
+% Input
+% x - signal
+%
+% Output
+% dbfs - sigmal level in dBFS
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference AES 17 3.12.3
+level_ms = mean(x.^2);
+dbfs = 10*log10(level_ms) + 20*log10(sqrt(2));
+
+end
diff --git a/test/std_utils/stdhpf.m b/test/std_utils/stdhpf.m
new file mode 100644
index 0000000..bf855a0
--- /dev/null
+++ b/test/std_utils/stdhpf.m
@@ -0,0 +1,54 @@
+function y = stdhpf(x, fu, fs)
+
+%% y = stdhpf(x, fu, fs)
+%
+% Standard high-pass filter
+%
+% Input
+% x - input signal
+% fu - upper band-edge frequency
+% fs - sample rate
+%
+% Output
+% y - filtered signal
+%
+% Reference AES17 5.2.6
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Design filter
+b = stdhpf_get(fu, fs);
+
+%% Filter
+y = filter(b, 1, x);
+
+
+end
diff --git a/test/std_utils/stdhpf_get.m b/test/std_utils/stdhpf_get.m
new file mode 100644
index 0000000..367a39b
--- /dev/null
+++ b/test/std_utils/stdhpf_get.m
@@ -0,0 +1,68 @@
+function b = stdhpf_get(fu, fs)
+
+%% y = stdhpf(x, fu, fs)
+%
+% Standard high-pass filter
+%
+% Input
+% x - input signal
+% fu - upper band-edge frequency
+% fs - sample rate
+%
+% Output
+% y - filtered signal
+%
+% Reference AES17 5.2.6
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Design filter
+rp = 0.5;
+rs = -50; % Some margin vs. requirement
+a = [0 1];
+fc = min(1.3*fu, 0.99*fs/2);
+f = [fu fc];
+dev = [ 10^(rs/20) (10^(rp/20)-1)/(10^(rp/20)+1) ];
+[n, wn, beta, ftype] = kaiserord(f, a, dev, fs);
+b = fir1(n, wn, ftype, kaiser(n+1,beta));
+
+if 0
+        f = linspace(0, fs/2, 1000);
+        h = freqz(b,1, f, fs);
+        figure
+        plot(f, 20*log10(abs(h)))
+        hold on;
+        plot( [0 fu], [-40 -40], 'r', [fc fs/2], [-0.5 -0.5], 'r', [fc fs/2], [0.5 0.5], 'r');
+        hold off;
+        grid on;
+end
+
+end
diff --git a/test/std_utils/stdlpf.m b/test/std_utils/stdlpf.m
new file mode 100644
index 0000000..56fdc5a
--- /dev/null
+++ b/test/std_utils/stdlpf.m
@@ -0,0 +1,54 @@
+function y = stdlpf(x, fu, fs)
+
+%% y = stdhpf(x, fu, fs)
+%
+% Standard high-pass filter
+%
+% Input
+% x - input signal
+% fu - upper band-edge frequency
+% fs - sample rate
+%
+% Output
+% y - filtered signal
+%
+% Reference AES17 5.2.5
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Design filter
+b = stdlpf_get(fu, fs);
+
+%% Filter
+y = filter(b, 1, x);
+
+
+end
diff --git a/test/std_utils/stdlpf_get.m b/test/std_utils/stdlpf_get.m
new file mode 100644
index 0000000..ac344d1
--- /dev/null
+++ b/test/std_utils/stdlpf_get.m
@@ -0,0 +1,70 @@
+function b = stdlpf_get(fu, fs)
+
+%% b = stdlpf_get(fu, fs)
+%
+% Standard loww-pass filter
+%
+% Input
+% fu - upper band-edge frequency
+% fs - sample rate
+%
+% Output
+% b - coefficients for FIR filter
+%
+% Reference AES17 5.2.5
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Design filter
+rp = 0.001; % Since this may need to be in frequency response measurement the ripple must be very small
+rs = -65; % Some margin vs. requirement
+a = [1 0];
+% Note: The fc-fu for digital low-pass is not feasible. Use of fu*1.2 instead
+% results to example 24 kHz for 20 kHz upper band-edge. This could be a mistake
+% in specification.
+fc = min(fu*1.2, 0.99*fs/2);
+f = [fu fc];
+dev = [ (10^(rp/20)-1)/(10^(rp/20)+1) 10^(rs/20) ];
+[n, wn, beta, ftype] = kaiserord(f, a, dev, fs);
+b = fir1(n, wn, ftype, kaiser(n+1,beta));
+
+if 0
+        f = linspace(0, fs/2, 1000);
+        h = freqz(b,1, f, fs);
+        figure
+        plot(f, 20*log10(abs(h)))
+        hold on;
+        plot( [fc fs/2], [-60 -60], 'r', [0 fu], [-0.1 -0.1], 'r', [0 fu], [0.1 0.1], 'r');
+        hold off;
+        grid on;
+end
+
+end
diff --git a/test/std_utils/stdnotch.m b/test/std_utils/stdnotch.m
new file mode 100644
index 0000000..51d00d2
--- /dev/null
+++ b/test/std_utils/stdnotch.m
@@ -0,0 +1,47 @@
+function y = stdnotch(x, fn, fs)
+
+%% y = stdnotch(x, fn, fs)
+%
+% Input
+% x  - input signal
+% fn - notch frequency
+% fs - sample rate
+%
+% Output
+% y - filtered signal
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+[b, a] = stdnotch_get(fn, fs);
+y = filter(b, a, x);
+
+end
diff --git a/test/std_utils/stdnotch_get.m b/test/std_utils/stdnotch_get.m
new file mode 100644
index 0000000..5213fa8
--- /dev/null
+++ b/test/std_utils/stdnotch_get.m
@@ -0,0 +1,70 @@
+function [b, a] = stdnotch_get(fn, fs)
+
+%% [b, a] = stdnotch_get(fn, fs)
+%
+% Input
+% fn - notch frequency
+% fs - sample rate
+%
+% Output
+% b - coefficients for filter zeros
+% a - coefficients for filter poles
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+target_q = 2.1;
+bw = (2*fn/fs)/target_q;
+if exist('iirnotch.m') == 2
+        [b, a] = iirnotch(2*fn/fs, bw);
+else
+        [b, a] = pei_tseng_notch(2*fn/fs, bw);
+end
+if 0
+        %% In AES17 5.2.8 standard notch must have Q 1.2-3.0
+        %  Quality factor is ratio of of center frequency to
+        %  differenence between -3 dB frequencies.
+        figure;
+        f = linspace(0.2*fn, min(2*fn,fs/2), 5000);
+        h = freqz(b, a, f, fs);
+        m = 20*log10(abs(h));
+        plot(f, m); grid on;
+        idx = find(m < -3);
+        f1 = f(idx(1));
+        f2 = f(idx(end));
+        q = fn/(f2-f1);
+        if (q < 1.2) || (q > 3.0)
+                fprintf('Required Q value failed, Q = %5.2f\n', q);
+        else
+                fprintf('Q = %5.2f\n', q);
+        end
+end
+end
diff --git a/test/std_utils/stdweight.m b/test/std_utils/stdweight.m
new file mode 100644
index 0000000..92e3a3c
--- /dev/null
+++ b/test/std_utils/stdweight.m
@@ -0,0 +1,86 @@
+function y = stdweight(x, fs)
+
+%% y = stdweight(x, fs)
+%
+% Input
+% x  - input signal
+% fs - sample rate
+%
+% Output
+% y - filtered signal
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Frequency grid for FIR design
+f = linspace(0, fs/2, 6000);
+
+%% From https://en.wikipedia.org/wiki/ITU-R_468_noise_weighting
+h1 = -4.737338981378384e-24*f.^6 +2.043828333606125e-15*f.^4 -1.363894795463638e-7*f.^2 +1;
+h2 =  1.306612257412824e-19*f.^5 -2.118150887518656e-11*f.^3 +5.559488023498642e-4*f;
+RITU = 1.246332637532143e-4*f./sqrt(h1.^2+h2.^2);
+ITU = 18.2+20*log10(RITU)-5.63; % AES17 CCIR-RMS
+fc = [ 31.5    63   100   200   400   800  1000  2000  3150  4000  5000  6300  7100  8000  9000 10000 12500 14000 16000 20000 31500];
+ga = [-35.5 -29.5 -25.4 -19.4 -13.4  -7.5  -5.6     0   3.4   4.9   6.1   6.6   6.4   5.8   4.5   2.5  -5.6 -10.9 -17.3 -27.8 -48.3];
+tu = [  2.0   1.4   1.0  0.85  0.70  0.55  0.50  0.50  0.50  0.50  0.50  0.01  0.20  0.40  0.60  0.80   1.2   1.4   1.6   2.0   2.8];
+tl = [ -2.0  -1.4  -1.0 -0.85 -0.70 -0.55 -0.50 -0.50 -0.50 -0.50 -0.50 -0.01 -0.20 -0.40 -0.60 -0.80  -1.2  -1.4  -1.6  -2.0   NaN];
+
+%% Fine tune the 6300Hz, 6.6 dB point
+if fs > 2*6300
+        idx = find(f > 6300, 1, 'first');
+        ITU = ITU + 6.6-ITU(idx);
+else
+        idx = find(f > 3150, 1, 'first');
+        ITU = ITU + 3.4-ITU(idx);
+end
+
+m_fir = 10.^(ITU/20);
+f_fir = 2*f/fs;
+n_fir = 4000; % Sufficient up to 192 kHz
+if (fs < 96001)
+        n_fir = 2000;
+end
+if (fs < 48001)
+        n_fir = 1000;
+end
+if (fs < 16001)
+        n_fir = 400;
+end
+bz = fir2(n_fir, f_fir, m_fir);
+y = filter(bz, 1, x);
+if 0
+        h = freqz(bz, 1, f, fs);
+        my_w_db = 20*log10(abs(h));
+        figure;
+        semilogx(f,ITU,fc,ga,'x',fc,ga+tu,fc,ga+tl, f, my_w_db );
+        grid on; xlabel('Hz'); ylabel('dB');
+end
+end
diff --git a/test/std_utils/thdnf_test_input.m b/test/std_utils/thdnf_test_input.m
new file mode 100644
index 0000000..b07f21f
--- /dev/null
+++ b/test/std_utils/thdnf_test_input.m
@@ -0,0 +1,95 @@
+function test = thdnf_test_input(test)
+
+%% t = dr_test_input(t)
+%
+% Create tone data file for playback & record on real device or
+% for algorithm simulation.
+%
+% Input parameters
+% t.fs        - sample rate
+% t.bits_in   - signal word length
+% t.ch        - mix test signal to channel ch
+% t.nch       - total number of channels in data
+%
+% Output parameters
+% t.fn_in     - created input file name
+% t.fn_out    - proposed output file name for captured output
+% t.f         - test signal frequency
+% t.tl        - tone length in seconds
+% t.ts        - tone start time
+% t.tr        - tone gain ramp length in seconds
+% t.ti        - ignore time from tone start and end, must be ti > tr
+% t.a         - tone amplitude (lin)
+% t.a_db      - tone amplitude (dB)
+% t.mark_t    - length of marker tone in seconds
+% t.mark_a    - amplitude max of marker tone (lin)
+% t.mark_a_db - amplitude max of marker tone (dB)
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.3.2 THD+N ratio vs frequency
+%  http://www.aes.org/publications/standards/
+
+if nargin < 1
+        fprintf('Warning, using default parameters!\n');
+        test.fs = 48e3; test.f_start=20; test.f_end=20e3; test.bits_in=32; test.ch=1; test.nch=1;
+end
+
+if test.ch == 0
+        test.ch = 1+round(rand(1,1)*(test.nch-1)); % Test random channel 1..Nch
+end
+
+fprintf('Using parameters Fstart=%.0f Hz, Fend=%.0f Hz, Fs=%.1f Hz, bits_in=%d, ch=%d, Nch=%d\n', ...
+        test.f_start, test.f_end, test.fs/1e3, test.bits_in, test.ch, test.nch );
+
+test.fn_in = sprintf('thdnf_test_in.%s', test.fmt);
+test.fn_out = sprintf('thdnf_test_out.%s', test.fmt);
+noct = ceil(log(test.f_end/test.f_start)/log(2)); % Max 1 octave steps
+test.f = logspace(log10(test.f_start),log10(test.f_end), noct);
+
+
+%% Tone sweep parameters
+test.is = 20e-3; % Ignore signal from tone start
+test.ie = 20e-3; % Ignore signal from tone end
+test.tr = 10e-3; % Gain ramp time for tones
+test.sm = 3; % Seek start marker from 3s from start
+test.em = 3; % Seek end marker from 3s from end
+test.mt = 0.1; % Error if marker positions delta is greater than 0.1s
+test.a_db = [-1 -20]; % -1 and -20 dBFS levels
+test.a = 10.^(test.a_db/20);
+test.tl = 4; % 3 seconds tone
+test.nst = 2; % Wait 1 seconds for frequency specific notch output to settle
+
+%% Mix the input file for test and write output
+test = mix_sweep(test);
+
+end
diff --git a/test/std_utils/thdnf_test_measure.m b/test/std_utils/thdnf_test_measure.m
new file mode 100644
index 0000000..6e10f17
--- /dev/null
+++ b/test/std_utils/thdnf_test_measure.m
@@ -0,0 +1,83 @@
+function test = thdnf_test_measure(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Reference: AES17 6.3.2 THD+N ratio vs frequency
+%  http://www.aes.org/publications/standards/
+
+%% Load output file
+[x, nx] = load_test_output(test);
+if nx == 0
+        test.g_db = NaN;
+        test.fail = 1;
+        return
+end
+
+%% Standard low-pass
+y0 = stdlpf(x, test.fu, test.fs);
+
+%% Find sync
+[d, nt, nt_use, nt_skip] = find_test_signal(y0, test);
+
+%% Measure all test frequencies
+ml = zeros(test.nf,test.na);
+mn = zeros(test.nf,test.na);
+n_notch_settle = round(test.fs*test.nst);
+nn = 1;
+for m=1:test.na
+        for n=1:test.nf
+                fprintf('Measuring %.0f Hz ...\n', test.f(n));
+                i1 = d+(nn-1)*nt+nt_skip;
+                i2 = i1+nt_use-1;
+                nn = nn+1;
+                y0n = stdnotch(y0(i1:i2), test.f(n), test.fs);
+                ml(n,m) = level_dbfs(y0(i1:i2));
+                mn(n,m) = level_dbfs(y0n(n_notch_settle:end));
+        end
+end
+
+test.thdnf = mn - ml;
+test.thdnf_high = test.thdnf(:,1);
+test.thdnf_low = test.thdnf(:,2);
+if max(max(test.thdnf)) > test.thdnf_max
+        test.fail = 1;
+else
+        test.fail = 0;
+end
+
+test.fh = figure('visible', test.visible);
+semilogx(test.f, test.thdnf(:,1), 'b', test.f, test.thdnf(:,2), 'g--');
+grid on;
+xlabel('Frequency (Hz)');
+ylabel('THD+N (dB)');
+legend('-1 dBFS','-20 dBFS');
+
+end
diff --git a/test/test_utils/chirp_test_analyze.m b/test/test_utils/chirp_test_analyze.m
new file mode 100644
index 0000000..e7026f6
--- /dev/null
+++ b/test/test_utils/chirp_test_analyze.m
@@ -0,0 +1,91 @@
+function test = chirp_test_analyze(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Load output file
+[x, nx] = load_test_output(test);
+if nx < 1
+	test.fail = -1; % No data
+	return;
+end
+
+%% Find sync
+[d, nt, nt_use, nt_skip] = find_test_signal(x(:,test.ch(1)), test);
+
+%% Trim sample
+i1 = d+nt_skip;
+i2 = i1+nt_use-1;
+z = x(i1:i2, :);
+y = z(:,test.ch);
+s = sum(z,2);
+
+%% Quick check length, RMS, offset, and channels sum
+sz = size(z);
+tz = sz(1)/test.fs;
+et = abs(test.cl-tz)/test.cl;
+rms_db = 10*log10(mean(z.^2)) + 20*log10(sqrt(2));
+offs_db = 20*log10(abs(mean(z)));
+sum_max_db = 20*log10(max(abs(s)));
+% Check for proper ratio of out/in samples, minimum level, maximum offset
+% and maximum of sum of channels. The input is such that the channels should
+% sum to zero. A phase difference in channels would cause non-zero output
+% for channels sum. Dithered input causes a small non-zero sum value.
+
+if et > 0.05
+	fail = 1;
+	fprintf('Failed output chirp length, err=%f, t=%f.\n', et, tz);
+else if (min(rms_db) < -3) && (test.fs2 + 1 > test.fs1)
+	     fail = 1;
+	     fprintf('Failed output chirp level.\n');
+     else if max(offs_db) > -40
+		  fail = 1;
+		  fprintf('Failed output chirp DC offset.\n');
+	  else if (sum_max_db > -100) && (mod(test.nch, 2) == 0)
+		       fail = 1;
+		       fprintf('Failed output chirp channels phase.\n');
+	       else
+		       fail = 0;
+	       end
+	  end
+     end
+end
+
+test.fh = figure('visible', test.visible);
+ns = 1024;
+no = round(0.9*ns);
+specgram(y(:,1), ns, test.fs, kaiser(ns,27), no);
+colormap('jet');
+caxis([-150 0]);
+colorbar('EastOutside');
+
+test.fail = fail;
+
+end
diff --git a/test/test_utils/chirp_test_input.m b/test/test_utils/chirp_test_input.m
new file mode 100644
index 0000000..89b2861
--- /dev/null
+++ b/test/test_utils/chirp_test_input.m
@@ -0,0 +1,96 @@
+function test = chirp_test_input(test)
+
+%% t = dr_test_input(t)
+%
+% Create tone data file for playback & record on real device or
+% for algorithm simulation.
+%
+% Input parameters
+% t.fs        - sample rate
+% t.bits_in   - signal word length
+% t.ch        - mix test signal to channel ch
+% t.nch       - total number of channels in data
+%
+% Output parameters
+% t.fn_in     - created input file name
+% t.fn_out    - proposed output file name for captured output
+% t.f         - test signal frequency
+% t.tl        - tone length in seconds
+% t.ts        - tone start time
+% t.tr        - tone gain ramp length in seconds
+% t.ti        - ignore time from tone start and end, must be ti > tr
+% t.a         - tone amplitude (lin)
+% t.a_db      - tone amplitude (dB)
+% t.mark_t    - length of marker tone in seconds
+% t.mark_a    - amplitude max of marker tone (lin)
+% t.mark_a_db - amplitude max of marker tone (dB)
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 1
+        fprintf('Warning, using default parameters!\n');
+        test.fs = 48e3; test.bits=32; test.ch=1; test.nch=1;
+end
+
+if test.ch == 0
+        test.ch = 1:test.nch; % Test all channels 1..Nch
+end
+
+fprintf('Using parameters Fs=%.1f, bits_in=%d', test.fs/1e3, test.bits_in);
+fprintf(', ch=%d', test.ch );
+fprintf(', Nch=%d\n', test.nch );
+
+test.fn_in = sprintf('chirp_test_in.%s', test.fmt);
+test.fn_out =  sprintf('chirp_test_out.%s', test.fmt);
+
+
+%% Chirp parameters
+test.a_db = -0.1; % Near full scale
+test.a = 10^(test.a_db/20);
+test.f_min = 20;
+test.f_max = 0.99*test.fs/2;
+test.cl = 2.0;
+
+
+%% Parameters to find signal between markers
+test.nf = 1;
+test.na = 1;
+test.sm = 3; % Seek start marker from 3s from start
+test.em = 3; % Seek end marker from 3s from end
+test.mt = 0.3; % Error if marker positions delta is greater than 0.3s
+test.is = 0; % Ignore signal from tone start
+test.ie = 0; % Ignore signal from tone end
+
+%% Mix the input file for test and write output
+test = mix_chirp(test);
+
+end
diff --git a/test/test_utils/delete_check.m b/test/test_utils/delete_check.m
new file mode 100644
index 0000000..b3e1c82
--- /dev/null
+++ b/test/test_utils/delete_check.m
@@ -0,0 +1,35 @@
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+function delete_check(really, f)
+if really && exist(f) == 2
+        delete(f);
+end
+end
diff --git a/test/test_utils/dither_and_quantize.m b/test/test_utils/dither_and_quantize.m
new file mode 100644
index 0000000..56a2a58
--- /dev/null
+++ b/test/test_utils/dither_and_quantize.m
@@ -0,0 +1,61 @@
+%% xq = dither_and_quantize(x, bits)
+%
+% Input
+% x - input signal
+% bits - number of bits
+%
+% Output
+% (int32) xq - scaled, dithered and quantized signal
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+function xq = dither_and_quantize(x, bits)
+
+if (bits > 32) || (bits < 1)
+        error('This function supports max 32 bits quantization!');
+end
+
+scale = 2^(bits-1);
+smax = scale-1;
+smin = -scale;
+sx = size(x);
+nx = sx(1);
+nch = sx(2);
+
+xq = int32(floor( scale*x + randn(nx,nch) - randn(nx,nch) -0.5)); % TPDF dither
+%xq = int32(round( scale*x )); % Omit dither
+idx = find(xq > smax);
+xq(idx) = smax;
+idx = find(xq < smin);
+xq(idx) = smin;
+
+end
diff --git a/test/test_utils/find_test_signal.m b/test/test_utils/find_test_signal.m
new file mode 100644
index 0000000..fee52d5
--- /dev/null
+++ b/test/test_utils/find_test_signal.m
@@ -0,0 +1,76 @@
+function [d, nt, nt_use, nt_skip] = find_test_signal(x, test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Find start marker
+fprintf('Finding test start marker...\n');
+s = sync_chirp(test.fs, 'up');
+nx = length(x);
+n_seek = round(test.fs*(test.idle_t + test.mark_t));
+n = min(round(test.fs*test.sm), n_seek);
+y = x(1:n);
+[r, lags] = xcorr(y, s);
+[r_max, idx] = max(r);
+d_start = lags(idx);
+
+%% Find end marker
+fprintf('Finding test end marker...\n');
+s = sync_chirp(test.fs, 'down');
+n_seek = round(test.fs*(2*test.idle_t + test.mark_t));
+n = min(round(test.fs*test.em),n_seek);
+y = x(end-n+1:end);
+[r, lags] = xcorr(y, s);
+[r_max, idx] = max(r);
+d_end = nx-n+lags(idx);
+
+%% Check correct length of signal
+len = d_end-d_start;
+len_s = len/test.fs;
+ref_s = test.mark_t+test.nf*test.na*test.tl;
+if abs(len_s-ref_s) > test.mt
+        len_s
+        ref_s
+        error('Start and end markers were not found. Test play or capture quality may be poor');
+end
+
+%% Delay to first tone, length of tone in samples
+d = d_start + round(test.mark_t*test.fs);
+if (d < 0)
+	error('Invalid negative delay seen. Test play or capture quality may be poor');
+end
+nt = round(test.tl*test.fs);
+nt_use = nt -round(test.is*test.fs) -round(test.ie*test.fs);
+if nt_use < 0
+        error('Test signal length parameters must be wrong!');
+end
+nt_skip = round(test.is*test.fs);
+
+end
diff --git a/test/test_utils/load_test_output.m b/test/test_utils/load_test_output.m
new file mode 100644
index 0000000..320a4d6
--- /dev/null
+++ b/test/test_utils/load_test_output.m
@@ -0,0 +1,87 @@
+function [x, nx] = load_test_output(test)
+
+%% [x, n] = load_test_output(t)
+%
+% Input
+% t.fn_out     - file name to load
+% t.bits_out   - word length of data
+% t.fmt        - file format 'raw' or 'txt
+% t.ch         - channel to extract
+% t.nch        - number of channels in (interleaved) data
+%
+% Output
+% x - samples
+% n - number of samples
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Integer type for binary files
+switch test.bits_out
+	case 16
+		bfmt = 'int16';
+	case 24
+		bfmt = 'int32';
+	case 32
+		bfmt = 'int32';
+	otherwise
+		error('Bits_out must be 16, 24, or 32.');
+end
+
+%% Check that output file exists
+if exist(test.fn_out)
+        fprintf('Reading output data file %s...\n', test.fn_out);
+	switch lower(test.fmt)
+		case 'txt'
+			out = load(test.fn_out);
+		case 'raw'
+			fh = fopen(test.fn_out, 'r');
+			out = fread(fh, inf, bfmt);
+			fclose(fh);
+		otherwise
+			error('Fmt must be raw or txt.');
+	end
+else
+        out = [];
+end
+
+%% Exctract channels to measure
+scale = 1/2^(test.bits_out-1);
+lout = length(out);
+nx = floor(lout/test.nch);
+x = zeros(nx,length(test.ch));
+j = 1;
+for ch = test.ch
+        x(:,j) = out(ch:test.nch:end)*scale;
+        j = j + 1;
+end
+
+end
diff --git a/test/test_utils/mix_chirp.m b/test/test_utils/mix_chirp.m
new file mode 100644
index 0000000..9b57f2c
--- /dev/null
+++ b/test/test_utils/mix_chirp.m
@@ -0,0 +1,82 @@
+function  test = mix_chirp(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Adjust tone length to integer number of samples
+test.nt = round(test.cl*test.fs); % Make number of samples per tone
+test.tl = test.nt/test.fs;        % an integer by adjusting tl.
+
+%% Test start and end marker tones
+[h1, mark_start] = sync_chirp(test.fs, 'up');
+[h2, mark_end] = sync_chirp(test.fs, 'down');
+test.mark_t = mark_start.t;
+test.mark_a = mark_start.a;
+test.mark_a_db = mark_start.a_db;
+test.ts = mark_start.t;
+
+%% Idle time to start and end
+test.idle_t = 0.5;
+n_idle = round(test.fs*test.idle_t);
+t_idle = n_idle/test.fs;
+x = zeros(test.nt + mark_start.n + mark_end.n +2*n_idle, test.nch, 'int32');
+
+%% Add markers
+idx1 = n_idle+1;
+idx2 = length(x)-n_idle-mark_end.n;
+for ch=test.ch
+        x(idx1:idx1+mark_start.n-1, ch) = dither_and_quantize(h1, test.bits_in);
+        x(idx2:idx2+mark_end.n-1, ch) = dither_and_quantize(h2, test.bits_in);
+end
+
+%% Dither also idle parts
+x(1:n_idle) = dither_and_quantize(zeros(n_idle,1), test.bits_in);
+x(end-n_idle+1:end) = dither_and_quantize(zeros(n_idle,1), test.bits_in);
+
+%% Add Chirp
+i1 = n_idle+mark_start.n+1;
+i2 = i1+test.nt-1;
+fprintf('Mixing %.1f dBFS chirp ...\n', test.a_db);
+tc = ((1:round(test.cl*test.fs))-1)/test.fs;
+s = test.a * chirp(tc, test.f_min, test.tl, test.f_max, 'linear', 90);
+sign = 1;
+for ch=test.ch
+        x(i1:i2, ch) = dither_and_quantize(sign * s, test.bits_in);
+	sign = -sign;
+end
+
+test.signal = x;
+
+%% Output
+fprintf('Writing output data file %s...\n', test.fn_in);
+write_test_data(x, test.fn_in, test.bits_in, test.fmt);
+fprintf('Done.\n')
+
+end
diff --git a/test/test_utils/mix_sweep.m b/test/test_utils/mix_sweep.m
new file mode 100644
index 0000000..1b76437
--- /dev/null
+++ b/test/test_utils/mix_sweep.m
@@ -0,0 +1,103 @@
+function  test = mix_sweep(test)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Adjust tone lengt to integer number of samples
+test.nt = round(test.tl*test.fs); % Make number of samples per tone
+test.tl = test.nt/test.fs;        % an integer by adjusting tl.
+test.nf = length(test.f); % Number of frequencies
+test.na = length(test.a); % Number of amplitudes
+
+%% Test start and end marker tones
+[h1, mark_start] = sync_chirp(test.fs, 'up');
+[h2, mark_end] = sync_chirp(test.fs, 'down');
+test.mark_t = mark_start.t;
+test.mark_a = mark_start.a;
+test.mark_a_db = mark_start.a_db;
+test.ts = mark_start.t;
+
+%% Idle time to start and end
+test.idle_t = 0.5;
+n_idle = round(test.fs*test.idle_t);
+t_idle = n_idle/test.fs;
+x = zeros(test.nf*test.na*test.nt +mark_start.n +mark_end.n +2*n_idle, ...
+        test.nch, 'int32');
+
+%% Add markers
+idx1 = n_idle+1;
+idx2 = length(x)-n_idle-mark_end.n;
+for ch=test.ch
+        x(idx1:idx1+mark_start.n-1, ch) = dither_and_quantize(h1, test.bits_in);
+        x(idx2:idx2+mark_end.n-1, ch) = dither_and_quantize(h2, test.bits_in);
+end
+
+%% Dither also idle parts
+x(1:n_idle) = dither_and_quantize(zeros(n_idle,1), test.bits_in);
+x(end-n_idle+1:end) = dither_and_quantize(zeros(n_idle,1), test.bits_in);
+
+%% Add discrete frequencies sweep
+n_r = round(test.fs*test.tr);
+win = ones(test.nt,1);
+win(1:n_r) = linspace(0,1,n_r);
+win(end-n_r+1:end) = linspace(1,0,n_r);
+i0 = n_idle+mark_start.n+1;
+nn = 1;
+for m=1:test.na
+        for n=1:test.nf
+                i1 = i0 + (nn-1)*test.nt+1;
+                i2 = i1+test.nt-1;
+                nn = nn+1;
+                if length(test.f) > 1
+                        f = test.f(n);
+                else
+                        f = test.f;
+                end
+                if length(test.a) > 1
+                        a = test.a(m);
+                else
+                        a = test.a;
+                end
+                fprintf('Mixing %.0f Hz %.1f dBFS sine ...\n', f, 20*log10(a));
+                s = multitone(test.fs, f, a, test.tl);
+                for ch=test.ch
+                        x(i1:i2, ch) = dither_and_quantize(s.*win, test.bits_in);
+                end
+        end
+end
+
+test.signal = x;
+
+%% Output
+fprintf('Writing output data file %s...\n', test.fn_in);
+write_test_data(x, test.fn_in, test.bits_in, test.fmt);
+fprintf('Done.\n')
+
+end
diff --git a/test/test_utils/mkdir_check.m b/test/test_utils/mkdir_check.m
new file mode 100644
index 0000000..b453d0b
--- /dev/null
+++ b/test/test_utils/mkdir_check.m
@@ -0,0 +1,35 @@
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+function d = mkdir_check(d)
+if exist(d) ~= 7
+        mkdir(d);
+end
+end
diff --git a/test/test_utils/multitone.m b/test/test_utils/multitone.m
new file mode 100644
index 0000000..7f3faa3
--- /dev/null
+++ b/test/test_utils/multitone.m
@@ -0,0 +1,61 @@
+function x = multitone( fs, f, amp, tlength )
+
+%%
+% Create single or multiple sine wave(s)
+%
+% x = multitone(fs, f, a, t);
+%
+% fs     - Sample rate
+% f      - Frequency (Hz)
+% a      - Amplitude (lin)
+% t      - Lenght in seconds
+%
+% Example:
+% x = multitone(48000, [997 1997], 10.^([-26 -46]/20), 1.0);
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+n = round(fs*tlength);
+t = (0:n-1)/fs;
+nf = length(f);
+if nf > 1
+        ph = rand(nf, 1)*2*pi;
+else
+        ph = 0;
+end
+
+x = amp(1)*sin(2*pi*f(1)*t');
+for i=2:length(f)
+        x = x + amp(i)*sin(2*pi*f(i)*t+ph(i));
+end
+
+end
diff --git a/test/test_utils/sync_chirp.m b/test/test_utils/sync_chirp.m
new file mode 100644
index 0000000..513a426
--- /dev/null
+++ b/test/test_utils/sync_chirp.m
@@ -0,0 +1,68 @@
+function [y, mark]= sync_chirp(fs, direction)
+
+%% [y, mark]= sync_chirp(fs, direction)
+%
+% Returns a chirp signal that can be used to mark end and beginning of audio
+% tests to syncronize input and captured output accurately.
+%
+% Input
+% fs - sample rate
+% direction - direction of frequency sweep 'up' or 'down'
+%
+% Output
+% y - windowed chirp signal
+% mark - struct with parameters for chirp
+%
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+mark.a_db = -10;
+mark.a = 10^(mark.a_db/20);
+mark.fs = fs;
+mark.t = 0.2; % Short, to not consume much test time
+switch lower(direction)
+        case 'up'
+                mark.f0 = 200; % Should work with any speaker
+                mark.f1 = 3500; % Should work with any speaker
+        case 'down'
+                mark.f1 = 200; % Should work with any speaker
+                mark.f0 = 3500; % Should work with any speaker
+        otherwise
+                error('Parameter direction must be ''up'' or ''down''');
+end
+
+mark.n = round(mark.t*fs);
+t_vec = (0:mark.n-1)/fs;
+w = hanning(mark.n);
+x = chirp(t_vec, mark.f0, mark.t, mark.f1, 'linear')';
+y = x .* w * mark.a;
+
+end
diff --git a/test/test_utils/test_run.m b/test/test_utils/test_run.m
new file mode 100644
index 0000000..1eb3405
--- /dev/null
+++ b/test/test_utils/test_run.m
@@ -0,0 +1,53 @@
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+function test = test_run(test)
+
+if exist(test.ex) == 2
+	%fcmd = sprintf('file %s', test.ex);
+	%[status, output]=system(fcmd);
+	%if findstr(output, "Tensilica Xtensa")
+	%	ex = sprintf('xt-run --turbo --summary %s', test.ex);
+	%else
+		ex = test.ex;
+	%end
+else
+        error('Can''t find executable %s', test.ex);
+end
+test.narg = length(test.arg);
+arg = '';
+for n=1:test.narg
+        arg = sprintf('%s %s', arg, char(test.arg(n)));
+end
+rcmd = sprintf('%s %s', ex, arg);
+fprintf('Running ''%s''...\n', rcmd);
+system(rcmd);
+
+end
diff --git a/test/test_utils/write_test_data.m b/test/test_utils/write_test_data.m
new file mode 100644
index 0000000..e998fff
--- /dev/null
+++ b/test/test_utils/write_test_data.m
@@ -0,0 +1,71 @@
+function write_test_data(x, fn, bits, fmt)
+
+%%
+% Copyright (c) 2017, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+switch lower(fmt)
+	case 'raw'
+		fh = fopen(fn, 'wb');
+	case 'txt'
+		fh = fopen(fn, 'w');
+	otherwise
+		error('The file format must be raw or txt');
+end
+switch bits
+	case 16
+		bfmt = 'int16';
+	case 24
+		bfmt = 'int32';
+	case 32
+		bfmt = 'int32';
+	otherwise
+		error('The bits must be set to 16, 24, or 32');
+end
+
+%% Interleave the channels if two or more
+sx = size(x);
+xi = zeros(sx(1)*sx(2), 1, bfmt);
+if sx(2) > 1
+        for n=1:sx(2)
+                xi(n:sx(2):end) = x(:,n);
+        end
+else
+	xi(1:end) = x;
+end
+
+%% Write file and close
+if strcmp(lower(fmt), 'raw')
+	fwrite(fh, xi, bfmt);
+else
+	fprintf(fh,'%d\n', xi);
+end
+fclose(fh);
+
+end
diff --git a/topology/Makefile.am b/topology/Makefile.am
new file mode 100644
index 0000000..207e520
--- /dev/null
+++ b/topology/Makefile.am
@@ -0,0 +1,74 @@
+
+#
+# Dependencies
+#
+
+SUBDIRS = m4 sof common platform
+
+DEPS = \
+	platform/intel/*.m4 \
+	platform/common/*.m4 \
+	common/*.m4 \
+	m4/*.m4 \
+	sof/*.m4
+
+#
+# Machines
+#
+
+MACHINES = \
+	sof-cht-nocodec.tplg \
+	sof-cht-max98090.tplg \
+	sof-apl-hdmi.tplg \
+	sof-apl-nocodec.tplg \
+	sof-byt-nocodec.tplg \
+	sof-bdw-rt286.tplg \
+	sof-bdw-rt5640.tplg \
+	sof-byt-rt5640.tplg \
+	sof-byt-rt5645.tplg \
+	sof-byt-rt5651.tplg \
+	sof-byt-da7213.tplg \
+	sof-cnl-rt274.tplg \
+	sof-hsw-rt5640.tplg \
+	sof-apl-tdf8532.tplg \
+	sof-apl-pcm512x.tplg \
+	sof-apl-wm8804.tplg \
+	sof-apl-da7219.tplg \
+	sof-glk-da7219.tplg \
+	sof-icl-nocodec.tplg
+
+# Uncomment the following line if you want to debug conf files
+.PRECIOUS: %.conf
+
+%.conf : %.m4 ${DEPS}
+	m4 -I m4 -I common -I platform/common $< > $@
+
+%.tplg : %.conf
+	alsatplg -v 1 -c $< -o $@
+
+all: ${MACHINES}
+
+clean-local:
+	rm -f *.conf
+	rm -f *.tplg
+
+EXTRA_DIST = \
+	sof-cht-nocodec.m4 \
+	sof-cht-max98090.m4 \
+	sof-apl-hdmi.m4 \
+	sof-apl-nocodec.m4 \
+	sof-byt-nocodec.m4 \
+	sof-bdw-rt286.m4 \
+	sof-bdw-rt5640.m4 \
+	sof-byt-rt5640.m4 \
+	sof-byt-rt5645.m4 \
+	sof-byt-rt5651.m4 \
+	sof-byt-da7213.m4 \
+	sof-cnl-rt274.m4 \
+	sof-hsw-rt5640.m4 \
+	sof-apl-tdf8532.m4 \
+	sof-apl-pcm512x.m4 \
+	sof-apl-wm8804.m4 \
+	sof-apl-da7219.m4 \
+	sof-glk-da7219.m4 \
+	sof-icl-nocodec.m4
diff --git a/topology/common/Makefile.am b/topology/common/Makefile.am
new file mode 100644
index 0000000..7e207a7
--- /dev/null
+++ b/topology/common/Makefile.am
@@ -0,0 +1,4 @@
+EXTRA_DIST = \
+	tlv.m4 \
+	memory.m4
+
diff --git a/topology/common/memory.m4 b/topology/common/memory.m4
new file mode 100644
index 0000000..0852dff
--- /dev/null
+++ b/topology/common/memory.m4
@@ -0,0 +1,15 @@
+dnl
+dnl Memory capabilities.
+dnl
+dnl These are ORed together to create a capability mask that's sent to the
+dnl SOF firmware when creating buffer or allocating other memory resources.
+dnl
+dnl ** Must match SOF_MEM_CAPS_ values in ipc.h **
+
+define(`MEM_CAP_RAM', eval(1 << 0))
+define(`MEM_CAP_ROM', eval(1 << 1))
+define(`MEM_CAP_EXT', eval(1 << 2))
+define(`MEM_CAP_LP', eval(1 << 3))
+define(`MEM_CAP_HP', eval(1 << 4))
+define(`MEM_CAP_DMA', eval(1 << 5))
+define(`MEM_CAP_CACHE', eval(1 << 6))
diff --git a/topology/common/tlv.m4 b/topology/common/tlv.m4
new file mode 100644
index 0000000..f1a9eff
--- /dev/null
+++ b/topology/common/tlv.m4
@@ -0,0 +1,14 @@
+# TLV
+#
+# Common TLV control ranges
+#
+
+SectionTLV."vtlv_m90s3" {
+	Comment "-64dB step 2dB"
+
+	scale {
+		min "-6400"
+		step "200"
+		mute "1"
+	}
+}
diff --git a/topology/m4/Makefile.am b/topology/m4/Makefile.am
new file mode 100644
index 0000000..4d74cef
--- /dev/null
+++ b/topology/m4/Makefile.am
@@ -0,0 +1,12 @@
+EXTRA_DIST = \
+	buffer.m4 \
+	dai.m4 \
+	hda.m4 \
+	mixer.m4 \
+	mixercontrol.m4 \
+	pcm.m4 \
+	pga.m4 \
+	pipeline.m4 \
+	src.m4 \
+	tone.m4 \
+	utils.m4
diff --git a/topology/m4/buffer.m4 b/topology/m4/buffer.m4
new file mode 100644
index 0000000..55dd065
--- /dev/null
+++ b/topology/m4/buffer.m4
@@ -0,0 +1,32 @@
+divert(-1)
+
+dnl Define the macro for buffer widget
+
+dnl Buffer name)
+define(`N_BUFFER', `BUF'PIPELINE_ID`.'$1)
+
+dnl W_BUFFER(name, size, capabilities)
+define(`W_BUFFER',
+`SectionVendorTuples."'N_BUFFER($1)`_tuples" {'
+`	tokens "sof_buffer_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_BUF_SIZE'	STR($2)
+`		SOF_TKN_BUF_CAPS'	STR($3)
+`	}'
+`}'
+`SectionData."'N_BUFFER($1)`_data" {'
+`	tuples "'N_BUFFER($1)`_tuples"'
+`}'
+`SectionWidget."'N_BUFFER($1)`" {'
+`	index "'PIPELINE_ID`"'
+`	type "buffer"'
+`	no_pm "true"'
+`	data ['
+`		"'N_BUFFER($1)`_data"'
+`	]'
+`}')
+
+dnl COMP_BUFFER_SIZE( num_periods, sample_size, channels, fmames)
+define(`COMP_BUFFER_SIZE', `eval(`$1 * $2 * $3 * $4')')
+
+divert(0)dnl
diff --git a/topology/m4/dai.m4 b/topology/m4/dai.m4
new file mode 100644
index 0000000..7471718
--- /dev/null
+++ b/topology/m4/dai.m4
@@ -0,0 +1,199 @@
+divert(-1)
+
+include(`debug.m4')
+
+dnl Define macros for DAI IN/OUT widgets and DAI config
+
+dnl DAI name)
+define(`N_DAI', DAI_NAME)
+define(`N_DAI_OUT', DAI_NAME`.OUT')
+define(`N_DAI_IN', DAI_NAME`.IN')
+
+dnl W_DAI_OUT(type, index, dai_link, format, periods_sink, periods_source, preload)
+define(`W_DAI_OUT',
+`SectionVendorTuples."'N_DAI_OUT($2)`_tuples_w_comp" {'
+`	tokens "sof_comp_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_COMP_PERIOD_SINK_COUNT'		STR($5)
+`		SOF_TKN_COMP_PERIOD_SOURCE_COUNT'	STR($6)
+`		SOF_TKN_COMP_PRELOAD_COUNT'		STR($7)
+`	}'
+`}'
+`SectionData."'N_DAI_OUT($2)`_data_w_comp" {'
+`	tuples "'N_DAI_OUT($2)`_tuples_w_comp"'
+`}'
+`SectionVendorTuples."'N_DAI_OUT($2)`_tuples_w" {'
+`	tokens "sof_dai_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_DAI_INDEX'	$2
+`	}'
+`}'
+`SectionData."'N_DAI_OUT($2)`_data_w" {'
+`	tuples "'N_DAI_OUT($2)`_tuples_w"'
+`}'
+`SectionVendorTuples."'N_DAI_OUT($2)`_tuples_str" {'
+`	tokens "sof_dai_tokens"'
+`	tuples."string" {'
+`		SOF_TKN_DAI_TYPE'	$1
+`	}'
+`}'
+`SectionData."'N_DAI_OUT($2)`_data_str" {'
+`	tuples "'N_DAI_OUT($2)`_tuples_str"'
+`}'
+`SectionVendorTuples."'N_DAI_OUT($2)`_tuples_comp_str" {'
+`	tokens "sof_comp_tokens"'
+`	tuples."string" {'
+`		SOF_TKN_COMP_FORMAT'	STR($4)
+`	}'
+`}'
+`SectionData."'N_DAI_OUT($2)`_data_comp_str" {'
+`	tuples "'N_DAI_OUT($2)`_tuples_comp_str"'
+`}'
+`SectionWidget."'N_DAI_OUT`" {'
+`	index "'PIPELINE_ID`"'
+`	type "dai_in"'
+`	stream_name' STR($3)
+`	no_pm "true"'
+`	data ['
+`		"'N_DAI_OUT($2)`_data_w"'
+`		"'N_DAI_OUT($2)`_data_w_comp"'
+`		"'N_DAI_OUT($2)`_data_str"'
+`		"'N_DAI_OUT($2)`_data_comp_str"'
+`	]'
+`}')
+
+dnl W_DAI_IN(type, index, dai_link, format, periods_sink, periods_source, preload)
+define(`W_DAI_IN',
+`SectionVendorTuples."'N_DAI_IN($2)`_tuples_w_comp" {'
+`	tokens "sof_comp_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_COMP_PERIOD_SINK_COUNT'		STR($5)
+`		SOF_TKN_COMP_PERIOD_SOURCE_COUNT'	STR($6)
+`		SOF_TKN_COMP_PRELOAD_COUNT'		STR($7)
+`	}'
+`}'
+`SectionData."'N_DAI_IN($2)`_data_w_comp" {'
+`	tuples "'N_DAI_IN($2)`_tuples_w_comp"'
+`}'
+`SectionVendorTuples."'N_DAI_IN($2)`_tuples_w" {'
+`	tokens "sof_dai_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_DAI_INDEX'	$2
+`	}'
+`}'
+`SectionData."'N_DAI_IN($2)`_data_w" {'
+`	tuples "'N_DAI_IN($2)`_tuples_w"'
+`}'
+`SectionVendorTuples."'N_DAI_IN($2)`_tuples_str" {'
+`	tokens "sof_dai_tokens"'
+`	tuples."string" {'
+`		SOF_TKN_DAI_TYPE'	$1
+`	}'
+`}'
+`SectionData."'N_DAI_IN($2)`_data_str" {'
+`	tuples "'N_DAI_IN($2)`_tuples_str"'
+`}'
+`SectionVendorTuples."'N_DAI_IN($2)`_tuples_comp_str" {'
+`	tokens "sof_comp_tokens"'
+`	tuples."string" {'
+`		SOF_TKN_COMP_FORMAT'	STR($4)
+`	}'
+`}'
+`SectionData."'N_DAI_IN($2)`_data_comp_str" {'
+`	tuples "'N_DAI_IN($2)`_tuples_comp_str"'
+`}'
+`SectionWidget."'N_DAI_IN`" {'
+`	index "'PIPELINE_ID`"'
+`	type "dai_out"'
+`	stream_name' STR($3)
+`	no_pm "true"'
+`	data ['
+`		"'N_DAI_IN($2)`_data_w"'
+`		"'N_DAI_IN($2)`_data_w_comp"'
+`		"'N_DAI_IN($2)`_data_str"'
+`		"'N_DAI_IN($2)`_data_comp_str"'
+`	]'
+`}')
+
+dnl D_DAI(id, playback, capture, data))
+define(`D_DAI', `SectionDAI."'N_DAI`" {'
+`	index "'PIPELINE_ID`"'
+`	id "'$1`"'
+`	playback "'$2`"'
+`	capture "'$3`"'
+`}')
+
+dnl DAI Config)
+define(`N_DAI_CONFIG', `DAICONFIG.'$1)
+
+dnl DAI_CONFIG(type, idx, link_id, name, ssp_config/dmic_config)
+define(`DAI_CONFIG',
+`SectionHWConfig."'$1$2`" {'
+`'
+`	id		"'$3`"'
+`'
+`	ifelse($1, `SSP', $5, `}')'
+`ifelse($1, `DMIC', $5, `')'
+`SectionVendorTuples."'N_DAI_CONFIG($1$2)`_tuples_common" {'
+`	tokens "sof_dai_tokens"'
+`	tuples."string" {'
+`		SOF_TKN_DAI_TYPE'		STR($1)
+`	}'
+`	tuples."word" {'
+`		SOF_TKN_DAI_INDEX'		STR($2)
+`	}'
+`}'
+`SectionData."'N_DAI_CONFIG($1$2)`_data_common" {'
+`	tuples "'N_DAI_CONFIG($1$2)`_tuples_common"'
+`}'
+`'
+`SectionBE."'$4`" {'
+`	id "'$3`"'
+`	index "0"'
+`	default_hw_conf_id	"'$3`"'
+`'
+`	hw_configs ['
+`		"'$1$2`"'
+`	]'
+`	data ['
+`		"'N_DAI_CONFIG($1$2)`_data"'
+`		"'N_DAI_CONFIG($1$2)`_data_common"'
+`ifelse($1, `DMIC',`		"'N_DAI_CONFIG($1$2)`_pdm_data"', `')'
+`	]'
+`}'
+`DEBUG_DAI_CONFIG($1, $3)'
+)
+
+dnl DAI_ADD(pipeline,
+dnl     pipe id, dai type, dai_index, dai_be,
+dnl     buffer, periods, format,
+dnl     frames, deadline, priority, core)
+define(`DAI_ADD',
+`undefine(`PIPELINE_ID')'
+`undefine(`DAI_TYPE')'
+`undefine(`DAI_INDEX')'
+`undefine(`DAI_BE')'
+`undefine(`DAI_BUF')'
+`undefine(`DAI_PERIODS')'
+`undefine(`DAI_FORMAT')'
+`undefine(`SCHEDULE_FRAMES')'
+`undefine(`SCHEDULE_DEADLINE')'
+`undefine(`SCHEDULE_PRIORITY')'
+`undefine(`SCHEDULE_CORE')'
+`define(`PIPELINE_ID', $2)'
+`define(`DAI_TYPE', STR($3))'
+`define(`DAI_INDEX', STR($4))'
+`define(`DAI_BE', $5)'
+`define(`DAI_BUF', $6)'
+`define(`DAI_NAME', $3$4)'
+`define(`DAI_PERIODS', $7)'
+`define(`DAI_FORMAT', $8)'
+`define(`SCHEDULE_FRAMES', $9)'
+`define(`SCHEDULE_DEADLINE', $10)'
+`define(`SCHEDULE_PRIORITY', $11)'
+`define(`SCHEDULE_CORE', $12)'
+`include($1)'
+`DEBUG_DAI($3, $4)'
+)
+
+divert(0)dnl
diff --git a/topology/m4/debug.m4 b/topology/m4/debug.m4
new file mode 100644
index 0000000..6cd16c8
--- /dev/null
+++ b/topology/m4/debug.m4
@@ -0,0 +1,29 @@
+divert(-1)
+
+define(`DEBUG_START',
+`ifdef(`GRAPH', `errprint(`digraph topology {
+node [color=Red,fontname=Courier]
+edge [color=Blue, style=dashed]'
+)')')
+
+define(`DEBUG_END',
+`ifdef(`GRAPH', `errprint(`}'
+)')')
+
+define(`DEBUG_GRAPH',
+`ifdef(`GRAPH', `errprint("$2"->"$1"
+)')')
+
+define(`DEBUG_DAI',
+`ifdef(`INFO', `errprint(/* note: $1 DAI ADD dai_index $2 should match the member (index) in struct dai array (firmware platform specific, usually in dai.c) */
+)')')
+
+define(`DEBUG_DAI_CONFIG',
+`ifdef(`INFO', `errprint(/* note: $1 DAI CONFIG id $2 should match the member (id) in struct snd_soc_dai_link in kernel machine driver (usually under linux/sound/soc/intel/boards/) */
+)')')
+
+define(`DEBUG_PCM_ADD',
+`ifdef(`INFO', `errprint(/* note: PCM ADD for $1 id $2 should be unique within playback or capture pcm ids*/
+)')')
+
+divert(0)dnl
diff --git a/topology/m4/hda.m4 b/topology/m4/hda.m4
new file mode 100644
index 0000000..dcce69f
--- /dev/null
+++ b/topology/m4/hda.m4
@@ -0,0 +1,22 @@
+dnl HDA_DAI_CONFIG(idx, link_id, name)
+define(`HDA_DAI_CONFIG',
+`SectionVendorTuples."'N_DAI_CONFIG(HDA$1)`_tuples_common" {'
+`       tokens "sof_dai_tokens"'
+`       tuples."string" {'
+`               SOF_TKN_DAI_TYPE                "HDA"'
+`       }'
+`       tuples."word" {'
+`               SOF_TKN_DAI_INDEX'              STR($1)
+`       }'
+`}'
+`SectionData."'N_DAI_CONFIG(HDA$1)`_data_common" {'
+`       tuples "'N_DAI_CONFIG(HDA$1)`_tuples_common"'
+`}'
+`'
+`SectionBE."'$3`" {'
+`       id "'$2`"'
+`       index "0"'
+`       data ['
+`               "'N_DAI_CONFIG(HDA$1)`_data_common"'
+`       ]'
+`}')
diff --git a/topology/m4/mixer.m4 b/topology/m4/mixer.m4
new file mode 100644
index 0000000..1f2376e
--- /dev/null
+++ b/topology/m4/mixer.m4
@@ -0,0 +1,43 @@
+divert(-1)
+
+dnl Define macro for Mixer widget
+
+dnl Mixer Name)
+define(`N_MIXER', `MIXER'PIPELINE_ID`.'$1)
+
+dnl Pipe Buffer name in pipeline (pipeline, buffer)
+define(`NPIPELINE_MIXER', `MIXER'$1`.'$2)
+
+dnl W_MIXER(name, format, periods_sink, periods_source, preload)
+define(`W_MIXER',
+`SectionVendorTuples."'N_MIXER($1)`_tuples_w" {'
+`	tokens "sof_comp_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_COMP_PERIOD_SINK_COUNT'		STR($3)
+`		SOF_TKN_COMP_PERIOD_SOURCE_COUNT'	STR($4)
+`		SOF_TKN_COMP_PRELOAD_COUNT'		STR($5)
+`	}'
+`}'
+`SectionData."'N_MIXER($1)`_data_w" {'
+`	tuples "'N_MIXER($1)`_tuples_w"'
+`}'
+`SectionVendorTuples."'N_MIXER($1)`_tuples_str" {'
+`	tokens "sof_comp_tokens"'
+`	tuples."string" {'
+`		SOF_TKN_COMP_FORMAT'	STR($2)
+`	}'
+`}'
+`SectionData."'N_MIXER($1)`_data_str" {'
+`	tuples "'N_MIXER($1)`_tuples_str"'
+`}'
+`SectionWidget."'N_MIXER($1)`" {'
+`	index "'PIPELINE_ID`"'
+`	type "mixer"'
+`	no_pm "true"'
+`	data ['
+`		"'N_MIXER($1)`_data_w"'
+`		"'N_MIXER($1)`_data_str"'
+`	]'
+`}')
+
+divert(0)dnl
diff --git a/topology/m4/mixercontrol.m4 b/topology/m4/mixercontrol.m4
new file mode 100644
index 0000000..a3423c3
--- /dev/null
+++ b/topology/m4/mixercontrol.m4
@@ -0,0 +1,49 @@
+divert(-1)
+
+dnl Define macro for mixer control
+
+dnl KCONTROL_CHANNEL(name, reg, shift)
+define(`KCONTROL_CHANNEL',
+`channel.STR($1) {'
+`		reg STR($2)'
+`		shift STR($3)'
+`	}')
+
+dnl CONTROLMIXER_MAX(comment, value)
+define(`CONTROLMIXER_MAX',
+`#$1'
+`	max STR($2)')
+
+dnl CONTROLMIXER_TLV(comment, value)
+define(`CONTROLMIXER_TLV',
+`#$1'
+`	tlv STR($2)')
+
+dnl CONTROLMIXER_OPS(info, comment, get, put)
+define(`CONTROLMIXER_OPS',
+`ops."ctl" {'
+`		info STR($1)'
+`		#$2'
+`		get STR($3)'
+`		put STR($4)'
+`	}')
+
+dnl C_CONTROLMIXER(name, index, ops, max, invert, tlv, KCONTROL_CHANNELS)
+define(`C_CONTROLMIXER',
+`SectionControlMixer."$1 PIPELINE_ID" {'
+`'
+`	# control belongs to this index group'
+`	index STR($2)'
+`'
+`	#$7'
+`	$8'
+`	# control uses bespoke driver get/put/info ID'
+`	$3'
+`'
+`	$4'
+`	invert STR($5)'
+`	$6'
+
+`}')
+
+divert(0)dnl
diff --git a/topology/m4/pcm.m4 b/topology/m4/pcm.m4
new file mode 100644
index 0000000..f8b4ee6
--- /dev/null
+++ b/topology/m4/pcm.m4
@@ -0,0 +1,130 @@
+divert(-1)
+
+dnl Define the macro for PCM playback/capture/capabilities
+
+dnl PCM name)
+define(`N_PCMP', `PCM'$1`P')
+define(`N_PCMC', `PCM'$1`C')
+
+dnl W_PCM_PLAYBACK(pcm, stream, periods_sink, periods_source, preload)
+dnl  PCM platform configuration
+define(`W_PCM_PLAYBACK',
+`SectionVendorTuples."'N_PCMP($1)`_tuples_w_comp" {'
+`	tokens "sof_comp_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_COMP_PERIOD_SINK_COUNT'		STR($3)
+`		SOF_TKN_COMP_PERIOD_SOURCE_COUNT'	STR($4)
+`		SOF_TKN_COMP_PRELOAD_COUNT'		STR($5)
+`	}'
+`}'
+`SectionData."'N_PCMP($1)`_data_w_comp" {'
+`	tuples "'N_PCMP($1)`_tuples_w_comp"'
+`}'
+`SectionWidget."'N_PCMP($1)`" {'
+`	index "'PIPELINE_ID`"'
+`	type "aif_in"'
+`	no_pm "true"'
+`	stream_name "'$2` '$1`"'
+`	data ['
+`		"'N_PCMP($1)`_data_w_comp"'
+`	]'
+`}')
+
+
+dnl W_PCM_CAPTURE(pcm, stream, periods_sink, periods_source, preload)
+define(`W_PCM_CAPTURE',
+`SectionVendorTuples."'N_PCMC($1)`_tuples_w_comp" {'
+`	tokens "sof_comp_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_COMP_PERIOD_SINK_COUNT'		STR($3)
+`		SOF_TKN_COMP_PERIOD_SOURCE_COUNT'	STR($4)
+`		SOF_TKN_COMP_PRELOAD_COUNT'		STR($5)
+`	}'
+`}'
+`SectionData."'N_PCMC($1)`_data_w_comp" {'
+`	tuples "'N_PCMC($1)`_tuples_w_comp"'
+`}'
+`SectionWidget."'N_PCMC($1)`" {'
+`	index "'PIPELINE_ID`"'
+`	type "aif_out"'
+`	no_pm "true"'
+`	stream_name "'$2` '$1`"'
+`	data ['
+`		"'N_PCMC($1)`_data_w_comp"'
+`	]'
+`}')
+
+dnl PCM_CAPABILITIES(name, formats, rate_min, rate_max, channels_min, channels_max, periods_min, periods_max, period_size_min, period_size_max, buffer_size_min, buffer_size_max)
+define(`PCM_CAPABILITIES',
+`SectionPCMCapabilities.STR($1) {'
+`'
+`	formats "$2"'
+`	rate_min STR($3)'
+`	rate_max STR($4)'
+`	channels_min STR($5)'
+`	channels_max STR($6)'
+`	periods_min STR($7)'
+`	periods_max STR($8)'
+`	period_size_min	STR($9)'
+`	period_size_max	STR($10)'
+`	buffer_size_min	STR($11)'
+`	buffer_size_max	STR($12)'
+`}')
+
+dnl PCM_PLAYBACK_ADD(name, pcm_id, playback)
+define(`PCM_PLAYBACK_ADD',
+`SectionPCM.STR($1) {'
+`'
+`	# used for binding to the PCM'
+`	id STR($2)'
+`'
+`	dai.STR($1 $2) {'
+`		id STR($2)'
+`	}'
+`'
+`	pcm."playback" {'
+`'
+`		capabilities STR($3)'
+`	}'
+`}')
+
+dnl PCM_CAPTURE_ADD(name, pcm_id, capture)
+define(`PCM_CAPTURE_ADD',
+`SectionPCM.STR($1) {'
+`'
+`	# used for binding to the PCM'
+`	id STR($2)'
+`'
+`	dai.STR($1 $2) {'
+`		id STR($2)'
+`	}'
+`'
+`	pcm."capture" {'
+`'
+`		capabilities STR($3)'
+`	}'
+`}')
+
+dnl PCM_DUPLEX_ADD(name, pcm_id, playback, capture)
+define(`PCM_DUPLEX_ADD',
+`SectionPCM.STR($1) {'
+`'
+`	# used for binding to the PCM'
+`	id STR($2)'
+`'
+`	dai.STR($1 $2) {'
+`		id STR($2)'
+`	}'
+`'
+`	pcm."capture" {'
+`'
+`		capabilities STR($4)'
+`	}'
+`'
+`	pcm."playback" {'
+`'
+`		capabilities STR($3)'
+`	}'
+`}')
+
+divert(0)dnl
diff --git a/topology/m4/pga.m4 b/topology/m4/pga.m4
new file mode 100644
index 0000000..f38f820
--- /dev/null
+++ b/topology/m4/pga.m4
@@ -0,0 +1,44 @@
+divert(-1)
+
+dnl Define macro for PGA widget
+
+dnl PGA name)
+define(`N_PGA', `PGA'PIPELINE_ID`.'$1)
+
+dnl W_PGA(name, format, periods_sink, periods_source, preload, kcontrol0. kcontrol1...etc)
+define(`W_PGA',
+`SectionVendorTuples."'N_PGA($1)`_tuples_w" {'
+`	tokens "sof_comp_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_COMP_PERIOD_SINK_COUNT'		STR($3)
+`		SOF_TKN_COMP_PERIOD_SOURCE_COUNT'	STR($4)
+`		SOF_TKN_COMP_PRELOAD_COUNT'		STR($5)
+`	}'
+`}'
+`SectionData."'N_PGA($1)`_data_w" {'
+`	tuples "'N_PGA($1)`_tuples_w"'
+`}'
+`SectionVendorTuples."'N_PGA($1)`_tuples_str" {'
+`	tokens "sof_comp_tokens"'
+`	tuples."string" {'
+`		SOF_TKN_COMP_FORMAT'	STR($2)
+`	}'
+`}'
+`SectionData."'N_PGA($1)`_data_str" {'
+`	tuples "'N_PGA($1)`_tuples_str"'
+`}'
+`SectionWidget."'N_PGA($1)`" {'
+`	index "'PIPELINE_ID`"'
+`	type "pga"'
+`	no_pm "true"'
+`	data ['
+`		"'N_PGA($1)`_data_w"'
+`		"'N_PGA($1)`_data_str"'
+`	]'
+`	mixer ['
+		$6
+`	]'
+
+`}')
+
+divert(0)dnl
diff --git a/topology/m4/pipeline.m4 b/topology/m4/pipeline.m4
new file mode 100644
index 0000000..7c1f307
--- /dev/null
+++ b/topology/m4/pipeline.m4
@@ -0,0 +1,112 @@
+divert(-1)
+
+dnl Define macro for pipeline widget
+
+dnl Pipeline name)
+define(`N_PIPELINE', `PIPELINE.'PIPELINE_ID`.'$1)
+
+dnl W_PIPELINE(stream, deadline, priority, frames, core, timer, platform)
+define(`W_PIPELINE',
+`SectionVendorTuples."'N_PIPELINE($1)`_tuples" {'
+`	tokens "sof_sched_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_SCHED_DEADLINE'		STR($2)
+`		SOF_TKN_SCHED_PRIORITY'		STR($3)
+`		SOF_TKN_SCHED_CORE'		STR($5)
+`		SOF_TKN_SCHED_FRAMES'		STR($4)
+`		SOF_TKN_SCHED_TIMER'		STR($6)
+`	}'
+`}'
+`SectionData."'N_PIPELINE($1)`_data" {'
+`	tuples "'N_PIPELINE($1)`_tuples"'
+`}'
+`SectionWidget."'N_PIPELINE($1)`" {'
+`	index "'PIPELINE_ID`"'
+`	type "scheduler"'
+`	no_pm "true"'
+`	stream_name "'$1`"'
+`	data ['
+`		"'N_PIPELINE($1)`_data"'
+`		"'$7`"'
+`	]'
+`}')
+
+dnl PIPELINE_PCM_ADD(pipeline,
+dnl     pipe id, pcm, max channels, format,
+dnl     frames, deadline, priority, core)
+define(`PIPELINE_PCM_ADD',
+`undefine(`PCM_ID')'
+`undefine(`PIPELINE_ID')'
+`undefine(`PIPELINE_CHANNELS')'
+`undefine(`PIPELINE_FORMAT')'
+`undefine(`SCHEDULE_FRAMES')'
+`undefine(`SCHEDULE_DEADLINE')'
+`undefine(`SCHEDULE_PRIORITY')'
+`undefine(`SCHEDULE_CORE')'
+`define(`PIPELINE_ID', $2)'
+`define(`PCM_ID', $3)'
+`define(`PIPELINE_CHANNELS', $4)'
+`define(`PIPELINE_FORMAT', $5)'
+`define(`SCHEDULE_FRAMES', $6)'
+`define(`SCHEDULE_DEADLINE', $7)'
+`define(`SCHEDULE_PRIORITY', $8)'
+`define(`SCHEDULE_CORE', $9)'
+`include($1)'
+`DEBUG_PCM_ADD($1, $3)'
+)
+
+dnl PIPELINE_PCM_DAI_ADD(pipeline,
+dnl     pipe id, pcm, max channels, format,
+dnl     frames, deadline, priority, core,
+dnl     dai type, dai_index, dai format, periods)
+define(`PIPELINE_PCM_DAI_ADD',
+`undefine(`PCM_ID')'
+`undefine(`PIPELINE_ID')'
+`undefine(`PIPELINE_CHANNELS')'
+`undefine(`PIPELINE_FORMAT')'
+`undefine(`SCHEDULE_FRAMES')'
+`undefine(`SCHEDULE_DEADLINE')'
+`undefine(`SCHEDULE_PRIORITY')'
+`undefine(`SCHEDULE_CORE')'
+`undefine(`DAI_TYPE')'
+`undefine(`DAI_INDEX')'
+`undefine(`DAI_FORMAT')'
+`undefine(`DAI_PERIODS')'
+`define(`PIPELINE_ID', $2)'
+`define(`PCM_ID', $3)'
+`define(`PIPELINE_CHANNELS', $4)'
+`define(`PIPELINE_FORMAT', $5)'
+`define(`SCHEDULE_FRAMES', $6)'
+`define(`SCHEDULE_DEADLINE', $7)'
+`define(`SCHEDULE_PRIORITY', $8)'
+`define(`SCHEDULE_CORE', $9)'
+`define(`DAI_TYPE', STR($10))'
+`define(`DAI_INDEX', STR($11))'
+`define(`DAI_FORMAT', $12)'
+`define(`DAI_PERIODS', $13)'
+`define(`DAI_NAME', $10$11)'
+`include($1)'
+)
+
+dnl PIPELINE_ADD(pipeline,
+dnl     pipe id, max channels, format,
+dnl     frames, deadline, priority, core)
+define(`PIPELINE_ADD',
+`undefine(`PIPELINE_ID')'
+`undefine(`PIPELINE_CHANNELS')'
+`undefine(`PIPELINE_FORMAT')'
+`undefine(`SCHEDULE_FRAMES')'
+`undefine(`SCHEDULE_DEADLINE')'
+`undefine(`SCHEDULE_PRIORITY')'
+`undefine(`SCHEDULE_CORE')'
+`define(`PIPELINE_ID', $2)'
+`define(`PIPELINE_CHANNELS', $3)'
+`define(`PIPELINE_FORMAT', $4)'
+`define(`SCHEDULE_FRAMES', $5)'
+`define(`SCHEDULE_DEADLINE', $6)'
+`define(`SCHEDULE_PRIORITY', $7)'
+`define(`SCHEDULE_CORE', $8)'
+`include($1)'
+)
+
+divert(0)dnl
diff --git a/topology/m4/src.m4 b/topology/m4/src.m4
new file mode 100644
index 0000000..aca18e3
--- /dev/null
+++ b/topology/m4/src.m4
@@ -0,0 +1,41 @@
+divert(-1)
+
+dnl Defines the macro for SRC widget
+
+dnl SRC name)
+define(`N_SRC', `SRC'PIPELINE_ID`.'$1)
+
+dnl W_SRC(name, format, periods_sink, periods_source, data, preload)
+define(`W_SRC',
+`SectionVendorTuples."'N_SRC($1)`_tuples_w" {'
+`	tokens "sof_comp_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_COMP_PERIOD_SINK_COUNT'		STR($3)
+`		SOF_TKN_COMP_PERIOD_SOURCE_COUNT'	STR($4)
+`		SOF_TKN_COMP_PRELOAD_COUNT'		STR($6)
+`	}'
+`}'
+`SectionData."'N_SRC($1)`_data_w" {'
+`	tuples "'N_SRC($1)`_tuples_w"'
+`}'
+`SectionVendorTuples."'N_SRC($1)`_tuples_str" {'
+`	tokens "sof_comp_tokens"'
+`	tuples."string" {'
+`		SOF_TKN_COMP_FORMAT'	STR($2)
+`	}'
+`}'
+`SectionData."'N_SRC($1)`_data_str" {'
+`	tuples "'N_SRC($1)`_tuples_str"'
+`}'
+`SectionWidget."'N_SRC($1)`" {'
+`	index "'PIPELINE_ID`"'
+`	type "src"'
+`	no_pm "true"'
+`	data ['
+`		"'N_SRC($1)`_data_w"'
+`		"'N_SRC($1)`_data_str"'
+`		"'$5`"'
+`	]'
+`}')
+
+divert(0)dnl
diff --git a/topology/m4/tone.m4 b/topology/m4/tone.m4
new file mode 100644
index 0000000..583134c
--- /dev/null
+++ b/topology/m4/tone.m4
@@ -0,0 +1,50 @@
+divert(-1)
+
+dnl Define macro for siggen widget
+
+dnl Tone name)
+define(`N_TONE', `TONE'PIPELINE_ID`.'$1)
+
+dnl W_TONE(name, format, periods_sink, periods_source, preload, kcontrols_list)
+define(`W_TONE',
+`SectionVendorTuples."'N_TONE($1)`_tuples_w" {'
+`	tokens "sof_comp_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_COMP_PERIOD_SINK_COUNT'		STR($3)
+`		SOF_TKN_COMP_PERIOD_SOURCE_COUNT'	STR($4)
+`		SOF_TKN_COMP_PRELOAD_COUNT'		STR($5)
+`	}'
+`}'
+`SectionVendorTuples."'N_TONE($1)`_tone_tuples_w" {'
+`	tokens "sof_tone_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_TONE_SAMPLE_RATE'		ifdef(TONE_SAMPLE_RATE, STR(TONE_SAMPLE_RATE), "48000")
+`	}'
+`}'
+`SectionData."'N_TONE($1)`_data_w" {'
+`	tuples "'N_TONE($1)`_tuples_w"'
+`	tuples "'N_TONE($1)`_tone_tuples_w"'
+`}'
+`SectionVendorTuples."'N_TONE($1)`_tuples_str" {'
+`	tokens "sof_comp_tokens"'
+`	tuples."string" {'
+`		SOF_TKN_COMP_FORMAT'	STR($2)
+`	}'
+`}'
+`SectionData."'N_TONE($1)`_data_str" {'
+`	tuples "'N_TONE($1)`_tuples_str"'
+`}'
+`SectionWidget."'N_TONE($1)`" {'
+`	index "'PIPELINE_ID`"'
+`	type "siggen"'
+`	no_pm "true"'
+`	data ['
+`		"'N_TONE($1)`_data_w"'
+`		"'N_TONE($1)`_data_str"'
+`	]'
+`	mixer ['
+		$6
+`	]'
+`}')
+
+divert(0)dnl
diff --git a/topology/m4/utils.m4 b/topology/m4/utils.m4
new file mode 100644
index 0000000..a1fe94b
--- /dev/null
+++ b/topology/m4/utils.m4
@@ -0,0 +1,114 @@
+divert(-1)
+
+include(`debug.m4')
+
+define(`concat',`$1$2')
+
+define(`STR', `"'$1`"')
+
+dnl Argument iterator.
+define(`argn', `ifelse(`$1', 1, ``$2'',
+       `argn(decr(`$1'), shift(shift($@)))')')
+
+dnl Defines a list of items from a variable number of params.
+dnl Use as last argument in a macro.
+dnl The first argument specifies the number of tabs to be added for formatting
+define(`LIST_LOOP', `argn(j,$@)
+$1ifelse(i,`2', `', `define(`i', decr(i))define(`j', incr(j))$0($@)')')
+
+define(`LIST', `pushdef(`i', $#)pushdef(`j', `2')LIST_LOOP($@)popdef(i)popdef(j)')
+
+dnl Sums a list of variable arguments. Use as last argument in macro.
+define(`SUM_LOOP', `eval(argn(j,$@)
+		ifelse(i,`1', `', `define(`i', decr(i)) define(`j', incr(j)) + $0($@)'))')
+
+dnl Memory capabilities
+define(`MEMCAPS', `pushdef(`i', $#) pushdef(`j', `1') SUM_LOOP($@)')
+
+dnl create direct DAPM/pipeline link between 2 widgets)
+define(`dapm', `"$1, , $2"'`DEBUG_GRAPH($1, $2)')
+
+dnl COMP_SAMPLE_SIZE(FMT)
+define(`COMP_SAMPLE_SIZE',
+`ifelse(
+	$1, `s16le', `2',
+	$1, `s24_4le', `4',
+	$1, `s32le', `4',
+	$1, `float', `4',
+	`4')')
+
+dnl COMP_FORMAT_NAME(FMT)
+define(`COMP_FORMAT_NAME',
+`ifelse(
+	$1, `s16le', `S16_LE',
+	$1, `s24le', `S24_LE',
+	$1, `s32le', `S32_LE',
+	$1, `float', `FLOAT_LE',
+	)')
+
+dnl P_GRAPH(name, CONNECTIONS)
+define(`P_GRAPH',
+`SectionGraph.STR($1) {'
+`	index STR($2)'
+`'
+`	lines ['
+`		$3'
+`	]'
+`}')
+
+dnl W_VENDORTUPLES(name, tokens, RATE_OUT)
+define(`W_VENDORTUPLES',
+`SectionVendorTuples.STR($1) {'
+`	tokens STR($2)'
+`'
+`	tuples."word" {'
+`		$3'
+`	}'
+`}')
+
+dnl W_DATA(name, tuples)
+define(`W_DATA',
+`SectionData.STR($1) {'
+`	tuples STR($2)'
+`}')
+
+dnl VIRTUAL_DAPM_ROUTE_OUT(name, dai type, dai index, direction, index)
+define(`VIRTUAL_DAPM_ROUTE_OUT',
+`SectionWidget.STR($1) {'
+`       index STR($5)'
+`       type "output"'
+`       no_pm "true"'
+`}'
+`SectionGraph.STR($2) {'
+`       index STR($5)'
+`'
+`       lines ['
+`               dapm($1,$2$3.$4)'
+`       ]'
+`}')
+
+dnl VIRTUAL_DAPM_ROUTE_IN(name, dai type, dai index, direction, index)
+define(`VIRTUAL_DAPM_ROUTE_IN',
+`SectionWidget.STR($1) {'
+`       index STR($5)'
+`       type "input"'
+`       no_pm "true"'
+`}'
+`SectionGraph.STR($2) {'
+`       index STR($5)'
+`'
+`       lines ['
+`               dapm($2$3.$4, $1)'
+`       ]'
+`}')
+
+dnl VIRTUAL_WIDGET(name, index)
+define(`VIRTUAL_WIDGET',
+`SectionWidget.STR($1) {'
+`       index STR($2)'
+`       type "out_drv"'
+`       no_pm "true"'
+`}')
+
+divert(0) dnl
+
diff --git a/topology/platform/Makefile.am b/topology/platform/Makefile.am
new file mode 100644
index 0000000..011ff9e
--- /dev/null
+++ b/topology/platform/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = intel common
diff --git a/topology/platform/common/Makefile.am b/topology/platform/common/Makefile.am
new file mode 100644
index 0000000..a8576d5
--- /dev/null
+++ b/topology/platform/common/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = \
+	ssp.m4
diff --git a/topology/platform/common/ssp.m4 b/topology/platform/common/ssp.m4
new file mode 100644
index 0000000..f3c7862
--- /dev/null
+++ b/topology/platform/common/ssp.m4
@@ -0,0 +1,46 @@
+divert(-1)
+
+dnl SSP related macros
+
+dnl SSP_CLOCK(clock, freq, codec_master)
+define(`SSP_CLOCK',
+	$1		STR($3)
+	$1_freq	STR($2))
+
+
+dnl SSP_TDM(slots, width, tx_mask, rx_mask)
+define(`SSP_TDM',
+`tdm_slots	'STR($1)
+`	tdm_slot_width	'STR($2)
+`	tx_slots	'STR($3)
+`	rx_slots	'STR($4)
+)
+dnl SSP_CONFIG(format, mclk, bclk, fsync, tdm, ssp_config_data)
+define(`SSP_CONFIG',
+`	format		"'$1`"'
+`	'$2
+`	'$3
+`	'$4
+`	'$5
+`}'
+$6
+)
+
+dnl SSP_CONFIG_DATA(type, idx, valid bits, mclk_id)
+dnl mclk_id is optional
+define(`SSP_CONFIG_DATA',
+`SectionVendorTuples."'N_DAI_CONFIG($1$2)`_tuples" {'
+`	tokens "sof_ssp_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_INTEL_SSP_SAMPLE_BITS'	STR($3)
+`	}'
+`	tuples."short" {'
+`		SOF_TKN_INTEL_SSP_MCLK_ID'	ifelse($4, `', "0", STR($4))
+`	}'
+`}'
+`SectionData."'N_DAI_CONFIG($1$2)`_data" {'
+`	tuples "'N_DAI_CONFIG($1$2)`_tuples"'
+`}'
+)
+
+divert(0)dnl
diff --git a/topology/platform/intel/Makefile.am b/topology/platform/intel/Makefile.am
new file mode 100644
index 0000000..bc56971
--- /dev/null
+++ b/topology/platform/intel/Makefile.am
@@ -0,0 +1,9 @@
+EXTRA_DIST = \
+	bdw.m4 \
+	bxt.m4 \
+	byt.m4 \
+	cht.m4 \
+	hsw.m4 \
+	cnl.m4 \
+	dmic.m4
+
diff --git a/topology/platform/intel/bdw.m4 b/topology/platform/intel/bdw.m4
new file mode 100644
index 0000000..1af6699
--- /dev/null
+++ b/topology/platform/intel/bdw.m4
@@ -0,0 +1,31 @@
+#
+# Broadwell differentiation for pipelines and components
+#
+
+include(`memory.m4')
+
+dnl Memory capabilities for diferent buffer types on Broadwell
+define(`PLATFORM_DAI_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_HOST_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_PASS_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE))
+
+# Low Latency PCM Configuration
+W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"50000"'))
+
+W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens)
+
+# Media PCM Configuration
+W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"100000"'))
+
+W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens)
+
+# Tone Signal Generator Configuration
+W_VENDORTUPLES(pipe_tone_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"200000"'))
+
+W_DATA(pipe_tone_schedule_plat, pipe_tone_schedule_plat_tokens)
+
+# DAI schedule Configuration - scheduled by IRQ
+W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"5000"'))
+
+W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens)
diff --git a/topology/platform/intel/bxt.m4 b/topology/platform/intel/bxt.m4
new file mode 100644
index 0000000..7626513
--- /dev/null
+++ b/topology/platform/intel/bxt.m4
@@ -0,0 +1,34 @@
+#
+# Broxton differentiation for pipelines and components
+#
+
+include(`memory.m4')
+
+dnl Memory capabilities for diferent buffer types on Baytrail
+define(`PLATFORM_DAI_MEM_CAP',
+	MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_HOST_MEM_CAP',
+	MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_PASS_MEM_CAP',
+	MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE))
+
+# Low Latency PCM Configuration
+W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"50000"'))
+
+W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens)
+
+# Media PCM Configuration
+W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"100000"'))
+
+W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens)
+
+# Tone Signal Generator Configuration
+W_VENDORTUPLES(pipe_tone_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"200000"'))
+
+W_DATA(pipe_tone_schedule_plat, pipe_tone_schedule_plat_tokens)
+
+# DAI schedule Configuration - scheduled by IRQ
+W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"5000"'))
+
+W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens)
diff --git a/topology/platform/intel/byt.m4 b/topology/platform/intel/byt.m4
new file mode 100644
index 0000000..a25d993
--- /dev/null
+++ b/topology/platform/intel/byt.m4
@@ -0,0 +1,31 @@
+#
+# Baytrail differentiation for pipelines and components
+#
+
+include(`memory.m4')
+
+dnl Memory capabilities for diferent buffer types on Baytrail
+define(`PLATFORM_DAI_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_HOST_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_PASS_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE))
+
+# Low Latency PCM Configuration
+W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"50000"'))
+
+W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens)
+
+# Media PCM Configuration
+W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"100000"'))
+
+W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens)
+
+# Tone Signal Generator Configuration
+W_VENDORTUPLES(pipe_tone_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"200000"'))
+
+W_DATA(pipe_tone_schedule_plat, pipe_tone_schedule_plat_tokens)
+
+# DAI schedule Configuration - scheduled by IRQ
+W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"5000"'))
+
+W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens)
diff --git a/topology/platform/intel/cht.m4 b/topology/platform/intel/cht.m4
new file mode 100644
index 0000000..b6317cd
--- /dev/null
+++ b/topology/platform/intel/cht.m4
@@ -0,0 +1,31 @@
+#
+# Cherrytrail differentiation for pipelines and components
+#
+
+include(`memory.m4')
+
+dnl Memory capabilities for diferent buffer types on Cherrytrail
+define(`PLATFORM_DAI_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_HOST_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_PASS_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE))
+
+# Low Latency PCM Configuration
+W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"50000"'))
+
+W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens)
+
+# Media PCM Configuration
+W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"100000"'))
+
+W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens)
+
+# Tone Signal Generator Configuration
+W_VENDORTUPLES(pipe_tone_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"200000"'))
+
+W_DATA(pipe_tone_schedule_plat, pipe_tone_schedule_plat_tokens)
+
+# DAI schedule Configuration - scheduled by IRQ
+W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"5000"'))
+
+W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens)
diff --git a/topology/platform/intel/cnl.m4 b/topology/platform/intel/cnl.m4
new file mode 100644
index 0000000..96bf6de
--- /dev/null
+++ b/topology/platform/intel/cnl.m4
@@ -0,0 +1,35 @@
+#
+# Broxton differentiation for pipelines and components
+#
+
+include(`memory.m4')
+
+dnl Memory capabilities for diferent buffer types on Cannonlake
+define(`PLATFORM_DAI_MEM_CAP',
+	MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_HOST_MEM_CAP',
+	MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_PASS_MEM_CAP',
+	MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE))
+
+# Low Latency PCM Configuration
+# Low Latency PCM Configuration
+W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"50000"'))
+
+W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens)
+
+# Media PCM Configuration
+W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"100000"'))
+
+W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens)
+
+# Tone Signal Generator Configuration
+W_VENDORTUPLES(pipe_tone_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"200000"'))
+
+W_DATA(pipe_tone_schedule_plat, pipe_tone_schedule_plat_tokens)
+
+# DAI schedule Configuration - scheduled by IRQ
+W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"5000"'))
+
+W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens)
diff --git a/topology/platform/intel/dmic.m4 b/topology/platform/intel/dmic.m4
new file mode 100644
index 0000000..7a93069
--- /dev/null
+++ b/topology/platform/intel/dmic.m4
@@ -0,0 +1,69 @@
+divert(-1)
+
+dnl  DMIC related macros
+
+dnl PDM_TUPLES(pdm ctrl id, mic_a_enable, mic_b_enable, polarity_a, polarity_b,
+dnl	       clk_egde, skew)
+define(`PDM_TUPLES',
+`	tuples."short.pdm$1" {'
+`		SOF_TKN_INTEL_DMIC_PDM_CTRL_ID'		STR($1)
+`		SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable'	STR($2)
+`		SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable'	STR($3)
+`		SOF_TKN_INTEL_DMIC_PDM_POLARITY_A'	STR($4)
+`		SOF_TKN_INTEL_DMIC_PDM_POLARITY_B'	STR($5)
+`		SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE'	STR($6)
+`		SOF_TKN_INTEL_DMIC_PDM_SKEW'		STR($7)
+`	}'
+)
+
+dnl PDM_CONFIG(type, idx, num pdm active, pdm tuples list)
+define(`PDM_CONFIG',
+`		SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE'	STR($3)
+`	}'
+`}'
+`SectionVendorTuples."'N_DAI_CONFIG($1$2)`_pdm_tuples" {'
+`	tokens "sof_dmic_pdm_tokens"'
+$4
+`}'
+)
+
+dnl DMIC currently only supports 16 bit or 32-bit word length
+dnl DMIC_WORD_LENGTH(frame format)
+define(`DMIC_WORD_LENGTH',
+`ifelse($1, `s16le', 16, $1, `s32le', 32, `')')
+
+dnl DMIC_CONFIG(driver_version, clk_min, clk_mac, duty_min, duty_max,
+dnl		sample_rate,
+dnl		fifo word length, type, idx, pdm controller config)
+define(`DMIC_CONFIG',
+`SectionVendorTuples."'N_DAI_CONFIG($8$9)`_dmic_tuples" {'
+`	tokens "sof_dmic_tokens"'
+`	tuples."word" {'
+`		SOF_TKN_INTEL_DMIC_DRIVER_VERSION'	STR($1)
+`		SOF_TKN_INTEL_DMIC_CLK_MIN'		STR($2)
+`		SOF_TKN_INTEL_DMIC_CLK_MAX'		STR($3)
+`		SOF_TKN_INTEL_DMIC_DUTY_MIN'		STR($4)
+`		SOF_TKN_INTEL_DMIC_DUTY_MAX'		STR($5)
+`		SOF_TKN_INTEL_DMIC_SAMPLE_RATE'		STR($6)
+`		SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH'	STR($7)
+dnl PDM config for the number of active PDM controllers
+$10
+`SectionData."'N_DAI_CONFIG($8$9)`_pdm_data" {'
+`	tuples "'N_DAI_CONFIG($8$9)`_pdm_tuples"'
+`}'
+`SectionData."'N_DAI_CONFIG($8$9)`_data" {'
+`	tuples "'N_DAI_CONFIG($8$9)`_dmic_tuples"'
+
+`}'
+)
+
+dnl DMIC PDM configurations
+dnl macros to get the number of active pdm's and their config
+define(`MONO_PDM0_MICA', `1, LIST(`', PDM_TUPLES(0, 1, 0, 0, 0, 0, 0))')
+define(`MONO_PDM0_MICB', `1, LIST(`', PDM_TUPLES(0, 0, 1, 0, 0, 0, 0))')
+define(`STEREO_PDM0', `1, LIST(`', PDM_TUPLES(0, 1, 1, 0, 0, 0, 0))')
+define(`STEREO_PDM1', `1, LIST(`', PDM_TUPLES(1, 1, 1, 0, 0, 0, 0))')
+define(`FOUR_CH_PDM0_PDM1',
+	`2, LIST(`', PDM_TUPLES(0, 1, 1, 0, 0, 0, 0), PDM_TUPLES(1, 1, 1, 0, 0, 0, 0))')
+
+divert(0)dnl
diff --git a/topology/platform/intel/hsw.m4 b/topology/platform/intel/hsw.m4
new file mode 100644
index 0000000..c096732
--- /dev/null
+++ b/topology/platform/intel/hsw.m4
@@ -0,0 +1,31 @@
+#
+# Haswell differentiation for pipelines and components
+#
+
+include(`memory.m4')
+
+dnl Memory capabilities for diferent buffer types on Haswell
+define(`PLATFORM_DAI_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_HOST_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_PASS_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE))
+define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE))
+
+# Low Latency PCM Configuration
+W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"50000"'))
+
+W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens)
+
+# Media PCM Configuration
+W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"100000"'))
+
+W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens)
+
+# Tone Signal Generator Configuration
+W_VENDORTUPLES(pipe_tone_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"200000"'))
+
+W_DATA(pipe_tone_schedule_plat, pipe_tone_schedule_plat_tokens)
+
+# DAI schedule Configuration - scheduled by IRQ
+W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens, LIST(`		', `SOF_TKN_SCHED_MIPS	"5000"'))
+
+W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens)
diff --git a/topology/platform/intel/icl.m4 b/topology/platform/intel/icl.m4
new file mode 100644
index 0000000..9671289
--- /dev/null
+++ b/topology/platform/intel/icl.m4
@@ -0,0 +1,38 @@
+#
+# Icelake differentiation for pipelines and components
+#
+
+include(`memory.m4')
+
+dnl Memory capabilities for different buffer types on Icelake
+define(`PLATFORM_DAI_MEM_CAP',
+	MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_HOST_MEM_CAP',
+	MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_PASS_MEM_CAP',
+	MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE, MEM_CAP_HP))
+define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE))
+
+# Low Latency PCM Configuration
+W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens,
+		LIST(`		', `SOF_TKN_SCHED_MIPS	"50000"'))
+
+W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens)
+
+# Media PCM Configuration
+W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens,
+		LIST(`		', `SOF_TKN_SCHED_MIPS	"100000"'))
+
+W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens)
+
+# Tone Signal Generator Configuration
+W_VENDORTUPLES(pipe_tone_schedule_plat_tokens, sof_sched_tokens,
+		LIST(`		', `SOF_TKN_SCHED_MIPS	"200000"'))
+
+W_DATA(pipe_tone_schedule_plat, pipe_tone_schedule_plat_tokens)
+
+# DAI schedule Configuration - scheduled by IRQ
+W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens,
+		LIST(`		', `SOF_TKN_SCHED_MIPS	"5000"'))
+
+W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens)
diff --git a/topology/sof-apl-da7219.m4 b/topology/sof-apl-da7219.m4
new file mode 100644
index 0000000..0c102fe
--- /dev/null
+++ b/topology/sof-apl-da7219.m4
@@ -0,0 +1,143 @@
+#
+# Topology for AppoloLake with headset on SSP1, spk on SSP5 and DMIC capture
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include bxt DSP configuration
+include(`platform/intel/bxt.m4')
+include(`platform/intel/dmic.m4')
+
+DEBUG_START
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume -----> SSP5 (speaker - maxim98357a)
+# PCM1 <---> volume <----> SSP1 (headset - da7219)
+# PCM99 <---- volume <----- DMIC0 (dmic capture)
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	1, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency playback pipeline 2 on PCM 1 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	2, 1, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+	3, 1, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 4 on PCM 0 using max 4 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+#PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4,
+	4, 99, 4, s32le,
+	48, 1000, 0, 0)
+
+#
+# DAIs configuration
+#
+
+# playback DAI is SSP5 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 5, SSP5-Codec,
+	PIPELINE_SOURCE_1, 2, s16le,
+	48, 1000, 0, 0)
+
+# playback DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	2, SSP, 1, SSP1-Codec,
+	PIPELINE_SOURCE_2, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	3, SSP, 1, SSP1-Codec,
+	PIPELINE_SINK_3, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is DMIC0 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	4, DMIC, 0, dmic01,
+	PIPELINE_SINK_4, 2, s32le,
+	48, 1000, 0, 0)
+
+PCM_PLAYBACK_ADD(Speakers, 0, PIPELINE_PCM_1)
+PCM_DUPLEX_ADD(Headset, 1, PIPELINE_PCM_2, PIPELINE_PCM_3)
+PCM_CAPTURE_ADD(DMIC01, 99, PIPELINE_PCM_4)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+
+#SSP 5 (ID: 0) with 19.2 MHz mclk with MCLK_ID 0 (unused), 1.536 MHz blck
+DAI_CONFIG(SSP, 5, 0, SSP5-Codec,
+	SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+		SSP_CLOCK(bclk, 1536000, codec_slave),
+		SSP_CLOCK(fsync, 48000, codec_slave),
+		SSP_TDM(2, 16, 3, 3),
+		SSP_CONFIG_DATA(SSP, 5, 16, 0)))
+
+#SSP 1 (ID: 1) with 19.2 MHz mclk with MCLK_ID 0, 1.92 MHz bclk
+DAI_CONFIG(SSP, 1, 1, SSP1-Codec,
+	SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+		SSP_CLOCK(bclk, 1920000, codec_slave),
+		SSP_CLOCK(fsync, 48000, codec_slave),
+		SSP_TDM(2, 20, 3, 3),
+		SSP_CONFIG_DATA(SSP, 1, 16, 0)))
+
+# dmic01 (id: 2)
+DAI_CONFIG(DMIC, 0, 2, dmic01,
+	DMIC_CONFIG(1, 500000, 4800000, 40, 60, 48000,
+		DMIC_WORD_LENGTH(s32le), DMIC, 0,
+		# FIXME: what is the right configuration
+		# PDM_CONFIG(DMIC, 0, FOUR_CH_PDM0_PDM1)))
+		PDM_CONFIG(DMIC, 0, STEREO_PDM0)))
+
+## remove warnings with SST hard-coded routes (FIXME)
+
+VIRTUAL_WIDGET(ssp5 Tx, 0)
+VIRTUAL_WIDGET(ssp1 Rx, 1)
+VIRTUAL_WIDGET(ssp1 Tx, 2)
+VIRTUAL_WIDGET(DMIC01 Rx, 3)
+VIRTUAL_WIDGET(DMic, 4)
+VIRTUAL_WIDGET(dmic01_hifi, 5)
+VIRTUAL_WIDGET(hif5-0 Output, 6)
+VIRTUAL_WIDGET(hif6-0 Output, 7)
+VIRTUAL_WIDGET(hif7-0 Output, 8)
+VIRTUAL_WIDGET(hifi1, 9)
+VIRTUAL_WIDGET(hifi2, 10)
+VIRTUAL_WIDGET(hifi3, 11)
+
+VIRTUAL_DAPM_ROUTE_OUT(codec0_out, SSP, 0, OUT, 12)
+VIRTUAL_DAPM_ROUTE_OUT(codec1_out, SSP, 0, OUT, 13)
+VIRTUAL_DAPM_ROUTE_OUT(ssp1 Tx, SSP, 0, OUT, 14)
+VIRTUAL_DAPM_ROUTE_IN(ssp1 Rx, SSP, 0, IN, 15)
+VIRTUAL_DAPM_ROUTE_OUT(Capture, SSP, 0, OUT, 16)
+VIRTUAL_DAPM_ROUTE_OUT(SoC DMIC, SSP, 0, OUT, 17)
+VIRTUAL_DAPM_ROUTE_IN(codec0_in, SSP, 0, IN, 18)
+
+DEBUG_END
diff --git a/topology/sof-apl-hdmi.m4 b/topology/sof-apl-hdmi.m4
new file mode 100644
index 0000000..00d7c68
--- /dev/null
+++ b/topology/sof-apl-hdmi.m4
@@ -0,0 +1,93 @@
+#
+# Topology for generic Apollolake board with no codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`hda.m4')
+include(`ssp.m4')
+include(`pipeline.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Apollolake DSP configuration
+include(`platform/intel/bxt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume -----> iDisp1
+# PCM1 ----> Volume -----> iDisp2
+# PCM2 ----> volume -----> iDisp3
+
+dnl PIPELINE_PCM_ADD(pipeline,
+dnl     pipe id, pcm, max channels, format,
+dnl     frames, deadline, priority, core)
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	1, 0, 2, s16le,
+	48, 1000, 0, 0)
+
+# Low Latency playback pipeline 2 on PCM 1 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	2, 1, 2, s16le,
+	48, 1000, 0, 0)
+
+# Low Latency playback pipeline 3 on PCM 2 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	3, 2, 2, s16le,
+	48, 1000, 0, 0)
+
+#
+# DAIs configuration
+#
+
+dnl DAI_ADD(pipeline,
+dnl     pipe id, dai type, dai_index, dai_be,
+dnl     buffer, periods, format,
+dnl     frames, deadline, priority, core)
+
+# playback DAI is iDisp1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, HDA, 0, iDisp1,
+	PIPELINE_SOURCE_1, 2, s16le,
+	48, 1000, 0, 0)
+
+# playback DAI is iDisp2 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	2, HDA, 1, iDisp2,
+	PIPELINE_SOURCE_2, 2, s16le,
+	48, 1000, 0, 0)
+
+# playback DAI is iDisp3 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	3, HDA, 2, iDisp3,
+	PIPELINE_SOURCE_3, 2, s16le,
+	48, 1000, 0, 0)
+
+
+dnl PCM_PLAYBACK_ADD(name, pcm_id, playback)
+PCM_PLAYBACK_ADD(HDMI1, 0, PIPELINE_PCM_1)
+PCM_PLAYBACK_ADD(HDMI2, 1, PIPELINE_PCM_2)
+PCM_PLAYBACK_ADD(HDMI3, 2, PIPELINE_PCM_3)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+
+dnl HDA_DAI_CONFIG(dai_index, link_id, name)
+HDA_DAI_CONFIG(0, 1, iDisp1)
+HDA_DAI_CONFIG(1, 2, iDisp2)
+HDA_DAI_CONFIG(2, 3, iDisp3)
diff --git a/topology/sof-apl-nocodec.m4 b/topology/sof-apl-nocodec.m4
new file mode 100644
index 0000000..da61ece
--- /dev/null
+++ b/topology/sof-apl-nocodec.m4
@@ -0,0 +1,290 @@
+#
+# Topology for generic Apollolake board with no codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`ssp.m4')
+include(`pipeline.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Apollolake DSP configuration
+include(`platform/intel/bxt.m4')
+include(`platform/intel/dmic.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume -----> SSP0
+#      <---- volume <----- SSP0
+# PCM1 ----> Volume <----- SSP1
+#      <---- Volume <----- SSP1
+# PCM2 ----> volume -----> SSP2
+#      <---- Volume <----- SSP2
+# PCM3 ----> volume -----> SSP3
+#      <---- volume <----- SSP3
+# PCM4 ----> volume -----> SSP4
+#      <---- Volume <----- SSP4
+# PCM5 ----> volume -----> SSP5
+#      <---- volume <----- SSP5
+# PCM6 <---- volume <----- DMIC6 (DMIC01)
+#
+
+dnl PIPELINE_PCM_ADD(pipeline,
+dnl     pipe id, pcm, max channels, format,
+dnl     frames, deadline, priority, core)
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	1, 0, 2, s16le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+	2, 0, 2, s16le,
+	48, 1000, 0, 0)
+
+# Low Latency playback pipeline 3 on PCM 1 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	3, 1, 2, s16le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 4 on PCM 1 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+	4, 1, 2, s16le,
+	48, 1000, 0, 0)
+
+# Low Latency playback pipeline 5 on PCM 2 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	5, 2, 2, s16le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 6 on PCM 2 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+	6, 2, 2, s16le,
+	48, 1000, 0, 0)
+
+# Low Latency playback pipeline 7 on PCM 3 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	7, 3, 2, s16le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 8 on PCM 3 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+	8, 3, 2, s16le,
+	48, 1000, 0, 0)
+
+# Low Latency playback pipeline 9 on PCM 4 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	9, 4, 2, s16le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 10 on PCM 4 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+	10, 4, 2, s16le,
+	48, 1000, 0, 0)
+
+# Low Latency playback pipeline 11 on PCM 5 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	11, 5, 2, s16le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 12 on PCM 5 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+	12, 5, 2, s16le,
+	48, 1000, 0, 0)
+
+# Passthrough capture pipeline 13 on PCM 6 using max 4 channels.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4,
+	13, 6, 4, s32le,
+	48, 1000, 0, 0)
+
+#
+# DAIs configuration
+#
+
+dnl DAI_ADD(pipeline,
+dnl     pipe id, dai type, dai_index, dai_be,
+dnl     buffer, periods, format,
+dnl     frames, deadline, priority, core)
+
+# playback DAI is SSP0 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 0, NoCodec-0,
+	PIPELINE_SOURCE_1, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP0 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, SSP, 0, NoCodec-0,
+	PIPELINE_SINK_2, 2, s16le,
+	48, 1000, 0, 0)
+
+# playback DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	3, SSP, 1, NoCodec-1,
+	PIPELINE_SOURCE_3, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	4, SSP, 1, NoCodec-1,
+	PIPELINE_SINK_4, 2, s16le,
+	48, 1000, 0, 0)
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	5, SSP, 2, NoCodec-2,
+	PIPELINE_SOURCE_5, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	6, SSP, 2, NoCodec-2,
+	PIPELINE_SINK_6, 2, s16le,
+	48, 1000, 0, 0)
+
+# playback DAI is SSP3 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	7, SSP, 3, NoCodec-3,
+	PIPELINE_SOURCE_7, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP3 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	8, SSP, 3, NoCodec-3,
+	PIPELINE_SINK_8, 2, s16le,
+	48, 1000, 0, 0)
+
+# playback DAI is SSP4 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	9, SSP, 4, NoCodec-4,
+	PIPELINE_SOURCE_9, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP4 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	10, SSP, 4, NoCodec-4,
+	PIPELINE_SINK_10, 2, s16le,
+	48, 1000, 0, 0)
+
+# playback DAI is SSP5 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	11, SSP, 5, NoCodec-5,
+	PIPELINE_SOURCE_11, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP5 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	12, SSP, 5, NoCodec-5,
+	PIPELINE_SINK_12, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is DMIC 0 using 2 periods
+# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	13, DMIC, 0, NoCodec-6,
+	PIPELINE_SINK_13, 2, s32le,
+	48, 1000, 0, 0)
+
+dnl PCM_DUPLEX_ADD(name, pcm_id, playback, capture)
+PCM_DUPLEX_ADD(Port0, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+PCM_DUPLEX_ADD(Port1, 1, PIPELINE_PCM_3, PIPELINE_PCM_4)
+PCM_DUPLEX_ADD(Port2, 2, PIPELINE_PCM_5, PIPELINE_PCM_6)
+PCM_DUPLEX_ADD(Port3, 3, PIPELINE_PCM_7, PIPELINE_PCM_8)
+PCM_DUPLEX_ADD(Port4, 4, PIPELINE_PCM_9, PIPELINE_PCM_10)
+PCM_DUPLEX_ADD(Port5, 5, PIPELINE_PCM_11, PIPELINE_PCM_12)
+dnl PCM_CAPTURE_ADD(name, pipeline, capture)
+PCM_CAPTURE_ADD(DMIC01, 6, PIPELINE_PCM_13)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+
+dnl DAI_CONFIG(type, dai_index, link_id, name, ssp_config/dmic_config)
+DAI_CONFIG(SSP, 0, 0, NoCodec-0,
+	   dnl SSP_CONFIG(format, mclk, bclk, fsync, tdm, ssp_config_data)
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 1536000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 16, 3, 3),
+		      dnl SSP_CONFIG_DATA(type, dai_index, valid bits, mclk_id)
+		      SSP_CONFIG_DATA(SSP, 0, 16)))
+
+DAI_CONFIG(SSP, 1, 1, NoCodec-1,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 1536000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 16, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 1, 16)))
+
+DAI_CONFIG(SSP, 2, 2, NoCodec-2,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 1536000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 16, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 2, 16)))
+
+DAI_CONFIG(SSP, 3, 3, NoCodec-3,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 1536000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 16, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 3, 16)))
+
+DAI_CONFIG(SSP, 4, 4, NoCodec-4,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 1536000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 16, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 4, 16)))
+
+DAI_CONFIG(SSP, 5, 5, NoCodec-5,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 1536000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 16, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 5, 16)))
+
+DAI_CONFIG(DMIC, 0, 6, NoCodec-6,
+	   dnl DMIC_CONFIG(driver_version, clk_min, clk_mac, duty_min, duty_max,
+	   dnl		   sample_rate,
+	   dnl		   fifo word length, type, dai_index, pdm controller config)
+	   DMIC_CONFIG(1, 500000, 4800000, 40, 60, 48000,
+		dnl DMIC_WORD_LENGTH(frame_format)
+		DMIC_WORD_LENGTH(s32le), DMIC, 0,
+		dnl PDM_CONFIG(type, dai_index, num pdm active, pdm tuples list)
+		dnl STEREO_PDM0 is a pre-defined pdm config for stereo capture
+		PDM_CONFIG(DMIC, 0, STEREO_PDM0)))
+
diff --git a/topology/sof-apl-pcm512x.m4 b/topology/sof-apl-pcm512x.m4
new file mode 100644
index 0000000..48257ae
--- /dev/null
+++ b/topology/sof-apl-pcm512x.m4
@@ -0,0 +1,59 @@
+#
+# Topology for generic Apollolake UP^2 with pcm512x codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Apollolake DSP configuration
+include(`platform/intel/bxt.m4')
+
+DEBUG_START
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume -----> SSP5 (pcm512x)
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	1, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+#
+# DAIs configuration
+#
+
+# playback DAI is SSP5 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 5, SSP5-Codec,
+	PIPELINE_SOURCE_1, 2, s24le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency, id 0
+PCM_PLAYBACK_ADD(Port5, 0, PIPELINE_PCM_1)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+
+DAI_CONFIG(SSP, 5, 0, SSP5-Codec,
+	SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+		SSP_CLOCK(bclk, 3072000, codec_slave),
+		SSP_CLOCK(fsync, 48000, codec_slave),
+		SSP_TDM(2, 32, 3, 3),
+		SSP_CONFIG_DATA(SSP, 5, 24)))
+
+DEBUG_END
diff --git a/topology/sof-apl-tdf8532.m4 b/topology/sof-apl-tdf8532.m4
new file mode 100644
index 0000000..c82c1f0
--- /dev/null
+++ b/topology/sof-apl-tdf8532.m4
@@ -0,0 +1,245 @@
+#
+# Topology for generic Apollolake board with TDF8532
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Apollolake DSP configuration
+include(`platform/intel/bxt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume -----> SSP4
+# PCM1 ----> volume -----> SSP2(Dirana Pb)
+#      <---- Volume <----- SSP2(Dirana Cp)
+# PCM2 ----> volume -----> SSP0(BT HFP out)
+#      <---- volume <----- SSP0(BT HFP in)
+# PCM3 <---- Volume <----- SSP1(HDMI in)
+# PCM4 ----> volume -----> SSP3(Modem out)
+#      <---- volume <----- SSP3(Modem in)
+# PCM5 ----> volume -----> SSP5(TestPin out)
+#      <---- volume <----- SSP3(TestPin in)
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 4 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-playback.m4,
+	1, 0, 4, s32le,
+	48, 1000, 0, 0, SSP, 4, s32le, 2)
+
+# Low Latency playback pipeline 2 on PCM 1 using max 8 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-playback.m4,
+	2, 1, 8, s32le,
+	48, 1000, 0, 0, SSP, 2, s32le, 2)
+
+# Low Latency capture pipeline 3 on PCM 1 using max 8 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-capture.m4,
+	3, 1, 8, s32le,
+	48, 1000, 0, 0, SSP, 2, s32le, 2)
+
+# Low Latency playback pipeline 4 on PCM 2 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-playback.m4,
+	4, 2, 2, s16le,
+	48, 1000, 0, 0, SSP, 0, s16le, 2)
+
+# Low Latency capture pipeline 5 on PCM 2 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-capture.m4,
+	5, 2, 2, s16le,
+	48, 1000, 0, 0, SSP, 0, s16le, 2)
+
+# Low Latency capture pipeline 6 on PCM 3 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-capture.m4,
+	6, 3, 2, s16le,
+	48, 1000, 0, 0, SSP, 1, s16le, 2)
+
+# Low Latency playback pipeline 7 on PCM 4 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-playback.m4,
+	7, 4, 2, s16le,
+	48, 1000, 0, 0, SSP, 3, s16le, 2)
+
+# Low Latency capture pipeline 8 on PCM 4 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-capture.m4,
+	8, 4, 2, s16le,
+	48, 1000, 0, 0, SSP, 3, s16le, 2)
+
+# Low Latency playback pipeline 9 on PCM 5 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-playback.m4,
+	9, 5, 2, s16le,
+	48, 1000, 0, 0, SSP, 5, s16le, 2)
+
+# Low Latency capture pipeline 10 on PCM 5 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-capture.m4,
+	10, 5, 2, s16le,
+	48, 1000, 0, 0, SSP, 5, s16le, 2)
+
+
+#
+# DAIs configuration
+#
+
+# playback DAI is SSP0 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	4, SSP, 0, SSP0-Codec,
+	PIPELINE_SOURCE_4, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP0 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	5, SSP, 0, SSP0-Codec,
+	PIPELINE_SINK_5, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	6, SSP, 1, SSP1-Codec,
+	PIPELINE_SINK_6, 2, s16le,
+	48, 1000, 0, 0)
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	2, SSP, 2, SSP2-Codec,
+	PIPELINE_SOURCE_2, 2, s32le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	3, SSP, 2, SSP2-Codec,
+	PIPELINE_SINK_3, 2, s32le,
+	48, 1000, 0, 0)
+
+# playback DAI is SSP3 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	7, SSP, 3, SSP3-Codec,
+	PIPELINE_SOURCE_7, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP3 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	8, SSP, 3, SSP3-Codec,
+	PIPELINE_SINK_8, 2, s16le,
+	48, 1000, 0, 0)
+
+# playback DAI is SSP4 using 2 periods
+# Buffers use s32le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 4, SSP4-Codec,
+	PIPELINE_SOURCE_1, 2, s32le,
+	48, 1000, 0, 0)
+
+# playback DAI is SSP5 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	9, SSP, 5, SSP5-Codec,
+	PIPELINE_SOURCE_9, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP5 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	10, SSP, 5, SSP5-Codec,
+	PIPELINE_SINK_10, 2, s16le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency, id 0
+PCM_DUPLEX_ADD(Port0, 2, PIPELINE_PCM_4, PIPELINE_PCM_5)
+PCM_CAPTURE_ADD(Port1, 3, PIPELINE_PCM_6)
+PCM_DUPLEX_ADD(Port2, 1, PIPELINE_PCM_2, PIPELINE_PCM_3)
+PCM_DUPLEX_ADD(Port3, 4, PIPELINE_PCM_7, PIPELINE_PCM_8)
+PCM_PLAYBACK_ADD(Port4, 0, PIPELINE_PCM_1)
+PCM_DUPLEX_ADD(Port5, 5, PIPELINE_PCM_9, PIPELINE_PCM_10)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 0, 0, SSP0-Codec,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 1536000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 16, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 0, 16)))
+
+DAI_CONFIG(SSP, 1, 1, SSP1-Codec,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 1536000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 16, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 1, 16)))
+
+DAI_CONFIG(SSP, 2, 2, SSP2-Codec,
+	   SSP_CONFIG(DSP_B, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 12288000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(8, 32, 255, 255),
+		      SSP_CONFIG_DATA(SSP, 2, 32)))
+
+DAI_CONFIG(SSP, 3, 3, SSP3-Codec,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 1536000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 16, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 3, 16)))
+
+DAI_CONFIG(SSP, 4, 4, SSP4-Codec,
+	   SSP_CONFIG(DSP_B, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 12288000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(8, 32, 15, 15),
+		      SSP_CONFIG_DATA(SSP, 4, 32)))
+
+DAI_CONFIG(SSP, 5, 5, SSP5-Codec,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 1536000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 16, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 5, 16)))
+
+
+VIRTUAL_DAPM_ROUTE_IN(BtHfp_ssp0_in, SSP, 0, IN, 0)
+VIRTUAL_DAPM_ROUTE_OUT(BtHfp_ssp0_out, SSP, 0, OUT, 1)
+VIRTUAL_DAPM_ROUTE_IN(hdmi_ssp1_in, SSP, 1, IN, 2)
+VIRTUAL_DAPM_ROUTE_IN(dirana_in, SSP, 2, IN, 3)
+VIRTUAL_DAPM_ROUTE_IN(dirana_aux_in, SSP, 2, IN, 4)
+VIRTUAL_DAPM_ROUTE_IN(dirana_tuner_in, SSP, 2, IN, 5)
+VIRTUAL_DAPM_ROUTE_OUT(dirana_out, SSP, 2, OUT, 6)
+VIRTUAL_DAPM_ROUTE_IN(Modem_ssp3_in, SSP, 3, IN, 7)
+VIRTUAL_DAPM_ROUTE_OUT(Modem_ssp3_out, SSP, 3, OUT, 8)
+VIRTUAL_DAPM_ROUTE_OUT(codec0_out, SSP, 4, OUT, 9)
+VIRTUAL_DAPM_ROUTE_IN(TestPin_ssp5_in, SSP, 5, IN, 10)
+VIRTUAL_DAPM_ROUTE_OUT(TestPin_ssp5_out, SSP, 5, OUT, 11)
+VIRTUAL_WIDGET(ssp0 Tx, 12)
+VIRTUAL_WIDGET(ssp0 Rx, 13)
+VIRTUAL_WIDGET(ssp1 Rx, 14)
+VIRTUAL_WIDGET(ssp2 Tx, 15)
+VIRTUAL_WIDGET(ssp2 Rx, 16)
+VIRTUAL_WIDGET(ssp3 Tx, 17)
+VIRTUAL_WIDGET(ssp3 Rx, 18)
+VIRTUAL_WIDGET(ssp4 Tx, 19)
+VIRTUAL_WIDGET(ssp5 Tx, 20)
+VIRTUAL_WIDGET(ssp5 Rx, 21)
diff --git a/topology/sof-apl-wm8804.m4 b/topology/sof-apl-wm8804.m4
new file mode 100644
index 0000000..4dc15eb
--- /dev/null
+++ b/topology/sof-apl-wm8804.m4
@@ -0,0 +1,55 @@
+#
+# Topology for generic Apollolake UP^2 with wm8804 codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Apollolake DSP configuration
+include(`platform/intel/bxt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume -----> SSP5 (wm8804)
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	1, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+#
+# DAIs configuration
+#
+
+# playback DAI is SSP5 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 5, SSP5-Codec,
+	PIPELINE_SOURCE_1, 2, s24le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency, id 0
+PCM_PLAYBACK_ADD(Port5, 0, PIPELINE_PCM_1)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+
+DAI_CONFIG(SSP, 5, 0, SSP5-Codec,
+	SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24576000, codec_mclk_in),
+		SSP_CLOCK(bclk, 3072000, codec_master),
+		SSP_CLOCK(fsync, 48000, codec_master),
+		SSP_TDM(2, 32, 3, 3),
+		SSP_CONFIG_DATA(SSP, 5, 24)))
diff --git a/topology/sof-bdw-rt286.m4 b/topology/sof-bdw-rt286.m4
new file mode 100644
index 0000000..a750344
--- /dev/null
+++ b/topology/sof-bdw-rt286.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Broadwell board with no codec.
+#
+
+# Include topology builder
+include(`pipeline.m4')
+include(`utils.m4')
+include(`dai.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Broadwell DSP configuration
+include(`platform/intel/bdw.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+#                                  |--low latency mixer ----> volume ---->  SSP2
+# PCM2 ----> SRC -----> volume ----+
+#                                  |
+#           Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP0
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+	1, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+	2, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 96 frames per 2000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+	3, 1, 2, s32le,
+	96, 2000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+	5, 2, s32le,
+	192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-bdw-rt286" {
+	index "0"
+
+	lines [
+		# media 0
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+		#tone
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+	]
+}
+
+#
+# DAI configuration
+#
+# SSP port 0 is our only pipeline DAI
+#
+
+# playback DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 0, Codec,
+	PIPELINE_SOURCE_1, 2, s24le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, SSP, 0, Codec,
+	PIPELINE_SINK_2, 2, s24le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 0, 0, Codec,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24000000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 2400000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 25, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 0, 24)))
diff --git a/topology/sof-bdw-rt5640.m4 b/topology/sof-bdw-rt5640.m4
new file mode 100644
index 0000000..454e050
--- /dev/null
+++ b/topology/sof-bdw-rt5640.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Broadwell board with no codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Broadwell DSP configuration
+include(`platform/intel/bdw.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+#                                  |--low latency mixer ----> volume ---->  SSP2
+# PCM2 ----> SRC -----> volume ----+
+#                                  |
+#           Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP0
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+	1, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+	2, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 96 frames per 2000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+	3, 1, 2, s32le,
+	96, 2000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+	5, 2, s32le,
+	192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-bdw-rt5640" {
+	index "0"
+
+	lines [
+		# media 0
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+		#tone
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+	]
+}
+
+#
+# DAI configuration
+#
+# SSP port 0 is our only pipeline DAI
+#
+
+# playback DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 0, Codec,
+	PIPELINE_SOURCE_1, 2, s24le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, SSP, 0, Codec,
+	PIPELINE_SINK_2, 2, s24le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 0, 0, Codec,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24000000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 2400000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 25, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 0, 24)))
diff --git a/topology/sof-byt-da7213.m4 b/topology/sof-byt-da7213.m4
new file mode 100644
index 0000000..6008ff0
--- /dev/null
+++ b/topology/sof-byt-da7213.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Baytrail board with DA7213 codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`platform/intel/byt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+#                                  |--low latency mixer ----> volume ---->  SSP2
+# PCM2 ----> SRC -----> volume ----+
+#                                  |
+#           Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP2
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+	1, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+	2, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+	3, 1, 2, s32le,
+	192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+	5, 2, s32le,
+	192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-byt-da7212" {
+	index "0"
+
+	lines [
+		# media 0
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+		#tone
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+	]
+}
+
+#
+# DAI configuration
+#
+# SSP port 2 is our only pipeline DAI
+#
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 2, SSP2-Codec,
+	PIPELINE_SOURCE_1, 2, s24le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, SSP, 2, SSP2-Codec,
+	PIPELINE_SINK_2, 2, s24le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 2, 0, SSP2-Codec,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 2400000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 25, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 2, 24)))
diff --git a/topology/sof-byt-nocodec.m4 b/topology/sof-byt-nocodec.m4
new file mode 100644
index 0000000..6df25ca
--- /dev/null
+++ b/topology/sof-byt-nocodec.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Baytrail board with no codec.
+#
+
+# Include topology builder
+include(`pipeline.m4')
+include(`utils.m4')
+include(`dai.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`platform/intel/byt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+#                                  |--low latency mixer ----> volume ---->  SSP2
+# PCM2 ----> SRC -----> volume ----+
+#                                  |
+#           Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP2
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+	1, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+	2, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+	3, 1, 2, s32le,
+	192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+	5, 2, s32le,
+	192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-byt-nocodec" {
+	index "0"
+
+	lines [
+		# media 0
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+		#tone
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+	]
+}
+
+#
+# DAI configuration
+#
+# SSP port 2 is our only pipeline DAI
+#
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 2, NoCodec-2,
+	PIPELINE_SOURCE_1, 2, s24le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, SSP, 2, NoCodec-2,
+	PIPELINE_SINK_2, 2, s24le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 2, 2, NoCodec-2,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 2400000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 25, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 2, 24)))
diff --git a/topology/sof-byt-rt5640.m4 b/topology/sof-byt-rt5640.m4
new file mode 100644
index 0000000..2177fe3
--- /dev/null
+++ b/topology/sof-byt-rt5640.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Baytrail board with RT5640.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`platform/intel/byt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+#                                  |--low latency mixer ----> volume ---->  SSP2
+# PCM2 ----> SRC -----> volume ----+
+#                                  |
+#           Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP2
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+	1, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+	2, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+	3, 1, 2, s32le,
+	192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+	5, 2, s32le,
+	192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-byt-rt5640" {
+	index "0"
+
+	lines [
+		# media 0
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+		#tone
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+	]
+}
+
+#
+# DAI configuration
+#
+# SSP port 2 is our only pipeline DAI
+#
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 2, SSP2-Codec,
+	PIPELINE_SOURCE_1, 2, s24le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, SSP, 2, SSP2-Codec,
+	PIPELINE_SINK_2, 2, s24le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 2, 0, SSP2-Codec,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 2400000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 25, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 2, 24)))
diff --git a/topology/sof-byt-rt5645.m4 b/topology/sof-byt-rt5645.m4
new file mode 100644
index 0000000..23f1a75
--- /dev/null
+++ b/topology/sof-byt-rt5645.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Baytrail board with no codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`platform/intel/byt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+#                                  |--low latency mixer ----> volume ---->  SSP2
+# PCM2 ----> SRC -----> volume ----+
+#                                  |
+#           Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP2
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+	1, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+	2, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+	3, 1, 2, s32le,
+	192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+	5, 2, s32le,
+	192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-byt-rt5645" {
+	index "0"
+
+	lines [
+		# media 0
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+		#tone
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+	]
+}
+
+#
+# DAI configuration
+#
+# SSP port 2 is our only pipeline DAI
+#
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 2, SSP2-Codec,
+	PIPELINE_SOURCE_1, 2, s24le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, SSP, 2, SSP2-Codec,
+	PIPELINE_SINK_2, 2, s24le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 2, 0, SSP2-Codec,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 2400000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 25, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 2, 24)))
diff --git a/topology/sof-byt-rt5651.m4 b/topology/sof-byt-rt5651.m4
new file mode 100644
index 0000000..724c34e
--- /dev/null
+++ b/topology/sof-byt-rt5651.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Baytrail board with no RT5651.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`platform/intel/byt.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+#                                  |--low latency mixer ----> volume ---->  SSP2
+# PCM2 ----> SRC -----> volume ----+
+#                                  |
+#           Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP2
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+	1, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+	2, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+	3, 1, 2, s32le,
+	192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+	5, 2, s32le,
+	192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-byt-rt5651" {
+	index "0"
+
+	lines [
+		# media 0
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+		#tone
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+	]
+}
+
+#
+# DAI configuration
+#
+# SSP port 2 is our only pipeline DAI
+#
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 2, SSP2-Codec,
+	PIPELINE_SOURCE_1, 2, s24le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, SSP, 2, SSP2-Codec,
+	PIPELINE_SINK_2, 2, s24le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 2, 0, SSP2-Codec,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 2400000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 25, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 2, 24)))
diff --git a/topology/sof-cht-max98090.m4 b/topology/sof-cht-max98090.m4
new file mode 100644
index 0000000..627181f
--- /dev/null
+++ b/topology/sof-cht-max98090.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic CHT/BSW board with Maxim 98090 codec
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Cherrytrail DSP configuration
+include(`platform/intel/cht.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+#                                  |--low latency mixer ----> volume ---->  SSP2
+# PCM2 ----> SRC -----> volume ----+
+#                                  |
+#           Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP2
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+	1, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+	2, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+	3, 1, 2, s32le,
+	192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+	5, 2, s32le,
+	192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-cht-max98090" {
+	index "0"
+
+	lines [
+		# media 0
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+		#tone
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+	]
+}
+
+#
+# DAI configuration
+#
+# SSP port 2 is our only pipeline DAI
+#
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 2, SSP2-Codec,
+	PIPELINE_SOURCE_1, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, SSP, 2, SSP2-Codec,
+	PIPELINE_SINK_2, 2, s16le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 2, 0, SSP2-Codec,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 1920000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 20, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 2, 16)))
diff --git a/topology/sof-cht-nocodec.m4 b/topology/sof-cht-nocodec.m4
new file mode 100644
index 0000000..dae6dca
--- /dev/null
+++ b/topology/sof-cht-nocodec.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic CherryTrail board with no codec.
+#
+
+# Include topology builder
+include(`pipeline.m4')
+include(`utils.m4')
+include(`dai.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include CherryTrail DSP configuration
+include(`platform/intel/cht.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+#                                  |--low latency mixer ----> volume ---->  SSP2
+# PCM2 ----> SRC -----> volume ----+
+#                                  |
+#           Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP2
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+	1, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+	2, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+	3, 1, 2, s32le,
+	192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+	5, 2, s32le,
+	192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-cht-nocodec" {
+	index "0"
+
+	lines [
+		# media 0
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+		#tone
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+	]
+}
+
+#
+# DAI configuration
+#
+# SSP port 2 is our only pipeline DAI
+#
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 2, NoCodec-2,
+	PIPELINE_SOURCE_1, 2, s24le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP2 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, SSP, 2, NoCodec-2,
+	PIPELINE_SINK_2, 2, s24le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 2, 0, NoCodec-2,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 2400000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 25, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 2, 24)))
diff --git a/topology/sof-cnl-rt274.m4 b/topology/sof-cnl-rt274.m4
new file mode 100644
index 0000000..d40efc1
--- /dev/null
+++ b/topology/sof-cnl-rt274.m4
@@ -0,0 +1,92 @@
+#
+# Topology for generic Cannonlake board with RT274
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Apollolake DSP configuration
+include(`platform/intel/cnl.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume -----> volume ---->  SSP0
+#
+# PCM1 <---- Volume <---- SSP0
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s24le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-playback.m4,
+	1, 0, 2, s24le,
+	48, 1000, 0, 0, SSP, 0, s24le, 2)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s24le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-capture.m4,
+	2, 0, 2, s24le,
+	48, 1000, 0, 0, SSP, 0, s24le, 2)
+
+#
+# DAI configuration
+#
+# SSP port 0 is our only pipeline DAI
+#
+
+# playback DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 0, SSP0-Codec,
+	PIPELINE_SOURCE_1, 2, s24le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, SSP, 0, SSP0-Codec,
+	PIPELINE_SINK_2, 2, s24le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Passthrough, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 0, 1, SSP0-Codec,
+	   SSP_CONFIG(DSP_B, SSP_CLOCK(mclk, 24000000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 4800000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(4, 25, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 0, 24)))
+
+VIRTUAL_DAPM_ROUTE_OUT(codec0_out, SSP, 0, OUT, 0)
+VIRTUAL_DAPM_ROUTE_OUT(codec1_out, SSP, 0, OUT, 1)
+VIRTUAL_DAPM_ROUTE_OUT(ssp0 Tx, SSP, 0, OUT, 2)
+VIRTUAL_DAPM_ROUTE_OUT(Capture, SSP, 0, OUT, 3)
+VIRTUAL_DAPM_ROUTE_OUT(SoC DMIC, SSP, 0, OUT, 4)
+VIRTUAL_DAPM_ROUTE_IN(codec0_in, SSP, 0, IN, 5)
+VIRTUAL_DAPM_ROUTE_OUT(ssp2_out, SSP, 0, OUT, 6)
+VIRTUAL_DAPM_ROUTE_IN(ssp2_in, SSP, 0, IN, 7)
+VIRTUAL_DAPM_ROUTE_OUT(ssp1_out, SSP, 0, OUT, 8)
+VIRTUAL_WIDGET(DMIC01 Rx, 9)
+VIRTUAL_WIDGET(DMic, 10)
+VIRTUAL_WIDGET(dmic01_hifi, 11)
+VIRTUAL_WIDGET(ssp0 Rx, 12)
+VIRTUAL_WIDGET(ssp1_out, 13)
+VIRTUAL_WIDGET(ssp2_out, 14)
+VIRTUAL_WIDGET(ssp2_in, 15)
+VIRTUAL_WIDGET(ssp2 Rx, 16)
+VIRTUAL_WIDGET(ssp2 Tx, 17)
+VIRTUAL_WIDGET(Dummy Playback, 18)
+VIRTUAL_WIDGET(Dummy Capture, 19)
diff --git a/topology/sof-glk-da7219.m4 b/topology/sof-glk-da7219.m4
new file mode 100644
index 0000000..a2ac09f
--- /dev/null
+++ b/topology/sof-glk-da7219.m4
@@ -0,0 +1,195 @@
+#
+# Topology for AppoloLake with headset on SSP2, spk on SSP1 and DMIC capture
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+include(`hda.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include bxt DSP configuration
+include(`platform/intel/bxt.m4')
+include(`platform/intel/dmic.m4')
+
+#
+# Define the pipelines
+#
+# PCM0  ----> volume (pipe 1)   -----> SSP1 (speaker - maxim98357a, BE link 0)
+# PCM1  <---> volume (pipe 2,3) <----> SSP2 (headset - da7219, BE link 1)
+# PCM99 <---- volume (pipe 4)   <----- DMIC0 (dmic capture, BE link 2)
+# PCM5  ----> volume (pipe 5)   -----> iDisp1 (HDMI/DP playback, BE link 3)
+# PCM6  ----> Volume (pipe 6)   -----> iDisp2 (HDMI/DP playback, BE link 4)
+# PCM7  ----> volume (pipe 7)   -----> iDisp3 (HDMI/DP playback, BE link 5)
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	1, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency playback pipeline 2 on PCM 1 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+	2, 1, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+	3, 1, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 4 on PCM 99 using max 4 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+#PIPELINE_PCM_ADD(sof/pipe-volume-capture.m4,
+PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4,
+	4, 99, 4, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency playback pipeline 5 on PCM 5 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+# PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4,
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+        5, 5, 2, s16le,
+        48, 1000, 0, 0)
+
+# Low Latency playback pipeline 6 on PCM 6 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+# PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4,
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+        6, 6, 2, s16le,
+        48, 1000, 0, 0)
+
+# Low Latency playback pipeline 7 on PCM 7 using max 2 channels of s16le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+# PIPELINE_PCM_ADD(sof/pipe-passthrough-playback.m4,
+PIPELINE_PCM_ADD(sof/pipe-volume-playback.m4,
+        7, 7, 2, s16le,
+        48, 1000, 0, 0)
+
+#
+# DAIs configuration
+#
+
+# playback DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 1, SSP1-Codec,
+	PIPELINE_SOURCE_1, 2, s16le,
+	48, 1000, 0, 0)
+
+# playback DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	2, SSP, 2, SSP2-Codec,
+	PIPELINE_SOURCE_2, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	3, SSP, 2, SSP2-Codec,
+	PIPELINE_SINK_3, 2, s16le,
+	48, 1000, 0, 0)
+
+# capture DAI is DMIC0 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	4, DMIC, 0, dmic01,
+	PIPELINE_SINK_4, 2, s32le,
+	48, 1000, 0, 0)
+
+# playback DAI is iDisp1 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+        5, HDA, 3, iDisp1,
+        PIPELINE_SOURCE_5, 2, s16le,
+        48, 1000, 0, 0)
+
+# playback DAI is iDisp2 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+        6, HDA, 4, iDisp2,
+        PIPELINE_SOURCE_6, 2, s16le,
+        48, 1000, 0, 0)
+
+# playback DAI is iDisp3 using 2 periods
+# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+        7, HDA, 5, iDisp3,
+        PIPELINE_SOURCE_7, 2, s16le,
+        48, 1000, 0, 0)
+
+PCM_PLAYBACK_ADD(Speakers, 0, PIPELINE_PCM_1)
+PCM_DUPLEX_ADD(Headset, 1, PIPELINE_PCM_2, PIPELINE_PCM_3)
+PCM_CAPTURE_ADD(DMIC01, 99, PIPELINE_PCM_4)
+PCM_PLAYBACK_ADD(HDMI1, 5, PIPELINE_PCM_5)
+PCM_PLAYBACK_ADD(HDMI2, 6, PIPELINE_PCM_6)
+PCM_PLAYBACK_ADD(HDMI3, 7, PIPELINE_PCM_7)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+
+#SSP 1 (ID: 0) with 19.2 MHz mclk with MCLK_ID 1 (unused), 1.536 MHz blck
+DAI_CONFIG(SSP, 1, 0, SSP1-Codec,
+	SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+		SSP_CLOCK(bclk, 1536000, codec_slave),
+		SSP_CLOCK(fsync, 48000, codec_slave),
+		SSP_TDM(2, 16, 3, 3),
+		SSP_CONFIG_DATA(SSP, 1, 16, 1)))
+
+#SSP 2 (ID: 1) with 19.2 MHz mclk with MCLK_ID 1, 1.92 MHz bclk
+DAI_CONFIG(SSP, 2, 1, SSP2-Codec,
+	SSP_CONFIG(I2S, SSP_CLOCK(mclk, 19200000, codec_mclk_in),
+		SSP_CLOCK(bclk, 1920000, codec_slave),
+		SSP_CLOCK(fsync, 48000, codec_slave),
+		SSP_TDM(2, 20, 3, 3),
+		SSP_CONFIG_DATA(SSP, 2, 16, 1)))
+
+# dmic01 (id: 2)
+DAI_CONFIG(DMIC, 0, 2, dmic01,
+	DMIC_CONFIG(1, 500000, 4800000, 40, 60, 48000,
+		DMIC_WORD_LENGTH(s32le), DMIC, 0,
+		# FIXME: what is the right configuration
+		# PDM_CONFIG(DMIC, 0, FOUR_CH_PDM0_PDM1)))
+		PDM_CONFIG(DMIC, 0, STEREO_PDM0)))
+
+# 3 HDMI/DP outputs (ID: 3,4,5)
+HDA_DAI_CONFIG(3, 3, iDisp1)
+HDA_DAI_CONFIG(4, 4, iDisp2)
+HDA_DAI_CONFIG(5, 5, iDisp3)
+
+## remove warnings with SST hard-coded routes (FIXME)
+
+VIRTUAL_WIDGET(ssp5 Tx, 0)
+VIRTUAL_WIDGET(ssp1 Rx, 1)
+VIRTUAL_WIDGET(ssp1 Tx, 2)
+VIRTUAL_WIDGET(DMIC01 Rx, 3)
+VIRTUAL_WIDGET(DMic, 4)
+VIRTUAL_WIDGET(dmic01_hifi, 5)
+VIRTUAL_WIDGET(hif5-0 Output, 6)
+VIRTUAL_WIDGET(hif6-0 Output, 7)
+VIRTUAL_WIDGET(hif7-0 Output, 8)
+
+VIRTUAL_DAPM_ROUTE_OUT(codec0_out, SSP, 0, OUT, 12)
+VIRTUAL_DAPM_ROUTE_OUT(codec1_out, SSP, 0, OUT, 13)
+VIRTUAL_DAPM_ROUTE_OUT(ssp1 Tx, SSP, 0, OUT, 14)
+VIRTUAL_DAPM_ROUTE_IN(ssp1 Rx, SSP, 0, IN, 15)
+VIRTUAL_DAPM_ROUTE_OUT(Capture, SSP, 0, OUT, 16)
+VIRTUAL_DAPM_ROUTE_OUT(SoC DMIC, SSP, 0, OUT, 17)
+VIRTUAL_DAPM_ROUTE_IN(codec0_in, SSP, 0, IN, 18)
+
+
+
+
+
diff --git a/topology/sof-hsw-rt5640.m4 b/topology/sof-hsw-rt5640.m4
new file mode 100644
index 0000000..272cb15
--- /dev/null
+++ b/topology/sof-hsw-rt5640.m4
@@ -0,0 +1,99 @@
+#
+# Topology for generic Haswell board with no codec.
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Haswell DSP configuration
+include(`platform/intel/hsw.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> volume ---------------+
+#                                  |--low latency mixer ----> volume ---->  SSP2
+# PCM2 ----> SRC -----> volume ----+
+#                                  |
+#           Tone -----> volume ----+
+#
+# PCM1 <---- Volume <---- SSP0
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-playback.m4,
+	1, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s32le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_ADD(sof/pipe-low-latency-capture.m4,
+	2, 0, 2, s32le,
+	48, 1000, 0, 0)
+
+# PCM Media Playback pipeline 3 on PCM 1 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 1
+PIPELINE_PCM_ADD(sof/pipe-pcm-media.m4,
+	3, 1, 2, s32le,
+	192, 4000, 1, 0)
+
+# Tone Playback pipeline 5 using max 2 channels of s32le.
+# Schedule 192 frames per 4000us deadline on core 0 with priority 2
+PIPELINE_ADD(sof/pipe-tone.m4,
+	5, 2, s32le,
+	192, 4000, 2, 0)
+
+# Connect pipelines together
+SectionGraph."pipe-hsw-rt5640" {
+	index "0"
+
+	lines [
+		# media 0
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_3)
+		#tone
+		dapm(PIPELINE_MIXER_1, PIPELINE_SOURCE_5)
+	]
+}
+
+#
+# DAI configuration
+#
+# SSP port 0 is our only pipeline DAI
+#
+
+# playback DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 0, Codec,
+	PIPELINE_SOURCE_1, 2, s24le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, SSP, 0, Codec,
+	PIPELINE_SINK_2, 2, s24le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Low Latency, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 0, 0, Codec,
+	   SSP_CONFIG(I2S, SSP_CLOCK(mclk, 24000000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 2400000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 25, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 0, 24)))
diff --git a/topology/sof-icl-nocodec.m4 b/topology/sof-icl-nocodec.m4
new file mode 100644
index 0000000..1dffe18
--- /dev/null
+++ b/topology/sof-icl-nocodec.m4
@@ -0,0 +1,71 @@
+#
+# Topology for generic Icelake board with nocodec
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+include(`ssp.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Icelake DSP configuration
+include(`platform/intel/icl.m4')
+
+#
+# Define the pipelines
+#
+# PCM0 ----> Volume ----> SSP0
+#
+# PCM1 <---- Volume <---- SSP0
+#
+
+# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s24le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-playback.m4,
+	1, 0, 2, s24le,
+	48, 1000, 0, 0, SSP, 0, s24le, 2)
+
+# Low Latency capture pipeline 2 on PCM 0 using max 2 channels of s24le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+PIPELINE_PCM_DAI_ADD(sof/pipe-volume-capture.m4,
+	2, 0, 2, s24le,
+	48, 1000, 0, 0, SSP, 0, s24le, 2)
+
+#
+# DAI configuration
+#
+# SSP port 0 is our only pipeline DAI
+#
+
+# playback DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, SSP, 0, NoCodec-0,
+	PIPELINE_SOURCE_1, 2, s24le,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP0 using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, SSP, 0, NoCodec-0,
+	PIPELINE_SINK_2, 2, s24le,
+	48, 1000, 0, 0)
+
+# PCM Low Latency
+PCM_DUPLEX_ADD(Passthrough, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+DAI_CONFIG(SSP, 0, 0, NoCodec-0,
+	   SSP_CONFIG(DSP_B, SSP_CLOCK(mclk, 38400000, codec_mclk_in),
+		      SSP_CLOCK(bclk, 2400000, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, 25, 3, 3),
+		      SSP_CONFIG_DATA(SSP, 0, 24)))
diff --git a/topology/sof/Makefile.am b/topology/sof/Makefile.am
new file mode 100644
index 0000000..fc92591
--- /dev/null
+++ b/topology/sof/Makefile.am
@@ -0,0 +1,14 @@
+EXTRA_DIST = \
+	pipe-dai-capture.m4 \
+	pipe-dai-playback.m4 \
+	pipe-low-latency-capture.m4 \
+	pipe-low-latency-playback.m4 \
+	pipe-passthrough-capture.m4 \
+	pipe-passthrough-playback.m4 \
+	pipe-pcm-media.m4 \
+	pipe-src-capture.m4 \
+	pipe-src-playback.m4 \
+	pipe-tone.m4 \
+	pipe-volume-capture.m4 \
+	pipe-volume-playback.m4 \
+	tokens.m4
diff --git a/topology/sof/pipe-dai-capture.m4 b/topology/sof/pipe-dai-capture.m4
new file mode 100644
index 0000000..c69d586
--- /dev/null
+++ b/topology/sof/pipe-dai-capture.m4
@@ -0,0 +1,22 @@
+# DAI Capture connector
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+
+#
+# DAI definitions
+#
+W_DAI_IN(DAI_TYPE, DAI_INDEX, DAI_BE, DAI_FORMAT, 2, 0, 0)
+
+#
+# DAI pipeline - always use 0 for DAIs
+#
+W_PIPELINE(N_DAI_IN, SCHEDULE_DEADLINE, SCHEDULE_PRIORITY, SCHEDULE_FRAMES, SCHEDULE_CORE, 0, pipe_dai_schedule_plat)
+
+#
+# Graph connections to pipelines
+
+P_GRAPH(DAI_NAME, PIPELINE_ID,
+	LIST(`		', `dapm(DAI_BUF, N_DAI_IN)'))
diff --git a/topology/sof/pipe-dai-playback.m4 b/topology/sof/pipe-dai-playback.m4
new file mode 100644
index 0000000..804b180
--- /dev/null
+++ b/topology/sof/pipe-dai-playback.m4
@@ -0,0 +1,22 @@
+# DAI Playback connector
+
+# Include topology builder
+include(`utils.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+
+#
+# DAI definitions
+#
+W_DAI_OUT(DAI_TYPE, DAI_INDEX, DAI_BE, DAI_FORMAT, 0, 2, 2)
+
+#
+# DAI pipeline - always use 0 for DAIs
+#
+W_PIPELINE(N_DAI_OUT, SCHEDULE_DEADLINE, SCHEDULE_PRIORITY, SCHEDULE_FRAMES, SCHEDULE_CORE, 0, pipe_dai_schedule_plat)
+
+#
+# Graph connections to pipelines
+
+P_GRAPH(DAI_NAME, PIPELINE_ID,
+	LIST(`		', `dapm(N_DAI_OUT, DAI_BUF)'))
diff --git a/topology/sof/pipe-low-latency-capture.m4 b/topology/sof/pipe-low-latency-capture.m4
new file mode 100644
index 0000000..39c2cce
--- /dev/null
+++ b/topology/sof/pipe-low-latency-capture.m4
@@ -0,0 +1,67 @@
+# Low Latency Pipeline and PCM
+#
+# Pipeline Endpoints for connection are :-
+#
+#  host PCM_C <--B5-- volume(0C) <--B4-- source DAI0
+
+# Include topology builder
+include(`utils.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`pga.m4')
+include(`mixercontrol.m4')
+
+#
+# Controls
+#
+# Volume Mixer control with max value of 32
+C_CONTROLMIXER(PCM PCM_ID Capture Volume, PIPELINE_ID,
+	CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
+	CONTROLMIXER_MAX(, 40),
+	false,
+	CONTROLMIXER_TLV(TLV 32 steps from -90dB to +6dB for 3dB, vtlv_m90s3),
+	Channel register and shift for Front Left/Right,
+	LIST(`	', KCONTROL_CHANNEL(FL, 0, 0), KCONTROL_CHANNEL(FR, 0, 1)))
+
+#
+# Components and Buffers
+#
+
+# Host "Low Latency Capture" PCM
+# with 0 sink and 2 source periods
+W_PCM_CAPTURE(PCM_ID, Low Latency Capture, 0, 2, 0)
+
+# "Capture Volume" has 2 sink and source periods for host and DAI ping-pong
+W_PGA(0, PIPELINE_FORMAT, 2, 2, 0, LIST(`		', "PCM PCM_ID Capture Volume PIPELINE_ID"))
+
+# Capture Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(2,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_DAI_MEM_CAP)
+W_BUFFER(1, COMP_BUFFER_SIZE(2,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_HOST_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+#  host PCM <--B1-- volume <--B0-- source DAI0
+
+P_GRAPH(pipe-ll-capture-PIPELINE_ID, PIPELINE_ID,
+	LIST(`		',
+	`dapm(Low Latency Capture PCM_ID, N_PCMC(PCM_ID))',
+	`dapm(N_PCMC(PCM_ID), N_BUFFER(1))',
+	`dapm(N_BUFFER(1), N_PGA(0))',
+	`dapm(N_PGA(0), N_BUFFER(0))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SINK_', PIPELINE_ID), N_BUFFER(0))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Low Latency Capture PCM_ID)
+
+#
+# PCM Configuration
+#
+
+PCM_CAPABILITIES(Low Latency Capture PCM_ID, `S32_LE,S24_LE,S16_LE', 48000, 48000, 2, 4, 2, 4, 192, 16384, 65536, 65536)
diff --git a/topology/sof/pipe-low-latency-playback.m4 b/topology/sof/pipe-low-latency-playback.m4
new file mode 100644
index 0000000..8cfe5e4
--- /dev/null
+++ b/topology/sof/pipe-low-latency-playback.m4
@@ -0,0 +1,119 @@
+# Low Latency Pipeline
+#
+#  Low Latency Playback PCM mixed into single sink pipe.
+#  Low latency Capture PCM.
+#
+# Pipeline Endpoints for connection are :-
+#
+#	LL Playback Mixer (Mixer)
+#	LL Capture Volume B4 (DAI buffer)
+#	LL Playback Volume B3 (DAI buffer)
+#
+#
+#  host PCM_P --B0--> volume(0P) --B1--+
+#                                      |--ll mixer(M) --B2--> volume(LL) ---B3-->  sink DAI0
+#                     pipeline n+1 >---+
+#                                      |
+#                     pipeline n+2 >---+
+#                                      |
+#                     pipeline n+3 >---+  .....etc....more pipes can be mixed here
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`pga.m4')
+include(`mixer.m4')
+include(`mixercontrol.m4')
+
+#
+# Controls
+#
+# Volume Mixer control with max value of 32
+C_CONTROLMIXER(PCM PCM_ID Playback Volume, PIPELINE_ID,
+	CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
+	CONTROLMIXER_MAX(, 32),
+	false,
+	CONTROLMIXER_TLV(TLV 32 steps from -90dB to +6dB for 3dB, vtlv_m90s3),
+	Channel register and shift for Front Left/Right,
+	LIST(KCONTROL_CHANNEL(FL, 0, 0), KCONTROL_CHANNEL(FR, 0, 1)))
+
+# Volume Mixer control with max value of 32
+C_CONTROLMIXER(Master Playback Volume, PIPELINE_ID,
+	CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
+	CONTROLMIXER_MAX(, 32),
+	false,
+	CONTROLMIXER_TLV(TLV 32 steps from -90dB to +6dB for 3dB, vtlv_m90s3),
+	Channel register and shift for Front Left/Right,
+	LIST(`	', KCONTROL_CHANNEL(FL, 1, 0), KCONTROL_CHANNEL(FR, 1, 1)))
+
+#
+# Components and Buffers
+#
+
+# Host "Low latency Playback" PCM
+# with 2 sink and 0 source periods
+W_PCM_PLAYBACK(PCM_ID, Low Latency Playback, 2, 0, 2)
+
+# "Playback Volume" has 1 sink period and 2 source periods for host ping-pong
+W_PGA(0, PIPELINE_FORMAT, 1, 2, 1, LIST(`		', "PCM PCM_ID Playback Volume PIPELINE_ID"))
+
+# "Master Playback Volume" has 1 source and 2 sink periods for DAI ping-pong
+W_PGA(1, PIPELINE_FORMAT, 2, 1, 1, LIST(`		', "Master Playback Volume PIPELINE_ID"))
+
+# Mixer 0 has 1 sink and source periods.
+W_MIXER(0, PIPELINE_FORMAT, 1, 1, 1)
+
+# Low Latency Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(2,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_HOST_MEM_CAP)
+W_BUFFER(1, COMP_BUFFER_SIZE(1,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS,SCHEDULE_FRAMES),
+	PLATFORM_COMP_MEM_CAP)
+W_BUFFER(2, COMP_BUFFER_SIZE(1,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_COMP_MEM_CAP)
+W_BUFFER(3, COMP_BUFFER_SIZE(2,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_DAI_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+#  host PCM_P --B0--> volume(0P) --B1--+
+#                                      |--ll mixer(M) --B2--> volume(LL) ---B3-->  sink DAI0
+#                     pipeline n+1 >---+
+#                                      |
+#                     pipeline n+2 >---+
+#                                      |
+#                     pipeline n+3 >---+  .....etc....more pipes can be mixed here
+#
+
+P_GRAPH(pipe-ll-playback-PIPELINE_ID, PIPELINE_ID,
+	LIST(`		',
+	`dapm(N_PCMP(PCM_ID), Low Latency Playback PCM_ID)',
+	`dapm(N_BUFFER(0), N_PCMP(PCM_ID))',
+	`dapm(N_PGA(0), N_BUFFER(0))',
+	`dapm(N_BUFFER(1), N_PGA(0))',
+	`dapm(N_MIXER(0), N_BUFFER(1))',
+	`dapm(N_BUFFER(2), N_MIXER(0))',
+	`dapm(N_PGA(1), N_BUFFER(2))',
+	`dapm(N_BUFFER(3), N_PGA(1))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(3))
+indir(`define', concat(`PIPELINE_MIXER_', PIPELINE_ID), N_MIXER(0))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Low Latency Playback PCM_ID)
+
+#
+# PCM Configuration
+#
+
+
+# PCM capabilities supported by FW
+PCM_CAPABILITIES(Low Latency Playback PCM_ID, `S32_LE,S24_LE,S16_LE', 48000, 48000, 2, 2, 2, 16, 192, 16384, 65536, 65536)
+
diff --git a/topology/sof/pipe-passthrough-capture.m4 b/topology/sof/pipe-passthrough-capture.m4
new file mode 100644
index 0000000..4614083
--- /dev/null
+++ b/topology/sof/pipe-passthrough-capture.m4
@@ -0,0 +1,47 @@
+# Capture Passthrough Pipeline and PCM
+#
+# Pipeline Endpoints for connection are :-
+#
+#  host PCM_C <-- B0 <-- sink DAI0
+
+# Include topology builder
+include(`utils.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+
+#
+# Components and Buffers
+#
+
+# Host "Passthrough Capture" PCM
+# with 0 sink and 2 source periods
+W_PCM_CAPTURE(PCM_ID, Passthrough Capture, 0, 2, 2)
+
+# Capture Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(2,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_PASS_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+#  host PCM_C <-- B0 <-- sink DAI0
+
+P_GRAPH(pipe-pass-capture-PIPELINE_ID, PIPELINE_ID,
+	LIST(`		',
+	`dapm(Passthrough Capture PCM_ID, N_PCMC(PCM_ID))',
+	`dapm(N_PCMC(PCM_ID), N_BUFFER(0))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SINK_', PIPELINE_ID), N_BUFFER(0))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Capture PCM_ID)
+
+#
+# PCM Configuration
+#
+
+PCM_CAPABILITIES(Passthrough Capture PCM_ID, COMP_FORMAT_NAME(PIPELINE_FORMAT), 8000, 192000, 1, 16, 2, 16, 192, 16384, 65536, 65536)
diff --git a/topology/sof/pipe-passthrough-playback.m4 b/topology/sof/pipe-passthrough-playback.m4
new file mode 100644
index 0000000..c7c1237
--- /dev/null
+++ b/topology/sof/pipe-passthrough-playback.m4
@@ -0,0 +1,47 @@
+# Low Latency Passthrough Pipeline and PCM
+#
+# Pipeline Endpoints for connection are :-
+#
+#  host PCM_P --> B0 --> sink DAI0
+
+# Include topology builder
+include(`utils.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+
+#
+# Components and Buffers
+#
+
+# Host "Passthrough Playback" PCM
+# with 2 sink and 0 source periods
+W_PCM_PLAYBACK(PCM_ID, Passthrough Playback, 2, 0, 2)
+
+# Playback Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(2,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_PASS_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+#  host PCM_P --> B0 --> sink DAI0
+
+P_GRAPH(pipe-pass-playback-PIPELINE_ID, PIPELINE_ID,
+	LIST(`		',
+	`dapm(N_PCMP(PCM_ID), Passthrough Playback PCM_ID)',
+	`dapm(N_BUFFER(0), N_PCMP(PCM_ID))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(0))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Playback PCM_ID)
+
+#
+# PCM Configuration
+#
+
+PCM_CAPABILITIES(Passthrough Playback PCM_ID, COMP_FORMAT_NAME(PIPELINE_FORMAT), 48000, 48000, 2, 4, 2, 16, 192, 16384, 65536, 65536)
diff --git a/topology/sof/pipe-pcm-media.m4 b/topology/sof/pipe-pcm-media.m4
new file mode 100644
index 0000000..b526e43
--- /dev/null
+++ b/topology/sof/pipe-pcm-media.m4
@@ -0,0 +1,117 @@
+# Low Power PCM Media Pipeline
+#
+#  Low power PCM media playback with SRC and volume.
+#
+# Pipeline Endpoints for connection are :-
+#
+#  host PCM_P --B0--> volume(0P) --B1--> SRC -- B2 --> Endpoint Pipeline
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`src.m4')
+include(`buffer.m4')
+include(`pga.m4')
+include(`mixercontrol.m4')
+include(`pipeline.m4')
+include(`pcm.m4')
+
+#
+# Controls
+#
+# Volume Mixer control with max value of 32
+C_CONTROLMIXER(PCM PCM_ID Playback Volume, PIPELINE_ID,
+	CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
+	CONTROLMIXER_MAX(, 32),
+	false,
+	CONTROLMIXER_TLV(TLV 32 steps from -90dB to +6dB for 3dB, vtlv_m90s3),
+	Channel register and shift for Front Left/Right,
+	LIST(`	', KCONTROL_CHANNEL(FL, 1, 0), KCONTROL_CHANNEL(FR, 1, 1)))
+
+#
+# SRC Configuration
+#
+
+W_VENDORTUPLES(media_src_tokens, sof_src_tokens, LIST(`		', `SOF_TKN_SRC_RATE_OUT	"48000"'))
+
+W_DATA(media_src_conf, media_src_tokens)
+
+#
+# Components and Buffers
+#
+
+# Host "Low latency Playback" PCM
+# with 2 sink and 0 source periods
+W_PCM_PLAYBACK(PCM_ID, Media Playback, 2, 0, 2)
+
+# "Playback Volume" has 2 sink period and 2 source periods for host ping-pong
+W_PGA(0, PIPELINE_FORMAT, 2, 2, 2, LIST(`		', "PCM PCM_ID Playback Volume PIPELINE_ID"))
+
+# "SRC 0" has 2 sink and source periods.
+W_SRC(0, PIPELINE_FORMAT, 2, 2, media_src_conf, 2)
+
+# Media Source Buffers to SRC, make them big enough to deal with 2 * rate.
+W_BUFFER(0, COMP_BUFFER_SIZE(4,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_HOST_MEM_CAP)
+W_BUFFER(1,COMP_BUFFER_SIZE(4,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_COMP_MEM_CAP)
+
+# Buffer B2 is on fixed rate sink side of SRC. Set it 1.5 * rate.
+W_BUFFER(2, COMP_BUFFER_SIZE(3,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_COMP_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+#  PCM --B0--> volume --B1--> SRC --> B2 --> Endpoint Pipeline
+#
+
+P_GRAPH(pipe-media-PIPELINE_ID, PIPELINE_ID,
+	LIST(`		',
+	`dapm(N_PCMP(PCM_ID), Media Playback PCM_ID)',
+	`dapm(N_BUFFER(0), N_PCMP(PCM_ID))',
+	`dapm(N_PGA(0), N_BUFFER(0))',
+	`dapm(N_BUFFER(1), N_PGA(0))',
+	`dapm(N_SRC(0), N_BUFFER(1))'
+	`dapm(N_BUFFER(2), N_SRC(0))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(2))
+
+#
+# Pipeline Configuration.
+#
+
+W_PIPELINE(N_SRC(0), SCHEDULE_DEADLINE, SCHEDULE_PRIORITY, SCHEDULE_FRAMES, SCHEDULE_CORE, 1, pipe_media_schedule_plat)
+
+#
+# PCM Configuration
+#
+
+# PCM capabilities supported by FW
+
+PCM_CAPABILITIES(Media Playback PCM_ID, `S32_LE,S24_LE,S16_LE', 8000, 192000, 2, 2, 2, 32, 192, 262144, 8388608, 8388608)
+
+# PCM Low Latency Playback and Capture
+SectionPCM.STR(Media Playback PCM_ID) {
+
+	index STR(PIPELINE_ID)
+
+	# used for binding to the PCM
+	id STR(PCM_ID)
+
+	dai.STR(Media Playback PCM_ID) {
+		id STR(PCM_ID)
+	}
+
+	# Playback and Capture Configuration
+	pcm."playback" {
+
+		capabilities STR(Media Playback PCM_ID)
+	}
+}
diff --git a/topology/sof/pipe-src-capture.m4 b/topology/sof/pipe-src-capture.m4
new file mode 100644
index 0000000..e0a68e4
--- /dev/null
+++ b/topology/sof/pipe-src-capture.m4
@@ -0,0 +1,64 @@
+# Low Latency Passthrough with volume Pipeline and PCM
+#
+# Pipeline Endpoints for connection are :-
+#
+#  host PCM_P --> SRC --> sink DAI0
+
+# Include topology builder
+include(`utils.m4')
+include(`src.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+
+#
+# Components and Buffers
+#
+
+# Host "Passthrough Capture" PCM
+# with 4 sink and 0 source periods
+W_PCM_CAPTURE(PCM_ID, Passthrough Capture, 4, 0, 2)
+
+#
+# SRC Configuration
+#
+
+W_VENDORTUPLES(media_src_tokens, sof_src_tokens, LIST(`		', `SOF_TKN_SRC_RATE_OUT	"48000"'))
+
+W_DATA(media_src_conf, media_src_tokens)
+
+# "SRC" has 4 source and 4 sink periods
+W_SRC(0, PIPELINE_FORMAT, 4, 4, media_src_conf, 2)
+
+# Capture Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(4,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_HOST_MEM_CAP)
+W_BUFFER(1, COMP_BUFFER_SIZE(4,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_DAI_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+#  host PCM_P <-- B0 <-- SRC 0 <-- B1 <-- sink DAI0
+
+P_GRAPH(pipe-pass-src-capture-PIPELINE_ID, PIPELINE_ID,
+	LIST(`		',
+	`dapm(Passthrough Capture PCM_ID, N_PCMC(PCM_ID))',
+	`dapm(N_PCMC(PCM_ID), N_BUFFER(0))',
+	`dapm(N_BUFFER(0), N_SRC(0))',
+	`dapm(N_SRC(0), N_BUFFER(1))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SINK_', PIPELINE_ID), N_BUFFER(1))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Capture PCM_ID)
+
+#
+# PCM Configuration
+#
+
+PCM_CAPABILITIES(Passthrough Capture PCM_ID, `S32_LE,S24_LE,S16_LE', 8000, 96000, 2, 4, 2, 16, 192, 16384, 65536, 65536)
diff --git a/topology/sof/pipe-src-playback.m4 b/topology/sof/pipe-src-playback.m4
new file mode 100644
index 0000000..ce05b94
--- /dev/null
+++ b/topology/sof/pipe-src-playback.m4
@@ -0,0 +1,65 @@
+# Low Latency Passthrough with volume Pipeline and PCM
+#
+# Pipeline Endpoints for connection are :-
+#
+#  host PCM_P --> SRC --> sink DAI0
+
+# Include topology builder
+include(`utils.m4')
+include(`src.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`dai.m4')
+include(`pipeline.m4')
+
+#
+# Components and Buffers
+#
+
+# Host "Passthrough Playback" PCM
+# with 3 sink and 0 source periods
+W_PCM_PLAYBACK(PCM_ID, Passthrough Playback, 3, 0, 2)
+
+#
+# SRC Configuration
+#
+
+W_VENDORTUPLES(media_src_tokens, sof_src_tokens, LIST(`		', `SOF_TKN_SRC_RATE_OUT	"48000"'))
+
+W_DATA(media_src_conf, media_src_tokens)
+
+# "SRC" has 3 source and 3 sink periods
+W_SRC(0, PIPELINE_FORMAT, 3, 3, media_src_conf, 2)
+
+# Playback Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(3,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_HOST_MEM_CAP)
+W_BUFFER(1, COMP_BUFFER_SIZE(3,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_DAI_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+#  host PCM_P --> B0 --> SRC 0 --> B1 --> sink DAI0
+
+P_GRAPH(pipe-pass-src-playback-PIPELINE_ID, PIPELINE_ID,
+	LIST(`		',
+	`dapm(N_PCMP(PCM_ID), Passthrough Playback PCM_ID)',
+	`dapm(N_BUFFER(0), N_PCMP(PCM_ID))',
+	`dapm(N_SRC(0), N_BUFFER(0))',
+	`dapm(N_BUFFER(1), N_SRC(0))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(1))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Playback PCM_ID)
+
+#
+# PCM Configuration
+#
+
+PCM_CAPABILITIES(Passthrough Playback PCM_ID, `S32_LE,S24_LE,S16_LE', 8000, 192000, 2, 8, 2, 16, 192, 16384, 65536, 65536)
+
diff --git a/topology/sof/pipe-tone.m4 b/topology/sof/pipe-tone.m4
new file mode 100644
index 0000000..fc5eb00
--- /dev/null
+++ b/topology/sof/pipe-tone.m4
@@ -0,0 +1,80 @@
+# Tone Generator
+#
+#  Multi Frequency Tone Generator.
+#
+# Pipeline Endpoints for connection are :-
+#
+#  Tone --B0--> volume --B1--> Endpoint Pipeline
+#
+
+# Include topology builder
+include(`utils.m4')
+include(`buffer.m4')
+include(`pga.m4')
+include(`tone.m4')
+include(`mixercontrol.m4')
+include(`pipeline.m4')
+
+#
+# Controls
+#
+
+# Volume Mixer control with max value of 32
+C_CONTROLMIXER(Tone Volume, PIPELINE_ID,
+	CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
+	CONTROLMIXER_MAX(, 32),
+	false,
+	CONTROLMIXER_TLV(TLV 32 steps from -90dB to +6dB for 3dB, vtlv_m90s3),
+	Channel register and shift for Front Left/Right,
+	LIST(`	', KCONTROL_CHANNEL(FL, 1, 0), KCONTROL_CHANNEL(FR, 1, 1)))
+
+# Switch type Mixer Control with max value of 1
+C_CONTROLMIXER(Tone Switch, PIPELINE_ID,
+	CONTROLMIXER_OPS(volsw, 259 binds the mixer control to switch get/put handlers, 259, 259),
+	CONTROLMIXER_MAX(max 1 indicates switch type control, 1),
+	false,
+	,
+	Channel register and shift for Front Left/Right,
+	LIST(`	', KCONTROL_CHANNEL(FL, 2, 0), KCONTROL_CHANNEL(FR, 2, 1)))
+
+#
+# Components and Buffers
+#
+
+# "Tone 0" has 2 sink period and 0 source periods
+W_TONE(0, PIPELINE_FORMAT, 2, 0, 0, LIST(`		', "Tone Switch PIPELINE_ID"))
+
+# "Tone Volume" has 2 sink period and 2 source periods
+W_PGA(0, PIPELINE_FORMAT, 2, 2, 0, LIST(`		', "Tone Volume PIPELINE_ID"))
+
+# Low Latency Buffers
+W_BUFFER(0,COMP_BUFFER_SIZE(2,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_COMP_MEM_CAP)
+W_BUFFER(1, COMP_BUFFER_SIZE(2,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_COMP_MEM_CAP)
+
+
+#
+# Pipeline Graph
+#
+#  Tone --B0--> volume --B1--> Endpoint Pipeline
+#
+
+P_GRAPH(pipe-tone-PIPELINE_ID, PIPELINE_ID,
+	LIST(`		',
+	`dapm(N_BUFFER(0), N_TONE(0))',
+	`dapm(N_PGA(0), N_BUFFER(0))',
+	`dapm(N_BUFFER(1), N_PGA(0))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(1))
+
+#
+# Pipeline Configuration.
+#
+
+W_PIPELINE(N_TONE(0), SCHEDULE_DEADLINE, SCHEDULE_PRIORITY, SCHEDULE_FRAMES, SCHEDULE_CORE, 0, pipe_tone_schedule_plat)
diff --git a/topology/sof/pipe-volume-capture.m4 b/topology/sof/pipe-volume-capture.m4
new file mode 100644
index 0000000..820b745
--- /dev/null
+++ b/topology/sof/pipe-volume-capture.m4
@@ -0,0 +1,70 @@
+# Passthrough with volume Pipeline and PCM
+#
+# Pipeline Endpoints for connection are :-
+#
+#  host PCM_C <-- B0 <-- Volume 0 <-- B1 <-- source DAI0
+
+# Include topology builder
+include(`utils.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`pga.m4')
+include(`dai.m4')
+include(`mixercontrol.m4')
+include(`pipeline.m4')
+
+#
+# Controls
+#
+# Volume Mixer control with max value of 32
+C_CONTROLMIXER(Master Capture Volume, PIPELINE_ID,
+	CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
+	CONTROLMIXER_MAX(, 32),
+	false,
+	CONTROLMIXER_TLV(TLV 32 steps from -90dB to +6dB for 3dB, vtlv_m90s3),
+	Channel register and shift for Front Left/Right,
+	LIST(`	', KCONTROL_CHANNEL(FL, 1, 0), KCONTROL_CHANNEL(FR, 1, 1)))
+
+#
+# Components and Buffers
+#
+
+# Host "Passthrough Capture" PCM
+# with 0 sink and 2 source periods
+W_PCM_CAPTURE(PCM_ID, Passthrough Capture, 0, 2, 2)
+
+# "Volume" has 2 source and 2 sink periods
+W_PGA(0, PIPELINE_FORMAT, 2, 2, 2, LIST(`		', "Master Capture Volume PIPELINE_ID"))
+
+# Capture Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(2,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_HOST_MEM_CAP)
+W_BUFFER(1, COMP_BUFFER_SIZE(2,
+	COMP_SAMPLE_SIZE(DAI_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_DAI_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+#  host PCM_P <-- B0 <-- Volume 0 <-- B1 <-- sink DAI0
+
+P_GRAPH(pipe-pass-vol-capture-PIPELINE_ID, PIPELINE_ID,
+	LIST(`		',
+	`dapm(Passthrough Capture PCM_ID, N_PCMC(PCM_ID))',
+	`dapm(N_PCMC(PCM_ID), N_BUFFER(0))',
+	`dapm(N_BUFFER(0), N_PGA(0))',
+	`dapm(N_PGA(0), N_BUFFER(1))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SINK_', PIPELINE_ID), N_BUFFER(1))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Capture PCM_ID)
+
+#
+# PCM Configuration
+#
+
+PCM_CAPABILITIES(Passthrough Capture PCM_ID, `S32_LE,S24_LE,S16_LE', 48000, 48000, 2, 8, 2, 16, 192, 16384, 65536, 65536)
+
diff --git a/topology/sof/pipe-volume-playback.m4 b/topology/sof/pipe-volume-playback.m4
new file mode 100644
index 0000000..4ebd02d
--- /dev/null
+++ b/topology/sof/pipe-volume-playback.m4
@@ -0,0 +1,71 @@
+# Low Latency Passthrough with volume Pipeline and PCM
+#
+# Pipeline Endpoints for connection are :-
+#
+#  host PCM_P --> B0 --> Volume 0 --> B1 --> sink DAI0
+
+# Include topology builder
+include(`utils.m4')
+include(`buffer.m4')
+include(`pcm.m4')
+include(`pga.m4')
+include(`dai.m4')
+include(`mixercontrol.m4')
+include(`pipeline.m4')
+
+#
+# Controls
+#
+# Volume Mixer control with max value of 32
+C_CONTROLMIXER(Master Playback Volume, PIPELINE_ID,
+	CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
+	CONTROLMIXER_MAX(, 32),
+	false,
+	CONTROLMIXER_TLV(TLV 32 steps from -90dB to +6dB for 3dB, vtlv_m90s3),
+	Channel register and shift for Front Left/Right,
+	LIST(`	', KCONTROL_CHANNEL(FL, 1, 0), KCONTROL_CHANNEL(FR, 1, 1)))
+
+#
+# Components and Buffers
+#
+
+# Host "Passthrough Playback" PCM
+# with 2 sink and 0 source periods
+W_PCM_PLAYBACK(PCM_ID, Passthrough Playback, 2, 0, 2)
+
+# "Volume" has 2 source and 2 sink periods
+W_PGA(0, PIPELINE_FORMAT, 2, 2, 2, LIST(`		', "Master Playback Volume PIPELINE_ID"))
+
+# Playback Buffers
+W_BUFFER(0, COMP_BUFFER_SIZE(2,
+	COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_HOST_MEM_CAP)
+W_BUFFER(1, COMP_BUFFER_SIZE(2,
+	COMP_SAMPLE_SIZE(DAI_FORMAT), PIPELINE_CHANNELS, SCHEDULE_FRAMES),
+	PLATFORM_DAI_MEM_CAP)
+
+#
+# Pipeline Graph
+#
+#  host PCM_P --> B0 --> Volume 0 --> B1 --> sink DAI0
+
+P_GRAPH(pipe-pass-vol-playback-PIPELINE_ID, PIPELINE_ID,
+	LIST(`		',
+	`dapm(N_PCMP(PCM_ID), Passthrough Playback PCM_ID)',
+	`dapm(N_BUFFER(0), N_PCMP(PCM_ID))',
+	`dapm(N_PGA(0), N_BUFFER(0))',
+	`dapm(N_BUFFER(1), N_PGA(0))'))
+
+#
+# Pipeline Source and Sinks
+#
+indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(1))
+indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Playback PCM_ID)
+
+
+#
+# PCM Configuration
+
+#
+PCM_CAPABILITIES(Passthrough Playback PCM_ID, `S32_LE,S24_LE,S16_LE', 48000, 48000, 2, 8, 2, 16, 192, 16384, 65536, 65536)
+
diff --git a/topology/sof/tokens.m4 b/topology/sof/tokens.m4
new file mode 100644
index 0000000..4aa2fea
--- /dev/null
+++ b/topology/sof/tokens.m4
@@ -0,0 +1,84 @@
+
+#
+# SOF Tokens for differentiation.
+#
+# Differentiation can be done at the platform and machine level.
+#
+# Tokens are GUIDs
+
+# TODO: pre-process this with UAPI headers GNU cpp.
+
+
+SectionVendorTokens."sof_buffer_tokens" {
+	SOF_TKN_BUF_SIZE			"100"
+	SOF_TKN_BUF_CAPS			"101"
+}
+
+SectionVendorTokens."sof_dai_tokens" {
+	SOF_TKN_DAI_DMAC_CONFIG			"153"
+	SOF_TKN_DAI_TYPE			"154"
+	SOF_TKN_DAI_INDEX			"155"
+}
+
+SectionVendorTokens."sof_sched_tokens" {
+	SOF_TKN_SCHED_DEADLINE			"200"
+	SOF_TKN_SCHED_PRIORITY			"201"
+	SOF_TKN_SCHED_MIPS			"202"
+	SOF_TKN_SCHED_CORE			"203"
+	SOF_TKN_SCHED_FRAMES			"204"
+	SOF_TKN_SCHED_TIMER			"205"
+}
+
+SectionVendorTokens."sof_volume_tokens" {
+	SOF_TKN_VOLUME_RAMP_STEP_TYPE		"250"
+	SOF_TKN_VOLUME_RAMP_STEP_MS		"251"
+}
+
+SectionVendorTokens."sof_src_tokens" {
+	SOF_TKN_SRC_RATE_IN			"300"
+	SOF_TKN_SRC_RATE_OUT			"301"
+}
+
+SectionVendorTokens."sof_pcm_tokens" {
+	SOF_TKN_PCM_DMAC_CONFIG			"353"
+}
+
+SectionVendorTokens."sof_comp_tokens" {
+	SOF_TKN_COMP_PERIOD_SINK_COUNT		"400"
+	SOF_TKN_COMP_PERIOD_SOURCE_COUNT	"401"
+	SOF_TKN_COMP_FORMAT			"402"
+	SOF_TKN_COMP_PRELOAD_COUNT		"403"
+}
+
+SectionVendorTokens."sof_ssp_tokens" {
+	SOF_TKN_INTEL_SSP_MCLK_KEEP_ACTIVE	"500"
+	SOF_TKN_INTEL_SSP_BCLK_KEEP_ACTIVE	"501"
+	SOF_TKN_INTEL_SSP_FS_KEEP_ACTIVE	"502"
+	SOF_TKN_INTEL_SSP_MCLK_ID		"503"
+	SOF_TKN_INTEL_SSP_SAMPLE_BITS		"504"
+}
+
+SectionVendorTokens."sof_dmic_tokens" {
+	SOF_TKN_INTEL_DMIC_DRIVER_VERSION	"600"
+	SOF_TKN_INTEL_DMIC_CLK_MIN		"601"
+	SOF_TKN_INTEL_DMIC_CLK_MAX		"602"
+	SOF_TKN_INTEL_DMIC_DUTY_MIN		"603"
+	SOF_TKN_INTEL_DMIC_DUTY_MAX		"604"
+	SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE	"605"
+	SOF_TKN_INTEL_DMIC_SAMPLE_RATE		"608"
+	SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH	"609"
+}
+
+SectionVendorTokens."sof_dmic_pdm_tokens" {
+	SOF_TKN_INTEL_DMIC_PDM_CTRL_ID		"700"
+	SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable	"701"
+	SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable	"702"
+	SOF_TKN_INTEL_DMIC_PDM_POLARITY_A	"703"
+	SOF_TKN_INTEL_DMIC_PDM_POLARITY_B	"704"
+	SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE		"705"
+	SOF_TKN_INTEL_DMIC_PDM_SKEW		"706"
+}
+
+SectionVendorTokens."sof_tone_tokens" {
+	SOF_TKN_TONE_SAMPLE_RATE		"800"
+}
diff --git a/topology/test/Makefile.am b/topology/test/Makefile.am
new file mode 100644
index 0000000..3a613e8
--- /dev/null
+++ b/topology/test/Makefile.am
@@ -0,0 +1,32 @@
+
+#
+# Dependencies
+#
+
+if XARGS
+export USE_XARGS=yes
+endif
+
+DEPS = \
+	../platform/intel/*.m4 \
+	../common/*.m4 \
+	../m4/*.m4 \
+	../sof/*.m4
+
+# Uncomment the following line if you want to debug conf files
+.PRECIOUS: %.conf
+
+all : *.m4 ${DEPS}
+	./tplg-build.sh
+
+clean-local:
+	rm -f *.conf
+	rm -f *.tplg
+
+
+EXTRA_DIST = \
+	test-capture.m4 \
+	test-playback.m4 \
+	test-tone-playback.m4 \
+	test-all.m4 \
+	tplg-build.sh
diff --git a/topology/test/test-all.m4 b/topology/test/test-all.m4
new file mode 100644
index 0000000..518c909
--- /dev/null
+++ b/topology/test/test-all.m4
@@ -0,0 +1,97 @@
+#
+# Topology for pass through pipeline
+#
+
+# Include topology builder
+include(`dai.m4')
+include(`ssp.m4')
+include(`utils.m4')
+include(`pipeline.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`byt.m4')
+
+#
+# Machine Specific Config - !! MUST BE SET TO MATCH TEST MACHINE DRIVER !!
+#
+# TEST_PIPE_NAME - Pipe name
+# TEST_DAI_LINK_NAME - BE DAI link name e.g. "NoCodec"
+# TEST_DAI_PORT	- SSP port number e.g. 2
+# TEST_DAI_FORMAT - SSP data format e.g s16le
+# TEST_PIPE_FORMAT - Pipeline format e.g. s16le
+# TEST_SSP_MCLK - SSP BCLK in Hz
+# TEST_SSP_BCLK - SSP BCLK in Hz
+# TEST_SSP_PHY_BITS - SSP physical slot size
+# TEST_SSP_DATA_BITS - SSP data slot size
+# TEST_SSP_MODE - SSP mode e.g. I2S, LEFT_J, DSP_A and DSP_B
+#
+
+#
+# Define the pipeline
+#
+# PCM0 <-- TEST_PIPE_NAME pipe --> SSP TEST_DAI_PORT
+#
+
+# Passthrough playback pipeline 1 on PCM 0 using max 2 channels of s24le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+
+PIPELINE_PCM_DAI_ADD(sof/pipe-TEST_PIPE_NAME-playback.m4,
+	1, 0, 2, TEST_PIPE_FORMAT,
+	48, 1000, 0, 0,
+	TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_FORMAT, 2)
+
+
+# Passthrough playback pipeline 2 on PCM 0 using max 2 channels of s24le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+
+PIPELINE_PCM_DAI_ADD(sof/pipe-TEST_PIPE_NAME-capture.m4,
+	2, 0, 2, TEST_PIPE_FORMAT,
+	48, 1000, 0, 0,
+	TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_FORMAT, 2)
+
+#
+# DAI configuration
+#
+# SSP port TEST_DAI_PORT is our only pipeline DAI
+#
+
+# playback DAI is SSP TEST_DAI_PORT using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+	PIPELINE_SOURCE_1, 2, TEST_DAI_FORMAT,
+	48, 1000, 0, 0)
+
+# capture DAI is SSP TEST_DAI_PORT using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+	PIPELINE_SINK_2, 2, TEST_DAI_FORMAT,
+	48, 1000, 0, 0)
+
+# PCM Passthrough
+PCM_DUPLEX_ADD(Passthrough, 0, PIPELINE_PCM_1, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+# Clocks masters wrt codec
+#
+# TEST_SSP_DATA_BITS bit I2S using TEST_SSP_PHY_BITS bit sample conatiner on SSP TEST_DAI_PORT
+#
+DAI_CONFIG(TEST_DAI_TYPE, TEST_DAI_PORT,
+	   ifelse(index(TEST_DAI_LINK_NAME, NoCodec), -1, 0 ,TEST_DAI_PORT),
+	   TEST_DAI_LINK_NAME,
+	   SSP_CONFIG(TEST_SSP_MODE,
+		      SSP_CLOCK(mclk, TEST_SSP_MCLK, codec_mclk_in),
+		      SSP_CLOCK(bclk, TEST_SSP_BCLK, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, TEST_SSP_PHY_BITS, 3, 3),
+		      SSP_CONFIG_DATA(TEST_DAI_TYPE, TEST_DAI_PORT,
+				      TEST_SSP_DATA_BITS, TEST_SSP_MCLK_ID)))
diff --git a/topology/test/test-capture.m4 b/topology/test/test-capture.m4
new file mode 100644
index 0000000..4e10d3d
--- /dev/null
+++ b/topology/test/test-capture.m4
@@ -0,0 +1,89 @@
+#
+# Topology for pass through pipeline
+#
+
+# Include topology builder
+include(`dai.m4')
+include(`ssp.m4')
+include(`dmic.m4')
+include(`utils.m4')
+include(`pipeline.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`byt.m4')
+
+#
+# Machine Specific Config - !! MUST BE SET TO MATCH TEST MACHINE DRIVER !!
+#
+# TEST_PIPE_NAME - Pipe name
+# TEST_DAI_LINK_NAME - BE DAI link name e.g. "NoCodec"
+# TEST_DAI_PORT	- SSP port number e.g. 2
+# TEST_DAI_FORMAT - SSP data format e.g s16le
+# TEST_PIPE_FORMAT - Pipeline format e.g. s16le
+# TEST_SSP_MCLK - SSP MCLK in Hz
+# TEST_SSP_BCLK - SSP BCLK in Hz
+# TEST_SSP_PHY_BITS - SSP physical slot size
+# TEST_SSP_DATA_BITS - SSP data slot size
+# TEST_SSP_MODE - SSP mode e.g. I2S, LEFT_J, DSP_A and DSP_B
+#
+
+#
+# Define the pipeline
+#
+# PCM0 <---> SSP TEST_DAI_PORT
+#
+
+# Passthrough capture pipeline 2 on PCM 0 using max 4 channels.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+
+PIPELINE_PCM_DAI_ADD(sof/pipe-TEST_PIPE_NAME-capture.m4,
+	2, 0, 4, TEST_PIPE_FORMAT,
+	48, 1000, 0, 0,
+	TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_FORMAT, 2)
+
+#
+# DAI configuration
+#
+# SSP port TEST_DAI_PORT is our only pipeline DAI
+#
+# capture DAI is SSP TEST_DAI_PORT using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-capture.m4,
+	2, TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+	PIPELINE_SINK_2, 2, TEST_DAI_FORMAT,
+	48, 1000, 0, 0)
+
+# PCM Passthrough
+PCM_CAPTURE_ADD(Passthrough, 0, PIPELINE_PCM_2)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+# Clocks masters wrt codec
+#
+# TEST_SSP_DATA_BITS bit I2S using TEST_SSP_PHY_BITS bit sample conatiner on SSP TEST_DAI_PORT
+#
+DAI_CONFIG(TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+	   ifelse(TEST_DAI_TYPE, `SSP',
+		  SSP_CONFIG(TEST_SSP_MODE,
+			     SSP_CLOCK(mclk, TEST_SSP_MCLK, codec_mclk_in),
+			     SSP_CLOCK(bclk, TEST_SSP_BCLK, codec_slave),
+			     SSP_CLOCK(fsync, 48000, codec_slave),
+			     SSP_TDM(2, TEST_SSP_PHY_BITS, 3, 3),
+			     SSP_CONFIG_DATA(TEST_DAI_TYPE, TEST_DAI_PORT,
+					     TEST_SSP_DATA_BITS, TEST_SSP_MCLK_ID)),
+		  TEST_DAI_TYPE, `DMIC',
+		  DMIC_CONFIG(TEST_DMIC_DRIVER_VERSION, TEST_DMIC_CLK_MIN,
+			      TEST_DMIC_CLK_MAX, TEST_DMIC_DUTY_MIN,
+			      TEST_DMIC_DUTY_MAX, TEST_DMIC_SAMPLE_RATE,
+			      DMIC_WORD_LENGTH(TEST_DAI_FORMAT),
+			      TEST_DAI_TYPE, TEST_DAI_PORT,
+			      PDM_CONFIG(TEST_DAI_TYPE, TEST_DAI_PORT,
+					 TEST_DMIC_PDM_CONFIG)),
+		  `'))
diff --git a/topology/test/test-playback.m4 b/topology/test/test-playback.m4
new file mode 100644
index 0000000..9833ea9
--- /dev/null
+++ b/topology/test/test-playback.m4
@@ -0,0 +1,78 @@
+#
+# Topology for pass through pipeline
+#
+
+# Include topology builder
+include(`pipeline.m4')
+include(`dai.m4')
+include(`ssp.m4')
+include(`utils.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`byt.m4')
+
+#
+# Machine Specific Config - !! MUST BE SET TO MATCH TEST MACHINE DRIVER !!
+#
+# TEST_PIPE_NAME - Pipe name
+# TEST_DAI_LINK_NAME - BE DAI link name e.g. "NoCodec"
+# TEST_DAI_PORT	- SSP port number e.g. 2
+# TEST_DAI_FORMAT - SSP data format e.g s16le
+# TEST_PIPE_FORMAT - Pipeline format e.g. s16le
+# TEST_SSP_MCLK - SSP MCLK in Hz
+# TEST_SSP_BCLK - SSP BCLK in Hz
+# TEST_SSP_PHY_BITS - SSP physical slot size
+# TEST_SSP_DATA_BITS - SSP data slot size
+# TEST_SSP_MODE - SSP mode e.g. I2S, LEFT_J, DSP_A and DSP_B
+#
+
+#
+# Define the pipeline
+#
+# PCM0 <---> SSP TEST_DAI_PORT
+#
+
+# Passthrough playback pipeline 1 on PCM 0 using max 2 channels of s24le.
+# Schedule 48 frames per 1000us deadline on core 0 with priority 0
+
+PIPELINE_PCM_DAI_ADD(sof/pipe-TEST_PIPE_NAME-playback.m4,
+	1, 0, 2, TEST_PIPE_FORMAT,
+	48, 1000, 0, 0,
+	TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_FORMAT, 2)
+#
+# DAI configuration
+#
+# SSP port TEST_DAI_PORT is our only pipeline DAI
+#
+
+# playback DAI is SSP TEST_DAI_PORT using 2 periods
+# Buffers use s24le format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	1, TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+	PIPELINE_SOURCE_1, 2, TEST_DAI_FORMAT,
+	48, 1000, 0, 0)
+
+# PCM Passthrough
+PCM_PLAYBACK_ADD(Passthrough, 0, PIPELINE_PCM_1)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+# Clocks masters wrt codec
+#
+# TEST_SSP_DATA_BITS bit I2S using TEST_SSP_PHY_BITS bit sample conatiner on SSP TEST_DAI_PORT
+#
+DAI_CONFIG(TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+	   SSP_CONFIG(TEST_SSP_MODE,
+		      SSP_CLOCK(mclk, TEST_SSP_MCLK, codec_slave),
+		      SSP_CLOCK(bclk, TEST_SSP_BCLK, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, TEST_SSP_PHY_BITS, 3, 3),
+		      SSP_CONFIG_DATA(TEST_DAI_TYPE, TEST_DAI_PORT,
+				      TEST_SSP_DATA_BITS, TEST_SSP_MCLK_ID)))
diff --git a/topology/test/test-tone-playback.m4 b/topology/test/test-tone-playback.m4
new file mode 100644
index 0000000..77db4d1
--- /dev/null
+++ b/topology/test/test-tone-playback.m4
@@ -0,0 +1,70 @@
+#
+# Topology for Tone Generator Playback
+#
+
+# Include topology builder
+include(`pipeline.m4')
+include(`dai.m4')
+include(`ssp.m4')
+include(`utils.m4')
+
+# Include TLV library
+include(`common/tlv.m4')
+
+# Include Token library
+include(`sof/tokens.m4')
+
+# Include Baytrail DSP configuration
+include(`byt.m4')
+
+#
+# Machine Specific Config - !! MUST BE SET TO MATCH TEST MACHINE DRIVER !!
+#
+# TEST_PIPE_NAME - Pipe name
+# TEST_DAI_LINK_NAME - BE DAI link name e.g. "NoCodec"
+# TEST_DAI_PORT	- SSP port number e.g. 2
+# TEST_DAI_FORMAT - SSP data format e.g s16le
+# TEST_PIPE_FORMAT - Pipeline format e.g. s16le
+# TEST_SSP_MCLK - SSP MCLK in Hz
+# TEST_SSP_BCLK - SSP BCLK in Hz
+# TEST_SSP_PHY_BITS - SSP physical slot size
+# TEST_SSP_DATA_BITS - SSP data slot size
+#
+
+#
+# Define the pipeline
+#
+#  Tone --B0--> volume --B1--> SSP2
+#
+
+# Set sample rate for tone
+define(`TONE_SAMPLE_RATE', 48000)
+
+# Tone Playback pipeline 5 using max 2 channels of TEST_PIPE_FORMAT.
+# Schedule with 48 frame per 1000us deadline on core 0 with priority 0
+PIPELINE_ADD(sof/pipe-tone.m4,
+	5, 2, TEST_PIPE_FORMAT,
+	48, 1000, 0, 0)
+
+# playback DAI is SSP2 using 2 periods
+# Buffers use TEST_DAI_FORMAT format, with 48 frame per 1000us on core 0 with priority 0
+DAI_ADD(sof/pipe-dai-playback.m4,
+	5, TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+	PIPELINE_SOURCE_5, 2, TEST_DAI_FORMAT,
+	48, 1000, 2, 0)
+
+#
+# BE configurations - overrides config in ACPI if present
+#
+# Clocks masters wrt codec
+#
+# TEST_SSP_DATA_BITS bit I2S using TEST_SSP_PHY_BITS bit sample conatiner on SSP TEST_DAI_PORT
+#
+DAI_CONFIG(TEST_DAI_TYPE, TEST_DAI_PORT, TEST_DAI_PORT, TEST_DAI_LINK_NAME,
+	   SSP_CONFIG(TEST_SSP_MODE,
+		      SSP_CLOCK(mclk, TEST_SSP_MCLK, codec_mclk_in),
+		      SSP_CLOCK(bclk, TEST_SSP_BCLK, codec_slave),
+		      SSP_CLOCK(fsync, 48000, codec_slave),
+		      SSP_TDM(2, TEST_SSP_PHY_BITS, 3, 3),
+		      SSP_CONFIG_DATA(TEST_DAI_TYPE, TEST_DAI_PORT,
+				      TEST_SSP_DATA_BITS, TEST_SSP_MCLK_ID)))
diff --git a/topology/test/tplg-build.sh b/topology/test/tplg-build.sh
new file mode 100755
index 0000000..bd50593
--- /dev/null
+++ b/topology/test/tplg-build.sh
@@ -0,0 +1,252 @@
+#!/bin/bash
+
+# Utility script to pre-process and compile topology sources into topology test
+# binaries. Currently supports simple PCM <-> component <-> SSP style tests
+# using simple_test()
+
+# fail immediately on any errors
+set -e
+
+# M4 preprocessor flags
+export M4PATH="../:../m4:../common:../platform/intel:../platform/common"
+
+# Simple component test cases
+# can be used on components with 1 sink and 1 source.
+SIMPLE_TESTS=(test-all test-capture test-playback)
+TONE_TEST=test-tone-playback
+DMIC_TEST=test-capture
+TEST_STRINGS=""
+M4_STRINGS=""
+# process m4 simple tests -
+# simple_test(name, pipe_name, be_name, format, dai_id, dai_format, dai_phy_bits, dai_data_bits dai_bclk)
+# 1) name - test filename suffix
+# 2) pipe_name - test component pipeline filename in sof/
+# 3) be_name - BE DAI link name in machine driver, used for matching
+# 4) format - PCM sample format
+# 5) dai_type - dai type e.g. SSP/DMIC
+# 5) dai_id - SSP port number
+# 6) dai_format - SSP sample format
+# 7) dai_phy_bits - SSP physical number of BLKCs per slot/channel
+# 8) dai_data_bits - SSP number of valid data bits per slot/channel
+# 9) dai_bclk - SSP BCLK in HZ
+# 10) dai_mclk - SSP MCLK in HZ
+# 11) SSP mode - SSP mode e.g. I2S, LEFT_J, DSP_A and DSP_B
+# 12) SSP mclk_id
+# 13) Test pipelines
+#
+
+function simple_test {
+	if [ $5 == "SSP" ]
+	then
+		TESTS=("${!14}")
+	elif [ $5 == "DMIC" ]
+	then
+		TESTS=("${!15}")
+	fi
+	for i in ${TESTS[@]}
+	do
+		if [ $5 == "DMIC" ]
+		then
+			TFILE="$i-dmic$6-${14}-$2-$4-$7-$((${13} / 1000))k-$1"
+			echo "M4 pre-processing test $i -> ${TFILE}"
+			m4 ${M4_FLAGS} \
+				-DTEST_PIPE_NAME="$2" \
+				-DTEST_DAI_LINK_NAME="$3" \
+				-DTEST_DAI_PORT=$6 \
+				-DTEST_DAI_FORMAT=$7 \
+				-DTEST_PIPE_FORMAT=$4 \
+				-DTEST_DAI_TYPE=$5 \
+				-DTEST_DMIC_DRIVER_VERSION=$8 \
+				-DTEST_DMIC_CLK_MIN=$9 \
+				-DTEST_DMIC_CLK_MAX=${10} \
+				-DTEST_DMIC_DUTY_MIN=${11} \
+				-DTEST_DMIC_DUTY_MAX=${12} \
+				-DTEST_DMIC_SAMPLE_RATE=${13} \
+				-DTEST_DMIC_PDM_CONFIG=${14} \
+				$i.m4 > ${TFILE}.conf
+			echo "Compiling test $i -> ${TFILE}.tplg"
+			alsatplg -v 1 -c ${TFILE}.conf -o ${TFILE}.tplg
+		else
+			if [ "$USE_XARGS" == "yes" ]
+			then
+				#if DAI type is SSP, define the SSP specific params
+				if [ $5 == "SSP" ]
+				then
+					if [ $i == "test-all" ]
+					then
+						TFILE="test-ssp$6-mclk-${13}-${12}-$2-$4-$7-48k-$((${11} / 1000))k-$1"
+					else
+						TFILE="$i-ssp$6-mclk-${13}-${12}-$2-$4-$7-48k-$((${11} / 1000))k-$1"
+					fi
+					#create input string for batch m4 processing
+					M4_STRINGS+="-DTEST_PIPE_NAME=$2,-DTEST_DAI_LINK_NAME=$3\
+						-DTEST_DAI_PORT=$6,-DTEST_DAI_FORMAT=$7\
+						-DTEST_PIPE_FORMAT=$4,-DTEST_SSP_BCLK=${10}\
+						-DTEST_SSP_MCLK=${11},-DTEST_SSP_PHY_BITS=$8\
+						-DTEST_SSP_DATA_BITS=$9,-DTEST_SSP_MODE=${12}\
+						-DTEST_SSP_MCLK_ID=${13},-DTEST_DAI_TYPE=$5\
+						$i.m4,${TFILE},"
+					#create input string for batch processing of conf files
+					TEST_STRINGS+=${TFILE}","
+				fi
+			else
+				#if DAI type is SSP, define the SSP specific params
+				if [ $5 == "SSP" ]
+				then
+					if [ $i == "test-all" ]
+					then
+						TFILE="test-ssp$6-mclk-${13}-${12}-$2-$4-$7-48k-$((${11} / 1000))k-$1"
+					else
+						TFILE="$i-ssp$6-mclk-${13}-${12}-$2-$4-$7-48k-$((${11} / 1000))k-$1"
+					fi
+					echo "M4 pre-processing test $i -> ${TFILE}"
+					m4 ${M4_FLAGS} \
+						-DTEST_PIPE_NAME="$2" \
+						-DTEST_DAI_LINK_NAME="$3" \
+						-DTEST_DAI_PORT=$6 \
+						-DTEST_DAI_FORMAT=$7 \
+						-DTEST_PIPE_FORMAT=$4 \
+						-DTEST_SSP_BCLK=${10} \
+						-DTEST_SSP_MCLK=${11} \
+						-DTEST_SSP_PHY_BITS=$8 \
+						-DTEST_SSP_DATA_BITS=$9 \
+						-DTEST_SSP_MODE=${12} \
+						-DTEST_SSP_MCLK_ID=${13} \
+						-DTEST_DAI_TYPE=$5 \
+						$i.m4 > ${TFILE}.conf
+					echo "Compiling test $i -> ${TFILE}.tplg"
+					alsatplg -v 1 -c ${TFILE}.conf -o ${TFILE}.tplg
+				fi
+			fi
+		fi
+	done
+}
+
+echo "Preparing topology build input..."
+
+# Pre-process the simple tests
+simple_test nocodec passthrough "NoCodec-2" s16le SSP 2 s16le 20 16 1920000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec passthrough "NoCodec-2" s24le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec volume "NoCodec-2" s16le SSP 2 s16le 20 16 1920000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec volume "NoCodec-2" s24le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec volume "NoCodec-2" s16le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec src "NoCodec-2" s24le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+
+simple_test codec passthrough "SSP2-Codec" s16le SSP 2 s16le 20 16 1920000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test codec passthrough "SSP2-Codec" s24le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test codec volume "SSP2-Codec" s16le SSP 2 s16le 20 16 1920000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test codec volume "SSP2-Codec" s24le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test codec volume "SSP2-Codec" s24le SSP 2 s16le 20 16 1920000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test codec volume "SSP2-Codec" s16le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+simple_test codec src "SSP2-Codec" s24le SSP 2 s24le 25 24 2400000 19200000 I2S 0 SIMPLE_TESTS[@]
+
+# for APL
+APL_PROTOCOL_TESTS=(I2S LEFT_J DSP_A DSP_B)
+APL_SSP_TESTS=(0 1 2 3 4 5)
+APL_MODE_TESTS=(volume src)
+APL_FORMAT_TESTS=(s16le s24le s32le)
+MCLK_IDS=(0 1)
+
+for protocol in ${APL_PROTOCOL_TESTS[@]}
+do
+	for ssp in ${APL_SSP_TESTS[@]}
+	do
+		for mode in ${APL_MODE_TESTS[@]}
+		do
+			for format in ${APL_FORMAT_TESTS[@]}
+			do
+				for mclk_id in ${MCLK_IDS[@]}
+				do
+					simple_test nocodec $mode "NoCodec-${ssp}" $format SSP $ssp s16le 16 16 1536000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+					simple_test nocodec $mode "NoCodec-${ssp}" $format SSP $ssp s24le 32 24 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+					simple_test nocodec $mode "NoCodec-${ssp}" $format SSP $ssp s32le 32 32 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+
+					simple_test codec $mode "SSP${ssp}-Codec" $format SSP $ssp s16le 16 16 1536000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+					simple_test codec $mode "SSP${ssp}-Codec" $format SSP $ssp s24le 32 24 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+					simple_test codec $mode "SSP${ssp}-Codec" $format SSP $ssp s32le 32 32 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+				done
+			done
+		done
+		for mclk_id in ${MCLK_IDS[@]}
+		do
+			simple_test nocodec passthrough "NoCodec-${ssp}" s16le SSP $ssp s16le 16 16 1536000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+			simple_test nocodec passthrough "NoCodec-${ssp}" s24le SSP $ssp s24le 32 24 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+			simple_test nocodec passthrough "NoCodec-${ssp}" s32le SSP $ssp s32le 32 32 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+
+			simple_test codec passthrough "SSP${ssp}-Codec" s16le SSP $ssp s16le 16 16 1536000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+			simple_test codec passthrough "SSP${ssp}-Codec"	s24le SSP $ssp s24le 32 24 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+			simple_test codec passthrough "SSP${ssp}-Codec"	s32le SSP $ssp s32le 32 32 3072000 24576000 $protocol $mclk_id SIMPLE_TESTS[@]
+		done
+	done
+done
+
+for protocol in ${APL_PROTOCOL_TESTS[@]}
+do
+	for ssp in ${APL_SSP_TESTS[@]}
+	do
+		for mode in ${APL_MODE_TESTS[@]}
+		do
+			for format in ${APL_FORMAT_TESTS[@]}
+			do
+				simple_test nocodec $mode "NoCodec-${ssp}" $format SSP $ssp s16le 20 16 1920000 19200000 $protocol 0 SIMPLE_TESTS[@]
+				simple_test nocodec $mode "NoCodec-${ssp}" $format SSP $ssp s24le 25 24 2400000 19200000 $protocol 0 SIMPLE_TESTS[@]
+
+				simple_test codec $mode "SSP${ssp}-Codec" $format SSP $ssp s16le 20 16 1920000 19200000 $protocol 0 SIMPLE_TESTS[@]
+				simple_test codec $mode "SSP${ssp}-Codec" $format SSP $ssp s24le 25 24 2400000 19200000 $protocol 0 SIMPLE_TESTS[@]
+			done
+		done
+		simple_test nocodec passthrough "NoCodec-${ssp}" s16le SSP $ssp s16le 20 16 1920000 19200000 $protocol 0 SIMPLE_TESTS[@]
+		simple_test nocodec passthrough "NoCodec-${ssp}" s24le SSP $ssp s24le 25 24 2400000 19200000 $protocol 0 SIMPLE_TESTS[@]
+
+		simple_test codec passthrough "SSP${ssp}-Codec" s16le SSP $ssp s16le 20 16 1920000 19200000 $protocol 0 SIMPLE_TESTS[@]
+		simple_test codec passthrough "SSP${ssp}-Codec" s24le SSP $ssp s24le 25 24 2400000 19200000 $protocol 0 SIMPLE_TESTS[@]
+	done
+done
+
+# for CNL
+simple_test nocodec passthrough "NoCodec-2" s16le SSP 2 s16le 25 16 2400000 24000000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec passthrough "NoCodec-2" s24le SSP 2 s24le 25 24 2400000 24000000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec volume "NoCodec-2" s16le SSP 2 s16le 25 16 2400000 24000000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec volume "NoCodec-2" s16le SSP 2 s24le 25 24 2400000 24000000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec volume "NoCodec-2" s24le SSP 2 s24le 25 24 2400000 24000000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec volume "NoCodec-2" s24le SSP 2 s16le 25 16 2400000 24000000 I2S 0 SIMPLE_TESTS[@]
+simple_test nocodec src "NoCodec-4" s24le SSP 4 s24le 25 24 2400000 24000000 I2S 0 SIMPLE_TESTS[@]
+
+# Tone test: Tone component only supports s32le currently
+simple_test codec tone "SSP2-Codec" s32le SSP 2 s16le 20 16 1920000 19200000 I2S 0 TONE_TEST[@]
+#Tone Test for APL
+simple_test codec tone "SSP5-Codec" s32le SSP 5 s24le 32 24 3072000 24576000 I2S 0 TONE_TEST[@]
+simple_test codec tone "SSP5-Codec" s32le SSP 5 s32le 32 32 3072000 24576000 I2S 0 TONE_TEST[@]
+
+# DMIC Test Topologies for APL/GLK
+DMIC_PDM_CONFIGS=(MONO_PDM0_MICA MONO_PDM0_MICB STEREO_PDM0 STEREO_PDM1 FOUR_CH_PDM0_PDM1)
+DMIC_SAMPLE_RATE=(8000 16000 24000 32000 48000 64000 96000)
+DMIC_SAMPLE_FORMATS=(s16le s32le)
+
+for pdm in ${DMIC_PDM_CONFIGS[@]}
+do
+	for rate in ${DMIC_SAMPLE_RATE[@]}
+	do
+		for format in ${DMIC_SAMPLE_FORMATS[@]}
+		do
+			simple_test nocodec passthrough "DMIC0" $format DMIC 0\
+				$format 1 500000 4800000 40 60 $rate $pdm\
+				DMIC_TEST[@]
+		done
+	done
+done
+
+if [ "$USE_XARGS" == "yes" ]
+then
+	echo "Batch processing m4 files..."
+	M4_STRINGS=${M4_STRINGS%?}
+	#m4 processing
+	echo $M4_STRINGS | tr " " "," | tr '\n' '\0' | xargs -P0 -d ',' -n14 bash -c 'm4 "${@:1:${#}-1}" > ${14}.conf' m4
+
+	#execute alsatplg to create topology binary
+	TEST_STRINGS=${TEST_STRINGS%?}
+	echo $TEST_STRINGS | tr '\n' ',' |\
+		xargs -d ',' -P0 -n1 -I string alsatplg -v 1 -c\
+			string".conf" -o string".tplg"
+fi
+
diff --git a/tune/eq/eq_align.m b/tune/eq/eq_align.m
new file mode 100644
index 0000000..71edfd6
--- /dev/null
+++ b/tune/eq/eq_align.m
@@ -0,0 +1,52 @@
+function  [am, offs, p] = eq_align(f, m, f_align, m_align)
+
+%% [am, offs, p] = eq_align(f, m, f_align, m_align)
+%
+% Move by adding/subtracting an offset to frequency response
+% curve to cross desired frequency and magnitude, usually 997 Hz, 0 dB
+%
+% Input
+% f - frequencies
+% m - magnitude response
+%
+% Output
+% am - aligned magnitude resposne
+% offs - offset (gain) in decibels used
+% p - index of f_align in f
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+p = find(f < f_align, 1, 'last')+1;
+offs = m_align-m(p);
+am = m+offs;
+
+end
diff --git a/tune/eq/eq_alsactl_write.m b/tune/eq/eq_alsactl_write.m
new file mode 100644
index 0000000..56b7988
--- /dev/null
+++ b/tune/eq/eq_alsactl_write.m
@@ -0,0 +1,56 @@
+function eq_alsactl_write(fn, blob8)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Write blob
+fh = fopen(fn, 'w');
+
+%% Pad blob length to multiple of four bytes
+n_orig = length(blob8);
+n_new = ceil(n_orig/4);
+blob8_new = zeros(1, n_new*4);
+blob8_new(1:n_orig) = blob8;
+
+%% Convert to 32 bit
+blob32 = zeros(1, n_new, 'uint32');
+k = 2.^[0 8 16 24];
+for i=1:n_new
+	j = (i-1)*4;
+	blob32(i) = blob8_new(j+1)*k(1) + blob8_new(j+2)*k(2) ...
+		    +  blob8_new(j+3)*k(3) + blob8_new(j+4)*k(4);
+end
+for i=1:n_new-1
+	fprintf(fh, '%ld,', blob32(i));
+end
+fprintf(fh, '%ld,\n', blob32(end));
+fclose(fh);
+
+end
diff --git a/tune/eq/eq_blob_write.m b/tune/eq/eq_blob_write.m
new file mode 100644
index 0000000..95f8385
--- /dev/null
+++ b/tune/eq/eq_blob_write.m
@@ -0,0 +1,49 @@
+function eq_blob_write(fn, blob8)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Write blob
+fh = fopen(fn, 'wb');
+fwrite(fh, blob8, 'uint8');
+fclose(fh);
+
+%% Print as 8 bit hex
+nb = length(blob8);
+nl = ceil(nb/16);
+for i = 1:nl
+	m = min(16, nb-(i-1)*16);
+	for j = 1:m
+		fprintf(1, "%02x ", blob8((i-1)*16 + j));
+	end
+	fprintf(1, "\n");
+end
+
+end
diff --git a/tune/eq/eq_coef_quant.m b/tune/eq/eq_coef_quant.m
new file mode 100644
index 0000000..e56efca
--- /dev/null
+++ b/tune/eq/eq_coef_quant.m
@@ -0,0 +1,50 @@
+function qc = eq_coef_quant(c, bits, qf)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+scale = 2^qf;
+cmax =  2^(bits-1)-1;
+cmin = -2^(bits-1);
+qc = int64(round(c*scale));
+idx = find(qc > cmax);
+if ~isempty(idx)
+        fprintf('Warning: Max. value of Q format is exceeded: %d (%d)\n', ...
+                qc(idx(1)), cmax);
+        qc(idx) = cmax;
+end
+idx = find(qc < cmin);
+if ~isempty(idx)
+        fprintf('Warning: Min. value of Q format is exceeded: %d (%d)\n', ...
+                qc(idx(1)), cmin);
+        qc(idx) = cmin;
+end
+
+end
diff --git a/tune/eq/eq_compute.m b/tune/eq/eq_compute.m
new file mode 100644
index 0000000..57a6293
--- /dev/null
+++ b/tune/eq/eq_compute.m
@@ -0,0 +1,462 @@
+function eq = eq_compute( eq )
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Sanity checks
+if eq.enable_iir == 0 && eq.enable_fir == 0
+        fprintf('Warning: Nothing to do. Please enable FIR or IIR!\n');
+end
+
+%% Extrapolate response to 0..fs/2, convert to logaritmic grid, and smooth
+%  with 1/N octave filter
+eq = preprocess_responses(eq);
+
+%% Define target (e.g. speaker) response as parametric filter. This could also
+%  be numerical data interpolated to the grid.
+if length(eq.parametric_target_response) > 0
+        [eq.t_z, eq.t_p, eq.t_k] = eq_define_parametric_eq( ...
+                eq.parametric_target_response, eq.fs);
+        eq.t_db = eq_compute_response(eq.t_z, eq.t_p, eq.t_k, eq.f, eq.fs);
+end
+
+if isempty(eq.t_db)
+        fprintf('Warning: No target response is defined.\n');
+end
+
+%% Align responses at some frequency and dB
+[eq.m_db_s, offs] = eq_align(eq.f, eq.m_db_s, eq.f_align, eq.db_align);
+eq.raw_m_db = eq.raw_m_db + offs;
+eq.m_db = eq.m_db + offs;
+eq.t_db = eq_align(eq.f, eq.t_db, eq.f_align, eq.db_align);
+
+%% Error to equalize = target - raw response, apply 1/N octave smoothing to
+%  soften the EQ shape
+eq.err_db = eq.t_db - eq.m_db;
+[eq.err_db_s, eq.logsmooth_noct] = logsmooth(eq.f, eq.err_db, eq.logsmooth_eq);
+
+%% Parametric IIR EQ definition
+if eq.enable_iir
+        [eq.p_z, eq.p_p, eq.p_k] = eq_define_parametric_eq(eq.peq, eq.fs);
+        if max(length(eq.p_z), length(eq.p_p)) > 2*eq.iir_biquads_max
+                error('Maximum number of IIR biquads is exceeded');
+        end
+else
+        [eq.p_z, eq.p_p, eq.p_k] = tf2zp(1, 1);
+end
+[eq.iir_eq_db, eq.iir_eq_ph, eq.iir_eq_gd] = eq_compute_response(eq.p_z, ...
+        eq.p_p, eq.p_k, eq.f, eq.fs);
+
+
+%% FIR EQ computation
+%  Find remaining responses error ater IIR for FIR to handle
+if eq.fir_compensate_iir
+        eq.err2_db = eq.err_db_s-eq.iir_eq_db;
+else
+        eq.err2_db = eq.err_db_s;
+end
+
+if eq.enable_fir
+        [eq.t_fir_db, eq.fmin_fir, eq.fmax_fir] = ...
+                get_fir_target(eq.f, eq.err2_db, eq.fmin_fir, eq.fmax_fir, ...
+                eq.amin_fir, eq.amax_fir, eq.logsmooth_noct, eq.fir_autoband);
+
+        if eq.fir_minph
+                eq.b_fir = compute_minph_fir(eq.f, eq.t_fir_db, ...
+                        eq.fir_length, eq.fs, eq.fir_beta);
+        else
+                eq.b_fir = compute_linph_fir(eq.f, eq.t_fir_db, ...
+                        eq.fir_length, eq.fs, eq.fir_beta);
+        end
+else
+        eq.b_fir = 1;
+        eq.tfirdb = zeros(1,length(eq.f));
+end
+
+%% Update all responses
+eq = eq_compute_tot_response(eq);
+
+%% Normalize
+eq = eq_norm(eq);
+
+end
+
+function eq = preprocess_responses(eq)
+%% Usually too narrow measurement without the lowest and highest frequencies
+[f0, m0, gd0] = fix_response_dcnyquist_mult(eq.raw_f, eq.raw_m_db, ...
+        eq.raw_gd_s, eq.fs);
+
+%% Create dense logarithmic frequency grid, then average possible multiple
+%  measurements
+[eq.f, eq.m_db, eq.gd_s, eq.num_responses] = map_to_logfreq_mult(f0, m0, ...
+        gd0, 1, eq.fs/2, eq.np_fine);
+
+%% Smooth response with 1/N octave filter for plotting
+eq.m_db_s = logsmooth(eq.f, eq.m_db, eq.logsmooth_plot);
+
+if length(eq.target_m_db) > 0
+        % Use target_m_db as dummy group delay, ignore other than magnitude
+        [f0, m0, ~] = fix_response_dcnyquist_mult(eq.target_f, ...
+                eq.target_m_db, [], eq.fs);
+        [~, eq.t_db, ~, ~] = map_to_logfreq_mult(f0, m0, [], 1, ...
+                eq.fs/2, eq.np_fine);
+end
+end
+
+
+function [f_hz, m_db, gd_s] = fix_response_dcnyquist(f_hz0, m_db0, gd_s0, fs)
+%% Append DC and Fs/2 if missing
+f_hz = f_hz0;
+m_db = m_db0;
+gd_s = gd_s0;
+if min(f_hz) >  0
+        f_hz = [0 f_hz];
+        m_db = [m_db(1) m_db]; % DC the same as 1st measured point
+        if length(gd_s) > 0
+                gd_s = [gd_s(1) gd_s]; % DC the same as 1st measured point
+        end
+end
+if max(f_hz) <  fs/2
+        f_hz = [f_hz fs/2];
+        m_db = [m_db m_db(end)]; % Fs/2 the same as last measured point
+        if length(gd_s) > 0
+                gd_s = [gd_s gd_s(end)]; % Fs/2 the same as last measured point
+        end
+end
+end
+
+function [f_hz, m_db, gd_s] = fix_response_dcnyquist_mult(f_hz0, m_db0, ...
+        gd_s0, fs)
+
+if iscolumn(f_hz0)
+        f_hz0 = f_hz0.';
+end
+if iscolumn(m_db0)
+        m_db0 = m_db0.';
+end
+if iscolumn(gd_s0)
+        gd_s0 = gd_s0.';
+end
+
+s1 = size(f_hz0);
+s2 = size(m_db0);
+s3 = size(gd_s0);
+
+if s1(1) == 0
+        error('Frequencies vector is empty');
+end
+if (s1(1) ~= s2(1))
+        error('There must be equal number of frequency and magnitude data');
+end
+if (s1(2) ~= s2(2))
+        error('There must be equal number of points in frequency, magnitude, and group delay data');
+end
+if sum(s3) == 0
+        gd_s0 = zeros(s2(1),s2(2));
+end
+for i=1:s1(1)
+        [f_hz(i,:), m_db(i,:), gd_s(i,:)] = fix_response_dcnyquist(...
+                f_hz0(i,:), m_db0(i,:), gd_s0(i,:), fs);
+end
+
+end
+
+function [f_hz, m_db, gd_s] = map_to_logfreq(f_hz0, m_db0, gd_s0, f1, f2, np)
+%% Create logarithmic frequency vector and interpolate
+f_hz = logspace(log10(f1),log10(f2), np);
+m_db = interp1(f_hz0, m_db0, f_hz);
+gd_s = interp1(f_hz0, gd_s0, f_hz);
+m_db(end) = m_db(end-1); % Fix NaN in the end
+gd_s(end) = gd_s(end-1); % Fix NaN in the end
+end
+
+function [f_hz, mm_db, mgd_s, num] = map_to_logfreq_mult(f_hz0, m_db0, ...
+        gd_s0, f1, f2, np)
+
+s1 = size(f_hz0);
+s2 = size(m_db0);
+s3 = size(gd_s0);
+if (s1(1) ~= s2(1))
+        error('There must be equal number of frequency and magnitude data sets');
+end
+if (s1(2) ~= s2(2))
+        error('There must be equal number of points in frequency and magnitude data');
+end
+num = s1(1);
+if sum(s3) == 0
+        gd_s0 = zeros(s2(1),s2(2));
+end
+for i=1:num
+        [f_hz, m_db(i,:), gd_s(i,:)] = map_to_logfreq(f_hz0(i,:), ...
+                m_db0(i,:), gd_s0(i,:), f1, f2, np);
+end
+
+if num > 1
+        mm_db = mean(m_db);
+        mgd_s = mean(gd_s);
+else
+        mm_db = m_db;
+        mgd_s = gd_s;
+end
+end
+
+function [ms_db, noct] = logsmooth(f, m_db, c)
+
+%% Create a 1/N octave smoothing filter
+ind1 = find(f < 1000);
+ind2 = find(f < 2000);
+noct = ind2(end)-ind1(end);
+n = 2*round(c*noct/2);
+b_smooth = ones(1,n)*1/n;
+
+%% Smooth the response
+tmp = filter(b_smooth, 1, m_db);
+ms_db = [tmp(n/2+1:end) linspace(tmp(end), m_db(end), n/2)];
+ms_db(1:n) = ones(1,n)*ms_db(n);
+end
+
+function [m_db, fmin_fir, fmax_fir] = get_fir_target(fhz, err2db, fmin_fir, ...
+        fmax_fir, amin_fir, amax_fir, noct, auto)
+
+
+%% Find maximum in 1-6 kHz band
+idx = find(fhz > 1e3, 1, 'first') - 1;
+m_db = err2db - err2db(idx);
+if auto
+        cf = [1e3 6e3];
+        ind1 = find(fhz < cf(2));
+        ind2 = find(fhz(ind1) > cf(1));
+        ipeak = find(m_db(ind2) == max(m_db(ind2))) + ind2(1);
+        ind1 = find(fhz < cf(1));
+        ind2 = find(m_db(ind1) > m_db(ipeak));
+        if length(ind2) > 0
+                fmin_fir = fhz(ind2(end));
+        end
+        ind1 = find(fhz > cf(2));
+        ind2 = find(m_db(ind1) > m_db(ipeak)) + ind1(1);
+        if length(ind2) > 0
+                fmax_fir = fhz(ind2(1));
+        end
+end
+
+%% Find FIR target response
+ind1 = find(fhz < fmin_fir);
+ind2 = find(fhz > fmax_fir);
+p1 = ind1(end)+1;
+if length(ind2) > 0
+        p2 = ind2(1)-1;
+else
+        p2 = length(fhz);
+end
+m_db(ind1) = m_db(p1);
+m_db(ind2) = m_db(p2);
+ind = find(m_db > amax_fir);
+m_db(ind) = amax_fir;
+ind = find(m_db < amin_fir);
+m_db(ind) = amin_fir;
+
+%% Smooth high frequency corner with spline
+nn = round(noct/8);
+x = [p2-nn p2-nn+1 p2+nn-1 p2+nn];
+if max(x) < length(m_db)
+        y = m_db(x);
+        xx = p2-nn:p2+nn;
+        yy = spline(x, y, xx);
+        m_db(p2-nn:p2+nn) = yy;
+end
+
+%% Smooth low frequency corner with spline
+nn = round(noct/8);
+x = [p1-nn p1-nn+1 p1+nn-1 p1+nn];
+if min(x) > 0
+        y = m_db(x);
+        xx = p1-nn:p1+nn;
+        yy = spline(x, y, xx);
+        m_db(p1-nn:p1+nn) = yy;
+end
+
+end
+
+function b = compute_linph_fir(f_hz, m_db, taps, fs, beta)
+if nargin < 5
+        beta = 4;
+end
+if mod(taps,2) == 0
+        fprintf('Warning: Even FIR length requested.\n');
+end
+n_fft = 2*2^ceil(log(taps)/log(2));
+n_half = n_fft/2+1;
+f_fft = linspace(0, fs/2, n_half);
+m_lin = 10.^(m_db/20);
+if f_hz(1) > 0
+        f_hz = [0 f_hz];
+        m_lin = [m_lin(1) m_lin];
+end
+a_half = interp1(f_hz, m_lin, f_fft, 'linear');
+a = [a_half conj(a_half(end-1:-1:2))];
+h = real(fftshift(ifft(a)));
+b0 = h(n_half-floor((taps-1)/2):n_half+floor((taps-1)/2));
+win = kaiser(length(b0), beta)';
+b = b0 .* win;
+if length(b) < taps
+        % Append to even length
+        b = [b 0];
+end
+end
+
+function b_fir = compute_minph_fir(f, m_db, fir_length, fs, beta)
+
+%% Design double length H^2 FIR
+n = 2*fir_length+1;
+m_lin2 = (10.^(m_db/20)).^2;
+m_db2 = 20*log10(m_lin2);
+blin = compute_linph_fir(f, m_db2, n, fs,  beta);
+
+%% Find zeros inside unit circle
+myeps = 1e-3;
+hdzeros = roots(blin);
+ind1 = find( abs(hdzeros) < (1-myeps) );
+minzeros = hdzeros(ind1);
+
+%% Find double zeros at unit circle
+ind2 = find( abs(hdzeros) > (1-myeps) );
+outzeros = hdzeros(ind2);
+ind3 = find( abs(outzeros) < (1+myeps) );
+circlezeros = outzeros(ind3);
+
+%% Get half of the unit circle zeros
+if isempty(circlezeros)
+        %% We are fine ...
+else
+        %% Eliminate double zeros
+        cangle = angle(circlezeros);
+        [sorted_cangle, ind] = sort(cangle);
+        sorted_czeros = circlezeros(ind);
+        pos = find(angle(sorted_czeros) > 0);
+        neg = find(angle(sorted_czeros) < 0);
+        pos_czeros = sorted_czeros(pos);
+        neg_czeros = sorted_czeros(neg(end:-1:1));
+        h1 = [];
+        for i = 1:2:length(pos_czeros)-1
+                x=mean(angle(pos_czeros(i:i+1)));
+                h1 = [h1' complex(cos(x),sin(x))]';
+        end
+        h2 = [];
+        for i = 1:2:length(neg_czeros)-1;
+                x=mean(angle(neg_czeros(i:i+1)));
+                h2 = [h2' complex(cos(x),sin(x))]';
+        end
+        halfcirclezeros = [h1' h2']';
+        if length(halfcirclezeros)*2 < length(circlezeros)-0.1
+                %% Replace the last zero pair
+                halfcirclezeros = [halfcirclezeros' complex(-1, 0)]';
+        end
+        minzeros = [ minzeros' halfcirclezeros' ]';
+end
+
+%% Convert to transfer function
+bmin = mypoly(minzeros);
+
+%% Scale peak in passhz to max m_db
+hmin = freqz(bmin, 1, 512, fs);
+b_fir = 10^(max(m_db)/20)*bmin/max(abs(hmin));
+
+end
+
+function tf = mypoly( upolyroots )
+
+% Sort roots to increasing angle to ensure more consistent behavior
+aa = abs(angle(upolyroots));
+[sa, ind] = sort(aa);
+polyroots = upolyroots(ind);
+
+n = length(polyroots);
+n1 = 16; % do not change, hardwired to 16 code below
+
+if n < (2*n1+1)
+        % No need to split
+        tf = poly(polyroots);
+else
+        % Split roots evenly to 16 poly computations
+        % The fist polys will rpb+1 roots and the rest
+        % rpb roots to compute
+        rpb = floor(n/n1);
+        rem = mod(n,n1);
+        i1 = zeros(1,n1);
+        i2 = zeros(1,n1);
+        i1(1) = 1;
+        for i = 1:n1-1;
+                if rem > 0
+                        i2(i) = i1(i)+rpb;
+                        rem = rem-1;
+                else
+                        i2(i) = i1(i)+rpb-1;
+                end
+                i1(i+1) = i2(i)+1;
+        end
+        i2(n1) = n;
+        tf101 = poly(polyroots(i1(1):i2(1)));
+        tf102 = poly(polyroots(i1(2):i2(2)));
+        tf103 = poly(polyroots(i1(3):i2(3)));
+        tf104 = poly(polyroots(i1(4):i2(4)));
+        tf105 = poly(polyroots(i1(5):i2(5)));
+        tf106 = poly(polyroots(i1(6):i2(6)));
+        tf107 = poly(polyroots(i1(7):i2(7)));
+        tf108 = poly(polyroots(i1(8):i2(8)));
+        tf109 = poly(polyroots(i1(9):i2(9)));
+        tf110 = poly(polyroots(i1(10):i2(10)));
+        tf111 = poly(polyroots(i1(11):i2(11)));
+        tf112 = poly(polyroots(i1(12):i2(12)));
+        tf113 = poly(polyroots(i1(13):i2(13)));
+        tf114 = poly(polyroots(i1(14):i2(14)));
+        tf115 = poly(polyroots(i1(15):i2(15)));
+        tf116 = poly(polyroots(i1(16):i2(16)));
+        % Combine coefficients with convolution
+        tf21 = conv(tf101, tf116);
+        tf22 = conv(tf102, tf115);
+        tf23 = conv(tf103, tf114);
+        tf24 = conv(tf104, tf113);
+        tf25 = conv(tf105, tf112);
+        tf26 = conv(tf106, tf111);
+        tf27 = conv(tf107, tf110);
+        tf28 = conv(tf108, tf109);
+        tf31 = conv(tf21, tf28);
+        tf32 = conv(tf22, tf27);
+        tf33 = conv(tf23, tf26);
+        tf34 = conv(tf24, tf25);
+        tf41 = conv(tf31, tf34);
+        tf42 = conv(tf32, tf33);
+        tf   = conv(tf41, tf42);
+
+        % Ensure the tf coefficents are real if rounding issues
+        tf = real(tf);
+end
+
+end
diff --git a/tune/eq/eq_compute_response.m b/tune/eq/eq_compute_response.m
new file mode 100644
index 0000000..e8a4704
--- /dev/null
+++ b/tune/eq/eq_compute_response.m
@@ -0,0 +1,72 @@
+function [m, ph, gd] = eq_compute_response(z, p, k, f, fs)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+switch nargin
+        case 3
+                b = z;  % 1st arg
+                f = p;  % 2nd arg
+                fs = k; % 3rd arg
+                h = freqz(b, 1, f, fs);
+                m = 20*log10(abs(h));
+                ph = 180/pi*angle(h);
+
+                if length(b) == 1
+                        gd = zeros(1, length(f));
+                else
+			if exist('OCTAVE_VERSION', 'builtin')
+				% grpdelay() has some issue so better to not show a plot
+				gd = NaN * zeros(1, length(f));
+			else
+				gd = 1/fs*grpdelay(b, 1, f, fs);
+			end
+                end
+        case 5
+                [b, a] = zp2tf(z, p, k);
+                h = freqz(b, a, f, fs);
+                m = 20*log10(abs(h));
+                ph = 180/pi*angle(h);
+
+                if length(z) == 0 && length(p) == 0
+                        gd = zeros(1, length(f));
+                else
+			if exist('OCTAVE_VERSION', 'builtin')
+				% grpdelay() has some issue so better to not show a plot
+				gd = NaN * zeros(1, length(f));
+			else
+				gd = 1/fs*grpdelay(b, a, f, fs);
+			end
+                end
+        otherwise
+                error('Incorrect input parameters');
+end
+
+end
diff --git a/tune/eq/eq_compute_tot_response.m b/tune/eq/eq_compute_tot_response.m
new file mode 100644
index 0000000..250c364
--- /dev/null
+++ b/tune/eq/eq_compute_tot_response.m
@@ -0,0 +1,50 @@
+function eq = eq_compute_tot_response(eq)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+% FIR response and combined IIR+FIR EQ
+[eq.iir_eq_db, eq.iir_eq_ph, eq.iir_eq_gd] = eq_compute_response(eq.p_z, eq.p_p, eq.p_k, eq.f, eq.fs);
+[eq.fir_eq_db, eq.fir_eq_ph, eq.fir_eq_gd] = eq_compute_response(eq.b_fir, eq.f, eq.fs);
+eq.tot_eq_db = eq.iir_eq_db + eq.fir_eq_db;
+eq.tot_eq_gd = eq.iir_eq_gd + eq.fir_eq_gd;
+
+% Simulated equalized result
+eq.m_eqd = eq.m_db + eq.tot_eq_db; % Simulated response
+eq.m_eqd_s = eq.m_db_s + eq.tot_eq_db; % Smoothed simulated response
+eq.gd_eqd = eq.gd_s' + eq.tot_eq_gd;
+
+% Align
+[eq.m_eqd_s, adjust, p] = eq_align(eq.f, eq.m_eqd_s, eq.f_align, eq.db_align);
+eq.m_eqd = eq.m_eqd + adjust;
+eq.m_eq_loss = eq.tot_eq_db(p);
+eq.m_eqd_abs = eq.m_db_abs+eq.m_eq_loss;
+
+end
diff --git a/tune/eq/eq_defaults.m b/tune/eq/eq_defaults.m
new file mode 100644
index 0000000..880e4e3
--- /dev/null
+++ b/tune/eq/eq_defaults.m
@@ -0,0 +1,113 @@
+function p = eq_defaults
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+% Misc
+p.plot_figs = 0;
+p.fn = 'configuration.txt';
+p.fs = 48e3;
+p.f_align = 997;
+p.db_align = 0;
+p.logsmooth_plot = 1/3; % Smooth over 1/3 octaves
+p.logsmooth_eq = 1/3; % Smooth over 1/3 octaves
+p.np_fine = 5000; % 5000 point design grid
+
+% Parametric EQ IDs
+p.PEQ_HP1 = 1; p.PEQ_HP2 = 2; p.PEQ_LP1 = 3; p.PEQ_LP2 = 4;
+p.PEQ_LS1 = 5; p.PEQ_LS2 = 6; p.PEQ_HS1 = 7; p.PEQ_HS2 = 8;
+p.PEQ_PN2 = 9; p.PEQ_LP4 = 10; p.PEQ_HP4 = 11;
+
+% FIR constraints
+p.fmin_fir = 200; %
+p.fmax_fir = 15e3; %
+p.amax_fir =  20;
+p.amin_fir = -20;
+p.fir_beta = 8;
+p.fir_length = 63;
+p.fir_minph = 0; % 0 = linear phase, 1 = minimum phase
+% Adjust fmin_fir, fmax_fir automatically for least gain loss in FIR
+p.fir_autoband = 1;
+p.enable_fir = 0;
+
+% IIR conf
+p.iir_biquads_max = 8;
+p.enable_iir = 0;
+
+% Initialize other fields those are computed later to allow use of struct
+% arrays
+p.raw_f = [10 100e3];
+p.raw_m_db = [0 0];
+p.raw_gd_s = [];
+p.f = [];
+p.m_db = [];
+p.gd_s = [];
+p.num_responses = 0;
+p.m_db_s = [];
+p.gd_s_s = [];
+p.logsmooth_noct = 0;
+p.t_z = [];
+p.t_p = [];
+p.t_k = [];
+p.t_db = [];
+p.m_db_abs = 0;
+p.m_db_offs = 0;
+p.raw_m_noalign_db = [];
+p.err_db = [];
+p.p_z = [];
+p.p_p = [];
+p.p_k = [];
+p.iir_eq_db = [];
+p.iir_eq_ph = [];
+p.iir_eq_gd = [];
+p.err2_db = [];
+p.t_fir_db = [];
+p.b_fir = [];
+p.fir_eq_db = [];
+p.fir_eq_ph = [];
+p.fir_eq_gd = [];
+p.tot_eq_db = [];
+p.tot_eq_gd = [];
+p.m_eqd = [];
+p.gd_eqd = [];
+p.m_eq_loss = 0;
+p.m_eqd_abs = 0;
+p.sim_m_db = [];
+p.parametric_target_response = [];
+p.target_f = [10 100e3];
+p.target_m_db = [0 0];
+p.fir_compensate_iir = 1;
+p.p_fmin = 10;
+p.p_fmax = 30e3;
+p.name = '';
+p.norm_type = 'loudness'; % loudness/peak/1k
+p.norm_offs_db = 0;
+
+end
diff --git a/tune/eq/eq_define_parametric_eq.m b/tune/eq/eq_define_parametric_eq.m
new file mode 100644
index 0000000..2beecf2
--- /dev/null
+++ b/tune/eq/eq_define_parametric_eq.m
@@ -0,0 +1,143 @@
+function [z, p, k] = eq_define_parametric_eq(peq, fs)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+% Parametric types
+PEQ_HP1 = 1; PEQ_HP2 = 2; PEQ_LP1 = 3; PEQ_LP2 = 4;
+PEQ_LS1 = 5; PEQ_LS2 = 6; PEQ_HS1 = 7; PEQ_HS2 = 8;
+PEQ_PN2 = 9; PEQ_LP4 = 10; PEQ_HP4 = 11;
+
+sp = size(peq);
+z = [];
+p = [];
+k = 1;
+for i=1:sp(1)
+        type = peq(i,1);
+        f = peq(i,2);
+        g = peq(i,3);
+        Q = peq(i,4);
+        if f < fs/2
+                a0 = [];
+                b0 = [];
+                z0 = [];
+                p0 = [];
+                k0 = [];
+                switch peq(i,1)
+                        case PEQ_HP1, [z0, p0, k0] = butter(1, 2*f/fs, 'high');
+                        case PEQ_HP2, [z0, p0, k0] = butter(2, 2*f/fs, 'high');
+                        case PEQ_HP4, [z0, p0, k0] = butter(4, 2*f/fs, 'high');
+                        case PEQ_LP1, [z0, p0, k0] = butter(1, 2*f/fs);
+                        case PEQ_LP2, [z0, p0, k0] = butter(2, 2*f/fs);
+                        case PEQ_LP4, [z0, p0, k0] = butter(4, 2*f/fs);
+                        case PEQ_LS1, [b0, a0] = low_shelf_1st(f, g, fs);
+                        case PEQ_LS2, [b0, a0] = low_shelf_2nd(f, g, fs);
+                        case PEQ_HS1, [b0, a0] = high_shelf_1st(f, g, fs);
+                        case PEQ_HS2, [b0, a0] = high_shelf_2nd(f, g, fs);
+                        case PEQ_PN2, [b0, a0] = peak_2nd(f, g, Q, fs);
+                        otherwise
+                                error('Unknown parametric EQ type');
+                end
+                if length(a0) > 0
+                        [z0, p0, k0] = tf2zp(b0, a0);
+                end
+                if length(k0) > 0
+                        z = [z ; z0(:)];
+                        p = [p ; p0(:)];
+                        k = k * k0;
+                end
+        end
+end
+end
+
+function [b, a] = low_shelf_1st(fhz, gdb, fs)
+zw = 2*pi*fhz;
+w = wmap(zw, fs);
+glin = 10^(gdb/20);
+bs = [1 glin*w];
+as = [1 w];
+[b, a] = my_bilinear(bs, as, fs);
+end
+
+function [b, a] = low_shelf_2nd(fhz, gdb, fs)
+zw = 2*pi*fhz;
+w = wmap(zw, fs);
+glin = 10^(gdb/20);
+bs = [1 w*sqrt(2*glin) glin*w^2];
+as = [1 w*sqrt(2) w^2];
+[b, a] = my_bilinear(bs, as, fs);
+end
+
+function [b, a] = high_shelf_1st(fhz, gdb, fs)
+zw = 2*pi*fhz;
+w = wmap(zw, fs);
+glin = 10^(gdb/20);
+bs = [glin w];
+as = [1 w];
+[b, a] = my_bilinear(bs, as, fs);
+end
+
+function [b, a] = high_shelf_2nd(fhz, gdb, fs)
+zw = 2*pi*fhz;
+w = wmap(zw, fs);
+glin = 10^(gdb/20);
+bs = [glin w*sqrt(2*glin) w^2];
+as = [1 w*sqrt(2) w^2];
+[b, a] = my_bilinear(bs, as, fs);
+end
+
+
+function [b, a] = peak_2nd(fhz, gdb, Q, fs)
+	% Reference http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
+	A = 10^(gdb/40); % Square root of linear gain
+	wc = 2*pi*fhz/fs;
+	alpha = sin(wc)/(2*Q);
+	b0 = 1 + alpha * A;
+	b1 = -2 * cos(wc);
+	b2 = 1 - alpha * A;
+	a0 = 1 + alpha / A;
+	a1 = -2 * cos(wc);
+	a2 = 1 - alpha / A;
+	b = [b0 / a0 b1 / a0 b2 / a0];
+	a = [1 a1 / a0 a2 / a0];
+end
+
+function [b, a] = my_bilinear(sb, sa, fs)
+if exist('OCTAVE_VERSION', 'builtin')
+        [b, a] = bilinear(sb, sa, 1/fs);
+else
+        [b, a] = bilinear(sb, sa, fs);
+end
+end
+
+function sw = wmap(w, fs)
+t = 1/fs;
+sw = 2/t*tan(w*t/2);
+end
diff --git a/tune/eq/eq_fir_blob_merge.m b/tune/eq/eq_fir_blob_merge.m
new file mode 100644
index 0000000..6876453
--- /dev/null
+++ b/tune/eq/eq_fir_blob_merge.m
@@ -0,0 +1,50 @@
+function bs = eq_fir_blob_merge(platform_max_channels, ...
+        number_of_responses_defined, assign_response, all_coefficients);
+
+%% Merge equalizer definition into a struct used by successive blob making
+%  functions.
+%
+% bs = eq_fir_blob_merge(platform_max_channels, number_of_responses_defined, ...
+%        assign_response, all_coefficients);
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if length(assign_response) ~= platform_max_channels
+	error("Incorrect length in EQ assign vector!");
+end
+
+bs.platform_max_channels = platform_max_channels;
+bs.number_of_responses_defined = number_of_responses_defined;
+bs.assign_response = assign_response;
+bs.all_coefficients = all_coefficients;
+
+end
diff --git a/tune/eq/eq_fir_blob_pack.m b/tune/eq/eq_fir_blob_pack.m
new file mode 100644
index 0000000..f8e647f
--- /dev/null
+++ b/tune/eq/eq_fir_blob_pack.m
@@ -0,0 +1,139 @@
+function blob8 = eq_fir_blob_pack(bs, endian)
+
+%% Pack equalizer struct to bytes
+%
+% blob8 = eq_fir_blob_pack(bs, endian)
+% bs - blob struct
+% endian - optional, use 'little' or 'big'. Defaults to little.
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 2
+	endian = 'little';
+end
+
+%% Endiannes of blob
+switch lower(endian)
+        case 'little'
+                sh16 = [0 -8];
+                sh32 = [0 -8 -16 -24];
+        case 'big'
+                sh16 = [-8 0];
+                sh32 = [-24 -16 -8 0];
+        otherwise
+                error('Unknown endiannes');
+end
+
+%% Channels count must be even
+if mod(bs.platform_max_channels, 2) > 0
+	error("Channels # must be even");
+end
+
+%% Channels cound and assign vector length must be the same
+if bs.platform_max_channels ~= length( bs.assign_response)
+	bs
+	error("Channels # and response assign length must match");
+end
+
+%% Coefficients vector length must be multiple of 4
+len = length(bs.all_coefficients);
+len_no_header = len - 2 * bs.number_of_responses_defined;
+if mod(len_no_header, 4) > 0
+	bs
+	error("Coefficient data vector length must be multiple of 4");
+end
+
+%% Pack as 16 bits
+nh16 = 4+bs.platform_max_channels;
+h16 = zeros(1, nh16, 'int16');
+h16(3) = bs.platform_max_channels;
+h16(4) = bs.number_of_responses_defined;
+for i=1:bs.platform_max_channels
+        h16(4+i) = bs.assign_response(i);
+end
+
+%% Merge header and coefficients, make even number of int16 to make it
+%  multiple of int32
+nc16 = length(bs.all_coefficients);
+nb16 = ceil((nh16+nc16)/2)*2;
+blob16 = zeros(1,nb16, 'int16');
+blob16(1:nh16) = h16;
+blob16(nh16+1:nh16+nc16) = int16(bs.all_coefficients);
+
+%% Print as 16 bit hex
+nl = ceil(nb16/16);
+for i = 1:nl
+	m = min(16, nb16-(i-1)*16);
+	for j = 1:m
+		k = (i-1)*16 + j;
+		v =  int32(blob16(k));
+		if v < 0
+			v = 65536+v;
+		end
+		fprintf(1, "%04x ", v);
+	end
+	fprintf(1, "\n");
+end
+fprintf(1, "\n");
+
+
+%% Pack as 8 bits
+nb8 = length(blob16)*2;
+blob8 = zeros(1, nb8, 'uint8');
+j = 1;
+for i = 1:length(blob16)
+        blob8(j:j+1) = w16b(blob16(i), sh16);
+        j = j+2;
+end
+
+%% Add size into first four bytes
+blob8(1:4) = w32b(nb8, sh32);
+
+%% Done
+fprintf('Blob size is %d bytes.\n', nb8);
+
+end
+
+
+function bytes = w16b(word, sh)
+bytes = uint8(zeros(1,2));
+bytes(1) = bitand(bitshift(word, sh(1)), 255);
+bytes(2) = bitand(bitshift(word, sh(2)), 255);
+end
+
+function bytes = w32b(word, sh)
+bytes = uint8(zeros(1,4));
+bytes(1) = bitand(bitshift(word, sh(1)), 255);
+bytes(2) = bitand(bitshift(word, sh(2)), 255);
+bytes(3) = bitand(bitshift(word, sh(3)), 255);
+bytes(4) = bitand(bitshift(word, sh(4)), 255);
+end
diff --git a/tune/eq/eq_fir_blob_quant.m b/tune/eq/eq_fir_blob_quant.m
new file mode 100644
index 0000000..6d06003
--- /dev/null
+++ b/tune/eq/eq_fir_blob_quant.m
@@ -0,0 +1,105 @@
+function fbr = eq_fir_blob_quant(b, bits)
+
+%% Quantize FIR coefficients and return vector with length,
+%  out shift, and coefficients to be used in the setup blob.
+%
+%  fbr = eq_fir_blob_resp(b, bits)
+%  b - FIR coefficients
+%  bits - optional number of bits, defaults to 16
+%
+%  fbr - vector with length, in shift, out shift, and quantized coefficients
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 2
+	bits = 16;
+end
+
+%% Quantize
+[bq, shift] = eq_fir_quantize(b, bits);
+
+%% Check trailing zeros
+nf = length(bq);
+nz = nf;
+while bq(nz) == 0
+	nz = nz - 1;
+end
+if nz < nf
+	nb = nz + 1;
+	fprintf(1,'Note: Filter length was reduced to %d -> %d due to trailing zeros.\n', ...
+		nf, nb);
+	bq = bq(1:nb);
+else
+	nb = nf;
+end
+
+%% Make length multiple of four (optimized FIR core)
+mod4 = mod(nb, 4);
+if mod4 > 0
+	pad = zeros(1,4-mod4);
+	bqp = [bq pad];
+	nnew = length(bqp);
+	fprintf(1,'Note: Filter length was %d, padded length into %d.\n', nb, nnew);
+else
+	nnew = nb;
+	bqp = bq;
+end
+
+fbr = [nnew shift bqp];
+
+end
+
+function [bq, shift] = eq_fir_quantize(b, bits)
+
+% [bq, shift] = eq_fir_quantize(b, bits)
+%
+% Inputs
+% b - FIR coefficients
+% bits - number bits for 2s complement coefficient
+%
+% Outputs
+% bq - quantized coefficients
+% shift - shift right parameter to apply after FIR computation to
+% compensate for coefficients scaling
+%
+
+scale = 2^(bits-1);
+
+%% Output shift for coefficients
+m = max(abs(b));
+shift = -ceil(log(m+1/scale)/log(2));
+bsr = b*2^shift;
+
+%% Quantize to Q1.bits-1 format, e.g. Q1.15 for 16 bits
+bq = eq_coef_quant(bsr, bits, bits-1);
+
+end
diff --git a/tune/eq/eq_iir_blob_merge.m b/tune/eq/eq_iir_blob_merge.m
new file mode 100644
index 0000000..c05fe67
--- /dev/null
+++ b/tune/eq/eq_iir_blob_merge.m
@@ -0,0 +1,52 @@
+function bs = eq_iir_blob_merge(platform_max_channels, ...
+        number_of_responses_defined, ...
+        assign_response, ...
+        all_coefficients);
+
+%% Merge equalizer definition into a struct used by successive blob making
+%  functions.
+%
+% bs = eq_iir_blob_merge(platform_max_channels, number_of_responses_defined, ...
+%        assign_response, all_coefficients);
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if length(assign_response) ~= platform_max_channels
+	error("Assign response does not match channels count!");
+end
+
+bs.platform_max_channels = platform_max_channels;
+bs.number_of_responses_defined = number_of_responses_defined;
+bs.assign_response = assign_response;
+bs.all_coefficients = all_coefficients;
+
+end
diff --git a/tune/eq/eq_iir_blob_pack.m b/tune/eq/eq_iir_blob_pack.m
new file mode 100644
index 0000000..8a55f38
--- /dev/null
+++ b/tune/eq/eq_iir_blob_pack.m
@@ -0,0 +1,84 @@
+function blob8 = eq_iir_blob_pack(bs, endian)
+
+%% Pack equalizer struct to bytes
+%
+% blob8 = eq_iir_blob_pack(bs, endian)
+% bs - blob struct
+% endian - optional, use 'little' or 'big'. Defaults to little.
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 2
+	endian = 'little';
+end
+
+%% Shift values for little/big endian
+switch lower(endian)
+        case 'little'
+                sh = [0 -8 -16 -24];
+        case 'big'
+                sh = [-24 -16 -8 0];
+        otherwise
+                error('Unknown endiannes');
+end
+
+%% Pack as 8 bits, header
+nbytes_head = (3+bs.platform_max_channels)*4;
+nbytes_coef = length(bs.all_coefficients)*4;
+nbytes = nbytes_head + nbytes_coef;
+blob8 = uint8(zeros(1,nbytes));
+
+j = 1;
+blob8(j:j+3) = w2b(nbytes, sh); j=j+4;
+blob8(j:j+3) = w2b(bs.platform_max_channels, sh); j=j+4;
+blob8(j:j+3) = w2b(bs.number_of_responses_defined, sh); j=j+4;
+
+for i=1:bs.platform_max_channels
+        blob8(j:j+3) = w2b(bs.assign_response(i), sh); j=j+4;
+end
+
+%% Pack coefficients
+for i=1:length(bs.all_coefficients)
+        blob8(j:j+3) = w2b(bs.all_coefficients(i), sh); j=j+4;
+end
+fprintf('Blob size is %d bytes.\n', nbytes);
+
+
+end
+
+function bytes = w2b(word, sh)
+bytes = uint8(zeros(1,4));
+bytes(1) = bitand(bitshift(word, sh(1)), 255);
+bytes(2) = bitand(bitshift(word, sh(2)), 255);
+bytes(3) = bitand(bitshift(word, sh(3)), 255);
+bytes(4) = bitand(bitshift(word, sh(4)), 255);
+end
diff --git a/tune/eq/eq_iir_blob_quant.m b/tune/eq/eq_iir_blob_quant.m
new file mode 100644
index 0000000..0c19fb3
--- /dev/null
+++ b/tune/eq/eq_iir_blob_quant.m
@@ -0,0 +1,144 @@
+function iir_resp = eq_iir_blob_quant(eq_z, eq_p, eq_k)
+
+%% Convert IIR coefficients to 2nd order sections and quantize
+%
+%  iir_resp = eq_iir_blob_quant(z, p, k)
+%
+%  z - zeros
+%  p - poles
+%  k - gain
+%
+%  iir_resp - vector to setup an IIR equalizer with number of sections, shifts,
+%  and quantized coefficients
+%
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Settings
+bits_iir = 32; % Q2.30
+qf_iir = 30;
+bits_gain = 16; % Q2.14
+qf_gain = 14;
+scale_max = -6; % dB, scale biquads peak gain to this
+plot_pz = 0;
+plot_fr = 0;
+
+%% Convert IIR to 2nd order sections
+%  This a simple implementation of zp2sos() function. It is not used here due
+%  to utilization of rather strong scaling and resulting low SNR with the
+%  available word length in EQ in SOF. This poles and zeros allocation to
+%  biquads is base only in ascending sort of angular frequency.
+sz = length(eq_z);
+sp = length(eq_p);
+sk = length(eq_k);
+nb = max(sz, sp)/2;
+az = angle(eq_z);
+ap = angle(eq_p);
+[~, iz] = sort(abs(az));
+[~, ip] = sort(abs(ap));
+eq_z = eq_z(iz);
+eq_p = eq_p(ip);
+sos = zeros(nb, 6);
+for i = 1:nb
+        j = 2*(i-1)+1;
+        if i == 1
+                [b, a] = zp2tf(eq_z(j:j+1), eq_p(j:j+1), eq_k);
+        else
+                [b, a] = zp2tf(eq_z(j:j+1), eq_p(j:j+1), 1);
+        end
+        sos(i,1:3) = b;
+        sos(i,4:6) = a;
+end
+gain = 1;
+
+%% Convert 2nd order sections to SOF parameters format and scale the biquads
+%  with criteria below (Gain max -6 dB at any frequency). Then calculate 
+%  scaling shifts and finally gain multiplier for output.
+sz = size(sos);
+nbr_sections = sz(1);
+n_section_header = 2;
+n_section = 7;
+iir_resp = int32(zeros(1,n_section_header+nbr_sections*n_section));
+iir_resp(1) = nbr_sections;
+iir_resp(2) = nbr_sections; % Note: All sections in series
+
+scale_max_lin = 10^(scale_max/20);
+for n=1:nbr_sections
+        b = sos(n,1:3);
+        a = sos(n,4:6);
+        if plot_pz
+                figure
+                zplane(b,a);
+                tstr = sprintf('SOS %d poles and zeros', n);
+                title(tstr);
+        end
+
+        np = 1024;
+        [h, w] = freqz(b, a, np);
+        hm = max(abs(h));
+        scale = scale_max_lin/hm;
+        gain_remain = 1/scale;
+        gain = gain*gain_remain;
+        b = b * scale;
+        ma = max(abs(a));
+        mb = max(abs(b));
+        if plot_fr
+                figure
+                [h, w] = freqz(b, a, np);
+                plot(w, 20*log10(abs(h))); grid on;
+                xlabel('Frequency (w)');
+                ylabel('Magnitude (dB)');
+                tstr = sprintf('SOS %d frequency response', n);
+                title(tstr);
+        end
+
+        %% Apply remaining gain at last section output
+        if n == nbr_sections
+                section_shift = -fix(log(gain)/log(2));
+                section_gain= gain/2^(-section_shift);
+        else
+                section_shift = 0;
+                section_gain = 1;
+        end
+
+        %% Note: Invert sign of a!
+        %% Note:  a(1) is omitted, it's always 1
+        m = n_section_header+(n-1)*n_section+1;
+        iir_resp(m:m+1) = eq_coef_quant(-a(3:-1:2), bits_iir, qf_iir);
+        iir_resp(m+2:m+4) =  eq_coef_quant( b(3:-1:1), bits_iir, qf_iir);
+        iir_resp(m+5) = section_shift;
+        iir_resp(m+6) = eq_coef_quant( section_gain, bits_gain, qf_gain);
+
+	%fprintf('sec=%d, shift=%d, gain=%f\n', n, section_shift, section_gain);
+
+end
+
+end
diff --git a/tune/eq/eq_norm.m b/tune/eq/eq_norm.m
new file mode 100644
index 0000000..47b40d9
--- /dev/null
+++ b/tune/eq/eq_norm.m
@@ -0,0 +1,114 @@
+function eq = eq_norm(eq)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Normalize loudness of EQ by computing weighted average of linear
+%  response. Find scale need to make the average one.
+w_lin = level_norm_fweight(eq.f);
+m_lin_fir = 10.^(eq.fir_eq_db/20);
+m_lin_iir = 10.^(eq.iir_eq_db/20);
+i1k = find(eq.f > 1e3, 1, 'first') - 1;
+m_max_fir = max(eq.fir_eq_db);
+m_max_iir = max(eq.iir_eq_db);
+sens_fir = sum(m_lin_fir.*w_lin)/sum(w_lin);
+sens_iir = sum(m_lin_iir.*w_lin)/sum(w_lin);
+g_offs = 10^(eq.norm_offs_db/20);
+
+%% Determine scaling gain
+switch lower(eq.norm_type)
+        case 'loudness'
+                g_fir = 1/sens_fir;
+                g_iir = 1/sens_iir;
+        case '1k'
+                g_fir = 1/m_lin_fir(i1k);
+                g_iir = 1/m_lin_iir(i1k);
+
+        case 'peak'
+                g_fir = 10^(-m_max_fir/20);
+                g_iir = 10^(-m_max_iir/20);
+        otherwise
+                error('Requested normalization is not supported');
+end
+
+%% Adjust FIR and IIR gains if enabled
+if eq.enable_fir && eq.enable_iir
+        eq.b_fir = eq.b_fir * g_fir * g_offs;
+        eq.p_k = eq.p_k * g_iir * g_offs;
+end
+if eq.enable_fir && eq.enable_iir == 0
+        eq.b_fir = eq.b_fir * g_fir * g_offs;
+end
+if eq.enable_fir == 0 && eq.enable_iir
+        eq.p_k = eq.p_k * g_iir * g_offs;
+end
+
+%% Re-compute response after adjusting gain
+eq = eq_compute_tot_response(eq);
+
+end
+
+function m_lin = level_norm_fweight(f)
+
+%% w_lin = level_norm_fweight(f)
+%
+% Provides frequency weight that is useful in normalization of
+% loudness of effect like equalizers. The weight consists of pink noise
+% like spectral shape that attenuates higher frequencies 3 dB per
+% octave. The low frequencies are shaped by 2nd order high-pass
+% response at 20 Hz and higher frequencies by 3rd order low-pass at 20
+% kHz.
+%
+% Note: This weight may have similarity with a standard defined test signal
+% characteristic for evaluating music player output levels but this is not
+% an implementation of it. This weight may help in avoiding a designed EQ to
+% exceed safe playback levels in othervise compliant device.
+%
+% Input f - frequencies vector in Hz
+%
+% Output w_lin  - weight curve, aligned to peak of 1.0 in the requested f
+%
+
+[z_hp, p_hp] = butter(2, 22.4,'high','s');
+[z_lp, p_lp] = butter(3, 22.4e3,'s');
+z_bp = conv(z_hp, z_lp);
+p_bp = conv(p_hp, p_lp);
+h = freqs(z_bp, p_bp, f);
+m0 = 20*log10(abs(h));
+noct = log(max(f)/min(f))/log(2);
+att = 3*noct;
+nf = length(f);
+w = zeros(1,nf);
+w = w - linspace(0,att,nf);
+m = m0 + w;
+m = m-max(m);
+m_lin = 10.^(m/20);
+
+end
diff --git a/tune/eq/eq_plot.m b/tune/eq/eq_plot.m
new file mode 100644
index 0000000..95968c4
--- /dev/null
+++ b/tune/eq/eq_plot.m
@@ -0,0 +1,178 @@
+function eq_plot(eq, fn)
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 2
+        fn = 1;
+end
+
+%% Raw measured response
+if length(eq.raw_m_db) > 2
+        % Raw without EQ
+        fh=figure(fn); fn = fn+1;
+	f1 = min(eq.raw_f);
+	f2 = max(eq.raw_f);
+	i1 = find(eq.f > f1, 1, 'first') - 1;
+	i2 = find(eq.f > f2, 1, 'first') - 1;
+	idx = i1:i2;
+        semilogx(eq.f(idx), eq.m_db(idx), eq.f(idx), eq.m_db_s(idx));
+        grid on;
+        ax=axis; axis([eq.p_fmin eq.p_fmax min(max(ax(3:4), -40), 20)]);
+        legend('Raw','Smoothed');
+        xlabel('Frequency (Hz)');
+        ylabel('Magnitude (dB)');
+        tstr = sprintf('Imported frequency response: %s', eq.name);
+        title(tstr);
+
+        % Simulated with EQ
+        fh=figure(fn); fn = fn+1;
+        semilogx(eq.f(idx), eq.m_eqd(idx), eq.f(idx), eq.m_eqd_s(idx));
+        grid on;
+        ax=axis; axis([eq.p_fmin eq.p_fmax min(max(ax(3:4), -40), 20)]);
+        legend('Raw','Smoothed');
+        xlabel('Frequency (Hz)');
+        ylabel('Magnitude (dB)');
+        tstr = sprintf('Simulated frequency response: %s', eq.name);
+        title(tstr);
+end
+
+%% Filter responses
+fh=figure(fn); fn = fn+1;
+i1k = find(eq.f > 1e3, 1, 'first') - 1;
+offs_tot = -eq.tot_eq_db(i1k);
+offs_fir = -eq.fir_eq_db(i1k);
+offs_iir = -eq.iir_eq_db(i1k);
+if eq.enable_fir && eq.enable_iir
+        semilogx(eq.f, eq.err_db_s, eq.f, eq.tot_eq_db + offs_tot, ...
+                eq.f, eq.iir_eq_db + offs_iir, '--',...
+                eq.f, eq.fir_eq_db + offs_fir, '--');
+        legend('Target', 'Combined', 'IIR', 'FIR', 'Location', 'NorthWest');
+end
+if eq.enable_fir && eq.enable_iir == 0
+        semilogx(eq.f, eq.err_db_s, eq.f, eq.fir_eq_db + offs_fir);
+        legend('Target', 'FIR', 'Location', 'NorthWest');
+end
+if eq.enable_fir == 0 && eq.enable_iir
+        semilogx(eq.f, eq.err_db_s, eq.f, eq.iir_eq_db + offs_iir);
+        legend('Target', 'IIR', 'Location', 'NorthWest');
+end
+grid on;
+ax=axis; axis([eq.p_fmin eq.p_fmax min(max(ax(3:4), -40), 40)]);
+xlabel('Frequency (Hz)');
+ylabel('Magnitude (dB)');
+tstr = sprintf('Filter target vs. achieved response: %s', eq.name);
+title(tstr);
+
+%% FIR filter
+if length(eq.b_fir) > 1
+        % Response
+	fh=figure(fn); fn = fn+1;
+	semilogx(eq.f, eq.fir_eq_db);
+	grid on;
+	xlabel('Frequency (Hz)');
+	ylabel('Magnitude (dB)');
+        ax = axis; axis([eq.p_fmin eq.p_fmax max(ax(3:4), -40)]);
+        tstr = sprintf('FIR filter normalized response: %s', eq.name);
+        title(tstr);
+
+        % Impulse response / coefficients
+        fh=figure(fn); fn = fn+1;
+	stem(eq.b_fir);
+	grid on;
+	xlabel('Coefficient #');
+	ylabel('Coefficient value');
+        tstr = sprintf('FIR filter impulse response: %s', eq.name);
+        title(tstr);
+
+end
+
+%% IIR filter
+if length(eq.p_z) > 1 || length(eq.p_p) > 1
+        % Response
+	fh=figure(fn); fn = fn+1;
+	semilogx(eq.f, eq.iir_eq_db);
+	grid on;
+	xlabel('Frequency (Hz)');
+	ylabel('Magnitude (dB)');
+        ax = axis; axis([eq.p_fmin eq.p_fmax max(ax(3:4), -40)]);
+        tstr = sprintf('IIR filter normalized response: %s', eq.name);
+        title(tstr);
+
+        % Polar
+        fh=figure(fn); fn = fn+1;
+        zplane(eq.p_z, eq.p_p);
+        grid on;
+        tstr = sprintf('IIR zeros and poles: %s', eq.name);
+        title(tstr);
+
+        % Impulse
+        ti = 50e-3;
+        x = zeros(1, ti * round(eq.fs));
+        x(1) = 1;
+        sos = zp2sos(eq.p_z, eq.p_p, eq.p_k);
+        y = sosfilt(sos, x);
+	fh=figure(fn); fn = fn+1;
+        t = (0:(length(x)-1)) / eq.fs;
+        plot(t, y);
+        grid on;
+        xlabel('Time (s)');
+        ylabel('Sample value');
+        tstr = sprintf('IIR filter impulse response: %s', eq.name);
+        title(tstr);
+end
+
+%% Group delay
+if ~exist('OCTAVE_VERSION', 'builtin')
+	% Skip plot if running in Octave due to incorrect result
+	fh=figure(fn); fn = fn+1;
+	if eq.enable_fir && eq.enable_iir
+		semilogx(eq.f, eq.tot_eq_gd * 1e3, ...
+			 eq.f, eq.fir_eq_gd * 1e3, '--', ...
+			 eq.f, eq.iir_eq_gd * 1e3, '--');
+		legend('Combined','FIR','IIR');
+	end
+	if eq.enable_fir && eq.enable_iir == 0
+		semilogx(eq.f, eq.fir_eq_gd * 1e3);
+		legend('FIR');
+	end
+	if eq.enable_fir == 0 && eq.enable_iir
+		semilogx(eq.f, eq.iir_eq_gd * 1e3);
+		legend('IIR');
+	end
+	grid on;
+	xlabel('Frequency (Hz)');
+	ylabel('Group delay (ms)');
+	ax = axis; axis([eq.p_fmin eq.p_fmax ax(3:4)]);
+	tstr = sprintf('Filter group delay: %s', eq.name);
+	title(tstr);
+end
+
+end
diff --git a/tune/eq/eq_tplg_write.m b/tune/eq/eq_tplg_write.m
new file mode 100644
index 0000000..cda5e01
--- /dev/null
+++ b/tune/eq/eq_tplg_write.m
@@ -0,0 +1,63 @@
+function eq_tplg_write(fn, blob8, eqtype)
+
+%%
+% Copyright (c) 2018, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Pad blob length to multiple of four bytes
+n_orig = length(blob8);
+n_new = ceil(n_orig/4)*4;
+blob8_new = zeros(1, n_new);
+blob8_new(1:n_orig) = blob8;
+
+%% Write blob
+fh = fopen(fn, 'w');
+nl = 8;
+fprintf(fh, '`SectionData."''N_EQ_%s($1)`_data_bytes" {''\n', ...
+       upper(eqtype));
+fprintf(fh, '`       bytes "');
+for i = 1:nl:n_new
+	if i > 1
+		fprintf(fh, '`       ');
+	end
+	for j = 0:nl-1
+		n = i + j;
+		if n < n_new
+			fprintf(fh, '0x%02x,', blob8_new(n));
+		end
+		if n == n_new
+			fprintf(fh, '0x%02x"', blob8_new(n));
+		end
+	end
+	fprintf(fh, '''\n');
+end
+fprintf(fh, '`}''\n');
+fclose(fh);
+
+end
diff --git a/tune/eq/example_fir_eq.m b/tune/eq/example_fir_eq.m
new file mode 100644
index 0000000..2186ea6
--- /dev/null
+++ b/tune/eq/example_fir_eq.m
@@ -0,0 +1,115 @@
+%% Design demo EQs and bundle them to parameter block
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+function example_fir_eq()
+
+ascii_blob_fn = 'example_fir_eq.txt';
+binary_blob_fn = 'example_fir_eq.blob';
+tplg_blob_fn = 'example_fir_eq.m4';
+endian = 'little';
+fs = 48e3;
+
+%% Design FIR loudness equalizer
+eq_loud = loudness_fir_eq(fs);
+
+%% Define a passthru EQ with one tap
+b_pass = 1;
+
+%% Quantize filter coefficients for both equalizers
+bq_pass = eq_fir_blob_quant(b_pass);
+bq_loud = eq_fir_blob_quant(eq_loud.b_fir);
+
+%% Build blob
+platform_max_channels = 4;   % Setup max 4 channels EQ
+assign_response = [1 1 1 1]; % Switch to response #1
+num_responses = 2;           % Two responses pass, loud
+bm = eq_fir_blob_merge(platform_max_channels, ...
+		       num_responses, ...
+		       assign_response, ...
+		       [ bq_pass bq_loud ]);
+
+%% Pack and write file
+bp = eq_fir_blob_pack(bm, endian);
+eq_alsactl_write(ascii_blob_fn, bp);
+eq_blob_write(binary_blob_fn, bp);
+eq_tplg_write(tplg_blob_fn, bp, 'FIR');
+
+end
+
+function eq = loudness_fir_eq(fs)
+
+%% Derived from Fletcher-Munson curves for 80 and 60 phon
+f = [ 20,21,22,24,25,27,28,30,32,34,36,38,40,43,45,48,51,54,57,60,64, ...
+        68,72,76,81,85,90,96,102,108,114,121,128,136,144,153,162,171, ...
+        182,192,204,216,229,243,257,273,289,306,324,344,364,386,409, ...
+        434,460,487,516,547,580,614,651,690,731,775,821,870,922,977, ...
+        1036,1098,1163,1233,1307,1385,1467,1555,1648,1747,1851,1962, ...
+        2079,2203,2335,2474,2622,2779,2945,3121,3308,3505,3715,3937, ...
+        4172,4421,4686,4966,5263,5577,5910,6264,6638,7035,7455,7901, ...
+        8373,8873,9404,9966,10561,11193,11861,12570,13322,14118,14962, ...
+        15856,16803,17808,18872,20000];
+
+m = [ 0.00,-0.13,-0.27,-0.39,-0.52,-0.64,-0.77,-0.89,-1.02,-1.16,  ...
+        -1.31,-1.46,-1.61,-1.76,-1.91,-2.07,-2.24,-2.43,-2.64,-2.85, ...
+        -3.04,-3.21,-3.35,-3.48,-3.62,-3.78,-3.96,-4.16,-4.35,-4.54, ...
+        -4.72,-4.90,-5.08,-5.26,-5.45,-5.64,-5.83,-6.02,-6.19,-6.37, ...
+        -6.57,-6.77,-6.98,-7.19,-7.40,-7.58,-7.76,-7.92,-8.08,-8.25, ...
+        -8.43,-8.60,-8.76,-8.92,-9.08,-9.23,-9.38,-9.54,-9.69,-9.84, ...
+        -9.97,-10.09,-10.18,-10.26,-10.33,-10.38,-10.43,-10.48,-10.54, ...
+        -10.61,-10.70,-10.78,-10.85,-10.91,-10.95,-10.98,-11.02, ...
+        -11.05,-11.07,-11.10,-11.11,-11.11,-11.10,-11.10,-11.11, ...
+        -11.14,-11.17,-11.20,-11.21,-11.22,-11.21,-11.20,-11.20, ...
+        -11.21,-11.21,-11.20,-11.17,-11.11,-11.02,-10.91,-10.78, ...
+        -10.63,-10.46,-10.25,-10.00,-9.72,-9.39,-9.02,-8.62,-8.19, ...
+        -7.73,-7.25,-6.75,-6.25,-5.75,-5.28,-4.87,-4.54,-4.33,-4.30];
+
+%% Design EQ
+eq = eq_defaults();
+eq.fs = fs;
+eq.target_f = f;            % Set EQ frequency response target: frequency vector
+eq.target_m_db = m;         % Set EQ frequency response target: magnitude
+eq.norm_type = 'loudness';  % Can be loudness/peak/1k to select normalize criteria
+eq.norm_offs_db = 0;        % E.g. -1 would leave 1 dB headroom if used with peak
+
+eq.enable_fir = 1;          % By default both FIR and IIR disabled, enable one
+eq.fir_beta = 3.5;          % Use with care, low value can corrupt
+eq.fir_length = 136;        % Gives just < 316 bytes
+eq.fir_autoband = 0;        % Select manually frequency limits
+eq.fmin_fir = 100;          % Equalization starts from 100 Hz
+eq.fmax_fir = 20e3;         % Equalization ends at 20 kHz
+eq.fir_minph = 1;           % If no linear phase required, check result carefully if 1
+eq = eq_compute(eq);
+
+%% Plot
+eq_plot(eq);
+
+end
diff --git a/tune/eq/example_iir_eq.m b/tune/eq/example_iir_eq.m
new file mode 100644
index 0000000..0345bcf
--- /dev/null
+++ b/tune/eq/example_iir_eq.m
@@ -0,0 +1,128 @@
+%% Design effect EQs and bundle them to parameter block
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+function example_iir_eq()
+
+blob_fn = 'example_iir_eq.blob';
+alsa_fn = 'example_iir_eq.txt';
+tplg_fn = 'example_iir_eq.m4';
+endian = 'little';
+fs = 48e3;
+
+%% Design IIR loudness equalizer
+eq_loud = loudness_iir_eq(fs);
+
+%% Define a passthru IIR EQ equalizer
+[z_pass, p_pass, k_pass] = tf2zp([1 0 0],[1 0 0]);
+
+%% Quantize and pack filter coefficients plus shifts etc.
+bq_pass = eq_iir_blob_quant(z_pass, p_pass, k_pass);
+bq_loud = eq_iir_blob_quant(eq_loud.p_z, eq_loud.p_p, eq_loud.p_k);
+
+%% Build blob
+platform_max_channels = 4;   % Setup max 4 channels EQ
+assign_response = [1 1 1 1]; % Switch to response #1
+num_responses = 2;           % Two responses: pass, loud
+bm = eq_iir_blob_merge(platform_max_channels, ...
+		       num_responses, ...
+		       assign_response, ...
+		       [bq_pass bq_loud]);
+
+%% Pack and write file
+bp = eq_iir_blob_pack(bm);
+eq_blob_write(blob_fn, bp);
+eq_alsactl_write(alsa_fn, bp);
+eq_tplg_write(tplg_fn, bp, 'IIR');
+
+end
+
+%%
+
+function eq = loudness_iir_eq(fs)
+
+%% Derived from Fletcher-Munson curves for 80 and 60 phon
+f = [ 20,21,22,24,25,27,28,30,32,34,36,38,40,43,45,48,51,54,57,60,64, ...
+        68,72,76,81,85,90,96,102,108,114,121,128,136,144,153,162,171, ...
+        182,192,204,216,229,243,257,273,289,306,324,344,364,386,409, ...
+        434,460,487,516,547,580,614,651,690,731,775,821,870,922,977, ...
+        1036,1098,1163,1233,1307,1385,1467,1555,1648,1747,1851,1962, ...
+        2079,2203,2335,2474,2622,2779,2945,3121,3308,3505,3715,3937, ...
+        4172,4421,4686,4966,5263,5577,5910,6264,6638,7035,7455,7901, ...
+        8373,8873,9404,9966,10561,11193,11861,12570,13322,14118,14962, ...
+        15856,16803,17808,18872,20000];
+
+m = [ 0.00,-0.13,-0.27,-0.39,-0.52,-0.64,-0.77,-0.89,-1.02,-1.16,  ...
+        -1.31,-1.46,-1.61,-1.76,-1.91,-2.07,-2.24,-2.43,-2.64,-2.85, ...
+        -3.04,-3.21,-3.35,-3.48,-3.62,-3.78,-3.96,-4.16,-4.35,-4.54, ...
+        -4.72,-4.90,-5.08,-5.26,-5.45,-5.64,-5.83,-6.02,-6.19,-6.37, ...
+        -6.57,-6.77,-6.98,-7.19,-7.40,-7.58,-7.76,-7.92,-8.08,-8.25, ...
+        -8.43,-8.60,-8.76,-8.92,-9.08,-9.23,-9.38,-9.54,-9.69,-9.84, ...
+        -9.97,-10.09,-10.18,-10.26,-10.33,-10.38,-10.43,-10.48,-10.54, ...
+        -10.61,-10.70,-10.78,-10.85,-10.91,-10.95,-10.98,-11.02, ...
+        -11.05,-11.07,-11.10,-11.11,-11.11,-11.10,-11.10,-11.11, ...
+        -11.14,-11.17,-11.20,-11.21,-11.22,-11.21,-11.20,-11.20, ...
+        -11.21,-11.21,-11.20,-11.17,-11.11,-11.02,-10.91,-10.78, ...
+        -10.63,-10.46,-10.25,-10.00,-9.72,-9.39,-9.02,-8.62,-8.19, ...
+        -7.73,-7.25,-6.75,-6.25,-5.75,-5.28,-4.87,-4.54,-4.33,-4.30];
+
+%% Get defaults for equalizer design
+eq = eq_defaults();
+eq.fs = fs;
+eq.target_f = f;
+eq.target_m_db = m;
+eq.enable_iir = 1;
+eq.norm_type = 'loudness';
+eq.norm_offs_db = 0;
+
+%% Manually setup low-shelf and high shelf parametric equalizers
+%
+% Parametric EQs are PEQ_HP1, PEQ_HP2, PEQ_LP1, PEQ_LP2, PEQ_LS1,
+% PEQ_LS2, PEQ_HS1, PEQ_HS2 = 8, PEQ_PN2, PEQ_LP4, and  PEQ_HP4.
+%
+% Parametric EQs take as second argument the cutoff frequency in Hz
+% and as second argument a dB value (or NaN when not applicable) . The
+% Third argument is a Q-value (or NaN when not applicable).
+eq.peq = [ ...
+                 eq.PEQ_LS1 40 +2 NaN ; ...
+                 eq.PEQ_LS1 80 +3 NaN ; ...
+                 eq.PEQ_LS1 200 +3 NaN ; ...
+                 eq.PEQ_LS1 400 +3 NaN ; ...
+                 eq.PEQ_HS2 13000 +7 NaN ; ...
+         ];
+
+%% Design EQ
+eq = eq_compute(eq);
+
+%% Plot
+eq_plot(eq);
+
+end
diff --git a/tune/eq/example_spk_eq.m b/tune/eq/example_spk_eq.m
new file mode 100644
index 0000000..d829e02
--- /dev/null
+++ b/tune/eq/example_spk_eq.m
@@ -0,0 +1,155 @@
+function example_spk_eq()
+
+%% Design an example speaker equalizer with the provided sample data
+%  This equalizer by default uses a FIR and IIR components those should be
+%  both in the speaker pipeline.
+%
+%  Note that IIR should be first since the included band-pass response provides
+%  signal headroom.
+
+%%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+%% Get defaults for equalizer design
+eq = eq_defaults();
+
+%% Settings for this EQ
+eq.fs = 48e3;               % Default sample rate in SOF
+eq.enable_fir = 1;          % Try enabling and disabling FIR part
+eq.enable_iir = 1;          % Try enabling and disabling IIR part
+eq.norm_type = 'peak';      % Scale filters to have peak at 0 dB
+eq.norm_offs_db = 0;        % Can be used to control gain
+eq.p_fmin = 100;            % With this data start plots from 100 Hz
+eq.p_fmax = 20e3;           % and end to 20 kHz.
+
+%% Get acousticial frequency response measurement data. This is
+%  a quite typical response for a miniature speaker. Alternatively
+%  the response could be read from spreadsheet column format that is
+%  commonly supported by audio measurement equipment. Then extract
+%  the frequency and magnitude columns. E.g.
+%
+%      data = xlsread('spkr.xlsx', 1, 'A5:B78');
+%      eq.raw_f = data(:,1);
+%      eq.raw_m_db = data(:,2);
+
+eq.raw_f = [ ...
+         298.533,  316.232,  334.971,  354.813,  375.838,  398.106,  ...
+         421.699,  446.685,  473.153,  501.186,  530.887,  562.342,  ...
+         595.663,  630.958,  668.345,  707.946,  749.895,  794.329,  ...
+         841.397,  891.252,  944.062,     1000,  1059.26,  1122.02,  ...
+          1188.5,  1258.93,  1333.52,  1412.54,  1496.24,   1584.9,  ...
+         1678.81,  1778.28,  1883.65,  1995.27,  2113.49,  2238.72,  ...
+         2371.38,  2511.89,  2660.73,  2818.39,  2985.39,  3162.28,  ...
+         3349.66,  3548.14,  3758.38,  3981.08,  4216.97,  4466.84,  ...
+         4731.52,  5011.88,  5308.85,  5623.42,  5956.63,  6309.58,  ...
+         6683.45,  7079.47,  7498.95,   7943.3,  8413.97,  8912.52,  ...
+         9440.62,    10000,  10592.6,  11220.2,    11885,  12589.3,  ...
+         13335.2,  14125.4,  14962.4,    15849,  16788.1,  17782.8,  ...
+         18836.5,  19952.7 ...
+];
+
+eq.raw_m_db = [ ...
+         58.1704,   60.074,  60.4541,  61.3079,  62.8198,  64.3749,  ...
+         65.1556,   66.512,  67.5916,  68.6344,  69.9276,  70.7658,  ...
+         71.1125,  72.0627,  73.5348,  75.4887,  77.3088,  79.1541,  ...
+         80.9627,  82.0607,   81.943,  81.2228,  81.9497,  83.1848,  ...
+         84.3375,  85.4993,  86.4642,  87.1179,  87.4424,    87.53,  ...
+         85.7425,  85.0095,  82.9405,  82.9242,  82.7327,  83.6423,  ...
+         83.2839,  82.4201,  84.1403,  84.6485,  83.9274,  83.3366,  ...
+         83.3005,  84.2598,  85.1544,   86.015,  86.6519,  87.2118,  ...
+         87.5498,  88.1742,  88.5215,  88.3801,  89.8762,  91.4418,  ...
+         93.1845,  94.3355,  95.0918,  95.0258,  94.0337,  91.1068,  ...
+         88.7303,  87.4853,  86.2916,   83.037,  79.8056,  78.2022,  ...
+         76.0341,  74.5674,  69.2288,  56.1308,   68.697,   69.687,  ...
+         68.0005,   64.698 ...
+];
+
+%% With parametric IIR EQ try to place peaking EQ at
+%  resonant frequencies 1.4 kHz and 7.5 kHz. The gain
+%  and Q values were experimented manually. Additionally
+%  The lowest and highest frequeciens below and above speaker
+%  capability are attenuated with high-pass and low-pass
+%  filtering.
+if eq.enable_iir;
+	eq.peq = [ ...
+			 eq.PEQ_HP2   100 NaN NaN; ...
+			 eq.PEQ_PN2  1480  -7 2.0; ...
+			 eq.PEQ_PN2  7600 -11 1.3; ...
+			 eq.PEQ_LP2 14500 NaN NaN; ...
+		 ];
+end
+
+%% With FIR EQ try to flatten frequency response within
+%  1 - 13 kHz frequency band.
+if eq.enable_fir
+        eq.fir_minph = 1;
+	eq.fir_beta = 4;
+	eq.fir_length = 63;
+	eq.fir_autoband = 0;
+	eq.fmin_fir = 900;
+	eq.fmax_fir = 10700;
+end
+
+%% Design EQ
+eq = eq_compute(eq);
+
+%% Plot
+eq_plot(eq, 1);
+
+%% Export FIR part
+platform_max_channels = 2;  % Identical two speakers
+assign_response = [0 0];    % Switch to response #0
+num_responses = 1;          % Single response
+if eq.enable_fir
+        bq_fir = eq_fir_blob_quant(eq.b_fir);
+        bm_fir = eq_fir_blob_merge(platform_max_channels, ...
+                num_responses, ...
+                assign_response, ...
+                [ bq_fir ]);
+        bp_fir = eq_fir_blob_pack(bm_fir);
+        eq_alsactl_write('example_spk_eq_fir.txt', bp_fir);
+        eq_blob_write('example_spk_eq_fir.blob', bp_fir);
+	eq_tplg_write('example_spk_eq_fir.m4', bp_fir, 'FIR');
+end
+
+%% Export IIR part
+if eq.enable_iir
+        bq_iir = eq_iir_blob_quant(eq.p_z, eq.p_p, eq.p_k);
+        bm_iir = eq_iir_blob_merge(platform_max_channels, ...
+                num_responses, ...
+                assign_response, ...
+                [ bq_iir ]);
+        bp_iir = eq_iir_blob_pack(bm_iir);
+        eq_alsactl_write('example_spk_eq_iir.txt', bp_iir);
+        eq_blob_write('example_spk_eq_iir.blob', bp_iir);
+	eq_tplg_write('example_spk_eq_iir.m4', bp_iir, 'IIR');
+end
+
+end
diff --git a/tune/src/README b/tune/src/README
new file mode 100644
index 0000000..e135f9a
--- /dev/null
+++ b/tune/src/README
@@ -0,0 +1,36 @@
+Sample rate converter (SRC) Setup Tools
+=======================================
+
+This is a tool to set up SRC conversions sample rates list, define
+quality related parameters, and test the C implementation for a number
+of objective audio quality parameters.
+
+The tools need GNU Octave version 4.0.0 or later with octave-signal
+package.
+
+src_std_int32.m
+---------------
+
+This script creates the default coefficient set and contains nothing
+else but call for src_generate.
+
+src_tiny_int16.m
+----------------
+
+This script creates the tiny coefficient set. The script contains an
+example how to customize the input/output rates matrix and in a simple
+way the scale conversions quality. More controlled quality adjust can
+be done by editing file src_param.m directly. Note that int16
+presentation for SRC coefficients will degrade even the default
+quality.
+
+src_generate.m
+--------------
+
+Creates the header files to include to C into directory "include". A
+report of create modes is written to directory "reports". The
+coefficients need to be copied to directory
+sof.git/src/include/sof/audio/coefficients/src.
+
+The default quality of SRC is defined in module src_param.m. The
+quality impacts the complexity and coefficents tables size of SRC.
diff --git a/tune/src/src_export_coef.m b/tune/src/src_export_coef.m
new file mode 100644
index 0000000..f6fdbb4
--- /dev/null
+++ b/tune/src/src_export_coef.m
@@ -0,0 +1,212 @@
+function success=src_export_coef(src, ctype, vtype, hdir, profile)
+
+% src_export_coef - Export FIR coefficients
+%
+% success=src_export_coef(src, ctype, hdir, profile)
+%
+% src     - src definition struct
+% ctype   - 'float','int32', or 'int24'
+% vtype   - 'float','int32_t'
+% hdir    - directory for header files
+% profile - string to append to filename
+%
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 5
+        profile = '';
+end
+
+if src.L == src.M
+        success = 0;
+else
+        pbi =  round(src.c_pb*1e4);
+        sbi =  round(src.c_sb*1e4);
+        if isempty(profile)
+                hfn = sprintf('%s/src_%s_%d_%d_%d_%d.h', ...
+                        hdir, ctype, src.L, src.M, pbi, sbi);
+        else
+                hfn = sprintf('%s/src_%s_%s_%d_%d_%d_%d.h', ...
+                        hdir, profile, ctype, src.L, src.M, pbi, sbi);
+        end
+        vfn = sprintf('src_%s_%d_%d_%d_%d_fir', ctype, src.L, src.M, pbi, sbi);
+        sfn = sprintf('src_%s_%d_%d_%d_%d', ctype, src.L, src.M, pbi, sbi);
+
+        fprintf('Exporting %s ...\n', hfn);
+        fh = fopen(hfn, 'w');
+
+        switch ctype
+                case 'float'
+                        fprintf(fh, 'const %s %s[%d] = {\n', ...
+                                vtype, vfn, src.filter_length);
+                        fprintf(fh,'\t%16.9e', src.coefs(1));
+                        for n=2:src.filter_length
+                                fprintf(fh, ',\n');
+                                fprintf(fh,'\t%16.9e', src.coefs(n));
+                        end
+                        fprintf(fh,'\n\n};');
+                case 'int32'
+			print_int_coef(src, fh, vtype, vfn, 32);
+                case 'int24'
+			print_int_coef(src, fh, vtype, vfn, 24);
+                case 'int16'
+			print_int_coef(src, fh, vtype, vfn, 16);
+                otherwise
+                        error('Unknown type %s !!!', ctype);
+        end
+
+        fprintf(fh, '\n');
+        switch ctype
+                case 'float'
+                        fprintf(fh, 'struct src_stage %s = {\n', sfn);
+			fprintf(fh, '\t%d, %d, %d, %d, %d, %d, %d, %d, %f,\n\t%s};\n', ...
+                                src.idm, src.odm, src.num_of_subfilters, ...
+                                src.subfilter_length, src.filter_length, ...
+                                src.blk_in, src.blk_out, src.halfband, ...
+                                src.gain, vfn);
+                case { 'int16' 'int24' 'int32' }
+                        fprintf(fh, 'struct src_stage %s = {\n', sfn);
+			fprintf(fh, '\t%d, %d, %d, %d, %d, %d, %d, %d, %d,\n\t%s};\n', ...
+                                src.idm, src.odm, src.num_of_subfilters, ...
+                                src.subfilter_length, src.filter_length, ...
+                                src.blk_in, src.blk_out, src.halfband, ...
+                                src.shift, vfn);
+                otherwise
+                        error('Unknown type %s !!!', ctype);
+        end
+        %fprintf(fh, '\n');
+        fclose(fh);
+        success = 1;
+end
+
+end
+
+function print_int_coef(src, fh, vtype, vfn, nbits)
+        fprintf(fh, 'const %s %s[%d] = {\n', ...
+                vtype, vfn, src.filter_length);
+
+        cint = coef_quant(src, nbits);
+        fprintf(fh,'\t%d', cint(1));
+        for n=2:src.filter_length
+                fprintf(fh, ',\n');
+                fprintf(fh,'\t%d', cint(n));
+        end
+        fprintf(fh,'\n\n};');
+end
+
+function cint = coef_quant(src, nbits)
+
+	sref = 2^(nbits-1);
+	pmax = sref-1;
+	nmin = -sref;
+
+        if nbits > 16
+                %% Round() is OK
+                cint0 = round(sref*src.coefs);
+        else
+                %% Prepare to optimize coefficient quantization
+                fs = max(src.fs1, src.fs2);
+                f = linspace(0, fs/2, 1000);
+
+                %% Test sensitivity for stopband and find the most sensitive
+                %  coefficients
+                sbf = linspace(src.f_sb,fs/2, 500);
+                n = src.filter_length;
+                psens = zeros(1,n);
+                bq0 = round(sref*src.coefs);
+                h = freqz(bq0/sref/src.L, 1, sbf, fs);
+                sb1 = 20*log10(sqrt(sum(h.*conj(h))));
+                for i=1:n
+                        bq = src.coefs;
+                        bq(i) = round(sref*bq(i))/sref;
+                        %tbq = bq; %tbq(i) = bq(i)+1;
+                        h = freqz(bq, 1, sbf, fs);
+                        psens(i) = sum(h.*conj(h));
+                end
+                [spsens, pidx] = sort(psens, 'descend');
+
+                %% Test quantization in the found order
+                %  The impact to passband is minimal so it's not tested
+                bi = round(sref*src.coefs);
+                bi0 = bi;
+                dl = -1:1;
+                nd = length(dl);
+                msb = zeros(1,nd);
+                for i=pidx
+                        bit = bi;
+                        for j=1:nd
+                                bit(i) = bi(i) + dl(j);
+                                h = freqz(bit, 1, sbf, fs);
+                                msb(j) = sum(h.*conj(h));
+                        end
+                        idx = find(msb == min(msb), 1, 'first');
+                        bi(i) = bi(i) + dl(idx);
+                end
+                h = freqz(bi/sref/src.L, 1, sbf, fs);
+                sb2 = 20*log10(sqrt(sum(h.*conj(h))));
+
+                %% Plot to compare
+                if 0
+                        f = linspace(0, fs/2, 1000);
+                        h1 = freqz(src.coefs/src.L, 1, f, fs);
+                        h2 = freqz(bq0/sref/src.L, 1, f, fs);
+                        h3 = freqz(bi/sref/src.L, 1, f, fs);
+                        figure;
+                        plot(f, 20*log10(abs(h1)), f, 20*log10(abs(h2)), f, 20*log10(abs(h3)));
+                        grid on;
+                        fprintf('Original = %4.1f dB, optimized = %4.1f dB, delta = %4.1f dB\n', ...
+                                sb1, sb2, sb1-sb2);
+                end
+                cint0 = bi;
+        end
+
+
+        %% Re-order coefficients for filter implementation
+        cint = zeros(src.filter_length,1);
+        for n = 1:src.num_of_subfilters
+                i11 = (n-1)*src.subfilter_length+1;
+                i12 = i11+src.subfilter_length-1;
+                cint(i11:i12) = cint0(n:src.num_of_subfilters:end);
+        end
+
+        %% Done check for no overflow
+        max_fix = max(cint);
+	min_fix = min(cint);
+	if (max_fix > pmax)
+		printf('Fixed point coefficient %d exceeded %d\n.', max_fix, pmax);
+		error('Something went wrong!');
+	end
+	if (min_fix < nmin)
+		printf('Fixed point coefficient %d exceeded %d\n.', min_fix, nmax);
+		error('Something went wrong!');
+        end
+
+
+end
diff --git a/tune/src/src_export_defines.m b/tune/src/src_export_defines.m
new file mode 100644
index 0000000..63fb4c2
--- /dev/null
+++ b/tune/src/src_export_defines.m
@@ -0,0 +1,66 @@
+function src_export_defines(defs, ctype, hdir, profile)
+
+% src_export_defines - Exports the constants to header files
+%
+% src_export_defines(defs, ctype, hdir)
+%
+% defs    - defs struct
+% ctype   - e.g. 'int24' appended to file name
+% hdir    - directory for header file
+% profile - string to append to file name
+%
+
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 4
+        profile = '';
+end
+
+if isempty(profile)
+        hfn = sprintf('src_%s_define.h', ctype);
+else
+        hfn = sprintf('src_%s_%s_define.h', profile, ctype);
+end
+fh = fopen(fullfile(hdir,hfn), 'w');
+fprintf(fh, '/* SRC constants */\n');
+fprintf(fh, '#define MAX_FIR_DELAY_SIZE %d\n', defs.fir_delay_size);
+fprintf(fh, '#define MAX_OUT_DELAY_SIZE %d\n', defs.out_delay_size);
+fprintf(fh, '#define MAX_BLK_IN %d\n', defs.blk_in);
+fprintf(fh, '#define MAX_BLK_OUT %d\n', defs.blk_out);
+fprintf(fh, '#define NUM_IN_FS %d\n', defs.num_in_fs);
+fprintf(fh, '#define NUM_OUT_FS %d\n', defs.num_out_fs);
+fprintf(fh, '#define STAGE1_TIMES_MAX %d\n', defs.stage1_times_max);
+fprintf(fh, '#define STAGE2_TIMES_MAX %d\n', defs.stage2_times_max);
+fprintf(fh, '#define STAGE_BUF_SIZE %d\n', defs.stage_buf_size);
+fprintf(fh, '#define NUM_ALL_COEFFICIENTS %d\n', defs.sum_filter_lengths);
+fclose(fh);
+
+end
diff --git a/tune/src/src_export_table_2s.m b/tune/src/src_export_table_2s.m
new file mode 100644
index 0000000..7772b93
--- /dev/null
+++ b/tune/src/src_export_table_2s.m
@@ -0,0 +1,190 @@
+function sfl = src_export_table_2s(fs_in, fs_out, l_2s, m_2s, ...
+        pb_2s, sb_2s, taps_2s, ctype, vtype, ppath, hdir, profile)
+
+% src_export_table_2s - Export src setup table
+%
+% src_export_table_2s(fs_in, fs_out, l, m, pb, sb, ctype, vtype, hdir, profile)
+%
+% The parameters are used to differentiate files for possibly many same
+% conversion factor filters with possibly different characteristic.
+%
+% fs_in   - input sample rates
+% fs_out  - output sample rates
+% l       - interpolation factors
+% m       - decimation factors
+% pb      - passband widths
+% sb      - stopband start frequencies
+% ctype   - coefficient quantization
+% vtype   - C variable type
+% ppath   - print directory prefix to header file name include
+% hdir    - directory for header files
+% profile - string to append to file name
+%
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if nargin < 12
+        profile = '';
+end
+
+if isempty(profile)
+        hfn = sprintf('src_%s_table.h', ctype);
+else
+        hfn = sprintf('src_%s_%s_table.h', profile, ctype);
+end
+fh = fopen(fullfile(hdir,hfn), 'w');
+
+fprintf(fh, '/* SRC conversions */\n');
+sfl = 0;
+n_in = length(fs_in);
+n_out = length(fs_out);
+i=1;
+all_modes = zeros(2*n_in*n_out, 7);
+for n=1:2
+        for b=1:n_out
+                for a=1:n_in
+                        all_modes(i,:) = [ l_2s(n,a,b) m_2s(n,a,b) ...
+                                pb_2s(n,a,b) sb_2s(n,a,b) n a b ];
+                        i=i+1;
+                end
+        end
+end
+
+all_modes_sub = all_modes(:,1:4);
+[unique_modes, ia] = unique(all_modes_sub,'rows');
+sm = size(unique_modes);
+
+if isempty(profile)
+        prof_ctype = ctype;
+else
+        prof_ctype = sprintf('%s_%s', profile, ctype);
+end
+for i=1:sm(1)
+        um_tmp = unique_modes(i,:);
+        if isequal(um_tmp(1:2),[1 1]) || isequal(um_tmp(1:2),[0 0])
+        else
+                fprintf(fh, '#include <%ssrc_%s_%d_%d_%d_%d.h>\n', ...
+                        ppath, prof_ctype, um_tmp(1:4));
+
+                n = all_modes(ia(i), 5);
+                a = all_modes(ia(i), 6);
+                b = all_modes(ia(i), 7);
+                sfl = sfl +taps_2s(n, a, b); % Count sum of filter lengths
+        end
+end
+fprintf(fh,'\n');
+
+fprintf(fh, '/* SRC table */\n');
+switch ctype
+        case 'float'
+                fprintf(fh, '%s fir_one = 1.0;\n', vtype);
+                fprintf(fh, 'struct src_stage src_double_1_1_0_0 =  { 0, 0, 1, 1, 1, 1, 1, 0, 1.0, &fir_one };\n');
+                fprintf(fh, 'struct src_stage src_double_0_0_0_0 =  { 0, 0, 0, 0, 0, 0, 0, 0, 0.0, &fir_one };\n');
+        case 'int16'
+                scale16 = 2^15;
+                fprintf(fh, '%s fir_one = %d;\n', vtype, round(scale16*0.5));
+                fprintf(fh, 'struct src_stage src_int16_1_1_0_0 =  { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n');
+                fprintf(fh, 'struct src_stage src_int16_0_0_0_0 =  { 0, 0, 0, 0, 0, 0, 0, 0,  0, &fir_one };\n');
+        case 'int24'
+                scale24 = 2^23;
+                fprintf(fh, '%s fir_one = %d;\n', vtype, round(scale24*0.5));
+                fprintf(fh, 'struct src_stage src_int24_1_1_0_0 =  { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n');
+                fprintf(fh, 'struct src_stage src_int24_0_0_0_0 =  { 0, 0, 0, 0, 0, 0, 0, 0,  0, &fir_one };\n');
+        case 'int32'
+                scale32 = 2^31;
+                fprintf(fh, '%s fir_one = %d;\n', vtype, round(scale32*0.5));
+                fprintf(fh, 'struct src_stage src_int32_1_1_0_0 =  { 0, 0, 1, 1, 1, 1, 1, 0, -1, &fir_one };\n');
+                fprintf(fh, 'struct src_stage src_int32_0_0_0_0 =  { 0, 0, 0, 0, 0, 0, 0, 0,  0, &fir_one };\n');
+        otherwise
+                error('Unknown coefficient type!');
+end
+
+fprintf(fh, 'int src_in_fs[%d] = {', n_in);
+j = 1;
+for i=1:n_in
+        fprintf(fh, ' %d', fs_in(i));
+	if i < n_in
+		fprintf(fh, ',');
+	end
+	j = j + 1;
+	if (j > 8)
+		fprintf(fh, '\n\t');
+		j = 1;
+	end
+end
+fprintf(fh, '};\n');
+
+fprintf(fh, 'int src_out_fs[%d] = {', n_out);
+j = 1;
+for i=1:n_out
+        fprintf(fh, ' %d', fs_out(i));
+	if i < n_out
+		fprintf(fh, ',');
+	end
+	j = j + 1;
+	if (j > 8)
+		fprintf(fh, '\n\t');
+		j = 1;
+	end
+end
+fprintf(fh, '};\n');
+
+for n = 1:2
+        fprintf(fh, 'struct src_stage *src_table%d[%d][%d] = {\n', ...
+                n, n_out, n_in);
+	i = 1;
+        for b = 1:n_out
+                fprintf(fh, '\t{');
+                for a = 1:n_in
+                        fprintf(fh, ' &src_%s_%d_%d_%d_%d', ...
+                                ctype, l_2s(n,a,b), m_2s(n,a,b), ...
+                                pb_2s(n,a,b), sb_2s(n,a,b));
+                        if a < n_in
+                                fprintf(fh, ',');
+                        end
+			i = i + 1;
+			if i  > 2
+				fprintf(fh, '\n\t');
+				i = 1;
+			end
+                end
+                fprintf(fh, '}');
+                if b < n_out
+                        fprintf(fh, ',\n');
+                else
+                        fprintf(fh, '\n');
+                end
+        end
+        fprintf(fh, '};\n');
+end
+
+fclose(fh);
+
+end
diff --git a/tune/src/src_factor1_lm.m b/tune/src/src_factor1_lm.m
new file mode 100644
index 0000000..54e9173
--- /dev/null
+++ b/tune/src/src_factor1_lm.m
@@ -0,0 +1,44 @@
+function [l, m] = src_factor1_lm(fs1, fs2)
+
+% factor1_lm - factorize input and output sample rates ratio to fraction l/m
+%
+% [l, m] = factor1_lm(fs1, fs2)
+%
+% fs1 - input sample rate
+% fs2 - output sample rate
+%
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+k = gcd(fs1, fs2);
+l = fs2/k;
+m = fs1/k;
+
+end
diff --git a/tune/src/src_factor2_lm.m b/tune/src/src_factor2_lm.m
new file mode 100644
index 0000000..6ac8602
--- /dev/null
+++ b/tune/src/src_factor2_lm.m
@@ -0,0 +1,155 @@
+function [l1, m1, l2, m2] = src_factor2_lm(fs1, fs2)
+
+% factor2_lm - factorize input and output sample rates ratio to fraction l1/m2*l2/m2
+%
+% [l1, m1, l2, m2] = factor2_lm(fs1, fs2)
+%
+% fs1 - input sample rate
+% fs2 - output sample rate
+%
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+
+%% The same sample rate?
+if abs(fs1-fs2) < eps
+        l1 = 1; m1 = 1; l2 = 1; m2 = 1;
+        return
+end
+
+%% Find fraction, and factorize
+k = gcd(fs1, fs2);
+l = fs2/k;
+m = fs1/k;
+[l01, l02] = factor2(l);
+[m01, m02] = factor2(m);
+
+%% Hand fixing for some ratios, guide to reuse some common filters
+if (l==147) && (m==640)
+        l01 = 7; m01 = 8; l02 = l/l01; m02 = m/m01; % 192 to 44.1
+end
+if (l==147) && (m==320)
+        l01 = 7; m01 = 8; l02 = l/l01; m02 = m/m01; % 96 to 44.1
+end
+if (l==147) && (m==160)
+        l01 = 7; m01 = 8; l02 = l/l01; m02 = m/m01; % 48 to 44.1
+end
+if (l==160) && (m==147)
+        l01 = 8; m01 = 7; l02 = l/l01; m02 = m/m01; % 44.1 to 48
+end
+if (l==320) && (m==147)
+        l01 = 8; m01 = 7; l02 = l/l01; m02 = m/m01; % 44.1 to 96
+end
+if (l==4) && (m==3)
+        l01 = 4; m01 = 3; l02 = l/l01; m02 = m/m01; % 24 to 32, no 2 stage
+end
+if (l==3) && (m==4)
+        l01 = 3; m01 = 4; l02 = l/l01; m02 = m/m01; % 24 to 32, no 2 stage
+end
+
+
+r11 = l01/m01;
+r22 = l02/m02;
+r12 = l01/m02;
+r21 = l02/m01;
+fs3 = [r11 r12 r21 r22].*fs1;
+
+
+if fs1 > fs2 % Decrease sample rate, dont go below output rate
+        idx = find(fs3 >= fs2);
+        if length(idx) < 1
+                error('Cant factorise interpolations');
+        end
+        fs3_possible = fs3(idx);
+        delta = fs3_possible-fs2; % Fs3 that is nearest to fs2
+        idx = find(delta == min(delta), 1, 'first');
+        fs3_min = fs3_possible(idx);
+        idx = find(fs3 == fs3_min, 1, 'first');
+        switch idx
+                case 1, l1 = l01; m1 = m01; l2 = l02; m2 = m02;
+                case 2, l1 = l01; m1 = m02; l2 = l02; m2 = m01;
+                case 3, l1 = l02; m1 = m01; l2 = l01; m2 = m02;
+                case 4, l1 = l02; m1 = m02; l2 = l01; m2 = m01;
+        end
+else % Increase sample rate, don't go below input rate
+        idx = find(fs3 >= fs1);
+        if length(idx) < 1
+                error('Cant factorise interpolations');
+        end
+        fs3_possible = fs3(idx);
+        delta = fs3_possible-fs1; % Fs2 that is nearest to fs1
+        idx = find(delta == min(delta), 1, 'first');
+        fs3_min = fs3_possible(idx);
+        idx = find(fs3 == fs3_min, 1, 'first');
+        switch idx
+                case 1, l1 = l01; m1 = m01; l2 = l02; m2 = m02;
+                case 2, l1 = l01; m1 = m02; l2 = l02; m2 = m01;
+                case 3, l1 = l02; m1 = m01; l2 = l01; m2 = m02;
+                case 4, l1 = l02; m1 = m02; l2 = l01; m2 = m01;
+        end
+end
+
+%% If 1st stage is 1:1
+if (l1 == 1) && (m1 == 1)
+        l1 = l2;
+        m1 = m2;
+        l2 = 1;
+        m2 = 1;
+end
+
+f1=l/m;
+f2=l1/m1*l2/m2;
+if abs(f1 - f2) > 1e-6
+        error('Bug in factorization code!');
+end
+
+end
+
+
+function [a, b]=factor2(c)
+x = round(sqrt(c));
+t1 = x:2*x;
+d1 = c./t1;
+idx1 = find(d1 == floor(d1), 1, 'first');
+a1 = t1(idx1);
+t2 = x:-1:floor(x/2);
+d2 = c./t2;
+idx2 = find(d2 == floor(d2), 1, 'first');
+a2 = t2(idx2);
+if (a1-x) < (x-a2)
+        a = a1;
+else
+        a = a2;
+end
+b = c/a;
+end
+
+
+
diff --git a/tune/src/src_find_l0m0.m b/tune/src/src_find_l0m0.m
new file mode 100644
index 0000000..2a360a3
--- /dev/null
+++ b/tune/src/src_find_l0m0.m
@@ -0,0 +1,71 @@
+function [l0, m0] = src_find_l0m0(L, M)
+
+% find_l0m0 - find l0, m0 to meet -l0*L + m0*M == 1
+%
+% [l0, m0] = find_l0m0(L, M)
+%
+% L - interpolatation factor
+% M - decimation factor
+%
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if M == 1
+        l0 = 0;
+        m0 = 1;
+        return
+end
+
+if L == 1
+        l0 = 1;
+        m0 = 0;
+        return
+end
+
+l0 = [];
+m0 = [];
+for lt=1:4*L
+        mt = (1+lt*L)/M; % Check if -lt*L + mt*M == 1
+        if floor(mt) == mt
+                l0 = [l0 lt];
+                m0 = [m0 mt];
+        end
+end
+
+s = l0+m0;
+idx = find(s == min(s), 1, 'first');
+l0 = l0(idx);
+m0 = m0(idx);
+
+if -l0*L + m0*M ~= 1
+        error('Something went wrong!');
+end
+
+end
diff --git a/tune/src/src_generate.m b/tune/src/src_generate.m
new file mode 100644
index 0000000..b01b29d
--- /dev/null
+++ b/tune/src/src_generate.m
@@ -0,0 +1,311 @@
+function src_generate(fs_in, fs_out, ctype, fs_inout, profile, qc)
+
+% src_generate - export src conversions for given fs_in and fs_out
+%
+% src_generate(fs_in, fs_out <, ctype, fs_inout>>)
+%
+% fs_in    - vector of input sample rates (M)
+% fs_out   - vector of output sample rates (N)
+% ctype    - coefficient type, use 'int16','int24', 'int32', or 'float'
+% fs_inout - matrix of supported conversions (MxN),
+%            0 = no support, 1 = supported
+%				%
+% if ctype is omitted then ctype defaults to 'int16'.
+%
+% If fs_inout matrix is omitted this script will compute coefficients
+% for all fs_in <-> fs_out combinations.
+%
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+if (nargin == 1) || (nargin > 6)
+	error('Incorrect arguments for function!');
+end
+if nargin == 0
+	%% Default input and output rates
+        fs_in = [8e3 11025 12e3 16e3 18900 22050 24e3 32e3 44100 48e3 ...
+		     64e3 88.2e3 96e3 176400 192e3];
+
+	fs_out = [8e3 11025 12e3 16e3 18900 22050 24e3 32e3 44100 48e3];
+
+	fs_inout = [ 0 0 0 1 0 0 1 1 0 1 ; ...
+		     0 0 0 0 0 0 0 0 0 1 ; ...
+		     0 0 0 0 0 0 0 0 0 1 ; ...
+		     1 0 0 0 0 0 1 1 0 1 ; ...
+		     0 0 0 0 0 0 0 0 0 1 ; ...
+		     0 0 0 0 0 0 0 0 0 1 ; ...
+		     1 0 0 1 0 0 0 1 0 1 ; ...
+		     1 0 0 1 0 0 1 0 0 1 ; ...
+		     0 0 0 0 0 0 0 0 0 1 ; ...
+		     1 1 1 1 0 1 1 1 1 0 ; ...
+		     0 0 0 0 0 0 0 0 0 1 ; ...
+		     0 0 0 0 0 0 0 0 0 1 ; ...
+		     0 0 0 0 0 0 0 0 0 1 ; ...
+		     0 0 0 0 0 0 0 0 0 1 ; ...
+		     0 0 0 0 0 0 0 0 0 1 ];
+
+	ctype = 'int32';
+        profile = 'std';
+	qc = 1.0;
+else
+	if nargin < 3
+		ctype = 'int16';
+	end
+	if nargin < 4
+		fs_inout = ones(length(fs_in), length(fs_out));
+        end
+        if nargin < 5
+                profile = '';
+        end
+	if nargin < 6
+		qc = 1.0;
+	end
+end
+
+sio = size(fs_inout);
+if (length(fs_in) ~= sio(1)) ||  (length(fs_out) ~= sio(2))
+	error('Sample rates in/out matrix size mismatch!');
+end
+
+%% Exported coefficients type int16, int24, int32, float
+
+switch ctype
+       case 'int16'
+	       coef_label = 'int16';
+	       coef_ctype = 'int16_t';
+	       coef_bits = 16;
+	       coef_bytes = 2;
+       case 'int24'
+	       coef_label = 'int24';
+	       coef_ctype = 'int32_t';
+	       coef_bits = 24;
+	       coef_bytes = 4;
+       case 'int32'
+	       coef_label = 'int32';
+	       coef_ctype = 'int32_t';
+	       coef_bits = 32;
+	       coef_bytes = 4;
+       case 'float'
+	       coef_label = 'float'; coef_ctype = 'float';
+	       coef_bits = 24;
+	       coef_bytes = 4;
+       otherwise
+	       error('Request for incorrect coefficient type');
+end
+data_bytes = 4;
+
+hdir = mkdir_check('include');
+rdir = mkdir_check('reports');
+
+%% Find fractional conversion factors
+nfsi = length(fs_in);
+nfso = length(fs_out);
+l_2s = zeros(2, nfsi, nfso);
+m_2s = zeros(2, nfsi, nfso);
+mops_2s = zeros(2, nfsi, nfso);
+pb_2s = zeros(2,nfsi, nfso);
+sb_2s = zeros(2,nfsi, nfso);
+taps_2s = zeros(2,nfsi, nfso);
+defs.fir_delay_size = 0;
+defs.out_delay_size = 0;
+defs.blk_in = 0;
+defs.blk_out = 0;
+defs.num_in_fs = nfsi;
+defs.num_out_fs = nfso;
+defs.stage1_times_max = 0;
+defs.stage2_times_max = 0;
+defs.stage_buf_size = 0;
+h = 1;
+for b = 1:nfso
+        for a = 1:nfsi
+                fs1 = fs_in(a);
+                fs2 = fs_out(b);
+                [l1, m1, l2, m2] = src_factor2_lm(fs1, fs2);
+                fs3 = fs1*l1/m1;
+                cnv1 = src_param(fs1, fs3, coef_bits, qc);
+                cnv2 = src_param(fs3, fs2, coef_bits, qc);
+                if (fs2 < fs1)
+                        % When decimating 1st stage passband can be limited
+                        % for wider transition band
+                        f_pb = fs2*cnv2.c_pb;
+                        cnv1.c_pb = f_pb/min(fs1,fs3);
+                end
+                if (fs2 > fs1)
+                        % When interpolating 2nd stage passband can be limited
+                        % for wider transition band
+                        f_pb = fs1*cnv1.c_pb;
+                        cnv2.c_pb = f_pb/min(fs2,fs3);
+                end
+		if fs_inout(a,b) > 0 || (a == b)
+                        if cnv2.fs1-cnv2.fs2 > eps
+                                % Allow half ripple for dual stage SRC parts
+                                cnv1.rp = cnv1.rp/2;
+                                cnv2.rp = cnv2.rp/2;
+                        end
+                        src1 = src_get(cnv1);
+                        src2 = src_get(cnv2);
+                        k = gcd(src1.blk_out, src2.blk_in);
+                        stage1_times = src2.blk_in/k;
+                        stage2_times = stage1_times*src1.blk_out/src2.blk_in;
+                        defs.stage1_times_max = max(defs.stage1_times_max, stage1_times);
+                        defs.stage2_times_max = max(defs.stage2_times_max, stage2_times);
+                        l_2s(:,a,b) = [src1.L src2.L];
+                        m_2s(:,a,b) = [src1.M src2.M];
+                        mops_2s(:,a,b) = [src1.MOPS src2.MOPS];
+                        pb_2s(:,a,b) = [round(1e4*src1.c_pb) round(1e4*src2.c_pb)];
+                        sb_2s(:,a,b) = [round(1e4*src1.c_sb) round(1e4*src2.c_sb)];
+			taps_2s(:,a,b) = [src1.filter_length src2.filter_length];
+                        defs.fir_delay_size = max(defs.fir_delay_size, src1.fir_delay_size);
+                        defs.out_delay_size = max(defs.out_delay_size, src1.out_delay_size);
+                        defs.blk_in = max(defs.blk_in, src1.blk_in);
+                        defs.blk_out = max(defs.blk_out, src1.blk_out);
+                        defs.fir_delay_size = max(defs.fir_delay_size, src2.fir_delay_size);
+                        defs.out_delay_size = max(defs.out_delay_size, src2.out_delay_size);
+                        defs.blk_in = max(defs.blk_in, src2.blk_in);
+                        defs.blk_out = max(defs.blk_out, src2.blk_out);
+                        defs.stage_buf_size = max(defs.stage_buf_size, src1.blk_out*stage1_times);
+                        src_export_coef(src1, coef_label, coef_ctype, hdir, profile);
+                        src_export_coef(src2, coef_label, coef_ctype, hdir, profile);
+                end
+        end
+end
+
+%% Export modes table
+defs.sum_filter_lengths = src_export_table_2s(fs_in, fs_out, l_2s, m_2s, ...
+        pb_2s, sb_2s, taps_2s, coef_label, coef_ctype, ...
+        'sof/audio/coefficients/src/', hdir, profile);
+src_export_defines(defs, coef_label, hdir, profile);
+
+%% Print 2 stage conversion factors
+fn = sprintf('%s/src_2stage.txt', rdir);
+fh = fopen(fn,'w');
+fprintf(fh,'\n');
+fprintf(fh,'Dual stage fractional SRC: Ratios\n');
+fprintf(fh,'%8s, ', 'in \ out');
+for b = 1:nfso
+        fprintf(fh,'%12.1f, ', fs_out(b)/1e3);
+end
+fprintf(fh,'\n');
+for a = 1:nfsi
+        fprintf(fh,'%8.1f, ', fs_in(a)/1e3);
+        for b = 1:nfso
+                cstr = print_ratios(l_2s, m_2s, a, b);
+                fprintf(fh,'%12s, ', cstr);
+        end
+        fprintf(fh,'\n');
+end
+fprintf(fh,'\n');
+
+%% Print 2 stage MOPS
+fprintf(fh,'Dual stage fractional SRC: MOPS\n');
+fprintf(fh,'%8s, ', 'in \ out');
+for b = 1:nfso
+        fprintf(fh,'%8.1f, ', fs_out(b)/1e3);
+end
+fprintf(fh,'\n');
+for a = 1:nfsi
+        fprintf(fh,'%8.1f, ', fs_in(a)/1e3);
+        for b = 1:nfso
+                mops = sum(mops_2s(:,a,b));
+                if sum(l_2s(:,a,b)) < eps
+                        mops_str = 'x';
+                else
+                        mops_str = sprintf('%.2f', mops);
+                end
+                fprintf(fh,'%8s, ', mops_str);
+        end
+        fprintf(fh,'\n');
+end
+fprintf(fh,'\n');
+
+%% Print 2 stage MOPS per stage
+fprintf(fh,'Dual stage fractional SRC: MOPS per stage\n');
+fprintf(fh,'%10s, ', 'in \ out');
+for b = 1:nfso
+        fprintf(fh,'%10.1f, ', fs_out(b)/1e3);
+end
+fprintf(fh,'\n');
+for a = 1:nfsi
+        fprintf(fh,'%10.1f, ', fs_in(a)/1e3);
+        for b = 1:nfso
+                mops = mops_2s(:,a,b);
+                if sum(l_2s(:,a,b)) < eps
+                        mops_str = 'x';
+                else
+                        mops_str = sprintf('%.2f+%.2f', mops(1), mops(2));
+                end
+                fprintf(fh,'%10s, ', mops_str);
+        end
+        fprintf(fh,'\n');
+end
+fprintf(fh,'\n');
+
+fprintf(fh,'Coefficient RAM %.1f kB\n', ...
+        defs.sum_filter_lengths*coef_bytes/1024);
+fprintf(fh,'Max. data RAM %.1f kB\n', ...
+	(defs.fir_delay_size + defs.out_delay_size+defs.stage_buf_size) ...
+        * data_bytes/1024);
+
+fprintf(fh,'\n');
+fclose(fh);
+type(fn);
+
+end
+
+function d = mkdir_check(d)
+if exist(d) ~= 7
+        mkdir(d);
+end
+end
+
+function cstr = print_ratios(l_2s, m_2s, a, b)
+l1 = l_2s(1,a,b);
+m1 = m_2s(1,a,b);
+l2 = l_2s(2,a,b);
+m2 = m_2s(2,a,b);
+if l1+m2+l2+m2 == 0
+        cstr = 'x';
+else
+        if m2 == 1
+                if l2 == 1
+                        cstr2 = '';
+                else
+                        cstr2 = sprintf('*%d', l2);
+                end
+        else
+                cstr2 = sprintf('*%d/%d', l2, m2);
+        end
+        if m1 == 1
+                cstr1 = sprintf('%d', l1);
+        else
+                cstr1 = sprintf('%d/%d', l1, m1);
+        end
+        cstr = sprintf('%s%s', cstr1, cstr2);
+end
+end
diff --git a/tune/src/src_get.m b/tune/src/src_get.m
new file mode 100644
index 0000000..4520af9
--- /dev/null
+++ b/tune/src/src_get.m
@@ -0,0 +1,254 @@
+function src = src_get(cnv)
+
+% src_get - calculate coefficients for a src
+%
+% src = src_get(cnv);
+%
+% cnv - src parameters
+% src - src result
+%
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+use_firpm = 0;
+use_remez = 0;
+use_kaiser = 0;
+switch lower(cnv.design)
+	case 'firpm'
+		if exist('OCTAVE_VERSION', 'builtin')
+			use_remez = 1;
+		else
+			use_firpm = 1;
+		end
+	case 'kaiser'
+		use_kaiser = 1;
+	otherwise
+		error('Unknown FIR design request!');
+end
+
+if abs(cnv.fs1-cnv.fs2) < 1
+        %% Return minimum needed for scripts to work
+        src.L=1;
+        src.M=1;
+        src.odm=1;
+        src.idm=1;
+        src.MOPS=0;
+        src.c_pb = 0;
+        src.c_sb = 0;
+        src.fir_delay_size = 0;
+        src.out_delay_size = 0;
+        src.blk_in = 1;
+        src.blk_out = 1;
+        src.gain = 1;
+	src.filter_length = 0;
+        return
+end
+
+%% fractional SRC parameters
+[L, M] = src_factor1_lm(cnv.fs1, cnv.fs2);
+src.L = L;
+src.M = M;
+src.num_of_subfilters = L;
+[src.idm src.odm] = src_find_l0m0(src.L, src.M);
+min_fs = min(cnv.fs1,cnv.fs2);
+src.f_pb = min_fs*cnv.c_pb;
+src.f_sb = min_fs*cnv.c_sb;
+src.c_pb = cnv.c_pb;
+src.c_sb = cnv.c_sb;
+src.fs1 = cnv.fs1;
+src.fs2 = cnv.fs2;
+src.rp = cnv.rp;
+src.rs = cnv.rs;
+
+%% FIR PM design
+fs3 = src.L*cnv.fs1;
+f = [src.f_pb src.f_sb];
+a = [1 0];
+
+% Kaiser fir is not equiripple, can allow more ripple in the passband
+% lower freq.
+dev = [(10^(cnv.rp/20)-1)/(10^(cnv.rp/20)+1) 10^(-cnv.rs/20)];
+[kn0, kw, kbeta, kftype] = kaiserord(f, a, dev, fs3);
+if use_firpm
+        %dev = [(10^(cnv.rp/20)-1)/(10^(cnv.rp/20)+1) 10^(-cnv.rs/20)];
+        [n0,fo,ao,w] = firpmord(f,a,dev,fs3);
+	n0 = round(n0*0.95); % Decrease order to 95%
+end
+if use_remez
+        n0 = round(kn0*0.60); % Decrease order to 70%
+	fo = [0 2*f/fs3 1];
+	ao = [1 1 0 0];
+	w =  [1 dev(1)/dev(2)];
+end
+if use_kaiser
+	n0 = round(kn0*0.70); % Decrease order to 70%
+end
+
+% Constrain filter length to be a suitable multiple. Multiple of
+% interpolation factor ensures that all subfilters are equal length.
+% Make each sub-filter order multiple of N helps in making efficient
+% implementation.
+nfir_increment = src.num_of_subfilters * cnv.filter_length_mult;
+
+nsf0 = (n0+1)/nfir_increment;
+if nsf0 > floor(nsf0)
+        n = (floor(nsf0)+1)*nfir_increment-1;
+else
+        n = n0;
+end
+
+src.subfilter_length = (n+1)/src.num_of_subfilters;
+src.filter_length = n+1;
+nfir = n;
+f_sb = linspace(src.f_sb, fs3/2, 500);
+stopband_ok = 0;
+need_to_stop = 0;
+delta = 100;
+n_worse = 0;
+n_worse_max = 20;
+n = 1;
+n_max = 100;
+dn = ones(1, n_max)*1000;
+fn = zeros(1, n_max);
+while (stopband_ok) == 0 && (n < n_max)
+        if use_firpm || use_remez
+                if nfir > 1800
+                        b = fir1(nfir, kw, kftype, kaiser(nfir+1, kbeta));
+                else
+			if use_firpm
+				b = firpm(nfir,fo,ao,w);
+			else
+				b = remez(nfir,fo,ao,w);
+			end
+                end
+        else
+                b = fir1(nfir, kw, kftype, kaiser(nfir+1, kbeta));
+        end
+	m_b = max(abs(b));
+	%sref = 2^(cnv.coef_bits-1);
+	%bq = round(b*sref/m_b)*m_b/sref;
+        bq = b;
+        h_sb = freqz(bq, 1, f_sb, fs3);
+        m_sb = 20*log10(abs(h_sb));
+	delta_prev = delta;
+        delta = cnv.rs+max(m_sb);
+        fprintf('Step=%3d, Delta=%f dB, N=%d\n', n, delta, nfir);
+        dn(n) = delta;
+        fn(n) = nfir;
+        if delta < 0
+		stopband_ok = 1;
+        else
+		if delta_prev < delta
+                        n_worse = n_worse+1;
+                        if n_worse > n_worse_max
+                                need_to_stop = 1; % No improvement, reverse
+                                idx = find(dn == min(dn), 1, 'first');
+                                nfir = fn(idx);
+                        else
+				nfir = nfir + nfir_increment;
+                        end
+		else
+			if need_to_stop == 0
+				nfir = nfir + nfir_increment;
+			else
+				stopband_ok = 1; % Exit after reverse
+				fprintf('Warning: Filter stop band could not be ');
+				fprintf('reached.\n', cnv.coef_bits);
+			end
+		end
+        end
+        n = n + 1;
+end
+
+f_p = linspace(0, fs3/2, 2000);
+m_db = 20*log10(abs(freqz(bq, 1, f_p, fs3)));
+i_pb = find(f_p < src.f_pb);
+g_pb = max(m_db(i_pb));
+g_att_lin = 10^(-g_pb/20);
+
+if 1
+        p_ymin = floor((-cnv.rs-50)/10)*10;
+        p_ymax = 10;
+        figure;
+        clf;
+        plot(f_p, m_db);
+        grid on;
+        xlabel('Frequency (Hz)');
+        ylabel('Magnitude (dB)');
+        axis([0 fs3/2 p_ymin p_ymax]);
+        hold on
+        plot([src.f_sb src.f_sb],[p_ymin p_ymax], 'r--');
+        plot([0 fs3],[-cnv.rs -cnv.rs], 'r--');
+        hold off
+        axes('Position', [ 0.58 0.7 0.3 0.2]);
+        box on;
+        plot(f_p(i_pb), m_db(i_pb));
+        axis([0 src.f_pb -cnv.rp-0.01 cnv.rp+0.01]);
+        hold on
+        plot([0 src.f_pb], +0.5*cnv.rp*ones(1,2), 'r--');
+        plot([0 src.f_pb], -0.5*cnv.rp*ones(1,2), 'r--');
+        hold off
+        grid on;
+        box off;
+end
+
+src.subfilter_length = ceil((nfir+1)/src.num_of_subfilters);
+src.filter_length = src.subfilter_length*src.num_of_subfilters;
+src.b = zeros(src.filter_length,1);
+src.gain = 1;
+src.b(1:nfir+1) = b*src.L*g_att_lin;
+m = max(abs(src.b));
+gmax = (32767/32768)/m;
+maxshift = floor(log(gmax)/log(2));
+src.b = src.b * 2^maxshift;
+src.gain = 1/2^maxshift;
+src.shift = maxshift;
+
+%% Reorder coefficients
+if 1
+        src.coefs = src.b;
+else
+        src.coefs = zeros(src.filter_length,1);
+        for n = 1:src.num_of_subfilters
+                i11 = (n-1)*src.subfilter_length+1;
+                i12 = i11+src.subfilter_length-1;
+                src.coefs(i11:i12) = src.b(n:src.num_of_subfilters:end);
+        end
+end
+
+src.halfband = 0;
+src.blk_in = M;
+src.blk_out = L;
+src.MOPS = cnv.fs1/M*src.filter_length/1e6;
+src.fir_delay_size = src.subfilter_length + ...
+        (src.num_of_subfilters-1)*src.idm + src.blk_in;
+src.out_delay_size = (src.num_of_subfilters-1)*src.odm + 1;
+
+end
diff --git a/tune/src/src_param.m b/tune/src/src_param.m
new file mode 100644
index 0000000..49e935c
--- /dev/null
+++ b/tune/src/src_param.m
@@ -0,0 +1,87 @@
+function cnv = src_param(fs1, fs2, coef_bits, q)
+
+% src_param - get converter parameters
+%
+% cnv = src_param(fs1, fs2, coef_bits, q)
+%
+% fs1       - input rate
+% fs2       - output rate
+% coef_bits - word length identifier
+% q         - quality scale filter bandwidth and stopband attenuation,
+%	      1 is default
+%
+
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+% Note: firpm design with rs 93 dB, or kaiser with 69 dB rs is fair quality.
+% Both give about -80 dB THD+N with 24 bit coefficients. With 16 bit
+% coefficients THD+N is limited to about -76 dB.
+
+if nargin < 4
+	q = 1.0;
+end
+
+%% Copy input parameters
+cnv.fs1 = fs1;
+cnv.fs2 = fs2;
+cnv.coef_bits = coef_bits;
+
+%% FIR design
+cnv.design = 'kaiser'; % Use firpm or kaiser
+
+%% Default SRC quality
+cnv.c_pb = q * 22/48; % Gives 22 kHz BW @ 48 kHz
+cnv.c_sb = 0.5; % Start stopband at Fs/2
+cnv.rs = 70; % Stopband attenuation in dB
+cnv.rp = 0.1; % Passband ripple in dB
+cnv.rp_tot = 0.1; % Max +/- passband ripple allowed, used in test script only
+
+%% Constrain sub-filter lengths. Make subfilters lengths multiple of four
+%  is a good assumption for processors.
+cnv.filter_length_mult = 4;
+
+%% Exceptions for quality
+if min(fs1, fs2) > 80e3
+	cnv.c_pb = 30e3/min(fs1, fs2); % 30 kHz BW for > 80 kHz
+end
+
+%% Sanity checks
+if cnv.c_pb > 0.49
+	error('Too wide passband');
+end
+if cnv.c_pb < 0.15
+	error('Too narrow passband');
+end
+if cnv.rs > 160
+	error('Too large stopband attenuation');
+end
+if cnv.rs < 40
+	error('Too low stopband attenuation');
+end
diff --git a/tune/src/src_std_int32.m b/tune/src/src_std_int32.m
new file mode 100644
index 0000000..125ae96
--- /dev/null
+++ b/tune/src/src_std_int32.m
@@ -0,0 +1,30 @@
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+src_generate();
diff --git a/tune/src/src_tiny_int16.m b/tune/src/src_tiny_int16.m
new file mode 100644
index 0000000..be310fb
--- /dev/null
+++ b/tune/src/src_tiny_int16.m
@@ -0,0 +1,41 @@
+% Copyright (c) 2016, Intel Corporation
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions are met:
+%   * Redistributions of source code must retain the above copyright
+%     notice, this list of conditions and the following disclaimer.
+%   * Redistributions in binary form must reproduce the above copyright
+%     notice, this list of conditions and the following disclaimer in the
+%     documentation and/or other materials provided with the distribution.
+%   * Neither the name of the Intel Corporation nor the
+%     names of its contributors may be used to endorse or promote products
+%     derived from this software without specific prior written permission.
+%
+% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+% POSSIBILITY OF SUCH DAMAGE.
+%
+% Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
+%
+
+fs1 = [8e3 16e3 24e3 32e3 44.1e3 48e3];
+fs2 = [8e3 16e3 24e3 32e3 44.1e3 48e3];
+fsm  = [0 0 0 0 0 1; ...
+        0 0 0 0 0 1; ...
+        0 0 0 0 0 1; ...
+        0 0 0 0 0 1; ...
+        0 0 0 0 0 1; ...
+        1 1 1 1 1 0; ...
+        ];
+fmt = 'int16'; profile = 'tiny'; q = 0.75;
+
+src_generate(fs1, fs2, fmt, fsm, profile, q);