1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2020 Intel Corporation 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 19 request.header = msg.val; 20 reply.size = sizeof(*version); 21 reply.data = version; 22 23 return catpt_dsp_send_msg(cdev, request, &reply, "get fw version"); 24 } 25 26 struct catpt_alloc_stream_input { 27 enum catpt_path_id path_id:8; 28 enum catpt_stream_type stream_type:8; 29 enum catpt_format_id format_id:8; 30 u8 reserved; 31 struct catpt_audio_format input_format; 32 struct catpt_ring_info ring_info; 33 u8 num_entries; 34 /* flex array with entries here */ 35 struct catpt_memory_info persistent_mem; 36 struct catpt_memory_info scratch_mem; 37 u32 num_notifications; /* obsolete */ 38 } __packed; 39 40 int catpt_ipc_alloc_stream(struct catpt_dev *cdev, 41 enum catpt_path_id path_id, 42 enum catpt_stream_type type, 43 struct catpt_audio_format *afmt, 44 struct catpt_ring_info *rinfo, 45 u8 num_modules, 46 struct catpt_module_entry *modules, 47 struct resource *persistent, 48 struct resource *scratch, 49 struct catpt_stream_info *sinfo) 50 { 51 union catpt_global_msg msg = CATPT_GLOBAL_MSG(ALLOCATE_STREAM); 52 struct catpt_alloc_stream_input input; 53 struct catpt_ipc_msg request, reply; 54 size_t size, arrsz; 55 u8 *payload; 56 off_t off; 57 int ret; 58 59 off = offsetof(struct catpt_alloc_stream_input, persistent_mem); 60 arrsz = sizeof(*modules) * num_modules; 61 size = sizeof(input) + arrsz; 62 63 payload = kzalloc(size, GFP_KERNEL); 64 if (!payload) 65 return -ENOMEM; 66 67 memset(&input, 0, sizeof(input)); 68 input.path_id = path_id; 69 input.stream_type = type; 70 input.format_id = CATPT_FORMAT_PCM; 71 input.input_format = *afmt; 72 input.ring_info = *rinfo; 73 input.num_entries = num_modules; 74 input.persistent_mem.offset = catpt_to_dsp_offset(persistent->start); 75 input.persistent_mem.size = resource_size(persistent); 76 if (scratch) { 77 input.scratch_mem.offset = catpt_to_dsp_offset(scratch->start); 78 input.scratch_mem.size = resource_size(scratch); 79 } 80 81 /* re-arrange the input: account for flex array 'entries' */ 82 memcpy(payload, &input, sizeof(input)); 83 memmove(payload + off + arrsz, payload + off, sizeof(input) - off); 84 memcpy(payload + off, modules, arrsz); 85 86 request.header = msg.val; 87 request.size = size; 88 request.data = payload; 89 reply.size = sizeof(*sinfo); 90 reply.data = sinfo; 91 92 ret = catpt_dsp_send_msg(cdev, request, &reply, "alloc stream"); 93 kfree(payload); 94 return ret; 95 } 96 97 int catpt_ipc_free_stream(struct catpt_dev *cdev, u8 stream_hw_id) 98 { 99 union catpt_global_msg msg = CATPT_GLOBAL_MSG(FREE_STREAM); 100 struct catpt_ipc_msg request; 101 102 request.header = msg.val; 103 request.size = sizeof(stream_hw_id); 104 request.data = &stream_hw_id; 105 106 return catpt_dsp_send_msg(cdev, request, NULL, "free stream"); 107 } 108 109 int catpt_ipc_set_device_format(struct catpt_dev *cdev, 110 struct catpt_ssp_device_format *devfmt) 111 { 112 union catpt_global_msg msg = CATPT_GLOBAL_MSG(SET_DEVICE_FORMATS); 113 struct catpt_ipc_msg request; 114 115 request.header = msg.val; 116 request.size = sizeof(*devfmt); 117 request.data = devfmt; 118 119 return catpt_dsp_send_msg(cdev, request, NULL, "set device format"); 120 } 121 122 int catpt_ipc_enter_dxstate(struct catpt_dev *cdev, enum catpt_dx_state state, 123 struct catpt_dx_context *context) 124 { 125 union catpt_global_msg msg = CATPT_GLOBAL_MSG(ENTER_DX_STATE); 126 struct catpt_ipc_msg request, reply; 127 128 request.header = msg.val; 129 request.size = sizeof(state); 130 request.data = &state; 131 reply.size = sizeof(*context); 132 reply.data = context; 133 134 return catpt_dsp_send_msg(cdev, request, &reply, "enter dx state"); 135 } 136 137 int catpt_ipc_get_mixer_stream_info(struct catpt_dev *cdev, 138 struct catpt_mixer_stream_info *info) 139 { 140 union catpt_global_msg msg = CATPT_GLOBAL_MSG(GET_MIXER_STREAM_INFO); 141 struct catpt_ipc_msg request = {{0}}, reply; 142 143 request.header = msg.val; 144 reply.size = sizeof(*info); 145 reply.data = info; 146 147 return catpt_dsp_send_msg(cdev, request, &reply, "get mixer info"); 148 } 149 150 int catpt_ipc_reset_stream(struct catpt_dev *cdev, u8 stream_hw_id) 151 { 152 union catpt_stream_msg msg = CATPT_STREAM_MSG(RESET_STREAM); 153 struct catpt_ipc_msg request = {{0}}; 154 155 msg.stream_hw_id = stream_hw_id; 156 request.header = msg.val; 157 158 return catpt_dsp_send_msg(cdev, request, NULL, "reset stream"); 159 } 160 161 int catpt_ipc_pause_stream(struct catpt_dev *cdev, u8 stream_hw_id) 162 { 163 union catpt_stream_msg msg = CATPT_STREAM_MSG(PAUSE_STREAM); 164 struct catpt_ipc_msg request = {{0}}; 165 166 msg.stream_hw_id = stream_hw_id; 167 request.header = msg.val; 168 169 return catpt_dsp_send_msg(cdev, request, NULL, "pause stream"); 170 } 171 172 int catpt_ipc_resume_stream(struct catpt_dev *cdev, u8 stream_hw_id) 173 { 174 union catpt_stream_msg msg = CATPT_STREAM_MSG(RESUME_STREAM); 175 struct catpt_ipc_msg request = {{0}}; 176 177 msg.stream_hw_id = stream_hw_id; 178 request.header = msg.val; 179 180 return catpt_dsp_send_msg(cdev, request, NULL, "resume stream"); 181 } 182 183 struct catpt_set_volume_input { 184 u32 channel; 185 u32 target_volume; 186 u64 curve_duration; 187 u32 curve_type; 188 } __packed; 189 190 int catpt_ipc_set_volume(struct catpt_dev *cdev, u8 stream_hw_id, 191 u32 channel, u32 volume, 192 u32 curve_duration, 193 enum catpt_audio_curve_type curve_type) 194 { 195 union catpt_stream_msg msg = CATPT_STAGE_MSG(SET_VOLUME); 196 struct catpt_ipc_msg request; 197 struct catpt_set_volume_input input; 198 199 msg.stream_hw_id = stream_hw_id; 200 input.channel = channel; 201 input.target_volume = volume; 202 input.curve_duration = curve_duration; 203 input.curve_type = curve_type; 204 205 request.header = msg.val; 206 request.size = sizeof(input); 207 request.data = &input; 208 209 return catpt_dsp_send_msg(cdev, request, NULL, "set stream volume"); 210 } 211 212 struct catpt_set_write_pos_input { 213 u32 new_write_pos; 214 bool end_of_buffer; 215 bool low_latency; 216 } __packed; 217 218 int catpt_ipc_set_write_pos(struct catpt_dev *cdev, u8 stream_hw_id, 219 u32 pos, bool eob, bool ll) 220 { 221 union catpt_stream_msg msg = CATPT_STAGE_MSG(SET_WRITE_POSITION); 222 struct catpt_ipc_msg request; 223 struct catpt_set_write_pos_input input; 224 225 msg.stream_hw_id = stream_hw_id; 226 input.new_write_pos = pos; 227 input.end_of_buffer = eob; 228 input.low_latency = ll; 229 230 request.header = msg.val; 231 request.size = sizeof(input); 232 request.data = &input; 233 234 return catpt_dsp_send_msg(cdev, request, NULL, "set stream write pos"); 235 } 236 237 int catpt_ipc_mute_loopback(struct catpt_dev *cdev, u8 stream_hw_id, bool mute) 238 { 239 union catpt_stream_msg msg = CATPT_STAGE_MSG(MUTE_LOOPBACK); 240 struct catpt_ipc_msg request; 241 242 msg.stream_hw_id = stream_hw_id; 243 request.header = msg.val; 244 request.size = sizeof(mute); 245 request.data = &mute; 246 247 return catpt_dsp_send_msg(cdev, request, NULL, "mute loopback"); 248 } 249