1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. 3 // Copyright (c) 2018, Linaro Limited 4 5 #include <linux/device.h> 6 #include <linux/jiffies.h> 7 #include <linux/kernel.h> 8 #include <linux/kref.h> 9 #include <linux/module.h> 10 #include <linux/of.h> 11 #include <linux/of_platform.h> 12 #include <linux/platform_device.h> 13 #include <linux/sched.h> 14 #include <linux/slab.h> 15 #include <linux/soc/qcom/apr.h> 16 #include <linux/wait.h> 17 #include <sound/asound.h> 18 #include "q6adm.h" 19 #include "q6afe.h" 20 #include "q6core.h" 21 #include "q6dsp-common.h" 22 #include "q6dsp-errno.h" 23 24 #define ADM_CMD_DEVICE_OPEN_V5 0x00010326 25 #define ADM_CMDRSP_DEVICE_OPEN_V5 0x00010329 26 #define ADM_CMD_DEVICE_CLOSE_V5 0x00010327 27 #define ADM_CMD_MATRIX_MAP_ROUTINGS_V5 0x00010325 28 29 #define TIMEOUT_MS 1000 30 #define RESET_COPP_ID 99 31 #define INVALID_COPP_ID 0xFF 32 /* Definition for a legacy device session. */ 33 #define ADM_LEGACY_DEVICE_SESSION 0 34 #define ADM_MATRIX_ID_AUDIO_RX 0 35 #define ADM_MATRIX_ID_AUDIO_TX 1 36 37 struct q6copp { 38 int afe_port; 39 int copp_idx; 40 int id; 41 int topology; 42 int mode; 43 int rate; 44 int bit_width; 45 int channels; 46 int app_type; 47 int acdb_id; 48 49 struct aprv2_ibasic_rsp_result_t result; 50 struct kref refcount; 51 wait_queue_head_t wait; 52 struct list_head node; 53 struct q6adm *adm; 54 }; 55 56 struct q6adm { 57 struct apr_device *apr; 58 struct device *dev; 59 struct q6core_svc_api_info ainfo; 60 unsigned long copp_bitmap[AFE_MAX_PORTS]; 61 struct list_head copps_list; 62 spinlock_t copps_list_lock; 63 struct aprv2_ibasic_rsp_result_t result; 64 struct mutex lock; 65 wait_queue_head_t matrix_map_wait; 66 }; 67 68 struct q6adm_cmd_device_open_v5 { 69 u16 flags; 70 u16 mode_of_operation; 71 u16 endpoint_id_1; 72 u16 endpoint_id_2; 73 u32 topology_id; 74 u16 dev_num_channel; 75 u16 bit_width; 76 u32 sample_rate; 77 u8 dev_channel_mapping[8]; 78 } __packed; 79 80 struct q6adm_cmd_matrix_map_routings_v5 { 81 u32 matrix_id; 82 u32 num_sessions; 83 } __packed; 84 85 struct q6adm_session_map_node_v5 { 86 u16 session_id; 87 u16 num_copps; 88 } __packed; 89 90 static struct q6copp *q6adm_find_copp(struct q6adm *adm, int port_idx, 91 int copp_idx) 92 { 93 struct q6copp *c; 94 struct q6copp *ret = NULL; 95 unsigned long flags; 96 97 spin_lock_irqsave(&adm->copps_list_lock, flags); 98 list_for_each_entry(c, &adm->copps_list, node) { 99 if ((port_idx == c->afe_port) && (copp_idx == c->copp_idx)) { 100 ret = c; 101 kref_get(&c->refcount); 102 break; 103 } 104 } 105 106 spin_unlock_irqrestore(&adm->copps_list_lock, flags); 107 108 return ret; 109 110 } 111 112 static int q6adm_apr_send_copp_pkt(struct q6adm *adm, struct q6copp *copp, 113 struct apr_pkt *pkt, uint32_t rsp_opcode) 114 { 115 struct device *dev = adm->dev; 116 uint32_t opcode = pkt->hdr.opcode; 117 int ret; 118 119 mutex_lock(&adm->lock); 120 copp->result.opcode = 0; 121 copp->result.status = 0; 122 ret = apr_send_pkt(adm->apr, pkt); 123 if (ret < 0) { 124 dev_err(dev, "Failed to send APR packet\n"); 125 ret = -EINVAL; 126 goto err; 127 } 128 129 /* Wait for the callback with copp id */ 130 if (rsp_opcode) 131 ret = wait_event_timeout(copp->wait, 132 (copp->result.opcode == opcode) || 133 (copp->result.opcode == rsp_opcode), 134 msecs_to_jiffies(TIMEOUT_MS)); 135 else 136 ret = wait_event_timeout(copp->wait, 137 (copp->result.opcode == opcode), 138 msecs_to_jiffies(TIMEOUT_MS)); 139 140 if (!ret) { 141 dev_err(dev, "ADM copp cmd timedout\n"); 142 ret = -ETIMEDOUT; 143 } else if (copp->result.status > 0) { 144 dev_err(dev, "DSP returned error[%d]\n", 145 copp->result.status); 146 ret = -EINVAL; 147 } 148 149 err: 150 mutex_unlock(&adm->lock); 151 return ret; 152 } 153 154 static int q6adm_device_close(struct q6adm *adm, struct q6copp *copp, 155 int port_id, int copp_idx) 156 { 157 struct apr_pkt close; 158 159 close.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, 160 APR_HDR_LEN(APR_HDR_SIZE), 161 APR_PKT_VER); 162 close.hdr.pkt_size = sizeof(close); 163 close.hdr.src_port = port_id; 164 close.hdr.dest_port = copp->id; 165 close.hdr.token = port_id << 16 | copp_idx; 166 close.hdr.opcode = ADM_CMD_DEVICE_CLOSE_V5; 167 168 return q6adm_apr_send_copp_pkt(adm, copp, &close, 0); 169 } 170 171 static void q6adm_free_copp(struct kref *ref) 172 { 173 struct q6copp *c = container_of(ref, struct q6copp, refcount); 174 struct q6adm *adm = c->adm; 175 unsigned long flags; 176 int ret; 177 178 ret = q6adm_device_close(adm, c, c->afe_port, c->copp_idx); 179 if (ret < 0) 180 dev_err(adm->dev, "Failed to close copp %d\n", ret); 181 182 spin_lock_irqsave(&adm->copps_list_lock, flags); 183 clear_bit(c->copp_idx, &adm->copp_bitmap[c->afe_port]); 184 list_del(&c->node); 185 spin_unlock_irqrestore(&adm->copps_list_lock, flags); 186 kfree(c); 187 } 188 189 static int q6adm_callback(struct apr_device *adev, struct apr_resp_pkt *data) 190 { 191 struct aprv2_ibasic_rsp_result_t *result = data->payload; 192 int port_idx, copp_idx; 193 struct apr_hdr *hdr = &data->hdr; 194 struct q6copp *copp; 195 struct q6adm *adm = dev_get_drvdata(&adev->dev); 196 197 if (!data->payload_size) 198 return 0; 199 200 copp_idx = (hdr->token) & 0XFF; 201 port_idx = ((hdr->token) >> 16) & 0xFF; 202 if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) { 203 dev_err(&adev->dev, "Invalid port idx %d token %d\n", 204 port_idx, hdr->token); 205 return 0; 206 } 207 if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) { 208 dev_err(&adev->dev, "Invalid copp idx %d token %d\n", 209 copp_idx, hdr->token); 210 return 0; 211 } 212 213 switch (hdr->opcode) { 214 case APR_BASIC_RSP_RESULT: { 215 if (result->status != 0) { 216 dev_err(&adev->dev, "cmd = 0x%x return error = 0x%x\n", 217 result->opcode, result->status); 218 } 219 switch (result->opcode) { 220 case ADM_CMD_DEVICE_OPEN_V5: 221 case ADM_CMD_DEVICE_CLOSE_V5: 222 list_for_each_entry(copp, &adm->copps_list, node) { 223 if ((port_idx == copp->afe_port) && (copp_idx == copp->copp_idx)) { 224 copp->result = *result; 225 wake_up(&copp->wait); 226 break; 227 } 228 } 229 break; 230 case ADM_CMD_MATRIX_MAP_ROUTINGS_V5: 231 adm->result = *result; 232 wake_up(&adm->matrix_map_wait); 233 break; 234 235 default: 236 dev_err(&adev->dev, "Unknown Cmd: 0x%x\n", 237 result->opcode); 238 break; 239 } 240 return 0; 241 } 242 case ADM_CMDRSP_DEVICE_OPEN_V5: { 243 struct adm_cmd_rsp_device_open_v5 { 244 u32 status; 245 u16 copp_id; 246 u16 reserved; 247 } __packed *open = data->payload; 248 249 copp = q6adm_find_copp(adm, port_idx, copp_idx); 250 if (!copp) 251 return 0; 252 253 if (open->copp_id == INVALID_COPP_ID) { 254 dev_err(&adev->dev, "Invalid coppid rxed %d\n", 255 open->copp_id); 256 copp->result.status = ADSP_EBADPARAM; 257 wake_up(&copp->wait); 258 kref_put(&copp->refcount, q6adm_free_copp); 259 break; 260 } 261 copp->result.opcode = hdr->opcode; 262 copp->id = open->copp_id; 263 wake_up(&copp->wait); 264 kref_put(&copp->refcount, q6adm_free_copp); 265 } 266 break; 267 default: 268 dev_err(&adev->dev, "Unknown cmd:0x%x\n", 269 hdr->opcode); 270 break; 271 } 272 273 return 0; 274 } 275 276 static struct q6copp *q6adm_alloc_copp(struct q6adm *adm, int port_idx) 277 { 278 struct q6copp *c; 279 int idx; 280 281 idx = find_first_zero_bit(&adm->copp_bitmap[port_idx], 282 MAX_COPPS_PER_PORT); 283 284 if (idx >= MAX_COPPS_PER_PORT) 285 return ERR_PTR(-EBUSY); 286 287 c = kzalloc(sizeof(*c), GFP_ATOMIC); 288 if (!c) 289 return ERR_PTR(-ENOMEM); 290 291 set_bit(idx, &adm->copp_bitmap[port_idx]); 292 c->copp_idx = idx; 293 c->afe_port = port_idx; 294 c->adm = adm; 295 296 init_waitqueue_head(&c->wait); 297 298 return c; 299 } 300 301 static struct q6copp *q6adm_find_matching_copp(struct q6adm *adm, 302 int port_id, int topology, 303 int mode, int rate, 304 int channel_mode, int bit_width, 305 int app_type) 306 { 307 struct q6copp *c; 308 struct q6copp *ret = NULL; 309 unsigned long flags; 310 311 spin_lock_irqsave(&adm->copps_list_lock, flags); 312 313 list_for_each_entry(c, &adm->copps_list, node) { 314 if ((port_id == c->afe_port) && (topology == c->topology) && 315 (mode == c->mode) && (rate == c->rate) && 316 (bit_width == c->bit_width) && (app_type == c->app_type)) { 317 ret = c; 318 kref_get(&c->refcount); 319 } 320 } 321 spin_unlock_irqrestore(&adm->copps_list_lock, flags); 322 323 return ret; 324 } 325 326 static int q6adm_device_open(struct q6adm *adm, struct q6copp *copp, 327 int port_id, int path, int topology, 328 int channel_mode, int bit_width, int rate) 329 { 330 struct q6adm_cmd_device_open_v5 *open; 331 int afe_port = q6afe_get_port_id(port_id); 332 struct apr_pkt *pkt; 333 int ret, pkt_size = APR_HDR_SIZE + sizeof(*open); 334 void *p __free(kfree) = kzalloc(pkt_size, GFP_KERNEL); 335 if (!p) 336 return -ENOMEM; 337 338 pkt = p; 339 open = p + APR_HDR_SIZE; 340 pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, 341 APR_HDR_LEN(APR_HDR_SIZE), 342 APR_PKT_VER); 343 pkt->hdr.pkt_size = pkt_size; 344 pkt->hdr.src_port = afe_port; 345 pkt->hdr.dest_port = afe_port; 346 pkt->hdr.token = port_id << 16 | copp->copp_idx; 347 pkt->hdr.opcode = ADM_CMD_DEVICE_OPEN_V5; 348 open->flags = ADM_LEGACY_DEVICE_SESSION; 349 open->mode_of_operation = path; 350 open->endpoint_id_1 = afe_port; 351 open->topology_id = topology; 352 open->dev_num_channel = channel_mode & 0x00FF; 353 open->bit_width = bit_width; 354 open->sample_rate = rate; 355 356 ret = q6dsp_map_channels(&open->dev_channel_mapping[0], 357 channel_mode); 358 if (ret) 359 return ret; 360 361 return q6adm_apr_send_copp_pkt(adm, copp, pkt, ADM_CMDRSP_DEVICE_OPEN_V5); 362 } 363 364 /** 365 * q6adm_open() - open adm and grab a free copp 366 * 367 * @dev: Pointer to adm child device. 368 * @port_id: port id 369 * @path: playback or capture path. 370 * @rate: rate at which copp is required. 371 * @channel_mode: channel mode 372 * @topology: adm topology id 373 * @perf_mode: performace mode. 374 * @bit_width: audio sample bit width 375 * @app_type: Application type. 376 * @acdb_id: ACDB id 377 * 378 * Return: Will be an negative on error or a valid copp pointer on success. 379 */ 380 struct q6copp *q6adm_open(struct device *dev, int port_id, int path, int rate, 381 int channel_mode, int topology, int perf_mode, 382 uint16_t bit_width, int app_type, int acdb_id) 383 { 384 struct q6adm *adm = dev_get_drvdata(dev->parent); 385 struct q6copp *copp; 386 unsigned long flags; 387 int ret = 0; 388 389 if (port_id < 0) { 390 dev_err(dev, "Invalid port_id %d\n", port_id); 391 return ERR_PTR(-EINVAL); 392 } 393 394 copp = q6adm_find_matching_copp(adm, port_id, topology, perf_mode, 395 rate, channel_mode, bit_width, app_type); 396 if (copp) { 397 dev_err(dev, "Found Matching Copp 0x%x\n", copp->copp_idx); 398 return copp; 399 } 400 401 spin_lock_irqsave(&adm->copps_list_lock, flags); 402 copp = q6adm_alloc_copp(adm, port_id); 403 if (IS_ERR(copp)) { 404 spin_unlock_irqrestore(&adm->copps_list_lock, flags); 405 return ERR_CAST(copp); 406 } 407 408 list_add_tail(&copp->node, &adm->copps_list); 409 spin_unlock_irqrestore(&adm->copps_list_lock, flags); 410 411 kref_init(&copp->refcount); 412 copp->topology = topology; 413 copp->mode = perf_mode; 414 copp->rate = rate; 415 copp->channels = channel_mode; 416 copp->bit_width = bit_width; 417 copp->app_type = app_type; 418 419 ret = q6adm_device_open(adm, copp, port_id, path, topology, 420 channel_mode, bit_width, rate); 421 if (ret < 0) { 422 kref_put(&copp->refcount, q6adm_free_copp); 423 return ERR_PTR(ret); 424 } 425 426 return copp; 427 } 428 EXPORT_SYMBOL_GPL(q6adm_open); 429 430 /** 431 * q6adm_get_copp_id() - get copp index 432 * 433 * @copp: Pointer to valid copp 434 * 435 * Return: Will be an negative on error or a valid copp index on success. 436 **/ 437 int q6adm_get_copp_id(struct q6copp *copp) 438 { 439 if (!copp) 440 return -EINVAL; 441 442 return copp->copp_idx; 443 } 444 EXPORT_SYMBOL_GPL(q6adm_get_copp_id); 445 446 /** 447 * q6adm_matrix_map() - Map asm streams and afe ports using payload 448 * 449 * @dev: Pointer to adm child device. 450 * @path: playback or capture path. 451 * @payload_map: map between session id and afe ports. 452 * @perf_mode: Performace mode. 453 * 454 * Return: Will be an negative on error or a zero on success. 455 */ 456 int q6adm_matrix_map(struct device *dev, int path, 457 struct route_payload payload_map, int perf_mode) 458 { 459 struct q6adm *adm = dev_get_drvdata(dev->parent); 460 struct q6adm_cmd_matrix_map_routings_v5 *route; 461 struct q6adm_session_map_node_v5 *node; 462 struct apr_pkt *pkt; 463 uint16_t *copps_list; 464 int ret, i, copp_idx; 465 /* Assumes port_ids have already been validated during adm_open */ 466 struct q6copp *copp; 467 int pkt_size = (APR_HDR_SIZE + sizeof(*route) + sizeof(*node) + 468 (sizeof(uint32_t) * payload_map.num_copps)); 469 void *matrix_map __free(kfree) = kzalloc(pkt_size, GFP_KERNEL); 470 if (!matrix_map) 471 return -ENOMEM; 472 473 pkt = matrix_map; 474 route = matrix_map + APR_HDR_SIZE; 475 node = matrix_map + APR_HDR_SIZE + sizeof(*route); 476 copps_list = matrix_map + APR_HDR_SIZE + sizeof(*route) + sizeof(*node); 477 478 pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, 479 APR_HDR_LEN(APR_HDR_SIZE), 480 APR_PKT_VER); 481 pkt->hdr.pkt_size = pkt_size; 482 pkt->hdr.token = 0; 483 pkt->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5; 484 route->num_sessions = 1; 485 486 switch (path) { 487 case ADM_PATH_PLAYBACK: 488 route->matrix_id = ADM_MATRIX_ID_AUDIO_RX; 489 break; 490 case ADM_PATH_LIVE_REC: 491 route->matrix_id = ADM_MATRIX_ID_AUDIO_TX; 492 break; 493 default: 494 dev_err(dev, "Wrong path set[%d]\n", path); 495 break; 496 } 497 498 node->session_id = payload_map.session_id; 499 node->num_copps = payload_map.num_copps; 500 501 for (i = 0; i < payload_map.num_copps; i++) { 502 int port_idx = payload_map.port_id[i]; 503 504 if (port_idx < 0) { 505 dev_err(dev, "Invalid port_id %d\n", 506 payload_map.port_id[i]); 507 return -EINVAL; 508 } 509 copp_idx = payload_map.copp_idx[i]; 510 511 copp = q6adm_find_copp(adm, port_idx, copp_idx); 512 if (!copp) 513 return -EINVAL; 514 515 copps_list[i] = copp->id; 516 kref_put(&copp->refcount, q6adm_free_copp); 517 } 518 519 mutex_lock(&adm->lock); 520 adm->result.status = 0; 521 adm->result.opcode = 0; 522 523 ret = apr_send_pkt(adm->apr, pkt); 524 if (ret < 0) { 525 dev_err(dev, "routing for stream %d failed ret %d\n", 526 payload_map.session_id, ret); 527 goto fail_cmd; 528 } 529 ret = wait_event_timeout(adm->matrix_map_wait, 530 adm->result.opcode == pkt->hdr.opcode, 531 msecs_to_jiffies(TIMEOUT_MS)); 532 if (!ret) { 533 dev_err(dev, "routing for stream %d failed\n", 534 payload_map.session_id); 535 ret = -ETIMEDOUT; 536 goto fail_cmd; 537 } else if (adm->result.status > 0) { 538 dev_err(dev, "DSP returned error[%d]\n", 539 adm->result.status); 540 ret = -EINVAL; 541 goto fail_cmd; 542 } 543 544 fail_cmd: 545 mutex_unlock(&adm->lock); 546 return ret; 547 } 548 EXPORT_SYMBOL_GPL(q6adm_matrix_map); 549 550 /** 551 * q6adm_close() - Close adm copp 552 * 553 * @dev: Pointer to adm child device. 554 * @copp: pointer to previously opened copp 555 * 556 * Return: Will be an negative on error or a zero on success. 557 */ 558 int q6adm_close(struct device *dev, struct q6copp *copp) 559 { 560 kref_put(&copp->refcount, q6adm_free_copp); 561 562 return 0; 563 } 564 EXPORT_SYMBOL_GPL(q6adm_close); 565 566 static int q6adm_probe(struct apr_device *adev) 567 { 568 struct device *dev = &adev->dev; 569 struct q6adm *adm; 570 571 adm = devm_kzalloc(dev, sizeof(*adm), GFP_KERNEL); 572 if (!adm) 573 return -ENOMEM; 574 575 adm->apr = adev; 576 dev_set_drvdata(dev, adm); 577 adm->dev = dev; 578 q6core_get_svc_api_info(adev->svc_id, &adm->ainfo); 579 mutex_init(&adm->lock); 580 init_waitqueue_head(&adm->matrix_map_wait); 581 582 INIT_LIST_HEAD(&adm->copps_list); 583 spin_lock_init(&adm->copps_list_lock); 584 585 return devm_of_platform_populate(dev); 586 } 587 588 #ifdef CONFIG_OF 589 static const struct of_device_id q6adm_device_id[] = { 590 { .compatible = "qcom,q6adm" }, 591 {}, 592 }; 593 MODULE_DEVICE_TABLE(of, q6adm_device_id); 594 #endif 595 596 static struct apr_driver qcom_q6adm_driver = { 597 .probe = q6adm_probe, 598 .callback = q6adm_callback, 599 .driver = { 600 .name = "qcom-q6adm", 601 .of_match_table = of_match_ptr(q6adm_device_id), 602 }, 603 }; 604 605 module_apr_driver(qcom_q6adm_driver); 606 MODULE_DESCRIPTION("Q6 Audio Device Manager"); 607 MODULE_LICENSE("GPL v2"); 608