1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2020 Intel Corporation. All rights reserved. 4 // 5 // Author: Cezary Rojewski <cezary.rojewski@intel.com> 6 // 7 8 #include <linux/slab.h> 9 #include "core.h" 10 #include "messages.h" 11 #include "registers.h" 12 13 int catpt_ipc_get_fw_version(struct catpt_dev *cdev, 14 struct catpt_fw_version *version) 15 { 16 union catpt_global_msg msg = CATPT_GLOBAL_MSG(GET_FW_VERSION); 17 struct catpt_ipc_msg request = {{0}}, reply; 18 int ret; 19 20 request.header = msg.val; 21 reply.size = sizeof(*version); 22 reply.data = version; 23 24 ret = catpt_dsp_send_msg(cdev, request, &reply); 25 if (ret) 26 dev_err(cdev->dev, "get fw version failed: %d\n", ret); 27 28 return ret; 29 } 30 31 struct catpt_alloc_stream_input { 32 enum catpt_path_id path_id:8; 33 enum catpt_stream_type stream_type:8; 34 enum catpt_format_id format_id:8; 35 u8 reserved; 36 struct catpt_audio_format input_format; 37 struct catpt_ring_info ring_info; 38 u8 num_entries; 39 /* flex array with entries here */ 40 struct catpt_memory_info persistent_mem; 41 struct catpt_memory_info scratch_mem; 42 u32 num_notifications; /* obsolete */ 43 } __packed; 44 45 int catpt_ipc_alloc_stream(struct catpt_dev *cdev, 46 enum catpt_path_id path_id, 47 enum catpt_stream_type type, 48 struct catpt_audio_format *afmt, 49 struct catpt_ring_info *rinfo, 50 u8 num_modules, 51 struct catpt_module_entry *modules, 52 struct resource *persistent, 53 struct resource *scratch, 54 struct catpt_stream_info *sinfo) 55 { 56 union catpt_global_msg msg = CATPT_GLOBAL_MSG(ALLOCATE_STREAM); 57 struct catpt_alloc_stream_input input; 58 struct catpt_ipc_msg request, reply; 59 size_t size, arrsz; 60 u8 *payload; 61 off_t off; 62 int ret; 63 64 off = offsetof(struct catpt_alloc_stream_input, persistent_mem); 65 arrsz = sizeof(*modules) * num_modules; 66 size = sizeof(input) + arrsz; 67 68 payload = kzalloc(size, GFP_KERNEL); 69 if (!payload) 70 return -ENOMEM; 71 72 memset(&input, 0, sizeof(input)); 73 input.path_id = path_id; 74 input.stream_type = type; 75 input.format_id = CATPT_FORMAT_PCM; 76 input.input_format = *afmt; 77 input.ring_info = *rinfo; 78 input.num_entries = num_modules; 79 input.persistent_mem.offset = catpt_to_dsp_offset(persistent->start); 80 input.persistent_mem.size = resource_size(persistent); 81 if (scratch) { 82 input.scratch_mem.offset = catpt_to_dsp_offset(scratch->start); 83 input.scratch_mem.size = resource_size(scratch); 84 } 85 86 /* re-arrange the input: account for flex array 'entries' */ 87 memcpy(payload, &input, sizeof(input)); 88 memmove(payload + off + arrsz, payload + off, sizeof(input) - off); 89 memcpy(payload + off, modules, arrsz); 90 91 request.header = msg.val; 92 request.size = size; 93 request.data = payload; 94 reply.size = sizeof(*sinfo); 95 reply.data = sinfo; 96 97 ret = catpt_dsp_send_msg(cdev, request, &reply); 98 if (ret) 99 dev_err(cdev->dev, "alloc stream type %d failed: %d\n", 100 type, ret); 101 102 kfree(payload); 103 return ret; 104 } 105 106 int catpt_ipc_free_stream(struct catpt_dev *cdev, u8 stream_hw_id) 107 { 108 union catpt_global_msg msg = CATPT_GLOBAL_MSG(FREE_STREAM); 109 struct catpt_ipc_msg request; 110 int ret; 111 112 request.header = msg.val; 113 request.size = sizeof(stream_hw_id); 114 request.data = &stream_hw_id; 115 116 ret = catpt_dsp_send_msg(cdev, request, NULL); 117 if (ret) 118 dev_err(cdev->dev, "free stream %d failed: %d\n", 119 stream_hw_id, ret); 120 121 return ret; 122 } 123 124 int catpt_ipc_set_device_format(struct catpt_dev *cdev, 125 struct catpt_ssp_device_format *devfmt) 126 { 127 union catpt_global_msg msg = CATPT_GLOBAL_MSG(SET_DEVICE_FORMATS); 128 struct catpt_ipc_msg request; 129 int ret; 130 131 request.header = msg.val; 132 request.size = sizeof(*devfmt); 133 request.data = devfmt; 134 135 ret = catpt_dsp_send_msg(cdev, request, NULL); 136 if (ret) 137 dev_err(cdev->dev, "set device format failed: %d\n", ret); 138 139 return ret; 140 } 141 142 int catpt_ipc_enter_dxstate(struct catpt_dev *cdev, enum catpt_dx_state state, 143 struct catpt_dx_context *context) 144 { 145 union catpt_global_msg msg = CATPT_GLOBAL_MSG(ENTER_DX_STATE); 146 struct catpt_ipc_msg request, reply; 147 int ret; 148 149 request.header = msg.val; 150 request.size = sizeof(state); 151 request.data = &state; 152 reply.size = sizeof(*context); 153 reply.data = context; 154 155 ret = catpt_dsp_send_msg(cdev, request, &reply); 156 if (ret) 157 dev_err(cdev->dev, "enter dx state failed: %d\n", ret); 158 159 return ret; 160 } 161 162 int catpt_ipc_get_mixer_stream_info(struct catpt_dev *cdev, 163 struct catpt_mixer_stream_info *info) 164 { 165 union catpt_global_msg msg = CATPT_GLOBAL_MSG(GET_MIXER_STREAM_INFO); 166 struct catpt_ipc_msg request = {{0}}, reply; 167 int ret; 168 169 request.header = msg.val; 170 reply.size = sizeof(*info); 171 reply.data = info; 172 173 ret = catpt_dsp_send_msg(cdev, request, &reply); 174 if (ret) 175 dev_err(cdev->dev, "get mixer info failed: %d\n", ret); 176 177 return ret; 178 } 179 180 int catpt_ipc_reset_stream(struct catpt_dev *cdev, u8 stream_hw_id) 181 { 182 union catpt_stream_msg msg = CATPT_STREAM_MSG(RESET_STREAM); 183 struct catpt_ipc_msg request = {{0}}; 184 int ret; 185 186 msg.stream_hw_id = stream_hw_id; 187 request.header = msg.val; 188 189 ret = catpt_dsp_send_msg(cdev, request, NULL); 190 if (ret) 191 dev_err(cdev->dev, "reset stream %d failed: %d\n", 192 stream_hw_id, ret); 193 194 return ret; 195 } 196 197 int catpt_ipc_pause_stream(struct catpt_dev *cdev, u8 stream_hw_id) 198 { 199 union catpt_stream_msg msg = CATPT_STREAM_MSG(PAUSE_STREAM); 200 struct catpt_ipc_msg request = {{0}}; 201 int ret; 202 203 msg.stream_hw_id = stream_hw_id; 204 request.header = msg.val; 205 206 ret = catpt_dsp_send_msg(cdev, request, NULL); 207 if (ret) 208 dev_err(cdev->dev, "pause stream %d failed: %d\n", 209 stream_hw_id, ret); 210 211 return ret; 212 } 213 214 int catpt_ipc_resume_stream(struct catpt_dev *cdev, u8 stream_hw_id) 215 { 216 union catpt_stream_msg msg = CATPT_STREAM_MSG(RESUME_STREAM); 217 struct catpt_ipc_msg request = {{0}}; 218 int ret; 219 220 msg.stream_hw_id = stream_hw_id; 221 request.header = msg.val; 222 223 ret = catpt_dsp_send_msg(cdev, request, NULL); 224 if (ret) 225 dev_err(cdev->dev, "resume stream %d failed: %d\n", 226 stream_hw_id, ret); 227 228 return ret; 229 } 230 231 struct catpt_set_volume_input { 232 u32 channel; 233 u32 target_volume; 234 u64 curve_duration; 235 u32 curve_type; 236 } __packed; 237 238 int catpt_ipc_set_volume(struct catpt_dev *cdev, u8 stream_hw_id, 239 u32 channel, u32 volume, 240 u32 curve_duration, 241 enum catpt_audio_curve_type curve_type) 242 { 243 union catpt_stream_msg msg = CATPT_STAGE_MSG(SET_VOLUME); 244 struct catpt_ipc_msg request; 245 struct catpt_set_volume_input input; 246 int ret; 247 248 msg.stream_hw_id = stream_hw_id; 249 input.channel = channel; 250 input.target_volume = volume; 251 input.curve_duration = curve_duration; 252 input.curve_type = curve_type; 253 254 request.header = msg.val; 255 request.size = sizeof(input); 256 request.data = &input; 257 258 ret = catpt_dsp_send_msg(cdev, request, NULL); 259 if (ret) 260 dev_err(cdev->dev, "set stream %d volume failed: %d\n", 261 stream_hw_id, ret); 262 263 return ret; 264 } 265 266 struct catpt_set_write_pos_input { 267 u32 new_write_pos; 268 bool end_of_buffer; 269 bool low_latency; 270 } __packed; 271 272 int catpt_ipc_set_write_pos(struct catpt_dev *cdev, u8 stream_hw_id, 273 u32 pos, bool eob, bool ll) 274 { 275 union catpt_stream_msg msg = CATPT_STAGE_MSG(SET_WRITE_POSITION); 276 struct catpt_ipc_msg request; 277 struct catpt_set_write_pos_input input; 278 int ret; 279 280 msg.stream_hw_id = stream_hw_id; 281 input.new_write_pos = pos; 282 input.end_of_buffer = eob; 283 input.low_latency = ll; 284 285 request.header = msg.val; 286 request.size = sizeof(input); 287 request.data = &input; 288 289 ret = catpt_dsp_send_msg(cdev, request, NULL); 290 if (ret) 291 dev_err(cdev->dev, "set stream %d write pos failed: %d\n", 292 stream_hw_id, ret); 293 294 return ret; 295 } 296 297 int catpt_ipc_mute_loopback(struct catpt_dev *cdev, u8 stream_hw_id, bool mute) 298 { 299 union catpt_stream_msg msg = CATPT_STAGE_MSG(MUTE_LOOPBACK); 300 struct catpt_ipc_msg request; 301 int ret; 302 303 msg.stream_hw_id = stream_hw_id; 304 request.header = msg.val; 305 request.size = sizeof(mute); 306 request.data = &mute; 307 308 ret = catpt_dsp_send_msg(cdev, request, NULL); 309 if (ret) 310 dev_err(cdev->dev, "mute loopback failed: %d\n", ret); 311 312 return ret; 313 } 314