diff options
author | Patrick Georgi <pgeorgi@google.com> | 2015-03-10 12:51:31 +0100 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2015-04-18 08:42:04 +0200 |
commit | e17d57ecabe02d0c95ebe0f41c7e1fee5f2804c9 (patch) | |
tree | 0ddd9e6951b153a43662ddd7b8e65555e386e780 /payloads/libpayload/drivers | |
parent | 49a80ce47507dd7be309baad880a9d93704bd675 (diff) |
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>
Diffstat (limited to 'payloads/libpayload/drivers')
-rw-r--r-- | payloads/libpayload/drivers/udc/chipidea.c | 48 |
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; } } |