Commit e85cbe8b34147126cdd5dab09f4c745157f6083c
Committed by
Bin Meng
1 parent
025543554c
Exists in
smarc_8mq_lf_v2020.04
and in
9 other branches
x86: Add support for ACPI general-purpose events
ACPI GPEs are used to signal interrupts from peripherals that are accessed via ACPI. In U-Boot these are modelled as interrupts using a separate interrupt controller. Configuration is via the device tree. Add a simple driver for this. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Showing 4 changed files with 149 additions and 0 deletions Side-by-side Diff
arch/x86/Kconfig
... | ... | @@ -923,5 +923,38 @@ |
923 | 923 | depends on SPL && X86 |
924 | 924 | default SPL_TEXT_BASE |
925 | 925 | |
926 | +config ACPI_GPE | |
927 | + bool "Support ACPI general-purpose events" | |
928 | + help | |
929 | + Enable a driver for ACPI GPEs to allow peripherals to send interrupts | |
930 | + via ACPI to the OS. In U-Boot this is only used when U-Boot itself | |
931 | + needs access to these interrupts. This can happen when it uses a | |
932 | + peripheral that is set up to use GPEs and so cannot use the normal | |
933 | + GPIO mechanism for polling an input. | |
934 | + | |
935 | + See https://queue.acm.org/blogposting.cfm?id=18977 for more info | |
936 | + | |
937 | +config SPL_ACPI_GPE | |
938 | + bool "Support ACPI general-purpose events in SPL" | |
939 | + help | |
940 | + Enable a driver for ACPI GPEs to allow peripherals to send interrupts | |
941 | + via ACPI to the OS. In U-Boot this is only used when U-Boot itself | |
942 | + needs access to these interrupts. This can happen when it uses a | |
943 | + peripheral that is set up to use GPEs and so cannot use the normal | |
944 | + GPIO mechanism for polling an input. | |
945 | + | |
946 | + See https://queue.acm.org/blogposting.cfm?id=18977 for more info | |
947 | + | |
948 | +config TPL_ACPI_GPE | |
949 | + bool "Support ACPI general-purpose events in TPL" | |
950 | + help | |
951 | + Enable a driver for ACPI GPEs to allow peripherals to send interrupts | |
952 | + via ACPI to the OS. In U-Boot this is only used when U-Boot itself | |
953 | + needs access to these interrupts. This can happen when it uses a | |
954 | + peripheral that is set up to use GPEs and so cannot use the normal | |
955 | + GPIO mechanism for polling an input. | |
956 | + | |
957 | + See https://queue.acm.org/blogposting.cfm?id=18977 for more info | |
958 | + | |
926 | 959 | endmenu |
arch/x86/cpu/Makefile
... | ... | @@ -55,6 +55,7 @@ |
55 | 55 | obj-$(CONFIG_INTEL_TANGIER) += tangier/ |
56 | 56 | obj-$(CONFIG_APIC) += lapic.o ioapic.o |
57 | 57 | obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += irq.o |
58 | +obj-$(CONFIG_$(SPL_TPL_)ACPI_GPE) += acpi_gpe.o | |
58 | 59 | obj-$(CONFIG_QFW) += qfw_cpu.o |
59 | 60 | ifndef CONFIG_$(SPL_)X86_64 |
60 | 61 | obj-$(CONFIG_SMP) += mp_init.o |
arch/x86/cpu/acpi_gpe.c
1 | +// SPDX-License-Identifier: GPL-2.0+ | |
2 | +/* | |
3 | + * Copyright 2019 Google, LLC | |
4 | + * Written by Simon Glass <sjg@chromium.org> | |
5 | + */ | |
6 | + | |
7 | +#include <common.h> | |
8 | +#include <dm.h> | |
9 | +#include <irq.h> | |
10 | +#include <asm/io.h> | |
11 | + | |
12 | +/** | |
13 | + * struct acpi_gpe_priv - private driver information | |
14 | + * | |
15 | + * @acpi_base: Base I/O address of ACPI registers | |
16 | + */ | |
17 | +struct acpi_gpe_priv { | |
18 | + ulong acpi_base; | |
19 | +}; | |
20 | + | |
21 | +#define GPE0_STS(x) (0x20 + ((x) * 4)) | |
22 | + | |
23 | +static int acpi_gpe_read_and_clear(struct irq *irq) | |
24 | +{ | |
25 | + struct acpi_gpe_priv *priv = dev_get_priv(irq->dev); | |
26 | + u32 mask, sts; | |
27 | + ulong start; | |
28 | + int ret = 0; | |
29 | + int bank; | |
30 | + | |
31 | + bank = irq->id / 32; | |
32 | + mask = 1 << (irq->id % 32); | |
33 | + | |
34 | + /* Wait up to 1ms for GPE status to clear */ | |
35 | + start = get_timer(0); | |
36 | + do { | |
37 | + if (get_timer(start) > 1) | |
38 | + return ret; | |
39 | + | |
40 | + sts = inl(priv->acpi_base + GPE0_STS(bank)); | |
41 | + if (sts & mask) { | |
42 | + outl(mask, priv->acpi_base + GPE0_STS(bank)); | |
43 | + ret = 1; | |
44 | + } | |
45 | + } while (sts & mask); | |
46 | + | |
47 | + return ret; | |
48 | +} | |
49 | + | |
50 | +static int acpi_gpe_ofdata_to_platdata(struct udevice *dev) | |
51 | +{ | |
52 | + struct acpi_gpe_priv *priv = dev_get_priv(dev); | |
53 | + | |
54 | + priv->acpi_base = dev_read_addr(dev); | |
55 | + if (!priv->acpi_base || priv->acpi_base == FDT_ADDR_T_NONE) | |
56 | + return log_msg_ret("acpi_base", -EINVAL); | |
57 | + | |
58 | + return 0; | |
59 | +} | |
60 | + | |
61 | +static int acpi_gpe_of_xlate(struct irq *irq, struct ofnode_phandle_args *args) | |
62 | +{ | |
63 | + irq->id = args->args[0]; | |
64 | + | |
65 | + return 0; | |
66 | +} | |
67 | + | |
68 | +static const struct irq_ops acpi_gpe_ops = { | |
69 | + .read_and_clear = acpi_gpe_read_and_clear, | |
70 | + .of_xlate = acpi_gpe_of_xlate, | |
71 | +}; | |
72 | + | |
73 | +static const struct udevice_id acpi_gpe_ids[] = { | |
74 | + { .compatible = "intel,acpi-gpe", .data = X86_IRQT_ACPI_GPE }, | |
75 | + { } | |
76 | +}; | |
77 | + | |
78 | +U_BOOT_DRIVER(acpi_gpe_drv) = { | |
79 | + .name = "acpi_gpe", | |
80 | + .id = UCLASS_IRQ, | |
81 | + .of_match = acpi_gpe_ids, | |
82 | + .ops = &acpi_gpe_ops, | |
83 | + .ofdata_to_platdata = acpi_gpe_ofdata_to_platdata, | |
84 | + .priv_auto_alloc_size = sizeof(struct acpi_gpe_priv), | |
85 | +}; |
doc/device-tree-bindings/interrupt-controller/intel,acpi-gpe.txt
1 | +* Intel Advanced Configuration and Power Interface General Purpose Events | |
2 | + | |
3 | +This describes an interrupt controller which provides access to GPEs supported | |
4 | +by the SoC. | |
5 | + | |
6 | +Required properties: | |
7 | + | |
8 | +- compatible : "intel,acpi-gpe" | |
9 | +- interrupt-controller : Identifies the node as an interrupt controller | |
10 | +- #interrupt-cells : The number of cells to define the interrupts. Must be 2: | |
11 | + cell 0: interrupt number (normally >=32 since GPEs below that are reserved) | |
12 | + cell 1: 0 (flags, but none are currently defined) | |
13 | +- reg : The register bank for the controller (set this to the ACPI base). | |
14 | + | |
15 | +Example: | |
16 | + | |
17 | + general-purpose-events { | |
18 | + reg = <IOMAP_ACPI_BASE IOMAP_ACPI_SIZE>; | |
19 | + compatible = "intel,acpi-gpe"; | |
20 | + interrupt-controller; | |
21 | + #interrupt-cells = <2>; | |
22 | + }; | |
23 | + | |
24 | + ... | |
25 | + tpm@50 { | |
26 | + reg = <0x50>; | |
27 | + compatible = "google,cr50"; | |
28 | + ready-gpio = <&gpio_n 0x1c GPIO_ACTIVE_LOW>; | |
29 | + interrupts-extended = <&acpi_gpe 0x3c 0>; | |
30 | + }; |