1/*	$OpenBSD: acpi_machdep.c,v 1.22 2024/05/22 05:51:49 jsg 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/device.h>
20#include <sys/malloc.h>
21#include <sys/systm.h>
22
23#include <uvm/uvm_extern.h>
24
25#include <machine/apmvar.h>
26#include <machine/bus.h>
27#include <machine/fdt.h>
28
29#include <dev/ofw/openfirm.h>
30#include <dev/ofw/fdt.h>
31
32#include <dev/acpi/acpivar.h>
33#include <dev/acpi/dsdt.h>
34
35#include <arm64/dev/acpiiort.h>
36
37#include "apm.h"
38
39int	pwr_action = 1;
40
41int	acpi_fdt_match(struct device *, void *, void *);
42void	acpi_fdt_attach(struct device *, struct device *, void *);
43
44const struct cfattach acpi_fdt_ca = {
45	sizeof(struct acpi_softc), acpi_fdt_match, acpi_fdt_attach
46};
47
48int
49acpi_fdt_match(struct device *parent, void *match, void *aux)
50{
51	struct fdt_attach_args *faa = aux;
52
53	return OF_is_compatible(faa->fa_node, "openbsd,acpi-5.0");
54}
55
56void
57acpi_fdt_attach(struct device *parent, struct device *self, void *aux)
58{
59	struct acpi_softc *sc = (struct acpi_softc *)self;
60	struct fdt_attach_args *faa = aux;
61	bus_dma_tag_t dmat;
62
63	sc->sc_memt = faa->fa_iot;
64	sc->sc_ci_dmat = faa->fa_dmat;
65
66	/* Create coherent DMA tag. */
67	dmat = malloc(sizeof(*sc->sc_cc_dmat), M_DEVBUF, M_WAITOK | M_ZERO);
68	memcpy(dmat, faa->fa_dmat, sizeof(*dmat));
69	dmat->_flags |= BUS_DMA_COHERENT;
70	sc->sc_cc_dmat = dmat;
71
72	acpi_attach_common(sc, faa->fa_reg[0].addr);
73}
74
75int
76acpi_map(paddr_t pa, size_t len, struct acpi_mem_map *handle)
77{
78	paddr_t pgpa = trunc_page(pa);
79	paddr_t endpa = round_page(pa + len);
80	vaddr_t va = (vaddr_t)km_alloc(endpa - pgpa, &kv_any, &kp_none,
81	    &kd_nowait);
82
83	if (va == 0)
84		return (ENOMEM);
85
86	handle->baseva = va;
87	handle->va = (u_int8_t *)(va + (pa & PGOFSET));
88	handle->vsize = endpa - pgpa;
89	handle->pa = pa;
90
91	do {
92		pmap_kenter_pa(va, pgpa, PROT_READ | PROT_WRITE);
93		va += NBPG;
94		pgpa += NBPG;
95	} while (pgpa < endpa);
96
97	return 0;
98}
99
100void
101acpi_unmap(struct acpi_mem_map *handle)
102{
103	pmap_kremove(handle->baseva, handle->vsize);
104	km_free((void *)handle->baseva, handle->vsize, &kv_any, &kp_none);
105}
106
107int
108acpi_bus_space_map(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
109    int flags, bus_space_handle_t *bshp)
110{
111	return bus_space_map(t, addr, size, flags, bshp);
112}
113
114void
115acpi_bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh,
116    bus_size_t size)
117{
118	bus_space_unmap(t, bsh, size);
119}
120
121int
122acpi_acquire_glk(uint32_t *lock)
123{
124	/* No global lock. */
125	return 1;
126}
127
128int
129acpi_release_glk(uint32_t *lock)
130{
131	/* No global lock. */
132	return 0;
133}
134
135void
136acpi_attach_machdep(struct acpi_softc *sc)
137{
138#if NAPM > 0
139	apm_setinfohook(acpi_apminfo);
140#endif
141}
142
143void *
144acpi_intr_establish(int irq, int flags, int level,
145    int (*func)(void *), void *arg, const char *name)
146{
147	struct interrupt_controller *ic;
148	struct machine_intr_handle *aih;
149	uint32_t interrupt[3];
150	void *cookie;
151
152	extern LIST_HEAD(, interrupt_controller) interrupt_controllers;
153	LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
154		if (ic->ic_phandle == 1)
155			break;
156	}
157	if (ic == NULL)
158		return NULL;
159
160	interrupt[0] = 0;
161	interrupt[1] = irq - 32;
162	if (flags & LR_EXTIRQ_MODE) { /* edge */
163		if (flags & LR_EXTIRQ_POLARITY)
164			interrupt[2] = 0x2; /* falling */
165		else
166			interrupt[2] = 0x1; /* rising */
167	} else { /* level */
168		if (flags & LR_EXTIRQ_POLARITY)
169			interrupt[2] = 0x8; /* low */
170		else
171			interrupt[2] = 0x4; /* high */
172	}
173
174	cookie = ic->ic_establish(ic->ic_cookie, interrupt, level, NULL,
175	    func, arg, (char *)name);
176	if (cookie == NULL)
177		return NULL;
178
179	aih = malloc(sizeof(*aih), M_DEVBUF, M_WAITOK);
180	aih->ih_ic = ic;
181	aih->ih_ih = cookie;
182
183	return aih;
184}
185
186void
187acpi_intr_disestablish(void *cookie)
188{
189	struct machine_intr_handle *aih = cookie;
190	struct interrupt_controller *ic = aih->ih_ic;
191
192	ic->ic_disestablish(aih->ih_ih);
193	free(aih, M_DEVBUF, sizeof(*aih));
194}
195
196bus_dma_tag_t
197acpi_iommu_device_map(struct aml_node *node, bus_dma_tag_t dmat)
198{
199	return acpiiort_device_map(node, dmat);
200}
201