diff mbox

[3/5] firmware: ti_sci: Add support for Device control

Message ID 20160819225159.10758-4-nm@ti.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Nishanth Menon Aug. 19, 2016, 10:51 p.m. UTC
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(+)

Comments

Lokesh Vutla Aug. 22, 2016, 3:56 a.m. UTC | #1
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
Nishanth Menon Aug. 23, 2016, 6:45 p.m. UTC | #2
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
Santosh Shilimkar Aug. 29, 2016, 10:30 p.m. UTC | #3
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 mbox

Patch

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)