Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 54 additions & 20 deletions src/drivers/intel/ssp/ssp.c
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ static int ssp_set_config(struct dai *dai,
* SSP dai is activated, for either power saving or params runtime
* configurable flexibility.
*/
static int ssp_pre_start(struct dai *dai)
static int ssp_port_start(struct dai *dai)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);
struct sof_ipc_dai_config *config = &ssp->config;
Expand All @@ -627,7 +627,12 @@ static int ssp_pre_start(struct dai *dai)

int ret = 0;

dai_info(dai, "ssp_pre_start()");
dai_info(dai, "ssp_port_start(), port_ref = %d", ssp->port_ref);

ssp->port_ref++;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not use "state" here, I'm assuming this needs to be in a configured but inactive state ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the state checking is added back.


if (ssp->port_ref > 1)
return 0;

/* SSP active means bclk already configured. */
if (ssp->state[SOF_IPC_STREAM_PLAYBACK] == COMP_STATE_ACTIVE ||
Expand Down Expand Up @@ -671,7 +676,7 @@ static int ssp_pre_start(struct dai *dai)

/* divisor must be within SCR range */
if (mdiv > (SSCR0_SCR_MASK >> 8)) {
dai_err(dai, "ssp_pre_start(): divisor %d is not within SCR range",
dai_err(dai, "ssp_port_start(): divisor %d is not within SCR range",
mdiv);
ret = -EINVAL;
goto out;
Expand All @@ -683,9 +688,12 @@ static int ssp_pre_start(struct dai *dai)

ssp_write(dai, SSCR0, sscr0);

dai_info(dai, "ssp_set_config(), sscr0 = 0x%08x", sscr0);
out:
dai_info(dai, "ssp_port_start(), sscr0 = 0x%08x", sscr0);

/* enable port */
ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE);
dai_info(dai, "ssp_port_start(), SSP%d port enabled", dai->index);
out:
return ret;
}

Expand All @@ -694,13 +702,20 @@ static int ssp_pre_start(struct dai *dai)
* dai is changed to inactive, though the runtime param configuration
* don't have to be reset.
*/
static void ssp_post_stop(struct dai *dai)
static void ssp_port_stop(struct dai *dai)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);

/* release clocks if SSP is inactive */
if (ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_ACTIVE &&
ssp->state[SOF_IPC_STREAM_CAPTURE] != COMP_STATE_ACTIVE) {
dai_info(dai, "ssp_port_stop(), port_ref = %d", ssp->port_ref);

ssp->port_ref--;

if (ssp->port_ref == 0) {
/* disable SSP port if no users */
ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0);
dai_info(dai, "ssp_port_stop(), SSP%d port disabled", dai->index);

/* release clocks if SSP is inactive */
dai_info(dai, "releasing BCLK/MCLK clocks for SSP%d...", dai->index);
#if CONFIG_INTEL_MN
mn_release_bclk(dai->index);
Expand Down Expand Up @@ -749,10 +764,8 @@ static void ssp_start(struct dai *dai, int direction)
spin_lock(&dai->lock);

/* request mclk/bclk */
ssp_pre_start(dai);
ssp_port_start(dai);

/* enable port */
ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE);
ssp->state[direction] = COMP_STATE_ACTIVE;

dai_info(dai, "ssp_start()");
Expand Down Expand Up @@ -810,14 +823,7 @@ static void ssp_stop(struct dai *dai, int direction)
dai_info(dai, "ssp_stop(), TX stop");
}

/* disable SSP port if no users */
if (ssp->state[SOF_IPC_STREAM_CAPTURE] == COMP_STATE_PREPARE &&
ssp->state[SOF_IPC_STREAM_PLAYBACK] == COMP_STATE_PREPARE) {
ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0);
dai_info(dai, "ssp_stop(), SSP port disabled");
}

ssp_post_stop(dai);
ssp_port_stop(dai);

