Unverified Commit c23ff4b3 authored by Mark Brown's avatar Mark Brown
Browse files

Merge tag 'sdw_interfaces_5.6' of...

Merge tag 'sdw_interfaces_5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire into asoc-5.6

SoundWire tag for ASoC

This contains the recently merged soundwire interface changes for ASoC
subsystem.
parents a0aab9e1 09f6a72d
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -529,17 +529,24 @@ intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
	intel_writel(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id), conf);
}

static int intel_config_stream(struct sdw_intel *sdw,
static int intel_params_stream(struct sdw_intel *sdw,
			       struct snd_pcm_substream *substream,
			       struct snd_soc_dai *dai,
			       struct snd_pcm_hw_params *hw_params, int link_id)
			       struct snd_pcm_hw_params *hw_params,
			       int link_id, int alh_stream_id)
{
	struct sdw_intel_link_res *res = sdw->res;
	struct sdw_intel_stream_params_data params_data;

	if (res->ops && res->ops->config_stream && res->arg)
		return res->ops->config_stream(res->arg,
				substream, dai, hw_params, link_id);
	params_data.substream = substream;
	params_data.dai = dai;
	params_data.hw_params = hw_params;
	params_data.link_id = link_id;
	params_data.alh_stream_id = alh_stream_id;

	if (res->ops && res->ops->params_stream && res->dev)
		return res->ops->params_stream(res->dev,
					       &params_data);
	return -EIO;
}

