Commit 025543554c36615a66d66c154f3f763ac788ee15

Authored by Simon Glass
Committed by Bin Meng
1 parent d9a5fad808

dm: irq: Add support for requesting interrupts

At present driver model supports the IRQ uclass but there is no way to
request a particular interrupt for a driver.

Add a mechanism, similar to clock and reset, to read the interrupts
required by a device from the device tree and to request those interrupts.

U-Boot itself does not have interrupt-driven handlers, so just provide a
means to read and clear an interrupt. This can be useful to handle
peripherals which must use an interrupt to determine when data is
available, for example.

Bring over the basic binding file as well, from Linux v5.4. Note that the
older binding is not supported in U-Boot; the newer 'special form' must be
used.

Add a simple test of the new functionality.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>

Showing 6 changed files with 439 additions and 1 deletions Side-by-side Diff

arch/sandbox/dts/test.dts
... ... @@ -93,6 +93,7 @@
93 93 <&gpio_b 9 0xc 3 2 1>;
94 94 int-value = <1234>;
95 95 uint-value = <(-1234)>;
  96 + interrupts-extended = <&irq 3 0>;
96 97 };
97 98  
98 99 junk {
99 100  
... ... @@ -357,8 +358,10 @@
357 358 vss-microvolts = <0>;
358 359 };
359 360  
360   - irq {
  361 + irq: irq {
361 362 compatible = "sandbox,irq";
  363 + interrupt-controller;
  364 + #interrupt-cells = <2>;
362 365 };
363 366  
364 367 lcd {
doc/device-tree-bindings/interrupt-controller/interrupts.txt
  1 +Specifying interrupt information for devices
  2 +============================================
  3 +
  4 +1) Interrupt client nodes
  5 +-------------------------
  6 +
  7 +Nodes that describe devices which generate interrupts must contain an
  8 +"interrupts" property, an "interrupts-extended" property, or both. If both are
  9 +present, the latter should take precedence; the former may be provided simply
  10 +for compatibility with software that does not recognize the latter. These
  11 +properties contain a list of interrupt specifiers, one per output interrupt. The
  12 +format of the interrupt specifier is determined by the interrupt controller to
  13 +which the interrupts are routed; see section 2 below for details.
  14 +
  15 + Example:
  16 + interrupt-parent = <&intc1>;
  17 + interrupts = <5 0>, <6 0>;
  18 +
  19 +The "interrupt-parent" property is used to specify the controller to which
  20 +interrupts are routed and contains a single phandle referring to the interrupt
  21 +controller node. This property is inherited, so it may be specified in an
  22 +interrupt client node or in any of its parent nodes. Interrupts listed in the
  23 +"interrupts" property are always in reference to the node's interrupt parent.
  24 +
  25 +The "interrupts-extended" property is a special form; useful when a node needs
  26 +to reference multiple interrupt parents or a different interrupt parent than
  27 +the inherited one. Each entry in this property contains both the parent phandle
  28 +and the interrupt specifier.
  29 +
  30 + Example:
  31 + interrupts-extended = <&intc1 5 1>, <&intc2 1 0>;
  32 +
  33 +(NOTE: only this 'special form' is supported in U-Boot)
  34 +
  35 +
  36 +2) Interrupt controller nodes
  37 +-----------------------------
  38 +
  39 +A device is marked as an interrupt controller with the "interrupt-controller"
  40 +property. This is a empty, boolean property. An additional "#interrupt-cells"
  41 +property defines the number of cells needed to specify a single interrupt.
  42 +
  43 +It is the responsibility of the interrupt controller's binding to define the
  44 +length and format of the interrupt specifier. The following two variants are
  45 +commonly used:
  46 +
  47 + a) one cell
  48 + -----------
  49 + The #interrupt-cells property is set to 1 and the single cell defines the
  50 + index of the interrupt within the controller.
  51 +
  52 + Example:
  53 +
  54 + vic: intc@10140000 {
  55 + compatible = "arm,versatile-vic";
  56 + interrupt-controller;
  57 + #interrupt-cells = <1>;
  58 + reg = <0x10140000 0x1000>;
  59 + };
  60 +
  61 + sic: intc@10003000 {
  62 + compatible = "arm,versatile-sic";
  63 + interrupt-controller;
  64 + #interrupt-cells = <1>;
  65 + reg = <0x10003000 0x1000>;
  66 + interrupt-parent = <&vic>;
  67 + interrupts = <31>; /* Cascaded to vic */
  68 + };
  69 +
  70 + b) two cells
  71 + ------------
  72 + The #interrupt-cells property is set to 2 and the first cell defines the
  73 + index of the interrupt within the controller, while the second cell is used
  74 + to specify any of the following flags:
  75 + - bits[3:0] trigger type and level flags
  76 + 1 = low-to-high edge triggered
  77 + 2 = high-to-low edge triggered
  78 + 4 = active high level-sensitive
  79 + 8 = active low level-sensitive
  80 +
  81 + Example:
  82 +
  83 + i2c@7000c000 {
  84 + gpioext: gpio-adnp@41 {
  85 + compatible = "ad,gpio-adnp";
  86 + reg = <0x41>;
  87 +
  88 + interrupt-parent = <&gpio>;
  89 + interrupts = <160 1>;
  90 +
  91 + gpio-controller;
  92 + #gpio-cells = <1>;
  93 +
  94 + interrupt-controller;
  95 + #interrupt-cells = <2>;
  96 +
  97 + nr-gpios = <64>;
  98 + };
  99 +
  100 + sx8634@2b {
  101 + compatible = "smtc,sx8634";
  102 + reg = <0x2b>;
  103 +
  104 + interrupt-parent = <&gpioext>;
  105 + interrupts = <3 0x8>;
  106 +
  107 + #address-cells = <1>;
  108 + #size-cells = <0>;
  109 +
  110 + threshold = <0x40>;
  111 + sensitivity = <7>;
  112 + };
  113 + };
  114 +
  115 +
  116 +Example of special form (supported by U-Boot):
  117 +
  118 + acpi_gpe: general-purpose-events {
  119 + reg = <IOMAP_ACPI_BASE IOMAP_ACPI_SIZE>;
  120 + compatible = "intel,acpi-gpe";
  121 + interrupt-controller;
  122 + #interrupt-cells = <2>;
  123 + };
  124 +
  125 + tpm@50 {
  126 + reg = <0x50>;
  127 + compatible = "google,cr50";
  128 + u-boot,i2c-offset-len = <0>;
  129 + ready-gpio = <&gpio_n 28 GPIO_ACTIVE_LOW>;
  130 + interrupts-extended = <&acpi_gpe 0x3c 0>;
  131 + };
