Alsa-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Vinod Koul <vinod.koul@intel.com>
To: alsa-devel@alsa-project.org
Cc: tiwai@suse.de, patches.audio@intel.com,
	liam.r.girdwood@linux.intel.com,
	Vinod Koul <vinod.koul@intel.com>,
	broonie@kernel.org,
	"Subhransu S. Prusty" <subhransu.s.prusty@intel.com>
Subject: [RFC 4/9] ASoC: hda: Add DSP init and boot up functionality
Date: Fri, 17 Apr 2015 18:46:02 +0530	[thread overview]
Message-ID: <1429276567-29007-5-git-send-email-vinod.koul@intel.com> (raw)
In-Reply-To: <1429276567-29007-1-git-send-email-vinod.koul@intel.com>

From: "Subhransu S. Prusty" <subhransu.s.prusty@intel.com>

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 include/sound/soc-hda-sst-dsp.h       |   28 +++
 sound/soc/hda/intel/soc-hda-sst-dsp.c |  350 +++++++++++++++++++++++++++++++++
 2 files changed, 378 insertions(+)

diff --git a/include/sound/soc-hda-sst-dsp.h b/include/sound/soc-hda-sst-dsp.h
index 44e8d67aab3a..4a89c3dda5ab 100644
--- a/include/sound/soc-hda-sst-dsp.h
+++ b/include/sound/soc-hda-sst-dsp.h
@@ -101,6 +101,34 @@
 #define ADSPIC_IPC                      1
 #define ADSPIS_IPC			1
 
