xref: /haiku/src/add-ons/kernel/busses/mmc/sdhci_acpi.cpp (revision 9f3bdf3d039430b5172c424def20ce5d9f7367d4)
1 /*
2  * Copyright 2018-2024 Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		B Krishnan Iyer, krishnaniyer97@gmail.com
7  *		Adrien Destugues, pulkomandy@pulkomandy.tk
8  *		Ron Ben Aroya, sed4906birdie@gmail.com
9  */
10 #include <algorithm>
11 #include <new>
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include <bus/PCI.h>
16 #include <ACPI.h>
17 #include "acpi.h"
18 
19 #include <KernelExport.h>
20 
21 #include "IOSchedulerSimple.h"
22 #include "mmc.h"
23 #include "sdhci.h"
24 
25 
26 #define TRACE_SDHCI
27 #ifdef TRACE_SDHCI
28 #	define TRACE(x...) dprintf("\33[33msdhci:\33[0m " x)
29 #else
30 #	define TRACE(x...) ;
31 #endif
32 #define TRACE_ALWAYS(x...)	dprintf("\33[33msdhci:\33[0m " x)
33 #define ERROR(x...)			dprintf("\33[33msdhci:\33[0m " x)
34 #define CALLED(x...)		TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
35 
36 
37 #define SDHCI_DEVICE_MODULE_NAME "busses/mmc/sdhci/driver_v1"
38 #define SDHCI_ACPI_MMC_BUS_MODULE_NAME "busses/mmc/sdhci/acpi/device/v1"
39 
40 static acpi_status
41 sdhci_acpi_scan_parse_callback(ACPI_RESOURCE *res, void *context)
42 {
43 	struct sdhci_crs* crs = (struct sdhci_crs*)context;
44 
45 	if (res->Type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
46 		crs->addr_bas = res->Data.FixedMemory32.Address;
47 		crs->addr_len = res->Data.FixedMemory32.AddressLength;
48 	} else if (res->Type == ACPI_RESOURCE_TYPE_IRQ) {
49 		crs->irq = res->Data.Irq.Interrupt;
50 		//crs->irq_triggering = res->Data.Irq.Triggering;
51 		//crs->irq_polarity = res->Data.Irq.Polarity;
52 		//crs->irq_shareable = res->Data.Irq.Shareable;
53 	} else if (res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
54 		crs->irq = res->Data.ExtendedIrq.Interrupt;
55 		//crs->irq_triggering = res->Data.ExtendedIrq.Triggering;
56 		//crs->irq_polarity = res->Data.ExtendedIrq.Polarity;
57 		//crs->irq_shareable = res->Data.ExtendedIrq.Shareable;
58 	}
59 
60 	return B_OK;
61 }
62 
63 status_t
64 init_bus_acpi(device_node* node, void** bus_cookie)
65 {
66 	CALLED();
67 
68 	// Get the ACPI driver and device
69 	acpi_device_module_info* acpi;
70 	acpi_device device;
71 
72 	device_node* parent = gDeviceManager->get_parent_node(node);
73 	device_node* acpiParent = gDeviceManager->get_parent_node(parent);
74 	gDeviceManager->get_driver(acpiParent, (driver_module_info**)&acpi,
75 			(void**)&device);
76 	gDeviceManager->put_node(acpiParent);
77 	gDeviceManager->put_node(parent);
78 
79 	// Ignore invalid bars
80 	TRACE("Register SD bus\n");
81 
82 	struct sdhci_crs crs;
83 	if(acpi->walk_resources(device, (ACPI_STRING)"_CRS",
84 			sdhci_acpi_scan_parse_callback, &crs) != B_OK) {
85 		ERROR("Couldn't scan ACPI register set\n");
86 		return B_IO_ERROR;
87 	}
88 
89 	TRACE("addr: %" B_PRIx32 " len: %" B_PRIx32 "\n", crs.addr_bas, crs.addr_len);
90 
91 	if (crs.addr_bas == 0 || crs.addr_len == 0) {
92 		ERROR("No registers to map\n");
93 		return B_IO_ERROR;
94 	}
95 
96 	// map the slot registers
97 	area_id	regs_area;
98 	struct registers* _regs;
99 	regs_area = map_physical_memory("sdhc_regs_map",
100 		crs.addr_bas, crs.addr_len, B_ANY_KERNEL_BLOCK_ADDRESS,
101 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&_regs);
102 
103 	if (regs_area < B_OK) {
104 		ERROR("Could not map registers\n");
105 		return B_BAD_VALUE;
106 	}
107 
108 	// the interrupt is shared between all busses in an SDHC controller, but
109 	// they each register an handler. Not a problem, we will just test the
110 	// interrupt registers for all busses one after the other and find no
111 	// interrupts on the idle busses.
112 	uint8_t irq = crs.irq;
113 	TRACE("irq interrupt line: %d\n", irq);
114 
115 	SdhciBus* bus = new(std::nothrow) SdhciBus(_regs, irq, true);
116 
117 	status_t status = B_NO_MEMORY;
118 	if (bus != NULL)
119 		status = bus->InitCheck();
120 
121 	if (status != B_OK) {
122 		if (bus != NULL)
123 			delete bus;
124 		else
125 			delete_area(regs_area);
126 		return status;
127 	}
128 
129 	// Store the created object as a cookie, allowing users of the bus to
130 	// locate it.
131 	*bus_cookie = bus;
132 
133 	return status;
134 }
135 
136 status_t
137 register_child_devices_acpi(void* cookie)
138 {
139 	CALLED();
140 	SdhciDevice* context = (SdhciDevice*)cookie;
141 	device_node* parent = gDeviceManager->get_parent_node(context->fNode);
142 	acpi_device_module_info* acpi;
143 	acpi_device* device;
144 
145 	gDeviceManager->get_driver(parent, (driver_module_info**)&acpi,
146 		(void**)&device);
147 
148 	TRACE("register_child_devices\n");
149 
150 	char prettyName[25];
151 
152 	sprintf(prettyName, "SDHC bus");
153 	device_attr attrs[] = {
154 		// properties of this controller for mmc bus manager
155 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = prettyName } },
156 		{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
157 			{.string = MMC_BUS_MODULE_NAME} },
158 		{ B_DEVICE_BUS, B_STRING_TYPE, {.string = "mmc"} },
159 
160 		// DMA properties
161 		// The high alignment is to force access only to complete sectors
162 		// These constraints could be removed by using ADMA which allows
163 		// use of the full 64bit address space and can do scatter-gather.
164 		{ B_DMA_ALIGNMENT, B_UINT32_TYPE, { .ui32 = 511 }},
165 		{ B_DMA_HIGH_ADDRESS, B_UINT64_TYPE, { .ui64 = 0x100000000LL }},
166 		{ B_DMA_BOUNDARY, B_UINT32_TYPE, { .ui32 = (1 << 19) - 1 }},
167 		{ B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE, { .ui32 = 1 }},
168 		{ B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE, { .ui32 = (1 << 10) - 1 }},
169 
170 		// private data to identify device
171 		{ NULL }
172 	};
173 	device_node* node;
174 	if (gDeviceManager->register_node(context->fNode,
175 			SDHCI_ACPI_MMC_BUS_MODULE_NAME, attrs, NULL,
176 			&node) != B_OK)
177 		return B_BAD_VALUE;
178 	return B_OK;
179 }
180 
181 float
182 supports_device_acpi(device_node* parent)
183 {
184 	const char* hid;
185 	const char* uid;
186 	uint32 type;
187 
188 	if (gDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, &type, false)
189 		|| type != ACPI_TYPE_DEVICE) {
190 		return 0.0f;
191 	}
192 
193 	if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &hid, false)) {
194 		TRACE("No hid attribute\n");
195 		return 0.0f;
196 	}
197 
198 	if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_UID_ITEM, &uid, false)) {
199 		TRACE("No uid attribute\n");
200 		return 0.0f;
201 	}
202 
203 	TRACE("supports_device(hid:%s uid:%s)\n", hid, uid);
204 
205 	if (!(strcmp(hid, "80860F14") == 0
206 			||	strcmp(hid, "80860F16") == 0
207 			||	strcmp(hid, "80865ACA") == 0
208 			||	strcmp(hid, "80865AD0") == 0
209 			||	strcmp(hid, "INT33C6") == 0
210 			||	strcmp(hid, "INT3436") == 0
211 			||	strcmp(hid, "INT344D") == 0
212 			||	strcmp(hid, "INT33BB") == 0
213 			||	strcmp(hid, "NXP0003") == 0
214 			||	strcmp(hid, "RKCP0D40") == 0
215 			||	strcmp(hid, "PNP0D40") == 0))
216 		return 0.0f;
217 
218 	acpi_device_module_info* acpi;
219 	acpi_device* device;
220 	gDeviceManager->get_driver(parent, (driver_module_info**)&acpi,
221 		(void**)&device);
222 	TRACE("SDHCI Device found! hid: %s, uid: %s\n", hid, uid);
223 
224 	return 0.8f;
225 }
226 
227 // Device node registered for each SD slot. It implements the MMC operations so
228 // the bus manager can use it to communicate with SD cards.
229 mmc_bus_interface gSDHCIACPIDeviceModule = {
230 	.info = {
231 		.info = {
232 			.name = SDHCI_ACPI_MMC_BUS_MODULE_NAME,
233 		},
234 
235 		.init_driver = init_bus_acpi,
236 		.uninit_driver = uninit_bus,
237 		.device_removed = bus_removed,
238 	},
239 
240 	.set_clock = set_clock,
241 	.execute_command = execute_command,
242 	.do_io = do_io,
243 	.set_scan_semaphore = set_scan_semaphore,
244 	.set_bus_width = set_bus_width,
245 };