summaryrefslogtreecommitdiff
path: root/drivers/firmware
diff options
context:
space:
mode:
authorLokesh Vutla <lokeshvutla@ti.com>2019-06-07 16:54:41 +0300
committerTom Rini <trini@konsulko.com>2019-07-27 04:49:22 +0300
commit9566b777ae0ae01a9899aa7e225076ee8d4af861 (patch)
tree4658047006c6912bdd7563f717bd453352c29020 /drivers/firmware
parent410adcc9e2750d6852afe9f544cd74ad434f8937 (diff)
downloadu-boot-9566b777ae0ae01a9899aa7e225076ee8d4af861.tar.xz
firmware: ti_sci: Add a command for releasing all exclusive devices
Any host while requesting for a device can request for its exclusive access. If an exclusive permission is obtained then it is the host's responsibility to release the device before the software entity on the host completes its execution. Else any other host's request for the device will be nacked. So add a command that releases all the exclusive devices that is acquired by the current host. This should be used with utmost care and can be called only at the end of the execution. Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/ti_sci.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 8c68f98788..1fd29f2cdf 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -87,11 +87,18 @@ struct ti_sci_info {
struct mbox_chan chan_notify;
struct ti_sci_xfer xfer;
struct list_head list;
+ struct list_head dev_list;
bool is_secure;
u8 host_id;
u8 seq;
};
+struct ti_sci_exclusive_dev {
+ u32 id;
+ u32 count;
+ struct list_head list;
+};
+
#define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle)
/**
@@ -427,6 +434,47 @@ static int ti_sci_cmd_set_board_config_pm(const struct ti_sci_handle *handle,
addr, size);
}
+static struct ti_sci_exclusive_dev
+*ti_sci_get_exclusive_dev(struct list_head *dev_list, u32 id)
+{
+ struct ti_sci_exclusive_dev *dev;
+
+ list_for_each_entry(dev, dev_list, list)
+ if (dev->id == id)
+ return dev;
+
+ return NULL;
+}
+
+static void ti_sci_add_exclusive_dev(struct ti_sci_info *info, u32 id)
+{
+ struct ti_sci_exclusive_dev *dev;
+
+ dev = ti_sci_get_exclusive_dev(&info->dev_list, id);
+ if (dev) {
+ dev->count++;
+ return;
+ }
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ dev->id = id;
+ dev->count = 1;
+ INIT_LIST_HEAD(&dev->list);
+ list_add_tail(&dev->list, &info->dev_list);
+}
+
+static void ti_sci_delete_exclusive_dev(struct ti_sci_info *info, u32 id)
+{
+ struct ti_sci_exclusive_dev *dev;
+
+ dev = ti_sci_get_exclusive_dev(&info->dev_list, id);
+ if (!dev)
+ return;
+
+ if (dev->count > 0)
+ dev->count--;
+}
+
/**
* ti_sci_set_device_state() - Set device state helper
* @handle: pointer to TI SCI handle
@@ -474,6 +522,11 @@ static int ti_sci_set_device_state(const struct ti_sci_handle *handle,
if (!ti_sci_is_response_ack(resp))
return -ENODEV;
+ if (state == MSG_DEVICE_SW_STATE_AUTO_OFF)
+ ti_sci_delete_exclusive_dev(info, id);
+ else if (flags & MSG_FLAG_DEVICE_EXCLUSIVE)
+ ti_sci_add_exclusive_dev(info, id);
+
return ret;
}
@@ -651,6 +704,25 @@ static int ti_sci_cmd_put_device(const struct ti_sci_handle *handle, u32 id)
MSG_DEVICE_SW_STATE_AUTO_OFF);
}
+static
+int ti_sci_cmd_release_exclusive_devices(const struct ti_sci_handle *handle)
+{
+ struct ti_sci_exclusive_dev *dev, *tmp;
+ struct ti_sci_info *info;
+ int i, cnt;
+
+ info = handle_to_ti_sci_info(handle);
+
+ list_for_each_entry_safe(dev, tmp, &info->dev_list, list) {
+ cnt = dev->count;
+ debug("%s: id = %d, cnt = %d\n", __func__, dev->id, cnt);
+ for (i = 0; i < cnt; i++)
+ ti_sci_cmd_put_device(handle, dev->id);
+ }
+
+ return 0;
+}
+
/**
* ti_sci_cmd_dev_is_valid() - Is the device valid
* @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle
@@ -2839,6 +2911,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
dops->is_transitioning = ti_sci_cmd_dev_is_trans;
dops->set_device_resets = ti_sci_cmd_set_device_resets;
dops->get_device_resets = ti_sci_cmd_get_device_resets;
+ dops->release_exclusive_devices = ti_sci_cmd_release_exclusive_devices;
cops->get_clock = ti_sci_cmd_get_clock;
cops->idle_clock = ti_sci_cmd_idle_clock;
@@ -3033,6 +3106,8 @@ static int ti_sci_probe(struct udevice *dev)
ret = ti_sci_cmd_get_revision(&info->handle);
+ INIT_LIST_HEAD(&info->dev_list);
+
return ret;
}