spin_unlock(&dai->lock);
}
Expand Down Expand Up @@ -870,6 +876,31 @@ static int ssp_trigger(struct dai *dai, int cmd, int direction)
return 0;
}

static int ssp_clkctrl(struct dai *dai, struct sof_ipc_dai_clkctrl *clkctrl)
{
int ret = 0;

dai_info(dai, "ssp_clkctrl(): SSP%d clk_en %d clk_id %d",
dai->index, clkctrl->clk_en, clkctrl->clk_id);

/* enable the entire port instead of checking clk_id */

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I don't know how to control mclk/bclk separately...

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest that we add two helper functions to control mclk and bclk respectively. We count ref count in those helper functions. And we use the helper functions within ssp_set_clkctrl, ssp_port_stop, and ssp_port_start.

spin_lock(&dai->lock);

if (clkctrl->clk_en) {
ret = ssp_port_start(dai);
if (ret) {
dai_err(dai,
"ssp_clkctrl(): fail to start clk for SSP%d",
dai->index);
}
} else {
ssp_port_stop(dai);
}

spin_unlock(&dai->lock);
return ret;
}

static int ssp_probe(struct dai *dai)
{
struct ssp_pdata *ssp;
Expand All @@ -888,6 +919,8 @@ static int ssp_probe(struct dai *dai)
ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_READY;
ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_READY;

ssp->port_ref = 0;

#if CONFIG_INTEL_MN
/* Reset M/N, power-gating functions need it */
mn_reset_bclk_divider(dai->index);
Expand Down Expand Up @@ -943,6 +976,7 @@ const struct dai_driver ssp_driver = {
.ops = {
.trigger = ssp_trigger,
.set_config = ssp_set_config,
.clkctrl = ssp_clkctrl,
.pm_context_store = ssp_context_store,
.pm_context_restore = ssp_context_restore,
.get_hw_params = ssp_get_hw_params,
Expand Down
10 changes: 10 additions & 0 deletions src/include/ipc/dai-intel.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@
/* DMIC max. four controllers for eight microphone channels */
#define SOF_DAI_INTEL_DMIC_NUM_CTRL 4

/* SSP clocks to enable/disable
*
* Macros for clk_id field in sof_ipc_dai_ssp_clkctrl struct.
*/

/* mclk */
#define SOF_DAI_INTEL_CLKCTRL_MCLK 1
/* bclk */
#define SOF_DAI_INTEL_CLKCTRL_BCLK 2

/* SSP Configuration Request - SOF_IPC_DAI_SSP_CONFIG */
struct sof_ipc_dai_ssp_params {
uint32_t reserved0;
Expand Down
10 changes: 10 additions & 0 deletions src/include/ipc/dai.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,14 @@ struct sof_ipc_dai_config {
};
} __attribute__((packed, aligned(4)));

/* general purpose DAI clock control */
struct sof_ipc_dai_clkctrl {
struct sof_ipc_cmd_hdr hdr;
uint32_t type; /**< DAI type - enum sof_ipc_dai_type */
uint32_t dai_index; /**< index of this type dai */

uint32_t clk_en; /**< zero to disable the clock */
uint32_t clk_id; /**< clock id to operate */
} __attribute__((packed, aligned(4)));

#endif /* __IPC_DAI_H__ */
1 change: 1 addition & 0 deletions src/include/ipc/header.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@
*/
#define SOF_IPC_DAI_CONFIG SOF_CMD_TYPE(0x001)
#define SOF_IPC_DAI_LOOPBACK SOF_CMD_TYPE(0x002)
#define SOF_IPC_DAI_CLKCTRL SOF_CMD_TYPE(0x003)

/** @} */

Expand Down
2 changes: 1 addition & 1 deletion src/include/kernel/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

/** \brief SOF ABI version major, minor and patch numbers */
#define SOF_ABI_MAJOR 3
#define SOF_ABI_MINOR 18
#define SOF_ABI_MINOR 19
#define SOF_ABI_PATCH 1

/** \brief SOF ABI version number. Format within 32bit word is MMmmmppp */
Expand Down
3 changes: 3 additions & 0 deletions src/include/sof/drivers/ssp.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ struct ssp_pdata {
uint32_t sscr1;
uint32_t psp;
uint32_t state[2]; /* SSP_STATE_ for each direction */
uint32_t port_ref; /* reference count for the port enable
* request from trigger or IPC
*/
struct sof_ipc_dai_config config;
struct sof_ipc_dai_ssp_params params;
};
Expand Down
16 changes: 16 additions & 0 deletions src/include/sof/lib/dai.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

struct dai;
struct sof_ipc_dai_config;
struct sof_ipc_dai_clkctrl;
struct sof_ipc_stream_params;

/** \addtogroup sof_dai_drivers DAI Drivers
Expand Down Expand Up @@ -72,6 +73,7 @@ struct sof_ipc_stream_params;
*/
struct dai_ops {
int (*set_config)(struct dai *dai, struct sof_ipc_dai_config *config);
int (*clkctrl)(struct dai *dai, struct sof_ipc_dai_clkctrl *clkctrl);
int (*trigger)(struct dai *dai, int cmd, int direction);
int (*pm_context_restore)(struct dai *dai);
int (*pm_context_store)(struct dai *dai);
Expand Down Expand Up @@ -333,6 +335,20 @@ static inline int dai_set_config(struct dai *dai,
return ret;
}

/**
* \brief Digital Audio interface clock control
*/
static inline int dai_clkctrl(struct dai *dai,
struct sof_ipc_dai_clkctrl *clkctrl)
{
int ret = 0;

if (dai->drv->ops.clkctrl)
ret = dai->drv->ops.clkctrl(dai, clkctrl);

return ret;
}

/**
* \brief Digital Audio interface trigger
*/
Expand Down
36 changes: 36 additions & 0 deletions src/ipc/handler-ipc3.c
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,39 @@ static int ipc_dai_config(uint32_t header)
return ipc_comp_dai_config(ipc, ipc->comp_data);
}

static int ipc_dai_clkctrl(uint32_t header)
{
struct ipc *ipc = ipc_get();
struct sof_ipc_dai_clkctrl clkctrl;
struct dai *dai;
int ret;

/* copy message with ABI safe method */
IPC_COPY_CMD(clkctrl, ipc->comp_data);

tr_dbg(&ipc_tr, "ipc: dai %d.%d -> clkctrl ", clkctrl.type,
clkctrl.dai_index);

/* get DAI */
dai = dai_get(clkctrl.type, clkctrl.dai_index, 0 /* existing only */);
if (!dai) {
tr_err(&ipc_tr, "ipc: dai %d,%d not found", clkctrl.type,
clkctrl.dai_index);
return -ENODEV;
}

/* configure DAI */
ret = dai_clkctrl(dai, &clkctrl);
dai_put(dai); /* free ref immediately */
if (ret < 0) {
tr_err(&ipc_tr, "ipc: dai %d,%d clkctrl failed %d", clkctrl.type,
clkctrl.dai_index, ret);
return ret;
}

return 0;
}

static int ipc_glb_dai_message(uint32_t header)
{
uint32_t cmd = iCS(header);
Expand All @@ -532,6 +565,9 @@ static int ipc_glb_dai_message(uint32_t header)
return ipc_dai_config(header);
case SOF_IPC_DAI_LOOPBACK:
//return ipc_comp_set_value(header, COMP_CMD_LOOPBACK);
return -EINVAL;
case SOF_IPC_DAI_CLKCTRL:
return ipc_dai_clkctrl(header);
default:
tr_err(&ipc_tr, "ipc: unknown DAI cmd 0x%x", cmd);
return -EINVAL;
Expand Down