diff mbox series

[v9,02/14] ASoC: Intel: catpt: Implement IPC protocol

Message ID 20200926085910.21948-3-cezary.rojewski@intel.com
State Superseded
Headers show
Series ASoC: Intel: Catpt - Lynx and Wildcat point | expand

Commit Message

Cezary Rojewski Sept. 26, 2020, 8:58 a.m. UTC
Implement IRQ handlers for immediate and delayed replies and
notifications. Communication is synchronous and allows for serialization
of maximum one message at a time.

DSP may respond with ADSP_PENDING status for a request - known as
delayed reply - and when situation occurs, framework keeps the lock and
awaits upcoming response through IPCD channel which is handled in
bottom-half. Immediate replies spawn no BH at all as their processing is
very short.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/catpt/core.h      |  44 ++++
 sound/soc/intel/catpt/ipc.c       | 245 ++++++++++++++++++
 sound/soc/intel/catpt/messages.h  | 401 ++++++++++++++++++++++++++++++
 sound/soc/intel/catpt/registers.h |   1 -
 4 files changed, 690 insertions(+), 1 deletion(-)
 create mode 100644 sound/soc/intel/catpt/ipc.c
 create mode 100644 sound/soc/intel/catpt/messages.h

Comments

Andy Shevchenko Sept. 28, 2020, 1:44 p.m. UTC | #1
On Sat, Sep 26, 2020 at 10:58:58AM +0200, Cezary Rojewski wrote:
> Implement IRQ handlers for immediate and delayed replies and
> notifications. Communication is synchronous and allows for serialization
> of maximum one message at a time.
> 
> DSP may respond with ADSP_PENDING status for a request - known as
> delayed reply - and when situation occurs, framework keeps the lock and
> awaits upcoming response through IPCD channel which is handled in
> bottom-half. Immediate replies spawn no BH at all as their processing is
> very short.

...

> +static int catpt_dsp_do_send_msg(struct catpt_dev *cdev,
> +				 struct catpt_ipc_msg request,
> +				 struct catpt_ipc_msg *reply, int timeout)
> +{
> +	struct catpt_ipc *ipc = &cdev->ipc;
> +	unsigned long flags;
> +	int ret;
> +
> +	if (!ipc->ready)
> +		return -EPERM;
> +	if (request.size > ipc->config.outbox_size ||
> +	    (reply && reply->size > ipc->config.outbox_size))
> +		return -EINVAL;
> +
> +	spin_lock_irqsave(&ipc->lock, flags);
> +	catpt_ipc_msg_init(ipc, reply);
> +	catpt_dsp_send_tx(cdev, &request);
> +	spin_unlock_irqrestore(&ipc->lock, flags);
> +
> +	ret = catpt_wait_msg_completion(cdev, timeout);
> +	if (ret) {
> +		dev_crit(cdev->dev, "communication severed: %d, rebooting dsp..\n",
> +			 ret);
> +		ipc->ready = false;
> +		/* TODO: attempt recovery */
> +		return ret;
> +	}

> +	ret = ipc->rx.rsp.status;
> +	if (reply) {
> +		reply->header = ipc->rx.header;
> +		if (!ret && reply->data)
> +			memcpy(reply->data, ipc->rx.data, reply->size);
> +	}
> +
> +	return ret;

One more looking into this... What about

	if (reply)
		reply->header = ipc->rx.header;

	ret = ipc->rx.rsp.status; // or even directly if (status) return status.
	if (ret)
		return ret;

	if (reply->data)
		memcpy(reply->data, ipc->rx.data, reply->size);

	return 0;

It may be verbose but I think readability is better here.

> +}

...

> +	CATPT_CHANNEL_CONFIG_5_POINT_0	= 7, /* L, C, R, Ls & Rs */
> +	CATPT_CHANNEL_CONFIG_5_POINT_1	= 8, /* L, C, R, Ls, Rs & LFE */
> +	CATPT_CHANNEL_CONFIG_DUAL_MONO	= 9, /* One channel replicated in two */
> +	CATPT_CHANNEL_CONFIG_INVALID	= 10,

Hmm... I think I got the point why DUAL_MONO was at the end of the switch-case.

...

> +enum catpt_module_id {
> +	CATPT_MODID_BASE_FW = 0x0,
> +	CATPT_MODID_MP3 = 0x1,
> +	CATPT_MODID_AAC_5_1 = 0x2,
> +	CATPT_MODID_AAC_2_0 = 0x3,
> +	CATPT_MODID_SRC = 0x4,
> +	CATPT_MODID_WAVES = 0x5,
> +	CATPT_MODID_DOLBY = 0x6,
> +	CATPT_MODID_BOOST = 0x7,
> +	CATPT_MODID_LPAL = 0x8,
> +	CATPT_MODID_DTS = 0x9,
> +	CATPT_MODID_PCM_CAPTURE = 0xA,
> +	CATPT_MODID_PCM_SYSTEM = 0xB,
> +	CATPT_MODID_PCM_REFERENCE = 0xC,
> +	CATPT_MODID_PCM = 0xD, /* offload */
> +	CATPT_MODID_BLUETOOTH_RENDER = 0xE,
> +	CATPT_MODID_BLUETOOTH_CAPTURE = 0xF,
> +	CATPT_MODID_LAST = CATPT_MODID_BLUETOOTH_CAPTURE,
> +};

if you indent the values to be on the same column it will increase readability.

...

> +enum catpt_mclk_frequency {
> +	CATPT_MCLK_OFF = 0,
> +	CATPT_MCLK_FREQ_6_MHZ = 1,
> +	CATPT_MCLK_FREQ_21_MHZ = 2,
> +	CATPT_MCLK_FREQ_24_MHZ = 3,
> +};

Looks like a 3 MHz as base frequency with multiplicators 0, 2, 7, 8. 

...

> +#define CATPT_STREAM_MSG(msg_type) \
> +{ \
> +	.stream_msg_type = CATPT_STRM_##msg_type, \
> +	.global_msg_type = CATPT_GLB_STREAM_MESSAGE }
> +#define CATPT_STAGE_MSG(msg_type) \
> +{ \
> +	.stage_action = CATPT_STG_##msg_type, \
> +	.stream_msg_type = CATPT_STRM_STAGE_MESSAGE, \
> +	.global_msg_type = CATPT_GLB_STREAM_MESSAGE }

Hmm... This split is interesting. I would rather move } to a new line.

...

> @@ -15,7 +15,6 @@
>  #define CATPT_SHIM_REGS_SIZE	4096
>  #define CATPT_DMA_REGS_SIZE	1024
>  #define CATPT_DMA_COUNT		2

> -#define CATPT_SSP_COUNT		2

Why is this?