drivers/misc/irq-uclass.c
... ... @@ -4,8 +4,11 @@
4 4 * Written by Simon Glass <sjg@chromium.org>
5 5 */
6 6  
  7 +#define LOG_CATEGORY UCLASS_IRQ
  8 +
7 9 #include <common.h>
8 10 #include <dm.h>
  11 +#include <dt-structs.h>
9 12 #include <irq.h>
10 13 #include <dm/device-internal.h>
11 14  
... ... @@ -47,6 +50,119 @@
47 50 return -ENOSYS;
48 51  
49 52 return ops->restore_polarities(dev);
  53 +}
  54 +
  55 +int irq_read_and_clear(struct irq *irq)
  56 +{
  57 + const struct irq_ops *ops = irq_get_ops(irq->dev);
  58 +
  59 + if (!ops->read_and_clear)
  60 + return -ENOSYS;
  61 +
  62 + return ops->read_and_clear(irq);
  63 +}
  64 +
  65 +#if CONFIG_IS_ENABLED(OF_PLATDATA)
  66 +int irq_get_by_index_platdata(struct udevice *dev, int index,
  67 + struct phandle_1_arg *cells, struct irq *irq)
  68 +{
  69 + int ret;
  70 +
  71 + if (index != 0)
  72 + return -ENOSYS;
  73 + ret = uclass_get_device(UCLASS_IRQ, 0, &irq->dev);
  74 + if (ret)
  75 + return ret;
  76 + irq->id = cells[0].arg[0];
  77 +
  78 + return 0;
  79 +}
  80 +#else
  81 +static int irq_of_xlate_default(struct irq *irq,
  82 + struct ofnode_phandle_args *args)
  83 +{
  84 + log_debug("(irq=%p)\n", irq);
  85 +
  86 + if (args->args_count > 1) {
  87 + log_debug("Invaild args_count: %d\n", args->args_count);
  88 + return -EINVAL;
  89 + }
  90 +
  91 + if (args->args_count)
  92 + irq->id = args->args[0];
  93 + else
  94 + irq->id = 0;
  95 +
  96 + return 0;
  97 +}
  98 +
  99 +static int irq_get_by_index_tail(int ret, ofnode node,
  100 + struct ofnode_phandle_args *args,
  101 + const char *list_name, int index,
  102 + struct irq *irq)
  103 +{
  104 + struct udevice *dev_irq;
  105 + const struct irq_ops *ops;
  106 +
  107 + assert(irq);
  108 + irq->dev = NULL;
  109 + if (ret)
  110 + goto err;
  111 +
  112 + ret = uclass_get_device_by_ofnode(UCLASS_IRQ, args->node, &dev_irq);
  113 + if (ret) {
  114 + log_debug("uclass_get_device_by_ofnode failed: err=%d\n", ret);
  115 + return ret;
  116 + }
  117 +
  118 + irq->dev = dev_irq;
  119 +
  120 + ops = irq_get_ops(dev_irq);
  121 +
  122 + if (ops->of_xlate)
  123 + ret = ops->of_xlate(irq, args);
  124 + else
  125 + ret = irq_of_xlate_default(irq, args);
  126 + if (ret) {
  127 + log_debug("of_xlate() failed: %d\n", ret);
  128 + return ret;
  129 + }
  130 +
  131 + return irq_request(dev_irq, irq);
  132 +err:
  133 + log_debug("Node '%s', property '%s', failed to request IRQ index %d: %d\n",
  134 + ofnode_get_name(node), list_name, index, ret);
  135 + return ret;
  136 +}
  137 +
  138 +int irq_get_by_index(struct udevice *dev, int index, struct irq *irq)
  139 +{
  140 + struct ofnode_phandle_args args;
  141 + int ret;
  142 +
  143 + ret = dev_read_phandle_with_args(dev, "interrupts-extended",
  144 + "#interrupt-cells", 0, index, &args);
  145 +
  146 + return irq_get_by_index_tail(ret, dev_ofnode(dev), &args,
  147 + "interrupts-extended", index > 0, irq);
  148 +}
  149 +#endif /* OF_PLATDATA */
  150 +
  151 +int irq_request(struct udevice *dev, struct irq *irq)
  152 +{
  153 + const struct irq_ops *ops;
  154 +
  155 + log_debug("(dev=%p, irq=%p)\n", dev, irq);
  156 + if (!irq)
  157 + return 0;
  158 + ops = irq_get_ops(dev);
  159 +
  160 + irq->dev = dev;
  161 +
  162 + if (!ops->request)
  163 + return 0;
  164 +
  165 + return ops->request(irq);
50 166 }
51 167  
52 168 int irq_first_device_type(enum irq_dev_t type, struct udevice **devp)
drivers/misc/irq_sandbox.c
... ... @@ -8,7 +8,19 @@
8 8 #include <common.h>
9 9 #include <dm.h>
10 10 #include <irq.h>
  11 +#include <asm/test.h>