@@ -654,7 +661,8 @@ static int intel_hw_params(struct snd_pcm_substream *substream,


	/* Inform DSP about PDI stream number */
	ret = intel_config_stream(sdw, substream, dai, params,
	ret = intel_params_stream(sdw, substream, dai, params,
				  sdw->instance,
				  pdi->intel_alh_id);
	if (ret)
		goto error;
+8 −5
Original line number Diff line number Diff line
@@ -5,23 +5,26 @@
#define __SDW_INTEL_LOCAL_H

/**
 * struct sdw_intel_link_res - Soundwire link resources
 * struct sdw_intel_link_res - Soundwire Intel link resource structure,
 * typically populated by the controller driver.
 * @pdev: platform_device
 * @mmio_base: mmio base of SoundWire registers
 * @registers: Link IO registers base
 * @shim: Audio shim pointer
 * @alh: ALH (Audio Link Hub) pointer
 * @irq: Interrupt line
 * @ops: Shim callback ops
 * @arg: Shim callback ops argument
 *
 * This is set as pdata for each link instance.
 * @dev: device implementing hw_params and free callbacks
 */
struct sdw_intel_link_res {
	struct platform_device *pdev;
	void __iomem *mmio_base; /* not strictly needed, useful for debug */
	void __iomem *registers;
	void __iomem *shim;
	void __iomem *alh;
	int irq;
	const struct sdw_intel_ops *ops;
	void *arg;
	struct device *dev;
};

#endif /* __SDW_INTEL_LOCAL_H */
+8 −24
Original line number Diff line number Diff line
@@ -27,19 +27,9 @@ static int link_mask;
module_param_named(sdw_link_mask, link_mask, int, 0444);
MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)");

struct sdw_link_data {
	struct sdw_intel_link_res res;
	struct platform_device *pdev;
};

struct sdw_intel_ctx {
	int count;
	struct sdw_link_data *links;
};

static int sdw_intel_cleanup_pdev(struct sdw_intel_ctx *ctx)
{
	struct sdw_link_data *link = ctx->links;
	struct sdw_intel_link_res *link = ctx->links;
	int i;

	if (!link)
@@ -62,7 +52,7 @@ static struct sdw_intel_ctx
{
	struct platform_device_info pdevinfo;
	struct platform_device *pdev;
	struct sdw_link_data *link;
	struct sdw_intel_link_res *link;
	struct sdw_intel_ctx *ctx;
	struct acpi_device *adev;
	int ret, i;
@@ -123,14 +113,13 @@ static struct sdw_intel_ctx
			continue;
		}

		link->res.irq = res->irq;
		link->res.registers = res->mmio_base + SDW_LINK_BASE
		link->registers = res->mmio_base + SDW_LINK_BASE
					+ (SDW_LINK_SIZE * i);
		link->res.shim = res->mmio_base + SDW_SHIM_BASE;
		link->res.alh = res->mmio_base + SDW_ALH_BASE;
		link->shim = res->mmio_base + SDW_SHIM_BASE;
		link->alh = res->mmio_base + SDW_ALH_BASE;

		link->res.ops = res->ops;
		link->res.arg = res->arg;
		link->ops = res->ops;
		link->dev = res->dev;

		memset(&pdevinfo, 0, sizeof(pdevinfo));

@@ -138,8 +127,6 @@ static struct sdw_intel_ctx
		pdevinfo.name = "int-sdw";
		pdevinfo.id = i;
		pdevinfo.fwnode = acpi_fwnode_handle(adev);
		pdevinfo.data = &link->res;
		pdevinfo.size_data = sizeof(link->res);

		pdev = platform_device_register_full(&pdevinfo);
		if (IS_ERR(pdev)) {
@@ -216,7 +203,6 @@ void *sdw_intel_init(acpi_handle *parent_handle, struct sdw_intel_res *res)

	return sdw_intel_add_controller(res);
}
EXPORT_SYMBOL(sdw_intel_init);

/**
 * sdw_intel_exit() - SoundWire Intel exit
@@ -224,10 +210,8 @@ EXPORT_SYMBOL(sdw_intel_init);
 *
 * Delete the controller instances created and cleanup
 */
void sdw_intel_exit(void *arg)
void sdw_intel_exit(struct sdw_intel_ctx *ctx)
{
	struct sdw_intel_ctx *ctx = arg;

	sdw_intel_cleanup_pdev(ctx);
	kfree(ctx);
}
+19 −0
Original line number Diff line number Diff line
@@ -547,6 +547,20 @@ struct sdw_slave_ops {
 * @node: node for bus list
 * @port_ready: Port ready completion flag for each Slave port
 * @dev_num: Device Number assigned by Bus
 * @probed: boolean tracking driver state
 * @probe_complete: completion utility to control potential races
 * on startup between driver probe/initialization and SoundWire
 * Slave state changes/implementation-defined interrupts
 * @enumeration_complete: completion utility to control potential races
 * on startup between device enumeration and read/write access to the
 * Slave device
 * @initialization_complete: completion utility to control potential races
 * on startup between device enumeration and settings being restored
 * @unattach_request: mask field to keep track why the Slave re-attached and
 * was re-initialized. This is useful to deal with potential race conditions
 * between the Master suspending and the codec resuming, and make sure that
 * when the Master triggered a reset the Slave is properly enumerated and
 * initialized
 */
struct sdw_slave {
	struct sdw_slave_id id;
@@ -561,6 +575,11 @@ struct sdw_slave {
	struct list_head node;
	struct completion *port_ready;
	u16 dev_num;
	bool probed;
	struct completion probe_complete;
	struct completion enumeration_complete;
	struct completion initialization_complete;
	u32 unattach_request;
};

#define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev)
+147 −9
Original line number Diff line number Diff line
@@ -4,36 +4,174 @@
#ifndef __SDW_INTEL_H
#define __SDW_INTEL_H

#include <linux/irqreturn.h>

/**
 * struct sdw_intel_stream_params_data: configuration passed during
 * the @params_stream callback, e.g. for interaction with DSP
 * firmware.
 */
struct sdw_intel_stream_params_data {
	struct snd_pcm_substream *substream;
	struct snd_soc_dai *dai;
	struct snd_pcm_hw_params *hw_params;
	int link_id;
	int alh_stream_id;
};

/**
 * struct sdw_intel_stream_free_data: configuration passed during
 * the @free_stream callback, e.g. for interaction with DSP
 * firmware.
 */
struct sdw_intel_stream_free_data {
	struct snd_pcm_substream *substream;
	struct snd_soc_dai *dai;
	int link_id;
};

/**
 * struct sdw_intel_ops: Intel audio driver callback ops
 *
 * @config_stream: configure the stream with the hw_params
 * the first argument containing the context is mandatory
 */
struct sdw_intel_ops {
	int (*config_stream)(void *arg, void *substream,
			     void *dai, void *hw_params, int stream_num);
	int (*params_stream)(struct device *dev,
			     struct sdw_intel_stream_params_data *params_data);
	int (*free_stream)(struct device *dev,
			   struct sdw_intel_stream_free_data *free_data);
};

/**
 * struct sdw_intel_acpi_info - Soundwire Intel information found in ACPI tables
 * @handle: ACPI controller handle
 * @count: link count found with "sdw-master-count" property
 * @link_mask: bit-wise mask listing links enabled by BIOS menu
 *
 * this structure could be expanded to e.g. provide all the _ADR
 * information in case the link_mask is not sufficient to identify
 * platform capabilities.
 */
struct sdw_intel_acpi_info {
	acpi_handle handle;
	int count;
	u32 link_mask;
};

struct sdw_intel_link_res;

/* Intel clock-stop/pm_runtime quirk definitions */

/*
 * Force the clock to remain on during pm_runtime suspend. This might
 * be needed if Slave devices do not have an alternate clock source or
 * if the latency requirements are very strict.
 */
#define SDW_INTEL_CLK_STOP_NOT_ALLOWED		BIT(0)

/*
 * Stop the bus during pm_runtime suspend. If set, a complete bus
 * reset and re-enumeration will be performed when the bus
 * restarts. This mode shall not be used if Slave devices can generate
 * in-band wakes.
 */
#define SDW_INTEL_CLK_STOP_TEARDOWN		BIT(1)

/*
 * Stop the bus during pm_suspend if Slaves are not wake capable
 * (e.g. speaker amplifiers). The clock-stop mode is typically
 * slightly higher power than when the IP is completely powered-off.
 */
#define SDW_INTEL_CLK_STOP_WAKE_CAPABLE_ONLY	BIT(2)

/*
 * Require a bus reset (and complete re-enumeration) when exiting
 * clock stop modes. This may be needed if the controller power was
 * turned off and all context lost. This quirk shall not be used if a
 * Slave device needs to remain enumerated and keep its context,
 * e.g. to provide the reasons for the wake, report acoustic events or
 * pass a history buffer.
 */
#define SDW_INTEL_CLK_STOP_BUS_RESET		BIT(3)

/**
 * struct sdw_intel_ctx - context allocated by the controller
 * driver probe
 * @count: link count
 * @mmio_base: mmio base of SoundWire registers, only used to check
 * hardware capabilities after all power dependencies are settled.
 * @link_mask: bit-wise mask listing SoundWire links reported by the
 * Controller
 * @handle: ACPI parent handle
 * @links: information for each link (controller-specific and kept
 * opaque here)
 * @link_list: list to handle interrupts across all links
 * @shim_lock: mutex to handle concurrent rmw access to shared SHIM registers.
 */
struct sdw_intel_ctx {
	int count;
	void __iomem *mmio_base;
	u32 link_mask;
	acpi_handle handle;
	struct sdw_intel_link_res *links;
	struct list_head link_list;
	struct mutex shim_lock; /* lock for access to shared SHIM registers */
};

/**
 * struct sdw_intel_res - Soundwire Intel resource structure
 * struct sdw_intel_res - Soundwire Intel global resource structure,
 * typically populated by the DSP driver
 *
 * @count: link count
 * @mmio_base: mmio base of SoundWire registers
 * @irq: interrupt number
 * @handle: ACPI parent handle
 * @parent: parent device
 * @ops: callback ops
 * @arg: callback arg
 * @dev: device implementing hwparams and free callbacks
 * @link_mask: bit-wise mask listing links selected by the DSP driver
 * This mask may be a subset of the one reported by the controller since
 * machine-specific quirks are handled in the DSP driver.
 * @clock_stop_quirks: mask array of possible behaviors requested by the
 * DSP driver. The quirks are common for all links for now.
 */
struct sdw_intel_res {
	int count;
	void __iomem *mmio_base;
	int irq;
	acpi_handle handle;
	struct device *parent;
	const struct sdw_intel_ops *ops;
	void *arg;
	struct device *dev;
	u32 link_mask;
	u32 clock_stop_quirks;
};

void *sdw_intel_init(acpi_handle *parent_handle, struct sdw_intel_res *res);
void sdw_intel_exit(void *arg);
/*
 * On Intel platforms, the SoundWire IP has dependencies on power
 * rails shared with the DSP, and the initialization steps are split
 * in three. First an ACPI scan to check what the firmware describes
 * in DSDT tables, then an allocation step (with no hardware
 * configuration but with all the relevant devices created) and last
 * the actual hardware configuration. The final stage is a global
 * interrupt enable which is controlled by the DSP driver. Splitting
 * these phases helps simplify the boot flow and make early decisions
 * on e.g. which machine driver to select (I2S mode, HDaudio or
 * SoundWire).
 */
int sdw_intel_acpi_scan(acpi_handle *parent_handle,
			struct sdw_intel_acpi_info *info);

void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx);

struct sdw_intel_ctx *
sdw_intel_probe(struct sdw_intel_res *res);

int sdw_intel_startup(struct sdw_intel_ctx *ctx);

void sdw_intel_exit(struct sdw_intel_ctx *ctx);

void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable);

irqreturn_t sdw_intel_thread(int irq, void *dev_id);

#endif