📄 pxa27x_camera.c
字号:
VirtAddr_Last_Pn_CH0 = pDescriptorInfo->pVirtAddr_XPn_CH0;
VirtAddr_Last_Pn_CH1 = pDescriptorInfo->pVirtAddr_XPn_CH1;
VirtAddr_Last_Pn_CH2 = pDescriptorInfo->pVirtAddr_XPn_CH2;
VirtAddr_Last_n_CH0 = pDescriptorInfo->pVirtAddr_Xn_CH0;
VirtAddr_Last_n_CH1 = pDescriptorInfo->pVirtAddr_Xn_CH1;
VirtAddr_Last_n_CH2 = pDescriptorInfo->pVirtAddr_Xn_CH2;
} else if (BufferType == STILL_CAPTURE_BUFFER)
{
if (bFirstStillBufferSubmitted == FALSE)
{
StillCaptureDescriptorPhysicalStartAddress_CH0 = pDescriptorInfo->pPhysAddr_X1_CH0;
StillCaptureDescriptorPhysicalStartAddress_CH1 = pDescriptorInfo->pPhysAddr_X1_CH1;
StillCaptureDescriptorPhysicalStartAddress_CH2 = pDescriptorInfo->pPhysAddr_X1_CH2;
bFirstStillBufferSubmitted = TRUE;
pXPn_CH0 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_XPn_CH0;
pXPn_CH1 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_XPn_CH1;
pXPn_CH2 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_XPn_CH2;
pXn_CH0 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_Xn_CH0;
pXn_CH1 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_Xn_CH1;
pXn_CH2 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_Xn_CH2;
// Chain last phantom descriptor XPn to the first phantom descriptor XP1.
// This loops the phantom descriptor back to itself.
pXPn_CH0->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH0;
if (isYUV_PLANAR) pXPn_CH1->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH1;
if (isYUV_PLANAR) pXPn_CH2->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH2;
// Chain the last real descriptor to the start of the phantom descriptor chain
pXn_CH0->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH0;
if (isYUV_PLANAR) pXn_CH1->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH1;
if (isYUV_PLANAR) pXn_CH2->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH2;
}
}
} else
{
if (!pBufInfo)
NKDbgPrintfW(TEXT("Buffer is null. Submit buffer failed.\r\n"));
else
NKDbgPrintfW(TEXT("Buffer list had null entry. Submit buffer failed. Buffer ID %d\r\n"),pBufInfo->BufferID);
}
}
// Given a buffer allocated by the application, this function maps the buffer into discreet 4K chunks in the physical
// address space, then builds a DMA descriptor chain that performs a scatter gather DMA sequence using these
// 4K chunks as individual target buffers. It also builds a phantom descriptor chain which is executed after
// the primary descriptor chain completes. The phantom descriptor chain is created so that the DMA can run
// continuously in the background, even if there is no client ready to read the data from the primary chain. This
// way primary buffers will remain untouched, the dma activity is undisturbed, the sensor is unaware of the flow control,
// and the primary buffers remain ready for their consumption by the application that submitted them.
// Buffers are chained together based on the order in which they are submitted by the application. In this way,
// the application can now manage the buffer memory according to its own needs. If an application needs to lock
// down a buffer, it simply chooses not to resubmit that buffer until it has completed using it.
int CameraPrepareBuffer(P_CAMERA_DMA_BUFFER_INFO pBufInfo, int BufferType)
{
int limit = 0;
int i = 0;
int j = 0;
int num_descriptors;
int memory_required;
int planes_number;
DESCRIPTOR_INFO_T *pDescriptorInfo;
DWORD *pPhysicalBufferAddress;
DWORD *pPhysicalDescriptorBufferAddress;
DWORD *VirtAddr;
int fifo0_num_descriptors = 0;
int fifo1_num_descriptors = 0;
int fifo2_num_descriptors = 0;
int fifo0_transfer_size = 0;
int fifo1_transfer_size = 0;
int fifo2_transfer_size = 0;
int frame_size = (VIDEO_CAPTURE_BUFFER == BufferType ? g_HwContext.XllpCAMERA.Video_capture_width : g_HwContext.XllpCAMERA.Still_capture_width) * \
(VIDEO_CAPTURE_BUFFER == BufferType ? g_HwContext.XllpCAMERA.Video_capture_height : g_HwContext.XllpCAMERA.Still_capture_height) * 2;
// Determine the length of the image transfer. This is the sum of each fifo transfer length.
switch(g_HwContext.XllpCAMERA.capture_output_format)
{
case XLLP_CAMERA_IMAGE_FORMAT_RGB555:
case XLLP_CAMERA_IMAGE_FORMAT_RGB565:
fifo0_transfer_size = frame_size;
planes_number = 1;
break;
case XLLP_CAMERA_IMAGE_FORMAT_YCBCR422_PACKED:
fifo0_transfer_size = frame_size;
planes_number = 1;
break;
case XLLP_CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR:
fifo0_transfer_size = frame_size / 2;
fifo1_transfer_size = frame_size / 4;
fifo2_transfer_size = frame_size / 4;
planes_number = 3;
break;
default:
NKDbgPrintfW(TEXT("Unsupported capture format.\r\n"));
return FALSE;
break;
}
// Allocate some memory to store the physical address of each descriptor used to map each 4K segment
// We need one set of descriptors to DMA the data to a real buffer. We need another set of descriptors
// (phantom descriptors) to DMA the data to non-incrementing address that will be used only for flow control.
// Therefore, twice as many descriptors are required for the whole chain, than for just the primary DMA sequence.
// We can obtain physical addresses with 4K granularity. And the pages are not guaranteed to be contiguous.
// Therefore, we'll dedicate one descriptor for every 4K of image data.
fifo0_num_descriptors = (( fifo0_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
/ SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;
fifo1_num_descriptors = (( fifo1_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
/ SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;
fifo2_num_descriptors = (( fifo2_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
/ SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;
num_descriptors = fifo0_num_descriptors + fifo1_num_descriptors + fifo2_num_descriptors;
memory_required = ((num_descriptors / 2) * SINGLE_DESCRIPTOR_TRANSFER_MAX);
if (pBufInfo->size < memory_required)
{
pBufInfo->size = memory_required;
//NKDbgPrintfW(TEXT("Memory size inadequate. Need %d bytes\r\n"),pBufInfo->size);
return FALSE;
}
if (NumBuffers >= MAX_CAMERA_DMA_BUFFERS)
{
NKDbgPrintfW(TEXT("Max number of buffers reached.\r\n"));
return FALSE;
}
MasterBufferList[NumBuffers] = (DESCRIPTOR_INFO_T *)malloc(sizeof(DESCRIPTOR_INFO_T));
if (MasterBufferList[NumBuffers] == NULL)
{
NKDbgPrintfW(TEXT("Unable to allocate memory for entry into MasterBufferList.\r\n"));
return FALSE;
}
pDescriptorInfo = MasterBufferList[NumBuffers];
memset(pDescriptorInfo, 0x0, sizeof(DESCRIPTOR_INFO_T));
// Assign a unique frame ID
pDescriptorInfo->FrameID = NumBuffers;
pBufInfo->BufferID = NumBuffers;
pDescriptorInfo->dwPlanesNumber = planes_number;
VirtAddr = (DWORD *)MapCallerPtr((void *)pBufInfo->VirtAddr, pBufInfo->size);
if (VirtAddr == 0x0)
{
NKDbgPrintfW(TEXT("Unable to map application buffer 0x%x into driver's address space.\r\n"), pBufInfo->VirtAddr);
return FALSE;
}
// Set the memory to uncached, unbuffered
VirtualSetAttributes((void *)VirtAddr, memory_required, 0, 0xC, NULL);
pBufInfo->pY = (DWORD *)pBufInfo->VirtAddr;
pBufInfo->pCb = (DWORD *)pBufInfo->VirtAddr + (((fifo0_num_descriptors / 2) * SINGLE_DESCRIPTOR_TRANSFER_MAX) / 4);
pBufInfo->pCr = (DWORD *)pBufInfo->VirtAddr + (((fifo0_num_descriptors / 2) * SINGLE_DESCRIPTOR_TRANSFER_MAX) / 4)
+ (((fifo1_num_descriptors / 2) * SINGLE_DESCRIPTOR_TRANSFER_MAX) / 4);
// This list holds a pointer to each physical destination buffer
pDescriptorInfo->pBufferPhyAddress = (DWORD *)malloc(num_descriptors * sizeof(DWORD));
if (pDescriptorInfo->pBufferPhyAddress == NULL)
{
NKDbgPrintfW(TEXT("Unable to allocate memory for pDescriptorInfo->pBufferPhyAddress.\r\n"));
return FALSE;
}
pDescriptorInfo->pBufferVirtAddress = VirtAddr;
// Allocate memory for the descriptor buffer list, plus one dummy entry in order to simplify the buffer chaining logic
// The last entry in the descriptor chain needs an entry for the DDADR register, and if we allocate an extra unused entry
// in this list, we can assign the dummy value without any harm.
pDescriptorInfo->pDescriptorBufferPhyAddress = (DWORD *)malloc((num_descriptors + 1) * sizeof(DWORD));
if (!pDescriptorInfo->pDescriptorBufferPhyAddress)
{
NKDbgPrintfW(TEXT("Unable to allocate memory for pDescriptorInfo->pDescriptorBufferPhyAddress\r\n"));
return FALSE;
}
pDescriptorInfo->pDescriptorBufferVirtAddress = (DWORD *)malloc((num_descriptors + 1) * sizeof(XLLP_DMA_DESCRIPTOR_T));
if (!pDescriptorInfo->pDescriptorBufferVirtAddress)
{
NKDbgPrintfW(TEXT("Unable to allocate memory for pDescriptorInfo->pDescriptorBufferVirtAddress\r\n"));
return FALSE;
}
memset(pDescriptorInfo->pDescriptorBufferVirtAddress, 0x0, (num_descriptors + 1) * sizeof(XLLP_DMA_DESCRIPTOR_T));
// Set the descriptor memory to uncached, unbuffered so that the descriptors have valid data in them when read by the DMA engine later.
VirtualSetAttributes((void *)pDescriptorInfo->pDescriptorBufferVirtAddress, (num_descriptors + 1) * sizeof(XLLP_DMA_DESCRIPTOR_T), 0, 0xC, NULL);
// Create the lookup table that maps the user allocated virtual buffer address to the corresponding physical address.
// We know that buffers are contiguous within each 4K segment.
pPhysicalBufferAddress = pDescriptorInfo->pBufferPhyAddress;
limit = (DWORD)VirtAddr + pBufInfo->size;
// Now determine the physical addresses for each 4K segment and store them in the array maintained for this descriptor chain
for (i = (DWORD)VirtAddr; i < limit; i+= SINGLE_DESCRIPTOR_TRANSFER_MAX)
{
getPhyAddress ((DWORD *)i, pPhysicalBufferAddress);
//NKDbgPrintfW(TEXT("Target Buffer Virtual Address 0x%x has Physical address 0x%x\r\n"),i, *pPhysicalBufferAddress);
pPhysicalBufferAddress++;
}
// Create the lookup table that maps the virtual address space that was just allocated for the descriptors to the corresponding physical address.
pPhysicalDescriptorBufferAddress = pDescriptorInfo->pDescriptorBufferPhyAddress;
limit = (DWORD)(pDescriptorInfo->pDescriptorBufferVirtAddress) + ((num_descriptors + 1) * sizeof(XLLP_DMA_DESCRIPTOR_T));
// Now determine the physical addresses for each descriptor address and store them in the array maintained for this descriptor chain
for (i = (DWORD)(pDescriptorInfo->pDescriptorBufferVirtAddress); i < limit; i+= sizeof(XLLP_DMA_DESCRIPTOR_T))
{
getPhyAddress ((DWORD *)i, pPhysicalDescriptorBufferAddress);
//NKDbgPrintfW(TEXT("Descriptor Virtual Address 0x%x has Physical address 0x%x\r\n"),i, *pPhysicalDescriptorBufferAddress);
pPhysicalDescriptorBufferAddress++;
}
// Make sure we align the buffer
if (VirtAddr_Phantom_Buffer == 0x0)
{
VirtAddr_Phantom_Buffer_Base_Address = (DWORD)((DWORD *)malloc(SINGLE_DESCRIPTOR_TRANSFER_MAX + 0xFFF));
if (VirtAddr_Phantom_Buffer_Base_Address == 0x0)
{
NKDbgPrintfW(TEXT("Unable to allocate memory for VirtAddr_Phantom_Buffer\r\n"));
return FALSE;
}
VirtAddr_Phantom_Buffer = VirtAddr_Phantom_Buffer_Base_Address;
if (VirtAddr_Phantom_Buffer & 0xFFF)
{
VirtAddr_Phantom_Buffer += 0x1000 - (VirtAddr_Phantom_Buffer & 0xFFF);
}
getPhyAddress ((DWORD *)VirtAddr_Phantom_Buffer, &((DWORD)PhysAddr_Phantom_Buffer));
//NKDbgPrintfW(TEXT("Phantom buffer Virtual Address 0x%x has Physical address 0x%x\r\n"),VirtAddr_Phantom_Buffer, PhysAddr_Phantom_Buffer);
}
pDescriptorInfo->pPhysAddr_Phantom = PhysAddr_Phantom_Buffer;
GenerateDMAChain( pDescriptorInfo, fifo0_transfer_size, fifo1_transfer_size, fifo2_transfer_size);
NumBuffers++;
// return (int)pDescriptorInfo->FrameID;
return TRUE;
}
// Generate a primary descriptor chain that fills the provided buffers.
// Generate a phantom descriptor chain that executes after the primary chain.
// When buffers are chained together, each primary chain is linked to the next primary
// descriptor chain. The last primary descriptor chain is linked to the phantom descriptor chain.
int GenerateDMAChain(
DESCRIPTOR_INFO_T *pDescriptorInfo,
int fifo0_transfer_size,
int fifo1_transfer_size,
int fifo2_transfer_size
)
{
XLLP_DMAC_DESCRIPTOR_T *cur_des_virtual;
int des_transfer_size, remain_size;
unsigned int i,j,k,l;
unsigned int fifo0_num_descriptors = 0;
unsigned int fifo1_num_descriptors = 0;
unsigned int fifo2_num_descriptors = 0;
// calculate how many descriptors are needed per frame
fifo0_num_descriptors = (( fifo0_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
/ SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;
fifo1_num_descriptors = (( fifo1_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
/ SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;
fifo2_num_descriptors = (( fifo2_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
/ SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;
cur_des_virtual = (XLLP_DMAC_DESCRIPTOR_T*)pDescriptorInfo->pDescriptorBufferVirtAddress;
// First iteration, build the real chain.
// Second iteration, build the phantom chain.
k = 0;
l = 0;
for(i=0; i < 2; i++) {
remain_size = fifo0_transfer_size;
for(j=0; j < fifo0_num_descriptors >> 1; j++) {
// set descriptor
if (remain_size > SINGLE_DESCRIPTOR_TRANSFER_MAX)
des_transfer_size = SINGLE_DESCRIPTOR_TRANSFER_MAX;
else
des_transfer_size = remain_size;
// Build the primary DMA chain
if (i == 0)
{
cur_des_virtual->DDADR = (unsigned)pDescriptorInfo->pDescriptorBufferPhyAddress[++l];
cur_des_virtual->DSADR = XLLP_CI_REGBASE_PHY + XLLP_CIBR0; // FIFO0 physical address
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -