[Sound-open-firmware] [PATCH] dai: config: Use a generic structure for DAI configuration
Liam Girdwood
liam.r.girdwood at linux.intel.com
Mon Aug 21 21:34:36 CEST 2017
Use a generic structure containing common DAI settings for configuration.
This structure also contains a tail of DAI specific data that can also
be used by DAI drivers.
Signed-off-by: Liam Girdwood <liam.r.girdwood at linux.intel.com>
---
src/audio/dai.c | 31 +++++++--------
src/drivers/ssp.c | 52 ++++++++++++-------------
src/include/reef/audio/component.h | 7 ++--
src/include/reef/dai.h | 16 ++------
src/include/reef/ipc.h | 2 +-
src/include/reef/ssp.h | 1 +
src/include/uapi/ipc.h | 77 ++++++++++++++++++++++++--------------
src/ipc/intel-ipc.c | 31 ++++++---------
src/ipc/ipc.c | 2 +-
9 files changed, 110 insertions(+), 109 deletions(-)
diff --git a/src/audio/dai.c b/src/audio/dai.c
index 4464398..c89103d 100644
--- a/src/audio/dai.c
+++ b/src/audio/dai.c
@@ -544,26 +544,23 @@ static int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn)
return 0;
}
-static int dai_config(struct comp_dev *dev, struct dai_config *dai_config)
+static int dai_config(struct comp_dev *dev, struct sof_ipc_dai_config *config)
{
- struct dai_data *dd = comp_get_drvdata(dev);
-
- switch (dai_config->type) {
- case DAI_TYPE_INTEL_SSP:
- switch (dai_config->ssp->frame_width) {
- case 16:
- dd->sample_width = 2;
- break;
- case 17 ... 32:
- dd->sample_width = 4;
- break;
- default:
- trace_dai_error("eft");
- return -EINVAL;
- }
+ /* calc frame bytes */
+ switch (config->sample_valid_bits) {
+ case 16:
+ dev->frame_bytes = 2 * config->num_slots;
+ break;
+ case 17 ... 32:
+ dev->frame_bytes = 4 * config->num_slots;
break;
default:
- dd->sample_width = 2;
+ break;
+ }
+
+ if (dev->frame_bytes == 0) {
+ trace_dai_error("de1");
+ return -EINVAL;
}
return 0;
diff --git a/src/drivers/ssp.c b/src/drivers/ssp.c
index 2146f83..1a1000a 100644
--- a/src/drivers/ssp.c
+++ b/src/drivers/ssp.c
@@ -65,12 +65,12 @@ static int ssp_context_restore(struct dai *dai)
}
/* Digital Audio interface formatting */
-static inline int ssp_set_config(struct dai *dai, struct dai_config *dai_config)
+static inline int ssp_set_config(struct dai *dai,
+ struct sof_ipc_dai_config *config)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);
- struct sof_ipc_dai_ssp_params *params = &ssp->params;
uint32_t sscr0, sscr1, sspsp, sfifott, mdiv, bdiv;
- uint32_t stop_size, phy_frame_size, data_size;
+ uint32_t stop_size, data_size;
int ret = 0;
spin_lock(&ssp->lock);
@@ -88,10 +88,15 @@ static inline int ssp_set_config(struct dai *dai, struct dai_config *dai_config)
sscr0 = 0;
sscr1 = 0;
sspsp = 0;
- ssp->params = *dai_config->ssp;
+
+ ssp->config = *config;
+ ssp->params = config->ssp[0];
+
+ /* TODO: allow topology to define SSP clock type */
+ config->ssp[0].clk_id = SSP_CLK_EXT;
/* clock masters */
- switch (params->format & SOF_DAI_FMT_MASTER_MASK) {
+ switch (config->format & SOF_DAI_FMT_MASTER_MASK) {
case SOF_DAI_FMT_CBM_CFM:
sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
break;
@@ -112,7 +117,7 @@ static inline int ssp_set_config(struct dai *dai, struct dai_config *dai_config)
}
/* clock signal polarity */
- switch (params->format & SOF_DAI_FMT_INV_MASK) {
+ switch (config->format & SOF_DAI_FMT_INV_MASK) {
case SOF_DAI_FMT_NB_NF:
break;
case SOF_DAI_FMT_NB_IF:
@@ -129,7 +134,7 @@ static inline int ssp_set_config(struct dai *dai, struct dai_config *dai_config)
}
/* clock source */
- switch (params->clk_id) {
+ switch (config->ssp[0].clk_id) {
case SSP_CLK_AUDIO:
sscr0 |= SSCR0_ACS;
break;
@@ -148,14 +153,14 @@ static inline int ssp_set_config(struct dai *dai, struct dai_config *dai_config)
}
/* BCLK is generated from MCLK - must be divisable */
- if (params->mclk % params->bclk) {
+ if (config->mclk % config->bclk) {
trace_ssp_error("ec1");
ret = -EINVAL;
goto out;
}
/* divisor must be within SCR range */
- mdiv = (params->mclk / params->bclk)- 1;
+ mdiv = (config->mclk / config->bclk)- 1;
if (mdiv > (SSCR0_SCR_MASK >> 8)) {
trace_ssp_error("ec2");
ret = -EINVAL;
@@ -166,23 +171,22 @@ static inline int ssp_set_config(struct dai *dai, struct dai_config *dai_config)
sscr0 |= SSCR0_SCR(mdiv);
/* calc frame width based on BCLK and rate - must be divisable */
- if (params->bclk % params->fclk) {
+ if (config->bclk % config->fclk) {
trace_ssp_error("ec3");
ret = -EINVAL;
goto out;
}
/* must be enouch BCLKs for data */
- bdiv = params->bclk / params->fclk;
- if (bdiv < params->frame_width * params->num_slots) {
+ bdiv = config->bclk / config->fclk;
+ if (bdiv < config->sample_container_bits * config->num_slots) {
trace_ssp_error("ec4");
ret = -EINVAL;
goto out;
}
- /* physical frame size must be <= 38 */
- phy_frame_size = bdiv / params->num_slots;
- if (phy_frame_size > 38) {
+ /* sample_container_bits must be <= 38 for SSP */
+ if (config->sample_container_bits > 38) {
trace_ssp_error("ec5");
ret = -EINVAL;
goto out;
@@ -190,14 +194,14 @@ static inline int ssp_set_config(struct dai *dai, struct dai_config *dai_config)
trace_value(mdiv);
trace_value(bdiv);
- trace_value(phy_frame_size);
/* format */
- switch (params->format & SOF_DAI_FMT_FORMAT_MASK) {
+ switch (config->format & SOF_DAI_FMT_FORMAT_MASK) {
case SOF_DAI_FMT_I2S:
/* calculate dummy stop size and include dummy start */
- stop_size = phy_frame_size - params->frame_width - 1;
+ stop_size = config->sample_container_bits -
+ (config->sample_valid_bits) - 1;
trace_value(stop_size);
if (stop_size > 3) {
trace_ssp_error("ec6");
@@ -207,9 +211,9 @@ static inline int ssp_set_config(struct dai *dai, struct dai_config *dai_config)
sscr0 |= SSCR0_PSP;
sscr1 |= SSCR1_TRAIL;
- sspsp |= SSPSP_SFRMWDTH(phy_frame_size);
+ sspsp |= SSPSP_SFRMWDTH(config->sample_container_bits);
/* subtract 1 for I2S start delay */
- sspsp |= SSPSP_SFRMDLY((phy_frame_size - 1) * 2);
+ sspsp |= SSPSP_SFRMDLY((config->sample_container_bits - 1) * 2);
sspsp |= SSPSP_DMYSTRT(1);
sspsp |= SSPSP_DMYSTOP(stop_size);
break;
@@ -225,16 +229,12 @@ static inline int ssp_set_config(struct dai *dai, struct dai_config *dai_config)
}
/* sample data size on SSP FIFO */
- switch (params->frame_width) {
+ switch (config->sample_valid_bits) {
case 16: /* 2 * 16bit packed into 32bit FIFO */
- case 24: /* 1 * 24bit in 32bit FIFO (8 MSBs not used) */
- case 32: /* 1 * 32bit packed into 32bit FIFO */
data_size = 32;
break;
default:
- trace_ssp_error("ec7");
- ret = -EINVAL;
- goto out;
+ data_size = config->sample_valid_bits;
}
if (data_size > 16)
diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h
index a74395c..260fbda 100644
--- a/src/include/reef/audio/component.h
+++ b/src/include/reef/audio/component.h
@@ -122,7 +122,8 @@ struct comp_ops {
int (*preload)(struct comp_dev *dev);
/* set component audio stream paramters */
- int (*dai_config)(struct comp_dev *dev, struct dai_config *dai_config);
+ int (*dai_config)(struct comp_dev *dev,
+ struct sof_ipc_dai_config *dai_config);
/* used to pass standard and bespoke commands (with data) to component */
int (*cmd)(struct comp_dev *dev, int cmd, void *data);
@@ -261,10 +262,10 @@ static inline int comp_reset(struct comp_dev *dev)
/* DAI configuration - only mandatory for DAI components */
static inline int comp_dai_config(struct comp_dev *dev,
- struct dai_config *dai_config)
+ struct sof_ipc_dai_config *config)
{
if (dev->drv->ops.dai_config)
- return dev->drv->ops.dai_config(dev, dai_config);
+ return dev->drv->ops.dai_config(dev, config);
return 0;
}
diff --git a/src/include/reef/dai.h b/src/include/reef/dai.h
index 258b016..75eabce 100644
--- a/src/include/reef/dai.h
+++ b/src/include/reef/dai.h
@@ -58,7 +58,7 @@ struct dai;
/* DAI operations - all optional */
struct dai_ops {
- int (*set_config)(struct dai *dai, struct dai_config *dai_config);
+ int (*set_config)(struct dai *dai, struct sof_ipc_dai_config *config);
int (*trigger)(struct dai *dai, int cmd, int direction);
int (*pm_context_restore)(struct dai *dai);
int (*pm_context_store)(struct dai *dai);
@@ -78,15 +78,6 @@ enum dai_type {
DAI_TYPE_INTEL_DMIC,
};
-/* DAI runtime hardware configuration */
-struct dai_config {
- enum dai_type type;
- union {
- struct sof_ipc_dai_ssp_params *ssp;
- struct sof_ipc_dai_hda_params *hda;
- struct sof_ipc_dai_dmic_params *dmic;
- };
-};
struct dai_plat_fifo_data {
uint32_t offset;
@@ -126,9 +117,10 @@ struct dai *dai_get(uint32_t type, uint32_t index);
dai->plat_data.fifo[direction].offset
/* Digital Audio interface formatting */
-static inline int dai_set_config(struct dai *dai, struct dai_config *dai_config)
+static inline int dai_set_config(struct dai *dai,
+ struct sof_ipc_dai_config *config)
{
- return dai->ops->set_config(dai, dai_config);
+ return dai->ops->set_config(dai, config);
}
/* Digital Audio interface formatting */
diff --git a/src/include/reef/ipc.h b/src/include/reef/ipc.h
index 96f2924..253f4f4 100644
--- a/src/include/reef/ipc.h
+++ b/src/include/reef/ipc.h
@@ -157,6 +157,6 @@ struct ipc_comp_dev *ipc_get_comp(struct ipc *ipc, uint32_t id);
/*
* Configure all DAI components attached to DAI.
*/
-int ipc_comp_dai_config(struct ipc *ipc, struct dai_config *config);
+int ipc_comp_dai_config(struct ipc *ipc, struct sof_ipc_dai_config *config);
#endif
diff --git a/src/include/reef/ssp.h b/src/include/reef/ssp.h
index 77d7b2e..7e557ed 100644
--- a/src/include/reef/ssp.h
+++ b/src/include/reef/ssp.h
@@ -153,6 +153,7 @@ struct ssp_pdata {
spinlock_t lock;
uint32_t state[2]; /* SSP_STATE_ for each direction */
completion_t drain_complete;
+ struct sof_ipc_dai_config config;
struct sof_ipc_dai_ssp_params params;
};
diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h
index 19ee898..ddca551 100644
--- a/src/include/uapi/ipc.h
+++ b/src/include/uapi/ipc.h
@@ -99,10 +99,8 @@
#define SOF_IPC_COMP_GET_SRC SOF_CMD_TYPE(0x007)
/* DAI messages */
-#define SOF_IPC_COMP_SSP_CONFIG SOF_CMD_TYPE(0x000)
-#define SOF_IPC_COMP_HDA_CONFIG SOF_CMD_TYPE(0x001)
-#define SOF_IPC_COMP_DMIC_CONFIG SOF_CMD_TYPE(0x002)
-#define SOF_IPC_COMP_LOOPBACK SOF_CMD_TYPE(0x003)
+#define SOF_IPC_DAI_CONFIG SOF_CMD_TYPE(0x001)
+#define SOF_IPC_DAI_LOOPBACK SOF_CMD_TYPE(0x002)
/* stream */
#define SOF_IPC_STREAM_PCM_PARAMS SOF_CMD_TYPE(0x001)
@@ -193,37 +191,68 @@ struct sof_ipc_compound_hdr {
#define SOF_DAI_FMT_INV_MASK 0x0f00
#define SOF_DAI_FMT_MASTER_MASK 0xf000
+/* types of DAI */
+enum sof_ipc_dai_type {
+ SOF_DAI_INTEL_NONE = 0,
+ SOF_DAI_INTEL_SSP,
+ SOF_DAI_INTEL_DMIC,
+ SOF_DAI_INTEL_HDA,
+};
+
/* SSP Configuration Request - SOF_IPC_DAI_SSP_CONFIG */
struct sof_ipc_dai_ssp_params {
struct sof_ipc_hdr hdr;
- uint32_t mclk;
- uint32_t bclk;
- uint32_t fclk;
- uint16_t ssp_id;
uint16_t mode;
- uint16_t num_slots;
- uint16_t frame_width;
uint16_t clk_id;
- uint16_t format; /* SOF_DAI_FMT_ */
- uint16_t mclk_master;
} __attribute__((packed));
/* HDA Configuration Request - SOF_IPC_DAI_HDA_CONFIG */
struct sof_ipc_dai_hda_params {
struct sof_ipc_hdr hdr;
- uint32_t hda_id;
- uint32_t mclk;
/* TODO */
} __attribute__((packed));
/* DMIC Configuration Request - SOF_IPC_DAI_DMIC_CONFIG */
struct sof_ipc_dai_dmic_params {
struct sof_ipc_hdr hdr;
- uint32_t dmic_id;
- uint32_t mclk;
/* TODO */
} __attribute__((packed));
+
+/* general purpose DAI configuration */
+struct sof_ipc_dai_config {
+ struct sof_ipc_hdr hdr;
+ enum sof_ipc_dai_type type;
+ uint32_t id; /* physical number if more than 1 of this type */
+
+ /* physical protocol and clocking */
+ uint16_t format; /* SOF_DAI_FMT_ */
+ uint16_t reserved; /* alignment */
+ uint32_t mclk; /* mclk frequency in Hz */
+ uint32_t bclk; /* bclk frequency in Hz */
+ uint32_t fclk; /* cclk frequency in Hz */
+
+ /* TDM */
+ uint32_t num_slots;
+ uint32_t rx_slot_mask;
+ uint32_t tx_slot_mask;
+
+ /* data */
+ uint16_t sample_valid_bits;
+ uint16_t sample_container_bits;
+
+ /* MCLK */
+ uint16_t mclk_always_run;
+ uint16_t mclk_master;
+
+ /* HW specific data */
+ union {
+ struct sof_ipc_dai_ssp_params ssp[0];
+ struct sof_ipc_dai_hda_params hda[0];
+ struct sof_ipc_dai_dmic_params dmic[0];
+ };
+};
+
/*
* Stream configuration.
*/
@@ -325,9 +354,11 @@ struct sof_ipc_stream_params {
enum sof_ipc_buffer_format buffer_fmt;
uint32_t rate;
uint32_t channels;
- uint32_t sample_size;
+ uint32_t sample_valid_bytes;
+ uint32_t sample_container_bytes;
/* for notifying host period has completed - 0 means no period IRQ */
uint32_t host_period_bytes;
+ enum sof_ipc_chmap chmap[SOF_IPC_MAX_CHANNELS]; /* channel map */
} __attribute__((packed));
/* PCM params info - SOF_IPC_STREAM_PCM_PARAMS */
@@ -454,25 +485,13 @@ struct sof_ipc_buffer {
uint32_t size; /* buffer size in bytes */
} __attribute__((packed));
-/* types of DAI */
-enum sof_ipc_dai_type {
- SOF_DAI_INTEL_NONE = 0,
- SOF_DAI_INTEL_SSP,
- SOF_DAI_INTEL_DMIC,
- SOF_DAI_INTEL_HDA,
-};
/* generic component config data */
struct sof_ipc_comp_config {
- uint32_t format; /* data format */
- uint32_t frames; /* number of frames to process, 0 is variable */
- uint32_t channels; /* max number of channels */
- uint32_t frame_size; /* sample size in bytes */
uint32_t periods_sink; /* 0 means variable */
uint32_t periods_source; /* 0 means variable */
uint32_t preload_count; /* how many periods to preload */
enum sof_ipc_frame frame_fmt;
- enum sof_ipc_chmap chmap[SOF_IPC_MAX_CHANNELS]; /* channel map */
} __attribute__((packed));
/* generic host component */
diff --git a/src/ipc/intel-ipc.c b/src/ipc/intel-ipc.c
index 2d73fbb..81b30b5 100644
--- a/src/ipc/intel-ipc.c
+++ b/src/ipc/intel-ipc.c
@@ -400,39 +400,32 @@ static int ipc_glb_stream_message(uint32_t header)
* DAI IPC Operations.
*/
-static int ipc_dai_ssp_config(uint32_t header)
+static int ipc_dai_config(uint32_t header)
{
- struct sof_ipc_dai_ssp_params *ssp = _ipc->comp_data;
- struct dai_config dai_config;
+ struct sof_ipc_dai_config *config = _ipc->comp_data;
struct dai *dai;
int ret;
trace_ipc("DsF");
- /* TODO: set type in topology */
- dai_config.type = DAI_TYPE_INTEL_SSP;
- dai_config.ssp = ssp;
-
- /* TODO: allow topology to define SSP clock type */
- dai_config.ssp->clk_id = SSP_CLK_EXT;
-
/* get DAI */
- dai = dai_get(SOF_DAI_INTEL_SSP, ssp->ssp_id);
+ dai = dai_get(config->type, config->id);
if (dai == NULL) {
trace_ipc_error("eDi");
- trace_value(ssp->ssp_id);
+ trace_value(config->type);
+ trace_value(config->id);
return -ENODEV;
}
/* configure DAI */
- ret = dai_set_config(dai, &dai_config);
+ ret = dai_set_config(dai, config);
if (ret < 0) {
trace_ipc_error("eDC");
return ret;
}
- /* now send params to all components who use that DAI */
- return ipc_comp_dai_config(_ipc, &dai_config);
+ /* now send params to all DAI components who use that physical DAI */
+ return ipc_comp_dai_config(_ipc, config);
}
static int ipc_glb_dai_message(uint32_t header)
@@ -440,12 +433,10 @@ static int ipc_glb_dai_message(uint32_t header)
uint32_t cmd = (header & SOF_CMD_TYPE_MASK) >> SOF_CMD_TYPE_SHIFT;
switch (cmd) {
- case iCS(SOF_IPC_COMP_SSP_CONFIG):
- return ipc_dai_ssp_config(header);
- case iCS(SOF_IPC_COMP_LOOPBACK):
+ case iCS(SOF_IPC_DAI_CONFIG):
+ return ipc_dai_config(header);
+ case iCS(SOF_IPC_DAI_LOOPBACK):
//return ipc_comp_set_value(header, COMP_CMD_LOOPBACK);
- case iCS(SOF_IPC_COMP_HDA_CONFIG):
- case iCS(SOF_IPC_COMP_DMIC_CONFIG):
default:
trace_ipc_error("eDc");
trace_value(header);
diff --git a/src/ipc/ipc.c b/src/ipc/ipc.c
index 530fee9..323468b 100644
--- a/src/ipc/ipc.c
+++ b/src/ipc/ipc.c
@@ -307,7 +307,7 @@ void ipc_pipeline_complete(struct ipc *ipc, uint32_t comp_id)
pipeline_complete(ipc_pipe->pipeline);
}
-int ipc_comp_dai_config(struct ipc *ipc, struct dai_config *config)
+int ipc_comp_dai_config(struct ipc *ipc, struct sof_ipc_dai_config *config)
{
struct ipc_comp_dev *icd;
struct list_item *clist;
--
2.11.0
More information about the Sound-open-firmware
mailing list