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