blob: 70badb15a3beff0b3914de39df00c9ec7c5b40c8 [file] [log] [blame]
Simon Glasse85cbe82020-02-06 09:55:01 -07001// 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>
Simon Glassf7ae49f2020-05-10 11:40:05 -060010#include <log.h>
Simon Glassa8c27892020-07-07 21:32:34 -060011#include <acpi/acpi_device.h>
Simon Glasse85cbe82020-02-06 09:55:01 -070012#include <asm/io.h>
Simon Glassa8c27892020-07-07 21:32:34 -060013#include <dt-bindings/interrupt-controller/irq.h>
14#include <dt-bindings/interrupt-controller/x86-irq.h>
Simon Glasse85cbe82020-02-06 09:55:01 -070015
16/**
17 * struct acpi_gpe_priv - private driver information
18 *
19 * @acpi_base: Base I/O address of ACPI registers
20 */
21struct acpi_gpe_priv {
22 ulong acpi_base;
23};
24
25#define GPE0_STS(x) (0x20 + ((x) * 4))
26
27static int acpi_gpe_read_and_clear(struct irq *irq)
28{
29 struct acpi_gpe_priv *priv = dev_get_priv(irq->dev);
30 u32 mask, sts;
31 ulong start;
32 int ret = 0;
33 int bank;
34
35 bank = irq->id / 32;
36 mask = 1 << (irq->id % 32);
37
38 /* Wait up to 1ms for GPE status to clear */
39 start = get_timer(0);
40 do {
41 if (get_timer(start) > 1)
42 return ret;
43
44 sts = inl(priv->acpi_base + GPE0_STS(bank));
45 if (sts & mask) {
46 outl(mask, priv->acpi_base + GPE0_STS(bank));
47 ret = 1;
48 }
49 } while (sts & mask);
50
51 return ret;
52}
53
54static int acpi_gpe_ofdata_to_platdata(struct udevice *dev)
55{
56 struct acpi_gpe_priv *priv = dev_get_priv(dev);
57
58 priv->acpi_base = dev_read_addr(dev);
59 if (!priv->acpi_base || priv->acpi_base == FDT_ADDR_T_NONE)
60 return log_msg_ret("acpi_base", -EINVAL);
61
62 return 0;
63}
64
65static int acpi_gpe_of_xlate(struct irq *irq, struct ofnode_phandle_args *args)
66{
67 irq->id = args->args[0];
Simon Glassa8c27892020-07-07 21:32:34 -060068 irq->flags = args->args[1];
Simon Glasse85cbe82020-02-06 09:55:01 -070069
70 return 0;
71}
72
Simon Glassa8c27892020-07-07 21:32:34 -060073#if CONFIG_IS_ENABLED(ACPIGEN)
74static int acpi_gpe_get_acpi(const struct irq *irq, struct acpi_irq *acpi_irq)
75{
76 memset(acpi_irq, '\0', sizeof(*acpi_irq));
77 acpi_irq->pin = irq->id;
78 acpi_irq->mode = irq->flags & IRQ_TYPE_EDGE_BOTH ?
79 ACPI_IRQ_EDGE_TRIGGERED : ACPI_IRQ_LEVEL_TRIGGERED;
80 acpi_irq->polarity = irq->flags &
81 (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW) ?
82 ACPI_IRQ_ACTIVE_LOW : ACPI_IRQ_ACTIVE_HIGH;
83 acpi_irq->shared = irq->flags & X86_IRQ_TYPE_SHARED ?
84 ACPI_IRQ_SHARED : ACPI_IRQ_EXCLUSIVE;
85 acpi_irq->wake = irq->flags & X86_IRQ_TYPE_WAKE ? ACPI_IRQ_WAKE :
86 ACPI_IRQ_NO_WAKE;
87
88 return 0;
89}
90#endif
91
Simon Glasse85cbe82020-02-06 09:55:01 -070092static const struct irq_ops acpi_gpe_ops = {
93 .read_and_clear = acpi_gpe_read_and_clear,
94 .of_xlate = acpi_gpe_of_xlate,
Simon Glassa8c27892020-07-07 21:32:34 -060095#if CONFIG_IS_ENABLED(ACPIGEN)
96 .get_acpi = acpi_gpe_get_acpi,
97#endif
Simon Glasse85cbe82020-02-06 09:55:01 -070098};
99
100static const struct udevice_id acpi_gpe_ids[] = {
101 { .compatible = "intel,acpi-gpe", .data = X86_IRQT_ACPI_GPE },
102 { }
103};
104
105U_BOOT_DRIVER(acpi_gpe_drv) = {
106 .name = "acpi_gpe",
107 .id = UCLASS_IRQ,
108 .of_match = acpi_gpe_ids,
109 .ops = &acpi_gpe_ops,
110 .ofdata_to_platdata = acpi_gpe_ofdata_to_platdata,
111 .priv_auto_alloc_size = sizeof(struct acpi_gpe_priv),
112};