fimc-dev.c 是Samsung FIMC 设备的V4L2 驱动。上层应用直接操作这个设备,进行capture,图片处理,以及overlay输出。
43 int fimc_dma_alloc(struct fimc_control *ctrl, struct fimc_buf_set *bs,
44 int i, int align)
45 {
46 dma_addr_t end, *curr;
47
48 mutex_lock(&ctrl->alloc_lock);
49
50 end = ctrl->mem.base + ctrl->mem.size;
51 curr = &ctrl->mem.curr;
52
53 if (!bs->length[i])
54 return -EINVAL;
55
56 if (!align) {
57 if (*curr + bs->length[i] > end) {
58 goto overflow;
59 } else {
60 bs->base[i] = *curr;
61 bs->garbage[i] = 0;
62 *curr += bs->length[i];
63 }
64 } else {
65 if (ALIGN(*curr, align) + bs->length[i] > end)
66 goto overflow;
67 else {
68 bs->base[i] = ALIGN(*curr, align);
69 bs->garbage[i] = ALIGN(*curr, align) - *curr;
70 *curr += (bs->length[i] + bs->garbage[i]);
71 }
72 }
73
74 mutex_unlock(&ctrl->alloc_lock);
75
76 return 0;
77
78 overflow:
79 bs->base[i] = 0;
80 bs->length[i] = 0;
81 bs->garbage[i] = 0;
82
83 mutex_unlock(&ctrl->alloc_lock);
84
85 return -ENOMEM;
86 }
这个函数很简单,之所以提出来说下,是因为我在DMA对齐问题上卡了一个多星期
FIMC使用预分配的物理内存来申请DMA buffer,参数中的align指明申请buffer的对齐方式,对于FIMC capture来说,似乎output DMA要求4k对齐(尽管我没有在datasheet中找到),如果给定的DMA地址没有4K对齐,FIMC DMA控制器会很聪明的从4K对齐的地址开始传送数据,这会导致了帧数据偏移。
@i 参数指定了plane数,FIMC 输出支持很多种格式,有单层的比如YUYV,两层的V4L2_PIX_FMT_NV12,还有三层的V4L2_PIX_FMT_NV12T
单层格式输出申请一个buffer,两层格式输出申请两个buffer,三层则需申请三个buffer。
88 void fimc_dma_free(struct fimc_control *ctrl, struct fimc_buf_set *bs, int i)
89 {
90 int total = bs->length[i] + bs->garbage[i];
91 mutex_lock(&ctrl->alloc_lock);
92
93 if (bs->base[i]) {
94 if (ctrl->mem.curr - total >= ctrl->mem.base)
95 ctrl->mem.curr -= total;
96
97 bs->base[i] = 0;
98 bs->length[i] = 0;
99 bs->garbage[i] = 0;
100 }
101
102 mutex_unlock(&ctrl->alloc_lock);
103 }
这个函数有问题,93 ~ 95 成立的条件是bs->base[i]所占的地址必须在ctrl->mem.base最后面,显然,这不一定成立。
655 static inline int fimc_mmap_cap(struct file *filp, struct vm_area_struct *vma)
656 {
657 struct fimc_prv_data *prv_data =
658 (struct fimc_prv_data *)filp->private_data;
659 struct fimc_control *ctrl = prv_data->ctrl;
660 u32 size