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@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;