>  #define CATPT_SSP_REGS_SIZE	512
>  
>  /* DSP Shim registers */
Cezary Rojewski Sept. 28, 2020, 4:52 p.m. UTC | #2
On 2020-09-28 3:44 PM, Andy Shevchenko wrote:
> On Sat, Sep 26, 2020 at 10:58:58AM +0200, Cezary Rojewski wrote:
>> Implement IRQ handlers for immediate and delayed replies and
>> notifications. Communication is synchronous and allows for serialization
>> of maximum one message at a time.
>>
>> DSP may respond with ADSP_PENDING status for a request - known as
>> delayed reply - and when situation occurs, framework keeps the lock and
>> awaits upcoming response through IPCD channel which is handled in
>> bottom-half. Immediate replies spawn no BH at all as their processing is
>> very short.

...

>> +static int catpt_dsp_do_send_msg(struct catpt_dev *cdev,
>> +				 struct catpt_ipc_msg request,
>> +				 struct catpt_ipc_msg *reply, int timeout)
>> +{
>> +	struct catpt_ipc *ipc = &cdev->ipc;
>> +	unsigned long flags;
>> +	int ret;
>> +
>> +	if (!ipc->ready)
>> +		return -EPERM;
>> +	if (request.size > ipc->config.outbox_size ||
>> +	    (reply && reply->size > ipc->config.outbox_size))
>> +		return -EINVAL;
>> +
>> +	spin_lock_irqsave(&ipc->lock, flags);
>> +	catpt_ipc_msg_init(ipc, reply);
>> +	catpt_dsp_send_tx(cdev, &request);
>> +	spin_unlock_irqrestore(&ipc->lock, flags);
>> +
>> +	ret = catpt_wait_msg_completion(cdev, timeout);
>> +	if (ret) {
>> +		dev_crit(cdev->dev, "communication severed: %d, rebooting dsp..\n",
>> +			 ret);
>> +		ipc->ready = false;
>> +		/* TODO: attempt recovery */
>> +		return ret;
>> +	}
> 
>> +	ret = ipc->rx.rsp.status;
>> +	if (reply) {
>> +		reply->header = ipc->rx.header;
>> +		if (!ret && reply->data)
>> +			memcpy(reply->data, ipc->rx.data, reply->size);
>> +	}
>> +
>> +	return ret;
> 
> One more looking into this... What about
> 
> 	if (reply)
> 		reply->header = ipc->rx.header;
> 
> 	ret = ipc->rx.rsp.status; // or even directly if (status) return status.
> 	if (ret)
> 		return ret;
> 
> 	if (reply->data)
> 		memcpy(reply->data, ipc->rx.data, reply->size);
> 
> 	return 0;
> 
> It may be verbose but I think readability is better here.
> 
>> +}
> 

In your example, last 'if' will cause exception if reply==NULL.

Got your point, although that's just few lines which already involve
'if' with { } spacing. After removing size-checks you suggested this
code is quite thin already.

>> +	CATPT_CHANNEL_CONFIG_5_POINT_0	= 7, /* L, C, R, Ls & Rs */
>> +	CATPT_CHANNEL_CONFIG_5_POINT_1	= 8, /* L, C, R, Ls, Rs & LFE */
>> +	CATPT_CHANNEL_CONFIG_DUAL_MONO	= 9, /* One channel replicated in two */
>> +	CATPT_CHANNEL_CONFIG_INVALID	= 10,
> 
> Hmm... I think I got the point why DUAL_MONO was at the end of the switch-case.
> 

Well, well. Indeed we found where Willy is..

>> +enum catpt_module_id {
>> +	CATPT_MODID_BASE_FW = 0x0,
>> +	CATPT_MODID_MP3 = 0x1,
>> +	CATPT_MODID_AAC_5_1 = 0x2,
>> +	CATPT_MODID_AAC_2_0 = 0x3,
>> +	CATPT_MODID_SRC = 0x4,
>> +	CATPT_MODID_WAVES = 0x5,
>> +	CATPT_MODID_DOLBY = 0x6,
>> +	CATPT_MODID_BOOST = 0x7,
>> +	CATPT_MODID_LPAL = 0x8,
>> +	CATPT_MODID_DTS = 0x9,
>> +	CATPT_MODID_PCM_CAPTURE = 0xA,
>> +	CATPT_MODID_PCM_SYSTEM = 0xB,
>> +	CATPT_MODID_PCM_REFERENCE = 0xC,
>> +	CATPT_MODID_PCM = 0xD, /* offload */
>> +	CATPT_MODID_BLUETOOTH_RENDER = 0xE,
>> +	CATPT_MODID_BLUETOOTH_CAPTURE = 0xF,
>> +	CATPT_MODID_LAST = CATPT_MODID_BLUETOOTH_CAPTURE,
>> +};
> 
> if you indent the values to be on the same column it will increase readability.
> 

Sure, can indent for readability reasons.

>> +enum catpt_mclk_frequency {
>> +	CATPT_MCLK_OFF = 0,
>> +	CATPT_MCLK_FREQ_6_MHZ = 1,
>> +	CATPT_MCLK_FREQ_21_MHZ = 2,
>> +	CATPT_MCLK_FREQ_24_MHZ = 3,
>> +};
> 
> Looks like a 3 MHz as base frequency with multiplicators 0, 2, 7, 8.
> 

Naming based on FW enum type equivalent.

>> +#define CATPT_STREAM_MSG(msg_type) \
>> +{ \
>> +	.stream_msg_type = CATPT_STRM_##msg_type, \
>> +	.global_msg_type = CATPT_GLB_STREAM_MESSAGE }
>> +#define CATPT_STAGE_MSG(msg_type) \
>> +{ \
>> +	.stage_action = CATPT_STG_##msg_type, \
>> +	.stream_msg_type = CATPT_STRM_STAGE_MESSAGE, \
>> +	.global_msg_type = CATPT_GLB_STREAM_MESSAGE }
> 
> Hmm... This split is interesting. I would rather move } to a new line.
> 

As basically everything in my code, style is based on existing example -
usually stuff from ASoC core - here, it's include/sound/soc.h. It's full
of such definitions so because catpt belongs to ASoC subsystem, I've
used the exact same style. No problem changing if that's your preference.

>> @@ -15,7 +15,6 @@
>>   #define CATPT_SHIM_REGS_SIZE	4096
>>   #define CATPT_DMA_REGS_SIZE	1024
>>   #define CATPT_DMA_COUNT		2
> 
>> -#define CATPT_SSP_COUNT		2
> 
> Why is this?
> 

Declaration of struct catpt_spec in patch 01/14 requires this while the
actual, logical (I'm not sure that's the right word here but I bet you
know what I mean) definition - one based on enum catpt_ssp_iface - is
available only here (02/14), with all other messages structs. I'd rather
modify the location of this constant than play with declaration of
struct catpt_spec between the patches.

