11cdb3bebSSED4906 /*
21cdb3bebSSED4906 * Copyright 2018-2024 Haiku, Inc. All rights reserved.
31cdb3bebSSED4906 * Distributed under the terms of the MIT License.
41cdb3bebSSED4906 *
51cdb3bebSSED4906 * Authors:
61cdb3bebSSED4906 * B Krishnan Iyer, krishnaniyer97@gmail.com
71cdb3bebSSED4906 * Adrien Destugues, pulkomandy@pulkomandy.tk
81cdb3bebSSED4906 * Ron Ben Aroya, sed4906birdie@gmail.com
91cdb3bebSSED4906 */
101cdb3bebSSED4906 #include <algorithm>
111cdb3bebSSED4906 #include <new>
121cdb3bebSSED4906 #include <stdio.h>
131cdb3bebSSED4906 #include <string.h>
141cdb3bebSSED4906
151cdb3bebSSED4906 #include <bus/PCI.h>
161cdb3bebSSED4906 #include <ACPI.h>
171cdb3bebSSED4906 #include "acpi.h"
181cdb3bebSSED4906
191cdb3bebSSED4906 #include <KernelExport.h>
201cdb3bebSSED4906
211cdb3bebSSED4906 #include "IOSchedulerSimple.h"
221cdb3bebSSED4906 #include "mmc.h"
231cdb3bebSSED4906 #include "sdhci.h"
241cdb3bebSSED4906
251cdb3bebSSED4906
26*a03edeabSAugustin Cavalier //#define TRACE_SDHCI
271cdb3bebSSED4906 #ifdef TRACE_SDHCI
281cdb3bebSSED4906 # define TRACE(x...) dprintf("\33[33msdhci:\33[0m " x)
291cdb3bebSSED4906 #else
301cdb3bebSSED4906 # define TRACE(x...) ;
311cdb3bebSSED4906 #endif
321cdb3bebSSED4906 #define TRACE_ALWAYS(x...) dprintf("\33[33msdhci:\33[0m " x)
331cdb3bebSSED4906 #define ERROR(x...) dprintf("\33[33msdhci:\33[0m " x)
341cdb3bebSSED4906 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
351cdb3bebSSED4906
361cdb3bebSSED4906
371cdb3bebSSED4906 #define SDHCI_DEVICE_MODULE_NAME "busses/mmc/sdhci/driver_v1"
381cdb3bebSSED4906 #define SDHCI_ACPI_MMC_BUS_MODULE_NAME "busses/mmc/sdhci/acpi/device/v1"
391cdb3bebSSED4906
401cdb3bebSSED4906 static acpi_status
sdhci_acpi_scan_parse_callback(ACPI_RESOURCE * res,void * context)411cdb3bebSSED4906 sdhci_acpi_scan_parse_callback(ACPI_RESOURCE *res, void *context)
421cdb3bebSSED4906 {
431cdb3bebSSED4906 struct sdhci_crs* crs = (struct sdhci_crs*)context;
441cdb3bebSSED4906
451cdb3bebSSED4906 if (res->Type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
461cdb3bebSSED4906 crs->addr_bas = res->Data.FixedMemory32.Address;
471cdb3bebSSED4906 crs->addr_len = res->Data.FixedMemory32.AddressLength;
481cdb3bebSSED4906 } else if (res->Type == ACPI_RESOURCE_TYPE_IRQ) {
491cdb3bebSSED4906 crs->irq = res->Data.Irq.Interrupt;
501cdb3bebSSED4906 //crs->irq_triggering = res->Data.Irq.Triggering;
511cdb3bebSSED4906 //crs->irq_polarity = res->Data.Irq.Polarity;
521cdb3bebSSED4906 //crs->irq_shareable = res->Data.Irq.Shareable;
531cdb3bebSSED4906 } else if (res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
541cdb3bebSSED4906 crs->irq = res->Data.ExtendedIrq.Interrupt;
551cdb3bebSSED4906 //crs->irq_triggering = res->Data.ExtendedIrq.Triggering;
561cdb3bebSSED4906 //crs->irq_polarity = res->Data.ExtendedIrq.Polarity;
571cdb3bebSSED4906 //crs->irq_shareable = res->Data.ExtendedIrq.Shareable;
581cdb3bebSSED4906 }
591cdb3bebSSED4906
601cdb3bebSSED4906 return B_OK;
611cdb3bebSSED4906 }
621cdb3bebSSED4906
631cdb3bebSSED4906 status_t
init_bus_acpi(device_node * node,void ** bus_cookie)641cdb3bebSSED4906 init_bus_acpi(device_node* node, void** bus_cookie)
651cdb3bebSSED4906 {
661cdb3bebSSED4906 CALLED();
671cdb3bebSSED4906
681cdb3bebSSED4906 // Get the ACPI driver and device
691cdb3bebSSED4906 acpi_device_module_info* acpi;
701cdb3bebSSED4906 acpi_device device;
711cdb3bebSSED4906
721cdb3bebSSED4906 device_node* parent = gDeviceManager->get_parent_node(node);
731cdb3bebSSED4906 device_node* acpiParent = gDeviceManager->get_parent_node(parent);
741cdb3bebSSED4906 gDeviceManager->get_driver(acpiParent, (driver_module_info**)&acpi,
751cdb3bebSSED4906 (void**)&device);
761cdb3bebSSED4906 gDeviceManager->put_node(acpiParent);
771cdb3bebSSED4906 gDeviceManager->put_node(parent);
781cdb3bebSSED4906
791cdb3bebSSED4906 // Ignore invalid bars
801cdb3bebSSED4906 TRACE("Register SD bus\n");
811cdb3bebSSED4906
821cdb3bebSSED4906 struct sdhci_crs crs;
831cdb3bebSSED4906 if(acpi->walk_resources(device, (ACPI_STRING)"_CRS",
841cdb3bebSSED4906 sdhci_acpi_scan_parse_callback, &crs) != B_OK) {
851cdb3bebSSED4906 ERROR("Couldn't scan ACPI register set\n");
861cdb3bebSSED4906 return B_IO_ERROR;
871cdb3bebSSED4906 }
881cdb3bebSSED4906
891cdb3bebSSED4906 TRACE("addr: %" B_PRIx32 " len: %" B_PRIx32 "\n", crs.addr_bas, crs.addr_len);
901cdb3bebSSED4906
911cdb3bebSSED4906 if (crs.addr_bas == 0 || crs.addr_len == 0) {
921cdb3bebSSED4906 ERROR("No registers to map\n");
931cdb3bebSSED4906 return B_IO_ERROR;
941cdb3bebSSED4906 }
951cdb3bebSSED4906
961cdb3bebSSED4906 // map the slot registers
971cdb3bebSSED4906 area_id regs_area;
981cdb3bebSSED4906 struct registers* _regs;
991cdb3bebSSED4906 regs_area = map_physical_memory("sdhc_regs_map",
1001cdb3bebSSED4906 crs.addr_bas, crs.addr_len, B_ANY_KERNEL_BLOCK_ADDRESS,
1011cdb3bebSSED4906 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&_regs);
1021cdb3bebSSED4906
1031cdb3bebSSED4906 if (regs_area < B_OK) {
1041cdb3bebSSED4906 ERROR("Could not map registers\n");
1051cdb3bebSSED4906 return B_BAD_VALUE;
1061cdb3bebSSED4906 }
1071cdb3bebSSED4906
1081cdb3bebSSED4906 // the interrupt is shared between all busses in an SDHC controller, but
1091cdb3bebSSED4906 // they each register an handler. Not a problem, we will just test the
1101cdb3bebSSED4906 // interrupt registers for all busses one after the other and find no
1111cdb3bebSSED4906 // interrupts on the idle busses.
1121cdb3bebSSED4906 uint8_t irq = crs.irq;
1131cdb3bebSSED4906 TRACE("irq interrupt line: %d\n", irq);
1141cdb3bebSSED4906
1151cdb3bebSSED4906 SdhciBus* bus = new(std::nothrow) SdhciBus(_regs, irq, true);
1161cdb3bebSSED4906
1171cdb3bebSSED4906 status_t status = B_NO_MEMORY;
1181cdb3bebSSED4906 if (bus != NULL)
1191cdb3bebSSED4906 status = bus->InitCheck();
1201cdb3bebSSED4906
1211cdb3bebSSED4906 if (status != B_OK) {
1221cdb3bebSSED4906 if (bus != NULL)
1231cdb3bebSSED4906 delete bus;
1241cdb3bebSSED4906 else
1251cdb3bebSSED4906 delete_area(regs_area);
1261cdb3bebSSED4906 return status;
1271cdb3bebSSED4906 }
1281cdb3bebSSED4906
1291cdb3bebSSED4906 // Store the created object as a cookie, allowing users of the bus to
1301cdb3bebSSED4906 // locate it.
1311cdb3bebSSED4906 *bus_cookie = bus;
1321cdb3bebSSED4906
1331cdb3bebSSED4906 return status;
1341cdb3bebSSED4906 }
1351cdb3bebSSED4906
1361cdb3bebSSED4906 status_t
register_child_devices_acpi(void * cookie)1371cdb3bebSSED4906 register_child_devices_acpi(void* cookie)
1381cdb3bebSSED4906 {
1391cdb3bebSSED4906 CALLED();
1401cdb3bebSSED4906 SdhciDevice* context = (SdhciDevice*)cookie;
1411cdb3bebSSED4906 device_node* parent = gDeviceManager->get_parent_node(context->fNode);
1421cdb3bebSSED4906 acpi_device_module_info* acpi;
1431cdb3bebSSED4906 acpi_device* device;
1441cdb3bebSSED4906
1451cdb3bebSSED4906 gDeviceManager->get_driver(parent, (driver_module_info**)&acpi,
1461cdb3bebSSED4906 (void**)&device);
1471cdb3bebSSED4906
1481cdb3bebSSED4906 TRACE("register_child_devices\n");
1491cdb3bebSSED4906
1501cdb3bebSSED4906 char prettyName[25];
1511cdb3bebSSED4906
1521cdb3bebSSED4906 sprintf(prettyName, "SDHC bus");
1531cdb3bebSSED4906 device_attr attrs[] = {
1541cdb3bebSSED4906 // properties of this controller for mmc bus manager
1551cdb3bebSSED4906 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = prettyName } },
1561cdb3bebSSED4906 { B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
1571cdb3bebSSED4906 {.string = MMC_BUS_MODULE_NAME} },
1581cdb3bebSSED4906 { B_DEVICE_BUS, B_STRING_TYPE, {.string = "mmc"} },
1591cdb3bebSSED4906
1601cdb3bebSSED4906 // DMA properties
1611cdb3bebSSED4906 // The high alignment is to force access only to complete sectors
1621cdb3bebSSED4906 // These constraints could be removed by using ADMA which allows
1631cdb3bebSSED4906 // use of the full 64bit address space and can do scatter-gather.
1641cdb3bebSSED4906 { B_DMA_ALIGNMENT, B_UINT32_TYPE, { .ui32 = 511 }},
1651cdb3bebSSED4906 { B_DMA_HIGH_ADDRESS, B_UINT64_TYPE, { .ui64 = 0x100000000LL }},
1661cdb3bebSSED4906 { B_DMA_BOUNDARY, B_UINT32_TYPE, { .ui32 = (1 << 19) - 1 }},
1671cdb3bebSSED4906 { B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE, { .ui32 = 1 }},
1681cdb3bebSSED4906 { B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE, { .ui32 = (1 << 10) - 1 }},
1691cdb3bebSSED4906
1701cdb3bebSSED4906 // private data to identify device
1711cdb3bebSSED4906 { NULL }
1721cdb3bebSSED4906 };
1731cdb3bebSSED4906 device_node* node;
1741cdb3bebSSED4906 if (gDeviceManager->register_node(context->fNode,
1751cdb3bebSSED4906 SDHCI_ACPI_MMC_BUS_MODULE_NAME, attrs, NULL,
1761cdb3bebSSED4906 &node) != B_OK)
1771cdb3bebSSED4906 return B_BAD_VALUE;
1781cdb3bebSSED4906 return B_OK;
1791cdb3bebSSED4906 }
1801cdb3bebSSED4906
1811cdb3bebSSED4906 float
supports_device_acpi(device_node * parent)1821cdb3bebSSED4906 supports_device_acpi(device_node* parent)
1831cdb3bebSSED4906 {
1841cdb3bebSSED4906 const char* hid;
1851cdb3bebSSED4906 const char* uid;
1861cdb3bebSSED4906 uint32 type;
1871cdb3bebSSED4906
1881cdb3bebSSED4906 if (gDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, &type, false)
1891cdb3bebSSED4906 || type != ACPI_TYPE_DEVICE) {
1901cdb3bebSSED4906 return 0.0f;
1911cdb3bebSSED4906 }
1921cdb3bebSSED4906
1931cdb3bebSSED4906 if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &hid, false)) {
1941cdb3bebSSED4906 TRACE("No hid attribute\n");
1951cdb3bebSSED4906 return 0.0f;
1961cdb3bebSSED4906 }
1971cdb3bebSSED4906
1981cdb3bebSSED4906 if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_UID_ITEM, &uid, false)) {
1991cdb3bebSSED4906 TRACE("No uid attribute\n");
2001cdb3bebSSED4906 return 0.0f;
2011cdb3bebSSED4906 }
2021cdb3bebSSED4906
2031cdb3bebSSED4906 TRACE("supports_device(hid:%s uid:%s)\n", hid, uid);
2041cdb3bebSSED4906
2051cdb3bebSSED4906 if (!(strcmp(hid, "80860F14") == 0
2061cdb3bebSSED4906 || strcmp(hid, "80860F16") == 0
2071cdb3bebSSED4906 || strcmp(hid, "80865ACA") == 0
2081cdb3bebSSED4906 || strcmp(hid, "80865AD0") == 0
2091cdb3bebSSED4906 || strcmp(hid, "INT33C6") == 0
2101cdb3bebSSED4906 || strcmp(hid, "INT3436") == 0
2111cdb3bebSSED4906 || strcmp(hid, "INT344D") == 0
2121cdb3bebSSED4906 || strcmp(hid, "INT33BB") == 0
2131cdb3bebSSED4906 || strcmp(hid, "NXP0003") == 0
2141cdb3bebSSED4906 || strcmp(hid, "RKCP0D40") == 0
2151cdb3bebSSED4906 || strcmp(hid, "PNP0D40") == 0))
2161cdb3bebSSED4906 return 0.0f;
2171cdb3bebSSED4906
2181cdb3bebSSED4906 acpi_device_module_info* acpi;
2191cdb3bebSSED4906 acpi_device* device;
2201cdb3bebSSED4906 gDeviceManager->get_driver(parent, (driver_module_info**)&acpi,
2211cdb3bebSSED4906 (void**)&device);
2221cdb3bebSSED4906 TRACE("SDHCI Device found! hid: %s, uid: %s\n", hid, uid);
2231cdb3bebSSED4906
2241cdb3bebSSED4906 return 0.8f;
2251cdb3bebSSED4906 }
2261cdb3bebSSED4906
2271cdb3bebSSED4906 // Device node registered for each SD slot. It implements the MMC operations so
2281cdb3bebSSED4906 // the bus manager can use it to communicate with SD cards.
2291cdb3bebSSED4906 mmc_bus_interface gSDHCIACPIDeviceModule = {
2301cdb3bebSSED4906 .info = {
2311cdb3bebSSED4906 .info = {
2321cdb3bebSSED4906 .name = SDHCI_ACPI_MMC_BUS_MODULE_NAME,
2331cdb3bebSSED4906 },
2341cdb3bebSSED4906
2351cdb3bebSSED4906 .init_driver = init_bus_acpi,
2361cdb3bebSSED4906 .uninit_driver = uninit_bus,
2371cdb3bebSSED4906 .device_removed = bus_removed,
2381cdb3bebSSED4906 },
2391cdb3bebSSED4906
2401cdb3bebSSED4906 .set_clock = set_clock,
2411cdb3bebSSED4906 .execute_command = execute_command,
2421cdb3bebSSED4906 .do_io = do_io,
2431cdb3bebSSED4906 .set_scan_semaphore = set_scan_semaphore,
2441cdb3bebSSED4906 .set_bus_width = set_bus_width,
2451cdb3bebSSED4906 };
246