summaryrefslogtreecommitdiffstats
path: root/sound/soc/sof/imx/imx-common.h
blob: 9bd711dbb5d03f3ed963f1cada870b82f779bf0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */

#ifndef __IMX_COMMON_H__
#define __IMX_COMMON_H__

#include <linux/clk.h>
#include <linux/of_platform.h>
#include <sound/sof/xtensa.h>

#include "../sof-of-dev.h"
#include "../ops.h"

#define EXCEPT_MAX_HDR_SIZE	0x400
#define IMX8_STACK_DUMP_SIZE 32

/* chip_info refers to the data stored in struct sof_dev_desc's chip_info */
#define get_chip_info(sdev)\
	((const struct imx_chip_info *)((sdev)->pdata->desc->chip_info))

/* chip_pdata refers to the data stored in struct imx_common_data's chip_pdata */
#define get_chip_pdata(sdev)\
	(((struct imx_common_data *)((sdev)->pdata->hw_pdata))->chip_pdata)

/* can be used if:
 *	1) The only supported IPC version is IPC3.
 *	2) The default paths/FW name match values below.
 *
 * otherwise, just explicitly declare the structure
 */
#define IMX_SOF_DEV_DESC(mach_name, of_machs,				\
			 mach_chip_info, mach_ops, mach_ops_init)	\
static struct sof_dev_desc sof_of_##mach_name##_desc = {		\
	.of_machines = of_machs,					\
	.chip_info = mach_chip_info,					\
	.ipc_supported_mask = BIT(SOF_IPC_TYPE_3),			\
	.ipc_default = SOF_IPC_TYPE_3,					\
	.default_fw_path = {						\
		[SOF_IPC_TYPE_3] = "imx/sof",				\
	},								\
	.default_tplg_path = {						\
		[SOF_IPC_TYPE_3] = "imx/sof-tplg",			\
	},								\
	.default_fw_filename = {					\
		[SOF_IPC_TYPE_3] = "sof-" #mach_name ".ri",		\
	},								\
	.ops = mach_ops,						\
	.ops_init = mach_ops_init,					\
}

/* to be used alongside IMX_SOF_DEV_DESC() */
#define IMX_SOF_DEV_DESC_NAME(mach_name) sof_of_##mach_name##_desc

/* dai driver entry w/ playback and capture caps. If one direction is missing
 * then set the channels to 0.
 */
#define IMX_SOF_DAI_DRV_ENTRY(dai_name, pb_cmin, pb_cmax, cap_cmin, cap_cmax)	\
{										\
	.name = dai_name,							\
	.playback = {								\
		.channels_min = pb_cmin,					\
		.channels_max = pb_cmax,					\
	},									\
	.capture = {								\
		.channels_min = cap_cmin,					\
		.channels_max = cap_cmax,					\
	},									\
}

/* use if playback and capture have the same min/max channel count */
#define IMX_SOF_DAI_DRV_ENTRY_BIDIR(dai_name, cmin, cmax)\
	IMX_SOF_DAI_DRV_ENTRY(dai_name, cmin, cmax, cmin, cmax)

struct imx_ipc_info {
	/* true if core is able to write a panic code to the debug box */
	bool has_panic_code;
	/* offset to mailbox in which firmware initially writes FW_READY */
	int boot_mbox_offset;
	/* offset to region at which the mailboxes start */
	int window_offset;
};

struct imx_chip_ops {
	/* called after clocks and PDs are enabled */
	int (*probe)(struct snd_sof_dev *sdev);
	/* used directly by the SOF core */
	int (*core_kick)(struct snd_sof_dev *sdev);
	/* called during suspend()/remove() before clocks are disabled */
	int (*core_shutdown)(struct snd_sof_dev *sdev);
	/* used directly by the SOF core */
	int (*core_reset)(struct snd_sof_dev *sdev);
};

struct imx_memory_info {
	const char *name;
	bool reserved;
};

struct imx_chip_info {
	struct imx_ipc_info ipc_info;
	/* does the chip have a reserved memory region for DMA? */
	bool has_dma_reserved;
	struct imx_memory_info *memory;
	struct snd_soc_dai_driver *drv;
	int num_drv;
	/* optional */
	const struct imx_chip_ops *ops;
};

struct imx_common_data {
	struct platform_device *ipc_dev;
	struct imx_dsp_ipc *ipc_handle;
	/* core may have no clocks */
	struct clk_bulk_data *clks;
	int clk_num;
	/* core may have no PDs */
	struct dev_pm_domain_list *pd_list;
	void *chip_pdata;
};

static inline int imx_chip_core_kick(struct snd_sof_dev *sdev)
{
	const struct imx_chip_ops *ops = get_chip_info(sdev)->ops;

	if (ops && ops->core_kick)
		return ops->core_kick(sdev);

	return 0;
}

static inline int imx_chip_core_shutdown(struct snd_sof_dev *sdev)
{
	const struct imx_chip_ops *ops = get_chip_info(sdev)->ops;

	if (ops && ops->core_shutdown)
		return ops->core_shutdown(sdev);

	return 0;
}

static inline int imx_chip_core_reset(struct snd_sof_dev *sdev)
{
	const struct imx_chip_ops *ops = get_chip_info(sdev)->ops;

	if (ops && ops->core_reset)
		return ops->core_reset(sdev);

	return 0;
}

static inline int imx_chip_probe(struct snd_sof_dev *sdev)
{
	const struct imx_chip_ops *ops = get_chip_info(sdev)->ops;

	if (ops && ops->probe)
		return ops->probe(sdev);

	return 0;
}

void imx8_get_registers(struct snd_sof_dev *sdev,
			struct sof_ipc_dsp_oops_xtensa *xoops,
			struct sof_ipc_panic_info *panic_info,
			u32 *stack, size_t stack_words);

void imx8_dump(struct snd_sof_dev *sdev, u32 flags);

extern const struct snd_sof_dsp_ops sof_imx_ops;

#endif