Czarek
Andy Shevchenko Sept. 29, 2020, 8:46 a.m. UTC | #3
On Mon, Sep 28, 2020 at 04:52:41PM +0000, Rojewski, Cezary wrote:
> On 2020-09-28 3:44 PM, Andy Shevchenko wrote:
> > On Sat, Sep 26, 2020 at 10:58:58AM +0200, Cezary Rojewski wrote:

...

> >> +	ret = ipc->rx.rsp.status;
> >> +	if (reply) {
> >> +		reply->header = ipc->rx.header;
> >> +		if (!ret && reply->data)
> >> +			memcpy(reply->data, ipc->rx.data, reply->size);
> >> +	}
> >> +
> >> +	return ret;
> > 
> > One more looking into this... What about
> > 
> > 	if (reply)
> > 		reply->header = ipc->rx.header;
> > 
> > 	ret = ipc->rx.rsp.status; // or even directly if (status) return status.
> > 	if (ret)
> > 		return ret;
> > 
> > 	if (reply->data)
> > 		memcpy(reply->data, ipc->rx.data, reply->size);
> > 
> > 	return 0;
> > 
> > It may be verbose but I think readability is better here.
> 
> In your example, last 'if' will cause exception if reply==NULL.

Yeah, should be reply && reply->data.

> Got your point, although that's just few lines which already involve
> 'if' with { } spacing. After removing size-checks you suggested this
> code is quite thin already.

Yes, sometimes too thin is not good in terms of readability.

...

> >> +	CATPT_CHANNEL_CONFIG_5_POINT_0	= 7, /* L, C, R, Ls & Rs */
> >> +	CATPT_CHANNEL_CONFIG_5_POINT_1	= 8, /* L, C, R, Ls, Rs & LFE */
> >> +	CATPT_CHANNEL_CONFIG_DUAL_MONO	= 9, /* One channel replicated in two */
> >> +	CATPT_CHANNEL_CONFIG_INVALID	= 10,
> > 
> > Hmm... I think I got the point why DUAL_MONO was at the end of the switch-case.
> > 
> 
> Well, well. Indeed we found where Willy is..

So, we may return to the previous state, up to you.

...

> >> +enum catpt_mclk_frequency {
> >> +	CATPT_MCLK_OFF = 0,
> >> +	CATPT_MCLK_FREQ_6_MHZ = 1,
> >> +	CATPT_MCLK_FREQ_21_MHZ = 2,
> >> +	CATPT_MCLK_FREQ_24_MHZ = 3,
> >> +};
> > 
> > Looks like a 3 MHz as base frequency with multiplicators 0, 2, 7, 8.
> 
> Naming based on FW enum type equivalent.

It was just an observation without any AR item :-)
If you really know the (hardware) background of these choices then perhaps
comment would be good to have.

...

> >> +#define CATPT_STREAM_MSG(msg_type) \
> >> +{ \
> >> +	.stream_msg_type = CATPT_STRM_##msg_type, \
> >> +	.global_msg_type = CATPT_GLB_STREAM_MESSAGE }
> >> +#define CATPT_STAGE_MSG(msg_type) \
> >> +{ \
> >> +	.stage_action = CATPT_STG_##msg_type, \
> >> +	.stream_msg_type = CATPT_STRM_STAGE_MESSAGE, \
> >> +	.global_msg_type = CATPT_GLB_STREAM_MESSAGE }
> > 
> > Hmm... This split is interesting. I would rather move } to a new line.
> > 
> 
> As basically everything in my code, style is based on existing example -
> usually stuff from ASoC core - here, it's include/sound/soc.h. It's full
> of such definitions so because catpt belongs to ASoC subsystem, I've
> used the exact same style. No problem changing if that's your preference.

I think it's better to follow the existing style across subsystem. You may
discard my (style related) comments if they contradict with used style.
Cezary Rojewski Sept. 29, 2020, 9:39 a.m. UTC | #4
On 2020-09-29 10:46 AM, Andy Shevchenko wrote:
> On Mon, Sep 28, 2020 at 04:52:41PM +0000, Rojewski, Cezary wrote:
>> On 2020-09-28 3:44 PM, Andy Shevchenko wrote:
>>> On Sat, Sep 26, 2020 at 10:58:58AM +0200, Cezary Rojewski wrote:

...

>>>> +	ret = ipc->rx.rsp.status;
>>>> +	if (reply) {
>>>> +		reply->header = ipc->rx.header;
>>>> +		if (!ret && reply->data)
>>>> +			memcpy(reply->data, ipc->rx.data, reply->size);
>>>> +	}
>>>> +
>>>> +	return ret;
>>>
>>> One more looking into this... What about
>>>
>>> 	if (reply)
>>> 		reply->header = ipc->rx.header;
>>>
>>> 	ret = ipc->rx.rsp.status; // or even directly if (status) return status.
>>> 	if (ret)
>>> 		return ret;
>>>
>>> 	if (reply->data)
>>> 		memcpy(reply->data, ipc->rx.data, reply->size);
>>>
>>> 	return 0;
>>>
>>> It may be verbose but I think readability is better here.
>>
>> In your example, last 'if' will cause exception if reply==NULL.
> 
> Yeah, should be reply && reply->data.
> 
>> Got your point, although that's just few lines which already involve
>> 'if' with { } spacing. After removing size-checks you suggested this
>> code is quite thin already.
> 
> Yes, sometimes too thin is not good in terms of readability.
> 

This will cost us additional check (2x reply==NULL instead of 1x). Maybe
a newline between:

	reply->header = ipc->rx.header;

	if (!ret && reply->data)
		memcpy(reply->data, ipc->rx.data, reply->size);

suffices?


...

>>>> +	CATPT_CHANNEL_CONFIG_5_POINT_0	= 7, /* L, C, R, Ls & Rs */
>>>> +	CATPT_CHANNEL_CONFIG_5_POINT_1	= 8, /* L, C, R, Ls, Rs & LFE */
>>>> +	CATPT_CHANNEL_CONFIG_DUAL_MONO	= 9, /* One channel replicated in two */
>>>> +	CATPT_CHANNEL_CONFIG_INVALID	= 10,
>>>
>>> Hmm... I think I got the point why DUAL_MONO was at the end of the switch-case.
>>>
>>
>> Well, well. Indeed we found where Willy is..
> 
> So, we may return to the previous state, up to you.
> 
> ...
> 
>>>> +enum catpt_mclk_frequency {
>>>> +	CATPT_MCLK_OFF = 0,
>>>> +	CATPT_MCLK_FREQ_6_MHZ = 1,
>>>> +	CATPT_MCLK_FREQ_21_MHZ = 2,
>>>> +	CATPT_MCLK_FREQ_24_MHZ = 3,
>>>> +};
>>>
>>> Looks like a 3 MHz as base frequency with multiplicators 0, 2, 7, 8.
>>
>> Naming based on FW enum type equivalent.
> 
> It was just an observation without any AR item :-)
> If you really know the (hardware) background of these choices then perhaps
> comment would be good to have.
> 

