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
|