summaryrefslogtreecommitdiff
path: root/sys/src/9/omap/usbehciomap.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/omap/usbehciomap.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/omap/usbehciomap.c')
-rwxr-xr-xsys/src/9/omap/usbehciomap.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/sys/src/9/omap/usbehciomap.c b/sys/src/9/omap/usbehciomap.c
new file mode 100755
index 000000000..a1592bb54
--- /dev/null
+++ b/sys/src/9/omap/usbehciomap.c
@@ -0,0 +1,224 @@
+/*
+ * OMAP3-specific code for
+ * USB Enhanced Host Controller Interface (EHCI) driver
+ * High speed USB 2.0.
+ */
+
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "../port/usb.h"
+#include "usbehci.h"
+
+static Ctlr* ctlrs[Nhcis];
+
+static void
+ehcireset(Ctlr *ctlr)
+{
+ Eopio *opio;
+ int i;
+
+ ilock(ctlr);
+ dprint("ehci %#p reset\n", ctlr->capio);
+ opio = ctlr->opio;
+
+ /*
+ * Turn off legacy mode. Some controllers won't
+ * interrupt us as expected otherwise.
+ */
+ ehcirun(ctlr, 0);
+
+ /* clear high 32 bits of address signals if it's 64 bits capable.
+ * This is probably not needed but it does not hurt and others do it.
+ */
+ if((ctlr->capio->capparms & C64) != 0){
+ dprint("ehci: 64 bits\n");
+ opio->seg = 0;
+ }
+
+ if(ehcidebugcapio != ctlr->capio){
+ opio->cmd |= Chcreset; /* controller reset */
+ coherence();
+ for(i = 0; i < 100; i++){
+ if((opio->cmd & Chcreset) == 0)
+ break;
+ delay(1);
+ }
+ if(i == 100)
+ print("ehci %#p controller reset timed out\n", ctlr->capio);
+ }
+
+ /* requesting more interrupts per µframe may miss interrupts */
+ opio->cmd |= Citc8; /* 1 intr. per ms */
+ coherence();
+ switch(opio->cmd & Cflsmask){
+ case Cfls1024:
+ ctlr->nframes = 1024;
+ break;
+ case Cfls512:
+ ctlr->nframes = 512;
+ break;
+ case Cfls256:
+ ctlr->nframes = 256;
+ break;
+ default:
+ panic("ehci: unknown fls %ld", opio->cmd & Cflsmask);
+ }
+ coherence();
+ dprint("ehci: %d frames\n", ctlr->nframes);
+ iunlock(ctlr);
+}
+
+static void
+setdebug(Hci*, int d)
+{
+ ehcidebug = d;
+}
+
+static void
+shutdown(Hci *hp)
+{
+ int i;
+ Ctlr *ctlr;
+ Eopio *opio;
+
+ ctlr = hp->aux;
+ ilock(ctlr);
+ opio = ctlr->opio;
+ opio->cmd |= Chcreset; /* controller reset */
+ coherence();
+ for(i = 0; i < 100; i++){
+ if((opio->cmd & Chcreset) == 0)
+ break;
+ delay(1);
+ }
+ if(i >= 100)
+ print("ehci %#p controller reset timed out\n", ctlr->capio);
+ delay(100);
+ ehcirun(ctlr, 0);
+ opio->frbase = 0;
+ coherence();
+ iunlock(ctlr);
+}
+
+/*
+ * omap3-specific ehci code
+ */
+
+enum {
+ /* opio->insn[5] bits */
+ Control = 1<<31, /* set to start access, cleared when done */
+ Write = 2<<22,
+ Read = 3<<22,
+ Portsh = 24,
+ Regaddrsh = 16, /* 0x2f means use extended reg addr */
+ Eregaddrsh = 8,
+
+ /* phy reg addresses */
+ Funcctlreg = 4,
+ Ifcctlreg = 7,
+
+ Phystppullupoff = 0x90, /* on is 0x10 */
+
+ Phyrstport2 = 147, /* gpio # */
+
+};
+
+static void
+wrulpi(Eopio *opio, int port, int reg, uchar data)
+{
+ opio->insn[5] = Control | port << Portsh | Write | reg << Regaddrsh |
+ data;
+ coherence();
+ /*
+ * this seems contrary to the skimpy documentation in the manual
+ * but inverting the test hangs forever.
+ */
+ while (!(opio->insn[5] & Control))
+ ;
+}
+
+static int
+reset(Hci *hp)
+{
+ Ctlr *ctlr;
+ Ecapio *capio;
+ Eopio *opio;
+ Uhh *uhh;
+ static int beenhere;
+
+ if (beenhere)
+ return -1;
+ beenhere = 1;
+
+ if(getconf("*nousbehci") != nil || probeaddr(PHYSEHCI) < 0)
+ return -1;
+
+ ctlr = smalloc(sizeof(Ctlr));
+ /*
+ * don't bother with vmap; i/o space is all mapped anyway,
+ * and a size less than 1MB will blow an assertion in mmukmap.
+ */
+ ctlr->capio = capio = (Ecapio *)PHYSEHCI;
+ ctlr->opio = opio = (Eopio*)((uintptr)capio + (capio->cap & 0xff));
+
+ hp->aux = ctlr;
+ hp->port = (uintptr)ctlr->capio;
+ hp->irq = 77;
+ hp->nports = capio->parms & Cnports;
+
+ ddprint("echi: %s, ncc %lud npcc %lud\n",
+ capio->parms & 0x10000 ? "leds" : "no leds",
+ (capio->parms >> 12) & 0xf, (capio->parms >> 8) & 0xf);
+ ddprint("ehci: routing %s, %sport power ctl, %d ports\n",
+ capio->parms & 0x40 ? "explicit" : "automatic",
+ capio->parms & 0x10 ? "" : "no ", hp->nports);
+
+ ehcireset(ctlr);
+ ehcimeminit(ctlr);
+
+ /* omap35-specific set up */
+ /* bit 5 `must be set to 1 for proper behavior', spruf98d §23.2.6.7.17 */
+ opio->insn[4] |= 1<<5;
+ coherence();
+
+ /* insn[5] is for both utmi and ulpi, depending on hostconfig mode */
+ uhh = (Uhh *)PHYSUHH;
+ if (uhh->hostconfig & P1ulpi_bypass) { /* utmi port 1 active */
+ /* not doing this */
+ iprint("usbehci: bypassing ulpi on port 1!\n");
+ opio->insn[5] &= ~(MASK(4) << 13);
+ opio->insn[5] |= 1 << 13; /* select port 1 */
+ coherence();
+ } else { /* ulpi port 1 active */
+ /* TODO may need to reset gpio port2 here */
+
+ /* disable integrated stp pull-up resistor */
+ wrulpi(opio, 1, Ifcctlreg, Phystppullupoff);
+
+ /* force phy to `high-speed' */
+ wrulpi(opio, 1, Funcctlreg, 0x40);
+ }
+
+ /*
+ * Linkage to the generic HCI driver.
+ */
+ ehcilinkage(hp);
+ hp->shutdown = shutdown;
+ hp->debug = setdebug;
+
+ intrenable(78, hp->interrupt, hp, UNKNOWN, "usbtll");
+ intrenable(92, hp->interrupt, hp, UNKNOWN, "usb otg");
+ intrenable(93, hp->interrupt, hp, UNKNOWN, "usb otg dma");
+ return 0;
+}
+
+void
+usbehcilink(void)
+{
+ addhcitype("ehci", reset);
+}