In general I'm avoiding that subject here. Quite disappointed with what
I had to face, and that's not "just" existing linux solution but every
other component involved in LPT/WPT ADSP project.

I have plans for many more comments Andy, e.g.: fw image block division
(ascii graph and such). All of that will come in time, eventually. Not
intending to leave catpt without maintenance like other sound/soc/intel/
solutions once were.

>>>> +#define CATPT_STREAM_MSG(msg_type) \
>>>> +{ \
>>>> +	.stream_msg_type = CATPT_STRM_##msg_type, \
>>>> +	.global_msg_type = CATPT_GLB_STREAM_MESSAGE }
>>>> +#define CATPT_STAGE_MSG(msg_type) \
>>>> +{ \
>>>> +	.stage_action = CATPT_STG_##msg_type, \
>>>> +	.stream_msg_type = CATPT_STRM_STAGE_MESSAGE, \
>>>> +	.global_msg_type = CATPT_GLB_STREAM_MESSAGE }
>>>
>>> Hmm... This split is interesting. I would rather move } to a new line.
>>>
>>
>> As basically everything in my code, style is based on existing example -
>> usually stuff from ASoC core - here, it's include/sound/soc.h. It's full
>> of such definitions so because catpt belongs to ASoC subsystem, I've
>> used the exact same style. No problem changing if that's your preference.
> 
> I think it's better to follow the existing style across subsystem. You may
> discard my (style related) comments if they contradict with used style.
> 

If there are no other concerns, either a quick spinoff (v10) or delay
those readability improvements till series with resource_union() re-use?

While catpt is a big upgrade when compared to existing /haswell/
(obviously) there are more fruits of this rewrite: house cleaning -
follow-up series targeting /haswell/, /baytrail/ and /common/ of
sound/soc/intel. Guess everyone would like to see those in 5.10.

Regards,
Czarek
Andy Shevchenko Sept. 29, 2020, 10:43 a.m. UTC | #5
On Tue, Sep 29, 2020 at 09:39:36AM +0000, Rojewski, Cezary wrote:
> On 2020-09-29 10:46 AM, Andy Shevchenko wrote:
> > On Mon, Sep 28, 2020 at 04:52:41PM +0000, Rojewski, Cezary wrote:
> >> On 2020-09-28 3:44 PM, Andy Shevchenko wrote:
> >>> On Sat, Sep 26, 2020 at 10:58:58AM +0200, Cezary Rojewski wrote:

...

> >>>> +	ret = ipc->rx.rsp.status;
> >>>> +	if (reply) {
> >>>> +		reply->header = ipc->rx.header;
> >>>> +		if (!ret && reply->data)
> >>>> +			memcpy(reply->data, ipc->rx.data, reply->size);
> >>>> +	}
> >>>> +
> >>>> +	return ret;
> >>>
> >>> One more looking into this... What about
> >>>
> >>> 	if (reply)
> >>> 		reply->header = ipc->rx.header;
> >>>
> >>> 	ret = ipc->rx.rsp.status; // or even directly if (status) return status.
> >>> 	if (ret)
> >>> 		return ret;
> >>>
> >>> 	if (reply->data)
> >>> 		memcpy(reply->data, ipc->rx.data, reply->size);
> >>>
> >>> 	return 0;
> >>>
> >>> It may be verbose but I think readability is better here.
> >>
> >> In your example, last 'if' will cause exception if reply==NULL.
> > 
> > Yeah, should be reply && reply->data.
> > 
> >> Got your point, although that's just few lines which already involve
> >> 'if' with { } spacing. After removing size-checks you suggested this
> >> code is quite thin already.
> > 
> > Yes, sometimes too thin is not good in terms of readability.
> > 
> 
> This will cost us additional check (2x reply==NULL instead of 1x). Maybe
> a newline between:
> 
> 	reply->header = ipc->rx.header;
> 
> 	if (!ret && reply->data)
> 		memcpy(reply->data, ipc->rx.data, reply->size);
> 
> suffices?

I don't like the !ret piece, TBH.
But I wouldn't object too much if you leave it as is. And double check for
reply at least makes it cleaner in my opinion than compressing in few lines.

...

> If there are no other concerns, either a quick spinoff (v10) or delay
> those readability improvements till series with resource_union() re-use?

I guess we may do v10 w/o waiting. Let me look at the last two patches I
haven't commented yet.

> While catpt is a big upgrade when compared to existing /haswell/
> (obviously) there are more fruits of this rewrite: house cleaning -
> follow-up series targeting /haswell/, /baytrail/ and /common/ of
> sound/soc/intel. Guess everyone would like to see those in 5.10.

Yes!
diff mbox series

Patch

diff --git a/sound/soc/intel/catpt/core.h b/sound/soc/intel/catpt/core.h
index 48952e93d86f..8819d928e891 100644
--- a/sound/soc/intel/catpt/core.h
+++ b/sound/soc/intel/catpt/core.h
@@ -9,6 +9,8 @@ 
 #define __SND_SOC_INTEL_CATPT_CORE_H
 
 #include <linux/dma/dw.h>
+#include <linux/irqreturn.h>
+#include "messages.h"
 #include "registers.h"
 
 struct catpt_dev;
@@ -29,6 +31,31 @@  static inline bool catpt_resource_overlapping(struct resource *r1,
 	return true;
 }
 
