summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Georgi <pgeorgi@google.com>2015-03-10 12:51:31 +0100
committerPatrick Georgi <pgeorgi@google.com>2015-04-18 08:42:04 +0200
commite17d57ecabe02d0c95ebe0f41c7e1fee5f2804c9 (patch)
tree0ddd9e6951b153a43662ddd7b8e65555e386e780
parent49a80ce47507dd7be309baad880a9d93704bd675 (diff)
downloadcoreboot-e17d57ecabe02d0c95ebe0f41c7e1fee5f2804c9.tar.xz
libpayload: Enforce strict packet handling order in ChipIdea driver
First handle IN packets, then OUT packets and finally SETUP packets. This makes OS X happy. It isn't implemented as the data sheet recommends but it avoids implementing a state machine and should always produce observable effects identical to that of the stateful solution. BRANCH=none BUG=none TEST=`fastboot getvar version` on OSX works Change-Id: Ic7b27387771d6a7794fba12fc822fccc48770ea8 Signed-off-by: Patrick Georgi <pgeorgi@chromium.org> Original-Commit-Id: f0e59547519d50b1d34f6abdc6132330125f94f3 Original-Change-Id: Iada1cff011f11e7d5cb1a1b34896ab590f488ec7 Original-Signed-off-by: Patrick Georgi <pgeorgi@chromium.org> Original-Reviewed-on: https://chromium-review.googlesource.com/258062 Original-Reviewed-by: Furquan Shaikh <furquan@chromium.org> Reviewed-on: http://review.coreboot.org/9788 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
-rw-r--r--payloads/libpayload/drivers/udc/chipidea.c48
1 files changed, 36 insertions, 12 deletions
diff --git a/payloads/libpayload/drivers/udc/chipidea.c b/payloads/libpayload/drivers/udc/chipidea.c
index a399e8cd96..8299a08859 100644
--- a/payloads/libpayload/drivers/udc/chipidea.c
+++ b/payloads/libpayload/drivers/udc/chipidea.c
@@ -359,30 +359,54 @@ static int chipidea_poll(struct usbdev_ctrl *this)
}
if (sts & (USBSTS_UEI | USBSTS_UI)) {
- uint32_t bitmap = readl(&p->opreg->epsetupstat);
- int ep = 0;
+ uint32_t bitmap;
+ int ep;
+
+ /* This slightly deviates from the recommendation in the
+ * data sheets, but the strict ordering is to simplify
+ * handling control transfers, which are initialized in
+ * the third step with a SETUP packet, then proceed in
+ * the next poll loop with in transfers (either data or
+ * status phase), then optionally out transfers (status
+ * phase).
+ */
+
+ /* in transfers */
+ bitmap = (readl(&p->opreg->epcomplete) >> 16) & 0xffff;
+ ep = 0;
while (bitmap) {
if (bitmap & 1) {
- debug("incoming packet on EP %d (setup)\n", ep);
- start_setup(this, ep);
+ debug("incoming packet on EP %d (in)\n", ep);
+ handle_endpoint(this, ep, 1);
+ clear_ep(p, ep & 0xf, 1);
+ }
+ bitmap >>= 1;
+ ep++;
+ }
+
+ /* out transfers */
+ bitmap = readl(&p->opreg->epcomplete) & 0xffff;
+ ep = 0;
+ while (bitmap) {
+ if (bitmap & 1) {
+ debug("incoming packet on EP %d (out)\n", ep);
+ handle_endpoint(this, ep, 0);
+ clear_ep(p, ep, 0);
}
bitmap >>= 1;
ep++;
}
- bitmap = readl(&p->opreg->epcomplete);
+
+ /* setup transfers */
+ bitmap = readl(&p->opreg->epsetupstat);
ep = 0;
- int dir_in = 0;
while (bitmap) {
if (bitmap & 1) {
- debug("incoming packet on EP %d (%s)\n",
- ep, dir_in ? "intr/in" : "out");
- handle_endpoint(this, ep & 0xf, dir_in);
- clear_ep(p, ep & 0xf, dir_in);
+ debug("incoming packet on EP %d (setup)\n", ep);
+ start_setup(this, ep);
}
bitmap >>= 1;
ep++;
- if (ep == 16)
- dir_in = 1;
}
}