mirror of
https://github.com/u-boot/u-boot.git
synced 2025-05-07 12:49:24 +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 {
|
f-test {
|
||||||
|
#interrupt-cells = <2>;
|
||||||
|
interrupt-parent = <&irq>;
|
||||||
|
interrupts = <4 0>;
|
||||||
compatible = "denx,u-boot-fdt-test";
|
compatible = "denx,u-boot-fdt-test";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,40 @@ int irq_read_and_clear(struct irq *irq)
|
||||||
return ops->read_and_clear(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)
|
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||||
int irq_get_by_phandle(struct udevice *dev, const struct phandle_2_arg *cells,
|
int irq_get_by_phandle(struct udevice *dev, const struct phandle_2_arg *cells,
|
||||||
struct irq *irq)
|
struct irq *irq)
|
||||||
|
@ -142,10 +176,40 @@ err:
|
||||||
int irq_get_by_index(struct udevice *dev, int index, struct irq *irq)
|
int irq_get_by_index(struct udevice *dev, int index, struct irq *irq)
|
||||||
{
|
{
|
||||||
struct ofnode_phandle_args args;
|
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",
|
ret = dev_read_phandle_with_args(dev, "interrupts-extended",
|
||||||
"#interrupt-cells", 0, index, &args);
|
"#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,
|
return irq_get_by_index_tail(ret, dev_ofnode(dev), &args,
|
||||||
"interrupts-extended", index > 0, irq);
|
"interrupts-extended", index > 0, irq);
|
||||||
|
|
|
@ -200,6 +200,20 @@ int irq_restore_polarities(struct udevice *dev);
|
||||||
*/
|
*/
|
||||||
int irq_read_and_clear(struct irq *irq);
|
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;
|
struct phandle_2_arg;
|
||||||
/**
|
/**
|
||||||
* irq_get_by_phandle() - Get an irq by its phandle information (of-platadata)
|
* 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);
|
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() */
|
/* Test of irq_get_acpi() */
|
||||||
static int dm_test_irq_get_acpi(struct unit_test_state *uts)
|
static int dm_test_irq_get_acpi(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue