mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-11 07:24:46 +00:00
drivers: misc: irq-uclass: Update irq_get_by_index
Support reading the "interrupts" property from the devicetree in case the "interrupts-extended" property isn't found. As the "interrupts" property is commonly used, this allows to parse all existing FDT and makes irq_get_by_index() more useful. The "interrupts" property doesn't contain a phandle as "interrupts-extended" does, so implement a new method to locate the interrupt-parent called irq_get_interrupt_parent(). TEST: Read the interrupts from the GIC node for ACPI MADT generation. Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> Reviewed-by: Moritz Fischer <moritzf@google.com>
This commit is contained in:
parent
df8d759d9d
commit
f116feadea
4 changed files with 97 additions and 1 deletions
|
@ -522,6 +522,9 @@
|
|||
};
|
||||
|
||||
f-test {
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&irq>;
|
||||
interrupts = <4 0>;
|
||||
compatible = "denx,u-boot-fdt-test";
|
||||
};
|
||||
|
||||
|
|
|
@ -62,6 +62,40 @@ int irq_read_and_clear(struct irq *irq)
|
|||
return ops->read_and_clear(irq);
|
||||
}
|
||||
|
||||
int irq_get_interrupt_parent(const struct udevice *dev,
|
||||
struct udevice **interrupt_parent)
|
||||
{
|
||||
struct ofnode_phandle_args phandle_args;
|
||||
struct udevice *irq = NULL;
|
||||
ofnode node;
|
||||
int ret;
|
||||
|
||||
if (!dev || !interrupt_parent)
|
||||
return -EINVAL;
|
||||
|
||||
*interrupt_parent = NULL;
|
||||
|
||||
node = dev_ofnode(dev);
|
||||
if (!ofnode_valid(node))
|
||||
return -EINVAL;
|
||||
|
||||
while (ofnode_valid(node)) {
|
||||
ret = ofnode_parse_phandle_with_args(node, "interrupt-parent",
|
||||
NULL, 0, 0, &phandle_args);
|
||||
if (!ret && !device_get_global_by_ofnode(phandle_args.node, &irq))
|
||||
break;
|
||||
node = ofnode_get_parent(node);
|
||||
}
|
||||
|
||||
if (!irq) {
|
||||
log_err("Cannot find an interrupt parent for device %s\n", dev->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
*interrupt_parent = irq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
int irq_get_by_phandle(struct udevice *dev, const struct phandle_2_arg *cells,
|
||||
struct irq *irq)
|
||||
|
@ -142,10 +176,40 @@ err:
|
|||
int irq_get_by_index(struct udevice *dev, int index, struct irq *irq)
|
||||
{
|
||||
struct ofnode_phandle_args args;
|
||||
int ret;
|
||||
struct udevice *interrupt_parent;
|
||||
int ret, size, i;
|
||||
const __be32 *list;
|
||||
u32 count;
|
||||
|
||||
ret = dev_read_phandle_with_args(dev, "interrupts-extended",
|
||||
"#interrupt-cells", 0, index, &args);
|
||||
if (ret) {
|
||||
list = dev_read_prop(dev, "interrupts", &size);
|
||||
if (!list)
|
||||
return -ENOENT;
|
||||
|
||||
ret = irq_get_interrupt_parent(dev, &interrupt_parent);
|
||||
if (ret)
|
||||
return -ENODEV;
|
||||
args.node = dev_ofnode(interrupt_parent);
|
||||
|
||||
if (dev_read_u32(interrupt_parent, "#interrupt-cells", &count)) {
|
||||
log_err("%s: could not get #interrupt-cells for %s\n",
|
||||
__func__, dev->name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (index * count >= size / sizeof(*list))
|
||||
return -ENOENT;
|
||||
if (count > OF_MAX_PHANDLE_ARGS)
|
||||
count = OF_MAX_PHANDLE_ARGS;
|
||||
args.args_count = count;
|
||||
for (i = 0; i < count; i++)
|
||||
args.args[i] = be32_to_cpup(&list[index * count + i]);
|
||||
|
||||
return irq_get_by_index_tail(ret, dev_ofnode(dev), &args,
|
||||
"interrupts", index, irq);
|
||||
}
|
||||
|
||||
return irq_get_by_index_tail(ret, dev_ofnode(dev), &args,
|
||||
"interrupts-extended", index > 0, irq);
|
||||
|
|
|
@ -200,6 +200,20 @@ int irq_restore_polarities(struct udevice *dev);
|
|||
*/
|
||||
int irq_read_and_clear(struct irq *irq);
|
||||
|
||||
/**
|
||||
* irq_get_interrupt_parent() - returns the interrupt parent
|
||||
*
|
||||
* Walks the devicetree and returns the interrupt parent's ofnode
|
||||
* for the specified device.
|
||||
*
|
||||
* @dev: device
|
||||
* @interrupt_parent: The interrupt parent's ofnode'
|
||||
* Return: 0 success, or error value
|
||||
*
|
||||
*/
|
||||
int irq_get_interrupt_parent(const struct udevice *dev,
|
||||
struct udevice **interrupt_parent);
|
||||
|
||||
struct phandle_2_arg;
|
||||
/**
|
||||
* irq_get_by_phandle() - Get an irq by its phandle information (of-platadata)
|
||||
|
|
|
@ -76,6 +76,21 @@ static int dm_test_request(struct unit_test_state *uts)
|
|||
}
|
||||
DM_TEST(dm_test_request, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
||||
|
||||
/* Test of irq_get_by_index() */
|
||||
static int dm_test_irq_get_by_index(struct unit_test_state *uts)
|
||||
{
|
||||
struct udevice *dev;
|
||||
struct irq irq;
|
||||
|
||||
ut_assertok(uclass_get_device_by_name(UCLASS_TEST_FDT, "f-test",
|
||||
&dev));
|
||||
ut_assertok(irq_get_by_index(dev, 0, &irq));
|
||||
ut_asserteq(4, irq.id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_irq_get_by_index, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
||||
|
||||
/* Test of irq_get_acpi() */
|
||||
static int dm_test_irq_get_acpi(struct unit_test_state *uts)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue