xref: /openbsd-src/sys/dev/acpi/com_acpi.c (revision 5e3c7963eb248119b7dfd4b0defad58a7d9cd306)
1 /*	$OpenBSD: com_acpi.c,v 1.1 2018/07/01 10:29:30 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2018 Mark Kettenis
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/malloc.h>
20 #include <sys/systm.h>
21 #include <sys/tty.h>
22 
23 #include <dev/acpi/acpireg.h>
24 #include <dev/acpi/acpivar.h>
25 #include <dev/acpi/acpidev.h>
26 #include <dev/acpi/amltypes.h>
27 #include <dev/acpi/dsdt.h>
28 
29 #undef DEVNAME
30 #include <dev/ic/comreg.h>
31 #include <dev/ic/comvar.h>
32 #include <dev/cons.h>
33 
34 #define com_usr 31	/* Synopsys DesignWare UART */
35 
36 struct com_acpi_softc {
37 	struct com_softc sc;
38 	struct acpi_softc *sc_acpi;
39 	struct aml_node *sc_node;
40 
41 	bus_addr_t sc_addr;
42 	bus_size_t sc_size;
43 
44 	int sc_irq;
45 	int sc_irq_flags;
46 	void *sc_ih;
47 };
48 
49 int	com_acpi_match(struct device *, void *, void *);
50 void	com_acpi_attach(struct device *, struct device *, void *);
51 
52 struct cfattach com_acpi_ca = {
53 	sizeof(struct com_acpi_softc), com_acpi_match, com_acpi_attach
54 };
55 
56 const char *com_hids[] = {
57 	"HISI0031",
58 	NULL
59 };
60 
61 int	com_acpi_parse_resources(int, union acpi_resource *, void *);
62 int	com_acpi_is_console(struct com_acpi_softc *);
63 int	com_acpi_intr_designware(void *);
64 
65 int
66 com_acpi_match(struct device *parent, void *match, void *aux)
67 {
68 	struct acpi_attach_args *aaa = aux;
69 	struct cfdata *cf = match;
70 
71 	return acpi_matchhids(aaa, com_hids, cf->cf_driver->cd_name);
72 }
73 
74 void
75 com_acpi_attach(struct device *parent, struct device *self, void *aux)
76 {
77 	struct acpi_attach_args *aaa = aux;
78 	struct com_acpi_softc *sc = (struct com_acpi_softc *)self;
79 	struct aml_value res;
80 	uint32_t freq;
81 
82 	sc->sc_acpi = (struct acpi_softc *)parent;
83 	sc->sc_node = aaa->aaa_node;
84 	printf(" %s", sc->sc_node->name);
85 
86 	if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) {
87 		printf(": can't find registers\n");
88 		return;
89 	}
90 
91 	aml_parse_resource(&res, com_acpi_parse_resources, sc);
92 	printf(" addr 0x%lx/0x%lx", sc->sc_addr, sc->sc_size);
93 	if (sc->sc_addr == 0 || sc->sc_size == 0) {
94 		printf("\n");
95 		return;
96 	}
97 
98 	printf(" irq %d", sc->sc_irq);
99 
100 	freq = acpi_getpropint(sc->sc_node, "clock-frequency", 0);
101 
102 	sc->sc.sc_iot = aaa->aaa_memt;
103 	sc->sc.sc_iobase = sc->sc_addr;
104 	sc->sc.sc_uarttype = COM_UART_16550;
105 	sc->sc.sc_frequency = freq ? freq : COM_FREQ;
106 
107 	sc->sc.sc_reg_width = acpi_getpropint(sc->sc_node, "reg-io-width", 4);
108 	sc->sc.sc_reg_shift = acpi_getpropint(sc->sc_node, "reg-shift", 2);
109 
110 	if (com_acpi_is_console(sc)) {
111 		SET(sc->sc.sc_hwflags, COM_HW_CONSOLE);
112 		SET(sc->sc.sc_swflags, COM_SW_SOFTCAR);
113 		comconsfreq = sc->sc.sc_frequency;
114 		comconsrate = B115200;
115 	}
116 
117 	if (bus_space_map(sc->sc.sc_iot, sc->sc_addr, sc->sc_size, 0,
118 	    &sc->sc.sc_ioh)) {
119 		printf(": can't map registers\n");
120 		return;
121 	}
122 
123 	sc->sc_ih = acpi_intr_establish(sc->sc_irq, sc->sc_irq_flags, IPL_TTY,
124 	    com_acpi_intr_designware, sc, sc->sc.sc_dev.dv_xname);
125 	if (sc->sc_ih == NULL) {
126 		printf(": can't establish interrupt\n");
127 		return;
128 	}
129 
130 	com_attach_subr(&sc->sc);
131 }
132 
133 int
134 com_acpi_parse_resources(int crsidx, union acpi_resource *crs, void *arg)
135 {
136 	struct com_acpi_softc *sc = arg;
137 	int type = AML_CRSTYPE(crs);
138 
139 	switch (type) {
140 	case LR_MEM32FIXED:
141 		sc->sc_addr = crs->lr_m32fixed._bas;
142 		sc->sc_size = crs->lr_m32fixed._len;
143 		break;
144 	case LR_EXTIRQ:
145 		sc->sc_irq = crs->lr_extirq.irq[0];
146 		sc->sc_irq_flags = crs->lr_extirq.flags;
147 		break;
148 	}
149 
150 	return 0;
151 }
152 
153 int
154 com_acpi_is_console(struct com_acpi_softc *sc)
155 {
156 	struct acpi_table_header *hdr;
157 	struct acpi_spcr *spcr;
158 	struct acpi_gas *base;
159 	struct acpi_q *entry;
160 
161 	SIMPLEQ_FOREACH(entry, &sc->sc_acpi->sc_tables, q_next) {
162 		hdr = entry->q_table;
163 		if (strncmp(hdr->signature, SPCR_SIG,
164 		    sizeof(hdr->signature)) == 0) {
165 			spcr = entry->q_table;
166 			base = &spcr->base_address;
167 			if (base->address_space_id == GAS_SYSTEM_MEMORY &&
168 			    base->address == sc->sc_addr)
169 				return 1;
170 		}
171 	}
172 
173 	return 0;
174 }
175 
176 int
177 com_acpi_intr_designware(void *cookie)
178 {
179 	struct com_softc *sc = cookie;
180 
181 	com_read_reg(sc, com_usr);
182 
183 	return comintr(sc);
184 }
185