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