Message ID | 20160819225159.10758-4-nm@ti.com (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers | show |
On Saturday 20 August 2016 04:21 AM, Nishanth Menon wrote: > Texas Instrument's System Control Interface (TI-SCI) Message Protocol > is used in Texas Instrument's System on Chip (SoC) such as those > in keystone family K2G SoC to communicate between various compute > processors with a central system controller entity. > > TI-SCI message protocol provides support for management of various > hardware entitites within the SoC. Add support driver to allow > communication with system controller entity within the SoC using the > mailbox client. > > We introduce the fundamental device management capability support to > the driver protocol as part of this change. > > [d-gerlach@ti.com: Contributed device reset handling] > Signed-off-by: Dave Gerlach <d-gerlach@ti.com> > Signed-off-by: Nishanth Menon <nm@ti.com> > --- > drivers/firmware/ti_sci.c | 433 +++++++++++++++++++++++++++++++++ > drivers/firmware/ti_sci.h | 98 ++++++++ > include/linux/soc/ti/ti_sci_protocol.h | 91 +++++++ > 3 files changed, 622 insertions(+) > > diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c > index 4580c29dcb52..e0e286e76095 100644 > --- a/drivers/firmware/ti_sci.c > +++ b/drivers/firmware/ti_sci.c > @@ -496,6 +496,437 @@ fail: > } > > /** > + * tis_sci_is_response_ack() - Generic ACK/NACK message checkup > + * @r: pointer to response buffer > + * > + * Return: true if the response was an ACK, else returns false. > + */ > +static inline bool tis_sci_is_response_ack(void *r) May be just ti_sci_is_response_ack() to be consistent? or you wanted to keep it tis_sci* ? > +{ > + struct ti_sci_msg_hdr *hdr = r; > + > + return hdr->flags & TI_SCI_FLAG_RESP_GENERIC_ACK ? true : false; > +} > + > +/** > + * ti_sci_set_device_state() - Set device state helper > + * @handle: pointer to TI SCI handle > + * @id: Device identifier > + * @flags: flags to setup for the device > + * @state: State to move the device to > + * > + * Return: 0 if all went well, else returns appropriate error value. > + */ > +static int ti_sci_set_device_state(const struct ti_sci_handle *handle, > + u32 id, u32 flags, u8 state) > +{ > + struct ti_sci_info *info; > + struct ti_sci_msg_req_set_device_state *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_SET_DEVICE_STATE, > + flags | 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_set_device_state *)xfer->xfer_buf; > + req->id = id; > + req->state = state; > + > + 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; > + > + ret = tis_sci_is_response_ack(resp) ? 0 : -ENODEV; > + > +fail: > + ti_sci_put_one_xfer(&info->minfo, xfer); > + > + return ret; > +} > + > +/** > + * ti_sci_get_device_state() - Get device state helper > + * @handle: Handle to the device > + * @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 went fine, else return appropriate error. > + */ > +static int ti_sci_get_device_state(const struct ti_sci_handle *handle, > + u32 id, u32 *clcnt, u32 *resets, > + u8 *p_state, u8 *c_state) > +{ > + struct ti_sci_info *info; > + struct ti_sci_msg_req_get_device_state *req; > + struct ti_sci_msg_resp_get_device_state *resp; > + struct ti_sci_xfer *xfer; > + struct device *dev; > + int ret = 0; > + > + if (IS_ERR(handle)) > + return PTR_ERR(handle); > + if (!handle) > + return -EINVAL; > + > + if (!clcnt && !resets && !p_state && !c_state) > + return -EINVAL; > + > + info = handle_to_ti_sci_info(handle); > + dev = info->dev; > + > + /* Response is expected, so need of any flags */ ^^ no* Thanks and regards, Lokesh > + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_DEVICE_STATE, > + 0, 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_get_device_state *)xfer->xfer_buf; > + req->id = id; > + > + 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_resp_get_device_state *)xfer->xfer_buf; > + if (!tis_sci_is_response_ack(resp)) { > + ret = -ENODEV; > + goto fail; > + } > + > + 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; > +fail: > + ti_sci_put_one_xfer(&info->minfo, xfer); > + > + return ret; > +} > + > +/** > + * ti_sci_cmd_get_device() - command to request for device managed by TISCI > + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle > + * @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 went fine, else return appropriate error. > + */ > +static int ti_sci_cmd_get_device(const struct ti_sci_handle *handle, u32 id) > +{ > + return ti_sci_set_device_state(handle, id, > + MSG_FLAG_DEVICE_EXCLUSIVE, > + MSG_DEVICE_SW_STATE_ON); > +} > + > +/** > + * ti_sci_cmd_idle_device() - Command to idle a device managed by TISCI > + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle > + * @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 went fine, else return appropriate error. > + */ > +static int ti_sci_cmd_idle_device(const struct ti_sci_handle *handle, u32 id) > +{ > + return ti_sci_set_device_state(handle, id, > + MSG_FLAG_DEVICE_EXCLUSIVE, > + MSG_DEVICE_SW_STATE_RETENTION); > +} > + > +/** > + * ti_sci_cmd_put_device() - command to release a device managed by TISCI > + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle > + * @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 went fine, else return appropriate error. > + */ > +static int ti_sci_cmd_put_device(const struct ti_sci_handle *handle, u32 id) > +{ > + return ti_sci_set_device_state(handle, id, > + 0, MSG_DEVICE_SW_STATE_AUTO_OFF); > +} > + > +/** > + * ti_sci_cmd_dev_is_valid() - Is the device valid > + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle > + * @id: Device Identifier > + * > + * Return: 0 if all went fine and the device ID is valid, else return > + * appropriate error. > + */ > +static int ti_sci_cmd_dev_is_valid(const struct ti_sci_handle *handle, u32 id) > +{ > + u8 unused; > + > + /* check the device state which will also tell us if the ID is valid */ > + return ti_sci_get_device_state(handle, id, NULL, NULL, NULL, &unused); > +} > + > +/** > + * ti_sci_cmd_dev_get_clcnt() - Get context loss counter > + * @handle: Pointer to TISCI handle > + * @id: Device Identifier > + * @count: Pointer to Context Loss counter to populate > + * > + * Return: 0 if all went fine, else return appropriate error. > + */ > +static int ti_sci_cmd_dev_get_clcnt(const struct ti_sci_handle *handle, u32 id, > + u32 *count) > +{ > + return ti_sci_get_device_state(handle, id, count, NULL, NULL, NULL); > +} > + > +/** > + * ti_sci_cmd_dev_is_idle() - Check if the device is requested to be idle > + * @handle: Pointer to TISCI handle > + * @id: Device Identifier > + * @r_state: true if requested to be idle > + * > + * Return: 0 if all went fine, else return appropriate error. > + */ > +static int ti_sci_cmd_dev_is_idle(const struct ti_sci_handle *handle, u32 id, > + bool *r_state) > +{ > + int ret; > + u8 state; > + > + if (!r_state) > + return -EINVAL; > + > + ret = ti_sci_get_device_state(handle, id, NULL, NULL, &state, NULL); > + if (ret) > + return ret; > + > + *r_state = (state == MSG_DEVICE_SW_STATE_RETENTION); > + > + return 0; > +} > + > +/** > + * ti_sci_cmd_dev_is_stop() - Check if the device is requested to be stopped > + * @handle: Pointer to TISCI handle > + * @id: Device Identifier > + * @r_state: true if requested to be stopped > + * @curr_state: true if currently stopped. > + * > + * Return: 0 if all went fine, else return appropriate error. > + */ > +static int ti_sci_cmd_dev_is_stop(const struct ti_sci_handle *handle, u32 id, > + bool *r_state, bool *curr_state) > +{ > + int ret; > + u8 p_state, c_state; > + > + if (!r_state && !curr_state) > + return -EINVAL; > + > + ret = > + ti_sci_get_device_state(handle, 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_cmd_dev_is_on() - Check if the device is requested to be ON > + * @handle: Pointer to TISCI handle > + * @id: Device Identifier > + * @r_state: true if requested to be ON > + * @curr_state: true if currently ON and active > + * > + * Return: 0 if all went fine, else return appropriate error. > + */ > +static int ti_sci_cmd_dev_is_on(const struct ti_sci_handle *handle, u32 id, > + bool *r_state, bool *curr_state) > +{ > + int ret; > + u8 p_state, c_state; > + > + if (!r_state && !curr_state) > + return -EINVAL; > + > + ret = > + ti_sci_get_device_state(handle, 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_cmd_dev_is_trans() - Check if the device is currently transitioning > + * @handle: Pointer to TISCI handle > + * @id: Device Identifier > + * @curr_state: true if currently transitioning. > + * > + * Return: 0 if all went fine, else return appropriate error. > + */ > +static int ti_sci_cmd_dev_is_trans(const struct ti_sci_handle *handle, u32 id, > + bool *curr_state) > +{ > + int ret; > + u8 state; > + > + if (!curr_state) > + return -EINVAL; > + > + ret = ti_sci_get_device_state(handle, id, NULL, NULL, NULL, &state); > + if (ret) > + return ret; > + > + *curr_state = (state == MSG_DEVICE_HW_STATE_TRANS); > + > + return 0; > +} > + > +/** > + * ti_sci_cmd_set_device_resets() - command to set resets for device managed > + * by TISCI > + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle > + * @id: Device Identifier > + * @reset_state: Device specific reset bit field > + * > + * Return: 0 if all went fine, else return appropriate error. > + */ > +static int ti_sci_cmd_set_device_resets(const struct ti_sci_handle *handle, > + u32 id, u32 reset_state) > +{ > + struct ti_sci_info *info; > + struct ti_sci_msg_req_set_device_resets *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_SET_DEVICE_RESETS, > + 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_set_device_resets *)xfer->xfer_buf; > + req->id = id; > + req->resets = reset_state; > + > + 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; > + > + ret = tis_sci_is_response_ack(resp) ? 0 : -ENODEV; > + > +fail: > + ti_sci_put_one_xfer(&info->minfo, xfer); > + > + return ret; > +} > + > +/** > + * ti_sci_cmd_get_device_resets() - Get reset state for device managed > + * by TISCI > + * @handle: Pointer to TISCI handle > + * @id: Device Identifier > + * @reset_state: Pointer to reset state to populate > + * > + * Return: 0 if all went fine, else return appropriate error. > + */ > +static int ti_sci_cmd_get_device_resets(const struct ti_sci_handle *handle, > + u32 id, u32 *reset_state) > +{ > + return ti_sci_get_device_state(handle, id, NULL, reset_state, NULL, > + NULL); > +} > + > +/* > + * ti_sci_setup_ops() - Setup the operations structures > + * @info: pointer to TISCI pointer > + */ > +static void ti_sci_setup_ops(struct ti_sci_info *info) > +{ > + struct ti_sci_ops *ops = &info->handle.ops; > + struct ti_sci_dev_ops *dops = &ops->dev_ops; > + > + dops->get_device = ti_sci_cmd_get_device; > + dops->idle_device = ti_sci_cmd_idle_device; > + dops->put_device = ti_sci_cmd_put_device; > + > + dops->is_valid = ti_sci_cmd_dev_is_valid; > + dops->get_context_loss_count = ti_sci_cmd_dev_get_clcnt; > + dops->is_idle = ti_sci_cmd_dev_is_idle; > + dops->is_stop = ti_sci_cmd_dev_is_stop; > + dops->is_on = ti_sci_cmd_dev_is_on; > + 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; > +} > + > +/** > * ti_sci_get_handle() - Get the TI SCI handle for a device > * @dev: Pointer to device for which we want SCI handle > * > @@ -735,6 +1166,8 @@ static int ti_sci_probe(struct platform_device *pdev) > goto out; > } > > + ti_sci_setup_ops(info); > + > 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.firmware_revision, > diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h > index e9dc53f26e0e..29ce0532a7ca 100644 > --- a/drivers/firmware/ti_sci.h > +++ b/drivers/firmware/ti_sci.h > @@ -47,6 +47,11 @@ > #define TI_SCI_MSG_WAKE_REASON 0x0003 > #define TI_SCI_MSG_GOODBYE 0x0004 > > +/* Device requests */ > +#define TI_SCI_MSG_SET_DEVICE_STATE 0x0200 > +#define TI_SCI_MSG_GET_DEVICE_STATE 0x0201 > +#define TI_SCI_MSG_SET_DEVICE_RESETS 0x0202 > + > /** > * struct ti_sci_msg_hdr - Generic Message Header for All messages and responses > * @type: Type of messages: One of TI_SCI_MSG* values > @@ -90,4 +95,97 @@ struct ti_sci_msg_resp_version { > u8 abi_minor; > } __packed; > > +/** > + * struct ti_sci_msg_req_set_device_state - Set the desired state of the device > + * @hdr: Generic header > + * @id: Indicates which device to modify > + * @reserved: Reserved space in message, must be 0 for backward compatibility > + * @state: The desired state of the device. > + * > + * Certain flags can also be set to alter the device state: > + * + MSG_FLAG_DEVICE_WAKE_ENABLED - Configure the device to be a wake source. > + * The meaning of this flag will vary slightly from device to device and from > + * SoC to SoC but it generally allows the device to wake the SoC out of deep > + * suspend states. > + * + MSG_FLAG_DEVICE_RESET_ISO - Enable reset isolation for this device. > + * + MSG_FLAG_DEVICE_EXCLUSIVE - Claim this device exclusively. When passed > + * with STATE_RETENTION or STATE_ON, it will claim the device exclusively. > + * If another host already has this device set to STATE_RETENTION or STATE_ON, > + * the message will fail. Once successful, other hosts attempting to set > + * STATE_RETENTION or STATE_ON will fail. > + * > + * Request type is TI_SCI_MSG_SET_DEVICE_STATE, responded with a generic > + * ACK/NACK message. > + */ > +struct ti_sci_msg_req_set_device_state { > + /* Additional hdr->flags options */ > +#define MSG_FLAG_DEVICE_WAKE_ENABLED TI_SCI_MSG_FLAG(8) > +#define MSG_FLAG_DEVICE_RESET_ISO TI_SCI_MSG_FLAG(9) > +#define MSG_FLAG_DEVICE_EXCLUSIVE TI_SCI_MSG_FLAG(10) > + struct ti_sci_msg_hdr hdr; > + u32 id; > + u32 reserved; > + > +#define MSG_DEVICE_SW_STATE_AUTO_OFF 0 > +#define MSG_DEVICE_SW_STATE_RETENTION 1 > +#define MSG_DEVICE_SW_STATE_ON 2 > + u8 state; > +} __packed; > + > +/** > + * struct ti_sci_msg_req_get_device_state - Request to get device. > + * @hdr: Generic header > + * @id: Device Identifier > + * > + * Request type is TI_SCI_MSG_GET_DEVICE_STATE, responded device state > + * information > + */ > +struct ti_sci_msg_req_get_device_state { > + struct ti_sci_msg_hdr hdr; > + u32 id; > +} __packed; > + > +/** > + * struct ti_sci_msg_resp_get_device_state - Response to get device request. > + * @hdr: Generic header > + * @context_loss_count: Indicates how many times the device has lost context. A > + * driver can use this monotonic counter to determine if the device has > + * lost context since the last time this message was exchanged. > + * @resets: Programmed state of the reset lines. > + * @programmed_state: The state as programmed by set_device. > + * - Uses the MSG_DEVICE_SW_* macros > + * @current_state: The actual state of the hardware. > + * > + * Response to request TI_SCI_MSG_GET_DEVICE_STATE. > + */ > +struct ti_sci_msg_resp_get_device_state { > + struct ti_sci_msg_hdr hdr; > + u32 context_loss_count; > + u32 resets; > + u8 programmed_state; > +#define MSG_DEVICE_HW_STATE_OFF 0 > +#define MSG_DEVICE_HW_STATE_ON 1 > +#define MSG_DEVICE_HW_STATE_TRANS 2 > + u8 current_state; > +} __packed; > + > +/** > + * struct ti_sci_msg_req_set_device_resets - Set the desired resets > + * configuration of the device > + * @hdr: Generic header > + * @id: Indicates which device to modify > + * @resets: A bit field of resets for the device. The meaning, behavior, > + * and usage of the reset flags are device specific. 0 for a bit > + * indicates releasing the reset represented by that bit while 1 > + * indicates keeping it held. > + * > + * Request type is TI_SCI_MSG_SET_DEVICE_RESETS, responded with a generic > + * ACK/NACK message. > + */ > +struct ti_sci_msg_req_set_device_resets { > + struct ti_sci_msg_hdr hdr; > + u32 id; > + u32 resets; > +} __packed; > + > #endif /* __TI_SCI_H */ > diff --git a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/ti_sci_protocol.h > index e73483fd5327..87fa73851471 100644 > --- a/include/linux/soc/ti/ti_sci_protocol.h > +++ b/include/linux/soc/ti/ti_sci_protocol.h > @@ -33,12 +33,103 @@ struct ti_sci_version_info { > char firmware_description[32]; > }; > > +struct ti_sci_handle; > + > +/** > + * struct ti_sci_dev_ops - Device control operations > + * @get_device: Command to request for device managed by TISCI > + * Returns 0 for successful exclusive request, else returns > + * corresponding error message. > + * @idle_device: Command to idle a device managed by TISCI > + * Returns 0 for successful exclusive request, else returns > + * corresponding error message. > + * @put_device: Command to release a device managed by TISCI > + * Returns 0 for successful release, else returns corresponding > + * error message. > + * @is_valid: Check if the device ID is a valid ID. > + * Returns 0 if the ID is valid, else returns corresponding error. > + * @get_context_loss_count: Command to retrieve context loss counter - this > + * increments every time the device looses context. Overflow > + * is possible. > + * - count: pointer to u32 which will retrieve counter > + * Returns 0 for successful information request and count has > + * proper data, else returns corresponding error message. > + * @is_idle: Reports back about device idle state > + * - req_state: Returns requested idle state > + * Returns 0 for successful information request and req_state and > + * current_state has proper data, else returns corresponding error > + * message. > + * @is_stop: Reports back about device stop state > + * - req_state: Returns requested stop state > + * - current_state: Returns current stop state > + * Returns 0 for successful information request and req_state and > + * current_state has proper data, else returns corresponding error > + * message. > + * @is_on: Reports back about device ON(or active) state > + * - req_state: Returns requested ON state > + * - current_state: Returns current ON state > + * Returns 0 for successful information request and req_state and > + * current_state has proper data, else returns corresponding error > + * message. > + * @is_transitioning: Reports back if the device is in the middle of transition > + * of state. > + * -current_state: Returns 'true' if currently transitioning. > + * @set_device_resets: Command to configure resets for device managed by TISCI. > + * -reset_state: Device specific reset bit field > + * Returns 0 for successful request, else returns > + * corresponding error message. > + * @get_device_resets: Command to read state of resets for device managed > + * by TISCI. > + * -reset_state: pointer to u32 which will retrieve resets > + * Returns 0 for successful request, else returns > + * corresponding error message. > + * > + * NOTE: for all these functions, the following parameters are generic in > + * nature: > + * -handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle > + * -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. > + */ > +struct ti_sci_dev_ops { > + int (*get_device)(const struct ti_sci_handle *handle, u32 id); > + int (*idle_device)(const struct ti_sci_handle *handle, u32 id); > + int (*put_device)(const struct ti_sci_handle *handle, u32 id); > + int (*is_valid)(const struct ti_sci_handle *handle, u32 id); > + int (*get_context_loss_count)(const struct ti_sci_handle *handle, > + u32 id, u32 *count); > + int (*is_idle)(const struct ti_sci_handle *handle, u32 id, > + bool *requested_state); > + int (*is_stop)(const struct ti_sci_handle *handle, u32 id, > + bool *req_state, bool *current_state); > + int (*is_on)(const struct ti_sci_handle *handle, u32 id, > + bool *req_state, bool *current_state); > + int (*is_transitioning)(const struct ti_sci_handle *handle, u32 id, > + bool *current_state); > + int (*set_device_resets)(const struct ti_sci_handle *handle, u32 id, > + u32 reset_state); > + int (*get_device_resets)(const struct ti_sci_handle *handle, u32 id, > + u32 *reset_state); > +}; > + > +/** > + * struct ti_sci_ops - Function support for TI SCI > + * @dev_ops: Device specific operations > + */ > +struct ti_sci_ops { > + struct ti_sci_dev_ops dev_ops; > +}; > + > /** > * struct ti_sci_handle - Handle returned to TI SCI clients for usage. > * @version: structure containing version information > + * @ops: operations that are made available to TI SCI clients > */ > struct ti_sci_handle { > struct ti_sci_version_info version; > + struct ti_sci_ops ops; > }; > > #if IS_ENABLED(CONFIG_TI_SCI_PROTOCOL) > -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Sun, Aug 21, 2016 at 10:56 PM, Lokesh Vutla <lokeshvutla@ti.com> wrote: >> /** >> + * tis_sci_is_response_ack() - Generic ACK/NACK message checkup >> + * @r: pointer to response buffer >> + * >> + * Return: true if the response was an ACK, else returns false. >> + */ >> +static inline bool tis_sci_is_response_ack(void *r) > > May be just ti_sci_is_response_ack() to be consistent? or you wanted to > keep it tis_sci* ? Uggh.. Fat fingered that one.. thanks for catching.. fixed and will post a v2 next week if there is no further comments --- Regards, Nishanth Menon -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Nishant, On 8/23/2016 11:45 AM, Nishanth Menon wrote: > On Sun, Aug 21, 2016 at 10:56 PM, Lokesh Vutla <lokeshvutla@ti.com> wrote: >>> /** >>> + * tis_sci_is_response_ack() - Generic ACK/NACK message checkup >>> + * @r: pointer to response buffer >>> + * >>> + * Return: true if the response was an ACK, else returns false. >>> + */ >>> +static inline bool tis_sci_is_response_ack(void *r) >> >> May be just ti_sci_is_response_ack() to be consistent? or you wanted to >> keep it tis_sci* ? > > > Uggh.. Fat fingered that one.. thanks for catching.. fixed and will > post a v2 next week if there is no further comments > I would like to send the next merge window queue up so please repost the reviewed patches which needs to be queued up. Regards, Santosh -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 4580c29dcb52..e0e286e76095 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -496,6 +496,437 @@ fail: } /** + * tis_sci_is_response_ack() - Generic ACK/NACK message checkup + * @r: pointer to response buffer + * + * Return: true if the response was an ACK, else returns false. + */ +static inline bool tis_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_set_device_state() - Set device state helper + * @handle: pointer to TI SCI handle + * @id: Device identifier + * @flags: flags to setup for the device + * @state: State to move the device to + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_set_device_state(const struct ti_sci_handle *handle, + u32 id, u32 flags, u8 state) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_set_device_state *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_SET_DEVICE_STATE, + flags | 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_set_device_state *)xfer->xfer_buf; + req->id = id; + req->state = state; + + 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; + + ret = tis_sci_is_response_ack(resp) ? 0 : -ENODEV; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_get_device_state() - Get device state helper + * @handle: Handle to the device + * @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 went fine, else return appropriate error. + */ +static int ti_sci_get_device_state(const struct ti_sci_handle *handle, + u32 id, u32 *clcnt, u32 *resets, + u8 *p_state, u8 *c_state) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_get_device_state *req; + struct ti_sci_msg_resp_get_device_state *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + if (!clcnt && !resets && !p_state && !c_state) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + /* Response is expected, so need of any flags */ + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_DEVICE_STATE, + 0, 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_get_device_state *)xfer->xfer_buf; + req->id = id; + + 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_resp_get_device_state *)xfer->xfer_buf; + if (!tis_sci_is_response_ack(resp)) { + ret = -ENODEV; + goto fail; + } + + 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; +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_get_device() - command to request for device managed by TISCI + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * @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 went fine, else return appropriate error. + */ +static int ti_sci_cmd_get_device(const struct ti_sci_handle *handle, u32 id) +{ + return ti_sci_set_device_state(handle, id, + MSG_FLAG_DEVICE_EXCLUSIVE, + MSG_DEVICE_SW_STATE_ON); +} + +/** + * ti_sci_cmd_idle_device() - Command to idle a device managed by TISCI + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * @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 went fine, else return appropriate error. + */ +static int ti_sci_cmd_idle_device(const struct ti_sci_handle *handle, u32 id) +{ + return ti_sci_set_device_state(handle, id, + MSG_FLAG_DEVICE_EXCLUSIVE, + MSG_DEVICE_SW_STATE_RETENTION); +} + +/** + * ti_sci_cmd_put_device() - command to release a device managed by TISCI + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * @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 went fine, else return appropriate error. + */ +static int ti_sci_cmd_put_device(const struct ti_sci_handle *handle, u32 id) +{ + return ti_sci_set_device_state(handle, id, + 0, MSG_DEVICE_SW_STATE_AUTO_OFF); +} + +/** + * ti_sci_cmd_dev_is_valid() - Is the device valid + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * @id: Device Identifier + * + * Return: 0 if all went fine and the device ID is valid, else return + * appropriate error. + */ +static int ti_sci_cmd_dev_is_valid(const struct ti_sci_handle *handle, u32 id) +{ + u8 unused; + + /* check the device state which will also tell us if the ID is valid */ + return ti_sci_get_device_state(handle, id, NULL, NULL, NULL, &unused); +} + +/** + * ti_sci_cmd_dev_get_clcnt() - Get context loss counter + * @handle: Pointer to TISCI handle + * @id: Device Identifier + * @count: Pointer to Context Loss counter to populate + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_dev_get_clcnt(const struct ti_sci_handle *handle, u32 id, + u32 *count) +{ + return ti_sci_get_device_state(handle, id, count, NULL, NULL, NULL); +} + +/** + * ti_sci_cmd_dev_is_idle() - Check if the device is requested to be idle + * @handle: Pointer to TISCI handle + * @id: Device Identifier + * @r_state: true if requested to be idle + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_dev_is_idle(const struct ti_sci_handle *handle, u32 id, + bool *r_state) +{ + int ret; + u8 state; + + if (!r_state) + return -EINVAL; + + ret = ti_sci_get_device_state(handle, id, NULL, NULL, &state, NULL); + if (ret) + return ret; + + *r_state = (state == MSG_DEVICE_SW_STATE_RETENTION); + + return 0; +} + +/** + * ti_sci_cmd_dev_is_stop() - Check if the device is requested to be stopped + * @handle: Pointer to TISCI handle + * @id: Device Identifier + * @r_state: true if requested to be stopped + * @curr_state: true if currently stopped. + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_dev_is_stop(const struct ti_sci_handle *handle, u32 id, + bool *r_state, bool *curr_state) +{ + int ret; + u8 p_state, c_state; + + if (!r_state && !curr_state) + return -EINVAL; + + ret = + ti_sci_get_device_state(handle, 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_cmd_dev_is_on() - Check if the device is requested to be ON + * @handle: Pointer to TISCI handle + * @id: Device Identifier + * @r_state: true if requested to be ON + * @curr_state: true if currently ON and active + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_dev_is_on(const struct ti_sci_handle *handle, u32 id, + bool *r_state, bool *curr_state) +{ + int ret; + u8 p_state, c_state; + + if (!r_state && !curr_state) + return -EINVAL; + + ret = + ti_sci_get_device_state(handle, 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_cmd_dev_is_trans() - Check if the device is currently transitioning + * @handle: Pointer to TISCI handle + * @id: Device Identifier + * @curr_state: true if currently transitioning. + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_dev_is_trans(const struct ti_sci_handle *handle, u32 id, + bool *curr_state) +{ + int ret; + u8 state; + + if (!curr_state) + return -EINVAL; + + ret = ti_sci_get_device_state(handle, id, NULL, NULL, NULL, &state); + if (ret) + return ret; + + *curr_state = (state == MSG_DEVICE_HW_STATE_TRANS); + + return 0; +} + +/** + * ti_sci_cmd_set_device_resets() - command to set resets for device managed + * by TISCI + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * @id: Device Identifier + * @reset_state: Device specific reset bit field + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_set_device_resets(const struct ti_sci_handle *handle, + u32 id, u32 reset_state) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_set_device_resets *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_SET_DEVICE_RESETS, + 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_set_device_resets *)xfer->xfer_buf; + req->id = id; + req->resets = reset_state; + + 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; + + ret = tis_sci_is_response_ack(resp) ? 0 : -ENODEV; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_get_device_resets() - Get reset state for device managed + * by TISCI + * @handle: Pointer to TISCI handle + * @id: Device Identifier + * @reset_state: Pointer to reset state to populate + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_get_device_resets(const struct ti_sci_handle *handle, + u32 id, u32 *reset_state) +{ + return ti_sci_get_device_state(handle, id, NULL, reset_state, NULL, + NULL); +} + +/* + * ti_sci_setup_ops() - Setup the operations structures + * @info: pointer to TISCI pointer + */ +static void ti_sci_setup_ops(struct ti_sci_info *info) +{ + struct ti_sci_ops *ops = &info->handle.ops; + struct ti_sci_dev_ops *dops = &ops->dev_ops; + + dops->get_device = ti_sci_cmd_get_device; + dops->idle_device = ti_sci_cmd_idle_device; + dops->put_device = ti_sci_cmd_put_device; + + dops->is_valid = ti_sci_cmd_dev_is_valid; + dops->get_context_loss_count = ti_sci_cmd_dev_get_clcnt; + dops->is_idle = ti_sci_cmd_dev_is_idle; + dops->is_stop = ti_sci_cmd_dev_is_stop; + dops->is_on = ti_sci_cmd_dev_is_on; + 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; +} + +/** * ti_sci_get_handle() - Get the TI SCI handle for a device * @dev: Pointer to device for which we want SCI handle * @@ -735,6 +1166,8 @@ static int ti_sci_probe(struct platform_device *pdev) goto out; } + ti_sci_setup_ops(info); + 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.firmware_revision, diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index e9dc53f26e0e..29ce0532a7ca 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h @@ -47,6 +47,11 @@ #define TI_SCI_MSG_WAKE_REASON 0x0003 #define TI_SCI_MSG_GOODBYE 0x0004 +/* Device requests */ +#define TI_SCI_MSG_SET_DEVICE_STATE 0x0200 +#define TI_SCI_MSG_GET_DEVICE_STATE 0x0201 +#define TI_SCI_MSG_SET_DEVICE_RESETS 0x0202 + /** * struct ti_sci_msg_hdr - Generic Message Header for All messages and responses * @type: Type of messages: One of TI_SCI_MSG* values @@ -90,4 +95,97 @@ struct ti_sci_msg_resp_version { u8 abi_minor; } __packed; +/** + * struct ti_sci_msg_req_set_device_state - Set the desired state of the device + * @hdr: Generic header + * @id: Indicates which device to modify + * @reserved: Reserved space in message, must be 0 for backward compatibility + * @state: The desired state of the device. + * + * Certain flags can also be set to alter the device state: + * + MSG_FLAG_DEVICE_WAKE_ENABLED - Configure the device to be a wake source. + * The meaning of this flag will vary slightly from device to device and from + * SoC to SoC but it generally allows the device to wake the SoC out of deep + * suspend states. + * + MSG_FLAG_DEVICE_RESET_ISO - Enable reset isolation for this device. + * + MSG_FLAG_DEVICE_EXCLUSIVE - Claim this device exclusively. When passed + * with STATE_RETENTION or STATE_ON, it will claim the device exclusively. + * If another host already has this device set to STATE_RETENTION or STATE_ON, + * the message will fail. Once successful, other hosts attempting to set + * STATE_RETENTION or STATE_ON will fail. + * + * Request type is TI_SCI_MSG_SET_DEVICE_STATE, responded with a generic + * ACK/NACK message. + */ +struct ti_sci_msg_req_set_device_state { + /* Additional hdr->flags options */ +#define MSG_FLAG_DEVICE_WAKE_ENABLED TI_SCI_MSG_FLAG(8) +#define MSG_FLAG_DEVICE_RESET_ISO TI_SCI_MSG_FLAG(9) +#define MSG_FLAG_DEVICE_EXCLUSIVE TI_SCI_MSG_FLAG(10) + struct ti_sci_msg_hdr hdr; + u32 id; + u32 reserved; + +#define MSG_DEVICE_SW_STATE_AUTO_OFF 0 +#define MSG_DEVICE_SW_STATE_RETENTION 1 +#define MSG_DEVICE_SW_STATE_ON 2 + u8 state; +} __packed; + +/** + * struct ti_sci_msg_req_get_device_state - Request to get device. + * @hdr: Generic header + * @id: Device Identifier + * + * Request type is TI_SCI_MSG_GET_DEVICE_STATE, responded device state + * information + */ +struct ti_sci_msg_req_get_device_state { + struct ti_sci_msg_hdr hdr; + u32 id; +} __packed; + +/** + * struct ti_sci_msg_resp_get_device_state - Response to get device request. + * @hdr: Generic header + * @context_loss_count: Indicates how many times the device has lost context. A + * driver can use this monotonic counter to determine if the device has + * lost context since the last time this message was exchanged. + * @resets: Programmed state of the reset lines. + * @programmed_state: The state as programmed by set_device. + * - Uses the MSG_DEVICE_SW_* macros + * @current_state: The actual state of the hardware. + * + * Response to request TI_SCI_MSG_GET_DEVICE_STATE. + */ +struct ti_sci_msg_resp_get_device_state { + struct ti_sci_msg_hdr hdr; + u32 context_loss_count; + u32 resets; + u8 programmed_state; +#define MSG_DEVICE_HW_STATE_OFF 0 +#define MSG_DEVICE_HW_STATE_ON 1 +#define MSG_DEVICE_HW_STATE_TRANS 2 + u8 current_state; +} __packed; + +/** + * struct ti_sci_msg_req_set_device_resets - Set the desired resets + * configuration of the device + * @hdr: Generic header + * @id: Indicates which device to modify + * @resets: A bit field of resets for the device. The meaning, behavior, + * and usage of the reset flags are device specific. 0 for a bit + * indicates releasing the reset represented by that bit while 1 + * indicates keeping it held. + * + * Request type is TI_SCI_MSG_SET_DEVICE_RESETS, responded with a generic + * ACK/NACK message. + */ +struct ti_sci_msg_req_set_device_resets { + struct ti_sci_msg_hdr hdr; + u32 id; + u32 resets; +} __packed; + #endif /* __TI_SCI_H */ diff --git a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/ti_sci_protocol.h index e73483fd5327..87fa73851471 100644 --- a/include/linux/soc/ti/ti_sci_protocol.h +++ b/include/linux/soc/ti/ti_sci_protocol.h @@ -33,12 +33,103 @@ struct ti_sci_version_info { char firmware_description[32]; }; +struct ti_sci_handle; + +/** + * struct ti_sci_dev_ops - Device control operations + * @get_device: Command to request for device managed by TISCI + * Returns 0 for successful exclusive request, else returns + * corresponding error message. + * @idle_device: Command to idle a device managed by TISCI + * Returns 0 for successful exclusive request, else returns + * corresponding error message. + * @put_device: Command to release a device managed by TISCI + * Returns 0 for successful release, else returns corresponding + * error message. + * @is_valid: Check if the device ID is a valid ID. + * Returns 0 if the ID is valid, else returns corresponding error. + * @get_context_loss_count: Command to retrieve context loss counter - this + * increments every time the device looses context. Overflow + * is possible. + * - count: pointer to u32 which will retrieve counter + * Returns 0 for successful information request and count has + * proper data, else returns corresponding error message. + * @is_idle: Reports back about device idle state + * - req_state: Returns requested idle state + * Returns 0 for successful information request and req_state and + * current_state has proper data, else returns corresponding error + * message. + * @is_stop: Reports back about device stop state + * - req_state: Returns requested stop state + * - current_state: Returns current stop state + * Returns 0 for successful information request and req_state and + * current_state has proper data, else returns corresponding error + * message. + * @is_on: Reports back about device ON(or active) state + * - req_state: Returns requested ON state + * - current_state: Returns current ON state + * Returns 0 for successful information request and req_state and + * current_state has proper data, else returns corresponding error + * message. + * @is_transitioning: Reports back if the device is in the middle of transition + * of state. + * -current_state: Returns 'true' if currently transitioning. + * @set_device_resets: Command to configure resets for device managed by TISCI. + * -reset_state: Device specific reset bit field + * Returns 0 for successful request, else returns + * corresponding error message. + * @get_device_resets: Command to read state of resets for device managed + * by TISCI. + * -reset_state: pointer to u32 which will retrieve resets + * Returns 0 for successful request, else returns + * corresponding error message. + * + * NOTE: for all these functions, the following parameters are generic in + * nature: + * -handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * -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. + */ +struct ti_sci_dev_ops { + int (*get_device)(const struct ti_sci_handle *handle, u32 id); + int (*idle_device)(const struct ti_sci_handle *handle, u32 id); + int (*put_device)(const struct ti_sci_handle *handle, u32 id); + int (*is_valid)(const struct ti_sci_handle *handle, u32 id); + int (*get_context_loss_count)(const struct ti_sci_handle *handle, + u32 id, u32 *count); + int (*is_idle)(const struct ti_sci_handle *handle, u32 id, + bool *requested_state); + int (*is_stop)(const struct ti_sci_handle *handle, u32 id, + bool *req_state, bool *current_state); + int (*is_on)(const struct ti_sci_handle *handle, u32 id, + bool *req_state, bool *current_state); + int (*is_transitioning)(const struct ti_sci_handle *handle, u32 id, + bool *current_state); + int (*set_device_resets)(const struct ti_sci_handle *handle, u32 id, + u32 reset_state); + int (*get_device_resets)(const struct ti_sci_handle *handle, u32 id, + u32 *reset_state); +}; + +/** + * struct ti_sci_ops - Function support for TI SCI + * @dev_ops: Device specific operations + */ +struct ti_sci_ops { + struct ti_sci_dev_ops dev_ops; +}; + /** * struct ti_sci_handle - Handle returned to TI SCI clients for usage. * @version: structure containing version information + * @ops: operations that are made available to TI SCI clients */ struct ti_sci_handle { struct ti_sci_version_info version; + struct ti_sci_ops ops; }; #if IS_ENABLED(CONFIG_TI_SCI_PROTOCOL)