Lines Matching +full:mhu +full:- +full:rx

1 // SPDX-License-Identifier: GPL-2.0-only
6 * and the Application Processors(AP). The Message Handling Unit(MHU)
7 * provides a mechanism for inter-processor communication between SCP's
207 -1, /* GET_CLOCK_INFO */
216 -1, /* SET_DEVICE_PWR_STATE */
217 -1, /* GET_DEVICE_PWR_STATE */
240 spinlock_t rx_lock; /* locking for the rx pending list */
259 * The SCP firmware only executes in little-endian mode, so any buffers
260 * shared through SCPI should have their contents converted to little-endian
332 -EINVAL, /* SCPI_ERR_PARAM */
333 -ENOEXEC, /* SCPI_ERR_ALIGN */
334 -EMSGSIZE, /* SCPI_ERR_SIZE */
335 -EINVAL, /* SCPI_ERR_HANDLER */
336 -EACCES, /* SCPI_ERR_ACCESS */
337 -ERANGE, /* SCPI_ERR_RANGE */
338 -ETIMEDOUT, /* SCPI_ERR_TIMEOUT */
339 -ENOMEM, /* SCPI_ERR_NOMEM */
340 -EINVAL, /* SCPI_ERR_PWRSTATE */
341 -EOPNOTSUPP, /* SCPI_ERR_SUPPORT */
342 -EIO, /* SCPI_ERR_DEVICE */
343 -EBUSY, /* SCPI_ERR_BUSY */
350 return -EIO; in scpi_to_linux_errno()
358 spin_lock_irqsave(&ch->rx_lock, flags); in scpi_process_cmd()
359 if (list_empty(&ch->rx_pending)) { in scpi_process_cmd()
360 spin_unlock_irqrestore(&ch->rx_lock, flags); in scpi_process_cmd()
365 * We should consider that command is the head of pending RX commands in scpi_process_cmd()
368 if (scpi_info->is_legacy) { in scpi_process_cmd()
369 match = list_first_entry(&ch->rx_pending, struct scpi_xfer, in scpi_process_cmd()
371 list_del(&match->node); in scpi_process_cmd()
373 list_for_each_entry(t, &ch->rx_pending, node) in scpi_process_cmd()
374 if (CMD_XTRACT_UNIQ(t->cmd) == CMD_XTRACT_UNIQ(cmd)) { in scpi_process_cmd()
375 list_del(&t->node); in scpi_process_cmd()
380 /* check if wait_for_completion is in progress or timed-out */ in scpi_process_cmd()
381 if (match && !completion_done(&match->done)) { in scpi_process_cmd()
384 if (scpi_info->is_legacy) { in scpi_process_cmd()
386 ch->rx_payload; in scpi_process_cmd()
388 /* RX Length is not replied by the legacy Firmware */ in scpi_process_cmd()
389 len = match->rx_len; in scpi_process_cmd()
391 match->status = ioread32(&mem->status); in scpi_process_cmd()
392 memcpy_fromio(match->rx_buf, mem->payload, len); in scpi_process_cmd()
394 struct scpi_shared_mem __iomem *mem = ch->rx_payload; in scpi_process_cmd()
396 len = min_t(unsigned int, match->rx_len, CMD_SIZE(cmd)); in scpi_process_cmd()
398 match->status = ioread32(&mem->status); in scpi_process_cmd()
399 memcpy_fromio(match->rx_buf, mem->payload, len); in scpi_process_cmd()
402 if (match->rx_len > len) in scpi_process_cmd()
403 memset(match->rx_buf + len, 0, match->rx_len - len); in scpi_process_cmd()
404 complete(&match->done); in scpi_process_cmd()
406 spin_unlock_irqrestore(&ch->rx_lock, flags); in scpi_process_cmd()
412 struct scpi_shared_mem __iomem *mem = ch->rx_payload; in scpi_handle_remote_msg()
415 if (!scpi_info->is_legacy) in scpi_handle_remote_msg()
416 cmd = ioread32(&mem->command); in scpi_handle_remote_msg()
426 struct scpi_shared_mem __iomem *mem = ch->tx_payload; in scpi_tx_prepare()
428 if (t->tx_buf) { in scpi_tx_prepare()
429 if (scpi_info->is_legacy) in scpi_tx_prepare()
430 memcpy_toio(ch->tx_payload, t->tx_buf, t->tx_len); in scpi_tx_prepare()
432 memcpy_toio(mem->payload, t->tx_buf, t->tx_len); in scpi_tx_prepare()
435 if (t->rx_buf) { in scpi_tx_prepare()
436 if (!(++ch->token)) in scpi_tx_prepare()
437 ++ch->token; in scpi_tx_prepare()
438 t->cmd |= FIELD_PREP(CMD_TOKEN_ID_MASK, ch->token); in scpi_tx_prepare()
439 spin_lock_irqsave(&ch->rx_lock, flags); in scpi_tx_prepare()
440 list_add_tail(&t->node, &ch->rx_pending); in scpi_tx_prepare()
441 spin_unlock_irqrestore(&ch->rx_lock, flags); in scpi_tx_prepare()
444 if (!scpi_info->is_legacy) in scpi_tx_prepare()
445 iowrite32(t->cmd, &mem->command); in scpi_tx_prepare()
452 mutex_lock(&ch->xfers_lock); in get_scpi_xfer()
453 if (list_empty(&ch->xfers_list)) { in get_scpi_xfer()
454 mutex_unlock(&ch->xfers_lock); in get_scpi_xfer()
457 t = list_first_entry(&ch->xfers_list, struct scpi_xfer, node); in get_scpi_xfer()
458 list_del(&t->node); in get_scpi_xfer()
459 mutex_unlock(&ch->xfers_lock); in get_scpi_xfer()
465 mutex_lock(&ch->xfers_lock); in put_scpi_xfer()
466 list_add_tail(&t->node, &ch->xfers_list); in put_scpi_xfer()
467 mutex_unlock(&ch->xfers_lock); in put_scpi_xfer()
479 if (scpi_info->commands[idx] < 0) in scpi_send_message()
480 return -EOPNOTSUPP; in scpi_send_message()
482 cmd = scpi_info->commands[idx]; in scpi_send_message()
484 if (scpi_info->is_legacy) in scpi_send_message()
485 chan = test_bit(cmd, scpi_info->cmd_priority) ? 1 : 0; in scpi_send_message()
487 chan = atomic_inc_return(&scpi_info->next_chan) % in scpi_send_message()
488 scpi_info->num_chans; in scpi_send_message()
489 scpi_chan = scpi_info->channels + chan; in scpi_send_message()
493 return -ENOMEM; in scpi_send_message()
495 if (scpi_info->is_legacy) { in scpi_send_message()
496 msg->cmd = PACK_LEGACY_SCPI_CMD(cmd, tx_len); in scpi_send_message()
497 msg->slot = msg->cmd; in scpi_send_message()
499 msg->slot = BIT(SCPI_SLOT); in scpi_send_message()
500 msg->cmd = PACK_SCPI_CMD(cmd, tx_len); in scpi_send_message()
502 msg->tx_buf = tx_buf; in scpi_send_message()
503 msg->tx_len = tx_len; in scpi_send_message()
504 msg->rx_buf = rx_buf; in scpi_send_message()
505 msg->rx_len = rx_len; in scpi_send_message()
506 reinit_completion(&msg->done); in scpi_send_message()
508 ret = mbox_send_message(scpi_chan->chan, msg); in scpi_send_message()
512 if (!wait_for_completion_timeout(&msg->done, MAX_RX_TIMEOUT)) in scpi_send_message()
513 ret = -ETIMEDOUT; in scpi_send_message()
516 ret = msg->status; in scpi_send_message()
518 if (ret < 0 && rx_buf) /* remove entry from the list if timed-out */ in scpi_send_message()
519 scpi_process_cmd(scpi_chan, msg->cmd); in scpi_send_message()
528 return scpi_info->protocol_version; in scpi_get_version()
609 return t1->freq - t2->freq; in opp_cmp_func()
620 return ERR_PTR(-EINVAL); in scpi_dvfs_get_info()
622 if (scpi_info->dvfs[domain]) /* data already populated */ in scpi_dvfs_get_info()
623 return scpi_info->dvfs[domain]; in scpi_dvfs_get_info()
632 return ERR_PTR(-ENOMEM); in scpi_dvfs_get_info()
634 info->count = buf.opp_count; in scpi_dvfs_get_info()
635 info->latency = le16_to_cpu(buf.latency) * 1000; /* uS to nS */ in scpi_dvfs_get_info()
637 info->opps = kcalloc(info->count, sizeof(*opp), GFP_KERNEL); in scpi_dvfs_get_info()
638 if (!info->opps) { in scpi_dvfs_get_info()
640 return ERR_PTR(-ENOMEM); in scpi_dvfs_get_info()
643 for (i = 0, opp = info->opps; i < info->count; i++, opp++) { in scpi_dvfs_get_info()
644 opp->freq = le32_to_cpu(buf.opps[i].freq); in scpi_dvfs_get_info()
645 opp->m_volt = le32_to_cpu(buf.opps[i].m_volt); in scpi_dvfs_get_info()
648 sort(info->opps, info->count, sizeof(*opp), opp_cmp_func, NULL); in scpi_dvfs_get_info()
650 scpi_info->dvfs[domain] = info; in scpi_dvfs_get_info()
658 if (of_parse_phandle_with_args(dev->of_node, "clocks", "#clock-cells", in scpi_dev_domain_id()
660 return -EINVAL; in scpi_dev_domain_id()
682 return info->latency; in scpi_dvfs_get_transition_latency()
694 if (!info->opps) in scpi_dvfs_add_opps_to_device()
695 return -EIO; in scpi_dvfs_add_opps_to_device()
697 for (opp = info->opps, idx = 0; idx < info->count; idx++, opp++) { in scpi_dvfs_add_opps_to_device()
698 ret = dev_pm_opp_add(dev, opp->freq, opp->m_volt * 1000); in scpi_dvfs_add_opps_to_device()
701 opp->freq, opp->m_volt); in scpi_dvfs_add_opps_to_device()
702 while (idx-- > 0) in scpi_dvfs_add_opps_to_device()
703 dev_pm_opp_remove(dev, (--opp)->freq); in scpi_dvfs_add_opps_to_device()
733 info->sensor_id = le16_to_cpu(_info.sensor_id); in scpi_sensor_get_info()
750 if (scpi_info->is_legacy) in scpi_sensor_get_value()
751 /* only 32-bits supported, upper 32 bits can be junk */ in scpi_sensor_get_value()
802 return scpi_info ? scpi_info->scpi_ops : NULL; in get_scpi_ops()
814 info->protocol_version = le32_to_cpu(caps.protocol_version); in scpi_init_versions()
815 info->firmware_version = le32_to_cpu(caps.platform_version); in scpi_init_versions()
818 if (info->is_legacy && ret == -EOPNOTSUPP) in scpi_init_versions()
830 FIELD_GET(PROTO_REV_MAJOR_MASK, scpi_info->protocol_version), in protocol_version_show()
831 FIELD_GET(PROTO_REV_MINOR_MASK, scpi_info->protocol_version)); in protocol_version_show()
841 FIELD_GET(FW_REV_MAJOR_MASK, scpi_info->firmware_version), in firmware_version_show()
842 FIELD_GET(FW_REV_MINOR_MASK, scpi_info->firmware_version), in firmware_version_show()
843 FIELD_GET(FW_REV_PATCH_MASK, scpi_info->firmware_version)); in firmware_version_show()
859 for (i = 0; i < info->num_chans; i++) in scpi_free_channels()
860 mbox_free_channel(info->channels[i].chan); in scpi_free_channels()
870 for (i = 0; i < MAX_DVFS_DOMAINS && info->dvfs[i]; i++) { in scpi_remove()
871 kfree(info->dvfs[i]->opps); in scpi_remove()
872 kfree(info->dvfs[i]); in scpi_remove()
886 return -ENOMEM; in scpi_alloc_xfer_list()
888 ch->xfers = xfers; in scpi_alloc_xfer_list()
890 init_completion(&xfers->done); in scpi_alloc_xfer_list()
891 list_add_tail(&xfers->node, &ch->xfers_list); in scpi_alloc_xfer_list()
898 {.compatible = "arm,scpi-pre-1.0"},
903 { .compatible = "amlogic,meson-gxbb-scp-shmem", },
904 { .compatible = "amlogic,meson-axg-scp-shmem", },
905 { .compatible = "arm,juno-scp-shmem", },
906 { .compatible = "arm,scp-shmem", },
914 struct device *dev = &pdev->dev; in scpi_probe()
915 struct device_node *np = dev->of_node; in scpi_probe()
920 return -ENOMEM; in scpi_probe()
922 if (of_match_device(legacy_scpi_of_match, &pdev->dev)) in scpi_probe()
923 scpi_drvinfo->is_legacy = true; in scpi_probe()
925 count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells"); in scpi_probe()
928 return -ENODEV; in scpi_probe()
931 scpi_drvinfo->channels = in scpi_probe()
933 if (!scpi_drvinfo->channels) in scpi_probe()
934 return -ENOMEM; in scpi_probe()
940 for (; scpi_drvinfo->num_chans < count; scpi_drvinfo->num_chans++) { in scpi_probe()
942 int idx = scpi_drvinfo->num_chans; in scpi_probe()
943 struct scpi_chan *pchan = scpi_drvinfo->channels + idx; in scpi_probe()
944 struct mbox_client *cl = &pchan->cl; in scpi_probe()
948 return -ENXIO; in scpi_probe()
958 pchan->rx_payload = devm_ioremap(dev, res.start, size); in scpi_probe()
959 if (!pchan->rx_payload) { in scpi_probe()
961 return -EADDRNOTAVAIL; in scpi_probe()
963 pchan->tx_payload = pchan->rx_payload + (size >> 1); in scpi_probe()
965 cl->dev = dev; in scpi_probe()
966 cl->rx_callback = scpi_handle_remote_msg; in scpi_probe()
967 cl->tx_prepare = scpi_tx_prepare; in scpi_probe()
968 cl->tx_block = true; in scpi_probe()
969 cl->tx_tout = 20; in scpi_probe()
970 cl->knows_txdone = false; /* controller can't ack */ in scpi_probe()
972 INIT_LIST_HEAD(&pchan->rx_pending); in scpi_probe()
973 INIT_LIST_HEAD(&pchan->xfers_list); in scpi_probe()
974 spin_lock_init(&pchan->rx_lock); in scpi_probe()
975 mutex_init(&pchan->xfers_lock); in scpi_probe()
979 pchan->chan = mbox_request_channel(cl, idx); in scpi_probe()
980 if (!IS_ERR(pchan->chan)) in scpi_probe()
982 ret = PTR_ERR(pchan->chan); in scpi_probe()
983 if (ret != -EPROBE_DEFER) in scpi_probe()
990 scpi_drvinfo->commands = scpi_std_commands; in scpi_probe()
994 if (scpi_drvinfo->is_legacy) { in scpi_probe()
997 scpi_drvinfo->commands = scpi_legacy_commands; in scpi_probe()
1002 scpi_drvinfo->cmd_priority); in scpi_probe()
1014 if (scpi_drvinfo->is_legacy && !scpi_drvinfo->protocol_version && in scpi_probe()
1015 !scpi_drvinfo->firmware_version) in scpi_probe()
1016 dev_info(dev, "SCP Protocol legacy pre-1.0 firmware\n"); in scpi_probe()
1020 scpi_drvinfo->protocol_version), in scpi_probe()
1022 scpi_drvinfo->protocol_version), in scpi_probe()
1024 scpi_drvinfo->firmware_version), in scpi_probe()
1026 scpi_drvinfo->firmware_version), in scpi_probe()
1028 scpi_drvinfo->firmware_version)); in scpi_probe()
1030 scpi_drvinfo->scpi_ops = &scpi_ops; in scpi_probe()
1041 {.compatible = "arm,scpi-pre-1.0"},