[PATCH 2/7] firmware: ti_sci: update from U-Boot

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This imports some U-Boot changes into the ti_sci driver. For upcoming
k3-udma driver we'll need ti_sci_get_by_phandle() and
devm_ti_sci_get_of_resource().

Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx>
---
 drivers/firmware/ti_sci.c        | 276 ++++++++++++++++++++++++++++++++-------
 drivers/firmware/ti_sci.h        |   2 +-
 include/soc/ti/ti_sci_protocol.h |  38 +++++-
 3 files changed, 264 insertions(+), 52 deletions(-)

diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index c81e8aa1e7..9047f84434 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -3,18 +3,22 @@
  * Texas Instruments System Control Interface Protocol Driver
  * Based on drivers/firmware/ti_sci.c from Linux.
  *
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
  *	Lokesh Vutla <lokeshvutla@xxxxxx>
  */
 
-#include <common.h>
 #include <mailbox.h>
-#include <restart.h>
+#include <driver.h>
 #include <soc/ti/k3-sec-proxy.h>
 #include <soc/ti/ti_sci_protocol.h>
+#include <linux/slab.h>
+#include <linux/device.h>
 
 #include "ti_sci.h"
 
+/* List of all TI SCI devices active in system */
+static LIST_HEAD(ti_sci_list);
+
 /**
  * struct ti_sci_xfer - Structure representing a message flow
  * @tx_message:	Transmit message
@@ -126,7 +130,6 @@ static struct ti_sci_xfer *ti_sci_setup_one_xfer(struct ti_sci_info *info,
 		return ERR_PTR(-ERANGE);
 	}
 
-
 	info->seq = ~info->seq;
 	xfer->tx_message.buf = buf;
 	xfer->tx_message.len = tx_message_size;
@@ -223,21 +226,27 @@ static int ti_sci_do_xfer(struct ti_sci_info *info,
 {
 	struct k3_sec_proxy_msg *msg = &xfer->tx_message;
 	u8 secure_buf[info->desc->max_msg_size];
-	struct ti_sci_secure_msg_hdr secure_hdr;
+	struct ti_sci_secure_msg_hdr *secure_hdr = (struct ti_sci_secure_msg_hdr *)secure_buf;
 	int ret;
 
+	/*
+	 * The reason why we need the is_secure code is because of boot R5.
+	 * boot R5 starts off in "secure mode" when it hands off from Boot
+	 * ROM over to the Secondary bootloader. The initial set of calls
+	 * we have to make need to be on a secure pipe.
+	 */
 	if (info->is_secure) {
 		/* ToDo: get checksum of the entire message */
-		secure_hdr.checksum = 0;
-		secure_hdr.reserved = 0;
-		memcpy(&secure_buf[sizeof(secure_hdr)], xfer->tx_message.buf,
+		secure_hdr->checksum = 0;
+		secure_hdr->reserved = 0;
+		memcpy(&secure_buf[sizeof(*secure_hdr)], xfer->tx_message.buf,
 		       xfer->tx_message.len);
 
 		xfer->tx_message.buf = (u32 *)secure_buf;
-		xfer->tx_message.len += sizeof(secure_hdr);
+		xfer->tx_message.len += sizeof(*secure_hdr);
 
 		if (xfer->rx_len)
-			xfer->rx_len += sizeof(secure_hdr);
+			xfer->rx_len += sizeof(*secure_hdr);
 	}
 
 	/* Send the message */
@@ -2558,13 +2567,6 @@ static int ti_sci_cmd_change_fwl_owner(const struct ti_sci_handle *handle,
 	return ret;
 }
 
-static struct ti_sci_handle *g_handle;
-
-const struct ti_sci_handle *ti_sci_get_handle(struct device *dev)
-{
-	return g_handle;
-}
-
 /*
  * ti_sci_setup_ops() - Setup the operations structures
  * @info:	pointer to TISCI pointer
@@ -2648,57 +2650,231 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
 	fwl_ops->change_fwl_owner = ti_sci_cmd_change_fwl_owner;
 }
 
-static void ti_sci_reset(struct restart_handler *unused)
+/**
+ * ti_sci_get_handle_from_sysfw() - Get the TI SCI handle of the SYSFW
+ * @dev:	Pointer to the SYSFW device
+ *
+ * Return: pointer to handle if successful, else EINVAL if invalid conditions
+ *         are encountered.
+ */
+const
+struct ti_sci_handle *ti_sci_get_handle_from_sysfw(struct device *sci_dev)
 {
-	ti_sci_cmd_core_reboot(g_handle);
+	struct ti_sci_info *info;
+	int ret;
+
+	if (!sci_dev)
+		return ERR_PTR(-EINVAL);
+
+	info = dev_get_priv(sci_dev);
+	if (!info)
+		return ERR_PTR(-EINVAL);
+
+	ret = ti_sci_cmd_get_revision(&info->handle);
+	if (ret)
+		return ERR_PTR(-EINVAL);
+
+	return &info->handle;
 }
 
-static int ti_sci_probe(struct device *dev)
+/**
+ * ti_sci_get_handle() - Get the TI SCI handle for a device
+ * @dev:	Pointer to device for which we want SCI handle
+ *
+ * Return: pointer to handle if successful, else EINVAL if invalid conditions
+ *         are encountered.
+ */
+const struct ti_sci_handle *ti_sci_get_handle(struct device *dev)
 {
-	struct ti_sci_info *info;
-	const void *data;
-	int ret;
+	struct device *sci_dev;
 
-	if (g_handle)
-		return 0;
+	if (!dev)
+		return ERR_PTR(-EINVAL);
 
-	ret = dev_get_drvdata(dev, &data);
-        if (ret)
-                return ret;
+	sci_dev = dev->parent;
 
-	info = xzalloc(sizeof(*info));
+	return ti_sci_get_handle_from_sysfw(sci_dev);
+}
 
-	info->chan_rx = mbox_request_channel_byname(dev, "rx");
-	if (IS_ERR(info->chan_rx))
-		return PTR_ERR(info->chan_rx);
+/**
+ * ti_sci_get_by_phandle() - Get the TI SCI handle using DT phandle
+ * @dev:	device node
+ * @propname:	property name containing phandle on TISCI node
+ *
+ * Return: pointer to handle if successful, else appropriate error value.
+ */
+const struct ti_sci_handle *ti_sci_get_by_phandle(struct device *dev,
+						  const char *property)
+{
+	struct ti_sci_info *entry, *info = NULL;
+	struct device_node *np;
+
+	np = of_parse_phandle(dev->of_node, property, 0);
+	if (!np)
+		return ERR_PTR(-EINVAL);
+
+	of_device_ensure_probed(np);
+
+	list_for_each_entry(entry, &ti_sci_list, list)
+		if (dev_of_node(entry->dev) == np) {
+			info = entry;
+			break;
+		}
 
+	if (!info)
+		return ERR_PTR(-ENODEV);
+
+	return &info->handle;
+}
+
+/**
+ * ti_sci_of_to_info() - generate private data from device tree
+ * @dev:	corresponding system controller interface device
+ * @info:	pointer to driver specific private data
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int ti_sci_of_to_info(struct device *dev, struct ti_sci_info *info)
+{
 	info->chan_tx = mbox_request_channel_byname(dev, "tx");
-	if (IS_ERR(info->chan_tx))
+	if (IS_ERR(info->chan_tx)) {
+		dev_err(dev, "%s: Acquiring Tx channel failed: %pe\n",
+			__func__, info->chan_tx);
 		return PTR_ERR(info->chan_tx);
+	}
+
+	info->chan_rx = mbox_request_channel_byname(dev, "rx");
+	if (IS_ERR(info->chan_rx)) {
+		dev_err(dev, "%s: Acquiring Rx channel failed: %pe\n",
+			__func__, info->chan_rx);
+		return PTR_ERR(info->chan_rx);
+	}
+
+	/* Notify channel is optional. Enable only if populated */
+	info->chan_notify = mbox_request_channel_byname(dev, "notify");
+	if (IS_ERR(info->chan_notify)) {
+		dev_dbg(dev, "%s: Acquiring notify channel failed: %pe\n",
+			__func__, info->chan_notify);
+	}
 
-	info->desc = data;
 	info->host_id = info->desc->default_host_id;
 	of_property_read_u32(dev->of_node, "ti,host-id", &info->host_id);
 
-        info->is_secure = of_property_read_bool(dev->of_node, "ti,secure-host");
+	info->is_secure = of_property_read_bool(dev->of_node, "ti,secure-host");
+
+	return 0;
+}
+
+/**
+ * ti_sci_probe() - Basic probe
+ * @dev:	corresponding system controller interface device
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int ti_sci_probe(struct device *dev)
+{
+	struct ti_sci_info *info;
+	int ret;
+
+	info = xzalloc(sizeof(*info));
+	info->desc = device_get_match_data(dev);
+
+	ret = ti_sci_of_to_info(dev, info);
+	if (ret) {
+		dev_err(dev, "%s: Probe failed with error %d\n", __func__, ret);
+		return ret;
+	}
 
+	dev->priv = info;
 	info->dev = dev;
-	info->seq = 0xA;
-	INIT_LIST_HEAD(&info->dev_list);
+	info->seq = 0xa;
 
+	list_add_tail(&info->list, &ti_sci_list);
 	ti_sci_setup_ops(info);
 
-	ret = ti_sci_cmd_get_revision(&info->handle);
+	INIT_LIST_HEAD(&info->dev_list);
+
+	return 0;
+}
+
+/**
+ * devm_ti_sci_get_of_resource() - Get a TISCI resource assigned to a device
+ * @handle:	TISCI handle
+ * @dev:	Device pointer to which the resource is assigned
+ * @of_prop:	property name by which the resource are represented
+ *
+ * Note: This function expects of_prop to be in the form of tuples
+ *	<type, subtype>. Allocates and initializes ti_sci_resource structure
+ *	for each of_prop. Client driver can directly call
+ *	ti_sci_(get_free, release)_resource apis for handling the resource.
+ *
+ * Return: Pointer to ti_sci_resource if all went well else appropriate
+ *	   error pointer.
+ */
+struct ti_sci_resource *
+devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
+			    struct device *dev, u32 dev_id, char *of_prop)
+{
+	u32 resource_subtype;
+	struct ti_sci_resource *res;
+	bool valid_set = false;
+	int sets, i, ret;
+	u32 *temp;
+	const void *pp;
+
+	res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
+	if (!res)
+		return ERR_PTR(-ENOMEM);
+
+	pp = of_get_property(dev->of_node, of_prop, &sets);
+	if (!pp) {
+		dev_err(dev, "%s resource type ids not available\n", of_prop);
+		return ERR_PTR(sets);
+	}
+	temp = malloc(sets);
+	sets /= sizeof(u32);
+	res->sets = sets;
+
+	res->desc = devm_kcalloc(dev, res->sets, sizeof(*res->desc),
+				 GFP_KERNEL);
+	if (!res->desc)
+		return ERR_PTR(-ENOMEM);
+
+	ret = of_property_read_u32_array(dev->of_node, of_prop, temp, res->sets);
 	if (ret)
-		return ret;
+		return ERR_PTR(-EINVAL);
+
+	for (i = 0; i < res->sets; i++) {
+		resource_subtype = temp[i];
+		ret = handle->ops.rm_core_ops.get_range(handle, dev_id,
+							resource_subtype,
+							&res->desc[i].start,
+							&res->desc[i].num);
+		if (ret) {
+			dev_dbg(dev, "type %d subtype %d not allocated for host %d\n",
+				dev_id, resource_subtype,
+				handle_to_ti_sci_info(handle)->host_id);
+			res->desc[i].start = 0;
+			res->desc[i].num = 0;
+			continue;
+		}
 
-	g_handle = &info->handle;
+		valid_set = true;
+		dev_dbg(dev, "res type = %d, subtype = %d, start = %d, num = %d\n",
+			dev_id, resource_subtype, res->desc[i].start,
+			res->desc[i].num);
 
-	of_platform_populate(dev->of_node, NULL, NULL);
+		res->desc[i].res_map =
+			devm_kzalloc(dev, BITS_TO_LONGS(res->desc[i].num) *
+				     sizeof(*res->desc[i].res_map), GFP_KERNEL);
+		if (!res->desc[i].res_map)
+			return ERR_PTR(-ENOMEM);
+	}
 
-	restart_handler_register_fn("ti-sci", ti_sci_reset);
+	if (valid_set)
+		return res;
 
-	return 0;
+	return ERR_PTR(-EINVAL);
 }
 
 /* Description for K2G */
