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_PCI_MMC_BUS_MODULE_NAME "busses/mmc/sdhci/pci/device/v1"
39
40#define SLOT_NUMBER				"device/slot"
41#define BAR_INDEX				"device/bar"
42
43status_t
44init_bus_pci(device_node* node, void** bus_cookie)
45{
46	CALLED();
47
48	// Get the PCI driver and device
49	pci_device_module_info* pci;
50	pci_device* device;
51
52	device_node* parent = gDeviceManager->get_parent_node(node);
53	device_node* pciParent = gDeviceManager->get_parent_node(parent);
54	gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci,
55	        (void**)&device);
56	gDeviceManager->put_node(pciParent);
57	gDeviceManager->put_node(parent);
58
59	uint8_t bar, slot;
60	if (gDeviceManager->get_attr_uint8(node, SLOT_NUMBER, &slot, false) < B_OK
61		|| gDeviceManager->get_attr_uint8(node, BAR_INDEX, &bar, false) < B_OK)
62		return B_BAD_TYPE;
63
64	// Ignore invalid bars
65	TRACE("Register SD bus at slot %d, using bar %d\n", slot + 1, bar);
66
67	pci_info pciInfo;
68	pci->get_pci_info(device, &pciInfo);
69
70	for (; bar < 6 && slot > 0; bar++, slot--) {
71		if ((pciInfo.u.h0.base_register_flags[bar] & PCI_address_type)
72			== PCI_address_type_64) {
73			bar++;
74		}
75	}
76
77	phys_addr_t physicalAddress = pciInfo.u.h0.base_registers[bar];
78	uint64 barSize = pciInfo.u.h0.base_register_sizes[bar];
79	if ((pciInfo.u.h0.base_register_flags[bar] & PCI_address_type)
80			== PCI_address_type_64) {
81		physicalAddress |= (uint64)pciInfo.u.h0.base_registers[bar + 1] << 32;
82		barSize |= (uint64)pciInfo.u.h0.base_register_sizes[bar + 1] << 32;
83	}
84
85	if (physicalAddress == 0 || barSize == 0) {
86		ERROR("No registers to map\n");
87		return B_IO_ERROR;
88	}
89
90	// enable bus master and io
91	uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2);
92	pcicmd &= ~(PCI_command_int_disable | PCI_command_io);
93	pcicmd |= PCI_command_master | PCI_command_memory;
94	pci->write_pci_config(device, PCI_command, 2, pcicmd);
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		physicalAddress, barSize, 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 = pciInfo.u.h0.interrupt_line;
113	TRACE("irq interrupt line: %d\n", irq);
114
115	SdhciBus* bus = new(std::nothrow) SdhciBus(_regs, irq, false);
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
136status_t
137register_child_devices_pci(void* cookie)
138{
139	CALLED();
140	SdhciDevice* context = (SdhciDevice*)cookie;
141	device_node* parent = gDeviceManager->get_parent_node(context->fNode);
142	pci_device_module_info* pci;
143	pci_device* device;
144
145	gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
146		(void**)&device);
147	uint8 slotsInfo = pci->read_pci_config(device, SDHCI_PCI_SLOT_INFO, 1);
148	uint8 bar = SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(slotsInfo);
149	uint8 slotsCount = SDHCI_PCI_SLOTS(slotsInfo);
150
151	TRACE("register_child_devices: %u, %u\n", bar, slotsCount);
152
153	char prettyName[25];
154
155	if (slotsCount > 6 || bar > 5) {
156		ERROR("Invalid slots count: %d or BAR count: %d \n", slotsCount, bar);
157		return B_BAD_VALUE;
158	}
159
160	for (uint8_t slot = 0; slot < slotsCount; slot++) {
161		sprintf(prettyName, "SDHC bus %" B_PRIu8, slot);
162		device_attr attrs[] = {
163			// properties of this controller for mmc bus manager
164			{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = prettyName } },
165			{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
166				{.string = MMC_BUS_MODULE_NAME} },
167			{ B_DEVICE_BUS, B_STRING_TYPE, {.string = "mmc"} },
168
169			// DMA properties
170			// The high alignment is to force access only to complete sectors
171			// These constraints could be removed by using ADMA which allows
172			// use of the full 64bit address space and can do scatter-gather.
173			{ B_DMA_ALIGNMENT, B_UINT32_TYPE, { .ui32 = 511 }},
174			{ B_DMA_HIGH_ADDRESS, B_UINT64_TYPE, { .ui64 = 0x100000000LL }},
175			{ B_DMA_BOUNDARY, B_UINT32_TYPE, { .ui32 = (1 << 19) - 1 }},
176			{ B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE, { .ui32 = 1 }},
177			{ B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE, { .ui32 = (1 << 10) - 1 }},
178
179			// private data to identify device
180			{ SLOT_NUMBER, B_UINT8_TYPE, { .ui8 = slot} },
181			{ BAR_INDEX, B_UINT8_TYPE, { .ui8 = bar} },
182			{ NULL }
183		};
184		device_node* node;
185		if (gDeviceManager->register_node(context->fNode,
186				SDHCI_PCI_MMC_BUS_MODULE_NAME, attrs, NULL,
187				&node) != B_OK)
188			return B_BAD_VALUE;
189	}
190	return B_OK;
191}
192
193status_t
194init_device_pci(device_node* node, SdhciDevice* context)
195{
196	// Get the PCI driver and device
197	pci_device_module_info* pci;
198	pci_device* device;
199	uint16 vendorId, deviceId;
200
201	device_node* pciParent = gDeviceManager->get_parent_node(context->fNode);
202	gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci,
203	        (void**)&device);
204	gDeviceManager->put_node(pciParent);
205
206	if (gDeviceManager->get_attr_uint16(node, B_DEVICE_VENDOR_ID,
207			&vendorId, true) != B_OK
208		|| gDeviceManager->get_attr_uint16(node, B_DEVICE_ID, &deviceId,
209			true) != B_OK) {
210		panic("No vendor or device id attribute\n");
211		return B_OK; // Let's hope it didn't need the quirk?
212	}
213
214	if (vendorId == 0x1180 && deviceId == 0xe823) {
215		// Switch the device to SD2.0 mode
216		// This should change its device id to 0xe822 if succesful.
217		// The device then remains in SD2.0 mode even after reboot.
218		pci->write_pci_config(device, SDHCI_PCI_RICOH_MODE_KEY, 1, 0xfc);
219		context->fRicohOriginalMode = pci->read_pci_config(device,
220			SDHCI_PCI_RICOH_MODE, 1);
221		pci->write_pci_config(device, SDHCI_PCI_RICOH_MODE, 1,
222			SDHCI_PCI_RICOH_MODE_SD20);
223		pci->write_pci_config(device, SDHCI_PCI_RICOH_MODE_KEY, 1, 0);
224
225		deviceId = pci->read_pci_config(device, 2, 2);
226		TRACE("Device ID after Ricoh quirk: %x\n", deviceId);
227	}
228
229	return B_OK;
230}
231
232void
233uninit_device_pci(SdhciDevice* context, device_node* pciParent)
234{
235	// Get the PCI driver and device
236	pci_device_module_info* pci;
237	pci_device* device;
238	uint16 vendorId, deviceId;
239
240	gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci,
241	        (void**)&device);
242
243	if (gDeviceManager->get_attr_uint16(context->fNode, B_DEVICE_VENDOR_ID,
244			&vendorId, true) != B_OK
245		|| gDeviceManager->get_attr_uint16(context->fNode, B_DEVICE_ID,
246			&deviceId, false) != B_OK) {
247		ERROR("No vendor or device id attribute\n");
248	} else if (vendorId == 0x1180 && deviceId == 0xe823) {
249		pci->write_pci_config(device, SDHCI_PCI_RICOH_MODE_KEY, 1, 0xfc);
250		pci->write_pci_config(device, SDHCI_PCI_RICOH_MODE, 1,
251			context->fRicohOriginalMode);
252		pci->write_pci_config(device, SDHCI_PCI_RICOH_MODE_KEY, 1, 0);
253	}
254}
255
256float
257supports_device_pci(device_node* parent)
258{
259	uint16 type, subType;
260	uint16 vendorId, deviceId;
261
262	if (gDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID, &vendorId,
263			false) != B_OK
264		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceId,
265			false) != B_OK) {
266		TRACE("No vendor or device id attribute\n");
267		return 0.0f;
268	}
269
270	TRACE("supports_device(vid:%04x pid:%04x)\n", vendorId, deviceId);
271
272	if (gDeviceManager->get_attr_uint16(parent, B_DEVICE_SUB_TYPE, &subType,
273			false) < B_OK
274		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_TYPE, &type,
275			false) < B_OK) {
276		TRACE("Could not find type/subtype attributes\n");
277		return -1;
278	}
279
280	if (type == PCI_base_peripheral) {
281		if (subType != PCI_sd_host) {
282			// Also accept some compliant devices that do not advertise
283			// themselves as such.
284			if (vendorId != 0x1180
285				|| (deviceId != 0xe823 && deviceId != 0xe822)) {
286				TRACE("Not the right subclass, and not a Ricoh device\n");
287				return 0.0f;
288			}
289		}
290
291		pci_device_module_info* pci;
292		pci_device* device;
293		gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
294			(void**)&device);
295		TRACE("SDHCI Device found! Subtype: 0x%04x, type: 0x%04x\n",
296			subType, type);
297
298		return 0.8f;
299	}
300
301	return 0.0f;
302}
303
304// Device node registered for each SD slot. It implements the MMC operations so
305// the bus manager can use it to communicate with SD cards.
306mmc_bus_interface gSDHCIPCIDeviceModule = {
307	.info = {
308		.info = {
309			.name = SDHCI_PCI_MMC_BUS_MODULE_NAME,
310		},
311
312		.init_driver = init_bus_pci,
313		.uninit_driver = uninit_bus,
314		.device_removed = bus_removed,
315	},
316
317	.set_clock = set_clock,
318	.execute_command = execute_command,
319	.do_io = do_io,
320	.set_scan_semaphore = set_scan_semaphore,
321	.set_bus_width = set_bus_width,
322};