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