123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- MODULE UsbEhciZynq; (** AUTHOR "Timothée Martiel"; PURPOSE "Instal EHCI driver on Zynq systems."; *)
- (**
- * The main purpose of this module is to install the EHCI driver on Zynq SoCs.
- * Call
- * UsbEhciZynq.Install ~
- * to install the driver and unload this module ro remove it.
- *
- * This module also patches the behavior of the EHCI driver to the Zynq host controller. The host controller is
- * not fully compliant with the EHCI specifications and has On-The-Go features that require additional steps in
- * the initialization. These differences are accounted for in the EnhancedHostController object provided here.
- *)
- IMPORT SYSTEM, Platform, BootConfig, Machine, Objects, Kernel, KernelLog, Debug := UsbDebug, Usbdi, Usb, UsbHcdi, UsbEhci, UsbEhciPhy;
- CONST
- HcUlpiViewport = 30H;
- HcOtgSc = 64H;
- HcUsbMode = 68H;
- TTCtrl * = 1CH;
- (* HcUsbMode bits *)
- ModeHost = {0, 1};
- ModeDevice = {1};
- ModeIdle = {};
-
- (* HcOtgSc bits *)
- OtgScId = 8;
- OtgScIdPu = 5;
- (* HcPortSc bits *)
- PortScPortSpeed = {26, 27};
- PortScPortSpeedLow = {26};
- PortScPortSpeedFull = {};
- PortScPortSpeedHigh = {27};
- TYPE
- (** Zynq-specific EHCI driver. Uses the main implementation and adds Zynq-specific initialization code where needed. *)
- EnhancedHostController = OBJECT (UsbEhci.EnhancedHostController)
- VAR
- phyResetGpio: LONGINT;
- PROCEDURE GetPortStatus * (port : LONGINT; ack : BOOLEAN) : SET;
- VAR
- status, dword: SET;
- BEGIN
- status := GetPortStatus^(port, ack);
- dword := SYSTEM.VAL(SET, SYSTEM.GET32(ports[port]));
- IF UsbHcdi.PortStatusEnabled * status # {} THEN
- IF dword * PortScPortSpeed = PortScPortSpeedHigh THEN
- status := status + UsbHcdi.PortStatusHighSpeed
- ELSIF dword * PortScPortSpeed = PortScPortSpeedLow THEN
- status := status + UsbHcdi.PortStatusLowSpeed
- ELSIF dword * PortScPortSpeed = PortScPortSpeedFull THEN
- status := status + UsbHcdi.PortStatusFullSpeed
- END
- END;
- RETURN status
- END GetPortStatus;
- PROCEDURE HasCompanion * (): BOOLEAN;
- BEGIN
- RETURN FALSE
- END HasCompanion;
- PROCEDURE ResetAndEnablePort (port: LONGINT): BOOLEAN;
- VAR
- dword: SET;
- res: BOOLEAN;
- BEGIN
- res := ResetAndEnablePort^(port);
- IF res THEN
- dword := SYSTEM.VAL(SET, SYSTEM.GET32(iobase + HcUsbMode));
- dword := dword + ModeHost;
- SYSTEM.PUT32(iobase + HcUsbMode, dword);
- END;
- RETURN res
- END ResetAndEnablePort;
- (* Reset the host controller. Note: This will NOT assert reset on the USB downstream ports. *)
- PROCEDURE HardwareReset() : BOOLEAN;
- VAR
- viewportInit: ARRAY 32 OF CHAR;
- viewport: LONGINT;
- dword: SET;
- res: BOOLEAN;
- BEGIN
- (* Set mode to host *)
- SYSTEM.GET(iobase + HcUsbMode, dword);
- SYSTEM.PUT(iobase + HcUsbMode, dword + ModeHost);
- res := HardwareReset^();
- IF res THEN
- (* Set mode to host *)
- SYSTEM.GET(iobase + HcUsbMode, dword);
- SYSTEM.PUT(iobase + HcUsbMode, dword + ModeHost);
- SYSTEM.GET(iobase + HcOtgSc, dword);
- INCL(dword, 7);
- INCL(dword, 5);
- SYSTEM.PUT(iobase + HcOtgSc, dword);
- (* Try putting port in full-speed mode *)
- SYSTEM.PUT(iobase + UsbEhci.HcPortSc, {8});
- END;
- IF ~res THEN
- RETURN FALSE
- END;
- Machine.GetConfig('UsbViewportInit', viewportInit);
- IF viewportInit = '0' THEN
- viewport := 0
- ELSE
- viewport := iobase + HcUlpiViewport
- END;
- RETURN UsbEhciPhy.Init(viewport, phyResetGpio)
- END HardwareReset;
- (*
- * Start the host controller.
- * This will:
- * - enable interrupts for the host controller and install a interrupt handler
- * - set the addresses for the periodic and asynchronous lists
- * - turn the host controller on
- * - route all ports to the EHCI controller
- * - power on all ports of the root hub
- *)
- PROCEDURE Start():BOOLEAN;
- VAR dword : SET;
- res: BOOLEAN;
- BEGIN
- res := Start^();
- IF ~res THEN RETURN FALSE END;
- (* Clear interrupts *)
- SYSTEM.PUT32(iobase + UsbEhci.HcUsbSts, 0);
-
- (* Enable all interrupts except the frame list rollover interrupt *)
- dword := SYSTEM.VAL(SET, SYSTEM.GET32(iobase + UsbEhci.HcUsbIntr));
- interruptsEnabled := dword + {0 .. 5} - UsbEhci.StsFrameListRollover + {19} (* UPI: triggered by iTD IOC *);
- SYSTEM.PUT32(iobase + UsbEhci.HcUsbIntr, interruptsEnabled);
- (* Set the TT HubAddress to 7FH *)
- (*SYSTEM.PUT32(iobase + 1CH, SYSTEM.VAL(SET, SYSTEM.GET32(iobase + (* TTCTRL *)1CH)) + {24 .. 30});*)
- RETURN TRUE
- END Start;
- PROCEDURE Schedule * (transfer: UsbHcdi.TransferToken);
- VAR
- address: LONGINT;
- BEGIN
- IF (transfer.pipe.speed = UsbHcdi.LowSpeed) OR (transfer.pipe.speed = UsbHcdi.FullSpeed) THEN
- address := transfer.pipe.device(Usb.UsbDevice).ttAddress;
- IF address = 0 THEN
- address := transfer.pipe.address
- END;
- END;
- SYSTEM.PUT32(iobase + TTCtrl, LSH(address, 24));
- Schedule^(transfer);
- END Schedule;
- END EnhancedHostController;
- VAR
- i: LONGINT;
- (**
- * Initializes and install the EHCI host controller driver on the host controller mapped at address iobase
- * and using interrupt number irq.
- *)
- PROCEDURE Init(irq, phyResetGpio: LONGINT; iobase: ADDRESS);
- CONST
- (* Some part of the EHCI driver is PCI-related. These are dummy values for it. *)
- bus = 0;
- device = 0;
- function = 0;
- VAR
- hostController: EnhancedHostController;
- BEGIN
- NEW(hostController, bus, device, function);
- hostController.phyResetGpio := phyResetGpio;
- IF hostController.Init(iobase, irq) THEN
- KernelLog.String("UsbEhci: Initialised USB Enhanced Host Controller."); KernelLog.Ln;
- UsbHcdi.RegisterHostController(hostController, UsbEhci.Description);
- ELSE
- KernelLog.String("UsbEhci: Cannot init USB Enhanced Host Controller."); KernelLog.Ln;
- END;
- END Init;
- PROCEDURE Install*;
- (* Load module *)
- END Install;
- BEGIN
- IF BootConfig.GetBoolValue("UsbEnable0") THEN
- KernelLog.Enter; KernelLog.String("Initializing USB"); KernelLog.Int(0, 0); KernelLog.String(", Address = "); KernelLog.Address(Platform.UsbBase[0]); KernelLog.String(", IRQ = "); KernelLog.Int(Platform.UsbIrq[0], 0); KernelLog.String(", PHY Reset = "); KernelLog.Int(BootConfig.GetIntValue("UsbPhyRstGpio0"), 0); KernelLog.Exit;
- Init(Platform.UsbIrq[0], BootConfig.GetIntValue("UsbPhyRstGpio0"), Platform.UsbBase[0])
- END;
- IF BootConfig.GetBoolValue("UsbEnable1") THEN
- KernelLog.Enter; KernelLog.String("Initializing USB"); KernelLog.Int(1, 0); KernelLog.String(", Address = "); KernelLog.Address(Platform.UsbBase[1]); KernelLog.String(", IRQ = "); KernelLog.Int(Platform.UsbIrq[1], 0); KernelLog.String(", PHY Reset = "); KernelLog.Int(BootConfig.GetIntValue("UsbPhyRstGpio1"), 0); KernelLog.Exit;
- Init(Platform.UsbIrq[1], BootConfig.GetIntValue("UsbPhyRstGpio1"), Platform.UsbBase[1])
- END
- END UsbEhciZynq.
|