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