mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 21:54:01 +00:00
firmware: ti_sci: Add processor shutdown API method
Add and expose a new processor shutdown API that wraps the two TISCI messages involved in initiating a core shutdown. The API will first queue a message to have the DMSC wait for a certain processor boot status to happen followed by a message to trigger the actual shutdown- with both messages being sent without waiting or requesting for a response. Note that the processor shutdown API call will need to be followed up by user software placing the respective core into either WFE or WFI mode. Signed-off-by: Andreas Dannenberg <dannenberg@ti.com>
This commit is contained in:
parent
ae0b8a2bc8
commit
410adcc9e2
3 changed files with 241 additions and 4 deletions
|
@ -101,7 +101,8 @@ struct ti_sci_info {
|
|||
* @msg_flags: Flag to set for the message
|
||||
* @buf: Buffer to be send to mailbox channel
|
||||
* @tx_message_size: transmit message size
|
||||
* @rx_message_size: receive message size
|
||||
* @rx_message_size: receive message size. may be set to zero for send-only
|
||||
* transactions.
|
||||
*
|
||||
* Helper function which is used by various command functions that are
|
||||
* exposed to clients of this driver for allocating a message traffic event.
|
||||
|
@ -121,7 +122,8 @@ static struct ti_sci_xfer *ti_sci_setup_one_xfer(struct ti_sci_info *info,
|
|||
/* Ensure we have sane transfer sizes */
|
||||
if (rx_message_size > info->desc->max_msg_size ||
|
||||
tx_message_size > info->desc->max_msg_size ||
|
||||
rx_message_size < sizeof(*hdr) || tx_message_size < sizeof(*hdr))
|
||||
(rx_message_size > 0 && rx_message_size < sizeof(*hdr)) ||
|
||||
tx_message_size < sizeof(*hdr))
|
||||
return ERR_PTR(-ERANGE);
|
||||
|
||||
info->seq = ~info->seq;
|
||||
|
@ -219,7 +221,9 @@ static inline int ti_sci_do_xfer(struct ti_sci_info *info,
|
|||
|
||||
xfer->tx_message.buf = (u32 *)secure_buf;
|
||||
xfer->tx_message.len += sizeof(secure_hdr);
|
||||
xfer->rx_len += sizeof(secure_hdr);
|
||||
|
||||
if (xfer->rx_len)
|
||||
xfer->rx_len += sizeof(secure_hdr);
|
||||
}
|
||||
|
||||
/* Send the message */
|
||||
|
@ -230,7 +234,11 @@ static inline int ti_sci_do_xfer(struct ti_sci_info *info,
|
|||
return ret;
|
||||
}
|
||||
|
||||
return ti_sci_get_response(info, xfer, &info->chan_rx);
|
||||
/* Get response if requested */
|
||||
if (xfer->rx_len)
|
||||
ret = ti_sci_get_response(info, xfer, &info->chan_rx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -469,6 +477,49 @@ static int ti_sci_set_device_state(const struct ti_sci_handle *handle,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_set_device_state_no_wait() - Set device state helper without
|
||||
* requesting or waiting for a response.
|
||||
* @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_no_wait(const struct ti_sci_handle *handle,
|
||||
u32 id, u32 flags, u8 state)
|
||||
{
|
||||
struct ti_sci_msg_req_set_device_state req;
|
||||
struct ti_sci_info *info;
|
||||
struct ti_sci_xfer *xfer;
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR(handle))
|
||||
return PTR_ERR(handle);
|
||||
if (!handle)
|
||||
return -EINVAL;
|
||||
|
||||
info = handle_to_ti_sci_info(handle);
|
||||
|
||||
xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_SET_DEVICE_STATE,
|
||||
flags | TI_SCI_FLAG_REQ_GENERIC_NORESPONSE,
|
||||
(u32 *)&req, sizeof(req), 0);
|
||||
if (IS_ERR(xfer)) {
|
||||
ret = PTR_ERR(xfer);
|
||||
dev_err(info->dev, "Message alloc failed(%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
req.id = id;
|
||||
req.state = state;
|
||||
|
||||
ret = ti_sci_do_xfer(info, xfer);
|
||||
if (ret)
|
||||
dev_err(info->dev, "Mbox send fail %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_get_device_state() - Get device state helper
|
||||
* @handle: Handle to the device
|
||||
|
@ -2039,6 +2090,137 @@ static int ti_sci_cmd_get_proc_boot_status(const struct ti_sci_handle *handle,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_proc_wait_boot_status_no_wait() - Helper function to wait for a
|
||||
* processor boot status without requesting or
|
||||
* waiting for a response.
|
||||
* @proc_id: Processor ID this request is for
|
||||
* @num_wait_iterations: Total number of iterations we will check before
|
||||
* we will timeout and give up
|
||||
* @num_match_iterations: How many iterations should we have continued
|
||||
* status to account for status bits glitching.
|
||||
* This is to make sure that match occurs for
|
||||
* consecutive checks. This implies that the
|
||||
* worst case should consider that the stable
|
||||
* time should at the worst be num_wait_iterations
|
||||
* num_match_iterations to prevent timeout.
|
||||
* @delay_per_iteration_us: Specifies how long to wait (in micro seconds)
|
||||
* between each status checks. This is the minimum
|
||||
* duration, and overhead of register reads and
|
||||
* checks are on top of this and can vary based on
|
||||
* varied conditions.
|
||||
* @delay_before_iterations_us: Specifies how long to wait (in micro seconds)
|
||||
* before the very first check in the first
|
||||
* iteration of status check loop. This is the
|
||||
* minimum duration, and overhead of register
|
||||
* reads and checks are.
|
||||
* @status_flags_1_set_all_wait:If non-zero, Specifies that all bits of the
|
||||
* status matching this field requested MUST be 1.
|
||||
* @status_flags_1_set_any_wait:If non-zero, Specifies that at least one of the
|
||||
* bits matching this field requested MUST be 1.
|
||||
* @status_flags_1_clr_all_wait:If non-zero, Specifies that all bits of the
|
||||
* status matching this field requested MUST be 0.
|
||||
* @status_flags_1_clr_any_wait:If non-zero, Specifies that at least one of the
|
||||
* bits matching this field requested MUST be 0.
|
||||
*
|
||||
* Return: 0 if all goes well, else appropriate error message
|
||||
*/
|
||||
static int
|
||||
ti_sci_proc_wait_boot_status_no_wait(const struct ti_sci_handle *handle,
|
||||
u8 proc_id,
|
||||
u8 num_wait_iterations,
|
||||
u8 num_match_iterations,
|
||||
u8 delay_per_iteration_us,
|
||||
u8 delay_before_iterations_us,
|
||||
u32 status_flags_1_set_all_wait,
|
||||
u32 status_flags_1_set_any_wait,
|
||||
u32 status_flags_1_clr_all_wait,
|
||||
u32 status_flags_1_clr_any_wait)
|
||||
{
|
||||
struct ti_sci_msg_req_wait_proc_boot_status req;
|
||||
struct ti_sci_info *info;
|
||||
struct ti_sci_xfer *xfer;
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR(handle))
|
||||
return PTR_ERR(handle);
|
||||
if (!handle)
|
||||
return -EINVAL;
|
||||
|
||||
info = handle_to_ti_sci_info(handle);
|
||||
|
||||
xfer = ti_sci_setup_one_xfer(info, TISCI_MSG_WAIT_PROC_BOOT_STATUS,
|
||||
TI_SCI_FLAG_REQ_GENERIC_NORESPONSE,
|
||||
(u32 *)&req, sizeof(req), 0);
|
||||
if (IS_ERR(xfer)) {
|
||||
ret = PTR_ERR(xfer);
|
||||
dev_err(info->dev, "Message alloc failed(%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
req.processor_id = proc_id;
|
||||
req.num_wait_iterations = num_wait_iterations;
|
||||
req.num_match_iterations = num_match_iterations;
|
||||
req.delay_per_iteration_us = delay_per_iteration_us;
|
||||
req.delay_before_iterations_us = delay_before_iterations_us;
|
||||
req.status_flags_1_set_all_wait = status_flags_1_set_all_wait;
|
||||
req.status_flags_1_set_any_wait = status_flags_1_set_any_wait;
|
||||
req.status_flags_1_clr_all_wait = status_flags_1_clr_all_wait;
|
||||
req.status_flags_1_clr_any_wait = status_flags_1_clr_any_wait;
|
||||
|
||||
ret = ti_sci_do_xfer(info, xfer);
|
||||
if (ret)
|
||||
dev_err(info->dev, "Mbox send fail %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_cmd_proc_shutdown_no_wait() - Command to shutdown a core without
|
||||
* requesting or waiting for a response. Note that this API call
|
||||
* should be followed by placing the respective processor into
|
||||
* either WFE or WFI mode.
|
||||
* @handle: Pointer to TI SCI handle
|
||||
* @proc_id: Processor ID this request is for
|
||||
*
|
||||
* Return: 0 if all went well, else returns appropriate error value.
|
||||
*/
|
||||
static int ti_sci_cmd_proc_shutdown_no_wait(const struct ti_sci_handle *handle,
|
||||
u8 proc_id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Send the core boot status wait message waiting for either WFE or
|
||||
* WFI without requesting or waiting for a TISCI response with the
|
||||
* maximum wait time to give us the best chance to get to the WFE/WFI
|
||||
* command that should follow the invocation of this API before the
|
||||
* DMSC-internal processing of this command times out. Note that
|
||||
* waiting for the R5 WFE/WFI flags will also work on an ARMV8 type
|
||||
* core as the related flag bit positions are the same.
|
||||
*/
|
||||
ret = ti_sci_proc_wait_boot_status_no_wait(handle, proc_id,
|
||||
U8_MAX, 100, U8_MAX, U8_MAX,
|
||||
0, PROC_BOOT_STATUS_FLAG_R5_WFE | PROC_BOOT_STATUS_FLAG_R5_WFI,
|
||||
0, 0);
|
||||
if (ret) {
|
||||
dev_err(info->dev, "Sending core %u wait message fail %d\n",
|
||||
proc_id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release a processor managed by TISCI without requesting or waiting
|
||||
* for a response.
|
||||
*/
|
||||
ret = ti_sci_set_device_state_no_wait(handle, proc_id, 0,
|
||||
MSG_DEVICE_SW_STATE_AUTO_OFF);
|
||||
if (ret)
|
||||
dev_err(info->dev, "Sending core %u shutdown message fail %d\n",
|
||||
proc_id, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_cmd_ring_config() - configure RA ring
|
||||
* @handle: pointer to TI SCI handle
|
||||
|
@ -2687,6 +2869,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
|
|||
pops->set_proc_boot_ctrl = ti_sci_cmd_set_proc_boot_ctrl;
|
||||
pops->proc_auth_boot_image = ti_sci_cmd_proc_auth_boot_image;
|
||||
pops->get_proc_boot_status = ti_sci_cmd_get_proc_boot_status;
|
||||
pops->proc_shutdown_no_wait = ti_sci_cmd_proc_shutdown_no_wait;
|
||||
|
||||
rops->config = ti_sci_cmd_ring_config;
|
||||
rops->get_config = ti_sci_cmd_ring_get_config;
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#define TISCI_MSG_SET_PROC_BOOT_CTRL 0xc101
|
||||
#define TISCI_MSG_PROC_AUTH_BOOT_IMIAGE 0xc120
|
||||
#define TISCI_MSG_GET_PROC_BOOT_STATUS 0xc400
|
||||
#define TISCI_MSG_WAIT_PROC_BOOT_STATUS 0xc401
|
||||
|
||||
/* Resource Management Requests */
|
||||
#define TI_SCI_MSG_GET_RESOURCE_RANGE 0x1500
|
||||
|
@ -772,6 +773,55 @@ struct ti_sci_msg_resp_get_proc_boot_status {
|
|||
u32 status_flags;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_req_wait_proc_boot_status - Wait for a processor
|
||||
* boot status
|
||||
* @hdr: Generic Header
|
||||
* @processor_id: ID of processor
|
||||
* @num_wait_iterations: Total number of iterations we will check before
|
||||
* we will timeout and give up
|
||||
* @num_match_iterations: How many iterations should we have continued
|
||||
* status to account for status bits glitching.
|
||||
* This is to make sure that match occurs for
|
||||
* consecutive checks. This implies that the
|
||||
* worst case should consider that the stable
|
||||
* time should at the worst be num_wait_iterations
|
||||
* num_match_iterations to prevent timeout.
|
||||
* @delay_per_iteration_us: Specifies how long to wait (in micro seconds)
|
||||
* between each status checks. This is the minimum
|
||||
* duration, and overhead of register reads and
|
||||
* checks are on top of this and can vary based on
|
||||
* varied conditions.
|
||||
* @delay_before_iterations_us: Specifies how long to wait (in micro seconds)
|
||||
* before the very first check in the first
|
||||
* iteration of status check loop. This is the
|
||||
* minimum duration, and overhead of register
|
||||
* reads and checks are.
|
||||
* @status_flags_1_set_all_wait:If non-zero, Specifies that all bits of the
|
||||
* status matching this field requested MUST be 1.
|
||||
* @status_flags_1_set_any_wait:If non-zero, Specifies that at least one of the
|
||||
* bits matching this field requested MUST be 1.
|
||||
* @status_flags_1_clr_all_wait:If non-zero, Specifies that all bits of the
|
||||
* status matching this field requested MUST be 0.
|
||||
* @status_flags_1_clr_any_wait:If non-zero, Specifies that at least one of the
|
||||
* bits matching this field requested MUST be 0.
|
||||
*
|
||||
* Request type is TISCI_MSG_WAIT_PROC_BOOT_STATUS, response is appropriate
|
||||
* message, or NACK in case of inability to satisfy request.
|
||||
*/
|
||||
struct ti_sci_msg_req_wait_proc_boot_status {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
u8 processor_id;
|
||||
u8 num_wait_iterations;
|
||||
u8 num_match_iterations;
|
||||
u8 delay_per_iteration_us;
|
||||
u8 delay_before_iterations_us;
|
||||
u32 status_flags_1_set_all_wait;
|
||||
u32 status_flags_1_set_any_wait;
|
||||
u32 status_flags_1_clr_all_wait;
|
||||
u32 status_flags_1_clr_any_wait;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_rm_ring_cfg_req - Configure a Navigator Subsystem ring
|
||||
*
|
||||
|
|
|
@ -266,6 +266,8 @@ struct ti_sci_core_ops {
|
|||
* @set_proc_boot_ctrl: Setup limited control flags in specific cases.
|
||||
* @proc_auth_boot_image:
|
||||
* @get_proc_boot_status: Get the state of physical processor
|
||||
* @proc_shutdown_no_wait: Shutdown a core without requesting or waiting for a
|
||||
* response.
|
||||
*
|
||||
* NOTE: for all these functions, the following parameters are generic in
|
||||
* nature:
|
||||
|
@ -287,6 +289,8 @@ struct ti_sci_proc_ops {
|
|||
int (*get_proc_boot_status)(const struct ti_sci_handle *handle, u8 pid,
|
||||
u64 *bv, u32 *cfg_flags, u32 *ctrl_flags,
|
||||
u32 *sts_flags);
|
||||
int (*proc_shutdown_no_wait)(const struct ti_sci_handle *handle,
|
||||
u8 pid);
|
||||
};
|
||||
|
||||
#define TI_SCI_RING_MODE_RING (0)
|
||||
|
|
Loading…
Reference in a new issue