aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNishanth Menon2015-11-05 11:47:14 -0600
committerTero Kristo2015-11-06 09:25:39 -0600
commit1e4110da3fa05abcdea0a0c9881e382cdfaabd40 (patch)
tree8fbb997eb73909396f96f396ef01643e46d6487d /drivers/firmware/ti_sci.c
parent7a6f6dd0c3865b7706cbb71de84f4e8d2309f6d5 (diff)
downloadti-linux-kernel-1e4110da3fa05abcdea0a0c9881e382cdfaabd40.tar.gz
ti-linux-kernel-1e4110da3fa05abcdea0a0c9881e382cdfaabd40.tar.xz
ti-linux-kernel-1e4110da3fa05abcdea0a0c9881e382cdfaabd40.zip
firmware: ti_sci: Add support for Device control
Texas Instrument's System Control Interface (TI-SCI) Message Protocol is used in Texas Instrument's System on Chip (SoC) such as those in keystone family K2G SoC to communicate between various compute processors with a central system controller entity. SCI message protocol provides support for management of various hardware entitites within the SoC. Add support driver to allow communication with system controller entity within the SoC using the mailbox client. We introduce the fundamental device management capability support to the driver protocol as part of this change. Signed-off-by: Nishanth Menon <nm@ti.com>
Diffstat (limited to 'drivers/firmware/ti_sci.c')
-rw-r--r--drivers/firmware/ti_sci.c364
1 files changed, 364 insertions, 0 deletions
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index b266d7c2c09f..1e9a2a68c471 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -496,6 +496,368 @@ fail:
496} 496}
497 497
498/** 498/**
499 * tis_sci_is_response_ack() - Generic ACK/NACK message checkup
500 * @r: pointer to response buffer
501 *
502 * Return: true if the response was an ACK, else returns false.
503 */
504static inline bool tis_sci_is_response_ack(void *r)
505{
506 struct ti_sci_msg_hdr *hdr = r;
507
508 return hdr->flags & TI_SCI_FLAG_RESP_GENERIC_ACK ? true : false;
509}
510
511/**
512 * ti_sci_set_device_state() - Set device state helper
513 * @handle: pointer to TI SCI handle
514 * @id: Device identifier
515 * @flags: flags to setup for the device
516 * @resets: resets to setup for the device
517 * @state: State to move the device to
518 *
519 * Return: 0 if all went well, else returns appropriate error value.
520 */
521static int ti_sci_set_device_state(const struct ti_sci_handle *handle,
522 u32 id, u32 flags, u32 resets, u8 state)
523{
524 struct ti_sci_info *info;
525 struct ti_sci_msg_req_set_device_state *req;
526 struct ti_sci_msg_hdr *resp;
527 struct ti_sci_xfer *xfer;
528 struct device *dev;
529 int ret = 0;
530
531 if (IS_ERR(handle))
532 return PTR_ERR(handle);
533 if (!handle)
534 return -EINVAL;
535
536 info = handle_to_ti_sci_info(handle);
537 dev = info->dev;
538
539 xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_DEVICE_STATE,
540 TI_SCI_FLAG_REQ_ACK_ON_PROCESSED | flags,
541 sizeof(*req), sizeof(*resp));
542 if (IS_ERR(xfer)) {
543 ret = PTR_ERR(xfer);
544 dev_err(dev, "Message alloc failed(%d)\n", ret);
545 return ret;
546 }
547 req = (struct ti_sci_msg_req_set_device_state *)xfer->xfer_buf;
548 req->id = id;
549 req->state = state;
550 req->resets = resets;
551
552 ret = ti_sci_do_xfer(info, xfer);
553 if (ret) {
554 dev_err(dev, "Mbox send fail %d\n", ret);
555 goto fail;
556 }
557
558 resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
559
560 ret = tis_sci_is_response_ack(resp) ? 0 : -ENODEV;
561
562fail:
563 ti_sci_put_one_xfer(&info->minfo, xfer);
564
565 return ret;
566}
567
568/**
569 * ti_sci_get_device_state() - Get device state helper
570 * @handle: Handle to the device
571 * @id: Device Identifier
572 * @clcnt: Pointer to Context Loss Count
573 * @resets: pointer to resets
574 * @p_state: pointer to p_state
575 * @c_state: pointer to c_state
576 *
577 * Return: 0 if all went fine, else return appropriate error.
578 */
579static int ti_sci_get_device_state(const struct ti_sci_handle *handle,
580 u32 id, u32 *clcnt, u32 *resets,
581 u8 *p_state, u8 *c_state)
582{
583 struct ti_sci_info *info;
584 struct ti_sci_msg_req_get_device_state *req;
585 struct ti_sci_msg_resp_get_device_state *resp;
586 struct ti_sci_xfer *xfer;
587 struct device *dev;
588 int ret = 0;
589
590 if (IS_ERR(handle))
591 return PTR_ERR(handle);
592 if (!handle)
593 return -EINVAL;
594
595 if (!clcnt && !resets && !p_state && !c_state)
596 return -EINVAL;
597
598 info = handle_to_ti_sci_info(handle);
599 dev = info->dev;
600
601 /* Response is expected, so need of any flags */
602 xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_DEVICE_STATE,
603 0, sizeof(*req), sizeof(*resp));
604 if (IS_ERR(xfer)) {
605 ret = PTR_ERR(xfer);
606 dev_err(dev, "Message alloc failed(%d)\n", ret);
607 return ret;
608 }
609 req = (struct ti_sci_msg_req_get_device_state *)xfer->xfer_buf;
610 req->id = id;
611
612 ret = ti_sci_do_xfer(info, xfer);
613 if (ret) {
614 dev_err(dev, "Mbox send fail %d\n", ret);
615 goto fail;
616 }
617
618 resp = (struct ti_sci_msg_resp_get_device_state *)xfer->xfer_buf;
619 if (!tis_sci_is_response_ack(resp)) {
620 ret = -ENODEV;
621 goto fail;
622 }
623
624 if (clcnt)
625 *clcnt = resp->context_loss_count;
626 if (resets)
627 *resets = resp->resets;
628 if (p_state)
629 *p_state = resp->programmed_state;
630 if (c_state)
631 *c_state = resp->current_state;
632fail:
633 ti_sci_put_one_xfer(&info->minfo, xfer);
634
635 return ret;
636}
637
638/**
639 * ti_sci_cmd_get_device() - command to request for device managed by TISCI
640 * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle
641 * @id: Device Identifier
642 * @reset_state: Device specific reset bit field
643 *
644 * Request for the device - NOTE: the client MUST maintain integrity of
645 * usage count by balancing get_device with put_device. No refcounting is
646 * managed by driver for that purpose.
647 *
648 * NOTE: The request is for exclusive access for the processor.
649 *
650 * Return: 0 if all went fine, else return appropriate error.
651 */
652static int ti_sci_cmd_get_device(const struct ti_sci_handle *handle, u32 id,
653 u32 reset_state)
654{
655 return ti_sci_set_device_state(handle, id,
656 MSG_FLAG_DEVICE_EXCLUSIVE,
657 reset_state, MSG_DEVICE_SW_STATE_ON);
658}
659
660/**
661 * ti_sci_cmd_idle_device() - Command to idle a device managed by TISCI
662 * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle
663 * @id: Device Identifier
664 *
665 * Request for the device - NOTE: the client MUST maintain integrity of
666 * usage count by balancing get_device with put_device. No refcounting is
667 * managed by driver for that purpose.
668 *
669 * Return: 0 if all went fine, else return appropriate error.
670 */
671static int ti_sci_cmd_idle_device(const struct ti_sci_handle *handle, u32 id)
672{
673 return ti_sci_set_device_state(handle, id,
674 MSG_FLAG_DEVICE_EXCLUSIVE,
675 0, MSG_DEVICE_SW_STATE_RETENTION);
676}
677
678/**
679 * ti_sci_cmd_put_device() - command to release a device managed by TISCI
680 * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle
681 * @id: Device Identifier
682 *
683 * Request for the device - NOTE: the client MUST maintain integrity of
684 * usage count by balancing get_device with put_device. No refcounting is
685 * managed by driver for that purpose.
686 *
687 * Return: 0 if all went fine, else return appropriate error.
688 */
689static int ti_sci_cmd_put_device(const struct ti_sci_handle *handle, u32 id)
690{
691 return ti_sci_set_device_state(handle, id,
692 0, 0, MSG_DEVICE_SW_STATE_AUTO_OFF);
693}
694
695/**
696 * ti_sci_cmd_dev_is_valid() - Is the device valid
697 * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle
698 * @id: Device Identifier
699 *
700 * Return: 0 if all went fine and the device ID is valid, else return
701 * appropriate error.
702 */
703static int ti_sci_cmd_dev_is_valid(const struct ti_sci_handle *handle, u32 id)
704{
705 u8 unused;
706
707 /* check the device state which will also tell us if the ID is valid */
708 return ti_sci_get_device_state(handle, id, NULL, NULL, NULL, &unused);
709}
710
711/**
712 * ti_sci_cmd_dev_get_clcnt() - Get context loss counter
713 * @handle: Pointer to TISCI handle
714 * @id: Device Identifier
715 * @count: Pointer to Context Loss counter to populate
716 *
717 * Return: 0 if all went fine, else return appropriate error.
718 */
719static int ti_sci_cmd_dev_get_clcnt(const struct ti_sci_handle *handle, u32 id,
720 u32 *count)
721{
722 return ti_sci_get_device_state(handle, id, count, NULL, NULL, NULL);
723}
724
725/**
726 * ti_sci_cmd_dev_is_idle() - Check if the device is requested to be idle
727 * @handle: Pointer to TISCI handle
728 * @id: Device Identifier
729 * @r_state: true if requested to be idle
730 *
731 * Return: 0 if all went fine, else return appropriate error.
732 */
733static int ti_sci_cmd_dev_is_idle(const struct ti_sci_handle *handle, u32 id,
734 bool *r_state)
735{
736 int ret;
737 u8 state;
738
739 if (!r_state)
740 return -EINVAL;
741
742 ret = ti_sci_get_device_state(handle, id, NULL, NULL, &state, NULL);
743 if (ret)
744 return ret;
745
746 *r_state = (state == MSG_DEVICE_SW_STATE_RETENTION);
747
748 return 0;
749}
750
751/**
752 * ti_sci_cmd_dev_is_stop() - Check if the device is requested to be stopped
753 * @handle: Pointer to TISCI handle
754 * @id: Device Identifier
755 * @r_state: true if requested to be stopped
756 * @curr_state: true if currently stopped.
757 *
758 * Return: 0 if all went fine, else return appropriate error.
759 */
760static int ti_sci_cmd_dev_is_stop(const struct ti_sci_handle *handle, u32 id,
761 bool *r_state, bool *curr_state)
762{
763 int ret;
764 u8 p_state, c_state;
765
766 if (!r_state && !curr_state)
767 return -EINVAL;
768
769 ret =
770 ti_sci_get_device_state(handle, id, NULL, NULL, &p_state, &c_state);
771 if (ret)
772 return ret;
773
774 if (r_state)
775 *r_state = (p_state == MSG_DEVICE_SW_STATE_AUTO_OFF);
776 if (curr_state)
777 *curr_state = (c_state == MSG_DEVICE_HW_STATE_OFF);
778
779 return 0;
780}
781
782/**
783 * ti_sci_cmd_dev_is_on() - Check if the device is requested to be ON
784 * @handle: Pointer to TISCI handle
785 * @id: Device Identifier
786 * @r_state: true if requested to be ON
787 * @curr_state: true if currently ON and active
788 *
789 * Return: 0 if all went fine, else return appropriate error.
790 */
791static int ti_sci_cmd_dev_is_on(const struct ti_sci_handle *handle, u32 id,
792 bool *r_state, bool *curr_state)
793{
794 int ret;
795 u8 p_state, c_state;
796
797 if (!r_state && !curr_state)
798 return -EINVAL;
799
800 ret =
801 ti_sci_get_device_state(handle, id, NULL, NULL, &p_state, &c_state);
802 if (ret)
803 return ret;
804
805 if (r_state)
806 *r_state = (p_state == MSG_DEVICE_SW_STATE_ON);
807 if (curr_state)
808 *curr_state = (c_state == MSG_DEVICE_HW_STATE_ON);
809
810 return 0;
811}
812
813/**
814 * ti_sci_cmd_dev_is_trans() - Check if the device is currently transitioning
815 * @handle: Pointer to TISCI handle
816 * @id: Device Identifier
817 * @curr_state: true if currently transitioning.
818 *
819 * Return: 0 if all went fine, else return appropriate error.
820 */
821static int ti_sci_cmd_dev_is_trans(const struct ti_sci_handle *handle, u32 id,
822 bool *curr_state)
823{
824 int ret;
825 u8 state;
826
827 if (!curr_state)
828 return -EINVAL;
829
830 ret = ti_sci_get_device_state(handle, id, NULL, NULL, NULL, &state);
831 if (ret)
832 return ret;
833
834 *curr_state = (state == MSG_DEVICE_HW_STATE_TRANS);
835
836 return 0;
837}
838
839/**
840 * ti_sci_setup_ops() - Setup the operations structures
841 * @info: pointer to TISCI pointer
842 */
843static void ti_sci_setup_ops(struct ti_sci_info *info)
844{
845 struct ti_sci_ops *ops = &info->handle.ops;
846 struct ti_sci_dev_ops *dops = &ops->dev_ops;
847
848 dops->get_device = ti_sci_cmd_get_device;
849 dops->idle_device = ti_sci_cmd_idle_device;
850 dops->put_device = ti_sci_cmd_put_device;
851
852 dops->is_valid = ti_sci_cmd_dev_is_valid;
853 dops->get_context_loss_count = ti_sci_cmd_dev_get_clcnt;
854 dops->is_idle = ti_sci_cmd_dev_is_idle;
855 dops->is_stop = ti_sci_cmd_dev_is_stop;
856 dops->is_on = ti_sci_cmd_dev_is_on;
857 dops->is_transitioning = ti_sci_cmd_dev_is_trans;
858}
859
860/**
499 * ti_sci_get_handle() - Get the TI SCI handle for a device 861 * ti_sci_get_handle() - Get the TI SCI handle for a device
500 * @dev: Pointer to device for which we want SCI handle 862 * @dev: Pointer to device for which we want SCI handle
501 * 863 *
@@ -734,6 +1096,8 @@ static int ti_sci_probe(struct platform_device *pdev)
734 goto out; 1096 goto out;
735 } 1097 }
736 1098
1099 ti_sci_setup_ops(info);
1100
737 dev_info(dev, "ABI: %d.%d (firmware rev 0x%04x '%s')\n", 1101 dev_info(dev, "ABI: %d.%d (firmware rev 0x%04x '%s')\n",
738 info->handle.version.abi_major, info->handle.version.abi_minor, 1102 info->handle.version.abi_major, info->handle.version.abi_minor,
739 info->handle.version.firmware_revision, 1103 info->handle.version.firmware_revision,