/ src / device / xhci_resource.c
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  }