Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull IRQ chip updates from Ingo Molnar: "A late irqchips update: - New TI INTR/INTA set of drivers - Rewrite of the stm32mp1-exti driver as a platform driver - Update the IOMMU MSI mapping API to be RT friendly - A number of cleanups and other low impact fixes" * 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (34 commits) iommu/dma-iommu: Remove iommu_dma_map_msi_msg() irqchip/gic-v3-mbi: Don't map the MSI page in mbi_compose_m{b, s}i_msg() irqchip/ls-scfg-msi: Don't map the MSI page in ls_scfg_msi_compose_msg() irqchip/gic-v3-its: Don't map the MSI page in its_irq_compose_msi_msg() irqchip/gicv2m: Don't map the MSI page in gicv2m_compose_msi_msg() iommu/dma-iommu: Split iommu_dma_map_msi_msg() in two parts genirq/msi: Add a new field in msi_desc to store an IOMMU cookie arm64: arch_k3: Enable interrupt controller drivers irqchip/ti-sci-inta: Add msi domain support soc: ti: Add MSI domain bus support for Interrupt Aggregator irqchip/ti-sci-inta: Add support for Interrupt Aggregator driver dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings irqchip/ti-sci-intr: Add support for Interrupt Router driver dt-bindings: irqchip: Introduce TISCI Interrupt router bindings gpio: thunderx: Use the default parent apis for {request,release}_resources genirq: Introduce irq_chip_{request,release}_resource_parent() apis firmware: ti_sci: Add helper apis to manage resources firmware: ti_sci: Add RM mapping table for am654 firmware: ti_sci: Add support for IRQ management firmware: ti_sci: Add support for RM core ops ...
This commit is contained in:
@@ -64,6 +64,22 @@ struct ti_sci_xfers_info {
|
||||
spinlock_t xfer_lock;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ti_sci_rm_type_map - Structure representing TISCI Resource
|
||||
* management representation of dev_ids.
|
||||
* @dev_id: TISCI device ID
|
||||
* @type: Corresponding id as identified by TISCI RM.
|
||||
*
|
||||
* Note: This is used only as a work around for using RM range apis
|
||||
* for AM654 SoC. For future SoCs dev_id will be used as type
|
||||
* for RM range APIs. In order to maintain ABI backward compatibility
|
||||
* type is not being changed for AM654 SoC.
|
||||
*/
|
||||
struct ti_sci_rm_type_map {
|
||||
u32 dev_id;
|
||||
u16 type;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ti_sci_desc - Description of SoC integration
|
||||
* @default_host_id: Host identifier representing the compute entity
|
||||
@@ -71,12 +87,14 @@ struct ti_sci_xfers_info {
|
||||
* @max_msgs: Maximum number of messages that can be pending
|
||||
* simultaneously in the system
|
||||
* @max_msg_size: Maximum size of data per message that can be handled.
|
||||
* @rm_type_map: RM resource type mapping structure.
|
||||
*/
|
||||
struct ti_sci_desc {
|
||||
u8 default_host_id;
|
||||
int max_rx_timeout_ms;
|
||||
int max_msgs;
|
||||
int max_msg_size;
|
||||
struct ti_sci_rm_type_map *rm_type_map;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1600,6 +1618,392 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ti_sci_get_resource_type(struct ti_sci_info *info, u16 dev_id,
|
||||
u16 *type)
|
||||
{
|
||||
struct ti_sci_rm_type_map *rm_type_map = info->desc->rm_type_map;
|
||||
bool found = false;
|
||||
int i;
|
||||
|
||||
/* If map is not provided then assume dev_id is used as type */
|
||||
if (!rm_type_map) {
|
||||
*type = dev_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; rm_type_map[i].dev_id; i++) {
|
||||
if (rm_type_map[i].dev_id == dev_id) {
|
||||
*type = rm_type_map[i].type;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_get_resource_range - Helper to get a range of resources assigned
|
||||
* to a host. Resource is uniquely identified by
|
||||
* type and subtype.
|
||||
* @handle: Pointer to TISCI handle.
|
||||
* @dev_id: TISCI device ID.
|
||||
* @subtype: Resource assignment subtype that is being requested
|
||||
* from the given device.
|
||||
* @s_host: Host processor ID to which the resources are allocated
|
||||
* @range_start: Start index of the resource range
|
||||
* @range_num: Number of resources in the range
|
||||
*
|
||||
* Return: 0 if all went fine, else return appropriate error.
|
||||
*/
|
||||
static int ti_sci_get_resource_range(const struct ti_sci_handle *handle,
|
||||
u32 dev_id, u8 subtype, u8 s_host,
|
||||
u16 *range_start, u16 *range_num)
|
||||
{
|
||||
struct ti_sci_msg_resp_get_resource_range *resp;
|
||||
struct ti_sci_msg_req_get_resource_range *req;
|
||||
struct ti_sci_xfer *xfer;
|
||||
struct ti_sci_info *info;
|
||||
struct device *dev;
|
||||
u16 type;
|
||||
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_GET_RESOURCE_RANGE,
|
||||
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;
|
||||
}
|
||||
|
||||
ret = ti_sci_get_resource_type(info, dev_id, &type);
|
||||
if (ret) {
|
||||
dev_err(dev, "rm type lookup failed for %u\n", dev_id);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
req = (struct ti_sci_msg_req_get_resource_range *)xfer->xfer_buf;
|
||||
req->secondary_host = s_host;
|
||||
req->type = type & MSG_RM_RESOURCE_TYPE_MASK;
|
||||
req->subtype = subtype & MSG_RM_RESOURCE_SUBTYPE_MASK;
|
||||
|
||||
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_resource_range *)xfer->xfer_buf;
|
||||
|
||||
if (!ti_sci_is_response_ack(resp)) {
|
||||
ret = -ENODEV;
|
||||
} else if (!resp->range_start && !resp->range_num) {
|
||||
ret = -ENODEV;
|
||||
} else {
|
||||
*range_start = resp->range_start;
|
||||
*range_num = resp->range_num;
|
||||
};
|
||||
|
||||
fail:
|
||||
ti_sci_put_one_xfer(&info->minfo, xfer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_cmd_get_resource_range - Get a range of resources assigned to host
|
||||
* that is same as ti sci interface host.
|
||||
* @handle: Pointer to TISCI handle.
|
||||
* @dev_id: TISCI device ID.
|
||||
* @subtype: Resource assignment subtype that is being requested
|
||||
* from the given device.
|
||||
* @range_start: Start index of the resource range
|
||||
* @range_num: Number of resources in the range
|
||||
*
|
||||
* Return: 0 if all went fine, else return appropriate error.
|
||||
*/
|
||||
static int ti_sci_cmd_get_resource_range(const struct ti_sci_handle *handle,
|
||||
u32 dev_id, u8 subtype,
|
||||
u16 *range_start, u16 *range_num)
|
||||
{
|
||||
return ti_sci_get_resource_range(handle, dev_id, subtype,
|
||||
TI_SCI_IRQ_SECONDARY_HOST_INVALID,
|
||||
range_start, range_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_cmd_get_resource_range_from_shost - Get a range of resources
|
||||
* assigned to a specified host.
|
||||
* @handle: Pointer to TISCI handle.
|
||||
* @dev_id: TISCI device ID.
|
||||
* @subtype: Resource assignment subtype that is being requested
|
||||
* from the given device.
|
||||
* @s_host: Host processor ID to which the resources are allocated
|
||||
* @range_start: Start index of the resource range
|
||||
* @range_num: Number of resources in the range
|
||||
*
|
||||
* Return: 0 if all went fine, else return appropriate error.
|
||||
*/
|
||||
static
|
||||
int ti_sci_cmd_get_resource_range_from_shost(const struct ti_sci_handle *handle,
|
||||
u32 dev_id, u8 subtype, u8 s_host,
|
||||
u16 *range_start, u16 *range_num)
|
||||
{
|
||||
return ti_sci_get_resource_range(handle, dev_id, subtype, s_host,
|
||||
range_start, range_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_manage_irq() - Helper api to configure/release the irq route between
|
||||
* the requested source and destination
|
||||
* @handle: Pointer to TISCI handle.
|
||||
* @valid_params: Bit fields defining the validity of certain params
|
||||
* @src_id: Device ID of the IRQ source
|
||||
* @src_index: IRQ source index within the source device
|
||||
* @dst_id: Device ID of the IRQ destination
|
||||
* @dst_host_irq: IRQ number of the destination device
|
||||
* @ia_id: Device ID of the IA, if the IRQ flows through this IA
|
||||
* @vint: Virtual interrupt to be used within the IA
|
||||
* @global_event: Global event number to be used for the requesting event
|
||||
* @vint_status_bit: Virtual interrupt status bit to be used for the event
|
||||
* @s_host: Secondary host ID to which the irq/event is being
|
||||
* requested for.
|
||||
* @type: Request type irq set or release.
|
||||
*
|
||||
* Return: 0 if all went fine, else return appropriate error.
|
||||
*/
|
||||
static int ti_sci_manage_irq(const struct ti_sci_handle *handle,
|
||||
u32 valid_params, u16 src_id, u16 src_index,
|
||||
u16 dst_id, u16 dst_host_irq, u16 ia_id, u16 vint,
|
||||
u16 global_event, u8 vint_status_bit, u8 s_host,
|
||||
u16 type)
|
||||
{
|
||||
struct ti_sci_msg_req_manage_irq *req;
|
||||
struct ti_sci_msg_hdr *resp;
|
||||
struct ti_sci_xfer *xfer;
|
||||
struct ti_sci_info *info;
|
||||
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, type, 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_manage_irq *)xfer->xfer_buf;
|
||||
req->valid_params = valid_params;
|
||||
req->src_id = src_id;
|
||||
req->src_index = src_index;
|
||||
req->dst_id = dst_id;
|
||||
req->dst_host_irq = dst_host_irq;
|
||||
req->ia_id = ia_id;
|
||||
req->vint = vint;
|
||||
req->global_event = global_event;
|
||||
req->vint_status_bit = vint_status_bit;
|
||||
req->secondary_host = s_host;
|
||||
|
||||
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 = ti_sci_is_response_ack(resp) ? 0 : -ENODEV;
|
||||
|
||||
fail:
|
||||
ti_sci_put_one_xfer(&info->minfo, xfer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_set_irq() - Helper api to configure the irq route between the
|
||||
* requested source and destination
|
||||
* @handle: Pointer to TISCI handle.
|
||||
* @valid_params: Bit fields defining the validity of certain params
|
||||
* @src_id: Device ID of the IRQ source
|
||||
* @src_index: IRQ source index within the source device
|
||||
* @dst_id: Device ID of the IRQ destination
|
||||
* @dst_host_irq: IRQ number of the destination device
|
||||
* @ia_id: Device ID of the IA, if the IRQ flows through this IA
|
||||
* @vint: Virtual interrupt to be used within the IA
|
||||
* @global_event: Global event number to be used for the requesting event
|
||||
* @vint_status_bit: Virtual interrupt status bit to be used for the event
|
||||
* @s_host: Secondary host ID to which the irq/event is being
|
||||
* requested for.
|
||||
*
|
||||
* Return: 0 if all went fine, else return appropriate error.
|
||||
*/
|
||||
static int ti_sci_set_irq(const struct ti_sci_handle *handle, u32 valid_params,
|
||||
u16 src_id, u16 src_index, u16 dst_id,
|
||||
u16 dst_host_irq, u16 ia_id, u16 vint,
|
||||
u16 global_event, u8 vint_status_bit, u8 s_host)
|
||||
{
|
||||
pr_debug("%s: IRQ set with valid_params = 0x%x from src = %d, index = %d, to dst = %d, irq = %d,via ia_id = %d, vint = %d, global event = %d,status_bit = %d\n",
|
||||
__func__, valid_params, src_id, src_index,
|
||||
dst_id, dst_host_irq, ia_id, vint, global_event,
|
||||
vint_status_bit);
|
||||
|
||||
return ti_sci_manage_irq(handle, valid_params, src_id, src_index,
|
||||
dst_id, dst_host_irq, ia_id, vint,
|
||||
global_event, vint_status_bit, s_host,
|
||||
TI_SCI_MSG_SET_IRQ);
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_free_irq() - Helper api to free the irq route between the
|
||||
* requested source and destination
|
||||
* @handle: Pointer to TISCI handle.
|
||||
* @valid_params: Bit fields defining the validity of certain params
|
||||
* @src_id: Device ID of the IRQ source
|
||||
* @src_index: IRQ source index within the source device
|
||||
* @dst_id: Device ID of the IRQ destination
|
||||
* @dst_host_irq: IRQ number of the destination device
|
||||
* @ia_id: Device ID of the IA, if the IRQ flows through this IA
|
||||
* @vint: Virtual interrupt to be used within the IA
|
||||
* @global_event: Global event number to be used for the requesting event
|
||||
* @vint_status_bit: Virtual interrupt status bit to be used for the event
|
||||
* @s_host: Secondary host ID to which the irq/event is being
|
||||
* requested for.
|
||||
*
|
||||
* Return: 0 if all went fine, else return appropriate error.
|
||||
*/
|
||||
static int ti_sci_free_irq(const struct ti_sci_handle *handle, u32 valid_params,
|
||||
u16 src_id, u16 src_index, u16 dst_id,
|
||||
u16 dst_host_irq, u16 ia_id, u16 vint,
|
||||
u16 global_event, u8 vint_status_bit, u8 s_host)
|
||||
{
|
||||
pr_debug("%s: IRQ release with valid_params = 0x%x from src = %d, index = %d, to dst = %d, irq = %d,via ia_id = %d, vint = %d, global event = %d,status_bit = %d\n",
|
||||
__func__, valid_params, src_id, src_index,
|
||||
dst_id, dst_host_irq, ia_id, vint, global_event,
|
||||
vint_status_bit);
|
||||
|
||||
return ti_sci_manage_irq(handle, valid_params, src_id, src_index,
|
||||
dst_id, dst_host_irq, ia_id, vint,
|
||||
global_event, vint_status_bit, s_host,
|
||||
TI_SCI_MSG_FREE_IRQ);
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_cmd_set_irq() - Configure a host irq route between the requested
|
||||
* source and destination.
|
||||
* @handle: Pointer to TISCI handle.
|
||||
* @src_id: Device ID of the IRQ source
|
||||
* @src_index: IRQ source index within the source device
|
||||
* @dst_id: Device ID of the IRQ destination
|
||||
* @dst_host_irq: IRQ number of the destination device
|
||||
* @vint_irq: Boolean specifying if this interrupt belongs to
|
||||
* Interrupt Aggregator.
|
||||
*
|
||||
* Return: 0 if all went fine, else return appropriate error.
|
||||
*/
|
||||
static int ti_sci_cmd_set_irq(const struct ti_sci_handle *handle, u16 src_id,
|
||||
u16 src_index, u16 dst_id, u16 dst_host_irq)
|
||||
{
|
||||
u32 valid_params = MSG_FLAG_DST_ID_VALID | MSG_FLAG_DST_HOST_IRQ_VALID;
|
||||
|
||||
return ti_sci_set_irq(handle, valid_params, src_id, src_index, dst_id,
|
||||
dst_host_irq, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_cmd_set_event_map() - Configure an event based irq route between the
|
||||
* requested source and Interrupt Aggregator.
|
||||
* @handle: Pointer to TISCI handle.
|
||||
* @src_id: Device ID of the IRQ source
|
||||
* @src_index: IRQ source index within the source device
|
||||
* @ia_id: Device ID of the IA, if the IRQ flows through this IA
|
||||
* @vint: Virtual interrupt to be used within the IA
|
||||
* @global_event: Global event number to be used for the requesting event
|
||||
* @vint_status_bit: Virtual interrupt status bit to be used for the event
|
||||
*
|
||||
* Return: 0 if all went fine, else return appropriate error.
|
||||
*/
|
||||
static int ti_sci_cmd_set_event_map(const struct ti_sci_handle *handle,
|
||||
u16 src_id, u16 src_index, u16 ia_id,
|
||||
u16 vint, u16 global_event,
|
||||
u8 vint_status_bit)
|
||||
{
|
||||
u32 valid_params = MSG_FLAG_IA_ID_VALID | MSG_FLAG_VINT_VALID |
|
||||
MSG_FLAG_GLB_EVNT_VALID |
|
||||
MSG_FLAG_VINT_STS_BIT_VALID;
|
||||
|
||||
return ti_sci_set_irq(handle, valid_params, src_id, src_index, 0, 0,
|
||||
ia_id, vint, global_event, vint_status_bit, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_cmd_free_irq() - Free a host irq route between the between the
|
||||
* requested source and destination.
|
||||
* @handle: Pointer to TISCI handle.
|
||||
* @src_id: Device ID of the IRQ source
|
||||
* @src_index: IRQ source index within the source device
|
||||
* @dst_id: Device ID of the IRQ destination
|
||||
* @dst_host_irq: IRQ number of the destination device
|
||||
* @vint_irq: Boolean specifying if this interrupt belongs to
|
||||
* Interrupt Aggregator.
|
||||
*
|
||||
* Return: 0 if all went fine, else return appropriate error.
|
||||
*/
|
||||
static int ti_sci_cmd_free_irq(const struct ti_sci_handle *handle, u16 src_id,
|
||||
u16 src_index, u16 dst_id, u16 dst_host_irq)
|
||||
{
|
||||
u32 valid_params = MSG_FLAG_DST_ID_VALID | MSG_FLAG_DST_HOST_IRQ_VALID;
|
||||
|
||||
return ti_sci_free_irq(handle, valid_params, src_id, src_index, dst_id,
|
||||
dst_host_irq, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sci_cmd_free_event_map() - Free an event map between the requested source
|
||||
* and Interrupt Aggregator.
|
||||
* @handle: Pointer to TISCI handle.
|
||||
* @src_id: Device ID of the IRQ source
|
||||
* @src_index: IRQ source index within the source device
|
||||
* @ia_id: Device ID of the IA, if the IRQ flows through this IA
|
||||
* @vint: Virtual interrupt to be used within the IA
|
||||
* @global_event: Global event number to be used for the requesting event
|
||||
* @vint_status_bit: Virtual interrupt status bit to be used for the event
|
||||
*
|
||||
* Return: 0 if all went fine, else return appropriate error.
|
||||
*/
|
||||
static int ti_sci_cmd_free_event_map(const struct ti_sci_handle *handle,
|
||||
u16 src_id, u16 src_index, u16 ia_id,
|
||||
u16 vint, u16 global_event,
|
||||
u8 vint_status_bit)
|
||||
{
|
||||
u32 valid_params = MSG_FLAG_IA_ID_VALID |
|
||||
MSG_FLAG_VINT_VALID | MSG_FLAG_GLB_EVNT_VALID |
|
||||
MSG_FLAG_VINT_STS_BIT_VALID;
|
||||
|
||||
return ti_sci_free_irq(handle, valid_params, src_id, src_index, 0, 0,
|
||||
ia_id, vint, global_event, vint_status_bit, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ti_sci_setup_ops() - Setup the operations structures
|
||||
* @info: pointer to TISCI pointer
|
||||
@@ -1610,6 +2014,8 @@ 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_rm_core_ops *rm_core_ops = &ops->rm_core_ops;
|
||||
struct ti_sci_rm_irq_ops *iops = &ops->rm_irq_ops;
|
||||
|
||||
core_ops->reboot_device = ti_sci_cmd_core_reboot;
|
||||
|
||||
@@ -1640,6 +2046,15 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
|
||||
cops->get_best_match_freq = ti_sci_cmd_clk_get_match_freq;
|
||||
cops->set_freq = ti_sci_cmd_clk_set_freq;
|
||||
cops->get_freq = ti_sci_cmd_clk_get_freq;
|
||||
|
||||
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;
|
||||
|
||||
iops->set_irq = ti_sci_cmd_set_irq;
|
||||
iops->set_event_map = ti_sci_cmd_set_event_map;
|
||||
iops->free_irq = ti_sci_cmd_free_irq;
|
||||
iops->free_event_map = ti_sci_cmd_free_event_map;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1764,6 +2179,219 @@ const struct ti_sci_handle *devm_ti_sci_get_handle(struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_ti_sci_get_handle);
|
||||
|
||||
/**
|
||||
* ti_sci_get_by_phandle() - Get the TI SCI handle using DT phandle
|
||||
* @np: device node
|
||||
* @property: property name containing phandle on TISCI node
|
||||
*
|
||||
* NOTE: The function does not track individual clients of the framework
|
||||
* and is expected to be maintained by caller of TI SCI protocol library.
|
||||
* ti_sci_put_handle must be balanced with successful ti_sci_get_by_phandle
|
||||
* Return: pointer to handle if successful, else:
|
||||
* -EPROBE_DEFER if the instance is not ready
|
||||
* -ENODEV if the required node handler is missing
|
||||
* -EINVAL if invalid conditions are encountered.
|
||||
*/
|
||||
const struct ti_sci_handle *ti_sci_get_by_phandle(struct device_node *np,
|
||||
const char *property)
|
||||
{
|
||||
struct ti_sci_handle *handle = NULL;
|
||||
struct device_node *ti_sci_np;
|
||||
struct ti_sci_info *info;
|
||||
struct list_head *p;
|
||||
|
||||
if (!np) {
|
||||
pr_err("I need a device pointer\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
ti_sci_np = of_parse_phandle(np, property, 0);
|
||||
if (!ti_sci_np)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
mutex_lock(&ti_sci_list_mutex);
|
||||
list_for_each(p, &ti_sci_list) {
|
||||
info = list_entry(p, struct ti_sci_info, node);
|
||||
if (ti_sci_np == info->dev->of_node) {
|
||||
handle = &info->handle;
|
||||
info->users++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ti_sci_list_mutex);
|
||||
of_node_put(ti_sci_np);
|
||||
|
||||
if (!handle)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
return handle;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ti_sci_get_by_phandle);
|
||||
|
||||
/**
|
||||
* devm_ti_sci_get_by_phandle() - Managed get handle using phandle
|
||||
* @dev: Device pointer requesting TISCI handle
|
||||
* @property: property name containing phandle on TISCI node
|
||||
*
|
||||
* NOTE: This releases the handle once the device resources are
|
||||
* no longer needed. MUST NOT BE released with ti_sci_put_handle.
|
||||
* The function does not track individual clients of the framework
|
||||
* and is expected to be maintained by caller of TI SCI protocol library.
|
||||
*
|
||||
* Return: 0 if all went fine, else corresponding error.
|
||||
*/
|
||||
const struct ti_sci_handle *devm_ti_sci_get_by_phandle(struct device *dev,
|
||||
const char *property)
|
||||
{
|
||||
const struct ti_sci_handle *handle;
|
||||
const struct ti_sci_handle **ptr;
|
||||
|
||||
ptr = devres_alloc(devm_ti_sci_release, sizeof(*ptr), GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
handle = ti_sci_get_by_phandle(dev_of_node(dev), property);
|
||||
|
||||
if (!IS_ERR(handle)) {
|
||||
*ptr = handle;
|
||||
devres_add(dev, ptr);
|
||||
} else {
|
||||
devres_free(ptr);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_ti_sci_get_by_phandle);
|
||||
|
||||
/**
|
||||
* ti_sci_get_free_resource() - Get a free resource from TISCI resource.
|
||||
* @res: Pointer to the TISCI resource
|
||||
*
|
||||
* Return: resource num if all went ok else TI_SCI_RESOURCE_NULL.
|
||||
*/
|
||||
u16 ti_sci_get_free_resource(struct ti_sci_resource *res)
|
||||
{
|
||||
unsigned long flags;
|
||||
u16 set, free_bit;
|
||||
|
||||
raw_spin_lock_irqsave(&res->lock, flags);
|
||||
for (set = 0; set < res->sets; set++) {
|
||||
free_bit = find_first_zero_bit(res->desc[set].res_map,
|
||||
res->desc[set].num);
|
||||
if (free_bit != res->desc[set].num) {
|
||||
set_bit(free_bit, res->desc[set].res_map);
|
||||
raw_spin_unlock_irqrestore(&res->lock, flags);
|
||||
return res->desc[set].start + free_bit;
|
||||
}
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&res->lock, flags);
|
||||
|
||||
return TI_SCI_RESOURCE_NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ti_sci_get_free_resource);
|
||||
|
||||
/**
|
||||
* ti_sci_release_resource() - Release a resource from TISCI resource.
|
||||
* @res: Pointer to the TISCI resource
|
||||
* @id: Resource id to be released.
|
||||
*/
|
||||
void ti_sci_release_resource(struct ti_sci_resource *res, u16 id)
|
||||
{
|
||||
unsigned long flags;
|
||||
u16 set;
|
||||
|
||||
raw_spin_lock_irqsave(&res->lock, flags);
|
||||
for (set = 0; set < res->sets; set++) {
|
||||
if (res->desc[set].start <= id &&
|
||||
(res->desc[set].num + res->desc[set].start) > id)
|
||||
clear_bit(id - res->desc[set].start,
|
||||
res->desc[set].res_map);
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&res->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ti_sci_release_resource);
|
||||
|
||||
/**
|
||||
* ti_sci_get_num_resources() - Get the number of resources in TISCI resource
|
||||
* @res: Pointer to the TISCI resource
|
||||
*
|
||||
* Return: Total number of available resources.
|
||||
*/
|
||||
u32 ti_sci_get_num_resources(struct ti_sci_resource *res)
|
||||
{
|
||||
u32 set, count = 0;
|
||||
|
||||
for (set = 0; set < res->sets; set++)
|
||||
count += res->desc[set].num;
|
||||
|
||||
return count;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ti_sci_get_num_resources);
|
||||
|
||||
/**
|
||||
* devm_ti_sci_get_of_resource() - Get a TISCI resource assigned to a device
|
||||
* @handle: TISCI handle
|
||||
* @dev: Device pointer to which the resource is assigned
|
||||
* @dev_id: TISCI device id to which the resource is assigned
|
||||
* @of_prop: property name by which the resource are represented
|
||||
*
|
||||
* Return: Pointer to ti_sci_resource if all went well else appropriate
|
||||
* error pointer.
|
||||
*/
|
||||
struct ti_sci_resource *
|
||||
devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
|
||||
struct device *dev, u32 dev_id, char *of_prop)
|
||||
{
|
||||
struct ti_sci_resource *res;
|
||||
u32 resource_subtype;
|
||||
int i, ret;
|
||||
|
||||
res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
|
||||
if (!res)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
res->sets = of_property_count_elems_of_size(dev_of_node(dev), of_prop,
|
||||
sizeof(u32));
|
||||
if (res->sets < 0) {
|
||||
dev_err(dev, "%s resource type ids not available\n", of_prop);
|
||||
return ERR_PTR(res->sets);
|
||||
}
|
||||
|
||||
res->desc = devm_kcalloc(dev, res->sets, sizeof(*res->desc),
|
||||
GFP_KERNEL);
|
||||
if (!res->desc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
for (i = 0; i < res->sets; i++) {
|
||||
ret = of_property_read_u32_index(dev_of_node(dev), of_prop, i,
|
||||
&resource_subtype);
|
||||
if (ret)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
ret = handle->ops.rm_core_ops.get_range(handle, dev_id,
|
||||
resource_subtype,
|
||||
&res->desc[i].start,
|
||||
&res->desc[i].num);
|
||||
if (ret) {
|
||||
dev_err(dev, "dev = %d subtype %d not allocated for this host\n",
|
||||
dev_id, resource_subtype);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
dev_dbg(dev, "dev = %d, subtype = %d, start = %d, num = %d\n",
|
||||
dev_id, resource_subtype, res->desc[i].start,
|
||||
res->desc[i].num);
|
||||
|
||||
res->desc[i].res_map =
|
||||
devm_kzalloc(dev, BITS_TO_LONGS(res->desc[i].num) *
|
||||
sizeof(*res->desc[i].res_map), GFP_KERNEL);
|
||||
if (!res->desc[i].res_map)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
raw_spin_lock_init(&res->lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode,
|
||||
void *cmd)
|
||||
{
|
||||
@@ -1784,10 +2412,33 @@ static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = {
|
||||
/* Limited by MBOX_TX_QUEUE_LEN. K2G can handle upto 128 messages! */
|
||||
.max_msgs = 20,
|
||||
.max_msg_size = 64,
|
||||
.rm_type_map = NULL,
|
||||
};
|
||||
|
||||
static struct ti_sci_rm_type_map ti_sci_am654_rm_type_map[] = {
|
||||
{.dev_id = 56, .type = 0x00b}, /* GIC_IRQ */
|
||||
{.dev_id = 179, .type = 0x000}, /* MAIN_NAV_UDMASS_IA0 */
|
||||
{.dev_id = 187, .type = 0x009}, /* MAIN_NAV_RA */
|
||||
{.dev_id = 188, .type = 0x006}, /* MAIN_NAV_UDMAP */
|
||||
{.dev_id = 194, .type = 0x007}, /* MCU_NAV_UDMAP */
|
||||
{.dev_id = 195, .type = 0x00a}, /* MCU_NAV_RA */
|
||||
{.dev_id = 0, .type = 0x000}, /* end of table */
|
||||
};
|
||||
|
||||
/* Description for AM654 */
|
||||
static const struct ti_sci_desc ti_sci_pmmc_am654_desc = {
|
||||
.default_host_id = 12,
|
||||
/* Conservative duration */
|
||||
.max_rx_timeout_ms = 10000,
|
||||
/* Limited by MBOX_TX_QUEUE_LEN. K2G can handle upto 128 messages! */
|
||||
.max_msgs = 20,
|
||||
.max_msg_size = 60,
|
||||
.rm_type_map = ti_sci_am654_rm_type_map,
|
||||
};
|
||||
|
||||
static const struct of_device_id ti_sci_of_match[] = {
|
||||
{.compatible = "ti,k2g-sci", .data = &ti_sci_pmmc_k2g_desc},
|
||||
{.compatible = "ti,am654-sci", .data = &ti_sci_pmmc_am654_desc},
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ti_sci_of_match);
|
||||
|
@@ -35,6 +35,13 @@
|
||||
#define TI_SCI_MSG_QUERY_CLOCK_FREQ 0x010d
|
||||
#define TI_SCI_MSG_GET_CLOCK_FREQ 0x010e
|
||||
|
||||
/* Resource Management Requests */
|
||||
#define TI_SCI_MSG_GET_RESOURCE_RANGE 0x1500
|
||||
|
||||
/* IRQ requests */
|
||||
#define TI_SCI_MSG_SET_IRQ 0x1000
|
||||
#define TI_SCI_MSG_FREE_IRQ 0x1001
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_hdr - Generic Message Header for All messages and responses
|
||||
* @type: Type of messages: One of TI_SCI_MSG* values
|
||||
@@ -461,4 +468,99 @@ struct ti_sci_msg_resp_get_clock_freq {
|
||||
u64 freq_hz;
|
||||
} __packed;
|
||||
|
||||
#define TI_SCI_IRQ_SECONDARY_HOST_INVALID 0xff
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_req_get_resource_range - Request to get a host's assigned
|
||||
* range of resources.
|
||||
* @hdr: Generic Header
|
||||
* @type: Unique resource assignment type
|
||||
* @subtype: Resource assignment subtype within the resource type.
|
||||
* @secondary_host: Host processing entity to which the resources are
|
||||
* allocated. This is required only when the destination
|
||||
* host id id different from ti sci interface host id,
|
||||
* else TI_SCI_IRQ_SECONDARY_HOST_INVALID can be passed.
|
||||
*
|
||||
* Request type is TI_SCI_MSG_GET_RESOURCE_RANGE. Responded with requested
|
||||
* resource range which is of type TI_SCI_MSG_GET_RESOURCE_RANGE.
|
||||
*/
|
||||
struct ti_sci_msg_req_get_resource_range {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
#define MSG_RM_RESOURCE_TYPE_MASK GENMASK(9, 0)
|
||||
#define MSG_RM_RESOURCE_SUBTYPE_MASK GENMASK(5, 0)
|
||||
u16 type;
|
||||
u8 subtype;
|
||||
u8 secondary_host;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_resp_get_resource_range - Response to resource get range.
|
||||
* @hdr: Generic Header
|
||||
* @range_start: Start index of the resource range.
|
||||
* @range_num: Number of resources in the range.
|
||||
*
|
||||
* Response to request TI_SCI_MSG_GET_RESOURCE_RANGE.
|
||||
*/
|
||||
struct ti_sci_msg_resp_get_resource_range {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
u16 range_start;
|
||||
u16 range_num;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_req_manage_irq - Request to configure/release the route
|
||||
* between the dev and the host.
|
||||
* @hdr: Generic Header
|
||||
* @valid_params: Bit fields defining the validity of interrupt source
|
||||
* parameters. If a bit is not set, then corresponding
|
||||
* field is not valid and will not be used for route set.
|
||||
* Bit field definitions:
|
||||
* 0 - Valid bit for @dst_id
|
||||
* 1 - Valid bit for @dst_host_irq
|
||||
* 2 - Valid bit for @ia_id
|
||||
* 3 - Valid bit for @vint
|
||||
* 4 - Valid bit for @global_event
|
||||
* 5 - Valid bit for @vint_status_bit_index
|
||||
* 31 - Valid bit for @secondary_host
|
||||
* @src_id: IRQ source peripheral ID.
|
||||
* @src_index: IRQ source index within the peripheral
|
||||
* @dst_id: IRQ Destination ID. Based on the architecture it can be
|
||||
* IRQ controller or host processor ID.
|
||||
* @dst_host_irq: IRQ number of the destination host IRQ controller
|
||||
* @ia_id: Device ID of the interrupt aggregator in which the
|
||||
* vint resides.
|
||||
* @vint: Virtual interrupt number if the interrupt route
|
||||
* is through an interrupt aggregator.
|
||||
* @global_event: Global event that is to be mapped to interrupt
|
||||
* aggregator virtual interrupt status bit.
|
||||
* @vint_status_bit: Virtual interrupt status bit if the interrupt route
|
||||
* utilizes an interrupt aggregator status bit.
|
||||
* @secondary_host: Host ID of the IRQ destination computing entity. This is
|
||||
* required only when destination host id is different
|
||||
* from ti sci interface host id.
|
||||
*
|
||||
* Request type is TI_SCI_MSG_SET/RELEASE_IRQ.
|
||||
* Response is generic ACK / NACK message.
|
||||
*/
|
||||
struct ti_sci_msg_req_manage_irq {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
#define MSG_FLAG_DST_ID_VALID TI_SCI_MSG_FLAG(0)
|
||||
#define MSG_FLAG_DST_HOST_IRQ_VALID TI_SCI_MSG_FLAG(1)
|
||||
#define MSG_FLAG_IA_ID_VALID TI_SCI_MSG_FLAG(2)
|
||||
#define MSG_FLAG_VINT_VALID TI_SCI_MSG_FLAG(3)
|
||||
#define MSG_FLAG_GLB_EVNT_VALID TI_SCI_MSG_FLAG(4)
|
||||
#define MSG_FLAG_VINT_STS_BIT_VALID TI_SCI_MSG_FLAG(5)
|
||||
#define MSG_FLAG_SHOST_VALID TI_SCI_MSG_FLAG(31)
|
||||
u32 valid_params;
|
||||
u16 src_id;
|
||||
u16 src_index;
|
||||
u16 dst_id;
|
||||
u16 dst_host_irq;
|
||||
u16 ia_id;
|
||||
u16 vint;
|
||||
u16 global_event;
|
||||
u8 vint_status_bit;
|
||||
u8 secondary_host;
|
||||
} __packed;
|
||||
|
||||
#endif /* __TI_SCI_H */
|
||||
|
Reference in New Issue
Block a user