All of lore.kernel.org
 help / color / mirror / Atom feed
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
To: alsa-devel@alsa-project.org
Cc: Liam Girdwood <liam.r.girdwood@linux.intel.com>,
	Mark Brown <broonie@kernel.org>
Subject: [PATCH v2 08/12] ASoC: SOF: Add DSP HW abstraction operations
Date: Fri, 31 Aug 2018 16:19:06 +0100	[thread overview]
Message-ID: <20180831151910.16122-9-liam.r.girdwood@linux.intel.com> (raw)
In-Reply-To: <20180831151910.16122-1-liam.r.girdwood@linux.intel.com>

Add operation pointers that can be called by core to control a wide
variety of DSP targets. The DSP HW drivers will fill in these
operations.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
---
 sound/soc/sof/ops.c | 210 +++++++++++++++++++++++++++++++
 sound/soc/sof/ops.h | 298 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 508 insertions(+)
 create mode 100644 sound/soc/sof/ops.c
 create mode 100644 sound/soc/sof/ops.h

diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c
new file mode 100644
index 000000000000..48ea9ac32620
--- /dev/null
+++ b/sound/soc/sof/ops.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license.  When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2018 Intel Corporation. All rights reserved.
+//
+// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
+//
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <uapi/sound/sof-ipc.h>
+#include "ops.h"
+#include "sof-priv.h"
+
+int snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset,
+				     u32 mask, u32 value)
+{
+	bool change;
+	unsigned int old, new;
+	u32 ret = ~0; /* explicit init to remove uninitialized use warnings */
+
+	pci_read_config_dword(sdev->pci, offset, &ret);
+	dev_dbg(sdev->dev, "Debug PCIR: %8.8x at  %8.8x\n",
+		pci_read_config_dword(sdev->pci, offset, &ret), offset);
+
+	old = ret;
+	new = (old & (~mask)) | (value & mask);
+
+	change = (old != new);
+	if (change) {
+		pci_write_config_dword(sdev->pci, offset, new);
+		dev_dbg(sdev->dev, "Debug PCIW: %8.8x at  %8.8x\n", value,
+			offset);
+	}
+
+	return change;
+}
+EXPORT_SYMBOL(snd_sof_pci_update_bits_unlocked);
+
+int snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset,
+			    u32 mask, u32 value)
+{
+	unsigned long flags;
+	bool change;
+
+	spin_lock_irqsave(&sdev->hw_lock, flags);
+	change = snd_sof_pci_update_bits_unlocked(sdev, offset, mask, value);
+	spin_unlock_irqrestore(&sdev->hw_lock, flags);
+	return change;
+}
+EXPORT_SYMBOL(snd_sof_pci_update_bits);
+
+int snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar,
+				     u32 offset, u32 mask, u32 value)
+{
+	bool change;
+	unsigned int old, new;
+	u32 ret;
+
+	ret = snd_sof_dsp_read(sdev, bar, offset);
+
+	old = ret;
+	new = (old & (~mask)) | (value & mask);
+
+	change = (old != new);
+	if (change)
+		snd_sof_dsp_write(sdev, bar, offset, new);
+
+	return change;
+}
+EXPORT_SYMBOL(snd_sof_dsp_update_bits_unlocked);
+
+int snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar,
+				       u32 offset, u64 mask, u64 value)
+{
+	bool change;
+	u64 old, new;
+
+	old = snd_sof_dsp_read64(sdev, bar, offset);
+
+	new = (old & (~mask)) | (value & mask);
+
+	change = (old != new);
+	if (change)
+		snd_sof_dsp_write64(sdev, bar, offset, new);
+
+	return change;
+}
+EXPORT_SYMBOL(snd_sof_dsp_update_bits64_unlocked);
+
+/* This is for registers bits with attribute RWC */
+void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar,
+					     u32 offset, u32 mask, u32 value)
+{
+	unsigned int old, new;
+	u32 ret;
+
+	ret = snd_sof_dsp_read(sdev, bar, offset);
+
+	old = ret;
+	new = (old & (~mask)) | (value & mask);
+
+	snd_sof_dsp_write(sdev, bar, offset, new);
+}
+EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced_unlocked);
+
+int snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset,
+			    u32 mask, u32 value)
+{
+	unsigned long flags;
+	bool change;
+
+	spin_lock_irqsave(&sdev->hw_lock, flags);
+	change = snd_sof_dsp_update_bits_unlocked(sdev, bar, offset, mask,
+						  value);
+	spin_unlock_irqrestore(&sdev->hw_lock, flags);
+	return change;
+}
+EXPORT_SYMBOL(snd_sof_dsp_update_bits);
+
+int snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, u32 offset,
+			      u64 mask, u64 value)
+{
+	unsigned long flags;
+	bool change;
+
+	spin_lock_irqsave(&sdev->hw_lock, flags);
+	change = snd_sof_dsp_update_bits64_unlocked(sdev, bar, offset, mask,
+						    value);
+	spin_unlock_irqrestore(&sdev->hw_lock, flags);
+	return change;
+}
+EXPORT_SYMBOL(snd_sof_dsp_update_bits64);
+
+/* This is for registers bits with attribute RWC */
+void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar,
+				    u32 offset, u32 mask, u32 value)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sdev->hw_lock, flags);
+	snd_sof_dsp_update_bits_forced_unlocked(sdev, bar, offset, mask, value);
+	spin_unlock_irqrestore(&sdev->hw_lock, flags);
+}
+EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced);
+
+int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset,
+			      u32 mask, u32 target, u32 timeout)
+{
+	int time, ret;
+	bool done = false;
+
+	/*
+	 * we will poll for couple of ms using mdelay, if not successful
+	 * then go to longer sleep using usleep_range
+	 */
+
+	/* check if set state successful */
+	for (time = 0; time < 5; time++) {
+		if ((snd_sof_dsp_read(sdev, bar, offset) & mask) == target) {
+			done = true;
+			break;
+		}
+		msleep(20);
+	}
+
+	if (!done) {
+		/* sleeping in 10ms steps so adjust timeout value */
+		timeout /= 10;
+
+		for (time = 0; time < timeout; time++) {
+			if ((snd_sof_dsp_read(sdev, bar, offset) & mask) ==
+				target)
+				break;
+
+			usleep_range(5000, 10000);
+		}
+	}
+
+	ret = time < timeout ? 0 : -ETIME;
+
+	return ret;
+}
+EXPORT_SYMBOL(snd_sof_dsp_register_poll);
+
+void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset)
+{
+	dev_err(sdev->dev, "error : DSP panic!\n");
+
+	/* check if DSP is not ready and did not set the dsp_oops_offset.
+	 * if the dsp_oops_offset is not set, set it from the panic message.
+	 * Also add a check to memory window setting with panic message.
+	 */
+	if (!sdev->dsp_oops_offset)
+		sdev->dsp_oops_offset = offset;
+	else
+		dev_dbg(sdev->dev, "panic: dsp_oops_offset %zu offset %d\n",
+			sdev->dsp_oops_offset, offset);
+
+	snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
+	snd_sof_trace_notify_for_error(sdev);
+	snd_sof_dsp_cmd_done(sdev, SOF_IPC_HOST_REPLY);
+}
+EXPORT_SYMBOL(snd_sof_dsp_panic);
diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h
new file mode 100644
index 000000000000..6574707cd69b
--- /dev/null
+++ b/sound/soc/sof/ops.h
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license.  When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2018 Intel Corporation. All rights reserved.
+//
+// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
+//
+
+#ifndef __SOUND_SOC_SOF_IO_H
+#define __SOUND_SOC_SOF_IO_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <uapi/sound/sof-ipc.h>
+#include "sof-priv.h"
+
+/* init */
+static inline int snd_sof_probe(struct snd_sof_dev *sdev)
+{
+	if (sdev->ops->probe)
+		return sdev->ops->probe(sdev);
+	else
+		return 0;
+}
+
+static inline int snd_sof_remove(struct snd_sof_dev *sdev)
+{
+	if (sdev->ops->remove)
+		return sdev->ops->remove(sdev);
+	else
+		return 0;
+}
+
+/* control */
+static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev)
+{
+	if (sdev->ops->run)
+		return sdev->ops->run(sdev);
+	else
+		return 0;
+}
+
+static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev)
+{
+	if (sdev->ops->stall)
+		return sdev->ops->stall(sdev);
+	else
+		return 0;
+}
+
+static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev)
+{
+	if (sdev->ops->reset)
+		return sdev->ops->reset(sdev);
+	else
+		return 0;
+}
+
+/* power management */
+static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev)
+{
+	if (sdev->ops->resume)
+		return sdev->ops->resume(sdev);
+	else
+		return 0;
+}
+
+static inline int snd_sof_dsp_suspend(struct snd_sof_dev *sdev, int state)
+{
+	if (sdev->ops->suspend)
+		return sdev->ops->suspend(sdev, state);
+	else
+		return 0;
+}
+
+static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq)
+{
+	if (sdev->ops->set_clk)
+		return sdev->ops->set_clk(sdev, freq);
+	else
+		return 0;
+}
+
+/* debug */
+static inline void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags)
+{
+	if (sdev->ops->dbg_dump)
+		return sdev->ops->dbg_dump(sdev, flags);
+}
+
+/* register IO */
+static inline void snd_sof_dsp_write(struct snd_sof_dev *sdev, u32 bar,
+				     u32 offset, u32 value)
+{
+	if (sdev->ops->write)
+		sdev->ops->write(sdev, sdev->bar[bar] + offset, value);
+}
+
+static inline void snd_sof_dsp_write64(struct snd_sof_dev *sdev, u32 bar,
+				       u32 offset, u64 value)
+{
+	if (sdev->ops->write64)
+		sdev->ops->write64(sdev,
+			sdev->bar[bar] + offset, value);
+}
+
+static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar,
+				   u32 offset)
+{
+	if (sdev->ops->read)
+		return sdev->ops->read(sdev, sdev->bar[bar] + offset);
+	else
+		return 0;
+}
+
+static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar,
+				     u32 offset)
+{
+	if (sdev->ops->read64)
+		return sdev->ops->read64(sdev, sdev->bar[bar] + offset);
+	else
+		return 0;
+}
+
+/* block IO */
+static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev,
+					  u32 offset, void *dest, size_t bytes)
+{
+	if (sdev->ops->block_read)
+		sdev->ops->block_read(sdev, offset, dest, bytes);
+}
+
+static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev,
+					   u32 offset, void *src, size_t bytes)
+{
+	if (sdev->ops->block_write)
+		sdev->ops->block_write(sdev, offset, src, bytes);
+}
+
+/* mailbox */
+static inline void snd_sof_dsp_mailbox_read(struct snd_sof_dev *sdev,
+					    u32 offset, void *message,
+					    size_t bytes)
+{
+	if (sdev->ops->mailbox_read)
+		sdev->ops->mailbox_read(sdev, offset, message, bytes);
+}
+
+static inline void snd_sof_dsp_mailbox_write(struct snd_sof_dev *sdev,
+					     u32 offset, void *message,
+					     size_t bytes)
+{
+	if (sdev->ops->mailbox_write)
+		sdev->ops->mailbox_write(sdev, offset, message, bytes);
+}
+
+/* ipc */
+static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev,
+				       struct snd_sof_ipc_msg *msg)
+{
+	if (sdev->ops->send_msg)
+		return sdev->ops->send_msg(sdev, msg);
+	else
+		return 0;
+}
+
+static inline int snd_sof_dsp_get_reply(struct snd_sof_dev *sdev,
+					struct snd_sof_ipc_msg *msg)
+{
+	if (sdev->ops->get_reply)
+		return sdev->ops->get_reply(sdev, msg);
+	else
+		return 0;
+}
+
+static inline int snd_sof_dsp_is_ready(struct snd_sof_dev *sdev)
+{
+	if (sdev->ops->is_ready)
+		return sdev->ops->is_ready(sdev);
+	else
+		return 0;
+}
+
+static inline int snd_sof_dsp_cmd_done(struct snd_sof_dev *sdev,
+				       int dir)
+{
+	if (sdev->ops->cmd_done)
+		return sdev->ops->cmd_done(sdev, dir);
+	else
+		return 0;
+}
+
+/* host DMA trace */
+static inline int snd_sof_dma_trace_init(struct snd_sof_dev *sdev,
+					 u32 *stream_tag)
+{
+	if (sdev->ops->trace_init)
+		return sdev->ops->trace_init(sdev, stream_tag);
+	else
+		return 0;
+}
+
+static inline int snd_sof_dma_trace_release(struct snd_sof_dev *sdev)
+{
+	if (sdev->ops->trace_release)
+		return sdev->ops->trace_release(sdev);
+	else
+		return 0;
+}
+
+static inline int snd_sof_dma_trace_trigger(struct snd_sof_dev *sdev, int cmd)
+{
+	if (sdev->ops->trace_trigger)
+		return sdev->ops->trace_trigger(sdev, cmd);
+	else
+		return 0;
+}
+
+/* host PCM ops */
+static inline int
+snd_sof_pcm_platform_open(struct snd_sof_dev *sdev,
+			  struct snd_pcm_substream *substream)
+{
+	if (sdev->ops && sdev->ops->pcm_open)
+		return sdev->ops->pcm_open(sdev, substream);
+	else
+		return 0;
+}
+
+/* disconnect pcm substream to a host stream */
+static inline int
+snd_sof_pcm_platform_close(struct snd_sof_dev *sdev,
+			   struct snd_pcm_substream *substream)
+{
+	if (sdev->ops && sdev->ops->pcm_close)
+		return sdev->ops->pcm_close(sdev, substream);
+	else
+		return 0;
+}
+
+/* host stream hw params */
+static inline int
+snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev,
+			       struct snd_pcm_substream *substream,
+			       struct snd_pcm_hw_params *params)
+{
+	if (sdev->ops && sdev->ops->pcm_hw_params)
+		return sdev->ops->pcm_hw_params(sdev, substream, params);
+	else
+		return 0;
+}
+
+/* host stream trigger */
+static inline int
+snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev,
+			     struct snd_pcm_substream *substream, int cmd)
+{
+	if (sdev->ops && sdev->ops->pcm_trigger)
+		return sdev->ops->pcm_trigger(sdev, substream, cmd);
+	else
+		return 0;
+}
+
+int snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar,
+				     u32 offset, u32 mask, u32 value);
+
+int snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar,
+				       u32 offset, u64 mask, u64 value);
+
+/* This is for registers bits with attribute RWC */
+void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar,
+					     u32 offset, u32 mask, u32 value);
+
+int snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset,
+			    u32 mask, u32 value);
+
+int snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar,
+			      u32 offset, u64 mask, u64 value);
+
+/* This is for registers bits with attribute RWC */
+void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar,
+				    u32 offset, u32 mask, u32 value);
+
+int snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset,
+				     u32 mask, u32 value);
+
+int snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset,
+			    u32 mask, u32 value);
+
+int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset,
+			      u32 mask, u32 target, u32 timeout);
+
+void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset);
+#endif
-- 
2.17.1

  parent reply	other threads:[~2018-08-31 15:19 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-08-31 15:18 [PATCH v2 00/12] Sound Open Firmware Core Liam Girdwood
2018-08-31 15:18 ` [PATCH v2 01/12] ASoC: SOF: Add Sound Open Firmware driver core Liam Girdwood
2018-09-03 15:07   ` Mark Brown
2018-08-31 15:19 ` [PATCH v2 02/12] ASoC: SOF: Add Sound Open Firmware KControl support Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 03/12] ASoC: SOF: Add driver debug support Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 04/12] ASoC: SOF: Add support for IPC IO between DSP and Host Liam Girdwood
2018-09-03 15:53   ` Mark Brown
2018-09-04 13:15     ` Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 05/12] ASoC: SOF: Add PCM operations support Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 06/12] ASoC: SOF: Add support for loading topologies Liam Girdwood
2018-09-03 16:19   ` Mark Brown
2018-08-31 15:19 ` [PATCH v2 07/12] ASoC: SOF: Add DSP firmware trace event support Liam Girdwood
2018-09-03 16:25   ` Mark Brown
2018-09-04 13:21     ` Liam Girdwood
2018-09-04 15:03       ` Mark Brown
2018-09-04 15:28         ` Liam Girdwood
2018-09-04 15:46           ` Mark Brown
2018-09-20 16:02             ` Liam Girdwood
2018-08-31 15:19 ` Liam Girdwood [this message]
2018-08-31 15:19 ` [PATCH v2 09/12] ASoC: SOF: Add firmware loader support Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 10/12] ASoC: SOF: Add PM support Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 11/12] ASoC: SOF: Add userspace ABI support Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 12/12] ASoC: SOF: Add Build support for SOF core Liam Girdwood

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=20180831151910.16122-9-liam.r.girdwood@linux.intel.com \
    --to=liam.r.girdwood@linux.intel.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=broonie@kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.