@@ -2721,7 +2897,7 @@ static const struct ti_sci_desc ti_sci_pmmc_am654_desc = {
 	.max_msg_size = 60,
 };
 
-static const struct of_device_id ti_sci_of_match[] = {
+static const struct of_device_id of_ti_sci_ids[] = {
 	{
 		.compatible = "ti,k2g-sci",
 		.data = &ti_sci_pmmc_k2g_desc
@@ -2729,14 +2905,14 @@ static const struct of_device_id ti_sci_of_match[] = {
 		.compatible = "ti,am654-sci",
 		.data = &ti_sci_pmmc_am654_desc
 	}, {
-		/* sentinel */
-	}
+		/* Sentinel */
+	},
 };
-MODULE_DEVICE_TABLE(of, ti_sci_of_match);
 
 static struct driver ti_sci_driver = {
-        .name   = "ti-sci",
-        .probe  = ti_sci_probe,
-        .of_compatible = DRV_OF_COMPAT(ti_sci_of_match),
+	.probe  = ti_sci_probe,
+	.name   = "ti_sci",
+	.of_compatible = of_ti_sci_ids,
 };
+
 core_platform_driver(ti_sci_driver);
diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h
index 101210eb21..bb8bc7beea 100644
--- a/drivers/firmware/ti_sci.h
+++ b/drivers/firmware/ti_sci.h
@@ -6,7 +6,7 @@
  * The system works in a message response protocol
  * See: http://processors.wiki.ti.com/index.php/TISCI for details
  *
- * Copyright (C)  2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C)  2018 Texas Instruments Incorporated - https://www.ti.com/
  * Based on drivers/firmware/ti_sci.h from Linux.
  *
  */
