first and last commit

This commit is contained in:
Chris Nutter committed 2023-07-08 13:03:17 -07:00
commit 1bf4efd552
2612 files changed
+636500

No files matched your search

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2010 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#ifndef __AE2_DMA_H__
#define __AE2_DMA_H__
typedef void * dma_object_t;
/*
* dma_object_t is an object that can be used to control a dma
*/
typedef enum {
kDirectionNone = 0,
kDirectionIn = 1,
kDirectionOut = 2
} DMADirection;
typedef struct LLI
{
uint32_t source;
uint32_t destination;
struct LLI *next;
uint32_t control;
} DMALinkedListItem;
typedef enum {
kI2S_0 = 0,
kI2S_1,
kI2S_2,
kI2S_3,
kMCA_0,
kMCA_1,
kAudioDevice_Last
} AudioDevice_Index;
// create a dma object that will transfer to/from a buffer from/to a device, depending
// on the direction.
dma_object_t create_dma_object(void *buffer, AudioDevice_Index device, DMALinkedListItem *chain, DMADirection direction, size_t bytesToTransfer);
void destroy_dma_object(dma_object_t dma);
void setupInterruptHandler(dma_object_t dma, int_handler handler, void *arg);
void setupErrorHandler(dma_object_t dma, int_handler handler, void *arg);
typedef enum {
kFrameError = 0,
kRXOverrun,
kRXUnderrun,
kTXOverrun,
kTXUnderrun,
kError_last
} Error_Index;
static const char* const kErrorTypeStr[kError_last] = {
"Frame_Error",
"RX_Overrun",
"RX_Underrun",
"TX_Overrun",
"TX_Underrun",
};
uint32_t getErrorCount(dma_object_t dma, Error_Index which);
void startDMAObject(dma_object_t dma);
void stopDMAObject(dma_object_t dma, bool immediate);
#endif /* __AE2_DMA_H__ */
@@ -0,0 +1,305 @@
/*
* Copyright (C) 2010-2011 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
/**
* The PIO object pretends to be a DMA for MCA.
*/
#include "pio_ae2.h"
#include "ae2_i2s.h"
#include "ae2_mca.h"
#include <drivers/audio/audio.h>
#include <debug.h>
#include <stdlib.h>
//Per AE2 Local DMA Controller/Requests
static void* sDMAAddressRX[kAudioDevice_Last] = { (void*)rI2S0_RXDB, (void*)rI2S1_RXDB, (void*)rI2S2_RXDB, (void*)rI2S3_RXDB, (void*)rMCA0_RXDATA, (void*)rMCA1_RXDATA };
static void* sDMAAddressTX[kAudioDevice_Last] = { (void*)rI2S0_TXDB, (void*)rI2S1_TXDB, (void*)rI2S2_TXDB, (void*)rI2S3_TXDB, (void*)rMCA0_TXDATA, (void*)rMCA1_TXDATA };
static internal_pio_object_t* sPIOObjects[kNumPIOs] = { NULL };
static uint32_t sPIORunning = 0;
uint32_t readReg(uint32_t address)
{
return *(volatile uint32_t *)address;
}
void writeReg(uint32_t address, uint32_t value)
{
*(volatile uint32_t *)address = value;
}
uint32_t readMCA0Reg(uint32_t offset)
{
return readReg(rMCA0_BASE + offset);
}
void writeMCA0Reg(uint32_t offset, uint32_t value)
{
writeReg(rMCA0_BASE + offset, value);
}
dma_object_t create_dma_object(void *buffer, AudioDevice_Index device, DMALinkedListItem *chain, DMADirection direction, size_t bytesToTransfer)
{
dprintf(DEBUG_CRITICAL, "Creating a PIO object\n");
// hardcoding to support only MCA right now.
if ((device >= kAudioDevice_Last) || ((direction != kDirectionIn) && (direction != kDirectionOut)) || (device != kMCA_0))
{
dprintf(DEBUG_CRITICAL, "oops, bad arg\n");
return NULL;
}
uint32_t whichPIO = (direction == kDirectionIn) ? kPIOReceive : kPIOTransmit;
// fail if device already exists
if (sPIOObjects[whichPIO])
{
dprintf(DEBUG_CRITICAL, "PIO already exists\n");
return NULL;
}
internal_pio_object_t *This = (internal_pio_object_t*)malloc(sizeof(internal_pio_object_t));
if (This)
{
This->mWhichDevice = whichPIO;
This->mInterruptHandler = NULL;
This->mInterruptHandlerData = NULL;
for (uint32_t i = kFrameError; i < kError_last; ++i)
{
This->mErrorCount[i] = 0;
}
if (direction == kDirectionIn)
{
setupPIO(This, sDMAAddressRX[device], buffer, chain, bytesToTransfer);
}
else
{
setupPIO(This, buffer, sDMAAddressTX[device], chain, bytesToTransfer);
}
sPIOObjects[This->mWhichDevice] = This;
// we can do this here repeatedly
install_int_handler(AE2_INT_MCA0, handleAudioDeviceInterrupt, NULL);
}
return This;
}
void destroy_dma_object(dma_object_t dma)
{
// preliminary stop
stopDMAObject(dma, true);
internal_pio_object_t *This = (internal_pio_object_t*)dma;
if (This)
{
sPIOObjects[This->mWhichDevice] = NULL;
free(This);
}
}
uint32_t getErrorCount(dma_object_t dma, Error_Index which)
{
// preliminary stop
internal_pio_object_t *This = (internal_pio_object_t*)dma;
if (This)
{
return This->mErrorCount[which];
}
return 0;
}
void setupInterruptHandler(dma_object_t dma, int_handler handler, void *arg)
{
internal_pio_object_t *This = (internal_pio_object_t*)dma;
if (This)
{
This->mInterruptHandler = handler;
This->mInterruptHandlerData = arg;
}
}
void setupErrorHandler(dma_object_t dma, int_handler handler, void *arg)
{
}
void startDMAObject(dma_object_t dma)
{
internal_pio_object_t *This = (internal_pio_object_t*)dma;
if (This)
{
startPIO(This);
// we wait until two of them are ready before we unmask the int
sPIORunning |= (1 << This->mWhichDevice);
if (sPIORunning == 3)
{
unmask_int(AE2_INT_MCA0);
}
}
}
void stopDMAObject(dma_object_t dma, bool immediate)
{
internal_pio_object_t *This = (internal_pio_object_t*)dma;
if (This)
{
sPIORunning &= ~(1 << This->mWhichDevice);
if (sPIORunning != 3)
{
mask_int(AE2_INT_MCA0);
}
stopPIO(This);
}
}
bool receivePIOData(DMALinkedListItem * item)
{
// we do burst sizes of 16-bit data
int16_t data[kBurstSize];
volatile uint32_t * src = (volatile uint32_t *)item->source;
for (size_t i = 0; i < sizeof(data)/sizeof(data[0]); ++i)
{
data[i] = *src;
}
uint8_t * dst = (uint8_t*)item->destination;
memcpy(dst, data, sizeof(data));
dst += sizeof(data);
item->destination = (uint32_t) dst;
item->control -= sizeof(data);
return !item->control;
}
bool transmitPIOData(DMALinkedListItem * item)
{
// we do burst sizes of 16-bit data
int16_t data[kBurstSize];
uint8_t * src = (uint8_t*)item->source;
memcpy(data, src, sizeof(data));
volatile uint32_t * dst = (volatile uint32_t *)item->destination;
for (size_t i = 0; i < sizeof(data)/sizeof(data[0]); ++i)
{
*dst = data[i];
}
src += sizeof(data);
item->source = (uint32_t) src;
item->control -= sizeof(data);
return !item->control;
}
void setupNextLLI(DMALinkedListItem * item)
{
*item = *(item->next);
}
void handleAudioDeviceInterrupt()
{
uint32_t status = readMCA0Reg(rMCASTATUS);
// <rdar://problem/13467070> Panic when setting AppleSongbirdDSP sidetone EQ
// clear any sort of sticky-bit errors.
uint32_t errors = status & ( rMCASTATUS_FRAMEEEROR_MASK | rMCASTATUS_RXOVERRUN_MASK | rMCASTATUS_RXUNDERRUN_MASK | rMCASTATUS_TXOVERRUN_MASK | rMCASTATUS_TXUNDERRUN_MASK );
writeMCA0Reg(rMCASTATUS, errors);
if (errors)
{
if (sPIOObjects[kPIOReceive])
{
if (status & rMCASTATUS_FRAMEEEROR_MASK) ++sPIOObjects[kPIOReceive]->mErrorCount[kFrameError];
if (status & rMCASTATUS_RXOVERRUN_MASK) ++sPIOObjects[kPIOReceive]->mErrorCount[kRXOverrun];
if (status & rMCASTATUS_RXUNDERRUN_MASK) ++sPIOObjects[kPIOReceive]->mErrorCount[kRXUnderrun];
if (status & rMCASTATUS_TXOVERRUN_MASK) ++sPIOObjects[kPIOReceive]->mErrorCount[kTXOverrun];
if (status & rMCASTATUS_TXUNDERRUN_MASK) ++sPIOObjects[kPIOReceive]->mErrorCount[kTXUnderrun];
}
}
if (status & (1 << rMCASTATUS_RXHIGHWATER))
{
if (sPIOObjects[kPIOReceive])
{
if (receivePIOData(&sPIOObjects[kPIOReceive]->mCurrentDMAItem))
{
setupNextLLI(&sPIOObjects[kPIOReceive]->mCurrentDMAItem);
if (sPIOObjects[kPIOReceive]->mInterruptHandler)
{
sPIOObjects[kPIOReceive]->mInterruptHandler(sPIOObjects[kPIOReceive]->mInterruptHandlerData);
}
}
}
}
if (status & (1 << rMCASTATUS_TXLOWWATER))
{
if (sPIOObjects[kPIOTransmit])
{
if (transmitPIOData(&sPIOObjects[kPIOTransmit]->mCurrentDMAItem))
{
setupNextLLI(&sPIOObjects[kPIOTransmit]->mCurrentDMAItem);
if (sPIOObjects[kPIOTransmit]->mInterruptHandler)
{
sPIOObjects[kPIOTransmit]->mInterruptHandler(sPIOObjects[kPIOTransmit]->mInterruptHandlerData);
}
}
}
}
}
void setupPIO(internal_pio_object_t * This, void *src, void *dst, DMALinkedListItem *chain, size_t bytesToTransfer)
{
uint32_t transferSize = bytesToTransfer;
uint32_t control = transferSize;
DMALinkedListItem *chainElement = chain;
while(chainElement != NULL)
{
chainElement->control = (uint32_t)control;
chainElement = chainElement->next;
if(chainElement == chain)
{
//We've populated all of the control values in this circular linked list, we are done here
break;
}
}
This->mCurrentDMAItem.source = (uint32_t)src;
This->mCurrentDMAItem.destination = (uint32_t)dst;
This->mCurrentDMAItem.next = chain;
This->mCurrentDMAItem.control = control;
}
void startPIO(internal_pio_object_t * pio_object)
{
if (pio_object)
{
if (pio_object->mWhichDevice == kPIOReceive)
{
uint32_t MCAUNSRXCFG = readMCA0Reg(rMCAUNSRXCFG);
writeMCA0Reg(rMCAUNSRXCFG, MCAUNSRXCFG | (1 << rMCAUNSRXCFG_IRQ_EN));
}
else
{
uint32_t MCAUNSTXCFG = readMCA0Reg(rMCAUNSTXCFG);
writeMCA0Reg(rMCAUNSTXCFG, MCAUNSTXCFG | (1 << rMCAUNSTXCFG_IRQ_EN));
}
}
}
void stopPIO(internal_pio_object_t * pio_object)
{
if (pio_object)
{
if (pio_object->mWhichDevice == kPIOReceive)
{
uint32_t MCAUNSRXCFG = readMCA0Reg(rMCAUNSRXCFG);
writeMCA0Reg(rMCAUNSRXCFG, MCAUNSRXCFG & ~((1 << rMCAUNSRXCFG_IRQ_EN)));
}
else
{
uint32_t MCAUNSTXCFG = readMCA0Reg(rMCAUNSTXCFG);
writeMCA0Reg(rMCAUNSTXCFG, MCAUNSTXCFG & ~((1 << rMCAUNSTXCFG_IRQ_EN)));
}
}
}
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2010 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#ifndef __PL080DMAC_AE2__
#define __PL080DMAC_AE2__
#include <stdint.h>
#include <platform/int.h>
#include "ae2_dma.h"
typedef enum {
kPIOReceive = 0,
kPIOTransmit = 1,
kNumPIOs = 2,
} ePIOType;
enum { kBurstSize = 4 };
typedef struct
{
ePIOType mWhichDevice;
int_handler mInterruptHandler;
void * mInterruptHandlerData;
DMALinkedListItem mCurrentDMAItem;
uint32_t mErrorCount[kAudioDevice_Last];
} internal_pio_object_t;
void handleAudioDeviceInterrupt();
/*
setup pio. Set the DMA linked list for doing PIO operations.
preps the pio_object for doing it's first pio op
*/
void setupPIO(internal_pio_object_t * pio_object, void *src, void *dst, DMALinkedListItem *chain, size_t bytesToTransfer);
/*
Startup PIO
*/
void startPIO(internal_pio_object_t * pio_object);
/*
Stop PIO
*/
void stopPIO(internal_pio_object_t * pio_object);
#endif /* __PL080DMAC_AE2__ */
@@ -0,0 +1,380 @@
/*
* Copyright (C) 2010-2011 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include "pl080dmac_ae2.h"
#include "ae2_i2s.h"
#include "ae2_mca.h"
#include <drivers/audio/audio.h>
#include <debug.h>
#include <stdlib.h>
#ifdef MAP_SRAM_CACHED
#error DMA requires the SRAM to be uncached
#endif
typedef struct
{
uint32_t mDMAChannel;
int_handler mInterruptHandler;
void * mInterruptHandlerData;
int_handler mErrorHandler;
void * mErrorHandlerData;
} internal_dma_object_t;
#define validDMAChannel(dmaChannel) (dmaChannel!=0xffffffff)
//Per AE2 Local DMA Controller/Requests
static const uint32_t sDMARequestInterfaceRx[kAudioDevice_Last] = {0, 2, 4, 6, 10, 6};
static const uint32_t sDMARequestInterfaceTx[kAudioDevice_Last] = {1, 3, 5, 7, 11, 7};
static void* sDMAAddressRX[kAudioDevice_Last] = { (void*)rI2S0_RXDB, (void*)rI2S1_RXDB, (void*)rI2S2_RXDB, (void*)rI2S3_RXDB, (void*)rMCA0_RXDATA, (void*)rMCA1_RXDATA };
static void* sDMAAddressTX[kAudioDevice_Last] = { (void*)rI2S0_TXDB, (void*)rI2S1_TXDB, (void*)rI2S2_TXDB, (void*)rI2S3_TXDB, (void*)rMCA0_TXDATA, (void*)rMCA1_TXDATA };
static internal_dma_object_t* sDMAChannelObjects[kDMAChannelsPerController] = { NULL };
static uint32_t sDMACC0InUse = 0;
static uint32_t sDMACC0Running = 0;
uint32_t readReg(uint32_t address)
{
return *(volatile uint32_t *)address;
}
void writeReg(uint32_t address, uint32_t value)
{
*(volatile uint32_t *)address = value;
}
uint32_t readDMAReg(uint32_t offset)
{
return readReg(kDMACBase + offset);
}
void writeDMAReg(uint32_t offset, uint32_t value)
{
writeReg(kDMACBase + offset, value);
}
uint32_t readDMAChannelReg(uint32_t channel, uint32_t offset)
{
uint32_t dmaChannelOffset = kDMAC0Base + channel * kDMACRegisterSize;
return readReg(dmaChannelOffset + offset);
}
void writeDMAChannelReg(uint32_t channel, uint32_t offset, uint32_t value)
{
uint32_t dmaChannelOffset = kDMAC0Base + channel * kDMACRegisterSize;
writeReg(dmaChannelOffset + offset, value);
}
dma_object_t create_dma_object(void *buffer, AudioDevice_Index device, DMALinkedListItem *chain, DMADirection direction, size_t bytesToTransfer)
{
dprintf(DEBUG_CRITICAL, "Creating a DMA object\n");
if ((device >= kAudioDevice_Last) || ((direction != kDirectionIn) && (direction != kDirectionOut)))
{
dprintf(DEBUG_CRITICAL, "oops, bad arg\n");
return NULL;
}
internal_dma_object_t *This = (internal_dma_object_t*)malloc(sizeof(internal_dma_object_t));
if (This)
{
uint32_t dmaChannel = acquireDMAChannel();
dprintf(DEBUG_CRITICAL, "channel is %d\n", dmaChannel);
if (dmaChannel == 0xFFFFFFFF)
{
free(This);
return NULL;
}
This->mDMAChannel = dmaChannel;
This->mInterruptHandler = NULL;
This->mInterruptHandlerData = NULL;
This->mErrorHandler = NULL;
This->mErrorHandlerData = NULL;
configureDMA(This->mDMAChannel);
if (direction == kDirectionIn)
{
setupDMA(This->mDMAChannel, sDMAAddressRX[device], buffer, chain, kDirectionIn, sDMARequestInterfaceRx[device], bytesToTransfer);
}
else
{
setupDMA(This->mDMAChannel, buffer, sDMAAddressTX[device], chain, kDirectionOut, sDMARequestInterfaceTx[device], bytesToTransfer);
}
sDMAChannelObjects[This->mDMAChannel] = This;
// we can do this here repeatedly
install_int_handler(AE2_INT_DMACINTTC, handleAudioDeviceDMAInterrupt, NULL);
install_int_handler(AE2_INT_DMACINTERR, handleAudioDeviceDMAInterruptError, NULL);
}
return This;
}
void destroy_dma_object(dma_object_t dma)
{
// preliminary stop
stopDMAObject(dma, true);
internal_dma_object_t *This = (internal_dma_object_t*)dma;
if (This)
{
sDMAChannelObjects[This->mDMAChannel] = NULL;
freeDMAChannel(This->mDMAChannel);
free(This);
}
}
uint32_t getErrorCount(dma_object_t, Error_Index)
{
return 0;
}
void setupInterruptHandler(dma_object_t dma, int_handler handler, void *arg)
{
internal_dma_object_t *This = (internal_dma_object_t*)dma;
if (This)
{
This->mInterruptHandler = handler;
This->mInterruptHandlerData = arg;
}
}
void setupErrorHandler(dma_object_t dma, int_handler handler, void *arg)
{
internal_dma_object_t *This = (internal_dma_object_t*)dma;
if (This)
{
This->mErrorHandler = handler;
This->mErrorHandlerData = arg;
}
}
void startDMAObject(dma_object_t dma)
{
internal_dma_object_t *This = (internal_dma_object_t*)dma;
if (This)
{
startDMA(This->mDMAChannel);
sDMACC0Running |= (1 << This->mDMAChannel);
if (sDMACC0Running)
{
unmask_int(AE2_INT_DMACINTTC);
unmask_int(AE2_INT_DMACINTERR);
}
}
}
void stopDMAObject(dma_object_t dma, bool immediate)
{
internal_dma_object_t *This = (internal_dma_object_t*)dma;
if (This)
{
if (immediate)
{
disableDMAImmediate(This->mDMAChannel);
}
else
{
disableDMA(This->mDMAChannel);
}
sDMACC0Running &= ~(1 << This->mDMAChannel);
if (!sDMACC0Running)
{
mask_int(AE2_INT_DMACINTTC);
mask_int(AE2_INT_DMACINTERR);
}
}
}
void handleAudioDeviceDMAInterrupt()
{
uint32_t status = readDMAReg(kDMACIntTCStatus);
for (uint32_t channel = 0; channel < kDMAChannelsPerController; channel++)
{
uint32_t mask = 1 << channel;
if (status & mask)
{
writeDMAReg(kDMACIntTCClear, mask); //clear int
if(sDMAChannelObjects[channel] != NULL && sDMAChannelObjects[channel]->mInterruptHandler)
{
sDMAChannelObjects[channel]->mInterruptHandler(sDMAChannelObjects[channel]->mInterruptHandlerData);
}
}
}
}
void handleAudioDeviceDMAInterruptError()
{
uint32_t status = readDMAReg(kDMACIntErrStatus);
for (uint32_t channel = 0; channel < kDMAChannelsPerController; channel++)
{
uint32_t mask = 1 << channel;
if (status & mask)
{
writeDMAReg(kDMACIntErrClear, mask); //clear int
if(sDMAChannelObjects[channel] != NULL && sDMAChannelObjects[channel]->mInterruptHandler)
{
sDMAChannelObjects[channel]->mInterruptHandler(sDMAChannelObjects[channel]->mInterruptHandlerData);
}
}
}
}
uint32_t acquireDMAChannel(void)
{
uint32_t result = 0xFFFFFFFF;
for(uint32_t channel = 0; channel < kDMAChannelsPerController; channel++)
{
if(!(sDMACC0InUse & (1 << channel)))
{
sDMACC0InUse |= (1 << channel);
result = channel;
break;
}
}
if (sDMACC0InUse)
{
writeReg(kDMACClockGating, 0);
writeDMAReg(kDMACConfiguration, DMACConfiguration_M2_Little | DMACConfiguration_M1_Little | DMACConfiguration_E_Enable);
}
return result;
}
void freeDMAChannel(uint32_t dmaChannel)
{
sDMACC0InUse &= ~(1 << dmaChannel);
// if there are no channels in use, shut down DMA
if (!sDMACC0InUse)
{
uint32_t config = readDMAReg(kDMACConfiguration);
writeDMAReg(kDMACConfiguration, config & ~DMACConfiguration_E_Enable);
}
}
void configureDMA(uint32_t dmaChannel)
{
if(!validDMAChannel(dmaChannel)) return;
uint32_t control = DMACCxControl_I_Enable |
DMACCxControl_D_Master1 |
DMACCxControl_S_Master1 |
DMACCxControl_SWidth_Halfword |
DMACCxControl_DWidth_Halfword |
DMACCxControl_SBSize_4 |
DMACCxControl_DBSize_4;
writeDMAChannelReg(dmaChannel, kDMACCtrlOffset, control);
}
void setupDMA(uint32_t dmaChannel, void *src, void *dst, DMALinkedListItem *chain, DMADirection direction, uint32_t peripheral, size_t bytesToTransfer)
{
if(!validDMAChannel(dmaChannel)) return;
uint32_t transferSize = bytesToTransfer >> 1; //assuming burst size of DMACCxControl_DWidth_Halfword
uint32_t control = readDMAChannelReg(dmaChannel, kDMACCtrlOffset);
control &= ~(DMACCxControl_TransferSizeMask | // Clear transfer size
DMACCxControl_SI_Mask | // Clear source increment
DMACCxControl_DI_Mask); // Clear destination increment
control |= (transferSize & 0x0FFF);
uint32_t flowControl, sourcePeripheral, destinationPeripheral;
if(direction == kDirectionIn) // -> peripheral-to-memory
{
control |= DMACCxControl_SI_No_Increment;
control |= DMACCxControl_DI_Increment;
flowControl = DMACCxConfiguration_FlowCntrl_Peripheral_to_Memory_DMA;
sourcePeripheral = peripheral;
destinationPeripheral = 0; //mem
}
else if(direction == kDirectionOut) //kDirectionOut -> memory-to-peripheral
{
control |= DMACCxControl_SI_Increment;
control |= DMACCxControl_DI_No_Increment;
flowControl = DMACCxConfiguration_FlowCntrl_Memory_to_Peripheral_DMA;
sourcePeripheral = 0; //mem
destinationPeripheral = peripheral;
}
else //kDirectionNone -> mem-to-mem here
{
control |= DMACCxControl_SI_Increment;
control |= DMACCxControl_DI_Increment;
flowControl = DMACCxConfiguration_FlowCntrl_Memory_to_Memory_DMA;
sourcePeripheral = 0; //mem
destinationPeripheral = 0; //mem
}
DMALinkedListItem *chainElement = chain;
while(chainElement != NULL)
{
chainElement->control = (uint32_t)control;
chainElement = chainElement->next;
if(chainElement == chain)
{
//We've populated all of the control values in this circular linked list, we are done here
break;
}
}
writeDMAChannelReg(dmaChannel, kDMACSourceOffset, (uint32_t)src);
writeDMAChannelReg(dmaChannel, kDMACDestOffset, (uint32_t)dst);
writeDMAChannelReg(dmaChannel, kDMACLLIOffset, (uint32_t)chain);
writeDMAChannelReg(dmaChannel, kDMACCtrlOffset, control);
flowControl |= DMACCxConfiguration_ITC_Enable;
flowControl |= DMACCxConfiguration_IError_Enable;
flowControl |= ((destinationPeripheral & 0xF) << 6);
flowControl |= ((sourcePeripheral & 0xF) << 1);
// do this in the start
//flowControl |= DMACCxConfiguration_E_Enable;
writeDMAChannelReg(dmaChannel, kDMACConfigOffset, flowControl);
}
void startDMA(uint32_t dmaChannel)
{
if(!validDMAChannel(dmaChannel)) return;
uint32_t flowControl = readDMAChannelReg(dmaChannel, kDMACConfigOffset);
writeDMAChannelReg(dmaChannel, kDMACConfigOffset, flowControl |= DMACCxConfiguration_E_Enable);
}
void disableDMA(uint32_t dmaChannel)
{
if(!validDMAChannel(dmaChannel)) return;
uint32_t config = readDMAChannelReg(dmaChannel, kDMACConfigOffset);
writeDMAChannelReg(dmaChannel, kDMACConfigOffset, config | DMACCxConfiguration_Halt);
config = readDMAChannelReg(dmaChannel, kDMACConfigOffset);
// give a chance for the DMA to timeout. But don't wait forever...
int timeToWait = 0x100;
while(config & DMACCxConfiguration_Active && (timeToWait-- > 0))
{
config = readDMAChannelReg(dmaChannel, kDMACConfigOffset);
}
disableDMAImmediate(dmaChannel);
}
void disableDMAImmediate(uint32_t dmaChannel)
{
if(!validDMAChannel(dmaChannel)) return;
uint32_t config = readDMAChannelReg(dmaChannel, kDMACConfigOffset);
writeDMAChannelReg(dmaChannel, kDMACConfigOffset, config & ~DMACCxConfiguration_E_Enable);
writeDMAReg(kDMACIntTCClear, 1 << dmaChannel); // clear any outstanding ints
writeDMAReg(kDMACIntErrClear, 1 << dmaChannel); // clear any outstanding ints
}
@@ -0,0 +1,123 @@
/*
* Copyright (C) 2010 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#ifndef __PL080DMAC_AE2__
#define __PL080DMAC_AE2__
#include <stdint.h>
#include <platform/int.h>
#include "ae2_dma.h"
#define kDMACClockGating 0x341A0004
#define kDMAChannelsPerController 8
#define kDMACBase 0x341A3000
#define kDMAC0Base 0x341A3100
#define kDMACIntStatus 0x0
#define kDMACIntTCStatus 0x4
#define kDMACIntTCClear 0x8
#define kDMACIntErrStatus 0xC
#define kDMACIntErrClear 0x10
#define kDMACConfiguration 0x30
#define kDMACSourceOffset 0x0
#define kDMACDestOffset 0x4
#define kDMACLLIOffset 0x8
#define kDMACCtrlOffset 0xC
#define kDMACConfigOffset 0x10
#define kDMACRegisterSize 0x20
#define DMACConfiguration_M2_Mask (1 << 2)
#define DMACConfiguration_M2_Little (0 << 2)
#define DMACConfiguration_M2_Big (1 << 2)
#define DMACConfiguration_M1_Mask (1 << 1)
#define DMACConfiguration_M1_Little (0 << 1)
#define DMACConfiguration_M1_Big (1 << 1)
#define DMACConfiguration_E_Mask (1 << 0)
#define DMACConfiguration_E_Disable (0 << 0)
#define DMACConfiguration_E_Enable (1 << 0)
#define DMACCxConfiguration_Halt (1 << 18)
#define DMACCxConfiguration_Active (1 << 17)
#define DMACCxConfiguration_ITC_Enable (1 << 15)
#define DMACCxConfiguration_IError_Enable (1 << 14)
#define DMACCxConfiguration_E_Enable (1 << 0)
#define DMACCxControl_I_Mask (1 << 31)
#define DMACCxControl_I_Disable (0 << 31)
#define DMACCxControl_I_Enable (1 << 31)
#define DMACCxControl_SI_Mask (1 << 26)
#define DMACCxControl_SI_No_Increment (0 << 26)
#define DMACCxControl_SI_Increment (1 << 26)
#define DMACCxControl_DI_Mask (1 << 27)
#define DMACCxControl_DI_No_Increment (0 << 27)
#define DMACCxControl_DI_Increment (1 << 27)
#define DMACCxControl_D_Master1 (0 << 25)
#define DMACCxControl_S_Master1 (0 << 24)
#define DMACCxControl_SWidth_Halfword (1 << 18)
#define DMACCxControl_DWidth_Halfword (1 << 21)
#define DMACCxControl_DBSize_1 (0 << 15)
#define DMACCxControl_DBSize_4 (1 << 15)
#define DMACCxControl_SBSize_1 (0 << 12)
#define DMACCxControl_SBSize_4 (1 << 12)
#define DMACCxControl_TransferSizeMask (0x0FFF)
#define DMACCxConfiguration_FlowCntrl_Memory_to_Memory_DMA (0 << 11)
#define DMACCxConfiguration_FlowCntrl_Memory_to_Peripheral_DMA (1 << 11)
#define DMACCxConfiguration_FlowCntrl_Peripheral_to_Memory_DMA (2 << 11)
void handleAudioDeviceDMAInterrupt();
void handleAudioDeviceDMAInterruptError();
/*
Get a free DMA channel
*/
uint32_t acquireDMAChannel(void);
/*
Free a DMA channel
*/
void freeDMAChannel(uint32_t dmaChannel);
/*
Make sure the pl080 clock is enabled and initialize DMA channels 0 and 1
*/
void configureDMA(uint32_t dmaChannel);
/*
Startup DMA from address src to destination dst
If chain is not NULL, will setup that in the LLI to auto-restart DMA from the chain
*/
void setupDMA(uint32_t dmaChannel, void *src, void *dst, DMALinkedListItem *chain, DMADirection direction, uint32_t peripheral, size_t bytesToTransfer);
/*
Startup DMA from address src to destination dst
If chain is not NULL, will setup that in the LLI to auto-restart DMA from the chain
*/
void startDMA(uint32_t dmaChannel);
/*
Halts the channel, then blocks until the DMA is complete and then fully disables it
*/
void disableDMA(uint32_t dmaChannel);
/*
Blocks until the DMA is complete and then fully disables it
*/
void disableDMAImmediate(uint32_t dmaChannel);
#endif /* __PL080DMAC_AE2__ */