11 12  
  13 +/**
  14 + * struct sandbox_irq_priv - private data for this driver
  15 + *
  16 + * @count: Counts the number calls to the read_and_clear() method
  17 + * @pending: true if an interrupt is pending, else false
  18 + */
  19 +struct sandbox_irq_priv {
  20 + int count;
  21 + bool pending;
  22 +};
  23 +
12 24 static int sandbox_set_polarity(struct udevice *dev, uint irq, bool active_low)
13 25 {
14 26 if (irq > 10)
15 27  
... ... @@ -35,11 +47,39 @@
35 47 return 0;
36 48 }
37 49  
  50 +static int sandbox_irq_read_and_clear(struct irq *irq)
  51 +{
  52 + struct sandbox_irq_priv *priv = dev_get_priv(irq->dev);
  53 +
  54 + if (irq->id != SANDBOX_IRQN_PEND)
  55 + return -EINVAL;
  56 + priv->count++;
  57 + if (priv->pending) {
  58 + priv->pending = false;
  59 + return 1;
  60 + }
  61 +
  62 + if (!(priv->count % 3))
  63 + priv->pending = true;
  64 +
  65 + return 0;
  66 +}
  67 +
  68 +static int sandbox_irq_of_xlate(struct irq *irq,
  69 + struct ofnode_phandle_args *args)
  70 +{
  71 + irq->id = args->args[0];
  72 +
  73 + return 0;
  74 +}
  75 +
