Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'renesas-drivers-for-v6.20-tag2' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel into soc/drivers

Renesas driver updates for v6.20 (take two)

- Add and use for_each_of_imap_item() iterator,
- Add support for the RZ/N1 GPIO Interrupt Multiplexer.

* tag 'renesas-drivers-for-v6.20-tag2' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel:
soc: renesas: Add support for RZ/N1 GPIO Interrupt Multiplexer
irqchip/renesas-rza1: Use for_each_of_imap_item iterator
irqchip/ls-extirq: Use for_each_of_imap_item iterator
of: unittest: Add a test case for for_each_of_imap_item iterator
of/irq: Introduce for_each_of_imap_item

Signed-off-by: Arnd Bergmann <arnd@arndb.de>

+400 -58
+17 -30
drivers/irqchip/irq-ls-extirq.c
··· 125 125 static int 126 126 ls_extirq_parse_map(struct ls_extirq_data *priv, struct device_node *node) 127 127 { 128 - const __be32 *map; 129 - u32 mapsize; 128 + struct of_imap_parser imap_parser; 129 + struct of_imap_item imap_item; 130 130 int ret; 131 131 132 - map = of_get_property(node, "interrupt-map", &mapsize); 133 - if (!map) 134 - return -ENOENT; 135 - if (mapsize % sizeof(*map)) 136 - return -EINVAL; 137 - mapsize /= sizeof(*map); 132 + ret = of_imap_parser_init(&imap_parser, node, &imap_item); 133 + if (ret) 134 + return ret; 138 135 139 - while (mapsize) { 136 + for_each_of_imap_item(&imap_parser, &imap_item) { 140 137 struct device_node *ipar; 141 - u32 hwirq, intsize, j; 138 + u32 hwirq; 139 + int i; 142 140 143 - if (mapsize < 3) 141 + hwirq = imap_item.child_imap[0]; 142 + if (hwirq >= MAXIRQ) { 143 + of_node_put(imap_item.parent_args.np); 144 144 return -EINVAL; 145 - hwirq = be32_to_cpup(map); 146 - if (hwirq >= MAXIRQ) 147 - return -EINVAL; 145 + } 148 146 priv->nirq = max(priv->nirq, hwirq + 1); 149 147 150 - ipar = of_find_node_by_phandle(be32_to_cpup(map + 2)); 151 - map += 3; 152 - mapsize -= 3; 153 - if (!ipar) 154 - return -EINVAL; 155 - priv->map[hwirq].fwnode = &ipar->fwnode; 156 - ret = of_property_read_u32(ipar, "#interrupt-cells", &intsize); 157 - if (ret) 158 - return ret; 148 + ipar = of_node_get(imap_item.parent_args.np); 149 + priv->map[hwirq].fwnode = of_fwnode_handle(ipar); 159 150 160 - if (intsize > mapsize) 161 - return -EINVAL; 162 - 163 - priv->map[hwirq].param_count = intsize; 164 - for (j = 0; j < intsize; ++j) 165 - priv->map[hwirq].param[j] = be32_to_cpup(map++); 166 - mapsize -= intsize; 151 + priv->map[hwirq].param_count = imap_item.parent_args.args_count; 152 + for (i = 0; i < priv->map[hwirq].param_count; i++) 153 + priv->map[hwirq].param[i] = imap_item.parent_args.args[i]; 167 154 } 168 155 return 0; 169 156 }
+16 -27
drivers/irqchip/irq-renesas-rza1.c
··· 142 142 static int rza1_irqc_parse_map(struct rza1_irqc_priv *priv, 143 143 struct device_node *gic_node) 144 144 { 145 + struct of_imap_parser imap_parser; 145 146 struct device *dev = priv->dev; 146 - unsigned int imaplen, i, j; 147 + struct of_imap_item imap_item; 147 148 struct device_node *ipar; 148 - const __be32 *imap; 149 - u32 intsize; 149 + unsigned int j; 150 + u32 i = 0; 150 151 int ret; 151 152 152 - imap = of_get_property(dev->of_node, "interrupt-map", &imaplen); 153 - if (!imap) 154 - return -EINVAL; 153 + ret = of_imap_parser_init(&imap_parser, dev->of_node, &imap_item); 154 + if (ret) 155 + return ret; 155 156 156 - for (i = 0; i < IRQC_NUM_IRQ; i++) { 157 - if (imaplen < 3) 158 - return -EINVAL; 159 - 157 + for_each_of_imap_item(&imap_parser, &imap_item) { 160 158 /* Check interrupt number, ignore sense */ 161 - if (be32_to_cpup(imap) != i) 159 + if (imap_item.child_imap[0] != i) { 160 + of_node_put(imap_item.parent_args.np); 162 161 return -EINVAL; 162 + } 163 163 164 - ipar = of_find_node_by_phandle(be32_to_cpup(imap + 2)); 164 + ipar = imap_item.parent_args.np; 165 165 if (ipar != gic_node) { 166 166 of_node_put(ipar); 167 167 return -EINVAL; 168 168 } 169 169 170 - imap += 3; 171 - imaplen -= 3; 170 + priv->map[i].args_count = imap_item.parent_args.args_count; 171 + for (j = 0; j < priv->map[i].args_count; j++) 172 + priv->map[i].args[j] = imap_item.parent_args.args[j]; 172 173 173 - ret = of_property_read_u32(ipar, "#interrupt-cells", &intsize); 174 - of_node_put(ipar); 175 - if (ret) 176 - return ret; 177 - 178 - if (imaplen < intsize) 179 - return -EINVAL; 180 - 181 - priv->map[i].args_count = intsize; 182 - for (j = 0; j < intsize; j++) 183 - priv->map[i].args[j] = be32_to_cpup(imap++); 184 - 185 - imaplen -= intsize; 174 + i++; 186 175 } 187 176 188 177 return 0;
+70
drivers/of/irq.c
··· 157 157 return imap; 158 158 } 159 159 160 + int of_imap_parser_init(struct of_imap_parser *parser, struct device_node *node, 161 + struct of_imap_item *item) 162 + { 163 + int imaplen; 164 + u32 tmp; 165 + int ret; 166 + 167 + /* 168 + * parent_offset is the offset where the parent part is starting. 169 + * In other words, the offset where the parent interrupt controller 170 + * phandle is present. 171 + * 172 + * Compute this offset (child #interrupt-cells + child #address-cells) 173 + */ 174 + parser->parent_offset = of_bus_n_addr_cells(node); 175 + 176 + ret = of_property_read_u32(node, "#interrupt-cells", &tmp); 177 + if (ret) 178 + return ret; 179 + 180 + parser->parent_offset += tmp; 181 + 182 + if (WARN(parser->parent_offset > ARRAY_SIZE(item->child_imap), 183 + "child part size = %u, cannot fit in array of %zu items", 184 + parser->parent_offset, ARRAY_SIZE(item->child_imap))) 185 + return -EINVAL; 186 + 187 + parser->imap = of_get_property(node, "interrupt-map", &imaplen); 188 + if (!parser->imap) 189 + return -ENOENT; 190 + 191 + imaplen /= sizeof(*parser->imap); 192 + parser->imap_end = parser->imap + imaplen; 193 + 194 + memset(item, 0, sizeof(*item)); 195 + item->child_imap_count = parser->parent_offset; 196 + 197 + return 0; 198 + } 199 + EXPORT_SYMBOL_GPL(of_imap_parser_init); 200 + 201 + struct of_imap_item *of_imap_parser_one(struct of_imap_parser *parser, 202 + struct of_imap_item *item) 203 + { 204 + const __be32 *imap_parent, *imap_next; 205 + int i; 206 + 207 + /* Release previously get parent node */ 208 + of_node_put(item->parent_args.np); 209 + 210 + if (parser->imap + parser->parent_offset + 1 >= parser->imap_end) 211 + return NULL; 212 + 213 + imap_parent = parser->imap + parser->parent_offset; 214 + 215 + imap_next = of_irq_parse_imap_parent(imap_parent, 216 + parser->imap_end - imap_parent, 217 + &item->parent_args); 218 + if (!imap_next) 219 + return NULL; 220 + 221 + for (i = 0; i < parser->parent_offset; i++) 222 + item->child_imap[i] = be32_to_cpu(*(parser->imap + i)); 223 + 224 + parser->imap = imap_next; 225 + 226 + return item; 227 + } 228 + EXPORT_SYMBOL_GPL(of_imap_parser_one); 229 + 160 230 /** 161 231 * of_irq_parse_raw - Low level interrupt tree parsing 162 232 * @addr: address specifier (start of "reg" property of the device) in be32 format
+9
drivers/of/unittest-data/tests-interrupts.dtsi
··· 50 50 interrupt-map = <0x5000 1 2 &test_intc0 15>; 51 51 }; 52 52 53 + intmap2 { 54 + #interrupt-cells = <2>; 55 + #address-cells = <0>; 56 + interrupt-map = <1 11 &test_intc0 100>, 57 + <2 22 &test_intc1 200 201 202>, 58 + <3 33 &test_intc2 300 301>, 59 + <4 44 &test_intc2 400 401>; 60 + }; 61 + 53 62 test_intc_intmap0: intc-intmap0 { 54 63 #interrupt-cells = <1>; 55 64 #address-cells = <1>;
+116
drivers/of/unittest.c
··· 1654 1654 of_node_put(np); 1655 1655 } 1656 1656 1657 + struct of_unittest_expected_imap_item { 1658 + u32 child_imap_count; 1659 + u32 child_imap[2]; 1660 + const char *parent_path; 1661 + int parent_args_count; 1662 + u32 parent_args[3]; 1663 + }; 1664 + 1665 + static const struct of_unittest_expected_imap_item of_unittest_expected_imap_items[] = { 1666 + { 1667 + .child_imap_count = 2, 1668 + .child_imap = {1, 11}, 1669 + .parent_path = "/testcase-data/interrupts/intc0", 1670 + .parent_args_count = 1, 1671 + .parent_args = {100}, 1672 + }, { 1673 + .child_imap_count = 2, 1674 + .child_imap = {2, 22}, 1675 + .parent_path = "/testcase-data/interrupts/intc1", 1676 + .parent_args_count = 3, 1677 + .parent_args = {200, 201, 202}, 1678 + }, { 1679 + .child_imap_count = 2, 1680 + .child_imap = {3, 33}, 1681 + .parent_path = "/testcase-data/interrupts/intc2", 1682 + .parent_args_count = 2, 1683 + .parent_args = {300, 301}, 1684 + }, { 1685 + .child_imap_count = 2, 1686 + .child_imap = {4, 44}, 1687 + .parent_path = "/testcase-data/interrupts/intc2", 1688 + .parent_args_count = 2, 1689 + .parent_args = {400, 401}, 1690 + } 1691 + }; 1692 + 1693 + static void __init of_unittest_parse_interrupt_map(void) 1694 + { 1695 + const struct of_unittest_expected_imap_item *expected_item; 1696 + struct device_node *imap_np, *expected_parent_np; 1697 + struct of_imap_parser imap_parser; 1698 + struct of_imap_item imap_item; 1699 + int count, ret, i; 1700 + 1701 + if (of_irq_workarounds & (OF_IMAP_NO_PHANDLE | OF_IMAP_OLDWORLD_MAC)) 1702 + return; 1703 + 1704 + imap_np = of_find_node_by_path("/testcase-data/interrupts/intmap2"); 1705 + if (!imap_np) { 1706 + pr_err("missing testcase data\n"); 1707 + return; 1708 + } 1709 + 1710 + ret = of_imap_parser_init(&imap_parser, imap_np, &imap_item); 1711 + if (unittest(!ret, "of_imap_parser_init(%pOF) returned error %d\n", 1712 + imap_np, ret)) 1713 + goto end; 1714 + 1715 + expected_item = of_unittest_expected_imap_items; 1716 + count = 0; 1717 + 1718 + for_each_of_imap_item(&imap_parser, &imap_item) { 1719 + if (unittest(count < ARRAY_SIZE(of_unittest_expected_imap_items), 1720 + "imap item number %d not expected. Max number %zu\n", 1721 + count, ARRAY_SIZE(of_unittest_expected_imap_items) - 1)) { 1722 + of_node_put(imap_item.parent_args.np); 1723 + goto end; 1724 + } 1725 + 1726 + expected_parent_np = of_find_node_by_path(expected_item->parent_path); 1727 + if (unittest(expected_parent_np, 1728 + "missing dependent testcase data (%s)\n", 1729 + expected_item->parent_path)) { 1730 + of_node_put(imap_item.parent_args.np); 1731 + goto end; 1732 + } 1733 + 1734 + unittest(imap_item.child_imap_count == expected_item->child_imap_count, 1735 + "imap[%d] child_imap_count = %u, expected %u\n", 1736 + count, imap_item.child_imap_count, 1737 + expected_item->child_imap_count); 1738 + 1739 + for (i = 0; i < expected_item->child_imap_count; i++) 1740 + unittest(imap_item.child_imap[i] == expected_item->child_imap[i], 1741 + "imap[%d] child_imap[%d] = %u, expected %u\n", 1742 + count, i, imap_item.child_imap[i], 1743 + expected_item->child_imap[i]); 1744 + 1745 + unittest(imap_item.parent_args.np == expected_parent_np, 1746 + "imap[%d] parent np = %pOF, expected %pOF\n", 1747 + count, imap_item.parent_args.np, expected_parent_np); 1748 + 1749 + unittest(imap_item.parent_args.args_count == expected_item->parent_args_count, 1750 + "imap[%d] parent param_count = %d, expected %d\n", 1751 + count, imap_item.parent_args.args_count, 1752 + expected_item->parent_args_count); 1753 + 1754 + for (i = 0; i < expected_item->parent_args_count; i++) 1755 + unittest(imap_item.parent_args.args[i] == expected_item->parent_args[i], 1756 + "imap[%d] parent param[%d] = %u, expected %u\n", 1757 + count, i, imap_item.parent_args.args[i], 1758 + expected_item->parent_args[i]); 1759 + 1760 + of_node_put(expected_parent_np); 1761 + count++; 1762 + expected_item++; 1763 + } 1764 + 1765 + unittest(count == ARRAY_SIZE(of_unittest_expected_imap_items), 1766 + "Missing items. %d parsed, expected %zu\n", 1767 + count, ARRAY_SIZE(of_unittest_expected_imap_items)); 1768 + end: 1769 + of_node_put(imap_np); 1770 + } 1771 + 1657 1772 #if IS_ENABLED(CONFIG_OF_DYNAMIC) 1658 1773 static void __init of_unittest_irq_refcount(void) 1659 1774 { ··· 4510 4395 of_unittest_changeset_prop(); 4511 4396 of_unittest_parse_interrupts(); 4512 4397 of_unittest_parse_interrupts_extended(); 4398 + of_unittest_parse_interrupt_map(); 4513 4399 of_unittest_irq_refcount(); 4514 4400 of_unittest_dma_get_max_cpu_address(); 4515 4401 of_unittest_parse_dma_ranges();
+4
drivers/soc/renesas/Kconfig
··· 62 62 select PM 63 63 select PM_GENERIC_DOMAINS 64 64 select ARM_AMBA 65 + select RZN1_IRQMUX if GPIO_DWAPB 65 66 66 67 if ARM && ARCH_RENESAS 67 68 ··· 460 459 461 460 config RST_RCAR 462 461 bool "Reset Controller support for R-Car" if COMPILE_TEST 462 + 463 + config RZN1_IRQMUX 464 + bool "Renesas RZ/N1 GPIO IRQ multiplexer support" if COMPILE_TEST 463 465 464 466 config SYSC_RZ 465 467 bool "System controller for RZ SoCs" if COMPILE_TEST
+1
drivers/soc/renesas/Makefile
··· 14 14 # Family 15 15 obj-$(CONFIG_PWC_RZV2M) += pwc-rzv2m.o 16 16 obj-$(CONFIG_RST_RCAR) += rcar-rst.o 17 + obj-$(CONFIG_RZN1_IRQMUX) += rzn1_irqmux.o 17 18 obj-$(CONFIG_SYSC_RZ) += rz-sysc.o
+127
drivers/soc/renesas/rzn1_irqmux.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * RZ/N1 GPIO Interrupt Multiplexer 4 + * 5 + * Copyright 2025 Schneider Electric 6 + * Author: Herve Codina <herve.codina@bootlin.com> 7 + */ 8 + 9 + #include <linux/bitmap.h> 10 + #include <linux/bitops.h> 11 + #include <linux/mod_devicetable.h> 12 + #include <linux/module.h> 13 + #include <linux/of.h> 14 + #include <linux/of_irq.h> 15 + #include <linux/platform_device.h> 16 + #include <dt-bindings/interrupt-controller/arm-gic.h> 17 + 18 + /* 19 + * Up to 8 output lines are connected to GIC SPI interrupt controller 20 + * starting at IRQ 103. 21 + */ 22 + #define RZN1_IRQMUX_GIC_SPI_BASE 103 23 + #define RZN1_IRQMUX_NUM_OUTPUTS 8 24 + 25 + static int rzn1_irqmux_parent_args_to_line_index(struct device *dev, 26 + const struct of_phandle_args *parent_args) 27 + { 28 + /* 29 + * The parent interrupt should be one of the GIC controller. 30 + * Three arguments must be provided. 31 + * - args[0]: GIC_SPI 32 + * - args[1]: The GIC interrupt number 33 + * - args[2]: The interrupt flags 34 + * 35 + * We retrieve the line index based on the GIC interrupt number 36 + * provided. 37 + */ 38 + 39 + if (parent_args->args_count != 3 || parent_args->args[0] != GIC_SPI) { 40 + dev_err(dev, "Invalid interrupt-map item\n"); 41 + return -EINVAL; 42 + } 43 + 44 + if (parent_args->args[1] < RZN1_IRQMUX_GIC_SPI_BASE || 45 + parent_args->args[1] >= RZN1_IRQMUX_GIC_SPI_BASE + RZN1_IRQMUX_NUM_OUTPUTS) { 46 + dev_err(dev, "Invalid GIC interrupt %u\n", parent_args->args[1]); 47 + return -EINVAL; 48 + } 49 + 50 + return parent_args->args[1] - RZN1_IRQMUX_GIC_SPI_BASE; 51 + } 52 + 53 + static int rzn1_irqmux_probe(struct platform_device *pdev) 54 + { 55 + DECLARE_BITMAP(index_done, RZN1_IRQMUX_NUM_OUTPUTS) = {}; 56 + struct device *dev = &pdev->dev; 57 + struct device_node *np = dev->of_node; 58 + struct of_imap_parser imap_parser; 59 + struct of_imap_item imap_item; 60 + u32 __iomem *regs; 61 + int index; 62 + int ret; 63 + u32 tmp; 64 + 65 + regs = devm_platform_ioremap_resource(pdev, 0); 66 + if (IS_ERR(regs)) 67 + return PTR_ERR(regs); 68 + 69 + /* We support only #interrupt-cells = <1> and #address-cells = <0> */ 70 + ret = of_property_read_u32(np, "#interrupt-cells", &tmp); 71 + if (ret) 72 + return ret; 73 + if (tmp != 1) 74 + return -EINVAL; 75 + 76 + ret = of_property_read_u32(np, "#address-cells", &tmp); 77 + if (ret) 78 + return ret; 79 + if (tmp != 0) 80 + return -EINVAL; 81 + 82 + ret = of_imap_parser_init(&imap_parser, np, &imap_item); 83 + if (ret) 84 + return ret; 85 + 86 + for_each_of_imap_item(&imap_parser, &imap_item) { 87 + index = rzn1_irqmux_parent_args_to_line_index(dev, &imap_item.parent_args); 88 + if (index < 0) { 89 + of_node_put(imap_item.parent_args.np); 90 + return index; 91 + } 92 + 93 + if (test_and_set_bit(index, index_done)) { 94 + of_node_put(imap_item.parent_args.np); 95 + dev_err(dev, "Mux output line %d already defined in interrupt-map\n", 96 + index); 97 + return -EINVAL; 98 + } 99 + 100 + /* 101 + * The child #address-cells is 0 (already checked). The first 102 + * value in imap item is the src hwirq. 103 + */ 104 + writel(imap_item.child_imap[0], regs + index); 105 + } 106 + 107 + return 0; 108 + } 109 + 110 + static const struct of_device_id rzn1_irqmux_of_match[] = { 111 + { .compatible = "renesas,rzn1-gpioirqmux", }, 112 + { /* sentinel */ } 113 + }; 114 + MODULE_DEVICE_TABLE(of, rzn1_irqmux_of_match); 115 + 116 + static struct platform_driver rzn1_irqmux_driver = { 117 + .probe = rzn1_irqmux_probe, 118 + .driver = { 119 + .name = "rzn1_irqmux", 120 + .of_match_table = rzn1_irqmux_of_match, 121 + }, 122 + }; 123 + module_platform_driver(rzn1_irqmux_driver); 124 + 125 + MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); 126 + MODULE_DESCRIPTION("Renesas RZ/N1 GPIO IRQ Multiplexer Driver"); 127 + MODULE_LICENSE("GPL");
+40 -1
include/linux/of_irq.h
··· 11 11 12 12 typedef int (*of_irq_init_cb_t)(struct device_node *, struct device_node *); 13 13 14 + struct of_imap_parser { 15 + struct device_node *node; 16 + const __be32 *imap; 17 + const __be32 *imap_end; 18 + u32 parent_offset; 19 + }; 20 + 21 + struct of_imap_item { 22 + struct of_phandle_args parent_args; 23 + u32 child_imap_count; 24 + u32 child_imap[16]; /* Arbitrary size. 25 + * Should be #address-cells + #interrupt-cells but 26 + * avoid using allocation and so, expect that 16 27 + * should be enough 28 + */ 29 + }; 30 + 31 + /* 32 + * If the iterator is exited prematurely (break, goto, return) of_node_put() has 33 + * to be called on item.parent_args.np 34 + */ 35 + #define for_each_of_imap_item(parser, item) \ 36 + for (; of_imap_parser_one(parser, item);) 37 + 14 38 /* 15 39 * Workarounds only applied to 32bit powermac machines 16 40 */ ··· 73 49 extern int of_irq_to_resource_table(struct device_node *dev, 74 50 struct resource *res, int nr_irqs); 75 51 extern struct device_node *of_irq_find_parent(struct device_node *child); 52 + extern int of_imap_parser_init(struct of_imap_parser *parser, 53 + struct device_node *node, 54 + struct of_imap_item *item); 55 + extern struct of_imap_item *of_imap_parser_one(struct of_imap_parser *parser, 56 + struct of_imap_item *item); 76 57 extern struct irq_domain *of_msi_get_domain(struct device *dev, 77 58 const struct device_node *np, 78 59 enum irq_domain_bus_token token); ··· 121 92 { 122 93 return NULL; 123 94 } 124 - 95 + static inline int of_imap_parser_init(struct of_imap_parser *parser, 96 + struct device_node *node, 97 + struct of_imap_item *item) 98 + { 99 + return -ENOSYS; 100 + } 101 + static inline struct of_imap_item *of_imap_parser_one(struct of_imap_parser *parser, 102 + struct of_imap_item *item) 103 + { 104 + return NULL; 105 + } 125 106 static inline struct irq_domain *of_msi_get_domain(struct device *dev, 126 107 struct device_node *np, 127 108 enum irq_domain_bus_token token)