xhci_resource.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 3 #include <arch/mmio.h> 4 #include <console/console.h> 5 #include <device/pci_def.h> 6 #include <device/xhci.h> 7 #include <string.h> 8 9 union xhci_ext_caps_header { 10 uint32_t val; 11 struct { 12 uint32_t cap_id : 8; 13 uint32_t next_ptr : 8; 14 uint32_t reserved : 16; 15 }; 16 }; 17 18 enum cb_err xhci_resource_for_each_ext_cap(const struct resource *res, void *context, 19 void (*callback)(void *context, 20 const struct xhci_ext_cap *cap)) 21 { 22 uint32_t *ext_cap_ptr; 23 uint32_t ext_caps_word_offset; 24 union xhci_ext_caps_header header; 25 struct xhci_ext_cap cap; 26 27 if (!res || !callback) 28 return CB_ERR_ARG; 29 30 if (!(res->flags & IORESOURCE_ASSIGNED)) { 31 printk(BIOS_ERR, "%s: BAR is not assigned\n", __func__); 32 return CB_ERR; 33 } 34 35 if (res->limit > 0xFFFFFFFF) { 36 printk(BIOS_ERR, "%s: 64-bit BAR is not supported\n", __func__); 37 return CB_ERR; 38 } 39 40 ext_caps_word_offset = read16(res2mmio(res, XHCI_HCCPARAMS1_XECP, 0)); 41 42 if (!ext_caps_word_offset) { 43 printk(BIOS_ERR, "%s: No extended capabilities defined\n", __func__); 44 return CB_ERR; 45 } 46 47 ext_cap_ptr = res2mmio(res, ext_caps_word_offset << 2, 0); 48 49 while ((uintptr_t)ext_cap_ptr < (uintptr_t)res->limit) { 50 header.val = read32(ext_cap_ptr); 51 52 cap.cap_id = header.cap_id; 53 54 if (header.cap_id == XHCI_ECP_CAP_ID_SUPP) { 55 cap.supported_protocol.reg0 = header.val; 56 cap.supported_protocol.reg1 = read32(ext_cap_ptr + 1); 57 cap.supported_protocol.reg2 = read32(ext_cap_ptr + 2); 58 } 59 60 callback(context, &cap); 61 62 if (!header.next_ptr) 63 break; 64 65 ext_cap_ptr += header.next_ptr; 66 } 67 68 return CB_SUCCESS; 69 } 70 71 struct supported_usb_cap_context { 72 void *context; 73 void (*callback)(void *context, const struct xhci_supported_protocol *data); 74 }; 75 76 static void xhci_supported_usb_cap_handler(void *context, const struct xhci_ext_cap *cap) 77 { 78 const struct xhci_supported_protocol *data; 79 struct supported_usb_cap_context *internal_context = context; 80 81 if (cap->cap_id != XHCI_ECP_CAP_ID_SUPP) 82 return; 83 84 data = &cap->supported_protocol; 85 86 if (memcmp(data->name, "USB ", 4)) { 87 printk(BIOS_DEBUG, "%s: Unknown Protocol: %.*s\n", __func__, 88 (int)sizeof(data->name), data->name); 89 return; 90 } 91 92 internal_context->callback(internal_context->context, data); 93 } 94 95 enum cb_err xhci_resource_for_each_supported_usb_cap( 96 const struct resource *res, void *context, 97 void (*callback)(void *context, const struct xhci_supported_protocol *data)) 98 { 99 struct supported_usb_cap_context internal_context = { 100 .context = context, 101 .callback = callback, 102 }; 103 104 return xhci_resource_for_each_ext_cap(res, &internal_context, 105 xhci_supported_usb_cap_handler); 106 } 107 108 void xhci_print_supported_protocol(const struct xhci_supported_protocol *supported_protocol) 109 { 110 printk(BIOS_DEBUG, "xHCI Supported Protocol:\n"); 111 printk(BIOS_DEBUG, " Major: %#x, Minor: %#x, Protocol: '%.*s'\n", 112 supported_protocol->major_rev, supported_protocol->minor_rev, 113 (int)sizeof(supported_protocol->name), supported_protocol->name); 114 printk(BIOS_DEBUG, " Port Offset: %d, Port Count: %d\n", 115 supported_protocol->port_offset, supported_protocol->port_count); 116 }