From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wm1-f66.google.com (mail-wm1-f66.google.com [209.85.128.66]) by mx.groups.io with SMTP id smtpd.web11.3789.1588590026924814616 for ; Mon, 04 May 2020 04:00:27 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@nuviainc-com.20150623.gappssmtp.com header.s=20150623 header.b=ZozJY0rH; spf=pass (domain: nuviainc.com, ip: 209.85.128.66, mailfrom: leif@nuviainc.com) Received: by mail-wm1-f66.google.com with SMTP id u127so8510583wmg.1 for ; Mon, 04 May 2020 04:00:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nuviainc-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=k944Qs8BLxJcKqXW4mBLUS09SPFwAod6/ISzsFkLe8E=; b=ZozJY0rHFTJ2C3sa37C/ENF2HfSRPKlwX1b4CUxe9WhQCj0QDFJ59npJdrk7o/beTg JeBSBdx3yhIK1kFIdHqKRDTpZSwSkfmgHQy80KFXP61ZyoUR2wnZZvaflJ/mVDtZpgY9 fFdFj/rj9ixh+qtykWZZMKa8dc4Mud+bZ1oUPI0wBQbuxHUZwqgGj7OvAKzXonQBpWIA JSj4KvQppCHjarvGEq3086bSaHYQcfu6OU2rcGawGQKaviQ9EYToqpRNWj7w/MgC2i3m b+d5o9MLQ6XFlTcPIAjPcjUrZcCQbnJK38gR6WpBP5a6FSBqQS2RGlus7x/gYewvIaIY Bg8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=k944Qs8BLxJcKqXW4mBLUS09SPFwAod6/ISzsFkLe8E=; b=ZWlyAv4bUK589WhmpgleKPamDHVBNziKUPoEaFh/Wh5nf5Z4yOZYvZ5odIZRA9eLTw jClR5yCLybkoPryU9BsazmIlm0zMUKofasO13WTrGxyLcjnRHseTEO5tbKcuiwhet0sN 6BVy5aONSnDf4vs1oWTN9Hgv9wOfXaQ5eALw0KmfV22KTgoa464nYTdfWr/naw3RCl65 2Qg7yhVSLjf26Jvy06qPXvjxxY5Jx0LWL3zVJz9IiU5tFE8S+VhjQItdaP65B7AnWNlw AEBhMRcz0XITRFw7DRgFMnTzjuCPapWF4s0q5d1XB3AGakp9/9u8OCkPNcv8mS/ssSk6 g+3w== X-Gm-Message-State: AGi0PuZjtes3SHJ9DvzdUs4cf9XB83SNbJ3qZmWuCHIqqLjwYYaPMEuX rUinZ8xlb1axaoEj3bGjr5But0m2k/8= X-Google-Smtp-Source: APiQypJZSM6lkWVpqU8Ssg7Luwy2Ijn8upPJp8DviHb1hnngx4+C8eMus5Y2KCzRxWgbKXgnFAWLRA== X-Received: by 2002:a1c:9c0a:: with SMTP id f10mr14075581wme.139.1588590025151; Mon, 04 May 2020 04:00:25 -0700 (PDT) Return-Path: Received: from vanye ([2001:470:1f09:12f0:b26e:bfff:fea9:f1b8]) by smtp.gmail.com with ESMTPSA id s18sm19509763wra.94.2020.05.04.04.00.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2020 04:00:24 -0700 (PDT) Date: Mon, 4 May 2020 12:00:22 +0100 From: "Leif Lindholm" To: Ard Biesheuvel Cc: devel@edk2.groups.io Subject: Re: [PATCH edk2-platforms v3 8/8] Platform/ARM/VExpressPkg: incorporate ISP 1761 USB host driver Message-ID: <20200504110022.GE21486@vanye> References: <20200430171650.24139-1-ard.biesheuvel@arm.com> <20200430171650.24139-9-ard.biesheuvel@arm.com> MIME-Version: 1.0 In-Reply-To: <20200430171650.24139-9-ard.biesheuvel@arm.com> User-Agent: Mutt/1.10.1 (2018-07-13) Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Thu, Apr 30, 2020 at 19:16:49 +0200, Ard Biesheuvel wrote: > Incorporate the ISP 1761 USB host driver from EmbeddedPkg, which is > only used on obsolete ARM development platforms and does not follow > the UEFI driver model. This will allow us to drop it from the core EDK2 > repository. > > Signed-off-by: Ard Biesheuvel > --- > Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc | 2 +- > Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf | 2 +- > Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc | 2 +- > Platform/ARM/VExpressPkg/ArmVExpressPkg.dec | 3 + > Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.c | 636 ++++++++++++++++++++ > Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.h | 123 ++++ > Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf | 39 ++ > 7 files changed, 804 insertions(+), 3 deletions(-) > > diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc > index bee7913feb52..144dd4f8b8e9 100644 > --- a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc > +++ b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc > @@ -157,7 +157,7 @@ [PcdsFixedAtBuild.common] > gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0x2C002000 > > # ISP1761 USB OTG Controller > - gEmbeddedTokenSpaceGuid.PcdIsp1761BaseAddress|0x1B000000 > + gArmVExpressTokenSpaceGuid.PcdIsp1761BaseAddress|0x1B000000 > > # Ethernet (SMSC LAN9118) > gArmVExpressTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x1A000000 > diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf > index b133375e1a11..f98de162e634 100644 > --- a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf > +++ b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf > @@ -126,7 +126,7 @@ [FV.FvMain] > # > # USB support > # > - INF EmbeddedPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf > + INF Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf > > # > # Android Fastboot > diff --git a/Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc b/Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc > index 912ad5e5a1ec..bde3437b56d7 100644 > --- a/Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc > +++ b/Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc > @@ -455,4 +455,4 @@ [Components.common] > [Components.ARM] > > # ISP1761 USB OTG Controller > - EmbeddedPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf > + Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf > diff --git a/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec b/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec > index e42905aabf2b..f78c5ce7c764 100644 > --- a/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec > +++ b/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec > @@ -67,3 +67,6 @@ [PcdsFixedAtBuild.common] > # The default feature mask below disables full duplex negotiation, since full > # duplex operation is suspected to be broken in the driver. > gArmVExpressTokenSpaceGuid.PcdLan9118NegotiationFeatureMask|0xFFFFFEBF|UINT32|0x00000028 > + > + # ISP1761 USB OTG Controller > + gArmVExpressTokenSpaceGuid.PcdIsp1761BaseAddress|0|UINT32|0x00000029 > diff --git a/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.c b/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.c > new file mode 100644 > index 000000000000..c23c0ecf737d > --- /dev/null > +++ b/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.c > @@ -0,0 +1,636 @@ > +/** @file > + > + WARNING: > + This driver fails to follow the UEFI driver model without a good > + reason, and only remains in the tree because it is still used by > + a small number of platforms. It will be removed when no longer used. > + New platforms should not use it, and no one should use this as > + reference code for developing new drivers. > + > + Copyright (c) 2013-2015, ARM Ltd. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#include > + > +#include "Isp1761UsbDxe.h" > + > +/* > + Driver for using the NXP ISP1761 as a USB Peripheral controller. > + Doesn't use USB OTG - just sets it in Pure Peripheral mode. > + > + The ISP1582 datasheet has a little more info on the Peripheral controller > + registers than the ISP1761 datasheet > + > + We don't do string descriptors. They're optional. > + We currently assume the device has one configuration, one interface, one IN > + endpoint, and one OUT endpoint (plus the default control endpoint). > + > + In fact, this driver is the minimum required to implement fastboot. > +*/ > + > +// TODO Make sure the controller isn't sending empty packets when it shouldn't > +// (check behaviour in cases when Buffer Length isn't explicitly set) > + > +// ISP1582 Datasheet: > +// "Data transfers preceding the status stage must first be fully > +// completed before the STATUS bit can be set." > +// This variable stores whether some control data has been pended in the EP0TX > +// Tx buffer, so that when an EP0TX interrupt is received we can set the STATUS > +// bit to go to the Status stage of the control transfer. > +STATIC BOOLEAN mControlTxPending = FALSE; > + > +STATIC USB_DEVICE_DESCRIPTOR *mDeviceDescriptor; > + > +// The config descriptor, interface descriptor, and endpoint descriptors in a > +// buffer (in that order) > +STATIC VOID *mDescriptors; > +// Convenience pointers to those descriptors inside the buffer: > +STATIC USB_INTERFACE_DESCRIPTOR *mInterfaceDescriptor; > +STATIC USB_CONFIG_DESCRIPTOR *mConfigDescriptor; > +STATIC USB_ENDPOINT_DESCRIPTOR *mEndpointDescriptors; > + > +STATIC USB_DEVICE_RX_CALLBACK mDataReceivedCallback; > +STATIC USB_DEVICE_TX_CALLBACK mDataSentCallback; > + > +// The time between interrupt polls, in units of 100 nanoseconds > +// 10 Microseconds > +#define ISP1761_INTERRUPT_POLL_PERIOD 10000 > + > +STATIC > +VOID > +SelectEndpoint ( > + IN UINT8 Endpoint > + ) > +{ > + // The DMA Endpoint Index must not point to the same as the > + // Endpoint Index Register. > + WRITE_REG32 (ISP1761_DMA_ENDPOINT_INDEX, ((Endpoint + 2) % ISP1761_NUM_ENDPOINTS)); > + WRITE_REG32 (ISP1761_ENDPOINT_INDEX, Endpoint); > +} > + > +// Enable going to the Data stage of a control transfer > +STATIC > +VOID > +DataStageEnable ( > + IN UINT8 Endpoint > + ) > +{ > + SelectEndpoint (Endpoint); > + WRITE_REG32 (ISP1761_CTRL_FUNCTION, ISP1761_CTRL_FUNCTION_DSEN); > +} > + > +// Go to the Status stage of a successful control transfer > +STATIC > +VOID > +StatusAcknowledge ( > + IN UINT8 Endpoint > +) > +{ > + SelectEndpoint (Endpoint); > + WRITE_REG32 (ISP1761_CTRL_FUNCTION, ISP1761_CTRL_FUNCTION_STATUS); > +} > + > +// Read the FIFO for the endpoint indexed by Endpoint, into the buffer pointed > +// at by Buffer, whose size is *Size bytes. > +// > +// If *Size is less than the number of bytes in the FIFO, return EFI_BUFFER_TOO_SMALL > +// > +// Update *Size with the number of bytes of data in the FIFO. > +STATIC > +EFI_STATUS > +ReadEndpointBuffer ( > + IN UINT8 Endpoint, > + IN OUT UINTN *Size, > + IN OUT VOID *Buffer > + ) > +{ > + UINT16 NumBytesAvailable; > + UINT32 Val32; > + UINTN Index; > + UINTN NumBytesRead; > + > + SelectEndpoint (Endpoint); > + > + NumBytesAvailable = READ_REG16 (ISP1761_BUFFER_LENGTH); > + > + if (NumBytesAvailable > *Size) { > + *Size = NumBytesAvailable; > + return EFI_BUFFER_TOO_SMALL; > + } > + *Size = NumBytesAvailable; > + > + /* -- NB! -- > + The datasheet says the Data Port is 16 bits but it actually appears to > + be 32 bits. > + */ > + > + // Read 32-bit chunks > + for (Index = 0; Index < NumBytesAvailable / 4; Index++) { > + ((UINT32 *) Buffer)[Index] = READ_REG32 (ISP1761_DATA_PORT); > + } > + > + // Read remaining bytes > + > + // Round NumBytesAvailable down to nearest power of 4 > + NumBytesRead = NumBytesAvailable & (~0x3); > + if (NumBytesRead != NumBytesAvailable) { > + Val32 = READ_REG32 (ISP1761_DATA_PORT); > + // Copy each required byte of 32-bit word into buffer > + for (Index = 0; Index < NumBytesAvailable % 4; Index++) { > + ((UINT8 *) Buffer)[NumBytesRead + Index] = Val32 >> (Index * 8); > + } > + } > + return EFI_SUCCESS; > +} > + > +/* > + Write an endpoint buffer. Parameters: > + Endpoint Endpoint index (see Endpoint Index Register in datasheet) > + MaxPacketSize The MaxPacketSize this endpoint is configured for > + Size The size of the Buffer > + Buffer The data > + > + Assumes MaxPacketSize is a multiple of 4. > + (It seems that all valid values for MaxPacketSize _are_ multiples of 4) > +*/ > +STATIC > +EFI_STATUS > +WriteEndpointBuffer ( > + IN UINT8 Endpoint, > + IN UINTN MaxPacketSize, > + IN UINTN Size, > + IN CONST VOID *Buffer > + ) > +{ > + UINTN Index; > + UINT32 *DwordBuffer; > + > + DwordBuffer = (UINT32 *) Buffer; > + SelectEndpoint (Endpoint); > + > + /* -- NB! -- > + The datasheet says the Data Port is 16 bits but it actually appears to > + be 32 bits. > + */ > + > + // Write packets of size MaxPacketSize > + while (Size > MaxPacketSize) { > + for (Index = 0; Index < MaxPacketSize / 4; Index++) { > + WRITE_REG32 (ISP1761_DATA_PORT, DwordBuffer[Index]); > + } > + Size -= MaxPacketSize; > + DwordBuffer += (MaxPacketSize / sizeof (UINT32)); > + } > + > + // Write remaining data > + > + if (Size > 0) { > + WRITE_REG32 (ISP1761_BUFFER_LENGTH, Size); > + > + while (Size > 4) { > + WRITE_REG32 (ISP1761_DATA_PORT, DwordBuffer[0]); > + Size -= 4; > + DwordBuffer++; > + } > + > + if (Size > 0) { > + WRITE_REG32 (ISP1761_DATA_PORT, DwordBuffer[0]); > + } > + } > + > + return EFI_SUCCESS; > +} > + > +STATIC > +EFI_STATUS > +HandleGetDescriptor ( > + IN USB_DEVICE_REQUEST *Request > + ) > +{ > + EFI_STATUS Status; > + UINT8 DescriptorType; > + UINTN ResponseSize; > + VOID *ResponseData; > + > + ResponseSize = 0; > + ResponseData = NULL; > + Status = EFI_SUCCESS; > + > + // Pretty confused if bmRequestType is anything but this: > + ASSERT (Request->RequestType == USB_DEV_GET_DESCRIPTOR_REQ_TYPE); > + > + // Choose the response > + DescriptorType = Request->Value >> 8; > + switch (DescriptorType) { > + case USB_DESC_TYPE_DEVICE: > + DEBUG ((EFI_D_INFO, "USB: Got a request for device descriptor\n")); > + ResponseSize = sizeof (USB_DEVICE_DESCRIPTOR); > + ResponseData = mDeviceDescriptor; > + break; > + case USB_DESC_TYPE_CONFIG: > + DEBUG ((EFI_D_INFO, "USB: Got a request for config descriptor\n")); > + ResponseSize = mConfigDescriptor->TotalLength; > + ResponseData = mDescriptors; > + break; > + case USB_DESC_TYPE_STRING: > + DEBUG ((EFI_D_INFO, "USB: Got a request for String descriptor %d\n", Request->Value & 0xFF)); > + break; > + default: > + DEBUG ((EFI_D_INFO, "USB: Didn't understand request for descriptor 0x%04x\n", Request->Value)); > + Status = EFI_NOT_FOUND; > + break; > + } > + > + // Send the response > + if (ResponseData) { > + ASSERT (ResponseSize != 0); > + > + if (Request->Length < ResponseSize) { > + // Truncate response > + ResponseSize = Request->Length; > + } else if (Request->Length > ResponseSize) { > + DEBUG ((EFI_D_INFO, "USB: Info: ResponseSize < wLength\n")); > + } > + > + DataStageEnable (ISP1761_EP0TX); > + Status = WriteEndpointBuffer ( > + ISP1761_EP0TX, > + MAX_PACKET_SIZE_CONTROL, > + ResponseSize, > + ResponseData > + ); > + if (!EFI_ERROR (Status)) { > + // Setting this value should cause us to go to the Status stage on the > + // next EP0TX interrupt > + mControlTxPending = TRUE; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +STATIC > +EFI_STATUS > +HandleSetAddress ( > + IN USB_DEVICE_REQUEST *Request > + ) > +{ > + // Pretty confused if bmRequestType is anything but this: > + ASSERT (Request->RequestType == USB_DEV_SET_ADDRESS_REQ_TYPE); > + // USB Spec: "The USB device does not change its device address until after > + // the Status stage of this request is completed successfully." > + // ISP1582 datasheet: "The new device address is activated when the > + // device receives an acknowledgment from the host for the empty packet > + // token". (StatusAcknowledge causes an empty packet to be sent). > + // So, we write the Address register _before_ acking the SET_ADDRESS. > + DEBUG ((EFI_D_INFO, "USB: Setting address to %d\n", Request->Value)); > + WRITE_REG32 (ISP1761_ADDRESS, Request->Value | ISP1761_ADDRESS_DEVEN); > + StatusAcknowledge (ISP1761_EP0TX); > + > + return EFI_SUCCESS; > +} > + > +// Move the device to the Configured state. > +// (This code only supports one configuration for a device, so the configuration > +// index is ignored) > +STATIC > +EFI_STATUS > +HandleSetConfiguration ( > + IN USB_DEVICE_REQUEST *Request > + ) > +{ > + USB_ENDPOINT_DESCRIPTOR *EPDesc; > + UINTN Index; > + UINT8 EndpointIndex; > + > + ASSERT (Request->RequestType == USB_DEV_SET_CONFIGURATION_REQ_TYPE); > + DEBUG ((EFI_D_INFO, "USB: Setting configuration.\n")); > + > + // Configure endpoints > + for (Index = 0; Index < mInterfaceDescriptor->NumEndpoints; Index++) { > + EPDesc = &mEndpointDescriptors[Index]; > + > + // To simplify for now, assume endpoints aren't "sparse", and are in order. > + ASSERT ((EPDesc->EndpointAddress & 0xF) == ((Index / 2) + 1)); > + > + // Convert from USB endpoint index to ISP1761 endpoint Index > + // USB: Endpoint number is bits [3:0], IN/OUT is bit [7] > + // ISP1761: Endpoint number is bits [4:1], IN/OUT is bit [0] > + EndpointIndex = ((EPDesc->EndpointAddress & 0xF) << 1) | > + ((EPDesc->EndpointAddress & BIT7) >> 7); > + SelectEndpoint (EndpointIndex); > + // Set endpoint type (Bulk/Isochronous/Interrupt) > + WRITE_REG32 (ISP1761_ENDPOINT_MAX_PACKET_SIZE, EPDesc->MaxPacketSize); > + // Hardware foible (bug?): Although the datasheet seems to suggest it should > + // automatically be set to MaxPacketSize, the Buffer Length register appears > + // to be reset to 0, which causes an empty packet to be sent in response to > + // the first IN token of the session. The NOEMPKT field of the Endpoint Type > + // register sounds like it might fix this problem, but it doesn't > + // (it's "applicable only in the DMA mode"). > + WRITE_REG32 (ISP1761_BUFFER_LENGTH, EPDesc->MaxPacketSize); > + WRITE_REG32 (ISP1761_ENDPOINT_TYPE, (EPDesc->Attributes & 0x3) | > + ISP1761_ENDPOINT_TYPE_ENABLE); > + } > + > + StatusAcknowledge (ISP1761_EP0TX); > + return EFI_SUCCESS; > +} > + > +STATIC > +EFI_STATUS > +HandleDeviceRequest ( > + IN USB_DEVICE_REQUEST *Request > + ) > +{ > + EFI_STATUS Status; > + > + Status = EFI_SUCCESS; > + > + switch (Request->Request) { > + case USB_DEV_GET_DESCRIPTOR: > + Status = HandleGetDescriptor (Request); > + break; > + case USB_DEV_SET_ADDRESS: > + Status = HandleSetAddress (Request); > + break; > + case USB_DEV_SET_CONFIGURATION: > + Status = HandleSetConfiguration (Request); > + break; > + default: > + DEBUG ((EFI_D_ERROR, > + "Didn't understand RequestType 0x%x Request 0x%x\n", > + Request->RequestType, Request->Request)); > + Status = EFI_INVALID_PARAMETER; > + break; > + } > + > + return Status; > +} > + > +// Instead of actually registering interrupt handlers, we poll the controller's > +// interrupt source register in this function. > +STATIC > +VOID > +CheckInterrupts ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + UINT32 DcInterrupts; > + UINTN NumBytes; > + UINTN MoreBytes; > + UINT8 Packet[512]; > + VOID *DataPacket; > + UINT32 HandledInterrupts; > + UINT32 UnhandledInterrupts; > + EFI_STATUS Status; > + > + // Set bits in HandledInterrupts to mark the interrupt source handled. > + HandledInterrupts = 0; > + > + WRITE_REG32 (ISP1761_DEVICE_UNLOCK, ISP1761_DEVICE_UNLOCK_MAGIC); > + > + DcInterrupts = READ_REG32 (ISP1761_DC_INTERRUPT); > + if (DcInterrupts & ISP1761_DC_INTERRUPT_SUSP) { > + DEBUG ((EFI_D_INFO, "USB: Suspend\n")); > + HandledInterrupts |= ISP1761_DC_INTERRUPT_SUSP; > + } > + if (DcInterrupts & ISP1761_DC_INTERRUPT_RESUME) { > + DEBUG ((EFI_D_INFO, "USB: Resume\n")); > + HandledInterrupts |= ISP1761_DC_INTERRUPT_RESUME; > + } > + if (DcInterrupts & ISP1761_DC_INTERRUPT_EP0SETUP) { > + NumBytes = 512; > + ReadEndpointBuffer (0x20, &NumBytes, &Packet); > + ASSERT (NumBytes == 8); > + HandleDeviceRequest ((USB_DEVICE_REQUEST *) Packet); > + HandledInterrupts |= ISP1761_DC_INTERRUPT_EP0SETUP; > + } > + if (DcInterrupts & ISP1761_DC_INTERRUPT_EP0RX) { > + HandledInterrupts |= ISP1761_DC_INTERRUPT_EP0RX; > + } > + if (DcInterrupts & ISP1761_DC_INTERRUPT_EP0TX) { > + if (mControlTxPending) { > + // We previously put some data in the Control Endpoint's IN (Tx) FIFO. > + // We assume that that data has now been sent in response to the IN token > + // that triggered this interrupt. We can therefore go to the Status stage > + // of the control transfer. > + StatusAcknowledge (ISP1761_EP0TX); > + mControlTxPending = FALSE; > + } > + HandledInterrupts |= ISP1761_DC_INTERRUPT_EP0TX; > + } > + if (DcInterrupts & ISP1761_DC_INTERRUPT_EP1RX) { > + NumBytes = 512; > + DataPacket = AllocatePool (NumBytes); > + Status = ReadEndpointBuffer (ISP1761_EP1RX, &NumBytes, DataPacket); > + if (EFI_ERROR (Status) || NumBytes == 0) { > + if (EFI_ERROR (Status)) { > + DEBUG ((EFI_D_ERROR, "Couldn't read EP1RX data: %r\n", Status)); > + } > + FreePool (DataPacket); > + } else { > + // Signal this event again so we poll again ASAP > + gBS->SignalEvent (Event); > + mDataReceivedCallback (NumBytes, DataPacket); > + } > + HandledInterrupts |= ISP1761_DC_INTERRUPT_EP1RX; > + } > + if (DcInterrupts & ISP1761_DC_INTERRUPT_EP1TX) { > + mDataSentCallback (1); > + HandledInterrupts |= ISP1761_DC_INTERRUPT_EP1TX; > + } > + if (DcInterrupts & (ISP1761_DC_INTERRUPT_SOF | ISP1761_DC_INTERRUPT_PSOF)) { > + // Don't care about SOFs or pseudo-SOFs > + HandledInterrupts |= (ISP1761_DC_INTERRUPT_SOF | ISP1761_DC_INTERRUPT_PSOF); > + } > + if (ISP1761_DC_INTERRUPT_BRESET) { > + HandledInterrupts |= ISP1761_DC_INTERRUPT_BRESET; > + } > + if (ISP1761_DC_INTERRUPT_HS_STAT) { > + HandledInterrupts |= ISP1761_DC_INTERRUPT_HS_STAT; > + } > + if (ISP1761_DC_INTERRUPT_VBUS) { > + HandledInterrupts |= ISP1761_DC_INTERRUPT_VBUS; > + } > + > + UnhandledInterrupts = DcInterrupts & (~HandledInterrupts) & ISP1761_DC_INTERRUPT_MASK; > + if (UnhandledInterrupts) { > + DEBUG ((EFI_D_ERROR, "USB: Unhandled DC Interrupts: 0x%08x\n", > + UnhandledInterrupts)); > + } > + > + // Check if we received any more data while we were handling the interrupt. > + SelectEndpoint (ISP1761_EP1RX); > + MoreBytes = READ_REG16 (ISP1761_BUFFER_LENGTH); > + if (MoreBytes) { > + HandledInterrupts &= ~ISP1761_DC_INTERRUPT_EP1RX; > + } > + > + WRITE_REG32 (ISP1761_DC_INTERRUPT, HandledInterrupts); > +} > + > +EFI_STATUS > +Isp1761PeriphSend ( > + IN UINT8 EndpointIndex, > + IN UINTN Size, > + IN CONST VOID *Buffer > + ) > +{ > + return WriteEndpointBuffer ( > + (EndpointIndex << 1) | 0x1, //Convert to ISP1761 endpoint index, Tx > + MAX_PACKET_SIZE_BULK, > + Size, > + Buffer > + ); > +} > + > +EFI_STATUS > +EFIAPI > +Isp1761PeriphStart ( > + IN USB_DEVICE_DESCRIPTOR *DeviceDescriptor, > + IN VOID **Descriptors, > + IN USB_DEVICE_RX_CALLBACK RxCallback, > + IN USB_DEVICE_TX_CALLBACK TxCallback > + ) > +{ > + UINT16 OtgStatus; > + UINT8 *Ptr; > + EFI_STATUS Status; > + EFI_EVENT TimerEvent; > + > + ASSERT (DeviceDescriptor != NULL); > + ASSERT (Descriptors[0] != NULL); > + ASSERT (RxCallback != NULL); > + ASSERT (TxCallback != NULL); > + > + WRITE_REG32 (ISP1761_DEVICE_UNLOCK, ISP1761_DEVICE_UNLOCK_MAGIC); > + > + WRITE_REG32 (ISP1761_SW_RESET_REG, ISP1761_SW_RESET_ALL); > + while (READ_REG32 (ISP1761_SW_RESET_REG) & ISP1761_SW_RESET_ALL) { > + //busy wait > + } > + WRITE_REG32 (ISP1761_MODE, ISP1761_MODE_SFRESET); > + while (READ_REG32 (ISP1761_MODE) & ISP1761_MODE_SFRESET) { > + //busy wait > + } > + DEBUG ((EFI_D_INFO, "USB: Software reset done\n")); > + > + WRITE_REG32 (ISP1761_DC_INTERRUPT_ENABLE, 0x03FFFFFF); > + WRITE_REG32 (ISP1761_OTG_INTERRUPT_ENABLE_RISE, 0x07FF); > + > + WRITE_REG8 (ISP1761_ADDRESS, ISP1761_ADDRESS_DEVEN); > + WRITE_REG8 (ISP1761_MODE, ISP1761_MODE_WKUPCS | ISP1761_MODE_CLKAON); > + > + // Use port 1 as peripheral controller (magic - disagrees with datasheet) > + WRITE_REG32 (ISP1761_OTG_CTRL_SET, 0xffff0000); > + WRITE_REG32 (ISP1761_OTG_CTRL_SET, 0x000014d1); > + > + OtgStatus = READ_REG16 (ISP1761_OTG_STATUS); > + if ((OtgStatus & ISP1761_OTG_STATUS_B_SESS_END) != 0) { > + DEBUG ((EFI_D_ERROR, "USB: Vbus not powered.\n")); > + } > + if ((OtgStatus & ISP1761_OTG_STATUS_A_B_SESS_VLD) == 0) { > + DEBUG ((EFI_D_ERROR, "USB: Session not valid.\n")); > + } > + > + // Configure Control endpoints > + SelectEndpoint (0x20); > + WRITE_REG32 (ISP1761_ENDPOINT_MAX_PACKET_SIZE, MAX_PACKET_SIZE_CONTROL); > + WRITE_REG32 (ISP1761_ENDPOINT_TYPE, ISP1761_ENDPOINT_TYPE_ENABLE); > + SelectEndpoint (0x0); > + WRITE_REG32 (ISP1761_ENDPOINT_MAX_PACKET_SIZE, MAX_PACKET_SIZE_CONTROL); > + WRITE_REG32 (ISP1761_ENDPOINT_TYPE, ISP1761_ENDPOINT_TYPE_ENABLE); > + SelectEndpoint (0x1); > + WRITE_REG32 (ISP1761_ENDPOINT_MAX_PACKET_SIZE, MAX_PACKET_SIZE_CONTROL); > + WRITE_REG32 (ISP1761_ENDPOINT_TYPE, ISP1761_ENDPOINT_TYPE_ENABLE); > + > + // Interrupt on all ACK and NAK > + WRITE_REG32 (ISP1761_INTERRUPT_CONFIG, ISP1761_INTERRUPT_CONFIG_ACK_ONLY); > + > + mDeviceDescriptor = DeviceDescriptor; > + mDescriptors = Descriptors[0]; > + > + // Right now we just support one configuration > + ASSERT (mDeviceDescriptor->NumConfigurations == 1); > + // ... and one interface > + mConfigDescriptor = (USB_CONFIG_DESCRIPTOR *)mDescriptors; > + ASSERT (mConfigDescriptor->NumInterfaces == 1); > + > + Ptr = ((UINT8 *) mDescriptors) + sizeof (USB_CONFIG_DESCRIPTOR); > + mInterfaceDescriptor = (USB_INTERFACE_DESCRIPTOR *) Ptr; > + Ptr += sizeof (USB_INTERFACE_DESCRIPTOR); > + > + mEndpointDescriptors = (USB_ENDPOINT_DESCRIPTOR *) Ptr; > + > + mDataReceivedCallback = RxCallback; > + mDataSentCallback = TxCallback; > + > + // Register a timer event so CheckInterrupts gets called periodically > + Status = gBS->CreateEvent ( > + EVT_TIMER | EVT_NOTIFY_SIGNAL, > + TPL_CALLBACK, > + CheckInterrupts, > + NULL, > + &TimerEvent > + ); > + ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status = gBS->SetTimer ( > + TimerEvent, > + TimerPeriodic, > + ISP1761_INTERRUPT_POLL_PERIOD > + ); > + ASSERT_EFI_ERROR (Status); > + > + return Status; > +} > + > +USB_DEVICE_PROTOCOL mUsbDevice = { > + Isp1761PeriphStart, > + Isp1761PeriphSend > +}; > + > + > +EFI_STATUS > +EFIAPI > +Isp1761PeriphEntryPoint ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + UINT32 DeviceId; > + EFI_HANDLE Handle; > + > + DeviceId = READ_REG32 (ISP1761_DEVICE_ID); > + > + if (DeviceId != ISP1761_DEVICE_ID_VAL) { > + DEBUG ((EFI_D_ERROR, > + "ERROR: Read incorrect device ID for ISP1761: 0x%08x, expected 0x%08x\n", > + DeviceId , ISP1761_DEVICE_ID_VAL > + )); > + return EFI_DEVICE_ERROR; > + } > + > + Handle = NULL; > + return gBS->InstallProtocolInterface ( > + &Handle, > + &gUsbDeviceProtocolGuid, > + EFI_NATIVE_INTERFACE, > + &mUsbDevice > + ); > +} > diff --git a/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.h b/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.h > new file mode 100644 > index 000000000000..f7155d48d8ad > --- /dev/null > +++ b/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.h > @@ -0,0 +1,123 @@ > +/** @file > + > + WARNING: > + This driver fails to follow the UEFI driver model without a good > + reason, and only remains in the tree because it is still used by > + a small number of platforms. It will be removed when no longer used. > + New platforms should not use it, and no one should use this as > + reference code for developing new drivers. > + > + Copyright (c) 2013-2014, ARM Ltd. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef __ISP1761_USB_DXE_H__ > +#define __ISP1761_USB_DXE_H__ > + > +#define ISP1761_USB_BASE FixedPcdGet32 (PcdIsp1761BaseAddress) > + > +#define READ_REG32(Offset) MmioRead32 (ISP1761_USB_BASE + Offset) > +#define READ_REG16(Offset) (UINT16) READ_REG32 (Offset) > +#define WRITE_REG32(Offset, Val) MmioWrite32 (ISP1761_USB_BASE + Offset, Val) > +#define WRITE_REG16(Offset, Val) MmioWrite32 (ISP1761_USB_BASE + Offset, (UINT32) Val) > +#define WRITE_REG8(Offset, Val) MmioWrite32 (ISP1761_USB_BASE + Offset, (UINT32) Val) > + > +// Max packet size in bytes (For Full Speed USB 64 is the only valid value) > +#define MAX_PACKET_SIZE_CONTROL 64 > + > +#define MAX_PACKET_SIZE_BULK 512 > + > +// 8 Endpoints, in and out. Don't count the Endpoint 0 setup buffer > +#define ISP1761_NUM_ENDPOINTS 16 > + > +// Endpoint Indexes > +#define ISP1761_EP0SETUP 0x20 > +#define ISP1761_EP0RX 0x00 > +#define ISP1761_EP0TX 0x01 > +#define ISP1761_EP1RX 0x02 > +#define ISP1761_EP1TX 0x03 > + > +// DcInterrupt bits > +#define ISP1761_DC_INTERRUPT_BRESET BIT0 > +#define ISP1761_DC_INTERRUPT_SOF BIT1 > +#define ISP1761_DC_INTERRUPT_PSOF BIT2 > +#define ISP1761_DC_INTERRUPT_SUSP BIT3 > +#define ISP1761_DC_INTERRUPT_RESUME BIT4 > +#define ISP1761_DC_INTERRUPT_HS_STAT BIT5 > +#define ISP1761_DC_INTERRUPT_DMA BIT6 > +#define ISP1761_DC_INTERRUPT_VBUS BIT7 > +#define ISP1761_DC_INTERRUPT_EP0SETUP BIT8 > +#define ISP1761_DC_INTERRUPT_EP0RX BIT10 > +#define ISP1761_DC_INTERRUPT_EP0TX BIT11 > +#define ISP1761_DC_INTERRUPT_EP1RX BIT12 > +#define ISP1761_DC_INTERRUPT_EP1TX BIT13 > +// All valid peripheral controller interrupts > +#define ISP1761_DC_INTERRUPT_MASK 0x003FFFDFF > + > +#define ISP1761_ADDRESS 0x200 > +#define ISP1761_ADDRESS_DEVEN BIT7 > + > +#define ISP1761_MODE 0x20C > +#define ISP1761_MODE_DATA_BUS_WIDTH BIT8 > +#define ISP1761_MODE_CLKAON BIT7 > +#define ISP1761_MODE_SFRESET BIT4 > +#define ISP1761_MODE_WKUPCS BIT2 > + > +#define ISP1761_ENDPOINT_MAX_PACKET_SIZE 0x204 > + > +#define ISP1761_ENDPOINT_TYPE 0x208 > +#define ISP1761_ENDPOINT_TYPE_NOEMPKT BIT4 > +#define ISP1761_ENDPOINT_TYPE_ENABLE BIT3 > + > +#define ISP1761_INTERRUPT_CONFIG 0x210 > +// Interrupt config value to only interrupt on ACK of IN and OUT tokens > +#define ISP1761_INTERRUPT_CONFIG_ACK_ONLY BIT2 | BIT5 | BIT6 > + > +#define ISP1761_DC_INTERRUPT 0x218 > +#define ISP1761_DC_INTERRUPT_ENABLE 0x214 > + > +#define ISP1761_CTRL_FUNCTION 0x228 > +#define ISP1761_CTRL_FUNCTION_VENDP BIT3 > +#define ISP1761_CTRL_FUNCTION_DSEN BIT2 > +#define ISP1761_CTRL_FUNCTION_STATUS BIT1 > + > +#define ISP1761_DEVICE_UNLOCK 0x27C > +#define ISP1761_DEVICE_UNLOCK_MAGIC 0xAA37 > + > +#define ISP1761_SW_RESET_REG 0x30C > +#define ISP1761_SW_RESET_ALL BIT0 > + > +#define ISP1761_DEVICE_ID 0x370 > + > +#define ISP1761_OTG_CTRL_SET 0x374 > +#define ISP1761_OTG_CTRL_CLR OTG_CTRL_SET + 2 > +#define ISP1761_OTG_CTRL_OTG_DISABLE BIT10 > +#define ISP1761_OTG_CTRL_VBUS_CHRG BIT6 > +#define ISP1761_OTG_CTRL_VBUS_DISCHRG BIT5 > +#define ISP1761_OTG_CTRL_DM_PULLDOWN BIT2 > +#define ISP1761_OTG_CTRL_DP_PULLDOWN BIT1 > +#define ISP1761_OTG_CTRL_DP_PULLUP BIT0 > + > +#define ISP1761_OTG_STATUS 0x378 > +#define ISP1761_OTG_STATUS_B_SESS_END BIT7 > +#define ISP1761_OTG_STATUS_A_B_SESS_VLD BIT1 > + > +#define ISP1761_OTG_INTERRUPT_LATCH_SET 0x37C > +#define ISP1761_OTG_INTERRUPT_LATCH_CLR 0x37E > +#define ISP1761_OTG_INTERRUPT_ENABLE_RISE 0x384 > + > +#define ISP1761_DMA_ENDPOINT_INDEX 0x258 > + > +#define ISP1761_ENDPOINT_INDEX 0x22c > +#define ISP1761_DATA_PORT 0x220 > +#define ISP1761_BUFFER_LENGTH 0x21c > + > +// Device ID Values > +#define PHILLIPS_VENDOR_ID_VAL 0x04cc > +#define ISP1761_PRODUCT_ID_VAL 0x1761 > +#define ISP1761_DEVICE_ID_VAL ((ISP1761_PRODUCT_ID_VAL << 16) |\ > + PHILLIPS_VENDOR_ID_VAL) > + > +#endif //ifndef __ISP1761_USB_DXE_H__ > diff --git a/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf b/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf > new file mode 100644 > index 000000000000..b161547bf73a > --- /dev/null > +++ b/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf > @@ -0,0 +1,39 @@ > +#/** @file > +# > +# Copyright (c) 2013-2015, ARM Ltd. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# Comment only: This file, unlike some other .infs in this series, does not include the WARNING header. Feel free to fold one in before pushing. > +# > +#**/ > + > +[Defines] > + INF_VERSION = 0x00010005 > + BASE_NAME = Isp1761PeriphDxe > + FILE_GUID = 72d78ea6-4dee-11e3-8100-f3842a48d0a0 > + MODULE_TYPE = UEFI_DRIVER > + VERSION_STRING = 1.0 > + ENTRY_POINT = Isp1761PeriphEntryPoint > + > +[Sources.common] > + Isp1761UsbDxe.c > + > +[LibraryClasses] > + DebugLib > + IoLib > + MemoryAllocationLib > + UefiBootServicesTableLib > + UefiDriverEntryPoint > + > +[Protocols] > + gEfiDriverBindingProtocolGuid > + gUsbDeviceProtocolGuid > + > +[Packages] > + EmbeddedPkg/EmbeddedPkg.dec > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + Platform/ARM/VExpressPkg/ArmVExpressPkg.dec > + > +[Pcd] > + gArmVExpressTokenSpaceGuid.PcdIsp1761BaseAddress > -- > 2.17.1 >