]> git.proxmox.com Git - mirror_edk2.git/blobdiff - Omap35xxPkg/Library/OmapDmaLib/OmapDmaLib.c
Add a DMA lib for the OMAP. It is a combination of PCI IO (generic ARM) DMA functions...
[mirror_edk2.git] / Omap35xxPkg / Library / OmapDmaLib / OmapDmaLib.c
diff --git a/Omap35xxPkg/Library/OmapDmaLib/OmapDmaLib.c b/Omap35xxPkg/Library/OmapDmaLib/OmapDmaLib.c
new file mode 100755 (executable)
index 0000000..f979b94
--- /dev/null
@@ -0,0 +1,348 @@
+/** @file\r
+  OMAP35xx DMA abstractions modeled on PCI IO protocol. EnableDma()/DisableDma()\r
+  are from OMAP35xx TRM. \r
+\r
+  Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
+  \r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Base.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/OmapDmaLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UncachedMemoryAllocationLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Omap3530/Omap3530.h>\r
+\r
+#include <Protocol/Cpu.h>\r
+\r
+typedef struct {\r
+  EFI_PHYSICAL_ADDRESS      HostAddress;\r
+  EFI_PHYSICAL_ADDRESS      DeviceAddress;\r
+  UINTN                     NumberOfBytes;\r
+  DMA_MAP_OPERATION         Operation;\r
+} MAP_INFO_INSTANCE;\r
+\r
+\r
+\r
+EFI_CPU_ARCH_PROTOCOL      *gCpu;
+\r
+/**                                                                 \r
+  Configure OMAP DMA Channel\r
+            \r
+  @param  Channel               DMA Channel to configure\r
+  @param  Dma4                  Pointer to structure used to initialize DMA registers for the Channel                                                \r
+                                  \r
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.\r
+  @retval EFI_INVALID_PARAMETER Channel is not valid\r
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested information.\r
+                                   \r
+**/
+EFI_STATUS
+EFIAPI
+EnableDmaChannel (
+  IN  UINTN       Channel,
+  IN  OMAP_DMA4   *DMA4
+  )
+{
+  UINT32  RegVal;
+
+
+  if (Channel > DMA4_MAX_CHANNEL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  /* 1) Configure the transfer parameters in the logical DMA registers */\r
+  /*-------------------------------------------------------------------*/\r
+\r
+  /* a) Set the data type CSDP[1:0], the Read/Write Port access type \r
+        CSDP[8:7]/[15:14], the Source/dest endianism CSDP[21]/CSDP[19], \r
+        write mode CSDP[17:16], source/dest packed or nonpacked CSDP[6]/CSDP[13] */\r
+  \r
+  // Read CSDP\r
+  RegVal = MmioRead32 (DMA4_CSDP (Channel));\r
+  \r
+  // Build reg\r
+  RegVal = ((RegVal & ~ 0x3) | DMA4->DataType );\r
+  RegVal = ((RegVal & ~(0x3 <<  7)) | (DMA4->ReadPortAccessType << 7));\r
+  RegVal = ((RegVal & ~(0x3 << 14)) | (DMA4->WritePortAccessType << 14));\r
+  RegVal = ((RegVal & ~(0x1 << 21)) | (DMA4->SourceEndiansim << 21));\r
+  RegVal = ((RegVal & ~(0x1 << 19)) | (DMA4->DestinationEndianism << 19));\r
+  RegVal = ((RegVal & ~(0x3 << 16)) | (DMA4->WriteMode << 16));\r
+  RegVal = ((RegVal & ~(0x1 <<  6)) | (DMA4->SourcePacked << 6));\r
+  RegVal = ((RegVal & ~(0x1 << 13)) | (DMA4->DestinationPacked << 13));\r
+  // Write CSDP\r
+  MmioWrite32 (DMA4_CSDP (Channel), RegVal);\r
+  \r
+  /* b) Set the number of element per frame CEN[23:0]*/\r
+  MmioWrite32 (DMA4_CEN (Channel), DMA4->NumberOfElementPerFrame);\r
\r
+  /* c) Set the number of frame per block CFN[15:0]*/\r
+  MmioWrite32 (DMA4_CFN (Channel), DMA4->NumberOfFramePerTransferBlock);\r
+  \r
+  /* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0]*/\r
+  MmioWrite32 (DMA4_CSSA (Channel), DMA4->SourceStartAddress);\r
+  MmioWrite32 (DMA4_CDSA (Channel), DMA4->DestinationStartAddress);\r
+  \r
+  /* e) Set the Read Port addressing mode CCR[13:12], the Write Port addressing mode CCR[15:14],\r
+        read/write priority CCR[6]/CCR[26]\r
+        I changed LCH CCR[20:19]=00 and CCR[4:0]=00000 to \r
+        LCH CCR[20:19]= DMA4->WriteRequestNumber and CCR[4:0]=DMA4->ReadRequestNumber\r
+  */\r
+  \r
+  // Read CCR\r
+  RegVal = MmioRead32 (DMA4_CCR (Channel));\r
+\r
+  // Build reg\r
+  RegVal  = ((RegVal &  ~0x1f)            | DMA4->ReadRequestNumber);\r
+  RegVal  = ((RegVal &  ~(BIT20 | BIT19)) | DMA4->WriteRequestNumber << 19);\r
+  RegVal  = ((RegVal & ~(0x3 << 12)) | (DMA4->ReadPortAccessMode << 12));\r
+  RegVal  = ((RegVal & ~(0x3 << 14)) | (DMA4->WritePortAccessMode << 14));\r
+  RegVal  = ((RegVal & ~(0x1 <<  6)) | (DMA4->ReadPriority << 6));\r
+  RegVal  = ((RegVal & ~(0x1 << 26)) | (DMA4->WritePriority << 26));\r
+  \r
+  // Write CCR\r
+  MmioWrite32 (DMA4_CCR (Channel), RegVal);\r
+  \r
+  /* f)- Set the source element index CSEI[15:0]*/\r
+  MmioWrite32 (DMA4_CSEI (Channel), DMA4->SourceElementIndex);\r
+  \r
+  /* - Set the source frame index CSFI[15:0]*/\r
+  MmioWrite32 (DMA4_CSFI (Channel), DMA4->SourceFrameIndex);\r
+\r
+\r
+  /* - Set the destination element index CDEI[15:0]*/\r
+  MmioWrite32 (DMA4_CDEI (Channel), DMA4->DestinationElementIndex);\r
+\r
+  /* - Set the destination frame index CDFI[31:0]*/\r
+  MmioWrite32 (DMA4_CDFI (Channel), DMA4->DestinationFrameIndex);\r
+  \r
+  /* 2) Start the DMA transfer by Setting the enable bit CCR[7]=1 */\r
+  /*--------------------------------------------------------------*/\r
+  //write enable bit\r
+  MmioOr32 (DMA4_CCR(0), DMA4_CCR_ENABLE); //Launch transfer
+
+  return EFI_SUCCESS;
+}
+
+/**                                                                 \r
+  Turn of DMA channel configured by EnableDma().\r
+            \r
+  @param  Channel               DMA Channel to configure\r
+                                  \r
+  @retval EFI_SUCCESS           DMA hardware disabled\r
+  @retval EFI_INVALID_PARAMETER Channel is not valid\r
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested information.\r
+                                   \r
+**/
+EFI_STATUS
+EFIAPI
+DisableDmaChannel (
+  IN  UINTN       Channel
+  )
+{
+  if (Channel > DMA4_MAX_CHANNEL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  MmioAnd32 (DMA4_CCR(0), ~(DMA4_CCR_ENABLE | DMA4_CCR_RD_ACTIVE | DMA4_CCR_WR_ACTIVE)); 
+  return EFI_SUCCESS;
+}
+
+/**                                                                 \r
+  Provides the DMA controller-specific addresses needed to access system memory.\r
+  \r
+  Operation is relative to the DMA bus master.\r
+            \r
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.\r
+  @param  HostAddress           The system memory address to map to the DMA controller.\r
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes\r
+                                that were mapped.                                                 \r
+  @param  DeviceAddress         The resulting map address for the bus master controller to use to\r
+                                access the hosts HostAddress.                                        \r
+  @param  Mapping               A resulting value to pass to Unmap().\r
+                                  \r
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.\r
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.                                \r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.\r
+                                   \r
+**/
+EFI_STATUS
+EFIAPI
+DmaMap (
+  IN     DMA_MAP_OPERATION              Operation,
+  IN     VOID                           *HostAddress,\r
+  IN OUT UINTN                          *NumberOfBytes,\r
+  OUT    PHYSICAL_ADDRESS               *DeviceAddress,\r
+  OUT    VOID                           **Mapping\r
+  )
+{
+  MAP_INFO_INSTANCE     *Map;
+
+  if ( HostAddress == NULL || NumberOfBytes == NULL || 
+       DeviceAddress == NULL || Mapping == NULL ) {
+    return EFI_INVALID_PARAMETER;
+  }
+  
+
+  if (Operation >= MapOperationMaximum) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *DeviceAddress = ConvertToPhysicalAddress (HostAddress);
+
+  // Remember range so we can flush on the other side
+  Map = AllocatePool (sizeof (MAP_INFO_INSTANCE));
+  if (Map == NULL) {
+    return  EFI_OUT_OF_RESOURCES;
+  }
+  
+  *Mapping = Map;
+
+  Map->HostAddress   = (UINTN)HostAddress;
+  Map->DeviceAddress = *DeviceAddress;
+  Map->NumberOfBytes = *NumberOfBytes;
+  Map->Operation     = Operation;
+
+  // EfiCpuFlushTypeWriteBack, EfiCpuFlushTypeInvalidate
+  gCpu->FlushDataCache (gCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress, *NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate);
+  
+  return EFI_SUCCESS;
+}
+
+
+/**                                                                 \r
+  Completes the DmaMapBusMasterRead(), DmaMapBusMasterWrite(), or DmaMapBusMasterCommonBuffer()\r
+  operation and releases any corresponding resources.\r
+            \r
+  @param  Mapping               The mapping value returned from DmaMap*().\r
+                                  \r
+  @retval EFI_SUCCESS           The range was unmapped.\r
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.\r
+                                   \r
+**/
+EFI_STATUS
+EFIAPI
+DmaUnmap (
+  IN  VOID                         *Mapping\r
+  )
+{
+  MAP_INFO_INSTANCE *Map;
+  
+  if (Mapping == NULL) {
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+  
+  Map = (MAP_INFO_INSTANCE *)Mapping;
+  if (Map->Operation == MapOperationBusMasterWrite) {
+    //
+    // Make sure we read buffer from uncached memory and not the cache
+    //
+    gCpu->FlushDataCache (gCpu, Map->HostAddress, Map->NumberOfBytes, EfiCpuFlushTypeInvalidate);
+  } 
+  
+  FreePool (Map);
+
+  return EFI_SUCCESS;
+}
+
+/**                                                                 \r
+  Allocates pages that are suitable for an DmaMap() of type MapOperationBusMasterCommonBuffer.\r
+  mapping.                                                                       \r
+            \r
+  @param  MemoryType            The type of memory to allocate, EfiBootServicesData or\r
+                                EfiRuntimeServicesData.                               \r
+  @param  Pages                 The number of pages to allocate.                                \r
+  @param  HostAddress           A pointer to store the base system memory address of the\r
+                                allocated range.                                        \r
+\r
+                                @retval EFI_SUCCESS           The requested memory pages were allocated.\r
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are\r
+                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.                     \r
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.  \r
+                                   \r
+**/EFI_STATUS
+EFIAPI
+DmaAllocateBuffer (
+  IN  EFI_MEMORY_TYPE              MemoryType,
+  IN  UINTN                        Pages,\r
+  OUT VOID                         **HostAddress\r
+  )\r
+{
+  if (HostAddress == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
+  //
+  // We used uncached memory to keep coherency
+  //
+  if (MemoryType == EfiBootServicesData) {
+    *HostAddress = UncachedAllocatePages (Pages);
+  } else if (MemoryType != EfiRuntimeServicesData) {
+    *HostAddress = UncachedAllocateRuntimePages (Pages);
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**                                                                 \r
+  Frees memory that was allocated with DmaAllocateBuffer().\r
+            \r
+  @param  Pages                 The number of pages to free.                                \r
+  @param  HostAddress           The base system memory address of the allocated range.                                    \r
+                                  \r
+  @retval EFI_SUCCESS           The requested memory pages were freed.\r
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
+                                was not allocated with DmaAllocateBuffer().\r
+                                     \r
+**/\r
+EFI_STATUS
+EFIAPI
+DmaFreeBuffer (
+  IN  UINTN                        Pages,\r
+  IN  VOID                         *HostAddress\r
+  )\r
+{
+  if (HostAddress == NULL) {
+     return EFI_INVALID_PARAMETER;
+  } 
+  
+  UncachedFreePages (HostAddress, Pages);
+  return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+OmapDmaLibConstructor (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  EFI_STATUS              Status;
+
+  // Get the Cpu protocol for later use
+  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
+  ASSERT_EFI_ERROR(Status);
+
+  return EFI_SUCCESS;
+}
+