xref: /openbsd-src/sys/arch/arm64/dev/acpiiort.c (revision ce76b8c8ac8d4b18e8e9fcd4f8c2d1396fc693bf)
1*ce76b8c8Spatrick /* $OpenBSD: acpiiort.c,v 1.9 2022/09/07 18:25:08 patrick Exp $ */
2ffdeadb5Spatrick /*
3ffdeadb5Spatrick  * Copyright (c) 2021 Patrick Wildt <patrick@blueri.se>
4ffdeadb5Spatrick  *
5ffdeadb5Spatrick  * Permission to use, copy, modify, and distribute this software for any
6ffdeadb5Spatrick  * purpose with or without fee is hereby granted, provided that the above
7ffdeadb5Spatrick  * copyright notice and this permission notice appear in all copies.
8ffdeadb5Spatrick  *
9ffdeadb5Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10ffdeadb5Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11ffdeadb5Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12ffdeadb5Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13ffdeadb5Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14ffdeadb5Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15ffdeadb5Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16ffdeadb5Spatrick  */
17ffdeadb5Spatrick 
18ffdeadb5Spatrick #include <sys/param.h>
19ffdeadb5Spatrick #include <sys/systm.h>
20ffdeadb5Spatrick #include <sys/device.h>
21ffdeadb5Spatrick 
22ffdeadb5Spatrick #include <dev/acpi/acpireg.h>
23ffdeadb5Spatrick #include <dev/acpi/acpivar.h>
247d187974Spatrick #include <dev/acpi/dsdt.h>
25ffdeadb5Spatrick 
26ffdeadb5Spatrick #include <arm64/dev/acpiiort.h>
27ffdeadb5Spatrick 
28ffdeadb5Spatrick SIMPLEQ_HEAD(, acpiiort_smmu) acpiiort_smmu_list =
29ffdeadb5Spatrick     SIMPLEQ_HEAD_INITIALIZER(acpiiort_smmu_list);
30ffdeadb5Spatrick 
31ffdeadb5Spatrick int acpiiort_match(struct device *, void *, void *);
32ffdeadb5Spatrick void acpiiort_attach(struct device *, struct device *, void *);
33ffdeadb5Spatrick 
34471aeecfSnaddy const struct cfattach acpiiort_ca = {
35ffdeadb5Spatrick 	sizeof(struct device), acpiiort_match, acpiiort_attach
36ffdeadb5Spatrick };
37ffdeadb5Spatrick 
38ffdeadb5Spatrick struct cfdriver acpiiort_cd = {
39ffdeadb5Spatrick 	NULL, "acpiiort", DV_DULL
40ffdeadb5Spatrick };
41ffdeadb5Spatrick 
42ffdeadb5Spatrick int
acpiiort_match(struct device * parent,void * match,void * aux)43ffdeadb5Spatrick acpiiort_match(struct device *parent, void *match, void *aux)
44ffdeadb5Spatrick {
45ffdeadb5Spatrick 	struct acpi_attach_args *aaa = aux;
46ffdeadb5Spatrick 	struct acpi_table_header *hdr;
47ffdeadb5Spatrick 
48ffdeadb5Spatrick 	/* If we do not have a table, it is not us */
49ffdeadb5Spatrick 	if (aaa->aaa_table == NULL)
50ffdeadb5Spatrick 		return 0;
51ffdeadb5Spatrick 
52ffdeadb5Spatrick 	/* If it is an IORT table, we can attach */
53ffdeadb5Spatrick 	hdr = (struct acpi_table_header *)aaa->aaa_table;
54ffdeadb5Spatrick 	if (memcmp(hdr->signature, IORT_SIG, sizeof(IORT_SIG) - 1) != 0)
55ffdeadb5Spatrick 		return 0;
56ffdeadb5Spatrick 
57ffdeadb5Spatrick 	return 1;
58ffdeadb5Spatrick }
59ffdeadb5Spatrick 
60ffdeadb5Spatrick void
acpiiort_attach(struct device * parent,struct device * self,void * aux)61ffdeadb5Spatrick acpiiort_attach(struct device *parent, struct device *self, void *aux)
62ffdeadb5Spatrick {
63ffdeadb5Spatrick 	struct acpi_attach_args *aaa = aux;
64ffdeadb5Spatrick 	struct acpi_iort *iort = (struct acpi_iort *)aaa->aaa_table;
65ffdeadb5Spatrick 	struct acpi_iort_node *node;
66ffdeadb5Spatrick 	struct acpiiort_attach_args aia;
67ffdeadb5Spatrick 	uint32_t offset;
68ffdeadb5Spatrick 	int i;
69ffdeadb5Spatrick 
70ffdeadb5Spatrick 	printf("\n");
71ffdeadb5Spatrick 
72ffdeadb5Spatrick 	memset(&aia, 0, sizeof(aia));
73ffdeadb5Spatrick 	aia.aia_iot = aaa->aaa_iot;
74ffdeadb5Spatrick 	aia.aia_memt = aaa->aaa_memt;
75ffdeadb5Spatrick 	aia.aia_dmat = aaa->aaa_dmat;
76ffdeadb5Spatrick 
77ffdeadb5Spatrick 	offset = iort->offset;
78ffdeadb5Spatrick 	for (i = 0; i < iort->number_of_nodes; i++) {
79ffdeadb5Spatrick 		node = (struct acpi_iort_node *)((char *)iort + offset);
80ffdeadb5Spatrick 		aia.aia_node = node;
81ffdeadb5Spatrick 		config_found(self, &aia, NULL);
82ffdeadb5Spatrick 		offset += node->length;
83ffdeadb5Spatrick 	}
84ffdeadb5Spatrick }
85ffdeadb5Spatrick 
86ffdeadb5Spatrick void
acpiiort_smmu_register(struct acpiiort_smmu * as)87ffdeadb5Spatrick acpiiort_smmu_register(struct acpiiort_smmu *as)
88ffdeadb5Spatrick {
89ffdeadb5Spatrick 	SIMPLEQ_INSERT_TAIL(&acpiiort_smmu_list, as, as_list);
90ffdeadb5Spatrick }
91ffdeadb5Spatrick 
9288933a1fSpatrick bus_dma_tag_t
acpiiort_smmu_map(struct acpi_iort_node * node,uint32_t rid,bus_dma_tag_t dmat)9388933a1fSpatrick acpiiort_smmu_map(struct acpi_iort_node *node, uint32_t rid,
9488933a1fSpatrick     bus_dma_tag_t dmat)
95ffdeadb5Spatrick {
96ffdeadb5Spatrick 	struct acpiiort_smmu *as;
97ffdeadb5Spatrick 
98ffdeadb5Spatrick 	SIMPLEQ_FOREACH(as, &acpiiort_smmu_list, as_list) {
9988933a1fSpatrick 		if (as->as_node == node)
10088933a1fSpatrick 			return as->as_map(as->as_cookie, rid, dmat);
101ffdeadb5Spatrick 	}
10288933a1fSpatrick 
10388933a1fSpatrick 	return dmat;
104ffdeadb5Spatrick }
1057d187974Spatrick 
106415019ceSpatrick void
acpiiort_smmu_reserve_region(struct acpi_iort_node * node,uint32_t rid,bus_addr_t addr,bus_size_t size)107415019ceSpatrick acpiiort_smmu_reserve_region(struct acpi_iort_node *node, uint32_t rid,
108415019ceSpatrick     bus_addr_t addr, bus_size_t size)
109415019ceSpatrick {
110415019ceSpatrick 	struct acpiiort_smmu *as;
111415019ceSpatrick 
112415019ceSpatrick 	SIMPLEQ_FOREACH(as, &acpiiort_smmu_list, as_list) {
113415019ceSpatrick 		if (as->as_node == node) {
114415019ceSpatrick 			as->as_reserve(as->as_cookie, rid, addr, size);
115415019ceSpatrick 			return;
116415019ceSpatrick 		}
117415019ceSpatrick 	}
118415019ceSpatrick }
119415019ceSpatrick 
1207d187974Spatrick bus_dma_tag_t
acpiiort_device_map(struct aml_node * root,bus_dma_tag_t dmat)1217d187974Spatrick acpiiort_device_map(struct aml_node *root, bus_dma_tag_t dmat)
1227d187974Spatrick {
1237d187974Spatrick 	struct acpi_table_header *hdr;
1247d187974Spatrick 	struct acpi_iort *iort = NULL;
1257d187974Spatrick 	struct acpi_iort_node *node;
1267d187974Spatrick 	struct acpi_iort_mapping *map;
1277d187974Spatrick 	struct acpi_iort_nc_node *nc;
1287d187974Spatrick 	struct acpi_q *entry;
1293dbfdff0Spatrick 	struct aml_node *anc;
1307d187974Spatrick 	uint32_t rid, offset;
1317d187974Spatrick 	int i;
1327d187974Spatrick 
1337d187974Spatrick 	/* Look for IORT table. */
1347d187974Spatrick 	SIMPLEQ_FOREACH(entry, &acpi_softc->sc_tables, q_next) {
1357d187974Spatrick 		hdr = entry->q_table;
1367d187974Spatrick 		if (strncmp(hdr->signature, IORT_SIG,
1377d187974Spatrick 		    sizeof(hdr->signature)) == 0) {
1387d187974Spatrick 			iort = entry->q_table;
1397d187974Spatrick 			break;
1407d187974Spatrick 		}
1417d187974Spatrick 	}
1427d187974Spatrick 	if (iort == NULL)
1437d187974Spatrick 		return dmat;
1447d187974Spatrick 
1457d187974Spatrick 	/* Find our named component. */
1467d187974Spatrick 	offset = iort->offset;
1477d187974Spatrick 	for (i = 0; i < iort->number_of_nodes; i++) {
1487d187974Spatrick 		node = (struct acpi_iort_node *)((char *)iort + offset);
1497d187974Spatrick 		if (node->type == ACPI_IORT_NAMED_COMPONENT) {
1507d187974Spatrick 			nc = (struct acpi_iort_nc_node *)&node[1];
1513dbfdff0Spatrick 			anc = aml_searchname(acpi_softc->sc_root,
1523dbfdff0Spatrick 			    nc->device_object_name);
1533dbfdff0Spatrick 			if (anc == root)
1547d187974Spatrick 				break;
1557d187974Spatrick 		}
1567d187974Spatrick 		offset += node->length;
1577d187974Spatrick 	}
1587d187974Spatrick 
1597d187974Spatrick 	/* No NC found? Weird. */
1607d187974Spatrick 	if (i >= iort->number_of_nodes)
1617d187974Spatrick 		return dmat;
1627d187974Spatrick 
1637d187974Spatrick 	/* Find our output base towards SMMU. */
1647d187974Spatrick 	map = (struct acpi_iort_mapping *)((char *)node + node->mapping_offset);
1657d187974Spatrick 	for (i = 0; i < node->number_of_mappings; i++) {
1667d187974Spatrick 		offset = map[i].output_reference;
1677d187974Spatrick 
1687d187974Spatrick 		if (map[i].flags & ACPI_IORT_MAPPING_SINGLE) {
1697d187974Spatrick 			rid = map[i].output_base;
1707d187974Spatrick 			break;
1717d187974Spatrick 		}
1727d187974Spatrick 	}
1737d187974Spatrick 
174*ce76b8c8Spatrick 	/*
175*ce76b8c8Spatrick 	 * The IORT spec allows NCs to use implementation-defined IDs, whose
176*ce76b8c8Spatrick 	 * interpretation is up to the device driver.  For now simply take the
177*ce76b8c8Spatrick 	 * mapping if there's a single one.  This might change in the future.
178*ce76b8c8Spatrick 	 */
179*ce76b8c8Spatrick 	if (i >= node->number_of_mappings && node->number_of_mappings == 1) {
180*ce76b8c8Spatrick 		i = 0;
181*ce76b8c8Spatrick 		rid = map[i].output_base;
182*ce76b8c8Spatrick 	}
183*ce76b8c8Spatrick 
1847d187974Spatrick 	/* No mapping found? Even weirder. */
1857d187974Spatrick 	if (i >= node->number_of_mappings)
1867d187974Spatrick 		return dmat;
1877d187974Spatrick 
1887d187974Spatrick 	node = (struct acpi_iort_node *)((char *)iort + offset);
189227a6d54Spatrick 	if (node->type == ACPI_IORT_SMMU || node->type == ACPI_IORT_SMMU_V3)
1907d187974Spatrick 		return acpiiort_smmu_map(node, rid, dmat);
1917d187974Spatrick 
1927d187974Spatrick 	return dmat;
1937d187974Spatrick }
194