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 };