+struct catpt_ipc_msg {
+	union {
+		u32 header;
+		union catpt_global_msg rsp;
+	};
+	void *data;
+	size_t size;
+};
+
+struct catpt_ipc {
+	struct device *dev;
+
+	struct catpt_ipc_msg rx;
+	struct catpt_fw_ready config;
+	u32 default_timeout;
+	bool ready;
+
+	spinlock_t lock;
+	struct mutex mutex;
+	struct completion done_completion;
+	struct completion busy_completion;
+};
+
+void catpt_ipc_init(struct catpt_ipc *ipc, struct device *dev);
+
 struct catpt_module_type {
 	bool loaded;
 	u32 entry_point;
@@ -59,6 +86,7 @@  struct catpt_spec {
 struct catpt_dev {
 	struct device *dev;
 	struct dw_dma_chip *dmac;
+	struct catpt_ipc ipc;
 
 	void __iomem *pci_ba;
 	void __iomem *lpe_ba;
@@ -83,4 +111,20 @@  int catpt_dma_memcpy_fromdsp(struct catpt_dev *cdev, struct dma_chan *chan,
 			     dma_addr_t dst_addr, dma_addr_t src_addr,
 			     size_t size);
 
+irqreturn_t catpt_dsp_irq_handler(int irq, void *dev_id);
+irqreturn_t catpt_dsp_irq_thread(int irq, void *dev_id);
+
+/*
+ * IPC handlers may return positive values which denote successful
+ * HOST <-> DSP communication yet failure to process specific request.
+ * Use below macro to convert returned non-zero values appropriately
+ */
+#define CATPT_IPC_ERROR(err) (((err) < 0) ? (err) : -EREMOTEIO)
+
+int catpt_dsp_send_msg_timeout(struct catpt_dev *cdev,
+			       struct catpt_ipc_msg request,
+			       struct catpt_ipc_msg *reply, int timeout);
+int catpt_dsp_send_msg(struct catpt_dev *cdev, struct catpt_ipc_msg request,
+		       struct catpt_ipc_msg *reply);
+
 #endif
diff --git a/sound/soc/intel/catpt/ipc.c b/sound/soc/intel/catpt/ipc.c
new file mode 100644
index 000000000000..fbc2ed2590e9
--- /dev/null
+++ b/sound/soc/intel/catpt/ipc.c
@@ -0,0 +1,245 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2020 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/irqreturn.h>
+#include "core.h"
+#include "messages.h"
+#include "registers.h"
+
+#define CATPT_IPC_TIMEOUT_MS	300
+
+void catpt_ipc_init(struct catpt_ipc *ipc, struct device *dev)
+{
+	ipc->dev = dev;
+	ipc->ready = false;
+	ipc->default_timeout = CATPT_IPC_TIMEOUT_MS;
+	init_completion(&ipc->done_completion);
+	init_completion(&ipc->busy_completion);
+	spin_lock_init(&ipc->lock);
+	mutex_init(&ipc->mutex);
+}
+
+static int catpt_ipc_arm(struct catpt_ipc *ipc, struct catpt_fw_ready *config)
+{
+	/*
+	 * Both tx and rx are put into and received from outbox. Inbox is
+	 * only used for notifications where payload size is known upfront,
+	 * thus no separate buffer is allocated for it.
+	 */
+	ipc->rx.data = devm_kzalloc(ipc->dev, config->outbox_size, GFP_KERNEL);
+	if (!ipc->rx.data)
+		return -ENOMEM;
+
+	memcpy(&ipc->config, config, sizeof(*config));
+	ipc->ready = true;
+
+	return 0;
+}
+
+static void catpt_ipc_msg_init(struct catpt_ipc *ipc,
+			       struct catpt_ipc_msg *reply)
+{
+	lockdep_assert_held(&ipc->lock);
+
+	ipc->rx.header = 0;
+	ipc->rx.size = reply ? reply->size : 0;
+	reinit_completion(&ipc->done_completion);
+	reinit_completion(&ipc->busy_completion);
+}
+
+static void catpt_dsp_send_tx(struct catpt_dev *cdev,
+			      const struct catpt_ipc_msg *tx)
+{
+	u32 header = tx->header | CATPT_IPCC_BUSY;
+
+	memcpy_toio(catpt_outbox_addr(cdev), tx->data, tx->size);
+	catpt_writel_shim(cdev, IPCC, header);
+}
+
+static int catpt_wait_msg_completion(struct catpt_dev *cdev, int timeout)
+{
+	struct catpt_ipc *ipc = &cdev->ipc;
+	int ret;
+
+	ret = wait_for_completion_timeout(&ipc->done_completion,
+					  msecs_to_jiffies(timeout));
+	if (!ret)
+		return -ETIMEDOUT;
+	if (ipc->rx.rsp.status != CATPT_REPLY_PENDING)
+		return 0;
+
+	/* wait for delayed reply */
+	ret = wait_for_completion_timeout(&ipc->busy_completion,
+					  msecs_to_jiffies(timeout));
+	return ret ? 0 : -ETIMEDOUT;
+}
+
+static int catpt_dsp_do_send_msg(struct catpt_dev *cdev,
+				 struct catpt_ipc_msg request,
+				 struct catpt_ipc_msg *reply, int timeout)
+{
+	struct catpt_ipc *ipc = &cdev->ipc;
+	unsigned long flags;
+	int ret;
+
+	if (!ipc->ready)
+		return -EPERM;
+	if (request.size > ipc->config.outbox_size ||
+	    (reply && reply->size > ipc->config.outbox_size))
+		return -EINVAL;
+
+	spin_lock_irqsave(&ipc->lock, flags);
+	catpt_ipc_msg_init(ipc, reply);
+	catpt_dsp_send_tx(cdev, &request);
+	spin_unlock_irqrestore(&ipc->lock, flags);
+
+	ret = catpt_wait_msg_completion(cdev, timeout);
+	if (ret) {
+		dev_crit(cdev->dev, "communication severed: %d, rebooting dsp..\n",
+			 ret);
+		ipc->ready = false;
+		/* TODO: attempt recovery */
+		return ret;
+	}
+
+	ret = ipc->rx.rsp.status;
+	if (reply) {
+		reply->header = ipc->rx.header;
+		if (!ret && reply->data)
+			memcpy(reply->data, ipc->rx.data, reply->size);
+	}
+
+	return ret;
+}
+
+int catpt_dsp_send_msg_timeout(struct catpt_dev *cdev,
+			       struct catpt_ipc_msg request,
+			       struct catpt_ipc_msg *reply, int timeout)
+{
+	struct catpt_ipc *ipc = &cdev->ipc;
+	int ret;
+
+	mutex_lock(&ipc->mutex);
+	ret = catpt_dsp_do_send_msg(cdev, request, reply, timeout);
+	mutex_unlock(&ipc->mutex);
+
+	return ret;
+}
+
+int catpt_dsp_send_msg(struct catpt_dev *cdev, struct catpt_ipc_msg request,
+		       struct catpt_ipc_msg *reply)
+{
+	return catpt_dsp_send_msg_timeout(cdev, request, reply,
+					  cdev->ipc.default_timeout);
+}
+
+static void catpt_dsp_copy_rx(struct catpt_dev *cdev, u32 header)
+{
+	struct catpt_ipc *ipc = &cdev->ipc;
+
+	ipc->rx.header = header;
+	if (ipc->rx.rsp.status != CATPT_REPLY_SUCCESS)
+		return;
+
+	memcpy_fromio(ipc->rx.data, catpt_outbox_addr(cdev), ipc->rx.size);
+}
+
+static void catpt_dsp_process_response(struct catpt_dev *cdev, u32 header)
+{
+	union catpt_notify_msg msg = CATPT_MSG(header);
+	struct catpt_ipc *ipc = &cdev->ipc;
+
+	if (msg.fw_ready) {
+		struct catpt_fw_ready config;
+		/* to fit 32b header original address is shifted right by 3 */
+		u32 off = msg.mailbox_address << 3;
+
+		memcpy_fromio(&config, cdev->lpe_ba + off, sizeof(config));
+
+		catpt_ipc_arm(ipc, &config);
+		complete(&cdev->fw_ready);
+		return;
+	}
+
+	switch (msg.global_msg_type) {
+	case CATPT_GLB_REQUEST_CORE_DUMP:
+		break;
+
+	case CATPT_GLB_STREAM_MESSAGE:
+		switch (msg.stream_msg_type) {
+		case CATPT_STRM_NOTIFICATION:
+			break;
+		default:
+			catpt_dsp_copy_rx(cdev, header);
+			/* signal completion of delayed reply */
+			complete(&ipc->busy_completion);
+			break;
+		}
+		break;
+
+	default:
+		dev_warn(cdev->dev, "unknown response: %d received\n",
+			 msg.global_msg_type);
+		break;
+	}
+}
+
+irqreturn_t catpt_dsp_irq_thread(int irq, void *dev_id)
+{
+	struct catpt_dev *cdev = dev_id;
+	u32 ipcd;
+
+	ipcd = catpt_readl_shim(cdev, IPCD);
+
+	/* ensure there is delayed reply or notification to process */
+	if (!(ipcd & CATPT_IPCD_BUSY))
+		return IRQ_NONE;
+
+	catpt_dsp_process_response(cdev, ipcd);
+
+	/* tell DSP processing is completed */
+	catpt_updatel_shim(cdev, IPCD, CATPT_IPCD_BUSY | CATPT_IPCD_DONE,
+			   CATPT_IPCD_DONE);
+	/* unmask dsp BUSY interrupt */
+	catpt_updatel_shim(cdev, IMC, CATPT_IMC_IPCDB, 0);
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t catpt_dsp_irq_handler(int irq, void *dev_id)
+{
+	struct catpt_dev *cdev = dev_id;
+	irqreturn_t ret = IRQ_NONE;
+	u32 isc, ipcc;
+
+	isc = catpt_readl_shim(cdev, ISC);
+
+	/* immediate reply */
+	if (isc & CATPT_ISC_IPCCD) {
+		/* mask host DONE interrupt */
+		catpt_updatel_shim(cdev, IMC, CATPT_IMC_IPCCD, CATPT_IMC_IPCCD);
+
+		ipcc = catpt_readl_shim(cdev, IPCC);
+		catpt_dsp_copy_rx(cdev, ipcc);
+		complete(&cdev->ipc.done_completion);
+
+		/* tell DSP processing is completed */
+		catpt_updatel_shim(cdev, IPCC, CATPT_IPCC_DONE, 0);
+		/* unmask host DONE interrupt */
+		catpt_updatel_shim(cdev, IMC, CATPT_IMC_IPCCD, 0);
+		ret = IRQ_HANDLED;
+	}
+
+	/* delayed reply or notification */
+	if (isc & CATPT_ISC_IPCDB) {
+		/* mask dsp BUSY interrupt */
+		catpt_updatel_shim(cdev, IMC, CATPT_IMC_IPCDB, CATPT_IMC_IPCDB);
+		ret = IRQ_WAKE_THREAD;
+	}
+
+	return ret;
+}
diff --git a/sound/soc/intel/catpt/messages.h b/sound/soc/intel/catpt/messages.h
new file mode 100644
index 000000000000..1c51d142c177
--- /dev/null
+++ b/sound/soc/intel/catpt/messages.h
@@ -0,0 +1,401 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2020 Intel Corporation. All rights reserved.
+ *
+ * Author: Cezary Rojewski <cezary.rojewski@intel.com>
+ */
+
+#ifndef __SND_SOC_INTEL_CATPT_MSG_H
+#define __SND_SOC_INTEL_CATPT_MSG_H
+
+struct catpt_dev;
+
+/* IPC messages base types  */
+
+enum catpt_reply_status {
+	CATPT_REPLY_SUCCESS = 0,
+	CATPT_REPLY_ERROR_INVALID_PARAM = 1,
+	CATPT_REPLY_UNKNOWN_MESSAGE_TYPE = 2,
+	CATPT_REPLY_OUT_OF_RESOURCES = 3,
+	CATPT_REPLY_BUSY = 4,
+	CATPT_REPLY_PENDING = 5,
+	CATPT_REPLY_FAILURE = 6,
+	CATPT_REPLY_INVALID_REQUEST = 7,
+	CATPT_REPLY_UNINITIALIZED = 8,
+	CATPT_REPLY_NOT_FOUND = 9,
+	CATPT_REPLY_SOURCE_NOT_STARTED = 10,
+};
+
+/* GLOBAL messages */
+
+enum catpt_global_msg_type {
+	CATPT_GLB_GET_FW_VERSION = 0,
+	CATPT_GLB_ALLOCATE_STREAM = 3,
+	CATPT_GLB_FREE_STREAM = 4,
+	CATPT_GLB_STREAM_MESSAGE = 6,
+	CATPT_GLB_REQUEST_CORE_DUMP = 7,
+	CATPT_GLB_SET_DEVICE_FORMATS = 10,
+	CATPT_GLB_ENTER_DX_STATE = 12,
+	CATPT_GLB_GET_MIXER_STREAM_INFO = 13,
+};
+
+union catpt_global_msg {
+	u32 val;
+	struct {
+		u32 status:5;
+		u32 context:19; /* stream or module specific */
+		u32 global_msg_type:5;
+		u32 fw_ready:1;
+		u32 done:1;
+		u32 busy:1;
+	};
+} __packed;
+
+#define CATPT_MSG(hdr) { .val = hdr }
+#define CATPT_GLOBAL_MSG(msg_type) \
+	{ .global_msg_type = CATPT_GLB_##msg_type }
+
+#define BUILD_HASH_SIZE		40
+
+struct catpt_fw_version {
+	u8 build;
+	u8 minor;
+	u8 major;
+	u8 type;
+	u8 build_hash[BUILD_HASH_SIZE];
+	u32 log_providers_hash;
+} __packed;
+
+int catpt_ipc_get_fw_version(struct catpt_dev *cdev,
+			     struct catpt_fw_version *version);
+
+enum catpt_pin_id {
+	CATPT_PIN_ID_SYSTEM = 0,
+	CATPT_PIN_ID_REFERENCE = 1,
+	CATPT_PIN_ID_CAPTURE1 = 2,
+	CATPT_PIN_ID_CAPTURE2 = 3,
+	CATPT_PIN_ID_OFFLOAD1 = 4,
+	CATPT_PIN_ID_OFFLOAD2 = 5,
+	CATPT_PIN_ID_MIXER = 7,
+	CATPT_PIN_ID_BLUETOOTH_CAPTURE = 8,
+	CATPT_PIN_ID_BLUETOOTH_RENDER = 9,
+};
+
+enum catpt_path_id {
+	CATPT_PATH_SSP0_OUT = 0,
+	CATPT_PATH_SSP0_IN = 1,
+	CATPT_PATH_SSP1_OUT = 2,
+	CATPT_PATH_SSP1_IN = 3,
+	/* duplicated audio in capture path */
+	CATPT_PATH_SSP0_IN_DUP = 4,
+};
+
+enum catpt_stream_type {
+	CATPT_STRM_TYPE_RENDER = 0, /* offload */
+	CATPT_STRM_TYPE_SYSTEM = 1,
+	CATPT_STRM_TYPE_CAPTURE = 2,
+	CATPT_STRM_TYPE_LOOPBACK = 3,
+	CATPT_STRM_TYPE_BLUETOOTH_RENDER = 4,
+	CATPT_STRM_TYPE_BLUETOOTH_CAPTURE = 5,
+};
+
+enum catpt_format_id {
+	CATPT_FORMAT_PCM = 0,
+	CATPT_FORMAT_MP3 = 1,
+	CATPT_FORMAT_AAC = 2,
+	CATPT_FORMAT_WMA = 3,
+};
+
+enum catpt_channel_index {
+	CATPT_CHANNEL_LEFT = 0x0,
+	CATPT_CHANNEL_CENTER = 0x1,
+	CATPT_CHANNEL_RIGHT = 0x2,
+	CATPT_CHANNEL_LEFT_SURROUND = 0x3,
+	CATPT_CHANNEL_CENTER_SURROUND = 0x3,
+	CATPT_CHANNEL_RIGHT_SURROUND = 0x4,
+	CATPT_CHANNEL_LFE = 0x7,
+	CATPT_CHANNEL_INVALID = 0xF,
+};
+
+enum catpt_channel_config {
+	CATPT_CHANNEL_CONFIG_MONO	= 0, /* One channel only */
+	CATPT_CHANNEL_CONFIG_STEREO	= 1, /* L & R */
+	CATPT_CHANNEL_CONFIG_2_POINT_1	= 2, /* L, R & LFE; PCM only */
+	CATPT_CHANNEL_CONFIG_3_POINT_0	= 3, /* L, C & R; MP3 & AAC only */
+	CATPT_CHANNEL_CONFIG_3_POINT_1	= 4, /* L, C, R & LFE; PCM only */
+	CATPT_CHANNEL_CONFIG_QUATRO	= 5, /* L, R, Ls & Rs; PCM only */
+	CATPT_CHANNEL_CONFIG_4_POINT_0	= 6, /* L, C, R & Cs; MP3 & AAC only */
+	CATPT_CHANNEL_CONFIG_5_POINT_0	= 7, /* L, C, R, Ls & Rs */
+	CATPT_CHANNEL_CONFIG_5_POINT_1	= 8, /* L, C, R, Ls, Rs & LFE */
+	CATPT_CHANNEL_CONFIG_DUAL_MONO	= 9, /* One channel replicated in two */
+	CATPT_CHANNEL_CONFIG_INVALID	= 10,
+};
+
+enum catpt_interleaving_style {
+	CATPT_INTERLEAVING_PER_CHANNEL = 0,
+	CATPT_INTERLEAVING_PER_SAMPLE  = 1,
+};
+
+struct catpt_audio_format {
+	u32 sample_rate;
+	u32 bit_depth;
+	u32 channel_map;
+	u32 channel_config;
+	u32 interleaving;
+	u8 num_channels;
+	u8 valid_bit_depth;
+	u8 reserved[2];
+} __packed;
+
+struct catpt_ring_info {
+	u32 page_table_addr;
+	u32 num_pages;
+	u32 size;
+	u32 offset;
+	u32 ring_first_page_pfn;
+} __packed;
+
+#define CATPT_MODULE_COUNT (CATPT_MODID_LAST + 1)
+
+enum catpt_module_id {
+	CATPT_MODID_BASE_FW = 0x0,
+	CATPT_MODID_MP3 = 0x1,
+	CATPT_MODID_AAC_5_1 = 0x2,
+	CATPT_MODID_AAC_2_0 = 0x3,
+	CATPT_MODID_SRC = 0x4,
+	CATPT_MODID_WAVES = 0x5,
+	CATPT_MODID_DOLBY = 0x6,
+	CATPT_MODID_BOOST = 0x7,
+	CATPT_MODID_LPAL = 0x8,
+	CATPT_MODID_DTS = 0x9,
+	CATPT_MODID_PCM_CAPTURE = 0xA,
+	CATPT_MODID_PCM_SYSTEM = 0xB,
+	CATPT_MODID_PCM_REFERENCE = 0xC,
+	CATPT_MODID_PCM = 0xD, /* offload */
+	CATPT_MODID_BLUETOOTH_RENDER = 0xE,
+	CATPT_MODID_BLUETOOTH_CAPTURE = 0xF,
+	CATPT_MODID_LAST = CATPT_MODID_BLUETOOTH_CAPTURE,
+};
+
+struct catpt_module_entry {
+	u32 module_id;
+	u32 entry_point;
+} __packed;
+
+struct catpt_module_map {
+	u8 num_entries;
+	struct catpt_module_entry entries[];
+} __packed;
+
+struct catpt_memory_info {
+	u32 offset;
+	u32 size;
+} __packed;
+
+#define CATPT_CHANNELS_MAX	4
+#define CATPT_ALL_CHANNELS_MASK	UINT_MAX
+
+struct catpt_stream_info {
+	u32 stream_hw_id;
+	u32 reserved;
+	u32 read_pos_regaddr;
+	u32 pres_pos_regaddr;
+	u32 peak_meter_regaddr[CATPT_CHANNELS_MAX];
+	u32 volume_regaddr[CATPT_CHANNELS_MAX];
+} __packed;
+
+int catpt_ipc_alloc_stream(struct catpt_dev *cdev,
+			   enum catpt_path_id path_id,
+			   enum catpt_stream_type type,
+			   struct catpt_audio_format *afmt,
+			   struct catpt_ring_info *rinfo,
+			   u8 num_modules,
+			   struct catpt_module_entry *modules,
+			   struct resource *persistent,
+			   struct resource *scratch,
+			   struct catpt_stream_info *sinfo);
+int catpt_ipc_free_stream(struct catpt_dev *cdev, u8 stream_hw_id);
+
+enum catpt_ssp_iface {
+	CATPT_SSP_IFACE_0 = 0,
+	CATPT_SSP_IFACE_1 = 1,
+	CATPT_SSP_IFACE_LAST = CATPT_SSP_IFACE_1,
+};
+
+#define CATPT_SSP_COUNT (CATPT_SSP_IFACE_LAST + 1)
+
+enum catpt_mclk_frequency {
+	CATPT_MCLK_OFF = 0,
+	CATPT_MCLK_FREQ_6_MHZ = 1,
+	CATPT_MCLK_FREQ_21_MHZ = 2,
+	CATPT_MCLK_FREQ_24_MHZ = 3,
+};
+
+enum catpt_ssp_mode {
+	CATPT_SSP_MODE_I2S_CONSUMER = 0,
+	CATPT_SSP_MODE_I2S_PROVIDER = 1,
+	CATPT_SSP_MODE_TDM_PROVIDER = 2,
+};
+
+struct catpt_ssp_device_format {
+	u32 iface;
+	u32 mclk;
+	u32 mode;
+	u16 clock_divider;
+	u8 channels;
+} __packed;
+
+int catpt_ipc_set_device_format(struct catpt_dev *cdev,
+				struct catpt_ssp_device_format *devfmt);
+
+enum catpt_dx_state {
+	CATPT_DX_STATE_D3 = 3,
+};
+
+enum catpt_dx_type {
+	CATPT_DX_TYPE_FW_IMAGE = 0,
+	CATPT_DX_TYPE_MEMORY_DUMP = 1,
+};
+
+struct catpt_save_meminfo {
+	u32 offset;
+	u32 size;
+	u32 source;
+} __packed;
+
+#define SAVE_MEMINFO_MAX	14
+
+struct catpt_dx_context {
+	u32 num_meminfo;
+	struct catpt_save_meminfo meminfo[SAVE_MEMINFO_MAX];
+} __packed;
+
+int catpt_ipc_enter_dxstate(struct catpt_dev *cdev, enum catpt_dx_state state,
+			    struct catpt_dx_context *context);
+
+struct catpt_mixer_stream_info {
+	u32 mixer_hw_id;
+	u32 peak_meter_regaddr[CATPT_CHANNELS_MAX];
+	u32 volume_regaddr[CATPT_CHANNELS_MAX];
+} __packed;
+
+int catpt_ipc_get_mixer_stream_info(struct catpt_dev *cdev,
+				    struct catpt_mixer_stream_info *info);
+
+/* STREAM messages */
+
+enum catpt_stream_msg_type {
+	CATPT_STRM_RESET_STREAM = 0,
+	CATPT_STRM_PAUSE_STREAM = 1,
+	CATPT_STRM_RESUME_STREAM = 2,
+	CATPT_STRM_STAGE_MESSAGE = 3,
+	CATPT_STRM_NOTIFICATION = 4,
+};
+
+enum catpt_stage_action {
+	CATPT_STG_SET_VOLUME = 1,
+	CATPT_STG_SET_WRITE_POSITION = 2,
+	CATPT_STG_MUTE_LOOPBACK = 3,
+};
+
+union catpt_stream_msg {
+	u32 val;
+	struct {
+		u32 status:5;
+		u32 reserved:7;
+		u32 stage_action:4;
+		u32 stream_hw_id:4;
+		u32 stream_msg_type:4;
+		u32 global_msg_type:5;
+		u32 fw_ready:1;
+		u32 done:1;
+		u32 busy:1;
+	};
+} __packed;
+
+#define CATPT_STREAM_MSG(msg_type) \
+{ \
+	.stream_msg_type = CATPT_STRM_##msg_type, \
+	.global_msg_type = CATPT_GLB_STREAM_MESSAGE }
+#define CATPT_STAGE_MSG(msg_type) \
+{ \
+	.stage_action = CATPT_STG_##msg_type, \
+	.stream_msg_type = CATPT_STRM_STAGE_MESSAGE, \
+	.global_msg_type = CATPT_GLB_STREAM_MESSAGE }
+
+int catpt_ipc_reset_stream(struct catpt_dev *cdev, u8 stream_hw_id);
+int catpt_ipc_pause_stream(struct catpt_dev *cdev, u8 stream_hw_id);
+int catpt_ipc_resume_stream(struct catpt_dev *cdev, u8 stream_hw_id);
+
+/* STREAM messages - STAGE subtype */
+
+enum catpt_audio_curve_type {
+	CATPT_AUDIO_CURVE_NONE = 0,
+	CATPT_AUDIO_CURVE_WINDOWS_FADE = 1,
+};
+
+int catpt_ipc_set_volume(struct catpt_dev *cdev, u8 stream_hw_id,
+			 u32 channel, u32 volume,
+			 u32 curve_duration,
+			 enum catpt_audio_curve_type curve_type);
+
+int catpt_ipc_set_write_pos(struct catpt_dev *cdev, u8 stream_hw_id,
+			    u32 pos, bool eob, bool ll);
+
+int catpt_ipc_mute_loopback(struct catpt_dev *cdev, u8 stream_hw_id, bool mute);
+
+/* NOTIFICATION messages */
+
+enum catpt_notify_reason {
+	CATPT_NOTIFY_POSITION_CHANGED = 0,
+	CATPT_NOTIFY_GLITCH_OCCURRED = 1,
+};
+
+union catpt_notify_msg {
+	u32 val;
+	struct {
+		u32 mailbox_address:29;
+		u32 fw_ready:1;
+		u32 done:1;
+		u32 busy:1;
+	};
+	struct {
+		u32 status:5;
+		u32 reserved:7;
+		u32 notify_reason:4;
+		u32 stream_hw_id:4;
+		u32 stream_msg_type:4;
+		u32 global_msg_type:5;
+		u32 hdr:3; /* fw_ready, done, busy */
+	};
+} __packed;
+
+#define FW_INFO_SIZE_MAX	100
+
+struct catpt_fw_ready {
+	u32 inbox_offset;
+	u32 outbox_offset;
+	u32 inbox_size;
+	u32 outbox_size;
+	u32 fw_info_size;
+	char fw_info[FW_INFO_SIZE_MAX];
+} __packed;
+
+struct catpt_notify_position {
+	u32 stream_position;
+	u32 fw_cycle_count;
+} __packed;
+
+enum catpt_glitch_type {
+	CATPT_GLITCH_UNDERRUN = 1,
+	CATPT_GLITCH_DECODER_ERROR = 2,
+	CATPT_GLITCH_DOUBLED_WRITE_POS = 3,
+};
+
+struct catpt_notify_glitch {
+	u32 type;
+	u64 presentation_pos;
+	u32 write_pos;
+} __packed;
+
+#endif
diff --git a/sound/soc/intel/catpt/registers.h b/sound/soc/intel/catpt/registers.h
index a051d8b36d88..47280d82842e 100644
--- a/sound/soc/intel/catpt/registers.h
+++ b/sound/soc/intel/catpt/registers.h
@@ -15,7 +15,6 @@ 
 #define CATPT_SHIM_REGS_SIZE	4096
 #define CATPT_DMA_REGS_SIZE	1024
 #define CATPT_DMA_COUNT		2
-#define CATPT_SSP_COUNT		2
 #define CATPT_SSP_REGS_SIZE	512
 
 /* DSP Shim registers */