Lines Matching +full:mhu +full:- +full:tx
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
210 -1, /* GET_CLOCK_INFO */
219 -1, /* SET_DEVICE_PWR_STATE */
220 -1, /* GET_DEVICE_PWR_STATE */
262 * The SCP firmware only executes in little-endian mode, so any buffers
263 * shared through SCPI should have their contents converted to little-endian
335 -EINVAL, /* SCPI_ERR_PARAM */
336 -ENOEXEC, /* SCPI_ERR_ALIGN */
337 -EMSGSIZE, /* SCPI_ERR_SIZE */
338 -EINVAL, /* SCPI_ERR_HANDLER */
339 -EACCES, /* SCPI_ERR_ACCESS */
340 -ERANGE, /* SCPI_ERR_RANGE */
341 -ETIMEDOUT, /* SCPI_ERR_TIMEOUT */
342 -ENOMEM, /* SCPI_ERR_NOMEM */
343 -EINVAL, /* SCPI_ERR_PWRSTATE */
344 -EOPNOTSUPP, /* SCPI_ERR_SUPPORT */
345 -EIO, /* SCPI_ERR_DEVICE */
346 -EBUSY, /* SCPI_ERR_BUSY */
353 return -EIO; in scpi_to_linux_errno()
361 spin_lock_irqsave(&ch->rx_lock, flags); in scpi_process_cmd()
362 if (list_empty(&ch->rx_pending)) { in scpi_process_cmd()
363 spin_unlock_irqrestore(&ch->rx_lock, flags); in scpi_process_cmd()
369 * if the list is not empty. In TX only mode, the list would be empty. in scpi_process_cmd()
371 if (scpi_info->is_legacy) { in scpi_process_cmd()
372 match = list_first_entry(&ch->rx_pending, struct scpi_xfer, in scpi_process_cmd()
374 list_del(&match->node); in scpi_process_cmd()
376 list_for_each_entry(t, &ch->rx_pending, node) in scpi_process_cmd()
377 if (CMD_XTRACT_UNIQ(t->cmd) == CMD_XTRACT_UNIQ(cmd)) { in scpi_process_cmd()
378 list_del(&t->node); in scpi_process_cmd()
383 /* check if wait_for_completion is in progress or timed-out */ in scpi_process_cmd()
384 if (match && !completion_done(&match->done)) { in scpi_process_cmd()
387 if (scpi_info->is_legacy) { in scpi_process_cmd()
389 ch->rx_payload; in scpi_process_cmd()
392 len = match->rx_len; in scpi_process_cmd()
394 match->status = ioread32(&mem->status); in scpi_process_cmd()
395 memcpy_fromio(match->rx_buf, mem->payload, len); in scpi_process_cmd()
397 struct scpi_shared_mem __iomem *mem = ch->rx_payload; in scpi_process_cmd()
399 len = min_t(unsigned int, match->rx_len, CMD_SIZE(cmd)); in scpi_process_cmd()
401 match->status = ioread32(&mem->status); in scpi_process_cmd()
402 memcpy_fromio(match->rx_buf, mem->payload, len); in scpi_process_cmd()
405 if (match->rx_len > len) in scpi_process_cmd()
406 memset(match->rx_buf + len, 0, match->rx_len - len); in scpi_process_cmd()
407 complete(&match->done); in scpi_process_cmd()
409 spin_unlock_irqrestore(&ch->rx_lock, flags); in scpi_process_cmd()
415 struct scpi_shared_mem __iomem *mem = ch->rx_payload; in scpi_handle_remote_msg()
418 if (!scpi_info->is_legacy) in scpi_handle_remote_msg()
419 cmd = ioread32(&mem->command); in scpi_handle_remote_msg()
429 struct scpi_shared_mem __iomem *mem = ch->tx_payload; in scpi_tx_prepare()
431 if (t->tx_buf) { in scpi_tx_prepare()
432 if (scpi_info->is_legacy) in scpi_tx_prepare()
433 memcpy_toio(ch->tx_payload, t->tx_buf, t->tx_len); in scpi_tx_prepare()
435 memcpy_toio(mem->payload, t->tx_buf, t->tx_len); in scpi_tx_prepare()
438 if (t->rx_buf) { in scpi_tx_prepare()
439 if (!(++ch->token)) in scpi_tx_prepare()
440 ++ch->token; in scpi_tx_prepare()
441 t->cmd |= FIELD_PREP(CMD_TOKEN_ID_MASK, ch->token); in scpi_tx_prepare()
442 spin_lock_irqsave(&ch->rx_lock, flags); in scpi_tx_prepare()
443 list_add_tail(&t->node, &ch->rx_pending); in scpi_tx_prepare()
444 spin_unlock_irqrestore(&ch->rx_lock, flags); in scpi_tx_prepare()
447 if (!scpi_info->is_legacy) in scpi_tx_prepare()
448 iowrite32(t->cmd, &mem->command); in scpi_tx_prepare()
455 mutex_lock(&ch->xfers_lock); in get_scpi_xfer()
456 if (list_empty(&ch->xfers_list)) { in get_scpi_xfer()
457 mutex_unlock(&ch->xfers_lock); in get_scpi_xfer()
460 t = list_first_entry(&ch->xfers_list, struct scpi_xfer, node); in get_scpi_xfer()
461 list_del(&t->node); in get_scpi_xfer()
462 mutex_unlock(&ch->xfers_lock); in get_scpi_xfer()
468 mutex_lock(&ch->xfers_lock); in put_scpi_xfer()
469 list_add_tail(&t->node, &ch->xfers_list); in put_scpi_xfer()
470 mutex_unlock(&ch->xfers_lock); in put_scpi_xfer()
482 if (scpi_info->commands[idx] < 0) in scpi_send_message()
483 return -EOPNOTSUPP; in scpi_send_message()
485 cmd = scpi_info->commands[idx]; in scpi_send_message()
487 if (scpi_info->is_legacy) in scpi_send_message()
488 chan = test_bit(cmd, scpi_info->cmd_priority) ? 1 : 0; in scpi_send_message()
490 chan = atomic_inc_return(&scpi_info->next_chan) % in scpi_send_message()
491 scpi_info->num_chans; in scpi_send_message()
492 scpi_chan = scpi_info->channels + chan; in scpi_send_message()
496 return -ENOMEM; in scpi_send_message()
498 if (scpi_info->is_legacy) { in scpi_send_message()
499 msg->cmd = PACK_LEGACY_SCPI_CMD(cmd, tx_len); in scpi_send_message()
500 msg->slot = msg->cmd; in scpi_send_message()
502 msg->slot = BIT(SCPI_SLOT); in scpi_send_message()
503 msg->cmd = PACK_SCPI_CMD(cmd, tx_len); in scpi_send_message()
505 msg->tx_buf = tx_buf; in scpi_send_message()
506 msg->tx_len = tx_len; in scpi_send_message()
507 msg->rx_buf = rx_buf; in scpi_send_message()
508 msg->rx_len = rx_len; in scpi_send_message()
509 reinit_completion(&msg->done); in scpi_send_message()
511 ret = mbox_send_message(scpi_chan->chan, msg); in scpi_send_message()
515 if (!wait_for_completion_timeout(&msg->done, MAX_RX_TIMEOUT)) in scpi_send_message()
516 ret = -ETIMEDOUT; in scpi_send_message()
519 ret = msg->status; in scpi_send_message()
521 if (ret < 0 && rx_buf) /* remove entry from the list if timed-out */ in scpi_send_message()
522 scpi_process_cmd(scpi_chan, msg->cmd); in scpi_send_message()
531 return scpi_info->protocol_version; in scpi_get_version()
612 return t1->freq - t2->freq; in opp_cmp_func()
623 return ERR_PTR(-EINVAL); in scpi_dvfs_get_info()
625 if (scpi_info->dvfs[domain]) /* data already populated */ in scpi_dvfs_get_info()
626 return scpi_info->dvfs[domain]; in scpi_dvfs_get_info()
635 return ERR_PTR(-ENOMEM); in scpi_dvfs_get_info()
637 info->count = buf.opp_count; in scpi_dvfs_get_info()
638 info->latency = le16_to_cpu(buf.latency) * 1000; /* uS to nS */ in scpi_dvfs_get_info()
640 info->opps = kcalloc(info->count, sizeof(*opp), GFP_KERNEL); in scpi_dvfs_get_info()
641 if (!info->opps) { in scpi_dvfs_get_info()
643 return ERR_PTR(-ENOMEM); in scpi_dvfs_get_info()
646 for (i = 0, opp = info->opps; i < info->count; i++, opp++) { in scpi_dvfs_get_info()
647 opp->freq = le32_to_cpu(buf.opps[i].freq); in scpi_dvfs_get_info()
648 opp->m_volt = le32_to_cpu(buf.opps[i].m_volt); in scpi_dvfs_get_info()
651 sort(info->opps, info->count, sizeof(*opp), opp_cmp_func, NULL); in scpi_dvfs_get_info()
653 scpi_info->dvfs[domain] = info; in scpi_dvfs_get_info()
661 if (of_parse_phandle_with_args(dev->of_node, "clocks", "#clock-cells", in scpi_dev_domain_id()
663 return -EINVAL; in scpi_dev_domain_id()
685 return info->latency; in scpi_dvfs_get_transition_latency()
697 if (!info->opps) in scpi_dvfs_add_opps_to_device()
698 return -EIO; in scpi_dvfs_add_opps_to_device()
700 for (opp = info->opps, idx = 0; idx < info->count; idx++, opp++) { in scpi_dvfs_add_opps_to_device()
701 ret = dev_pm_opp_add(dev, opp->freq, opp->m_volt * 1000); in scpi_dvfs_add_opps_to_device()
704 opp->freq, opp->m_volt); in scpi_dvfs_add_opps_to_device()
705 while (idx-- > 0) in scpi_dvfs_add_opps_to_device()
706 dev_pm_opp_remove(dev, (--opp)->freq); in scpi_dvfs_add_opps_to_device()
736 info->sensor_id = le16_to_cpu(_info.sensor_id); in scpi_sensor_get_info()
753 if (scpi_info->is_legacy) in scpi_sensor_get_value()
754 /* only 32-bits supported, upper 32 bits can be junk */ in scpi_sensor_get_value()
805 return scpi_info ? scpi_info->scpi_ops : NULL; in get_scpi_ops()
817 info->protocol_version = le32_to_cpu(caps.protocol_version); in scpi_init_versions()
818 info->firmware_version = le32_to_cpu(caps.platform_version); in scpi_init_versions()
821 if (info->is_legacy && ret == -EOPNOTSUPP) in scpi_init_versions()
833 FIELD_GET(PROTO_REV_MAJOR_MASK, scpi_info->protocol_version), in protocol_version_show()
834 FIELD_GET(PROTO_REV_MINOR_MASK, scpi_info->protocol_version)); in protocol_version_show()
844 FIELD_GET(FW_REV_MAJOR_MASK, scpi_info->firmware_version), in firmware_version_show()
845 FIELD_GET(FW_REV_MINOR_MASK, scpi_info->firmware_version), in firmware_version_show()
846 FIELD_GET(FW_REV_PATCH_MASK, scpi_info->firmware_version)); in firmware_version_show()
862 for (i = 0; i < info->num_chans; i++) in scpi_free_channels()
863 mbox_free_channel(info->channels[i].chan); in scpi_free_channels()
873 for (i = 0; i < MAX_DVFS_DOMAINS && info->dvfs[i]; i++) { in scpi_remove()
874 kfree(info->dvfs[i]->opps); in scpi_remove()
875 kfree(info->dvfs[i]); in scpi_remove()
887 return -ENOMEM; in scpi_alloc_xfer_list()
889 ch->xfers = xfers; in scpi_alloc_xfer_list()
891 init_completion(&xfers->done); in scpi_alloc_xfer_list()
892 list_add_tail(&xfers->node, &ch->xfers_list); in scpi_alloc_xfer_list()
899 { .compatible = "amlogic,meson-gxbb-scp-shmem", },
900 { .compatible = "amlogic,meson-axg-scp-shmem", },
901 { .compatible = "arm,juno-scp-shmem", },
902 { .compatible = "arm,scp-shmem", },
910 struct device *dev = &pdev->dev; in scpi_probe()
911 struct device_node *np = dev->of_node; in scpi_probe()
916 return -ENOMEM; in scpi_probe()
918 scpi_drvinfo->is_legacy = !!device_get_match_data(dev); in scpi_probe()
920 count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells"); in scpi_probe()
923 return -ENODEV; in scpi_probe()
926 scpi_drvinfo->channels = in scpi_probe()
928 if (!scpi_drvinfo->channels) in scpi_probe()
929 return -ENOMEM; in scpi_probe()
935 for (; scpi_drvinfo->num_chans < count; scpi_drvinfo->num_chans++) { in scpi_probe()
937 int idx = scpi_drvinfo->num_chans; in scpi_probe()
938 struct scpi_chan *pchan = scpi_drvinfo->channels + idx; in scpi_probe()
939 struct mbox_client *cl = &pchan->cl; in scpi_probe()
943 return -ENXIO; in scpi_probe()
953 pchan->rx_payload = devm_ioremap(dev, res.start, size); in scpi_probe()
954 if (!pchan->rx_payload) { in scpi_probe()
956 return -EADDRNOTAVAIL; in scpi_probe()
958 pchan->tx_payload = pchan->rx_payload + (size >> 1); in scpi_probe()
960 cl->dev = dev; in scpi_probe()
961 cl->rx_callback = scpi_handle_remote_msg; in scpi_probe()
962 cl->tx_prepare = scpi_tx_prepare; in scpi_probe()
963 cl->tx_block = true; in scpi_probe()
964 cl->tx_tout = 20; in scpi_probe()
965 cl->knows_txdone = false; /* controller can't ack */ in scpi_probe()
967 INIT_LIST_HEAD(&pchan->rx_pending); in scpi_probe()
968 INIT_LIST_HEAD(&pchan->xfers_list); in scpi_probe()
969 spin_lock_init(&pchan->rx_lock); in scpi_probe()
970 mutex_init(&pchan->xfers_lock); in scpi_probe()
974 pchan->chan = mbox_request_channel(cl, idx); in scpi_probe()
975 if (!IS_ERR(pchan->chan)) in scpi_probe()
977 ret = PTR_ERR(pchan->chan); in scpi_probe()
978 if (ret != -EPROBE_DEFER) in scpi_probe()
985 scpi_drvinfo->commands = scpi_std_commands; in scpi_probe()
989 if (scpi_drvinfo->is_legacy) { in scpi_probe()
992 scpi_drvinfo->commands = scpi_legacy_commands; in scpi_probe()
997 scpi_drvinfo->cmd_priority); in scpi_probe()
1009 if (scpi_drvinfo->is_legacy && !scpi_drvinfo->protocol_version && in scpi_probe()
1010 !scpi_drvinfo->firmware_version) in scpi_probe()
1011 dev_info(dev, "SCP Protocol legacy pre-1.0 firmware\n"); in scpi_probe()
1015 scpi_drvinfo->protocol_version), in scpi_probe()
1017 scpi_drvinfo->protocol_version), in scpi_probe()
1019 scpi_drvinfo->firmware_version), in scpi_probe()
1021 scpi_drvinfo->firmware_version), in scpi_probe()
1023 scpi_drvinfo->firmware_version)); in scpi_probe()
1025 scpi_drvinfo->scpi_ops = &scpi_ops; in scpi_probe()
1036 {.compatible = "arm,scpi-pre-1.0", .data = (void *)1UL },