+/* ADSPCS - Audio DSP Control & Status */
+#define DSP_CORES 1
+#define DSP_CORE0_MASK 1
+#define DSP_CORES_MASK ((1 << DSP_CORES) - 1)
+
+/* Core Reset - asserted high */
+#define ADSPCS_CRST_SHIFT	0
+#define ADSPCS_CRST_MASK	(DSP_CORES_MASK << ADSPCS_CRST_SHIFT)
+#define ADSPCS_CRST(x)		((x << ADSPCS_CRST_SHIFT) & ADSPCS_CRST_MASK)
+
+/* Core run/stall - when set to '1' core is stalled */
+#define ADSPCS_CSTALL_SHIFT	8
+#define ADSPCS_CSTALL_MASK	(DSP_CORES_MASK << ADSPCS_CSTALL_SHIFT)
+#define ADSPCS_CSTALL(x)	((x << ADSPCS_CSTALL_SHIFT) & ADSPCS_CSTALL_MASK)
+
+/* Set Power Active - when set to '1' turn cores on */
+#define ADSPCS_SPA_SHIFT	16
+#define ADSPCS_SPA_MASK		(DSP_CORES_MASK << ADSPCS_SPA_SHIFT)
+#define ADSPCS_SPA(x)		((x << ADSPCS_SPA_SHIFT) & ADSPCS_SPA_MASK)
+
+/* Current Power Active - power status of cores, set by hardware */
+#define ADSPCS_CPA_SHIFT	24
+#define ADSPCS_CPA_MASK		(DSP_CORES_MASK << ADSPCS_CPA_SHIFT)
+#define ADSPCS_CPA(x)		((x << ADSPCS_CPA_SHIFT) & ADSPCS_CPA_MASK)
+
+#define SST_DSP_POWER_D0              0x0  /* full On */
+#define SST_DSP_POWER_D3              0x3  /* Off */
+
 struct ssth_window {
 	void __iomem *w0stat;
 	void __iomem *w0up;
diff --git a/sound/soc/hda/intel/soc-hda-sst-dsp.c b/sound/soc/hda/intel/soc-hda-sst-dsp.c
index 6e85645b3a3e..6285a6772e73 100644
--- a/sound/soc/hda/intel/soc-hda-sst-dsp.c
+++ b/sound/soc/hda/intel/soc-hda-sst-dsp.c
@@ -34,6 +34,11 @@
 #include <sound/soc-hda-sst-dsp.h>
 #include <sound/soc-hda-sst-ipc.h>
 
+#define DSP_CORE_POWER_UP_TIMEOUT		50
+#define DSP_CORE_POWER_DOWN_TIMEOUT		50
+#define DSP_CORE_SET_RESET_STATE_TIMEOUT	50
+#define DSP_CORE_UNSET_RESET_STATE_TIMEOUT	50
+
 u8 ssth_readb_traced(struct ssth_lib *dsp, u32 offset)
 {
 	u8 val;
@@ -135,5 +140,350 @@ void ssth_mailbox_read(struct ssth_lib  *ctx, void *msg, size_t bytes)
 	_ssth_memcpy_fromio_32(msg, ctx->window.w0up, bytes);
 }
 
+int ssth_register_poll(struct ssth_lib  *ctx, u32 offset, u32 mask,
+			 u32 expected_value, u32 timeout, char *operation)
+{
+	int time = 0;
+	int ret = 0;
+	u32 reg;
+
+	dev_dbg(ctx->dev, "In %s\n", __func__);
+
+	/* check if set state successful */
+	for (time = 0; time < timeout; time++) {
+		if ((ssth_readl_alt(ctx, offset) & mask) == expected_value)
+			break;
+
+		mdelay(1);
+	}
+	reg = ssth_readl_alt(ctx, offset);
+	dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s %s\n", reg, operation,
+			(time < timeout) ? "successful" : "timedout");
+	ret = time < timeout ? 0 : -ETIME;
+
+	return ret;
+}
+
+static int ssth_dsp_core_set_reset_state(struct ssth_lib  *ctx)
+{
+	int ret = 0;
+
+	dev_dbg(ctx->dev, "In %s\n", __func__);
+
+	/* update bits */
+	ssth_updatel_locked(ctx, ADSPCS, CRST_MASK,
+				ADSPCS_CRST(DSP_CORES_MASK));
+
+	/* poll with timeout to check if operation successful */
+	ret = ssth_register_poll(ctx,
+			HDA_ADSP_REG_ADSPCS,
+			ADSPCS_CRST_MASK,
+			ADSPCS_CRST(DSP_CORES_MASK),
+			DSP_CORE_SET_RESET_STATE_TIMEOUT,
+			"Set reset");
+	if ((ssth_readl(ctx, ADSPCS) & ADSPCS_CRST(DSP_CORES_MASK)) !=
+			ADSPCS_CRST(DSP_CORES_MASK)) {
+		dev_err(ctx->dev, "Set reset state failed\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int ssth_dsp_core_unset_reset_state(struct ssth_lib  *ctx)
+{
+	int ret = 0;
+
+	dev_dbg(ctx->dev, "In %s\n", __func__);
+
+	/* update bits */
+	ssth_updatel_locked(ctx, ADSPCS, CRST_MASK, 0);
+
+	/* poll with timeout to check if operation successful */
+	ret = ssth_register_poll(ctx,
+			HDA_ADSP_REG_ADSPCS,
+			ADSPCS_CRST_MASK,
+			0,
+			DSP_CORE_UNSET_RESET_STATE_TIMEOUT,
+			"Unset reset");
+
+	if ((ssth_readl(ctx, ADSPCS) & ADSPCS_CRST(DSP_CORES_MASK)) != 0) {
+		dev_err(ctx->dev, "Unset reset state failed\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int ssth_dsp_core_power_up(struct ssth_lib  *ctx)
+{
+	int ret = 0;
+
+	dev_dbg(ctx->dev, "In %s\n", __func__);
+	/* update bits */
+	ssth_updatel_locked(ctx,
+			ADSPCS, SPA_MASK, ADSPCS_SPA(DSP_CORES_MASK));
+
+	/* poll with timeout to check if operation successful */
+	ret = ssth_register_poll(ctx,
+			HDA_ADSP_REG_ADSPCS,
+			ADSPCS_CPA_MASK,
+			ADSPCS_CPA(DSP_CORES_MASK),
+			DSP_CORE_POWER_UP_TIMEOUT,
+			"Power up");
+
+	if ((ssth_readl(ctx, ADSPCS) & ADSPCS_CPA(DSP_CORES_MASK)) !=
+			ADSPCS_CPA(DSP_CORES_MASK)) {
+		dev_err(ctx->dev, "DSP core power up failed\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int ssth_dsp_core_power_down(struct ssth_lib  *ctx)
+{
+	int ret = 0;
+
+	dev_dbg(ctx->dev, "In %s\n", __func__);
+
+	/* update bits */
+	ssth_updatel_locked(ctx, ADSPCS, SPA_MASK, 0);
+
+	/* poll with timeout to check if operation successful */
+	ret = ssth_register_poll(ctx,
+			HDA_ADSP_REG_ADSPCS,
+			ADSPCS_SPA_MASK,
+			0,
+			DSP_CORE_POWER_DOWN_TIMEOUT,
+			"Power down");
+
+	return ret;
+}
+
+static bool ssth_is_dsp_core_enable(struct ssth_lib  *ctx)
+{
+	int val = 0;
+	bool is_enable;
+
+	val = ssth_readl(ctx, ADSPCS);
+
+	is_enable = ((val & ADSPCS_CPA(DSP_CORES_MASK)) &&
+			(val & ADSPCS_SPA(DSP_CORES_MASK)) &&
+			!(val & ADSPCS_CRST(DSP_CORES_MASK)) &&
+			!(val & ADSPCS_CSTALL(DSP_CORES_MASK)));
+
+	dev_dbg(ctx->dev, "DSP core is enabled=%d\n", is_enable);
+	return is_enable;
+}
+
+
+int ssth_enable_dsp_core(struct ssth_lib  *ctx)
+{
+	int ret = 0;
+
+	dev_dbg(ctx->dev, "In %s\n", __func__);
+
+	/* power up */
+	ret = ssth_dsp_core_power_up(ctx);
+	if (ret < 0) {
+		dev_dbg(ctx->dev, "dsp core power up failed\n");
+		return ret;
+	}
+
+	/* unset reset state */
+	ret = ssth_dsp_core_unset_reset_state(ctx);
+	if (ret < 0) {
+		dev_dbg(ctx->dev, "dsp core reset failed\n");
+		return ret;
+	}
+
+	/* run core */
+	dev_dbg(ctx->dev, "run core...\n");
+	ssth_writel(ctx, ADSPCS, ssth_readl(ctx, ADSPCS) &
+			~ADSPCS_CSTALL(DSP_CORES_MASK));
+
+	if (!ssth_is_dsp_core_enable(ctx)) {
+		dev_err(ctx->dev, "DSP core enable failed\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+int ssth_disable_dsp_core(struct ssth_lib  *ctx)
+{
+	int ret = 0;
+
+	dev_dbg(ctx->dev, "In %s\n", __func__);
+
+	/* stall core */
+	ssth_writel(ctx, ADSPCS, ssth_readl(ctx, ADSPCS) |
+			ADSPCS_CSTALL(DSP_CORES_MASK));
+
+	/* set reset state */
+	ret = ssth_dsp_core_set_reset_state(ctx);
+	if (ret < 0) {
+		dev_err(ctx->dev, "dsp core reset failed\n");
+		return ret;
+	}
+
+	/* power down core*/
+	ret = ssth_dsp_core_power_down(ctx);
+	if (ret < 0) {
+		dev_err(ctx->dev, "dsp core power down failed\n");
+		return ret;
+	}
+
+	if (ssth_is_dsp_core_enable(ctx)) {
+		dev_err(ctx->dev, "DSP core disable failed\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int ssth_reset_dsp_core(struct ssth_lib  *ctx)
+{
+	int ret = 0;
+
+	dev_dbg(ctx->dev, "In %s\n", __func__);
+
+	/* stall core */
+	ssth_writel(ctx, ADSPCS, ssth_readl(ctx, ADSPCS) &
+			ADSPCS_CSTALL(DSP_CORES_MASK));
+
+	/* set reset state */
+	ret = ssth_dsp_core_set_reset_state(ctx);
+	if (ret < 0) {
+		dev_err(ctx->dev, "dsp reset failed\n");
+		return ret;
+	}
+
+	/* unset reset state */
+	ret = ssth_dsp_core_unset_reset_state(ctx);
+	if (ret < 0) {
+		dev_dbg(ctx->dev, "dsp unset reset failes\n");
+		return ret;
+	}
+
+	/* run core */
+	dev_dbg(ctx->dev, "run core...\n");
+	ssth_writel(ctx, ADSPCS, ssth_readl(ctx, ADSPCS) &
+			~ADSPCS_CSTALL(DSP_CORES_MASK));
+
+	if (ssth_is_dsp_core_enable(ctx)) {
+		dev_err(ctx->dev, "DSP core reset failed\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+int ssth_boot_dsp(struct ssth_lib *ctx)
+{
+	int ret = 0;
+
+	dev_dbg(ctx->dev, "In %s\n", __func__);
+
+	if (ssth_is_dsp_core_enable(ctx)) {
+		/* Dsp core powered up - simply reset core */
+		dev_dbg(ctx->dev, "dsp core is already enabled, so reset the dap core\n");
+		ret = ssth_reset_dsp_core(ctx);
+	} else {
+		/*disable and enable to make sure DSP is invalid state */
+		ret = ssth_disable_dsp_core(ctx);
+
+		if (ret < 0) {
+			dev_err(ctx->dev, "dsp disable core failes\n");
+			return ret;
+		}
+		ret = ssth_enable_dsp_core(ctx);
+	}
+
+	return ret;
+}
+
+/*
+ * interrupt handler
+ */
+static irqreturn_t ssth_interrupt(int irq, void *dev_id)
+{
+	struct ssth_lib *ctx = (struct ssth_lib *) dev_id;
+	u32 val;
+	irqreturn_t result = IRQ_NONE;
+
+	spin_lock(&ctx->reg_lock);
+
+	val = ssth_readl(ctx, ADSPIS);
+
+	if (val & ADSPIS_IPC) {
+		ssth_ipc_int_disable(ctx);
+		queue_work(ctx->intr_wq, &ctx->ipc_process_msg_work);
+		result = IRQ_HANDLED;
+	}
+
+	spin_unlock(&ctx->reg_lock);
+	return result;
+}
+
+static int ssth_acquire_irq(struct ssth_lib *ctx)
+{
+	if (request_threaded_irq(ctx->irq, ssth_interrupt,
+			NULL, IRQF_SHARED, KBUILD_MODNAME, ctx)) {
+		dev_err(ctx->dev, "unable to grab threaded IRQ %d, disabling device\n", ctx->irq);
+		return -1;
+	}
+	return 0;
+}
+
+int ssth_dsp_init(struct ssth_lib *ctx)
+{
+	int ret = 0;
+
+	mutex_init(&ctx->sst_lock);
+	spin_lock_init(&ctx->reg_lock);
+
+	dev_dbg(ctx->dev, "In %s\n", __func__);
+
+	/* initialize IPC */
+	ctx->ipc = ssth_ipc_init(ctx->dev, ctx);
+	if (ctx->ipc == NULL)
+		ret = -ENODEV;
+
+	/* Now let's request the IRQ */
+	ssth_acquire_irq(ctx);
+
+	return ret;
+}
+
+int ssth_dsp_free0(struct ssth_lib *dsp)
+{
+	int ret = 0;
+
+	dev_dbg(dsp->dev, "In %s\n", __func__);
+
+	ssth_ipc_int_disable(dsp);
+
+	free_irq(dsp->irq, dsp);
+	ssth_ipc_free(dsp->ipc);
+	ssth_disable_dsp_core(dsp);
+	kfree(dsp);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ssth_dsp_free0);
+
+bool ssth_dsp_is_running(struct ssth_lib *ctx)
+{
+	bool ret = 0;
+
+	mutex_lock(&ctx->sst_lock);
+	ret = (ctx->sst_state == SST_DSP_RUNNING) ? 1 : 0;
+	mutex_unlock(&ctx->sst_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ssth_dsp_is_running);
+
 MODULE_DESCRIPTION("HDA SST/IPC Library");
 MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

  parent reply	other threads:[~2015-04-17 13:21 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-17 13:15 [RFC 0/9] Add SKL ipc handling code Vinod Koul
2015-04-17 13:15 ` [RFC 1/9] ASoC: hda: Add helper to read/write to dsp mmio space Vinod Koul
2015-04-20 21:46   ` Mark Brown
2015-04-22  3:50     ` Vinod Koul
2015-04-24 17:33       ` Mark Brown
2015-04-26 14:34         ` Vinod Koul
2015-04-27 21:02           ` Mark Brown
2015-04-29 11:03             ` Vinod Koul
2015-04-17 13:16 ` [RFC 2/9] ASoC: hda: Add IPC library for SKL platform Vinod Koul
2015-04-20 21:56   ` Mark Brown
2015-04-22  3:54     ` Vinod Koul
2015-04-24 17:34       ` Mark Brown
2015-04-26 14:36         ` Vinod Koul
2015-04-17 13:16 ` [RFC 3/9] ASoC: hda: Add config option for SKL ipc library Vinod Koul
2015-04-17 13:16 ` Vinod Koul [this message]
2015-04-24 17:11   ` [RFC 4/9] ASoC: hda: Add DSP init and boot up functionality Mark Brown
2015-04-26 14:21     ` Vinod Koul
2015-04-17 13:16 ` [RFC 5/9] ASoC: hda: Add dsp loader ops Vinod Koul
2015-04-17 13:16 ` [RFC 6/9] ASoC: hda: Add Code Loader DMA support Vinod Koul
2015-04-24 17:18   ` Mark Brown
2015-04-26 14:28     ` Vinod Koul
2015-04-27 14:17       ` Mark Brown
2015-04-29 11:08         ` Vinod Koul
2015-04-17 13:16 ` [RFC 7/9] ASoC: hda: Add DSP library functions for SKL platform Vinod Koul
2015-04-17 13:16 ` [RFC 8/9] ASoC: hda: Add for CL DMA interrupt handling Vinod Koul
2015-04-24 17:30   ` Mark Brown
2015-04-26 14:28     ` Vinod Koul
2015-04-17 13:16 ` [RFC 9/9] ASoC: hda: Export API to change DSP power state Vinod Koul
2015-04-24 17:33   ` Mark Brown
2015-04-20 21:44 ` [RFC 0/9] Add SKL ipc handling code Mark Brown
2015-04-22  4:00   ` Vinod Koul
2015-04-22 11:19     ` Liam Girdwood
2015-04-22 15:53       ` Vinod Koul
2015-04-22 19:06         ` Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1429276567-29007-5-git-send-email-vinod.koul@intel.com \
    --to=vinod.koul@intel.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=broonie@kernel.org \
    --cc=liam.r.girdwood@linux.intel.com \
    --cc=patches.audio@intel.com \
    --cc=subhransu.s.prusty@intel.com \
    --cc=tiwai@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox