mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-28 16:52:18 +00:00
TI SoC driver updates for v6.13
- knav_qmss_queue: Cleanups around request_irq params and redundant code. - ti_sci: Power management ops in preperation for suspend/resume capability. Also includes dependency patch to export dev_pm_qos_read_value (acked by Rafael). -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE+KKGk1TrgjIXoxo03bWEnRc2JJ0FAmcrXIEACgkQ3bWEnRc2 JJ0ZRhAAiJKWaG8TS3E9Bpy1HtgMvtn5mXC+72EFCqFWn7oUmuAmL5ivO7XDKbcO scAtdzkupgazD6h4lLwu7VQYEGRt/1+mTaQ1MfgnHlQiShLeJQ8tbkmv49MXGiH0 OKNMlKYfxVvTmyQYVYStM1WoH54ab3vn6iMZT1uiDAAkHniGE+uBgX92+Y+AjV9p 26rBct9aOHzfoEx339/mr3yElf6y74kuie2rpskJfCqT8dRqIw1glu6mFI8T2Bwp BFjjSny7rAg37Q9gzhhg623TznXhNxFEpDKE/thsgc9LU6OiMSTuONjXvCuPhANe OvAt8FTg691Op5Dkj+3e3AUp7cQ46BTQZdpLS7aEjjiT810zqsp0U+BL2ozyPgs8 9BHNRDlsctj+92emzi8XujivmpariYaeTvFY4h2MvaIUJnubaoxN90568fS2orgb U/DykVczyau3VIUFft7DJ7VlPYz3pfbvutfEhKmRpF51HOlqSZyZXHOJByrIzMpt MFQCbjHWAJlvQfIemv7ybAMpKFyCjWlFxsKnMFJU1V6bjYei89IYTIGqegH6Yy4d hOLZJCM388T4RupGk3+Mbh3IlmZq5H33Pich1c1FC/EB2v0ni5qZunEIEaYXWMES ddLAo+2eeVCi1HSiMYWzX+DFCR1d4WU3TDJPU+eemgE/1UcJuDY= =xIlb -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEiK/NIGsWEZVxh/FrYKtH/8kJUicFAmczbbYACgkQYKtH/8kJ UicSehAAwcjh2YgHkAzfSlXBzfCs3rai0YprsqrKspw4cA6VR2s3i7z47x5mX+DS 7czKBAoR2pmWdbnQQqvp07DTR9h3VpG3PfVeXJXQf4b+ylzXU8qYycjcX7mIsh59 fwNc0z3FDtCawmM3x/tZBSizr2I5Z7kfdDJcqBIyJVaLsPdknmB4pKXGFXoT7oK4 aCDgNnTyCD4nWfK3WGC9Sn/uWUOYuoWnIBEwbLu7wrGcG0i2gKGlTc1AD8N8sR7O z4jfKcFm8CZF/KsmkV+dytctDP4U3iGG/OPvouTIWgCui3htQHr0dcZnZLAXuwJa EfEfis41M82osS2RjSudBRX+sYVrTjDNr1BME1ns/dZoyBBKWWOI4tc6Q+Q7MeQL VSPk/4nSKE9XqC8XnPvp1op26h4FfZlmvlzyWHqHTT+e4bPwm1b36LQNQFXBcpvp pETbYBSrAfjPrPGOyQd0H+ttef1Y8nN+SIe4QlMYUtLoJLwPMo3gAqC8C7PpFDmc jymtSxhN9BI9FfeFANvS0H/m7tL/dozazxRj1YlM7ZfKWJRzUp+bgmTajBRvPqyF 3HkFFuxdke8QuenF8kevSHEphXQ2g1Wc6m6sww2fyTCqhrf9KPgfpCBm7QyUuv1o nE5sbmy0WK82NGjyRJbiOKk8fWYJ5KWuSrsVPyRDUmjNHlpaI0o= =Y17E -----END PGP SIGNATURE----- Merge tag 'ti-driver-soc-for-v6.13' of https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux into soc/drivers TI SoC driver updates for v6.13 - knav_qmss_queue: Cleanups around request_irq params and redundant code. - ti_sci: Power management ops in preperation for suspend/resume capability. Also includes dependency patch to export dev_pm_qos_read_value (acked by Rafael). * tag 'ti-driver-soc-for-v6.13' of https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux: firmware: ti_sci: Remove use of of_match_ptr() helper firmware: ti_sci: add CPU latency constraint management firmware: ti_sci: Introduce Power Management Ops firmware: ti_sci: Add system suspend and resume call firmware: ti_sci: Add support for querying the firmware caps PM: QoS: Export dev_pm_qos_read_value soc: ti: knav_qmss_queue: Drop redundant continue statement soc: ti: knav_qmss_queue: Use IRQF_NO_AUTOEN flag in request_irq() Link: https://lore.kernel.org/r/20241106121708.rso5wvc7wbhfi6xk@maverick Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
ffca677936
@ -137,6 +137,7 @@ s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type)
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_qos_read_value);
|
||||
|
||||
/**
|
||||
* apply_constraint - Add/modify/remove device PM QoS request.
|
||||
|
@ -2,13 +2,14 @@
|
||||
/*
|
||||
* Texas Instruments System Control Interface Protocol Driver
|
||||
*
|
||||
* Copyright (C) 2015-2022 Texas Instruments Incorporated - https://www.ti.com/
|
||||
* Copyright (C) 2015-2024 Texas Instruments Incorporated - https://www.ti.com/
|
||||
* Nishanth Menon
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/io.h>
|
||||
@ -19,11 +20,14 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/soc/ti/ti-msgmgr.h>
|
||||
#include <linux/soc/ti/ti_sci_protocol.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/reboot.h>
|
||||
|
||||
#include "ti_sci.h"
|
||||
@ -98,6 +102,7 @@ struct ti_sci_desc {
|
||||
* @minfo: Message info
|
||||
* @node: list head
|
||||
* @host_id: Host ID
|
||||
* @fw_caps: FW/SoC low power capabilities
|
||||
* @users: Number of users of this instance
|
||||
*/
|
||||
struct ti_sci_info {
|
||||
@ -114,6 +119,7 @@ struct ti_sci_info {
|
||||
struct ti_sci_xfers_info minfo;
|
||||
struct list_head node;
|
||||
u8 host_id;
|
||||
u64 fw_caps;
|
||||
/* protected by ti_sci_list_mutex */
|
||||
int users;
|
||||
};
|
||||
@ -1651,6 +1657,364 @@ static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_cmd_prepare_sleep() - Prepare system for system suspend
|
||||
* @handle: pointer to TI SCI handle
|
||||
* @mode: Device identifier
|
||||
* @ctx_lo: Low part of address for context save
|
||||
* @ctx_hi: High part of address for context save
|
||||
* @debug_flags: Debug flags to pass to firmware
|
||||
*
|
||||
* Return: 0 if all went well, else returns appropriate error value.
|
||||
*/
|
||||
static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode,
|
||||
u32 ctx_lo, u32 ctx_hi, u32 debug_flags)
|
||||
{
|
||||
struct ti_sci_info *info;
|
||||
struct ti_sci_msg_req_prepare_sleep *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_PREPARE_SLEEP,
|
||||
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_prepare_sleep *)xfer->xfer_buf;
|
||||
req->mode = mode;
|
||||
req->ctx_lo = ctx_lo;
|
||||
req->ctx_hi = ctx_hi;
|
||||
req->debug_flags = debug_flags;
|
||||
|
||||
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;
|
||||
|
||||
if (!ti_sci_is_response_ack(resp)) {
|
||||
dev_err(dev, "Failed to prepare sleep\n");
|
||||
ret = -ENODEV;
|
||||
}
|
||||
|
||||
fail:
|
||||
ti_sci_put_one_xfer(&info->minfo, xfer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_msg_cmd_query_fw_caps() - Get the FW/SoC capabilities
|
||||
* @handle: Pointer to TI SCI handle
|
||||
* @fw_caps: Each bit in fw_caps indicating one FW/SOC capability
|
||||
*
|
||||
* Check if the firmware supports any optional low power modes.
|
||||
* Old revisions of TIFS (< 08.04) will NACK the request which results in
|
||||
* -ENODEV being returned.
|
||||
*
|
||||
* Return: 0 if all went well, else returns appropriate error value.
|
||||
*/
|
||||
static int ti_sci_msg_cmd_query_fw_caps(const struct ti_sci_handle *handle,
|
||||
u64 *fw_caps)
|
||||
{
|
||||
struct ti_sci_info *info;
|
||||
struct ti_sci_xfer *xfer;
|
||||
struct ti_sci_msg_resp_query_fw_caps *resp;
|
||||
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_QUERY_FW_CAPS,
|
||||
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
|
||||
sizeof(struct ti_sci_msg_hdr),
|
||||
sizeof(*resp));
|
||||
if (IS_ERR(xfer)) {
|
||||
ret = PTR_ERR(xfer);
|
||||
dev_err(dev, "Message alloc failed(%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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_query_fw_caps *)xfer->xfer_buf;
|
||||
|
||||
if (!ti_sci_is_response_ack(resp)) {
|
||||
dev_err(dev, "Failed to get capabilities\n");
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (fw_caps)
|
||||
*fw_caps = resp->fw_caps;
|
||||
|
||||
fail:
|
||||
ti_sci_put_one_xfer(&info->minfo, xfer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_cmd_set_io_isolation() - Enable IO isolation in LPM
|
||||
* @handle: Pointer to TI SCI handle
|
||||
* @state: The desired state of the IO isolation
|
||||
*
|
||||
* Return: 0 if all went well, else returns appropriate error value.
|
||||
*/
|
||||
static int ti_sci_cmd_set_io_isolation(const struct ti_sci_handle *handle,
|
||||
u8 state)
|
||||
{
|
||||
struct ti_sci_info *info;
|
||||
struct ti_sci_msg_req_set_io_isolation *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_IO_ISOLATION,
|
||||
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_io_isolation *)xfer->xfer_buf;
|
||||
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;
|
||||
|
||||
if (!ti_sci_is_response_ack(resp)) {
|
||||
dev_err(dev, "Failed to set IO isolation\n");
|
||||
ret = -ENODEV;
|
||||
}
|
||||
|
||||
fail:
|
||||
ti_sci_put_one_xfer(&info->minfo, xfer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_msg_cmd_lpm_wake_reason() - Get the wakeup source from LPM
|
||||
* @handle: Pointer to TI SCI handle
|
||||
* @source: The wakeup source that woke the SoC from LPM
|
||||
* @timestamp: Timestamp of the wakeup event
|
||||
* @pin: The pin that has triggered wake up
|
||||
* @mode: The last entered low power mode
|
||||
*
|
||||
* Return: 0 if all went well, else returns appropriate error value.
|
||||
*/
|
||||
static int ti_sci_msg_cmd_lpm_wake_reason(const struct ti_sci_handle *handle,
|
||||
u32 *source, u64 *timestamp, u8 *pin, u8 *mode)
|
||||
{
|
||||
struct ti_sci_info *info;
|
||||
struct ti_sci_xfer *xfer;
|
||||
struct ti_sci_msg_resp_lpm_wake_reason *resp;
|
||||
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_LPM_WAKE_REASON,
|
||||
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
|
||||
sizeof(struct ti_sci_msg_hdr),
|
||||
sizeof(*resp));
|
||||
if (IS_ERR(xfer)) {
|
||||
ret = PTR_ERR(xfer);
|
||||
dev_err(dev, "Message alloc failed(%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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_lpm_wake_reason *)xfer->xfer_buf;
|
||||
|
||||
if (!ti_sci_is_response_ack(resp)) {
|
||||
dev_err(dev, "Failed to get wake reason\n");
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (source)
|
||||
*source = resp->wake_source;
|
||||
if (timestamp)
|
||||
*timestamp = resp->wake_timestamp;
|
||||
if (pin)
|
||||
*pin = resp->wake_pin;
|
||||
if (mode)
|
||||
*mode = resp->mode;
|
||||
|
||||
fail:
|
||||
ti_sci_put_one_xfer(&info->minfo, xfer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_cmd_set_device_constraint() - Set LPM constraint on behalf of a device
|
||||
* @handle: pointer to TI SCI handle
|
||||
* @id: Device identifier
|
||||
* @state: The desired state of device constraint: set or clear
|
||||
*
|
||||
* Return: 0 if all went well, else returns appropriate error value.
|
||||
*/
|
||||
static int ti_sci_cmd_set_device_constraint(const struct ti_sci_handle *handle,
|
||||
u32 id, u8 state)
|
||||
{
|
||||
struct ti_sci_info *info;
|
||||
struct ti_sci_msg_req_lpm_set_device_constraint *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_LPM_SET_DEVICE_CONSTRAINT,
|
||||
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_lpm_set_device_constraint *)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;
|
||||
|
||||
if (!ti_sci_is_response_ack(resp)) {
|
||||
dev_err(dev, "Failed to set device constraint\n");
|
||||
ret = -ENODEV;
|
||||
}
|
||||
|
||||
fail:
|
||||
ti_sci_put_one_xfer(&info->minfo, xfer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_cmd_set_latency_constraint() - Set LPM resume latency constraint
|
||||
* @handle: pointer to TI SCI handle
|
||||
* @latency: maximum acceptable latency (in ms) to wake up from LPM
|
||||
* @state: The desired state of latency constraint: set or clear
|
||||
*
|
||||
* Return: 0 if all went well, else returns appropriate error value.
|
||||
*/
|
||||
static int ti_sci_cmd_set_latency_constraint(const struct ti_sci_handle *handle,
|
||||
u16 latency, u8 state)
|
||||
{
|
||||
struct ti_sci_info *info;
|
||||
struct ti_sci_msg_req_lpm_set_latency_constraint *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_LPM_SET_LATENCY_CONSTRAINT,
|
||||
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_lpm_set_latency_constraint *)xfer->xfer_buf;
|
||||
req->latency = latency;
|
||||
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;
|
||||
|
||||
if (!ti_sci_is_response_ack(resp)) {
|
||||
dev_err(dev, "Failed to set device constraint\n");
|
||||
ret = -ENODEV;
|
||||
}
|
||||
|
||||
fail:
|
||||
ti_sci_put_one_xfer(&info->minfo, xfer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ti_sci_cmd_core_reboot(const struct ti_sci_handle *handle)
|
||||
{
|
||||
struct ti_sci_info *info;
|
||||
@ -2793,6 +3157,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
|
||||
struct ti_sci_core_ops *core_ops = &ops->core_ops;
|
||||
struct ti_sci_dev_ops *dops = &ops->dev_ops;
|
||||
struct ti_sci_clk_ops *cops = &ops->clk_ops;
|
||||
struct ti_sci_pm_ops *pmops = &ops->pm_ops;
|
||||
struct ti_sci_rm_core_ops *rm_core_ops = &ops->rm_core_ops;
|
||||
struct ti_sci_rm_irq_ops *iops = &ops->rm_irq_ops;
|
||||
struct ti_sci_rm_ringacc_ops *rops = &ops->rm_ring_ops;
|
||||
@ -2832,6 +3197,13 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
|
||||
cops->set_freq = ti_sci_cmd_clk_set_freq;
|
||||
cops->get_freq = ti_sci_cmd_clk_get_freq;
|
||||
|
||||
if (info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED) {
|
||||
pr_debug("detected DM managed LPM in fw_caps\n");
|
||||
pmops->lpm_wake_reason = ti_sci_msg_cmd_lpm_wake_reason;
|
||||
pmops->set_device_constraint = ti_sci_cmd_set_device_constraint;
|
||||
pmops->set_latency_constraint = ti_sci_cmd_set_latency_constraint;
|
||||
}
|
||||
|
||||
rm_core_ops->get_range = ti_sci_cmd_get_resource_range;
|
||||
rm_core_ops->get_range_from_shost =
|
||||
ti_sci_cmd_get_resource_range_from_shost;
|
||||
@ -3262,6 +3634,111 @@ static int tisci_reboot_handler(struct sys_off_data *data)
|
||||
return NOTIFY_BAD;
|
||||
}
|
||||
|
||||
static int ti_sci_prepare_system_suspend(struct ti_sci_info *info)
|
||||
{
|
||||
/*
|
||||
* Map and validate the target Linux suspend state to TISCI LPM.
|
||||
* Default is to let Device Manager select the low power mode.
|
||||
*/
|
||||
switch (pm_suspend_target_state) {
|
||||
case PM_SUSPEND_MEM:
|
||||
if (info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED) {
|
||||
/*
|
||||
* For the DM_MANAGED mode the context is reserved for
|
||||
* internal use and can be 0
|
||||
*/
|
||||
return ti_sci_cmd_prepare_sleep(&info->handle,
|
||||
TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED,
|
||||
0, 0, 0);
|
||||
} else {
|
||||
/* DM Managed is not supported by the firmware. */
|
||||
dev_err(info->dev, "Suspend to memory is not supported by the firmware\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Do not fail if we don't have action to take for a
|
||||
* specific suspend mode.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int __maybe_unused ti_sci_suspend(struct device *dev)
|
||||
{
|
||||
struct ti_sci_info *info = dev_get_drvdata(dev);
|
||||
struct device *cpu_dev, *cpu_dev_max = NULL;
|
||||
s32 val, cpu_lat = 0;
|
||||
int i, ret;
|
||||
|
||||
if (info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED) {
|
||||
for_each_possible_cpu(i) {
|
||||
cpu_dev = get_cpu_device(i);
|
||||
val = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_RESUME_LATENCY);
|
||||
if (val != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) {
|
||||
cpu_lat = max(cpu_lat, val);
|
||||
cpu_dev_max = cpu_dev;
|
||||
}
|
||||
}
|
||||
if (cpu_dev_max) {
|
||||
dev_dbg(cpu_dev_max, "%s: sending max CPU latency=%u\n", __func__, cpu_lat);
|
||||
ret = ti_sci_cmd_set_latency_constraint(&info->handle,
|
||||
cpu_lat, TISCI_MSG_CONSTRAINT_SET);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ti_sci_prepare_system_suspend(info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused ti_sci_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct ti_sci_info *info = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
ret = ti_sci_cmd_set_io_isolation(&info->handle, TISCI_MSG_VALUE_IO_ENABLE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused ti_sci_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct ti_sci_info *info = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
u32 source;
|
||||
u64 time;
|
||||
u8 pin;
|
||||
u8 mode;
|
||||
|
||||
ret = ti_sci_cmd_set_io_isolation(&info->handle, TISCI_MSG_VALUE_IO_DISABLE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ti_sci_msg_cmd_lpm_wake_reason(&info->handle, &source, &time, &pin, &mode);
|
||||
/* Do not fail to resume on error as the wake reason is not critical */
|
||||
if (!ret)
|
||||
dev_info(dev, "ti_sci: wakeup source:0x%x, pin:0x%x, mode:0x%x\n",
|
||||
source, pin, mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops ti_sci_pm_ops = {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.suspend = ti_sci_suspend,
|
||||
.suspend_noirq = ti_sci_suspend_noirq,
|
||||
.resume_noirq = ti_sci_resume_noirq,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Description for K2G */
|
||||
static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = {
|
||||
.default_host_id = 2,
|
||||
@ -3390,6 +3867,13 @@ static int ti_sci_probe(struct platform_device *pdev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ti_sci_msg_cmd_query_fw_caps(&info->handle, &info->fw_caps);
|
||||
dev_dbg(dev, "Detected firmware capabilities: %s%s%s\n",
|
||||
info->fw_caps & MSG_FLAG_CAPS_GENERIC ? "Generic" : "",
|
||||
info->fw_caps & MSG_FLAG_CAPS_LPM_PARTIAL_IO ? " Partial-IO" : "",
|
||||
info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED ? " DM-Managed" : ""
|
||||
);
|
||||
|
||||
ti_sci_setup_ops(info);
|
||||
|
||||
ret = devm_register_restart_handler(dev, tisci_reboot_handler, info);
|
||||
@ -3421,8 +3905,9 @@ static struct platform_driver ti_sci_driver = {
|
||||
.probe = ti_sci_probe,
|
||||
.driver = {
|
||||
.name = "ti-sci",
|
||||
.of_match_table = of_match_ptr(ti_sci_of_match),
|
||||
.of_match_table = ti_sci_of_match,
|
||||
.suppress_bind_attrs = true,
|
||||
.pm = &ti_sci_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(ti_sci_driver);
|
||||
|
@ -6,7 +6,7 @@
|
||||
* The system works in a message response protocol
|
||||
* See: https://software-dl.ti.com/tisci/esd/latest/index.html for details
|
||||
*
|
||||
* Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/
|
||||
* Copyright (C) 2015-2024 Texas Instruments Incorporated - https://www.ti.com/
|
||||
*/
|
||||
|
||||
#ifndef __TI_SCI_H
|
||||
@ -19,6 +19,7 @@
|
||||
#define TI_SCI_MSG_WAKE_REASON 0x0003
|
||||
#define TI_SCI_MSG_GOODBYE 0x0004
|
||||
#define TI_SCI_MSG_SYS_RESET 0x0005
|
||||
#define TI_SCI_MSG_QUERY_FW_CAPS 0x0022
|
||||
|
||||
/* Device requests */
|
||||
#define TI_SCI_MSG_SET_DEVICE_STATE 0x0200
|
||||
@ -35,6 +36,13 @@
|
||||
#define TI_SCI_MSG_QUERY_CLOCK_FREQ 0x010d
|
||||
#define TI_SCI_MSG_GET_CLOCK_FREQ 0x010e
|
||||
|
||||
/* Low Power Mode Requests */
|
||||
#define TI_SCI_MSG_PREPARE_SLEEP 0x0300
|
||||
#define TI_SCI_MSG_LPM_WAKE_REASON 0x0306
|
||||
#define TI_SCI_MSG_SET_IO_ISOLATION 0x0307
|
||||
#define TI_SCI_MSG_LPM_SET_DEVICE_CONSTRAINT 0x0309
|
||||
#define TI_SCI_MSG_LPM_SET_LATENCY_CONSTRAINT 0x030A
|
||||
|
||||
/* Resource Management Requests */
|
||||
#define TI_SCI_MSG_GET_RESOURCE_RANGE 0x1500
|
||||
|
||||
@ -132,6 +140,27 @@ struct ti_sci_msg_req_reboot {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_resp_query_fw_caps - Response for query firmware caps
|
||||
* @hdr: Generic header
|
||||
* @fw_caps: Each bit in fw_caps indicating one FW/SOC capability
|
||||
* MSG_FLAG_CAPS_GENERIC: Generic capability (LPM not supported)
|
||||
* MSG_FLAG_CAPS_LPM_PARTIAL_IO: Partial IO in LPM
|
||||
* MSG_FLAG_CAPS_LPM_DM_MANAGED: LPM can be managed by DM
|
||||
*
|
||||
* Response to a generic message with message type TI_SCI_MSG_QUERY_FW_CAPS
|
||||
* providing currently available SOC/firmware capabilities. SoC that don't
|
||||
* support low power modes return only MSG_FLAG_CAPS_GENERIC capability.
|
||||
*/
|
||||
struct ti_sci_msg_resp_query_fw_caps {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
#define MSG_FLAG_CAPS_GENERIC TI_SCI_MSG_FLAG(0)
|
||||
#define MSG_FLAG_CAPS_LPM_PARTIAL_IO TI_SCI_MSG_FLAG(4)
|
||||
#define MSG_FLAG_CAPS_LPM_DM_MANAGED TI_SCI_MSG_FLAG(5)
|
||||
#define MSG_MASK_CAPS_LPM GENMASK_ULL(4, 1)
|
||||
u64 fw_caps;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_req_set_device_state - Set the desired state of the device
|
||||
* @hdr: Generic header
|
||||
@ -545,6 +574,118 @@ struct ti_sci_msg_resp_get_clock_freq {
|
||||
u64 freq_hz;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct tisci_msg_req_prepare_sleep - Request for TISCI_MSG_PREPARE_SLEEP.
|
||||
*
|
||||
* @hdr TISCI header to provide ACK/NAK flags to the host.
|
||||
* @mode Low power mode to enter.
|
||||
* @ctx_lo Low 32-bits of physical pointer to address to use for context save.
|
||||
* @ctx_hi High 32-bits of physical pointer to address to use for context save.
|
||||
* @debug_flags Flags that can be set to halt the sequence during suspend or
|
||||
* resume to allow JTAG connection and debug.
|
||||
*
|
||||
* This message is used as the first step of entering a low power mode. It
|
||||
* allows configurable information, including which state to enter to be
|
||||
* easily shared from the application, as this is a non-secure message and
|
||||
* therefore can be sent by anyone.
|
||||
*/
|
||||
struct ti_sci_msg_req_prepare_sleep {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
|
||||
#define TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED 0xfd
|
||||
u8 mode;
|
||||
u32 ctx_lo;
|
||||
u32 ctx_hi;
|
||||
u32 debug_flags;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct tisci_msg_set_io_isolation_req - Request for TI_SCI_MSG_SET_IO_ISOLATION.
|
||||
*
|
||||
* @hdr: Generic header
|
||||
* @state: The deseared state of the IO isolation.
|
||||
*
|
||||
* This message is used to enable/disable IO isolation for low power modes.
|
||||
* Response is generic ACK / NACK message.
|
||||
*/
|
||||
struct ti_sci_msg_req_set_io_isolation {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
u8 state;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_resp_lpm_wake_reason - Response for TI_SCI_MSG_LPM_WAKE_REASON.
|
||||
*
|
||||
* @hdr: Generic header.
|
||||
* @wake_source: The wake up source that woke soc from LPM.
|
||||
* @wake_timestamp: Timestamp at which soc woke.
|
||||
* @wake_pin: The pin that has triggered wake up.
|
||||
* @mode: The last entered low power mode.
|
||||
* @rsvd: Reserved for future use.
|
||||
*
|
||||
* Response to a generic message with message type TI_SCI_MSG_LPM_WAKE_REASON,
|
||||
* used to query the wake up source, pin and entered low power mode.
|
||||
*/
|
||||
struct ti_sci_msg_resp_lpm_wake_reason {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
u32 wake_source;
|
||||
u64 wake_timestamp;
|
||||
u8 wake_pin;
|
||||
u8 mode;
|
||||
u32 rsvd[2];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_req_lpm_set_device_constraint - Request for
|
||||
* TISCI_MSG_LPM_SET_DEVICE_CONSTRAINT.
|
||||
*
|
||||
* @hdr: TISCI header to provide ACK/NAK flags to the host.
|
||||
* @id: Device ID of device whose constraint has to be modified.
|
||||
* @state: The desired state of device constraint: set or clear.
|
||||
* @rsvd: Reserved for future use.
|
||||
*
|
||||
* This message is used by host to set constraint on the device. This can be
|
||||
* sent anytime after boot before prepare sleep message. Any device can set a
|
||||
* constraint on the low power mode that the SoC can enter. It allows
|
||||
* configurable information to be easily shared from the application, as this
|
||||
* is a non-secure message and therefore can be sent by anyone. By setting a
|
||||
* constraint, the device ensures that it will not be powered off or reset in
|
||||
* the selected mode. Note: Access Restriction: Exclusivity flag of Device will
|
||||
* be honored. If some other host already has constraint on this device ID,
|
||||
* NACK will be returned.
|
||||
*/
|
||||
struct ti_sci_msg_req_lpm_set_device_constraint {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
u32 id;
|
||||
u8 state;
|
||||
u32 rsvd[2];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_req_lpm_set_latency_constraint - Request for
|
||||
* TISCI_MSG_LPM_SET_LATENCY_CONSTRAINT.
|
||||
*
|
||||
* @hdr: TISCI header to provide ACK/NAK flags to the host.
|
||||
* @wkup_latency: The maximum acceptable latency to wake up from low power mode
|
||||
* in milliseconds. The deeper the state, the higher the latency.
|
||||
* @state: The desired state of wakeup latency constraint: set or clear.
|
||||
* @rsvd: Reserved for future use.
|
||||
*
|
||||
* This message is used by host to set wakeup latency from low power mode. This can
|
||||
* be sent anytime after boot before prepare sleep message, and can be sent after
|
||||
* current low power mode is exited. Any device can set a constraint on the low power
|
||||
* mode that the SoC can enter. It allows configurable information to be easily shared
|
||||
* from the application, as this is a non-secure message and therefore can be sent by
|
||||
* anyone. By setting a wakeup latency constraint, the host ensures that the resume time
|
||||
* from selected low power mode will be less than the constraint value.
|
||||
*/
|
||||
struct ti_sci_msg_req_lpm_set_latency_constraint {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
u16 latency;
|
||||
u8 state;
|
||||
u32 rsvd;
|
||||
} __packed;
|
||||
|
||||
#define TI_SCI_IRQ_SECONDARY_HOST_INVALID 0xff
|
||||
|
||||
/**
|
||||
|
@ -119,11 +119,10 @@ static int knav_queue_setup_irq(struct knav_range_info *range,
|
||||
|
||||
if (range->flags & RANGE_HAS_IRQ) {
|
||||
irq = range->irqs[queue].irq;
|
||||
ret = request_irq(irq, knav_queue_int_handler, 0,
|
||||
inst->irq_name, inst);
|
||||
ret = request_irq(irq, knav_queue_int_handler, IRQF_NO_AUTOEN,
|
||||
inst->irq_name, inst);
|
||||
if (ret)
|
||||
return ret;
|
||||
disable_irq(irq);
|
||||
if (range->irqs[queue].cpu_mask) {
|
||||
ret = irq_set_affinity_hint(irq, range->irqs[queue].cpu_mask);
|
||||
if (ret) {
|
||||
@ -723,7 +722,6 @@ static void kdesc_empty_pool(struct knav_pool *pool)
|
||||
if (!desc) {
|
||||
dev_dbg(pool->kdev->dev,
|
||||
"couldn't unmap desc, continuing\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
WARN_ON(i != pool->num_desc);
|
||||
|
@ -195,6 +195,35 @@ struct ti_sci_clk_ops {
|
||||
u64 *current_freq);
|
||||
};
|
||||
|
||||
/* TISCI LPM IO isolation control values */
|
||||
#define TISCI_MSG_VALUE_IO_ENABLE 1
|
||||
#define TISCI_MSG_VALUE_IO_DISABLE 0
|
||||
|
||||
/* TISCI LPM constraint state values */
|
||||
#define TISCI_MSG_CONSTRAINT_SET 1
|
||||
#define TISCI_MSG_CONSTRAINT_CLR 0
|
||||
|
||||
/**
|
||||
* struct ti_sci_pm_ops - Low Power Mode (LPM) control operations
|
||||
* @lpm_wake_reason: Get the wake up source that woke the SoC from LPM
|
||||
* - source: The wake up source that woke soc from LPM.
|
||||
* - timestamp: Timestamp at which soc woke.
|
||||
* @set_device_constraint: Set LPM constraint on behalf of a device
|
||||
* - id: Device Identifier
|
||||
* - state: The desired state of device constraint: set or clear.
|
||||
* @set_latency_constraint: Set LPM resume latency constraint
|
||||
* - latency: maximum acceptable latency to wake up from low power mode
|
||||
* - state: The desired state of latency constraint: set or clear.
|
||||
*/
|
||||
struct ti_sci_pm_ops {
|
||||
int (*lpm_wake_reason)(const struct ti_sci_handle *handle,
|
||||
u32 *source, u64 *timestamp, u8 *pin, u8 *mode);
|
||||
int (*set_device_constraint)(const struct ti_sci_handle *handle,
|
||||
u32 id, u8 state);
|
||||
int (*set_latency_constraint)(const struct ti_sci_handle *handle,
|
||||
u16 latency, u8 state);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ti_sci_resource_desc - Description of TI SCI resource instance range.
|
||||
* @start: Start index of the first resource range.
|
||||
@ -539,6 +568,7 @@ struct ti_sci_ops {
|
||||
struct ti_sci_core_ops core_ops;
|
||||
struct ti_sci_dev_ops dev_ops;
|
||||
struct ti_sci_clk_ops clk_ops;
|
||||
struct ti_sci_pm_ops pm_ops;
|
||||
struct ti_sci_rm_core_ops rm_core_ops;
|
||||
struct ti_sci_rm_irq_ops rm_irq_ops;
|
||||
struct ti_sci_rm_ringacc_ops rm_ring_ops;
|
||||
|
Loading…
Reference in New Issue
Block a user