📄 dma.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
#include <windows.h>
#include <ceddk.h>
#include <string.h>
#include <stdio.h>
#include <tchar.h>
#include <nkintr.h>
#include "qci.h"
#include "qci_private.h"
#define MAX_BUF_NUM 1200
#define MAX_FRAG_NUM 10
#define MAX_EMPTY_NUM 5
#define SINGLE_DESCRIPTOR_TRANSFER_MAX 4096
frame_list_t *current_frame_list;
frame_t *video_frame_tail;
static void frame_dma_link(frame_t *f1, frame_t *f2);
static void free_frame(frame_t* frame);
static frame_list_t* find_frame_list(format_t* format);
static void frame_free_dma_buf(frame_t *frame);
void DMABufAlloc(dma_buf_t *buf, UINT32 size, BOOL cache)
{
DMA_ADAPTER_OBJECT adapter;
PHYSICAL_ADDRESS phy_addr;
adapter.ObjectSize = sizeof (DMA_ADAPTER_OBJECT);
adapter.InterfaceType = Internal;
adapter.BusNumber = 0;
buf->buf = HalAllocateCommonBuffer(&adapter, size, &phy_addr, FALSE);
buf->phy_addr = phy_addr.LowPart;
buf->size = size;
if (!buf->buf)
{
ERRORMSG(1,(L"[Camera]: QCI Failed to AllocateBuffer!!!\r\n"));
return;
}
if (cache)
buf->buf = MmMapIoSpace(phy_addr, size, TRUE);
}
void DMABufFree(dma_buf_t *buf)
{
PHYSICAL_ADDRESS phy_addr;
if (buf->buf == NULL)
return;
memset(&phy_addr, 0, sizeof(phy_addr));
HalFreeCommonBuffer(NULL, 0, phy_addr, (PVOID)buf->buf, 0);
buf->buf = NULL;
}
#define DMA_DESC_SIZE (sizeof(PXA_CI_DMAC_DESCRIPTOR_T))
// Add the buffer into the buffer pool and generate the DMA chains for the buffer
static BOOL dma_chain_init(plane_t *plane,
UINT32 dma_chain)
{
UINT32 i, n = 0;
UINT32 size = 0;
UINT32 remain = 0;
PXA_CI_DMAC_DESCRIPTOR_T *descs;
UINT32 descs_n;
UINT32 phy_addr;
UINT32 buf_phy_addr;
descs = (PXA_CI_DMAC_DESCRIPTOR_T*)plane->desc_buf.buf;
descs_n = plane->desc_buf.size / sizeof(*descs);
phy_addr = plane->desc_buf.phy_addr;
remain = plane->buf.size;
buf_phy_addr = plane->buf.phy_addr;
for (i = 0; i < descs_n; i++)
{
if (remain == 0)
{
ERRORMSG(1, (L"[Camera]: DMA buffer is smaller than expected!!!\r\n"));
return FALSE;
}
size = remain > SINGLE_DESCRIPTOR_TRANSFER_MAX?
SINGLE_DESCRIPTOR_TRANSFER_MAX : remain;
phy_addr += sizeof(*descs);
descs[i].ddadr = phy_addr;
descs[i].dsadr = dma_chain;
descs[i].dtadr = buf_phy_addr;
descs[i].dcmd = size | PXA_CI_DMAC_DCMD_INC_TRG_ADDR;
remain -= size;
buf_phy_addr += size;
}
return TRUE;
}
// calculate frame buffer sizes by frame format and dimension
static void get_buffer_desc_size(int format,
UINT32 width,
UINT32 height,
int plane_size[3],
int n_descs[3])
{
UINT32 frame_size;
int i;
plane_size[0] = 0;
plane_size[1] = 0;
plane_size[2] = 0;
switch(format)
{
case PXA_CAMERA_IMAGE_FORMAT_RAW10:
case PXA_CAMERA_IMAGE_FORMAT_RAW9:
case PXA_CAMERA_IMAGE_FORMAT_RGB565:
case PXA_CAMERA_IMAGE_FORMAT_YCBCR422_PACKED:
frame_size = width * height * 2;
plane_size[0] = frame_size;
break;
case PXA_CAMERA_IMAGE_FORMAT_RGB888_PACKED:
frame_size = width * height * 3;
plane_size[0] = frame_size;
break;
case PXA_CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR:
frame_size = width * height * 2;
plane_size[0] = frame_size / 2;
plane_size[1] = frame_size / 4;
plane_size[2] = frame_size / 4;
break;
default:
break;
}
for (i = 0; i < 3; i++)
n_descs[i] = (plane_size[i] + SINGLE_DESCRIPTOR_TRANSFER_MAX - 1)
/ SINGLE_DESCRIPTOR_TRANSFER_MAX;
}
UINT32 round(UINT32 x, UINT32 y)
{
return ((x + y - 1) / y) * y;
}
#define MIN(x, y) ((x) > (y)? (y) : (x))
static BOOL frame_alloc_dma_buf(frame_t *frame)
{
int plane_size[3];
int n_descs[3];
int i;
//UINT32 chain_tbl[3] = {g_pCIRegs->PXA_CIBR0, g_pCIRegs->PXA_CIBR1, g_pCIRegs->PXA_CIBR2};
UINT32 chain_tbl[3] = {(PXA_CI_REGBASE_PHY+0x28), (PXA_CI_REGBASE_PHY+0x30), (PXA_CI_REGBASE_PHY+0x38)};
format_t* format = &frame->list->format;
get_buffer_desc_size(format->format, format->width, format->height,
plane_size, n_descs);
for (i = 0; i < 3; i++)
{
plane_t *plane = &frame->plane[i];
int desc_buf_size;
int rev = 0;
if (!plane_size[i])
break;
desc_buf_size = n_descs[i] * sizeof(PXA_CI_DMAC_DESCRIPTOR_T);
DMABufAlloc(&plane->desc_buf, desc_buf_size, 0);
if (!plane->desc_buf.buf)
goto clean;
DMABufAlloc(&plane->buf, round(plane_size[i], 16), 1);
if (!plane->buf.buf)
goto clean;
if (!dma_chain_init(plane, chain_tbl[i]))
goto clean;
}
return TRUE;
clean:
frame_free_dma_buf(frame);
ERRORMSG(1, (L"[Camera]: Failed to Allocate DMABuffer!!!"));
return FALSE;
}
static void frame_free_dma_buf(frame_t *frame)
{
UINT32 i;
for (i = 0; i < 3; i++)
{
plane_t *plane = &frame->plane[i];
DMABufFree(&plane->buf);
DMABufFree(&plane->desc_buf);
}
}
static void frame_link(frame_t *f1, frame_t *f2)
{
f1->next = f2;
frame_dma_link(f1, f2);
}
// mark a frame before dma transfer.
// if a mark is overwritten, it means the frame is ready
const short dma_mark[4] = { 0x0, 0xffff, 0x0, 0xffff };
static char *get_mark_ptr(frame_t *frame)
{
plane_t *plane = &frame->plane[0];
dma_buf_t *buf = &plane->buf;
return buf->buf + buf->size - sizeof(dma_mark);
}
static void frame_clean_cache(frame_t *frame)
{
UINT32 i;
for (i = 0; i < 3; i++)
CacheRangeFlush(frame->plane[i].buf.buf, frame->plane[i].buf.size, CACHE_SYNC_DISCARD);
}
static void frame_mark(frame_t *frame)
{
char *mark = get_mark_ptr(frame);
memcpy(mark, dma_mark, sizeof(dma_mark));
}
static BOOL frame_check_mark(frame_t *frame)
{
//char *mark = get_mark_ptr(frame);
short *mark = (short*)get_mark_ptr(frame);
if ( dma_mark[0] == mark[0]
&& dma_mark[1] == mark[1]
&& dma_mark[2] == mark[2]
&& dma_mark[3] == mark[3] )
{
return TRUE;
}
return FALSE;
//return memcmp(mark, dma_mark, sizeof(dma_mark)) == 0;
}
static void frame_dma_link(frame_t *f1, frame_t *f2)
{
UINT32 i;
for (i = 0; i < 3; i++)
{
PXA_CI_DMAC_DESCRIPTOR_T *descs;
UINT32 descs_n;
plane_t *p1 = &f1->plane[i];
plane_t *p2 = &f2->plane[i];
if (!p1->buf.buf)
return;
descs = (PXA_CI_DMAC_DESCRIPTOR_T*)p1->desc_buf.buf;
descs_n = p1->desc_buf.size / sizeof(*descs);
descs[descs_n - 1].ddadr = p2->desc_buf.phy_addr;
}
}
static void frame_append(frame_t *frame)
{
if (!frame->list)
return;
frame->next = NULL;
frame_mark(frame);
frame_clean_cache(frame);
frame_dma_link(frame, frame);
if (!frame->list->head)
frame->list->head = frame;
else
frame_link(frame->list->tail, frame);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -