All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point
@ 2020-08-12 20:57 Cezary Rojewski
  2020-08-12 20:57 ` [PATCH v4 01/13] ASoC: Intel: Add catpt device Cezary Rojewski
                   ` (14 more replies)
  0 siblings, 15 replies; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-12 20:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: pierre-louis.bossart, Cezary Rojewski, andriy.shevchenko,
	filip.kaczmarski, harshapriya.n, marcin.barlik, zwisler,
	lgirdwood, tiwai, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

Implement support for Lynxpoint and Wildcat Point AudioDSP. Catpt
solution deprecates existing sound/soc/intel/haswell which is removed in
the following series. This cover-letter is followed by 'Developer's deep
dive' message schedding light on catpt's key concepts and areas
addressed.

Due to high range of errors and desynchronization from recommendations
set by Windows solution, re-write came as a lower-cost solution compared
to refactoring /haswell/ with several series of patches.

Special thanks go to Marcin Barlik and Piotr Papierkowski for sharing
their LPT/WPT AudioDSP architecture expertise as well as helping
backtrack its historical background.
My thanks go to Amadeusz Slawinski for reviews and improvements proposed
on and off the internal list. Most of internal diff below is his
contribution.
Krzysztof Hejmowski helped me setup my own Xtensa environment and
recompile LPT/WPT FW binary sources what sped up the development greatly.

This would not have been possible without help from these champions,
especially considering how quickly the catpt was written: 2 weeks
features, 3 weeks optimizations. Thank you.

Userspace-exposed members are compatible with what is exposed by
deprecated solution as well as FW binary being re-used thus no harm is
done. The only visible differences are: the newly added 'Loopback Mute'
kcontrol and volume support extending to quad from stereo.

On top of fixing erros and design flows, catpt also adds module reload,
dynamic SRAM memory allocation during PCM runtime and exposes missing
userspace API: 'Loopback Mute' kcontrol, quad volume controls and sysfs
fw-version entries. Event tracing is provided to easy solution
debugging.

Following are not included in this update and are scheduled as later
addition:
- fw logging
- module (library) support

Note: LPT power up/down sequences might get aligned with WPT once enough
testing is done as capabilities are shared for both DSPs.
Note #2: Both LPT and WPT power up/down sequences may get optimized in
future updates as thanks to help from the Windows team, most of nuances
behind why/what/when in regard to hw registers have been backtracked and
reviewed again.

Link to developer's deep dive message:
https://www.spinics.net/lists/alsa-devel/msg113563.html

Changes in v4:
- fixed compilation with i386 kconfig (conflicting names)
- streamlined naming for SHIM and PCI registers to match SSP ones
  (SHIM_REG -> SHIM)
- catpt_component_probe removed and kcontrols again initializzed
  statically via snd_kcontrol_new array: this is to remove
  kctl->id.device shenanigans
- renamed catpt_set_ctlvol to catpt_set_dspvol - function name wasn't
  matching its purpose

Changes in v3:
- fixed IRAM mask usage in lpt_dsp_power_up (dsp.c)
- updated dbg message formatting in catpt_restore_fwimage as suggested
  by Andy
- fixed alignment for struct catpt_ssp_device_format
- catpt_set_ctlvol now verifies all-equal scenario based on all
  channels rather than just first two as requested by Amadeo
- fixed SPDX for registers.h

Changes in v2:
- fixed SPDX formatting for all header files as well as pcm.c
- fixed size used when memcping fs.c::fw_build_read as reported by Mark
- renamed struct catpt_pdata to struct catpt_spec (cosmetic)
- fixed erroneous path in catpt_load_block: region is properly released
- trace.h events for updating registers have been removed and usages
  replaced by dev_dbg (SRAMPGE/ LPCS)

- as requested by Andy, struct resource has replaced struct catpt_mbank
  and struct catpt_mregion. This change cascaded into:

  - catpt_mbank_size and catpt_mregion_size replaced by resource_size
  - catpt_mregion_intersects replaced by resource_overlaps
  - all catpt_mbank_ and catpt_mregion_ handlers found in loader.c
    (_request, _reserve, _release, _extract, _split, _join) have been
    removed
  - __request_region and __release_region have been enlisted in their
    place
  - catpt_mregion_intersecting renamed to catpt_resource_overlapping
  - catpt_request_region helper has been provided to deal with -size
    based requests
      o haven't found direct replacements in resource.c/ ioport.h for
      both functions

  - catpt_mbank_create and catpt_mbank_remove renamed to catpt_sram_init
    and catpt_sram_free respectively
  - catpt_sram_init now returns void instead of int and has been
    converted to simple initialized. This change ultimately cascaded
    into:
      o both SRAM banks initialization being moved to catpt_dev_init
        from catpt_acpi_probe (device.c)
      o catpt_dev::spec is now initialized first, with catpt_dev_init
        following it soon after
      o catpt_acpi_probe erroneous path has been simplified as SRAM
        banks no longer need to be freed

  - catpt_sram_free now frees all resources via child -> sibling
    enumeration rather than region_list iteration
  - catpt_dsp_update_srampge and catpt_dsp_set_srampge now accept new
    argument: unsigned long mask. Caused by removal of catpt_mbank -
    mask is taken directly from catpt_dev::spec::d/iram_mask
  - trace.h events for catpt_mbank and catpt_mregion have been removed

Diff against last drop on internal list:
- replaced spinlock with mutex for mregion allocation and release to
  address sleeping in atomic context warnings
- fixed coredump fw_hash dumping
- kcontrol values are now always stored regardless of stream of interest
  is running or not
- kcontrol values are now applied after stream is prepared instead of
  ignoring what has been set by user initially
- catpt_pdata instances have been renamed from hsw_ and bdw_ to lpt_ and
  wpt_ respectively
- reordered Makefile .o(s) (cosmetic)

Cezary Rojewski (13):
  ASoC: Intel: Add catpt device
  ASoC: Intel: catpt: Define DSP operations
  ASoC: Intel: catpt: Firmware loading and context restore
  ASoC: Intel: catpt: Implement IPC protocol
  ASoC: Intel: catpt: Add IPC messages
  ASoC: Intel: catpt: PCM operations
  ASoC: Intel: catpt: Event tracing
  ASoC: Intel: catpt: Simple sysfs attributes
  ASoC: Intel: Select catpt and deprecate haswell
  ASoC: Intel: haswell: Remove haswell-solution specific code
  ASoC: Intel: broadwell: Remove haswell-solution specific code
  ASoC: Intel: bdw-5650: Remove haswell-solution specific code
  ASoC: Intel: bdw-5677: Remove haswell-solution specific code

 sound/soc/intel/Kconfig             |   22 +-
 sound/soc/intel/Makefile            |    2 +-
 sound/soc/intel/boards/Kconfig      |    8 +-
 sound/soc/intel/boards/bdw-rt5650.c |   36 -
 sound/soc/intel/boards/bdw-rt5677.c |   33 -
 sound/soc/intel/boards/broadwell.c  |   33 -
 sound/soc/intel/boards/haswell.c    |   28 +-
 sound/soc/intel/catpt/Makefile      |    6 +
 sound/soc/intel/catpt/core.h        |  187 +++++
 sound/soc/intel/catpt/device.c      |  376 +++++++++
 sound/soc/intel/catpt/dsp.c         |  596 +++++++++++++
 sound/soc/intel/catpt/fs.c          |   79 ++
 sound/soc/intel/catpt/ipc.c         |  298 +++++++
 sound/soc/intel/catpt/loader.c      |  673 +++++++++++++++
 sound/soc/intel/catpt/messages.c    |  312 +++++++
 sound/soc/intel/catpt/messages.h    |  401 +++++++++
 sound/soc/intel/catpt/pcm.c         | 1212 +++++++++++++++++++++++++++
 sound/soc/intel/catpt/registers.h   |  191 +++++
 sound/soc/intel/catpt/trace.h       |   83 ++
 19 files changed, 4434 insertions(+), 142 deletions(-)
 create mode 100644 sound/soc/intel/catpt/Makefile
 create mode 100644 sound/soc/intel/catpt/core.h
 create mode 100644 sound/soc/intel/catpt/device.c
 create mode 100644 sound/soc/intel/catpt/dsp.c
 create mode 100644 sound/soc/intel/catpt/fs.c
 create mode 100644 sound/soc/intel/catpt/ipc.c
 create mode 100644 sound/soc/intel/catpt/loader.c
 create mode 100644 sound/soc/intel/catpt/messages.c
 create mode 100644 sound/soc/intel/catpt/messages.h
 create mode 100644 sound/soc/intel/catpt/pcm.c
 create mode 100644 sound/soc/intel/catpt/registers.h
 create mode 100644 sound/soc/intel/catpt/trace.h

-- 
2.17.1


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

* [PATCH v4 01/13] ASoC: Intel: Add catpt device
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
@ 2020-08-12 20:57 ` Cezary Rojewski
  2020-08-13 18:29   ` Andy Shevchenko
  2020-08-12 20:57 ` [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations Cezary Rojewski
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-12 20:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: pierre-louis.bossart, Cezary Rojewski, andriy.shevchenko,
	filip.kaczmarski, harshapriya.n, marcin.barlik, zwisler,
	lgirdwood, tiwai, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

Declare base structures, registers and device routines for the catpt
solution. Catpt deprecates and is a direct replacement for
sound/soc/intel/haswell. Supports Lynxpoint and Wildcat Point both.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/catpt/core.h      | 187 +++++++++++++++
 sound/soc/intel/catpt/device.c    | 376 ++++++++++++++++++++++++++++++
 sound/soc/intel/catpt/registers.h | 191 +++++++++++++++
 3 files changed, 754 insertions(+)
 create mode 100644 sound/soc/intel/catpt/core.h
 create mode 100644 sound/soc/intel/catpt/device.c
 create mode 100644 sound/soc/intel/catpt/registers.h

diff --git a/sound/soc/intel/catpt/core.h b/sound/soc/intel/catpt/core.h
new file mode 100644
index 000000000000..aa231ba9eaa9
--- /dev/null
+++ b/sound/soc/intel/catpt/core.h
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2020 Intel Corporation. All rights reserved.
+ *
+ * Author: Cezary Rojewski <cezary.rojewski@intel.com>
+ */
+
+#ifndef __SND_SOC_INTEL_CATPT_CORE_H
+#define __SND_SOC_INTEL_CATPT_CORE_H
+
+#include <linux/dma/dw.h>
+#include <linux/irqreturn.h>
+#include "messages.h"
+#include "registers.h"
+
+void catpt_sram_init(struct resource *sram, u32 start, u32 size);
+void catpt_sram_free(struct resource *sram);
+struct resource *
+catpt_request_region(struct resource *root, resource_size_t size);
+
+static inline bool catpt_resource_overlapping(struct resource *r1,
+					      struct resource *r2,
+					      struct resource *ret)
+{
+	if (!resource_overlaps(r1, r2))
+		return false;
+	ret->start = max(r1->start, r2->start);
+	ret->end = min(r1->end, r2->end);
+	return true;
+}
+
+struct catpt_ipc_msg {
+	union {
+		u32 header;
+		union catpt_global_msg rsp;
+	};
+	void *data;
+	size_t size;
+};
+
+struct catpt_ipc {
+	struct device *dev;
+
+	struct catpt_ipc_msg rx;
+	struct catpt_fw_ready config;
+	u32 default_timeout;
+	bool ready;
+
+	spinlock_t lock;
+	struct mutex mutex;
+	struct completion done_completion;
+	struct completion busy_completion;
+};
+
+void catpt_ipc_init(struct catpt_ipc *ipc, struct device *dev);
+
+struct catpt_module_type {
+	bool loaded;
+	u32 entry_point;
+	u32 persistent_size;
+	u32 scratch_size;
+	/* DRAM, initial module state */
+	u32 state_offset;
+	u32 state_size;
+
+	struct list_head node;
+};
+
+struct catpt_spec {
+	struct snd_soc_acpi_mach *machines;
+	u8 core_id;
+	u32 host_dram_offset;
+	u32 host_iram_offset;
+	u32 host_shim_offset;
+	u32 host_dma_offset[CATPT_DMA_COUNT];
+	u32 host_ssp_offset[CATPT_SSP_COUNT];
+	u32 dram_mask;
+	u32 iram_mask;
+	void (*pll_shutdown)(struct catpt_dev *cdev, bool enable);
+	int (*power_up)(struct catpt_dev *cdev);
+	int (*power_down)(struct catpt_dev *cdev);
+};
+
+struct catpt_dev {
+	struct device *dev;
+	struct dw_dma_chip *dmac;
+	struct catpt_ipc ipc;
+
+	void __iomem *pci_ba;
+	void __iomem *lpe_ba;
+	u32 lpe_base;
+	int irq;
+
+	const struct catpt_spec *spec;
+	struct completion fw_ready;
+
+	struct resource dram;
+	struct resource iram;
+	struct resource *scratch;
+
+	struct catpt_mixer_stream_info mixer;
+	struct catpt_module_type modules[CATPT_MODULE_COUNT];
+	struct catpt_ssp_device_format devfmt[CATPT_SSP_COUNT];
+	struct list_head stream_list;
+	spinlock_t list_lock;
+	struct mutex clk_mutex;
+
+	struct catpt_dx_context dx_ctx;
+	void *dxbuf_vaddr;
+	dma_addr_t dxbuf_paddr;
+};
+
+int catpt_dmac_probe(struct catpt_dev *cdev);
+void catpt_dmac_remove(struct catpt_dev *cdev);
+struct dma_chan *catpt_dma_request_config_chan(struct catpt_dev *cdev);
+int catpt_dma_memcpy_todsp(struct catpt_dev *cdev, struct dma_chan *chan,
+			   dma_addr_t dst_addr, dma_addr_t src_addr,
+			   size_t size);
+int catpt_dma_memcpy_fromdsp(struct catpt_dev *cdev, struct dma_chan *chan,
+			     dma_addr_t dst_addr, dma_addr_t src_addr,
+			     size_t size);
+
+void lpt_dsp_pll_shutdown(struct catpt_dev *cdev, bool enable);
+void wpt_dsp_pll_shutdown(struct catpt_dev *cdev, bool enable);
+int lpt_dsp_power_up(struct catpt_dev *cdev);
+int lpt_dsp_power_down(struct catpt_dev *cdev);
+int wpt_dsp_power_up(struct catpt_dev *cdev);
+int wpt_dsp_power_down(struct catpt_dev *cdev);
+int catpt_dsp_stall(struct catpt_dev *cdev, bool stall);
+void catpt_dsp_update_srampge(struct catpt_dev *cdev, struct resource *sram,
+			      unsigned long mask);
+int catpt_dsp_update_lpclock(struct catpt_dev *cdev);
+irqreturn_t catpt_dsp_irq_handler(int irq, void *dev_id);
+irqreturn_t catpt_dsp_irq_thread(int irq, void *dev_id);
+
+/*
+ * IPC handlers may return positive values which denote successful
+ * HOST <-> DSP communication yet failure to process specific request.
+ * Use below macro to convert returned non-zero values appropriately
+ */
+#define CATPT_IPC_ERROR(err) ((err < 0) ? err : -EREMOTEIO)
+
+int catpt_dsp_send_msg_timeout(struct catpt_dev *cdev,
+			       struct catpt_ipc_msg request,
+			       struct catpt_ipc_msg *reply, int timeout);
+int catpt_dsp_send_msg(struct catpt_dev *cdev, struct catpt_ipc_msg request,
+		       struct catpt_ipc_msg *reply);
+
+int catpt_first_boot_firmware(struct catpt_dev *cdev);
+int catpt_boot_firmware(struct catpt_dev *cdev, bool restore);
+int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan);
+int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan);
+int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan);
+int catpt_coredump(struct catpt_dev *cdev);
+
+int catpt_sysfs_create(struct catpt_dev *cdev);
+void catpt_sysfs_remove(struct catpt_dev *cdev);
+
+#include <sound/memalloc.h>
+#include <uapi/sound/asound.h>
+
+struct snd_pcm_substream;
+struct catpt_stream_template;
+
+struct catpt_stream_runtime {
+	struct snd_pcm_substream *substream;
+
+	struct catpt_stream_template *template;
+	struct catpt_stream_info info;
+	struct resource *persistent;
+	struct snd_dma_buffer pgtbl;
+
+	bool allocated:1;
+	bool prepared:1;
+
+	struct list_head node;
+};
+
+int catpt_register_plat_component(struct catpt_dev *cdev);
+void catpt_stream_update_position(struct catpt_dev *cdev,
+				  struct catpt_stream_runtime *stream,
+				  struct catpt_notify_position *pos);
+struct catpt_stream_runtime *
+catpt_stream_find(struct catpt_dev *cdev, u8 stream_hw_id);
+int catpt_arm_stream_templates(struct catpt_dev *cdev);
+
+#endif
diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c
new file mode 100644
index 000000000000..a4a498ba3456
--- /dev/null
+++ b/sound/soc/intel/catpt/device.c
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2020 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+// Special thanks to:
+//    Marcin Barlik <marcin.barlik@intel.com>
+//    Piotr Papierkowski <piotr.papierkowski@intel.com>
+//
+// for sharing LPT-LP and WTP-LP AudioDSP architecture expertise and
+// helping backtrack its historical background
+//
+
+#include <linux/acpi.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "core.h"
+#include "registers.h"
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+#ifdef CONFIG_PM
+static int catpt_suspend(struct device *dev)
+{
+	struct catpt_dev *cdev = dev_get_drvdata(dev);
+	struct dma_chan *chan;
+	int ret;
+
+	chan = catpt_dma_request_config_chan(cdev);
+	if (IS_ERR(chan))
+		return PTR_ERR(chan);
+
+	memset(&cdev->dx_ctx, 0, sizeof(cdev->dx_ctx));
+	ret = catpt_ipc_enter_dxstate(cdev, CATPT_DX_STATE_D3, &cdev->dx_ctx);
+	if (ret) {
+		ret = CATPT_IPC_ERROR(ret);
+		goto exit;
+	}
+
+	ret = catpt_dsp_stall(cdev, true);
+	if (ret < 0)
+		goto exit;
+
+	ret = catpt_store_memdumps(cdev, chan);
+	if (ret < 0) {
+		dev_err(cdev->dev, "store memdumps failed: %d\n", ret);
+		goto exit;
+	}
+
+	ret = catpt_store_module_states(cdev, chan);
+	if (ret < 0) {
+		dev_err(cdev->dev, "store module states failed: %d\n", ret);
+		goto exit;
+	}
+
+	ret = catpt_store_streams_context(cdev, chan);
+	if (ret < 0) {
+		dev_err(cdev->dev, "store streams ctx failed: %d\n", ret);
+		goto exit;
+	}
+exit:
+	dma_release_channel(chan);
+	if (ret < 0)
+		return ret;
+	return cdev->spec->power_down(cdev);
+}
+
+static int catpt_resume(struct device *dev)
+{
+	struct catpt_dev *cdev = dev_get_drvdata(dev);
+	int ret, i;
+
+	ret = cdev->spec->power_up(cdev);
+	if (ret < 0)
+		return ret;
+
+	if (!module_is_live(dev->driver->owner)) {
+		dev_info(dev, "module unloading, skipping fw boot\n");
+		return 0;
+	}
+
+	ret = catpt_boot_firmware(cdev, true);
+	if (ret < 0) {
+		dev_err(cdev->dev, "boot firmware failed: %d\n", ret);
+		return ret;
+	}
+
+	/* reconfigure SSP devices after dx transition */
+	for (i = 0; i < CATPT_SSP_COUNT; i++) {
+		if (cdev->devfmt[i].iface == UINT_MAX)
+			continue;
+
+		ret = catpt_ipc_set_device_format(cdev, &cdev->devfmt[i]);
+		if (ret)
+			return CATPT_IPC_ERROR(ret);
+	}
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int catpt_runtime_suspend(struct device *dev)
+{
+	return catpt_suspend(dev);
+}
+
+static int catpt_runtime_resume(struct device *dev)
+{
+	return catpt_resume(dev);
+}
+#endif
+
+static const struct dev_pm_ops catpt_dev_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(catpt_suspend, catpt_resume)
+	SET_RUNTIME_PM_OPS(catpt_runtime_suspend, catpt_runtime_resume, NULL)
+};
+
+/* machine board owned by CATPT is removed with this hook */
+static void board_pdev_unregister(void *data)
+{
+	platform_device_unregister(data);
+}
+
+static int catpt_register_board(struct catpt_dev *cdev)
+{
+	const struct catpt_spec *spec = cdev->spec;
+	struct snd_soc_acpi_mach *mach;
+	struct platform_device *board;
+	int ret;
+
+	mach = snd_soc_acpi_find_machine(spec->machines);
+	if (!mach) {
+		dev_info(cdev->dev, "no machines present\n");
+		return 0;
+	}
+
+	mach->mach_params.platform = "catpt-platform";
+	board = platform_device_register_data(NULL, mach->drv_name,
+					PLATFORM_DEVID_NONE,
+					(const void *)mach, sizeof(*mach));
+	if (!board) {
+		dev_err(cdev->dev, "board register failed\n");
+		return PTR_ERR(board);
+	}
+
+	ret = devm_add_action(cdev->dev, board_pdev_unregister, board);
+	if (ret < 0) {
+		platform_device_unregister(board);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int catpt_probe_components(struct catpt_dev *cdev)
+{
+	int ret;
+
+	ret = cdev->spec->power_up(cdev);
+	if (ret < 0)
+		return ret;
+
+	ret = catpt_dmac_probe(cdev);
+	if (ret < 0) {
+		dev_err(cdev->dev, "DMAC probe failed: %d\n", ret);
+		goto dmac_err;
+	}
+
+	ret = catpt_first_boot_firmware(cdev);
+	if (ret < 0) {
+		dev_err(cdev->dev, "first fw boot failed: %d\n", ret);
+		goto boot_fw_err;
+	}
+
+	ret = catpt_register_plat_component(cdev);
+	if (ret < 0) {
+		dev_err(cdev->dev, "register plat comp failed: %d\n", ret);
+		goto boot_fw_err;
+	}
+
+	ret = catpt_register_board(cdev);
+	if (ret < 0) {
+		dev_err(cdev->dev, "register board failed: %d\n", ret);
+		goto board_err;
+	}
+
+	ret = catpt_sysfs_create(cdev);
+	if (ret < 0)
+		goto board_err;
+
+	/* reflect actual ADSP state in pm_runtime */
+	pm_runtime_set_active(cdev->dev);
+
+	pm_runtime_set_autosuspend_delay(cdev->dev, 2000);
+	pm_runtime_use_autosuspend(cdev->dev);
+	pm_runtime_mark_last_busy(cdev->dev);
+	pm_runtime_enable(cdev->dev);
+	return 0;
+
+board_err:
+	snd_soc_unregister_component(cdev->dev);
+boot_fw_err:
+	catpt_dmac_remove(cdev);
+dmac_err:
+	cdev->spec->power_down(cdev);
+
+	return ret;
+}
+
+static void catpt_dev_init(struct catpt_dev *cdev, struct device *dev)
+{
+	cdev->dev = dev;
+	init_completion(&cdev->fw_ready);
+	INIT_LIST_HEAD(&cdev->stream_list);
+	spin_lock_init(&cdev->list_lock);
+	mutex_init(&cdev->clk_mutex);
+	/*
+	 * Mark both device formats as uninitialized. Once corresponding
+	 * cpu_dai's pcm is created, proper values are assigned
+	 */
+	cdev->devfmt[CATPT_SSP_IFACE_0].iface = UINT_MAX;
+	cdev->devfmt[CATPT_SSP_IFACE_1].iface = UINT_MAX;
+
+	catpt_ipc_init(&cdev->ipc, dev);
+
+	catpt_sram_init(&cdev->dram, cdev->spec->host_dram_offset,
+			catpt_dram_size(cdev));
+	catpt_sram_init(&cdev->iram, cdev->spec->host_iram_offset,
+			catpt_iram_size(cdev));
+}
+
+static int catpt_acpi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct catpt_dev *cdev;
+	struct resource *res;
+	int ret;
+
+	cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL);
+	if (!cdev)
+		return -ENOMEM;
+
+	cdev->spec = device_get_match_data(dev);
+	if (!cdev->spec)
+		return -ENODEV;
+
+	catpt_dev_init(cdev, dev);
+
+	/* map DSP bar address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+	cdev->lpe_ba = devm_ioremap(dev, res->start, resource_size(res));
+	if (!cdev->lpe_ba)
+		return -EIO;
+	cdev->lpe_base = res->start;
+
+	/* map PCI bar address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res)
+		return -ENODEV;
+	cdev->pci_ba = devm_ioremap(dev, res->start, resource_size(res));
+	if (!cdev->pci_ba)
+		return -EIO;
+
+	/* alloc buffer for storing DRAM context during dx transitions */
+	cdev->dxbuf_vaddr = dma_alloc_coherent(dev, catpt_dram_size(cdev),
+					       &cdev->dxbuf_paddr, GFP_KERNEL);
+	if (!cdev->dxbuf_vaddr)
+		return -ENOMEM;
+
+	ret = platform_get_irq(pdev, 0);
+	if (ret < 0)
+		goto irq_err;
+	cdev->irq = ret;
+
+	platform_set_drvdata(pdev, cdev);
+
+	ret = devm_request_threaded_irq(dev, cdev->irq, catpt_dsp_irq_handler,
+					catpt_dsp_irq_thread,
+					IRQF_SHARED, "AudioDSP", cdev);
+	if (ret < 0)
+		goto irq_err;
+
+	ret = catpt_probe_components(cdev);
+	if (ret < 0)
+		goto irq_err;
+	return 0;
+
+irq_err:
+	dma_free_coherent(cdev->dev, catpt_dram_size(cdev),
+			  cdev->dxbuf_vaddr, cdev->dxbuf_paddr);
+
+	return ret;
+}
+
+static int catpt_acpi_remove(struct platform_device *pdev)
+{
+	struct catpt_dev *cdev = platform_get_drvdata(pdev);
+
+	pm_runtime_disable(cdev->dev);
+
+	snd_soc_unregister_component(cdev->dev);
+	catpt_dmac_remove(cdev);
+	cdev->spec->power_down(cdev);
+
+	dma_free_coherent(cdev->dev, catpt_dram_size(cdev),
+			  cdev->dxbuf_vaddr, cdev->dxbuf_paddr);
+	catpt_sram_free(&cdev->iram);
+	catpt_sram_free(&cdev->dram);
+
+	catpt_sysfs_remove(cdev);
+
+	return 0;
+}
+
+static struct catpt_spec lpt_desc = {
+	.machines = snd_soc_acpi_intel_haswell_machines,
+	.core_id = 0x01,
+	.host_dram_offset = 0x000000,
+	.host_iram_offset = 0x080000,
+	.host_shim_offset = 0x0E7000,
+	.host_dma_offset = { 0x0F0000, 0x0F8000 },
+	.host_ssp_offset = { 0x0E8000, 0x0E9000 },
+	.dram_mask = LPT_VDRTCTL0_DSRAMPGE_MASK,
+	.iram_mask = LPT_VDRTCTL0_ISRAMPGE_MASK,
+	.pll_shutdown = lpt_dsp_pll_shutdown,
+	.power_up = lpt_dsp_power_up,
+	.power_down = lpt_dsp_power_down,
+};
+
+static struct catpt_spec wpt_desc = {
+	.machines = snd_soc_acpi_intel_broadwell_machines,
+	.core_id = 0x02,
+	.host_dram_offset = 0x000000,
+	.host_iram_offset = 0x0A0000,
+	.host_shim_offset = 0x0FB000,
+	.host_dma_offset = { 0x0FE000, 0x0FF000 },
+	.host_ssp_offset = { 0x0FC000, 0x0FD000 },
+	.dram_mask = WPT_VDRTCTL0_DSRAMPGE_MASK,
+	.iram_mask = WPT_VDRTCTL0_ISRAMPGE_MASK,
+	.pll_shutdown = wpt_dsp_pll_shutdown,
+	.power_up = wpt_dsp_power_up,
+	.power_down = wpt_dsp_power_down,
+};
+
+static const struct acpi_device_id catpt_ids[] = {
+	{ "INT33C8", (unsigned long)&lpt_desc },
+	{ "INT3438", (unsigned long)&wpt_desc },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, catpt_ids);
+
+static struct platform_driver catpt_acpi_driver = {
+	.probe = catpt_acpi_probe,
+	.remove = catpt_acpi_remove,
+	.driver = {
+		.name = "catpt_adsp",
+		.acpi_match_table = ACPI_PTR(catpt_ids),
+		.pm = &catpt_dev_pm,
+	},
+};
+module_platform_driver(catpt_acpi_driver);
+
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_DESCRIPTION("Intel LPT/WPT AudioDSP driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/catpt/registers.h b/sound/soc/intel/catpt/registers.h
new file mode 100644
index 000000000000..108bec961183
--- /dev/null
+++ b/sound/soc/intel/catpt/registers.h
@@ -0,0 +1,191 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2020 Intel Corporation. All rights reserved.
+ *
+ * Author: Cezary Rojewski <cezary.rojewski@intel.com>
+ */
+
+#ifndef __SND_SOC_INTEL_CATPT_REGS_H
+#define __SND_SOC_INTEL_CATPT_REGS_H
+
+#include <linux/iopoll.h>
+
+#define CATPT_SHIM_REGS_SIZE	4096
+#define CATPT_DMA_REGS_SIZE	1024
+#define CATPT_DMA_COUNT		2
+#define CATPT_SSP_REGS_SIZE	512
+
+/* DSP Shim registers */
+
+#define CATPT_SHIM_CS1		0x0
+#define CATPT_SHIM_ISC		0x18
+#define CATPT_SHIM_ISD		0x20
+#define CATPT_SHIM_IMC		0x28
+#define CATPT_SHIM_IMD		0x30
+#define CATPT_SHIM_IPCC		0x38
+#define CATPT_SHIM_IPCD		0x40
+#define CATPT_SHIM_CLKCTL	0x78
+#define CATPT_SHIM_CS2		0x80
+#define CATPT_SHIM_LTRC		0xE0
+#define CATPT_SHIM_HMDC		0xE8
+
+#define CATPT_CS_LPCS		BIT(31)
+#define CATPT_CS_SFCR(ssp)	BIT(27 + ssp)
+#define CATPT_CS_S1IOCS		BIT(23)
+#define CATPT_CS_S0IOCS		BIT(21)
+#define CATPT_CS_PCE		BIT(15)
+#define CATPT_CS_SDPM(ssp)	BIT(11 + ssp)
+#define CATPT_CS_STALL		BIT(10)
+#define CATPT_CS_DCS		GENMASK(6, 4)
+/* b100 DSP core & audio fabric high clock */
+#define CATPT_CS_DCS_HIGH	(0x4 << 4)
+#define CATPT_CS_SBCS(ssp)	BIT(2 + ssp)
+#define CATPT_CS_RST		BIT(1)
+
+#define CATPT_ISC_IPCDB		BIT(1)
+#define CATPT_ISC_IPCCD		BIT(0)
+#define CATPT_ISD_DCPWM		BIT(31)
+#define CATPT_ISD_IPCCB		BIT(1)
+#define CATPT_ISD_IPCDD		BIT(0)
+
+#define CATPT_IMC_IPCDB		BIT(1)
+#define CATPT_IMC_IPCCD		BIT(0)
+#define CATPT_IMD_IPCCB		BIT(1)
+#define CATPT_IMD_IPCDD		BIT(0)
+
+#define CATPT_IPCC_BUSY		BIT(31)
+#define CATPT_IPCC_DONE		BIT(30)
+#define CATPT_IPCD_BUSY		BIT(31)
+#define CATPT_IPCD_DONE		BIT(30)
+
+#define CATPT_CLKCTL_CFCIP	BIT(31)
+#define CATPT_CLKCTL_SMOS	GENMASK(25, 24)
+
+#define CATPT_HMDC_HDDA(e, ch)	BIT(8 * e + ch)
+
+#define CATPT_CS_DEFAULT	0x8480040E
+#define CATPT_ISC_DEFAULT	0x0
+#define CATPT_ISD_DEFAULT	0x0
+#define CATPT_IMC_DEFAULT	0x7FFF0003
+#define CATPT_IMD_DEFAULT	0x7FFF0003
+#define CATPT_IPCC_DEFAULT	0x0
+#define CATPT_IPCD_DEFAULT	0x0
+#define CATPT_CLKCTL_DEFAULT	0x7FF
+#define CATPT_CS2_DEFAULT	0x0
+#define CATPT_LTRC_DEFAULT	0x0
+#define CATPT_HMDC_DEFAULT	0x0
+
+/* PCI Configuration registers */
+
+#define CATPT_PCI_PMCS		0x84
+#define CATPT_PCI_VDRTCTL0	0xA0
+#define CATPT_PCI_VDRTCTL2	0xA8
+
+#define CATPT_PMCS_PS		GENMASK(1, 0)
+#define CATPT_PMCS_PS_D3HOT	(0x3 << 0)
+
+#define CATPT_VDRTCTL2_DTCGE	BIT(10)
+#define CATPT_VDRTCTL2_DCLCGE	BIT(1)
+#define CATPT_VDRTCTL2_CGEALL	0xF7F
+
+/* LPT PCI Configuration bits */
+
+#define LPT_VDRTCTL0_DSRAMPGE(b)	BIT(16 + b)
+#define LPT_VDRTCTL0_DSRAMPGE_MASK	GENMASK(31, 16)
+#define LPT_VDRTCTL0_ISRAMPGE(b)	BIT(6 + b)
+#define LPT_VDRTCTL0_ISRAMPGE_MASK	GENMASK(15, 6)
+#define LPT_VDRTCTL0_D3SRAMPGD		BIT(2)
+#define LPT_VDRTCTL0_D3PGD		BIT(1)
+#define LPT_VDRTCTL0_APLLSE		BIT(0)
+
+/* WPT PCI Configuration bits */
+
+#define WPT_VDRTCTL0_DSRAMPGE(b)	BIT(12 + b)
+#define WPT_VDRTCTL0_DSRAMPGE_MASK	GENMASK(31, 12)
+#define WPT_VDRTCTL0_ISRAMPGE(b)	BIT(2 + b)
+#define WPT_VDRTCTL0_ISRAMPGE_MASK	GENMASK(11, 2)
+#define WPT_VDRTCTL0_D3SRAMPGD		BIT(1)
+#define WPT_VDRTCTL0_D3PGD		BIT(0)
+
+#define WPT_VDRTCTL2_APLLSE		BIT(31)
+
+/* SSP Interface registers */
+
+#define CATPT_SSP_SSC0		0x0
+#define CATPT_SSP_SSC1		0x4
+#define CATPT_SSP_SSS		0x8
+#define CATPT_SSP_SSIT		0xC
+#define CATPT_SSP_SSD		0x10
+#define CATPT_SSP_SSTO		0x28
+#define CATPT_SSP_SSPSP		0x2C
+#define CATPT_SSP_SSTSA		0x30
+#define CATPT_SSP_SSRSA		0x34
+#define CATPT_SSP_SSTSS		0x38
+#define CATPT_SSP_SSC2		0x40
+#define CATPT_SSP_SSPSP2	0x44
+
+#define CATPT_SSP_SSC0_DEFAULT		0x0
+#define CATPT_SSP_SSC1_DEFAULT		0x0
+#define CATPT_SSP_SSS_DEFAULT		0xF004
+#define CATPT_SSP_SSIT_DEFAULT		0x0
+#define CATPT_SSP_SSD_DEFAULT		0xC43893A3
+#define CATPT_SSP_SSTO_DEFAULT		0x0
+#define CATPT_SSP_SSPSP_DEFAULT		0x0
+#define CATPT_SSP_SSTSA_DEFAULT		0x0
+#define CATPT_SSP_SSRSA_DEFAULT		0x0
+#define CATPT_SSP_SSTSS_DEFAULT		0x0
+#define CATPT_SSP_SSC2_DEFAULT		0x0
+#define CATPT_SSP_SSPSP2_DEFAULT	0x0
+
+/* Physically the same block, access address differs between host and dsp */
+#define CATPT_DSP_DRAM_OFFSET		0x400000
+#define catpt_to_host_offset(offset)	(offset & ~(CATPT_DSP_DRAM_OFFSET))
+#define catpt_to_dsp_offset(offset)	(offset | CATPT_DSP_DRAM_OFFSET)
+
+#define CATPT_MEMBLOCK_SIZE	0x8000
+#define catpt_num_dram(cdev)	(hweight_long((cdev)->spec->dram_mask))
+#define catpt_num_iram(cdev)	(hweight_long((cdev)->spec->iram_mask))
+#define catpt_dram_size(cdev)	(catpt_num_dram(cdev) * CATPT_MEMBLOCK_SIZE)
+#define catpt_iram_size(cdev)	(catpt_num_iram(cdev) * CATPT_MEMBLOCK_SIZE)
+
+/* registry I/O helpers */
+
+#define catpt_shim_addr(cdev) \
+	((cdev)->lpe_ba + (cdev)->spec->host_shim_offset)
+#define catpt_dma_addr(cdev, dma) \
+	((cdev)->lpe_ba + (cdev)->spec->host_dma_offset[dma])
+#define catpt_ssp_addr(cdev, ssp) \
+	((cdev)->lpe_ba + (cdev)->spec->host_ssp_offset[ssp])
+#define catpt_inbox_addr(cdev) \
+	((cdev)->lpe_ba + (cdev)->ipc.config.inbox_offset)
+#define catpt_outbox_addr(cdev) \
+	((cdev)->lpe_ba + (cdev)->ipc.config.outbox_offset)
+
+#define catpt_writel_ssp(cdev, ssp, reg, val) \
+	writel(val, catpt_ssp_addr(cdev, ssp) + CATPT_SSP_##reg)
+
+#define catpt_readl_shim(cdev, reg) \
+	readl(catpt_shim_addr(cdev) + CATPT_SHIM_##reg)
+#define catpt_writel_shim(cdev, reg, val) \
+	writel(val, catpt_shim_addr(cdev) + CATPT_SHIM_##reg)
+#define catpt_updatel_shim(cdev, reg, mask, val) \
+	catpt_writel_shim(cdev, reg, \
+			(catpt_readl_shim(cdev, reg) & ~(mask)) | val)
+
+#define catpt_readl_poll_shim(cdev, reg, val, cond, delay_us, timeout_us) \
+	readl_poll_timeout(catpt_shim_addr(cdev) + CATPT_SHIM_##reg, \
+			   val, cond, delay_us, timeout_us)
+
+#define catpt_readl_pci(cdev, reg) \
+	readl(cdev->pci_ba + CATPT_PCI_##reg)
+#define catpt_writel_pci(cdev, reg, val) \
+	writel(val, cdev->pci_ba + CATPT_PCI_##reg)
+#define catpt_updatel_pci(cdev, reg, mask, val) \
+	catpt_writel_pci(cdev, reg, \
+			(catpt_readl_pci(cdev, reg) & ~(mask)) | val)
+
+#define catpt_readl_poll_pci(cdev, reg, val, cond, delay_us, timeout_us) \
+	readl_poll_timeout((cdev)->pci_ba + CATPT_PCI_##reg, \
+			   val, cond, delay_us, timeout_us)
+
+#endif
-- 
2.17.1


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

* [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
  2020-08-12 20:57 ` [PATCH v4 01/13] ASoC: Intel: Add catpt device Cezary Rojewski
@ 2020-08-12 20:57 ` Cezary Rojewski
  2020-08-13 18:51   ` Andy Shevchenko
  2020-08-12 20:57 ` [PATCH v4 03/13] ASoC: Intel: catpt: Firmware loading and context restore Cezary Rojewski
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-12 20:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: pierre-louis.bossart, Cezary Rojewski, andriy.shevchenko,
	filip.kaczmarski, harshapriya.n, marcin.barlik, zwisler,
	lgirdwood, tiwai, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

Implement dsp lifecycle functions such as core RESET and STALL,
SRAM power control and LP clock selection. This also adds functions for
handling transport over DW DMA controller.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/catpt/dsp.c | 497 ++++++++++++++++++++++++++++++++++++
 1 file changed, 497 insertions(+)
 create mode 100644 sound/soc/intel/catpt/dsp.c

diff --git a/sound/soc/intel/catpt/dsp.c b/sound/soc/intel/catpt/dsp.c
new file mode 100644
index 000000000000..1474e2e11672
--- /dev/null
+++ b/sound/soc/intel/catpt/dsp.c
@@ -0,0 +1,497 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2020 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/dma-mapping.h>
+#include <linux/acpi_dma.h>
+#include <linux/firmware.h>
+#include "core.h"
+#include "messages.h"
+#include "registers.h"
+#include "trace.h"
+
+static void catpt_dma_transfer_complete(void *arg)
+{
+	struct catpt_dev *cdev = arg;
+
+	dev_dbg(cdev->dev, "%s\n", __func__);
+}
+
+static bool catpt_dma_filter(struct dma_chan *chan, void *param)
+{
+	return chan->device->dev == (struct device *)param;
+}
+
+#define CATPT_DMA_DEVID		1 /* dma engine used */
+#define CATPT_DMA_MAXBURST	0x3
+#define CATPT_DMA_DSP_ADDR_MASK	0xFFF00000
+
+struct dma_chan *catpt_dma_request_config_chan(struct catpt_dev *cdev)
+{
+	struct dma_slave_config config;
+	struct dma_chan *chan;
+	dma_cap_mask_t mask;
+	int ret;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	dma_cap_set(DMA_MEMCPY, mask);
+
+	chan = dma_request_channel(mask, catpt_dma_filter, cdev->dev);
+	if (!chan) {
+		dev_err(cdev->dev, "request channel failed\n");
+		dump_stack();
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	memset(&config, 0, sizeof(config));
+	config.direction = DMA_MEM_TO_DEV;
+	config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	config.src_maxburst = CATPT_DMA_MAXBURST;
+	config.dst_maxburst = CATPT_DMA_MAXBURST;
+
+	ret = dmaengine_slave_config(chan, &config);
+	if (ret) {
+		dev_err(cdev->dev, "slave config failed: %d\n", ret);
+		dma_release_channel(chan);
+		return ERR_PTR(ret);
+	}
+
+	return chan;
+}
+
+static int catpt_dma_memcpy(struct catpt_dev *cdev, struct dma_chan *chan,
+			    dma_addr_t dst_addr, dma_addr_t src_addr,
+			    size_t size)
+{
+	struct dma_async_tx_descriptor *desc;
+	enum dma_status status;
+
+	desc = dmaengine_prep_dma_memcpy(chan, dst_addr, src_addr, size,
+					 DMA_CTRL_ACK);
+	if (!desc) {
+		dev_err(cdev->dev, "prep dma memcpy failed\n");
+		return -EIO;
+	}
+
+	/* enable demand mode for dma channel */
+	catpt_updatel_shim(cdev, HMDC,
+			   CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id),
+			   CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id));
+	desc->callback = catpt_dma_transfer_complete;
+	desc->callback_param = cdev;
+	dmaengine_submit(desc);
+
+	status = dma_wait_for_async_tx(desc);
+	catpt_updatel_shim(cdev, HMDC,
+			   CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id), 0);
+
+	return (status == DMA_COMPLETE) ? 0 : -EPROTO;
+}
+
+int catpt_dma_memcpy_todsp(struct catpt_dev *cdev, struct dma_chan *chan,
+			   dma_addr_t dst_addr, dma_addr_t src_addr,
+			   size_t size)
+{
+	return catpt_dma_memcpy(cdev, chan, dst_addr | CATPT_DMA_DSP_ADDR_MASK,
+				src_addr, size);
+}
+
+int catpt_dma_memcpy_fromdsp(struct catpt_dev *cdev, struct dma_chan *chan,
+			     dma_addr_t dst_addr, dma_addr_t src_addr,
+			     size_t size)
+{
+	return catpt_dma_memcpy(cdev, chan, dst_addr,
+				src_addr | CATPT_DMA_DSP_ADDR_MASK, size);
+}
+
+int catpt_dmac_probe(struct catpt_dev *cdev)
+{
+	struct dw_dma_chip *dmac;
+	struct resource res;
+	int ret;
+
+	dmac = devm_kzalloc(cdev->dev, sizeof(*dmac), GFP_KERNEL);
+	if (!dmac)
+		return -ENOMEM;
+
+	memset(&res, 0, sizeof(res));
+	res.start = cdev->lpe_base +
+		    cdev->spec->host_dma_offset[CATPT_DMA_DEVID];
+	res.end = res.start + (CATPT_DMA_REGS_SIZE - 1);
+	res.flags = IORESOURCE_MEM;
+	dmac->dev = cdev->dev;
+	dmac->irq = cdev->irq;
+
+	dmac->regs = devm_ioremap_resource(cdev->dev, &res);
+	if (IS_ERR(dmac->regs))
+		return PTR_ERR(dmac->regs);
+
+	ret = dma_coerce_mask_and_coherent(cdev->dev, DMA_BIT_MASK(31));
+	if (ret < 0)
+		return ret;
+	/*
+	 * Caller is responsible for putting device in D0 to allow
+	 * for I/O and memory access before probing DW
+	 */
+	ret = dw_dma_probe(dmac);
+	if (ret < 0)
+		return ret;
+
+	cdev->dmac = dmac;
+	return 0;
+}
+
+void catpt_dmac_remove(struct catpt_dev *cdev)
+{
+	/*
+	 * As do_dma_remove() juggles with pm_runtime_get_xxx() and
+	 * pm_runtime_put_xxx() while both ADSP and DW 'devices' are part of
+	 * the same module, caller makes sure pm_runtime_disable() is invoked
+	 * before removing DW to prevent postmortem resume and suspend
+	 */
+	dw_dma_remove(cdev->dmac);
+}
+
+static void catpt_dsp_set_srampge(struct catpt_dev *cdev, struct resource *sram,
+				  unsigned long mask, unsigned long new)
+{
+	unsigned long old;
+	u32 off = sram->start;
+	u32 b = __ffs(mask);
+
+	old = catpt_readl_pci(cdev, VDRTCTL0) & mask;
+	dev_dbg(cdev->dev, "SRAMPGE [0x%08lx] 0x%08lx -> 0x%08lx",
+		mask, old, new);
+
+	if (old == new)
+		return;
+
+	catpt_updatel_pci(cdev, VDRTCTL0, mask, new);
+	udelay(60);
+
+	/*
+	 * dummy read as the very first access after block enable
+	 * to prevent byte loss in future operations
+	 */
+	for_each_clear_bit_from(b, &new, fls(mask)) {
+		u8 buf[4];
+
+		/* newly enabled: new bit=0 while old bit=1 */
+		if (test_bit(b, &old)) {
+			dev_dbg(cdev->dev, "sanitize block %ld: off 0x%08x\n",
+				(b - __ffs(mask)), off);
+			memcpy_fromio(buf, cdev->lpe_ba + off, sizeof(buf));
+		}
+		off += CATPT_MEMBLOCK_SIZE;
+	}
+}
+
+void catpt_dsp_update_srampge(struct catpt_dev *cdev, struct resource *sram,
+			      unsigned long mask)
+{
+	struct resource *res;
+	unsigned long new = 0;
+
+	/* flag all busy blocks */
+	for (res = sram->child; res; res = res->sibling) {
+		u32 h, l;
+
+		h = (res->end - sram->start) / CATPT_MEMBLOCK_SIZE;
+		l = (res->start - sram->start) / CATPT_MEMBLOCK_SIZE;
+		new |= GENMASK(h, l);
+	}
+
+	/* offset value given mask's start and invert it as ON=b0 */
+	new <<= __ffs(mask);
+	new = ~(new) & mask;
+
+	/* disable core clock gating */
+	catpt_updatel_pci(cdev, VDRTCTL2, CATPT_VDRTCTL2_DCLCGE, 0);
+
+	catpt_dsp_set_srampge(cdev, sram, mask, new);
+
+	/* enable core clock gating */
+	catpt_updatel_pci(cdev, VDRTCTL2, CATPT_VDRTCTL2_DCLCGE,
+			  CATPT_VDRTCTL2_DCLCGE);
+}
+
+int catpt_dsp_stall(struct catpt_dev *cdev, bool stall)
+{
+	u32 reg, val;
+
+	val = stall ? CATPT_CS_STALL : 0;
+	catpt_updatel_shim(cdev, CS1, CATPT_CS_STALL, val);
+
+	return catpt_readl_poll_shim(cdev, CS1,
+				     reg, (reg & CATPT_CS_STALL) == val,
+				     500, 10000);
+}
+
+static int catpt_dsp_reset(struct catpt_dev *cdev, bool reset)
+{
+	u32 reg, val;
+
+	val = reset ? CATPT_CS_RST : 0;
+	catpt_updatel_shim(cdev, CS1, CATPT_CS_RST, val);
+
+	return catpt_readl_poll_shim(cdev, CS1,
+				     reg, (reg & CATPT_CS_RST) == val,
+				     500, 10000);
+}
+
+void lpt_dsp_pll_shutdown(struct catpt_dev *cdev, bool enable)
+{
+	u32 val;
+
+	val = enable ? LPT_VDRTCTL0_APLLSE : 0;
+	catpt_updatel_pci(cdev, VDRTCTL0, LPT_VDRTCTL0_APLLSE, val);
+}
+
+void wpt_dsp_pll_shutdown(struct catpt_dev *cdev, bool enable)
+{
+	u32 val;
+
+	val = enable ? WPT_VDRTCTL2_APLLSE : 0;
+	catpt_updatel_pci(cdev, VDRTCTL2, WPT_VDRTCTL2_APLLSE, val);
+}
+
+static int catpt_dsp_select_lpclock(struct catpt_dev *cdev, bool lp, bool waiti)
+{
+	u32 mask, reg, val;
+	int ret;
+
+	mutex_lock(&cdev->clk_mutex);
+
+	val = lp ? CATPT_CS_LPCS : 0;
+	reg = catpt_readl_shim(cdev, CS1) & CATPT_CS_LPCS;
+	dev_dbg(cdev->dev, "LPCS [0x%08lx] 0x%08x -> 0x%08x",
+		CATPT_CS_LPCS, reg, val);
+
+	if (reg == val) {
+		mutex_unlock(&cdev->clk_mutex);
+		return 0;
+	}
+
+	if (waiti) {
+		/* wait for DSP to signal WAIT state */
+		ret = catpt_readl_poll_shim(cdev, ISD,
+					    reg, (reg & CATPT_ISD_DCPWM),
+					    500, 10000);
+		if (ret < 0) {
+			dev_warn(cdev->dev, "await WAITI timeout\n");
+			mutex_unlock(&cdev->clk_mutex);
+			return ret;
+		}
+	}
+
+	ret = catpt_readl_poll_shim(cdev, CLKCTL,
+				    reg, !(reg & CATPT_CLKCTL_CFCIP),
+				    500, 10000);
+	if (ret < 0)
+		dev_warn(cdev->dev, "clock change still in progress\n");
+
+	/* default to DSP core & audio fabric high clock */
+	val |= CATPT_CS_DCS_HIGH;
+	mask = CATPT_CS_LPCS | CATPT_CS_DCS;
+	catpt_updatel_shim(cdev, CS1, mask, val);
+
+	ret = catpt_readl_poll_shim(cdev, CLKCTL,
+				    reg, !(reg & CATPT_CLKCTL_CFCIP),
+				    500, 10000);
+	if (ret < 0)
+		dev_warn(cdev->dev, "clock change still in progress\n");
+
+	/* update PLL accordingly */
+	cdev->spec->pll_shutdown(cdev, lp);
+
+	mutex_unlock(&cdev->clk_mutex);
+	return 0;
+}
+
+int catpt_dsp_update_lpclock(struct catpt_dev *cdev)
+{
+	struct catpt_stream_runtime *stream;
+	bool lp;
+
+	if (list_empty(&cdev->stream_list))
+		return catpt_dsp_select_lpclock(cdev, true, true);
+
+	lp = true;
+	list_for_each_entry(stream, &cdev->stream_list, node) {
+		if (stream->prepared) {
+			lp = false;
+			break;
+		}
+	}
+
+	return catpt_dsp_select_lpclock(cdev, lp, true);
+}
+
+/* bring registers to their defaults as HW won't reset itself */
+static void catpt_dsp_set_regs_defaults(struct catpt_dev *cdev)
+{
+	int i;
+
+	catpt_writel_shim(cdev, CS1, CATPT_CS_DEFAULT);
+	catpt_writel_shim(cdev, ISC, CATPT_ISC_DEFAULT);
+	catpt_writel_shim(cdev, ISD, CATPT_ISD_DEFAULT);
+	catpt_writel_shim(cdev, IMC, CATPT_IMC_DEFAULT);
+	catpt_writel_shim(cdev, IMD, CATPT_IMD_DEFAULT);
+	catpt_writel_shim(cdev, IPCC, CATPT_IPCC_DEFAULT);
+	catpt_writel_shim(cdev, IPCD, CATPT_IPCD_DEFAULT);
+	catpt_writel_shim(cdev, CLKCTL, CATPT_CLKCTL_DEFAULT);
+	catpt_writel_shim(cdev, CS2, CATPT_CS2_DEFAULT);
+	catpt_writel_shim(cdev, LTRC, CATPT_LTRC_DEFAULT);
+	catpt_writel_shim(cdev, HMDC, CATPT_HMDC_DEFAULT);
+
+	for (i = 0; i < CATPT_SSP_COUNT; i++) {
+		catpt_writel_ssp(cdev, i, SSC0, CATPT_SSP_SSC0_DEFAULT);
+		catpt_writel_ssp(cdev, i, SSC1, CATPT_SSP_SSC1_DEFAULT);
+		catpt_writel_ssp(cdev, i, SSS, CATPT_SSP_SSS_DEFAULT);
+		catpt_writel_ssp(cdev, i, SSIT, CATPT_SSP_SSIT_DEFAULT);
+		catpt_writel_ssp(cdev, i, SSD, CATPT_SSP_SSD_DEFAULT);
+		catpt_writel_ssp(cdev, i, SSTO, CATPT_SSP_SSTO_DEFAULT);
+		catpt_writel_ssp(cdev, i, SSPSP, CATPT_SSP_SSPSP_DEFAULT);
+		catpt_writel_ssp(cdev, i, SSTSA, CATPT_SSP_SSTSA_DEFAULT);
+		catpt_writel_ssp(cdev, i, SSRSA, CATPT_SSP_SSRSA_DEFAULT);
+		catpt_writel_ssp(cdev, i, SSTSS, CATPT_SSP_SSTSS_DEFAULT);
+		catpt_writel_ssp(cdev, i, SSC2, CATPT_SSP_SSC2_DEFAULT);
+		catpt_writel_ssp(cdev, i, SSPSP2, CATPT_SSP_SSPSP2_DEFAULT);
+	}
+}
+
+int lpt_dsp_power_down(struct catpt_dev *cdev)
+{
+	catpt_dsp_reset(cdev, true);
+
+	/* set 24Mhz clock for both SSPs */
+	catpt_updatel_shim(cdev, CS1, CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1),
+			   CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1));
+	catpt_dsp_select_lpclock(cdev, true, false);
+
+	/* DRAM power gating all */
+	catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask,
+			      cdev->spec->dram_mask);
+	catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask,
+			      cdev->spec->iram_mask);
+
+	/* set D3 */
+	catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, CATPT_PMCS_PS_D3HOT);
+	udelay(50);
+
+	return 0;
+}
+
+int lpt_dsp_power_up(struct catpt_dev *cdev)
+{
+	/* SRAM power gating none */
+	catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask, 0);
+	catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask, 0);
+
+	/* set D0 */
+	catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, 0);
+	udelay(100);
+
+	catpt_dsp_select_lpclock(cdev, false, false);
+	catpt_updatel_shim(cdev, CS1,
+			CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1),
+			CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1));
+	udelay(50);
+
+	catpt_dsp_reset(cdev, false);
+	/* generate int deassert msg to fix inversed int logic */
+	catpt_updatel_shim(cdev, IMC, CATPT_IMC_IPCDB | CATPT_IMC_IPCCD, 0);
+
+	return 0;
+}
+
+int wpt_dsp_power_down(struct catpt_dev *cdev)
+{
+	u32 mask, val;
+
+	/* disable core clock gating */
+	catpt_updatel_pci(cdev, VDRTCTL2, CATPT_VDRTCTL2_DCLCGE, 0);
+
+	catpt_dsp_reset(cdev, true);
+	/* set 24Mhz clock for both SSPs */
+	catpt_updatel_shim(cdev, CS1, CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1),
+			   CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1));
+	catpt_dsp_select_lpclock(cdev, true, false);
+	/* disable MCLK */
+	catpt_updatel_shim(cdev, CLKCTL, CATPT_CLKCTL_SMOS, 0);
+
+	catpt_dsp_set_regs_defaults(cdev);
+
+	/* switch clock gating */
+	mask = CATPT_VDRTCTL2_CGEALL & (~CATPT_VDRTCTL2_DCLCGE);
+	val = mask & (~CATPT_VDRTCTL2_DTCGE);
+	catpt_updatel_pci(cdev, VDRTCTL2, mask, val);
+	/* enable DTCGE separatelly */
+	catpt_updatel_pci(cdev, VDRTCTL2, CATPT_VDRTCTL2_DTCGE,
+			  CATPT_VDRTCTL2_DTCGE);
+
+	/* SRAM power gating all */
+	catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask,
+			      cdev->spec->dram_mask);
+	catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask,
+			      cdev->spec->iram_mask);
+	mask = WPT_VDRTCTL0_D3SRAMPGD | WPT_VDRTCTL0_D3PGD;
+	catpt_updatel_pci(cdev, VDRTCTL0, mask, WPT_VDRTCTL0_D3PGD);
+
+	/* set D3 */
+	catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, CATPT_PMCS_PS_D3HOT);
+	udelay(50);
+
+	/* enable core clock gating */
+	catpt_updatel_pci(cdev, VDRTCTL2, CATPT_VDRTCTL2_DCLCGE,
+			  CATPT_VDRTCTL2_DCLCGE);
+	udelay(50);
+
+	return 0;
+}
+
+int wpt_dsp_power_up(struct catpt_dev *cdev)
+{
+	u32 mask, val;
+
+	/* disable core clock gating */
+	catpt_updatel_pci(cdev, VDRTCTL2, CATPT_VDRTCTL2_DCLCGE, 0);
+
+	/* switch clock gating */
+	mask = CATPT_VDRTCTL2_CGEALL & (~CATPT_VDRTCTL2_DCLCGE);
+	val = mask & (~CATPT_VDRTCTL2_DTCGE);
+	catpt_updatel_pci(cdev, VDRTCTL2, mask, val);
+
+	/* set D0 */
+	catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, 0);
+
+	/* SRAM power gating none */
+	mask = WPT_VDRTCTL0_D3SRAMPGD | WPT_VDRTCTL0_D3PGD;
+	catpt_updatel_pci(cdev, VDRTCTL0, mask, mask);
+	catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask, 0);
+	catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask, 0);
+
+	catpt_dsp_set_regs_defaults(cdev);
+
+	/* restore MCLK */
+	catpt_updatel_shim(cdev, CLKCTL, CATPT_CLKCTL_SMOS, CATPT_CLKCTL_SMOS);
+	catpt_dsp_select_lpclock(cdev, false, false);
+	/* set 24Mhz clock for both SSPs */
+	catpt_updatel_shim(cdev, CS1, CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1),
+			   CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1));
+	catpt_dsp_reset(cdev, false);
+
+	/* enable core clock gating */
+	catpt_updatel_pci(cdev, VDRTCTL2, CATPT_VDRTCTL2_DCLCGE,
+			  CATPT_VDRTCTL2_DCLCGE);
+
+	/* generate int deassert msg to fix inversed int logic */
+	catpt_updatel_shim(cdev, IMC, CATPT_IMC_IPCDB | CATPT_IMC_IPCCD, 0);
+
+	return 0;
+}
-- 
2.17.1


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

* [PATCH v4 03/13] ASoC: Intel: catpt: Firmware loading and context restore
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
  2020-08-12 20:57 ` [PATCH v4 01/13] ASoC: Intel: Add catpt device Cezary Rojewski
  2020-08-12 20:57 ` [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations Cezary Rojewski
@ 2020-08-12 20:57 ` Cezary Rojewski
  2020-08-12 20:57 ` [PATCH v4 04/13] ASoC: Intel: catpt: Implement IPC protocol Cezary Rojewski
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-12 20:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: pierre-louis.bossart, Cezary Rojewski, andriy.shevchenko,
	filip.kaczmarski, harshapriya.n, marcin.barlik, zwisler,
	lgirdwood, tiwai, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

For Lynxpoint and Wildcat Point solution, is it host's responsibility to
allocate SRAM regions and ensure those already taken are not overwritten
with other data until released. Blocks are transferred to SRAM - either
IRAM or DRAM - via DW DMA controller. Once basefw is booted, ownership
of DMA transfer is lost in favour of DSP.

Hosts reponsibilities don't end on initial block allocation and binary
transfer. During Dx transitions host must store FW runtime context from
DRAM before putting AudioDSP subsystem into lower power state. Said
context gets flashed after D0 entry to bring DSP right where it was just
before suspending.

Load and restore procedures are finalized with SRAM power gating and
adequate clock level selection. This power gates unused EBBs and clock
speed effectively reducing power consumption.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/catpt/loader.c | 673 +++++++++++++++++++++++++++++++++
 1 file changed, 673 insertions(+)
 create mode 100644 sound/soc/intel/catpt/loader.c

diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c
new file mode 100644
index 000000000000..21559ba9f30b
--- /dev/null
+++ b/sound/soc/intel/catpt/loader.c
@@ -0,0 +1,673 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2020 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include "core.h"
+#include "registers.h"
+#include "trace.h"
+
+/* FW load (200ms) plus operational delays */
+#define FW_READY_TIMEOUT_MSECS	250
+
+#define FW_SIGNATURE	"$SST"
+#define FW_SIGNATURE_SIZE 4
+
+/* some nice binary layout picture here */
+
+struct catpt_fw_hdr {
+	char signature[FW_SIGNATURE_SIZE];
+	u32 file_size;
+	u32 modules;
+	u32 file_format;
+	u32 reserved[4];
+} __packed;
+
+struct catpt_fw_mod_hdr {
+	char signature[FW_SIGNATURE_SIZE];
+	u32 mod_size;
+	u32 blocks;
+	u16 slot;
+	enum catpt_module_id id:16;
+	u32 entry_point;
+	u32 persistent_size;
+	u32 scratch_size;
+} __packed;
+
+enum catpt_ram_type {
+	CATPT_RAM_TYPE_IRAM = 1,
+	CATPT_RAM_TYPE_DRAM = 2,
+	/* DRAM with module's initial state */
+	CATPT_RAM_TYPE_INSTANCE = 3,
+};
+
+struct catpt_fw_block_hdr {
+	enum catpt_ram_type type __aligned(4);
+	u32 size;
+	u32 ram_offset;
+	u32 rsvd;
+} __packed;
+
+void catpt_sram_init(struct resource *sram, u32 start, u32 size)
+{
+	sram->start = start;
+	sram->end = start + size - 1;
+}
+
+void catpt_sram_free(struct resource *sram)
+{
+	struct resource *res, *save;
+
+	for (res = sram->child; res;) {
+		save = res->sibling;
+		release_resource(res);
+		kfree(res);
+		res = save;
+	}
+}
+
+struct resource *
+catpt_request_region(struct resource *root, resource_size_t size)
+{
+	struct resource *res = root->child;
+	resource_size_t addr = root->start;
+
+	for (;;) {
+		if (res->start - addr >= size)
+			break;
+		addr = res->end + 1;
+		res = res->sibling;
+		if (!res)
+			return NULL;
+	}
+
+	return __request_region(root, addr, size, NULL, 0);
+}
+
+int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan)
+{
+	struct catpt_stream_runtime *stream;
+
+	list_for_each_entry(stream, &cdev->stream_list, node) {
+		u32 off, size;
+		int ret;
+
+		off = stream->persistent->start;
+		size = resource_size(stream->persistent);
+		dev_dbg(cdev->dev, "storing stream %d ctx: off 0x%08x size %d\n",
+			stream->info.stream_hw_id, off, size);
+
+		ret = catpt_dma_memcpy_fromdsp(cdev, chan,
+					       cdev->dxbuf_paddr + off,
+					       cdev->lpe_base + off,
+					       ALIGN(size, 4));
+		if (ret < 0) {
+			dev_err(cdev->dev, "memcpy fromdsp failed: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cdev->modules); i++) {
+		struct catpt_module_type *type;
+		u32 off;
+		int ret;
+
+		type = &cdev->modules[i];
+		if (!type->loaded || !type->state_size)
+			continue;
+
+		off = type->state_offset;
+		dev_dbg(cdev->dev, "storing mod %d state: off 0x%08x size %d\n",
+			i, off, type->state_size);
+
+		ret = catpt_dma_memcpy_fromdsp(cdev, chan,
+					       cdev->dxbuf_paddr + off,
+					       cdev->lpe_base + off,
+					       ALIGN(type->state_size, 4));
+		if (ret < 0) {
+			dev_err(cdev->dev, "memcpy fromdsp failed: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan)
+{
+	int i;
+
+	for (i = 0; i < cdev->dx_ctx.num_meminfo; i++) {
+		struct catpt_save_meminfo *info;
+		u32 off;
+		int ret;
+
+		info = &cdev->dx_ctx.meminfo[i];
+		if (info->source != CATPT_DX_TYPE_MEMORY_DUMP)
+			continue;
+
+		off = catpt_to_host_offset(info->offset);
+		if (off < cdev->dram.start || off > cdev->dram.end)
+			continue;
+
+		dev_dbg(cdev->dev, "storing memdump: off 0x%08x size %d\n",
+			off, info->size);
+
+		ret = catpt_dma_memcpy_fromdsp(cdev, chan,
+					       cdev->dxbuf_paddr + off,
+					       cdev->lpe_base + off,
+					       ALIGN(info->size, 4));
+		if (ret < 0) {
+			dev_err(cdev->dev, "memcpy fromdsp failed: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int
+catpt_restore_streams_context(struct catpt_dev *cdev, struct dma_chan *chan)
+{
+	struct catpt_stream_runtime *stream;
+
+	list_for_each_entry(stream, &cdev->stream_list, node) {
+		u32 off, size;
+		int ret;
+
+		off = stream->persistent->start;
+		size = resource_size(stream->persistent);
+		dev_dbg(cdev->dev, "restoring stream %d ctx: off 0x%08x size %d\n",
+			stream->info.stream_hw_id, off, size);
+
+		ret = catpt_dma_memcpy_todsp(cdev, chan,
+					     cdev->lpe_base + off,
+					     cdev->dxbuf_paddr + off,
+					     ALIGN(size, 4));
+		if (ret < 0) {
+			dev_err(cdev->dev, "memcpy fromdsp failed: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int catpt_restore_memdumps(struct catpt_dev *cdev, struct dma_chan *chan)
+{
+	int i;
+
+	for (i = 0; i < cdev->dx_ctx.num_meminfo; i++) {
+		struct catpt_save_meminfo *info;
+		u32 off;
+		int ret;
+
+		info = &cdev->dx_ctx.meminfo[i];
+		if (info->source != CATPT_DX_TYPE_MEMORY_DUMP)
+			continue;
+
+		off = catpt_to_host_offset(info->offset);
+		if (off < cdev->dram.start || off > cdev->dram.end)
+			continue;
+
+		dev_dbg(cdev->dev, "restoring memdump: off 0x%08x size %d\n",
+			off, info->size);
+
+		ret = catpt_dma_memcpy_todsp(cdev, chan,
+					     cdev->lpe_base + off,
+					     cdev->dxbuf_paddr + off,
+					     ALIGN(info->size, 4));
+		if (ret < 0) {
+			dev_err(cdev->dev, "restore block failed: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int catpt_restore_fwimage(struct catpt_dev *cdev,
+				 struct dma_chan *chan, dma_addr_t paddr,
+				 struct catpt_fw_block_hdr *blk)
+{
+	struct resource r1, r2, common;
+	int i;
+
+	print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
+			     blk, sizeof(*blk), false);
+
+	r1.start = cdev->dram.start + blk->ram_offset;
+	r1.end = r1.start + blk->size - 1;
+	/* advance to data area */
+	paddr += sizeof(*blk);
+
+	for (i = 0; i < cdev->dx_ctx.num_meminfo; i++) {
+		struct catpt_save_meminfo *info;
+		u32 off;
+		int ret;
+
+		info = &cdev->dx_ctx.meminfo[i];
+
+		if (info->source != CATPT_DX_TYPE_FW_IMAGE)
+			continue;
+
+		off = catpt_to_host_offset(info->offset);
+		if (off < cdev->dram.start || off > cdev->dram.end)
+			continue;
+
+		r2.start = off;
+		r2.end = r2.start + info->size - 1;
+
+		if (!catpt_resource_overlapping(&r2, &r1, &common))
+			continue;
+		/* calculate start offset of common data area */
+		off = common.start - r1.start;
+
+		dev_dbg(cdev->dev, "restoring fwimage: %pr\n", &common);
+
+		ret = catpt_dma_memcpy_todsp(cdev, chan, common.start,
+					     paddr + off,
+					     resource_size(&common));
+		if (ret < 0) {
+			dev_err(cdev->dev, "memcpy todsp failed: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int catpt_load_block(struct catpt_dev *cdev,
+			    struct dma_chan *chan, dma_addr_t paddr,
+			    struct catpt_fw_block_hdr *blk, bool alloc)
+{
+	struct resource *sram, *res;
+	dma_addr_t dst_addr;
+	int ret;
+
+	print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
+			     blk, sizeof(*blk), false);
+
+	switch (blk->type) {
+	case CATPT_RAM_TYPE_IRAM:
+		sram = &cdev->iram;
+		break;
+	default:
+		sram = &cdev->dram;
+		break;
+	};
+
+	dst_addr = sram->start + blk->ram_offset;
+	if (alloc) {
+		res = __request_region(sram, dst_addr, blk->size, NULL, 0);
+		if (!res)
+			return -EBUSY;
+	}
+
+	/* advance to data area */
+	paddr += sizeof(*blk);
+
+	ret = catpt_dma_memcpy_todsp(cdev, chan, dst_addr, paddr, blk->size);
+	if (ret < 0) {
+		dev_err(cdev->dev, "memcpy error: %d\n", ret);
+		__release_region(sram, dst_addr, blk->size);
+	}
+
+	return ret;
+}
+
+static int catpt_restore_basefw(struct catpt_dev *cdev,
+				struct dma_chan *chan, dma_addr_t paddr,
+				struct catpt_fw_mod_hdr *basefw)
+{
+	u32 offset = sizeof(*basefw);
+	int ret, i;
+
+	print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
+			     basefw, sizeof(*basefw), false);
+
+	/* restore basefw image */
+	for (i = 0; i < basefw->blocks; i++) {
+		struct catpt_fw_block_hdr *blk;
+
+		blk = (struct catpt_fw_block_hdr *)((u8 *)basefw + offset);
+
+		switch (blk->type) {
+		case CATPT_RAM_TYPE_IRAM:
+			ret = catpt_load_block(cdev, chan, paddr + offset,
+					       blk, false);
+			break;
+		default:
+			ret = catpt_restore_fwimage(cdev, chan, paddr + offset,
+						    blk);
+			break;
+		}
+
+		if (ret < 0) {
+			dev_err(cdev->dev, "restore block failed: %d\n", ret);
+			return ret;
+		}
+
+		offset += sizeof(*blk) + blk->size;
+	}
+
+	/* then proceed with memory dumps */
+	ret = catpt_restore_memdumps(cdev, chan);
+	if (ret < 0)
+		dev_err(cdev->dev, "restore memdumps failed: %d\n", ret);
+
+	return ret;
+}
+
+static int catpt_restore_module(struct catpt_dev *cdev,
+				struct dma_chan *chan, dma_addr_t paddr,
+				struct catpt_fw_mod_hdr *mod)
+{
+	u32 offset = sizeof(*mod);
+	int i;
+
+	print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
+			     mod, sizeof(*mod), false);
+
+	for (i = 0; i < mod->blocks; i++) {
+		struct catpt_fw_block_hdr *blk;
+		int ret;
+
+		blk = (struct catpt_fw_block_hdr *)((u8 *)mod + offset);
+
+		switch (blk->type) {
+		case CATPT_RAM_TYPE_INSTANCE:
+			/* restore module state */
+			ret = catpt_dma_memcpy_todsp(cdev, chan,
+					cdev->lpe_base + blk->ram_offset,
+					cdev->dxbuf_paddr + blk->ram_offset,
+					ALIGN(blk->size, 4));
+			break;
+		default:
+			ret = catpt_load_block(cdev, chan, paddr + offset,
+					       blk, false);
+			break;
+		}
+
+		if (ret < 0) {
+			dev_err(cdev->dev, "restore block failed: %d\n", ret);
+			return ret;
+		}
+
+		offset += sizeof(*blk) + blk->size;
+	}
+
+	return 0;
+}
+
+static int catpt_load_module(struct catpt_dev *cdev,
+			     struct dma_chan *chan, dma_addr_t paddr,
+			     struct catpt_fw_mod_hdr *mod)
+{
+	struct catpt_module_type *type;
+	u32 offset = sizeof(*mod);
+	int i;
+
+	print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
+			     mod, sizeof(*mod), false);
+
+	type = &cdev->modules[mod->id];
+
+	for (i = 0; i < mod->blocks; i++) {
+		struct catpt_fw_block_hdr *blk;
+		int ret;
+
+		blk = (struct catpt_fw_block_hdr *)((u8 *)mod + offset);
+
+		ret = catpt_load_block(cdev, chan, paddr + offset, blk, true);
+		if (ret < 0) {
+			dev_err(cdev->dev, "load block failed: %d\n", ret);
+			return ret;
+		}
+
+		/*
+		 * Save state window coordinates - these will be
+		 * used to capture module state on D0 exit
+		 */
+		if (blk->type == CATPT_RAM_TYPE_INSTANCE) {
+			type->state_offset = blk->ram_offset;
+			type->state_size = blk->size;
+		}
+
+		offset += sizeof(*blk) + blk->size;
+	}
+
+	/* init module type static info */
+	type->loaded = true;
+	/* DSP expects address from module header substracted by 4 */
+	type->entry_point = mod->entry_point - 4;
+	type->persistent_size = mod->persistent_size;
+	type->scratch_size = mod->scratch_size;
+
+	return 0;
+}
+
+static int catpt_restore_firmware(struct catpt_dev *cdev,
+				  struct dma_chan *chan, dma_addr_t paddr,
+				  struct catpt_fw_hdr *fw)
+{
+	u32 offset = sizeof(*fw);
+	int i;
+
+	print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
+			     fw, sizeof(*fw), false);
+
+	for (i = 0; i < fw->modules; i++) {
+		struct catpt_fw_mod_hdr *mod;
+		int ret;
+
+		mod = (struct catpt_fw_mod_hdr *)((u8 *)fw + offset);
+		if (strncmp(fw->signature, mod->signature,
+			    FW_SIGNATURE_SIZE)) {
+			dev_err(cdev->dev, "module signature mismatch\n");
+			return -EINVAL;
+		}
+
+		if (mod->id > CATPT_MODID_LAST)
+			return -EINVAL;
+
+		switch (mod->id) {
+		case CATPT_MODID_BASE_FW:
+			ret = catpt_restore_basefw(cdev, chan, paddr + offset,
+						   mod);
+			break;
+		default:
+			ret = catpt_restore_module(cdev, chan, paddr + offset,
+						   mod);
+			break;
+		}
+
+		if (ret < 0) {
+			dev_err(cdev->dev, "restore module failed: %d\n", ret);
+			return ret;
+		}
+
+		offset += sizeof(*mod) + mod->mod_size;
+	}
+
+	return 0;
+}
+
+static int catpt_load_firmware(struct catpt_dev *cdev,
+			       struct dma_chan *chan, dma_addr_t paddr,
+			       struct catpt_fw_hdr *fw)
+{
+	u32 offset = sizeof(*fw);
+	int i;
+
+	print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
+			     fw, sizeof(*fw), false);
+
+	for (i = 0; i < fw->modules; i++) {
+		struct catpt_fw_mod_hdr *mod;
+		int ret;
+
+		mod = (struct catpt_fw_mod_hdr *)((u8 *)fw + offset);
+		if (strncmp(fw->signature, mod->signature,
+			    FW_SIGNATURE_SIZE)) {
+			dev_err(cdev->dev, "module signature mismatch\n");
+			return -EINVAL;
+		}
+
+		if (mod->id > CATPT_MODID_LAST)
+			return -EINVAL;
+
+		ret = catpt_load_module(cdev, chan, paddr + offset, mod);
+		if (ret < 0) {
+			dev_err(cdev->dev, "load module failed: %d\n", ret);
+			return ret;
+		}
+
+		offset += sizeof(*mod) + mod->mod_size;
+	}
+
+	return 0;
+}
+
+static int catpt_load_image(struct catpt_dev *cdev, struct dma_chan *chan,
+			    const char *name, const char *signature,
+			    bool restore)
+{
+	struct catpt_fw_hdr *fw;
+	struct firmware *img;
+	dma_addr_t paddr;
+	void *vaddr;
+	int ret;
+
+	ret = request_firmware((const struct firmware **)&img, name, cdev->dev);
+	if (ret < 0)
+		return ret;
+
+	fw = (struct catpt_fw_hdr *)img->data;
+	if (strncmp(fw->signature, signature, FW_SIGNATURE_SIZE)) {
+		dev_err(cdev->dev, "firmware signature mismatch\n");
+		ret = -EINVAL;
+		goto release_fw;
+	}
+
+	vaddr = dma_alloc_coherent(cdev->dev, img->size, &paddr, GFP_KERNEL);
+	if (!vaddr) {
+		ret = -ENOMEM;
+		goto release_fw;
+	}
+
+	memcpy(vaddr, img->data, img->size);
+	fw = (struct catpt_fw_hdr *)vaddr;
+	if (restore)
+		ret = catpt_restore_firmware(cdev, chan, paddr, fw);
+	else
+		ret = catpt_load_firmware(cdev, chan, paddr, fw);
+
+	dma_free_coherent(cdev->dev, img->size, vaddr, paddr);
+release_fw:
+	release_firmware(img);
+	return ret;
+}
+
+static int catpt_load_images(struct catpt_dev *cdev, bool restore)
+{
+	static const char *const names[] = {
+		"intel/IntcSST1.bin",
+		"intel/IntcSST2.bin",
+	};
+	struct dma_chan *chan;
+	int ret;
+
+	chan = catpt_dma_request_config_chan(cdev);
+	if (IS_ERR(chan))
+		return PTR_ERR(chan);
+
+	ret = catpt_load_image(cdev, chan, names[cdev->spec->core_id - 1],
+			       FW_SIGNATURE, restore);
+	if (ret < 0)
+		goto exit;
+
+	if (!restore)
+		goto exit;
+	ret = catpt_restore_streams_context(cdev, chan);
+	if (ret < 0)
+		dev_err(cdev->dev, "restore streams ctx failed: %d\n", ret);
+exit:
+	dma_release_channel(chan);
+	return ret;
+}
+
+int catpt_boot_firmware(struct catpt_dev *cdev, bool restore)
+{
+	int ret;
+
+	catpt_dsp_stall(cdev, true);
+
+	ret = catpt_load_images(cdev, restore);
+	if (ret < 0) {
+		dev_err(cdev->dev, "load binaries failed: %d\n", ret);
+		return ret;
+	}
+
+	reinit_completion(&cdev->fw_ready);
+	catpt_dsp_stall(cdev, false);
+
+	ret = wait_for_completion_timeout(&cdev->fw_ready,
+			msecs_to_jiffies(FW_READY_TIMEOUT_MSECS));
+	if (!ret) {
+		dev_err(cdev->dev, "firmware ready timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	/* update sram pg & clock once done booting */
+	catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask);
+	catpt_dsp_update_srampge(cdev, &cdev->iram, cdev->spec->iram_mask);
+
+	return catpt_dsp_update_lpclock(cdev);
+}
+
+int catpt_first_boot_firmware(struct catpt_dev *cdev)
+{
+	struct resource *res;
+	int ret;
+
+	ret = catpt_boot_firmware(cdev, false);
+	if (ret < 0) {
+		dev_err(cdev->dev, "basefw boot failed: %d\n", ret);
+		return ret;
+	}
+
+	/* restrict FW Core dump area */
+	__request_region(&cdev->dram, 0, 0x200, NULL, 0);
+	/* restrict entire area following BASE_FW - highest offset in DRAM */
+	for (res = cdev->dram.child; res->sibling; res = res->sibling)
+		;
+	__request_region(&cdev->dram, res->end + 1,
+			 cdev->dram.end - res->end, NULL, 0);
+
+	ret = catpt_ipc_get_mixer_stream_info(cdev, &cdev->mixer);
+	if (ret)
+		return CATPT_IPC_ERROR(ret);
+
+	ret = catpt_arm_stream_templates(cdev);
+	if (ret < 0) {
+		dev_err(cdev->dev, "arm templates failed: %d\n", ret);
+		return ret;
+	}
+
+	/* update dram pg for scratch and restricted regions */
+	catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask);
+
+	return 0;
+}
-- 
2.17.1


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

* [PATCH v4 04/13] ASoC: Intel: catpt: Implement IPC protocol
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
                   ` (2 preceding siblings ...)
  2020-08-12 20:57 ` [PATCH v4 03/13] ASoC: Intel: catpt: Firmware loading and context restore Cezary Rojewski
@ 2020-08-12 20:57 ` Cezary Rojewski
  2020-08-12 20:57 ` [PATCH v4 05/13] ASoC: Intel: catpt: Add IPC messages Cezary Rojewski
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-12 20:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: pierre-louis.bossart, Cezary Rojewski, andriy.shevchenko,
	filip.kaczmarski, harshapriya.n, marcin.barlik, zwisler,
	lgirdwood, tiwai, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

Implement IRQ handlers for immediate and delayed replies and
notifications. Communication is synchronous and allows for serialization
of maximum one message at a time.

DSP may respond with ADSP_PENDING status for a request - known as
delayed reply - and when situation occurs, framework keeps the lock and
awaits upcoming response through IPCD channel which is handled in
bottom-half. Immediate replies spawn no BH at all as their processing is
very short.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/catpt/dsp.c |  99 ++++++++++++
 sound/soc/intel/catpt/ipc.c | 298 ++++++++++++++++++++++++++++++++++++
 2 files changed, 397 insertions(+)
 create mode 100644 sound/soc/intel/catpt/ipc.c

diff --git a/sound/soc/intel/catpt/dsp.c b/sound/soc/intel/catpt/dsp.c
index 1474e2e11672..9ebd4af97100 100644
--- a/sound/soc/intel/catpt/dsp.c
+++ b/sound/soc/intel/catpt/dsp.c
@@ -5,6 +5,7 @@
 // Author: Cezary Rojewski <cezary.rojewski@intel.com>
 //
 
+#include <linux/devcoredump.h>
 #include <linux/dma-mapping.h>
 #include <linux/acpi_dma.h>
 #include <linux/firmware.h>
@@ -495,3 +496,101 @@ int wpt_dsp_power_up(struct catpt_dev *cdev)
 
 	return 0;
 }
+
+#define CATPT_DUMP_MAGIC		0xcd42
+#define CATPT_DUMP_SECTION_ID_FILE	0x00
+#define CATPT_DUMP_SECTION_ID_IRAM	0x01
+#define CATPT_DUMP_SECTION_ID_DRAM	0x02
+#define CATPT_DUMP_SECTION_ID_REGS	0x03
+
+struct catpt_dump_section_hdr {
+	u16 magic;
+	u8 core_id;
+	u8 section_id;
+	u32 size;
+};
+
+int catpt_coredump(struct catpt_dev *cdev)
+{
+	struct catpt_dump_section_hdr *hdr;
+	size_t dump_size, regs_size;
+	u8 *dump, *pos;
+	int i, j;
+
+	regs_size = CATPT_SHIM_REGS_SIZE;
+	regs_size += CATPT_DMA_COUNT * CATPT_DMA_REGS_SIZE;
+	regs_size += CATPT_SSP_COUNT * CATPT_SSP_REGS_SIZE;
+	dump_size = resource_size(&cdev->dram);
+	dump_size += resource_size(&cdev->iram);
+	dump_size += regs_size;
+	dump_size += 4 * sizeof(*hdr) + 20; /* hdrs and fw hash */
+
+	dump = vzalloc(dump_size);
+	if (!dump)
+		return -ENOMEM;
+
+	pos = dump;
+
+	hdr = (struct catpt_dump_section_hdr *)pos;
+	hdr->magic = CATPT_DUMP_MAGIC;
+	hdr->core_id = cdev->spec->core_id;
+	hdr->section_id = CATPT_DUMP_SECTION_ID_FILE;
+	hdr->size = dump_size - sizeof(*hdr);
+	pos += sizeof(*hdr);
+
+	for (i = j = 0; i < FW_INFO_SIZE_MAX; i++)
+		if (cdev->ipc.config.fw_info[i] == ' ')
+			if (++j == 4)
+				break;
+	for (j = ++i; j < FW_INFO_SIZE_MAX && j - i < 20; j++) {
+		if (cdev->ipc.config.fw_info[j] == ' ')
+			break;
+		*(pos + j - i) = cdev->ipc.config.fw_info[j];
+	}
+	pos += 20;
+
+	hdr = (struct catpt_dump_section_hdr *)pos;
+	hdr->magic = CATPT_DUMP_MAGIC;
+	hdr->core_id = cdev->spec->core_id;
+	hdr->section_id = CATPT_DUMP_SECTION_ID_IRAM;
+	hdr->size = resource_size(&cdev->iram);
+	pos += sizeof(*hdr);
+
+	memcpy_fromio(pos, cdev->lpe_ba + cdev->iram.start, hdr->size);
+	pos += hdr->size;
+
+	hdr = (struct catpt_dump_section_hdr *)pos;
+	hdr->magic = CATPT_DUMP_MAGIC;
+	hdr->core_id = cdev->spec->core_id;
+	hdr->section_id = CATPT_DUMP_SECTION_ID_DRAM;
+	hdr->size = resource_size(&cdev->dram);
+	pos += sizeof(*hdr);
+
+	memcpy_fromio(pos, cdev->lpe_ba + cdev->dram.start, hdr->size);
+	pos += hdr->size;
+
+	hdr = (struct catpt_dump_section_hdr *)pos;
+	hdr->magic = CATPT_DUMP_MAGIC;
+	hdr->core_id = cdev->spec->core_id;
+	hdr->section_id = CATPT_DUMP_SECTION_ID_REGS;
+	hdr->size = regs_size;
+	pos += sizeof(*hdr);
+
+	memcpy_fromio(pos, catpt_shim_addr(cdev), CATPT_SHIM_REGS_SIZE);
+	pos += CATPT_SHIM_REGS_SIZE;
+
+	for (i = 0; i < CATPT_SSP_COUNT; i++) {
+		memcpy_fromio(pos, catpt_ssp_addr(cdev, i),
+			      CATPT_SSP_REGS_SIZE);
+		pos += CATPT_SSP_REGS_SIZE;
+	}
+	for (i = 0; i < CATPT_DMA_COUNT; i++) {
+		memcpy_fromio(pos, catpt_dma_addr(cdev, i),
+			      CATPT_DMA_REGS_SIZE);
+		pos += CATPT_DMA_REGS_SIZE;
+	}
+
+	dev_coredumpv(cdev->dev, dump, dump_size, GFP_KERNEL);
+
+	return 0;
+}
diff --git a/sound/soc/intel/catpt/ipc.c b/sound/soc/intel/catpt/ipc.c
new file mode 100644
index 000000000000..a2cec2ba12e7
--- /dev/null
+++ b/sound/soc/intel/catpt/ipc.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2020 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/irqreturn.h>
+#include "core.h"
+#include "messages.h"
+#include "registers.h"
+#include "trace.h"
+
+#define CATPT_IPC_TIMEOUT_MSECS	300
+
+void catpt_ipc_init(struct catpt_ipc *ipc, struct device *dev)
+{
+	ipc->dev = dev;
+	ipc->ready = false;
+	ipc->default_timeout = CATPT_IPC_TIMEOUT_MSECS;
+	init_completion(&ipc->done_completion);
+	init_completion(&ipc->busy_completion);
+	spin_lock_init(&ipc->lock);
+	mutex_init(&ipc->mutex);
+}
+
+static int catpt_ipc_arm(struct catpt_ipc *ipc, struct catpt_fw_ready *config)
+{
+	/*
+	 * Both tx and rx are put into and received from outbox. Inbox is
+	 * only used for notifications where payload size is known upfront,
+	 * thus no separate buffer is allocated for it
+	 */
+	ipc->rx.data = devm_kzalloc(ipc->dev, config->outbox_size, GFP_KERNEL);
+	if (!ipc->rx.data)
+		return -ENOMEM;
+
+	memcpy(&ipc->config, config, sizeof(*config));
+	ipc->ready = true;
+
+	return 0;
+}
+
+static void catpt_ipc_msg_init(struct catpt_ipc *ipc,
+			       struct catpt_ipc_msg *reply)
+{
+	lockdep_assert_held(&ipc->lock);
+
+	ipc->rx.header = 0;
+	ipc->rx.size = reply ? reply->size : 0;
+	reinit_completion(&ipc->done_completion);
+	reinit_completion(&ipc->busy_completion);
+}
+
+static void catpt_dsp_send_tx(struct catpt_dev *cdev,
+			      const struct catpt_ipc_msg *tx)
+{
+	u32 header = tx->header | CATPT_IPCC_BUSY;
+
+	trace_catpt_ipc_request(header);
+	trace_catpt_ipc_payload(tx->data, tx->size);
+
+	if (tx->size)
+		memcpy_toio(catpt_outbox_addr(cdev), tx->data, tx->size);
+	catpt_writel_shim(cdev, IPCC, header);
+}
+
+static int catpt_wait_msg_completion(struct catpt_dev *cdev, int timeout)
+{
+	struct catpt_ipc *ipc = &cdev->ipc;
+	int ret;
+
+	ret = wait_for_completion_timeout(&ipc->done_completion,
+					  msecs_to_jiffies(timeout));
+	if (!ret)
+		return -ETIMEDOUT;
+	if (ipc->rx.rsp.status != CATPT_REPLY_PENDING)
+		return 0;
+
+	/* wait for delayed reply */
+	ret = wait_for_completion_timeout(&ipc->busy_completion,
+					  msecs_to_jiffies(timeout));
+	return ret ? 0 : -ETIMEDOUT;
+}
+
+static int catpt_dsp_do_send_msg(struct catpt_dev *cdev,
+				 struct catpt_ipc_msg request,
+				 struct catpt_ipc_msg *reply, int timeout)
+{
+	struct catpt_ipc *ipc = &cdev->ipc;
+	unsigned long flags;
+	int ret;
+
+	if (!ipc->ready)
+		return -EPERM;
+	if (request.size > ipc->config.outbox_size ||
+	    (reply && reply->size > ipc->config.outbox_size))
+		return -EINVAL;
+
+	spin_lock_irqsave(&ipc->lock, flags);
+	catpt_ipc_msg_init(ipc, reply);
+	catpt_dsp_send_tx(cdev, &request);
+	spin_unlock_irqrestore(&ipc->lock, flags);
+
+	ret = catpt_wait_msg_completion(cdev, timeout);
+	if (ret < 0) {
+		dev_crit(cdev->dev, "communication severed: %d, rebooting dsp..\n",
+			 ret);
+		ipc->ready = false;
+		/* TODO: attempt recovery */
+		return ret;
+	}
+
+	ret = ipc->rx.rsp.status;
+	if (reply) {
+		reply->header = ipc->rx.header;
+		if (!ret && reply->data && reply->size)
+			memcpy(reply->data, ipc->rx.data, ipc->rx.size);
+	}
+
+	return ret;
+}
+
+int catpt_dsp_send_msg_timeout(struct catpt_dev *cdev,
+			       struct catpt_ipc_msg request,
+			       struct catpt_ipc_msg *reply, int timeout)
+{
+	struct catpt_ipc *ipc = &cdev->ipc;
+	int ret;
+
+	mutex_lock(&ipc->mutex);
+	ret = catpt_dsp_do_send_msg(cdev, request, reply, timeout);
+	mutex_unlock(&ipc->mutex);
+
+	return ret;
+}
+
+int catpt_dsp_send_msg(struct catpt_dev *cdev, struct catpt_ipc_msg request,
+		       struct catpt_ipc_msg *reply)
+{
+	return catpt_dsp_send_msg_timeout(cdev, request, reply,
+					  cdev->ipc.default_timeout);
+}
+
+static void
+catpt_dsp_notify_stream(struct catpt_dev *cdev, union catpt_notify_msg msg)
+{
+	struct catpt_stream_runtime *stream;
+	struct catpt_notify_position pos;
+	struct catpt_notify_glitch glitch;
+
+	stream = catpt_stream_find(cdev, msg.stream_hw_id);
+	if (!stream) {
+		dev_warn(cdev->dev, "notify %d for non-existent stream %d\n",
+			 msg.notify_reason, msg.stream_hw_id);
+		return;
+	}
+
+	switch (msg.notify_reason) {
+	case CATPT_NOTIFY_POSITION_CHANGED:
+		memcpy_fromio(&pos, catpt_inbox_addr(cdev), sizeof(pos));
+		trace_catpt_ipc_payload((u8 *)&pos, sizeof(pos));
+
+		catpt_stream_update_position(cdev, stream, &pos);
+		break;
+
+	case CATPT_NOTIFY_GLITCH_OCCURRED:
+		memcpy_fromio(&glitch, catpt_inbox_addr(cdev), sizeof(glitch));
+		trace_catpt_ipc_payload((u8 *)&glitch, sizeof(glitch));
+
+		dev_warn(cdev->dev, "glitch %d at pos: 0x%08llx, wp: 0x%08x\n",
+			 glitch.type, glitch.presentation_pos,
+			 glitch.write_pos);
+		break;
+
+	default:
+		dev_warn(cdev->dev, "unknown notification: %d received\n",
+			 msg.notify_reason);
+		break;
+	}
+}
+
+static void catpt_dsp_copy_rx(struct catpt_dev *cdev, u32 header)
+{
+	struct catpt_ipc *ipc = &cdev->ipc;
+
+	ipc->rx.header = header;
+	if (ipc->rx.size && ipc->rx.rsp.status == CATPT_REPLY_SUCCESS) {
+		memcpy_fromio(ipc->rx.data, catpt_outbox_addr(cdev),
+			      ipc->rx.size);
+		trace_catpt_ipc_payload(ipc->rx.data, ipc->rx.size);
+	}
+}
+
+static void catpt_dsp_process_response(struct catpt_dev *cdev, u32 header)
+{
+	union catpt_notify_msg msg = CATPT_MSG(header);
+	struct catpt_ipc *ipc = &cdev->ipc;
+
+	if (msg.fw_ready) {
+		struct catpt_fw_ready config;
+		/* to fit 32b header original address is shifted right by 3 */
+		u32 off = msg.mailbox_address << 3;
+
+		memcpy_fromio(&config, cdev->lpe_ba + off, sizeof(config));
+		trace_catpt_ipc_payload((u8 *)&config, sizeof(config));
+
+		catpt_ipc_arm(ipc, &config);
+		complete(&cdev->fw_ready);
+		return;
+	}
+
+	switch (msg.type) {
+	case CATPT_GLB_REQUEST_CORE_DUMP:
+		dev_err(cdev->dev, "ADSP device coredump received\n");
+		ipc->ready = false;
+		catpt_coredump(cdev);
+		/* TODO: attempt recovery */
+		break;
+
+	case CATPT_GLB_STREAM_MESSAGE:
+		switch (msg.subtype) {
+		case CATPT_STRM_NOTIFICATION:
+			catpt_dsp_notify_stream(cdev, msg);
+			break;
+		default:
+			catpt_dsp_copy_rx(cdev, header);
+			/* signal completion of delayed reply */
+			complete(&ipc->busy_completion);
+			break;
+		}
+		break;
+
+	default:
+		dev_warn(cdev->dev, "unknown response: %d received\n",
+			 msg.type);
+		break;
+	}
+}
+
+irqreturn_t catpt_dsp_irq_thread(int irq, void *dev_id)
+{
+	struct catpt_dev *cdev = dev_id;
+	u32 ipcd;
+
+	ipcd = catpt_readl_shim(cdev, IPCD);
+	trace_catpt_ipc_notify(ipcd);
+
+	/* ensure there is delayed reply or notification to process */
+	if (!(ipcd & CATPT_IPCD_BUSY))
+		return IRQ_NONE;
+
+	catpt_dsp_process_response(cdev, ipcd);
+
+	/* tell DSP processing is completed */
+	catpt_updatel_shim(cdev, IPCD, CATPT_IPCD_BUSY | CATPT_IPCD_DONE,
+			   CATPT_IPCD_DONE);
+	/* unmask dsp BUSY interrupt */
+	catpt_updatel_shim(cdev, IMC, CATPT_IMC_IPCDB, 0);
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t catpt_dsp_irq_handler(int irq, void *dev_id)
+{
+	struct catpt_dev *cdev = dev_id;
+	irqreturn_t ret = IRQ_NONE;
+	u32 isc, ipcc;
+
+	isc = catpt_readl_shim(cdev, ISC);
+	trace_catpt_irq(isc);
+
+	/* immediate reply */
+	if (isc & CATPT_ISC_IPCCD) {
+		/* mask host DONE interrupt */
+		catpt_updatel_shim(cdev, IMC, CATPT_IMC_IPCCD, CATPT_IMC_IPCCD);
+
+		ipcc = catpt_readl_shim(cdev, IPCC);
+		trace_catpt_ipc_reply(ipcc);
+		catpt_dsp_copy_rx(cdev, ipcc);
+		complete(&cdev->ipc.done_completion);
+
+		/* tell DSP processing is completed */
+		catpt_updatel_shim(cdev, IPCC, CATPT_IPCC_DONE, 0);
+		/* unmask host DONE interrupt */
+		catpt_updatel_shim(cdev, IMC, CATPT_IMC_IPCCD, 0);
+		ret = IRQ_HANDLED;
+	}
+
+	/* delayed reply or notification */
+	if (isc & CATPT_ISC_IPCDB) {
+		/* mask dsp BUSY interrupt */
+		catpt_updatel_shim(cdev, IMC, CATPT_IMC_IPCDB, CATPT_IMC_IPCDB);
+		ret = IRQ_WAKE_THREAD;
+	}
+
+	return ret;
+}
-- 
2.17.1


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

* [PATCH v4 05/13] ASoC: Intel: catpt: Add IPC messages
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
                   ` (3 preceding siblings ...)
  2020-08-12 20:57 ` [PATCH v4 04/13] ASoC: Intel: catpt: Implement IPC protocol Cezary Rojewski
@ 2020-08-12 20:57 ` Cezary Rojewski
  2020-08-12 20:57 ` [PATCH v4 06/13] ASoC: Intel: catpt: PCM operations Cezary Rojewski
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-12 20:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: pierre-louis.bossart, Cezary Rojewski, andriy.shevchenko,
	filip.kaczmarski, harshapriya.n, marcin.barlik, zwisler,
	lgirdwood, tiwai, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

Declare global and stream IPC message types and define appropriate
message handlers.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/catpt/messages.c | 312 ++++++++++++++++++++++++
 sound/soc/intel/catpt/messages.h | 401 +++++++++++++++++++++++++++++++
 2 files changed, 713 insertions(+)
 create mode 100644 sound/soc/intel/catpt/messages.c
 create mode 100644 sound/soc/intel/catpt/messages.h

diff --git a/sound/soc/intel/catpt/messages.c b/sound/soc/intel/catpt/messages.c
new file mode 100644
index 000000000000..e8583b40830d
--- /dev/null
+++ b/sound/soc/intel/catpt/messages.c
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2020 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include "core.h"
+#include "messages.h"
+#include "registers.h"
+
+int catpt_ipc_get_fw_version(struct catpt_dev *cdev,
+			     struct catpt_fw_version *version)
+{
+	union catpt_global_msg msg = CATPT_GLOBAL_MSG(GET_FW_VERSION);
+	struct catpt_ipc_msg request = {{0}}, reply;
+	int ret;
+
+	request.header = msg.val;
+	reply.size = sizeof(*version);
+	reply.data = version;
+
+	ret = catpt_dsp_send_msg(cdev, request, &reply);
+	if (ret)
+		dev_err(cdev->dev, "get fw version failed: %d\n", ret);
+
+	return ret;
+}
+
+struct catpt_alloc_stream_input {
+	enum catpt_path_id path_id:8;
+	enum catpt_stream_type stream_type:8;
+	enum catpt_format_id format_id:8;
+	u8 reserved;
+	struct catpt_audio_format input_format;
+	struct catpt_ring_info ring_info;
+	u8 num_entries;
+	/* flex array with entries here */
+	struct catpt_memory_info persistent_mem;
+	struct catpt_memory_info scratch_mem;
+	u32 num_notifications; /* obsolete */
+} __packed;
+
+int catpt_ipc_alloc_stream(struct catpt_dev *cdev,
+			   enum catpt_path_id path_id,
+			   enum catpt_stream_type type,
+			   struct catpt_audio_format *afmt,
+			   struct catpt_ring_info *rinfo,
+			   u8 num_modules,
+			   struct catpt_module_entry *modules,
+			   struct resource *persistent,
+			   struct resource *scratch,
+			   struct catpt_stream_info *sinfo)
+{
+	union catpt_global_msg msg = CATPT_GLOBAL_MSG(ALLOCATE_STREAM);
+	struct catpt_alloc_stream_input input;
+	struct catpt_ipc_msg request, reply;
+	size_t size, arrsz;
+	u8 *payload;
+	off_t off;
+	int ret;
+
+	off = offsetof(struct catpt_alloc_stream_input, persistent_mem);
+	arrsz = sizeof(*modules) * num_modules;
+	size = sizeof(input) + arrsz;
+
+	payload = kzalloc(size, GFP_KERNEL);
+	if (!payload)
+		return -ENOMEM;
+
+	memset(&input, 0, sizeof(input));
+	input.path_id = path_id;
+	input.stream_type = type;
+	input.format_id = CATPT_FORMAT_PCM;
+	input.input_format = *afmt;
+	input.ring_info = *rinfo;
+	input.num_entries = num_modules;
+	input.persistent_mem.offset = catpt_to_dsp_offset(persistent->start);
+	input.persistent_mem.size = resource_size(persistent);
+	if (scratch) {
+		input.scratch_mem.offset = catpt_to_dsp_offset(scratch->start);
+		input.scratch_mem.size = resource_size(scratch);
+	}
+
+	/* re-arrange the input: account for flex array 'entries' */
+	memcpy(payload, &input, sizeof(input));
+	memmove(payload + off + arrsz, payload + off, sizeof(input) - off);
+	memcpy(payload + off, modules, arrsz);
+
+	request.header = msg.val;
+	request.size = size;
+	request.data = payload;
+	reply.size = sizeof(*sinfo);
+	reply.data = sinfo;
+
+	ret = catpt_dsp_send_msg(cdev, request, &reply);
+	if (ret)
+		dev_err(cdev->dev, "alloc stream type %d failed: %d\n",
+			type, ret);
+
+	kfree(payload);
+	return ret;
+}
+
+int catpt_ipc_free_stream(struct catpt_dev *cdev, u8 stream_hw_id)
+{
+	union catpt_global_msg msg = CATPT_GLOBAL_MSG(FREE_STREAM);
+	struct catpt_ipc_msg request;
+	int ret;
+
+	request.header = msg.val;
+	request.size = sizeof(stream_hw_id);
+	request.data = &stream_hw_id;
+
+	ret = catpt_dsp_send_msg(cdev, request, NULL);
+	if (ret)
+		dev_err(cdev->dev, "free stream %d failed: %d\n",
+			stream_hw_id, ret);
+
+	return ret;
+}
+
+int catpt_ipc_set_device_format(struct catpt_dev *cdev,
+				struct catpt_ssp_device_format *devfmt)
+{
+	union catpt_global_msg msg = CATPT_GLOBAL_MSG(SET_DEVICE_FORMATS);
+	struct catpt_ipc_msg request;
+	int ret;
+
+	request.header = msg.val;
+	request.size = sizeof(*devfmt);
+	request.data = devfmt;
+
+	ret = catpt_dsp_send_msg(cdev, request, NULL);
+	if (ret)
+		dev_err(cdev->dev, "set device format failed: %d\n", ret);
+
+	return ret;
+}
+
+int catpt_ipc_enter_dxstate(struct catpt_dev *cdev, enum catpt_dx_state state,
+			    struct catpt_dx_context *dx_ctx)
+{
+	union catpt_global_msg msg = CATPT_GLOBAL_MSG(ENTER_DX_STATE);
+	struct catpt_ipc_msg request, reply;
+	int ret;
+
+	request.header = msg.val;
+	request.size = sizeof(state);
+	request.data = &state;
+	reply.size = sizeof(*dx_ctx);
+	reply.data = dx_ctx;
+
+	ret = catpt_dsp_send_msg(cdev, request, &reply);
+	if (ret)
+		dev_err(cdev->dev, "enter dx state failed: %d\n", ret);
+
+	return ret;
+}
+
+int catpt_ipc_get_mixer_stream_info(struct catpt_dev *cdev,
+				    struct catpt_mixer_stream_info *info)
+{
+	union catpt_global_msg msg = CATPT_GLOBAL_MSG(GET_MIXER_STREAM_INFO);
+	struct catpt_ipc_msg request = {{0}}, reply;
+	int ret;
+
+	request.header = msg.val;
+	reply.size = sizeof(*info);
+	reply.data = info;
+
+	ret = catpt_dsp_send_msg(cdev, request, &reply);
+	if (ret)
+		dev_err(cdev->dev, "get mixer info failed: %d\n", ret);
+
+	return ret;
+}
+
+int catpt_ipc_reset_stream(struct catpt_dev *cdev, u8 stream_hw_id)
+{
+	union catpt_stream_msg msg = CATPT_STREAM_MSG(RESET_STREAM);
+	struct catpt_ipc_msg request = {{0}};
+	int ret;
+
+	msg.stream_hw_id = stream_hw_id;
+	request.header = msg.val;
+
+	ret = catpt_dsp_send_msg(cdev, request, NULL);
+	if (ret)
+		dev_err(cdev->dev, "reset stream %d failed: %d\n",
+			stream_hw_id, ret);
+
+	return ret;
+}
+
+int catpt_ipc_pause_stream(struct catpt_dev *cdev, u8 stream_hw_id)
+{
+	union catpt_stream_msg msg = CATPT_STREAM_MSG(PAUSE_STREAM);
+	struct catpt_ipc_msg request = {{0}};
+	int ret;
+
+	msg.stream_hw_id = stream_hw_id;
+	request.header = msg.val;
+
+	ret = catpt_dsp_send_msg(cdev, request, NULL);
+	if (ret)
+		dev_err(cdev->dev, "pause stream %d failed: %d\n",
+			stream_hw_id, ret);
+
+	return ret;
+}
+
+int catpt_ipc_resume_stream(struct catpt_dev *cdev, u8 stream_hw_id)
+{
+	union catpt_stream_msg msg = CATPT_STREAM_MSG(RESUME_STREAM);
+	struct catpt_ipc_msg request = {{0}};
+	int ret;
+
+	msg.stream_hw_id = stream_hw_id;
+	request.header = msg.val;
+
+	ret = catpt_dsp_send_msg(cdev, request, NULL);
+	if (ret)
+		dev_err(cdev->dev, "resume stream %d failed: %d\n",
+			stream_hw_id, ret);
+
+	return ret;
+}
+
+struct catpt_set_volume_input {
+	u32 channel;
+	u32 target_volume;
+	u64 curve_duration;
+	enum catpt_audio_curve_type curve_type __aligned(4);
+} __packed;
+
+int catpt_ipc_set_volume(struct catpt_dev *cdev, u8 stream_hw_id,
+			 u32 channel, u32 volume,
+			 u32 curve_duration,
+			 enum catpt_audio_curve_type curve_type)
+{
+	union catpt_stream_msg msg = CATPT_STAGE_MSG(SET_VOLUME);
+	struct catpt_ipc_msg request;
+	struct catpt_set_volume_input input;
+	int ret;
+
+	msg.stream_hw_id = stream_hw_id;
+	input.channel = channel;
+	input.target_volume = volume;
+	input.curve_duration = curve_duration;
+	input.curve_type = curve_type;
+
+	request.header = msg.val;
+	request.size = sizeof(input);
+	request.data = &input;
+
+	ret = catpt_dsp_send_msg(cdev, request, NULL);
+	if (ret)
+		dev_err(cdev->dev, "set stream %d volume failed: %d\n",
+			stream_hw_id, ret);
+
+	return ret;
+}
+
+struct catpt_set_write_pos_input {
+	u32 new_write_pos;
+	bool end_of_buffer;
+	bool low_latency;
+} __packed;
+
+int catpt_ipc_set_write_pos(struct catpt_dev *cdev, u8 stream_hw_id,
+			    u32 pos, bool eob, bool ll)
+{
+	union catpt_stream_msg msg = CATPT_STAGE_MSG(SET_WRITE_POSITION);
+	struct catpt_ipc_msg request;
+	struct catpt_set_write_pos_input input;
+	int ret;
+
+	msg.stream_hw_id = stream_hw_id;
+	input.new_write_pos = pos;
+	input.end_of_buffer = eob;
+	input.low_latency = ll;
+
+	request.header = msg.val;
+	request.size = sizeof(input);
+	request.data = &input;
+
+	ret = catpt_dsp_send_msg(cdev, request, NULL);
+	if (ret)
+		dev_err(cdev->dev, "set stream %d write pos failed: %d\n",
+			stream_hw_id, ret);
+
+	return ret;
+}
+
+int catpt_ipc_mute_loopback(struct catpt_dev *cdev, u8 stream_hw_id, bool mute)
+{
+	union catpt_stream_msg msg = CATPT_STAGE_MSG(MUTE_LOOPBACK);
+	struct catpt_ipc_msg request;
+	int ret;
+
+	msg.stream_hw_id = stream_hw_id;
+	request.header = msg.val;
+	request.size = sizeof(mute);
+	request.data = &mute;
+
+	ret = catpt_dsp_send_msg(cdev, request, NULL);
+	if (ret)
+		dev_err(cdev->dev, "mute loopback failed: %d\n", ret);
+
+	return ret;
+}
diff --git a/sound/soc/intel/catpt/messages.h b/sound/soc/intel/catpt/messages.h
new file mode 100644
index 000000000000..214c0ce3c7af
--- /dev/null
+++ b/sound/soc/intel/catpt/messages.h
@@ -0,0 +1,401 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2020 Intel Corporation. All rights reserved.
+ *
+ * Author: Cezary Rojewski <cezary.rojewski@intel.com>
+ */
+
+#ifndef __SND_SOC_INTEL_CATPT_MSG_H
+#define __SND_SOC_INTEL_CATPT_MSG_H
+
+struct catpt_dev;
+
+/* IPC messages base types  */
+
+enum catpt_reply_status {
+	CATPT_REPLY_SUCCESS = 0,
+	CATPT_REPLY_ERROR_INVALID_PARAM = 1,
+	CATPT_REPLY_UNKNOWN_MESSAGE_TYPE = 2,
+	CATPT_REPLY_OUT_OF_RESOURCES = 3,
+	CATPT_REPLY_BUSY = 4,
+	CATPT_REPLY_PENDING = 5,
+	CATPT_REPLY_FAILURE = 6,
+	CATPT_REPLY_INVALID_REQUEST = 7,
+	CATPT_REPLY_UNINITIALIZED = 8,
+	CATPT_REPLY_NOT_FOUND = 9,
+	CATPT_REPLY_SOURCE_NOT_STARTED = 10,
+};
+
+/* GLOBAL messages */
+
+enum catpt_global_msg_type {
+	CATPT_GLB_GET_FW_VERSION = 0,
+	CATPT_GLB_ALLOCATE_STREAM = 3,
+	CATPT_GLB_FREE_STREAM = 4,
+	CATPT_GLB_STREAM_MESSAGE = 6,
+	CATPT_GLB_REQUEST_CORE_DUMP = 7,
+	CATPT_GLB_SET_DEVICE_FORMATS = 10,
+	CATPT_GLB_ENTER_DX_STATE = 12,
+	CATPT_GLB_GET_MIXER_STREAM_INFO = 13,
+};
+
+union catpt_global_msg {
+	u32 val;
+	struct {
+		enum catpt_reply_status status:5;
+		u32 context:19; /* stream or module specific */
+		enum catpt_global_msg_type type:5;
+		u32 fw_ready:1;
+		u32 done:1;
+		u32 busy:1;
+	};
+} __packed;
+
+#define CATPT_MSG(hdr) { .val = hdr }
+#define CATPT_GLOBAL_MSG(msg_type) \
+	{ .type = CATPT_GLB_##msg_type }
+
+#define BUILD_HASH_SIZE		40
+
+struct catpt_fw_version {
+	u8 build;
+	u8 minor;
+	u8 major;
+	u8 type;
+	u8 build_hash[BUILD_HASH_SIZE];
+	u32 log_providers_hash;
+} __packed;
+
+int catpt_ipc_get_fw_version(struct catpt_dev *cdev,
+			     struct catpt_fw_version *version);
+
+enum catpt_pin_id {
+	CATPT_PIN_ID_SYSTEM = 0,
+	CATPT_PIN_ID_REFERENCE = 1,
+	CATPT_PIN_ID_CAPTURE1 = 2,
+	CATPT_PIN_ID_CAPTURE2 = 3,
+	CATPT_PIN_ID_OFFLOAD1 = 4,
+	CATPT_PIN_ID_OFFLOAD2 = 5,
+	CATPT_PIN_ID_MIXER = 7,
+	CATPT_PIN_ID_BLUETOOTH_CAPTURE = 8,
+	CATPT_PIN_ID_BLUETOOTH_RENDER = 9,
+};
+
+enum catpt_path_id {
+	CATPT_PATH_SSP0_OUT = 0,
+	CATPT_PATH_SSP0_IN = 1,
+	CATPT_PATH_SSP1_OUT = 2,
+	CATPT_PATH_SSP1_IN = 3,
+	/* duplicated audio in capture path */
+	CATPT_PATH_SSP0_IN_DUP = 4,
+};
+
+enum catpt_stream_type {
+	CATPT_STRM_TYPE_RENDER = 0, /* offload */
+	CATPT_STRM_TYPE_SYSTEM = 1,
+	CATPT_STRM_TYPE_CAPTURE = 2,
+	CATPT_STRM_TYPE_LOOPBACK = 3,
+	CATPT_STRM_TYPE_BLUETOOTH_RENDER = 4,
+	CATPT_STRM_TYPE_BLUETOOTH_CAPTURE = 5,
+};
+
+enum catpt_format_id {
+	CATPT_FORMAT_PCM = 0,
+	CATPT_FORMAT_MP3 = 1,
+	CATPT_FORMAT_AAC = 2,
+	CATPT_FORMAT_WMA = 3,
+};
+
+enum catpt_channel_index {
+	CATPT_CHANNEL_LEFT = 0x0,
+	CATPT_CHANNEL_CENTER = 0x1,
+	CATPT_CHANNEL_RIGHT = 0x2,
+	CATPT_CHANNEL_LEFT_SURROUND = 0x3,
+	CATPT_CHANNEL_CENTER_SURROUND = 0x3,
+	CATPT_CHANNEL_RIGHT_SURROUND = 0x4,
+	CATPT_CHANNEL_LFE = 0x7,
+	CATPT_CHANNEL_INVALID = 0xF,
+};
+
+enum catpt_channel_config {
+	CATPT_CHANNEL_CONFIG_MONO	= 0, /* One channel only */
+	CATPT_CHANNEL_CONFIG_STEREO	= 1, /* L & R */
+	CATPT_CHANNEL_CONFIG_2_POINT_1	= 2, /* L, R & LFE; PCM only */
+	CATPT_CHANNEL_CONFIG_3_POINT_0	= 3, /* L, C & R; MP3 & AAC only */
+	CATPT_CHANNEL_CONFIG_3_POINT_1	= 4, /* L, C, R & LFE; PCM only */
+	CATPT_CHANNEL_CONFIG_QUATRO	= 5, /* L, R, Ls & Rs; PCM only */
+	CATPT_CHANNEL_CONFIG_4_POINT_0	= 6, /* L, C, R & Cs; MP3 & AAC only */
+	CATPT_CHANNEL_CONFIG_5_POINT_0	= 7, /* L, C, R, Ls & Rs */
+	CATPT_CHANNEL_CONFIG_5_POINT_1	= 8, /* L, C, R, Ls, Rs & LFE */
+	CATPT_CHANNEL_CONFIG_DUAL_MONO	= 9, /* One channel replicated in two */
+	CATPT_CHANNEL_CONFIG_INVALID	= 10,
+};
+
+enum catpt_interleaving_style {
+	CATPT_INTERLEAVING_PER_CHANNEL = 0,
+	CATPT_INTERLEAVING_PER_SAMPLE  = 1,
+};
+
+struct catpt_audio_format {
+	u32 sample_rate;
+	u32 bit_depth;
+	u32 channel_map;
+	enum catpt_channel_config channel_config __aligned(4);
+	enum catpt_interleaving_style interleaving __aligned(4);
+	u8 num_channels;
+	u8 valid_bit_depth;
+	u8 reserved[2];
+} __packed;
+
+struct catpt_ring_info {
+	u32 page_table_addr;
+	u32 num_pages;
+	u32 size;
+	u32 offset;
+	u32 ring_first_page_pfn;
+} __packed;
+
+#define CATPT_MODULE_COUNT (CATPT_MODID_LAST + 1)
+
+enum catpt_module_id {
+	CATPT_MODID_BASE_FW = 0x0,
+	CATPT_MODID_MP3 = 0x1,
+	CATPT_MODID_AAC_5_1 = 0x2,
+	CATPT_MODID_AAC_2_0 = 0x3,
+	CATPT_MODID_SRC = 0x4,
+	CATPT_MODID_WAVES = 0x5,
+	CATPT_MODID_DOLBY = 0x6,
+	CATPT_MODID_BOOST = 0x7,
+	CATPT_MODID_LPAL = 0x8,
+	CATPT_MODID_DTS = 0x9,
+	CATPT_MODID_PCM_CAPTURE = 0xA,
+	CATPT_MODID_PCM_SYSTEM = 0xB,
+	CATPT_MODID_PCM_REFERENCE = 0xC,
+	CATPT_MODID_PCM = 0xD, /* offload */
+	CATPT_MODID_BLUETOOTH_RENDER = 0xE,
+	CATPT_MODID_BLUETOOTH_CAPTURE = 0xF,
+	CATPT_MODID_LAST = CATPT_MODID_BLUETOOTH_CAPTURE,
+};
+
+struct catpt_module_entry {
+	enum catpt_module_id module_id __aligned(4);
+	u32 entry_point;
+} __packed;
+
+struct catpt_module_map {
+	u8 num_entries;
+	struct catpt_module_entry entries[];
+} __packed;
+
+struct catpt_memory_info {
+	u32 offset;
+	u32 size;
+} __packed;
+
+#define CATPT_CHANNELS_MAX	4
+#define CATPT_ALL_CHANNELS_MASK	UINT_MAX
+
+struct catpt_stream_info {
+	u32 stream_hw_id;
+	u32 reserved;
+	u32 read_pos_regaddr;
+	u32 pres_pos_regaddr;
+	u32 peak_meter_regaddr[CATPT_CHANNELS_MAX];
+	u32 volume_regaddr[CATPT_CHANNELS_MAX];
+} __packed;
+
+int catpt_ipc_alloc_stream(struct catpt_dev *cdev,
+			   enum catpt_path_id path_id,
+			   enum catpt_stream_type type,
+			   struct catpt_audio_format *afmt,
+			   struct catpt_ring_info *rinfo,
+			   u8 num_modules,
+			   struct catpt_module_entry *modules,
+			   struct resource *persistent,
+			   struct resource *scratch,
+			   struct catpt_stream_info *sinfo);
+int catpt_ipc_free_stream(struct catpt_dev *cdev, u8 stream_hw_id);
+
+#define CATPT_SSP_COUNT (CATPT_SSP_IFACE_LAST + 1)
+
+enum catpt_ssp_iface {
+	CATPT_SSP_IFACE_0 = 0,
+	CATPT_SSP_IFACE_1 = 1,
+	CATPT_SSP_IFACE_LAST = CATPT_SSP_IFACE_1,
+};
+
+enum catpt_mclk_frequency {
+	CATPT_MCLK_OFF = 0,
+	CATPT_MCLK_FREQ_6_MHZ = 1,
+	CATPT_MCLK_FREQ_21_MHZ = 2,
+	CATPT_MCLK_FREQ_24_MHZ = 3,
+};
+
+enum catpt_ssp_mode {
+	CATPT_SSP_MODE_I2S_SLAVE = 0,
+	CATPT_SSP_MODE_I2S_MASTER = 1,
+	CATPT_SSP_MODE_TDM_MASTER = 2,
+};
+
+struct catpt_ssp_device_format {
+	enum catpt_ssp_iface iface;
+	enum catpt_mclk_frequency mclk;
+	enum catpt_ssp_mode mode;
+	u16 clock_divider;
+	u8 channels;
+} __packed;
+
+int catpt_ipc_set_device_format(struct catpt_dev *cdev,
+				struct catpt_ssp_device_format *devfmt);
+
+enum catpt_dx_state {
+	CATPT_DX_STATE_D3 = 3,
+};
+
+enum catpt_dx_type {
+	CATPT_DX_TYPE_FW_IMAGE = 0,
+	CATPT_DX_TYPE_MEMORY_DUMP = 1,
+};
+
+struct catpt_save_meminfo {
+	u32 offset;
+	u32 size;
+	enum catpt_dx_type source __aligned(4);
+} __packed;
+
+#define SAVE_MEMINFO_MAX	14
+
+struct catpt_dx_context {
+	u32 num_meminfo;
+	struct catpt_save_meminfo meminfo[SAVE_MEMINFO_MAX];
+} __packed;
+
+int catpt_ipc_enter_dxstate(struct catpt_dev *cdev, enum catpt_dx_state state,
+			    struct catpt_dx_context *context);
+
+struct catpt_mixer_stream_info {
+	u32 mixer_hw_id;
+	u32 peak_meter_regaddr[CATPT_CHANNELS_MAX];
+	u32 volume_regaddr[CATPT_CHANNELS_MAX];
+} __packed;
+
+int catpt_ipc_get_mixer_stream_info(struct catpt_dev *cdev,
+				    struct catpt_mixer_stream_info *info);
+
+/* STREAM messages */
+
+enum catpt_stream_msg_type {
+	CATPT_STRM_RESET_STREAM = 0,
+	CATPT_STRM_PAUSE_STREAM = 1,
+	CATPT_STRM_RESUME_STREAM = 2,
+	CATPT_STRM_STAGE_MESSAGE = 3,
+	CATPT_STRM_NOTIFICATION = 4,
+};
+
+enum catpt_stage_action {
+	CATPT_STG_SET_VOLUME = 1,
+	CATPT_STG_SET_WRITE_POSITION = 2,
+	CATPT_STG_MUTE_LOOPBACK = 3,
+};
+
+union catpt_stream_msg {
+	u32 val;
+	struct {
+		enum catpt_reply_status status:5;
+		u32 reserved:7;
+		enum catpt_stage_action stage_action:4;
+		u32 stream_hw_id:4;
+		enum catpt_stream_msg_type subtype:4;
+		enum catpt_global_msg_type type:5;
+		u32 fw_ready:1;
+		u32 done:1;
+		u32 busy:1;
+	};
+} __packed;
+
+#define CATPT_STREAM_MSG(msg_type) \
+{ \
+	.subtype = CATPT_STRM_##msg_type, \
+	.type = CATPT_GLB_STREAM_MESSAGE }
+#define CATPT_STAGE_MSG(msg_type) \
+{ \
+	.stage_action = CATPT_STG_##msg_type, \
+	.subtype = CATPT_STRM_STAGE_MESSAGE, \
+	.type = CATPT_GLB_STREAM_MESSAGE }
+
+int catpt_ipc_reset_stream(struct catpt_dev *cdev, u8 stream_hw_id);
+int catpt_ipc_pause_stream(struct catpt_dev *cdev, u8 stream_hw_id);
+int catpt_ipc_resume_stream(struct catpt_dev *cdev, u8 stream_hw_id);
+
+/* STREAM messages - STAGE subtype */
+
+enum catpt_audio_curve_type {
+	CATPT_AUDIO_CURVE_NONE = 0,
+	CATPT_AUDIO_CURVE_WINDOWS_FADE = 1,
+};
+
+int catpt_ipc_set_volume(struct catpt_dev *cdev, u8 stream_hw_id,
+			 u32 channel, u32 volume,
+			 u32 curve_duration,
+			 enum catpt_audio_curve_type curve_type);
+
+int catpt_ipc_set_write_pos(struct catpt_dev *cdev, u8 stream_hw_id,
+			    u32 pos, bool eob, bool ll);
+
+int catpt_ipc_mute_loopback(struct catpt_dev *cdev, u8 stream_hw_id, bool mute);
+
+/* NOTIFICATION messages */
+
+enum catpt_notify_reason {
+	CATPT_NOTIFY_POSITION_CHANGED = 0,
+	CATPT_NOTIFY_GLITCH_OCCURRED = 1,
+};
+
+union catpt_notify_msg {
+	u32 val;
+	struct {
+		u32 mailbox_address:29;
+		u32 fw_ready:1;
+		u32 done:1;
+		u32 busy:1;
+	};
+	struct {
+		enum catpt_reply_status status:5;
+		u32 reserved:7;
+		enum catpt_notify_reason notify_reason:4;
+		u32 stream_hw_id:4;
+		enum catpt_stream_msg_type subtype:4;
+		enum catpt_global_msg_type type:5;
+		u32 hdr:3; /* fw_ready, done, busy */
+	};
+} __packed;
+
+#define FW_INFO_SIZE_MAX	100
+
+struct catpt_fw_ready {
+	u32 inbox_offset;
+	u32 outbox_offset;
+	u32 inbox_size;
+	u32 outbox_size;
+	u32 fw_info_size;
+	char fw_info[FW_INFO_SIZE_MAX];
+} __packed;
+
+struct catpt_notify_position {
+	u32 stream_position;
+	u32 fw_cycle_count;
+} __packed;
+
+enum catpt_glitch_type {
+	CATPT_GLITCH_UNDERRUN = 1,
+	CATPT_GLITCH_DECODER_ERROR = 2,
+	CATPT_GLITCH_DOUBLED_WRITE_POS = 3,
+};
+
+struct catpt_notify_glitch {
+	enum catpt_glitch_type type __aligned(4);
+	u64 presentation_pos;
+	u32 write_pos;
+} __packed;
+
+#endif
-- 
2.17.1


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

* [PATCH v4 06/13] ASoC: Intel: catpt: PCM operations
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
                   ` (4 preceding siblings ...)
  2020-08-12 20:57 ` [PATCH v4 05/13] ASoC: Intel: catpt: Add IPC messages Cezary Rojewski
@ 2020-08-12 20:57 ` Cezary Rojewski
  2020-08-12 20:57 ` [PATCH v4 07/13] ASoC: Intel: catpt: Event tracing Cezary Rojewski
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-12 20:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: pierre-louis.bossart, Cezary Rojewski, andriy.shevchenko,
	filip.kaczmarski, harshapriya.n, marcin.barlik, zwisler,
	lgirdwood, tiwai, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

DSP designed for Lynxpoint and Wildcat Point offers no dynamic topology
i.e. all pipelines are already defined within firmware and host is
relegated to allocing stream for predefined pins. This is represented by
'catpt_topology' member.

Implementation covers all available pin types:
- system playback and capture
- two offload streams
- loopback (reference)
- bluetooth playback and capture

PCM DAI operations differentiate between those pins as some (mainly
offload) are to be handled differently - DSP expects wp updates on each
notify_position notification.

System playback has no volume control capability as it is routed to
mixer stream directly. Other primary streams - capture and two offloads
- offer individual volume controls.

Compared to sound/soc/intel/haswell this configures SSP device format
automatically on pcm creation.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/catpt/pcm.c | 1212 +++++++++++++++++++++++++++++++++++
 1 file changed, 1212 insertions(+)
 create mode 100644 sound/soc/intel/catpt/pcm.c

diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c
new file mode 100644
index 000000000000..1043542ee8db
--- /dev/null
+++ b/sound/soc/intel/catpt/pcm.c
@@ -0,0 +1,1212 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2020 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <uapi/sound/tlv.h>
+#include "core.h"
+#include "messages.h"
+
+struct catpt_stream_template {
+	enum catpt_path_id path_id;
+	enum catpt_stream_type type;
+	u32 persistent_size;
+	u8 num_entries;
+	struct catpt_module_entry entries[];
+};
+
+static struct catpt_stream_template system_pb = {
+	.path_id = CATPT_PATH_SSP0_OUT,
+	.type = CATPT_STRM_TYPE_SYSTEM,
+	.num_entries = 1,
+	.entries = {{ CATPT_MODID_PCM_SYSTEM, 0 }},
+};
+
+static struct catpt_stream_template system_cp = {
+	.path_id = CATPT_PATH_SSP0_IN,
+	.type = CATPT_STRM_TYPE_CAPTURE,
+	.num_entries = 1,
+	.entries = {{ CATPT_MODID_PCM_CAPTURE, 0 }},
+};
+
+static struct catpt_stream_template offload_pb = {
+	.path_id = CATPT_PATH_SSP0_OUT,
+	.type = CATPT_STRM_TYPE_RENDER,
+	.num_entries = 1,
+	.entries = {{ CATPT_MODID_PCM, 0 }},
+};
+
+static struct catpt_stream_template loopback_cp = {
+	.path_id = CATPT_PATH_SSP0_OUT,
+	.type = CATPT_STRM_TYPE_LOOPBACK,
+	.num_entries = 1,
+	.entries = {{ CATPT_MODID_PCM_REFERENCE, 0 }},
+};
+
+static struct catpt_stream_template bluetooth_pb = {
+	.path_id = CATPT_PATH_SSP1_OUT,
+	.type = CATPT_STRM_TYPE_BLUETOOTH_RENDER,
+	.num_entries = 1,
+	.entries = {{ CATPT_MODID_BLUETOOTH_RENDER, 0 }},
+};
+
+static struct catpt_stream_template bluetooth_cp = {
+	.path_id = CATPT_PATH_SSP1_IN,
+	.type = CATPT_STRM_TYPE_BLUETOOTH_CAPTURE,
+	.num_entries = 1,
+	.entries = {{ CATPT_MODID_BLUETOOTH_CAPTURE, 0 }},
+};
+
+static struct catpt_stream_template *catpt_topology[] = {
+	[CATPT_STRM_TYPE_RENDER]		= &offload_pb,
+	[CATPT_STRM_TYPE_SYSTEM]		= &system_pb,
+	[CATPT_STRM_TYPE_CAPTURE]		= &system_cp,
+	[CATPT_STRM_TYPE_LOOPBACK]		= &loopback_cp,
+	[CATPT_STRM_TYPE_BLUETOOTH_RENDER]	= &bluetooth_pb,
+	[CATPT_STRM_TYPE_BLUETOOTH_CAPTURE]	= &bluetooth_cp,
+};
+
+static struct catpt_stream_template *
+catpt_get_stream_template(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtm = substream->private_data;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtm, 0);
+	enum catpt_stream_type type;
+
+	type = cpu_dai->driver->id;
+
+	/* account for capture in bidirectional dais */
+	switch (type) {
+	case CATPT_STRM_TYPE_SYSTEM:
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			type = CATPT_STRM_TYPE_CAPTURE;
+		break;
+	case CATPT_STRM_TYPE_BLUETOOTH_RENDER:
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			type = CATPT_STRM_TYPE_BLUETOOTH_CAPTURE;
+		break;
+	default:
+		break;
+	};
+
+	return catpt_topology[type];
+}
+
+struct catpt_stream_runtime *
+catpt_stream_find(struct catpt_dev *cdev, u8 stream_hw_id)
+{
+	struct catpt_stream_runtime *pos, *result = NULL;
+
+	spin_lock(&cdev->list_lock);
+	list_for_each_entry(pos, &cdev->stream_list, node) {
+		if (pos->info.stream_hw_id == stream_hw_id) {
+			result = pos;
+			break;
+		}
+	}
+
+	spin_unlock(&cdev->list_lock);
+	return result;
+}
+
+static u32 catpt_stream_read_position(struct catpt_dev *cdev,
+				      struct catpt_stream_runtime *stream)
+{
+	u32 pos;
+
+	memcpy_fromio(&pos, cdev->lpe_ba + stream->info.read_pos_regaddr,
+		      sizeof(pos));
+	return pos;
+}
+
+static u32 catpt_stream_volume(struct catpt_dev *cdev,
+			       struct catpt_stream_runtime *stream, u32 channel)
+{
+	u32 volume, offset;
+
+	if (channel >= CATPT_CHANNELS_MAX)
+		channel = 0;
+
+	offset = stream->info.volume_regaddr[channel];
+	memcpy_fromio(&volume, cdev->lpe_ba + offset, sizeof(volume));
+	return volume;
+}
+
+static u32 catpt_mixer_volume(struct catpt_dev *cdev,
+			      struct catpt_mixer_stream_info *info, u32 channel)
+{
+	u32 volume, offset;
+
+	if (channel >= CATPT_CHANNELS_MAX)
+		channel = 0;
+
+	offset = info->volume_regaddr[channel];
+	memcpy_fromio(&volume, cdev->lpe_ba + offset, sizeof(volume));
+	return volume;
+}
+
+static void catpt_arrange_page_table(struct snd_pcm_substream *substream,
+				     struct snd_dma_buffer *pgtbl)
+{
+	struct snd_pcm_runtime *rtm = substream->runtime;
+	struct snd_dma_buffer *databuf = snd_pcm_get_dma_buf(substream);
+	int i, pages;
+
+	pages = snd_sgbuf_aligned_pages(rtm->dma_bytes);
+
+	for (i = 0; i < pages; i++) {
+		u32 pfn, offset;
+		u32 *page_table;
+
+		pfn = snd_sgbuf_get_addr(databuf, i * PAGE_SIZE) >> PAGE_SHIFT;
+		/* incrementing by 2 on even and 3 on odd */
+		offset = ((i << 2) + i) >> 1;
+		page_table = (u32 *)(pgtbl->area + offset);
+
+		if (i & 1)
+			*page_table |= (pfn << 4);
+		else
+			*page_table |= pfn;
+	}
+}
+
+static u32 catpt_get_channel_map(enum catpt_channel_config config)
+{
+	switch (config) {
+	case CATPT_CHANNEL_CONFIG_MONO:
+		return (0xFFFFFFF0 | CATPT_CHANNEL_CENTER);
+
+	case CATPT_CHANNEL_CONFIG_STEREO:
+		return (0xFFFFFF00 | CATPT_CHANNEL_LEFT
+				   | (CATPT_CHANNEL_RIGHT << 4));
+
+	case CATPT_CHANNEL_CONFIG_2_POINT_1:
+		return (0xFFFFF000 | CATPT_CHANNEL_LEFT
+				   | (CATPT_CHANNEL_RIGHT << 4)
+				   | (CATPT_CHANNEL_LFE << 8));
+
+	case CATPT_CHANNEL_CONFIG_3_POINT_0:
+		return (0xFFFFF000 | CATPT_CHANNEL_LEFT
+				   | (CATPT_CHANNEL_CENTER << 4)
+				   | (CATPT_CHANNEL_RIGHT << 8));
+
+	case CATPT_CHANNEL_CONFIG_3_POINT_1:
+		return (0xFFFF0000 | CATPT_CHANNEL_LEFT
+				   | (CATPT_CHANNEL_CENTER << 4)
+				   | (CATPT_CHANNEL_RIGHT << 8)
+				   | (CATPT_CHANNEL_LFE << 12));
+
+	case CATPT_CHANNEL_CONFIG_QUATRO:
+		return (0xFFFF0000 | CATPT_CHANNEL_LEFT
+				   | (CATPT_CHANNEL_RIGHT << 4)
+				   | (CATPT_CHANNEL_LEFT_SURROUND << 8)
+				   | (CATPT_CHANNEL_RIGHT_SURROUND << 12));
+
+	case CATPT_CHANNEL_CONFIG_4_POINT_0:
+		return (0xFFFF0000 | CATPT_CHANNEL_LEFT
+				   | (CATPT_CHANNEL_CENTER << 4)
+				   | (CATPT_CHANNEL_RIGHT << 8)
+				   | (CATPT_CHANNEL_CENTER_SURROUND << 12));
+
+	case CATPT_CHANNEL_CONFIG_5_POINT_0:
+		return (0xFFF00000 | CATPT_CHANNEL_LEFT
+				   | (CATPT_CHANNEL_CENTER << 4)
+				   | (CATPT_CHANNEL_RIGHT << 8)
+				   | (CATPT_CHANNEL_LEFT_SURROUND << 12)
+				   | (CATPT_CHANNEL_RIGHT_SURROUND << 16));
+
+	case CATPT_CHANNEL_CONFIG_5_POINT_1:
+		return (0xFF000000 | CATPT_CHANNEL_CENTER
+				   | (CATPT_CHANNEL_LEFT << 4)
+				   | (CATPT_CHANNEL_RIGHT << 8)
+				   | (CATPT_CHANNEL_LEFT_SURROUND << 12)
+				   | (CATPT_CHANNEL_RIGHT_SURROUND << 16)
+				   | (CATPT_CHANNEL_LFE << 20));
+
+	case CATPT_CHANNEL_CONFIG_DUAL_MONO:
+		return (0xFFFFFF00 | CATPT_CHANNEL_LEFT
+				   | (CATPT_CHANNEL_LEFT << 4));
+
+	default:
+		return 0xFFFFFFFF;
+	}
+}
+
+static enum catpt_channel_config catpt_get_channel_config(u32 num_channels)
+{
+	switch (num_channels) {
+	case 6:
+		return CATPT_CHANNEL_CONFIG_5_POINT_1;
+	case 5:
+		return CATPT_CHANNEL_CONFIG_5_POINT_0;
+	case 4:
+		return CATPT_CHANNEL_CONFIG_QUATRO;
+	case 3:
+		return CATPT_CHANNEL_CONFIG_2_POINT_1;
+	case 1:
+		return CATPT_CHANNEL_CONFIG_MONO;
+	case 2:
+	default:
+		return CATPT_CHANNEL_CONFIG_STEREO;
+	}
+}
+
+static int catpt_dai_startup(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
+	struct catpt_stream_template *template;
+	struct catpt_stream_runtime *stream;
+	struct resource *res;
+	int ret;
+
+	template = catpt_get_stream_template(substream);
+
+	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+	if (!stream)
+		return -ENOMEM;
+
+	ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, cdev->dev, PAGE_SIZE,
+				  &stream->pgtbl);
+	if (ret < 0)
+		goto pgtbl_err;
+
+	res = catpt_request_region(&cdev->dram, template->persistent_size);
+	if (!res) {
+		ret = -EBUSY;
+		goto request_err;
+	}
+
+	catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask);
+
+	stream->template = template;
+	stream->persistent = res;
+	stream->substream = substream;
+	INIT_LIST_HEAD(&stream->node);
+	snd_soc_dai_set_dma_data(dai, substream, stream);
+
+	spin_lock(&cdev->list_lock);
+	list_add_tail(&stream->node, &cdev->stream_list);
+	spin_unlock(&cdev->list_lock);
+
+	return 0;
+
+request_err:
+	snd_dma_free_pages(&stream->pgtbl);
+pgtbl_err:
+	kfree(stream);
+	return ret;
+}
+
+static void catpt_dai_shutdown(struct snd_pcm_substream *substream,
+			       struct snd_soc_dai *dai)
+{
+	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
+	struct catpt_stream_runtime *stream;
+
+	stream = snd_soc_dai_get_dma_data(dai, substream);
+
+	spin_lock(&cdev->list_lock);
+	list_del(&stream->node);
+	spin_unlock(&cdev->list_lock);
+
+	release_resource(stream->persistent);
+	kfree(stream->persistent);
+	catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask);
+
+	snd_dma_free_pages(&stream->pgtbl);
+	kfree(stream);
+	snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
+			       struct snd_pcm_hw_params *params,
+			       struct snd_soc_dai *dai)
+{
+	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
+	struct catpt_stream_runtime *stream;
+	struct catpt_audio_format afmt;
+	struct catpt_ring_info rinfo;
+	struct snd_pcm_runtime *rtm = substream->runtime;
+	struct snd_dma_buffer *dmab;
+	int ret;
+
+	stream = snd_soc_dai_get_dma_data(dai, substream);
+	if (stream->allocated)
+		return 0;
+
+	memset(&afmt, 0, sizeof(afmt));
+	afmt.sample_rate = params_rate(params);
+	afmt.bit_depth = params_physical_width(params);
+	afmt.valid_bit_depth = params_width(params);
+	afmt.bit_depth = params_physical_width(params);
+	afmt.valid_bit_depth = params_width(params);
+	afmt.num_channels = params_channels(params);
+	afmt.channel_config = catpt_get_channel_config(afmt.num_channels);
+	afmt.channel_map = catpt_get_channel_map(afmt.channel_config);
+	afmt.interleaving = CATPT_INTERLEAVING_PER_CHANNEL;
+
+	dmab = snd_pcm_get_dma_buf(substream);
+	catpt_arrange_page_table(substream, &stream->pgtbl);
+
+	memset(&rinfo, 0, sizeof(rinfo));
+	rinfo.page_table_addr = stream->pgtbl.addr;
+	rinfo.num_pages = DIV_ROUND_UP(rtm->dma_bytes, PAGE_SIZE);
+	rinfo.size = rtm->dma_bytes;
+	rinfo.offset = 0;
+	rinfo.ring_first_page_pfn = snd_sgbuf_get_addr(dmab, 0) >> PAGE_SHIFT;
+
+	ret = catpt_ipc_alloc_stream(cdev, stream->template->path_id,
+				     stream->template->type,
+				     &afmt, &rinfo,
+				     stream->template->num_entries,
+				     stream->template->entries,
+				     stream->persistent,
+				     cdev->scratch,
+				     &stream->info);
+	if (ret)
+		return CATPT_IPC_ERROR(ret);
+
+	stream->allocated = true;
+	return 0;
+}
+
+static int catpt_dai_hw_free(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
+	struct catpt_stream_runtime *stream;
+
+	stream = snd_soc_dai_get_dma_data(dai, substream);
+	if (!stream->allocated)
+		return 0;
+
+	catpt_ipc_reset_stream(cdev, stream->info.stream_hw_id);
+	catpt_ipc_free_stream(cdev, stream->info.stream_hw_id);
+
+	stream->allocated = false;
+	return 0;
+}
+
+static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol);
+
+static int catpt_dai_apply_usettings(struct snd_soc_dai *dai,
+				     struct catpt_stream_runtime *stream)
+{
+	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
+	struct snd_soc_component *component = dai->component;
+	struct snd_kcontrol *pos, *kctl = NULL;
+	const char *name;
+	int ret;
+	u32 id = stream->info.stream_hw_id;
+
+	/* only selected streams have individual controls */
+	switch (id) {
+	case CATPT_PIN_ID_OFFLOAD1:
+		name = "Media0 Playback Volume";
+		break;
+	case CATPT_PIN_ID_OFFLOAD2:
+		name = "Media1 Playback Volume";
+		break;
+	case CATPT_PIN_ID_CAPTURE1:
+		name = "Mic Capture Volume";
+		break;
+	case CATPT_PIN_ID_REFERENCE:
+		name = "Loopback Mute";
+		break;
+	default:
+		return 0;
+	};
+
+	list_for_each_entry(pos, &component->card->snd_card->controls, list) {
+		if (pos->private_data == component &&
+		    !strncmp(name, pos->id.name, sizeof(pos->id.name))) {
+			kctl = pos;
+			break;
+		}
+	}
+	if (!kctl)
+		return -ENOENT;
+
+	if (stream->template->type != CATPT_STRM_TYPE_LOOPBACK)
+		return catpt_set_dspvol(cdev, id, (long *)kctl->private_value);
+	ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)kctl->private_value);
+	if (ret)
+		return CATPT_IPC_ERROR(ret);
+	return 0;
+}
+
+static int catpt_dai_prepare(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
+	struct catpt_stream_runtime *stream;
+	int ret;
+
+	stream = snd_soc_dai_get_dma_data(dai, substream);
+	if (stream->prepared)
+		return 0;
+
+	ret = catpt_ipc_reset_stream(cdev, stream->info.stream_hw_id);
+	if (ret)
+		return CATPT_IPC_ERROR(ret);
+
+	ret = catpt_ipc_pause_stream(cdev, stream->info.stream_hw_id);
+	if (ret)
+		return CATPT_IPC_ERROR(ret);
+
+	ret = catpt_dsp_update_lpclock(cdev);
+	if (ret < 0)
+		return ret;
+
+	ret = catpt_dai_apply_usettings(dai, stream);
+	if (ret < 0)
+		return ret;
+
+	stream->prepared = true;
+	return 0;
+}
+
+static int catpt_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+			     struct snd_soc_dai *dai)
+{
+	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
+	struct catpt_stream_runtime *stream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	snd_pcm_uframes_t pos;
+	int ret;
+
+	stream = snd_soc_dai_get_dma_data(dai, substream);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		/* only offload is set_write_pos driven */
+		if (stream->template->type != CATPT_STRM_TYPE_RENDER)
+			goto resume_stream;
+
+		pos = frames_to_bytes(runtime, runtime->start_threshold);
+		/*
+		 * Dsp operates on buffer halves, thus max 2x set_write_pos
+		 * (entire buffer filled) prior to stream start
+		 */
+		ret = catpt_ipc_set_write_pos(cdev, stream->info.stream_hw_id,
+					      pos, false, false);
+		if (ret)
+			return CATPT_IPC_ERROR(ret);
+		fallthrough;
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	resume_stream:
+		ret = catpt_ipc_resume_stream(cdev, stream->info.stream_hw_id);
+		if (ret)
+			return CATPT_IPC_ERROR(ret);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		stream->prepared = false;
+		catpt_dsp_update_lpclock(cdev);
+		fallthrough;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ret = catpt_ipc_pause_stream(cdev, stream->info.stream_hw_id);
+		if (ret)
+			return CATPT_IPC_ERROR(ret);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+void catpt_stream_update_position(struct catpt_dev *cdev,
+				  struct catpt_stream_runtime *stream,
+				  struct catpt_notify_position *pos)
+{
+	struct snd_pcm_substream *substream = stream->substream;
+	struct snd_pcm_runtime *r = substream->runtime;
+	snd_pcm_uframes_t dsppos, newpos;
+	int ret;
+
+	dsppos = bytes_to_frames(r, pos->stream_position);
+
+	/* only offload is set_write_pos driven */
+	if (stream->template->type != CATPT_STRM_TYPE_RENDER)
+		goto exit;
+
+	if (dsppos >= r->buffer_size / 2)
+		newpos = r->buffer_size / 2;
+	else
+		newpos = 0;
+	/*
+	 * Dsp operates on buffer halves, thus on every notify position
+	 * (buffer half consumed) update wp to allow stream progression
+	 */
+	ret = catpt_ipc_set_write_pos(cdev, stream->info.stream_hw_id,
+				      frames_to_bytes(r, newpos),
+				      false, false);
+	if (ret) {
+		dev_err(cdev->dev, "update position for stream %d failed: %d\n",
+			stream->info.stream_hw_id, ret);
+		return;
+	}
+exit:
+	snd_pcm_period_elapsed(substream);
+}
+
+#define CATPT_BUFFER_MAX_SIZE	76800 /* 200ms native format */
+#define CATPT_PCM_PERIODS_MAX	4
+#define CATPT_PCM_PERIODS_MIN	2
+
+static const struct snd_pcm_hardware catpt_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_PAUSE |
+				  SNDRV_PCM_INFO_RESUME |
+				  SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
+				  SNDRV_PCM_FMTBIT_S24_LE |
+				  SNDRV_PCM_FMTBIT_S32_LE,
+	.period_bytes_min	= PAGE_SIZE,
+	.period_bytes_max	= CATPT_BUFFER_MAX_SIZE / CATPT_PCM_PERIODS_MIN,
+	.periods_min		= CATPT_PCM_PERIODS_MIN,
+	.periods_max		= CATPT_PCM_PERIODS_MAX,
+	.buffer_bytes_max	= CATPT_BUFFER_MAX_SIZE,
+};
+
+static int catpt_component_pcm_construct(struct snd_soc_component *component,
+					 struct snd_soc_pcm_runtime *rtd)
+{
+	struct catpt_dev *cdev = dev_get_drvdata(component->dev);
+
+	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV_SG,
+				       cdev->dev,
+				       catpt_pcm_hardware.buffer_bytes_max,
+				       catpt_pcm_hardware.buffer_bytes_max);
+
+	return 0;
+}
+
+static int catpt_component_open(struct snd_soc_component *component,
+				struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtm = substream->private_data;
+
+	if (rtm->dai_link->no_pcm)
+		return 0;
+	snd_soc_set_runtime_hwparams(substream, &catpt_pcm_hardware);
+	return 0;
+}
+
+static snd_pcm_uframes_t
+catpt_component_pointer(struct snd_soc_component *component,
+			struct snd_pcm_substream *substream)
+{
+	struct catpt_dev *cdev = dev_get_drvdata(component->dev);
+	struct catpt_stream_runtime *stream;
+	struct snd_soc_pcm_runtime *rtm = substream->private_data;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtm, 0);
+	u32 pos;
+
+	if (rtm->dai_link->no_pcm)
+		return 0;
+
+	stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
+	pos = catpt_stream_read_position(cdev, stream);
+
+	return bytes_to_frames(substream->runtime, pos);
+}
+
+static const struct snd_soc_dai_ops catpt_fe_dai_ops = {
+	.startup = catpt_dai_startup,
+	.shutdown = catpt_dai_shutdown,
+	.hw_params = catpt_dai_hw_params,
+	.hw_free = catpt_dai_hw_free,
+	.prepare = catpt_dai_prepare,
+	.trigger = catpt_dai_trigger,
+};
+
+static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtd,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
+	struct catpt_ssp_device_format devfmt;
+	int ret;
+
+	devfmt.iface = dai->driver->id;
+	devfmt.channels = codec_dai->driver->capture.channels_max;
+
+	switch (devfmt.iface) {
+	case CATPT_SSP_IFACE_0:
+		devfmt.mclk = CATPT_MCLK_FREQ_24_MHZ;
+
+		switch (devfmt.channels) {
+		case 4:
+			devfmt.mode = CATPT_SSP_MODE_TDM_MASTER;
+			devfmt.clock_divider = 4;
+			break;
+		case 2:
+		default:
+			devfmt.mode = CATPT_SSP_MODE_I2S_MASTER;
+			devfmt.clock_divider = 9;
+			break;
+		}
+		break;
+
+	case CATPT_SSP_IFACE_1:
+		devfmt.mclk = CATPT_MCLK_OFF;
+		devfmt.mode = CATPT_SSP_MODE_I2S_SLAVE;
+		devfmt.clock_divider = 0;
+		break;
+	}
+
+	ret = catpt_ipc_set_device_format(cdev, &devfmt);
+	if (ret)
+		return CATPT_IPC_ERROR(ret);
+
+	/* store device format set for given SSP */
+	memcpy(&cdev->devfmt[devfmt.iface], &devfmt, sizeof(devfmt));
+	return 0;
+}
+
+static struct snd_soc_dai_driver dai_drivers[] = {
+/* FE DAIs */
+{
+	.name  = "System Pin",
+	.id = CATPT_STRM_TYPE_SYSTEM,
+	.ops = &catpt_fe_dai_ops,
+	.playback = {
+		.stream_name = "System Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+	.capture = {
+		.stream_name = "Analog Capture",
+		.channels_min = 2,
+		.channels_max = 4,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+},
+{
+	.name  = "Offload0 Pin",
+	.id = CATPT_STRM_TYPE_RENDER,
+	.ops = &catpt_fe_dai_ops,
+	.playback = {
+		.stream_name = "Offload0 Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+},
+{
+	.name  = "Offload1 Pin",
+	.id = CATPT_STRM_TYPE_RENDER,
+	.ops = &catpt_fe_dai_ops,
+	.playback = {
+		.stream_name = "Offload1 Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+},
+{
+	.name  = "Loopback Pin",
+	.id = CATPT_STRM_TYPE_LOOPBACK,
+	.ops = &catpt_fe_dai_ops,
+	.capture = {
+		.stream_name = "Loopback Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+},
+{
+	.name  = "Bluetooth Pin",
+	.id = CATPT_STRM_TYPE_BLUETOOTH_RENDER,
+	.ops = &catpt_fe_dai_ops,
+	.playback = {
+		.stream_name = "Bluetooth Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "Bluetooth Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+},
+/* BE DAIs */
+{
+	.name = "ssp0-port",
+	.id = CATPT_SSP_IFACE_0,
+	.pcm_new = catpt_dai_pcm_new,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 8,
+	},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 8,
+	},
+},
+{
+	.name = "ssp1-port",
+	.id = CATPT_SSP_IFACE_1,
+	.pcm_new = catpt_dai_pcm_new,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 8,
+	},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 8,
+	},
+},
+};
+
+#define DSP_VOLUME_MAX	0x7FFFFFFF /* 0db */
+
+static const u32 volume_map[] = {
+	DSP_VOLUME_MAX >> 30,
+	DSP_VOLUME_MAX >> 29,
+	DSP_VOLUME_MAX >> 28,
+	DSP_VOLUME_MAX >> 27,
+	DSP_VOLUME_MAX >> 26,
+	DSP_VOLUME_MAX >> 25,
+	DSP_VOLUME_MAX >> 24,
+	DSP_VOLUME_MAX >> 23,
+	DSP_VOLUME_MAX >> 22,
+	DSP_VOLUME_MAX >> 21,
+	DSP_VOLUME_MAX >> 20,
+	DSP_VOLUME_MAX >> 19,
+	DSP_VOLUME_MAX >> 18,
+	DSP_VOLUME_MAX >> 17,
+	DSP_VOLUME_MAX >> 16,
+	DSP_VOLUME_MAX >> 15,
+	DSP_VOLUME_MAX >> 14,
+	DSP_VOLUME_MAX >> 13,
+	DSP_VOLUME_MAX >> 12,
+	DSP_VOLUME_MAX >> 11,
+	DSP_VOLUME_MAX >> 10,
+	DSP_VOLUME_MAX >> 9,
+	DSP_VOLUME_MAX >> 8,
+	DSP_VOLUME_MAX >> 7,
+	DSP_VOLUME_MAX >> 6,
+	DSP_VOLUME_MAX >> 5,
+	DSP_VOLUME_MAX >> 4,
+	DSP_VOLUME_MAX >> 3,
+	DSP_VOLUME_MAX >> 2,
+	DSP_VOLUME_MAX >> 1,
+	DSP_VOLUME_MAX >> 0,
+};
+
+static u32 ctlvol_to_dspvol(u32 value)
+{
+	if (value >= ARRAY_SIZE(volume_map))
+		value = 0;
+	return volume_map[value];
+}
+
+static u32 dspvol_to_ctlvol(u32 volume)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(volume_map); i++)
+		if (volume_map[i] >= volume)
+			return i;
+	return i - 1;
+}
+
+static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol)
+{
+	bool all_equal = true;
+	u32 dspvol;
+	int ret, i;
+
+	for (i = 1; all_equal && i < CATPT_CHANNELS_MAX; i++)
+		all_equal = (ctlvol[i] == ctlvol[0]);
+
+	if (all_equal) {
+		dspvol = ctlvol_to_dspvol(ctlvol[0]);
+
+		ret = catpt_ipc_set_volume(cdev, stream_id,
+					   CATPT_ALL_CHANNELS_MASK, dspvol,
+					   0, CATPT_AUDIO_CURVE_NONE);
+	} else {
+		for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
+			dspvol = ctlvol_to_dspvol(ctlvol[i]);
+
+			ret = catpt_ipc_set_volume(cdev, stream_id,
+						   i, dspvol,
+						   0, CATPT_AUDIO_CURVE_NONE);
+			if (ret)
+				goto exit;
+		}
+	}
+exit:
+	if (ret)
+		return CATPT_IPC_ERROR(ret);
+	return 0;
+}
+
+static int catpt_volume_info(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = CATPT_CHANNELS_MAX;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = ARRAY_SIZE(volume_map) - 1;
+	return 0;
+}
+
+static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct catpt_dev *cdev = dev_get_drvdata(component->dev);
+	u32 dspvol;
+	int i;
+
+	pm_runtime_get_sync(cdev->dev);
+
+	for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
+		dspvol = catpt_mixer_volume(cdev, &cdev->mixer, i);
+		ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol);
+	}
+
+	pm_runtime_mark_last_busy(cdev->dev);
+	pm_runtime_put_autosuspend(cdev->dev);
+
+	return 0;
+}
+
+static int catpt_mixer_volume_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct catpt_dev *cdev = dev_get_drvdata(component->dev);
+	int ret;
+
+	pm_runtime_get_sync(cdev->dev);
+
+	ret = catpt_set_dspvol(cdev, cdev->mixer.mixer_hw_id,
+			       ucontrol->value.integer.value);
+
+	pm_runtime_mark_last_busy(cdev->dev);
+	pm_runtime_put_autosuspend(cdev->dev);
+
+	return ret;
+}
+
+static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol,
+				   enum catpt_pin_id pin_id)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct catpt_dev *cdev = dev_get_drvdata(component->dev);
+	struct catpt_stream_runtime *stream;
+	long *ctlvol = (long *)kcontrol->private_value;
+	u32 dspvol;
+	int i;
+
+	stream = catpt_stream_find(cdev, pin_id);
+	if (!stream) {
+		for (i = 0; i < CATPT_CHANNELS_MAX; i++)
+			ucontrol->value.integer.value[i] = ctlvol[i];
+		return 0;
+	}
+
+	pm_runtime_get_sync(cdev->dev);
+
+	for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
+		dspvol = catpt_stream_volume(cdev, stream, i);
+		ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol);
+	}
+
+	pm_runtime_mark_last_busy(cdev->dev);
+	pm_runtime_put_autosuspend(cdev->dev);
+
+	return 0;
+}
+
+static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol,
+				   enum catpt_pin_id pin_id)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct catpt_dev *cdev = dev_get_drvdata(component->dev);
+	struct catpt_stream_runtime *stream;
+	long *ctlvol = (long *)kcontrol->private_value;
+	int ret, i;
+
+	stream = catpt_stream_find(cdev, pin_id);
+	if (!stream) {
+		for (i = 0; i < CATPT_CHANNELS_MAX; i++)
+			ctlvol[i] = ucontrol->value.integer.value[i];
+		return 0;
+	}
+
+	pm_runtime_get_sync(cdev->dev);
+
+	ret = catpt_set_dspvol(cdev, stream->info.stream_hw_id,
+			       ucontrol->value.integer.value);
+
+	pm_runtime_mark_last_busy(cdev->dev);
+	pm_runtime_put_autosuspend(cdev->dev);
+
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < CATPT_CHANNELS_MAX; i++)
+		ctlvol[i] = ucontrol->value.integer.value[i];
+	return 0;
+}
+
+static int catpt_offload1_volume_get(struct snd_kcontrol *kctl,
+				     struct snd_ctl_elem_value *uctl)
+{
+	return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_OFFLOAD1);
+}
+
+static int catpt_offload1_volume_put(struct snd_kcontrol *kctl,
+				     struct snd_ctl_elem_value *uctl)
+{
+	return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_OFFLOAD1);
+}
+
+static int catpt_offload2_volume_get(struct snd_kcontrol *kctl,
+				     struct snd_ctl_elem_value *uctl)
+{
+	return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_OFFLOAD2);
+}
+
+static int catpt_offload2_volume_put(struct snd_kcontrol *kctl,
+				     struct snd_ctl_elem_value *uctl)
+{
+	return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_OFFLOAD2);
+}
+
+static int catpt_capture_volume_get(struct snd_kcontrol *kctl,
+				    struct snd_ctl_elem_value *uctl)
+{
+	return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_CAPTURE1);
+}
+
+static int catpt_capture_volume_put(struct snd_kcontrol *kctl,
+				    struct snd_ctl_elem_value *uctl)
+{
+	return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_CAPTURE1);
+}
+
+static int catpt_loopback_switch_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = *(bool *)kcontrol->private_value;
+	return 0;
+}
+
+static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_kcontrol_component(kcontrol);
+	struct catpt_dev *cdev = dev_get_drvdata(component->dev);
+	struct catpt_stream_runtime *stream;
+	bool mute;
+	int ret;
+
+	mute = (bool)ucontrol->value.integer.value[0];
+	stream = catpt_stream_find(cdev, CATPT_PIN_ID_REFERENCE);
+	if (!stream) {
+		*(bool *)kcontrol->private_value = mute;
+		return 0;
+	}
+
+	pm_runtime_get_sync(cdev->dev);
+
+	ret = catpt_ipc_mute_loopback(cdev, stream->info.stream_hw_id, mute);
+
+	pm_runtime_mark_last_busy(cdev->dev);
+	pm_runtime_put_autosuspend(cdev->dev);
+
+	if (ret)
+		return CATPT_IPC_ERROR(ret);
+
+	*(bool *)kcontrol->private_value = mute;
+	return 0;
+}
+
+static int catpt_waves_switch_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	return 0;
+}
+
+static int catpt_waves_switch_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	return 0;
+}
+
+static int catpt_waves_param_get(struct snd_kcontrol *kcontrol,
+				 unsigned int __user *bytes,
+				 unsigned int size)
+{
+	return 0;
+}
+
+static int catpt_waves_param_put(struct snd_kcontrol *kcontrol,
+				 const unsigned int __user *bytes,
+				 unsigned int size)
+{
+	return 0;
+}
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(catpt_volume_tlv, -9000, 300, 1);
+
+#define CATPT_VOLUME_CTL(kname, sname) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+	.name = (kname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+		  SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.info = catpt_volume_info, \
+	.get = catpt_##sname##_volume_get, \
+	.put = catpt_##sname##_volume_put, \
+	.tlv.p = catpt_volume_tlv, \
+	.private_value = (unsigned long) \
+		&(long[CATPT_CHANNELS_MAX]) {0} }
+
+static const struct snd_kcontrol_new component_kcontrols[] = {
+/* Master volume (mixer stream) */
+CATPT_VOLUME_CTL("Master Playback Volume", mixer),
+/* Individual volume controls for offload and capture */
+CATPT_VOLUME_CTL("Media0 Playback Volume", offload1),
+CATPT_VOLUME_CTL("Media1 Playback Volume", offload2),
+CATPT_VOLUME_CTL("Mic Capture Volume", capture),
+SOC_SINGLE_BOOL_EXT("Loopback Mute", (unsigned long)&(bool[1]) {0},
+		    catpt_loopback_switch_get, catpt_loopback_switch_put),
+/* Enable or disable WAVES module */
+SOC_SINGLE_BOOL_EXT("Waves Switch", 0,
+		    catpt_waves_switch_get, catpt_waves_switch_put),
+/* WAVES module parameter control */
+SND_SOC_BYTES_TLV("Waves Set Param", 128,
+		  catpt_waves_param_get, catpt_waves_param_put),
+};
+
+static const struct snd_soc_dapm_widget component_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("SSP0 CODEC IN", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SSP0 CODEC OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SSP1 BT IN", NULL, 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SSP1 BT OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MIXER("Playback VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route component_routes[] = {
+	{"Playback VMixer", NULL, "System Playback"},
+	{"Playback VMixer", NULL, "Offload0 Playback"},
+	{"Playback VMixer", NULL, "Offload1 Playback"},
+
+	{"SSP0 CODEC OUT", NULL, "Playback VMixer"},
+
+	{"Analog Capture", NULL, "SSP0 CODEC IN"},
+	{"Loopback Capture", NULL, "SSP0 CODEC IN"},
+
+	{"SSP1 BT OUT", NULL, "Bluetooth Playback"},
+	{"Bluetooth Capture", NULL, "SSP1 BT IN"},
+};
+
+static const struct snd_soc_component_driver catpt_comp_driver = {
+	.name = "catpt-platform",
+
+	.pcm_construct = catpt_component_pcm_construct,
+	.open = catpt_component_open,
+	.pointer = catpt_component_pointer,
+
+	.controls = component_kcontrols,
+	.num_controls = ARRAY_SIZE(component_kcontrols),
+	.dapm_widgets = component_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(component_widgets),
+	.dapm_routes = component_routes,
+	.num_dapm_routes = ARRAY_SIZE(component_routes),
+};
+
+int catpt_arm_stream_templates(struct catpt_dev *cdev)
+{
+	struct resource *res;
+	u32 scratch_size = 0;
+	int i, j;
+
+	for (i = 0; i < ARRAY_SIZE(catpt_topology); i++) {
+		struct catpt_stream_template *template;
+		struct catpt_module_entry *entry;
+		struct catpt_module_type *type;
+
+		template = catpt_topology[i];
+		template->persistent_size = 0;
+
+		for (j = 0; j < template->num_entries; j++) {
+			entry = &template->entries[j];
+			type = &cdev->modules[entry->module_id];
+
+			if (!type->loaded)
+				return -ENOENT;
+
+			entry->entry_point = type->entry_point;
+			template->persistent_size += type->persistent_size;
+			if (type->scratch_size > scratch_size)
+				scratch_size = type->scratch_size;
+		}
+	}
+
+	if (scratch_size) {
+		/* allocate single scratch area for all modules */
+		res = catpt_request_region(&cdev->dram, scratch_size);
+		if (!res)
+			return -EBUSY;
+		cdev->scratch = res;
+	}
+
+	return 0;
+}
+
+int catpt_register_plat_component(struct catpt_dev *cdev)
+{
+	struct snd_soc_component *component;
+	int ret;
+
+	component = devm_kzalloc(cdev->dev, sizeof(*component), GFP_KERNEL);
+	if (!component)
+		return -ENOMEM;
+
+	ret = snd_soc_component_initialize(component, &catpt_comp_driver,
+					   cdev->dev);
+	if (ret < 0)
+		return ret;
+
+	component->name = catpt_comp_driver.name;
+	return snd_soc_add_component(component, dai_drivers,
+				     ARRAY_SIZE(dai_drivers));
+}
-- 
2.17.1


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

* [PATCH v4 07/13] ASoC: Intel: catpt: Event tracing
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
                   ` (5 preceding siblings ...)
  2020-08-12 20:57 ` [PATCH v4 06/13] ASoC: Intel: catpt: PCM operations Cezary Rojewski
@ 2020-08-12 20:57 ` Cezary Rojewski
  2020-08-12 20:57 ` [PATCH v4 08/13] ASoC: Intel: catpt: Simple sysfs attributes Cezary Rojewski
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-12 20:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: pierre-louis.bossart, Cezary Rojewski, andriy.shevchenko,
	filip.kaczmarski, harshapriya.n, marcin.barlik, zwisler,
	lgirdwood, tiwai, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

Define tracing macros for easy catpt debug. These cover all IPC message
types: requests, replies and notifications.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/catpt/trace.h | 83 +++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)
 create mode 100644 sound/soc/intel/catpt/trace.h

diff --git a/sound/soc/intel/catpt/trace.h b/sound/soc/intel/catpt/trace.h
new file mode 100644
index 000000000000..bb3d627dbeaf
--- /dev/null
+++ b/sound/soc/intel/catpt/trace.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2020 Intel Corporation. All rights reserved.
+ *
+ * Author: Cezary Rojewski <cezary.rojewski@intel.com>
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM intel_catpt
+
+#if !defined(__SND_SOC_INTEL_CATPT_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __SND_SOC_INTEL_CATPT_TRACE_H
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(catpt_ipc_msg,
+
+	TP_PROTO(u32 header),
+
+	TP_ARGS(header),
+
+	TP_STRUCT__entry(
+		__field(u32, header)
+	),
+
+	TP_fast_assign(
+		__entry->header = header;
+	),
+
+	TP_printk("0x%08x", __entry->header)
+);
+
+DEFINE_EVENT(catpt_ipc_msg, catpt_irq,
+	TP_PROTO(u32 header),
+	TP_ARGS(header)
+);
+
+DEFINE_EVENT(catpt_ipc_msg, catpt_ipc_request,
+	TP_PROTO(u32 header),
+	TP_ARGS(header)
+);
+
+DEFINE_EVENT(catpt_ipc_msg, catpt_ipc_reply,
+	TP_PROTO(u32 header),
+	TP_ARGS(header)
+);
+
+DEFINE_EVENT(catpt_ipc_msg, catpt_ipc_notify,
+	TP_PROTO(u32 header),
+	TP_ARGS(header)
+);
+
+TRACE_EVENT_CONDITION(catpt_ipc_payload,
+
+	TP_PROTO(const u8 *data, size_t size),
+
+	TP_ARGS(data, size),
+
+	TP_CONDITION(data && size),
+
+	TP_STRUCT__entry(
+		__dynamic_array(u8, buf, size)
+	),
+
+	TP_fast_assign(
+		memcpy(__get_dynamic_array(buf), data, size);
+	),
+
+	TP_printk("%u byte(s)%s",
+		  __get_dynamic_array_len(buf),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 16, 4,
+				   __get_dynamic_array(buf),
+				   __get_dynamic_array_len(buf), false))
+);
+
+#endif /* __SND_SOC_INTEL_CATPT_TRACE_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace
+#include <trace/define_trace.h>
-- 
2.17.1


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

* [PATCH v4 08/13] ASoC: Intel: catpt: Simple sysfs attributes
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
                   ` (6 preceding siblings ...)
  2020-08-12 20:57 ` [PATCH v4 07/13] ASoC: Intel: catpt: Event tracing Cezary Rojewski
@ 2020-08-12 20:57 ` Cezary Rojewski
  2020-08-12 20:57 ` [PATCH v4 09/13] ASoC: Intel: Select catpt and deprecate haswell Cezary Rojewski
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-12 20:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: pierre-louis.bossart, Cezary Rojewski, andriy.shevchenko,
	filip.kaczmarski, harshapriya.n, marcin.barlik, zwisler,
	lgirdwood, tiwai, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

Add sysfs entries for displaying version of FW currently in use as well
as binary dump of entire version info, including build and log providers
hashes.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/catpt/fs.c | 79 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 sound/soc/intel/catpt/fs.c

diff --git a/sound/soc/intel/catpt/fs.c b/sound/soc/intel/catpt/fs.c
new file mode 100644
index 000000000000..d73493687f4a
--- /dev/null
+++ b/sound/soc/intel/catpt/fs.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-pcm
+//
+// Copyright(c) 2020 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/pm_runtime.h>
+#include "core.h"
+
+static ssize_t fw_version_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct catpt_dev *cdev = dev_get_drvdata(dev);
+	struct catpt_fw_version version;
+	int ret;
+
+	pm_runtime_get_sync(cdev->dev);
+
+	ret = catpt_ipc_get_fw_version(cdev, &version);
+
+	pm_runtime_mark_last_busy(cdev->dev);
+	pm_runtime_put_autosuspend(cdev->dev);
+
+	if (ret)
+		return CATPT_IPC_ERROR(ret);
+
+	return sprintf(buf, "%d.%d.%d.%d\n", version.type, version.major,
+		       version.minor, version.build);
+}
+
+static DEVICE_ATTR_RO(fw_version);
+
+static ssize_t fw_build_read(struct file *filp, struct kobject *kobj,
+			     struct bin_attribute *bin_attr, char *buf,
+			     loff_t off, size_t count)
+{
+	struct catpt_dev *cdev = dev_get_drvdata(kobj_to_dev(kobj));
+	struct catpt_fw_version version;
+	int ret;
+
+	pm_runtime_get_sync(cdev->dev);
+
+	ret = catpt_ipc_get_fw_version(cdev, &version);
+
+	pm_runtime_mark_last_busy(cdev->dev);
+	pm_runtime_put_autosuspend(cdev->dev);
+
+	if (ret)
+		return CATPT_IPC_ERROR(ret);
+
+	memcpy(buf, &version, sizeof(version));
+	return count;
+}
+
+static BIN_ATTR_RO(fw_build, sizeof(struct catpt_fw_version));
+
+int catpt_sysfs_create(struct catpt_dev *cdev)
+{
+	int ret;
+
+	ret = sysfs_create_file(&cdev->dev->kobj, &dev_attr_fw_version.attr);
+	if (ret)
+		return ret;
+
+	ret = sysfs_create_bin_file(&cdev->dev->kobj, &bin_attr_fw_build);
+	if (ret) {
+		sysfs_remove_file(&cdev->dev->kobj, &dev_attr_fw_version.attr);
+		return ret;
+	}
+
+	return 0;
+}
+
+void catpt_sysfs_remove(struct catpt_dev *cdev)
+{
+	sysfs_remove_bin_file(&cdev->dev->kobj, &bin_attr_fw_build);
+	sysfs_remove_file(&cdev->dev->kobj, &dev_attr_fw_version.attr);
+}
-- 
2.17.1


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

* [PATCH v4 09/13] ASoC: Intel: Select catpt and deprecate haswell
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
                   ` (7 preceding siblings ...)
  2020-08-12 20:57 ` [PATCH v4 08/13] ASoC: Intel: catpt: Simple sysfs attributes Cezary Rojewski
@ 2020-08-12 20:57 ` Cezary Rojewski
  2020-08-12 20:57 ` [PATCH v4 10/13] ASoC: Intel: haswell: Remove haswell-solution specific code Cezary Rojewski
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-12 20:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: pierre-louis.bossart, Cezary Rojewski, andriy.shevchenko,
	filip.kaczmarski, harshapriya.n, marcin.barlik, zwisler,
	lgirdwood, tiwai, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

Prevent sound/soc/intel/haswell code compile and select catpt instead as
a recommended solution. Userspace-exposed members are compatible with
what is exposed by deprecated solution thus no harm is done. The only
visible difference is the newly added 'Loopback Mute' kcontrol.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/Kconfig        | 22 +++++++++++-----------
 sound/soc/intel/Makefile       |  2 +-
 sound/soc/intel/boards/Kconfig |  8 ++++----
 sound/soc/intel/catpt/Makefile |  6 ++++++
 4 files changed, 22 insertions(+), 16 deletions(-)
 create mode 100644 sound/soc/intel/catpt/Makefile

diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 82805a8681e5..4a18e8f83eeb 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -47,21 +47,21 @@ config SND_SOC_INTEL_SST_FIRMWARE
 	# Haswell/Broadwell/Baytrail legacy and will be set
 	# when these platforms are enabled
 
-config SND_SOC_INTEL_HASWELL
-	tristate "Haswell/Broadwell Platforms"
+config SND_SOC_INTEL_CATPT
+	tristate "Haswell and Broadwell"
 	depends on SND_DMA_SGBUF
 	depends on DMADEVICES && ACPI
-	select SND_SOC_INTEL_SST
-	select SND_SOC_INTEL_SST_ACPI
-	select SND_SOC_INTEL_SST_FIRMWARE
+	select DW_DMAC_CORE
 	select SND_SOC_ACPI_INTEL_MATCH
 	help
-	  If you have a Intel Haswell or Broadwell platform connected to
-	  an I2S codec, then enable this option by saying Y or m. This is
-	  typically used for Chromebooks. This is a recommended option.
-	  This option is mutually exclusive with the SOF support on
-	  Broadwell. If you want to enable SOF on Broadwell, you need to
-	  deselect this option first.
+	  Enable support for Intel(R) Haswell and Broadwell platforms
+	  with I2S codec present. This is a recommended option.
+	  Say Y or m if you have such device.
+	  If unsure, say N.
+
+config SND_SOC_INTEL_HASWELL
+	tristate
+	select SND_SOC_INTEL_CATPT
 
 config SND_SOC_INTEL_BAYTRAIL
 	tristate "Baytrail (legacy) Platforms"
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index 04ee48204fc9..c88c615f85f7 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -3,9 +3,9 @@
 obj-$(CONFIG_SND_SOC) += common/
 
 # Platform Support
-obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/
 obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/
 obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += atom/
+obj-$(CONFIG_SND_SOC_INTEL_CATPT) += catpt/
 obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += skylake/
 obj-$(CONFIG_SND_SOC_INTEL_KEEMBAY) += keembay/
 
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index d96fc1313434..f4358c33059b 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -26,7 +26,7 @@ config SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES
 	  interface.
 	  If unsure select N.
 
-if SND_SOC_INTEL_HASWELL
+if SND_SOC_INTEL_CATPT
 
 config SND_SOC_INTEL_HASWELL_MACH
 	tristate "Haswell Lynxpoint"
@@ -40,9 +40,9 @@ config SND_SOC_INTEL_HASWELL_MACH
 	  Say Y or m if you have such a device.
 	  If unsure select "N".
 
-endif ## SND_SOC_INTEL_HASWELL
+endif ## SND_SOC_INTEL_CATPT
 
-if SND_SOC_INTEL_HASWELL || SND_SOC_SOF_BROADWELL
+if SND_SOC_INTEL_CATPT || SND_SOC_SOF_BROADWELL
 
 config SND_SOC_INTEL_BDW_RT5650_MACH
 	tristate "Broadwell with RT5650 codec"
@@ -83,7 +83,7 @@ config SND_SOC_INTEL_BROADWELL_MACH
 	  Ultrabook platforms.
 	  Say Y or m if you have such a device. This is a recommended option.
 	  If unsure select "N".
-endif ## SND_SOC_INTEL_HASWELL || SND_SOC_SOF_BROADWELL
+endif ## SND_SOC_INTEL_CATPT || SND_SOC_SOF_BROADWELL
 
 if SND_SOC_INTEL_BAYTRAIL
 
diff --git a/sound/soc/intel/catpt/Makefile b/sound/soc/intel/catpt/Makefile
new file mode 100644
index 000000000000..0717190106d9
--- /dev/null
+++ b/sound/soc/intel/catpt/Makefile
@@ -0,0 +1,6 @@
+snd-soc-catpt-objs := device.o dsp.o loader.o ipc.o messages.o pcm.o fs.o
+
+# tell define_trace.h where to find the trace header
+CFLAGS_device.o := -I$(src)
+
+obj-$(CONFIG_SND_SOC_INTEL_CATPT) += snd-soc-catpt.o
-- 
2.17.1


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

* [PATCH v4 10/13] ASoC: Intel: haswell: Remove haswell-solution specific code
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
                   ` (8 preceding siblings ...)
  2020-08-12 20:57 ` [PATCH v4 09/13] ASoC: Intel: Select catpt and deprecate haswell Cezary Rojewski
@ 2020-08-12 20:57 ` Cezary Rojewski
  2020-08-13 18:57   ` Andy Shevchenko
  2020-08-12 20:57 ` [PATCH v4 11/13] ASoC: Intel: broadwell: " Cezary Rojewski
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-12 20:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: pierre-louis.bossart, Cezary Rojewski, andriy.shevchenko,
	filip.kaczmarski, harshapriya.n, marcin.barlik, zwisler,
	lgirdwood, tiwai, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

Remove code specific to sound/soc/intel/haswell. Update BE dai_link
definition to provide seamless transition to catpt solution.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/boards/haswell.c | 28 ++++------------------------
 1 file changed, 4 insertions(+), 24 deletions(-)

diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c
index 744b7b5b8106..c268405e5594 100644
--- a/sound/soc/intel/boards/haswell.c
+++ b/sound/soc/intel/boards/haswell.c
@@ -13,9 +13,6 @@
 #include <sound/soc-acpi.h>
 #include <sound/pcm_params.h>
 
-#include "../common/sst-dsp.h"
-#include "../haswell/sst-haswell-ipc.h"
-
 #include "../../codecs/rt5640.h"
 
 /* Haswell ULT platforms have a Headphone and Mic jack */
@@ -77,25 +74,6 @@ static const struct snd_soc_ops haswell_rt5640_ops = {
 	.hw_params = haswell_rt5640_hw_params,
 };
 
-static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
-	struct sst_pdata *pdata = dev_get_platdata(component->dev);
-	struct sst_hsw *haswell = pdata->dsp;
-	int ret;
-
-	/* Set ADSP SSP port settings */
-	ret = sst_hsw_device_set_config(haswell, SST_HSW_DEVICE_SSP_0,
-		SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
-		SST_HSW_DEVICE_CLOCK_MASTER, 9);
-	if (ret < 0) {
-		dev_err(rtd->dev, "failed to set device config\n");
-		return ret;
-	}
-
-	return 0;
-}
-
 SND_SOC_DAILINK_DEF(dummy,
 	DAILINK_COMP_ARRAY(COMP_DUMMY()));
 
@@ -117,13 +95,15 @@ SND_SOC_DAILINK_DEF(codec,
 SND_SOC_DAILINK_DEF(platform,
 	DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
 
+SND_SOC_DAILINK_DEF(ssp0_port,
+	    DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
+
 static struct snd_soc_dai_link haswell_rt5640_dais[] = {
 	/* Front End DAI links */
 	{
 		.name = "System",
 		.stream_name = "System Playback/Capture",
 		.dynamic = 1,
-		.init = haswell_rtd_init,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
 		.dpcm_playback = 1,
 		.dpcm_capture = 1,
@@ -167,7 +147,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = {
 		.ops = &haswell_rt5640_ops,
 		.dpcm_playback = 1,
 		.dpcm_capture = 1,
-		SND_SOC_DAILINK_REG(dummy, codec, dummy),
+		SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
 	},
 };
 
-- 
2.17.1


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

* [PATCH v4 11/13] ASoC: Intel: broadwell: Remove haswell-solution specific code
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
                   ` (9 preceding siblings ...)
  2020-08-12 20:57 ` [PATCH v4 10/13] ASoC: Intel: haswell: Remove haswell-solution specific code Cezary Rojewski
@ 2020-08-12 20:57 ` Cezary Rojewski
  2020-08-13 18:56   ` Andy Shevchenko
  2020-08-12 20:57 ` [PATCH v4 12/13] ASoC: Intel: bdw-5650: " Cezary Rojewski
                   ` (3 subsequent siblings)
  14 siblings, 1 reply; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-12 20:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: pierre-louis.bossart, Cezary Rojewski, andriy.shevchenko,
	filip.kaczmarski, harshapriya.n, marcin.barlik, zwisler,
	lgirdwood, tiwai, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

Remove code specific to sound/soc/intel/haswell. Update BE dai_link
definition to provide seamless transition to catpt solution.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/boards/broadwell.c | 33 ------------------------------
 1 file changed, 33 deletions(-)

diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c
index f6399077d291..ea2818f27105 100644
--- a/sound/soc/intel/boards/broadwell.c
+++ b/sound/soc/intel/boards/broadwell.c
@@ -14,9 +14,6 @@
 #include <sound/pcm_params.h>
 #include <sound/soc-acpi.h>
 
-#include "../common/sst-dsp.h"
-#include "../haswell/sst-haswell-ipc.h"
-
 #include "../../codecs/rt286.h"
 
 static struct snd_soc_jack broadwell_headset;
@@ -122,27 +119,6 @@ static const struct snd_soc_ops broadwell_rt286_ops = {
 	.hw_params = broadwell_rt286_hw_params,
 };
 
-#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
-static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
-	struct sst_pdata *pdata = dev_get_platdata(component->dev);
-	struct sst_hsw *broadwell = pdata->dsp;
-	int ret;
-
-	/* Set ADSP SSP port settings */
-	ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0,
-		SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
-		SST_HSW_DEVICE_CLOCK_MASTER, 9);
-	if (ret < 0) {
-		dev_err(rtd->dev, "error: failed to set device config\n");
-		return ret;
-	}
-
-	return 0;
-}
-#endif
-
 static const unsigned int channels[] = {
 	2,
 };
@@ -189,10 +165,8 @@ SND_SOC_DAILINK_DEF(platform,
 SND_SOC_DAILINK_DEF(codec,
 	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1")));
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
 SND_SOC_DAILINK_DEF(ssp0_port,
 	    DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
-#endif
 
 /* broadwell digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link broadwell_rt286_dais[] = {
@@ -201,9 +175,6 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
 		.name = "System PCM",
 		.stream_name = "System Playback/Capture",
 		.dynamic = 1,
-#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
-		.init = broadwell_rtd_init,
-#endif
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
 		.ops = &broadwell_fe_ops,
 		.dpcm_playback = 1,
@@ -248,11 +219,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
 		.ops = &broadwell_rt286_ops,
 		.dpcm_playback = 1,
 		.dpcm_capture = 1,
-#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
-		SND_SOC_DAILINK_REG(dummy, codec, dummy),
-#else
 		SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
-#endif
 	},
 };
 
-- 
2.17.1


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

* [PATCH v4 12/13] ASoC: Intel: bdw-5650: Remove haswell-solution specific code
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
                   ` (10 preceding siblings ...)
  2020-08-12 20:57 ` [PATCH v4 11/13] ASoC: Intel: broadwell: " Cezary Rojewski
@ 2020-08-12 20:57 ` Cezary Rojewski
  2020-08-13 18:56   ` Andy Shevchenko
  2020-08-12 20:57 ` [PATCH v4 13/13] ASoC: Intel: bdw-5677: " Cezary Rojewski
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-12 20:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: pierre-louis.bossart, Cezary Rojewski, andriy.shevchenko,
	filip.kaczmarski, harshapriya.n, marcin.barlik, zwisler,
	lgirdwood, tiwai, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

Remove code specific to sound/soc/intel/haswell. Update BE dai_link
definition to provide seamless transition to catpt solution.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/boards/bdw-rt5650.c | 36 -----------------------------
 1 file changed, 36 deletions(-)

diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c
index ce7320916b22..c5820787c53e 100644
--- a/sound/soc/intel/boards/bdw-rt5650.c
+++ b/sound/soc/intel/boards/bdw-rt5650.c
@@ -16,9 +16,6 @@
 #include <sound/soc.h>
 #include <sound/soc-acpi.h>
 
-#include "../common/sst-dsp.h"
-#include "../haswell/sst-haswell-ipc.h"
-
 #include "../../codecs/rt5645.h"
 
 struct bdw_rt5650_priv {
@@ -138,30 +135,6 @@ static struct snd_soc_ops bdw_rt5650_ops = {
 	.hw_params = bdw_rt5650_hw_params,
 };
 
-#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
-static int bdw_rt5650_rtd_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_component *component =
-		snd_soc_rtdcom_lookup(rtd, DRV_NAME);
-	struct sst_pdata *pdata = dev_get_platdata(component->dev);
-	struct sst_hsw *broadwell = pdata->dsp;
-	int ret;
-
-	/* Set ADSP SSP port settings
-	 * clock_divider = 4 means BCLK = MCLK/5 = 24MHz/5 = 4.8MHz
-	 */
-	ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0,
-		SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
-		SST_HSW_DEVICE_TDM_CLOCK_MASTER, 4);
-	if (ret < 0) {
-		dev_err(rtd->dev, "error: failed to set device config\n");
-		return ret;
-	}
-
-	return 0;
-}
-#endif
-
 static const unsigned int channels[] = {
 	2, 4,
 };
@@ -251,10 +224,8 @@ SND_SOC_DAILINK_DEF(platform,
 SND_SOC_DAILINK_DEF(be,
 	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5650:00", "rt5645-aif1")));
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
 SND_SOC_DAILINK_DEF(ssp0_port,
 	    DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
-#endif
 
 static struct snd_soc_dai_link bdw_rt5650_dais[] = {
 	/* Front End DAI links */
@@ -263,9 +234,6 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = {
 		.stream_name = "System Playback",
 		.dynamic = 1,
 		.ops = &bdw_rt5650_fe_ops,
-#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
-		.init = bdw_rt5650_rtd_init,
-#endif
 		.trigger = {
 			SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST
@@ -289,11 +257,7 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = {
 		.dpcm_playback = 1,
 		.dpcm_capture = 1,
 		.init = bdw_rt5650_init,
-#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
-		SND_SOC_DAILINK_REG(dummy, be, dummy),
-#else
 		SND_SOC_DAILINK_REG(ssp0_port, be, platform),
-#endif
 	},
 };
 
-- 
2.17.1


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

* [PATCH v4 13/13] ASoC: Intel: bdw-5677: Remove haswell-solution specific code
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
                   ` (11 preceding siblings ...)
  2020-08-12 20:57 ` [PATCH v4 12/13] ASoC: Intel: bdw-5650: " Cezary Rojewski
@ 2020-08-12 20:57 ` Cezary Rojewski
  2020-08-13 18:57   ` Andy Shevchenko
  2020-08-13  8:30 ` [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Amadeusz Sławiński
  2020-08-13 16:00 ` Liam Girdwood
  14 siblings, 1 reply; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-12 20:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: pierre-louis.bossart, Cezary Rojewski, andriy.shevchenko,
	filip.kaczmarski, harshapriya.n, marcin.barlik, zwisler,
	lgirdwood, tiwai, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

Remove code specific to sound/soc/intel/haswell. Update BE dai_link
definition to provide seamless transition to catpt solution.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/boards/bdw-rt5677.c | 33 -----------------------------
 1 file changed, 33 deletions(-)

diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c
index 86e427e3822f..4451957fc170 100644
--- a/sound/soc/intel/boards/bdw-rt5677.c
+++ b/sound/soc/intel/boards/bdw-rt5677.c
@@ -17,9 +17,6 @@
 #include <sound/jack.h>
 #include <sound/soc-acpi.h>
 
-#include "../common/sst-dsp.h"
-#include "../haswell/sst-haswell-ipc.h"
-
 #include "../../codecs/rt5677.h"
 
 struct bdw_rt5677_priv {
@@ -201,27 +198,6 @@ static const struct snd_soc_ops bdw_rt5677_dsp_ops = {
 	.hw_params = bdw_rt5677_dsp_hw_params,
 };
 
-#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
-static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
-	struct sst_pdata *pdata = dev_get_platdata(component->dev);
-	struct sst_hsw *broadwell = pdata->dsp;
-	int ret;
-
-	/* Set ADSP SSP port settings */
-	ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0,
-		SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
-		SST_HSW_DEVICE_CLOCK_MASTER, 9);
-	if (ret < 0) {
-		dev_err(rtd->dev, "error: failed to set device config\n");
-		return ret;
-	}
-
-	return 0;
-}
-#endif
-
 static const unsigned int channels[] = {
 	2,
 };
@@ -333,10 +309,8 @@ SND_SOC_DAILINK_DEF(platform,
 SND_SOC_DAILINK_DEF(be,
 	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RT5677CE:00", "rt5677-aif1")));
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
 SND_SOC_DAILINK_DEF(ssp0_port,
 	    DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
-#endif
 
 /* Wake on voice interface */
 SND_SOC_DAILINK_DEFS(dsp,
@@ -350,9 +324,6 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = {
 		.name = "System PCM",
 		.stream_name = "System Playback/Capture",
 		.dynamic = 1,
-#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
-		.init = bdw_rt5677_rtd_init,
-#endif
 		.trigger = {
 			SND_SOC_DPCM_TRIGGER_POST,
 			SND_SOC_DPCM_TRIGGER_POST
@@ -387,11 +358,7 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = {
 		.dpcm_capture = 1,
 		.init = bdw_rt5677_init,
 		.exit = bdw_rt5677_exit,
-#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
-		SND_SOC_DAILINK_REG(dummy, be, dummy),
-#else
 		SND_SOC_DAILINK_REG(ssp0_port, be, platform),
-#endif
 	},
 };
 
-- 
2.17.1


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

* Re: [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
                   ` (12 preceding siblings ...)
  2020-08-12 20:57 ` [PATCH v4 13/13] ASoC: Intel: bdw-5677: " Cezary Rojewski
@ 2020-08-13  8:30 ` Amadeusz Sławiński
  2020-08-13 16:00 ` Liam Girdwood
  14 siblings, 0 replies; 43+ messages in thread
From: Amadeusz Sławiński @ 2020-08-13  8:30 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: andriy.shevchenko, filip.kaczmarski, harshapriya.n,
	ppapierkowski, marcin.barlik, zwisler, pierre-louis.bossart,
	lgirdwood, filip.proborszcz, broonie, michal.wasko, tiwai,
	krzysztof.hejmowski, cujomalainey, vamshi.krishna.gopal



On 8/12/2020 10:57 PM, Cezary Rojewski wrote:
> Implement support for Lynxpoint and Wildcat Point AudioDSP. Catpt
> solution deprecates existing sound/soc/intel/haswell which is removed in
> the following series. This cover-letter is followed by 'Developer's deep
> dive' message schedding light on catpt's key concepts and areas
> addressed.
> 
> Due to high range of errors and desynchronization from recommendations
> set by Windows solution, re-write came as a lower-cost solution compared
> to refactoring /haswell/ with several series of patches.
> 
> Special thanks go to Marcin Barlik and Piotr Papierkowski for sharing
> their LPT/WPT AudioDSP architecture expertise as well as helping
> backtrack its historical background.
> My thanks go to Amadeusz Slawinski for reviews and improvements proposed
> on and off the internal list. Most of internal diff below is his
> contribution.
> Krzysztof Hejmowski helped me setup my own Xtensa environment and
> recompile LPT/WPT FW binary sources what sped up the development greatly.
> 
> This would not have been possible without help from these champions,
> especially considering how quickly the catpt was written: 2 weeks
> features, 3 weeks optimizations. Thank you.
> 
> Userspace-exposed members are compatible with what is exposed by
> deprecated solution as well as FW binary being re-used thus no harm is
> done. The only visible differences are: the newly added 'Loopback Mute'
> kcontrol and volume support extending to quad from stereo.
> 
> On top of fixing erros and design flows, catpt also adds module reload,
> dynamic SRAM memory allocation during PCM runtime and exposes missing
> userspace API: 'Loopback Mute' kcontrol, quad volume controls and sysfs
> fw-version entries. Event tracing is provided to easy solution
> debugging.
> 
> Following are not included in this update and are scheduled as later
> addition:
> - fw logging
> - module (library) support
> 
> Note: LPT power up/down sequences might get aligned with WPT once enough
> testing is done as capabilities are shared for both DSPs.
> Note #2: Both LPT and WPT power up/down sequences may get optimized in
> future updates as thanks to help from the Windows team, most of nuances
> behind why/what/when in regard to hw registers have been backtracked and
> reviewed again.
> 
> Link to developer's deep dive message:
> https://www.spinics.net/lists/alsa-devel/msg113563.html
> 
> Changes in v4:
> - fixed compilation with i386 kconfig (conflicting names)
> - streamlined naming for SHIM and PCI registers to match SSP ones
>    (SHIM_REG -> SHIM)
> - catpt_component_probe removed and kcontrols again initializzed
>    statically via snd_kcontrol_new array: this is to remove
>    kctl->id.device shenanigans
> - renamed catpt_set_ctlvol to catpt_set_dspvol - function name wasn't
>    matching its purpose
> 

I see nothing more, so once again:

Reviewed-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>

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

* Re: [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point
  2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
                   ` (13 preceding siblings ...)
  2020-08-13  8:30 ` [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Amadeusz Sławiński
@ 2020-08-13 16:00 ` Liam Girdwood
  2020-08-13 18:11   ` Cezary Rojewski
  14 siblings, 1 reply; 43+ messages in thread
From: Liam Girdwood @ 2020-08-13 16:00 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: andriy.shevchenko, filip.kaczmarski, harshapriya.n,
	ppapierkowski, marcin.barlik, zwisler, pierre-louis.bossart,
	lgirdwood, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, tiwai, krzysztof.hejmowski, cujomalainey,
	vamshi.krishna.gopal

On Wed, 2020-08-12 at 22:57 +0200, Cezary Rojewski wrote:
> Implement support for Lynxpoint and Wildcat Point AudioDSP. Catpt
> 
> solution deprecates existing sound/soc/intel/haswell which is removed
> in
> 
> the following series. This cover-letter is followed by 'Developer's
> deep
> 
> dive' message schedding light on catpt's key concepts and areas
> 
> addressed.

Whilst I applaud removing the old driver I do NOT support adding yet
*another* Intel audio DSP driver. Our goal is to remove DSP drivers and
unify under one codebase (and this was discussed in Lyon last year at
the audio Miniconf).

Please take all these good improvements and add them into the SOF
driver.

Please also remember that we are adding an IPC abstraction layer into
the SOF driver so it can cope with multiple IPC versions. You are most
welcome to help in this effort.

Thanks

Liam






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

* Re: [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point
  2020-08-13 16:00 ` Liam Girdwood
@ 2020-08-13 18:11   ` Cezary Rojewski
  2020-08-13 19:03     ` Liam Girdwood
  0 siblings, 1 reply; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-13 18:11 UTC (permalink / raw)
  To: Liam Girdwood, alsa-devel
  Cc: andriy.shevchenko, filip.kaczmarski, harshapriya.n,
	ppapierkowski, marcin.barlik, zwisler, pierre-louis.bossart,
	lgirdwood, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, tiwai, krzysztof.hejmowski, cujomalainey,
	vamshi.krishna.gopal

On 2020-08-13 6:00 PM, Liam Girdwood wrote:
> On Wed, 2020-08-12 at 22:57 +0200, Cezary Rojewski wrote:
>> Implement support for Lynxpoint and Wildcat Point AudioDSP. Catpt
>>
>> solution deprecates existing sound/soc/intel/haswell which is removed
>> in
>>
>> the following series. This cover-letter is followed by 'Developer's
>> deep
>>
>> dive' message schedding light on catpt's key concepts and areas
>>
>> addressed.
> 
> Whilst I applaud removing the old driver I do NOT support adding yet
> *another* Intel audio DSP driver. Our goal is to remove DSP drivers and
> unify under one codebase (and this was discussed in Lyon last year at
> the audio Miniconf).
> 
> Please take all these good improvements and add them into the SOF
> driver.
> 
> Please also remember that we are adding an IPC abstraction layer into
> the SOF driver so it can cope with multiple IPC versions. You are most
> welcome to help in this effort.
> 
Presented catpt is created as a solution to existing problems reported 
by clients and users for WPT platforms. It is not "yet another" DSP 
driver but an update to an existing one - due to high range of problems 
found when testing it, catpt came as a lower-cost solution and /haswell/ 
is being removed soon after. So, the status quo is maintained - single 
driver for LPT/WPT architecture.

Please don't use 'our goal' term, it's misplaced: it was agreed on 
several occasions that older DSP platforms remain with closed firmware 
and are to be supported with existing DSP drivers.
SOF FW does not support BDW and instead is tasked with support of newer 
platforms. Neither SOF FW team nor Chrome support team agreed with WPT 
being moved out of closed firmware. Please, speak with management first 
before writing statements saying otherwise.

I don't see your input for any of the patches. Internal heads-up has 
been given. No review for either internal or upstream patchsets. 
Afterall, you were the author of original /haswell/ and your input could 
have proved important in speeding the progress and yielding even better 
results to our clients.

As you've given no technical points for denying LPT/WPT improvements and 
your statement disagrees with management's decision, message shall be 
discarded and ignored for the rest of the upstream process. Further 
discussion will be taken off this list.

Mark, Takashi and others,
I'm sorry for this inconvenience, such actions do not represent One 
Intel and Truth & Transparency which Intel is committed to stand by.

Czarek

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

* Re: [PATCH v4 01/13] ASoC: Intel: Add catpt device
  2020-08-12 20:57 ` [PATCH v4 01/13] ASoC: Intel: Add catpt device Cezary Rojewski
@ 2020-08-13 18:29   ` Andy Shevchenko
  2020-08-17 10:02     ` Cezary Rojewski
  0 siblings, 1 reply; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-13 18:29 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Wed, Aug 12, 2020 at 10:57:41PM +0200, Cezary Rojewski wrote:
> Declare base structures, registers and device routines for the catpt
> solution. Catpt deprecates and is a direct replacement for
> sound/soc/intel/haswell. Supports Lynxpoint and Wildcat Point both.

Before doing v5 give a chance to review entire series, please!

...

> +static inline bool catpt_resource_overlapping(struct resource *r1,
> +					      struct resource *r2,
> +					      struct resource *ret)
> +{
> +	if (!resource_overlaps(r1, r2))
> +		return false;
> +	ret->start = max(r1->start, r2->start);
> +	ret->end = min(r1->end, r2->end);
> +	return true;
> +}

JFYI, I have just submitted a series [1] that includes this helper [2]
to be available for all.

[1]: https://lore.kernel.org/linux-acpi/20200813175729.15088-1-andriy.shevchenko@linux.intel.com/
[2]: https://lore.kernel.org/linux-acpi/20200813175729.15088-4-andriy.shevchenko@linux.intel.com/

...

> +struct catpt_dev {
> +	struct device *dev;

> +	struct dw_dma_chip *dmac;

Is it possible to use opaque pointer here? It will be better if in the future
(I think unlikely, but still) somebody decides to use this with another DMA
engine.

> +	struct catpt_ipc ipc;
> +
> +	void __iomem *pci_ba;
> +	void __iomem *lpe_ba;
> +	u32 lpe_base;
> +	int irq;
> +
> +	const struct catpt_spec *spec;
> +	struct completion fw_ready;
> +
> +	struct resource dram;
> +	struct resource iram;
> +	struct resource *scratch;
> +
> +	struct catpt_mixer_stream_info mixer;
> +	struct catpt_module_type modules[CATPT_MODULE_COUNT];
> +	struct catpt_ssp_device_format devfmt[CATPT_SSP_COUNT];
> +	struct list_head stream_list;
> +	spinlock_t list_lock;
> +	struct mutex clk_mutex;
> +
> +	struct catpt_dx_context dx_ctx;
> +	void *dxbuf_vaddr;
> +	dma_addr_t dxbuf_paddr;
> +};

...

> +#define CATPT_IPC_ERROR(err) ((err < 0) ? err : -EREMOTEIO)

err -> (err) in all cases of right side.

...

> +struct catpt_stream_runtime {
> +	struct snd_pcm_substream *substream;
> +
> +	struct catpt_stream_template *template;
> +	struct catpt_stream_info info;
> +	struct resource *persistent;
> +	struct snd_dma_buffer pgtbl;
> +

> +	bool allocated:1;
> +	bool prepared:1;

Does this ':1' make any sense?

> +	struct list_head node;
> +};

...

> +#ifdef CONFIG_PM

Perhaps __maybe_unused?

...

> +	ret = catpt_dsp_stall(cdev, true);
> +	if (ret < 0)

I'm wondering if all these ' < 0' all over the code make sense? What do you
expect out of positive returned values if any?

> +		goto exit;

...

> +#ifdef CONFIG_PM_SLEEP

Perhaps __maybe_unused?

...

> +	board = platform_device_register_data(NULL, mach->drv_name,
> +					PLATFORM_DEVID_NONE,
> +					(const void *)mach, sizeof(*mach));
> +	if (!board) {

Here obviously not correct check.

> +		dev_err(cdev->dev, "board register failed\n");
> +		return PTR_ERR(board);
> +	}
> +
> +	ret = devm_add_action(cdev->dev, board_pdev_unregister, board);
> +	if (ret < 0) {
> +		platform_device_unregister(board);

> +		return ret;
> +	}
> +
> +	return 0;

return ret;

...

> +	mutex_init(&cdev->clk_mutex);

+ blank line.

> +	/*
> +	 * Mark both device formats as uninitialized. Once corresponding
> +	 * cpu_dai's pcm is created, proper values are assigned

Please, use period(s) in multi-line comments.

> +	 */

...

> +static int catpt_acpi_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct catpt_dev *cdev;
> +	struct resource *res;
> +	int ret;
> +
> +	cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL);
> +	if (!cdev)
> +		return -ENOMEM;


> +	cdev->spec = device_get_match_data(dev);
> +	if (!cdev->spec)
> +		return -ENODEV;

You may save some cycles if you do this before memory allocations.

> +	catpt_dev_init(cdev, dev);
> +
> +	/* map DSP bar address */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +	cdev->lpe_ba = devm_ioremap(dev, res->start, resource_size(res));
> +	if (!cdev->lpe_ba)
> +		return -EIO;
> +	cdev->lpe_base = res->start;

Why the region is not get requested?

> +	/* map PCI bar address */
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	if (!res)
> +		return -ENODEV;
> +	cdev->pci_ba = devm_ioremap(dev, res->start, resource_size(res));
> +	if (!cdev->pci_ba)
> +		return -EIO;

Ditto.

> +	/* alloc buffer for storing DRAM context during dx transitions */
> +	cdev->dxbuf_vaddr = dma_alloc_coherent(dev, catpt_dram_size(cdev),

dmam_alloc_coherent() ?

> +					       &cdev->dxbuf_paddr, GFP_KERNEL);
> +	if (!cdev->dxbuf_vaddr)
> +		return -ENOMEM;

> +	ret = platform_get_irq(pdev, 0);
> +	if (ret < 0)
> +		goto irq_err;
> +	cdev->irq = ret;

But you may return directly if you get IRQ resource before allocation (despite
previous comment).

> +
> +	platform_set_drvdata(pdev, cdev);
> +
> +	ret = devm_request_threaded_irq(dev, cdev->irq, catpt_dsp_irq_handler,
> +					catpt_dsp_irq_thread,
> +					IRQF_SHARED, "AudioDSP", cdev);
> +	if (ret < 0)
> +		goto irq_err;
> +
> +	ret = catpt_probe_components(cdev);

return ...

> +	if (ret < 0)
> +		goto irq_err;
> +	return 0;
> +
> +irq_err:
> +	dma_free_coherent(cdev->dev, catpt_dram_size(cdev),
> +			  cdev->dxbuf_vaddr, cdev->dxbuf_paddr);
> +
> +	return ret;

This will be gone...

> +}

...

> +static const struct acpi_device_id catpt_ids[] = {
> +	{ "INT33C8", (unsigned long)&lpt_desc },
> +	{ "INT3438", (unsigned long)&wpt_desc },

> +	{ },

No need to have comma in terminator line.

> +};

...

> +static struct platform_driver catpt_acpi_driver = {
> +	.probe = catpt_acpi_probe,
> +	.remove = catpt_acpi_remove,
> +	.driver = {
> +		.name = "catpt_adsp",

> +		.acpi_match_table = ACPI_PTR(catpt_ids),

ACPI_PTR() either bogus (when you have depends on ACPI) or mistake that brings
you compiler warning (unused variable).

I highly recommend in new code avoid completely ACPI_PTR() and of_match_ptr()
macros.

> +		.pm = &catpt_dev_pm,
> +	},
> +};

...

> +#include <linux/iopoll.h>

Missed headers:
bits.h (note, the below guarantees to provide this one)
bitops.h
io.h (writel(), readl(), etc)

...

> +/* DSP Shim registers */
> +
> +#define CATPT_SHIM_CS1		0x0

Please, keep all register definitions of the same width, like 0x00 here or so.

...

> +#define CATPT_CS_SFCR(ssp)	BIT(27 + ssp)

In all macros, try to be a little bit defensive, e.g. here ssp -> (ssp).

...

> +#define CATPT_HMDC_HDDA(e, ch)	BIT(8 * e + ch)

...or e -> (e) and ch -> (ch) here.

...

> +#define CATPT_CS_DEFAULT	0x8480040E
> +#define CATPT_IMC_DEFAULT	0x7FFF0003
> +#define CATPT_IMD_DEFAULT	0x7FFF0003
> +#define CATPT_CLKCTL_DEFAULT	0x7FF

These looks like set of bit fields, can we describe them either in comments
or in the values like GENMASK(x, y) | BIT(z) ?

...

> +/* PCI Configuration registers */
> +
> +#define CATPT_PCI_PMCS		0x84

Why?! We have PCI capability and entire infrastructure for that in PCI core.

...

> +#define CATPT_PMCS_PS		GENMASK(1, 0)
> +#define CATPT_PMCS_PS_D3HOT	(0x3 << 0)

Ditto.

...

> +#define CATPT_SSP_SSC0		0x0
> +#define CATPT_SSP_SSC1		0x4
> +#define CATPT_SSP_SSS		0x8
> +#define CATPT_SSP_SSIT		0xC
> +#define CATPT_SSP_SSD		0x10
> +#define CATPT_SSP_SSTO		0x28
> +#define CATPT_SSP_SSPSP		0x2C
> +#define CATPT_SSP_SSTSA		0x30
> +#define CATPT_SSP_SSRSA		0x34
> +#define CATPT_SSP_SSTSS		0x38
> +#define CATPT_SSP_SSC2		0x40
> +#define CATPT_SSP_SSPSP2	0x44

Isn't it PXA2xx register set? Can you use their definitions?

...

> +#define CATPT_SSP_SSC0_DEFAULT		0x0
> +#define CATPT_SSP_SSC1_DEFAULT		0x0
> +#define CATPT_SSP_SSS_DEFAULT		0xF004
> +#define CATPT_SSP_SSIT_DEFAULT		0x0
> +#define CATPT_SSP_SSD_DEFAULT		0xC43893A3
> +#define CATPT_SSP_SSTO_DEFAULT		0x0
> +#define CATPT_SSP_SSPSP_DEFAULT		0x0
> +#define CATPT_SSP_SSTSA_DEFAULT		0x0
> +#define CATPT_SSP_SSRSA_DEFAULT		0x0
> +#define CATPT_SSP_SSTSS_DEFAULT		0x0
> +#define CATPT_SSP_SSC2_DEFAULT		0x0
> +#define CATPT_SSP_SSPSP2_DEFAULT	0x0

These defaults lack of comments.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations
  2020-08-12 20:57 ` [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations Cezary Rojewski
@ 2020-08-13 18:51   ` Andy Shevchenko
  2020-08-17 11:12     ` Cezary Rojewski
  0 siblings, 1 reply; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-13 18:51 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Wed, Aug 12, 2020 at 10:57:42PM +0200, Cezary Rojewski wrote:
> Implement dsp lifecycle functions such as core RESET and STALL,
> SRAM power control and LP clock selection. This also adds functions for
> handling transport over DW DMA controller.

...

> +static void catpt_dma_transfer_complete(void *arg)
> +{
> +	struct catpt_dev *cdev = arg;
> +

> +	dev_dbg(cdev->dev, "%s\n", __func__);

Noise. Somebody should provide either trace events, of get used to function tracer / perf.

> +}

...

> +static bool catpt_dma_filter(struct dma_chan *chan, void *param)
> +{

> +	return chan->device->dev == (struct device *)param;

Redundant casting, and please, consider to swap left and right side (in this
case easily to find these and perhaps provide a generic helper function).

> +}

...

> +#define CATPT_DMA_DEVID		1 /* dma engine used */

Not sure I understand what exactly this means.

...

> +#define CATPT_DMA_MAXBURST	0x3

We have DMA engine definitions for that, please avoid magic numbers.

...

> +#define CATPT_DMA_DSP_ADDR_MASK	0xFFF00000

GENMASK()

...

> +	dma_cap_set(DMA_SLAVE, mask);

How this helps with mem2mem channel?

...

> +	chan = dma_request_channel(mask, catpt_dma_filter, cdev->dev);
> +	if (!chan) {
> +		dev_err(cdev->dev, "request channel failed\n");

> +		dump_stack();

Huh?!

> +		return ERR_PTR(-EPROBE_DEFER);
> +	}

...

> +	status = dma_wait_for_async_tx(desc);

> +	catpt_updatel_shim(cdev, HMDC,
> +			   CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id), 0);

Update even in erroneous case?

> +	return (status == DMA_COMPLETE) ? 0 : -EPROTO;

...

> +static void catpt_dsp_set_srampge(struct catpt_dev *cdev, struct resource *sram,
> +				  unsigned long mask, unsigned long new)
> +{
> +	unsigned long old;
> +	u32 off = sram->start;
> +	u32 b = __ffs(mask);
> +
> +	old = catpt_readl_pci(cdev, VDRTCTL0) & mask;

> +	dev_dbg(cdev->dev, "SRAMPGE [0x%08lx] 0x%08lx -> 0x%08lx",
> +		mask, old, new);

trace event / point?

> +	if (old == new)
> +		return;
> +
> +	catpt_updatel_pci(cdev, VDRTCTL0, mask, new);

> +	udelay(60);

Delays should be commented.

> +
> +	/*
> +	 * dummy read as the very first access after block enable
> +	 * to prevent byte loss in future operations
> +	 */
> +	for_each_clear_bit_from(b, &new, fls(mask)) {

fls_long()

> +		u8 buf[4];
> +
> +		/* newly enabled: new bit=0 while old bit=1 */
> +		if (test_bit(b, &old)) {
> +			dev_dbg(cdev->dev, "sanitize block %ld: off 0x%08x\n",

> +				(b - __ffs(mask)), off);

Unneeded parentheses.

> +			memcpy_fromio(buf, cdev->lpe_ba + off, sizeof(buf));
> +		}
> +		off += CATPT_MEMBLOCK_SIZE;
> +	}
> +}

...

> +	/* offset value given mask's start and invert it as ON=b0 */

> +	new <<= __ffs(mask);
> +	new = ~(new) & mask;

Unneeded parentheses.
And perhaps in one line it will be better to understand:

	new = ~(new << __ffs(mask)) & mask;

...

> +	if (waiti) {
> +		/* wait for DSP to signal WAIT state */
> +		ret = catpt_readl_poll_shim(cdev, ISD,
> +					    reg, (reg & CATPT_ISD_DCPWM),
> +					    500, 10000);
> +		if (ret < 0) {

> +			dev_warn(cdev->dev, "await WAITI timeout\n");

Shouldn't be an error level?

> +			mutex_unlock(&cdev->clk_mutex);
> +			return ret;
> +		}
> +	}

...

> +int catpt_dsp_update_lpclock(struct catpt_dev *cdev)
> +{
> +	struct catpt_stream_runtime *stream;

> +	bool lp;
> +
> +	if (list_empty(&cdev->stream_list))
> +		return catpt_dsp_select_lpclock(cdev, true, true);
> +
> +	lp = true;
> +	list_for_each_entry(stream, &cdev->stream_list, node) {
> +		if (stream->prepared) {
> +			lp = false;
> +			break;
> +		}
> +	}
> +
> +	return catpt_dsp_select_lpclock(cdev, lp, true);

Seems too much duplication.

	struct catpt_stream_runtime *stream;

	list_for_each_entry(stream, &cdev->stream_list, node) {
		if (stream->prepared)
			return catpt_dsp_select_lpclock(cdev, false, true);
	}

	return catpt_dsp_select_lpclock(cdev, true, true);


Better?

> +}

...

> +	/* set D3 */
> +	catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, CATPT_PMCS_PS_D3HOT);
> +	udelay(50);

Don't we have PCI core function for this?

...

> +	/* set D0 */
> +	catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, 0);
> +	udelay(100);

Ditto.

...

> +	/* set D3 */
> +	catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, CATPT_PMCS_PS_D3HOT);
> +	udelay(50);

Ditto.

...

> +	/* set D0 */
> +	catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, 0);

Ditto.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 11/13] ASoC: Intel: broadwell: Remove haswell-solution specific code
  2020-08-12 20:57 ` [PATCH v4 11/13] ASoC: Intel: broadwell: " Cezary Rojewski
@ 2020-08-13 18:56   ` Andy Shevchenko
  0 siblings, 0 replies; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-13 18:56 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Wed, Aug 12, 2020 at 10:57:51PM +0200, Cezary Rojewski wrote:
> Remove code specific to sound/soc/intel/haswell. Update BE dai_link
> definition to provide seamless transition to catpt solution.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>

> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
> ---
>  sound/soc/intel/boards/broadwell.c | 33 ------------------------------
>  1 file changed, 33 deletions(-)
> 
> diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c
> index f6399077d291..ea2818f27105 100644
> --- a/sound/soc/intel/boards/broadwell.c
> +++ b/sound/soc/intel/boards/broadwell.c
> @@ -14,9 +14,6 @@
>  #include <sound/pcm_params.h>
>  #include <sound/soc-acpi.h>
>  
> -#include "../common/sst-dsp.h"
> -#include "../haswell/sst-haswell-ipc.h"
> -
>  #include "../../codecs/rt286.h"
>  
>  static struct snd_soc_jack broadwell_headset;
> @@ -122,27 +119,6 @@ static const struct snd_soc_ops broadwell_rt286_ops = {
>  	.hw_params = broadwell_rt286_hw_params,
>  };
>  
> -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
> -static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
> -{
> -	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
> -	struct sst_pdata *pdata = dev_get_platdata(component->dev);
> -	struct sst_hsw *broadwell = pdata->dsp;
> -	int ret;
> -
> -	/* Set ADSP SSP port settings */
> -	ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0,
> -		SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
> -		SST_HSW_DEVICE_CLOCK_MASTER, 9);
> -	if (ret < 0) {
> -		dev_err(rtd->dev, "error: failed to set device config\n");
> -		return ret;
> -	}
> -
> -	return 0;
> -}
> -#endif
> -
>  static const unsigned int channels[] = {
>  	2,
>  };
> @@ -189,10 +165,8 @@ SND_SOC_DAILINK_DEF(platform,
>  SND_SOC_DAILINK_DEF(codec,
>  	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1")));
>  
> -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
>  SND_SOC_DAILINK_DEF(ssp0_port,
>  	    DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
> -#endif
>  
>  /* broadwell digital audio interface glue - connects codec <--> CPU */
>  static struct snd_soc_dai_link broadwell_rt286_dais[] = {
> @@ -201,9 +175,6 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
>  		.name = "System PCM",
>  		.stream_name = "System Playback/Capture",
>  		.dynamic = 1,
> -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
> -		.init = broadwell_rtd_init,
> -#endif
>  		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
>  		.ops = &broadwell_fe_ops,
>  		.dpcm_playback = 1,
> @@ -248,11 +219,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
>  		.ops = &broadwell_rt286_ops,
>  		.dpcm_playback = 1,
>  		.dpcm_capture = 1,
> -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
> -		SND_SOC_DAILINK_REG(dummy, codec, dummy),
> -#else
>  		SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
> -#endif
>  	},
>  };
>  
> -- 
> 2.17.1
> 

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 12/13] ASoC: Intel: bdw-5650: Remove haswell-solution specific code
  2020-08-12 20:57 ` [PATCH v4 12/13] ASoC: Intel: bdw-5650: " Cezary Rojewski
@ 2020-08-13 18:56   ` Andy Shevchenko
  0 siblings, 0 replies; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-13 18:56 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Wed, Aug 12, 2020 at 10:57:52PM +0200, Cezary Rojewski wrote:
> Remove code specific to sound/soc/intel/haswell. Update BE dai_link
> definition to provide seamless transition to catpt solution.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
> ---
>  sound/soc/intel/boards/bdw-rt5650.c | 36 -----------------------------
>  1 file changed, 36 deletions(-)
> 
> diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c
> index ce7320916b22..c5820787c53e 100644
> --- a/sound/soc/intel/boards/bdw-rt5650.c
> +++ b/sound/soc/intel/boards/bdw-rt5650.c
> @@ -16,9 +16,6 @@
>  #include <sound/soc.h>
>  #include <sound/soc-acpi.h>
>  
> -#include "../common/sst-dsp.h"
> -#include "../haswell/sst-haswell-ipc.h"
> -
>  #include "../../codecs/rt5645.h"
>  
>  struct bdw_rt5650_priv {
> @@ -138,30 +135,6 @@ static struct snd_soc_ops bdw_rt5650_ops = {
>  	.hw_params = bdw_rt5650_hw_params,
>  };
>  
> -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
> -static int bdw_rt5650_rtd_init(struct snd_soc_pcm_runtime *rtd)
> -{
> -	struct snd_soc_component *component =
> -		snd_soc_rtdcom_lookup(rtd, DRV_NAME);
> -	struct sst_pdata *pdata = dev_get_platdata(component->dev);
> -	struct sst_hsw *broadwell = pdata->dsp;
> -	int ret;
> -
> -	/* Set ADSP SSP port settings
> -	 * clock_divider = 4 means BCLK = MCLK/5 = 24MHz/5 = 4.8MHz
> -	 */
> -	ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0,
> -		SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
> -		SST_HSW_DEVICE_TDM_CLOCK_MASTER, 4);
> -	if (ret < 0) {
> -		dev_err(rtd->dev, "error: failed to set device config\n");
> -		return ret;
> -	}
> -
> -	return 0;
> -}
> -#endif
> -
>  static const unsigned int channels[] = {
>  	2, 4,
>  };
> @@ -251,10 +224,8 @@ SND_SOC_DAILINK_DEF(platform,
>  SND_SOC_DAILINK_DEF(be,
>  	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5650:00", "rt5645-aif1")));
>  
> -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
>  SND_SOC_DAILINK_DEF(ssp0_port,
>  	    DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
> -#endif
>  
>  static struct snd_soc_dai_link bdw_rt5650_dais[] = {
>  	/* Front End DAI links */
> @@ -263,9 +234,6 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = {
>  		.stream_name = "System Playback",
>  		.dynamic = 1,
>  		.ops = &bdw_rt5650_fe_ops,
> -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
> -		.init = bdw_rt5650_rtd_init,
> -#endif
>  		.trigger = {
>  			SND_SOC_DPCM_TRIGGER_POST,
>  			SND_SOC_DPCM_TRIGGER_POST
> @@ -289,11 +257,7 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = {
>  		.dpcm_playback = 1,
>  		.dpcm_capture = 1,
>  		.init = bdw_rt5650_init,
> -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
> -		SND_SOC_DAILINK_REG(dummy, be, dummy),
> -#else
>  		SND_SOC_DAILINK_REG(ssp0_port, be, platform),
> -#endif
>  	},
>  };
>  
> -- 
> 2.17.1
> 

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 13/13] ASoC: Intel: bdw-5677: Remove haswell-solution specific code
  2020-08-12 20:57 ` [PATCH v4 13/13] ASoC: Intel: bdw-5677: " Cezary Rojewski
@ 2020-08-13 18:57   ` Andy Shevchenko
  0 siblings, 0 replies; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-13 18:57 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Wed, Aug 12, 2020 at 10:57:53PM +0200, Cezary Rojewski wrote:
> Remove code specific to sound/soc/intel/haswell. Update BE dai_link
> definition to provide seamless transition to catpt solution.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
> ---
>  sound/soc/intel/boards/bdw-rt5677.c | 33 -----------------------------
>  1 file changed, 33 deletions(-)
> 
> diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c
> index 86e427e3822f..4451957fc170 100644
> --- a/sound/soc/intel/boards/bdw-rt5677.c
> +++ b/sound/soc/intel/boards/bdw-rt5677.c
> @@ -17,9 +17,6 @@
>  #include <sound/jack.h>
>  #include <sound/soc-acpi.h>
>  
> -#include "../common/sst-dsp.h"
> -#include "../haswell/sst-haswell-ipc.h"
> -
>  #include "../../codecs/rt5677.h"
>  
>  struct bdw_rt5677_priv {
> @@ -201,27 +198,6 @@ static const struct snd_soc_ops bdw_rt5677_dsp_ops = {
>  	.hw_params = bdw_rt5677_dsp_hw_params,
>  };
>  
> -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
> -static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd)
> -{
> -	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
> -	struct sst_pdata *pdata = dev_get_platdata(component->dev);
> -	struct sst_hsw *broadwell = pdata->dsp;
> -	int ret;
> -
> -	/* Set ADSP SSP port settings */
> -	ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0,
> -		SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
> -		SST_HSW_DEVICE_CLOCK_MASTER, 9);
> -	if (ret < 0) {
> -		dev_err(rtd->dev, "error: failed to set device config\n");
> -		return ret;
> -	}
> -
> -	return 0;
> -}
> -#endif
> -
>  static const unsigned int channels[] = {
>  	2,
>  };
> @@ -333,10 +309,8 @@ SND_SOC_DAILINK_DEF(platform,
>  SND_SOC_DAILINK_DEF(be,
>  	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RT5677CE:00", "rt5677-aif1")));
>  
> -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
>  SND_SOC_DAILINK_DEF(ssp0_port,
>  	    DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
> -#endif
>  
>  /* Wake on voice interface */
>  SND_SOC_DAILINK_DEFS(dsp,
> @@ -350,9 +324,6 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = {
>  		.name = "System PCM",
>  		.stream_name = "System Playback/Capture",
>  		.dynamic = 1,
> -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
> -		.init = bdw_rt5677_rtd_init,
> -#endif
>  		.trigger = {
>  			SND_SOC_DPCM_TRIGGER_POST,
>  			SND_SOC_DPCM_TRIGGER_POST
> @@ -387,11 +358,7 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = {
>  		.dpcm_capture = 1,
>  		.init = bdw_rt5677_init,
>  		.exit = bdw_rt5677_exit,
> -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
> -		SND_SOC_DAILINK_REG(dummy, be, dummy),
> -#else
>  		SND_SOC_DAILINK_REG(ssp0_port, be, platform),
> -#endif
>  	},
>  };
>  
> -- 
> 2.17.1
> 

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 10/13] ASoC: Intel: haswell: Remove haswell-solution specific code
  2020-08-12 20:57 ` [PATCH v4 10/13] ASoC: Intel: haswell: Remove haswell-solution specific code Cezary Rojewski
@ 2020-08-13 18:57   ` Andy Shevchenko
  0 siblings, 0 replies; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-13 18:57 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Wed, Aug 12, 2020 at 10:57:50PM +0200, Cezary Rojewski wrote:
> Remove code specific to sound/soc/intel/haswell. Update BE dai_link
> definition to provide seamless transition to catpt solution.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
> ---
>  sound/soc/intel/boards/haswell.c | 28 ++++------------------------
>  1 file changed, 4 insertions(+), 24 deletions(-)
> 
> diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c
> index 744b7b5b8106..c268405e5594 100644
> --- a/sound/soc/intel/boards/haswell.c
> +++ b/sound/soc/intel/boards/haswell.c
> @@ -13,9 +13,6 @@
>  #include <sound/soc-acpi.h>
>  #include <sound/pcm_params.h>
>  
> -#include "../common/sst-dsp.h"
> -#include "../haswell/sst-haswell-ipc.h"
> -
>  #include "../../codecs/rt5640.h"
>  
>  /* Haswell ULT platforms have a Headphone and Mic jack */
> @@ -77,25 +74,6 @@ static const struct snd_soc_ops haswell_rt5640_ops = {
>  	.hw_params = haswell_rt5640_hw_params,
>  };
>  
> -static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd)
> -{
> -	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
> -	struct sst_pdata *pdata = dev_get_platdata(component->dev);
> -	struct sst_hsw *haswell = pdata->dsp;
> -	int ret;
> -
> -	/* Set ADSP SSP port settings */
> -	ret = sst_hsw_device_set_config(haswell, SST_HSW_DEVICE_SSP_0,
> -		SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
> -		SST_HSW_DEVICE_CLOCK_MASTER, 9);
> -	if (ret < 0) {
> -		dev_err(rtd->dev, "failed to set device config\n");
> -		return ret;
> -	}
> -
> -	return 0;
> -}
> -
>  SND_SOC_DAILINK_DEF(dummy,
>  	DAILINK_COMP_ARRAY(COMP_DUMMY()));
>  
> @@ -117,13 +95,15 @@ SND_SOC_DAILINK_DEF(codec,
>  SND_SOC_DAILINK_DEF(platform,
>  	DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
>  
> +SND_SOC_DAILINK_DEF(ssp0_port,
> +	    DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
> +
>  static struct snd_soc_dai_link haswell_rt5640_dais[] = {
>  	/* Front End DAI links */
>  	{
>  		.name = "System",
>  		.stream_name = "System Playback/Capture",
>  		.dynamic = 1,
> -		.init = haswell_rtd_init,
>  		.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
>  		.dpcm_playback = 1,
>  		.dpcm_capture = 1,
> @@ -167,7 +147,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = {
>  		.ops = &haswell_rt5640_ops,
>  		.dpcm_playback = 1,
>  		.dpcm_capture = 1,
> -		SND_SOC_DAILINK_REG(dummy, codec, dummy),
> +		SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
>  	},
>  };
>  
> -- 
> 2.17.1
> 

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point
  2020-08-13 18:11   ` Cezary Rojewski
@ 2020-08-13 19:03     ` Liam Girdwood
  0 siblings, 0 replies; 43+ messages in thread
From: Liam Girdwood @ 2020-08-13 19:03 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel
  Cc: andriy.shevchenko, filip.kaczmarski, harshapriya.n,
	ppapierkowski, marcin.barlik, zwisler, pierre-louis.bossart,
	lgirdwood, filip.proborszcz, broonie, amadeuszx.slawinski,
	michal.wasko, tiwai, krzysztof.hejmowski, cujomalainey,
	vamshi.krishna.gopal

On Thu, 2020-08-13 at 20:11 +0200, Cezary Rojewski wrote:
> On 2020-08-13 6:00 PM, Liam Girdwood wrote:
> > On Wed, 2020-08-12 at 22:57 +0200, Cezary Rojewski wrote:
> > > Implement support for Lynxpoint and Wildcat Point AudioDSP. Catpt
> > > 
> > > solution deprecates existing sound/soc/intel/haswell which is
> > > removed
> > > in
> > > 
> > > the following series. This cover-letter is followed by
> > > 'Developer's
> > > deep
> > > 
> > > dive' message schedding light on catpt's key concepts and areas
> > > 
> > > addressed.
> > 
> > Whilst I applaud removing the old driver I do NOT support adding
> > yet
> > *another* Intel audio DSP driver. Our goal is to remove DSP drivers
> > and
> > unify under one codebase (and this was discussed in Lyon last year
> > at
> > the audio Miniconf).
> > 
> > Please take all these good improvements and add them into the SOF
> > driver.
> > 
> > Please also remember that we are adding an IPC abstraction layer
> > into
> > the SOF driver so it can cope with multiple IPC versions. You are
> > most
> > welcome to help in this effort.
> > 
> Presented catpt is created as a solution to existing problems
> reported 
> by clients and users for WPT platforms. It is not "yet another" DSP 
> driver but an update to an existing one - due to high range of
> problems 
> found when testing it, catpt came as a lower-cost solution and
> /haswell/ 
> is being removed soon after. So, the status quo is maintained -
> single 
> driver for LPT/WPT architecture.

Its a new driver. Fix the old driver or (preferred) fix the SOF driver
so we can remove the haswell driver and have one less DSP driver to
maintain.

> 
> Please don't use 'our goal' term, it's misplaced: it was agreed on 
> several occasions that older DSP platforms remain with closed
> firmware 
> and are to be supported with existing DSP drivers.

I'm not suggesting using SOF FW, but using the existing FW with the IPC
abstraction.

> SOF FW does not support BDW and instead is tasked with support of
> newer 
> platforms. Neither SOF FW team nor Chrome support team agreed with
> WPT 
> being moved out of closed firmware. Please, speak with management
> first 
> before writing statements saying otherwise.

To be clear - I'm saying fix the SOF driver to use the old FW (not the
SOF FW). You know that we need IPC abstraction here (and for other
platforms)

> 
> I don't see your input for any of the patches. Internal heads-up has 
> been given. No review for either internal or upstream patchsets. 
> Afterall, you were the author of original /haswell/ and your input
> could 
> have proved important in speeding the progress and yielding even
> better 
> results to our clients.
> 

Please don't mistake silence for my approval. I knew that updates were
forthcoming but not a new driver.

> As you've given no technical points for denying LPT/WPT improvements
> and 
> your statement disagrees with management's decision, message shall
> be 
> discarded and ignored for the rest of the upstream process. Further 
> discussion will be taken off this list.
> 
> Mark, Takashi and others,
> I'm sorry for this inconvenience, such actions do not represent One 
> Intel and Truth & Transparency which Intel is committed to stand by.
> 

Seriously ? It's really simple for anyone to understand that
introducing a new driver introduces new bugs. It's also very well
understood that fixing or extending existing drivers is always the best
path forwards over adding another new immature driver.

I hope you understand that long term **convergence** is key for
quality, maintainability and reduced effort, if not, I'm happy have a
call.

Thanks

Liam 
  



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

* Re: [PATCH v4 01/13] ASoC: Intel: Add catpt device
  2020-08-13 18:29   ` Andy Shevchenko
@ 2020-08-17 10:02     ` Cezary Rojewski
  2020-08-18 10:07       ` Andy Shevchenko
  2020-08-25 20:43       ` Cezary Rojewski
  0 siblings, 2 replies; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-17 10:02 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On 2020-08-13 8:29 PM, Andy Shevchenko wrote:
> On Wed, Aug 12, 2020 at 10:57:41PM +0200, Cezary Rojewski wrote:

Thanks for good review Andy!


>> +static inline bool catpt_resource_overlapping(struct resource *r1,
>> +					      struct resource *r2,
>> +					      struct resource *ret)
>> +{
>> +	if (!resource_overlaps(r1, r2))
>> +		return false;
>> +	ret->start = max(r1->start, r2->start);
>> +	ret->end = min(r1->end, r2->end);
>> +	return true;
>> +}
> 
> JFYI, I have just submitted a series [1] that includes this helper [2]
> to be available for all.
> 
> [1]: https://lore.kernel.org/linux-acpi/20200813175729.15088-1-andriy.shevchenko@linux.intel.com/
> [2]: https://lore.kernel.org/linux-acpi/20200813175729.15088-4-andriy.shevchenko@linux.intel.com/
> 

Well, I'm happy that catpt somewhat impacted resource-API getting more 
flexble, although it would be nice to get --cc'ed as 
_overlapping/_intersecting got moved into general part of kernel without 
changes, basically.

This raises a dependancy issue, am I right? i.e. until this gets merged, 
catpt will cause compilation errors on Mark's for-next. -or- perhaps you 
want me to leave things as they are for current release while removing 
said function later, once your PR get's merged?

>> +struct catpt_dev {
>> +	struct device *dev;
> 
>> +	struct dw_dma_chip *dmac;
> 
> Is it possible to use opaque pointer here? It will be better if in the future
> (I think unlikely, but still) somebody decides to use this with another DMA
> engine.
> 

Any opaque structure comes at a cost -> requires higher level of 
understanding from developers maintaining given piece of code (that 
includes architecture knowledge too, to get a grasp of why such decision 
was even made) == higher maintaince cost.

One could device ADSP architectures into:
1) LPT/WPT
2) BYT/CHT/BDW
3) cAVS (SKL+)
4) new (which I won't be elaborating here for obvious reasons)

To my knowledge, except for 1), none of them makes use of dmaengine.h 
when loading FW or doing any other action for that matter. As such, I 
don't see any reason to convert something explicit into something 
implicit. Don't believe either of options would be reusing struct 
catpt_dev too. In general, to make that happen you'd have to start with 
conversion of existing HDAudio transport (cAVS+) into dmaengine model 
and then do the same with SoundWire (cAVS+) - haven't seen sdw code in a 
while but still pretty sure it's not dmaengine-friendly.

> 
>> +#define CATPT_IPC_ERROR(err) ((err < 0) ? err : -EREMOTEIO)
> 
> err -> (err) in all cases of right side.
> 

Ack.

> 
>> +struct catpt_stream_runtime {
>> +	struct snd_pcm_substream *substream;
>> +
>> +	struct catpt_stream_template *template;
>> +	struct catpt_stream_info info;
>> +	struct resource *persistent;
>> +	struct snd_dma_buffer pgtbl;
>> +
> 
>> +	bool allocated:1;
>> +	bool prepared:1;
> 
> Does this ':1' make any sense?
> 

In current state it does not, really. Playing internally with segments 
which are not part of this release (as noted in cover-letter) where some 
of these did. Will remove in v5.

>> +	struct list_head node;
>> +};
> 
> ...
> 
>> +#ifdef CONFIG_PM
> 
> Perhaps __maybe_unused?
> 

Sure, removal of #ifdefs is always nice.

> 
>> +	ret = catpt_dsp_stall(cdev, true);
>> +	if (ret < 0)
> 
> I'm wondering if all these ' < 0' all over the code make sense? What do you
> expect out of positive returned values if any?
> 

Isn't this more of a preference? Please note I'm basing many of my 
decisions on code that's around me - /sound/core/ and sound/soc/ *.c.

Except for IPCs, basically all catpt rets retrieved from functions 
called will be returning either 0 (success) or <0 (error). No 
objections, but I don't see much difference either.

>> +		goto exit;

> 
>> +#ifdef CONFIG_PM_SLEEP
> 
> Perhaps __maybe_unused?
> 

Same as above~1, ack.

> 
>> +	board = platform_device_register_data(NULL, mach->drv_name,
>> +					PLATFORM_DEVID_NONE,
>> +					(const void *)mach, sizeof(*mach));
>> +	if (!board) {
> 
> Here obviously not correct check.
> 

Indeed, ack.

>> +		dev_err(cdev->dev, "board register failed\n");
>> +		return PTR_ERR(board);
>> +	}
>> +
>> +	ret = devm_add_action(cdev->dev, board_pdev_unregister, board);
>> +	if (ret < 0) {
>> +		platform_device_unregister(board);
> 
>> +		return ret;
>> +	}
>> +
>> +	return 0;
> 
> return ret;
> 

Similarly, to comment~2 regarding preferences, don't mind the change (in 
fact, I'm a fan) but in the past got messaged to leave things explicit - 
leave last 'if' with return ret, while return 0 marking success outside.

> 
>> +	mutex_init(&cdev->clk_mutex);
> 
> + blank line.
> 

Thought wide comment makes enough distance already.

>> +	/*
>> +	 * Mark both device formats as uninitialized. Once corresponding
>> +	 * cpu_dai's pcm is created, proper values are assigned
> 
> Please, use period(s) in multi-line comments.
> 

Used to: all-but-last sentence with period(s). Will update as requested 
in v5.

> 
>> +static int catpt_acpi_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct catpt_dev *cdev;
>> +	struct resource *res;
>> +	int ret;
>> +
>> +	cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL);
>> +	if (!cdev)
>> +		return -ENOMEM;
> 
> 
>> +	cdev->spec = device_get_match_data(dev);
>> +	if (!cdev->spec)
>> +		return -ENODEV;
> 
> You may save some cycles if you do this before memory allocations.
> 

i.e. define a local for spec, assign and begin the init process only 
once it's found? Isn't that a loss in most cases? Comes down to:

	declare local + later cdev->spec = spec assignment
	vs
	unlikely -ENODEV with memory being unnecessarily allocated

Perhaps I'm unaware of what's going on with device_get_match_data, but I 
believe .probe() won't get called until one of .acpi_match_table ids 
matches device available on the bus. Existing list of ids won't ever get 
changed as there are only two platforms available for 2011-2013 ADSP 
architecture.

>> +	catpt_dev_init(cdev, dev);
>> +
>> +	/* map DSP bar address */
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	if (!res)
>> +		return -ENODEV;
>> +	cdev->lpe_ba = devm_ioremap(dev, res->start, resource_size(res));
>> +	if (!cdev->lpe_ba)
>> +		return -EIO;
>> +	cdev->lpe_base = res->start;
> 
> Why the region is not get requested?
> 
>> +	/* map PCI bar address */
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>> +	if (!res)
>> +		return -ENODEV;
>> +	cdev->pci_ba = devm_ioremap(dev, res->start, resource_size(res));
>> +	if (!cdev->pci_ba)
>> +		return -EIO;
> 
> Ditto.
> 

Comes from catpt_dmac_probe() (dsp.c) making use of 
devm_ioremap_resource(). If you _get_ requested resource there, the 
function called in catpt_dmac_probe() will yielrd -EBUSY.

This is based on existing code:
/sound/soc/intel/common/sst-acpi.c ::sst_acpi_probe() see mmio assignments.
/sound/soc/intel/common/sst-firmate.ce ::dw_probe() see chip->regs 
assignment.

Perhaps you've found even more problems in existing code than I did..

>> +	/* alloc buffer for storing DRAM context during dx transitions */
>> +	cdev->dxbuf_vaddr = dma_alloc_coherent(dev, catpt_dram_size(cdev),
> 
> dmam_alloc_coherent() ?
> 

Nice! Wasn't aware of this helper. Simplifies error-path too.

>> +					       &cdev->dxbuf_paddr, GFP_KERNEL);
>> +	if (!cdev->dxbuf_vaddr)
>> +		return -ENOMEM;
> 
>> +	ret = platform_get_irq(pdev, 0);
>> +	if (ret < 0)
>> +		goto irq_err;
>> +	cdev->irq = ret;
> 
> But you may return directly if you get IRQ resource before allocation (despite
> previous comment).
> 

Indeed, reordering irq-request and dxbuf allocation would alloc for 
s/goto irq_err/return <err>/
Error-path wouldn't be removed though, as final operation - 
catpt_probe_components - must be verified before leaving scope.

>> +
>> +	platform_set_drvdata(pdev, cdev);
>> +
>> +	ret = devm_request_threaded_irq(dev, cdev->irq, catpt_dsp_irq_handler,
>> +					catpt_dsp_irq_thread,
>> +					IRQF_SHARED, "AudioDSP", cdev);
>> +	if (ret < 0)
>> +		goto irq_err;
>> +
>> +	ret = catpt_probe_components(cdev);
> 
> return ...
> 

With dmam_xxx helper, true.

>> +	if (ret < 0)
>> +		goto irq_err;
>> +	return 0;
>> +
>> +irq_err:
>> +	dma_free_coherent(cdev->dev, catpt_dram_size(cdev),
>> +			  cdev->dxbuf_vaddr, cdev->dxbuf_paddr);
>> +
>> +	return ret;
> 
> This will be gone...
> 

Ditto. Thanks!

>> +}
> 
> ...
> 
>> +static const struct acpi_device_id catpt_ids[] = {
>> +	{ "INT33C8", (unsigned long)&lpt_desc },
>> +	{ "INT3438", (unsigned long)&wpt_desc },
> 
>> +	{ },
> 
> No need to have comma in terminator line.
> 

Well, that's a habbit to add a ',' at the end of each enumeration line 
and I bet it's a good one. No problem removing this one though.

>> +};
> 
> ...
> 
>> +static struct platform_driver catpt_acpi_driver = {
>> +	.probe = catpt_acpi_probe,
>> +	.remove = catpt_acpi_remove,
>> +	.driver = {
>> +		.name = "catpt_adsp",
> 
>> +		.acpi_match_table = ACPI_PTR(catpt_ids),
> 
> ACPI_PTR() either bogus (when you have depends on ACPI) or mistake that brings
> you compiler warning (unused variable).
> 
> I highly recommend in new code avoid completely ACPI_PTR() and of_match_ptr()
> macros.
> 

That's something new for me. Thanks for a good advice.

>> +		.pm = &catpt_dev_pm,
>> +	},
>> +};
> 
> ...
> 
>> +#include <linux/iopoll.h>
> 
> Missed headers:
> bits.h (note, the below guarantees to provide this one)
> bitops.h
> io.h (writel(), readl(), etc)
> 

Removed these as registers.h always gets included with other files which 
already inhering them via nesting.
Will update in v5 as requested.

>> +/* DSP Shim registers */
>> +
>> +#define CATPT_SHIM_CS1		0x0
> 
> Please, keep all register definitions of the same width, like 0x00 here or so.
> 

Ack.

> 
>> +#define CATPT_CS_SFCR(ssp)	BIT(27 + ssp)
> 
> In all macros, try to be a little bit defensive, e.g. here ssp -> (ssp).
> 
> ...
> 
>> +#define CATPT_HMDC_HDDA(e, ch)	BIT(8 * e + ch)
> 
> ...or e -> (e) and ch -> (ch) here.
> 

Agreed, will update in v5.

>> +#define CATPT_CS_DEFAULT	0x8480040E
>> +#define CATPT_IMC_DEFAULT	0x7FFF0003
>> +#define CATPT_IMD_DEFAULT	0x7FFF0003
>> +#define CATPT_CLKCTL_DEFAULT	0x7FF
> 
> These looks like set of bit fields, can we describe them either in comments
> or in the values like GENMASK(x, y) | BIT(z) ?
> 

Let's go with the latter. As explained below, I don't have much info in 
regard to re-setting registers to their defaults. This knowldge might 
come in time (and a ton of testing) but certainly, won't be part of this 
release.

One issue might arise when describing the "reserved" regions as some 
bits should not be modified by sw normally, but are part of "recommended 
sequence" anyway. I'll see if there are any among '1's.

>> +/* PCI Configuration registers */
>> +
>> +#define CATPT_PCI_PMCS		0x84
> 
> Why?! We have PCI capability and entire infrastructure for that in PCI core.
> 
> ...
> 
>> +#define CATPT_PMCS_PS		GENMASK(1, 0)
>> +#define CATPT_PMCS_PS_D3HOT	(0x3 << 0)
> 
> Ditto.
> 

No need for astonishment : ) Wasn't aware of this, in fact, I count on 
more experienced kernel developers - like you Andy - to help others in 
learning about such improvements. Certainly, this isn't knowledge one is 
going to inherit from developing drivers in Windows environment.

Ack.

> 
>> +#define CATPT_SSP_SSC0		0x0
>> +#define CATPT_SSP_SSC1		0x4
>> +#define CATPT_SSP_SSS		0x8
>> +#define CATPT_SSP_SSIT		0xC
>> +#define CATPT_SSP_SSD		0x10
>> +#define CATPT_SSP_SSTO		0x28
>> +#define CATPT_SSP_SSPSP		0x2C
>> +#define CATPT_SSP_SSTSA		0x30
>> +#define CATPT_SSP_SSRSA		0x34
>> +#define CATPT_SSP_SSTSS		0x38
>> +#define CATPT_SSP_SSC2		0x40
>> +#define CATPT_SSP_SSPSP2	0x44
> 
> Isn't it PXA2xx register set? Can you use their definitions?
> 

Could you be more specific? Wasn't able to find anything useful in /include.

> 
>> +#define CATPT_SSP_SSC0_DEFAULT		0x0
>> +#define CATPT_SSP_SSC1_DEFAULT		0x0
>> +#define CATPT_SSP_SSS_DEFAULT		0xF004
>> +#define CATPT_SSP_SSIT_DEFAULT		0x0
>> +#define CATPT_SSP_SSD_DEFAULT		0xC43893A3
>> +#define CATPT_SSP_SSTO_DEFAULT		0x0
>> +#define CATPT_SSP_SSPSP_DEFAULT		0x0
>> +#define CATPT_SSP_SSTSA_DEFAULT		0x0
>> +#define CATPT_SSP_SSRSA_DEFAULT		0x0
>> +#define CATPT_SSP_SSTSS_DEFAULT		0x0
>> +#define CATPT_SSP_SSC2_DEFAULT		0x0
>> +#define CATPT_SSP_SSPSP2_DEFAULT	0x0
> 
> These defaults lack of comments.
> 

Because there aren't any available to choose from. While these are part 
of "recommended sequence", the only comment attached is:
     bring hw to their defaults as hw won't reset itself

catpt is an effort of sw and fw guys, no hw input is included as I've 
found only one guy still @ intel but he is busy with different projects 
and honestly, even if he would agree, him digging now why was this 
needed might take weeks. That's 2011 ADSP architecture, not some 
cutting-edge stuff.

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

* Re: [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations
  2020-08-13 18:51   ` Andy Shevchenko
@ 2020-08-17 11:12     ` Cezary Rojewski
  2020-08-18 11:50       ` Andy Shevchenko
  2020-08-20  7:30       ` Cezary Rojewski
  0 siblings, 2 replies; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-17 11:12 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On 2020-08-13 8:51 PM, Andy Shevchenko wrote:
> On Wed, Aug 12, 2020 at 10:57:42PM +0200, Cezary Rojewski wrote:
>> Implement dsp lifecycle functions such as core RESET and STALL,
>> SRAM power control and LP clock selection. This also adds functions for
>> handling transport over DW DMA controller.

Thanks for your input Andy!

>> +static void catpt_dma_transfer_complete(void *arg)
>> +{
>> +	struct catpt_dev *cdev = arg;
>> +
> 
>> +	dev_dbg(cdev->dev, "%s\n", __func__);
> 
> Noise. Somebody should provide either trace events, of get used to function tracer / perf.
> 

Agree. Don't have much expertise with DMA-engine and some stuff is based 
on existing stuff:
/sound/soc/intel/common/sst-firmware.c ::sst_dma_transfer_complete()

That's not somebody - that's CI. I don't mind ftracer, but our's CI 
logging is currently dmesg/ event traces -based.

Anyway, with log removed, catpt_dma_transfer_complete() ceases to exist too.

> 
>> +static bool catpt_dma_filter(struct dma_chan *chan, void *param)
>> +{
> 
>> +	return chan->device->dev == (struct device *)param;
> 
> Redundant casting, and please, consider to swap left and right side (in this
> case easily to find these and perhaps provide a generic helper function).
> 

Good point. Yeah, I've tried to find generic-helper before even adding 
this, but with no result.

> 
>> +#define CATPT_DMA_DEVID		1 /* dma engine used */
> 
> Not sure I understand what exactly this means.
> 

Well, you may choose either engine 0 or 1 for loading images. Reference 
solution which I'm basing catpt on - Windows driver equivalent - makes 
use of engine 1. Goal of this implementation is to align closely to 
stable Windows solution wherever possible to reduce maintainance cost.

> 
>> +#define CATPT_DMA_MAXBURST	0x3
> 
> We have DMA engine definitions for that, please avoid magic numbers.
> 

As with most of the dma stuff, based on existing:
/sound/soc/intel/common/sst-firmware.c SST_DSP_DMA_MAX_BURST

Ack.

>> +#define CATPT_DMA_DSP_ADDR_MASK	0xFFF00000
> 
> GENMASK()
> 

Ditto as above. Ack.

>> +	dma_cap_set(DMA_SLAVE, mask);
> 
> How this helps with mem2mem channel?
> 
> ...
> 
>> +	chan = dma_request_channel(mask, catpt_dma_filter, cdev->dev);
>> +	if (!chan) {
>> +		dev_err(cdev->dev, "request channel failed\n");
> 
>> +		dump_stack();
> 
> Huh?!
> 

I'm as surpriced as you : )
Remnant of pm_runtime + single platform_device (for adsp and dw both) 
debug. Removed in v5.

>> +		return ERR_PTR(-EPROBE_DEFER);
>> +	}
> 
> ...
> 
>> +	status = dma_wait_for_async_tx(desc);
> 
>> +	catpt_updatel_shim(cdev, HMDC,
>> +			   CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id), 0);
> 
> Update even in erroneous case?
> 

Yes. This is based on stable Windows solution equivalent and get's 
updated even in failure case to disable access to HOST memory in demand 
more.

>> +	return (status == DMA_COMPLETE) ? 0 : -EPROTO;
> 
> ...
> 
>> +static void catpt_dsp_set_srampge(struct catpt_dev *cdev, struct resource *sram,
>> +				  unsigned long mask, unsigned long new)
>> +{
>> +	unsigned long old;
>> +	u32 off = sram->start;
>> +	u32 b = __ffs(mask);
>> +
>> +	old = catpt_readl_pci(cdev, VDRTCTL0) & mask;
> 
>> +	dev_dbg(cdev->dev, "SRAMPGE [0x%08lx] 0x%08lx -> 0x%08lx",
>> +		mask, old, new);
> 
> trace event / point?
> 

Well, I've just replaced these with dev_dbg (from trace events). Not 
many usages and caused all reg-related prints to be available in dmesg.

>> +	if (old == new)
>> +		return;
>> +
>> +	catpt_updatel_pci(cdev, VDRTCTL0, mask, new);
> 
>> +	udelay(60);
> 
> Delays should be commented.
> 

Similarly to previous review (comment regarding hw support), I'm afraid 
I don't have good comments for most occurences available.

I'll try to add something meaningful for at least some of these.

>> +
>> +	/*
>> +	 * dummy read as the very first access after block enable
>> +	 * to prevent byte loss in future operations
>> +	 */
>> +	for_each_clear_bit_from(b, &new, fls(mask)) {
> 
> fls_long()
> 

Ack.

>> +		u8 buf[4];
>> +
>> +		/* newly enabled: new bit=0 while old bit=1 */
>> +		if (test_bit(b, &old)) {
>> +			dev_dbg(cdev->dev, "sanitize block %ld: off 0x%08x\n",
> 
>> +				(b - __ffs(mask)), off);
> 
> Unneeded parentheses.
> 

Ack.

>> +			memcpy_fromio(buf, cdev->lpe_ba + off, sizeof(buf));
>> +		}
>> +		off += CATPT_MEMBLOCK_SIZE;
>> +	}
>> +}
> 
> ...
> 
>> +	/* offset value given mask's start and invert it as ON=b0 */
> 
>> +	new <<= __ffs(mask);
>> +	new = ~(new) & mask;
> 
> Unneeded parentheses.
> And perhaps in one line it will be better to understand:
> 
> 	new = ~(new << __ffs(mask)) & mask;
> 

Was called out in the past not to combine everything in one-line like if 
I'm to hide something from reviewer.

No problem with combining these together in v5.

>> +	if (waiti) {
>> +		/* wait for DSP to signal WAIT state */
>> +		ret = catpt_readl_poll_shim(cdev, ISD,
>> +					    reg, (reg & CATPT_ISD_DCPWM),
>> +					    500, 10000);
>> +		if (ret < 0) {
> 
>> +			dev_warn(cdev->dev, "await WAITI timeout\n");
> 
> Shouldn't be an error level?
> 

As this causes early return, I agree.

>> +			mutex_unlock(&cdev->clk_mutex);
>> +			return ret;
>> +		}
>> +	}
> 
> ...
> 
>> +int catpt_dsp_update_lpclock(struct catpt_dev *cdev)
>> +{
>> +	struct catpt_stream_runtime *stream;
> 
>> +	bool lp;
>> +
>> +	if (list_empty(&cdev->stream_list))
>> +		return catpt_dsp_select_lpclock(cdev, true, true);
>> +
>> +	lp = true;
>> +	list_for_each_entry(stream, &cdev->stream_list, node) {
>> +		if (stream->prepared) {
>> +			lp = false;
>> +			break;
>> +		}
>> +	}
>> +
>> +	return catpt_dsp_select_lpclock(cdev, lp, true);
> 
> Seems too much duplication.
> 
> 	struct catpt_stream_runtime *stream;
> 
> 	list_for_each_entry(stream, &cdev->stream_list, node) {
> 		if (stream->prepared)
> 			return catpt_dsp_select_lpclock(cdev, false, true);
> 	}
> 
> 	return catpt_dsp_select_lpclock(cdev, true, true);
> 
> 
> Better?
> 

list_first_entry (part of list_for_each_entry) expects list to be 
non-empty. ->streal_list may be empty when invoking 
catpt_dsp_update_lpclock().

>> +	/* set D3 */
>> +	catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, CATPT_PMCS_PS_D3HOT);
>> +	udelay(50);
> 
> Don't we have PCI core function for this?
> 
> ...
> 
>> +	/* set D0 */
>> +	catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, 0);
>> +	udelay(100);
> 
> Ditto.
> 
> ...
> 
>> +	/* set D3 */
>> +	catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, CATPT_PMCS_PS_D3HOT);
>> +	udelay(50);
> 
> Ditto.
> 
> ...
> 
>> +	/* set D0 */
>> +	catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, 0);
> 
> Ditto.
> 

Thanks to you now I know the correct answer: yes.
Ack for all of these. Good advice Andy, again!

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

* Re: [PATCH v4 01/13] ASoC: Intel: Add catpt device
  2020-08-17 10:02     ` Cezary Rojewski
@ 2020-08-18 10:07       ` Andy Shevchenko
  2020-08-19 13:26         ` Cezary Rojewski
  2020-08-25 20:43       ` Cezary Rojewski
  1 sibling, 1 reply; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-18 10:07 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Mon, Aug 17, 2020 at 12:02:39PM +0200, Cezary Rojewski wrote:
> On 2020-08-13 8:29 PM, Andy Shevchenko wrote:
> > On Wed, Aug 12, 2020 at 10:57:41PM +0200, Cezary Rojewski wrote:
> 
> Thanks for good review Andy!

You're welcome!

...

> > JFYI, I have just submitted a series [1] that includes this helper [2]
> > to be available for all.
> > 
> > [1]: https://lore.kernel.org/linux-acpi/20200813175729.15088-1-andriy.shevchenko@linux.intel.com/
> > [2]: https://lore.kernel.org/linux-acpi/20200813175729.15088-4-andriy.shevchenko@linux.intel.com/
> > 
> 
> Well, I'm happy that catpt somewhat impacted resource-API getting more
> flexble, although it would be nice to get --cc'ed as
> _overlapping/_intersecting got moved into general part of kernel without
> changes, basically.
> 
> This raises a dependancy issue, am I right? i.e. until this gets merged,
> catpt will cause compilation errors on Mark's for-next. -or- perhaps you
> want me to leave things as they are for current release while removing said
> function later, once your PR get's merged?

I hope Rafael accepts the v2 soon and thus may provide an immutable branch to
be consumed by others. That's the way how usually we solve cross-subsystem
series.

In any case we still have time for better review of the rest of the series.

...

> > > +struct catpt_dev {
> > > +	struct device *dev;
> > 
> > > +	struct dw_dma_chip *dmac;
> > 
> > Is it possible to use opaque pointer here? It will be better if in the future
> > (I think unlikely, but still) somebody decides to use this with another DMA
> > engine.
> 
> Any opaque structure comes at a cost -> requires higher level of
> understanding from developers maintaining given piece of code (that includes
> architecture knowledge too, to get a grasp of why such decision was even
> made) == higher maintaince cost.
> 
> One could device ADSP architectures into:
> 1) LPT/WPT
> 2) BYT/CHT/BDW
> 3) cAVS (SKL+)
> 4) new (which I won't be elaborating here for obvious reasons)
> 
> To my knowledge, except for 1), none of them makes use of dmaengine.h when
> loading FW or doing any other action for that matter. As such, I don't see
> any reason to convert something explicit into something implicit. Don't
> believe either of options would be reusing struct catpt_dev too. In general,
> to make that happen you'd have to start with conversion of existing HDAudio
> transport (cAVS+) into dmaengine model and then do the same with SoundWire
> (cAVS+) - haven't seen sdw code in a while but still pretty sure it's not
> dmaengine-friendly.


Some documentation says that Audio is using iDMA 32-bit in (some?) BSW/CHT,
some documentation says otherwise (Synopsys DesignWare). Can you somewhere
clarify what the actual state of affairs? I remember even some (android?) ASoC
code used to have different type of DMA engines because of that.

...

> > > +	if (ret < 0)
> > 
> > I'm wondering if all these ' < 0' all over the code make sense? What do you
> > expect out of positive returned values if any?
> > 
> 
> Isn't this more of a preference? Please note I'm basing many of my decisions
> on code that's around me - /sound/core/ and sound/soc/ *.c.
> 
> Except for IPCs, basically all catpt rets retrieved from functions called
> will be returning either 0 (success) or <0 (error). No objections, but I
> don't see much difference either.

In case some will return positive code you may hide the (potential) issue.
I prefer be explicit over implicit, means use ' < 0' only where it makes sense.

> > > +		goto exit;

...

> > > +	ret = devm_add_action(cdev->dev, board_pdev_unregister, board);
> > > +	if (ret < 0) {
> > > +		platform_device_unregister(board);
> > 
> > > +		return ret;
> > > +	}
> > > +
> > > +	return 0;
> > 
> > return ret;
> > 
> 
> Similarly, to comment~2 regarding preferences, don't mind the change (in
> fact, I'm a fan) but in the past got messaged to leave things explicit -
> leave last 'if' with return ret, while return 0 marking success outside.

Actually you may simplify by calling devm_add_action_or_reset() instead.

...

> > > +	cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL);
> > > +	if (!cdev)
> > > +		return -ENOMEM;
> > 
> > 
> > > +	cdev->spec = device_get_match_data(dev);
> > > +	if (!cdev->spec)
> > > +		return -ENODEV;
> > 
> > You may save some cycles if you do this before memory allocations.
> > 
> 
> i.e. define a local for spec, assign and begin the init process only once
> it's found? Isn't that a loss in most cases? Comes down to:
> 
> 	declare local + later cdev->spec = spec assignment
> 	vs
> 	unlikely -ENODEV with memory being unnecessarily allocated
> 
> Perhaps I'm unaware of what's going on with device_get_match_data, but I
> believe .probe() won't get called until one of .acpi_match_table ids matches
> device available on the bus. Existing list of ids won't ever get changed as
> there are only two platforms available for 2011-2013 ADSP architecture.

Up to you but I consider cleaner code if we don't do heavier operation ahead
when lighter ones can fail.

...

> > > +	/* map DSP bar address */
> > > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > +	if (!res)
> > > +		return -ENODEV;
> > > +	cdev->lpe_ba = devm_ioremap(dev, res->start, resource_size(res));
> > > +	if (!cdev->lpe_ba)
> > > +		return -EIO;
> > > +	cdev->lpe_base = res->start;
> > 
> > Why the region is not get requested?
> > 
> > > +	/* map PCI bar address */
> > > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> > > +	if (!res)
> > > +		return -ENODEV;
> > > +	cdev->pci_ba = devm_ioremap(dev, res->start, resource_size(res));
> > > +	if (!cdev->pci_ba)
> > > +		return -EIO;
> > 
> > Ditto.
> > 
> 
> Comes from catpt_dmac_probe() (dsp.c) making use of devm_ioremap_resource().
> If you _get_ requested resource there, the function called in
> catpt_dmac_probe() will yielrd -EBUSY.
> 
> This is based on existing code:
> /sound/soc/intel/common/sst-acpi.c ::sst_acpi_probe() see mmio assignments.
> /sound/soc/intel/common/sst-firmate.ce ::dw_probe() see chip->regs
> assignment.
> 
> Perhaps you've found even more problems in existing code than I did..

Hmm... But isn't catpt_dmac_probe(), actually what is in the DMA engine driver
beneath, should take care of the requesting *and* remapping resource?

...

> > > +		.acpi_match_table = ACPI_PTR(catpt_ids),
> > 
> > ACPI_PTR() either bogus (when you have depends on ACPI) or mistake that brings
> > you compiler warning (unused variable).
> > 
> > I highly recommend in new code avoid completely ACPI_PTR() and of_match_ptr()
> > macros.
> > 
> 
> That's something new for me. Thanks for a good advice.

Basically of_match_ptr / ACPI_PTR should go together with ugly ifdeffery,
otherwise neither of them should be present. If the driver can be compiled but
won't be functional w/o OF / ACPI dependency, then we do something like

	depends on ACPI || COMPILE_TEST

to give a hint to the user.

...

> > > +#include <linux/iopoll.h>
> > 
> > Missed headers:
> > bits.h (note, the below guarantees to provide this one)
> > bitops.h
> > io.h (writel(), readl(), etc)
> > 
> 
> Removed these as registers.h always gets included with other files which
> already inhering them via nesting.
> Will update in v5 as requested.

The rule of thumb is to include headers which we are direct users of.
This is listed in Submit Patches Checklist document AFAIR.

...

> > > +#define CATPT_SSP_SSC0		0x0
> > > +#define CATPT_SSP_SSC1		0x4
> > > +#define CATPT_SSP_SSS		0x8
> > > +#define CATPT_SSP_SSIT		0xC
> > > +#define CATPT_SSP_SSD		0x10
> > > +#define CATPT_SSP_SSTO		0x28
> > > +#define CATPT_SSP_SSPSP		0x2C
> > > +#define CATPT_SSP_SSTSA		0x30
> > > +#define CATPT_SSP_SSRSA		0x34
> > > +#define CATPT_SSP_SSTSS		0x38
> > > +#define CATPT_SSP_SSC2		0x40
> > > +#define CATPT_SSP_SSPSP2	0x44
> > 
> > Isn't it PXA2xx register set? Can you use their definitions?
> > 
> 
> Could you be more specific? Wasn't able to find anything useful in /include.

include/linux/pxa2xx_ssp.h

...

> > These defaults lack of comments.
> > 
> 
> Because there aren't any available to choose from. While these are part of
> "recommended sequence", the only comment attached is:
>     bring hw to their defaults as hw won't reset itself
> 
> catpt is an effort of sw and fw guys, no hw input is included as I've found
> only one guy still @ intel but he is busy with different projects and
> honestly, even if he would agree, him digging now why was this needed might
> take weeks. That's 2011 ADSP architecture, not some cutting-edge stuff.

I understand, but try your best to leave at least a little trail of these...
Sometimes, btw, so called Production Kernel repository (patches there) may give
a hint. Lately, during AtomISP v2 resurrection, it appears that Intel Aero
platform has support there and a lot of quirks available somewhere.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations
  2020-08-17 11:12     ` Cezary Rojewski
@ 2020-08-18 11:50       ` Andy Shevchenko
  2020-08-19 13:46         ` Cezary Rojewski
  2020-08-20  7:30       ` Cezary Rojewski
  1 sibling, 1 reply; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-18 11:50 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Mon, Aug 17, 2020 at 01:12:01PM +0200, Cezary Rojewski wrote:
> On 2020-08-13 8:51 PM, Andy Shevchenko wrote:
> > On Wed, Aug 12, 2020 at 10:57:42PM +0200, Cezary Rojewski wrote:
> > > Implement dsp lifecycle functions such as core RESET and STALL,
> > > SRAM power control and LP clock selection. This also adds functions for
> > > handling transport over DW DMA controller.
> 
> Thanks for your input Andy!

You're welcome!

...

> > > +#define CATPT_DMA_DEVID		1 /* dma engine used */
> > 
> > Not sure I understand what exactly this means.
> > 
> 
> Well, you may choose either engine 0 or 1 for loading images. Reference
> solution which I'm basing catpt on - Windows driver equivalent - makes use
> of engine 1. Goal of this implementation is to align closely to stable
> Windows solution wherever possible to reduce maintainance cost.

Please, give extended comment here.

...

> > > +	status = dma_wait_for_async_tx(desc);
> > 
> > > +	catpt_updatel_shim(cdev, HMDC,
> > > +			   CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id), 0);
> > 
> > Update even in erroneous case?
> > 
> 
> Yes. This is based on stable Windows solution equivalent and get's updated
> even in failure case to disable access to HOST memory in demand more.

I guess this deserves a comment.

> > > +	return (status == DMA_COMPLETE) ? 0 : -EPROTO;

...

> > > +	new <<= __ffs(mask);
> > > +	new = ~(new) & mask;
> > 
> > Unneeded parentheses.
> > And perhaps in one line it will be better to understand:
> > 
> > 	new = ~(new << __ffs(mask)) & mask;
> > 
> 
> Was called out in the past not to combine everything in one-line like if I'm
> to hide something from reviewer.
> 
> No problem with combining these together in v5.

you also may consider to use u32_replace_bits() or so.

...

> > > +	bool lp;
> > > +
> > > +	if (list_empty(&cdev->stream_list))
> > > +		return catpt_dsp_select_lpclock(cdev, true, true);
> > > +
> > > +	lp = true;
> > > +	list_for_each_entry(stream, &cdev->stream_list, node) {
> > > +		if (stream->prepared) {
> > > +			lp = false;
> > > +			break;
> > > +		}
> > > +	}
> > > +
> > > +	return catpt_dsp_select_lpclock(cdev, lp, true);
> > 
> > Seems too much duplication.
> > 
> > 	struct catpt_stream_runtime *stream;
> > 
> > 	list_for_each_entry(stream, &cdev->stream_list, node) {
> > 		if (stream->prepared)
> > 			return catpt_dsp_select_lpclock(cdev, false, true);
> > 	}
> > 
> > 	return catpt_dsp_select_lpclock(cdev, true, true);
> > 
> > 
> > Better?
> 
> list_first_entry (part of list_for_each_entry) expects list to be non-empty.
> ->streal_list may be empty when invoking catpt_dsp_update_lpclock().

I didn't get this. Can you point out where is exactly problematic place?

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 01/13] ASoC: Intel: Add catpt device
  2020-08-18 10:07       ` Andy Shevchenko
@ 2020-08-19 13:26         ` Cezary Rojewski
  2020-08-19 13:43           ` Andy Shevchenko
  0 siblings, 1 reply; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-19 13:26 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On 2020-08-18 12:07 PM, Andy Shevchenko wrote:
> On Mon, Aug 17, 2020 at 12:02:39PM +0200, Cezary Rojewski wrote:
>> On 2020-08-13 8:29 PM, Andy Shevchenko wrote:
>>> On Wed, Aug 12, 2020 at 10:57:41PM +0200, Cezary Rojewski wrote:
>>
>> Thanks for good review Andy!
> 
> You're welcome!
> 

>>>> +struct catpt_dev {
>>>> +	struct device *dev;
>>>
>>>> +	struct dw_dma_chip *dmac;
>>>
>>> Is it possible to use opaque pointer here? It will be better if in the future
>>> (I think unlikely, but still) somebody decides to use this with another DMA
>>> engine.
>>
>> Any opaque structure comes at a cost -> requires higher level of
>> understanding from developers maintaining given piece of code (that includes
>> architecture knowledge too, to get a grasp of why such decision was even
>> made) == higher maintaince cost.
>>
>> One could device ADSP architectures into:
>> 1) LPT/WPT
>> 2) BYT/CHT/BDW
>> 3) cAVS (SKL+)
>> 4) new (which I won't be elaborating here for obvious reasons)
>>
>> To my knowledge, except for 1), none of them makes use of dmaengine.h when
>> loading FW or doing any other action for that matter. As such, I don't see
>> any reason to convert something explicit into something implicit. Don't
>> believe either of options would be reusing struct catpt_dev too. In general,
>> to make that happen you'd have to start with conversion of existing HDAudio
>> transport (cAVS+) into dmaengine model and then do the same with SoundWire
>> (cAVS+) - haven't seen sdw code in a while but still pretty sure it's not
>> dmaengine-friendly.
> 
> 
> Some documentation says that Audio is using iDMA 32-bit in (some?) BSW/CHT,
> some documentation says otherwise (Synopsys DesignWare). Can you somewhere
> clarify what the actual state of affairs? I remember even some (android?) ASoC
> code used to have different type of DMA engines because of that.

Well, we are supporting Android for HDA-based platforms only. At least 
that's true for Androids my team is covering. LPT/WPT and BYT/CHT/BSW 
architectures are not part of that coverage (and I'm not aware of any 
support for these on Android, probably some hard-maintainance with no 
possibility of changes). As HDA DMAs are made use of during image 
loading in cAVS+, there is no need for enlisting DW DMAC.

BYT/CHT/BSW support moved to /sound/soc/intel/atom (away from 
/sound/soc/intel/baytrail in case of BYT) mostly with support available 
in SOF too. Support for that architecture in either of the solutions is 
not within my area of expertise but I don't believe any DMAC is enlisted 
there either.

>>>> +	if (ret < 0)
>>>
>>> I'm wondering if all these ' < 0' all over the code make sense? What do you
>>> expect out of positive returned values if any?
>>>
>>
>> Isn't this more of a preference? Please note I'm basing many of my decisions
>> on code that's around me - /sound/core/ and sound/soc/ *.c.
>>
>> Except for IPCs, basically all catpt rets retrieved from functions called
>> will be returning either 0 (success) or <0 (error). No objections, but I
>> don't see much difference either.
> 
> In case some will return positive code you may hide the (potential) issue.
> I prefer be explicit over implicit, means use ' < 0' only where it makes sense.
> 

Ack.

>>>> +	ret = devm_add_action(cdev->dev, board_pdev_unregister, board);
>>>> +	if (ret < 0) {
>>>> +		platform_device_unregister(board);
>>>
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>
>>> return ret;
>>>
>>
>> Similarly, to comment~2 regarding preferences, don't mind the change (in
>> fact, I'm a fan) but in the past got messaged to leave things explicit -
>> leave last 'if' with return ret, while return 0 marking success outside.
> 
> Actually you may simplify by calling devm_add_action_or_reset() instead.
> 

Indeed, that simplifies things. Ack.

>>>> +	cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL);
>>>> +	if (!cdev)
>>>> +		return -ENOMEM;
>>>
>>>
>>>> +	cdev->spec = device_get_match_data(dev);
>>>> +	if (!cdev->spec)
>>>> +		return -ENODEV;
>>>
>>> You may save some cycles if you do this before memory allocations.
>>>
>>
>> i.e. define a local for spec, assign and begin the init process only once
>> it's found? Isn't that a loss in most cases? Comes down to:
>>
>> 	declare local + later cdev->spec = spec assignment
>> 	vs
>> 	unlikely -ENODEV with memory being unnecessarily allocated
>>
>> Perhaps I'm unaware of what's going on with device_get_match_data, but I
>> believe .probe() won't get called until one of .acpi_match_table ids matches
>> device available on the bus. Existing list of ids won't ever get changed as
>> there are only two platforms available for 2011-2013 ADSP architecture.
> 
> Up to you but I consider cleaner code if we don't do heavier operation ahead
> when lighter ones can fail.
> 

And this is a very good approach. Thought device_get_match_data is 
'heavier' than the devm_kzalloc.

>>>> +	/* map DSP bar address */
>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>> +	if (!res)
>>>> +		return -ENODEV;
>>>> +	cdev->lpe_ba = devm_ioremap(dev, res->start, resource_size(res));
>>>> +	if (!cdev->lpe_ba)
>>>> +		return -EIO;
>>>> +	cdev->lpe_base = res->start;
>>>
>>> Why the region is not get requested?
>>>
>>>> +	/* map PCI bar address */
>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>>>> +	if (!res)
>>>> +		return -ENODEV;
>>>> +	cdev->pci_ba = devm_ioremap(dev, res->start, resource_size(res));
>>>> +	if (!cdev->pci_ba)
>>>> +		return -EIO;
>>>
>>> Ditto.
>>>
>>
>> Comes from catpt_dmac_probe() (dsp.c) making use of devm_ioremap_resource().
>> If you _get_ requested resource there, the function called in
>> catpt_dmac_probe() will yielrd -EBUSY.
>>
>> This is based on existing code:
>> /sound/soc/intel/common/sst-acpi.c ::sst_acpi_probe() see mmio assignments.
>> /sound/soc/intel/common/sst-firmate.ce ::dw_probe() see chip->regs
>> assignment.
>>
>> Perhaps you've found even more problems in existing code than I did..
> 
> Hmm... But isn't catpt_dmac_probe(), actually what is in the DMA engine driver
> beneath, should take care of the requesting *and* remapping resource?
> 
> ...
> 

One could say ADSP subsystem in LPT/WPT is made of following modules:
- dsp (shim) space
- 2x dma (engine 0 & 1)
- 2x ssp (with 1 tasked with BT-paths and 0 for non-BT-paths)

Recommended sequences in dsp.c (_power_up/ _power_down) will be 
operating only on SHIM and SSP spaces. DMA space is actually only 
accessed when dumping memory during device coredump. Because of that 
though, I cannot say "adsp will never access DMA space".

-

I did some testing today and indeed very simple approach suffices:
- devm_platform_get_and_ioremap_resource for DSP bar
- devm_platform_ioremap_resource for PCI bar
- instead of doing devm_ioremap_resource() separately for dmac in 
catpt_dmac_probe(), just do:

dmac->regs = cdev->lpe_ba + cdev->spec->host_dma_offset[<engine id>]

>>>> +		.acpi_match_table = ACPI_PTR(catpt_ids),
>>>
>>> ACPI_PTR() either bogus (when you have depends on ACPI) or mistake that brings
>>> you compiler warning (unused variable).
>>>
>>> I highly recommend in new code avoid completely ACPI_PTR() and of_match_ptr()
>>> macros.
>>>
>>
>> That's something new for me. Thanks for a good advice.
> 
> Basically of_match_ptr / ACPI_PTR should go together with ugly ifdeffery,
> otherwise neither of them should be present. If the driver can be compiled but
> won't be functional w/o OF / ACPI dependency, then we do something like
> 
> 	depends on ACPI || COMPILE_TEST
> 
> to give a hint to the user.
> 

Ack(s) all the way.

>>>> +#include <linux/iopoll.h>
>>>
>>> Missed headers:
>>> bits.h (note, the below guarantees to provide this one)
>>> bitops.h
>>> io.h (writel(), readl(), etc)
>>>
>>
>> Removed these as registers.h always gets included with other files which
>> already inhering them via nesting.
>> Will update in v5 as requested.
> 
> The rule of thumb is to include headers which we are direct users of.
> This is listed in Submit Patches Checklist document AFAIR.
> 

Thanks for info! Ack.

>>>> +#define CATPT_SSP_SSC0		0x0
>>>> +#define CATPT_SSP_SSC1		0x4
>>>> +#define CATPT_SSP_SSS		0x8
>>>> +#define CATPT_SSP_SSIT		0xC
>>>> +#define CATPT_SSP_SSD		0x10 and
>>>> +#define CATPT_SSP_SSTO		0x28
>>>> +#define CATPT_SSP_SSPSP		0x2C
>>>> +#define CATPT_SSP_SSTSA		0x30
>>>> +#define CATPT_SSP_SSRSA		0x34
>>>> +#define CATPT_SSP_SSTSS		0x38
>>>> +#define CATPT_SSP_SSC2		0x40
>>>> +#define CATPT_SSP_SSPSP2	0x44
>>>
>>> Isn't it PXA2xx register set? Can you use their definitions?
>>>
>>
>> Could you be more specific? Wasn't able to find anything useful in /include.
> 
> include/linux/pxa2xx_ssp.h
> 

Did some reconnaissance and it while this registers are shared, LPT/WPT 
are equipped with a newer version of said ssp device with some old 
functionalities have been removed too. So the question comes down to: do 
I re-use PXA2XX registers due to historical background (inheritance) 
-or- leave it explicit as is. Honestly, I don't really mind either of 
these. Got surprised by short register names in mentioned header though.

>>> These defaults lack of comments.
>>>
>>
>> Because there aren't any available to choose from. While these are part of
>> "recommended sequence", the only comment attached is:
>>      bring hw to their defaults as hw won't reset itself
>>
>> catpt is an effort of sw and fw guys, no hw input is included as I've found
>> only one guy still @ intel but he is busy with different projects and
>> honestly, even if he would agree, him digging now why was this needed might
>> take weeks. That's 2011 ADSP architecture, not some cutting-edge stuff.
> 
> I understand, but try your best to leave at least a little trail of these...
> Sometimes, btw, so called Production Kernel repository (patches there) may give
> a hint. Lately, during AtomISP v2 resurrection, it appears that Intel Aero
> platform has support there and a lot of quirks available somewhere.
> 

I'll see what I can do.

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

* Re: [PATCH v4 01/13] ASoC: Intel: Add catpt device
  2020-08-19 13:26         ` Cezary Rojewski
@ 2020-08-19 13:43           ` Andy Shevchenko
  2020-08-25  9:32             ` Cezary Rojewski
  0 siblings, 1 reply; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-19 13:43 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Wed, Aug 19, 2020 at 03:26:04PM +0200, Cezary Rojewski wrote:
> On 2020-08-18 12:07 PM, Andy Shevchenko wrote:
> > On Mon, Aug 17, 2020 at 12:02:39PM +0200, Cezary Rojewski wrote:
> > > On 2020-08-13 8:29 PM, Andy Shevchenko wrote:
> > > > On Wed, Aug 12, 2020 at 10:57:41PM +0200, Cezary Rojewski wrote:

...

> And this is a very good approach. Thought device_get_match_data is 'heavier'
> than the devm_kzalloc.

Memory allocation in 90% cases are heavier then the rest (because of page fault
exceptions).

...

> I did some testing today and indeed very simple approach suffices:
> - devm_platform_get_and_ioremap_resource for DSP bar
> - devm_platform_ioremap_resource for PCI bar
> - instead of doing devm_ioremap_resource() separately for dmac in
> catpt_dmac_probe(), just do:
> 
> dmac->regs = cdev->lpe_ba + cdev->spec->host_dma_offset[<engine id>]

Yes, something like this. Basically what you have is particular case of MFD
(see drivers/mfd for other uses).

...

> > > > > +#define CATPT_SSP_SSC0		0x0
> > > > > +#define CATPT_SSP_SSC1		0x4
> > > > > +#define CATPT_SSP_SSS		0x8
> > > > > +#define CATPT_SSP_SSIT		0xC
> > > > > +#define CATPT_SSP_SSD		0x10 and
> > > > > +#define CATPT_SSP_SSTO		0x28
> > > > > +#define CATPT_SSP_SSPSP		0x2C
> > > > > +#define CATPT_SSP_SSTSA		0x30
> > > > > +#define CATPT_SSP_SSRSA		0x34
> > > > > +#define CATPT_SSP_SSTSS		0x38
> > > > > +#define CATPT_SSP_SSC2		0x40
> > > > > +#define CATPT_SSP_SSPSP2	0x44
> > > > 
> > > > Isn't it PXA2xx register set? Can you use their definitions?
> > > 
> > > Could you be more specific? Wasn't able to find anything useful in /include.
> > 
> > include/linux/pxa2xx_ssp.h
> 
> Did some reconnaissance and it while this registers are shared, LPT/WPT are
> equipped with a newer version of said ssp device with some old
> functionalities have been removed too. So the question comes down to: do I
> re-use PXA2XX registers due to historical background (inheritance) -or-
> leave it explicit as is. Honestly, I don't really mind either of these. Got
> surprised by short register names in mentioned header though.

Short names are for historical reasons, but you may change them over the
kernel, if you wish (I think you won't spend time on this).

My vision is to extend that header to cover changes and use it in your code.
It might, though, require some cleanups to be done against pxa2xx_ssp.h.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations
  2020-08-18 11:50       ` Andy Shevchenko
@ 2020-08-19 13:46         ` Cezary Rojewski
  2020-08-19 14:21           ` Andy Shevchenko
  0 siblings, 1 reply; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-19 13:46 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On 2020-08-18 1:50 PM, Andy Shevchenko wrote:
> On Mon, Aug 17, 2020 at 01:12:01PM +0200, Cezary Rojewski wrote:
>> On 2020-08-13 8:51 PM, Andy Shevchenko wrote:
>>> On Wed, Aug 12, 2020 at 10:57:42PM +0200, Cezary Rojewski wrote:
>>>> Implement dsp lifecycle functions such as core RESET and STALL,
>>>> SRAM power control and LP clock selection. This also adds functions for
>>>> handling transport over DW DMA controller.
>>
>> Thanks for your input Andy!
> 
> You're welcome!
> 

>>>> +#define CATPT_DMA_DEVID		1 /* dma engine used */
>>>
>>> Not sure I understand what exactly this means.
>>>
>>
>> Well, you may choose either engine 0 or 1 for loading images. Reference
>> solution which I'm basing catpt on - Windows driver equivalent - makes use
>> of engine 1. Goal of this implementation is to align closely to stable
>> Windows solution wherever possible to reduce maintainance cost.
> 
> Please, give extended comment here.
> 

Sure, ack.

>>>> +	status = dma_wait_for_async_tx(desc);
>>>
>>>> +	catpt_updatel_shim(cdev, HMDC,
>>>> +			   CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id), 0);
>>>
>>> Update even in erroneous case?
>>>
>>
>> Yes. This is based on stable Windows solution equivalent and get's updated
>> even in failure case to disable access to HOST memory in demand more.
> 
> I guess this deserves a comment.
> 

Ditto.

>>>> +	return (status == DMA_COMPLETE) ? 0 : -EPROTO;
> 
> ...
> 
>>>> +	new <<= __ffs(mask);
>>>> +	new = ~(new) & mask;
>>>
>>> Unneeded parentheses.
>>> And perhaps in one line it will be better to understand:
>>>
>>> 	new = ~(new << __ffs(mask)) & mask;
>>>
>>
>> Was called out in the past not to combine everything in one-line like if I'm
>> to hide something from reviewer.
>>
>> No problem with combining these together in v5.
> 
> you also may consider to use u32_replace_bits() or so.
> 

I'll check bitfields.h too, sure.

>>>> +	bool lp;
>>>> +
>>>> +	if (list_empty(&cdev->stream_list))
>>>> +		return catpt_dsp_select_lpclock(cdev, true, true);
>>>> +
>>>> +	lp = true;
>>>> +	list_for_each_entry(stream, &cdev->stream_list, node) {
>>>> +		if (stream->prepared) {
>>>> +			lp = false;
>>>> +			break;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	return catpt_dsp_select_lpclock(cdev, lp, true);
>>>
>>> Seems too much duplication.
>>>
>>> 	struct catpt_stream_runtime *stream;
>>>
>>> 	list_for_each_entry(stream, &cdev->stream_list, node) {
>>> 		if (stream->prepared)
>>> 			return catpt_dsp_select_lpclock(cdev, false, true);
>>> 	}
>>>
>>> 	return catpt_dsp_select_lpclock(cdev, true, true);
>>>
>>>
>>> Better?
>>
>> list_first_entry (part of list_for_each_entry) expects list to be non-empty.
>> ->streal_list may be empty when invoking catpt_dsp_update_lpclock().
> 
> I didn't get this. Can you point out where is exactly problematic place?
> 

list_for_each_entry makes use of list_first_entry when initializing 
'pos' index variable. Documentation for list_first_entry reads: "Note, 
that list is expected to be not empty" so I'm validating list's status 
before moving on to the loop as stream_list may be empty when 
catpt_dsp_update_lpclock() gets called.

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

* Re: [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations
  2020-08-19 13:46         ` Cezary Rojewski
@ 2020-08-19 14:21           ` Andy Shevchenko
  2020-08-19 14:54             ` Cezary Rojewski
  0 siblings, 1 reply; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-19 14:21 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Wed, Aug 19, 2020 at 03:46:30PM +0200, Cezary Rojewski wrote:
> On 2020-08-18 1:50 PM, Andy Shevchenko wrote:
> > On Mon, Aug 17, 2020 at 01:12:01PM +0200, Cezary Rojewski wrote:
> > > On 2020-08-13 8:51 PM, Andy Shevchenko wrote:
> > > > On Wed, Aug 12, 2020 at 10:57:42PM +0200, Cezary Rojewski wrote:

...

> > > > > +	bool lp;
> > > > > +
> > > > > +	if (list_empty(&cdev->stream_list))
> > > > > +		return catpt_dsp_select_lpclock(cdev, true, true);
> > > > > +
> > > > > +	lp = true;
> > > > > +	list_for_each_entry(stream, &cdev->stream_list, node) {
> > > > > +		if (stream->prepared) {
> > > > > +			lp = false;
> > > > > +			break;
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	return catpt_dsp_select_lpclock(cdev, lp, true);
> > > > 
> > > > Seems too much duplication.
> > > > 
> > > > 	struct catpt_stream_runtime *stream;
> > > > 
> > > > 	list_for_each_entry(stream, &cdev->stream_list, node) {
> > > > 		if (stream->prepared)
> > > > 			return catpt_dsp_select_lpclock(cdev, false, true);
> > > > 	}
> > > > 
> > > > 	return catpt_dsp_select_lpclock(cdev, true, true);
> > > > 
> > > > 
> > > > Better?
> > > 
> > > list_first_entry (part of list_for_each_entry) expects list to be non-empty.
> > > ->streal_list may be empty when invoking catpt_dsp_update_lpclock().
> > 
> > I didn't get this. Can you point out where is exactly problematic place?
> > 
> 
> list_for_each_entry makes use of list_first_entry when initializing 'pos'
> index variable.

Correct.

> Documentation for list_first_entry reads: "Note, that list
> is expected to be not empty"

Correct.

> so I'm validating list's status before moving
> on to the loop as stream_list may be empty when catpt_dsp_update_lpclock()
> gets called.

But here you missed the second part of the for-loop, i.e. exit conditional.

If your assumption (that list_for_each_*() is not empty-safe) is correct,
it would be disaster in global kernel source level.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations
  2020-08-19 14:21           ` Andy Shevchenko
@ 2020-08-19 14:54             ` Cezary Rojewski
  0 siblings, 0 replies; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-19 14:54 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On 2020-08-19 4:21 PM, Andy Shevchenko wrote:
> On Wed, Aug 19, 2020 at 03:46:30PM +0200, Cezary Rojewski wrote:
>> On 2020-08-18 1:50 PM, Andy Shevchenko wrote:
>>> On Mon, Aug 17, 2020 at 01:12:01PM +0200, Cezary Rojewski wrote:
>>>> On 2020-08-13 8:51 PM, Andy Shevchenko wrote:
>>>>> On Wed, Aug 12, 2020 at 10:57:42PM +0200, Cezary Rojewski wrote:

>>>>>> +	bool lp;
>>>>>> +
>>>>>> +	if (list_empty(&cdev->stream_list))
>>>>>> +		return catpt_dsp_select_lpclock(cdev, true, true);
>>>>>> +
>>>>>> +	lp = true;
>>>>>> +	list_for_each_entry(stream, &cdev->stream_list, node) {
>>>>>> +		if (stream->prepared) {
>>>>>> +			lp = false;
>>>>>> +			break;
>>>>>> +		}
>>>>>> +	}
>>>>>> +
>>>>>> +	return catpt_dsp_select_lpclock(cdev, lp, true);
>>>>>
>>>>> Seems too much duplication.
>>>>>
>>>>> 	struct catpt_stream_runtime *stream;
>>>>>
>>>>> 	list_for_each_entry(stream, &cdev->stream_list, node) {
>>>>> 		if (stream->prepared)
>>>>> 			return catpt_dsp_select_lpclock(cdev, false, true);
>>>>> 	}
>>>>>
>>>>> 	return catpt_dsp_select_lpclock(cdev, true, true);
>>>>>
>>>>>
>>>>> Better?
>>>>
>>>> list_first_entry (part of list_for_each_entry) expects list to be non-empty.
>>>> ->streal_list may be empty when invoking catpt_dsp_update_lpclock().
>>>
>>> I didn't get this. Can you point out where is exactly problematic place?
>>>
>>
>> list_for_each_entry makes use of list_first_entry when initializing 'pos'
>> index variable.
> 
> Correct.
> 
>> Documentation for list_first_entry reads: "Note, that list
>> is expected to be not empty"
> 
> Correct.
> 
>> so I'm validating list's status before moving
>> on to the loop as stream_list may be empty when catpt_dsp_update_lpclock()
>> gets called.
> 
> But here you missed the second part of the for-loop, i.e. exit conditional.
> 
> If your assumption (that list_for_each_*() is not empty-safe) is correct,
> it would be disaster in global kernel source level.
> 

We want no disasters here : )
safety-out. Ack.

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

* Re: [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations
  2020-08-17 11:12     ` Cezary Rojewski
  2020-08-18 11:50       ` Andy Shevchenko
@ 2020-08-20  7:30       ` Cezary Rojewski
  2020-08-20  9:00         ` Andy Shevchenko
  1 sibling, 1 reply; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-20  7:30 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On 2020-08-17 1:12 PM, Cezary Rojewski wrote:
> On 2020-08-13 8:51 PM, Andy Shevchenko wrote:
>> On Wed, Aug 12, 2020 at 10:57:42PM +0200, Cezary Rojewski wrote:

>>
>>> +#define CATPT_DMA_MAXBURST    0x3
>>
>> We have DMA engine definitions for that, please avoid magic numbers.
>>
> 
> As with most of the dma stuff, based on existing:
> /sound/soc/intel/common/sst-firmware.c SST_DSP_DMA_MAX_BURST
> 
> Ack.
> 

Actually, wasn't able to find anything _MAXBURST related in dmaengine.h. 
_BUSWIDTH_ have their constants defined there, true, but I'm already 
making use of these and this is dst/src_maxburst we're talking about. 
 From what I've seen in kernel sources, most usages are direct 
assignments: xxx_maxburst = Y;

>>> +    /* set D3 */
>>> +    catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, CATPT_PMCS_PS_D3HOT);
>>> +    udelay(50);
>>
>> Don't we have PCI core function for this?
>>
>> ...
>>
>>> +    /* set D0 */
>>> +    catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, 0);
>>> +    udelay(100);
>>
>> Ditto.
>>
>> ...
>>
>>> +    /* set D3 */
>>> +    catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, CATPT_PMCS_PS_D3HOT);
>>> +    udelay(50);
>>
>> Ditto.
>>
>> ...
>>
>>> +    /* set D0 */
>>> +    catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, 0);
>>
>> Ditto.
>>
> 
> Thanks to you now I know the correct answer: yes.
> Ack for all of these. Good advice Andy, again!

Similar situation occurred here. What we're dealing with is: instance of 
'struct platform_device' type, found on bus: acpi with PCI set as a 
parent device.

Scope found in DSDT:
	\_SB_.PCI0.ADSP
sysfs device path:
	/sys/devices/pci0000:00/INT3438:00
Within the latter _no_ standard utility files will be available e.g.: 
ability to dump PCI config space, bars and such.

I haven't found any functionality to extract "pci_companion" from a 
platform_device. What can be made use of is: PCI_D3hot and PCI_D0 enum 
constants, as pci_set_power_state() does not apply - expects struct 
pci_dev *.

Perhaps got misled by the function naming? catpt_updatel_xxx helpers: 
_xxx denotes specific ADSP device's mmio space. Almost all cases are 
covered by _pci and _shim.

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

* Re: [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations
  2020-08-20  7:30       ` Cezary Rojewski
@ 2020-08-20  9:00         ` Andy Shevchenko
  2020-08-24 16:33           ` Cezary Rojewski
  0 siblings, 1 reply; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-20  9:00 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Thu, Aug 20, 2020 at 09:30:13AM +0200, Cezary Rojewski wrote:
> On 2020-08-17 1:12 PM, Cezary Rojewski wrote:
> > On 2020-08-13 8:51 PM, Andy Shevchenko wrote:
> > > On Wed, Aug 12, 2020 at 10:57:42PM +0200, Cezary Rojewski wrote:

...

> > > > +#define CATPT_DMA_MAXBURST    0x3
> > > 
> > > We have DMA engine definitions for that, please avoid magic numbers.
> > 
> > As with most of the dma stuff, based on existing:
> > /sound/soc/intel/common/sst-firmware.c SST_DSP_DMA_MAX_BURST
> > 
> > Ack.
> 
> Actually, wasn't able to find anything _MAXBURST related in dmaengine.h.
> _BUSWIDTH_ have their constants defined there, true, but I'm already making
> use of these and this is dst/src_maxburst we're talking about. From what
> I've seen in kernel sources, most usages are direct assignments:
> xxx_maxburst = Y;

Okay, and how 0x3 bytes can be a burst? Does DMA engine support this?

...

> > > > +    /* set D3 */
> > > > +    catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, CATPT_PMCS_PS_D3HOT);
> > > > +    udelay(50);
> > > 
> > > Don't we have PCI core function for this?
> > > 
> > > > +    /* set D0 */
> > > > +    catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, 0);
> > > > +    udelay(100);
> > > 
> > > Ditto.
> > > 
> > > > +    /* set D3 */
> > > > +    catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, CATPT_PMCS_PS_D3HOT);
> > > > +    udelay(50);
> > > 
> > > Ditto.
> > > 
> > > > +    /* set D0 */
> > > > +    catpt_updatel_pci(cdev, PMCS, CATPT_PMCS_PS, 0);
> > > 
> > > Ditto.
> > 
> > Thanks to you now I know the correct answer: yes.
> > Ack for all of these. Good advice Andy, again!
> 
> Similar situation occurred here. What we're dealing with is: instance of
> 'struct platform_device' type, found on bus: acpi with PCI set as a parent
> device.
> 
> Scope found in DSDT:
> 	\_SB_.PCI0.ADSP
> sysfs device path:
> 	/sys/devices/pci0000:00/INT3438:00
> Within the latter _no_ standard utility files will be available e.g.:
> ability to dump PCI config space, bars and such.

I see. Can you dump DSDT somewhere? We are interested in
PSx/PRx/PSE/PSW/PSC/PRE/PRW/ON/OFF (x=0..3) methods.

> I haven't found any functionality to extract "pci_companion" from a
> platform_device. What can be made use of is: PCI_D3hot and PCI_D0 enum
> constants, as pci_set_power_state() does not apply - expects struct pci_dev
> *.
> 
> Perhaps got misled by the function naming? catpt_updatel_xxx helpers: _xxx
> denotes specific ADSP device's mmio space. Almost all cases are covered by
> _pci and _shim.

If we really need to use these commands directly, utilize at least definitions
from PCI core, e.g. PCI_D0, PCI_D3hot, PCI_PM_CTRL.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations
  2020-08-20  9:00         ` Andy Shevchenko
@ 2020-08-24 16:33           ` Cezary Rojewski
  2020-08-25 13:16             ` Andy Shevchenko
  0 siblings, 1 reply; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-24 16:33 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On 2020-08-20 11:00 AM, Andy Shevchenko wrote:
> On Thu, Aug 20, 2020 at 09:30:13AM +0200, Cezary Rojewski wrote:
>> On 2020-08-17 1:12 PM, Cezary Rojewski wrote:
>>> On 2020-08-13 8:51 PM, Andy Shevchenko wrote:
>>>> On Wed, Aug 12, 2020 at 10:57:42PM +0200, Cezary Rojewski wrote:

>>>>> +#define CATPT_DMA_MAXBURST    0x3
>>>>
>>>> We have DMA engine definitions for that, please avoid magic numbers.
>>>
>>> As with most of the dma stuff, based on existing:
>>> /sound/soc/intel/common/sst-firmware.c SST_DSP_DMA_MAX_BURST
>>>
>>> Ack.
>>
>> Actually, wasn't able to find anything _MAXBURST related in dmaengine.h.
>> _BUSWIDTH_ have their constants defined there, true, but I'm already making
>> use of these and this is dst/src_maxburst we're talking about. From what
>> I've seen in kernel sources, most usages are direct assignments:
>> xxx_maxburst = Y;
> 
> Okay, and how 0x3 bytes can be a burst? Does DMA engine support this?
> 

That's a very good question. Early this morning starting digging.

I believe this stems from attempt of sst_dsp_dma_get_channel() to serve 
two masters - MID DMAC and DW DMAC - at the same time.

Intel MID DMAC has been first introduced in version v2.6.36-rc1 and 
subsequently removed in v4.1-rc1 due to lack of any usage throughout its 
whole life. Reference:
	https://cateee.net/lkddb/web-lkddb/INTEL_MID_DMAC.html

files to look for in said kernel versions:
	drivers/dma/intel_mid_dma.c
	drivers/dma/intel_mid_regs.h

As MID DMAC is supposed to handle Langwell PCH which is coupled with 
Atom CPUs my guess is that /atom/ was supposed to make use of said DMAC 
at certain point in time which actually never happened. This is backed 
up by the following:

/haswell/ makes use of DW DMAC but that wasn't always the case - 
solution, which was first introduced in v3.15-rc1 have had the 
sst_dma_new() and friends (wrappers calling dw_dma_probe()) implemented 
only since v3.19-rc1. So, there was a period in time where both 
solutions were not using any DMAC whatsoever. As stated, in v3.19-rc1 
/haswell/ moved to recommended flow where DW DMAC gets involved in image 
loading. The same cannot be said about /atom/ -or- /baytrail/ for that 
matter and that is why I believe MID DMAC got removed, eventually.

Now, one can notice the following when viewing older versions of 
/haswell/ e.g.:
	https://elixir.bootlin.com/linux/v4.0.9/source/sound/soc/intel/sst-firmware.c#L224

notice the comment mentioning why sst_dsp_dma_get_channel() is somewhat 
ambiguous:
	The Intel MID DMA engine driver needs the slave config set but
	Synopsis DMA engine driver safely ignores the slave config

And thus:
	dma_cap_set(DMA_SLAVE, mask);
is flagged only because of MID DMAC while causing no harm to DW. As MID 
no longer exists, so should DMA_SLAVE flagging. This should answer your 
question from:

On 2020-08-13 8:51 PM, Andy Shevchenko wrote:
 > On Wed, Aug 12, 2020 at 10:57:42PM +0200, Cezary Rojewski wrote:
 >> Implement dsp lifecycle functions such as core RESET and STALL,
 >> SRAM power control and LP clock selection. This also adds functions for
 >> handling transport over DW DMA controller.
 >
 >> +	dma_cap_set(DMA_SLAVE, mask);
 >
 > How this helps with mem2mem channel?
 >

In regard to maxburst, (SST_DSP_DMA_MAX_BURST 0x3) this is again mixture 
of MID & DW expectations - MID owns no conversion code, value assigned 
to src_/dst_maxburst is taken directly:

	https://elixir.bootlin.com/linux/v4.0.9/source/drivers/dma/intel_mid_dma.c#L495
vs
	https://elixir.bootlin.com/linux/v4.0.9/source/drivers/dma/dw/core.c#L965
notice convert_burst() (/drivers/dma/dw has seen several improvements 
and code isn't identical in newer kernels but functionality remains the 
same)

combine that knowledge with:
	enum dw_dma_msize {
		DW_DMA_MSIZE_1,
		DW_DMA_MSIZE_4,
		DW_DMA_MSIZE_8,
		DW_DMA_MSIZE_16,

from:
	https://elixir.bootlin.com/linux/v4.0.9/source/drivers/dma/dw/regs.h#L135

and one can safely assume maxburst is mistakenly set for DW - direct 
enum constant is used, ignoring the fact that is it DW code which 
converts provided value behind the scenes to appropriate one. Currently 
we end up with:
fls(0x3) -> 2;
2 - 2 = 0 (conversion method) -> DW_DMA_MSIZE_1

Conclusion: I believe DW_DMA_MSIZE_16 (0x3) is the correct one i.e.:
	src_maxburst = 16;
	dst_maxburst = 16;
should be present within catpt_dma_request_config_chan().

>>
>> Similar situation occurred here. What we're dealing with is: instance of
>> 'struct platform_device' type, found on bus: acpi with PCI set as a parent
>> device.
>>
>> Scope found in DSDT:
>> 	\_SB_.PCI0.ADSP
>> sysfs device path:
>> 	/sys/devices/pci0000:00/INT3438:00
>> Within the latter _no_ standard utility files will be available e.g.:
>> ability to dump PCI config space, bars and such.
> 
> I see. Can you dump DSDT somewhere? We are interested in
> PSx/PRx/PSE/PSW/PSC/PRE/PRW/ON/OFF (x=0..3) methods.
> 
>> I haven't found any functionality to extract "pci_companion" from a
>> platform_device. What can be made use of is: PCI_D3hot and PCI_D0 enum
>> constants, as pci_set_power_state() does not apply - expects struct pci_dev
>> *.
>>
>> Perhaps got misled by the function naming? catpt_updatel_xxx helpers: _xxx
>> denotes specific ADSP device's mmio space. Almost all cases are covered by
>> _pci and _shim.
> 
> If we really need to use these commands directly, utilize at least definitions
> from PCI core, e.g. PCI_D0, PCI_D3hot, PCI_PM_CTRL.
> 

Kudos to you, Andy, for taking time and debugging ACPI tables from our 
BDW machines.
Unfortunately explicit _updatel_pci for d3hot/d0 will have to remain as 
there is no other way to cause explicit power_state change for the device.

Another question though: PCI_PM_CTRL. In order for me to make use of 
this, "pm_cap" member would have to be declared for my device. As this 
is no struct pci_dev, catpt has currently no separate member for that 
purpose. I don't believe you want me to add that field into struct's 
declaration.
Second option is to define constant for pm_cap offset aka 0x80 within 
registers.h and then do the operations as follows:
	catpt_updatel_pci(cdev, CATPT_PM_CAP + PCI_PM_CTRL, ...)

However, in such case I won't be able to make use of current version of 
_updatel_pci() as definition of that macro allows me to skip prefix and 
type implicitly - PMCS (the rest is appended automatically).
Maybe let's leave it within registers.h altogether so I can actually 
keep using said macro?

Czarek

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

* Re: [PATCH v4 01/13] ASoC: Intel: Add catpt device
  2020-08-19 13:43           ` Andy Shevchenko
@ 2020-08-25  9:32             ` Cezary Rojewski
  2020-08-25 13:18               ` Andy Shevchenko
  0 siblings, 1 reply; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-25  9:32 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On 2020-08-19 3:43 PM, Andy Shevchenko wrote:
> On Wed, Aug 19, 2020 at 03:26:04PM +0200, Cezary Rojewski wrote:
>> On 2020-08-18 12:07 PM, Andy Shevchenko wrote:
>>> On Mon, Aug 17, 2020 at 12:02:39PM +0200, Cezary Rojewski wrote:
>>>> On 2020-08-13 8:29 PM, Andy Shevchenko wrote:
>>>>> On Wed, Aug 12, 2020 at 10:57:41PM +0200, Cezary Rojewski wrote:

>>>>>> +#define CATPT_SSP_SSC0		0x0
>>>>>> +#define CATPT_SSP_SSC1		0x4
>>>>>> +#define CATPT_SSP_SSS		0x8
>>>>>> +#define CATPT_SSP_SSIT		0xC
>>>>>> +#define CATPT_SSP_SSD		0x10 and
>>>>>> +#define CATPT_SSP_SSTO		0x28
>>>>>> +#define CATPT_SSP_SSPSP		0x2C
>>>>>> +#define CATPT_SSP_SSTSA		0x30
>>>>>> +#define CATPT_SSP_SSRSA		0x34
>>>>>> +#define CATPT_SSP_SSTSS		0x38
>>>>>> +#define CATPT_SSP_SSC2		0x40
>>>>>> +#define CATPT_SSP_SSPSP2	0x44
>>>>>
>>>>> Isn't it PXA2xx register set? Can you use their definitions?
>>>>
>>>> Could you be more specific? Wasn't able to find anything useful in /include.
>>>
>>> include/linux/pxa2xx_ssp.h
>>
>> Did some reconnaissance and it while this registers are shared, LPT/WPT are
>> equipped with a newer version of said ssp device with some old
>> functionalities have been removed too. So the question comes down to: do I
>> re-use PXA2XX registers due to historical background (inheritance) -or-
>> leave it explicit as is. Honestly, I don't really mind either of these. Got
>> surprised by short register names in mentioned header though.
> 
> Short names are for historical reasons, but you may change them over the
> kernel, if you wish (I think you won't spend time on this).
> 
> My vision is to extend that header to cover changes and use it in your code.
> It might, though, require some cleanups to be done against pxa2xx_ssp.h.
> 

Conclusion from checking pxa2_ssp.h registers:

- SSPSP2 is missing (0x44)
- SSC2 vs SSACDD (0x40) both same offset but different purpose so 
probably new define would have to be added

As situation is similar to the resource-API case below are the options:
a) ship catpt with existing ssp reg set, update pxa2_ssp.h in following 
series and then re-use them for catpt
b) update pxa2_ssp.h first, await merge, ship catpt only afterward

I vote for option a) given the maturity driver is reaching plus I'd 
rather be done with sound/soc/intel/ sanitization sooner than later.

Czarek

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

* Re: [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations
  2020-08-24 16:33           ` Cezary Rojewski
@ 2020-08-25 13:16             ` Andy Shevchenko
  2020-08-25 13:23               ` Andy Shevchenko
  2020-08-27 10:06               ` Cezary Rojewski
  0 siblings, 2 replies; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-25 13:16 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Mon, Aug 24, 2020 at 06:33:17PM +0200, Cezary Rojewski wrote:
> On 2020-08-20 11:00 AM, Andy Shevchenko wrote:
> > On Thu, Aug 20, 2020 at 09:30:13AM +0200, Cezary Rojewski wrote:
> > > On 2020-08-17 1:12 PM, Cezary Rojewski wrote:
> > > > On 2020-08-13 8:51 PM, Andy Shevchenko wrote:
> > > > > On Wed, Aug 12, 2020 at 10:57:42PM +0200, Cezary Rojewski wrote:
> 
> > > > > > +#define CATPT_DMA_MAXBURST    0x3
> > > > > 
> > > > > We have DMA engine definitions for that, please avoid magic numbers.
> > > > 
> > > > As with most of the dma stuff, based on existing:
> > > > /sound/soc/intel/common/sst-firmware.c SST_DSP_DMA_MAX_BURST
> > > > 
> > > > Ack.
> > > 
> > > Actually, wasn't able to find anything _MAXBURST related in dmaengine.h.
> > > _BUSWIDTH_ have their constants defined there, true, but I'm already making
> > > use of these and this is dst/src_maxburst we're talking about. From what
> > > I've seen in kernel sources, most usages are direct assignments:
> > > xxx_maxburst = Y;
> > 
> > Okay, and how 0x3 bytes can be a burst? Does DMA engine support this?
> > 
> 
> That's a very good question. Early this morning starting digging.
> 
> I believe this stems from attempt of sst_dsp_dma_get_channel() to serve two
> masters - MID DMAC and DW DMAC - at the same time.
> 
> Intel MID DMAC has been first introduced in version v2.6.36-rc1 and
> subsequently removed in v4.1-rc1 due to lack of any usage throughout its
> whole life. Reference:
> 	https://cateee.net/lkddb/web-lkddb/INTEL_MID_DMAC.html
> 
> files to look for in said kernel versions:
> 	drivers/dma/intel_mid_dma.c
> 	drivers/dma/intel_mid_regs.h
> 
> As MID DMAC is supposed to handle Langwell PCH which is coupled with Atom
> CPUs my guess is that /atom/ was supposed to make use of said DMAC at
> certain point in time which actually never happened. This is backed up by
> the following:
> 
> /haswell/ makes use of DW DMAC but that wasn't always the case - solution,
> which was first introduced in v3.15-rc1 have had the sst_dma_new() and
> friends (wrappers calling dw_dma_probe()) implemented only since v3.19-rc1.
> So, there was a period in time where both solutions were not using any DMAC
> whatsoever. As stated, in v3.19-rc1 /haswell/ moved to recommended flow
> where DW DMAC gets involved in image loading. The same cannot be said about
> /atom/ -or- /baytrail/ for that matter and that is why I believe MID DMAC
> got removed, eventually.

Yes, I have removed it because it's a copy cat of Synopsys DesignWare. At Intel
at that time Vinod, who was developing that driver, had probably no idea that
he is reinventing the wheel. This theory is supported by (internal)
documentation for Medfield which has no words Synopsys, DesignWare in it.

> Now, one can notice the following when viewing older versions of /haswell/
> e.g.:
> 	https://elixir.bootlin.com/linux/v4.0.9/source/sound/soc/intel/sst-firmware.c#L224
> 
> notice the comment mentioning why sst_dsp_dma_get_channel() is somewhat
> ambiguous:
> 	The Intel MID DMA engine driver needs the slave config set but
> 	Synopsis DMA engine driver safely ignores the slave config
> 
> And thus:
> 	dma_cap_set(DMA_SLAVE, mask);
> is flagged only because of MID DMAC while causing no harm to DW. As MID no
> longer exists, so should DMA_SLAVE flagging. This should answer your
> question from:
> 
> On 2020-08-13 8:51 PM, Andy Shevchenko wrote:
> > On Wed, Aug 12, 2020 at 10:57:42PM +0200, Cezary Rojewski wrote:
> >> Implement dsp lifecycle functions such as core RESET and STALL,
> >> SRAM power control and LP clock selection. This also adds functions for
> >> handling transport over DW DMA controller.
> >
> >> +	dma_cap_set(DMA_SLAVE, mask);
> >
> > How this helps with mem2mem channel?
> >
> 
> In regard to maxburst, (SST_DSP_DMA_MAX_BURST 0x3) this is again mixture of
> MID & DW expectations - MID owns no conversion code, value assigned to
> src_/dst_maxburst is taken directly:
> 
> 	https://elixir.bootlin.com/linux/v4.0.9/source/drivers/dma/intel_mid_dma.c#L495
> vs
> 	https://elixir.bootlin.com/linux/v4.0.9/source/drivers/dma/dw/core.c#L965
> notice convert_burst() (/drivers/dma/dw has seen several improvements and
> code isn't identical in newer kernels but functionality remains the same)

Correct.

> combine that knowledge with:
> 	enum dw_dma_msize {
> 		DW_DMA_MSIZE_1,
> 		DW_DMA_MSIZE_4,
> 		DW_DMA_MSIZE_8,
> 		DW_DMA_MSIZE_16,
> 
> from:
> 	https://elixir.bootlin.com/linux/v4.0.9/source/drivers/dma/dw/regs.h#L135
> 
> and one can safely assume maxburst is mistakenly set for DW - direct enum
> constant is used, ignoring the fact that is it DW code which converts
> provided value behind the scenes to appropriate one. Currently we end up
> with:
> fls(0x3) -> 2;
> 2 - 2 = 0 (conversion method) -> DW_DMA_MSIZE_1
> 
> Conclusion: I believe DW_DMA_MSIZE_16 (0x3) is the correct one i.e.:
> 	src_maxburst = 16;
> 	dst_maxburst = 16;
> should be present within catpt_dma_request_config_chan().

Yes!

> > > Similar situation occurred here. What we're dealing with is: instance of
> > > 'struct platform_device' type, found on bus: acpi with PCI set as a parent
> > > device.
> > > 
> > > Scope found in DSDT:
> > > 	\_SB_.PCI0.ADSP
> > > sysfs device path:
> > > 	/sys/devices/pci0000:00/INT3438:00
> > > Within the latter _no_ standard utility files will be available e.g.:
> > > ability to dump PCI config space, bars and such.
> > 
> > I see. Can you dump DSDT somewhere? We are interested in
> > PSx/PRx/PSE/PSW/PSC/PRE/PRW/ON/OFF (x=0..3) methods.
> > 
> > > I haven't found any functionality to extract "pci_companion" from a
> > > platform_device. What can be made use of is: PCI_D3hot and PCI_D0 enum
> > > constants, as pci_set_power_state() does not apply - expects struct pci_dev
> > > *.
> > > 
> > > Perhaps got misled by the function naming? catpt_updatel_xxx helpers: _xxx
> > > denotes specific ADSP device's mmio space. Almost all cases are covered by
> > > _pci and _shim.
> > 
> > If we really need to use these commands directly, utilize at least definitions
> > from PCI core, e.g. PCI_D0, PCI_D3hot, PCI_PM_CTRL.
> > 
> 
> Kudos to you, Andy, for taking time and debugging ACPI tables from our BDW
> machines.
> Unfortunately explicit _updatel_pci for d3hot/d0 will have to remain as
> there is no other way to cause explicit power_state change for the device.

I see, thanks for checking this.

> Another question though: PCI_PM_CTRL. In order for me to make use of this,
> "pm_cap" member would have to be declared for my device. As this is no
> struct pci_dev, catpt has currently no separate member for that purpose. I
> don't believe you want me to add that field into struct's declaration.
> Second option is to define constant for pm_cap offset aka 0x80 within
> registers.h and then do the operations as follows:
> 	catpt_updatel_pci(cdev, CATPT_PM_CAP + PCI_PM_CTRL, ...)

> However, in such case I won't be able to make use of current version of
> _updatel_pci() as definition of that macro allows me to skip prefix and type
> implicitly - PMCS (the rest is appended automatically).
> Maybe let's leave it within registers.h altogether so I can actually keep
> using said macro?

Basically what you do with accessing PCI configuration space via these methods
(catpt_update_pci(), etc) is something repetitive / similar to what xHCI DbC
support code does. I recommend to spend some time to look for similarities here
(catpt) and there (PCI core, xHCI DbC, etc) and, if we were lucky, derive
common helpers for traverse the capability list in more generalized way.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 01/13] ASoC: Intel: Add catpt device
  2020-08-25  9:32             ` Cezary Rojewski
@ 2020-08-25 13:18               ` Andy Shevchenko
  2020-08-25 13:19                 ` Andy Shevchenko
  0 siblings, 1 reply; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-25 13:18 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Tue, Aug 25, 2020 at 11:32:57AM +0200, Cezary Rojewski wrote:
> On 2020-08-19 3:43 PM, Andy Shevchenko wrote:
> > On Wed, Aug 19, 2020 at 03:26:04PM +0200, Cezary Rojewski wrote:

...

> > My vision is to extend that header to cover changes and use it in your code.
> > It might, though, require some cleanups to be done against pxa2xx_ssp.h.
> 
> Conclusion from checking pxa2_ssp.h registers:
> 
> - SSPSP2 is missing (0x44)
> - SSC2 vs SSACDD (0x40) both same offset but different purpose so probably
> new define would have to be added
> 
> As situation is similar to the resource-API case below are the options:
> a) ship catpt with existing ssp reg set, update pxa2_ssp.h in following
> series and then re-use them for catpt
> b) update pxa2_ssp.h first, await merge, ship catpt only afterward
> 
> I vote for option a) given the maturity driver is reaching plus I'd rather
> be done with sound/soc/intel/ sanitization sooner than later.

Luckily we have Mark to maintain both SPI and ASoC, which means you may prepend
your series with PXA2xx header update and have his Ack for it. He can create an
immutable branch and apply it to SPI tree afterwards, or other way around. So I
definitely vote for b).

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 01/13] ASoC: Intel: Add catpt device
  2020-08-25 13:18               ` Andy Shevchenko
@ 2020-08-25 13:19                 ` Andy Shevchenko
  0 siblings, 0 replies; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-25 13:19 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Tue, Aug 25, 2020 at 04:18:21PM +0300, Andy Shevchenko wrote:
> On Tue, Aug 25, 2020 at 11:32:57AM +0200, Cezary Rojewski wrote:
> > On 2020-08-19 3:43 PM, Andy Shevchenko wrote:
> > > On Wed, Aug 19, 2020 at 03:26:04PM +0200, Cezary Rojewski wrote:

...

> > > My vision is to extend that header to cover changes and use it in your code.
> > > It might, though, require some cleanups to be done against pxa2xx_ssp.h.
> > 
> > Conclusion from checking pxa2_ssp.h registers:
> > 
> > - SSPSP2 is missing (0x44)
> > - SSC2 vs SSACDD (0x40) both same offset but different purpose so probably
> > new define would have to be added
> > 
> > As situation is similar to the resource-API case below are the options:
> > a) ship catpt with existing ssp reg set, update pxa2_ssp.h in following
> > series and then re-use them for catpt
> > b) update pxa2_ssp.h first, await merge, ship catpt only afterward
> > 
> > I vote for option a) given the maturity driver is reaching plus I'd rather
> > be done with sound/soc/intel/ sanitization sooner than later.
> 
> Luckily we have Mark to maintain both SPI and ASoC, which means you may prepend
> your series with PXA2xx header update and have his Ack for it. He can create an
> immutable branch and apply it to SPI tree afterwards, or other way around. So I
> definitely vote for b).

Let's say "for b+)" mean the fast track of the changes to both subsystems.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations
  2020-08-25 13:16             ` Andy Shevchenko
@ 2020-08-25 13:23               ` Andy Shevchenko
  2020-08-27 10:06               ` Cezary Rojewski
  1 sibling, 0 replies; 43+ messages in thread
From: Andy Shevchenko @ 2020-08-25 13:23 UTC (permalink / raw)
  To: Cezary Rojewski
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On Tue, Aug 25, 2020 at 04:16:15PM +0300, Andy Shevchenko wrote:
> On Mon, Aug 24, 2020 at 06:33:17PM +0200, Cezary Rojewski wrote:
> > On 2020-08-20 11:00 AM, Andy Shevchenko wrote:

...

> > Another question though: PCI_PM_CTRL. In order for me to make use of this,
> > "pm_cap" member would have to be declared for my device. As this is no
> > struct pci_dev, catpt has currently no separate member for that purpose. I
> > don't believe you want me to add that field into struct's declaration.
> > Second option is to define constant for pm_cap offset aka 0x80 within
> > registers.h and then do the operations as follows:
> > 	catpt_updatel_pci(cdev, CATPT_PM_CAP + PCI_PM_CTRL, ...)
> 
> > However, in such case I won't be able to make use of current version of
> > _updatel_pci() as definition of that macro allows me to skip prefix and type
> > implicitly - PMCS (the rest is appended automatically).
> > Maybe let's leave it within registers.h altogether so I can actually keep
> > using said macro?
> 
> Basically what you do with accessing PCI configuration space via these methods
> (catpt_update_pci(), etc) is something repetitive / similar to what xHCI DbC
> support code does. I recommend to spend some time to look for similarities here
> (catpt) and there (PCI core, xHCI DbC, etc) and, if we were lucky, derive
> common helpers for traverse the capability list in more generalized way.

Throwing the idea loud: perhaps we may have something like regmap-pci.c to
access PCI configuration space and make regmap API to take care of which IO
accessors (and locking) will be used.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 01/13] ASoC: Intel: Add catpt device
  2020-08-17 10:02     ` Cezary Rojewski
  2020-08-18 10:07       ` Andy Shevchenko
@ 2020-08-25 20:43       ` Cezary Rojewski
  1 sibling, 0 replies; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-25 20:43 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On 2020-08-17 12:02 PM, Cezary Rojewski wrote:
> On 2020-08-13 8:29 PM, Andy Shevchenko wrote:
>> On Wed, Aug 12, 2020 at 10:57:41PM +0200, Cezary Rojewski wrote:

...

>>> +#define CATPT_CS_DEFAULT    0x8480040E
>>> +#define CATPT_IMC_DEFAULT    0x7FFF0003
>>> +#define CATPT_IMD_DEFAULT    0x7FFF0003
>>> +#define CATPT_CLKCTL_DEFAULT    0x7FF
>>
>> These looks like set of bit fields, can we describe them either in 
>> comments
>> or in the values like GENMASK(x, y) | BIT(z) ?
>>
> 
> Let's go with the latter. As explained below, I don't have much info in 
> regard to re-setting registers to their defaults. This knowldge might 
> come in time (and a ton of testing) but certainly, won't be part of this 
> release.
> 
> One issue might arise when describing the "reserved" regions as some 
> bits should not be modified by sw normally, but are part of "recommended 
> sequence" anyway. I'll see if there are any among '1's.
> 

In regard to your comment related to defaults, I've provided WPT ADSP 
Cspec within previously shared location:

	\\10.237.149.136\AudioDspShare\crojewsk\acpi\bdw-y
Note: Chapter 50.7 describes the register map.

What I've said in the last paragraph proved true - many (in some cases 
most..) bits are of 'Reserved' type. Because of spaghetti generated when 
attempting to mask this, I'd stick with existing, explicit default 
values which are frankly more readable.
I've added single comment above each _DEFAULT block instead:
	/* defaults to reset SSP|SHIM registers to after each power cycle */

Thanks once again for your input during 'catpt' upstream process.
Please note I'll remove the Cspec from linked location as soon as I read 
your response to this e-mail (probably tomorrow morning).

Czarek

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

* Re: [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations
  2020-08-25 13:16             ` Andy Shevchenko
  2020-08-25 13:23               ` Andy Shevchenko
@ 2020-08-27 10:06               ` Cezary Rojewski
  1 sibling, 0 replies; 43+ messages in thread
From: Cezary Rojewski @ 2020-08-27 10:06 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: pierre-louis.bossart, alsa-devel, filip.kaczmarski,
	harshapriya.n, marcin.barlik, zwisler, lgirdwood, tiwai,
	filip.proborszcz, broonie, amadeuszx.slawinski, michal.wasko,
	cujomalainey, krzysztof.hejmowski, ppapierkowski,
	vamshi.krishna.gopal

On 2020-08-25 3:16 PM, Andy Shevchenko wrote:
> On Mon, Aug 24, 2020 at 06:33:17PM +0200, Cezary Rojewski wrote:
>> On 2020-08-20 11:00 AM, Andy Shevchenko wrote:

...

>> Another question though: PCI_PM_CTRL. In order for me to make use of this,
>> "pm_cap" member would have to be declared for my device. As this is no
>> struct pci_dev, catpt has currently no separate member for that purpose. I
>> don't believe you want me to add that field into struct's declaration.
>> Second option is to define constant for pm_cap offset aka 0x80 within
>> registers.h and then do the operations as follows:
>> 	catpt_updatel_pci(cdev, CATPT_PM_CAP + PCI_PM_CTRL, ...)
> 
>> However, in such case I won't be able to make use of current version of
>> _updatel_pci() as definition of that macro allows me to skip prefix and type
>> implicitly - PMCS (the rest is appended automatically).
>> Maybe let's leave it within registers.h altogether so I can actually keep
>> using said macro?
> 
> Basically what you do with accessing PCI configuration space via these methods
> (catpt_update_pci(), etc) is something repetitive / similar to what xHCI DbC
> support code does. I recommend to spend some time to look for similarities here
> (catpt) and there (PCI core, xHCI DbC, etc) and, if we were lucky, derive
> common helpers for traverse the capability list in more generalized way.
> 

I wouldn't call direct-access a repetitive procedure, i.e. had procedure 
for enumerating PCI capabilities list been implemented individually by 
every PCI device type, then one can describe that as repetitiveness. 
Here, we are dealing with no procedure at all, just a writel & readl.

About xHCI, I believe you meant: xhci_find_next_ext_cap()
	https://elixir.bootlin.com/linux/latest/source/drivers/usb/host/xhci-ext-caps.h#L97

in case of PCI that's: pci_find_next_capability(), __pci_find_next_cap() 
and friends. pci_find_next_capability() is pci_dev dependent while most 
of the rest pci_bus instead. We fail both dependencies in catpt case.

xhci_find_next_ext_cap search method seems xHCI-specific, notice the 
0x10 offset for HCCPARAMS1 and then the left-shift-by-2. PCI doesn't do 
that when enumerating capabilities, instead it checks Capabilities 
List-bit within Status reg and then begins iterating given the start pos 
- Capability Pointer, usually 0x34. Abstracting these (if even possible) 
would end up with 80% code gluing two different worlds with 20% left 
doing the actual job. Fact that those two are separated increases code 
readability.

While catpt is of platform_device type located on acpi bus, beneath 
there's a (incomplete?) description of PCI device.

PCI config
catpt_acpi_probe00000000: 9cb68086 00100006 04010003 00000000
catpt_acpi_probe00000010: fe000000 fe100000 00000000 00000000
catpt_acpi_probe00000020: 00000000 00000000 00000000 00000000
catpt_acpi_probe00000030: 00000000 00000080 00000000 00000100

PCI base + 0x80
catpt_acpi_probe00000000: 40030001 0000000b 00000000 00000000
catpt_acpi_probe00000010: 00000000 00000000 00000000 00000000
catpt_acpi_probe00000020: fffffffd 00000000 80000fff 00000000
catpt_acpi_probe00000030: 00000000 00000000 00000000 00000000

Capabilities List-bit is set, start pos from Capabilitiy Pointer equals 
0x80. What we have here is singular list of capabilities - PM as the 
only element. Following is the important DWORD (_PM_CTRL) - 0xb tells us 
that device is currently in D3hot. For LPT/WPT ADSP basically all other 
PM bits are hardwired to 0 or not supported.

So, quite frankly, had the BIOS offered correct ADSP device description, 
we wouldn't be dealing with ACPI device/ACPI bus at all. This has been 
corrected from SKL+ ADSP onward. To answer the immediate question: no, 
device of id 0x9cb6 won't be present within /sys/bus/pci/devices/ (cat 
'./device' for id for every entry). Even converted catpt driver from 
acpi to pci just to make sure.

I don't mind adding new constant within register.h for transparency:
	#define CATPT_PCI_PMCAPID 0x80
	#define CATPT_PCI_PMCS (CATPT_PCI_PMCAPID + PCI_PM_CTRL)

Current status for PM catpt_updatel_pci:
	catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D3hot)
	catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D0)
which looks very good to me.

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

end of thread, other threads:[~2020-08-27 10:08 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-12 20:57 [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Cezary Rojewski
2020-08-12 20:57 ` [PATCH v4 01/13] ASoC: Intel: Add catpt device Cezary Rojewski
2020-08-13 18:29   ` Andy Shevchenko
2020-08-17 10:02     ` Cezary Rojewski
2020-08-18 10:07       ` Andy Shevchenko
2020-08-19 13:26         ` Cezary Rojewski
2020-08-19 13:43           ` Andy Shevchenko
2020-08-25  9:32             ` Cezary Rojewski
2020-08-25 13:18               ` Andy Shevchenko
2020-08-25 13:19                 ` Andy Shevchenko
2020-08-25 20:43       ` Cezary Rojewski
2020-08-12 20:57 ` [PATCH v4 02/13] ASoC: Intel: catpt: Define DSP operations Cezary Rojewski
2020-08-13 18:51   ` Andy Shevchenko
2020-08-17 11:12     ` Cezary Rojewski
2020-08-18 11:50       ` Andy Shevchenko
2020-08-19 13:46         ` Cezary Rojewski
2020-08-19 14:21           ` Andy Shevchenko
2020-08-19 14:54             ` Cezary Rojewski
2020-08-20  7:30       ` Cezary Rojewski
2020-08-20  9:00         ` Andy Shevchenko
2020-08-24 16:33           ` Cezary Rojewski
2020-08-25 13:16             ` Andy Shevchenko
2020-08-25 13:23               ` Andy Shevchenko
2020-08-27 10:06               ` Cezary Rojewski
2020-08-12 20:57 ` [PATCH v4 03/13] ASoC: Intel: catpt: Firmware loading and context restore Cezary Rojewski
2020-08-12 20:57 ` [PATCH v4 04/13] ASoC: Intel: catpt: Implement IPC protocol Cezary Rojewski
2020-08-12 20:57 ` [PATCH v4 05/13] ASoC: Intel: catpt: Add IPC messages Cezary Rojewski
2020-08-12 20:57 ` [PATCH v4 06/13] ASoC: Intel: catpt: PCM operations Cezary Rojewski
2020-08-12 20:57 ` [PATCH v4 07/13] ASoC: Intel: catpt: Event tracing Cezary Rojewski
2020-08-12 20:57 ` [PATCH v4 08/13] ASoC: Intel: catpt: Simple sysfs attributes Cezary Rojewski
2020-08-12 20:57 ` [PATCH v4 09/13] ASoC: Intel: Select catpt and deprecate haswell Cezary Rojewski
2020-08-12 20:57 ` [PATCH v4 10/13] ASoC: Intel: haswell: Remove haswell-solution specific code Cezary Rojewski
2020-08-13 18:57   ` Andy Shevchenko
2020-08-12 20:57 ` [PATCH v4 11/13] ASoC: Intel: broadwell: " Cezary Rojewski
2020-08-13 18:56   ` Andy Shevchenko
2020-08-12 20:57 ` [PATCH v4 12/13] ASoC: Intel: bdw-5650: " Cezary Rojewski
2020-08-13 18:56   ` Andy Shevchenko
2020-08-12 20:57 ` [PATCH v4 13/13] ASoC: Intel: bdw-5677: " Cezary Rojewski
2020-08-13 18:57   ` Andy Shevchenko
2020-08-13  8:30 ` [PATCH v4 00/13] ASoC: Intel: Catpt - Lynx and Wildcat point Amadeusz Sławiński
2020-08-13 16:00 ` Liam Girdwood
2020-08-13 18:11   ` Cezary Rojewski
2020-08-13 19:03     ` Liam Girdwood

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.