38 76 static const struct irq_ops sandbox_irq_ops = {
39 77 .route_pmc_gpio_gpe = sandbox_route_pmc_gpio_gpe,
40 78 .set_polarity = sandbox_set_polarity,
41 79 .snapshot_polarities = sandbox_snapshot_polarities,
42 80 .restore_polarities = sandbox_restore_polarities,
  81 + .read_and_clear = sandbox_irq_read_and_clear,
  82 + .of_xlate = sandbox_irq_of_xlate,
43 83 };
44 84  
45 85 static const struct udevice_id sandbox_irq_ids[] = {
... ... @@ -52,5 +92,6 @@
52 92 .id = UCLASS_IRQ,
53 93 .of_match = sandbox_irq_ids,
54 94 .ops = &sandbox_irq_ops,
  95 + .priv_auto_alloc_size = sizeof(struct sandbox_irq_priv),
55 96 };
... ... @@ -20,7 +20,20 @@
20 20 };
21 21  
22 22 /**
  23 + * struct irq - A single irq line handled by an interrupt controller
  24 + *
  25 + * @dev: IRQ device that handles this irq
  26 + * @id: ID to identify this irq with the device
  27 + */
  28 +struct irq {
  29 + struct udevice *dev;
  30 + ulong id;
  31 +};
  32 +
  33 +/**
23 34 * struct irq_ops - Operations for the IRQ
  35 + *
  36 + * Each IRQ device can handle mulitple IRQ lines
24 37 */
25 38 struct irq_ops {
26 39 /**
... ... @@ -57,6 +70,55 @@
57 70 * @return 0
58 71 */
59 72 int (*restore_polarities)(struct udevice *dev);
  73 +
  74 + /**
  75 + * read_and_clear() - get the value of an interrupt and clear it
  76 + *
  77 + * Clears the interrupt if pending
  78 + *
  79 + * @irq: IRQ line
  80 + * @return 0 if interrupt is not pending, 1 if it was (and so has been
  81 + * cleared), -ve on error
  82 + */
  83 + int (*read_and_clear)(struct irq *irq);
  84 + /**
  85 + * of_xlate - Translate a client's device-tree (OF) irq specifier.
  86 + *
  87 + * The irq core calls this function as the first step in implementing
  88 + * a client's irq_get_by_*() call.
  89 + *
  90 + * If this function pointer is set to NULL, the irq core will use a
  91 + * default implementation, which assumes #interrupt-cells = <1>, and
  92 + * that the DT cell contains a simple integer irq ID.
  93 + *
  94 + * @irq: The irq struct to hold the translation result.
  95 + * @args: The irq specifier values from device tree.
  96 + * @return 0 if OK, or a negative error code.
  97 + */
  98 + int (*of_xlate)(struct irq *irq, struct ofnode_phandle_args *args);
  99 + /**
  100 + * request - Request a translated irq.
  101 + *
  102 + * The irq core calls this function as the second step in
  103 + * implementing a client's irq_get_by_*() call, following a successful
  104 + * xxx_xlate() call, or as the only step in implementing a client's
  105 + * irq_request() call.
  106 + *
  107 + * @irq: The irq struct to request; this has been fille in by
  108 + * a previoux xxx_xlate() function call, or by the caller
  109 + * of irq_request().
  110 + * @return 0 if OK, or a negative error code.
  111 + */
  112 + int (*request)(struct irq *irq);
  113 + /**
  114 + * free - Free a previously requested irq.
  115 + *
  116 + * This is the implementation of the client irq_free() API.
  117 + *
  118 + * @irq: The irq to free.
  119 + * @return 0 if OK, or a negative error code.
  120 + */
  121 + int (*free)(struct irq *irq);
60 122 };
61 123  
62 124 #define irq_get_ops(dev) ((struct irq_ops *)(dev)->driver->ops)
... ... @@ -95,6 +157,59 @@
95 157 * @return 0
96 158 */
97 159 int irq_restore_polarities(struct udevice *dev);
  160 +
  161 +/**
  162 + * read_and_clear() - get the value of an interrupt and clear it
  163 + *
  164 + * Clears the interrupt if pending
  165 + *
  166 + * @dev: IRQ device
  167 + * @return 0 if interrupt is not pending, 1 if it was (and so has been
  168 + * cleared), -ve on error
  169 + */
  170 +int irq_read_and_clear(struct irq *irq);
  171 +
  172 +/**
  173 + * irq_get_by_index - Get/request an irq by integer index.
  174 + *
  175 + * This looks up and requests an irq. The index is relative to the client
  176 + * device; each device is assumed to have n irqs associated with it somehow,
  177 + * and this function finds and requests one of them. The mapping of client
  178 + * device irq indices to provider irqs may be via device-tree
  179 + * properties, board-provided mapping tables, or some other mechanism.
  180 + *
  181 + * @dev: The client device.
  182 + * @index: The index of the irq to request, within the client's list of
  183 + * irqs.
  184 + * @irq: A pointer to a irq struct to initialise.
  185 + * @return 0 if OK, or a negative error code.
  186 + */
  187 +int irq_get_by_index(struct udevice *dev, int index, struct irq *irq);
  188 +
  189 +/**
  190 + * irq_request - Request a irq by provider-specific ID.
  191 + *
  192 + * This requests a irq using a provider-specific ID. Generally, this function
  193 + * should not be used, since irq_get_by_index/name() provide an interface that
  194 + * better separates clients from intimate knowledge of irq providers.
  195 + * However, this function may be useful in core SoC-specific code.
  196 + *
  197 + * @dev: The irq provider device.
  198 + * @irq: A pointer to a irq struct to initialise. The caller must
  199 + * have already initialised any field in this struct which the
  200 + * irq provider uses to identify the irq.
  201 + * @return 0 if OK, or a negative error code.
  202 + */
  203 +int irq_request(struct udevice *dev, struct irq *irq);
  204 +
  205 +/**
  206 + * irq_free - Free a previously requested irq.
  207 + *
  208 + * @irq: A irq struct that was previously successfully requested by
  209 + * irq_request/get_by_*().
  210 + * @return 0 if OK, or a negative error code.
  211 + */
  212 +int irq_free(struct irq *irq);
