ti: k3: drivers: ti_sci: Add support for Device control
TI-SCI message protocol provides support for management of various
hardware entitites within the SoC.
We introduce the fundamental device management capability support to
the driver protocol as part of this change.
Signed-off-by: Andrew F. Davis <afd@ti.com>
Reviewed-by: Andreas Dannenberg <dannenberg@ti.com>
diff --git a/plat/ti/k3/common/drivers/ti_sci/ti_sci.c b/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
index 47dc777..be77dc8 100644
--- a/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
@@ -205,6 +205,363 @@
}
/**
+ * ti_sci_is_response_ack() - Generic ACK/NACK message check
+ *
+ * @r: pointer to response buffer
+ *
+ * Return: true if the response was an ACK, else returns false
+ */
+static inline bool ti_sci_is_response_ack(void *r)
+{
+ struct ti_sci_msg_hdr *hdr = r;
+
+ return hdr->flags & TI_SCI_FLAG_RESP_GENERIC_ACK ? true : false;
+}
+
+/**
+ * ti_sci_device_set_state() - Set device state
+ *
+ * @id: Device identifier
+ * @flags: flags to setup for the device
+ * @state: State to move the device to
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_set_state(uint32_t id, uint32_t flags, uint8_t state)
+{
+ struct ti_sci_msg_req_set_device_state req;
+ struct ti_sci_msg_hdr resp;
+
+ struct ti_sci_xfer xfer;
+ int ret;
+
+ ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_DEVICE_STATE,
+ flags | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+ &req, sizeof(req),
+ &resp, sizeof(resp),
+ &xfer);
+ if (ret) {
+ ERROR("Message alloc failed (%d)\n", ret);
+ return ret;
+ }
+
+ req.id = id;
+ req.state = state;
+
+ ret = ti_sci_do_xfer(&xfer);
+ if (ret) {
+ ERROR("Transfer send failed (%d)\n", ret);
+ return ret;
+ }
+
+ if (!ti_sci_is_response_ack(&resp))
+ return -ENODEV;
+
+ return 0;
+}
+
+/**
+ * ti_sci_device_get_state() - Get device state
+ *
+ * @id: Device Identifier
+ * @clcnt: Pointer to Context Loss Count
+ * @resets: pointer to resets
+ * @p_state: pointer to p_state
+ * @c_state: pointer to c_state
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_get_state(uint32_t id, uint32_t *clcnt, uint32_t *resets,
+ uint8_t *p_state, uint8_t *c_state)
+{
+ struct ti_sci_msg_req_get_device_state req;
+ struct ti_sci_msg_resp_get_device_state resp;
+
+ struct ti_sci_xfer xfer;
+ int ret;
+
+ if (!clcnt && !resets && !p_state && !c_state)
+ return -EINVAL;
+
+ ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_DEVICE_STATE, 0,
+ &req, sizeof(req),
+ &resp, sizeof(resp),
+ &xfer);
+ if (ret) {
+ ERROR("Message alloc failed (%d)\n", ret);
+ return ret;
+ }
+
+ req.id = id;
+
+ ret = ti_sci_do_xfer(&xfer);
+ if (ret) {
+ ERROR("Transfer send failed (%d)\n", ret);
+ return ret;
+ }
+
+ if (!ti_sci_is_response_ack(&resp))
+ return -ENODEV;
+
+ if (clcnt)
+ *clcnt = resp.context_loss_count;
+ if (resets)
+ *resets = resp.resets;
+ if (p_state)
+ *p_state = resp.programmed_state;
+ if (c_state)
+ *c_state = resp.current_state;
+
+ return 0;
+}
+
+/**
+ * ti_sci_device_get() - Request for device managed by TISCI
+ *
+ * @id: Device Identifier
+ *
+ * Request for the device - NOTE: the client MUST maintain integrity of
+ * usage count by balancing get_device with put_device. No refcounting is
+ * managed by driver for that purpose.
+ *
+ * NOTE: The request is for exclusive access for the processor.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_get(uint32_t id)
+{
+ return ti_sci_device_set_state(id,
+ MSG_FLAG_DEVICE_EXCLUSIVE,
+ MSG_DEVICE_SW_STATE_ON);
+}
+
+/**
+ * ti_sci_device_idle() - Idle a device managed by TISCI
+ *
+ * @id: Device Identifier
+ *
+ * Request for the device - NOTE: the client MUST maintain integrity of
+ * usage count by balancing get_device with put_device. No refcounting is
+ * managed by driver for that purpose.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_idle(uint32_t id)
+{
+ return ti_sci_device_set_state(id,
+ MSG_FLAG_DEVICE_EXCLUSIVE,
+ MSG_DEVICE_SW_STATE_RETENTION);
+}
+
+/**
+ * ti_sci_device_put() - Release a device managed by TISCI
+ *
+ * @id: Device Identifier
+ *
+ * Request for the device - NOTE: the client MUST maintain integrity of
+ * usage count by balancing get_device with put_device. No refcounting is
+ * managed by driver for that purpose.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_put(uint32_t id)
+{
+ return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_AUTO_OFF);
+}
+
+/**
+ * ti_sci_device_is_valid() - Is the device valid
+ *
+ * @id: Device Identifier
+ *
+ * Return: 0 if all goes well and the device ID is valid, else return
+ * appropriate error
+ */
+int ti_sci_device_is_valid(uint32_t id)
+{
+ uint8_t unused;
+
+ /* check the device state which will also tell us if the ID is valid */
+ return ti_sci_device_get_state(id, NULL, NULL, NULL, &unused);
+}
+
+/**
+ * ti_sci_device_get_clcnt() - Get context loss counter
+ *
+ * @id: Device Identifier
+ * @count: Pointer to Context Loss counter to populate
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_get_clcnt(uint32_t id, uint32_t *count)
+{
+ return ti_sci_device_get_state(id, count, NULL, NULL, NULL);
+}
+
+/**
+ * ti_sci_device_is_idle() - Check if the device is requested to be idle
+ *
+ * @id: Device Identifier
+ * @r_state: true if requested to be idle
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_is_idle(uint32_t id, bool *r_state)
+{
+ int ret;
+ uint8_t state;
+
+ if (!r_state)
+ return -EINVAL;
+
+ ret = ti_sci_device_get_state(id, NULL, NULL, &state, NULL);
+ if (ret)
+ return ret;
+
+ *r_state = (state == MSG_DEVICE_SW_STATE_RETENTION);
+
+ return 0;
+}
+
+/**
+ * ti_sci_device_is_stop() - Check if the device is requested to be stopped
+ *
+ * @id: Device Identifier
+ * @r_state: true if requested to be stopped
+ * @curr_state: true if currently stopped
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_is_stop(uint32_t id, bool *r_state, bool *curr_state)
+{
+ int ret;
+ uint8_t p_state, c_state;
+
+ if (!r_state && !curr_state)
+ return -EINVAL;
+
+ ret = ti_sci_device_get_state(id, NULL, NULL, &p_state, &c_state);
+ if (ret)
+ return ret;
+
+ if (r_state)
+ *r_state = (p_state == MSG_DEVICE_SW_STATE_AUTO_OFF);
+ if (curr_state)
+ *curr_state = (c_state == MSG_DEVICE_HW_STATE_OFF);
+
+ return 0;
+}
+
+/**
+ * ti_sci_device_is_on() - Check if the device is requested to be ON
+ *
+ * @id: Device Identifier
+ * @r_state: true if requested to be ON
+ * @curr_state: true if currently ON and active
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_is_on(uint32_t id, bool *r_state, bool *curr_state)
+{
+ int ret;
+ uint8_t p_state, c_state;
+
+ if (!r_state && !curr_state)
+ return -EINVAL;
+
+ ret =
+ ti_sci_device_get_state(id, NULL, NULL, &p_state, &c_state);
+ if (ret)
+ return ret;
+
+ if (r_state)
+ *r_state = (p_state == MSG_DEVICE_SW_STATE_ON);
+ if (curr_state)
+ *curr_state = (c_state == MSG_DEVICE_HW_STATE_ON);
+
+ return 0;
+}
+
+/**
+ * ti_sci_device_is_trans() - Check if the device is currently transitioning
+ *
+ * @id: Device Identifier
+ * @curr_state: true if currently transitioning
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_is_trans(uint32_t id, bool *curr_state)
+{
+ int ret;
+ uint8_t state;
+
+ if (!curr_state)
+ return -EINVAL;
+
+ ret = ti_sci_device_get_state(id, NULL, NULL, NULL, &state);
+ if (ret)
+ return ret;
+
+ *curr_state = (state == MSG_DEVICE_HW_STATE_TRANS);
+
+ return 0;
+}
+
+/**
+ * ti_sci_device_set_resets() - Set resets for device managed by TISCI
+ *
+ * @id: Device Identifier
+ * @reset_state: Device specific reset bit field
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_set_resets(uint32_t id, uint32_t reset_state)
+{
+ struct ti_sci_msg_req_set_device_resets req;
+ struct ti_sci_msg_hdr resp;
+
+ struct ti_sci_xfer xfer;
+ int ret;
+
+ ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_DEVICE_RESETS,
+ TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
+ &req, sizeof(req),
+ &resp, sizeof(resp),
+ &xfer);
+ if (ret) {
+ ERROR("Message alloc failed (%d)\n", ret);
+ return ret;
+ }
+
+ req.id = id;
+ req.resets = reset_state;
+
+ ret = ti_sci_do_xfer(&xfer);
+ if (ret) {
+ ERROR("Transfer send failed (%d)\n", ret);
+ return ret;
+ }
+
+ if (!ti_sci_is_response_ack(&resp))
+ return -ENODEV;
+
+ return 0;
+}
+
+/**
+ * ti_sci_device_get_resets() - Get reset state for device managed by TISCI
+ *
+ * @id: Device Identifier
+ * @reset_state: Pointer to reset state to populate
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_get_resets(uint32_t id, uint32_t *reset_state)
+{
+ return ti_sci_device_get_state(id, NULL, reset_state, NULL, NULL);
+}
+
+/**
* ti_sci_init() - Basic initialization
*
* Return: 0 if all goes well, else appropriate error message
diff --git a/plat/ti/k3/common/drivers/ti_sci/ti_sci.h b/plat/ti/k3/common/drivers/ti_sci/ti_sci.h
index f8b6505..3056bda 100644
--- a/plat/ti/k3/common/drivers/ti_sci/ti_sci.h
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci.h
@@ -10,6 +10,65 @@
#ifndef __TI_SCI_H
#define __TI_SCI_H
+#include <stdint.h>
+#include <stdbool.h>
+
+/**
+ * Device control operations
+ *
+ * - ti_sci_device_set_state - Set device state helper
+ * @flags: flags to setup for the device
+ * @state: State to move the device to
+ * - ti_sci_device_get_state - Get device state helper
+ * @clcnt: Pointer to Context Loss Count
+ * @resets: pointer to resets
+ * @p_state: pointer to p_state
+ * @c_state: pointer to c_state
+ * - ti_sci_device_get - command to request for device managed by TISCI
+ * - ti_sci_device_idle - Command to idle a device managed by TISCI
+ * - ti_sci_device_put - command to release a device managed by TISCI
+ * - ti_sci_device_is_valid - Is the device valid
+ * - ti_sci_device_get_clcnt - Get context loss counter
+ * @count: Pointer to Context Loss counter to populate
+ * - ti_sci_device_is_idle - Check if the device is requested to be idle
+ * @r_state: true if requested to be idle
+ * - ti_sci_device_is_stop - Check if the device is requested to be stopped
+ * @r_state: true if requested to be stopped
+ * @curr_state: true if currently stopped.
+ * - ti_sci_device_is_on - Check if the device is requested to be ON
+ * @r_state: true if requested to be ON
+ * @curr_state: true if currently ON and active
+ * - ti_sci_device_is_trans - Check if the device is currently transitioning
+ * @curr_state: true if currently transitioning.
+ * - ti_sci_device_set_resets - Command to set resets for
+ * device managed by TISCI
+ * @reset_state: Device specific reset bit field
+ * - ti_sci_device_get_resets - Get reset state for device managed by TISCI
+ * @reset_state: Pointer to reset state to populate
+ *
+ * NOTE: for all these functions, the following are generic in nature:
+ * @id: Device Identifier
+ * Returns 0 for successful request, else returns corresponding error message.
+ *
+ * Request for the device - NOTE: the client MUST maintain integrity of
+ * usage count by balancing get_device with put_device. No refcounting is
+ * managed by driver for that purpose.
+ */
+int ti_sci_device_set_state(uint32_t id, uint32_t flags, uint8_t state);
+int ti_sci_device_get_state(uint32_t id, uint32_t *clcnt, uint32_t *resets,
+ uint8_t *p_state, uint8_t *c_state);
+int ti_sci_device_get(uint32_t id);
+int ti_sci_device_idle(uint32_t id);
+int ti_sci_device_put(uint32_t id);
+int ti_sci_device_is_valid(uint32_t id);
+int ti_sci_device_get_clcnt(uint32_t id, uint32_t *count);
+int ti_sci_device_is_idle(uint32_t id, bool *r_state);
+int ti_sci_device_is_stop(uint32_t id, bool *r_state, bool *curr_state);
+int ti_sci_device_is_on(uint32_t id, bool *r_state, bool *curr_state);
+int ti_sci_device_is_trans(uint32_t id, bool *curr_state);
+int ti_sci_device_set_resets(uint32_t id, uint32_t reset_state);
+int ti_sci_device_get_resets(uint32_t id, uint32_t *reset_state);
+
/**
* ti_sci_init() - Basic initialization
*