coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
elog.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <device/mmio.h>
4 #include <device/pci_ops.h>
5 #include <elog.h>
6 #include <intelblocks/xhci.h>
7 #include <soc/pci_devs.h>
8 #include <stdint.h>
9 
10 /* Wake on disconnect enable */
11 #define XHCI_STATUS_WDE (1 << 26)
12 /* Wake on connect enable */
13 #define XHCI_STATUS_WCE (1 << 25)
14 /* Port link status change */
15 #define XHCI_STATUS_PLC (1 << 22)
16 /* Connect status change */
17 #define XHCI_STATUS_CSC (1 << 17)
18 /* Port link status */
19 #define XHCI_STATUS_PLS_SHIFT (5)
20 #define XHCI_STATUS_PLS_MASK (0xF << XHCI_STATUS_PLS_SHIFT)
21 #define XHCI_STATUS_PLS_RESUME (15 << XHCI_STATUS_PLS_SHIFT)
22 
23 static bool xhci_csc_set(uint32_t port_status)
24 {
25  return !!(port_status & XHCI_STATUS_CSC);
26 }
27 
28 static bool xhci_wake_capable(uint32_t port_status)
29 {
30  return !!((port_status & XHCI_STATUS_WCE) |
31  (port_status & XHCI_STATUS_WDE));
32 }
33 
34 static bool xhci_plc_set(uint32_t port_status)
35 {
36  return !!(port_status & XHCI_STATUS_PLC);
37 }
38 
39 static bool xhci_resume(uint32_t port_status)
40 {
41  return (port_status & XHCI_STATUS_PLS_MASK) == XHCI_STATUS_PLS_RESUME;
42 }
43 
44 /*
45  * Check if a particular USB port caused wake by:
46  * 1. Change in connect/disconnect status (if enabled)
47  * 2. USB device activity
48  *
49  * Params:
50  * base : MMIO address of first port.
51  * num : Number of ports.
52  * event : Event that needs to be added in case wake source is found.
53  *
54  * Return value:
55  * true : Wake source was found.
56  * false : Wake source was not found.
57  */
58 static bool xhci_port_wake_check(uintptr_t base, uint8_t num, uint8_t host_event, uint8_t event)
59 {
60  uint32_t i, port_status;
61  bool found = false;
62 
63  for (i = 0; i < num; i++, base += 0x10) {
64  /* Read port status and control register for the port. */
65  port_status = read32((void *)base);
66 
67  /* Ensure that the status is not all 1s. */
68  if (port_status == 0xffffffff)
69  continue;
70 
71  /*
72  * Check if CSC bit is set and port is capable of wake on
73  * connect/disconnect to identify if the port caused wake
74  * event for USB attach/detach.
75  */
76  if (xhci_csc_set(port_status) &&
77  xhci_wake_capable(port_status)) {
78  elog_add_event_wake(host_event, 0);
79  elog_add_event_wake(event, i + 1);
80  found = true;
81  continue;
82  }
83 
84  /*
85  * Check if PLC is set and PLS indicates resume to identify if
86  * the port caused wake event for USB activity.
87  */
88  if (xhci_plc_set(port_status) &&
89  xhci_resume(port_status)) {
90  elog_add_event_wake(host_event, 0);
91  elog_add_event_wake(event, i + 1);
92  found = true;
93  }
94  }
95  return found;
96 }
97 
98 bool xhci_update_wake_event(const struct xhci_wake_info *wake_info,
99  size_t wake_info_count)
100 {
101  const struct xhci_usb_info *usb_info;
102  uintptr_t mmio_base;
103  bool event_found = false;
104  size_t i;
105 
106  for (i = 0; i < wake_info_count; ++i) {
107  /* Assumes BAR0 is MBAR */
108  pci_devfn_t devfn = PCI_DEV(0, PCI_SLOT(wake_info[i].xhci_dev),
109  PCI_FUNC(wake_info[i].xhci_dev));
110  mmio_base = pci_s_read_config32(devfn, PCI_BASE_ADDRESS_0);
111  mmio_base &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
112  usb_info = soc_get_xhci_usb_info(wake_info[i].xhci_dev);
113 
114  /* Check USB2 port status & control registers */
117  wake_info[i].elog_wake_type_host,
119  event_found = true;
120 
121  /* Check USB3 port status & control registers */
124  wake_info[i].elog_wake_type_host,
126  event_found = true;
127  }
128 
129  return event_found;
130 }
static uint32_t read32(const void *addr)
Definition: mmio.h:22
#define ELOG_WAKE_SOURCE_PME_XHCI_USB_3
Definition: elog.h:181
#define ELOG_WAKE_SOURCE_PME_XHCI_USB_2
Definition: elog.h:180
int elog_add_event_wake(u8 source, u32 instance)
Definition: elog.c:883
#define PCI_BASE_ADDRESS_MEM_ATTR_MASK
Definition: pci_def.h:77
#define PCI_FUNC(devfn)
Definition: pci_def.h:550
#define PCI_BASE_ADDRESS_0
Definition: pci_def.h:63
#define PCI_SLOT(devfn)
Definition: pci_def.h:549
static __always_inline uint32_t pci_s_read_config32(pci_devfn_t dev, uint16_t reg)
Definition: pci_io_cfg.h:92
#define PCI_DEV(SEGBUS, DEV, FN)
Definition: pci_type.h:14
u32 pci_devfn_t
Definition: pci_type.h:8
uintptr_t base
Definition: uart.c:17
static const struct xhci_usb_info usb_info
Definition: xhci.c:22
const struct xhci_usb_info * soc_get_xhci_usb_info(pci_devfn_t xhci_dev)
Definition: xhci.c:36
static bool xhci_wake_capable(uint32_t port_status)
Definition: elog.c:28
#define XHCI_STATUS_PLS_MASK
Definition: elog.c:20
static bool xhci_port_wake_check(uintptr_t base, uint8_t num, uint8_t host_event, uint8_t event)
Definition: elog.c:58
static bool xhci_resume(uint32_t port_status)
Definition: elog.c:39
static bool xhci_csc_set(uint32_t port_status)
Definition: elog.c:23
#define XHCI_STATUS_PLC
Definition: elog.c:15
#define XHCI_STATUS_CSC
Definition: elog.c:17
#define XHCI_STATUS_WCE
Definition: elog.c:13
bool xhci_update_wake_event(const struct xhci_wake_info *wake_info, size_t wake_info_count)
Definition: elog.c:98
static bool xhci_plc_set(uint32_t port_status)
Definition: elog.c:34
#define XHCI_STATUS_WDE
Definition: elog.c:11
#define XHCI_STATUS_PLS_RESUME
Definition: elog.c:21
unsigned int uint32_t
Definition: stdint.h:14
unsigned long uintptr_t
Definition: stdint.h:21
unsigned char uint8_t
Definition: stdint.h:8
uint32_t usb3_port_status_reg
Definition: xhci.h:20
uint32_t usb2_port_status_reg
Definition: xhci.h:18
uint32_t num_usb2_ports
Definition: xhci.h:19
uint32_t num_usb3_ports
Definition: xhci.h:21
uint8_t elog_wake_type_host
Definition: xhci.h:31