Loading...
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 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | /* * Copyright (c) 2018, NXP * * SPDX-License-Identifier: Apache-2.0 */ #include <errno.h> #include <string.h> #include <device.h> #include <soc.h> #include <drivers/ipm.h> #include <mu_imx.h> #define MU(config) ((MU_Type *)config->base) #if ((CONFIG_IPM_IMX_MAX_DATA_SIZE % 4) != 0) #error CONFIG_IPM_IMX_MAX_DATA_SIZE is invalid #endif #define IMX_IPM_DATA_REGS (CONFIG_IPM_IMX_MAX_DATA_SIZE / 4) struct imx_mu_config { MU_Type *base; void (*irq_config_func)(struct device *dev); }; struct imx_mu_data { ipm_callback_t callback; void *callback_ctx; }; static void imx_mu_isr(void *arg) { struct device *dev = (struct device *)arg; const struct imx_mu_config *config = dev->config->config_info; MU_Type *base = MU(config); struct imx_mu_data *data = dev->driver_data; u32_t data32[IMX_IPM_DATA_REGS]; u32_t status_reg; s32_t id; s32_t i; bool all_registers_full; status_reg = base->SR >>= MU_SR_RFn_SHIFT; for (id = CONFIG_IPM_IMX_MAX_ID_VAL; id >= 0; id--) { if (status_reg & 0x1U) { /* * Check if all receive registers are full. If not, * it is violation of the protocol (status register * are set earlier than all receive registers). * Do not read any of the registers in such situation. */ all_registers_full = true; for (i = 0; i < IMX_IPM_DATA_REGS; i++) { if (!MU_IsRxFull(base, (id * IMX_IPM_DATA_REGS) + i)) { all_registers_full = false; break; } } if (all_registers_full) { for (i = 0; i < IMX_IPM_DATA_REGS; i++) { MU_ReceiveMsg(base, (id * IMX_IPM_DATA_REGS) + i, &data32[i]); } if (data->callback) { data->callback(data->callback_ctx, (u32_t)id, &data32[0]); } } } status_reg >>= IMX_IPM_DATA_REGS; } /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F * Store immediate overlapping exception return operation * might vector to incorrect interrupt */ #if defined __CORTEX_M && (__CORTEX_M == 4U) __DSB(); #endif } static int imx_mu_ipm_send(struct device *dev, int wait, u32_t id, const void *data, int size) { const struct imx_mu_config *config = dev->config->config_info; MU_Type *base = MU(config); u32_t data32[IMX_IPM_DATA_REGS]; mu_status_t status; int i; if (id > CONFIG_IPM_IMX_MAX_ID_VAL) { return -EINVAL; } if (size > CONFIG_IPM_IMX_MAX_DATA_SIZE) { return -EMSGSIZE; } /* Actual message is passing using 32 bits registers */ memcpy(data32, data, size); for (i = 0; i < IMX_IPM_DATA_REGS; i++) { status = MU_TrySendMsg(base, id * IMX_IPM_DATA_REGS + i, data32[i]); if (status == kStatus_MU_TxNotEmpty) { return -EBUSY; } } if (wait) { while (!MU_IsTxEmpty(base, (id * IMX_IPM_DATA_REGS) + IMX_IPM_DATA_REGS - 1)) { } } return 0; } static int imx_mu_ipm_max_data_size_get(struct device *dev) { ARG_UNUSED(dev); return CONFIG_IPM_IMX_MAX_DATA_SIZE; } static u32_t imx_mu_ipm_max_id_val_get(struct device *dev) { ARG_UNUSED(dev); return CONFIG_IPM_IMX_MAX_ID_VAL; } static void imx_mu_ipm_register_callback(struct device *dev, ipm_callback_t cb, void *context) { struct imx_mu_data *driver_data = dev->driver_data; driver_data->callback = cb; driver_data->callback_ctx = context; } static int imx_mu_ipm_set_enabled(struct device *dev, int enable) { const struct imx_mu_config *config = dev->config->config_info; MU_Type *base = MU(config); #if CONFIG_IPM_IMX_MAX_DATA_SIZE_4 if (enable) { MU_EnableRxFullInt(base, 0U); MU_EnableRxFullInt(base, 1U); MU_EnableRxFullInt(base, 2U); MU_EnableRxFullInt(base, 3U); } else { MU_DisableRxFullInt(base, 0U); MU_DisableRxFullInt(base, 1U); MU_DisableRxFullInt(base, 2U); MU_DisableRxFullInt(base, 3U); } #elif CONFIG_IPM_IMX_MAX_DATA_SIZE_8 if (enable) { MU_EnableRxFullInt(base, 1U); MU_EnableRxFullInt(base, 3U); } else { MU_DisableRxFullInt(base, 1U); MU_DisableRxFullInt(base, 3U); } #elif CONFIG_IPM_IMX_MAX_DATA_SIZE_16 if (enable) { MU_EnableRxFullInt(base, 3U); } else { MU_DisableRxFullInt(base, 3U); } #else #error "CONFIG_IPM_IMX_MAX_DATA_SIZE_n is not set" #endif return 0; } static int imx_mu_init(struct device *dev) { const struct imx_mu_config *config = dev->config->config_info; MU_Init(MU(config)); config->irq_config_func(dev); return 0; } static const struct ipm_driver_api imx_mu_driver_api = { .send = imx_mu_ipm_send, .register_callback = imx_mu_ipm_register_callback, .max_data_size_get = imx_mu_ipm_max_data_size_get, .max_id_val_get = imx_mu_ipm_max_id_val_get, .set_enabled = imx_mu_ipm_set_enabled }; /* Config MU */ static void imx_mu_config_func_b(struct device *dev); static const struct imx_mu_config imx_mu_b_config = { .base = (MU_Type *)DT_IPM_IMX_MU_B_BASE_ADDRESS, .irq_config_func = imx_mu_config_func_b, }; static struct imx_mu_data imx_mu_b_data; DEVICE_AND_API_INIT(mu_b, DT_IPM_IMX_MU_B_NAME, &imx_mu_init, &imx_mu_b_data, &imx_mu_b_config, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &imx_mu_driver_api); static void imx_mu_config_func_b(struct device *dev) { IRQ_CONNECT(DT_IPM_IMX_MU_B_IRQ, DT_IPM_IMX_MU_B_IRQ_PRI, imx_mu_isr, DEVICE_GET(mu_b), 0); irq_enable(DT_IPM_IMX_MU_B_IRQ); } |