libpayload: Drop usb_fatal()
[coreboot.git] / payloads / libpayload / drivers / usb / xhci_rh.c
1 /*
2  * This file is part of the libpayload project.
3  *
4  * Copyright (C) 2010 Patrick Georgi
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #define USB_DEBUG
31
32 #include <libpayload.h>
33 #include "xhci_private.h"
34 #include "xhci.h"
35
36 typedef struct {
37         int numports;
38         int *port;
39 } rh_inst_t;
40
41 #define RH_INST(dev) ((rh_inst_t*)(dev)->data)
42
43 static void
44 xhci_rh_enable_port (usbdev_t *dev, int port)
45 {
46         // FIXME: check power situation?
47         // enable slot
48         // attach device context to slot
49         // address device
50 }
51
52 /* disable root hub */
53 static void
54 xhci_rh_disable_port (usbdev_t *dev, int port)
55 {
56 }
57
58 static void
59 xhci_rh_scanport (usbdev_t *dev, int port)
60 {
61         // clear CSC
62         int val = XHCI_INST (dev->controller)->opreg->prs[port].portsc;
63         val &= PORTSC_RW_MASK;
64         val |= PORTSC_CSC;
65         XHCI_INST (dev->controller)->opreg->prs[port].portsc = val;
66
67         debug("device attach status on port %x: %x\n", port, XHCI_INST (dev->controller)->opreg->prs[port].portsc & PORTSC_CCS);
68 }
69
70 static int
71 xhci_rh_report_port_changes (usbdev_t *dev)
72 {
73         int i;
74         // no change
75         if (!(XHCI_INST (dev->controller)->opreg->usbsts & USBSTS_PCD))
76                 return -1;
77
78         for (i = 0; i < RH_INST (dev)->numports; i++) {
79                 if (XHCI_INST (dev->controller)->opreg->prs[i].portsc & PORTSC_CSC) {
80                         debug("found connect status change on port %d\n", i);
81                         return i;
82                 }
83         }
84
85         return -1; // shouldn't ever happen
86 }
87
88 static void
89 xhci_rh_destroy (usbdev_t *dev)
90 {
91         int i;
92         for (i = 0; i < RH_INST (dev)->numports; i++)
93                 xhci_rh_disable_port (dev, i);
94         free (RH_INST (dev));
95 }
96
97 static void
98 xhci_rh_poll (usbdev_t *dev)
99 {
100         int port;
101         while ((port = xhci_rh_report_port_changes (dev)) != -1)
102                 xhci_rh_scanport (dev, port);
103 }
104
105 void
106 xhci_rh_init (usbdev_t *dev)
107 {
108         int i;
109
110         dev->destroy = xhci_rh_destroy;
111         dev->poll = xhci_rh_poll;
112
113         dev->data = malloc (sizeof (rh_inst_t));
114         if (!dev->data)
115                 fatal("Not enough memory for XHCI RH.\n");
116
117         RH_INST (dev)->numports = XHCI_INST (dev->controller)->capreg->MaxPorts;
118         RH_INST (dev)->port = malloc(sizeof(int) * RH_INST (dev)->numports);
119         debug("%d ports registered\n", RH_INST (dev)->numports);
120
121         for (i = 0; i < RH_INST (dev)->numports; i++) {
122                 xhci_rh_enable_port (dev, i);
123                 RH_INST (dev)->port[i] = -1;
124         }
125
126         /* we can set them here because a root hub _really_ shouldn't
127            appear elsewhere */
128         dev->address = 0;
129         dev->hub = -1;
130         dev->port = -1;
131
132         debug("rh init done\n");
133 }