📄 pxa27x_camera.c
字号:
bFirstVideoCaptureBufferSubmitted = 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;
pLast_Pn_CH0 = (XLLP_DMAC_DESCRIPTOR_T *)VirtAddr_Last_Pn_CH0;
pLast_Pn_CH1 = (XLLP_DMAC_DESCRIPTOR_T *)VirtAddr_Last_Pn_CH1;
pLast_Pn_CH2 = (XLLP_DMAC_DESCRIPTOR_T *)VirtAddr_Last_Pn_CH2;
pLast_n_CH0 = (XLLP_DMAC_DESCRIPTOR_T *)VirtAddr_Last_n_CH0;
pLast_n_CH1 = (XLLP_DMAC_DESCRIPTOR_T *)VirtAddr_Last_n_CH1;
pLast_n_CH2 = (XLLP_DMAC_DESCRIPTOR_T *)VirtAddr_Last_n_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;
// Chain the last descriptor to this new descriptor by adding this new descriptor to the end of the chain.
// We either are already looping on the phantom descriptor by the time this frame buffer is submitted, or
// we have yet to begin looping on the phantom descriptor. Therefore, we must program the end of the phantom descriptor
// to branch to the beginning of the new descriptor. And, if we were not already looping on the phantom descriptor,
// then we want to program the last real descriptor so that it branches to the beginning of the new descriptor.
if (VirtAddr_Last_Pn_CH0)
{
pLast_Pn_CH0->DDADR = pDescriptorInfo->pPhysAddr_X1_CH0;
if (isYUV_PLANAR) pLast_Pn_CH1->DDADR = pDescriptorInfo->pPhysAddr_X1_CH1;
if (isYUV_PLANAR) pLast_Pn_CH2->DDADR = pDescriptorInfo->pPhysAddr_X1_CH2;
pLast_n_CH0->DDADR = pDescriptorInfo->pPhysAddr_X1_CH0;
if (isYUV_PLANAR) pLast_n_CH1->DDADR = pDescriptorInfo->pPhysAddr_X1_CH1;
if (isYUV_PLANAR) pLast_n_CH2->DDADR = pDescriptorInfo->pPhysAddr_X1_CH2;
}
// Update pVirtAddr_Last_Pn and pVirtAddr_Last_n so they point to this new buffer
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;
unsigned int capture_onput_format;
if (VIDEO_CAPTURE_BUFFER == BufferType)
{
capture_onput_format = g_HwContext.XllpCAMERA.Video_capture_output_format;
}
else
{
capture_onput_format = g_HwContext.XllpCAMERA.Still_capture_output_format;
}
// Determine the length of the image transfer. This is the sum of each fifo transfer length.
switch(capture_onput_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 *)pBufInfo->VirtAddr;
// 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -