/* * To handle RAW format we are re-using the CBY422 * vpdma data type so that we use the vpdma to re-order * the incoming bytes, as the parser assumes that the * first byte presented on the bus is the MSB of a 2 * bytes value. * RAW8 handles from 1 to 8 bits * RAW16 handles from 9 to 16 bits
*/ conststruct vpdma_data_format vpdma_raw_fmts[] = {
[VPDMA_DATA_FMT_RAW8] = {
.type = VPDMA_DATA_FMT_TYPE_YUV,
.data_type = DATA_TYPE_CBY422,
.depth = 8,
},
[VPDMA_DATA_FMT_RAW16] = {
.type = VPDMA_DATA_FMT_TYPE_YUV,
.data_type = DATA_TYPE_CBY422,
.depth = 16,
},
};
EXPORT_SYMBOL(vpdma_raw_fmts);
/* * dumping registers of only group0 and group3, because VPE channels * lie within group0 and group3 registers
*/
DUMPREG(INT_CHAN_STAT(0));
DUMPREG(INT_CHAN_MASK(0));
DUMPREG(INT_CHAN_STAT(3));
DUMPREG(INT_CHAN_MASK(3));
DUMPREG(INT_CLIENT0_STAT);
DUMPREG(INT_CLIENT0_MASK);
DUMPREG(INT_CLIENT1_STAT);
DUMPREG(INT_CLIENT1_MASK);
DUMPREG(INT_LIST0_STAT);
DUMPREG(INT_LIST0_MASK);
/* * these are registers specific to VPE clients, we can make this * function dump client registers specific to VPE or VIP based on * who is using it
*/
DUMPREG(DEI_CHROMA1_CSTAT);
DUMPREG(DEI_LUMA1_CSTAT);
DUMPREG(DEI_CHROMA2_CSTAT);
DUMPREG(DEI_LUMA2_CSTAT);
DUMPREG(DEI_CHROMA3_CSTAT);
DUMPREG(DEI_LUMA3_CSTAT);
DUMPREG(DEI_MV_IN_CSTAT);
DUMPREG(DEI_MV_OUT_CSTAT);
DUMPREG(VIP_UP_Y_CSTAT);
DUMPREG(VIP_UP_UV_CSTAT);
DUMPREG(VPI_CTL_CSTAT);
}
EXPORT_SYMBOL(vpdma_dump_regs);
/* * Allocate a DMA buffer
*/ int vpdma_alloc_desc_buf(struct vpdma_buf *buf, size_t size)
{
buf->size = size;
buf->mapped = false;
buf->addr = kzalloc(size, GFP_KERNEL); if (!buf->addr) return -ENOMEM;
/* * Cleanup all pending descriptors of a list * First, stop the current list being processed. * If the VPDMA was busy, this step makes vpdma to accept post lists. * To cleanup the internal FSM, post abort list descriptor for all the * channels from @channels array of size @size.
*/ int vpdma_list_cleanup(struct vpdma_data *vpdma, int list_num, int *channels, int size)
{ struct vpdma_desc_list abort_list; int i, ret, timeout = 500;
ret = vpdma_create_desc_list(&abort_list,
size * sizeof(struct vpdma_dtd), VPDMA_LIST_TYPE_NORMAL); if (ret) return ret;
for (i = 0; i < size; i++)
vpdma_add_abort_channel_ctd(&abort_list, channels[i]);
ret = vpdma_map_desc_buf(vpdma, &abort_list.buf); if (ret) goto free_desc;
ret = vpdma_submit_descs(vpdma, &abort_list, list_num); if (ret) goto unmap_desc;
while (vpdma_list_busy(vpdma, list_num) && --timeout)
;
if (timeout == 0) {
dev_err(&vpdma->pdev->dev, "Timed out cleaning up VPDMA list\n");
ret = -EBUSY;
}
/* * create a descriptor list, the user of this list will append configuration, * control and data descriptors to this list, this list will be submitted to * VPDMA. VPDMA's list parser will go through each descriptor and perform the * required DMA operations
*/ int vpdma_create_desc_list(struct vpdma_desc_list *list, size_t size, int type)
{ int r;
r = vpdma_alloc_desc_buf(&list->buf, size); if (r) return r;
/* * once a descriptor list is parsed by VPDMA, we reset the list by emptying it, * to allow new descriptors to be added to the list.
*/ void vpdma_reset_desc_list(struct vpdma_desc_list *list)
{
list->next = list->buf.addr;
}
EXPORT_SYMBOL(vpdma_reset_desc_list);
/* * free the buffer allocated for the VPDMA descriptor list, this should be * called when the user doesn't want to use VPDMA any more.
*/ void vpdma_free_desc_list(struct vpdma_desc_list *list)
{
vpdma_free_desc_buf(&list->buf);
/* * submit a list of DMA descriptors to the VPE VPDMA, do not wait for completion
*/ int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list, int list_num)
{ int list_size; unsignedlong flags;
if (vpdma_list_busy(vpdma, list_num)) return -EBUSY;
pr_debug("word3: pkt_type = %d, direct = %d, class = %d, dest = %d, payload_len = %d\n",
cfd_get_pkt_type(cfd),
cfd_get_direct(cfd), class, cfd_get_dest(cfd),
cfd_get_payload_len(cfd));
}
/* * append a configuration descriptor to the given descriptor list, where the * payload is in the form of a simple data block specified in the descriptor * header, this is used to upload scaler coefficients to the scaler module
*/ void vpdma_add_cfd_block(struct vpdma_desc_list *list, int client, struct vpdma_buf *blk, u32 dest_offset)
{ struct vpdma_cfd *cfd; int len = blk->size;
/* * append a configuration descriptor to the given descriptor list, where the * payload is in the address data block format, this is used to a configure a * discontiguous set of MMRs
*/ void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client, struct vpdma_buf *adb)
{ struct vpdma_cfd *cfd; unsignedint len = adb->size;
/* * control descriptor format change based on what type of control descriptor it * is, we only use 'sync on channel' control descriptors for now, so assume it's * that
*/ staticvoid dump_ctd(struct vpdma_ctd *ctd)
{
pr_debug("control descriptor\n");
/* * append a 'sync on channel' type control descriptor to the given descriptor * list, this descriptor stalls the VPDMA list till the time DMA is completed * on the specified channel
*/ void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list, enum vpdma_channel chan)
{ struct vpdma_ctd *ctd;
/* * append an 'abort_channel' type control descriptor to the given descriptor * list, this descriptor aborts any DMA transaction happening using the * specified channel
*/ void vpdma_add_abort_channel_ctd(struct vpdma_desc_list *list, int chan_num)
{ struct vpdma_ctd *ctd;
pr_debug("word6: client specific attr0 = 0x%08x\n", dtd->client_attr0);
pr_debug("word7: client specific attr1 = 0x%08x\n", dtd->client_attr1);
}
/* * append an outbound data transfer descriptor to the given descriptor list, * this sets up a 'client to memory' VPDMA transfer for the given VPDMA channel * * @list: vpdma desc list to which we add this descriptor * @width: width of the image in pixels in memory * @c_rect: compose params of output image * @fmt: vpdma data format of the buffer * dma_addr: dma address as seen by VPDMA * max_width: enum for maximum width of data transfer * max_height: enum for maximum height of data transfer * chan: VPDMA channel * flags: VPDMA flags to configure some descriptor fields
*/ void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, int stride, conststruct v4l2_rect *c_rect, conststruct vpdma_data_format *fmt, dma_addr_t dma_addr, int max_w, int max_h, enum vpdma_channel chan, u32 flags)
{
vpdma_rawchan_add_out_dtd(list, width, stride, c_rect, fmt, dma_addr,
max_w, max_h, chan_info[chan].num, flags);
}
EXPORT_SYMBOL(vpdma_add_out_dtd);
void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, int stride, conststruct v4l2_rect *c_rect, conststruct vpdma_data_format *fmt, dma_addr_t dma_addr, int max_w, int max_h, int raw_vpdma_chan, u32 flags)
{ int priority = 0; int field = 0; int notify = 1; int channel, next_chan; struct v4l2_rect rect = *c_rect; int depth = fmt->depth; struct vpdma_dtd *dtd;
/* * append an inbound data transfer descriptor to the given descriptor list, * this sets up a 'memory to client' VPDMA transfer for the given VPDMA channel * * @list: vpdma desc list to which we add this descriptor * @width: width of the image in pixels in memory(not the cropped width) * @c_rect: crop params of input image * @fmt: vpdma data format of the buffer * dma_addr: dma address as seen by VPDMA * chan: VPDMA channel * field: top or bottom field info of the input image * flags: VPDMA flags to configure some descriptor fields * frame_width/height: the complete width/height of the image presented to the * client (this makes sense when multiple channels are * connected to the same client, forming a larger frame) * start_h, start_v: position where the given channel starts providing pixel * data to the client (makes sense when multiple channels * contribute to the client)
*/ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, int stride, conststruct v4l2_rect *c_rect, conststruct vpdma_data_format *fmt, dma_addr_t dma_addr, enum vpdma_channel chan, int field, u32 flags, int frame_width, int frame_height, int start_h, int start_v)
{ int priority = 0; int notify = 1; int depth = fmt->depth; int channel, next_chan; struct v4l2_rect rect = *c_rect; struct vpdma_dtd *dtd;
/* set or clear the mask for list complete interrupt */ void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int irq_num, int list_num, bool enable)
{
u32 reg_addr = VPDMA_INT_LIST0_MASK + VPDMA_INTX_OFFSET * irq_num;
u32 val;
val = read_reg(vpdma, reg_addr); if (enable)
val |= (1 << (list_num * 2)); else
val &= ~(1 << (list_num * 2));
write_reg(vpdma, reg_addr, val);
}
EXPORT_SYMBOL(vpdma_enable_list_complete_irq);
/* get the LIST_STAT register */ unsignedint vpdma_get_list_stat(struct vpdma_data *vpdma, int irq_num)
{
u32 reg_addr = VPDMA_INT_LIST0_STAT + VPDMA_INTX_OFFSET * irq_num;
/* * configures the output mode of the line buffer for the given client, the * line buffer content can either be mirrored(each line repeated twice) or * passed to the client as is
*/ void vpdma_set_line_mode(struct vpdma_data *vpdma, int line_mode, enum vpdma_channel chan)
{ int client_cstat = chan_info[chan].cstat_offset;
/* * configures the event which should trigger VPDMA transfer for the given * client
*/ void vpdma_set_frame_start_event(struct vpdma_data *vpdma, enum vpdma_frame_start_event fs_event, enum vpdma_channel chan)
{ int client_cstat = chan_info[chan].cstat_offset;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.