From 2e4ef6f4798c1d2951dd7bb3ae5f0d41ec3d31e8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 13 Mar 2023 13:03:40 +0200 Subject: ASoC: SOF: uapi: header: Convert sof_abi_hdr comments to kernel style Replace the comments for sof_abi_hdr to kernel style. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Jaska Uimonen Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230313110344.16644-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/header.h | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/sound/sof/header.h b/include/uapi/sound/sof/header.h index e9bba93a5399..e53b62b9e2c5 100644 --- a/include/uapi/sound/sof/header.h +++ b/include/uapi/sound/sof/header.h @@ -11,19 +11,25 @@ #include -/* - * Header for all non IPC ABI data. +/** + * struct sof_abi_hdr - Header for all non IPC ABI data. + * @magic: Magic number for validation: 0x00464F53 ('S', 'O', 'F', '\0') + * @type: Component specific type + * @size: The size in bytes of the data, excluding this struct + * @abi: SOF ABI version + * @reserved: Reserved for future use + * @data: Component data - opaque to core * * Identifies data type, size and ABI. * Used by any bespoke component data structures or binary blobs. */ struct sof_abi_hdr { - __u32 magic; /**< 'S', 'O', 'F', '\0' */ - __u32 type; /**< component specific type */ - __u32 size; /**< size in bytes of data excl. this struct */ - __u32 abi; /**< SOF ABI version */ - __u32 reserved[4]; /**< reserved for future use */ - __u32 data[]; /**< Component data - opaque to core */ + __u32 magic; + __u32 type; + __u32 size; + __u32 abi; + __u32 reserved[4]; + __u32 data[]; } __packed; #define SOF_MANIFEST_DATA_TYPE_NHLT 1 -- cgit v1.2.3-58-ga151 From ea4a4e82f625ae451175a2a74779776b006d25a1 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 13 Mar 2023 13:03:41 +0200 Subject: ASoC: SOF: uapi: header: Update sof_abi_hdr doc for IPC4 use With IPC4 the sof_abit_hdr is only used between user space (and in topology) and kernel. The same abi header is used with small differencies like different magic number and the type field have slightly different name, but similar function in IPC4 (param_id). Update the kernel documentation to highlight the differences. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Jaska Uimonen Reviewed-by: Kai Vehmanen Link: https://lore.kernel.org/r/20230313110344.16644-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/abi.h | 2 ++ include/uapi/sound/sof/header.h | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 3566630ca965..45c657c3919e 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -60,5 +60,7 @@ /* SOF ABI magic number "SOF\0". */ #define SOF_ABI_MAGIC 0x00464F53 +/* SOF IPC4 ABI magic number "SOF4". */ +#define SOF_IPC4_ABI_MAGIC 0x34464F53 #endif diff --git a/include/uapi/sound/sof/header.h b/include/uapi/sound/sof/header.h index e53b62b9e2c5..cb3c1ace69e3 100644 --- a/include/uapi/sound/sof/header.h +++ b/include/uapi/sound/sof/header.h @@ -13,10 +13,15 @@ /** * struct sof_abi_hdr - Header for all non IPC ABI data. - * @magic: Magic number for validation: 0x00464F53 ('S', 'O', 'F', '\0') - * @type: Component specific type + * @magic: Magic number for validation + * for IPC3 data: 0x00464F53 ('S', 'O', 'F', '\0') + * for IPC4 data: 0x34464F53 ('S', 'O', 'F', '4') + * @type: module specific parameter + * for IPC3: Component specific type + * for IPC4: parameter ID (param_id) of the data * @size: The size in bytes of the data, excluding this struct - * @abi: SOF ABI version + * @abi: SOF ABI version. The version is valid in scope of the 'magic', IPC3 and + * IPC4 ABI version numbers have no relationship. * @reserved: Reserved for future use * @data: Component data - opaque to core * -- cgit v1.2.3-58-ga151 From 3f738e4a126c9ee082d814edeb7416697f9e2b37 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 13 Mar 2023 14:48:46 +0200 Subject: ASoC: SOF: rename a couple of tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename SOF_TKN_CAVS_AUDIO_FORMAT_IN_VALID and SOF_TKN_CAVS_AUDIO_FORMAT_OUT_VALID as SOF_TKN_CAVS_AUDIO_FORMAT_IN_VALID_BIT_DEPTH and SOF_TKN_CAVS_AUDIO_FORMAT_OUT_VALID_BIT_DEPTH respectively. These are currently not used. Signed-off-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230313124856.8140-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index bacaf8a6317e..a1ef6b5c0d45 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -173,7 +173,7 @@ /* CAVS AUDIO FORMAT */ #define SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE 1900 #define SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH 1901 -#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_VALID_BIT 1902 +#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_VALID_BIT_DEPTH 1902 #define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CHANNELS 1903 #define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP 1904 #define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG 1905 @@ -183,7 +183,7 @@ /* intentional token numbering discontinuity, reserved for future use */ #define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE 1930 #define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH 1931 -#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_VALID_BIT 1932 +#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_VALID_BIT_DEPTH 1932 #define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CHANNELS 1933 #define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP 1934 #define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG 1935 -- cgit v1.2.3-58-ga151 From bb79f2a608245cd92b3183d77aec6902e51de950 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 13 Mar 2023 14:48:47 +0200 Subject: ASoC: SOF: Use input/output pin consistently MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we use input/output and sink/source pins interchangeably. Remove the references to sink/source pins and replace with input/output pins everywhere for consistency and clarity. Signed-off-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230313124856.8140-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 12 +++---- sound/soc/sof/ipc4-topology.c | 48 ++++++++++++------------- sound/soc/sof/sof-audio.h | 32 ++++++++--------- sound/soc/sof/topology.c | 80 ++++++++++++++++++++--------------------- 4 files changed, 86 insertions(+), 86 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index a1ef6b5c0d45..0b5110427132 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -88,14 +88,14 @@ #define SOF_TKN_COMP_CPC 406 #define SOF_TKN_COMP_IS_PAGES 409 #define SOF_TKN_COMP_NUM_AUDIO_FORMATS 410 -#define SOF_TKN_COMP_NUM_SINK_PINS 411 -#define SOF_TKN_COMP_NUM_SOURCE_PINS 412 +#define SOF_TKN_COMP_NUM_INPUT_PINS 411 +#define SOF_TKN_COMP_NUM_OUTPUT_PINS 412 /* - * The token for sink/source pin binding, it specifies the widget - * name that the sink/source pin is connected from/to. + * The token for input/output pin binding, it specifies the widget + * name that the input/output pin is connected from/to. */ -#define SOF_TKN_COMP_SINK_PIN_BINDING_WNAME 413 -#define SOF_TKN_COMP_SRC_PIN_BINDING_WNAME 414 +#define SOF_TKN_COMP_INPUT_PIN_BINDING_WNAME 413 +#define SOF_TKN_COMP_OUTPUT_PIN_BINDING_WNAME 414 /* SSP */ diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 0bb16ed38e48..a501eb9befa8 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1698,17 +1698,17 @@ static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget, u32 num_pins; int i; - if (pin_type == SOF_PIN_TYPE_SOURCE) { + if (pin_type == SOF_PIN_TYPE_OUTPUT) { current_swidget = src_widget; - pin_binding = src_widget->src_pin_binding; - queue_ida = &src_widget->src_queue_ida; - num_pins = src_widget->num_source_pins; + pin_binding = src_widget->output_pin_binding; + queue_ida = &src_widget->output_queue_ida; + num_pins = src_widget->num_output_pins; buddy_name = sink_widget->widget->name; } else { current_swidget = sink_widget; - pin_binding = sink_widget->sink_pin_binding; - queue_ida = &sink_widget->sink_queue_ida; - num_pins = sink_widget->num_sink_pins; + pin_binding = sink_widget->input_pin_binding; + queue_ida = &sink_widget->input_queue_ida; + num_pins = sink_widget->num_input_pins; buddy_name = src_widget->widget->name; } @@ -1716,12 +1716,12 @@ static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget, if (num_pins < 1) { dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n", - (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"), + (pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"), num_pins, current_swidget->widget->name); return -EINVAL; } - /* If there is only one sink/source pin, queue id must be 0 */ + /* If there is only one input/output pin, queue id must be 0 */ if (num_pins == 1) return 0; @@ -1736,7 +1736,7 @@ static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget, * mixed use pin binding array and ida for queue ID allocation. */ dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n", - (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"), + (pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"), current_swidget->widget->name); return -EINVAL; } @@ -1752,14 +1752,14 @@ static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id, char **pin_binding; int num_pins; - if (pin_type == SOF_PIN_TYPE_SOURCE) { - pin_binding = swidget->src_pin_binding; - queue_ida = &swidget->src_queue_ida; - num_pins = swidget->num_source_pins; + if (pin_type == SOF_PIN_TYPE_OUTPUT) { + pin_binding = swidget->output_pin_binding; + queue_ida = &swidget->output_queue_ida; + num_pins = swidget->num_output_pins; } else { - pin_binding = swidget->sink_pin_binding; - queue_ida = &swidget->sink_queue_ida; - num_pins = swidget->num_sink_pins; + pin_binding = swidget->input_pin_binding; + queue_ida = &swidget->input_queue_ida; + num_pins = swidget->num_input_pins; } /* Nothing to free if queue ID is not allocated with ida. */ @@ -1829,7 +1829,7 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * int ret; sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, - SOF_PIN_TYPE_SOURCE); + SOF_PIN_TYPE_OUTPUT); if (sroute->src_queue_id < 0) { dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n", src_widget->widget->name); @@ -1837,12 +1837,12 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * } sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, - SOF_PIN_TYPE_SINK); + SOF_PIN_TYPE_INPUT); if (sroute->dst_queue_id < 0) { dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n", sink_widget->widget->name); sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, - SOF_PIN_TYPE_SOURCE); + SOF_PIN_TYPE_OUTPUT); return sroute->dst_queue_id; } @@ -1886,8 +1886,8 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * return ret; out: - sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE); - sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK); + sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT); + sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT); return ret; } @@ -1932,8 +1932,8 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s src_widget->widget->name, sroute->src_queue_id, sink_widget->widget->name, sroute->dst_queue_id); out: - sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK); - sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE); + sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT); + sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT); return ret; } diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 239b82f37976..a1c4d3f34153 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -30,9 +30,9 @@ */ #define SOF_WIDGET_MAX_NUM_PINS 8 -/* The type of a widget pin is either sink or source */ -#define SOF_PIN_TYPE_SINK 0 -#define SOF_PIN_TYPE_SOURCE 1 +/* Widget pin type */ +#define SOF_PIN_TYPE_INPUT 0 +#define SOF_PIN_TYPE_OUTPUT 1 /* max number of FE PCMs before BEs */ #define SOF_BE_PCM_BASE 16 @@ -433,31 +433,31 @@ struct snd_sof_widget { struct snd_sof_tuple *tuples; /* - * The allowed range for num_sink/source_pins is [0, SOF_WIDGET_MAX_NUM_PINS]. - * Widgets may have zero sink or source pins, for example the tone widget has - * zero sink pins. + * The allowed range for num_input/output_pins is [0, SOF_WIDGET_MAX_NUM_PINS]. + * Widgets may have zero input or output pins, for example the tone widget has + * zero input pins. */ - u32 num_sink_pins; - u32 num_source_pins; + u32 num_input_pins; + u32 num_output_pins; /* - * The sink/source pin binding array, it takes the form of + * The input/output pin binding array, it takes the form of * [widget_name_connected_to_pin0, widget_name_connected_to_pin1, ...], * with the index as the queue ID. * * The array is used for special pin binding. Note that even if there - * is only one sink/source pin requires special pin binding, pin binding - * should be defined for all sink/source pins in topology, for pin(s) that + * is only one input/output pin requires special pin binding, pin binding + * should be defined for all input/output pins in topology, for pin(s) that * are not used, give the value "NotConnected". * * If pin binding is not defined in topology, nothing to parse in the kernel, - * sink_pin_binding and src_pin_binding shall be NULL. + * input_pin_binding and output_pin_binding shall be NULL. */ - char **sink_pin_binding; - char **src_pin_binding; + char **input_pin_binding; + char **output_pin_binding; - struct ida src_queue_ida; - struct ida sink_queue_ida; + struct ida output_queue_ida; + struct ida input_queue_ida; void *private; /* core does not touch this */ }; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 9f3a038fe21a..9f84b4c362c3 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -416,19 +416,19 @@ static const struct sof_topology_token led_tokens[] = { }; static const struct sof_topology_token comp_pin_tokens[] = { - {SOF_TKN_COMP_NUM_SINK_PINS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct snd_sof_widget, num_sink_pins)}, - {SOF_TKN_COMP_NUM_SOURCE_PINS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct snd_sof_widget, num_source_pins)}, + {SOF_TKN_COMP_NUM_INPUT_PINS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct snd_sof_widget, num_input_pins)}, + {SOF_TKN_COMP_NUM_OUTPUT_PINS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct snd_sof_widget, num_output_pins)}, }; -static const struct sof_topology_token comp_sink_pin_binding_tokens[] = { - {SOF_TKN_COMP_SINK_PIN_BINDING_WNAME, SND_SOC_TPLG_TUPLE_TYPE_STRING, +static const struct sof_topology_token comp_input_pin_binding_tokens[] = { + {SOF_TKN_COMP_INPUT_PIN_BINDING_WNAME, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_string, 0}, }; -static const struct sof_topology_token comp_src_pin_binding_tokens[] = { - {SOF_TKN_COMP_SRC_PIN_BINDING_WNAME, SND_SOC_TPLG_TUPLE_TYPE_STRING, +static const struct sof_topology_token comp_output_pin_binding_tokens[] = { + {SOF_TKN_COMP_OUTPUT_PIN_BINDING_WNAME, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_string, 0}, }; @@ -1286,12 +1286,12 @@ static void sof_free_pin_binding(struct snd_sof_widget *swidget, u32 num_pins; int i; - if (pin_type == SOF_PIN_TYPE_SINK) { - pin_binding = swidget->sink_pin_binding; - num_pins = swidget->num_sink_pins; + if (pin_type == SOF_PIN_TYPE_INPUT) { + pin_binding = swidget->input_pin_binding; + num_pins = swidget->num_input_pins; } else { - pin_binding = swidget->src_pin_binding; - num_pins = swidget->num_source_pins; + pin_binding = swidget->output_pin_binding; + num_pins = swidget->num_output_pins; } if (pin_binding) { @@ -1313,14 +1313,14 @@ static int sof_parse_pin_binding(struct snd_sof_widget *swidget, int ret; int i; - if (pin_type == SOF_PIN_TYPE_SINK) { - num_pins = swidget->num_sink_pins; - pin_binding_token = comp_sink_pin_binding_tokens; - token_count = ARRAY_SIZE(comp_sink_pin_binding_tokens); + if (pin_type == SOF_PIN_TYPE_INPUT) { + num_pins = swidget->num_input_pins; + pin_binding_token = comp_input_pin_binding_tokens; + token_count = ARRAY_SIZE(comp_input_pin_binding_tokens); } else { - num_pins = swidget->num_source_pins; - pin_binding_token = comp_src_pin_binding_tokens; - token_count = ARRAY_SIZE(comp_src_pin_binding_tokens); + num_pins = swidget->num_output_pins; + pin_binding_token = comp_output_pin_binding_tokens; + token_count = ARRAY_SIZE(comp_output_pin_binding_tokens); } memset(pin_binding, 0, SOF_WIDGET_MAX_NUM_PINS * sizeof(char *)); @@ -1337,10 +1337,10 @@ static int sof_parse_pin_binding(struct snd_sof_widget *swidget, ret = -ENOMEM; goto err; } - if (pin_type == SOF_PIN_TYPE_SINK) - swidget->sink_pin_binding = pb; + if (pin_type == SOF_PIN_TYPE_INPUT) + swidget->input_pin_binding = pb; else - swidget->src_pin_binding = pb; + swidget->output_pin_binding = pb; } return 0; @@ -1379,8 +1379,8 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, swidget->private = NULL; mutex_init(&swidget->setup_mutex); - ida_init(&swidget->src_queue_ida); - ida_init(&swidget->sink_queue_ida); + ida_init(&swidget->output_queue_ida); + ida_init(&swidget->input_queue_ida); ret = sof_parse_tokens(scomp, swidget, comp_pin_tokens, ARRAY_SIZE(comp_pin_tokens), priv->array, @@ -1391,29 +1391,29 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, goto widget_free; } - if (swidget->num_sink_pins > SOF_WIDGET_MAX_NUM_PINS || - swidget->num_source_pins > SOF_WIDGET_MAX_NUM_PINS) { - dev_err(scomp->dev, "invalid pins for %s: [sink: %d, src: %d]\n", - swidget->widget->name, swidget->num_sink_pins, swidget->num_source_pins); + if (swidget->num_input_pins > SOF_WIDGET_MAX_NUM_PINS || + swidget->num_output_pins > SOF_WIDGET_MAX_NUM_PINS) { + dev_err(scomp->dev, "invalid pins for %s: [input: %d, output: %d]\n", + swidget->widget->name, swidget->num_input_pins, swidget->num_output_pins); ret = -EINVAL; goto widget_free; } - if (swidget->num_sink_pins > 1) { - ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_SINK); + if (swidget->num_input_pins > 1) { + ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_INPUT); /* on parsing error, pin binding is not allocated, nothing to free. */ if (ret < 0) { - dev_err(scomp->dev, "failed to parse sink pin binding for %s\n", + dev_err(scomp->dev, "failed to parse input pin binding for %s\n", w->name); goto widget_free; } } - if (swidget->num_source_pins > 1) { - ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_SOURCE); + if (swidget->num_output_pins > 1) { + ret = sof_parse_pin_binding(swidget, priv, SOF_PIN_TYPE_OUTPUT); /* on parsing error, pin binding is not allocated, nothing to free. */ if (ret < 0) { - dev_err(scomp->dev, "failed to parse source pin binding for %s\n", + dev_err(scomp->dev, "failed to parse output pin binding for %s\n", w->name); goto widget_free; } @@ -1422,7 +1422,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, dev_dbg(scomp->dev, "tplg: widget %d (%s) is ready [type: %d, pipe: %d, pins: %d / %d, stream: %s]\n", swidget->comp_id, w->name, swidget->id, index, - swidget->num_sink_pins, swidget->num_source_pins, + swidget->num_input_pins, swidget->num_output_pins, strnlen(w->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 ? w->sname : "none"); widget_ops = tplg_ops ? tplg_ops->widget : NULL; @@ -1643,11 +1643,11 @@ out: if (widget_ops && widget_ops[swidget->id].ipc_free) widget_ops[swidget->id].ipc_free(swidget); - ida_destroy(&swidget->src_queue_ida); - ida_destroy(&swidget->sink_queue_ida); + ida_destroy(&swidget->output_queue_ida); + ida_destroy(&swidget->input_queue_ida); - sof_free_pin_binding(swidget, SOF_PIN_TYPE_SINK); - sof_free_pin_binding(swidget, SOF_PIN_TYPE_SOURCE); + sof_free_pin_binding(swidget, SOF_PIN_TYPE_INPUT); + sof_free_pin_binding(swidget, SOF_PIN_TYPE_OUTPUT); kfree(swidget->tuples); -- cgit v1.2.3-58-ga151 From 594c1bb9ff7365b90cb4d325deb8c38ddda90557 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 13 Mar 2023 14:48:49 +0200 Subject: ASoC: SOF: ipc4-topology: Do not parse the DMA_BUFFER_SIZE token MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not parse the SOF_TKN_CAVS_AUDIO_FORMAT_DMA_BUFFER_SIZE token as the dma_buffer_size can be derived from the input/output buffer size and the type of widget during copier prepare. For the deep buffer case, introduce a new token that will be used to get the deep buffer DMA size for the host copier from topology. Signed-off-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230313124856.8140-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 1 + sound/soc/sof/ipc4-topology.c | 112 +++++++++++++++++----------------------- sound/soc/sof/ipc4-topology.h | 5 +- sound/soc/sof/sof-audio.h | 2 +- sound/soc/sof/topology.c | 1 - 5 files changed, 52 insertions(+), 69 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 0b5110427132..9e91e2640dd4 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -197,6 +197,7 @@ /* COPIER */ #define SOF_TKN_INTEL_COPIER_NODE_TYPE 1980 +#define SOF_TKN_INTEL_COPIER_DEEP_BUFFER_DMA_MS 1981 /* ACP I2S */ #define SOF_TKN_AMD_ACPI2S_RATE 1700 diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index d56e0f12b5d0..50cd4fe3141c 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -78,8 +78,8 @@ static const struct sof_topology_token ipc4_out_audio_format_tokens[] = { offsetof(struct sof_ipc4_audio_format, fmt_cfg)}, }; -static const struct sof_topology_token ipc4_copier_gateway_cfg_tokens[] = { - {SOF_TKN_CAVS_AUDIO_FORMAT_DMA_BUFFER_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0}, +static const struct sof_topology_token ipc4_copier_deep_buffer_tokens[] = { + {SOF_TKN_INTEL_COPIER_DEEP_BUFFER_DMA_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0}, }; static const struct sof_topology_token ipc4_copier_tokens[] = { @@ -138,8 +138,8 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { [SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS] = {"IPC4 Audio format buffer size tokens", ipc4_audio_format_buffer_size_tokens, ARRAY_SIZE(ipc4_audio_format_buffer_size_tokens)}, - [SOF_COPIER_GATEWAY_CFG_TOKENS] = {"IPC4 Copier gateway config tokens", - ipc4_copier_gateway_cfg_tokens, ARRAY_SIZE(ipc4_copier_gateway_cfg_tokens)}, + [SOF_COPIER_DEEP_BUFFER_TOKENS] = {"IPC4 Copier deep buffer tokens", + ipc4_copier_deep_buffer_tokens, ARRAY_SIZE(ipc4_copier_deep_buffer_tokens)}, [SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens, ARRAY_SIZE(ipc4_copier_tokens)}, [SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens", @@ -348,7 +348,7 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget) struct snd_soc_component *scomp = swidget->scomp; struct sof_ipc4_copier *ipc4_copier; int node_type = 0; - int ret, i; + int ret; ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL); if (!ipc4_copier) @@ -363,13 +363,6 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget) if (ret) goto free_copier; - available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32), - GFP_KERNEL); - if (!available_fmt->dma_buffer_size) { - ret = -ENOMEM; - goto free_available_fmt; - } - /* * This callback is used by host copier and module-to-module copier, * and only host copier needs to set gtw_cfg. @@ -377,21 +370,6 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget) if (!WIDGET_IS_AIF(swidget->id)) goto skip_gtw_cfg; - ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size, - SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples, - swidget->num_tuples, sizeof(u32), - available_fmt->audio_fmt_num); - if (ret) { - dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n", - swidget->widget->name); - goto err; - } - - dev_dbg(scomp->dev, "dma buffer size:\n"); - for (i = 0; i < available_fmt->audio_fmt_num; i++) - dev_dbg(scomp->dev, "%d: %u\n", i, - available_fmt->dma_buffer_size[i]); - ret = sof_update_ipc_object(scomp, &node_type, SOF_COPIER_TOKENS, swidget->tuples, swidget->num_tuples, sizeof(node_type), 1); @@ -399,7 +377,7 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget) if (ret) { dev_err(scomp->dev, "parse host copier node type token failed %d\n", ret); - goto err; + goto free_available_fmt; } dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type); @@ -407,7 +385,7 @@ skip_gtw_cfg: ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL); if (!ipc4_copier->gtw_attr) { ret = -ENOMEM; - goto err; + goto free_available_fmt; } ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr; @@ -438,8 +416,6 @@ skip_gtw_cfg: free_gtw_attr: kfree(ipc4_copier->gtw_attr); -err: - kfree(available_fmt->dma_buffer_size); free_available_fmt: sof_ipc4_free_audio_fmt(available_fmt); free_copier: @@ -457,7 +433,6 @@ static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget) return; available_fmt = &ipc4_copier->available_fmt; - kfree(available_fmt->dma_buffer_size); kfree(available_fmt->base_config); kfree(available_fmt->out_audio_fmt); kfree(ipc4_copier->gtw_attr); @@ -472,7 +447,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) struct snd_sof_dai *dai = swidget->private; struct sof_ipc4_copier *ipc4_copier; int node_type = 0; - int ret, i; + int ret; ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL); if (!ipc4_copier) @@ -486,33 +461,12 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) if (ret) goto free_copier; - available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32), - GFP_KERNEL); - if (!available_fmt->dma_buffer_size) { - ret = -ENOMEM; - goto free_available_fmt; - } - - ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size, - SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples, - swidget->num_tuples, sizeof(u32), - available_fmt->audio_fmt_num); - if (ret) { - dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n", - swidget->widget->name); - goto err; - } - - for (i = 0; i < available_fmt->audio_fmt_num; i++) - dev_dbg(scomp->dev, "%d: dma buffer size: %u\n", i, - available_fmt->dma_buffer_size[i]); - ret = sof_update_ipc_object(scomp, &node_type, SOF_COPIER_TOKENS, swidget->tuples, swidget->num_tuples, sizeof(node_type), 1); if (ret) { dev_err(scomp->dev, "parse dai node type failed %d\n", ret); - goto err; + goto free_available_fmt; } ret = sof_update_ipc_object(scomp, ipc4_copier, @@ -520,7 +474,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) swidget->num_tuples, sizeof(u32), 1); if (ret) { dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret); - goto err; + goto free_available_fmt; } dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name, @@ -554,7 +508,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) blob = kzalloc(sizeof(*blob), GFP_KERNEL); if (!blob) { ret = -ENOMEM; - goto err; + goto free_available_fmt; } list_for_each_entry(w, &sdev->widget_list, list) { @@ -583,7 +537,7 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL); if (!ipc4_copier->gtw_attr) { ret = -ENOMEM; - goto err; + goto free_available_fmt; } ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr; @@ -604,8 +558,6 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) free_copier_config: kfree(ipc4_copier->copier_config); -err: - kfree(available_fmt->dma_buffer_size); free_available_fmt: sof_ipc4_free_audio_fmt(available_fmt); free_copier: @@ -633,7 +585,6 @@ static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget) ipc4_copier = dai->private; available_fmt = &ipc4_copier->available_fmt; - kfree(available_fmt->dma_buffer_size); kfree(available_fmt->base_config); kfree(available_fmt->out_audio_fmt); if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP && @@ -1166,6 +1117,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, int *ipc_config_size; u32 **data; int ipc_size, ret; + u32 deep_buffer_dma_ms = 0; dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); @@ -1177,6 +1129,16 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_sof_widget *pipe_widget; struct sof_ipc4_pipeline *pipeline; + /* parse the deep buffer dma size */ + ret = sof_update_ipc_object(scomp, &deep_buffer_dma_ms, + SOF_COPIER_DEEP_BUFFER_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(u32), 1); + if (ret) { + dev_err(scomp->dev, "Failed to parse deep buffer dma size for %s\n", + swidget->widget->name); + return ret; + } + pipe_widget = swidget->spipe->pipe_widget; pipeline = pipe_widget->private; ipc4_copier = (struct sof_ipc4_copier *)swidget->private; @@ -1367,8 +1329,29 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, return -EINVAL; } - /* set the gateway dma_buffer_size using the matched ID returned above */ - copier_data->gtw_cfg.dma_buffer_size = available_fmt->dma_buffer_size[ret]; + /* + * Set the gateway dma_buffer_size to 2ms buffer size to meet the FW expectation. In the + * deep buffer case, set the dma_buffer_size depending on the deep_buffer_dma_ms set + * in topology. + */ + switch (swidget->id) { + case snd_soc_dapm_dai_in: + copier_data->gtw_cfg.dma_buffer_size = + SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.ibs; + break; + case snd_soc_dapm_aif_in: + copier_data->gtw_cfg.dma_buffer_size = + max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms) * + copier_data->base_config.ibs; + break; + case snd_soc_dapm_dai_out: + case snd_soc_dapm_aif_out: + copier_data->gtw_cfg.dma_buffer_size = + SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.obs; + break; + default: + break; + } data = &ipc4_copier->copier_config; ipc_config_size = &ipc4_copier->ipc_config_size; @@ -2170,7 +2153,7 @@ static enum sof_tokens common_copier_token_list[] = { SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, SOF_IN_AUDIO_FORMAT_TOKENS, SOF_OUT_AUDIO_FORMAT_TOKENS, - SOF_COPIER_GATEWAY_CFG_TOKENS, + SOF_COPIER_DEEP_BUFFER_TOKENS, SOF_COPIER_TOKENS, SOF_COMP_EXT_TOKENS, }; @@ -2186,7 +2169,6 @@ static enum sof_tokens dai_token_list[] = { SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, SOF_IN_AUDIO_FORMAT_TOKENS, SOF_OUT_AUDIO_FORMAT_TOKENS, - SOF_COPIER_GATEWAY_CFG_TOKENS, SOF_COPIER_TOKENS, SOF_DAI_TOKENS, SOF_COMP_EXT_TOKENS, diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index addc5b55cc10..696d6c39a21b 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -55,6 +55,9 @@ #define SOF_IPC4_INVALID_NODE_ID 0xffffffff +/* FW requires minimum 2ms DMA buffer size */ +#define SOF_IPC4_MIN_DMA_BUFFER_SIZE 2 + /* * The base of multi-gateways. Multi-gateways addressing starts from * ALH_MULTI_GTW_BASE and there are ALH_MULTI_GTW_COUNT multi-sources @@ -148,7 +151,6 @@ struct ipc4_pipeline_set_state_data { * @out_audio_fmt: Available output audio format * @input_audio_fmts: Available input audio formats * @ref_audio_fmt: Reference audio format to match runtime audio format - * @dma_buffer_size: Available Gateway DMA buffer size (in bytes) * @audio_fmt_num: Number of available audio formats */ struct sof_ipc4_available_audio_format { @@ -156,7 +158,6 @@ struct sof_ipc4_available_audio_format { struct sof_ipc4_audio_format *out_audio_fmt; struct sof_ipc4_audio_format *input_audio_fmts; struct sof_ipc4_audio_format *ref_audio_fmt; - u32 *dma_buffer_size; int audio_fmt_num; }; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index a1c4d3f34153..4504f9efdc50 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -257,7 +257,7 @@ enum sof_tokens { SOF_IN_AUDIO_FORMAT_TOKENS, SOF_OUT_AUDIO_FORMAT_TOKENS, SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, - SOF_COPIER_GATEWAY_CFG_TOKENS, + SOF_COPIER_DEEP_BUFFER_TOKENS, SOF_COPIER_TOKENS, SOF_AUDIO_FMT_NUM_TOKENS, SOF_COPIER_FORMAT_TOKENS, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 9f84b4c362c3..2d76ab13b3d1 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1232,7 +1232,6 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s continue; case SOF_IN_AUDIO_FORMAT_TOKENS: case SOF_OUT_AUDIO_FORMAT_TOKENS: - case SOF_COPIER_GATEWAY_CFG_TOKENS: case SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS: num_sets = sof_get_token_value(SOF_TKN_COMP_NUM_AUDIO_FORMATS, swidget->tuples, swidget->num_tuples); -- cgit v1.2.3-58-ga151 From 7ab6b1e8302cf7a9bc8808c43b3e751e4148a351 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 13 Mar 2023 14:48:52 +0200 Subject: ASoC: SOF: ipc4-topology: Modify the type of available input/output formats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a new struct sof_ipc4_pin_format which contains the pin index and the buffer size. Replace the type of available input/output audio formats in struct sof_ipc4_available_audio_format with this new struct type and rename them to input_pin_fmts and output_pin_fmts. Also, add a new token, SOF_TKN_CAVS_AUDIO_FORMAT_PIN_INDEX that will be used to parse the pin index for the audio format from topology. Currently we only set the audio format for Pin 0 in topology, so the default value will be 0 for all audio formats. Finally, parse the pin_index and the input/output buffer sizes along with audio formats into the pin_format arrays in struct sof_ipc4_available_audio_format. This makes the base_config array in struct sof_ipc4_available_audio_format redundant. So remove it. This change will allow the addition of audio formats for the non-zero pins in topology transparent to the topology parser in the kernel. Signed-off-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230313124856.8140-8-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 1 + sound/soc/sof/ipc4-pcm.c | 2 +- sound/soc/sof/ipc4-topology.c | 181 ++++++++++++++++------------------------ sound/soc/sof/ipc4-topology.h | 27 ++++-- sound/soc/sof/sof-audio.h | 1 - sound/soc/sof/topology.c | 1 - 6 files changed, 96 insertions(+), 117 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 9e91e2640dd4..92360601b49c 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -180,6 +180,7 @@ #define SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE 1906 #define SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG 1907 #define SOF_TKN_CAVS_AUDIO_FORMAT_IN_SAMPLE_TYPE 1908 +#define SOF_TKN_CAVS_AUDIO_FORMAT_PIN_INDEX 1909 /* intentional token numbering discontinuity, reserved for future use */ #define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE 1930 #define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH 1931 diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index a679c08d9bb1..701da5ee4e4e 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -389,7 +389,7 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, snd_mask_none(fmt); snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); - rate->min = ipc4_copier->available_fmt.input_audio_fmts->sampling_frequency; + rate->min = ipc4_copier->available_fmt.input_pin_fmts->audio_fmt.sampling_frequency; rate->max = rate->min; switch (ipc4_copier->dai_type) { diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 0e1e4fc9224c..c462db95f3b2 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -41,41 +41,44 @@ static const struct sof_topology_token ipc4_comp_tokens[] = { offsetof(struct sof_ipc4_base_module_cfg, is_pages)}, }; -static const struct sof_topology_token ipc4_audio_format_buffer_size_tokens[] = { - {SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc4_base_module_cfg, ibs)}, - {SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc4_base_module_cfg, obs)}, -}; - static const struct sof_topology_token ipc4_in_audio_format_tokens[] = { {SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc4_audio_format, sampling_frequency)}, + offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)}, {SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc4_audio_format, bit_depth)}, + offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)}, {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc4_audio_format, ch_map)}, + offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)}, {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc4_audio_format, ch_cfg)}, + offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)}, {SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD, - get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)}, + get_token_u32, offsetof(struct sof_ipc4_pin_format, + audio_fmt.interleaving_style)}, {SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc4_audio_format, fmt_cfg)}, + offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_pin_format, pin_index)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_pin_format, buffer_size)}, }; static const struct sof_topology_token ipc4_out_audio_format_tokens[] = { {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc4_audio_format, sampling_frequency)}, + offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)}, {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc4_audio_format, bit_depth)}, + offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)}, {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc4_audio_format, ch_map)}, + offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)}, {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc4_audio_format, ch_cfg)}, + offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)}, {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD, - get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)}, + get_token_u32, offsetof(struct sof_ipc4_pin_format, + audio_fmt.interleaving_style)}, {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc4_audio_format, fmt_cfg)}, + offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_pin_format, pin_index)}, + {SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_pin_format, buffer_size)}, }; static const struct sof_topology_token ipc4_copier_deep_buffer_tokens[] = { @@ -135,9 +138,6 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)}, [SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens", ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)}, - [SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS] = {"IPC4 Audio format buffer size tokens", - ipc4_audio_format_buffer_size_tokens, - ARRAY_SIZE(ipc4_audio_format_buffer_size_tokens)}, [SOF_COPIER_DEEP_BUFFER_TOKENS] = {"IPC4 Copier deep buffer tokens", ipc4_copier_deep_buffer_tokens, ARRAY_SIZE(ipc4_copier_deep_buffer_tokens)}, [SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens, @@ -148,20 +148,18 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, }; -static void sof_ipc4_dbg_audio_format(struct device *dev, - struct sof_ipc4_audio_format *format, - size_t object_size, int num_format) +static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_format *pin_fmt, + int num_formats) { - struct sof_ipc4_audio_format *fmt; - void *ptr = format; int i; - for (i = 0; i < num_format; i++, ptr = (u8 *)ptr + object_size) { - fmt = ptr; + for (i = 0; i < num_formats; i++) { + struct sof_ipc4_audio_format *fmt = &pin_fmt[i].audio_fmt; dev_dbg(dev, - " #%d: %uHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x)\n", - i, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map, - fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg); + "Pin index #%d: %uHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n", + pin_fmt[i].pin_index, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map, + fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg, + pin_fmt[i].buffer_size); } } @@ -179,10 +177,9 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, struct sof_ipc4_available_audio_format *available_fmt, struct sof_ipc4_base_module_cfg *module_base_cfg) { - struct sof_ipc4_base_module_cfg *base_config; - struct sof_ipc4_audio_format *out_format, *in_format; + struct sof_ipc4_pin_format *out_format, *in_format; int audio_fmt_num = 0; - int ret, i; + int ret; ret = sof_update_ipc_object(scomp, &audio_fmt_num, SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples, @@ -195,47 +192,25 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, dev_dbg(scomp->dev, "Number of audio formats: %d\n", available_fmt->audio_fmt_num); - base_config = kcalloc(available_fmt->audio_fmt_num, sizeof(*base_config), GFP_KERNEL); - if (!base_config) - return -ENOMEM; - /* set cpc and is_pages in the module's base_config */ ret = sof_update_ipc_object(scomp, module_base_cfg, SOF_COMP_TOKENS, swidget->tuples, swidget->num_tuples, sizeof(*module_base_cfg), 1); if (ret) { dev_err(scomp->dev, "parse comp tokens for %s failed, error: %d\n", swidget->widget->name, ret); - goto err; + return ret; } dev_dbg(scomp->dev, "widget %s cpc: %d is_pages: %d\n", swidget->widget->name, module_base_cfg->cpc, module_base_cfg->is_pages); - /* copy the ibs/obs for each base_cfg */ - ret = sof_update_ipc_object(scomp, base_config, - SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, swidget->tuples, - swidget->num_tuples, sizeof(*base_config), - available_fmt->audio_fmt_num); - if (ret) { - dev_err(scomp->dev, "parse buffer size tokens failed %d\n", ret); - goto err; - } - - for (i = 0; i < available_fmt->audio_fmt_num; i++) - dev_dbg(scomp->dev, "%d: ibs: %d obs: %d\n", i, - base_config[i].ibs, base_config[i].obs); - - in_format = kcalloc(available_fmt->audio_fmt_num, - sizeof(struct sof_ipc4_audio_format), GFP_KERNEL); - if (!in_format) { - kfree(base_config); - ret = -ENOMEM; - goto err; - } + in_format = kcalloc(available_fmt->audio_fmt_num, sizeof(*in_format), GFP_KERNEL); + if (!in_format) + return -ENOMEM; - ret = sof_update_ipc_object(scomp, available_fmt->input_audio_fmts, + ret = sof_update_ipc_object(scomp, in_format, SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples, - swidget->num_tuples, sizeof(struct sof_ipc4_audio_format), + swidget->num_tuples, sizeof(*in_format), available_fmt->audio_fmt_num); if (ret) { dev_err(scomp->dev, "parse base_config audio_fmt tokens failed %d\n", ret); @@ -243,8 +218,7 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, } dev_dbg(scomp->dev, "Get input audio formats for %s\n", swidget->widget->name); - sof_ipc4_dbg_audio_format(scomp->dev, available_fmt->input_audio_fmts, - sizeof(struct sof_ipc4_audio_format), + sof_ipc4_dbg_audio_format(scomp->dev, available_fmt->input_pin_fmts, available_fmt->audio_fmt_num); out_format = kcalloc(available_fmt->audio_fmt_num, sizeof(*out_format), GFP_KERNEL); @@ -264,12 +238,10 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, } dev_dbg(scomp->dev, "Get output audio formats for %s\n", swidget->widget->name); - sof_ipc4_dbg_audio_format(scomp->dev, out_format, sizeof(*out_format), - available_fmt->audio_fmt_num); + sof_ipc4_dbg_audio_format(scomp->dev, out_format, available_fmt->audio_fmt_num); - available_fmt->base_config = base_config; - available_fmt->out_audio_fmt = out_format; - available_fmt->input_audio_fmts = in_format; + available_fmt->output_pin_fmts = out_format; + available_fmt->input_pin_fmts = in_format; return 0; @@ -277,8 +249,6 @@ err_out: kfree(out_format); err_in: kfree(in_format); -err: - kfree(base_config); return ret; } @@ -286,12 +256,10 @@ err: static void sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format *available_fmt) { - kfree(available_fmt->base_config); - available_fmt->base_config = NULL; - kfree(available_fmt->out_audio_fmt); - available_fmt->out_audio_fmt = NULL; - kfree(available_fmt->input_audio_fmts); - available_fmt->input_audio_fmts = NULL; + kfree(available_fmt->output_pin_fmts); + available_fmt->output_pin_fmts = NULL; + kfree(available_fmt->input_pin_fmts); + available_fmt->input_pin_fmts = NULL; } static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget) @@ -431,8 +399,7 @@ static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget) return; available_fmt = &ipc4_copier->available_fmt; - kfree(available_fmt->base_config); - kfree(available_fmt->out_audio_fmt); + kfree(available_fmt->output_pin_fmts); kfree(ipc4_copier->gtw_attr); kfree(ipc4_copier); swidget->private = NULL; @@ -584,8 +551,7 @@ static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget) ipc4_copier = dai->private; available_fmt = &ipc4_copier->available_fmt; - kfree(available_fmt->base_config); - kfree(available_fmt->out_audio_fmt); + kfree(available_fmt->output_pin_fmts); if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP && ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC) kfree(ipc4_copier->copier_config); @@ -866,14 +832,14 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params, struct sof_ipc4_available_audio_format *available_fmt) { - struct sof_ipc4_audio_format *fmt = available_fmt->ref_audio_fmt; + struct sof_ipc4_pin_format *pin_fmt = available_fmt->ref_audio_fmt; u32 valid_bits; u32 channels; u32 rate; int sample_valid_bits; int i; - if (!fmt) { + if (!pin_fmt) { dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name); return -EINVAL; } @@ -902,7 +868,9 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, * Search supported audio formats to match rate, channels ,and * sample_valid_bytes from runtime params */ - for (i = 0; i < available_fmt->audio_fmt_num; i++, fmt++) { + for (i = 0; i < available_fmt->audio_fmt_num; i++) { + struct sof_ipc4_audio_format *fmt = &pin_fmt[i].audio_fmt; + rate = fmt->sampling_frequency; channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); @@ -921,15 +889,16 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, } /* copy input format */ - memcpy(&base_config->audio_fmt, &available_fmt->input_audio_fmts[i], sizeof(*fmt)); + memcpy(&base_config->audio_fmt, &available_fmt->input_pin_fmts[i].audio_fmt, + sizeof(*out_format)); /* set base_cfg ibs/obs */ - base_config->ibs = available_fmt->base_config[i].ibs; - base_config->obs = available_fmt->base_config[i].obs; + base_config->ibs = available_fmt->input_pin_fmts[i].buffer_size; + base_config->obs = available_fmt->output_pin_fmts[i].buffer_size; dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name); - sof_ipc4_dbg_audio_format(sdev->dev, &base_config->audio_fmt, - sizeof(*base_config), 1); + sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->input_pin_fmts[i], 1); + if (out_format) { /* * Current topology defines pin 0 input and output formats only in pairs. @@ -938,10 +907,10 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, * input format. This logic will need to be updated when the format definitions * in topology change. */ - memcpy(out_format, &available_fmt->out_audio_fmt[i], sizeof(*fmt)); + memcpy(out_format, &available_fmt->output_pin_fmts[i].audio_fmt, + sizeof(*out_format)); dev_dbg(sdev->dev, "Init output audio formats for %s\n", swidget->widget->name); - sof_ipc4_dbg_audio_format(sdev->dev, out_format, - sizeof(*out_format), 1); + sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->output_pin_fmts[i], 1); } /* Return the index of the matched format */ @@ -1144,13 +1113,13 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, available_fmt = &ipc4_copier->available_fmt; /* - * Use the input_audio_fmts to match pcm params for playback and the out_audio_fmt + * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts * for capture. */ if (dir == SNDRV_PCM_STREAM_PLAYBACK) - available_fmt->ref_audio_fmt = available_fmt->input_audio_fmts; + available_fmt->ref_audio_fmt = available_fmt->input_pin_fmts; else - available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt; + available_fmt->ref_audio_fmt = available_fmt->output_pin_fmts; copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; copier_data->gtw_cfg.node_id |= @@ -1170,7 +1139,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, copier_data = &ipc4_copier->data; available_fmt = &ipc4_copier->available_fmt; if (dir == SNDRV_PCM_STREAM_CAPTURE) { - available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt; + available_fmt->ref_audio_fmt = available_fmt->output_pin_fmts; /* * modify the input params for the dai copier as it only supports @@ -1180,7 +1149,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, snd_mask_none(fmt); snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); } else { - available_fmt->ref_audio_fmt = available_fmt->input_audio_fmts; + available_fmt->ref_audio_fmt = available_fmt->input_pin_fmts; } ref_params = pipeline_params; @@ -1201,7 +1170,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, available_fmt = &ipc4_copier->available_fmt; /* Use the input formats as the reference to match pcm params */ - available_fmt->ref_audio_fmt = available_fmt->input_audio_fmts; + available_fmt->ref_audio_fmt = available_fmt->input_pin_fmts; ref_params = pipeline_params; break; @@ -1388,7 +1357,7 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt; int ret; - available_fmt->ref_audio_fmt = available_fmt->input_audio_fmts; + available_fmt->ref_audio_fmt = available_fmt->input_pin_fmts; /* output format is not required to be sent to the FW for gain */ ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config, @@ -1414,7 +1383,7 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, int ret; /* only 32bit is supported by mixer */ - available_fmt->ref_audio_fmt = available_fmt->input_audio_fmts; + available_fmt->ref_audio_fmt = available_fmt->input_pin_fmts; /* output format is not required to be sent to the FW for mixer */ ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config, @@ -1440,7 +1409,7 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, struct snd_interval *rate; int ret; - available_fmt->ref_audio_fmt = available_fmt->input_audio_fmts; + available_fmt->ref_audio_fmt = available_fmt->input_pin_fmts; /* output format is not required to be sent to the FW for SRC */ ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config, @@ -2147,7 +2116,6 @@ static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link static enum sof_tokens common_copier_token_list[] = { SOF_COMP_TOKENS, SOF_AUDIO_FMT_NUM_TOKENS, - SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, SOF_IN_AUDIO_FORMAT_TOKENS, SOF_OUT_AUDIO_FORMAT_TOKENS, SOF_COPIER_DEEP_BUFFER_TOKENS, @@ -2163,7 +2131,6 @@ static enum sof_tokens pipeline_token_list[] = { static enum sof_tokens dai_token_list[] = { SOF_COMP_TOKENS, SOF_AUDIO_FMT_NUM_TOKENS, - SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, SOF_IN_AUDIO_FORMAT_TOKENS, SOF_OUT_AUDIO_FORMAT_TOKENS, SOF_COPIER_TOKENS, @@ -2175,8 +2142,8 @@ static enum sof_tokens pga_token_list[] = { SOF_COMP_TOKENS, SOF_GAIN_TOKENS, SOF_AUDIO_FMT_NUM_TOKENS, - SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, SOF_IN_AUDIO_FORMAT_TOKENS, + SOF_OUT_AUDIO_FORMAT_TOKENS, SOF_COMP_EXT_TOKENS, }; @@ -2184,7 +2151,7 @@ static enum sof_tokens mixer_token_list[] = { SOF_COMP_TOKENS, SOF_AUDIO_FMT_NUM_TOKENS, SOF_IN_AUDIO_FORMAT_TOKENS, - SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, + SOF_OUT_AUDIO_FORMAT_TOKENS, SOF_COMP_EXT_TOKENS, }; @@ -2193,7 +2160,7 @@ static enum sof_tokens src_token_list[] = { SOF_SRC_TOKENS, SOF_AUDIO_FMT_NUM_TOKENS, SOF_IN_AUDIO_FORMAT_TOKENS, - SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, + SOF_OUT_AUDIO_FORMAT_TOKENS, SOF_COMP_EXT_TOKENS, }; diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index 696d6c39a21b..2d9b1ba549f7 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -145,19 +145,32 @@ struct ipc4_pipeline_set_state_data { DECLARE_FLEX_ARRAY(u32, pipeline_ids); } __packed; +/** + * struct sof_ipc4_pin_format - Module pin format + * @pin_index: pin index + * @buffer_size: buffer size in bytes + * @audio_fmt: audio format for the pin + * + * This structure can be used for both output or input pins and the pin_index is relative to the + * pin type i.e output/input pin + */ +struct sof_ipc4_pin_format { + u32 pin_index; + u32 buffer_size; + struct sof_ipc4_audio_format audio_fmt; +}; + /** * struct sof_ipc4_available_audio_format - Available audio formats - * @base_config: Available base config - * @out_audio_fmt: Available output audio format - * @input_audio_fmts: Available input audio formats + * @output_pin_fmts: Available output pin formats + * @input_pin_fmts: Available input pin formats * @ref_audio_fmt: Reference audio format to match runtime audio format * @audio_fmt_num: Number of available audio formats */ struct sof_ipc4_available_audio_format { - struct sof_ipc4_base_module_cfg *base_config; - struct sof_ipc4_audio_format *out_audio_fmt; - struct sof_ipc4_audio_format *input_audio_fmts; - struct sof_ipc4_audio_format *ref_audio_fmt; + struct sof_ipc4_pin_format *output_pin_fmts; + struct sof_ipc4_pin_format *input_pin_fmts; + struct sof_ipc4_pin_format *ref_audio_fmt; int audio_fmt_num; }; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 4504f9efdc50..d220af5f08fb 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -256,7 +256,6 @@ enum sof_tokens { SOF_COMP_EXT_TOKENS, SOF_IN_AUDIO_FORMAT_TOKENS, SOF_OUT_AUDIO_FORMAT_TOKENS, - SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, SOF_COPIER_DEEP_BUFFER_TOKENS, SOF_COPIER_TOKENS, SOF_AUDIO_FMT_NUM_TOKENS, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 2d76ab13b3d1..3a091f18731f 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1232,7 +1232,6 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s continue; case SOF_IN_AUDIO_FORMAT_TOKENS: case SOF_OUT_AUDIO_FORMAT_TOKENS: - case SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS: num_sets = sof_get_token_value(SOF_TKN_COMP_NUM_AUDIO_FORMATS, swidget->tuples, swidget->num_tuples); -- cgit v1.2.3-58-ga151 From 4fdef47a44d6ff735902dfe740918f23932225ca Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 13 Mar 2023 14:48:55 +0200 Subject: ASoC: SOF: ipc4-topology: Add new tokens for input/output pin format count MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for handling processing modules with different input/output pin counts, introduce two new tokens for input/output audio format counts. Use these token values to parse all the available audio formats from topology. Signed-off-by: Ranjani Sridharan Reviewed-by: Rander Wang Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230313124856.8140-11-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 2 + sound/soc/sof/ipc4-topology.c | 143 ++++++++++++++++++++++++---------------- sound/soc/sof/ipc4-topology.h | 6 +- sound/soc/sof/topology.c | 42 +++++++----- 4 files changed, 116 insertions(+), 77 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 92360601b49c..bd02842124f9 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -96,6 +96,8 @@ */ #define SOF_TKN_COMP_INPUT_PIN_BINDING_WNAME 413 #define SOF_TKN_COMP_OUTPUT_PIN_BINDING_WNAME 414 +#define SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS 415 +#define SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS 416 /* SSP */ diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 3aacc440a5e4..c91a90dd8a6e 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -90,8 +90,10 @@ static const struct sof_topology_token ipc4_copier_tokens[] = { }; static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = { - {SOF_TKN_COMP_NUM_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - 0}, + {SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_available_audio_format, num_input_formats)}, + {SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_available_audio_format, num_output_formats)}, }; static const struct sof_topology_token dai_tokens[] = { @@ -178,19 +180,24 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, struct sof_ipc4_base_module_cfg *module_base_cfg) { struct sof_ipc4_pin_format *out_format, *in_format; - int audio_fmt_num = 0; int ret; - ret = sof_update_ipc_object(scomp, &audio_fmt_num, + ret = sof_update_ipc_object(scomp, available_fmt, SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples, - swidget->num_tuples, sizeof(audio_fmt_num), 1); - if (ret || audio_fmt_num <= 0) { - dev_err(scomp->dev, "Invalid number of audio formats: %d\n", audio_fmt_num); + swidget->num_tuples, sizeof(available_fmt), 1); + if (ret) { + dev_err(scomp->dev, "Failed to parse audio format token count\n"); + return ret; + } + + if (!available_fmt->num_input_formats && !available_fmt->num_output_formats) { + dev_err(scomp->dev, "No input/output pin formats set in topology\n"); return -EINVAL; } - available_fmt->audio_fmt_num = audio_fmt_num; - dev_dbg(scomp->dev, "Number of audio formats: %d\n", available_fmt->audio_fmt_num); + dev_dbg(scomp->dev, + "Number of input audio formats: %d. Number of output audio formats: %d\n", + available_fmt->num_input_formats, available_fmt->num_output_formats); /* set cpc and is_pages in the module's base_config */ ret = sof_update_ipc_object(scomp, module_base_cfg, SOF_COMP_TOKENS, swidget->tuples, @@ -204,51 +211,57 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, dev_dbg(scomp->dev, "widget %s cpc: %d is_pages: %d\n", swidget->widget->name, module_base_cfg->cpc, module_base_cfg->is_pages); - in_format = kcalloc(available_fmt->audio_fmt_num, sizeof(*in_format), GFP_KERNEL); - if (!in_format) - return -ENOMEM; + if (available_fmt->num_input_formats) { + in_format = kcalloc(available_fmt->num_input_formats, + sizeof(*in_format), GFP_KERNEL); + if (!in_format) + return -ENOMEM; + available_fmt->input_pin_fmts = in_format; + + ret = sof_update_ipc_object(scomp, in_format, + SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*in_format), + available_fmt->num_input_formats); + if (ret) { + dev_err(scomp->dev, "parse input audio fmt tokens failed %d\n", ret); + goto err_in; + } - ret = sof_update_ipc_object(scomp, in_format, - SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples, - swidget->num_tuples, sizeof(*in_format), - available_fmt->audio_fmt_num); - if (ret) { - dev_err(scomp->dev, "parse base_config audio_fmt tokens failed %d\n", ret); - goto err_in; + dev_dbg(scomp->dev, "Input audio formats for %s\n", swidget->widget->name); + sof_ipc4_dbg_audio_format(scomp->dev, in_format, + available_fmt->num_input_formats); } - dev_dbg(scomp->dev, "Get input audio formats for %s\n", swidget->widget->name); - sof_ipc4_dbg_audio_format(scomp->dev, available_fmt->input_pin_fmts, - available_fmt->audio_fmt_num); - - out_format = kcalloc(available_fmt->audio_fmt_num, sizeof(*out_format), GFP_KERNEL); - if (!out_format) { - ret = -ENOMEM; - goto err_in; - } + if (available_fmt->num_output_formats) { + out_format = kcalloc(available_fmt->num_output_formats, sizeof(*out_format), + GFP_KERNEL); + if (!out_format) { + ret = -ENOMEM; + goto err_in; + } - ret = sof_update_ipc_object(scomp, out_format, - SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples, - swidget->num_tuples, sizeof(*out_format), - available_fmt->audio_fmt_num); + ret = sof_update_ipc_object(scomp, out_format, + SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(*out_format), + available_fmt->num_output_formats); + if (ret) { + dev_err(scomp->dev, "parse output audio fmt tokens failed\n"); + goto err_out; + } - if (ret) { - dev_err(scomp->dev, "parse output audio_fmt tokens failed\n"); - goto err_out; + available_fmt->output_pin_fmts = out_format; + dev_dbg(scomp->dev, "Output audio formats for %s\n", swidget->widget->name); + sof_ipc4_dbg_audio_format(scomp->dev, out_format, + available_fmt->num_output_formats); } - dev_dbg(scomp->dev, "Get output audio formats for %s\n", swidget->widget->name); - sof_ipc4_dbg_audio_format(scomp->dev, out_format, available_fmt->audio_fmt_num); - - available_fmt->output_pin_fmts = out_format; - available_fmt->input_pin_fmts = in_format; - return 0; err_out: kfree(out_format); err_in: kfree(in_format); + available_fmt->input_pin_fmts = NULL; return ret; } @@ -830,7 +843,7 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, struct sof_ipc4_base_module_cfg *base_config, struct snd_pcm_hw_params *params, struct sof_ipc4_available_audio_format *available_fmt, - struct sof_ipc4_pin_format *pin_fmts) + struct sof_ipc4_pin_format *pin_fmts, u32 pin_fmts_size) { u32 valid_bits; u32 channels; @@ -858,7 +871,7 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, return -EINVAL; } - if (!available_fmt->audio_fmt_num) { + if (!pin_fmts_size) { dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name); return -EINVAL; } @@ -867,7 +880,7 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, * Search supported audio formats to match rate, channels ,and * sample_valid_bytes from runtime params */ - for (i = 0; i < available_fmt->audio_fmt_num; i++) { + for (i = 0; i < pin_fmts_size; i++) { struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt; rate = fmt->sampling_frequency; @@ -881,22 +894,26 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, } } - if (i == available_fmt->audio_fmt_num) { + if (i == pin_fmts_size) { dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n", __func__, params_rate(params), sample_valid_bits, params_channels(params)); return -EINVAL; } /* copy input format */ - memcpy(&base_config->audio_fmt, &available_fmt->input_pin_fmts[i].audio_fmt, - sizeof(struct sof_ipc4_audio_format)); + if (available_fmt->num_input_formats && i < available_fmt->num_input_formats) { + memcpy(&base_config->audio_fmt, &available_fmt->input_pin_fmts[i].audio_fmt, + sizeof(struct sof_ipc4_audio_format)); + + /* set base_cfg ibs/obs */ + base_config->ibs = available_fmt->input_pin_fmts[i].buffer_size; - /* set base_cfg ibs/obs */ - base_config->ibs = available_fmt->input_pin_fmts[i].buffer_size; - base_config->obs = available_fmt->output_pin_fmts[i].buffer_size; + dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name); + sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->input_pin_fmts[i], 1); + } - dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name); - sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->input_pin_fmts[i], 1); + if (available_fmt->num_output_formats && i < available_fmt->num_output_formats) + base_config->obs = available_fmt->output_pin_fmts[i].buffer_size; /* Return the index of the matched format */ return i; @@ -1070,6 +1087,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, u32 **data; int ipc_size, ret; u32 deep_buffer_dma_ms = 0; + u32 format_list_count; dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); @@ -1102,10 +1120,13 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts * for capture. */ - if (dir == SNDRV_PCM_STREAM_PLAYBACK) + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { format_list_to_search = available_fmt->input_pin_fmts; - else + format_list_count = available_fmt->num_input_formats; + } else { format_list_to_search = available_fmt->output_pin_fmts; + format_list_count = available_fmt->num_output_formats; + } copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; copier_data->gtw_cfg.node_id |= @@ -1126,6 +1147,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, available_fmt = &ipc4_copier->available_fmt; if (dir == SNDRV_PCM_STREAM_CAPTURE) { format_list_to_search = available_fmt->output_pin_fmts; + format_list_count = available_fmt->num_output_formats; /* * modify the input params for the dai copier as it only supports @@ -1136,6 +1158,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); } else { format_list_to_search = available_fmt->input_pin_fmts; + format_list_count = available_fmt->num_input_formats; } ref_params = pipeline_params; @@ -1157,6 +1180,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, /* Use the input formats to match pcm params */ format_list_to_search = available_fmt->input_pin_fmts; + format_list_count = available_fmt->num_input_formats; ref_params = pipeline_params; break; @@ -1169,7 +1193,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, /* set input and output audio formats */ ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config, ref_params, - available_fmt, format_list_to_search); + available_fmt, format_list_to_search, format_list_count); if (ret < 0) return ret; @@ -1356,7 +1380,8 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config, pipeline_params, available_fmt, - available_fmt->input_pin_fmts); + available_fmt->input_pin_fmts, + available_fmt->num_input_formats); if (ret < 0) return ret; @@ -1379,7 +1404,8 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config, pipeline_params, available_fmt, - available_fmt->input_pin_fmts); + available_fmt->input_pin_fmts, + available_fmt->num_input_formats); if (ret < 0) return ret; @@ -1403,7 +1429,8 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config, pipeline_params, available_fmt, - available_fmt->input_pin_fmts); + available_fmt->input_pin_fmts, + available_fmt->num_input_formats); if (ret < 0) return ret; diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index 6359ef8736ae..fad7a628f782 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -164,12 +164,14 @@ struct sof_ipc4_pin_format { * struct sof_ipc4_available_audio_format - Available audio formats * @output_pin_fmts: Available output pin formats * @input_pin_fmts: Available input pin formats - * @audio_fmt_num: Number of available audio formats + * @num_input_formats: Number of input pin formats + * @num_output_formats: Number of output pin formats */ struct sof_ipc4_available_audio_format { struct sof_ipc4_pin_format *output_pin_fmts; struct sof_ipc4_pin_format *input_pin_fmts; - int audio_fmt_num; + u32 num_input_formats; + u32 num_output_formats; }; /** diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 3a091f18731f..b642835e14df 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1231,35 +1231,43 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s continue; case SOF_IN_AUDIO_FORMAT_TOKENS: - case SOF_OUT_AUDIO_FORMAT_TOKENS: - num_sets = sof_get_token_value(SOF_TKN_COMP_NUM_AUDIO_FORMATS, + num_sets = sof_get_token_value(SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS, swidget->tuples, swidget->num_tuples); - if (num_sets < 0) { - dev_err(sdev->dev, "Invalid audio format count for %s\n", + dev_err(sdev->dev, "Invalid input audio format count for %s\n", swidget->widget->name); ret = num_sets; goto err; } - - if (num_sets > 1) { - struct snd_sof_tuple *new_tuples; - - num_tuples += token_list[object_token_list[i]].count * num_sets; - new_tuples = krealloc(swidget->tuples, - sizeof(*new_tuples) * num_tuples, GFP_KERNEL); - if (!new_tuples) { - ret = -ENOMEM; - goto err; - } - - swidget->tuples = new_tuples; + break; + case SOF_OUT_AUDIO_FORMAT_TOKENS: + num_sets = sof_get_token_value(SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS, + swidget->tuples, swidget->num_tuples); + if (num_sets < 0) { + dev_err(sdev->dev, "Invalid output audio format count for %s\n", + swidget->widget->name); + ret = num_sets; + goto err; } break; default: break; } + if (num_sets > 1) { + struct snd_sof_tuple *new_tuples; + + num_tuples += token_list[object_token_list[i]].count * num_sets; + new_tuples = krealloc(swidget->tuples, + sizeof(*new_tuples) * num_tuples, GFP_KERNEL); + if (!new_tuples) { + ret = -ENOMEM; + goto err; + } + + swidget->tuples = new_tuples; + } + /* copy one set of tuples per token ID into swidget->tuples */ ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size), object_token_list[i], num_sets, swidget->tuples, -- cgit v1.2.3-58-ga151 From ca5ce0caa67fa9eeecaa29d895c2e4c3151c159e Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 21 Mar 2023 11:26:54 +0200 Subject: ASoC: SOF: ipc4/intel: Add support for chained DMA Add logic for setting up and tearing down chained DMA connections. Since pipelines are not used, all the logic to set the pipeline states can be bypassed, with only the DMA programming sequences remaining. In addition the same format needs to be used for host- and link-DMA, without the usual fixup to use the S32_LE format on the link. Note however that for convenience and compatibility with existing definitions, the topology relies on the concept of pipelines with a 'USE_CHAIN_DMA' token indicating that all the logic shall be bypassed. Unlike 'normal' ALSA sequences, the chain DMA is not programmed in hw_params/hw_free. The IPC message to set-up and tear-down chained DMA are sent in sof_ipc4_trigger_pipelines(), but the contents prepared earlier. Chained DMA is only supported by the Intel HDA DAI for now, and only S16_LE and S32_LE formats are supported for now. Signed-off-by: Jyri Sarha Reviewed-by: Rander Wang Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230321092654.7292-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 1 + sound/soc/sof/intel/hda-dai-ops.c | 18 +++++- sound/soc/sof/ipc4-pcm.c | 122 ++++++++++++++++++++++++++++++++++++-- sound/soc/sof/ipc4-topology.c | 120 ++++++++++++++++++++++++++++++++++++- sound/soc/sof/ipc4-topology.h | 2 + 5 files changed, 255 insertions(+), 8 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index bd02842124f9..bbc37877aaff 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -54,6 +54,7 @@ #define SOF_TKN_SCHED_DYNAMIC_PIPELINE 206 #define SOF_TKN_SCHED_LP_MODE 207 #define SOF_TKN_SCHED_MEM_USAGE 208 +#define SOF_TKN_SCHED_USE_CHAIN_DMA 209 /* volume */ #define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250 diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index be109f33715f..de48f13259f1 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -277,6 +277,15 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { .post_trigger = hda_ipc4_post_trigger }; +static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = { + .get_hext_stream = hda_get_hext_stream, + .assign_hext_stream = hda_assign_hext_stream, + .release_hext_stream = hda_release_hext_stream, + .setup_hext_stream = hda_setup_hext_stream, + .reset_hext_stream = hda_reset_hext_stream, + .trigger = hda_trigger, +}; + static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream, int cmd) { @@ -331,8 +340,15 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg { struct sof_ipc4_copier *ipc4_copier = sdai->private; - if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) + if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) { + struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; + + if (pipeline->use_chain_dma) + return &hda_ipc4_chain_dma_ops; + return &hda_ipc4_dma_ops; + } break; } default: diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 4598057b7f28..db64200ba1e5 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -193,6 +193,88 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd, * prepare ioctl before the START trigger. */ +/* + * Chained DMA is a special case where there is no processing on + * DSP. The samples are just moved over by host side DMA to a single + * buffer on DSP and directly from there to link DMA. However, the + * model on SOF driver has two notional pipelines, one at host DAI, + * and another at link DAI. They both shall have the use_chain_dma + * attribute. + */ + +static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev, + struct snd_sof_pcm_stream_pipeline_list *pipeline_list, + int state, int cmd) +{ + bool allocate, enable, set_fifo_size; + struct sof_ipc4_msg msg = {{ 0 }}; + int i; + + switch (state) { + case SOF_IPC4_PIPE_RUNNING: /* Allocate and start chained dma */ + allocate = true; + enable = true; + /* + * SOF assumes creation of a new stream from the presence of fifo_size + * in the message, so we must leave it out in pause release case. + */ + if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) + set_fifo_size = false; + else + set_fifo_size = true; + break; + case SOF_IPC4_PIPE_PAUSED: /* Disable chained DMA. */ + allocate = true; + enable = false; + set_fifo_size = false; + break; + case SOF_IPC4_PIPE_RESET: /* Disable and free chained DMA. */ + allocate = false; + enable = false; + set_fifo_size = false; + break; + default: + dev_err(sdev->dev, "Unexpected state %d", state); + return -EINVAL; + } + + msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CHAIN_DMA); + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); + + /* + * To set-up the DMA chain, the host DMA ID and SCS setting + * are retrieved from the host pipeline configuration. Likewise + * the link DMA ID and fifo_size are retrieved from the link + * pipeline configuration. + */ + for (i = 0; i < pipeline_list->count; i++) { + struct snd_sof_pipeline *spipe = pipeline_list->pipelines[i]; + struct snd_sof_widget *pipe_widget = spipe->pipe_widget; + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; + + if (!pipeline->use_chain_dma) { + dev_err(sdev->dev, + "All pipelines in chained DMA stream should have use_chain_dma attribute set."); + return -EINVAL; + } + + msg.primary |= pipeline->msg.primary; + + /* Add fifo_size (actually DMA buffer size) field to the message */ + if (set_fifo_size) + msg.extension |= pipeline->msg.extension; + } + + if (allocate) + msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ALLOCATE_MASK; + + if (enable) + msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ENABLE_MASK; + + return sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); +} + static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, struct snd_pcm_substream *substream, int state, int cmd) { @@ -201,6 +283,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, struct snd_sof_pcm_stream_pipeline_list *pipeline_list; struct sof_ipc4_fw_data *ipc4_data = sdev->private; struct ipc4_pipeline_set_state_data *trigger_list; + struct snd_sof_widget *pipe_widget; + struct sof_ipc4_pipeline *pipeline; struct snd_sof_pipeline *spipe; struct snd_sof_pcm *spcm; int ret; @@ -218,6 +302,17 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, if (!pipeline_list->pipelines || !pipeline_list->count) return 0; + spipe = pipeline_list->pipelines[0]; + pipe_widget = spipe->pipe_widget; + pipeline = pipe_widget->private; + + /* + * If use_chain_dma attribute is set we proceed to chained DMA + * trigger function that handles the rest for the substream. + */ + if (pipeline->use_chain_dma) + return sof_ipc4_chain_dma_trigger(sdev, pipeline_list, state, cmd); + /* allocate memory for the pipeline data */ trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count), GFP_KERNEL); @@ -422,8 +517,10 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct sof_ipc4_copier *ipc4_copier; - int ret; + bool use_chain_dma = false; + int dir; if (!dai) { dev_err(component->dev, "%s: No DAI found with name %s\n", __func__, @@ -438,9 +535,26 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, return -EINVAL; } - ret = sof_ipc4_pcm_dai_link_fixup_rate(sdev, params, ipc4_copier); - if (ret) - return ret; + for_each_pcm_streams(dir) { + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, dir); + + if (w) { + struct snd_sof_widget *swidget = w->dobj.private; + struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; + + if (pipeline->use_chain_dma) + use_chain_dma = true; + } + } + + /* Chain DMA does not use copiers, so no fixup needed */ + if (!use_chain_dma) { + int ret = sof_ipc4_pcm_dai_link_fixup_rate(sdev, params, ipc4_copier); + + if (ret) + return ret; + } switch (ipc4_copier->dai_type) { case SOF_DAI_INTEL_SSP: diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 3a4a3267017b..f1e1aed94da4 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -19,6 +19,7 @@ #define SOF_IPC4_GAIN_PARAM_ID 0 #define SOF_IPC4_TPLG_ABI_SIZE 6 +#define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2 static DEFINE_IDA(alh_group_ida); static DEFINE_IDA(pipeline_ida); @@ -26,6 +27,8 @@ static DEFINE_IDA(pipeline_ida); static const struct sof_topology_token ipc4_sched_tokens[] = { {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct sof_ipc4_pipeline, lp_mode)}, + {SOF_TKN_SCHED_USE_CHAIN_DMA, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, + offsetof(struct sof_ipc4_pipeline, use_chain_dma)}, {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct sof_ipc4_pipeline, core_id)}, }; @@ -475,6 +478,8 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) struct snd_soc_component *scomp = swidget->scomp; struct snd_sof_dai *dai = swidget->private; struct sof_ipc4_copier *ipc4_copier; + struct snd_sof_widget *pipe_widget; + struct sof_ipc4_pipeline *pipeline; int node_type = 0; int ret; @@ -512,6 +517,16 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type); + pipe_widget = swidget->spipe->pipe_widget; + pipeline = pipe_widget->private; + if (pipeline->use_chain_dma && ipc4_copier->dai_type != SOF_DAI_INTEL_HDA) { + dev_err(scomp->dev, + "Bad DAI type '%d', Chained DMA is only supported by HDA DAIs (%d).\n", + ipc4_copier->dai_type, SOF_DAI_INTEL_HDA); + ret = -ENODEV; + goto free_available_fmt; + } + switch (ipc4_copier->dai_type) { case SOF_DAI_INTEL_ALH: { @@ -643,6 +658,12 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) swidget->core = pipeline->core_id; + if (pipeline->use_chain_dma) { + dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name); + swidget->private = pipeline; + return 0; + } + /* parse one set of pipeline tokens */ ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples, swidget->num_tuples, sizeof(*swidget), 1); @@ -1103,11 +1124,21 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) pipeline->mem_usage = 0; if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) { + if (pipeline->use_chain_dma) { + pipeline->msg.primary = 0; + pipeline->msg.extension = 0; + } ipc4_copier = swidget->private; } else if (WIDGET_IS_DAI(swidget->id)) { struct snd_sof_dai *dai = swidget->private; ipc4_copier = dai->private; + + if (pipeline->use_chain_dma) { + pipeline->msg.primary = 0; + pipeline->msg.extension = 0; + } + if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data; struct sof_ipc4_alh_configuration_blob *blob; @@ -1344,13 +1375,44 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, return ret; } - pipe_widget = swidget->spipe->pipe_widget; - pipeline = pipe_widget->private; ipc4_copier = (struct sof_ipc4_copier *)swidget->private; gtw_attr = ipc4_copier->gtw_attr; copier_data = &ipc4_copier->data; available_fmt = &ipc4_copier->available_fmt; + pipe_widget = swidget->spipe->pipe_widget; + pipeline = pipe_widget->private; + + if (pipeline->use_chain_dma) { + u32 host_dma_id; + u32 fifo_size; + + host_dma_id = platform_params->stream_tag - 1; + pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id); + + /* Set SCS bit for S16_LE format only */ + if (params_format(fe_params) == SNDRV_PCM_FORMAT_S16_LE) + pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK; + + /* + * Despite its name the bitfield 'fifo_size' is used to define DMA buffer + * size. The expression calculates 2ms buffer size. + */ + fifo_size = DIV_ROUND_UP((SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS * + params_rate(fe_params) * + params_channels(fe_params) * + params_physical_width(fe_params)), 8000); + pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size); + + /* + * Chain DMA does not support stream timestamping, set node_id to invalid + * to skip the code in sof_ipc4_get_stream_start_offset(). + */ + copier_data->gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID; + + return 0; + } + /* * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts * for capture. @@ -1375,6 +1437,12 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, case snd_soc_dapm_dai_in: case snd_soc_dapm_dai_out: { + struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; + + if (pipeline->use_chain_dma) + return 0; + dai = swidget->private; ipc4_copier = (struct sof_ipc4_copier *)dai->private; @@ -1921,6 +1989,9 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget case snd_soc_dapm_scheduler: pipeline = swidget->private; + if (pipeline->use_chain_dma) + return 0; + dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id, pipeline->mem_usage); @@ -1943,6 +2014,10 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget { struct sof_ipc4_copier *ipc4_copier = swidget->private; + pipeline = pipe_widget->private; + if (pipeline->use_chain_dma) + return 0; + ipc_size = ipc4_copier->ipc_config_size; ipc_data = ipc4_copier->ipc_config_data; @@ -1955,6 +2030,10 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget struct snd_sof_dai *dai = swidget->private; struct sof_ipc4_copier *ipc4_copier = dai->private; + pipeline = pipe_widget->private; + if (pipeline->use_chain_dma) + return 0; + ipc_size = ipc4_copier->ipc_config_size; ipc_data = ipc4_copier->ipc_config_data; @@ -2066,6 +2145,9 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget struct sof_ipc4_msg msg = {{ 0 }}; u32 header; + if (pipeline->use_chain_dma) + return 0; + header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id); header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE); header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); @@ -2082,7 +2164,11 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; ida_free(&pipeline_ida, swidget->instance_id); } else { - ida_free(&fw_module->m_ida, swidget->instance_id); + struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; + + if (!pipeline->use_chain_dma) + ida_free(&fw_module->m_ida, swidget->instance_id); } mutex_unlock(&ipc4_data->pipeline_state_mutex); @@ -2234,12 +2320,27 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * { struct snd_sof_widget *src_widget = sroute->src_widget; struct snd_sof_widget *sink_widget = sroute->sink_widget; + struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget; + struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget; struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; + struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private; + struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private; struct sof_ipc4_msg msg = {{ 0 }}; u32 header, extension; int ret; + /* no route set up if chain DMA is used */ + if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) { + if (!src_pipeline->use_chain_dma || !sink_pipeline->use_chain_dma) { + dev_err(sdev->dev, + "use_chain_dma must be set for both src %s and sink %s pipelines\n", + src_widget->widget->name, sink_widget->widget->name); + return -EINVAL; + } + return 0; + } + sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, SOF_PIN_TYPE_OUTPUT); if (sroute->src_queue_id < 0) { @@ -2310,9 +2411,17 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; struct sof_ipc4_msg msg = {{ 0 }}; + struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget; + struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget; + struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private; + struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private; u32 header, extension; int ret = 0; + /* no route is set up if chain DMA is used */ + if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) + return 0; + dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n", src_widget->widget->name, sroute->src_queue_id, sink_widget->widget->name, sroute->dst_queue_id); @@ -2374,6 +2483,11 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * switch (ipc4_copier->dai_type) { case SOF_DAI_INTEL_HDA: + if (pipeline->use_chain_dma) { + pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK; + pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(data->dai_data); + break; + } gtw_attr = ipc4_copier->gtw_attr; gtw_attr->lp_buffer_alloc = pipeline->lp_mode; pipeline->skip_during_fe_trigger = true; diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index 015027b23588..cf007282867b 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -126,6 +126,7 @@ struct sof_ipc4_copier_config_set_sink_format { * @mem_usage: Memory usage * @core_id: Target core for the pipeline * @state: Pipeline state + * @use_chain_dma: flag to indicate if the firmware shall use chained DMA * @msg: message structure for pipeline * @skip_during_fe_trigger: skip triggering this pipeline during the FE DAI trigger */ @@ -135,6 +136,7 @@ struct sof_ipc4_pipeline { uint32_t mem_usage; uint32_t core_id; int state; + bool use_chain_dma; struct sof_ipc4_msg msg; bool skip_during_fe_trigger; }; -- cgit v1.2.3-58-ga151 From 102882b5c62f6bfe403178bb36adef3ba542d148 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 6 Apr 2023 15:25:21 +0200 Subject: ALSA: document that struct __snd_pcm_mmap_control64 is messed up I'm not the first one to run into this, see e.g. https://lore.kernel.org/all/29QBMJU8DE71E.2YZSH8IHT5HMH@mforney.org/ Signed-off-by: Oswald Buddenhagen Link: https://lore.kernel.org/r/20230406132521.2252019-1-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- include/uapi/sound/asound.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/uapi') diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index de6810e94abe..7eecc99ddef7 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -570,7 +570,8 @@ struct __snd_pcm_mmap_status64 { struct __snd_pcm_mmap_control64 { __pad_before_uframe __pad1; snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */ - __pad_before_uframe __pad2; + __pad_before_uframe __pad2; // This should be __pad_after_uframe, but binary + // backwards compatibility constraints prevent a fix. __pad_before_uframe __pad3; snd_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */ -- cgit v1.2.3-58-ga151 From 9f656705c5faa18afb26d922cfc64f9fd103c38d Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 20 Apr 2023 13:33:23 +0200 Subject: ALSA: pcm: rewrite snd_pcm_playback_silence() The auto-silencer supports two modes: "thresholded" to fill up "just enough", and "top-up" to fill up "as much as possible". The two modes used rather distinct code paths, which this patch unifies. The only remaining distinction is how much we actually want to fill. This fixes a bug in thresholded mode, where we failed to use new_hw_ptr, resulting in under-fill. Top-up mode is now more well-behaved and much easier to understand in corner cases. This also updates comments in the proximity of silencing-related data structures. Signed-off-by: Oswald Buddenhagen Reviewed-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20230420113324.877164-1-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- .../sound/kernel-api/writing-an-alsa-driver.rst | 17 +++-- include/sound/pcm.h | 14 ++-- include/uapi/sound/asound.h | 11 ++- sound/core/pcm_lib.c | 86 +++++++++------------- sound/core/pcm_local.h | 3 +- sound/core/pcm_native.c | 6 +- 6 files changed, 66 insertions(+), 71 deletions(-) (limited to 'include/uapi') diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst index a368529e8ed3..e37d9dba320d 100644 --- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst +++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst @@ -1577,14 +1577,19 @@ are the contents of this file: unsigned int period_step; unsigned int sleep_min; /* min ticks to sleep */ snd_pcm_uframes_t start_threshold; - snd_pcm_uframes_t stop_threshold; - snd_pcm_uframes_t silence_threshold; /* Silence filling happens when - noise is nearest than this */ - snd_pcm_uframes_t silence_size; /* Silence filling size */ + /* + * The following two thresholds alleviate playback buffer underruns; when + * hw_avail drops below the threshold, the respective action is triggered: + */ + snd_pcm_uframes_t stop_threshold; /* - stop playback */ + snd_pcm_uframes_t silence_threshold; /* - pre-fill buffer with silence */ + snd_pcm_uframes_t silence_size; /* max size of silence pre-fill; when >= boundary, + * fill played area with silence immediately */ snd_pcm_uframes_t boundary; /* pointers wrap point */ - snd_pcm_uframes_t silenced_start; - snd_pcm_uframes_t silenced_size; + /* internal data of auto-silencer */ + snd_pcm_uframes_t silence_start; /* starting pointer to silence area */ + snd_pcm_uframes_t silence_filled; /* size filled with silence */ snd_pcm_sync_id_t sync; /* hardware synchronization ID */ diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 27040b472a4f..19f564606ac4 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -378,18 +378,18 @@ struct snd_pcm_runtime { unsigned int rate_den; unsigned int no_period_wakeup: 1; - /* -- SW params -- */ - int tstamp_mode; /* mmap timestamp is updated */ + /* -- SW params; see struct snd_pcm_sw_params for comments -- */ + int tstamp_mode; unsigned int period_step; snd_pcm_uframes_t start_threshold; snd_pcm_uframes_t stop_threshold; - snd_pcm_uframes_t silence_threshold; /* Silence filling happens when - noise is nearest than this */ - snd_pcm_uframes_t silence_size; /* Silence filling size */ - snd_pcm_uframes_t boundary; /* pointers wrap point */ + snd_pcm_uframes_t silence_threshold; + snd_pcm_uframes_t silence_size; + snd_pcm_uframes_t boundary; + /* internal data of auto-silencer */ snd_pcm_uframes_t silence_start; /* starting pointer to silence area */ - snd_pcm_uframes_t silence_filled; /* size filled with silence */ + snd_pcm_uframes_t silence_filled; /* already filled part of silence area */ union snd_pcm_sync_id sync; /* hardware synchronization ID */ diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 7eecc99ddef7..0aa955aa8246 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -429,9 +429,14 @@ struct snd_pcm_sw_params { snd_pcm_uframes_t avail_min; /* min avail frames for wakeup */ snd_pcm_uframes_t xfer_align; /* obsolete: xfer size need to be a multiple */ snd_pcm_uframes_t start_threshold; /* min hw_avail frames for automatic start */ - snd_pcm_uframes_t stop_threshold; /* min avail frames for automatic stop */ - snd_pcm_uframes_t silence_threshold; /* min distance from noise for silence filling */ - snd_pcm_uframes_t silence_size; /* silence block size */ + /* + * The following two thresholds alleviate playback buffer underruns; when + * hw_avail drops below the threshold, the respective action is triggered: + */ + snd_pcm_uframes_t stop_threshold; /* - stop playback */ + snd_pcm_uframes_t silence_threshold; /* - pre-fill buffer with silence */ + snd_pcm_uframes_t silence_size; /* max size of silence pre-fill; when >= boundary, + * fill played area with silence immediately */ snd_pcm_uframes_t boundary; /* pointers wrap point */ unsigned int proto; /* protocol version */ unsigned int tstamp_type; /* timestamp type (req. proto >= 2.0.12) */ diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index af1eb136feb0..d21c73944efd 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -42,70 +42,56 @@ static int fill_silence_frames(struct snd_pcm_substream *substream, * * when runtime->silence_size >= runtime->boundary - fill processed area with silence immediately */ -void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr) +void snd_pcm_playback_silence(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_uframes_t frames, ofs, transfer; + snd_pcm_uframes_t appl_ptr = READ_ONCE(runtime->control->appl_ptr); + snd_pcm_sframes_t added, hw_avail, frames; + snd_pcm_uframes_t noise_dist, ofs, transfer; int err; + added = appl_ptr - runtime->silence_start; + if (added) { + if (added < 0) + added += runtime->boundary; + if (added < runtime->silence_filled) + runtime->silence_filled -= added; + else + runtime->silence_filled = 0; + runtime->silence_start = appl_ptr; + } + + // This will "legitimately" turn negative on underrun, and will be mangled + // into a huge number by the boundary crossing handling. The initial state + // might also be not quite sane. The code below MUST account for these cases. + hw_avail = appl_ptr - runtime->status->hw_ptr; + if (hw_avail < 0) + hw_avail += runtime->boundary; + + noise_dist = hw_avail + runtime->silence_filled; if (runtime->silence_size < runtime->boundary) { - snd_pcm_sframes_t noise_dist, n; - snd_pcm_uframes_t appl_ptr = READ_ONCE(runtime->control->appl_ptr); - if (runtime->silence_start != appl_ptr) { - n = appl_ptr - runtime->silence_start; - if (n < 0) - n += runtime->boundary; - if ((snd_pcm_uframes_t)n < runtime->silence_filled) - runtime->silence_filled -= n; - else - runtime->silence_filled = 0; - runtime->silence_start = appl_ptr; - } - if (runtime->silence_filled >= runtime->buffer_size) - return; - noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled; - if (noise_dist >= (snd_pcm_sframes_t) runtime->silence_threshold) - return; frames = runtime->silence_threshold - noise_dist; + if (frames <= 0) + return; if (frames > runtime->silence_size) frames = runtime->silence_size; } else { - if (new_hw_ptr == ULONG_MAX) { /* initialization */ - snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime); - if (avail > runtime->buffer_size) - avail = runtime->buffer_size; - runtime->silence_filled = avail > 0 ? avail : 0; - runtime->silence_start = (runtime->status->hw_ptr + - runtime->silence_filled) % - runtime->boundary; - } else { - ofs = runtime->status->hw_ptr; - frames = new_hw_ptr - ofs; - if ((snd_pcm_sframes_t)frames < 0) - frames += runtime->boundary; - runtime->silence_filled -= frames; - if ((snd_pcm_sframes_t)runtime->silence_filled < 0) { - runtime->silence_filled = 0; - runtime->silence_start = new_hw_ptr; - } else { - runtime->silence_start = ofs; - } - } - frames = runtime->buffer_size - runtime->silence_filled; + frames = runtime->buffer_size - noise_dist; + if (frames <= 0) + return; } + if (snd_BUG_ON(frames > runtime->buffer_size)) return; - if (frames == 0) - return; - ofs = runtime->silence_start % runtime->buffer_size; - while (frames > 0) { + ofs = (runtime->silence_start + runtime->silence_filled) % runtime->buffer_size; + do { transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames; err = fill_silence_frames(substream, ofs, transfer); snd_BUG_ON(err < 0); runtime->silence_filled += transfer; frames -= transfer; ofs = 0; - } + } while (frames > 0); snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); } @@ -439,10 +425,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, return 0; } - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - runtime->silence_size > 0) - snd_pcm_playback_silence(substream, new_hw_ptr); - if (in_interrupt) { delta = new_hw_ptr - runtime->hw_ptr_interrupt; if (delta < 0) @@ -460,6 +442,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, runtime->hw_ptr_wrap += runtime->boundary; } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + runtime->silence_size > 0) + snd_pcm_playback_silence(substream); + update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp); return snd_pcm_update_state(substream, runtime); diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h index ecb21697ae3a..42fe3a4e9154 100644 --- a/sound/core/pcm_local.h +++ b/sound/core/pcm_local.h @@ -29,8 +29,7 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime); int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); -void snd_pcm_playback_silence(struct snd_pcm_substream *substream, - snd_pcm_uframes_t new_hw_ptr); +void snd_pcm_playback_silence(struct snd_pcm_substream *substream); static inline snd_pcm_uframes_t snd_pcm_avail(struct snd_pcm_substream *substream) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 94185267a7b9..3d0c4a5b701b 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -958,7 +958,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, if (snd_pcm_running(substream)) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) - snd_pcm_playback_silence(substream, ULONG_MAX); + snd_pcm_playback_silence(substream); err = snd_pcm_update_state(substream, runtime); } snd_pcm_stream_unlock_irq(substream); @@ -1455,7 +1455,7 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, __snd_pcm_set_state(runtime, state); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) - snd_pcm_playback_silence(substream, ULONG_MAX); + snd_pcm_playback_silence(substream); snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART); } @@ -1916,7 +1916,7 @@ static void snd_pcm_post_reset(struct snd_pcm_substream *substream, runtime->control->appl_ptr = runtime->status->hw_ptr; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) - snd_pcm_playback_silence(substream, ULONG_MAX); + snd_pcm_playback_silence(substream); snd_pcm_stream_unlock_irq(substream); } -- cgit v1.2.3-58-ga151 From d4af7ca20173e61b77584e4f2025387b7b76ef75 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 21 Apr 2023 16:10:02 +0200 Subject: ALSA: emu10k1: remove obsolete card type variable and defines The use of the variable was removed in commit 2b637da5a1b ("clean up card features"). That commit also broke user space (the ioctl structure), at which point the defines became meaningless, so I don't think purging them is a problem. Signed-off-by: Oswald Buddenhagen Link: https://lore.kernel.org/r/20230421141006.1005452-3-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 1 - include/uapi/sound/emu10k1.h | 3 --- 2 files changed, 4 deletions(-) (limited to 'include/uapi') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 3407ca4a1210..ddc1e71a8de5 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1689,7 +1689,6 @@ struct snd_emu10k1 { unsigned int revision; /* chip revision */ unsigned int serial; /* serial number */ unsigned short model; /* subsystem id */ - unsigned int card_type; /* EMU10K1_CARD_* */ unsigned int ecard_ctrl; /* ecard control bits */ unsigned int address_mode; /* address mode */ unsigned long dma_mask; /* PCI DMA mask */ diff --git a/include/uapi/sound/emu10k1.h b/include/uapi/sound/emu10k1.h index 1c1f1dd44611..c2414bd5aecd 100644 --- a/include/uapi/sound/emu10k1.h +++ b/include/uapi/sound/emu10k1.h @@ -15,9 +15,6 @@ * ---- FX8010 ---- */ -#define EMU10K1_CARD_CREATIVE 0x00000000 -#define EMU10K1_CARD_EMUAPS 0x00000001 - #define EMU10K1_FX8010_PCM_COUNT 8 /* -- cgit v1.2.3-58-ga151 From a869057cd639ed41a1b16bc072fb20cb1ed1dc51 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 22 Apr 2023 18:10:15 +0200 Subject: ALSA: emu10k1: comment updates Move comments to better locations, de-duplicate, fix/remove incorrect/ outdated ones, add new ones, and unify spacing somewhat. While at it, also add testing credits for Jonathan Dowland (SB Live! Platinum) and myself (E-MU 0404b). Signed-off-by: Oswald Buddenhagen Link: https://lore.kernel.org/r/20230422161021.1143903-2-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 504 +++++++++++++++++++-------------------- include/uapi/sound/emu10k1.h | 3 + sound/pci/emu10k1/emu10k1.c | 11 - sound/pci/emu10k1/emu10k1_main.c | 77 +++--- sound/pci/emu10k1/emufx.c | 12 +- sound/pci/emu10k1/emumixer.c | 5 +- sound/pci/emu10k1/emupcm.c | 26 +- sound/pci/emu10k1/io.c | 8 - sound/pci/emu10k1/p16v.h | 2 +- sound/pci/emu10k1/p17v.h | 4 +- 10 files changed, 312 insertions(+), 340 deletions(-) (limited to 'include/uapi') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 790dedd42340..7786d5807679 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -97,9 +97,9 @@ #define IPR_CHANNELLOOP 0x00000040 /* Channel (half) loop interrupt(s) pending */ #define IPR_CHANNELNUMBERMASK 0x0000003f /* When IPR_CHANNELLOOP is set, indicates the */ /* highest set channel in CLIPL, CLIPH, HLIPL, */ - /* or HLIPH. When IP is written with CL set, */ + /* or HLIPH. When IPR is written with CL set, */ /* the bit in H/CLIPL or H/CLIPH corresponding */ - /* to the CIN value written will be cleared. */ + /* to the CN value written will be cleared. */ #define INTE 0x0c /* Interrupt enable register */ #define INTE_VIRTUALSB_MASK 0xc0000000 /* Virtual Soundblaster I/O port capture */ @@ -180,6 +180,7 @@ #define HCFG_CODECFORMAT_MASK 0x00030000 /* CODEC format */ /* Specific to Alice2, CA0102 */ + #define HCFG_CODECFORMAT_AC97_1 0x00000000 /* AC97 CODEC format -- Ver 1.03 */ #define HCFG_CODECFORMAT_AC97_2 0x00010000 /* AC97 CODEC format -- Ver 2.1 */ #define HCFG_AUTOMUTE_ASYNC 0x00008000 /* When set, the async sample rate convertors */ @@ -200,9 +201,8 @@ /* I2S format input */ /* Rest of HCFG 0x0000000f same as below. LOCKSOUNDCACHE etc. */ - - /* Older chips */ + #define HCFG_CODECFORMAT_AC97 0x00000000 /* AC97 CODEC format -- Primary Output */ #define HCFG_CODECFORMAT_I2S 0x00010000 /* I2S CODEC format -- Secondary (Rear) Output */ #define HCFG_GPINPUT0 0x00004000 /* External pin112 */ @@ -238,7 +238,7 @@ /* Should be set to 1 when the EMU10K1 is */ /* completely initialized. */ -//For Audigy, MPU port move to 0x70-0x74 ptr register +// On Audigy, the MPU port moved to the 0x70-0x74 ptr registers #define MUDATA 0x18 /* MPU401 data register (8 bits) */ @@ -277,12 +277,6 @@ #define A_IOCFG_REAR_JACK 0x8000 #define A_IOCFG_PHONES_JACK 0x0100 /* LiveDrive */ -/* outputs: - * for audigy2 platinum: 0xa00 - * for a2 platinum ex: 0x1c00 - * for a1 platinum: 0x0 - */ - #define TIMER 0x1a /* Timer terminal count register */ /* NOTE: After the rate is changed, a maximum */ /* of 1024 sample periods should be allowed */ @@ -323,7 +317,7 @@ /* 0x00000000 2-channel output. */ /* 0x00000200 8-channel output. */ /* 0x00000004 pauses stream/irq fail. */ - /* Rest of bits no nothing to sound output */ + /* Rest of bits do nothing to sound output */ /* bit 0: Enable P16V audio. * bit 1: Lock P16V record memory cache. * bit 2: Lock P16V playback memory cache. @@ -337,6 +331,7 @@ */ #define IPR3 0x38 /* Cdif interrupt pending register */ #define INTE3 0x3c /* Cdif interrupt enable register. */ + /************************************************************************************************/ /* PCI function 1 registers, address = + PCIBASE1 */ /************************************************************************************************/ @@ -355,11 +350,38 @@ #define JOYSTICK_BUTTONS 0x0f /* Joystick button data */ #define JOYSTICK_COMPARATOR 0xf0 /* Joystick comparator data */ - /********************************************************************************************************/ /* Emu10k1 pointer-offset register set, accessed through the PTR and DATA registers */ /********************************************************************************************************/ +// No official documentation was released for EMU10K1, but some info +// about playback can be extrapolated from the EMU8K documents: +// "AWE32/EMU8000 Programmer’s Guide" (emu8kpgm.pdf) - registers +// "AWE32 Developer's Information Pack" (adip301.pdf) - high-level view + +// The short version: +// - The engine has 64 playback channels, also called voices. The channels +// operate independently, except when paired for stereo (see below). +// - PCM samples are fetched into the cache; see description of CD0 below. +// - Samples are consumed at the rate CPF_CURRENTPITCH. +// - 8-bit samples are transformed upon use: cooked = (raw ^ 0x80) << 8 +// - 8 samples are read at CCR_READADDRESS:CPF_FRACADDRESS and interpolated +// according to CCCA_INTERPROM_*. With CCCA_INTERPROM_0 selected and a zero +// CPF_FRACADDRESS, this results in CCR_READADDRESS[3] being used verbatim. +// - The value is multiplied by CVCF_CURRENTVOL. +// - The value goes through a filter with cutoff CVCF_CURRENTFILTER; +// delay stages Z1 and Z2. +// - The value is added by so-called `sends` to 4 (EMU10K1) / 8 (EMU10K2) +// of the 16 (EMU10K1) / 64 (EMU10K2) FX bus accumulators via FXRT*, +// multiplied by a per-send amount (*_FXSENDAMOUNT_*). +// The scaling of the send amounts is exponential-ish. +// - The DSP has a go at FXBUS* and outputs the values to EXTOUT* or EMU32OUT*. +// - The pitch, volume, and filter cutoff can be modulated by two envelope +// engines and two low frequency oscillators. +// - To avoid abrupt changes to the parameters (which may cause audible +// distortion), the modulation engine sets the target registers, towards +// which the current registers "swerve" gradually. + #define CPF 0x00 /* Current pitch and fraction register */ #define CPF_CURRENTPITCH_MASK 0xffff0000 /* Current pitch (linear, 0x4000 == unity pitch shift) */ #define CPF_CURRENTPITCH 0x10100000 @@ -399,7 +421,7 @@ #define PSST_LOOPSTARTADDR_MASK 0x00ffffff /* Loop start address of the specified channel */ #define PSST_LOOPSTARTADDR 0x18000006 -#define DSL 0x07 /* Send D amount and loop start address register */ +#define DSL 0x07 /* Send D amount and loop end address register */ #define DSL_FXSENDAMOUNT_D_MASK 0xff000000 /* Linear level of channel output sent to FX send bus D */ #define DSL_FXSENDAMOUNT_D 0x08180007 @@ -424,25 +446,28 @@ #define CCCA_INTERPROM_6 0x0c000000 /* Select interpolation ROM 6 */ #define CCCA_INTERPROM_7 0x0e000000 /* Select interpolation ROM 7 */ #define CCCA_8BITSELECT 0x01000000 /* 1 = Sound memory for this channel uses 8-bit samples */ + /* 8-bit samples are unsigned, 16-bit ones signed */ #define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */ #define CCCA_CURRADDR 0x18000008 #define CCR 0x09 /* Cache control register */ #define CCR_CACHEINVALIDSIZE 0x07190009 -#define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */ +#define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples before the read address */ #define CCR_CACHELOOPFLAG 0x01000000 /* 1 = Cache has a loop service pending */ #define CCR_INTERLEAVEDSAMPLES 0x00800000 /* 1 = A cache service will fetch interleaved samples */ + /* Auto-set from CPF_STEREO_MASK */ #define CCR_WORDSIZEDSAMPLES 0x00400000 /* 1 = A cache service will fetch word sized samples */ + /* Auto-set from CCCA_8BITSELECT */ #define CCR_READADDRESS 0x06100009 -#define CCR_READADDRESS_MASK 0x003f0000 /* Location of cache just beyond current cache service */ +#define CCR_READADDRESS_MASK 0x003f0000 /* Next cached sample to play */ #define CCR_LOOPINVALSIZE 0x0000fe00 /* Number of invalid samples in cache prior to loop */ /* NOTE: This is valid only if CACHELOOPFLAG is set */ #define CCR_LOOPFLAG 0x00000100 /* Set for a single sample period when a loop occurs */ -#define CCR_CACHELOOPADDRHI 0x000000ff /* DSL_LOOPSTARTADDR's hi byte if CACHELOOPFLAG is set */ +#define CCR_CACHELOOPADDRHI 0x000000ff /* CLP_LOOPSTARTADDR's hi byte if CACHELOOPFLAG is set */ #define CLP 0x0a /* Cache loop register (valid if CCR_CACHELOOPFLAG = 1) */ /* NOTE: This register is normally not used */ -#define CLP_CACHELOOPADDR 0x0000ffff /* Cache loop address (DSL_LOOPSTARTADDR [0..15]) */ +#define CLP_CACHELOOPADDR 0x0000ffff /* Cache loop address low word */ #define FXRT 0x0b /* Effects send routing register */ /* NOTE: It is illegal to assign the same routing to */ @@ -454,7 +479,6 @@ #define A_HR 0x0b /* High Resolution. 24bit playback from host to DSP. */ #define MAPA 0x0c /* Cache map A */ - #define MAPB 0x0d /* Cache map B */ #define MAP_PTE_MASK0 0xfffff000 /* The 20 MSBs of the PTE indexed by the PTI */ @@ -463,7 +487,7 @@ #define MAP_PTE_MASK1 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */ #define MAP_PTI_MASK1 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */ -/* 0x0e, 0x0f: Not used */ +/* 0x0e, 0x0f: Internal state, at least on Audigy */ #define ENVVOL 0x10 /* Volume envelope register */ #define ENVVOL_MASK 0x0000ffff /* Current value of volume envelope state variable */ @@ -476,9 +500,9 @@ /* 0 = infinite, 1 = 10.9msec, ... 0x7f = 5.5msec */ #define DCYSUSV 0x12 /* Volume envelope sustain and decay register */ -#define DCYSUSV_PHASE1_MASK 0x00008000 /* 0 = Begin attack phase, 1 = begin release phase */ +#define DCYSUSV_PHASE1_MASK 0x00008000 /* 0 = Begin decay phase, 1 = begin release phase */ #define DCYSUSV_SUSTAINLEVEL_MASK 0x00007f00 /* 127 = full, 0 = off, 0.75dB increments */ -#define DCYSUSV_CHANNELENABLE_MASK 0x00000080 /* 1 = Inhibit envelope engine from writing values in */ +#define DCYSUSV_CHANNELENABLE_MASK 0x00000080 /* 0 = Inhibit envelope engine from writing values in */ /* this channel and from writing to pitch, filter and */ /* volume targets. */ #define DCYSUSV_DECAYTIME_MASK 0x0000007f /* Volume envelope decay time, log encoded */ @@ -499,7 +523,7 @@ /* 0 = infinite, 1 = 11msec, ... 0x7f = 5.5msec */ #define DCYSUSM 0x16 /* Modulation envelope decay and sustain register */ -#define DCYSUSM_PHASE1_MASK 0x00008000 /* 0 = Begin attack phase, 1 = begin release phase */ +#define DCYSUSM_PHASE1_MASK 0x00008000 /* 0 = Begin decay phase, 1 = begin release phase */ #define DCYSUSM_SUSTAINLEVEL_MASK 0x00007f00 /* 127 = full, 0 = off, 0.75dB increments */ #define DCYSUSM_DECAYTIME_MASK 0x0000007f /* Envelope decay time, log encoded */ /* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec */ @@ -521,7 +545,6 @@ #define IFATN_ATTENUATION_MASK 0x000000ff /* Initial attenuation in 0.375dB steps */ #define IFATN_ATTENUATION 0x08000019 - #define PEFE 0x1a /* Pitch envelope and filter envelope amount register */ #define PEFE_PITCHAMOUNT_MASK 0x0000ff00 /* Pitch envlope amount */ /* Signed 2's complement, +/- one octave peak extremes */ @@ -529,19 +552,19 @@ #define PEFE_FILTERAMOUNT_MASK 0x000000ff /* Filter envlope amount */ /* Signed 2's complement, +/- six octaves peak extremes */ #define PEFE_FILTERAMOUNT 0x0800001a + #define FMMOD 0x1b /* Vibrato/filter modulation from LFO register */ #define FMMOD_MODVIBRATO 0x0000ff00 /* Vibrato LFO modulation depth */ /* Signed 2's complement, +/- one octave extremes */ #define FMMOD_MOFILTER 0x000000ff /* Filter LFO modulation depth */ /* Signed 2's complement, +/- three octave extremes */ - #define TREMFRQ 0x1c /* Tremolo amount and modulation LFO frequency register */ #define TREMFRQ_DEPTH 0x0000ff00 /* Tremolo depth */ /* Signed 2's complement, with +/- 12dB extremes */ - #define TREMFRQ_FREQUENCY 0x000000ff /* Tremolo LFO frequency */ /* ??Hz steps, maximum of ?? Hz. */ + #define FM2FRQ2 0x1d /* Vibrato amount and vibrato LFO frequency register */ #define FM2FRQ2_DEPTH 0x0000ff00 /* Vibrato LFO vibrato depth */ /* Signed 2's complement, +/- one octave extremes */ @@ -645,7 +668,7 @@ #define FXBA 0x47 /* FX Buffer Address */ #define FXBA_MASK 0xfffff000 /* 20 bit base address */ -#define A_HWM 0x48 /* High PCI Water Mark - word access, defaults to 3f */ +#define A_HWM 0x48 /* High PCI Water Mark - word access, defaults to 3f */ #define MICBS 0x49 /* Microphone buffer size register */ @@ -653,9 +676,7 @@ #define FXBS 0x4b /* FX buffer size register */ -/* register: 0x4c..4f: ffff-ffff current amounts, per-channel */ - -/* The following mask values define the size of the ADC, MIX and FX buffers in bytes */ +/* The following mask values define the size of the ADC, MIC and FX buffers in bytes */ #define ADCBS_BUFSIZE_NONE 0x00000000 #define ADCBS_BUFSIZE_384 0x00000001 #define ADCBS_BUFSIZE_448 0x00000002 @@ -689,29 +710,21 @@ #define ADCBS_BUFSIZE_57344 0x0000001e #define ADCBS_BUFSIZE_65536 0x0000001f -/* Current Send B, A Amounts */ -#define A_CSBA 0x4c - -/* Current Send D, C Amounts */ -#define A_CSDC 0x4d - -/* Current Send F, E Amounts */ -#define A_CSFE 0x4e - -/* Current Send H, G Amounts */ -#define A_CSHG 0x4f - +#define A_CSBA 0x4c /* FX send B & A current amounts */ +#define A_CSDC 0x4d /* FX send D & C current amounts */ +#define A_CSFE 0x4e /* FX send F & E current amounts */ +#define A_CSHG 0x4f /* FX send H & G current amounts */ -#define CDCS 0x50 /* CD-ROM digital channel status register */ +// NOTE: 0x50,51,52: 64-bit (split over voices 0 & 1) +#define CDCS 0x50 /* CD-ROM digital channel status register */ -#define GPSCS 0x51 /* General Purpose SPDIF channel status register*/ +#define GPSCS 0x51 /* General Purpose SPDIF channel status register */ -#define DBG 0x52 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ +#define DBG 0x52 -/* S/PDIF Input C Channel Status */ -#define A_SPSC 0x52 +#define A_SPSC 0x52 /* S/PDIF Input C Channel Status */ -#define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ +#define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ #define A_DBG 0x53 #define A_DBG_SINGLE_STEP 0x00020000 /* Set to zero to start dsp */ @@ -720,7 +733,7 @@ #define A_DBG_SATURATION_OCCURED 0x20000000 #define A_DBG_SATURATION_ADDR 0x0ffc0000 -// NOTE: 0x54,55,56: 64-bit +// NOTE: 0x54,55,56: 64-bit (split over voices 0 & 1) #define SPCS0 0x54 /* SPDIF output Channel Status 0 register */ #define SPCS1 0x55 /* SPDIF output Channel Status 1 register */ @@ -753,17 +766,14 @@ /* 0x57: Not used */ -/* The 32-bit CLIx and SOLx registers all have one bit per channel control/status */ +/* The 32-bit CLIx and SOLEx registers all have one bit per channel control/status */ #define CLIEL 0x58 /* Channel loop interrupt enable low register */ - #define CLIEH 0x59 /* Channel loop interrupt enable high register */ #define CLIPL 0x5a /* Channel loop interrupt pending low register */ - #define CLIPH 0x5b /* Channel loop interrupt pending high register */ #define SOLEL 0x5c /* Stop on loop enable low register */ - #define SOLEH 0x5d /* Stop on loop enable high register */ #define SPBYPASS 0x5e /* SPDIF BYPASS mode register */ @@ -773,13 +783,12 @@ #define SPBYPASS_FORMAT 0x00000f00 /* If 1, SPDIF XX uses 24 bit, if 0 - 20 bit */ #define AC97SLOT 0x5f /* additional AC97 slots enable bits */ -#define AC97SLOT_REAR_RIGHT 0x01 /* Rear left */ -#define AC97SLOT_REAR_LEFT 0x02 /* Rear right */ -#define AC97SLOT_CNTR 0x10 /* Center enable */ -#define AC97SLOT_LFE 0x20 /* LFE enable */ +#define AC97SLOT_REAR_RIGHT 0x01 /* Rear left */ +#define AC97SLOT_REAR_LEFT 0x02 /* Rear right */ +#define AC97SLOT_CNTR 0x10 /* Center enable */ +#define AC97SLOT_LFE 0x20 /* LFE enable */ -/* PCB Revision */ -#define A_PCB 0x5f +#define A_PCB 0x5f /* PCB Revision */ // NOTE: 0x60,61,62: 64-bit #define CDSRCS 0x60 /* CD-ROM Sample Rate Converter status register */ @@ -819,27 +828,21 @@ #define FXIDX_MASK 0x0000ffff /* 16-bit value */ #define FXIDX_IDX 0x10000065 -/* The 32-bit HLIx and HLIPx registers all have one bit per channel control/status */ +/* The 32-bit HLIEx and HLIPx registers all have one bit per channel control/status */ #define HLIEL 0x66 /* Channel half loop interrupt enable low register */ - #define HLIEH 0x67 /* Channel half loop interrupt enable high register */ #define HLIPL 0x68 /* Channel half loop interrupt pending low register */ - #define HLIPH 0x69 /* Channel half loop interrupt pending high register */ -/* S/PDIF Host Record Index (bypasses SRC) */ -#define A_SPRI 0x6a -/* S/PDIF Host Record Address */ -#define A_SPRA 0x6b -/* S/PDIF Host Record Control */ -#define A_SPRC 0x6c -/* Delayed Interrupt Counter & Enable */ -#define A_DICE 0x6d -/* Tank Table Base */ -#define A_TTB 0x6e -/* Tank Delay Offset */ -#define A_TDOF 0x6f +#define A_SPRI 0x6a /* S/PDIF Host Record Index (bypasses SRC) */ +#define A_SPRA 0x6b /* S/PDIF Host Record Address */ +#define A_SPRC 0x6c /* S/PDIF Host Record Control */ + +#define A_DICE 0x6d /* Delayed Interrupt Counter & Enable */ + +#define A_TTB 0x6e /* Tank Table Base */ +#define A_TDOF 0x6f /* Tank Delay Offset */ /* This is the MPU port on the card (via the game port) */ #define A_MUDATA1 0x70 @@ -852,7 +855,7 @@ #define A_MUSTAT2 A_MUCMD2 /* The next two are the Audigy equivalent of FXWC */ -/* the Audigy can record any output (16bit, 48kHz, up to 64 channel simultaneously) */ +/* the Audigy can record any output (16bit, 48kHz, up to 64 channels simultaneously) */ /* Each bit selects a channel for recording */ #define A_FXWC1 0x74 /* Selects 0x7f-0x60 for FX recording */ #define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */ @@ -880,20 +883,13 @@ #define A_PCM_96000 0x00004000 #define A_PCM_44100 0x00008000 -/* I2S0 Sample Rate Tracker Status */ -#define A_SRT3 0x77 - -/* I2S1 Sample Rate Tracker Status */ -#define A_SRT4 0x78 - -/* I2S2 Sample Rate Tracker Status */ -#define A_SRT5 0x79 +#define A_SRT3 0x77 /* I2S0 Sample Rate Tracker Status */ +#define A_SRT4 0x78 /* I2S1 Sample Rate Tracker Status */ +#define A_SRT5 0x79 /* I2S2 Sample Rate Tracker Status */ /* - default to 0x01080000 on my audigy 2 ZS --rlrevell */ -/* Tank Table DMA Address */ -#define A_TTDA 0x7a -/* Tank Table DMA Data */ -#define A_TTDD 0x7b +#define A_TTDA 0x7a /* Tank Table DMA Address */ +#define A_TTDD 0x7b /* Tank Table DMA Data */ #define A_FXRT2 0x7c #define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */ @@ -906,6 +902,7 @@ #define A_FXSENDAMOUNT_F_MASK 0x00FF0000 #define A_FXSENDAMOUNT_G_MASK 0x0000FF00 #define A_FXSENDAMOUNT_H_MASK 0x000000FF + /* 0x7c, 0x7e "high bit is used for filtering" */ /* The send amounts for this one are the same as used with the emu10k1 */ @@ -956,15 +953,47 @@ #define A_HIWORD_RESULT_MASK 0x007ff000 #define A_HIWORD_OPA_MASK 0x000007ff + +/************************************************************************************************/ +/* E-MU Digital Audio System overview */ +/************************************************************************************************/ + +// - These cards use a regular PCI-attached Audigy chip (Alice2/Tina/Tina2); +// the PCIe variants simply put the Audigy chip behind a PCI bridge. +// - All physical PCM I/O is routed through an additional FPGA; the regular +// EXTIN/EXTOUT ports are unconnected. +// - The FPGA has a signal routing matrix, to connect each destination (output +// socket or capture channel) to a source (input socket or playback channel). +// - The FPGA is controlled via Audigy's GPIO port, while sample data is +// transmitted via proprietary EMU32 serial links. On first-generation +// E-MU 1010 cards, Audigy's I2S inputs are also used for sample data. +// - The Audio/Micro Dock is attached to Hana via EDI, a "network" link. +// - The Audigy chip operates in slave mode; the clock is supplied by the FPGA. +// Gen1 E-MU 1010 cards have two crystals (for 44.1 kHz and 48 kHz multiples), +// while the later cards use a single crystal and a PLL chip. +// - The whole card is switched to 2x/4x mode to achieve 88.2/96/176.4/192 kHz +// sample rates. Alice2/Tina keeps running at 44.1/48 kHz, but multiple channels +// are bundled. +// - The number of available EMU32/EDI channels is hit in 2x/4x mode, so the total +// number of usable inputs/outputs is limited, esp. with ADAT in use. +// - S/PDIF is unavailable in 4x mode (only over TOSLINK on newer 1010 cards) due +// to being unspecified at 176.4/192 kHz. Therefore, the Dock's S/PDIF channels +// can overlap with the Dock's ADC/DAC's high channels. +// - The code names are mentioned below and in the emu_chip_details table. + /************************************************************************************************/ -/* EMU1010m HANA FPGA registers */ +/* EMU1010 FPGA registers */ /************************************************************************************************/ + #define EMU_HANA_DESTHI 0x00 /* 0000xxx 3 bits Link Destination */ #define EMU_HANA_DESTLO 0x01 /* 00xxxxx 5 bits */ + #define EMU_HANA_SRCHI 0x02 /* 0000xxx 3 bits Link Source */ #define EMU_HANA_SRCLO 0x03 /* 00xxxxx 5 bits */ + #define EMU_HANA_DOCK_PWR 0x04 /* 000000x 1 bits Audio Dock power */ #define EMU_HANA_DOCK_PWR_ON 0x01 /* Audio Dock power on */ + #define EMU_HANA_WCLOCK 0x05 /* 0000xxx 3 bits Word Clock source select */ /* Must be written after power on to reset DLL */ /* One is unable to detect the Audio dock without this */ @@ -1073,21 +1102,19 @@ #define EMU_HANA_0202_DAC_PAD1 0x10 /* 14dB Attenuation on 0202 DAC 1. Left and Right */ /* 0x14 - 0x1f Unused R/W registers */ -#define EMU_HANA_IRQ_STATUS 0x20 /* 000xxxx 4 bits IRQ Status */ -#if 0 /* Already defined for reg 0x09 IRQ_ENABLE */ -#define EMU_HANA_IRQ_WCLK_CHANGED 0x01 -#define EMU_HANA_IRQ_ADAT 0x02 -#define EMU_HANA_IRQ_DOCK 0x04 -#define EMU_HANA_IRQ_DOCK_LOST 0x08 -#endif + +#define EMU_HANA_IRQ_STATUS 0x20 /* 00xxxxx 5 bits IRQ Status */ + /* Same bits as for EMU_HANA_IRQ_ENABLE */ + /* Reading the register resets it. */ #define EMU_HANA_OPTION_CARDS 0x21 /* 000xxxx 4 bits Presence of option cards */ -#define EMU_HANA_OPTION_HAMOA 0x01 /* HAMOA card present */ +#define EMU_HANA_OPTION_HAMOA 0x01 /* Hamoa (analog I/O) card present */ #define EMU_HANA_OPTION_SYNC 0x02 /* Sync card present */ -#define EMU_HANA_OPTION_DOCK_ONLINE 0x04 /* Audio Dock online and FPGA configured */ -#define EMU_HANA_OPTION_DOCK_OFFLINE 0x08 /* Audio Dock online and FPGA not configured */ +#define EMU_HANA_OPTION_DOCK_ONLINE 0x04 /* Audio/Micro dock present and FPGA configured */ +#define EMU_HANA_OPTION_DOCK_OFFLINE 0x08 /* Audio/Micro dock present and FPGA not configured */ -#define EMU_HANA_ID 0x22 /* 1010101 7 bits ID byte & 0x7f = 0x55 */ +#define EMU_HANA_ID 0x22 /* 1010101 7 bits ID byte & 0x7f = 0x55 with Alice2 */ + /* 0010101 5 bits ID byte & 0x1f = 0x15 with Tina/2 */ #define EMU_HANA_MAJOR_REV 0x23 /* 0000xxx 3 bit Hana FPGA Major rev */ #define EMU_HANA_MINOR_REV 0x24 /* 0000xxx 3 bit Hana FPGA Minor rev */ @@ -1110,31 +1137,31 @@ #define EMU_HANA2_WC_SPDIF_HI 0x2e /* 0xxxxxx 6 bit HANA2 SPDIF IN Word clock, upper 6 bits */ #define EMU_HANA2_WC_SPDIF_LO 0x2f /* 0xxxxxx 6 bit HANA2 SPDIF IN Word clock, lower 6 bits */ + /* 0x30 - 0x3f Unused Read only registers */ /************************************************************************************************/ -/* EMU1010m HANA Destinations */ +/* EMU1010 Audio Destinations */ /************************************************************************************************/ -/* Hana, original 1010,1212,1820 using Alice2 - * Destiniations for SRATEX = 1X rates: 44.1 kHz or 48 kHz +/* Hana, original 1010,1212m,1820[m] using Alice2 * 0x00, 0x00-0x0f: 16 EMU32 channels to Alice2 - * 0x01, 0x10-0x1f: 32 Elink channels to Audio Dock - * 0x01, 0x00: Dock DAC 1 Left - * 0x01, 0x04: Dock DAC 1 Right - * 0x01, 0x08: Dock DAC 2 Left - * 0x01, 0x0c: Dock DAC 2 Right - * 0x01, 0x10: Dock DAC 3 Left - * 0x01, 0x12: PHONES Left - * 0x01, 0x14: Dock DAC 3 Right - * 0x01, 0x16: PHONES Right - * 0x01, 0x18: Dock DAC 4 Left - * 0x01, 0x1a: S/PDIF Left - * 0x01, 0x1c: Dock DAC 4 Right - * 0x01, 0x1e: S/PDIF Right + * 0x01, 0x00-0x1f: 32 EDI channels to Audio Dock + * 0x00: Dock DAC 1 Left + * 0x04: Dock DAC 1 Right + * 0x08: Dock DAC 2 Left + * 0x0c: Dock DAC 2 Right + * 0x10: Dock DAC 3 Left + * 0x12: PHONES Left (n/a in 2x/4x mode; output mirrors DAC4 Left) + * 0x14: Dock DAC 3 Right + * 0x16: PHONES Right (n/a in 2x/4x mode; output mirrors DAC4 Right) + * 0x18: Dock DAC 4 Left + * 0x1a: S/PDIF Left + * 0x1c: Dock DAC 4 Right + * 0x1e: S/PDIF Right * 0x02, 0x00: Hana S/PDIF Left * 0x02, 0x01: Hana S/PDIF Right - * 0x03, 0x00: Hanoa DAC Left - * 0x03, 0x01: Hanoa DAC Right + * 0x03, 0x00: Hamoa DAC Left + * 0x03, 0x01: Hamoa DAC Right * 0x04, 0x00-0x07: Hana ADAT * 0x05, 0x00: I2S0 Left to Alice2 * 0x05, 0x01: I2S0 Right to Alice2 @@ -1146,40 +1173,29 @@ * Hana2 never released, but used Tina * Not needed. * - * Hana3, rev2 1010,1212,1616 using Tina - * Destinations for SRATEX = 1X rates: 44.1 kHz or 48 kHz + * Hana3, rev2 1010,1212m,1616[m] using Tina * 0x00, 0x00-0x0f: 16 EMU32A channels to Tina - * 0x01, 0x10-0x1f: 32 EDI channels to Micro Dock - * 0x01, 0x00: Dock DAC 1 Left - * 0x01, 0x04: Dock DAC 1 Right - * 0x01, 0x08: Dock DAC 2 Left - * 0x01, 0x0c: Dock DAC 2 Right - * 0x01, 0x10: Dock DAC 3 Left - * 0x01, 0x12: Dock S/PDIF Left - * 0x01, 0x14: Dock DAC 3 Right - * 0x01, 0x16: Dock S/PDIF Right - * 0x01, 0x18-0x1f: Dock ADAT 0-7 + * 0x01, 0x00-0x1f: 32 EDI channels to Micro Dock + * 0x00: Dock DAC 1 Left + * 0x04: Dock DAC 1 Right + * 0x08: Dock DAC 2 Left + * 0x0c: Dock DAC 2 Right + * 0x10: Dock DAC 3 Left + * 0x12: Dock S/PDIF Left + * 0x14: Dock DAC 3 Right + * 0x16: Dock S/PDIF Right + * 0x18-0x1f: Dock ADAT 0-7 * 0x02, 0x00: Hana3 S/PDIF Left * 0x02, 0x01: Hana3 S/PDIF Right - * 0x03, 0x00: Hanoa DAC Left - * 0x03, 0x01: Hanoa DAC Right + * 0x03, 0x00: Hamoa DAC Left + * 0x03, 0x01: Hamoa DAC Right * 0x04, 0x00-0x07: Hana3 ADAT 0-7 * 0x05, 0x00-0x0f: 16 EMU32B channels to Tina * 0x06-0x07: Not used * * HanaLite, rev1 0404 using Alice2 - * Destiniations for SRATEX = 1X rates: 44.1 kHz or 48 kHz - * 0x00, 0x00-0x0f: 16 EMU32 channels to Alice2 - * 0x01: Not used - * 0x02, 0x00: S/PDIF Left - * 0x02, 0x01: S/PDIF Right - * 0x03, 0x00: DAC Left - * 0x03, 0x01: DAC Right - * 0x04-0x07: Not used - * - * HanaLiteLite, rev2 0404 using Alice2 - * Destiniations for SRATEX = 1X rates: 44.1 kHz or 48 kHz - * 0x00, 0x00-0x0f: 16 EMU32 channels to Alice2 + * HanaLiteLite, rev2 0404 using Tina + * 0x00, 0x00-0x0f: 16 EMU32 channels to Alice2/Tina * 0x01: Not used * 0x02, 0x00: S/PDIF Left * 0x02, 0x01: S/PDIF Right @@ -1188,35 +1204,21 @@ * 0x04-0x07: Not used * * Mana, Cardbus 1616 using Tina2 - * Destinations for SRATEX = 1X rates: 44.1 kHz or 48 kHz * 0x00, 0x00-0x0f: 16 EMU32A channels to Tina2 - * 0x01, 0x10-0x1f: 32 EDI channels to Micro Dock - * 0x01, 0x00: Dock DAC 1 Left - * 0x01, 0x04: Dock DAC 1 Right - * 0x01, 0x08: Dock DAC 2 Left - * 0x01, 0x0c: Dock DAC 2 Right - * 0x01, 0x10: Dock DAC 3 Left - * 0x01, 0x12: Dock S/PDIF Left - * 0x01, 0x14: Dock DAC 3 Right - * 0x01, 0x16: Dock S/PDIF Right - * 0x01, 0x18-0x1f: Dock ADAT 0-7 + * 0x01, 0x00-0x1f: 32 EDI channels to Micro Dock + * (same as rev2 1010) * 0x02: Not used * 0x03, 0x00: Mana DAC Left * 0x03, 0x01: Mana DAC Right * 0x04, 0x00-0x0f: 16 EMU32B channels to Tina2 * 0x05-0x07: Not used - * - * */ + /* 32-bit destinations of signal in the Hana FPGA. Destinations are either - * physical outputs of Hana, or outputs going to Alice2 (audigy) for capture - * - 16 x EMU_DST_ALICE2_EMU32_X. - */ -/* EMU32 = 32-bit serial channel between Alice2 (audigy) and Hana (FPGA) */ -/* EMU_DST_ALICE2_EMU32_X - data channels from Hana to Alice2 used for capture. - * Which data is fed into a EMU_DST_ALICE2_EMU32_X channel in Hana depends on - * setup of mixer control for each destination - see emumixer.c - - * snd_emu1010_output_enum_ctls[], snd_emu1010_input_enum_ctls[] + * physical outputs of Hana, or outputs going to Alice2/Tina for capture - + * 16 x EMU_DST_ALICE2_EMU32_X (2x on rev2 boards). Which data is fed into + * a channel depends on the mixer control setting for each destination - see + * emumixer.c - snd_emu1010_output_enum_ctls[], snd_emu1010_input_enum_ctls[] */ #define EMU_DST_ALICE2_EMU32_0 0x000f /* 16 EMU32 channels to Alice2 +0 to +0xf */ #define EMU_DST_ALICE2_EMU32_1 0x0000 /* 16 EMU32 channels to Alice2 +0 to +0xf */ @@ -1286,6 +1288,7 @@ #define EMU_DST_HAMOA_DAC_RIGHT2 0x0303 /* Hamoa DAC Right, 2nd or 96kHz */ #define EMU_DST_HAMOA_DAC_RIGHT3 0x0305 /* Hamoa DAC Right, 3rd or 192kHz */ #define EMU_DST_HAMOA_DAC_RIGHT4 0x0307 /* Hamoa DAC Right, 4th or 192kHz */ +// In S/MUX mode, the samples of one channel are adjacent. #define EMU_DST_HANA_ADAT 0x0400 /* Hana ADAT 8 channel out +0 to +7 */ #define EMU_DST_ALICE_I2S0_LEFT 0x0500 /* Alice2 I2S0 Left */ #define EMU_DST_ALICE_I2S0_RIGHT 0x0501 /* Alice2 I2S0 Right */ @@ -1295,39 +1298,32 @@ #define EMU_DST_ALICE_I2S2_RIGHT 0x0701 /* Alice2 I2S2 Right */ /* Additional destinations for 1616(M)/Microdock */ -/* Microdock S/PDIF OUT Left, 1st or 48kHz only */ -#define EMU_DST_MDOCK_SPDIF_LEFT1 0x0112 -/* Microdock S/PDIF OUT Left, 2nd or 96kHz */ -#define EMU_DST_MDOCK_SPDIF_LEFT2 0x0113 -/* Microdock S/PDIF OUT Right, 1st or 48kHz only */ -#define EMU_DST_MDOCK_SPDIF_RIGHT1 0x0116 -/* Microdock S/PDIF OUT Right, 2nd or 96kHz */ -#define EMU_DST_MDOCK_SPDIF_RIGHT2 0x0117 -/* Microdock S/PDIF ADAT 8 channel out +8 to +f */ -#define EMU_DST_MDOCK_ADAT 0x0118 - -/* Headphone jack on 1010 cardbus? 44.1/48kHz only? */ -#define EMU_DST_MANA_DAC_LEFT 0x0300 -/* Headphone jack on 1010 cardbus? 44.1/48kHz only? */ -#define EMU_DST_MANA_DAC_RIGHT 0x0301 + +#define EMU_DST_MDOCK_SPDIF_LEFT1 0x0112 /* Microdock S/PDIF OUT Left, 1st or 48kHz only */ +#define EMU_DST_MDOCK_SPDIF_LEFT2 0x0113 /* Microdock S/PDIF OUT Left, 2nd or 96kHz */ +#define EMU_DST_MDOCK_SPDIF_RIGHT1 0x0116 /* Microdock S/PDIF OUT Right, 1st or 48kHz only */ +#define EMU_DST_MDOCK_SPDIF_RIGHT2 0x0117 /* Microdock S/PDIF OUT Right, 2nd or 96kHz */ +#define EMU_DST_MDOCK_ADAT 0x0118 /* Microdock S/PDIF ADAT 8 channel out +8 to +f */ + +#define EMU_DST_MANA_DAC_LEFT 0x0300 /* Headphone jack on 1010 cardbus? 44.1/48kHz only? */ +#define EMU_DST_MANA_DAC_RIGHT 0x0301 /* Headphone jack on 1010 cardbus? 44.1/48kHz only? */ /************************************************************************************************/ -/* EMU1010m HANA Sources */ +/* EMU1010 Audio Sources */ /************************************************************************************************/ -/* Hana, original 1010,1212,1820 using Alice2 - * Sources SRATEX = 1X rates: 44.1 kHz or 48 kHz - * 0x00,0x00-0x1f: Silence - * 0x01, 0x10-0x1f: 32 Elink channels from Audio Dock - * 0x01, 0x00: Dock Mic A - * 0x01, 0x04: Dock Mic B - * 0x01, 0x08: Dock ADC 1 Left - * 0x01, 0x0c: Dock ADC 1 Right - * 0x01, 0x10: Dock ADC 2 Left - * 0x01, 0x14: Dock ADC 2 Right - * 0x01, 0x18: Dock ADC 3 Left - * 0x01, 0x1c: Dock ADC 3 Right - * 0x02, 0x00: Hana ADC Left - * 0x02, 0x01: Hana ADC Right +/* Hana, original 1010,1212m,1820[m] using Alice2 + * 0x00, 0x00-0x1f: Silence + * 0x01, 0x00-0x1f: 32 EDI channels from Audio Dock + * 0x00: Dock Mic A + * 0x04: Dock Mic B + * 0x08: Dock ADC 1 Left + * 0x0c: Dock ADC 1 Right + * 0x10: Dock ADC 2 Left + * 0x14: Dock ADC 2 Right + * 0x18: Dock ADC 3 Left + * 0x1c: Dock ADC 3 Right + * 0x02, 0x00: Hamoa ADC Left + * 0x02, 0x01: Hamoa ADC Right * 0x03, 0x00-0x0f: 16 inputs from Alice2 Emu32A output * 0x03, 0x10-0x1f: 16 inputs from Alice2 Emu32B output * 0x04, 0x00-0x07: Hana ADAT @@ -1338,23 +1334,20 @@ * Hana2 never released, but used Tina * Not needed. * - * Hana3, rev2 1010,1212,1616 using Tina - * Sources SRATEX = 1X rates: 44.1 kHz or 48 kHz - * 0x00,0x00-0x1f: Silence - * 0x01, 0x10-0x1f: 32 Elink channels from Audio Dock - * 0x01, 0x00: Dock Mic A - * 0x01, 0x04: Dock Mic B - * 0x01, 0x08: Dock ADC 1 Left - * 0x01, 0x0c: Dock ADC 1 Right - * 0x01, 0x10: Dock ADC 2 Left - * 0x01, 0x12: Dock S/PDIF Left - * 0x01, 0x14: Dock ADC 2 Right - * 0x01, 0x16: Dock S/PDIF Right - * 0x01, 0x18-0x1f: Dock ADAT 0-7 - * 0x01, 0x18: Dock ADC 3 Left - * 0x01, 0x1c: Dock ADC 3 Right - * 0x02, 0x00: Hanoa ADC Left - * 0x02, 0x01: Hanoa ADC Right + * Hana3, rev2 1010,1212m,1616[m] using Tina + * 0x00, 0x00-0x1f: Silence + * 0x01, 0x00-0x1f: 32 EDI channels from Micro Dock + * 0x00: Dock Mic A + * 0x04: Dock Mic B + * 0x08: Dock ADC 1 Left + * 0x0c: Dock ADC 1 Right + * 0x10: Dock ADC 2 Left + * 0x12: Dock S/PDIF Left + * 0x14: Dock ADC 2 Right + * 0x16: Dock S/PDIF Right + * 0x18-0x1f: Dock ADAT 0-7 + * 0x02, 0x00: Hamoa ADC Left + * 0x02, 0x01: Hamoa ADC Right * 0x03, 0x00-0x0f: 16 inputs from Tina Emu32A output * 0x03, 0x10-0x1f: 16 inputs from Tina Emu32B output * 0x04, 0x00-0x07: Hana3 ADAT @@ -1363,58 +1356,32 @@ * 0x06-0x07: Not used * * HanaLite, rev1 0404 using Alice2 - * Sources SRATEX = 1X rates: 44.1 kHz or 48 kHz - * 0x00,0x00-0x1f: Silence + * HanaLiteLite, rev2 0404 using Tina + * 0x00, 0x00-0x1f: Silence * 0x01: Not used * 0x02, 0x00: ADC Left * 0x02, 0x01: ADC Right - * 0x03, 0x00-0x0f: 16 inputs from Alice2 Emu32A output - * 0x03, 0x10-0x1f: 16 inputs from Alice2 Emu32B output - * 0x04: Not used - * 0x05, 0x00: S/PDIF Left - * 0x05, 0x01: S/PDIF Right - * 0x06-0x07: Not used - * - * HanaLiteLite, rev2 0404 using Alice2 - * Sources SRATEX = 1X rates: 44.1 kHz or 48 kHz - * 0x00,0x00-0x1f: Silence - * 0x01: Not used - * 0x02, 0x00: ADC Left - * 0x02, 0x01: ADC Right - * 0x03, 0x00-0x0f: 16 inputs from Alice2 Emu32A output - * 0x03, 0x10-0x1f: 16 inputs from Alice2 Emu32B output + * 0x03, 0x00-0x0f: 16 inputs from Alice2/Tina Emu32A output + * 0x03, 0x10-0x1f: 16 inputs from Alice2/Tina Emu32B output * 0x04: Not used * 0x05, 0x00: S/PDIF Left * 0x05, 0x01: S/PDIF Right * 0x06-0x07: Not used * * Mana, Cardbus 1616 using Tina2 - * Sources SRATEX = 1X rates: 44.1 kHz or 48 kHz - * 0x00,0x00-0x1f: Silence - * 0x01, 0x10-0x1f: 32 Elink channels from Audio Dock - * 0x01, 0x00: Dock Mic A - * 0x01, 0x04: Dock Mic B - * 0x01, 0x08: Dock ADC 1 Left - * 0x01, 0x0c: Dock ADC 1 Right - * 0x01, 0x10: Dock ADC 2 Left - * 0x01, 0x12: Dock S/PDIF Left - * 0x01, 0x14: Dock ADC 2 Right - * 0x01, 0x16: Dock S/PDIF Right - * 0x01, 0x18-0x1f: Dock ADAT 0-7 - * 0x01, 0x18: Dock ADC 3 Left - * 0x01, 0x1c: Dock ADC 3 Right + * 0x00, 0x00-0x1f: Silence + * 0x01, 0x00-0x1f: 32 EDI channels from Micro Dock + * (same as rev2 1010) * 0x02: Not used - * 0x03, 0x00-0x0f: 16 inputs from Tina Emu32A output - * 0x03, 0x10-0x1f: 16 inputs from Tina Emu32B output + * 0x03, 0x00-0x0f: 16 inputs from Tina2 Emu32A output + * 0x03, 0x10-0x1f: 16 inputs from Tina2 Emu32B output * 0x04-0x07: Not used - * */ /* 32-bit sources of signal in the Hana FPGA. The sources are routed to - * destinations using mixer control for each destination - see emumixer.c - * Sources are either physical inputs of FPGA, - * or outputs from Alice (audigy) - 16 x EMU_SRC_ALICE_EMU32A + - * 16 x EMU_SRC_ALICE_EMU32B + * destinations using a mixer control for each destination - see emumixer.c. + * Sources are either physical inputs of Hana, or inputs from Alice2/Tina - + * 16 x EMU_SRC_ALICE_EMU32A + 16 x EMU_SRC_ALICE_EMU32B. */ #define EMU_SRC_SILENCE 0x0000 /* Silence */ #define EMU_SRC_DOCK_MIC_A1 0x0100 /* Audio Dock Mic A, 1st or 48kHz only */ @@ -1459,6 +1426,7 @@ #define EMU_SRC_HAMOA_ADC_RIGHT4 0x0207 /* Hamoa ADC Right, 4th or 192kHz */ #define EMU_SRC_ALICE_EMU32A 0x0300 /* Alice2 EMU32a 16 outputs. +0 to +0xf */ #define EMU_SRC_ALICE_EMU32B 0x0310 /* Alice2 EMU32b 16 outputs. +0 to +0xf */ +// In S/MUX mode, the samples of one channel are adjacent. #define EMU_SRC_HANA_ADAT 0x0400 /* Hana ADAT 8 channel in +0 to +7 */ #define EMU_SRC_HANA_SPDIF_LEFT1 0x0500 /* Hana SPDIF Left, 1st or 48kHz only */ #define EMU_SRC_HANA_SPDIF_LEFT2 0x0502 /* Hana SPDIF Left, 2nd or 96kHz */ @@ -1466,16 +1434,12 @@ #define EMU_SRC_HANA_SPDIF_RIGHT2 0x0503 /* Hana SPDIF Right, 2nd or 96kHz */ /* Additional inputs for 1616(M)/Microdock */ -/* Microdock S/PDIF Left, 1st or 48kHz only */ -#define EMU_SRC_MDOCK_SPDIF_LEFT1 0x0112 -/* Microdock S/PDIF Left, 2nd or 96kHz */ -#define EMU_SRC_MDOCK_SPDIF_LEFT2 0x0113 -/* Microdock S/PDIF Right, 1st or 48kHz only */ -#define EMU_SRC_MDOCK_SPDIF_RIGHT1 0x0116 -/* Microdock S/PDIF Right, 2nd or 96kHz */ -#define EMU_SRC_MDOCK_SPDIF_RIGHT2 0x0117 -/* Microdock ADAT 8 channel in +8 to +f */ -#define EMU_SRC_MDOCK_ADAT 0x0118 + +#define EMU_SRC_MDOCK_SPDIF_LEFT1 0x0112 /* Microdock S/PDIF Left, 1st or 48kHz only */ +#define EMU_SRC_MDOCK_SPDIF_LEFT2 0x0113 /* Microdock S/PDIF Left, 2nd or 96kHz */ +#define EMU_SRC_MDOCK_SPDIF_RIGHT1 0x0116 /* Microdock S/PDIF Right, 1st or 48kHz only */ +#define EMU_SRC_MDOCK_SPDIF_RIGHT2 0x0117 /* Microdock S/PDIF Right, 2nd or 96kHz */ +#define EMU_SRC_MDOCK_ADAT 0x0118 /* Microdock ADAT 8 channel in +8 to +f */ /* 0x600 and 0x700 no used */ @@ -1642,14 +1606,26 @@ enum { EMU_MODEL_EMU0404, }; +// Chip-o-logy: +// - All SB Live! cards use EMU10K1 chips +// - All SB Audigy cards use CA* chips, termed "emu10k2" by the driver +// - Original Audigy uses CA0100 "Alice" +// - Audigy 2 uses CA0102/CA10200 "Alice2" +// - Has an interface for CA0151 (P16V) "Alice3" +// - Audigy 2 Value uses CA0108/CA10300 "Tina" +// - Approximately a CA0102 with an on-chip CA0151 (P17V) +// - Audigy 2 ZS NB uses CA0109 "Tina2" +// - Cardbus version of CA0108 struct snd_emu_chip_details { u32 vendor; u32 device; u32 subsystem; unsigned char revision; unsigned char emu10k1_chip; /* Original SB Live. Not SB Live 24bit. */ + /* Redundant with emu10k2_chip being unset. */ unsigned char emu10k2_chip; /* Audigy 1 or Audigy 2. */ unsigned char ca0102_chip; /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */ + /* Redundant with ca0108_chip being unset. */ unsigned char ca0108_chip; /* Audigy 2 Value */ unsigned char ca_cardbus_chip; /* Audigy 2 ZS Notebook */ unsigned char ca0151_chip; /* P16V */ @@ -1659,8 +1635,8 @@ struct snd_emu_chip_details { unsigned char ac97_chip; /* Has an AC97 chip: 1 = mandatory, 2 = optional */ unsigned char ecard; /* APS EEPROM */ unsigned char emu_model; /* EMU model type */ - unsigned char spi_dac; /* SPI interface for DAC */ - unsigned char i2c_adc; /* I2C interface for ADC */ + unsigned char spi_dac; /* SPI interface for DAC; requires ca0108_chip */ + unsigned char i2c_adc; /* I2C interface for ADC; requires ca0108_chip */ unsigned char adc_1361t; /* Use Philips 1361T ADC */ unsigned char invert_shared_spdif; /* analog/digital switch inverted */ const char *driver; @@ -1734,9 +1710,9 @@ struct snd_emu10k1 { void *synth; int (*get_synth_voice)(struct snd_emu10k1 *emu); - spinlock_t reg_lock; - spinlock_t emu_lock; - spinlock_t voice_lock; + spinlock_t reg_lock; // high-level driver lock + spinlock_t emu_lock; // low-level i/o lock + spinlock_t voice_lock; // voice allocator lock spinlock_t spi_lock; /* serialises access to spi port */ spinlock_t i2c_lock; /* serialises access to i2c port */ diff --git a/include/uapi/sound/emu10k1.h b/include/uapi/sound/emu10k1.h index c2414bd5aecd..33e5228f5d8c 100644 --- a/include/uapi/sound/emu10k1.h +++ b/include/uapi/sound/emu10k1.h @@ -111,6 +111,9 @@ #define CC_REG_NONZERO C_00000100 /* FX buses */ +// These are arbitrary mappings; our DSP code simply expects +// the config files to route the channels this way. +// The numbers are documented in {audigy,sb-live}-mixer.rst. #define FXBUS_PCM_LEFT 0x00 #define FXBUS_PCM_RIGHT 0x01 #define FXBUS_PCM_LEFT_REAR 0x02 diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 672af4b9597b..b8163f26004a 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -68,17 +68,6 @@ static const struct pci_device_id snd_emu10k1_ids[] = { { 0, } }; -/* - * Audigy 2 Value notes: - * A_IOCFG Input (GPIO) - * 0x400 = Front analog jack plugged in. (Green socket) - * 0x1000 = Read analog jack plugged in. (Black socket) - * 0x2000 = Center/LFE analog jack plugged in. (Orange socket) - * A_IOCFG Output (GPIO) - * 0x60 = Sound out of front Left. - * Win sets it to 0xXX61 - */ - MODULE_DEVICE_TABLE(pci, snd_emu10k1_ids); static int snd_card_emu10k1_probe(struct pci_dev *pci, diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c37df604d470..39b63c4ca1df 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -162,6 +162,8 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir) outl(0, emu->port + INTE); snd_emu10k1_ptr_write(emu, CLIEL, 0, 0); snd_emu10k1_ptr_write(emu, CLIEH, 0, 0); + + /* disable stop on loop end */ snd_emu10k1_ptr_write(emu, SOLEL, 0, 0); snd_emu10k1_ptr_write(emu, SOLEH, 0, 0); @@ -660,13 +662,14 @@ static int snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, return -EIO; /* The FPGA is a Xilinx Spartan IIE XC2S50E */ + /* On E-MU 0404b it is a Xilinx Spartan III XC3S50 */ /* GPIO7 -> FPGA PGMN * GPIO6 -> FPGA CCLK * GPIO5 -> FPGA DIN * FPGA CONFIG OFF -> FPGA PGMN */ spin_lock_irqsave(&emu->emu_lock, flags); - outw(0x00, emu->port + A_GPIO); /* Set PGMN low for 1uS. */ + outw(0x00, emu->port + A_GPIO); /* Set PGMN low for 100uS. */ write_post = inw(emu->port + A_GPIO); udelay(100); outw(0x80, emu->port + A_GPIO); /* Leave bit 7 set during netlist setup. */ @@ -782,7 +785,7 @@ static void emu1010_firmware_work(struct work_struct *work) } else if (!reg && emu->emu1010.last_reg) { /* Audio Dock removed */ dev_info(emu->card->dev, "emu1010: Audio Dock detached\n"); - /* Unmute all */ + /* The hardware auto-mutes all, so we unmute again */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); } @@ -794,29 +797,6 @@ static void emu1010_firmware_work(struct work_struct *work) } /* - * EMU-1010 - details found out from this driver, official MS Win drivers, - * testing the card: - * - * Audigy2 (aka Alice2): - * --------------------- - * * communication over PCI - * * conversion of 32-bit data coming over EMU32 links from HANA FPGA - * to 2 x 16-bit, using internal DSP instructions - * * slave mode, clock supplied by HANA - * * linked to HANA using: - * 32 x 32-bit serial EMU32 output channels - * 16 x EMU32 input channels - * (?) x I2S I/O channels (?) - * - * FPGA (aka HANA): - * --------------- - * * provides all (?) physical inputs and outputs of the card - * (ADC, DAC, SPDIF I/O, ADAT I/O, etc.) - * * provides clock signal for the card and Alice2 - * * two crystals - for 44.1kHz and 48kHz multiples - * * provides internal routing of signal sources to signal destinations - * * inputs/outputs to Alice2 - see above - * * Current status of the driver: * ---------------------------- * * only 44.1/48kHz supported (the MS Win driver supports up to 192 kHz) @@ -884,11 +864,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg); /* Optical -> ADAT I/O */ - /* 0 : SPDIF - * 1 : ADAT - */ emu->emu1010.optical_in = 1; /* IN_ADAT */ - emu->emu1010.optical_out = 1; /* IN_ADAT */ + emu->emu1010.optical_out = 1; /* OUT_ADAT */ tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); @@ -1279,6 +1256,15 @@ static const struct snd_emu_chip_details emu_chip_details[] = { * AC97: STAC9750 * CA0151: None */ + /* + * A_IOCFG Input (GPIO) + * 0x400 = Front analog jack plugged in. (Green socket) + * 0x1000 = Rear analog jack plugged in. (Black socket) + * 0x2000 = Center/LFE analog jack plugged in. (Orange socket) + * A_IOCFG Output (GPIO) + * 0x60 = Sound out of front Left. + * Win sets it to 0xXX61 + */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, .driver = "Audigy2", .name = "SB Audigy 2 Value [SB0400]", .id = "Audigy2", @@ -1327,6 +1313,9 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .spi_dac = 1, .i2c_adc = 1, .spk71 = 1} , + /* This is MAEM8950 "Mana" */ + /* Attach MicroDock[M] to make it an E-MU 1616[m]. */ + /* Does NOT support sync daughter card (obviously). */ /* Tested by James@superbug.co.uk 4th Nov 2007. */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102, .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", @@ -1337,7 +1326,10 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .spk71 = 1 , .emu_model = EMU_MODEL_EMU1616}, /* Tested by James@superbug.co.uk 4th Nov 2007. */ - /* This is MAEM8960, 0202 is MAEM 8980 */ + /* This is MAEM8960 "Hana3", 0202 is MAEM8980 */ + /* Attach 0202 daughter card to make it an E-MU 1212m, OR a + * MicroDock[M] to make it an E-MU 1616[m]. */ + /* Does NOT support sync daughter card. */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102, .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM8960]", .id = "EMU1010", @@ -1347,6 +1339,11 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 new revision */ /* Tested by Maxim Kachur 17th Oct 2012. */ /* This is MAEM8986, 0202 is MAEM8980 */ + /* Attach 0202 daughter card to make it an E-MU 1212m, OR a + * MicroDockM to make it an E-MU 1616m. The non-m + * version was never sold with this card, but should + * still work. */ + /* Does NOT support sync daughter card. */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40071102, .driver = "Audigy2", .name = "E-mu 1010 PCIe [MAEM8986]", .id = "EMU1010", @@ -1355,7 +1352,10 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .spk71 = 1, .emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 PCIe */ /* Tested by James@superbug.co.uk 8th July 2005. */ - /* This is MAEM8810, 0202 is MAEM8820 */ + /* This is MAEM8810 "Hana", 0202 is MAEM8820 "Hamoa" */ + /* Attach 0202 daughter card to make it an E-MU 1212m, OR an + * AudioDock[M] to make it an E-MU 1820[m]. */ + /* Supports sync daughter card. */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, .driver = "Audigy2", .name = "E-mu 1010 [MAEM8810]", .id = "EMU1010", @@ -1363,7 +1363,9 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .ca0102_chip = 1, .spk71 = 1, .emu_model = EMU_MODEL_EMU1010}, /* EMU 1010 old revision */ - /* EMU0404b */ + /* This is MAEM8852 "HanaLiteLite" */ + /* Supports sync daughter card. */ + /* Tested by oswald.buddenhagen@gmx.de Mar 2023. */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40021102, .driver = "Audigy2", .name = "E-mu 0404b PCI [MAEM8852]", .id = "EMU0404", @@ -1371,6 +1373,8 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .ca0108_chip = 1, .spk71 = 1, .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 new revision */ + /* This is MAEM8850 "HanaLite" */ + /* Supports sync daughter card. */ /* Tested by James@superbug.co.uk 20-3-2007. */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40021102, .driver = "Audigy2", .name = "E-mu 0404 [MAEM8850]", @@ -1380,6 +1384,7 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .spk71 = 1, .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */ /* EMU0404 PCIe */ + /* Does NOT support sync daughter card. */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40051102, .driver = "Audigy2", .name = "E-mu 0404 PCIe [MAEM8984]", .id = "EMU0404", @@ -1387,7 +1392,6 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .ca0108_chip = 1, .spk71 = 1, .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 PCIe ver_03 */ - /* Note that all E-mu cards require kernel 2.6 or newer. */ {.vendor = 0x1102, .device = 0x0008, .driver = "Audigy2", .name = "SB Audigy 2 Value [Unknown]", .id = "Audigy2", @@ -1468,6 +1472,8 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .spdif_bug = 1, .adc_1361t = 1, /* 24 bit capture instead of 16bit */ .ac97_chip = 1} , + /* Audigy 2 Platinum EX */ + /* Win driver sets A_IOCFG output to 0x1c00 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, .driver = "Audigy2", .name = "Audigy 2 Platinum EX [SB0280]", .id = "Audigy2", @@ -1488,6 +1494,8 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .spdif_bug = 1, .invert_shared_spdif = 1, /* digital/analog switch swapped */ .ac97_chip = 1} , + /* Audigy 2 Platinum */ + /* Win driver sets A_IOCFG output to 0xa00 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102, .driver = "Audigy2", .name = "SB Audigy 2 Platinum [SB0240P]", .id = "Audigy2", @@ -1593,6 +1601,9 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , + /* SB Live! Platinum */ + /* Win driver sets A_IOCFG output to 0 */ + /* Tested by Jonathan Dowland Apr 2023. */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102, .driver = "EMU10K1", .name = "SB Live! Platinum [CT4760P]", .id = "Live", diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 6a51aed59238..510b776f856d 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -1187,8 +1187,8 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl } /* - * Used for emu1010 - conversion from 32-bit capture inputs from HANA - * to 2 x 16-bit registers in audigy - their values are read via DMA. + * Used for emu1010 - conversion from 32-bit capture inputs from the FPGA + * to 2 x 16-bit registers in Audigy - their values are read via DMA. * Conversion is performed by Audigy DSP instructions of FX8010. */ static int snd_emu10k1_audigy_dsp_convert_32_to_2x16( @@ -1330,8 +1330,9 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) #define A_ADD_VOLUME_IN(var,vol,input) \ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) - /* emu1212 DSP 0 and DSP 1 Capture */ if (emu->card_capabilities->emu_model) { + /* EMU1010 DSP 0 and DSP 1 Capture */ + // The 24 MSB hold the actual value. We implicitly discard the 16 LSB. if (emu->card_capabilities->ca0108_chip) { /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */ A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001); @@ -1636,8 +1637,11 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) #endif if (emu->card_capabilities->emu_model) { + /* Capture 16 channels of S32_LE sound. */ if (emu->card_capabilities->ca0108_chip) { dev_info(emu->card->dev, "EMU2 inputs on\n"); + /* Note that the Tina[2] DSPs have 16 more EMU32 inputs which we don't use. */ + for (z = 0; z < 0x10; z++) { snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, @@ -1646,7 +1650,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) } } else { dev_info(emu->card->dev, "EMU inputs on\n"); - /* Capture 16 (originally 8) channels of S32_LE sound */ + /* Note that the Alice2 DSPs have 6 I2S inputs which we don't use. */ /* dev_dbg(emu->card->dev, "emufx.c: gpr=0x%x, tmp=0x%x\n", diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 754d91050af2..3d2ed5e0a59d 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -346,7 +346,7 @@ static const unsigned int emu1616_output_dst[] = { }; /* - * Data destinations - HANA outputs going to Alice2 (audigy) for + * Data destinations - FPGA outputs going to Alice2 (Audigy) for * capture (EMU32 + I2S links) * Each destination has an enum mixer control to choose a data source */ @@ -367,6 +367,7 @@ static const unsigned int emu1010_input_dst[] = { EMU_DST_ALICE2_EMU32_D, EMU_DST_ALICE2_EMU32_E, EMU_DST_ALICE2_EMU32_F, + /* These exist only on rev1 EMU1010 cards. */ EMU_DST_ALICE_I2S0_LEFT, EMU_DST_ALICE_I2S0_RIGHT, EMU_DST_ALICE_I2S1_LEFT, @@ -708,7 +709,7 @@ static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, /* 44100 */ /* Mute all */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); - /* Default fallback clock 48kHz */ + /* Default fallback clock 44.1kHz */ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); /* Word Clock source, Internal 44.1kHz x1 */ snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index c2749ad59e10..a91ea0f863d3 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -326,7 +326,6 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, } else snd_emu10k1_ptr_write(emu, FXRT, voice, snd_emu10k1_compose_send_routing(send_routing)); - /* Stop CA */ /* Assumption that PT is already 0 so no harm overwriting */ snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); @@ -480,9 +479,6 @@ static int snd_emu10k1_efx_playback_prepare(struct snd_pcm_substream *substream) start_addr = epcm->start_addr; end_addr = epcm->start_addr + snd_pcm_lib_buffer_bytes(substream); - /* - * the kX driver leaves some space between voices - */ channel_size = ( end_addr - start_addr ) / NUM_EFX_PLAYBACK; snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra, @@ -1218,9 +1214,7 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) runtime->hw.rate_min = runtime->hw.rate_max = 48000; spin_lock_irq(&emu->reg_lock); if (emu->card_capabilities->emu_model) { - /* Nb. of channels has been increased to 16 */ /* TODO - * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 @@ -1231,13 +1225,14 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) * Need to add mixer control to fix sample rate * * There are 32 mono channels of 16bits each. - * 24bit Audio uses 2x channels over 16bit - * 96kHz uses 2x channels over 48kHz - * 192kHz uses 4x channels over 48kHz - * So, for 48kHz 24bit, one has 16 channels - * for 96kHz 24bit, one has 8 channels - * for 192kHz 24bit, one has 4 channels - * + * 24bit Audio uses 2x channels over 16bit, + * 96kHz uses 2x channels over 48kHz, + * 192kHz uses 4x channels over 48kHz. + * So, for 48kHz 24bit, one has 16 channels, + * for 96kHz 24bit, one has 8 channels, + * for 192kHz 24bit, one has 4 channels. + * 1010rev2 and 1616(m) cards have double that, + * but we don't exceed 16 channels anyway. */ #if 1 switch (emu->emu1010.internal_clock) { @@ -1459,11 +1454,12 @@ static int snd_emu10k1_pcm_efx_voices_mask_put(struct snd_kcontrol *kcontrol, st nval[idx / 32] |= 1 << (idx % 32); bits++; } - + + // Check that the number of requested channels is a power of two + // not bigger than the number of available channels. for (idx = 0; idx < nefxb; idx++) if (1 << idx == bits) break; - if (idx >= nefxb) return -EINVAL; diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 42b06f2e5552..c60573f14ea8 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -314,7 +314,6 @@ void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenu unsigned int val; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(CLIEH << 16, emu->port + PTR); val = inl(emu->port + DATA); @@ -334,7 +333,6 @@ void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicen unsigned int val; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(CLIEH << 16, emu->port + PTR); val = inl(emu->port + DATA); @@ -353,7 +351,6 @@ void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum) unsigned long flags; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(CLIPH << 16, emu->port + PTR); voicenum = 1 << (voicenum - 32); @@ -371,7 +368,6 @@ void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned i unsigned int val; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(HLIEH << 16, emu->port + PTR); val = inl(emu->port + DATA); @@ -391,7 +387,6 @@ void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned unsigned int val; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(HLIEH << 16, emu->port + PTR); val = inl(emu->port + DATA); @@ -410,7 +405,6 @@ void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int unsigned long flags; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(HLIPH << 16, emu->port + PTR); voicenum = 1 << (voicenum - 32); @@ -428,7 +422,6 @@ void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voice unsigned int sol; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(SOLEH << 16, emu->port + PTR); sol = inl(emu->port + DATA); @@ -448,7 +441,6 @@ void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voi unsigned int sol; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(SOLEH << 16, emu->port + PTR); sol = inl(emu->port + DATA); diff --git a/sound/pci/emu10k1/p16v.h b/sound/pci/emu10k1/p16v.h index 3cdafa311617..9d429ad1feff 100644 --- a/sound/pci/emu10k1/p16v.h +++ b/sound/pci/emu10k1/p16v.h @@ -64,7 +64,7 @@ */ /********************************************************************************************************/ -/* Audigy2 P16V pointer-offset register set, accessed through the PTR2 and DATA2 registers */ +/* Audigy2 P16V pointer-offset register set, accessed through the PTR2 and DATA2 registers */ /********************************************************************************************************/ /* The sample rate of the SPDIF outputs is set by modifying a register in the EMU10K2 PTR register A_SPDIF_SAMPLERATE. diff --git a/sound/pci/emu10k1/p17v.h b/sound/pci/emu10k1/p17v.h index 3a6568346fad..d4ada1c430c8 100644 --- a/sound/pci/emu10k1/p17v.h +++ b/sound/pci/emu10k1/p17v.h @@ -6,8 +6,8 @@ */ /******************************************************************************/ -/* Audigy2Value Tina (P17V) pointer-offset register set, - * accessed through the PTR20 and DATA24 registers */ +/* Audigy2Value Tina (P17V) pointer-offset register set, */ +/* accessed through the PTR2 and DATA2 registers */ /******************************************************************************/ /* 00 - 07: Not used */ -- cgit v1.2.3-58-ga151 From 2696d5a3b0ec9f242b0220999933b6c78502b1b2 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 22 Apr 2023 18:10:20 +0200 Subject: ALSA: emu10k1: fixup DSP defines Firstly, fix the distribution between public and private headers. Otherwise, some of the already public macros wouldn't actually work, and the SNDRV_EMU10K1_IOCTL_DBG_READ result for Audigy would be useless. Secondly, add condition code registers for Audigy. These are just aliases for selected constant registers, and thus are generation- specific. At least A_CC_REG_ZERO is actually correct ... Finally, shuffle around some defines to more logical places while at it, and fix up some more comments. Signed-off-by: Oswald Buddenhagen Link: https://lore.kernel.org/r/20230422161021.1143903-7-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 46 ++------------ include/uapi/sound/emu10k1.h | 144 ++++++++++++++++++++++++++++--------------- 2 files changed, 99 insertions(+), 91 deletions(-) (limited to 'include/uapi') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 0d288cc618c1..5958cae819fd 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -704,18 +704,15 @@ #define GPSCS 0x51 /* General Purpose SPDIF channel status register */ +// Corresponding EMU10K1_DBG_* constants are in the public header #define DBG 0x52 #define A_SPSC 0x52 /* S/PDIF Input C Channel Status */ #define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */ -#define A_DBG 0x53 -#define A_DBG_SINGLE_STEP 0x00020000 /* Set to zero to start dsp */ -#define A_DBG_ZC 0x40000000 /* zero tram counter */ -#define A_DBG_STEP_ADDR 0x000003ff -#define A_DBG_SATURATION_OCCURED 0x20000000 -#define A_DBG_SATURATION_ADDR 0x0ffc0000 +// Corresponding A_DBG_* constants are in the public header +#define A_DBG 0x53 // NOTE: 0x54,55,56: 64-bit (split over voices 0 & 1) #define SPCS0 0x54 /* SPDIF output Channel Status 0 register */ @@ -908,45 +905,14 @@ #define A_FXRT_CHANNELD 0x3f000000 /* 0x7f: Not used */ -/* Each FX general purpose register is 32 bits in length, all bits are used */ -#define FXGPREGBASE 0x100 /* FX general purpose registers base */ -#define A_FXGPREGBASE 0x400 /* Audigy GPRs, 0x400 to 0x5ff */ - -#define A_TANKMEMCTLREGBASE 0x100 /* Tank memory control registers base - only for Audigy */ -#define A_TANKMEMCTLREG_MASK 0x1f /* only 5 bits used - only for Audigy */ - -/* Tank audio data is logarithmically compressed down to 16 bits before writing to TRAM and is */ -/* decompressed back to 20 bits on a read. There are a total of 160 locations, the last 32 */ -/* locations are for external TRAM. */ -#define TANKMEMDATAREGBASE 0x200 /* Tank memory data registers base */ -#define TANKMEMDATAREG_MASK 0x000fffff /* 20 bit tank audio data field */ - -/* Combined address field and memory opcode or flag field. 160 locations, last 32 are external */ -#define TANKMEMADDRREGBASE 0x300 /* Tank memory address registers base */ -#define TANKMEMADDRREG_ADDR_MASK 0x000fffff /* 20 bit tank address field */ -#define TANKMEMADDRREG_CLEAR 0x00800000 /* Clear tank memory */ -#define TANKMEMADDRREG_ALIGN 0x00400000 /* Align read or write relative to tank access */ -#define TANKMEMADDRREG_WRITE 0x00200000 /* Write to tank memory */ -#define TANKMEMADDRREG_READ 0x00100000 /* Read from tank memory */ -#define MICROCODEBASE 0x400 /* Microcode data base address */ +/* The public header defines the GPR and TRAM base addresses that + * are valid for _both_ CPU and DSP addressing. */ /* Each DSP microcode instruction is mapped into 2 doublewords */ /* NOTE: When writing, always write the LO doubleword first. Reads can be in either order. */ -#define LOWORD_OPX_MASK 0x000ffc00 /* Instruction operand X */ -#define LOWORD_OPY_MASK 0x000003ff /* Instruction operand Y */ -#define HIWORD_OPCODE_MASK 0x00f00000 /* Instruction opcode */ -#define HIWORD_RESULT_MASK 0x000ffc00 /* Instruction result */ -#define HIWORD_OPA_MASK 0x000003ff /* Instruction operand A */ - - -/* Audigy Soundcard have a different instruction format */ +#define MICROCODEBASE 0x400 /* Microcode data base address */ #define A_MICROCODEBASE 0x600 -#define A_LOWORD_OPY_MASK 0x000007ff -#define A_LOWORD_OPX_MASK 0x007ff000 -#define A_HIWORD_OPCODE_MASK 0x0f000000 -#define A_HIWORD_RESULT_MASK 0x007ff000 -#define A_HIWORD_OPA_MASK 0x000007ff /************************************************************************************************/ diff --git a/include/uapi/sound/emu10k1.h b/include/uapi/sound/emu10k1.h index 33e5228f5d8c..c8e131d6da00 100644 --- a/include/uapi/sound/emu10k1.h +++ b/include/uapi/sound/emu10k1.h @@ -43,6 +43,19 @@ #define iINTERP 0x0e /* R = A + (X * (Y - A) >> 31) ; saturation */ #define iSKIP 0x0f /* R = A (cc_reg), X (count), Y (cc_test) */ +#define LOWORD_OPX_MASK 0x000ffc00 /* Instruction operand X */ +#define LOWORD_OPY_MASK 0x000003ff /* Instruction operand Y */ +#define HIWORD_OPCODE_MASK 0x00f00000 /* Instruction opcode */ +#define HIWORD_RESULT_MASK 0x000ffc00 /* Instruction result */ +#define HIWORD_OPA_MASK 0x000003ff /* Instruction operand A */ + +/* Audigy Soundcards have a different instruction format */ +#define A_LOWORD_OPX_MASK 0x007ff000 +#define A_LOWORD_OPY_MASK 0x000007ff +#define A_HIWORD_OPCODE_MASK 0x0f000000 +#define A_HIWORD_RESULT_MASK 0x007ff000 +#define A_HIWORD_OPA_MASK 0x000007ff + /* GPRs */ #define FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x0f */ #define EXTIN(x) (0x10 + (x)) /* x = 0x00 - 0x0f */ @@ -50,6 +63,16 @@ #define FXBUS2(x) (0x30 + (x)) /* x = 0x00 - 0x0f copies of fx buses for capture -> FXWC high 16 bits */ /* NB: 0x31 and 0x32 are shared with Center/LFE on SB live 5.1 */ +#define A_FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x3f FX buses */ +#define A_EXTIN(x) (0x40 + (x)) /* x = 0x00 - 0x0f physical ins */ +#define A_P16VIN(x) (0x50 + (x)) /* x = 0x00 - 0x0f p16v ins (A2 only) "EMU32 inputs" */ +#define A_EXTOUT(x) (0x60 + (x)) /* x = 0x00 - 0x1f physical outs -> A_FXWC1 0x79-7f unknown */ +#define A_FXBUS2(x) (0x80 + (x)) /* x = 0x00 - 0x1f extra outs used for EFX capture -> A_FXWC2 */ +#define A_EMU32OUTH(x) (0xa0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_10 - _1F" */ +#define A_EMU32OUTL(x) (0xb0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_01 - _0F" */ +#define A3_EMU32IN(x) (0x160 + (x)) /* x = 0x00 - 0x1f "EMU32_IN_00 - _1F" - Only when .device = 0x0008 */ +#define A3_EMU32OUT(x) (0x1E0 + (x)) /* x = 0x00 - 0x1f "EMU32_OUT_00 - _1F" - Only when .device = 0x0008 */ + #define C_00000000 0x40 #define C_00000001 0x41 #define C_00000002 0x42 @@ -78,12 +101,66 @@ #define GPR_NOISE1 0x59 /* noise source */ #define GPR_IRQ 0x5a /* IRQ register */ #define GPR_DBAC 0x5b /* TRAM Delay Base Address Counter */ + +/* Audigy constants */ +#define A_C_00000000 0xc0 +#define A_C_00000001 0xc1 +#define A_C_00000002 0xc2 +#define A_C_00000003 0xc3 +#define A_C_00000004 0xc4 +#define A_C_00000008 0xc5 +#define A_C_00000010 0xc6 +#define A_C_00000020 0xc7 +#define A_C_00000100 0xc8 +#define A_C_00010000 0xc9 +#define A_C_00000800 0xca +#define A_C_10000000 0xcb +#define A_C_20000000 0xcc +#define A_C_40000000 0xcd +#define A_C_80000000 0xce +#define A_C_7fffffff 0xcf +#define A_C_ffffffff 0xd0 +#define A_C_fffffffe 0xd1 +#define A_C_c0000000 0xd2 +#define A_C_4f1bbcdc 0xd3 +#define A_C_5a7ef9db 0xd4 +#define A_C_00100000 0xd5 +#define A_GPR_ACCU 0xd6 /* ACCUM, accumulator */ +#define A_GPR_COND 0xd7 /* CCR, condition register */ +#define A_GPR_NOISE0 0xd8 /* noise source */ +#define A_GPR_NOISE1 0xd9 /* noise source */ +#define A_GPR_IRQ 0xda /* IRQ register */ +#define A_GPR_DBAC 0xdb /* TRAM Delay Base Address Counter - internal */ +#define A_GPR_DBACE 0xde /* TRAM Delay Base Address Counter - external */ + +/* Each FX general purpose register is 32 bits in length, all bits are used */ +#define FXGPREGBASE 0x100 /* FX general purpose registers base */ +#define A_FXGPREGBASE 0x400 /* Audigy GPRs, 0x400 to 0x5ff */ + +#define A_TANKMEMCTLREGBASE 0x100 /* Tank memory control registers base - only for Audigy */ +#define A_TANKMEMCTLREG_MASK 0x1f /* only 5 bits used - only for Audigy */ + +/* Tank audio data is logarithmically compressed down to 16 bits before writing to TRAM and is */ +/* decompressed back to 20 bits on a read. There are a total of 160 locations, the last 32 */ +/* locations are for external TRAM. */ +#define TANKMEMDATAREGBASE 0x200 /* Tank memory data registers base */ +#define TANKMEMDATAREG_MASK 0x000fffff /* 20 bit tank audio data field */ + +/* Combined address field and memory opcode or flag field. 160 locations, last 32 are external */ +#define TANKMEMADDRREGBASE 0x300 /* Tank memory address registers base */ +#define TANKMEMADDRREG_ADDR_MASK 0x000fffff /* 20 bit tank address field */ +#define TANKMEMADDRREG_CLEAR 0x00800000 /* Clear tank memory */ +#define TANKMEMADDRREG_ALIGN 0x00400000 /* Align read or write relative to tank access */ +#define TANKMEMADDRREG_WRITE 0x00200000 /* Write to tank memory */ +#define TANKMEMADDRREG_READ 0x00100000 /* Read from tank memory */ + #define GPR(x) (FXGPREGBASE + (x)) /* free GPRs: x = 0x00 - 0xff */ #define ITRAM_DATA(x) (TANKMEMDATAREGBASE + 0x00 + (x)) /* x = 0x00 - 0x7f */ #define ETRAM_DATA(x) (TANKMEMDATAREGBASE + 0x80 + (x)) /* x = 0x00 - 0x1f */ #define ITRAM_ADDR(x) (TANKMEMADDRREGBASE + 0x00 + (x)) /* x = 0x00 - 0x7f */ #define ETRAM_ADDR(x) (TANKMEMADDRREGBASE + 0x80 + (x)) /* x = 0x00 - 0x1f */ +#define A_GPR(x) (A_FXGPREGBASE + (x)) #define A_ITRAM_DATA(x) (TANKMEMDATAREGBASE + 0x00 + (x)) /* x = 0x00 - 0xbf */ #define A_ETRAM_DATA(x) (TANKMEMDATAREGBASE + 0xc0 + (x)) /* x = 0x00 - 0x3f */ #define A_ITRAM_ADDR(x) (TANKMEMADDRREGBASE + 0x00 + (x)) /* x = 0x00 - 0xbf */ @@ -91,17 +168,6 @@ #define A_ITRAM_CTL(x) (A_TANKMEMCTLREGBASE + 0x00 + (x)) /* x = 0x00 - 0xbf */ #define A_ETRAM_CTL(x) (A_TANKMEMCTLREGBASE + 0xc0 + (x)) /* x = 0x00 - 0x3f */ -#define A_FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x3f FX buses */ -#define A_EXTIN(x) (0x40 + (x)) /* x = 0x00 - 0x0f physical ins */ -#define A_P16VIN(x) (0x50 + (x)) /* x = 0x00 - 0x0f p16v ins (A2 only) "EMU32 inputs" */ -#define A_EXTOUT(x) (0x60 + (x)) /* x = 0x00 - 0x1f physical outs -> A_FXWC1 0x79-7f unknown */ -#define A_FXBUS2(x) (0x80 + (x)) /* x = 0x00 - 0x1f extra outs used for EFX capture -> A_FXWC2 */ -#define A_EMU32OUTH(x) (0xa0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_10 - _1F" - ??? */ -#define A_EMU32OUTL(x) (0xb0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_1 - _F" - ??? */ -#define A3_EMU32IN(x) (0x160 + (x)) /* x = 0x00 - 0x3f "EMU32_IN_00 - _3F" - Only when .device = 0x0008 */ -#define A3_EMU32OUT(x) (0x1E0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_00 - _3F" - Only when .device = 0x0008 */ -#define A_GPR(x) (A_FXGPREGBASE + (x)) - /* cc_reg constants */ #define CC_REG_NORMALIZED C_00000001 #define CC_REG_BORROW C_00000002 @@ -110,6 +176,13 @@ #define CC_REG_SATURATE C_00000010 #define CC_REG_NONZERO C_00000100 +#define A_CC_REG_NORMALIZED A_C_00000001 +#define A_CC_REG_BORROW A_C_00000002 +#define A_CC_REG_MINUS A_C_00000004 +#define A_CC_REG_ZERO A_C_00000008 +#define A_CC_REG_SATURATE A_C_00000010 +#define A_CC_REG_NONZERO A_C_00000100 + /* FX buses */ // These are arbitrary mappings; our DSP code simply expects // the config files to route the channels this way. @@ -203,38 +276,7 @@ #define A_EXTOUT_ADC_CAP_R 0x17 /* right */ #define A_EXTOUT_MIC_CAP 0x18 /* Mic capture buffer */ -/* Audigy constants */ -#define A_C_00000000 0xc0 -#define A_C_00000001 0xc1 -#define A_C_00000002 0xc2 -#define A_C_00000003 0xc3 -#define A_C_00000004 0xc4 -#define A_C_00000008 0xc5 -#define A_C_00000010 0xc6 -#define A_C_00000020 0xc7 -#define A_C_00000100 0xc8 -#define A_C_00010000 0xc9 -#define A_C_00000800 0xca -#define A_C_10000000 0xcb -#define A_C_20000000 0xcc -#define A_C_40000000 0xcd -#define A_C_80000000 0xce -#define A_C_7fffffff 0xcf -#define A_C_ffffffff 0xd0 -#define A_C_fffffffe 0xd1 -#define A_C_c0000000 0xd2 -#define A_C_4f1bbcdc 0xd3 -#define A_C_5a7ef9db 0xd4 -#define A_C_00100000 0xd5 -#define A_GPR_ACCU 0xd6 /* ACCUM, accumulator */ -#define A_GPR_COND 0xd7 /* CCR, condition register */ -#define A_GPR_NOISE0 0xd8 /* noise source */ -#define A_GPR_NOISE1 0xd9 /* noise source */ -#define A_GPR_IRQ 0xda /* IRQ register */ -#define A_GPR_DBAC 0xdb /* TRAM Delay Base Address Counter - internal */ -#define A_GPR_DBACE 0xde /* TRAM Delay Base Address Counter - external */ - -/* definitions for debug register */ +/* Definitions for debug register. Note that these are for emu10k1 ONLY. */ #define EMU10K1_DBG_ZC 0x80000000 /* zero tram counter */ #define EMU10K1_DBG_SATURATION_OCCURED 0x02000000 /* saturation control */ #define EMU10K1_DBG_SATURATION_ADDR 0x01ff0000 /* saturation address */ @@ -243,14 +285,14 @@ #define EMU10K1_DBG_CONDITION_CODE 0x00003e00 /* condition code */ #define EMU10K1_DBG_SINGLE_STEP_ADDR 0x000001ff /* single step address */ -/* tank memory address line */ -#ifndef __KERNEL__ -#define TANKMEMADDRREG_ADDR_MASK 0x000fffff /* 20 bit tank address field */ -#define TANKMEMADDRREG_CLEAR 0x00800000 /* Clear tank memory */ -#define TANKMEMADDRREG_ALIGN 0x00400000 /* Align read or write relative to tank access */ -#define TANKMEMADDRREG_WRITE 0x00200000 /* Write to tank memory */ -#define TANKMEMADDRREG_READ 0x00100000 /* Read from tank memory */ -#endif +/* Definitions for emu10k2 debug register. */ +#define A_DBG_ZC 0x40000000 /* zero tram counter */ +#define A_DBG_SATURATION_OCCURED 0x20000000 +#define A_DBG_SATURATION_ADDR 0x0ffc0000 +#define A_DBG_SINGLE_STEP 0x00020000 /* Set to zero to start dsp */ +#define A_DBG_STEP 0x00010000 +#define A_DBG_CONDITION_CODE 0x0000f800 +#define A_DBG_STEP_ADDR 0x000003ff struct snd_emu10k1_fx8010_info { unsigned int internal_tram_size; /* in samples */ -- cgit v1.2.3-58-ga151