Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

firmware: ti_sci: Add support for reboot core service

Since system controller now has control over SoC power management, it
needs to be explicitly requested to reboot the SoC. Add support for
it.

In some systems however, SoC needs to toggle a GPIO or send event to an
external entity (like a PMIC) for a system reboot to take place. To
facilitate that, we allow for a DT property to determine if the reboot
handler will be registered and further, the service is also made
available to other drivers (such as PMIC driver) to sequence the
additional operation and trigger the SoC reboot as the last step.

Tested-by: Lokesh Vutla <lokeshvutla@ti.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Tero Kristo <t-kristo@ti.com>

authored by

Nishanth Menon and committed by
Tero Kristo
912cffb4 9f723220

+106
+83
drivers/firmware/ti_sci.c
··· 28 28 #include <linux/slab.h> 29 29 #include <linux/soc/ti/ti-msgmgr.h> 30 30 #include <linux/soc/ti/ti_sci_protocol.h> 31 + #include <linux/reboot.h> 31 32 32 33 #include "ti_sci.h" 33 34 ··· 91 90 * struct ti_sci_info - Structure representing a TI SCI instance 92 91 * @dev: Device pointer 93 92 * @desc: SoC description for this instance 93 + * @nb: Reboot Notifier block 94 94 * @d: Debugfs file entry 95 95 * @debug_region: Memory region where the debug message are available 96 96 * @debug_region_size: Debug region size ··· 106 104 */ 107 105 struct ti_sci_info { 108 106 struct device *dev; 107 + struct notifier_block nb; 109 108 const struct ti_sci_desc *desc; 110 109 struct dentry *d; 111 110 void __iomem *debug_region; ··· 120 117 struct list_head node; 121 118 /* protected by ti_sci_list_mutex */ 122 119 int users; 120 + 123 121 }; 124 122 125 123 #define cl_to_ti_sci_info(c) container_of(c, struct ti_sci_info, cl) 126 124 #define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle) 125 + #define reboot_to_ti_sci_info(n) container_of(n, struct ti_sci_info, nb) 127 126 128 127 #ifdef CONFIG_DEBUG_FS 129 128 ··· 1576 1571 return ret; 1577 1572 } 1578 1573 1574 + static int ti_sci_cmd_core_reboot(const struct ti_sci_handle *handle) 1575 + { 1576 + struct ti_sci_info *info; 1577 + struct ti_sci_msg_req_reboot *req; 1578 + struct ti_sci_msg_hdr *resp; 1579 + struct ti_sci_xfer *xfer; 1580 + struct device *dev; 1581 + int ret = 0; 1582 + 1583 + if (IS_ERR(handle)) 1584 + return PTR_ERR(handle); 1585 + if (!handle) 1586 + return -EINVAL; 1587 + 1588 + info = handle_to_ti_sci_info(handle); 1589 + dev = info->dev; 1590 + 1591 + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SYS_RESET, 1592 + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, 1593 + sizeof(*req), sizeof(*resp)); 1594 + if (IS_ERR(xfer)) { 1595 + ret = PTR_ERR(xfer); 1596 + dev_err(dev, "Message alloc failed(%d)\n", ret); 1597 + return ret; 1598 + } 1599 + req = (struct ti_sci_msg_req_reboot *)xfer->xfer_buf; 1600 + 1601 + ret = ti_sci_do_xfer(info, xfer); 1602 + if (ret) { 1603 + dev_err(dev, "Mbox send fail %d\n", ret); 1604 + goto fail; 1605 + } 1606 + 1607 + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; 1608 + 1609 + if (!ti_sci_is_response_ack(resp)) 1610 + ret = -ENODEV; 1611 + else 1612 + ret = 0; 1613 + 1614 + fail: 1615 + ti_sci_put_one_xfer(&info->minfo, xfer); 1616 + 1617 + return ret; 1618 + } 1619 + 1579 1620 /* 1580 1621 * ti_sci_setup_ops() - Setup the operations structures 1581 1622 * @info: pointer to TISCI pointer ··· 1629 1578 static void ti_sci_setup_ops(struct ti_sci_info *info) 1630 1579 { 1631 1580 struct ti_sci_ops *ops = &info->handle.ops; 1581 + struct ti_sci_core_ops *core_ops = &ops->core_ops; 1632 1582 struct ti_sci_dev_ops *dops = &ops->dev_ops; 1633 1583 struct ti_sci_clk_ops *cops = &ops->clk_ops; 1584 + 1585 + core_ops->reboot_device = ti_sci_cmd_core_reboot; 1634 1586 1635 1587 dops->get_device = ti_sci_cmd_get_device; 1636 1588 dops->idle_device = ti_sci_cmd_idle_device; ··· 1786 1732 } 1787 1733 EXPORT_SYMBOL_GPL(devm_ti_sci_get_handle); 1788 1734 1735 + static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode, 1736 + void *cmd) 1737 + { 1738 + struct ti_sci_info *info = reboot_to_ti_sci_info(nb); 1739 + const struct ti_sci_handle *handle = &info->handle; 1740 + 1741 + ti_sci_cmd_core_reboot(handle); 1742 + 1743 + /* call fail OR pass, we should not be here in the first place */ 1744 + return NOTIFY_BAD; 1745 + } 1746 + 1789 1747 /* Description for K2G */ 1790 1748 static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = { 1791 1749 .host_id = 2, ··· 1825 1759 struct mbox_client *cl; 1826 1760 int ret = -EINVAL; 1827 1761 int i; 1762 + int reboot = 0; 1828 1763 1829 1764 of_id = of_match_device(ti_sci_of_match, dev); 1830 1765 if (!of_id) { ··· 1840 1773 1841 1774 info->dev = dev; 1842 1775 info->desc = desc; 1776 + reboot = of_property_read_bool(dev->of_node, 1777 + "ti,system-reboot-controller"); 1843 1778 INIT_LIST_HEAD(&info->node); 1844 1779 minfo = &info->minfo; 1845 1780 ··· 1914 1845 1915 1846 ti_sci_setup_ops(info); 1916 1847 1848 + if (reboot) { 1849 + info->nb.notifier_call = tisci_reboot_handler; 1850 + info->nb.priority = 128; 1851 + 1852 + ret = register_restart_handler(&info->nb); 1853 + if (ret) { 1854 + dev_err(dev, "reboot registration fail(%d)\n", ret); 1855 + return ret; 1856 + } 1857 + } 1858 + 1917 1859 dev_info(dev, "ABI: %d.%d (firmware rev 0x%04x '%s')\n", 1918 1860 info->handle.version.abi_major, info->handle.version.abi_minor, 1919 1861 info->handle.version.firmware_revision, ··· 1953 1873 of_platform_depopulate(dev); 1954 1874 1955 1875 info = platform_get_drvdata(pdev); 1876 + 1877 + if (info->nb.notifier_call) 1878 + unregister_restart_handler(&info->nb); 1956 1879 1957 1880 mutex_lock(&ti_sci_list_mutex); 1958 1881 if (info->users)
+12
drivers/firmware/ti_sci.h
··· 46 46 #define TI_SCI_MSG_VERSION 0x0002 47 47 #define TI_SCI_MSG_WAKE_REASON 0x0003 48 48 #define TI_SCI_MSG_GOODBYE 0x0004 49 + #define TI_SCI_MSG_SYS_RESET 0x0005 49 50 50 51 /* Device requests */ 51 52 #define TI_SCI_MSG_SET_DEVICE_STATE 0x0200 ··· 104 103 u16 firmware_revision; 105 104 u8 abi_major; 106 105 u8 abi_minor; 106 + } __packed; 107 + 108 + /** 109 + * struct ti_sci_msg_req_reboot - Reboot the SoC 110 + * @hdr: Generic Header 111 + * 112 + * Request type is TI_SCI_MSG_SYS_RESET, responded with a generic 113 + * ACK/NACK message. 114 + */ 115 + struct ti_sci_msg_req_reboot { 116 + struct ti_sci_msg_hdr hdr; 107 117 } __packed; 108 118 109 119 /**
+11
include/linux/soc/ti/ti_sci_protocol.h
··· 36 36 struct ti_sci_handle; 37 37 38 38 /** 39 + * struct ti_sci_core_ops - SoC Core Operations 40 + * @reboot_device: Reboot the SoC 41 + * Returns 0 for successful request(ideally should never return), 42 + * else returns corresponding error value. 43 + */ 44 + struct ti_sci_core_ops { 45 + int (*reboot_device)(const struct ti_sci_handle *handle); 46 + }; 47 + 48 + /** 39 49 * struct ti_sci_dev_ops - Device control operations 40 50 * @get_device: Command to request for device managed by TISCI 41 51 * Returns 0 for successful exclusive request, else returns ··· 206 196 * @clk_ops: Clock specific operations 207 197 */ 208 198 struct ti_sci_ops { 199 + struct ti_sci_core_ops core_ops; 209 200 struct ti_sci_dev_ops dev_ops; 210 201 struct ti_sci_clk_ops clk_ops; 211 202 };