linux/sound/soc/intel/catpt/messages.c
<<
>>
Prefs
   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
  13int 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
  31struct 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
  45int 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
 106int 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
 124int 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
 142int 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
 162int 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
 180int 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
 197int 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
 214int 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
 231struct catpt_set_volume_input {
 232        u32 channel;
 233        u32 target_volume;
 234        u64 curve_duration;
 235        u32 curve_type;
 236} __packed;
 237
 238int 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
 266struct catpt_set_write_pos_input {
 267        u32 new_write_pos;
 268        bool end_of_buffer;
 269        bool low_latency;
 270} __packed;
 271
 272int 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
 297int 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