98 213  
99 214 /**
100 215 * irq_first_device_type() - Get a particular interrupt controller
... ... @@ -43,4 +43,36 @@
43 43 return 0;
44 44 }
45 45 DM_TEST(dm_test_irq_type, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  46 +
  47 +/* Test of irq_read_and_clear() */
  48 +static int dm_test_read_and_clear(struct unit_test_state *uts)
  49 +{
  50 + struct irq irq;
  51 +
  52 + ut_assertok(irq_first_device_type(SANDBOX_IRQT_BASE, &irq.dev));
  53 + irq.id = SANDBOX_IRQN_PEND;
  54 + ut_asserteq(0, irq_read_and_clear(&irq));
  55 + ut_asserteq(0, irq_read_and_clear(&irq));
  56 + ut_asserteq(0, irq_read_and_clear(&irq));
  57 + ut_asserteq(1, irq_read_and_clear(&irq));
  58 + ut_asserteq(0, irq_read_and_clear(&irq));
  59 +
  60 + return 0;
  61 +}
  62 +DM_TEST(dm_test_read_and_clear, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  63 +
  64 +/* Test of irq_request() */
  65 +static int dm_test_request(struct unit_test_state *uts)
  66 +{
  67 + struct udevice *dev;
  68 + struct irq irq;
  69 +
  70 + ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev));
  71 + ut_asserteq_str("a-test", dev->name);
  72 + ut_assertok(irq_get_by_index(dev, 0, &irq));
  73 + ut_asserteq(3, irq.id);
  74 +
  75 + return 0;
  76 +}
  77 +DM_TEST(dm_test_request, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);