diff --git a/include/soc/ti/ti_sci_protocol.h b/include/soc/ti/ti_sci_protocol.h
index ec69f07b8e..f41ed82b91 100644
--- a/include/soc/ti/ti_sci_protocol.h
+++ b/include/soc/ti/ti_sci_protocol.h
@@ -3,7 +3,7 @@
  * Texas Instruments System Control Interface Protocol
  * Based on include/linux/soc/ti/ti_sci_protocol.h from Linux.
  *
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
  *	Nishanth Menon
  *	Lokesh Vutla <lokeshvutla@xxxxxx>
  */
@@ -652,6 +652,42 @@ struct ti_sci_resource {
 	struct ti_sci_resource_desc *desc;
 };
 
+#if IS_ENABLED(CONFIG_TI_SCI_PROTOCOL)
+
+const struct ti_sci_handle *ti_sci_get_handle_from_sysfw(struct device *dev);
 const struct ti_sci_handle *ti_sci_get_handle(struct device *dev);
+const struct ti_sci_handle *ti_sci_get_by_phandle(struct device *dev,
+						  const char *property);
+struct ti_sci_resource *
+devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
+			    struct device *dev, u32 dev_id, char *of_prop);
+#else	/* CONFIG_TI_SCI_PROTOCOL */
+
+static inline
+const struct ti_sci_handle *ti_sci_get_handle_from_sysfw(struct device *dev)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline const struct ti_sci_handle *ti_sci_get_handle(struct device *dev)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline
+const struct ti_sci_handle *ti_sci_get_by_phandle(struct device *dev,
+						  const char *property)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline struct ti_sci_resource *
+devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
+			    struct device *dev, u32 dev_id, char *of_prop)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+#endif	/* CONFIG_TI_SCI_PROTOCOL */
 
 #endif	/* __TISCI_PROTOCOL_H */

-- 
2.39.5





[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux