Commit c23ff4b3 authored by Mark Brown's avatar Mark Brown

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
...@@ -529,17 +529,24 @@ intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) ...@@ -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); 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_pcm_substream *substream,
struct snd_soc_dai *dai, 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_link_res *res = sdw->res;
struct sdw_intel_stream_params_data params_data;
if (res->ops && res->ops->config_stream && res->arg) params_data.substream = substream;
return res->ops->config_stream(res->arg, params_data.dai = dai;
substream, dai, hw_params, link_id); 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; return -EIO;
} }
...@@ -654,7 +661,8 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -654,7 +661,8 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
/* Inform DSP about PDI stream number */ /* 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); pdi->intel_alh_id);
if (ret) if (ret)
goto error; goto error;
......
...@@ -5,23 +5,26 @@ ...@@ -5,23 +5,26 @@
#define __SDW_INTEL_LOCAL_H #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 * @registers: Link IO registers base
* @shim: Audio shim pointer * @shim: Audio shim pointer
* @alh: ALH (Audio Link Hub) pointer * @alh: ALH (Audio Link Hub) pointer
* @irq: Interrupt line * @irq: Interrupt line
* @ops: Shim callback ops * @ops: Shim callback ops
* @arg: Shim callback ops argument * @dev: device implementing hw_params and free callbacks
*
* This is set as pdata for each link instance.
*/ */
struct sdw_intel_link_res { struct sdw_intel_link_res {
struct platform_device *pdev;
void __iomem *mmio_base; /* not strictly needed, useful for debug */
void __iomem *registers; void __iomem *registers;
void __iomem *shim; void __iomem *shim;
void __iomem *alh; void __iomem *alh;
int irq; int irq;
const struct sdw_intel_ops *ops; const struct sdw_intel_ops *ops;
void *arg; struct device *dev;
}; };
#endif /* __SDW_INTEL_LOCAL_H */ #endif /* __SDW_INTEL_LOCAL_H */
...@@ -27,19 +27,9 @@ static int link_mask; ...@@ -27,19 +27,9 @@ static int link_mask;
module_param_named(sdw_link_mask, link_mask, int, 0444); module_param_named(sdw_link_mask, link_mask, int, 0444);
MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)"); 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) 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; int i;
if (!link) if (!link)
...@@ -62,7 +52,7 @@ static struct sdw_intel_ctx ...@@ -62,7 +52,7 @@ static struct sdw_intel_ctx
{ {
struct platform_device_info pdevinfo; struct platform_device_info pdevinfo;
struct platform_device *pdev; struct platform_device *pdev;
struct sdw_link_data *link; struct sdw_intel_link_res *link;
struct sdw_intel_ctx *ctx; struct sdw_intel_ctx *ctx;
struct acpi_device *adev; struct acpi_device *adev;
int ret, i; int ret, i;
...@@ -123,14 +113,13 @@ static struct sdw_intel_ctx ...@@ -123,14 +113,13 @@ static struct sdw_intel_ctx
continue; continue;
} }
link->res.irq = res->irq; link->registers = res->mmio_base + SDW_LINK_BASE
link->res.registers = res->mmio_base + SDW_LINK_BASE
+ (SDW_LINK_SIZE * i); + (SDW_LINK_SIZE * i);
link->res.shim = res->mmio_base + SDW_SHIM_BASE; link->shim = res->mmio_base + SDW_SHIM_BASE;
link->res.alh = res->mmio_base + SDW_ALH_BASE; link->alh = res->mmio_base + SDW_ALH_BASE;
link->res.ops = res->ops; link->ops = res->ops;
link->res.arg = res->arg; link->dev = res->dev;
memset(&pdevinfo, 0, sizeof(pdevinfo)); memset(&pdevinfo, 0, sizeof(pdevinfo));
...@@ -138,8 +127,6 @@ static struct sdw_intel_ctx ...@@ -138,8 +127,6 @@ static struct sdw_intel_ctx
pdevinfo.name = "int-sdw"; pdevinfo.name = "int-sdw";
pdevinfo.id = i; pdevinfo.id = i;
pdevinfo.fwnode = acpi_fwnode_handle(adev); pdevinfo.fwnode = acpi_fwnode_handle(adev);
pdevinfo.data = &link->res;
pdevinfo.size_data = sizeof(link->res);
pdev = platform_device_register_full(&pdevinfo); pdev = platform_device_register_full(&pdevinfo);
if (IS_ERR(pdev)) { if (IS_ERR(pdev)) {
...@@ -216,7 +203,6 @@ void *sdw_intel_init(acpi_handle *parent_handle, struct sdw_intel_res *res) ...@@ -216,7 +203,6 @@ void *sdw_intel_init(acpi_handle *parent_handle, struct sdw_intel_res *res)
return sdw_intel_add_controller(res); return sdw_intel_add_controller(res);
} }
EXPORT_SYMBOL(sdw_intel_init);
/** /**
* sdw_intel_exit() - SoundWire Intel exit * sdw_intel_exit() - SoundWire Intel exit
...@@ -224,10 +210,8 @@ EXPORT_SYMBOL(sdw_intel_init); ...@@ -224,10 +210,8 @@ EXPORT_SYMBOL(sdw_intel_init);
* *
* Delete the controller instances created and cleanup * 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); sdw_intel_cleanup_pdev(ctx);
kfree(ctx); kfree(ctx);
} }
......
...@@ -547,6 +547,20 @@ struct sdw_slave_ops { ...@@ -547,6 +547,20 @@ struct sdw_slave_ops {
* @node: node for bus list * @node: node for bus list
* @port_ready: Port ready completion flag for each Slave port * @port_ready: Port ready completion flag for each Slave port
* @dev_num: Device Number assigned by Bus * @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 {
struct sdw_slave_id id; struct sdw_slave_id id;
...@@ -561,6 +575,11 @@ struct sdw_slave { ...@@ -561,6 +575,11 @@ struct sdw_slave {
struct list_head node; struct list_head node;
struct completion *port_ready; struct completion *port_ready;
u16 dev_num; 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) #define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev)
......
...@@ -4,36 +4,174 @@ ...@@ -4,36 +4,174 @@
#ifndef __SDW_INTEL_H #ifndef __SDW_INTEL_H
#define __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 * 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 { struct sdw_intel_ops {
int (*config_stream)(void *arg, void *substream, int (*params_stream)(struct device *dev,
void *dai, void *hw_params, int stream_num); 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 * @mmio_base: mmio base of SoundWire registers
* @irq: interrupt number * @irq: interrupt number
* @handle: ACPI parent handle * @handle: ACPI parent handle
* @parent: parent device * @parent: parent device
* @ops: callback ops * @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 { struct sdw_intel_res {
int count;
void __iomem *mmio_base; void __iomem *mmio_base;
int irq; int irq;
acpi_handle handle; acpi_handle handle;
struct device *parent; struct device *parent;
const struct sdw_intel_ops *ops; 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 #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment