|
@@ -28,6 +28,7 @@
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/soc/ti/ti-msgmgr.h>
|
|
#include <linux/soc/ti/ti-msgmgr.h>
|
|
#include <linux/soc/ti/ti_sci_protocol.h>
|
|
#include <linux/soc/ti/ti_sci_protocol.h>
|
|
|
|
+#include <linux/reboot.h>
|
|
|
|
|
|
#include "ti_sci.h"
|
|
#include "ti_sci.h"
|
|
|
|
|
|
@@ -90,6 +91,7 @@ struct ti_sci_desc {
|
|
* struct ti_sci_info - Structure representing a TI SCI instance
|
|
* struct ti_sci_info - Structure representing a TI SCI instance
|
|
* @dev: Device pointer
|
|
* @dev: Device pointer
|
|
* @desc: SoC description for this instance
|
|
* @desc: SoC description for this instance
|
|
|
|
+ * @nb: Reboot Notifier block
|
|
* @d: Debugfs file entry
|
|
* @d: Debugfs file entry
|
|
* @debug_region: Memory region where the debug message are available
|
|
* @debug_region: Memory region where the debug message are available
|
|
* @debug_region_size: Debug region size
|
|
* @debug_region_size: Debug region size
|
|
@@ -104,6 +106,7 @@ struct ti_sci_desc {
|
|
*/
|
|
*/
|
|
struct ti_sci_info {
|
|
struct ti_sci_info {
|
|
struct device *dev;
|
|
struct device *dev;
|
|
|
|
+ struct notifier_block nb;
|
|
const struct ti_sci_desc *desc;
|
|
const struct ti_sci_desc *desc;
|
|
struct dentry *d;
|
|
struct dentry *d;
|
|
void __iomem *debug_region;
|
|
void __iomem *debug_region;
|
|
@@ -117,10 +120,12 @@ struct ti_sci_info {
|
|
struct list_head node;
|
|
struct list_head node;
|
|
/* protected by ti_sci_list_mutex */
|
|
/* protected by ti_sci_list_mutex */
|
|
int users;
|
|
int users;
|
|
|
|
+
|
|
};
|
|
};
|
|
|
|
|
|
#define cl_to_ti_sci_info(c) container_of(c, struct ti_sci_info, cl)
|
|
#define cl_to_ti_sci_info(c) container_of(c, struct ti_sci_info, cl)
|
|
#define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle)
|
|
#define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle)
|
|
|
|
+#define reboot_to_ti_sci_info(n) container_of(n, struct ti_sci_info, nb)
|
|
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
#ifdef CONFIG_DEBUG_FS
|
|
|
|
|
|
@@ -1571,6 +1576,52 @@ fail:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int ti_sci_cmd_core_reboot(const struct ti_sci_handle *handle)
|
|
|
|
+{
|
|
|
|
+ struct ti_sci_info *info;
|
|
|
|
+ struct ti_sci_msg_req_reboot *req;
|
|
|
|
+ struct ti_sci_msg_hdr *resp;
|
|
|
|
+ struct ti_sci_xfer *xfer;
|
|
|
|
+ struct device *dev;
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ if (IS_ERR(handle))
|
|
|
|
+ return PTR_ERR(handle);
|
|
|
|
+ if (!handle)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ info = handle_to_ti_sci_info(handle);
|
|
|
|
+ dev = info->dev;
|
|
|
|
+
|
|
|
|
+ xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SYS_RESET,
|
|
|
|
+ TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
|
|
|
|
+ sizeof(*req), sizeof(*resp));
|
|
|
|
+ if (IS_ERR(xfer)) {
|
|
|
|
+ ret = PTR_ERR(xfer);
|
|
|
|
+ dev_err(dev, "Message alloc failed(%d)\n", ret);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ req = (struct ti_sci_msg_req_reboot *)xfer->xfer_buf;
|
|
|
|
+
|
|
|
|
+ ret = ti_sci_do_xfer(info, xfer);
|
|
|
|
+ if (ret) {
|
|
|
|
+ dev_err(dev, "Mbox send fail %d\n", ret);
|
|
|
|
+ goto fail;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
|
|
|
|
+
|
|
|
|
+ if (!ti_sci_is_response_ack(resp))
|
|
|
|
+ ret = -ENODEV;
|
|
|
|
+ else
|
|
|
|
+ ret = 0;
|
|
|
|
+
|
|
|
|
+fail:
|
|
|
|
+ ti_sci_put_one_xfer(&info->minfo, xfer);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* ti_sci_setup_ops() - Setup the operations structures
|
|
* ti_sci_setup_ops() - Setup the operations structures
|
|
* @info: pointer to TISCI pointer
|
|
* @info: pointer to TISCI pointer
|
|
@@ -1578,9 +1629,12 @@ fail:
|
|
static void ti_sci_setup_ops(struct ti_sci_info *info)
|
|
static void ti_sci_setup_ops(struct ti_sci_info *info)
|
|
{
|
|
{
|
|
struct ti_sci_ops *ops = &info->handle.ops;
|
|
struct ti_sci_ops *ops = &info->handle.ops;
|
|
|
|
+ struct ti_sci_core_ops *core_ops = &ops->core_ops;
|
|
struct ti_sci_dev_ops *dops = &ops->dev_ops;
|
|
struct ti_sci_dev_ops *dops = &ops->dev_ops;
|
|
struct ti_sci_clk_ops *cops = &ops->clk_ops;
|
|
struct ti_sci_clk_ops *cops = &ops->clk_ops;
|
|
|
|
|
|
|
|
+ core_ops->reboot_device = ti_sci_cmd_core_reboot;
|
|
|
|
+
|
|
dops->get_device = ti_sci_cmd_get_device;
|
|
dops->get_device = ti_sci_cmd_get_device;
|
|
dops->idle_device = ti_sci_cmd_idle_device;
|
|
dops->idle_device = ti_sci_cmd_idle_device;
|
|
dops->put_device = ti_sci_cmd_put_device;
|
|
dops->put_device = ti_sci_cmd_put_device;
|
|
@@ -1732,6 +1786,18 @@ const struct ti_sci_handle *devm_ti_sci_get_handle(struct device *dev)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_ti_sci_get_handle);
|
|
EXPORT_SYMBOL_GPL(devm_ti_sci_get_handle);
|
|
|
|
|
|
|
|
+static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode,
|
|
|
|
+ void *cmd)
|
|
|
|
+{
|
|
|
|
+ struct ti_sci_info *info = reboot_to_ti_sci_info(nb);
|
|
|
|
+ const struct ti_sci_handle *handle = &info->handle;
|
|
|
|
+
|
|
|
|
+ ti_sci_cmd_core_reboot(handle);
|
|
|
|
+
|
|
|
|
+ /* call fail OR pass, we should not be here in the first place */
|
|
|
|
+ return NOTIFY_BAD;
|
|
|
|
+}
|
|
|
|
+
|
|
/* Description for K2G */
|
|
/* Description for K2G */
|
|
static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = {
|
|
static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = {
|
|
.host_id = 2,
|
|
.host_id = 2,
|
|
@@ -1759,6 +1825,7 @@ static int ti_sci_probe(struct platform_device *pdev)
|
|
struct mbox_client *cl;
|
|
struct mbox_client *cl;
|
|
int ret = -EINVAL;
|
|
int ret = -EINVAL;
|
|
int i;
|
|
int i;
|
|
|
|
+ int reboot = 0;
|
|
|
|
|
|
of_id = of_match_device(ti_sci_of_match, dev);
|
|
of_id = of_match_device(ti_sci_of_match, dev);
|
|
if (!of_id) {
|
|
if (!of_id) {
|
|
@@ -1773,6 +1840,8 @@ static int ti_sci_probe(struct platform_device *pdev)
|
|
|
|
|
|
info->dev = dev;
|
|
info->dev = dev;
|
|
info->desc = desc;
|
|
info->desc = desc;
|
|
|
|
+ reboot = of_property_read_bool(dev->of_node,
|
|
|
|
+ "ti,system-reboot-controller");
|
|
INIT_LIST_HEAD(&info->node);
|
|
INIT_LIST_HEAD(&info->node);
|
|
minfo = &info->minfo;
|
|
minfo = &info->minfo;
|
|
|
|
|
|
@@ -1845,6 +1914,17 @@ static int ti_sci_probe(struct platform_device *pdev)
|
|
|
|
|
|
ti_sci_setup_ops(info);
|
|
ti_sci_setup_ops(info);
|
|
|
|
|
|
|
|
+ if (reboot) {
|
|
|
|
+ info->nb.notifier_call = tisci_reboot_handler;
|
|
|
|
+ info->nb.priority = 128;
|
|
|
|
+
|
|
|
|
+ ret = register_restart_handler(&info->nb);
|
|
|
|
+ if (ret) {
|
|
|
|
+ dev_err(dev, "reboot registration fail(%d)\n", ret);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
dev_info(dev, "ABI: %d.%d (firmware rev 0x%04x '%s')\n",
|
|
dev_info(dev, "ABI: %d.%d (firmware rev 0x%04x '%s')\n",
|
|
info->handle.version.abi_major, info->handle.version.abi_minor,
|
|
info->handle.version.abi_major, info->handle.version.abi_minor,
|
|
info->handle.version.firmware_revision,
|
|
info->handle.version.firmware_revision,
|
|
@@ -1874,6 +1954,9 @@ static int ti_sci_remove(struct platform_device *pdev)
|
|
|
|
|
|
info = platform_get_drvdata(pdev);
|
|
info = platform_get_drvdata(pdev);
|
|
|
|
|
|
|
|
+ if (info->nb.notifier_call)
|
|
|
|
+ unregister_restart_handler(&info->nb);
|
|
|
|
+
|
|
mutex_lock(&ti_sci_list_mutex);
|
|
mutex_lock(&ti_sci_list_mutex);
|
|
if (info->users)
|
|
if (info->users)
|
|
ret = -EBUSY;
|
|
ret = -EBUSY;
|